Commit Graph

18 Commits

  • chore(config) rm Feature::CodexGitCommit (#22412)
    ## Summary
    Removes the unused Feature::CodexGitCommit
    
    ## Testing
    - [x] tests pass
  • refactor: split memories extension crate modules (#22500)
    ## Why
    
    The memories extension has several distinct responsibilities:
    registering its prompt and tool contributors, enforcing local-memory
    filesystem boundaries, implementing list/read/search behavior, and
    wrapping that backend as extension tools. Those responsibilities were
    concentrated in `lib.rs`, `local.rs`, and the tool modules, which made
    follow-up work harder to review and risked growing files through
    unrelated edits.
    
    This PR reorganizes the crate so each responsibility has a narrower
    owner while preserving the same extension entrypoint and memory tool
    behavior.
    
    ## What Changed
    
    - Moved extension lifecycle, prompt, and tool registration into
    `src/extension.rs`, leaving `src/lib.rs` as the small crate entrypoint.
    - Split `LocalMemoriesBackend` helpers into `local/list.rs`,
    `local/path.rs`, `local/read.rs`, and `local/search.rs`.
    - Centralized tool names and limits at the crate level, and kept the
    backend and extension implementation crate-private.
    - Made `memory_list`, `memory_read`, and `memory_search` tool executors
    generic over `MemoriesBackend`, so tests can exercise the full executor
    path without depending on tool internals.
    - Consolidated and expanded memory extension tests in `src/tests.rs`,
    including read/search tool output coverage, multi-query search, windowed
    `all_within_lines`, and legacy `query` rejection.
    
    ## Testing
    
    - Not run locally.
  • fix: main (#22503)
    Fix main due to conflicting merge
  • feat: memories ext (#22498)
    First memories extension implementation
    Based on memories-mcp tools
  • feat: add config-change extension contributor (#22488)
    ## Why
    
    Extensions can observe thread and turn lifecycle events today, but there
    was no single host-owned hook for changes to the effective thread
    configuration. That makes features that need to react to model,
    permission, or tool-suggest updates either depend on individual mutation
    paths or risk going stale after runtime config refreshes.
    
    This adds a typed config-change contributor so extension-owned state can
    stay synchronized with the effective thread config while the host
    remains responsible for deciding when config changed.
    
    ## What Changed
    
    - Added `ConfigContributor<C>` to `codex_extension_api`, with
    before/after immutable snapshots of the effective config plus
    session/thread extension stores.
    - Added registry builder/accessor support through `config_contributor`
    and `config_contributors`.
    - Emits config-change callbacks after committed updates from session
    settings, per-turn setting updates, and `refresh_runtime_config`.
    - Builds effective config snapshots only when config contributors are
    registered, and suppresses no-op callbacks when the before/after
    snapshots are equal.
    - Added a core session regression test that verifies contributors
    observe both model changes and user-layer runtime config changes,
    including access to session and thread extension stores.
    
    ## Validation
    
    Added `config_change_contributor_observes_effective_config_changes` in
    `codex-rs/core/src/session/tests.rs` to cover the new contributor path.
  • Make context contributors async (#22491)
    ## Summary
    - make ContextContributor return a boxed Send future
    - await context contributors during initial context assembly
    - update existing contributors and extension-api examples for the async
    contract
    
    ## Testing
    - cargo test -p codex-extension-api --examples
    - cargo test -p codex-git-attribution
    - cargo test -p codex-core
    build_initial_context_includes_git_attribution_from_extensions --
    --nocapture
    - cargo test -p codex-core
    build_initial_context_omits_git_attribution_when_feature_is_disabled --
    --nocapture
    - cargo test -p codex-core (fails in unrelated
    agent::control::tests::spawn_agent_fork_last_n_turns_keeps_only_recent_turns
    stack overflow)
    - just fix -p codex-extension-api
    - just fix -p codex-git-attribution
    - just fix -p codex-core
    - cargo clippy -p codex-extension-api --examples
  • feat: move extension scope ids into ExtensionData (#22490)
    ## Summary
    - add a scoped level_id to ExtensionData and expose it through
    level_id()
    - remove thread_id/turn_id parameters from extension contributor inputs
    where the scoped ExtensionData already carries that identity
    - move turn-scoped extension data onto TurnContext so token usage and
    lifecycle contributors can share the same turn store
    
    ## Testing
    - cargo check -p codex-extension-api -p codex-core --tests
    - cargo test -p codex-extension-api
    - cargo test -p codex-guardian
    - cargo test -p codex-core --lib
    record_token_usage_info_notifies_extension_contributors
    - cargo test -p codex-core --lib
    submission_loop_channel_close_emits_thread_stop_lifecycle
    - cargo test -p codex-core --lib
    submission_loop_channel_close_aborts_active_turn_before_thread_stop_lifecycle
    - just fix -p codex-extension-api
    - just fix -p codex-guardian
    - just fix -p codex-core
    - just fmt
    
    ## Note
    - Attempted cargo test -p codex-core; it aborted in
    agent::control::tests::spawn_agent_fork_last_n_turns_keeps_only_recent_turns
    with the existing stack overflow before the full suite completed.
  • feat: add token usage contributor hook (#22485)
    ## Why
    
    Extensions need a stable place to observe token accounting after Codex
    folds model-provider usage into the session's cached `TokenUsageInfo`.
    Without a contributor hook, extension-owned features that need last-turn
    or cumulative token usage have to duplicate session plumbing or infer
    state from client-facing `TokenCount` notifications.
    
    ## What changed
    
    - Added `TokenUsageContributor` to `codex-extension-api`, passing
    session/thread `ExtensionData`, `ThreadId`, turn id, and the current
    `TokenUsageInfo`.
    - Added registry builder/storage support for token-usage contributors.
    - Invoked registered contributors from
    `Session::record_token_usage_info` after the session token cache is
    updated and before the client `TokenCount` notification is emitted.
    
    ## Testing
    
    - Added `record_token_usage_info_notifies_extension_contributors`,
    covering cumulative token usage updates and access to both extension
    stores.
  • feat: add turn lifecycle contributors (#22480)
    ## Why
    
    Extensions can already contribute prompt, tool, turn-item, and
    thread-lifecycle behavior, but there was no explicit host-owned hook for
    per-turn setup and cleanup. That makes extension-private turn state
    awkward: an extension either has to stash it outside the turn lifecycle
    or depend on core runtime objects.
    
    This adds a small turn lifecycle boundary. Extensions receive stable
    identifiers plus the existing session, thread, and turn `ExtensionData`
    stores, while core keeps owning task scheduling, cancellation, and turn
    teardown.
    
    ## What Changed
    
    - Added `TurnLifecycleContributor` with `on_turn_start`, `on_turn_stop`,
    and `on_turn_abort` callbacks in `codex-rs/ext/extension-api`.
    - Added typed `TurnStartInput`, `TurnStopInput`, and `TurnAbortInput`
    payloads that expose `thread_id`, `turn_id`, `session_store`,
    `thread_store`, and `turn_store`.
    - Registered and re-exported turn lifecycle contributors through
    `ExtensionRegistry` and `ExtensionRegistryBuilder`.
    - Wired `Session` to emit turn start, stop, and abort callbacks from the
    existing turn/task lifecycle paths.
    - Carried the turn-scoped `ExtensionData` through `RunningTask` and
    `RemovedTask` so stop/abort callbacks receive the same turn store
    created at turn start.
    
    ## Verification
    
    - Not run locally.
  • feat: add thread lifecycle contributor hooks (#22476)
    ## Why
    
    Extensions that need thread-scoped state currently only get a start-time
    callback. That is enough for seeding stores, but it leaves the host
    without a shared extension seam for later thread rehydrate and flush
    work as thread ownership evolves. This PR turns that start-only seam
    into a host-owned thread lifecycle contributor contract so
    extension-private state can stay behind the extension API instead of
    leaking extra orchestration through core.
    
    ## What changed
    
    - Replaced `ThreadStartContributor` with `ThreadLifecycleContributor`
    and added typed lifecycle inputs for thread start, resume, and stop. The
    contract lives in
    [`contributors/thread_lifecycle.rs`](https://github.com/openai/codex/blob/d0e9211f70e58d6b07ef07e84f359d1b9aa25955/codex-rs/ext/extension-api/src/contributors/thread_lifecycle.rs#L1-L64).
    - Kept the existing start-time behavior intact by routing session
    construction through `on_thread_start`.
    - Invoked `on_thread_stop` during session shutdown before thread-scoped
    extension state is dropped, while isolating contributor failures behind
    warning logs.
    - Migrated `git-attribution` and `guardian` onto the lifecycle
    registration path.
    - Renamed the extension registry plumbing from start-specific
    contributors to lifecycle-specific contributors.
    
    ## Notes
    
    `on_thread_resume` is introduced at the API boundary here so extensions
    can target the final lifecycle shape; host resume dispatch can be wired
    where that runtime path is finalized.
  • Refactor extension tools onto shared ToolExecutor (#22369)
    ## Why
    
    Extension tools were split across two public runtime contracts:
    `codex-tool-api` exposed `ToolBundle` plus its own call/spec/error
    types, while core native tools used `codex_tools::ToolExecutor`. That
    made contributed tool specs and execution behavior easy to drift apart
    and added another crate boundary for what should be one executable-tool
    seam.
    
    This PR makes `ToolExecutor` the single runtime contract and keeps
    extension-specific pinning in `codex-extension-api`.
    
    ## Remaining todo
    
    https://github.com/openai/codex/pull/22369/changes#diff-b935ea8245c3ce568a30cff660175fa6390b66b872ae409e1e2e965738250741R5
    Either generic `Invocation` or sub-extract the `ToolCall` and clean
    `ToolInvocation`
    
    ## What changed
    
    - Removed the `codex-tool-api` workspace crate and its dependencies from
    core and `codex-extension-api`.
    - Made `codex_tools::ToolExecutor` object-safe with `async_trait` so
    extension contributors can return a dyn executor.
    - Added the extension-facing aliases under
    `ext/extension-api/src/contributors/tools.rs`, including
    `ExtensionToolExecutor = dyn ToolExecutor<ToolCall, Output =
    ExtensionToolOutput>`.
    - Changed `ToolContributor::tools` to return extension executors
    directly instead of `ToolBundle`s.
    - Updated core’s extension tool handler/registry/router path to adapt
    those extension executors into the existing native `ToolInvocation`
    runtime path.
    - Added focused coverage for extension tools being registered,
    model-visible, dispatchable, and not replacing built-in tools.
    
    ## Verification
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-extension-api`
  • extension-api: add approval review contributor flow (#22344)
    ## Why
    
    `codex-extension-api` needs an approval hook that lets an installed
    extension own a rendered approval-review prompt and produce the final
    `ReviewDecision`. The prior interceptor stub only exposed a yes/no claim
    and did not model the review result itself, which left the host with the
    missing half of the control flow.
    
    ## What changed
    
    - Replaces `ApprovalInterceptorContributor` with
    [`ApprovalReviewContributor`](https://github.com/openai/codex/blob/c49d17531e15057a373a9b17f410cafb6299d0c1/codex-rs/ext/extension-api/src/contributors.rs#L43-L55),
    which may claim a rendered prompt and return an async `ReviewDecision`.
    - Re-exports the new contributor and future types from `extension-api`.
    - Adds registry support through `approval_review_contributor(...)` plus
    [`ExtensionRegistry::approval_review(...)`](https://github.com/openai/codex/blob/c49d17531e15057a373a9b17f410cafb6299d0c1/codex-rs/ext/extension-api/src/registry.rs#L90-L101),
    which returns the first installed contributor that claims the prompt.
  • feat: guardian as an extension (contributors part) (#22216)
    Part 1 of guardian as extension. This bind all the logic to spawn
    another agent from an extension and it adds `ThreadId` in the start
    thread collaborator
  • feat: wire extension tool bundles into core (#22147)
    ## Why
    
    This is the next narrow step toward moving concrete tool families out of
    core. After #22138 introduced `codex-tool-api`, we still needed a real
    end-to-end seam that lets an extension own an executable tool definition
    once and have core install it without the temporary `extension-api`
    wrapper or a dependency on `codex-tools`.
    
    `codex-tool-api` is the small extension-facing execution contract, while
    `codex-tools` still has a different job: host-side shared tool metadata
    and planning logic that is not “run this contributed tool”, like spec
    shaping, namespaces, discovery, code-mode augmentation, and
    MCP/dynamic-to-Responses API conversion
    
    ## What changed
    
    - Moved the shared leaf tool-spec and JSON Schema types into
    `codex-tool-api`, so the executable contract now lives with
    [`ToolBundle`](https://github.com/openai/codex/blob/c538758095337d4fe0a52a172363ccede4066bda/codex-rs/tool-api/src/bundle.rs#L19-L70).
    - Replaced the temporary extension-side tool wrapper with direct
    `ToolBundle` use in `codex-extension-api`.
    - Taught core to collect contributed bundles, include them in spec
    planning, register them through
    [`ToolRegistryBuilder::register_tool_bundle`](https://github.com/openai/codex/blob/c538758095337d4fe0a52a172363ccede4066bda/codex-rs/core/src/tools/registry.rs#L653-L667),
    and dispatch them through the existing router/runtime path.
    - Added focused coverage for contributed tools becoming model-visible
    and dispatchable, plus spec-planning coverage for contributed function
    and freeform tools.
    
    ## Verification
    
    - Added `extension_tool_bundles_are_model_visible_and_dispatchable` in
    `core/src/tools/router_tests.rs`.
    - Added spec-plan coverage in `core/src/tools/spec_plan_tests.rs` for
    contributed extension bundles.
    
    ## Related
    
    - Follow-up to #22138
  • feat: drop CodexExtension (#22140)
    Drop `CodexExtension` as not needed for now
  • extension: move git attribution into an extension (#21738)
    ## Why
    
    Git commit attribution is prompt policy, not session orchestration.
    After #21737 adds the extension-registry seam, this moves that
    prompt-only behavior out of `codex-core` so `Session` can consume
    extension-contributed prompt fragments instead of owning a one-off
    policy path itself.
    
    Before this PR, `Session` injected the trailer instruction directly from
    `codex-core` ([session
    assembly](https://github.com/openai/codex/blob/a57a747eb667753118217b8bb47dfd1fff88cbde/codex-rs/core/src/session/mod.rs#L2733-L2739),
    [helper
    module](https://github.com/openai/codex/blob/a57a747eb667753118217b8bb47dfd1fff88cbde/codex-rs/core/src/commit_attribution.rs#L1-L33)).
    This branch moves that same responsibility into
    [`codex-git-attribution`](https://github.com/openai/codex/blob/b5029a67360fe5c948aa849d4cf65fd2597ebaae/codex-rs/ext/git-attribution/src/lib.rs#L14-L100).
    
    ## What changed
    
    - Added the `codex-git-attribution` extension crate.
    - Snapshot `CodexGitCommit` plus `commit_attribution` at thread start,
    then contribute the developer-policy fragment through the extension
    registry.
    - Register the extension in app-server thread extensions.
    - Remove the old `codex-core` helper module and direct `Session`
    injection path.
    
    This keeps the existing behavior intact: the prompt is only contributed
    when `CodexGitCommit` is enabled, blank attribution still disables the
    trailer, and the default remains `Codex <noreply@openai.com>`.
    
    ## Stack
    
    - Stacked on #21737.
  • extension: add initial typed extension API (#21736)
    ## Why
    
    `codex-core` still owns a growing amount of product-specific behavior.
    This PR starts the extraction path by introducing a small, typed
    first-party extension seam: features can install the contribution
    families they actually own, while the host keeps lifecycle and state
    ownership instead of pushing a broad service locator into the API.
    
    See the `examples/` for illustration
    
    ## Known limitations
    * Tool contract definition will be shared with core
    * Fragments must be extracted
    * Missing some contributors