@agen-ai/agent-runtime 0.4.1 → 0.4.3
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 +176 -74
- package/dist/adapterValidation.d.ts +4 -2
- package/dist/adapterValidation.js +108 -59
- package/dist/contractErrors.d.ts +1 -1
- package/dist/contractErrors.js +7 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -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 +1 -0
- package/dist/providerCatalog.d.ts +1 -1
- package/dist/providerDriver.d.ts +4 -1
- package/dist/providerInstanceRegistry.d.ts +4 -4
- package/dist/sessionAdmission.d.ts +14 -0
- package/dist/sessionAdmission.js +67 -0
- package/dist/sessionInteractions/lifetime.d.ts +32 -3
- package/dist/sessionInteractions/lifetime.js +145 -13
- package/dist/sessionInteractions/request.d.ts +3 -2
- package/dist/sessionInteractions/request.js +98 -25
- package/dist/sessionInteractions/types.d.ts +68 -12
- package/dist/sessionInteractions/validation.d.ts +13 -9
- package/dist/sessionInteractions/validation.js +121 -60
- package/dist/sessionValidation.d.ts +80 -2
- package/dist/sessionValidation.js +348 -283
- package/dist/sessions.d.ts +33 -2
- package/dist/testing/conformance.d.ts +3 -1
- package/dist/testing/conformance.js +180 -85
- package/dist/testing/fakeProvider.js +2 -2
- 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/contractErrors.js
CHANGED
|
@@ -26,6 +26,7 @@ const AGENT_PROVIDER_CONTRACT_ERROR_CODES = [
|
|
|
26
26
|
"input_capability_mismatch",
|
|
27
27
|
"invalid_turn_sequence",
|
|
28
28
|
"request_resolution_mismatch",
|
|
29
|
+
"request_identity_limit_exceeded",
|
|
29
30
|
"configuration_key_unsupported",
|
|
30
31
|
"configuration_value_unsupported",
|
|
31
32
|
"request_pending",
|
|
@@ -38,7 +39,12 @@ const AGENT_PROVIDER_CONTRACT_ERROR_CODES = [
|
|
|
38
39
|
"host_tool_result_invalid",
|
|
39
40
|
"host_tool_capacity_exhausted",
|
|
40
41
|
"invalid_session_interaction",
|
|
41
|
-
"session_interactions_unsupported"
|
|
42
|
+
"session_interactions_unsupported",
|
|
43
|
+
"native_continuations_unsupported",
|
|
44
|
+
"native_continuation_preparation_failed",
|
|
45
|
+
"native_continuation_reader_not_ready",
|
|
46
|
+
"native_continuation_limit_exceeded",
|
|
47
|
+
"invalid_native_continuation"
|
|
42
48
|
];
|
|
43
49
|
class AgentProviderContractError extends Error {
|
|
44
50
|
constructor(providerKey, code, message, options) {
|
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export * from "./providerInstanceRegistry.js";
|
|
|
14
14
|
export * from "./readiness.js";
|
|
15
15
|
export * from "./sessions.js";
|
|
16
16
|
export * from "./sessionInteractions/index.js";
|
|
17
|
+
export * from "./nativeContinuations/index.js";
|
|
17
18
|
export { createAgentProviderSessionCleanupError, isAgentProviderSessionCleanupErrorFor } from "./sessionCleanup.js";
|
|
18
19
|
export * from "./text.js";
|
|
19
20
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,7 @@ export * from "./providerInstanceRegistry.js";
|
|
|
14
14
|
export * from "./readiness.js";
|
|
15
15
|
export * from "./sessions.js";
|
|
16
16
|
export * from "./sessionInteractions/index.js";
|
|
17
|
+
export * from "./nativeContinuations/index.js";
|
|
17
18
|
import { createAgentProviderSessionCleanupError, isAgentProviderSessionCleanupErrorFor } from "./sessionCleanup.js";
|
|
18
19
|
export * from "./text.js";
|
|
19
20
|
export {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type AgentSessionResponse } from "@agen-ai/agent-protocol";
|
|
2
|
+
import type { AgentRequestResolutionResult } from "../sessions.js";
|
|
3
|
+
import type { SessionInteractionOwner } from "../sessionInteractions/lifetime.js";
|
|
4
|
+
import type { AgentProviderPreparedSessionInteraction } from "../sessionInteractions/types.js";
|
|
5
|
+
import type { AgentSessionResponseAttemptId } from "./types.js";
|
|
6
|
+
export declare function mintSessionResponseAttemptId(): AgentSessionResponseAttemptId;
|
|
7
|
+
export declare function dispatchPreparedSessionResponse(input: Readonly<{
|
|
8
|
+
owner: SessionInteractionOwner;
|
|
9
|
+
candidate: AgentProviderPreparedSessionInteraction;
|
|
10
|
+
response: AgentSessionResponse;
|
|
11
|
+
attemptId: AgentSessionResponseAttemptId;
|
|
12
|
+
signal: AbortSignal;
|
|
13
|
+
requireCurrent: () => void;
|
|
14
|
+
onDispatch: (deadline: number) => void;
|
|
15
|
+
observeActualReceipt: (work: Promise<AgentRequestResolutionResult>) => void;
|
|
16
|
+
}>): Promise<AgentRequestResolutionResult>;
|
|
17
|
+
//# sourceMappingURL=admission.d.ts.map
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { parseAgentTurnId } from "@agen-ai/agent-protocol";
|
|
3
|
+
import { AgentProviderContractError, AgentProviderSessionCleanupError } from "../contractErrors.js";
|
|
4
|
+
import { interactionRecord } from "../sessionInteractions/validation.js";
|
|
5
|
+
import { hasExactOwnKeys } from "../internal/objectShape.js";
|
|
6
|
+
import { validateAgentRequestResolutionResult } from "../turnExecution/receipts.js";
|
|
7
|
+
function mintSessionResponseAttemptId() {
|
|
8
|
+
return randomUUID();
|
|
9
|
+
}
|
|
10
|
+
function continuationError(owner, code, message, cause) {
|
|
11
|
+
return new AgentProviderContractError(owner.providerKey, code, message, ...cause === void 0 ? [] : [{ cause }]);
|
|
12
|
+
}
|
|
13
|
+
function until(work, deadline, failure, signal) {
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
const timer = setTimeout(() => reject(failure()), Math.max(0, deadline - Date.now()));
|
|
16
|
+
const aborted = () => reject(signal?.reason ?? new DOMException("Prepared response was aborted.", "AbortError"));
|
|
17
|
+
signal?.addEventListener("abort", aborted, { once: true });
|
|
18
|
+
if (signal?.aborted) aborted();
|
|
19
|
+
void work.then(resolve, reject).finally(() => {
|
|
20
|
+
clearTimeout(timer);
|
|
21
|
+
signal?.removeEventListener("abort", aborted);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function capturePrepared(input) {
|
|
26
|
+
const value = interactionRecord(input);
|
|
27
|
+
if (typeof value.dispatch !== "function" || typeof value.cancel !== "function") throw new TypeError("Prepared response requires dispatch and cancellation ports.");
|
|
28
|
+
if (value.kind === "no_continuation" && hasExactOwnKeys(value, ["kind", "dispatch", "cancel"])) {
|
|
29
|
+
return Object.freeze({ kind: "no_continuation", dispatch: value.dispatch.bind(input), cancel: value.cancel.bind(input) });
|
|
30
|
+
}
|
|
31
|
+
if (value.kind === "native_continuation" && hasExactOwnKeys(value, ["kind", "dispatch", "cancel", "createExecution", "outcome"]) && typeof value.createExecution === "function" && value.outcome && typeof interactionRecord(value.outcome).then === "function") {
|
|
32
|
+
return Object.freeze({
|
|
33
|
+
kind: "native_continuation",
|
|
34
|
+
dispatch: value.dispatch.bind(input),
|
|
35
|
+
cancel: value.cancel.bind(input),
|
|
36
|
+
createExecution: value.createExecution.bind(input),
|
|
37
|
+
outcome: Promise.resolve(value.outcome)
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
throw new TypeError("Invalid prepared response.");
|
|
41
|
+
}
|
|
42
|
+
function outcome(input) {
|
|
43
|
+
const value = interactionRecord(input);
|
|
44
|
+
if (!hasExactOwnKeys(value, ["kind"]) || value.kind !== "started" && value.kind !== "not_started") throw new TypeError("Invalid continuation outcome.");
|
|
45
|
+
return Object.freeze({ kind: value.kind });
|
|
46
|
+
}
|
|
47
|
+
async function dispatchPreparedSessionResponse(input) {
|
|
48
|
+
const { owner } = input;
|
|
49
|
+
const readinessDeadline = Date.now() + 3e4;
|
|
50
|
+
const controller = new AbortController();
|
|
51
|
+
const signal = AbortSignal.any([input.signal, controller.signal, owner.openingSignal]);
|
|
52
|
+
let prepared;
|
|
53
|
+
let execution;
|
|
54
|
+
let reservation;
|
|
55
|
+
let entered = false;
|
|
56
|
+
let callback;
|
|
57
|
+
let callbackFailure;
|
|
58
|
+
let cancelAttempt;
|
|
59
|
+
let canceled = false;
|
|
60
|
+
let actualOutcome;
|
|
61
|
+
let earlyOutcome;
|
|
62
|
+
let outcomeFailure;
|
|
63
|
+
let resolveOutcome;
|
|
64
|
+
let rejectOutcome;
|
|
65
|
+
const publicOutcome = new Promise((resolve, reject) => {
|
|
66
|
+
resolveOutcome = resolve;
|
|
67
|
+
rejectOutcome = reject;
|
|
68
|
+
});
|
|
69
|
+
void publicOutcome.catch(() => {
|
|
70
|
+
});
|
|
71
|
+
const actualPreparation = owner.track(Promise.resolve().then(() => {
|
|
72
|
+
input.requireCurrent();
|
|
73
|
+
owner.requireUsable();
|
|
74
|
+
return input.candidate.prepareResponse({
|
|
75
|
+
response: input.response,
|
|
76
|
+
responseAttemptId: input.attemptId,
|
|
77
|
+
signal
|
|
78
|
+
});
|
|
79
|
+
}).then((value) => {
|
|
80
|
+
try {
|
|
81
|
+
return capturePrepared(value);
|
|
82
|
+
} catch (cause) {
|
|
83
|
+
throw continuationError(owner, "invalid_native_continuation", "Provider returned an invalid prepared response.", cause);
|
|
84
|
+
}
|
|
85
|
+
}).then((value) => {
|
|
86
|
+
prepared = value;
|
|
87
|
+
if (value.kind === "native_continuation") {
|
|
88
|
+
actualOutcome = owner.track(value.outcome.then((value2) => {
|
|
89
|
+
const parsed = outcome(value2);
|
|
90
|
+
if (!entered) {
|
|
91
|
+
earlyOutcome = parsed;
|
|
92
|
+
if (parsed.kind === "started") throw continuationError(owner, "invalid_native_continuation", "Provider started native work before dispatch.");
|
|
93
|
+
}
|
|
94
|
+
return parsed;
|
|
95
|
+
}).catch((cause) => {
|
|
96
|
+
throw cause instanceof AgentProviderContractError && cause.code === "invalid_native_continuation" ? cause : continuationError(owner, "invalid_native_continuation", "Provider native continuation outcome is invalid.", cause);
|
|
97
|
+
}));
|
|
98
|
+
void actualOutcome.catch((cause) => {
|
|
99
|
+
outcomeFailure = cause;
|
|
100
|
+
if (entered) owner.fail(cause);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return value;
|
|
104
|
+
}));
|
|
105
|
+
void actualPreparation.catch(() => {
|
|
106
|
+
});
|
|
107
|
+
const cancel = () => {
|
|
108
|
+
if (canceled) return Promise.resolve();
|
|
109
|
+
if (cancelAttempt) return cancelAttempt;
|
|
110
|
+
controller.abort(new DOMException("Prepared response admission was canceled.", "AbortError"));
|
|
111
|
+
cancelAttempt = (async () => {
|
|
112
|
+
let value;
|
|
113
|
+
try {
|
|
114
|
+
value = prepared ?? await actualPreparation;
|
|
115
|
+
} catch (cause) {
|
|
116
|
+
cleanup();
|
|
117
|
+
owner.fail(cause);
|
|
118
|
+
throw continuationError(owner, "native_continuation_preparation_failed", "Preparation failed without returning its allocated cancellation owner.", cause);
|
|
119
|
+
}
|
|
120
|
+
execution?.stop(new DOMException("Prepared execution admission was canceled.", "AbortError"));
|
|
121
|
+
await value.cancel();
|
|
122
|
+
execution?.settleNoWork();
|
|
123
|
+
await execution?.join();
|
|
124
|
+
if (value.kind === "native_continuation") {
|
|
125
|
+
const result = await actualOutcome;
|
|
126
|
+
if (result?.kind !== "not_started") throw continuationError(owner, "invalid_native_continuation", "Canceled preparation did not prove no native work.");
|
|
127
|
+
}
|
|
128
|
+
resolveOutcome(Object.freeze({ kind: "not_started" }));
|
|
129
|
+
await callback?.catch(() => {
|
|
130
|
+
});
|
|
131
|
+
if (reservation) owner.validationOwner.releaseExecution(reservation);
|
|
132
|
+
canceled = true;
|
|
133
|
+
})().finally(() => {
|
|
134
|
+
cancelAttempt = void 0;
|
|
135
|
+
});
|
|
136
|
+
void cancelAttempt.catch(() => {
|
|
137
|
+
});
|
|
138
|
+
return cancelAttempt;
|
|
139
|
+
};
|
|
140
|
+
const cleanup = owner.retainPreparation(async () => {
|
|
141
|
+
if (!entered) await cancel();
|
|
142
|
+
});
|
|
143
|
+
try {
|
|
144
|
+
const value = await until(actualPreparation, readinessDeadline, () => continuationError(owner, "native_continuation_preparation_failed", "Native continuation preparation did not finish before its deadline."), signal);
|
|
145
|
+
input.requireCurrent();
|
|
146
|
+
owner.requireUsable();
|
|
147
|
+
if (outcomeFailure) throw outcomeFailure;
|
|
148
|
+
if (earlyOutcome) throw continuationError(owner, "invalid_native_continuation", "Prepared outcome forbids native response dispatch.");
|
|
149
|
+
if (value.kind === "native_continuation") {
|
|
150
|
+
owner.requireContinuation(input.candidate.request.kind);
|
|
151
|
+
reservation = owner.validationOwner.reserveExecution();
|
|
152
|
+
const turnId = parseAgentTurnId(`native-${randomUUID()}`);
|
|
153
|
+
execution = owner.validationOwner.installNativeExecution(reservation, turnId, (executionSignal) => value.createExecution({ turnId, signal: executionSignal }));
|
|
154
|
+
const offered = execution;
|
|
155
|
+
try {
|
|
156
|
+
callback = Promise.resolve(owner.continuations.onExecution(Object.freeze({
|
|
157
|
+
sessionId: owner.sessionId,
|
|
158
|
+
requestId: input.candidate.request.requestId,
|
|
159
|
+
responseAttemptId: input.attemptId,
|
|
160
|
+
execution: offered.execution,
|
|
161
|
+
outcome: publicOutcome
|
|
162
|
+
})));
|
|
163
|
+
} catch (cause) {
|
|
164
|
+
callbackFailure = { cause };
|
|
165
|
+
callback = Promise.reject(cause);
|
|
166
|
+
}
|
|
167
|
+
owner.track(callback);
|
|
168
|
+
const rejection = new Promise((_, reject) => {
|
|
169
|
+
void callback.catch(reject);
|
|
170
|
+
});
|
|
171
|
+
void callback.catch((cause) => {
|
|
172
|
+
callbackFailure = { cause };
|
|
173
|
+
if (entered) owner.fail(cause);
|
|
174
|
+
});
|
|
175
|
+
await until(
|
|
176
|
+
Promise.race([offered.readerReady, rejection]),
|
|
177
|
+
readinessDeadline,
|
|
178
|
+
() => continuationError(owner, "native_continuation_reader_not_ready", "Native continuation requires an outstanding output pull."),
|
|
179
|
+
signal
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
input.requireCurrent();
|
|
183
|
+
owner.requireUsable();
|
|
184
|
+
if (signal.aborted) throw signal.reason;
|
|
185
|
+
if (Date.now() >= readinessDeadline) throw continuationError(owner, "native_continuation_reader_not_ready", "Native continuation reader admission expired.");
|
|
186
|
+
if (callbackFailure) throw continuationError(owner, "native_continuation_reader_not_ready", "Native continuation host rejected output ownership before dispatch.", callbackFailure.cause);
|
|
187
|
+
if (outcomeFailure || earlyOutcome) throw outcomeFailure ?? continuationError(owner, "invalid_native_continuation", "Prepared outcome arrived before dispatch.");
|
|
188
|
+
if (reservation && !owner.validationOwner.ownsExecution(reservation)) throw continuationError(owner, "invalid_native_continuation", "Native continuation lost its execution reservation.");
|
|
189
|
+
try {
|
|
190
|
+
execution?.admitDispatch();
|
|
191
|
+
} catch (cause) {
|
|
192
|
+
throw continuationError(owner, "native_continuation_reader_not_ready", "Native continuation output ownership ended before dispatch.", cause);
|
|
193
|
+
}
|
|
194
|
+
const responseDeadline = Date.now() + owner.limits.responseTimeoutMs;
|
|
195
|
+
entered = true;
|
|
196
|
+
input.onDispatch(responseDeadline);
|
|
197
|
+
let actualReceipt;
|
|
198
|
+
try {
|
|
199
|
+
actualReceipt = Promise.resolve(value.dispatch()).then((result) => validateAgentRequestResolutionResult(result, owner.providerKey));
|
|
200
|
+
} catch (cause) {
|
|
201
|
+
actualReceipt = Promise.reject(cause);
|
|
202
|
+
}
|
|
203
|
+
owner.track(actualReceipt);
|
|
204
|
+
input.observeActualReceipt(actualReceipt);
|
|
205
|
+
if (actualOutcome && execution) {
|
|
206
|
+
const currentExecution = execution;
|
|
207
|
+
const exactReservation = reservation;
|
|
208
|
+
const observedOutcome = until(actualOutcome, responseDeadline, () => continuationError(owner, "invalid_native_continuation", "Native continuation outcome did not settle before its response deadline."));
|
|
209
|
+
owner.track(observedOutcome.then(async (result) => {
|
|
210
|
+
resolveOutcome(result);
|
|
211
|
+
if (result.kind === "not_started") currentExecution.settleNoWork();
|
|
212
|
+
else currentExecution.markStarted();
|
|
213
|
+
await currentExecution.completed;
|
|
214
|
+
await actualReceipt.catch(() => {
|
|
215
|
+
});
|
|
216
|
+
await callback?.catch(() => {
|
|
217
|
+
});
|
|
218
|
+
await currentExecution.join();
|
|
219
|
+
owner.validationOwner.releaseExecution(exactReservation);
|
|
220
|
+
}).catch((cause) => {
|
|
221
|
+
rejectOutcome(cause);
|
|
222
|
+
owner.fail(cause);
|
|
223
|
+
}));
|
|
224
|
+
}
|
|
225
|
+
return await until(actualReceipt, responseDeadline, () => new Error("Session response delivery observation expired."));
|
|
226
|
+
} catch (cause) {
|
|
227
|
+
if (entered) throw cause;
|
|
228
|
+
let failure = cause;
|
|
229
|
+
if (!(cause instanceof AgentProviderContractError) && !(cause instanceof DOMException && cause.name === "AbortError")) {
|
|
230
|
+
failure = continuationError(owner, prepared ? "native_continuation_reader_not_ready" : "native_continuation_preparation_failed", "Native continuation failed before response entry.", cause);
|
|
231
|
+
}
|
|
232
|
+
try {
|
|
233
|
+
await until(cancel(), Date.now() + owner.limits.cleanupTimeoutMs, () => new Error("Prepared cancellation did not finish before its deadline."));
|
|
234
|
+
} catch (cleanupFailure) {
|
|
235
|
+
owner.fail(failure);
|
|
236
|
+
throw new AgentProviderSessionCleanupError({ providerKey: owner.providerKey, errors: [failure, cleanupFailure], retryCleanup: async () => {
|
|
237
|
+
if (prepared) await cancel();
|
|
238
|
+
else await owner.cleanupFailedPreparation();
|
|
239
|
+
} });
|
|
240
|
+
}
|
|
241
|
+
if (failure instanceof AgentProviderContractError && failure.code === "invalid_native_continuation") owner.fail(failure);
|
|
242
|
+
throw failure;
|
|
243
|
+
} finally {
|
|
244
|
+
if (entered || canceled) cleanup();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
export {
|
|
248
|
+
dispatchPreparedSessionResponse,
|
|
249
|
+
mintSessionResponseAttemptId
|
|
250
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./types.js";
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { AgentRequestId, AgentSessionId, AgentTurnId } from "@agen-ai/agent-protocol";
|
|
2
|
+
import type { MaybePromise } from "../foundation.js";
|
|
3
|
+
import type { AgentProviderTurnExecution, AgentRequestResolutionResult } from "../sessions.js";
|
|
4
|
+
import type { AgentSessionInteractionOpeningOperation } from "../sessionInteractions/types.js";
|
|
5
|
+
declare const agentSessionResponseAttemptIdBrand: unique symbol;
|
|
6
|
+
export type AgentSessionResponseAttemptId = string & {
|
|
7
|
+
readonly [agentSessionResponseAttemptIdBrand]: "AgentSessionResponseAttemptId";
|
|
8
|
+
};
|
|
9
|
+
export type AgentNativeContinuationTiming = "after_open_return" | "before_open_return" | "before_binding";
|
|
10
|
+
export interface AgentNativeContinuationMapping {
|
|
11
|
+
readonly openingOperation: AgentSessionInteractionOpeningOperation;
|
|
12
|
+
readonly requestKind: "form" | "plan_review";
|
|
13
|
+
readonly timing: AgentNativeContinuationTiming;
|
|
14
|
+
}
|
|
15
|
+
export type AgentNativeContinuationSupport = Readonly<{
|
|
16
|
+
kind: "unsupported";
|
|
17
|
+
}> | Readonly<{
|
|
18
|
+
kind: "supported";
|
|
19
|
+
mappings: readonly [AgentNativeContinuationMapping, ...AgentNativeContinuationMapping[]];
|
|
20
|
+
producerOwnership: "exclusive";
|
|
21
|
+
}>;
|
|
22
|
+
export type AgentNativeContinuationOutcome = Readonly<{
|
|
23
|
+
kind: "started";
|
|
24
|
+
}> | Readonly<{
|
|
25
|
+
kind: "not_started";
|
|
26
|
+
}>;
|
|
27
|
+
export interface AgentPreparedSessionResponseControl {
|
|
28
|
+
readonly dispatch: () => Promise<AgentRequestResolutionResult>;
|
|
29
|
+
readonly cancel: () => Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
export type AgentPreparedSessionResponse = (AgentPreparedSessionResponseControl & Readonly<{
|
|
32
|
+
kind: "no_continuation";
|
|
33
|
+
}>) | (AgentPreparedSessionResponseControl & Readonly<{
|
|
34
|
+
kind: "native_continuation";
|
|
35
|
+
createExecution: (input: Readonly<{
|
|
36
|
+
turnId: AgentTurnId;
|
|
37
|
+
signal: AbortSignal;
|
|
38
|
+
}>) => AgentProviderTurnExecution;
|
|
39
|
+
outcome: Promise<AgentNativeContinuationOutcome>;
|
|
40
|
+
}>);
|
|
41
|
+
export interface AgentNativeContinuation {
|
|
42
|
+
readonly sessionId: AgentSessionId;
|
|
43
|
+
readonly requestId: AgentRequestId;
|
|
44
|
+
readonly responseAttemptId: AgentSessionResponseAttemptId;
|
|
45
|
+
readonly execution: AgentProviderTurnExecution;
|
|
46
|
+
readonly outcome: Promise<AgentNativeContinuationOutcome>;
|
|
47
|
+
}
|
|
48
|
+
export interface AgentNativeContinuationContext {
|
|
49
|
+
readonly onExecution: (continuation: AgentNativeContinuation) => MaybePromise<void>;
|
|
50
|
+
}
|
|
51
|
+
export {};
|
|
52
|
+
//# sourceMappingURL=types.d.ts.map
|
|
File without changes
|
package/dist/outputValidation.js
CHANGED
|
@@ -120,6 +120,7 @@ function isEventCapabilitySupported(capabilities, event) {
|
|
|
120
120
|
case "context.usage.updated":
|
|
121
121
|
return isContextUsageCapabilitySupported(capabilities, event);
|
|
122
122
|
case "turn.started":
|
|
123
|
+
case "request.unavailable":
|
|
123
124
|
case "turn.state_changed":
|
|
124
125
|
case "turn.completed":
|
|
125
126
|
case "progress.updated":
|
|
@@ -9,5 +9,5 @@ export interface AgentProviderInstanceCatalogEntry {
|
|
|
9
9
|
readonly capabilities: AgentCapabilities;
|
|
10
10
|
}
|
|
11
11
|
export declare function createAgentProviderCatalogEntries(drivers: Iterable<AgentProviderDriver>): readonly AgentProviderCatalogEntry[];
|
|
12
|
-
export declare function createAgentProviderInstanceCatalogEntries(instances: readonly MaterializedAgentProviderInstance[]): readonly AgentProviderInstanceCatalogEntry[];
|
|
12
|
+
export declare function createAgentProviderInstanceCatalogEntries(instances: readonly Pick<MaterializedAgentProviderInstance, "instanceId" | "capabilities">[]): readonly AgentProviderInstanceCatalogEntry[];
|
|
13
13
|
//# sourceMappingURL=providerCatalog.d.ts.map
|
package/dist/providerDriver.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { MaybePromise } from "./foundation.js";
|
|
|
3
3
|
import type { AgentAccountQuotaPort } from "./accountQuota/types.js";
|
|
4
4
|
import type { AgentEnvironmentDiscoveryPort } from "./environment/types.js";
|
|
5
5
|
import type { AgentProviderReadiness } from "./readiness.js";
|
|
6
|
-
import type { AgentProviderAdapter } from "./sessions.js";
|
|
6
|
+
import type { AgentProviderAdapter, AgentValidatedProviderAdapter } from "./sessions.js";
|
|
7
7
|
export interface AgentProviderInstanceDefinition {
|
|
8
8
|
readonly providerKey: AgentProviderKey;
|
|
9
9
|
readonly instanceId: AgentInstanceId;
|
|
@@ -21,6 +21,9 @@ export interface MaterializedAgentProviderInstance {
|
|
|
21
21
|
readonly checkReadiness: (input?: AgentProviderReadinessCheckInput) => MaybePromise<AgentProviderReadiness>;
|
|
22
22
|
readonly dispose: () => MaybePromise<void>;
|
|
23
23
|
}
|
|
24
|
+
export type ValidatedMaterializedAgentProviderInstance = Omit<MaterializedAgentProviderInstance, "adapter"> & Readonly<{
|
|
25
|
+
adapter: AgentValidatedProviderAdapter;
|
|
26
|
+
}>;
|
|
24
27
|
export interface AgentProviderDriverCreateInput<Configuration> {
|
|
25
28
|
readonly instanceId: AgentInstanceId;
|
|
26
29
|
readonly configuration: Configuration;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type AgentInstanceId, type AgentProviderKey } from "@agen-ai/agent-protocol";
|
|
2
2
|
import { type AgentProviderCatalogEntry, type AgentProviderInstanceCatalogEntry } from "./providerCatalog.js";
|
|
3
|
-
import { type AgentProviderDriver, type AgentProviderInstanceDefinition, type
|
|
3
|
+
import { type AgentProviderDriver, type AgentProviderInstanceDefinition, type ValidatedMaterializedAgentProviderInstance } from "./providerDriver.js";
|
|
4
4
|
import { type AgentProviderReadiness } from "./readiness.js";
|
|
5
5
|
export declare const AGENT_PROVIDER_REGISTRY_ERROR_CODES: readonly ["invalid_driver", "duplicate_provider", "duplicate_instance", "provider_not_registered", "multiple_instances_unsupported", "invalid_instance_configuration", "instance_materialization_failed", "instance_contract_mismatch", "instance_not_found", "instance_disposed", "instance_cleanup_failed", "registry_disposed"];
|
|
6
6
|
export type AgentProviderRegistryErrorCode = (typeof AGENT_PROVIDER_REGISTRY_ERROR_CODES)[number];
|
|
@@ -22,10 +22,10 @@ export declare class AgentProviderRegistryError extends Error {
|
|
|
22
22
|
export interface AgentProviderRegistry {
|
|
23
23
|
readonly listProviderCatalogEntries: () => readonly AgentProviderCatalogEntry[];
|
|
24
24
|
readonly listInstanceCatalogEntries: () => readonly AgentProviderInstanceCatalogEntry[];
|
|
25
|
-
readonly listInstances: () => readonly
|
|
26
|
-
readonly getInstance: (instanceId: AgentInstanceId) =>
|
|
25
|
+
readonly listInstances: () => readonly ValidatedMaterializedAgentProviderInstance[];
|
|
26
|
+
readonly getInstance: (instanceId: AgentInstanceId) => ValidatedMaterializedAgentProviderInstance | null;
|
|
27
27
|
readonly hasInstance: (instanceId: AgentInstanceId) => boolean;
|
|
28
|
-
readonly requireInstance: (instanceId: AgentInstanceId) =>
|
|
28
|
+
readonly requireInstance: (instanceId: AgentInstanceId) => ValidatedMaterializedAgentProviderInstance;
|
|
29
29
|
readonly checkReadiness: (instanceId: AgentInstanceId, input?: Readonly<{
|
|
30
30
|
signal?: AbortSignal;
|
|
31
31
|
}>) => Promise<AgentProviderReadiness>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AgentProviderKey, AgentRequestId } from "@agen-ai/agent-protocol";
|
|
2
|
+
export declare function createAgentSessionAdmission<Execution = unknown>(providerKey: AgentProviderKey): {
|
|
3
|
+
trackOperation(): () => void;
|
|
4
|
+
joinOperations(): Promise<void>;
|
|
5
|
+
reserveExecution(): object;
|
|
6
|
+
installExecution(token: object, execution: Execution): void;
|
|
7
|
+
releaseExecution(token: object): void;
|
|
8
|
+
readonly execution: Execution | null;
|
|
9
|
+
ownsExecution(token: object): boolean;
|
|
10
|
+
stop(): void;
|
|
11
|
+
claimRequest(requestId: AgentRequestId, duplicateCode: "invalid_turn_sequence" | "invalid_session_interaction"): void;
|
|
12
|
+
};
|
|
13
|
+
export type AgentSessionAdmission = Pick<ReturnType<typeof createAgentSessionAdmission>, "claimRequest">;
|
|
14
|
+
//# sourceMappingURL=sessionAdmission.d.ts.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { throwAgentProviderContractError } from "./contractErrors.js";
|
|
2
|
+
const MAX_REQUEST_IDENTITIES = 4096;
|
|
3
|
+
const MAX_REQUEST_ID_BYTES = 1048576;
|
|
4
|
+
function createAgentSessionAdmission(providerKey) {
|
|
5
|
+
const requestIds = /* @__PURE__ */ new Set();
|
|
6
|
+
let requestIdBytes = 0;
|
|
7
|
+
let slot;
|
|
8
|
+
let stopped = false;
|
|
9
|
+
const operations = /* @__PURE__ */ new Set();
|
|
10
|
+
return {
|
|
11
|
+
trackOperation() {
|
|
12
|
+
if (stopped) throwAgentProviderContractError(providerKey, "session_unusable", "Session admission is stopped.");
|
|
13
|
+
const completion = Promise.withResolvers();
|
|
14
|
+
operations.add(completion.promise);
|
|
15
|
+
return () => {
|
|
16
|
+
operations.delete(completion.promise);
|
|
17
|
+
completion.resolve();
|
|
18
|
+
};
|
|
19
|
+
},
|
|
20
|
+
async joinOperations() {
|
|
21
|
+
await Promise.all(operations);
|
|
22
|
+
},
|
|
23
|
+
reserveExecution() {
|
|
24
|
+
if (stopped) throwAgentProviderContractError(providerKey, "session_unusable", "Session admission is stopped.");
|
|
25
|
+
if (slot) throwAgentProviderContractError(providerKey, "concurrent_turn", "Provider session already owns an execution.");
|
|
26
|
+
const token = Object.freeze({});
|
|
27
|
+
slot = { kind: "reserved", token };
|
|
28
|
+
return token;
|
|
29
|
+
},
|
|
30
|
+
installExecution(token, execution) {
|
|
31
|
+
if (stopped || !slot || slot.token !== token || slot.kind !== "reserved") {
|
|
32
|
+
throwAgentProviderContractError(providerKey, "invalid_native_continuation", "Execution reservation is no longer installable.");
|
|
33
|
+
}
|
|
34
|
+
slot = { kind: "installed", token, execution };
|
|
35
|
+
},
|
|
36
|
+
releaseExecution(token) {
|
|
37
|
+
if (slot?.token === token) slot = void 0;
|
|
38
|
+
},
|
|
39
|
+
get execution() {
|
|
40
|
+
return slot?.kind === "installed" ? slot.execution : null;
|
|
41
|
+
},
|
|
42
|
+
ownsExecution(token) {
|
|
43
|
+
return !stopped && slot?.token === token;
|
|
44
|
+
},
|
|
45
|
+
stop() {
|
|
46
|
+
stopped = true;
|
|
47
|
+
},
|
|
48
|
+
claimRequest(requestId, duplicateCode) {
|
|
49
|
+
if (requestIds.has(requestId)) {
|
|
50
|
+
throwAgentProviderContractError(providerKey, duplicateCode, "Provider reused a request ID within this session generation.");
|
|
51
|
+
}
|
|
52
|
+
const bytes = Buffer.byteLength(requestId, "utf8");
|
|
53
|
+
if (requestIds.size >= MAX_REQUEST_IDENTITIES || requestIdBytes + bytes > MAX_REQUEST_ID_BYTES) {
|
|
54
|
+
throwAgentProviderContractError(
|
|
55
|
+
providerKey,
|
|
56
|
+
"request_identity_limit_exceeded",
|
|
57
|
+
"Provider exceeded this session generation's bounded request identity capacity."
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
requestIds.add(requestId);
|
|
61
|
+
requestIdBytes += bytes;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
createAgentSessionAdmission
|
|
67
|
+
};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { AgentError, AgentProviderKey, AgentSessionId } from "@agen-ai/agent-protocol";
|
|
2
2
|
import type { MaybePromise } from "../foundation.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { AgentSessionAdmission } from "../sessionAdmission.js";
|
|
4
|
+
import type { AgentSessionValidationOwner } from "../sessionValidation.js";
|
|
5
|
+
import type { AgentNativeContinuationContext, AgentNativeContinuationSupport } from "../nativeContinuations/types.js";
|
|
6
|
+
import type { AgentProviderSessionInteractionContext, AgentSessionInteractionContext, AgentSessionInteractionOpeningOperation, AgentSessionInteractionSupport, AgentSessionInteractionTerminal } from "./types.js";
|
|
4
7
|
import { SessionInteractionRequest } from "./request.js";
|
|
5
8
|
import { type ValidatedSessionInteractionContext } from "./validation.js";
|
|
6
9
|
export declare function sessionInteractionError(code: string, message: string, uncertain?: boolean): AgentError;
|
|
@@ -8,7 +11,12 @@ export declare function waitForInteractionWork<Result>(work: Promise<Result>, ti
|
|
|
8
11
|
export declare class SessionInteractionOwner {
|
|
9
12
|
readonly providerKey: AgentProviderKey;
|
|
10
13
|
readonly sessionId: AgentSessionId;
|
|
11
|
-
readonly
|
|
14
|
+
readonly validationOwner: AgentSessionValidationOwner;
|
|
15
|
+
readonly operation: AgentSessionInteractionOpeningOperation;
|
|
16
|
+
readonly support: AgentSessionInteractionSupport;
|
|
17
|
+
readonly nativeSupport: AgentNativeContinuationSupport;
|
|
18
|
+
readonly admission: AgentSessionAdmission;
|
|
19
|
+
readonly facade: AgentProviderSessionInteractionContext;
|
|
12
20
|
readonly openingSignal: AbortSignal;
|
|
13
21
|
readonly limits: ValidatedSessionInteractionContext["limits"];
|
|
14
22
|
readonly failure: Promise<unknown>;
|
|
@@ -25,14 +33,32 @@ export declare class SessionInteractionOwner {
|
|
|
25
33
|
private cleanupAttempt;
|
|
26
34
|
private cleanupDeadline;
|
|
27
35
|
private cleanupComplete;
|
|
36
|
+
private retainedCleanup;
|
|
28
37
|
private cleanupFailure;
|
|
29
38
|
private adopted;
|
|
39
|
+
private bound;
|
|
40
|
+
private returned;
|
|
41
|
+
private readonly waiting;
|
|
42
|
+
private associationTimer;
|
|
43
|
+
private prebindingCount;
|
|
44
|
+
private prebindingBytes;
|
|
45
|
+
private readonly preparations;
|
|
46
|
+
private stoppedExecution;
|
|
47
|
+
readonly continuations: AgentNativeContinuationContext | undefined;
|
|
30
48
|
private readonly context;
|
|
31
|
-
constructor(providerKey: AgentProviderKey, sessionId: AgentSessionId, context: AgentSessionInteractionContext, signal?: AbortSignal);
|
|
49
|
+
constructor(providerKey: AgentProviderKey, sessionId: AgentSessionId, context: AgentSessionInteractionContext, validationOwner: AgentSessionValidationOwner, operation: AgentSessionInteractionOpeningOperation, support: AgentSessionInteractionSupport, nativeSupport: AgentNativeContinuationSupport, continuations?: AgentNativeContinuationContext, signal?: AbortSignal);
|
|
32
50
|
track<Result>(promise: Promise<Result>): Promise<Result>;
|
|
33
51
|
get accepting(): boolean;
|
|
34
52
|
requireUsable(): void;
|
|
35
53
|
private offer;
|
|
54
|
+
requireContinuation(kind: "form" | "plan_review"): void;
|
|
55
|
+
private canPresent;
|
|
56
|
+
bind(): void;
|
|
57
|
+
markReturned(): void;
|
|
58
|
+
private presentWaiting;
|
|
59
|
+
cleanupFailedPreparation(): Promise<void>;
|
|
60
|
+
quiesce(): void;
|
|
61
|
+
retainPreparation(cleanup: () => Promise<void>): () => void;
|
|
36
62
|
installClose(close: () => Promise<void>): void;
|
|
37
63
|
adopt(): void;
|
|
38
64
|
fence(cause: unknown, source: SessionInteractionRequest): void;
|
|
@@ -46,7 +72,10 @@ export declare function createSessionInteractionOwner(input: Readonly<{
|
|
|
46
72
|
sessionId: AgentSessionId;
|
|
47
73
|
operation: AgentSessionInteractionOpeningOperation;
|
|
48
74
|
support: AgentSessionInteractionSupport;
|
|
75
|
+
nativeSupport: AgentNativeContinuationSupport;
|
|
76
|
+
validationOwner: AgentSessionValidationOwner;
|
|
49
77
|
context?: AgentSessionInteractionContext;
|
|
78
|
+
continuations?: AgentNativeContinuationContext;
|
|
50
79
|
signal?: AbortSignal;
|
|
51
80
|
}>): SessionInteractionOwner | undefined;
|
|
52
81
|
//# sourceMappingURL=lifetime.d.ts.map
|