## Why
Answers collected by `request_user_input` can change what the user authorizes, but post-tool hooks may replace or reject the tool output that Guardian normally sees.
## What changed
- Record bounded, host-observed answers before post-tool hooks run and provide them as trusted evidence to synchronous and asynchronous Guardian reviews.
- Include root-thread answers in worker review context.
- Count successful answers as authorization changes so earlier review evidence becomes stale, while ignoring empty or unrelated answers.
## Testing
Add coverage for allowed and denied stale reviews, empty and oversized answers, hook-modified output, and root-to-worker propagation.
GitOrigin-RevId: 970c52e40338ecd057c7cd2a69d04b06e97cd068
## Why
Clients need a bounded view of realtime conversations that preserves the order of speech, agent work, and turn lifecycle events without loading the full thread history.
## What changed
- Persist realtime session boundaries, transcript segments, and promoted agent items in paginated thread rollouts.
- Add the experimental `thread/timeline/list` API to page ordinary items, realtime items, and turn boundaries in canonical rollout order. Include `activeRealtimeSessionAtPageStart` so each page can be rendered independently.
- Emit typed `thread/realtime/item/started`, `thread/realtime/item/transcript/delta`, and `thread/realtime/item/completed` notifications around durable realtime items.
- Keep the existing `thread/items/list` response and legacy thread history behavior unchanged.
## Testing
- Cover mixed timeline pagination, realtime-session state at page boundaries, rollout replay, subagent history prefixes, transcript streaming, steering, and promoted agent artifacts.
GitOrigin-RevId: faa2c420192d63e060e8fb32446e3c797422656e
## Why
Multi-Agent V2 children are owned by their parent at runtime. Resuming an
unloaded child directly could rebuild it from caller-provided settings instead
of the parent's current authority.
## What changed
- Route child reloads through their loaded immediate parent and reject direct
cold resume when that parent is unavailable.
- Preserve the child's recorded model, provider, reasoning effort, and role
while inheriting the parent's execution policy and MCP extensions.
- Validate cached environments against the parent, intersect local permission
profiles, and reject stale remote or workspace-root configurations.
- Keep paginated cold-resume token usage attribution when attaching to the
reloaded child.
## Testing
Add coverage for owner validation, nested-parent reloads, permission and
environment changes, role instruction restoration, paginated usage replay,
and app-server child resume behavior.
GitOrigin-RevId: 84014762bcdb57f94fc23974c9c1af55dc1babf1
## What changed
- Add a dedicated contextual fragment for developer instructions that emits the
`generic.developer_instructions` content kind.
- Use the fragment when adding child-specific developer instructions to a
full-history subagent fork, preserving their classification and ensuring they
reach the child exactly once without appearing in the parent request.
## Testing
- Extend full-history subagent coverage to verify the child-only instructions'
annotation, placement, and count.
GitOrigin-RevId: 82589d311535225fed76d500a19458fda72f40f2
## Why
Developer-message content and its positional `content_item_kinds` metadata must stay aligned when parent history is prepared for a spawned agent.
## What changed
- Filter and rewrite developer-message content as annotated content so each retained item keeps its matching kind.
- Rebuild both message content and annotation metadata together after removing parent-only instructions and multi-agent usage hints.
## Testing
- Extend forked-history coverage to verify retained annotation kinds.
- Assert that spawned child requests contain the same number of content items and annotation kinds.
GitOrigin-RevId: 59748d9e8c4fc06ef8e5b90389bcf40465589f90
## What changed
- Retain bounded evidence from completed synchronous Guardian allow and deny reviews and supply it to subsequent Guardian v2 async classifier samples as trusted developer context.
- Keep review evidence isolated from the conversation transcript, escape and truncate its fields, and ignore failed or incomplete reviews.
- Invalidate retained evidence after conversation history rewrites or new user messages, including authorization changes in a worker's root thread.
## Testing
- Cover approved, denied, malformed, and forged review inputs, plus root rollback and authorization-change scenarios.
GitOrigin-RevId: 27817e1fde9a136de727048c4220d148fcf72f42
## Why
MultiAgent V2 workers can be reviewed after the root conversation has received
new user authorization that is absent from the worker's own transcript. Guardian
reviews need that genuine user context without treating forwarded or
assistant-authored claims as authorization.
## What changed
- Add the bounded root conversation to Guardian prompts for worker reviews.
- Preserve user and assistant roles, and explicitly treat only root user messages
as authorization evidence.
- Exclude summaries, review artifacts, and assistant commentary from the root
conversation evidence.
- Apply the same evidence to both core Guardian prompts and Guardian V2
classification.
## Testing
Add an integration test covering late root-user authorization, forged role text,
forwarded agent claims, and filtered synthetic authorization.
GitOrigin-RevId: 8846de69ba214a88f58f70675798d324e213427c
## Why
External tool events may need to enter thread history without a preceding function call and therefore do not have a `call_id`.
## What changed
- Allow `function_call_output` items to omit `call_id` and carry optional `name` and `namespace` fields.
- Preserve named standalone outputs during history normalization and agent forks while retaining existing pairing behavior for outputs with a `call_id`.
- Accept, persist, and forward these outputs through `thread/inject_items`, and update the app-server schemas and documentation.
## Testing
- Cover paired and standalone JSON round trips, history normalization, agent forks, and injected thread history.
GitOrigin-RevId: a3258163a7dc93777c7c3023116fe204819bdbb0
## What changed
- Add `additional_developer_instructions` to managed requirements and expose it through `configRequirements/read` as `additionalDeveloperInstructions`, independently of ordinary developer instructions.
- Include the managed instructions in model context, emit explicit replacement or removal messages when requirements change, and preserve the current value across compaction, resume, and agent forks without duplication.
- Reject managed instructions whose rendered context exceeds 10,000 estimated tokens.
## Testing
- Cover requirements layering and API serialization, context updates and removal, size validation, repeated model requests, compaction and resume, rollout migration, and agent forks.
GitOrigin-RevId: bc0b70fb7988944c2f68176dff55f5ed61eb46c8
## Why
Developer messages can contain both inherited agent policy and unrelated context. Full-history forks need to replace the parent policy without dropping the unrelated content that shares its message.
## What changed
- Filter fork-specific developer instructions by content item instead of excluding an entire developer message.
- Remove inherited multi-agent mode instructions before applying the child agent's current mode.
- Preserve unrelated content items and discard developer messages only when filtering leaves them empty.
## Testing
Extend agent-control and subagent notification tests to cover compound compacted messages, multi-agent mode instructions, and proactive-to-explicit mode transitions.
GitOrigin-RevId: 028834e237d8636c13b17a724574bc8eb09a55ba
## Why
Environment-owned permission profiles and workspace roots must remain effective
without being persisted or restored as thread-owned settings.
## What changed
- Keep thread settings snapshots and restore data separate from the effective
configuration supplied by the primary environment.
- Use resolved environment permissions, active profiles, workspace roots, and
network policy when building turn context and session events.
- Preserve environment selections when agents are evicted, resumed, or spawned,
and validate owner configuration when it becomes ready.
- Start memory initialization only after the primary environment is configured.
## Testing
- Extend remote-environment and multi-agent tests to cover settings persistence,
owner permission profiles, workspace roots, spawning, eviction, and resume.
GitOrigin-RevId: d82f126981cd0190233020bbdd61d96c70558868
## Why
Agent roles should customize a child agent without expanding the authority or changing the provider configuration inherited from its parent session.
## What changed
- Apply only supported role overrides for model behavior, developer instructions, personality, service tier, and capability reductions.
- Preserve parent-owned permissions, model providers, endpoints, MCP servers, notifications, and other unrestricted configuration.
- Keep managed feature requirements effective when a role disables capabilities, and reject symlinked user role files.
- Use the same bounded role application path for both multi-agent implementations and resumed agents.
## Testing
Add coverage for authority preservation, managed feature requirements, symlink rejection, provider inheritance, and provider routing after resume.
GitOrigin-RevId: c528d615b691f9c02bfbc21154d514ea07743010
## What changed
- Add model-catalog messages for root and subagent roles, explicit delegation, and delegation hints.
- Resolve role instructions in config, catalog, then bundled-default order, while preserving empty values as an explicit way to suppress fallback text.
- Refresh catalog-provided role and mode instructions when the model changes, and give full-history forks the selected child model's subagent role without retaining the parent's role guidance.
- Keep existing config overrides and reasoning-effort behavior, including proactive delegation for ultra reasoning effort.
## Testing
- Cover message deserialization and preservation through model overrides.
- Cover precedence, empty overrides, model switches, resumed sessions, and full-history subagent forks.
GitOrigin-RevId: 4625cf7c6a5490176adddfaa0fb99100707daea9
## What changed
- Exclude current-time reminder developer messages when copying parent history into a full-history subagent.
- Keep the child's newly generated reminder, preventing inherited reminders from accumulating while preserving the rest of the forked context.
## Testing
- Extend the full-history V2 spawn test to verify that two reminders in the parent become one fresh reminder in the child request.
GitOrigin-RevId: fb61c72f7f0d61d1068f2c599a8b8caf1788b7e2
## What changed
- Add a `SecurityRiskScore` rollout item containing a category and numeric score.
- Persist the item in both thread history modes while excluding it from model context, user-visible thread history, search text, forks, and reconstructed conversation history.
- Re-export the score type from the extension API.
## Testing
- Cover serialization, persistence and loading, thread history projection, session reconstruction, append planning, and memory filtering.
GitOrigin-RevId: 1926fe366aeaa75052708a6da589f45a38eefb52
## What changed
- Add `TurnInputRequest` and typed submission results for atomically starting a turn, steering the active turn, or declining input with a specific reason.
- Expose `start_or_steer_turn`, `start_turn_if_idle`, and `steer_turn` on `CodexThread`, and migrate Core consumers to these APIs.
- Make app-server `turn/start` steer an active regular turn and return that turn's ID. Reject incompatible output schemas and non-steerable turns without applying settings or enqueueing input.
## Testing
- Cover concurrent start-or-steer submissions, accepted and rejected settings updates, output-schema compatibility, idle-start rejection, and app-server steering.
GitOrigin-RevId: dd9b5528d76ec650c019e97af420bc13190ea86a
## What changed
- Add fractional Unix creation times to locally authored user, developer, agent, and tool-output items when they enter durable conversation history.
- Preserve any creation time already supplied with an item across subsequent requests, remote compaction, and resumed history.
## Testing
- Cover timestamp assignment and preservation in session, client, tool, agent-spawn, and remote-compaction tests.
GitOrigin-RevId: 431d1770b9746005c808bc0a43953845166d68ad
## Why
`parent_turn_id` identifies the immediate caller of a nested request, but not the
top-level turn that initiated a multi-level chain of work.
## What changed
- Add `root_turn_id` to turn state, submissions, and Responses API metadata.
- Propagate the root through spawned agents, delegated work, review sessions, and
turn-triggering inter-agent messages.
- Omit the root when background work has no user turn or combined input makes the
root ambiguous.
## Testing
Added coverage for nested agent resumes, reviews, mailbox delivery, steered input,
and reserved metadata handling.
GitOrigin-RevId: 60057db2ee81f4efefa946a9f63c74ff98b93929
## What changed
- Wrap response items with optional harness-owned metadata while keeping the persisted response payload shape backward compatible.
- Store compacted-history metadata in an aligned sidecar and reject malformed sidecars.
- Carry metadata through history normalization, compaction, resume, fork, truncation, migration, and rollout recording without sending it to model providers.
## Testing
- Cover legacy rollout compatibility, metadata serialization and validation, compaction retention, and resume/fork reconstruction.
GitOrigin-RevId: 17a6127c9048ff984cb4df4d97c0751a38c29f5f
## What changed
- Add `PersistContext` to the thread-store persistence contract so stores can
identify persistence requested immediately before model sampling. A
`TurnStart` request may be enqueued in the background when later flush and
shutdown operations fence it and report any failure; all other persistence
remains synchronous.
- Use the turn-start context only for the initial input of a regular turn, while
admission acknowledgments, steered input, and other persistence paths keep
the standard durability behavior.
- Flush pending metadata before turn-start persistence and ensure shutdown is
still attempted if that metadata update fails.
## Testing
- Verify that developer instructions and user input are persisted before the
model request completes for a default paginated-history thread.
GitOrigin-RevId: 162f0ec796a61aebe66ca0b909fbcccec3047b85
## Why
Multi-agent v2 rejected `agent_type` when `fork_turns` was `all`, forcing callers to choose between a configured role and the parent's full conversation context.
## What changed
- Apply an explicitly selected role to full-history forks, including its model and developer instructions.
- Preserve the parent's developer instructions when the selected role does not define its own.
- Keep the inherited conversation history and model-switch context intact.
- Update the `spawn_agent` schema to clarify that roles apply independently of history inheritance.
## Testing
- Cover full-history role overrides and developer-instruction precedence in multi-agent v2 tests.
GitOrigin-RevId: cd4f35e31d75f56289760f245bff38dd0233abe6
## Why
Reloading an unloaded v2 agent could inherit the model provider from the
agent that triggered the reload, even though the worker's model was restored
from its persisted thread state.
## What changed
- Restore both the model and model provider from the stored thread when
reloading a v2 agent.
- Return an invalid-request error if the stored provider is no longer present
in the configured provider map.
## Testing
Extend the v2 agent reload test to trigger the reload with a different sender
provider and verify that the worker retains its stored provider.
GitOrigin-RevId: 6401d9f0d1c116e9954e3bd193d016f04da5f223
## What changed
- Allow multi-agent v2 parents to spawn any visible model that has not explicitly disabled multi-agent support.
- Expose collaboration tools to child agents only when their selected model supports multi-agent v2, keeping legacy models as leaf workers.
- Preserve a worker's selected model when reloading it into residency.
- Propagate multi-agent capability metadata to Amazon Bedrock model entries so delegation is gated consistently.
## Testing
- Cover model selection, leaf-worker tool visibility, Bedrock capability handling, and model preservation after reload.
GitOrigin-RevId: 1457adb1a09806d1f0621311d5a42a6815b9dd4e
## What changed
- Retain bounded, non-completion agent messages in remote v2 compaction history so delegated tasks remain available on follow-up turns.
- Account for encrypted agent-message content when estimating token usage and place restored initial context before the latest real user or agent message.
- Exclude child completion messages from retained follow-up history and strip inherited parent agent messages when forking a child.
## Testing
- Extend compaction, history-estimation, and agent-fork tests to cover encrypted delegated tasks, child completions, context ordering, and fork sanitization.
GitOrigin-RevId: ba4392e9cfdf4ecbcdc9c7d8581d58a8d2d78260
## What changed
- Consume owned rollout vectors when truncating fork and subagent history, reusing their allocations instead of copying slices.
- Project ephemeral fork responses and token-usage ownership before moving the source history into the new thread.
- Preserve canonical `beforeTurnId` validation for rolled-back and synthetic legacy turns.
## Testing
- Add truncation tests covering rolled-back and synthetic legacy `beforeTurnId` values.
GitOrigin-RevId: 5785d004b74d7e057b82379a172676b023bcfb4f
## What changed
- Propagate the initiating turn ID through agent spawns, follow-up tasks, reviews, and delegated Codex sessions.
- Add `parent_turn_id` to Responses client and turn metadata while keeping it out of external MCP metadata.
- Preserve parent-turn provenance across queued agent messages when their triggering parent is unambiguous.
## Testing
- Cover spawned, resumed, nested, reviewed, delegated, and WebSocket request metadata.
- Verify queued messages do not claim ambiguous or queue-only parent turns.
GitOrigin-RevId: 481fdebbe7df2031880fe259509273cce50b20a8
## What changed
- Add `features.multi_agent_v2.subagent_developer_instructions` to override inherited developer instructions for subagents that do not define role-specific instructions.
- Preserve role-specific instructions as the higher-precedence setting, and carry the effective instructions through full and bounded forks, compacted histories, and cold resume without duplication.
- Treat an unset override as inheritance and a blank override as clearing inherited instructions.
## Testing
- Cover configuration parsing and materialization, instruction precedence, fork modes, compaction, role application, and resumed subagents.
GitOrigin-RevId: 32321e61abc59b14a1be5f31e6bd6570bb1cd89d
## What changed
- Wrap `CodexErrorDetails` and an optional retry delay in `CodexErr`, allowing any mapped error to preserve server-provided retry timing.
- Generate the payload-free `CodexErrKind` classification alongside the error details and reuse it for analytics.
- Update error handling sites to inspect `CodexErr::details()` while preserving existing display, debug, protocol mapping, and retryability behavior.
## Testing
- Add coverage for legacy debug formatting, error-specific retryability, and retry-delay propagation through API error mapping.
GitOrigin-RevId: d3ab8a305f2a2ee21d0c0a8c8c388b06dda9c59a
## What changed
- Add `StartThreadOptions::new` to provide the standard configuration for a new thread.
- Make `ThreadManager::start_thread` the single thread-start entry point and migrate callers from the previous convenience methods.
- Derive default environment selections when `environments` is `None`, while preserving explicit selections, including an empty list.
GitOrigin-RevId: 8977dc11aed54c5e1215a81eaed2b2cf5fc6087a
## What changed
- Require the parent thread to be live before forking its history.
- Read the history mode and multi-agent usage hints from that live parent so
the fork loads and filters history using the active configuration.
- Verify that forking a legacy parent keeps the child in legacy history mode.
GitOrigin-RevId: 79416b78544467a1801f21300d3fe8db4fef59df
## Why
Durable v2 sub-agents can be lazily reloaded after their root session resumes. The reload path restored the agent identity but did not reapply the agent's selected role configuration.
## What changed
- Recover the agent role from the resumed session source and apply it before reloading the sub-agent.
- Preserve the runtime approval policy, approval reviewer, working directory, and permission profile while applying the role.
## Testing
Extend the cold-resume integration test to verify that the reloaded worker retains its role-defined instructions, model, provider, reasoning effort, and permission profile.
GitOrigin-RevId: a26dbbd2599838ca317326a1223a6a0a9cb2a2ed
## What changed
- Inherit paginated history mode when spawning or forking a subagent from a paginated parent.
- Load the parent's model context when forking and persist it as an inherited rollout prefix, while excluding that prefix from the child's projected turns, items, and metadata.
- Record the boundary between inherited context and child history, and reject partially initialized paginated subagent rollouts on resume.
- Resume paginated subagents from their stored model context instead of legacy rollout history.
## Testing
Added coverage for fresh and forked paginated subagents, compacted-history forks, model-context resume, inherited-prefix projection, metadata isolation, and incomplete-prefix detection.
GitOrigin-RevId: e57dc37c29aa4aaaf57b052b991be591d730e5ba
## What changed
- Replace the combined `Codex` wrapper with an `Arc<Session>` and a dedicated
`SessionIo` handle for submissions, events, status, and loop termination.
- Make `Session::spawn` return the session and I/O handle separately, and have
`CodexThread` own both.
- Update thread management, delegated sessions, guardian reviews, and agent
control to use the appropriate session or I/O interface.
GitOrigin-RevId: 8523bad7e7366e2969fd0cc3849b4247b141427a
## Why
After a cold resume, a Multi-Agent V2 root thread must still be able to
address its persisted descendants even though their runtimes are not reopened
eagerly.
## What changed
- Restore metadata for open descendant agents when resuming a V2 root thread.
- Preserve each descendant's path, nickname, and role while leaving its runtime
unloaded until a message targets it.
- Reuse the spawn metadata preparation path so restored identities retain the
same reservation and naming checks as newly spawned agents.
## Testing
Added an end-to-end cold-resume test that follows up with a persisted agent by
name and verifies that the original agent thread is loaded on demand.
GitOrigin-RevId: a1663c1ae60eefadb948cd39f933cd3bbb49a492
## What changed
- Add an optional `error` payload to `TurnCompleteEvent` and omit it when a turn completes without an error.
- Preserve the full terminal `ErrorEvent` through the turn lifecycle so the completion event includes the same error details emitted separately by `EventMsg::Error`.
## Testing
- Extend the stream-error integration test to verify that `TurnCompleteEvent` contains the emitted error and that the next turn can still proceed.
GitOrigin-RevId: 8d32942a44132763076130102d8b89ab356d59d0
## What changed
- Add an optional `started_at` Unix timestamp to `TurnCompleteEvent` and
`TurnAbortedEvent`.
- Populate the timestamp from turn timing state when a turn completes or is
aborted.
- Preserve the timestamp when synthesizing interrupted fork history and when
importing external sessions.
## Testing
- Verify that interrupting a turn emits a `TurnAbortedEvent` with a start
timestamp.
GitOrigin-RevId: 75b3911b95c060e5fc1843a5e293d8fe47377186
## Why
[#30867](https://github.com/openai/codex/pull/30867) makes
`submit_inter_agent_communication` the common outbound sink for
multi-agent v2 communications. This follow-up uses that single point to
log every communication lifecycle without requiring new hooks as spawn,
messaging, follow-up, or result paths evolve.
For each communication, the logs need to identify its type, sender and
receiver threads, and content, while correlating the successful send
with receipt by the destination mailbox. The logging path must not query
externally supplied time providers because those calls can be expensive
for app-server clients.
## What changed
- Added structured `INFO` events on the OpenTelemetry-exported
`codex_otel.agent_communication` target for `spawn`, `message`,
`followup`, and `result` communications.
- Logged successful sends from `submit_inter_agent_communication` with
the communication kind, sender and receiver thread IDs, content, and
submission ID.
- Logged receives after the communication has been enqueued in the
receiver mailbox, using the same submission ID.
- Avoided time-provider calls and other asynchronous work in the logging
path.
- Narrowed ordinary spawn and send-input APIs to `Vec<UserInput>` so
`Op::InterAgentCommunication` cannot bypass the context-bearing
centralized path.
The refactor does not change submission IDs, capacity checks, last-task
bookkeeping, mailbox ordering, protocol types, rollout data, or
model-visible context.
## Event shape
Illustrative JSON representation of the two independently emitted
records:
```json
[
{
"event.name": "codex.agent_communication",
"communication_id": "019f20e1-40d1-7890-a123-456789abcdef",
"kind": "spawn",
"state": "send",
"sender_thread_id": "019f20df-fbe1-7890-a123-456789abcdef",
"receiver_thread_id": "019f20e1-3f79-7890-a123-456789abcdef",
"content": "inspect the repository"
},
{
"event.name": "codex.agent_communication",
"communication_id": "019f20e1-40d1-7890-a123-456789abcdef",
"state": "receive"
}
]
```
Consumers join the receive record to the send record by
`communication_id` for the immutable communication metadata.
## Testing
- Extended the existing end-to-end multi-agent v2 spawn test to verify
content, both thread IDs, and a correlated send/receive submission ID.
- Re-ran focused control and handler coverage for direct messages,
follow-up tasks, and completion results.
## Why
`selectedCapabilityRoots` is durable thread intent: “use this capability
root from environment `worker`.”
The important product assumption is:
> One environment ID always names the same logical executor and stable
contents.
`worker` does not silently change from executor A to an unrelated
executor B. The process-local connection handle for `worker` can still
be replaced while Codex is running, though, for example when
`environment/add` registers a fresh handle for the same logical
environment.
The thread should persist only the stable selection. Each model step
should pair that selection with the exact ready handle captured for that
step.
## The boundary
```text
persisted thread intent
plugin@1 -> environment "worker"
|
| capture the current step
v
model-step view
unavailable, or
plugin@1 + worker's exact captured ready handle
```
The environment ID is the stable identity and cache key. The
`Arc<Environment>` is only a process-local handle retained so consumers
of one model step use the same captured environment. It is never
persisted and it does not imply different environment contents.
## What changes
### Persist the stable selection
Selected roots are written into `SessionMeta` and restored with the
thread. Forked subagents inherit the same selections, including
bounded-history forks.
Only stable data is persisted: root ID, environment ID, and root path.
### Capture readiness together with the exact handle
The environment snapshot records:
```rust
environment_id -> Some(Arc<Environment>) // ready in this step
environment_id -> None // still starting in this step
```
This prevents readiness and execution from coming from different
registry snapshots.
For example:
```text
step snapshot: worker -> handle A, ready
environment/add: worker -> fresh handle B for the same logical environment
current step: plugin@1 still uses captured handle A
```
Without carrying handle A in the snapshot, the resolver could combine “A
was ready” with handle B and treat B as ready before it had finished
starting.
This does not change cache invalidation. Stable capability metadata
remains identified by environment ID and capability root. Replacing a
process-local handle under the same stable environment ID does not
invalidate or rediscover that metadata.
### Resolve availability per model step
- A ready captured environment produces resolved roots using its
captured handle.
- A starting, missing, or failed environment is omitted from that step.
- A selected lazy environment that is outside the turn's captured
environment set is asked to start, and a later step can observe it as
ready.
- No capability files are scanned here.
Transient transport disconnects remain the remote client's reconnect
concern. This PR models initial attachment/readiness; it does not add
live socket-connectivity state.
## Example
```text
thread selection: plugin@1 -> environment "worker"
step 1: worker is starting -> plugin@1 unavailable
step 2: worker is ready -> plugin@1 resolves through worker's captured handle
step 3: fresh local handle -> current step remains pinned; a later step captures its own view
```
Temporary unavailability does not discard the durable selection. Later
PRs can retain stable metadata caches while projecting only currently
available capabilities into model-visible World State.
## Compatibility
The app-server request shape does not change. Older rollouts without
`selected_capability_roots` deserialize to an empty list.
## Stack
1. **This PR:** persist stable selected roots and resolve them through
an exact model-step handle.
2. #29960: cache stable skill metadata and project available skills into
World State.
3. #29946: cache stable plugin declarations and manage the separate live
MCP runtime.
## Why
Ultra should be one user-facing reasoning selection for work that
benefits from both maximum reasoning and proactive multi-agent
delegation. Without it, clients must coordinate maximum reasoning with
the experimental `multiAgentMode` setting, even though the inference
backend still expects its existing `max` effort value.
This change makes reasoning effort the source of truth: clients select
`ultra`, core derives proactive multi-agent behavior when the turn is
eligible for multi-agent V2, and inference requests continue to use the
backend-compatible `max` value.
## What changed
- Add `ultra` as a first-class reasoning effort and preserve
model-catalog ordering when exposing it to clients.
- Convert `ultra` to `max` at the inference request boundary, including
Responses HTTP/WebSocket requests, startup prewarm, compaction, and
memory summarization.
- Derive effective multi-agent mode per turn from effective reasoning
effort:
- eligible multi-agent V2 + `ultra` → `proactive`
- eligible multi-agent V2 + any other effort → `explicitRequestOnly`
- V1 or otherwise ineligible sessions → no multi-agent mode instruction
- Keep the derived effective mode in turn context history so successive
turns can emit a developer-message update only when the effective mode
changes.
- Remove selected multi-agent mode from core session configuration, turn
construction, thread settings, resume/fork restoration, and subagent
spawn plumbing. Subagents inherit reasoning effort and derive their own
effective mode.
- Retain the experimental app-server `multiAgentMode` fields for wire
compatibility while marking them deprecated. Request values are accepted
but ignored; compatibility response fields report `explicitRequestOnly`.
- Display Ultra in the TUI using the order supplied by `model/list`.
## Validation
- `just test -p codex-core ultra_reasoning_uses_max_for_requests`
- `just test -p codex-tui model_reasoning_selection_popup`
## Why
`WorldState` currently remembers its model-visible diff baseline only in
memory. That leaves no durable source for restoring the exact baseline
after resume, fork, rollback, or compaction.
This is the second PR in the WorldState persistence stack, built on
#29833 and following #29249. It records durable state transitions; the
next PR will replay them during rollout reconstruction.
## What
- Add a `world_state` rollout item containing either a full snapshot or
an RFC 7386 JSON Merge Patch.
- Persist a full snapshot after initial context and after compaction
establishes a new context window.
- Persist non-empty patches when later sampling steps or turns advance
the WorldState baseline.
- Write model-visible history before its matching WorldState record, so
an interrupted write can only cause a safe repeated update on replay.
- Preserve WorldState records for full-history forks while excluding
them from thread previews, metadata, and app-server history
materialization.
Older binaries read rollout lines independently, so they skip the
unknown `world_state` records while retaining the rest of the thread.
## Testing
- `just test -p codex-core
snapshot_merge_patch_changes_and_removes_nested_values`
- `just test -p codex-core
world_state_baseline_deduplicates_until_history_is_replaced`
- `just test -p codex-core
deferred_executor_compaction_preserves_then_updates_environment_once`
- `just test -p codex-protocol`
- `just test -p codex-rollout`
- `just test -p codex-state`
- `just test -p codex-thread-store`
- `just test -p codex-app-server-protocol`
Pick up the AgentGraphStore migration.
- Inject an explicit optional agent graph store into `ThreadManager`
- Move all calls to spawn, close, recursive resume, and
subtree/archive/delete/feedback traversal through it
- Keep using `LocalAgentGraphStore` when SQLite is available
This required some changes to the interface to deal with futures:
- The interface now matches `ThreadStore`'s object-safe pattern by
returning a boxed `AgentGraphStoreFuture` directly, allowing
`ThreadManager` to hold `Arc<dyn AgentGraphStore>`
*Slight behavior change!* Unfiltered subtree enumeration now performs a
single all-status breadth-first traversal, so a closed grandchild
beneath an open edge is included; the previous Open-then-Closed
traversals could not cross mixed-status paths and silently omitted it.
## Why
Inter-agent messages are recorded in live history as
`ResponseItem::AgentMessage`, but rollouts stored
`InterAgentCommunication` and rebuilt the response item during resume.
This made the rollout differ from the actual Responses history.
## What changed
- store the prepared `agent_message` response item directly
- keep `trigger_turn` in a small local metadata record for fork
truncation
- keep reading older `inter_agent_communication` rollout items
## Summary
Resuming a persisted thread currently deep-clones its complete rollout
history several times. `InitialHistory` is retained for the app-server
response, copied into thread persistence, and copied again by read-only
accessors. These copies scale with the complete rollout rather than the
bounded model context and add measurable latency for large sessions.
This change stores resumed rollout history in `Arc<Vec<RolloutItem>>`.
Rollout loading wraps the parsed vector once, while app-server response
construction, session initialization, and thread persistence share it
through inexpensive `Arc` clones. Read-only history access now returns a
borrowed slice, and fork paths use `Arc::unwrap_or_clone` where they
genuinely need mutable ownership. Rollout reconstruction also consumes
its temporary context instead of cloning the reconstructed model
history.
The serialized representation remains unchanged. In an artificial 123 MB
rollout benchmark, sharing resumed history reduced cold resume latency
by roughly 9–10%. The affected crates compile with their test targets,
all 80 thread-store tests pass, and the Bazel dependency lock remains
valid.
When using Responses Lite, we should all use `additional_tools` and a
developer item instead of the top level tools array & instructions
field. This keeps things 1-to-1.
Forced namespacing for _all_ tools will land in a following PR after
some coordination & fixes in Responses API (around collisions & return
items).
The goal is to eventually expand the scope of this to _all_ requests
from codex, but that will require larger coordination across providers &
slower rollout.
## Why
Multi-agent delegation policy was split across `multiAgentMode`,
`features.multi_agent_mode`, and `usage_hint_enabled`. These controls
could disagree: a requested mode could be downgraded by the feature
flag, and disabling usage hints also disabled mode instructions.
Some clients also need multi-agent tools without adding
delegation-policy text to model context. The previous two-mode API could
not express that directly.
## What changed
`multiAgentMode` is now the only live delegation-policy control:
| Mode | Behavior |
| --- | --- |
| `none` | Keep multi-agent tools available without adding mode
instructions. |
| `explicitRequestOnly` | Only delegate after an explicit user request.
|
| `proactive` | Delegate when parallel work materially improves speed or
quality. |
- new threads default to `explicitRequestOnly`; omitting the mode on
later turns keeps the current value
- thread start, resume, fork, and settings responses always report the
concrete current mode instead of `null`
- mode selection remains sticky across turns and resume
- usage-hint text no longer controls whether mode instructions apply
- `features.multi_agent_mode` and `usage_hint_enabled` remain accepted
as ignored compatibility settings so existing configs continue to load
- app-server documentation and generated schemas describe the three-mode
API
## Tests
- `just test -p codex-core multi_agent_mode`
- `just test -p codex-core multi_agent_v2_config_from_feature_table`
- `just test -p codex-core spawn_agent_description`
- `just test -p codex-features`
- `just test -p codex-app-server-protocol`
- `just test -p codex-app-server multi_agent_mode`
## Why
Once multi-agent mode can be selected per turn, clients also need to
choose the initial selection when creating a thread and observe that
selection through lifecycle and settings APIs.
The selected value is intentionally distinct from the effective
model-visible value: no client selection is represented as `null`, even
though an eligible multi-agent v2 turn derives `explicitRequestOnly` as
its effective default.
## What changed
- Add the optional experimental `thread/start.multiAgentMode` parameter
and pass it through thread creation.
- Preserve an omitted initial value as an unset selection rather than
eagerly storing `explicitRequestOnly`.
- Apply an explicit `thread/start` selection to the first turn through
the session configuration established at thread creation.
- Restore the latest persisted effective mode as the selected baseline
on cold resume when rollout history contains one.
- Inherit the optional selected mode from a loaded parent when creating
related runtime threads.
- Return the current selected `multiAgentMode` from `thread/start`,
`thread/resume`, `thread/fork`, and thread settings, using `null` when
no mode is selected.
- Keep lifecycle reporting independent from model capability and feature
eligibility; core turn construction remains responsible for calculating
and persisting the effective mode.
## Not covered
- Clearing an existing loaded-session selection back to unset through
`turn/start`; omitted or `null` currently retains the session's
selection.
- A TUI control, slash command, or `config.toml` preference.
## Verification
- `CARGO_INCREMENTAL=0 just test -p codex-app-server-protocol`
- `CARGO_INCREMENTAL=0 just test -p codex-app-server multi_agent_mode`
The focused app-server coverage verifies explicit `thread/start`
initialization, first-turn prompting, nullable reporting for an omitted
selection, and retention of selections that are not currently
runtime-eligible.
## Stack
Stacked on #28685. This PR contains only the thread initialization and
lifecycle/settings API layer.
## Why
Shell snapshots are currently session-scoped even though shell and cwd
are properties of a selected turn environment. That makes snapshot
refresh depend on separate session-cwd plumbing, prevents retained
environments from retaining their snapshot work, and can make snapshot
construction use a different shell than command execution.
This follows #27955 by making the retained thread-environment service
own environment snapshot lifecycles. Session configuration remains the
requested selection state, while `ThreadEnvironments` remains the source
of successfully resolved environments.
## What changed
- Configure the shell-snapshot builder before initial environment
resolution.
- Start each local environment snapshot task when its `TurnEnvironment`
is built and retain that shared task while environment ID and cwd still
match.
- Inherit retained environment snapshots into spawned child threads.
- Carry the selected `TurnEnvironment` through shell runtimes so
snapshot construction and command execution use the same
environment-specific shell and cwd.
- Load project instructions and warm plugins/skills after initial
environment resolution.
- Continue decoding invalid UTF-8 instruction files lossily without
emitting a startup warning.
- Keep requested selections in `SessionConfiguration`; failed or
duplicate resolutions only affect the resolved environment snapshot.
## Validation
- `cargo check -p codex-core --tests`
- `just test -p codex-home instructions` (6 passed)
- Focused environment, instruction, shell-snapshot, and user-shell tests
(84 passed)
- Focused shell-snapshot, user-shell, and unified-exec tests (126
passed; two event-timing tests passed on retry)
## Description
This PR adds an optional `metadata` field to `ResponseItem` for
Responses API calls. Only mechanical plumbing, no actual values
populated and sent yet. Turns out just adding a new field to
`ResponseItem` has quite a large blast radius already.
This change is backwards compatible because `metadata` is optional and
omitted when absent, so existing response items and rollout history
without it still deserialize and requests that do not set it keep the
same wire shape. For provider compatibility, we strip out `metadata`
before non-OpenAI Responses requests so Azure and AWS Bedrock never see
this field.
My followup PR here will actually make use of it to start storing and
passing along `turn_id`: https://github.com/openai/codex/pull/28360
## What changed
- Added `ResponseItemMetadata` with optional `turn_id`, plus optional
`metadata` on Responses API item variants and inter-agent communication.
- Preserved item metadata through response-item rewrites such as
truncation, missing tool-output synthesis, compaction history
rebuilding, visible-history conversion, rollout/resume, and generated
app-server schemas/types.
- Strip item metadata from non-OpenAI Responses requests while
preserving it for OpenAI-shaped requests.
- Updated the mechanical fixture/test construction churn required by the
new optional field.
## Why
Multi-agent v2 `send_message` deliveries already reach the receiving
model as typed `agent_message` items with encrypted content.
Child-completion notifications are generated by Codex itself, so their
content is plaintext and previously fell back to a serialized JSON
envelope inside an assistant message.
With plaintext `input_text` supported for `agent_message`, both delivery
paths can use the same model-visible type while preserving explicit
author and recipient metadata.
## What changed
- add plaintext `input_text` support to `AgentMessageInputContent` and
regenerate the affected app-server schemas
- preserve `InterAgentCommunication` as structured mailbox input instead
of converting it to assistant text
- record delivered communications as typed `agent_message` history items
- persist a dedicated rollout item so local delivery metadata such as
`trigger_turn` remains available without leaking into the Responses
request
- reconstruct typed agent messages on resume and preserve fork-turn
truncation behavior
- remove request-time assistant-content parsing
- preserve plaintext and encrypted inter-agent deliveries in stage-one
memory inputs
- normalize and link plaintext and encrypted agent messages in rollout
traces without treating inbound messages as child results
- cover the real MultiAgent V2 child-completion path end to end with
deterministic mailbox synchronization
## Verification
- `just test -p codex-core
plaintext_multi_agent_v2_completion_sends_agent_message`
- `just test -p codex-core input_queue_drains_mailbox_in_delivery_order
record_initial_history_reconstructs_typed_inter_agent_message
fork_turn_positions_use_inter_agent_delivery_metadata`
- `just test -p codex-memories-write
serializes_inter_agent_communications_for_memory`
- `just test -p codex-rollout-trace
agent_messages_preserve_routing_and_content
sub_agent_started_activity_creates_spawn_edge`
- `just test -p codex-rollout-trace
agent_result_edge_falls_back_to_child_thread_without_result_message`
- `just test -p codex-protocol -p codex-rollout -p
codex-app-server-protocol`
## Why
Multi-agent v2 residency is intended to keep only the threads that need
to be live. The existing rollout resume path still walked persisted open
descendants and reopened the entire descendant tree when resuming a v2
root, which turns resume into an eager reload of work that should stay
unloaded until it is explicitly needed.
The interrupted-agent path has a related residency issue. Interrupted
agents remain open by design, so an idle interrupted resident should be
eligible for eviction just like an idle completed or errored resident.
Otherwise a resident set full of interrupted agents can consume every v2
slot and block later spawns or reloads with `AgentLimitReached`.
## What Changed
- Return early from `resume_agent_from_rollout` after resuming a v2
thread so persisted v2 descendants are not reopened eagerly.
- Treat idle `Interrupted` v2 residents as unloadable in the LRU
residency path.
- Add focused coverage for v2 root resume leaving descendants unloaded
and for eviction of an idle interrupted v2 resident when a new slot is
needed.
## Verification
Added targeted `codex-core` tests covering:
- v2 root resume with persisted descendants, verifying only the root is
loaded after resume.
- residency eviction of an idle interrupted v2 agent when the resident
set is full.