Skip to content

feat: AI-native 统一工具架构(Agent 工具调用 · MCP 三层 · 流式 · 记忆) - #2

Open
yolopunk wants to merge 18 commits into
mainfrom
claude/agent-capabilities-analysis-c8fyns
Open

feat: AI-native 统一工具架构(Agent 工具调用 · MCP 三层 · 流式 · 记忆)#2
yolopunk wants to merge 18 commits into
mainfrom
claude/agent-capabilities-analysis-c8fyns

Conversation

@yolopunk

@yolopunk yolopunk commented Jul 1, 2026

Copy link
Copy Markdown
Owner

概述

把 Jedi 的 AI 能力从"多一个聊天页"推进到 AI-native:Agent 能安全地操作整个产品、接入 MCP 生态、也能对外输出,并具备流式、降级、规划与跨会话记忆。核心是一套统一工具架构——Agent 只依赖一个 AgentTool 抽象,MCP 只是它的一个来源/出口,而非唯一入口。

设计文档:docs/ai-chat/05-unified-tool-architecture.md(含评审后的 v1.1 修订)。

架构:一个抽象,三种来源

Agent Loop → ToolRegistry(统一) → ┬ 主力:内置工具(进程内直调)
                                  ├ 可选:MCP 客户端(接第三方 server,stdio + SSE)
                                  └ 战略:MCP 服务端(对外暴露给别的 Agent)

分阶段改动

基础:统一工具架构(P1–P4)

  • P1 新增 src-tauri/src/tools/AgentTool trait、ToolRegistryRiskLevel/ToolDeclaration/ToolFilter;hosts 从伪-MCP 迁为进程内原生工具;agent.rs 改走 ToolRegistry;工具名统一下划线命名
  • P2 可挂起确认回路(PendingConfirmations oneshot + UndoStacks):Write/System 工具执行前 dry_run 预览并挂起等待前端确认(120s 超时);hosts 敏感域名动态升级为 System、写前快照校验、写后可回滚;新增 wallpaper/podcast/system 原生工具;前端确认卡片 + 撤销 + 取消
  • P3 第三方 MCP 客户端:连接外部 server,把远端工具适配为 AgentTool 注入注册表(默认 Write 风险=需确认);前端 server 配置管理 UI
  • P4 对外 MCP 服务端:jedi --mcp-server 无头 stdio 模式,暴露只读原生工具

传输:stdio + SSE

  • 抽象出同步 Transport trait,McpClient 支持 Box<dyn Transport>
  • 新增 SseTransport(MCP 2024-11-05 HTTP+SSE,reqwest blocking + 后台读取线程);前端 server 表单支持 STDIO/SSE 切换

健壮:模型能力探测 + 降级

  • 所选模型不支持 function calling 时跳过工具注入、降级为纯对话并提示(依据 models.dev 的 tool_call 标志,未知则安全默认)

体验:全流式

  • OpenAI 系与 Anthropic 两路均改为流式,token 级增量推送(content_delta),工具调用从同一流拼装;前端实时流式气泡

纵深:Agent 编排

  • 注入可配置的 Agent 系统提示(规划 / 确认与安全 / 记忆使用 / 简洁收尾);达步数上限时优雅收尾而非报错

记忆:跨会话

  • memory 原生工具组(save/recall/list/delete),持久化到 ~/.jedi/agent_memory.json,Read 风险无摩擦

验证

  • Rust 单测:新增覆盖 tools / agent(含流式累加器)/ confirm / mcp(含 manager、server、SSE)等,本 PR 新增测试全部通过(仓库既有 4 个环境性失败:OS keyring、联网 RSS,与本 PR 无关)
  • 端到端
    • 第三方 MCP stdioSSE 各用一个 python mock server 实测 initialize → tools/list → tools/call
    • 对外 --mcp-server 实测 stdio JSON-RPC(initialize / tools/list / tools/call / 错误方法)
  • 浏览器层 QA:预装 Chromium 加载构建产物,聊天壳 / SKILLS 面板 / SESSIONS·TRACE 标签 / 四个路由均正常渲染、无未捕获错误(截图确认)
  • 前端vue-tsc + vite build 干净

备注:涉及真实 Tauri invoke 的 GUI 交互流(确认卡片、流式气泡、MCP 连接)需在真机端到端验证,其宿主视图已确认渲染正常。SSE 目前仅支持静态 token;OAuth / Streamable HTTP 留作后续。

🤖 Generated with Claude Code

claude added 18 commits July 1, 2026 12:26
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
@yolopunk yolopunk changed the title feat: AI-native 统一工具架构(Agent 工具调用 + MCP 三层) feat: AI-native 统一工具架构(Agent 工具调用 · MCP 三层 · 流式 · 记忆) Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants