@tanstack/ai 0.36.0 → 0.37.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 (205) hide show
  1. package/dist/esm/activities/chat/adapter.d.ts +163 -0
  2. package/dist/esm/activities/chat/adapter.js +17 -0
  3. package/dist/esm/activities/chat/adapter.js.map +1 -0
  4. package/dist/esm/activities/chat/agent-loop-strategies.d.ts +59 -0
  5. package/dist/esm/activities/chat/agent-loop-strategies.js +23 -0
  6. package/dist/esm/activities/chat/agent-loop-strategies.js.map +1 -0
  7. package/dist/esm/activities/chat/index.d.ts +270 -0
  8. package/dist/esm/activities/chat/index.js +1724 -0
  9. package/dist/esm/activities/chat/index.js.map +1 -0
  10. package/dist/esm/activities/chat/mcp/manager.d.ts +25 -0
  11. package/dist/esm/activities/chat/mcp/manager.js +71 -0
  12. package/dist/esm/activities/chat/mcp/manager.js.map +1 -0
  13. package/dist/esm/activities/chat/mcp/types.d.ts +56 -0
  14. package/dist/esm/activities/chat/messages.d.ts +78 -0
  15. package/dist/esm/activities/chat/messages.js +374 -0
  16. package/dist/esm/activities/chat/messages.js.map +1 -0
  17. package/dist/esm/activities/chat/middleware/builder.d.ts +46 -0
  18. package/dist/esm/activities/chat/middleware/builder.js +17 -0
  19. package/dist/esm/activities/chat/middleware/builder.js.map +1 -0
  20. package/dist/esm/activities/chat/middleware/capabilities.d.ts +93 -0
  21. package/dist/esm/activities/chat/middleware/capabilities.js +45 -0
  22. package/dist/esm/activities/chat/middleware/capabilities.js.map +1 -0
  23. package/dist/esm/activities/chat/middleware/compose.d.ts +87 -0
  24. package/dist/esm/activities/chat/middleware/compose.js +510 -0
  25. package/dist/esm/activities/chat/middleware/compose.js.map +1 -0
  26. package/dist/esm/activities/chat/middleware/define.d.ts +20 -0
  27. package/dist/esm/activities/chat/middleware/define.js +7 -0
  28. package/dist/esm/activities/chat/middleware/define.js.map +1 -0
  29. package/dist/esm/activities/chat/middleware/index.d.ts +10 -0
  30. package/dist/esm/activities/chat/middleware/tool-cache-middleware.d.ts +89 -0
  31. package/dist/esm/activities/chat/middleware/tool-cache-middleware.js +76 -0
  32. package/dist/esm/activities/chat/middleware/tool-cache-middleware.js.map +1 -0
  33. package/dist/esm/activities/chat/middleware/types.d.ts +405 -0
  34. package/dist/esm/activities/chat/middleware/validate.d.ts +19 -0
  35. package/dist/esm/activities/chat/middleware/validate.js +30 -0
  36. package/dist/esm/activities/chat/middleware/validate.js.map +1 -0
  37. package/dist/esm/activities/chat/runtime-context-types.d.ts +43 -0
  38. package/dist/esm/activities/chat/stream/index.d.ts +11 -0
  39. package/dist/esm/activities/chat/stream/json-parser.d.ts +38 -0
  40. package/dist/esm/activities/chat/stream/json-parser.js +28 -0
  41. package/dist/esm/activities/chat/stream/json-parser.js.map +1 -0
  42. package/dist/esm/activities/chat/stream/message-updaters.d.ts +81 -0
  43. package/dist/esm/activities/chat/stream/message-updaters.js +253 -0
  44. package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -0
  45. package/dist/esm/activities/chat/stream/processor.d.ts +439 -0
  46. package/dist/esm/activities/chat/stream/processor.js +1426 -0
  47. package/dist/esm/activities/chat/stream/processor.js.map +1 -0
  48. package/dist/esm/activities/chat/stream/strategies.d.ts +43 -0
  49. package/dist/esm/activities/chat/stream/strategies.js +54 -0
  50. package/dist/esm/activities/chat/stream/strategies.js.map +1 -0
  51. package/dist/esm/activities/chat/stream/types.d.ts +90 -0
  52. package/dist/esm/activities/chat/tools/lazy-tool-manager.d.ts +82 -0
  53. package/dist/esm/activities/chat/tools/lazy-tool-manager.js +194 -0
  54. package/dist/esm/activities/chat/tools/lazy-tool-manager.js.map +1 -0
  55. package/dist/esm/activities/chat/tools/lazy-tools.d.ts +15 -0
  56. package/dist/esm/activities/chat/tools/lazy-tools.js +16 -0
  57. package/dist/esm/activities/chat/tools/lazy-tools.js.map +1 -0
  58. package/dist/esm/activities/chat/tools/schema-converter.d.ts +140 -0
  59. package/dist/esm/activities/chat/tools/schema-converter.js +167 -0
  60. package/dist/esm/activities/chat/tools/schema-converter.js.map +1 -0
  61. package/dist/esm/activities/chat/tools/tool-calls.d.ts +140 -0
  62. package/dist/esm/activities/chat/tools/tool-calls.js +512 -0
  63. package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -0
  64. package/dist/esm/activities/chat/tools/tool-definition.d.ts +135 -0
  65. package/dist/esm/activities/chat/tools/tool-definition.js +25 -0
  66. package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -0
  67. package/dist/esm/activities/error-payload.d.ts +30 -0
  68. package/dist/esm/activities/error-payload.js +54 -0
  69. package/dist/esm/activities/error-payload.js.map +1 -0
  70. package/dist/esm/activities/generateAudio/adapter.d.ts +62 -0
  71. package/dist/esm/activities/generateAudio/adapter.js +16 -0
  72. package/dist/esm/activities/generateAudio/adapter.js.map +1 -0
  73. package/dist/esm/activities/generateAudio/index.d.ts +85 -0
  74. package/dist/esm/activities/generateAudio/index.js +114 -0
  75. package/dist/esm/activities/generateAudio/index.js.map +1 -0
  76. package/dist/esm/activities/generateImage/adapter.d.ts +78 -0
  77. package/dist/esm/activities/generateImage/adapter.js +16 -0
  78. package/dist/esm/activities/generateImage/adapter.js.map +1 -0
  79. package/dist/esm/activities/generateImage/index.d.ts +134 -0
  80. package/dist/esm/activities/generateImage/index.js +121 -0
  81. package/dist/esm/activities/generateImage/index.js.map +1 -0
  82. package/dist/esm/activities/generateSpeech/adapter.d.ts +62 -0
  83. package/dist/esm/activities/generateSpeech/adapter.js +16 -0
  84. package/dist/esm/activities/generateSpeech/adapter.js.map +1 -0
  85. package/dist/esm/activities/generateSpeech/index.d.ts +96 -0
  86. package/dist/esm/activities/generateSpeech/index.js +119 -0
  87. package/dist/esm/activities/generateSpeech/index.js.map +1 -0
  88. package/dist/esm/activities/generateTranscription/adapter.d.ts +62 -0
  89. package/dist/esm/activities/generateTranscription/adapter.js +16 -0
  90. package/dist/esm/activities/generateTranscription/adapter.js.map +1 -0
  91. package/dist/esm/activities/generateTranscription/index.d.ts +109 -0
  92. package/dist/esm/activities/generateTranscription/index.js +109 -0
  93. package/dist/esm/activities/generateTranscription/index.js.map +1 -0
  94. package/dist/esm/activities/generateVideo/adapter.d.ts +145 -0
  95. package/dist/esm/activities/generateVideo/adapter.js +30 -0
  96. package/dist/esm/activities/generateVideo/adapter.js.map +1 -0
  97. package/dist/esm/activities/generateVideo/index.d.ts +223 -0
  98. package/dist/esm/activities/generateVideo/index.js +295 -0
  99. package/dist/esm/activities/generateVideo/index.js.map +1 -0
  100. package/dist/esm/activities/generateVideo/snap.d.ts +14 -0
  101. package/dist/esm/activities/generateVideo/snap.js +54 -0
  102. package/dist/esm/activities/generateVideo/snap.js.map +1 -0
  103. package/dist/esm/activities/index.d.ts +27 -0
  104. package/dist/esm/activities/index.js +43 -0
  105. package/dist/esm/activities/index.js.map +1 -0
  106. package/dist/esm/activities/middleware/index.d.ts +2 -0
  107. package/dist/esm/activities/middleware/run.d.ts +20 -0
  108. package/dist/esm/activities/middleware/run.js +42 -0
  109. package/dist/esm/activities/middleware/run.js.map +1 -0
  110. package/dist/esm/activities/middleware/types.d.ts +118 -0
  111. package/dist/esm/activities/stream-generation-result.d.ts +15 -0
  112. package/dist/esm/activities/stream-generation-result.js +49 -0
  113. package/dist/esm/activities/stream-generation-result.js.map +1 -0
  114. package/dist/esm/activities/summarize/adapter.d.ts +74 -0
  115. package/dist/esm/activities/summarize/adapter.js +16 -0
  116. package/dist/esm/activities/summarize/adapter.js.map +1 -0
  117. package/dist/esm/activities/summarize/chat-stream-summarize.d.ts +45 -0
  118. package/dist/esm/activities/summarize/chat-stream-summarize.js +212 -0
  119. package/dist/esm/activities/summarize/chat-stream-summarize.js.map +1 -0
  120. package/dist/esm/activities/summarize/index.d.ts +108 -0
  121. package/dist/esm/activities/summarize/index.js +113 -0
  122. package/dist/esm/activities/summarize/index.js.map +1 -0
  123. package/dist/esm/adapter-internals.d.ts +5 -0
  124. package/dist/esm/adapter-internals.js +10 -0
  125. package/dist/esm/adapter-internals.js.map +1 -0
  126. package/dist/esm/client.d.ts +44 -0
  127. package/dist/esm/client.js +67 -0
  128. package/dist/esm/client.js.map +1 -0
  129. package/dist/esm/extend-adapter.d.ts +152 -0
  130. package/dist/esm/extend-adapter.js +21 -0
  131. package/dist/esm/extend-adapter.js.map +1 -0
  132. package/dist/esm/index.d.ts +45 -0
  133. package/dist/esm/index.js +109 -0
  134. package/dist/esm/index.js.map +1 -0
  135. package/dist/esm/logger/console-logger.d.ts +29 -0
  136. package/dist/esm/logger/console-logger.js +83 -0
  137. package/dist/esm/logger/console-logger.js.map +1 -0
  138. package/dist/esm/logger/internal-logger.d.ts +41 -0
  139. package/dist/esm/logger/internal-logger.js +86 -0
  140. package/dist/esm/logger/internal-logger.js.map +1 -0
  141. package/dist/esm/logger/resolve.d.ts +14 -0
  142. package/dist/esm/logger/resolve.js +54 -0
  143. package/dist/esm/logger/resolve.js.map +1 -0
  144. package/dist/esm/logger/types.d.ts +75 -0
  145. package/dist/esm/middlewares/content-guard.d.ts +77 -0
  146. package/dist/esm/middlewares/content-guard.js +156 -0
  147. package/dist/esm/middlewares/content-guard.js.map +1 -0
  148. package/dist/esm/middlewares/index.d.ts +2 -0
  149. package/dist/esm/middlewares/index.js +7 -0
  150. package/dist/esm/middlewares/index.js.map +1 -0
  151. package/dist/esm/middlewares/otel.d.ts +81 -0
  152. package/dist/esm/middlewares/otel.js +745 -0
  153. package/dist/esm/middlewares/otel.js.map +1 -0
  154. package/dist/esm/middlewares/tool-cache.d.ts +1 -0
  155. package/dist/esm/middlewares/usage-attributes.d.ts +24 -0
  156. package/dist/esm/middlewares/usage-attributes.js +43 -0
  157. package/dist/esm/middlewares/usage-attributes.js.map +1 -0
  158. package/dist/esm/realtime/index.d.ts +28 -0
  159. package/dist/esm/realtime/index.js +8 -0
  160. package/dist/esm/realtime/index.js.map +1 -0
  161. package/dist/esm/realtime/types.d.ts +282 -0
  162. package/dist/esm/stream-to-response.d.ts +102 -0
  163. package/dist/esm/stream-to-response.js +121 -0
  164. package/dist/esm/stream-to-response.js.map +1 -0
  165. package/dist/esm/strip-to-spec-middleware.d.ts +18 -0
  166. package/dist/esm/strip-to-spec-middleware.js +20 -0
  167. package/dist/esm/strip-to-spec-middleware.js.map +1 -0
  168. package/dist/esm/system-prompts.d.ts +66 -0
  169. package/dist/esm/system-prompts.js +23 -0
  170. package/dist/esm/system-prompts.js.map +1 -0
  171. package/dist/esm/tool-registry.d.ts +81 -0
  172. package/dist/esm/tool-registry.js +49 -0
  173. package/dist/esm/tool-registry.js.map +1 -0
  174. package/dist/esm/tools/provider-tool.d.ts +30 -0
  175. package/dist/esm/tools/provider-tool.js +7 -0
  176. package/dist/esm/tools/provider-tool.js.map +1 -0
  177. package/dist/esm/types.d.ts +1594 -0
  178. package/dist/esm/utilities/ag-ui-wire.d.ts +44 -0
  179. package/dist/esm/utilities/ag-ui-wire.js +107 -0
  180. package/dist/esm/utilities/ag-ui-wire.js.map +1 -0
  181. package/dist/esm/utilities/chat-params.d.ts +85 -0
  182. package/dist/esm/utilities/chat-params.js +100 -0
  183. package/dist/esm/utilities/chat-params.js.map +1 -0
  184. package/dist/esm/utilities/errors.d.ts +13 -0
  185. package/dist/esm/utilities/errors.js +22 -0
  186. package/dist/esm/utilities/errors.js.map +1 -0
  187. package/dist/esm/utilities/media-prompt.d.ts +35 -0
  188. package/dist/esm/utilities/media-prompt.js +43 -0
  189. package/dist/esm/utilities/media-prompt.js.map +1 -0
  190. package/dist/esm/utilities/numbers.d.ts +8 -0
  191. package/dist/esm/utilities/numbers.js +12 -0
  192. package/dist/esm/utilities/numbers.js.map +1 -0
  193. package/dist/esm/utilities/sampling-keys.d.ts +20 -0
  194. package/dist/esm/utilities/sampling-keys.js +20 -0
  195. package/dist/esm/utilities/sampling-keys.js.map +1 -0
  196. package/dist/esm/utilities/tool-result.d.ts +21 -0
  197. package/dist/esm/utilities/tool-result.js +37 -0
  198. package/dist/esm/utilities/tool-result.js.map +1 -0
  199. package/dist/esm/utilities/usage.d.ts +31 -0
  200. package/dist/esm/utilities/usage.js +11 -0
  201. package/dist/esm/utilities/usage.js.map +1 -0
  202. package/dist/esm/utils.d.ts +17 -0
  203. package/dist/esm/utils.js +20 -0
  204. package/dist/esm/utils.js.map +1 -0
  205. package/package.json +3 -3
@@ -0,0 +1,20 @@
1
+ import { CapabilityHandle } from './capabilities.js';
2
+ import { ChatMiddleware } from './types.js';
3
+ /**
4
+ * A middleware whose `requires`/`provides` tuple types are captured precisely
5
+ * (via `const` inference) for the array coverage check and the builder.
6
+ */
7
+ export interface DefinedChatMiddleware<TContext, TRequires extends ReadonlyArray<CapabilityHandle>, TProvides extends ReadonlyArray<CapabilityHandle>> extends ChatMiddleware<TContext> {
8
+ requires?: TRequires;
9
+ provides?: TProvides;
10
+ }
11
+ /**
12
+ * Identity helper for authoring middleware with precise capability inference.
13
+ * Returns the middleware unchanged at runtime; only sharpens its type so the
14
+ * `chat()` array coverage check and `createChatMiddleware` builder can read the
15
+ * exact `requires`/`provides`.
16
+ */
17
+ export declare function defineChatMiddleware<TContext = unknown, const TRequires extends ReadonlyArray<CapabilityHandle> = readonly [], const TProvides extends ReadonlyArray<CapabilityHandle> = readonly []>(middleware: ChatMiddleware<TContext> & {
18
+ requires?: TRequires;
19
+ provides?: TProvides;
20
+ }): DefinedChatMiddleware<TContext, TRequires, TProvides>;
@@ -0,0 +1,7 @@
1
+ function defineChatMiddleware(middleware) {
2
+ return middleware;
3
+ }
4
+ export {
5
+ defineChatMiddleware
6
+ };
7
+ //# sourceMappingURL=define.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define.js","sources":["../../../../../src/activities/chat/middleware/define.ts"],"sourcesContent":["import type { CapabilityHandle } from './capabilities'\nimport type { ChatMiddleware } from './types'\n\n/**\n * A middleware whose `requires`/`provides` tuple types are captured precisely\n * (via `const` inference) for the array coverage check and the builder.\n */\nexport interface DefinedChatMiddleware<\n TContext,\n TRequires extends ReadonlyArray<CapabilityHandle>,\n TProvides extends ReadonlyArray<CapabilityHandle>,\n> extends ChatMiddleware<TContext> {\n requires?: TRequires\n provides?: TProvides\n}\n\n/**\n * Identity helper for authoring middleware with precise capability inference.\n * Returns the middleware unchanged at runtime; only sharpens its type so the\n * `chat()` array coverage check and `createChatMiddleware` builder can read the\n * exact `requires`/`provides`.\n */\nexport function defineChatMiddleware<\n TContext = unknown,\n const TRequires extends ReadonlyArray<CapabilityHandle> = readonly [],\n const TProvides extends ReadonlyArray<CapabilityHandle> = readonly [],\n>(\n middleware: ChatMiddleware<TContext> & {\n requires?: TRequires\n provides?: TProvides\n },\n): DefinedChatMiddleware<TContext, TRequires, TProvides> {\n return middleware\n}\n"],"names":[],"mappings":"AAsBO,SAAS,qBAKd,YAIuD;AACvD,SAAO;AACT;"}
@@ -0,0 +1,10 @@
1
+ export type { ChatMiddleware, ChatMiddlewareContext, ChatMiddlewarePhase, ChatMiddlewareConfig, StructuredOutputMiddlewareConfig, ToolCallHookContext, BeforeToolCallDecision, AfterToolCallInfo, IterationInfo, ToolPhaseCompleteInfo, UsageInfo, FinishInfo, AbortInfo, ErrorInfo, } from './types.js';
2
+ export { MiddlewareRunner } from './compose.js';
3
+ export { createCapability, CapabilityRegistry } from './capabilities.js';
4
+ export type { Capability, CapabilityHandle, CapabilityContext, CapabilityGetter, CapabilityProvider, CapabilityGetOptions, } from './capabilities.js';
5
+ export { defineChatMiddleware } from './define.js';
6
+ export type { DefinedChatMiddleware } from './define.js';
7
+ export { createChatMiddleware } from './builder.js';
8
+ export type { ChatMiddlewareBuilder, MissingCapabilities, NamesOf, } from './builder.js';
9
+ export { validateCapabilities } from './validate.js';
10
+ export type { AnyChatMiddleware } from './types.js';
@@ -0,0 +1,89 @@
1
+ import { ChatMiddleware } from './types.js';
2
+ /**
3
+ * A cache entry stored by the tool cache middleware.
4
+ */
5
+ export interface ToolCacheEntry {
6
+ result: unknown;
7
+ timestamp: number;
8
+ }
9
+ /**
10
+ * Custom storage backend for the tool cache middleware.
11
+ *
12
+ * When provided, the middleware delegates all cache operations to this storage
13
+ * instead of using the built-in in-memory Map. This enables external storage
14
+ * backends like Redis, localStorage, databases, etc.
15
+ *
16
+ * All methods may return a Promise for async storage backends.
17
+ */
18
+ export interface ToolCacheStorage {
19
+ getItem: (key: string) => ToolCacheEntry | undefined | Promise<ToolCacheEntry | undefined>;
20
+ setItem: (key: string, value: ToolCacheEntry) => void | Promise<void>;
21
+ deleteItem: (key: string) => void | Promise<void>;
22
+ }
23
+ /**
24
+ * Options for the tool cache middleware.
25
+ */
26
+ export interface ToolCacheMiddlewareOptions {
27
+ /**
28
+ * Maximum number of entries in the cache.
29
+ * When exceeded, the oldest entry is evicted (LRU).
30
+ *
31
+ * Only applies to the default in-memory storage.
32
+ * When a custom `storage` is provided, capacity management is the storage's responsibility.
33
+ *
34
+ * @default 100
35
+ */
36
+ maxSize?: number;
37
+ /**
38
+ * Time-to-live in milliseconds. Entries older than this are not served from cache.
39
+ * @default Infinity (no expiry)
40
+ */
41
+ ttl?: number;
42
+ /**
43
+ * Tool names to cache. If not provided, all tools are cached.
44
+ */
45
+ toolNames?: Array<string>;
46
+ /**
47
+ * Custom function to generate a cache key from tool name and args.
48
+ * Defaults to `JSON.stringify([toolName, args])`.
49
+ */
50
+ keyFn?: (toolName: string, args: unknown) => string;
51
+ /**
52
+ * Custom storage backend. When provided, the middleware uses this instead of
53
+ * the built-in in-memory Map. The storage is responsible for its own capacity
54
+ * management — the `maxSize` option is ignored.
55
+ *
56
+ * @example
57
+ * ```ts
58
+ * toolCacheMiddleware({
59
+ * storage: {
60
+ * getItem: (key) => redisClient.get(key).then(v => v ? JSON.parse(v) : undefined),
61
+ * setItem: (key, value) => redisClient.set(key, JSON.stringify(value)),
62
+ * deleteItem: (key) => redisClient.del(key),
63
+ * },
64
+ * })
65
+ * ```
66
+ */
67
+ storage?: ToolCacheStorage;
68
+ }
69
+ /**
70
+ * Creates a middleware that caches tool call results based on tool name + arguments.
71
+ *
72
+ * When a tool is called with the same name and arguments as a previous call,
73
+ * the cached result is returned immediately without executing the tool.
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * import { chat, toolCacheMiddleware } from '@tanstack/ai'
78
+ *
79
+ * const stream = chat({
80
+ * adapter,
81
+ * messages,
82
+ * tools: [weatherTool, stockTool],
83
+ * middleware: [
84
+ * toolCacheMiddleware({ ttl: 60_000, toolNames: ['getWeather'] }),
85
+ * ],
86
+ * })
87
+ * ```
88
+ */
89
+ export declare function toolCacheMiddleware(options?: ToolCacheMiddlewareOptions): ChatMiddleware;
@@ -0,0 +1,76 @@
1
+ function defaultKeyFn(toolName, args) {
2
+ return JSON.stringify([toolName, args]);
3
+ }
4
+ function createDefaultStorage(maxSize) {
5
+ const cache = /* @__PURE__ */ new Map();
6
+ return {
7
+ getItem: (key) => {
8
+ const entry = cache.get(key);
9
+ if (entry !== void 0) {
10
+ cache.delete(key);
11
+ cache.set(key, entry);
12
+ }
13
+ return entry;
14
+ },
15
+ setItem: (key, value) => {
16
+ if (cache.has(key)) {
17
+ cache.delete(key);
18
+ } else if (cache.size >= maxSize) {
19
+ const firstKey = cache.keys().next().value;
20
+ if (firstKey !== void 0) {
21
+ cache.delete(firstKey);
22
+ }
23
+ }
24
+ cache.set(key, value);
25
+ },
26
+ deleteItem: (key) => {
27
+ cache.delete(key);
28
+ }
29
+ };
30
+ }
31
+ function toolCacheMiddleware(options = {}) {
32
+ const {
33
+ maxSize = 100,
34
+ ttl = Infinity,
35
+ toolNames,
36
+ keyFn = defaultKeyFn,
37
+ storage = createDefaultStorage(maxSize)
38
+ } = options;
39
+ return {
40
+ name: "tool-cache-middleware",
41
+ onBeforeToolCall: async (_ctx, hookCtx) => {
42
+ if (toolNames && !toolNames.includes(hookCtx.toolName)) {
43
+ return void 0;
44
+ }
45
+ const key = keyFn(hookCtx.toolName, hookCtx.args);
46
+ const entry = await storage.getItem(key);
47
+ if (entry) {
48
+ const age = Date.now() - entry.timestamp;
49
+ if (age < ttl) {
50
+ return { type: "skip", result: entry.result };
51
+ }
52
+ await storage.deleteItem(key);
53
+ }
54
+ return void 0;
55
+ },
56
+ onAfterToolCall: async (_ctx, info) => {
57
+ if (!info.ok) return;
58
+ if (toolNames && !toolNames.includes(info.toolName)) return;
59
+ let parsedArgs;
60
+ try {
61
+ parsedArgs = JSON.parse(info.toolCall.function.arguments.trim() || "{}");
62
+ } catch {
63
+ return;
64
+ }
65
+ const key = keyFn(info.toolName, parsedArgs);
66
+ await storage.setItem(key, {
67
+ result: info.result,
68
+ timestamp: Date.now()
69
+ });
70
+ }
71
+ };
72
+ }
73
+ export {
74
+ toolCacheMiddleware
75
+ };
76
+ //# sourceMappingURL=tool-cache-middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-cache-middleware.js","sources":["../../../../../src/activities/chat/middleware/tool-cache-middleware.ts"],"sourcesContent":["import type { ChatMiddleware } from './types'\n\n/**\n * A cache entry stored by the tool cache middleware.\n */\nexport interface ToolCacheEntry {\n result: unknown\n timestamp: number\n}\n\n/**\n * Custom storage backend for the tool cache middleware.\n *\n * When provided, the middleware delegates all cache operations to this storage\n * instead of using the built-in in-memory Map. This enables external storage\n * backends like Redis, localStorage, databases, etc.\n *\n * All methods may return a Promise for async storage backends.\n */\nexport interface ToolCacheStorage {\n getItem: (\n key: string,\n ) => ToolCacheEntry | undefined | Promise<ToolCacheEntry | undefined>\n setItem: (key: string, value: ToolCacheEntry) => void | Promise<void>\n deleteItem: (key: string) => void | Promise<void>\n}\n\n/**\n * Options for the tool cache middleware.\n */\nexport interface ToolCacheMiddlewareOptions {\n /**\n * Maximum number of entries in the cache.\n * When exceeded, the oldest entry is evicted (LRU).\n *\n * Only applies to the default in-memory storage.\n * When a custom `storage` is provided, capacity management is the storage's responsibility.\n *\n * @default 100\n */\n maxSize?: number\n\n /**\n * Time-to-live in milliseconds. Entries older than this are not served from cache.\n * @default Infinity (no expiry)\n */\n ttl?: number\n\n /**\n * Tool names to cache. If not provided, all tools are cached.\n */\n toolNames?: Array<string>\n\n /**\n * Custom function to generate a cache key from tool name and args.\n * Defaults to `JSON.stringify([toolName, args])`.\n */\n keyFn?: (toolName: string, args: unknown) => string\n\n /**\n * Custom storage backend. When provided, the middleware uses this instead of\n * the built-in in-memory Map. The storage is responsible for its own capacity\n * management — the `maxSize` option is ignored.\n *\n * @example\n * ```ts\n * toolCacheMiddleware({\n * storage: {\n * getItem: (key) => redisClient.get(key).then(v => v ? JSON.parse(v) : undefined),\n * setItem: (key, value) => redisClient.set(key, JSON.stringify(value)),\n * deleteItem: (key) => redisClient.del(key),\n * },\n * })\n * ```\n */\n storage?: ToolCacheStorage\n}\n\nfunction defaultKeyFn(toolName: string, args: unknown): string {\n return JSON.stringify([toolName, args])\n}\n\nfunction createDefaultStorage(maxSize: number): ToolCacheStorage {\n const cache = new Map<string, ToolCacheEntry>()\n\n return {\n getItem: (key) => {\n const entry = cache.get(key)\n if (entry !== undefined) {\n // Refresh recency: delete and re-insert so this key becomes newest\n cache.delete(key)\n cache.set(key, entry)\n }\n return entry\n },\n setItem: (key, value) => {\n // Delete first so re-inserts also refresh recency\n if (cache.has(key)) {\n cache.delete(key)\n } else if (cache.size >= maxSize) {\n // LRU eviction: Map iteration order is insertion order — first key is least recently used\n const firstKey = cache.keys().next().value\n if (firstKey !== undefined) {\n cache.delete(firstKey)\n }\n }\n cache.set(key, value)\n },\n deleteItem: (key) => {\n cache.delete(key)\n },\n }\n}\n\n/**\n * Creates a middleware that caches tool call results based on tool name + arguments.\n *\n * When a tool is called with the same name and arguments as a previous call,\n * the cached result is returned immediately without executing the tool.\n *\n * @example\n * ```ts\n * import { chat, toolCacheMiddleware } from '@tanstack/ai'\n *\n * const stream = chat({\n * adapter,\n * messages,\n * tools: [weatherTool, stockTool],\n * middleware: [\n * toolCacheMiddleware({ ttl: 60_000, toolNames: ['getWeather'] }),\n * ],\n * })\n * ```\n */\nexport function toolCacheMiddleware(\n options: ToolCacheMiddlewareOptions = {},\n): ChatMiddleware {\n const {\n maxSize = 100,\n ttl = Infinity,\n toolNames,\n keyFn = defaultKeyFn,\n storage = createDefaultStorage(maxSize),\n } = options\n\n return {\n name: 'tool-cache-middleware',\n\n onBeforeToolCall: async (_ctx, hookCtx) => {\n if (toolNames && !toolNames.includes(hookCtx.toolName)) {\n return undefined\n }\n\n const key = keyFn(hookCtx.toolName, hookCtx.args)\n const entry = await storage.getItem(key)\n\n if (entry) {\n const age = Date.now() - entry.timestamp\n if (age < ttl) {\n return { type: 'skip', result: entry.result }\n }\n // Expired — remove\n await storage.deleteItem(key)\n }\n\n return undefined\n },\n\n onAfterToolCall: async (_ctx, info) => {\n if (!info.ok) return\n if (toolNames && !toolNames.includes(info.toolName)) return\n\n // Re-derive the key from the raw arguments to match what onBeforeToolCall produces\n let parsedArgs: unknown\n try {\n parsedArgs = JSON.parse(info.toolCall.function.arguments.trim() || '{}')\n } catch {\n return\n }\n\n const key = keyFn(info.toolName, parsedArgs)\n\n await storage.setItem(key, {\n result: info.result,\n timestamp: Date.now(),\n })\n },\n }\n}\n"],"names":[],"mappings":"AA8EA,SAAS,aAAa,UAAkB,MAAuB;AAC7D,SAAO,KAAK,UAAU,CAAC,UAAU,IAAI,CAAC;AACxC;AAEA,SAAS,qBAAqB,SAAmC;AAC/D,QAAM,4BAAY,IAAA;AAElB,SAAO;AAAA,IACL,SAAS,CAAC,QAAQ;AAChB,YAAM,QAAQ,MAAM,IAAI,GAAG;AAC3B,UAAI,UAAU,QAAW;AAEvB,cAAM,OAAO,GAAG;AAChB,cAAM,IAAI,KAAK,KAAK;AAAA,MACtB;AACA,aAAO;AAAA,IACT;AAAA,IACA,SAAS,CAAC,KAAK,UAAU;AAEvB,UAAI,MAAM,IAAI,GAAG,GAAG;AAClB,cAAM,OAAO,GAAG;AAAA,MAClB,WAAW,MAAM,QAAQ,SAAS;AAEhC,cAAM,WAAW,MAAM,KAAA,EAAO,OAAO;AACrC,YAAI,aAAa,QAAW;AAC1B,gBAAM,OAAO,QAAQ;AAAA,QACvB;AAAA,MACF;AACA,YAAM,IAAI,KAAK,KAAK;AAAA,IACtB;AAAA,IACA,YAAY,CAAC,QAAQ;AACnB,YAAM,OAAO,GAAG;AAAA,IAClB;AAAA,EAAA;AAEJ;AAsBO,SAAS,oBACd,UAAsC,IACtB;AAChB,QAAM;AAAA,IACJ,UAAU;AAAA,IACV,MAAM;AAAA,IACN;AAAA,IACA,QAAQ;AAAA,IACR,UAAU,qBAAqB,OAAO;AAAA,EAAA,IACpC;AAEJ,SAAO;AAAA,IACL,MAAM;AAAA,IAEN,kBAAkB,OAAO,MAAM,YAAY;AACzC,UAAI,aAAa,CAAC,UAAU,SAAS,QAAQ,QAAQ,GAAG;AACtD,eAAO;AAAA,MACT;AAEA,YAAM,MAAM,MAAM,QAAQ,UAAU,QAAQ,IAAI;AAChD,YAAM,QAAQ,MAAM,QAAQ,QAAQ,GAAG;AAEvC,UAAI,OAAO;AACT,cAAM,MAAM,KAAK,IAAA,IAAQ,MAAM;AAC/B,YAAI,MAAM,KAAK;AACb,iBAAO,EAAE,MAAM,QAAQ,QAAQ,MAAM,OAAA;AAAA,QACvC;AAEA,cAAM,QAAQ,WAAW,GAAG;AAAA,MAC9B;AAEA,aAAO;AAAA,IACT;AAAA,IAEA,iBAAiB,OAAO,MAAM,SAAS;AACrC,UAAI,CAAC,KAAK,GAAI;AACd,UAAI,aAAa,CAAC,UAAU,SAAS,KAAK,QAAQ,EAAG;AAGrD,UAAI;AACJ,UAAI;AACF,qBAAa,KAAK,MAAM,KAAK,SAAS,SAAS,UAAU,KAAA,KAAU,IAAI;AAAA,MACzE,QAAQ;AACN;AAAA,MACF;AAEA,YAAM,MAAM,MAAM,KAAK,UAAU,UAAU;AAE3C,YAAM,QAAQ,QAAQ,KAAK;AAAA,QACzB,QAAQ,KAAK;AAAA,QACb,WAAW,KAAK,IAAA;AAAA,MAAI,CACrB;AAAA,IACH;AAAA,EAAA;AAEJ;"}
@@ -0,0 +1,405 @@
1
+ import { JSONSchema, ModelMessage, StreamChunk, TokenUsage, Tool, ToolCall } from '../../../types.js';
2
+ import { SystemPrompt } from '../../../system-prompts.js';
3
+ import { Capability, CapabilityHandle, CapabilityRegistry } from './capabilities.js';
4
+ /**
5
+ * Phase of the chat middleware lifecycle.
6
+ * - 'init': Initial config transform before the chat engine starts
7
+ * - 'beforeModel': Before each adapter chatStream call (per agent iteration)
8
+ * - 'modelStream': During model streaming
9
+ * - 'beforeTools': Before tool execution phase
10
+ * - 'afterTools': After tool execution phase
11
+ * - 'structuredOutput': During the final structured-output adapter call (set
12
+ * for chunks from adapter.structuredOutputStream or the synthesized fallback)
13
+ */
14
+ export type ChatMiddlewarePhase = 'init' | 'beforeModel' | 'modelStream' | 'beforeTools' | 'afterTools' | 'structuredOutput';
15
+ /**
16
+ * Stable context object passed to all middleware hooks.
17
+ * Created once per chat() invocation and shared across all hooks.
18
+ */
19
+ export interface ChatMiddlewareContext<TContext = unknown> {
20
+ /** Unique identifier for this chat request */
21
+ requestId: string;
22
+ /** Unique identifier for this stream */
23
+ streamId: string;
24
+ /** AG-UI run identifier for correlating client and server events */
25
+ runId: string;
26
+ /**
27
+ * AG-UI thread identifier — a stable per-conversation ID used to
28
+ * correlate client and server devtools events. Resolves to the
29
+ * caller-provided `threadId` (or legacy `conversationId`), or an
30
+ * auto-generated value when neither is supplied.
31
+ */
32
+ threadId: string;
33
+ /**
34
+ * @deprecated Use `threadId` instead. Retained as an alias of
35
+ * `threadId` so middleware written before the AG-UI rename keeps
36
+ * working unchanged. Will be removed in a future major release.
37
+ */
38
+ conversationId?: string;
39
+ /** Current lifecycle phase */
40
+ phase: ChatMiddlewarePhase;
41
+ /** Current agent loop iteration (0-indexed) */
42
+ iteration: number;
43
+ /** Running count of chunks yielded so far */
44
+ chunkIndex: number;
45
+ /** Abort signal from the chat request */
46
+ signal?: AbortSignal;
47
+ /** Abort the chat run with a reason */
48
+ abort: (reason?: string) => void;
49
+ /** Runtime context provided by chat() options */
50
+ context: TContext;
51
+ /**
52
+ * Defer a non-blocking side-effect promise.
53
+ * Deferred promises do not block streaming and are awaited
54
+ * after the terminal hook (onFinish/onAbort/onError).
55
+ */
56
+ defer: (promise: Promise<unknown>) => void;
57
+ /**
58
+ * Which activity this context describes — always `'chat'`. Present so the
59
+ * chat context structurally satisfies the base `GenerationMiddlewareContext`,
60
+ * letting an observe-only middleware authored against the base (e.g.
61
+ * `otelMiddleware`) run on both chat and media activities.
62
+ */
63
+ activity: 'chat';
64
+ /** Provider name (e.g., 'openai', 'anthropic') */
65
+ provider: string;
66
+ /** Model identifier (e.g., 'gpt-4o') */
67
+ model: string;
68
+ /** Source of the chat invocation — always 'server' for server-side chat */
69
+ source: 'client' | 'server';
70
+ /** Whether the chat is streaming */
71
+ streaming: boolean;
72
+ /** System prompts configured for this chat */
73
+ systemPrompts: Array<SystemPrompt>;
74
+ /** Names of configured tools, if any */
75
+ toolNames?: Array<string>;
76
+ /** Flattened generation options (metadata) */
77
+ options?: Record<string, unknown> | undefined;
78
+ /** Provider-specific model options */
79
+ modelOptions?: Record<string, unknown> | undefined;
80
+ /** Number of messages at the start of the request */
81
+ messageCount: number;
82
+ /** Whether tools are configured */
83
+ hasTools: boolean;
84
+ /** Current assistant message ID (changes per iteration) */
85
+ currentMessageId: string | null;
86
+ /** Accumulated text content for the current iteration */
87
+ accumulatedContent: string;
88
+ /** Current messages array (read-only view) */
89
+ messages: ReadonlyArray<ModelMessage>;
90
+ /** Generate a unique ID with the given prefix */
91
+ createId: (prefix: string) => string;
92
+ /**
93
+ * Capability bookkeeping for this request. Populated by middleware `setup`
94
+ * hooks (via `provide` accessors) and read by later middleware (via `get`
95
+ * accessors). Prefer the accessors returned by `createCapability` over using
96
+ * this directly. Orthogonal to `context` (the user runtime context).
97
+ */
98
+ capabilities: CapabilityRegistry;
99
+ /**
100
+ * Read a provided capability by its handle. Equivalent to the handle's own
101
+ * `get` accessor (`getX(ctx)`); throws if the capability was never provided.
102
+ */
103
+ get: <TValue>(capability: Capability<TValue>) => TValue;
104
+ /**
105
+ * Read a capability by its handle, returning `undefined` if it was never
106
+ * provided (never throws).
107
+ */
108
+ getOptional: <TValue>(capability: Capability<TValue>) => TValue | undefined;
109
+ /**
110
+ * Provide a capability value. Equivalent to the handle's own `provide`
111
+ * accessor (`provideX(ctx, value)`). Typically called from `setup`.
112
+ */
113
+ provide: <TValue>(capability: Capability<TValue>, value: TValue) => void;
114
+ }
115
+ /**
116
+ * Chat configuration that middleware can observe or transform.
117
+ * This is a subset of the chat engine's effective configuration
118
+ * that middleware is allowed to modify.
119
+ */
120
+ export interface ChatMiddlewareConfig {
121
+ messages: Array<ModelMessage>;
122
+ systemPrompts: Array<SystemPrompt>;
123
+ tools: Array<Tool>;
124
+ metadata?: Record<string, unknown> | undefined;
125
+ modelOptions?: Record<string, unknown> | undefined;
126
+ }
127
+ /**
128
+ * Config passed to onStructuredOutputConfig.
129
+ *
130
+ * Mirrors ChatMiddlewareConfig minus `tools` (the final structured-output call
131
+ * is a single typed-response request, not an agentic loop — tools cannot be
132
+ * forwarded to it), plus the `outputSchema` being sent to the provider.
133
+ * Middleware may transform the schema (e.g., inject $defs, strip
134
+ * vendor-incompatible keywords) by returning a partial that includes
135
+ * `outputSchema`.
136
+ */
137
+ export interface StructuredOutputMiddlewareConfig extends Omit<ChatMiddlewareConfig, 'tools'> {
138
+ /** JSON Schema being sent to the provider for structured output. */
139
+ outputSchema: JSONSchema;
140
+ }
141
+ /**
142
+ * Context provided to tool call hooks (onBeforeToolCall / onAfterToolCall).
143
+ */
144
+ export interface ToolCallHookContext {
145
+ /** The tool call being executed */
146
+ toolCall: ToolCall;
147
+ /** The resolved tool definition, if found */
148
+ tool: Tool | undefined;
149
+ /** Parsed arguments for the tool call */
150
+ args: unknown;
151
+ /** Name of the tool */
152
+ toolName: string;
153
+ /** ID of the tool call */
154
+ toolCallId: string;
155
+ }
156
+ /**
157
+ * Decision returned from onBeforeToolCall.
158
+ * - undefined/void: continue with normal execution
159
+ * - { type: 'transformArgs', args }: replace args used for execution
160
+ * - { type: 'skip', result }: skip execution, use provided result
161
+ * - { type: 'abort', reason }: abort the entire chat run
162
+ */
163
+ export type BeforeToolCallDecision = void | undefined | null | {
164
+ type: 'transformArgs';
165
+ args: unknown;
166
+ } | {
167
+ type: 'skip';
168
+ result: unknown;
169
+ } | {
170
+ type: 'abort';
171
+ reason?: string;
172
+ };
173
+ /**
174
+ * Outcome information provided to onAfterToolCall.
175
+ */
176
+ export interface AfterToolCallInfo {
177
+ /** The tool call that was executed */
178
+ toolCall: ToolCall;
179
+ /** The resolved tool definition */
180
+ tool: Tool | undefined;
181
+ /** Name of the tool */
182
+ toolName: string;
183
+ /** ID of the tool call */
184
+ toolCallId: string;
185
+ /** Whether the execution succeeded */
186
+ ok: boolean;
187
+ /** Duration of tool execution in milliseconds */
188
+ duration: number;
189
+ /** The result (if ok) or error (if not ok) */
190
+ result?: unknown;
191
+ error?: unknown;
192
+ }
193
+ /**
194
+ * Information passed to onIteration at the start of each agent loop iteration.
195
+ */
196
+ export interface IterationInfo {
197
+ /** 0-based iteration index */
198
+ iteration: number;
199
+ /** The assistant message ID created for this iteration */
200
+ messageId: string;
201
+ }
202
+ /**
203
+ * Aggregate information passed to onToolPhaseComplete after all tool calls
204
+ * in an iteration have been processed.
205
+ */
206
+ export interface ToolPhaseCompleteInfo {
207
+ /** Tool calls that were assigned to the assistant message */
208
+ toolCalls: Array<ToolCall>;
209
+ /** Completed tool results */
210
+ results: Array<{
211
+ toolCallId: string;
212
+ toolName: string;
213
+ result: unknown;
214
+ duration?: number;
215
+ }>;
216
+ /** Tools that need user approval */
217
+ needsApproval: Array<{
218
+ toolCallId: string;
219
+ toolName: string;
220
+ input: unknown;
221
+ approvalId: string;
222
+ }>;
223
+ /** Tools that need client-side execution */
224
+ needsClientExecution: Array<{
225
+ toolCallId: string;
226
+ toolName: string;
227
+ input: unknown;
228
+ }>;
229
+ }
230
+ /**
231
+ * Token usage statistics passed to the onUsage hook.
232
+ * Extracted from the RUN_FINISHED chunk when usage data is present.
233
+ *
234
+ * Includes optional provider-reported `cost`/`costDetails` (see {@link TokenUsage}).
235
+ * Kept as an interface extending `TokenUsage` to preserve declaration merging for
236
+ * this publicly exported type.
237
+ */
238
+ export interface UsageInfo extends TokenUsage {
239
+ }
240
+ /**
241
+ * Information passed to onFinish.
242
+ */
243
+ export interface FinishInfo {
244
+ /** The finish reason from the last model response */
245
+ finishReason: string | null;
246
+ /** Total duration of the chat run in milliseconds */
247
+ duration: number;
248
+ /** Final accumulated text content */
249
+ content: string;
250
+ /** Final usage totals, if available (optionally including provider-reported cost) */
251
+ usage?: TokenUsage | undefined;
252
+ }
253
+ /**
254
+ * Information passed to onAbort.
255
+ */
256
+ export interface AbortInfo {
257
+ /** The reason for the abort, if provided */
258
+ reason?: string;
259
+ /** Duration until abort in milliseconds */
260
+ duration: number;
261
+ }
262
+ /**
263
+ * Information passed to onError.
264
+ */
265
+ export interface ErrorInfo {
266
+ /** The error that caused the failure */
267
+ error: unknown;
268
+ /** Duration until error in milliseconds */
269
+ duration: number;
270
+ }
271
+ /**
272
+ * Chat middleware interface.
273
+ *
274
+ * All hooks are optional. Middleware is composed in array order:
275
+ * - `onConfig`: config piped through middlewares in order (first transform influences later)
276
+ * - `onChunk`: each output chunk is fed into the next middleware in order
277
+ *
278
+ * @example Logging middleware
279
+ * ```ts
280
+ * const loggingMiddleware: ChatMiddleware = {
281
+ * name: 'logging',
282
+ * onStart(ctx) { console.log('Chat started', ctx.requestId) },
283
+ * onChunk(ctx, chunk) { console.log('Chunk:', chunk.type) },
284
+ * onFinish(ctx, info) { console.log('Done:', info.duration, 'ms') },
285
+ * }
286
+ * ```
287
+ *
288
+ * @example Redaction middleware
289
+ * ```ts
290
+ * const redactionMiddleware: ChatMiddleware = {
291
+ * name: 'redaction',
292
+ * onChunk(ctx, chunk) {
293
+ * if (chunk.type === 'TEXT_MESSAGE_CONTENT') {
294
+ * return { ...chunk, delta: redact(chunk.delta) }
295
+ * }
296
+ * },
297
+ * }
298
+ * ```
299
+ */
300
+ export interface ChatMiddleware<TContext = unknown> {
301
+ /** Optional name for debugging and identification */
302
+ name?: string;
303
+ /**
304
+ * Capabilities this middleware requires. `chat()` validates that some
305
+ * middleware (or the adapter) provides each one; unsatisfied requirements are
306
+ * a compile-time error (array coverage / builder) and a runtime error before
307
+ * the adapter runs.
308
+ */
309
+ requires?: ReadonlyArray<CapabilityHandle>;
310
+ /**
311
+ * Capabilities this middleware provides. Each declared capability MUST be
312
+ * provided (via its `provide` accessor) inside `setup`, or `chat()` throws
313
+ * after the setup phase.
314
+ */
315
+ provides?: ReadonlyArray<CapabilityHandle>;
316
+ /**
317
+ * Capabilities this middleware uses if present but does not require.
318
+ * Non-gating: never causes a validation error. Read with
319
+ * `getX(ctx, { optional: true })`.
320
+ */
321
+ optionalRequires?: ReadonlyArray<CapabilityHandle>;
322
+ /**
323
+ * Provisioning hook. Runs FIRST — before `onConfig` (init) — across all
324
+ * middleware in array order. Use it to call `provide` accessors so later
325
+ * middleware (`onConfig` onward) can consume the capabilities. Receives the
326
+ * stable context; does NOT receive the mutable config.
327
+ */
328
+ setup?: (ctx: ChatMiddlewareContext<TContext>) => void | Promise<void>;
329
+ /**
330
+ * Called to observe or transform the chat configuration.
331
+ * Called at init and at the beginning of each agent iteration.
332
+ *
333
+ * Return a partial config to merge with the current config, or void to pass through.
334
+ * Only the fields you return are overwritten — everything else is preserved.
335
+ */
336
+ onConfig?: (ctx: ChatMiddlewareContext<TContext>, config: ChatMiddlewareConfig) => void | null | Partial<ChatMiddlewareConfig> | Promise<void | null | Partial<ChatMiddlewareConfig>>;
337
+ /**
338
+ * Called at the start of the final structured-output call (when the chat
339
+ * was invoked with outputSchema). Pipes through middleware in order, like
340
+ * onConfig, but with access to the JSON Schema being sent to the provider.
341
+ *
342
+ * Return a partial to shallow-merge into the current config, or void to
343
+ * pass through.
344
+ *
345
+ * Fires BEFORE onConfig at the structured-output boundary. onConfig also
346
+ * re-fires at the same boundary with ctx.phase === 'structuredOutput',
347
+ * receiving the post-onStructuredOutputConfig view of the config (minus
348
+ * outputSchema). Use onConfig for general-purpose transforms that apply
349
+ * to every adapter call; use this hook when you need to transform the
350
+ * outputSchema or apply structured-output-specific behavior.
351
+ */
352
+ onStructuredOutputConfig?: (ctx: ChatMiddlewareContext<TContext>, config: StructuredOutputMiddlewareConfig) => void | null | Partial<StructuredOutputMiddlewareConfig> | Promise<void | null | Partial<StructuredOutputMiddlewareConfig>>;
353
+ /**
354
+ * Called when the chat run starts (after initial onConfig).
355
+ */
356
+ onStart?: (ctx: ChatMiddlewareContext<TContext>) => void | Promise<void>;
357
+ /**
358
+ * Called at the start of each agent loop iteration, after a new assistant message ID
359
+ * is created. Use this to observe iteration boundaries.
360
+ */
361
+ onIteration?: (ctx: ChatMiddlewareContext<TContext>, info: IterationInfo) => void | Promise<void>;
362
+ /**
363
+ * Called for every chunk yielded by chat().
364
+ * Can observe, transform, expand, or drop chunks.
365
+ *
366
+ * @returns void (pass through), chunk (replace), chunk[] (expand), null (drop)
367
+ */
368
+ onChunk?: (ctx: ChatMiddlewareContext<TContext>, chunk: StreamChunk) => void | StreamChunk | Array<StreamChunk> | null | Promise<void | StreamChunk | Array<StreamChunk> | null>;
369
+ /**
370
+ * Called before a tool is executed.
371
+ * Can observe, transform args, skip execution, or abort the run.
372
+ */
373
+ onBeforeToolCall?: (ctx: ChatMiddlewareContext<TContext>, hookCtx: ToolCallHookContext) => BeforeToolCallDecision | Promise<BeforeToolCallDecision>;
374
+ /**
375
+ * Called after a tool execution completes (success or failure).
376
+ */
377
+ onAfterToolCall?: (ctx: ChatMiddlewareContext<TContext>, info: AfterToolCallInfo) => void | Promise<void>;
378
+ /**
379
+ * Called after all tool calls in an iteration have been processed.
380
+ * Provides aggregate data about tool execution results, approvals, and client tools.
381
+ */
382
+ onToolPhaseComplete?: (ctx: ChatMiddlewareContext<TContext>, info: ToolPhaseCompleteInfo) => void | Promise<void>;
383
+ /**
384
+ * Called when usage data is available from a RUN_FINISHED chunk.
385
+ * Called once per model iteration that reports usage.
386
+ */
387
+ onUsage?: (ctx: ChatMiddlewareContext<TContext>, usage: UsageInfo) => void | Promise<void>;
388
+ /**
389
+ * Called when the chat run completes normally.
390
+ * Exactly one of onFinish/onAbort/onError will be called per run.
391
+ */
392
+ onFinish?: (ctx: ChatMiddlewareContext<TContext>, info: FinishInfo) => void | Promise<void>;
393
+ /**
394
+ * Called when the chat run is aborted.
395
+ * Exactly one of onFinish/onAbort/onError will be called per run.
396
+ */
397
+ onAbort?: (ctx: ChatMiddlewareContext<TContext>, info: AbortInfo) => void | Promise<void>;
398
+ /**
399
+ * Called when the chat run encounters an unhandled error.
400
+ * Exactly one of onFinish/onAbort/onError will be called per run.
401
+ */
402
+ onError?: (ctx: ChatMiddlewareContext<TContext>, info: ErrorInfo) => void | Promise<void>;
403
+ }
404
+ /** A `ChatMiddleware` with a permissive context — for use as a constraint. */
405
+ export type AnyChatMiddleware = ChatMiddleware<any>;
@@ -0,0 +1,19 @@
1
+ import { CapabilityHandle } from './capabilities.js';
2
+ import { AnyChatMiddleware } from './types.js';
3
+ /** Minimal adapter shape needed for capability validation. */
4
+ interface CapabilityRequiringAdapter {
5
+ name: string;
6
+ requires?: ReadonlyArray<CapabilityHandle>;
7
+ }
8
+ /**
9
+ * Runtime validation: every required capability (from middleware `requires` and
10
+ * the adapter's `requires`) must be provided by some middleware's `provides`.
11
+ * `optionalRequires` is never gating. Throws a clear error otherwise.
12
+ *
13
+ * Presence only — ORDER is not validated here (a provider may appear after its
14
+ * consumer in the array and still pass). Use the `createChatMiddleware()`
15
+ * builder for compile-time order enforcement; at runtime, a consumer that reads
16
+ * a not-yet-provided capability during `setup` fails loud via its getter.
17
+ */
18
+ export declare function validateCapabilities(middlewares: ReadonlyArray<AnyChatMiddleware>, adapter: CapabilityRequiringAdapter): void;
19
+ export {};