Event-driven task panel refresh on exec_shell_cancel/exec_shell_wait/task_cancel plus an immediate refresh after ShellJob actions, so the Tasks sidebar reflects cancellations without waiting for the periodic refresh. Addresses #2937.
The <runtime_prompt> tag includes a visibility="internal" attribute that
was listed in the tag format but never explained. Models sometimes
interpreted this as an instruction to announce or restate the current
mode to the user, leading to repetitive YOLO-mode confirmations before
every tool call (#2922).
Add a one-sentence explanation: the attribute marks this tag as a
runtime instruction for the model (not user input), and the model should
apply the referenced rules silently without announcing the mode.
Closes#2922
Background shell task cancellation was unreliable because the Tasks
sidebar panel was not refreshed immediately after cancel actions.
Root cause:
- ShellJobAction::Cancel/CancelAll killed the process in ShellManager
but did not trigger a task_panel refresh, leaving stale "running"
entries until the next 2.5 s periodic poll.
- The tool-name refresh list at line 1734 missed exec_shell_cancel,
exec_shell_wait, and task_cancel.
Fix:
- Add refresh_active_task_panel() call after ShellJobAction dispatch.
- Add exec_shell_cancel, exec_shell_wait, task_cancel to the
immediate-refresh tool name list.
Tests:
- shell_manager_cancel_transitions_task_to_not_running
- task_panel_entry_roundtrips_status
Qwen 3.6 Plus already had full catalog/resolver/picker support. Add
dedicated provider-hinted resolution tests to close the remaining gap.
- Add qwen3_6_plus_resolves_to_canonical_on_openrouter test
- Add qwen3_6_plus_alias_qwen_dash_resolves test
- Both verify /model qwen3.6-plus resolves to qwen/qwen3.6-plus on OpenRouter
Tightens the experimental OpenAI Codex (ChatGPT) provider so the v0.8.55
gate is green.
- clippy: collapse 5 nested if/if-let blocks flagged by
clippy::collapsible_if into let-chains (oauth.rs env-override
resolution, responses.rs SSE delta handling). cargo clippy --workspace
--all-targets -- -D warnings is now clean.
- fmt: cargo fmt --all over the Codex/Together changes (the gate's
--check was failing, incl. a mangled "| ApiProvider::Ollama").
- default model: Config::default_model() now resolves to the Codex
default (gpt-5.5) for the Codex provider instead of leaking a DeepSeek
default_text_model the Responses backend rejects. The carve-out sits
after the explicit provider-scoped model block (so
[providers.openai_codex] model still wins) and before the
DeepSeek-validating path, which is unchanged. Adds a behavior test.
https://claude.ai/code/session_013cHWv5sR6XPnVWzfMP8uma
Verified live against the ChatGPT Codex backend (real codex login):
`exec --model gpt-5.5` through the openai-codex provider returns a correct
completion. Fixes found while getting there:
- Route the non-streaming path too. create_message only dispatched chat
completions; for OpenAI Codex it now drives the Responses stream and folds it
into a MessageResponse (handle_responses_message), so `exec` and other
non-streaming callers use the same wire path as the interactive stream.
- Present a non-browser User-Agent on the Codex path. The ChatGPT backend sits
behind Cloudflare, which served a JS challenge (HTTP 403) to our browser-like
"Mozilla/5.0 (compatible; codewhale/...)" UA. A codex_cli_rs UA passes.
- Always send `instructions` (Responses rejects empty instructions); fall back
to a minimal system prompt.
- Map reasoning effort onto the Codex-allowed set (none/minimal/low/medium/
high/xhigh); CodeWhale's "auto" has no equivalent and maps to medium.
- Send `Accept: text/event-stream`.
Antislop pass on the changeset:
- Inline the one-caller codex_access_token wrapper (config calls get_credentials
directly) and drop the one-caller credentials_present helper; both presence
checks now use auth_file_path().exists() consistently with the Kimi path.
- Remove dead stream-parser state (ToolCallState fields, unused response_id /
current_item_type / output_text / thinking_text accumulators).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Completes the in-progress OpenAI Codex provider and bumps the workspace to
0.8.55. Builds on the committed Together AI provider + model catalog work.
OpenAI Codex (ChatGPT) provider — experimental:
- Wire the previously-dead OAuth module into credential resolution. The TUI
config now resolves the access token via the Codex CLI login in
~/.codex/auth.json (env overrides OPENAI_CODEX_ACCESS_TOKEN/CODEX_ACCESS_TOKEN),
refreshing expired tokens synchronously via the OpenAI token endpoint —
mirroring the existing Kimi OAuth flow rather than introducing a new pattern.
- Send the ChatGPT backend's required headers from the Responses client
(chatgpt-account-id, OpenAI-Beta: responses=experimental, originator) and
stop duplicating the Authorization header already installed on the client.
- Fix the cli crate's non-exhaustive ProviderKind matches (compile blocker).
Consistency / de-slop pass (so the provider fits the whole app, not one path):
- has_api_key_for / active_provider_has_config_api_key now detect the Codex
OAuth login on disk, the same way they detect Kimi OAuth — a `codex login`
user is no longer reported as unauthenticated.
- Replace the bogus OPENAI_CODEX_API_KEY hint (which exists nowhere else) with
the real OPENAI_CODEX_ACCESS_TOKEN/CODEX_ACCESS_TOKEN in the auth-error and
picker surfaces.
- Drop dead state in the Responses stream parser (unused ToolCallState fields /
imports); tool-call data is streamed live.
- Update docs/PROVIDERS.md, config.example.toml, and the provider-metadata wire
test for the Responses wire format.
Release:
- Bump workspace + crates + npm package to 0.8.55; update CHANGELOG.md and
crates/tui/CHANGELOG.md.
Note: the live Responses round-trip has not been exercised against the
production ChatGPT backend in this environment; the provider ships as preview.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`pdf_extract::extract_text` uses an internal codepath that can hang on
certain PDF cross-reference tables or font encodings. The per-page
`extract_text_by_pages` path does not trigger this hang and produces
identical output when joined.
When `pages` is not specified, route through `extract_text_by_pages`
and join all pages instead of calling `extract_text`.
Fixes#2641.
The 1ms heartbeat timeout raced the synchronous touch()->cleanup()
gap on loaded CI runners (Windows scheduler can deschedule >1ms),
intermittently reaping the just-touched agent so cleanup() returned 1.
Widen the timeout to 50ms and the staleness sleep to 150ms to keep the
logic exercised without the timing race. Addresses CI flakiness under
the v0.9.0 stabilization gate (#2721).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Harvested from PR #2885 by @greyfreedom. Wires ask-rules into the
app-server and core ExecPolicyEngine (previously inert). Removes the
original PR's NeedsApproval arm that incorrectly allow-listed the
working directory as a network host.
Co-Authored-By: greyfreedom <11493871+greyfreedom@users.noreply.github.com>
Harvests 7 safe fixes from PR #2880 by @HUQIANTAO: tool-name hex-digit
guard, token-usage u32 clamp, read-file line usize::try_from, grep
context-lines cap, UTF-8 PDF trim, run_skill dedup, and
Volcengine/SiliconflowCn reasoning_content support. Excludes the
DeepSeek stream-stop change and the unwired prompt_persist module
(deferred for separate review).
Co-Authored-By: HUQIANTAO <58421104+HUQIANTAO@users.noreply.github.com>
Mechanical rustfmt of the runtime_prompt tests rewritten in PR #2874
(LeoAlex0). No logic change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
tokio::task::spawn_blocking requires a running tokio runtime, which
breaks tests that call hook functions outside a tokio context. Since
hooks are fire-and-forget (no JoinHandle needed), std::thread::spawn
is the correct choice.