Local Agent

Agent 构造参数

详细说明本地 Agent 的 id、path、instruction、prepare_session、env、tools 和 plugins 参数

Agent 构造参数

本地 Agent 的构造方式:

new Agent({
  id,
  path,
  prepare_session,
  env,
  instruction,
  tools,
  shell,
  plugins,
  Session,
})

id

agent 的稳定标识。

它会影响 SDK session 落盘路径:

<projectRoot>/.downcity/agents/<agentId>/...

推荐:

  • 稳定
  • 可 URL 编码
  • 不要随便改

因为它直接决定了 session 落盘目录分区。

path

当前 agent 绑定的项目根目录。

SDK 会基于它:

  • 读取项目 .env
  • 组织会话落盘目录

如果 path 给错,后面很多行为都会变得不符合预期,因为 Agent 会在错误上下文里读取配置和写数据。

instruction

调用方传入的本地 SDK Agent 静态基础指令。

new Agent({
  id: "repo-helper",
  path: "/path/to/project",
  instruction: [
    "你是一个简洁的代码助手。",
    "解释代码时优先给出明确文件引用。",
  ],
});

关键点:

  • instruction 是静态的,应该保持缓存友好
  • SDK 不会对它做动态变量渲染
  • SDK 不读取项目 prompt 配置文件
  • 如果省略 instruction,SDK 会使用包内最小 core instruction 作为 fallback

宿主需要额外基础指令时,应通过 instruction 显式传入。

prepare_session

Session 每次执行前调用的宿主准备钩子。

new Agent({
  id: "repo-helper",
  path: "/path/to/project",
  prepare_session: async (session) => {
    await session.set({ model: openai.responses("gpt-5") });
  },
});

关键点:

  • SDK 不负责选择、保存或恢复模型 ID
  • 宿主先创建 LanguageModel,再通过钩子注入
  • 钩子每个 turn 执行前调用,宿主配置可在下一轮生效
  • 该钩子也可以准备其他宿主级运行时依赖

env

这个 agent 可见的环境变量快照。

new Agent({
  id: "repo-helper",
  path: "/path/to/project",
  env: {
    OPENAI_API_KEY: process.env.OPENAI_API_KEY ?? "",
  },
});

关键点:

  • SDK 会先采用显式传入的 env,再由项目 .env 覆盖同名值
  • SDK 不再区分 global env 和 agent env
  • 如果宿主需要合并多层 env,应先在外部合并,再把最终结果传给 env
  • 这些值会参与配置解析与运行时上下文装配,但不会自动回写系统环境变量

运行时更新 env

构造 agent 之后,你也可以在运行期增量更新或整体替换 configured env:

const agent = new Agent({ id, path, env: { FOO: "1" } });

agent.getEnv();              // => { FOO: "1" }
agent.patchEnv({ BAR: "2" }); // 增量合并
agent.patchEnv({ FOO: null }); // null 表示删除
agent.setEnv({ ONLY: "ok" });  // 整体覆盖

关键点:

  • getEnv() 返回的是浅拷贝快照,修改它不会影响 agent 真实状态
  • patchEnv()null / undefined 表示删除该 key,其余值会强制转字符串
  • setEnv() 会先清空当前 env,再写入新值,仍然保持原引用不变
  • 已有 Session 会在下一个 Session step 检查点统一提交 Agent instruction、env 与 plugin 修改
  • 正在进行的 provider 请求及其工具调用继续使用当前 step 已生效的 env
  • 如果当前 Session turn 没有后续 step,排队中的修改会在下一个 Session turn 开始时提交
  • 配置真正生效时,Session timeline 会写入 completed action message
  • 运行时变更只活在内存,不会回写项目 .env 或系统环境变量

tools

agent 级默认工具集合。

关键点:

  • 它属于 agent 级,不是 session 级
  • 当前 agent 创建出来的 session 会直接复用这份工具集合

这很适合“多个 session 共用一套默认工具能力”的场景。

shell

详细配置参见 Shell 与沙箱

可选的内建 shell 能力。

import { Agent } from "@downcity/agent";
import { Shell } from "@downcity/shell";

const agent = new Agent({
  id: "repo-helper",
  path: "/path/to/project",
  shell: new Shell(),
});

关键点:

  • Shell 不是 plugin
  • Agent 会从 Shell 实例挂载 shell_execshell_sessiongrepfindreadwriteedit
  • session 与 turn 上下文由 Agent 内部自动接线
  • 审批归属具体 Session,使用 session.approvals()session.resolve_approval(...)session.set_approval_mode(...)
  • 文件和搜索工具固定限制在 Agent 项目根目录内,不提供 unrestricted 模式

plugins

这里接收的是已经实例化好的 BasePlugin 对象。

例如:

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()],
});

SDK 会为当前 Agent 创建独立的 plugin registry。

关键点:

  • 应该传 new SkillPlugin() 这类实例,而不是原始 plugin 定义对象
  • 它不会默认注册全部内建 plugin
  • 它不会复用全局 runtime 的 plugin manager
  • 同名 plugin 被重复注册时会直接报错
  • agent.pluginsAgentContext.plugins 会使用这份 registry
  • 如果你想一次性注入整套内建 plugin,可以从 @downcity/plugins 传入 plugins: createBuiltinPlugins()

Session

本地 session 的高级自定义类。

当你希望替换本地 session 实现,或者在 Session 层注入自定义 Composer 时使用它。Agent 只负责用这个类创建和恢复 session,不理解 Composer 的具体策略。

import {
  Agent,
  Session,
  type SessionOptions,
  type SessionSystemComposer,
} from "@downcity/agent";

const systemComposer: SessionSystemComposer = {
  name: "custom_system",
  async resolve() {
    return [{ role: "system", content: "始终简洁回答。" }];
  },
};

class CustomSession extends Session {
  constructor(options: SessionOptions) {
    super({
      ...options,
      composers: {
        systemComposer,
      },
    });
  }
}

const agent = new Agent({
  id: "repo-helper",
  path: "/path/to/project",
  Session: CustomSession,
});

关键点:

  • 传入的是 class,不是已经创建好的 session 实例
  • 这样 Agent 可以按不同 sessionId 创建多个 session
  • Composer 自定义留在自定义 Session 类内部
  • RemoteAgent 不支持本地 Session 类,因为它只是远程 runtime 的访问器