Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/concepts/unified-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ The only required change is model selection. Everything else stays unchanged.

| Model | Alias |
|---|---|
| GPT-5.4 | `gpt-5.4` |
| GPT-5.4 Pro | `gpt-5.4-pro` |
| GPT-5.3 Codex | `gpt-5.3-codex` |
| GPT-5.3 Codex Spark | `gpt-5.3-codex-spark` |
| GPT-5.2 Codex | `gpt-5.2-codex` |
Expand All @@ -76,7 +78,7 @@ The only required change is model selection. Everything else stays unchanged.
Locus infers the provider from the model name:

1. Known Claude aliases (`opus`, `sonnet`, `haiku`) → Claude
2. Known Codex aliases → Codex
2. Known Codex models (`gpt-5.4`, `gpt-5.4-pro`, `gpt-5.3-codex`, etc.) → Codex
3. Model name starts with `claude-` → Claude
4. Model name contains `codex` → Codex

Expand Down
16 changes: 16 additions & 0 deletions packages/cli/__tests__/codex-runner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,20 @@ describe("buildCodexArgs", () => {
expect(args).not.toContain("--approval-mode");
expect(args.at(-1)).toBe("-");
});

test("includes gpt-5.4 model", () => {
const args = buildCodexArgs("gpt-5.4");

expect(args).toContain("--model");
expect(args).toContain("gpt-5.4");
expect(args.at(-1)).toBe("-");
});

test("includes gpt-5.4-pro model", () => {
const args = buildCodexArgs("gpt-5.4-pro");

expect(args).toContain("--model");
expect(args).toContain("gpt-5.4-pro");
expect(args.at(-1)).toBe("-");
});
});
25 changes: 25 additions & 0 deletions packages/cli/__tests__/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,17 @@ describe("config", () => {
expect(config.ai.provider).toBe("codex");
expect(config.ai.model).toBe("gpt-5.3-codex");
});

it("infers codex provider from gpt-5.4 model on load", () => {
setupProject({
version: "3.0.0",
github: { owner: "custom", repo: "mine", defaultBranch: "develop" },
ai: { provider: "claude", model: "gpt-5.4" },
});
const config = loadConfig(TEST_DIR);
expect(config.ai.provider).toBe("codex");
expect(config.ai.model).toBe("gpt-5.4");
});
});

describe("saveConfig", () => {
Expand Down Expand Up @@ -175,6 +186,20 @@ describe("config", () => {
expect(updated.ai.provider).toBe("codex");
});

it("updates provider when model changes to gpt-5.4", () => {
setupProject();
const updated = updateConfigValue(TEST_DIR, "ai.model", "gpt-5.4");
expect(updated.ai.model).toBe("gpt-5.4");
expect(updated.ai.provider).toBe("codex");
});

it("updates provider when model changes to gpt-5.4-pro", () => {
setupProject();
const updated = updateConfigValue(TEST_DIR, "ai.model", "gpt-5.4-pro");
expect(updated.ai.model).toBe("gpt-5.4-pro");
expect(updated.ai.provider).toBe("codex");
});

it("auto-coerces string 'true' to boolean", () => {
setupProject();
const updated = updateConfigValue(TEST_DIR, "agent.autoLabel", "false");
Expand Down
13 changes: 13 additions & 0 deletions packages/cli/__tests__/repl-model-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,17 @@ describe("repl model config persistence", () => {
expect(reloaded.ai.model).toBe("gpt-5.3-codex");
expect(reloaded.ai.provider).toBe("codex");
});

it("persists gpt-5.4 model and infers codex provider", () => {
const inMemoryConfig = loadConfig(TEST_DIR);

persistReplModelSelection(TEST_DIR, inMemoryConfig, "gpt-5.4");

expect(inMemoryConfig.ai.model).toBe("gpt-5.4");
expect(inMemoryConfig.ai.provider).toBe("codex");

const reloaded = loadConfig(TEST_DIR);
expect(reloaded.ai.model).toBe("gpt-5.4");
expect(reloaded.ai.provider).toBe("codex");
});
});
2 changes: 2 additions & 0 deletions packages/cli/src/core/ai-models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const CLAUDE_MODELS = [
] as const;

const CODEX_MODELS = [
"gpt-5.4",
"gpt-5.4-pro",
"gpt-5.3-codex",
"gpt-5.3-codex-spark",
"gpt-5.2-codex",
Expand Down