@arnilo/prism-supervisor 0.0.96 → 0.1.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 +117 -4
- package/README.md +2 -2
- package/dist/a2a-card.js +19 -7
- package/dist/a2a-client.js +345 -65
- package/dist/a2a-event-source.d.ts +42 -0
- package/dist/a2a-event-source.js +40 -0
- package/dist/a2a-parts.js +109 -19
- package/dist/a2a-push.js +10 -2
- package/dist/a2a-server.js +239 -88
- package/dist/a2a-types.d.ts +12 -1
- package/dist/errors.js +12 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/limits.js +4 -1
- package/dist/supervisor.js +180 -26
- package/dist/types.d.ts +23 -1
- package/package.json +2 -2
package/dist/a2a-types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentRunResult, AgentSession, OwnershipScope, SecretRedactor } from "@arnilo/prism";
|
|
1
|
+
import type { AgentIdentity, AgentRunResult, AgentSession, OwnershipScope, SecretRedactor } from "@arnilo/prism";
|
|
2
2
|
export declare const A2A_PROTOCOL_VERSION = "1.0";
|
|
3
3
|
export interface A2AAgentInterface {
|
|
4
4
|
readonly url: string;
|
|
@@ -113,6 +113,11 @@ export type A2ATaskEvent = {
|
|
|
113
113
|
readonly lastChunk?: boolean;
|
|
114
114
|
};
|
|
115
115
|
};
|
|
116
|
+
/** A streaming response may be a task lifecycle or one direct message. */
|
|
117
|
+
export type A2AStreamEvent = A2ATaskEvent | {
|
|
118
|
+
readonly eventId: string;
|
|
119
|
+
readonly message: A2AMessage;
|
|
120
|
+
};
|
|
116
121
|
export type A2ARequestId = string | number | null;
|
|
117
122
|
export interface A2AJsonRpcRequest {
|
|
118
123
|
readonly jsonrpc: "2.0";
|
|
@@ -132,6 +137,8 @@ export interface A2AJsonRpcResponse {
|
|
|
132
137
|
}
|
|
133
138
|
export interface A2AAuthorization {
|
|
134
139
|
readonly ownership: OwnershipScope;
|
|
140
|
+
/** Host-verified identity; when set must project onto ownership without widening. */
|
|
141
|
+
readonly identity?: AgentIdentity;
|
|
135
142
|
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
136
143
|
}
|
|
137
144
|
export type A2AAuthorizer = (input: {
|
|
@@ -284,6 +291,10 @@ export interface A2AClient {
|
|
|
284
291
|
stream(input: string, options?: {
|
|
285
292
|
readonly signal?: AbortSignal;
|
|
286
293
|
}): AsyncIterable<string>;
|
|
294
|
+
/** Rich `SendStreamingMessage` events. Host-supplied messages remain subject to client bounds/card verification. */
|
|
295
|
+
streamMessage(message: A2AMessage, options?: {
|
|
296
|
+
readonly signal?: AbortSignal;
|
|
297
|
+
}): AsyncIterable<A2AStreamEvent>;
|
|
287
298
|
getTask(id: string, options?: {
|
|
288
299
|
readonly signal?: AbortSignal;
|
|
289
300
|
readonly historyLength?: number;
|
package/dist/errors.js
CHANGED
|
@@ -7,13 +7,22 @@ export class SupervisorError extends Error {
|
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
export class SupervisorValidationError extends SupervisorError {
|
|
10
|
-
constructor(message) {
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super(message, "ERR_PRISM_SUPERVISOR_VALIDATION");
|
|
12
|
+
this.name = "SupervisorValidationError";
|
|
13
|
+
}
|
|
11
14
|
}
|
|
12
15
|
export class SupervisorLimitError extends SupervisorError {
|
|
13
|
-
constructor(message) {
|
|
16
|
+
constructor(message) {
|
|
17
|
+
super(message, "ERR_PRISM_SUPERVISOR_LIMIT");
|
|
18
|
+
this.name = "SupervisorLimitError";
|
|
19
|
+
}
|
|
14
20
|
}
|
|
15
21
|
export class SupervisorDeniedError extends SupervisorError {
|
|
16
|
-
constructor(message = "Delegation denied") {
|
|
22
|
+
constructor(message = "Delegation denied") {
|
|
23
|
+
super(message, "ERR_PRISM_SUPERVISOR_DENIED");
|
|
24
|
+
this.name = "SupervisorDeniedError";
|
|
25
|
+
}
|
|
17
26
|
}
|
|
18
27
|
export class A2AError extends SupervisorError {
|
|
19
28
|
status;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/limits.js
CHANGED
|
@@ -37,6 +37,9 @@ export function narrowSupervisorLimits(parent, input) {
|
|
|
37
37
|
if (!input)
|
|
38
38
|
return parent;
|
|
39
39
|
const requested = resolveSupervisorLimits({ ...parent, ...input });
|
|
40
|
-
return Object.fromEntries(Object.keys(SPECS).map((key) => [
|
|
40
|
+
return Object.fromEntries(Object.keys(SPECS).map((key) => [
|
|
41
|
+
key,
|
|
42
|
+
Math.min(parent[key], requested[key]),
|
|
43
|
+
]));
|
|
41
44
|
}
|
|
42
45
|
//# sourceMappingURL=limits.js.map
|
package/dist/supervisor.js
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
import { AgentRunError, createAgent, createEventMultiplexer, } from "@arnilo/prism";
|
|
1
|
+
import { AgentDelegationSuspendedError, AgentRunError, assertIdentityActive, assertIdentityMatchesOwnership, createAgent, createEventMultiplexer, resumeAgentRun, } from "@arnilo/prism";
|
|
2
2
|
import { SupervisorDeniedError, SupervisorError, SupervisorLimitError, SupervisorValidationError } from "./errors.js";
|
|
3
3
|
import { narrowSupervisorLimits, resolveSupervisorLimits } from "./limits.js";
|
|
4
4
|
const ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
|
|
5
|
+
const DELEGATION_NAMESPACE = "prism.supervisor-delegation";
|
|
5
6
|
export function createSupervisor(options) {
|
|
6
7
|
requireOwnership(options.ownership);
|
|
8
|
+
if (options.checkpoints && !options.definitionRevision?.trim()) {
|
|
9
|
+
throw new SupervisorValidationError("definitionRevision is required when checkpoints are configured");
|
|
10
|
+
}
|
|
11
|
+
if (options.identity) {
|
|
12
|
+
assertIdentityActive(options.identity);
|
|
13
|
+
assertIdentityMatchesOwnership(options.identity, options.ownership);
|
|
14
|
+
}
|
|
7
15
|
const id = options.id ?? "supervisor";
|
|
8
16
|
if (!ID.test(id))
|
|
9
17
|
throw new SupervisorValidationError("Supervisor id is invalid");
|
|
@@ -80,6 +88,8 @@ export function createSupervisor(options) {
|
|
|
80
88
|
depth,
|
|
81
89
|
path,
|
|
82
90
|
ownership: options.ownership,
|
|
91
|
+
identity: options.identity,
|
|
92
|
+
effectStore: options.effectStore,
|
|
83
93
|
resourceId,
|
|
84
94
|
threadId,
|
|
85
95
|
permission: preliminaryPermission,
|
|
@@ -90,9 +100,14 @@ export function createSupervisor(options) {
|
|
|
90
100
|
...childAgent.config,
|
|
91
101
|
permission: intersectPolicies(preliminaryPermission, childAgent.config.permission),
|
|
92
102
|
ownership: options.ownership,
|
|
103
|
+
identity: options.identity ?? childAgent.config.identity,
|
|
104
|
+
effectStore: options.effectStore ?? childAgent.config.effectStore,
|
|
93
105
|
redactor: options.redactor ?? childAgent.config.redactor,
|
|
94
106
|
});
|
|
95
|
-
const session = agent.createSession({
|
|
107
|
+
const session = agent.createSession({
|
|
108
|
+
id: `${delegationId}-session`,
|
|
109
|
+
metadata: { supervisorId: id, delegationId, resourceId, threadId },
|
|
110
|
+
});
|
|
96
111
|
let result;
|
|
97
112
|
try {
|
|
98
113
|
result = await abortable(session.run(input, {
|
|
@@ -106,37 +121,72 @@ export function createSupervisor(options) {
|
|
|
106
121
|
ownership: options.ownership,
|
|
107
122
|
redactor: options.redactor,
|
|
108
123
|
metadata: { ...request.metadata, supervisorId: id, delegationId, resourceId, threadId, depth },
|
|
124
|
+
...(options.checkpoints
|
|
125
|
+
? {
|
|
126
|
+
runState: {
|
|
127
|
+
checkpoints: options.checkpoints,
|
|
128
|
+
definitionRevision: options.definitionRevision,
|
|
129
|
+
interruptBeforeTool: true,
|
|
130
|
+
resumeNestedRun,
|
|
131
|
+
},
|
|
132
|
+
}
|
|
133
|
+
: {}),
|
|
109
134
|
}), controller.signal);
|
|
110
135
|
}
|
|
111
136
|
catch (error) {
|
|
112
137
|
if (error instanceof AgentRunError && error.result.limit) {
|
|
113
|
-
const label = error.result.limit.limit === "maxTotalTokens"
|
|
114
|
-
|
|
115
|
-
|
|
138
|
+
const label = error.result.limit.limit === "maxTotalTokens"
|
|
139
|
+
? "token"
|
|
140
|
+
: error.result.limit.limit === "maxToolCalls"
|
|
141
|
+
? "tool-call"
|
|
142
|
+
: error.result.limit.limit === "maxWallTimeMs"
|
|
143
|
+
? "timeout"
|
|
116
144
|
: "run";
|
|
117
145
|
throw new SupervisorLimitError(`Delegation ${label} limit exceeded`);
|
|
118
146
|
}
|
|
119
147
|
throw error;
|
|
120
148
|
}
|
|
121
|
-
|
|
149
|
+
if (result.status === "suspended") {
|
|
150
|
+
// Child approvals surface on the hosting root run: persist the rebuild mapping, then
|
|
151
|
+
// signal core with the child's pending decisions (core hashes/attributes the ids).
|
|
152
|
+
const pending = result.interruption?.pendingDecisions;
|
|
153
|
+
const version = result.runState?.version;
|
|
154
|
+
if (!pending?.length || version === undefined) {
|
|
155
|
+
throw new SupervisorError("Child run suspended without a pending-decision set");
|
|
156
|
+
}
|
|
157
|
+
await saveMapping(result.runId, {
|
|
158
|
+
childId: request.childId,
|
|
159
|
+
delegationId,
|
|
160
|
+
threadId,
|
|
161
|
+
path,
|
|
162
|
+
version,
|
|
163
|
+
input,
|
|
164
|
+
});
|
|
165
|
+
throw new AgentDelegationSuspendedError({ runId: result.runId, sessionId: result.sessionId }, pending, path);
|
|
166
|
+
}
|
|
167
|
+
const totalTokens = result.usage?.totalTokens ?? (result.usage?.inputTokens ?? 0) + (result.usage?.outputTokens ?? 0);
|
|
122
168
|
events.publish({ type: "delegation_finished", childId: request.childId, delegationId, depth, status: result.status, totalTokens });
|
|
123
169
|
await complete(toCompletion(result, request.childId, delegationId, depth, options));
|
|
124
170
|
completionSent = true;
|
|
125
171
|
return result;
|
|
126
172
|
}
|
|
127
173
|
catch (error) {
|
|
174
|
+
if (error instanceof AgentDelegationSuspendedError)
|
|
175
|
+
throw error;
|
|
128
176
|
if (!(error instanceof SupervisorDeniedError && completionSent)) {
|
|
129
177
|
const result = error instanceof AgentRunError ? error.result : undefined;
|
|
130
178
|
const message = safeError(error, options);
|
|
131
179
|
events.publish({ type: "delegation_error", childId: request.childId, delegationId, depth, error: message });
|
|
132
|
-
await complete(result
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
180
|
+
await complete(result
|
|
181
|
+
? toCompletion(result, request.childId, delegationId, depth, options)
|
|
182
|
+
: {
|
|
183
|
+
childId: request.childId,
|
|
184
|
+
delegationId,
|
|
185
|
+
depth,
|
|
186
|
+
status: controller.signal.aborted ? "aborted" : "rejected",
|
|
187
|
+
text: "",
|
|
188
|
+
error: message,
|
|
189
|
+
});
|
|
140
190
|
}
|
|
141
191
|
if (error instanceof AgentRunError || error instanceof SupervisorError)
|
|
142
192
|
throw error;
|
|
@@ -148,6 +198,91 @@ export function createSupervisor(options) {
|
|
|
148
198
|
activeChildren -= 1;
|
|
149
199
|
}
|
|
150
200
|
}
|
|
201
|
+
async function saveMapping(runId, mapping) {
|
|
202
|
+
const existing = await options.checkpoints.loadCheckpoint({ namespace: DELEGATION_NAMESPACE, key: runId });
|
|
203
|
+
await options.checkpoints.saveCheckpoint({
|
|
204
|
+
namespace: DELEGATION_NAMESPACE,
|
|
205
|
+
key: runId,
|
|
206
|
+
version: (existing?.version ?? 0) + 1,
|
|
207
|
+
expectedVersion: existing?.version,
|
|
208
|
+
value: mapping,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
const resumeNestedRun = async (nested, decisions) => {
|
|
212
|
+
const checkpoints = options.checkpoints;
|
|
213
|
+
if (!checkpoints || !options.definitionRevision) {
|
|
214
|
+
throw new SupervisorValidationError("Nested-run resume requires supervisor checkpoints and definitionRevision");
|
|
215
|
+
}
|
|
216
|
+
const record = await checkpoints.loadCheckpoint({ namespace: DELEGATION_NAMESPACE, key: nested.ref.runId });
|
|
217
|
+
const mapping = record?.value;
|
|
218
|
+
// Non-enumerating: unknown and foreign run ids share one error.
|
|
219
|
+
if (!mapping || typeof mapping.childId !== "string" || typeof mapping.version !== "number") {
|
|
220
|
+
throw new SupervisorDeniedError("Unknown delegated run");
|
|
221
|
+
}
|
|
222
|
+
const child = options.children[mapping.childId];
|
|
223
|
+
if (!child)
|
|
224
|
+
throw new SupervisorDeniedError("Unknown delegated run");
|
|
225
|
+
const depth = mapping.path.length;
|
|
226
|
+
const controller = new AbortController();
|
|
227
|
+
let limits = narrowSupervisorLimits(baseLimits, child.limits);
|
|
228
|
+
let hookPermission;
|
|
229
|
+
// The before-hook re-runs at resume so its narrowing applies exactly as it did to the
|
|
230
|
+
// original run; hooks must be idempotent (same contract as core resume guardrails).
|
|
231
|
+
if (options.hooks?.before) {
|
|
232
|
+
const decision = await options.hooks.before(Object.freeze({
|
|
233
|
+
childId: mapping.childId,
|
|
234
|
+
delegationId: mapping.delegationId,
|
|
235
|
+
depth,
|
|
236
|
+
path: mapping.path,
|
|
237
|
+
input: mapping.input,
|
|
238
|
+
limits,
|
|
239
|
+
metadata: undefined,
|
|
240
|
+
signal: controller.signal,
|
|
241
|
+
}));
|
|
242
|
+
if (decision.allowed === false) {
|
|
243
|
+
return { status: "failed", code: "delegation_denied", message: safeError(decision.reason ?? "Delegation denied", options) };
|
|
244
|
+
}
|
|
245
|
+
limits = narrowSupervisorLimits(limits, decision.limits);
|
|
246
|
+
hookPermission = decision.permission;
|
|
247
|
+
}
|
|
248
|
+
const resourceId = `${id}/${mapping.delegationId}/${mapping.childId}`;
|
|
249
|
+
const permission = intersectPolicies(options.permission, child.permission, hookPermission, toolBudgetPolicy(limits.maxToolCalls));
|
|
250
|
+
const childAgent = await child.createAgent(Object.freeze({
|
|
251
|
+
childId: mapping.childId,
|
|
252
|
+
delegationId: mapping.delegationId,
|
|
253
|
+
depth,
|
|
254
|
+
path: mapping.path,
|
|
255
|
+
ownership: options.ownership,
|
|
256
|
+
identity: options.identity,
|
|
257
|
+
effectStore: options.effectStore,
|
|
258
|
+
resourceId,
|
|
259
|
+
threadId: mapping.threadId,
|
|
260
|
+
permission,
|
|
261
|
+
signal: controller.signal,
|
|
262
|
+
delegate: (nestedRequest) => delegate(nestedRequest, { path: mapping.path, signal: controller.signal }),
|
|
263
|
+
}));
|
|
264
|
+
const agent = createAgent({
|
|
265
|
+
...childAgent.config,
|
|
266
|
+
permission: intersectPolicies(permission, childAgent.config.permission),
|
|
267
|
+
ownership: options.ownership,
|
|
268
|
+
identity: options.identity ?? childAgent.config.identity,
|
|
269
|
+
effectStore: options.effectStore ?? childAgent.config.effectStore,
|
|
270
|
+
redactor: options.redactor ?? childAgent.config.redactor,
|
|
271
|
+
});
|
|
272
|
+
const result = await resumeAgentRun(agent, { runId: nested.ref.runId, ...(nested.ref.sessionId ? { sessionId: nested.ref.sessionId } : {}) }, { decisions, expectedVersion: mapping.version }, { checkpoints, definitionRevision: options.definitionRevision, ownership: options.ownership, resumeNestedRun });
|
|
273
|
+
if (result.status === "suspended") {
|
|
274
|
+
await saveMapping(nested.ref.runId, { ...mapping, version: result.runState?.version ?? mapping.version });
|
|
275
|
+
return { status: "suspended", pendingDecisions: result.interruption?.pendingDecisions ?? [] };
|
|
276
|
+
}
|
|
277
|
+
if (result.status === "succeeded") {
|
|
278
|
+
return { status: "completed", value: options.redactor?.redact(result.text) ?? result.text };
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
status: "failed",
|
|
282
|
+
code: result.status === "denied" ? "delegation_denied" : "delegation_failed",
|
|
283
|
+
message: safeError(result.error?.message ?? `Delegated run ${result.status}`, options),
|
|
284
|
+
};
|
|
285
|
+
};
|
|
151
286
|
async function complete(value) {
|
|
152
287
|
if (!options.hooks?.after)
|
|
153
288
|
return;
|
|
@@ -155,10 +290,23 @@ export function createSupervisor(options) {
|
|
|
155
290
|
await options.hooks.after(Object.freeze(value));
|
|
156
291
|
}
|
|
157
292
|
catch (error) {
|
|
158
|
-
events.publish({
|
|
293
|
+
events.publish({
|
|
294
|
+
type: "delegation_error",
|
|
295
|
+
childId: value.childId,
|
|
296
|
+
delegationId: value.delegationId,
|
|
297
|
+
depth: value.depth,
|
|
298
|
+
error: safeError(error, options),
|
|
299
|
+
});
|
|
159
300
|
}
|
|
160
301
|
}
|
|
161
|
-
return {
|
|
302
|
+
return {
|
|
303
|
+
delegate: (request) => delegate(request),
|
|
304
|
+
resumeNestedRun,
|
|
305
|
+
subscribe: () => events.subscribe(),
|
|
306
|
+
get activeChildren() {
|
|
307
|
+
return activeChildren;
|
|
308
|
+
},
|
|
309
|
+
};
|
|
162
310
|
}
|
|
163
311
|
function toCompletion(result, childId, delegationId, depth, options) {
|
|
164
312
|
return Object.freeze({
|
|
@@ -173,23 +321,27 @@ function toCompletion(result, childId, delegationId, depth, options) {
|
|
|
173
321
|
}
|
|
174
322
|
function intersectPolicies(...policies) {
|
|
175
323
|
const active = policies.filter((policy) => policy !== undefined);
|
|
176
|
-
return {
|
|
324
|
+
return {
|
|
325
|
+
async check(request) {
|
|
177
326
|
for (const policy of active) {
|
|
178
327
|
const decision = await policy.check(request);
|
|
179
328
|
if (!decision.allowed)
|
|
180
329
|
return decision;
|
|
181
330
|
}
|
|
182
331
|
return { allowed: true };
|
|
183
|
-
}
|
|
332
|
+
},
|
|
333
|
+
};
|
|
184
334
|
}
|
|
185
335
|
function toolBudgetPolicy(max) {
|
|
186
336
|
let count = 0;
|
|
187
|
-
return {
|
|
337
|
+
return {
|
|
338
|
+
check(request) {
|
|
188
339
|
if (request.kind !== "tool" || request.action !== "execute")
|
|
189
340
|
return { allowed: true };
|
|
190
341
|
count += 1;
|
|
191
342
|
return count <= max ? { allowed: true } : { allowed: false, reason: "Delegation tool-call limit exceeded" };
|
|
192
|
-
}
|
|
343
|
+
},
|
|
344
|
+
};
|
|
193
345
|
}
|
|
194
346
|
function linkSignals(controller, ...signals) {
|
|
195
347
|
const removers = [];
|
|
@@ -204,8 +356,10 @@ function linkSignals(controller, ...signals) {
|
|
|
204
356
|
removers.push(() => signal.removeEventListener("abort", abort));
|
|
205
357
|
}
|
|
206
358
|
}
|
|
207
|
-
return () => {
|
|
208
|
-
remove
|
|
359
|
+
return () => {
|
|
360
|
+
for (const remove of removers)
|
|
361
|
+
remove();
|
|
362
|
+
};
|
|
209
363
|
}
|
|
210
364
|
function abortable(promise, signal) {
|
|
211
365
|
if (signal.aborted)
|
|
@@ -221,10 +375,10 @@ function assertBytes(value, max, label) {
|
|
|
221
375
|
throw new SupervisorLimitError(`${label} exceeds max bytes`);
|
|
222
376
|
}
|
|
223
377
|
function requireOwnership(ownership) {
|
|
224
|
-
if (!ownership.tenantId?.trim()
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
378
|
+
if (!ownership.tenantId?.trim() ||
|
|
379
|
+
(ownership.accountId !== undefined && !ownership.accountId.trim()) ||
|
|
380
|
+
(ownership.userId !== undefined && !ownership.userId.trim()) ||
|
|
381
|
+
(!ownership.accountId && !ownership.userId))
|
|
228
382
|
throw new SupervisorValidationError("tenantId and non-empty accountId or userId are required");
|
|
229
383
|
}
|
|
230
384
|
function safeError(error, options) {
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Agent, AgentRunResult, OwnershipScope, PermissionPolicy, SecretRedactor } from "@arnilo/prism";
|
|
1
|
+
import type { Agent, AgentIdentity, AgentRunResult, CheckpointStore, OwnershipScope, PermissionPolicy, ResumeNestedRun, SecretRedactor, ToolEffectStore } from "@arnilo/prism";
|
|
2
2
|
import type { ResolvedSupervisorLimits, SupervisorLimits } from "./limits.js";
|
|
3
3
|
export interface DelegationRequest {
|
|
4
4
|
readonly childId: string;
|
|
@@ -14,6 +14,10 @@ export interface DelegationChildContext {
|
|
|
14
14
|
readonly depth: number;
|
|
15
15
|
readonly path: readonly string[];
|
|
16
16
|
readonly ownership: OwnershipScope;
|
|
17
|
+
/** Parent-verified identity; child factories cannot widen it. */
|
|
18
|
+
readonly identity?: AgentIdentity;
|
|
19
|
+
/** One shared durable effect store for every child run. */
|
|
20
|
+
readonly effectStore?: ToolEffectStore;
|
|
17
21
|
readonly resourceId: string;
|
|
18
22
|
readonly threadId: string;
|
|
19
23
|
readonly permission: PermissionPolicy;
|
|
@@ -86,14 +90,32 @@ export type SupervisorEvent = {
|
|
|
86
90
|
export interface CreateSupervisorOptions {
|
|
87
91
|
readonly id?: string;
|
|
88
92
|
readonly ownership: OwnershipScope;
|
|
93
|
+
/** Optional parent-verified identity, propagated unchanged to every child. */
|
|
94
|
+
readonly identity?: AgentIdentity;
|
|
95
|
+
/** Optional parent effect store, propagated unchanged to every child. */
|
|
96
|
+
readonly effectStore?: ToolEffectStore;
|
|
89
97
|
readonly children: Readonly<Record<string, SupervisorChild>>;
|
|
90
98
|
readonly permission?: PermissionPolicy;
|
|
91
99
|
readonly limits?: SupervisorLimits;
|
|
92
100
|
readonly hooks?: SupervisorHooks;
|
|
93
101
|
readonly redactor?: SecretRedactor;
|
|
102
|
+
/**
|
|
103
|
+
* Durable child runs: with `checkpoints` + `definitionRevision`, every child runs with
|
|
104
|
+
* `interruptBeforeTool`; a child that suspends on pending decisions throws
|
|
105
|
+
* `AgentDelegationSuspendedError` so the hosting root run can surface them.
|
|
106
|
+
*/
|
|
107
|
+
readonly checkpoints?: CheckpointStore;
|
|
108
|
+
/** Host-authored revision shared by child durable runs; bump on policy/definition change. */
|
|
109
|
+
readonly definitionRevision?: string;
|
|
94
110
|
}
|
|
95
111
|
export interface Supervisor {
|
|
96
112
|
delegate(request: DelegationRequest): Promise<AgentRunResult>;
|
|
113
|
+
/**
|
|
114
|
+
* Routes root-run decisions back to the suspended child. Pass as `resumeNestedRun` in the
|
|
115
|
+
* root run's `runState` (sticky auto-apply) and every `resumeAgentRun` options object.
|
|
116
|
+
* Throws when `checkpoints`/`definitionRevision` are not configured.
|
|
117
|
+
*/
|
|
118
|
+
readonly resumeNestedRun: ResumeNestedRun;
|
|
97
119
|
subscribe(): AsyncIterable<SupervisorEvent>;
|
|
98
120
|
readonly activeChildren: number;
|
|
99
121
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arnilo/prism-supervisor",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Bounded supervisor delegation and A2A 1.0 durable task, rich-part, reconnect, and push interoperability.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"pack:dry-run": "npm pack --dry-run"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"@arnilo/prism": "0.0
|
|
28
|
+
"@arnilo/prism": "0.1.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@arnilo/prism": "file:../.."
|