@tanstack/ai 0.42.0 → 0.43.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. package/README.md +15 -1
  2. package/dist/esm/activities/chat/adapter.js +23 -16
  3. package/dist/esm/activities/chat/adapter.js.map +1 -1
  4. package/dist/esm/activities/chat/agent-loop-strategies.d.ts +5 -36
  5. package/dist/esm/activities/chat/agent-loop-strategies.js +75 -21
  6. package/dist/esm/activities/chat/agent-loop-strategies.js.map +1 -1
  7. package/dist/esm/activities/chat/cancel.d.ts +40 -0
  8. package/dist/esm/activities/chat/cancel.js +54 -0
  9. package/dist/esm/activities/chat/cancel.js.map +1 -0
  10. package/dist/esm/activities/chat/index.d.ts +28 -21
  11. package/dist/esm/activities/chat/index.js +2100 -1813
  12. package/dist/esm/activities/chat/index.js.map +1 -1
  13. package/dist/esm/activities/chat/mcp/manager.d.ts +2 -2
  14. package/dist/esm/activities/chat/mcp/manager.js +90 -77
  15. package/dist/esm/activities/chat/mcp/manager.js.map +1 -1
  16. package/dist/esm/activities/chat/mcp/types.d.ts +2 -2
  17. package/dist/esm/activities/chat/messages.js +397 -346
  18. package/dist/esm/activities/chat/messages.js.map +1 -1
  19. package/dist/esm/activities/chat/middleware/builder.js +17 -15
  20. package/dist/esm/activities/chat/middleware/builder.js.map +1 -1
  21. package/dist/esm/activities/chat/middleware/capabilities.js +78 -43
  22. package/dist/esm/activities/chat/middleware/capabilities.js.map +1 -1
  23. package/dist/esm/activities/chat/middleware/compose.d.ts +94 -1
  24. package/dist/esm/activities/chat/middleware/compose.js +623 -531
  25. package/dist/esm/activities/chat/middleware/compose.js.map +1 -1
  26. package/dist/esm/activities/chat/middleware/define.js +12 -5
  27. package/dist/esm/activities/chat/middleware/define.js.map +1 -1
  28. package/dist/esm/activities/chat/middleware/index.d.ts +5 -1
  29. package/dist/esm/activities/chat/middleware/locks.d.ts +50 -0
  30. package/dist/esm/activities/chat/middleware/locks.js +71 -0
  31. package/dist/esm/activities/chat/middleware/locks.js.map +1 -0
  32. package/dist/esm/activities/chat/middleware/pending-turn.d.ts +15 -0
  33. package/dist/esm/activities/chat/middleware/pending-turn.js +35 -0
  34. package/dist/esm/activities/chat/middleware/pending-turn.js.map +1 -0
  35. package/dist/esm/activities/chat/middleware/run-disconnect.d.ts +23 -0
  36. package/dist/esm/activities/chat/middleware/run-disconnect.js +42 -0
  37. package/dist/esm/activities/chat/middleware/run-disconnect.js.map +1 -0
  38. package/dist/esm/activities/chat/middleware/run-store.d.ts +283 -0
  39. package/dist/esm/activities/chat/middleware/run-store.js +176 -0
  40. package/dist/esm/activities/chat/middleware/run-store.js.map +1 -0
  41. package/dist/esm/activities/chat/middleware/sandbox-runtime.js +14 -8
  42. package/dist/esm/activities/chat/middleware/sandbox-runtime.js.map +1 -1
  43. package/dist/esm/activities/chat/middleware/tool-cache-middleware.js +79 -70
  44. package/dist/esm/activities/chat/middleware/tool-cache-middleware.js.map +1 -1
  45. package/dist/esm/activities/chat/middleware/types.d.ts +59 -2
  46. package/dist/esm/activities/chat/middleware/validate.js +23 -28
  47. package/dist/esm/activities/chat/middleware/validate.js.map +1 -1
  48. package/dist/esm/activities/chat/stream/json-parser.js +39 -25
  49. package/dist/esm/activities/chat/stream/json-parser.js.map +1 -1
  50. package/dist/esm/activities/chat/stream/message-updaters.js +275 -234
  51. package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
  52. package/dist/esm/activities/chat/stream/processor.d.ts +24 -4
  53. package/dist/esm/activities/chat/stream/processor.js +1341 -1542
  54. package/dist/esm/activities/chat/stream/processor.js.map +1 -1
  55. package/dist/esm/activities/chat/stream/strategies.js +69 -53
  56. package/dist/esm/activities/chat/stream/strategies.js.map +1 -1
  57. package/dist/esm/activities/chat/tools/approval-schema.d.ts +19 -0
  58. package/dist/esm/activities/chat/tools/approval-schema.js +117 -0
  59. package/dist/esm/activities/chat/tools/approval-schema.js.map +1 -0
  60. package/dist/esm/activities/chat/tools/lazy-tool-manager.js +164 -191
  61. package/dist/esm/activities/chat/tools/lazy-tool-manager.js.map +1 -1
  62. package/dist/esm/activities/chat/tools/lazy-tools.js +24 -12
  63. package/dist/esm/activities/chat/tools/lazy-tools.js.map +1 -1
  64. package/dist/esm/activities/chat/tools/schema-converter.js +293 -146
  65. package/dist/esm/activities/chat/tools/schema-converter.js.map +1 -1
  66. package/dist/esm/activities/chat/tools/tool-calls.d.ts +18 -2
  67. package/dist/esm/activities/chat/tools/tool-calls.js +522 -531
  68. package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
  69. package/dist/esm/activities/chat/tools/tool-definition.d.ts +75 -16
  70. package/dist/esm/activities/chat/tools/tool-definition.js +95 -23
  71. package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -1
  72. package/dist/esm/activities/error-payload.js +85 -47
  73. package/dist/esm/activities/error-payload.js.map +1 -1
  74. package/dist/esm/activities/generateAudio/adapter.js +22 -15
  75. package/dist/esm/activities/generateAudio/adapter.js.map +1 -1
  76. package/dist/esm/activities/generateAudio/index.d.ts +4 -0
  77. package/dist/esm/activities/generateAudio/index.js +141 -105
  78. package/dist/esm/activities/generateAudio/index.js.map +1 -1
  79. package/dist/esm/activities/generateImage/adapter.js +22 -15
  80. package/dist/esm/activities/generateImage/adapter.js.map +1 -1
  81. package/dist/esm/activities/generateImage/index.d.ts +4 -0
  82. package/dist/esm/activities/generateImage/index.js +155 -111
  83. package/dist/esm/activities/generateImage/index.js.map +1 -1
  84. package/dist/esm/activities/generateSpeech/adapter.js +22 -15
  85. package/dist/esm/activities/generateSpeech/adapter.js.map +1 -1
  86. package/dist/esm/activities/generateSpeech/index.d.ts +4 -0
  87. package/dist/esm/activities/generateSpeech/index.js +159 -110
  88. package/dist/esm/activities/generateSpeech/index.js.map +1 -1
  89. package/dist/esm/activities/generateTranscription/adapter.js +22 -15
  90. package/dist/esm/activities/generateTranscription/adapter.js.map +1 -1
  91. package/dist/esm/activities/generateTranscription/index.d.ts +4 -0
  92. package/dist/esm/activities/generateTranscription/index.js +159 -100
  93. package/dist/esm/activities/generateTranscription/index.js.map +1 -1
  94. package/dist/esm/activities/generateVideo/adapter.js +36 -29
  95. package/dist/esm/activities/generateVideo/adapter.js.map +1 -1
  96. package/dist/esm/activities/generateVideo/index.d.ts +143 -19
  97. package/dist/esm/activities/generateVideo/index.js +456 -279
  98. package/dist/esm/activities/generateVideo/index.js.map +1 -1
  99. package/dist/esm/activities/generateVideo/snap.js +60 -48
  100. package/dist/esm/activities/generateVideo/snap.js.map +1 -1
  101. package/dist/esm/activities/index.js +8 -34
  102. package/dist/esm/activities/middleware/index.d.ts +1 -1
  103. package/dist/esm/activities/middleware/run.d.ts +10 -0
  104. package/dist/esm/activities/middleware/run.js +53 -29
  105. package/dist/esm/activities/middleware/run.js.map +1 -1
  106. package/dist/esm/activities/middleware/types.d.ts +44 -6
  107. package/dist/esm/activities/stream-generation-result.d.ts +4 -1
  108. package/dist/esm/activities/stream-generation-result.js +79 -44
  109. package/dist/esm/activities/stream-generation-result.js.map +1 -1
  110. package/dist/esm/activities/summarize/adapter.js +22 -15
  111. package/dist/esm/activities/summarize/adapter.js.map +1 -1
  112. package/dist/esm/activities/summarize/chat-stream-summarize.js +252 -202
  113. package/dist/esm/activities/summarize/chat-stream-summarize.js.map +1 -1
  114. package/dist/esm/activities/summarize/index.d.ts +27 -0
  115. package/dist/esm/activities/summarize/index.js +268 -102
  116. package/dist/esm/activities/summarize/index.js.map +1 -1
  117. package/dist/esm/adapter-internals.d.ts +2 -1
  118. package/dist/esm/adapter-internals.js +4 -11
  119. package/dist/esm/client.d.ts +25 -3
  120. package/dist/esm/client.js +131 -64
  121. package/dist/esm/client.js.map +1 -1
  122. package/dist/esm/custom-events.d.ts +76 -0
  123. package/dist/esm/custom-events.js +37 -0
  124. package/dist/esm/custom-events.js.map +1 -0
  125. package/dist/esm/delivery-detach.d.ts +50 -0
  126. package/dist/esm/delivery-detach.js +71 -0
  127. package/dist/esm/delivery-detach.js.map +1 -0
  128. package/dist/esm/delivery-disconnect.d.ts +62 -0
  129. package/dist/esm/delivery-disconnect.js +81 -0
  130. package/dist/esm/delivery-disconnect.js.map +1 -0
  131. package/dist/esm/extend-adapter.js +19 -17
  132. package/dist/esm/extend-adapter.js.map +1 -1
  133. package/dist/esm/index.d.ts +24 -6
  134. package/dist/esm/index.js +30 -98
  135. package/dist/esm/interrupt-resume.d.ts +71 -0
  136. package/dist/esm/interrupt-resume.js +438 -0
  137. package/dist/esm/interrupt-resume.js.map +1 -0
  138. package/dist/esm/interrupt-serialization.d.ts +12 -0
  139. package/dist/esm/interrupt-serialization.js +178 -0
  140. package/dist/esm/interrupt-serialization.js.map +1 -0
  141. package/dist/esm/interrupts.d.ts +84 -0
  142. package/dist/esm/interrupts.js +31 -0
  143. package/dist/esm/interrupts.js.map +1 -0
  144. package/dist/esm/locks.d.ts +10 -0
  145. package/dist/esm/locks.js +2 -0
  146. package/dist/esm/logger/console-logger.js +101 -78
  147. package/dist/esm/logger/console-logger.js.map +1 -1
  148. package/dist/esm/logger/internal-logger.js +104 -89
  149. package/dist/esm/logger/internal-logger.js.map +1 -1
  150. package/dist/esm/logger/resolve.js +54 -49
  151. package/dist/esm/logger/resolve.js.map +1 -1
  152. package/dist/esm/logger/types.d.ts +1 -1
  153. package/dist/esm/middlewares/content-guard.js +142 -148
  154. package/dist/esm/middlewares/content-guard.js.map +1 -1
  155. package/dist/esm/middlewares/index.js +2 -6
  156. package/dist/esm/middlewares/otel.d.ts +3 -1
  157. package/dist/esm/middlewares/otel.js +599 -732
  158. package/dist/esm/middlewares/otel.js.map +1 -1
  159. package/dist/esm/middlewares/usage-attributes.js +47 -40
  160. package/dist/esm/middlewares/usage-attributes.js.map +1 -1
  161. package/dist/esm/realtime/event-emitter.js +24 -25
  162. package/dist/esm/realtime/event-emitter.js.map +1 -1
  163. package/dist/esm/realtime/index.d.ts +5 -9
  164. package/dist/esm/realtime/index.js +29 -6
  165. package/dist/esm/realtime/index.js.map +1 -1
  166. package/dist/esm/scope.d.ts +47 -0
  167. package/dist/esm/stream-durability.d.ts +171 -0
  168. package/dist/esm/stream-durability.js +295 -0
  169. package/dist/esm/stream-durability.js.map +1 -0
  170. package/dist/esm/stream-to-response.d.ts +178 -13
  171. package/dist/esm/stream-to-response.js +663 -115
  172. package/dist/esm/stream-to-response.js.map +1 -1
  173. package/dist/esm/strip-to-spec-middleware.js +30 -16
  174. package/dist/esm/strip-to-spec-middleware.js.map +1 -1
  175. package/dist/esm/system-prompts.js +27 -21
  176. package/dist/esm/system-prompts.js.map +1 -1
  177. package/dist/esm/tool-registry.js +72 -45
  178. package/dist/esm/tool-registry.js.map +1 -1
  179. package/dist/esm/tools/provider-tool.js +14 -5
  180. package/dist/esm/tools/provider-tool.js.map +1 -1
  181. package/dist/esm/types.d.ts +321 -42
  182. package/dist/esm/types.js +2 -0
  183. package/dist/esm/utilities/ag-ui-wire.js +79 -93
  184. package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
  185. package/dist/esm/utilities/chat-params.d.ts +26 -4
  186. package/dist/esm/utilities/chat-params.js +218 -92
  187. package/dist/esm/utilities/chat-params.js.map +1 -1
  188. package/dist/esm/utilities/errors.js +28 -18
  189. package/dist/esm/utilities/errors.js.map +1 -1
  190. package/dist/esm/utilities/media-prompt.js +46 -41
  191. package/dist/esm/utilities/media-prompt.js.map +1 -1
  192. package/dist/esm/utilities/numbers.js +13 -10
  193. package/dist/esm/utilities/numbers.js.map +1 -1
  194. package/dist/esm/utilities/provider-executed.js +20 -11
  195. package/dist/esm/utilities/provider-executed.js.map +1 -1
  196. package/dist/esm/utilities/sampling-keys.js +31 -19
  197. package/dist/esm/utilities/sampling-keys.js.map +1 -1
  198. package/dist/esm/utilities/tool-result.js +42 -30
  199. package/dist/esm/utilities/tool-result.js.map +1 -1
  200. package/dist/esm/utilities/usage.js +27 -9
  201. package/dist/esm/utilities/usage.js.map +1 -1
  202. package/dist/esm/utils.js +26 -18
  203. package/dist/esm/utils.js.map +1 -1
  204. package/package.json +10 -6
  205. package/skills/ai-core/SKILL.md +69 -18
  206. package/skills/ai-core/adapter-configuration/SKILL.md +44 -21
  207. package/skills/ai-core/adapter-configuration/references/anthropic-adapter.md +1 -3
  208. package/skills/ai-core/adapter-configuration/references/byteplus-adapter.md +148 -0
  209. package/skills/ai-core/adapter-configuration/references/gemini-adapter.md +2 -6
  210. package/skills/ai-core/adapter-configuration/references/groq-adapter.md +2 -6
  211. package/skills/ai-core/adapter-configuration/references/openai-adapter.md +1 -3
  212. package/skills/ai-core/ag-ui-protocol/SKILL.md +1 -1
  213. package/skills/ai-core/chat-experience/SKILL.md +98 -11
  214. package/skills/ai-core/client-persistence/SKILL.md +277 -0
  215. package/skills/ai-core/custom-backend-integration/SKILL.md +1 -1
  216. package/skills/ai-core/debug-logging/SKILL.md +1 -1
  217. package/skills/ai-core/locks/SKILL.md +143 -0
  218. package/skills/ai-core/media-generation/SKILL.md +144 -12
  219. package/skills/ai-core/middleware/SKILL.md +258 -33
  220. package/skills/ai-core/structured-outputs/SKILL.md +1 -1
  221. package/skills/ai-core/tool-calling/SKILL.md +54 -61
  222. package/src/activities/chat/agent-loop-strategies.ts +5 -39
  223. package/src/activities/chat/cancel.ts +81 -0
  224. package/src/activities/chat/index.ts +1091 -200
  225. package/src/activities/chat/mcp/manager.ts +4 -4
  226. package/src/activities/chat/mcp/types.ts +2 -2
  227. package/src/activities/chat/messages.ts +5 -3
  228. package/src/activities/chat/middleware/builder.ts +1 -1
  229. package/src/activities/chat/middleware/compose.ts +186 -9
  230. package/src/activities/chat/middleware/index.ts +26 -0
  231. package/src/activities/chat/middleware/locks.ts +102 -0
  232. package/src/activities/chat/middleware/pending-turn.ts +47 -0
  233. package/src/activities/chat/middleware/run-disconnect.ts +62 -0
  234. package/src/activities/chat/middleware/run-store.ts +412 -0
  235. package/src/activities/chat/middleware/types.ts +62 -1
  236. package/src/activities/chat/stream/processor.ts +189 -5
  237. package/src/activities/chat/tools/approval-schema.ts +205 -0
  238. package/src/activities/chat/tools/tool-calls.ts +106 -13
  239. package/src/activities/chat/tools/tool-definition.ts +210 -39
  240. package/src/activities/generateAudio/index.ts +20 -3
  241. package/src/activities/generateImage/index.ts +20 -3
  242. package/src/activities/generateSpeech/index.ts +25 -3
  243. package/src/activities/generateTranscription/index.ts +26 -3
  244. package/src/activities/generateVideo/index.ts +345 -82
  245. package/src/activities/middleware/index.ts +2 -0
  246. package/src/activities/middleware/run.ts +31 -0
  247. package/src/activities/middleware/types.ts +49 -5
  248. package/src/activities/stream-generation-result.ts +30 -2
  249. package/src/activities/summarize/chat-stream-summarize.ts +5 -0
  250. package/src/activities/summarize/index.ts +200 -10
  251. package/src/adapter-internals.ts +10 -1
  252. package/src/client.ts +244 -0
  253. package/src/custom-events.ts +107 -0
  254. package/src/delivery-detach.ts +72 -0
  255. package/src/delivery-disconnect.ts +84 -0
  256. package/src/index.ts +138 -1
  257. package/src/interrupt-resume.ts +824 -0
  258. package/src/interrupt-serialization.ts +183 -0
  259. package/src/interrupts.ts +146 -0
  260. package/src/locks.ts +17 -0
  261. package/src/logger/types.ts +1 -1
  262. package/src/middlewares/otel.ts +23 -5
  263. package/src/realtime/index.ts +5 -9
  264. package/src/scope.ts +47 -0
  265. package/src/stream-durability.ts +598 -0
  266. package/src/stream-to-response.ts +1051 -95
  267. package/src/strip-to-spec-middleware.ts +3 -3
  268. package/src/types.ts +405 -45
  269. package/src/utilities/chat-params.ts +245 -55
  270. package/dist/esm/activities/index.js.map +0 -1
  271. package/dist/esm/adapter-internals.js.map +0 -1
  272. package/dist/esm/index.js.map +0 -1
  273. package/dist/esm/middlewares/index.js.map +0 -1
