## What changed
Add optional `contentTokenCount` metadata to `item/completed` notifications, carrying the producer-supplied token count for each completed assistant message in default and plan modes. Counts include any sampled footer and are `null` when unavailable.
Keep this telemetry separate from stored thread items and omit it from subsequent model requests. Update the protocol schemas and generated TypeScript and Python types.
## Testing
Add coverage for per-message counts, including zero, in default and plan modes; missing and malformed metadata; backward-compatible notification decoding; and exclusion from subsequent model requests.
GitOrigin-RevId: 35973037a42650fa2d7569da8e88cb81215cf971
## What changed
- Add `currentAccountOnly` to `thread/list` and `thread/search`, defaulting to `false`, and enable it for TUI history discovery, resume pickers, and task mentions.
- Mark newly created threads as account-scoped and require each recorded creator user or account ID to match the current login. Older threads and threads without creator IDs remain shared; API-key logins continue to see all local history.
- Preserve account scope through resume and revert, including fallback to original rollout metadata when an older binary drops the marker. Forks receive new-thread scope.
- Skip unreadable rollout headers in scoped discovery and filter search candidates before reading snippets. Direct access by thread ID remains available.
## Testing
Add coverage for account matching, shared legacy history, list page refilling, search pagination, API-key visibility, and scope preservation across reverts. Extend rollout lookup coverage to compressed active and archived files.
GitOrigin-RevId: aa374f5e69165be5a71c0716ded1b105f5fb51e0
## What changed
Keep inherited incremental tool declarations in MCP-disabled prediction forks and `thread/sample` requests, and append a developer notice that MCP tools are unavailable. Skip tool declaration updates within the inherited context window; new windows still declare the current tools.
Add the default-enabled `prediction_preserve_parent_tools` feature flag and its configuration schema entries.
## Testing
Update core snapshots and app-server tests to cover inherited declarations, the MCP-unavailable notice, preservation across MCP refresh, and continued parent tool availability.
GitOrigin-RevId: 3adf96c7d0e0093986dbdbd540bd47674a2c105c
## Why
Attached threads need inherited context for model requests while exposing only their own turns to clients. Parent turns and token usage should not appear as activity in an empty attached thread.
## What changed
- Stop attached-thread history traversal at the parent boundary, including after reverts, and hide inherited interruption markers.
- Apply visible-history boundaries to search, realtime timelines, and turn-specific fork and revert requests.
- Suppress inherited token-usage replay on paginated fork resumes, require fork replay to reference a returned turn, and skip empty turn IDs.
- Require a paginated source for `thread/fork` with `attachToSource` and update the protocol documentation.
## Testing
Extend regression coverage for attached-thread restart and database recovery, retained parent context in model requests, child-only history, mid-turn fork boundaries, legacy-source rejection, and suppression of parent token-usage notifications.
GitOrigin-RevId: 67858caf3bb74b7e79d4dd59bed9c61055fe0ff1
## Why
A running turn can record stale permissions after the thread accepts a settings update. Resuming or forking from that history should preserve the accepted approval and permission settings.
## What changed
- Prefer settings snapshots owned by the source thread over stale turn contexts, including later legacy updates associated with that thread's checkpoint.
- Restore unnamed permission profiles from attributable settings updates while honoring explicit request overrides. Avoid restoring raw permission grants from history without an identifiable owner.
- Share permission restoration logic between resume and fork.
## Testing
Add regression coverage for stale turn contexts, legacy updates across thread ownership boundaries, and unnamed permission restoration on resume and fork.
GitOrigin-RevId: 450bc1688be78c7ec685f6dc56bcc5e5dd2d130a
## What changed
- Add nullable `startedAtMs` and `completedAtMs` fields to `ThreadItem` in live notifications and turn history. Values are Unix milliseconds when recorded.
- Preserve recorded item times through history reconstruction, pagination, and resume, including command start times recorded during approval.
- Separate the Rust item payload into `ThreadItemPayload` while keeping the JSON payload flat, and update consumers, schemas, and generated TypeScript and Python types.
## Testing
Extend coverage for timestamp serialization, history reconstruction, paginated reads and resume, and persisted Python SDK items.
GitOrigin-RevId: ecbcee95af52db7c807b46a6e9deb30e5fba1f80
## What changed
- Add `attachToSource` to `thread/fork` to persist a fork attached to its source without emitting `thread/started`. Attached forks require local storage and cannot use `ephemeral` or `deferGoalContinuation`.
- Hide attached threads from ordinary listings and add `attachedToThreadId` to `thread/list` for explicit discovery, including empty threads. Keep this relationship separate from spawned-agent parent and ancestor filters.
- Persist attachment metadata in rollouts and SQLite so it survives restarts and database recovery. Reject source deletion until its attached threads are deleted.
## Testing
Add coverage for legacy and paginated history, restart and missing or corrupt database recovery, filtered listings and pagination, resume, conflicting options, and deletion safeguards across store instances.
GitOrigin-RevId: 589f3174fc36f6054e75d65818360695645a5913
## What changed
Store `RolloutItem::SessionMeta` and `RolloutItem::Compacted` payloads in `Box` values and update their producers, consumers, and test fixtures. Preserve the existing serialized rollout format.
GitOrigin-RevId: 59fcc4beb47d23160872dcb6e95ace9b142d3d11
## What changed
Add `experimentalDisablePredictionMcp` to `thread/fork` and `disableMcp` to `thread/sample`. Disable MCP servers when requested and the inherited history contains incremental tools on Responses Lite. The fork option requires `experimentalPredictionMode: true`.
Apply disablement through a thread-local policy that excludes configured MCP servers and runtime contributions, including after MCP refresh. Preserve the inherited history prefix and append tool-removal instructions without changing the parent's tools.
## Testing
Add coverage for prediction forks with legacy and paginated history, flag validation, conditional disablement, MCP refresh, and sample/fork request parity. Add a request-history snapshot covering preserved history, tool removal across child turns, and unchanged parent tools.
GitOrigin-RevId: e31d602480e6550ed130d8152f538b8668280fa0
## Why
A live thread can have updated SQLite metadata before its rollout file exists.
Reading metadata from the missing file loses creation details such as fork and
parent relationships and triggers unnecessary filesystem discovery and retries.
## What changed
- Read deferred `SessionMeta` through the rollout writer, ordered with persistence.
Return no in-memory metadata once the rollout is materialized or resumed.
- Combine that creation metadata with SQLite metadata for reads that exclude
history, and use it to determine the canonical history mode during updates.
- Keep untouched threads without a stored record unavailable for fork and resume.
## Testing
Add coverage for metadata reads and updates before persistence in both legacy and
paginated history modes, including equality with metadata read after persistence.
Verify the recorder exposes creation metadata only while deferred, and expand
fork/resume rejection tests across history modes and resume turn inclusion.
GitOrigin-RevId: 8d293cc8f87156409f195130437d93858a4099b9
## Why
Thread unload timing used the server-wide delay, ignoring per-thread configuration overrides. Clients need to control how long individual idle, unsubscribed threads remain loaded.
## What changed
- Resolve unload timing from each loaded thread's `thread_unload_delay_secs` configuration. Setting it to `0` allows immediate unloading once the thread has no subscribers or activity.
- Allow this runtime retention override in `experimentalPredictionMode` forks while continuing to reject other configuration overrides. Reject negative values and delays too large to schedule.
- Replace the source-specific immediate-unload behavior with explicit configuration.
## Testing
Extend integration coverage for per-thread delays, unloading after active turns finish, fork overrides, and invalid prediction-fork delays. Verify that immediate unloading preserves persistent history and that cold resumes and ordinary nested forks use their default delay instead of retaining the previous runtime's override.
GitOrigin-RevId: fcb82bd73a101260c51e2a8476f94320c23ac929
## What changed
Set the app server's unload delay to zero for ephemeral threads whose `thread_source` is `composer_predictions`, excluding subagent sessions. These threads unload once they are idle and have no subscribers, while active turns continue to completion.
## Testing
Extend integration coverage to check immediate unloading after an active prediction turn finishes and after unsubscribing from a fork that inherits the prediction configuration. Verify that persistent threads and ephemeral threads without the prediction source retain the configured delay.
GitOrigin-RevId: 04a0e405b666c689ccf6f482055d24692b18ead0
## What changed
- Add the disabled-by-default `output_token_replay` feature to request `output.encrypted_content` from OpenAI providers.
- Preserve encrypted message and tool-call output, message and function-call status, and output-text `annotations` and `logprobs` through history and replay. Update the generated protocol schemas and SDK types.
- Strip output ciphertext from requests to other providers while retaining it in stored history, including after replay is disabled. Remove encrypted content from memory extraction inputs.
## Testing
Add integration coverage for the feature/provider combinations, metadata replay across follow-up requests, and history preservation when resuming with replay disabled.
GitOrigin-RevId: 77729a021b6771933402aebe74ece8eb39c057e2
## What changed
- Add experimental `readState` to `thread/read` and a thread-ID-keyed `readStates` map to `thread/list` for eligible durable local user threads. Each receipt contains `firstUnread` and an opaque `revision`.
- Publish new visible terminal results before `turn/completed`, after flushing the rollout. Reading snapshots leaves activity unread; replayed history does not publish new activity.
- Clear unread positions removed by a paginated thread revert while preserving explicit thread-start marks and concurrent receipt updates.
## Testing
Add an integration test covering completed-turn receipts, repeated reads without acknowledgement, matching list receipts, and revert cleanup with a changed revision.
GitOrigin-RevId: e7f6ddfbb1fc2fa95d1ef2876d7f0f7b9f99ff65
## Why
Prediction forks need to preserve the parent's effective context and request settings to maximize prompt-cache reuse.
## What changed
- Add `experimentalPredictionMode` to `thread/fork` for ephemeral forks of loaded, persisted parents. Reject configuration overrides, `path`, `lastTurnId`, and `beforeTurnId` in this mode.
- Inherit the parent's effective configuration, tools, environments, collaboration settings, disabled plugins, and persisted history.
- Enable `features.reasoning_effort_override` on the fork while preserving the parent's request-effort baseline, including when overrides were disabled on the parent.
- Report the fork's effective model, service tier, and reasoning effort in the response.
## Testing
Add coverage for matching parent and fork requests and prompt-cache keys across legacy and paginated history, invalid fork parameters, and reasoning-effort inheritance. Add a context snapshot for identical parent and fork continuations.
GitOrigin-RevId: 46b41f2ac331562b441dadff1a0a9f926c94880d
## Why
Clients displaying a saved manual thread order need to list the remaining threads without repeating those already loaded separately.
## What changed
Add optional `excludedThreadIds` to `thread/list` and the generated protocol bindings. Apply exclusions before the result limit, refilling pages until the requested limit is reached or history is exhausted while preserving existing filters and ordering. Clients must send the same exclusions on each page.
Accept up to 100 entries, counting duplicates toward the bound. Reject invalid IDs or oversized lists with JSON-RPC error `-32602` rather than truncating them. Omitted, null, and empty lists preserve existing behavior.
## Testing
Add integration coverage for page refill across database-only and scan/repair paths, archived threads, sort directions, and project/section scopes. Cover duplicate and unknown IDs, the 100-entry boundary, invalid input, and preservation of section order.
GitOrigin-RevId: e9a884e642ae25d166aff7e275469d1d43179c6c
## Why
Clients starting delegated work need to attribute descendant turns to the original turn and retain that attribution through completion and history reads.
## What changed
- Accept optional `parentTurnId` and `rootTurnId` in `turn/start`, and expose `rootTurnId` on returned turns and lifecycle notifications.
- Default new turns to their own root when none is supplied. Preserve the active turn's root when steering, ignoring incoming lineage fields.
- Carry root IDs through completion, interruption, recovery, and fork boundaries, and persist them for paginated history reads. Leave unknown roots null in older history.
- Update protocol schemas and generated TypeScript and Python bindings.
## Testing
Extend coverage for default and explicit roots, steering without changing lineage, interrupted and recovered turns, history reads after restart in both history modes, nested fork pagination, and compatibility with older database writers.
GitOrigin-RevId: f1a570a12bd11742929fd2e8b017e5d35aa07dcb
## Why
Recovering an interrupted turn replaced its original trigger with `retry` and restored only its root lineage from model context. Turns suspended before that context was written could lose their attribution entirely.
## What changed
- Persist regular-turn attribution in `TurnStartedEvent` and compaction resume metadata, including the trigger, parent and root turn IDs, and initiating agent path.
- Restore matching attribution during recovery, keep unknown triggers absent, and retain the model-context root fallback for older records.
- Reconstruct attribution from surviving turns across rollback and late completion or abort events, and clear inherited attribution when spawning a forked agent.
## Testing
Add coverage for repeated cold recovery, suspension before context persistence, legacy rollouts, fresh attribution on subsequent turns, compaction checkpoints, rollback, and late terminal events.
GitOrigin-RevId: 85b5763e8fbd48a1ea2c07cfda8196e63c2cd33a
## What changed
Copy the source thread's current attachments when creating a non-ephemeral fork, including forks at an earlier turn. Copies receive new attachment IDs and creation timestamps while preserving resource identities and payloads. Attachment membership can then change independently on either thread; referenced resources are not copied.
Await the atomic copy before publishing the fork. If copying fails, log the error and allow the conversation fork to succeed without attachments. Resuming a fork does not copy attachments again.
Document that clients should use `forkedFromId` on `thread/started` and fetch the fork's attachments with `thread/attachment/list`; copying does not emit per-attachment updates.
## Testing
Add coverage for atomic rollback, independent attachment membership, inheritance across history cutoffs, successful conversation forks after copy failures, and resuming without restoring removed attachments.
GitOrigin-RevId: 939d2c6a3073ccfcd922380c6beda45d3deac606
## Why
Persisted turn-start events lack the originating root turn ID, so they cannot directly associate child turns with the root turn that initiated them.
## What changed
- Add optional `root_turn_id` to `TurnStartedEvent`. Use the inherited root turn ID when available, otherwise the turn's own ID.
- Centralize turn-start emission for regular turns, shell commands, and manual compaction so they record attribution consistently.
- Carry attribution into `ThreadHistoryTurnChange` when processing turn-start events and retain it through completion in the history builder.
- Keep older records compatible by defaulting missing attribution to `None`.
## Testing
Add coverage for root and child turn attribution, persistence when tool collisions fail a turn before sampling, history change propagation, and deserialization of older turn-start records.
GitOrigin-RevId: 54a80b828ca7d1c4c19f13d468c01d052e1b9130
## What changed
- Add the creation-time `originator` to app-server thread responses and `thread/started` notifications.
- Persist originators in thread metadata and preserve the first recorded value across list, read, resume, rollout, and SQLite paths.
- Add an `originators` allowlist to `thread/list` for hosted backends. The local app-server accepts omitted or empty values but rejects nonempty filters.
## Testing
- Cover originator persistence across server restarts and list, read, and resume requests.
- Verify local `thread/list` handling for nonempty, omitted, null, and empty originator filters.
- Heap-allocate large TUI dispatcher futures in affected tests to keep them within the Windows test-thread stack.
GitOrigin-RevId: 73ad6e61b8fdd2d93a22d1f971723a19ec7be3fc
## Why
Directly deserializing the flattened `RolloutLine` envelope can reject nested
decimal values, preventing affected paginated sessions from resuming.
## What changed
- Add canonical string, byte, and reverse-scanner helpers that decode rollout
records through `serde_json::Value` before decoding the flattened item.
- Route rollout readers across session discovery, history, migration, search,
thread storage, and transcript previews through those helpers.
- Remove `Deserialize` from `RolloutLine` so new readers cannot bypass the
canonical persistence decoder.
## Testing
Add coverage that resumes a paginated rollout after a token-count record with
a decimal rate-limit value and verifies that ordinal sequencing continues.
GitOrigin-RevId: 49abac1e0751c073daa5a93a840d8a483fd2d013
## Why
Forking a resumed paginated thread failed when the managed `sessions` directory was a symlink, even though the rollout remained under that managed root.
## What changed
- Validate rollout lineage references against the canonical `sessions` and `archived_sessions` roots.
- Accept rollouts beneath symlinked managed roots while rejecting nested symlinks that escape those roots.
## Testing
- Cover forking a resumed rollout under a symlinked `sessions` root.
- Cover rejection of rollout lineage paths that escape through a nested symlink.
GitOrigin-RevId: 0128ecde7087120ef510baa3ed62cdbb33073117
## What changed
- Add the zero-based `window_number` to Responses turn metadata and include it in prewarm requests.
- Persist `forked_from_ordinal_exclusive` separately from the physical history base so fork lineage remains accurate after reverts and cold resumes.
- Report context-inheriting subagents through `parent_thread_id` without also emitting fork lineage.
- Reserve the new metadata keys while accepting and filtering previously valid configured values so Codex-owned values take precedence.
## Testing
- Cover window numbering across compaction, resume, and fork operations.
- Cover fork cutoff persistence across direct forks, legacy rollouts, reverts into inherited history, and cold resumes.
GitOrigin-RevId: 288f6cd632254814c1f166668b33828082d799a1
## Why
Paginated thread history should be loaded incrementally through
`thread/turns/list` and `thread/items/list` instead of being fully reconstructed
in `thread.turns`.
## What changed
- Emit `deprecationNotice` when `thread/read`, `thread/resume`, or `thread/fork`
requests full history for a paginated thread.
- Direct clients to omit `includeTurns` for reads or use `excludeTurns: true` for
resumes and forks, then page history through the list APIs.
- Document the deprecation in the protocol schemas and app-server README.
## Testing
- Cover notices for paginated reads, cold and loaded resumes, and forks.
- Verify metadata-only requests, legacy threads, and rejected forks do not emit
the notice.
GitOrigin-RevId: 0d387b46d73608f90b7960120a54af4ef332e510
## Why
Cold resumes and forks could lose the thread's active permission profile and
fall back to the current configured default.
## What changed
- Restore the latest persisted approval policy, approvals reviewer, and active
permission-profile ID when resuming or forking a thread.
- Re-resolve persisted profile IDs through current configuration and
requirements. Missing or invalid profiles fall back to the configured
default, while threads without a persisted profile continue to use current
configuration.
- Keep explicit permission and approval overrides ahead of persisted settings.
## Testing
Added coverage for legacy and paginated histories, settings updates, explicit
overrides, removed or changed profiles, requirement fallbacks, and forks.
GitOrigin-RevId: 2289af2f3206bf131a6ffe0e8447e8d402e76c47
## 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 `codex-history` for model-history and persisted-rollout domain types, including `RolloutItem`, `RolloutLine`, `CompactedItem`, and initial/resumed history state.
- Re-export the persisted types from `codex-rollout` and update consumers to use the new crate boundary instead of `codex-protocol`.
- Preserve existing rollout serialization, including legacy numeric compacted-window IDs.
## Testing
- Add `codex-history` tests for rollout JSON round trips, compacted-history compatibility, persisted history modes, and multi-agent version selection.
GitOrigin-RevId: 944daa9297ddd231d3aebbdcb05fff4adf8b4e1b
## What changed
- Keep paginated resume, transcript, and fork workflows on bounded turn and item page requests, while preserving the legacy full-history fallback.
- Refill underfilled terminal scrollback from older pages and show a transcript shortcut when earlier history is unloaded or truncated by the row cap.
- Preserve a successfully created fork if its initial history hydration fails, keep side forks bounded, and retain the correct history boundary for nested forks and subagents.
## Testing
- Add coverage for scrollback refill and truncation notices, bounded paginated requests, fork hydration failures, nested forks, and inherited subagent history filtering.
GitOrigin-RevId: 10ba952ffb2f69717fbc71aa03cac7685f7dcf78
## What changed
- Restart the test app server before injecting the source thread's active goal so a late idle hook cannot continue it.
- Remove the unrelated ordinary-fork assertion and keep the scenario focused on deferred goal continuation across paginated forks.
GitOrigin-RevId: 5383f56ffa1687a4ebd18b5e37cbd61290fa59a7
## What changed
- Replace the `isPinned` thread metadata and filters with an optional persisted
`section` and `sectionId`.
- Add the paginated `threadSection/list` app-server method so clients can
discover sections even when they contain no threads.
- Seed a stable `Pinned` section, validate section assignments, and support
filtering for a specific section or for unsectioned threads.
## Testing
- Cover section protocol serialization, listing and pagination, metadata
updates, filtering, persistence, migration compatibility, and operation
without SQLite state.
GitOrigin-RevId: 7972b5471d29317b9387bfd90aa9f573f691ad4c
## What changed
- Set the Rust recursion limit to 256 for both the MCP server library and binary crates.
- Populate `started_at_ms` in the thread-fork test's completed-item fixture.
GitOrigin-RevId: b25eeaeecaf94265fe3be8f23cb3c395595afc2a
## What changed
- Allow `thread/fork` to create an ephemeral fork from paginated history when
`excludeTurns: true` is set, and return an invalid-request error otherwise.
- Preserve the selected history and fork preview without creating a rollout
path or exposing the ephemeral thread through `thread/list`.
## Testing
- Cover full-history and bounded ephemeral forks, active-turn boundaries,
preview selection, model input, and thread listing behavior.
GitOrigin-RevId: 4c0d9739b3310d7d0d7389bec127045ac4f55b44
## Why
`thread/fork` rejected threads using paginated history, so they could not use the same fork workflow as legacy threads.
## What changed
- Create paginated forks by referencing a frozen source-history prefix while persisting only child-owned records in the new rollout.
- Support latest, `lastTurnId`, and `beforeTurnId` boundaries, including inherited lineage, model-context reconstruction, interruption markers, and approval-reviewer inheritance.
- Make paginated reads and occurrence search traverse referenced history while excluding source records added after the fork.
- Coordinate fork preparation with archive and delete operations, and materialize compressed rollouts before they become fork references.
## Testing
Added app-server and thread-store coverage for boundary selection, active turns, inherited reads and search, compressed lineage, and concurrent source lifecycle operations.
GitOrigin-RevId: 66052d69517d7fb97a3b7817ab77a39c5ad995fd
## Why
Codex and SQLite data can use separate home directories, but state consumers
could reconstruct database paths from the Codex home instead of consistently
using the resolved SQLite configuration.
## What changed
- Pass `SqliteConfig` through the core, rollout, state runtime, and thread store
instead of passing a directory and rebuilding the configuration downstream.
- Use that shared configuration for state, logs, memories, goals, and paginated
thread-history database access, including integrity checks and cleanup.
- Reject state database handles whose SQLite configuration does not match the
requesting store.
## Testing
Add coverage with separate Codex and SQLite homes that verifies startup
backfill, thread listing, and paginated history all use the configured SQLite
directory.
GitOrigin-RevId: 1de1cdd1d6ff1d70bbb6c360c8352e6543fb8ebf
## What changed
- Add `isPinned` to thread responses and allow `thread/metadata/update` to pin or unpin stored threads.
- Add an `isPinned` filter to `thread/list`, including cursor-based pagination and combinations with relationship filters.
- Persist pin state in SQLite without modifying rollout files, default existing threads to unpinned, and preserve pins through reconciliation and archive transitions.
## Testing
- Cover protocol serialization, database migration and indexing, pin updates, filtered pagination, rollout reconciliation, and archive/unarchive behavior.
GitOrigin-RevId: c2eacabd6dae465e2ae6ce8a169e00740960cdb7
## What changed
- Add typed helpers for initialized app-server instances, JSON-RPC requests,
responses, notifications, and thread startup.
- Add a composable `MockResponsesConfig` builder while preserving the existing
mock config writers.
- Migrate the app-server integration suite to the shared helpers, removing
repeated request ID management, deserialization, initialization, and config
assembly.
## Testing
- Add unit coverage for composing mock provider, feature, and extra config, and
for compatibility of the existing mock config writer.
GitOrigin-RevId: 62da177c1d6e8299400de64bd6766567bf1ba3d8
## Why
Forking a persisted thread could lose its approvals reviewer and fall back to
configuration defaults.
## What changed
- Restore the latest persisted approvals reviewer from the full source history
when creating a fork, while continuing to honor explicit overrides.
- Keep boundary-based history truncation independent from reviewer restoration,
so a fork at an earlier turn retains the source thread's latest setting.
## Testing
- Add an app-server test that sets auto-review, forks at an earlier turn, and
verifies the fork reports auto-review.
GitOrigin-RevId: 41c515755de7de600f71c1259f96908f2d169ca7
## What changed
- Add experimental `beforeTurnId` support to `thread/fork` for copying history strictly before a turn, including an in-progress turn.
- Use before-turn forks for TUI backtracking and safety retries so the replacement prompt retains thread context instead of recreating the branch from the preceding turn or a new thread.
- Add experimental `deferGoalContinuation` support so safety-retry forks can inherit an active goal while waiting for the replacement turn before automatic continuation resumes.
- Hide duplicated nested-review prompts when replaying history or selecting a prompt to edit.
## Testing
- Cover before-turn truncation, fork validation, active-goal inheritance, TUI safety retries, backtracking, and nested-review replay.
GitOrigin-RevId: 4915d85ae1929a0b8c40f3ed7dca29c7a5bdcdf3
## What changed
- Check the source thread's `history_mode` before loading its history for
`thread/fork`.
- Return the existing `paginated_threads is not supported yet` method-not-found
error for paginated source threads.
## Testing
- Add an app-server integration test covering rejection of a paginated source
thread.
GitOrigin-RevId: 49b4b8aef7c9488eec93c24e831cea6382f8c995
## Why
We should be running as many integrations tests as possible against the
split cross-OS configuration.
## What
- migrate eligible thread starts and builders to auto env
- keep explicit custom/local-executor cases local with rationale
comments
- keep auto-env coverage where possible and add narrow `TODO(anp)` skips
for fixtures that are not target-native yet
## Description
This adds stable optional `turnId` support to `thread/fork`. When
supplied, the fork copies persisted history through that terminal turn,
inclusive, and drops later turns from the new thread.
Omitting or passing `null` preserves the existing full-history fork
behavior, including the interruption marker when the stored source
history ends mid-turn.
## Why
We're deprecating `thread/rollback` and this will help certain UX use
cases work around it by using `thread/fork` + `turn_id` instead.
## Why
Desktop Work threads and regular Codex threads can share the same
app-server connection. App-server analytics currently copy
`product_client_id` from connection metadata for every thread-scoped
event, so Work thread activity is attributed to the Desktop connection
instead of the thread's resolved originator. This prevents analytics
from distinguishing the two products on a shared connection.
## What changed
- Publish the resolved originator after a thread is materialized,
covering new, resumed, forked, and subagent threads.
- Store that originator in the analytics reducer's existing per-thread
state.
- Override only `app_server_client.product_client_id` for thread, turn,
tool, review, goal, guardian, and compaction events while preserving the
connection's client name, version, and transport metadata.
- Fall back to the connection-wide product client ID when a thread has
no originator override.
- Preserve persisted originators in thread initialization analytics for
resume and fork flows.
## Validation
- `just test -p codex-analytics
thread_originator_overrides_shared_connection_across_thread_events
subagent_events_keep_thread_originator_with_explicit_turn_connection`
- `just test -p codex-app-server
turn_start_tracks_thread_originator_in_analytics
thread_start_tracks_thread_initialized_analytics
thread_fork_tracks_thread_initialized_analytics
thread_resume_tracks_thread_initialized_analytics`
- `just test -p codex-core thread_manager`
## Why
`thread/list` can filter direct children with `parentThreadId`, but
clients cannot request an entire spawned subtree. Discovering every
descendant requires repeated client-side requests and gives up the
database's existing filtering and pagination path.
## What changed
Experimental clients can use `ancestorThreadId` to return strict
descendants at any depth while `parentThreadId` retains its direct-child
meaning. The filters are mutually exclusive, the ancestor is excluded,
and every result preserves its immediate `parentThreadId` so callers can
reconstruct the tree.
## How it works
- **Explicit relationship:** Internal list parameters distinguish direct
children from transitive descendants without changing the meaning of
`parentThreadId`.
- **Existing graph:** Persisted parent-child spawn edges remain the
source of truth, so descendant lookup needs no schema migration or
ancestry cache.
- **Indexed traversal:** A recursive SQLite query starts from the
parent-edge index, walks each generation, and applies thread filters,
sorting, and cursor pagination in the same database request.
- **Reconstructable results:** The response stays flat and normally
ordered while carrying each descendant's immediate parent.
## Verification
Ran 550 tests across the protocol, state, rollout, and thread-store
crates, then reran the four focused state, store, and app-server
descendant-listing tests after the final diff reduction. Scoped Clippy
and formatting checks passed. Stable and experimental schema generation
was checked; the stable fixtures remain unchanged while the experimental
schema includes the new field.
## Why
Topology-neutral app-server integration tests should exercise automatic
environment selection so the same setup covers local and remote
executors.
## What
Migrate eligible tests to `TestAppServer::new_with_auto_env()` and
`send_thread_start_request_with_auto_env()`. Leave explicit-topology
tests unchanged, and skip the request-permissions case on Windows with a
TODO for cross-platform tool routing.
## Validation
- `just test -p codex-app-server`
- `bazel test //codex-rs/app-server:app-server-all-wine-exec-test
--test_output=errors`
Stacked on #29788.
## Why
Clients that display or coordinate spawned subagents need an
authoritative snapshot of a thread's immediate spawned children when
they connect to app-server or recover after missing live events.
`thread/list` cannot query by parent, so clients must otherwise scan
unrelated threads or reconstruct relationships from rollout history and
transient events.
The direct spawn relationship already exists in persisted
`thread_spawn_edges` state. Review and Guardian threads do not
participate in that lifecycle and are intentionally outside this
filter's scope.
## What changed
This adds an experimental `parentThreadId` filter to `thread/list`.
Parent-filtered requests return direct spawned children from persisted
state while preserving the existing response shape, explicit filters,
sorting, and timestamp-only cursor behavior. The lookup does not read
rollout transcripts or recursively return descendants.
Supersedes #25112 with the narrower `thread/list` filter approach.
## How it works
1. An experimental client passes a valid thread ID as `parentThreadId`.
2. App-server routes the list through the existing thread-store and
state-database boundaries.
3. SQLite selects threads whose IDs have a direct persisted spawn edge
from that parent.
4. Omitted provider and source filters include all values; explicit
filters keep ordinary `thread/list` semantics.
5. Grandchildren, Review threads, and Guardian threads are excluded.
## Verification
State (144 tests), rollout (69 tests), and focused app-server
thread-list (31 tests) suites passed. Scoped Clippy checks and
repository formatting also passed. Coverage includes direct spawned
children, omitted grandchildren, pagination, malformed IDs, mixed source
kinds, explicit filters, and operation without rollout files.
## Why
- Thread initialization analytics do not identify the source thread for
forked threads.
- The session viewer needs this lineage to construct thread trees.
- Depends on openai/openai#987854. Do not release this change before
that backend schema change is deployed.
## What Changed
- Adds optional `forked_from_thread_id` to `codex_thread_initialized`.
- Populates it from the existing thread fork lineage for app-server and
in-process subagent initialization paths.
- Keeps it null for non-forked threads.
## Verification
- `just fmt`
- `just test -p codex-analytics`
- `just test -p codex-app-server
thread_fork_tracks_thread_initialized_analytics`
Fixes#25950.
## Why
Forking a renamed thread could fall back to the source thread's
first-prompt title because the fork path did not preserve the source's
explicit name. That meant fork-of-renamed-fork flows could show stale
sidebar labels even though the user had renamed the parent.
## What changed
`thread/fork` now reads the source thread's distinct `name`, normalizes
it, persists it onto materialized forks, and applies it to the returned
API thread. Because the source `name` already excludes first-prompt
pseudo-titles, forks inherit only an explicit user rename instead of
stale generated metadata.