feat: AI-native 统一工具架构(Agent 工具调用 · MCP 三层 · 流式 · 记忆) - #2
Open
yolopunk wants to merge 18 commits into
Open
Conversation
Connect the previously-dormant MCP layer to the AI chat so the agent can
actually invoke tools. Adds a backend tool-calling loop and exposes it via
Tauri commands.
Backend:
- New api/ai_chat/agent.rs: MCP server registry (hosts), tool-definition
conversion for OpenAI/Anthropic, an agent loop that runs function calling
until the model produces a final answer, and per-step events emitted on
`agent-event-{request_id}` for the trace panel.
- Register agent_chat, mcp_list_tools, mcp_call_tool in the invoke handler.
- Add ModelProviderManagerState::get_credentials to resolve API key/endpoint.
- Unit tests for tool listing, tool->server mapping, and schema conversion.
Frontend:
- api/ai-chat.ts: agentChat / mcpListTools / mcpCallTool wrappers plus
AgentEvent types.
- stores/aiChat: when MCP servers are enabled, route sendMessage through the
agent loop, collect trace events, and expose agentTrace state.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013ryGEgpqp9hChcXFpsqVRo
Generated by the Tauri build on Linux, matching the already-tracked macOS/windows/desktop capability schemas. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ryGEgpqp9hChcXFpsqVRo
- New AgentTrace.vue: terminal-style live log of the agent tool-calling loop (think / call / result / answer / error), matching the existing sci-fi console aesthetic with a light-theme variant. - Right panel becomes tabbed (SESSIONS / TRACE); auto-switches to TRACE when agent activity starts and shows a step-count badge. - Left SKILLS panel toggles now sync to the store's MCP servers, so enabling HOSTS_MGR actually activates the agent tool-calling loop; initial states are synced from the store on mount. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ryGEgpqp9hChcXFpsqVRo
Design spec for making Jedi AI-native without over-using MCP: a single AgentTool abstraction with three sources — native in-process tools (primary), MCP client for third-party servers (optional), and MCP server export (strategic). Covers tool registry, risk-tiered human confirmation with diff preview/undo, third-party MCP trust model, provider adaptation, frontend config UI, Tauri command surface, a migration path from the current pseudo-MCP hosts dispatch, and a phased rollout. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ryGEgpqp9hChcXFpsqVRo
Address architecture review findings:
- R1: tool names use underscores (function-calling names must match
^[a-zA-Z0-9_-]{1,64}$; dots/colons are rejected). Structured source
and UI group moved off the LLM-facing name.
- R2: new §7.1 suspendable loop — backend-hold confirmation via a
PendingConfirmations oneshot map, tool_confirm/agent_cancel commands,
timeout and cleanup; agent_chat becomes a long-running task.
- Y1: §7.2 snapshot consistency — dry_run emits a snapshot token, call
verifies the resource is unchanged before writing.
- Y2: AgentTool gains dynamic_risk to escalate by args.
- Y3: §6.1 tool-subset injection to handle tool bloat.
- Y4: per-turn undo stack instead of single undo token.
- §14 open questions converged with recommended defaults.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013ryGEgpqp9hChcXFpsqVRo
Introduce src-tauri/src/tools: AgentTool trait, ToolRegistry (managed state), RiskLevel/ToolSource/ToolDeclaration/ToolOutcome/ToolFilter. Migrate the six hosts tools off the pseudo-MCP HostsMcpServer into native in-process AgentTool implementations, reusing api::hosts read/write logic. agent.rs now dispatches through ToolRegistry instead of HostsMcpServer; tool-declaration conversion (OpenAI/Anthropic) consumes ToolDeclaration. Commands mcp_list_tools/mcp_call_tool replaced by tool_list_all/tool_call. Tool names use underscores (function-calling name rule). Registry wired in main.rs via with_builtins(). Behavior unchanged — pure refactor. Frontend api wrappers renamed to toolListAll/toolCall with ToolDeclaration /ToolOutcome types. 12 backend unit tests pass; vue-tsc clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ryGEgpqp9hChcXFpsqVRo
Hosts tools gain safety features: - dynamic_risk escalates Write→System when a sensitive domain (microsoft.com, apple.com, github.com, ...) is targeted - dry_run produces a diff preview + a content-hash snapshot token - call verifies the snapshot before writing (rejects on external change) - undo restores the pre-write snapshot; writes push an undo token New api/ai_chat/confirm.rs (R2 approach A): - PendingConfirmations: oneshot map keyed by request_id::call_id; register/resolve/cancel/clear - UndoStacks: per-request undo stack - ConfirmMode (auto/normal) + should_confirm tiering - commands: tool_confirm, agent_cancel, turn_undo, tool_undo agent.rs loop is now confirmation-aware via ExecCtx: Write/System tools emit a ConfirmRequest event and suspend on a oneshot (120s timeout → reject) before executing; approvals may edit args; successful writes push to the undo stack; cancel short-circuits the loop. agent_chat takes optional confirm_mode/auto_approve and manages PendingConfirmations/ UndoStacks state. 28 ai_chat unit tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ryGEgpqp9hChcXFpsqVRo
Add app-handle-backed native tools so the agent can operate the whole product, not just hosts: - system_info (read) - wallpaper_list / wallpaper_current (read), wallpaper_set (write) - podcast_subscriptions / podcast_episodes (read), podcast_subscribe / podcast_unsubscribe (write) A global AppHandle (OnceLock) is injected in Tauri setup so these tools can reuse the existing api::wallpapers/podcast/os commands. Write tools route through the P2 confirmation loop automatically. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ryGEgpqp9hChcXFpsqVRo
AgentTrace panel now renders the full confirmation flow: - confirm_request events become interactive cards with a risk badge (read/write/system), a diff preview, and Approve/Reject buttons wired to tool_confirm; decided state is shown inline - tool_result rows expose an inline Undo button when an undo_token is present (single-step rollback) Store gains agentRequestId + confirmMode and confirmTool/cancelAgent/ undoTool/undoTurn actions; agent_chat is invoked with confirmMode. The tool groups shown in the skills panel now match the real native groups (hosts/wallpaper/podcast/system); the abort button cancels the running agent loop. vue-tsc + vite build clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ryGEgpqp9hChcXFpsqVRo
Backend (mcp/manager.rs):
- McpManager (managed state) connects external stdio MCP servers by
wrapping the existing synchronous McpClient; blocking calls run on
spawn_blocking threads
- McpClientTool adapts each remote tool into an AgentTool and registers
it in the ToolRegistry under a function-call-safe name
(mcp_<server>_<tool>); source=Mcp{server_id, remote_name}
- third-party tools default to Write risk (trust boundary → confirmation)
- commands: mcp_connect, mcp_disconnect, mcp_list_connected,
mcp_server_test; disconnect unregisters tools and drops the client
(child process stopped on drop)
Frontend:
- api wrappers + McpServerConfig/McpServerStatus types
- store persists third-party server configs (localStorage), tracks
connected ids, and includes them in the agent's enabled tool set
- ChatSettingsTab gains a section to add/connect/disconnect stdio MCP
servers
Note: SSE transport is rejected for now (stdio only); live connection to
a real MCP server is not exercisable in this sandbox. Unit tests cover
name mangling, result flattening, and config validation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013ryGEgpqp9hChcXFpsqVRo
`jedi --mcp-server` runs a headless stdio MCP server (no GUI) that exposes Jedi's read-only native tools to external agents (Claude Desktop, Cursor). Implements initialize / tools/list / tools/call over line-delimited JSON-RPC, reusing the ToolRegistry. Per the §14 trust decision only read-only, AppHandle-free tools are exported (hosts_read, hosts_list); write tools are never exposed. Notifications are ignored; unknown methods return -32601. Verified end-to-end: initialize returns the handshake, tools/list returns the two read tools, tools/call hosts_read returns live hosts data, and bogus methods are rejected. Unit tests cover the export registry, tool conversion, and request handling. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ryGEgpqp9hChcXFpsqVRo
Add a minimal stdio JSON-RPC mock MCP server fixture (python) and an integration test that drives the real synchronous McpClient through start_client: spawns the subprocess, performs the initialize handshake, lists tools, and calls the echo tool — asserting the flattened result. This exercises the third-party MCP connection path end-to-end (the piece that couldn't be verified without an external server). The test skips gracefully if python3 is unavailable, so it never fails spuriously. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ryGEgpqp9hChcXFpsqVRo
Introduce a sync Transport trait (stdio/sse share it) and make McpClient transport-agnostic via Box<dyn Transport> + McpClient::with_transport. New SseTransport implements the MCP 2024-11-05 HTTP+SSE transport with reqwest blocking: opens the GET event-stream, resolves the `endpoint` event, POSTs JSON-RPC requests, and matches responses pushed back over the stream (background reader thread + condvar, per-request timeout). Relative endpoints are resolved against the SSE origin; auth headers are forwarded. The manager's start_client now branches stdio/sse from the server config (url/headers added). Frontend: MCP server add-form gains a stdio/sse transport selector and a URL field; McpServerConfig carries url/headers. Verified end-to-end against a mock HTTP+SSE MCP server (python): initialize → tools/list → tools/call echo over the full round trip, alongside the existing stdio e2e test. 40 mcp tests pass; vue-tsc + vite build clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ryGEgpqp9hChcXFpsqVRo
Companion fixture for the SSE end-to-end integration test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ryGEgpqp9hChcXFpsqVRo
When the selected model does not support function calling, skip tool injection and run as plain chat instead of erroring. - agent_chat gains an optional supports_tools flag; Some(false) clears the tool set and emits a Notice event - frontend resolves the flag lazily from models.dev (tool_call), cached per model; unknown → undefined → tools injected as before (safe default) - AgentTrace renders the Notice row Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ryGEgpqp9hChcXFpsqVRo
Both provider loops now stream. Each turn is requested with stream:true; SSE deltas are parsed incrementally and content pieces are pushed to the frontend as content_delta events, while tool_calls are assembled from the same stream and drive the existing tool loop. - OpenAiStreamAcc: accumulates content + indexed tool_calls (id/name/ argument fragments), detects finish_reason/[DONE] - AnthropicStreamAcc: accumulates content blocks; text_delta streams, input_json_delta assembles tool_use input; reconstructs the assistant content array on message_stop - frontend appends content_delta to streamingContent (not into the Trace) and renders a live assistant bubble while streaming; the plain "PROCESSING" indicator shows only before the first token Unit tests cover both accumulators (content streaming + fragmented tool-call/tool-use assembly). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ryGEgpqp9hChcXFpsqVRo
When running in agent mode (tools present) and no system message exists, prepend a configurable agent system prompt that shapes behavior: briefly plan multi-step tasks, respect confirmations (don't retry on rejection), validate tool args, use memory when available, summarize concisely. An optional system_prompt param overrides the default. Hitting MAX_ITERATIONS now emits a Notice + Done and returns a graceful message instead of erroring out. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ryGEgpqp9hChcXFpsqVRo
Add a "memory" native tool group so the agent can remember user preferences and common configs across sessions: - memory_save / memory_recall / memory_list / memory_delete - persisted to ~/.jedi/agent_memory.json (key/value) - classified Read-risk (touches only Jedi's private store, never the system) so remembering/recalling is friction-free (no confirmation) The agent system prompt already tells the model to use memory when available. Exposed as a tool group in the store and skills panel. Path-parameterized core ops are unit-tested (save/recall/list/delete). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ryGEgpqp9hChcXFpsqVRo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述
把 Jedi 的 AI 能力从"多一个聊天页"推进到 AI-native:Agent 能安全地操作整个产品、接入 MCP 生态、也能对外输出,并具备流式、降级、规划与跨会话记忆。核心是一套统一工具架构——Agent 只依赖一个
AgentTool抽象,MCP 只是它的一个来源/出口,而非唯一入口。设计文档:
docs/ai-chat/05-unified-tool-architecture.md(含评审后的 v1.1 修订)。架构:一个抽象,三种来源
分阶段改动
基础:统一工具架构(P1–P4)
src-tauri/src/tools/:AgentTooltrait、ToolRegistry、RiskLevel/ToolDeclaration/ToolFilter;hosts 从伪-MCP 迁为进程内原生工具;agent.rs改走ToolRegistry;工具名统一下划线命名PendingConfirmationsoneshot +UndoStacks):Write/System 工具执行前dry_run预览并挂起等待前端确认(120s 超时);hosts 敏感域名动态升级为 System、写前快照校验、写后可回滚;新增 wallpaper/podcast/system 原生工具;前端确认卡片 + 撤销 + 取消AgentTool注入注册表(默认 Write 风险=需确认);前端 server 配置管理 UIjedi --mcp-server无头 stdio 模式,暴露只读原生工具传输:stdio + SSE
Transporttrait,McpClient支持Box<dyn Transport>SseTransport(MCP 2024-11-05 HTTP+SSE,reqwest blocking + 后台读取线程);前端 server 表单支持 STDIO/SSE 切换健壮:模型能力探测 + 降级
tool_call标志,未知则安全默认)体验:全流式
content_delta),工具调用从同一流拼装;前端实时流式气泡纵深:Agent 编排
记忆:跨会话
memory原生工具组(save/recall/list/delete),持久化到~/.jedi/agent_memory.json,Read 风险无摩擦验证
--mcp-server实测 stdio JSON-RPC(initialize / tools/list / tools/call / 错误方法)vue-tsc+vite build干净🤖 Generated with Claude Code