@agen-ai/agent-runtime 0.4.3 → 0.4.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.
Files changed (56) hide show
  1. package/README.md +297 -10
  2. package/dist/adapterValidation.js +38 -4
  3. package/dist/contractErrors.d.ts +2 -2
  4. package/dist/contractErrors.js +8 -1
  5. package/dist/executionInput/index.d.ts +3 -0
  6. package/dist/executionInput/index.js +4 -0
  7. package/dist/executionInput/lifetime.d.ts +47 -0
  8. package/dist/executionInput/lifetime.js +241 -0
  9. package/dist/executionInput/types.d.ts +61 -0
  10. package/dist/executionInput/types.js +0 -0
  11. package/dist/executionInput/validation.d.ts +25 -0
  12. package/dist/executionInput/validation.js +178 -0
  13. package/dist/generation/cleanup.d.ts +15 -0
  14. package/dist/generation/cleanup.js +108 -0
  15. package/dist/generation/deadline.d.ts +16 -0
  16. package/dist/generation/deadline.js +81 -0
  17. package/dist/generation/decoding.d.ts +4 -0
  18. package/dist/generation/decoding.js +59 -0
  19. package/dist/generation/errors.d.ts +29 -0
  20. package/dist/generation/errors.js +39 -0
  21. package/dist/generation/generateObject.d.ts +3 -0
  22. package/dist/generation/generateObject.js +148 -0
  23. package/dist/generation/index.d.ts +5 -0
  24. package/dist/generation/index.js +8 -0
  25. package/dist/generation/preflight.d.ts +25 -0
  26. package/dist/generation/preflight.js +48 -0
  27. package/dist/generation/requests.d.ts +17 -0
  28. package/dist/generation/requests.js +117 -0
  29. package/dist/generation/types.d.ts +22 -0
  30. package/dist/generation/types.js +0 -0
  31. package/dist/index.d.ts +3 -0
  32. package/dist/index.js +7 -1
  33. package/dist/nativeContinuations/admission.js +1 -0
  34. package/dist/outputValidation.d.ts +2 -0
  35. package/dist/outputValidation.js +29 -1
  36. package/dist/sessionInteractions/lifetime.d.ts +1 -0
  37. package/dist/sessionInteractions/lifetime.js +4 -0
  38. package/dist/sessionInteractions/request.d.ts +1 -0
  39. package/dist/sessionInteractions/request.js +3 -0
  40. package/dist/sessionValidation.d.ts +13 -3
  41. package/dist/sessionValidation.js +80 -6
  42. package/dist/sessions.d.ts +7 -1
  43. package/dist/structuredOutput/admission.d.ts +16 -0
  44. package/dist/structuredOutput/admission.js +89 -0
  45. package/dist/structuredOutput/candidate.d.ts +22 -0
  46. package/dist/structuredOutput/candidate.js +64 -0
  47. package/dist/structuredOutput/validation.d.ts +8 -0
  48. package/dist/structuredOutput/validation.js +26 -0
  49. package/dist/testing/conformance.d.ts +20 -1
  50. package/dist/testing/conformance.js +103 -3
  51. package/dist/testing/fakeProvider.js +5 -4
  52. package/dist/turnExecution/execution.d.ts +9 -1
  53. package/dist/turnExecution/execution.js +88 -7
  54. package/dist/turnExecution/terminalBuffer.d.ts +9 -0
  55. package/dist/turnExecution/terminalBuffer.js +38 -0
  56. package/package.json +6 -2
