diff --git a/doc/DEVELOPING.md b/doc/DEVELOPING.md index 53215d9dd4..5f6bb10206 100644 --- a/doc/DEVELOPING.md +++ b/doc/DEVELOPING.md @@ -3149,8 +3149,12 @@ their existing preparation order. OpenCode defaults to `allow`, with explicit `ask` and `deny` options; ACPX defaults to `approve-all`, with explicit `approve-paperclip`, `approve-reads`, and `deny-all` options. Codex conversion keeps a non-empty model and -otherwise stores the shared `gpt-5.6-sol` default. The native execution boundary -applies the same default to older runner rows whose model is missing or blank. +otherwise stores the shared `gpt-6.1-sol` default (half the `gpt-5.6-sol` token +price on the reviewed OpenAI rate card in `server/src/services/codex-pricing.ts`). +The native execution boundary applies the same default to older runner rows whose +model is missing or blank; a stored model, including `gpt-5.6-sol`, is never +rewritten. A remote Codex CLI older than 0.159.0 falls back to an older compatible +Sol model (`gpt-6-sol`, then `gpt-5.6-sol`). For an Agent Chat test drive, configure two agents with Paperclip Runner: native Codex and ACPX Claude. Connect the Claude account through the agent's **AI connection** section (or supply an diff --git a/packages/adapter-utils/src/paperclip-runner-permissions.ts b/packages/adapter-utils/src/paperclip-runner-permissions.ts index 18ead96ff1..9b2840f700 100644 --- a/packages/adapter-utils/src/paperclip-runner-permissions.ts +++ b/packages/adapter-utils/src/paperclip-runner-permissions.ts @@ -11,7 +11,7 @@ export type PaperclipRunnerPermissionMode = export const PAPERCLIP_RUNNER_IDLE_TIMEOUT_DEFAULT_MS = 300_000; export const PAPERCLIP_RUNNER_IDLE_TIMEOUT_MAX_MS = 86_400_000; export const PAPERCLIP_RUNNER_DEFAULT_MODELS = { - codex: "gpt-5.6-sol", + codex: "gpt-6.1-sol", acpx: "claude-opus-5-5", opencode: "openrouter/deepseek/deepseek-v4-flash-0731", } as const; diff --git a/packages/adapters/codex-local/src/index.test.ts b/packages/adapters/codex-local/src/index.test.ts index 7976cab2e3..67dd4b3bfa 100644 --- a/packages/adapters/codex-local/src/index.test.ts +++ b/packages/adapters/codex-local/src/index.test.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from "vitest"; import { CODEX_CHATGPT_MODEL_REJECTION_RE, + CODEX_LOCAL_COMPATIBILITY_FALLBACK_MODEL, codexChatGptRetirementForModel, codexCliVersionAtLeast, codexLocalReasoningEffortsForModel, @@ -20,7 +21,12 @@ describe("codex model CLI floors", () => { expect(minimumCodexCliVersionForModel("gpt-6-luna")).toBe("0.157.0"); }); - it.each([DEFAULT_CODEX_LOCAL_MODEL, "gpt-5.6", "gpt-6-astra", "gpt-5.5", "custom-model", "", null, undefined])( + it("gates the default model on its CLI floor and keeps the compatibility fallback floor-free", () => { + expect(minimumCodexCliVersionForModel(DEFAULT_CODEX_LOCAL_MODEL)).toBe("0.159.0"); + expect(minimumCodexCliVersionForModel(CODEX_LOCAL_COMPATIBILITY_FALLBACK_MODEL)).toBeNull(); + }); + + it.each([CODEX_LOCAL_COMPATIBILITY_FALLBACK_MODEL, "gpt-5.6", "gpt-6-astra", "gpt-5.5", "custom-model", "", null, undefined])( "has no floor for %s so callers skip the version probe", (model) => { expect(minimumCodexCliVersionForModel(model)).toBeNull(); }, @@ -72,9 +78,10 @@ describe("codex local adapter metadata", () => { it("advertises current Codex-capable OpenAI models without changing the default", () => { const modelIds = models.map((model) => model.id); - // Default to the concrete gpt-5.6-sol slug — Codex ships no metadata for the bare gpt-5.6 - // alias, so it must not be advertised or used as the default (it triggers a fallback warning). - expect(DEFAULT_CODEX_LOCAL_MODEL).toBe("gpt-5.6-sol"); + // Default to gpt-6.1-sol, half the gpt-5.6-sol price on the reviewed rate card. Bare family + // aliases such as gpt-5.6 have no Codex metadata, so they are never advertised or the default. + expect(DEFAULT_CODEX_LOCAL_MODEL).toBe("gpt-6.1-sol"); + expect(CODEX_LOCAL_COMPATIBILITY_FALLBACK_MODEL).toBe("gpt-5.6-sol"); // Ordered like the ChatGPT app: newest version first, then by capability within a version (#14878). expect(modelIds.slice(0, 13)).toEqual([ "gpt-6.1-sol", diff --git a/packages/adapters/codex-local/src/index.ts b/packages/adapters/codex-local/src/index.ts index c5bb78db66..11c5d42f5e 100644 --- a/packages/adapters/codex-local/src/index.ts +++ b/packages/adapters/codex-local/src/index.ts @@ -8,10 +8,15 @@ export const label = "Codex"; export const SANDBOX_INSTALL_COMMAND = "npm install -g @openai/codex"; -// Use the concrete `gpt-5.6-sol` slug (Codex's own default for the 5.6 family) rather than the -// bare `gpt-5.6` alias: OpenAI ships no model metadata for the bare slug, so passing it makes the -// Codex CLI warn ("Model metadata for `gpt-5.6` not found") and fall back to generic context limits. +// The default is `gpt-6.1-sol`: the reviewed OpenAI rate card in server/src/services/codex-pricing.ts +// prices it at half of `gpt-5.6-sol`. It applies only to agents without an explicit model; a stored +// model is never rewritten. Always use a concrete slug rather than a bare family alias such as +// `gpt-5.6`: OpenAI ships no model metadata for bare slugs, so the Codex CLI warns and falls back to +// generic context limits. export const DEFAULT_CODEX_LOCAL_MODEL = PAPERCLIP_RUNNER_DEFAULT_MODELS.codex; +// The floor-free model a remote Codex CLI too old for the requested model falls back to. It stays +// `gpt-5.6-sol` because the default `gpt-6.1-sol` itself needs Codex 0.159.0 or newer. +export const CODEX_LOCAL_COMPATIBILITY_FALLBACK_MODEL = "gpt-5.6-sol"; export const DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX = true; export function resolveCodexLocalCliPolicy(config: unknown, options: { networkAccess?: boolean } = {}) { @@ -219,8 +224,7 @@ export const models = [ { id: "gpt-6-astra", label: "gpt-6-astra" }, { id: "gpt-6-sol", label: "gpt-6-sol" }, { id: "gpt-6-luna", label: "gpt-6-luna" }, - // DEFAULT_CODEX_LOCAL_MODEL is gpt-5.6-sol, the first 5.6 entry. - { id: DEFAULT_CODEX_LOCAL_MODEL, label: DEFAULT_CODEX_LOCAL_MODEL }, + { id: "gpt-5.6-sol", label: "gpt-5.6-sol" }, { id: "gpt-5.6-terra", label: "gpt-5.6-terra" }, { id: "gpt-5.6-luna", label: "gpt-5.6-luna" }, { id: "gpt-5.5", label: "gpt-5.5" }, diff --git a/packages/adapters/codex-local/src/ui/build-config.test.ts b/packages/adapters/codex-local/src/ui/build-config.test.ts index 7bf6e308b8..cb8d4ba0b4 100644 --- a/packages/adapters/codex-local/src/ui/build-config.test.ts +++ b/packages/adapters/codex-local/src/ui/build-config.test.ts @@ -378,7 +378,7 @@ describe("buildPaperclipRunnerConfig", () => { it("uses the Codex default when no model was selected", () => { expect(buildPaperclipRunnerConfig(makeValues({ model: "" }))).toMatchObject({ provider: "codex", - model: "gpt-5.6-sol", + model: "gpt-6.1-sol", }); }); diff --git a/packages/paperclip-runner/devtools/issue-thread/src/App.tsx b/packages/paperclip-runner/devtools/issue-thread/src/App.tsx index 010bad1195..8c37d90123 100644 --- a/packages/paperclip-runner/devtools/issue-thread/src/App.tsx +++ b/packages/paperclip-runner/devtools/issue-thread/src/App.tsx @@ -55,11 +55,11 @@ const CHAT_HARNESS_KEY = "paperclip-runner.capability.chat.harness.v1"; const MODEL_PRESETS = { codex: ["gpt-5.4-mini", "gpt-5.4"], opencode: ["openrouter/deepseek/deepseek-v4-flash-0731"], - acpx: ["openrouter/deepseek/deepseek-v4-flash-0731", "claude-sonnet-5", "gpt-5.6-sol"], + acpx: ["openrouter/deepseek/deepseek-v4-flash-0731", "claude-sonnet-5", "gpt-6.1-sol"], } as const; const ACPX_DEFAULT_MODELS = { claude: "claude-sonnet-5", - codex: "gpt-5.6-sol", + codex: "gpt-6.1-sol", } as const; function acpxLabel(configuration: CapabilityHarnessConfiguration | null | undefined): string { diff --git a/packages/paperclip-runner/scripts/run-local-provider-smoke.mjs b/packages/paperclip-runner/scripts/run-local-provider-smoke.mjs index a45dbcf80b..65492b77e8 100644 --- a/packages/paperclip-runner/scripts/run-local-provider-smoke.mjs +++ b/packages/paperclip-runner/scripts/run-local-provider-smoke.mjs @@ -53,7 +53,7 @@ function liveCandidate(id, candidateSlots) { source && { ...source, id: "runner-codex-sol", - model: "gpt-5.6-sol", + model: "gpt-6.1-sol", } ); } diff --git a/packages/paperclip-runner/src/eval/live-workflow-matrix.ts b/packages/paperclip-runner/src/eval/live-workflow-matrix.ts index 6ece8d18a4..a1e0ffaf8d 100644 --- a/packages/paperclip-runner/src/eval/live-workflow-matrix.ts +++ b/packages/paperclip-runner/src/eval/live-workflow-matrix.ts @@ -202,7 +202,7 @@ export const RUNNER_LIVE_CANDIDATE_SLOTS: readonly RunnerLiveCandidateSlot[] = slotId: "acpx-codex", adapter: "acpx_runtime", provider: "acpx", - model: "gpt-5.6-sol", + model: "gpt-6.1-sol", tier: "strong", reasoningEffort: "medium", qualification: { diff --git a/server/src/__tests__/agent-adapter-validation-routes.test.ts b/server/src/__tests__/agent-adapter-validation-routes.test.ts index 1606070bb7..d3f368803f 100644 --- a/server/src/__tests__/agent-adapter-validation-routes.test.ts +++ b/server/src/__tests__/agent-adapter-validation-routes.test.ts @@ -1133,7 +1133,7 @@ describe("agent routes adapter validation", () => { expect.objectContaining({ adapterConfig: expect.objectContaining({ provider: "codex", - model: "gpt-5.6-sol", + model: "gpt-6.1-sol", codexPermissionMode: "never", lifecycleMode: "per_turn", paperclipSkillSync: { desiredSkills: ["company-1/reviewer"] }, @@ -1426,7 +1426,7 @@ describe("agent routes adapter validation", () => { expect(mockAgentService.update).toHaveBeenCalledWith( "11111111-1111-4111-8111-111111111111", expect.objectContaining({ - adapterConfig: expect.objectContaining({ model: "gpt-5.6-sol" }), + adapterConfig: expect.objectContaining({ model: "gpt-6.1-sol" }), }), expect.any(Object), ); diff --git a/server/src/services/native-runtime/codex-model-fallback.ts b/server/src/services/native-runtime/codex-model-fallback.ts index dbf95b1b0d..1436d23cfa 100644 --- a/server/src/services/native-runtime/codex-model-fallback.ts +++ b/server/src/services/native-runtime/codex-model-fallback.ts @@ -1,7 +1,7 @@ import { posix } from "node:path"; import { codexCliVersionAtLeast, - DEFAULT_CODEX_LOCAL_MODEL, + CODEX_LOCAL_COMPATIBILITY_FALLBACK_MODEL, minimumCodexCliVersionForModel, models, normalizeCodexModel, @@ -11,7 +11,7 @@ import type { CommandManagedRuntimeRunner } from "@paperclipai/adapter-utils/com import { createNativeSshCommandRunner } from "./native-ssh-command-runner.js"; import { isSupportedRemoteCodexVersion, parseCodexCliVersion } from "./codex-runtime-compatibility.js"; -/** Newest older model in the same class first, then the stable Runner default. */ +/** Newest older model in the same class first, then the floor-free compatibility model. */ export function codexModelFallbackCandidates(requestedModel: string): string[] { const requested = normalizeCodexModel(requestedModel); const identity = /^gpt-(\d+(?:\.\d+)?)-(astra|sol|terra|luna)$/.exec(requested); @@ -20,7 +20,7 @@ export function codexModelFallbackCandidates(requestedModel: string): string[] { return candidate && candidate[2] === identity[2] && Number(candidate[1]) < Number(identity[1]) ? [id] : []; }) : []; - return [...new Set([...sameClass, DEFAULT_CODEX_LOCAL_MODEL])].filter((model) => model !== requested); + return [...new Set([...sameClass, CODEX_LOCAL_COMPATIBILITY_FALLBACK_MODEL])].filter((model) => model !== requested); } export function compatibleCodexModel(model: string | null, version: string | null): string | null { diff --git a/tests/acpx-qualification-models.ts b/tests/acpx-qualification-models.ts index ef4a978009..68381aa9c8 100644 --- a/tests/acpx-qualification-models.ts +++ b/tests/acpx-qualification-models.ts @@ -1,7 +1,7 @@ /** Explicit evaluation selections, not runtime defaults or model allowlists. */ export const ACPX_QUALIFICATION_MODELS = { claude: "claude-sonnet-5", - codex: "gpt-5.6-sol", + codex: "gpt-6.1-sol", grok: "grok-4.7", pi: "openrouter/anthropic/claude-sonnet-4.6", } as const; diff --git a/tests/runner-e2e/EVERYDAY-WORKFLOWS.md b/tests/runner-e2e/EVERYDAY-WORKFLOWS.md index 705164b860..cc0f2d1d44 100644 --- a/tests/runner-e2e/EVERYDAY-WORKFLOWS.md +++ b/tests/runner-e2e/EVERYDAY-WORKFLOWS.md @@ -138,7 +138,7 @@ native Codex Daytona cell. | `three-turn-revise` | `runner-opencode-deepseek-1017.daytona` (per-turn lease) | S49 hit turn 3 on an ephemeral Daytona lease. | | `long-silent-command` | `runner-opencode-deepseek-1017.daytona` (warm lease) | S52/S52b hung on remote runners during a silent command. | | `tree-pause-release` | `runner-opencode-deepseek-1017.local` | S50/S50b is tree-hold and parked-retry scheduling. | -| `queue-steer` | `runner-codex.daytona` (warm lease) | H2 needs a steering-capable driver; OpenCode has no steering. | +| `queue-steer` | `runner-codex.daytona` (warm lease, `gpt-6.1-sol`) | H2 needs a steering-capable driver; OpenCode has no steering. | | `queued-across-restart` | `runner-opencode-deepseek-1017.daytona` (warm lease) | S55/U9 happened across a restart with a remote lease. | The local plan cells cannot reproduce Daytona-only signatures: the remote @@ -150,7 +150,7 @@ S47, S48 and S50. The extras are outside the TestOps plan. Every case except `queue-steer` (whose Codex cell is the plan cell) also runs once on native Codex (`runner-codex`, -`gpt-5.6-sol`) on Daytona: the warm environment, except `three-turn-revise` on +`gpt-6.1-sol`) on Daytona: the warm environment, except `three-turn-revise` on the per-turn lease. `long-silent-command` also runs on the released ACPX facades Grok (`runner-acpx-grok`), Kimi (`runner-acpx-kimi`) and OpenRouter/Pi (`runner-acpx-pi`), which hung 3/3 before the fix. They run @@ -221,7 +221,7 @@ cause" contract is checked only if a loss happens naturally. ## Matrix and running -The local matrix has fourteen cases on native Codex `gpt-5.6-sol`, native ACPX Claude +The local matrix has fourteen cases on native Codex `gpt-6.1-sol`, native ACPX Claude `claude-sonnet-5`, and native Codex `gpt-5.4-mini`: 42 cells. The two core profiles also declare build/revise, delegation, controller-restart, and skill-creation cases on Daytona: eight cells. OpenCode adds only local hiring/reuse and delegation, diff --git a/tests/runner-e2e/installed-cli.test.ts b/tests/runner-e2e/installed-cli.test.ts index 2d1ade82a8..fae4f5975e 100644 --- a/tests/runner-e2e/installed-cli.test.ts +++ b/tests/runner-e2e/installed-cli.test.ts @@ -160,7 +160,7 @@ async function startupFixture(mode: "normal" | "wrong-model" | "ambient-codex" | constructor(options){this.options=options;} async openSession(){state.calls.push("open");save(); ${mode === "startup-and-cleanup-failed" ? 'throw new Error("fixture original provider startup failure");' : ''} - const model=${JSON.stringify(mode === "wrong-model" ? "wrong-model" : "gpt-5.6-sol")}; + const model=${JSON.stringify(mode === "wrong-model" ? "wrong-model" : "gpt-6.1-sol")}; return {ids:()=>({driverSessionId:"PRIVATE-DRIVER-ID",providerSessionId:"PRIVATE-PROVIDER-ID"}), events:()=>({async *[Symbol.asyncIterator](){yield {eventType:"session.started",payload:{context:{model,sandbox:{permissionProfile:{id:"paperclip-runner-workspace-read-only"}}}}};}}), startTurn(){state.calls.push("FORBIDDEN-TURN");save();throw new Error("No provider turn is permitted");}, diff --git a/tests/runner-e2e/installed-cli.ts b/tests/runner-e2e/installed-cli.ts index 820577869a..3a75b80834 100644 --- a/tests/runner-e2e/installed-cli.ts +++ b/tests/runner-e2e/installed-cli.ts @@ -140,7 +140,7 @@ export async function probeInstalledCodexStartup(input: { const driver = new runtime.CodexAppServerDriver({ taskEnvelope: { schema: "paperclip.skillless_task.v1", objective: "Credential-free installed startup proof.", completionContract: { revision: "installed-startup-v1", criteria: [] }, constraints: [], expectedResultSchema: "paperclip.run_result.v1" }, - model: "gpt-5.6-sol", conversationMode: "direct", requestedCollaborationMode: "plan", approvalPolicy: "never", + model: "gpt-6.1-sol", conversationMode: "direct", requestedCollaborationMode: "plan", approvalPolicy: "never", includeCollaborationModeInstructions: false, dynamicTools: [], environment, transportFactory: () => bundle.transport, requireProviderSessionIdentity: true, }); @@ -148,7 +148,7 @@ export async function probeInstalledCodexStartup(input: { const event = await session.events()[Symbol.asyncIterator]().next(); const identity = session.ids(); const evidence = bundle.evidence(); - if (event.value?.eventType !== "session.started" || event.value.payload?.context?.model !== "gpt-5.6-sol" || + if (event.value?.eventType !== "session.started" || event.value.payload?.context?.model !== "gpt-6.1-sol" || event.value.payload?.context?.sandbox?.permissionProfile?.id !== "paperclip-runner-workspace-read-only" || !identity.driverSessionId || !identity.providerSessionId || evidence.providerDriver !== "codex_app_server" || !(evidence.runnerPid > 0) || !(evidence.codexPid > 0)) throw new Error("Installed Codex startup returned no matching native identity or read-only model context"); @@ -157,7 +157,7 @@ export async function probeInstalledCodexStartup(input: { if (!bundle.evidence().runnerExited) throw new Error("Installed Codex startup cleanup is incomplete"); cleanupConfirmed = true; return { schema: "paperclip.e2e.installed-codex-startup/v1", platform: `${process.platform}-${process.arch}`, - runnerSha256, codexSha256, codexVersion, providerDriver: "codex_app_server", model: "gpt-5.6-sol", + runnerSha256, codexSha256, codexVersion, providerDriver: "codex_app_server", model: "gpt-6.1-sol", nativeSessionStarted: true, cleanupConfirmed: true, providerTurns: 0, credentialsUsed: false, defaultRuntimeResolution: true, reasoningEffortExercised: false }; } catch (error) { diff --git a/tests/runner-e2e/product-regression-testops-catalog.test.ts b/tests/runner-e2e/product-regression-testops-catalog.test.ts index 27429cdc00..7abd3b5577 100644 --- a/tests/runner-e2e/product-regression-testops-catalog.test.ts +++ b/tests/runner-e2e/product-regression-testops-catalog.test.ts @@ -72,7 +72,7 @@ it("runs every standing Product regression case through its existing full-stack expect(projected.records[1]!.value.checks).toHaveLength(matcherResults.length); expect(projected.records[1]!.value.checks?.map(check => check.passed)).toEqual(matcherResults.map(check => check.passed)); if (firstTask) { - const alias = "gpt-5.6-sol-2026-11-01", secret = "sk-proj-syntheticcredentialabcdefghijklmnop"; + const alias = "gpt-6.1-sol-2026-11-01", secret = "sk-proj-syntheticcredentialabcdefghijklmnop"; for (const [configuredModel, observedModels] of [[row.model, [alias]], [null, []], [row.model, [secret]]] as const) { const reported = observedModels[0] ?? configuredModel ?? "provider-default (unreported)"; const output = project({ ...raw, model: reported, firstTask: { ...firstTask, configuredModel, observedModels: [...observedModels] } }); @@ -83,7 +83,7 @@ it("runs every standing Product regression case through its existing full-stack expect(output.records[1]!.value.reportedModelSha256).toBe(createHash("sha256").update(reported).digest("hex")); expect(JSON.stringify(output)).not.toContain(reported); } - for (const configuredModel of ["gpt-6.1-sol", secret]) { + for (const configuredModel of ["gpt-5.6-sol", secret]) { expect(() => project({ ...raw, model: alias, firstTask: { ...firstTask, configuredModel, observedModels: [alias] } })) .toThrow("product_regression_testops_metadata_invalid"); } diff --git a/tests/runner-e2e/product-regression-testops.mjs b/tests/runner-e2e/product-regression-testops.mjs index fe16dfd15a..262f7f5f17 100644 --- a/tests/runner-e2e/product-regression-testops.mjs +++ b/tests/runner-e2e/product-regression-testops.mjs @@ -26,8 +26,7 @@ export const productRegressionCases = [ [168, 'agent-chat', 'new-session'], ].map(([id, suite, name, profile = 'runner-codex']) => Object.freeze({ id, suite, name, profile, - model: suite === 'task-workspaces' ? 'openrouter/deepseek/deepseek-v4-flash-0731' - : suite === 'configured-repository' ? 'gpt-6.1-sol' : 'gpt-5.6-sol', + model: suite === 'task-workspaces' ? 'openrouter/deepseek/deepseek-v4-flash-0731' : 'gpt-6.1-sol', fullName: `paperclip.Product E2E.${suite}.${name}`, executionId: `${suite}.${profile}.local.${name}`, plan: 'product-regression', environment: 'local', diff --git a/tests/runner-e2e/product-regression-testops.test.mjs b/tests/runner-e2e/product-regression-testops.test.mjs index 03368ba39b..0790bf089b 100644 --- a/tests/runner-e2e/product-regression-testops.test.mjs +++ b/tests/runner-e2e/product-regression-testops.test.mjs @@ -20,7 +20,7 @@ const selection = cases => ({ schema: 'paperclip.product-regression-testops-sele const result = (overrides = {}) => ({ executionId: selected.executionId, suiteId: selected.suite, caseId: selected.name, profileId: selected.profile, environmentId: 'local', source: { sha: targetSha }, attempt: 1, - status: 'passed', cleanup: 'passed', model: 'gpt-5.6-sol', suiteDefinitionHash: 'c'.repeat(64), + status: 'passed', cleanup: 'passed', model: 'gpt-6.1-sol', suiteDefinitionHash: 'c'.repeat(64), matcherResults: [{ matcher: { kind: 'json_path', path: 'observed.outputVerified', expected: true }, passed: true }], ...overrides, }); @@ -133,7 +133,7 @@ test('the transmission projection excludes raw errors, provider IDs, narratives test('secret-shaped and unknown metadata cannot cross the reporting boundary', () => { const sentinel = 'sk-proj-syntheticcredentialabcdefghijklmnop'; - for (const mutation of [{ model: sentinel }, { model: 'gpt-6.1-sol' }, { failureClass: sentinel }, { cleanup: sentinel }, + for (const mutation of [{ model: sentinel }, { model: 'gpt-5.6-sol' }, { failureClass: sentinel }, { cleanup: sentinel }, { matcherResults: [{ passed: true, matcher: { kind: sentinel } }] }]) { assert.throws(() => projectProductResults(campaign([result(mutation)]), selection([selected]), targetSha), error => error.message === 'product_regression_testops_metadata_invalid'); diff --git a/tests/runner-e2e/reliability-testops-catalog.test.ts b/tests/runner-e2e/reliability-testops-catalog.test.ts index 7eec6f1883..0d407e131b 100644 --- a/tests/runner-e2e/reliability-testops-catalog.test.ts +++ b/tests/runner-e2e/reliability-testops-catalog.test.ts @@ -27,7 +27,9 @@ it("binds every TestOps Reliability case to its existing explicit-only cell", () expect(execution.environment.id).toBe(row.environment); expect(row.environment).toBe(cell.environment); // Six cells use DeepSeek 1017 on OpenCode; queue-steer needs a steering-capable driver (Codex app server). - if (row.name === "queue-steer") expect([execution.profile.provider, execution.profile.id]).toEqual(["codex", "runner-codex"]); + // It runs the cheaper gpt-6.1-sol, half the gpt-5.6-sol price on the reviewed rate card. + if (row.name === "queue-steer") expect([execution.profile.provider, execution.profile.id, execution.profile.model]) + .toEqual(["codex", "runner-codex", "gpt-6.1-sol"]); else expect([execution.profile.provider, execution.profile.model]).toEqual(["opencode", reliabilityModel]); expect(row.signature).toBe(everydayReliabilitySignatures[row.name as keyof typeof everydayReliabilitySignatures].signature); // OpenRouter (or the OpenAI key for the Codex steering cell), plus Daytona only for sandbox cells. @@ -41,6 +43,13 @@ it("binds every TestOps Reliability case to its existing explicit-only cell", () for (const job of buildMatrixJobs(executions)) expect(job.timeoutMinutes).toBeGreaterThan(20); }); +it("runs every native Codex everyday cell, standard and reliability, on the gpt-6.1-sol default", () => { + const codex = runnerMatrix.filter(execution => execution.suite.id === "everyday-workflows" && execution.profile.id === "runner-codex"); + expect(codex.filter(execution => everydayReliabilityCaseIds.includes(execution.task.id as never))).toHaveLength(7); + expect(codex.filter(execution => !everydayReliabilityCaseIds.includes(execution.task.id as never)).length).toBeGreaterThan(0); + expect(new Set(codex.map(execution => execution.profile.model))).toEqual(new Set(["gpt-6.1-sol"])); +}); + it("keeps a case that steers an active turn on a steering-capable driver", async () => { // queue-steer requires a 2xx same-turn steer. The OpenCode server driver // declares steering false, so the route answers steering_unsupported there. diff --git a/tests/runner-e2e/reliability-testops.mjs b/tests/runner-e2e/reliability-testops.mjs index d687eb4cf3..d8db09e0e6 100644 --- a/tests/runner-e2e/reliability-testops.mjs +++ b/tests/runner-e2e/reliability-testops.mjs @@ -13,7 +13,7 @@ export const reliabilityPlanName = 'Reliability — staging soak'; export const reliabilitySuite = 'everyday-workflows'; export const reliabilityProfile = 'runner-opencode-deepseek-1017'; export const reliabilityModel = 'openrouter/deepseek/deepseek-v4.1-flash-1017'; -const steeringProfile = ['runner-codex', 'gpt-5.6-sol']; +const steeringProfile = ['runner-codex', 'gpt-6.1-sol']; // Daytona only where the soak failure was a sandbox lease failure (S49, S52/S52b, // S55). The catalog test binds this table to everyday-reliability-cases.ts. diff --git a/tests/runner-e2e/reliability-testops.test.mjs b/tests/runner-e2e/reliability-testops.test.mjs index 4cda542b8c..a2e09a9210 100644 --- a/tests/runner-e2e/reliability-testops.test.mjs +++ b/tests/runner-e2e/reliability-testops.test.mjs @@ -39,7 +39,7 @@ test('the plan is six DeepSeek 1017 cells plus native Codex for steering, Dayton assert.ok(reliabilityDefinitions.every(row => row.fullName === `paperclip.Product E2E.everyday-workflows.${row.name}`)); // OpenCode declares steering: false, so only queue-steer uses the steering-capable native Codex cell. assert.deepEqual(reliabilityDefinitions.filter(row => row.profile !== reliabilityProfile || row.model !== reliabilityModel) - .map(row => [row.name, row.profile, row.model, row.environment]), [['queue-steer', 'runner-codex', 'gpt-5.6-sol', 'daytona']]); + .map(row => [row.name, row.profile, row.model, row.environment]), [['queue-steer', 'runner-codex', 'gpt-6.1-sol', 'daytona']]); assert.deepEqual(reliabilityDefinitions.filter(row => row.profile === reliabilityProfile && row.environment === 'daytona').map(row => row.name), ['three-turn-revise', 'long-silent-command', 'queued-across-restart']); assert.equal(testOpsPlanDetails.reliability.size, 7); diff --git a/tests/runner-e2e/scheduled-forecast.test.ts b/tests/runner-e2e/scheduled-forecast.test.ts index d6aa1efdca..491cc05b09 100644 --- a/tests/runner-e2e/scheduled-forecast.test.ts +++ b/tests/runner-e2e/scheduled-forecast.test.ts @@ -58,7 +58,7 @@ it("computes distributions within one cohort and does not sum P95s", () => { const snapshot = structuredClone(measurements); const cell = selected("daily").find(cell => cell.id.startsWith("core-"))!; const sample = snapshot.samples.find(sample => sample.executionId === cell.id)!; - snapshot.samples = Array.from({ length: 20 }, (_, index) => ({ ...sample, attemptId: `attempt-${index}`, + snapshot.samples = Array.from({ length: 20 }, (_, index) => ({ ...sample, definitionHash: cell.suiteDefinitionHash, attemptId: `attempt-${index}`, knownModelUsd: String(index + 1), attemptDurationMs: (index + 1) * 1000 })); const forecast = scheduledForecast([cell], models, snapshot); expect(forecast.cells[0]!.compatibleSuccessful).toEqual({ samples: 20, @@ -85,7 +85,7 @@ it("preserves nanodollar costs and genuine measured zero", () => { const snapshot = structuredClone(measurements); const cell = selected("daily").find(cell => cell.id.startsWith("core-"))!; const sample = snapshot.samples.find(sample => sample.executionId === cell.id)!; - snapshot.samples = [{ ...sample, knownModelUsd: "0.000000001", attemptDurationMs: 0 }]; + snapshot.samples = [{ ...sample, definitionHash: cell.suiteDefinitionHash, knownModelUsd: "0.000000001", attemptDurationMs: 0 }]; expect(scheduledForecast([cell], models, snapshot).compatibleSuccessfulSelection) .toEqual({ modelUsd: "0.000000001", summedAttemptMs: 0 }); snapshot.samples[0]!.knownModelUsd = "0"; @@ -95,7 +95,7 @@ it("preserves nanodollar costs and genuine measured zero", () => { it("keeps hosts separate and requires hosted evidence for the whole selection", () => { const snapshot = structuredClone(measurements); const cell = selected("daily").find(cell => cell.id.startsWith("core-"))!; - const sample = snapshot.samples.find(sample => sample.executionId === cell.id)!; + const sample = { ...snapshot.samples.find(sample => sample.executionId === cell.id)!, definitionHash: cell.suiteDefinitionHash }; snapshot.samples = [sample, { ...sample, attemptId: "different-host", measurementHost: "local-docker-linux-arm64" }]; const forecast = scheduledForecast([cell], models, snapshot); expect(forecast.cells[0]!.historicalCohorts).toHaveLength(2); diff --git a/tests/runner-e2e/scheduled-operations.test.ts b/tests/runner-e2e/scheduled-operations.test.ts index 7157a0efc8..8ccdfa2f14 100644 --- a/tests/runner-e2e/scheduled-operations.test.ts +++ b/tests/runner-e2e/scheduled-operations.test.ts @@ -26,10 +26,12 @@ it.each(["daily", "weekly"] as const)("runs the exact %s selection through one s expect(manifest.models.every(model => Number(evalRequestReservation({ ...model, mode: "braintrust", apiKey: "fixture" })) <= Number(manifest.limits.maxUsd))).toBe(true); }); -it("does not reduce Codex's verified context ceiling to fit the daily allowance", () => { +it("keeps Codex's verified context ceiling and long-context reservation without joining the daily selection", () => { const codex = scheduledManifest({ ...input, cadence: "weekly" }).models.find(row => row.provider === "openai")!; + expect(codex.price.model).toBe("gpt-6.1-sol"); expect(codex.maximumInputTokens).toBe(1_050_000); - expect(Number(evalRequestReservation({ ...codex, mode: "braintrust", apiKey: "fixture" }))).toBeGreaterThan(20); + // The full 1.05M-token request reserves at the long-context rates; gpt-6.1-sol halves the gpt-5.6-sol hold. + expect(Number(evalRequestReservation({ ...codex, mode: "braintrust", apiKey: "fixture" }))).toBeCloseTo(10.74576, 5); expect(scheduledManifest(input).models.map(model => model.provider)).toEqual(["anthropic"]); }); diff --git a/tests/runner-e2e/scheduled-prices.json b/tests/runner-e2e/scheduled-prices.json index c1d437be77..8904b4d599 100644 --- a/tests/runner-e2e/scheduled-prices.json +++ b/tests/runner-e2e/scheduled-prices.json @@ -3,6 +3,33 @@ "verifiedAt": "2026-10-20T00:00:00Z", "expiresAt": "2026-11-19T00:00:00Z", "models": [ + { + "provider": "openai", + "maximumInputTokens": 1050000, + "maximumOutputTokens": 16384, + "timeoutMs": 180000, + "price": { + "provider": "openai", + "model": "gpt-6.1-sol", + "version": "openai-standard-2026-11-06", + "sourceUrl": "https://developers.openai.com/api/docs/pricing", + "inputUsdPerMillion": "2", + "cachedReadUsdPerMillion": "0.1", + "outputUsdPerMillion": "10", + "cacheWrite30mUsdPerMillion": "2.5", + "cacheWrite12hUsdPerMillion": "5", + "longContext": { + "aboveInputTokens": 272000, + "rates": { + "inputUsdPerMillion": "4", + "cachedReadUsdPerMillion": "0.2", + "outputUsdPerMillion": "15", + "cacheWrite30mUsdPerMillion": "5", + "cacheWrite12hUsdPerMillion": "10" + } + } + } + }, { "provider": "openai", "maximumInputTokens": 1050000, diff --git a/ui/src/components/AgentConfigForm.test.ts b/ui/src/components/AgentConfigForm.test.ts index 9ba42adc09..d0cc530bca 100644 --- a/ui/src/components/AgentConfigForm.test.ts +++ b/ui/src/components/AgentConfigForm.test.ts @@ -31,7 +31,7 @@ describe("resolvePaperclipRunnerTransitionModel", () => { it("uses the current Codex default when the source model is blank", () => { expect(resolvePaperclipRunnerTransitionModel("codex_local", "")) - .toBe("gpt-5.6-sol"); + .toBe("gpt-6.1-sol"); }); }); diff --git a/ui/src/components/ai-connections/AiConnectionPoolConnector.tsx b/ui/src/components/ai-connections/AiConnectionPoolConnector.tsx index c34c94478a..624c2c636d 100644 --- a/ui/src/components/ai-connections/AiConnectionPoolConnector.tsx +++ b/ui/src/components/ai-connections/AiConnectionPoolConnector.tsx @@ -2,6 +2,7 @@ import { useEffect, useState } from "react"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { ArrowDown, ArrowUp, ExternalLink, Loader2, MoreHorizontal, Plus, Search, Trash2, X } from "lucide-react"; import { aiConnectionRouterAppDefinition, type AiConnectionPool, type AiConnectionPoolConfig, type AiConnectionPoolMember, type AiManagedConnectionSummary, type ToolConnection } from "@paperclipai/shared"; +import { PAPERCLIP_RUNNER_DEFAULT_MODELS } from "@paperclipai/adapter-utils"; import { aiConnectionsApi } from "@/api/ai-connections"; import { aiConnectionPoolsApi, type PoolInspection } from "@/api/ai-connection-pools"; import { describeError } from "@/api/errors"; @@ -29,7 +30,7 @@ import { AI_PROVIDERS, aiMethodLabel } from "./model"; const configOf = ({ name, enabled, members, mode, thresholdPercent }: AiConnectionPoolConfig): AiConnectionPoolConfig => ({ name, enabled, members, mode, thresholdPercent }); const emptyConfig = (): AiConnectionPoolConfig => ({ name: "AI connection pool", enabled: false, members: [], mode: "round_robin", thresholdPercent: 90 }); function memberOf(account: AiManagedConnectionSummary): AiConnectionPoolMember { - const profile: AiConnectionPoolMember["profile"] = account.provider === "openai" ? { provider: "codex", model: "gpt-5.6-sol" } + const profile: AiConnectionPoolMember["profile"] = account.provider === "openai" ? { provider: "codex", model: PAPERCLIP_RUNNER_DEFAULT_MODELS.codex } : account.provider === "anthropic" ? { provider: "acpx", acpxAgent: "claude", model: "claude-sonnet-5" } : account.provider === "xai" ? { provider: "acpx", acpxAgent: "grok", model: "grok-4.7" } : { provider: "opencode", model: "openrouter/anthropic/claude-sonnet-4.6" }; diff --git a/ui/src/components/task-chat/composer-run-settings.test.ts b/ui/src/components/task-chat/composer-run-settings.test.ts index 7639b8053f..f46e59e0d5 100644 --- a/ui/src/components/task-chat/composer-run-settings.test.ts +++ b/ui/src/components/task-chat/composer-run-settings.test.ts @@ -19,7 +19,7 @@ describe("composer run settings", () => { expect(composerDefaultModel({ ...agent("claude_local"), adapterConfig: { env: { ANTHROPIC_MODEL: { type: "secret_ref", secretId: "model-secret" } } } })).toBe(""); expect(composerDefaultModel({ ...agent("codex_local"), adapterConfig: { model: " private-codex " } })).toBe("private-codex"); expect(composerDefaultModel(agent("codex_local"))).toBe(""); - expect(composerDefaultModel(agent("paperclip_runner", "codex"))).toBe("gpt-5.6-sol"); + expect(composerDefaultModel(agent("paperclip_runner", "codex"))).toBe("gpt-6.1-sol"); expect(composerDefaultModel(agent("grok_local"))).toBe("grok-build"); expect(composerDefaultModel(undefined)).toBe(""); }); diff --git a/ui/storybook/prototypes/ConnectionPoolConnectorHost.tsx b/ui/storybook/prototypes/ConnectionPoolConnectorHost.tsx index e5dbc35bde..4cc9631e5e 100644 --- a/ui/storybook/prototypes/ConnectionPoolConnectorHost.tsx +++ b/ui/storybook/prototypes/ConnectionPoolConnectorHost.tsx @@ -26,7 +26,7 @@ export function ConnectionPoolConnectorHost({ pluginKey = "example.pool-router", useEffect(() => { const previous = window.fetch; const catalog = [aiConnectionRouterAppDefinition(pluginKey, descriptor, scenario === "unavailable" ? { available: false, reason: "Ask your instance operator to enable AI connection routing." } : { available: true }), ...["openai", "anthropic", "openrouter", "github"].map(slug => getAppStoreDefinition(slug)!)]; - let pools: AiConnectionPool[] = ["setup", "empty", "catalog", "unavailable"].includes(scenario) ? [] : [{ id: poolId, companyId, pluginKey, name: "Research accounts", enabled: false, mode: ["usage", "exhausted", "unknown"].includes(scenario) ? "usage_aware" : "round_robin", thresholdPercent: 90, revision: 1, members: poolStoryAccounts.slice(0, 2).map((account, index) => ({ id: `20000000-0000-4000-8000-00000000000${index + 1}`, binding: { mode: "delegated", provider: account.provider, method: account.method, connectionId: account.id, grantId: account.grantId }, profile: index === 0 ? { provider: "codex", model: "gpt-5.6-sol" } : { provider: "acpx", acpxAgent: "claude", model: "claude-sonnet-5" } })) }]; + let pools: AiConnectionPool[] = ["setup", "empty", "catalog", "unavailable"].includes(scenario) ? [] : [{ id: poolId, companyId, pluginKey, name: "Research accounts", enabled: false, mode: ["usage", "exhausted", "unknown"].includes(scenario) ? "usage_aware" : "round_robin", thresholdPercent: 90, revision: 1, members: poolStoryAccounts.slice(0, 2).map((account, index) => ({ id: `20000000-0000-4000-8000-00000000000${index + 1}`, binding: { mode: "delegated", provider: account.provider, method: account.method, connectionId: account.id, grantId: account.grantId }, profile: index === 0 ? { provider: "codex", model: "gpt-6.1-sol" } : { provider: "acpx", acpxAgent: "claude", model: "claude-sonnet-5" } })) }]; const accounts = scenario === "empty" ? [] : scenario === "revoked" ? poolStoryAccounts.slice(1) : poolStoryAccounts; const applications = (): ToolApplication[] => catalog.map(app => ({ id: `app-${app.slug}`, companyId, applicationKey: app.aiConnectionRouter ? `plugin:${pluginKey}:ai-router` : `app-gallery:${app.slug}`, name: app.name, description: app.description, type: app.aiConnectionRouter ? "paperclip_plugin" : "mcp_http", status: "active", pluginId: app.aiConnectionRouter ? "plugin-storybook" : null, ownerAgentId: null, ownerUserId: "dotta", metadata: { sourceTemplateKey: app.slug }, archivedAt: null, createdAt: date, updatedAt: date })); const connections = (): ToolConnection[] => [...accounts.map(account => ({ id: account.id, name: account.name, enabled: true, slug: account.provider, config: { sourceTemplateKey: account.provider, ai: { provider: account.provider, method: account.method }, aiIsolatedSubscription: true } })), ...pools.map(pool => ({ id: pool.id, name: pool.name, enabled: pool.enabled, slug: aiConnectionRouterSlug(pluginKey), config: { aiRouter: { pluginKey }, sourceTemplateKey: aiConnectionRouterSlug(pluginKey) } }))].map(row => ({ id: row.id, companyId, applicationId: `app-${row.slug}`, name: row.name, uid: row.id, connectionKind: "managed", ownership: "customer", connectionPurpose: "ai", transport: "runtime_auth", authKind: "none", credentialSource: "paperclip_vault", credentialPolicy: "per_user", status: "active", enabled: row.enabled, transportConfig: {}, config: row.config, credentialSecretRefs: [], healthStatus: "ok", healthCheckedAt: date, healthMessage: null, lastError: null, createdByAgentId: null, createdByUserId: "dotta", createdAt: date, updatedAt: date })); diff --git a/ui/storybook/prototypes/agent-settings/AgentSettingsPreview.tsx b/ui/storybook/prototypes/agent-settings/AgentSettingsPreview.tsx index 6ffff13ddc..65a6ff5a8c 100644 --- a/ui/storybook/prototypes/agent-settings/AgentSettingsPreview.tsx +++ b/ui/storybook/prototypes/agent-settings/AgentSettingsPreview.tsx @@ -86,7 +86,7 @@ export function AgentSettingsPreview({ const [fixtures] = useState(() => { const fixtures = createSettingsFixtures(adapterType, testOutcome, saveFails); if (adapterType === "codex_local" || adapterType === "paperclip_runner") { - fixtures.agent.adapterConfig = { ...fixtures.agent.adapterConfig, model: "gpt-5.6-sol", modelReasoningEffort: "high", ...(adapterType === "paperclip_runner" ? { provider: "codex" } : {}) }; + fixtures.agent.adapterConfig = { ...fixtures.agent.adapterConfig, model: "gpt-6.1-sol", modelReasoningEffort: "high", ...(adapterType === "paperclip_runner" ? { provider: "codex" } : {}) }; } return fixtures; }); diff --git a/ui/storybook/prototypes/composer-model-picker/fixtures.ts b/ui/storybook/prototypes/composer-model-picker/fixtures.ts index 711d81b7ef..b8efa3b349 100644 --- a/ui/storybook/prototypes/composer-model-picker/fixtures.ts +++ b/ui/storybook/prototypes/composer-model-picker/fixtures.ts @@ -21,7 +21,8 @@ export type ComposerAgent = { }; const codexModels: ModelOption[] = [ - { id: "gpt-5.6-sol", label: "GPT-5.6 Sol", detail: "Agent default" }, + { id: "gpt-6.1-sol", label: "GPT-6.1 Sol", detail: "Agent default" }, + { id: "gpt-5.6-sol", label: "GPT-5.6 Sol" }, { id: "gpt-6-astra", label: "GPT-6 Astra", detail: "Extended effort range" }, { id: "gpt-5.6-terra", label: "GPT-5.6 Terra" }, { id: "gpt-5.6-luna", label: "GPT-5.6 Luna" }, @@ -30,7 +31,7 @@ const codexModels: ModelOption[] = [ ]; export const composerAgents: ComposerAgent[] = [ - { id: "codex", name: "Codie", role: "Engineering", harness: "Codex", adapterType: "codex_local", defaultModel: "gpt-5.6-sol", models: codexModels, manualPattern: "Model ID, e.g. gpt-5.6-sol" }, + { id: "codex", name: "Codie", role: "Engineering", harness: "Codex", adapterType: "codex_local", defaultModel: "gpt-6.1-sol", models: codexModels, manualPattern: "Model ID, e.g. gpt-6.1-sol" }, { id: "claude", name: "Clara", role: "Research", harness: "Claude Code", adapterType: "claude_local", defaultModel: "claude-sonnet-5", models: [ { id: "claude-sonnet-5", label: "Claude Sonnet 5" }, { id: "claude-opus-5", label: "Claude Opus 5" }, @@ -62,7 +63,7 @@ export const composerAgents: ComposerAgent[] = [ { id: "sonnet-4.6", label: "Sonnet 4.6" }, ], manualPattern: "Cursor model ID" }, { id: "cursor-cloud", name: "Cloudy", role: "Remote engineering", harness: "Cursor Cloud", adapterType: "cursor_cloud", defaultLabel: "Account default", models: [], manualPattern: "Cursor Cloud model ID" }, - { id: "runner", name: "Runa", role: "Operations", harness: "Paperclip Runner", adapterType: "paperclip_runner", provider: "Codex profile", defaultModel: "gpt-5.6-sol", models: codexModels, manualPattern: "Codex model ID" }, + { id: "runner", name: "Runa", role: "Operations", harness: "Paperclip Runner", adapterType: "paperclip_runner", provider: "Codex profile", defaultModel: "gpt-6.1-sol", models: codexModels, manualPattern: "Codex model ID" }, { id: "grok", name: "Grok", role: "Investigation", harness: "Grok CLI", adapterType: "grok_local", defaultModel: "grok-build", models: [ { id: "grok-build", label: "Grok Build" }, { id: "grok-4.7", label: "Grok 4.7" }, @@ -86,9 +87,9 @@ export const composerAgents: ComposerAgent[] = [ { id: "kimi-code/kimi-for-coding", label: "K2.8 Preview" }, { id: "kimi-code/k3", label: "K3" }, ], manualPattern: "kimi-code/model" }, - { id: "long-labels", name: "Alexandra Engineering Coordinator", role: "Engineering", harness: "Codex", adapterType: "codex_local", defaultModel: "gpt-5.6-sol", models: [ - { id: "gpt-5.6-sol", label: "GPT-5.6 Sol Extended Context Preview", detail: "Agent default" }, - ], manualPattern: "Model ID, e.g. gpt-5.6-sol" }, + { id: "long-labels", name: "Alexandra Engineering Coordinator", role: "Engineering", harness: "Codex", adapterType: "codex_local", defaultModel: "gpt-6.1-sol", models: [ + { id: "gpt-6.1-sol", label: "GPT-6.1 Sol Extended Context Preview", detail: "Agent default" }, + ], manualPattern: "Model ID, e.g. gpt-6.1-sol" }, ]; /** Share the capsule-avatar palettes used by the agent persona stories. */ diff --git a/ui/storybook/stories/runs-adapters/connection-pools.stories.tsx b/ui/storybook/stories/runs-adapters/connection-pools.stories.tsx index bbb6f63f08..af73674dcd 100644 --- a/ui/storybook/stories/runs-adapters/connection-pools.stories.tsx +++ b/ui/storybook/stories/runs-adapters/connection-pools.stories.tsx @@ -18,19 +18,19 @@ const pool: AiConnectionPool = { id: poolId, companyId, pluginKey: "paperclip-cloud.plugin-connection-pool", revision: 3, name: "Research accounts", enabled: true, mode: "round_robin", thresholdPercent: 90, members: [ - { id: "20000000-0000-4000-8000-000000000001", binding: { mode: "delegated", provider: "openai", method: "subscription", connectionId: "30000000-0000-4000-8000-000000000001", grantId: "40000000-0000-4000-8000-000000000001" }, profile: { provider: "codex", model: "gpt-5.6-sol", effort: "high" } }, + { id: "20000000-0000-4000-8000-000000000001", binding: { mode: "delegated", provider: "openai", method: "subscription", connectionId: "30000000-0000-4000-8000-000000000001", grantId: "40000000-0000-4000-8000-000000000001" }, profile: { provider: "codex", model: "gpt-6.1-sol", effort: "high" } }, { id: "20000000-0000-4000-8000-000000000002", binding: { mode: "delegated", provider: "anthropic", method: "subscription", connectionId: "30000000-0000-4000-8000-000000000002", grantId: "40000000-0000-4000-8000-000000000002" }, profile: { provider: "acpx", acpxAgent: "claude", model: "claude-sonnet-5" } }, ], }; const accounts: AiConnectionList = { currentUserId: "user-board", canManageConnections: true, pools: [pool], connections: pool.members.map((m, index) => ({ id: m.binding.connectionId!, grantId: m.binding.grantId!, companyId, provider: m.binding.provider, method: m.binding.method!, name: index === 0 ? "My OpenAI subscription" : "My Claude subscription", ownership: "personal", ownerUserId: "user-board", isDefault: true, status: "connected", })) }; -const models = [{ id: "gpt-5.6-sol", label: "GPT-5.6 Sol · Codex" }, { id: "claude-sonnet-5", label: "Claude Sonnet 5 · Claude ACP" }]; -const agent: Agent = { ...storybookAgents.find(a => a.id === agentId)!, adapterType: "paperclip_runner", adapterConfig: { provider: "codex", model: "gpt-5.6-sol" }, runtimeConfig: { aiConnection: { mode: "router", connectionId: poolId } } }; +const models = [{ id: "gpt-6.1-sol", label: "GPT-6.1 Sol · Codex" }, { id: "claude-sonnet-5", label: "Claude Sonnet 5 · Claude ACP" }]; +const agent: Agent = { ...storybookAgents.find(a => a.id === agentId)!, adapterType: "paperclip_runner", adapterConfig: { provider: "codex", model: "gpt-6.1-sol" }, runtimeConfig: { aiConnection: { mode: "router", connectionId: poolId } } }; type Scenario = "overview" | "selector" | "legacy" | "adoption" | "unavailable" | "read-only" | "models" | "effort" | "mobile" | "claude-model" | "quota" | "checking" | "run-codex" | "run-claude" | "fallback" | "retry"; function PoolComposer({ scenario }: { scenario: Scenario }) { - const [settings, setSettings] = useState({ model: scenario === "claude-model" ? "claude-sonnet-5" : "gpt-5.6-sol", effort: null, fast: false }); + const [settings, setSettings] = useState({ model: scenario === "claude-model" ? "claude-sonnet-5" : "gpt-6.1-sol", effort: null, fast: false }); return

Choose settings for the next turn. The task keeps its account and harness.