Merge current origin/main into #2257 and keep the rescue scoped to the balance statusline feature.
Credits #2257 by @HUQIANTAO and the carried #1970 balance work by @MoriTang.
The rescue gates startup, turn-complete, and provider-switch balance fetches on StatusItem::Balance, preserves current main Cargo metadata, and adds the missing Vietnamese balance label.
Add SiliconFlow as an additive OpenAI-compatible hosted provider across config, secrets, CLI, agent registry, TUI runtime, picker, and docs.
Credit: based in part on the SiliconFlow provider direction from #1864 by @qychen2001, extended here with broader registry, documentation, and test coverage on current main.
When the model invokes write/modify/delete tools, extract its preceding
text content as an 'intent summary' and pass it to the approval view.
This gives users context about why a change is being made before they
review what will change.
Changes:
- Add intent_summary field to ApprovalRequired event (events.rs)
- Extract model text from current_text_visible when write tools
are detected in the turn loop (turn_loop.rs)
- Add ApprovalRequest::new_with_intent constructor with
intent_summary parameter (approval.rs)
- Pass intent_summary through TUI event handler to approval view
(ui.rs)
- Render intent summary in approval widget: up to 3 lines of the
model explanation, truncated to available card width, with
i18n labels for zh-Hans locale (widgets/mod.rs)
- Adapt existing tests to new event field (runtime_threads.rs,
ui/tests.rs)
Design decisions:
- Non-blocking: if the model provides no explanation, the approval
still proceeds normally (no extra round-trip or token cost)
- Backward compatible: YOLO mode and approval cache unaffected
- The new() constructor is gated behind #[cfg(test)] since
production code now uses new_with_intent()
New `/purge` command lets the agent surgically remove or rewrite
conversation history via a purge_context tool call. The engine
validates and applies the operations, cascading tool-result removal
to the paired tool-use call.
The whale-route fallback in the picker constructor used show_custom_model_row
as the gate for selecting the 'auto' vs custom row, but a known DeepSeek model
(e.g. v4-pro) paired with ReasoningEffort::Auto would not match any whale route
yet still have show_custom_model_row=false — silently landing on the auto row
and replacing the explicit model with 'auto' on apply.
Key the fallback on whether the initial model is actually 'auto' instead.
When a whale-route fallback selects the custom row, ensure show_custom_model_row
is set to true so the row is visible in the picker UI.
Also:
- Add regression test: known-model + Auto effort must not fall to auto row.
- Clean up picker_auto_model_forces_auto_effort_on_apply: remove manual
mutations of selected_model_idx / selected_effort_idx which whale-route
mode never reads.
- Rename Porpoise → Beluga per #2016, which excludes porpoises from the
user-facing whale pool.