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: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ OpenAI Codex ("Login with ChatGPT") for `@intx/inference`: the OAuth client conf
## Why @corbits/codex-provider?

1. **Inference on a ChatGPT subscription.** Codex has no API-key path. This package supplies the PKCE login config, the code exchange and refresh, and the `chatgpt-account-id` the backend requires on every request.
2. **The exact request Codex accepts.** `store: false`, `parallel_tool_calls: false`, no `max_output_tokens`, the host prompt as a leading `developer` message, and the Codex CLI's `originator` header are fixed in the adapter, not left to each host.
2. **The exact request Codex accepts.** `store: false`, `parallel_tool_calls: true`, no `max_output_tokens`, the host prompt as a leading `developer` message, and the Codex CLI's `originator` header are fixed in the adapter, not left to each host.
3. **Backend bugs repaired, host identity required.** `withCodexContentTypeRepair` restores the `content-type` the backend drops on some SSE streams. The host names itself through `CodexQuirks`; there is no default product name.

## Install

```bash
bun add @corbits/codex-provider @corbits/oauth-core@^0.2.0 @corbits/openai-responses@^0.2.0 @intx/inference@^0.4.0 @intx/types@^0.4.0
bun add @corbits/codex-provider @corbits/oauth-core@^0.2.0 @corbits/openai-responses@^0.2.4 @intx/inference@^0.4.0 @intx/types@^0.4.0
```

Runs on Bun >= 1.2 or Node >= 24.
Expand Down
6 changes: 3 additions & 3 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
},
"devDependencies": {
"@corbits/oauth-core": "0.3.4",
"@corbits/openai-responses": "0.2.3",
"@corbits/openai-responses": "0.2.4",
"@intx/inference": "0.5.0",
"@intx/types": "0.5.0",
"@types/bun": "1.3.14",
Expand All @@ -63,7 +63,7 @@
},
"peerDependencies": {
"@corbits/oauth-core": "^0.3.4",
"@corbits/openai-responses": "^0.2.3",
"@corbits/openai-responses": "^0.2.4",
"@intx/inference": "^0.5.0",
"@intx/types": "^0.5.0"
},
Expand Down
8 changes: 4 additions & 4 deletions src/responses-adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ function parseCodexBody(rawBody: string) {
// chatgpt-account-id header only rides when the option is set, session_id
// rides in both the header and the body, `instructions` is omitted (the
// host's own system prompt leads `input` as a wrapped developer message),
// and the three fields the backend requires explicit values for (`store`,
// `parallel_tool_calls`, `max_output_tokens`) are on the wire correctly.
// `store` and `max_output_tokens` are set as the backend requires, and
// `parallel_tool_calls` is on.
describe("Codex responses adapter — request shape", () => {
test("throws when the quirks bag is absent — there is no honest default product name", () => {
expect(() => createCodexResponsesAdapter(source, undefined)).toThrow();
Expand Down Expand Up @@ -104,13 +104,13 @@ describe("Codex responses adapter — request shape", () => {
expect(bridgeText).toContain("operate carefully");
});

test("always sends store:false and parallel_tool_calls:false, and omits max_output_tokens", () => {
test("always sends store:false and parallel_tool_calls:true, and omits max_output_tokens", () => {
const adapter = createCodexResponsesAdapter(source, quirks);
const request = adapter.buildRequest(turns, "gpt-5.5", { maxTokens: 4096 });
const body = parseCodexBody(request.body);

expect(body.store).toBe(false);
expect(body.parallel_tool_calls).toBe(false);
expect(body.parallel_tool_calls).toBe(true);
expect(body.max_output_tokens).toBeUndefined();
});

Expand Down
6 changes: 3 additions & 3 deletions src/responses-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import {
import { wrapCodexBridgeMessage } from "./instructions.js";
import { parseCodexQuirks, type CodexQuirks } from "./quirks.js";

// `store` and `parallelToolCalls` need an explicit `false` on the wire, and
// `maxOutputTokens: false` because the backend 400s on `max_output_tokens`.
// `store` needs an explicit `false` on the wire, and `maxOutputTokens: false`
// omits `max_output_tokens`, which the backend 400s on.
function codexResponsesQuirks(quirks: CodexQuirks): ResponsesQuirks {
return {
path: CODEX_RESPONSES_PATH,
Expand All @@ -37,7 +37,7 @@ function codexResponsesQuirks(quirks: CodexQuirks): ResponsesQuirks {
systemPrompt: { role: "developer", shape: "parts" },
contentShape: "typed",
store: false,
parallelToolCalls: false,
parallelToolCalls: true,
maxOutputTokens: false,
reasoning: {
effortOption: CODEX_REASONING_EFFORT_OPTION,
Expand Down
Loading