Files
paseo/public-docs/sdk/agents.zh-CN.md
Mohamed Boudra bd15e40e94 Serve paseo.sh in Simplified Chinese (#7373)
* feat(website): serve paseo.sh in Simplified Chinese

Every page of the website now has a Simplified Chinese version under
/zh-CN: the interface, docs, blog posts, comparison pages, legal pages,
all changelog releases and the homepage mockup. English URLs are unchanged.

The URL alone decides the language. There is no browser-language redirect
and no stored preference, because either would have to redirect the
unprefixed English URLs that people share and search engines index.
Internal links carry the page's language instead, and hreflang alternates
point Chinese search results at /zh-CN.

Translated headings pin the English anchor with {#id}, so section links
work in both languages. content-translations.test.ts fails when a page
has no translation or a translation's headings drift from the English.
Changelog releases and plugin listings without a translation render
whole in English under a notice, so a release never waits on one.

Plugin manifests and the registry gain optional translations and
OVERVIEW.zh-CN.md fields; older clients and registries ignore them.

* feat(website): replace the native language select with an EN/ZH menu

The header showed an OS-native select whose popup did not match the site.
The trigger now shows the language abbreviated (EN, ZH) and opens a menu in
the app's dropdown style that names each language in itself, with its name
in the page language underneath. Rows are real links to the same page in
that language; arrows, Escape, outside presses and taps behave as a menu
button, and the menu keeps itself on screen when a narrow header pushes the
trigger toward an edge.

Also drops the stray space after the full-width comma in the Chinese
homepage subtitle.

* docs(website): translate main's new docs and 0.12.0 release notes

Main added Keep run workspaces to the schedules docs, rewrote plugin icons
around inline SVG, and promoted 0.12.0 with new entries. Bring the Chinese
pages and changelog in line so no section falls back to English.

* fix(server): leave plugin listing translations to the registry

The daemon rejected manifests whose translations the registry would refuse,
so a plugin main installs could fail to load here. Paseo never reads
translations; the registry validates them at publish. Docs now say which
checks are automated at publish and which are human review.

* docs(plugins): describe the registry's final overview translation discovery

* style(server): format manifest test

* test(app): measure sidebar rows one at a time

After a reload the developer error toast appears while expectVerticalOrder
measures every row at once. Each concurrent boundingBox runs the toast
locator handler, and only one of them resumes, so the poll timed out on
every attempt since #7424. Measuring sequentially keeps one action in flight.

* test(app): return sidebar row measuring to main

#7480 hides the developer toast instead of running a locator handler, so
measuring the rows concurrently no longer races it. Reverts 41ac23016.

* test(app): wait for the compact shell before opening compact Changes

The shell survives the breakpoint, so right after the resize the wide
Explorer could still be visible: the test skipped the Explorer toggle and
the tab then disappeared, or toggled at the wrong time. Wait for the
compact-shell marker, as the composer helpers do since #7424.

* docs(website): translate main's plugin file panel docs

* test(app): edit the code font size after the font family remount

A committed appearance change remounts the settings screen through
AppearanceStyleBoundary, and the new form starts from the stored size.
Filling the size before that remount lost the edit in CI.

* docs(website): translate main's client/ui import docs

Follows #7474: one /client/ui entry, StreamedText instead of useRevealedText,
SettingsGroup dropped from the settings table, and the new
'UI imports in v0.13' migration section.

* test(app): wait for the previous layout's file panel picker to leave

After a resize the old layout's picker animates out while the new one is
already mounted, so the Use button matched two elements and the strict
locator failed. Wait for the shell's layout and a single picker first.
2026-10-21 13:13:03 +07:00

7.1 KiB

title, description, nav
title description nav
在 SDK 中使用 Agent 用 TypeScript 创建、运行、查找、复用、设置父级和归档编程 Agent。 Agent

在 SDK 中使用 Agent

Agent 句柄持有一个稳定的 Agent ID,并在不暴露 daemon RPC 的情况下提供每一轮的生命周期。

运行初始提示词

const agent = await client.agents.create({
  config: {
    provider: "claude/claude-sonnet-5",
  },
  cwd: "/Users/me/dev/storefront",
  prompt: "Review the checkout flow and propose one focused fix.",
  labels: { source: "checkout-review" },
});

const result = await agent.waitForFinish();
console.log(result.status, result.lastMessage);

waitForFinish() 返回以下四种状态之一:

状态 含义
idle 本轮已完成,Agent 可以接收下一条提示词。
permission Agent 需要有人在 Paseo 中回应权限请求。
error Provider 以错误结束了本轮。
timeout 已超过等待截止时间;Agent 可能仍在运行。

超时不会取消 Agent。

为后续提示词保持会话

当提示词稍后才会到来时,创建一个空闲的会话:

const reviewer = await client.agents.create({
  config: {
    provider: "codex/gpt-5.5",
  },
  cwd: "/Users/me/dev/storefront",
  title: "Checkout reviewer",
});

const first = await reviewer.run("Review the current diff.");

if (first.status === "idle") {
  const second = await reviewer.run("Now focus on failure recovery.");
  console.log(second.lastMessage);
}

只管发送、不关心结果时使用 send()。调用方需要该轮的结果时使用 run()。

按标签查找 Agent

创建时设置 labels,之后按标签过滤。匹配由 daemon 完成:

const page = await client.agents.list({
  filter: { labels: { "issue-provider": "my-tracker" } },
});

for (const { agent } of page.entries) {
  console.log(agent.id, agent.title, agent.status);
}

通过 ID 继续 Agent

const agent = client.agents.ref("agent_01H8X...");

const result = await agent.run("Now write the fix.");
console.log(result.lastMessage);

ref() 不会联系 daemon。当你需要知道 Agent 是否仍然存在时,先调用 refresh();如果不存在,它返回 null。

创建子 Agent

通过工作区创建子 Agent。句柄负责位置,因此调用方无需重复提供目录:

if (!parent.workspaceId) throw new Error("Parent has no workspace");

const workspace = client.workspaces.ref(parent.workspaceId);
const child = await workspace.agents.create({
  config: {
    provider: "codex/gpt-5.5",
  },
  parent,
  title: "Implement checkout fix",
  prompt: "Implement the accepted checkout plan and run focused tests.",
});

parent 建立父子关系。归档父 Agent 会级联归档它的子 Agent。如果子 Agent 应该独立继续,请先调用 detach()。

在后台工作区中运行工作

在一次调用中创建一个后台工作区及其第一个 Agent。把 background 放在工作区选项中,把 Agent 的配置放在 agent 下:

const cwd = "/Users/me/dev/storefront";
const workspace = await client.workspaces.create({
  source: { kind: "directory", path: cwd },
  background: true,
  agent: {
    cwd,
    config: { provider: "codex/gpt-5.5" },
    prompt: "Review the checkout flow.",
  },
});

该调用返回一个工作区句柄,并用提供的提示词启动它的第一个 Agent。

后台 Agent 会保留历史记录,并在 daemon 重启后继续存在。默认的发现结果会隐藏它们;使用 client.agents.list({ filter: { includeBackground: true } }) 可以包含它们。精确 ID 的句柄可以正常使用。默认值和调用方继承规则见创建工作区。

请求结构化输出

const schema = {
  type: "object",
  properties: {
    summary: { type: "string" },
    risk: { type: "string", enum: ["low", "medium", "high"] },
  },
  required: ["summary", "risk"],
  additionalProperties: false,
};

const agent = await client.agents.create({
  config: {
    provider: "codex/gpt-5.5",
  },
  cwd: "/Users/me/dev/storefront",
  outputSchema: schema,
  prompt: "Assess the release risk of the current diff.",
});

const result = await agent.waitForFinish();
if (result.status !== "idle" || !result.lastMessage) {
  throw new Error(result.error ?? "Agent returned no structured output");
}

const assessment = JSON.parse(result.lastMessage) as {
  summary: string;
  risk: "low" | "medium" | "high";
};

在把解析出的值作为可信输入使用之前,请在你的应用中校验它。

读取 Agent 的当前状态

const agent = client.agents.ref("agent_01H8X...");
await agent.refresh();

if (agent.pendingPermissions?.length) {
  console.log(`Waiting on ${agent.pendingPermissions.length} permission request(s)`);
}
console.log(agent.lastUsage?.totalCostUsd, agent.runtimeInfo?.sessionId);

句柄以属性的形式提供 status、capabilities、availableModes、pendingPermissions、activeTurn、lastUsage、lastError、features、runtimeInfo、archivedAt、workspaceId 和 cwd。它们读取的都是句柄最近观察到的快照,从不发起请求。

ref() 返回的句柄还没有观察到任何内容,因此在 refresh()、run()、waitForFinish()、时间线重新获取或 subscribe() 投递快照之前,这些属性都是 null。已观察到的快照中的可选值也读作 null。当你需要整个快照,或需要区分这些状态时,请使用 current()。

subscribe() 是一个本地监听器。它的更新来自一个由你持有的 Agent 目录观察:

const unsubscribe = agent.subscribe(() => {
  if (agent.status === "error") console.error(agent.lastError);
});
const directory = await client.agents.list({ subscribe: {} });

// When this view closes:
unsubscribe();
await directory.subscription.release();

列出会话加载的命令

const { commands, error } = await agent.commands();
if (error) throw new Error(error);

const skills = commands.filter((command) => command.kind === "skill");

结果来自正在运行的会话,而不是目录扫描,因此它包含 Provider 内置的、从不出现在磁盘上的命令和技能。kind 是 Provider 自己的分类,且是可选的;缺少 kind 时应视为未分类,而不是假定为 "command"。

无法生成列表的 Provider 会在 error 中报告,并返回空的 commands 数组。该调用不会 reject。

归档或解除父子关系

await agent.archive(); // Soft-deletes the agent and closes its runtime.
await child.detach(); // Keeps the child alive but removes its parent relationship.

关闭 SDK 连接不会归档 Agent。请显式归档临时 Agent,最好放在 finally 中。