Preserve Programmatic Tool Calling caller linkage in App Server and rollouts
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
Summary
Codex currently drops the Responses API Programmatic Tool Calling parent relationship before App Server and rollout consumers can observe it. Preserve the upstream program / nested call / result / program_output relationship so clients can measure real nested tool execution without treating source text or temporal containment as runtime call identity.
Current observed boundary
I checked Codex CLI 0.149.1 and public main at dc08ace7821614a702b1214c9d08ae0db2634d82.
codex app-server generate-json-schema --experimentalexposescall_idon rawfunction_call,function_call_output,custom_tool_call, andcustom_tool_call_outputresponse items.- The generated
ResponseItemunion has noprogramorprogram_outputvariant and those call/result variants have nocallerfield. - v2
ThreadItemcall variants such ascommandExecution,fileChange, anddynamicToolCallhave a presentationid, status, and some duration fields, but no stable nestedcallIdor parentcaller. item/startedanditem/completedalready carrystartedAtMsandcompletedAtMsrespectively, so lifecycle timing exists but cannot be joined into the programmatic caller graph.- A real Codex rollout containing
functions.execprogrammatic calls persisted the outercustom_tool_call/custom_tool_call_outputand independently observed command/edit items, but no rawprogram,program_output, or nested caller-linked lifecycle rows.
This is not a claim that the current App Server documentation promises those fields. It is a request to preserve the separate, documented Responses API Programmatic Tool Calling relationship through Codex's protocol and persistence surfaces.
Upstream contract
The official Programmatic Tool Calling guide defines:
- a
programitem with its owncall_id; - program-issued calls with their own
call_idandcaller: { type: "program", caller_id: <program call id> }; - caller preservation when returning the matching call output; and
program_output.call_idmatching the program, with terminal status.
Guide: https://developers.openai.com/api/docs/guides/tools-programmatic-tool-calling
The App Server guide defines item/started and item/completed, with the completed item authoritative:
https://developers.openai.com/codex/app-server
Requested Codex behavior
- Extend the core raw response model so
programandprogram_outputround-trip without loss, and program-issued function/custom calls and outputs retain their optionalcaller { type, caller_id }. - Preserve those raw items unchanged in rollout JSONL and
rawResponseItem/completednotifications. - Add stable
callIdplus optionalcaller { type, callerId }to App ServerThreadItemcall variants. For programmatic calls, emit the same identifiers on bothitem/startedanditem/completed. - Keep presentation
id, lifecycle joincallId, and parent joincallerIddistinct. - Preserve started nested calls across failure, interruption, cancellation, and missing-result cases. Allow a nested call to be the caller of another call so the graph has arbitrary depth.
- Represent terminal state explicitly (
completed,failed,cancelled/interrupted, or the existing equivalent) and keep the existing lifecycle timestamps.
Equivalent names are fine if the protocol owns a different canonical vocabulary; the required information and stable joins are the contract.
Acceptance evidence
- Generated JSON Schema and TypeScript include the raw
program/program_outputvariants and caller fields, plus caller linkage on relevantThreadItemvariants. - Serialization round-trip tests prove caller preservation on both calls and outputs.
- App Server integration tests cover sequential siblings, parallel siblings, depth greater than one, failure, cancellation/interruption, and a started call with no result.
- A real rollout proves the same stable nested
callIdandcallerIdon lifecycle start/completion, while the outer orchestration envelope remains distinguishable from its nested operations.
Without those fields, consumers can still report independently observed commands and edits as unlinked lower-bound evidence, but cannot honestly claim complete nested-call attribution, depth, concurrency, or inclusive nested operational duration.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the core raw response model, generated JSON Schema and TypeScript unions, then trace App Server ThreadItem definitions, rollout JSONL, and rawResponseItem/completed notifications. Compare these surfaces with the linked Programmatic Tool Calling guide and existing lifecycle behavior; done means round-trip preservation and integration evidence for nested, parallel, failed, cancelled, and result-less calls.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust, typescript
- Domain
- api, backend, testing
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 28/100