@@ -0,0 +1,81 @@
1
+ import { throwIfAgentOperationAborted } from "../foundation.js";
2
+ import { AgentGenerationError } from "./errors.js";
3
+ const AGENT_GENERATION_TIMEOUT_MS = 3e5;
4
+ const AGENT_GENERATION_MAX_TIMEOUT_MS = 36e5;
5
+ const AGENT_GENERATION_OBSERVER_TIMEOUT_MS = 3e4;
6
+ const AGENT_GENERATION_REQUEST_TIMEOUT_MS = 3e5;
7
+ const AGENT_GENERATION_RESPONSE_TIMEOUT_MS = 3e4;
8
+ const AGENT_GENERATION_CLEANUP_TIMEOUT_MS = 3e4;
9
+ const AGENT_GENERATION_REQUEST_LIMIT = 8;
10
+ function waitForGenerationWork(work, signal) {
11
+ if (signal.aborted) {
12
+ try {
13
+ throwIfAgentOperationAborted(signal);
14
+ } catch (error) {
15
+ return Promise.reject(error);
16
+ }
17
+ }
18
+ return new Promise((resolve, reject) => {
19
+ const abort = () => {
20
+ try {
21
+ throwIfAgentOperationAborted(signal);
22
+ } catch (error) {
23
+ reject(error);
24
+ }
25
+ };
26
+ signal.addEventListener("abort", abort, { once: true });
27
+ void work.then(resolve, reject).finally(() => signal.removeEventListener("abort", abort));
28
+ });
29
+ }
30
+ function createGenerationDeadline(deadlineAt, callerSignal) {
31
+ const controller = new AbortController();
32
+ const abort = () => {
33
+ try {
34
+ throwIfAgentOperationAborted(callerSignal);
35
+ } catch (error) {
36
+ controller.abort(error);
37
+ }
38
+ };
39
+ callerSignal?.addEventListener("abort", abort, { once: true });
40
+ if (callerSignal?.aborted) abort();
41
+ const expire = () => controller.abort(new AgentGenerationError("timeout", "Object generation exceeded its deadline."));
42
+ const timeout = setTimeout(expire, Math.max(0, deadlineAt - Date.now()));
43
+ return {
44
+ signal: controller.signal,
45
+ check() {
46
+ if (Date.now() >= deadlineAt && !controller.signal.aborted) expire();
47
+ throwIfAgentOperationAborted(controller.signal);
48
+ },
49
+ stop(error) {
50
+ controller.abort(error);
51
+ },
52
+ dispose() {
53
+ clearTimeout(timeout);
54
+ callerSignal?.removeEventListener("abort", abort);
55
+ }
56
+ };
57
+ }
58
+ async function waitForBoundedGenerationWork(work, signal, timeoutMs, error) {
59
+ const controller = new AbortController();
60
+ const expiresAt = Date.now() + timeoutMs;
61
+ const timeout = setTimeout(() => controller.abort(error), timeoutMs);
62
+ try {
63
+ const result = await waitForGenerationWork(work, AbortSignal.any([signal, controller.signal]));
64
+ if (Date.now() >= expiresAt) throw error;
65
+ return result;
66
+ } finally {
67
+ clearTimeout(timeout);
68
+ }
69
+ }
70
+ export {
71
+ AGENT_GENERATION_CLEANUP_TIMEOUT_MS,
72
+ AGENT_GENERATION_MAX_TIMEOUT_MS,
73
+ AGENT_GENERATION_OBSERVER_TIMEOUT_MS,
74
+ AGENT_GENERATION_REQUEST_LIMIT,
75
+ AGENT_GENERATION_REQUEST_TIMEOUT_MS,
76
+ AGENT_GENERATION_RESPONSE_TIMEOUT_MS,
77
+ AGENT_GENERATION_TIMEOUT_MS,
78
+ createGenerationDeadline,
79
+ waitForBoundedGenerationWork,
80
+ waitForGenerationWork
81
+ };
@@ -0,0 +1,4 @@
1
+ import { type AgentJsonObject, type AgentOutputDefinition, type AgentOutputSchema } from "@agen-ai/agent-protocol";
2
+ export declare function captureGenerationCandidate(schema: AgentOutputSchema, value: unknown, maxOutputBytes: number): AgentJsonObject;
3
+ export declare function decodeGenerationCandidate<T>(definition: AgentOutputDefinition<T>, candidate: AgentJsonObject, maxOutputBytes: number): T;
4
+ //# sourceMappingURL=decoding.d.ts.map
@@ -0,0 +1,59 @@
1
+ import { normalizeAgentStructuredOutputIssues, validateAgentOutputValue } from "@agen-ai/agent-protocol";
2
+ import { AgentGenerationError } from "./errors.js";
3
+ function freezeJson(value) {
4
+ if (value === null || typeof value !== "object") return;
5
+ for (const child of Object.values(value)) freezeJson(child);
6
+ Object.freeze(value);
7
+ }
8
+ function captureGenerationCandidate(schema, value, maxOutputBytes) {
9
+ const parsed = validateAgentOutputValue(schema, value, { maxOutputBytes });
10
+ if (!parsed.success) throw new AgentGenerationError("generation_failed", "Structured generation did not produce a valid object.");
11
+ freezeJson(parsed.data);
12
+ return parsed.data;
13
+ }
14
+ function isJsonArray(value) {
15
+ return Array.isArray(value);
16
+ }
17
+ function equalJson(left, right) {
18
+ if (left === right) return true;
19
+ if (left === null || right === null || typeof left !== "object" || typeof right !== "object") return false;
20
+ if (isJsonArray(left) || isJsonArray(right)) {
21
+ return isJsonArray(left) && isJsonArray(right) && left.length === right.length && left.every((child, index) => equalJson(child, right[index]));
22
+ }
23
+ const keys = Object.keys(left);
24
+ return keys.length === Object.keys(right).length && keys.every((key) => Object.hasOwn(right, key) && equalJson(left[key], right[key]));
25
+ }
26
+ function decodeGenerationCandidate(definition, candidate, maxOutputBytes) {
27
+ let decoded;
28
+ try {
29
+ decoded = definition.decode(candidate);
30
+ } catch (cause) {
31
+ throw new AgentGenerationError("decoding_failed", "Object decoder failed.", { cause });
32
+ }
33
+ try {
34
+ if (!decoded.success) throw new AgentGenerationError("decoding_failed", "Object decoder rejected the generated value.", {
35
+ issues: normalizeAgentStructuredOutputIssues(decoded.issues)
36
+ });
37
+ const value = decoded.data;
38
+ const admitted = validateAgentOutputValue(definition.schema, value, { maxOutputBytes });
39
+ if (!admitted.success) {
40
+ throw new AgentGenerationError("decoding_failed", "Object decoder returned invalid JSON data.", {
41
+ issues: normalizeAgentStructuredOutputIssues(admitted.issues)
42
+ });
43
+ }
44
+ if (!equalJson(candidate, admitted.data)) {
45
+ throw new AgentGenerationError("decoding_failed", "Object decoder must preserve the generated JSON value.", {
46
+ issues: normalizeAgentStructuredOutputIssues([{ code: "decoded_value_changed", path: [], message: "Object decoder changed the generated JSON value." }])
47
+ });
48
+ }
49
+ freezeJson(value);
50
+ return value;
51
+ } catch (cause) {
52
+ if (cause instanceof AgentGenerationError) throw cause;
53
+ throw new AgentGenerationError("decoding_failed", "Object decoder failed.", { cause });
54
+ }
55
+ }
56
+ export {
57
+ captureGenerationCandidate,
58
+ decodeGenerationCandidate
59
+ };
@@ -0,0 +1,29 @@
1
+ import type { AgentProviderKey, AgentStructuredOutputUnavailableReason, ValidationIssue } from "@agen-ai/agent-protocol";
2
+ import { AgentProviderSessionCleanupError } from "../contractErrors.js";
3
+ import type { AgentRequestResolutionResult } from "../sessions.js";
4
+ import type { AgentGeneratedObject } from "./types.js";
5
+ export declare const AGENT_GENERATION_ERROR_CODES: readonly ["unsupported", "interaction_required", "generation_failed", "decoding_failed", "observer_failed", "request_failed", "timeout"];
6
+ export type AgentGenerationErrorCode = (typeof AGENT_GENERATION_ERROR_CODES)[number];
7
+ export declare class AgentGenerationError extends Error {
8
+ readonly code: AgentGenerationErrorCode;
9
+ readonly reason?: AgentStructuredOutputUnavailableReason;
10
+ readonly issues?: readonly ValidationIssue[];
11
+ readonly receipt?: AgentRequestResolutionResult;
12
+ constructor(code: AgentGenerationErrorCode, message: string, options?: ErrorOptions & Readonly<{
13
+ reason?: AgentStructuredOutputUnavailableReason;
14
+ issues?: readonly ValidationIssue[];
15
+ receipt?: AgentRequestResolutionResult;
16
+ }>);
17
+ }
18
+ export declare class AgentGenerationCleanupError<T = unknown> extends AgentProviderSessionCleanupError {
19
+ readonly primaryError?: unknown;
20
+ readonly result?: AgentGeneratedObject<T>;
21
+ constructor(input: Readonly<{
22
+ providerKey: AgentProviderKey;
23
+ errors: readonly unknown[];
24
+ retryCleanup: () => Promise<void>;
25
+ primaryError?: unknown;
26
+ result?: AgentGeneratedObject<T>;
27
+ }>);
28
+ }
29
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1,39 @@
1
+ import { AgentProviderSessionCleanupError } from "../contractErrors.js";
2
+ const AGENT_GENERATION_ERROR_CODES = [
3
+ "unsupported",
4
+ "interaction_required",
5
+ "generation_failed",
6
+ "decoding_failed",
7
+ "observer_failed",
8
+ "request_failed",
9
+ "timeout"
10
+ ];
11
+ class AgentGenerationError extends Error {
12
+ constructor(code, message, options) {
13
+ super(message, options);
14
+ this.code = code;
15
+ this.name = "AgentGenerationError";
16
+ this.reason = options?.reason;
17
+ this.issues = options?.issues;
18
+ this.receipt = options?.receipt;
19
+ }
20
+ reason;
21
+ issues;
22
+ receipt;
23
+ }
24
+ class AgentGenerationCleanupError extends AgentProviderSessionCleanupError {
25
+ primaryError;
26
+ result;
27
+ constructor(input) {
28
+ super(input);
29
+ this.name = "AgentGenerationCleanupError";
30
+ this.message = "Object generation cleanup remains incomplete.";
31
+ this.primaryError = input.primaryError;
32
+ this.result = input.result;
33
+ }
34
+ }
35
+ export {
36
+ AGENT_GENERATION_ERROR_CODES,
37
+ AgentGenerationCleanupError,
38
+ AgentGenerationError
39
+ };
@@ -0,0 +1,3 @@
1
+ import type { AgentGeneratedObject, AgentGenerateObjectInput } from "./types.js";
2
+ export declare function generateObject<T>(input: AgentGenerateObjectInput<T>): Promise<AgentGeneratedObject<T>>;
3
+ //# sourceMappingURL=generateObject.d.ts.map
@@ -0,0 +1,148 @@
1
+ import {
2
+ AgentProtocolValidationError
3
+ } from "@agen-ai/agent-protocol";
4
+ import { AgentProviderContractError, AgentProviderSessionCleanupError } from "../contractErrors.js";
5
+ import { isAgentOperationAbortError } from "../foundation.js";
6
+ import { createGenerationCleanupOwner } from "./cleanup.js";
7
+ import { captureGenerationCandidate, decodeGenerationCandidate } from "./decoding.js";
8
+ import { AGENT_GENERATION_OBSERVER_TIMEOUT_MS, createGenerationDeadline, waitForBoundedGenerationWork, waitForGenerationWork } from "./deadline.js";
9
+ import { AgentGenerationCleanupError, AgentGenerationError } from "./errors.js";
10
+ import { preflightGeneration } from "./preflight.js";
11
+ import { createGenerationRequests } from "./requests.js";
12
+ function unavailableFailure(output) {
13
+ return new AgentGenerationError("generation_failed", "Object generation did not complete with a structured object.", output.kind === "unavailable" ? {
14
+ reason: output.reason,
15
+ ...output.reason !== "schema_mismatch" || output.issues === void 0 ? {} : {
16
+ issues: Object.freeze(output.issues.map((issue) => Object.freeze({ ...issue, path: Object.freeze([...issue.path]) })))
17
+ }
18
+ } : void 0);
19
+ }
20
+ function executionFailure(cause) {
21
+ if (cause instanceof AgentGenerationError || cause instanceof AgentProtocolValidationError || cause instanceof AgentProviderContractError || isAgentOperationAbortError(cause)) return cause;
22
+ return new AgentGenerationError("generation_failed", "Object generation execution failed.", { cause });
23
+ }
24
+ async function generateObject(input) {
25
+ const admitted = preflightGeneration(input);
26
+ const deadline = createGenerationDeadline(admitted.deadlineAt, input.signal);
27
+ let primary;
28
+ let failed = false;
29
+ let result;
30
+ let stopRequests = () => {
31
+ };
32
+ const owner = createGenerationCleanupOwner({ turnId: admitted.turn.turnId, stopCallbacks: () => stopRequests() });
33
+ let shutdown;
34
+ const fail = (error) => {
35
+ if (failed) return;
36
+ failed = true;
37
+ primary = error;
38
+ shutdown = owner.cleanup(true);
39
+ void shutdown.catch(() => {
40
+ });
41
+ deadline.stop(error);
42
+ };
43
+ const aborted = () => fail(deadline.signal.reason);
44
+ deadline.signal.addEventListener("abort", aborted, { once: true });
45
+ let opening;
46
+ let opened = false;
47
+ try {
48
+ const output = Object.freeze({ kind: "json_schema", schema: admitted.schema });
49
+ let bindingSeen = false;
50
+ opening = Promise.resolve().then(() => input.instance.adapter.createSession({
51
+ ...admitted.session,
52
+ signal: deadline.signal,
53
+ ...admitted.capability.scope === "session" ? { output } : {},
54
+ onBindingCreated() {
55
+ bindingSeen = true;
56
+ }
57
+ }));
58
+ owner.setOpening(opening);
59
+ const session = await waitForGenerationWork(opening, deadline.signal);
60
+ opened = true;
61
+ deadline.check();
62
+ if (!bindingSeen) throw new AgentProviderContractError(input.instance.capabilities.providerKey, "binding_callback_missing", "Object generation opening did not report its session binding.");
63
+ const execution = session.startTurn({
64
+ ...admitted.turn,
65
+ signal: deadline.signal,
66
+ ...admitted.capability.scope === "turn" ? { output } : {},
67
+ onProviderExecutionStarted: owner.markEntered
68
+ });
69
+ const requests = createGenerationRequests({
70
+ handler: input.onRequest,
71
+ execution,
72
+ signal: deadline.signal,
73
+ deadlineAt: admitted.deadlineAt,
74
+ owner,
75
+ fail,
76
+ checkDeadline: deadline.check
77
+ });
78
+ stopRequests = requests.stop;
79
+ let terminal;
80
+ const reader = (async () => {
81
+ for await (const outputEvent of execution.outputs) {
82
+ if (outputEvent.kind === "event") {
83
+ const event = outputEvent.event;
84
+ if (event.type === "turn.completed") {
85
+ owner.markTerminal();
86
+ terminal = event.payload.outcome === "completed" && event.payload.structuredOutput.kind === "json" ? { outcome: "completed", candidate: captureGenerationCandidate(admitted.schema, event.payload.structuredOutput.value, admitted.capability.maxOutputBytes) } : { outcome: "failed", error: unavailableFailure(event.payload.structuredOutput) };
87
+ }
88
+ requests.observe(event);
89
+ }
90
+ if (!failed && input.onOutput) {
91
+ const observer = input.onOutput;
92
+ const callback = owner.retain(Promise.resolve().then(() => {
93
+ if (!failed) return observer(outputEvent);
94
+ }));
95
+ try {
96
+ await waitForBoundedGenerationWork(
97
+ callback,
98
+ deadline.signal,
99
+ AGENT_GENERATION_OBSERVER_TIMEOUT_MS,
100
+ new AgentGenerationError("observer_failed", "Object output observer exceeded its deadline.")
101
+ );
102
+ deadline.check();
103
+ } catch (cause) {
104
+ try {
105
+ deadline.check();
106
+ } catch (error) {
107
+ fail(error);
108
+ }
109
+ if (!failed) fail(cause instanceof AgentGenerationError ? cause : new AgentGenerationError("observer_failed", "Object output observer failed.", { cause }));
110
+ }
111
+ }
112
+ }
113
+ })();
114
+ owner.retain(reader);
115
+ await waitForGenerationWork(reader, deadline.signal);
116
+ if (failed) throw primary;
117
+ deadline.check();
118
+ if (!terminal || terminal.outcome !== "completed") {
119
+ throw terminal?.outcome === "failed" ? terminal.error : new AgentGenerationError("generation_failed", "Object generation stream ended without a terminal result.");
120
+ }
121
+ const value = decodeGenerationCandidate({ schema: admitted.schema, decode: admitted.decode }, terminal.candidate, admitted.capability.maxOutputBytes);
122
+ deadline.check();
123
+ result = Object.freeze({ value, sessionId: admitted.session.sessionId, turnId: admitted.turn.turnId });
124
+ } catch (cause) {
125
+ if (!opened && cause instanceof AgentProviderSessionCleanupError && !failed) throw cause;
126
+ fail(executionFailure(cause));
127
+ } finally {
128
+ deadline.signal.removeEventListener("abort", aborted);
129
+ deadline.dispose();
130
+ }
131
+ try {
132
+ await (shutdown ?? owner.cleanup(failed));
133
+ } catch (cleanupError) {
134
+ throw new AgentGenerationCleanupError({
135
+ providerKey: input.instance.capabilities.providerKey,
136
+ errors: failed ? [primary, cleanupError] : [cleanupError],
137
+ retryCleanup: () => owner.cleanup(failed),
138
+ ...failed ? { primaryError: primary } : {},
139
+ ...result === void 0 ? {} : { result }
140
+ });
141
+ }
142
+ if (failed) throw primary;
143
+ if (!result) throw new AgentGenerationError("generation_failed", "Object generation returned no validated result.");
144
+ return result;
145
+ }
146
+ export {
147
+ generateObject
148
+ };
@@ -0,0 +1,5 @@
1
+ export { generateObject } from "./generateObject.js";
2
+ export { AGENT_GENERATION_ERROR_CODES, AgentGenerationError, AgentGenerationCleanupError } from "./errors.js";
3
+ export type { AgentGenerationErrorCode } from "./errors.js";
4
+ export type { AgentGenerateObjectInput, AgentGeneratedObject } from "./types.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,8 @@
1
+ import { generateObject } from "./generateObject.js";
2
+ import { AGENT_GENERATION_ERROR_CODES, AgentGenerationError, AgentGenerationCleanupError } from "./errors.js";
3
+ export {
4
+ AGENT_GENERATION_ERROR_CODES,
5
+ AgentGenerationCleanupError,
6
+ AgentGenerationError,
7
+ generateObject
8
+ };
@@ -0,0 +1,25 @@
1
+ import type { AgentGenerateObjectInput } from "./types.js";
2
+ export declare function preflightGeneration<T>(input: AgentGenerateObjectInput<T>): {
3
+ schema: import("@agen-ai/agent-protocol").AgentOutputSchema;
4
+ decode: (value: import("@agen-ai/agent-protocol").AgentJsonObject) => import("@agen-ai/agent-protocol").AgentProtocolParseResult<T>;
5
+ capability: Readonly<{
6
+ kind: "supported";
7
+ mechanism: "native";
8
+ schemaProfile: typeof import("@agen-ai/agent-protocol").AGENT_OUTPUT_SCHEMA_PROFILE;
9
+ scope: "turn" | "session";
10
+ maxSchemaBytes: number;
11
+ maxOutputBytes: number;
12
+ resume: false;
13
+ branch: false;
14
+ }>;
15
+ session: {
16
+ configuration: import("@agen-ai/agent-protocol").AgentSessionConfiguration;
17
+ interactions?: import("../index.js").AgentSessionInteractionContext;
18
+ sessionId: import("@agen-ai/agent-protocol").AgentSessionId;
19
+ workingDirectory: string;
20
+ hostBinding?: import("../index.js").AgentSessionHostBinding;
21
+ };
22
+ turn: import("@agen-ai/agent-protocol").AgentTurnRunInput;
23
+ deadlineAt: number;
24
+ };
25
+ //# sourceMappingURL=preflight.d.ts.map
@@ -0,0 +1,48 @@
1
+ import {
2
+ agentProtocolSerializedJsonBytes,
3
+ parseAgentOutputSchema,
4
+ parseAgentSessionOpenInput,
5
+ parseAgentTurnRunInput
6
+ } from "@agen-ai/agent-protocol";
7
+ import { assertAgentSessionConfigurationSupported } from "../configurationValidation.js";
8
+ import { throwAgentProviderContractError } from "../contractErrors.js";
9
+ import { throwIfAgentOperationAborted } from "../foundation.js";
10
+ import { assertAgentTurnInputCapability } from "../sessionValidation.js";
11
+ import { AGENT_GENERATION_MAX_TIMEOUT_MS, AGENT_GENERATION_TIMEOUT_MS } from "./deadline.js";
12
+ import { AgentGenerationError } from "./errors.js";
13
+ function preflightGeneration(input) {
14
+ throwIfAgentOperationAborted(input.signal);
15
+ const timeoutMs = input.timeoutMs ?? AGENT_GENERATION_TIMEOUT_MS;
16
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0 || timeoutMs > AGENT_GENERATION_MAX_TIMEOUT_MS) {
17
+ throw new RangeError("Object generation timeout must be a positive integer of at most one hour.");
18
+ }
19
+ for (const key of ["output", "signal", "onBindingCreated", "nativeContinuations"]) {
20
+ if (Reflect.has(input.session, key)) throw new TypeError(`Object generation owns session ${key}.`);
21
+ }
22
+ for (const key of ["output", "signal", "onProviderExecutionStarted"]) {
23
+ if (Reflect.has(input.turn, key)) throw new TypeError(`Object generation owns turn ${key}.`);
24
+ }
25
+ if (typeof input.output?.decode !== "function") throw new TypeError("Object generation requires an output decoder.");
26
+ if (input.onOutput !== void 0 && typeof input.onOutput !== "function") throw new TypeError("Object output observer must be a function.");
27
+ if (input.onRequest !== void 0 && typeof input.onRequest !== "function") throw new TypeError("Object request handler must be a function.");
28
+ const schema = parseAgentOutputSchema(input.output.schema);
29
+ const capability = input.instance.capabilities.turns.structuredOutput;
30
+ if (capability.kind !== "supported") throw new AgentGenerationError("unsupported", "Provider does not support structured object generation.");
31
+ const boundedSchema = parseAgentOutputSchema(schema, { maxOutputBytes: capability.maxOutputBytes });
32
+ if (agentProtocolSerializedJsonBytes(boundedSchema) > capability.maxSchemaBytes) {
33
+ throwAgentProviderContractError(input.instance.capabilities.providerKey, "invalid_structured_output", "Object schema exceeds the provider's advertised byte limit.");
34
+ }
35
+ const session = parseAgentSessionOpenInput({ operation: "create", sessionId: input.session.sessionId, configuration: input.session.configuration });
36
+ assertAgentSessionConfigurationSupported(input.instance.capabilities, session.configuration);
37
+ const turn = parseAgentTurnRunInput(input.turn);
38
+ assertAgentTurnInputCapability({ capability: input.instance.capabilities.input, parts: turn.parts, providerKey: input.instance.capabilities.providerKey });
39
+ if (!input.instance.capabilities.turns.interactionModes.includes(turn.interactionMode)) {
40
+ throwAgentProviderContractError(input.instance.capabilities.providerKey, "input_capability_mismatch", "Provider does not support the requested interaction mode.");
41
+ }
42
+ const deadlineAt = Math.min(Date.now() + timeoutMs, turn.deadlineAt === void 0 ? Infinity : Date.parse(turn.deadlineAt));
43
+ if (deadlineAt <= Date.now()) throw new AgentGenerationError("timeout", "Object generation deadline has expired.");
44
+ return { schema: boundedSchema, decode: input.output.decode, capability, session: { ...input.session, configuration: session.configuration }, turn, deadlineAt };
45
+ }
46
+ export {
47
+ preflightGeneration
48
+ };
@@ -0,0 +1,17 @@
1
+ import type { AgentEvent } from "@agen-ai/agent-protocol";
2
+ import type { AgentProviderTurnExecution } from "../sessions.js";
3
+ import type { GenerationCleanupOwner } from "./cleanup.js";
4
+ import type { AgentGenerateObjectInput } from "./types.js";
5
+ export declare function createGenerationRequests(input: Readonly<{
6
+ handler: AgentGenerateObjectInput<unknown>["onRequest"];
7
+ execution: AgentProviderTurnExecution;
8
+ signal: AbortSignal;
9
+ deadlineAt: number;
10
+ owner: GenerationCleanupOwner;
11
+ fail: (error: unknown) => void;
12
+ checkDeadline: () => void;
13
+ }>): {
14
+ stop(): void;
15
+ observe(event: AgentEvent): void;
16
+ };
17
+ //# sourceMappingURL=requests.d.ts.map
@@ -0,0 +1,117 @@
1
+ import { parseAgentRequest } from "@agen-ai/agent-protocol";
2
+ import { throwIfAgentOperationAborted } from "../foundation.js";
3
+ import {
4
+ AGENT_GENERATION_REQUEST_LIMIT,
5
+ AGENT_GENERATION_REQUEST_TIMEOUT_MS,
6
+ AGENT_GENERATION_RESPONSE_TIMEOUT_MS,
7
+ waitForBoundedGenerationWork
8
+ } from "./deadline.js";
9
+ import { AgentGenerationError } from "./errors.js";
10
+ function createGenerationRequests(input) {
11
+ const records = /* @__PURE__ */ new Map();
12
+ let stopped = false;
13
+ const retire = (record) => {
14
+ record.live = false;
15
+ record.controller.abort(new DOMException("The generation request is no longer available.", "AbortError"));
16
+ };
17
+ return {
18
+ stop() {
19
+ stopped = true;
20
+ for (const record of records.values()) retire(record);
21
+ },
22
+ observe(event) {
23
+ if (event.type === "request.unavailable") {
24
+ const record2 = records.get(event.payload.requestId);
25
+ if (record2) retire(record2);
26
+ return;
27
+ }
28
+ if (event.type === "turn.completed") {
29
+ for (const record2 of records.values()) retire(record2);
30
+ return;
31
+ }
32
+ if (event.type !== "request.opened" || stopped) return;
33
+ if (!input.handler) {
34
+ input.fail(new AgentGenerationError("interaction_required", "Object generation requires a request handler."));
35
+ return;
36
+ }
37
+ if (records.size >= AGENT_GENERATION_REQUEST_LIMIT) {
38
+ input.fail(new AgentGenerationError("request_failed", "Object generation exceeded its active request handler limit."));
39
+ return;
40
+ }
41
+ const request = parseAgentRequest(event.payload.request);
42
+ const record = { controller: new AbortController(), live: true, pending: 0, finished: false };
43
+ records.set(request.requestId, record);
44
+ const handler = input.handler;
45
+ const signal = AbortSignal.any([input.signal, record.controller.signal]);
46
+ let expiry;
47
+ if (request.expiresAt !== void 0) {
48
+ const expiresAt = Date.parse(request.expiresAt);
49
+ const remaining = expiresAt - Date.now();
50
+ if (remaining <= 0) retire(record);
51
+ else if (expiresAt < input.deadlineAt) expiry = setTimeout(() => retire(record), remaining);
52
+ }
53
+ const clearRecord = () => {
54
+ if (record.finished && record.pending === 0 && records.get(request.requestId) === record) records.delete(request.requestId);
55
+ };
56
+ const retain = (work) => {
57
+ record.pending += 1;
58
+ void work.then(() => {
59
+ record.pending -= 1;
60
+ clearRecord();
61
+ }, () => {
62
+ record.pending -= 1;
63
+ clearRecord();
64
+ });
65
+ return input.owner.retain(work);
66
+ };
67
+ let deliveryEntered = false;
68
+ const task = (async () => {
69
+ try {
70
+ const callback = retain(Promise.resolve().then(() => {
71
+ throwIfAgentOperationAborted(signal);
72
+ return handler(request, { signal });
73
+ }));
74
+ const resolution = await waitForBoundedGenerationWork(
75
+ callback,
76
+ signal,
77
+ AGENT_GENERATION_REQUEST_TIMEOUT_MS,
78
+ new AgentGenerationError("request_failed", "Object generation request handler exceeded its deadline.")
79
+ );
80
+ input.checkDeadline();
81
+ if (!record.live || stopped || signal.aborted) return;
82
+ const delivery = retain(Promise.resolve().then(() => {
83
+ input.checkDeadline();
84
+ if (!record.live || stopped) throw new DOMException("The generation request is no longer available.", "AbortError");
85
+ deliveryEntered = true;
86
+ return input.execution.resolveRequest({ resolution, signal: input.signal });
87
+ }));
88
+ const receipt = await waitForBoundedGenerationWork(
89
+ delivery,
90
+ input.signal,
91
+ AGENT_GENERATION_RESPONSE_TIMEOUT_MS,
92
+ new AgentGenerationError("request_failed", "Object generation request delivery exceeded its deadline.")
93
+ );
94
+ if (receipt.status !== "delivered") {
95
+ input.fail(new AgentGenerationError("request_failed", "Object generation request was not delivered.", { receipt, cause: receipt }));
96
+ }
97
+ } catch (cause) {
98
+ try {
99
+ input.checkDeadline();
100
+ } catch {
101
+ }
102
+ if ((record.live || deliveryEntered) && !stopped && !input.signal.aborted) {
103
+ input.fail(cause instanceof AgentGenerationError ? cause : new AgentGenerationError("request_failed", "Object generation request handler or delivery failed.", { cause }));
104
+ }
105
+ } finally {
106
+ if (expiry !== void 0) clearTimeout(expiry);
107
+ record.finished = true;
108
+ clearRecord();
109
+ }
110
+ })();
111
+ input.owner.retain(task);
112
+ }
113
+ };
114
+ }
115
+ export {
116
+ createGenerationRequests
117
+ };
@@ -0,0 +1,22 @@
1
+ import type { AgentOutputDefinition, AgentRequest, AgentRequestResolution, AgentSessionId, AgentTurnId } from "@agen-ai/agent-protocol";
2
+ import type { MaybePromise } from "../foundation.js";
3
+ import type { ValidatedMaterializedAgentProviderInstance } from "../providerDriver.js";
4
+ import type { AgentCreateSessionInput, AgentProviderOutputObserver, AgentProviderStartTurnInput } from "../sessions.js";
5
+ export interface AgentGenerateObjectInput<T> {
6
+ readonly instance: ValidatedMaterializedAgentProviderInstance;
7
+ readonly session: Omit<AgentCreateSessionInput, "output" | "signal" | "onBindingCreated" | "nativeContinuations">;
8
+ readonly turn: Omit<AgentProviderStartTurnInput, "output" | "signal" | "onProviderExecutionStarted">;
9
+ readonly output: AgentOutputDefinition<T>;
10
+ readonly signal?: AbortSignal;
11
+ readonly timeoutMs?: number;
12
+ readonly onOutput?: AgentProviderOutputObserver;
13
+ readonly onRequest?: (request: AgentRequest, context: Readonly<{
14
+ signal: AbortSignal;
15
+ }>) => MaybePromise<AgentRequestResolution>;
16
+ }
17
+ export interface AgentGeneratedObject<T> {
18
+ readonly value: T;
19
+ readonly sessionId: AgentSessionId;
20
+ readonly turnId: AgentTurnId;
21
+ }
22
+ //# sourceMappingURL=types.d.ts.map
File without changes
package/dist/index.d.ts CHANGED
@@ -15,6 +15,9 @@ export * from "./readiness.js";
15
15
  export * from "./sessions.js";
