@alphacoder-v0/pi-loops 0.22.8 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +717 -0
- package/CONTRACT.md +7 -7
- package/README.md +114 -78
- package/README.zh-CN.md +62 -41
- package/docs/cli.md +352 -91
- package/docs/configuration.md +86 -24
- package/docs/design.md +404 -61
- package/docs/downstream.md +2 -2
- package/docs/goal.md +12 -3
- package/docs/hooks.md +6 -7
- package/docs/loops.md +288 -59
- package/docs/mcp.md +22 -14
- package/docs/recipes.md +6 -0
- package/docs/screenshot.png +0 -0
- package/docs/triggers.md +120 -26
- package/docs/troubleshooting.md +41 -28
- package/docs/web-ui-parity.md +702 -65
- package/package.json +4 -3
- package/recipes/autoresearch/recipe.toml +1 -0
- package/recipes/changelog-draft/recipe.toml +1 -0
- package/recipes/ci-sweeper/recipe.toml +1 -0
- package/recipes/daily-digest/recipe.toml +1 -0
- package/recipes/deps-sweeper/recipe.toml +1 -0
- package/recipes/ecosystem/recipe.toml +1 -0
- package/recipes/issue-loop/recipe.toml +1 -0
- package/recipes/pr-watch/recipe.toml +1 -0
- package/skills/pi-loops/SKILL.md +6 -4
- package/src/activity.ts +199 -0
- package/src/archive.ts +21 -9
- package/src/args.ts +6 -2
- package/src/browser-open.ts +169 -0
- package/src/cli-entry.mjs +12 -3
- package/src/cli.ts +960 -143
- package/src/config.ts +53 -5
- package/src/conversation-rows.ts +469 -0
- package/src/danger.ts +227 -6
- package/src/engine.ts +1240 -0
- package/src/goal.ts +71 -0
- package/src/held-read.ts +27 -0
- package/src/hooks.ts +49 -18
- package/src/host-control-channel.ts +455 -40
- package/src/host-control.ts +602 -111
- package/src/host-entry.mjs +5 -3
- package/src/host-runtime.ts +455 -42
- package/src/host.ts +659 -123
- package/src/inbox-card.ts +278 -0
- package/src/inbox.ts +139 -62
- package/src/job-edit.ts +7 -1
- package/src/job-health.ts +14 -2
- package/src/job-lines.ts +201 -13
- package/src/job-owner.ts +74 -13
- package/src/job-tune.ts +110 -0
- package/src/lease.ts +537 -0
- package/src/lock.ts +7 -2
- package/src/mcp-pool.ts +66 -14
- package/src/mcp.ts +1 -1
- package/src/open-file.ts +54 -0
- package/src/page-children.ts +1507 -0
- package/src/page-devices.ts +192 -0
- package/src/page-server.ts +3150 -0
- package/src/path-precheck.ts +215 -0
- package/src/paths.ts +24 -0
- package/src/pi-floor.ts +10 -0
- package/src/pi-loops.ts +1370 -473
- package/src/pi-resolver.d.mts +1 -0
- package/src/pi-resolver.mjs +110 -10
- package/src/presence.ts +12 -63
- package/src/protocol.ts +10 -1
- package/src/recipe.ts +43 -1
- package/src/requests.ts +354 -0
- package/src/rule-lines.ts +68 -0
- package/src/run-card.ts +105 -0
- package/src/runner.ts +18 -1
- package/src/schedule.ts +1 -2
- package/src/scheduler.ts +595 -245
- package/src/sdk-runner.ts +321 -27
- package/src/seen.ts +278 -0
- package/src/session-head.ts +21 -0
- package/src/share.ts +12 -2
- package/src/snapshot.ts +3 -2
- package/src/store.ts +81 -8
- package/src/tools.ts +196 -65
- package/src/trigger-runtime.ts +164 -127
- package/src/triggers.ts +39 -7
- package/src/trust.ts +46 -2
- package/src/ui-prefs.ts +22 -7
- package/src/watch-plan.ts +174 -0
- package/src/web.d.mts +3 -0
- package/src/web.mjs +2261 -2340
- package/src/window-executor.ts +459 -0
- package/src/window-guard.ts +158 -0
- package/docs/agents/issue-tracker.md +0 -34
package/README.zh-CN.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
给 [pi](https://github.com/earendil-works/pi) 的自动化层,做成一个 extension:cron 和有记忆的 loop、一个分诊用的 inbox、动态 trigger 与 MCP 推送通知、生命周期 hooks。pi 的代码一行没动。
|
|
6
6
|
|
|
7
|
-

|
|
8
8
|
|
|
9
9
|
一个 loop 醒来时带着上次留下的笔记,在干净上下文的子代理里干完活,把 finding 归档;你想看的时候去看,值得认真处理的那条再 claim 成真正的一轮。加上 `--verify`,第二个对抗式子代理会先把每条 finding 挑一遍,留下的才到你面前。关掉 pi 之后,这些照样跑。
|
|
10
10
|
|
|
@@ -28,7 +28,7 @@ pi-loops --continue # 接着这个目录里最新的那个会
|
|
|
28
28
|
pi-loops sessions [--all] # 这个目录(或整台机器)记下的会话
|
|
29
29
|
pi-loops inspect <file> # 别人发来的 .pisession,导入前先看清里面是什么
|
|
30
30
|
pi-loops upgrade # 装最新的发布版,当初从哪装就从哪装
|
|
31
|
-
pi-loops
|
|
31
|
+
pi-loops status # 看一眼没有 pi 开着时在跑的自动化
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
上面这几条都得先有 `pi-loops` 这个命令,它在 [上手](#上手) 里装。其余都是会话里的斜杠命令(`/cron`、`/inbox`、`/triggers`、`/goal`),装上扩展重启 pi 就能用。
|
|
@@ -39,7 +39,7 @@ pi-loops host status # 看一眼没有 pi 开着时在跑的自
|
|
|
39
39
|
|
|
40
40
|
Node ≥ 22.6(pi 直接加载 TypeScript 源码),pi ≥ 0.84.3(实际在 0.85 上测;更老的 pi 会在加载时被明确拒绝,报一句写明所需版本的话,而不是一个缺导出的链接错误),以及**一个真的能说上话的 provider**——先跑一次 `pi`,发一句,确认有回答。pi-loops 会在你不看着的时候替你跑子代理;凭据没配好,别等到第二天早上看见空 inbox 才知道。
|
|
41
41
|
|
|
42
|
-
pi-loops
|
|
42
|
+
pi-loops 自己没有任何运行时依赖。负责跑 loop 的 后台进程始终用 node 运行;pi 跑在 bun 下时,pi-loops 使用 PATH 上的 `node`。
|
|
43
43
|
|
|
44
44
|
### 2. 装上
|
|
45
45
|
|
|
@@ -51,7 +51,7 @@ pi install npm:@alphacoder-v0/pi-loops
|
|
|
51
51
|
|
|
52
52
|
重启 pi,装到这里就够了——那四个斜杠命令现在就能用。下面这段只跟 `pi-loops` 这个命令有关:浏览器窗口和几个 shell 子命令靠它,不要浏览器窗口可以先跳过。
|
|
53
53
|
|
|
54
|
-
`pi install` 把包放在 pi 自己的托管目录里、**不进 `PATH`**,所以此刻 `pi-loops` 这个命令还不存在。这一步不用你自己动手:`pi install`
|
|
54
|
+
`pi install` 把包放在 pi 自己的托管目录里、**不进 `PATH`**,所以此刻 `pi-loops` 这个命令还不存在。这一步不用你自己动手:`pi install` 之后第一次打开 pi,它会直接把 `pi-loops` 放进 `PATH` 上已有的目录,并用一行告诉你放在哪、怎么删;之后也一直替你维护着——包被 pi 挪到另一个位置,下一个会话会把启动器改回能用的样子,并用一行告诉你改了什么。不想要的话,`pi-loops uninstall-launcher` 删掉它,以后也不会再写;改了主意,`/pi-loops install-launcher` 随时给你写一个:
|
|
55
55
|
|
|
56
56
|
```text
|
|
57
57
|
/pi-loops install-launcher # 在 pi 里面,扩展本来就加载着
|
|
@@ -86,9 +86,9 @@ pi-loops --model anthropic/claude-opus-5 -e .
|
|
|
86
86
|
|
|
87
87
|
重新开始不用回终端:**clear** 开一个新会话,**resume** 回到这个项目里早先的某个会话,**compact** 压缩当前上下文并告诉你压成了多少。三个都是按钮,也都可以在输入框里直接敲(`/clear` 或 `/new`、`/resume`、`/compact 保住 API 的形状`)。谁都不删东西:离开的那个会话就是磁盘上的一个文件,`resume` 里列的就是它,标题是当时说的第一句话。
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
浏览器那个页面由后台的 pi-loops 提供,地址是 **`http://127.0.0.1:4173/`**:`pi-loops` 把它打开就退出,关掉那个终端,页面照样开着。token 存在文件里,所以这个地址明天还是它,可以直接收藏(4173 被占了,用 `config.toml` 里的 `[page] port` 换一个)。第一次访问会留一个 cookie,之后再也看不到 token。token 去不掉:页面一直开着,所以一直挡在它后面。
|
|
90
90
|
|
|
91
|
-
手机上用:最好的路是 `tailscale serve --bg 4173`——服务器仍然只绑 127.0.0.1,TLS 和身份都交给 tailnet,手机打开 `https://<机器>.<tailnet>.ts.net/`。同一个 wifi
|
|
91
|
+
手机上用:最好的路是 `tailscale serve --bg 4173`——服务器仍然只绑 127.0.0.1,TLS 和身份都交给 tailnet,手机打开 `https://<机器>.<tailnet>.ts.net/`。同一个 wifi 里也可以在 `config.toml` 里写 `[page] host = "0.0.0.0"`,再 `pi-loops restart`。手机第一次进什么都不用输:在已经登录的浏览器里点 **add device**,拿手机扫那个二维码就进去了,之后一直是登录状态(不想扫也可以输下面那六位数)。加到主屏幕会以独立窗口打开(有 manifest,没有 service worker)。
|
|
92
92
|
|
|
93
93
|
### 4. 第一个 loop
|
|
94
94
|
|
|
@@ -99,7 +99,7 @@ pi-loops --model anthropic/claude-opus-5 -e .
|
|
|
99
99
|
每天早上一个干净上下文的子代理带着上次写的笔记跑一遍,回复末尾给出 `<loop-state>…</loop-state>`(留给明天的笔记)和 `<inbox>一行 finding</inbox>`:状态写进一个 Markdown 文件,finding 进 inbox,你的对话一个字都不动。下面是一个盯着 TODO 文件的 loop 相隔半小时的两次运行,第一次:
|
|
100
100
|
|
|
101
101
|
```text
|
|
102
|
-
|
|
102
|
+
todo · 5s · $0.000 · 0 findings · state updated
|
|
103
103
|
MD5 unchanged (`06ff2ec8af3668bb89ecc6580110ecad`), git rev still `15b6562`. No new unchecked items — nothing to report.
|
|
104
104
|
/cron trace todo · /inbox
|
|
105
105
|
```
|
|
@@ -107,7 +107,7 @@ MD5 unchanged (`06ff2ec8af3668bb89ecc6580110ecad`), git rev still `15b6562`. No
|
|
|
107
107
|
中间提交了一次之后,第二次:
|
|
108
108
|
|
|
109
109
|
```text
|
|
110
|
-
|
|
110
|
+
todo · 4s · $0.000 · 1 finding · state updated
|
|
111
111
|
md5 changed (06ff2ec8… → fe00aaad…). One new unchecked item appeared.
|
|
112
112
|
• TODO.md: new unchecked item — cache the /search results for 60s (commit 395a124 "todo: cache search results")
|
|
113
113
|
/cron trace todo · /inbox
|
|
@@ -120,7 +120,6 @@ md5 changed (06ff2ec8… → fe00aaad…). One new unchecked item appeared.
|
|
|
120
120
|
Inbox (acme-api, 3 new, times +00:00):
|
|
121
121
|
1. [inb-aae794d5] TODO: rate-limit the /search endpoint (acme-api, cron:todo, 2026-09-12 05:25)
|
|
122
122
|
2. [inb-74b73c72] TODO.md: new unchecked item — cache the /search results for 60s (acme-api, cron:todo, 2026-09-12 05:28)
|
|
123
|
-
claim with /inbox claim <n>, dismiss with /inbox dismiss <n>
|
|
124
123
|
```
|
|
125
124
|
|
|
126
125
|
```text
|
|
@@ -144,7 +143,7 @@ claim with /inbox claim <n>, dismiss with /inbox dismiss <n>
|
|
|
144
143
|
daily_budget_usd = 5.0
|
|
145
144
|
```
|
|
146
145
|
|
|
147
|
-
|
|
146
|
+
只要有启用的 loop、规则或待处理推送,pi 窗口就会启动后台运行的 pi-loops,所以关闭窗口后早上九点的任务仍会运行(`/pi-loops`、`pi-loops status`)。不想自动启动就在同一个文件里写 `[host] auto = false`。
|
|
148
147
|
|
|
149
148
|
## 升级
|
|
150
149
|
|
|
@@ -163,14 +162,27 @@ pi-loops upgrade --check # 只看看有没有新的
|
|
|
163
162
|
|
|
164
163
|
## 卸载
|
|
165
164
|
|
|
165
|
+
卸载扩展前先停止 pi-loops,并删掉 `pi-loops` 启动器(`uninstall-launcher` 只删 pi-loops 自己写的那个):
|
|
166
|
+
|
|
166
167
|
```bash
|
|
168
|
+
pi-loops stop
|
|
169
|
+
pi-loops uninstall-launcher
|
|
167
170
|
pi remove npm:@alphacoder-v0/pi-loops # 当初怎么装的就怎么删:npm: 包名、git: ref 或检出路径
|
|
168
171
|
pi remove git:github.com/alphacoder-v0/pi-loops
|
|
169
172
|
pi -e /path/to/pi-loops # 或者:只在这次启动试用,什么都不装
|
|
170
173
|
pi update --extensions # 对齐已安装的包
|
|
171
174
|
```
|
|
172
175
|
|
|
173
|
-
数据留在 `~/.pi/agent/loops
|
|
176
|
+
数据留在 `~/.pi/agent/loops`,想清就删目录。以后重新安装时,在 pi 里运行 `/pi-loops install-launcher` 把命令放回来:删掉的启动器不会再自动写回。
|
|
177
|
+
|
|
178
|
+
要退回 0.22.8:趁 0.23 还装着,先停止 pi-loops,再安装 0.22.8:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
pi-loops stop
|
|
182
|
+
pi install npm:@alphacoder-v0/pi-loops@<version> # <version> 填 0.22.8
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
0.22.8 能直接读你现有的 job 和规则,但不会运行已关闭对话里的 plain job,也不理会只有 0.23 才写的那些文件,所以 `deliveries/` 里还在排队的规则结果不会再送达。
|
|
174
186
|
|
|
175
187
|
包里附带一个 skill(`skills/pi-loops`),让 agent 知道什么时候该用 `cron_create`、`new_trigger` 和 inbox。
|
|
176
188
|
|
|
@@ -247,11 +259,11 @@ playbook 拷到 `.agents/skills/<name>/`,通过 `.git/info/exclude` 排除在
|
|
|
247
259
|
/cron state ci loop 的笔记(状态脊柱)
|
|
248
260
|
/cron runs [ci] 最近运行,最新在前
|
|
249
261
|
/cron trace ci 2 第 2 新那次运行的 transcript:prompt、工具调用、结果、回复
|
|
250
|
-
/cron scheduler
|
|
262
|
+
/cron scheduler 当前窗口、它的会话、pi-loops 状态(`/cron status` 是 `/cron` 的别名)
|
|
251
263
|
/cron cost [today|7d|all] 自动化花了多少,按任务分,对照 [limits] daily_budget_usd
|
|
252
264
|
/cron disable --all 本项目全停(--all-projects 停整台机器);/cron clear <ref> 清掉死进程留下的 running 标记
|
|
253
265
|
/cron gc 清掉会话已消失的任务(本项目;--all 才跨项目)
|
|
254
|
-
/
|
|
266
|
+
/pi-loops [start|stop] 查看、启动或停止后台运行的 pi-loops
|
|
255
267
|
/cron snapshot 把「只有这个进程知道的状态」写进会话:哪些 MCP 连上了、暴露了什么工具、
|
|
256
268
|
当前 active tools、hooks、谁拥有时钟。给非终端的前端读的
|
|
257
269
|
|
|
@@ -385,9 +397,9 @@ backup.pisession 无压缩 ustar,0600,拒绝覆盖已有文
|
|
|
385
397
|
- 结果默认只落在 TUI 卡片和 audit 里;规则带 `promote_to_chat` 时,它以 `[Trigger <trace_id>] …` 开头插进主对话,后面的 turn 看得见。
|
|
386
398
|
- 5 分钟 dedup 窗口,`listChanged` 类通知用稳定 key 折叠成最新一条,自定义通知必须带 `_meta.pi_dedup_key`,否则在源头丢弃并计数。
|
|
387
399
|
- 自然语言里出现「每小时 / daily / cron / 定时任务」之类时,`new_trigger` 会拒绝并让 agent 改用 `cron_create`。
|
|
388
|
-
- 工具:`new_trigger`(condition / action / spec / fire_once / promote_to_chat)、`list_triggers`、`remove_trigger`(id | all)、`set_trigger_state`,描述与返回文本固定。建规则、删规则、重新启用自动化这三件事都要你点头:工具把原因摆出来等你确认,没有 UI
|
|
400
|
+
- 工具:`new_trigger`(condition / action / spec / fire_once / promote_to_chat)、`list_triggers`、`remove_trigger`(id | all)、`set_trigger_state`,描述与返回文本固定。建规则、删规则、重新启用自动化这三件事都要你点头:工具把原因摆出来等你确认,没有 UI 可点的场合(子会话、后台进程)一律拒绝。
|
|
389
401
|
- 规则是机器全局的(带 cwd),`/triggers rules` 默认只看本项目;子代理进程里不注册这些工具,所以一条 trigger 的动作造不出新的 trigger。
|
|
390
|
-
-
|
|
402
|
+
- 轮询间隔:`config.toml` 的 `[triggers] poll_interval_secs`,pi-loops 每分钟重读一次。`--trigger-poll-secs` 已不起作用,传了会提示一句。
|
|
391
403
|
|
|
392
404
|
### MCP 推送作为 trigger 源
|
|
393
405
|
|
|
@@ -446,7 +458,7 @@ stdio 服务器崩溃后自动重连;`Mcp-Session-Id` 会话头;服务器发
|
|
|
446
458
|
- 单条规则写错只跳过那条并提示,其它照常加载。同一事件的规则按文件顺序串行执行,不阻塞 agent。
|
|
447
459
|
- 超时或 Ctrl-C 时杀掉 hook 的整棵进程树,不只是 `sh`。
|
|
448
460
|
- 项目级 `<repo>/.pi/hooks.toml` 默认忽略;用户 `hooks.toml` 顶层写 `allow_project_hooks = true`、或 `config.toml` 同名键、或 `PI_ALLOW_PROJECT_HOOKS=1`(`true` 也算,其它值都算关)才启用。**在无头宿主里还额外要求 pi 对那个任务的 cwd 有精确的信任记录**——`allow_project_hooks` 是对「你会打开的项目」的表态,不是对「模型顺手指过去的目录」的表态。
|
|
449
|
-
- hook 打到 stdout 的东西写进本进程日志(`logs/pi-<pid>.log
|
|
461
|
+
- hook 打到 stdout 的东西写进本进程日志(`logs/pi-<pid>.log`,后台日志写入 `host.log`),截到 4000 字符——「打印点东西再去看」这个最常用的调试手段现在是通的。
|
|
450
462
|
- 子代理进程里不触发 hooks,只有你交互的那个 pi 触发。
|
|
451
463
|
|
|
452
464
|
## 子代理每次收到的 prompt
|
|
@@ -473,7 +485,7 @@ Output protocol (mandatory):
|
|
|
473
485
|
| **状态脊柱** — 每个 loop 一份 ≤2000 字符的笔记,run N+1 读到 run N 写的 | `<loop-state>` 标签解析后写入 Markdown,下次运行拼进 prompt 头部 | `~/.pi/agent/loops/state/<id>.md` |
|
|
474
486
|
| **maker/checker** | `--verify`:第二个对抗式子代理逐条核实 findings,drop 的不进 inbox | `runs.jsonl` 的 `checker` 字段 |
|
|
475
487
|
| **路由层** — 产出既不打断你也不沉进日志 | `<inbox>` 标签 → JSONL 追加,`new → claimed/dismissed` 生命周期,状态栏 `Inbox: N new` 角标;条目 id `inb-<32hex>`、来源 `cron:<id或name>`、`/inbox` 与 `/inbox all` 的行格式、错误措辞都固定下来,已核实的多一个 `✓` 标记 | `~/.pi/agent/loops/inbox.jsonl` |
|
|
476
|
-
| stateful job 走 SubAgent、永不碰主对话 |
|
|
488
|
+
| stateful job 走 SubAgent、永不碰主对话 | 在后台运行的 pi-loops 里开的子会话(pi SDK),干净上下文;MCP 连接由 pi-loops 按 `mcp.toml` 和项目配置自己建立,不再借用某个窗口的连接;完整 transcript 保留在 `sessions/<id>/`,`/cron trace` 可看 | `~/.pi/agent/loops/sessions/<id>/*.jsonl` |
|
|
477
489
|
| trigger 的产出看得见、可追溯 | 每次运行结束在 transcript 里落一张卡片(耗时、成本、findings、摘要),run log 记退出码与用量 | `runs.jsonl` |
|
|
478
490
|
| 预览与 audit 一律脱敏 | `src/redact.ts` 一套 redactor,列表、卡片、run log、trace 全部过一遍 | — |
|
|
479
491
|
| 普通 cron 走 inject-and-run | 不加 `--stateful` 的任务到点用 `pi.sendUserMessage` 注入创建它的会话,消息带 `[Trigger <trace>] ` 前缀(空闲直接发,忙则 followUp 排队) | — |
|
|
@@ -486,18 +498,23 @@ Output protocol (mandatory):
|
|
|
486
498
|
## 自动化要活过开它的那个窗口
|
|
487
499
|
|
|
488
500
|
定时任务值不值得信,取决于你关掉编辑器之后会发生什么。所以这里把「pi 重启过」当成常态:
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
+
任务和规则保存在本机的 loops 目录。
|
|
502
|
+
|
|
503
|
+
一个 loops 目录最多运行一个后台运行的 pi-loops。pi 窗口在会话开始、每 30 秒一次的 tick,以及新建 loop、规则后,
|
|
504
|
+
只要存在启用的 loop、规则或有待处理推送的 MCP 服务器,或者某个已关闭的会话有普通任务或排队的规则结果,
|
|
505
|
+
就会按需启动 pi-loops。pi-loops 运行所有 stateful loop、动态规则检查和 MCP 推送,也在已关闭的会话里运行它们的
|
|
506
|
+
普通任务,每次都是一轮模型调用;窗口运行在它里面打开的那个会话的普通任务。规则结果回到创建规则的
|
|
507
|
+
会话:窗口持有该会话时送入会话,其他进程判定时排队给该窗口;会话已关闭时由 pi-loops 追加进会话。只有会话
|
|
508
|
+
文件无法写入时,结果才进入 inbox。
|
|
509
|
+
由 shell 创建且没有会话的规则,结果进入 inbox。
|
|
510
|
+
|
|
511
|
+
pi-loops 不会因窗口打开或关闭而退出。`/pi-loops` 显示 pid、pi-loops 版本、启动时间、正在运行的工作、窗口
|
|
512
|
+
持有的会话和日志;`/pi-loops stop` 会记录手动停止,在 `/pi-loops start` 前窗口不会重新启动它。
|
|
513
|
+
`[host] auto = false` 或单进程环境变量 `PI_LOOPS_HOST=off` 禁止窗口自动启动。无法启动时会在 1、5、30
|
|
514
|
+
分钟后重试,状态行显示暂停原因,`/pi-loops status` 和 `host.log` 提供详情。窗口连续三次探测不到控制 socket
|
|
515
|
+
会替换失联的 pi-loops:先发 SIGTERM,10 秒后再发 SIGKILL;仍在启动的 pi-loops 不会因此被杀掉。新版窗口会替换旧版
|
|
516
|
+
pi-loops,旧版窗口不会替换新版 pi-loops。升级期间,pi-loops 0.22 窗口让后台进程运行 loop、自己待命,但仍会运行自己持有
|
|
517
|
+
会话的普通任务;重启这些旧窗口才能让普通任务也采用新行为。机器重启后,要等 pi 窗口打开才会恢复运行。pi-loops 还有一个只读状态页,`pi-loops status --url` 打印带令牌的地址。
|
|
501
518
|
|
|
502
519
|
## 对 pi 的无侵入性
|
|
503
520
|
|
|
@@ -517,13 +534,17 @@ Output protocol (mandatory):
|
|
|
517
534
|
| `~/.pi/agent/loops/spend.json` | 轮转掉的那部分花费按天留一份,预算上限不会因为 run log 被截断而失效 |
|
|
518
535
|
| `~/.pi/agent/loops/logs/pi-<pid>.log` | 每个 pi 进程的自动化诊断,超 2 MB 保留后半,只留最近五个进程(进程还活着的那份不算) |
|
|
519
536
|
| `~/.pi/agent/loops/sessions/<id>/*.jsonl` | 子代理完整 transcript,每个 loop 保留最近 20 份 |
|
|
520
|
-
| `~/.pi/agent/loops/
|
|
537
|
+
| `~/.pi/agent/loops/host-service.json`、`host.log` | 后台运行的 pi-loops 记录与日志 |
|
|
538
|
+
| `~/.pi/agent/loops/leases/`、`requests/` | 每个会话在哪里打开,以及等着送进会话的内容 |
|
|
539
|
+
| `~/.pi/agent/loops/pages/` | 浏览器页面里开着的每个会话一条记录:它的 pi 的 pid,以及标签页最近一次用它的时间 |
|
|
521
540
|
| `~/.pi/agent/loops/triggers.json` | 动态 trigger 规则(全局,带 cwd) |
|
|
522
541
|
| `~/.pi/agent/loops/triggers-audit.jsonl` | trigger audit,超 2 MB 保留后半 |
|
|
523
542
|
| `~/.pi/agent/loops/sessions/triggers-<项目>-<哈希>/*.jsonl` | 动态检查子代理的 transcript,每个项目一个目录(目录名带项目路径的哈希,同名的两个项目不会共用),保留最近 40 份 |
|
|
524
543
|
| `~/.pi/agent/loops/config.toml` | `[triggers] poll_interval_secs`、`allow_project_hooks` |
|
|
525
544
|
| `~/.pi/agent/loops/mcp.toml` · `hooks.toml` | MCP 推送源、生命周期 hooks |
|
|
526
545
|
|
|
546
|
+
完整的文件列表见 [docs/configuration.md](docs/configuration.md)。
|
|
547
|
+
|
|
527
548
|
跨进程写入靠 `mkdir` 锁 + 原子改名,没有原生依赖。
|
|
528
549
|
|
|
529
550
|
## 代码结构
|
|
@@ -531,12 +552,12 @@ Output protocol (mandatory):
|
|
|
531
552
|
```
|
|
532
553
|
src/extension-entry.ts pi 加载的入口:先查 pi 版本(src/pi-floor.ts),够了再导入 src/pi-loops.ts
|
|
533
554
|
src/pi-loops.ts 扩展本体:命令、工具、生命周期、状态栏角标、面板
|
|
534
|
-
src/cli.ts `pi-loops`:会话入口(网页或终端)与 sessions / inspect / export / import /
|
|
555
|
+
src/cli.ts `pi-loops`:会话入口(网页或终端)与 sessions / inspect / export / import / start / stop / status
|
|
535
556
|
src/cli-entry.mjs bin
|
|
536
557
|
src/ts-entry.mjs .mjs 入口怎么加载本包的 .ts:Node 自己剥类型,装在 node_modules 下就借 pi 的 jiti
|
|
537
558
|
|
|
538
559
|
流水线
|
|
539
|
-
src/scheduler.ts tick
|
|
560
|
+
src/scheduler.ts tick 循环、到期判定、错过补发、并发/重叠控制、子会话执行、写回;pi-loops 在后台运行 loops,窗口跑其会话的普通任务
|
|
540
561
|
src/trigger-runtime.ts 动态规则运行时:admit、投递(sub_agent / inject_summary / inject_and_run)、fire-once、promote、audit
|
|
541
562
|
src/triggers.ts 规则本身:解析、prompt、id 提取、存储、dedup 窗口
|
|
542
563
|
src/goal.ts /goal:停止条件状态机、评估器 prompt、续跑预算
|
|
@@ -557,12 +578,12 @@ src/subagent-guard.ts 把该策略装进每个子会话的合成扩展
|
|
|
557
578
|
src/transcript.ts 把子代理 session 文件压成可读的几十行
|
|
558
579
|
|
|
559
580
|
没有 pi 开着的时候
|
|
560
|
-
src/host.ts
|
|
561
|
-
src/host-entry.mjs
|
|
562
|
-
src/host-control.ts
|
|
563
|
-
src/host-control-channel.ts
|
|
564
|
-
src/host-runtime.ts
|
|
565
|
-
src/presence.ts
|
|
581
|
+
src/host.ts 后台运行的 pi-loops:认领、自检、0.22 兼容边界
|
|
582
|
+
src/host-entry.mjs pi-loops 的启动入口,负责加载 node_modules 下的 TypeScript
|
|
583
|
+
src/host-control.ts 服务记录、启动、退出与恢复决策
|
|
584
|
+
src/host-control-channel.ts 控制 socket:状态、中止、停止、运行与升级
|
|
585
|
+
src/host-runtime.ts 后台运行逻辑(调度器、triggers、按请求提供的工具)
|
|
586
|
+
src/presence.ts pi-loops 0.22 窗口写入;升级时只读
|
|
566
587
|
src/register-pi.mjs 在 pi 之外解析 pi 包的 node --import 钩子(宿主、测试用)
|
|
567
588
|
src/pi-resolver.mjs 这个钩子去哪里找
|
|
568
589
|
|
|
@@ -606,13 +627,13 @@ TypeScript 的类型信息判断。
|
|
|
606
627
|
|
|
607
628
|
- 子会话继承父会话的 model/thinking(任务固定了模型则用固定的);子会话里不再加载这个扩展本身,不会递归。
|
|
608
629
|
- 子会话没有 UI 就没有审批弹窗:需要确认的工具在子会话里 **fail-closed 拒绝**。没人能点「同意」的时候,默认答案只能是「不」。要收紧就用 `--tools read,grep,ls`。
|
|
609
|
-
- 状态栏角标最多五段,按需出现,之间用 ` · ` 隔开:`Inbox: N new`、`N
|
|
630
|
+
- 状态栏角标最多五段,按需出现,之间用 ` · ` 隔开:`Inbox: N new`、`N loops failing (<name> ×K)`、`running: <loop>`(多个用逗号连起来,trigger 检查在这儿显示成 `trigger-check`)、`mcp: 1 source down` / `mcp: 2 sources down`、`loops paused: the pi-loops could not start`。
|
|
610
631
|
- 同一任务上一轮还在跑时新 tick 直接跳过并计数(`overlap-skipped`),不排队。
|
|
611
632
|
- 同时最多 3 个子代理在跑(`[cron] max_concurrent_runs`)——loop 运行、trigger 检查、`/goal` 评估器**共用这一个池子**(`src/slots.ts`),三条路加起来一共 3 个。`/goal` 评估器和 `/cron run` 占槽但永不被拒(你直接要的东西,机器悄悄不做和从没设过是一样的),所以 `/triggers running` 有可能显示 `4 of 3 sub-agent slot(s) in use`。
|
|
612
633
|
- `[limits] daily_budget_usd` 不只挡派发,也会**停掉正在跑的运行**:算的是运行日志里已落账的花费加上本进程在飞的(并行的兄弟运行,以及 `--verify` 那对共用 runId 的 maker/checker)。被预算停掉记为 aborted 而不是 failed,所以时隙还欠着、失败连击不累加。
|
|
613
634
|
- inbox 的状态改写是「最后写者赢」:两个进程同时处理同一条时,后写的那个说了算,不做冲突检测。
|
|
614
|
-
- 常驻面板是编辑器上方的 widget:`Triggers` 规则最多 5 条 + `Polling` 最近一次检查、`Inbox N new`、`Cron` 启停统计与任务最多 5 条、`MCP`
|
|
615
|
-
- 跨设备访问不放 broker 在中间:让你从别处够到那个还待在原地的前端——`tailscale serve` 在 tailnet 上终结 TLS、代理到本机 loopback
|
|
635
|
+
- 常驻面板是编辑器上方的 widget:`Triggers` 规则最多 5 条 + `Polling` 最近一次检查、`Inbox N new`、`Cron` 启停统计与任务最多 5 条、`MCP` 各服务器连接状态与工具数、`Hooks` cli_hooks 规则数与事件——这几段各自没内容时不显示。规则、任务、新 findings、MCP 服务器全都没有时整个面板不显示;`/cron panel off` 或 `/triggers panel off` 关闭,偏好存在 `ui.json`。
|
|
636
|
+
- 跨设备访问不放 broker 在中间:让你从别处够到那个还待在原地的前端——`tailscale serve` 在 tailnet 上终结 TLS、代理到本机 loopback,手机就能开,中间不经过任何第三方;同一网段则在 `config.toml` 里设 `[page] host`。手机第一次进用配对码和二维码([docs/cli.md](docs/cli.md#from-a-phone))。真正没覆盖的是「手机两个网络都不在」,那种情况才需要中继。
|
|
616
637
|
- 这是一个自动化层,不是一个 agent:写代码、读网页、管 skill 都是 pi 自己的本事,这里只决定什么时候、在哪里、带着什么上下文去跑它们。
|
|
617
638
|
|
|
618
639
|
## 致谢
|