@tshu-w/pi-agents 0.0.0-stage → 0.1.0

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.
Files changed (48) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +81 -2
  3. package/bin/daemon.mjs +204 -0
  4. package/bin/host.mjs +170 -0
  5. package/bin/pd.mjs +139 -0
  6. package/docs/PROGRAM.md +310 -0
  7. package/docs/SPEC.md +427 -0
  8. package/docs/WORKBENCH.md +165 -0
  9. package/package.json +62 -4
  10. package/src/agents/agents.ts +882 -0
  11. package/src/agents/registry.ts +257 -0
  12. package/src/agents/scheduler.ts +204 -0
  13. package/src/agents/search.ts +131 -0
  14. package/src/agents/tool.ts +205 -0
  15. package/src/daemon/client.mjs +84 -0
  16. package/src/daemon/router.mjs +103 -0
  17. package/src/daemon/sessions.mjs +129 -0
  18. package/src/daemon/version.mjs +19 -0
  19. package/src/host/client.mjs +139 -0
  20. package/src/host/extension.ts +74 -0
  21. package/src/host/frames.mjs +34 -0
  22. package/src/host/keys.mjs +19 -0
  23. package/src/index.ts +208 -0
  24. package/src/output.ts +56 -0
  25. package/src/params.ts +4 -0
  26. package/src/pi.mjs +16 -0
  27. package/src/programs/codemode.ts +74 -0
  28. package/src/programs/execute.ts +131 -0
  29. package/src/programs/host-patches.ts +128 -0
  30. package/src/programs/loadout.ts +99 -0
  31. package/src/programs/programs.ts +284 -0
  32. package/src/programs/sandbox.ts +90 -0
  33. package/src/programs/scope.ts +94 -0
  34. package/src/programs/tool.ts +198 -0
  35. package/src/render-call.ts +90 -0
  36. package/src/roots/discovery.mjs +113 -0
  37. package/src/roots/guard.mjs +227 -0
  38. package/src/roots/lock-extension.mjs +167 -0
  39. package/src/roots/locks.mjs +167 -0
  40. package/src/roots/paths.mjs +66 -0
  41. package/src/roots/report.ts +156 -0
  42. package/src/roots/runtime.ts +174 -0
  43. package/src/roots/snapshot.mjs +46 -0
  44. package/src/roots/socket-recovery.mjs +21 -0
  45. package/src/roots/transport.mjs +341 -0
  46. package/src/ui/panel.ts +96 -0
  47. package/src/ui/viewer.ts +445 -0
  48. package/src/workbench.mjs +587 -0
