@yusukeshib/pi-babysit 0.3.11 → 0.3.13
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/README.md +28 -17
- package/agents.ts +23 -9
- package/index.ts +610 -225
- package/package.json +1 -1
- package/self-reap.ts +30 -23
package/package.json
CHANGED
package/self-reap.ts
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* keep talking to never dies; only a genuinely-abandoned one does.
|
|
14
14
|
* 2. Process parks — a turn that ends only to await a background-process
|
|
15
15
|
* exit notification (babysit_run inside the subagent, or the legacy
|
|
16
|
-
* `process` tool) also
|
|
17
|
-
* detect
|
|
16
|
+
* `process` tool) also settles the agent, but pi resumes on its own. We
|
|
17
|
+
* detect a parked toolResult anywhere in that run (same rule the parent
|
|
18
18
|
* uses) and DON'T schedule a reap, so a subagent waiting on a long
|
|
19
19
|
* build/test is never false-killed.
|
|
20
20
|
*
|
|
@@ -36,22 +36,25 @@ function parseDurMs(s: string | undefined): number | null {
|
|
|
36
36
|
return n * (u === "ms" ? 1 : u === "s" ? 1000 : u === "m" ? 60_000 : 3_600_000);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
// Same parked-turn rule as the parent
|
|
40
|
-
//
|
|
41
|
-
// as the LAST message means "parked awaiting the exit notification".
|
|
39
|
+
// Same parked-turn rule as the parent: scan the run because models sometimes
|
|
40
|
+
// add an assistant note after the marker-bearing tool result.
|
|
42
41
|
function isParked(
|
|
43
|
-
|
|
42
|
+
messages: { role?: string; toolName?: string; content?: unknown }[] | undefined,
|
|
44
43
|
): boolean {
|
|
45
|
-
if (!
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
44
|
+
if (!messages) return false;
|
|
45
|
+
for (let index = messages.length - 1; index >= 0; index--) {
|
|
46
|
+
const message = messages[index];
|
|
47
|
+
if (message?.role !== "toolResult") continue;
|
|
48
|
+
if (message.toolName === "process") return true; // legacy pi-processes
|
|
49
|
+
if (message.toolName !== "babysit_run") continue;
|
|
50
|
+
try {
|
|
51
|
+
const serialized = JSON.stringify(message.content ?? null);
|
|
52
|
+
if (serialized === "null" || serialized.includes(NOTIFY_MARKER)) return true;
|
|
53
|
+
} catch {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
54
56
|
}
|
|
57
|
+
return false;
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
export default function (pi: ExtensionAPI) {
|
|
@@ -61,6 +64,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
61
64
|
if (graceMs == null) return; // reaping disabled
|
|
62
65
|
|
|
63
66
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
67
|
+
let lastEndWasParked = false;
|
|
64
68
|
const cancel = () => {
|
|
65
69
|
if (timer) {
|
|
66
70
|
clearTimeout(timer);
|
|
@@ -71,22 +75,25 @@ export default function (pi: ExtensionAPI) {
|
|
|
71
75
|
// A new task/turn is starting — the subagent is wanted again. Stand down.
|
|
72
76
|
pi.on("before_agent_start", () => {
|
|
73
77
|
cancel();
|
|
78
|
+
lastEndWasParked = false;
|
|
74
79
|
});
|
|
75
80
|
|
|
76
81
|
pi.on("agent_end", (event) => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const msgs = (
|
|
82
|
+
const messages = (
|
|
80
83
|
event as { messages?: { role?: string; toolName?: string; content?: unknown }[] }
|
|
81
84
|
).messages;
|
|
82
|
-
|
|
85
|
+
lastEndWasParked = isParked(messages);
|
|
86
|
+
});
|
|
83
87
|
|
|
88
|
+
// agent_end can precede automatic retries, compaction retries, and queued
|
|
89
|
+
// continuations. Start the grace timer only once Pi is truly settled.
|
|
90
|
+
pi.on("agent_settled", (_event, ctx) => {
|
|
91
|
+
cancel();
|
|
92
|
+
if (lastEndWasParked) return;
|
|
84
93
|
timer = setTimeout(() => {
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
process.exit(0);
|
|
94
|
+
// Graceful shutdown emits session_shutdown for every loaded extension.
|
|
95
|
+
ctx.shutdown();
|
|
88
96
|
}, graceMs);
|
|
89
|
-
// Don't let this timer keep the event loop alive on its own.
|
|
90
97
|
timer.unref?.();
|
|
91
98
|
});
|
|
92
99
|
}
|