Adds native xiaomi-mimo provider configuration, auth/env aliases, model registry entries, TUI request handling, tests, and docs. Keeps credentials in existing provider-scoped config/env/keyring paths and uses placeholders only in docs.
Resolve the prompt-layer conflict by keeping the core tool taxonomy block while routing base prompt composition through the override accessor. Tighten the override API so duplicate registrations return the rejected string, and make locale preamble/closer overrides symmetric across supported bookend locales.
Route user cells in the transcript cache through the existing user-message renderer.
The live chat view renders through lines_with_copy_metadata(), which previously
bypassed the user-message highlight path. As a result, submitted user prompts did
not show the intended full-row background in the main transcript.
Add a regression test for the transcript cache path.
The second feature-flag gate in tool_setup.rs was calling
with_shell_tools() again when allow_shell was already true, causing
duplicate tool registration. Remove the redundant gate since
with_agent_tools() already handles the allow_shell check.
Also add task_shell_wait to MODES.md alongside task_shell_start.
task_shell_start delegates to ExecShellTool, providing the same shell
execution capability as exec_shell. Previously, task_shell_start was
registered unconditionally in with_runtime_task_tools while exec_shell
was gated behind allow_shell, creating an inconsistent security gate.
This caused the model to try exec_shell first, fail, then fall back to
task_shell_start — wasting tokens and bypassing the intended security
boundary.
Split TaskShellStartTool and TaskShellWaitTool out of
with_runtime_task_tools into a new with_runtime_task_shell_tools method,
and gate both behind the allow_shell check in with_agent_tools.
Closes#2303
Two bugs in the folded-thinking rendering path:
1. Cache invalidation: changing folded_thinking did not invalidate cached
cell renders because the cell revision stayed the same. Now track
folded_cells in the cache and force re-render when it changes.
2. Index mapping: in the slow path (with collapsed cells), the cache idx
is a filtered position, but folded_cells uses original virtual indices.
Add original_index_map parameter to ensure_split so fold lookups
resolve correctly.
Added two regression tests:
- folded_thinking_cache_invalidation: verifies fold/unfold triggers re-render
- folded_thinking_with_collapsed_cells_uses_original_indices: verifies
correct fold behavior when collapsed_cells filtering is active
Change from to so Space
toggles the collapsed state relative to the global verbose flag:
- verbose off (default): thinking collapsed; Space unfolds it
- verbose on: thinking expanded; Space folds it
This lets users expand individual thinking blocks even when the global
verbose mode is off, without needing to toggle verbose for all blocks.
Closes#2074
Adds FauxStep::Factory(Box<dyn Fn(&MessageRequest) -> CannedTurn + Send + Sync>)
to MockLlmClient. When a Factory step is dequeued, its closure runs
against the real outgoing MessageRequest before the response stream is
built, so any assert! panic surfaces directly from the client call
instead of later in stream polling.
Internal storage moves from VecDeque<CannedTurn> to VecDeque<FauxStep>,
but every existing public method keeps working:
- MockLlmClient::new(Vec<CannedTurn>) wraps each turn in FauxStep::Canned.
- push_turn(CannedTurn) appends as FauxStep::Canned.
Adds push_factory(closure) for tests that want the Factory branch.
Doc comment on the Factory variant captures the DeepSeek V4
thinking-mode tool-call invariant (the v0.4.9-v0.5.1 reasoning_content
drop that produced HTTP 400 on follow-up turns).
Adds:
- crates/tui/tests/reasoning_content_replayed_after_tool_call.rs — a
regression test whose factory asserts the assistant tool-call turn
carries a Thinking content block after a thinking + tool-call round.
- An additional unit test in mock.rs covering create_message_synthesizes_from_factory_turn.
All 20 tests in the new file pass, and the existing
integration_mock_llm suite (27 tests) is unchanged.
Previously, Space on a thinking cell hid it entirely from the transcript.
Now Space toggles between folded (summary preview) and unfolded (full
content) for thinking cells, while other cells retain the existing
hide/show behavior.
Changes:
- Add folded_thinking HashSet to App for per-cell fold tracking
- Add lines_with_options_folded / lines_with_copy_metadata_folded that
accept an explicit folded flag, overriding the global verbose setting
- Update transcript cache to pass fold state during rendering
- Update Space key handler to toggle fold for thinking cells
- Update affordance text to mention Space for expanding folded thinking
Closes#2348
Adds riscv64 to build pipelines so CodeWhale ships prebuilt binaries
and npm wrappers for 64-bit RISC-V Linux (glibc) systems.
Changes:
**CI / build**
- release.yml: +2 build matrix entries (codewhale + codewhale-tui for
riscv64gc-unknown-linux-gnu), cross-compilation toolchain step using
a dedicated DEB822-format apt source for ports.ubuntu.com, bundle
step, and release-notes table row.
- nightly.yml: +2 matrix entries, matching cross-compilation setup.
- resolve job: handle workflow_dispatch when the target tag does not
yet exist (fall back to HEAD SHA).
**Packaging**
- npm/codewhale/scripts/artifacts.js: add riscv64 to ASSET_MATRIX
under linux so npm install -g codewhale resolves on RISC-V.
**Docs**
- docs/INSTALL.md: add riscv64 row to supported platforms table;
replace with clearer 'other architectures' wording.
Build strategy: cross-compile from ubuntu-latest (x86_64) using
gcc-riscv64-linux-gnu. The dbus runtime dependency (from the keyring
crate's secret-service backend) is satisfied via ports.ubuntu.com.
PKG_CONFIG_ALLOW_CROSS and a cross-target libdir are set so the
keyring crate finds dbus-1 during cross-compilation.
Docker support for linux/riscv64 is intentionally not added here:
GitHub Actions does not yet provide the infrastructure to build or
emulate riscv64 containers. The Dockerfile changes will follow when
the hosted CI surface supports it.
Clearing active_turn immediately breaks is_interrupt_requested detection
in monitor_turn, causing turn status to be Completed instead of Interrupted.
Let monitor_turn handle the cleanup after it detects the interrupt flag
and performs full finalization with correct status, usage, and error.
- Change 'not loaded' to 'not found' in submit_user_input and
cancel_user_input so map_thread_err correctly maps to 404
- Use map_thread_err in submit_user_input API endpoint for
consistent error response (404 for missing thread, 409 for
conflict, etc.) instead of always returning 500
The monitor_turn loop already handles full turn finalization when the
engine shuts down after cancellation, including saving turn status,
usage, error, emitting turn.completed, and clearing active_turn.
Having interrupt_turn also save turn status and emit turn.completed
causes duplicate SSE events and loses usage/error data that
monitor_turn would have captured from TurnComplete.
Keep only the active_turn cleanup so the 409 error is resolved while
monitor_turn remains the single source of truth for turn completion.
Add SSE event forwarding for UserInputRequired, REST endpoint for submitting user input responses, timeout protection for await_user_input, and fix interrupt_turn to clear active_turn immediately.
The DNS-resolution SSRF guard in `validate_dns_resolved_ip` rejects any
hostname that resolves into a restricted IP range. Under a transparent-proxy
/ TUN setup running in `fake-ip` mode, the local resolver maps *every*
hostname to a reserved placeholder range (commonly `198.18.0.0/15`), so the
guard rejects all outbound `fetch_url` requests even though the proxy will
route them correctly.
Add a narrowly-scoped, opt-in trust list on `NetworkPolicyDecider`:
- `with_trusted_fakeip_cidrs(&["198.18.0.0/15"])` registers IPv4 CIDR ranges
to treat as benign fake-ip placeholders (default: empty — no behavior
change unless the embedder configures it).
- `is_trusted_fakeip_addr(ip)` matches only those configured ranges.
`validate_dns_resolved_ip` now allows a resolved IP if it is either in a
configured fake-ip range or the host is on the existing trusted-proxy list.
Real private/loopback/link-local/cloud-metadata IPs match neither and stay
blocked, so this does not widen SSRF exposure for default configurations.
Includes CIDR parsing/containment helpers and a unit test covering the
placeholder-allowed / real-private-blocked / nothing-configured cases.
Bing wraps every SERP result URL in a `/ck/a?...&u=<base64>` click-tracking
redirect, and in the raw HTML the separators are `&` entities.
normalize_bing_url parsed the href without decoding entities first, so
extract_query_param looked for `u` while the actual key was `amp;u`. The
base64 redirect target was never recovered: every result collapsed to a
`bing.com` root domain, is_likely_spam_results rejected the whole batch,
and Bing — the default backend — returned zero results.
Decode HTML entities before extracting the redirect target. Adds a
regression test.