Agent

Agent SDK

在 Node 应用中嵌入 Downcity Agent 运行时

Agent SDK

@downcity/agent 用于在同一进程中创建 Agent、管理 Session 并执行模型调用。完整 API 参考在 Agent SDK 文档

import { Agent, Workspace } from "@downcity/agent";
import { Shell } from "@downcity/shell";
import { MacOsSeatbeltSandbox } from "@downcity/sandbox-macos";

const workspace = new Workspace({
  path: process.cwd(),
  shell: new Shell({ sandbox: new MacOsSeatbeltSandbox() }),
  env: { API_KEY: process.env.API_KEY ?? "" },
});

const agent = new Agent({
  id: "repo-helper",
  workspace,
  model,
  tools: { search: search_tool },
  plugins: [plugin],
});

const session = await agent.sessions.create();
const turn = await session.prompt({ query: "检查当前项目" });
const result = await turn.finished;

await agent.dispose();

Workspace 是统一资源容器,同时提供 AgentStore、WorkspaceTools、Env 与可选 Shell。Session 历史和元数据默认保存在同一个项目的 .downcity 目录中,也可以被 Workspace 的文件工具正常读取和编辑;创建 Agent 时不需要单独配置 Store。

每个 Workspace 实例只绑定一个 Agent,并由 agent.dispose() 一并释放。多个 Agent 可以操作同一物理目录,但需要分别创建 Workspace 实例。

Agent 在构造时启动 plugin 生命周期与后台任务;需要明确等待就绪时使用 await agent.ready(),关闭时使用 await agent.dispose()。HTTP 与 RPC 由独立包 @downcity/serverAgentHTTPAgentRPC 提供。

流式消息

subscribe() 返回统一的实时 Session Mutation:

const unsubscribe = session.subscribe((mutation) => {
  if (mutation.variant === "delta" && mutation.type === "text") {
    process.stdout.write(mutation.delta);
  }
});

Tool 生命周期使用 type: "tool",用户参与使用 type: "interaction"。pending Interaction 携带完整请求,关联 Tool 同时进入 waiting-user;响应通过独立 Session 命令提交:

同一 Assistant step 内的 Part 顺序始终与模型流一致。即使 Tool 已提前进入执行准备,它也会等待对应的 Tool Part 出现在流中,不会越过尚未写入的前置文本。等待按 tool_call_id 相互隔离,多个 Tool 仍可并发执行;客户端应按 Mutation 与历史快照中的顺序直接渲染,无需自行重排。

const unsubscribe = session.subscribe((mutation) => {
  if (
    mutation.variant === "part" &&
    mutation.type === "interaction" &&
    mutation.part.status === "pending"
  ) {
    render_interaction(mutation.part);
  }
});

async function decide_approval(interaction_id: string, decision: "approved" | "denied") {
  await session.respond({
    interaction_id,
    response: { kind: "approval", decision },
  });
}

历史快照使用 session.messages()。它返回当前 Active 页;存在更早的不可变 Segment 时,会同时返回 next_before_sequence 游标。连接断开后重新读取快照并建立新的订阅。

需要渲染平铺活动时间线的宿主可以直接使用 SDK 投影,不需要依赖 .downcity 的物理文件名:

import { to_session_message_timeline_events } from "@downcity/agent";

const page = await session.messages();
const timeline = page.items.flatMap(to_session_message_timeline_events);

Session JSONL、日志和调度任务统一通过 Workspace FileSystem 完成根目录限制、原子写入与跨进程文件事务。应用应通过 Agent 和 Session API 访问结构化状态,而不是直接读取物理存储布局。

继续阅读: