@marcoscale98/pi-extensible-workflows 5.14.1-fork.1
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 +536 -0
- package/README.md +64 -0
- package/dist/src/agent-execution.d.ts +338 -0
- package/dist/src/agent-execution.js +1633 -0
- package/dist/src/background-widget.d.ts +74 -0
- package/dist/src/background-widget.js +1340 -0
- package/dist/src/budget.d.ts +38 -0
- package/dist/src/budget.js +188 -0
- package/dist/src/changelog.d.ts +6 -0
- package/dist/src/changelog.js +112 -0
- package/dist/src/decoders.d.ts +96 -0
- package/dist/src/decoders.js +629 -0
- package/dist/src/execution.d.ts +19 -0
- package/dist/src/execution.js +749 -0
- package/dist/src/herdr.d.ts +53 -0
- package/dist/src/herdr.js +270 -0
- package/dist/src/host-delivery.d.ts +95 -0
- package/dist/src/host-delivery.js +376 -0
- package/dist/src/host-navigator.d.ts +83 -0
- package/dist/src/host-navigator.js +1087 -0
- package/dist/src/host-phases.d.ts +89 -0
- package/dist/src/host-phases.js +320 -0
- package/dist/src/host-recovery.d.ts +141 -0
- package/dist/src/host-recovery.js +356 -0
- package/dist/src/host-runtime.d.ts +78 -0
- package/dist/src/host-runtime.js +378 -0
- package/dist/src/host-view.d.ts +116 -0
- package/dist/src/host-view.js +868 -0
- package/dist/src/host.d.ts +40 -0
- package/dist/src/host.js +1641 -0
- package/dist/src/index.d.ts +29 -0
- package/dist/src/index.js +13725 -0
- package/dist/src/index.js.map +6 -0
- package/dist/src/io.d.ts +14 -0
- package/dist/src/io.js +82 -0
- package/dist/src/package-identity.d.ts +4 -0
- package/dist/src/package-identity.js +6 -0
- package/dist/src/paths.d.ts +14 -0
- package/dist/src/paths.js +51 -0
- package/dist/src/persistence.d.ts +5 -0
- package/dist/src/persistence.js +5 -0
- package/dist/src/pi-runtime-adapter.d.ts +27 -0
- package/dist/src/pi-runtime-adapter.js +243 -0
- package/dist/src/pi-runtime-runner.d.ts +42 -0
- package/dist/src/pi-runtime-runner.js +505 -0
- package/dist/src/registry.d.ts +48 -0
- package/dist/src/registry.js +379 -0
- package/dist/src/retention.d.ts +17 -0
- package/dist/src/retention.js +195 -0
- package/dist/src/runtime/agent-runner.d.ts +143 -0
- package/dist/src/runtime/agent-runner.js +12 -0
- package/dist/src/runtime/index.d.ts +2 -0
- package/dist/src/runtime/index.js +2 -0
- package/dist/src/runtime/namespace.d.ts +14 -0
- package/dist/src/runtime/namespace.js +1 -0
- package/dist/src/runtime/workflow-result.d.ts +2 -0
- package/dist/src/runtime/workflow-result.js +6 -0
- package/dist/src/session-handoff.d.ts +2 -0
- package/dist/src/session-handoff.js +82 -0
- package/dist/src/session-lease.d.ts +12 -0
- package/dist/src/session-lease.js +180 -0
- package/dist/src/store.d.ts +95 -0
- package/dist/src/store.js +951 -0
- package/dist/src/subagent-manager-handle.d.ts +4 -0
- package/dist/src/subagent-manager-handle.js +6 -0
- package/dist/src/tool-timing.d.ts +12 -0
- package/dist/src/tool-timing.js +33 -0
- package/dist/src/trajectory-contracts.d.ts +8 -0
- package/dist/src/trajectory-contracts.js +9 -0
- package/dist/src/trajectory-host-handle.d.ts +12 -0
- package/dist/src/trajectory-host-handle.js +6 -0
- package/dist/src/trajectory.d.ts +128 -0
- package/dist/src/trajectory.js +594 -0
- package/dist/src/types.d.ts +960 -0
- package/dist/src/types.js +60 -0
- package/dist/src/utils.d.ts +57 -0
- package/dist/src/utils.js +225 -0
- package/dist/src/validation.d.ts +29 -0
- package/dist/src/validation.js +1100 -0
- package/dist/src/workflow-artifacts.d.ts +14 -0
- package/dist/src/workflow-artifacts.js +40 -0
- package/dist/starter/index.d.ts +1 -0
- package/dist/starter/index.js +103 -0
- package/dist/starter/index.js.map +6 -0
- package/dist/starter/review-loop.d.ts +72 -0
- package/dist/starter/review-loop.js +43 -0
- package/dist/starter/roles/developer.md +6 -0
- package/dist/starter/roles/oracle.md +18 -0
- package/dist/starter/roles/researcher.md +20 -0
- package/dist/starter/roles/reviewer.md +19 -0
- package/dist/starter/roles/scout.md +18 -0
- package/dist/subagents/index.d.ts +8 -0
- package/dist/subagents/index.js +8021 -0
- package/dist/subagents/index.js.map +6 -0
- package/dist/subagents/src/contracts.d.ts +173 -0
- package/dist/subagents/src/contracts.js +68 -0
- package/dist/subagents/src/decode.d.ts +15 -0
- package/dist/subagents/src/decode.js +182 -0
- package/dist/subagents/src/index.d.ts +12 -0
- package/dist/subagents/src/index.js +180 -0
- package/dist/subagents/src/manager.d.ts +3 -0
- package/dist/subagents/src/manager.js +1636 -0
- package/dist/subagents/src/navigator.d.ts +5 -0
- package/dist/subagents/src/navigator.js +627 -0
- package/dist/subagents/src/view.d.ts +70 -0
- package/dist/subagents/src/view.js +387 -0
- package/dist/subagents/src/worktree.d.ts +34 -0
- package/dist/subagents/src/worktree.js +68 -0
- package/dist/trajectory/assets/favicon.png +0 -0
- package/dist/trajectory/assets/index.html +772 -0
- package/dist/trajectory/assets/marked.min.js +6 -0
- package/dist/trajectory/assets/morphdom.min.js +1 -0
- package/dist/trajectory/index.d.ts +5 -0
- package/dist/trajectory/index.js +3459 -0
- package/dist/trajectory/index.js.map +6 -0
- package/dist/trajectory/src/assets/favicon.png +0 -0
- package/dist/trajectory/src/assets/index.html +772 -0
- package/dist/trajectory/src/assets/marked.min.js +6 -0
- package/dist/trajectory/src/assets/morphdom.min.js +1 -0
- package/dist/trajectory/src/export.d.ts +25 -0
- package/dist/trajectory/src/export.js +80 -0
- package/dist/trajectory/src/index.d.ts +26 -0
- package/dist/trajectory/src/index.js +732 -0
- package/dist/trajectory/src/server.d.ts +7 -0
- package/dist/trajectory/src/server.js +2534 -0
- package/dist/trajectory/src/server.js.map +6 -0
- package/examples/advanced-patterns/auto-model-router.mjs +78 -0
- package/examples/workflow-extension-template/README.md +37 -0
- package/examples/workflow-extension-template/extension.test.mjs +59 -0
- package/examples/workflow-extension-template/index.js +51 -0
- package/examples/workflow-extension-template/roles/reviewer.md +4 -0
- package/package.json +105 -0
- package/skills/pi-extensible-workflows/SKILL.md +160 -0
- package/src/agent-execution.ts +1533 -0
- package/src/background-widget.ts +1496 -0
- package/src/budget.ts +109 -0
- package/src/changelog.ts +114 -0
- package/src/decoders.ts +567 -0
- package/src/execution.ts +652 -0
- package/src/herdr.ts +240 -0
- package/src/host-delivery.ts +346 -0
- package/src/host-navigator.ts +871 -0
- package/src/host-phases.ts +264 -0
- package/src/host-recovery.ts +333 -0
- package/src/host-runtime.ts +373 -0
- package/src/host-view.ts +828 -0
- package/src/host.ts +1502 -0
- package/src/index.ts +29 -0
- package/src/io.ts +73 -0
- package/src/package-identity.ts +7 -0
- package/src/paths.ts +49 -0
- package/src/persistence.ts +11 -0
- package/src/pi-runtime-adapter.ts +247 -0
- package/src/pi-runtime-runner.ts +436 -0
- package/src/registry.ts +321 -0
- package/src/retention.ts +178 -0
- package/src/runtime/agent-runner.ts +158 -0
- package/src/runtime/index.ts +2 -0
- package/src/runtime/namespace.ts +16 -0
- package/src/runtime/workflow-result.ts +8 -0
- package/src/session-handoff.ts +78 -0
- package/src/session-lease.ts +125 -0
- package/src/store.ts +832 -0
- package/src/subagent-manager-handle.ts +8 -0
- package/src/tool-timing.ts +47 -0
- package/src/trajectory-contracts.ts +13 -0
- package/src/trajectory-host-handle.ts +16 -0
- package/src/trajectory.ts +543 -0
- package/src/types.ts +374 -0
- package/src/utils.ts +192 -0
- package/src/validation.ts +910 -0
- package/src/workflow-artifacts.ts +35 -0
- package/starter/index.ts +35 -0
- package/starter/prompts/council.md +16 -0
- package/starter/prompts/deep-research.md +16 -0
- package/starter/prompts/oracle.md +14 -0
- package/starter/prompts/parallel-review.md +22 -0
- package/starter/prompts/parallel-scout.md +16 -0
- package/starter/prompts/review-loop.md +14 -0
- package/starter/prompts/review.md +14 -0
- package/starter/prompts/scout.md +14 -0
- package/starter/review-loop.ts +73 -0
- package/starter/roles/developer.md +6 -0
- package/starter/roles/oracle.md +18 -0
- package/starter/roles/researcher.md +20 -0
- package/starter/roles/reviewer.md +19 -0
- package/starter/roles/scout.md +18 -0
- package/subagents/README.md +145 -0
- package/subagents/index.ts +8 -0
- package/subagents/src/contracts.ts +176 -0
- package/subagents/src/decode.ts +158 -0
- package/subagents/src/index.ts +194 -0
- package/subagents/src/manager.ts +1560 -0
- package/subagents/src/navigator.ts +488 -0
- package/subagents/src/view.ts +376 -0
- package/subagents/src/worktree.ts +99 -0
- package/trajectory/index.ts +5 -0
- package/trajectory/src/assets/favicon.png +0 -0
- package/trajectory/src/assets/index.html +772 -0
- package/trajectory/src/assets/marked.min.js +6 -0
- package/trajectory/src/assets/morphdom.min.js +1 -0
- package/trajectory/src/export.ts +85 -0
- package/trajectory/src/index.ts +604 -0
- package/trajectory/src/server.ts +447 -0
package/dist/src/io.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const gitIdentity: {
|
|
2
|
+
GIT_AUTHOR_NAME: string;
|
|
3
|
+
GIT_AUTHOR_EMAIL: string;
|
|
4
|
+
GIT_COMMITTER_NAME: string;
|
|
5
|
+
GIT_COMMITTER_EMAIL: string;
|
|
6
|
+
GIT_AUTHOR_DATE: string;
|
|
7
|
+
GIT_COMMITTER_DATE: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function atomicWriteFile(path: string, content: string): Promise<void>;
|
|
10
|
+
export declare function atomicWriteFile(path: string, content: string, sync: true): void;
|
|
11
|
+
export declare function atomicJson(path: string, value: unknown): Promise<void>;
|
|
12
|
+
export declare function atomicPrettyJson(path: string, value: unknown): Promise<void>;
|
|
13
|
+
export declare function json(path: string): Promise<unknown>;
|
|
14
|
+
export declare function git(cwd: string, args: readonly string[], extraEnv?: NodeJS.ProcessEnv): Promise<string>;
|
package/dist/src/io.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { renameSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
import { WorkflowError } from "./types.js";
|
|
7
|
+
import { isNodeError } from "./utils.js";
|
|
8
|
+
const execute = promisify(execFile);
|
|
9
|
+
// ponytail: retry window is capped at 1.585s; use durable lock coordination if holders outlive it.
|
|
10
|
+
const RENAME_RETRY_DELAYS_MS = [10, 25, 50, 100, 200, 400, 800];
|
|
11
|
+
const syncSleepBuffer = new Int32Array(new SharedArrayBuffer(4));
|
|
12
|
+
function retryableRenameError(error) { return isNodeError(error, "EPERM") || isNodeError(error, "EBUSY") || isNodeError(error, "EACCES"); }
|
|
13
|
+
async function renameWithRetry(from, to) {
|
|
14
|
+
for (let attempt = 0;; attempt += 1) {
|
|
15
|
+
try {
|
|
16
|
+
await rename(from, to);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
const delayMs = RENAME_RETRY_DELAYS_MS[attempt];
|
|
21
|
+
if (!retryableRenameError(error) || delayMs === undefined)
|
|
22
|
+
throw error;
|
|
23
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function renameSyncWithRetry(from, to) {
|
|
28
|
+
for (let attempt = 0;; attempt += 1) {
|
|
29
|
+
try {
|
|
30
|
+
renameSync(from, to);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
const delayMs = RENAME_RETRY_DELAYS_MS[attempt];
|
|
35
|
+
if (!retryableRenameError(error) || delayMs === undefined)
|
|
36
|
+
throw error;
|
|
37
|
+
Atomics.wait(syncSleepBuffer, 0, 0, delayMs);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export const gitIdentity = {
|
|
42
|
+
GIT_AUTHOR_NAME: "pi-extensible-workflows", GIT_AUTHOR_EMAIL: "pi-extensible-workflows@localhost", GIT_COMMITTER_NAME: "pi-extensible-workflows", GIT_COMMITTER_EMAIL: "pi-extensible-workflows@localhost",
|
|
43
|
+
GIT_AUTHOR_DATE: "2000-01-01T00:00:00Z", GIT_COMMITTER_DATE: "2000-01-01T00:00:00Z",
|
|
44
|
+
};
|
|
45
|
+
export function atomicWriteFile(path, content, sync = false) {
|
|
46
|
+
const temporary = `${path}.${String(process.pid)}.${randomUUID()}.tmp`;
|
|
47
|
+
if (sync) {
|
|
48
|
+
try {
|
|
49
|
+
writeFileSync(temporary, content, { encoding: "utf8", mode: 0o600 });
|
|
50
|
+
renameSyncWithRetry(temporary, path);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
try {
|
|
54
|
+
rmSync(temporary, { force: true });
|
|
55
|
+
}
|
|
56
|
+
catch { /* Preserve the original write error. */ }
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
return writeFile(temporary, content, { encoding: "utf8", mode: 0o600 }).then(() => renameWithRetry(temporary, path)).catch(async (error) => {
|
|
62
|
+
try {
|
|
63
|
+
await rm(temporary, { force: true });
|
|
64
|
+
}
|
|
65
|
+
catch { /* Preserve the original write error. */ }
|
|
66
|
+
throw error;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
export async function atomicJson(path, value) {
|
|
70
|
+
const serialized = JSON.stringify(value);
|
|
71
|
+
if (typeof serialized !== "string")
|
|
72
|
+
throw new WorkflowError("INTERNAL_ERROR", `Cannot serialize JSON for ${path}`);
|
|
73
|
+
await atomicWriteFile(path, `${serialized}\n`);
|
|
74
|
+
}
|
|
75
|
+
export async function atomicPrettyJson(path, value) {
|
|
76
|
+
await atomicWriteFile(path, `${JSON.stringify(value, null, 2)}\n`);
|
|
77
|
+
}
|
|
78
|
+
export async function json(path) { return JSON.parse(await readFile(path, "utf8")); }
|
|
79
|
+
export async function git(cwd, args, extraEnv = {}) {
|
|
80
|
+
const { stdout } = await execute("git", ["-c", "core.hooksPath=/dev/null", "-c", "commit.gpgSign=false", ...args], { cwd, env: { ...process.env, ...extraEnv }, encoding: "utf8", maxBuffer: 10 * 1024 * 1024 });
|
|
81
|
+
return stdout;
|
|
82
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const CORE_PACKAGE_NAME = "@marcoscale98/pi-extensible-workflows";
|
|
2
|
+
export declare const CORE_PACKAGE_COMPATIBILITY_NAME = "pi-extensible-workflows";
|
|
3
|
+
export declare const CORE_PACKAGE_NAMES: readonly ["@marcoscale98/pi-extensible-workflows", "pi-extensible-workflows"];
|
|
4
|
+
export declare function isCorePackageName(value: unknown): boolean;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const CORE_PACKAGE_NAME = "@marcoscale98/pi-extensible-workflows";
|
|
2
|
+
export const CORE_PACKAGE_COMPATIBILITY_NAME = "pi-extensible-workflows";
|
|
3
|
+
export const CORE_PACKAGE_NAMES = [CORE_PACKAGE_NAME, CORE_PACKAGE_COMPATIBILITY_NAME];
|
|
4
|
+
export function isCorePackageName(value) {
|
|
5
|
+
return typeof value === "string" && CORE_PACKAGE_NAMES.includes(value);
|
|
6
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function safePart(value: string): string;
|
|
2
|
+
/**
|
|
3
|
+
* Resolves a path to its filesystem spelling, including symlink and platform aliases.
|
|
4
|
+
* A missing path safely falls back to its absolute lexical spelling rather than
|
|
5
|
+
* guessing at the identity of an object that does not exist.
|
|
6
|
+
*/
|
|
7
|
+
export declare function canonicalPath(path: string): string;
|
|
8
|
+
export declare function sameFilesystemPath(left: string, right: string): boolean;
|
|
9
|
+
export declare function workflowProjectSettingsPath(cwd: string): string;
|
|
10
|
+
export declare function projectStorageKey(cwd: string): string;
|
|
11
|
+
export declare function projectSessionsDirectory(cwd: string, home?: string): string;
|
|
12
|
+
export declare function runsDirectory(cwd: string, sessionId: string, home?: string): string;
|
|
13
|
+
export declare function listPersistedSessionIds(cwd: string, home?: string): Promise<string[]>;
|
|
14
|
+
export declare function structuralPath(...names: string[]): string;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { realpathSync } from "node:fs";
|
|
3
|
+
import { readdir } from "node:fs/promises";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { basename, join, resolve } from "node:path";
|
|
6
|
+
import { WorkflowError } from "./types.js";
|
|
7
|
+
import { isNodeError } from "./utils.js";
|
|
8
|
+
export function safePart(value) { return value.replace(/[^a-zA-Z0-9._-]/g, "_"); }
|
|
9
|
+
/**
|
|
10
|
+
* Resolves a path to its filesystem spelling, including symlink and platform aliases.
|
|
11
|
+
* A missing path safely falls back to its absolute lexical spelling rather than
|
|
12
|
+
* guessing at the identity of an object that does not exist.
|
|
13
|
+
*/
|
|
14
|
+
export function canonicalPath(path) {
|
|
15
|
+
const absolute = resolve(path);
|
|
16
|
+
try {
|
|
17
|
+
return realpathSync(absolute);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return absolute;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function sameFilesystemPath(left, right) { return canonicalPath(left) === canonicalPath(right); }
|
|
24
|
+
export function workflowProjectSettingsPath(cwd) { return join(cwd, ".pi", "pi-extensible-workflows", "settings.json"); }
|
|
25
|
+
export function projectStorageKey(cwd) {
|
|
26
|
+
const exact = resolve(cwd);
|
|
27
|
+
const slug = safePart(basename(exact)) || "root";
|
|
28
|
+
return `${slug}-${createHash("sha256").update(exact).digest("hex").slice(0, 12)}`;
|
|
29
|
+
}
|
|
30
|
+
export function projectSessionsDirectory(cwd, home = homedir()) {
|
|
31
|
+
return join(home, ".pi", "workflows", "projects", projectStorageKey(cwd), "sessions");
|
|
32
|
+
}
|
|
33
|
+
export function runsDirectory(cwd, sessionId, home = homedir()) {
|
|
34
|
+
return join(projectSessionsDirectory(cwd, home), safePart(sessionId), "runs");
|
|
35
|
+
}
|
|
36
|
+
export async function listPersistedSessionIds(cwd, home = homedir()) {
|
|
37
|
+
try {
|
|
38
|
+
const entries = await readdir(projectSessionsDirectory(cwd, home), { withFileTypes: true });
|
|
39
|
+
return entries.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map(({ name }) => name);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (isNodeError(error, "ENOENT"))
|
|
43
|
+
return [];
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export function structuralPath(...names) {
|
|
48
|
+
if (names.length === 0 || names.some((name) => name.trim() === ""))
|
|
49
|
+
throw new WorkflowError("INVALID_METADATA", "Structural paths require non-empty explicit names");
|
|
50
|
+
return names.map((name) => encodeURIComponent(name)).join("/");
|
|
51
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { atomicJson, atomicWriteFile, json } from "./io.js";
|
|
2
|
+
export { projectStorageKey, projectSessionsDirectory, runsDirectory, listPersistedSessionIds, structuralPath, } from "./paths.js";
|
|
3
|
+
export { hasLiveSessionLease, SessionLease, acquireSessionLease, listRunIds, processAlive } from "./session-lease.js";
|
|
4
|
+
export { RunStore } from "./store.js";
|
|
5
|
+
export { EffectiveSystemPrompt, PersistedRun, RunSummaryAgent, RunSummaryArtifacts, RunSummary, CompletedOperation, AwaitingCheckpoint, PendingWorkflowDecision, PersistedOwnershipNode, WorktreeReference, BorrowedWorktreeBinding, isPersistedRun, } from "./decoders.js";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { atomicJson, atomicWriteFile, json } from "./io.js";
|
|
2
|
+
export { projectStorageKey, projectSessionsDirectory, runsDirectory, listPersistedSessionIds, structuralPath, } from "./paths.js";
|
|
3
|
+
export { hasLiveSessionLease, SessionLease, acquireSessionLease, listRunIds, processAlive } from "./session-lease.js";
|
|
4
|
+
export { RunStore } from "./store.js";
|
|
5
|
+
export { isPersistedRun, } from "./decoders.js";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { RuntimeAgentHandoff, RuntimeAgentProgress } from "./runtime/agent-runner.js";
|
|
2
|
+
import type { AgentProgress } from "./agent-execution.js";
|
|
3
|
+
import type { LiveSessionHandoff, WorkflowAgentMessage, WorkflowAgentSession, WorkflowAgentSessionEvent } from "./types.js";
|
|
4
|
+
export declare function normalizePiMessage(value: unknown): WorkflowAgentMessage | undefined;
|
|
5
|
+
/** An assistant turn Pi aborted before it produced any content; it carries no usable result. */
|
|
6
|
+
export declare function isEmptyAbortedAssistant(message: WorkflowAgentMessage | undefined): boolean;
|
|
7
|
+
export declare function normalizePiSessionEvent(value: unknown): WorkflowAgentSessionEvent | undefined;
|
|
8
|
+
export declare function isTurnBoundaryStart(type: string): boolean;
|
|
9
|
+
/** A turn boundary start or an agent start: either one means the session is busy until the next turn end. */
|
|
10
|
+
export declare function isTurnActivityStart(type: string): boolean;
|
|
11
|
+
export declare function isTurnBoundaryEnd(type: string): boolean;
|
|
12
|
+
export declare function isTurnEnd(type: string): boolean;
|
|
13
|
+
export declare function createRuntimeHandoffAdapter(handoff: LiveSessionHandoff): RuntimeAgentHandoff;
|
|
14
|
+
export interface PiRuntimeProgressObservation {
|
|
15
|
+
readonly event: WorkflowAgentSessionEvent;
|
|
16
|
+
readonly progress: RuntimeAgentProgress;
|
|
17
|
+
readonly report: boolean;
|
|
18
|
+
readonly persist: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface PiRuntimeSessionAdapter {
|
|
21
|
+
readonly handoff: RuntimeAgentHandoff;
|
|
22
|
+
observe(event: WorkflowAgentSessionEvent): PiRuntimeProgressObservation | undefined;
|
|
23
|
+
snapshot(persist: boolean): RuntimeAgentProgress;
|
|
24
|
+
dispose(): void;
|
|
25
|
+
}
|
|
26
|
+
export declare function createPiRuntimeSessionAdapter(session: WorkflowAgentSession, handoff: LiveSessionHandoff, clock?: () => number): PiRuntimeSessionAdapter;
|
|
27
|
+
export declare function runtimeProgressToAgentProgress(value: RuntimeAgentProgress): AgentProgress;
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { isThinkingLevel, sanitizeDisplayText } from "./utils.js";
|
|
2
|
+
const TURN_START_EVENTS = new Set(["turn_start", "turn_started", "turnStarted"]);
|
|
3
|
+
const MAX_ACTIVITY_TEXT_CHARS = 200;
|
|
4
|
+
const AGENT_START_EVENTS = new Set(["agent_start"]);
|
|
5
|
+
const TURN_END_EVENTS = new Set(["turn_end", "turnEnded", "agent_end", "agent_settled"]);
|
|
6
|
+
function record(value) { return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined; }
|
|
7
|
+
function stringValue(value) { return typeof value === "string" ? value : undefined; }
|
|
8
|
+
function finiteNumber(value) { return typeof value === "number" && Number.isFinite(value) ? value : undefined; }
|
|
9
|
+
function normalizeMessage(value) {
|
|
10
|
+
const candidate = record(value);
|
|
11
|
+
const role = stringValue(candidate?.role);
|
|
12
|
+
if (!candidate || role === undefined)
|
|
13
|
+
return undefined;
|
|
14
|
+
const usage = record(candidate.usage);
|
|
15
|
+
const cost = record(usage?.cost);
|
|
16
|
+
const input = finiteNumber(usage?.input);
|
|
17
|
+
const output = finiteNumber(usage?.output);
|
|
18
|
+
const cacheRead = finiteNumber(usage?.cacheRead);
|
|
19
|
+
const cacheWrite = finiteNumber(usage?.cacheWrite);
|
|
20
|
+
const totalCost = finiteNumber(cost?.total);
|
|
21
|
+
const normalizedUsage = input === undefined || output === undefined || cacheRead === undefined || cacheWrite === undefined || totalCost === undefined ? undefined : { input, output, cacheRead, cacheWrite, cost: { total: totalCost } };
|
|
22
|
+
const stopReason = stringValue(candidate.stopReason);
|
|
23
|
+
const errorMessage = stringValue(candidate.errorMessage);
|
|
24
|
+
return {
|
|
25
|
+
role,
|
|
26
|
+
...(candidate.content === undefined ? {} : { content: candidate.content }),
|
|
27
|
+
...(stopReason === undefined ? {} : { stopReason }),
|
|
28
|
+
...(errorMessage === undefined ? {} : { errorMessage }),
|
|
29
|
+
...(normalizedUsage === undefined ? {} : { usage: normalizedUsage }),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function normalizePiMessage(value) { return normalizeMessage(value); }
|
|
33
|
+
/** An assistant turn Pi aborted before it produced any content; it carries no usable result. */
|
|
34
|
+
export function isEmptyAbortedAssistant(message) { return message?.stopReason === "aborted" && Array.isArray(message.content) && message.content.length === 0; }
|
|
35
|
+
function normalizeState(value) {
|
|
36
|
+
const candidate = record(value);
|
|
37
|
+
const model = record(candidate?.model);
|
|
38
|
+
const provider = stringValue(model?.provider);
|
|
39
|
+
const modelName = stringValue(model?.model);
|
|
40
|
+
const rawTools = candidate?.tools;
|
|
41
|
+
const tools = Array.isArray(rawTools) ? rawTools.filter((tool) => typeof tool === "string") : undefined;
|
|
42
|
+
if (!candidate || !model || provider === undefined || modelName === undefined || tools === undefined || !Array.isArray(rawTools) || tools.length !== rawTools.length)
|
|
43
|
+
return undefined;
|
|
44
|
+
const thinking = candidate.thinking === undefined ? model.thinking : candidate.thinking;
|
|
45
|
+
if (thinking !== undefined && !isThinkingLevel(thinking))
|
|
46
|
+
return undefined;
|
|
47
|
+
const systemPrompt = candidate.systemPrompt;
|
|
48
|
+
if (systemPrompt !== undefined && typeof systemPrompt !== "string")
|
|
49
|
+
return undefined;
|
|
50
|
+
return {
|
|
51
|
+
model: { provider, model: modelName, ...(thinking === undefined ? {} : { thinking }) },
|
|
52
|
+
...(thinking === undefined ? {} : { thinking }),
|
|
53
|
+
tools: [...tools],
|
|
54
|
+
...(systemPrompt === undefined ? {} : { systemPrompt }),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function normalizedEvent(value) {
|
|
58
|
+
const candidate = record(value);
|
|
59
|
+
const type = stringValue(candidate?.type);
|
|
60
|
+
if (!candidate || type === undefined)
|
|
61
|
+
return undefined;
|
|
62
|
+
const state = normalizeState(candidate.state);
|
|
63
|
+
const message = normalizeMessage(candidate.message);
|
|
64
|
+
const assistantMessageEvent = record(candidate.assistantMessageEvent);
|
|
65
|
+
const assistantType = stringValue(assistantMessageEvent?.type);
|
|
66
|
+
const assistantDelta = stringValue(assistantMessageEvent?.delta);
|
|
67
|
+
const toolCallId = stringValue(candidate.toolCallId);
|
|
68
|
+
const toolName = stringValue(candidate.toolName);
|
|
69
|
+
const isError = candidate.isError;
|
|
70
|
+
return {
|
|
71
|
+
type,
|
|
72
|
+
...(state === undefined ? {} : { state }),
|
|
73
|
+
...(message === undefined ? {} : { message }),
|
|
74
|
+
...(assistantType === undefined ? {} : { assistantMessageEvent: { type: assistantType, ...(assistantDelta === undefined ? {} : { delta: assistantDelta }) } }),
|
|
75
|
+
...(toolCallId === undefined ? {} : { toolCallId }),
|
|
76
|
+
...(toolName === undefined ? {} : { toolName }),
|
|
77
|
+
...(typeof isError === "boolean" ? { isError } : {}),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export function normalizePiSessionEvent(value) { return normalizedEvent(value); }
|
|
81
|
+
function stateFromSession(session) {
|
|
82
|
+
const current = session.getState();
|
|
83
|
+
return {
|
|
84
|
+
model: { ...current.model },
|
|
85
|
+
...(current.thinking === undefined ? {} : { thinking: current.thinking }),
|
|
86
|
+
tools: [...current.tools],
|
|
87
|
+
...(current.systemPrompt === undefined ? {} : { systemPrompt: current.systemPrompt }),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function runtimeState(state) { return { model: { ...state.model }, ...(state.thinking === undefined ? {} : { thinking: state.thinking }), tools: [...state.tools], ...(state.systemPrompt === undefined ? {} : { systemPrompt: state.systemPrompt }) }; }
|
|
91
|
+
function runtimeUsage(session) {
|
|
92
|
+
const stats = session.getSessionStats();
|
|
93
|
+
const values = [stats.tokens.input, stats.tokens.output, stats.tokens.cacheRead, stats.tokens.cacheWrite, stats.cost];
|
|
94
|
+
if (values.some((value) => !Number.isFinite(value)))
|
|
95
|
+
return { availability: "unavailable" };
|
|
96
|
+
return { availability: "complete", input: stats.tokens.input, output: stats.tokens.output, cacheRead: stats.tokens.cacheRead, cacheWrite: stats.tokens.cacheWrite, costUsd: stats.cost };
|
|
97
|
+
}
|
|
98
|
+
function sameActivity(left, right) { return left?.kind === right?.kind && left?.text === right?.text; }
|
|
99
|
+
function runtimeHandoffState(state) {
|
|
100
|
+
if (state === "handoff-pending")
|
|
101
|
+
return "takeover-pending";
|
|
102
|
+
if (state === "herdr-running")
|
|
103
|
+
return "remote-running";
|
|
104
|
+
return state;
|
|
105
|
+
}
|
|
106
|
+
export function isTurnBoundaryStart(type) { return TURN_START_EVENTS.has(type); }
|
|
107
|
+
/** A turn boundary start or an agent start: either one means the session is busy until the next turn end. */
|
|
108
|
+
export function isTurnActivityStart(type) { return TURN_START_EVENTS.has(type) || AGENT_START_EVENTS.has(type); }
|
|
109
|
+
export function isTurnBoundaryEnd(type) { return TURN_END_EVENTS.has(type); }
|
|
110
|
+
export function isTurnEnd(type) { return type === "turn_end" || type === "turnEnded"; }
|
|
111
|
+
function boundaryEvent(type) {
|
|
112
|
+
if (isTurnActivityStart(type))
|
|
113
|
+
return "turn_started";
|
|
114
|
+
if (isTurnBoundaryEnd(type))
|
|
115
|
+
return "turn_end";
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
export function createRuntimeHandoffAdapter(handoff) {
|
|
119
|
+
return {
|
|
120
|
+
get state() { return runtimeHandoffState(handoff.state); },
|
|
121
|
+
get transferred() { return handoff.transferred; },
|
|
122
|
+
observe(event) {
|
|
123
|
+
const type = boundaryEvent(event.type);
|
|
124
|
+
if (type !== undefined)
|
|
125
|
+
handoff.observe({ type });
|
|
126
|
+
},
|
|
127
|
+
request: (launch) => handoff.request(launch),
|
|
128
|
+
waitForTakeover: () => handoff.waitForTakeover(),
|
|
129
|
+
takeover: () => { handoff.takeover(); },
|
|
130
|
+
waitForResume: () => handoff.waitForResume(),
|
|
131
|
+
release: (reason) => { handoff.release(reason); },
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
export function createPiRuntimeSessionAdapter(session, handoff, clock = Date.now) {
|
|
135
|
+
const neutralHandoff = createRuntimeHandoffAdapter(handoff);
|
|
136
|
+
const toolCalls = new Map();
|
|
137
|
+
let activity;
|
|
138
|
+
let streamText = "";
|
|
139
|
+
let lastEventAt;
|
|
140
|
+
let lastReportedEventAt;
|
|
141
|
+
let disposed = false;
|
|
142
|
+
let toolCallsView = [];
|
|
143
|
+
const progressAt = (persist, stateOverride, toolCallsValue, activityValue, eventAtValue) => ({ usage: runtimeUsage(session), toolCalls: toolCallsValue, state: stateOverride ?? stateFromSession(session), ...(activityValue === undefined ? {} : { activity: activityValue }), ...(eventAtValue === undefined ? {} : { lastEventAt: eventAtValue }), persist });
|
|
144
|
+
const snapshot = (persist) => progressAt(persist, undefined, [...toolCalls.values()], activity, lastEventAt);
|
|
145
|
+
return {
|
|
146
|
+
handoff: neutralHandoff,
|
|
147
|
+
observe(event) {
|
|
148
|
+
if (disposed)
|
|
149
|
+
return undefined;
|
|
150
|
+
neutralHandoff.observe(event);
|
|
151
|
+
const eventAt = clock();
|
|
152
|
+
lastEventAt = eventAt;
|
|
153
|
+
const eventState = event.state === undefined ? undefined : runtimeState(event.state);
|
|
154
|
+
let report = false;
|
|
155
|
+
let persist = false;
|
|
156
|
+
const previousActivity = activity;
|
|
157
|
+
let eventToolCalls = toolCallsView;
|
|
158
|
+
if (event.type === "state_changed") {
|
|
159
|
+
report = true;
|
|
160
|
+
persist = true;
|
|
161
|
+
}
|
|
162
|
+
if (event.type === "message_start" && event.message?.role === "assistant") {
|
|
163
|
+
streamText = "";
|
|
164
|
+
activity = { kind: "text", text: "" };
|
|
165
|
+
report = true;
|
|
166
|
+
}
|
|
167
|
+
if (event.type === "message_update") {
|
|
168
|
+
const updateType = event.assistantMessageEvent?.type;
|
|
169
|
+
if (updateType === "thinking_start" || updateType === "text_start")
|
|
170
|
+
streamText = "";
|
|
171
|
+
const delta = event.assistantMessageEvent?.delta;
|
|
172
|
+
if ((updateType === "thinking_delta" || updateType === "text_delta") && delta)
|
|
173
|
+
streamText = `${streamText}${delta}`.replace(/\s+/g, " ").slice(-MAX_ACTIVITY_TEXT_CHARS);
|
|
174
|
+
if (updateType && ["thinking_start", "thinking_delta", "thinking_end"].includes(updateType))
|
|
175
|
+
activity = { kind: "reasoning", text: streamText };
|
|
176
|
+
else if (updateType && ["text_start", "text_delta", "text_end", "toolcall_start", "toolcall_delta", "toolcall_end"].includes(updateType))
|
|
177
|
+
activity = { kind: "text", text: streamText };
|
|
178
|
+
report = previousActivity?.kind !== activity?.kind;
|
|
179
|
+
}
|
|
180
|
+
if (event.type === "message_end") {
|
|
181
|
+
streamText = "";
|
|
182
|
+
activity = undefined;
|
|
183
|
+
report = !sameActivity(previousActivity, activity);
|
|
184
|
+
if (event.message?.role === "assistant") {
|
|
185
|
+
persist = true;
|
|
186
|
+
report = true;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (event.type === "tool_execution_start" && event.toolCallId && event.toolName) {
|
|
190
|
+
toolCalls.set(event.toolCallId, { id: event.toolCallId, name: event.toolName, state: "running" });
|
|
191
|
+
toolCallsView = [...toolCalls.values()];
|
|
192
|
+
activity = { kind: "tool", text: event.toolName };
|
|
193
|
+
report = true;
|
|
194
|
+
}
|
|
195
|
+
if (event.type === "tool_execution_update" && event.toolName) {
|
|
196
|
+
activity = { kind: "tool", text: event.toolName };
|
|
197
|
+
report = !sameActivity(previousActivity, activity);
|
|
198
|
+
}
|
|
199
|
+
let removeToolCallId;
|
|
200
|
+
if (event.type === "tool_execution_end" && event.toolCallId && event.toolName) {
|
|
201
|
+
toolCalls.set(event.toolCallId, { id: event.toolCallId, name: event.toolName, state: event.isError ? "failed" : "completed" });
|
|
202
|
+
eventToolCalls = [...toolCalls.values()];
|
|
203
|
+
if (activity?.kind === "tool" && activity.text === event.toolName)
|
|
204
|
+
activity = undefined;
|
|
205
|
+
report = true;
|
|
206
|
+
removeToolCallId = event.toolCallId;
|
|
207
|
+
}
|
|
208
|
+
if (removeToolCallId === undefined)
|
|
209
|
+
eventToolCalls = toolCallsView;
|
|
210
|
+
if (!report && (lastReportedEventAt === undefined || eventAt - lastReportedEventAt >= 1000))
|
|
211
|
+
report = true;
|
|
212
|
+
const eventActivity = activity;
|
|
213
|
+
let materialized;
|
|
214
|
+
const result = { event, get progress() { return materialized ??= progressAt(persist, eventState, eventToolCalls, eventActivity, eventAt); }, report, persist };
|
|
215
|
+
if (report)
|
|
216
|
+
lastReportedEventAt = eventAt;
|
|
217
|
+
if (removeToolCallId !== undefined) {
|
|
218
|
+
toolCalls.delete(removeToolCallId);
|
|
219
|
+
toolCallsView = [...toolCalls.values()];
|
|
220
|
+
}
|
|
221
|
+
return result;
|
|
222
|
+
},
|
|
223
|
+
snapshot,
|
|
224
|
+
dispose() { disposed = true; toolCalls.clear(); toolCallsView = []; activity = undefined; },
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
function requiredUsage(value, name) {
|
|
228
|
+
if (value === undefined || !Number.isFinite(value))
|
|
229
|
+
throw new Error(`Pi runtime usage is missing ${name}`);
|
|
230
|
+
return value;
|
|
231
|
+
}
|
|
232
|
+
export function runtimeProgressToAgentProgress(value) {
|
|
233
|
+
if (value.usage.availability !== "complete")
|
|
234
|
+
throw new Error(`Cannot convert ${value.usage.availability} runtime usage to Pi accounting`);
|
|
235
|
+
return {
|
|
236
|
+
accounting: { input: requiredUsage(value.usage.input, "input"), output: requiredUsage(value.usage.output, "output"), cacheRead: requiredUsage(value.usage.cacheRead, "cacheRead"), cacheWrite: requiredUsage(value.usage.cacheWrite, "cacheWrite"), cost: requiredUsage(value.usage.costUsd, "costUsd") },
|
|
237
|
+
toolCalls: value.toolCalls.map(({ id, name, state }) => ({ id, name, state })),
|
|
238
|
+
...(value.state === undefined ? {} : { state: { model: { ...value.state.model }, ...(value.state.thinking === undefined ? {} : { thinking: value.state.thinking }), tools: [...value.state.tools], ...(value.state.systemPrompt === undefined ? {} : { systemPrompt: value.state.systemPrompt }) } }),
|
|
239
|
+
...(value.activity === undefined ? {} : { activity: { ...value.activity, text: sanitizeDisplayText(value.activity.text) } }),
|
|
240
|
+
...(value.lastEventAt === undefined ? {} : { lastEventAt: value.lastEventAt }),
|
|
241
|
+
persist: value.persist,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { RuntimeAgentRunRequest, RuntimeAgentRunResult, RuntimeAgentRunner, RuntimeTool } from "./runtime/agent-runner.js";
|
|
3
|
+
import { RuntimeAgentProviderError } from "./runtime/agent-runner.js";
|
|
4
|
+
import { WorkflowError, type AgentTransport, type AgentTransportContext, type LiveSessionHandoff, type PreparedAgentSession, type WorkflowAgentSession } from "./types.js";
|
|
5
|
+
type PiRuntimeAgentRunnerCallbacks = {
|
|
6
|
+
readonly onSession?: (session: WorkflowAgentSession, handoff: LiveSessionHandoff, prepared: Readonly<PreparedAgentSession>) => void | Promise<void>;
|
|
7
|
+
readonly onSessionReady?: () => void | Promise<void>;
|
|
8
|
+
readonly onBeforeComplete?: () => void | Promise<void>;
|
|
9
|
+
readonly onComplete?: (result: RuntimeAgentRunResult, session: WorkflowAgentSession) => void | Promise<void>;
|
|
10
|
+
readonly onFailure?: (error: WorkflowError, session: WorkflowAgentSession) => void | Promise<void>;
|
|
11
|
+
readonly onSystemPrompt?: (entry: {
|
|
12
|
+
readonly sessionId: string;
|
|
13
|
+
readonly turn: number;
|
|
14
|
+
readonly prompt: string;
|
|
15
|
+
}) => void | Promise<void>;
|
|
16
|
+
};
|
|
17
|
+
export interface PiRuntimeAgentRunnerOptions {
|
|
18
|
+
readonly transport: AgentTransport;
|
|
19
|
+
readonly prepared: Readonly<PreparedAgentSession>;
|
|
20
|
+
readonly context: Readonly<AgentTransportContext>;
|
|
21
|
+
readonly handoff: LiveSessionHandoff;
|
|
22
|
+
readonly callbacks?: PiRuntimeAgentRunnerCallbacks;
|
|
23
|
+
}
|
|
24
|
+
type PiToolContext = Parameters<ToolDefinition["execute"]>[4];
|
|
25
|
+
export declare function runtimeToolFromPiDefinition(definition: ToolDefinition, context: PiToolContext): RuntimeTool;
|
|
26
|
+
export declare function isRuntimeAgentProviderError(error: unknown): error is RuntimeAgentProviderError;
|
|
27
|
+
export declare function normalizePiRuntimeError(error: unknown, signal: AbortSignal, setupFailed?: boolean): WorkflowError;
|
|
28
|
+
export declare class PiRuntimeAgentRunner implements RuntimeAgentRunner {
|
|
29
|
+
#private;
|
|
30
|
+
readonly id = "pi";
|
|
31
|
+
readonly capabilities: {
|
|
32
|
+
customTools: boolean;
|
|
33
|
+
structuredResults: boolean;
|
|
34
|
+
steering: boolean;
|
|
35
|
+
handoff: boolean;
|
|
36
|
+
usage: "complete";
|
|
37
|
+
};
|
|
38
|
+
constructor(options: PiRuntimeAgentRunnerOptions);
|
|
39
|
+
run(request: Readonly<RuntimeAgentRunRequest>): Promise<RuntimeAgentRunResult>;
|
|
40
|
+
}
|
|
41
|
+
export declare function createPiRuntimeAgentRunner(options: PiRuntimeAgentRunnerOptions): RuntimeAgentRunner;
|
|
42
|
+
export type { PiRuntimeAgentRunnerCallbacks };
|