Commit Graph

822 Commits

Author SHA1 Message Date
Eric Traut
d72d669ca7 tui: update safety buffering copy (#31813)
## Summary

The safety-buffering message currently leads with additional safety
checks, which can make the delay feel accusatory. Update it to describe
the system taking more time before responding, matching the revised
user-facing language.

- Replace the safety-buffering copy in both retry and non-retry flows.
- Keep the faster-model escape hatch while aligning its wording with the
updated message.
- Update the TUI snapshots for both states.
2026-07-09 10:03:22 -07:00
Felipe Coury
f46b53bd85 fix(tui): hide empty reasoning summaries (#31652)
## Why

Reasoning summaries can contain an empty HTML comment placeholder, `<!--
-->`, when a generated summary part has no prose. The TUI treated that
placeholder as visible summary content, so it leaked into both the
completed conversation history and persisted transcript. Multi-part
empty summaries could also leave later generated status headings visible
as orphaned transcript content.

## What

- Strip the empty reasoning-summary placeholder at the shared
`ReasoningSummaryCell` boundary.
- Suppress the cell when removing placeholders leaves only generated
bold status headings.
- Cover the multi-part placeholder-only shape with a rendering
regression test for both normal history and transcript output.

## How to Test

1. Start Codex TUI with reasoning summaries visible, for example with
`hide_agent_reasoning = false` and `model_reasoning_summary =
"detailed"`.
2. Run a turn that receives an empty generated reasoning-summary part.
3. Confirm that the in-progress status heading may appear while the turn
is running, but the completed history and transcript contain neither
literal `<!-- -->` tokens nor orphaned reasoning headings.
4. Confirm that a reasoning summary with actual prose still renders
normally.

The model output is nondeterministic, so the targeted regression covers
the exact multi-part placeholder shape from the report:

- `just test -p codex-tui
reasoning_summary_block_hides_empty_html_comment_parts`
2026-07-09 16:27:50 +00:00
github-actions[bot]
3380969a29 Update models.json (#31684)
Automated update of models.json.

---------

Co-authored-by: sayan-oai <244841968+sayan-oai@users.noreply.github.com>
Co-authored-by: sayan-oai <sayan@openai.com>
2026-07-09 03:40:08 +00:00
github-actions[bot]
b780738014 Update models.json (#21818)
Automated update of models.json.

---------

Co-authored-by: aibrahim-oai <219906144+aibrahim-oai@users.noreply.github.com>
Co-authored-by: Ahmed Ibrahim <aibrahim@openai.com>
Co-authored-by: Sayan Sisodiya <sayan@openai.com>
2026-07-08 16:24:12 -07:00
Shijie Rao
927004c06d tui: warn on Ultra with high multi-agent concurrency (#31621)
## Why

Ultra reasoning may proactively use multiple agents. When
`features.multi_agent_v2.max_concurrent_threads_per_session` is
configured at 8 or higher, explicitly selecting Ultra can allow up to `N
- 1` subagents to work concurrently and increase usage quickly. Showing
the configured limits at selection time makes that tradeoff visible and
points users to the setting that controls it.

## What changed

- Show a warning history cell after the user explicitly selects Ultra
reasoning with a concurrent-thread limit of at least 8.
- Include the configured concurrent-thread count and maximum subagent
count in the warning.
- Apply the warning consistently across model and reasoning pickers,
Plan-mode scope selection, and reasoning shortcuts.
- Keep the trigger limited to the selected reasoning effort and
configured thread limit, independent of how multi-agent v2 is activated.
- Add focused threshold coverage and an `insta` snapshot for the
rendered warning.

## User impact

Users with high multi-agent concurrency receive a concrete warning
immediately after selecting Ultra. Other reasoning efforts, limits below
8, and startup behavior are unchanged.


https://github.com/user-attachments/assets/5795bcb9-432e-42bc-bde3-ee363e9aeb69

## Test plan

- `just test -p codex-tui ultra_reasoning_selection`
- Built the full debug CLI with `cargo build -p codex-cli`.
- Manually verified the debug TUI with a 10-thread limit: switching from
Max to Ultra displayed the warning with 10 concurrent threads and up to
9 subagents.
2026-07-08 12:29:21 -07:00
Owen Lin
a219b6fdb4 core: migrate standalone web search to extension-owned turn items (#31525)
## Description

This PR migrates standalone web search onto the extension-owned
turn-item path introduced in #31283.

Standalone web search now emits `ExtensionItem::WebSearch` through
generic `TurnItem::Extension`, while app-server still exposes the
existing typed `ThreadItem::WebSearch` JSON shape. Hosted Responses API
web search stays on core-owned `TurnItem::WebSearch`.

## What changed

- Added `web_search::WebSearchItem` and `WebSearchAction` to
`codex-extension-items` under the stable `web.search` kind.
- Collapsed `ExtensionTurnItem` to generic `{ item, legacy_events }` now
that no typed extension special cases remain.
- Kept the existing `WebSearchBegin` / `WebSearchEnd` compatibility
events and canonical-first ordering.
- Updated app-server projection/history and generated TypeScript; the
app-server JSON schema is unchanged.
2026-07-08 09:40:00 -07:00
Owen Lin
f1affbac5e core: support extension-owned turn items (#31283)
## Description

This PR adds a `codex-extension-items` crate for extension-owned
`TurnItem` schemas, and updates standalone image generation to start
using it via `TurnItem::Extension`.

This gives us a way to prevent Core from having to be aware of all
extension items. App-server still exposes the existing public
`ThreadItem::ImageGeneration` shape, now by wrapping the same shared
`image_generation::ImageGenerationItem` type.

The new `codex-extension-items` crate is necessary because the image gen
extension item is used by:
- `codex-image-generation-extension`, which produces it.
- `codex-tools / core`, which carry it generically.
- `codex-protocol`, which serializes it into lifecycle events and
rollouts.
- `app-server protocol`, which wraps it in public
`ThreadItem::ImageGeneration`

```
extension implementation
        ↓
codex-extension-items
        ↓
protocol / tools / app-server
```

We keep the hosted Responses API image generation as
`TurnItem::ImageGeneration` because core still owns its persistence and
legacy fanout.

### Before

Standalone image generation is implemented as an extension, but its item
representation previously lived in the core protocol. This sets the
precedent that core is aware of all extension items, which would be good
to avoid.

```
image-gen extension
→ constructs codex_protocol::ImageGenerationItem
→ emits ExtensionTurnItem::ImageGeneration
→ core matches ImageGeneration specially
→ protocol stores TurnItem::ImageGeneration
```

### After
```
image-gen extension
→ constructs extension-owned ImageGenerationItem
→ emits generic ExtensionItem
→ core transports/persists it generically
→ app-server wraps ImageGenerationItem as ThreadItem::ImageGeneration
```

Future extension items can have typed app-server APIs without adding a
new `TurnItem` variant, `ExtensionTurnItem` variant, or core emitter
match arm.

## What changed

- Added `codex-extension-items` with the closed `ExtensionItem` enum and
shared `image_generation::ImageGenerationItem` schema.
- Added generic `TurnItem::Extension(ExtensionItem)` and
`ExtensionTurnItem::Extension { item, legacy_events }` paths.
- Updated standalone image generation to emit a typed extension item and
provide its existing legacy `ImageGenerationBegin` /
`ImageGenerationEnd` events explicitly.
- Kept canonical lifecycle ordering: core emits `ItemStarted` /
`ItemCompleted` before extension-provided legacy events.

## Follow-up

Standalone web search still uses its typed special-case path. Migrating
it later would let `ExtensionTurnItem` collapse into a single
extension-item struct.
2026-07-08 03:55:13 +00:00
Francis Chalissery
78df1237d1 Handle bio policy errors in Codex (#31439)
## Summary

- Treat streamed Responses `bio_policy` failures as terminal invalid
requests instead of retryable stream errors.
- Recognize the new biology policy code and message in the TUI while
preserving the legacy `invalid_prompt` contract.
- Keep the existing dedicated biology safety notice and add
regression/snapshot coverage for all supported error shapes.

## Why

[openai/openai#1068559](https://github.com/openai/openai/pull/1068559)
gates a Responses API contract change from `invalid_prompt` and the
legacy message to `bio_policy` and new biology copy.

Without this compatibility change, streamed blocks are retried as
transient failures and the OSS TUI falls back to a generic/raw error
instead of the dedicated safety notice.

## Validation

- `just test -p codex-api` — 137 passed
- `just test -p codex-tui
app_server_safety_access_errors_render_dedicated_notice` — passed
- `just fix -p codex-api`
- `just fix -p codex-tui`
- `just fmt`
- `just test -p codex-tui` — 2,957 passed; two reproducible failures
remain in untouched Guardian feature-flag persistence tests:
-
`update_feature_flags_disabling_guardian_clears_review_policy_and_restores_default`
-
`update_feature_flags_disabling_guardian_clears_manual_review_policy_without_history`
2026-07-07 10:33:42 -07:00
jay
d7ab20ce62 [codex-cli] Show reset details in redemption picker (#30488)
## Why

Users can see that usage-limit reset credits are available, but not
which credits they have, when each one expires, or which credit will be
consumed. The TUI should use the supported rate-limit RPC for that
information without maintaining a second reset-credit request path.

## What changed

- load reset-credit details through the existing
`account/rateLimits/read` refresh when the user opens **Redeem usage
limit reset**
- show available credits sorted by expiry, using the backend title when
present and a scope-based fallback otherwise
- consume the exact selected credit and preserve its idempotency key
across retries
- fall back to the existing generic reset action when the RPC returns a
positive count without detail rows
- remove the dedicated list-RPC event, request, response-combining, and
TUI state plumbing
- handle a selected credit becoming unavailable without incorrectly
caching the user's total count as zero
- handle forward-compatible unknown reset types with the existing
scope-based fallback label

## TUI preview

Rendered from the final standard-width and narrow `insta` snapshots in
this PR.

<img width="1280" height="570" alt="pr30488-reset-picker-preview"
src="https://github.com/user-attachments/assets/8b84cd33-cb35-4a37-aaed-dbd6b62bff51"
/>

## Validation

- `just test -p codex-tui chatwidget::tests::usage` (32 passed)
- `just fix -p codex-tui`
- no pending `insta` snapshots

Uses the reset-credit details added by #30395.

Fixes #29618.
2026-07-06 21:19:50 -07:00
Eric Ning
c71895f63b [codex] app-server: expose plugin install policy source (#31293)
## Summary

- Add `PluginInstallPolicySource` to the app-server v2 `PluginSummary`
payload.
- Propagate remote `installation_policy_source` through plugin
summaries, details, installed-plugin caching, and app-server responses.
- Preserve the supported source values and map unrecognized backend
values to `null`.
- Return `null` for local plugins and expose the field in generated JSON
and TypeScript schemas.
- Update app-server API documentation and plugin list/read coverage.

## Testing

- `just test -p codex-app-server-protocol` (251 passed)
- Targeted `codex-app-server` plugin list, installed, and read tests (4
passed)
- Targeted `codex-core-plugins` known and unknown policy source tests (2
passed)
- `just fmt`
- `git diff --check`
2026-07-06 17:12:39 -07:00
Abhinav
02868b9019 [tui] Truncate hook context in conversation history (#31252) 2026-07-06 16:33:13 -04:00
jay
58ec528315 [app-server] Include reset-credit details in rate limits (#30395)
## Why

Supported clients currently receive only a reset-credit count from
`account/rateLimits/read`. The redemption UI and other app-server
clients need each available credit's expiry and ID so they can explain
what will expire and consume the credit a user selected. This
information belongs on the existing rate-limit read surface rather than
a second app-server list RPC that clients would need to coordinate.

## What changed

- extend `rateLimitResetCredits` on `account/rateLimits/read` with
nullable `credits` detail rows
- fetch usage and reset-credit details concurrently; if the detail
request fails, times out, or cannot be parsed, preserve the usage
response and return `credits: null`
- expose each credit's ID, reset type, status, grant time, expiry time,
title, and description
- add an optional nullable `creditId` to
`account/rateLimitResetCredit/consume`; omitting it preserves the
existing automatic-selection behavior
- forward a selected credit ID to the Codex backend and update the
app-server documentation and generated schemas

The TUI consumer is stacked in #30488.

## Validation

- `just test -p codex-app-server-protocol` (251 passed)
- `just test -p codex-backend-client` (16 passed)
- `just test -p codex-app-server rate_limit` (18 passed)

Part of #29618.
2026-07-06 12:54:06 -07:00
Alexi Christakis
7b4e70d567 Revert "[core] Support interleaved response items" (#31261)
Reverts openai/codex#30876
2026-07-06 10:09:54 -07:00
Alexi Christakis
8917244f7d [core] Support interleaved response items (#30876)
## Summary

- preserve reasoning item IDs on summary part and text delta events
- track streamed response items by ID so reasoning summaries can
continue after later items begin
- keep TUI output complete and deduplicated when reasoning and
final-answer events interleave

## Stack

- **1/2: this PR — interleaved item support**
- 2/2: #30752 — wire reasoning summary delivery configuration through
the CLI and app-server

## Validation

- just test -p codex-api preserves_reasoning_summary_item_ids
- just test -p codex-core
interleaved_reasoning_summary_events_keep_reasoning_item_metadata
- just test -p codex-tui
live_reasoning_summary_is_not_rendered_twice_when_item_completes
- just fix -p codex-api -p codex-core -p codex-tui
- just fmt
2026-07-06 09:12:45 -07:00
Eric Ning
d206a5d68f [codex] expose remote plugin versions (#30981) 2026-07-03 17:14:49 -06:00
Eric Traut
9d13291955 Update safety check links (#30491)
## Summary

Bio/Cyber safety surfaces in the TUI could send users to stale Trusted
Access pages, and safety buffering did not always expose the Help
Center.

This follow-up to #30317 adds the missing Learn more action, refreshes
the Bio access URL and block copy, and updates the affected snapshots
while preserving the existing retry and wait behavior.
2026-06-29 11:10:11 -07:00
Shijie Rao
80f54d1266 [codex] Treat max as a first-class reasoning effort (#30467)
## Why

The Bedrock GPT-5.6 catalog advertises `max`, but Codex treated it as an
opaque custom effort. That made the reasoning picker render it as
lowercase `max` while known efforts use productized labels.

Making `max` a known effort aligns catalog data, parsing, and UI
presentation without changing the `max` wire value or persisted
representation.

## What changed

- Add first-class `ReasoningEffort::Max` parsing and serialization.
- Use the typed effort in the Bedrock catalog and render it as `Max` in
the TUI.
- Preserve forward-compatible custom-effort coverage with a genuinely
unknown `future` value.

### Before
<img width="559" height="124" alt="Screenshot 2026-06-28 at 12 08 47 PM"
src="https://github.com/user-attachments/assets/7c43cf4f-020b-4605-9239-0a9c97eb7364"
/>

### After
<img width="558" height="107" alt="Screenshot 2026-06-28 at 12 09 10 PM"
src="https://github.com/user-attachments/assets/b9cc5ded-c940-43b4-b024-bba25abe0a17"
/>
2026-06-29 09:38:49 -07:00
Felipe Coury
850da19dc4 fix(tui): clear completed safety buffering prompt (#30490)
## Why

The safety-buffering prompt is a modal TUI view, but the normal
successful-turn path only hid the running status indicator. If the turn
completed while the prompt was open, the stale modal remained over the
composer until the user dismissed it or another turn started.

This aligns the TUI with the app behavior: keep the safety notice
visible while the turn is active, then remove it when the turn becomes
terminal. It also prevents the stale retry action from changing the
model and reasoning effort for a future turn after the buffered turn has
already completed.

| New copy |
|---|
| <img width="1014" height="313" alt="CleanShot 2026-06-28 at 20 27 18"
src="https://github.com/user-attachments/assets/f0f37359-5d77-442f-add2-9d1874bdc422"
/> |

## What changed

- Clear the active safety-buffering view and retry state when a turn
completes successfully.
- Update the retry-capable message to say “Hang tight or retry with a
faster model”.
- Extend the safety-buffering regression coverage to verify that the
prompt remains visible after assistant output starts and disappears when
the turn completes.
- Update the TUI snapshot for the revised copy.

This is a follow-up to #29919.

## How to Test

1. Start a TUI turn that receives `model/safetyBuffering/updated` with
`showBufferingUi: true` and a `fasterModel`.
2. Confirm the prompt says “Hang tight or retry with a faster model”.
3. Let the turn continue and confirm the prompt remains visible while
the turn is active.
4. Let the turn finish successfully and confirm the prompt disappears
and the composer is restored without requiring an extra keypress.
5. Confirm a buffering update without a faster model still shows the
shorter non-retry message.

Targeted automated coverage:

- `just test -p codex-tui safety_buffering` — 4 passed.
- `just test -p codex-tui` — 2,951 passed; two unrelated Guardian
feature-flag tests failed identically on `main` in this environment.

The argument-comment lint was also audited manually. The workspace Bazel
invocation was blocked by a missing external LLVM `compiler-rt` BUILD
file, and the packaged per-crate fallback uses a nightly older than the
current `sqlx` minimum Rust version.
2026-06-28 20:55:53 -03:00
xl-openai
e428a12d22 [codex] Enable remote plugins by default (#30297)
## Summary

- enable the remote plugin feature by default
- promote the remote plugin feature from under development to stable
- preserve the existing `features.remote_plugin` override for explicitly
disabling it
- keep legacy disabled-path coverage explicit in TUI and app-server
tests

## Impact

Remote plugin functionality is enabled by default for configurations
that do not set the feature flag. The existing Codex backend
authentication gate still applies.

## Validation

- `just fmt`
- `just test -p codex-features`
- `just test -p codex-tui
plugins_popup_remote_section_fallback_states_snapshot`
- targeted `codex-app-server` plugin-list and skills-list tests
- `git diff --check`

The full TUI and app-server suites were also exercised locally. All
remote-plugin-related coverage passed; unrelated local
sandbox/test-binary failures remain outside this change.
2026-06-28 11:46:25 -07:00
Eric Traut
c464468493 Update security check wording (#30317) 2026-06-26 20:05:32 -07:00
charlesgong-openai
6509f3148a [codex] Support npm marketplace plugin sources (#29375)
## Why

Marketplace source deserialization treated `{"source":"npm", ...}` as
unsupported. The loader logged and skipped the entry, so npm-backed
plugins never appeared in `plugin list --available` and `plugin add`
returned "plugin not found".

Codex plugins are installed from a plugin root, not from an npm
dependency tree. For npm-backed marketplace entries, Codex should fetch
the published package contents without running package scripts or
installing unrelated dependencies.

## What changed

- Add `npm` marketplace plugin sources with `package`, optional semver
`version` or version range, and optional HTTPS `registry`.
- Reject unsafe npm source fields before materialization, including
invalid package names, non-semver version selectors, plaintext or
credential-bearing registry URLs, and registry query/fragment data.
- Materialize npm plugins with `npm pack --ignore-scripts`, then unpack
the resulting tarball through the existing hardened plugin bundle
extractor.
- Enforce npm archive and extracted-size limits, require the standard
npm `package/` archive root, and verify the extracted `package.json`
name matches the requested package before installing.
- Keep plugin listings, install-source descriptions, CLI JSON/human
output, app-server v2 `PluginSource`, TUI source summaries, regenerated
schema fixtures, and app-server documentation in sync.

## Impact

Marketplaces can distribute Codex plugins from public or configured
private HTTPS npm registries using the same install flow as existing
materialized plugin sources. `npm` must be available on `PATH` when an
npm-backed plugin is installed.

Fixes #27831

## Validation

- `just write-app-server-schema`
- `just test -p codex-core-plugins -p codex-app-server-protocol -p
codex-app-server -p codex-cli`
  - npm/schema/core-plugin coverage passed in the run.
- The full focused command finished with `1739 passed`, `11 failed`, and
`6 timed out`; the failures were unrelated local app-server environment
failures from `sandbox-exec: sandbox_apply: Operation not permitted`
plus one missing `test_stdio_server` helper binary.
- Installed an npm-published Codex plugin package through a throwaway
local marketplace and throwaway `CODEX_HOME` to exercise the real npm
materialization path end to end.
2026-06-26 17:24:46 -04:00
felixxia-oai
a6d20ed297 [codex] Surface MCP reauthentication-required startup failures (#29877)
## Summary

- distinguish expired, non-refreshable stored MCP OAuth credentials from
first-time missing credentials
- carry a typed `failureReason: "reauthenticationRequired"` on the
existing `mcpServer/startupStatus/updated` notification only when user
action is required
- keep the public MCP auth-status API unchanged and regenerate the
app-server protocol schemas and documentation

## Why

An MCP server with an expired access token and no usable refresh token
currently fails startup without giving clients a reliable, typed
recovery signal.

The existing startup-status notification is the natural place to carry
this state. Its nullable `failureReason` keeps the recovery reason
attached to the failed startup transition without adding a one-off
notification. Internally, Codex distinguishes first-time login from
reauthentication and emits the reason only when the startup error itself
requires authentication.

## User impact

App clients can prompt an existing user to reconnect an MCP server when
automatic recovery is impossible by handling a failed
`mcpServer/startupStatus/updated` notification whose `failureReason` is
`reauthenticationRequired`. Starting, ready, cancelled, unrelated
failures, and first-time setup carry no reauthentication reason.

## Companion app PR

- openai/openai#1069582

## Validation

- `just test -p codex-app-server-protocol` — 248 passed; schema fixture
tests passed
- `cargo check -p codex-app-server -p codex-tui`
- `just test -p codex-rmcp-client -p codex-mcp` — 184 passed, 2 skipped
- `just test -p codex-protocol -p codex-app-server-protocol -p
codex-mcp` — 579 passed
- `just write-app-server-schema`
- `just fmt`
2026-06-25 21:50:36 +00:00
Shijie Rao
df1199fddb [codex] Add Ultra reasoning effort (#29899)
## Why

Ultra should be one user-facing reasoning selection for work that
benefits from both maximum reasoning and proactive multi-agent
delegation. Without it, clients must coordinate maximum reasoning with
the experimental `multiAgentMode` setting, even though the inference
backend still expects its existing `max` effort value.

This change makes reasoning effort the source of truth: clients select
`ultra`, core derives proactive multi-agent behavior when the turn is
eligible for multi-agent V2, and inference requests continue to use the
backend-compatible `max` value.

## What changed

- Add `ultra` as a first-class reasoning effort and preserve
model-catalog ordering when exposing it to clients.
- Convert `ultra` to `max` at the inference request boundary, including
Responses HTTP/WebSocket requests, startup prewarm, compaction, and
memory summarization.
- Derive effective multi-agent mode per turn from effective reasoning
effort:
  - eligible multi-agent V2 + `ultra` → `proactive`
  - eligible multi-agent V2 + any other effort → `explicitRequestOnly`
- V1 or otherwise ineligible sessions → no multi-agent mode instruction
- Keep the derived effective mode in turn context history so successive
turns can emit a developer-message update only when the effective mode
changes.
- Remove selected multi-agent mode from core session configuration, turn
construction, thread settings, resume/fork restoration, and subagent
spawn plumbing. Subagents inherit reasoning effort and derive their own
effective mode.
- Retain the experimental app-server `multiAgentMode` fields for wire
compatibility while marking them deprecated. Request values are accepted
but ignored; compatibility response fields report `explicitRequestOnly`.
- Display Ultra in the TUI using the order supplied by `model/list`.

## Validation

- `just test -p codex-core ultra_reasoning_uses_max_for_requests`
- `just test -p codex-tui model_reasoning_selection_popup`
2026-06-24 20:13:52 -07:00
Eric Traut
6801941cfe TUI support for buffer experience (#29919) 2026-06-24 19:50:50 -07:00
canvrno-oai
a0d5fd772e TUI Plugin Sharing 5 - polish remote plugin catalog rows (#26705)
This is the final plugin sharing PR in the 5-PR stack. It applies the
remaining TUI polish for remote plugin catalog rows and tabs:
admin-disabled plugins now read as blocked/view-only instead of looking
toggleable, admin-installed/default-installed plugins count and sort
like installed plugins, plugin search matches richer metadata, and an
empty successful `Shared with me` section stays hidden.

- Admin-disabled rows use a blocked marker, show `Disabled`, and keep
Enter-only detail behavior without a toggle hint.
- Admin-installed/default-installed plugins show as installed in counts,
ordering, tabs, and detail copy.
- Plugin search now matches descriptions and keywords in addition to
existing row metadata.
- Successful-empty `Shared with me` tabs are hidden, while loading,
error, workspace-empty, and real shared-plugin states remain visible.
- Updates coverage in
`plugins_popup_snapshot_shows_all_marketplaces_and_sorts_installed_then_name`,
`plugins_popup_admin_disabled_installed_plugin_has_no_toggle_hint`,
`plugins_popup_search_matches_plugin_descriptions`, and
`plugins_popup_remote_section_fallback_states_snapshot`.
- Updates snapshots `plugins_popup_curated_marketplace` and
`plugins_popup_empty_shared_section_hidden`.


<img width="2034" height="106" alt="image"
src="https://github.com/user-attachments/assets/3f9a57e1-edd8-4e6c-b0b0-9f632a3c9529"
/>
<img width="2038" height="380" alt="image"
src="https://github.com/user-attachments/assets/45a47491-3381-4846-a13d-496bc0051d42"
/>
2026-06-24 18:48:11 -07:00
Drew
a33ad93996 [apps] Thread structured icon assets through app list (#29889)
## Summary

- Add `iconAssets` and `iconDarkAssets` to the app-list protocol.
- Preserve structured icons through directory merging and the connector,
app-
  server, and TUI boundaries.
- Keep legacy logo URLs unchanged as compatibility fallbacks.
- Update generated protocol schemas and TypeScript types.
2026-06-24 13:25:44 -07:00
Brooks
5013d10824 [codex] suppress low usage remaining warnings when credits are available (#28593)
## Why

The TUI computed proactive `Heads up, you have less than ...` warnings
before considering workspace credits. As a result, users could see
included-limit warnings even when they could continue using Codex with
workspace credits.

`has_credits` alone is not sufficient to determine whether finite
credits are usable: a spend-control hard limit can cap the reported
balance to zero while `has_credits` still reflects the workspace's raw
balance. Unlimited credits are the opposite case: they are usable even
though no numeric balance is reported.

## What changed

- suppress proactive TUI rate-limit usage warnings and the lower-cost
model nudge when usable workspace credits are available
- treat credits as usable when `has_credits` is true and either
`unlimited` is true or the parsed balance is positive
- continue showing warnings when the usable balance is zero, including
when a spend-control limit has capped otherwise available workspace
credits
- add regression coverage for zero-balance, positive-balance, and
unlimited workspace-credit snapshots

## Validation

- `just test -p codex-tui rate_limit_usage_warnings_`
2026-06-24 18:43:17 +00:00
Adam Perry @ OpenAI
e639e8c4bd connectors: own app metadata types (#29723)
## Why

Connector metadata is consumed by connector discovery, ChatGPT
integration, core, and TUI code. Treating app-server's wire DTO as the
shared domain model reverses the intended dependency direction.

## What changed

- Added connector-owned app branding, review, screenshot, metadata, and
info types.
- Added explicit conversions in app-server and TUI while preserving
app-server's wire payloads.
- Removed production app-server-protocol dependencies from connectors
and ChatGPT connector code.

## Stack

This is PR 4 of 6, stacked on [PR
#29722](https://github.com/openai/codex/pull/29722). Review only the
delta from `codex/split-config-layer-types`. Next: [PR
#29724](https://github.com/openai/codex/pull/29724).

## Validation

- Connector and tools coverage passed.
- App-server app-list coverage passed: 13 tests.
2026-06-23 22:08:23 -07:00
Adam Perry @ OpenAI
1d65ccabd5 config: own layer provenance types (#29722)
## Why

Config layer provenance describes how effective configuration was
assembled, so it belongs with the config loader rather than in
app-server's serialized API types.

## What changed

- Moved `ConfigLayerSource`, `ConfigLayerMetadata`, and `ConfigLayer`
ownership into `codex-config`.
- Kept app-server's wire payloads unchanged and added explicit
conversions at the app boundary.
- Removed lower-level app-server-protocol dependencies from config
consumers.

## Stack

This is PR 3 of 6, stacked on [PR
#29721](https://github.com/openai/codex/pull/29721). Review only the
delta from `codex/split-auth-domain-types`. Next: [PR
#29723](https://github.com/openai/codex/pull/29723).

## Validation

- `codex-config` coverage passed.
- App-server config-manager and config RPC coverage passed.
2026-06-24 04:03:04 +00:00
Adam Perry @ OpenAI
510bce9927 core: resolve view_image paths in selected environment (#29526)
## Why

view_image needs to support foreign OS remote executors.

## What

- resolve image paths against the selected environment as `PathUri` and
read them through that environment's filesystem
- keep app-server's public path field wire-compatible as
`LegacyAppPathString`, with purpose-specific UI rendering
- cover relative and absolute target-native paths in the core
integration test and run the full `view_image` suite under wine-exec
without skips
2026-06-23 19:52:37 +00:00
Celia Chen
3310fc8ae5 chore: warn when Code Mode lacks model metadata (#29490) 2026-06-23 01:15:11 +00:00
canvrno-oai
fbd575ab4a TUI Plugin Sharing 4 - cover remote plugin catalog flows (#26704)
Remote plugin catalogs now span workspace, shared, and local sources, so
their TUI behavior needs focused regression coverage across loading,
navigation, actions, and refreshes.

This PR:

- Covers product labels and rendered loading/error states for Workspace,
Shared with me, Shared with me (link), and Local tabs, including tab
persistence across refresh and detail navigation.
- Covers remote/local deduplication, Installed-tab remote detail
routing, marketplace load-error handling, and disabled install/uninstall
navigation.
- Adds a full detail snapshot for local shared-plugin metadata plus
focused snapshots for marketplace labels and admin-disabled status.
- Verifies shared plugins remain eligible for mentions and successful
uninstalls trigger a catalog refresh.
2026-06-22 17:31:14 -07:00
Drew
2c351cb864 [plugins] Add dark-mode logo metadata (#29488)
Adds additive dark-mode plugin logo metadata across manifests, remote
catalogs, and the app-server protocol while keeping uninstalled Git
listings free of synthetic local paths.

Supersedes #28945. This replacement uses an upstream branch so trusted
CI can use the repository-provided remote Bazel configuration.

## Current state

Plugin interfaces expose only the default logo asset. Clients therefore
cannot select a dedicated dark-mode logo even when a plugin provides
one.

## What this PR changes

- Adds nullable `logoDark` and `logoUrlDark` fields to
`PluginInterface`.
- Resolves local `interface.logoDark` assets and maps remote
`logo_url_dark` values.
- Removes path-backed interface assets, including `logoDark`, from
uninstalled Git fallback listings until the plugin has a real local
root.
- Updates the bundled plugin validator and manifest reference.
- Regenerates the app-server JSON schemas and TypeScript types.

Local manifests expose `interface.logoDark` as a package-relative asset
path. Remote catalog responses expose `logo_url_dark`. These values map
into separate app-server fields so clients can preserve local-path and
remote-URL handling.

## Risk

The fields are additive and nullable, so existing clients retain their
current logo behavior. The main risks are an incomplete mapping path or
exposing a synthetic local path for an uninstalled Git plugin.
Local-manifest, remote-catalog, fallback-listing, protocol
serialization, and app-server integration tests cover those paths.

Spiciness: 2/5

## Testing

- `just write-app-server-schema`
- `just fmt`
- Regression test first failed with `logo_dark` resolved to
`/assets/logo-dark.png`, then passed after the fallback-listing fix.
- `just test -p codex-core-plugins` (267 tests passed)
- `just test -p codex-app-server 'suite::v2::plugin'` (114 tests passed)
- `just test -p codex-app-server-protocol -p codex-core-plugins -p
codex-plugin -p codex-skills` (517 tests passed before the follow-up)
- `just test -p codex-tui plugin` (47 tests passed)
- Validated a local plugin manifest containing `interface.logoDark` with
the bundled validator.

## Manual verification

Create a local plugin with both `interface.logo` and
`interface.logoDark`, then call `plugin/list` or `plugin/read`. Confirm
the response contains separate `logo` and `logoDark` paths. For a remote
catalog entry, confirm `logoUrlDark` is populated from `logo_url_dark`.
For an uninstalled Git marketplace entry, confirm path-backed interface
assets remain absent until installation.

Issue: N/A - coordinated maintainer change.
2026-06-22 16:01:27 -07:00
viyatb-oai
6db576895a fix(config): address permission profile review follow-ups (#29479)
## Summary

- rename `Config::permission_profile_allowed` to
`is_permission_profile_allowed`
- use `BUILT_IN_PERMISSION_PROFILE_DANGER_FULL_ACCESS` in the TUI and
its assertion
- follow up on the late review comments from #26678

The previous `:danger-no-sandbox` value was an invalid built-in profile
ID. #26678 corrected it to `:danger-full-access`; this PR centralizes
the value to prevent future drift.

## Testing

- Not run per request; `cargo fmt` only

Co-authored-by: Codex <noreply@openai.com>
2026-06-22 21:05:50 +00:00
viyatb-oai
ced3e4b9a7 permission profiles: expose availability to clients (#26678)
## Why

`permissionProfile/list` currently advertises every built-in and
configured profile even when effective enterprise requirements prevent
selecting it. That forces each client to reconstruct policy from
lower-level requirement fields, which is easy to miss and difficult to
keep consistent.

The catalog should remain complete so clients can explain that an option
was disabled by an administrator, while also reporting whether each
profile is selectable.

## What

- Add an `allowed` field to each permission profile summary.
- Build a shared catalog from the effective config and current
requirements, including `allowed_sandbox_modes`, `allowed_permissions`,
and filesystem restrictions.
- Use the shared catalog in app-server and the TUI so disallowed
profiles remain visible but cannot be selected.
- Use the canonical `:danger-full-access` profile ID in the TUI.
- Update the app-server schemas, API documentation, behavioral tests,
and TUI snapshots.

## Scope

This PR targets `main` directly and is independent of #24852. It
preserves the current behavior where built-in profiles are constrained
by sandbox-mode requirements and `allowed_permissions` applies to
configured profiles.

## Testing

- `just test -p codex-core
permission_profile_catalog_marks_profiles_disallowed_by_requirements`
- `just test -p codex-app-server permission_profile_list`
- `just test -p codex-app-server-protocol`
- `just test -p codex-tui profile_permissions`
- `just fix -p codex-core`
- `just fix -p codex-app-server-protocol`
- `just fix -p codex-app-server`
- `just fix -p codex-tui`
- `just fmt`

---------

Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Joey Trasatti <joey.trasatti@openai.com>
2026-06-22 13:48:09 -07:00
jay
5c0fbf3492 [codex] Fix usage-limit reset copy and state (#28793)
## Why

The reset flow introduced in #28154 still describes earned reset credits
as "rate-limit resets" and uses generic reset-scope copy. It can also
retain a stale available-credit count after redemption or an account
change, leaving the reset action enabled after the last credit is used.

This follow-up updates terminology only within that reset feature.
Existing rate-limit wording elsewhere in the CLI and TUI is unchanged.

## What changed

- Rename reset-specific `/usage` menu items, startup hints, and reset
dialogs to "usage limit reset."
- Describe monthly resets for Free, Go, and accounts that report a
monthly usage window; otherwise describe the current 5-hour and weekly
limits.
- Recheck a cached zero balance when `/usage` is reopened, and refresh
the balance after redemption so the final reset immediately disables the
action.
- Correlate async refresh results before updating snapshots and clear
account-derived reset state, warnings, prompts, and status surfaces when
the account changes.

## Validation

- `just test -p codex-tui chatwidget::tests::usage` — 29 passed.
- `just test -p codex-tui chatwidget::tests::status_command_tests` — 7
passed.
- Account-boundary prompt and plan-mode prompt regression tests passed.
- `cargo insta pending-snapshots` from `codex-rs/tui` — no pending
snapshots.\

<img width="814" height="318" alt="image"
src="https://github.com/user-attachments/assets/2a460e96-458b-4805-8d9f-c759382d21a4"
/>
view for monthly
<img width="905" height="243" alt="image"
src="https://github.com/user-attachments/assets/179f88e3-08fb-4af5-8dc6-ce6a944ed681"
/>
2026-06-22 18:45:41 +00:00
canvrno-oai
f6fa259312 TUI Plugin Sharing 3 - render remote plugin catalog sections (#26703)
## Summary

[#26701](https://github.com/openai/codex/pull/26701) added remote plugin
identity support, [#26702](https://github.com/openai/codex/pull/26702)
added remote-section fetching and state, and
[#28768](https://github.com/openai/codex/pull/28768) extracted the
catalog rendering module. This PR builds the product-facing `/plugins`
catalog on that foundation so remote records appear as OpenAI Curated,
Workspace, and Shared with me sections rather than backend marketplace
implementation details.

Plugin details remain read-only for sharing metadata. This PR does not
add share-authoring actions or change the app-server protocol.

## Changes

- Renders OpenAI Curated, Workspace, and Shared with me sections with
loading, empty, and error states.
- Preserves section selection and stable tab ordering as remote sections
transition between fallback and populated states.
- Shows OpenAI Curated loading only when the explicit vertical fallback
request was issued.
- Centralizes remote marketplace identity matching around the existing
marketplace constants.
- Uses product labels for remote marketplaces and identifies the
personal marketplace as Local by its path.
- Shows read-only source, authentication, version, and sharing metadata
in plugin detail views.
- Applies narrow display deduplication for local and remote records
sharing a remote plugin ID:
  - installed records take precedence;
- local mapped sources are preferred for details only when their
installed state matches the selected record.
- Returns from detail and confirmation views through the current plugin
cache so newly loaded remote sections are not overwritten by an older
captured response.
- Keeps admin-disabled plugins view-only and labels default-installed
plugins as Available by default.

## Tests

New tests:

- `plugins_popup_admin_disabled_available_plugin_has_view_only_hint`
- `plugins_popup_remote_section_fallback_states_snapshot`
-
`plugins_popup_installed_remote_row_keeps_remote_detail_when_local_share_is_uninstalled`

Updated existing plugin catalog tests and snapshots for product labels,
detail metadata, personal-marketplace labeling, and stable tab ordering.

Verification:

- `cargo clippy -p codex-tui --all-targets -- -D warnings`

## Follow-ups

- Local/remote duplicate normalization should eventually move into
app-server. This PR intentionally keeps the compatibility behavior
narrow and display-only.
- PR5 will sanitize sensitive components before displaying Git source
URLs.
2026-06-22 10:30:16 -07:00
xli-oai
21d36296f1 Add workspace messages app-server API (#29001)
## Summary

- Add backend-client types and fetch support for active workspace
messages.
- Add the app-server v2 `account/workspaceMessages/read` method,
generated schemas, and README documentation.
- Delegate workspace-message eligibility to the Codex backend feature
gate; map a backend 404 to `featureEnabled: false`.

## Testing

- `just write-app-server-schema`
- `just test -p codex-backend-client`
- `just test -p codex-app-server-protocol`
- `just test -p codex-app-server workspace_messages`
- `just fix -p codex-backend-client -p codex-app-server-protocol -p
codex-app-server`
- `just fmt`

## Stack

- Base PR for #28232, which adds the TUI status-line integration.
2026-06-22 04:25:07 -07:00
Francis Chalissery
566f7bf631 Propagate safety buffering events to app-server clients (#29371)
Responses API safety buffering metadata currently stops at the transport
boundary, so app-server clients cannot render the in-progress safety
review state.

This change:
- decodes and deduplicates `safety_buffering` metadata from Responses
API SSE and WebSocket events without suppressing the original response
event
- emits a typed core event containing the requested model plus backend
use cases and reasons
- forwards that event as `turn/safetyBuffering/updated` through
app-server v2 and updates generated protocol schemas
- keeps the side-channel event out of persisted rollouts and turn timing

This supports the Codex Apps buffering UX and depends on the Responses
API backend work in https://github.com/openai/openai/pull/1044569 and
https://github.com/openai/openai/pull/1044571.

Validation:
- focused `codex-core` safety-buffering integration test passes
- `cargo check -p codex-core -p codex-app-server -p
codex-app-server-protocol`
- `just fix -p codex-api -p codex-protocol -p codex-core -p
codex-app-server-protocol -p codex-app-server -p codex-rollout -p
codex-rollout-trace -p codex-otel`
- `just fmt`
- broad package test run: 4,430/4,492 passed; 62 unrelated
local-environment/concurrency failures involved unavailable test
binaries, MCP subprocess setup, and app-server timeouts
2026-06-22 03:39:14 +00:00
Eric Traut
d667082322 Allow resume and settings commands during tasks and MCP startup (#29154)
## Why

The TUI treats both an active turn and MCP startup as a running task.
That currently blocks `/resume` and several settings commands even
though they do not compete with turn execution, which is especially
frustrating when MCP startup is slow.

Model, permissions, personality, and service-tier selections already
update thread settings independently of the running turn. Other clients
can send those updates mid-turn, while the current turn continues with
its captured settings. Allowing the same updates from local slash
commands makes the TUI consistent with that existing behavior.

## What changed

- Allow `/resume` while a task is running.
- Allow `/model`, `/permissions`, `/personality`, and service-tier
commands such as `/fast` while a task is running.
- Keep the existing behavior where the active turn uses its captured
settings and updates apply to subsequent turns.
- Exercise the commands under the busy state in the existing TUI tests
and retain coverage for commands that should remain blocked.

## Behavior note

Turn settings such as model selection and reasoning effort are captured
when a turn starts. Changing them during an active turn affects the next
turn, not the turn already in progress. The status bar updates
immediately, so it may temporarily display the newly selected setting
before that setting is actually in effect.

## Verification

- Focused `codex-tui` tests for resume dispatch, settings popups,
`/fast`, and disabled-command behavior.

## Related issues

Closes #19015.

Addresses the next-turn-safe model/reasoning switching portion of
#14356; dedicated shortcuts and the proposed depth meter remain out of
scope.
2026-06-19 21:37:01 -07:00
Shijie Rao
7abfcf220b Expose thread-level multi-agent mode (#28792)
## Why

Once multi-agent mode can be selected per turn, clients also need to
choose the initial selection when creating a thread and observe that
selection through lifecycle and settings APIs.

The selected value is intentionally distinct from the effective
model-visible value: no client selection is represented as `null`, even
though an eligible multi-agent v2 turn derives `explicitRequestOnly` as
its effective default.

## What changed

- Add the optional experimental `thread/start.multiAgentMode` parameter
and pass it through thread creation.
- Preserve an omitted initial value as an unset selection rather than
eagerly storing `explicitRequestOnly`.
- Apply an explicit `thread/start` selection to the first turn through
the session configuration established at thread creation.
- Restore the latest persisted effective mode as the selected baseline
on cold resume when rollout history contains one.
- Inherit the optional selected mode from a loaded parent when creating
related runtime threads.
- Return the current selected `multiAgentMode` from `thread/start`,
`thread/resume`, `thread/fork`, and thread settings, using `null` when
no mode is selected.
- Keep lifecycle reporting independent from model capability and feature
eligibility; core turn construction remains responsible for calculating
and persisting the effective mode.

## Not covered

- Clearing an existing loaded-session selection back to unset through
`turn/start`; omitted or `null` currently retains the session's
selection.
- A TUI control, slash command, or `config.toml` preference.

## Verification

- `CARGO_INCREMENTAL=0 just test -p codex-app-server-protocol`
- `CARGO_INCREMENTAL=0 just test -p codex-app-server multi_agent_mode`

The focused app-server coverage verifies explicit `thread/start`
initialization, first-turn prompting, nullable reporting for an omitted
selection, and retention of selections that are not currently
runtime-eligible.

## Stack

Stacked on #28685. This PR contains only the thread initialization and
lifecycle/settings API layer.
2026-06-19 10:50:44 +02:00
Adam Perry @ OpenAI
dce673905a core: load AGENTS.md from foreign environments (#28958)
## Why

Make it possible to load AGENTS.md from remote exec-servers whose OS is
different than app-server.

## What

- keep `AGENTS.md` discovery and provenance as `PathUri`, with
root-aware parent and ancestor traversal
- expose lifecycle instruction sources as legacy app-server path strings
in events while retaining `PathUri` internally
- preserve and test mixed POSIX and Windows paths in model context and
TUI status output
- cover remote Windows loading end to end by seeding the Wine prefix
through host filesystem APIs
- fix bug in `PathUri`'s parent() implementation that would erase
Windows drive letters
2026-06-18 15:06:23 -07:00
martinauyeung-oai
765309d5a6 Emit Trusted MCP App Identity on Tool-Call Items (#27132)
## Summary

- Add optional `appContext` to app-server MCP tool-call items with
trusted `connectorId`, `linkId`, and `mcpAppResourceUri` metadata.
- Preserve that context across tool-call events, persisted history,
reconnects, and thread resume.
- Keep the deprecated top-level `mcpAppResourceUri` temporarily for
client migration.

The consumer contract is `{ appContext: { connectorId, linkId,
mcpAppResourceUri }, tool }`.

## Validation

- Full GitHub Actions suite passes, including CLA, Bazel tests, clippy,
release builds, and argument-comment lint.

---------

Co-authored-by: martinauyeung-oai <280153141+martinauyeung-oai@users.noreply.github.com>
2026-06-18 14:02:54 -07:00
rka-oai
f4602b7516 Add app-server current-time impl (varlatency 3/n) (#28835)
## What

Server should request:

```
{
  "id": 42,
  "method": "currentTime/read",
  "params": {
    "threadId": "11111111-1111-1111-1111-aaaaafdc2c11"
  }
}
```

Client should respond with something like:

```rust
{
  "id": 42,
  "result": {
    "currentTimeAt": 1781717655
  }
}
```

## Why

Sessions configured with `clock_source = "external"` need a
thread-specific external time source before inference. The system clock
remains the default production provider.

## Validation

- `cargo test -p codex-app-server-protocol`
- `cargo test -p codex-app-server --test all
current_time_read_round_trip_adds_reminder_to_model_input`
- `cargo test -p codex-app-server
first_attestation_capable_connection_for_thread_only_uses_thread_subscribers`
- `cargo test -p codex-analytics`
- `just fix -p codex-app-server-protocol`
- `just fix -p codex-app-server`

Stacked on #28824.
2026-06-18 13:12:11 -07:00
Gabriel Peal
21a599fa56 Support openai/form extended form elicitations (#27500)
# Summary
Allow App Server clients to opt into `openai/form` MCP elicitations.
2026-06-18 11:54:49 -07:00
Eric Traut
07298a948c Pause active goals before TUI interrupts (#28813)
Fixes #28104.

## Summary
Active `/goal` turns should leave the persisted goal paused whenever the
TUI interrupts the running turn. The bug in #28104 showed this most
visibly through `Esc`: some interrupt paths aborted the turn without
updating the goal status, so the goal could remain active and continue
automatically.

This change makes `ChatWidget` pause an active goal before the TUI sends
an interrupt from the status-row path, the pending-steer path, `Ctrl+C`,
or a request-user-input overlay. The modal overlay now reports whether a
key will interrupt the turn, which keeps modal `Esc` and `Ctrl+C`
behavior aligned with the normal interrupt paths.

## Manual Testing
Built the local CLI with `just codex --help`, then launched the local
TUI with goals enabled. Started an active `/goal` turn and interrupted
it with `Esc`, then resumed and repeated with `Ctrl+C`; both paths
showed `Goal paused`, the interrupted-conversation message, and the
`Goal paused (/goal resume)` footer. I also stopped the background
terminal and exited the TUI cleanly after the run.

I did not find a reliable standalone manual path to force the
request-user-input overlay case, so that path is covered by the focused
automated test.
2026-06-18 08:48:03 -07:00
Adam Perry @ OpenAI
3931bc2bde unified-exec: retain PathUri in command events (#28780)
## Why

App-server must report command events containing foreign-platform paths
without changing existing client or rollout path-string formats.

## What changed

- retain `PathUri` through exec command begin/end events
- convert cwd values to `LegacyAppPathString` at the app-server
compatibility boundary
- drop command actions with foreign paths and log them
- serialize rollout-trace cwd values using their inferred native path
representation
- restore Wine coverage for retained Windows cwd values and successful
completion
2026-06-18 05:00:04 +00:00
canvrno-oai
b668abb488 Extract TUI plugin catalog rendering (#28768)
This mechanically extracts the existing TUI plugin catalog and detail
popup rendering from `chatwidget/plugins.rs` into a new
`chatwidget/plugin_catalog.rs` module. `plugins.rs` now keeps the
stateful plugin workflow and orchestration, while `plugin_catalog.rs`
owns the presentation-heavy catalog/detail popup construction and its
pure helpers. The goal is to keep `plugins.rs` focused before later
plugin sharing work adds more catalog behavior.

- Moves existing catalog/detail popup builders and related pure helpers
into `plugin_catalog.rs`
- Leaves plugin fetch/state/key handling in `plugins.rs`
- Adds only minimal sibling-module visibility/import wiring
- Intentionally makes no product behavior or UI changes beyond the code
move
2026-06-17 11:57:19 -07:00
jif
1391d786bc Scope command approvals by execution environment (#28738)
## Why

Command approval cache keys included the command and working directory,
but not the execution environment. An approval for `/workspace` locally
could therefore be reused for the same command and path on an executor.

## What changed

- Include the selected environment ID in shell and unified-exec approval
cache keys.
- Carry that ID through the normal command approval request so clients
can show which environment is being approved.
- Expose the environment through app-server as a required nullable
`environmentId` and show it in the inline TUI approval prompt.
- Keep older recorded approval events compatible when the environment is
absent.

For example, `echo ok` in local `/workspace` and `echo ok` in executor
`/workspace` now produce different approval keys and separate prompts.

## Scope

This PR does not change network approvals, Guardian review actions, MCP
elicitation, full-screen TUI rendering, or environment-ID validation.
Remote `shell_command` execution itself remains in #28722; this PR only
makes its approval key environment-aware.
2026-06-17 19:52:43 +02:00
Adam Perry @ OpenAI
322b83de5e Clarify model-generated and legacy app path types (#28577)
## Why

`ApiPathString` kind of implies that it can be used anywhere we pull a
path out of JSON, but it's not really appropriate for tool arguments
when the model might generate relative paths.

Prefer `String` for model-generated paths and we can handle the
conversion per feature for now and define a shared abstraction later if
it makes sense.

# What

Rename `ApiPathString` to `AppLegacyPathString` to clarify its role.

Expand the `path-types` skill to tell the model to leave tool args as
bare strings.
2026-06-16 20:47:43 +00:00