Local Agent

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 上

继续看: