内容
<div align="center">
# 🧵 pi-fabric
**适用于 [Pi](https://github.com/earendil-works/pi-coding-agent) 的可编程工具和代理运行时**
_一种用于工具、MCP、代理、工作流、演员、网格、委员会和递归的 类型检查程序。_
<p>
<img src="https://raw.githubusercontent.com/monotykamary/pi-fabric/main/media/cover.jpg" alt="Pi Fabric 在 Pi TUI 中组合工具和代理" width="1100">
</p>
[](https://www.npmjs.com/package/pi-fabric)
[](https://github.com/monotykamary/pi-fabric/actions/workflows/test.yml)
[](https://github.com/earendil-works/pi-coding-agent)
[](LICENSE)
</div>
---
Pi Fabric 将工具使用转化为代码。模型看到一个 `fabric_exec` 工具,并编写类型检查的 TypeScript 代码,可以组合 Pi 的核心工具、延迟捕获的扩展工具、MCP 服务器、子代理、持久演员和耐用协调。中间值保留在 QuickJS 沙盒中;只有最终结果返回到模型上下文中。
## 为什么是 Fabric?
| | 功能 | 解锁内容 |
| :-: | ---------- | --------------- |
| ⚡ | **代码模式** | 一个扁平的工具模式;分支、循环、扇出和数据流在类型检查的 TypeScript 中生效。 |
| 🧰 | **能力路由** | 通过一个运行时调用 Pi 核心工具、捕获的扩展工具、MCP 服务器或显式 Fabric 提供程序。 |
| 🧑🤝🧑 | **代理运行时** | 运行一次性的工作程序、持久的事件驱动演员、委员会和有界递归查询。 |
| 🕸️ | **工作流 + 网格** | 跟踪阶段和进度,同时协调耐用主题、共享任务和比较-交换状态。 |
| 🛡️ | **防护栏** | 在主机桥上强制执行审批、隔离、超时、并发性、递归深度和共享成本预算。 |
| 🎛️ | **原生 TUI** | 查看结构化的嵌套预览、实时活动、交互式仪表板和设置,而无需离开 Pi。 |
## 安装
从 npm:
```bash
pi install npm:pi-fabric
```
从 GitHub:
```bash
pi install git:github.com/monotykamary/pi-fabric
```
从本地checkout:
```bash
pnpm install
pnpm build
pi install /absolute/path/to/pi-fabric
```
对于一次开发运行:
```bash
pi -e /absolute/path/to/pi-fabric
```
需要 Node.js 24 或更新版本和 Pi 0.80.6 或更新版本。
## 快速入门
要求 Fabric 组合多个操作在一个调用中:
```ts
const [manifest, sources] = await Promise.all([
pi.read({ path: "package.json" }),
pi.find({ pattern: "**/*.ts", path: "src" }),
]);
return {
package: JSON.parse(manifest).name,
sourceCount: sources.split("\n").filter(Boolean).length,
};
```
只有返回的值进入父模型的上下文中。其他内容都保留在执行中。
## 代码 API
在默认的完整代码模式下,`fabric_exec` 独家拥有 Pi 核心工具执行。父模型看到一个可编程工具,而不是直接的 `read`、`bash`、`edit`、`write`、`grep`、`find` 和 `ls` 模式。Fabric 程序通过 `pi.*` 使用这些功能:
```ts
const files = await pi.find({ pattern: "**/*.ts", path: "src" });
const matches = await pi.grep({ pattern: "TODO", path: "src" });
return { files, matches };
```
独立调用应该是并行的:
```ts
const [packageJson, readme] = await Promise.all([
pi.read({ path: "package.json" }),
pi.read({ path: "README.md" }),
]);
return {
package: JSON.parse(packageJson).name,
readmeLines: readme.split("\n").length,
};
```
### 完整代码模式
`fullCodeMode: true` 是默认的。Fabric 删除了父模型中活跃的 Pi 核心工具,并仅在 `fabric_exec` 中通过 `pi.*` 公开它们。注册的重写功能(如安全门和代码预览)也会被捕获,因此 `pi.read()` 继续通过重写路由,而不是绕过它。
Fabric 记得在接管之前哪些原生核心工具是活跃的。切换到仅编排模式或卸载 Fabric 会恢复该选择。在完整模式下,所有权在用户输入和代理启动之前重新断言,因此在此期间手动重新启用的工具不会泄漏回父模式中。
### 仅编排模式
用户希望使用 Fabric 进行 MCP、代理、环境演员、并行工作流、委员会和递归委托,但希望 Pi 的核心工具保持完全原生,可以选择退出完整代码模式:
```json
{
"fullCodeMode": false
}
```
在仅编排模式下:
- Pi 的 `read`、`bash`、`edit`、`write`、`grep`、`find` 和 `ls` 工具保留在 Pi 的正常模型面向和执行路径中。
- 注册的扩展工具也保留在 Pi 的原生注册表中;Fabric 不会隐藏、包装或通过 `extensions.*` 公开它们。
- `pi.*`、`extensions.*` 和等效的 `tools.call()` 引用在 `fabric_exec` 内不可用,包括当 TypeScript 检查被绕过时。
- MCP 提供程序、一次性和递归代理、持久环境演员、动态工作流、网格协调、委员会、显式 Fabric 提供程序和 Fabric TUI 仍然可用。
- 子代理继续使用其允许的 Pi 工具直接路由,因此并行和环境设置不会将它们的编码操作路由回 Fabric 代码模式。
默认值为 `true`。项目可以在 `.pi/fabric.json` 中设置标志,或用户可以在 `~/.pi/agent/fabric.json` 中全局设置。
### 发现和通用调用
```ts
const providers = await tools.providers();
const candidates = await tools.search({ query: "GitHub issues" });
const schema = await tools.describe({ ref: candidates[0].ref });
const result = await tools.call({
ref: schema.ref,
args: { query: "is:open label:bug" },
});
return result;
```
### 捕获的扩展工具
当启用 `fullCodeMode` 时,Fabric 拦截 Pi 的 `ExtensionRunner.getAllRegisteredTools()` 注册检查点。这捕获了其他扩展在启动时或稍后通过 `pi.registerTool()` 注册的工具,无论这些扩展是否在 Fabric 之前或之后加载。
捕获的自定义工具默认情况下从 Pi 的模型面向注册表中删除,因此它们的模式、代码段和指南不会占用父模型上下文。扩展本身仍然加载:它的命令、事件处理程序、状态和 UI 继续工作。只有工具发现和调用变成延迟的。
```ts
const matches = await tools.search({ query: "deployment status" });
const schema = await tools.describe({ ref: matches[0].ref });
const result = await tools.call({
ref: schema.ref,
args: { environment: "staging" },
});
return result;
```
对于有效为 JavaScript 属性名称的工具名称,请使用较短的代理:
```ts
const result = await extensions.project_status({ verbose: true });
return result.text;
```
结果保留 `content`、`text` 内容、`details`、`isError`、`terminate` 和源出处。Fabric 运行捕获的定义的 `prepareArguments()` 和原始执行器及其所属扩展上下文。Pi 的 `tool_calls`、`tool_result` 和 `tool_execution_*` 生命周期处理程序也应用于嵌套调用。
在完整代码模式下,核心工具的重写被捕获并隐藏其内置对应项。Fabric 中的 `pi.read`、`pi.bash` 等内置函数会自动通过捕获的重写路由,当存在时;`extensions.read` 公开重写的完整原生结果形状。`capture.keepVisible` 可以保留非核心扩展工具在 Pi 的直接注册表中,但核心工具名称在完整代码模式下始终被排除。
### 通过 mcporter 进行 MCP
Pi Fabric 使用公共的 [`mcporter`](https://github.com/openclaw/mcporter) 运行时。它继承了 mcporter's 配置发现、导入、OAuth 缓存和连接池。
```ts
const servers = await mcp.servers(); // 名称和传输元数据;凭证从不暴露
const result = await mcp.context7.resolve_library_id({
libraryName: "react",
query: "hooks documentation",
});
return result;
```
在更改 mcporter 配置后使用 `await mcp.reload()`。当服务器或工具名称无法方便地表示为属性访问时,可以使用 `mcp.call({ server, tool, args })`。
程序可以直接在 mcporter's 池运行时中注册一个临时服务器:
```ts
await mcp.register({
name: "project-docs",
command: "npx",
args: ["-y", "@example/docs-mcp"],
cwd: ".",
});
return mcp.project_docs.search({ query: "authentication" });
```
HTTP 服务器使用 `baseUrl` 代替 `command`。动态定义在 `mcp.reload()` 或会话关闭之前生效;它们不会写入配置文件。
### 动态工作流
Fabric 程序已经在代码中保留编排和中间值。工作流全局变量添加了 Claude Code 风格的名称和进度阶段,而无需引入第二个 JavaScript 运行时:
```ts
await workflow.configure({
name: "身份验证审计",
description: "发现相关文件,并行审计,然后验证发现结果",
});
await phase("发现", { total: 1 });
const inventory = await agent<{ files: string[] }>(
"列出与身份验证相关的源文件。",
{
label: "身份验证清单",
tools: ["read", "grep", "find", "ls"],
schema: {
type: "object",
properties: { files: { type: "array", items: { type: "string" } } },
required: ["files"],
additionalProperties: false,
},
},
);
await phase("审计", { total: inventory.files.length });
const findings = await parallel(
inventory.files.map(
(file) => () =>
agent(`审计 ${file} 以查找具体的安全缺陷。`, {
label: `audit ${file}`,
tools: ["read", "grep", "find", "ls"],
}),
),
{ concurrency: 8 },
);
await phase("验证", { total: 1 });
return agent(`验证并综合这些发现结果:${JSON.stringify(findings)}`, {
label: "验证发现结果",
tools: ["read", "grep", "find", "ls"],
});
```
可用的帮助程序包括 `workflow.agent()`、`workflow.parallel()`、`workflow.pipeline()`、`workflow.configure()`、`workflow.phase()`、`workflow.item()`、`workflow.event()`、`workflow.log()` 和 `workflow.budget`。`configure()` 命名活动范围;阶段选项接受 `id`、`description` 和预期的 `total`。`item()` 允许任意非代理工作报告状态、详细信息和进度,而无需自定义渲染器。`event()` 在运行日志中添加一个有界的里程碑。较短的 `agent()`、`parallel()`、`pipeline()`、`phase()`、`log()` 和 `budget` 别名是等价的。`fabric_exec` 接受可选的 `agentBudget` 和 `tokenBudget` 限制;配置提供每个执行的硬上限。
JSON 模式的代理请求使工作程序通过 `result.value` 返回验证的结构化数据。工作流帮助程序直接返回该值,否则返回代理的最终文本。
### 子代理
```ts
const result = await agents.run({
name: "安全审查",
task: "审查当前差异的具体安全缺陷。不要编辑文件。",
transport: "localterm",
tools: ["read", "grep", "find", "ls"],
});
return result;
```
后台句柄是显式的:
```ts
const handle = await agents.spawn({
task: "映射持久层并确定其公共入口点。",
transport: "tmux",
});
// 在此处执行独立工作。
return await agents.wait({ id: handle.id });
```
子继承父模型,除非指定 `model`。它们的工具允许列表默认为 `subagents.defaultTools`。它们的推理努力默认为 `subagents.thinking`(默认为 `medium`),除非调用或演员设置 `thinking`;该级别被限制在每个模型的支持级别,选择下一个最高级别,如果请求级别不受支持。
支持的传输:
| 传输 | 行为 | 附加命令 |
| ----------- | ---------------------------------------------------------- | ---------------------------- |
| `process` | detached 本地工作进程;默认和最低开销 | 无 |
| `tmux` | 一个分离的 tmux 会话,每个子进程一个 | `tmux attach-session -t …` |
| `screen` | 一个分离的 GNU Screen 会话,每个子进程一个 | `screen -r …` |
| `localterm` | 一个固定的 LocalTerm PTY 子进程 | `localterm session attach …` |
| `auto` | 尝试 LocalTerm、tmux、screen,然后是进程 | 传输特定 |
LocalTerm 已经公开了所需的 tmux 平价原语:分离创建、固定、列表、捕获、执行、附加和杀死。Pi Fabric 因此不需要 LocalTerm 补丁。启动其守护进程:
```bash
localterm start
```
使用 `/fabric agents` 列出子进程,并使用 `/fabric attach <id>` 显示适当的附加命令。终止信号会传播到传输和子进程 Pi 进程。
设置 `worktree: true` 以创建专用 Git 工作树和 `pi-fabric/<name>-<id>` 分支。工作树保留检查,直到调用 `agents.cleanup()`。
### 持久演员和环境代理
`agents.create()` 创建一个命名演员,具有持久的 Pi 会话、序列化邮箱和可选的父会话事件或耐用网格主题订阅:
```ts
return agents.create({
name: "auth-supervisor",
instructions: `监视主会话,直到身份验证迁移完成并经过测试。
优先保持沉默。仅在发生实质性漂移、阻塞或验证完成时回复指令。`,
events: ["agent_settled", "tool_error"],
responseMode: "directive",
delivery: "steer",
triggerTurn: true,
thinking: "high",
tools: ["read", "grep", "find", "ls"],
});
```
这是涌现的监管者和顾问的基元;两者都不需要另一个扩展程序。主机事件包括有界的最近会话快照。演员一次处理一个消息,默认情况下合并重复的主机事件,在其自己的会话文件中保留模型上下文,并在同一个 Pi 会话被重新打开受信任的项目时恢复。每个演员的推理努力是其 `thinking` 级别(`off`、`minimal`、`low`、`medium`、`high`、`xhigh`、`max`),默认为 `subagents.thinking`(`medium`),并限制在模型的支持级别;可以在创建时更改或使用仪表盘上的 `e` 更改。
有两个响应模式:
- `text`: 每个非空响应成为演员出站消息。
- `directive`: 验证 `{ action: "silent" | "message" | "stop", message?, data? }` 输出让演员决定干预是否有用。
交付可以保留在 `mailbox` 或进入主会话作为 `steer`、`followUp` 或 `nextTurn`。创建者修复交付策略;演员不能在响应中升级它。使用 `agents.ask()` 进行阻塞交换,使用 `agents.tell()` 进行无需回应的邮件,使用 `agents.messages()` 获取历史记录,使用 `agents.remove()` 进行清理。
### 耐用网格协调
`mesh` API 是一个项目范围的、基于事件的协调基板:
```ts
const event = await mesh.publish({
topic: "team.auth",
kind: "finding",
text: "Refresh-token rotation is not atomic",
data: { path: "src/auth/refresh.ts" });
const task = await mesh.put({
key: "tasks/auth-review",
value: { status: "ready", owner: null },
ifVersion: 0 });
const claimed = await mesh.put({
key: task.key,
value: { status: "claimed", owner: "security-reviewer" },
ifVersion: task.version },
return { event, claimed };
```
主题提供耐用通道和直接消息功能,具有序列游标。`mesh.members()` 发现 Fabric 会话中的演员存在。版本 `get`/`put`/`delete` 操作提供任务声明、租赁、预留和决策的比较-交换状态。与持久演员一起,这些足以在 Fabric 代码中表达信使风格的群集,而无需守护进程或固定的规划器/工作角色。
### 委员会
```ts
return council.run({
task: "审查当前实现并推荐是否准备好合并。",
roles: ["correctness reviewer", "security reviewer", "test reviewer"],
transport: "localterm",
synthesize: true,
});
```
委员会成员并发运行在全局子代理信号量下。启用 `synthesize: true` 时,最终的子代理协调他们的报告。
### 递归查询
```ts
return rlm.query({
task: "递归分解存储库并生成一个紧凑的架构图。",
transport: "process",
});
```
`rlm.query()` 是 `agents.run()`,并在子进程中启用 Fabric。递归拒绝在 `subagents.maxDepth` 处拒绝。批准初始递归调用仅委托 `agent` 风险能力;网络、执行和写入批准不继承。每个 Fabric 进程强制执行其自己的配置的并发性和超时限制。当 `subagents.budgetUsd` 设置时,共享的追加成本账本限制整个递归树上的总支出:每个节点记录它生成的子进程的成本,并继承环境,每个节点拒绝新的子进程达到预算。检查是最佳努力的(并发的子进程可以每个都通过,而任何成本落地,因此树可能会略微超出)。结果和实时状态的每个递归子进程带有 `budget` 摘要(`limit`、`spent`、`remaining`、`tokens`)。
## 包含的技能
Pi 自动发现这些软件包技能:
| 命令 | 模式 |
| --- | --- |
| `/skill:fabric-supervisor <目标>` | 由 `agent_settled` 和工具错误事件驱动的持久目标监视器 |
| `/skill:fabric-advisor [焦点]` | 决策点同行评审(空闲和工具错误)优先考虑沉默 |
| `/skill:fabric-ambient <角色>` | 自定义事件驱动环境演员的元模式 |
| `/skill:fabric-workflow <任务>` | 代码控制阶段、扇出、管道、结构化输出和合成 |
| `/skill:fabric-rlm <任务>` | 通过 `rlm.query()` 进行递归自我委托,适用于超出一个上下文窗口的任务 |
| `/skill:fabric-swarm <目标>` | 持久演员、持久主题和基于 CAS 的共享任务 |
| `/skill:fabric-council <决策>` | 有限独立视角加合成 |
`fabric-exec` 是可发现的引用技能:它包含完整的 `fabric_exec` API(核心 `pi.*` 工具、`tools` 发现、`π` 字符串、错误恢复)以及 MCP、代理/rlm 和网格的引用文件,通过相对路径加载(不是单独的技能)。它出现在 `<available_skills>` 中;在第一次 `fabric_exec` 调用之前或调用出错时通过 `read` 加载它。
监督者和顾问是刻意设计成技能而不是硬编码的主机服务:技能编写普通的 Fabric 代码,通过与每个其他模式可用的相同演员原始操作。
## 视觉集成
`fabric_exec` 使用公共的 `pi-code-previews` 协作 shell。它继承用户的边框/背景模式、折叠结果行为、错误样式和工具调用计时,不接管 Pi 的内置工具渲染器。其渲染器添加编号的 TypeScript 预览、实时阶段/调用活动和紧凑的阶段/嵌套调用摘要。嵌套的 `pi.read`/`pi.bash`/`pi.grep`/`pi.find`/`pi.ls`/`pi.write`/`pi.edit` 调用呈现为结构化预览(路径/命令头、编号内容)而不是原始 JSON。`pi.read` 和 `pi.write` 内容使用与 `pi-code-previews` 配置相同的 shiki 主题进行语法高亮,因此颜色与 Pi 的原生工具预览相匹配;`pi.bash` 命令在调用标题中高亮显示,`pi.edit` 操作呈现为 `+`/`-` 行差异(带有共享上下文)使用 Pi 核心的差异颜色。高亮器惰性初始化,并在准备好之前回落到纯文本。折叠的预览显示配置的展开快捷键(例如 `Ctrl-O`)以展开,匹配 Pi 的内置工具预览。用户无需单独安装 `pi-code-previews`。
Fabric 还拥有一个通用的、主题感知的活动表面,适用于任何代理设置:
- 聊天上方的一个紧凑小部件(类似 `pi-supervisor`)跟随当前阶段并显示活动代理、演员、工具、自定义项目、共享任务、令牌使用和已用时间。在普通运行变得安静后,它会消失,而持久演员仍然作为一个紧凑的环境行可见。
- `/fabric dashboard` 打开一个响应式交互式叠加层。宽终端使用类似 Claude-workflow 样式的阶段窗格位于代理和工作项旁边;窄终端堆叠相同的面板。代理详细信息包括任务、模型、当前工具、使用情况、结果、工作树和附加元数据。演员邮箱、网格状态和最近的网格事件使用相同的视图而不是角色特定的屏幕。在演员详细信息视图中,按 `m` 打开模型选择器并更改该演员的模型,或按 `e` 打开思考(推理努力)选择器并更改该演员的 `thinking` 级别(或选择继承以回退到 Fabric 默认);这两种更改都将持续到演员注册表并在演员的下一次运行中生效。
- `/fabric settings` 打开一个内联设置视图,镜像 Pi 核心的 `/settings`(顶部和底部边框、模糊搜索、部分子菜单)并将更改写入 `fabric.json`。受信任的项目写入 `<project>/.pi/fabric.json`;不受信任的会话写入全局 `~/.pi/agent/fabric.json`。完整代码模式、捕获、执行器、批准和 UI 更改立即生效;网格、子代理和 MCP 更改持续存在,并在下一个 `/fabric reload` 生效。`subagents.defaultTools` 和 `capture.keepVisible` 的列表编辑器切换已知工具的开启和关闭;`keepVisible` 候选包括 `fabric_exec` 以及每个捕获的扩展工具。
- `↑`/`↓` 或 `j`/`k` 选择,`←`/`→` 或 Tab 切换面板,Enter 进入详细信息,`f` 循环状态过滤器,`[`/`]` 切换保留的运行,`m` 更改演员的模型,`e` 更改其思考级别从详细信息视图,Esc 退出或关闭。
该表面是数据驱动的。Fabric 自动检测嵌套提供者调用、子代理、持久演员和任务形的网格条目。工作流可以添加领域特定的标签和任意进度,而无需添加扩展 UI 代码:
```ts
await workflow.configure({ name: "发布列车", description: "构建、验证和发布" });
await phase("构建", { total: packages.length });
await workflow.item({
id: "文档",
label: "文档",
status: "运行中",
completed: 2,
total: 5,
});
await workflow.event({ message: "金丝雀已通过", level: "成功" });
```
外部 Fabric 提供者可以发出结构化的 `context.activity()` 更新,用于实体、进度消息或指标。这使得 TUI 保持通用,同时允许虚拟提供者公开更丰富的实时状态。
## 配置
Pi Fabric 读取:
1. `~/.pi/agent/fabric.json`
2. `<project>/.pi/fabric.json`,仅适用于受信任的项目
项目值覆盖全局值。
```json
{
"fullCodeMode": true,
"executor": {
"timeoutMs": 120000,
"memoryLimitBytes": 67108864,
"maxOutputChars": 100000,
"maxNestedResultChars": 2000000
},
"approvals": {
"read": "允许",
"write": "允许",
"execute": "允许",
"network": "允许",
"agent": "允许"
},
"capture": {
"enabled": true,
"hideFromModel": true,
"keepVisible": ["fabric_exec"],
"defaultRisk": "执行",
"risks": {
"read": "读取",
"grep": "读取",
"find": "读取",
"ls": "读取",
"edit": "写入",
"write": "写入",
"bash": "执行"
}
},
"mcp": {
"enabled": true,
"disableOAuth": true,
"allowDynamicServers": true,
"callTimeoutMs": 120000
},
"subagents": {
"enabled": true,
"transport": "进程",
"thinking": "中等",
"maxConcurrent": 4,
"maxPerExecution": 100,
"maxDepth": 2,
"timeoutMs": 600000,
"extensions": true,
"defaultTools": ["read", "bash", "edit", "write", "grep", "find", "ls"],
"retainRuns": false,
"notifyOnComplete": true,
"budgetUsd": 0
},
"ui": {
"enabled": true,
"widget": "自动",
"maxRows": 6,
"refreshMs": 500,
"lingerMs": 10000,
"eventHistory": 80
},
"mesh": {
"enabled": true,
"actorScope": "项目",
"maxEventBytes": 262144,
"maxReadEvents": 500,
"actorPollMs": 250,
"actorQueueLimit": 32,
"eventContextChars": 40000
}
}
```
`fullCodeMode` 默认值为 `true`。完整模式禁用父会话中的原生核心工具,并使 `fabric_exec` 成为其独有的模型面向所有者。当为假时,Fabric 使用仅编排模式:原生 Pi 和已注册的扩展工具保持直接,捕获被禁用,Fabric 的内部注册表省略 `pi` 和 `extensions` 提供者。
Fabric 风险类别为 `read`、`write`、`execute`、`network` 和 `agent`;批准策略值为 `allow`、`ask` 或 `deny`。捕获的工具默认使用保守的 `execute` 风险,因为 Pi 工具定义不声明效果。在 `capture.risks` 下添加确切的工具名称覆盖。设置 `capture.hideFromModel` 为 `false` 以索引非核心扩展工具而不隐藏它们。`capture.keepVisible` 名称同时存在于 Fabric 和 Pi 的直接注册表中,除了在完整代码模式下,Pi 核心名称始终由 Fabric 所有。在无交互式 UI 的无头模式下,`ask` 策略是关闭的。批准按风险类别缓存一个 `fabric_exec` 执行。
当 `mcp.disableOAuth` 为真时,MCP 调用可能使用缓存的凭证,但不能启动新的交互式 OAuth 流。
UI `widget` 模式为 `auto`、`always` 或 `hidden`。`auto` 显示活动工作、最近完成和实时持久演员。小部件在聊天上方渲染(像 `pi-supervisor`);设置 `ui.enabled` 为 `false` 以禁用小部件和仪表板控制器。
网格数据默认为 `<project>/.pi/fabric/mesh`。设置 `mesh.root` 为相对或绝对路径以重新定位持久主题、共享状态和演员会话。将 `.pi/fabric/mesh/` 添加到项目的忽略文件中,除非协调日志有意版本化。设置 `mesh.enabled` 为 `false` 以禁用网格操作和环境演员恢复。
`mesh.actorScope` 控制持久演员定义、邮箱和子会话的存储和恢复位置。默认 `"project"` 在 `.pi/fabric/mesh/actors/` 中保留单个共享演员注册表,因此演员在同一项目中的多个 Pi 会话之间存活,不需要重新定义。将其设置为 `"session"` 以隔离每个 Pi 会话的演员(在 `.pi/fabric/mesh/actors/<sessionId>/` 下),这是以前的默认设置;当在单个项目中运行并发 Pi 会话并希望每个会话拥有自己的演员时,请使用此设置。具有项目范围时,一个 Pi 进程应该一次拥有演员注册表;并发会话共享注册表可能会在写入时发生冲突。网格主题是追加的,不会自动压缩;当不再需要旧网格根的历史记录时,请存档或删除它。
## 外部提供者协议
普通的 `pi.registerTool()` 工具会自动捕获。扩展程序仍然可以加入版本提供者协议,当他们需要公开非工具功能、更丰富的风险声明或大量虚拟操作目录而不为每个操作注册一个 Pi 工具:
```ts
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import {
FABRIC_PROVIDER_DISCOVER_EVENT,
FABRIC_PROVIDER_REGISTER_EVENT,
type FabricProvider,
type FabricProviderDiscovery,
} from "pi-fabric/protocol";
export default function extension(pi: ExtensionAPI) {
const provider: FabricProvider = {
name: "示例",
description: "示例操作",
async list() {
return [];
},
async describe() {
return undefined;
},
async invoke() {
return null;
},
};
pi.events.emit(FABRIC_PROVIDER_REGISTER_EVENT, {
version: 1,
provider,
overwrite: true,
});
pi.events.on(FABRIC_PROVIDER_DISCOVER_EVENT, (event: FabricProviderDiscovery) => {
event.register(provider, { overwrite: true });
});
}
```
提供者拥有自己的模式、状态和执行语义。Pi Fabric 验证参数、强制执行的声明风险策略、记录嵌套调用审计并传播取消。提供者可以通过不注册 TUI 组件来丰富通用活动表面:
```ts
async invoke(actionName, args, context) {
context.activity?.({ type: "entity", id: job.id, kind: "custom", name: job.name });
context.activity?.({ type: "progress", message: "Indexing package 3/12" });
context.activity?.({ type: "metrics", tokens: 4200, toolCalls: 9 });
return job.result;
}
```
## 命令
```text
/fabric 状态
/fabric 仪表板
/fabric 设置
/fabric 重载
/fabric 提供者
/fabric 捕获 [查询]
/fabric 代理
/fabric 演员
/fabric 消息 <actor-id>
/fabric 附加 <subagent-id>
/fabric 停止 <actor-or-subagent-id>
```
## 架构
```text
fabric_exec
│
▼
TypeScript 检查器 → QuickJS 沙盒
│ JSON-only 主机桥
▼
操作注册表
├── pi.* 内置 Pi 工具定义
├── extensions.* 捕获的 pi.registerTool 定义
├── mcp.* 池化的 mcporter 运行时
├── agents.* 一次性工作程序 + 持久邮箱演员
├── mesh.* 持久主题 + 比较和交换状态
└── external 显式 pi.events 提供者
活动存储 → 紧凑小部件 + 页脚状态 + 交互式仪表板
```
访客代码没有 `process`、`require`、文件系统、网络或子进程全局变量。所有效果都跨主机桥接,在那里应用模式、审批、审计记录、超时和取消。每个执行都接收一个全新的 QuickJS 上下文。`strings` 工具参数中传递的命名字符串作为 `π.key` 可用;访问未提供的键会抛出一个清晰、可操作的错误,列出提供的键而不是静默返回 `undefined`。
## 工具调用的鲁棒性
面向模型的 `fabric_exec` 模式故意设计为扁平的——一个大的 `code` 字符串加上标量/可选参数——没有任何嵌套的数组对象,其中包含转义的内容。新 SOTA 模型在单个主要工具形状的单个训练数据上进行训练,可以在嵌套的 JSON 字段中构造尾随键(例如,在长多行字符串后),而严格的模式会拒绝这些键。唯一的嵌套字段 `display` 忽略未知键:这些键由模式接受并过滤为 `{ name, description }` 然后执行,镜像训练数据的主导工具客户端的行为。
fabric 的架构本身就是对此类错误的缓解措施。模型作者编写 TypeScript 调用工具,因此它永远不必在采样压力下忠实地发出替代工具模式。嵌套对象构造发生在确定性、类型检查的代码中。残留的故障模式是不正确的 TypeScript,由 QuickJS 类型检查器捕获,并带有可操作的、带有行号的错误——在代码级别而不是 JSON 模式级别的验证/报告/重试循环。对于也直接调用 pi 工具(`read`/`write`/`edit`/`grep`/`find`/`ls`/`bash`)的会话,请安装 [pi-tool-repair](https://github.com/monotykamary/pi-tool-repair) 作为伴侣。它验证然后修复那些直接调用会犯的有限一组工具调用错误——发明的键、错误字段名称、字符串化的数组、锚点泄漏和泄漏的工具调用语法——在工具执行之前。它钩住 `before_provider_request`/`message_end`/`tool_calls`;fabric 注册一个工具,因此两者不会冲突。
fabric 之外的外部杠杆是在提供者上启用Anthropic 严格工具使用,这会阻止服务器采样不在模式中的键。这是模式漂移的最强缓解措施,但与Anthropic 的复杂性限制严格的工具定义进行交易。
## 安全性和局限性
- 当没有捕获的覆盖时,Pi Fabric 调用单独构造的 Pi 内置定义。这些未覆盖的内置调用不会通过 Pi 的顶级 `tool_calls` 和 `tool_result` 钩子。捕获的覆盖和其他扩展调用会运行这些钩子;Fabric 的批准和审计层在每个嵌套调用周围保持权威。
- 捕获的工具使用其所属扩展的完全权限。隐藏工具模式是上下文优化,而不是沙盒捕获的工具保留其定义和原生渲染器,但嵌套调用呈现为封闭 Fabric 执行的一部分,而不是作为单独的原生工具行。
- 注册拦截通过公共 `ExtensionRunner.getAllRegisteredTools()` 方法组合。一个扩展程序替换此方法而不委托以前的实现,可以防止捕获。
- MCP 服务器和外部提供者使用它们自己的主机权限。审查他们的配置和代码。
- 类型检查提高可靠性,但不是安全边界;QuickJS 隔离和主机功能桥是边界。
- 子 Pi 进程默认加载普通扩展,因此提供者支持的模型继续工作。它们的活动工具列表由 `defaultTools` 限制;`fabric_exec` 除非显式请求递归,否则不会被排除。
- Git 工作树隔离文件,但不隔离凭证、网络访问、进程或外部服务。
- 背景一次性子进程在父 Pi 会话关闭时停止。分离的 `agents.spawn()` 发送后续完成消息,除非调用者稍后等待它或禁用 `notifyOnComplete`。完成的工作树有意保留。
- 持久演员在关闭时暂停,并在项目信任激活时恢复。默认情况下(`mesh.actorScope: "project"`),它们的定义、邮箱历史和子会话文件位于 `.pi/fabric/mesh/actors/` 下,因此演员在 `/new` 之间存活。将其设置为 `mesh.actorScope: "session"` 以隔离每个 Pi 会话的演员(在 `.pi/fabric/mesh/actors/<sessionId>/` 下),这是以前的默认设置。网格主题是追加的,不会自动压缩;存档或删除旧网格根时,请存档或删除它。
- 批准 `agents.create()` 委托未来的订阅事件给该演员,直到它停止。每个激活使用演员的固定工具允许列表和模型设置;审查这些设置后再批准持久演员。
- 演员响应只能通过创建时固定的交付策略进入主上下文。指令输出是模式验证的,但它是未受信任的模型输出,主代理应该权衡。
- 一个 Pi 进程应该一次拥有演员注册表。这尤其适用于项目范围,其中同一项目中的并发 Pi 会话共享一个注册表,并且可能在写入时发生冲突。网格主题是追加的,不会自动压缩;存档或删除旧网格根时,请存档或删除它。
## 开发
```bash
pnpm install
pnpm typecheck
pnpm test
pnpm build
```
确定性测试套件涵盖了配置、模式验证、提供者调度、已注册工具的拦截和执行、QuickJS隔离、Pi内置调用、直接进程子代理、工作流助手、持久网格状态、演员邮箱、订阅和演员恢复。
## 许可证
MIT
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器