Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 幽灵文字也要在用户接受进输入框后才参与识别。

Expand Down Expand Up @@ -516,7 +516,7 @@ pi install npm:pi-intercom
<details>
<summary><strong>模型工具速查</strong></summary>

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。

Expand Down
4 changes: 4 additions & 0 deletions extensions/capabilities/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 检查这个实现",
]) {
Expand All @@ -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"],
Expand Down Expand Up @@ -325,6 +327,8 @@ test("conditional or negated capability boilerplate does not widen the tool surf
"如果需要,请使用子代理。",
"不要使用子代理。",
"不能使用子代理。",
"子代理是什么?",
"子代理的设计有哪些取舍?",
"Do not use OpenPI tools.",
]) {
const h = harness();
Expand Down
8 changes: 8 additions & 0 deletions extensions/capabilities/ui.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ test("highlights capability names only when shared intent authorizes them", () =
"用 <accent>Subagent</accent> 检查,再用 <accent>Workflow</accent> 汇总",
]);

const leadingChinese = editor("子代理了解下项目");
assert.deepEqual(leadingChinese.highlighted.render(120), [
"<accent>子代理</accent>了解下项目",
]);

const named = editor("Subagent 和 Workflow 有什么区别?");
assert.deepEqual(named.highlighted.render(120), [
"<accent>Subagent</accent> 和 <accent>Workflow</accent> 有什么区别?",
Expand All @@ -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", () => {
Expand Down
13 changes: 13 additions & 0 deletions extensions/shared/capability-intent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion extensions/shared/capability-intent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading