diff --git a/doc/plans/2026-10-06-default-agent-runner.md b/doc/plans/2026-10-06-default-agent-runner.md index be83cffb15..a97a47a7a3 100644 --- a/doc/plans/2026-10-06-default-agent-runner.md +++ b/doc/plans/2026-10-06-default-agent-runner.md @@ -38,8 +38,9 @@ Docker materialization, Git installer, or extra login isolation wholesale. Authorized 2026-10-09. Canonical branch: `codex/codex-runner-default`. Master base: `57e977be7` (includes both prerequisite merges and Pi integration). Canonical PR: [draft #15683](https://github.com/paperclipai/paperclip/pull/15683). -Initial CI candidate: `8ce217b71`; final source freeze follows scoped discovery -and explicit-native import preservation checks. +Initial CI candidate: `8ce217b71`. Scoped environment discovery and native import +preservation are committed at `5ba1bc986`; the final follow-up preserves saved +model, effort, and timeout through runner-only built-in configuration changes. Preview: [isolated Codex QA](http://127.0.0.1:3124), normal dev supervisor, separate empty database. Current-head live evidence is pending the source freeze and verified binary provenance; older services and artifacts are not proof. @@ -116,8 +117,8 @@ Local startup hit the macOS shared-memory ID limit. One detached 56-byte segment was released only after zero attachments and exited owners were verified. No running server or database file was changed. The separate QA server is healthy. -Next action: finish core integration checks, commit and push the candidate, -then run existing Linux CI/install checks and bounded actual journeys. Preserve +Next action: verify the final candidate through existing Linux CI/install checks, +fresh review, and bounded actual journeys. Preserve failed attempts and costs. Unrelated findings and remaining harness qualification belong to later slices. @@ -135,3 +136,6 @@ pass 280 cases plus three final regressions. Missing discovery metadata shows loading or the server error with Retry; explicit Legacy remains available. Final portability checks pass 105 cases; approval, built-in asset and CLI unit controls pass eight, three and three. The 72 skipped DB cases still need Linux. +Final candidate Storybook builds at `5ba1bc986`; fresh desktop/mobile captures +are in progress against the frozen UI tree. The runner-only built-in regression +now checks nondefault settings through switches in both directions. diff --git a/server/src/__tests__/built-in-agents.test.ts b/server/src/__tests__/built-in-agents.test.ts index 067e9e53f1..0ef7789b8f 100644 --- a/server/src/__tests__/built-in-agents.test.ts +++ b/server/src/__tests__/built-in-agents.test.ts @@ -287,7 +287,8 @@ describeEmbeddedPostgres("built-in agents", () => { it("keeps existing legacy and native built-in runners through unrelated edits and startup", async () => { const companyId = await seedCompany({ requireApproval: false }); const svc = builtInAgentService(db); - const created = await svc.ensure(companyId, "briefs", { adapterType: "codex_local", adapterConfig: { model: "gpt-5.4" }, runner: "legacy" }); + const savedSettings = { model: "gpt-5.5", modelReasoningEffort: "high", timeoutSec: 123 }; + const created = await svc.ensure(companyId, "briefs", { adapterType: "codex_local", adapterConfig: savedSettings, runner: "legacy" }); expect(created.agent?.adapterType).toBe("codex_local"); await svc.ensure(companyId, "briefs", { budgetMonthlyCents: 100 }); await reconcileBuiltInAgentsOnStartup(db); @@ -295,10 +296,14 @@ describeEmbeddedPostgres("built-in agents", () => { expect(legacy.agent?.adapterType).toBe("codex_local"); expect(legacy.agent?.adapterConfig).toEqual(created.agent?.adapterConfig); const switched = await svc.ensure(companyId, "briefs", { runner: "paperclip" }); - expect(switched.agent).toMatchObject({ adapterType: "paperclip_runner", adapterConfig: { provider: "codex" } }); + expect(switched.agent).toMatchObject({ adapterType: "paperclip_runner", adapterConfig: { provider: "codex", ...savedSettings } }); await svc.ensure(companyId, "briefs", { budgetMonthlyCents: 200 }); await reconcileBuiltInAgentsOnStartup(db); expect((await svc.get(companyId, "briefs")).agent?.adapterConfig).toEqual(switched.agent?.adapterConfig); + const switchedBack = await svc.ensure(companyId, "briefs", { runner: "legacy" }); + expect(switchedBack.agent).toMatchObject({ adapterType: "codex_local", adapterConfig: savedSettings }); + const switchedAgain = await svc.ensure(companyId, "briefs", { runner: "paperclip" }); + expect(switchedAgain.agent).toMatchObject({ adapterType: "paperclip_runner", adapterConfig: { provider: "codex", ...savedSettings } }); // A saved native profile remains editable on source-built macOS installs. runnerTarget.platform = "darwin"; runnerTarget.architecture = "arm64"; diff --git a/server/src/services/built-in-agents.ts b/server/src/services/built-in-agents.ts index 713b98db48..089ddfcf75 100644 --- a/server/src/services/built-in-agents.ts +++ b/server/src/services/built-in-agents.ts @@ -1742,7 +1742,10 @@ export function builtInAgentService(db: Db) { ); const resolvedInput = existingPendingApproval || preserveExistingAdapter ? input - : await defaultProvisionInput(companyId, definition, input); + : existing && input.runner !== undefined && input.adapterType === undefined && input.adapterConfig === undefined + // A runner-only request translates saved settings, not provisioning defaults. + ? { ...input, adapterType: existing.adapterType, adapterConfig: existing.adapterConfig } + : await defaultProvisionInput(companyId, definition, input); if (!existingPendingApproval && !preserveExistingAdapter) { await assertKnownBuiltInAgentModel(definition, resolvedInput); }