fix(i18n): limit subagent terminology changes to requested UI copy

This commit is contained in:
ZiyaZhang
2026-09-23 01:09:27 -07:00
parent f132684c81
commit a2278b460c
17 changed files with 53 additions and 53 deletions
@@ -20,8 +20,8 @@
- button "查看 Agent 循环": Agent 循环
- text: 控制 Agent 派发工具调用的方式。
- listitem:
- button "查看 子智能体": 子智能体
- text: 设置子智能体的递归层级、数量和模型。
- button "查看 Subagent": Subagent
- text: 设置 Subagent 的递归层级、数量和模型。
- listitem:
- button "查看 网页搜索": 网页搜索
- text: 设置 DeepSeek 的搜索提供方。
@@ -1,6 +1,6 @@
- button "返回插件列表": 插件列表
- heading "子智能体" [level=3]
- paragraph: 设置子智能体的递归层级、数量和模型。
- heading "Subagent" [level=3]
- paragraph: 设置 Subagent 的递归层级、数量和模型。
- region "运行限制":
- heading "运行限制" [level=3]
- text: 最大递归深度
@@ -10,16 +10,16 @@
- textbox "最大递归深度":
- /placeholder: ""
- text: "2"
- text: 子智能体并行数量上限
- button "子智能体并行数量上限说明"
- text: Subagent 并行数量上限
- button "Subagent 并行数量上限说明"
- text: 已覆盖
- button "恢复默认"
- textbox "子智能体并行数量上限":
- textbox "Subagent 并行数量上限":
- /placeholder: ""
- text: "12"
- region "模型选择":
- heading "模型选择" [level=3]
- text: 允许智能体为子智能体选择模型
- switch "允许智能体为子智能体选择模型"
- paragraph: 关闭后,子智能体使用配置的默认模型或继承父智能体的模型;已选模型会保留。
- text: 允许 Agent 为 Subagent 选择模型
- switch "允许 Agent 为 Subagent 选择模型"
- paragraph: 关闭后,Subagent 使用配置的默认模型或继承父 Agent 的模型;已选模型会保留。
- button "保存" [disabled]
+16 -16
View File
@@ -93,7 +93,7 @@ describe('web e2e: plugin configuration pages', () => {
const official = panel.locator('[data-plugin-group="official"]')
expect(await official.locator('[data-plugin-package]').count()).toBe(2)
expect(await official.locator('[data-plugin-item]').count()).toBe(4)
for (const title of ['终端', 'Agent 循环', '子智能体', '网页搜索']) {
for (const title of ['终端', 'Agent 循环', 'Subagent', '网页搜索']) {
expect(await official.getByRole('button', { name: `查看 ${title}`, exact: true }).count()).toBe(1)
}
// A card carries the one-liner; the fields wait for the page.
@@ -107,9 +107,9 @@ describe('web e2e: plugin configuration pages', () => {
it('saves subagent limits and resets them to the deployment defaults', async () => {
const panel = await openPlugins()
await openPage(panel, '子智能体')
await openPage(panel, 'Subagent')
const depth = panel.getByLabel('最大递归深度', { exact: true })
const capacity = panel.getByLabel('子智能体并行数量上限', { exact: true })
const capacity = panel.getByLabel('Subagent 并行数量上限', { exact: true })
expect(await depth.inputValue()).toBe('1')
expect(await capacity.inputValue()).toBe('8')
await depth.fill('2')
@@ -119,7 +119,7 @@ describe('web e2e: plugin configuration pages', () => {
await expect.poll(settingsDocument).toContain('maxActiveSubagents: 12')
await expect.poll(settingsDocument).toContain('maxDepth: 2')
await openPlugins()
await openPage(panel, '子智能体')
await openPage(panel, 'Subagent')
const snapshot = await captureStableAria(page, '[data-plugin-panel]', scaffold.workspaceCwd)
await compareOrRefreshGolden(join(SNAPSHOT_DIR, 'subagent.expected.md'), snapshot, MODE)
const controlHeight = await depth.evaluate(element => element.getBoundingClientRect().height)
@@ -132,7 +132,7 @@ describe('web e2e: plugin configuration pages', () => {
await panel.getByRole('button', { name: '保存', exact: true }).click()
await expect.poll(() => panel.getByRole('button', { name: '保存', exact: true }).isDisabled()).toBe(true)
await openPlugins()
await openPage(panel, '子智能体')
await openPage(panel, 'Subagent')
expect(await depth.inputValue()).toBe('1')
expect(await capacity.inputValue()).toBe('8')
await panel.getByRole('button', { name: '返回插件列表', exact: true }).click()
@@ -140,7 +140,7 @@ describe('web e2e: plugin configuration pages', () => {
it('opens field explanations with the keyboard and retains unsaved edits', async () => {
const panel = await openPlugins()
await openPage(panel, '子智能体')
await openPage(panel, 'Subagent')
const depth = panel.getByLabel('最大递归深度', { exact: true })
await depth.fill('2')
const depthHelp = panel.getByRole('button', { name: '最大递归深度说明', exact: true })
@@ -148,31 +148,31 @@ describe('web e2e: plugin configuration pages', () => {
await depthHelp.press('Enter')
const depthRules = panel.getByRole('region', { name: '最大递归深度说明', exact: true })
await depthRules.waitFor()
expect(await depthRules.getByText('限制智能体创建子智能体的递归层级。', { exact: true }).count()).toBe(1)
expect(await depthRules.getByText('限制 Agent 创建 Subagent 的递归层级。', { exact: true }).count()).toBe(1)
const depthTable = depthRules.getByRole('table', { name: '最大递归深度说明', exact: true })
expect(await depthTable.getByRole('row', { name: '0 禁用子智能体', exact: true }).count()).toBe(1)
expect(await depthTable.getByRole('row', { name: '1 仅允许主智能体创建子智能体', exact: true }).count()).toBe(1)
expect(await depthTable.getByRole('row', { name: '0 禁用 Subagent', exact: true }).count()).toBe(1)
expect(await depthTable.getByRole('row', { name: '1 仅允许主 Agent 创建 Subagent', exact: true }).count()).toBe(1)
expect(await depthRules.getByText('如果某个工具单独设置了最大递归深度,以该工具的设置为准。', { exact: true }).count()).toBe(1)
await depthHelp.press('Enter')
expect(await depthRules.count()).toBe(0)
expect(await depth.inputValue()).toBe('2')
await panel.getByRole('button', { name: '子智能体并行数量上限说明', exact: true }).click()
const capacityRules = panel.getByRole('region', { name: '子智能体并行数量上限说明', exact: true })
expect(await capacityRules.getByText('同一主智能体下,所有递归层级同时存活的子智能体总数,主智能体不计入。达到上限时,新的启动请求会被拒绝。', { exact: true }).count()).toBe(1)
await panel.getByRole('button', { name: 'Subagent 并行数量上限说明', exact: true }).click()
const capacityRules = panel.getByRole('region', { name: 'Subagent 并行数量上限说明', exact: true })
expect(await capacityRules.getByText('同一主 Agent 下,所有递归层级同时存活的 Subagent 总数,主 Agent 不计入。达到上限时,新的启动请求会被拒绝。', { exact: true }).count()).toBe(1)
await panel.getByRole('button', { name: '返回插件列表', exact: true }).click()
await openPage(panel, '子智能体')
await openPage(panel, 'Subagent')
expect(await depth.inputValue()).toBe('1')
})
it('saves limits and the model allowlist together from the shared card', async () => {
onTestFailed(() => saveFailureShot(page, 'web-e2e-plugin-config-subagent-model-selection'))
const panel = await openPlugins()
await openPage(panel, '子智能体')
const toggle = panel.getByRole('switch', { name: '允许智能体为子智能体选择模型' })
await openPage(panel, 'Subagent')
const toggle = panel.getByRole('switch', { name: '允许 Agent 为 Subagent 选择模型' })
await panel.getByLabel('最大递归深度', { exact: true }).fill('2')
await toggle.click()
const models = panel.getByRole('group', { name: '智能体可选择的模型' })
const models = panel.getByRole('group', { name: 'Agent 可选择的模型' })
await models.waitFor({ timeout: 10_000 })
const firstModel = models.getByRole('checkbox').first()
await firstModel.check()
+1 -1
View File
@@ -64,7 +64,7 @@
| spawn | spawn | | | |
| steering | steering | steering(中途引导) | | |
| job id | job id | | 任务 id | 保留英文 |
| subagent | subagent | | | 文档正文保留英文;Client UI(含文档中引用的界面文案)固定译作「子智能体」,不使用「子代理」 |
| subagent | subagent | | | 文档正文保留英文;中文 UI 中译作「子智能体」,不使用「子代理」 |
| transcript | transcript | transcript(文本记录) | | 指会话渲染给用户或编辑器的完整文本,区别于事件日志 |
| Typert | Typert | | TypeRT、typeRT、Type RT | DeepSeek Harness 类型图、生成器、loader 与运行时 registry 的产品拼写 |
| waterfall | waterfall | waterfall(瀑布式事件) | | |
@@ -88,7 +88,7 @@ export const guideZh: Record<PresetGuideKey, string> = {
guideStandardIntro: '新建任务时选择「标准模式」,说明要完成什么、相关文件在哪里,以及怎样判断任务完成。',
guideStandardExplanation: [
'### 工作方式',
'Agent 直接调用工具来读写文件、检索资料和执行终端命令。包含 Skills、计划、目标、子智能体、工作流和上下文压缩等能力。',
'Agent 直接调用工具来读写文件、检索资料和执行终端命令。包含 Skills、计划、目标、子 Agent、工作流和上下文压缩等能力。',
'### 什么时候选',
'日常编程、文件处理和资料整理可以从这里开始。标准模式也能编写脚本、批量处理文件;PTC 改变的是工具调用方式,批量任务并不必须使用 PTC。',
].join('\n\n'),
@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/client/ui-chat/src/client/conversation-nodes/README.md
README.md: 3a1660677e173461c353da1d40af3e8adae6d216
README.zh.md: 1b35c8d832fbd35c9a0f46238fbbc07f9aa184c6
README.zh.md: 024ea0f5da55826651611a7059a647b0c6478e08
@@ -245,9 +245,9 @@ Subagent 工具遵循普通分组边界,不会仅因委派任务就单独成
|---|---|
| `subagent`、`subagent_codex`、`subagent_claude_code` 或其他 `subagent_*` 名称 | 每个不同 `callId` 计一次 `subagents`,但先命中更靠前的名称规则时除外;provider 和 model 选择不改变类别。 |
| 配置为 `subagent_inspect` 这样的名称 | 归 `search`:`_inspect` 后缀先于 `subagent_` 前缀匹配;同理,`terminal_inspect` 归 `search` 而不是 `commands`。 |
| subagent 控制工具 `send_message`、`list_agents`、`list_subagent_models`,以及任务控制工具 `job_output`、`job_kill` | 归 `tools`,不归 `subagents`;业务用途不覆盖名称表。 |
| 子代理控制工具 `send_message`、`list_agents`、`list_subagent_models`,以及任务控制工具 `job_output`、`job_kill` | 归 `tools`,不归 `subagents`;业务用途不覆盖名称表。 |
| 委派工具被改为表外名称,例如 `research_agent` | 即使调用相同的 subagent provider,也归 `tools`。 |
| 后台 subagent 的启动调用已返回工具结果,但 subagent 仍在运行 | 保留类别次数,但该调用不再参与运行中活动选择;subagent 的执行不会维持父组的 subagent 活动状态。 |
| 后台 subagent 的启动调用已返回工具结果,但子代理仍在运行 | 保留类别次数,但该调用不再参与运行中活动选择;子代理的执行不会维持父组的 subagent 活动状态。 |
| 工具调用只记录在子 Session 中 | 不纳入父组计数或实时详情;只有实际附在本组成员 `subCalls` 中的调用才递归参与。 |
`run_code` 根调用自身计一次 `code`,已记录的每个 PTC 子调用另按自己的类别计数。不会用叶子调用替代包装调用,也不会把子调用统一归为 `code`。各调用 id 不同时,`run_code → [read, bash, subagent_codex]` 得到 `code=1, read=1, commands=1, subagents=1`,同次数时按此顺序排列。外层 `run_code` 仍在运行时,组的实时类别可以由子调用决定。
@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/client/ui-settings-subagent/README.md
README.md: 66761cc1ca16ecd26e33e84d402a2de186ef1e4f
README.zh.md: cea9a99096a420e7e89e1a7e1daa40d86e9ac0ba
README.zh.md: 5ab125b02f1650a6c4a87159ba5ffc685f82bbf6
@@ -9,7 +9,7 @@ kind: "package-reference"
## 概述
在侧栏打开**插件**,在官方分组里选择 **子智能体**,即可设置委派可以多深、多宽,以及 Agent 可以为 Subagent 选择哪些模型。页面把 Host 的两个命名空间 `subagent` 与 `subagent-model-selection` 收在一次保存之下;Host 服务其中任一命名空间时页面就存在,并只显示被服务的部分。
在侧栏打开**插件**,在官方分组里选择 **Subagent**,即可设置委派可以多深、多宽,以及 Agent 可以为 Subagent 选择哪些模型。页面把 Host 的两个命名空间 `subagent` 与 `subagent-model-selection` 收在一次保存之下;Host 服务其中任一命名空间时页面就存在,并只显示被服务的部分。
## 目录
@@ -25,7 +25,7 @@ kind: "package-reference"
<a id="use-this-package"></a>
## 使用本包
**运行限制**把**最大递归深度**和 **子智能体并行数量上限**并排放置,窄屏时上下堆叠;每个标签旁的信息按钮展开它的规则——深度是一张两行示例表,容量是计数口径——填了不在范围内的整数会阻止保存并在字段下说明。深度让位于工具自己的上限;容量统计同一主 Agent 下所有层级存活的 Subagent,主 Agent 不计入。
**运行限制**把**最大递归深度**和 **Subagent 并行数量上限**并排放置,窄屏时上下堆叠;每个标签旁的信息按钮展开它的规则——深度是一张两行示例表,容量是计数口径——填了不在范围内的整数会阻止保存并在字段下说明。深度让位于工具自己的上限;容量统计同一主 Agent 下所有层级存活的 Subagent,主 Agent 不计入。
**模型选择**把权限开关和精确的适配器路由一起暂存。开启时至少要选一条路由;关闭会保留已选路由以备后用。Host 已存储但没有适配器公布的路由留在**已保存但当前不可用**分组里并且仍可移除;加载失败的提供方会被报告而不隐藏其他提供方,加载失败时提供**重试**。
@@ -69,24 +69,24 @@ export const zh: Record<SubagentSettingsLocaleKey, string> = {
save: '保存',
saving: '保存中…',
saveFailed: '本部署没有接受这些值,已保留供你修改。',
subagentTitle: '子智能体',
subagentDescription: '设置子智能体的递归层级、数量和模型。',
subagentTitle: 'Subagent',
subagentDescription: '设置 Subagent 的递归层级、数量和模型。',
subagentLimitsTitle: '运行限制',
subagentMaxDepth: '最大递归深度',
subagentDepthHelpLabel: '最大递归深度说明',
subagentDepthHelp: '限制智能体创建子智能体的递归层级。',
subagentDepthZero: '禁用子智能体',
subagentDepthOne: '仅允许主智能体创建子智能体',
subagentDepthHelp: '限制 Agent 创建 Subagent 的递归层级。',
subagentDepthZero: '禁用 Subagent',
subagentDepthOne: '仅允许主 Agent 创建 Subagent',
subagentDepthOverride: '如果某个工具单独设置了最大递归深度,以该工具的设置为准。',
subagentMaxActive: '子智能体并行数量上限',
subagentCapacityHelpLabel: '子智能体并行数量上限说明',
subagentCapacityHelp: '同一主智能体下,所有递归层级同时存活的子智能体总数,主智能体不计入。达到上限时,新的启动请求会被拒绝。',
subagentMaxActive: 'Subagent 并行数量上限',
subagentCapacityHelpLabel: 'Subagent 并行数量上限说明',
subagentCapacityHelp: '同一主 Agent 下,所有递归层级同时存活的 Subagent 总数,主 Agent 不计入。达到上限时,新的启动请求会被拒绝。',
subagentDepthInvalid: '请输入不小于 0 的整数。',
subagentCapacityInvalid: '请输入不小于 1 的整数。',
subagentModelSelectionTitle: '模型选择',
subagentModelSelectionToggle: '允许智能体为子智能体选择模型',
subagentModelSelectionChoose: '开启后,智能体可以从下方授权模型中,为每个子智能体选择提供方、模型和推理强度。仅影响新会话。',
subagentModelSelectionAllowed: '智能体可选择的模型',
subagentModelSelectionToggle: '允许 Agent 为 Subagent 选择模型',
subagentModelSelectionChoose: '开启后,Agent 可以从下方授权模型中,为每个 Subagent 选择提供方、模型和推理强度。仅影响新会话。',
subagentModelSelectionAllowed: 'Agent 可选择的模型',
subagentModelSelectionLoading: '正在加载模型…',
subagentModelSelectionLoadFailed: '无法加载模型。',
subagentModelSelectionRetry: '重试',
@@ -96,7 +96,7 @@ export const zh: Record<SubagentSettingsLocaleKey, string> = {
subagentModelSelectionEmpty: '当前没有模型提供方公布模型。',
subagentModelSelectionRequired: '保存前请至少选择一个模型。',
subagentModelSelectionConflict: '设置已在其他位置更新。请放弃修改后重试。',
subagentModelSelectionOff: '关闭后,子智能体使用配置的默认模型或继承父智能体的模型;已选模型会保留。',
subagentModelSelectionOff: '关闭后,Subagent 使用配置的默认模型或继承父 Agent 的模型;已选模型会保留。',
}
/**
@@ -62,7 +62,7 @@ describe('ui-settings-subagent apply', () => {
await vi.waitFor(() => { expect(slots.entries('plugins.item')).toHaveLength(1) })
const entry = slots.entries('plugins.item')[0]!
expect(entry.options).toMatchObject({ id: 'subagent', order: 30 })
expect(resolveSlotLabel(entry.options.label)).toBe('子智能体')
expect(resolveSlotLabel(entry.options.label)).toBe('Subagent')
expect(entry.locale).toBe(NS)
const face = (entry.inject as () => Pick<SubagentCardFace, 'hooks'>)()
expect(Object.keys(face.hooks).sort()).toEqual(['subagentLimitsCard', 'subagentModelSelectionCard'])
@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/client/ui-workspace/README.md
README.md: 7dcff13bc1767051c301174240979873444d4291
README.zh.md: 5b94a759ac6e6e7de0a13a53e4538a069c3b4804
README.zh.md: 1b3e83c71f700976799ff5b93b6fe4c60f896583
+1 -1
View File
@@ -49,7 +49,7 @@ kind: "package-reference"
Session 行内的 Rename 操作打开一个以该行显示标题预填的对话框;确认未修改的标题是有意允许的——这正是把当前自动标题钉住、不再被重新生成覆盖的手势。双击标题也会打开 Rename;对于未归档 Session,先发生的点击会打开其对话。Rename 使用临时 `workspaceOperation` reference,并等待首次历史打开。行内 Fork 在源会话最后一个已完成轮次处 fork,通过 Session Controller 递增继承的持久化标题,不 retain 子会话、不打开其历史,也不改变选择。Workspace 行内的 Delete 操作会打开确认框,说明保留边界;成功后该分组被移除,其 Session 则留在 Ungrouped 下。Pin、Rename、Fork、Archive 本身就是 `sidebar.workspaces.session.menu.item` 列表的条目(pin 与 archive 同时也是 `sidebar.workspaces.session.row.action` 的条目),因此客户端插件的 action 由其 `order` 决定落在哪个位置。
对静止的 Session,Archive 不经确认对话框直接提交,并保留 Session 的记账位置。仍有工作在跑的 Session 是唯一会先询问的情形:Host 拒绝普通归档并列出这些工作,侧栏随即打开"停止并归档"对话框,按族列出——进行中的回合、运行中的 subagent、后台任务、定时提醒,各带名称——并写明恢复路径;确认后请 Host 按停止按钮同样的方式停止这些工作,归档集合持久化后即完成归档,停止在后台收敛;取消则让 Session 继续运行并保持可见。视图选项控制显隐:默认隐藏已归档 Session,显示已归档会将其纳入列表,仅显示已归档则隐藏普通 Session。可见的归档行置灰,并提供无障碍说明,告知取消归档后才能打开;Rename、Fork 与取消归档仍然可用。归档成功后的提示提供"撤销"和"筛选已归档会话"两个动作,后者直接把筛选切到显示已归档;停止并归档显示同样的提示但措辞不同,撤销只恢复 Session,不会让被停止的工作继续。取消归档移除归档标记,但不恢复置顶,也不改变保存的位置。
对静止的 Session,Archive 不经确认对话框直接提交,并保留 Session 的记账位置。仍有工作在跑的 Session 是唯一会先询问的情形:Host 拒绝普通归档并列出这些工作,侧栏随即打开"停止并归档"对话框,按族列出——进行中的回合、运行中的子代理、后台任务、定时提醒,各带名称——并写明恢复路径;确认后请 Host 按停止按钮同样的方式停止这些工作,归档集合持久化后即完成归档,停止在后台收敛;取消则让 Session 继续运行并保持可见。视图选项控制显隐:默认隐藏已归档 Session,显示已归档会将其纳入列表,仅显示已归档则隐藏普通 Session。可见的归档行置灰,并提供无障碍说明,告知取消归档后才能打开;Rename、Fork 与取消归档仍然可用。归档成功后的提示提供"撤销"和"筛选已归档会话"两个动作,后者直接把筛选切到显示已归档;停止并归档显示同样的提示但措辞不同,撤销只恢复 Session,不会让被停止的工作继续。取消归档移除归档标记,但不恢复置顶,也不改变保存的位置。
标题宽于所在行时,静止状态以省略号裁切。把指针停在行上,标题会滚动到远端——例如 fork 递增后的标题——并在揭示时不显示省略号;指针离开后标题回到开头。
+1 -1
View File
@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/subagent/subagent/README.md
README.md: adffd0edfdc55177afee0390c8d1c2f7fbee7999
README.zh.md: ecea304da848079b404e2ba4477b1c02cfe45ffc
README.zh.md: 79d39ca879c8a15385e1e97c6556178b04897fca
+1 -1
View File
@@ -44,7 +44,7 @@ kind: "package-reference"
### 委派设置
**插件 → 子智能体** 页面的限制部分编辑 Host 的 `subagent` 设置分节。用户值覆盖本插件的组合配置;恢复默认会删除用户覆盖。`maxDepth` 默认为 `1`,在委派工具自身未配置深度时提供默认值。工具显式指定的深度(包括 `provider-managed`)优先。深度 `0` 禁止继承此设置的工具委派;深度 `1` 只允许直接子代理。修改在下一次委派时生效。直接调用服务的调用方仍自行提供可选的请求深度。
**插件 → Subagent** 页面的限制部分编辑 Host 的 `subagent` 设置分节。用户值覆盖本插件的组合配置;恢复默认会删除用户覆盖。`maxDepth` 默认为 `1`,在委派工具自身未配置深度时提供默认值。工具显式指定的深度(包括 `provider-managed`)优先。深度 `0` 禁止继承此设置的工具委派;深度 `1` 只允许直接子代理。修改在下一次委派时生效。直接调用服务的调用方仍自行提供可选的请求深度。
### 可续接子代理容量
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -330,7 +330,7 @@ const subsystemGroups = [
['web.md', 'Web 访问', 'Web access'],
['skills.md', '技能', 'Skills'],
['workflow.md', '工作流', 'Workflows'],
['subagent.md', 'Subagent', 'Subagents'],
['subagent.md', '子智能体', 'Subagents'],
]],
['策略与交互', 'Policy and interaction', [
['approval.md', '审批', 'Approvals'],