@marcoscale98/pi-extensible-workflows 5.17.0-fork.1 → 5.19.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 +68 -0
- package/dist/src/agent-execution.js +81 -39
- package/dist/src/background-widget.d.ts +5 -0
- package/dist/src/background-widget.js +1 -1
- package/dist/src/decoders.js +26 -0
- package/dist/src/execution.d.ts +4 -2
- package/dist/src/execution.js +43 -2
- package/dist/src/host-delivery.js +1 -0
- package/dist/src/host-recovery.d.ts +5 -2
- package/dist/src/host-recovery.js +3 -3
- package/dist/src/host-view.d.ts +5 -0
- package/dist/src/host-view.js +29 -5
- package/dist/src/host.d.ts +2 -2
- package/dist/src/host.js +190 -37
- package/dist/src/index.js +495 -93
- package/dist/src/index.js.map +3 -3
- package/dist/src/paths.d.ts +2 -0
- package/dist/src/paths.js +2 -0
- package/dist/src/registry.js +1 -1
- package/dist/src/roles.js +4 -3
- package/dist/src/script-tools.d.ts +27 -0
- package/dist/src/script-tools.js +87 -0
- package/dist/src/settings.d.ts +13 -0
- package/dist/src/settings.js +27 -3
- package/dist/src/trajectory.d.ts +12 -2
- package/dist/src/trajectory.js +30 -8
- package/dist/src/types.d.ts +30 -2
- package/dist/src/types.js +1 -1
- package/dist/src/utils.d.ts +19 -0
- package/dist/src/utils.js +30 -0
- package/dist/src/validation.d.ts +6 -1
- package/dist/src/validation.js +21 -1
- package/dist/starter/index.js +0 -2
- package/dist/starter/index.js.map +1 -1
- package/dist/starter/review-loop.d.ts +0 -13
- package/dist/starter/review-loop.js +0 -2
- package/dist/subagents/index.js +267 -159
- package/dist/subagents/index.js.map +2 -2
- package/dist/subagents/src/contracts.d.ts +45 -29
- package/dist/subagents/src/contracts.js +18 -7
- package/dist/subagents/src/index.d.ts +1 -1
- package/dist/subagents/src/index.js +13 -6
- package/dist/subagents/src/manager.js +3 -3
- package/dist/subagents/src/view.d.ts +1 -0
- package/dist/subagents/src/view.js +13 -52
- package/dist/trajectory/assets/index.html +27 -5
- package/dist/trajectory/index.js +76 -28
- package/dist/trajectory/index.js.map +2 -2
- package/dist/trajectory/src/assets/index.html +27 -5
- package/dist/trajectory/src/index.js +8 -18
- package/dist/trajectory/src/server.js +4 -2
- package/dist/trajectory/src/server.js.map +2 -2
- package/package.json +6 -6
- package/skills/pi-extensible-workflows/SKILL.md +2 -0
- package/src/agent-execution.ts +77 -41
- package/src/background-widget.ts +1 -1
- package/src/decoders.ts +20 -0
- package/src/execution.ts +41 -4
- package/src/host-delivery.ts +1 -0
- package/src/host-recovery.ts +8 -7
- package/src/host-view.ts +23 -5
- package/src/host.ts +173 -35
- package/src/paths.ts +3 -0
- package/src/registry.ts +1 -1
- package/src/roles.ts +4 -3
- package/src/script-tools.ts +76 -0
- package/src/settings.ts +22 -4
- package/src/trajectory.ts +30 -11
- package/src/types.ts +11 -4
- package/src/utils.ts +28 -0
- package/src/validation.ts +19 -1
- package/starter/review-loop.ts +0 -2
- package/subagents/README.md +2 -2
- package/subagents/src/contracts.ts +18 -7
- package/subagents/src/index.ts +16 -6
- package/subagents/src/manager.ts +3 -3
- package/subagents/src/view.ts +13 -50
- package/trajectory/src/assets/index.html +27 -5
- package/trajectory/src/index.ts +6 -9
- package/trajectory/src/server.ts +2 -2
package/dist/src/index.js
CHANGED
|
@@ -42,6 +42,7 @@ var ERROR_CODES = [
|
|
|
42
42
|
"AGENT_FAILED",
|
|
43
43
|
"AGENT_RESULT_COLLECTED",
|
|
44
44
|
"RESULT_INVALID",
|
|
45
|
+
"TOOL_FAILED",
|
|
45
46
|
"CANCELLED",
|
|
46
47
|
"WORKER_UNRESPONSIVE",
|
|
47
48
|
"WORKTREE_FAILED",
|
|
@@ -135,6 +136,7 @@ function createToolTimingExtension(clock = Date.now) {
|
|
|
135
136
|
}
|
|
136
137
|
|
|
137
138
|
// src/utils.ts
|
|
139
|
+
import { createHash } from "node:crypto";
|
|
138
140
|
import { Minimatch } from "minimatch";
|
|
139
141
|
var SerialLane = class {
|
|
140
142
|
#tail = Promise.resolve();
|
|
@@ -160,6 +162,14 @@ function isStringKey(key) {
|
|
|
160
162
|
function stringKeyValue(value, key) {
|
|
161
163
|
return object(value) ? value[key] : void 0;
|
|
162
164
|
}
|
|
165
|
+
function sortedJson(value) {
|
|
166
|
+
if (Array.isArray(value)) return value.map(sortedJson);
|
|
167
|
+
if (value === null || typeof value !== "object") return value;
|
|
168
|
+
return Object.fromEntries(Object.keys(value).sort().map((key) => [key, sortedJson(value[key])]));
|
|
169
|
+
}
|
|
170
|
+
function jsonDigest(value) {
|
|
171
|
+
return createHash("sha256").update(JSON.stringify(sortedJson(value))).digest("hex").slice(0, 16);
|
|
172
|
+
}
|
|
163
173
|
function jsonValue(value, seen = /* @__PURE__ */ new Set()) {
|
|
164
174
|
if (value === null || typeof value === "boolean" || typeof value === "string") return true;
|
|
165
175
|
if (typeof value === "number") return Number.isFinite(value);
|
|
@@ -320,6 +330,16 @@ function resolveModelReference(value, aliases = {}, knownModels, settingsPath) {
|
|
|
320
330
|
};
|
|
321
331
|
return resolveReference(value, []);
|
|
322
332
|
}
|
|
333
|
+
function reachableTools(pi) {
|
|
334
|
+
const undeclared = pi.getAllTools?.().filter(({ exposure }) => exposure === "codemode" || exposure === "deferred").map(({ name }) => name) ?? [];
|
|
335
|
+
return [.../* @__PURE__ */ new Set([...pi.getActiveTools(), ...undeclared])];
|
|
336
|
+
}
|
|
337
|
+
var VIRTUAL_MODEL_PROVIDER = "workflow";
|
|
338
|
+
function physicalModel(spec, aliases = {}, knownModels, settingsPath) {
|
|
339
|
+
if (spec.provider !== VIRTUAL_MODEL_PROVIDER || !modelAliasName(spec.model, aliases)) return spec;
|
|
340
|
+
const target = resolveModelReference(spec.model, aliases, knownModels, settingsPath);
|
|
341
|
+
return spec.thinking === void 0 ? target : { ...target, thinking: spec.thinking };
|
|
342
|
+
}
|
|
323
343
|
function modelCapability(value, aliases, knownModels, settingsPath) {
|
|
324
344
|
const parsed = typeof value === "string" ? resolveModelReference(value, aliases, knownModels, settingsPath) : value;
|
|
325
345
|
return `${parsed.provider}/${parsed.model}`;
|
|
@@ -378,7 +398,7 @@ function validateSchema(schema, at = "schema") {
|
|
|
378
398
|
}
|
|
379
399
|
|
|
380
400
|
// src/paths.ts
|
|
381
|
-
import { createHash } from "node:crypto";
|
|
401
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
382
402
|
import { realpathSync } from "node:fs";
|
|
383
403
|
import { readdir } from "node:fs/promises";
|
|
384
404
|
import { homedir } from "node:os";
|
|
@@ -394,6 +414,9 @@ function canonicalPath(path) {
|
|
|
394
414
|
return absolute;
|
|
395
415
|
}
|
|
396
416
|
}
|
|
417
|
+
function extensionIdentity(path) {
|
|
418
|
+
return path.startsWith("builtin:") ? path : canonicalPath(path);
|
|
419
|
+
}
|
|
397
420
|
function sameFilesystemPath(left, right) {
|
|
398
421
|
return canonicalPath(left) === canonicalPath(right);
|
|
399
422
|
}
|
|
@@ -403,7 +426,7 @@ function workflowProjectSettingsPath(cwd) {
|
|
|
403
426
|
function projectStorageKey(cwd) {
|
|
404
427
|
const exact = resolve(cwd);
|
|
405
428
|
const slug = safePart(basename(exact)) || "root";
|
|
406
|
-
return `${slug}-${
|
|
429
|
+
return `${slug}-${createHash2("sha256").update(exact).digest("hex").slice(0, 12)}`;
|
|
407
430
|
}
|
|
408
431
|
function projectSessionsDirectory(cwd, home = homedir()) {
|
|
409
432
|
return join(home, ".pi", "workflows", "projects", projectStorageKey(cwd), "sessions");
|
|
@@ -1201,6 +1224,22 @@ function decodeRunEvent(value) {
|
|
|
1201
1224
|
if (timestamp === INVALID_PERSISTED_VALUE) return void 0;
|
|
1202
1225
|
return { type: value.type, message: value.message, ...timestamp === void 0 ? {} : { timestamp } };
|
|
1203
1226
|
}
|
|
1227
|
+
function decodeScriptCall(value) {
|
|
1228
|
+
if (!object(value) || value.kind !== "shell" && value.kind !== "tool" || typeof value.name !== "string" || typeof value.path !== "string" || !finiteNumber(value.startedAt)) return void 0;
|
|
1229
|
+
const shell = value.kind === "shell";
|
|
1230
|
+
if (shell && !jsonValue(value.input)) return void 0;
|
|
1231
|
+
const inputBytes = shell ? optionalNumber(value.inputBytes) : void 0;
|
|
1232
|
+
const phase = optionalString(value.phase);
|
|
1233
|
+
const finishedAt = optionalNumber(value.finishedAt);
|
|
1234
|
+
let error;
|
|
1235
|
+
if (value.error !== void 0) {
|
|
1236
|
+
if (shell) error = decodeWorkflowError(value.error);
|
|
1237
|
+
else if (object(value.error) && typeof value.error.code === "string") error = { code: isWorkflowErrorCode(value.error.code) ? value.error.code : "INTERNAL_ERROR" };
|
|
1238
|
+
if (!error) return void 0;
|
|
1239
|
+
}
|
|
1240
|
+
if (inputBytes === INVALID_PERSISTED_VALUE || phase === INVALID_PERSISTED_VALUE || finishedAt === INVALID_PERSISTED_VALUE) return void 0;
|
|
1241
|
+
return { kind: value.kind, name: value.name, path: value.path, ...shell && jsonValue(value.input) ? { input: value.input } : {}, ...inputBytes === void 0 ? {} : { inputBytes }, ...phase === void 0 ? {} : { phase }, startedAt: value.startedAt, ...finishedAt === void 0 ? {} : { finishedAt }, ...error === void 0 ? {} : { error } };
|
|
1242
|
+
}
|
|
1204
1243
|
function decodeDelivery(value) {
|
|
1205
1244
|
if (!object(value)) return void 0;
|
|
1206
1245
|
const mode = value.mode;
|
|
@@ -1230,6 +1269,8 @@ function decodePersistedRun(value, allowLegacyAgentSessions = false) {
|
|
|
1230
1269
|
const budgetEvents = value.budgetEvents === void 0 ? void 0 : decodeArray(value.budgetEvents, decodeBudgetEvent);
|
|
1231
1270
|
const events = value.events === void 0 ? void 0 : decodeArray(value.events, decodeRunEvent);
|
|
1232
1271
|
const delivery = value.delivery === void 0 ? void 0 : decodeDelivery(value.delivery);
|
|
1272
|
+
const scriptCalls = value.scriptCalls === void 0 ? void 0 : decodeArray(value.scriptCalls, decodeScriptCall);
|
|
1273
|
+
if (value.scriptCalls !== void 0 && !scriptCalls) return void 0;
|
|
1233
1274
|
if (!agentSessions || !agents || parentRunId === INVALID_PERSISTED_VALUE || value.retry !== void 0 && !retry || phase === INVALID_PERSISTED_VALUE || value.phaseHistory !== void 0 && !phaseHistory || phaseHistoryIndex === INVALID_PERSISTED_VALUE || activeShells === INVALID_PERSISTED_VALUE || activeShellStartedAt === INVALID_PERSISTED_VALUE || value.activeShellsByPhase !== void 0 && !activeShellsByPhase || value.error !== void 0 && !error || failedAt === INVALID_PERSISTED_VALUE || value.budget !== void 0 && !budget || budgetVersion === INVALID_PERSISTED_VALUE || value.budgetVersion !== void 0 && !integer(budgetVersion) || value.usage !== void 0 && !usage || value.budgetEvents !== void 0 && !budgetEvents || value.events !== void 0 && !events || value.delivery !== void 0 && !delivery) return void 0;
|
|
1234
1275
|
if (value.agentSessions === void 0 && !allowLegacyAgentSessions) return void 0;
|
|
1235
1276
|
return {
|
|
@@ -1248,6 +1289,7 @@ function decodePersistedRun(value, allowLegacyAgentSessions = false) {
|
|
|
1248
1289
|
...activeShells === void 0 ? {} : { activeShells },
|
|
1249
1290
|
...activeShellStartedAt === void 0 ? {} : { activeShellStartedAt },
|
|
1250
1291
|
...activeShellsByPhase === void 0 ? {} : { activeShellsByPhase },
|
|
1292
|
+
...scriptCalls === void 0 ? {} : { scriptCalls },
|
|
1251
1293
|
...error === void 0 ? {} : { error },
|
|
1252
1294
|
...failedAt === void 0 ? {} : { failedAt },
|
|
1253
1295
|
...budget === void 0 ? {} : { budget },
|
|
@@ -1527,7 +1569,7 @@ async function listRunIds(cwd, sessionId, home = homedir2(), cleanTemps = true)
|
|
|
1527
1569
|
|
|
1528
1570
|
// src/store.ts
|
|
1529
1571
|
import { execFile as execFile2 } from "node:child_process";
|
|
1530
|
-
import { createHash as
|
|
1572
|
+
import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
|
|
1531
1573
|
import { access, mkdir as mkdir2, readdir as readdir3, readFile as readFile3, realpath, rename as rename3, rm as rm3, stat as stat2, writeFile as writeFile2 } from "node:fs/promises";
|
|
1532
1574
|
import { homedir as homedir3 } from "node:os";
|
|
1533
1575
|
import { dirname, join as join3, relative, resolve as resolve2, sep } from "node:path";
|
|
@@ -1725,7 +1767,7 @@ var RunStore = class _RunStore {
|
|
|
1725
1767
|
}
|
|
1726
1768
|
}
|
|
1727
1769
|
async appendSystemPromptV2(entry) {
|
|
1728
|
-
const sha256 =
|
|
1770
|
+
const sha256 = createHash3("sha256").update(entry.prompt).digest("hex");
|
|
1729
1771
|
const bodyPath = join3(systemPromptBodiesPath(this.directory), sha256);
|
|
1730
1772
|
try {
|
|
1731
1773
|
await access(bodyPath);
|
|
@@ -1778,7 +1820,7 @@ var RunStore = class _RunStore {
|
|
|
1778
1820
|
const sha256 = record3.sha256;
|
|
1779
1821
|
if (typeof sessionId !== "string" || !sessionId || !positiveInteger(attempt) || !positiveInteger(turn) || typeof sha256 !== "string" || !/^[0-9a-f]{64}$/.test(sha256)) throw new Error("Persisted system-prompt record is invalid");
|
|
1780
1822
|
const prompt = await readFile3(join3(systemPromptBodiesPath(this.directory), sha256), "utf8");
|
|
1781
|
-
if (
|
|
1823
|
+
if (createHash3("sha256").update(prompt).digest("hex") !== sha256) throw new Error("Persisted system-prompt body is invalid");
|
|
1782
1824
|
entries.push({ sessionId, attempt, turn, sha256, prompt });
|
|
1783
1825
|
}
|
|
1784
1826
|
if (sequence < highest) throw new Error("Persisted system-prompt sequence is invalid");
|
|
@@ -1920,7 +1962,7 @@ var RunStore = class _RunStore {
|
|
|
1920
1962
|
});
|
|
1921
1963
|
}
|
|
1922
1964
|
#worktreeKey(owner) {
|
|
1923
|
-
return
|
|
1965
|
+
return createHash3("sha256").update(`${this.sessionId}\0${this.runId}\0${owner}`).digest("hex").slice(0, 16);
|
|
1924
1966
|
}
|
|
1925
1967
|
expectedWorktree(owner) {
|
|
1926
1968
|
const key = this.#worktreeKey(owner);
|
|
@@ -2391,7 +2433,7 @@ function workflowSettingsPath(agentDir = getAgentDir()) {
|
|
|
2391
2433
|
return join4(agentDir, ROLE_DIRECTORY, "settings.json");
|
|
2392
2434
|
}
|
|
2393
2435
|
function normalizedResourcePath(value, settingsPath) {
|
|
2394
|
-
if (value === "*") return value;
|
|
2436
|
+
if (value === "*" || value.startsWith("builtin:")) return value;
|
|
2395
2437
|
let expanded = value === "~" ? homedir4() : value.startsWith("~/") || value.startsWith("~\\") ? join4(homedir4(), value.slice(2)) : value;
|
|
2396
2438
|
if (expanded.startsWith("file://")) expanded = fileURLToPath(expanded);
|
|
2397
2439
|
const resolved = resolve3(dirname2(settingsPath), expanded);
|
|
@@ -2503,7 +2545,7 @@ function parseSettings(path, partial) {
|
|
|
2503
2545
|
fail("CONFIG_ERROR", `Invalid workflow settings JSON at ${path}: ${errorText(error)}`);
|
|
2504
2546
|
}
|
|
2505
2547
|
if (!object(parsed)) fail("INVALID_SETTINGS", `Workflow settings at ${path} must be an object`);
|
|
2506
|
-
const allowed = /* @__PURE__ */ new Set(["concurrency", "modelAliases", "skills", "extensions", "extensionSettings", "tools", "retention", "worktreePostCreateCommand", ...partial ? [] : ["backgroundWidget"]]);
|
|
2548
|
+
const allowed = /* @__PURE__ */ new Set(["concurrency", "modelAliases", "skills", "extensions", "extensionSettings", "tools", "retention", "worktreePostCreateCommand", ...partial ? [] : ["backgroundWidget", "codemodeTools"]]);
|
|
2507
2549
|
const unknown = Object.keys(parsed).find((key) => !allowed.has(key));
|
|
2508
2550
|
if (Object.prototype.hasOwnProperty.call(parsed, "disabledAgentResources")) fail("INVALID_SETTINGS", `disabledAgentResources is no longer supported; use skills, extensions, and tools selectors (settings: ${path})`);
|
|
2509
2551
|
if (unknown) fail("INVALID_SETTINGS", `Unknown workflow setting at ${path}: ${unknown}`);
|
|
@@ -2511,6 +2553,8 @@ function parseSettings(path, partial) {
|
|
|
2511
2553
|
if (concurrency !== void 0 && (!positiveInteger(concurrency) || concurrency > 16)) fail("INVALID_SETTINGS", `${path}.concurrency must be an integer from 1 to 16`);
|
|
2512
2554
|
const backgroundWidget = parsed.backgroundWidget === void 0 ? partial ? void 0 : DEFAULT_SETTINGS.backgroundWidget : parsed.backgroundWidget;
|
|
2513
2555
|
if (backgroundWidget !== void 0 && typeof backgroundWidget !== "boolean") fail("INVALID_SETTINGS", `${path}.backgroundWidget must be a boolean`);
|
|
2556
|
+
const codemodeTools = parsed.codemodeTools;
|
|
2557
|
+
if (codemodeTools !== void 0 && codemodeTools !== "all" && codemodeTools !== "read-only" && codemodeTools !== "none") fail("INVALID_SETTINGS", `${path}.codemodeTools must be "all", "read-only", or "none"`);
|
|
2514
2558
|
const modelAliases = parsed.modelAliases === void 0 ? void 0 : validateModelAliases(parsed.modelAliases, path);
|
|
2515
2559
|
const skills = validateSelectorList(parsed.skills, path, "skills");
|
|
2516
2560
|
const tools = validateSelectorList(parsed.tools, path, "tools");
|
|
@@ -2521,6 +2565,7 @@ function parseSettings(path, partial) {
|
|
|
2521
2565
|
return Object.freeze({
|
|
2522
2566
|
...concurrency === void 0 ? {} : { concurrency },
|
|
2523
2567
|
...backgroundWidget === void 0 ? {} : { backgroundWidget },
|
|
2568
|
+
...codemodeTools === void 0 ? {} : { codemodeTools },
|
|
2524
2569
|
...modelAliases === void 0 ? {} : { modelAliases },
|
|
2525
2570
|
...skills === void 0 ? {} : { skills },
|
|
2526
2571
|
...extensions === void 0 ? {} : { extensions },
|
|
@@ -2533,6 +2578,18 @@ function parseSettings(path, partial) {
|
|
|
2533
2578
|
function loadSettings(path = workflowSettingsPath()) {
|
|
2534
2579
|
return parseSettings(path, false);
|
|
2535
2580
|
}
|
|
2581
|
+
var READ_ONLY_WORKFLOW_TOOLS = /* @__PURE__ */ new Set(["workflow_status", "workflow_catalog", "subagents_inspect"]);
|
|
2582
|
+
function workflowToolExposure(name, codemodeTools) {
|
|
2583
|
+
const readOnly = READ_ONLY_WORKFLOW_TOOLS.has(name);
|
|
2584
|
+
return { ...codemodeTools === "none" || codemodeTools === "read-only" && !readOnly ? { exposure: "model-only" } : {}, ...readOnly ? { annotations: { readOnlyHint: true } } : {} };
|
|
2585
|
+
}
|
|
2586
|
+
function loadCodemodeToolsSetting(agentDir) {
|
|
2587
|
+
try {
|
|
2588
|
+
return loadSettings(workflowSettingsPath(agentDir)).codemodeTools;
|
|
2589
|
+
} catch {
|
|
2590
|
+
return void 0;
|
|
2591
|
+
}
|
|
2592
|
+
}
|
|
2536
2593
|
function loadSettingsOverrides(path) {
|
|
2537
2594
|
return parseSettings(path, true);
|
|
2538
2595
|
}
|
|
@@ -2607,7 +2664,7 @@ function saveModelAliases(path = workflowSettingsPath(), aliases = {}) {
|
|
|
2607
2664
|
}
|
|
2608
2665
|
|
|
2609
2666
|
// src/registry.ts
|
|
2610
|
-
var RESERVED_GLOBALS = /* @__PURE__ */ new Set(["agent", "shell", "prompt", "checkpoint", "parallel", "pipeline", "phase", "withWorktree", "log", "args", "Promise", "JSON", "Math", "Date", "eval", "Function", "WebAssembly", "process", "require", "module", "exports", "console", "fetch", "XMLHttpRequest", "WebSocket", "performance", "crypto", "setTimeout", "setInterval", "setImmediate", "queueMicrotask", "Intl", "SharedArrayBuffer", "Atomics", "globalThis", "global", "undefined", "NaN", "Infinity", "extensions", "workflow_catalog"]);
|
|
2667
|
+
var RESERVED_GLOBALS = /* @__PURE__ */ new Set(["agent", "shell", "tools", "prompt", "checkpoint", "parallel", "pipeline", "phase", "withWorktree", "log", "args", "Promise", "JSON", "Math", "Date", "eval", "Function", "WebAssembly", "process", "require", "module", "exports", "console", "fetch", "XMLHttpRequest", "WebSocket", "performance", "crypto", "setTimeout", "setInterval", "setImmediate", "queueMicrotask", "Intl", "SharedArrayBuffer", "Atomics", "globalThis", "global", "undefined", "NaN", "Infinity", "extensions", "workflow_catalog"]);
|
|
2611
2668
|
var IDENTIFIER = /^[A-Za-z_$][\w$]*$/;
|
|
2612
2669
|
var SEMVER = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
2613
2670
|
var PACKAGE_NAME = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/;
|
|
@@ -3127,7 +3184,7 @@ function loadAgentDefinitions(cwd, agentDir = getAgentDir2(), projectTrusted2 =
|
|
|
3127
3184
|
function canonicalExtensionSelector(selector, base = process.cwd()) {
|
|
3128
3185
|
const negated = selector.startsWith("!");
|
|
3129
3186
|
const body = negated ? selector.slice(1) : selector;
|
|
3130
|
-
if (body === "*" || body === "**" || body.startsWith("**/")) return selector;
|
|
3187
|
+
if (body === "*" || body === "**" || body.startsWith("**/") || body.startsWith("builtin:")) return selector;
|
|
3131
3188
|
const resolved = resolve4(base, body);
|
|
3132
3189
|
if (resourcePatternHasMagic(body)) return `${negated ? "!" : ""}${resolved}`;
|
|
3133
3190
|
return `${negated ? "!" : ""}${canonicalPath(resolved)}`;
|
|
@@ -3188,7 +3245,7 @@ function resolveRole(name, options) {
|
|
|
3188
3245
|
if (outsideRootTool) fail("UNKNOWN_TOOL", `Tool is outside the launching session boundary: ${outsideRootTool}`);
|
|
3189
3246
|
}
|
|
3190
3247
|
const selectedSkills = resources.skills === void 0 ? void 0 : selectResourcesByLayers(selectorLayers.skills, resources.skills);
|
|
3191
|
-
const extensionResources = resources.extensions?.map((extension) =>
|
|
3248
|
+
const extensionResources = resources.extensions?.map((extension) => extensionIdentity(extension));
|
|
3192
3249
|
const selectedExtensions = extensionResources === void 0 ? void 0 : selectResourcesByLayers(selectorLayers.extensions, extensionResources);
|
|
3193
3250
|
const unmatchedSkills = resources.skills === void 0 ? void 0 : unmatchedResourcePatterns(selectorLayers.skills.flatMap((layer) => layer ?? []), resources.skills);
|
|
3194
3251
|
const unmatchedExtensions = extensionResources === void 0 ? void 0 : unmatchedResourcePatterns(selectorLayers.extensions.flatMap((layer) => layer ?? []), extensionResources);
|
|
@@ -3408,6 +3465,19 @@ function callHasTrailingComma(source, call) {
|
|
|
3408
3465
|
}
|
|
3409
3466
|
return current?.type.label === ")" && previous?.type.label === ",";
|
|
3410
3467
|
}
|
|
3468
|
+
function scriptToolReferences(script) {
|
|
3469
|
+
const body = workflowBody(script);
|
|
3470
|
+
if (!body.trim()) return [];
|
|
3471
|
+
const names = /* @__PURE__ */ new Set();
|
|
3472
|
+
const opaque = (node, parent) => {
|
|
3473
|
+
if (node.type === "Identifier" && node.name === "tools") {
|
|
3474
|
+
if (parent?.type === "MemberExpression" && parent.object === node && !parent.computed && parent.property.type === "Identifier") names.add(parent.property.name);
|
|
3475
|
+
else if (!(parent?.type === "Property" && parent.key === node && !parent.computed && !parent.shorthand || parent?.type === "MemberExpression" && parent.property === node && !parent.computed)) return true;
|
|
3476
|
+
}
|
|
3477
|
+
return astChildren(node).some((child) => opaque(child, node));
|
|
3478
|
+
};
|
|
3479
|
+
return opaque(parseWorkflow(body)) ? void 0 : [...names];
|
|
3480
|
+
}
|
|
3411
3481
|
function instrumentWorkflow(script) {
|
|
3412
3482
|
const body = workflowBody(script);
|
|
3413
3483
|
if (!body.trim()) return body;
|
|
@@ -4013,6 +4083,30 @@ const functions = Object.freeze(Object.fromEntries(Object.entries(config.functio
|
|
|
4013
4083
|
Object.defineProperty(result, "toJSON", { value() { throw workError("INVALID_METADATA", "Workflow function result is a Promise; await it before serialization"); } });
|
|
4014
4084
|
return result;
|
|
4015
4085
|
}])));
|
|
4086
|
+
// tools.<id>(args) runs a Pi session tool through the host. Any identifier resolves, so a resumed run
|
|
4087
|
+
// replays journaled calls even when the tool is gone; the host rejects identifiers it cannot call.
|
|
4088
|
+
// A call is the n-th call with the same arguments in its scope, so replay does not depend on the
|
|
4089
|
+
// order in which concurrent calls start.
|
|
4090
|
+
const NOT_TOOLS = new Set(["then", "toJSON", "toString", "valueOf", "constructor"]);
|
|
4091
|
+
const sortedJson = value => Array.isArray(value) ? value.map(sortedJson) : value && typeof value === "object" ? Object.fromEntries(Object.keys(value).sort().map(key => [key, sortedJson(value[key])])) : value;
|
|
4092
|
+
const toolOccurrences = new Map();
|
|
4093
|
+
const toolCall = id => (...values) => {
|
|
4094
|
+
if (worktreeOwners.getStore()) throw workError("INVALID_METADATA", "tools." + id + " is unavailable inside withWorktree: session tools resolve paths against the session working directory");
|
|
4095
|
+
if (values.length > 1 || values[0] !== undefined && (!values[0] || typeof values[0] !== "object" || Array.isArray(values[0]))) throw workError("INVALID_METADATA", "tools." + id + " takes one arguments object");
|
|
4096
|
+
const args = values[0] === undefined ? {} : values[0];
|
|
4097
|
+
const structuralPath = inheritedAgentPath.getStore() || [];
|
|
4098
|
+
const key = JSON.stringify([structuralPath, id, sortedJson(args)]);
|
|
4099
|
+
const occurrence = (toolOccurrences.get(key) || 0) + 1;
|
|
4100
|
+
toolOccurrences.set(key, occurrence);
|
|
4101
|
+
return guardedResult(rpc("tool", [id, args, { structuralPath: [...structuralPath], occurrence }]), "tool");
|
|
4102
|
+
};
|
|
4103
|
+
const tools = new Proxy(Object.create(null), {
|
|
4104
|
+
get: (_target, key) => typeof key === "string" && !NOT_TOOLS.has(key) ? toolCall(key) : undefined,
|
|
4105
|
+
// Probing would branch on the session that resumed the run; the launch already checks named tools.
|
|
4106
|
+
has: () => { throw workError("INVALID_METADATA", "Workflow scripts cannot probe tools with 'in'; call tools.<name>(...) directly, and the launch checks that the tool exists"); },
|
|
4107
|
+
set: () => false,
|
|
4108
|
+
defineProperty: () => false,
|
|
4109
|
+
});
|
|
4016
4110
|
const recordEntries = (value, kind) => {
|
|
4017
4111
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw workError("INVALID_METADATA", kind + " must be a record");
|
|
4018
4112
|
return Object.entries(value);
|
|
@@ -4073,7 +4167,7 @@ const pipeline = async (operationName, items, stages) => {
|
|
|
4073
4167
|
return Object.fromEntries(results.map(result => [result.name, result.value]));
|
|
4074
4168
|
};
|
|
4075
4169
|
const safeMath = Object.fromEntries(Object.getOwnPropertyNames(Math).filter(name => name !== "random").map(name => [name, Math[name]]));
|
|
4076
|
-
const sandbox = { agent, shell, withWorktree: rejectWorktree, prompt, checkpoint, parallel, pipeline, phase, log, args: config.args, Promise, JSON, Math: Object.freeze(safeMath) };
|
|
4170
|
+
const sandbox = { agent, shell, withWorktree: rejectWorktree, prompt, checkpoint, parallel, pipeline, phase, log, tools, args: config.args, Promise, JSON, Math: Object.freeze(safeMath) };
|
|
4077
4171
|
for (const [name, fn] of Object.entries(functions)) Object.defineProperty(sandbox, name, { value: fn, writable: false, configurable: false });
|
|
4078
4172
|
for (const name of ["Date","eval","Function","WebAssembly","process","require","module","exports","console","fetch","XMLHttpRequest","WebSocket","performance","crypto","setTimeout","setInterval","setImmediate","queueMicrotask","Intl","SharedArrayBuffer","Atomics"]) sandbox[name] = undefined;
|
|
4079
4173
|
const context = vm.createContext(sandbox, { codeGeneration: { strings: false, wasm: false } });
|
|
@@ -4117,6 +4211,13 @@ function readShellIdentity(value) {
|
|
|
4117
4211
|
const identity = readAgentIdentity(value);
|
|
4118
4212
|
return { structuralPath: identity.structuralPath, callSite: identity.callSite, occurrence: identity.occurrence, ...identity.worktreeOwner ? { worktreeOwner: identity.worktreeOwner } : {} };
|
|
4119
4213
|
}
|
|
4214
|
+
function readToolIdentity(value) {
|
|
4215
|
+
if (!object(value) || !Array.isArray(value.structuralPath) || !value.structuralPath.every((part) => typeof part === "string" && Boolean(part.trim())) || !positiveInteger(value.occurrence)) fail("INTERNAL_ERROR", "Invalid workflow tool identity");
|
|
4216
|
+
return { structuralPath: [...value.structuralPath], occurrence: value.occurrence };
|
|
4217
|
+
}
|
|
4218
|
+
function toolIdentityPath(identifier, args, identity) {
|
|
4219
|
+
return structuralPath("tool", ...identity.structuralPath, identifier, `args:${jsonDigest(args)}`, String(identity.occurrence));
|
|
4220
|
+
}
|
|
4120
4221
|
function agentHandleTurnPath(handle, turn) {
|
|
4121
4222
|
return structuralPath("agent", "handle", handle, `turn:${String(turn)}`);
|
|
4122
4223
|
}
|
|
@@ -4409,6 +4510,11 @@ function runWorkflow(script, args = null, bridge = {}, signal) {
|
|
|
4409
4510
|
if (!OUTCOME_ERRORS.has(typed.code)) throw typed;
|
|
4410
4511
|
value = branded({ name, ok: false, failedAt: name, error: workerErrorShape(typed) });
|
|
4411
4512
|
}
|
|
4513
|
+
} else if (method === "tool") {
|
|
4514
|
+
if (typeof values[0] !== "string" || !object(values[1])) fail("INTERNAL_ERROR", "tool requires an identifier and object arguments");
|
|
4515
|
+
const identity = readToolIdentity(values[2]);
|
|
4516
|
+
if (!bridge.tool) fail("UNKNOWN_TOOL", `tools.${values[0]} is unavailable: this run has no session tools`);
|
|
4517
|
+
value = await bridge.tool(values[0], values[1], controller.signal, identity);
|
|
4412
4518
|
} else if (method === "worktree") {
|
|
4413
4519
|
if (!bridge.worktree || typeof values[0] !== "string" || !values[0]) fail("INTERNAL_ERROR", "worktree requires an active host bridge and scope");
|
|
4414
4520
|
value = await bridge.worktree(values[0], controller.signal);
|
|
@@ -4480,7 +4586,7 @@ import { basename as basename4, dirname as dirname5, join as join8, resolve as r
|
|
|
4480
4586
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
4481
4587
|
import { Type } from "@earendil-works/pi-ai";
|
|
4482
4588
|
import { Compile } from "typebox/compile";
|
|
4483
|
-
import { createAgentSession, DefaultPackageManager, DefaultResourceLoader, defineTool, getAgentDir as getAgentDir3, ModelRuntime, SessionManager, SettingsManager } from "@earendil-works/pi-coding-agent";
|
|
4589
|
+
import { createAgentSession, createCodemodeExtension, createMcpExtension, createToolSearchExtension, DefaultPackageManager, DefaultResourceLoader, defineTool, getAgentDir as getAgentDir3, ModelRuntime, SessionManager, SettingsManager } from "@earendil-works/pi-coding-agent";
|
|
4484
4590
|
|
|
4485
4591
|
// src/pi-runtime-adapter.ts
|
|
4486
4592
|
var TURN_START_EVENTS = /* @__PURE__ */ new Set(["turn_start", "turn_started", "turnStarted"]);
|
|
@@ -5319,16 +5425,25 @@ function parseModel(value, fallback, aliases = {}, knownModels, settingsPath) {
|
|
|
5319
5425
|
function accounting(stats) {
|
|
5320
5426
|
return { input: stats.tokens.input, output: stats.tokens.output, cacheRead: stats.tokens.cacheRead, cacheWrite: stats.tokens.cacheWrite, cost: stats.cost };
|
|
5321
5427
|
}
|
|
5322
|
-
var
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5428
|
+
var WORKFLOW_HOST_ENTRY_PATHS = ["src/index.ts", "dist/src/index.js", "starter/index.ts", "dist/starter/index.js", "subagents/index.ts", "dist/subagents/index.js"];
|
|
5429
|
+
function isWorkflowHostEntry(path) {
|
|
5430
|
+
const entryPath = canonicalPath(path);
|
|
5431
|
+
let packageRoot2 = dirname5(entryPath);
|
|
5432
|
+
while (packageRoot2 !== dirname5(packageRoot2)) {
|
|
5433
|
+
const packageMetadataPath = join8(packageRoot2, "package.json");
|
|
5434
|
+
if (existsSync(packageMetadataPath)) {
|
|
5435
|
+
try {
|
|
5436
|
+
const metadata = JSON.parse(readFileSync5(packageMetadataPath, "utf8"));
|
|
5437
|
+
if (typeof metadata !== "object" || metadata === null || !("name" in metadata) || !isCorePackageName(metadata.name)) return false;
|
|
5438
|
+
return WORKFLOW_HOST_ENTRY_PATHS.some((entry) => canonicalPath(join8(packageRoot2, entry)) === entryPath);
|
|
5439
|
+
} catch {
|
|
5440
|
+
return false;
|
|
5441
|
+
}
|
|
5442
|
+
}
|
|
5443
|
+
packageRoot2 = dirname5(packageRoot2);
|
|
5444
|
+
}
|
|
5445
|
+
return false;
|
|
5446
|
+
}
|
|
5332
5447
|
var WORKFLOW_DIRECTORY = "pi-extensible-workflows";
|
|
5333
5448
|
function workflowSystemPromptPath(cwd, agentDir, projectTrusted2) {
|
|
5334
5449
|
const projectPath = join8(cwd, ".pi", WORKFLOW_DIRECTORY, "SYSTEM.md");
|
|
@@ -5361,33 +5476,40 @@ function loadPiPackageDirectory() {
|
|
|
5361
5476
|
}
|
|
5362
5477
|
}).catch((error) => ({ error: `could not load @earendil-works/pi-coding-agent package metadata: ${errorText(error)}` }));
|
|
5363
5478
|
}
|
|
5364
|
-
var
|
|
5365
|
-
async function
|
|
5479
|
+
var nativeCoreModules = /* @__PURE__ */ new Map();
|
|
5480
|
+
async function loadNativeCoreModule(file, label) {
|
|
5366
5481
|
const packageDirectory = await loadPiPackageDirectory();
|
|
5367
|
-
let
|
|
5482
|
+
let modulePath;
|
|
5368
5483
|
if (packageDirectory.directory) {
|
|
5369
|
-
const candidate = resolve6(packageDirectory.directory, "dist/core
|
|
5370
|
-
if (existsSync(candidate))
|
|
5484
|
+
const candidate = resolve6(packageDirectory.directory, "dist/core", file);
|
|
5485
|
+
if (existsSync(candidate)) modulePath = candidate;
|
|
5371
5486
|
}
|
|
5372
|
-
|
|
5487
|
+
modulePath ??= resolve6(dirname5(fileURLToPath3(import.meta.resolve("@earendil-works/pi-coding-agent"))), "core", file);
|
|
5373
5488
|
const packageDirectoryError = packageDirectory.error ? ` Package directory lookup failed: ${packageDirectory.error}` : "";
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5489
|
+
let loaded = nativeCoreModules.get(file);
|
|
5490
|
+
if (!loaded) {
|
|
5491
|
+
loaded = import(modulePath).catch((error) => {
|
|
5492
|
+
throw new Error(`Could not load Pi ${label}.${packageDirectoryError}`, { cause: error });
|
|
5493
|
+
});
|
|
5494
|
+
nativeCoreModules.set(file, loaded);
|
|
5495
|
+
}
|
|
5496
|
+
return loaded;
|
|
5377
5497
|
}
|
|
5378
5498
|
async function expandPromptTemplateForInspection(text, templates) {
|
|
5379
|
-
return (await
|
|
5499
|
+
return (await loadNativeCoreModule("prompt-templates.js", "prompt templates")).expandPromptTemplate(text, templates);
|
|
5500
|
+
}
|
|
5501
|
+
async function buildSystemPromptForInspection(options) {
|
|
5502
|
+
return (await loadNativeCoreModule("system-prompt.js", "system prompt builder")).buildSystemPrompt(options);
|
|
5380
5503
|
}
|
|
5381
5504
|
async function preparePiPrompt(native, text) {
|
|
5382
5505
|
const session = native;
|
|
5383
5506
|
const diagnostics = [];
|
|
5384
5507
|
const runner = session._extensionRunner;
|
|
5385
|
-
const baseSystemPrompt =
|
|
5508
|
+
const baseSystemPrompt = session.systemPrompt ?? "";
|
|
5386
5509
|
const baseOptions = session._baseSystemPromptOptions;
|
|
5387
5510
|
const expandSkillCommand = session._expandSkillCommand;
|
|
5388
5511
|
const templates = session.promptTemplates;
|
|
5389
5512
|
if (!runner) diagnostics.push({ type: "error", message: "Pi prompt inspection seam is unavailable: extension runner is missing", source: "Pi session" });
|
|
5390
|
-
if (typeof session._baseSystemPrompt !== "string") diagnostics.push({ type: "error", message: "Pi prompt inspection seam is unavailable: base system prompt is missing", source: "Pi session" });
|
|
5391
5513
|
if (baseOptions === void 0) diagnostics.push({ type: "error", message: "Pi prompt inspection seam is unavailable: base system prompt options are missing", source: "Pi session" });
|
|
5392
5514
|
if (typeof expandSkillCommand !== "function") diagnostics.push({ type: "error", message: "Pi prompt inspection seam is unavailable: skill expansion is missing", source: "Pi session" });
|
|
5393
5515
|
if (!Array.isArray(templates)) diagnostics.push({ type: "error", message: "Pi prompt inspection seam is unavailable: prompt templates are missing", source: "Pi session" });
|
|
@@ -5412,9 +5534,11 @@ async function preparePiPrompt(native, text) {
|
|
|
5412
5534
|
diagnostics.push({ type: "error", message: `Pi prompt template expansion is unavailable: ${errorText(error)}`, source: "Pi session" });
|
|
5413
5535
|
}
|
|
5414
5536
|
}
|
|
5415
|
-
const result = !inputHandled && runner && baseOptions !== void 0 ? await runner.emitBeforeAgentStart(expandedPrompt, void 0,
|
|
5537
|
+
const result = !inputHandled && runner && baseOptions !== void 0 ? await runner.emitBeforeAgentStart(expandedPrompt, void 0, baseOptions) : void 0;
|
|
5416
5538
|
const prepared = result;
|
|
5417
|
-
|
|
5539
|
+
const systemPromptOptions = prepared?.systemPromptOptions ?? baseOptions;
|
|
5540
|
+
const systemPrompt = prepared?.systemPromptOptions === void 0 ? baseSystemPrompt : await buildSystemPromptForInspection(prepared.systemPromptOptions);
|
|
5541
|
+
return { prompt: text, expandedPrompt, systemPrompt, systemPromptOptions, messages: prepared?.messages ?? [], inputHandled, diagnostics };
|
|
5418
5542
|
} finally {
|
|
5419
5543
|
unsubscribe?.();
|
|
5420
5544
|
}
|
|
@@ -5443,6 +5567,17 @@ function flushExtensionProviders(resourceLoader, modelRuntime) {
|
|
|
5443
5567
|
runtime.pendingNativeProviderRegistrations = [];
|
|
5444
5568
|
return failures;
|
|
5445
5569
|
}
|
|
5570
|
+
function builtinExtensions() {
|
|
5571
|
+
return [
|
|
5572
|
+
{ name: "codemode", factory: createCodemodeExtension(), replaceable: true, builtin: true },
|
|
5573
|
+
{ name: "tool-search", factory: createToolSearchExtension(), replaceable: true, builtin: true },
|
|
5574
|
+
{ name: "mcp", factory: createMcpExtension(), replaceable: true, builtin: true }
|
|
5575
|
+
];
|
|
5576
|
+
}
|
|
5577
|
+
var BUILTIN_EXTENSION_PREFIX = "builtin:";
|
|
5578
|
+
function isLlamaModel(model) {
|
|
5579
|
+
return model.provider === "llama.cpp";
|
|
5580
|
+
}
|
|
5446
5581
|
async function createLocalPiSessionHandle(input, sessionStartEvent) {
|
|
5447
5582
|
const agentDir = input.agentDir ?? getAgentDir3();
|
|
5448
5583
|
const systemPromptSource = workflowSystemPromptPath(input.cwd, agentDir, input.resourcePolicy?.projectTrusted ?? true);
|
|
@@ -5455,13 +5590,16 @@ async function createLocalPiSessionHandle(input, sessionStartEvent) {
|
|
|
5455
5590
|
const tools = [.../* @__PURE__ */ new Set([...input.tools, ...customTools.map(({ name }) => name)])];
|
|
5456
5591
|
let settingsManager;
|
|
5457
5592
|
let resourceLoader;
|
|
5593
|
+
const builtins = builtinExtensions();
|
|
5594
|
+
const builtinNames = builtins.flatMap((extension) => typeof extension === "function" ? [] : [extension.name]);
|
|
5595
|
+
const extensionFactories = [...builtins, ...input.extensionFactories ?? []];
|
|
5458
5596
|
const policy = input.resourcePolicy;
|
|
5459
5597
|
if (policy) {
|
|
5460
5598
|
settingsManager = SettingsManager.create(input.cwd, agentDir, { projectTrusted: false });
|
|
5461
5599
|
settingsManager.setProjectTrusted(policy.projectTrusted);
|
|
5462
|
-
const packageManager = new DefaultPackageManager({ cwd: input.cwd, agentDir, settingsManager });
|
|
5600
|
+
const packageManager = new DefaultPackageManager({ cwd: input.cwd, agentDir, settingsManager, builtinExtensions: builtinNames });
|
|
5463
5601
|
const resolved = await packageManager.resolve();
|
|
5464
|
-
const discoveredExtensions = [...new Set(resolved.extensions.filter(({ enabled, metadata }) => enabled && (policy.projectTrusted || metadata.scope !== "project")).map(({ path }) =>
|
|
5602
|
+
const discoveredExtensions = [...new Set(resolved.extensions.filter(({ enabled, metadata }) => enabled && (policy.projectTrusted || metadata.scope !== "project")).map(({ path }) => extensionIdentity(path)))];
|
|
5465
5603
|
const selectorSources = policy.selectorSources;
|
|
5466
5604
|
const selection = resolveRole(void 0, {
|
|
5467
5605
|
cwd: input.cwd,
|
|
@@ -5469,7 +5607,7 @@ async function createLocalPiSessionHandle(input, sessionStartEvent) {
|
|
|
5469
5607
|
resources: { extensions: discoveredExtensions }
|
|
5470
5608
|
});
|
|
5471
5609
|
const selectedExtensions = selection.selectedExtensions ?? [];
|
|
5472
|
-
const extensionPaths = selectedExtensions.filter((path) =>
|
|
5610
|
+
const extensionPaths = selectedExtensions.filter((path) => path.startsWith(BUILTIN_EXTENSION_PREFIX) || !isWorkflowHostEntry(path));
|
|
5473
5611
|
policy.selectedExtensions = selectedExtensions;
|
|
5474
5612
|
policy.unmatchedExtensions = selection.unmatchedExtensions ?? [];
|
|
5475
5613
|
const skillPaths = [...new Set(resolved.skills.filter(({ enabled, metadata }) => enabled && (policy.projectTrusted || metadata.scope !== "project")).map(({ path }) => path))];
|
|
@@ -5489,7 +5627,7 @@ async function createLocalPiSessionHandle(input, sessionStartEvent) {
|
|
|
5489
5627
|
additionalExtensionPaths: extensionPaths,
|
|
5490
5628
|
noSkills: true,
|
|
5491
5629
|
additionalSkillPaths: [.../* @__PURE__ */ new Set([...skillPaths, ...input.additionalSkillPaths ?? []])],
|
|
5492
|
-
|
|
5630
|
+
extensionFactories,
|
|
5493
5631
|
...contextFilesOverride ? { agentsFilesOverride: contextFilesOverride } : {},
|
|
5494
5632
|
skillsOverride: (base) => {
|
|
5495
5633
|
const disabledSkills = updateSkillMatches(base.skills);
|
|
@@ -5501,17 +5639,17 @@ async function createLocalPiSessionHandle(input, sessionStartEvent) {
|
|
|
5501
5639
|
await resourceLoader.reload();
|
|
5502
5640
|
} else {
|
|
5503
5641
|
settingsManager = SettingsManager.create(input.cwd, agentDir, { projectTrusted: true });
|
|
5504
|
-
const packageManager = new DefaultPackageManager({ cwd: input.cwd, agentDir, settingsManager });
|
|
5642
|
+
const packageManager = new DefaultPackageManager({ cwd: input.cwd, agentDir, settingsManager, builtinExtensions: builtinNames });
|
|
5505
5643
|
const resolved = await packageManager.resolve();
|
|
5506
|
-
const extensionPaths = [...new Set(resolved.extensions.filter(({ enabled }) => enabled).map(({ path }) =>
|
|
5507
|
-
resourceLoader = new DefaultResourceLoader({ cwd: input.cwd, agentDir, settingsManager, noExtensions: true, additionalExtensionPaths: extensionPaths, ...input.additionalSkillPaths?.length ? { additionalSkillPaths: [...input.additionalSkillPaths] } : {},
|
|
5644
|
+
const extensionPaths = [...new Set(resolved.extensions.filter(({ enabled }) => enabled).map(({ path }) => extensionIdentity(path)).filter((path) => path.startsWith(BUILTIN_EXTENSION_PREFIX) || !isWorkflowHostEntry(path)))];
|
|
5645
|
+
resourceLoader = new DefaultResourceLoader({ cwd: input.cwd, agentDir, settingsManager, noExtensions: true, additionalExtensionPaths: extensionPaths, ...input.additionalSkillPaths?.length ? { additionalSkillPaths: [...input.additionalSkillPaths] } : {}, extensionFactories, ...contextFilesOverride ? { agentsFilesOverride: contextFilesOverride } : {}, ...systemPromptOptions, ...input.systemPromptAppend ? { appendSystemPromptOverride: (base) => [...base, input.systemPromptAppend ?? ""] } : {} });
|
|
5508
5646
|
await resourceLoader.reload();
|
|
5509
5647
|
}
|
|
5510
5648
|
const providerFailures = flushExtensionProviders(resourceLoader, modelRuntime);
|
|
5511
5649
|
await modelRuntime.refresh({ allowNetwork: false });
|
|
5512
5650
|
const model = modelRuntime.getModel(input.model.provider, input.model.model);
|
|
5513
5651
|
if (!model) {
|
|
5514
|
-
const because = providerFailures.length > 0 ? ` (provider registration failed \u2014 ${providerFailures.join("; ")})` : "";
|
|
5652
|
+
const because = providerFailures.length > 0 ? ` (provider registration failed \u2014 ${providerFailures.join("; ")})` : isLlamaModel(input.model) ? " (Pi does not expose its built-in llama.cpp provider to extension sessions; declare the llama.cpp server as a provider in models.json and use that model instead)" : "";
|
|
5515
5653
|
throw new WorkflowError("UNKNOWN_MODEL", `Unknown model: ${input.model.provider}/${input.model.model}${because}`);
|
|
5516
5654
|
}
|
|
5517
5655
|
const effectiveSessionStartEvent = input.settings === void 0 && sessionStartEvent === void 0 ? void 0 : { ...sessionStartEvent ?? { type: "session_start", reason: "startup" }, settings: input.settings ?? Object.freeze({}) };
|
|
@@ -5536,13 +5674,13 @@ async function createLocalPiSessionHandle(input, sessionStartEvent) {
|
|
|
5536
5674
|
await shutdown("quit").catch(() => void 0);
|
|
5537
5675
|
throw error;
|
|
5538
5676
|
}
|
|
5539
|
-
const resourcePaths = { extensions: resourceLoader.getExtensions().extensions.filter(({ path }) => !path.startsWith("<")).map(({ resolvedPath }) =>
|
|
5677
|
+
const resourcePaths = { extensions: resourceLoader.getExtensions().extensions.filter(({ path }) => !path.startsWith("<")).map(({ resolvedPath }) => extensionIdentity(resolvedPath)), skills: resourceLoader.getSkills().skills.map(({ filePath }) => canonicalPath(filePath)) };
|
|
5540
5678
|
const resourceInspection = () => {
|
|
5541
5679
|
const extensions = resourceLoader.getExtensions();
|
|
5542
5680
|
const skills = resourceLoader.getSkills();
|
|
5543
5681
|
const diagnostics = [...extensions.errors.map(({ path, error }) => ({ type: "error", message: error, source: path })), ...skills.diagnostics.map(({ type, path, message }) => ({ type, message, ...path ? { source: path } : {} }))];
|
|
5544
5682
|
const systemSource = systemPromptSource;
|
|
5545
|
-
return { extensions: resourceLoader.getExtensions().extensions.filter(({ path }) => !path.startsWith("<")).map(({ resolvedPath }) =>
|
|
5683
|
+
return { extensions: resourceLoader.getExtensions().extensions.filter(({ path }) => !path.startsWith("<")).map(({ resolvedPath }) => extensionIdentity(resolvedPath)), skills: skills.skills.map(({ name }) => name), diagnostics, ...systemSource ? { systemPromptSource: systemSource } : resourceLoader.getSystemPrompt() !== void 0 ? { systemPromptSource: "Pi resource loader" } : {} };
|
|
5546
5684
|
};
|
|
5547
5685
|
const managedSession = Object.assign(session, {
|
|
5548
5686
|
getLeafId: () => manager.getLeafId(),
|
|
@@ -6204,7 +6342,7 @@ var WorkflowAgentExecutor = class {
|
|
|
6204
6342
|
...options.contextFiles === void 0 ? {} : { contextFiles: options.contextFiles },
|
|
6205
6343
|
...options.effectiveTools === void 0 ? {} : { effectiveTools: options.effectiveTools }
|
|
6206
6344
|
});
|
|
6207
|
-
return { model: resolved.model ?? this.root.model, ...resolved.requestedModel === void 0 ? {} : { requestedModel: resolved.requestedModel }, tools: resolved.tools ?? [], ...resolved.overrideSystemPrompt ? { systemPrompt: resolved.prompt } : {}, systemPromptAppend: resolved.overrideSystemPrompt ? "" : resolved.prompt, ...resolved.contextFiles === void 0 ? {} : { contextFiles: resolved.contextFiles } };
|
|
6345
|
+
return { model: physicalModel(resolved.model ?? this.root.model, this.root.modelAliases, this.root.knownModels, this.root.settingsPath), ...resolved.requestedModel === void 0 ? {} : { requestedModel: resolved.requestedModel }, tools: resolved.tools ?? [], ...resolved.overrideSystemPrompt ? { systemPrompt: resolved.prompt } : {}, systemPromptAppend: resolved.overrideSystemPrompt ? "" : resolved.prompt, ...resolved.contextFiles === void 0 ? {} : { contextFiles: resolved.contextFiles } };
|
|
6208
6346
|
}
|
|
6209
6347
|
async execute(task, options, signal, customTools = [], setSteer, beforeRetry) {
|
|
6210
6348
|
const executionSignal = signal ?? this.root.runContext?.signal;
|
|
@@ -6633,6 +6771,7 @@ var FairAgentScheduler = class {
|
|
|
6633
6771
|
label: "Child Agent",
|
|
6634
6772
|
description: "Start a direct child agent",
|
|
6635
6773
|
parameters: Type.Object({ prompt: Type.String(), label: Type.String(), tools: Type.Optional(Type.Array(Type.String())), skills: Type.Optional(Type.Array(Type.String())), extensions: Type.Optional(Type.Array(Type.String())), model: Type.Optional(Type.String()), role: Type.Optional(Type.String()), contextFiles: Type.Optional(Type.Array(Type.String())), outputSchema: Type.Optional(Type.Record(Type.String(), Type.Unknown())), retries: Type.Optional(Type.Integer({ minimum: 0 })), timeoutMs: Type.Optional(Type.Union([Type.Integer({ minimum: 1 }), Type.Null()])) }, { additionalProperties: true }),
|
|
6774
|
+
outputSchema: Type.Object({ id: Type.String() }),
|
|
6636
6775
|
execute: async (_id, params) => {
|
|
6637
6776
|
if (!isChildAgentToolParams(params)) throw new WorkflowError("INVALID_METADATA", "Invalid child agent parameters");
|
|
6638
6777
|
validateAgentOptions(params);
|
|
@@ -6643,7 +6782,7 @@ var FairAgentScheduler = class {
|
|
|
6643
6782
|
Reflect.deleteProperty(agentOptions, "prompt");
|
|
6644
6783
|
const options = { label: params.label, requestedLabel: params.label, cwd: parent.options.cwd, tools, agentOptions, ...params.skills ? { skills: params.skills } : {}, ...params.extensions ? { extensions: params.extensions } : {}, ...params.model ? { model: params.model } : {}, ...params.role ? { role: params.role } : {}, ...params.contextFiles ? { contextFiles: params.contextFiles } : {}, ...outputSchema === void 0 ? {} : { schema: outputSchema }, ...params.retries === void 0 ? {} : { retries: params.retries }, ...params.timeoutMs === void 0 ? {} : { timeoutMs: params.timeoutMs } };
|
|
6645
6784
|
const child = this.spawn(parent.runId, params.prompt, options, parentId);
|
|
6646
|
-
return { content: [{ type: "text", text: JSON.stringify({ id: child.id }) }], details: { id: child.id } };
|
|
6785
|
+
return { content: [{ type: "text", text: JSON.stringify({ id: child.id }) }], details: { id: child.id }, structuredContent: { id: child.id } };
|
|
6647
6786
|
}
|
|
6648
6787
|
});
|
|
6649
6788
|
const resultTool = defineTool({
|
|
@@ -6651,10 +6790,11 @@ var FairAgentScheduler = class {
|
|
|
6651
6790
|
label: "Child Result",
|
|
6652
6791
|
description: "Wait for a direct child and return its result once; repeated retrieval fails with AGENT_RESULT_COLLECTED",
|
|
6653
6792
|
parameters: Type.Object({ id: Type.String() }),
|
|
6793
|
+
outputSchema: Type.Object({ id: Type.String(), ok: Type.Boolean(), value: Type.Optional(Type.Unknown()), error: Type.Optional(Type.Object({ code: Type.String(), message: Type.String() })) }),
|
|
6654
6794
|
execute: async (_id, params) => {
|
|
6655
6795
|
const value = await this.result(parentId, params.id);
|
|
6656
6796
|
if (!value.ok && value.error.code === "BUDGET_EXHAUSTED") throw new WorkflowError("BUDGET_EXHAUSTED", value.error.message);
|
|
6657
|
-
return { content: [{ type: "text", text: JSON.stringify(value) }], details: value };
|
|
6797
|
+
return { content: [{ type: "text", text: JSON.stringify(value) }], details: value, structuredContent: value };
|
|
6658
6798
|
}
|
|
6659
6799
|
});
|
|
6660
6800
|
const steerTool = defineTool({
|
|
@@ -7257,6 +7397,7 @@ var WORKFLOW_ERROR_PROSE = {
|
|
|
7257
7397
|
RUN_NOT_FOUND: (detail) => /^Unknown workflow run\b/.test(detail) ? "The workflow run was not found." : `The workflow run was not found: ${detail}.`,
|
|
7258
7398
|
RPC_LIMIT_EXCEEDED: (detail) => `The workflow communication data exceeded its size limit: ${detail}.`,
|
|
7259
7399
|
SHELL_FAILED: (detail) => `The workflow shell command failed: ${detail}.`,
|
|
7400
|
+
TOOL_FAILED: (detail) => `The workflow tool call failed: ${detail}.`,
|
|
7260
7401
|
AGENT_TIMEOUT: (detail) => `The workflow agent timed out: ${detail}.`,
|
|
7261
7402
|
AGENT_FAILED: (detail) => `The workflow agent failed: ${detail}.`,
|
|
7262
7403
|
AGENT_RESULT_COLLECTED: (detail) => `The nested agent result was already collected: ${detail}.`,
|
|
@@ -7547,7 +7688,7 @@ function persistedFailure(run, error) {
|
|
|
7547
7688
|
return { ...run, error: { code: error.code, message: error.message, ...failedAt ? { failedAt } : {} }, ...failedAt ? { failedAt } : {} };
|
|
7548
7689
|
}
|
|
7549
7690
|
function createWorkflowRecovery(deps) {
|
|
7550
|
-
const { pi, home, runs, scheduler, eventPublisher, persistRunState, projectTrusted: projectTrusted2, resumeHostContext: resumeHostContext2, ensureSessionLease, createAgentExecutor, activeSnapshotTools, frozenResourcePolicy: frozenResourcePolicy2, resolveLaunchPrologue, resumeRoles, workflowAgentHandler, shellForRun, resolveWorktree, checkpointBridge, phaseBridge, logBridge, lifecycleFor, createProviderErrorRecovery, cleanupTerminalRun, deliver: deliver2, deliverTerminal, workflowToolUpdate: workflowToolUpdate2, registry, modelSpec: modelSpec2 } = deps;
|
|
7691
|
+
const { pi, home, runs, scheduler, eventPublisher, persistRunState, projectTrusted: projectTrusted2, resumeHostContext: resumeHostContext2, ensureSessionLease, createAgentExecutor, activeSnapshotTools, frozenResourcePolicy: frozenResourcePolicy2, resolveLaunchPrologue, resumeRoles, workflowAgentHandler, shellForRun, toolForRun, resolveWorktree, checkpointBridge, phaseBridge, logBridge, lifecycleFor, createProviderErrorRecovery, cleanupTerminalRun, deliver: deliver2, deliverTerminal, workflowToolUpdate: workflowToolUpdate2, registry, modelSpec: modelSpec2 } = deps;
|
|
7551
7692
|
const coordinateRunMutation = deps.coordinateRunMutation ?? ((task) => task());
|
|
7552
7693
|
const budgetDecisionDelivery = (metadata, request) => `Workflow ${metadata.name} budget adjustment ${request.proposalId} for run ${request.runId} requires approval. Consumed usage: ${JSON.stringify(request.consumed)}. Previous limits: ${JSON.stringify(request.previous)}. Proposed limits: ${JSON.stringify(request.proposed)}. Respond with workflow_respond using proposalId ${request.proposalId}.`;
|
|
7553
7694
|
const appendBudgetDecisionEvent = async (run, request, type) => {
|
|
@@ -7619,7 +7760,7 @@ function createWorkflowRecovery(deps) {
|
|
|
7619
7760
|
run.executor.setRunContext(runContext);
|
|
7620
7761
|
await scheduler.cancelRun(run.store.runId);
|
|
7621
7762
|
await run.lifecycle.resume();
|
|
7622
|
-
const execution = runWorkflow(script, loaded.snapshot.args, withWorkflowFunctions({ shell: (command, options, signal, identity) => shellForRun(run.store, run.metadata, run.lifecycle, command, options, signal, identity), agent: workflowAgentHandler(run.store, run.metadata, run.lifecycle, run.executor, run.store.cwd, run.store.runId, roles.capture), worktree: async (owner) => resolveWorktree(run.store, run.metadata, owner), checkpoint: checkpointBridge(run.store.runId, run.store, run.metadata, foreground, hasUI ? ui : void 0), phase: phaseBridge(run.store, run.metadata, run.lifecycle), log: logBridge(run.store, run.lifecycle, run.metadata.name) }, run.store, runContext, registry, snapshot.settings.extensionSettings), controller.signal);
|
|
7763
|
+
const execution = runWorkflow(script, loaded.snapshot.args, withWorkflowFunctions({ tool: (identifier, args, signal, identity) => toolForRun(run.store, run.lifecycle, context?.toolContext, identifier, args, signal, identity), shell: (command, options, signal, identity) => shellForRun(run.store, run.metadata, run.lifecycle, command, options, signal, identity), agent: workflowAgentHandler(run.store, run.metadata, run.lifecycle, run.executor, run.store.cwd, run.store.runId, roles.capture), worktree: async (owner) => resolveWorktree(run.store, run.metadata, owner), checkpoint: checkpointBridge(run.store.runId, run.store, run.metadata, foreground, hasUI ? ui : void 0), phase: phaseBridge(run.store, run.metadata, run.lifecycle), log: logBridge(run.store, run.lifecycle, run.metadata.name) }, run.store, runContext, registry, snapshot.settings.extensionSettings), controller.signal);
|
|
7623
7764
|
run.execution = execution;
|
|
7624
7765
|
const completion = execution.result.then(async (value) => {
|
|
7625
7766
|
await scheduler.flush(run.store.runId);
|
|
@@ -7818,7 +7959,7 @@ function createWorkflowRecovery(deps) {
|
|
|
7818
7959
|
await eventPublisher.runStarted(prepared.childRun.store, prepared.childRun.metadata);
|
|
7819
7960
|
const { hasUI, ui } = recoveryUi(context);
|
|
7820
7961
|
const recoveryContext = resumeHostContext2(context);
|
|
7821
|
-
const completed = await coldResumeRun(prepared.childRun, hasUI, ui, projectTrusted2(context), { model: prepared.hostModel, modelRegistry: prepared.modelRegistry, deliveryContext: recoveryContext.deliveryContext, resolvedAliases: prepared.currentAliases, blockedAliases: prepared.blockedAliases, blockedAliasTargets: prepared.blockedAliasTargets, ...signal ? { signal } : {} }, modeOverride);
|
|
7962
|
+
const completed = await coldResumeRun(prepared.childRun, hasUI, ui, projectTrusted2(context), { model: prepared.hostModel, modelRegistry: prepared.modelRegistry, deliveryContext: recoveryContext.deliveryContext, toolContext: recoveryContext.toolContext, resolvedAliases: prepared.currentAliases, blockedAliases: prepared.blockedAliases, blockedAliasTargets: prepared.blockedAliasTargets, ...signal ? { signal } : {} }, modeOverride);
|
|
7822
7963
|
const completion = runs.get(prepared.childRun.store.runId)?.completion;
|
|
7823
7964
|
if (completion) {
|
|
7824
7965
|
childStarted = true;
|
|
@@ -9131,6 +9272,15 @@ function formatShellActivity(activeShells, startedAt, spinner2, styles, now) {
|
|
|
9131
9272
|
const timing = started && startedAt !== void 0 && !Number.isNaN(started.getTime()) ? ` ${styles.dim(`started=${started.toISOString()} elapsed=${formatWorkflowRuntime(Math.max(0, now - startedAt))}`)}` : "";
|
|
9132
9273
|
return `${styles.accent(spinner2)} shell ${styles.accent("[running]")} ${styles.dim(`(${String(count)} active)`)}${timing}`;
|
|
9133
9274
|
}
|
|
9275
|
+
function formatToolActivity(run, spinner2, styles, now) {
|
|
9276
|
+
const calls = run.activeTools ?? [];
|
|
9277
|
+
if (!calls.length) return void 0;
|
|
9278
|
+
const counts = /* @__PURE__ */ new Map();
|
|
9279
|
+
for (const { name } of calls) counts.set(name, (counts.get(name) ?? 0) + 1);
|
|
9280
|
+
const names = [...counts].map(([name, count]) => count > 1 ? `${name} \xD7${String(count)}` : name).join(", ");
|
|
9281
|
+
const elapsed = formatWorkflowRuntime(Math.max(0, now - Math.min(...calls.map(({ startedAt }) => startedAt))));
|
|
9282
|
+
return `${styles.accent(spinner2)} tools ${styles.accent("[running]")} ${sanitizeDisplayText(names)} ${styles.dim(`elapsed=${elapsed}`)}`;
|
|
9283
|
+
}
|
|
9134
9284
|
function formatLogTimestamp(timestamp) {
|
|
9135
9285
|
if (timestamp === void 0 || !Number.isFinite(timestamp)) return "--:--:--";
|
|
9136
9286
|
const date = new Date(timestamp);
|
|
@@ -9211,12 +9361,15 @@ function workflowProgressLines(run, spinner2, styles, now, expanded, width, show
|
|
|
9211
9361
|
const scopedShells = (run.activeShellsByPhase?.length ?? 0) > 0;
|
|
9212
9362
|
const shellActivity = scopedShells ? void 0 : formatShellActivity(run.activeShells, run.activeShellStartedAt, spinner2, styles, now);
|
|
9213
9363
|
if (shellActivity) lines.push(` ${shellActivity}`);
|
|
9364
|
+
const toolActivity = formatToolActivity(run, spinner2, styles, now);
|
|
9365
|
+
if (toolActivity) lines.push(` ${toolActivity}`);
|
|
9214
9366
|
const byId = new Map(run.agents.map((agent) => [agent.id, agent]));
|
|
9215
9367
|
const position = new Map(run.agents.map((agent, index) => [agent, index]));
|
|
9216
9368
|
const renderAgents = (agents, nested2) => renderGroupedAgents(agents, ({ agent, depth }, grouped) => {
|
|
9217
|
-
const icon = agentStateGlyph(agent.state,
|
|
9369
|
+
const icon = agentStateGlyph(agent.state, "\u25CF");
|
|
9218
9370
|
const indent = " ".repeat((grouped ? 2 : 1) + depth);
|
|
9219
|
-
const
|
|
9371
|
+
const idleSpinner = agent.state === "running" && !agentActivityLabel(agent) ? styles.accent(spinner2) : "";
|
|
9372
|
+
const activity = SETTLED_AGENT_STATES.has(agent.state) ? "" : [idleSpinner, formatAgentActivity(agent, spinner2, styles, now)].filter(Boolean).join(" ");
|
|
9220
9373
|
const name = grouped ? agent.label ?? agent.name : styledAgentBreadcrumb(agent, byId, styles);
|
|
9221
9374
|
const state2 = progressStyleForState(agent.state, styles);
|
|
9222
9375
|
const detail = expanded ? formatWorkflowAgentDetail(agent, now) : "";
|
|
@@ -9514,7 +9667,7 @@ ${progressText}` : progressText, width);
|
|
|
9514
9667
|
invalidate() {
|
|
9515
9668
|
const displayed = currentRun();
|
|
9516
9669
|
const now = Date.now();
|
|
9517
|
-
if (!progress || !refresh || displayed.state !== "running" || !displayed.agents.some((agent) => agent.state === "running") && (displayed.activeShells ?? 0) <= 0) return;
|
|
9670
|
+
if (!progress || !refresh || displayed.state !== "running" || !displayed.agents.some((agent) => agent.state === "running") && (displayed.activeShells ?? 0) <= 0 && !displayed.activeTools?.length) return;
|
|
9518
9671
|
if (progress.refresh || now - progress.lastRefreshAt < WORKFLOW_PROGRESS_REFRESH_MS) return;
|
|
9519
9672
|
progress.lastRefreshAt = now;
|
|
9520
9673
|
const inputRun = progress.inputRun;
|
|
@@ -9727,6 +9880,8 @@ function formatNavigatorDashboard(run, checkpoints, worktrees, now = Date.now())
|
|
|
9727
9880
|
const lines = [header, meta, ...formatCompactBudgetStatus(run)];
|
|
9728
9881
|
const shellActivity = formatShellActivity(run.activeShells, run.activeShellStartedAt, "\u2826", PLAIN_WORKFLOW_PROGRESS_STYLES, now);
|
|
9729
9882
|
if (shellActivity) lines.push(` ${shellActivity}`);
|
|
9883
|
+
const toolActivity = formatToolActivity(run, "\u2826", PLAIN_WORKFLOW_PROGRESS_STYLES, now);
|
|
9884
|
+
if (toolActivity) lines.push(` ${toolActivity}`);
|
|
9730
9885
|
if (run.error) lines.push(`Error: ${run.error.code}: ${run.error.message}`);
|
|
9731
9886
|
if (run.events?.length) lines.push(...run.events.filter((event) => event.type === "warning").map((event) => `Warning: ${event.message}`));
|
|
9732
9887
|
lines.push("");
|
|
@@ -9766,6 +9921,8 @@ function formatNavigatorRun(loaded, checkpoints, worktrees, now = Date.now()) {
|
|
|
9766
9921
|
];
|
|
9767
9922
|
const shellActivity = formatShellActivity(run.activeShells, run.activeShellStartedAt, "\u2826", PLAIN_WORKFLOW_PROGRESS_STYLES, now);
|
|
9768
9923
|
if (shellActivity) lines.push(` ${shellActivity}`);
|
|
9924
|
+
const toolActivity = formatToolActivity(run, "\u2826", PLAIN_WORKFLOW_PROGRESS_STYLES, now);
|
|
9925
|
+
if (toolActivity) lines.push(` ${toolActivity}`);
|
|
9769
9926
|
if (run.error) lines.push(`Run error: ${run.error.code}: ${run.error.message}`);
|
|
9770
9927
|
if (run.events?.length) lines.push(...run.events.filter((event) => event.type === "warning").map((event) => `Warning: ${event.message}`));
|
|
9771
9928
|
const aliases = snapshot.modelAliases ?? snapshot.settings.modelAliases;
|
|
@@ -9865,6 +10022,8 @@ function formatWorkflowPhaseDashboard(run, snapshot, width, selection = {}, styl
|
|
|
9865
10022
|
const scopedShells = (run.activeShellsByPhase?.length ?? 0) > 0;
|
|
9866
10023
|
const shellActivity = scopedShells ? void 0 : formatShellActivity(run.activeShells, run.activeShellStartedAt, "\u2826", styles, now);
|
|
9867
10024
|
if (shellActivity) lines.push(` ${shellActivity}`);
|
|
10025
|
+
const toolActivity = formatToolActivity(run, "\u2826", styles, now);
|
|
10026
|
+
if (toolActivity) lines.push(` ${toolActivity}`);
|
|
9868
10027
|
const actionRows = () => {
|
|
9869
10028
|
const actions = selection.actions;
|
|
9870
10029
|
if (!actions) return [];
|
|
@@ -11101,6 +11260,66 @@ Mutations are available through workflow tools.`, "info");
|
|
|
11101
11260
|
});
|
|
11102
11261
|
}
|
|
11103
11262
|
|
|
11263
|
+
// src/script-tools.ts
|
|
11264
|
+
function scriptToolExcluded(name) {
|
|
11265
|
+
return name === "workflow" || name.startsWith("workflow_") || name.startsWith("subagents_");
|
|
11266
|
+
}
|
|
11267
|
+
function scriptToolIdentifier(name) {
|
|
11268
|
+
let identifier = "";
|
|
11269
|
+
for (const char of name) identifier += (identifier === "" ? /^[A-Za-z_$]$/ : /^[A-Za-z0-9_$]$/).test(char) ? char : "_";
|
|
11270
|
+
return identifier || "_";
|
|
11271
|
+
}
|
|
11272
|
+
function scriptToolContext(ctx) {
|
|
11273
|
+
return object(ctx) && typeof ctx.executeTool === "function" && Array.isArray(ctx.tools) ? ctx : void 0;
|
|
11274
|
+
}
|
|
11275
|
+
function scriptToolIdentifiers(context) {
|
|
11276
|
+
return (context?.tools ?? []).filter(({ name }) => !scriptToolExcluded(name)).map(({ name }) => scriptToolIdentifier(name));
|
|
11277
|
+
}
|
|
11278
|
+
function scriptTool(context, identifier) {
|
|
11279
|
+
return context.tools.find(({ name }) => !scriptToolExcluded(name) && scriptToolIdentifier(name) === identifier);
|
|
11280
|
+
}
|
|
11281
|
+
function scriptToolValue(tool, outcome) {
|
|
11282
|
+
const structured = tool.outputSchema === void 0 ? void 0 : outcome.result.structuredContent;
|
|
11283
|
+
const text = outcome.result.content.flatMap((item) => item.type === "text" ? [item.text] : []).join("\n");
|
|
11284
|
+
if (structured === void 0 && outcome.isError) throw new WorkflowError("TOOL_FAILED", `${tool.name}: ${text || "failed"}`);
|
|
11285
|
+
let value;
|
|
11286
|
+
try {
|
|
11287
|
+
value = JSON.parse(JSON.stringify(structured ?? text));
|
|
11288
|
+
} catch (error) {
|
|
11289
|
+
throw new WorkflowError("TOOL_FAILED", `${tool.name} returned a result that is not JSON: ${errorText(error)}`);
|
|
11290
|
+
}
|
|
11291
|
+
if (!jsonValue(value)) throw new WorkflowError("TOOL_FAILED", `${tool.name} returned a result that is not JSON`);
|
|
11292
|
+
if (Buffer.byteLength(JSON.stringify(value)) > RPC_LIMIT_BYTES) throw new WorkflowError("TOOL_FAILED", `${tool.name} returned more than the 10 MB workflow RPC limit`);
|
|
11293
|
+
return value;
|
|
11294
|
+
}
|
|
11295
|
+
function validateScriptToolReferences(script, context) {
|
|
11296
|
+
const references = scriptToolReferences(script);
|
|
11297
|
+
if (!references?.length) return;
|
|
11298
|
+
if (!context) throw new WorkflowError("UNKNOWN_TOOL", `Workflow scripts can call session tools only when launched by the workflow tool; this launch has none for ${references.map((name) => `tools.${name}`).join(", ")}`);
|
|
11299
|
+
const identifiers = scriptToolIdentifiers(context);
|
|
11300
|
+
const unknown = references.filter((name) => !identifiers.includes(name));
|
|
11301
|
+
if (unknown.length) throw new WorkflowError("UNKNOWN_TOOL", `Workflow script calls tools this session cannot call: ${unknown.map((name) => `tools.${name}`).join(", ")}`);
|
|
11302
|
+
const ambiguous = references.filter((name) => identifiers.indexOf(name) !== identifiers.lastIndexOf(name));
|
|
11303
|
+
if (ambiguous.length) throw new WorkflowError("UNKNOWN_TOOL", `Workflow script calls tools whose names collide after normalization: ${ambiguous.map((name) => `tools.${name}`).join(", ")}`);
|
|
11304
|
+
}
|
|
11305
|
+
function describeScriptOutput(schema) {
|
|
11306
|
+
if (!object(schema) || schema.type !== "object" || !object(schema.properties)) return schema === void 0 ? void 0 : "a JSON value";
|
|
11307
|
+
const required = new Set(Array.isArray(schema.required) ? schema.required : []);
|
|
11308
|
+
return `\`{ ${Object.keys(schema.properties).map((name) => required.has(name) ? name : `${name}?`).join(", ")} }\``;
|
|
11309
|
+
}
|
|
11310
|
+
function prepareScriptToolLoadout(loadout) {
|
|
11311
|
+
if (loadout.declared.some(({ name }) => name === "codemode")) return void 0;
|
|
11312
|
+
const callable = new Set(loadout.callable.map(({ name }) => name));
|
|
11313
|
+
const descriptions = {};
|
|
11314
|
+
for (const tool of loadout.declared) {
|
|
11315
|
+
const output = callable.has(tool.name) && !scriptToolExcluded(tool.name) ? describeScriptOutput(tool.outputSchema) : void 0;
|
|
11316
|
+
if (output) descriptions[tool.name] = `${tool.description.trim()}
|
|
11317
|
+
|
|
11318
|
+
Workflow scripts: \`tools.${scriptToolIdentifier(tool.name)}(args)\` resolves to ${output}.`;
|
|
11319
|
+
}
|
|
11320
|
+
return { descriptions };
|
|
11321
|
+
}
|
|
11322
|
+
|
|
11104
11323
|
// src/changelog.ts
|
|
11105
11324
|
import { mkdir as mkdir3, readFile as readFile6 } from "node:fs/promises";
|
|
11106
11325
|
import { dirname as dirname6, join as join14 } from "node:path";
|
|
@@ -11202,7 +11421,7 @@ async function showChangelogNotice(context, agentDir, packageDirectory) {
|
|
|
11202
11421
|
}
|
|
11203
11422
|
|
|
11204
11423
|
// src/trajectory.ts
|
|
11205
|
-
import { createHash as
|
|
11424
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
11206
11425
|
import { open as open2, readFile as readFile7, readdir as readdir5, stat as stat4 } from "node:fs/promises";
|
|
11207
11426
|
import { homedir as homedir7 } from "node:os";
|
|
11208
11427
|
import { basename as basename5, dirname as dirname7, join as join15, resolve as resolve8 } from "node:path";
|
|
@@ -11234,7 +11453,8 @@ var SUBAGENTS_RUN_PARAMETERS = Type2.Object({
|
|
|
11234
11453
|
timeoutMs: Type2.Optional(Type2.Union([Type2.Integer({ minimum: 1, description: "Optional execution timeout in milliseconds" }), Type2.Null()]))
|
|
11235
11454
|
}, { additionalProperties: false });
|
|
11236
11455
|
var SUBAGENTS_INSPECT_PARAMETERS = Type2.Object({
|
|
11237
|
-
id: Type2.Optional(Type2.String({ description: "Subagent ID; omit to list ordered run summaries" }))
|
|
11456
|
+
id: Type2.Optional(Type2.String({ description: "Subagent ID; omit to list ordered run summaries" })),
|
|
11457
|
+
scope: Type2.Optional(Type2.Union([Type2.Literal("session"), Type2.Literal("all")], { description: "List scope when id is omitted: session (default) lists runs from the current Pi session; all lists every stored run" }))
|
|
11238
11458
|
}, { additionalProperties: false });
|
|
11239
11459
|
var SUBAGENTS_ID_PARAMETERS = Type2.Object({
|
|
11240
11460
|
id: Type2.String({ description: "Subagent ID" })
|
|
@@ -11249,6 +11469,21 @@ var SUBAGENTS_STOP_PARAMETERS = Type2.Object({
|
|
|
11249
11469
|
var SUBAGENTS_RETRY_PARAMETERS = Type2.Object({
|
|
11250
11470
|
id: Type2.String({ description: "Failed or stopped subagent ID to retry" })
|
|
11251
11471
|
}, { additionalProperties: false });
|
|
11472
|
+
var SUBAGENT_STATUS_OUTPUT = Type2.Object({
|
|
11473
|
+
id: Type2.String(),
|
|
11474
|
+
state: Type2.String(),
|
|
11475
|
+
sessionId: Type2.Optional(Type2.String()),
|
|
11476
|
+
startedAt: Type2.Optional(Type2.Number()),
|
|
11477
|
+
finishedAt: Type2.Optional(Type2.Number()),
|
|
11478
|
+
attempts: Type2.Optional(Type2.Number()),
|
|
11479
|
+
attemptDetails: Type2.Optional(Type2.Array(Type2.Unknown())),
|
|
11480
|
+
worktree: Type2.Optional(Type2.Object({ path: Type2.String(), branch: Type2.String() })),
|
|
11481
|
+
error: Type2.Optional(Type2.Object({ code: Type2.String(), message: Type2.String() })),
|
|
11482
|
+
progress: Type2.Optional(Type2.Unknown()),
|
|
11483
|
+
value: Type2.Optional(Type2.Unknown())
|
|
11484
|
+
});
|
|
11485
|
+
var SUBAGENTS_INSPECT_OUTPUT = Type2.Union([SUBAGENT_STATUS_OUTPUT, Type2.Array(Type2.Object({ id: Type2.String(), state: Type2.String() }))]);
|
|
11486
|
+
var SUBAGENTS_STEER_OUTPUT = Type2.Object({ id: Type2.String(), accepted: Type2.Boolean() });
|
|
11252
11487
|
function normalizeSubagentRunRequest(value) {
|
|
11253
11488
|
if (!Value2.Check(SUBAGENTS_RUN_PARAMETERS, value)) throw new WorkflowError("INVALID_METADATA", "Invalid subagents_run parameters");
|
|
11254
11489
|
if (typeof value.worktree === "string" && !value.worktree.trim()) throw new WorkflowError("INVALID_METADATA", "worktree name must be a non-empty string");
|
|
@@ -11451,7 +11686,7 @@ function transcriptToolCallId(value) {
|
|
|
11451
11686
|
return void 0;
|
|
11452
11687
|
}
|
|
11453
11688
|
function isTimingTranscriptEntry(value) {
|
|
11454
|
-
return object(value) && value.type === "custom" && value.customType ===
|
|
11689
|
+
return object(value) && value.type === "custom" && value.customType === TOOL_TIMING_ENTRY_TYPE;
|
|
11455
11690
|
}
|
|
11456
11691
|
function timingToolCallId(value) {
|
|
11457
11692
|
if (!object(value) || !isTimingTranscriptEntry(value) || !object(value.data)) return void 0;
|
|
@@ -11572,7 +11807,7 @@ function withPiToolDescriptions(run) {
|
|
|
11572
11807
|
function canonicalExtensionSelector2(selector, base) {
|
|
11573
11808
|
const negated = selector.startsWith("!");
|
|
11574
11809
|
const body = negated ? selector.slice(1) : selector;
|
|
11575
|
-
if (body === "*" || body === "**" || body.startsWith("**/")) return selector;
|
|
11810
|
+
if (body === "*" || body === "**" || body.startsWith("**/") || body.startsWith("builtin:")) return selector;
|
|
11576
11811
|
const resolved = resolve8(base, body);
|
|
11577
11812
|
if (resourcePatternHasMagic(body)) return `${negated ? "!" : ""}${resolved}`;
|
|
11578
11813
|
return `${negated ? "!" : ""}${canonicalPath(resolved)}`;
|
|
@@ -11647,11 +11882,17 @@ function failedAgentOutput(agent) {
|
|
|
11647
11882
|
const status = agent.state === "cancelled" ? "cancelled" : "failed";
|
|
11648
11883
|
return { status, code: error?.code ?? (status === "cancelled" ? "CANCELLED" : "AGENT_FAILED"), message: error?.message ?? `Agent ${agent.state}` };
|
|
11649
11884
|
}
|
|
11885
|
+
function operationOutput(operation) {
|
|
11886
|
+
const bytes = serializedJsonBytes(operation.value);
|
|
11887
|
+
return bytes > DEFAULT_MAX_BYTES2 ? { status: "truncated", kind: "result", bytes } : { status: "available", value: operation.value, bytes };
|
|
11888
|
+
}
|
|
11889
|
+
function outputForCall(call, operation) {
|
|
11890
|
+
if (operation !== void 0) return call.kind === "tool" ? { status: "completed" } : operationOutput(operation);
|
|
11891
|
+
if (call.error) return { status: call.error.code === "CANCELLED" ? "cancelled" : "failed", code: call.error.code, ...call.kind === "shell" ? { message: call.error.message ?? "Shell failed" } : {} };
|
|
11892
|
+
return call.finishedAt === void 0 ? { status: "pending" } : { status: "unavailable" };
|
|
11893
|
+
}
|
|
11650
11894
|
function outputForAgent(agent, operation) {
|
|
11651
|
-
if (operation !== void 0)
|
|
11652
|
-
const bytes = serializedJsonBytes(operation.value);
|
|
11653
|
-
return bytes > DEFAULT_MAX_BYTES2 ? { status: "truncated", kind: "result", bytes } : { status: "available", value: operation.value, bytes };
|
|
11654
|
-
}
|
|
11895
|
+
if (operation !== void 0) return operationOutput(operation);
|
|
11655
11896
|
if (agent.state === "failed" || agent.state === "cancelled") return failedAgentOutput(agent);
|
|
11656
11897
|
if (agent.state === "completed") return { status: "unavailable" };
|
|
11657
11898
|
return { status: "pending" };
|
|
@@ -11659,7 +11900,17 @@ function outputForAgent(agent, operation) {
|
|
|
11659
11900
|
function applyTrajectoryAgentOutputs(run, operations) {
|
|
11660
11901
|
const byPath = new Map(operations.map((operation) => [operation.path, operation]));
|
|
11661
11902
|
const agents = run.agents.map((agent) => ({ ...agent, output: outputForAgent(agent, agent.resultPath === void 0 ? void 0 : byPath.get(agent.resultPath)) }));
|
|
11662
|
-
|
|
11903
|
+
const scriptCalls = run.scriptCalls?.map((call) => {
|
|
11904
|
+
const recorded = { ...call, output: outputForCall(call, byPath.get(call.path)) };
|
|
11905
|
+
if (call.kind === "tool") {
|
|
11906
|
+
delete recorded.input;
|
|
11907
|
+
delete recorded.inputBytes;
|
|
11908
|
+
if (call.error) recorded.error = { code: call.error.code };
|
|
11909
|
+
}
|
|
11910
|
+
return recorded;
|
|
11911
|
+
});
|
|
11912
|
+
const rest = run;
|
|
11913
|
+
return { ...rest, agents, ...scriptCalls === void 0 ? {} : { scriptCalls } };
|
|
11663
11914
|
}
|
|
11664
11915
|
function overlayTrajectoryRun(run, overlay) {
|
|
11665
11916
|
const overlaid = overlay(run);
|
|
@@ -11669,7 +11920,7 @@ function overlayTrajectoryRun(run, overlay) {
|
|
|
11669
11920
|
const output = previous?.status === "available" || previous?.status === "truncated" ? previous : outputForAgent(agent, void 0);
|
|
11670
11921
|
return { ...agent, output };
|
|
11671
11922
|
});
|
|
11672
|
-
return { ...overlaid, agents };
|
|
11923
|
+
return { ...overlaid, agents, ...run.scriptCalls === void 0 ? {} : { scriptCalls: run.scriptCalls } };
|
|
11673
11924
|
}
|
|
11674
11925
|
async function loadTrajectoryRun(store, includeTranscripts = true) {
|
|
11675
11926
|
const value = await store.load();
|
|
@@ -11719,7 +11970,7 @@ function createTrajectoryRunLoader(cwd, sessionId, home = homedir7(), overlay) {
|
|
|
11719
11970
|
return createCachedRunLoader(cwd, sessionId, home, (store) => loadTrajectoryRun(store), fileMtime, overlay);
|
|
11720
11971
|
}
|
|
11721
11972
|
function transcriptRevision(info) {
|
|
11722
|
-
const digest =
|
|
11973
|
+
const digest = createHash4("sha256").update(`${String(info.mtimeNs)}:${String(info.size)}`).digest();
|
|
11723
11974
|
return Math.max(1, digest.readUIntBE(0, 6));
|
|
11724
11975
|
}
|
|
11725
11976
|
async function transcriptMetadata(path) {
|
|
@@ -12002,6 +12253,12 @@ function mainAgentError(error) {
|
|
|
12002
12253
|
Object.assign(presented, typed);
|
|
12003
12254
|
return presented;
|
|
12004
12255
|
}
|
|
12256
|
+
function completionControlValue(result, controlRunId) {
|
|
12257
|
+
const record3 = { ...controlRunId === void 0 ? {} : { runId: controlRunId }, ...result };
|
|
12258
|
+
delete record3.run;
|
|
12259
|
+
delete record3.completion;
|
|
12260
|
+
return record3;
|
|
12261
|
+
}
|
|
12005
12262
|
function completionControlContent(result, controlRunId) {
|
|
12006
12263
|
const record3 = object(result) ? { ...result } : void 0;
|
|
12007
12264
|
if (record3 && controlRunId !== void 0 && record3.runId === void 0) record3.runId = controlRunId;
|
|
@@ -12047,7 +12304,7 @@ function formatWorkflowPreview(args) {
|
|
|
12047
12304
|
return [`workflow ${name}`, typeof args.description === "string" && args.description.trim() ? args.description.trim() : ""].filter(Boolean).join("\n");
|
|
12048
12305
|
}
|
|
12049
12306
|
var WORKFLOW_TOOL_LABEL = "Workflow";
|
|
12050
|
-
var WORKFLOW_TOOL_DESCRIPTION = "Run a deterministic JavaScript workflow with a named inline or file-backed parallel-to-summary path by default";
|
|
12307
|
+
var WORKFLOW_TOOL_DESCRIPTION = "Run a deterministic JavaScript workflow with a named inline or file-backed parallel-to-summary path by default. Scripts call this session's tools as `await tools.<name>(args)`, outside withWorktree: a tool resolves to its text unless its description gives a `tools.<name>(args)` result shape, and failures reject";
|
|
12051
12308
|
var WORKFLOW_TOOL_PROMPT_SNIPPET = "Run a deterministic, resumable JavaScript workflow. Prefer a named inline script that fans out independent work with parallel(...), awaits the keyed results before interpolating them into one summarizing agent(...), and returns. Provide exactly one of script or scriptPath and a non-empty name. Registered catalog functions are available as globals inside the script; call them there, for example return await someFunction(args). Advanced controls include registered functions, outputSchema, budgets, checkpoints, worktrees, retry/resume, CLI export, and pipelines. Runs are in the background by default; completion arrives as a follow-up message. Set foreground: true when the caller must wait for the final value. Manage runs from the interactive /workflow picker; use workflow_status, workflow_resume, workflow_retry, workflow_stop, and workflow_respond for explicit tool controls. If a foreground call detaches before its result is accepted, its terminal success or failure is promoted to one follow-up message. Foreground results include the completed run ID. Recovery inherits the source launch mode; legacy snapshots without launchMode recover in the background. Set foreground: true or false on workflow_resume/workflow_retry to override it; foreground recovery waits for terminal value and run details, while background recovery returns immediately and delivers completion or failure as a follow-up. After failure follow-ups, especially CANCELLED or interrupted runs, call workflow_status({ runId }) before recovery or replacement work, then pass its state as expectedState to workflow_retry/workflow_resume so recovery cannot act on a state that changed. Recovery map: agent(..., { retries }) reruns one agent call in the same run for transient failures; workflow_retry({ runId, expectedState?, foreground? }) replays a failed run into a child; workflow_resume({ runId, expectedState?, budget?, foreground? }) continues a budget_exhausted run; parentRunId on a new launch only borrows named worktrees and never replays or resumes.";
|
|
12052
12309
|
var WORKFLOW_TOOL_PARAMETERS = Type3.Object({
|
|
12053
12310
|
name: Type3.String({ description: "Required non-empty workflow name" }),
|
|
@@ -12062,6 +12319,19 @@ var WORKFLOW_TOOL_PARAMETERS = Type3.Object({
|
|
|
12062
12319
|
}, { additionalProperties: false });
|
|
12063
12320
|
var WORKFLOW_STATUS_PARAMETERS = Type3.Object({ runId: Type3.String({ description: "Workflow run ID visible in the current project" }) }, { additionalProperties: false });
|
|
12064
12321
|
var WORKFLOW_RETRY_PARAMETERS = Type3.Object({ runId: Type3.String({ description: "Explicit failed workflow run ID" }), expectedState: Type3.Optional(Type3.String({ description: "Persisted source state observed before recovery" })), foreground: Type3.Optional(Type3.Boolean({ description: "Override the source launch mode for this recovery" })) });
|
|
12322
|
+
var WORKFLOW_ERROR_OUTPUT = Type3.Object({ code: Type3.String(), message: Type3.String() });
|
|
12323
|
+
var WORKFLOW_LAUNCH_OUTPUT = Type3.Object({ runId: Type3.String(), state: Type3.String(), detached: Type3.Optional(Type3.Boolean()), value: Type3.Optional(Type3.Unknown()) });
|
|
12324
|
+
var WORKFLOW_STATUS_OUTPUT = Type3.Object({ runId: Type3.String(), workflowName: Type3.String(), state: Type3.String(), error: Type3.Optional(WORKFLOW_ERROR_OUTPUT), failedAt: Type3.Optional(Type3.String()), budget: Type3.Optional(Type3.Unknown()), usage: Type3.Optional(Type3.Unknown()), phase: Type3.Optional(Type3.String()), delivery: Type3.Optional(Type3.Object({ mode: Type3.String(), state: Type3.String() })), agents: Type3.Array(Type3.Object({ id: Type3.String(), label: Type3.Optional(Type3.String()), path: Type3.String(), state: Type3.String(), lastEventAt: Type3.Optional(Type3.Number()), accounting: Type3.Optional(Type3.Unknown()) })) });
|
|
12325
|
+
var WORKFLOW_STOP_OUTPUT = Type3.Object({ runId: Type3.String(), state: Type3.String(), stopped: Type3.Boolean(), reason: Type3.Optional(Type3.String()) });
|
|
12326
|
+
var WORKFLOW_RECOVERY_OUTPUT = Type3.Object({ state: Type3.String(), runId: Type3.Optional(Type3.String()), parentRunId: Type3.Optional(Type3.String()), proposalId: Type3.Optional(Type3.String()), value: Type3.Optional(Type3.Unknown()) });
|
|
12327
|
+
var WORKFLOW_RESPOND_OUTPUT = Type3.Object({ state: Type3.String(), approved: Type3.Boolean(), reason: Type3.String(), accepted: Type3.Optional(Type3.Boolean()), runId: Type3.Optional(Type3.String()), value: Type3.Optional(Type3.Unknown()) });
|
|
12328
|
+
var WORKFLOW_CATALOG_ALIAS_OUTPUT = Type3.Object({ name: Type3.String(), kind: Type3.String(), provenance: Type3.String(), version: Type3.Optional(Type3.String()), headline: Type3.Optional(Type3.String()) });
|
|
12329
|
+
var WORKFLOW_CATALOG_OUTPUT = Type3.Union([
|
|
12330
|
+
Type3.Object({ functions: Type3.Array(Type3.Object({ name: Type3.String(), description: Type3.String(), input: Type3.Unknown() })), modelAliasEntries: Type3.Optional(Type3.Array(WORKFLOW_CATALOG_ALIAS_OUTPUT)), settings: Type3.Optional(Type3.Unknown()) }),
|
|
12331
|
+
Type3.Object({ name: Type3.String(), version: Type3.String(), headline: Type3.String(), description: Type3.String(), input: Type3.Unknown(), output: Type3.Unknown() }),
|
|
12332
|
+
WORKFLOW_CATALOG_ALIAS_OUTPUT,
|
|
12333
|
+
Type3.Object({ error: Type3.Object({ code: Type3.String(), name: Type3.String(), message: Type3.String() }) })
|
|
12334
|
+
]);
|
|
12065
12335
|
function workflowToolUpdate(run) {
|
|
12066
12336
|
const done = run.agents.filter((agent) => SETTLED_AGENT_STATES.has(agent.state)).length;
|
|
12067
12337
|
return { content: [{ type: "text", text: `Workflow: ${run.workflowName} (${String(done)}/${String(run.agents.length)} done) [${run.state}]` }], details: { runId: run.id, run } };
|
|
@@ -12144,7 +12414,42 @@ function modelInventory(root, registry) {
|
|
|
12144
12414
|
}
|
|
12145
12415
|
function resumeHostContext(ctx) {
|
|
12146
12416
|
const model = object(ctx) && object(ctx.model) && typeof ctx.model.provider === "string" && typeof ctx.model.id === "string" ? { provider: ctx.model.provider, id: ctx.model.id } : void 0;
|
|
12147
|
-
return { model, modelRegistry: contextHostCapabilities(ctx).modelRegistry, deliveryContext: completionContext(ctx) };
|
|
12417
|
+
return { model, modelRegistry: contextHostCapabilities(ctx).modelRegistry, deliveryContext: completionContext(ctx), toolContext: scriptToolContext(ctx) };
|
|
12418
|
+
}
|
|
12419
|
+
var SCRIPT_CALL_TEXT_LIMIT_BYTES = 16 * 1024;
|
|
12420
|
+
function scriptCallInput(input) {
|
|
12421
|
+
const text = JSON.stringify(input);
|
|
12422
|
+
const bytes = Buffer.byteLength(text);
|
|
12423
|
+
return bytes <= SCRIPT_CALL_TEXT_LIMIT_BYTES ? { input } : { input: utf8Prefix(text, SCRIPT_CALL_TEXT_LIMIT_BYTES), inputBytes: bytes };
|
|
12424
|
+
}
|
|
12425
|
+
function startScriptCall(run, call) {
|
|
12426
|
+
const recorded = { ...call, ...run.phase === void 0 ? {} : { phase: run.phase } };
|
|
12427
|
+
const calls = run.scriptCalls ?? [];
|
|
12428
|
+
return { ...run, scriptCalls: calls.some(({ path }) => path === call.path) ? calls.map((current) => current.path === call.path ? recorded : current) : [...calls, recorded] };
|
|
12429
|
+
}
|
|
12430
|
+
function finishScriptCall(run, path, error) {
|
|
12431
|
+
const finishedAt = Date.now();
|
|
12432
|
+
return { ...run, scriptCalls: (run.scriptCalls ?? []).map((call) => call.path === path ? { ...call, finishedAt, ...error ? { error: { code: error.code, ...call.kind === "shell" ? { message: utf8Prefix(error.message, SCRIPT_CALL_TEXT_LIMIT_BYTES) } : {} } } : {} } : call) };
|
|
12433
|
+
}
|
|
12434
|
+
function registerAliasVirtualModels(pi, names, settingsPath) {
|
|
12435
|
+
const register = object(pi) ? asFn(pi.registerVirtualModel) : void 0;
|
|
12436
|
+
if (!register) return;
|
|
12437
|
+
for (const name of names) {
|
|
12438
|
+
const definition = {
|
|
12439
|
+
provider: VIRTUAL_MODEL_PROVIDER,
|
|
12440
|
+
id: name,
|
|
12441
|
+
name: `${name} (workflow alias)`,
|
|
12442
|
+
thinkingLevels: THINKING_LEVELS,
|
|
12443
|
+
route: (request, ctx) => {
|
|
12444
|
+
const aliases = resolveWorkflowSettings(ctx.cwd, projectTrusted(ctx), settingsPath).effective.modelAliases ?? {};
|
|
12445
|
+
const target = resolveModelReference(name, aliases, new Set(ctx.modelRegistry.getAll().map((model2) => `${model2.provider}/${model2.id}`)), settingsPath);
|
|
12446
|
+
const model = ctx.modelRegistry.find(target.provider, target.model);
|
|
12447
|
+
if (!model) throw new WorkflowError("UNKNOWN_MODEL", `Unknown model alias ${name} resolved to ${target.provider}/${target.model}`);
|
|
12448
|
+
return { model, thinkingLevel: request.thinkingLevel };
|
|
12449
|
+
}
|
|
12450
|
+
};
|
|
12451
|
+
Reflect.apply(register, pi, [definition]);
|
|
12452
|
+
}
|
|
12148
12453
|
}
|
|
12149
12454
|
async function resolveLaunchAliases(registry, staticAliases, context, availableModels, knownModels, settingsPath) {
|
|
12150
12455
|
const dynamic = typeof registry.resolveModelAliases === "function" ? await registry.resolveModelAliases(context, new Set(Object.keys(staticAliases))) : {};
|
|
@@ -12175,10 +12480,13 @@ function workflowExtension(pi, home, clipboard = copyToClipboard, transport = lo
|
|
|
12175
12480
|
});
|
|
12176
12481
|
let backgroundWidgetEnabled = true;
|
|
12177
12482
|
try {
|
|
12178
|
-
|
|
12483
|
+
const globalSettings = loadSettings(workflowSettingsPath(extensionAgentDir));
|
|
12484
|
+
backgroundWidgetEnabled = globalSettings.backgroundWidget ?? true;
|
|
12485
|
+
registerAliasVirtualModels(pi, Object.keys(globalSettings.modelAliases ?? {}), workflowSettingsPath(extensionAgentDir));
|
|
12179
12486
|
} catch {
|
|
12180
12487
|
}
|
|
12181
12488
|
const backgroundWidgetController = widget(pi, backgroundWidgetEnabled);
|
|
12489
|
+
const codemodeTools = loadCodemodeToolsSetting(extensionAgentDir);
|
|
12182
12490
|
const logBridge = (store, lifecycle, workflowName) => async (message) => {
|
|
12183
12491
|
const timestamp = Date.now();
|
|
12184
12492
|
const bounded = utf8Prefix(message, DELIVERY_LIMIT_BYTES);
|
|
@@ -12470,7 +12778,10 @@ Choose what to do`, ["Retry", "Change model", "Abort workflow"]);
|
|
|
12470
12778
|
if (replayed) return readShellResult(replayed.value);
|
|
12471
12779
|
const shellStartedAt = Date.now();
|
|
12472
12780
|
let shellPhaseIndex = -1;
|
|
12473
|
-
const
|
|
12781
|
+
const call = { kind: "shell", name: "shell", path, ...scriptCallInput({ command, ...options.timeoutMs === void 0 ? {} : { timeoutMs: options.timeoutMs }, ...options.env === void 0 ? {} : { env: Object.keys(options.env) }, ...identity.worktreeOwner ? { worktree: identity.worktreeOwner } : {} }), startedAt: shellStartedAt };
|
|
12782
|
+
let failure;
|
|
12783
|
+
const started = await persistRunState(store, metadata, (run) => {
|
|
12784
|
+
const current = startScriptCall(run, call);
|
|
12474
12785
|
const history = current.phaseHistory ?? [];
|
|
12475
12786
|
if (current.phase !== void 0) shellPhaseIndex = current.phaseHistoryIndex ?? (history.length ? history.length - 1 : 0);
|
|
12476
12787
|
const phaseActivities = [...current.activeShellsByPhase ?? []];
|
|
@@ -12486,8 +12797,12 @@ Choose what to do`, ["Retry", "Change model", "Abort workflow"]);
|
|
|
12486
12797
|
if (!jsonValue(result)) fail("SHELL_FAILED", "Shell result is not JSON-compatible");
|
|
12487
12798
|
await store.complete(path, result);
|
|
12488
12799
|
return result;
|
|
12800
|
+
} catch (error) {
|
|
12801
|
+
failure = asWorkflowError(error);
|
|
12802
|
+
throw error;
|
|
12489
12803
|
} finally {
|
|
12490
|
-
const stopped = await persistRunState(store, metadata, (
|
|
12804
|
+
const stopped = await persistRunState(store, metadata, (run) => {
|
|
12805
|
+
const current = finishScriptCall(run, path, failure);
|
|
12491
12806
|
const phaseActivities = [...current.activeShellsByPhase ?? []];
|
|
12492
12807
|
const phaseActivityIndex = phaseActivities.findIndex(({ phaseIndex }) => phaseIndex === shellPhaseIndex);
|
|
12493
12808
|
const phaseActivity = phaseActivities[phaseActivityIndex];
|
|
@@ -12507,6 +12822,55 @@ Choose what to do`, ["Retry", "Change model", "Abort workflow"]);
|
|
|
12507
12822
|
await lifecycle.leave();
|
|
12508
12823
|
}
|
|
12509
12824
|
};
|
|
12825
|
+
const toolForRun = async (store, lifecycle, context, identifier, args, signal, identity) => {
|
|
12826
|
+
await lifecycle.enter();
|
|
12827
|
+
try {
|
|
12828
|
+
const path = toolIdentityPath(identifier, args, identity);
|
|
12829
|
+
const replayed = await store.replay(path);
|
|
12830
|
+
if (replayed) return replayed.value;
|
|
12831
|
+
if (!context) fail("UNKNOWN_TOOL", `tools.${identifier} needs a run launched or recovered by a Pi tool call; runs resumed from /workflow or at session start, and headless launches, only replay journaled tool calls`);
|
|
12832
|
+
const render = async () => {
|
|
12833
|
+
try {
|
|
12834
|
+
const update = runs.get(store.runId)?.update;
|
|
12835
|
+
if (update) update(workflowToolUpdate(withLiveActivities((await store.load()).run)));
|
|
12836
|
+
} catch {
|
|
12837
|
+
}
|
|
12838
|
+
};
|
|
12839
|
+
const record3 = async (update) => {
|
|
12840
|
+
try {
|
|
12841
|
+
await store.updateState(update);
|
|
12842
|
+
} catch {
|
|
12843
|
+
}
|
|
12844
|
+
};
|
|
12845
|
+
let value;
|
|
12846
|
+
try {
|
|
12847
|
+
const tool = scriptTool(context, identifier);
|
|
12848
|
+
if (!tool) fail("UNKNOWN_TOOL", `tools.${identifier} is not a tool this session can call`);
|
|
12849
|
+
const cancelled = () => signal.aborted;
|
|
12850
|
+
if (cancelled()) fail("CANCELLED", "Workflow cancelled");
|
|
12851
|
+
await record3((run) => startScriptCall(run, { kind: "tool", name: tool.name, path, startedAt: Date.now() }));
|
|
12852
|
+
const finished = liveAgents.toolStarted(store.runId, tool.name);
|
|
12853
|
+
try {
|
|
12854
|
+
await render();
|
|
12855
|
+
const outcome = await context.executeTool(tool.name, args, { signal });
|
|
12856
|
+
if (cancelled()) fail("CANCELLED", "Workflow cancelled");
|
|
12857
|
+
value = scriptToolValue(tool, outcome);
|
|
12858
|
+
} finally {
|
|
12859
|
+
finished();
|
|
12860
|
+
}
|
|
12861
|
+
} catch (error) {
|
|
12862
|
+
const failure = error instanceof WorkflowError ? error : new WorkflowError("TOOL_FAILED", `tools.${identifier}: ${errorText(error)}`);
|
|
12863
|
+
await record3((run) => finishScriptCall(run, path, failure));
|
|
12864
|
+
throw failure;
|
|
12865
|
+
}
|
|
12866
|
+
await store.complete(path, value);
|
|
12867
|
+
await record3((run) => finishScriptCall(run, path));
|
|
12868
|
+
await render();
|
|
12869
|
+
return value;
|
|
12870
|
+
} finally {
|
|
12871
|
+
await lifecycle.leave();
|
|
12872
|
+
}
|
|
12873
|
+
};
|
|
12510
12874
|
const lifecycleFor = (store, state, metadata) => new RunLifecycle(state, async (next, previous, reason) => {
|
|
12511
12875
|
const run = runs.get(store.runId);
|
|
12512
12876
|
if (!run) throw new WorkflowError("INTERNAL_ERROR", `Unknown production run: ${store.runId}`);
|
|
@@ -12763,16 +13127,18 @@ Respond with workflow_respond.`);
|
|
|
12763
13127
|
return decision;
|
|
12764
13128
|
};
|
|
12765
13129
|
};
|
|
12766
|
-
const registerControlTool = (name, label, description, parameters, run) => {
|
|
13130
|
+
const registerControlTool = (name, label, description, parameters, outputSchema, run) => {
|
|
12767
13131
|
pi.registerTool({
|
|
12768
13132
|
name,
|
|
12769
13133
|
label,
|
|
12770
13134
|
description,
|
|
12771
13135
|
parameters,
|
|
13136
|
+
outputSchema,
|
|
13137
|
+
...workflowToolExposure(name, codemodeTools),
|
|
12772
13138
|
async execute(_id, params, signal, _onUpdate, ctx) {
|
|
12773
13139
|
try {
|
|
12774
13140
|
const result = await run(params, signal, ctx);
|
|
12775
|
-
return { content: [{ type: "text", text: result.text }], details: result.details };
|
|
13141
|
+
return { content: [{ type: "text", text: result.text }], details: result.details, structuredContent: result.structured };
|
|
12776
13142
|
} catch (error) {
|
|
12777
13143
|
throw mainAgentError(error);
|
|
12778
13144
|
}
|
|
@@ -12790,18 +13156,21 @@ Respond with workflow_respond.`);
|
|
|
12790
13156
|
"Workflow Respond",
|
|
12791
13157
|
"Approve or reject one pending workflow checkpoint or budget decision",
|
|
12792
13158
|
Type3.Object({ runId: Type3.String(), name: Type3.Optional(Type3.String()), proposalId: Type3.Optional(Type3.String()), approved: Type3.Boolean() }, { additionalProperties: false }),
|
|
13159
|
+
WORKFLOW_RESPOND_OUTPUT,
|
|
12793
13160
|
async (params, signal, ctx) => {
|
|
12794
13161
|
if (params.proposalId) {
|
|
12795
13162
|
const result = await recovery.answerBudgetDecision(params.runId, params.proposalId, params.approved, false, ctx, signal);
|
|
12796
13163
|
if (!result) {
|
|
12797
13164
|
const denied = { state: "budget_exhausted", approved: false, reason: "proposal_not_pending" };
|
|
12798
|
-
return { text: JSON.stringify(denied), details: denied };
|
|
13165
|
+
return { text: JSON.stringify(denied), details: denied, structured: denied };
|
|
12799
13166
|
}
|
|
12800
|
-
|
|
13167
|
+
const reason = params.approved ? "approved" : "rejected";
|
|
13168
|
+
return { text: completionControlContent(result, params.runId), details: { ...result, reason }, structured: { ...completionControlValue(result, params.runId), reason } };
|
|
12801
13169
|
}
|
|
12802
13170
|
if (!params.name) throw new WorkflowError("INVALID_METADATA", "workflow_respond requires name or proposalId");
|
|
12803
13171
|
const accepted = await answerCheckpoint(params.runId, params.name, params.approved);
|
|
12804
|
-
|
|
13172
|
+
const details = { accepted, state: accepted ? "checkpoint_answered" : "not_pending", approved: params.approved, reason: "checkpoint" };
|
|
13173
|
+
return { text: accepted ? "Checkpoint response accepted." : "Checkpoint is not awaiting a response.", details, structured: details };
|
|
12805
13174
|
}
|
|
12806
13175
|
);
|
|
12807
13176
|
registerControlTool(
|
|
@@ -12809,9 +13178,10 @@ Respond with workflow_respond.`);
|
|
|
12809
13178
|
"Workflow Stop",
|
|
12810
13179
|
"Stop an active workflow run by ID",
|
|
12811
13180
|
Type3.Object({ runId: Type3.String() }, { additionalProperties: false }),
|
|
13181
|
+
WORKFLOW_STOP_OUTPUT,
|
|
12812
13182
|
async (params) => {
|
|
12813
13183
|
const result = await stopWorkflowRun(params.runId);
|
|
12814
|
-
return { text: JSON.stringify(result), details: result };
|
|
13184
|
+
return { text: JSON.stringify(result), details: result, structured: result };
|
|
12815
13185
|
}
|
|
12816
13186
|
);
|
|
12817
13187
|
registerControlTool(
|
|
@@ -12819,9 +13189,10 @@ Respond with workflow_respond.`);
|
|
|
12819
13189
|
"Workflow Status",
|
|
12820
13190
|
"Read a compact summary of a workflow run in the current project",
|
|
12821
13191
|
WORKFLOW_STATUS_PARAMETERS,
|
|
13192
|
+
WORKFLOW_STATUS_OUTPUT,
|
|
12822
13193
|
async (params, _signal, ctx) => {
|
|
12823
13194
|
const result = await workflowStatusRun(params.runId, ctx);
|
|
12824
|
-
return { text: JSON.stringify(result), details: result };
|
|
13195
|
+
return { text: JSON.stringify(result), details: result, structured: result };
|
|
12825
13196
|
}
|
|
12826
13197
|
);
|
|
12827
13198
|
let catalogRegistered = false;
|
|
@@ -12834,13 +13205,15 @@ Respond with workflow_respond.`);
|
|
|
12834
13205
|
if (!catalog.functions.length && !hasAliases && !hasSettings) return;
|
|
12835
13206
|
pi.registerTool({
|
|
12836
13207
|
name: "workflow_catalog",
|
|
13208
|
+
...workflowToolExposure("workflow_catalog", codemodeTools),
|
|
13209
|
+
outputSchema: WORKFLOW_CATALOG_OUTPUT,
|
|
12837
13210
|
label: "Workflow Catalog",
|
|
12838
13211
|
description: "List reusable workflow functions and model aliases; pass `name` to load one entry in full",
|
|
12839
13212
|
parameters: Type3.Object({ name: Type3.Optional(Type3.String({ description: "Registered function or model alias name for full detail" })) }, { additionalProperties: false }),
|
|
12840
13213
|
async execute(_id, params = {}) {
|
|
12841
13214
|
const context = { cwd, projectTrusted: trustedProject, globalSettingsPath: workflowSettingsPath(extensionAgentDir) };
|
|
12842
13215
|
const result = params.name === void 0 ? registry.catalogIndex(context) : registry.catalogDetail(params.name, context);
|
|
12843
|
-
return { content: [{ type: "text", text: JSON.stringify(result) }], details: result };
|
|
13216
|
+
return { content: [{ type: "text", text: JSON.stringify(result) }], details: result, structuredContent: result };
|
|
12844
13217
|
},
|
|
12845
13218
|
renderCall(args, theme) {
|
|
12846
13219
|
const title = theme.fg("toolTitle", theme.bold("workflow_catalog"));
|
|
@@ -12869,9 +13242,9 @@ Respond with workflow_respond.`);
|
|
|
12869
13242
|
const captured = roleCapture(store, snapshot, definitions, project);
|
|
12870
13243
|
return { definitions, capture: (role, model) => captured.capture(role, model) };
|
|
12871
13244
|
};
|
|
12872
|
-
const activeSnapshotTools = (tools, active) => active === "session" ? new Set(tools.filter((tool) => pi
|
|
13245
|
+
const activeSnapshotTools = (tools, active) => active === "session" ? new Set(tools.filter((tool) => reachableTools(pi).includes(tool) && tool !== "workflow_catalog")) : new Set(tools.filter((tool) => active.has(tool) || tool === "workflow_catalog"));
|
|
12873
13246
|
const resumeLaunchPrologue = async (input) => {
|
|
12874
|
-
const active = new Set(pi
|
|
13247
|
+
const active = new Set(reachableTools(pi).filter((tool) => !INTERNAL_WORKFLOW_TOOLS.includes(tool)));
|
|
12875
13248
|
const missing = input.snapshot.tools.filter((tool) => tool !== "workflow_catalog").find((tool) => !active.has(tool));
|
|
12876
13249
|
if (missing) throw new WorkflowError("RESUME_INCOMPATIBLE", `Required tool is unavailable: ${missing}`);
|
|
12877
13250
|
const settingsPath = workflowSettingsPath(extensionAgentDir);
|
|
@@ -12961,6 +13334,7 @@ Respond with workflow_respond.`);
|
|
|
12961
13334
|
resumeRoles,
|
|
12962
13335
|
workflowAgentHandler,
|
|
12963
13336
|
shellForRun,
|
|
13337
|
+
toolForRun,
|
|
12964
13338
|
resolveWorktree,
|
|
12965
13339
|
checkpointBridge,
|
|
12966
13340
|
phaseBridge,
|
|
@@ -13035,9 +13409,10 @@ Respond with workflow_respond.`);
|
|
|
13035
13409
|
"Workflow Retry",
|
|
13036
13410
|
"Retry a failed workflow run by replaying its completed structural operations",
|
|
13037
13411
|
WORKFLOW_RETRY_PARAMETERS,
|
|
13412
|
+
WORKFLOW_RECOVERY_OUTPUT,
|
|
13038
13413
|
async (params, signal, ctx) => {
|
|
13039
13414
|
const result = await recovery.retryWorkflowRun(params.runId, ctx, signal, params.foreground, params.expectedState);
|
|
13040
|
-
return { text: completionControlContent(result), details: result };
|
|
13415
|
+
return { text: completionControlContent(result), details: result, structured: completionControlValue(result) };
|
|
13041
13416
|
}
|
|
13042
13417
|
);
|
|
13043
13418
|
registerControlTool(
|
|
@@ -13045,9 +13420,10 @@ Respond with workflow_respond.`);
|
|
|
13045
13420
|
"Workflow Resume",
|
|
13046
13421
|
"Resume an exhausted workflow with unchanged or patched aggregate budgets",
|
|
13047
13422
|
Type3.Object({ runId: Type3.String(), expectedState: Type3.Optional(Type3.String({ description: "Persisted source state observed before recovery" })), budget: Type3.Optional(Type3.Unknown()), foreground: Type3.Optional(Type3.Boolean({ description: "Override the source launch mode for this recovery" })) }, { additionalProperties: false }),
|
|
13423
|
+
WORKFLOW_RECOVERY_OUTPUT,
|
|
13048
13424
|
async (params, signal, ctx) => {
|
|
13049
13425
|
const result = await recovery.resumeWorkflowRun(params.runId, params.budget, ctx, signal, params.foreground, true, params.expectedState);
|
|
13050
|
-
return { text: completionControlContent(result), details: result };
|
|
13426
|
+
return { text: completionControlContent(result), details: result, structured: completionControlValue(result) };
|
|
13051
13427
|
}
|
|
13052
13428
|
);
|
|
13053
13429
|
const deliverStaleTerminal = async (store, run) => {
|
|
@@ -13179,6 +13555,8 @@ ${content}` };
|
|
|
13179
13555
|
description: WORKFLOW_TOOL_DESCRIPTION,
|
|
13180
13556
|
promptSnippet: WORKFLOW_TOOL_PROMPT_SNIPPET,
|
|
13181
13557
|
parameters: WORKFLOW_TOOL_PARAMETERS,
|
|
13558
|
+
outputSchema: WORKFLOW_LAUNCH_OUTPUT,
|
|
13559
|
+
prepareLoadout: prepareScriptToolLoadout,
|
|
13182
13560
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
13183
13561
|
let resolveDetached;
|
|
13184
13562
|
let foregroundStore;
|
|
@@ -13188,7 +13566,7 @@ ${content}` };
|
|
|
13188
13566
|
}) : void 0;
|
|
13189
13567
|
const detachedToolResult = (run) => {
|
|
13190
13568
|
const detached = { runId: run.id, state: "running", detached: true };
|
|
13191
|
-
return { content: [{ type: "text", text: JSON.stringify(detached) }], details: { ...detached, run, preview: `Moved workflow ${run.id} to background.` } };
|
|
13569
|
+
return { content: [{ type: "text", text: JSON.stringify(detached) }], details: { ...detached, run, preview: `Moved workflow ${run.id} to background.` }, structuredContent: detached };
|
|
13192
13570
|
};
|
|
13193
13571
|
try {
|
|
13194
13572
|
const headless = object(ctx) && ctx.headless === true;
|
|
@@ -13201,7 +13579,7 @@ ${content}` };
|
|
|
13201
13579
|
const inventory = modelInventory(rootModel, modelRegistry);
|
|
13202
13580
|
const knownModels = inventory.knownModels;
|
|
13203
13581
|
const availableModels = inventory.availableModels;
|
|
13204
|
-
const rootTools = pi
|
|
13582
|
+
const rootTools = reachableTools(pi).filter((name) => !INTERNAL_WORKFLOW_TOOLS.includes(name));
|
|
13205
13583
|
const trustedProject = projectTrusted(ctx);
|
|
13206
13584
|
const launchCwd = typeof ctx.cwd === "string" ? ctx.cwd : process.cwd();
|
|
13207
13585
|
const launch = workflowLaunchSettings(launchCwd, trustedProject, settingsPath, params.concurrency);
|
|
@@ -13219,6 +13597,8 @@ ${content}` };
|
|
|
13219
13597
|
if (trustedProject && launch.resolution.project.extensionSettings !== void 0) registry.validateExtensionSettings(launch.resolution.project.extensionSettings, { source: "project", cwd: ctx.cwd, projectTrusted: true, settingsPath: launch.resolution.projectSettingsPath });
|
|
13220
13598
|
const validated = validateWorkflowLaunchWithRegistry(params, { cwd: ctx.cwd, agentDir: extensionAgentDir, projectTrusted: trustedProject, availableModels, rootTools: new Set(rootTools), modelAliases, knownModels, settingsPath, ...settings.extensionSettings === void 0 ? {} : { extensionSettings: settings.extensionSettings } }, registry);
|
|
13221
13599
|
const { script, checked, agentDefinitions, projectAgentDefinitions, roleNames } = validated;
|
|
13600
|
+
const toolContext = scriptToolContext(ctx);
|
|
13601
|
+
validateScriptToolReferences(script, toolContext);
|
|
13222
13602
|
await ensureSessionLease(ctx.cwd, ctx.sessionManager.getSessionId());
|
|
13223
13603
|
const runId = randomUUID5();
|
|
13224
13604
|
const args = params.args ?? null;
|
|
@@ -13289,7 +13669,7 @@ ${content}` };
|
|
|
13289
13669
|
runs.set(runId, runRecord);
|
|
13290
13670
|
if (params.foreground && onUpdate) onUpdate(workflowToolUpdate((await store.load()).run));
|
|
13291
13671
|
scheduler.addRun(runId, settings.concurrency, () => runs.get(runId)?.budget.checkAgentLaunch(), settings.extensionSettings);
|
|
13292
|
-
const execution = runWorkflow(script, args, withWorkflowFunctions({ shell: (command, options, signal2, identity) => shellForRun(store, checked.metadata, lifecycle, command, options, signal2, identity), agent: workflowAgentHandler(store, checked.metadata, lifecycle, executor, ctx.cwd, runId, (role, model) => capturedRoles.capture(role, model)), worktree: async (owner) => resolveWorktree(store, checked.metadata, owner), checkpoint: checkpointBridge(runId, store, checked.metadata, () => runs.get(runId)?.foreground ?? foregroundAttached, ctx.hasUI ? ctx.ui : void 0, headless), phase: phaseBridge(store, checked.metadata, lifecycle), log: logBridge(store, lifecycle, checked.metadata.name) }, store, runContext, registry, settings.extensionSettings), runController.signal);
|
|
13672
|
+
const execution = runWorkflow(script, args, withWorkflowFunctions({ tool: (identifier, toolArgs, signal2, identity) => toolForRun(store, lifecycle, toolContext, identifier, toolArgs, signal2, identity), shell: (command, options, signal2, identity) => shellForRun(store, checked.metadata, lifecycle, command, options, signal2, identity), agent: workflowAgentHandler(store, checked.metadata, lifecycle, executor, ctx.cwd, runId, (role, model) => capturedRoles.capture(role, model)), worktree: async (owner) => resolveWorktree(store, checked.metadata, owner), checkpoint: checkpointBridge(runId, store, checked.metadata, () => runs.get(runId)?.foreground ?? foregroundAttached, ctx.hasUI ? ctx.ui : void 0, headless), phase: phaseBridge(store, checked.metadata, lifecycle), log: logBridge(store, lifecycle, checked.metadata.name) }, store, runContext, registry, settings.extensionSettings), runController.signal);
|
|
13293
13673
|
runRecord.execution = execution;
|
|
13294
13674
|
await eventPublisher.runStarted(store, checked.metadata);
|
|
13295
13675
|
const finish = execution.result.then(async (value2) => {
|
|
@@ -13327,7 +13707,7 @@ ${content}` };
|
|
|
13327
13707
|
}, async (error) => {
|
|
13328
13708
|
await deliveryController.deliverTerminal(store, deliverFailureContent(error), true);
|
|
13329
13709
|
});
|
|
13330
|
-
return { content: [{ type: "text", text: JSON.stringify({ runId, state: "running" }) }], details: { runId, preview: `Started workflow ${runId}.` } };
|
|
13710
|
+
return { content: [{ type: "text", text: JSON.stringify({ runId, state: "running" }) }], details: { runId, preview: `Started workflow ${runId}.` }, structuredContent: { runId, state: "running" } };
|
|
13331
13711
|
}
|
|
13332
13712
|
void completion.then(async (result) => {
|
|
13333
13713
|
await deliveryController.deliverDetachedTerminal(toolCallId, completionContent("background", result));
|
|
@@ -13349,7 +13729,7 @@ ${content}` };
|
|
|
13349
13729
|
}
|
|
13350
13730
|
deliveryController.foregroundDeliveries.delete(toolCallId);
|
|
13351
13731
|
const run = (await store.load()).run;
|
|
13352
|
-
return { content: [{ type: "text", text: foregroundDelivery.content }, ...foregroundDelivery.inlined ? [{ type: "text", text: `Workflow run ID: ${runId}` }] : []], details: { runId, value, run } };
|
|
13732
|
+
return { content: [{ type: "text", text: foregroundDelivery.content }, ...foregroundDelivery.inlined ? [{ type: "text", text: `Workflow run ID: ${runId}` }] : []], details: { runId, value, run }, structuredContent: { runId, state: "completed", value } };
|
|
13353
13733
|
} catch (error) {
|
|
13354
13734
|
if (params.foreground && foregroundStore && completionInstalled) {
|
|
13355
13735
|
const claim = await deliveryController.claimForegroundDelivery(foregroundStore, toolCallId);
|
|
@@ -13429,7 +13809,7 @@ ${content}` };
|
|
|
13429
13809
|
return textBlock(isPartial ? "Workflow starting..." : runDetails?.preview ?? (content?.type === "text" ? content.text : "Workflow finished"));
|
|
13430
13810
|
}
|
|
13431
13811
|
};
|
|
13432
|
-
pi.registerTool(workflowTool);
|
|
13812
|
+
pi.registerTool({ ...workflowTool, ...workflowToolExposure(workflowTool.name, codemodeTools) });
|
|
13433
13813
|
registerWorkflowNavigator({ pi, home, clipboard, extensionAgentDir, runs, terminalRunStates, hardTerminalRunStates: HARD_TERMINAL_RUN_STATES, ensureSessionLease, coordinateRunMutation, answerCheckpoint, recovery, stopWorkflowRun, moveForegroundToBackground: deliveryController.moveForegroundToBackground, isForegroundAttached: deliveryController.isForegroundAttached, liveAgents, registry, projectTrusted, resumeHostContext, resumeSelectedWorkflow, reportBlocked: reportWorkflowBlocked, trajectoryProvider, setNavigatorOpen: (open3) => {
|
|
13434
13814
|
if (open3) backgroundWidgetController.suspend();
|
|
13435
13815
|
else backgroundWidgetController.resume();
|
|
@@ -13458,6 +13838,7 @@ ${content}` };
|
|
|
13458
13838
|
}
|
|
13459
13839
|
var LiveAgentRegistry = class {
|
|
13460
13840
|
#byRun = /* @__PURE__ */ new Map();
|
|
13841
|
+
#tools = /* @__PURE__ */ new Map();
|
|
13461
13842
|
get(runId, agentId) {
|
|
13462
13843
|
return this.#byRun.get(runId)?.get(agentId);
|
|
13463
13844
|
}
|
|
@@ -13486,19 +13867,32 @@ var LiveAgentRegistry = class {
|
|
|
13486
13867
|
setEventTime(runId, agentId, timestamp) {
|
|
13487
13868
|
if (timestamp !== void 0) this.#state(runId, agentId).lastEventAt = timestamp;
|
|
13488
13869
|
}
|
|
13870
|
+
/** Marks a script tool call in flight until the returned callback runs. */
|
|
13871
|
+
toolStarted(runId, name) {
|
|
13872
|
+
const call = { name, startedAt: Date.now() };
|
|
13873
|
+
const calls = this.#tools.get(runId) ?? /* @__PURE__ */ new Set();
|
|
13874
|
+
this.#tools.set(runId, calls.add(call));
|
|
13875
|
+
return () => {
|
|
13876
|
+
calls.delete(call);
|
|
13877
|
+
if (!calls.size && this.#tools.get(runId) === calls) this.#tools.delete(runId);
|
|
13878
|
+
};
|
|
13879
|
+
}
|
|
13489
13880
|
deleteRun(runId) {
|
|
13490
13881
|
this.#byRun.delete(runId);
|
|
13882
|
+
this.#tools.delete(runId);
|
|
13491
13883
|
}
|
|
13492
|
-
/** Overlays live activity and
|
|
13884
|
+
/** Overlays live activity, freshness, and script tool calls onto a persisted run; returns the input when nothing is live. */
|
|
13493
13885
|
overlay(run) {
|
|
13886
|
+
const tools = this.#tools.get(run.id);
|
|
13887
|
+
const withTools = tools?.size ? { ...run, activeTools: [...tools].map((call) => ({ ...call })) } : run;
|
|
13494
13888
|
const agents = this.#byRun.get(run.id);
|
|
13495
|
-
if (!agents?.size) return
|
|
13889
|
+
if (!agents?.size) return withTools;
|
|
13496
13890
|
const next = run.agents.map((agent) => {
|
|
13497
13891
|
const live = agents.get(agent.id);
|
|
13498
13892
|
if (!live || live.activity === void 0 && live.lastEventAt === void 0) return agent;
|
|
13499
13893
|
return { ...agent, ...live.activity === void 0 ? {} : { activity: live.activity }, ...live.lastEventAt === void 0 ? {} : { lastEventAt: live.lastEventAt } };
|
|
13500
13894
|
});
|
|
13501
|
-
return next.some((agent, index) => agent !== run.agents[index]) ? { ...
|
|
13895
|
+
return next.some((agent, index) => agent !== run.agents[index]) ? { ...withTools, agents: next } : withTools;
|
|
13502
13896
|
}
|
|
13503
13897
|
#state(runId, agentId) {
|
|
13504
13898
|
const agents = this.#byRun.get(runId) ?? /* @__PURE__ */ new Map();
|
|
@@ -13835,6 +14229,7 @@ export {
|
|
|
13835
14229
|
SessionLease,
|
|
13836
14230
|
THINKING_LEVELS,
|
|
13837
14231
|
TOOL_TIMING_ENTRY_TYPE,
|
|
14232
|
+
VIRTUAL_MODEL_PROVIDER,
|
|
13838
14233
|
WORKFLOW_AGENT_STALL_THRESHOLD_MS,
|
|
13839
14234
|
WORKFLOW_AGENT_STATE_CHANGED_EVENT,
|
|
13840
14235
|
WORKFLOW_BLOCKED_EVENT,
|
|
@@ -13936,10 +14331,12 @@ export {
|
|
|
13936
14331
|
isTurnEnd,
|
|
13937
14332
|
isWorkflowAuthored,
|
|
13938
14333
|
isWorkflowErrorCode,
|
|
14334
|
+
jsonDigest,
|
|
13939
14335
|
jsonObject,
|
|
13940
14336
|
jsonValue,
|
|
13941
14337
|
listPersistedSessionIds,
|
|
13942
14338
|
loadAgentDefinitions,
|
|
14339
|
+
loadCodemodeToolsSetting,
|
|
13943
14340
|
loadLaunchSnapshot,
|
|
13944
14341
|
loadProjectAgentDefinitions,
|
|
13945
14342
|
loadRole,
|
|
@@ -13969,6 +14366,7 @@ export {
|
|
|
13969
14366
|
parseThinking,
|
|
13970
14367
|
persistActiveAgentAttempt,
|
|
13971
14368
|
persistAgentAttempts,
|
|
14369
|
+
physicalModel,
|
|
13972
14370
|
positiveInteger,
|
|
13973
14371
|
preflight,
|
|
13974
14372
|
prepareAgentSetupForInspection,
|
|
@@ -13977,6 +14375,7 @@ export {
|
|
|
13977
14375
|
progressStyleForState,
|
|
13978
14376
|
projectSessionsDirectory,
|
|
13979
14377
|
projectStorageKey,
|
|
14378
|
+
reachableTools,
|
|
13980
14379
|
readShellResult,
|
|
13981
14380
|
registerWorkflowExtension,
|
|
13982
14381
|
registeredWorkflowFunctionSources,
|
|
@@ -14002,11 +14401,13 @@ export {
|
|
|
14002
14401
|
sameFilesystemPath,
|
|
14003
14402
|
sanitizeDisplayText,
|
|
14004
14403
|
saveModelAliases,
|
|
14404
|
+
scriptToolReferences,
|
|
14005
14405
|
selectResourcesByLayers,
|
|
14006
14406
|
shellIdentityPath,
|
|
14007
14407
|
structuralPath,
|
|
14008
14408
|
sumAccounting,
|
|
14009
14409
|
themeWorkflowProgressStyles,
|
|
14410
|
+
toolIdentityPath,
|
|
14010
14411
|
truncateWorkflowProgress,
|
|
14011
14412
|
unknownModel,
|
|
14012
14413
|
unmatchedResourcePatterns,
|
|
@@ -14042,6 +14443,7 @@ export {
|
|
|
14042
14443
|
workflowRoleDirectories,
|
|
14043
14444
|
workflowScriptArtifact,
|
|
14044
14445
|
workflowSettingsPath,
|
|
14446
|
+
workflowToolExposure,
|
|
14045
14447
|
zeroAccounting
|
|
14046
14448
|
};
|
|
14047
14449
|
//# sourceMappingURL=index.js.map
|