@@ -1,194 +1,167 @@
1
1
  import { convertSchemaToJsonSchema } from "./schema-converter.js";
2
2
  import { renderLazyCatalogEntry } from "./lazy-tools.js";
3
- const DISCOVERY_TOOL_NAME = "__lazy__tool__discovery__";
4
- class LazyToolManager {
5
- eagerTools;
6
- lazyToolMap;
7
- discoveredTools;
8
- hasNewDiscoveries;
9
- discoveryTool;
10
- lazyToolsConfig;
11
- constructor(tools, messages, lazyToolsConfig = {}) {
12
- this.lazyToolsConfig = lazyToolsConfig;
13
- const eager = [];
14
- this.lazyToolMap = /* @__PURE__ */ new Map();
15
- this.discoveredTools = /* @__PURE__ */ new Set();
16
- this.hasNewDiscoveries = false;
17
- for (const tool of tools) {
18
- if (tool.lazy) {
19
- this.lazyToolMap.set(tool.name, tool);
20
- } else {
21
- eager.push(tool);
22
- }
23
- }
24
- this.eagerTools = eager;
25
- if (this.lazyToolMap.size === 0) {
26
- this.discoveryTool = null;
27
- return;
28
- }
29
- this.scanMessageHistory(messages);
30
- this.discoveryTool = this.createDiscoveryTool();
31
- }
32
- /**
33
- * Returns the set of tools that should be sent to the LLM:
34
- * eager tools + discovered lazy tools + discovery tool (if undiscovered tools remain).
35
- * Resets the hasNewDiscoveries flag.
36
- */
37
- getActiveTools() {
38
- this.hasNewDiscoveries = false;
39
- const active = [...this.eagerTools];
40
- for (const name of this.discoveredTools) {
41
- const tool = this.lazyToolMap.get(name);
42
- if (tool) {
43
- active.push(tool);
44
- }
45
- }
46
- if (this.discoveryTool && this.discoveredTools.size < this.lazyToolMap.size) {
47
- active.push(this.discoveryTool);
48
- }
49
- return active;
50
- }
51
- /**
52
- * Returns the tools that should be available for *execution* this turn.
53
- *
54
- * This is the advertised set (`getActiveTools()`, passed in as `activeTools`)
55
- * plus the discovery tool when a pending call references it but it is no
56
- * longer advertised. Once every lazy tool has been discovered the discovery
57
- * tool is dropped from the advertised set, but a model may still re-request
58
- * discovery (long context / hallucination); keeping it executable lets that
59
- * call return the schemas again instead of failing with "Unknown tool".
60
- *
61
- * The advertised set is intentionally left unchanged — only execution lookup
62
- * is widened. Operates on the already-built `activeTools`: it must NOT call
63
- * `getActiveTools()`, which would reset `hasNewDiscoveries` before the
64
- * post-execution refresh check in the agent loop.
65
- */
66
- getExecutableTools(activeTools, pendingToolCallNames) {
67
- if (this.discoveryTool && pendingToolCallNames.includes(DISCOVERY_TOOL_NAME) && !activeTools.some((t) => t.name === DISCOVERY_TOOL_NAME)) {
68
- return [...activeTools, this.discoveryTool];
69
- }
70
- return activeTools;
71
- }
72
- /**
73
- * Returns whether new tools have been discovered since the last getActiveTools() call.
74
- */
75
- hasNewlyDiscoveredTools() {
76
- return this.hasNewDiscoveries;
77
- }
78
- /**
79
- * Returns true if the given name is a lazy tool that has not yet been discovered.
80
- */
81
- isUndiscoveredLazyTool(name) {
82
- return this.lazyToolMap.has(name) && !this.discoveredTools.has(name);
83
- }
84
- /**
85
- * Returns a helpful error message for when an undiscovered lazy tool is called.
86
- */
87
- getUndiscoveredToolError(name) {
88
- return `Error: Tool '${name}' must be discovered first. Call ${DISCOVERY_TOOL_NAME} with toolNames: ['${name}'] to discover it.`;
89
- }
90
- /**
91
- * Scans message history to find previously discovered lazy tools.
92
- * Looks for assistant messages with discovery tool calls and their
93
- * corresponding tool result messages.
94
- */
95
- scanMessageHistory(messages) {
96
- const discoveryCallIds = /* @__PURE__ */ new Set();
97
- for (const msg of messages) {
98
- if (msg.role === "assistant" && msg.toolCalls) {
99
- for (const tc of msg.toolCalls) {
100
- if (tc.function.name === DISCOVERY_TOOL_NAME) {
101
- discoveryCallIds.add(tc.id);
102
- }
103
- }
104
- }
105
- }
106
- if (discoveryCallIds.size === 0) return;
107
- for (const msg of messages) {
108
- if (msg.role === "tool" && msg.toolCallId && discoveryCallIds.has(msg.toolCallId)) {
109
- try {
110
- const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
111
- const parsed = JSON.parse(content);
112
- if (parsed && Array.isArray(parsed.tools)) {
113
- for (const tool of parsed.tools) {
114
- if (tool && typeof tool.name === "string" && this.lazyToolMap.has(tool.name)) {
115
- this.discoveredTools.add(tool.name);
116
- }
117
- }
118
- }
119
- } catch {
120
- }
121
- }
122
- }
123
- }
124
- /**
125
- * Creates the synthetic discovery tool that the LLM can call
126
- * to discover lazy tools' descriptions and schemas.
127
- */
128
- createDiscoveryTool() {
129
- const undiscoveredNames = () => {
130
- const names = [];
131
- for (const [name] of this.lazyToolMap) {
132
- if (!this.discoveredTools.has(name)) {
133
- names.push(name);
134
- }
135
- }
136
- return names;
137
- };
138
- const lazyToolMap = this.lazyToolMap;
139
- const include = this.lazyToolsConfig.includeDescription ?? "none";
140
- const allLazyEntries = Array.from(this.lazyToolMap.values()).map(
141
- (t) => renderLazyCatalogEntry(t.name, t.description, include)
142
- );
143
- const description = `You have access to additional tools that can be discovered. Available tools: [${allLazyEntries.join(", ")}]. Call this tool with a list of tool names to discover their full descriptions and argument schemas before using them.`;
144
- const manager = this;
145
- return {
146
- name: DISCOVERY_TOOL_NAME,
147
- description,
148
- inputSchema: {
149
- type: "object",
150
- properties: {
151
- toolNames: {
152
- type: "array",
153
- items: { type: "string" },
154
- description: "List of tool names to discover. Each name must match one of the available tools."
155
- }
156
- },
157
- required: ["toolNames"]
158
- },
159
- execute: (args) => {
160
- const tools = [];
161
- const errors = [];
162
- for (const name of args.toolNames) {
163
- const tool = lazyToolMap.get(name);
164
- if (tool) {
165
- if (!manager.discoveredTools.has(name)) {
166
- manager.discoveredTools.add(name);
167
- manager.hasNewDiscoveries = true;
168
- }
169
- const jsonSchema = tool.inputSchema ? convertSchemaToJsonSchema(tool.inputSchema) : void 0;
170
- tools.push({
171
- name: tool.name,
172
- description: tool.description,
173
- ...jsonSchema ? { inputSchema: jsonSchema } : {}
174
- });
175
- } else {
176
- errors.push(
177
- `Unknown tool: '${name}'. Available tools: [${undiscoveredNames().join(", ")}]`
178
- );
179
- }
180
- }
181
- const result = { tools };
182
- if (errors.length > 0) {
183
- result.errors = errors;
184
- }
185
- return result;
186
- }
187
- };
188
- }
189
- }
190
- export {
191
- DISCOVERY_TOOL_NAME,
192
- LazyToolManager
3
+ //#region src/activities/chat/tools/lazy-tool-manager.ts
4
+ /**
5
+ * Name of the synthetic tool the LLM calls to discover lazy tools.
6
+ *
7
+ * Exported so callers building custom message-compaction / history-trimming
8
+ * logic can reference the discovery tool by constant instead of hard-coding
9
+ * the string (which is an internal contract that could change).
10
+ */
11
+ var DISCOVERY_TOOL_NAME = "__lazy__tool__discovery__";
12
+ /**
13
+ * Manages lazy tool discovery for the chat agent loop.
14
+ *
15
+ * Lazy tools are not sent to the LLM initially. Instead, a synthetic
16
+ * "discovery tool" is provided that lets the LLM discover lazy tools
17
+ * by name, receiving their full descriptions and schemas on demand.
18
+ */
19
+ var LazyToolManager = class {
20
+ eagerTools;
21
+ lazyToolMap;
22
+ discoveredTools;
23
+ hasNewDiscoveries;
24
+ discoveryTool;
25
+ lazyToolsConfig;
26
+ constructor(tools, messages, lazyToolsConfig = {}) {
27
+ this.lazyToolsConfig = lazyToolsConfig;
28
+ const eager = [];
29
+ this.lazyToolMap = /* @__PURE__ */ new Map();
30
+ this.discoveredTools = /* @__PURE__ */ new Set();
31
+ this.hasNewDiscoveries = false;
32
+ for (const tool of tools) if (tool.lazy) this.lazyToolMap.set(tool.name, tool);
33
+ else eager.push(tool);
34
+ this.eagerTools = eager;
35
+ if (this.lazyToolMap.size === 0) {
36
+ this.discoveryTool = null;
37
+ return;
38
+ }
39
+ this.scanMessageHistory(messages);
40
+ this.discoveryTool = this.createDiscoveryTool();
41
+ }
42
+ /**
43
+ * Returns the set of tools that should be sent to the LLM:
44
+ * eager tools + discovered lazy tools + discovery tool (if undiscovered tools remain).
45
+ * Resets the hasNewDiscoveries flag.
46
+ */
47
+ getActiveTools() {
48
+ this.hasNewDiscoveries = false;
49
+ const active = [...this.eagerTools];
50
+ for (const name of this.discoveredTools) {
51
+ const tool = this.lazyToolMap.get(name);
52
+ if (tool) active.push(tool);
53
+ }
54
+ if (this.discoveryTool && this.discoveredTools.size < this.lazyToolMap.size) active.push(this.discoveryTool);
55
+ return active;
56
+ }
57
+ /**
58
+ * Returns the tools that should be available for *execution* this turn.
59
+ *
60
+ * This is the advertised set (`getActiveTools()`, passed in as `activeTools`)
61
+ * plus the discovery tool when a pending call references it but it is no
62
+ * longer advertised. Once every lazy tool has been discovered the discovery
63
+ * tool is dropped from the advertised set, but a model may still re-request
64
+ * discovery (long context / hallucination); keeping it executable lets that
65
+ * call return the schemas again instead of failing with "Unknown tool".
66
+ *
67
+ * The advertised set is intentionally left unchanged — only execution lookup
68
+ * is widened. Operates on the already-built `activeTools`: it must NOT call
69
+ * `getActiveTools()`, which would reset `hasNewDiscoveries` before the
70
+ * post-execution refresh check in the agent loop.
71
+ */
72
+ getExecutableTools(activeTools, pendingToolCallNames) {
73
+ if (this.discoveryTool && pendingToolCallNames.includes("__lazy__tool__discovery__") && !activeTools.some((t) => t.name === "__lazy__tool__discovery__")) return [...activeTools, this.discoveryTool];
74
+ return activeTools;
75
+ }
76
+ /**
77
+ * Returns whether new tools have been discovered since the last getActiveTools() call.
78
+ */
79
+ hasNewlyDiscoveredTools() {
80
+ return this.hasNewDiscoveries;
81
+ }
82
+ /**
83
+ * Returns true if the given name is a lazy tool that has not yet been discovered.
84
+ */
85
+ isUndiscoveredLazyTool(name) {
86
+ return this.lazyToolMap.has(name) && !this.discoveredTools.has(name);
87
+ }
88
+ /**
89
+ * Returns a helpful error message for when an undiscovered lazy tool is called.
90
+ */
91
+ getUndiscoveredToolError(name) {
92
+ return `Error: Tool '${name}' must be discovered first. Call ${DISCOVERY_TOOL_NAME} with toolNames: ['${name}'] to discover it.`;
93
+ }
94
+ /**
95
+ * Scans message history to find previously discovered lazy tools.
96
+ * Looks for assistant messages with discovery tool calls and their
97
+ * corresponding tool result messages.
98
+ */
99
+ scanMessageHistory(messages) {
100
+ const discoveryCallIds = /* @__PURE__ */ new Set();
101
+ for (const msg of messages) if (msg.role === "assistant" && msg.toolCalls) {
102
+ for (const tc of msg.toolCalls) if (tc.function.name === "__lazy__tool__discovery__") discoveryCallIds.add(tc.id);
103
+ }
104
+ if (discoveryCallIds.size === 0) return;
105
+ for (const msg of messages) if (msg.role === "tool" && msg.toolCallId && discoveryCallIds.has(msg.toolCallId)) try {
106
+ const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
107
+ const parsed = JSON.parse(content);
108
+ if (parsed && Array.isArray(parsed.tools)) {
109
+ for (const tool of parsed.tools) if (tool && typeof tool.name === "string" && this.lazyToolMap.has(tool.name)) this.discoveredTools.add(tool.name);
110
+ }
111
+ } catch {}
112
+ }
113
+ /**
114
+ * Creates the synthetic discovery tool that the LLM can call
115
+ * to discover lazy tools' descriptions and schemas.
116
+ */
117
+ createDiscoveryTool() {
118
+ const undiscoveredNames = () => {
119
+ const names = [];
120
+ for (const [name] of this.lazyToolMap) if (!this.discoveredTools.has(name)) names.push(name);
121
+ return names;
122
+ };
123
+ const lazyToolMap = this.lazyToolMap;
124
+ const include = this.lazyToolsConfig.includeDescription ?? "none";
125
+ const description = `You have access to additional tools that can be discovered. Available tools: [${Array.from(this.lazyToolMap.values()).map((t) => renderLazyCatalogEntry(t.name, t.description, include)).join(", ")}]. Call this tool with a list of tool names to discover their full descriptions and argument schemas before using them.`;
126
+ const manager = this;
127
+ return {
128
+ name: DISCOVERY_TOOL_NAME,
129
+ description,
130
+ inputSchema: {
131
+ type: "object",
132
+ properties: { toolNames: {
133
+ type: "array",
134
+ items: { type: "string" },
135
+ description: "List of tool names to discover. Each name must match one of the available tools."
136
+ } },
137
+ required: ["toolNames"]
138
+ },
139
+ execute: (args) => {
140
+ const tools = [];
141
+ const errors = [];
142
+ for (const name of args.toolNames) {
143
+ const tool = lazyToolMap.get(name);
144
+ if (tool) {
145
+ if (!manager.discoveredTools.has(name)) {
146
+ manager.discoveredTools.add(name);
147
+ manager.hasNewDiscoveries = true;
148
+ }
149
+ const jsonSchema = tool.inputSchema ? convertSchemaToJsonSchema(tool.inputSchema) : void 0;
150
+ tools.push({
151
+ name: tool.name,
152
+ description: tool.description,
153
+ ...jsonSchema ? { inputSchema: jsonSchema } : {}
154
+ });
155
+ } else errors.push(`Unknown tool: '${name}'. Available tools: [${undiscoveredNames().join(", ")}]`);
156
+ }
157
+ const result = { tools };
158
+ if (errors.length > 0) result.errors = errors;
159
+ return result;
160
+ }
161
+ };
162
+ }
193
163
  };
194
- //# sourceMappingURL=lazy-tool-manager.js.map
164
+ //#endregion
165
+ export { DISCOVERY_TOOL_NAME, LazyToolManager };
166
+
167
+ //# sourceMappingURL=lazy-tool-manager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lazy-tool-manager.js","sources":["../../../../../src/activities/chat/tools/lazy-tool-manager.ts"],"sourcesContent":["import { convertSchemaToJsonSchema } from './schema-converter'\nimport { renderLazyCatalogEntry } from './lazy-tools'\nimport type { AnyTool, LazyToolsConfig, Tool } from '../../../types'\n\n/**\n * Name of the synthetic tool the LLM calls to discover lazy tools.\n *\n * Exported so callers building custom message-compaction / history-trimming\n * logic can reference the discovery tool by constant instead of hard-coding\n * the string (which is an internal contract that could change).\n */\nexport const DISCOVERY_TOOL_NAME = '__lazy__tool__discovery__'\n\n/**\n * Manages lazy tool discovery for the chat agent loop.\n *\n * Lazy tools are not sent to the LLM initially. Instead, a synthetic\n * \"discovery tool\" is provided that lets the LLM discover lazy tools\n * by name, receiving their full descriptions and schemas on demand.\n */\nexport class LazyToolManager {\n private readonly eagerTools: ReadonlyArray<Tool>\n private readonly lazyToolMap: Map<string, Tool>\n private readonly discoveredTools: Set<string>\n private hasNewDiscoveries: boolean\n private readonly discoveryTool: Tool | null\n private readonly lazyToolsConfig: LazyToolsConfig\n\n constructor(\n tools: ReadonlyArray<Tool>,\n messages: ReadonlyArray<{\n role: string\n content?: any\n toolCalls?: Array<{\n id: string\n type: string\n function: { name: string; arguments: string }\n }>\n toolCallId?: string\n }>,\n lazyToolsConfig: LazyToolsConfig = {},\n ) {\n this.lazyToolsConfig = lazyToolsConfig\n const eager: Array<Tool> = []\n this.lazyToolMap = new Map()\n this.discoveredTools = new Set()\n this.hasNewDiscoveries = false\n\n // Separate tools into eager and lazy\n for (const tool of tools) {\n if (tool.lazy) {\n this.lazyToolMap.set(tool.name, tool)\n } else {\n eager.push(tool)\n }\n }\n this.eagerTools = eager\n\n // If no lazy tools, no discovery tool needed\n if (this.lazyToolMap.size === 0) {\n this.discoveryTool = null\n return\n }\n\n // Scan message history to pre-populate discoveredTools\n this.scanMessageHistory(messages)\n\n // Create the synthetic discovery tool\n this.discoveryTool = this.createDiscoveryTool()\n }\n\n /**\n * Returns the set of tools that should be sent to the LLM:\n * eager tools + discovered lazy tools + discovery tool (if undiscovered tools remain).\n * Resets the hasNewDiscoveries flag.\n */\n getActiveTools(): Array<Tool> {\n this.hasNewDiscoveries = false\n\n const active: Array<Tool> = [...this.eagerTools]\n\n // Add discovered lazy tools\n for (const name of this.discoveredTools) {\n const tool = this.lazyToolMap.get(name)\n if (tool) {\n active.push(tool)\n }\n }\n\n // Add discovery tool if there are still undiscovered lazy tools\n if (\n this.discoveryTool &&\n this.discoveredTools.size < this.lazyToolMap.size\n ) {\n active.push(this.discoveryTool)\n }\n\n return active\n }\n\n /**\n * Returns the tools that should be available for *execution* this turn.\n *\n * This is the advertised set (`getActiveTools()`, passed in as `activeTools`)\n * plus the discovery tool when a pending call references it but it is no\n * longer advertised. Once every lazy tool has been discovered the discovery\n * tool is dropped from the advertised set, but a model may still re-request\n * discovery (long context / hallucination); keeping it executable lets that\n * call return the schemas again instead of failing with \"Unknown tool\".\n *\n * The advertised set is intentionally left unchanged — only execution lookup\n * is widened. Operates on the already-built `activeTools`: it must NOT call\n * `getActiveTools()`, which would reset `hasNewDiscoveries` before the\n * post-execution refresh check in the agent loop.\n */\n getExecutableTools(\n activeTools: ReadonlyArray<AnyTool>,\n pendingToolCallNames: ReadonlyArray<string>,\n ): ReadonlyArray<AnyTool> {\n if (\n this.discoveryTool &&\n pendingToolCallNames.includes(DISCOVERY_TOOL_NAME) &&\n !activeTools.some((t) => t.name === DISCOVERY_TOOL_NAME)\n ) {\n return [...activeTools, this.discoveryTool]\n }\n return activeTools\n }\n\n /**\n * Returns whether new tools have been discovered since the last getActiveTools() call.\n */\n hasNewlyDiscoveredTools(): boolean {\n return this.hasNewDiscoveries\n }\n\n /**\n * Returns true if the given name is a lazy tool that has not yet been discovered.\n */\n isUndiscoveredLazyTool(name: string): boolean {\n return this.lazyToolMap.has(name) && !this.discoveredTools.has(name)\n }\n\n /**\n * Returns a helpful error message for when an undiscovered lazy tool is called.\n */\n getUndiscoveredToolError(name: string): string {\n return `Error: Tool '${name}' must be discovered first. Call ${DISCOVERY_TOOL_NAME} with toolNames: ['${name}'] to discover it.`\n }\n\n /**\n * Scans message history to find previously discovered lazy tools.\n * Looks for assistant messages with discovery tool calls and their\n * corresponding tool result messages.\n */\n private scanMessageHistory(\n messages: ReadonlyArray<{\n role: string\n content?: any\n toolCalls?: Array<{\n id: string\n type: string\n function: { name: string; arguments: string }\n }>\n toolCallId?: string\n }>,\n ): void {\n // Collect tool call IDs for discovery tool invocations\n const discoveryCallIds = new Set<string>()\n\n for (const msg of messages) {\n if (msg.role === 'assistant' && msg.toolCalls) {\n for (const tc of msg.toolCalls) {\n if (tc.function.name === DISCOVERY_TOOL_NAME) {\n discoveryCallIds.add(tc.id)\n }\n }\n }\n }\n\n if (discoveryCallIds.size === 0) return\n\n // Find corresponding tool result messages\n for (const msg of messages) {\n if (\n msg.role === 'tool' &&\n msg.toolCallId &&\n discoveryCallIds.has(msg.toolCallId)\n ) {\n try {\n const content =\n typeof msg.content === 'string'\n ? msg.content\n : JSON.stringify(msg.content)\n const parsed = JSON.parse(content)\n if (parsed && Array.isArray(parsed.tools)) {\n for (const tool of parsed.tools) {\n if (\n tool &&\n typeof tool.name === 'string' &&\n this.lazyToolMap.has(tool.name)\n ) {\n this.discoveredTools.add(tool.name)\n }\n }\n }\n } catch {\n // Malformed JSON — skip gracefully\n }\n }\n }\n }\n\n /**\n * Creates the synthetic discovery tool that the LLM can call\n * to discover lazy tools' descriptions and schemas.\n */\n private createDiscoveryTool(): Tool {\n const undiscoveredNames = (): Array<string> => {\n const names: Array<string> = []\n for (const [name] of this.lazyToolMap) {\n if (!this.discoveredTools.has(name)) {\n names.push(name)\n }\n }\n return names\n }\n\n const lazyToolMap = this.lazyToolMap\n\n // Build the static description, rendering each entry per includeDescription.\n // With the default 'none' this is byte-identical to the legacy output.\n const include = this.lazyToolsConfig.includeDescription ?? 'none'\n const allLazyEntries = Array.from(this.lazyToolMap.values()).map((t) =>\n renderLazyCatalogEntry(t.name, t.description, include),\n )\n const description = `You have access to additional tools that can be discovered. Available tools: [${allLazyEntries.join(', ')}]. Call this tool with a list of tool names to discover their full descriptions and argument schemas before using them.`\n\n // Use the arrow function to capture `this` context\n const manager = this\n\n return {\n name: DISCOVERY_TOOL_NAME,\n description,\n inputSchema: {\n type: 'object',\n properties: {\n toolNames: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'List of tool names to discover. Each name must match one of the available tools.',\n },\n },\n required: ['toolNames'],\n },\n execute: (args: { toolNames: Array<string> }) => {\n const tools: Array<{\n name: string\n description: string\n inputSchema?: any\n }> = []\n const errors: Array<string> = []\n\n for (const name of args.toolNames) {\n const tool = lazyToolMap.get(name)\n if (tool) {\n // Only flag a refresh for genuinely new discoveries. Re-requesting\n // an already-discovered tool still returns its schema below (the\n // model asked for it), but must not trigger a redundant tool-list\n // refresh + continue in the agent loop.\n if (!manager.discoveredTools.has(name)) {\n manager.discoveredTools.add(name)\n manager.hasNewDiscoveries = true\n }\n const jsonSchema = tool.inputSchema\n ? convertSchemaToJsonSchema(tool.inputSchema)\n : undefined\n tools.push({\n name: tool.name,\n description: tool.description,\n ...(jsonSchema ? { inputSchema: jsonSchema } : {}),\n })\n } else {\n errors.push(\n `Unknown tool: '${name}'. Available tools: [${undiscoveredNames().join(', ')}]`,\n )\n }\n }\n\n const result: {\n tools: typeof tools\n errors?: Array<string>\n } = { tools }\n\n if (errors.length > 0) {\n result.errors = errors\n }\n\n return result\n },\n }\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lazy-tool-manager.js","names":[],"sources":["../../../../../src/activities/chat/tools/lazy-tool-manager.ts"],"sourcesContent":["import { convertSchemaToJsonSchema } from './schema-converter'\nimport { renderLazyCatalogEntry } from './lazy-tools'\nimport type { AnyTool, LazyToolsConfig, Tool } from '../../../types'\n\n/**\n * Name of the synthetic tool the LLM calls to discover lazy tools.\n *\n * Exported so callers building custom message-compaction / history-trimming\n * logic can reference the discovery tool by constant instead of hard-coding\n * the string (which is an internal contract that could change).\n */\nexport const DISCOVERY_TOOL_NAME = '__lazy__tool__discovery__'\n\n/**\n * Manages lazy tool discovery for the chat agent loop.\n *\n * Lazy tools are not sent to the LLM initially. Instead, a synthetic\n * \"discovery tool\" is provided that lets the LLM discover lazy tools\n * by name, receiving their full descriptions and schemas on demand.\n */\nexport class LazyToolManager {\n private readonly eagerTools: ReadonlyArray<Tool>\n private readonly lazyToolMap: Map<string, Tool>\n private readonly discoveredTools: Set<string>\n private hasNewDiscoveries: boolean\n private readonly discoveryTool: Tool | null\n private readonly lazyToolsConfig: LazyToolsConfig\n\n constructor(\n tools: ReadonlyArray<Tool>,\n messages: ReadonlyArray<{\n role: string\n content?: any\n toolCalls?: Array<{\n id: string\n type: string\n function: { name: string; arguments: string }\n }>\n toolCallId?: string\n }>,\n lazyToolsConfig: LazyToolsConfig = {},\n ) {\n this.lazyToolsConfig = lazyToolsConfig\n const eager: Array<Tool> = []\n this.lazyToolMap = new Map()\n this.discoveredTools = new Set()\n this.hasNewDiscoveries = false\n\n // Separate tools into eager and lazy\n for (const tool of tools) {\n if (tool.lazy) {\n this.lazyToolMap.set(tool.name, tool)\n } else {\n eager.push(tool)\n }\n }\n this.eagerTools = eager\n\n // If no lazy tools, no discovery tool needed\n if (this.lazyToolMap.size === 0) {\n this.discoveryTool = null\n return\n }\n\n // Scan message history to pre-populate discoveredTools\n this.scanMessageHistory(messages)\n\n // Create the synthetic discovery tool\n this.discoveryTool = this.createDiscoveryTool()\n }\n\n /**\n * Returns the set of tools that should be sent to the LLM:\n * eager tools + discovered lazy tools + discovery tool (if undiscovered tools remain).\n * Resets the hasNewDiscoveries flag.\n */\n getActiveTools(): Array<Tool> {\n this.hasNewDiscoveries = false\n\n const active: Array<Tool> = [...this.eagerTools]\n\n // Add discovered lazy tools\n for (const name of this.discoveredTools) {\n const tool = this.lazyToolMap.get(name)\n if (tool) {\n active.push(tool)\n }\n }\n\n // Add discovery tool if there are still undiscovered lazy tools\n if (\n this.discoveryTool &&\n this.discoveredTools.size < this.lazyToolMap.size\n ) {\n active.push(this.discoveryTool)\n }\n\n return active\n }\n\n /**\n * Returns the tools that should be available for *execution* this turn.\n *\n * This is the advertised set (`getActiveTools()`, passed in as `activeTools`)\n * plus the discovery tool when a pending call references it but it is no\n * longer advertised. Once every lazy tool has been discovered the discovery\n * tool is dropped from the advertised set, but a model may still re-request\n * discovery (long context / hallucination); keeping it executable lets that\n * call return the schemas again instead of failing with \"Unknown tool\".\n *\n * The advertised set is intentionally left unchanged — only execution lookup\n * is widened. Operates on the already-built `activeTools`: it must NOT call\n * `getActiveTools()`, which would reset `hasNewDiscoveries` before the\n * post-execution refresh check in the agent loop.\n */\n getExecutableTools(\n activeTools: ReadonlyArray<AnyTool>,\n pendingToolCallNames: ReadonlyArray<string>,\n ): ReadonlyArray<AnyTool> {\n if (\n this.discoveryTool &&\n pendingToolCallNames.includes(DISCOVERY_TOOL_NAME) &&\n !activeTools.some((t) => t.name === DISCOVERY_TOOL_NAME)\n ) {\n return [...activeTools, this.discoveryTool]\n }\n return activeTools\n }\n\n /**\n * Returns whether new tools have been discovered since the last getActiveTools() call.\n */\n hasNewlyDiscoveredTools(): boolean {\n return this.hasNewDiscoveries\n }\n\n /**\n * Returns true if the given name is a lazy tool that has not yet been discovered.\n */\n isUndiscoveredLazyTool(name: string): boolean {\n return this.lazyToolMap.has(name) && !this.discoveredTools.has(name)\n }\n\n /**\n * Returns a helpful error message for when an undiscovered lazy tool is called.\n */\n getUndiscoveredToolError(name: string): string {\n return `Error: Tool '${name}' must be discovered first. Call ${DISCOVERY_TOOL_NAME} with toolNames: ['${name}'] to discover it.`\n }\n\n /**\n * Scans message history to find previously discovered lazy tools.\n * Looks for assistant messages with discovery tool calls and their\n * corresponding tool result messages.\n */\n private scanMessageHistory(\n messages: ReadonlyArray<{\n role: string\n content?: any\n toolCalls?: Array<{\n id: string\n type: string\n function: { name: string; arguments: string }\n }>\n toolCallId?: string\n }>,\n ): void {\n // Collect tool call IDs for discovery tool invocations\n const discoveryCallIds = new Set<string>()\n\n for (const msg of messages) {\n if (msg.role === 'assistant' && msg.toolCalls) {\n for (const tc of msg.toolCalls) {\n if (tc.function.name === DISCOVERY_TOOL_NAME) {\n discoveryCallIds.add(tc.id)\n }\n }\n }\n }\n\n if (discoveryCallIds.size === 0) return\n\n // Find corresponding tool result messages\n for (const msg of messages) {\n if (\n msg.role === 'tool' &&\n msg.toolCallId &&\n discoveryCallIds.has(msg.toolCallId)\n ) {\n try {\n const content =\n typeof msg.content === 'string'\n ? msg.content\n : JSON.stringify(msg.content)\n const parsed = JSON.parse(content)\n if (parsed && Array.isArray(parsed.tools)) {\n for (const tool of parsed.tools) {\n if (\n tool &&\n typeof tool.name === 'string' &&\n this.lazyToolMap.has(tool.name)\n ) {\n this.discoveredTools.add(tool.name)\n }\n }\n }\n } catch {\n // Malformed JSON — skip gracefully\n }\n }\n }\n }\n\n /**\n * Creates the synthetic discovery tool that the LLM can call\n * to discover lazy tools' descriptions and schemas.\n */\n private createDiscoveryTool(): Tool {\n const undiscoveredNames = (): Array<string> => {\n const names: Array<string> = []\n for (const [name] of this.lazyToolMap) {\n if (!this.discoveredTools.has(name)) {\n names.push(name)\n }\n }\n return names\n }\n\n const lazyToolMap = this.lazyToolMap\n\n // Build the static description, rendering each entry per includeDescription.\n // With the default 'none' this is byte-identical to the legacy output.\n const include = this.lazyToolsConfig.includeDescription ?? 'none'\n const allLazyEntries = Array.from(this.lazyToolMap.values()).map((t) =>\n renderLazyCatalogEntry(t.name, t.description, include),\n )\n const description = `You have access to additional tools that can be discovered. Available tools: [${allLazyEntries.join(', ')}]. Call this tool with a list of tool names to discover their full descriptions and argument schemas before using them.`\n\n // Use the arrow function to capture `this` context\n const manager = this\n\n return {\n name: DISCOVERY_TOOL_NAME,\n description,\n inputSchema: {\n type: 'object',\n properties: {\n toolNames: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'List of tool names to discover. Each name must match one of the available tools.',\n },\n },\n required: ['toolNames'],\n },\n execute: (args: { toolNames: Array<string> }) => {\n const tools: Array<{\n name: string\n description: string\n inputSchema?: any\n }> = []\n const errors: Array<string> = []\n\n for (const name of args.toolNames) {\n const tool = lazyToolMap.get(name)\n if (tool) {\n // Only flag a refresh for genuinely new discoveries. Re-requesting\n // an already-discovered tool still returns its schema below (the\n // model asked for it), but must not trigger a redundant tool-list\n // refresh + continue in the agent loop.\n if (!manager.discoveredTools.has(name)) {\n manager.discoveredTools.add(name)\n manager.hasNewDiscoveries = true\n }\n const jsonSchema = tool.inputSchema\n ? convertSchemaToJsonSchema(tool.inputSchema)\n : undefined\n tools.push({\n name: tool.name,\n description: tool.description,\n ...(jsonSchema ? { inputSchema: jsonSchema } : {}),\n })\n } else {\n errors.push(\n `Unknown tool: '${name}'. Available tools: [${undiscoveredNames().join(', ')}]`,\n )\n }\n }\n\n const result: {\n tools: typeof tools\n errors?: Array<string>\n } = { tools }\n\n if (errors.length > 0) {\n result.errors = errors\n }\n\n return result\n },\n }\n }\n}\n"],"mappings":"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"}
@@ -1,16 +1,28 @@
1
+ //#region src/activities/chat/tools/lazy-tools.ts
2
+ /**
3
+ * Extract the first sentence of a description (up to the first ., !, or ?
4
+ * followed by whitespace or end-of-string). Falls back to the whole trimmed
5
+ * string when there is no sentence terminator.
6
+ */
1
7
  function firstSentence(text) {
2
- const trimmed = text.trim();
3
- if (!trimmed) return "";
4
- const match = trimmed.match(/^.*?[.!?](?=\s|$)/);
5
- return (match ? match[0] : trimmed).trim();
8
+ const trimmed = text.trim();
9
+ if (!trimmed) return "";
10
+ const match = trimmed.match(/^.*?[.!?](?=\s|$)/);
11
+ return (match ? match[0] : trimmed).trim();
6
12
  }
13
+ /**
14
+ * Render one entry in a lazy-tool catalog according to `includeDescription`.
15
+ * - 'none' (default) → bare name (preserves legacy chat behavior)
16
+ * - 'first-sentence' → `name — <first sentence>`
17
+ * - 'full' → `name — <full description>`
18
+ * Falls back to the bare name when there is no description.
19
+ */
7
20
  function renderLazyCatalogEntry(name, description, includeDescription = "none") {
8
- if (includeDescription === "none" || !description.trim()) return name;
9
- const desc = includeDescription === "first-sentence" ? firstSentence(description) : description.trim();
10
- return desc ? `${name} — ${desc}` : name;
21
+ if (includeDescription === "none" || !description.trim()) return name;
22
+ const desc = includeDescription === "first-sentence" ? firstSentence(description) : description.trim();
23
+ return desc ? `${name} — ${desc}` : name;
11
24
  }
12
- export {
13
- firstSentence,
14
- renderLazyCatalogEntry
15
- };
16
- //# sourceMappingURL=lazy-tools.js.map
25
+ //#endregion
26
+ export { firstSentence, renderLazyCatalogEntry };
27
+
28
+ //# sourceMappingURL=lazy-tools.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lazy-tools.js","sources":["../../../../../src/activities/chat/tools/lazy-tools.ts"],"sourcesContent":["import type { LazyToolsConfig } from '../../../types'\n\n/**\n * Extract the first sentence of a description (up to the first ., !, or ?\n * followed by whitespace or end-of-string). Falls back to the whole trimmed\n * string when there is no sentence terminator.\n */\nexport function firstSentence(text: string): string {\n const trimmed = text.trim()\n if (!trimmed) return ''\n const match = trimmed.match(/^.*?[.!?](?=\\s|$)/)\n return (match ? match[0] : trimmed).trim()\n}\n\n/**\n * Render one entry in a lazy-tool catalog according to `includeDescription`.\n * - 'none' (default) → bare name (preserves legacy chat behavior)\n * - 'first-sentence' → `name — <first sentence>`\n * - 'full' → `name — <full description>`\n * Falls back to the bare name when there is no description.\n */\nexport function renderLazyCatalogEntry(\n name: string,\n description: string,\n includeDescription: LazyToolsConfig['includeDescription'] = 'none',\n): string {\n if (includeDescription === 'none' || !description.trim()) return name\n const desc =\n includeDescription === 'first-sentence'\n ? firstSentence(description)\n : description.trim()\n return desc ? `${name} — ${desc}` : name\n}\n"],"names":[],"mappings":"AAOO,SAAS,cAAc,MAAsB;AAClD,QAAM,UAAU,KAAK,KAAA;AACrB,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,QAAQ,QAAQ,MAAM,mBAAmB;AAC/C,UAAQ,QAAQ,MAAM,CAAC,IAAI,SAAS,KAAA;AACtC;AASO,SAAS,uBACd,MACA,aACA,qBAA4D,QACpD;AACR,MAAI,uBAAuB,UAAU,CAAC,YAAY,KAAA,EAAQ,QAAO;AACjE,QAAM,OACJ,uBAAuB,mBACnB,cAAc,WAAW,IACzB,YAAY,KAAA;AAClB,SAAO,OAAO,GAAG,IAAI,MAAM,IAAI,KAAK;AACtC;"}
1
+ {"version":3,"file":"lazy-tools.js","names":[],"sources":["../../../../../src/activities/chat/tools/lazy-tools.ts"],"sourcesContent":["import type { LazyToolsConfig } from '../../../types'\n\n/**\n * Extract the first sentence of a description (up to the first ., !, or ?\n * followed by whitespace or end-of-string). Falls back to the whole trimmed\n * string when there is no sentence terminator.\n */\nexport function firstSentence(text: string): string {\n const trimmed = text.trim()\n if (!trimmed) return ''\n const match = trimmed.match(/^.*?[.!?](?=\\s|$)/)\n return (match ? match[0] : trimmed).trim()\n}\n\n/**\n * Render one entry in a lazy-tool catalog according to `includeDescription`.\n * - 'none' (default) → bare name (preserves legacy chat behavior)\n * - 'first-sentence' → `name — <first sentence>`\n * - 'full' → `name — <full description>`\n * Falls back to the bare name when there is no description.\n */\nexport function renderLazyCatalogEntry(\n name: string,\n description: string,\n includeDescription: LazyToolsConfig['includeDescription'] = 'none',\n): string {\n if (includeDescription === 'none' || !description.trim()) return name\n const desc =\n includeDescription === 'first-sentence'\n ? firstSentence(description)\n : description.trim()\n return desc ? `${name} — ${desc}` : name\n}\n"],"mappings":";;;;;;AAOA,SAAgB,cAAc,MAAsB;CAClD,MAAM,UAAU,KAAK,KAAK;CAC1B,IAAI,CAAC,SAAS,OAAO;CACrB,MAAM,QAAQ,QAAQ,MAAM,mBAAmB;CAC/C,QAAQ,QAAQ,MAAM,KAAK,QAAA,CAAS,KAAK;AAC3C;;;;;;;;AASA,SAAgB,uBACd,MACA,aACA,qBAA4D,QACpD;CACR,IAAI,uBAAuB,UAAU,CAAC,YAAY,KAAK,GAAG,OAAO;CACjE,MAAM,OACJ,uBAAuB,mBACnB,cAAc,WAAW,IACzB,YAAY,KAAK;CACvB,OAAO,OAAO,GAAG,KAAK,KAAK,SAAS;AACtC"}