diff --git a/README.md b/README.md index aa2b487e..291331d5 100644 --- a/README.md +++ b/README.md @@ -77,8 +77,8 @@ OpenPI 会把长期进程放到后台,把独立任务交给隔离 Context 的 > [!TIP] > Capability discovery 默认 `explicit`:明确说出能力意图才会加载对应组。英文 `subagent` 与 `workflow` 是保留授权词,单独输入也会加载对应能力。 -> 例如 `subagent, workflow` → 同时加载两组;「在后台运行 dev server」→ 后台终端;「用/使用子代理检查」→ Subagent;「用工作流编排」→ Workflow;「用 fd/rg 搜索」或「用 git diff 比较分支」→ 搜索与只读 Git 工具。 -> 关键是把意图说清楚(说「用子代理」「后台运行」这类带动作的短语),不需要记住任何工具名。 +> 例如 `subagent, workflow` → 同时加载两组;「在后台运行 dev server」→ 后台终端;「用/使用子代理检查」或句首「子代理了解下项目」→ Subagent;「用工作流编排」→ Workflow;「用 fd/rg 搜索」或「用 git diff 比较分支」→ 搜索与只读 Git 工具。 +> 关键是把意图说清楚(说「用子代理」「子代理检查项目」「后台运行」这类带执行动作的短语),不需要记住任何工具名。仅讨论能力的「子代理是什么」不会加载;否定或条件表达也继续 fail closed。 > `/plan` 是一个运行时安全例外:进入或恢复 Plan Mode 时会为当前 Session 自动加载 `search` 组,让只读调研直接使用结构化 Git 工具。 > 在交互输入框中,保留词 `Subagent` / `Workflow`,以及已被识别的中文能力请求,会使用 Claude Code 风格的薰衣草紫显示;浅色终端自动使用更深的紫色以维持可读性。变色表示提交后会加载对应能力。因为英文名称本身就是授权词,讨论中写出它们也会开闸;条件句和否定句仍保持普通显示,Suggestion 幽灵文字也要在用户接受进输入框后才参与识别。 @@ -516,7 +516,7 @@ pi install npm:pi-intercom
模型工具速查 -Capability discovery 默认是 `explicit`:普通父 Session 不常驻任何 OpenPI 模型工具,首轮保持 Pi 原生 `read`、`bash`、`edit`、`write`。用户明确要求结构化搜索、Subagent、Workflow、后台进程或 Session Goal/Tasks 时,OpenPI 在 `before_agent_start` 直接加载对应能力组;明确询问 OpenPI capabilities/tools/features 时显示 `openpi_load_tools`。可通过 `/openpi-setup` 显式选择 `adaptive`:此时只让小型 `openpi_load_tools` 网关常驻,模型可在判断任务确实受益时自主加载一个能力组。该选择也授权模型启动该组内的昂贵工作,因此不作为默认值。条件句(例如 “If you delegate…”)不会被当成显式委派意图。能力组在当前 Session 内单调保持,避免反复增删工具破坏缓存。Delegate 一经加载便一次性开放完整、稳定的 Subagent 工具族;资源不存在时由工具执行层明确返回空状态或 fail-closed,而不再按实例生命周期改变模型接口。其他组内管理工具仍只在资源成功创建或状态确实存在后出现。Mode / Setup / Context 工具独立跟随实时状态显示和隐藏。Background、Subagent 与 Workflow 的 Skill 文件仍随包发布,但只在对应能力触发后提示读取,不常驻普通系统 Prompt。 +Capability discovery 默认是 `explicit`:普通父 Session 不常驻任何 OpenPI 模型工具,首轮保持 Pi 原生 `read`、`bash`、`edit`、`write`。用户明确要求结构化搜索、Subagent、Workflow、后台进程或 Session Goal/Tasks 时,OpenPI 在 `before_agent_start` 直接加载对应能力组;明确询问 OpenPI capabilities/tools/features 时显示 `openpi_load_tools`。可通过 `/openpi-setup` 显式选择 `adaptive`:此时只让小型 `openpi_load_tools` 网关常驻,模型可在判断任务确实受益时自主加载一个能力组。该选择也授权模型启动该组内的昂贵工作,因此不作为默认值。句首「子代理了解下项目」这类带执行动作的表达会加载 Delegate;「子代理是什么」这类讨论、否定表达和条件句(例如 “If you delegate…”)不会被当成显式委派意图。能力组在当前 Session 内单调保持,避免反复增删工具破坏缓存。Delegate 一经加载便一次性开放完整、稳定的 Subagent 工具族;资源不存在时由工具执行层明确返回空状态或 fail-closed,而不再按实例生命周期改变模型接口。其他组内管理工具仍只在资源成功创建或状态确实存在后出现。Mode / Setup / Context 工具独立跟随实时状态显示和隐藏。Background、Subagent 与 Workflow 的 Skill 文件仍随包发布,但只在对应能力触发后提示读取,不常驻普通系统 Prompt。 普通产品默认采用 Pi-native execution:保留 Pi 原生完整历史、工具输出上限、Session compaction、显式 Bash timeout 与 provider loop,不再额外做固定事务投影、成功 Bash 二次裁剪、测试 timeout 改写、重复失败硬拦或恢复/轨迹提示。OpenPI 只保留独立的工作区安全边界:阻止未授权删除 pre-existing 路径,并从实际文件状态识别本轮通过原生写入、文字重定向或 literal `mkdir -p` 创建的 scratch,避免误拦其清理。旧执行策略仅保留为受 benchmark root 门控的实验 profile,不会进入普通 Session。 diff --git a/extensions/capabilities/index.test.ts b/extensions/capabilities/index.test.ts index 06f339f1..ece60652 100644 --- a/extensions/capabilities/index.test.ts +++ b/extensions/capabilities/index.test.ts @@ -254,6 +254,7 @@ test("reserved capability words load their groups without action verbs", () => { test("common Chinese and multi-agent delegation requests are explicit intent", () => { for (const prompt of [ "来多子代理一起讨论", + "子代理了解下项目", "Use multiple subagents.", "用 Subagent 检查这个实现", ]) { @@ -280,6 +281,7 @@ test("the README quick-start example and its advertised phrases load capabilitie // Every phrase the README TIP advertises as a trigger must actually match. const advertised: Array<[string, string]> = [ ["在后台运行 dev server", "bg_start"], + ["子代理了解下项目", "subagent_spawn"], ["用子代理检查", "subagent_spawn"], ["使用子代理检查", "subagent_spawn"], ["用工作流编排", "workflow"], @@ -325,6 +327,8 @@ test("conditional or negated capability boilerplate does not widen the tool surf "如果需要,请使用子代理。", "不要使用子代理。", "不能使用子代理。", + "子代理是什么?", + "子代理的设计有哪些取舍?", "Do not use OpenPI tools.", ]) { const h = harness(); diff --git a/extensions/capabilities/ui.test.ts b/extensions/capabilities/ui.test.ts index d654f7c9..8302e9f8 100644 --- a/extensions/capabilities/ui.test.ts +++ b/extensions/capabilities/ui.test.ts @@ -86,6 +86,11 @@ test("highlights capability names only when shared intent authorizes them", () = "用 Subagent 检查,再用 Workflow 汇总", ]); + const leadingChinese = editor("子代理了解下项目"); + assert.deepEqual(leadingChinese.highlighted.render(120), [ + "子代理了解下项目", + ]); + const named = editor("Subagent 和 Workflow 有什么区别?"); assert.deepEqual(named.highlighted.render(120), [ "SubagentWorkflow 有什么区别?", @@ -95,6 +100,9 @@ test("highlights capability names only when shared intent authorizes them", () = assert.deepEqual(negated.highlighted.render(120), [ "不要用 Subagent,也不要用 Workflow", ]); + + const discussion = editor("子代理是什么?"); + assert.deepEqual(discussion.highlighted.render(120), ["子代理是什么?"]); }); test("supports English plurals and Chinese capability names", () => { diff --git a/extensions/shared/capability-intent.test.ts b/extensions/shared/capability-intent.test.ts index e4f14f74..60db4c54 100644 --- a/extensions/shared/capability-intent.test.ts +++ b/extensions/shared/capability-intent.test.ts @@ -14,6 +14,9 @@ test("classifies explicit capability intent across English, Chinese, and mixed p capabilitiesRequestedByPrompt("用 Subagent 并行检查这三个模块"), ["delegate"], ); + assert.deepEqual(capabilitiesRequestedByPrompt("子代理了解下项目"), [ + "delegate", + ]); assert.deepEqual( capabilitiesRequestedByPrompt("Use subagents to review this change"), ["delegate"], @@ -46,6 +49,16 @@ test("negation and conditional language remain fail-closed", () => { } }); +test("Chinese discussion of subagents does not authorize delegation", () => { + for (const prompt of [ + "子代理是什么?", + "子代理的设计有哪些取舍?", + "聊聊子代理的设计", + ]) { + assert.deepEqual(capabilitiesRequestedByPrompt(prompt), [], prompt); + } +}); + test("gateway intent shares the same negation policy", () => { assert.equal(requestsCapabilityGateway("Show OpenPI capabilities."), true); assert.equal(requestsCapabilityGateway("Do not use OpenPI tools."), false); diff --git a/extensions/shared/capability-intent.ts b/extensions/shared/capability-intent.ts index 743761a3..f7da1d54 100644 --- a/extensions/shared/capability-intent.ts +++ b/extensions/shared/capability-intent.ts @@ -7,7 +7,7 @@ const CAPABILITY_INTENT = { search: /\b(?:use|run)\s+(?:fd|rg)\b|\buse\s+(?:structured\s+)?(?:(?:file|code|content)\s+)?search\b|\b(?:structured|fast)\s+(?:file|code|content)\s+search\b|(?:使用|用|运行).{0,8}(?:fd|rg|git\s+(?:show|diff|log))|结构化(?:文件|代码|内容)搜索/iu, delegate: - /\bsubagents?\b|(?:^|[.!?]\s+)(?:please\s+)?(?:delegate|parallelize)\s+(?:this|the)\s+(?:task|work)\b|\b(?:can|could|would)\s+you\s+(?:please\s+)?(?:delegate|parallelize)\s+(?:this|the)\s+(?:task|work)\b|\bparallel\s+agents?\b|(?:使用|用|启动|调用|来|开).{0,8}子代理|(?:多个?|多路)子代理|并行.{0,8}(?:代理|agent)|委派.{0,6}(?:任务|给|出去)/iu, + /\bsubagents?\b|(?:^|[.!?]\s+)(?:please\s+)?(?:delegate|parallelize)\s+(?:this|the)\s+(?:task|work)\b|\b(?:can|could|would)\s+you\s+(?:please\s+)?(?:delegate|parallelize)\s+(?:this|the)\s+(?:task|work)\b|\bparallel\s+agents?\b|^\s*子代理\s*[,,::]?\s*(?:(?:来|去|请|帮(?:我|忙)?|负责|给我)\s*)?(?:(?:先|全面|系统(?:性地)?|深入|快速|仔细)\s*)?(?:了解|查看|检查|审查|分析|研究|调研|梳理|探索|实现|修复|处理|执行|完成|阅读|总结)|(?:使用|用|启动|调用|来|开).{0,8}子代理|(?:多个?|多路)子代理|并行.{0,8}(?:代理|agent)|委派.{0,6}(?:任务|给|出去)/iu, workflow: /\bworkflows?\b|(?:使用|用|运行|创建|构建).{0,8}工作流/iu, background: /\b(?:run|start|keep)\b.{0,40}\b(?:in the background|background\s+(?:process|terminal|job))\b|后台.{0,8}(?:运行|启动|进程|终端|任务)/iu,