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.
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
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.
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.
The header bar was reported to appear vertically centered on macOS
Terminal.app with large blank space above and below. While the existing
Constraint::Min(1) layout with default Flex::Start should place the
header at row 0, some ratatui/flex interactions can produce unexpected
centering on certain terminal sizes.
Restructure the render layout into a defensive two-pass system:
1. First pass: split the terminal into header (Length(1)) + body (Min(1))
with explicit Flex::Start, pinning the header to the absolute top.
2. Second pass: split the body area for chat, preview, composer, footer.
This guarantees the header is never vertically centered regardless of
ratatui Flex defaults or terminal dimensions.
Fixes#1834
EngineConfig.instructions was Vec<PathBuf>, which forces embedders that
compute instructions at runtime to stage content to a disk file just to
satisfy the path API. That has two awkward side-effects:
1. The disk file looks like editable config but gets overwritten on
every launch, confusing for users browsing the install dir.
2. Multi-engine setups need per-engine paths to avoid `rehydrate`
re-reading the wrong session's content across concurrent engines.
Add an `InstructionSource` enum (`File(PathBuf)` / `Inline { name,
content }`) covering both shapes. `render_instructions_block` dispatches:
File sources read disk (original behavior preserved), Inline sources use
the content directly with `name` becoming the `<instructions source=...>`
attribute.
`From<PathBuf> for InstructionSource` is provided so the existing CLI /
runtime call sites upgrade with a single `.into_iter().map(Into::into).
collect()` chain — no behavior change for callers passing paths.
New test `render_instructions_block_handles_inline_source` covers Inline
empty / oversize-truncate / File+Inline mixed-ordering. The 5 existing
`render_instructions_block_*` tests are updated to use `.into()` on
`PathBuf` and continue to assert File-variant behavior.
Deduplicate failures per tool name, clear stale failures when
the same tool succeeds, and cap visible failures at 2 so old
failures don't crowd the sidebar after the task moves on.