@llblab/pi-actors 0.19.11 → 0.20.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/AGENTS.md +1 -1
- package/CHANGELOG.md +8 -0
- package/dist/lib/actor-inspector-tui.d.ts +55 -0
- package/dist/lib/actor-inspector-tui.js +559 -0
- package/dist/lib/actor-messages.d.ts +25 -0
- package/dist/lib/actor-messages.js +122 -0
- package/dist/lib/actor-recipe-context.d.ts +14 -0
- package/dist/lib/actor-recipe-context.js +79 -0
- package/dist/lib/actor-rooms.d.ts +81 -0
- package/dist/lib/actor-rooms.js +468 -0
- package/dist/lib/async-runs.d.ts +101 -0
- package/dist/lib/async-runs.js +612 -0
- package/dist/lib/command-templates.d.ts +70 -0
- package/dist/lib/command-templates.js +592 -0
- package/dist/lib/config.d.ts +34 -0
- package/dist/lib/config.js +226 -0
- package/dist/lib/execution.d.ts +63 -0
- package/dist/lib/execution.js +450 -0
- package/dist/lib/file-state.d.ts +6 -0
- package/dist/lib/file-state.js +25 -0
- package/dist/lib/identity.d.ts +9 -0
- package/dist/lib/identity.js +27 -0
- package/dist/lib/observability.d.ts +86 -0
- package/dist/lib/observability.js +534 -0
- package/dist/lib/output.d.ts +25 -0
- package/dist/lib/output.js +89 -0
- package/dist/lib/paths.d.ts +11 -0
- package/dist/lib/paths.js +28 -0
- package/dist/lib/prompts.d.ts +23 -0
- package/dist/lib/prompts.js +50 -0
- package/dist/lib/recipe-discovery.d.ts +50 -0
- package/dist/lib/recipe-discovery.js +317 -0
- package/dist/lib/recipe-migration.d.ts +21 -0
- package/dist/lib/recipe-migration.js +90 -0
- package/dist/lib/recipe-references.d.ts +67 -0
- package/dist/lib/recipe-references.js +542 -0
- package/dist/lib/recipe-usage.d.ts +6 -0
- package/dist/lib/recipe-usage.js +57 -0
- package/dist/lib/registry.d.ts +47 -0
- package/dist/lib/registry.js +222 -0
- package/dist/lib/runtime.d.ts +36 -0
- package/dist/lib/runtime.js +126 -0
- package/dist/lib/schema.d.ts +48 -0
- package/dist/lib/schema.js +355 -0
- package/dist/lib/temp.d.ts +10 -0
- package/dist/lib/temp.js +90 -0
- package/dist/lib/tools.d.ts +39 -0
- package/dist/lib/tools.js +982 -0
- package/lib/async-runs.ts +20 -4
- package/package.json +5 -2
- package/scripts/async-runner.mjs +8 -12
- package/scripts/validate-recipe.mjs +9 -13
- package/skills/actors/SKILL.md +1 -1
- package/skills/swarm/SKILL.md +1 -1
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Actor message protocol helpers.
|
|
3
|
+
* Zones: 0.10 draft communication protocol, addressed messages, mailbox metadata
|
|
4
|
+
* Owns pure validation/normalization for the semantic message envelope; transport routing stays in adapters.
|
|
5
|
+
*/
|
|
6
|
+
const ADDRESS_PATTERN = /^[A-Za-z0-9_.-]+$/;
|
|
7
|
+
const MESSAGE_TYPE_PATTERN = /^[A-Za-z][A-Za-z0-9_.:-]*$/;
|
|
8
|
+
function assertToken(value, label) {
|
|
9
|
+
const normalized = value.trim();
|
|
10
|
+
if (!normalized)
|
|
11
|
+
throw new Error(`${label} is required`);
|
|
12
|
+
if (!ADDRESS_PATTERN.test(normalized)) {
|
|
13
|
+
throw new Error(`${label} contains unsupported characters: ${value}`);
|
|
14
|
+
}
|
|
15
|
+
return normalized;
|
|
16
|
+
}
|
|
17
|
+
export function parseActorAddress(address) {
|
|
18
|
+
const value = address.trim();
|
|
19
|
+
if (value === "coordinator")
|
|
20
|
+
return { kind: "coordinator" };
|
|
21
|
+
const separator = value.indexOf(":");
|
|
22
|
+
if (separator < 0)
|
|
23
|
+
throw new Error(`Actor address must include kind: ${address}`);
|
|
24
|
+
const kind = value.slice(0, separator);
|
|
25
|
+
const rest = value.slice(separator + 1);
|
|
26
|
+
switch (kind) {
|
|
27
|
+
case "branch": {
|
|
28
|
+
const [run, branch, ...extra] = rest.split("/");
|
|
29
|
+
if (extra.length > 0)
|
|
30
|
+
throw new Error(`Branch address has too many parts: ${address}`);
|
|
31
|
+
return {
|
|
32
|
+
kind,
|
|
33
|
+
value: assertToken(run || "", "branch run"),
|
|
34
|
+
branch: assertToken(branch || "", "branch id"),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
case "room": {
|
|
38
|
+
const [run, room, ...extra] = rest.split("/");
|
|
39
|
+
if (extra.length > 0)
|
|
40
|
+
throw new Error(`Room address has too many parts: ${address}`);
|
|
41
|
+
if (room && room !== "main") {
|
|
42
|
+
throw new Error("Task rooms do not support named subrooms; use room:<run>.");
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
kind,
|
|
46
|
+
value: assertToken(run || "", "room run"),
|
|
47
|
+
room: "main",
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
case "run":
|
|
51
|
+
case "session":
|
|
52
|
+
case "tool":
|
|
53
|
+
return { kind, value: assertToken(rest, `${kind} address`) };
|
|
54
|
+
default:
|
|
55
|
+
throw new Error(`Unsupported actor address kind: ${kind}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export function formatActorAddress(address) {
|
|
59
|
+
if (address.kind === "coordinator")
|
|
60
|
+
return "coordinator";
|
|
61
|
+
if (address.kind === "branch") {
|
|
62
|
+
return `branch:${assertToken(address.value || "", "branch run")}/${assertToken(address.branch || "", "branch id")}`;
|
|
63
|
+
}
|
|
64
|
+
if (address.kind === "room") {
|
|
65
|
+
return `room:${assertToken(address.value || "", "room run")}`;
|
|
66
|
+
}
|
|
67
|
+
return `${address.kind}:${assertToken(address.value || "", `${address.kind} address`)}`;
|
|
68
|
+
}
|
|
69
|
+
function normalizeOptionalString(value, label) {
|
|
70
|
+
if (value === undefined || value === null)
|
|
71
|
+
return undefined;
|
|
72
|
+
if (typeof value !== "string")
|
|
73
|
+
throw new Error(`${label} must be a string`);
|
|
74
|
+
const normalized = value.trim();
|
|
75
|
+
return normalized || undefined;
|
|
76
|
+
}
|
|
77
|
+
function normalizeMetadata(value) {
|
|
78
|
+
if (value === undefined || value === null)
|
|
79
|
+
return undefined;
|
|
80
|
+
if (typeof value !== "object" || Array.isArray(value)) {
|
|
81
|
+
throw new Error("message metadata must be an object");
|
|
82
|
+
}
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
export function normalizeActorMessage(input) {
|
|
86
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
87
|
+
throw new Error("actor message must be an object");
|
|
88
|
+
}
|
|
89
|
+
const record = input;
|
|
90
|
+
const to = normalizeOptionalString(record.to, "message.to");
|
|
91
|
+
if (!to)
|
|
92
|
+
throw new Error("message.to is required");
|
|
93
|
+
const parsedTo = parseActorAddress(to);
|
|
94
|
+
const type = normalizeOptionalString(record.type, "message.type");
|
|
95
|
+
if (!type)
|
|
96
|
+
throw new Error("message.type is required");
|
|
97
|
+
if (!MESSAGE_TYPE_PATTERN.test(type)) {
|
|
98
|
+
throw new Error(`message.type contains unsupported characters: ${type}`);
|
|
99
|
+
}
|
|
100
|
+
const from = normalizeOptionalString(record.from, "message.from");
|
|
101
|
+
if (from)
|
|
102
|
+
parseActorAddress(from);
|
|
103
|
+
const normalizedTo = formatActorAddress(parsedTo);
|
|
104
|
+
return {
|
|
105
|
+
to: normalizedTo,
|
|
106
|
+
type,
|
|
107
|
+
...(record.body !== undefined ? { body: record.body } : {}),
|
|
108
|
+
...(record.correlation_id !== undefined
|
|
109
|
+
? { correlation_id: String(record.correlation_id) }
|
|
110
|
+
: {}),
|
|
111
|
+
...(from ? { from: formatActorAddress(parseActorAddress(from)) } : {}),
|
|
112
|
+
...(record.metadata !== undefined
|
|
113
|
+
? { metadata: normalizeMetadata(record.metadata) }
|
|
114
|
+
: {}),
|
|
115
|
+
...(record.reply_to !== undefined
|
|
116
|
+
? { reply_to: String(record.reply_to) }
|
|
117
|
+
: {}),
|
|
118
|
+
...(record.summary !== undefined
|
|
119
|
+
? { summary: String(record.summary) }
|
|
120
|
+
: {}),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Actor recipe context prompt helpers.
|
|
3
|
+
* Zones: async runner prompt context, recipe provenance, LLM child launches
|
|
4
|
+
*/
|
|
5
|
+
import type { CommandTemplateActorRecipeContext } from "./command-templates.ts";
|
|
6
|
+
import type { TemplateRecipeContextRecord } from "./recipe-references.ts";
|
|
7
|
+
export interface MarkedRecipeContextRecord extends TemplateRecipeContextRecord {
|
|
8
|
+
you_are_here?: true;
|
|
9
|
+
you_are_here_path?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function markRecipeContextRecords(records: TemplateRecipeContextRecord[], context?: CommandTemplateActorRecipeContext): MarkedRecipeContextRecord[];
|
|
12
|
+
export declare function formatRecipeContextJsonl(records: TemplateRecipeContextRecord[], context?: CommandTemplateActorRecipeContext): string;
|
|
13
|
+
export declare function buildRecipeContextPromptBlock(records: TemplateRecipeContextRecord[], context?: CommandTemplateActorRecipeContext): string;
|
|
14
|
+
export declare function appendRecipeContextToPiArgs(command: string, args: string[], records: TemplateRecipeContextRecord[] | undefined, context?: CommandTemplateActorRecipeContext): string[];
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Actor recipe context prompt helpers.
|
|
3
|
+
* Zones: async runner prompt context, recipe provenance, LLM child launches
|
|
4
|
+
*/
|
|
5
|
+
import { basename } from "node:path";
|
|
6
|
+
function commandName(command) {
|
|
7
|
+
return basename(command).toLowerCase();
|
|
8
|
+
}
|
|
9
|
+
function isPiCommand(command) {
|
|
10
|
+
return commandName(command) === "pi";
|
|
11
|
+
}
|
|
12
|
+
function findPrintPromptIndex(args) {
|
|
13
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
14
|
+
const arg = args[index];
|
|
15
|
+
if ((arg === "-p" || arg === "--print") && index + 1 < args.length) {
|
|
16
|
+
return index + 1;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
function matchesActorContext(record, context) {
|
|
22
|
+
if (!context)
|
|
23
|
+
return record.role === "entry";
|
|
24
|
+
if (context.file && context.file === record.file)
|
|
25
|
+
return true;
|
|
26
|
+
if (context.name && context.name === record.name)
|
|
27
|
+
return true;
|
|
28
|
+
if (context.alias && context.alias === record.alias)
|
|
29
|
+
return true;
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
function contextPath(record, context) {
|
|
33
|
+
return record.import_path.join(".") || context?.path || record.name;
|
|
34
|
+
}
|
|
35
|
+
export function markRecipeContextRecords(records, context) {
|
|
36
|
+
let marked = false;
|
|
37
|
+
const result = records.map((record) => {
|
|
38
|
+
if (marked || !matchesActorContext(record, context))
|
|
39
|
+
return record;
|
|
40
|
+
marked = true;
|
|
41
|
+
return {
|
|
42
|
+
...record,
|
|
43
|
+
you_are_here: true,
|
|
44
|
+
you_are_here_path: contextPath(record, context),
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
export function formatRecipeContextJsonl(records, context) {
|
|
50
|
+
return markRecipeContextRecords(records, context)
|
|
51
|
+
.map((record) => JSON.stringify(record))
|
|
52
|
+
.join("\n");
|
|
53
|
+
}
|
|
54
|
+
export function buildRecipeContextPromptBlock(records, context) {
|
|
55
|
+
const jsonl = formatRecipeContextJsonl(records, context);
|
|
56
|
+
if (!jsonl)
|
|
57
|
+
return "";
|
|
58
|
+
return [
|
|
59
|
+
"Actor recipe context bundle follows as JSONL.",
|
|
60
|
+
'Each line is one recipe/context record; `"you_are_here": true` marks the recipe node that launched this actor.',
|
|
61
|
+
"Use this as workflow/composition context, while the task prompt remains authoritative.",
|
|
62
|
+
"```jsonl",
|
|
63
|
+
jsonl,
|
|
64
|
+
"```",
|
|
65
|
+
].join("\n");
|
|
66
|
+
}
|
|
67
|
+
export function appendRecipeContextToPiArgs(command, args, records, context) {
|
|
68
|
+
if (!records || records.length === 0 || !isPiCommand(command))
|
|
69
|
+
return args;
|
|
70
|
+
const promptIndex = findPrintPromptIndex(args);
|
|
71
|
+
if (promptIndex === undefined)
|
|
72
|
+
return args;
|
|
73
|
+
const block = buildRecipeContextPromptBlock(records, context);
|
|
74
|
+
if (!block)
|
|
75
|
+
return args;
|
|
76
|
+
const next = [...args];
|
|
77
|
+
next[promptIndex] = `${next[promptIndex]}\n\n${block}`;
|
|
78
|
+
return next;
|
|
79
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Actor room persistence helpers.
|
|
3
|
+
* Zones: room timelines, room rosters, cross-branch discovery state
|
|
4
|
+
* Owns small file-backed room state; routing policy stays in tools/runtime adapters.
|
|
5
|
+
*/
|
|
6
|
+
import type { ActorMessage } from "./actor-messages.ts";
|
|
7
|
+
export interface RoomMember {
|
|
8
|
+
address: string;
|
|
9
|
+
caps?: unknown;
|
|
10
|
+
claim?: unknown;
|
|
11
|
+
display?: unknown;
|
|
12
|
+
joined_at: string;
|
|
13
|
+
last_seen: string;
|
|
14
|
+
parent?: unknown;
|
|
15
|
+
role?: unknown;
|
|
16
|
+
status?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface RoomTimelineEntry extends ActorMessage {
|
|
19
|
+
received_at: string;
|
|
20
|
+
}
|
|
21
|
+
export interface RoomAppendResult {
|
|
22
|
+
room: string;
|
|
23
|
+
message_count: number;
|
|
24
|
+
roster_count: number;
|
|
25
|
+
sent: true;
|
|
26
|
+
}
|
|
27
|
+
export interface RoomMessagePreview {
|
|
28
|
+
body_preview?: string;
|
|
29
|
+
from?: string;
|
|
30
|
+
summary?: string;
|
|
31
|
+
timestamp: string;
|
|
32
|
+
to: string;
|
|
33
|
+
type: string;
|
|
34
|
+
}
|
|
35
|
+
export interface RoomStatus {
|
|
36
|
+
room: string;
|
|
37
|
+
message_count: number;
|
|
38
|
+
roster_count: number;
|
|
39
|
+
last_message_at?: string;
|
|
40
|
+
last_message_from?: string;
|
|
41
|
+
last_message_summary?: string;
|
|
42
|
+
last_message_type?: string;
|
|
43
|
+
}
|
|
44
|
+
export interface RoomContact {
|
|
45
|
+
address: string;
|
|
46
|
+
caps?: unknown;
|
|
47
|
+
claim?: unknown;
|
|
48
|
+
parent?: unknown;
|
|
49
|
+
role?: unknown;
|
|
50
|
+
status?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface ActorCommunicationSnapshot {
|
|
53
|
+
contacts?: RoomContact[];
|
|
54
|
+
parent?: string;
|
|
55
|
+
root: string;
|
|
56
|
+
self: string;
|
|
57
|
+
rooms: Array<{
|
|
58
|
+
address: string;
|
|
59
|
+
members?: RoomMember[];
|
|
60
|
+
name: string;
|
|
61
|
+
}>;
|
|
62
|
+
updated_at: string;
|
|
63
|
+
}
|
|
64
|
+
export declare function readRoomRoster(stateDir: string, room: string): Record<string, RoomMember>;
|
|
65
|
+
export declare function readBranchInboxMessages(stateDir: string, run: string, address: string, limit?: number): Array<ActorMessage & {
|
|
66
|
+
id?: string;
|
|
67
|
+
queued_at?: string;
|
|
68
|
+
status?: string;
|
|
69
|
+
}>;
|
|
70
|
+
export declare function appendBranchInboxMessage(stateDir: string, run: string, address: string, message: ActorMessage): void;
|
|
71
|
+
export declare function updateBranchInboxMessageStatus(stateDir: string, run: string, address: string, id: string, status: "claimed" | "handled" | "failed", metadata?: Record<string, unknown>): boolean;
|
|
72
|
+
export declare function appendRoomMessage(stateDir: string, room: string, message: ActorMessage): RoomAppendResult;
|
|
73
|
+
export declare function readRoomMessages(stateDir: string, room: string, limit?: number): RoomTimelineEntry[];
|
|
74
|
+
export declare function readRoomMessagePreviews(stateDir: string, room: string, limit?: number): RoomMessagePreview[];
|
|
75
|
+
export declare function getRoomStatus(stateDir: string, room: string): RoomStatus;
|
|
76
|
+
export declare function ensureRoomMember(stateDir: string, run: string, room: string, address: string, body: Record<string, unknown>, summary: string): RoomAppendResult;
|
|
77
|
+
export declare function ensureDefaultRoom(stateDir: string, run: string): RoomAppendResult;
|
|
78
|
+
export declare function readCommunicationSnapshot(stateDir: string): ActorCommunicationSnapshot | undefined;
|
|
79
|
+
export declare function readRoomContacts(stateDir: string, room: string, self?: string): RoomContact[];
|
|
80
|
+
export declare function writeCommunicationSnapshot(stateDir: string, run: string): ActorCommunicationSnapshot;
|
|
81
|
+
export declare function writeBranchCommunicationSnapshot(stateDir: string, run: string, self: string): ActorCommunicationSnapshot;
|