Refs #1722
Preserves auto_compact as opt-in, adds the saved threshold setting, keeps the 500K hard floor, and wires Ctrl+L as a manual compaction shortcut for context-pressure recovery.
Harvested from PR #1723 by @aboimpinto
Co-authored-by: Paulo Aboim Pinto <aboimpinto@gmail.com>
Remove unneeded return in utils.rs (crates/tui/src/utils.rs:256) that was caught by clippy on the new commit. Also run cargo fmt to satisfy format checks.
- Remove ToolCallBefore observer firing from tool_routing.rs (the turn-loop gate now handles it) to prevent double-firing hooks for each tool call (greptile P1).
- Wrap hook_executor.execute() call in tokio::task::spawn_blocking so the Tokio worker thread is not blocked by child.wait_timeout() during hook execution (greptile P1).
Override `supports_parallel()` to return `true` in `WebSearchTool`,
allowing the engine to batch multiple concurrent web_search calls
into a `FuturesUnordered` parallel group instead of serializing them.
The tool is already read-only, auto-approved, and non-interactive —
parallel-safe by all other criteria. This change removes the final
gate (`supports_parallel() -> false` default) so co-issued searches
run concurrently rather than one-at-a-time.
Closes the ~55s serial wall-clock for 3 simultaneous web searches
(now ~20s, the slowest individual call).
Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit a7dcf63c556268b53ff430747ae2e141e4cd4451)
When MCP servers return tool schemas, the field order within each schema
object and the order of entries in required / dependentRequired arrays
can vary across reconnections. This causes the serialized tool catalog
bytes to change even when the logical schema is unchanged, busting
DeepSeek's KV prefix cache.
Add schema_canonicalize::canonicalize_schema which recursively:
- Sorts every required array alphabetically
- Sorts every dependentRequired sub-array alphabetically
- Rebuilds object keys in alphabetical order
- Recurses into all nested objects and arrays
The canonicalize step runs after schema_sanitize in build_api_tools,
so each tool's input_schema is first cleaned then byte-stabilized.
The existing OnceLock api_cache pins the result, ensuring the tool
catalog bytes are identical across reads and across process restarts.
8 unit tests cover: required sorting, dependentRequired sorting,
equivalent-ordering byte match, recursive nesting, empty schemas,
deeply nested schemas, non-required array preservation, and key
ordering.
(cherry picked from commit 7cee9cd5e12a74e8072bf2f6a1b18555ed0db0bf)
Addresses chatgpt-codex review: the previous full serde_json::to_string
included internal-only fields (allowed_callers, defer_loading,
input_examples, cache_control) that are never sent to the chat API.
This caused spurious drift detection when those fields changed.
- New tool_to_api_json() helper mirrors tool_to_chat() serialization:
only type, name, description, parameters, strict
- Doc comment fixed: 'sorted by name' → 'sorted lexicographically
by JSON text' (greptile review)
Phase 1.5 — upgrade PrefixFingerprint::compute() to hash the full tool
JSON serialization (name + description + schema) instead of just tool
names. This catches schema/description drift in addition to name changes.
- Serialize each tool via serde_json::to_string, sort by name, join
- New test: fingerprint_detects_schema_change_not_just_name_change
- All 21 prefix_cache tests pass
- Aligned with prompt_zones.rs tool_catalog_digest approach
Treat a missing tui.status_items field as None even when the [tui]
table exists, preserving the documented default footer behavior.
Add a regression test for configs that define [tui] without status_items.
with_agent_tools() unconditionally registered web_search/fetch_url/web.run
(via with_web_tools) and apply_patch (via with_patch_tools), but tool_setup.rs
conditionally registered them again based on Feature::WebSearch and
Feature::ApplyPatch flags. This caused double registration (overwritten
with a warning log on the second insert).
Changes:
- Remove with_web_tools() and with_patch_tools() from with_agent_tools()
- Move finance tool out of with_web_tools() into its own with_finance_tool()
(finance is market data, not web search — it should not be gated behind
the web-search feature flag)
- Add with_finance_tool() to with_agent_tools() so finance stays always
available
- Update tests: new test for with_finance_tool(), updated web_tools test
to verify finance is no longer in the web group