@agen-ai/agent-runtime 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +288 -29
- package/dist/adapterValidation.d.ts +1 -1
- package/dist/adapterValidation.js +199 -92
- package/dist/artifacts.js +0 -1
- package/dist/contractErrors.d.ts +16 -3
- package/dist/contractErrors.js +42 -6
- package/dist/hostBindings/index.d.ts +4 -0
- package/dist/hostBindings/index.js +9 -0
- package/dist/hostBindings/lifetime.d.ts +25 -0
- package/dist/hostBindings/lifetime.js +147 -0
- package/dist/hostBindings/opening.d.ts +14 -0
- package/dist/hostBindings/opening.js +82 -0
- package/dist/hostBindings/schema.d.ts +9 -0
- package/dist/hostBindings/schema.js +169 -0
- package/dist/hostBindings/types.d.ts +71 -0
- package/dist/hostBindings/types.js +0 -0
- package/dist/hostBindings/validation.d.ts +14 -0
- package/dist/hostBindings/validation.js +107 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +7 -0
- package/dist/internal/objectShape.d.ts +2 -0
- package/dist/internal/objectShape.js +7 -0
- package/dist/outputValidation.js +3 -2
- package/dist/providerDriver.js +0 -1
- package/dist/providerInstanceRegistry.js +2 -1
- package/dist/sessionCleanup.d.ts +9 -0
- package/dist/sessionCleanup.js +17 -0
- package/dist/sessionInteractions/index.d.ts +2 -0
- package/dist/sessionInteractions/index.js +1 -0
- package/dist/sessionInteractions/lifetime.d.ts +52 -0
- package/dist/sessionInteractions/lifetime.js +251 -0
- package/dist/sessionInteractions/request.d.ts +42 -0
- package/dist/sessionInteractions/request.js +308 -0
- package/dist/sessionInteractions/types.d.ts +54 -0
- package/dist/sessionInteractions/types.js +10 -0
- package/dist/sessionInteractions/validation.d.ts +21 -0
- package/dist/sessionInteractions/validation.js +119 -0
- package/dist/sessionValidation.d.ts +15 -2
- package/dist/sessionValidation.js +155 -318
- package/dist/sessions.d.ts +31 -4
- package/dist/testing/conformance.d.ts +3 -3
- package/dist/testing/conformance.js +24 -31
- package/dist/testing/fakeProvider.js +59 -49
- package/dist/turnExecution/execution.d.ts +26 -0
- package/dist/turnExecution/execution.js +214 -0
- package/dist/turnExecution/receipts.d.ts +6 -0
- package/dist/turnExecution/receipts.js +39 -0
- package/dist/turnExecution/requests.d.ts +19 -0
- package/dist/turnExecution/requests.js +56 -0
- package/package.json +2 -2
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import {
|
|
3
|
+
parseAgentError,
|
|
4
|
+
parseAgentSessionDecisionChoiceId,
|
|
5
|
+
parseAgentSessionDecisionRequest
|
|
6
|
+
} from "@agen-ai/agent-protocol";
|
|
7
|
+
import { AgentProviderContractError } from "../contractErrors.js";
|
|
8
|
+
import { hasExactOwnKeys } from "../internal/objectShape.js";
|
|
9
|
+
import {
|
|
10
|
+
DEFAULT_AGENT_SESSION_INTERACTION_LIMITS
|
|
11
|
+
} from "./types.js";
|
|
12
|
+
function record(input) {
|
|
13
|
+
if (input === null || typeof input !== "object" || Array.isArray(input)) throw new TypeError("Expected an interaction object.");
|
|
14
|
+
return input;
|
|
15
|
+
}
|
|
16
|
+
function interactionContractError(providerKey, message) {
|
|
17
|
+
return new AgentProviderContractError(providerKey, "invalid_session_interaction", message);
|
|
18
|
+
}
|
|
19
|
+
function validateSessionInteractionSupport(capabilities, adapter) {
|
|
20
|
+
const input = adapter.sessionInteractions;
|
|
21
|
+
if (input === void 0) return Object.freeze({ kind: "unsupported" });
|
|
22
|
+
try {
|
|
23
|
+
const value = record(input);
|
|
24
|
+
if (value.kind === "unsupported" && hasExactOwnKeys(value, ["kind"])) return Object.freeze({ kind: "unsupported" });
|
|
25
|
+
if (!hasExactOwnKeys(value, ["kind", "openingOperations", "requestKinds", "producerOwnership"]) || value.kind !== "supported" || value.producerOwnership !== "exclusive" || !Array.isArray(value.openingOperations) || value.openingOperations.length === 0 || !Array.isArray(value.requestKinds) || value.requestKinds.length !== 1 || value.requestKinds[0] !== "decision") throw new TypeError();
|
|
26
|
+
const operations = [];
|
|
27
|
+
for (const operation of value.openingOperations) {
|
|
28
|
+
if (operation !== "create" && operation !== "resume" && operation !== "branch") throw new TypeError();
|
|
29
|
+
if (operations.includes(operation)) throw new TypeError();
|
|
30
|
+
if (operation === "resume" && (!capabilities.sessions.resume || adapter.resumption.kind !== "supported")) throw new TypeError();
|
|
31
|
+
if (operation === "branch" && (capabilities.sessions.branch.kind !== "through_turn" || adapter.branching.kind !== "through_turn")) throw new TypeError();
|
|
32
|
+
operations.push(operation);
|
|
33
|
+
}
|
|
34
|
+
const order = ["create", "resume", "branch"];
|
|
35
|
+
if (operations.some((operation, index) => index > 0 && order.indexOf(operation) < order.indexOf(operations[index - 1]))) throw new TypeError();
|
|
36
|
+
const [first, ...rest] = operations;
|
|
37
|
+
if (first === void 0) throw new TypeError();
|
|
38
|
+
return Object.freeze({
|
|
39
|
+
kind: "supported",
|
|
40
|
+
producerOwnership: "exclusive",
|
|
41
|
+
openingOperations: Object.freeze([first, ...rest]),
|
|
42
|
+
requestKinds: Object.freeze(["decision"])
|
|
43
|
+
});
|
|
44
|
+
} catch {
|
|
45
|
+
throw interactionContractError(capabilities.providerKey, "Provider declared invalid session interaction support.");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const limitRanges = {
|
|
49
|
+
maxRetainedRequests: [1, 32],
|
|
50
|
+
maxRetainedBytes: [65536, 2097152],
|
|
51
|
+
requestTimeoutMs: [1e3, 18e5],
|
|
52
|
+
responseTimeoutMs: [1e3, 12e4],
|
|
53
|
+
cleanupTimeoutMs: [1e3, 12e4]
|
|
54
|
+
};
|
|
55
|
+
function validateSessionInteractionContext(input) {
|
|
56
|
+
const value = record(input);
|
|
57
|
+
const onRequest = value.onRequest;
|
|
58
|
+
if (!hasExactOwnKeys(value, Object.hasOwn(value, "limits") ? ["onRequest", "limits"] : ["onRequest"]) || typeof onRequest !== "function") throw new TypeError("Session interactions require a callable handler and known fields.");
|
|
59
|
+
const supplied = value.limits === void 0 ? {} : record(value.limits);
|
|
60
|
+
if (Reflect.ownKeys(supplied).some((key) => typeof key !== "string" || !Object.hasOwn(limitRanges, key))) {
|
|
61
|
+
throw new TypeError("Session interaction limits contain an unknown field.");
|
|
62
|
+
}
|
|
63
|
+
const limits = { ...DEFAULT_AGENT_SESSION_INTERACTION_LIMITS };
|
|
64
|
+
for (const key of Object.keys(limitRanges)) {
|
|
65
|
+
const number = supplied[key];
|
|
66
|
+
if (number === void 0) continue;
|
|
67
|
+
const [minimum, maximum] = limitRanges[key];
|
|
68
|
+
if (typeof number !== "number" || !Number.isSafeInteger(number) || number < minimum || number > maximum) {
|
|
69
|
+
throw new RangeError(`Session interaction ${key} must be an integer between ${minimum} and ${maximum}.`);
|
|
70
|
+
}
|
|
71
|
+
limits[key] = number;
|
|
72
|
+
}
|
|
73
|
+
return Object.freeze({ onRequest: onRequest.bind(input), limits: Object.freeze(limits) });
|
|
74
|
+
}
|
|
75
|
+
function captureSessionInteractionCandidate(input, observe) {
|
|
76
|
+
const value = record(input);
|
|
77
|
+
const terminal = value.terminal;
|
|
78
|
+
const observation = Promise.resolve(terminal);
|
|
79
|
+
void observation.catch(() => {
|
|
80
|
+
});
|
|
81
|
+
observe(observation);
|
|
82
|
+
const request = value.request;
|
|
83
|
+
const signal = value.signal;
|
|
84
|
+
const respond = value.respond;
|
|
85
|
+
if (!hasExactOwnKeys(value, ["request", "signal", "terminal", "respond"]) || !(signal instanceof AbortSignal) || typeof respond !== "function" || !terminal || typeof record(terminal).then !== "function") throw new TypeError("Provider offered an invalid session interaction handle.");
|
|
86
|
+
return Object.freeze({
|
|
87
|
+
request,
|
|
88
|
+
signal,
|
|
89
|
+
terminal: observation,
|
|
90
|
+
respond: respond.bind(input)
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
function validateSessionInteractionCandidate(input, sessionId, requestTimeoutMs) {
|
|
94
|
+
const parsed = parseAgentSessionDecisionRequest(input.request);
|
|
95
|
+
if (parsed.sessionId !== sessionId || !path.isAbsolute(parsed.target.path) || path.normalize(parsed.target.path) !== parsed.target.path) {
|
|
96
|
+
throw new TypeError("Session interaction does not match its session or canonical workspace target.");
|
|
97
|
+
}
|
|
98
|
+
const expiry = Math.min(Date.parse(parsed.expiresAt), Date.now() + requestTimeoutMs);
|
|
99
|
+
if (expiry <= Date.now()) throw new TypeError("Provider offered an expired session interaction.");
|
|
100
|
+
const request = parseAgentSessionDecisionRequest({ ...parsed, expiresAt: new Date(expiry).toISOString() });
|
|
101
|
+
return Object.freeze({ ...input, request });
|
|
102
|
+
}
|
|
103
|
+
function validateSessionInteractionTerminal(input) {
|
|
104
|
+
const value = record(input);
|
|
105
|
+
if (value.kind === "answered" && hasExactOwnKeys(value, ["kind", "choiceId"])) {
|
|
106
|
+
return Object.freeze({ kind: "answered", choiceId: parseAgentSessionDecisionChoiceId(value.choiceId) });
|
|
107
|
+
}
|
|
108
|
+
if ((value.kind === "failed" || value.kind === "rejected" || value.kind === "delivery_uncertain") && hasExactOwnKeys(value, ["kind", "error"])) return Object.freeze({ kind: value.kind, error: parseAgentError(value.error) });
|
|
109
|
+
if ((value.kind === "withdrawn" || value.kind === "expired" || value.kind === "session_closed") && hasExactOwnKeys(value, ["kind"])) return Object.freeze({ kind: value.kind });
|
|
110
|
+
throw new TypeError("Provider returned an invalid session interaction terminal.");
|
|
111
|
+
}
|
|
112
|
+
export {
|
|
113
|
+
captureSessionInteractionCandidate,
|
|
114
|
+
interactionContractError,
|
|
115
|
+
validateSessionInteractionCandidate,
|
|
116
|
+
validateSessionInteractionContext,
|
|
117
|
+
validateSessionInteractionSupport,
|
|
118
|
+
validateSessionInteractionTerminal
|
|
119
|
+
};
|
|
@@ -1,19 +1,32 @@
|
|
|
1
|
-
import { type AgentCapabilities, type AgentSessionBinding, type AgentSessionId } from "@agen-ai/agent-protocol";
|
|
1
|
+
import { type AgentCapabilities, type AgentProviderKey, type AgentSessionBinding, type AgentSessionId } from "@agen-ai/agent-protocol";
|
|
2
|
+
import { type AgentHostBindingLease } from "./hostBindings/lifetime.js";
|
|
2
3
|
import { type MaybePromise } from "./foundation.js";
|
|
3
4
|
import type { AgentProviderSession, AgentSessionBindingCreatedObserver } from "./sessions.js";
|
|
5
|
+
import type { SessionInteractionOwner } from "./sessionInteractions/lifetime.js";
|
|
4
6
|
export declare function validateAgentProviderSession(input: {
|
|
5
7
|
readonly capabilities: AgentCapabilities;
|
|
6
8
|
readonly sessionId: AgentSessionId;
|
|
7
9
|
readonly candidate: AgentProviderSession;
|
|
8
10
|
readonly expectedBinding?: AgentSessionBinding;
|
|
9
11
|
readonly sourceBinding?: AgentSessionBinding;
|
|
12
|
+
readonly hostBindingLease?: AgentHostBindingLease;
|
|
13
|
+
readonly sessionInteractionOwner?: SessionInteractionOwner;
|
|
10
14
|
}): AgentProviderSession;
|
|
11
|
-
export declare function closeRejectedAgentProviderSession(session: AgentProviderSession | null, error: unknown
|
|
15
|
+
export declare function closeRejectedAgentProviderSession(session: AgentProviderSession | null, error: unknown, hostBinding?: Readonly<{
|
|
16
|
+
providerKey: AgentProviderKey;
|
|
17
|
+
lease: AgentHostBindingLease;
|
|
18
|
+
}>, opening?: Readonly<{
|
|
19
|
+
providerKey: AgentProviderKey;
|
|
20
|
+
input: object;
|
|
21
|
+
}>, interactions?: SessionInteractionOwner): Promise<never>;
|
|
12
22
|
export declare function openIdentityCreatingAgentProviderSession(input: {
|
|
13
23
|
readonly capabilities: AgentCapabilities;
|
|
14
24
|
readonly sessionId: AgentSessionId;
|
|
15
25
|
readonly observer: AgentSessionBindingCreatedObserver;
|
|
16
26
|
readonly sourceBinding?: AgentSessionBinding;
|
|
27
|
+
readonly hostBindingLease?: AgentHostBindingLease;
|
|
28
|
+
readonly openingInput?: object;
|
|
29
|
+
readonly sessionInteractionOwner?: SessionInteractionOwner;
|
|
17
30
|
readonly open: (observer: AgentSessionBindingCreatedObserver) => MaybePromise<AgentProviderSession>;
|
|
18
31
|
}): Promise<AgentProviderSession>;
|
|
19
32
|
//# sourceMappingURL=sessionValidation.d.ts.map
|