外来程序可以在对话的六个口上改数据或换方向,也可以给模型登记方法。插件跑在独立进程里,通过 gRPC 和宿主说话。
没有 PLUGIN_DIR 时,服务不拉任何插件,主循环与现在完全一样。
plugin/example 是作者拷贝的模板:不订阅、不改正文、不换向、不登记方法。装进 PLUGIN_DIR 也不会改对话。复制本目录,改 go.mod 模块名、Manifest.Name 和策略,再在 Bootstrap 里填 Subscriptions。作者只 import codedock/pkg/plugin。go.mod 用 replace 指到本仓 server/。
可装载的插件放在仓根 plugin/,子目录名即插件名。plugin/redact 是脱敏插件:不拦工具,只在 input / request / post-execute 把秘密换成占位符。六个口要哪些字段,以 codedock/pkg/plugin 里的结构体为准(AgentInput、AgentInputResult 等),跳进类型就能看到。
本地编译后:
(cd plugin/example && go build -o example .)
(cd plugin/redact && go build -o redact .)
PLUGIN_DIR=$PWD/plugin pnpm run dev正文或工具回包含 AKIA… / API_KEY=… 时,落库和发给模型的是占位符。
目录约定:
plugin/ # PLUGIN_DIR 指这里
example/
example # 拷贝模板,不改对话
redact/
redact # 与子目录同名的二进制
每个口是一对 SDK 结构体,实现对应方法即可。没实现的口原样通过。字段含义写在结构体上。
| 口 | 方法 | 入参 | 回包 |
|---|---|---|---|
agent/input |
OnAgentInput |
AgentInput(正文、模式) |
AgentInputResult;Handle() 不建 Run |
agent/pre-step |
OnAgentPreStep |
AgentPreStep(系统提示、隐藏消息) |
AgentPreStepResult;Block() 取消本轮 |
agent/request |
OnAgentRequest |
AgentRequest |
AgentRequestResult;只能 Reply() |
llm/stream |
OnLLMStream |
LLMStream(请求头、请求体) |
LLMStreamResult;只能 Reply();fake 模型不插 |
tools/pre-execute |
OnToolPreExecute |
ToolPreExecute(工具调用) |
ToolPreExecuteResult;Deny() 当失败;AskApproval() 进审批 |
tools/post-execute |
OnToolPostExecute |
ToolPostExecute(工具结果) |
ToolPostExecuteResult;只能 Reply() |
账本通知走 OnLedgerNotify,没有换向。多个插件按子目录名排序,后一个看到前一个改完的结果。同一条链上问过的插件记在 Seen 里,不会再问自己。
跨口、跨插件传参数用各口上的 Context(Set("example.xxx", v) / Get)。这是宿主暂存的 JSON 对象,不进模型、不进消息表、不换向。键建议 插件名.字段。agent/input 时按会话挂;建 Run 后迁到该 Run。Handle() 或 Run 终态会清掉。上限 8KB,超了保留上一份。进程重启即丢。不要把协议塞进 Hidden。
隐藏提示用 sdk.HiddenText("...") 加进 AgentPreStep.Hidden。已批准但还没执行的工具不再走 OnToolPreExecute。流式增量 assistant.delta 不发给插件。
Bootstrap 拿到的 Host 只能做这些事:
Emit:另发一条与当前口无关的事件。不能发六个口的同名事件。RegisterMethod:给模型加方法。不能覆盖ping、memory_read、memory_write、memory_search。MemoryGet/MemoryUpsert:按会话读写一篇专题记忆。Complete:自己打一次模型,不进当前助手流。AppendNotice:写一条用户看得见的 system 消息(本期只落库,不实时推送)。
PLUGIN_RPC_TIMEOUT 默认 10s。超时或进程挂了:
agent/input、agent/pre-step、tools/pre-execute按否决处理agent/request、llm/stream、tools/post-execute保留原数据
进程崩了不会自动拉起。换二进制要重启服务。
| 变量 | 含义 |
|---|---|
PLUGIN_DIR |
插件根目录。每个子目录一个常驻进程。未设则不加载。 |
PLUGIN_RPC_TIMEOUT |
单次 RPC 超时,如 10s。 |