@agen-ai/agent-runtime 0.2.2 → 0.2.4
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/README.md +30 -8
- package/dist/configurationValidation.js +12 -17
- package/dist/contractErrors.d.ts +2 -2
- package/dist/contractErrors.js +6 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/interactionValidation.d.ts +23 -0
- package/dist/interactionValidation.js +238 -0
- package/dist/outputValidation.d.ts +4 -1
- package/dist/outputValidation.js +42 -4
- package/dist/sessionValidation.js +761 -18
- package/dist/sessions.d.ts +73 -4
- package/dist/testing/conformance.d.ts +5 -2
- package/dist/testing/conformance.js +166 -5
- package/dist/testing/fakeProvider.js +220 -17
- package/package.json +2 -2
|
@@ -1,17 +1,33 @@
|
|
|
1
1
|
import {
|
|
2
|
+
AGENT_COLLABORATION_GRAPH_LIMITS,
|
|
2
3
|
matchesAgentSessionBinding,
|
|
4
|
+
parseAgentCollaborationControlInput,
|
|
5
|
+
parseAgentCollaborationSpawnInput,
|
|
6
|
+
parseAgentConfigurationSelectionFor,
|
|
7
|
+
parseAgentGeneratedResourceId,
|
|
8
|
+
parseAgentOperationInvocation,
|
|
9
|
+
parseAgentOperationInvocationFor,
|
|
3
10
|
parseAgentRequestResolution,
|
|
4
11
|
parseAgentRequestResolutionFor,
|
|
5
12
|
parseAgentSessionBinding,
|
|
6
|
-
parseAgentSessionConfiguration,
|
|
7
13
|
parseAgentTurnId,
|
|
8
14
|
parseAgentTurnInputContent,
|
|
9
15
|
parseAgentTurnInterruptionInput,
|
|
10
16
|
parseAgentTurnRunInput
|
|
11
17
|
} from "@agen-ai/agent-protocol";
|
|
12
18
|
import {
|
|
13
|
-
|
|
14
|
-
} from "./
|
|
19
|
+
createAgentArtifactCandidate
|
|
20
|
+
} from "./artifacts.js";
|
|
21
|
+
import {
|
|
22
|
+
validateAgentCollaborationNodeForCapabilities,
|
|
23
|
+
validateAgentConfigurationCatalogForCapabilities,
|
|
24
|
+
validateAgentGeneratedResourceForCapabilities,
|
|
25
|
+
validateAgentIntegrationCatalogForCapabilities,
|
|
26
|
+
validateAgentManagedContentCatalogForCapabilities,
|
|
27
|
+
validateAgentOperationCatalogForCapabilities,
|
|
28
|
+
validateAgentOperationResultForInvocation,
|
|
29
|
+
validateAgentOperationResultTransition
|
|
30
|
+
} from "./interactionValidation.js";
|
|
15
31
|
import {
|
|
16
32
|
AgentProviderDelegatedOperationError,
|
|
17
33
|
throwAgentProviderContractError
|
|
@@ -24,15 +40,59 @@ import {
|
|
|
24
40
|
validateAgentProviderOutputForContext
|
|
25
41
|
} from "./outputValidation.js";
|
|
26
42
|
import { validateAgentTurnSteeringResult } from "./steeringValidation.js";
|
|
43
|
+
function hasExactOwnKeys(candidate, expectedKeys) {
|
|
44
|
+
const ownKeys = Reflect.ownKeys(candidate);
|
|
45
|
+
if (ownKeys.some((key) => typeof key !== "string")) return false;
|
|
46
|
+
const actualKeys = ownKeys.sort();
|
|
47
|
+
const canonicalExpectedKeys = [...expectedKeys].sort();
|
|
48
|
+
return actualKeys.length === canonicalExpectedKeys.length && actualKeys.every((key, index) => key === canonicalExpectedKeys[index]);
|
|
49
|
+
}
|
|
27
50
|
function validateSessionPorts(capabilities, session) {
|
|
28
|
-
if (
|
|
51
|
+
if (!hasExactOwnKeys(session, [
|
|
52
|
+
"binding",
|
|
53
|
+
"runTurn",
|
|
54
|
+
"resolveRequest",
|
|
55
|
+
"interruption",
|
|
56
|
+
"steering",
|
|
57
|
+
"configuration",
|
|
58
|
+
"operations",
|
|
59
|
+
"managedContent",
|
|
60
|
+
"integrations",
|
|
61
|
+
"collaboration",
|
|
62
|
+
"generatedResources",
|
|
63
|
+
"close"
|
|
64
|
+
]) || typeof session.runTurn !== "function" || typeof session.resolveRequest !== "function" || typeof session.close !== "function" || session.interruption === null || typeof session.interruption !== "object" || !["supported", "unsupported"].includes(session.interruption.kind) || session.steering === null || typeof session.steering !== "object" || !["supported", "unsupported"].includes(session.steering.kind) || session.configuration === null || typeof session.configuration !== "object" || !["managed", "selectable"].includes(session.configuration.kind) || session.operations === null || typeof session.operations !== "object" || !["supported", "unsupported"].includes(session.operations.kind) || session.managedContent === null || typeof session.managedContent !== "object" || !["supported", "unsupported"].includes(session.managedContent.kind) || session.integrations === null || typeof session.integrations !== "object" || !["supported", "unsupported"].includes(session.integrations.kind) || session.collaboration === null || typeof session.collaboration !== "object" || !["supported", "unsupported"].includes(session.collaboration.kind) || session.generatedResources === null || typeof session.generatedResources !== "object" || !["supported", "unsupported"].includes(session.generatedResources.kind)) {
|
|
29
65
|
throwAgentProviderContractError(
|
|
30
66
|
capabilities.providerKey,
|
|
31
67
|
"invalid_session",
|
|
32
68
|
`Provider ${capabilities.providerKey} returned an incomplete session.`
|
|
33
69
|
);
|
|
34
70
|
}
|
|
35
|
-
if (
|
|
71
|
+
if (!hasExactOwnKeys(
|
|
72
|
+
session.interruption,
|
|
73
|
+
session.interruption.kind === "supported" ? ["kind", "interruptTurn"] : ["kind"]
|
|
74
|
+
) || !hasExactOwnKeys(
|
|
75
|
+
session.steering,
|
|
76
|
+
session.steering.kind === "supported" ? ["kind", "steerTurn"] : ["kind"]
|
|
77
|
+
) || !hasExactOwnKeys(
|
|
78
|
+
session.configuration,
|
|
79
|
+
session.configuration.kind === "selectable" ? ["kind", "listConfiguration", "applyConfigurationSelection"] : ["kind"]
|
|
80
|
+
) || !hasExactOwnKeys(
|
|
81
|
+
session.operations,
|
|
82
|
+
session.operations.kind === "supported" ? ["kind", "listOperations", "invokeOperation"] : ["kind"]
|
|
83
|
+
) || !hasExactOwnKeys(
|
|
84
|
+
session.managedContent,
|
|
85
|
+
session.managedContent.kind === "supported" ? ["kind", "listManagedContent"] : ["kind"]
|
|
86
|
+
) || !hasExactOwnKeys(
|
|
87
|
+
session.integrations,
|
|
88
|
+
session.integrations.kind === "supported" ? ["kind", "observeIntegrations"] : ["kind"]
|
|
89
|
+
) || !hasExactOwnKeys(
|
|
90
|
+
session.collaboration,
|
|
91
|
+
session.collaboration.kind === "supported" ? ["kind", "spawnCollaboration", "controlCollaboration"] : ["kind"]
|
|
92
|
+
) || !hasExactOwnKeys(
|
|
93
|
+
session.generatedResources,
|
|
94
|
+
session.generatedResources.kind === "supported" ? ["kind", "getGeneratedResource"] : ["kind"]
|
|
95
|
+
) || session.interruption.kind === "supported" !== capabilities.turns.interrupt || session.steering.kind === "supported" !== (capabilities.turns.steer.kind === "supported") || session.configuration.kind !== capabilities.configuration.kind || session.interruption.kind === "supported" && typeof session.interruption.interruptTurn !== "function" || session.steering.kind === "supported" && typeof session.steering.steerTurn !== "function" || session.configuration.kind === "selectable" && (typeof session.configuration.listConfiguration !== "function" || typeof session.configuration.applyConfigurationSelection !== "function") || session.operations.kind === "supported" !== (capabilities.operations.kind === "supported") || session.operations.kind === "supported" && (typeof session.operations.listOperations !== "function" || typeof session.operations.invokeOperation !== "function") || session.managedContent.kind === "supported" !== (capabilities.managedContent.kind === "supported") || session.managedContent.kind === "supported" && typeof session.managedContent.listManagedContent !== "function" || session.integrations.kind === "supported" !== (capabilities.integrations.kind === "supported") || session.integrations.kind === "supported" && typeof session.integrations.observeIntegrations !== "function" || session.collaboration.kind === "supported" !== (capabilities.collaboration.kind === "supported") || session.collaboration.kind === "supported" && (typeof session.collaboration.spawnCollaboration !== "function" || typeof session.collaboration.controlCollaboration !== "function") || session.generatedResources.kind === "supported" !== (capabilities.generatedResources.kind === "supported") || session.generatedResources.kind === "supported" && typeof session.generatedResources.getGeneratedResource !== "function") {
|
|
36
96
|
throwAgentProviderContractError(
|
|
37
97
|
capabilities.providerKey,
|
|
38
98
|
"capability_port_mismatch",
|
|
@@ -40,6 +100,58 @@ function validateSessionPorts(capabilities, session) {
|
|
|
40
100
|
);
|
|
41
101
|
}
|
|
42
102
|
}
|
|
103
|
+
const TERMINAL_COLLABORATION_STATUSES = /* @__PURE__ */ new Set([
|
|
104
|
+
"completed",
|
|
105
|
+
"failed",
|
|
106
|
+
"canceled"
|
|
107
|
+
]);
|
|
108
|
+
function evaluateCollaborationGraphAdmission(input) {
|
|
109
|
+
const existing = input.nodes.get(input.candidate.collaborationId);
|
|
110
|
+
if (existing !== void 0) {
|
|
111
|
+
const parent2 = existing.parentCollaborationId === void 0 ? void 0 : input.nodes.get(existing.parentCollaborationId);
|
|
112
|
+
return parent2 === void 0 ? Object.freeze({ kind: "admitted" }) : Object.freeze({ kind: "admitted", parent: parent2 });
|
|
113
|
+
}
|
|
114
|
+
const reservation = input.reservations.get(input.candidate.collaborationId);
|
|
115
|
+
if (reservation !== void 0 && reservation.parentCollaborationId !== input.candidate.parentCollaborationId) {
|
|
116
|
+
return Object.freeze({ kind: "conflict" });
|
|
117
|
+
}
|
|
118
|
+
const parent = input.candidate.parentCollaborationId === void 0 ? void 0 : input.nodes.get(input.candidate.parentCollaborationId);
|
|
119
|
+
if (input.candidate.parentCollaborationId === void 0 && input.candidate.rootCollaborationId !== input.candidate.collaborationId || input.candidate.parentCollaborationId !== void 0 && (parent === void 0 || input.candidate.rootCollaborationId !== parent.rootCollaborationId || TERMINAL_COLLABORATION_STATUSES.has(parent.status) || parent.closedAt !== void 0)) {
|
|
120
|
+
return Object.freeze({ kind: "conflict" });
|
|
121
|
+
}
|
|
122
|
+
let depth = 1;
|
|
123
|
+
const visitedIds = /* @__PURE__ */ new Set([input.candidate.collaborationId]);
|
|
124
|
+
for (let ancestor = parent; ancestor !== void 0; ) {
|
|
125
|
+
if (visitedIds.has(ancestor.collaborationId)) {
|
|
126
|
+
return Object.freeze({ kind: "conflict" });
|
|
127
|
+
}
|
|
128
|
+
visitedIds.add(ancestor.collaborationId);
|
|
129
|
+
depth += 1;
|
|
130
|
+
if (ancestor.parentCollaborationId === void 0) break;
|
|
131
|
+
ancestor = input.nodes.get(ancestor.parentCollaborationId);
|
|
132
|
+
if (ancestor === void 0) {
|
|
133
|
+
return Object.freeze({ kind: "conflict" });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (reservation !== void 0) {
|
|
137
|
+
return parent === void 0 ? Object.freeze({ kind: "admitted" }) : Object.freeze({ kind: "admitted", parent });
|
|
138
|
+
}
|
|
139
|
+
const unmaterializedReservations = [...input.reservations].filter(
|
|
140
|
+
([collaborationId]) => !input.nodes.has(collaborationId)
|
|
141
|
+
);
|
|
142
|
+
const childCount = parent === void 0 ? 0 : [...input.nodes.values()].filter(
|
|
143
|
+
(node) => node.parentCollaborationId === parent.collaborationId
|
|
144
|
+
).length + unmaterializedReservations.filter(
|
|
145
|
+
([, retainedReservation]) => retainedReservation.parentCollaborationId === parent.collaborationId
|
|
146
|
+
).length;
|
|
147
|
+
const activeCount = [...input.nodes.values()].filter(
|
|
148
|
+
(node) => !TERMINAL_COLLABORATION_STATUSES.has(node.status)
|
|
149
|
+
).length + unmaterializedReservations.length;
|
|
150
|
+
if (input.nodes.size + unmaterializedReservations.length >= AGENT_COLLABORATION_GRAPH_LIMITS.maxNodes || childCount >= input.capability.maxChildrenPerNode || depth > input.capability.maxDepth || input.candidate.active && activeCount >= input.capability.maxActiveNodes) {
|
|
151
|
+
return Object.freeze({ kind: "capacity_exceeded" });
|
|
152
|
+
}
|
|
153
|
+
return parent === void 0 ? Object.freeze({ kind: "admitted" }) : Object.freeze({ kind: "admitted", parent });
|
|
154
|
+
}
|
|
43
155
|
function invalidTurnSequence(providerKey, message) {
|
|
44
156
|
return throwAgentProviderContractError(
|
|
45
157
|
providerKey,
|
|
@@ -59,7 +171,10 @@ function completeTurnSequence(input) {
|
|
|
59
171
|
}
|
|
60
172
|
const FINAL_DIFF_TRAILING_EVENT_TYPES = [
|
|
61
173
|
"artifact.referenced",
|
|
174
|
+
"collaboration.updated",
|
|
175
|
+
"operation.updated",
|
|
62
176
|
"provider.diagnostic",
|
|
177
|
+
"resource.updated",
|
|
63
178
|
"runtime.error",
|
|
64
179
|
"runtime.warning",
|
|
65
180
|
"turn.completed"
|
|
@@ -305,6 +420,84 @@ function observeTurnOutput(input) {
|
|
|
305
420
|
observeContextMaterializationBoundary(input.contextUsageState);
|
|
306
421
|
}
|
|
307
422
|
if (input.output.kind !== "event") return;
|
|
423
|
+
if (input.output.event.type === "operation.updated") {
|
|
424
|
+
const result = validateAgentOperationResultTransition({
|
|
425
|
+
providerKey: input.providerKey,
|
|
426
|
+
candidate: input.output.event.payload.result,
|
|
427
|
+
previous: input.interactionState.operationResults.get(
|
|
428
|
+
input.output.event.payload.result.invocationId
|
|
429
|
+
)
|
|
430
|
+
});
|
|
431
|
+
input.interactionState.operationResults.set(result.invocationId, result);
|
|
432
|
+
const invocation = input.interactionState.operationInvocations.get(
|
|
433
|
+
result.invocationId
|
|
434
|
+
);
|
|
435
|
+
if (invocation !== void 0) invocation.result = result;
|
|
436
|
+
}
|
|
437
|
+
if (input.output.event.type === "collaboration.updated") {
|
|
438
|
+
const node = validateAgentCollaborationNodeForCapabilities({
|
|
439
|
+
capabilities: input.capabilities,
|
|
440
|
+
candidate: input.output.event.payload.node,
|
|
441
|
+
previous: input.interactionState.collaborationNodes.get(
|
|
442
|
+
input.output.event.payload.node.collaborationId
|
|
443
|
+
)
|
|
444
|
+
});
|
|
445
|
+
const capability = input.capabilities.collaboration;
|
|
446
|
+
if (capability.kind !== "supported") {
|
|
447
|
+
throwAgentProviderContractError(
|
|
448
|
+
input.providerKey,
|
|
449
|
+
"output_capability_mismatch",
|
|
450
|
+
"Provider emitted collaboration state without declaring support."
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
const admission = evaluateCollaborationGraphAdmission({
|
|
454
|
+
capability,
|
|
455
|
+
candidate: {
|
|
456
|
+
collaborationId: node.collaborationId,
|
|
457
|
+
rootCollaborationId: node.rootCollaborationId,
|
|
458
|
+
...node.parentCollaborationId === void 0 ? {} : { parentCollaborationId: node.parentCollaborationId },
|
|
459
|
+
active: !TERMINAL_COLLABORATION_STATUSES.has(node.status)
|
|
460
|
+
},
|
|
461
|
+
nodes: input.interactionState.collaborationNodes,
|
|
462
|
+
reservations: input.interactionState.collaborationSpawnReservations
|
|
463
|
+
});
|
|
464
|
+
if (admission.kind === "conflict") {
|
|
465
|
+
throwAgentProviderContractError(
|
|
466
|
+
input.providerKey,
|
|
467
|
+
"output_collaboration_mismatch",
|
|
468
|
+
"Provider emitted a collaboration node outside the canonical graph."
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
if (admission.kind === "capacity_exceeded") {
|
|
472
|
+
throwAgentProviderContractError(
|
|
473
|
+
input.providerKey,
|
|
474
|
+
"output_capability_mismatch",
|
|
475
|
+
"Provider emitted a collaboration graph outside its declared limits."
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
input.interactionState.collaborationNodes.set(node.collaborationId, node);
|
|
479
|
+
}
|
|
480
|
+
if (input.output.event.type === "resource.updated") {
|
|
481
|
+
const capability = input.capabilities.generatedResources;
|
|
482
|
+
const resourceId = input.output.event.payload.resource.resourceId;
|
|
483
|
+
if (capability.kind !== "supported" || !input.state.generatedResourceIds.has(resourceId) && input.state.generatedResourceIds.size >= capability.maxResourcesPerTurn) {
|
|
484
|
+
throwAgentProviderContractError(
|
|
485
|
+
input.providerKey,
|
|
486
|
+
"output_capability_mismatch",
|
|
487
|
+
"Provider exceeded its declared generated-resource count for the turn."
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
const resource = validateAgentGeneratedResourceForCapabilities({
|
|
491
|
+
capabilities: input.capabilities,
|
|
492
|
+
candidate: input.output.event.payload.resource,
|
|
493
|
+
expectedResourceId: input.output.event.payload.resource.resourceId,
|
|
494
|
+
previous: input.interactionState.generatedResources.get(
|
|
495
|
+
input.output.event.payload.resource.resourceId
|
|
496
|
+
)
|
|
497
|
+
});
|
|
498
|
+
input.state.generatedResourceIds.add(resource.resourceId);
|
|
499
|
+
input.interactionState.generatedResources.set(resource.resourceId, resource);
|
|
500
|
+
}
|
|
308
501
|
observeTurnEvent({
|
|
309
502
|
providerKey: input.providerKey,
|
|
310
503
|
event: input.output.event,
|
|
@@ -314,6 +507,45 @@ function observeTurnOutput(input) {
|
|
|
314
507
|
contextUsageState: input.contextUsageState
|
|
315
508
|
});
|
|
316
509
|
}
|
|
510
|
+
const SESSION_OPERATION_OBSERVATION_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
511
|
+
"item.started",
|
|
512
|
+
"item.updated",
|
|
513
|
+
"item.completed",
|
|
514
|
+
"progress.updated",
|
|
515
|
+
"context.usage.updated",
|
|
516
|
+
"operation.updated",
|
|
517
|
+
"resource.updated",
|
|
518
|
+
"runtime.warning",
|
|
519
|
+
"runtime.error",
|
|
520
|
+
"provider.diagnostic"
|
|
521
|
+
]);
|
|
522
|
+
function observeSessionOperationOutput(input) {
|
|
523
|
+
if (input.output.kind === "event") {
|
|
524
|
+
const event = input.output.event;
|
|
525
|
+
if (!SESSION_OPERATION_OBSERVATION_EVENT_TYPES.has(event.type)) {
|
|
526
|
+
invalidTurnSequence(
|
|
527
|
+
input.providerKey,
|
|
528
|
+
"Provider emitted turn-owned output from a session operation."
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
if ((event.type === "item.started" || event.type === "item.updated" || event.type === "item.completed") && event.payload.itemKind !== "context_compaction") {
|
|
532
|
+
invalidTurnSequence(
|
|
533
|
+
input.providerKey,
|
|
534
|
+
"Provider emitted a non-compaction item from a session operation."
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
observeTurnOutput({
|
|
539
|
+
capabilities: input.capabilities,
|
|
540
|
+
providerKey: input.providerKey,
|
|
541
|
+
output: input.output,
|
|
542
|
+
state: input.state,
|
|
543
|
+
pendingRequests: /* @__PURE__ */ new Map(),
|
|
544
|
+
openedRequestIds: /* @__PURE__ */ new Set(),
|
|
545
|
+
contextUsageState: input.contextUsageState,
|
|
546
|
+
interactionState: input.interactionState
|
|
547
|
+
});
|
|
548
|
+
}
|
|
317
549
|
function assertStableTurnBoundary(input) {
|
|
318
550
|
const terminal = input.state.terminal && !input.state.waiting;
|
|
319
551
|
const waiting = !input.state.terminal && input.state.waiting && input.pendingRequests.size === 1;
|
|
@@ -355,7 +587,9 @@ function observeTurnOperationOutputs(input) {
|
|
|
355
587
|
state: input.state,
|
|
356
588
|
pendingRequests: input.pendingRequests,
|
|
357
589
|
openedRequestIds: input.openedRequestIds,
|
|
358
|
-
contextUsageState: input.contextUsageState
|
|
590
|
+
contextUsageState: input.contextUsageState,
|
|
591
|
+
capabilities: input.capabilities,
|
|
592
|
+
interactionState: input.interactionState
|
|
359
593
|
});
|
|
360
594
|
}
|
|
361
595
|
}
|
|
@@ -462,6 +696,15 @@ function validateAgentProviderSession(input) {
|
|
|
462
696
|
cumulativeByScope: /* @__PURE__ */ new Map(),
|
|
463
697
|
compactionReadyScopes: /* @__PURE__ */ new Set()
|
|
464
698
|
};
|
|
699
|
+
const interactionState = {
|
|
700
|
+
operationResults: /* @__PURE__ */ new Map(),
|
|
701
|
+
operationInvocations: /* @__PURE__ */ new Map(),
|
|
702
|
+
collaborationNodes: /* @__PURE__ */ new Map(),
|
|
703
|
+
collaborationSpawnReservations: /* @__PURE__ */ new Map(),
|
|
704
|
+
generatedResources: /* @__PURE__ */ new Map()
|
|
705
|
+
};
|
|
706
|
+
const collaborationNodes = interactionState.collaborationNodes;
|
|
707
|
+
const collaborationSpawnReservations = interactionState.collaborationSpawnReservations;
|
|
465
708
|
let activeTurn = null;
|
|
466
709
|
let closePromise = null;
|
|
467
710
|
let closed = false;
|
|
@@ -501,6 +744,49 @@ function validateAgentProviderSession(input) {
|
|
|
501
744
|
throw error;
|
|
502
745
|
}
|
|
503
746
|
};
|
|
747
|
+
const delegateProviderMutation = async (input2) => {
|
|
748
|
+
let executionStarted = false;
|
|
749
|
+
const onProviderExecutionStarted = () => {
|
|
750
|
+
if (executionStarted) {
|
|
751
|
+
throwAgentProviderContractError(
|
|
752
|
+
providerKey,
|
|
753
|
+
"invalid_operation_result",
|
|
754
|
+
"Provider reported operation execution more than once."
|
|
755
|
+
);
|
|
756
|
+
}
|
|
757
|
+
input2.observer?.();
|
|
758
|
+
executionStarted = true;
|
|
759
|
+
};
|
|
760
|
+
const onOutput = async (candidate) => {
|
|
761
|
+
if (!executionStarted) {
|
|
762
|
+
throwAgentProviderContractError(
|
|
763
|
+
providerKey,
|
|
764
|
+
"invalid_operation_result",
|
|
765
|
+
"Provider emitted operation output before reporting execution start."
|
|
766
|
+
);
|
|
767
|
+
}
|
|
768
|
+
await input2.observeOutput?.(candidate);
|
|
769
|
+
};
|
|
770
|
+
try {
|
|
771
|
+
const candidate = await input2.invoke(onProviderExecutionStarted, onOutput);
|
|
772
|
+
if (!executionStarted) {
|
|
773
|
+
throwAgentProviderContractError(
|
|
774
|
+
providerKey,
|
|
775
|
+
"invalid_operation_result",
|
|
776
|
+
"Provider completed an operation without reporting execution start."
|
|
777
|
+
);
|
|
778
|
+
}
|
|
779
|
+
return input2.validate(candidate);
|
|
780
|
+
} catch (error) {
|
|
781
|
+
if (!executionStarted) throw error;
|
|
782
|
+
unusable = true;
|
|
783
|
+
throw new AgentProviderDelegatedOperationError(
|
|
784
|
+
providerKey,
|
|
785
|
+
input2.operation,
|
|
786
|
+
error
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
};
|
|
504
790
|
const runTurn = async function* (turnInput) {
|
|
505
791
|
requireUsable();
|
|
506
792
|
throwIfAgentOperationAborted(turnInput.signal);
|
|
@@ -545,6 +831,7 @@ function validateAgentProviderSession(input) {
|
|
|
545
831
|
fileChangeMode: capabilities.output.fileChanges,
|
|
546
832
|
observedItems: /* @__PURE__ */ new Map(),
|
|
547
833
|
proposedPlans: /* @__PURE__ */ new Map(),
|
|
834
|
+
generatedResourceIds: /* @__PURE__ */ new Set(),
|
|
548
835
|
started: false,
|
|
549
836
|
terminal: false,
|
|
550
837
|
waiting: false,
|
|
@@ -564,12 +851,14 @@ function validateAgentProviderSession(input) {
|
|
|
564
851
|
outputContext(parsedInput.turnId)
|
|
565
852
|
);
|
|
566
853
|
observeTurnOutput({
|
|
854
|
+
capabilities,
|
|
567
855
|
providerKey,
|
|
568
856
|
output,
|
|
569
857
|
state: currentTurn.state,
|
|
570
858
|
pendingRequests: currentTurn.pendingRequests,
|
|
571
859
|
openedRequestIds,
|
|
572
|
-
contextUsageState
|
|
860
|
+
contextUsageState,
|
|
861
|
+
interactionState
|
|
573
862
|
});
|
|
574
863
|
yield output;
|
|
575
864
|
}
|
|
@@ -663,12 +952,14 @@ function validateAgentProviderSession(input) {
|
|
|
663
952
|
outputContext(pending.turnId)
|
|
664
953
|
);
|
|
665
954
|
observeTurnOutput({
|
|
955
|
+
capabilities,
|
|
666
956
|
providerKey,
|
|
667
957
|
output,
|
|
668
958
|
state: currentTurn.state,
|
|
669
959
|
pendingRequests: currentTurn.pendingRequests,
|
|
670
960
|
openedRequestIds,
|
|
671
|
-
contextUsageState
|
|
961
|
+
contextUsageState,
|
|
962
|
+
interactionState
|
|
672
963
|
});
|
|
673
964
|
yield output;
|
|
674
965
|
}
|
|
@@ -743,12 +1034,14 @@ function validateAgentProviderSession(input) {
|
|
|
743
1034
|
}
|
|
744
1035
|
try {
|
|
745
1036
|
observeTurnOperationOutputs({
|
|
1037
|
+
capabilities,
|
|
746
1038
|
providerKey,
|
|
747
1039
|
outputs: result.outputs,
|
|
748
1040
|
state: targetedTurn.state,
|
|
749
1041
|
pendingRequests: targetedTurn.pendingRequests,
|
|
750
1042
|
openedRequestIds,
|
|
751
|
-
contextUsageState
|
|
1043
|
+
contextUsageState,
|
|
1044
|
+
interactionState
|
|
752
1045
|
});
|
|
753
1046
|
if (terminalized && !targetedTurn.state.terminal) {
|
|
754
1047
|
completeTurnSequence({
|
|
@@ -821,22 +1114,467 @@ function validateAgentProviderSession(input) {
|
|
|
821
1114
|
const declaredConfiguration = input.candidate.configuration;
|
|
822
1115
|
const configuration = declaredConfiguration.kind === "managed" ? Object.freeze({ kind: "managed" }) : Object.freeze({
|
|
823
1116
|
kind: "selectable",
|
|
824
|
-
|
|
1117
|
+
listConfiguration: async (listInput = {}) => {
|
|
825
1118
|
requireUsable();
|
|
826
|
-
throwIfAgentOperationAborted(
|
|
827
|
-
|
|
828
|
-
|
|
1119
|
+
throwIfAgentOperationAborted(listInput.signal);
|
|
1120
|
+
return validateAgentConfigurationCatalogForCapabilities(
|
|
1121
|
+
capabilities,
|
|
1122
|
+
await declaredConfiguration.listConfiguration(
|
|
1123
|
+
listInput.signal === void 0 ? {} : { signal: listInput.signal }
|
|
1124
|
+
)
|
|
829
1125
|
);
|
|
830
|
-
|
|
1126
|
+
},
|
|
1127
|
+
applyConfigurationSelection: async (configurationInput) => {
|
|
1128
|
+
requireUsable();
|
|
1129
|
+
throwIfAgentOperationAborted(configurationInput.signal);
|
|
1130
|
+
const catalog = validateAgentConfigurationCatalogForCapabilities(
|
|
831
1131
|
capabilities,
|
|
832
|
-
|
|
1132
|
+
await declaredConfiguration.listConfiguration(
|
|
1133
|
+
configurationInput.signal === void 0 ? {} : { signal: configurationInput.signal }
|
|
1134
|
+
)
|
|
833
1135
|
);
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
1136
|
+
let selection;
|
|
1137
|
+
try {
|
|
1138
|
+
selection = parseAgentConfigurationSelectionFor(
|
|
1139
|
+
catalog,
|
|
1140
|
+
configurationInput.selection
|
|
1141
|
+
);
|
|
1142
|
+
} catch {
|
|
1143
|
+
return throwAgentProviderContractError(
|
|
1144
|
+
providerKey,
|
|
1145
|
+
"configuration_value_unsupported",
|
|
1146
|
+
"Configuration selection is stale or outside the offered catalog."
|
|
1147
|
+
);
|
|
1148
|
+
}
|
|
1149
|
+
return delegateProviderMutation({
|
|
1150
|
+
operation: "apply_configuration",
|
|
1151
|
+
observer: configurationInput.onProviderExecutionStarted,
|
|
1152
|
+
invoke: (onProviderExecutionStarted) => declaredConfiguration.applyConfigurationSelection({
|
|
1153
|
+
selection,
|
|
1154
|
+
onProviderExecutionStarted,
|
|
837
1155
|
...configurationInput.signal === void 0 ? {} : { signal: configurationInput.signal }
|
|
1156
|
+
}),
|
|
1157
|
+
validate: (candidate) => validateAgentProviderOperationResult(
|
|
1158
|
+
candidate,
|
|
1159
|
+
outputContext()
|
|
1160
|
+
)
|
|
1161
|
+
});
|
|
1162
|
+
}
|
|
1163
|
+
});
|
|
1164
|
+
const declaredOperations = input.candidate.operations;
|
|
1165
|
+
const operations = declaredOperations.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
|
|
1166
|
+
kind: "supported",
|
|
1167
|
+
listOperations: async (listInput = {}) => {
|
|
1168
|
+
requireUsable();
|
|
1169
|
+
throwIfAgentOperationAborted(listInput.signal);
|
|
1170
|
+
return validateAgentOperationCatalogForCapabilities(
|
|
1171
|
+
capabilities,
|
|
1172
|
+
await declaredOperations.listOperations(
|
|
1173
|
+
listInput.signal === void 0 ? {} : { signal: listInput.signal }
|
|
1174
|
+
)
|
|
1175
|
+
);
|
|
1176
|
+
},
|
|
1177
|
+
invokeOperation: async (operationInput) => {
|
|
1178
|
+
requireUsable();
|
|
1179
|
+
throwIfAgentOperationAborted(operationInput.signal);
|
|
1180
|
+
let invocation;
|
|
1181
|
+
let observationTurnId;
|
|
1182
|
+
try {
|
|
1183
|
+
invocation = parseAgentOperationInvocation(operationInput.invocation);
|
|
1184
|
+
observationTurnId = parseAgentTurnId(
|
|
1185
|
+
operationInput.observationTurnId
|
|
1186
|
+
);
|
|
1187
|
+
} catch {
|
|
1188
|
+
return throwAgentProviderContractError(
|
|
1189
|
+
providerKey,
|
|
1190
|
+
"input_operation_mismatch",
|
|
1191
|
+
"Operation invocation is invalid."
|
|
1192
|
+
);
|
|
1193
|
+
}
|
|
1194
|
+
const catalog = validateAgentOperationCatalogForCapabilities(
|
|
1195
|
+
capabilities,
|
|
1196
|
+
await declaredOperations.listOperations(
|
|
1197
|
+
operationInput.signal === void 0 ? {} : { signal: operationInput.signal }
|
|
1198
|
+
)
|
|
1199
|
+
);
|
|
1200
|
+
const descriptor = catalog.operations.find(
|
|
1201
|
+
(operation) => operation.operationId === invocation.operationId
|
|
1202
|
+
);
|
|
1203
|
+
if (descriptor === void 0) {
|
|
1204
|
+
return throwAgentProviderContractError(
|
|
1205
|
+
providerKey,
|
|
1206
|
+
"input_operation_mismatch",
|
|
1207
|
+
"Operation invocation does not identify an offered operation."
|
|
1208
|
+
);
|
|
1209
|
+
}
|
|
1210
|
+
try {
|
|
1211
|
+
invocation = parseAgentOperationInvocationFor(
|
|
1212
|
+
descriptor,
|
|
1213
|
+
invocation
|
|
1214
|
+
);
|
|
1215
|
+
} catch {
|
|
1216
|
+
return throwAgentProviderContractError(
|
|
1217
|
+
providerKey,
|
|
1218
|
+
"input_operation_mismatch",
|
|
1219
|
+
"Operation invocation is stale or outside the offered descriptor."
|
|
1220
|
+
);
|
|
1221
|
+
}
|
|
1222
|
+
const existing = interactionState.operationInvocations.get(
|
|
1223
|
+
invocation.invocationId
|
|
1224
|
+
);
|
|
1225
|
+
if (existing !== void 0) {
|
|
1226
|
+
if (JSON.stringify(existing.invocation) !== JSON.stringify(invocation)) {
|
|
1227
|
+
return throwAgentProviderContractError(
|
|
1228
|
+
providerKey,
|
|
1229
|
+
"input_operation_mismatch",
|
|
1230
|
+
"Operation invocation ID was reused with conflicting input."
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
if (descriptor.idempotency === "required" && existing.result !== void 0) {
|
|
1234
|
+
return existing.result;
|
|
1235
|
+
}
|
|
1236
|
+
return throwAgentProviderContractError(
|
|
1237
|
+
providerKey,
|
|
1238
|
+
"input_operation_mismatch",
|
|
1239
|
+
"Operation invocation ID is already active or is not replayable."
|
|
1240
|
+
);
|
|
1241
|
+
}
|
|
1242
|
+
const trackedInvocation = {
|
|
1243
|
+
invocation
|
|
1244
|
+
};
|
|
1245
|
+
const observationState = {
|
|
1246
|
+
fileChangeMode: capabilities.output.fileChanges,
|
|
1247
|
+
observedItems: /* @__PURE__ */ new Map(),
|
|
1248
|
+
proposedPlans: /* @__PURE__ */ new Map(),
|
|
1249
|
+
generatedResourceIds: /* @__PURE__ */ new Set(),
|
|
1250
|
+
started: true,
|
|
1251
|
+
terminal: false,
|
|
1252
|
+
waiting: false,
|
|
1253
|
+
finalDiffObserved: false
|
|
1254
|
+
};
|
|
1255
|
+
interactionState.operationInvocations.set(
|
|
1256
|
+
invocation.invocationId,
|
|
1257
|
+
trackedInvocation
|
|
1258
|
+
);
|
|
1259
|
+
try {
|
|
1260
|
+
const result = await delegateProviderMutation({
|
|
1261
|
+
operation: "invoke_operation",
|
|
1262
|
+
observer: operationInput.onProviderExecutionStarted,
|
|
1263
|
+
invoke: (onProviderExecutionStarted, onOutput) => declaredOperations.invokeOperation({
|
|
1264
|
+
invocation,
|
|
1265
|
+
observationTurnId,
|
|
1266
|
+
onProviderExecutionStarted,
|
|
1267
|
+
onOutput,
|
|
1268
|
+
...operationInput.signal === void 0 ? {} : { signal: operationInput.signal }
|
|
1269
|
+
}),
|
|
1270
|
+
observeOutput: async (candidate) => {
|
|
1271
|
+
const output = validateAgentProviderOutputForContext(
|
|
1272
|
+
candidate,
|
|
1273
|
+
{
|
|
1274
|
+
...outputContext(observationTurnId),
|
|
1275
|
+
operationInvocationId: invocation.invocationId
|
|
1276
|
+
}
|
|
1277
|
+
);
|
|
1278
|
+
observeSessionOperationOutput({
|
|
1279
|
+
capabilities,
|
|
1280
|
+
providerKey,
|
|
1281
|
+
output,
|
|
1282
|
+
state: observationState,
|
|
1283
|
+
contextUsageState,
|
|
1284
|
+
interactionState
|
|
1285
|
+
});
|
|
1286
|
+
await operationInput.onOutput?.(output);
|
|
1287
|
+
},
|
|
1288
|
+
validate: (candidate) => {
|
|
1289
|
+
const result2 = validateAgentOperationResultTransition({
|
|
1290
|
+
providerKey,
|
|
1291
|
+
candidate: validateAgentOperationResultForInvocation(
|
|
1292
|
+
providerKey,
|
|
1293
|
+
descriptor,
|
|
1294
|
+
invocation,
|
|
1295
|
+
candidate
|
|
1296
|
+
),
|
|
1297
|
+
previous: interactionState.operationResults.get(
|
|
1298
|
+
invocation.invocationId
|
|
1299
|
+
)
|
|
1300
|
+
});
|
|
1301
|
+
interactionState.operationResults.set(
|
|
1302
|
+
result2.invocationId,
|
|
1303
|
+
result2
|
|
1304
|
+
);
|
|
1305
|
+
return result2;
|
|
1306
|
+
}
|
|
1307
|
+
});
|
|
1308
|
+
trackedInvocation.result = result;
|
|
1309
|
+
return result;
|
|
1310
|
+
} catch (error) {
|
|
1311
|
+
if (!(error instanceof AgentProviderDelegatedOperationError)) {
|
|
1312
|
+
interactionState.operationInvocations.delete(
|
|
1313
|
+
invocation.invocationId
|
|
1314
|
+
);
|
|
1315
|
+
}
|
|
1316
|
+
throw error;
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
});
|
|
1320
|
+
const declaredManagedContent = input.candidate.managedContent;
|
|
1321
|
+
const managedContent = declaredManagedContent.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
|
|
1322
|
+
kind: "supported",
|
|
1323
|
+
listManagedContent: async (listInput = {}) => {
|
|
1324
|
+
requireUsable();
|
|
1325
|
+
throwIfAgentOperationAborted(listInput.signal);
|
|
1326
|
+
return validateAgentManagedContentCatalogForCapabilities(
|
|
1327
|
+
capabilities,
|
|
1328
|
+
await declaredManagedContent.listManagedContent(
|
|
1329
|
+
listInput.signal === void 0 ? {} : { signal: listInput.signal }
|
|
1330
|
+
)
|
|
1331
|
+
);
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
const declaredIntegrations = input.candidate.integrations;
|
|
1335
|
+
const integrations = declaredIntegrations.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
|
|
1336
|
+
kind: "supported",
|
|
1337
|
+
observeIntegrations: async (listInput = {}) => {
|
|
1338
|
+
requireUsable();
|
|
1339
|
+
throwIfAgentOperationAborted(listInput.signal);
|
|
1340
|
+
return validateAgentIntegrationCatalogForCapabilities(
|
|
1341
|
+
capabilities,
|
|
1342
|
+
await declaredIntegrations.observeIntegrations(
|
|
1343
|
+
listInput.signal === void 0 ? {} : { signal: listInput.signal }
|
|
1344
|
+
)
|
|
1345
|
+
);
|
|
1346
|
+
}
|
|
1347
|
+
});
|
|
1348
|
+
const declaredCollaboration = input.candidate.collaboration;
|
|
1349
|
+
const collaboration = declaredCollaboration.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
|
|
1350
|
+
kind: "supported",
|
|
1351
|
+
spawnCollaboration: async (collaborationInput) => {
|
|
1352
|
+
requireUsable();
|
|
1353
|
+
throwIfAgentOperationAborted(collaborationInput.signal);
|
|
1354
|
+
let spawn;
|
|
1355
|
+
try {
|
|
1356
|
+
spawn = parseAgentCollaborationSpawnInput(collaborationInput.spawn);
|
|
1357
|
+
} catch {
|
|
1358
|
+
return throwAgentProviderContractError(
|
|
1359
|
+
providerKey,
|
|
1360
|
+
"input_operation_mismatch",
|
|
1361
|
+
"Collaboration spawn input is invalid."
|
|
1362
|
+
);
|
|
1363
|
+
}
|
|
1364
|
+
const capability = capabilities.collaboration;
|
|
1365
|
+
if (capability.kind !== "supported" || !capability.controlActions.includes("spawn") || !capability.roles.includes(spawn.role) || collaborationNodes.has(spawn.collaborationId) || collaborationSpawnReservations.has(spawn.collaborationId)) {
|
|
1366
|
+
return throwAgentProviderContractError(
|
|
1367
|
+
providerKey,
|
|
1368
|
+
"input_capability_mismatch",
|
|
1369
|
+
"Collaboration spawn is outside the provider's declared capability."
|
|
1370
|
+
);
|
|
1371
|
+
}
|
|
1372
|
+
const observedParent = spawn.parentCollaborationId === void 0 ? void 0 : collaborationNodes.get(spawn.parentCollaborationId);
|
|
1373
|
+
const admission = evaluateCollaborationGraphAdmission({
|
|
1374
|
+
capability,
|
|
1375
|
+
candidate: {
|
|
1376
|
+
collaborationId: spawn.collaborationId,
|
|
1377
|
+
rootCollaborationId: observedParent?.rootCollaborationId ?? spawn.collaborationId,
|
|
1378
|
+
...spawn.parentCollaborationId === void 0 ? {} : { parentCollaborationId: spawn.parentCollaborationId },
|
|
1379
|
+
active: true
|
|
1380
|
+
},
|
|
1381
|
+
nodes: collaborationNodes,
|
|
1382
|
+
reservations: collaborationSpawnReservations
|
|
1383
|
+
});
|
|
1384
|
+
if (admission.kind === "conflict") {
|
|
1385
|
+
return throwAgentProviderContractError(
|
|
1386
|
+
providerKey,
|
|
1387
|
+
"input_operation_mismatch",
|
|
1388
|
+
"Collaboration parent is unavailable in the canonical graph."
|
|
1389
|
+
);
|
|
1390
|
+
}
|
|
1391
|
+
if (admission.kind === "capacity_exceeded") {
|
|
1392
|
+
return throwAgentProviderContractError(
|
|
1393
|
+
providerKey,
|
|
1394
|
+
"input_capability_mismatch",
|
|
1395
|
+
"Collaboration graph limit would be exceeded."
|
|
1396
|
+
);
|
|
1397
|
+
}
|
|
1398
|
+
const parent = admission.parent;
|
|
1399
|
+
collaborationSpawnReservations.set(
|
|
1400
|
+
spawn.collaborationId,
|
|
1401
|
+
Object.freeze({
|
|
1402
|
+
...spawn.parentCollaborationId === void 0 ? {} : { parentCollaborationId: spawn.parentCollaborationId }
|
|
838
1403
|
})
|
|
839
1404
|
);
|
|
1405
|
+
try {
|
|
1406
|
+
const node = await delegateProviderMutation({
|
|
1407
|
+
operation: "spawn_collaboration",
|
|
1408
|
+
observer: collaborationInput.onProviderExecutionStarted,
|
|
1409
|
+
invoke: (onProviderExecutionStarted) => declaredCollaboration.spawnCollaboration({
|
|
1410
|
+
spawn,
|
|
1411
|
+
onProviderExecutionStarted,
|
|
1412
|
+
...collaborationInput.signal === void 0 ? {} : { signal: collaborationInput.signal }
|
|
1413
|
+
}),
|
|
1414
|
+
validate: (candidate) => {
|
|
1415
|
+
const node2 = validateAgentCollaborationNodeForCapabilities({
|
|
1416
|
+
capabilities,
|
|
1417
|
+
candidate
|
|
1418
|
+
});
|
|
1419
|
+
if (node2.collaborationId !== spawn.collaborationId || node2.parentCollaborationId !== spawn.parentCollaborationId || node2.role !== spawn.role || node2.title !== spawn.title || node2.objective !== spawn.objective || node2.createdAt !== spawn.createdAt || node2.rootCollaborationId !== (parent?.rootCollaborationId ?? spawn.collaborationId)) {
|
|
1420
|
+
return throwAgentProviderContractError(
|
|
1421
|
+
providerKey,
|
|
1422
|
+
"output_collaboration_mismatch",
|
|
1423
|
+
"Provider collaboration node does not match the spawn input."
|
|
1424
|
+
);
|
|
1425
|
+
}
|
|
1426
|
+
return node2;
|
|
1427
|
+
}
|
|
1428
|
+
});
|
|
1429
|
+
collaborationNodes.set(node.collaborationId, node);
|
|
1430
|
+
collaborationSpawnReservations.delete(spawn.collaborationId);
|
|
1431
|
+
return node;
|
|
1432
|
+
} catch (error) {
|
|
1433
|
+
if (!(error instanceof AgentProviderDelegatedOperationError)) {
|
|
1434
|
+
collaborationSpawnReservations.delete(spawn.collaborationId);
|
|
1435
|
+
}
|
|
1436
|
+
throw error;
|
|
1437
|
+
}
|
|
1438
|
+
},
|
|
1439
|
+
controlCollaboration: async (collaborationInput) => {
|
|
1440
|
+
requireUsable();
|
|
1441
|
+
throwIfAgentOperationAborted(collaborationInput.signal);
|
|
1442
|
+
let control;
|
|
1443
|
+
try {
|
|
1444
|
+
control = parseAgentCollaborationControlInput(
|
|
1445
|
+
collaborationInput.control
|
|
1446
|
+
);
|
|
1447
|
+
} catch {
|
|
1448
|
+
return throwAgentProviderContractError(
|
|
1449
|
+
providerKey,
|
|
1450
|
+
"input_operation_mismatch",
|
|
1451
|
+
"Collaboration control input is invalid."
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1454
|
+
const capability = capabilities.collaboration;
|
|
1455
|
+
const previous = collaborationNodes.get(control.collaborationId);
|
|
1456
|
+
if (capability.kind !== "supported" || !capability.controlActions.includes(control.action) || previous === void 0) {
|
|
1457
|
+
return throwAgentProviderContractError(
|
|
1458
|
+
providerKey,
|
|
1459
|
+
"input_capability_mismatch",
|
|
1460
|
+
"Collaboration control is outside the observed graph or declared capability."
|
|
1461
|
+
);
|
|
1462
|
+
}
|
|
1463
|
+
const terminal = ["completed", "failed", "canceled"].includes(
|
|
1464
|
+
previous.status
|
|
1465
|
+
);
|
|
1466
|
+
if (control.action === "close" && previous.closedAt !== void 0) {
|
|
1467
|
+
return previous;
|
|
1468
|
+
}
|
|
1469
|
+
if (control.action === "close" && !terminal || control.action === "stop" && terminal || control.action === "steer" && terminal || control.action !== "inspect" && previous.closedAt !== void 0) {
|
|
1470
|
+
return throwAgentProviderContractError(
|
|
1471
|
+
providerKey,
|
|
1472
|
+
"input_capability_mismatch",
|
|
1473
|
+
"Collaboration control is unavailable in the current lifecycle state."
|
|
1474
|
+
);
|
|
1475
|
+
}
|
|
1476
|
+
const node = await delegateProviderMutation({
|
|
1477
|
+
operation: "control_collaboration",
|
|
1478
|
+
observer: collaborationInput.onProviderExecutionStarted,
|
|
1479
|
+
invoke: (onProviderExecutionStarted) => declaredCollaboration.controlCollaboration({
|
|
1480
|
+
control,
|
|
1481
|
+
onProviderExecutionStarted,
|
|
1482
|
+
...collaborationInput.signal === void 0 ? {} : { signal: collaborationInput.signal }
|
|
1483
|
+
}),
|
|
1484
|
+
validate: (candidate) => {
|
|
1485
|
+
const validated = validateAgentCollaborationNodeForCapabilities({
|
|
1486
|
+
capabilities,
|
|
1487
|
+
candidate,
|
|
1488
|
+
previous
|
|
1489
|
+
});
|
|
1490
|
+
if (control.action === "stop" && validated.status !== "canceled" || control.action === "close" && (validated.status !== previous.status || validated.closedAt === void 0)) {
|
|
1491
|
+
return throwAgentProviderContractError(
|
|
1492
|
+
providerKey,
|
|
1493
|
+
"output_collaboration_mismatch",
|
|
1494
|
+
"Provider collaboration result does not settle the requested control action."
|
|
1495
|
+
);
|
|
1496
|
+
}
|
|
1497
|
+
return validated;
|
|
1498
|
+
}
|
|
1499
|
+
});
|
|
1500
|
+
collaborationNodes.set(node.collaborationId, node);
|
|
1501
|
+
return node;
|
|
1502
|
+
}
|
|
1503
|
+
});
|
|
1504
|
+
function validateGeneratedResourceInspection(candidate, resourceId) {
|
|
1505
|
+
if (candidate === null || typeof candidate !== "object" || !hasExactOwnKeys(candidate, [
|
|
1506
|
+
"descriptor",
|
|
1507
|
+
..."candidate" in candidate ? ["candidate"] : []
|
|
1508
|
+
])) {
|
|
1509
|
+
return throwAgentProviderContractError(
|
|
1510
|
+
providerKey,
|
|
1511
|
+
"output_resource_mismatch",
|
|
1512
|
+
"Provider returned an invalid generated-resource inspection."
|
|
1513
|
+
);
|
|
1514
|
+
}
|
|
1515
|
+
const rawInspection = candidate;
|
|
1516
|
+
const descriptor = validateAgentGeneratedResourceForCapabilities({
|
|
1517
|
+
capabilities,
|
|
1518
|
+
candidate: rawInspection.descriptor,
|
|
1519
|
+
expectedResourceId: resourceId,
|
|
1520
|
+
previous: interactionState.generatedResources.get(resourceId)
|
|
1521
|
+
});
|
|
1522
|
+
const hasCandidate = Object.prototype.hasOwnProperty.call(
|
|
1523
|
+
rawInspection,
|
|
1524
|
+
"candidate"
|
|
1525
|
+
);
|
|
1526
|
+
if (descriptor.status === "available" !== hasCandidate) {
|
|
1527
|
+
return throwAgentProviderContractError(
|
|
1528
|
+
providerKey,
|
|
1529
|
+
"output_resource_mismatch",
|
|
1530
|
+
"Exactly available generated resources must include owned artifact bytes."
|
|
1531
|
+
);
|
|
1532
|
+
}
|
|
1533
|
+
if (!hasCandidate) return Object.freeze({ descriptor });
|
|
1534
|
+
let artifactCandidate;
|
|
1535
|
+
try {
|
|
1536
|
+
artifactCandidate = createAgentArtifactCandidate(
|
|
1537
|
+
rawInspection.candidate
|
|
1538
|
+
);
|
|
1539
|
+
} catch {
|
|
1540
|
+
return throwAgentProviderContractError(
|
|
1541
|
+
providerKey,
|
|
1542
|
+
"output_resource_mismatch",
|
|
1543
|
+
"Provider returned invalid generated-resource artifact bytes."
|
|
1544
|
+
);
|
|
1545
|
+
}
|
|
1546
|
+
const artifact = artifactCandidate.descriptor;
|
|
1547
|
+
const expectedArtifactKind = descriptor.kind === "image" ? "image" : "file";
|
|
1548
|
+
if (artifactCandidate.delivery !== "required_before_reference" || artifact.artifactId !== descriptor.artifactId || artifact.kind !== expectedArtifactKind || artifact.displayName !== descriptor.displayName || artifact.mediaType !== descriptor.mediaType || artifact.byteSize !== descriptor.byteSize || artifact.digest?.algorithm !== "sha256" || artifact.digest?.value !== descriptor.sha256 || artifact.summary !== descriptor.summary) {
|
|
1549
|
+
return throwAgentProviderContractError(
|
|
1550
|
+
providerKey,
|
|
1551
|
+
"output_resource_mismatch",
|
|
1552
|
+
"Generated-resource metadata does not match its immutable artifact candidate."
|
|
1553
|
+
);
|
|
1554
|
+
}
|
|
1555
|
+
return Object.freeze({ descriptor, candidate: artifactCandidate });
|
|
1556
|
+
}
|
|
1557
|
+
const declaredGeneratedResources = input.candidate.generatedResources;
|
|
1558
|
+
const generatedResources = declaredGeneratedResources.kind === "unsupported" ? Object.freeze({ kind: "unsupported" }) : Object.freeze({
|
|
1559
|
+
kind: "supported",
|
|
1560
|
+
getGeneratedResource: async (resourceInput) => {
|
|
1561
|
+
requireUsable();
|
|
1562
|
+
throwIfAgentOperationAborted(resourceInput.signal);
|
|
1563
|
+
const resourceId = parseAgentGeneratedResourceId(
|
|
1564
|
+
resourceInput.resourceId
|
|
1565
|
+
);
|
|
1566
|
+
const inspection = validateGeneratedResourceInspection(
|
|
1567
|
+
await declaredGeneratedResources.getGeneratedResource({
|
|
1568
|
+
resourceId,
|
|
1569
|
+
...resourceInput.signal === void 0 ? {} : { signal: resourceInput.signal }
|
|
1570
|
+
}),
|
|
1571
|
+
resourceId
|
|
1572
|
+
);
|
|
1573
|
+
interactionState.generatedResources.set(
|
|
1574
|
+
inspection.descriptor.resourceId,
|
|
1575
|
+
inspection.descriptor
|
|
1576
|
+
);
|
|
1577
|
+
return inspection;
|
|
840
1578
|
}
|
|
841
1579
|
});
|
|
842
1580
|
const close = (closeInput) => {
|
|
@@ -868,6 +1606,11 @@ function validateAgentProviderSession(input) {
|
|
|
868
1606
|
interruption,
|
|
869
1607
|
steering,
|
|
870
1608
|
configuration,
|
|
1609
|
+
operations,
|
|
1610
|
+
managedContent,
|
|
1611
|
+
integrations,
|
|
1612
|
+
collaboration,
|
|
1613
|
+
generatedResources,
|
|
871
1614
|
close
|
|
872
1615
|
});
|
|
873
1616
|
}
|