Commit Graph
63 Commits
Author SHA1 Message Date
marksteinbrick-oai 2b21129c6b Add Responses API client metadata patches for turn start and steer (#54053)
## Why

Clients need a way to update individual turn metadata entries without replacing the existing client metadata map.

## What changed

Add the experimental `responsesapiClientMetadataPatch` field to `turn/start` and `turn/steer`. Patches add or overwrite entries while retaining other keys and apply after `responsesapiClientMetadata` when both are supplied. The existing field retains replacement semantics, including clearing unprotected entries with an empty map.

Continue protecting reserved metadata keys and preserving targeted `misalignment_override` continuations across updates.

## Testing

Extend the app-server metadata integration test to cover replacement and patch steering, patch precedence at turn start, preservation of unrelated entries during patches, and protection of targeted continuations.

GitOrigin-RevId: 8c4da3ba1b87329da20b5295846bdcf3a88126de
2026-10-14 17:39:43 +00:00
reia-oai 14c8b7771a Attribute compaction analytics to the correct voice session (#51963)
## Why

Compaction analytics lack a voice session ID. A compaction event can arrive after its voice session has closed or another session has started, so attribution needs to account for when compaction began.

## What changed

Add `voice_session_id` to compaction events. Track realtime session starts, ID updates, and closures, retaining up to 16 recent closed session windows. Resolve the session from the compaction start timestamp, falling back to the turn's voice session ID.

Forward realtime session ID updates from the app server to analytics and update the active turn's attribution.

## Testing

Add coverage for realtime session boundary facts, compaction event serialization, and delayed compaction events across consecutive voice sessions.

GitOrigin-RevId: 981da0ea2c38a87079b6bab33daf2c88fd95160f
2026-10-08 05:29:11 +00:00
Eddie Chen cfc946f4e1 Expose and persist turn lineage across the app server (#51415)
## 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
2026-10-06 16:56:39 +00:00
Adam Perry @ OpenAI bcd6d9ab6b Add regression coverage for account switches between analytics batches (#49489)
## What changed

Add a debug-only analytics test that switches accounts after the first isolated event request. Assert that only the first request reaches the server and carries the original account's credentials, so subsequent batches do not send stale credentials after the switch.

Remove an unused `ToolCallSource` import.

GitOrigin-RevId: e66904c7a7176f1eaa37662b836132586328884a
2026-09-30 05:29:56 +00:00
papayo-oai 2e6cc4ed8d Attribute analytics requests to each thread's product SKU (#49117)
## Why

Sessions can share an analytics client while using different product SKUs. Analytics requests need per-thread attribution to reflect each session's configuration.

## What changed

- Register each thread's `apps_mcp_product_sku` and send `X-OpenAI-Product-Sku` on analytics requests grouped by product, without changing authentication.
- Send product groups concurrently while preserving event order within each group.
- Flush buffered tool events before changing or evicting their product attribution, and clear attribution when a session disables analytics.
- Bound retained thread registrations and concurrent product groups. Drop attribution when registration cannot be queued or a batch exceeds the product-group limit.

## Testing

Add tests for shared-session attribution, clearing attribution on resume with analytics disabled, buffered events across product changes, queue overflow recovery, registry limits, and concurrent delivery with preserved event order.

GitOrigin-RevId: 25a98788cd44d4a85f97ee87aadf3a6909607f6a
2026-09-29 00:49:23 +00:00
acrognale-oai 8f8ace78cb Enforce application network policy for AWS auth and telemetry (#47408)
## Why

AWS credential discovery, analytics, and telemetry used clients that did not share the application's network policy. These requests need to honor destination restrictions and permission revocation.

## What changed

- Route AWS credential and region HTTP requests through the shared HTTP client, and check the signing destination before loading credentials. Skip discovery for static access keys with an explicit region.
- Apply account-scoped policy to Bedrock authentication. Require unrestricted policy for credential exporters and reauthentication commands, and cancel active work when permission is revoked. Document that AWS profile `credential_process` network traffic remains outside the application's HTTP policy.
- Send analytics through the authenticated account's HTTP client factory.
- Guard OTLP log, trace, and metric exports with revocable permits, disable them under destination restrictions, and make managed HTTP exports cancellable. Suppress global Statsig settings while managed policy is active.

## Testing

Add coverage for metadata credential request cancellation, allowed and denied SigV4 destinations, AWS credential precedence and endpoint configuration, and blocked credential exporter recovery. Update telemetry tests for account transitions and managed-policy Statsig suppression.

GitOrigin-RevId: d8a2018bfbbe971ec430699b0d3f86a7a9e1e072
2026-09-23 00:47:34 +00:00
Eddie Chen 6a601c00da Preserve originating turn metadata for yielded skill calls (#47106)
## Why

Code Mode callbacks can retain skill tools after another turn becomes active. Looking up the active turn when a delayed skill invocation completes can lose access to the originating turn's metrics and metadata.

## What changed

- Capture and retain the originating `SkillTurnMetrics` when constructing skill analytics.
- Expose turn analytics metadata through the turn extension store and carry it into skill telemetry.
- Add optional turn metadata to `TrackEventsContext` and pass it from app, skill, and plugin usage call sites.

## Testing

Add a regression test that yields a Code Mode cell, starts another turn, and releases both skill reads through a shared barrier. Assert that each `skill_invocation` event retains its originating `turn_id`.

GitOrigin-RevId: aa629dd5f84563d558aa6a86bfbdfc356f1b98e4
2026-09-21 20:34:46 +00:00
Chris Dong 8ace915ace Attribute analytics events to realtime voice sessions (#46058)
## What changed

Add `voice_session_id` to turn, app-use, skill-invocation, and MCP tool-call analytics events. Track realtime session lifecycle and handoff markers to preserve attribution when a handoff starts a turn after the voice session closes, or steers an active turn. Keep that attribution from carrying over to subsequent text turns.

Record handoff markers using only the thread ID, without retaining transcript content in analytics facts.

## Testing

Add coverage for attribution after realtime closure, active-turn steering without tagging the next text turn, and handoff markers that exclude transcripts. Extend event serialization and MCP tool-call tests for `voice_session_id`.

GitOrigin-RevId: 024b0e7e4c6fbaf8325574de6c24c048bb4ca032
2026-09-16 23:33:00 +00:00
priyanshusingh-de b0af519c39 Add elicitation classification support to app and MCP analytics (#45649)
## What changed

Add an optional `elicitation_type` to app-used and MCP tool-call events, with `auth_or_link` and `approval` classifications and `null` for unclassified calls. Existing core app-use tracking passes `None`.

Expose an API to queue MCP classifications by thread, turn, and item before completion. Preserve them across turn completion, consume them on item completion, and clear them on thread closure. Bound pending classifications to 256 entries, evicting the oldest when full.

## Testing

Add coverage for serialization, first-classification retention during app-use deduplication, per-call classification across turn completion, pending-state eviction and cleanup, and exclusion of tool arguments from emitted events.

GitOrigin-RevId: 185a2ccb38153e123fc731231edff0259a26bce3
2026-09-15 08:28:03 +00:00
Eddie Chen 12b0164a48 Classify tool analytics events by call origin (#45535)
## What changed

Add `tool_event_type` to tool analytics events, using exact call ID evidence to distinguish `model_tool_call` from `inner_tool_call`. Serialize `null` when evidence is missing or conflicting at emission time; later evidence does not revise emitted events.

Classify sampled code-mode `exec` and `wait` calls as model calls and dispatched child calls as inner calls, without inferring origin from cell associations or parent lineage.

## Testing

Add coverage for exact and ambiguous origin evidence and late sampling evidence. Extend serialization, code-mode, collaborator, and subagent tests to check the classification.

GitOrigin-RevId: a41085b4665b28b20026aa2bcb10ff7fa8af8778
2026-09-14 22:52:40 +00:00
Eric Traut 91d54f1667 Restore collaboration mode when resuming threads (#45519)
## Why

Resuming a thread initialized its collaboration mode to Default, losing the saved Plan mode and its developer instructions. Reconnecting clients also lacked a server-reported mode to reconcile changes made by another client.

## What changed

- Restore the saved collaboration mode from the latest matching `ThreadSettingsApplied` event, falling back to the last legacy `TurnContext`. Apply the effective model and reasoning effort while retaining the saved mode and developer instructions.
- Include `collaborationMode` in `thread/resume` responses and update the generated schemas and bindings.
- Use the restored mode in the TUI, including the first prompt after resume. Prefer the server's mode when restoring disconnected input, while preserving the local selection for older servers that omit it.

## Testing

Add regression coverage for persisted and legacy collaboration modes, model and reasoning-effort overrides, the resumed Plan mode display and first prompt, and reconnect behavior with and without a server-reported mode.

GitOrigin-RevId: ed064516e7fae1c1668152ab448f510cbcacfe06
2026-09-14 21:33:45 +00:00
jwang-openai 4d8eca1ff3 Attribute command and plugin analytics to the invoking model (#45445)
## Why

Command execution and plugin measurement events lack model and reasoning-effort labels. Attribution needs to reflect the step that invoked the command, even when model settings change before a background process finishes.

## What changed

- Add `model_slug` and `reasoning_effort` to command execution and plugin measurement analytics.
- Capture model context from resolved step settings and carry it through execution, approval, Guardian review, and plugin metrics collection.
- Preserve the first command-start model context when subsequent start notifications arrive.
- Keep the carried context out of serialized protocol items and generated schemas.

## Testing

Extend analytics tests to cover model switches before invocation and during background execution, default reasoning effort, Guardian-denied commands, and repeated start notifications retaining the original model context.

GitOrigin-RevId: af90e1c0d39bab625f2e89786085b61a9b96c0ce
2026-09-14 15:30:22 +00:00
Matthew Zeng c62d191c4c Expose disabled plugin settings in the app-server API (#44905)
## What changed

- Accept `disabledPluginIds` in `thread/settings/update` and `turn/start`. A supplied list replaces the saved selection; omission or `null` preserves it, and `[]` clears it.
- Return the selection in thread start, resume, and fork responses and `thread/settings/updated` notifications. Update generated schemas and client types.
- Restore disabled plugin IDs from the history retained at the requested fork boundary, preserving explicit overrides.

The selection persists across resume but does not yet filter plugin capabilities.

## Testing

Add coverage for replacing, preserving, and clearing selections without inference; turn-start notifications; resume; and fork boundaries across legacy and paginated history, with loaded and restarted parents. Add a core regression test for history restoration and explicit clearing.

GitOrigin-RevId: 654a8c2a0527228d422c0dd4919228447e2663db
2026-09-11 20:27:37 +00:00
marksteinbrick-oai 818f1cca8c Remove repo_url from skill invocation analytics events (#44586)
## What changed

Remove `repo_url` from `SkillInvocationEventParams` and stop including it in
`skill_invocation` payloads. Update the analytics test fixtures and expected
serialized payload to match.

GitOrigin-RevId: 06762143fb861a31298fbd8ab737b9b969edfc89
2026-09-10 17:03:11 +00:00
faizan-oai 3921a30d6b Persist Daybreak preferences in thread metadata (#42854)
## Why

Clients need a per-thread Daybreak toggle that survives restarts and can be
restored on resume without changing the access program of an active or future
turn.

## What changed

- Add experimental `daybreakEnabled` support to `thread/metadata/update` and
  expose the saved value on thread responses.
- Store the preference in SQLite, including for threads without a first turn,
  and preserve it through reads, resumes, reconciliation, and restarts.
- Copy the preference when forking a thread while keeping subsequent updates
  independent.
- Keep `daybreakEnabled` separate from the per-turn `cyberAccessProgram` field;
  app-server does not derive one from the other.

## Testing

- Cover persistence across restarts, cold reads, reconciliation, and forks.
- Verify metadata updates do not alter the access program of active or later
  turns.

GitOrigin-RevId: bcf987a9fcd7b0ac8a88b1c8f0df06b33ed8ad6e
2026-09-04 21:17:25 +00:00
Can Sar 728cb12fe5 Expose thread originators through the app-server API (#42458)
## 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
2026-09-03 06:02:25 +00:00
jwang-openai 36984da442 Include originator in plugin measurement analytics (#42445)
## What changed

- Add `originator` to plugin measurement inputs and emitted analytics events.
- Populate it from the turn originator when recording plugin measurements.
- Extend analytics tests to verify the originator is preserved in event payloads.

GitOrigin-RevId: 9998f829760222fc690dc8a10324794b5da27220
2026-09-03 04:38:26 +00:00
Anton Panasenko 2b554fd3f9 Expose loaded thread environments in app-server responses (#42386)
## What changed

- Add the experimental `Thread.environments` field with each selected environment's ID, working directory, and runtime workspace roots.
- Populate the field from live thread state in start, resume, read, list, and unarchive responses. Use `null` for unloaded threads and an empty list when a loaded thread has no environment selection.
- Document that the field reports selection rather than connection status and does not affect executor selection or resume behavior.

## Testing

- Cover selection updates, unloaded and resumed threads, loaded pathless unarchives, and clients that subscribe after environment connection notifications.

GitOrigin-RevId: a6daa06aff7089d7c5a1e4c7d03109b41f12fa3c
2026-09-02 23:41:14 +00:00
Brent Traut 986ff1cc7c Expose model settings in app-server thread metadata (#42151)
## What changed

- Add nullable `model` and `reasoningEffort` fields to the shared app-server `Thread` object and generated schemas.
- Report current settings for loaded threads and the latest persisted settings for unloaded threads across thread read, list, start, resume, rollback, metadata update, and notification paths.
- Keep unavailable legacy or filesystem-only settings nullable, and allow metadata reads without loading a thread or dispatching queued work.

## Testing

- Cover live-setting precedence, persisted settings after restart, null legacy values, and model metadata returned by thread lifecycle operations.

GitOrigin-RevId: 22ebe8a8d1910a820d90a97730d812a00d8c1372
2026-09-01 22:56:18 +00:00
Eddie Chen 49880081fe Add root turn IDs to turn and tool analytics (#40486)
## Why

Analytics need to associate subagent activity with the top-level turn that
caused it, while avoiding a stale association when steering makes that origin
ambiguous.

## What changed

- Add `root_turn_id` to turn and tool-item analytics events.
- Read the root from live turn metadata when each event is built, reporting
  `null` when the root is unknown or ambiguous.
- Propagate the metadata through control-tool and code-mode completion facts so
  correlated and background tool events retain the correct root.

## Testing

- Cover root IDs for top-level turns, subagent turns, correlated code-mode
  calls, and tool events emitted after turn completion.
- Verify that queued and subsequent events report `null` after the live root is
  invalidated.

GitOrigin-RevId: 42fd76541c3c716cec74787d47b50adb2d22e6d2
2026-08-24 22:30:59 +00:00
Eddie Chen cc801d7048 Enrich thread archive analytics with thread context (#39797)
## What changed

- Add app-server client, runtime, thread source, and parent thread ID metadata to archive and unarchive analytics events when the reducer has that context.
- Omit non-automation feature thread sources and skip unavailable metadata.

## Testing

- Cover archive and unarchive event enrichment, filtered feature sources, and threads without cached context.
- Verify the app-server archive flow emits the enriched analytics payload.

GitOrigin-RevId: 163f9c30721cee0172bb4581b6dcd269e44cd941
2026-08-20 20:44:31 +00:00
Anton Panasenko 3b4569a920 Add experimental app-server project APIs (#38940)
## What changed

- Add SQLite-backed `project/list`, `project/read`, `project/create`,
  `project/import`, `project/update`, `project/move`, and `project/delete`
  endpoints with ordered roots, metadata, manual positioning, pagination, and
  idempotent creation.
- Add project assignment to thread start, metadata updates, list filtering,
  and fork inheritance. Project deletion clears assignments without deleting
  threads.
- Emit `project/changed` and `thread/project/updated` notifications after
  committed changes, and export the new protocol schemas and TypeScript types.

## Testing

- Cover project lifecycle and ordering, idempotency, atomic imports, cursor and
  filter validation, thread assignment, deletion, and fork inheritance.

GitOrigin-RevId: 47ae621be01ab8ef70a74a629fb29a5c5709ea33
2026-08-17 04:01:37 +00:00
Tamir Duberstein 5c6f498b0e Stop generating accepted-line fingerprints (#38473)
## What changed

- Replace accepted-line fingerprint generation with diff-based added and deleted line counts.
- Keep `line_fingerprints` in the analytics payload as a statically empty field for schema compatibility.
- Remove the fingerprint types and public parsing API that are no longer used.

## Testing

- Update diff parsing tests to cover accepted-line counts without generating fingerprints.

GitOrigin-RevId: 4247c76c7b56b1a323f70f960823937352b84f7b
2026-08-14 01:44:33 +00:00
Kyle Brown d6eefb26a6 Add bounded plugin measurement analytics (#38239)
## What changed

- Add `PluginMeasurementsInput` and `PluginMeasurementRow`, plus an analytics
  client method for recording batches and checking whether analytics are enabled.
- Emit each valid row as a `codex_plugin_measurement_event` with thread, turn,
  item, plugin, execution, and operation context.
- Bound batches at 100 rows and reject non-finite values, invalid identifiers,
  and rows with more than eight dimensions.
- Treat measurement events as plugin events when routing API-key analytics.

## Testing

- Cover batch limits, row filtering, serialized event payloads, and API-key
  plugin-event routing.

GitOrigin-RevId: f949ed06246ee1e22466df2660076f2d4f556444
2026-08-12 19:14:09 +00:00
edwardysun3 44d992c14e Track artifact operations from trusted plugin markers (#38057)
## What changed

- Recognize validated create and edit marker commands from the trusted presentations, documents, spreadsheets, and PDF plugins.
- Emit a `codex_artifact_operation` analytics event plus started-count and expected-output-count metrics when a recognized marker starts through unified exec.
- Attribute remote executor commands only when their plugin cache path and script contents match a trusted local plugin, including primary-runtime plugins.

## Testing

- Cover supported marker combinations and reject mismatched plugins, paths, arguments, counts, and output formats.
- Cover local, relocated remote, and Windows-style plugin attribution, including rejection of modified remote scripts.

GitOrigin-RevId: 475cc1689aa7f371a24dec0a8bdb6f7fd5a2e922
2026-08-11 19:26:41 +00:00
Eddie Chen 70b4653232 Track thread archive analytics (#37199)
## What changed

- Emit `codex_thread_archive_event` when a thread is successfully archived or
  unarchived, including the thread ID, action, and producer timestamp.
- Route archive notifications through the analytics client while preserving
  normal app-server notification delivery.

## Testing

- Extend app-server coverage for archive and unarchive analytics, including
  descendant archives and a repeated archive request that fails without
  producing another event.

GitOrigin-RevId: 0d973c232fd795b7cd6cddd47ecc9446234c44dd
2026-08-06 02:30:18 +00:00
jif 155f1ca9e5 Correlate code mode tool analytics with model responses (#36729)
## What changed

- Emit dynamic tool-call analytics for code mode `exec` and `wait` calls, including duration and terminal status.
- Associate code-mode cells and their nested tool calls with the originating and subsequent model response IDs.
- Buffer correlated tool events until the next response is known, while flushing pending events when turns, threads, or the analytics queue close.

## Testing

- Add reducer coverage for correlating `exec`, `wait`, and nested tool events across turns.
- Add an app-server test that verifies production analytics include the cell and response IDs for a code-mode `exec` call.

GitOrigin-RevId: 8b34ab59c1ad68ebbd57f9c8a05f19ab04df48a4
2026-08-03 10:19:04 +00:00
alicec-oai 6219b7c40f Correlate image requests and explicit interrupts with turns (#36092)
## What changed

- Send the active turn ID in the `x-codex-image-turn-id` header for image generation and edit requests.
- Add `explicit_client_interrupt_requested_at_ms` to turn analytics. Record the earliest explicit interrupt request that receives a successful response, while excluding rejected requests.
- Track errors returned by `turn/interrupt` so pending analytics state is cleaned up correctly.

## Testing

- Cover turn ID headers for image generation and editing.
- Cover accepted, retried, and rejected explicit interrupt requests in analytics tests.

GitOrigin-RevId: 80fe996a161b4952b79c5c38238f75b7661b92af
2026-07-30 05:53:21 +00:00
Charlie Marsh 88d6c2b2b4 Avoid cloning ignored analytics notifications (#36020)
## What changed

- Pass server notifications to analytics tracking by reference.
- Clone only the notification variants that are recorded as analytics facts.

## Testing

- Add unit coverage that verifies a turn diff notification is enqueued and a command output delta notification is ignored.

GitOrigin-RevId: 2fa0711dbdcca33dce82c3ef78ee53a3f5a65bd9
2026-07-29 20:09:41 +00:00
joeytrasatti-openai ad6fc66b6d Add persisted manual ordering for thread sections (#36007)
## What changed

- Add `thread/section/move` to atomically move a thread into, within, or out of a section. Threads can be inserted before an existing member or appended, and moves within a section preserve `sectionEnteredAt`.
- Add `section_position` sorting to `thread/list`, with ascending order as its default, and expose `sectionEnteredAt` in thread responses.
- Persist section positions and entry times in SQLite, including migration of existing section members into recency order. Section membership is no longer updated through `thread/metadata/update`.

## Testing

- Cover section moves, reordering, pagination, persistence across restarts and rollout reconciliation, concurrent updates, and rank renumbering.

GitOrigin-RevId: aec6d7ddedca5277029b5caf5c074975397e956c
2026-07-29 18:37:22 +00:00
acrognale-oai c41a38dd10 Reduce response serialization and rollout scan overhead (#36006)
## What changed

- Keep `ClientResponsePayload` typed through the app-server outgoing queue and serialize it at the transport boundary, avoiding an intermediate `serde_json::Value` while preserving the JSON-RPC wire shape.
- Return a JSON-RPC internal error when a response cannot be serialized, including over remote control, and skip unserializable analytics responses.
- Scan reverse JSONL input a chunk at a time with a larger buffer instead of processing each byte individually.

## Testing

- Cover typed response serialization and serialization failures for direct and remote-control transports.
- Cover filtering unserializable responses from analytics.

GitOrigin-RevId: cc4fd7a43461a273315bb95261bd1ae3ff65fbf7
2026-07-29 18:29:26 +00:00
joeytrasatti-openai 85c6da1c79 Add persisted sections for organizing threads (#35722)
## 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
2026-07-28 05:26:16 +00:00
jameswt-oai 0d2a0aa76b Track remote plugin IDs in skill invocation analytics (#35262)
## What changed

- Add `remote_plugin_id` to skill invocation facts and analytics event parameters.
- Propagate the ID for both explicit and implicit plugin skill invocations.

## Testing

- Cover explicit and implicit remote plugin skill invocations with analytics integration tests.

GitOrigin-RevId: 3e1d25b5ff88dcff9c2b6c9fe44bca97e8778221
2026-07-24 23:40:14 +00:00
joeytrasatti-openai 400ee190c3 Add persisted thread pinning to the app server (#34840)
## 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
2026-07-22 22:54:28 +00:00
Ben Romano 88f1cd9664 Flush analytics before in-process app server shutdown (#34831)
## Why

The in-process app server can shut down while analytics for a completed turn are
still queued, preventing the completed-turn and accepted-line events from being
delivered.

## What changed

- Add a bounded analytics queue flush that waits for all preceding facts to be
  processed.
- Flush analytics after the in-process runtime drains its outbound work and
  before acknowledging shutdown.
- Extend the in-process shutdown timeout budgets to cover runtime draining and
  the best-effort analytics flush.

## Testing

- Verify that the flush waits for preceding facts and is a no-op when analytics
  is disabled.
- Verify that shutdown waits for delayed analytics delivery, including the
  completed-turn and accepted-line events produced by a file change.

GitOrigin-RevId: 57ca24e535e5e2f3f3202b2e5498f075676c910a
2026-07-22 21:35:16 +00:00
Felipe Coury 3f0669dbd6 Make parent-owned sub-agent threads read-only in the TUI (#33841)
## Why

Multi-agent V2 spawned threads are controlled by their parent and reject direct
app-server input. The TUI should expose that ownership instead of presenting an
input flow that the server will reject.

## What changed

- Add the experimental `Thread.canAcceptDirectInput` capability for loaded
  threads and populate it from the same policy used to validate `turn/start`
  and `turn/steer`. Stored, unloaded threads report `null`.
- Carry the capability through TUI thread discovery, selection, startup, and
  resume flows, with a compatibility fallback for older app servers.
- Present parent-owned threads as view-only, preserve drafts and queued input,
  block agent-directed commands and settings shortcuts, and keep local
  navigation and inspection commands available.

## Testing

- Cover V1 writable and V2 view-only spawned threads through selection and
  resume.
- Cover composer submission paths, queued and initial input preservation,
  allowed navigation commands, settings shortcuts, and the view-only UI.

GitOrigin-RevId: 495ad051249e5577fb0b0c1cc8c40a0998d04918
2026-07-17 15:14:47 +00:00
Owen Lin da61f7d8e1 Enable paginated thread history in app-server (#33364)
## What changed

- Allow `thread/start` to select experimental `historyMode: "paginated"` when the thread store supports turn and item pagination.
- Resume paginated threads with bounded model context and require `excludeTurns: true` instead of loading full history.
- Return `turnsBackwardsCursor` and `itemsBackwardsCursor` from `thread/resume` so clients can hydrate durable history through `thread/turns/list` and `thread/items/list` while newer records arrive through live notifications.
- Reject operations that still require full history, including `initialTurnsPage`, `thread/read` with `includeTurns: true`, `thread/rollback`, and detached review.
- Make item cursors independent of the optional `turnId` filter.

## Testing

- Cover paginated thread start, cold and live resume, backwards cursor hydration, metadata reads, unsupported operations, and stores without pagination support.

GitOrigin-RevId: c42f9b268e29d049843330f474fa3ecde12f5b8a
2026-07-15 15:29:13 +00:00
jif 6629e08702 Add an agent extension runner (#33076)
## What changed

- Add `codex-agent-extension` with an `AgentRunner` that starts a resolved agent prompt in a thread forked from its parent.
- Propagate the invocation's trace context, select the configured execution environments, submit the initial prompt, and return the spawned thread and turn identifiers.
- Reject empty agent prompts and report when the owning thread manager is no longer available.

## Testing

- Add an integration test that verifies the agent runs in a forked thread, returns the started turn identifier, completes the turn, and sends the resolved prompt to the model.

GitOrigin-RevId: ffb805efabadf758969d6611a6867db6fa9f059a
2026-07-14 14:41:30 +00:00
felixxia-oai 5bed644799 Send plugin analytics with API key authentication (#33040)
## What changed

Allow API key sessions to send plugin-attributed `codex_plugin_used`,
`skill_invocation`, and `codex_mcp_tool_call_event` events. Continue to drop
events without a plugin ID and all other analytics events for these sessions.

## Testing

Add coverage that mixes plugin and non-plugin events and verifies that only the
three plugin-attributed event types are delivered without server-owned auth
fields.

GitOrigin-RevId: 1f47af5e9516723154f566ad032dba3ebd98abf9
2026-07-14 11:21:25 +00:00
Owen Lin 5267e805fb feat(app-server): add history_mode to thread (#29927)
## Description

This PR adds a new `historyMode = "legacy" | "paginated"` to `Thread`.
This will be stored in `SessionMeta` in the JSONL rollout file and as a
new column in the SQLite thread_metadata table, and exposed on
`thread/start` and on the `Thread` object in app-server.

## What changed

- Added canonical `ThreadHistoryMode` with `legacy` and `paginated`,
defaulting old and new SessionMeta to `legacy`.
- Carried `history_mode` through core session config, ThreadStore stored
metadata, local/in-memory stores, rollout metadata extraction, and the
existing SQLite `threads` table.
- Added experimental `historyMode` to app-server v2 `Thread` and
`thread/start`.
- Made paginated stored threads metadata-discoverable but unsupported
for legacy full-history reads, `load_history`, live resume, and create
paths.
- Regenerated app-server schema fixtures and added
protocol/state/thread-store/app-server coverage for persistence and
fail-closed behavior.

## Compatibility floor
Because users may be running various versions of Codex binaries on the
same machine (TUI, Codex App, etc.), we will need to establish a
compatibility floor for upcoming paginated threads, which will change
how thread storage reads and writes work.

The overall plan here:
```
Release N:
- Add historyMode to SessionMeta / Thread / SQLite metadata.
- Teach binaries to understand paginated threads.
- If a binary sees `historyMode="paginated"` but does not support the paginated contract, it refuses to resume/mutate the thread.
- Default remains `"legacy"`.

Release N+1:
- First-party clients start opting into paginated threads where appropriate.
- Internal dogfood / staged rollout.
- Measure old-client usage and paginated-thread unsupported errors.

Release N+2:
- Only after Release N+ is overwhelmingly deployed, make paginated the default.
- Accept that a small tail of N-1-or-older binaries may not understand paginated threads.
```

The important behavior change is fail-closed handling for a binary that
encounters a persisted `paginated` thread before it knows how to fully
support paginated history. In app-server, if a thread is `paginated`, we
will:

- allow metadata-only discovery paths like `thread/list` and
`thread/read(includeTurns=false)`, so clients can still see the thread
and inspect its `historyMode`
- reject legacy full-history/live-thread paths like
`thread/read(includeTurns=true)` and `thread/resume` with an unsupported
JSON-RPC error
- avoid silently treating an unknown or future `historyMode` as `legacy`

Under the hood, the ThreadStore layer also rejects legacy operations
that would need to load or replay the full thread history for a
paginated thread. That gives us the behavior we want for Release N:
future paginated threads are visible, but this binary fails closed
instead of trying to operate on them as if they were legacy threads.
2026-06-26 09:12:42 -07:00
Boyang Niu 354807920e core: add extra metadata field to Thread struct (#29675)
# Summary

Adds a field Thread.extras that can be used to hold arbitrary metadata
specific to a given thread.
2026-06-23 19:15:59 +00:00
Dylan Hurd 2cf2a6a844 chore(core) rm AskForApproval::OnFailure (#28418)
## Summary
Deletes the OnFailure variant of the `AskForApproval` enum. This option
has been deprecated since #11631.

## Testing
- [x] Tests pass
2026-06-23 12:13:54 -07:00
Shijie Rao 7abfcf220b Expose thread-level multi-agent mode (#28792)
## 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.
2026-06-19 10:50:44 +02:00
Jeremy Rose 7dc7096ae1 [codex] Restore thread recency with compatible migration history (#28671)
## Summary

- Revert #28655, restoring the thread `recencyAt` behavior introduced by
#27910.
- Move `threads_recency_at` to migration 0039 so it no longer collides
with `external_agent_config_imports` at version 0038.
- Repair databases that already applied the recency migration as version
38 by moving the matching migration-history row to version 39 before
SQLx validation. The current version-38 migration can then apply
normally.

## Validation

- `just test -p codex-state
migrations::tests::repairs_recency_migration_that_was_applied_as_version_38`
- `just test -p codex-state -p codex-rollout -p codex-thread-store -p
codex-app-server-protocol -p codex-tui`: 3,439 passed; six TUI tests
could not open the machine's existing read-only incident database at
`~/.codex/sqlite/state_5.sqlite`.
- `just fix -p codex-state`
- `just fmt`
- Verified that state migration versions are unique.
2026-06-17 18:52:18 +00:00
pakrym-oai cb15c64760 Revert thread recencyAt for sidebar ordering (#28655)
## Why

Revert #27910 to remove the newly introduced thread `recencyAt`
persistence and API behavior from `main`.

## What changed

This reverts commit `fac3158c2a783095768076489815f361fa9b0db4`,
including the state migration, thread-store propagation, app-server API
surface, generated schemas, and related tests.

## Validation

Not run before opening; relying on CI for the initial fast signal.
2026-06-16 21:39:30 -07:00
Jeremy Rose fac3158c2a Add thread recencyAt for sidebar ordering (#27910)
## Summary

Add a server-owned `recencyAt` timestamp and `recency_at` thread-list
sort key for product recency ordering while preserving the existing
meaning of `updatedAt` as the latest persisted thread mutation.

This is the server-side alternative to #27697. Rather than narrowing
`updatedAt`, clients can sort the sidebar by `recency_at` and continue
treating `updatedAt` as mutation time.

Paired Codex Apps PR:
[openai/openai#1024599](https://github.com/openai/openai/pull/1024599)

## Contract

- `recencyAt` initializes when a thread is created.
- A turn start advances `recencyAt` monotonically.
- Commentary, agent output, tool results, token/accounting updates, turn
completion, archive, unarchive, resume, and generic metadata writes do
not advance it.
- `updatedAt` retains its existing behavior and continues to advance for
persisted thread mutations.
- Current servers populate `recencyAt`; the response field is optional
in generated TypeScript so clients connected to older servers can fall
back to `updatedAt`.
- Filesystem-only fallback uses existing updated/mtime ordering when
SQLite is unavailable.

## Persistence and compatibility

Migration 0038 adds second- and millisecond-precision recency columns,
backfills them from the existing updated timestamp, creates list
indexes, and includes an insert trigger so older binaries writing to a
migrated database seed recency without causing later mutations to
advance it.

Generic metadata upserts preserve existing recency values. Turn-start
updates use a dedicated monotonic touch, and process-local allocation
keeps millisecond cursor values unique. State DB list, search, read,
filtered-list repair, rollout fallback propagation, and app-server
conversions all carry the new field.

## API

`Thread` responses include:

```ts
recencyAt?: number
```

`thread/list` and `thread/search` accept:

```json
{ "sortKey": "recency_at" }
```

Generated TypeScript and JSON schemas are included.

## Validation

- `just test -p codex-state` — 146 passed
- `just test -p codex-rollout` — 69 passed
- `just test -p codex-thread-store` — 81 passed
- `just test -p codex-app-server-protocol` — 231 passed
- Focused app-server list ordering, response mapping, archive/unarchive,
and resume lifecycle tests passed
- Scoped `just fix` for state, rollout, thread-store,
app-server-protocol, and app-server
- `just fmt`
- `git diff --check`
- Independent correctness, simplicity, elegance, security, and
test-quality reviews; actionable ordering, lifecycle, query-projection,
and timestamp-uniqueness findings were addressed
2026-06-16 17:06:22 -07:00
jameswt-oai e512e884ed [codex-analytics] Analytics Capture to File in Debug Builds (#27093)
## This PR

The original [combined remote plugin analytics PR
#26281](https://github.com/openai/codex/pull/26281) mixed reusable
analytics test infrastructure, two manual smoke workflows, a metadata
refactor, and the final identity behavior. This PR isolates the generic
capture mechanism so it can be reviewed and landed before any
plugin-specific behavior.

- Add a debug-only analytics destination that writes final request
payloads as JSONL.
- Suppress HTTP delivery whenever capture mode is selected, including
after capture write failures.
- Keep release behavior unchanged even when the capture environment
variable is present.
- Keep the mechanism generic; this PR contains no plugin-specific
behavior.

Set `CODEX_ANALYTICS_EVENTS_CAPTURE_FILE=/path/events.jsonl` when
running a debug Codex binary to inspect the exact batched payload that
would otherwise be sent to the analytics endpoint.

## Testing

- `just test -p codex-analytics` (76 passed)
- `just test --release -p codex-analytics` (73 passed)
- CI is green across the required platform matrix.

## Split Overview

```text
main
├── #27093  Debug analytics capture                 ← you are here
│   └── #27099  Non-mutating plugin smoke
│       └── #27100  Remote install/uninstall smoke
└── #27102  Plugin telemetry metadata refactor

After #27093, #27099, #27100, and #27102 merge:
└── Final PR: add remote_plugin_id to plugin analytics
```

Review order and dependencies:

1. [#27093 Add debug-only analytics event
capture](https://github.com/openai/codex/pull/27093) **(this PR, based
on `main`)**
2. [#27099 Add a plugin analytics smoke
workflow](https://github.com/openai/codex/pull/27099) (stacked on
#27093)
3. [#27100 Add a remote plugin analytics mutation smoke
workflow](https://github.com/openai/codex/pull/27100) (stacked on
#27099)
4. [#27102 Centralize plugin telemetry metadata
construction](https://github.com/openai/codex/pull/27102) (independent,
based on `main`)
5. Final remote-ID behavior PR (created after PRs 1-4 merge)

The original [#26281](https://github.com/openai/codex/pull/26281)
remains open as the green aggregate reference until the final PR is
published.
2026-06-15 16:32:38 -07:00
Owen Lin cf0911076f store and expose parent_thread_id on Threads (#25113)
## Why

This PR
https://github.com/openai/codex/pull/24161#discussion_r3325692763
revealed a subagent data modeling issue, where we overloaded
`forked_from_id` to also mean `parent_thread_id`. That's incorrect since
guardian and review subagents can be a subagent and NOT fork the main
thread's history.

The solution here is to explicitly store a new `parent_thread_id` on
`SessionMeta`, alongside `forked_from_id` which already exists. While
we're at it, also expose it in the app-server protocol on the `Thread`
object.

A thread->subagent relationship and a fork of thread history are
orthogonal concepts.

## What Changed

- Added top-level `parent_thread_id` persistence on `SessionMeta` and
runtime/session plumbing through `SessionConfiguredEvent`,
`CodexSpawnArgs`, `SessionConfiguration`, `ThreadConfigSnapshot`,
`TurnContext`, and `ModelClient`.
- Made turn metadata, request headers, analytics, and subagent-start
events read the separate runtime/top-level parent field instead of
deriving general parent lineage from `SessionSource` or
`forked_from_thread_id`.
- Passed parent lineage separately at delegated subagent, review,
guardian, agent-job, and multi-agent spawn construction sites;
copied-history fork lineage remains derived only from `InitialHistory`.
- Persisted and exposed parent lineage through rollout/thread-store
projections and app-server v2 `Thread.parentThreadId`.
- Updated app-server README text and regenerated app-server schema
fixtures for the additive `parentThreadId` response field.
2026-06-01 04:33:20 +00:00
Alexi Christakis e92c952b2e [codex] Add user input client ids (#24653)
## Summary

Adds an optional `clientId` field to app-server v2 `UserInput` and
carries it through the core `UserInput` model so clients can correlate
echoed user input items without relying on payload equality.

## Details

- Adds `client_id: Option<String>` to core `UserInput` variants.
- Exposes the v2 app-server field as `clientId` on the wire and in
generated TypeScript.
- Preserves the id when converting between app-server v2 and core
protocol types.
- Regenerates app-server schema fixtures.

## Validation

- `just fmt`
- `just write-app-server-schema`
- `cargo test -p codex-app-server-protocol`
- `cargo test -p codex-protocol`
- `just fix -p codex-app-server-protocol`
- `just fix -p codex-protocol`
- `git diff --check`
2026-05-28 14:54:39 -07:00
Brent Traut 2a1158b8e2 feat(app-server): include turns page on thread resume (#23534)
## Summary

The client currently calls `thread/resume` to establish live updates and
immediately follows it with `thread/turns/list` to hydrate recent turns.
This lets `thread/resume` return that page directly, eliminating a round
trip and the ordering/deduplication gap between the two calls.

Experimental clients opt in with `initialTurnsPage: { limit,
sortDirection, itemsView }`. The response returns `initialTurnsPage` as
a `TurnsPage`, including cursors for paging further back in history.
Keeping the controls in a nested opt-in object provides the useful
`thread/turns/list` knobs without spreading page-specific parameters
across `thread/resume`.

## Verification

- `just fmt`
- `just write-app-server-schema --experimental`
- `just write-app-server-schema`
- `cargo test -p codex-app-server-protocol`
- `cargo test -p codex-app-server
thread_resume_initial_turns_page_matches_requested_turns_list_page
--tests`
- `cargo test -p codex-app-server
thread_resume_rejoins_running_thread_even_with_override_mismatch
--tests`
- `just fix -p codex-app-server-protocol -p codex-app-server`
2026-05-28 09:18:13 -07:00