Agent 构造参数

详细说明 Workspace env、WorkspaceTools 以及本地 Agent 的身份、描述、instruction、model、tools 和 Powers 参数

本地 Agent 的构造方式:

const workspace = new Workspace({
  id,
  path,
  shell,
  env,
});

const agent = new Agent({
  id,
  name,
  description,
  model,
  instruction,
  tools,
  powers,
  Session,
});
// Session 在创建时选择 Workspace。

id

agent 的稳定标识。

它会影响用户级 Agent 数据路径:

~/.downcity/agents/<agent_id>/...

推荐:

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

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

name 与 description

name 是 Agent 的用户可见名称;省略或传入空字符串时回退到 id。description 是一句话能力简介,供宿主展示,也供 Group 调度器根据语义选择成员。

const reviewer = new Agent({
  id: "reviewer",
  name: "代码审查员",
  description: "负责审查代码质量、测试覆盖和交付风险",
  instruction: "审查时给出具体、可执行的修改建议。",
});

id 与 name 会组成每个 Session system prompt 最前面的 Agent 身份块:

# Agent Identity

You are "代码审查员" (agent id: reviewer).

两个值总是同时给出:模型用可读名称理解角色,宿主仍可用稳定 id 对账。

description 不会进入普通 AgentSession 的 system 指令,也不替代 instruction:前者描述“这个 Agent 适合做什么”,后者约束“这个 Agent 应该如何工作”。Group 调度只读取成员的 id/name/description,不会读取完整 instruction。

workspace 与会话目录

当前 Agent 可以访问的项目资源与安全边界。Workspace 统一持有项目根目录、文件与搜索工具,以及可选 Shell:

const workspace = new Workspace({
  id: "project",
  path: "/path/to/project",
  shell,
});

关键点:

  • macOS、Linux 和 Windows 使用同一个 Workspace
  • path 会在 Workspace 构造时解析为真实绝对目录
  • 文件和搜索工具固定限制在 Workspace 内
  • Shell 与文件工具使用同一个项目根目录
  • Agent 构造时可以传入 workspace 作为新建 Session 的默认目录;它不构成绑定
  • 会话的当前目录可以在创建后通过 session.set({ workspace }) 或在 get() 时指定,随时切换
  • 同一个 Agent 可以进入多个 Workspace,每个 Session 拥有独立的当前目录、历史、Shell 和 Power 上下文
  • 多个 Agent 可以指向同一目录,但使用各自的 agent.id 和数据分区

Workspace 只需要提供稳定的 id、真实项目 path,以及可选的 Shell 和 env。Downcity 内部数据根目录由实现自动解析:

const workspace = new Workspace({
  id: "project",
  path: "/path/to/project",
  shell,
});
// Session 在创建时选择 Workspace。

如果 path 不存在、不是目录或为空,Workspace 会立即拒绝构造。

本地实现默认把私有数据写入 ~/.downcity。测试或多实例宿主可以通过 DC_PLATFORM_ROOT 覆盖根目录,该环境变量不属于 Workspace API。

instruction

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

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

关键点:

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

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

model

Agent 持有的默认 ModelClient 实例。可以使用 Federation 目录返回的 CityModel,也可以使用进程内 Provider Adapter 创建模型。

const model = create_openai_compatible_model({
  id: "gpt-5",
  upstream_model: "gpt-5",
  base_url: "https://api.openai.com/v1",
  api_key: process.env.OPENAI_API_KEY!,
});

new Agent({
  id: "repo-helper",
  model,
});

关键点:

  • SDK 不负责选择、保存或恢复模型 ID,只持有 ModelClient 实例
  • CityModel 自身实现 ModelClient,Agent 直接调用 stream(call, signal)
  • Session 没有自己的模型时回退使用 Agent 模型
  • 本地 Session 可通过 session.set({ model }) 覆盖 Agent 模型
  • 有效模型解析顺序固定为 Session 模型、Agent 模型

Workspace 的 env

Env 描述当前 Workspace 的项目执行环境,由 Workspace 持有:

const workspace = new Workspace({
  id: "project",
  path: "/path/to/project",
  env: {
    OPENAI_API_KEY: process.env.OPENAI_API_KEY ?? "",
  },
});

关键点:

  • SDK 先读取项目 .env,再用 Workspace 构造参数 env 覆盖同名值
  • Env 属于 Workspace,不属于 Agent
  • 如果宿主需要合并多层 env,应先在外部合并,再把最终结果传给 env
  • 这些值会成为 Workspace 的运行时 env,但不会自动回写系统环境变量

运行时更新 env

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

workspace.set_env({ FOO: "1" });
workspace.get_env();                // => { FOO: "1" }
workspace.patch_env({ BAR: "2" }); // 增量合并
workspace.patch_env({ FOO: null }); // null 表示删除
workspace.set_env({ ONLY: "ok" }); // 整体覆盖

