@agen-ai/agent-runtime 0.4.0 → 0.4.2
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 +200 -9
- package/dist/adapterValidation.d.ts +4 -2
- package/dist/adapterValidation.js +140 -51
- package/dist/artifacts.js +0 -1
- package/dist/contractErrors.d.ts +2 -2
- package/dist/contractErrors.js +11 -7
- package/dist/hostBindings/opening.d.ts +2 -0
- package/dist/hostBindings/opening.js +58 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/nativeContinuations/admission.d.ts +17 -0
- package/dist/nativeContinuations/admission.js +250 -0
- package/dist/nativeContinuations/index.d.ts +2 -0
- package/dist/nativeContinuations/index.js +1 -0
- package/dist/nativeContinuations/types.d.ts +52 -0
- package/dist/nativeContinuations/types.js +0 -0
- package/dist/outputValidation.js +3 -2
- package/dist/providerCatalog.d.ts +1 -1
- package/dist/providerDriver.d.ts +4 -1
- package/dist/providerDriver.js +0 -1
- package/dist/providerInstanceRegistry.d.ts +4 -4
- package/dist/providerInstanceRegistry.js +2 -1
- package/dist/sessionAdmission.d.ts +12 -0
- package/dist/sessionAdmission.js +54 -0
- package/dist/sessionInteractions/index.d.ts +2 -0
- package/dist/sessionInteractions/index.js +1 -0
- package/dist/sessionInteractions/lifetime.d.ts +81 -0
- package/dist/sessionInteractions/lifetime.js +383 -0
- package/dist/sessionInteractions/request.d.ts +43 -0
- package/dist/sessionInteractions/request.js +381 -0
- package/dist/sessionInteractions/types.d.ts +110 -0
- package/dist/sessionInteractions/types.js +10 -0
- package/dist/sessionInteractions/validation.d.ts +25 -0
- package/dist/sessionInteractions/validation.js +180 -0
- package/dist/sessionValidation.d.ts +82 -3
- package/dist/sessionValidation.js +240 -181
- package/dist/sessions.d.ts +34 -0
- package/dist/testing/conformance.d.ts +3 -1
- package/dist/testing/conformance.js +180 -86
- package/dist/testing/fakeProvider.js +5 -6
- package/dist/turnExecution/execution.d.ts +23 -6
- package/dist/turnExecution/execution.js +136 -32
- package/dist/turnExecution/requests.d.ts +15 -3
- package/dist/turnExecution/requests.js +93 -28
- package/package.json +2 -2
package/dist/sessions.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { AgentAuthenticationFlow, AgentCollaborationControlInput, AgentCollaborationNode, AgentCollaborationSpawnInput, AgentConfigurationCatalog, AgentConfigurationSelectionInput, AgentError, AgentGeneratedResourceDescriptor, AgentGeneratedResourceId, AgentManagedContentCatalog, AgentOperationCatalog, AgentOperationInvocation, AgentOperationResult, AgentRequestResolution, AgentSessionBinding, AgentSessionBranchSource, AgentSessionConfiguration, AgentSessionId, AgentTurnId, AgentTurnInputContent, AgentTurnInteractionMode, AgentTurnInputPart, AgentTurnInterruptionReason } from "@agen-ai/agent-protocol";
|
|
2
|
+
import type { AgentNativeContinuationContext, AgentNativeContinuationSupport } from "./nativeContinuations/types.js";
|
|
2
3
|
import type { MaybePromise } from "./foundation.js";
|
|
3
4
|
import type { AgentSessionHostBinding, AgentSessionHostBindingSupport } from "./hostBindings/types.js";
|
|
4
5
|
import type { AgentProviderOutput } from "./outputs.js";
|
|
5
6
|
import type { AgentArtifactCandidate } from "./artifacts.js";
|
|
7
|
+
import type { AgentProviderSessionInteractionContext, AgentSessionInteractionContext, AgentSessionInteractionSupport } from "./sessionInteractions/types.js";
|
|
6
8
|
import type { AgentEnvironmentObservationPort } from "./environment/types.js";
|
|
7
9
|
export interface AgentProviderSessionContext {
|
|
8
10
|
readonly sessionId: AgentSessionId;
|
|
@@ -10,6 +12,7 @@ export interface AgentProviderSessionContext {
|
|
|
10
12
|
readonly configuration: AgentSessionConfiguration;
|
|
11
13
|
readonly signal?: AbortSignal;
|
|
12
14
|
readonly hostBinding?: AgentSessionHostBinding;
|
|
15
|
+
readonly interactions?: AgentProviderSessionInteractionContext;
|
|
13
16
|
}
|
|
14
17
|
export type AgentSessionBindingCreatedObserver = (binding: AgentSessionBinding) => void;
|
|
15
18
|
export interface AgentProviderCreateSessionInput extends AgentProviderSessionContext {
|
|
@@ -212,10 +215,41 @@ export type AgentProviderAuthentication = Readonly<{
|
|
|
212
215
|
cancel: (input: AgentProviderAuthenticationCancelInput) => MaybePromise<AgentProviderOperationResult>;
|
|
213
216
|
}>;
|
|
214
217
|
export interface AgentProviderAdapter {
|
|
218
|
+
readonly sessionInteractions?: AgentSessionInteractionSupport;
|
|
215
219
|
readonly hostBinding?: AgentSessionHostBindingSupport;
|
|
220
|
+
readonly nativeContinuations?: AgentNativeContinuationSupport;
|
|
216
221
|
readonly createSession: (input: AgentProviderCreateSessionInput) => MaybePromise<AgentProviderSession>;
|
|
217
222
|
readonly resumption: AgentSessionResumption;
|
|
218
223
|
readonly branching: AgentSessionBranching;
|
|
219
224
|
readonly authentication: AgentProviderAuthentication;
|
|
220
225
|
}
|
|
226
|
+
export type AgentSessionOpenContext = Omit<AgentProviderSessionContext, "interactions"> & Readonly<{
|
|
227
|
+
interactions?: AgentSessionInteractionContext;
|
|
228
|
+
nativeContinuations?: AgentNativeContinuationContext;
|
|
229
|
+
}>;
|
|
230
|
+
export type AgentCreateSessionInput = AgentSessionOpenContext & Readonly<{
|
|
231
|
+
onBindingCreated: AgentSessionBindingCreatedObserver;
|
|
232
|
+
}>;
|
|
233
|
+
export type AgentResumeSessionInput = AgentSessionOpenContext & Readonly<{
|
|
234
|
+
binding: AgentSessionBinding;
|
|
235
|
+
}>;
|
|
236
|
+
export type AgentBranchSessionInput = AgentSessionOpenContext & Readonly<{
|
|
237
|
+
source: AgentSessionBranchSource;
|
|
238
|
+
onBindingCreated: AgentSessionBindingCreatedObserver;
|
|
239
|
+
}>;
|
|
240
|
+
export type AgentValidatedProviderAdapter = Omit<AgentProviderAdapter, "createSession" | "resumption" | "branching"> & Readonly<{
|
|
241
|
+
createSession: (input: AgentCreateSessionInput) => MaybePromise<AgentProviderSession>;
|
|
242
|
+
resumption: Readonly<{
|
|
243
|
+
kind: "unsupported";
|
|
244
|
+
}> | Readonly<{
|
|
245
|
+
kind: "supported";
|
|
246
|
+
resumeSession: (input: AgentResumeSessionInput) => MaybePromise<AgentProviderSession>;
|
|
247
|
+
}>;
|
|
248
|
+
branching: Readonly<{
|
|
249
|
+
kind: "unsupported";
|
|
250
|
+
}> | Readonly<{
|
|
251
|
+
kind: "through_turn";
|
|
252
|
+
branchSession: (input: AgentBranchSessionInput) => MaybePromise<AgentProviderSession>;
|
|
253
|
+
}>;
|
|
254
|
+
}>;
|
|
221
255
|
//# sourceMappingURL=sessions.d.ts.map
|
|
@@ -18,7 +18,9 @@ export interface AgentProviderConformanceScenario {
|
|
|
18
18
|
readonly interruptionSessionId: AgentSessionId;
|
|
19
19
|
readonly turn: AgentProviderStartTurnInput;
|
|
20
20
|
readonly interruptionTurn: AgentProviderStartTurnInput;
|
|
21
|
-
readonly resolutionFor: (request: AgentRequest
|
|
21
|
+
readonly resolutionFor: (request: AgentRequest, context: Readonly<{
|
|
22
|
+
signal: AbortSignal;
|
|
23
|
+
}>) => AgentRequestResolution | undefined | Promise<AgentRequestResolution | undefined>;
|
|
22
24
|
readonly branchSource?: (binding: AgentSessionBinding, turnId: AgentTurnId) => AgentSessionBranchSource;
|
|
23
25
|
readonly steeringInput?: AgentTurnInputContent;
|
|
24
26
|
}
|
|
@@ -15,7 +15,6 @@ class AgentProviderConformanceError extends Error {
|
|
|
15
15
|
this.check = check;
|
|
16
16
|
this.name = "AgentProviderConformanceError";
|
|
17
17
|
}
|
|
18
|
-
check;
|
|
19
18
|
}
|
|
20
19
|
function requireCheck(condition, check, message) {
|
|
21
20
|
if (!condition) throw new AgentProviderConformanceError(check, message);
|
|
@@ -51,25 +50,104 @@ async function advanceToStartedTurn(session, input) {
|
|
|
51
50
|
);
|
|
52
51
|
outputs.push(next.value);
|
|
53
52
|
if (next.value.kind === "event" && next.value.event.type === "turn.started") {
|
|
54
|
-
return { execution, iterator, outputs };
|
|
53
|
+
return { session, execution, iterator, outputs };
|
|
55
54
|
}
|
|
56
55
|
}
|
|
57
56
|
} catch (error) {
|
|
58
|
-
|
|
57
|
+
const closing = session.close({ reason: "contract_rejected" });
|
|
58
|
+
const settled = await Promise.allSettled([closing, iterator.return?.()]);
|
|
59
|
+
const failures = settled.flatMap((result) => result.status === "rejected" ? [result.reason] : []);
|
|
60
|
+
if (failures.length > 0) throw new AggregateError([error, ...failures], "Conformance opening and cleanup failed.", { cause: error });
|
|
59
61
|
throw error;
|
|
60
62
|
}
|
|
61
63
|
}
|
|
62
|
-
async function collectRemainingOutputs(started, resolutionFor) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
64
|
+
async function collectRemainingOutputs(started, resolutionFor, beforeClose) {
|
|
65
|
+
const requests = /* @__PURE__ */ new Map();
|
|
66
|
+
const tasks = [];
|
|
67
|
+
let acceptingRequests = true;
|
|
68
|
+
let deliveredRequests = 0;
|
|
69
|
+
let failTask;
|
|
70
|
+
const taskFailure = new Promise((_resolve, reject) => {
|
|
71
|
+
failTask = reject;
|
|
72
|
+
});
|
|
73
|
+
const abortRequests = () => {
|
|
74
|
+
for (const controller of requests.values()) {
|
|
75
|
+
controller.abort(new DOMException("Conformance request is no longer answerable.", "AbortError"));
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const resolve = async (request, signal) => {
|
|
79
|
+
if (!resolutionFor) return;
|
|
80
|
+
let resolution;
|
|
81
|
+
try {
|
|
82
|
+
resolution = await resolutionFor(request, { signal });
|
|
83
|
+
} catch (error) {
|
|
84
|
+
if (signal.aborted && isAgentOperationAbortError(error)) return;
|
|
85
|
+
throw error;
|
|
71
86
|
}
|
|
87
|
+
if (resolution === void 0 || signal.aborted) return;
|
|
88
|
+
const receipt = await started.execution.resolveRequest({
|
|
89
|
+
resolution: parseAgentRequestResolutionFor(request, resolution)
|
|
90
|
+
});
|
|
91
|
+
requireCheck(
|
|
92
|
+
receipt.status === "delivered",
|
|
93
|
+
"request_resolution",
|
|
94
|
+
"Matching request answer was not accepted by the provider handler."
|
|
95
|
+
);
|
|
96
|
+
deliveredRequests += 1;
|
|
97
|
+
};
|
|
98
|
+
const reader = (async () => {
|
|
99
|
+
for (; ; ) {
|
|
100
|
+
const next = await started.iterator.next();
|
|
101
|
+
if (next.done || !acceptingRequests) return;
|
|
102
|
+
started.outputs.push(next.value);
|
|
103
|
+
if (next.value.kind !== "event") continue;
|
|
104
|
+
const event = next.value.event;
|
|
105
|
+
if (event.type === "request.opened" && resolutionFor) {
|
|
106
|
+
const request = event.payload.request;
|
|
107
|
+
const controller = new AbortController();
|
|
108
|
+
requests.set(request.requestId, controller);
|
|
109
|
+
const task = resolve(request, controller.signal);
|
|
110
|
+
tasks.push(task);
|
|
111
|
+
void task.catch((error) => {
|
|
112
|
+
acceptingRequests = false;
|
|
113
|
+
failTask(error);
|
|
114
|
+
});
|
|
115
|
+
} else if (event.type === "request.unavailable") {
|
|
116
|
+
requests.get(event.payload.requestId)?.abort(
|
|
117
|
+
new DOMException("The provider retired this conformance request.", "AbortError")
|
|
118
|
+
);
|
|
119
|
+
requests.delete(event.payload.requestId);
|
|
120
|
+
} else if (event.type === "turn.completed") {
|
|
121
|
+
abortRequests();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
})();
|
|
126
|
+
const checked = reader.then(async () => {
|
|
127
|
+
if (acceptingRequests) await beforeClose?.();
|
|
128
|
+
});
|
|
129
|
+
const failures = /* @__PURE__ */ new Set();
|
|
130
|
+
try {
|
|
131
|
+
await Promise.race([checked, taskFailure]);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
failures.add(error);
|
|
134
|
+
}
|
|
135
|
+
acceptingRequests = false;
|
|
136
|
+
abortRequests();
|
|
137
|
+
const closing = started.session.close({ reason: failures.size > 0 ? "contract_rejected" : "idle" });
|
|
138
|
+
const [closed, read, inspected, returned] = await Promise.allSettled([closing, reader, checked, started.iterator.return?.()]);
|
|
139
|
+
if (closed?.status === "rejected") failures.add(closed.reason);
|
|
140
|
+
for (const result of [read, inspected]) {
|
|
141
|
+
if (result?.status === "rejected" && !(failures.size > 0 && isAgentOperationAbortError(result.reason))) failures.add(result.reason);
|
|
72
142
|
}
|
|
143
|
+
if (returned?.status === "rejected") failures.add(returned.reason);
|
|
144
|
+
const joined = await Promise.allSettled(tasks);
|
|
145
|
+
for (const result of joined) {
|
|
146
|
+
if (result.status === "rejected") failures.add(result.reason);
|
|
147
|
+
}
|
|
148
|
+
if (failures.size === 1) throw failures.values().next().value;
|
|
149
|
+
if (failures.size > 1) throw new AggregateError(failures, "Conformance and owned cleanup failed.", { cause: failures.values().next().value });
|
|
150
|
+
return { outputs: started.outputs, deliveredRequests };
|
|
73
151
|
}
|
|
74
152
|
function requireOperationStatus(result, statuses, check, message) {
|
|
75
153
|
requireCheck(statuses.includes(result.status), check, message);
|
|
@@ -111,6 +189,7 @@ async function runAgentProviderConformance(scenario) {
|
|
|
111
189
|
});
|
|
112
190
|
let disposed = false;
|
|
113
191
|
let createdSession = null;
|
|
192
|
+
let failure;
|
|
114
193
|
try {
|
|
115
194
|
const instance = registry.requireInstance(scenario.definition.instanceId);
|
|
116
195
|
requireCheck(
|
|
@@ -277,55 +356,7 @@ async function runAgentProviderConformance(scenario) {
|
|
|
277
356
|
);
|
|
278
357
|
checks.push("abort");
|
|
279
358
|
}
|
|
280
|
-
const
|
|
281
|
-
let turnOutputs;
|
|
282
|
-
try {
|
|
283
|
-
if (instance.capabilities.turns.steer.kind === "supported") {
|
|
284
|
-
requireCheck(
|
|
285
|
-
created.steering.kind === "supported",
|
|
286
|
-
"steering",
|
|
287
|
-
"Steering capability has no handler."
|
|
288
|
-
);
|
|
289
|
-
const result = await created.steering.steerTurn({
|
|
290
|
-
turnId: scenario.turn.turnId,
|
|
291
|
-
...scenario.steeringInput ?? {
|
|
292
|
-
parts: [
|
|
293
|
-
{ type: "text", text: "Additional conformance input." }
|
|
294
|
-
]
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
requireCheck(
|
|
298
|
-
result.status === "delivered",
|
|
299
|
-
"steering",
|
|
300
|
-
"Steering did not deliver to the live turn."
|
|
301
|
-
);
|
|
302
|
-
} else {
|
|
303
|
-
requireCheck(
|
|
304
|
-
created.steering.kind === "unsupported",
|
|
305
|
-
"steering",
|
|
306
|
-
"Unsupported steering exposed a handler."
|
|
307
|
-
);
|
|
308
|
-
}
|
|
309
|
-
turnOutputs = await collectRemainingOutputs(startedTurn, scenario.resolutionFor);
|
|
310
|
-
} catch (error) {
|
|
311
|
-
await startedTurn.iterator.return?.();
|
|
312
|
-
await created.close({ reason: "contract_rejected" });
|
|
313
|
-
throw error;
|
|
314
|
-
}
|
|
315
|
-
const events = semanticEvents(turnOutputs);
|
|
316
|
-
requireCheck(
|
|
317
|
-
events[0]?.type === "turn.started",
|
|
318
|
-
"turn_order",
|
|
319
|
-
"Turn did not start first."
|
|
320
|
-
);
|
|
321
|
-
requireCheck(
|
|
322
|
-
hasStableTurnBoundary(events),
|
|
323
|
-
"turn_order",
|
|
324
|
-
"Turn did not terminate or enter a waiting state."
|
|
325
|
-
);
|
|
326
|
-
checks.push("turn_order");
|
|
327
|
-
if (events.some((event) => event.type === "request.opened")) checks.push("request_resolution");
|
|
328
|
-
checks.push("steering");
|
|
359
|
+
const turnChecksIndex = checks.length;
|
|
329
360
|
if (instance.capabilities.turns.interrupt) {
|
|
330
361
|
let interruptedBindingCount = 0;
|
|
331
362
|
const interrupted = await instance.adapter.createSession({
|
|
@@ -363,15 +394,15 @@ async function runAgentProviderConformance(scenario) {
|
|
|
363
394
|
"interruption",
|
|
364
395
|
"Live turn interruption did not succeed."
|
|
365
396
|
);
|
|
366
|
-
const outputs = await collectRemainingOutputs(liveTurn);
|
|
397
|
+
const { outputs } = await collectRemainingOutputs(liveTurn);
|
|
367
398
|
requireCheck(
|
|
368
399
|
semanticEvents(outputs).some((event) => event.type === "turn.completed"),
|
|
369
400
|
"interruption",
|
|
370
401
|
"Interrupted turn did not produce native terminal output."
|
|
371
402
|
);
|
|
372
403
|
} finally {
|
|
373
|
-
|
|
374
|
-
await
|
|
404
|
+
const closing = interrupted.close({ reason: "other" });
|
|
405
|
+
await Promise.all([closing, liveTurn?.iterator.return?.()]);
|
|
375
406
|
}
|
|
376
407
|
} else {
|
|
377
408
|
requireCheck(
|
|
@@ -527,28 +558,83 @@ async function runAgentProviderConformance(scenario) {
|
|
|
527
558
|
);
|
|
528
559
|
}
|
|
529
560
|
checks.push("collaboration");
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
561
|
+
const turnChecks = [];
|
|
562
|
+
const startedTurn = await advanceToStartedTurn(created, scenario.turn);
|
|
563
|
+
let turnResult;
|
|
564
|
+
try {
|
|
565
|
+
if (instance.capabilities.turns.steer.kind === "supported") {
|
|
566
|
+
requireCheck(
|
|
567
|
+
created.steering.kind === "supported",
|
|
568
|
+
"steering",
|
|
569
|
+
"Steering capability has no handler."
|
|
570
|
+
);
|
|
571
|
+
const result = await created.steering.steerTurn({
|
|
572
|
+
turnId: scenario.turn.turnId,
|
|
573
|
+
...scenario.steeringInput ?? {
|
|
574
|
+
parts: [
|
|
575
|
+
{ type: "text", text: "Additional conformance input." }
|
|
576
|
+
]
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
requireCheck(
|
|
580
|
+
result.status === "delivered",
|
|
581
|
+
"steering",
|
|
582
|
+
"Steering did not deliver to the live turn."
|
|
583
|
+
);
|
|
584
|
+
} else {
|
|
585
|
+
requireCheck(
|
|
586
|
+
created.steering.kind === "unsupported",
|
|
587
|
+
"steering",
|
|
588
|
+
"Unsupported steering exposed a handler."
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
turnResult = await collectRemainingOutputs(startedTurn, scenario.resolutionFor, async () => {
|
|
592
|
+
if (instance.capabilities.generatedResources.kind === "supported") {
|
|
593
|
+
requireCheck(
|
|
594
|
+
created.generatedResources.kind === "supported" && scenario.generatedResourceId !== void 0,
|
|
595
|
+
"generated_resources",
|
|
596
|
+
"Supported generated resources require an access port and fixture."
|
|
597
|
+
);
|
|
598
|
+
const resource = await created.generatedResources.getGeneratedResource({
|
|
599
|
+
resourceId: scenario.generatedResourceId
|
|
600
|
+
});
|
|
601
|
+
requireCheck(
|
|
602
|
+
resource.descriptor.resourceId === scenario.generatedResourceId,
|
|
603
|
+
"generated_resources",
|
|
604
|
+
"Generated resource access returned another resource."
|
|
605
|
+
);
|
|
606
|
+
} else {
|
|
607
|
+
requireCheck(
|
|
608
|
+
created.generatedResources.kind === "unsupported",
|
|
609
|
+
"generated_resources",
|
|
610
|
+
"Unsupported generated resources exposed an access port."
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
checks.push("generated_resources");
|
|
538
614
|
});
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
);
|
|
544
|
-
|
|
545
|
-
requireCheck(
|
|
546
|
-
created.generatedResources.kind === "unsupported",
|
|
547
|
-
"generated_resources",
|
|
548
|
-
"Unsupported generated resources exposed an access port."
|
|
549
|
-
);
|
|
615
|
+
} catch (error) {
|
|
616
|
+
const closing = created.close({ reason: "contract_rejected" });
|
|
617
|
+
const settled = await Promise.allSettled([closing, startedTurn.iterator.return?.()]);
|
|
618
|
+
const failures = settled.flatMap((result) => result.status === "rejected" ? [result.reason] : []);
|
|
619
|
+
if (failures.length > 0) throw new AggregateError([error, ...failures], "Conformance turn and cleanup failed.", { cause: error });
|
|
620
|
+
throw error;
|
|
550
621
|
}
|
|
551
|
-
|
|
622
|
+
const events = semanticEvents(turnResult.outputs);
|
|
623
|
+
requireCheck(
|
|
624
|
+
events[0]?.type === "turn.started",
|
|
625
|
+
"turn_order",
|
|
626
|
+
"Turn did not start first."
|
|
627
|
+
);
|
|
628
|
+
requireCheck(
|
|
629
|
+
hasStableTurnBoundary(events),
|
|
630
|
+
"turn_order",
|
|
631
|
+
"Turn did not terminate or enter a waiting state."
|
|
632
|
+
);
|
|
633
|
+
turnChecks.push("turn_order");
|
|
634
|
+
if (turnResult.deliveredRequests > 0) turnChecks.push("request_resolution");
|
|
635
|
+
if (events.some((event) => event.type === "request.unavailable")) turnChecks.push("request_unavailability");
|
|
636
|
+
turnChecks.push("steering");
|
|
637
|
+
checks.splice(turnChecksIndex, 0, ...turnChecks);
|
|
552
638
|
await created.close({ reason: "idle" });
|
|
553
639
|
await created.close({ reason: "idle" });
|
|
554
640
|
checks.push("idempotent_session_close");
|
|
@@ -621,9 +707,17 @@ async function runAgentProviderConformance(scenario) {
|
|
|
621
707
|
providerKey: scenario.definition.providerKey,
|
|
622
708
|
checks: Object.freeze(checks)
|
|
623
709
|
});
|
|
710
|
+
} catch (error) {
|
|
711
|
+
failure = { error };
|
|
712
|
+
throw error;
|
|
624
713
|
} finally {
|
|
625
|
-
|
|
626
|
-
|
|
714
|
+
try {
|
|
715
|
+
await createdSession?.close({ reason: "contract_rejected" });
|
|
716
|
+
if (!disposed) await registry.dispose();
|
|
717
|
+
} catch (error) {
|
|
718
|
+
if (failure) throw new AggregateError([failure.error, error], "Conformance and final cleanup failed.", { cause: failure.error });
|
|
719
|
+
throw error;
|
|
720
|
+
}
|
|
627
721
|
}
|
|
628
722
|
}
|
|
629
723
|
export {
|
|
@@ -44,7 +44,7 @@ function defaultCapabilities(providerKey) {
|
|
|
44
44
|
}
|
|
45
45
|
};
|
|
46
46
|
return parseAgentCapabilities({
|
|
47
|
-
protocolVersion:
|
|
47
|
+
protocolVersion: 12,
|
|
48
48
|
providerKey,
|
|
49
49
|
sessions: { create: true, resume: true, branch: { kind: "through_turn" } },
|
|
50
50
|
turns: {
|
|
@@ -55,6 +55,7 @@ function defaultCapabilities(providerKey) {
|
|
|
55
55
|
requests: {
|
|
56
56
|
approval: {
|
|
57
57
|
kind: "supported",
|
|
58
|
+
providerManagedRemembrance: false,
|
|
58
59
|
modes: [{ persistence: "once", scopeKinds: ["exact_action"] }]
|
|
59
60
|
},
|
|
60
61
|
elicitation: {
|
|
@@ -165,7 +166,7 @@ function sessionBinding(state, sessionId) {
|
|
|
165
166
|
};
|
|
166
167
|
}
|
|
167
168
|
function eventBase(sessionId, turnId, occurredAt) {
|
|
168
|
-
return { protocolVersion:
|
|
169
|
+
return { protocolVersion: 12, sessionId, turnId, occurredAt };
|
|
169
170
|
}
|
|
170
171
|
function fakeEnvironmentSnapshot(environmentId) {
|
|
171
172
|
return parseAgentEnvironmentSnapshot({
|
|
@@ -251,15 +252,13 @@ function requestForTurn(turnId) {
|
|
|
251
252
|
optionId: parseAgentApprovalOptionId("approval:allow-once"),
|
|
252
253
|
label: "Allow once",
|
|
253
254
|
decision: "approved",
|
|
254
|
-
persistence: "once",
|
|
255
|
-
scope: { kind: "exact_action" }
|
|
255
|
+
consequence: { kind: "scoped", persistence: "once", scope: { kind: "exact_action" } }
|
|
256
256
|
},
|
|
257
257
|
{
|
|
258
258
|
optionId: parseAgentApprovalOptionId("approval:deny-once"),
|
|
259
259
|
label: "Deny",
|
|
260
260
|
decision: "denied",
|
|
261
|
-
persistence: "once",
|
|
262
|
-
scope: { kind: "exact_action" }
|
|
261
|
+
consequence: { kind: "scoped", persistence: "once", scope: { kind: "exact_action" } }
|
|
263
262
|
}
|
|
264
263
|
]
|
|
265
264
|
};
|
|
@@ -1,26 +1,43 @@
|
|
|
1
|
-
import { type AgentProviderKey } from "@agen-ai/agent-protocol";
|
|
1
|
+
import { type AgentProviderKey, type AgentTurnId } from "@agen-ai/agent-protocol";
|
|
2
2
|
import type { AgentProviderOutput } from "../outputs.js";
|
|
3
|
+
import type { AgentSessionAdmission } from "../sessionAdmission.js";
|
|
3
4
|
import type { AgentProviderStartTurnInput, AgentProviderTurnExecution } from "../sessions.js";
|
|
4
|
-
import { type PendingAgentRequest, type SuspendedAgentTurnRequests } from "./requests.js";
|
|
5
|
+
import { type AgentTurnRequestAdmission, type PendingAgentRequest, type SuspendedAgentTurnRequests } from "./requests.js";
|
|
5
6
|
export interface ValidatedAgentTurnExecution {
|
|
6
7
|
readonly execution: AgentProviderTurnExecution;
|
|
7
8
|
readonly hasEntered: () => boolean;
|
|
8
9
|
readonly stop: (reason: Error) => void;
|
|
9
10
|
readonly join: () => Promise<void>;
|
|
10
11
|
readonly suspendRequests: () => SuspendedAgentTurnRequests;
|
|
12
|
+
readonly completed: Promise<void>;
|
|
11
13
|
}
|
|
12
|
-
|
|
14
|
+
type ExecutionOptions = Readonly<{
|
|
13
15
|
providerKey: AgentProviderKey;
|
|
14
|
-
turnInput: AgentProviderStartTurnInput;
|
|
15
16
|
pendingRequests: Map<string, PendingAgentRequest>;
|
|
17
|
+
sessionAdmission: AgentSessionAdmission;
|
|
16
18
|
inFlightOperations: Set<Promise<void>>;
|
|
17
|
-
start: (input: AgentProviderStartTurnInput) => AgentProviderTurnExecution;
|
|
18
19
|
requireUsable: () => void;
|
|
19
20
|
isTerminal: () => boolean;
|
|
20
|
-
|
|
21
|
+
canRestoreRequest: (pending: PendingAgentRequest) => boolean;
|
|
22
|
+
observe: (output: AgentProviderOutput, requests: AgentTurnRequestAdmission) => AgentProviderOutput;
|
|
21
23
|
assertCompleted: () => void;
|
|
22
24
|
release: () => void;
|
|
23
25
|
retire: () => void;
|
|
24
26
|
abandon: () => Promise<void>;
|
|
27
|
+
}>;
|
|
28
|
+
export declare function createValidatedAgentTurnExecution(input: ExecutionOptions & Readonly<{
|
|
29
|
+
turnInput: AgentProviderStartTurnInput;
|
|
30
|
+
start: (input: AgentProviderStartTurnInput) => AgentProviderTurnExecution;
|
|
25
31
|
}>): ValidatedAgentTurnExecution;
|
|
32
|
+
export interface AdoptedAgentTurnExecution extends ValidatedAgentTurnExecution {
|
|
33
|
+
readonly readerReady: Promise<void>;
|
|
34
|
+
readonly admitDispatch: () => void;
|
|
35
|
+
readonly settleNoWork: () => void;
|
|
36
|
+
readonly markStarted: () => void;
|
|
37
|
+
}
|
|
38
|
+
export declare function adoptValidatedAgentTurnExecution(input: ExecutionOptions & Readonly<{
|
|
39
|
+
turnId: AgentTurnId;
|
|
40
|
+
createCandidate: (signal: AbortSignal) => AgentProviderTurnExecution;
|
|
41
|
+
}>): AdoptedAgentTurnExecution;
|
|
42
|
+
export {};
|
|
26
43
|
//# sourceMappingURL=execution.d.ts.map
|