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
5 changes: 3 additions & 2 deletions src/codex/inject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1430,7 +1430,7 @@ export async function injectCodexConfig(
const historyMessage =
keepRootOverrideAlongsideTable
? (keptUserBaseUrl
? ` Codex resume history: left unchanged; threads already tagged openai follow your own root openai_base_url, not the proxy.\n`
? ` Codex resume history: left unchanged; threads already tagged openai follow your configured root openai_base_url.\n`
: ` Codex resume history: left unchanged; existing threads keep reaching the proxy through the retained openai_base_url override.\n`)
: config?.syncResumeHistory === false
? ` Codex resume history: left unchanged (syncResumeHistory=false).\n`
Expand All @@ -1447,6 +1447,7 @@ export async function injectCodexConfig(
// The client-compaction form writes a provider table as well, so "nothing was injected" would
// misdescribe the file it just produced: new threads do use the injected table. Report that
// mixed result on its own terms, and never tell the operator to delete a setting of theirs.
// Ownership alone says nothing about destination: their line may already target this proxy.
if (keptUserBaseUrl && keepRootOverrideAlongsideTable) {
return {
success: true,
Expand All @@ -1459,7 +1460,7 @@ export async function injectCodexConfig(
managedDefaultsMessage +
` New threads use the injected opencodex provider and route through the proxy.\n` +
` Threads already tagged openai resolve through Codex's built-in provider, which your root openai_base_url points at.\n` +
` Remove that line and rerun 'ocx start' only if you want those threads on the proxy too.\n` +
` No root URL change is required to enable client-side compaction for new threads.\n` +
` Fallback: codex --profile opencodex (same behavior)`,
};
}
Expand Down
6 changes: 6 additions & 0 deletions structure/02_config-and-codex-home.md
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,12 @@ explicitly runs legacy OpenAI recovery. A user-owned root `openai_base_url` is p
overwritten, and that case also blocks managed sub-agent defaults rather than fighting the user for
ownership.

Client-compaction mode can retain that user-owned root URL alongside an injected provider table.
Its status must distinguish ownership from destination: an unmarked user-owned line may already
point to this proxy. Report that existing `openai` threads follow the configured root URL and new
threads use the injected table, without inferring a foreign endpoint or prescribing URL removal.
This diagnostic distinction does not change URL ownership, journal entries, or session history.

**API auth header (non-loopback).** The built-in `openai` provider cannot carry the
`x-opencodex-api-key` env header, so this form re-tags the root provider and appends the table:

Expand Down
28 changes: 27 additions & 1 deletion tests/codex-integration/codex-inject-integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -934,7 +934,33 @@ describe("injectCodexConfig integration (Design B)", () => {
expect(message).not.toContain("Codex routing NOT injected");
expect(message).not.toContain("remove your openai_base_url line");
expect(message).toContain("left exactly as you set it");
expect(message).toContain("follow your own root openai_base_url, not the proxy");
expect(message).toContain("follow your configured root openai_base_url");
expect(message).not.toContain("not the proxy");
expect(message).not.toContain("Remove that line");
});

test("client compaction does not mistake a user-owned proxy URL for a foreign destination (#4110)", () => {
// The URL equals the target but lacks our marker: keep ownership separate from destination.
const rootLine = 'openai_base_url = "http://127.0.0.1:10100/v1"';
writeFileSync(join(codexHome, "config.toml"), `${rootLine}\nmodel = "gpt-5.5"\n`, "utf8");

const enabled = runInject(codexHome, ocxHome, JSON.stringify({ codexClientCompaction: true }));
expect(enabled.status).toBe(0);
const config = readFileSync(join(codexHome, "config.toml"), "utf8");
expect(config).toContain(rootLine);
expect(config.match(/openai_base_url/g)?.length).toBe(1);
expect(config).toContain('model_provider = "opencodex"');
expect(config).toContain("[model_providers.opencodex]");
const journal = JSON.parse(readFileSync(join(codexHome, "opencodex-journal.json"), "utf8"));
expect(journal.injectedOpenaiBaseUrl).toBeNull();

const message = String(JSON.parse(enabled.stdout).message);
expect(message).toContain("Injected opencodex as default provider");
expect(message).toContain("left exactly as you set it");
expect(message).toContain("follow your configured root openai_base_url");
expect(message).not.toContain("not the proxy");
expect(message).not.toContain("Remove that line");
expect(message).not.toContain("Codex routing NOT injected");
});

test("the managed override keeps reporting proxy routing for existing threads", () => {
Expand Down
Loading