16
16
  export * from "./sessionInteractions/index.js";
17
17
  export * from "./nativeContinuations/index.js";
18
+ export { parseAgentExecutionInputMessageId, type AgentExecutionInput, type AgentExecutionInputMessage, type AgentExecutionInputMessageId, type AgentExecutionInputOutcome, type AgentExecutionInputReceipt, type AgentExecutionInputSupport, } from "./executionInput/index.js";
19
+ export { createAgentStructuredOutputCandidate } from "./structuredOutput/candidate.js";
20
+ export type { AgentStructuredOutputCandidate, AgentStructuredOutputCandidateResult, CreateAgentStructuredOutputCandidateInput, } from "./structuredOutput/candidate.js";
18
21
  export { createAgentProviderSessionCleanupError, isAgentProviderSessionCleanupErrorFor } from "./sessionCleanup.js";
19
22
  export * from "./text.js";
20
23
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -15,9 +15,15 @@ export * from "./readiness.js";
15
15
  export * from "./sessions.js";
16
16
  export * from "./sessionInteractions/index.js";
17
17
  export * from "./nativeContinuations/index.js";
18
+ import {
19
+ parseAgentExecutionInputMessageId
20
+ } from "./executionInput/index.js";
21
+ import { createAgentStructuredOutputCandidate } from "./structuredOutput/candidate.js";
18
22
  import { createAgentProviderSessionCleanupError, isAgentProviderSessionCleanupErrorFor } from "./sessionCleanup.js";
19
23
  export * from "./text.js";
20
24
  export {
21
25
  createAgentProviderSessionCleanupError,
22
- isAgentProviderSessionCleanupErrorFor
26
+ createAgentStructuredOutputCandidate,
27
+ isAgentProviderSessionCleanupErrorFor,
28
+ parseAgentExecutionInputMessageId
23
29
  };
@@ -147,6 +147,7 @@ async function dispatchPreparedSessionResponse(input) {
147
147
  if (outcomeFailure) throw outcomeFailure;
148
148
  if (earlyOutcome) throw continuationError(owner, "invalid_native_continuation", "Prepared outcome forbids native response dispatch.");
149
149
  if (value.kind === "native_continuation") {
150
+ owner.validationOwner.requireNativeContinuationSupport();
150
151
  owner.requireContinuation(input.candidate.request.kind);
151
152
  reservation = owner.validationOwner.reserveExecution();
152
153
  const turnId = parseAgentTurnId(`native-${randomUUID()}`);