@llblab/pi-actors 0.12.13 → 0.13.3
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/BACKLOG.md +1 -1
- package/CHANGELOG.md +26 -0
- package/README.md +6 -6
- package/docs/actor-messages.md +12 -7
- package/docs/async-runs.md +19 -29
- package/docs/recipe-library.md +4 -4
- package/docs/template-recipes.md +3 -3
- package/lib/prompts.ts +1 -1
- package/lib/tools.ts +8 -7
- package/package.json +1 -1
- package/recipes/pipeline-async-run-ops.json +4 -4
- package/recipes/utility-run-ops-snapshot.json +3 -3
- package/scripts/recipe-utils.mjs +2 -2
package/BACKLOG.md
CHANGED
|
@@ -6,7 +6,7 @@ Continue progressive component/pipeline expansion in small validated slices; rea
|
|
|
6
6
|
|
|
7
7
|
- Plan organic universal communication primitives.
|
|
8
8
|
- Priority: High.
|
|
9
|
-
- Status: The actor-like model is empirically useful: async runs can emit follow-up messages upward, coordinators can send run-local commands downward, multiple parallel runs can progress independently, and recipes no longer need sleep-poll coordination. The design is captured in `docs/actor-messages.md`: `spawn`, `message`, and `inspect` as concentrated verbs; addressed actors; one symmetric message envelope; mailbox `accepts`/`emits`; and adapter mappings from runtime async actions. Initial implementation landed pure actor address/message normalization plus public `spawn`, `message`, and `inspect` tools for `run:<id>` actors; `spawn` accepts state/artifact metadata, `message` routes `run:<id>` → `coordinator` and `run:<id>` → `session:<id>` envelopes into the runtime attention path, `message` can invoke `tool:<name>` actors, `inspect target=tool:<name>` exposes registered tool actor contracts, `inspect target=coordinator` exposes current-session run inventory, all packaged async recipes declare mailbox metadata, `inspect view=mailbox` exposes recipe mailbox contracts from run metadata, recipe-authored messages now use envelope-aligned `type` fields with deterministic validated wrapping available through `utility-actor-message`, run termination now
|
|
9
|
+
- Status: The actor-like model is empirically useful: async runs can emit follow-up messages upward, coordinators can send run-local commands downward, multiple parallel runs can progress independently, and recipes no longer need sleep-poll coordination. The design is captured in `docs/actor-messages.md`: `spawn`, `message`, and `inspect` as concentrated verbs; addressed actors; one symmetric message envelope; mailbox `accepts`/`emits`; and adapter mappings from runtime async actions. Initial implementation landed pure actor address/message normalization plus public `spawn`, `message`, and `inspect` tools for `run:<id>` actors; `spawn` accepts state/artifact metadata, `message` routes `run:<id>` → `coordinator` and `run:<id>` → `session:<id>` envelopes into the runtime attention path, `message` can invoke `tool:<name>` actors, `inspect target=tool:<name>` exposes registered tool actor contracts, `inspect target=coordinator` exposes current-session run inventory, all packaged async recipes declare mailbox metadata, `inspect view=mailbox` exposes recipe mailbox contracts from run metadata, recipe-authored messages now use envelope-aligned `type` fields with deterministic validated wrapping available through `utility-actor-message`, run termination now uses actor-native `control.stop`/`control.cancel`/`control.kill` without runtime-prefixed control aliases, async command events preserve full argv details while keeping coordinator summaries bounded, async-run operations recommendations now emit structured `message`/`inspect` objects instead of shell-like suggestion strings, `inspect view=messages` exposes run actor messages while retaining `events` as a compatibility alias, async-run operations recipes now expose `message_file`/`messages` terminology instead of public event-file args, and operator-facing docs now describe coordination with actor-message terminology before transport details, async-run docs separate public actor behavior from storage/transport mechanics more clearly, public actor-message/template guidance avoids transport-specific wording, and async-run operations recipes now use only `message_file` for actor-message inputs. Remaining work is to absorb remaining runtime async action surfaces into the actor vocabulary instead of preserving a parallel public API.
|
|
10
10
|
- Scope: Design and implement a small semantic layer around addressed messages and actors while preserving low-level primitives as adapters where useful. Candidate top-level concepts are `spawn` for creating an actor/run from a recipe or template, `message` for sending typed messages to any address, and `inspect` for intentional observation/debugging. Candidate addresses include `run:<id>`, `branch:<run>/<branch>`, `coordinator`, `session:<id>`, `tool:<name>`, and future chat/session endpoints. Candidate message fields include `to`, `from`, `type`, `summary`, `body`, `reply_to`, `correlation_id`, and `metadata`.
|
|
11
11
|
- Contract direction: Unify “send down” and “messages up” as one message model. `to: run:<id>` routes to a run mailbox, `to: coordinator` routes to the coordinator attention path, and branch/tool/session addresses can be layered over the same semantic envelope. Recipes should declare mailbox capability (`accepts`, `emits`) without exposing FIFO/outbox mechanics or delivery policy as their public interface.
|
|
12
12
|
- Design gates: Breaking changes are allowed in this phase, so compress concepts instead of preserving accidental surfaces. Consolidate duplicated lifecycle/message/event APIs into a concentrated protocol with the fewest durable nouns and verbs that still explain the system. Duplex communication should be symmetric where the domain is symmetric: the same message envelope should represent run→coordinator, coordinator→run, run→run, branch→parent, and parent→branch traffic, with routing/transport hidden below it. Keep command templates as the portable synchronous execution graph; keep recipe files as semantic definitions; avoid leaking transports into public args; make polling an explicit diagnostic operation, not an example path; replace runtime action names with the actor API rather than preserving parallel concepts.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.13.3: Actor Vocabulary Cleanup
|
|
4
|
+
|
|
5
|
+
- `[Docs]` Removed remaining public FIFO/outbox phrasing from actor-message/template-recipe docs and runtime prompt guidance. Impact: agent and operator guidance now consistently describes `spawn`, `message`, and `inspect` without transport-specific vocabulary.
|
|
6
|
+
- `[Recipe Library]` Removed the legacy `event_file` default from async-run operations recipes. Impact: the recipe surface now uses only `message_file` for run actor-message inputs.
|
|
7
|
+
|
|
8
|
+
## 0.13.2: Async Run Actor Vocabulary Docs
|
|
9
|
+
|
|
10
|
+
- `[Docs]` Reframed `docs/async-runs.md` around actor messages and run-local control channels, keeping file names and transport details in implementation sections. Impact: the async-run standard now separates public `spawn`/`message`/`inspect` behavior from storage/transport mechanics more clearly.
|
|
11
|
+
|
|
12
|
+
## 0.13.1: Public Actor Vocabulary Docs
|
|
13
|
+
|
|
14
|
+
- `[Docs]` Replaced remaining public README and recipe-library wording that described run coordination as events, FIFO, or outbox paths with actor-message and run-local control-channel terminology. Impact: operator-facing docs now teach the actor vocabulary first while keeping transport details in the async-run implementation reference.
|
|
15
|
+
|
|
16
|
+
## 0.13.0: Actor-Native Control Surface
|
|
17
|
+
|
|
18
|
+
- `[Actor Messages]` Removed `runtime.cancel` and `runtime.kill` termination aliases from `message to=run:<id>`. Impact: run termination now uses only actor-native `control.stop`, `control.cancel`, and `control.kill`; runtime-prefixed control names are no longer treated as public API.
|
|
19
|
+
|
|
20
|
+
## 0.12.15: Run Operations Message File Vocabulary
|
|
21
|
+
|
|
22
|
+
- `[Recipe Library]` Renamed async-run operations recipe inputs from `event_file` to `message_file`, with legacy `event_file` retained only as an internal default fallback. Impact: public recipe args align with the actor-message vocabulary while existing value-based launches can still supply the old key.
|
|
23
|
+
- `[Recipe Utilities]` Renamed `run-ops-snapshot` output from `events` to `messages`. Impact: operations reports now describe run outbox records as actor messages instead of runtime events.
|
|
24
|
+
|
|
25
|
+
## 0.12.14: Actor Message Inspection Alias
|
|
26
|
+
|
|
27
|
+
- `[Actor Messages]` Added `inspect view=messages` for run actors, with `events` retained as a compatibility alias for the same outbox-backed actor messages. Impact: the public inspection vocabulary now matches the actor/message model while preserving existing event-oriented diagnostics.
|
|
28
|
+
|
|
3
29
|
## 0.12.13: Structured Run Operations Recommendations
|
|
4
30
|
|
|
5
31
|
- `[Recipe Utilities]` Changed `utility-run-ops-snapshot` recommendations from shell-like suggestion strings to structured `message` and `inspect` call objects. Impact: async-run operations reports now preserve the actor API shape directly and avoid reintroducing command-string parsing into coordinator handoffs.
|
package/README.md
CHANGED
|
@@ -295,13 +295,13 @@ Start from an inline template as an addressable run actor:
|
|
|
295
295
|
}
|
|
296
296
|
```
|
|
297
297
|
|
|
298
|
-
Do not check it on a timer. Let follow-up
|
|
298
|
+
Do not check it on a timer. Let follow-up actor messages arrive from the run, then react to a run-local request or redirect a long-lived recipe without polling/restarting it:
|
|
299
299
|
|
|
300
300
|
```json
|
|
301
301
|
{ "to": "run:docs-review", "type": "control.continue", "body": "continue" }
|
|
302
302
|
```
|
|
303
303
|
|
|
304
|
-
Read recent
|
|
304
|
+
Read recent actor messages or logs only after a follow-up asks for inspection, at a real decision point, or during diagnosis:
|
|
305
305
|
|
|
306
306
|
```json
|
|
307
307
|
{ "target": "run:docs-review", "view": "tail", "lines": "80" }
|
|
@@ -376,12 +376,12 @@ See [`docs/recipe-library.md`](./docs/recipe-library.md) for install notes and r
|
|
|
376
376
|
- Obvious high-risk templates such as shells, interpreter eval modes, and broad filesystem mutation surface lightweight warnings without blocking existing tools.
|
|
377
377
|
- `async: true` on a recipe selects detached run lifecycle; omitted or false async runs the recipe foreground through registered tools.
|
|
378
378
|
- Layer boundaries stay explicit: command templates define synchronous execution graphs; template recipes add saved JSON metadata/import resolution and named `artifacts`; async runs add detached lifecycle, state, IPC, and observability.
|
|
379
|
-
- `spawn`, `message`, and `inspect` are high-level actor adapters. `spawn` creates `run:<id>` actors from recipes or inline templates with optional state/artifact metadata, `message` sends one typed envelope to `run:<id>` mailboxes, `branch:<run>/<branch>` mailboxes, `tool:<name>` calls, or coordinator/session attention paths, and `inspect` intentionally reads `run:<id>` status/tail/
|
|
380
|
-
- `spawn`, `message`, and `inspect` are the public async coordination vocabulary. Low-level async actions map to this actor API: start belongs to `spawn`; send/control/stop/kill belongs to `message`; status/tail/
|
|
379
|
+
- `spawn`, `message`, and `inspect` are high-level actor adapters. `spawn` creates `run:<id>` actors from recipes or inline templates with optional state/artifact metadata, `message` sends one typed envelope to `run:<id>` mailboxes, `branch:<run>/<branch>` mailboxes, `tool:<name>` calls, or coordinator/session attention paths, and `inspect` intentionally reads `run:<id>` status/tail/messages/mailbox metadata, coordinator/session run status, or registered `tool:<name>` contracts while the broader actor/message protocol is refined.
|
|
380
|
+
- `spawn`, `message`, and `inspect` are the public async coordination vocabulary. Low-level async actions map to this actor API: start belongs to `spawn`; send/control/stop/kill belongs to `message`; status/tail/messages/list belongs to `inspect`; `events` remains a compatibility inspection view. Use `control.stop`, `control.cancel`, and `control.kill` for run termination; runtime-prefixed control aliases are no longer part of the public surface.
|
|
381
381
|
- Actor management returns compact text by default; pass `verbose: true` to `inspect` when full JSON state is needed.
|
|
382
382
|
- Detached runs inject `{run_id}` and `{state_dir}` into template values for run-local artifacts or recipe-specific control endpoints.
|
|
383
|
-
- Runtime actor messages are
|
|
384
|
-
- Native Windows should use WSL or a recipe-specific transport for
|
|
383
|
+
- Runtime actor messages are persisted in the run state dir; coordinator attention is inferred by the runtime, not exposed as recipe or message-envelope input. Follow-ups preserve bounded body previews and metadata for decision messages.
|
|
384
|
+
- Native Windows should use WSL or a recipe-specific transport for run-local message-controlled recipes; Linux uses stricter `/proc` runner ownership checks for stale PID protection.
|
|
385
385
|
- Registered tools may set `template` to a recipe JSON path/name; calling them follows that recipe's `async` mode.
|
|
386
386
|
- File-backed recipes may declare `imports` and embed imported recipes with `{ "name": "alias" }` nodes, or read `{alias.defaults.key}`, `{alias.defaults.key=fallback}`, and `{alias.values.key?yes:no}` references before command-template execution.
|
|
387
387
|
- Interactive sessions show ambient async activity as stable `▷` triangles aggregated across runs started by the current agent session. Each running async run contributes at least one triangle; parallel active branches can contribute more. One `▶` wave moves over the active set; terminal `done`/`failed`/unhandled `killed`/`exited` messages are delivered as compact follow-up context only to the launching coordinator agent, while intentional `cancel`, `kill`, and `stop` actions stay silent because the action already reports synchronously. Failed commands and in-flight parallel branch completions can bubble through `command.done`; successful final leaf completions remain diagnostic to avoid sequential pipeline noise.
|
package/docs/actor-messages.md
CHANGED
|
@@ -8,7 +8,7 @@ Compress communication to three durable verbs:
|
|
|
8
8
|
|
|
9
9
|
- `spawn`: create an addressable actor from a recipe, template, or tool.
|
|
10
10
|
- `message`: send one typed message to one address.
|
|
11
|
-
- `inspect`: intentionally observe state, logs,
|
|
11
|
+
- `inspect`: intentionally observe state, logs, actor messages, or artifacts.
|
|
12
12
|
|
|
13
13
|
Everything else is an adapter until proven otherwise.
|
|
14
14
|
|
|
@@ -78,8 +78,8 @@ coordinator -> tool
|
|
|
78
78
|
|
|
79
79
|
Transports differ, but the public contract does not:
|
|
80
80
|
|
|
81
|
-
- `to: run:<id>`
|
|
82
|
-
- `to: coordinator` routes to
|
|
81
|
+
- `to: run:<id>` routes through the run-local control channel selected by that recipe or runtime adapter.
|
|
82
|
+
- `to: coordinator` routes to the runtime attention path when `from` names a run actor. `to: session:<id>` uses the same actor-message path only when the sender run is owned by that session, making explicit session-directed checkpoints possible without exposing runtime delivery knobs. Generic async-runner `command.done` messages and explicit coordinator/session-bound messages include the actor envelope fields alongside runtime metadata.
|
|
83
83
|
- `to: branch:<run>/<branch>` routes through the parent run mailbox with the full envelope preserved so the run can dispatch branch-local control.
|
|
84
84
|
- `to: tool:<name>` invokes an executable pi tool by name. Object bodies become tool parameters; primitive bodies are passed as `{ "input": body }`.
|
|
85
85
|
|
|
@@ -92,13 +92,18 @@ Recipes can declare their conversational surface:
|
|
|
92
92
|
```json
|
|
93
93
|
{
|
|
94
94
|
"mailbox": {
|
|
95
|
-
"accepts": [
|
|
95
|
+
"accepts": [
|
|
96
|
+
"control.continue",
|
|
97
|
+
"control.revise",
|
|
98
|
+
"control.approve",
|
|
99
|
+
"control.stop"
|
|
100
|
+
],
|
|
96
101
|
"emits": ["checkpoint.needs_scope", "branch.done", "run.done"]
|
|
97
102
|
}
|
|
98
103
|
}
|
|
99
104
|
```
|
|
100
105
|
|
|
101
|
-
`mailbox.accepts` is a contract for coordinator-to-actor messages. `mailbox.emits` is a contract for actor-to-coordinator or actor-to-actor messages. Packaged interactive and message-producing recipes declare mailbox metadata so coordinators can discover semantic message types without reading
|
|
106
|
+
`mailbox.accepts` is a contract for coordinator-to-actor messages. `mailbox.emits` is a contract for actor-to-coordinator or actor-to-actor messages. Packaged interactive and message-producing recipes declare mailbox metadata so coordinators can discover semantic message types without reading transport details. Message-producing recipes produce actor-message-envelope-shaped records with `to`, `from`, `type`, `summary`, `body`, optional `correlation_id`/`reply_to`, and optional `metadata` fields. Coordinator follow-ups preserve bounded body previews and metadata so checkpoints do not lose their actionable payload. Deterministic pipelines should prefer `utility-actor-message` for this wrapping so message shape is validated and guaranteed instead of delegated to a prompt; its recipe args intentionally mirror the envelope field names.
|
|
102
107
|
|
|
103
108
|
## Spawn
|
|
104
109
|
|
|
@@ -126,7 +131,7 @@ Recipes can declare their conversational surface:
|
|
|
126
131
|
}
|
|
127
132
|
```
|
|
128
133
|
|
|
129
|
-
The implementation supports `status`, `tail`, `events`, `artifacts`, `files`, and `mailbox` for `run:<id>` actors, `status`/`runs` for `coordinator`, `session:<id>`, and `session:all` actors with optional status filtering, and `status`/`schema` for registered `tool:<name>` actors. `inspect target=coordinator` requires a current coordinator session; use `session:<id>` or `session:all` when the session is intentionally explicit. Direct `run:<id>` inspection respects coordinator-session ownership when the current session is known. `inspect` is for decision points and diagnosis only; examples must not teach sleep-then-inspect polling.
|
|
134
|
+
The implementation supports `status`, `tail`, `messages`, `events`, `artifacts`, `files`, and `mailbox` for `run:<id>` actors, `status`/`runs` for `coordinator`, `session:<id>`, and `session:all` actors with optional status filtering, and `status`/`schema` for registered `tool:<name>` actors. Prefer `messages` for actor-envelope inspection; `events` remains a compatibility alias for the same run message stream. `inspect target=coordinator` requires a current coordinator session; use `session:<id>` or `session:all` when the session is intentionally explicit. Direct `run:<id>` inspection respects coordinator-session ownership when the current session is known. `inspect` is for decision points and diagnosis only; examples must not teach sleep-then-inspect polling.
|
|
130
135
|
|
|
131
136
|
## Runtime Direction
|
|
132
137
|
|
|
@@ -144,7 +149,7 @@ intentional observe -> inspect
|
|
|
144
149
|
## Non-goals
|
|
145
150
|
|
|
146
151
|
- No generic expression language in templates.
|
|
147
|
-
- No public
|
|
152
|
+
- No public transport-path vocabulary in recipe args.
|
|
148
153
|
- No polling-first examples.
|
|
149
154
|
- No separate upward and downward message schemas.
|
|
150
155
|
- No broad facade that hides artifacts, logs, or ownership checks.
|
package/docs/async-runs.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Async runs are detached executions of a template recipe or inline command template.
|
|
4
4
|
|
|
5
|
-
**Meta-contract:** the command template is still the execution graph; the async run is only a lifecycle envelope with state, logs,
|
|
5
|
+
**Meta-contract:** the command template is still the execution graph; the async run is only a lifecycle envelope with state, logs, actor messages, status, cancellation, and coordinator-scoped observability.
|
|
6
6
|
|
|
7
|
-
**Scope:** run id, state path, runner pid, process-group cancellation, logs, status, tail, list, script-authored
|
|
7
|
+
**Scope:** run id, state path, runner pid, process-group cancellation, logs, status, tail, list, script-authored actor messages, run-local control messages, cancel, force-kill, terminal result state, ambient activity indicators, and extension-owned temp storage. No scheduler, queue daemon, workflow DSL, distributed worker, or second execution language.
|
|
8
8
|
|
|
9
|
-
Layer boundary: async-run configuration may inject lifecycle values such as `{run_id}` and `{state_dir}` and may choose detached execution through `async: true`, but it does not add command-template graph syntax. Recipe imports and recipe-local references belong to the template-recipe layer; status,
|
|
9
|
+
Layer boundary: async-run configuration may inject lifecycle values such as `{run_id}` and `{state_dir}` and may choose detached execution through `async: true`, but it does not add command-template graph syntax. Recipe imports and recipe-local references belong to the template-recipe layer; status, control messages, actor messages, cancel, and kill belong to the async-run layer.
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
@@ -15,7 +15,7 @@ Layer boundary: async-run configuration may inject lifecycle values such as `{ru
|
|
|
15
15
|
Async-run standard owns:
|
|
16
16
|
|
|
17
17
|
- Detached process lifecycle for one execution instance.
|
|
18
|
-
- Run identity, state directory, pid/process-group tracking, logs, status, list, tail,
|
|
18
|
+
- Run identity, state directory, pid/process-group tracking, logs, status, list, tail, actor-message inspection, run-local control, cancel, and kill.
|
|
19
19
|
- Injected lifecycle values such as `{run_id}` and `{state_dir}`.
|
|
20
20
|
- Coordinator-scoped observability and script-authored actor messages.
|
|
21
21
|
|
|
@@ -31,8 +31,8 @@ Async-run standard does not own:
|
|
|
31
31
|
```text
|
|
32
32
|
recipe = saved JSON definition
|
|
33
33
|
run = one execution instance
|
|
34
|
-
lifecycle = state/logs/
|
|
35
|
-
state dir = ordinary files for status/logs/
|
|
34
|
+
lifecycle = state/logs/messages/status/control/cancel/kill envelope
|
|
35
|
+
state dir = ordinary files for status/logs/messages/result
|
|
36
36
|
coordinator = agent session that started the run
|
|
37
37
|
```
|
|
38
38
|
|
|
@@ -80,8 +80,8 @@ Use ordinary files under the extension temp directory so status tools stay simpl
|
|
|
80
80
|
|
|
81
81
|
- `run.json`: pid, optional source metadata (`tool`, `recipe`, `recipe_file`), command-template config, cwd, coordinator owner id, values, named `artifacts`, mailbox metadata, created time, and state dir.
|
|
82
82
|
- `progress.json`: phase, active command count, completed count, failures, and updated time.
|
|
83
|
-
- `events.jsonl`: append-only lifecycle
|
|
84
|
-
- `outbox.jsonl`:
|
|
83
|
+
- `events.jsonl`: append-only implementation lifecycle log.
|
|
84
|
+
- `outbox.jsonl`: implementation storage for actor-message envelopes used by `inspect view=messages`, coordinator notifications, or follow-up context. Coordinator follow-ups preserve bounded `body` previews plus message metadata for decision points.
|
|
85
85
|
- `stdout.log` and `stderr.log`: detached process output.
|
|
86
86
|
- `result.json`: final code, killed flag, output selector, and optional full-output path.
|
|
87
87
|
|
|
@@ -107,7 +107,7 @@ Terminal status is `done` for result code 0 and `failed` for non-zero result cod
|
|
|
107
107
|
|
|
108
108
|
## Reactive Coordinator Loop
|
|
109
109
|
|
|
110
|
-
Async runs are designed for
|
|
110
|
+
Async runs are designed for message-driven coordination, not polling loops. A good coordinator starts long-lived or multi-agent work, lets completion and decision-point actor messages bubble upward, and sends corrective commands only when the run asks for input or the operator changes direction.
|
|
111
111
|
|
|
112
112
|
The core loop is:
|
|
113
113
|
|
|
@@ -117,7 +117,7 @@ The core loop is:
|
|
|
117
117
|
{ "recipe": "music-player.json", "as": "run:music" }
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
-
2. Let terminal
|
|
120
|
+
2. Let terminal completion, `command.done`, and script-authored follow-up messages reach the launching coordinator automatically.
|
|
121
121
|
|
|
122
122
|
3. Respond with explicit run-local messages when needed:
|
|
123
123
|
|
|
@@ -125,7 +125,7 @@ The core loop is:
|
|
|
125
125
|
{ "to": "run:music", "type": "player.next", "body": "next" }
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
-
4. Do not inspect just because time passed. Inspect `status`, `tail`, or `
|
|
128
|
+
4. Do not inspect just because time passed. Inspect `status`, `tail`, or `messages` only when a follow-up asks for inspection, a real decision depends on it, or a suspected stuck run needs diagnosis.
|
|
129
129
|
|
|
130
130
|
Addressed `message` calls and coordinator follow-ups are the paired control plane: run-to-coordinator actor messages flow upward, while coordinator-to-run actor messages flow downward. Recipe scripts own the message vocabulary (`next`, `pause`, `approve`, `revise`, `continue`, and so on); pi-actors owns the safe run-local transport, coordinator-session ownership checks, and coordinator attention policy.
|
|
131
131
|
|
|
@@ -135,13 +135,13 @@ The actor-level surface is:
|
|
|
135
135
|
|
|
136
136
|
- `spawn`: start a detached `run:<id>` actor from `file`, `recipe`, or inline `template`.
|
|
137
137
|
- `message`: send one typed envelope to `run:<id>`, `branch:<run>/<branch>`, `tool:<name>`, `coordinator`, or `session:<id>`.
|
|
138
|
-
- `inspect`: intentionally read owned `run:<id>` status, tail, events, artifacts, files, or mailbox metadata; read current `coordinator` run inventory only when a coordinator session is known; read `session:<id>` or `session:all` run inventory with optional status filtering when the session is explicit; read `tool:<name>` status or schema for registered tool actors.
|
|
138
|
+
- `inspect`: intentionally read owned `run:<id>` status, tail, messages, events, artifacts, files, or mailbox metadata; read current `coordinator` run inventory only when a coordinator session is known; read `session:<id>` or `session:all` run inventory with optional status filtering when the session is explicit; read `tool:<name>` status or schema for registered tool actors.
|
|
139
139
|
|
|
140
140
|
Low-level async actions map into the actor surface instead of forming a second public model:
|
|
141
141
|
|
|
142
142
|
- start → `spawn`
|
|
143
143
|
- send/control → `message`
|
|
144
|
-
- status/tail/events/list → `inspect`
|
|
144
|
+
- status/tail/messages/events/list → `inspect`
|
|
145
145
|
- stop/kill → `message` with `control.stop` or `control.kill`, with synchronous results
|
|
146
146
|
|
|
147
147
|
Compact text is returned by default so async management does not flood agent context; use verbose inspection when the full state object is needed. List output intentionally shares one state root across music, subagents, timers, and other async work; source fields such as `tool` and `recipe` distinguish run purpose when the launcher recorded them. Registered tools are the preferred user-facing surface for reusable recipes.
|
|
@@ -150,13 +150,7 @@ Compact text is returned by default so async management does not flood agent con
|
|
|
150
150
|
|
|
151
151
|
`message` is the explicit coordinator-to-actor command channel. Use it when a running recipe exposes a control vocabulary, a branch needs parent-mediated control, a registered tool should be invoked as `tool:<name>`, or the coordinator needs to redirect work without killing or restarting it.
|
|
152
152
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
```text
|
|
156
|
-
<state_dir>/control.fifo
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
When present, a caller can send a typed actor message:
|
|
153
|
+
Some recipes expose a run-local control channel. When present, a caller can send a typed actor message:
|
|
160
154
|
|
|
161
155
|
```json
|
|
162
156
|
{
|
|
@@ -166,23 +160,19 @@ When present, a caller can send a typed actor message:
|
|
|
166
160
|
}
|
|
167
161
|
```
|
|
168
162
|
|
|
169
|
-
For `run:<id>`, `message` adapts the body to the
|
|
163
|
+
For `run:<id>`, `message` adapts the body to the recipe's run-local control channel. For `branch:<run>/<branch>`, it sends the full envelope through the parent run mailbox so the run can dispatch branch-local control. For `tool:<name>`, object bodies become the target tool parameters and primitive bodies are passed as `{ "input": body }`. The generic runtime records control messages but does not interpret arbitrary run mailbox content. For example, a music player may accept `play`, `pause`, `next`, and `stop`, while a collaborative agent recipe may accept `continue`, `revise:<note>`, `approve`, or `abort`. Recipes may treat terminal control messages such as `stop` as synchronously handled so the later process exit does not generate a duplicate async follow-up.
|
|
170
164
|
|
|
171
|
-
|
|
165
|
+
The standard run-local transport is Unix-oriented. Use WSL/Linux/macOS for packaged message-controlled recipes, or let a Windows-specific recipe expose its own transport such as a Windows named pipe or localhost socket.
|
|
172
166
|
|
|
173
167
|
## Coordinator Notifications
|
|
174
168
|
|
|
175
169
|
The launching coordinator should not busy-poll long-running async runs. The extension watches run state directories and delivers terminal `done`/`failed`/unhandled `killed`/`exited` transitions plus script-authored `notify`/`followup` actor messages back to the owning session. This gives the top-level async task a completion signal on the happy path while still letting recipe-local messages bubble up when scripts need finer-grained notifications. Terminal follow-ups include recipe-level named `artifacts` when declared. The generic runner also emits compact `command.done` actor messages for completed leaf commands; recipe authors declare that capability in `mailbox.emits` rather than configuring a separate delivery policy. Failures and in-flight parallel branch completions can bubble as follow-ups, while successful final leaf completions stay diagnostic to avoid flooding long sequential pipelines. Branch-level `command.done` follow-ups omit artifact manifests because the top-level terminal follow-up carries them once. Intentional `control.stop`, `control.kill`, and recipe-local stop commands stay out of follow-up context because the initiating message already returns synchronously. If a follow-up asks for direction, answer with `message` rather than starting a polling loop. Use explicit `inspect` only when a delivered follow-up requests inspection, a real decision depends on state, or a suspected stuck run needs diagnosis — never merely because a timeout elapsed.
|
|
176
170
|
|
|
177
|
-
Ambient status indicators may refresh while work is active, but coordinator attention is
|
|
171
|
+
Ambient status indicators may refresh while work is active, but coordinator attention is driven from run-state changes rather than a coordinator agent loop. This lets the coordinator continue other work after `spawn`; the run signals back through lifecycle state, results, and actor messages. The ambient triangle count represents active async work units: each running async run contributes at least one triangle, and a run with multiple active parallel command/subagent branches contributes the reported active branch count. If a coordinator starts one parent run with four active parallel branches, four triangles are shown; if the same coordinator starts five independent single-branch runs, five triangles are shown.
|
|
178
172
|
|
|
179
173
|
## Run Actor Messages
|
|
180
174
|
|
|
181
|
-
A recipe or script may
|
|
182
|
-
|
|
183
|
-
```text
|
|
184
|
-
<state_dir>/outbox.jsonl
|
|
185
|
-
```
|
|
175
|
+
A recipe or script may emit coordinator-bound or session-bound actor message records. The runtime persists those records in the run state dir and exposes them through `inspect target=run:<id> view=messages`.
|
|
186
176
|
|
|
187
177
|
Shape:
|
|
188
178
|
|
|
@@ -208,7 +198,7 @@ An async run belongs to the current user, cwd, and launching agent session at st
|
|
|
208
198
|
|
|
209
199
|
On Unix-like systems, cancel and kill signal the runner process group when available, then fall back to the runner pid. The runner starts command-template children in that process group, so long-running descendants such as audio players stop with the run instead of becoming orphaned background processes. After the process exits, status reflects the operator action as `cancelled` or `killed` instead of a generic `exited`.
|
|
210
200
|
|
|
211
|
-
State is append-only where practical. Final result writes should be atomic. Recipe-local control endpoints and actor-message logs may live in the state dir. pi-actors core owns
|
|
201
|
+
State is append-only where practical. Final result writes should be atomic. Recipe-local control endpoints and actor-message logs may live in the state dir. pi-actors core owns the generic run-local message adapter and runtime attention policy; command and message vocabularies belong to the recipe/script.
|
|
212
202
|
|
|
213
203
|
## Extension Temp Directory
|
|
214
204
|
|
package/docs/recipe-library.md
CHANGED
|
@@ -117,9 +117,9 @@ Files:
|
|
|
117
117
|
- `recipes/music-player.json`
|
|
118
118
|
- `scripts/music-player.mjs`
|
|
119
119
|
|
|
120
|
-
Purpose: start a local or URL audio source as an async run so the agent can continue working while playback runs in the background. The running script exposes
|
|
120
|
+
Purpose: start a local or URL audio source as an async run so the agent can continue working while playback runs in the background. The running script exposes a run-local mailbox, so addressed `message` calls can control playback without a second recipe.
|
|
121
121
|
|
|
122
|
-
Requirements: Linux, macOS, or WSL
|
|
122
|
+
Requirements: Linux, macOS, or WSL, Node.js, and one of `mpv`, `ffplay`, `cvlc`, or SoX `play`. Native Windows is not supported by the standard wrapper; use WSL or a platform-specific recipe transport.
|
|
123
123
|
|
|
124
124
|
The required `source` arg accepts:
|
|
125
125
|
|
|
@@ -160,7 +160,7 @@ message to=run:music type=player.previous body=previous
|
|
|
160
160
|
message to=run:music type=player.stop body=stop
|
|
161
161
|
```
|
|
162
162
|
|
|
163
|
-
Use `inspect target=run:music view=status` only when an
|
|
163
|
+
Use `inspect target=run:music view=status` only when an actor message or operator decision requires inspection.
|
|
164
164
|
|
|
165
165
|
The wrapper also accepts control commands directly when a caller already has the run state dir:
|
|
166
166
|
|
|
@@ -168,7 +168,7 @@ The wrapper also accepts control commands directly when a caller already has the
|
|
|
168
168
|
scripts/music-player.mjs next ~/.pi/agent/tmp/pi-actors/runs/music
|
|
169
169
|
```
|
|
170
170
|
|
|
171
|
-
Message body is
|
|
171
|
+
Message body is adapted to the recipe's run-local control channel. The script writes `status.txt`, `player.json`, and track-change actor messages in the same state dir. Track-change messages stay diagnostic by default; interactive recipes should define a small command vocabulary for addressed messages, emit semantic actor messages for decision points, and let the coordinator react to messages rather than sleep-polling state.
|
|
172
172
|
|
|
173
173
|
## Safety Notes
|
|
174
174
|
|
package/docs/template-recipes.md
CHANGED
|
@@ -35,7 +35,7 @@ Template-recipe standard owns:
|
|
|
35
35
|
Template-recipe standard does not own:
|
|
36
36
|
|
|
37
37
|
- How command-template nodes execute internally.
|
|
38
|
-
- Async state files, logs,
|
|
38
|
+
- Async state files, logs, run-local transports, status, cancellation, or observability.
|
|
39
39
|
- Tool registry naming, button UX, package installation, or operator-specific policy.
|
|
40
40
|
- Domain workflows such as swarm quorum, release policy, backlog parsing, or merge policy.
|
|
41
41
|
|
|
@@ -86,7 +86,7 @@ Use recipe-level `artifacts` to declare stable artifact names and paths for the
|
|
|
86
86
|
}
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
`output` and `artifacts` are intentionally different. `output` is the command-template primary result selector and defaults to stdout; it participates in sequence/stdin flow. `artifacts` is recipe metadata: an ordered named artifact manifest for humans, async completion
|
|
89
|
+
`output` and `artifacts` are intentionally different. `output` is the command-template primary result selector and defaults to stdout; it participates in sequence/stdin flow. `artifacts` is recipe metadata: an ordered named artifact manifest for humans, async completion messages, and downstream tooling. `stdout` remains the default command result channel and is not renamed by `artifacts`.
|
|
90
90
|
|
|
91
91
|
## Mailbox
|
|
92
92
|
|
|
@@ -101,7 +101,7 @@ Use recipe-level `mailbox` to document the semantic messages a recipe actor acce
|
|
|
101
101
|
}
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
`mailbox` is contract metadata, not transport configuration. It should name semantic message types, not
|
|
104
|
+
`mailbox` is contract metadata, not transport configuration. It should name semantic message types, not transport commands, file paths, or CLI fragments.
|
|
105
105
|
|
|
106
106
|
## Actor Message Delivery
|
|
107
107
|
|
package/lib/prompts.ts
CHANGED
|
@@ -38,7 +38,7 @@ export const ONBOARDING_SYSTEM_PROMPT = `pi-actors quick model:
|
|
|
38
38
|
- Long async fanout = parent async recipe wrapping template(parallel: true) and imports; packaged fanout recipes bubble branch completion follow-ups by default.
|
|
39
39
|
- If asked to explore pi-actors, read README.md, docs/README.md, docs/template-recipes.md, docs/async-runs.md, and recipes/.
|
|
40
40
|
- Ambient triangles show active async commands/subagents for the launching coordinator.
|
|
41
|
-
- After async run finish, inspect status/tail/
|
|
41
|
+
- After async run finish, inspect status/tail/messages before final artifacts.`;
|
|
42
42
|
|
|
43
43
|
export const REGISTER_TOOL_PARAM_DESCRIPTIONS = {
|
|
44
44
|
name: "Tool name in snake_case (e.g., 'transcribe')",
|
package/lib/tools.ts
CHANGED
|
@@ -430,7 +430,7 @@ export function createInspectToolDefinition<TContext = unknown>(
|
|
|
430
430
|
status: stringSchema("Optional session run filter: all, running, active, terminal, done, failed, cancelled, killed, or exited."),
|
|
431
431
|
target: stringSchema("Actor address to inspect, e.g. run:<id>, coordinator, session:<id>, session:all, or tool:<name>."),
|
|
432
432
|
verbose: booleanSchema("Return full JSON instead of compact text where available."),
|
|
433
|
-
view: stringSchema("Inspection view: status, tail, events, artifacts, files, or mailbox."),
|
|
433
|
+
view: stringSchema("Inspection view: status, tail, messages, events, artifacts, files, or mailbox."),
|
|
434
434
|
},
|
|
435
435
|
["target", "view"],
|
|
436
436
|
),
|
|
@@ -522,17 +522,18 @@ export function createInspectToolDefinition<TContext = unknown>(
|
|
|
522
522
|
const text = AsyncRuns.tailRun(runId, Number(input.lines || 40));
|
|
523
523
|
return { content: [{ type: "text" as const, text: `\n${text}` }], details: {} };
|
|
524
524
|
}
|
|
525
|
+
case "messages":
|
|
525
526
|
case "events": {
|
|
526
527
|
assertRunAccessibleToContext(runId, ctx);
|
|
527
|
-
const
|
|
528
|
+
const messages = AsyncRuns.readRunEvents(runId, Number(input.lines || 40));
|
|
528
529
|
return {
|
|
529
530
|
content: [
|
|
530
531
|
{
|
|
531
532
|
type: "text" as const,
|
|
532
|
-
text: maybeJsonText(
|
|
533
|
+
text: maybeJsonText(messages, input.verbose === true, compactRunEvents(messages)),
|
|
533
534
|
},
|
|
534
535
|
],
|
|
535
|
-
details: { events },
|
|
536
|
+
details: { messages, events: messages },
|
|
536
537
|
};
|
|
537
538
|
}
|
|
538
539
|
case "artifacts":
|
|
@@ -562,7 +563,7 @@ export function createInspectToolDefinition<TContext = unknown>(
|
|
|
562
563
|
};
|
|
563
564
|
}
|
|
564
565
|
default:
|
|
565
|
-
throw new Error("inspect view must be one of: status, tail, events, artifacts, files, mailbox.");
|
|
566
|
+
throw new Error("inspect view must be one of: status, tail, messages, events, artifacts, files, mailbox.");
|
|
566
567
|
}
|
|
567
568
|
},
|
|
568
569
|
};
|
|
@@ -611,9 +612,9 @@ export function createActorMessageToolDefinition<TContext = unknown>(
|
|
|
611
612
|
let result: Record<string, unknown>;
|
|
612
613
|
if (address.kind === "run" && address.value) {
|
|
613
614
|
assertRunAccessibleToContext(address.value, ctx);
|
|
614
|
-
if (message.type === "control.stop" || message.type === "control.cancel"
|
|
615
|
+
if (message.type === "control.stop" || message.type === "control.cancel") {
|
|
615
616
|
result = AsyncRuns.cancelRun(address.value);
|
|
616
|
-
} else if (message.type === "control.kill"
|
|
617
|
+
} else if (message.type === "control.kill") {
|
|
617
618
|
result = AsyncRuns.killRun(address.value);
|
|
618
619
|
} else {
|
|
619
620
|
result = AsyncRuns.sendRunMessage(
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"args": [
|
|
10
10
|
"state_root:path",
|
|
11
|
-
"
|
|
11
|
+
"message_file:path",
|
|
12
12
|
"lines:int",
|
|
13
13
|
"stale_minutes:int",
|
|
14
14
|
"artifact_path:path",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
],
|
|
18
18
|
"defaults": {
|
|
19
19
|
"state_root": "~/.pi/agent/tmp/pi-actors/runs",
|
|
20
|
-
"
|
|
20
|
+
"message_file": "~/.pi/agent/tmp/pi-actors/runs/music/outbox.jsonl",
|
|
21
21
|
"lines": "80",
|
|
22
22
|
"stale_minutes": "60",
|
|
23
23
|
"artifact_path": "./async-run-ops.md",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"name": "snapshot",
|
|
34
34
|
"values": {
|
|
35
35
|
"state_root": "{state_root}",
|
|
36
|
-
"
|
|
36
|
+
"message_file": "{message_file}",
|
|
37
37
|
"lines": "{lines}",
|
|
38
38
|
"stale_minutes": "{stale_minutes}"
|
|
39
39
|
}
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
{
|
|
42
42
|
"name": "normalizer",
|
|
43
43
|
"values": {
|
|
44
|
-
"input": "Use async run operations snapshot JSON from stdin. State root: {state_root}.
|
|
44
|
+
"input": "Use async run operations snapshot JSON from stdin. State root: {state_root}. Message file: {message_file}.",
|
|
45
45
|
"format": "Markdown sections: Active Runs, Terminal Runs, Recent Events, Stale/Risky Runs, Recommended Controls, Follow-up Needed.",
|
|
46
46
|
"model": "{model}",
|
|
47
47
|
"thinking": "off",
|
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
"args": [
|
|
4
4
|
"repo:path",
|
|
5
5
|
"state_root:path",
|
|
6
|
-
"
|
|
6
|
+
"message_file:path",
|
|
7
7
|
"lines:int",
|
|
8
8
|
"stale_minutes:int"
|
|
9
9
|
],
|
|
10
10
|
"defaults": {
|
|
11
11
|
"repo": "~/.pi/agent/extensions/pi-actors",
|
|
12
12
|
"state_root": "~/.pi/agent/tmp/pi-actors/runs",
|
|
13
|
-
"
|
|
13
|
+
"message_file": "~/.pi/agent/tmp/pi-actors/runs/music/outbox.jsonl",
|
|
14
14
|
"lines": "80",
|
|
15
15
|
"stale_minutes": "60"
|
|
16
16
|
},
|
|
17
|
-
"template": "{repo}/scripts/recipe-utils.mjs run-ops-snapshot {state_root} {
|
|
17
|
+
"template": "{repo}/scripts/recipe-utils.mjs run-ops-snapshot {state_root} {message_file} {lines} {stale_minutes}"
|
|
18
18
|
}
|
package/scripts/recipe-utils.mjs
CHANGED
|
@@ -127,7 +127,7 @@ function tailJsonl(fileValue, linesValue = "80") {
|
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
function runOpsSnapshot(rootValue,
|
|
130
|
+
function runOpsSnapshot(rootValue, messageFileValue, linesValue = "80", staleMinutesValue = "60") {
|
|
131
131
|
const runs = collectRunSummary(rootValue);
|
|
132
132
|
const staleMs = Number(staleMinutesValue) * 60 * 1000;
|
|
133
133
|
const now = Date.now();
|
|
@@ -150,7 +150,7 @@ function runOpsSnapshot(rootValue, eventFileValue, linesValue = "80", staleMinut
|
|
|
150
150
|
}
|
|
151
151
|
return [];
|
|
152
152
|
});
|
|
153
|
-
console.log(JSON.stringify({ runs,
|
|
153
|
+
console.log(JSON.stringify({ runs, messages: tailJsonl(messageFileValue, linesValue), recommendations }, null, 2));
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
function playlist(
|