Commit Graph

2473 Commits

Author SHA1 Message Date
Hunter Bown a9a91053fa Merge PR #2930 from idling11: Qwen 3.6 Plus resolution tests
Tests-only: cover qwen3.6-plus and qwen-3.6-plus alias resolution on OpenRouter. Related #2908.
2026-06-09 20:06:20 -07:00
Hunter Bown edadd1e6db Merge PR #2941 from idling11: sync task panel after background shell cancel
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.
2026-06-09 20:05:20 -07:00
Hunter Bown 0e3c4a3dd6 Merge PR #2898 from idling11: avoid PDF read hang via extract_text_by_pages
Fixes the pdf-extract full-document hang on certain xref tables/font encodings by using the per-page extraction path. Closes #2641.
2026-06-09 20:04:15 -07:00
Hunter Bown fb341a9460 Merge PR #2880 from HUQIANTAO: fix 9 bugs across tools, client, and commands
UTF-8 boundary panic in clean_pdf_text, SSE ContentBlockStop index, skills TOCTOU double-call, token-count truncation, strict 6-digit hex decode in from_api_tool_name, response-body read errors surfaced, context_lines clamp, u64→usize try_from in read_file, SiliconflowCn/Volcengine reasoning-content support.
2026-06-09 20:03:45 -07:00
Hanmiao Li a20fe2a0cd fix(tui): sync task panel state after background shell cancel (#2937)
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
2026-06-09 15:08:33 +08:00
Hunter B 356b632b85 chore(cnb): remove deprecated deepseek shim references 2026-06-08 22:46:00 -07:00
Hunter B b6604b431a chore(release): add v0.8.55 compare link, sync tui CHANGELOG 2026-06-08 22:40:53 -07:00
Hanmiao Li f356802f9b fix: remove duplicate #[test] and restore lost test attribute 2026-06-09 11:59:16 +08:00
Hanmiao Li 68164524b1 feat(model): complete Qwen 3.6 Plus support with dedicated tests (#2908)
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
2026-06-09 11:49:50 +08:00
Claude a2ae9a1acf fix(codex): satisfy clippy/fmt gate and default to gpt-5.5 for Codex
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
2026-06-09 00:03:42 +00:00
Hunter Bown 0f19c395d5 fix(codex): make the Responses provider work end-to-end + de-slop
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>
2026-06-08 16:40:58 -07:00
Hunter Bown b46f607d91 feat(providers): finish OpenAI Codex (ChatGPT OAuth) provider and cut v0.8.55
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>
2026-06-08 16:17:30 -07:00
Hunter Bown c13bc24805 feat(models): add Together AI provider and update model catalog for v0.8.55
- Add Together AI as a first-class provider (ProviderKind::Together)
  - Config block [providers.together], env TOGETHER_API_KEY/TOGETHER_BASE_URL/TOGETHER_MODEL
  - Default models: deepseek-ai/DeepSeek-V4-Pro, deepseek-ai/DeepSeek-V4-Flash
  - Base URL: https://api.together.xyz/v1
  - TUI ApiProvider::Together with picker, auth, and capability support
  - CLI auth list/status support

- Add model catalog entries:
  - Qwen 3.7 Max (qwen/qwen3.7-max on OpenRouter)
  - MiniMax 2.7 (minimax/minimax-2.7 on OpenRouter)
  - NVIDIA Nemotron 3 Ultra (nvidia/nemotron-3-ultra on OpenRouter)

- Update docs/PROVIDERS.md, docs/CONFIGURATION.md, config.example.toml
- Update check-provider-registry.py compatible surfaces
- Fix provider picker tests for new provider count

Closes #2906, #2907, #2910, #2912, #2913
2026-06-08 15:12:42 -07:00
Hunter B 9463266cb1 ci(web): make Cloudflare deploy manual 2026-06-08 08:33:26 -07:00
Hunter B 0854425dc6 ci(web): deploy public site from main 2026-06-08 08:30:00 -07:00
Hunter B 7344b88eac fix(web): sync frontend lockfile for CI 2026-06-08 08:28:10 -07:00
Hunter B 3d503a0a24 docs: bring public surface and npm-deferred install copy 2026-06-08 08:01:18 -07:00
Hunter B c4ff9e5345 fix(release): allow asset publication despite docker failure 2026-06-08 07:47:48 -07:00
Hunter B 533b0f5766 fix(release): regenerate Cargo.lock for 0.8.54 workspace versions 2026-06-08 07:00:50 -07:00
Hunter B 78ae354fa4 chore(release): merge v0.9.0-stewardship into v0.8.54
Includes Paulo's command parity and Gherkin E2E harnesses,
HUQIANTAO's concurrency/security fixes, LeoAlex0's runtime_prompt
slim, reidliu41's hotbar persistence, HarmonyOS scaffolding,
Whaleflow foundation crate, and all v0.9.0 stabilization work.
2026-06-08 06:54:09 -07:00
Hunter B edd28066e1 chore(release): v0.8.54 — benchmark harness runners, MiMo routing 2026-06-08 06:47:21 -07:00
Hanmiao Li 1721393b97 fix(pdf): use extract_text_by_pages to avoid hang on full-PDF reads
`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.
2026-06-08 15:27:14 +08:00
Hunter B f88528a5a3 test(subagent): de-flake touch_refreshes_stale_running_agent_heartbeat
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>
2026-06-07 10:49:36 -07:00
greyfreedom 17dbed13c7 feat(execpolicy): wire permissions.toml ask-rules into runtime
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>
2026-06-07 10:49:36 -07:00
Hunter B 4e3184eae9 fix(client): consume probe response body to return connection to pool
Harvested from PR #2884 by @ousamabenyounes. Drops the orphan
desktop tray.rs module (dead code, never wired) from that PR.

Co-Authored-By: Ben Younes <2910651+ousamabenyounes@users.noreply.github.com>
2026-06-07 10:49:36 -07:00
Hunter B e2b7d5e197 fix: harvest safe bug fixes from PR #2880
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>
2026-06-07 10:49:36 -07:00
Hunter B ab65495b0e Merge PR #2781 from punkcanyang: opt-in ghost-text follow-up suggestion 2026-06-07 10:21:01 -07:00
Hunter B 8d329a434c Merge PR #2869 from ousamabenyounes: list saved models from all providers in /model picker 2026-06-07 10:21:00 -07:00
Hunter B b39e00e72b Merge PR #2883 from HUQIANTAO: concurrency hardening (mutex recovery, join handles) 2026-06-07 10:21:00 -07:00
Hunter B 1a9549babd Merge PR #2881 from HUQIANTAO: log instead of swallowing errors 2026-06-07 10:21:00 -07:00
Hunter B 4caa28772b Merge PR #2882 from HUQIANTAO: security fixes in execution policy and approval mapping 2026-06-07 10:21:00 -07:00
Hunter B face4dc27a Merge PR #2877 from LeoAlex0: cache_inspect test spillover root 2026-06-07 10:21:00 -07:00
Hunter B a54d08f28d chore(fmt): rustfmt engine tests from PR #2874
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>
2026-06-07 10:10:11 -07:00
Hunter B 3619962507 Merge PR #2874 from LeoAlex0: slim runtime_prompt to minimal tag 2026-06-07 10:09:21 -07:00
Hunter B a42e9115b1 Merge PR #2873 from reidliu41: hotbar slot persistence 2026-06-07 10:09:21 -07:00
Hunter B 2c56f7761e Merge PR #2887 from aboimpinto: Gherkin acceptance E2E harness 2026-06-07 10:04:12 -07:00
Hunter B b0d9c3196b Merge PR #2878 from aboimpinto: Layer 2 command parity harness 2026-06-07 10:04:08 -07:00
Ousama Ben Younes 97f6e0b2e5 fix(tui): use sort_by_key to satisfy clippy::unnecessary_sort_by 2026-06-07 15:17:13 +00:00
Paulo Aboim Pinto c25f7af219 Address acceptance harness review feedback 2026-06-07 16:29:40 +02:00
Paulo Aboim Pinto d90031f06f Add Gherkin acceptance E2E harness example 2026-06-07 16:12:12 +02:00
huqiantao bdf7b15bd7 revert: use std::thread::spawn for fire-and-forget hooks
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.
2026-06-07 19:59:17 +08:00
huqiantao 5cab1517a4 fix: add tracing dependency to app-server crate
Required for tracing::error! in persist_config error handling.
2026-06-07 19:56:06 +08:00
huqiantao 5e761a616c fix: collapse nested if-let to satisfy clippy::collapsible_if lint 2026-06-07 19:55:38 +08:00
huqiantao 3c197d707b fix: add sse_task field to SseTransport test initializer
The test at line 4768 was missing the new sse_task field added to
SseTransport. Add a dummy tokio::spawn task for the test.
2026-06-07 19:48:09 +08:00
huqiantao 9aa71e24c0 chore: update Cargo.lock for tracing dependency in core crate 2026-06-07 19:47:36 +08:00
huqiantao 4dd0a47c05 style: apply cargo fmt formatting 2026-06-07 19:46:24 +08:00
huqiantao 265b8ee142 fix: add tracing dependency to core crate and apply cargo fmt
- Add tracing.workspace = true to crates/core/Cargo.toml
  (required for tracing::warn! in lib.rs:752)
- Apply cargo fmt formatting to engine.rs, mcp.rs, tool_execution.rs, config/lib.rs
2026-06-07 19:46:02 +08:00
huqiantao 186b5b463f style: apply cargo fmt formatting to tools/file.rs 2026-06-07 19:44:25 +08:00
huqiantao 27ca87251e fix: use Box<dyn Write + Send> for cross-platform tracing writer
Replace platform-specific std::os::unix::io::FromRawFd with
Box<dyn std::io::Write + Send> return type. This compiles on
Windows, macOS, and Linux without unsafe code.

The closure now returns a boxed writer that is either:
- The cloned file handle (success case)
- A reopened file handle (clone failed)
- stderr (last resort, prevents panic)
2026-06-07 19:35:59 +08:00
huqiantao 75593a0eac fix: address security review comments
1. Fix whitespace bypass in normalize_command (execpolicy/lib.rs:446)
   - Collapse internal whitespace to prevent 'git  status' bypassing 'git status'
   - split_whitespace().join(' ') normalizes all whitespace

2. Fix 'never'/'deny' approval mapping (app-server/lib.rs:287)
   - Map to AskForApproval::Never instead of OnRequest
   - 'never'/'deny' should forbid commands, not prompt for approval

3. Optimize prefix matching (execpolicy/lib.rs:355, bash_arity.rs:375)
   - Avoid format! allocation on every check
   - Use byte comparison for space boundary check
2026-06-07 19:35:20 +08:00