@@ -0,0 +1,310 @@
1
+ # Pi Agents Program Specification
2
+
3
+ A Program is JavaScript that calls tools and Agents. Agents are defined in
4
+ SPEC.md.
5
+
6
+ The `program` tool replaces Pi's `codemode` tool and keeps its script API,
7
+ tool list, result format, and truncation. This document describes what
8
+ Programs add.
9
+
10
+ ## 1. Semantic model
11
+
12
+ An Agent runs a **Program** with the `program` tool. That Agent is the
13
+ Program's **caller**. The Program can call the caller's tools and create
14
+ Agents.
15
+
16
+ A Program runs in the **foreground** or the **background**. In the
17
+ foreground, the tool call returns the Program's result. In the background,
18
+ the tool call returns the Program's ID, and the caller gets the result with
19
+ `wait`.
20
+
21
+ A Program is shown by its short ID: the shortest prefix of its ID, at least
22
+ 8 characters, that none of the caller's other Programs' IDs starts with. A
23
+ target is an ID or a unique ID prefix.
24
+
25
+ Agents created with `agent()` belong to the Program: it gets their results
26
+ from `send()`, without `wait` or notifications, and only it can abort
27
+ them. Each of these Agents and the Agents under it see only one another,
28
+ and no other Agent sees them. The user sees them in `/tasks` and `/agents`,
29
+ and can talk to them or interrupt them in the viewer; an interrupted input
30
+ makes its `send()` throw. When the Program ends, their unfinished inputs end
31
+ as `aborted`, and the Agents go offline for good, from the bottom up.
32
+
33
+ A Program is `running` until it ends in one of three ways:
34
+
35
+ - `completed`: it returned.
36
+ - `failed`: it threw an error.
37
+ - `stopped`: it was stopped or timed out.
38
+
39
+ ## 2. Operations
40
+
41
+ - `run` runs a Program in the foreground or background, with an optional
42
+ timeout.
43
+ - `wait` waits for background Programs and returns their results.
44
+ - `list` lists the caller's background Programs.
45
+ - `stop` stops a running Program.
46
+
47
+ When a background Program ends and its caller is not waiting for it, the
48
+ caller gets a notification, as in SPEC §5.
49
+
50
+ ## 3. Program API
51
+
52
+ `tools` holds the caller's tools, except `program`; which tools the caller
53
+ can use is checked at each call. If a Program fails or is stopped, the
54
+ error or stop reason follows its output. Its `store()` writes are kept
55
+ only if it completes.
56
+
57
+ A Program also creates Agents with `agent()`:
58
+
59
+ ```ts
60
+ agent(options?: {
61
+ name?: string;
62
+ cwd?: string;
63
+ context?: "fresh" | "fork";
64
+ model?: string;
65
+ thinkingLevel?: string;
66
+ }): AgentHandle
67
+
68
+ interface AgentHandle {
69
+ readonly id: string;
70
+ readonly name: string;
71
+ send(message: string, options?: {
72
+ deliverAs?: "followUp" | "steer" | "write";
73
+ schema?: JsonSchema;
74
+ }): Promise<unknown>;
75
+ abort(): Promise<void>;
76
+ }
77
+ ```
78
+
79
+ `agent()` creates an idle Agent. Options work like `agent` `spawn`; an
80
+ omitted name is generated, unique within the Program. `send()` sends a
81
+ message and returns its result. `abort()` works like `agent` `abort`.
82
+ It gets its tools as if the caller had spawned it.
83
+
84
+ A result is the Agent's answer. If the input fails or is aborted, the
85
+ result throws an Error. A write returns `undefined` once accepted.
86
+
87
+ With `schema`, the Agent must call `submit_result` with a value that
88
+ matches the schema, and the result is that value. If it does not, the
89
+ input fails. `send()` throws if `schema` is used without `followUp`.
90
+
91
+ ## 4. Lifecycle
92
+
93
+ When a Program ends, it cancels its unfinished tool calls and aborts its
94
+ Agents' unfinished inputs, and waits for its Agents to go offline. It
95
+ returns its result after cleanup. Work not stopped within the cleanup
96
+ timeout is abandoned and may keep running; the Program's result and `stop`
97
+ report it as an error.
98
+ Stopping a Program does not undo completed tool calls.
99
+
100
+ When the caller goes offline, its running Programs stop. Their results
101
+ remain available when the caller is loaded again.
102
+
103
+ ## 5. Limits
104
+
105
+ A Program's Agents and the Agents under them count toward the caller's
106
+ tree: they share its slots and `maxOutstanding` limit, as in SPEC §4. At
107
+ `maxOutstanding`, `send()` throws.
108
+
109
+ An owned caller gives up its slot while a foreground Program runs or while
110
+ it waits for background Programs, and takes one again before continuing.
111
+
112
+ ## 6. Model-facing tool
113
+
114
+ ### `program`
115
+
116
+ description:
117
+
118
+ Run JavaScript that composes tool calls and Agents; only its output and
119
+ return value reach the caller. `run` runs a Program in the foreground, or
120
+ in the background with `background`; `wait` waits for background Programs
121
+ and returns their results; `list` lists background Programs; `stop` stops
122
+ a running Program. When a background Program ends while its caller is not
123
+ waiting for it, the caller receives a notification; `wait` returns the
124
+ result.
125
+
126
+ Program code is the body of an async function. It calls the caller's tools
127
+ through `tools.*`, which excludes `program`, and creates Agents through
128
+ `agent()`. These Agents belong to the Program, are isolated from other
129
+ Agents, and go offline when it ends.
130
+
131
+ `program` replaces the `codemode` tool; wherever `codemode` is mentioned,
132
+ use `program`.
133
+
134
+ [the script API of `codemode`, without its Model API]
135
+
136
+ Agent API:
137
+ ```ts
138
+ type JsonSchema = boolean | Record<string, unknown>;
139
+ interface AgentOptions {
140
+ /** Default: generated, unique within the Program. */
141
+ name?: string;
142
+ /** Default: the caller's cwd. */
143
+ cwd?: string;
144
+ /** `fresh` starts without the caller's conversation; `fork` snapshots it. Default: `fresh`. */
145
+ context?: "fresh" | "fork";
146
+ /** provider/modelId. Default: the caller's model. */
147
+ model?: string;
148
+ /** Default: the caller's level. */
149
+ thinkingLevel?: string;
150
+ }
151
+ interface SendOptions {
152
+ /** Default: `followUp`. */
153
+ deliverAs?: "followUp" | "steer" | "write";
154
+ /** `followUp` only. The Agent must submit a value matching it. */
155
+ schema?: JsonSchema;
156
+ }
157
+ interface AgentHandle {
158
+ readonly id: string;
159
+ readonly name: string;
160
+ /** Resolves with the answer, or with the submitted value when `schema` is set; a write resolves with undefined once accepted. Throws if the input fails or is aborted. */
161
+ send(message: string, options?: SendOptions): Promise<unknown>;
162
+ /** Aborts the Agent's current turn and queued inputs; the Agent stays usable. */
163
+ abort(): Promise<void>;
164
+ }
165
+
166
+ /** Creates an idle Agent that belongs to the Program. */
167
+ declare function agent(options?: AgentOptions): AgentHandle;
168
+ ```
169
+
170
+ [the Model API of `codemode`]
171
+
172
+ [the tool list, as set by `codemode.mode`]
173
+
174
+ promptSnippet:
175
+
176
+ Run JavaScript that composes tool calls and Agents
177
+
178
+ promptGuidelines:
179
+
180
+ - Use `program(action='run', code=...)` to call tools or Agents several
181
+ times without a model turn between the calls, for example to read many
182
+ files, filter large tool output, fan out Agents, or loop until a
183
+ condition holds.
184
+ - Use `Promise.allSettled` for independent calls. Return only what the
185
+ caller needs; use `text()` for progress worth reading.
186
+ - Use `background=true` for long Programs, and `program(action='wait', ...)`
187
+ when the next step depends on their results.
188
+
189
+ parameters:
190
+
191
+ - `action`: Operation and applicable parameters: `run(code, background?, timeout?)`, `wait(target?, timeout?)`, `list(limit?, offset?)`, or `stop(target)`.
192
+ - `code`: JavaScript async-function body for `run`.
193
+ - `background`: Whether `run` returns the Program ID at once (default: false).
194
+ - `timeout`: Maximum seconds. For `run` (default: none), expiry stops the Program. For `wait` (default: 30, min: 10, max: 3600), expiry does not stop Programs.
195
+ - `target`: Program ID or unique ID prefix for `wait` or `stop`. `wait` also accepts an array. When omitted for `wait`, selects running Programs and ended Programs whose result has not been returned.
196
+ - `limit`: Maximum Programs returned by `list` (default: 20, max: 200).
197
+ - `offset`: Number of Programs to skip for `list` (default: 0).
198
+
199
+ results:
200
+
201
+ In these formats, `<id>` is the Program's short ID.
202
+
203
+ `run` in the foreground returns the Program result, as an error if the
204
+ Program failed or was stopped.
205
+
206
+ `run` in the background:
207
+
208
+ ```text
209
+ Program <id> started.
210
+ ```
211
+
212
+ `wait` returns one block per result, followed by running Programs on
213
+ timeout:
214
+
215
+ ```text
216
+ <program-result id="<id>" status="<outcome>">
217
+ <result>
218
+ </program-result>
219
+
220
+ Still running: <id>, ...
221
+ ```
222
+
223
+ A single completed result, with nothing running, is returned alone. When
224
+ there are no results or running Programs:
225
+
226
+ ```text
227
+ No results.
228
+ ```
229
+
230
+ `list` returns one entry per background Program, newest first:
231
+
232
+ ```text
233
+ <id> <state>
234
+ ```
235
+
236
+ When more entries remain:
237
+
238
+ ```text
239
+ [N more results. Use offset=X to continue.]
240
+ ```
241
+
242
+ When there are no background Programs:
243
+
244
+ ```text
245
+ No Programs.
246
+ ```
247
+
248
+ `stop`:
249
+
250
+ ```text
251
+ Program <id> stopped.
252
+ Program <id> has already ended.
253
+ ```
254
+
255
+ When some of the Program's work does not stop within the timeout, `stop`
256
+ fails with:
257
+
258
+ ```text
259
+ Program <id> did not stop within the timeout and may still be running.
260
+ ```
261
+
262
+ and the Program's result ends with:
263
+
264
+ ```text
265
+ Cleanup error: some of the Program's work did not stop within the timeout and may still be running.
266
+ ```
267
+
268
+ errors:
269
+
270
+ Invalid calls fail with an error. Errors that need a follow-up say what to
271
+ do:
272
+
273
+ ```text
274
+ No Program matches "<target>". Use list to find Programs.
275
+ ```
276
+
277
+ ```text
278
+ "<target>" matches several Programs: <id>, ... Retry with a longer ID prefix.
279
+ ```
280
+
281
+ truncation:
282
+
283
+ `wait` text beyond Pi's output limits is truncated as in SPEC §6. `wait`
284
+ adds results in order; the result that crosses the limit is truncated but keeps
285
+ its closing tag, and later results are omitted. A truncated result counts
286
+ as returned. Omitted results stay unreturned, and the text ends with:
287
+
288
+ ```text
289
+ [Results omitted: <id>, ... Use wait with fewer targets.]
290
+ ```
291
+
292
+ messages:
293
+
294
+ A notification to the caller:
295
+
296
+ ```text
297
+ Program <id> <outcome>.
298
+ ```
299
+
300
+ ## 7. Human interface
301
+
302
+ The task panel (SPEC §7) lists running background Programs.
303
+
304
+ ## 8. Configuration
305
+
306
+ `program` is inactive by default, like `codemode`; enable it with `"defaultTools": ["+program"]` or `--tools`.
307
+ MCP treats `program` as `codemode`: it activates `program` when its servers need a script tool and neither is active, unless `autoEnableCodemode` is false, and a Program waits for the MCP servers its code names.
308
+ When both `program` and `codemode` are active, Pi warns once per Session, since they do a similar job.
309
+ `codemode.mode` decides how the tool list is presented, as for `codemode`.
310
+ `--program-only` activates `program` and uses `only` for the process, including its owned Agents.