关键点:

  • get_env() 返回浅拷贝快照
  • patch_env() 中 null / undefined 表示删除该 key
  • set_env() 整体覆盖当前 Workspace env
  • agent.set_instruction() 只影响之后新建的 Session,不会回溯修改当前内存中的已有 Session
  • Session 恢复时若没有 instruction.md,会从 Agent 当前 instruction 和 Power 重新生成 system;已有 Session 可用 session.syncshot() 手动刷新,并用 session.snapshot() 持久化
  • Workspace env 与 Power 修改会在已有 Session 的下一个 Session step 检查点提交
  • 正在进行的 provider 请求及其工具调用继续使用当前 step 已生效的 env
  • 如果当前 Session turn 没有后续 step,排队中的修改会在下一个 Session turn 开始时提交
  • 配置真正生效时,Session timeline 会写入 completed action message
  • 运行时变更只活在内存,不会回写项目 .env 或系统环境变量

tools

Agent 最终持有的额外自定义工具集合。

关键点:

  • Workspace 提供文件、搜索和可选 Shell 组成的 WorkspaceTools
  • 宿主为每个 Power 推送一个 AgentTool,工具名即 Power 名
  • AgentOptions.tools 提供调用方自定义工具
  • ask_question 等可选工具需要调用方从 @downcity/agent/tools 导入并显式传入
  • Agent 统一注册这些工具并由 Session 共享
  • 任意来源的工具重名会直接报错,不会静默覆盖

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

Workspace 的 shell

详细配置参见 Shell 与沙箱。

可选的内建 shell 能力。

import { Agent } from "@downcity/agent";
import { Workspace } from "@downcity/city";
import { Shell } from "@downcity/city";
import { MicrosandboxProvider } from "@downcity/sandbox-microsandbox";

const agent = new Agent({ id: "repo-helper" });
const workspace = new Workspace({
  id: "project",
  path: "/path/to/project",
  shell: new Shell({
    sandbox_provider: new MicrosandboxProvider(),
  }),
  runtime_path: "/path/to/downcity-runtime/project",
});

关键点:

  • Shell 不是 Power
  • Shell 只挂载 shell_exec 和 shell_session
  • Workspace 自身挂载 grep、find、read、write 和 edit,没有 Shell 时仍可使用
  • session 与 turn 上下文由 Agent 内部自动接线
  • 审批归属具体 Session,使用 session.interactions()、session.respond(...) 和 session.set({ security })
  • 文件和搜索工具固定根植于 Agent 项目目录,不提供 host 执行目标

Power 不属于 Agent 构造参数

AgentOptions 不接收 powers。City 登记 CityPowerRegistration 后,自动把全部 Power 提供给全部 Agent:

import { Agent } from "@downcity/agent";
import { City } from "@downcity/city";
import { create_builtin_power_registrations } from "@downcity/powers";

const agent = new Agent({ id: "repo-helper", tools: {} });
const city = new City({
  workspaces: [workspace],
  powers: create_builtin_power_registrations(),
});

city.agents.add(agent);

City 持有 Power 唯一实例、配置投影与生命周期;Agent 只持有身份、模型、指令、Tools 和 Sessions。 联网能力仍需由宿主配置,请参阅 Web Power 文档。

session_composer

只需要调整模型输入或上下文维护方式时,直接传入一个 Composer 实例。它属于 Agent 级特性,描述「这个 Agent 怎么和模型说话」,被该 Agent 的全部 Session 共享。

import { Agent, DefaultSessionComposer } from "@downcity/agent";

const agent = new Agent({
  id: "repo-helper",
  session_composer: new DefaultSessionComposer(),
});

因此 Composer 实现必须无状态:具体 Session 与上下文全部由 compose(input) 参数传入,派生数据写入传入的 derived 存储。不要在实例上缓存任何与 Session 相关的内容。

Session Composer 的定位

Composer 是唯一回答「这一步模型看到什么」的组件。canonical history 与派生存储都由调用方传入,Composer 只读取它们并返回模型输入:

方法用途
initialize(input)在当前 Session 的 session.db 初始化自己的派生 schema;没有派生状态的实现可以是空实现
compose(input)返回当前模型 Step 使用的 system、messages 和 tools
advance_context(input)在 usage_pressure 或 provider_context_limit 触发下尝试推进派生状态;发生有效推进时返回 true

compose(input) 可以:

  • 增删或重排 system messages
  • 筛选、转换或注入本轮模型 messages
  • 调整当前 Step 可见的 tools

「压缩」不是独立概念,而是 advance_context() 的一种实现。FullHistorySessionComposer 就是不推进派生状态的现成实现;自定义压缩算法只需继承 DefaultSessionComposer 并覆盖 advance_context()。

Composer 不消费 Prompt Queue,不控制 Turn,也不修改 canonical Message。它只能写命名空间为 composer_<name>_* 的可重建派生表。只有确实要替换 Session 行为时才使用 session_class。