pi-subagents 0.55.0 → 0.56.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -3
- package/docs/models.md +6 -0
- package/package.json +1 -1
- package/src/agents/agent-serializer.ts +2 -0
- package/src/agents/agents.ts +23 -1
- package/src/api/preflight.ts +20 -1
- package/src/extension/schemas.ts +5 -0
- package/src/runs/background/async-execution.ts +48 -18
- package/src/runs/background/async-resume.ts +3 -0
- package/src/runs/background/subagent-runner.ts +83 -11
- package/src/runs/foreground/execution.ts +35 -6
- package/src/runs/foreground/foreground-history.ts +3 -2
- package/src/runs/foreground/subagent-executor.ts +59 -8
- package/src/runs/foreground/workflow-detach-reconcile.ts +15 -6
- package/src/runs/shared/acceptance.ts +10 -5
- package/src/runs/shared/agent-contract.ts +1 -1
- package/src/runs/shared/completion-guard.ts +3 -2
- package/src/runs/shared/dynamic-fanout.ts +1 -1
- package/src/runs/shared/extension-bindings.ts +78 -0
- package/src/runs/shared/external-cli-runner.ts +2 -0
- package/src/runs/shared/fast-mode-extension.ts +10 -0
- package/src/runs/shared/model-exclusions.ts +2 -1
- package/src/runs/shared/model-fallback.ts +2 -7
- package/src/runs/shared/mutation-evidence.ts +145 -0
- package/src/runs/shared/parallel-utils.ts +3 -0
- package/src/runs/shared/pi-args.ts +47 -0
- package/src/runs/shared/structured-output.ts +18 -4
- package/src/runs/shared/subagent-prompt-runtime.ts +9 -5
- package/src/shared/launch-contract.ts +6 -0
- package/src/shared/settings.ts +6 -1
- package/src/shared/types.ts +48 -0
- package/src/workflows/scripted-workflow.ts +50 -3
|
@@ -150,7 +150,15 @@ function trackObservationTracker(tracker, promise, allowFutureObservations = fal
|
|
|
150
150
|
get(promiseTarget, prop) {
|
|
151
151
|
if (prop === "then") return function promiseThen(onFulfilled, onRejected) {
|
|
152
152
|
consumeTrackedObservations(tracker);
|
|
153
|
-
|
|
153
|
+
const chainTracker = { observations: tracker.observations, consumed: false, dependencies: [tracker] };
|
|
154
|
+
const wrapHandler = (handler) => typeof handler === "function"
|
|
155
|
+
? function trackedThenHandler(...args) {
|
|
156
|
+
const value = handler.apply(this, args);
|
|
157
|
+
addTrackerDependency(chainTracker, promiseObservationTracker(value));
|
|
158
|
+
return trackedPromiseTarget(value);
|
|
159
|
+
}
|
|
160
|
+
: handler;
|
|
161
|
+
return trackObservationTracker(chainTracker, promiseTarget.then(wrapHandler(onFulfilled), wrapHandler(onRejected)), true);
|
|
154
162
|
};
|
|
155
163
|
if (prop === "catch") return function promiseCatch(onRejected) {
|
|
156
164
|
consumeTrackedObservations(tracker);
|
|
@@ -276,8 +284,43 @@ function formatRef(result) {
|
|
|
276
284
|
return "[" + parts.join("; ") + "]";
|
|
277
285
|
}
|
|
278
286
|
|
|
287
|
+
function formatChildResultString(result) {
|
|
288
|
+
const output = typeof result?.output === "string" ? result.output.trim() : "";
|
|
289
|
+
return output || formatRef(result);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function decorateWorkflowChildResult(result) {
|
|
293
|
+
if (!result || typeof result !== "object" || Array.isArray(result)) return result;
|
|
294
|
+
Object.defineProperties(result, {
|
|
295
|
+
toString: { value() { return formatChildResultString(this); }, enumerable: false, configurable: true },
|
|
296
|
+
});
|
|
297
|
+
return result;
|
|
298
|
+
}
|
|
299
|
+
|
|
279
300
|
let runFingerprints = new Map();
|
|
280
301
|
|
|
302
|
+
function validateExtensionBindings(value, label) {
|
|
303
|
+
if (value === undefined) return;
|
|
304
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(label + " extensionBindings must be a plain JSON object.");
|
|
305
|
+
const keys = Object.keys(value);
|
|
306
|
+
if (keys.length > 16) throw new Error(label + " extensionBindings supports at most 16 namespaces.");
|
|
307
|
+
for (const key of keys) if (!/^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,62})\/[1-9][0-9]{0,8}$/.test(key)) throw new Error(label + " extensionBindings namespace '" + key + "' must use a package-like name followed by '/<positive-version>'.");
|
|
308
|
+
assertJsonValue(value, label + " extensionBindings");
|
|
309
|
+
let propertyCount = 0;
|
|
310
|
+
function visit(entry, depth) {
|
|
311
|
+
if (!entry || typeof entry !== "object") return;
|
|
312
|
+
if (depth > 16) throw new Error(label + " extensionBindings exceeds the maximum nesting depth of 16.");
|
|
313
|
+
if (Array.isArray(entry)) { for (const item of entry) visit(item, depth + 1); return; }
|
|
314
|
+
for (const child of Object.values(entry)) {
|
|
315
|
+
propertyCount++;
|
|
316
|
+
if (propertyCount > 256) throw new Error(label + " extensionBindings exceeds 256 total properties.");
|
|
317
|
+
visit(child, depth + 1);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
visit(value, 0);
|
|
321
|
+
if (new TextEncoder().encode(stableRunJson(value)).byteLength > 16384) throw new Error(label + " extensionBindings canonical JSON exceeds 16384 bytes.");
|
|
322
|
+
}
|
|
323
|
+
|
|
281
324
|
function validateRunCall(key, params, label, fingerprints) {
|
|
282
325
|
if (typeof key !== "string" || !runKeyPattern.test(key)) throw new Error(label + " has an invalid key.");
|
|
283
326
|
if (!params || typeof params !== "object" || Array.isArray(params)) throw new Error(label + " requires a params object.");
|
|
@@ -290,6 +333,7 @@ function validateRunCall(key, params, label, fingerprints) {
|
|
|
290
333
|
if (params.gate !== undefined && (typeof params.gate !== "string" || !params.gate.trim())) throw new Error(label + " gate must be a non-empty command string.");
|
|
291
334
|
if (params.gate !== undefined && params.acceptance !== undefined) throw new Error(label + " gate cannot be combined with acceptance; use one gate command or acceptance.verify.");
|
|
292
335
|
if (params.gate !== undefined && params.resume !== undefined) throw new Error(label + " gate is not supported with retained resume.");
|
|
336
|
+
if (params.extensionBindings !== undefined && params.resume !== undefined) throw new Error(label + " extensionBindings is not supported with retained resume; resume uses the original retained child binding.");
|
|
293
337
|
if (params.resume !== undefined && typeof params.resume !== "string") {
|
|
294
338
|
const reference = params.resume;
|
|
295
339
|
if (!reference || typeof reference !== "object" || Array.isArray(reference)) throw new Error(label + " resume must be a retained run id or keyed workflow receipt reference.");
|
|
@@ -302,6 +346,7 @@ function validateRunCall(key, params, label, fingerprints) {
|
|
|
302
346
|
if (typeof params.resume === "string" && !params.resume.trim()) throw new Error(label + " resume must be a non-empty retained run id.");
|
|
303
347
|
if (params.resume !== undefined && params.agent !== undefined) throw new Error(label + " resume and agent are mutually exclusive.");
|
|
304
348
|
if (params.resume !== undefined && (typeof params.task !== "string" || !params.task.trim())) throw new Error(label + " resume requires a non-empty task follow-up.");
|
|
349
|
+
validateExtensionBindings(params.extensionBindings, label);
|
|
305
350
|
assertJsonValue(params, label + " params");
|
|
306
351
|
const fingerprint = stableRunJson(params);
|
|
307
352
|
const existing = fingerprints.get(key);
|
|
@@ -312,7 +357,8 @@ function validateRunCall(key, params, label, fingerprints) {
|
|
|
312
357
|
const runs = Object.freeze({
|
|
313
358
|
run(key, params) {
|
|
314
359
|
validateRunCall(key, params, "runs.run", runFingerprints);
|
|
315
|
-
|
|
360
|
+
const launched = runHostCall(key, params, false);
|
|
361
|
+
return trackRunObservation([{ key, operation: "run", callId: launched.callId }], launched.promise.then(decorateWorkflowChildResult));
|
|
316
362
|
},
|
|
317
363
|
all(items) {
|
|
318
364
|
if (!Array.isArray(items)) throw new Error("runs.all(items) requires an array.");
|
|
@@ -329,7 +375,7 @@ const runs = Object.freeze({
|
|
|
329
375
|
runFingerprints = fingerprints;
|
|
330
376
|
const batch = { id: "batch-" + (++nextCallId), calls };
|
|
331
377
|
const launched = calls.map(({ key, params }) => runHostCall(key, params, true, batch));
|
|
332
|
-
return trackRunObservation(launched.map(({ key, callId }) => ({ key, operation: "run", callId })), Promise.all(launched.map(({ promise }) => promise)).then((results) => wrapRunsAllResults(results, calls.map(({ key }) => key))));
|
|
378
|
+
return trackRunObservation(launched.map(({ key, callId }) => ({ key, operation: "run", callId })), Promise.all(launched.map(({ promise }) => promise)).then((results) => wrapRunsAllResults(results.map(decorateWorkflowChildResult), calls.map(({ key }) => key))));
|
|
333
379
|
},
|
|
334
380
|
steer(key, message, options = {}) {
|
|
335
381
|
if (typeof key !== "string" || !runKeyPattern.test(key)) throw new Error("runs.steer has an invalid key.");
|
|
@@ -599,6 +645,7 @@ export interface WorkflowScriptChildResult {
|
|
|
599
645
|
output: string;
|
|
600
646
|
error?: string;
|
|
601
647
|
detached?: boolean;
|
|
648
|
+
interrupted?: boolean;
|
|
602
649
|
structuredOutput?: unknown;
|
|
603
650
|
requestedContext?: "fresh" | "fork";
|
|
604
651
|
resolvedContext?: "fresh" | "fork" | "mixed";
|