tools 和 plugins
如何给本地 Agent 注入工具与显式 plugin 实例
tools 和 plugins
tools
本地 Agent 可以直接接收工具集合:
const agent = new Agent({
id: "repo-helper",
path: "/path/to/project",
tools: {
my_tool: myTool,
},
});这些工具会在 session 执行时直接可用。
如果你的应用需要一套长期稳定的默认工具集合,这种 agent 级注入方式通常最顺手。
plugin 实例
如果你希望本地 Agent 持有长期运行的 plugin 能力,比如 chat 渠道,可以显式传入 plugin 实例:
import { Agent } from "@downcity/agent";
import { ChatPlugin } from "@downcity/plugins";
const agent = new Agent({
id: "repo-helper",
path: "/path/to/project",
tools: {},
plugins: [
new ChatPlugin({
telegram: {
botToken: process.env.TELEGRAM_BOT_TOKEN!,
},
}),
],
});这类写法适合:
- 你希望 SDK 自己启动 chat 渠道
- 你需要把 plugin 生命周期和应用代码绑定在一起
plugins
如果你需要让本地 Agent 持有一组 plugin,可以显式传入实例对象:
import { Agent } from "@downcity/agent";
import { SkillPlugin, WebPlugin } from "@downcity/plugins";
const agent = new Agent({
id: "repo-helper",
path: "/path/to/project",
tools: {},
plugins: [new SkillPlugin(), new WebPlugin()],
});
const plugins = agent.plugins.list();这些 plugin 会注册到当前 Agent 自己的 registry 里。
这意味着:
- plugin action 可以通过
agent.plugins.runAction(...)调用 - plugin hook 里拿到的
context.plugins会指向同一份 registry - 同名 plugin 重复注册会直接报错
- SDK 不会默认注册全部内建 plugin
当前本地 SDK 会接通 plugin registry、AgentContext.plugins,并在 session prompt 中注入已注册 plugin 的 system(context) 文本。
ImagePlugin
如果你希望 Agent 在对话过程中自己触发生图,可以把图片能力包装成 ImagePlugin:
import { Agent, ImagePlugin } from "@downcity/agent";
const agent = new Agent({
id: "creative-agent",
path: "/path/to/project",
model,
plugins: [
new ImagePlugin({
image: (input) => city.ai.image(input),
}),
],
});注册后,Agent 会自动获得一个内置的 plugin_call tool。模型在需要生图时会调用:
plugin_call({
plugin: "image",
action: "generate",
payload: {
prompt: "一张雨夜城市街角的电影感插画",
aspect_ratio: "16:9",
},
});ImagePlugin 不直接绑定 City,也不关心 OpenAI、Gemini、302.ai、Luchi 等 provider 的具体协议。它只要求 image(input) 返回 AI SDK UIMessage。
最终图片不会只停留在 tool result 里。Agent 底层会把生成结果中的 file parts 合并进最终 assistant message,因此 session 历史里会保存类似:
{
role: "assistant",
parts: [
{ type: "text", text: "已生成图片。" },
{ type: "file", mediaType: "image/png", url: "..." },
],
}plugin HTTP
如果 Town 暴露 Agent HTTP 网关,已注册 plugin 的 plugin.http.server.register(...) 也会自动挂到同一个 HTTP app 上。
也就是说:
- 插件是否存在,由
Agent构造参数里的plugins决定 - 插件 HTTP 是否真正暴露,由 Town 是否发布 Agent HTTP 网关决定
一个重要边界
SDK 这里的 plugins 是“你主动交给 Agent 的实例集合”,不是全局 plugin manager 的镜像。
所以不要把 SDK 模式想成“自动把项目里一切都搬进来”,它更强调显式装配。
如果你希望一次性带上整套内建 plugin,请显式使用 @downcity/plugins 里的 plugins: createBuiltinPlugins()。
如果你要进一步理解:
- plugin 应该怎么挂到本地 Agent 上
继续看: