feat(codex): add GPT-6 Sol support

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Devin FoleyandPaperclip committed 2026-09-22 13:36:21 -07:00
1 parent a10702a878
commit 240e5759c3
7 files changed
+29 -24

No files matched your search

@@ -14,21 +14,23 @@ describe("codex local adapter metadata", () => {
// 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");
expect(modelIds.slice(0, 4)).toEqual([
expect(modelIds.slice(0, 5)).toEqual([
"gpt-5.6-sol",
"gpt-6-astra",
"gpt-6-sol",
"gpt-5.6-terra",
"gpt-5.6-luna",
]);
expect(modelIds).not.toContain("gpt-5.6");
expect(isCodexLocalFastModeSupported(DEFAULT_CODEX_LOCAL_MODEL)).toBe(true);
expect(isCodexLocalFastModeSupported("gpt-6-astra")).toBe(true);
expect(isCodexLocalFastModeSupported("gpt-6-sol")).toBe(true);
expect(modelIds).not.toContain("gpt-5.3-codex");
expect(modelIds).not.toContain("gpt-5.3-codex-spark");
});
it("uses the reasoning efforts advertised for GPT-6 Astra", () => {
expect(codexLocalReasoningEffortsForModel("gpt-6-astra")).toEqual([
it.each(["gpt-6-astra", "gpt-6-sol", " gpt-6-sol "])("uses the reasoning efforts advertised for %s", (model) => {
expect(codexLocalReasoningEffortsForModel(model)).toEqual([
"low",
"medium",
"high",
+10 -7
View File
@@ -14,6 +14,7 @@ export const DEFAULT_CODEX_LOCAL_MODEL = PAPERCLIP_RUNNER_DEFAULT_MODELS.codex;
export const DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX = true;
export const CODEX_LOCAL_FAST_MODE_SUPPORTED_MODELS = [
"gpt-6-astra",
"gpt-6-sol",
"gpt-5.6-sol",
"gpt-5.6-terra",
"gpt-5.6-luna",
@@ -41,7 +42,7 @@ const CODEX_LOCAL_DEFAULT_REASONING_EFFORTS = [
"xhigh",
] as const;
const CODEX_LOCAL_ASTRA_REASONING_EFFORTS = [
const CODEX_LOCAL_GPT_6_REASONING_EFFORTS = [
"low",
"medium",
"high",
@@ -52,7 +53,7 @@ const CODEX_LOCAL_ASTRA_REASONING_EFFORTS = [
export type CodexLocalReasoningEffort =
| (typeof CODEX_LOCAL_DEFAULT_REASONING_EFFORTS)[number]
| (typeof CODEX_LOCAL_ASTRA_REASONING_EFFORTS)[number];
| (typeof CODEX_LOCAL_GPT_6_REASONING_EFFORTS)[number];
export function normalizeCodexModel(model: string | null | undefined): string {
const normalizedModel = normalizeModelId(model);
@@ -62,8 +63,9 @@ export function normalizeCodexModel(model: string | null | undefined): string {
export function codexLocalReasoningEffortsForModel(
model: string | null | undefined,
): readonly CodexLocalReasoningEffort[] {
return normalizeCodexModel(model) === "gpt-6-astra"
? CODEX_LOCAL_ASTRA_REASONING_EFFORTS
const normalizedModel = normalizeCodexModel(model);
return normalizedModel === "gpt-6-astra" || normalizedModel === "gpt-6-sol"
? CODEX_LOCAL_GPT_6_REASONING_EFFORTS
: CODEX_LOCAL_DEFAULT_REASONING_EFFORTS;
}
@@ -94,6 +96,7 @@ export const models = [
// DEFAULT_CODEX_LOCAL_MODEL is gpt-5.6-sol, so it doubles as the first (default) 5.6 entry.
{ id: DEFAULT_CODEX_LOCAL_MODEL, label: DEFAULT_CODEX_LOCAL_MODEL },
{ id: "gpt-6-astra", label: "gpt-6-astra" },
{ id: "gpt-6-sol", label: "gpt-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.4", label: "gpt-5.4" },
@@ -116,10 +119,10 @@ Core fields:
- cwd (string, optional): default absolute working directory fallback for the agent process (created if missing when possible)
- instructionsFilePath (string, optional): absolute path to a markdown instructions file prepended to stdin prompt at runtime
- model (string, optional): Codex model id
- modelReasoningEffort (string, optional): reasoning effort override passed via -c model_reasoning_effort=...; GPT-6 Astra supports low|medium|high|xhigh|max|ultra
- modelReasoningEffort (string, optional): reasoning effort override passed via -c model_reasoning_effort=...; GPT-6 Astra and Sol support low|medium|high|xhigh|max|ultra
- promptTemplate (string, optional): run prompt template
- search (boolean, optional): run codex with --search
- fastMode (boolean, optional): enable Codex Fast mode; supported on GPT-6 Astra, GPT-5.6 (sol/terra/luna), GPT-5.5, GPT-5.4 and passed through for manual model IDs
- fastMode (boolean, optional): enable Codex Fast mode; supported on GPT-6 Astra and Sol, GPT-5.6 (sol/terra/luna), GPT-5.5, GPT-5.4 and passed through for manual model IDs
- dangerouslyBypassApprovalsAndSandbox (boolean, optional): run with bypass flag
- command (string, optional): defaults to "codex"
- extraArgs (string[], optional): additional CLI args
@@ -150,7 +153,7 @@ Notes:
- Paperclip injects desired local skills into the effective CODEX_HOME/skills/ directory at execution time so Codex can discover "$paperclip" and related skills without polluting the project working directory. For new and updated agents, Paperclip assigns an isolated managed home at ~/.paperclip/instances/<id>/companies/<companyId>/agents/<agentId>/codex-home/skills/; when CODEX_HOME is explicitly overridden in adapter config, that override is used instead.
- New and updated codex_local agents persist an empty OPENAI_API_KEY override by default so a host-level OPENAI_API_KEY cannot leak into Codex runs through process inheritance. Explicit CODEX_HOME overrides must not point at the shared company codex-home, $CODEX_HOME, or ~/.codex.
- Some model/tool combinations reject certain effort levels (for example minimal with web search enabled).
- Fast mode is supported on GPT-6 Astra, GPT-5.6 (sol/terra/luna), GPT-5.5, GPT-5.4 and manual model IDs. When enabled for those models, Paperclip applies \`service_tier="fast"\` and \`features.fast_mode=true\`.
- Fast mode is supported on GPT-6 Astra and Sol, GPT-5.6 (sol/terra/luna), GPT-5.5, GPT-5.4 and manual model IDs. When enabled for those models, Paperclip applies \`service_tier="fast"\` and \`features.fast_mode=true\`.
- When Paperclip realizes a workspace/runtime for a run, it injects PAPERCLIP_WORKSPACE_* and PAPERCLIP_RUNTIME_* env vars for agent-side tooling.
- The ACP engine keeps its workspace sandbox and enables network access on each turn. Explicit sandbox_workspace_write.network_access overrides in extraArgs (or env.PAPERCLIP_CODEX_ACP_NETWORK_ACCESS="false") disable it; execution-target network denial wins. The bundled ACP patch is needed because upstream mode presets override Codex config.toml on every turn.
- The CLI engine defaults to a writable workspace sandbox with network access for unattended work and Paperclip API calls. It does not enable the dangerous bypass flag. Explicit sandbox modes/profiles and network overrides in extraArgs retain their meaning. An execution-target network denial remains enforced.
@@ -508,14 +508,14 @@ describe("codex_local ACP lane", () => {
});
});
it("forwards GPT-6 Astra controls to the ACPX Codex target", () => {
it.each(["gpt-6-astra", "gpt-6-sol"])("forwards %s controls to the ACPX Codex target", (model) => {
expect(buildCodexAcpConfig({
engine: "acp",
model: "gpt-6-astra",
model,
modelReasoningEffort: "ultra",
fastMode: true,
})).toMatchObject({
model: "gpt-6-astra",
model,
modelReasoningEffort: "ultra",
fastMode: true,
});
@@ -9,14 +9,14 @@ describe("buildCodexExecArgs", () => {
if (resumeSessionId) expect(args.slice(-3)).toEqual(["resume", resumeSessionId, "-"]);
});
it("forwards GPT-6 Astra, its ultra reasoning effort, and fast mode", () => {
it.each(["gpt-6-astra", "gpt-6-sol"])("forwards %s, its ultra reasoning effort, and fast mode", (model) => {
const result = buildCodexExecArgs({
model: "gpt-6-astra",
model,
modelReasoningEffort: "ultra",
fastMode: true,
});
expect(result.model).toBe("gpt-6-astra");
expect(result.model).toBe(model);
expect(result.fastModeApplied).toBe(true);
expect(result.fastModeIgnoredReason).toBeNull();
expect(result.args).toEqual([
@@ -24,7 +24,7 @@ describe("buildCodexExecArgs", () => {
"--json",
"--dangerously-bypass-approvals-and-sandbox",
"--model",
"gpt-6-astra",
model,
"-c",
'model_reasoning_effort="ultra"',
"-c",
@@ -148,7 +148,7 @@ describe("buildCodexExecArgs", () => {
expect(result.fastModeRequested).toBe(true);
expect(result.fastModeApplied).toBe(false);
expect(result.fastModeIgnoredReason).toContain(
"currently only supported on gpt-6-astra, gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4 or manually configured model IDs",
"currently only supported on gpt-6-astra, gpt-6-sol, gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4 or manually configured model IDs",
);
expect(result.args).toEqual([
"exec",
@@ -63,17 +63,17 @@ describe("buildCodexLocalConfig", () => {
});
});
it("persists the exact GPT-6 Astra model and supported controls", () => {
it.each(["gpt-6-astra", "gpt-6-sol"])("persists the exact %s model and supported controls", (model) => {
const config = buildCodexLocalConfig(
makeValues({
model: "gpt-6-astra",
model,
thinkingEffort: "ultra",
fastMode: true,
}),
);
expect(config).toMatchObject({
model: "gpt-6-astra",
model,
modelReasoningEffort: "ultra",
fastMode: true,
});
@@ -34,7 +34,7 @@ export const help: Record<string, string> = {
dangerouslySkipPermissions: "Run unattended by auto-approving adapter permission prompts when supported.",
dangerouslyBypassSandbox: "Run Codex without sandbox restrictions. Required for filesystem/network access.",
search: "Enable Codex web search capability during runs.",
fastMode: "Enable Codex Fast mode. This burns credits/tokens much faster and is supported on GPT-6 Astra, GPT-5.6, GPT-5.5, GPT-5.4, and manual Codex model IDs.",
fastMode: "Enable Codex Fast mode. This burns credits/tokens much faster and is supported on GPT-6 Astra and Sol, GPT-5.6, GPT-5.5, GPT-5.4, and manual Codex model IDs.",
workspaceStrategy: "How Paperclip should realize an execution workspace for this agent. Keep project_primary for normal cwd execution, or use git_worktree for issue-scoped isolated checkouts.",
workspaceBaseRef: "Base git ref used when creating a worktree branch. Leave blank to use the resolved workspace ref or HEAD.",
workspaceBranchTemplate: "Template for naming derived branches. Supports {{issue.identifier}}, {{issue.title}}, {{agent.name}}, {{project.id}}, {{workspace.repoRef}}, and {{slug}}.",
+2 -2
View File
@@ -4,8 +4,8 @@ import { describe, expect, it } from "vitest";
import { codexReasoningEffortOptions } from "./codex-reasoning-effort";
describe("codexReasoningEffortOptions", () => {
it("exposes only the supported GPT-6 Astra reasoning efforts", () => {
expect(codexReasoningEffortOptions("gpt-6-astra")).toEqual([
it.each(["gpt-6-astra", "gpt-6-sol"])("exposes only the supported %s reasoning efforts", (model) => {
expect(codexReasoningEffortOptions(model)).toEqual([
{ value: "", label: "Default" },
{ value: "low", label: "Low" },
{ value: "medium", label: "Medium" },