Skip to content

[codex] add compaction metadata to turn headers#24368

Merged
ningyi-oai merged 4 commits into
mainfrom
dev/ningyi/turn_metadata_compaction
May 27, 2026
Merged

[codex] add compaction metadata to turn headers#24368
ningyi-oai merged 4 commits into
mainfrom
dev/ningyi/turn_metadata_compaction

Conversation

@ningyi-oai
Copy link
Copy Markdown
Contributor

@ningyi-oai ningyi-oai commented May 24, 2026

Summary

  • Add request_kind values for foreground turn, startup prewarm, compaction, and detached memory model requests.
  • Attach compaction dispatch metadata to local Responses, legacy /v1/responses/compact, and remote v2 compact requests.
  • Add the existing logical context-window identifier as window_id on turn-owned model request metadata.
  • Keep identity fields optional for detached memory requests, while still emitting request_kind="memory" in non-git/no-sandbox workspaces.

Root Cause

x-codex-turn-metadata has more than one producer. Foreground turns and compaction requests own a real turn and should carry that turn identity. Detached memory stage-one requests do not own a foreground turn, so absent identity fields are valid rather than missing data. Startup websocket prewarm is also a model request, but it has generate=false and must not be counted as a foreground turn.

thread_source or session source identifies where a thread came from (for example review, guardian, or another subagent). request_kind identifies what the current outbound model request is doing (turn, prewarm, compaction, or memory). A review or guardian thread can issue either a normal turn request or a compaction request, so source cannot replace request kind.

Behavior / Impact

  • Ordinary foreground requests send request_kind="turn", their real identity fields, and window_id="<thread_id>:<window_generation>".
  • Startup websocket warmup requests send request_kind="prewarm" so they are not counted as foreground turns.
  • Compaction requests send request_kind="compaction", their real owning turn identity, the existing window_id, and compaction.{trigger,reason,implementation,phase,strategy}.
  • Detached memory stage-one requests send request_kind="memory" without session_id, thread_id, turn_id, or window_id; when no workspace metadata exists, the kind-only header is still emitted.
  • session_id, thread_id, turn_id, and window_id remain optional in the header schema because detached memory requests do not own a foreground turn or context window.
  • window_id is not a new ID system: it is copied from the already-sent x-codex-window-id / WS client metadata value at model-request dispatch time.
  • Existing x-codex-window-id HTTP/WS emission, value format, generation advancement, resume behavior, and fork reset behavior are unchanged.
  • request_kind, window_id, and upstream turn-owned identity fields remain schema-owned; input responsesapi_client_metadata cannot replace their canonical values.
  • No table, DAG, export, app-server API, or MCP _meta schema changes are included.

A compaction attempt stopped by a pre-compact hook issues no model request and therefore has no request header; its outcome remains in analytics events. Status, error, duration, and token deltas also remain analytics fields rather than request-header fields.

Future detached-memory attribution using a real initiating turn ID as trigger_turn_id is intentionally not part of this PR.

Sync With Main

  • Final pushed head 716342e79 is rebased onto origin/main@0d37db4b2.
  • The metadata conflict came from upstream #24160, which added forked_from_thread_id on the same turn_metadata surface. Resolution preserves that field and its protection from client metadata override alongside this PR's request-kind, compaction, and window-id fields.
  • While resolving the overlapping commits, I removed an accidental recursive model-request overlay and a duplicate detached-memory header builder before completing the rebase.

Latency / User Experience Boundary

  • Foreground turns perform no new filesystem, git, or network work. New fields are inserted into metadata already serialized for outgoing requests.
  • Compaction issues the same model/HTTP requests with the same prompt, model, service tier, and sampling settings; only metadata bytes change.
  • Startup prewarm already sent metadata; it is now correctly classified as prewarm.
  • Non-git detached memory now sends a small kind-only metadata header rather than no header.
  • This client diff adds no user-visible latency mechanism beyond negligible serialization and header bytes on already-existing requests.

Validation

On conflict-resolved head 1d35c2cfb based on origin/main@487521733:

  • just fmt (passed)
  • just fix -p codex-core (passed)
  • git diff --check origin/main...HEAD (passed)
  • just test -p codex-core -E 'test(turn_metadata) | test(websocket_first_turn_uses_startup_prewarm_and_create) | test(responses_stream_includes_turn_metadata_header_for_git_workspace_e2e) | test(responses_websocket_forwards_turn_metadata_on_initial_and_incremental_create) | test(remote_compact_v2_retries_failures_with_stream_retry_budget) | test(window_id_advances_after_compact_persists_on_resume_and_resets_on_fork)' (23 passed; bench-smoke passed)
  • just test -p codex-app-server -E 'test(turn_start_forwards_client_metadata_to_responses_request_v2) | test(turn_start_forwards_client_metadata_to_responses_websocket_request_body_v2) | test(auto_compaction_remote_emits_started_and_completed_items)' (3 passed; bench-smoke passed)
  • just test -p codex-memories-write (29 passed; bench-smoke passed)

After those tests completed, origin/main advanced by #24658, whose only changed file is codex-rs/core/src/goals.rs; the PR rebased cleanly to final pushed head 716342e79. On that final pushed head:

  • just fmt (passed)
  • git diff --check origin/main...HEAD (passed)
  • GitHub CI is running on the final head.

An earlier full just test -p codex-core attempt on a preceding base failed with broad unrelated environment symptoms (test_stdio_server missing and shell/unified-exec timeouts); the focused metadata, websocket, compaction, and window tests listed above passed after the actual turn_metadata conflict resolution.

Comment thread codex-rs/core/src/session_startup_prewarm.rs Outdated
Comment thread codex-rs/core/src/turn_metadata.rs Outdated

#[derive(Clone, Copy, Debug, Serialize)]
#[serde(rename_all = "snake_case")]
enum TurnMetadataRequestKind {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We shouldn't need this. We should re-use the session source or turn source or something else... this feels odd to add this. What about the other turn? Reviews for example? Or guardian

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think these are orthogonal. Source identifies the originating thread/worker (e.g., review or guardian), while request_kind identifies the model action (turn, prewarm, compaction, memory). A review or guardian thread can issue different request kinds, so turn kind still matters. Does this make sense?

@ningyi-oai ningyi-oai force-pushed the dev/ningyi/turn_metadata_compaction branch 2 times, most recently from cdec59d to 1882e93 Compare May 26, 2026 18:58
@ningyi-oai ningyi-oai force-pushed the dev/ningyi/turn_metadata_compaction branch from 1882e93 to 716342e Compare May 27, 2026 00:47
@ningyi-oai ningyi-oai marked this pull request as ready for review May 27, 2026 01:43
@ningyi-oai ningyi-oai requested a review from a team as a code owner May 27, 2026 01:43
@ningyi-oai ningyi-oai merged commit bee7880 into main May 27, 2026
32 of 33 checks passed
@ningyi-oai ningyi-oai deleted the dev/ningyi/turn_metadata_compaction branch May 27, 2026 18:09
@github-actions github-actions Bot locked and limited conversation to collaborators May 27, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants