@tanstack/ai 0.61.0 → 0.63.0

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 (65) hide show
  1. package/README.md +1 -0
  2. package/dist/esm/activities/chat/agents/define-agent.d.ts +17 -5
  3. package/dist/esm/activities/chat/agents/define-agent.js.map +1 -1
  4. package/dist/esm/activities/chat/agents/spawn.d.ts +2 -0
  5. package/dist/esm/activities/chat/agents/spawn.js +8 -5
  6. package/dist/esm/activities/chat/agents/spawn.js.map +1 -1
  7. package/dist/esm/activities/chat/index.js +156 -57
  8. package/dist/esm/activities/chat/index.js.map +1 -1
  9. package/dist/esm/activities/chat/messages.js +30 -18
  10. package/dist/esm/activities/chat/messages.js.map +1 -1
  11. package/dist/esm/activities/chat/middleware/types.d.ts +1 -0
  12. package/dist/esm/activities/chat/middleware/types.js.map +1 -1
  13. package/dist/esm/activities/chat/stream/message-updaters.d.ts +2 -2
  14. package/dist/esm/activities/chat/stream/message-updaters.js +2 -1
  15. package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
  16. package/dist/esm/activities/chat/stream/processor.d.ts +11 -9
  17. package/dist/esm/activities/chat/stream/processor.js +38 -18
  18. package/dist/esm/activities/chat/stream/processor.js.map +1 -1
  19. package/dist/esm/activities/chat/tools/tool-calls.d.ts +16 -2
  20. package/dist/esm/activities/chat/tools/tool-calls.js +55 -16
  21. package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
  22. package/dist/esm/activities/chat/tools/tool-definition.d.ts +4 -0
  23. package/dist/esm/activities/chat/tools/tool-definition.js +4 -0
  24. package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -1
  25. package/dist/esm/activities/evaluate/adapter.d.ts +4 -0
  26. package/dist/esm/activities/evaluate/adapter.js.map +1 -1
  27. package/dist/esm/activities/evaluate/index.d.ts +4 -0
  28. package/dist/esm/activities/evaluate/index.js +3 -1
  29. package/dist/esm/activities/evaluate/index.js.map +1 -1
  30. package/dist/esm/client.d.ts +1 -1
  31. package/dist/esm/client.js.map +1 -1
  32. package/dist/esm/index.d.ts +1 -1
  33. package/dist/esm/index.js +2 -2
  34. package/dist/esm/interrupt-resume.js +29 -4
  35. package/dist/esm/interrupt-resume.js.map +1 -1
  36. package/dist/esm/middlewares/otel.d.ts +5 -2
  37. package/dist/esm/middlewares/otel.js +114 -0
  38. package/dist/esm/middlewares/otel.js.map +1 -1
  39. package/dist/esm/types.d.ts +42 -1
  40. package/dist/esm/utilities/ag-ui-wire.js +5 -3
  41. package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
  42. package/dist/esm/utilities/tool-result.d.ts +2 -1
  43. package/dist/esm/utilities/tool-result.js +4 -1
  44. package/dist/esm/utilities/tool-result.js.map +1 -1
  45. package/package.json +3 -3
  46. package/skills/ai-core/chat-experience/SKILL.md +120 -0
  47. package/skills/ai-core/tool-calling/SKILL.md +103 -0
  48. package/src/activities/chat/agents/define-agent.ts +20 -3
  49. package/src/activities/chat/agents/spawn.ts +20 -12
  50. package/src/activities/chat/index.ts +235 -62
  51. package/src/activities/chat/messages.ts +40 -5
  52. package/src/activities/chat/middleware/types.ts +1 -0
  53. package/src/activities/chat/stream/message-updaters.ts +3 -0
  54. package/src/activities/chat/stream/processor.ts +57 -27
  55. package/src/activities/chat/tools/tool-calls.ts +98 -9
  56. package/src/activities/chat/tools/tool-definition.ts +8 -0
  57. package/src/activities/evaluate/adapter.ts +4 -0
  58. package/src/activities/evaluate/index.ts +6 -0
  59. package/src/client.ts +1 -0
  60. package/src/index.ts +1 -0
  61. package/src/interrupt-resume.ts +55 -4
  62. package/src/middlewares/otel.ts +161 -3
  63. package/src/types.ts +38 -1
  64. package/src/utilities/ag-ui-wire.ts +12 -1
  65. package/src/utilities/tool-result.ts +7 -1
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","names":[],"sources":["../../../../src/activities/evaluate/adapter.ts"],"sourcesContent":["import type { InternalLogger } from '../../logger/internal-logger'\nimport type { TokenUsage } from '../../types'\n\n/**\n * Configuration for evaluate adapter instances.\n */\nexport interface EvaluateAdapterConfig {\n apiKey?: string\n baseUrl?: string\n timeout?: number\n headers?: Record<string, string>\n}\n\n/**\n * Shared JSON value for `state` and question `instructions`.\n * A JSON array is one value, not a batch.\n */\nexport type EvaluateJsonValue = string | object | Array<unknown>\n\n/** Content the model judges. A JSON array is one state, not a batch. */\nexport type EvaluateState = EvaluateJsonValue\n\n/** Question text. Matches TypeSafe: string, object, or array. */\nexport type EvaluateInstructions = EvaluateJsonValue\n\n/**\n * TypeSafe choice question on the adapter wire.\n *\n * Generic parameters:\n * - TOptions: option key to description (or `null` when the key is enough)\n */\nexport interface WireChoiceQuestion<\n TOptions extends Record<string, string | null> = Record<\n string,\n string | null\n >,\n> {\n type: 'choice'\n instructions: EvaluateInstructions\n criteria: TOptions\n}\n\n/**\n * TypeSafe score question on the adapter wire.\n *\n * Generic parameters:\n * - TLevels: ordered level labels, at least two\n */\nexport interface WireScoreQuestion<\n TLevels extends ReadonlyArray<string> = ReadonlyArray<string>,\n> {\n type: 'score'\n instructions: EvaluateInstructions\n criteria: TLevels\n}\n\n/**\n * TypeSafe yes/no question on the adapter wire.\n * Public helpers call this `boolean`. The wire type is `noul`.\n */\nexport interface WireNoulQuestion {\n type: 'noul'\n instructions: EvaluateInstructions\n criteria?: {\n true?: string\n false?: string\n }\n}\n\n/** Question payload adapters send to the provider. */\nexport type WireQuestion =\n | WireChoiceQuestion\n | WireScoreQuestion\n | WireNoulQuestion\n\n/** TypeSafe choice answer. Adapters do not invent a public `.value`. */\nexport interface WireChoiceAnswer {\n type: 'choice'\n choice: string\n probabilities: Record<string, number>\n confidence: number\n}\n\n/** TypeSafe score answer. `score` is the raw fraction. */\nexport interface WireScoreAnswer {\n type: 'score'\n score: number\n legend: Record<string, string>\n probabilities: Record<string, number>\n confidence: number\n}\n\n/** TypeSafe yes/no answer. `noul` is P(true). */\nexport interface WireNoulAnswer {\n type: 'noul'\n noul: number\n}\n\n/** Provider payload for one question. The activity maps this to a unified answer. */\nexport type WireAnswer = WireChoiceAnswer | WireScoreAnswer | WireNoulAnswer\n\n/**\n * Options passed to {@link EvaluateAdapter.evaluate}.\n */\nexport interface EvaluateOptions<\n TProviderOptions extends object = Record<string, unknown>,\n> {\n model: string\n /** Shared state every question judges. A JSON array is one state, not a batch. */\n state: EvaluateState\n /** TypeSafe wire questions, keyed by the caller's question ids. */\n questions: Record<string, WireQuestion>\n /** Provider-specific options forwarded by `decide()`. */\n modelOptions?: TProviderOptions\n /** Forwarded to the provider request for cancellation. */\n abortSignal?: AbortSignal\n /**\n * Internal logger threaded from `decide()`. Adapters must call\n * `logger.request()` before the provider call and `logger.errors()` in catch\n * blocks.\n */\n logger: InternalLogger\n}\n\n/**\n * Provider-level evaluate result. Adapters return the wire payload plus usage.\n * The activity maps answers to the unified public shape.\n */\nexport interface EvaluateAdapterResult {\n /** Resolved model id from the provider. */\n model: string\n answers: Record<string, WireAnswer>\n usage: TokenUsage\n}\n\n/**\n * Evaluate adapter interface with pre-resolved generics.\n *\n * An adapter is created by a provider function: `provider('model')` → `adapter`.\n * All type resolution happens at the provider call site, not in this interface.\n *\n * Generic parameters:\n * - TModel: The specific model name (e.g. `'jev-latest'`)\n * - TProviderOptions: Provider-specific options (already resolved)\n */\nexport interface EvaluateAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n> {\n /** Discriminator for adapter kind */\n readonly kind: 'evaluate'\n /** Adapter name identifier */\n readonly name: string\n /** The model this adapter is configured for */\n readonly model: TModel\n\n /**\n * @internal Type-only properties for inference. Not assigned at runtime.\n */\n '~types': {\n providerOptions: TProviderOptions\n }\n\n /**\n * Evaluate typed questions against `state`. Return the provider payload.\n * Do not invent unified `.value` fields. The activity maps wire answers.\n */\n evaluate: (\n options: EvaluateOptions<TProviderOptions>,\n ) => Promise<EvaluateAdapterResult>\n}\n\n/**\n * An EvaluateAdapter with any/unknown type parameters.\n * Useful as a constraint in generic functions and interfaces.\n */\nexport type AnyEvaluateAdapter = EvaluateAdapter<any, any>\n\n/**\n * Abstract base class for evaluate adapters.\n * Extend this class to implement an evaluate adapter for a specific provider.\n *\n * Generic parameters match EvaluateAdapter. The provider function resolves them.\n */\nexport abstract class BaseEvaluateAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n> implements EvaluateAdapter<TModel, TProviderOptions> {\n readonly kind = 'evaluate' as const\n abstract readonly name: string\n readonly model: TModel\n\n // Type-only property - never assigned at runtime\n declare '~types': {\n providerOptions: TProviderOptions\n }\n\n protected config: EvaluateAdapterConfig\n\n constructor(config: EvaluateAdapterConfig = {}, model: TModel) {\n this.config = config\n this.model = model\n }\n\n abstract evaluate(\n options: EvaluateOptions<TProviderOptions>,\n ): Promise<EvaluateAdapterResult>\n\n protected generateId(): string {\n return `${this.name}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n }\n}\n"],"mappings":";;;;;;;AAwLA,IAAsB,sBAAtB,MAGuD;CACrD,OAAgB;CAEhB;CAOA;CAEA,YAAY,SAAgC,CAAC,GAAG,OAAe;EAC7D,KAAK,SAAS;EACd,KAAK,QAAQ;CACf;CAMA,aAA+B;EAC7B,OAAO,GAAG,KAAK,KAAK,GAAG,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;CAC5E;AACF"}
1
+ {"version":3,"file":"adapter.js","names":[],"sources":["../../../../src/activities/evaluate/adapter.ts"],"sourcesContent":["import type { InternalLogger } from '../../logger/internal-logger'\nimport type { TokenUsage } from '../../types'\n\n/**\n * Configuration for evaluate adapter instances.\n */\nexport interface EvaluateAdapterConfig {\n apiKey?: string\n baseUrl?: string\n timeout?: number\n headers?: Record<string, string>\n}\n\n/**\n * Shared JSON value for `state` and question `instructions`.\n * A JSON array is one value, not a batch.\n */\nexport type EvaluateJsonValue = string | object | Array<unknown>\n\n/** Content the model judges. A JSON array is one state, not a batch. */\nexport type EvaluateState = EvaluateJsonValue\n\n/** Question text. Matches TypeSafe: string, object, or array. */\nexport type EvaluateInstructions = EvaluateJsonValue\n\n/**\n * TypeSafe choice question on the adapter wire.\n *\n * Generic parameters:\n * - TOptions: option key to description (or `null` when the key is enough)\n */\nexport interface WireChoiceQuestion<\n TOptions extends Record<string, string | null> = Record<\n string,\n string | null\n >,\n> {\n type: 'choice'\n instructions: EvaluateInstructions\n criteria: TOptions\n}\n\n/**\n * TypeSafe score question on the adapter wire.\n *\n * Generic parameters:\n * - TLevels: ordered level labels, at least two\n */\nexport interface WireScoreQuestion<\n TLevels extends ReadonlyArray<string> = ReadonlyArray<string>,\n> {\n type: 'score'\n instructions: EvaluateInstructions\n criteria: TLevels\n}\n\n/**\n * TypeSafe yes/no question on the adapter wire.\n * Public helpers call this `boolean`. The wire type is `noul`.\n */\nexport interface WireNoulQuestion {\n type: 'noul'\n instructions: EvaluateInstructions\n criteria?: {\n true?: string\n false?: string\n }\n}\n\n/** Question payload adapters send to the provider. */\nexport type WireQuestion =\n | WireChoiceQuestion\n | WireScoreQuestion\n | WireNoulQuestion\n\n/** TypeSafe choice answer. Adapters do not invent a public `.value`. */\nexport interface WireChoiceAnswer {\n type: 'choice'\n choice: string\n probabilities: Record<string, number>\n confidence: number\n}\n\n/** TypeSafe score answer. `score` is the raw fraction. */\nexport interface WireScoreAnswer {\n type: 'score'\n score: number\n legend: Record<string, string>\n probabilities: Record<string, number>\n confidence: number\n}\n\n/** TypeSafe yes/no answer. `noul` is P(true). */\nexport interface WireNoulAnswer {\n type: 'noul'\n noul: number\n}\n\n/** Provider payload for one question. The activity maps this to a unified answer. */\nexport type WireAnswer = WireChoiceAnswer | WireScoreAnswer | WireNoulAnswer\n\n/**\n * Options passed to {@link EvaluateAdapter.evaluate}.\n */\nexport interface EvaluateOptions<\n TProviderOptions extends object = Record<string, unknown>,\n> {\n model: string\n /** Shared state every question judges. A JSON array is one state, not a batch. */\n state: EvaluateState\n /** TypeSafe wire questions, keyed by the caller's question ids. */\n questions: Record<string, WireQuestion>\n /** Provider-specific options forwarded by `decide()`. */\n modelOptions?: TProviderOptions\n /** Forwarded to the provider request for cancellation. */\n abortSignal?: AbortSignal\n /**\n * Internal logger threaded from `decide()`. Adapters must call\n * `logger.request()` before the provider call and `logger.errors()` in catch\n * blocks.\n */\n logger: InternalLogger\n}\n\n/**\n * Provider-level evaluate result. Adapters return the wire payload plus usage.\n * The activity maps answers to the unified public shape.\n */\nexport interface EvaluateAdapterResult {\n /** Resolved model id from the provider. */\n model: string\n answers: Record<string, WireAnswer>\n usage: TokenUsage\n /** Provider response id, for example to look the request up later. */\n id?: string\n /** Upstream provider that served the request, when a router reports it. */\n provider?: string\n}\n\n/**\n * Evaluate adapter interface with pre-resolved generics.\n *\n * An adapter is created by a provider function: `provider('model')` → `adapter`.\n * All type resolution happens at the provider call site, not in this interface.\n *\n * Generic parameters:\n * - TModel: The specific model name (e.g. `'jev-latest'`)\n * - TProviderOptions: Provider-specific options (already resolved)\n */\nexport interface EvaluateAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n> {\n /** Discriminator for adapter kind */\n readonly kind: 'evaluate'\n /** Adapter name identifier */\n readonly name: string\n /** The model this adapter is configured for */\n readonly model: TModel\n\n /**\n * @internal Type-only properties for inference. Not assigned at runtime.\n */\n '~types': {\n providerOptions: TProviderOptions\n }\n\n /**\n * Evaluate typed questions against `state`. Return the provider payload.\n * Do not invent unified `.value` fields. The activity maps wire answers.\n */\n evaluate: (\n options: EvaluateOptions<TProviderOptions>,\n ) => Promise<EvaluateAdapterResult>\n}\n\n/**\n * An EvaluateAdapter with any/unknown type parameters.\n * Useful as a constraint in generic functions and interfaces.\n */\nexport type AnyEvaluateAdapter = EvaluateAdapter<any, any>\n\n/**\n * Abstract base class for evaluate adapters.\n * Extend this class to implement an evaluate adapter for a specific provider.\n *\n * Generic parameters match EvaluateAdapter. The provider function resolves them.\n */\nexport abstract class BaseEvaluateAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n> implements EvaluateAdapter<TModel, TProviderOptions> {\n readonly kind = 'evaluate' as const\n abstract readonly name: string\n readonly model: TModel\n\n // Type-only property - never assigned at runtime\n declare '~types': {\n providerOptions: TProviderOptions\n }\n\n protected config: EvaluateAdapterConfig\n\n constructor(config: EvaluateAdapterConfig = {}, model: TModel) {\n this.config = config\n this.model = model\n }\n\n abstract evaluate(\n options: EvaluateOptions<TProviderOptions>,\n ): Promise<EvaluateAdapterResult>\n\n protected generateId(): string {\n return `${this.name}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n }\n}\n"],"mappings":";;;;;;;AA4LA,IAAsB,sBAAtB,MAGuD;CACrD,OAAgB;CAEhB;CAOA;CAEA,YAAY,SAAgC,CAAC,GAAG,OAAe;EAC7D,KAAK,SAAS;EACd,KAAK,QAAQ;CACf;CAMA,aAA+B;EAC7B,OAAO,GAAG,KAAK,KAAK,GAAG,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;CAC5E;AACF"}
@@ -51,6 +51,10 @@ export interface EvaluateResultMeta {
51
51
  /** Resolved model id from the provider. */
52
52
  model: string;
53
53
  usage: TokenUsage;
54
+ /** Provider response id, when the adapter returns one. */
55
+ id?: string;
56
+ /** Upstream provider that served the request, when the adapter returns one. */
57
+ provider?: string;
54
58
  }
55
59
  /**
56
60
  * Map a helper question (or wire question) to its public answer type.
@@ -292,7 +292,9 @@ async function decide(options) {
292
292
  });
293
293
  return withMeta(answers, {
294
294
  model: result.model,
295
- usage: result.usage
295
+ usage: result.usage,
296
+ ...result.id !== void 0 && { id: result.id },
297
+ ...result.provider !== void 0 && { provider: result.provider }
296
298
  });
297
299
  } catch (error) {
298
300
  const duration = Date.now() - startTime;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/activities/evaluate/index.ts"],"sourcesContent":["/**\n * Evaluate Activity\n *\n * Asks typed questions about a shared state and returns values your code can\n * branch on. This is a self-contained module with implementation, types, and\n * JSDoc.\n */\n\nimport { aiEventClient } from '@tanstack/ai-event-client'\nimport { resolveDebugOption } from '../../logger/resolve'\nimport { isAbortShapedError } from '../error-payload'\nimport {\n createGenerationContext,\n runGenerationAbort,\n runGenerationError,\n runGenerationFinish,\n runGenerationStart,\n runGenerationUsage,\n} from '../middleware/run'\nimport type { InternalLogger } from '../../logger/internal-logger'\nimport type { DebugOption } from '../../logger/types'\nimport type { TokenUsage } from '../../types'\nimport type { GenerationMiddleware } from '../middleware/types'\nimport type {\n EvaluateAdapter,\n EvaluateInstructions,\n EvaluateState,\n WireAnswer,\n WireChoiceAnswer,\n WireNoulAnswer,\n WireQuestion,\n WireScoreAnswer,\n WireScoreQuestion,\n} from './adapter'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'evaluate' as const\n\n/** Question key reserved for `result.meta`. */\nconst RESERVED_QUESTION_KEY = 'meta' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/** Extract provider options from an EvaluateAdapter via ~types */\nexport type EvaluateProviderOptions<TAdapter> = TAdapter extends {\n '~types': { providerOptions: infer P extends object }\n}\n ? P\n : object\n\n// ===========================\n// Unified answers\n// ===========================\n\n/**\n * Public choice answer. `.value` is the selected option key.\n */\nexport interface ChoiceAnswer<TValue extends string = string> {\n type: 'choice'\n value: TValue\n /** P(selected option). */\n probability: number\n confidence: number\n probabilities: Record<TValue, number>\n}\n\n/**\n * Public score answer. `.value` is the nearest level label.\n * `.score` is the raw TypeSafe fraction.\n */\nexport interface ScoreAnswer<TLevel extends string = string> {\n type: 'score'\n value: TLevel\n /** P(nearest level). */\n probability: number\n confidence: number\n score: number\n legend: Record<string, string>\n probabilities: Record<string, number>\n}\n\n/**\n * Public yes/no answer. `.value` is `true` when P(true) is 0.5 or more.\n * There is no `.confidence`.\n */\nexport interface BooleanAnswer {\n type: 'boolean'\n value: boolean\n /** P(true), from the wire `noul` field. */\n probability: number\n}\n\nexport interface EvaluateResultMeta {\n /** Resolved model id from the provider. */\n model: string\n usage: TokenUsage\n}\n\n/**\n * Map a helper question (or wire question) to its public answer type.\n */\nexport type InferEvaluateAnswer<TQuestion> = TQuestion extends {\n type: 'choice'\n criteria: infer TCriteria\n}\n ? TCriteria extends Record<string, string | null>\n ? ChoiceAnswer<Extract<keyof TCriteria, string>>\n : ChoiceAnswer\n : TQuestion extends { type: 'score'; criteria: infer TLevels }\n ? TLevels extends ReadonlyArray<string>\n ? ScoreAnswer<TLevels[number] & string>\n : ScoreAnswer\n : TQuestion extends { type: 'noul' }\n ? BooleanAnswer\n : never\n\n/**\n * Result of `decide()`. Each question key is a top-level answer.\n * `meta` holds the resolved model id and usage.\n */\nexport type EvaluateResult<TQuestions extends Record<string, WireQuestion>> = {\n [K in keyof TQuestions as K extends typeof RESERVED_QUESTION_KEY\n ? never\n : K]: InferEvaluateAnswer<TQuestions[K]>\n} & {\n meta: EvaluateResultMeta\n}\n\n// ===========================\n// Activity Options Types\n// ===========================\n\n/**\n * Options for the evaluate activity. The model is extracted from the\n * adapter's model property.\n *\n * @template TAdapter - The evaluate adapter type\n * @template TQuestions - The questions object passed to `decide`\n */\nexport interface EvaluateActivityOptions<\n TAdapter extends EvaluateAdapter<string, EvaluateProviderOptions<TAdapter>>,\n TQuestions extends Record<string, WireQuestion>,\n> {\n /** The evaluate adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /** Shared state every question judges. A JSON array is one state, not a batch. */\n state: EvaluateState\n /**\n * Questions built with `choice`, `score`, and `boolean`.\n * The key `meta` is reserved.\n */\n questions: TQuestions\n /** Provider-specific options */\n modelOptions?: EvaluateProviderOptions<TAdapter>\n /** Forwarded to the provider request for cancellation. */\n abortSignal?: AbortSignal\n /**\n * Observe-only middleware notified on start, usage, success, abort, and\n * error. Pass `otelMiddleware()` to emit OpenTelemetry spans, or implement\n * the `GenerationMiddleware` contract for a custom backend.\n */\n middleware?: Array<GenerationMiddleware>\n /**\n * Enable debug logging. Pass `true` to enable all categories, `false` to\n * silence everything including errors, or a `DebugConfig` object for granular\n * control and/or a custom `Logger`.\n */\n debug?: DebugOption\n}\n\n// ===========================\n// Helper Functions\n// ===========================\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n\nfunction isAbortError(error: unknown, signal?: AbortSignal): boolean {\n // Prefer the error's own identity over the signal state. A genuine\n // cancellation throws an abort-shaped error (DOM `AbortError`, the OpenRouter\n // SDK's `RequestAbortedError`, ...). Classifying on `signal.aborted` alone\n // would misroute a real failure to the abort hook whenever a shared signal\n // happens to already be aborted, hiding it from `onError` observers.\n if (isAbortShapedError(error)) return true\n // Fall back to signal state only for non-Error throws we can't otherwise\n // identify; a real Error with a non-abort name is never an abort.\n return error instanceof Error ? false : signal?.aborted === true\n}\n\nfunction questionKeys(questions: Record<string, WireQuestion>) {\n return Object.keys(questions)\n}\n\nfunction assertQuestions(questions: Record<string, WireQuestion>) {\n const keys = questionKeys(questions)\n if (keys.length === 0) {\n throw new Error('decide() requires at least one question')\n }\n if (Object.hasOwn(questions, RESERVED_QUESTION_KEY)) {\n throw new Error('decide() reserves the question key \"meta\"')\n }\n return keys\n}\n\nfunction mapChoiceAnswer(wire: WireChoiceAnswer, key: string) {\n const probability = wire.probabilities[wire.choice]\n if (typeof probability !== 'number') {\n throw new Error(\n `decide(): missing probability for choice \"${wire.choice}\" on \"${key}\"`,\n )\n }\n return {\n type: 'choice' as const,\n value: wire.choice,\n probability,\n confidence: wire.confidence,\n probabilities: wire.probabilities,\n }\n}\n\nfunction mapScoreAnswer(\n question: WireScoreQuestion,\n wire: WireScoreAnswer,\n key: string,\n) {\n const levels = question.criteria\n if (levels.length < 2) {\n throw new Error(\n `decide(): score question \"${key}\" needs at least two levels`,\n )\n }\n const lastIndex = levels.length - 1\n const rounded = Math.round(wire.score)\n const nearestIndex =\n rounded < 0 ? 0 : rounded > lastIndex ? lastIndex : rounded\n const value = levels[nearestIndex]\n if (value === undefined) {\n throw new Error(\n `decide(): score question \"${key}\" has no level at index ${nearestIndex}`,\n )\n }\n const probability = wire.probabilities[String(nearestIndex)]\n if (typeof probability !== 'number') {\n throw new Error(\n `decide(): missing probability for score level ${nearestIndex} on \"${key}\"`,\n )\n }\n return {\n type: 'score' as const,\n value,\n probability,\n confidence: wire.confidence,\n score: wire.score,\n legend: wire.legend,\n probabilities: wire.probabilities,\n }\n}\n\nfunction mapBooleanAnswer(wire: WireNoulAnswer) {\n return {\n type: 'boolean' as const,\n value: wire.noul >= 0.5,\n probability: wire.noul,\n }\n}\n\nfunction mapWireAnswer(question: WireQuestion, wire: WireAnswer, key: string) {\n switch (question.type) {\n case 'choice': {\n if (wire.type !== 'choice') {\n throw new Error(\n `decide(): expected choice answer for \"${key}\", got ${wire.type}`,\n )\n }\n return mapChoiceAnswer(wire, key)\n }\n case 'score': {\n if (wire.type !== 'score') {\n throw new Error(\n `decide(): expected score answer for \"${key}\", got ${wire.type}`,\n )\n }\n return mapScoreAnswer(question, wire, key)\n }\n case 'noul': {\n if (wire.type !== 'noul') {\n throw new Error(\n `decide(): expected noul answer for \"${key}\", got ${wire.type}`,\n )\n }\n return mapBooleanAnswer(wire)\n }\n }\n}\n\nfunction mapAnswers<TQuestions extends Record<string, WireQuestion>>(\n questions: TQuestions,\n wireAnswers: Record<string, WireAnswer>,\n) {\n const answers = {} as {\n [K in keyof TQuestions]: InferEvaluateAnswer<TQuestions[K]>\n }\n const keys = Object.keys(questions) as Array<keyof TQuestions>\n for (const key of keys) {\n const question = questions[key]\n const wire = wireAnswers[String(key)]\n if (question === undefined) {\n throw new Error(`decide(): missing question \"${String(key)}\"`)\n }\n if (wire === undefined) {\n throw new Error(`decide(): missing answer for question \"${String(key)}\"`)\n }\n answers[key] = mapWireAnswer(\n question,\n wire,\n String(key),\n ) as InferEvaluateAnswer<TQuestions[typeof key]>\n }\n return answers\n}\n\nfunction withMeta<TAnswers extends object>(\n answers: TAnswers,\n meta: EvaluateResultMeta,\n) {\n return { ...answers, meta }\n}\n\n// ===========================\n// Question helpers\n// ===========================\n\n/**\n * Build a choice question. The model picks one key from `options`.\n *\n * Option keys become the union on `.value`. Use `null` when a key needs no\n * extra description. On the wire, `options` is sent as TypeSafe `criteria`.\n *\n * @param options.instructions What the model should decide.\n * @param options.options Map of option key to description, or `null`.\n *\n * @example\n * ```ts\n * const queue = choice({\n * instructions: 'Which team should handle this ticket?',\n * options: {\n * billing: 'Payments, invoices, refunds',\n * tech: 'Bugs, outages, integrations',\n * sales: 'Pricing, upgrades, new accounts',\n * },\n * })\n * ```\n */\nexport function choice<\n const TOptions extends Record<string, string | null>,\n>(options: { instructions: EvaluateInstructions; options: TOptions }) {\n return {\n type: 'choice' as const,\n instructions: options.instructions,\n criteria: options.options,\n }\n}\n\n/**\n * Build a score question. The model rates `state` on ordered `levels`.\n *\n * You must pass at least two levels. `.value` is the nearest level label.\n * The raw fraction stays on `.score`. On the wire, `levels` is sent as\n * TypeSafe `criteria`.\n *\n * @param options.instructions What the model should rate.\n * @param options.levels Ordered labels, lowest first. At least two.\n *\n * @example\n * ```ts\n * const urgency = score({\n * instructions: 'How urgent is this ticket?',\n * levels: ['low', 'medium', 'high'],\n * })\n * ```\n */\nexport function score<const TLevels extends ReadonlyArray<string>>(options: {\n instructions: EvaluateInstructions\n levels: TLevels\n}) {\n if (options.levels.length < 2) {\n throw new Error('score() requires at least two levels')\n }\n return {\n type: 'score' as const,\n instructions: options.instructions,\n criteria: options.levels,\n }\n}\n\n/**\n * Build a yes/no question.\n *\n * `.value` is `true` when P(true) is 0.5 or more. There is no `.confidence`.\n * On the wire, the type is TypeSafe `noul`.\n *\n * @param options.instructions The yes/no question to judge.\n * @param options.criteria Optional descriptions of yes and no.\n *\n * @example\n * ```ts\n * const refund = boolean({\n * instructions: 'Is the customer asking for a refund?',\n * })\n * ```\n */\nexport function boolean(options: {\n instructions: EvaluateInstructions\n criteria?: {\n true?: string\n false?: string\n }\n}) {\n if (options.criteria === undefined) {\n return {\n type: 'noul' as const,\n instructions: options.instructions,\n }\n }\n return {\n type: 'noul' as const,\n instructions: options.instructions,\n criteria: options.criteria,\n }\n}\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * Ask typed questions about `state` and get answers your code can branch on.\n *\n * You have state (a ticket, a record, a log) and you need typed answers, not\n * prose. Pass questions built with `choice`, `score`, and `boolean`. Then\n * branch on `result.queue.value` in ordinary TypeScript.\n *\n * The question key `meta` is reserved. Throws if `questions` is empty or uses\n * that key.\n *\n * @param options.adapter Evaluate adapter created with a model.\n * @param options.state Shared state every question judges.\n * @param options.questions Questions built with `choice`, `score`, `boolean`.\n * @param options.modelOptions Provider-specific options.\n * @param options.abortSignal Cancels the in-flight request.\n * @param options.middleware Observe-only generation middleware.\n * @param options.debug Debug logging option.\n *\n * @example Route a support ticket\n * ```ts\n * import { decide, choice, score, boolean } from '@tanstack/ai'\n * import { typesafeDecider } from '@tanstack/ai-typesafe'\n *\n * const result = await decide({\n * adapter: typesafeDecider('jev-latest'),\n * state: ticket,\n * questions: {\n * queue: choice({\n * instructions: 'Which team should handle this ticket?',\n * options: {\n * billing: 'Payments, invoices, refunds',\n * tech: 'Bugs, outages, integrations',\n * sales: 'Pricing, upgrades, new accounts',\n * },\n * }),\n * urgency: score({\n * instructions: 'How urgent is this ticket?',\n * levels: ['low', 'medium', 'high'],\n * }),\n * refund: boolean({\n * instructions: 'Is the customer asking for a refund?',\n * }),\n * },\n * })\n *\n * result.queue.value\n * result.meta.model\n * result.meta.usage\n * ```\n */\nexport async function decide<\n TAdapter extends EvaluateAdapter<string, EvaluateProviderOptions<TAdapter>>,\n TQuestions extends Record<string, WireQuestion>,\n>(options: EvaluateActivityOptions<TAdapter, TQuestions>) {\n const {\n adapter,\n state,\n questions,\n modelOptions,\n abortSignal,\n middleware,\n debug,\n } = options\n const model = adapter.model\n const keys = assertQuestions(questions)\n const requestId = createId('evaluate')\n const startTime = Date.now()\n const logger: InternalLogger = resolveDebugOption(debug)\n\n const mwCtx = createGenerationContext({\n requestId,\n activity: 'evaluate',\n provider: adapter.name,\n model,\n modelOptions,\n createId,\n })\n\n await runGenerationStart(middleware, mwCtx)\n\n aiEventClient.emit('evaluate:request:started', {\n requestId,\n provider: adapter.name,\n model,\n questionCount: keys.length,\n timestamp: startTime,\n })\n\n logger.request(`activity=evaluate provider=${adapter.name}`, {\n provider: adapter.name,\n model,\n questionCount: keys.length,\n })\n\n try {\n const result = await adapter.evaluate({\n model,\n state,\n questions,\n modelOptions,\n abortSignal,\n logger,\n })\n\n const answers = mapAnswers(questions, result.answers)\n const duration = Date.now() - startTime\n\n aiEventClient.emit('evaluate:request:completed', {\n requestId,\n provider: adapter.name,\n model: result.model,\n questionCount: keys.length,\n duration,\n timestamp: Date.now(),\n })\n\n aiEventClient.emit('evaluate:usage', {\n requestId,\n model: result.model,\n usage: result.usage,\n timestamp: Date.now(),\n })\n\n logger.output(`activity=evaluate answers=${keys.length}`, {\n answerCount: keys.length,\n })\n\n await runGenerationUsage(middleware, mwCtx, result.usage)\n await runGenerationFinish(middleware, mwCtx, {\n duration,\n usage: result.usage,\n })\n\n return withMeta(answers, {\n model: result.model,\n usage: result.usage,\n })\n } catch (error) {\n const duration = Date.now() - startTime\n if (isAbortError(error, abortSignal)) {\n await runGenerationAbort(middleware, mwCtx, {\n reason: error instanceof Error ? error.message : undefined,\n duration,\n })\n } else {\n await runGenerationError(middleware, mwCtx, { error, duration })\n }\n logger.errors('evaluate activity failed', { error, source: 'evaluate' })\n throw error\n }\n}\n\n// Re-export adapter types\nexport type {\n EvaluateAdapter,\n EvaluateAdapterConfig,\n AnyEvaluateAdapter,\n EvaluateOptions,\n EvaluateAdapterResult,\n EvaluateState,\n EvaluateInstructions,\n EvaluateJsonValue,\n WireQuestion,\n WireAnswer,\n WireChoiceQuestion,\n WireScoreQuestion,\n WireNoulQuestion,\n WireChoiceAnswer,\n WireScoreAnswer,\n WireNoulAnswer,\n} from './adapter'\nexport { BaseEvaluateAdapter } from './adapter'\n"],"mappings":";;;;;;;;;;;;;;AAwCA,IAAa,OAAO;;AAGpB,IAAM,wBAAwB;AAyI9B,SAAS,SAAS,QAAwB;CACxC,OAAO,GAAG,OAAO,GAAG,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;AACzE;AAEA,SAAS,aAAa,OAAgB,QAA+B;CAMnE,IAAI,mBAAmB,KAAK,GAAG,OAAO;CAGtC,OAAO,iBAAiB,QAAQ,QAAQ,QAAQ,YAAY;AAC9D;AAEA,SAAS,aAAa,WAAyC;CAC7D,OAAO,OAAO,KAAK,SAAS;AAC9B;AAEA,SAAS,gBAAgB,WAAyC;CAChE,MAAM,OAAO,aAAa,SAAS;CACnC,IAAI,KAAK,WAAW,GAClB,MAAM,IAAI,MAAM,yCAAyC;CAE3D,IAAI,OAAO,OAAO,WAAW,qBAAqB,GAChD,MAAM,IAAI,MAAM,6CAA2C;CAE7D,OAAO;AACT;AAEA,SAAS,gBAAgB,MAAwB,KAAa;CAC5D,MAAM,cAAc,KAAK,cAAc,KAAK;CAC5C,IAAI,OAAO,gBAAgB,UACzB,MAAM,IAAI,MACR,6CAA6C,KAAK,OAAO,QAAQ,IAAI,EACvE;CAEF,OAAO;EACL,MAAM;EACN,OAAO,KAAK;EACZ;EACA,YAAY,KAAK;EACjB,eAAe,KAAK;CACtB;AACF;AAEA,SAAS,eACP,UACA,MACA,KACA;CACA,MAAM,SAAS,SAAS;CACxB,IAAI,OAAO,SAAS,GAClB,MAAM,IAAI,MACR,6BAA6B,IAAI,4BACnC;CAEF,MAAM,YAAY,OAAO,SAAS;CAClC,MAAM,UAAU,KAAK,MAAM,KAAK,KAAK;CACrC,MAAM,eACJ,UAAU,IAAI,IAAI,UAAU,YAAY,YAAY;CACtD,MAAM,QAAQ,OAAO;CACrB,IAAI,UAAU,KAAA,GACZ,MAAM,IAAI,MACR,6BAA6B,IAAI,0BAA0B,cAC7D;CAEF,MAAM,cAAc,KAAK,cAAc,OAAO,YAAY;CAC1D,IAAI,OAAO,gBAAgB,UACzB,MAAM,IAAI,MACR,iDAAiD,aAAa,OAAO,IAAI,EAC3E;CAEF,OAAO;EACL,MAAM;EACN;EACA;EACA,YAAY,KAAK;EACjB,OAAO,KAAK;EACZ,QAAQ,KAAK;EACb,eAAe,KAAK;CACtB;AACF;AAEA,SAAS,iBAAiB,MAAsB;CAC9C,OAAO;EACL,MAAM;EACN,OAAO,KAAK,QAAQ;EACpB,aAAa,KAAK;CACpB;AACF;AAEA,SAAS,cAAc,UAAwB,MAAkB,KAAa;CAC5E,QAAQ,SAAS,MAAjB;EACE,KAAK;GACH,IAAI,KAAK,SAAS,UAChB,MAAM,IAAI,MACR,yCAAyC,IAAI,SAAS,KAAK,MAC7D;GAEF,OAAO,gBAAgB,MAAM,GAAG;EAElC,KAAK;GACH,IAAI,KAAK,SAAS,SAChB,MAAM,IAAI,MACR,wCAAwC,IAAI,SAAS,KAAK,MAC5D;GAEF,OAAO,eAAe,UAAU,MAAM,GAAG;EAE3C,KAAK;GACH,IAAI,KAAK,SAAS,QAChB,MAAM,IAAI,MACR,uCAAuC,IAAI,SAAS,KAAK,MAC3D;GAEF,OAAO,iBAAiB,IAAI;CAEhC;AACF;AAEA,SAAS,WACP,WACA,aACA;CACA,MAAM,UAAU,CAAC;CAGjB,MAAM,OAAO,OAAO,KAAK,SAAS;CAClC,KAAK,MAAM,OAAO,MAAM;EACtB,MAAM,WAAW,UAAU;EAC3B,MAAM,OAAO,YAAY,OAAO,GAAG;EACnC,IAAI,aAAa,KAAA,GACf,MAAM,IAAI,MAAM,+BAA+B,OAAO,GAAG,EAAE,EAAE;EAE/D,IAAI,SAAS,KAAA,GACX,MAAM,IAAI,MAAM,0CAA0C,OAAO,GAAG,EAAE,EAAE;EAE1E,QAAQ,OAAO,cACb,UACA,MACA,OAAO,GAAG,CACZ;CACF;CACA,OAAO;AACT;AAEA,SAAS,SACP,SACA,MACA;CACA,OAAO;EAAE,GAAG;EAAS;CAAK;AAC5B;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,OAEd,SAAoE;CACpE,OAAO;EACL,MAAM;EACN,cAAc,QAAQ;EACtB,UAAU,QAAQ;CACpB;AACF;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,MAAmD,SAGhE;CACD,IAAI,QAAQ,OAAO,SAAS,GAC1B,MAAM,IAAI,MAAM,sCAAsC;CAExD,OAAO;EACL,MAAM;EACN,cAAc,QAAQ;EACtB,UAAU,QAAQ;CACpB;AACF;;;;;;;;;;;;;;;;;AAkBA,SAAgB,QAAQ,SAMrB;CACD,IAAI,QAAQ,aAAa,KAAA,GACvB,OAAO;EACL,MAAM;EACN,cAAc,QAAQ;CACxB;CAEF,OAAO;EACL,MAAM;EACN,cAAc,QAAQ;EACtB,UAAU,QAAQ;CACpB;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDA,eAAsB,OAGpB,SAAwD;CACxD,MAAM,EACJ,SACA,OACA,WACA,cACA,aACA,YACA,UACE;CACJ,MAAM,QAAQ,QAAQ;CACtB,MAAM,OAAO,gBAAgB,SAAS;CACtC,MAAM,YAAY,SAAS,UAAU;CACrC,MAAM,YAAY,KAAK,IAAI;CAC3B,MAAM,SAAyB,mBAAmB,KAAK;CAEvD,MAAM,QAAQ,wBAAwB;EACpC;EACA,UAAU;EACV,UAAU,QAAQ;EAClB;EACA;EACA;CACF,CAAC;CAED,MAAM,mBAAmB,YAAY,KAAK;CAE1C,cAAc,KAAK,4BAA4B;EAC7C;EACA,UAAU,QAAQ;EAClB;EACA,eAAe,KAAK;EACpB,WAAW;CACb,CAAC;CAED,OAAO,QAAQ,8BAA8B,QAAQ,QAAQ;EAC3D,UAAU,QAAQ;EAClB;EACA,eAAe,KAAK;CACtB,CAAC;CAED,IAAI;EACF,MAAM,SAAS,MAAM,QAAQ,SAAS;GACpC;GACA;GACA;GACA;GACA;GACA;EACF,CAAC;EAED,MAAM,UAAU,WAAW,WAAW,OAAO,OAAO;EACpD,MAAM,WAAW,KAAK,IAAI,IAAI;EAE9B,cAAc,KAAK,8BAA8B;GAC/C;GACA,UAAU,QAAQ;GAClB,OAAO,OAAO;GACd,eAAe,KAAK;GACpB;GACA,WAAW,KAAK,IAAI;EACtB,CAAC;EAED,cAAc,KAAK,kBAAkB;GACnC;GACA,OAAO,OAAO;GACd,OAAO,OAAO;GACd,WAAW,KAAK,IAAI;EACtB,CAAC;EAED,OAAO,OAAO,6BAA6B,KAAK,UAAU,EACxD,aAAa,KAAK,OACpB,CAAC;EAED,MAAM,mBAAmB,YAAY,OAAO,OAAO,KAAK;EACxD,MAAM,oBAAoB,YAAY,OAAO;GAC3C;GACA,OAAO,OAAO;EAChB,CAAC;EAED,OAAO,SAAS,SAAS;GACvB,OAAO,OAAO;GACd,OAAO,OAAO;EAChB,CAAC;CACH,SAAS,OAAO;EACd,MAAM,WAAW,KAAK,IAAI,IAAI;EAC9B,IAAI,aAAa,OAAO,WAAW,GACjC,MAAM,mBAAmB,YAAY,OAAO;GAC1C,QAAQ,iBAAiB,QAAQ,MAAM,UAAU,KAAA;GACjD;EACF,CAAC;OAED,MAAM,mBAAmB,YAAY,OAAO;GAAE;GAAO;EAAS,CAAC;EAEjE,OAAO,OAAO,4BAA4B;GAAE;GAAO,QAAQ;EAAW,CAAC;EACvE,MAAM;CACR;AACF"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/activities/evaluate/index.ts"],"sourcesContent":["/**\n * Evaluate Activity\n *\n * Asks typed questions about a shared state and returns values your code can\n * branch on. This is a self-contained module with implementation, types, and\n * JSDoc.\n */\n\nimport { aiEventClient } from '@tanstack/ai-event-client'\nimport { resolveDebugOption } from '../../logger/resolve'\nimport { isAbortShapedError } from '../error-payload'\nimport {\n createGenerationContext,\n runGenerationAbort,\n runGenerationError,\n runGenerationFinish,\n runGenerationStart,\n runGenerationUsage,\n} from '../middleware/run'\nimport type { InternalLogger } from '../../logger/internal-logger'\nimport type { DebugOption } from '../../logger/types'\nimport type { TokenUsage } from '../../types'\nimport type { GenerationMiddleware } from '../middleware/types'\nimport type {\n EvaluateAdapter,\n EvaluateInstructions,\n EvaluateState,\n WireAnswer,\n WireChoiceAnswer,\n WireNoulAnswer,\n WireQuestion,\n WireScoreAnswer,\n WireScoreQuestion,\n} from './adapter'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'evaluate' as const\n\n/** Question key reserved for `result.meta`. */\nconst RESERVED_QUESTION_KEY = 'meta' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/** Extract provider options from an EvaluateAdapter via ~types */\nexport type EvaluateProviderOptions<TAdapter> = TAdapter extends {\n '~types': { providerOptions: infer P extends object }\n}\n ? P\n : object\n\n// ===========================\n// Unified answers\n// ===========================\n\n/**\n * Public choice answer. `.value` is the selected option key.\n */\nexport interface ChoiceAnswer<TValue extends string = string> {\n type: 'choice'\n value: TValue\n /** P(selected option). */\n probability: number\n confidence: number\n probabilities: Record<TValue, number>\n}\n\n/**\n * Public score answer. `.value` is the nearest level label.\n * `.score` is the raw TypeSafe fraction.\n */\nexport interface ScoreAnswer<TLevel extends string = string> {\n type: 'score'\n value: TLevel\n /** P(nearest level). */\n probability: number\n confidence: number\n score: number\n legend: Record<string, string>\n probabilities: Record<string, number>\n}\n\n/**\n * Public yes/no answer. `.value` is `true` when P(true) is 0.5 or more.\n * There is no `.confidence`.\n */\nexport interface BooleanAnswer {\n type: 'boolean'\n value: boolean\n /** P(true), from the wire `noul` field. */\n probability: number\n}\n\nexport interface EvaluateResultMeta {\n /** Resolved model id from the provider. */\n model: string\n usage: TokenUsage\n /** Provider response id, when the adapter returns one. */\n id?: string\n /** Upstream provider that served the request, when the adapter returns one. */\n provider?: string\n}\n\n/**\n * Map a helper question (or wire question) to its public answer type.\n */\nexport type InferEvaluateAnswer<TQuestion> = TQuestion extends {\n type: 'choice'\n criteria: infer TCriteria\n}\n ? TCriteria extends Record<string, string | null>\n ? ChoiceAnswer<Extract<keyof TCriteria, string>>\n : ChoiceAnswer\n : TQuestion extends { type: 'score'; criteria: infer TLevels }\n ? TLevels extends ReadonlyArray<string>\n ? ScoreAnswer<TLevels[number] & string>\n : ScoreAnswer\n : TQuestion extends { type: 'noul' }\n ? BooleanAnswer\n : never\n\n/**\n * Result of `decide()`. Each question key is a top-level answer.\n * `meta` holds the resolved model id and usage.\n */\nexport type EvaluateResult<TQuestions extends Record<string, WireQuestion>> = {\n [K in keyof TQuestions as K extends typeof RESERVED_QUESTION_KEY\n ? never\n : K]: InferEvaluateAnswer<TQuestions[K]>\n} & {\n meta: EvaluateResultMeta\n}\n\n// ===========================\n// Activity Options Types\n// ===========================\n\n/**\n * Options for the evaluate activity. The model is extracted from the\n * adapter's model property.\n *\n * @template TAdapter - The evaluate adapter type\n * @template TQuestions - The questions object passed to `decide`\n */\nexport interface EvaluateActivityOptions<\n TAdapter extends EvaluateAdapter<string, EvaluateProviderOptions<TAdapter>>,\n TQuestions extends Record<string, WireQuestion>,\n> {\n /** The evaluate adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /** Shared state every question judges. A JSON array is one state, not a batch. */\n state: EvaluateState\n /**\n * Questions built with `choice`, `score`, and `boolean`.\n * The key `meta` is reserved.\n */\n questions: TQuestions\n /** Provider-specific options */\n modelOptions?: EvaluateProviderOptions<TAdapter>\n /** Forwarded to the provider request for cancellation. */\n abortSignal?: AbortSignal\n /**\n * Observe-only middleware notified on start, usage, success, abort, and\n * error. Pass `otelMiddleware()` to emit OpenTelemetry spans, or implement\n * the `GenerationMiddleware` contract for a custom backend.\n */\n middleware?: Array<GenerationMiddleware>\n /**\n * Enable debug logging. Pass `true` to enable all categories, `false` to\n * silence everything including errors, or a `DebugConfig` object for granular\n * control and/or a custom `Logger`.\n */\n debug?: DebugOption\n}\n\n// ===========================\n// Helper Functions\n// ===========================\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n\nfunction isAbortError(error: unknown, signal?: AbortSignal): boolean {\n // Prefer the error's own identity over the signal state. A genuine\n // cancellation throws an abort-shaped error (DOM `AbortError`, the OpenRouter\n // SDK's `RequestAbortedError`, ...). Classifying on `signal.aborted` alone\n // would misroute a real failure to the abort hook whenever a shared signal\n // happens to already be aborted, hiding it from `onError` observers.\n if (isAbortShapedError(error)) return true\n // Fall back to signal state only for non-Error throws we can't otherwise\n // identify; a real Error with a non-abort name is never an abort.\n return error instanceof Error ? false : signal?.aborted === true\n}\n\nfunction questionKeys(questions: Record<string, WireQuestion>) {\n return Object.keys(questions)\n}\n\nfunction assertQuestions(questions: Record<string, WireQuestion>) {\n const keys = questionKeys(questions)\n if (keys.length === 0) {\n throw new Error('decide() requires at least one question')\n }\n if (Object.hasOwn(questions, RESERVED_QUESTION_KEY)) {\n throw new Error('decide() reserves the question key \"meta\"')\n }\n return keys\n}\n\nfunction mapChoiceAnswer(wire: WireChoiceAnswer, key: string) {\n const probability = wire.probabilities[wire.choice]\n if (typeof probability !== 'number') {\n throw new Error(\n `decide(): missing probability for choice \"${wire.choice}\" on \"${key}\"`,\n )\n }\n return {\n type: 'choice' as const,\n value: wire.choice,\n probability,\n confidence: wire.confidence,\n probabilities: wire.probabilities,\n }\n}\n\nfunction mapScoreAnswer(\n question: WireScoreQuestion,\n wire: WireScoreAnswer,\n key: string,\n) {\n const levels = question.criteria\n if (levels.length < 2) {\n throw new Error(\n `decide(): score question \"${key}\" needs at least two levels`,\n )\n }\n const lastIndex = levels.length - 1\n const rounded = Math.round(wire.score)\n const nearestIndex =\n rounded < 0 ? 0 : rounded > lastIndex ? lastIndex : rounded\n const value = levels[nearestIndex]\n if (value === undefined) {\n throw new Error(\n `decide(): score question \"${key}\" has no level at index ${nearestIndex}`,\n )\n }\n const probability = wire.probabilities[String(nearestIndex)]\n if (typeof probability !== 'number') {\n throw new Error(\n `decide(): missing probability for score level ${nearestIndex} on \"${key}\"`,\n )\n }\n return {\n type: 'score' as const,\n value,\n probability,\n confidence: wire.confidence,\n score: wire.score,\n legend: wire.legend,\n probabilities: wire.probabilities,\n }\n}\n\nfunction mapBooleanAnswer(wire: WireNoulAnswer) {\n return {\n type: 'boolean' as const,\n value: wire.noul >= 0.5,\n probability: wire.noul,\n }\n}\n\nfunction mapWireAnswer(question: WireQuestion, wire: WireAnswer, key: string) {\n switch (question.type) {\n case 'choice': {\n if (wire.type !== 'choice') {\n throw new Error(\n `decide(): expected choice answer for \"${key}\", got ${wire.type}`,\n )\n }\n return mapChoiceAnswer(wire, key)\n }\n case 'score': {\n if (wire.type !== 'score') {\n throw new Error(\n `decide(): expected score answer for \"${key}\", got ${wire.type}`,\n )\n }\n return mapScoreAnswer(question, wire, key)\n }\n case 'noul': {\n if (wire.type !== 'noul') {\n throw new Error(\n `decide(): expected noul answer for \"${key}\", got ${wire.type}`,\n )\n }\n return mapBooleanAnswer(wire)\n }\n }\n}\n\nfunction mapAnswers<TQuestions extends Record<string, WireQuestion>>(\n questions: TQuestions,\n wireAnswers: Record<string, WireAnswer>,\n) {\n const answers = {} as {\n [K in keyof TQuestions]: InferEvaluateAnswer<TQuestions[K]>\n }\n const keys = Object.keys(questions) as Array<keyof TQuestions>\n for (const key of keys) {\n const question = questions[key]\n const wire = wireAnswers[String(key)]\n if (question === undefined) {\n throw new Error(`decide(): missing question \"${String(key)}\"`)\n }\n if (wire === undefined) {\n throw new Error(`decide(): missing answer for question \"${String(key)}\"`)\n }\n answers[key] = mapWireAnswer(\n question,\n wire,\n String(key),\n ) as InferEvaluateAnswer<TQuestions[typeof key]>\n }\n return answers\n}\n\nfunction withMeta<TAnswers extends object>(\n answers: TAnswers,\n meta: EvaluateResultMeta,\n) {\n return { ...answers, meta }\n}\n\n// ===========================\n// Question helpers\n// ===========================\n\n/**\n * Build a choice question. The model picks one key from `options`.\n *\n * Option keys become the union on `.value`. Use `null` when a key needs no\n * extra description. On the wire, `options` is sent as TypeSafe `criteria`.\n *\n * @param options.instructions What the model should decide.\n * @param options.options Map of option key to description, or `null`.\n *\n * @example\n * ```ts\n * const queue = choice({\n * instructions: 'Which team should handle this ticket?',\n * options: {\n * billing: 'Payments, invoices, refunds',\n * tech: 'Bugs, outages, integrations',\n * sales: 'Pricing, upgrades, new accounts',\n * },\n * })\n * ```\n */\nexport function choice<\n const TOptions extends Record<string, string | null>,\n>(options: { instructions: EvaluateInstructions; options: TOptions }) {\n return {\n type: 'choice' as const,\n instructions: options.instructions,\n criteria: options.options,\n }\n}\n\n/**\n * Build a score question. The model rates `state` on ordered `levels`.\n *\n * You must pass at least two levels. `.value` is the nearest level label.\n * The raw fraction stays on `.score`. On the wire, `levels` is sent as\n * TypeSafe `criteria`.\n *\n * @param options.instructions What the model should rate.\n * @param options.levels Ordered labels, lowest first. At least two.\n *\n * @example\n * ```ts\n * const urgency = score({\n * instructions: 'How urgent is this ticket?',\n * levels: ['low', 'medium', 'high'],\n * })\n * ```\n */\nexport function score<const TLevels extends ReadonlyArray<string>>(options: {\n instructions: EvaluateInstructions\n levels: TLevels\n}) {\n if (options.levels.length < 2) {\n throw new Error('score() requires at least two levels')\n }\n return {\n type: 'score' as const,\n instructions: options.instructions,\n criteria: options.levels,\n }\n}\n\n/**\n * Build a yes/no question.\n *\n * `.value` is `true` when P(true) is 0.5 or more. There is no `.confidence`.\n * On the wire, the type is TypeSafe `noul`.\n *\n * @param options.instructions The yes/no question to judge.\n * @param options.criteria Optional descriptions of yes and no.\n *\n * @example\n * ```ts\n * const refund = boolean({\n * instructions: 'Is the customer asking for a refund?',\n * })\n * ```\n */\nexport function boolean(options: {\n instructions: EvaluateInstructions\n criteria?: {\n true?: string\n false?: string\n }\n}) {\n if (options.criteria === undefined) {\n return {\n type: 'noul' as const,\n instructions: options.instructions,\n }\n }\n return {\n type: 'noul' as const,\n instructions: options.instructions,\n criteria: options.criteria,\n }\n}\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * Ask typed questions about `state` and get answers your code can branch on.\n *\n * You have state (a ticket, a record, a log) and you need typed answers, not\n * prose. Pass questions built with `choice`, `score`, and `boolean`. Then\n * branch on `result.queue.value` in ordinary TypeScript.\n *\n * The question key `meta` is reserved. Throws if `questions` is empty or uses\n * that key.\n *\n * @param options.adapter Evaluate adapter created with a model.\n * @param options.state Shared state every question judges.\n * @param options.questions Questions built with `choice`, `score`, `boolean`.\n * @param options.modelOptions Provider-specific options.\n * @param options.abortSignal Cancels the in-flight request.\n * @param options.middleware Observe-only generation middleware.\n * @param options.debug Debug logging option.\n *\n * @example Route a support ticket\n * ```ts\n * import { decide, choice, score, boolean } from '@tanstack/ai'\n * import { typesafeDecider } from '@tanstack/ai-typesafe'\n *\n * const result = await decide({\n * adapter: typesafeDecider('jev-latest'),\n * state: ticket,\n * questions: {\n * queue: choice({\n * instructions: 'Which team should handle this ticket?',\n * options: {\n * billing: 'Payments, invoices, refunds',\n * tech: 'Bugs, outages, integrations',\n * sales: 'Pricing, upgrades, new accounts',\n * },\n * }),\n * urgency: score({\n * instructions: 'How urgent is this ticket?',\n * levels: ['low', 'medium', 'high'],\n * }),\n * refund: boolean({\n * instructions: 'Is the customer asking for a refund?',\n * }),\n * },\n * })\n *\n * result.queue.value\n * result.meta.model\n * result.meta.usage\n * ```\n */\nexport async function decide<\n TAdapter extends EvaluateAdapter<string, EvaluateProviderOptions<TAdapter>>,\n TQuestions extends Record<string, WireQuestion>,\n>(options: EvaluateActivityOptions<TAdapter, TQuestions>) {\n const {\n adapter,\n state,\n questions,\n modelOptions,\n abortSignal,\n middleware,\n debug,\n } = options\n const model = adapter.model\n const keys = assertQuestions(questions)\n const requestId = createId('evaluate')\n const startTime = Date.now()\n const logger: InternalLogger = resolveDebugOption(debug)\n\n const mwCtx = createGenerationContext({\n requestId,\n activity: 'evaluate',\n provider: adapter.name,\n model,\n modelOptions,\n createId,\n })\n\n await runGenerationStart(middleware, mwCtx)\n\n aiEventClient.emit('evaluate:request:started', {\n requestId,\n provider: adapter.name,\n model,\n questionCount: keys.length,\n timestamp: startTime,\n })\n\n logger.request(`activity=evaluate provider=${adapter.name}`, {\n provider: adapter.name,\n model,\n questionCount: keys.length,\n })\n\n try {\n const result = await adapter.evaluate({\n model,\n state,\n questions,\n modelOptions,\n abortSignal,\n logger,\n })\n\n const answers = mapAnswers(questions, result.answers)\n const duration = Date.now() - startTime\n\n aiEventClient.emit('evaluate:request:completed', {\n requestId,\n provider: adapter.name,\n model: result.model,\n questionCount: keys.length,\n duration,\n timestamp: Date.now(),\n })\n\n aiEventClient.emit('evaluate:usage', {\n requestId,\n model: result.model,\n usage: result.usage,\n timestamp: Date.now(),\n })\n\n logger.output(`activity=evaluate answers=${keys.length}`, {\n answerCount: keys.length,\n })\n\n await runGenerationUsage(middleware, mwCtx, result.usage)\n await runGenerationFinish(middleware, mwCtx, {\n duration,\n usage: result.usage,\n })\n\n return withMeta(answers, {\n model: result.model,\n usage: result.usage,\n ...(result.id !== undefined && { id: result.id }),\n ...(result.provider !== undefined && { provider: result.provider }),\n })\n } catch (error) {\n const duration = Date.now() - startTime\n if (isAbortError(error, abortSignal)) {\n await runGenerationAbort(middleware, mwCtx, {\n reason: error instanceof Error ? error.message : undefined,\n duration,\n })\n } else {\n await runGenerationError(middleware, mwCtx, { error, duration })\n }\n logger.errors('evaluate activity failed', { error, source: 'evaluate' })\n throw error\n }\n}\n\n// Re-export adapter types\nexport type {\n EvaluateAdapter,\n EvaluateAdapterConfig,\n AnyEvaluateAdapter,\n EvaluateOptions,\n EvaluateAdapterResult,\n EvaluateState,\n EvaluateInstructions,\n EvaluateJsonValue,\n WireQuestion,\n WireAnswer,\n WireChoiceQuestion,\n WireScoreQuestion,\n WireNoulQuestion,\n WireChoiceAnswer,\n WireScoreAnswer,\n WireNoulAnswer,\n} from './adapter'\nexport { BaseEvaluateAdapter } from './adapter'\n"],"mappings":"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"}
@@ -40,7 +40,7 @@ export { getChunkRunId, getChunkThreadId } from './utilities/chunk-ids.js';
40
40
  export type { WireMessage } from './utilities/ag-ui-wire.js';
41
41
  export { fileSourceFromHandle } from './activities/files/index.js';
42
42
  export type { FileHandle } from './activities/files/adapter.js';
43
- export type { AudioPart, ContentPart, ContentPartDataSource, ContentPartFileSource, SubagentHandleData, SubagentStatus, ContentPartSource, ContentPartUrlSource, CustomEvent, DocumentPart, ImagePart, MediaInputMetadata, MediaInputRole, MediaPrompt, MediaPromptPart, MessagePart, ModelMessage, PersistedArtifactActivity, PersistedArtifactRef, PersistedArtifactRole, Interrupt, RunAgentResumeItem, RunErrorEvent, RunFinishedEvent, RunFinishedOutcome, SchemaInput, StreamChunk, StructuredOutputPart, TextPart, TanStackMessageMetadata, TanStackRunMetadata, ThinkingPart, ToolCall, ToolCallPart, ToolResultPart, UIMessage, UIResourcePart, VideoPart, InferSchemaType, } from './types.js';
43
+ export type { AudioPart, ContentPart, ContentPartDataSource, ContentPartFileSource, SubagentHandleData, SubagentStatus, ContentPartSource, ContentPartUrlSource, CustomEvent, DocumentPart, ImagePart, MediaInputMetadata, MediaInputRole, MediaPrompt, MediaPromptPart, MessagePart, ModelMessage, PersistedArtifactActivity, PersistedArtifactRef, PersistedArtifactRole, Interrupt, RunAgentResumeItem, RunErrorEvent, RunFinishedEvent, RunFinishedOutcome, SchemaInput, StreamChunk, StructuredOutputPart, TextPart, TanStackMessageMetadata, TanStackRunMetadata, ThinkingPart, ToolCall, ToolCallPart, ToolResultOutcome, ToolResultPart, UIMessage, UIResourcePart, VideoPart, InferSchemaType, } from './types.js';
44
44
  export { INTERRUPT_BINDING_VERSION, canonicalizeInterruptResolutions, } from './interrupts.js';
45
45
  export { defineInterrupt, hashInterruptDefinitionSchema, INTERRUPT_PAYLOAD_METADATA_KEY, } from './interrupt-definition.js';
46
46
  export { INTERRUPT_CONTINUATION_METADATA_KEY, INTERRUPT_CONTINUATION_VERSION, genericInterruptContinuationFromDescriptor, readGenericInterruptContinuation, wrapGenericInterruptContinuation, } from './generic-interrupt-continuation.js';
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":[],"sources":["../../src/client.ts"],"sourcesContent":["import type {\n AudioGenerationOptions,\n ImageGenerationOptions,\n TTSOptions,\n TranscriptionOptions,\n VoiceGenerationOptions,\n VideoGenerationOptions,\n WorldGenerationOptions,\n LiveVideoGenerationOptions,\n} from './types'\n\nexport type GenerationKind =\n | 'image'\n | 'audio'\n | 'tts'\n | 'voice'\n | 'video'\n | 'transcription'\n | 'world'\n | 'liveVideo'\n\ntype GenerationInputByKind = {\n image: Omit<ImageGenerationOptions, 'logger' | 'model'>\n audio: Omit<AudioGenerationOptions, 'logger' | 'model'>\n tts: Omit<TTSOptions, 'logger' | 'model'>\n voice: Omit<VoiceGenerationOptions, 'logger' | 'model'>\n video: Omit<VideoGenerationOptions, 'logger' | 'model'>\n transcription: Omit<TranscriptionOptions, 'logger' | 'model'>\n world: Omit<WorldGenerationOptions, 'logger' | 'model'>\n liveVideo: Omit<LiveVideoGenerationOptions, 'logger' | 'model'>\n}\n\nexport interface GenerationParams<TKind extends GenerationKind> {\n input: GenerationInputByKind[TKind]\n forwardedProps: Record<string, unknown>\n threadId?: string\n runId?: string\n}\n\nconst generationKinds = [\n 'image',\n 'audio',\n 'tts',\n 'voice',\n 'video',\n 'transcription',\n 'world',\n 'liveVideo',\n] as const satisfies ReadonlyArray<GenerationKind>\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction hasOwnKey(value: Record<string, unknown>, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(value, key)\n}\n\nfunction isGenerationEnvelope(body: unknown): body is Record<string, unknown> {\n return (\n isRecord(body) &&\n (hasOwnKey(body, 'data') || hasOwnKey(body, 'forwardedProps'))\n )\n}\n\nfunction assertGenerationKind(kind: unknown): asserts kind is GenerationKind {\n if (!generationKinds.includes(kind as GenerationKind)) {\n throw new Error(\n `Unsupported generation kind: ${String(\n kind,\n )}. Expected one of ${generationKinds.join(', ')}.`,\n )\n }\n}\n\n/**\n * The input field(s) that identify a generation body for a kind. Most kinds\n * have exactly one; `voice` accepts either of its two creation modes, so any\n * one of its keys is enough.\n */\nfunction requiredKeysForKind(kind: GenerationKind): Array<string> {\n // Enumerated rather than defaulted so a new generation kind has to declare\n // the field that identifies its body instead of silently inheriting\n // `prompt`.\n switch (kind) {\n case 'tts':\n return ['text']\n case 'transcription':\n return ['audio']\n case 'voice':\n return ['prompt', 'referenceAudio']\n case 'image':\n case 'audio':\n case 'video':\n case 'world':\n case 'liveVideo':\n return ['prompt']\n }\n}\n\nfunction assertInputForKind(\n kind: GenerationKind,\n input: unknown,\n): asserts input is GenerationInputByKind[GenerationKind] {\n if (!isRecord(input)) {\n throw new Error(`Generation ${kind} input must be an object.`)\n }\n\n const requiredKeys = requiredKeysForKind(kind)\n\n if (!requiredKeys.some((key) => hasOwnKey(input, key))) {\n throw new Error(\n `Generation ${kind} input must include ${requiredKeys.join(' or ')}.`,\n )\n }\n}\n\nfunction isInputForKind(kind: GenerationKind, input: unknown): boolean {\n if (!isRecord(input)) return false\n\n return requiredKeysForKind(kind).some((key) => hasOwnKey(input, key))\n}\n\nfunction forwardedPropsFromEnvelope(\n envelope: Record<string, unknown>,\n): Record<string, unknown> {\n if (!hasOwnKey(envelope, 'forwardedProps')) {\n return {}\n }\n\n if (!isRecord(envelope.forwardedProps)) {\n throw new Error('Generation envelope forwardedProps must be an object.')\n }\n\n return envelope.forwardedProps\n}\n\nfunction optionalStringField(\n envelope: Record<string, unknown>,\n key: 'threadId' | 'runId',\n): string | undefined {\n if (!hasOwnKey(envelope, key)) {\n return undefined\n }\n\n const value = envelope[key]\n if (typeof value !== 'string') {\n throw new Error(`Generation envelope ${key} must be a string.`)\n }\n\n return value\n}\n\nfunction generationIdentityFields(envelope: Record<string, unknown>): {\n threadId?: string\n runId?: string\n} {\n const identity: {\n threadId?: string\n runId?: string\n } = {}\n const threadId = optionalStringField(envelope, 'threadId')\n const runId = optionalStringField(envelope, 'runId')\n\n if (threadId !== undefined) identity.threadId = threadId\n if (runId !== undefined) identity.runId = runId\n\n return identity\n}\n\nexport function generationParamsFromBody<TKind extends GenerationKind>(\n kind: TKind,\n body: unknown,\n): GenerationParams<TKind> {\n assertGenerationKind(kind)\n\n if (isInputForKind(kind, body)) {\n assertInputForKind(kind, body)\n return {\n input: body as GenerationInputByKind[TKind],\n forwardedProps: {},\n }\n }\n\n if (!isGenerationEnvelope(body)) {\n assertInputForKind(kind, body)\n return {\n input: body as GenerationInputByKind[TKind],\n forwardedProps: {},\n }\n }\n\n if (!hasOwnKey(body, 'data')) {\n throw new Error(`Generation ${kind} envelope must include data.`)\n }\n\n const input = body.data\n assertInputForKind(kind, input)\n\n const forwardedProps = forwardedPropsFromEnvelope(body)\n\n return {\n input: input as GenerationInputByKind[TKind],\n forwardedProps,\n ...generationIdentityFields(body),\n }\n}\n\nexport async function generationParamsFromRequest<TKind extends GenerationKind>(\n kind: TKind,\n request: Request,\n): Promise<GenerationParams<TKind>> {\n let body: unknown\n try {\n body = await request.json()\n } catch (error) {\n throw new Error('Invalid JSON request body.', { cause: error })\n }\n\n if (!isRecord(body)) {\n throw new Error('Generation request body must be a JSON object.')\n }\n\n return generationParamsFromBody(kind, body)\n}\n\nexport { EventType } from '@ag-ui/core'\n\nexport {\n defineAgent,\n type DefinedAgent,\n type SubagentChoiceOptions,\n type SubagentRunContext,\n} from './activities/chat/agents/define-agent'\nexport {\n subagentRoute,\n type SubagentRouteOptions,\n} from './activities/chat/agents/route'\nexport type {\n SubagentOrder,\n SubagentRouterPick,\n SubagentRouterPlan,\n SubagentStep,\n SubagentStepsPlan,\n} from './activities/chat/agents/spawn'\n\nexport {\n toolDefinition,\n type AnyClientTool,\n type ClientTool,\n type InferToolInput,\n type InferToolName,\n type InferToolOutput,\n type ApprovalCapabilityOf,\n type ApprovalSchemaConfig,\n type ApprovalSchemaOf,\n type InputSchemaOf,\n type OutputSchemaOf,\n type NoSchema,\n type ToolDefinition,\n type ToolDefinitionConfig,\n type ToolDefinitionInstance,\n} from './activities/chat/tools/tool-definition'\n\nexport {\n hashSchemaInput,\n normalizeApprovalSchema,\n type NormalizedApprovalSchema,\n type NormalizedSchemaInput,\n} from './activities/chat/tools/approval-schema'\n\nexport {\n canonicalInterruptJson,\n cloneAndDeepFreezeJson,\n digestInterruptJson,\n} from './interrupt-serialization'\n\nexport {\n convertSchemaToJsonSchema,\n isStandardSchema,\n parseWithStandardSchema,\n validateWithStandardSchema,\n} from './activities/chat/tools/schema-converter'\n\nexport {\n convertMessagesToModelMessages,\n generateMessageId,\n modelMessageToUIMessage,\n modelMessagesToUIMessages,\n normalizeToUIMessage,\n uiMessageToModelMessages,\n} from './activities/chat/messages'\n\nexport {\n BatchStrategy,\n CompositeStrategy,\n defaultJSONParser,\n ImmediateStrategy,\n parsePartialJSON,\n PartialJSONParser,\n PunctuationStrategy,\n StreamProcessor,\n WordBoundaryStrategy,\n} from './activities/chat/stream/index'\nexport type {\n ChunkRecording,\n ChunkStrategy,\n InternalToolCallState,\n JSONParser,\n ProcessorResult,\n ProcessorState,\n StreamProcessorEvents,\n StreamProcessorOptions,\n ToolCallState,\n ToolResultState,\n} from './activities/chat/stream/index'\n\nexport { uiMessagesToWire } from './utilities/ag-ui-wire'\nexport {\n mergeMetadata,\n tanstackMetadata,\n withTanstackMetadata,\n} from './utilities/merge-metadata'\nexport { fromSpecTokenUsage, toSpecTokenUsage } from './utilities/ag-ui-usage'\nexport type { SpecTokenUsage } from './utilities/ag-ui-usage'\nexport { normalizeStreamChunk } from './utilities/normalize-stream-chunk'\nexport { restoreInboundChunk } from './utilities/restore-inbound-chunk'\nexport type { AdapterYieldChunk } from './utilities/adapter-yield-chunk'\nexport { getChunkRunId, getChunkThreadId } from './utilities/chunk-ids'\nexport type { WireMessage } from './utilities/ag-ui-wire'\n\n// A browser client that received an uploaded handle from its server can build\n// the `{ type: 'file' }` content source itself — `fileSourceFromHandle` is a\n// pure object builder, so exporting it here keeps the documented client flow\n// from pulling in the server entry.\nexport { fileSourceFromHandle } from './activities/files/index'\nexport type { FileHandle } from './activities/files/adapter'\n\nexport type {\n AudioPart,\n ContentPart,\n ContentPartDataSource,\n ContentPartFileSource,\n SubagentHandleData,\n SubagentStatus,\n ContentPartSource,\n ContentPartUrlSource,\n CustomEvent,\n DocumentPart,\n ImagePart,\n MediaInputMetadata,\n MediaInputRole,\n MediaPrompt,\n MediaPromptPart,\n MessagePart,\n ModelMessage,\n PersistedArtifactActivity,\n PersistedArtifactRef,\n PersistedArtifactRole,\n Interrupt,\n RunAgentResumeItem,\n RunErrorEvent,\n RunFinishedEvent,\n RunFinishedOutcome,\n SchemaInput,\n StreamChunk,\n StructuredOutputPart,\n TextPart,\n TanStackMessageMetadata,\n TanStackRunMetadata,\n ThinkingPart,\n ToolCall,\n ToolCallPart,\n ToolResultPart,\n UIMessage,\n UIResourcePart,\n VideoPart,\n InferSchemaType,\n} from './types'\n\n// Enumerated, not `export *` — see the matching note in `index.ts`. The\n// interrupt protocol surface is a commitment, so it is published field by\n// field.\nexport {\n INTERRUPT_BINDING_VERSION,\n canonicalizeInterruptResolutions,\n} from './interrupts'\nexport {\n defineInterrupt,\n hashInterruptDefinitionSchema,\n INTERRUPT_PAYLOAD_METADATA_KEY,\n} from './interrupt-definition'\nexport {\n INTERRUPT_CONTINUATION_METADATA_KEY,\n INTERRUPT_CONTINUATION_VERSION,\n genericInterruptContinuationFromDescriptor,\n readGenericInterruptContinuation,\n wrapGenericInterruptContinuation,\n} from './generic-interrupt-continuation'\nexport type {\n GenericInterruptContinuation,\n GenericInterruptContinuationReadResult,\n} from './generic-interrupt-continuation'\nexport type {\n GenericInterruptRequest,\n InterruptDefinition,\n} from './interrupt-definition'\nexport type {\n BatchInterruptError,\n BatchInterruptErrorCode,\n InterruptBinding,\n InterruptCorrelation,\n InterruptSubmissionError,\n ItemInterruptError,\n ItemInterruptErrorCode,\n ToolApprovalResolution,\n UnopenedInterruptBinding,\n} from './interrupts'\n\nexport {\n INTERRUPT_BINDING_METADATA_KEY,\n readInterruptBinding,\n readUnopenedInterruptBinding,\n withInterruptBinding,\n withoutInterruptBinding,\n} from './interrupt-resume'\n\nexport type {\n AudioVisualization,\n RealtimeAdapter,\n RealtimeConnection,\n RealtimeError,\n RealtimeErrorCode,\n RealtimeEvent,\n RealtimeEventHandler,\n RealtimeEventPayloads,\n RealtimeMessage,\n RealtimeMessagePart,\n RealtimeMode,\n RealtimeSessionConfig,\n RealtimeStatus,\n RealtimeToken,\n RealtimeAudioPart,\n RealtimeImagePart,\n RealtimeTextPart,\n RealtimeToolCallPart,\n RealtimeToolResultPart,\n VADConfig,\n} from './realtime/types'\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":[],"sources":["../../src/client.ts"],"sourcesContent":["import type {\n AudioGenerationOptions,\n ImageGenerationOptions,\n TTSOptions,\n TranscriptionOptions,\n VoiceGenerationOptions,\n VideoGenerationOptions,\n WorldGenerationOptions,\n LiveVideoGenerationOptions,\n} from './types'\n\nexport type GenerationKind =\n | 'image'\n | 'audio'\n | 'tts'\n | 'voice'\n | 'video'\n | 'transcription'\n | 'world'\n | 'liveVideo'\n\ntype GenerationInputByKind = {\n image: Omit<ImageGenerationOptions, 'logger' | 'model'>\n audio: Omit<AudioGenerationOptions, 'logger' | 'model'>\n tts: Omit<TTSOptions, 'logger' | 'model'>\n voice: Omit<VoiceGenerationOptions, 'logger' | 'model'>\n video: Omit<VideoGenerationOptions, 'logger' | 'model'>\n transcription: Omit<TranscriptionOptions, 'logger' | 'model'>\n world: Omit<WorldGenerationOptions, 'logger' | 'model'>\n liveVideo: Omit<LiveVideoGenerationOptions, 'logger' | 'model'>\n}\n\nexport interface GenerationParams<TKind extends GenerationKind> {\n input: GenerationInputByKind[TKind]\n forwardedProps: Record<string, unknown>\n threadId?: string\n runId?: string\n}\n\nconst generationKinds = [\n 'image',\n 'audio',\n 'tts',\n 'voice',\n 'video',\n 'transcription',\n 'world',\n 'liveVideo',\n] as const satisfies ReadonlyArray<GenerationKind>\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction hasOwnKey(value: Record<string, unknown>, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(value, key)\n}\n\nfunction isGenerationEnvelope(body: unknown): body is Record<string, unknown> {\n return (\n isRecord(body) &&\n (hasOwnKey(body, 'data') || hasOwnKey(body, 'forwardedProps'))\n )\n}\n\nfunction assertGenerationKind(kind: unknown): asserts kind is GenerationKind {\n if (!generationKinds.includes(kind as GenerationKind)) {\n throw new Error(\n `Unsupported generation kind: ${String(\n kind,\n )}. Expected one of ${generationKinds.join(', ')}.`,\n )\n }\n}\n\n/**\n * The input field(s) that identify a generation body for a kind. Most kinds\n * have exactly one; `voice` accepts either of its two creation modes, so any\n * one of its keys is enough.\n */\nfunction requiredKeysForKind(kind: GenerationKind): Array<string> {\n // Enumerated rather than defaulted so a new generation kind has to declare\n // the field that identifies its body instead of silently inheriting\n // `prompt`.\n switch (kind) {\n case 'tts':\n return ['text']\n case 'transcription':\n return ['audio']\n case 'voice':\n return ['prompt', 'referenceAudio']\n case 'image':\n case 'audio':\n case 'video':\n case 'world':\n case 'liveVideo':\n return ['prompt']\n }\n}\n\nfunction assertInputForKind(\n kind: GenerationKind,\n input: unknown,\n): asserts input is GenerationInputByKind[GenerationKind] {\n if (!isRecord(input)) {\n throw new Error(`Generation ${kind} input must be an object.`)\n }\n\n const requiredKeys = requiredKeysForKind(kind)\n\n if (!requiredKeys.some((key) => hasOwnKey(input, key))) {\n throw new Error(\n `Generation ${kind} input must include ${requiredKeys.join(' or ')}.`,\n )\n }\n}\n\nfunction isInputForKind(kind: GenerationKind, input: unknown): boolean {\n if (!isRecord(input)) return false\n\n return requiredKeysForKind(kind).some((key) => hasOwnKey(input, key))\n}\n\nfunction forwardedPropsFromEnvelope(\n envelope: Record<string, unknown>,\n): Record<string, unknown> {\n if (!hasOwnKey(envelope, 'forwardedProps')) {\n return {}\n }\n\n if (!isRecord(envelope.forwardedProps)) {\n throw new Error('Generation envelope forwardedProps must be an object.')\n }\n\n return envelope.forwardedProps\n}\n\nfunction optionalStringField(\n envelope: Record<string, unknown>,\n key: 'threadId' | 'runId',\n): string | undefined {\n if (!hasOwnKey(envelope, key)) {\n return undefined\n }\n\n const value = envelope[key]\n if (typeof value !== 'string') {\n throw new Error(`Generation envelope ${key} must be a string.`)\n }\n\n return value\n}\n\nfunction generationIdentityFields(envelope: Record<string, unknown>): {\n threadId?: string\n runId?: string\n} {\n const identity: {\n threadId?: string\n runId?: string\n } = {}\n const threadId = optionalStringField(envelope, 'threadId')\n const runId = optionalStringField(envelope, 'runId')\n\n if (threadId !== undefined) identity.threadId = threadId\n if (runId !== undefined) identity.runId = runId\n\n return identity\n}\n\nexport function generationParamsFromBody<TKind extends GenerationKind>(\n kind: TKind,\n body: unknown,\n): GenerationParams<TKind> {\n assertGenerationKind(kind)\n\n if (isInputForKind(kind, body)) {\n assertInputForKind(kind, body)\n return {\n input: body as GenerationInputByKind[TKind],\n forwardedProps: {},\n }\n }\n\n if (!isGenerationEnvelope(body)) {\n assertInputForKind(kind, body)\n return {\n input: body as GenerationInputByKind[TKind],\n forwardedProps: {},\n }\n }\n\n if (!hasOwnKey(body, 'data')) {\n throw new Error(`Generation ${kind} envelope must include data.`)\n }\n\n const input = body.data\n assertInputForKind(kind, input)\n\n const forwardedProps = forwardedPropsFromEnvelope(body)\n\n return {\n input: input as GenerationInputByKind[TKind],\n forwardedProps,\n ...generationIdentityFields(body),\n }\n}\n\nexport async function generationParamsFromRequest<TKind extends GenerationKind>(\n kind: TKind,\n request: Request,\n): Promise<GenerationParams<TKind>> {\n let body: unknown\n try {\n body = await request.json()\n } catch (error) {\n throw new Error('Invalid JSON request body.', { cause: error })\n }\n\n if (!isRecord(body)) {\n throw new Error('Generation request body must be a JSON object.')\n }\n\n return generationParamsFromBody(kind, body)\n}\n\nexport { EventType } from '@ag-ui/core'\n\nexport {\n defineAgent,\n type DefinedAgent,\n type SubagentChoiceOptions,\n type SubagentRunContext,\n} from './activities/chat/agents/define-agent'\nexport {\n subagentRoute,\n type SubagentRouteOptions,\n} from './activities/chat/agents/route'\nexport type {\n SubagentOrder,\n SubagentRouterPick,\n SubagentRouterPlan,\n SubagentStep,\n SubagentStepsPlan,\n} from './activities/chat/agents/spawn'\n\nexport {\n toolDefinition,\n type AnyClientTool,\n type ClientTool,\n type InferToolInput,\n type InferToolName,\n type InferToolOutput,\n type ApprovalCapabilityOf,\n type ApprovalSchemaConfig,\n type ApprovalSchemaOf,\n type InputSchemaOf,\n type OutputSchemaOf,\n type NoSchema,\n type ToolDefinition,\n type ToolDefinitionConfig,\n type ToolDefinitionInstance,\n} from './activities/chat/tools/tool-definition'\n\nexport {\n hashSchemaInput,\n normalizeApprovalSchema,\n type NormalizedApprovalSchema,\n type NormalizedSchemaInput,\n} from './activities/chat/tools/approval-schema'\n\nexport {\n canonicalInterruptJson,\n cloneAndDeepFreezeJson,\n digestInterruptJson,\n} from './interrupt-serialization'\n\nexport {\n convertSchemaToJsonSchema,\n isStandardSchema,\n parseWithStandardSchema,\n validateWithStandardSchema,\n} from './activities/chat/tools/schema-converter'\n\nexport {\n convertMessagesToModelMessages,\n generateMessageId,\n modelMessageToUIMessage,\n modelMessagesToUIMessages,\n normalizeToUIMessage,\n uiMessageToModelMessages,\n} from './activities/chat/messages'\n\nexport {\n BatchStrategy,\n CompositeStrategy,\n defaultJSONParser,\n ImmediateStrategy,\n parsePartialJSON,\n PartialJSONParser,\n PunctuationStrategy,\n StreamProcessor,\n WordBoundaryStrategy,\n} from './activities/chat/stream/index'\nexport type {\n ChunkRecording,\n ChunkStrategy,\n InternalToolCallState,\n JSONParser,\n ProcessorResult,\n ProcessorState,\n StreamProcessorEvents,\n StreamProcessorOptions,\n ToolCallState,\n ToolResultState,\n} from './activities/chat/stream/index'\n\nexport { uiMessagesToWire } from './utilities/ag-ui-wire'\nexport {\n mergeMetadata,\n tanstackMetadata,\n withTanstackMetadata,\n} from './utilities/merge-metadata'\nexport { fromSpecTokenUsage, toSpecTokenUsage } from './utilities/ag-ui-usage'\nexport type { SpecTokenUsage } from './utilities/ag-ui-usage'\nexport { normalizeStreamChunk } from './utilities/normalize-stream-chunk'\nexport { restoreInboundChunk } from './utilities/restore-inbound-chunk'\nexport type { AdapterYieldChunk } from './utilities/adapter-yield-chunk'\nexport { getChunkRunId, getChunkThreadId } from './utilities/chunk-ids'\nexport type { WireMessage } from './utilities/ag-ui-wire'\n\n// A browser client that received an uploaded handle from its server can build\n// the `{ type: 'file' }` content source itself — `fileSourceFromHandle` is a\n// pure object builder, so exporting it here keeps the documented client flow\n// from pulling in the server entry.\nexport { fileSourceFromHandle } from './activities/files/index'\nexport type { FileHandle } from './activities/files/adapter'\n\nexport type {\n AudioPart,\n ContentPart,\n ContentPartDataSource,\n ContentPartFileSource,\n SubagentHandleData,\n SubagentStatus,\n ContentPartSource,\n ContentPartUrlSource,\n CustomEvent,\n DocumentPart,\n ImagePart,\n MediaInputMetadata,\n MediaInputRole,\n MediaPrompt,\n MediaPromptPart,\n MessagePart,\n ModelMessage,\n PersistedArtifactActivity,\n PersistedArtifactRef,\n PersistedArtifactRole,\n Interrupt,\n RunAgentResumeItem,\n RunErrorEvent,\n RunFinishedEvent,\n RunFinishedOutcome,\n SchemaInput,\n StreamChunk,\n StructuredOutputPart,\n TextPart,\n TanStackMessageMetadata,\n TanStackRunMetadata,\n ThinkingPart,\n ToolCall,\n ToolCallPart,\n ToolResultOutcome,\n ToolResultPart,\n UIMessage,\n UIResourcePart,\n VideoPart,\n InferSchemaType,\n} from './types'\n\n// Enumerated, not `export *` — see the matching note in `index.ts`. The\n// interrupt protocol surface is a commitment, so it is published field by\n// field.\nexport {\n INTERRUPT_BINDING_VERSION,\n canonicalizeInterruptResolutions,\n} from './interrupts'\nexport {\n defineInterrupt,\n hashInterruptDefinitionSchema,\n INTERRUPT_PAYLOAD_METADATA_KEY,\n} from './interrupt-definition'\nexport {\n INTERRUPT_CONTINUATION_METADATA_KEY,\n INTERRUPT_CONTINUATION_VERSION,\n genericInterruptContinuationFromDescriptor,\n readGenericInterruptContinuation,\n wrapGenericInterruptContinuation,\n} from './generic-interrupt-continuation'\nexport type {\n GenericInterruptContinuation,\n GenericInterruptContinuationReadResult,\n} from './generic-interrupt-continuation'\nexport type {\n GenericInterruptRequest,\n InterruptDefinition,\n} from './interrupt-definition'\nexport type {\n BatchInterruptError,\n BatchInterruptErrorCode,\n InterruptBinding,\n InterruptCorrelation,\n InterruptSubmissionError,\n ItemInterruptError,\n ItemInterruptErrorCode,\n ToolApprovalResolution,\n UnopenedInterruptBinding,\n} from './interrupts'\n\nexport {\n INTERRUPT_BINDING_METADATA_KEY,\n readInterruptBinding,\n readUnopenedInterruptBinding,\n withInterruptBinding,\n withoutInterruptBinding,\n} from './interrupt-resume'\n\nexport type {\n AudioVisualization,\n RealtimeAdapter,\n RealtimeConnection,\n RealtimeError,\n RealtimeErrorCode,\n RealtimeEvent,\n RealtimeEventHandler,\n RealtimeEventPayloads,\n RealtimeMessage,\n RealtimeMessagePart,\n RealtimeMode,\n RealtimeSessionConfig,\n RealtimeStatus,\n RealtimeToken,\n RealtimeAudioPart,\n RealtimeImagePart,\n RealtimeTextPart,\n RealtimeToolCallPart,\n RealtimeToolResultPart,\n VADConfig,\n} from './realtime/types'\n"],"mappings":"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"}
@@ -86,7 +86,7 @@ export { normalizeStreamChunk } from './utilities/normalize-stream-chunk.js';
86
86
  export type { AdapterYieldChunk } from './utilities/adapter-yield-chunk.js';
87
87
  export { getChunkRunId, getChunkThreadId } from './utilities/chunk-ids.js';
88
88
  export type { WireMessage } from './utilities/ag-ui-wire.js';
89
- export { isContentPart, isContentPartArray, normalizeToolResult, } from './utilities/tool-result.js';
89
+ export { isContentPart, isContentPartArray, isToolResultOutcome, normalizeToolResult, } from './utilities/tool-result.js';
90
90
  export { assertMessagesFileSourceSupport, assertPromptFileSourceSupport, fileReferenceFor, isFileSource, unsupportedFileSourceError, type FileSourceCapable, } from './utilities/content-source.js';
91
91
  export { getProviderExecutedMetadata, isProviderExecutedToolCall, } from './utilities/provider-executed.js';
92
92
  export { createModel, extendAdapter } from './extend-adapter.js';
package/dist/esm/index.js CHANGED
@@ -18,7 +18,7 @@ import { INTERRUPT_BINDING_METADATA_KEY, InterruptResumeValidationError, interru
18
18
  import { INTERRUPT_PAYLOAD_METADATA_KEY, createInterruptBinding, defineInterrupt } from "./interrupt-definition.js";
19
19
  import { INTERRUPT_CONTINUATION_METADATA_KEY, INTERRUPT_CONTINUATION_VERSION, genericInterruptContinuationFromDescriptor, readGenericInterruptContinuation, wrapGenericInterruptContinuation } from "./generic-interrupt-continuation.js";
20
20
  import { getProviderExecutedMetadata, isProviderExecutedToolCall } from "./utilities/provider-executed.js";
21
- import { isContentPart, isContentPartArray, normalizeToolResult } from "./utilities/tool-result.js";
21
+ import { isContentPart, isContentPartArray, isToolResultOutcome, normalizeToolResult } from "./utilities/tool-result.js";
22
22
  import { subagentHostMessageId, wireSubagentInfo } from "./utilities/subagent-wire.js";
23
23
  import { convertMessagesToModelMessages, generateMessageId, modelMessageToUIMessage, modelMessagesToUIMessages, normalizeToUIMessage, uiMessageToModelMessages } from "./activities/chat/messages.js";
24
24
  import { uiMessagesToWire } from "./utilities/ag-ui-wire.js";
@@ -69,4 +69,4 @@ import { BatchStrategy, CompositeStrategy, ImmediateStrategy, PunctuationStrateg
69
69
  import { StreamProcessor, createReplayStream } from "./activities/chat/stream/processor.js";
70
70
  import { generationParamsFromBody, generationParamsFromRequest } from "./client.js";
71
71
  import { createModel, extendAdapter } from "./extend-adapter.js";
72
- export { BaseEvaluateAdapter, BaseRerankAdapter, BatchStrategy, CUSTOM_EVENT, CompositeStrategy, ConsoleLogger, DISCOVERY_TOOL_NAME, DetachableRunCapability, DuplicateToolNameError, EventType, INTERRUPT_BINDING_METADATA_KEY, INTERRUPT_BINDING_VERSION, INTERRUPT_BOUNDARY_PHASES, INTERRUPT_CONTINUATION_METADATA_KEY, INTERRUPT_CONTINUATION_VERSION, INTERRUPT_PAYLOAD_METADATA_KEY, INTERRUPT_TOOL_RESUMES, ImmediateStrategy, InMemoryRunStore, InterruptResumeValidationError, MCPDuplicateToolNameError, MetadataCapability, PartialJSONParser, PunctuationStrategy, RUN_ACCEPTED_EVENT, RUN_CANCEL_REASON, RunDetachedCapability, SkillLimitError, StandardSchemaValidationError, StreamProcessor, ToolCallManager, WordBoundaryStrategy, assertMessagesFileSourceSupport, assertPromptFileSourceSupport, boolean, brandProviderTool, buildBaseUsage, canonicalInterruptJson, canonicalizeInterruptResolutions, chat, chatParamsFromRequest, chatParamsFromRequestBody, choice, cloneAndDeepFreezeJson, combineStrategies, convertMessagesToModelMessages, convertSchemaToJsonSchema, countEmbeddingInputModalities, createAudioOptions, createCapability, createChatMiddleware, createChatOptions, createEmbedOptions, createFrozenRegistry, createImageOptions, createInterruptBinding, createLiveVideoOptions, createModel, createRealtimeEventEmitter, createReplayStream, createRerankOptions, createSpeechOptions, createSummarizeOptions, createToolRegistry, createTranscriptionOptions, createVideoOptions, createVoiceOptions, createWorldOptions, decide, decodeWsFrame, defaultJSONParser, defineAgent, defineChatMiddleware, defineInterrupt, defineRunStore, deleteFile, detectImageMimeType, digestInterruptJson, embed, encodeWsFrame, extendAdapter, fileReferenceFor, fileSourceFromHandle, firstSentence, fromSpecTokenUsage, generateAudio, generateImage, generateLiveVideo, generateMessageId, generateSpeech, generateTranscription, generateVideo, generateVoice, generateWorld, generationParamsFromBody, generationParamsFromRequest, genericInterruptContinuationFromDescriptor, getChunkRunId, getChunkThreadId, getDetachableRun, getFile, getMetadata, getProviderExecutedMetadata, getRunDetached, getVideoJobStatus, hashSchemaInput, interruptItemError, isCancelRequestedReason, isContentPart, isContentPartArray, isCustomEvent, isFileSource, isProviderExecutedToolCall, isRunStatus, isStandardSchema, isTerminalRunStatus, listVoices, maxIterations, memoryStream, mergeAgentTools, mergeMetadata, modelMessageToUIMessage, modelMessagesToUIMessages, normalizeApprovalSchema, normalizeStreamChunk, normalizeSystemPrompts, normalizeToUIMessage, normalizeToolResult, parsePartialJSON, parseWithStandardSchema, provideDetachableRun, provideMetadata, provideRunDetached, readGenericInterruptContinuation, readInterruptBinding, readUnopenedInterruptBinding, realtimeToken, renderLazyCatalogEntry, replayRunStream, requestRunCancel, requireTextOnlyEmbeddingInput, rerank, resolveEmbeddingInput, resolveMediaPrompt, resolveResumeRunId, resumeHttpResponse, resumeServerSentEventsResponse, resumeWebSocketResponse, resumeWebSocketStream, score, streamToText, subagentHostMessageId, subagentRoute, summarize, toHttpResponse, toHttpStream, toServerSentEventsResponse, toServerSentEventsStream, toSpecTokenUsage, toWebSocketResponse, toWebSocketStream, toolDefinition, uiMessageToModelMessages, uiMessagesToWire, unsupportedFileSourceError, untilFinishReason, uploadFile, validateInterruptResumeBatch, validateWithStandardSchema, wasCancelRequested, wireSubagentInfo, withInterruptBinding, withTanstackMetadata, withoutInterruptBinding, wrapGenericInterruptContinuation };
72
+ export { BaseEvaluateAdapter, BaseRerankAdapter, BatchStrategy, CUSTOM_EVENT, CompositeStrategy, ConsoleLogger, DISCOVERY_TOOL_NAME, DetachableRunCapability, DuplicateToolNameError, EventType, INTERRUPT_BINDING_METADATA_KEY, INTERRUPT_BINDING_VERSION, INTERRUPT_BOUNDARY_PHASES, INTERRUPT_CONTINUATION_METADATA_KEY, INTERRUPT_CONTINUATION_VERSION, INTERRUPT_PAYLOAD_METADATA_KEY, INTERRUPT_TOOL_RESUMES, ImmediateStrategy, InMemoryRunStore, InterruptResumeValidationError, MCPDuplicateToolNameError, MetadataCapability, PartialJSONParser, PunctuationStrategy, RUN_ACCEPTED_EVENT, RUN_CANCEL_REASON, RunDetachedCapability, SkillLimitError, StandardSchemaValidationError, StreamProcessor, ToolCallManager, WordBoundaryStrategy, assertMessagesFileSourceSupport, assertPromptFileSourceSupport, boolean, brandProviderTool, buildBaseUsage, canonicalInterruptJson, canonicalizeInterruptResolutions, chat, chatParamsFromRequest, chatParamsFromRequestBody, choice, cloneAndDeepFreezeJson, combineStrategies, convertMessagesToModelMessages, convertSchemaToJsonSchema, countEmbeddingInputModalities, createAudioOptions, createCapability, createChatMiddleware, createChatOptions, createEmbedOptions, createFrozenRegistry, createImageOptions, createInterruptBinding, createLiveVideoOptions, createModel, createRealtimeEventEmitter, createReplayStream, createRerankOptions, createSpeechOptions, createSummarizeOptions, createToolRegistry, createTranscriptionOptions, createVideoOptions, createVoiceOptions, createWorldOptions, decide, decodeWsFrame, defaultJSONParser, defineAgent, defineChatMiddleware, defineInterrupt, defineRunStore, deleteFile, detectImageMimeType, digestInterruptJson, embed, encodeWsFrame, extendAdapter, fileReferenceFor, fileSourceFromHandle, firstSentence, fromSpecTokenUsage, generateAudio, generateImage, generateLiveVideo, generateMessageId, generateSpeech, generateTranscription, generateVideo, generateVoice, generateWorld, generationParamsFromBody, generationParamsFromRequest, genericInterruptContinuationFromDescriptor, getChunkRunId, getChunkThreadId, getDetachableRun, getFile, getMetadata, getProviderExecutedMetadata, getRunDetached, getVideoJobStatus, hashSchemaInput, interruptItemError, isCancelRequestedReason, isContentPart, isContentPartArray, isCustomEvent, isFileSource, isProviderExecutedToolCall, isRunStatus, isStandardSchema, isTerminalRunStatus, isToolResultOutcome, listVoices, maxIterations, memoryStream, mergeAgentTools, mergeMetadata, modelMessageToUIMessage, modelMessagesToUIMessages, normalizeApprovalSchema, normalizeStreamChunk, normalizeSystemPrompts, normalizeToUIMessage, normalizeToolResult, parsePartialJSON, parseWithStandardSchema, provideDetachableRun, provideMetadata, provideRunDetached, readGenericInterruptContinuation, readInterruptBinding, readUnopenedInterruptBinding, realtimeToken, renderLazyCatalogEntry, replayRunStream, requestRunCancel, requireTextOnlyEmbeddingInput, rerank, resolveEmbeddingInput, resolveMediaPrompt, resolveResumeRunId, resumeHttpResponse, resumeServerSentEventsResponse, resumeWebSocketResponse, resumeWebSocketStream, score, streamToText, subagentHostMessageId, subagentRoute, summarize, toHttpResponse, toHttpStream, toServerSentEventsResponse, toServerSentEventsStream, toSpecTokenUsage, toWebSocketResponse, toWebSocketStream, toolDefinition, uiMessageToModelMessages, uiMessagesToWire, unsupportedFileSourceError, untilFinishReason, uploadFile, validateInterruptResumeBatch, validateWithStandardSchema, wasCancelRequested, wireSubagentInfo, withInterruptBinding, withTanstackMetadata, withoutInterruptBinding, wrapGenericInterruptContinuation };
@@ -1,3 +1,4 @@
1
+ import { tanstackMetadata } from "./utilities/merge-metadata.js";
1
2
  import { canonicalInterruptJson, digestInterruptJson } from "./interrupt-serialization.js";
2
3
  import { canonicalizeInterruptResolutions } from "./interrupts.js";
3
4
  import { isStandardSchema, validateWithStandardSchema } from "./activities/chat/tools/schema-converter.js";
@@ -29,6 +30,20 @@ function objectValue(value) {
29
30
  function stringField(value, key) {
30
31
  return typeof value[key] === "string" ? value[key] : void 0;
31
32
  }
33
+ function clientToolResult(entry) {
34
+ if (tanstackMetadata(entry)?.state === "output-error") {
35
+ const result = objectValue(entry.payload);
36
+ if (!result || Object.keys(result).length !== 1 || typeof result.error !== "string") return null;
37
+ return {
38
+ state: "output-error",
39
+ errorText: result.error
40
+ };
41
+ }
42
+ return {
43
+ state: "output-available",
44
+ output: entry.payload
45
+ };
46
+ }
32
47
  function normalizeIssuePath(path) {
33
48
  if (!path) return void 0;
34
49
  return path.map((segment) => {
@@ -203,7 +218,12 @@ async function validateInterruptResumeBatch(input) {
203
218
  }
204
219
  if (schemaDrifted) continue;
205
220
  if (binding.kind === "client-tool-execution") {
206
- if (responseSchema !== void 0) await pushSchemaIssues({
221
+ const result = clientToolResult(entry);
222
+ if (!result) {
223
+ errors.push(interruptItemError(input, record.interruptId, "invalid-tool-output", `Tool ${binding.toolName} result is invalid.`));
224
+ continue;
225
+ }
226
+ if (result.state === "output-available" && responseSchema !== void 0) await pushSchemaIssues({
207
227
  request: input,
208
228
  errors,
209
229
  interruptId: record.interruptId,
@@ -212,12 +232,12 @@ async function validateInterruptResumeBatch(input) {
212
232
  code: "invalid-tool-output",
213
233
  label: `Tool ${binding.toolName} output is invalid`
214
234
  });
215
- if (tool.outputSchema !== void 0) await pushSchemaIssues({
235
+ if (result.state === "output-available" && tool.outputSchema !== void 0) await pushSchemaIssues({
216
236
  request: input,
217
237
  errors,
218
238
  interruptId: record.interruptId,
219
239
  schema: tool.outputSchema,
220
- value: entry.payload,
240
+ value: result.output,
221
241
  code: "invalid-tool-output",
222
242
  label: `Tool ${binding.toolName} output is invalid`
223
243
  });
@@ -298,6 +318,7 @@ async function validateInterruptResumeBatch(input) {
298
318
  const canonical = canonicalizeInterruptResolutions(input.resume ?? []);
299
319
  const approvals = /* @__PURE__ */ new Map();
300
320
  const clientToolResults = /* @__PURE__ */ new Map();
321
+ const clientToolErrors = /* @__PURE__ */ new Map();
301
322
  const genericInterrupts = /* @__PURE__ */ new Map();
302
323
  const deniedToolResults = /* @__PURE__ */ new Map();
303
324
  const cancelledToolCallIds = /* @__PURE__ */ new Set();
@@ -335,7 +356,10 @@ async function validateInterruptResumeBatch(input) {
335
356
  continue;
336
357
  }
337
358
  if (binding.kind === "client-tool-execution") {
338
- clientToolResults.set(binding.toolCallId, entry.payload);
359
+ const result = clientToolResult(entry);
360
+ if (!result) continue;
361
+ if (result.state === "output-error") clientToolErrors.set(binding.toolCallId, result.errorText);
362
+ else clientToolResults.set(binding.toolCallId, result.output);
339
363
  continue;
340
364
  }
341
365
  const envelope = objectValue(entry.payload);
@@ -358,6 +382,7 @@ async function validateInterruptResumeBatch(input) {
358
382
  resumeToolState: {
359
383
  approvals,
360
384
  clientToolResults,
385
+ clientToolErrors,
361
386
  genericInterrupts,
362
387
  deniedToolResults,
363
388
  cancelledToolCallIds
@@ -1 +1 @@
1
- {"version":3,"file":"interrupt-resume.js","names":[],"sources":["../../src/interrupt-resume.ts"],"sourcesContent":["import {\n INTERRUPT_BINDING_VERSION,\n canonicalizeInterruptResolutions,\n} from './interrupts'\nimport {\n canonicalInterruptJson,\n digestInterruptJson,\n} from './interrupt-serialization'\nimport {\n hashSchemaInput,\n normalizeApprovalSchema,\n} from './activities/chat/tools/approval-schema'\nimport {\n isStandardSchema,\n validateWithStandardSchema,\n} from './activities/chat/tools/schema-converter'\nimport type {\n InterruptBinding,\n InterruptSubmissionError,\n ItemInterruptErrorCode,\n ToolApprovalResolution,\n UnopenedInterruptBinding,\n} from './interrupts'\nimport type {\n ChatMiddlewareConfig,\n ChatResumeToolState,\n} from './activities/chat/middleware/types'\nimport type {\n GenericInterruptRequest,\n InterruptDefinition,\n} from './interrupt-definition'\nimport type { Interrupt, RunAgentResumeItem } from './types'\n\n/**\n * The `Interrupt.metadata` key under which this package's resume binding\n * travels.\n *\n * Exported so anything that produces an interrupt this package must later\n * resume — an application middleware raising a generic pause, a future\n * workflow-to-AG-UI projection — attaches the binding through\n * {@link withInterruptBinding} rather than copying the string. Everything\n * outside this key is the plain AG-UI envelope and is left untouched.\n */\nexport const INTERRUPT_BINDING_METADATA_KEY = 'tanstack:interruptBinding'\n\nconst interruptBindingMetadataKey = INTERRUPT_BINDING_METADATA_KEY\n\n/** The persistence-neutral shape required to validate an interrupt resume. */\nexport interface PendingInterruptResumeRecord {\n interruptId: string\n payload: unknown\n binding: InterruptBinding\n /** Present for a first-party generic interrupt. */\n genericRequest?: GenericInterruptRequest<\n InterruptDefinition<any, any, any, any>\n >\n}\n\nexport interface ValidateInterruptResumeBatchInput {\n threadId: string\n interruptedRunId: string\n generation: number\n pending: ReadonlyArray<PendingInterruptResumeRecord>\n resume?: ReadonlyArray<RunAgentResumeItem>\n tools: ChatMiddlewareConfig['tools']\n now?: number\n}\n\nexport interface ValidatedInterruptResumeBatch {\n errors: ReadonlyArray<InterruptSubmissionError>\n resolutions?: ReadonlyArray<RunAgentResumeItem>\n canonicalResolutions?: string\n fingerprint?: string\n resumeToolState?: ChatResumeToolState\n}\n\nexport class InterruptResumeValidationError extends Error {\n override readonly name = 'InterruptResumeValidationError'\n\n constructor(readonly errors: ReadonlyArray<InterruptSubmissionError>) {\n super(errors.map((error) => error.message).join(' '))\n }\n}\n\nfunction objectValue(value: unknown): Record<string, unknown> | null {\n return value && typeof value === 'object'\n ? (value as Record<string, unknown>)\n : null\n}\n\nfunction stringField(\n value: Record<string, unknown>,\n key: string,\n): string | undefined {\n return typeof value[key] === 'string' ? value[key] : undefined\n}\n\nfunction normalizeIssuePath(\n path: ReadonlyArray<unknown> | undefined,\n): ReadonlyArray<string | number> | undefined {\n if (!path) return undefined\n return path.map((segment) => {\n if (typeof segment === 'string' || typeof segment === 'number') {\n return segment\n }\n const record = objectValue(segment)\n const key = record?.key\n return typeof key === 'number' ? key : String(key ?? segment)\n })\n}\n\nexport function interruptItemError(\n input: Pick<\n ValidateInterruptResumeBatchInput,\n 'threadId' | 'interruptedRunId' | 'generation'\n >,\n interruptId: string,\n code: ItemInterruptErrorCode,\n message: string,\n options?: {\n path?: ReadonlyArray<string | number>\n source?: 'client' | 'server'\n retryable?: boolean\n },\n): InterruptSubmissionError {\n return {\n scope: 'item',\n threadId: input.threadId,\n interruptedRunId: input.interruptedRunId,\n generation: input.generation,\n interruptId,\n code,\n message,\n source: options?.source ?? 'client',\n retryable: options?.retryable ?? false,\n ...(options?.path ? { path: options.path } : {}),\n }\n}\n\nasync function validateSchemaValue(input: {\n schema: unknown\n value: unknown\n onIssue: (message: string, path?: ReadonlyArray<string | number>) => void\n}): Promise<void> {\n if (isStandardSchema(input.schema)) {\n const result = await validateWithStandardSchema<unknown>(\n input.schema,\n input.value,\n )\n if (!result.success) {\n for (const issue of result.issues) {\n input.onIssue(issue.message, normalizeIssuePath(issue.path))\n }\n }\n return\n }\n\n // A non-Standard-Schema value (a raw JSON Schema, e.g. a generic interrupt's\n // wire responseSchema) is not validated by the library. The application\n // validates the resume value itself if it needs to; otherwise it flows\n // through as-is.\n}\n\ntype RuntimeTool = ChatMiddlewareConfig['tools'][number] & {\n approvalSchema?: Parameters<typeof normalizeApprovalSchema>[0]\n}\n\nfunction runtimeTool(\n tools: ChatMiddlewareConfig['tools'],\n name: string,\n): RuntimeTool | undefined {\n return tools.find((tool) => tool.name === name) as RuntimeTool | undefined\n}\n\nasync function parseSchemaValue(\n schema: unknown,\n value: unknown,\n): Promise<{ success: true; data: unknown } | { success: false }> {\n if (!isStandardSchema(schema)) return { success: true, data: value }\n const result = await validateWithStandardSchema<unknown>(schema, value)\n return result.success\n ? { success: true, data: result.data }\n : { success: false }\n}\n\nfunction descriptorResponseSchema(\n record: PendingInterruptResumeRecord,\n): unknown {\n return objectValue(record.payload)?.responseSchema\n}\n\nfunction schemaHash(schema: unknown): string {\n return digestInterruptJson(canonicalInterruptJson(schema))\n}\n\nasync function pushSchemaIssues(input: {\n request: ValidateInterruptResumeBatchInput\n errors: Array<InterruptSubmissionError>\n interruptId: string\n schema: unknown\n value: unknown\n code: ItemInterruptErrorCode\n label: string\n}): Promise<void> {\n try {\n await validateSchemaValue({\n schema: input.schema,\n value: input.value,\n onIssue: (message, path) => {\n input.errors.push(\n interruptItemError(\n input.request,\n input.interruptId,\n input.code,\n `${input.label}: ${message}`,\n { path },\n ),\n )\n },\n })\n } catch (error) {\n input.errors.push(\n interruptItemError(\n input.request,\n input.interruptId,\n 'invalid-response-schema',\n `${input.label} could not be validated: ${error instanceof Error ? error.message : String(error)}`,\n { source: 'server' },\n ),\n )\n }\n}\n\nfunction validateDescriptorSchema(\n input: ValidateInterruptResumeBatchInput,\n record: PendingInterruptResumeRecord,\n binding: InterruptBinding,\n errors: Array<InterruptSubmissionError>,\n): unknown {\n const schema = descriptorResponseSchema(record)\n const responseSchemaHash = binding.responseSchemaHash\n if (schema === undefined && responseSchemaHash === undefined) {\n return undefined\n }\n if (\n schema === undefined ||\n responseSchemaHash === undefined ||\n schemaHash(schema) !== responseSchemaHash\n ) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-response-schema',\n `Interrupt ${record.interruptId} response schema no longer matches its binding.`,\n { source: 'server' },\n ),\n )\n }\n return schema\n}\n\n/**\n * Validate and translate a complete interrupt batch before any tool executes.\n * Used by ephemeral chat resume; a durable layer may share the same validator.\n */\nexport async function validateInterruptResumeBatch(\n input: ValidateInterruptResumeBatchInput,\n): Promise<ValidatedInterruptResumeBatch> {\n const grouped = new Map<string, Array<InterruptSubmissionError>>()\n const batchErrors: Array<InterruptSubmissionError> = []\n const group = (interruptId: string): Array<InterruptSubmissionError> => {\n const existing = grouped.get(interruptId)\n if (existing) return existing\n const created: Array<InterruptSubmissionError> = []\n grouped.set(interruptId, created)\n return created\n }\n const pendingById = new Map(\n input.pending.map((record) => [record.interruptId, record]),\n )\n const resumeById = new Map<string, RunAgentResumeItem>()\n const counts = new Map<string, number>()\n for (const entry of input.resume ?? []) {\n counts.set(entry.interruptId, (counts.get(entry.interruptId) ?? 0) + 1)\n if (!resumeById.has(entry.interruptId))\n resumeById.set(entry.interruptId, entry)\n }\n\n for (const [interruptId, count] of counts) {\n if (count > 1) {\n group(interruptId).push(\n interruptItemError(\n input,\n interruptId,\n 'conflict',\n `Interrupt ${interruptId} has duplicate resume entries.`,\n ),\n )\n }\n }\n\n const pendingGenerics = input.pending.filter(\n (record) => record.binding.kind === 'generic',\n )\n const genericBatchSatisfied =\n pendingGenerics.length > 0 &&\n pendingGenerics.every((record) => resumeById.has(record.interruptId))\n\n let incomplete = false\n for (const record of input.pending) {\n const errors = group(record.interruptId)\n const entry = resumeById.get(record.interruptId)\n const binding = record.binding\n if (!entry) {\n // Client tools that share a generic interrupt batch wait for\n // `toolResume`. `continue` re-emits them; `cancel` / `stop` skip them.\n if (genericBatchSatisfied && binding.kind === 'client-tool-execution') {\n continue\n }\n incomplete = true\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'unknown-interrupt',\n `Missing resume entry for interrupt ${record.interruptId}.`,\n ),\n )\n }\n if (\n binding.interruptedRunId !== input.interruptedRunId ||\n binding.generation !== input.generation ||\n binding.interruptId !== record.interruptId\n ) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'stale',\n `Interrupt ${record.interruptId} has stale correlation metadata.`,\n { source: 'server' },\n ),\n )\n }\n if (binding.expiresAt !== undefined) {\n const expiresAt = Date.parse(binding.expiresAt)\n if (!Number.isFinite(expiresAt)) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Interrupt ${record.interruptId} has an invalid expiresAt.`,\n { source: 'server' },\n ),\n )\n } else if (expiresAt <= (input.now ?? Date.now())) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'expired',\n `Interrupt ${record.interruptId} has expired.`,\n { source: 'server' },\n ),\n )\n }\n }\n\n const responseSchema = validateDescriptorSchema(\n input,\n record,\n binding,\n errors,\n )\n if (!entry) continue\n const entryStatus: unknown = entry.status\n if (entryStatus !== 'resolved' && entryStatus !== 'cancelled') {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Interrupt ${record.interruptId} has invalid status ${String(entryStatus)}.`,\n ),\n )\n continue\n }\n if (binding.kind === 'generic') {\n const genericRequest = record.genericRequest\n if (genericRequest !== undefined) {\n const batchIndex = binding.batchIndex\n if (\n binding.definitionId !== genericRequest.definition.id ||\n binding.key !== genericRequest.key ||\n binding.interruptId !== record.interruptId ||\n batchIndex === undefined ||\n !Number.isInteger(batchIndex) ||\n batchIndex < 0\n ) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'stale',\n `Generic interrupt ${record.interruptId} has stale definition metadata.`,\n { source: 'server' },\n ),\n )\n }\n }\n if (entry.status === 'cancelled') {\n if (entry.payload !== undefined) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Cancelled interrupt ${record.interruptId} must not include a payload.`,\n ),\n )\n }\n } else if (genericRequest !== undefined) {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: genericRequest.definition.responseSchema,\n value: entry.payload,\n code: 'invalid-payload',\n label: `Interrupt ${record.interruptId} payload is invalid`,\n })\n } else if (responseSchema !== undefined) {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: responseSchema,\n value: entry.payload,\n code: 'invalid-payload',\n label: `Interrupt ${record.interruptId} payload is invalid`,\n })\n }\n continue\n }\n\n if (entry.status === 'cancelled') {\n if (entry.payload !== undefined) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Cancelled interrupt ${record.interruptId} must not include a payload.`,\n ),\n )\n }\n continue\n }\n\n const tool = runtimeTool(input.tools, binding.toolName)\n if (!tool) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'stale',\n `Tool ${binding.toolName} is unavailable for interrupt ${record.interruptId}.`,\n { source: 'server' },\n ),\n )\n continue\n }\n\n let approval: ReturnType<typeof normalizeApprovalSchema> | undefined\n let schemaDrifted = false\n if (binding.kind === 'client-tool-execution') {\n if (hashSchemaInput(tool.outputSchema) !== binding.outputSchemaHash) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'stale',\n `Tool ${binding.toolName} output schema has changed.`,\n { source: 'server' },\n ),\n )\n schemaDrifted = true\n }\n } else {\n try {\n approval = normalizeApprovalSchema(\n tool.approvalSchema,\n tool.inputSchema,\n )\n } catch {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'stale',\n `Tool ${binding.toolName} approval schema is unavailable.`,\n { source: 'server' },\n ),\n )\n schemaDrifted = true\n }\n if (\n approval !== undefined &&\n (hashSchemaInput(tool.inputSchema) !== binding.inputSchemaHash ||\n approval.approvalSchemaHash !== binding.approvalSchemaHash ||\n approval.responseSchemaHash !== binding.responseSchemaHash)\n ) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'stale',\n `Tool ${binding.toolName} approval schema has changed.`,\n { source: 'server' },\n ),\n )\n schemaDrifted = true\n }\n }\n\n if (schemaDrifted) continue\n\n if (binding.kind === 'client-tool-execution') {\n if (responseSchema !== undefined) {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: responseSchema,\n value: entry.payload,\n code: 'invalid-tool-output',\n label: `Tool ${binding.toolName} output is invalid`,\n })\n }\n if (tool.outputSchema !== undefined) {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: tool.outputSchema,\n value: entry.payload,\n code: 'invalid-tool-output',\n label: `Tool ${binding.toolName} output is invalid`,\n })\n }\n continue\n }\n\n if (approval === undefined) continue\n const envelope = objectValue(entry.payload)\n const approved =\n typeof entry.payload === 'boolean'\n ? entry.payload\n : typeof envelope?.approved === 'boolean'\n ? envelope.approved\n : undefined\n if (approved === undefined) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Approval ${record.interruptId} must be a boolean or decision envelope.`,\n ),\n )\n continue\n }\n if (envelope) {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: approval.responseSchema,\n value: entry.payload,\n code: 'invalid-payload',\n label: `Approval ${record.interruptId} envelope is invalid`,\n })\n }\n if (approved && envelope?.editedArgs !== undefined) {\n if (tool.inputSchema === undefined) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-edited-args',\n `Approval ${record.interruptId} cannot edit arguments without an input schema.`,\n ),\n )\n } else {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: tool.inputSchema,\n value: envelope.editedArgs,\n code: 'invalid-edited-args',\n label: `Approval ${record.interruptId} edited arguments are invalid`,\n })\n }\n }\n const branch = approved\n ? approval.branches.approve\n : approval.branches.reject\n if (branch) {\n if (!envelope) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Approval ${record.interruptId} requires a payload for the ${approved ? 'approve' : 'reject'} decision.`,\n ),\n )\n } else {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: branch.source,\n value: envelope.payload,\n code: 'invalid-payload',\n label: `Approval ${record.interruptId} payload is invalid`,\n })\n }\n }\n }\n\n for (const entry of input.resume ?? []) {\n if (!pendingById.has(entry.interruptId)) {\n incomplete = true\n group(entry.interruptId).push(\n interruptItemError(\n input,\n entry.interruptId,\n 'unknown-interrupt',\n `Resume entry references unknown interrupt ${entry.interruptId}.`,\n ),\n )\n }\n }\n\n if (incomplete) {\n batchErrors.push({\n scope: 'batch',\n threadId: input.threadId,\n interruptedRunId: input.interruptedRunId,\n generation: input.generation,\n code: 'incomplete-batch',\n message:\n 'Resume entries must resolve or cancel the complete interrupt batch.',\n source: 'client',\n retryable: false,\n interruptIds: input.pending.map((record) => record.interruptId),\n })\n }\n\n const itemErrors = [...grouped.entries()]\n .sort(([left], [right]) => left.localeCompare(right))\n .flatMap(([, errors]) => errors)\n if (itemErrors.length > 0) {\n batchErrors.push({\n scope: 'batch',\n threadId: input.threadId,\n interruptedRunId: input.interruptedRunId,\n generation: input.generation,\n code: 'item-validation-failed',\n message: 'One or more interrupt resolutions are invalid.',\n source: 'client',\n retryable: false,\n interruptIds: input.pending.map((record) => record.interruptId),\n })\n return { errors: [...itemErrors, ...batchErrors] }\n }\n\n const canonical = canonicalizeInterruptResolutions(input.resume ?? [])\n const approvals = new Map<string, ToolApprovalResolution>()\n const clientToolResults = new Map<string, unknown>()\n const genericInterrupts = new Map<\n string,\n | { interruptId: string; status: 'resolved'; payload: unknown }\n | { interruptId: string; status: 'cancelled' }\n >()\n const deniedToolResults = new Map<string, unknown>()\n const cancelledToolCallIds = new Set<string>()\n\n for (const record of input.pending) {\n const entry = resumeById.get(record.interruptId)\n if (!entry) continue\n const binding = record.binding\n if (binding.kind === 'generic') {\n if (entry.status !== 'resolved') {\n genericInterrupts.set(record.interruptId, {\n interruptId: record.interruptId,\n status: 'cancelled',\n })\n continue\n }\n if (record.genericRequest === undefined) {\n genericInterrupts.set(record.interruptId, {\n interruptId: record.interruptId,\n status: 'resolved',\n payload: entry.payload,\n })\n continue\n }\n const parsed = await parseSchemaValue(\n record.genericRequest.definition.responseSchema,\n entry.payload,\n )\n if (!parsed.success) {\n return {\n errors: [\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Interrupt ${record.interruptId} payload is invalid.`,\n ),\n ],\n }\n }\n genericInterrupts.set(record.interruptId, {\n interruptId: record.interruptId,\n status: 'resolved',\n payload: parsed.data,\n })\n continue\n }\n if (entry.status === 'cancelled') {\n cancelledToolCallIds.add(binding.toolCallId)\n continue\n }\n if (binding.kind === 'client-tool-execution') {\n clientToolResults.set(binding.toolCallId, entry.payload)\n continue\n }\n const envelope = objectValue(entry.payload)\n const resolution: ToolApprovalResolution =\n typeof entry.payload === 'boolean'\n ? entry.payload\n : envelope?.approved === true\n ? {\n approved: true,\n ...(envelope.editedArgs !== undefined\n ? { editedArgs: envelope.editedArgs }\n : {}),\n ...(envelope.payload !== undefined\n ? { payload: envelope.payload }\n : {}),\n }\n : {\n approved: false,\n ...(envelope?.payload !== undefined\n ? { payload: envelope.payload }\n : {}),\n }\n approvals.set(binding.toolCallId, resolution)\n if (\n resolution === false ||\n (typeof resolution === 'object' && !resolution.approved)\n ) {\n deniedToolResults.set(\n binding.toolCallId,\n typeof resolution === 'object' ? resolution.payload : undefined,\n )\n }\n }\n\n return {\n errors: [],\n resolutions: canonical.resolutions,\n canonicalResolutions: canonical.canonicalResolutions,\n fingerprint: canonical.fingerprint,\n resumeToolState: {\n approvals,\n clientToolResults,\n genericInterrupts,\n deniedToolResults,\n cancelledToolCallIds,\n },\n }\n}\n\n/**\n * Is this a binding written by a version of the protocol we understand?\n *\n * A missing `v` is read as {@link INTERRUPT_BINDING_VERSION} so bindings\n * written before the field existed still resume. A `v` we don't recognise is\n * rejected outright — a newer or foreign producer's binding must not be\n * duck-typed into ours.\n */\nfunction isSupportedBindingVersion(raw: Record<string, unknown>): boolean {\n const version = raw['v']\n if (version === undefined) return true\n return version === INTERRUPT_BINDING_VERSION\n}\n\nexport function readUnopenedInterruptBinding(\n descriptor: Interrupt,\n): UnopenedInterruptBinding | undefined {\n const metadata = objectValue(descriptor.metadata)\n const raw = metadata\n ? objectValue(metadata[interruptBindingMetadataKey])\n : null\n if (!raw || stringField(raw, 'interruptId') !== descriptor.id)\n return undefined\n if (!isSupportedBindingVersion(raw)) return undefined\n const kind = stringField(raw, 'kind')\n const interruptId = stringField(raw, 'interruptId')\n const responseSchemaHash = stringField(raw, 'responseSchemaHash')\n const expiresAt = stringField(raw, 'expiresAt')\n if (!interruptId || responseSchemaHash === '') return undefined\n if (expiresAt !== undefined && !Number.isFinite(Date.parse(expiresAt))) {\n return undefined\n }\n const v = INTERRUPT_BINDING_VERSION\n if (kind === 'generic') {\n const definitionId = stringField(raw, 'definitionId')\n const key = stringField(raw, 'key')\n const batchIndex = raw['batchIndex']\n const payloadSchemaHash = stringField(raw, 'payloadSchemaHash')\n const hasFirstPartyFields =\n definitionId !== undefined ||\n key !== undefined ||\n batchIndex !== undefined ||\n payloadSchemaHash !== undefined\n if (\n hasFirstPartyFields &&\n (!definitionId ||\n !key ||\n typeof batchIndex !== 'number' ||\n !Number.isInteger(batchIndex) ||\n batchIndex < 0)\n ) {\n return undefined\n }\n return {\n v,\n kind,\n interruptId,\n ...(responseSchemaHash ? { responseSchemaHash } : {}),\n ...(expiresAt ? { expiresAt } : {}),\n ...(definitionId ? { definitionId } : {}),\n ...(key ? { key } : {}),\n ...(typeof batchIndex === 'number' ? { batchIndex } : {}),\n ...(payloadSchemaHash ? { payloadSchemaHash } : {}),\n }\n }\n if (!responseSchemaHash) return undefined\n const toolName = stringField(raw, 'toolName')\n const toolCallId = stringField(raw, 'toolCallId')\n if (!toolName || !toolCallId) return undefined\n if (kind === 'client-tool-execution') {\n const outputSchemaHash = stringField(raw, 'outputSchemaHash')\n if (!outputSchemaHash) return undefined\n return {\n v,\n kind,\n interruptId,\n toolName,\n toolCallId,\n outputSchemaHash,\n responseSchemaHash,\n ...(expiresAt ? { expiresAt } : {}),\n }\n }\n if (kind === 'tool-approval') {\n const inputSchemaHash = stringField(raw, 'inputSchemaHash')\n const approvalSchemaHash = stringField(raw, 'approvalSchemaHash')\n if (!inputSchemaHash || !approvalSchemaHash) return undefined\n return {\n v,\n kind,\n interruptId,\n toolName,\n toolCallId,\n originalArgs: raw.originalArgs,\n inputSchemaHash,\n approvalSchemaHash,\n responseSchemaHash,\n ...(expiresAt ? { expiresAt } : {}),\n }\n }\n return undefined\n}\n\n/**\n * Attach a resume binding to an interrupt descriptor, under\n * {@link INTERRUPT_BINDING_METADATA_KEY}.\n *\n * This is the supported way to make an interrupt resumable by this package.\n * The descriptor keeps its AG-UI shape; only `metadata` gains the namespaced\n * key. Pass the unopened form (no `interruptedRunId` / `generation`) when\n * emitting from inside a run — those fields are stamped as the run finishes.\n */\nexport function withInterruptBinding(\n descriptor: Interrupt,\n binding: UnopenedInterruptBinding | InterruptBinding,\n): Interrupt {\n return {\n ...descriptor,\n metadata: {\n ...descriptor.metadata,\n [interruptBindingMetadataKey]: {\n ...binding,\n v: INTERRUPT_BINDING_VERSION,\n interruptId: descriptor.id,\n },\n },\n }\n}\n\n/**\n * Read the opened resume binding off a descriptor, or `undefined` when the\n * descriptor carries no binding of a version we understand.\n *\n * `undefined` means \"this interrupt is not ours to resume\" — it is not a\n * failure to recover from by inventing a binding.\n */\nexport function readInterruptBinding(\n descriptor: Interrupt,\n): InterruptBinding | undefined {\n const unopened = readUnopenedInterruptBinding(descriptor)\n if (!unopened) return undefined\n const metadata = objectValue(descriptor.metadata)\n const raw = metadata\n ? objectValue(metadata[interruptBindingMetadataKey])\n : null\n if (!raw) return undefined\n const interruptedRunId = stringField(raw, 'interruptedRunId')\n const generation = raw['generation']\n if (\n !interruptedRunId ||\n typeof generation !== 'number' ||\n !Number.isInteger(generation) ||\n generation < 0\n ) {\n return undefined\n }\n return { ...unopened, interruptedRunId, generation }\n}\n\nexport function withoutInterruptBinding(descriptor: Interrupt): Interrupt {\n const metadata = objectValue(descriptor.metadata)\n if (!metadata || !(interruptBindingMetadataKey in metadata)) return descriptor\n const publicMetadata = { ...metadata }\n delete publicMetadata[interruptBindingMetadataKey]\n return { ...descriptor, metadata: publicMetadata }\n}\n"],"mappings":";;;;;;;;;;;;;;;AA2CA,IAAa,iCAAiC;AAE9C,IAAM,8BAA8B;AA+BpC,IAAa,iCAAb,cAAoD,MAAM;CAGnC;CAFrB,OAAyB;CAEzB,YAAY,QAA0D;EACpE,MAAM,OAAO,KAAK,UAAU,MAAM,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC;EADjC,KAAA,SAAA;CAErB;AACF;AAEA,SAAS,YAAY,OAAgD;CACnE,OAAO,SAAS,OAAO,UAAU,WAC5B,QACD;AACN;AAEA,SAAS,YACP,OACA,KACoB;CACpB,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO,KAAA;AACvD;AAEA,SAAS,mBACP,MAC4C;CAC5C,IAAI,CAAC,MAAM,OAAO,KAAA;CAClB,OAAO,KAAK,KAAK,YAAY;EAC3B,IAAI,OAAO,YAAY,YAAY,OAAO,YAAY,UACpD,OAAO;EAGT,MAAM,MADS,YAAY,OACf,CAAA,EAAQ;EACpB,OAAO,OAAO,QAAQ,WAAW,MAAM,OAAO,OAAO,OAAO;CAC9D,CAAC;AACH;AAEA,SAAgB,mBACd,OAIA,aACA,MACA,SACA,SAK0B;CAC1B,OAAO;EACL,OAAO;EACP,UAAU,MAAM;EAChB,kBAAkB,MAAM;EACxB,YAAY,MAAM;EAClB;EACA;EACA;EACA,QAAQ,SAAS,UAAU;EAC3B,WAAW,SAAS,aAAa;EACjC,GAAI,SAAS,OAAO,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;CAChD;AACF;AAEA,eAAe,oBAAoB,OAIjB;CAChB,IAAI,iBAAiB,MAAM,MAAM,GAAG;EAClC,MAAM,SAAS,MAAM,2BACnB,MAAM,QACN,MAAM,KACR;EACA,IAAI,CAAC,OAAO,SACV,KAAK,MAAM,SAAS,OAAO,QACzB,MAAM,QAAQ,MAAM,SAAS,mBAAmB,MAAM,IAAI,CAAC;EAG/D;CACF;AAMF;AAMA,SAAS,YACP,OACA,MACyB;CACzB,OAAO,MAAM,MAAM,SAAS,KAAK,SAAS,IAAI;AAChD;AAEA,eAAe,iBACb,QACA,OACgE;CAChE,IAAI,CAAC,iBAAiB,MAAM,GAAG,OAAO;EAAE,SAAS;EAAM,MAAM;CAAM;CACnE,MAAM,SAAS,MAAM,2BAAoC,QAAQ,KAAK;CACtE,OAAO,OAAO,UACV;EAAE,SAAS;EAAM,MAAM,OAAO;CAAK,IACnC,EAAE,SAAS,MAAM;AACvB;AAEA,SAAS,yBACP,QACS;CACT,OAAO,YAAY,OAAO,OAAO,CAAC,EAAE;AACtC;AAEA,SAAS,WAAW,QAAyB;CAC3C,OAAO,oBAAoB,uBAAuB,MAAM,CAAC;AAC3D;AAEA,eAAe,iBAAiB,OAQd;CAChB,IAAI;EACF,MAAM,oBAAoB;GACxB,QAAQ,MAAM;GACd,OAAO,MAAM;GACb,UAAU,SAAS,SAAS;IAC1B,MAAM,OAAO,KACX,mBACE,MAAM,SACN,MAAM,aACN,MAAM,MACN,GAAG,MAAM,MAAM,IAAI,WACnB,EAAE,KAAK,CACT,CACF;GACF;EACF,CAAC;CACH,SAAS,OAAO;EACd,MAAM,OAAO,KACX,mBACE,MAAM,SACN,MAAM,aACN,2BACA,GAAG,MAAM,MAAM,2BAA2B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,KAC/F,EAAE,QAAQ,SAAS,CACrB,CACF;CACF;AACF;AAEA,SAAS,yBACP,OACA,QACA,SACA,QACS;CACT,MAAM,SAAS,yBAAyB,MAAM;CAC9C,MAAM,qBAAqB,QAAQ;CACnC,IAAI,WAAW,KAAA,KAAa,uBAAuB,KAAA,GACjD;CAEF,IACE,WAAW,KAAA,KACX,uBAAuB,KAAA,KACvB,WAAW,MAAM,MAAM,oBAEvB,OAAO,KACL,mBACE,OACA,OAAO,aACP,2BACA,aAAa,OAAO,YAAY,kDAChC,EAAE,QAAQ,SAAS,CACrB,CACF;CAEF,OAAO;AACT;;;;;AAMA,eAAsB,6BACpB,OACwC;CACxC,MAAM,0BAAU,IAAI,IAA6C;CACjE,MAAM,cAA+C,CAAC;CACtD,MAAM,SAAS,gBAAyD;EACtE,MAAM,WAAW,QAAQ,IAAI,WAAW;EACxC,IAAI,UAAU,OAAO;EACrB,MAAM,UAA2C,CAAC;EAClD,QAAQ,IAAI,aAAa,OAAO;EAChC,OAAO;CACT;CACA,MAAM,cAAc,IAAI,IACtB,MAAM,QAAQ,KAAK,WAAW,CAAC,OAAO,aAAa,MAAM,CAAC,CAC5D;CACA,MAAM,6BAAa,IAAI,IAAgC;CACvD,MAAM,yBAAS,IAAI,IAAoB;CACvC,KAAK,MAAM,SAAS,MAAM,UAAU,CAAC,GAAG;EACtC,OAAO,IAAI,MAAM,cAAc,OAAO,IAAI,MAAM,WAAW,KAAK,KAAK,CAAC;EACtE,IAAI,CAAC,WAAW,IAAI,MAAM,WAAW,GACnC,WAAW,IAAI,MAAM,aAAa,KAAK;CAC3C;CAEA,KAAK,MAAM,CAAC,aAAa,UAAU,QACjC,IAAI,QAAQ,GACV,MAAM,WAAW,CAAC,CAAC,KACjB,mBACE,OACA,aACA,YACA,aAAa,YAAY,+BAC3B,CACF;CAIJ,MAAM,kBAAkB,MAAM,QAAQ,QACnC,WAAW,OAAO,QAAQ,SAAS,SACtC;CACA,MAAM,wBACJ,gBAAgB,SAAS,KACzB,gBAAgB,OAAO,WAAW,WAAW,IAAI,OAAO,WAAW,CAAC;CAEtE,IAAI,aAAa;CACjB,KAAK,MAAM,UAAU,MAAM,SAAS;EAClC,MAAM,SAAS,MAAM,OAAO,WAAW;EACvC,MAAM,QAAQ,WAAW,IAAI,OAAO,WAAW;EAC/C,MAAM,UAAU,OAAO;EACvB,IAAI,CAAC,OAAO;GAGV,IAAI,yBAAyB,QAAQ,SAAS,yBAC5C;GAEF,aAAa;GACb,OAAO,KACL,mBACE,OACA,OAAO,aACP,qBACA,sCAAsC,OAAO,YAAY,EAC3D,CACF;EACF;EACA,IACE,QAAQ,qBAAqB,MAAM,oBACnC,QAAQ,eAAe,MAAM,cAC7B,QAAQ,gBAAgB,OAAO,aAE/B,OAAO,KACL,mBACE,OACA,OAAO,aACP,SACA,aAAa,OAAO,YAAY,mCAChC,EAAE,QAAQ,SAAS,CACrB,CACF;EAEF,IAAI,QAAQ,cAAc,KAAA,GAAW;GACnC,MAAM,YAAY,KAAK,MAAM,QAAQ,SAAS;GAC9C,IAAI,CAAC,OAAO,SAAS,SAAS,GAC5B,OAAO,KACL,mBACE,OACA,OAAO,aACP,mBACA,aAAa,OAAO,YAAY,6BAChC,EAAE,QAAQ,SAAS,CACrB,CACF;QACK,IAAI,cAAc,MAAM,OAAO,KAAK,IAAI,IAC7C,OAAO,KACL,mBACE,OACA,OAAO,aACP,WACA,aAAa,OAAO,YAAY,gBAChC,EAAE,QAAQ,SAAS,CACrB,CACF;EAEJ;EAEA,MAAM,iBAAiB,yBACrB,OACA,QACA,SACA,MACF;EACA,IAAI,CAAC,OAAO;EACZ,MAAM,cAAuB,MAAM;EACnC,IAAI,gBAAgB,cAAc,gBAAgB,aAAa;GAC7D,OAAO,KACL,mBACE,OACA,OAAO,aACP,mBACA,aAAa,OAAO,YAAY,sBAAsB,OAAO,WAAW,EAAE,EAC5E,CACF;GACA;EACF;EACA,IAAI,QAAQ,SAAS,WAAW;GAC9B,MAAM,iBAAiB,OAAO;GAC9B,IAAI,mBAAmB,KAAA,GAAW;IAChC,MAAM,aAAa,QAAQ;IAC3B,IACE,QAAQ,iBAAiB,eAAe,WAAW,MACnD,QAAQ,QAAQ,eAAe,OAC/B,QAAQ,gBAAgB,OAAO,eAC/B,eAAe,KAAA,KACf,CAAC,OAAO,UAAU,UAAU,KAC5B,aAAa,GAEb,OAAO,KACL,mBACE,OACA,OAAO,aACP,SACA,qBAAqB,OAAO,YAAY,kCACxC,EAAE,QAAQ,SAAS,CACrB,CACF;GAEJ;GACA,IAAI,MAAM,WAAW,aACf;QAAA,MAAM,YAAY,KAAA,GACpB,OAAO,KACL,mBACE,OACA,OAAO,aACP,mBACA,uBAAuB,OAAO,YAAY,6BAC5C,CACF;GAAA,OAEG,IAAI,mBAAmB,KAAA,GAC5B,MAAM,iBAAiB;IACrB,SAAS;IACT;IACA,aAAa,OAAO;IACpB,QAAQ,eAAe,WAAW;IAClC,OAAO,MAAM;IACb,MAAM;IACN,OAAO,aAAa,OAAO,YAAY;GACzC,CAAC;QACI,IAAI,mBAAmB,KAAA,GAC5B,MAAM,iBAAiB;IACrB,SAAS;IACT;IACA,aAAa,OAAO;IACpB,QAAQ;IACR,OAAO,MAAM;IACb,MAAM;IACN,OAAO,aAAa,OAAO,YAAY;GACzC,CAAC;GAEH;EACF;EAEA,IAAI,MAAM,WAAW,aAAa;GAChC,IAAI,MAAM,YAAY,KAAA,GACpB,OAAO,KACL,mBACE,OACA,OAAO,aACP,mBACA,uBAAuB,OAAO,YAAY,6BAC5C,CACF;GAEF;EACF;EAEA,MAAM,OAAO,YAAY,MAAM,OAAO,QAAQ,QAAQ;EACtD,IAAI,CAAC,MAAM;GACT,OAAO,KACL,mBACE,OACA,OAAO,aACP,SACA,QAAQ,QAAQ,SAAS,gCAAgC,OAAO,YAAY,IAC5E,EAAE,QAAQ,SAAS,CACrB,CACF;GACA;EACF;EAEA,IAAI;EACJ,IAAI,gBAAgB;EACpB,IAAI,QAAQ,SAAS,yBACf;OAAA,gBAAgB,KAAK,YAAY,MAAM,QAAQ,kBAAkB;IACnE,OAAO,KACL,mBACE,OACA,OAAO,aACP,SACA,QAAQ,QAAQ,SAAS,8BACzB,EAAE,QAAQ,SAAS,CACrB,CACF;IACA,gBAAgB;GAClB;SACK;GACL,IAAI;IACF,WAAW,wBACT,KAAK,gBACL,KAAK,WACP;GACF,QAAQ;IACN,OAAO,KACL,mBACE,OACA,OAAO,aACP,SACA,QAAQ,QAAQ,SAAS,mCACzB,EAAE,QAAQ,SAAS,CACrB,CACF;IACA,gBAAgB;GAClB;GACA,IACE,aAAa,KAAA,MACZ,gBAAgB,KAAK,WAAW,MAAM,QAAQ,mBAC7C,SAAS,uBAAuB,QAAQ,sBACxC,SAAS,uBAAuB,QAAQ,qBAC1C;IACA,OAAO,KACL,mBACE,OACA,OAAO,aACP,SACA,QAAQ,QAAQ,SAAS,gCACzB,EAAE,QAAQ,SAAS,CACrB,CACF;IACA,gBAAgB;GAClB;EACF;EAEA,IAAI,eAAe;EAEnB,IAAI,QAAQ,SAAS,yBAAyB;GAC5C,IAAI,mBAAmB,KAAA,GACrB,MAAM,iBAAiB;IACrB,SAAS;IACT;IACA,aAAa,OAAO;IACpB,QAAQ;IACR,OAAO,MAAM;IACb,MAAM;IACN,OAAO,QAAQ,QAAQ,SAAS;GAClC,CAAC;GAEH,IAAI,KAAK,iBAAiB,KAAA,GACxB,MAAM,iBAAiB;IACrB,SAAS;IACT;IACA,aAAa,OAAO;IACpB,QAAQ,KAAK;IACb,OAAO,MAAM;IACb,MAAM;IACN,OAAO,QAAQ,QAAQ,SAAS;GAClC,CAAC;GAEH;EACF;EAEA,IAAI,aAAa,KAAA,GAAW;EAC5B,MAAM,WAAW,YAAY,MAAM,OAAO;EAC1C,MAAM,WACJ,OAAO,MAAM,YAAY,YACrB,MAAM,UACN,OAAO,UAAU,aAAa,YAC5B,SAAS,WACT,KAAA;EACR,IAAI,aAAa,KAAA,GAAW;GAC1B,OAAO,KACL,mBACE,OACA,OAAO,aACP,mBACA,YAAY,OAAO,YAAY,yCACjC,CACF;GACA;EACF;EACA,IAAI,UACF,MAAM,iBAAiB;GACrB,SAAS;GACT;GACA,aAAa,OAAO;GACpB,QAAQ,SAAS;GACjB,OAAO,MAAM;GACb,MAAM;GACN,OAAO,YAAY,OAAO,YAAY;EACxC,CAAC;EAEH,IAAI,YAAY,UAAU,eAAe,KAAA,GAAW;GAClD,IAAI,KAAK,gBAAgB,KAAA,GACvB,OAAO,KACL,mBACE,OACA,OAAO,aACP,uBACA,YAAY,OAAO,YAAY,gDACjC,CACF;QAEA,MAAM,iBAAiB;IACrB,SAAS;IACT;IACA,aAAa,OAAO;IACpB,QAAQ,KAAK;IACb,OAAO,SAAS;IAChB,MAAM;IACN,OAAO,YAAY,OAAO,YAAY;GACxC,CAAC;EAEL;EACA,MAAM,SAAS,WACX,SAAS,SAAS,UAClB,SAAS,SAAS;EACtB,IAAI,QAAQ;GACV,IAAI,CAAC,UACH,OAAO,KACL,mBACE,OACA,OAAO,aACP,mBACA,YAAY,OAAO,YAAY,8BAA8B,WAAW,YAAY,SAAS,WAC/F,CACF;QAEA,MAAM,iBAAiB;IACrB,SAAS;IACT;IACA,aAAa,OAAO;IACpB,QAAQ,OAAO;IACf,OAAO,SAAS;IAChB,MAAM;IACN,OAAO,YAAY,OAAO,YAAY;GACxC,CAAC;EAEL;CACF;CAEA,KAAK,MAAM,SAAS,MAAM,UAAU,CAAC,GACnC,IAAI,CAAC,YAAY,IAAI,MAAM,WAAW,GAAG;EACvC,aAAa;EACb,MAAM,MAAM,WAAW,CAAC,CAAC,KACvB,mBACE,OACA,MAAM,aACN,qBACA,6CAA6C,MAAM,YAAY,EACjE,CACF;CACF;CAGF,IAAI,YACF,YAAY,KAAK;EACf,OAAO;EACP,UAAU,MAAM;EAChB,kBAAkB,MAAM;EACxB,YAAY,MAAM;EAClB,MAAM;EACN,SACE;EACF,QAAQ;EACR,WAAW;EACX,cAAc,MAAM,QAAQ,KAAK,WAAW,OAAO,WAAW;CAChE,CAAC;CAGH,MAAM,aAAa,CAAC,GAAG,QAAQ,QAAQ,CAAC,CAAC,CACtC,MAAM,CAAC,OAAO,CAAC,WAAW,KAAK,cAAc,KAAK,CAAC,CAAC,CACpD,SAAS,GAAG,YAAY,MAAM;CACjC,IAAI,WAAW,SAAS,GAAG;EACzB,YAAY,KAAK;GACf,OAAO;GACP,UAAU,MAAM;GAChB,kBAAkB,MAAM;GACxB,YAAY,MAAM;GAClB,MAAM;GACN,SAAS;GACT,QAAQ;GACR,WAAW;GACX,cAAc,MAAM,QAAQ,KAAK,WAAW,OAAO,WAAW;EAChE,CAAC;EACD,OAAO,EAAE,QAAQ,CAAC,GAAG,YAAY,GAAG,WAAW,EAAE;CACnD;CAEA,MAAM,YAAY,iCAAiC,MAAM,UAAU,CAAC,CAAC;CACrE,MAAM,4BAAY,IAAI,IAAoC;CAC1D,MAAM,oCAAoB,IAAI,IAAqB;CACnD,MAAM,oCAAoB,IAAI,IAI5B;CACF,MAAM,oCAAoB,IAAI,IAAqB;CACnD,MAAM,uCAAuB,IAAI,IAAY;CAE7C,KAAK,MAAM,UAAU,MAAM,SAAS;EAClC,MAAM,QAAQ,WAAW,IAAI,OAAO,WAAW;EAC/C,IAAI,CAAC,OAAO;EACZ,MAAM,UAAU,OAAO;EACvB,IAAI,QAAQ,SAAS,WAAW;GAC9B,IAAI,MAAM,WAAW,YAAY;IAC/B,kBAAkB,IAAI,OAAO,aAAa;KACxC,aAAa,OAAO;KACpB,QAAQ;IACV,CAAC;IACD;GACF;GACA,IAAI,OAAO,mBAAmB,KAAA,GAAW;IACvC,kBAAkB,IAAI,OAAO,aAAa;KACxC,aAAa,OAAO;KACpB,QAAQ;KACR,SAAS,MAAM;IACjB,CAAC;IACD;GACF;GACA,MAAM,SAAS,MAAM,iBACnB,OAAO,eAAe,WAAW,gBACjC,MAAM,OACR;GACA,IAAI,CAAC,OAAO,SACV,OAAO,EACL,QAAQ,CACN,mBACE,OACA,OAAO,aACP,mBACA,aAAa,OAAO,YAAY,qBAClC,CACF,EACF;GAEF,kBAAkB,IAAI,OAAO,aAAa;IACxC,aAAa,OAAO;IACpB,QAAQ;IACR,SAAS,OAAO;GAClB,CAAC;GACD;EACF;EACA,IAAI,MAAM,WAAW,aAAa;GAChC,qBAAqB,IAAI,QAAQ,UAAU;GAC3C;EACF;EACA,IAAI,QAAQ,SAAS,yBAAyB;GAC5C,kBAAkB,IAAI,QAAQ,YAAY,MAAM,OAAO;GACvD;EACF;EACA,MAAM,WAAW,YAAY,MAAM,OAAO;EAC1C,MAAM,aACJ,OAAO,MAAM,YAAY,YACrB,MAAM,UACN,UAAU,aAAa,OACrB;GACE,UAAU;GACV,GAAI,SAAS,eAAe,KAAA,IACxB,EAAE,YAAY,SAAS,WAAW,IAClC,CAAC;GACL,GAAI,SAAS,YAAY,KAAA,IACrB,EAAE,SAAS,SAAS,QAAQ,IAC5B,CAAC;EACP,IACA;GACE,UAAU;GACV,GAAI,UAAU,YAAY,KAAA,IACtB,EAAE,SAAS,SAAS,QAAQ,IAC5B,CAAC;EACP;EACR,UAAU,IAAI,QAAQ,YAAY,UAAU;EAC5C,IACE,eAAe,SACd,OAAO,eAAe,YAAY,CAAC,WAAW,UAE/C,kBAAkB,IAChB,QAAQ,YACR,OAAO,eAAe,WAAW,WAAW,UAAU,KAAA,CACxD;CAEJ;CAEA,OAAO;EACL,QAAQ,CAAC;EACT,aAAa,UAAU;EACvB,sBAAsB,UAAU;EAChC,aAAa,UAAU;EACvB,iBAAiB;GACf;GACA;GACA;GACA;GACA;EACF;CACF;AACF;;;;;;;;;AAUA,SAAS,0BAA0B,KAAuC;CACxE,MAAM,UAAU,IAAI;CACpB,IAAI,YAAY,KAAA,GAAW,OAAO;CAClC,OAAO,YAAA;AACT;AAEA,SAAgB,6BACd,YACsC;CACtC,MAAM,WAAW,YAAY,WAAW,QAAQ;CAChD,MAAM,MAAM,WACR,YAAY,SAAS,4BAA4B,IACjD;CACJ,IAAI,CAAC,OAAO,YAAY,KAAK,aAAa,MAAM,WAAW,IACzD,OAAO,KAAA;CACT,IAAI,CAAC,0BAA0B,GAAG,GAAG,OAAO,KAAA;CAC5C,MAAM,OAAO,YAAY,KAAK,MAAM;CACpC,MAAM,cAAc,YAAY,KAAK,aAAa;CAClD,MAAM,qBAAqB,YAAY,KAAK,oBAAoB;CAChE,MAAM,YAAY,YAAY,KAAK,WAAW;CAC9C,IAAI,CAAC,eAAe,uBAAuB,IAAI,OAAO,KAAA;CACtD,IAAI,cAAc,KAAA,KAAa,CAAC,OAAO,SAAS,KAAK,MAAM,SAAS,CAAC,GACnE;CAEF,MAAM,IAAA;CACN,IAAI,SAAS,WAAW;EACtB,MAAM,eAAe,YAAY,KAAK,cAAc;EACpD,MAAM,MAAM,YAAY,KAAK,KAAK;EAClC,MAAM,aAAa,IAAI;EACvB,MAAM,oBAAoB,YAAY,KAAK,mBAAmB;EAM9D,KAJE,iBAAiB,KAAA,KACjB,QAAQ,KAAA,KACR,eAAe,KAAA,KACf,sBAAsB,KAAA,OAGrB,CAAC,gBACA,CAAC,OACD,OAAO,eAAe,YACtB,CAAC,OAAO,UAAU,UAAU,KAC5B,aAAa,IAEf;EAEF,OAAO;GACL;GACA;GACA;GACA,GAAI,qBAAqB,EAAE,mBAAmB,IAAI,CAAC;GACnD,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;GACjC,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;GACvC,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;GACrB,GAAI,OAAO,eAAe,WAAW,EAAE,WAAW,IAAI,CAAC;GACvD,GAAI,oBAAoB,EAAE,kBAAkB,IAAI,CAAC;EACnD;CACF;CACA,IAAI,CAAC,oBAAoB,OAAO,KAAA;CAChC,MAAM,WAAW,YAAY,KAAK,UAAU;CAC5C,MAAM,aAAa,YAAY,KAAK,YAAY;CAChD,IAAI,CAAC,YAAY,CAAC,YAAY,OAAO,KAAA;CACrC,IAAI,SAAS,yBAAyB;EACpC,MAAM,mBAAmB,YAAY,KAAK,kBAAkB;EAC5D,IAAI,CAAC,kBAAkB,OAAO,KAAA;EAC9B,OAAO;GACL;GACA;GACA;GACA;GACA;GACA;GACA;GACA,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;EACnC;CACF;CACA,IAAI,SAAS,iBAAiB;EAC5B,MAAM,kBAAkB,YAAY,KAAK,iBAAiB;EAC1D,MAAM,qBAAqB,YAAY,KAAK,oBAAoB;EAChE,IAAI,CAAC,mBAAmB,CAAC,oBAAoB,OAAO,KAAA;EACpD,OAAO;GACL;GACA;GACA;GACA;GACA;GACA,cAAc,IAAI;GAClB;GACA;GACA;GACA,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;EACnC;CACF;AAEF;;;;;;;;;;AAWA,SAAgB,qBACd,YACA,SACW;CACX,OAAO;EACL,GAAG;EACH,UAAU;GACR,GAAG,WAAW;IACb,8BAA8B;IAC7B,GAAG;IACH,GAAA;IACA,aAAa,WAAW;GAC1B;EACF;CACF;AACF;;;;;;;;AASA,SAAgB,qBACd,YAC8B;CAC9B,MAAM,WAAW,6BAA6B,UAAU;CACxD,IAAI,CAAC,UAAU,OAAO,KAAA;CACtB,MAAM,WAAW,YAAY,WAAW,QAAQ;CAChD,MAAM,MAAM,WACR,YAAY,SAAS,4BAA4B,IACjD;CACJ,IAAI,CAAC,KAAK,OAAO,KAAA;CACjB,MAAM,mBAAmB,YAAY,KAAK,kBAAkB;CAC5D,MAAM,aAAa,IAAI;CACvB,IACE,CAAC,oBACD,OAAO,eAAe,YACtB,CAAC,OAAO,UAAU,UAAU,KAC5B,aAAa,GAEb;CAEF,OAAO;EAAE,GAAG;EAAU;EAAkB;CAAW;AACrD;AAEA,SAAgB,wBAAwB,YAAkC;CACxE,MAAM,WAAW,YAAY,WAAW,QAAQ;CAChD,IAAI,CAAC,YAAY,EAAE,+BAA+B,WAAW,OAAO;CACpE,MAAM,iBAAiB,EAAE,GAAG,SAAS;CACrC,OAAO,eAAe;CACtB,OAAO;EAAE,GAAG;EAAY,UAAU;CAAe;AACnD"}
1
+ {"version":3,"file":"interrupt-resume.js","names":[],"sources":["../../src/interrupt-resume.ts"],"sourcesContent":["import {\n INTERRUPT_BINDING_VERSION,\n canonicalizeInterruptResolutions,\n} from './interrupts'\nimport {\n canonicalInterruptJson,\n digestInterruptJson,\n} from './interrupt-serialization'\nimport {\n hashSchemaInput,\n normalizeApprovalSchema,\n} from './activities/chat/tools/approval-schema'\nimport {\n isStandardSchema,\n validateWithStandardSchema,\n} from './activities/chat/tools/schema-converter'\nimport { tanstackMetadata } from './utilities/merge-metadata'\nimport type {\n InterruptBinding,\n InterruptSubmissionError,\n ItemInterruptErrorCode,\n ToolApprovalResolution,\n UnopenedInterruptBinding,\n} from './interrupts'\nimport type {\n ChatMiddlewareConfig,\n ChatResumeToolState,\n} from './activities/chat/middleware/types'\nimport type {\n GenericInterruptRequest,\n InterruptDefinition,\n} from './interrupt-definition'\nimport type { Interrupt, RunAgentResumeItem } from './types'\n\n/**\n * The `Interrupt.metadata` key under which this package's resume binding\n * travels.\n *\n * Exported so anything that produces an interrupt this package must later\n * resume — an application middleware raising a generic pause, a future\n * workflow-to-AG-UI projection — attaches the binding through\n * {@link withInterruptBinding} rather than copying the string. Everything\n * outside this key is the plain AG-UI envelope and is left untouched.\n */\nexport const INTERRUPT_BINDING_METADATA_KEY = 'tanstack:interruptBinding'\n\nconst interruptBindingMetadataKey = INTERRUPT_BINDING_METADATA_KEY\n\n/** The persistence-neutral shape required to validate an interrupt resume. */\nexport interface PendingInterruptResumeRecord {\n interruptId: string\n payload: unknown\n binding: InterruptBinding\n /** Present for a first-party generic interrupt. */\n genericRequest?: GenericInterruptRequest<\n InterruptDefinition<any, any, any, any>\n >\n}\n\nexport interface ValidateInterruptResumeBatchInput {\n threadId: string\n interruptedRunId: string\n generation: number\n pending: ReadonlyArray<PendingInterruptResumeRecord>\n resume?: ReadonlyArray<RunAgentResumeItem>\n tools: ChatMiddlewareConfig['tools']\n now?: number\n}\n\nexport interface ValidatedInterruptResumeBatch {\n errors: ReadonlyArray<InterruptSubmissionError>\n resolutions?: ReadonlyArray<RunAgentResumeItem>\n canonicalResolutions?: string\n fingerprint?: string\n resumeToolState?: ChatResumeToolState\n}\n\nexport class InterruptResumeValidationError extends Error {\n override readonly name = 'InterruptResumeValidationError'\n\n constructor(readonly errors: ReadonlyArray<InterruptSubmissionError>) {\n super(errors.map((error) => error.message).join(' '))\n }\n}\n\nfunction objectValue(value: unknown): Record<string, unknown> | null {\n return value && typeof value === 'object'\n ? (value as Record<string, unknown>)\n : null\n}\n\nfunction stringField(\n value: Record<string, unknown>,\n key: string,\n): string | undefined {\n return typeof value[key] === 'string' ? value[key] : undefined\n}\n\ntype ClientToolResumeResult =\n | { state: 'output-available'; output: unknown }\n | { state: 'output-error'; errorText: string }\n\nfunction clientToolResult(\n entry: RunAgentResumeItem,\n): ClientToolResumeResult | null {\n if (tanstackMetadata(entry)?.state === 'output-error') {\n const result = objectValue(entry.payload)\n if (\n !result ||\n Object.keys(result).length !== 1 ||\n typeof result.error !== 'string'\n ) {\n return null\n }\n return {\n state: 'output-error',\n errorText: result.error,\n }\n }\n return {\n state: 'output-available',\n output: entry.payload,\n }\n}\n\nfunction normalizeIssuePath(\n path: ReadonlyArray<unknown> | undefined,\n): ReadonlyArray<string | number> | undefined {\n if (!path) return undefined\n return path.map((segment) => {\n if (typeof segment === 'string' || typeof segment === 'number') {\n return segment\n }\n const record = objectValue(segment)\n const key = record?.key\n return typeof key === 'number' ? key : String(key ?? segment)\n })\n}\n\nexport function interruptItemError(\n input: Pick<\n ValidateInterruptResumeBatchInput,\n 'threadId' | 'interruptedRunId' | 'generation'\n >,\n interruptId: string,\n code: ItemInterruptErrorCode,\n message: string,\n options?: {\n path?: ReadonlyArray<string | number>\n source?: 'client' | 'server'\n retryable?: boolean\n },\n): InterruptSubmissionError {\n return {\n scope: 'item',\n threadId: input.threadId,\n interruptedRunId: input.interruptedRunId,\n generation: input.generation,\n interruptId,\n code,\n message,\n source: options?.source ?? 'client',\n retryable: options?.retryable ?? false,\n ...(options?.path ? { path: options.path } : {}),\n }\n}\n\nasync function validateSchemaValue(input: {\n schema: unknown\n value: unknown\n onIssue: (message: string, path?: ReadonlyArray<string | number>) => void\n}): Promise<void> {\n if (isStandardSchema(input.schema)) {\n const result = await validateWithStandardSchema<unknown>(\n input.schema,\n input.value,\n )\n if (!result.success) {\n for (const issue of result.issues) {\n input.onIssue(issue.message, normalizeIssuePath(issue.path))\n }\n }\n return\n }\n\n // A non-Standard-Schema value (a raw JSON Schema, e.g. a generic interrupt's\n // wire responseSchema) is not validated by the library. The application\n // validates the resume value itself if it needs to; otherwise it flows\n // through as-is.\n}\n\ntype RuntimeTool = ChatMiddlewareConfig['tools'][number] & {\n approvalSchema?: Parameters<typeof normalizeApprovalSchema>[0]\n}\n\nfunction runtimeTool(\n tools: ChatMiddlewareConfig['tools'],\n name: string,\n): RuntimeTool | undefined {\n return tools.find((tool) => tool.name === name) as RuntimeTool | undefined\n}\n\nasync function parseSchemaValue(\n schema: unknown,\n value: unknown,\n): Promise<{ success: true; data: unknown } | { success: false }> {\n if (!isStandardSchema(schema)) return { success: true, data: value }\n const result = await validateWithStandardSchema<unknown>(schema, value)\n return result.success\n ? { success: true, data: result.data }\n : { success: false }\n}\n\nfunction descriptorResponseSchema(\n record: PendingInterruptResumeRecord,\n): unknown {\n return objectValue(record.payload)?.responseSchema\n}\n\nfunction schemaHash(schema: unknown): string {\n return digestInterruptJson(canonicalInterruptJson(schema))\n}\n\nasync function pushSchemaIssues(input: {\n request: ValidateInterruptResumeBatchInput\n errors: Array<InterruptSubmissionError>\n interruptId: string\n schema: unknown\n value: unknown\n code: ItemInterruptErrorCode\n label: string\n}): Promise<void> {\n try {\n await validateSchemaValue({\n schema: input.schema,\n value: input.value,\n onIssue: (message, path) => {\n input.errors.push(\n interruptItemError(\n input.request,\n input.interruptId,\n input.code,\n `${input.label}: ${message}`,\n { path },\n ),\n )\n },\n })\n } catch (error) {\n input.errors.push(\n interruptItemError(\n input.request,\n input.interruptId,\n 'invalid-response-schema',\n `${input.label} could not be validated: ${error instanceof Error ? error.message : String(error)}`,\n { source: 'server' },\n ),\n )\n }\n}\n\nfunction validateDescriptorSchema(\n input: ValidateInterruptResumeBatchInput,\n record: PendingInterruptResumeRecord,\n binding: InterruptBinding,\n errors: Array<InterruptSubmissionError>,\n): unknown {\n const schema = descriptorResponseSchema(record)\n const responseSchemaHash = binding.responseSchemaHash\n if (schema === undefined && responseSchemaHash === undefined) {\n return undefined\n }\n if (\n schema === undefined ||\n responseSchemaHash === undefined ||\n schemaHash(schema) !== responseSchemaHash\n ) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-response-schema',\n `Interrupt ${record.interruptId} response schema no longer matches its binding.`,\n { source: 'server' },\n ),\n )\n }\n return schema\n}\n\n/**\n * Validate and translate a complete interrupt batch before any tool executes.\n * Used by ephemeral chat resume; a durable layer may share the same validator.\n */\nexport async function validateInterruptResumeBatch(\n input: ValidateInterruptResumeBatchInput,\n): Promise<ValidatedInterruptResumeBatch> {\n const grouped = new Map<string, Array<InterruptSubmissionError>>()\n const batchErrors: Array<InterruptSubmissionError> = []\n const group = (interruptId: string): Array<InterruptSubmissionError> => {\n const existing = grouped.get(interruptId)\n if (existing) return existing\n const created: Array<InterruptSubmissionError> = []\n grouped.set(interruptId, created)\n return created\n }\n const pendingById = new Map(\n input.pending.map((record) => [record.interruptId, record]),\n )\n const resumeById = new Map<string, RunAgentResumeItem>()\n const counts = new Map<string, number>()\n for (const entry of input.resume ?? []) {\n counts.set(entry.interruptId, (counts.get(entry.interruptId) ?? 0) + 1)\n if (!resumeById.has(entry.interruptId))\n resumeById.set(entry.interruptId, entry)\n }\n\n for (const [interruptId, count] of counts) {\n if (count > 1) {\n group(interruptId).push(\n interruptItemError(\n input,\n interruptId,\n 'conflict',\n `Interrupt ${interruptId} has duplicate resume entries.`,\n ),\n )\n }\n }\n\n const pendingGenerics = input.pending.filter(\n (record) => record.binding.kind === 'generic',\n )\n const genericBatchSatisfied =\n pendingGenerics.length > 0 &&\n pendingGenerics.every((record) => resumeById.has(record.interruptId))\n\n let incomplete = false\n for (const record of input.pending) {\n const errors = group(record.interruptId)\n const entry = resumeById.get(record.interruptId)\n const binding = record.binding\n if (!entry) {\n // Client tools that share a generic interrupt batch wait for\n // `toolResume`. `continue` re-emits them; `cancel` / `stop` skip them.\n if (genericBatchSatisfied && binding.kind === 'client-tool-execution') {\n continue\n }\n incomplete = true\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'unknown-interrupt',\n `Missing resume entry for interrupt ${record.interruptId}.`,\n ),\n )\n }\n if (\n binding.interruptedRunId !== input.interruptedRunId ||\n binding.generation !== input.generation ||\n binding.interruptId !== record.interruptId\n ) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'stale',\n `Interrupt ${record.interruptId} has stale correlation metadata.`,\n { source: 'server' },\n ),\n )\n }\n if (binding.expiresAt !== undefined) {\n const expiresAt = Date.parse(binding.expiresAt)\n if (!Number.isFinite(expiresAt)) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Interrupt ${record.interruptId} has an invalid expiresAt.`,\n { source: 'server' },\n ),\n )\n } else if (expiresAt <= (input.now ?? Date.now())) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'expired',\n `Interrupt ${record.interruptId} has expired.`,\n { source: 'server' },\n ),\n )\n }\n }\n\n const responseSchema = validateDescriptorSchema(\n input,\n record,\n binding,\n errors,\n )\n if (!entry) continue\n const entryStatus: unknown = entry.status\n if (entryStatus !== 'resolved' && entryStatus !== 'cancelled') {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Interrupt ${record.interruptId} has invalid status ${String(entryStatus)}.`,\n ),\n )\n continue\n }\n if (binding.kind === 'generic') {\n const genericRequest = record.genericRequest\n if (genericRequest !== undefined) {\n const batchIndex = binding.batchIndex\n if (\n binding.definitionId !== genericRequest.definition.id ||\n binding.key !== genericRequest.key ||\n binding.interruptId !== record.interruptId ||\n batchIndex === undefined ||\n !Number.isInteger(batchIndex) ||\n batchIndex < 0\n ) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'stale',\n `Generic interrupt ${record.interruptId} has stale definition metadata.`,\n { source: 'server' },\n ),\n )\n }\n }\n if (entry.status === 'cancelled') {\n if (entry.payload !== undefined) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Cancelled interrupt ${record.interruptId} must not include a payload.`,\n ),\n )\n }\n } else if (genericRequest !== undefined) {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: genericRequest.definition.responseSchema,\n value: entry.payload,\n code: 'invalid-payload',\n label: `Interrupt ${record.interruptId} payload is invalid`,\n })\n } else if (responseSchema !== undefined) {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: responseSchema,\n value: entry.payload,\n code: 'invalid-payload',\n label: `Interrupt ${record.interruptId} payload is invalid`,\n })\n }\n continue\n }\n\n if (entry.status === 'cancelled') {\n if (entry.payload !== undefined) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Cancelled interrupt ${record.interruptId} must not include a payload.`,\n ),\n )\n }\n continue\n }\n\n const tool = runtimeTool(input.tools, binding.toolName)\n if (!tool) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'stale',\n `Tool ${binding.toolName} is unavailable for interrupt ${record.interruptId}.`,\n { source: 'server' },\n ),\n )\n continue\n }\n\n let approval: ReturnType<typeof normalizeApprovalSchema> | undefined\n let schemaDrifted = false\n if (binding.kind === 'client-tool-execution') {\n if (hashSchemaInput(tool.outputSchema) !== binding.outputSchemaHash) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'stale',\n `Tool ${binding.toolName} output schema has changed.`,\n { source: 'server' },\n ),\n )\n schemaDrifted = true\n }\n } else {\n try {\n approval = normalizeApprovalSchema(\n tool.approvalSchema,\n tool.inputSchema,\n )\n } catch {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'stale',\n `Tool ${binding.toolName} approval schema is unavailable.`,\n { source: 'server' },\n ),\n )\n schemaDrifted = true\n }\n if (\n approval !== undefined &&\n (hashSchemaInput(tool.inputSchema) !== binding.inputSchemaHash ||\n approval.approvalSchemaHash !== binding.approvalSchemaHash ||\n approval.responseSchemaHash !== binding.responseSchemaHash)\n ) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'stale',\n `Tool ${binding.toolName} approval schema has changed.`,\n { source: 'server' },\n ),\n )\n schemaDrifted = true\n }\n }\n\n if (schemaDrifted) continue\n\n if (binding.kind === 'client-tool-execution') {\n const result = clientToolResult(entry)\n if (!result) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-tool-output',\n `Tool ${binding.toolName} result is invalid.`,\n ),\n )\n continue\n }\n if (result.state === 'output-available' && responseSchema !== undefined) {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: responseSchema,\n value: entry.payload,\n code: 'invalid-tool-output',\n label: `Tool ${binding.toolName} output is invalid`,\n })\n }\n if (\n result.state === 'output-available' &&\n tool.outputSchema !== undefined\n ) {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: tool.outputSchema,\n value: result.output,\n code: 'invalid-tool-output',\n label: `Tool ${binding.toolName} output is invalid`,\n })\n }\n continue\n }\n\n if (approval === undefined) continue\n const envelope = objectValue(entry.payload)\n const approved =\n typeof entry.payload === 'boolean'\n ? entry.payload\n : typeof envelope?.approved === 'boolean'\n ? envelope.approved\n : undefined\n if (approved === undefined) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Approval ${record.interruptId} must be a boolean or decision envelope.`,\n ),\n )\n continue\n }\n if (envelope) {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: approval.responseSchema,\n value: entry.payload,\n code: 'invalid-payload',\n label: `Approval ${record.interruptId} envelope is invalid`,\n })\n }\n if (approved && envelope?.editedArgs !== undefined) {\n if (tool.inputSchema === undefined) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-edited-args',\n `Approval ${record.interruptId} cannot edit arguments without an input schema.`,\n ),\n )\n } else {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: tool.inputSchema,\n value: envelope.editedArgs,\n code: 'invalid-edited-args',\n label: `Approval ${record.interruptId} edited arguments are invalid`,\n })\n }\n }\n const branch = approved\n ? approval.branches.approve\n : approval.branches.reject\n if (branch) {\n if (!envelope) {\n errors.push(\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Approval ${record.interruptId} requires a payload for the ${approved ? 'approve' : 'reject'} decision.`,\n ),\n )\n } else {\n await pushSchemaIssues({\n request: input,\n errors,\n interruptId: record.interruptId,\n schema: branch.source,\n value: envelope.payload,\n code: 'invalid-payload',\n label: `Approval ${record.interruptId} payload is invalid`,\n })\n }\n }\n }\n\n for (const entry of input.resume ?? []) {\n if (!pendingById.has(entry.interruptId)) {\n incomplete = true\n group(entry.interruptId).push(\n interruptItemError(\n input,\n entry.interruptId,\n 'unknown-interrupt',\n `Resume entry references unknown interrupt ${entry.interruptId}.`,\n ),\n )\n }\n }\n\n if (incomplete) {\n batchErrors.push({\n scope: 'batch',\n threadId: input.threadId,\n interruptedRunId: input.interruptedRunId,\n generation: input.generation,\n code: 'incomplete-batch',\n message:\n 'Resume entries must resolve or cancel the complete interrupt batch.',\n source: 'client',\n retryable: false,\n interruptIds: input.pending.map((record) => record.interruptId),\n })\n }\n\n const itemErrors = [...grouped.entries()]\n .sort(([left], [right]) => left.localeCompare(right))\n .flatMap(([, errors]) => errors)\n if (itemErrors.length > 0) {\n batchErrors.push({\n scope: 'batch',\n threadId: input.threadId,\n interruptedRunId: input.interruptedRunId,\n generation: input.generation,\n code: 'item-validation-failed',\n message: 'One or more interrupt resolutions are invalid.',\n source: 'client',\n retryable: false,\n interruptIds: input.pending.map((record) => record.interruptId),\n })\n return { errors: [...itemErrors, ...batchErrors] }\n }\n\n const canonical = canonicalizeInterruptResolutions(input.resume ?? [])\n const approvals = new Map<string, ToolApprovalResolution>()\n const clientToolResults = new Map<string, unknown>()\n const clientToolErrors = new Map<string, string>()\n const genericInterrupts = new Map<\n string,\n | { interruptId: string; status: 'resolved'; payload: unknown }\n | { interruptId: string; status: 'cancelled' }\n >()\n const deniedToolResults = new Map<string, unknown>()\n const cancelledToolCallIds = new Set<string>()\n\n for (const record of input.pending) {\n const entry = resumeById.get(record.interruptId)\n if (!entry) continue\n const binding = record.binding\n if (binding.kind === 'generic') {\n if (entry.status !== 'resolved') {\n genericInterrupts.set(record.interruptId, {\n interruptId: record.interruptId,\n status: 'cancelled',\n })\n continue\n }\n if (record.genericRequest === undefined) {\n genericInterrupts.set(record.interruptId, {\n interruptId: record.interruptId,\n status: 'resolved',\n payload: entry.payload,\n })\n continue\n }\n const parsed = await parseSchemaValue(\n record.genericRequest.definition.responseSchema,\n entry.payload,\n )\n if (!parsed.success) {\n return {\n errors: [\n interruptItemError(\n input,\n record.interruptId,\n 'invalid-payload',\n `Interrupt ${record.interruptId} payload is invalid.`,\n ),\n ],\n }\n }\n genericInterrupts.set(record.interruptId, {\n interruptId: record.interruptId,\n status: 'resolved',\n payload: parsed.data,\n })\n continue\n }\n if (entry.status === 'cancelled') {\n cancelledToolCallIds.add(binding.toolCallId)\n continue\n }\n if (binding.kind === 'client-tool-execution') {\n const result = clientToolResult(entry)\n if (!result) continue\n if (result.state === 'output-error') {\n clientToolErrors.set(binding.toolCallId, result.errorText)\n } else {\n clientToolResults.set(binding.toolCallId, result.output)\n }\n continue\n }\n const envelope = objectValue(entry.payload)\n const resolution: ToolApprovalResolution =\n typeof entry.payload === 'boolean'\n ? entry.payload\n : envelope?.approved === true\n ? {\n approved: true,\n ...(envelope.editedArgs !== undefined\n ? { editedArgs: envelope.editedArgs }\n : {}),\n ...(envelope.payload !== undefined\n ? { payload: envelope.payload }\n : {}),\n }\n : {\n approved: false,\n ...(envelope?.payload !== undefined\n ? { payload: envelope.payload }\n : {}),\n }\n approvals.set(binding.toolCallId, resolution)\n if (\n resolution === false ||\n (typeof resolution === 'object' && !resolution.approved)\n ) {\n deniedToolResults.set(\n binding.toolCallId,\n typeof resolution === 'object' ? resolution.payload : undefined,\n )\n }\n }\n\n return {\n errors: [],\n resolutions: canonical.resolutions,\n canonicalResolutions: canonical.canonicalResolutions,\n fingerprint: canonical.fingerprint,\n resumeToolState: {\n approvals,\n clientToolResults,\n clientToolErrors,\n genericInterrupts,\n deniedToolResults,\n cancelledToolCallIds,\n },\n }\n}\n\n/**\n * Is this a binding written by a version of the protocol we understand?\n *\n * A missing `v` is read as {@link INTERRUPT_BINDING_VERSION} so bindings\n * written before the field existed still resume. A `v` we don't recognise is\n * rejected outright — a newer or foreign producer's binding must not be\n * duck-typed into ours.\n */\nfunction isSupportedBindingVersion(raw: Record<string, unknown>): boolean {\n const version = raw['v']\n if (version === undefined) return true\n return version === INTERRUPT_BINDING_VERSION\n}\n\nexport function readUnopenedInterruptBinding(\n descriptor: Interrupt,\n): UnopenedInterruptBinding | undefined {\n const metadata = objectValue(descriptor.metadata)\n const raw = metadata\n ? objectValue(metadata[interruptBindingMetadataKey])\n : null\n if (!raw || stringField(raw, 'interruptId') !== descriptor.id)\n return undefined\n if (!isSupportedBindingVersion(raw)) return undefined\n const kind = stringField(raw, 'kind')\n const interruptId = stringField(raw, 'interruptId')\n const responseSchemaHash = stringField(raw, 'responseSchemaHash')\n const expiresAt = stringField(raw, 'expiresAt')\n if (!interruptId || responseSchemaHash === '') return undefined\n if (expiresAt !== undefined && !Number.isFinite(Date.parse(expiresAt))) {\n return undefined\n }\n const v = INTERRUPT_BINDING_VERSION\n if (kind === 'generic') {\n const definitionId = stringField(raw, 'definitionId')\n const key = stringField(raw, 'key')\n const batchIndex = raw['batchIndex']\n const payloadSchemaHash = stringField(raw, 'payloadSchemaHash')\n const hasFirstPartyFields =\n definitionId !== undefined ||\n key !== undefined ||\n batchIndex !== undefined ||\n payloadSchemaHash !== undefined\n if (\n hasFirstPartyFields &&\n (!definitionId ||\n !key ||\n typeof batchIndex !== 'number' ||\n !Number.isInteger(batchIndex) ||\n batchIndex < 0)\n ) {\n return undefined\n }\n return {\n v,\n kind,\n interruptId,\n ...(responseSchemaHash ? { responseSchemaHash } : {}),\n ...(expiresAt ? { expiresAt } : {}),\n ...(definitionId ? { definitionId } : {}),\n ...(key ? { key } : {}),\n ...(typeof batchIndex === 'number' ? { batchIndex } : {}),\n ...(payloadSchemaHash ? { payloadSchemaHash } : {}),\n }\n }\n if (!responseSchemaHash) return undefined\n const toolName = stringField(raw, 'toolName')\n const toolCallId = stringField(raw, 'toolCallId')\n if (!toolName || !toolCallId) return undefined\n if (kind === 'client-tool-execution') {\n const outputSchemaHash = stringField(raw, 'outputSchemaHash')\n if (!outputSchemaHash) return undefined\n return {\n v,\n kind,\n interruptId,\n toolName,\n toolCallId,\n outputSchemaHash,\n responseSchemaHash,\n ...(expiresAt ? { expiresAt } : {}),\n }\n }\n if (kind === 'tool-approval') {\n const inputSchemaHash = stringField(raw, 'inputSchemaHash')\n const approvalSchemaHash = stringField(raw, 'approvalSchemaHash')\n if (!inputSchemaHash || !approvalSchemaHash) return undefined\n return {\n v,\n kind,\n interruptId,\n toolName,\n toolCallId,\n originalArgs: raw.originalArgs,\n inputSchemaHash,\n approvalSchemaHash,\n responseSchemaHash,\n ...(expiresAt ? { expiresAt } : {}),\n }\n }\n return undefined\n}\n\n/**\n * Attach a resume binding to an interrupt descriptor, under\n * {@link INTERRUPT_BINDING_METADATA_KEY}.\n *\n * This is the supported way to make an interrupt resumable by this package.\n * The descriptor keeps its AG-UI shape; only `metadata` gains the namespaced\n * key. Pass the unopened form (no `interruptedRunId` / `generation`) when\n * emitting from inside a run — those fields are stamped as the run finishes.\n */\nexport function withInterruptBinding(\n descriptor: Interrupt,\n binding: UnopenedInterruptBinding | InterruptBinding,\n): Interrupt {\n return {\n ...descriptor,\n metadata: {\n ...descriptor.metadata,\n [interruptBindingMetadataKey]: {\n ...binding,\n v: INTERRUPT_BINDING_VERSION,\n interruptId: descriptor.id,\n },\n },\n }\n}\n\n/**\n * Read the opened resume binding off a descriptor, or `undefined` when the\n * descriptor carries no binding of a version we understand.\n *\n * `undefined` means \"this interrupt is not ours to resume\" — it is not a\n * failure to recover from by inventing a binding.\n */\nexport function readInterruptBinding(\n descriptor: Interrupt,\n): InterruptBinding | undefined {\n const unopened = readUnopenedInterruptBinding(descriptor)\n if (!unopened) return undefined\n const metadata = objectValue(descriptor.metadata)\n const raw = metadata\n ? objectValue(metadata[interruptBindingMetadataKey])\n : null\n if (!raw) return undefined\n const interruptedRunId = stringField(raw, 'interruptedRunId')\n const generation = raw['generation']\n if (\n !interruptedRunId ||\n typeof generation !== 'number' ||\n !Number.isInteger(generation) ||\n generation < 0\n ) {\n return undefined\n }\n return { ...unopened, interruptedRunId, generation }\n}\n\nexport function withoutInterruptBinding(descriptor: Interrupt): Interrupt {\n const metadata = objectValue(descriptor.metadata)\n if (!metadata || !(interruptBindingMetadataKey in metadata)) return descriptor\n const publicMetadata = { ...metadata }\n delete publicMetadata[interruptBindingMetadataKey]\n return { ...descriptor, metadata: publicMetadata }\n}\n"],"mappings":"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"}