pi-task-dispatcher 3.2.0 → 3.2.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/extensions/task-dispatcher.ts +44 -61
- package/package.json +1 -1
|
@@ -104,7 +104,6 @@ interface WorkerAction {
|
|
|
104
104
|
|
|
105
105
|
/** Keep one replaceable presentation record for each assistant response or child tool lifecycle. */
|
|
106
106
|
interface WorkerPresentationEntry {
|
|
107
|
-
sequence: number;
|
|
108
107
|
id: string;
|
|
109
108
|
kind: "assistant" | "tool";
|
|
110
109
|
label: string;
|
|
@@ -253,7 +252,6 @@ interface ProxyWireResult {
|
|
|
253
252
|
}
|
|
254
253
|
|
|
255
254
|
interface ExecutorLease {
|
|
256
|
-
generation: number;
|
|
257
255
|
rootToolCallId: string;
|
|
258
256
|
ctx: ExtensionToolContext;
|
|
259
257
|
signal: AbortSignal | undefined;
|
|
@@ -880,7 +878,7 @@ class WorkerJob {
|
|
|
880
878
|
private requestSequence = 0;
|
|
881
879
|
private actionSequence = 0;
|
|
882
880
|
private completionSequence = 0;
|
|
883
|
-
private
|
|
881
|
+
private assistantIdSequence = 0;
|
|
884
882
|
private readonly presentationEntries: WorkerPresentationEntry[] = [];
|
|
885
883
|
private readonly presentationById = new Map<string, WorkerPresentationEntry>();
|
|
886
884
|
private readonly assistantTextBlocks = new Map<number, string>();
|
|
@@ -899,7 +897,6 @@ class WorkerJob {
|
|
|
899
897
|
private pausedLease: ReturnType<typeof setTimeout> | undefined;
|
|
900
898
|
private closePromise: Promise<void> | undefined;
|
|
901
899
|
private executorLease: ExecutorLease | undefined;
|
|
902
|
-
private executorLeaseSequence = 0;
|
|
903
900
|
private readonly proxyRequests = new Map<string, ProxyRequestState>();
|
|
904
901
|
private readonly seenProxyRequests = new Set<string>();
|
|
905
902
|
|
|
@@ -1315,8 +1312,7 @@ class WorkerJob {
|
|
|
1315
1312
|
if (this.activeAssistantPresentation) return this.activeAssistantPresentation;
|
|
1316
1313
|
this.assistantTextBlocks.clear();
|
|
1317
1314
|
const entry: WorkerPresentationEntry = {
|
|
1318
|
-
|
|
1319
|
-
id: `assistant-${this.presentationSequence}`,
|
|
1315
|
+
id: `assistant-${++this.assistantIdSequence}`,
|
|
1320
1316
|
kind: "assistant",
|
|
1321
1317
|
label: "assistant",
|
|
1322
1318
|
status: "streaming",
|
|
@@ -1365,7 +1361,6 @@ class WorkerJob {
|
|
|
1365
1361
|
if (existing) return existing;
|
|
1366
1362
|
const action = this.activeActions.get(toolCallId);
|
|
1367
1363
|
const entry: WorkerPresentationEntry = {
|
|
1368
|
-
sequence: ++this.presentationSequence,
|
|
1369
1364
|
id,
|
|
1370
1365
|
kind: "tool",
|
|
1371
1366
|
label: action?.label ?? formatActivity(toolName, args),
|
|
@@ -1580,7 +1575,7 @@ class WorkerJob {
|
|
|
1580
1575
|
}
|
|
1581
1576
|
|
|
1582
1577
|
/** Enforce selected capabilities during a lease and reject delayed calls from every revoked lease. */
|
|
1583
|
-
authorizeNestedToolCall(
|
|
1578
|
+
authorizeNestedToolCall(parentToolCallId: string | undefined, toolName: string): { block: boolean; reason: string } | undefined {
|
|
1584
1579
|
if (!parentToolCallId) return undefined;
|
|
1585
1580
|
const lease = this.executorLease;
|
|
1586
1581
|
if (lease && (parentToolCallId === lease.rootToolCallId || parentToolCallId.startsWith(`${lease.rootToolCallId}/`))) {
|
|
@@ -1595,7 +1590,7 @@ class WorkerJob {
|
|
|
1595
1590
|
/** Grant parent execution only while a start or continuation call actively owns the worker. */
|
|
1596
1591
|
private openExecutorLease(rootToolCallId: string, ctx: ExtensionToolContext, signal: AbortSignal | undefined): ExecutorLease {
|
|
1597
1592
|
if (this.executorLease) throw new Error("A manager executor lease is already active for this worker.");
|
|
1598
|
-
const lease: ExecutorLease = {
|
|
1593
|
+
const lease: ExecutorLease = { rootToolCallId, ctx, signal };
|
|
1599
1594
|
this.executorLease = lease;
|
|
1600
1595
|
return lease;
|
|
1601
1596
|
}
|
|
@@ -1692,43 +1687,41 @@ class WorkerJob {
|
|
|
1692
1687
|
removeParentAbort: lease.signal ? () => lease.signal?.removeEventListener("abort", abortFromParent) : undefined,
|
|
1693
1688
|
};
|
|
1694
1689
|
this.proxyRequests.set(requestId, request);
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
if (this.executorLease !== lease || this.proxyRequests.get(requestId) !== request) return;
|
|
1701
|
-
this.sendProxy({
|
|
1702
|
-
type: "task_dispatcher_proxy_update",
|
|
1703
|
-
nonce: this.proxyNonce,
|
|
1704
|
-
requestId,
|
|
1705
|
-
result: serializeProxyResult(partial),
|
|
1706
|
-
});
|
|
1707
|
-
},
|
|
1708
|
-
});
|
|
1709
|
-
if (this.executorLease === lease && this.proxyRequests.get(requestId) === request) {
|
|
1710
|
-
this.sendProxy({
|
|
1711
|
-
type: "task_dispatcher_proxy_result",
|
|
1712
|
-
nonce: this.proxyNonce,
|
|
1713
|
-
requestId,
|
|
1714
|
-
result: serializeProxyResult(outcome.result, outcome.isError),
|
|
1715
|
-
});
|
|
1716
|
-
}
|
|
1717
|
-
} catch (error) {
|
|
1718
|
-
if (this.executorLease === lease && this.proxyRequests.get(requestId) === request) {
|
|
1690
|
+
try {
|
|
1691
|
+
const outcome = await lease.ctx.executeTool(message.toolName as string, args, {
|
|
1692
|
+
signal: controller.signal,
|
|
1693
|
+
onUpdate: (partial) => {
|
|
1694
|
+
if (this.executorLease !== lease || this.proxyRequests.get(requestId) !== request) return;
|
|
1719
1695
|
this.sendProxy({
|
|
1720
|
-
type: "
|
|
1696
|
+
type: "task_dispatcher_proxy_update",
|
|
1721
1697
|
nonce: this.proxyNonce,
|
|
1722
1698
|
requestId,
|
|
1723
|
-
result:
|
|
1699
|
+
result: serializeProxyResult(partial),
|
|
1724
1700
|
});
|
|
1725
|
-
}
|
|
1726
|
-
}
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1701
|
+
},
|
|
1702
|
+
});
|
|
1703
|
+
if (this.executorLease === lease && this.proxyRequests.get(requestId) === request) {
|
|
1704
|
+
this.sendProxy({
|
|
1705
|
+
type: "task_dispatcher_proxy_result",
|
|
1706
|
+
nonce: this.proxyNonce,
|
|
1707
|
+
requestId,
|
|
1708
|
+
result: serializeProxyResult(outcome.result, outcome.isError),
|
|
1709
|
+
});
|
|
1730
1710
|
}
|
|
1731
|
-
}
|
|
1711
|
+
} catch (error) {
|
|
1712
|
+
if (this.executorLease === lease && this.proxyRequests.get(requestId) === request) {
|
|
1713
|
+
this.sendProxy({
|
|
1714
|
+
type: "task_dispatcher_proxy_result",
|
|
1715
|
+
nonce: this.proxyNonce,
|
|
1716
|
+
requestId,
|
|
1717
|
+
result: proxyErrorResult(`Manager execution of ${message.toolName as string} failed: ${error instanceof Error ? error.message : String(error)}`),
|
|
1718
|
+
});
|
|
1719
|
+
}
|
|
1720
|
+
} finally {
|
|
1721
|
+
request.removeParentAbort?.();
|
|
1722
|
+
request.removeParentAbort = undefined;
|
|
1723
|
+
if (this.proxyRequests.get(requestId) === request) this.proxyRequests.delete(requestId);
|
|
1724
|
+
}
|
|
1732
1725
|
}
|
|
1733
1726
|
|
|
1734
1727
|
/** Propagate a child-side proxy cancellation to the current manager nested-tool signal. */
|
|
@@ -1851,7 +1844,7 @@ class WorkerJob {
|
|
|
1851
1844
|
let activeJob: WorkerJob | undefined;
|
|
1852
1845
|
let lastSnapshot: WorkerSnapshot | undefined;
|
|
1853
1846
|
const latestRoleSnapshots = new Map<Role, WorkerSnapshot>();
|
|
1854
|
-
|
|
1847
|
+
let reportedUsage: { jobId: string; usage: UsageTotals } | undefined;
|
|
1855
1848
|
|
|
1856
1849
|
/** Resolve role overrides against the active parent model without assuming provider availability. */
|
|
1857
1850
|
function resolveWorkerConfig(config: WorkerRoleConfig, ctx: ExtensionToolContext): { role: ResolvedWorkerRoleConfig; contextWindow: number; maxTokens: number } {
|
|
@@ -1965,7 +1958,7 @@ function buildDelegatedToolManifests(requested: string[], pi: ExtensionAPI, ctx:
|
|
|
1965
1958
|
if (executionMode !== undefined && executionMode !== "sequential" && executionMode !== "parallel") {
|
|
1966
1959
|
throw new Error(`Delegated tool ${name} has unsupported execution-mode metadata.`);
|
|
1967
1960
|
}
|
|
1968
|
-
const
|
|
1961
|
+
const manifest: Omit<DelegatedToolManifest, "fingerprint"> = {
|
|
1969
1962
|
name,
|
|
1970
1963
|
label,
|
|
1971
1964
|
description,
|
|
@@ -1975,19 +1968,10 @@ function buildDelegatedToolManifests(requested: string[], pi: ExtensionAPI, ctx:
|
|
|
1975
1968
|
...(annotations === undefined ? {} : { annotations }),
|
|
1976
1969
|
...(promptGuidelines === undefined ? {} : { promptGuidelines }),
|
|
1977
1970
|
...(executionMode === undefined ? {} : { executionMode }),
|
|
1978
|
-
|
|
1979
|
-
}, `${name} delegated manifest`);
|
|
1971
|
+
};
|
|
1980
1972
|
return {
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
description,
|
|
1984
|
-
parameters,
|
|
1985
|
-
...(outputSchema === undefined ? {} : { outputSchema }),
|
|
1986
|
-
...(namespace === undefined ? {} : { namespace }),
|
|
1987
|
-
...(annotations === undefined ? {} : { annotations }),
|
|
1988
|
-
...(promptGuidelines === undefined ? {} : { promptGuidelines }),
|
|
1989
|
-
...(executionMode === undefined ? {} : { executionMode }),
|
|
1990
|
-
fingerprint: stableJson(comparable),
|
|
1973
|
+
...manifest,
|
|
1974
|
+
fingerprint: stableJson(cloneJsonValue({ ...manifest, sourceInfo }, `${name} delegated manifest`)),
|
|
1991
1975
|
};
|
|
1992
1976
|
});
|
|
1993
1977
|
assertJsonByteLimit(manifests as unknown as JsonValue, "delegated tool manifest", PROXY_MANIFEST_LIMIT_BYTES);
|
|
@@ -2246,12 +2230,11 @@ function renderWorkerResult(
|
|
|
2246
2230
|
/** Package a snapshot as bounded model content plus complete machine-readable details. */
|
|
2247
2231
|
function snapshotResult(snapshot: WorkerSnapshot, isError = false): { content: Array<{ type: "text"; text: string }>; details: WorkerSnapshot; usage: UsageTotals; isError: boolean } {
|
|
2248
2232
|
lastSnapshot = snapshot;
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
const previous = reportedUsage.get(snapshot.jobId) ?? emptyUsage();
|
|
2233
|
+
const previous = reportedUsage && reportedUsage.jobId === snapshot.jobId
|
|
2234
|
+
? reportedUsage.usage
|
|
2235
|
+
: emptyUsage();
|
|
2253
2236
|
const usage = usageDifference(snapshot.usage, previous);
|
|
2254
|
-
reportedUsage
|
|
2237
|
+
reportedUsage = { jobId: snapshot.jobId, usage: structuredClone(snapshot.usage) };
|
|
2255
2238
|
return {
|
|
2256
2239
|
content: [{ type: "text", text: formatSnapshot(snapshot) }],
|
|
2257
2240
|
details: snapshot,
|
|
@@ -2433,7 +2416,7 @@ export default function taskDispatcher(pi: ExtensionAPI): void {
|
|
|
2433
2416
|
registerControl(pi);
|
|
2434
2417
|
registerStatus(pi);
|
|
2435
2418
|
pi.on("tool_call", (event) => activeJob
|
|
2436
|
-
? activeJob.authorizeNestedToolCall(event.
|
|
2419
|
+
? activeJob.authorizeNestedToolCall(event.parentToolCallId, event.toolName)
|
|
2437
2420
|
: revokedExecutorDecision(event.parentToolCallId, event.toolName));
|
|
2438
2421
|
pi.on("session_shutdown", async () => {
|
|
2439
2422
|
if (activeJob) await activeJob.dispose();
|