fix(apps): pin the host default model on materialized bundled agents

Bundled agents can't ship a model override (the author's providers are
not the installer's), so materialized tasks ran on the bg-task category
default — gemini flash lite — which reliably mangles large app-set-data
payloads (invalid JSON string → contract rejection → the installed app
never gets data; observed with pr-dashboard's refresh agent).

Materialization now resolves getDefaultModelAndProvider() on the host
and pins that on the new task — the installer's machine picks the
strong model, the package still pins nothing. Existing tasks keep
their user-set model (update path unchanged).
This commit is contained in:
Gagan 2026-07-07 14:14:05 +05:30
parent 78defccb29
commit 3fc4621dc1

View file

@ -5,6 +5,7 @@ import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
import { TriggersSchema, type BackgroundTask } from '@x/shared/dist/background-task.js';
import type { AppSummary } from '@x/shared/dist/rowboat-app.js';
import { WorkDir } from '../config/config.js';
import { getDefaultModelAndProvider } from '../models/defaults.js';
import { appDir, agentTaskSlug } from './indexer.js';
// Bundled background agents (spec §8). Definitions ship in the app package at
@ -94,6 +95,17 @@ async function materializeAgent(folder: string, agentFile: string): Promise<stri
sourceApp: folder,
createdAt: new Date().toISOString(),
};
// Packages can't pin a model (§8.1 — the author's providers aren't the
// installer's), but the bg-task category default is a lite model that
// reliably mangles large tool payloads (invalid JSON → contract
// rejections → the app never gets data). Pin the HOST's default model at
// materialization instead — the installer's machine decides, exactly like
// the copilot does for tasks it authors.
try {
const sel = await getDefaultModelAndProvider();
task.model = sel.model;
task.provider = sel.provider;
} catch { /* no model config — leave the category default */ }
await fs.mkdir(taskDir, { recursive: true });
await fs.writeFile(taskYaml, stringifyYaml(task), 'utf-8');
await fs.writeFile(path.join(taskDir, 'index.md'), '', 'utf-8').catch(() => undefined);