Skip to content

Commit 18e2487

Browse files
Merge pull request #784 from corbitsdev/cl-6694-track-parallel_tool_calls-and-responses-continuity-as-follow
Document Codex Responses continuity and serial tool calls
2 parents e2cb803 + e3a2fb7 commit 18e2487

3 files changed

Lines changed: 16 additions & 2 deletions

File tree

docs/IMPLEMENTATION.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ Positional arguments after flags are joined into the optional initial task deliv
358358

359359
- OpenAI-compatible chat completions, streamed via `@intx/inference`
360360
- JSON-schema tool definitions for director-layer tools (`ask_operator`, `present`, `submit_output`) and agent tools (`manage_tasks`, `tool_search`, `use_skill`, `search_agents`, …)
361+
- Codex Responses (`codex-responses-adapter.ts` `buildRequest`): ChatGPT Codex is Responses-only. It requires `store: false` (`store: true` → 400) and rejects `previous_response_id`. Multi-turn continuity is full `input` replay; encrypted reasoning captured via `include: ["reasoning.encrypted_content"]` is resent as a `reasoning` item. `prompt_cache_key` (session id) is the cache-routing signal. `parallel_tool_calls` is sent `false` (serial at this surface); the reactor already fans out a multi-call batch concurrently. `max_output_tokens` is omitted (backend rejects it).
361362

362363
### State Persistence
363364

src/provider/codex-responses-adapter.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,15 @@ import { PRODUCT_NAME, ENVIRONMENT_TAG_NAME } from "../branding.js";
3030
// Credentials and the chatgpt-account-id ride through differently: the access
3131
// token is injected by the harness via the bearer sentinel, while the account
3232
// id and session id travel in `source.defaults.providerOptions` (merged into
33-
// InferenceOptions.providerOptions by the harness) and are lifted into headers
34-
// here. Neither is placed in the request body.
33+
// InferenceOptions.providerOptions by the harness). Account id is headers-only
34+
// (`chatgpt-account-id`). Session id is the `session_id` header and
35+
// `prompt_cache_key` in the body — the only cache-routing signal under
36+
// `store: false`.
37+
//
38+
// Continuity is not Responses store chaining. The ChatGPT Codex backend
39+
// requires `store: false` (`store: true` → 400) and rejects
40+
// `previous_response_id`. Every turn resends the full `input`; encrypted
41+
// reasoning captured from the prior stream is resent as a `reasoning` item.
3542

3643
export const CODEX_RESPONSES_PROVIDER = "codex-responses";
3744

@@ -342,6 +349,10 @@ function buildRequest(
342349
store: false,
343350
stream: true,
344351
include: ["reasoning.encrypted_content"],
352+
// Serial at the request layer. The reactor already executes a multi-call
353+
// batch concurrently; this flag is what the ChatGPT Codex backend is sent.
354+
// Do not flip without verifying the backend accepts true — unlike store /
355+
// previous_response_id there is no recorded 400.
345356
parallel_tool_calls: false,
346357
};
347358
// The Codex backend rejects `max_output_tokens`; it is intentionally omitted.

tests/unit/codex-responses-adapter.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ describe("codex-responses buildRequest", () => {
4747
expect(body["model"]).toBe("gpt-5-codex");
4848
expect(body["stream"]).toBe(true);
4949
expect(body["store"]).toBe(false);
50+
expect(body).not.toHaveProperty("previous_response_id");
51+
expect(body["parallel_tool_calls"]).toBe(false);
5052
expect(body["include"]).toEqual(["reasoning.encrypted_content"]);
5153
expect(body["prompt_cache_key"]).toBe("sess-1");
5254
expect(body["input"]).toEqual([

0 commit comments

Comments
 (0)