从问答到做事:
任务型侧边栏 Agent 是怎么搭起来的
以 Vercel AI Elements 和 AI SDK 7 为样本,拆开一个能规划、能调工具、能请你确认的侧边栏助理,一层一层看它由什么构成;最后回到墨笺 Markdown,对照现有代码给出改造路线。
三个会改变你计划的发现
核心结论:AI Elements 本身只是渲染层,任务能力来自它下面的 AI SDK 运行时和 UIMessage.parts 协议;你要学的是这套协议,组件库可以随时换。
你看的那个库要退役了
elements.ai-sdk.dev 的仓库公告:AI SDK Elements 将在 2026 年 11 月底弃用,由 shadcn/ui 10 月发布的 AI Elements(21 个模式)接替。新项目直接从 shadcn/ui 装,旧组件因为是拷进项目的代码,不会失效。
[来源: ui.shadcn.com changelog 2026-10;vercel/ai-elements README]
UI 是消息 parts 的投影
每个组件对应一种 part 或一个 part 状态:tool-* 的 approval-requested 渲染成确认卡,data-plan 渲染成计划。理解 parts,组件只是查表。
[来源: ui.shadcn.com/docs/ai-elements Tool / Plan / Confirmation]
墨笺不能直接装这些组件
墨笺前端是 DC runtime + 命令式渲染,没有 Tailwind 和 shadcn。能搬过去的是协议(UI Message Stream)和模式(Plan / Tool / Confirmation 的状态设计),渲染用墨笺自己的样式写。
[来源: mojian-markdown package.json、src/editor/aiMethods.ts]
Agent = 模型 + 工具 + 循环
AI SDK 文档对 Agent 的定义只有一句:在循环里使用工具完成任务的大模型。拆成三件事:模型决定下一步;工具把能力伸出文本之外(读文件、调接口、写库);循环负责上下文管理和停止条件。
这个循环在 SDK 里叫 ToolLoopAgent。每一轮叫一个 step:模型要么输出文本(结束),要么调用工具(SDK 执行工具,把结果塞回上下文,开始下一步)。循环在以下任一情况停下:
| 停止条件 | 含义 | 对侧边栏的意义 |
|---|---|---|
| finishReason ≠ tool-calls | 模型给出最终文本 | 正常收尾 |
| 工具没有 execute | 工具要由别处执行 | 客户端工具的基础:交给浏览器执行(比如改编辑器内容) |
| 工具需要审批 | 发出 approval 请求后暂停 | 人在回路:等用户点「允许」再继续 |
| stopWhen 命中 | 默认 isStepCount(20) | 防失控;可用 hasToolCall('done') 让模型主动交卷 |
[来源: ai@7.0.143 docs/03-agents/02-building-agents.mdx、04-loop-control.mdx]
四层架构:从模型到像素
一个侧边栏助理从后端到界面分四层。AI Elements 只占最上面一层,这是本次调研最需要摆正的认知:
[来源: ai@7.0.143 docs/04-ai-sdk-ui/50-stream-protocol.mdx、20-streaming-data.mdx]
Agent 的基础元素就是 parts
AI SDK 5 之后,一条消息不再是一段字符串,而是 parts 数组。一次任务里 Agent 想了什么、调了什么、产出了什么,都按顺序变成 part。AI Elements 定义「Agent 元素」的方式,就是给每类 part 配一个渲染模式。
| part.type | 是什么 | 关键字段 / 状态 | 对应模式 |
|---|---|---|---|
| text | 正文,流式增量 | text、state: streaming | done | Message(Markdown 渲染) |
| reasoning | 模型思考过程 | 流式文本 | Reasoning、Chain of Thought |
| tool-{name} | 静态声明的工具调用,类型安全 | toolCallId、input、output、state(见第 04 章) | Tool、Confirmation、Terminal、Stack Trace |
| dynamic-tool | 运行时才知道的工具(MCP 等) | 同上,toolName 是字符串 | Tool |
| source-url / source-document | 引用来源 | url、title | Sources、Inline Citation |
| file | 附件、生成的文件 | url、mediaType | Prompt Input 附件 |
| data-{name} | 你自定义的结构化数据 | id 相同则原地替换;transient 不入历史 | Plan、Queue、进度条…… |
| step-start | 新一步开始的分隔 | 无 | Trace 分组 |
[来源: ai@7.0.143 docs/04-ai-sdk-ui/03-chatbot-tool-usage.mdx、20-streaming-data.mdx、50-stream-protocol.mdx]
data-plan,用固定 id 反复写,前端那一块就原地更新。计划、进度、产物卡片都走这条路。21 个模式按「Agent 在做什么」分组
官方按字母排列。按任务型助理的需要重新分组更好记,每组回答一个问题:
它在说什么
- Chat流式时保持阅读位置
- Message一轮问答
- Prompt Input输入与附件
- Suggestion一键追问
- Model Selector选模型与推理档位
它在想什么
- Reasoning流式思考
- Chain of Thought步骤摘要
- Context上下文窗口用量
它打算做什么
- Plan步骤已知,显示进度
- Task步骤边做边出现
- Queue待办 / 已完成清单
- Subagent子代理的调用与结果
它在做什么
- Tool一次工具调用,从输入到输出
- Terminal命令与流式输出
- Stack Trace失败调用
- Test Results测试结果
它需要我什么
- Confirmation执行前审批
- Checkpoint回到某个会话点
它做出了什么
- File Tree改了哪些文件
- Sources用了哪些链接
- Inline Citation句内引用
[来源: ui.shadcn.com/docs/ai-elements,21 个模式清单]
模式,而不是包
AI Elements 的几条设计原则,直接决定了你接入时能改什么、该改什么:
代码归你
没有 npm 包。CLI 把源码拷进
components/ai-elements/,你直接改。代价是没有自动升级,这也是这次迁移「不必立即动手」的原因。组合式组件
Conversation包ConversationContent,Message包MessageContent再包MessageResponse。每块只做一件事,替换其中一块不影响其他块。所有 Agent 步骤一个形状
shadcn 版把 Tool、Plan、Reasoning、Subagent 都建在
Trace上:一行 = 图标 + 标题 + 可选描述 + 状态(running / error / pending),可折叠、可嵌套。界面统一,用户扫一眼就知道 Agent 走到哪。不碰状态
6 月发布的
MessageScroller只管滚动,不管消息、AI 状态、传输和持久化;滚动逻辑另有无样式版本@shadcn/react。数据层由你接。Props 贴着 SDK 类型
组件吃的就是
UIMessage的 part。迁移时导出名和 props 不变,只换渲染,调用方代码不用改。
[来源: elements.ai-sdk.dev/llms.txt;ui.shadcn.com changelog 2026-06、2026-10]
一次工具调用的七种状态
Tool 和 Confirmation 两个模式的全部逻辑,就是对下面这个状态机做 switch。把它记住,你就能自己写任何工具卡片:
preliminary: true:工具用 async generator 多次 yield 中间结果(子代理进度就是这样流出来的)。[来源: ui.shadcn.com/docs/ai-elements Tool;ai@7.0.143 docs/03-agents/06-subagents.mdx]
两个容易误判的边界
- 客户端工具停在
input-available,而聊天已停止:它在等addToolOutput。 - 渲染成「等待你操作」,不要标红。
- 服务端工具停在
input-available,聊天已停止:请求被打断。 - shadcn 的 Tool 模式此时显示为错误。
一次任务的流,逐帧回放
下面是一个墨笺场景的模拟:选中一段文字,让助理「改得更简洁,然后存到飞书」。左边是服务端发出的 UI Message Stream 事件,右边是前端把事件合并成 parts 后渲染的侧边栏。点「下一帧」,注意三件事:计划块是原地更新的;改写建议停下来等你采纳;发布动作要你审批。
模拟数据,事件格式按 ai@7 流协议文档编写;工具名为示意。
「会规划」到底是哪段代码
问答系统和任务型助理的差别,不在模型,而在三处设计:模型能否看到并维护一份计划;计划能否被用户看见;每一步能否被执行和验证。AI SDK 给了两种做法:
- 给模型一个
updatePlan工具,让它自己写、自己勾。 - Claude Code 的 TodoWrite 就是这个思路。
- 计划由模型维护,前端把这个工具的 part 渲染成 Plan / Queue。
- 服务端代码固定步骤,用
data-plan推进度。 - 适合流程固定的业务(审批流、报表生成)。
- 可靠,但不是 Agent 自主规划。
做法 A 的服务端骨架(AI SDK 7):
[来源: ai@7.0.143 docs/03-agents/02-building-agents.mdx、04-loop-control.mdx、06-tool-approvals.mdx]
三个进阶开关
| 开关 | 用途 | 侧边栏场景 |
|---|---|---|
| prepareStep | 每步前改模型、工具集、消息 | 第 0 步强制先调 updatePlan:toolChoice: { type: 'tool', toolName: 'updatePlan' } |
| runtimeContext / toolsContext | 不进 prompt 的服务端状态;按工具隔离的凭证 | 租户、用户权限、飞书 token 只给 publishToFeishu |
| 子代理 | 工具里再跑一个 Agent,async function* 逐步 yield | 长文调研交给子代理,主上下文只收摘要;注意子代理内不支持工具审批 |
[来源: ai@7.0.143 docs/03-agents/04-loop-control.mdx、06-subagents.mdx、02-building-agents.mdx]
侧边栏和聊天页的区别:它住在别人家里
独立聊天页只需要对话。侧边栏寄生在宿主页面上,它的价值来自对宿主的读和写。这引出工具的第二种分法,比「读 / 写」更重要:
| 工具类型 | 谁执行 | 怎么写 | 典型工具 |
|---|---|---|---|
| 服务端工具 | Agent 进程 | 带 execute | 查数据库、调业务 API、发布到飞书 |
| 客户端自动工具 | 浏览器,无需用户 | 不带 execute;前端 onToolCall 里 addToolOutput | 读当前选区、读表单值、滚动到某处 |
| 客户端交互工具 | 浏览器,等用户 | 渲染 UI,用户操作后 addToolOutput | 展示 diff 让用户采纳、让用户选一个选项 |
[来源: ai@7.0.143 docs/04-ai-sdk-ui/03-chatbot-tool-usage.mdx]
sendAutomaticallyWhen 接受函数这一点写的组合用法,文档分别示范了两个 helper。接入前在你的版本上跑一次确认。宿主上下文怎么进模型
三种方式,按优先级:① 让模型用工具按需取(readSelection、readPage),上下文最省;② 用 sendMessage 的 body 或 message metadata 带上当前页面标识,服务端在 prepareCall 里注入;③ 整页塞进 system,只适合小页面。墨笺现在用的是 ③(首轮带全文)。
业务侧边栏:按这个顺序学和建
每一步都能单独跑通、单独验证。前一步不稳,不要进下一步。
先定第 ② 层协议
你们已有 Agent 基建。如果它不是 AI SDK 写的,让它输出 UI Message Stream(SSE +
x-vercel-ai-ui-message-stream: v1头),前端就能直接用useChat。这一步定了,后面都好办。stream-protocoldata-* 命名约定message metadata跑通最小对话
useChat+DefaultChatTransport+ text part 渲染。鉴权头、租户信息放在 Transport 的 headers / body 里。useChatTransportstatusstop()接入 3 个只读工具
一个服务端、一个客户端自动、一个 dynamic(MCP)。目标是 Tool 模式的全部状态都见过一次。
tool()onToolCalladdToolOutputdynamic-tool加上计划
按第 06 章做法 A 加
updatePlan,前端渲染成 Plan。用prepareStep强制首步规划。prepareStepstopWhenhasToolCall加上写操作和审批
写操作统一走
toolApproval,前端 Confirmation 卡片。权限判断放在审批函数里,读runtimeContext,不要信前端传来的角色。toolApprovaladdToolApprovalResponseoutput-denied持久化与恢复
服务端存 UIMessage;服务端生成消息 id;只发最后一条消息;断线后恢复流。侧边栏会被频繁收起和展开,这一步比聊天页更重要。
message persistenceresume streamsvalidateUIMessages换上渲染层
到这一步再装 AI Elements,从 ui.shadcn.com 装,不要用即将弃用的
ai-elementsCLI。窄侧边栏里优先用 Trace 的折叠能力,默认折起工具输出。shadcn add trace code-blockChatToolPlanConfirmation可观测
生命周期回调记录每步耗时、工具错误、审批拒绝率;这三个数决定你下一步优化哪里。
onStepEndonToolExecutionEndtelemetry
[来源: ai@7.0.143 docs/04-ai-sdk-ui/*、03-agents/*;ui.shadcn.com/docs/ai-elements]
墨笺的助理为什么只会问答
读了 src/editor/aiMethods.ts 和 scripts/agent-bridge-*.js(提交 2a88f07)。墨笺其实已经有 Agent 模式:桥接进程拉起本机的 claude -p / codex exec,它们本身就是 Agent 循环。问题出在循环外面的四处设计:
| 环节 | 墨笺现状(代码事实) | 任务型的做法 |
|---|---|---|
| 要不要用工具 | 正则匹配关键词决定 chat / agent 模式(_questionNeedsProjectTools,aiMethods.ts:60) | 始终给工具,由模型判断;只读工具不需要授权 |
| 授权 | 发送前 window.confirm,整轮授权(aiMethods.ts:79) | 按工具调用审批,看到具体参数再批 |
| 过程可见 | Claude 渠道只流出纯文本(engines.js claudeInvocation 仅 -p);只有 Codex 的 JSON 事件被转成粗粒度 progress(engines.js:215) | 每次工具调用都是一个 part,有输入、输出、状态 |
| 消息模型 | assistant 是一段 text + progress 数组 + meta 字符串 | parts[],顺序记录思考、工具、文本 |
| 流协议 | 自定义 SSE 事件:delta / progress / artifacts / document-updated / meta / session-reset / error(aiMethods.ts:630) | UI Message Stream 标准事件 + 少量 data-* |
| 计划 | 无 | updatePlan 工具 + Plan 渲染 |
| 改原文 | CLI 改 scratch 文件,结束后整篇回写(agent-bridge-agent.js readAgentDocumentUpdate) | 客户端交互工具 proposeEdit:展示 diff,用户逐处采纳 |
三期改造,每期都能发布
一期 · 统一流协议(不改交互)
桥接层把 CLI 事件翻译成 UI Message Stream。Claude 改用 stream-json 输出(Claude Code 的
--output-format stream-json,需配合--verbose,接入前在本机确认参数),把其中的 tool_use / tool_result 映射为tool-input-available/tool-output-available;Codex 的item.*事件同理。现有meta、document-updated改成data-mojian-meta、data-document-updated。前端不引入 React 组件,用
ai包里与框架无关的readUIMessageStream把事件合成 UIMessage,替换手写的 SSE 解析(aiMethods.ts:677 起的 while 循环)。渲染函数改为遍历 parts。agent-bridge-engines.jsaiMethods.tsreadUIMessageStream二期 · 规划与审批
去掉正则路由和
window.confirm。分两条路径:文档类任务(改写、整理、发布):在桥接进程里跑自己的
ToolLoopAgent,工具都是墨笺领域工具:readDocument、readSelection(客户端)、proposeEdit(客户端交互)、updatePlan、publishToFeishu/publishToDingTalk(需审批)。粒度细,能逐步确认。工程类任务(读代码、跑命令):继续用 CLI。
claude -p在非交互模式下无法中途等前端审批,所以保留白名单做边界(更好的替代见第 12 章方案 B)。AI SDK 7 的HarnessAgent可以把 Claude Code / Codex 包成同一套流,但它目前标注为 experimental,且 Claude Code、Codex 适配器的运行位置是 sandbox bridge 而非本机进程,与墨笺「直接读本机工程」的定位不一致,先观察。ToolLoopAgenttoolApprovalproposeEditupdatePlan三期 · 墨笺版渲染层
按 AI Elements 的模式,用墨笺自己的样式实现 5 个渲染器:Message(沿用现有 marked 渲染)、Reasoning(默认折叠)、Tool 步骤行(状态 → 图标)、Confirmation 卡片、Plan 清单。一个统一的步骤行组件撑起后三者。
aiPanel.css新文件 aiPartsRender.ts
aiMethods.ts 现在 798 行,一期就必须把流解析和渲染拆出去;交付前跑 npm run check。一期的最小验证
在桥接层加一个开关,同一个问题分别走旧事件和新协议,对比三项:首字延迟、工具调用是否全部可见、文档回写是否一致。三项都持平或更好,再删旧路径。
托管 Agent 的流,有没有统一标准
核心结论:没有一个协议覆盖全部场景。市面上的协议分成四层,各管一段;托管 Agent 的会话接口(Claude Managed Agents、OpenAI Agents API)仍是各家私有格式。好在它们的基本单元高度一致,都能映射到第 04 章那台状态机上,所以你只需要写一个薄适配器。
[来源: docs.ag-ui.com/sdk/js/core/events;platform.claude.com/docs/en/managed-agents/reference;agentclientprotocol.com/get-started/agents;aaif.io A2A v1.0 builder's guide;developers.openai.com/learn/agents]
一张表看懂:同一台状态机,五种说法
按第 04 章的状态逐行对照。读法:只要某个协议能表达这一行,你就能在适配器里把它翻译成 AI SDK 的对应事件,前端渲染代码一行都不用改。
| 状态机环节 | AI SDK UI Stream | AG-UI 1.0 | Claude Managed Agents | ACP(本地) | A2A 1.0 |
|---|---|---|---|---|---|
| 文本流 | text-delta | TEXT_MESSAGE_CONTENT | agent.message(增量需开 event_deltas) | agent_message_chunk | Message / Artifact 的 parts |
| 思考 | reasoning-delta | REASONING_MESSAGE_CONTENT | agent.thinking(只有进度信号,不含内容) | agent_thought_chunk | 无对应 |
| 工具开始 | tool-input-available | TOOL_CALL_START / ARGS / END | agent.tool_use / agent.mcp_tool_use | tool_call(status: pending) | Agent 内部,不外露 |
| 工具结果 | tool-output-available / -error | TOOL_CALL_RESULT | agent.tool_result / agent.mcp_tool_result | tool_call_update(completed / failed) | Agent 内部,不外露 |
| 请求审批 | tool-approval-request | RUN_FINISHED 带 outcome.interrupt | session.status_idle,stop_reason: requires_action | session/request_permission | Task 状态 INPUT_REQUIRED |
| 回复审批 | addToolApprovalResponse | 新一次 run 带 resume[] | user.tool_confirmation(allow / deny + deny_message) | 选中 allow_once / reject_once 等选项 | 在同一 Task 上再发消息 |
| 客户端工具 | 无 execute + addToolOutput | 运行输入里声明前端工具,结果随下一次 run 带回 | agent.custom_tool_use → user.custom_tool_result | 客户端方法 fs/read_text_file、fs/write_text_file 等 | 无对应 |
| 计划 | data-plan 或计划工具 | STATE_SNAPSHOT / STATE_DELTA(JSON Patch) | 无内置事件,需自定义工具 | plan(content / priority / status) | Task 状态 + Artifact |
| 文件改动 | data-* 自定义 | ACTIVITY_SNAPSHOT | 工具结果里体现 | 工具内容类型 diff(path / oldText / newText) | Artifact |
| 结束 | finish | RUN_FINISHED | session.status_idle,stop_reason: end_turn | session/prompt 返回 stopReason | COMPLETED / FAILED 等终态 |
[来源: ai@7.0.143 docs/04-ai-sdk-ui/50-stream-protocol.mdx;docs.ag-ui.com/sdk/js/core/events、/concepts/interrupts;platform.claude.com/docs/en/managed-agents/reference、/events-and-streaming、/permission-policies;agentclientprotocol.com/protocol/v1/prompt-turn、/protocol/tool-calls;aaif.io A2A v1.0。AG-UI 前端工具一格与 ACP fs 方法一格来自我对规范的了解,本次未逐字核对]
每个协议适合谁
| 协议 | 适合场景 | 对侧边栏的意义 |
|---|---|---|
| AI SDK UI Stream | 前端用 AI SDK | 你业务里的默认选择,渲染层已经按它写 |
| AG-UI 1.0 | 后端是 LangGraph、AWS Strands 等框架,前端想换框架也不受影响 | 公司 Agent 基建若已接 AG-UI,前端写一层 AG-UI → UI Stream 翻译即可;中断机制是 2026 年新增的,LangGraph 需手动开启 |
| Claude Managed Agents | 不想自己维护循环和沙箱,长任务、异步任务 | 「用户填 API key 或指定一个 Agent」正好对应它的 Agent 资源;目前是 beta |
| OpenAI Agents API | OpenAI 生态里的同类托管会话 | 思路与 Claude Managed Agents 相同;本次只确认了产品目录,事件格式未核对 |
| ACP | 本机编辑器驱动本机编码 Agent | Gemini CLI、Codex(适配器)、Claude(Zed 适配器)等 43 个实现说同一种话 |
| A2A 1.0 | Agent 之间委派任务 | 侧边栏 Agent 把子任务交给公司其他 Agent 时用;不直接驱动界面 |
[来源: 同上;ACP 实现数量取自 agentclientprotocol.com/get-started/agents,2026-10-17 读取]
适配器长什么样:以 Claude Managed Agents 为例
托管会话的状态在对方服务器上,所以路由的写法和第 06 章不同:不重放整段历史,而是续接同一个 session。这和 AI SDK 文档里 HarnessAgent 接 useChat 的思路一致。一轮请求要做三件事:
把前端的回复转成会话事件
最后一条 UI 消息若是审批回复,发
user.tool_confirmation;若是客户端工具结果,发user.custom_tool_result;否则发user.message。先开流,再发事件
官方文档要求顺序如此,否则会漏掉事件。
把会话事件翻译成 UI Stream
按上表逐个翻译。收到
requires_action后结束这次 HTTP 响应,前端渲染 Confirmation 卡片,用户点击后发起下一次请求,回到第 1 步。
[来源: platform.claude.com/docs/en/managed-agents/events-and-streaming;ai@7.0.143 docs/04-ai-sdk-ui/20-streaming-data.mdx、03-ai-sdk-harnesses/07-ui.mdx]
write* 系列函数里需要读取的事件字段(工具名、输入、结果)没有在本次核对范围内,写之前看一眼 reference 页的字段定义。客户端工具在 Managed Agents 里会立刻暂停会话,agent.custom_tool_use 应翻译成「等待你操作」,不要标成运行中。用户只给一个 API key,能做到什么
墨笺现在只有一条路:本机装好并登录 claude / codex CLI。官网版(mojian.uk)因为没有桥接进程,直接提示不提供 AI 助手(aiMethods.ts:10)。去掉 CLI 依赖有四种做法,适用场景不同,可以并存:
| 方案 | 用户需要提供 | 循环跑在哪 | 审批怎么接 | 适合墨笺的哪类任务 |
|---|---|---|---|---|
| A · 自建 ToolLoopAgent | 任一模型 API key(Anthropic、OpenAI,或兼容 OpenAI 接口的国内模型) | 桥接进程(本机) | toolApproval,原生对接 Confirmation | 文档改写、整理、发布。工具全是墨笺自己的,粒度最细 |
| B · Claude Agent SDK | Anthropic API key | 桥接进程(本机),运行时随 npm 包按平台分发 | canUseTool 回调:挂起等前端回复,再返回 allow / deny | 需要读本机工程、跑命令的任务,等于免安装的 Claude Code |
| C · Claude Managed Agents | Anthropic API key + 一个 Agent ID | Anthropic 云端 | 权限策略 always_ask → user.tool_confirmation | 长任务、跨设备继续;墨笺编辑器操作作为自定义工具回到本地执行 |
| D · ACP 客户端 | 本机装有任一 ACP Agent | 本机 Agent 进程 | session/request_permission | 仍依赖本机 Agent,但能替换 engines.js 里逐家解析 CLI 输出的代码 |
[来源: ai@7.0.143 docs/03-agents/06-tool-approvals.mdx;code.claude.com/docs/en/agent-sdk/permissions;npm @anthropic-ai/claude-agent-sdk@0.3.302 包结构(含 8 个平台可选依赖,2026-10-17 检查);platform.claude.com/docs/en/managed-agents/tools、/permission-policies、/self-hosted-sandboxes;agentclientprotocol.com]
claude -p 成立,但 Claude Agent SDK 的 canUseTool 回调可以 await 一个 Promise,桥接进程在这里挂起,等前端的审批回复到达再返回结果。所以方案 B 能做到逐个工具审批。推荐组合
主路径用方案 A
墨笺的核心任务是读、改、发布文档,这些操作都可以写成墨笺自己的工具:
readSelection、proposeEdit、publishToFeishu。用户在设置页选择模型供应商并填写 key,桥接进程用 AI SDK 的对应 provider 跑 ToolLoopAgent。前端直接消费 UI Stream,第 10 章的三期改造全部沿用。@ai-sdk/anthropic@ai-sdk/openai-compatibletoolApproval工程类任务用方案 B 替代 CLI
保留「读本机工程」的能力,同时去掉安装 CLI 的前置条件。把 SDK 输出的消息翻译成 UI Stream,
canUseTool翻译成审批请求。现有的 Claude CLI 路径可以先保留为备选。@anthropic-ai/claude-agent-sdkcanUseToolallowedTools方案 C 先观察
它最贴近你说的「定制一个 Agent」:Agent 在控制台定义一次,用户只引用 ID。但目前有四个限制:仍是 beta;会话历史和产出存在 Anthropic 服务端,不在零数据保留范围内;云端沙箱看不到用户本机文件,只能通过自定义工具读取;自托管沙箱要求 Linux 主机和一把环境密钥,不适合分发到普通用户的桌面。
官网版要单独评估
方案 A、B 都依赖桥接进程,无法让 mojian.uk 网页版获得 AI 能力。如果网页版也要支持,需要一个服务端代理来保管 key 并转发流,key 不能留在浏览器里。这超出了个人项目的运维范围,建议暂不做。
方案 B 的审批挂起写法
[来源: code.claude.com/docs/en/agent-sdk/permissions]
canUseTool 返回值的字段名按文档示例写,接入前对照 TypeScript 参考页确认。学完的标志
勾选会保存在这台浏览器里。
来源
- Vercel Academy · AI Elements 课程
- shadcn/ui changelog 2026-10 · Trace、Code Block 与 AI Elements
- shadcn/ui changelog 2026-06 · Chat 组件
- ui.shadcn.com/docs/ai-elements(Tool、Confirmation、Plan 各页)
- vercel/ai-elements README(弃用公告)
- elements.ai-sdk.dev/llms.txt
- AI SDK · Loop Control;ToolLoopAgent 参考
- AG-UI · Events;AG-UI · Interrupts
- Claude Managed Agents · Session event stream;Reference;Permission policies;Self-hosted sandboxes
- Claude Agent SDK · Configure permissions
- ACP · Prompt turn;Tool calls;Agents
- AAIF · A2A v1.0 builder's guide
- OpenAI · Agents
- npm 包
ai@7.0.143自带 docs 目录(agents、ai-sdk-ui、ai-sdk-harnesses),2026-10-17 读取 - xiaoji121/mojian-markdown @ 2a88f07(2026-10-15)