@llblab/pi-kit 0.5.2 → 0.7.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.
- package/CHANGELOG.md +8 -0
- package/README.md +5 -5
- package/node_modules/@llblab/pi-actors/AGENTS.md +1 -1
- package/node_modules/@llblab/pi-actors/CHANGELOG.md +6 -0
- package/node_modules/@llblab/pi-actors/README.md +1 -1
- package/node_modules/@llblab/pi-actors/dist/lib/async-runs.d.ts +3 -0
- package/node_modules/@llblab/pi-actors/dist/lib/async-runs.js +14 -1
- package/node_modules/@llblab/pi-actors/dist/lib/command-templates.js +45 -3
- package/node_modules/@llblab/pi-actors/dist/lib/extension-runtime.js +1 -1
- package/node_modules/@llblab/pi-actors/dist/lib/observability.d.ts +16 -3
- package/node_modules/@llblab/pi-actors/dist/lib/observability.js +92 -7
- package/node_modules/@llblab/pi-actors/dist/lib/pi.d.ts +0 -1
- package/node_modules/@llblab/pi-actors/dist/lib/pi.js +15 -24
- package/node_modules/@llblab/pi-actors/dist/lib/run-delivery-lineage.d.ts +17 -0
- package/node_modules/@llblab/pi-actors/dist/lib/run-delivery-lineage.js +44 -0
- package/node_modules/@llblab/pi-actors/dist/lib/run-delivery.d.ts +4 -0
- package/node_modules/@llblab/pi-actors/dist/lib/run-delivery.js +102 -4
- package/node_modules/@llblab/pi-actors/dist/lib/run-ui-runtime.js +58 -39
- package/node_modules/@llblab/pi-actors/dist/lib/runtime.js +14 -6
- package/node_modules/@llblab/pi-actors/dist/skills/actors/SKILL.md +1 -1
- package/node_modules/@llblab/pi-actors/docs/async-runs.md +1 -1
- package/node_modules/@llblab/pi-actors/docs/coordinator-delivery.md +18 -23
- package/node_modules/@llblab/pi-actors/lib/async-runs.ts +18 -1
- package/node_modules/@llblab/pi-actors/lib/command-templates.ts +41 -3
- package/node_modules/@llblab/pi-actors/lib/extension-runtime.ts +1 -1
- package/node_modules/@llblab/pi-actors/lib/observability.ts +119 -5
- package/node_modules/@llblab/pi-actors/lib/pi.ts +15 -28
- package/node_modules/@llblab/pi-actors/lib/run-delivery-lineage.ts +68 -0
- package/node_modules/@llblab/pi-actors/lib/run-delivery.ts +120 -4
- package/node_modules/@llblab/pi-actors/lib/run-ui-runtime.ts +69 -44
- package/node_modules/@llblab/pi-actors/lib/runtime.ts +17 -6
- package/node_modules/@llblab/pi-actors/package.json +1 -1
- package/node_modules/@llblab/pi-actors/skills/actors/SKILL.md +1 -1
- package/node_modules/@llblab/pi-grow-loop/AGENTS.md +2 -2
- package/node_modules/@llblab/pi-grow-loop/CHANGELOG.md +4 -0
- package/node_modules/@llblab/pi-grow-loop/README.md +6 -6
- package/node_modules/@llblab/pi-grow-loop/index.ts +6 -3
- package/node_modules/@llblab/pi-grow-loop/package.json +1 -1
- package/node_modules/@llblab/pi-state-flow/AGENTS.md +33 -12
- package/node_modules/@llblab/pi-state-flow/BACKLOG.md +125 -2
- package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +87 -45
- package/node_modules/@llblab/pi-state-flow/README.md +203 -107
- package/node_modules/@llblab/pi-state-flow/docs/README.md +4 -0
- package/node_modules/@llblab/pi-state-flow/docs/architecture.md +188 -0
- package/node_modules/@llblab/pi-state-flow/docs/temporal-acceptance.md +42 -0
- package/node_modules/@llblab/pi-state-flow/index.ts +164 -2
- package/node_modules/@llblab/pi-state-flow/lib/acquisition.ts +138 -0
- package/node_modules/@llblab/pi-state-flow/lib/artifact.ts +273 -0
- package/node_modules/@llblab/pi-state-flow/lib/config.ts +48 -0
- package/node_modules/@llblab/pi-state-flow/lib/context.ts +18 -5
- package/node_modules/@llblab/pi-state-flow/lib/continuation.ts +268 -0
- package/node_modules/@llblab/pi-state-flow/lib/discovery.ts +117 -0
- package/node_modules/@llblab/pi-state-flow/lib/durable.ts +562 -0
- package/node_modules/@llblab/pi-state-flow/lib/episode.ts +24 -12
- package/node_modules/@llblab/pi-state-flow/lib/extension.ts +606 -70
- package/node_modules/@llblab/pi-state-flow/lib/git.ts +666 -0
- package/node_modules/@llblab/pi-state-flow/lib/history.ts +95 -0
- package/node_modules/@llblab/pi-state-flow/lib/json.ts +24 -0
- package/node_modules/@llblab/pi-state-flow/lib/maintenance.ts +141 -0
- package/node_modules/@llblab/pi-state-flow/lib/memory.ts +52 -0
- package/node_modules/@llblab/pi-state-flow/lib/migration.ts +88 -0
- package/node_modules/@llblab/pi-state-flow/lib/publication.ts +296 -0
- package/node_modules/@llblab/pi-state-flow/lib/recovery.ts +23 -7
- package/node_modules/@llblab/pi-state-flow/lib/rehydration.ts +79 -0
- package/node_modules/@llblab/pi-state-flow/lib/runtime.ts +264 -0
- package/node_modules/@llblab/pi-state-flow/lib/session.ts +6 -0
- package/node_modules/@llblab/pi-state-flow/lib/skills.ts +99 -7
- package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +305 -48
- package/node_modules/@llblab/pi-state-flow/lib/state.ts +74 -7
- package/node_modules/@llblab/pi-state-flow/lib/status.ts +125 -6
- package/node_modules/@llblab/pi-state-flow/lib/storage.ts +196 -0
- package/node_modules/@llblab/pi-state-flow/lib/temporal.ts +233 -0
- package/node_modules/@llblab/pi-state-flow/lib/terminal.ts +70 -24
- package/node_modules/@llblab/pi-state-flow/lib/transition.ts +254 -29
- package/node_modules/@llblab/pi-state-flow/package.json +8 -2
- package/node_modules/@llblab/pi-state-flow/skills/state-flow-memory/SKILL.md +128 -0
- package/node_modules/@llblab/pi-telegram/AGENTS.md +14 -9
- package/node_modules/@llblab/pi-telegram/BACKLOG.md +20 -4
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +22 -5
- package/node_modules/@llblab/pi-telegram/README.md +13 -9
- package/node_modules/@llblab/pi-telegram/docs/README.md +1 -0
- package/node_modules/@llblab/pi-telegram/docs/architecture.md +220 -18
- package/node_modules/@llblab/pi-telegram/docs/generative-apps.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +70 -19
- package/node_modules/@llblab/pi-telegram/docs/outbound.md +13 -7
- package/node_modules/@llblab/pi-telegram/docs/public-api.md +13 -5
- package/node_modules/@llblab/pi-telegram/docs/ui-style.md +3 -1
- package/node_modules/@llblab/pi-telegram/index.ts +4 -1415
- package/node_modules/@llblab/pi-telegram/lib/activity.ts +19 -5
- package/node_modules/@llblab/pi-telegram/lib/agent-messages.ts +6 -3
- package/node_modules/@llblab/pi-telegram/lib/bindings.ts +37 -2
- package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +600 -135
- package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +962 -55
- package/node_modules/@llblab/pi-telegram/lib/bus.ts +350 -26
- package/node_modules/@llblab/pi-telegram/lib/channel-posts.ts +544 -0
- package/node_modules/@llblab/pi-telegram/lib/commands.ts +234 -11
- package/node_modules/@llblab/pi-telegram/lib/config.ts +178 -25
- package/node_modules/@llblab/pi-telegram/lib/delivery.ts +18 -18
- package/node_modules/@llblab/pi-telegram/lib/extension.ts +1792 -0
- package/node_modules/@llblab/pi-telegram/lib/generative-apps.ts +20 -2
- package/node_modules/@llblab/pi-telegram/lib/journal.ts +2184 -126
- package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +7 -1
- package/node_modules/@llblab/pi-telegram/lib/locks.ts +38 -1
- package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +154 -15
- package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +74 -40
- package/node_modules/@llblab/pi-telegram/lib/outbound-voice.ts +28 -42
- package/node_modules/@llblab/pi-telegram/lib/outbound.ts +18 -14
- package/node_modules/@llblab/pi-telegram/lib/paths.ts +29 -0
- package/node_modules/@llblab/pi-telegram/lib/polling.ts +85 -17
- package/node_modules/@llblab/pi-telegram/lib/preview.ts +115 -70
- package/node_modules/@llblab/pi-telegram/lib/prompts.ts +5 -2
- package/node_modules/@llblab/pi-telegram/lib/queue.ts +66 -22
- package/node_modules/@llblab/pi-telegram/lib/replies.ts +47 -39
- package/node_modules/@llblab/pi-telegram/lib/routing.ts +305 -112
- package/node_modules/@llblab/pi-telegram/lib/status.ts +10 -0
- package/node_modules/@llblab/pi-telegram/lib/sync.ts +308 -39
- package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +315 -7
- package/node_modules/@llblab/pi-telegram/lib/thread-cleanup-manager.ts +664 -0
- package/node_modules/@llblab/pi-telegram/lib/thread-display.ts +226 -0
- package/node_modules/@llblab/pi-telegram/lib/thread-naming.ts +118 -0
- package/node_modules/@llblab/pi-telegram/lib/threads.ts +1686 -129
- package/node_modules/@llblab/pi-telegram/lib/updates.ts +1319 -97
- package/node_modules/@llblab/pi-telegram/lib/workspace-admission.ts +1643 -0
- package/node_modules/@llblab/pi-telegram/lib/workspace-retirement.ts +968 -0
- package/node_modules/@llblab/pi-telegram/lib/workspace-slots.ts +84 -0
- package/node_modules/@llblab/pi-telegram/package.json +1 -1
- package/node_modules/@llblab/pi-telegram/screenshot.png +0 -0
- package/node_modules/@llblab/pi-telegram/scripts/measure-bus.mjs +83 -0
- package/node_modules/@llblab/pi-telegram/scripts/measure-workspace.mjs +101 -0
- package/node_modules/@llblab/{skills → pi-telegram/skills}/show-me/SKILL.md +28 -6
- package/node_modules/@llblab/pi-telegram/skills/show-me/references/telegram-surfaces.md +43 -0
- package/node_modules/@llblab/pi-telegram/skills/telegram-bridge/references/delivery-and-threads.md +1 -1
- package/node_modules/@llblab/skills/abcd-context/AGENTS.md +1 -0
- package/node_modules/@llblab/skills/abcd-context/CHANGELOG.md +6 -2
- package/node_modules/@llblab/skills/abcd-context/SKILL.md +1 -1
- package/node_modules/@llblab/skills/abcd-context/docs/validation-design.md +11 -5
- package/node_modules/@llblab/skills/abcd-context/scripts/_self-test.mjs +61 -0
- package/node_modules/@llblab/skills/abcd-context/scripts/validate-context.mjs +67 -0
- package/node_modules/@llblab/skills/package.json +2 -3
- package/node_modules/@llblab/skills/release-flow/SKILL.md +2 -4
- package/package.json +7 -6
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@llblab/pi-kit` are documented here.
|
|
4
4
|
|
|
5
|
+
## 0.7.0 - 2026-09-10
|
|
6
|
+
|
|
7
|
+
- `Current Distribution`: Advances Actors to `0.53.0`, State Flow to `0.6.0`, Telegram to `0.45.0`, and Skills to `1.15.0`. The kit now includes durable Workspace-bound Telegram Threads, expanded run orchestration, current opt-in state handoffs, and the latest portable workflows while preserving the package set, resource inventory, and explicit load order.
|
|
8
|
+
|
|
9
|
+
## 0.6.0 - 2026-09-06
|
|
10
|
+
|
|
11
|
+
- `Current Distribution`: Advances Telegram to `0.44.0`, Grow Loop to `0.7.5`, and Skills to `1.14.1`. The kit now includes reliable default-on Telegram draft previews and prompt anchors, unambiguous `grow-loop` runtime status, and ABCd contiguous-list validation while preserving the existing package set, resource inventory, and load order.
|
|
12
|
+
|
|
5
13
|
## 0.5.2 - 2026-09-06
|
|
6
14
|
|
|
7
15
|
- `Telegram Ordering Hotfix`: Advances the exact Telegram pin to `0.43.2`, bringing bounded threadless command lifetime, causal final/artifact/compaction publication order, stale-delivery fencing, and suppression of voice replay after uncertain acknowledgement. Other pins and the resource inventory remain unchanged; operator-coordinated live smoke follows release.
|
package/README.md
CHANGED
|
@@ -10,13 +10,13 @@ Package links lead to the owning repositories for usage, documentation, issues,
|
|
|
10
10
|
|
|
11
11
|
| Package | Version | Purpose |
|
|
12
12
|
| --- | ---: | --- |
|
|
13
|
-
| [`@llblab/pi-actors`](https://github.com/llblab/pi-actors) | `0.
|
|
13
|
+
| [`@llblab/pi-actors`](https://github.com/llblab/pi-actors) | `0.53.0` | Inspectable local Runs, reusable Recipes, persistent tools, and delegation Skills |
|
|
14
14
|
| [`@llblab/pi-clean-room`](https://github.com/llblab/pi-clean-room) | `0.1.1` | Isolated nested Pi TUI with explicitly selected extensions |
|
|
15
15
|
| [`@llblab/pi-codex-usage`](https://github.com/llblab/pi-codex-usage) | `0.9.4` | Compact Codex/Spark subscription-limit status |
|
|
16
|
-
| [`@llblab/pi-grow-loop`](https://github.com/llblab/pi-grow-loop) | `0.7.
|
|
17
|
-
| [`@llblab/pi-state-flow`](https://github.com/llblab/pi-state-flow) | `0.
|
|
18
|
-
| [`@llblab/pi-telegram`](https://github.com/llblab/pi-telegram) | `0.
|
|
19
|
-
| [`@llblab/skills`](https://github.com/llblab/skills) | `1.
|
|
16
|
+
| [`@llblab/pi-grow-loop`](https://github.com/llblab/pi-grow-loop) | `0.7.5` | Visible continuation scheduling and bounded worker Skills |
|
|
17
|
+
| [`@llblab/pi-state-flow`](https://github.com/llblab/pi-state-flow) | `0.6.0` | Opt-in validated state handoffs between agent runs |
|
|
18
|
+
| [`@llblab/pi-telegram`](https://github.com/llblab/pi-telegram) | `0.45.0` | Telegram companion, queues, files, voice, controls, and Generative Apps guidance |
|
|
19
|
+
| [`@llblab/skills`](https://github.com/llblab/skills) | `1.15.0` | Portable workflows for engineering, review, design, context maintenance, and other focused tasks |
|
|
20
20
|
|
|
21
21
|
Versions are exact by design. An upstream release does not change an installed kit until this repository explicitly advances the dependency and publishes a new kit version. Runtime defects and package-specific feature requests belong in the linked repository; package selection and kit installation issues belong here.
|
|
22
22
|
|
|
@@ -136,7 +136,7 @@ Tool result/error text contributes exactly one leading line break. Keep model-fa
|
|
|
136
136
|
|
|
137
137
|
File watchers accelerate reconciliation; a bounded interval recovers missed terminal and retained-attention events. Canonical attention observation uses stable retained ids and bounds seen memory to the current suffix across compaction; only allowlisted legacy outbox fallback uses line offsets. Ordinary `notify` and `followup` hints prime at startup without replay and require durable state or artifacts for recovery. Explicit `steer` instead re-enters through the owner journal until exact presentation records its newer generation-fenced Trace marker.
|
|
138
138
|
|
|
139
|
-
Ordinary
|
|
139
|
+
Ordinary terminals retain inherited delivery lineage from each nested Actor process to the top-level coordinator. Only that root coordinator may schedule completion follow-ups; descendant sessions stay quiet, descendants wait for their containing top-level Run to terminate, and the complete ready forest is flattened into one immutable settled/idle batch with parent-child rows and bounded semantic outputs. The same batch renders as one visible operator card and one model prompt. Batch delivery is generation-fenced and bounded at 256 durable members, 64 model-facing rows, 16 KiB of context, and a 1 MiB journal. Successful `sendMessage()` acceptance durably finalizes the completion batch and authorizes exact-generation handled markers, so a missed context callback cannot block later completion epochs. Send failure retains the pending batch for retry; queued recovery remains only for the narrow crash boundary between transport acceptance and finalization. Restart recovery walks the bounded active Pi session parent chain: exact queued evidence waits without resend, proven absence returns the envelope to pending, and incomplete or conflicting evidence remains queued with diagnostics. Retry duplicates collapse before presentation, malformed envelopes fail closed, and automatic review waits behind an active completion batch.
|
|
140
140
|
|
|
141
141
|
When deferred Run results gate the next step, wait for their completion batch. Inspect early only for operator request, meaningful attention, or diagnosis of an overdue Run.
|
|
142
142
|
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
> Each release keeps at most 8 outcome records of at most 512 characters.
|
|
4
4
|
|
|
5
|
+
## 0.53.0: Tree-Compressed Completion Delivery
|
|
6
|
+
|
|
7
|
+
- `Quiet Draft Reloads`: Keeps automatic Recipe reload active for draft-directory changes while showing “Recipe tools refreshed” only for active non-draft Recipe changes or registry-root replacement, so ordinary spawn draft capture no longer produces misleading tool-refresh noise.
|
|
8
|
+
- `Tree-Compressed Completion Delivery`: Propagates exact root-owner and parent-generation lineage through nested Actor processes. Descendants stay quiet and wait for the complete top-level tree; the root batches ready trees and concurrent roots into one visible gray card plus one parent-child model prompt with bounded outputs. Completion forests render in stable root/descendant preorder. Successful Pi acceptance finalizes completion members immediately, preventing missed callbacks or long branches from blocking later epochs; settled/context delivery accepts fresh Pi context wrappers only for the exact active session owner, while urgent steer retains exact presentation acknowledgment.
|
|
9
|
+
- `Command Timeout Trees`: Terminates the full command-template descendant tree on timeout, preventing inherited output streams from leaving an Actor stuck after its command deadline while preserving outer Run process-group cancellation.
|
|
10
|
+
|
|
5
11
|
## 0.52.1: Unified Playback Control Hotfix
|
|
6
12
|
|
|
7
13
|
- `Unified Playback CLI`: Consolidates standalone playback and external control into `playback.mjs`; standalone commands remain runtime-independent, while Actor-owned commands retain exact terminal Control evidence. The maintained Music Player Generative App uses the same explicit control entrypoint. Post-stop status remains readable despite leftover Run metadata; inactive controls fail before journal admission. External callers of the removed `playback-client.mjs` use `playback.mjs control` instead.
|
|
@@ -153,7 +153,7 @@ Trace fields are exact: `id`, `ts`, `kind`, and optional `summary`, `data`, `lev
|
|
|
153
153
|
|
|
154
154
|
Generic command lifecycle is Trace-only: runner-owned `command.done` records preserve completion and execution evidence but never request or project attention, including malformed legacy records carrying `steer`. There is no Recipe-level command-completion delivery switch. Semantic attention is explicit: `notify` shows visible status without a model turn, `followup` supplies ordinary checkpoint context, and `steer` requests urgent delivery at Pi's next safe assistant/tool boundary. `notify` and `followup` remain retained wake hints that may compact away, so persist recovery state or an artifact first. `steer` is admitted to the bounded owner delivery journal before `deliverAs: "steer"`, acknowledged only in exact model-bound context, and never suppresses the eventual root-terminal batch. Store large evidence in artifacts or bounded execution captures.
|
|
155
155
|
|
|
156
|
-
Ordinary finite Runs project
|
|
156
|
+
Ordinary finite Runs project terminal results through one root-coordinator completion scheduler. Nested actors inherit durable parent-generation lineage: their own Pi sessions never emit completion turns, their results wait until the containing top-level Run terminates, and the ready trees join other top-level completions accumulated during the same active/idle epoch. One immutable bounded forest causes one automatic agent turn after the root Pi settles. The operator sees one gray completion card, while the agent receives the same parent-child tree with bounded actor outputs as one prompt; terminal generations are acknowledged after Pi durably accepts the exact batch, preventing one missed context callback from blocking later completion epochs. Sequence, parallel, repeat, and imported branches remain internal, while separately launched Runs retain exact independent generations. Silent Runs and synchronous stop acknowledgments remain non-projecting.
|
|
157
157
|
|
|
158
158
|
## Control
|
|
159
159
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { CommandTemplateFailureScope, CommandTemplateValue } from "./command-templates.ts";
|
|
6
6
|
import { type CurrentPolicyProvenance } from "./model-context.ts";
|
|
7
|
+
import * as RunDeliveryLineage from "./run-delivery-lineage.ts";
|
|
7
8
|
import * as RecipesReferences from "./recipes-references.ts";
|
|
8
9
|
import { type RunArtifactDeclaration } from "./runs-artifacts.ts";
|
|
9
10
|
import { type RunProcessIdentity } from "./runs-process.ts";
|
|
@@ -92,6 +93,8 @@ export interface AsyncRunMeta {
|
|
|
92
93
|
artifacts?: Record<string, RunArtifactDeclaration>;
|
|
93
94
|
control?: string[];
|
|
94
95
|
control_endpoint?: AsyncRunControlEndpoint;
|
|
96
|
+
delivery_owner_id?: string;
|
|
97
|
+
delivery_parent?: RunDeliveryLineage.RunDeliveryParent;
|
|
95
98
|
model_policy?: CurrentPolicyProvenance;
|
|
96
99
|
notification_policy?: "normal" | "silent";
|
|
97
100
|
process_identity?: RunProcessIdentity;
|
|
@@ -11,6 +11,7 @@ import { isDeepStrictEqual } from "node:util";
|
|
|
11
11
|
import { writeJsonAtomic } from "./file-state.js";
|
|
12
12
|
import { CURRENT_MODEL_VALUE_KEY, CURRENT_THINKING_VALUE_KEY, describeCurrentPolicyProvenance, } from "./model-context.js";
|
|
13
13
|
import * as Paths from "./paths.js";
|
|
14
|
+
import * as RunDeliveryLineage from "./run-delivery-lineage.js";
|
|
14
15
|
import * as RecipesReferences from "./recipes-references.js";
|
|
15
16
|
import * as RecipesUsage from "./recipes-usage.js";
|
|
16
17
|
import * as Schema from "./schema.js";
|
|
@@ -369,6 +370,8 @@ export function startRun(params, cwd, options = {}) {
|
|
|
369
370
|
};
|
|
370
371
|
const transportContext = normalizeRunTransportContext(startParams.transport_context);
|
|
371
372
|
const artifacts = resolveArtifactPaths(startParams.artifacts, outputValues);
|
|
373
|
+
const runInstanceId = randomUUID();
|
|
374
|
+
const deliveryLineage = RunDeliveryLineage.inheritedRunDeliveryLineage(startParams.ownerId);
|
|
372
375
|
const meta = {
|
|
373
376
|
argv: [process.execPath, ...argv],
|
|
374
377
|
createdAt: new Date().toISOString(),
|
|
@@ -386,7 +389,7 @@ export function startRun(params, cwd, options = {}) {
|
|
|
386
389
|
...(recipe ? { recipe } : {}),
|
|
387
390
|
...(recipeFile ? { recipe_file: recipeFile } : {}),
|
|
388
391
|
run,
|
|
389
|
-
run_instance_id:
|
|
392
|
+
run_instance_id: runInstanceId,
|
|
390
393
|
state_dir: stateDir,
|
|
391
394
|
state_schema: RuntimeIdentity.RUN_STATE_SCHEMA,
|
|
392
395
|
status: "running",
|
|
@@ -399,6 +402,7 @@ export function startRun(params, cwd, options = {}) {
|
|
|
399
402
|
...(startParams.control_endpoint
|
|
400
403
|
? { control_endpoint: startParams.control_endpoint }
|
|
401
404
|
: {}),
|
|
405
|
+
...(deliveryLineage ?? {}),
|
|
402
406
|
...(startParams.notification_policy === "silent"
|
|
403
407
|
? { notification_policy: "silent" }
|
|
404
408
|
: {}),
|
|
@@ -429,6 +433,15 @@ export function startRun(params, cwd, options = {}) {
|
|
|
429
433
|
const child = spawn(process.execPath, argv, {
|
|
430
434
|
cwd,
|
|
431
435
|
detached: true,
|
|
436
|
+
...(deliveryLineage
|
|
437
|
+
? {
|
|
438
|
+
env: RunDeliveryLineage.runDeliveryChildEnv(deliveryLineage, {
|
|
439
|
+
run,
|
|
440
|
+
run_instance_id: runInstanceId,
|
|
441
|
+
state_dir: stateDir,
|
|
442
|
+
}),
|
|
443
|
+
}
|
|
444
|
+
: {}),
|
|
432
445
|
stdio: ["ignore", outFd, errFd],
|
|
433
446
|
});
|
|
434
447
|
closeSync(outFd);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Zones: shell-free command parsing, placeholder expansion, local process execution, composition semantics
|
|
4
4
|
* Owns portable command-template parsing, expansion, risk checks, retries, timeouts, and direct execution.
|
|
5
5
|
*/
|
|
6
|
-
import { spawn } from "node:child_process";
|
|
6
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
7
7
|
import { accessSync, appendFileSync, constants, mkdirSync, mkdtempSync, statSync, writeFileSync } from "node:fs";
|
|
8
8
|
import { homedir, tmpdir } from "node:os";
|
|
9
9
|
import { basename, delimiter, extname, isAbsolute, join, resolve as resolvePath } from "node:path";
|
|
@@ -714,14 +714,56 @@ function execCommandTemplateOnce(command, args, options = {}) {
|
|
|
714
714
|
let settled = false;
|
|
715
715
|
let timeoutId;
|
|
716
716
|
let killTimeoutId;
|
|
717
|
+
const signalProcessTree = (signal) => {
|
|
718
|
+
if (proc.pid === undefined)
|
|
719
|
+
return;
|
|
720
|
+
if (process.platform === "win32") {
|
|
721
|
+
spawnSync("taskkill", [
|
|
722
|
+
"/PID",
|
|
723
|
+
String(proc.pid),
|
|
724
|
+
"/T",
|
|
725
|
+
...(signal === "SIGKILL" ? ["/F"] : []),
|
|
726
|
+
]);
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
const snapshot = spawnSync("ps", ["-eo", "pid=,ppid="], { encoding: "utf8" });
|
|
730
|
+
const children = new Map();
|
|
731
|
+
for (const line of snapshot.stdout?.split(/\r?\n/u) ?? []) {
|
|
732
|
+
const [pidText, parentText] = line.trim().split(/\s+/u);
|
|
733
|
+
const pid = Number(pidText);
|
|
734
|
+
const parent = Number(parentText);
|
|
735
|
+
if (!Number.isSafeInteger(pid) || !Number.isSafeInteger(parent))
|
|
736
|
+
continue;
|
|
737
|
+
const siblings = children.get(parent) ?? [];
|
|
738
|
+
siblings.push(pid);
|
|
739
|
+
children.set(parent, siblings);
|
|
740
|
+
}
|
|
741
|
+
const descendants = [];
|
|
742
|
+
const collect = (parent) => {
|
|
743
|
+
for (const child of children.get(parent) ?? []) {
|
|
744
|
+
collect(child);
|
|
745
|
+
descendants.push(child);
|
|
746
|
+
}
|
|
747
|
+
};
|
|
748
|
+
collect(proc.pid);
|
|
749
|
+
for (const pid of [...descendants, proc.pid]) {
|
|
750
|
+
try {
|
|
751
|
+
process.kill(pid, signal);
|
|
752
|
+
}
|
|
753
|
+
catch (error) {
|
|
754
|
+
if (error.code !== "ESRCH")
|
|
755
|
+
throw error;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
};
|
|
717
759
|
const killProcess = () => {
|
|
718
760
|
if (killed)
|
|
719
761
|
return;
|
|
720
762
|
killed = true;
|
|
721
|
-
|
|
763
|
+
signalProcessTree("SIGTERM");
|
|
722
764
|
killTimeoutId = setTimeout(() => {
|
|
723
765
|
if (!settled)
|
|
724
|
-
|
|
766
|
+
signalProcessTree("SIGKILL");
|
|
725
767
|
}, options.killGrace ?? 5000);
|
|
726
768
|
};
|
|
727
769
|
const settle = (code) => {
|
|
@@ -113,7 +113,7 @@ export function createActorExtensionRuntime(pi) {
|
|
|
113
113
|
},
|
|
114
114
|
getRunOwnerId,
|
|
115
115
|
onAgentSettled(ctx) {
|
|
116
|
-
if (
|
|
116
|
+
if (!activeRunOwnerId || getRunOwnerId(ctx) !== activeRunOwnerId)
|
|
117
117
|
return;
|
|
118
118
|
if (!runUiRuntime.flushCompletionBatch(ctx))
|
|
119
119
|
automaticReview.schedule();
|
|
@@ -13,6 +13,12 @@ export interface RunObservation {
|
|
|
13
13
|
activeSubagents?: number;
|
|
14
14
|
completed?: number;
|
|
15
15
|
descendantSubagents?: number;
|
|
16
|
+
deliveryOwnerId?: string;
|
|
17
|
+
deliveryParent?: {
|
|
18
|
+
run: string;
|
|
19
|
+
run_instance_id: string;
|
|
20
|
+
state_dir: string;
|
|
21
|
+
};
|
|
16
22
|
failures?: number;
|
|
17
23
|
ownerId?: string;
|
|
18
24
|
artifacts?: Record<string, string>;
|
|
@@ -69,6 +75,8 @@ export declare function readRunUiSnapshot(state: RunUiObservationState, ownerId:
|
|
|
69
75
|
includeAttention?: boolean;
|
|
70
76
|
stateRoot?: string;
|
|
71
77
|
}): RunUiSnapshot;
|
|
78
|
+
/** Observe every Run generation routed to one root coordinator. */
|
|
79
|
+
export declare function readRunDeliverySnapshot(state: RunUiObservationState, deliveryOwnerId: string, stateRoot?: string): RunUiSnapshot;
|
|
72
80
|
export declare function pruneRunUiObservationState(state: RunUiObservationState, snapshot: Pick<RunUiSnapshot, "summary" | "transitions">): void;
|
|
73
81
|
export declare function deliverRunAttentionNotifications(events: RunAttentionEvent[], sink: RunUiNotificationSink): void;
|
|
74
82
|
export interface RunRetirementCandidate {
|
|
@@ -124,6 +132,11 @@ export interface RunRetirementExecutorOptions {
|
|
|
124
132
|
sendStop: (candidate: RunRetirementCandidate) => Promise<unknown>;
|
|
125
133
|
}
|
|
126
134
|
export interface RunTransition {
|
|
135
|
+
deliveryParent?: {
|
|
136
|
+
run: string;
|
|
137
|
+
run_instance_id: string;
|
|
138
|
+
state_dir: string;
|
|
139
|
+
};
|
|
127
140
|
from: RunObservedStatus;
|
|
128
141
|
run: string;
|
|
129
142
|
runInstanceId?: string;
|
|
@@ -162,7 +175,7 @@ export interface RunAttentionEvent {
|
|
|
162
175
|
ts: string;
|
|
163
176
|
}
|
|
164
177
|
export type RunTransitionNotificationType = "info" | "warning" | "error";
|
|
165
|
-
export declare function summarizeRuns(stateRoot?: string, ownerId?: string): RunSummary;
|
|
178
|
+
export declare function summarizeRuns(stateRoot?: string, ownerId?: string, deliveryOwnerId?: string): RunSummary;
|
|
166
179
|
export declare function countRunningSubagentsByRun(stateRoot?: string, ownerId?: string): Map<string, number>;
|
|
167
180
|
export declare function countRunningSubagents(stateRoot?: string, ownerId?: string): number;
|
|
168
181
|
export declare function renderSubagentStatus(count: number, frame?: number): string | undefined;
|
|
@@ -180,6 +193,6 @@ export declare function shouldSendRunAttentionFollowUp(event: RunAttentionEvent)
|
|
|
180
193
|
export declare function formatRunAttentionMessage(event: RunAttentionEvent): string;
|
|
181
194
|
export declare function getRunTransitionNotificationType(transition: RunTransition): RunTransitionNotificationType;
|
|
182
195
|
export declare function shouldNotifyRunTransition(transition: RunTransition): boolean;
|
|
183
|
-
/** Build exact immutable
|
|
184
|
-
export declare function collectRunCompletionBatchMembers(transitions: RunTransition[]): RunCompletionBatchMember[];
|
|
196
|
+
/** Build exact immutable members only after each containing root Run is terminal. */
|
|
197
|
+
export declare function collectRunCompletionBatchMembers(transitions: RunTransition[], deliveryRuns?: RunObservation[]): RunCompletionBatchMember[];
|
|
185
198
|
export declare function formatRunTransitionMessage(transition: RunTransition): string;
|
|
@@ -32,6 +32,16 @@ export function readRunUiSnapshot(state, ownerId, options = {}) {
|
|
|
32
32
|
transitions: detectRunTransitions(state.observed, summary),
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
|
+
/** Observe every Run generation routed to one root coordinator. */
|
|
36
|
+
export function readRunDeliverySnapshot(state, deliveryOwnerId, stateRoot) {
|
|
37
|
+
const summary = summarizeRuns(stateRoot, undefined, deliveryOwnerId);
|
|
38
|
+
return {
|
|
39
|
+
attentionEvents: [],
|
|
40
|
+
status: undefined,
|
|
41
|
+
summary,
|
|
42
|
+
transitions: detectRunTransitions(state.observed, summary),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
35
45
|
export function pruneRunUiObservationState(state, snapshot) {
|
|
36
46
|
pruneRunObservationState(state.observed, state.legacyEventLines, snapshot.summary, snapshot.transitions.map((transition) => transition.stateDir ?? transition.run), state.attentionEventIds);
|
|
37
47
|
}
|
|
@@ -348,6 +358,19 @@ function observeRun(stateDir) {
|
|
|
348
358
|
failures: Array.isArray(progress.failures)
|
|
349
359
|
? progress.failures.length
|
|
350
360
|
: undefined,
|
|
361
|
+
...(typeof status.delivery_owner_id === "string"
|
|
362
|
+
? { deliveryOwnerId: status.delivery_owner_id }
|
|
363
|
+
: {}),
|
|
364
|
+
...(status.delivery_parent &&
|
|
365
|
+
typeof status.delivery_parent === "object" &&
|
|
366
|
+
!Array.isArray(status.delivery_parent) &&
|
|
367
|
+
typeof status.delivery_parent.run === "string" &&
|
|
368
|
+
typeof status.delivery_parent.run_instance_id === "string" &&
|
|
369
|
+
typeof status.delivery_parent.state_dir === "string"
|
|
370
|
+
? {
|
|
371
|
+
deliveryParent: status.delivery_parent,
|
|
372
|
+
}
|
|
373
|
+
: {}),
|
|
351
374
|
...(typeof status.ownerId === "string"
|
|
352
375
|
? { ownerId: status.ownerId }
|
|
353
376
|
: {}),
|
|
@@ -391,7 +414,7 @@ function observeRun(stateDir) {
|
|
|
391
414
|
return undefined;
|
|
392
415
|
}
|
|
393
416
|
}
|
|
394
|
-
export function summarizeRuns(stateRoot = Paths.getRunStateRoot(), ownerId) {
|
|
417
|
+
export function summarizeRuns(stateRoot = Paths.getRunStateRoot(), ownerId, deliveryOwnerId) {
|
|
395
418
|
if (!existsSync(stateRoot)) {
|
|
396
419
|
return {
|
|
397
420
|
cancelled: 0,
|
|
@@ -409,7 +432,10 @@ export function summarizeRuns(stateRoot = Paths.getRunStateRoot(), ownerId) {
|
|
|
409
432
|
scanRunStateDirs(stateRoot))
|
|
410
433
|
.map((stateDir) => observeRun(stateDir))
|
|
411
434
|
.filter((run) => Boolean(run))
|
|
412
|
-
.filter((run) =>
|
|
435
|
+
.filter((run) => deliveryOwnerId !== undefined
|
|
436
|
+
? run.deliveryOwnerId === deliveryOwnerId ||
|
|
437
|
+
(run.deliveryOwnerId === undefined && run.ownerId === deliveryOwnerId)
|
|
438
|
+
: ownerId === undefined || run.ownerId === ownerId)
|
|
413
439
|
.sort((a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? ""));
|
|
414
440
|
const processSubagentsByRun = countRunningSubagentsByRun(stateRoot, ownerId);
|
|
415
441
|
const runsWithDescendants = runs.map((run) => {
|
|
@@ -683,6 +709,7 @@ export function detectRunTransitions(previous, summary) {
|
|
|
683
709
|
transitions.push({
|
|
684
710
|
from: old ?? "running",
|
|
685
711
|
run: run.run,
|
|
712
|
+
...(run.deliveryParent ? { deliveryParent: run.deliveryParent } : {}),
|
|
686
713
|
...(run.stateDir ? { stateDir: run.stateDir } : {}),
|
|
687
714
|
...(run.artifacts ? { artifacts: run.artifacts } : {}),
|
|
688
715
|
...(run.launchCorrelation ? { launchCorrelation: run.launchCorrelation } : {}),
|
|
@@ -921,15 +948,56 @@ export function shouldNotifyRunTransition(transition) {
|
|
|
921
948
|
transition.to === "killed" ||
|
|
922
949
|
transition.to === "exited");
|
|
923
950
|
}
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
951
|
+
function deliveryGenerationIdentity(input) {
|
|
952
|
+
return input.stateDir && input.runInstanceId
|
|
953
|
+
? `${input.stateDir}\0${input.runInstanceId}`
|
|
954
|
+
: undefined;
|
|
955
|
+
}
|
|
956
|
+
function deliveryTreePosition(input, runsByIdentity) {
|
|
957
|
+
const ownIdentity = deliveryGenerationIdentity(input);
|
|
958
|
+
if (!ownIdentity)
|
|
959
|
+
return undefined;
|
|
960
|
+
let parent = input.deliveryParent;
|
|
961
|
+
let depth = 0;
|
|
962
|
+
let rootIdentity = ownIdentity;
|
|
963
|
+
const visited = new Set([ownIdentity]);
|
|
964
|
+
while (parent) {
|
|
965
|
+
const identity = `${parent.state_dir}\0${parent.run_instance_id}`;
|
|
966
|
+
if (visited.has(identity))
|
|
967
|
+
return undefined;
|
|
968
|
+
visited.add(identity);
|
|
969
|
+
const ancestor = runsByIdentity.get(identity);
|
|
970
|
+
if (!ancestor || ancestor.notificationPolicy === "silent")
|
|
971
|
+
return undefined;
|
|
972
|
+
depth += 1;
|
|
973
|
+
rootIdentity = identity;
|
|
974
|
+
parent = ancestor.deliveryParent;
|
|
975
|
+
}
|
|
976
|
+
return { depth, rootIdentity };
|
|
977
|
+
}
|
|
978
|
+
/** Build exact immutable members only after each containing root Run is terminal. */
|
|
979
|
+
export function collectRunCompletionBatchMembers(transitions, deliveryRuns = []) {
|
|
980
|
+
const runsByIdentity = new Map(deliveryRuns.flatMap((run) => {
|
|
981
|
+
const identity = deliveryGenerationIdentity(run);
|
|
982
|
+
return identity ? [[identity, run]] : [];
|
|
983
|
+
}));
|
|
984
|
+
const incompleteRoots = new Set(deliveryRuns.flatMap((run) => {
|
|
985
|
+
if (TERMINAL.has(run.status))
|
|
986
|
+
return [];
|
|
987
|
+
const position = deliveryTreePosition(run, runsByIdentity);
|
|
988
|
+
return position ? [position.rootIdentity] : [];
|
|
989
|
+
}));
|
|
990
|
+
const admitted = transitions.flatMap((transition) => {
|
|
927
991
|
if (!shouldNotifyRunTransition(transition) ||
|
|
928
992
|
!transition.stateDir ||
|
|
929
993
|
!transition.runInstanceId ||
|
|
930
994
|
!transition.terminalAt ||
|
|
931
995
|
Number.isNaN(Date.parse(transition.terminalAt)))
|
|
932
996
|
return [];
|
|
997
|
+
const position = deliveryTreePosition(transition, runsByIdentity);
|
|
998
|
+
if (!position || incompleteRoots.has(position.rootIdentity))
|
|
999
|
+
return [];
|
|
1000
|
+
const { depth } = position;
|
|
933
1001
|
const artifactEntries = Object.entries(transition.artifacts ?? {})
|
|
934
1002
|
.filter((entry) => typeof entry[1] === "string" && Boolean(entry[1]))
|
|
935
1003
|
.slice(0, 4);
|
|
@@ -939,6 +1007,20 @@ export function collectRunCompletionBatchMembers(transitions) {
|
|
|
939
1007
|
...(artifactEntries.length > 0
|
|
940
1008
|
? { artifacts: Object.fromEntries(artifactEntries) }
|
|
941
1009
|
: {}),
|
|
1010
|
+
...(transition.semanticResult?.body?.trim()
|
|
1011
|
+
? {
|
|
1012
|
+
output: transition.semanticResult.body.trim().length > 4_000
|
|
1013
|
+
? `${transition.semanticResult.body.trim().slice(0, 3_999)}…`
|
|
1014
|
+
: transition.semanticResult.body.trim(),
|
|
1015
|
+
}
|
|
1016
|
+
: {}),
|
|
1017
|
+
...(transition.deliveryParent
|
|
1018
|
+
? {
|
|
1019
|
+
parent_run: transition.deliveryParent.run,
|
|
1020
|
+
parent_run_instance_id: transition.deliveryParent.run_instance_id,
|
|
1021
|
+
parent_state_dir: transition.deliveryParent.state_dir,
|
|
1022
|
+
}
|
|
1023
|
+
: {}),
|
|
942
1024
|
run: transition.run,
|
|
943
1025
|
run_instance_id: transition.runInstanceId,
|
|
944
1026
|
state_dir: transition.stateDir,
|
|
@@ -947,11 +1029,14 @@ export function collectRunCompletionBatchMembers(transitions) {
|
|
|
947
1029
|
? `${rawSummary.slice(0, 999)}…`
|
|
948
1030
|
: rawSummary,
|
|
949
1031
|
terminal_at: transition.terminalAt,
|
|
1032
|
+
tree_depth: depth,
|
|
950
1033
|
}];
|
|
951
|
-
})
|
|
1034
|
+
});
|
|
1035
|
+
return admitted.sort((left, right) => left.tree_depth - right.tree_depth ||
|
|
1036
|
+
left.terminal_at.localeCompare(right.terminal_at) ||
|
|
952
1037
|
left.run.localeCompare(right.run) ||
|
|
953
1038
|
left.run_instance_id.localeCompare(right.run_instance_id) ||
|
|
954
|
-
left.state_dir.localeCompare(right.state_dir));
|
|
1039
|
+
left.state_dir.localeCompare(right.state_dir)).map(({ tree_depth: _depth, ...member }) => member);
|
|
955
1040
|
}
|
|
956
1041
|
const TERMINAL_FOLLOW_UP_ARTIFACT_LIMIT = 4;
|
|
957
1042
|
const TERMINAL_FOLLOW_UP_IDENTIFIER_CHARS = 120;
|
|
@@ -46,5 +46,4 @@ export declare function inspectRunSteerSessionEvidence(ctx: ExtensionContext, in
|
|
|
46
46
|
eventId: string;
|
|
47
47
|
steerId: string;
|
|
48
48
|
}): SessionEvidence.ActiveSessionEntryEvidence;
|
|
49
|
-
export declare function inspectRunCompletionBatchSessionEvidence(ctx: ExtensionContext, batchId: string, content: string): SessionEvidence.ActiveSessionEntryEvidence;
|
|
50
49
|
export declare function registerToolDefinitions(pi: ExtensionAPI, definitions: Iterable<unknown>): void;
|
|
@@ -22,7 +22,7 @@ export function sendRunCompletionBatch(pi, batchId, content) {
|
|
|
22
22
|
pi.sendMessage({
|
|
23
23
|
customType: RUN_COMPLETION_BATCH_CUSTOM_TYPE,
|
|
24
24
|
content,
|
|
25
|
-
display:
|
|
25
|
+
display: true,
|
|
26
26
|
details: {
|
|
27
27
|
pi_actors_delivery: {
|
|
28
28
|
batch_id: batchId,
|
|
@@ -59,18 +59,21 @@ function completionBatchMessage(message) {
|
|
|
59
59
|
typeof record.content !== "string")
|
|
60
60
|
return undefined;
|
|
61
61
|
const details = record.details;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
typeof envelope.batch_id
|
|
70
|
-
|
|
71
|
-
|
|
62
|
+
const delivery = details && typeof details === "object" && !Array.isArray(details)
|
|
63
|
+
? details.pi_actors_delivery
|
|
64
|
+
: undefined;
|
|
65
|
+
const envelope = delivery && typeof delivery === "object" && !Array.isArray(delivery)
|
|
66
|
+
? delivery
|
|
67
|
+
: undefined;
|
|
68
|
+
const detailedId = envelope?.kind === "completion_batch" &&
|
|
69
|
+
typeof envelope.batch_id === "string"
|
|
70
|
+
? envelope.batch_id
|
|
71
|
+
: undefined;
|
|
72
|
+
const contentId = /^Batch: `([^`]{1,128})`$/mu.exec(record.content)?.[1];
|
|
73
|
+
const batchId = detailedId ?? contentId;
|
|
74
|
+
if (!batchId || batchId.length > 128)
|
|
72
75
|
return undefined;
|
|
73
|
-
return { batchId
|
|
76
|
+
return { batchId, content: record.content };
|
|
74
77
|
}
|
|
75
78
|
/** Collapse exact retry duplicates and remove conflicting delivery envelopes. */
|
|
76
79
|
export function dedupeRunCompletionBatchContext(messages) {
|
|
@@ -183,18 +186,6 @@ export function inspectRunSteerSessionEvidence(ctx, input) {
|
|
|
183
186
|
},
|
|
184
187
|
});
|
|
185
188
|
}
|
|
186
|
-
export function inspectRunCompletionBatchSessionEvidence(ctx, batchId, content) {
|
|
187
|
-
return SessionEvidence.inspectBoundedActiveSessionEntries({
|
|
188
|
-
getEntry: (id) => ctx.sessionManager.getEntry(id),
|
|
189
|
-
leaf: ctx.sessionManager.getLeafEntry(),
|
|
190
|
-
match: (entry) => {
|
|
191
|
-
const batch = completionBatchMessage(entry);
|
|
192
|
-
if (!batch || batch.batchId !== batchId)
|
|
193
|
-
return undefined;
|
|
194
|
-
return batch.content === content ? "present" : "conflict";
|
|
195
|
-
},
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
189
|
export function registerToolDefinitions(pi, definitions) {
|
|
199
190
|
for (const definition of definitions)
|
|
200
191
|
pi.registerTool(definition);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run delivery lineage.
|
|
3
|
+
* Zones: inherited coordinator root, parent Run generation, delivery-tree filtering
|
|
4
|
+
* Owns durable completion ancestry; excludes delivery persistence and Pi scheduling.
|
|
5
|
+
*/
|
|
6
|
+
export interface RunDeliveryParent {
|
|
7
|
+
run: string;
|
|
8
|
+
run_instance_id: string;
|
|
9
|
+
state_dir: string;
|
|
10
|
+
}
|
|
11
|
+
export interface RunDeliveryLineage {
|
|
12
|
+
delivery_owner_id: string;
|
|
13
|
+
delivery_parent?: RunDeliveryParent;
|
|
14
|
+
}
|
|
15
|
+
export declare function inheritedRunDeliveryLineage(ownerId: string | undefined, env?: NodeJS.ProcessEnv): RunDeliveryLineage | undefined;
|
|
16
|
+
export declare function runDeliveryChildEnv(lineage: RunDeliveryLineage, parent: RunDeliveryParent, env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
17
|
+
export declare function getProcessDeliveryOwnerId(env?: NodeJS.ProcessEnv): string | undefined;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run delivery lineage.
|
|
3
|
+
* Zones: inherited coordinator root, parent Run generation, delivery-tree filtering
|
|
4
|
+
* Owns durable completion ancestry; excludes delivery persistence and Pi scheduling.
|
|
5
|
+
*/
|
|
6
|
+
const DELIVERY_OWNER_ENV = "PI_ACTORS_DELIVERY_OWNER_ID";
|
|
7
|
+
const PARENT_RUN_ENV = "PI_ACTORS_DELIVERY_PARENT_RUN";
|
|
8
|
+
const PARENT_INSTANCE_ENV = "PI_ACTORS_DELIVERY_PARENT_INSTANCE";
|
|
9
|
+
const PARENT_STATE_DIR_ENV = "PI_ACTORS_DELIVERY_PARENT_STATE_DIR";
|
|
10
|
+
function nonEmpty(value) {
|
|
11
|
+
const text = value?.trim();
|
|
12
|
+
return text || undefined;
|
|
13
|
+
}
|
|
14
|
+
export function inheritedRunDeliveryLineage(ownerId, env = process.env) {
|
|
15
|
+
const localOwner = nonEmpty(ownerId);
|
|
16
|
+
if (!localOwner)
|
|
17
|
+
return undefined;
|
|
18
|
+
const deliveryOwner = nonEmpty(env[DELIVERY_OWNER_ENV]) ?? localOwner;
|
|
19
|
+
const run = nonEmpty(env[PARENT_RUN_ENV]);
|
|
20
|
+
const runInstanceId = nonEmpty(env[PARENT_INSTANCE_ENV]);
|
|
21
|
+
const stateDir = nonEmpty(env[PARENT_STATE_DIR_ENV]);
|
|
22
|
+
const completeParent = run && runInstanceId && stateDir
|
|
23
|
+
? { run, run_instance_id: runInstanceId, state_dir: stateDir }
|
|
24
|
+
: undefined;
|
|
25
|
+
if ((run || runInstanceId || stateDir) && !completeParent) {
|
|
26
|
+
throw new Error("Inherited Run delivery parent lineage is incomplete");
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
delivery_owner_id: deliveryOwner,
|
|
30
|
+
...(completeParent ? { delivery_parent: completeParent } : {}),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function runDeliveryChildEnv(lineage, parent, env = process.env) {
|
|
34
|
+
return {
|
|
35
|
+
...env,
|
|
36
|
+
[DELIVERY_OWNER_ENV]: lineage.delivery_owner_id,
|
|
37
|
+
[PARENT_RUN_ENV]: parent.run,
|
|
38
|
+
[PARENT_INSTANCE_ENV]: parent.run_instance_id,
|
|
39
|
+
[PARENT_STATE_DIR_ENV]: parent.state_dir,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export function getProcessDeliveryOwnerId(env = process.env) {
|
|
43
|
+
return nonEmpty(env[DELIVERY_OWNER_ENV]);
|
|
44
|
+
}
|
|
@@ -7,6 +7,10 @@ export type RunCompletionDeliveryStatus = "done" | "failed" | "killed" | "exited
|
|
|
7
7
|
export type RunDeliveryPhase = "pending" | "queued" | "presented";
|
|
8
8
|
export interface RunCompletionBatchMember {
|
|
9
9
|
artifacts?: Record<string, string>;
|
|
10
|
+
parent_run?: string;
|
|
11
|
+
parent_run_instance_id?: string;
|
|
12
|
+
parent_state_dir?: string;
|
|
13
|
+
output?: string;
|
|
10
14
|
run: string;
|
|
11
15
|
run_instance_id: string;
|
|
12
16
|
state_dir: string;
|