Skip to content

[codex] assign IDs to normalized prompt outputs#30311

Closed
wsong-oai wants to merge 1 commit into
mainfrom
wsong/fix-synthetic-tool-output-item-ids
Closed

[codex] assign IDs to normalized prompt outputs#30311
wsong-oai wants to merge 1 commit into
mainfrom
wsong/fix-synthetic-tool-output-item-ids

Conversation

@wsong-oai

Copy link
Copy Markdown

Summary

  • Run the existing response-item ID allocator after ContextManager::for_prompt normalization.
  • Route regular turns, retry rebuilds, prompt debug, and local/remote compaction prompts through that finalization step.
  • Add integration coverage for a resumed call whose missing output is synthesized during normalization.

Root cause

item_ids assigns IDs at the durable history-recording boundary. Later, for_prompt can synthesize an "aborted" call output for an unmatched call. That prompt-only output bypassed the allocation boundary and serialized without an ID, which breaks consumers that require IDs for every rendered response item.

This keeps the existing feature gate and type-specific UUIDv7 allocator instead of weakening the downstream invariant. Related: #28814.

Validation

  • just test -p codex-core --test all normalized_call_outputs_receive_item_ids
  • cargo fmt --check
  • Attempted just test -p codex-core; currently blocked on main by the unrelated CreateThreadParams initializer missing history_mode in core/src/session/tests.rs:7006.

@wsong-oai wsong-oai requested a review from a team as a code owner June 26, 2026 23:00
@github-actions

Copy link
Copy Markdown
Contributor


Thank you for your submission, we really appreciate it. Like many open-source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution. You can sign the CLA by just posting a Pull Request Comment same as the below format.


I have read the CLA Document and I hereby sign the CLA


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4f3fd29028

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

items: Vec<ResponseItem>,
) -> Vec<ResponseItem> {
if turn_context.config.features.enabled(Feature::ItemIds) {
Self::assign_missing_response_item_ids(Cow::Owned(items)).into_owned()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep prompt-only item IDs stable across retries

When item_ids is enabled and normalization synthesizes a missing call output, this assigns a fresh UUID only in the prompt clone without recording it back to history. Any later prompt rebuild from the same history (for example a sampling retry, another turn after resuming the rollout, or a compaction retry) renders the same synthetic output with a different id, changing model-visible context and defeating prompt-cache reuse; it also means consumers still cannot rely on persistent IDs for normalized outputs. Consider deriving the synthetic ID from stable fields such as call_id, or installing the synthesized output/ID into history before prompt serialization.

AGENTS.md reference: AGENTS.md:L91-L97

Useful? React with 👍 / 👎.

bolinfest added a commit that referenced this pull request Jun 27, 2026
## Why

Response item IDs represent stable conversation identity.
`ContextManager::for_prompt` repairs an unmatched call by synthesizing
an `"aborted"` output in the disposable prompt projection, but that
output previously had no ID. Assigning a fresh ID on every prompt build
would make retries and resumes change otherwise identical model context
and reduce prompt-cache reuse.

The concrete bug is that these normalization-created outputs bypass the
regular item-ID allocation path. Even with item IDs enabled, a prompt
could therefore contain an identified call paired with a synthetic
output whose `id` was missing. This change closes that gap by deriving
the output ID from the source call's item ID. For legacy calls that have
no item ID, the output remains ID-less because there is no stable source
identity to derive from.

The originating call already has a stable item ID under the item-ID
model introduced in #28814. A prompt-only output can therefore derive
stable identity from that call without mutating canonical history or
persisted rollouts. This addresses the failure exposed by #30311 while
keeping normalization read-only outside its detached prompt snapshot.

UUIDv5 is intentional here because it is the standard namespaced,
deterministic UUID construction. Using the output kind and source call
ID as the name produces the same UUID on every projection while keeping
output kinds in separate name domains. UUIDv7 would introduce randomness
and time, so keeping it stable would require persisting the synthetic
repair. UUIDv5 uses SHA-1 internally, but this is only an identity
mapping—not an authenticity or security boundary.

## What changed

- Derive a deterministic UUIDv5 ID for each synthesized call output from
the source call item ID.
- Use the Responses API prefix appropriate for function, custom-tool,
tool-search, and local-shell outputs.
- Preserve the existing insertion position immediately after the
unmatched call.
- Keep synthesized outputs prompt-only; no rollout, task-lifecycle,
compaction, or raw-response behavior changes.

## Testing

- `just test -p codex-core
for_prompt_assigns_stable_id_to_synthetic_output_without_reordering_history`
- `just test -p codex-core
synthetic_call_output_id_is_stable_across_resumes`
- `just test -p codex-core normalize_adds_missing_output`
- `just test -p codex-core response_item_ids`
@wsong-oai wsong-oai closed this Jun 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant