Commit Graph

1914 Commits

  • fix(arc_monitor): api path (#14290)
    This PR just fixes the API path for ARC monitor.
  • Add snippets annotated with types to tools when code mode enabled (#14284)
    Main purpose is for code mode to understand the return type.
  • Split spawn_csv from multi_agent (#14282)
    - make `spawn_csv` a standalone feature for CSV agent jobs
    - keep `spawn_csv -> multi_agent` one-way and preserve restricted
    subagent disable paths
  • Add realtime start instructions config override (#14270)
    - add `realtime_start_instructions` config support
    - thread it into realtime context updates, schema, docs, and tests
  • Make unified exec session_id numeric (#14279)
    It's a number on the write_stdin input, make it a number on the output
    and also internally.
  • Show spawned agent model and effort in TUI (#14273)
    - include the requested sub-agent model and reasoning effort in the
    spawn begin event\n- render that metadata next to the spawned agent name
    and role in the TUI transcript
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Rename code mode tool to exec (#14254)
    Summary
    - update the code-mode handler, runner, instructions, and error text to
    refer to the `exec` tool name everywhere that used to say `code_mode`
    - ensure generated documentation strings and tool specs describe `exec`
    and rely on the shared `PUBLIC_TOOL_NAME`
    - refresh the suite tests so they invoke `exec` instead of the old name
    
    Testing
    - Not run (not requested)
  • prompt changes to guardian (#14263)
    ## Summary
      - update the guardian prompting
    - clarify the guardian rejection message so an action may still proceed
    if the user explicitly approves it after being informed of the risk
    
      ## Testing
      - cargo run on selected examples
  • chore: add a separate reject-policy flag for skill approvals (#14271)
    ## Summary
    - add `skill_approval` to `RejectConfig` and the app-server v2
    `AskForApproval::Reject` payload so skill-script prompts can be
    configured independently from sandbox and rule-based prompts
    - update Unix shell escalation to reject prompts based on the actual
    decision source, keeping prefix rules tied to `rules`, unmatched command
    fallbacks tied to `sandbox_approval`, and skill scripts tied to
    `skill_approval`
    - regenerate the affected protocol/config schemas and expand
    unit/integration coverage for the new flag and skill approval behavior
  • Add store/load support for code mode (#14259)
    adds support for transferring state across code mode invocations.
  • Pass more params to compaction (#14247)
    Pass more params to /compact. This should give us parity with the
    /responses endpoint to improve caching.
    
    I'm torn about the MCP await. Blocking will give us parity but it seems
    like we explicitly don't block on MCPs. Happy either way
  • feat: Add additional macOS Sandbox Permissions for Launch Services, Contacts, Reminders (#14155)
    Add additional macOS Sandbox Permissions levers for the following:
    
    - Launch Services
    - Contacts
    - Reminders
  • Add code_mode output helpers for text and images (#14244)
    Summary
    - document how code-mode can import `output_text`/`output_image` and
    ensure `add_content` stays compatible
    - add a synthetic `@openai/code_mode` module that appends content items
    and validates inputs
    - cover the new behavior with integration tests for structured text and
    image outputs
    
    Testing
    - Not run (not requested)
  • Clarify close_agent tool description (#14269)
    - clarify the `close_agent` tool description so it nudges models to
    close agents they no longer need
    - keep the change scoped to the tool spec text only
    
    Co-authored-by: Codex <noreply@openai.com>
  • Add model-controlled truncation for code mode results (#14258)
    Summary
    - document that `@openai/code_mode` exposes
    `set_max_output_tokens_per_exec_call` and that `code_mode` truncates the
    final Rust-side output when the budget is exceeded
    - enforce the configured budget in the Rust tool runner, reusing
    truncation helpers so text-only outputs follow the unified-exec wrapper
    and mixed outputs still fit within the limit
    - ensure the new behavior is covered by a code-mode integration test and
    string spec update
    
    Testing
    - Not run (not requested)
  • Add output schema to MCP tools and expose MCP tool results in code mode (#14236)
    Summary
    - drop `McpToolOutput` in favor of `CallToolResult`, moving its helpers
    to keep MCP tooling focused on the final result shape
    - wire the new schema definitions through code mode, context, handlers,
    and spec modules so MCP tools serialize the exact output shape expected
    by the model
    - extend code mode tests to cover multiple MCP call scenarios and ensure
    the serialized data matches the new schema
    - refresh JS runner helpers and protocol models alongside the schema
    changes
    
    Testing
    - Not run (not requested)
  • unifying all image saves to /tmp to bug-proof (#14149)
    image-gen feature will have the model saving to /tmp by default + at all
    times
  • Add spawn_agent model overrides (#14160)
    - add `model` and `reasoning_effort` to the `spawn_agent` schema so the
    values pass through
    - validate requested models against `model.model` and only check that
    the selected model supports the requested reasoning effort
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • feat: Allow sync with remote plugin status. (#14176)
    Add forceRemoteSync to plugin/list.
    When it is set to True, we will sync the local plugin status with the
    remote one (backend-api/plugins/list).
  • add(core): arc_monitor (#13936)
    ## Summary
    - add ARC monitor support for MCP tool calls by serializing MCP approval
    requests into the ARC action shape and sending the relevant
    conversation/policy context to the `/api/codex/safety/arc` endpoint
    - route ARC outcomes back into MCP approval flow so `ask-user` falls
    back to a user prompt and `steer-model` blocks the tool call, with
    guardian/ARC tests covering the new request shape
    - update the TUI approval copy from “Approve Once” to “Allow” / “Allow
    for this session” and refresh the related
      snapshots
    
    ---------
    
    Co-authored-by: Fouad Matin <fouad@openai.com>
    Co-authored-by: Fouad Matin <169186268+fouad-openai@users.noreply.github.com>
  • Reuse McpToolOutput in McpHandler (#14229)
    We already have a type to represent the MCP tool output, reuse it
    instead of the custom McpHandlerOutput
  • Expose strongly-typed result for exec_command (#14183)
    Summary
    - document output types for the various tool handlers and registry so
    the API exposes richer descriptions
    - update unified execution helpers and client tests to align with the
    new output metadata
    - clean up unused helpers across tool dispatch paths
    
    Testing
    - Not run (not requested)
  • Log ChatGPT user ID for feedback tags (#13901)
    There are some bug investigations that currently require us to ask users
    for their user ID even though they've already uploaded logs and session
    details via `/feedback`. This frustrates users and increases the time
    for diagnosis.
    
    This PR includes the ChatGPT user ID in the metadata uploaded for
    `/feedback` (both the TUI and app-server).
  • Fix Linux tmux segfault in user shell lookup (#13900)
    Replace the Unix shell lookup path in `codex-rs/core/src/shell.rs` to
    use
    `libc::getpwuid_r()` instead of `libc::getpwuid()` when resolving the
    current
    user's shell.
    
    Why:
    - `getpwuid()` can return pointers into libc-managed shared storage
    - on the musl static Linux build, concurrent callers can race on that
    storage
    - this matches the crash pattern reported in tmux/Linux sessions with
    parallel
      shell activity
    
    Refs:
    - Fixes #13842
  • Fix unified exec test output assertion (#14184)
    ## Summary
    - update the unified exec test to use truncated_output() instead of the
    removed output field
    - fix the compile failure on latest main after ExecCommandToolOutput
    changed shape
  • Use realtime transcript for handoff context (#14132)
    - collect input/output transcript deltas into active handoff transcript
    state
    - attach and clear that transcript on each handoff, and regenerate
    schema/tests
  • Implemented thread-level atomic elicitation counter for stopwatch pausing (#12296)
    ### Purpose
    While trying to build out CLI-Tools for the agent to use under skills we
    have found that those tools sometimes need to invoke a user elicitation.
    These elicitations are handled out of band of the codex app-server but
    need to indicate to the exec manager that the command running is not
    going to progress on the usual timeout horizon.
    
    ### Example
    Model calls universal exec:
    `$ download-credit-card-history --start-date 2026-01-19 --end-date
    2026-02-19 > credit_history.jsonl`
    
    download-cred-card-history might hit a hosted/preauthenticated service
    to fetch data. That service might decide that the request requires an
    end user approval the access to the personal data. It should be able to
    signal to the running thread that the command in question is blocked on
    user elicitation. In that case we want the exec to continue, but the
    timeout to not expire on the tool call, essentially freezing time until
    the user approves or rejects the command at which point the tool would
    signal the app-server to decrement the outstanding elicitation count.
    Now timeouts would proceed as normal.
    
    ### What's Added
    
    - New v2 RPC methods:
        - thread/increment_elicitation
        - thread/decrement_elicitation
    - Protocol updates in:
        - codex-rs/app-server-protocol/src/protocol/common.rs
        - codex-rs/app-server-protocol/src/protocol/v2.rs
    - App-server handlers wired in:
        - codex-rs/app-server/src/codex_message_processor.rs
    
    ### Behavior
    
    - Counter starts at 0 per thread.
    - increment atomically increases the counter.
    - decrement atomically decreases the counter; decrement at 0 returns
    invalid request.
    - Transition rules:
    - 0 -> 1: broadcast pause state, pausing all active stopwatches
    immediately.
        - \>0 -> >0: remain paused.
        - 1 -> 0: broadcast unpause state, resuming stopwatches.
    - Core thread/session logic:
        - codex-rs/core/src/codex_thread.rs
        - codex-rs/core/src/codex.rs
        - codex-rs/core/src/mcp_connection_manager.rs
    
    ### Exec-server stopwatch integration
    
    - Added centralized stopwatch tracking/controller:
        - codex-rs/exec-server/src/posix/stopwatch_controller.rs
    - Hooked pause/unpause broadcast handling + stopwatch registration:
        - codex-rs/exec-server/src/posix/mcp.rs
        - codex-rs/exec-server/src/posix/stopwatch.rs
        - codex-rs/exec-server/src/posix.rs
  • [apps] Fix apps enablement condition. (#14011)
    - [x] Fix apps enablement condition to check both the feature flag and
    that the user is not an API key user.
  • Move exec command truncation into ExecCommandToolOutput (#14169)
    Summary
    - relocate truncation logic for exec command output into the new
    `ExecCommandToolOutput` response helper instead of centralized handler
    code
    - update all affected tools and unified exec handling to use the new
    response item structure and eliminate `Function(FunctionToolOutput)`
    responses
    - adjust context, registry, and handler interfaces to align with the new
    response semantics and error fields
    
    Testing
    - Not run (not requested)
  • feat: support disabling bundled system skills (#13792)
    Support disable bundled system skills with a config:
    
    [skills.bundled]
    enabled = false
  • Export tools module into code mode runner (#14167)
    **Summary**
    - allow `code_mode` to pass enabled tools metadata to the runner and
    expose them via `tools.js`
    - import tools inside JavaScript rather than relying only on globals or
    proxies for nested tool calls
    - update specs, docs, and tests to exercise the new bridge and explain
    the tooling changes
    
    **Testing**
    - Not run (not requested)
  • Enforce single tool output type in codex handlers (#14157)
    We'll need to associate output schema with each tool. Each tool can only
    have on output type.
  • start of hooks engine (#13276)
    (Experimental)
    
    This PR adds a first MVP for hooks, with SessionStart and Stop
    
    The core design is:
    
    - hooks live in a dedicated engine under codex-rs/hooks
    - each hook type has its own event-specific file
    - hook execution is synchronous and blocks normal turn progression while
    running
    - matching hooks run in parallel, then their results are aggregated into
    a normalized HookRunSummary
    
    On the AppServer side, hooks are exposed as operational metadata rather
    than transcript-native items:
    
    - new live notifications: hook/started, hook/completed
    - persisted/replayed hook results live on Turn.hookRuns
    - we intentionally did not add hook-specific ThreadItem variants
    
    Hooks messages are not persisted, they remain ephemeral. The context
    changes they add are (they get appended to the user's prompt)
  • Add code_mode experimental feature (#13418)
    A much narrower and more isolated (no node features) version of js_repl
  • Refactor tool output into trait implementations (#14152)
    First state to making tool outputs strongly typed (and `renderable`).
  • fix: keep permissions profiles forward compatible (#14107)
    ## Summary
    - preserve unknown `:special_path` tokens, including nested entries, so
    older Codex builds warn and ignore instead of failing config load
    - fail closed with a startup warning when a permissions profile has
    missing or empty filesystem entries instead of aborting profile
    compilation
    - normalize Windows verbatim paths like `\?\C:\...` before absolute-path
    validation while keeping explicit errors for truly invalid paths
    
    ## Testing
    - just fmt
    - cargo test -p codex-core permissions_profiles_allow
    - cargo test -p codex-core
    normalize_absolute_path_for_platform_simplifies_windows_verbatim_paths
    - cargo test -p codex-protocol
    unknown_special_paths_are_ignored_by_legacy_bridge
    - cargo clippy -p codex-core -p codex-protocol --all-targets -- -D
    warnings
    - cargo clean
  • fix(protocol): preserve legacy workspace-write semantics (#13957)
    ## Summary
    This is a fast follow to the initial `[permissions]` structure.
    
    - keep the new split-policy carveout behavior for narrower non-write
    entries under broader writable roots
    - preserve legacy `WorkspaceWrite` semantics by using a cwd-aware bridge
    that drops only redundant nested readable roots when projecting from
    `SandboxPolicy`
    - route the legacy macOS seatbelt adapter through that same legacy
    bridge so redundant nested readable roots do not become read-only
    carveouts on macOS
    - derive the legacy bridge for `command_exec` using the sandbox root cwd
    rather than the request cwd so policy derivation matches later sandbox
    enforcement
    - add regression coverage for the legacy macOS nested-readable-root case
    
    ## Examples
    ### Legacy `workspace-write` on macOS
    A legacy `workspace-write` policy can redundantly list a nested readable
    root under an already-writable workspace root.
    
    For example, legacy config can effectively mean:
    - workspace root (`.` / `cwd`) is writable
    - `docs/` is also listed in `readable_roots`
    
    The new shared split-policy helper intentionally treats a narrower
    non-write entry under a broader writable root as a carveout for real
    `[permissions]` configs. Without this fast follow, the unchanged macOS
    seatbelt legacy adapter could project that legacy shape into a
    `FileSystemSandboxPolicy` that treated `docs/` like a read-only carveout
    under the writable workspace root. In practice, legacy callers on macOS
    could unexpectedly lose write access inside `docs/`, even though that
    path was writable before the `[permissions]` migration work.
    
    This change fixes that by routing the legacy seatbelt path through the
    cwd-aware legacy bridge, so:
    - legacy `workspace-write` keeps `docs/` writable when `docs/` was only
    a redundant readable root
    - explicit `[permissions]` entries like `'.' = 'write'` and `'docs' =
    'read'` still make `docs/` read-only, which is the new intended
    split-policy behavior
    
    ### Legacy `command_exec` with a subdirectory cwd
    `command_exec` can run a command from a request cwd that is narrower
    than the sandbox root cwd.
    
    For example:
    - sandbox root cwd is `/repo`
    - request cwd is `/repo/subdir`
    - legacy policy is still `workspace-write` rooted at `/repo`
    
    Before this fast follow, `command_exec` derived the legacy bridge using
    the request cwd, but the sandbox was later built using the sandbox root
    cwd. That mismatch could miss redundant legacy readable roots during
    projection and accidentally reintroduce read-only carveouts for paths
    that should still be writable under the legacy model.
    
    This change fixes that by deriving the legacy bridge with the same
    sandbox root cwd that sandbox enforcement later uses.
    
    ## Verification
    - `just fmt`
    - `cargo test -p codex-core
    seatbelt_legacy_workspace_write_nested_readable_root_stays_writable`
    - `cargo test -p codex-core test_sandbox_config_parsing`
    - `cargo clippy -p codex-core -p codex-app-server --all-targets -- -D
    warnings`
    - `cargo clean`
  • feat(approvals) RejectConfig for request_permissions (#14118)
    ## Summary
    We need to support allowing request_permissions calls when using
    `Reject` policy
    
    <img width="1133" height="588" alt="Screenshot 2026-03-09 at 12 06
    40 PM"
    src="https://github.com/user-attachments/assets/a8df987f-c225-4866-b8ab-5590960daec5"
    />
    
    Note that this is a backwards-incompatible change for Reject policy. I'm
    not sure if we need to add a default based on our current use/setup
    
    ## Testing
    - [x] Added tests
    - [x] Tested locally
  • fix(core) RequestPermissions + ApplyPatch (#14055)
    ## Summary
    The apply_patch tool should also respect AdditionalPermissions
    
    ## Testing
    - [x] Added unit tests
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • fix(core): use dedicated types for responsesapi web search tool config (#14136)
    This changes the web_search tool spec in codex-core to use dedicated
    Responses-API payload structs instead of shared config types and custom
    serializers.
    
    Previously, `ToolSpec::WebSearch` stored `WebSearchFilters` and
    `WebSearchUserLocation` directly and relied on hand-written serializers
    to shape the outgoing JSON. This worked, but it mixed config/schema
    types with the OpenAI Responses payload contract and created an easy
    place for drift if those shared types changed later.
    
    ### Why
    This keeps the boundary clearer:
    - app-server/config/schema types stay focused on config
    - Responses tool payload types stay focused on the OpenAI wire format
    
    It also makes the serialization behavior obvious from the structs
    themselves, instead of hiding it in custom serializer functions.
  • feat(core) Persist request_permission data across turns (#14009)
    ## Summary
    request_permissions flows should support persisting results for the
    session.
    
    Open Question: Still deciding if we need within-turn approvals - this
    adds complexity but I could see it being useful
    
    ## Testing
    - [x] Updated unit tests
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • pass on save info to model + ui tweaks (#14123)
    Passing on more information to the model for context purposes, to
    streamline image-identification.
  • feat(otel): Centralize OTEL metric names and shared tag builders (#14117)
    This cleans up a bunch of metric plumbing that had started to drift.
    
    The main change is making `codex-otel` the canonical home for shared
    metric definitions and metric tag helpers. I moved the `turn/thread`
    metric names that were still duplicated into the OTEL metric registry,
    added a shared `metrics::tags` module for common tag keys and session
    tag construction, and updated `SessionTelemetry` to build its metadata
    tags through that shared path.
    
    On the codex-core side, TTFT/TTFM now use the shared metric-name
    constants instead of local string definitions. I also switched the
    obvious remaining turn/thread metric callsites over to the shared
    constants, and added a small helper so TTFT/TTFM can attach an optional
    sanitized client.name tag from TurnContext.
    
    This should make follow-on telemetry work less ad hoc:
    - one canonical place for metric names
    - one canonical place for common metric tag keys/builders
    - less duplication between `codex-core` and `codex-otel`
  • chore: plugin/uninstall endpoint (#14111)
    add `plugin/uninstall` app-server endpoint to fully rm plugin from
    plugins cache dir and rm entry from user config file.
    
    plugin-enablement is session-scoped, so uninstalls are only picked up in
    new sessions (like installs).
    
    added tests.
  • Stabilize guardian approval coverage (#14103)
    ## Summary
    - align the guardian permission test with the actual sandbox policy it
    widens and use a slightly larger Windows-only timeout budget
    - expose the additional-permissions normalization helper to the guardian
    test module
    - replace the guardian popup snapshot assertion with targeted string
    assertions
    
    ## Why this fixes the flake
    This group was carrying two separate sources of drift. The guardian core
    test widened derived sandbox policies without updating the source
    sandbox policy, and it used a Windows command/timeout combination that
    was too tight on slower runners. Separately, the TUI test was
    snapshotting the full popup even though unrelated feature text changes
    were the only thing moving. The new assertions keep coverage on the
    guardian entry itself while removing unrelated snapshot churn.
  • Stabilize interrupted task approval cleanup (#14102)
    ## Summary
    - drain the active turn tasks before clearing pending approvals during
    interruption
    - keep the turn in hand long enough for interrupted tasks to observe
    cancellation first
    
    ## Why this fixes the flake
    Interrupted turns could clear pending approvals too early, which let an
    in-flight approval wait surface as a model-visible rejection before the
    turn emitted `TurnAborted`. Reordering the cleanup removes that race
    without changing the steady-state task model.
  • Serialize shell snapshot stdin test (#13878)
    ## What changed
    - `snapshot_shell_does_not_inherit_stdin` now runs under its own serial
    key.
    - The change isolates it from other Unix shell-snapshot tests that also
    interact with stdin.
    
    ## Why this fixes the flake
    - The failure was not a shell-snapshot logic bug. It was shared-stdin
    interference between concurrently executing tests.
    - When multiple tests compete for inherited stdin at the same time, one
    test can observe EOF or consumed input that actually belongs to a
    different test.
    - Running this specific test in a dedicated serial bucket guarantees
    exclusive ownership of stdin, which makes the assertion deterministic
    without weakening coverage.
    
    ## Scope
    - Test-only change.
  • guardian initial feedback / tweaks (#13897)
    ## Summary
    - remove the remaining model-visible guardian-specific `on-request`
    prompt additions so enabling the feature does not change the main
    approval-policy instructions
    - neutralize user-facing guardian wording to talk about automatic
    approval review / approval requests rather than a second reviewer or
    only sandbox escalations
    - tighten guardian retry-context handling so agent-authored
    `justification` stays in the structured action JSON and is not also
    injected as raw retry context
    - simplify guardian review plumbing in core by deleting dead
    prompt-append paths and trimming some request/transcript setup code
    
    ## Notable Changes
    - delete the dead `permissions/approval_policy/guardian.md` append path
    and stop threading `guardian_approval_enabled` through model-facing
    developer-instruction builders
    - rename the experimental feature copy to `Automatic approval review`
    and update the `/experimental` snapshot text accordingly
    - make approval-review status strings generic across shell, patch,
    network, and MCP review types
    - forward real sandbox/network retry reasons for shell and unified-exec
    guardian review, but do not pass agent-authored justification as raw
    retry context
    - simplify `guardian.rs` by removing the one-field request wrapper,
    deduping reasoning-effort selection, and cleaning up transcript entry
    collection
    
    ## Testing
    - `just fmt`
    - full validation left to CI
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>