Commit Graph
72 Commits
Author SHA1 Message Date
rhan-oai e103bbc06f Apply model catalog overrides to history, notes, and context tools (#56313)
## What changed

- Read optional tool descriptions and parameter schemas for `history`, `notes`, `new_context`, and `get_context_remaining` from the acting model's catalog messages.
- Support catalog namespace descriptions for history and notes, preserving explicit empty and whitespace descriptions.
- Share catalog override handling across native tools and MCP resource helpers. Keep bundled schemas when overrides are invalid, preserve encrypted parameters, and leave tool identity and transport fields unchanged.

## Testing

Add coverage for sparse catalog serialization, schema fallback and encryption preservation, per-step tool definitions, and context tool updates when switching models. Extend outgoing-request tests to verify history and notes overrides while retaining history image attachments.

GitOrigin-RevId: 1adac8b5009f95c91adba491f20a4e2e2dc91475
2026-10-23 00:46:28 +00:00
jif cd85a26cae Remove the patched zsh shell execution backend (#52160)
## What changed

- Use the standard shell executor and remove the zsh fork escalation runtime, `codex-execve-wrapper`, and `shell-escalation` crate.
- Ignore `shell_zsh_fork` and `unified_exec_zsh_fork`, emit migration notices for legacy configuration, and warn when ignoring managed requirements for these flags.
- Keep the active session's `apply_patch` alias directory readable under restricted filesystem permissions.

## Testing

Add coverage for legacy configuration startup and shell execution, migration notice rendering, active alias directory selection, and nested `apply_patch` execution while other files in `CODEX_HOME` remain unreadable.

GitOrigin-RevId: 43af461fea32b4980550ee7237effd2bc0646ed8
2026-10-08 16:19:09 +00:00
tongzhou wang e974aad3b1 Support model-specific function description prefixes (#51930)
## What changed

Add `functions_namespace_functions_description_prefixes` to model tool messages, keyed by unqualified tool name. Prepend this guidance to descriptions in the `functions` namespace across direct declarations, Code Mode documentation, and tool-search results, including custom tools.

Trim prefixes, ignore empty values and unavailable functions, and enforce a combined 256-byte UTF-8 limit including separators for reachable tools. Keep overrides local to each step, preserve search ranking text, and retain runtime caches for unaffected tools.

## Testing

Extend coverage for direct and indirect descriptions, clearing prefixes when switching models, namespace scoping for deferred dynamic tools, and tool-search cache reuse and reset.

GitOrigin-RevId: f434e37cec010764fe3e09fb12c339e933b3c21c
2026-10-08 03:20:54 +00:00
rhan-oai 8c66a5a243 Add model-specific prefixes to indirect tool descriptions (#47642)
## What changed

Add `model_messages.tools.indirect_description_prefixes` with selectors for exact namespaces and configured MCP server names. Apply the selected model's guidance to namespace documentation embedded in `CodeModeOnly` prompts, `ALL_TOOLS` descriptions, and namespaces returned by tool search.

Trim prefix values, treat empty values as no prefix, and reject conflicting selectors for the same namespace. Apply prefixes during rendering so model changes take effect without altering direct tool specifications, search ranking, or tool dispatch.

## Testing

Add unit tests for prefix normalization, namespace grouping, MCP server mapping, and conflicts. Add scenarios covering both Code Mode variants, clearing prefixes on model changes, unchanged tool dispatch, and conflict rejection before a model request.

GitOrigin-RevId: 0c7ce6d418c775945c2ccfdab3c605fa4d431b55
2026-09-23 19:54:07 +00:00
Charlie Marsh f3803587c9 Share tool output schemas and defer MCP envelope construction (#45439)
## Why

MCP tool parsing eagerly cloned structured output schemas and built full call-result envelopes. Cloning tool definitions also copied their output-schema JSON, even before a consumer needed it.

## What changed

- Introduce `ToolOutputSchema` with immutable `Arc` storage so tool definitions share output schemas when cloned.
- Retain MCP structured output schemas and materialize the call-result envelope only when JSON is requested.
- Update code-mode consumers and schema mutation sites to materialize JSON explicitly, reusing uniquely owned storage when possible.
- Move structured content into the MCP envelope without an extra clone, preserving property order.

## Testing

Add tests for JSON preservation, mutation isolation, equality between lazy and materialized schemas, reuse of uniquely owned storage, and equivalent code-mode definitions.

GitOrigin-RevId: e98ba4c2f0efedc99f7cbc7bba206cc63a3bd8f4
2026-09-14 15:05:16 +00:00
Tamir Duberstein e3609f2d02 Expose invocation sources to extension tools (#40382)
## What changed

- Add `ToolCallSource` to extension `ToolCall`s and propagate direct or Code Mode
  invocation metadata, including the runtime cell and nested tool-call IDs.
- Add `ToolCall::response_byte_budget` so extension tools can bound direct-call
  responses by the host truncation policy while allowing Code Mode responses up
  to the tool's own limit.
- Share the skills extension's response-size limit between its `list` and `read`
  tools.

## Testing

- Verify that Code Mode source metadata is preserved when core constructs an
  extension tool call.

GitOrigin-RevId: b10aef01be30d35b67bee3af24a1a4175c9ee112
2026-08-24 11:02:14 +00:00
jif bce5f2fcfc Standardize shell execution on unified exec (#39772)
## What changed

- Use `exec_command` and `write_stdin` as the shell tool surface.
- Treat legacy `default`, `local`, and `shell_command` model metadata as `unified_exec`.
- Remove obsolete shell-selection configuration and runtime paths while preserving the feature and policy gates for zsh fork execution.

GitOrigin-RevId: d743cbe598630d73052f1fecad680c4cde17977d
2026-08-20 18:29:35 +00:00
jif 8a40095ea3 Standardize shell execution on unified exec (#39757)
## What changed

- Remove the legacy `shell_command` handler and runtime, leaving `exec_command`
  and `write_stdin` as the shell execution tools.
- Treat legacy `shell_command` model metadata as `unified_exec`, and normalize
  legacy user opt-outs so they do not disable command execution. Managed feature
  requirements and `shell_tool` can still disable it.
- Preserve shell approvals, sandboxing, zsh-fork support, and output truncation
  through the unified execution path.

## Testing

- Cover legacy configuration and model-metadata compatibility.
- Exercise unified shell execution, approvals, truncation, and `apply_patch`
  serialization across the app-server and core test suites.

GitOrigin-RevId: 5c2fd6164fc3519cdae4944cb9db276b8467311c
2026-08-20 17:46:05 +00:00
jacobzhou-oai 56b82e676c Enforce Agent Plugin runtime boundaries (#37027)
## What changed

- Track Agent Plugin manifests through plugin, skill, and MCP loading so their capabilities use format-specific behavior without changing legacy plugins.
- Discover only direct-child skills, exclude app and hook capabilities, isolate MCP data, and reject MCP configuration files that are non-regular or resolve outside the plugin root.
- Bound model-visible skill instructions, plugin instructions, MCP descriptions, schemas, individual tools, and the aggregate Agent Plugin MCP tool set.
- Stop MCP and OAuth redirects when Agent Plugins send configured or authorization headers, while retaining existing redirect behavior for legacy MCP servers.

## Testing

- Add coverage for capability filtering, skill discovery, isolated MCP data and reserved-path expansion, unsafe MCP configuration files, context limits, and redirect handling.

GitOrigin-RevId: c9af66b051269f3226628ca280a58d32c808c38f
2026-08-05 04:54:33 +00:00
rka-oai f21dc46388 Canonicalize default tools under the functions namespace (#37022)
## What changed

- Group top-level function and custom tool definitions into a single `functions` namespace for Responses Lite providers that support namespaced tools.
- Normalize missing, empty, and explicit `functions` namespaces to the same tool identity across registration, routing, lifecycle hooks, configuration, and tool search.
- Keep default tool names unprefixed in code mode, display output, and dispatch traces while preserving explicit non-default namespaces.

## Testing

- Add coverage for Responses Lite serialization, tool search results, namespace normalization and collision handling, routing, lifecycle events, and code-mode namespace policies.

GitOrigin-RevId: d48414005b5d22d39b11a198e19c47814d3a19f2
2026-08-05 04:07:59 +00:00
tongzhou wang 51c9ed6d4f Add per-surface MCP tool exposure controls (#36781)
## Why

MCP tools can be exposed directly, discovered through tool search, or called
from Code Mode. Servers need to be able to opt out of any of these surfaces
without disabling their tools everywhere.

## What changed

- Add `omit_tools_from` to MCP server configuration, accepting any combination
  of `direct`, `deferred`, and `code_mode`.
- Apply the exclusions independently when building direct, deferred, and Code
  Mode tool surfaces while keeping omitted tools registered for permitted uses.
- Remove client-private `_meta` fields from MCP results returned to Code Mode.
- Include the new setting in the configuration schema and MCP config
  serialization.

## Testing

- Cover every exposure combination across Code Mode, Code-Mode-only sessions,
  tool search, direct-only namespaces, and prefixed and unprefixed MCP names.
- Verify direct and nested execution paths, parallel-call support, config
  round-tripping, and `_meta` filtering.

GitOrigin-RevId: 12dfcb78bb5c5ecf4d70f38a8b5022792463a27f
2026-08-03 18:51:46 +00:00
jif 12c115d558 Reduce cloning when building Responses requests (#34825)
## Why

Preparing Responses API requests rebuilt tool definitions as a generic JSON
tree, and incremental WebSocket requests cloned their full item prefix for
comparison.

## What changed

- Serialize tool definitions into shared raw JSON that can be embedded directly
  in HTTP and WebSocket requests.
- Compare incremental request prefixes in place while still ignoring internal
  message metadata.

## Testing

- Verify raw tool JSON matches the existing value encoding.
- Preserve the serialized WebSocket request payload.

GitOrigin-RevId: 66e2921792c332e8904954dafa597f6d39abcf29
2026-07-22 21:00:01 +00:00
Won Park 19ce6394af Route image extension reads through turn environments v2 (#27498)
## Why

Image generation used `std::fs::read` for referenced image paths, which
did not support environment-backed filesystems or their sandbox context.

## What changed

- Expose optional turn environments to extension tool calls.
- Include each environment’s ID, working directory, filesystem, and
sandbox context.
- Read referenced images through the selected environment filesystem.
- Keep sandbox usage at the extension call site so extensions can choose
the appropriate access mode.
- Consolidate image request construction into one async function.
- Add coverage for successful environment reads and read failures.

## Validation

- `cargo check -p codex-image-generation-extension --tests`
- `just fmt`
- `just bazel-lock-update`
- `just bazel-lock-check`

`just test -p codex-image-generation-extension` could not complete
because the build exhausted available disk space.
2026-06-11 16:32:52 -07:00
sayan-oai 728b8243a9 tools: simplify default tool search text (#27526)
## Why

Default tool search text currently derives identity from both `ToolName`
and `ToolSpec`. For function and namespace specs, this indexes the same
names more than once and also adds a flattened `{namespace}{name}` token
that is not model-visible.

## What changed

- Derive default search text entirely from `ToolSpec` while preserving
names, descriptions, namespace metadata, and recursive schema metadata.
- Keep the default search-text builder private and remove the unused
`ToolName` argument.
- Add coverage for the exact search text generated for a namespaced tool
with nested schema metadata.

## Example

For the `codex_app` namespace and `automation_update` tool (schema terms
omitted):

- Before: `codex_appautomation_update automation update codex_app
codex_app Manage Codex automations. automation_update automation update
...`
- After: `codex_app Manage Codex automations. automation_update
automation update ...`

## Testing

- `just test -p codex-tools`
2026-06-11 03:37:25 +00:00
Adam Perry @ OpenAI 2704ecea9a [codex] Remove async_trait from ToolExecutor (#27304)
## Why

We're now [discouraging use of
`async_trait`](https://github.com/openai/codex/pull/20242).

Removing use of `async_trait` from `ToolExecutor` yields a `codex_core`
debug test build speedup of ~78% (from 227.5s to 50.3s) on my machine.

Stacked on #27299, this PR applies the trait change after the handler
bodies have been outlined.

## What

Changed `ToolExecutor::handle` to return an explicit boxed
`ToolExecutorFuture` instead of using `async_trait`.

Updated ToolExecutor implementors to return `Box::pin(...)`, reexported
the future alias through `codex-tools` and `codex-extension-api`, and
removed `codex-tools` direct `async-trait` dependency.
2026-06-10 10:26:53 -07:00
Won Park 57f337a8e9 Route standalone image generation through host finalization md (#25176)
## Why

Standalone image-generation extensions emitted turn items through the
low-level event path, bypassing host-owned finalization such as image
persistence and contributor processing. At the same time, the
generated-image save-path hint must remain visible to the model through
the extension tool's `FunctionCallOutput`, rather than the legacy
built-in developer-message path.

## What changed

- Extended `ExtensionTurnItem` to support image-generation items while
keeping the extension-facing emitter API limited to `emit_started` and
`emit_completed`.
- Routed extension completion through core `finalize_turn_item`, so
standalone image-generation items receive host-owned processing and
persisted `saved_path` values before publication.
- Kept legacy built-in image generation on its existing
developer-message hint path, while standalone image generation returns
its deterministic saved-path hint in `FunctionCallOutput`.
- Shared the image artifact path and output-hint formatting used by core
and the image-generation extension.
- Passed thread identity through extension tool calls so standalone
image generation can construct the same intended artifact path as core.
- Added an app-server integration test covering real standalone image
generation, saved artifact publication, model-visible output hint
wiring, and absence of the legacy developer-message hint.

## Validation

- `just fmt`
- `just test -p codex-image-generation-extension`
- `just test -p codex-web-search-extension`
- `just test -p codex-goal-extension`
- `just test -p codex-memories-extension`
- Targeted `codex-core` tests for image save history, extension
completion finalization, and contributor execution
- `just test -p codex-app-server
standalone_image_generation_returns_saved_path_hint_to_model`
- `just fix -p codex-core`
- `just fix -p codex-image-generation-extension`
- `just bazel-lock-update`
- `just bazel-lock-check`
2026-06-02 12:00:04 -07:00
jif-oai 8d720feb69 Move tool search metadata onto ToolExecutor (#25684)
Deferred tools need to be searchable even when they are not implemented
inside `codex-core`. Extension-provided tools can be registered for
later discovery, but the search metadata path was still owned by
core-specific runtime hooks, which meant the shared `ToolExecutor`
abstraction could not describe how a deferred extension tool should
appear in `tool_search`.

## Changes

- Move `ToolSearchEntry` and `ToolSearchInfo` into `codex-tools` and
re-export them from the shared tools crate.
- Add a default `ToolExecutor::search_info` implementation that derives
loadable tool-search metadata from function and namespace specs.
- Forward search metadata through extension adapters and exposure
overrides while keeping custom search text/source metadata for dynamic,
MCP, and multi-agent tools.
- Remove the old core-local `tool_search_entry` module now that search
metadata lives with the shared executor APIs.

## Testing

- Added `deferred_extension_tools_are_discoverable_with_tool_search`
coverage in `core/src/tools/spec_plan_tests.rs`.
2026-06-02 00:24:41 +02:00
Michael Bolin d6748f741a feat: gate unified exec zsh fork composition (#24979)
## Why

`shell_zsh_fork` and unified exec need to remain independently
controllable for enterprise rollouts, but we also need a third mode that
composes them. That composed mode is intended to preserve unified exec
command lifecycle support while letting the zsh fork provide more
accurate `execv(2)` interception.

Enabling `unified_exec_zsh_fork` by itself is intentionally not
sufficient. It is a composition gate, not a dependency-enabling
shortcut:

- `unified_exec` selects the PTY-backed unified exec tool.
- `shell_zsh_fork` opts into the zsh fork backend.
- `unified_exec_zsh_fork` only allows those two already-enabled modes to
be composed so local zsh unified exec commands can launch through the
zsh fork.

This separation is deliberate. Enterprises and staged rollouts must be
able to enable or disable unified exec and zsh-fork independently. If
`unified_exec_zsh_fork` implied either dependency, then enabling one
under-development composition flag would silently activate a shell
backend that the configured feature set left disabled.

This PR introduces only the configuration and planning gate for that
composition. Existing `shell_zsh_fork` behavior continues to use the
standalone shell tool unless the new composition feature is explicitly
enabled alongside both dependencies.

## What Changed

- Added the under-development feature flag `unified_exec_zsh_fork`.
- Added `UnifiedExecFeatureMode` so the three input feature flags
collapse into `Disabled`, `Direct`, or `ZshFork` mode before tool
planning.
- Updated tool selection so zsh-fork composition requires
`unified_exec`, `shell_zsh_fork`, and `unified_exec_zsh_fork`.
- Kept the existing standalone zsh-fork shell tool behavior when only
`shell_zsh_fork` is enabled.
- Updated config schema output for the new feature flag.

## Verification

- Added feature and tool-config coverage for the new gate.
- Added planner coverage proving `shell_zsh_fork` remains standalone
until composition is explicitly enabled.
- Ran focused tests for `codex-features`, `codex-tools`, and the
affected `codex-core` planner case.





---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/24979).
* #24982
* #24981
* #24980
* __->__ #24979
2026-06-01 13:01:36 -07:00
Won Park 10b0399034 Route extension image generation through the native image completion pipeline (#24972)
## Why

The standalone `image_gen.imagegen` extension should behave like native
image generation for artifact persistence and UI completion, while
returning its save-location guidance as part of the tool result instead
of injecting a developer message.

## What Changed

- Added an image-generation completion hook for extension tools so core
can persist generated images and emit the existing `ImageGeneration`
lifecycle events.
- Reused core image artifact persistence for extension output and
removed extension-local save-path/file-writing logic.
- Split shared image persistence from built-in finalization so native
image generation keeps its existing developer-message instruction
behavior.
- Returned the generated image save-location instruction through the
extension `FunctionCallOutput`, alongside the generated image input for
model follow-up.
- Preserved the existing image-generation event shape for current UI and
replay compatibility.
- Avoided cloning the full generated-image base64 payload when emitting
the in-progress image item.
- Removed dependencies no longer needed after moving persistence out of
the extension crate.

## Fast Follow
- Adjust the existing Extension API and add a general `TurnItem`
finalization path for re-usability of code

## Validation

- Ran `just fmt`.
- Ran `just bazel-lock-update`.
- Ran `just bazel-lock-check`.
- Ran `just test -p codex-tools -p codex-extension-api -p
codex-image-generation-extension`.
- Ran `just test -p codex-core
image_generation_publication_is_finalized_by_core`.
- Ran `just test -p codex-core
handle_output_item_done_records_image_save_history_message`.
- Ran `just fix -p codex-tools -p codex-extension-api -p codex-core -p
codex-image-generation-extension`.
2026-05-29 17:33:13 +00:00
sayan-oaiandjif-oai 2066874415 extension-api: add TurnItemEmitter to tool calls (#24813)
## Why
Extension-contributed tools need to emit visible turn items through
Codex's normal event and persistence pipeline.

## What
- Add `TurnItemEmitter` to extension `ToolCall`s and route the core
implementation through `Session::emit_turn_item_*`.
- Hold weak session and turn references so retained tool calls cannot
keep host state alive.
- Provide a no-op emitter for extension test callers.

## Test Plan
- `just test -p codex-core -E
'test(passes_turn_fields_and_scoped_turn_item_emitter_to_extension_call)'`

---------

Co-authored-by: jif-oai <jif@openai.com>
2026-05-28 09:13:43 -07:00
sayan-oai 9fe55d68e6 fix: dont compact standalone websearch schema (#24660)
add new `parse_tool_input_schema_without_compaction` to bypass the
existing compaction/trimming of client-provided tool schemas that are
over 4k bytes.

we want this for standalone web search to keep field guidance/metadata
on certain fields; this keeps us closer to parity with existing hosted
tool schema (which didnt go through this 4k byte filter).
2026-05-27 01:05:19 +00:00
sayan-oai a22706dfae standalone websearch extension (#23823)
## Summary

Add the extension-backed standalone `web.run` tool so Codex can call the
standalone search endpoint through the `codex-api` search client and
return its encrypted output to Responses.

- gate the new tool behind `standalone_web_search`
- install the extension in the app-server thread registry and hide
hosted `web_search` when standalone search is enabled for OpenAI
providers so the two paths stay mutually exclusive
- build search context from persisted history using a small tail
heuristic: previous user message, assistant text between the last two
user turns capped at about 1k tokens, and current user message

## Test Plan

- `cargo test -p codex-web-search-extension`
- `cargo test -p codex-api`
- `cargo test -p codex-core
hosted_tools_follow_provider_auth_model_and_config_gates`
2026-05-26 11:12:24 -07:00
sayan-oai 7e802b22f1 Expose conversation history to extension tools (#23963)
## Why

Extension tools that need conversation context should be able to read it
from the live tool invocation instead of reaching into thread
persistence themselves.

## What changed

- Add a `ConversationHistory` snapshot to extension `ToolCall`s and
populate it from the current raw in-memory response history.
- Expose all history items at this boundary so each extension can filter
and bound the subset it needs before consuming or forwarding it.
- Cover the adapter and registry dispatch paths and update existing
extension tests that construct `ToolCall` literals.

## Test plan

- `cargo test -p codex-tools`
- `cargo test -p codex-extension-api`
- `cargo test -p codex-goal-extension`
- `cargo test -p codex-memories-extension`
- `cargo test -p codex-core passes_turn_fields_to_extension_call`
- `cargo test -p codex-core
extension_tool_executors_are_model_visible_and_dispatchable`
2026-05-22 01:11:47 +00:00
Matthew Zeng 8335b56c33 Split plugin install discovery into list and request tools (#23372)
## Summary
- Add `list_available_plugins_to_install` as the inventory step for
plugin and connector install suggestions.
- Slim `request_plugin_install` so it only handles the actual
elicitation, instead of carrying the full discoverable list in its
prompt.
- Emit send-time telemetry when an install elicitation is dispatched,
including requested tool identity in the event payload.
- Emit install-result telemetry through `SessionTelemetry`, including
tool type, user response action, and completion status.
- Update registration and tests to cover the new two-step flow while
keeping the existing `tool_suggest` feature gate unchanged.

## Testing
- `just fmt`
- `cargo test -p codex-tools`
- `cargo test -p codex-core request_plugin_install`
- `cargo test -p codex-core list_available_plugins_to_install`
- `cargo test -p codex-core
install_suggestion_tools_can_be_registered_without_search_tool`
- `cargo test -p codex-otel
manager_records_plugin_install_suggestion_metric`
- `cargo test -p codex-otel
manager_records_plugin_install_elicitation_sent_metric`
- `just fix -p codex-core`
- `just fix -p codex-tools`
- `just fix -p codex-otel`
- `cargo check -p codex-core`
2026-05-19 14:45:37 -07:00
jif-oai 05e171094d Remove ToolsConfig from tool planning (#22835)
## Why

`codex-tools` is meant to hold reusable tool primitives, but
`ToolsConfig` had become a second copy of core runtime decisions instead
of a small shared contract. It carried provider capabilities, auth/model
gates, permission and environment state, web/search/image feature gates,
multi-agent settings, and goal availability from core into `codex-tools`
([definition](https://github.com/openai/codex/blob/22dd9ad3929253ed24d7ee4f10f238e95ab25f37/codex-rs/tools/src/tool_config.rs#L97),
[stored on each
`TurnContext`](https://github.com/openai/codex/blob/22dd9ad3929253ed24d7ee4f10f238e95ab25f37/codex-rs/core/src/session/turn_context.rs#L87)).
Every session/context variant then had to build and mutate that snapshot
before assembling tools.

This PR removes that master object instead of renaming it. Tool planning
now reads the live `TurnContext`, where `codex-core` already owns those
decisions, while `codex-tools` keeps only reusable primitives and a
generic `ToolSetBuilder`/`ToolSet` accumulator.

## What Changed

- Removed `ToolsConfig` / `ToolsConfigParams` from `codex-tools`; the
crate keeps the shared helpers that still belong there, including
request-user-input mode selection, shell backend/type resolution,
`UnifiedExecShellMode`, and `ToolEnvironmentMode`.
- Replaced config-snapshot planning with `ToolRouter::from_turn_context`
and a `spec_plan` pipeline over `CoreToolPlanContext`, deriving provider
capabilities, auth gates, model support, feature gates, environment
count, goal support, multi-agent options, web search, and image
generation from the authoritative turn state.
- Added generic `codex_tools::ToolSetBuilder` / `ToolSet`, plus the
small core adapter needed to accumulate `CoreToolRuntime` values and
hosted model specs.
- Added the `tool_family::shell` registration module and moved
shell/unified-exec/memory accounting call sites to read the narrow
per-turn fields directly.
- Narrowed `TurnContext` to the remaining explicit per-turn fields
needed by planning: `available_models`, `unified_exec_shell_mode`, and
`goal_tools_supported`.
- Reworked MCP exposure and tool-search setup so deferred/direct MCP
behavior is driven by the current turn rather than a precomputed config
snapshot.
- Replaced the large expected-spec fixture tests with focused
behavior-level coverage for shell tools, environments, goal and
agent-job gates, MCP direct/deferred exposure, tool search,
request-plugin-install, code mode, multi-agent mode, hosted tools, and
extension executor dispatch.

## Verification

- `cargo check -p codex-tools`
- `cargo check -p codex-core --lib`
- `cargo test -p codex-tools`
- `cargo test -p codex-core spec_plan --lib`
- `cargo test -p codex-core router --lib`
2026-05-19 11:24:09 +02:00
jif-oai fdda59c00b Introduce tool exposure for deferred registration (#22489)
## Why

Deferred tools were tracked with separate side-channel filtering after
tool specs had already been assembled. That made the registry
responsible for executing tools while the router/spec planner separately
decided whether those same tools should be exposed to the model up
front.

This PR makes exposure part of the tool handler contract so direct
versus deferred availability travels with the executable tool
registration.

Next step will be to simplify registration

## What Changed

- Adds `ToolExposure` to `codex-tools` and exposes it through
`ToolExecutor`, defaulting tools to `Direct`.
- Teaches dynamic tools and MCP handlers to mark deferred tools as
`Deferred` at construction time.
- Renames the registry object-safe wrapper from `AnyToolHandler` to
`RegisteredTool` and uses `ToolExposure` when deciding whether to
include a handler's spec in the initial model-visible tool list.
- Refactors tool spec planning to derive direct specs and deferred
search entries from registered handlers, removing the router's
special-case deferred dynamic tool filtering.

## Verification

- Not run.
2026-05-13 18:16:51 +02:00
jif-oai 9c5dfa7b1a 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`
2026-05-13 12:12:06 +02:00
jif-oai 1824685a00 feat: extract shared tool executor interface (#22359)
## Why

Codex still models model-visible tools and executable behavior largely
inside `codex-core`, which makes it harder to evolve the tool system
toward a single reusable abstraction for built-ins, MCP-backed tools,
dynamic tools, and later tools injected from outside core.

This PR takes the next incremental step in that direction by moving the
common execution-facing pieces out of core and separating them from
core-only orchestration. The intent is to let shared tool abstractions
improve in one place, while `codex-core` keeps the parts that are still
inherently host-specific today, such as `ToolInvocation`, dispatch
wiring, and hook integration.

This PR is mostly moving things around. The only interesting piece is
this abstraction:
https://github.com/openai/codex/pull/22359/changes#diff-81af519002548ba51ed102bdaaf77e081d40a1e73a6e5f9b104bbbc96a6f1b3dR13

## What changed

- Added `codex_tools::ToolExecutor<Invocation>` as the shared execution
trait for model-visible tools.
- Moved the reusable execution support types from `codex-core` into
`codex-tools`:
  - `FunctionCallError`
  - `ToolPayload`
  - `ToolOutput`
- Refactored core tool implementations so that execution behavior lives
on `ToolExecutor<ToolInvocation>`, while `ToolHandler` remains the
core-local extension point for hook payloads, telemetry tags, diff
consumers, and other orchestration concerns.
- Kept the registry and dispatch flow behaviorally unchanged while
making the shared/extracted boundary explicit across built-in, MCP,
dynamic, extension-backed, shell, and multi-agent tool handlers.

## Verification

- `cargo test -p codex-tools`
- `just fix -p codex-tools`
- `just fix -p codex-core`
- `cargo test -p codex-core` progressed through the updated tool
surfaces and then hit the existing unrelated multi-agent stack overflow
in
`tools::handlers::multi_agents::tests::tool_handlers_cascade_close_and_resume_and_keep_explicitly_closed_subtrees_closed`.
2026-05-13 11:31:27 +02:00
pakrym-oai 104fc14956 Encapsulate tool search entries in handlers (#22261)
## Why

This builds on the handler-owned spec refactor by moving deferred
tool-search metadata to the same handlers that already own tool specs.
The registry builder no longer needs a separate prebuilt
`tool_search_entries` path; it can collect searchable entries from
deferred handlers directly.

## What changed

- Added `search_info()` to tool handlers and implemented it for MCP and
dynamic handlers.
- Reused handler `spec()` output when constructing tool-search entries,
adapting it into the deferred `LoadableToolSpec` shape expected by
`tool_search`.
- Simplified `build_tool_registry_builder(...)` so `tool_search`
registration is based on deferred handlers with search info.
- Removed the old standalone search-entry builders and now-unused
`codex-tools` discovery helper exports.

## Verification

- `cargo test -p codex-core tools::handlers::tool_search::tests:: --
--nocapture`
- `cargo test -p codex-core tools::spec_plan::tests::search_tool --
--nocapture`
- `cargo test -p codex-core tools::spec::tests:: -- --nocapture`
- `cargo test -p codex-core tools::spec_plan::tests:: -- --nocapture`
- `cargo test -p codex-tools`
- `just fix -p codex-core`
- `just fix -p codex-tools`
2026-05-12 20:48:02 -07:00
pakrym-oai c9e46ed639 [codex] Make handlers own parallel tool support (#22254)
## Why

`ToolRouter::tool_supports_parallel()` was still consulting configured
specs when a handler lookup missed, even though parallel schedulability
is really a property of the executable handler. Keeping that metadata on
`ConfiguredToolSpec` duplicated state between the model-visible spec
layer and the runtime handler layer.

This change makes handlers the sole source of truth for parallel tool
support and removes the extra spec wrapper that only existed to carry
duplicated metadata.

## What changed

- removed `ConfiguredToolSpec` and store plain `ToolSpec` values in the
registry/router builder path
- changed `ToolRouter::tool_supports_parallel()` to consult only the
handler registry and fall back to `false`
- simplified spec collection and test helpers to operate directly on
`ToolSpec`
- updated router/spec tests to cover handler-owned parallel behavior and
the no-handler fallback

## Validation

- `cargo test -p codex-tools`
- `cargo test -p codex-core mcp_parallel_support_uses_handler_data`
- `cargo test -p codex-core
deferred_responses_api_tool_serializes_with_defer_loading`
- `cargo test -p codex-core
tools_without_handlers_do_not_support_parallel`
- `cargo test -p codex-core
request_plugin_install_can_be_registered_without_search_tool`

## Docs

No documentation updates needed.
2026-05-11 22:26:33 -07:00
pakrym-oai 9417cf9696 [codex] Move tool specs into core handlers (#21416)
## Why

This is the first mechanical slice of moving tool spec ownership toward
the handlers. `codex-tools` should keep shared primitives and conversion
helpers, while builtin tool specs and registration planning live in
`codex-core` with the handlers that own those tools.

Keeping this PR to relocation and import updates isolates the copy/move
review from the later logic change that wires specs through registered
handlers.

## What changed

- Moved builtin tool spec constructors from `codex-rs/tools/src` into
`codex-rs/core/src/tools/handlers/*_spec.rs` or nearby core tool
modules.
- Moved the registry planning code into
`codex-rs/core/src/tools/spec_plan.rs` and its associated types/tests
into core.
- Kept shared primitives in `codex-tools`, including `ToolSpec`,
schema/types, discovery/config primitives, dynamic/MCP conversion
helpers, and code-mode collection helpers.
- Updated handlers that referenced moved argument types or tool-name
constants to use the core spec modules.
- Moved spec tests next to the moved spec modules.

## Verification

- `cargo check -p codex-tools`
- `cargo check -p codex-core`
- `cargo test -p codex-tools`
- `cargo test -p codex-core _spec::tests`
- `cargo test -p codex-core tools::spec_plan::tests`
- `just fix -p codex-tools`
- `just fix -p codex-core`

Note: I also tried the broader `cargo test -p codex-core tools::`; it
reached the moved spec-plan/spec tests successfully, then aborted with a
stack overflow in
`tools::handlers::multi_agents::tests::tool_handlers_cascade_close_and_resume_and_keep_explicitly_closed_subtrees_closed`,
which is outside this spec relocation.
2026-05-06 15:40:50 -07:00
jif-oai 70807730f5 tools: remove unused experimental list_dir tool (#21170)
## Why
`list_dir` still carries a full spec/handler/test path, but nothing in
the current model catalog advertises it via
`experimental_supported_tools`. That leaves us maintaining an
environment-backed tool surface that is effectively unused.

## What changed
- delete the `list_dir` handler and its tests from `codex-core`
- remove the `list_dir` spec builder, handler kind, and registry wiring
from `codex-tools`
- clean up the remaining internal README and registry tests so they no
longer mention the removed tool
2026-05-05 13:11:07 +02:00
starr-openaiandCodex 905987c08f Prepare selected environment plumbing (#20669)
## Why
This is a prep PR in the multi-environment process-tool stack. It
separates ownership/config cleanup from the behavior change that teaches
process tools to route by selected environment, so the follow-up PR can
focus on model-facing `environment_id` behavior.

## Stack
1. https://github.com/openai/codex/pull/20646 - `EnvironmentContext`
rendering for selected environments
2. https://github.com/openai/codex/pull/20669 - selected-environment
ownership and tool config prep (this PR)
3. https://github.com/openai/codex/pull/20647 - process-tool
`environment_id` routing

## What Changed
- keep the resolved turn environment list wrapped in
`ResolvedTurnEnvironments` through `TurnContext` instead of unwrapping
it back to a raw `Vec`
- add `TurnContext::resolve_path_against` so cwd-relative path
resolution has one shared helper
- replace the old tool config boolean with `ToolEnvironmentMode::{None,
Single, Multiple}`

## Testing
- Tests not run locally; this prep refactor is covered by GitHub CI for
the stack.

Co-authored-by: Codex <noreply@openai.com>
2026-05-04 17:55:49 +00:00
Matthew Zeng f88701f5c8 [tool_suggest] More prompt polishes. (#20566)
Tool suggest still misfires when model needs tool_search, updating the
prompts to further disambiguate it:

- [x] rename it from `tool_suggest` to `request_plugin_install`
- [x] rephrase "suggestion" to "install" in the tool descriptions.
- [x] disambiguate "the tool" vs "the plugin/connector". 

Tested with the Codex App and verified it still works.
2026-05-02 04:22:12 +00:00
pakrym-oai fedcefe9da Reduce the surface of collaboration modes (#20149)
Collaboration modes were slightly invasive both into ThreadManager
construction and ModelProvider
2026-04-29 17:22:41 -07:00
Matthew Zeng ebdf3a878c Support disabling tool suggest for specific tools. (#20072)
## Summary
- Add `disable_tool_suggest` to app and plugin config, schema, and
TypeScript output
- Exclude disabled connectors and plugins from tool suggestion discovery
- Persist "never show again" tool-suggestion choices back into
`config.toml`
- Update config docs and add coverage for connector and plugin
suppression

## Testing
- Added and updated unit tests for config persistence and tool-suggest
filtering
- Not run (not requested)
2026-04-29 00:19:34 +00:00
Eric Traut 32ace07ac5 Add goal model tools (3 / 5) (#18075)
Adds the model-facing goal tools on top of the app-server API from PR 2.

## Why

Once goals are persisted and exposed to clients, the model needs a
small, constrained tool surface for goal workflows. The tool contract
should let the model inspect goals, create them only when explicitly
requested, and mark them complete without giving it broad control over
user/runtime-owned state.

## What changed

- Added `get_goal`, `create_goal`, and `update_goal` tool specs behind
the `goals` feature flag.
- Added core goal tool handlers that validate objectives and token
budgets before mutating persisted state.
- Constrained `create_goal` to create only when no goal exists, with
optional `token_budget` only when a budget is explicitly provided.
- Tightened the `create_goal` instructions so the model does not infer
goals from ordinary task requests.
- Constrained `update_goal` to expose only goal completion; pause,
resume, clear, and budget-limited transitions remain user- or
runtime-controlled.
- Registered the goal tools in the tool registry and kept them out of
review contexts where they should not appear.

## Verification

- Added tool-registry coverage for feature gating and tool availability.
- Added core session tests for create/get/update behavior, duplicate
goal rejection, budget validation, and completion-only updates.
2026-04-24 20:54:40 -07:00
Curtis 'Fjord' Hawthorne 8a559e7938 Remove js_repl feature (#19410) 2026-04-24 17:49:29 -07:00
pash-openaiandSayan Sisodiya dc1a8f2190 [tool search] support namespaced deferred dynamic tools (#18413)
Deferred dynamic tools need to round-trip a namespace so a tool returned
by `tool_search` can be called through the same registry key that core
uses for dispatch.

This change adds namespace support for dynamic tool specs/calls,
persists it through app-server thread state, and routes dynamic tool
calls by full `ToolName` while still sending the app the leaf tool name.
Deferred dynamic tools must provide a namespace; non-deferred dynamic
tools may remain top-level.

It also introduces `LoadableToolSpec` as the shared
function-or-namespace Responses shape used by both `tool_search` output
and dynamic tool registration, so dynamic tools use the same wrapping
logic in both paths.

Validation:
- `cargo test -p codex-tools`
- `cargo test -p codex-core tool_search`

---------

Co-authored-by: Sayan Sisodiya <sayan@openai.com>
2026-04-21 14:13:08 +08:00
sayan-oaiandpash 6991be7ead enable tool search over dynamic tools (#18263)
## Summary

- Normalize deferred MCP and dynamic tools into `ToolSearchEntry` values
before constructing `ToolSearchHandler`.
- Move the tool-search entry adapter out of `tools/handlers` and into
`tools/tool_search_entry.rs` so the handlers directory stays focused on
handlers.
- Keep `ToolSearchHandler` operating over one generic entry list for
BM25 search, namespace grouping, and per-bucket default limits.

## Why

Follow-up cleanup for #17849. The dynamic tool-search support made the
handler juggle source-specific MCP and dynamic tool lists, index
arithmetic, output conversion, and namespace emission. This keeps source
adaptation outside the handler so the search loop itself is smaller and
source-agnostic.

## Validation

- `just fmt`
- `cargo test -p codex-core tools::handlers::tool_search::tests`
- `git diff --check`
- `cargo test -p codex-core` currently fails in unrelated
`plugins::manager::tests::list_marketplaces_ignores_installed_roots_missing_from_config`;
rerunning that single test fails the same way at
`core/src/plugins/manager_tests.rs:1692`.

---------

Co-authored-by: pash <pash@openai.com>
2026-04-18 02:07:59 +08:00
Curtis 'Fjord' Hawthorne 9e2fc31854 Support original-detail metadata on MCP image outputs (#17714)
## Summary
- honor `_meta["codex/imageDetail"] == "original"` on MCP image content
and map it to `detail: "original"` where supported
- strip that detail back out when the active model does not support
original-detail image inputs
- update code-mode `image(...)` to accept individual MCP image blocks
- teach `js_repl` / `codex.emitImage(...)` to preserve the same hint
from raw MCP image outputs
- document the new `_meta` contract and add generic RMCP-backed coverage
across protocol, core, code-mode, and js_repl paths
2026-04-15 14:43:33 -07:00
Shijie RaoandSayan Sisodiya 78ce61c78e Fix empty tool descriptions (#17946)
## Summary
- Ensure direct namespaced MCP tool groups are emitted with a non-empty
namespace description even when namespace metadata is missing or blank.
- Add regression coverage for missing MCP namespace descriptions.

## Cause
Latest `main` can serialize a direct namespaced MCP tool group with an
empty top-level `description`. The namespace description path used
`unwrap_or_default()` when `tool_namespaces` did not include metadata
for that namespace, so the outbound Responses API payload could contain
a tool like `{"type":"namespace","description":""}`. The Responses API
rejects that because namespace tool descriptions must be a non-empty
string.

## Fix
- Add a fallback namespace description: `Tools in the <namespace>
namespace.`
- Preserve provided namespace descriptions after trimming, but treat
blank descriptions as missing.

### Issue I am seeing
This is what I am seeing on the local build.
<img width="1593" height="488" alt="Screenshot 2026-04-15 at 10 55 55
AM"
src="https://github.com/user-attachments/assets/bab668ba-bf17-4c71-be4e-b102202fce57"
/>

---------

Co-authored-by: Sayan Sisodiya <sayan@openai.com>
2026-04-15 18:14:43 +00:00
sayan-oai 0df7e9a820 register all mcp tools with namespace (#17404)
stacked on #17402.

MCP tools returned by `tool_search` (deferred tools) get registered in
our `ToolRegistry` with a different format than directly available
tools. this leads to two different ways of accessing MCP tools from our
tool catalog, only one of which works for each. fix this by registering
all MCP tools with the namespace format, since this info is already
available.

also, direct MCP tools are registered to responsesapi without a
namespace, while deferred MCP tools have a namespace. this means we can
receive MCP `FunctionCall`s in both formats from namespaces. fix this by
always registering MCP tools with namespace, regardless of deferral
status.

make code mode track `ToolName` provenance of tools so it can map the
literal JS function name string to the correct `ToolName` for
invocation, rather than supporting both in core.

this lets us unify to a single canonical `ToolName` representation for
each MCP tool and force everywhere to use that one, without supporting
fallbacks.
2026-04-15 21:02:59 +08:00
sayan-oai 1325bcd3f6 chore: refactor name and namespace to single type (#17402)
avoid passing them both around, unify on a type. this now also keys
`ToolRegistry`.

tests pass
2026-04-11 23:06:22 +00:00
Vivian Fang 7bbe3b6011 Add output_schema to code mode render (#17210)
This updates code-mode tool rendering so MCP tools can surface
structured output types from their `outputSchema`.

What changed:
- Detect MCP tool-call result wrappers from the output schema shape
instead of relying on tool-name parsing or provenance flags.
- Render shared TypeScript aliases once for MCP tool results
(`CallToolResult`, `ContentBlock`, etc.) so multiple MCP tool
declarations stay compact.
- Type `structuredContent` from the tool definition's `outputSchema`
instead of rendering it as `unknown`.
- Update the shared MCP aliases to match the MCP draft `CallToolResult`
schema more closely.

Example:
- Before: `declare const tools: { mcp__rmcp__echo(args: { env_var?:
string; message: string; }): Promise<{ _meta?: unknown; content:
Array<unknown>; isError?: boolean; structuredContent?: unknown; }>; };`
- After: `declare const tools: { mcp__rmcp__echo(args: { env_var?:
string; message: string; }): Promise<CallToolResult<{ echo: string; env:
string | null; }>>; };`
2026-04-10 11:41:44 +00:00
Matthew Zeng d7f99b0fa6 [mcp] Expand tool search to custom MCPs. (#16944)
- [x] Expand tool search to custom MCPs.
- [x] Rename several variables/fields to be more generic.

Updated tool & server name lifecycles:

**Raw Identity**

ToolInfo.server_name is raw MCP server name.
ToolInfo.tool.name is raw MCP tool name.
MCP calls route back to raw via parse_tool_name() returning
(tool.server_name, tool.tool.name).
mcpServerStatus/list now groups by raw server and keys tools by
Tool.name: mod.rs:599
App-server just forwards that grouped raw snapshot:
codex_message_processor.rs:5245

**Callable Names**

On list-tools, we create provisional callable_namespace / callable_name:
mcp_connection_manager.rs:1556
For non-app MCP, provisional callable name starts as raw tool name.
For codex-apps, provisional callable name is sanitized and strips
connector name/id prefix; namespace includes connector name.
Then qualify_tools() sanitizes callable namespace + name to ASCII alnum
/ _ only: mcp_tool_names.rs:128
Note: this is stricter than Responses API. Hyphen is currently replaced
with _ for code-mode compatibility.

**Collision Handling**

We do initially collapse example-server and example_server to the same
base.
Then qualify_tools() detects distinct raw namespace identities behind
the same sanitized namespace and appends a hash to the callable
namespace: mcp_tool_names.rs:137
Same idea for tool-name collisions: hash suffix goes on callable tool
name.
Final list_all_tools() map key is callable_namespace + callable_name:
mcp_connection_manager.rs:769

**Direct Model Tools**

Direct MCP tool declarations use the full qualified sanitized key as the
Responses function name.
The raw rmcp Tool is converted but renamed for model exposure.

**Tool Search / Deferred**

Tool search result namespace = final ToolInfo.callable_namespace:
tool_search.rs:85
Tool search result nested name = final ToolInfo.callable_name:
tool_search.rs:86
Deferred tool handler is registered as "{namespace}:{name}":
tool_registry_plan.rs:248
When a function call comes back, core recombines namespace + name, looks
up the full qualified key, and gets the raw server/tool for MCP
execution: codex.rs:4353

**Separate Legacy Snapshot**

collect_mcp_snapshot_from_manager_with_detail() still returns a map
keyed by qualified callable name.
mcpServerStatus/list no longer uses that; it uses
McpServerStatusSnapshot, which is raw-inventory shaped.
2026-04-09 13:34:52 -07:00
Vivian Fang d47b755aa2 Render namespace description for tools (#16879) 2026-04-08 02:39:40 -07:00
Vivian Fang ea516f9a40 Support anyOf and enum in JsonSchema (#16875)
This brings us into better alignment with the JSON schema subset that is
supported in
<https://developers.openai.com/api/docs/guides/structured-outputs#supported-schemas>,
and also allows us to render richer function signatures in code mode
(e.g., anyOf{null, OtherObjectType})
2026-04-08 01:07:55 -07:00
jif-oai 7fc36249b5 chore: rename assign_task for followup_task (#16571) 2026-04-02 16:51:17 +02:00
Michael Bolin 828b837235 Extract tool registry planning into codex-tools (#16513)
## Why
This is a larger step in the `codex-core` -> `codex-tools` migration
called out in `AGENTS.md`.

`codex-rs/core/src/tools/spec.rs` had become mostly pure tool-spec
assembly plus handler registration. That made it hard to move more of
the tool-definition layer into `codex-tools`, because the runtime
binding and the crate-independent planning logic were still interleaved
in one function.

Splitting those concerns gives `codex-tools` ownership of the
declarative registry plan while keeping `codex-core` responsible for
instantiating concrete handlers.

## What Changed
- Add a `codex-tools` registry-plan layer in
`codex-rs/tools/src/tool_registry_plan.rs` and
`codex-rs/tools/src/tool_registry_plan_types.rs`.
- Move feature-gated tool-spec assembly, MCP/dynamic tool conversion,
tool-search aliases, and code-mode nested-plan expansion into
`codex-tools`.
- Keep `codex-rs/core/src/tools/spec.rs` as the core-side adapter that
maps each planned handler kind to concrete runtime handler instances.
- Update `spec_tests.rs` to import the moved `codex_tools` symbols
directly instead of relying on top-level `spec.rs` re-exports.

This is intended to be a straight refactor with no behavior change and
no new test surface.

## Verification
- `cargo test -p codex-tools`
- `cargo test -p codex-core tools::spec::tests`

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16513).
* #16521
* __->__ #16513
2026-04-02 00:18:18 -07:00