@yusukeshib/pi-babysit 0.3.12 → 0.3.14
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 +44 -25
- package/agents.ts +23 -9
- package/index.ts +1203 -242
- package/package.json +1 -1
- package/rpc-stream-proxy.mjs +70 -10
- package/self-reap.ts +48 -28
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ reachable from anywhere (`~/.pi-babysit/<pi-session-id>/`). Two kinds:
|
|
|
33
33
|
| kind | started by | completion | on completion |
|
|
34
34
|
| ---- | ---------- | ---------- | ------------- |
|
|
35
35
|
| **process** | `babysit_run { command }` | process **exit** | automatic notification message (`triggerTurn`), batched for all exits observed in the same poll — the agent may end its turn after starting and is resumed on exit, same contract as the old `process` tool |
|
|
36
|
-
| **subagent** | `babysit_run { profile: "subagent", task }` | `
|
|
36
|
+
| **subagent** | `babysit_run { profile: "subagent", task }` | `agent_settled` in the RPC event stream (process stays alive) | none — the agent polls `babysit_check` or blocks on `babysit_wait`; the idle session accepts follow-up tasks |
|
|
37
37
|
|
|
38
38
|
The **profile is a tool parameter, not a separate tool set**: domain knowledge
|
|
39
39
|
(RPC bookkeeping, per-task byte offsets, parked-turn detection, PTY-safe
|
|
@@ -56,10 +56,10 @@ programs** (installers, wizards, REPLs): type with `babysit_send`
|
|
|
56
56
|
|
|
57
57
|
| Tool | What it does |
|
|
58
58
|
| ---- | ------------ |
|
|
59
|
-
| `babysit_run` | Run any command (`command`, optional `name`/`pty`/`timeout`/`idleTimeout`/`retryOnWorkerDeath`) or start a subagent (`profile: "subagent"`, `task`, optional `agent`/`model`/`tools`/`maxDepth`). `maxDepth` defaults to 1 and can only be set by the top-level caller. Quick commands return inline; longer ones continue in the background |
|
|
59
|
+
| `babysit_run` | Run any command (`command`, optional `name`/`pty`/`timeout`/`idleTimeout`/`retryOnWorkerDeath`/`notificationGroup`) or start a subagent (`profile: "subagent"`, `task`, optional `agent`/`model`/`tools`/`maxDepth` and `maxCost`/`maxTurns`/`maxToolCalls`/`maxUsageTokens` budgets). `maxDepth` defaults to 1 and can only be set by the top-level caller. Quick commands return inline; longer ones continue in the background |
|
|
60
60
|
| `babysit_check` | List all sessions, inspect one, tail its bounded recent output, or search its raw log with `pattern`; `screen: true` captures TUIs and subagents otherwise show structured live progress |
|
|
61
61
|
| `babysit_send` | Process: type `text` / press `keys` into the PTY. Subagent: steer mid-run, or send a follow-up task when idle (`mode: auto/steer/task`) |
|
|
62
|
-
| `babysit_wait` | Block until done: process exit (or `expect: "regex"` readiness marker), subagent task completion. Multi-wait: `ids` + `mode: "any"\|"all"` |
|
|
62
|
+
| `babysit_wait` | Block until done: process exit (or `expect: "regex"` readiness marker), subagent task completion. Multi-wait: up to 32 unique `ids` + `mode: "any"\|"all"` |
|
|
63
63
|
| `babysit_kill` | Terminate a session, verify terminal state, then suppress the exit notification |
|
|
64
64
|
|
|
65
65
|
The built-in `bash` tool is removed from the active tool set so the model does
|
|
@@ -73,6 +73,7 @@ re-enables `bash`, including shell backgrounding (`… &`, `nohup`, `setsid`,
|
|
|
73
73
|
| Command | What it does |
|
|
74
74
|
| ------- | ------------ |
|
|
75
75
|
| `/babysit` | Arrow-key picker over all sessions. Renders an **inline snapshot** (no tmux): running **process** → current rendered screen + recent output + a copy-paste `babysit attach` take-over hint (detach `Ctrl-\ Ctrl-\`); running **subagent** → read-only progress (RPC stdin stays untouchable); finished → summary. Re-run `/babysit` to refresh |
|
|
76
|
+
| `/babysit gc [days]` | Preview and confirm deletion of old Pi-session roots (default 14 days). Active leases, live supervisor/child PIDs, unknown states, the current root, and recent roots are retained; deletion uses a GC lock and atomic rename |
|
|
76
77
|
|
|
77
78
|
A minimal widget above the editor shows live counts
|
|
78
79
|
(`N processes · M subagents working · K idle`).
|
|
@@ -94,18 +95,24 @@ babysit_check { id: "cargo-test", lines: 50 }
|
|
|
94
95
|
babysit_check { id: "cargo-test", pattern: "FAIL|ERROR", lines: 50 }
|
|
95
96
|
```
|
|
96
97
|
|
|
97
|
-
Tail and search results are capped at 200 lines, and
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
98
|
+
Tail and search results are capped at 200 lines, and ordinary returned tool
|
|
99
|
+
results (including lifecycle headers) are clipped to 8 KB. A single explicitly
|
|
100
|
+
waited-for subagent answer may use up to 24 KB; multi-session wait results default
|
|
101
|
+
to the 8 KB inline-output limit and can opt into a larger cap with `maxBytes`.
|
|
102
|
+
Pattern search returns the latest matching lines with line numbers. Prefer a
|
|
103
|
+
targeted pattern over a broad tail, and do not read a potentially large log file
|
|
104
|
+
in full. Subagent crashes return structured errors plus the full log path, never
|
|
105
|
+
a raw RPC JSON tail.
|
|
106
|
+
|
|
107
|
+
Subagent logs compact Pi's streaming `message_update` events before they are
|
|
108
|
+
recorded. Pi repeats the complete growing assistant message and partial snapshot
|
|
109
|
+
on every token; pi-babysit retains only the incremental delta. The opt-in
|
|
110
|
+
`compact` RPC log mode also removes duplicate payloads from `message_start`,
|
|
111
|
+
`turn_end`, successful `tool_execution_end`, and `agent_end`, while preserving
|
|
112
|
+
authoritative `message_end`, failures, responses, and errors. Parked-process
|
|
113
|
+
state is materialized as a small boolean so completion detection is unchanged.
|
|
114
|
+
Set `PI_BABYSIT_RPC_LOG_MODE=standard` for the legacy lifecycle payloads. Live
|
|
115
|
+
`/babysit` and attach views render either format.
|
|
109
116
|
|
|
110
117
|
All shell commands, including `pwd` and Git, go through `babysit_run`. Bundle
|
|
111
118
|
closely related tiny observations when doing so safely reduces tool turns.
|
|
@@ -127,20 +134,29 @@ because blindly rerunning an arbitrary command can duplicate side effects.
|
|
|
127
134
|
`pi.sendMessage(…, { triggerTurn: true, deliverAs: "steer" })` containing every
|
|
128
135
|
deliverable exit observed in that poll (deduped via `meta/<id>.json`). Waiting
|
|
129
136
|
for idleness prevents an immediately-following `babysit_wait` from racing the
|
|
130
|
-
poller and receiving a duplicate completion.
|
|
137
|
+
poller and receiving a duplicate completion. Processes with the same
|
|
138
|
+
`notificationGroup` wait for every currently running group member to stop and
|
|
139
|
+
then share one notification even when their exits span multiple polls.
|
|
131
140
|
`babysit_kill` and an exit already reported by `babysit_wait` suppress the
|
|
132
141
|
notification.
|
|
133
|
-
- **Subagent**: `babysit_wait` blocks on `babysit expect '"type":"
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
142
|
+
- **Subagent**: `babysit_wait` blocks on `babysit expect '"type":"agent_settled"'`.
|
|
143
|
+
Unlike `agent_end`, `agent_settled` cannot precede an automatic retry,
|
|
144
|
+
compaction retry, or queued continuation. A settled run containing a
|
|
145
|
+
**parked** toolResult — a `babysit_run { command }` result carrying the
|
|
146
|
+
`[notify-on-exit]` marker (or the legacy `process` tool) — only means "turn
|
|
147
|
+
parked awaiting a process-exit notification; pi resumes on its own", so the
|
|
148
|
+
wait continues. The marker-bearing result may be followed by a short
|
|
149
|
+
assistant note without defeating parked detection. Per-task byte offsets
|
|
150
|
+
scope check/wait to the CURRENT task, and appended log bytes are parsed
|
|
151
|
+
incrementally, which keeps follow-up tasks efficient.
|
|
140
152
|
|
|
141
153
|
Subagents load `self-reap.ts`, which exits an idle finished subagent after a
|
|
142
154
|
grace window (`PI_BABYSIT_REAP_AFTER`, default 120s) using the same parked-turn
|
|
143
|
-
rule, so a subagent waiting on a long build is never false-killed.
|
|
155
|
+
rule, so a subagent waiting on a long build is never false-killed. Optional task
|
|
156
|
+
budgets are checked by the parent poller. On the first exceeded limit the worker
|
|
157
|
+
is steered to stop using tools and return its best answer; if it remains active
|
|
158
|
+
after `PI_BABYSIT_BUDGET_GRACE`, termination is verified before the task is
|
|
159
|
+
marked budget-killed. Usage shown by check/wait is cumulative for the task.
|
|
144
160
|
|
|
145
161
|
## Environment overrides
|
|
146
162
|
|
|
@@ -151,8 +167,11 @@ rule, so a subagent waiting on a long build is never false-killed.
|
|
|
151
167
|
| `PI_BABYSIT_CLI` | `babysit` | babysit binary |
|
|
152
168
|
| `PI_BABYSIT_VIEW_CMD` | bundled `format-stream.mjs` | live-attach pretty printer for subagent JSONL (`""` disables) |
|
|
153
169
|
| `PI_BABYSIT_REAP_AFTER` | `120s` | idle grace before a finished subagent self-exits (`off`/`none`/`0` disables) |
|
|
170
|
+
| `PI_BABYSIT_BUDGET_GRACE` | `30s` | grace after a subagent budget is exceeded before verified termination |
|
|
171
|
+
| `PI_BABYSIT_RPC_LOG_MODE` | `standard` | `compact` removes duplicate RPC lifecycle payloads; `standard` retains legacy payloads |
|
|
172
|
+
| `PI_BABYSIT_RETENTION_DAYS` | unset | when set to a positive number, remove safe terminal roots older than this at session startup |
|
|
154
173
|
| `PI_BABYSIT_TAIL_MAX_BYTES` | `8000` | cap for explicit log tails/screens returned by `babysit_check` |
|
|
155
|
-
| `PI_BABYSIT_INLINE_OUTPUT_MAX_BYTES` | `8000` | cap for complete output
|
|
174
|
+
| `PI_BABYSIT_INLINE_OUTPUT_MAX_BYTES` | `8000` | cap for complete process output and aggregate multi-wait results |
|
|
156
175
|
| `PI_BABYSIT_NOTIFY_OUTPUT_MAX_BYTES` | `2000` | per-process output cap for unsolicited completion notifications (`0` omits all output) |
|
|
157
176
|
| `PI_BABYSIT_NOTIFY_COMMAND_MAX_BYTES` | `240` | cap for each command preview in completion notifications |
|
|
158
177
|
| `PI_BABYSIT_NOTIFY_BATCH_MAX_BYTES` | `8000` | hard cap for one aggregated completion notification |
|
package/agents.ts
CHANGED
|
@@ -56,20 +56,34 @@ function loadAgentsFromDir(
|
|
|
56
56
|
continue;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
let parsed: ReturnType<typeof parseFrontmatter<Record<string, unknown>>>;
|
|
60
|
+
try {
|
|
61
|
+
parsed = parseFrontmatter<Record<string, unknown>>(content);
|
|
62
|
+
} catch {
|
|
63
|
+
// One malformed definition must not prevent every other named agent
|
|
64
|
+
// from being discovered.
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const { frontmatter, body } = parsed;
|
|
68
|
+
if (
|
|
69
|
+
typeof frontmatter.name !== "string" ||
|
|
70
|
+
typeof frontmatter.description !== "string"
|
|
71
|
+
) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
62
74
|
|
|
63
|
-
const tools = frontmatter.tools
|
|
64
|
-
|
|
65
|
-
.
|
|
66
|
-
|
|
75
|
+
const tools = Array.isArray(frontmatter.tools)
|
|
76
|
+
? frontmatter.tools.filter((tool): tool is string => typeof tool === "string")
|
|
77
|
+
: typeof frontmatter.tools === "string"
|
|
78
|
+
? frontmatter.tools.split(",")
|
|
79
|
+
: [];
|
|
80
|
+
const normalizedTools = tools.map((tool) => tool.trim()).filter(Boolean);
|
|
67
81
|
|
|
68
82
|
agents.push({
|
|
69
83
|
name: frontmatter.name,
|
|
70
84
|
description: frontmatter.description,
|
|
71
|
-
tools:
|
|
72
|
-
model: frontmatter.model,
|
|
85
|
+
tools: normalizedTools.length > 0 ? normalizedTools : undefined,
|
|
86
|
+
model: typeof frontmatter.model === "string" ? frontmatter.model : undefined,
|
|
73
87
|
systemPrompt: body,
|
|
74
88
|
source,
|
|
75
89
|
filePath,
|