@mcp-abap-adt/llm-agent-server 10.0.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 (566) hide show
  1. package/README.md +13 -0
  2. package/bin/llm-agent +2 -0
  3. package/bin/llm-agent-check +2 -0
  4. package/dist/agent.d.ts +49 -0
  5. package/dist/agent.d.ts.map +1 -0
  6. package/dist/agent.js +97 -0
  7. package/dist/agent.js.map +1 -0
  8. package/dist/agents/anthropic-agent.d.ts +33 -0
  9. package/dist/agents/anthropic-agent.d.ts.map +1 -0
  10. package/dist/agents/anthropic-agent.js +138 -0
  11. package/dist/agents/anthropic-agent.js.map +1 -0
  12. package/dist/agents/base.d.ts +90 -0
  13. package/dist/agents/base.d.ts.map +1 -0
  14. package/dist/agents/base.js +107 -0
  15. package/dist/agents/base.js.map +1 -0
  16. package/dist/agents/deepseek-agent.d.ts +31 -0
  17. package/dist/agents/deepseek-agent.d.ts.map +1 -0
  18. package/dist/agents/deepseek-agent.js +121 -0
  19. package/dist/agents/deepseek-agent.js.map +1 -0
  20. package/dist/agents/index.d.ts +10 -0
  21. package/dist/agents/index.d.ts.map +1 -0
  22. package/dist/agents/index.js +10 -0
  23. package/dist/agents/index.js.map +1 -0
  24. package/dist/agents/openai-agent.d.ts +32 -0
  25. package/dist/agents/openai-agent.d.ts.map +1 -0
  26. package/dist/agents/openai-agent.js +122 -0
  27. package/dist/agents/openai-agent.js.map +1 -0
  28. package/dist/agents/prompt-based-agent.d.ts +29 -0
  29. package/dist/agents/prompt-based-agent.d.ts.map +1 -0
  30. package/dist/agents/prompt-based-agent.js +67 -0
  31. package/dist/agents/prompt-based-agent.js.map +1 -0
  32. package/dist/agents/sap-core-ai-agent.d.ts +41 -0
  33. package/dist/agents/sap-core-ai-agent.d.ts.map +1 -0
  34. package/dist/agents/sap-core-ai-agent.js +151 -0
  35. package/dist/agents/sap-core-ai-agent.js.map +1 -0
  36. package/dist/cli.d.ts +53 -0
  37. package/dist/cli.d.ts.map +1 -0
  38. package/dist/cli.js +338 -0
  39. package/dist/cli.js.map +1 -0
  40. package/dist/generated/version.d.ts +2 -0
  41. package/dist/generated/version.d.ts.map +1 -0
  42. package/dist/generated/version.js +3 -0
  43. package/dist/generated/version.js.map +1 -0
  44. package/dist/index.d.ts +75 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +78 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/llm-providers/anthropic.d.ts +25 -0
  49. package/dist/llm-providers/anthropic.d.ts.map +1 -0
  50. package/dist/llm-providers/anthropic.js +202 -0
  51. package/dist/llm-providers/anthropic.js.map +1 -0
  52. package/dist/llm-providers/base.d.ts +33 -0
  53. package/dist/llm-providers/base.d.ts.map +1 -0
  54. package/dist/llm-providers/base.js +18 -0
  55. package/dist/llm-providers/base.js.map +1 -0
  56. package/dist/llm-providers/deepseek.d.ts +24 -0
  57. package/dist/llm-providers/deepseek.d.ts.map +1 -0
  58. package/dist/llm-providers/deepseek.js +60 -0
  59. package/dist/llm-providers/deepseek.js.map +1 -0
  60. package/dist/llm-providers/index.d.ts +13 -0
  61. package/dist/llm-providers/index.d.ts.map +1 -0
  62. package/dist/llm-providers/index.js +15 -0
  63. package/dist/llm-providers/index.js.map +1 -0
  64. package/dist/llm-providers/openai.d.ts +34 -0
  65. package/dist/llm-providers/openai.d.ts.map +1 -0
  66. package/dist/llm-providers/openai.js +193 -0
  67. package/dist/llm-providers/openai.js.map +1 -0
  68. package/dist/llm-providers/sap-core-ai.d.ts +90 -0
  69. package/dist/llm-providers/sap-core-ai.d.ts.map +1 -0
  70. package/dist/llm-providers/sap-core-ai.js +394 -0
  71. package/dist/llm-providers/sap-core-ai.js.map +1 -0
  72. package/dist/mcp/client.d.ts +133 -0
  73. package/dist/mcp/client.d.ts.map +1 -0
  74. package/dist/mcp/client.js +314 -0
  75. package/dist/mcp/client.js.map +1 -0
  76. package/dist/smart-agent/adapters/cline-client-adapter.d.ts +18 -0
  77. package/dist/smart-agent/adapters/cline-client-adapter.d.ts.map +1 -0
  78. package/dist/smart-agent/adapters/cline-client-adapter.js +21 -0
  79. package/dist/smart-agent/adapters/cline-client-adapter.js.map +1 -0
  80. package/dist/smart-agent/adapters/index.d.ts +3 -0
  81. package/dist/smart-agent/adapters/index.d.ts.map +1 -0
  82. package/dist/smart-agent/adapters/index.js +3 -0
  83. package/dist/smart-agent/adapters/index.js.map +1 -0
  84. package/dist/smart-agent/adapters/llm-adapter.d.ts +24 -0
  85. package/dist/smart-agent/adapters/llm-adapter.d.ts.map +1 -0
  86. package/dist/smart-agent/adapters/llm-adapter.js +345 -0
  87. package/dist/smart-agent/adapters/llm-adapter.js.map +1 -0
  88. package/dist/smart-agent/adapters/mcp-client-adapter.d.ts +16 -0
  89. package/dist/smart-agent/adapters/mcp-client-adapter.d.ts.map +1 -0
  90. package/dist/smart-agent/adapters/mcp-client-adapter.js +95 -0
  91. package/dist/smart-agent/adapters/mcp-client-adapter.js.map +1 -0
  92. package/dist/smart-agent/adapters/non-streaming-llm.d.ts +18 -0
  93. package/dist/smart-agent/adapters/non-streaming-llm.d.ts.map +1 -0
  94. package/dist/smart-agent/adapters/non-streaming-llm.js +44 -0
  95. package/dist/smart-agent/adapters/non-streaming-llm.js.map +1 -0
  96. package/dist/smart-agent/agent.d.ts +229 -0
  97. package/dist/smart-agent/agent.d.ts.map +1 -0
  98. package/dist/smart-agent/agent.js +1538 -0
  99. package/dist/smart-agent/agent.js.map +1 -0
  100. package/dist/smart-agent/api-adapters/anthropic-adapter.d.ts +10 -0
  101. package/dist/smart-agent/api-adapters/anthropic-adapter.d.ts.map +1 -0
  102. package/dist/smart-agent/api-adapters/anthropic-adapter.js +356 -0
  103. package/dist/smart-agent/api-adapters/anthropic-adapter.js.map +1 -0
  104. package/dist/smart-agent/api-adapters/index.d.ts +3 -0
  105. package/dist/smart-agent/api-adapters/index.d.ts.map +1 -0
  106. package/dist/smart-agent/api-adapters/index.js +3 -0
  107. package/dist/smart-agent/api-adapters/index.js.map +1 -0
  108. package/dist/smart-agent/api-adapters/openai-adapter.d.ts +10 -0
  109. package/dist/smart-agent/api-adapters/openai-adapter.d.ts.map +1 -0
  110. package/dist/smart-agent/api-adapters/openai-adapter.js +277 -0
  111. package/dist/smart-agent/api-adapters/openai-adapter.js.map +1 -0
  112. package/dist/smart-agent/builder.d.ts +281 -0
  113. package/dist/smart-agent/builder.d.ts.map +1 -0
  114. package/dist/smart-agent/builder.js +942 -0
  115. package/dist/smart-agent/builder.js.map +1 -0
  116. package/dist/smart-agent/cache/index.d.ts +4 -0
  117. package/dist/smart-agent/cache/index.d.ts.map +1 -0
  118. package/dist/smart-agent/cache/index.js +3 -0
  119. package/dist/smart-agent/cache/index.js.map +1 -0
  120. package/dist/smart-agent/cache/noop-tool-cache.d.ts +7 -0
  121. package/dist/smart-agent/cache/noop-tool-cache.d.ts.map +1 -0
  122. package/dist/smart-agent/cache/noop-tool-cache.js +8 -0
  123. package/dist/smart-agent/cache/noop-tool-cache.js.map +1 -0
  124. package/dist/smart-agent/cache/tool-cache.d.ts +14 -0
  125. package/dist/smart-agent/cache/tool-cache.d.ts.map +1 -0
  126. package/dist/smart-agent/cache/tool-cache.js +32 -0
  127. package/dist/smart-agent/cache/tool-cache.js.map +1 -0
  128. package/dist/smart-agent/cache/types.d.ts +7 -0
  129. package/dist/smart-agent/cache/types.d.ts.map +1 -0
  130. package/dist/smart-agent/cache/types.js +2 -0
  131. package/dist/smart-agent/cache/types.js.map +1 -0
  132. package/dist/smart-agent/check-models-cli.d.ts +14 -0
  133. package/dist/smart-agent/check-models-cli.d.ts.map +1 -0
  134. package/dist/smart-agent/check-models-cli.js +237 -0
  135. package/dist/smart-agent/check-models-cli.js.map +1 -0
  136. package/dist/smart-agent/classifier/index.d.ts +3 -0
  137. package/dist/smart-agent/classifier/index.d.ts.map +1 -0
  138. package/dist/smart-agent/classifier/index.js +2 -0
  139. package/dist/smart-agent/classifier/index.js.map +1 -0
  140. package/dist/smart-agent/classifier/llm-classifier.d.ts +20 -0
  141. package/dist/smart-agent/classifier/llm-classifier.d.ts.map +1 -0
  142. package/dist/smart-agent/classifier/llm-classifier.js +128 -0
  143. package/dist/smart-agent/classifier/llm-classifier.js.map +1 -0
  144. package/dist/smart-agent/cli.d.ts +65 -0
  145. package/dist/smart-agent/cli.d.ts.map +1 -0
  146. package/dist/smart-agent/cli.js +199 -0
  147. package/dist/smart-agent/cli.js.map +1 -0
  148. package/dist/smart-agent/config/config-watcher.d.ts +54 -0
  149. package/dist/smart-agent/config/config-watcher.d.ts.map +1 -0
  150. package/dist/smart-agent/config/config-watcher.js +107 -0
  151. package/dist/smart-agent/config/config-watcher.js.map +1 -0
  152. package/dist/smart-agent/config/index.d.ts +2 -0
  153. package/dist/smart-agent/config/index.d.ts.map +1 -0
  154. package/dist/smart-agent/config/index.js +2 -0
  155. package/dist/smart-agent/config/index.js.map +1 -0
  156. package/dist/smart-agent/config.d.ts +35 -0
  157. package/dist/smart-agent/config.d.ts.map +1 -0
  158. package/dist/smart-agent/config.js +360 -0
  159. package/dist/smart-agent/config.js.map +1 -0
  160. package/dist/smart-agent/context/context-assembler.d.ts +49 -0
  161. package/dist/smart-agent/context/context-assembler.d.ts.map +1 -0
  162. package/dist/smart-agent/context/context-assembler.js +184 -0
  163. package/dist/smart-agent/context/context-assembler.js.map +1 -0
  164. package/dist/smart-agent/context/index.d.ts +3 -0
  165. package/dist/smart-agent/context/index.d.ts.map +1 -0
  166. package/dist/smart-agent/context/index.js +2 -0
  167. package/dist/smart-agent/context/index.js.map +1 -0
  168. package/dist/smart-agent/health/health-checker.d.ts +21 -0
  169. package/dist/smart-agent/health/health-checker.d.ts.map +1 -0
  170. package/dist/smart-agent/health/health-checker.js +52 -0
  171. package/dist/smart-agent/health/health-checker.js.map +1 -0
  172. package/dist/smart-agent/health/index.d.ts +3 -0
  173. package/dist/smart-agent/health/index.d.ts.map +1 -0
  174. package/dist/smart-agent/health/index.js +2 -0
  175. package/dist/smart-agent/health/index.js.map +1 -0
  176. package/dist/smart-agent/health/types.d.ts +25 -0
  177. package/dist/smart-agent/health/types.d.ts.map +1 -0
  178. package/dist/smart-agent/health/types.js +2 -0
  179. package/dist/smart-agent/health/types.js.map +1 -0
  180. package/dist/smart-agent/history/history-memory.d.ts +12 -0
  181. package/dist/smart-agent/history/history-memory.d.ts.map +1 -0
  182. package/dist/smart-agent/history/history-memory.js +26 -0
  183. package/dist/smart-agent/history/history-memory.js.map +1 -0
  184. package/dist/smart-agent/history/history-summarizer.d.ts +10 -0
  185. package/dist/smart-agent/history/history-summarizer.d.ts.map +1 -0
  186. package/dist/smart-agent/history/history-summarizer.js +27 -0
  187. package/dist/smart-agent/history/history-summarizer.js.map +1 -0
  188. package/dist/smart-agent/history/index.d.ts +3 -0
  189. package/dist/smart-agent/history/index.d.ts.map +1 -0
  190. package/dist/smart-agent/history/index.js +3 -0
  191. package/dist/smart-agent/history/index.js.map +1 -0
  192. package/dist/smart-agent/interfaces/api-adapter.d.ts +36 -0
  193. package/dist/smart-agent/interfaces/api-adapter.d.ts.map +1 -0
  194. package/dist/smart-agent/interfaces/api-adapter.js +9 -0
  195. package/dist/smart-agent/interfaces/api-adapter.js.map +1 -0
  196. package/dist/smart-agent/interfaces/client-adapter.d.ts +23 -0
  197. package/dist/smart-agent/interfaces/client-adapter.d.ts.map +1 -0
  198. package/dist/smart-agent/interfaces/client-adapter.js +10 -0
  199. package/dist/smart-agent/interfaces/client-adapter.js.map +1 -0
  200. package/dist/smart-agent/interfaces/mcp-connection-strategy.d.ts +27 -0
  201. package/dist/smart-agent/interfaces/mcp-connection-strategy.d.ts.map +1 -0
  202. package/dist/smart-agent/interfaces/mcp-connection-strategy.js +2 -0
  203. package/dist/smart-agent/interfaces/mcp-connection-strategy.js.map +1 -0
  204. package/dist/smart-agent/interfaces/model-resolver.d.ts +9 -0
  205. package/dist/smart-agent/interfaces/model-resolver.d.ts.map +1 -0
  206. package/dist/smart-agent/interfaces/model-resolver.js +2 -0
  207. package/dist/smart-agent/interfaces/model-resolver.js.map +1 -0
  208. package/dist/smart-agent/interfaces/pipeline.d.ts +125 -0
  209. package/dist/smart-agent/interfaces/pipeline.d.ts.map +1 -0
  210. package/dist/smart-agent/interfaces/pipeline.js +13 -0
  211. package/dist/smart-agent/interfaces/pipeline.js.map +1 -0
  212. package/dist/smart-agent/logger/console-logger.d.ts +7 -0
  213. package/dist/smart-agent/logger/console-logger.d.ts.map +1 -0
  214. package/dist/smart-agent/logger/console-logger.js +12 -0
  215. package/dist/smart-agent/logger/console-logger.js.map +1 -0
  216. package/dist/smart-agent/logger/default-request-logger.d.ts +17 -0
  217. package/dist/smart-agent/logger/default-request-logger.d.ts.map +1 -0
  218. package/dist/smart-agent/logger/default-request-logger.js +86 -0
  219. package/dist/smart-agent/logger/default-request-logger.js.map +1 -0
  220. package/dist/smart-agent/logger/index.d.ts +3 -0
  221. package/dist/smart-agent/logger/index.d.ts.map +1 -0
  222. package/dist/smart-agent/logger/index.js +2 -0
  223. package/dist/smart-agent/logger/index.js.map +1 -0
  224. package/dist/smart-agent/logger/noop-request-logger.d.ts +11 -0
  225. package/dist/smart-agent/logger/noop-request-logger.d.ts.map +1 -0
  226. package/dist/smart-agent/logger/noop-request-logger.js +20 -0
  227. package/dist/smart-agent/logger/noop-request-logger.js.map +1 -0
  228. package/dist/smart-agent/logger/session-logger.d.ts +10 -0
  229. package/dist/smart-agent/logger/session-logger.d.ts.map +1 -0
  230. package/dist/smart-agent/logger/session-logger.js +40 -0
  231. package/dist/smart-agent/logger/session-logger.js.map +1 -0
  232. package/dist/smart-agent/logger/types.d.ts +63 -0
  233. package/dist/smart-agent/logger/types.d.ts.map +1 -0
  234. package/dist/smart-agent/logger/types.js +2 -0
  235. package/dist/smart-agent/logger/types.js.map +1 -0
  236. package/dist/smart-agent/mcp-client-factory.d.ts +3 -0
  237. package/dist/smart-agent/mcp-client-factory.d.ts.map +1 -0
  238. package/dist/smart-agent/mcp-client-factory.js +21 -0
  239. package/dist/smart-agent/mcp-client-factory.js.map +1 -0
  240. package/dist/smart-agent/metrics/in-memory-metrics.d.ts +58 -0
  241. package/dist/smart-agent/metrics/in-memory-metrics.d.ts.map +1 -0
  242. package/dist/smart-agent/metrics/in-memory-metrics.js +78 -0
  243. package/dist/smart-agent/metrics/in-memory-metrics.js.map +1 -0
  244. package/dist/smart-agent/metrics/index.d.ts +4 -0
  245. package/dist/smart-agent/metrics/index.d.ts.map +1 -0
  246. package/dist/smart-agent/metrics/index.js +3 -0
  247. package/dist/smart-agent/metrics/index.js.map +1 -0
  248. package/dist/smart-agent/metrics/noop-metrics.d.ts +17 -0
  249. package/dist/smart-agent/metrics/noop-metrics.d.ts.map +1 -0
  250. package/dist/smart-agent/metrics/noop-metrics.js +22 -0
  251. package/dist/smart-agent/metrics/noop-metrics.js.map +1 -0
  252. package/dist/smart-agent/metrics/types.d.ts +36 -0
  253. package/dist/smart-agent/metrics/types.d.ts.map +1 -0
  254. package/dist/smart-agent/metrics/types.js +9 -0
  255. package/dist/smart-agent/metrics/types.js.map +1 -0
  256. package/dist/smart-agent/otel/index.d.ts +2 -0
  257. package/dist/smart-agent/otel/index.d.ts.map +1 -0
  258. package/dist/smart-agent/otel/index.js +2 -0
  259. package/dist/smart-agent/otel/index.js.map +1 -0
  260. package/dist/smart-agent/otel/otel-tracer-adapter.d.ts +15 -0
  261. package/dist/smart-agent/otel/otel-tracer-adapter.d.ts.map +1 -0
  262. package/dist/smart-agent/otel/otel-tracer-adapter.js +62 -0
  263. package/dist/smart-agent/otel/otel-tracer-adapter.js.map +1 -0
  264. package/dist/smart-agent/pipeline/condition-evaluator.d.ts +35 -0
  265. package/dist/smart-agent/pipeline/condition-evaluator.d.ts.map +1 -0
  266. package/dist/smart-agent/pipeline/condition-evaluator.js +143 -0
  267. package/dist/smart-agent/pipeline/condition-evaluator.js.map +1 -0
  268. package/dist/smart-agent/pipeline/context.d.ts +121 -0
  269. package/dist/smart-agent/pipeline/context.d.ts.map +1 -0
  270. package/dist/smart-agent/pipeline/context.js +19 -0
  271. package/dist/smart-agent/pipeline/context.js.map +1 -0
  272. package/dist/smart-agent/pipeline/default-pipeline.d.ts +69 -0
  273. package/dist/smart-agent/pipeline/default-pipeline.d.ts.map +1 -0
  274. package/dist/smart-agent/pipeline/default-pipeline.js +278 -0
  275. package/dist/smart-agent/pipeline/default-pipeline.js.map +1 -0
  276. package/dist/smart-agent/pipeline/executor.d.ts +54 -0
  277. package/dist/smart-agent/pipeline/executor.d.ts.map +1 -0
  278. package/dist/smart-agent/pipeline/executor.js +133 -0
  279. package/dist/smart-agent/pipeline/executor.js.map +1 -0
  280. package/dist/smart-agent/pipeline/handlers/assemble.d.ts +16 -0
  281. package/dist/smart-agent/pipeline/handlers/assemble.d.ts.map +1 -0
  282. package/dist/smart-agent/pipeline/handlers/assemble.js +72 -0
  283. package/dist/smart-agent/pipeline/handlers/assemble.js.map +1 -0
  284. package/dist/smart-agent/pipeline/handlers/build-tool-query.d.ts +30 -0
  285. package/dist/smart-agent/pipeline/handlers/build-tool-query.d.ts.map +1 -0
  286. package/dist/smart-agent/pipeline/handlers/build-tool-query.js +80 -0
  287. package/dist/smart-agent/pipeline/handlers/build-tool-query.js.map +1 -0
  288. package/dist/smart-agent/pipeline/handlers/classify.d.ts +21 -0
  289. package/dist/smart-agent/pipeline/handlers/classify.d.ts.map +1 -0
  290. package/dist/smart-agent/pipeline/handlers/classify.js +60 -0
  291. package/dist/smart-agent/pipeline/handlers/classify.js.map +1 -0
  292. package/dist/smart-agent/pipeline/handlers/expand.d.ts +16 -0
  293. package/dist/smart-agent/pipeline/handlers/expand.d.ts.map +1 -0
  294. package/dist/smart-agent/pipeline/handlers/expand.js +24 -0
  295. package/dist/smart-agent/pipeline/handlers/expand.js.map +1 -0
  296. package/dist/smart-agent/pipeline/handlers/history-upsert.d.ts +29 -0
  297. package/dist/smart-agent/pipeline/handlers/history-upsert.d.ts.map +1 -0
  298. package/dist/smart-agent/pipeline/handlers/history-upsert.js +75 -0
  299. package/dist/smart-agent/pipeline/handlers/history-upsert.js.map +1 -0
  300. package/dist/smart-agent/pipeline/handlers/index.d.ts +31 -0
  301. package/dist/smart-agent/pipeline/handlers/index.d.ts.map +1 -0
  302. package/dist/smart-agent/pipeline/handlers/index.js +44 -0
  303. package/dist/smart-agent/pipeline/handlers/index.js.map +1 -0
  304. package/dist/smart-agent/pipeline/handlers/rag-query.d.ts +27 -0
  305. package/dist/smart-agent/pipeline/handlers/rag-query.d.ts.map +1 -0
  306. package/dist/smart-agent/pipeline/handlers/rag-query.js +117 -0
  307. package/dist/smart-agent/pipeline/handlers/rag-query.js.map +1 -0
  308. package/dist/smart-agent/pipeline/handlers/rerank.d.ts +16 -0
  309. package/dist/smart-agent/pipeline/handlers/rerank.d.ts.map +1 -0
  310. package/dist/smart-agent/pipeline/handlers/rerank.js +27 -0
  311. package/dist/smart-agent/pipeline/handlers/rerank.js.map +1 -0
  312. package/dist/smart-agent/pipeline/handlers/skill-select.d.ts +18 -0
  313. package/dist/smart-agent/pipeline/handlers/skill-select.d.ts.map +1 -0
  314. package/dist/smart-agent/pipeline/handlers/skill-select.js +88 -0
  315. package/dist/smart-agent/pipeline/handlers/skill-select.js.map +1 -0
  316. package/dist/smart-agent/pipeline/handlers/summarize.d.ts +17 -0
  317. package/dist/smart-agent/pipeline/handlers/summarize.d.ts.map +1 -0
  318. package/dist/smart-agent/pipeline/handlers/summarize.js +56 -0
  319. package/dist/smart-agent/pipeline/handlers/summarize.js.map +1 -0
  320. package/dist/smart-agent/pipeline/handlers/tool-loop.d.ts +32 -0
  321. package/dist/smart-agent/pipeline/handlers/tool-loop.d.ts.map +1 -0
  322. package/dist/smart-agent/pipeline/handlers/tool-loop.js +734 -0
  323. package/dist/smart-agent/pipeline/handlers/tool-loop.js.map +1 -0
  324. package/dist/smart-agent/pipeline/handlers/tool-select.d.ts +21 -0
  325. package/dist/smart-agent/pipeline/handlers/tool-select.d.ts.map +1 -0
  326. package/dist/smart-agent/pipeline/handlers/tool-select.js +109 -0
  327. package/dist/smart-agent/pipeline/handlers/tool-select.js.map +1 -0
  328. package/dist/smart-agent/pipeline/handlers/translate.d.ts +17 -0
  329. package/dist/smart-agent/pipeline/handlers/translate.d.ts.map +1 -0
  330. package/dist/smart-agent/pipeline/handlers/translate.js +42 -0
  331. package/dist/smart-agent/pipeline/handlers/translate.js.map +1 -0
  332. package/dist/smart-agent/pipeline/index.d.ts +14 -0
  333. package/dist/smart-agent/pipeline/index.d.ts.map +1 -0
  334. package/dist/smart-agent/pipeline/index.js +16 -0
  335. package/dist/smart-agent/pipeline/index.js.map +1 -0
  336. package/dist/smart-agent/pipeline/stage-handler.d.ts +36 -0
  337. package/dist/smart-agent/pipeline/stage-handler.d.ts.map +1 -0
  338. package/dist/smart-agent/pipeline/stage-handler.js +24 -0
  339. package/dist/smart-agent/pipeline/stage-handler.js.map +1 -0
  340. package/dist/smart-agent/pipeline/types.d.ts +116 -0
  341. package/dist/smart-agent/pipeline/types.d.ts.map +1 -0
  342. package/dist/smart-agent/pipeline/types.js +54 -0
  343. package/dist/smart-agent/pipeline/types.js.map +1 -0
  344. package/dist/smart-agent/pipeline.d.ts +82 -0
  345. package/dist/smart-agent/pipeline.d.ts.map +1 -0
  346. package/dist/smart-agent/pipeline.js +8 -0
  347. package/dist/smart-agent/pipeline.js.map +1 -0
  348. package/dist/smart-agent/plugins/index.d.ts +4 -0
  349. package/dist/smart-agent/plugins/index.d.ts.map +1 -0
  350. package/dist/smart-agent/plugins/index.js +3 -0
  351. package/dist/smart-agent/plugins/index.js.map +1 -0
  352. package/dist/smart-agent/plugins/loader.d.ts +67 -0
  353. package/dist/smart-agent/plugins/loader.d.ts.map +1 -0
  354. package/dist/smart-agent/plugins/loader.js +114 -0
  355. package/dist/smart-agent/plugins/loader.js.map +1 -0
  356. package/dist/smart-agent/plugins/types.d.ts +164 -0
  357. package/dist/smart-agent/plugins/types.d.ts.map +1 -0
  358. package/dist/smart-agent/plugins/types.js +136 -0
  359. package/dist/smart-agent/plugins/types.js.map +1 -0
  360. package/dist/smart-agent/policy/fallback-llm-call-strategy.d.ts +16 -0
  361. package/dist/smart-agent/policy/fallback-llm-call-strategy.d.ts.map +1 -0
  362. package/dist/smart-agent/policy/fallback-llm-call-strategy.js +66 -0
  363. package/dist/smart-agent/policy/fallback-llm-call-strategy.js.map +1 -0
  364. package/dist/smart-agent/policy/heuristic-injection-detector.d.ts +5 -0
  365. package/dist/smart-agent/policy/heuristic-injection-detector.d.ts.map +1 -0
  366. package/dist/smart-agent/policy/heuristic-injection-detector.js +36 -0
  367. package/dist/smart-agent/policy/heuristic-injection-detector.js.map +1 -0
  368. package/dist/smart-agent/policy/index.d.ts +6 -0
  369. package/dist/smart-agent/policy/index.d.ts.map +1 -0
  370. package/dist/smart-agent/policy/index.js +5 -0
  371. package/dist/smart-agent/policy/index.js.map +1 -0
  372. package/dist/smart-agent/policy/mixed-tool-call-handler.d.ts +16 -0
  373. package/dist/smart-agent/policy/mixed-tool-call-handler.d.ts.map +1 -0
  374. package/dist/smart-agent/policy/mixed-tool-call-handler.js +49 -0
  375. package/dist/smart-agent/policy/mixed-tool-call-handler.js.map +1 -0
  376. package/dist/smart-agent/policy/non-streaming-llm-call-strategy.d.ts +6 -0
  377. package/dist/smart-agent/policy/non-streaming-llm-call-strategy.d.ts.map +1 -0
  378. package/dist/smart-agent/policy/non-streaming-llm-call-strategy.js +21 -0
  379. package/dist/smart-agent/policy/non-streaming-llm-call-strategy.js.map +1 -0
  380. package/dist/smart-agent/policy/pending-tool-results-registry.d.ts +25 -0
  381. package/dist/smart-agent/policy/pending-tool-results-registry.d.ts.map +1 -0
  382. package/dist/smart-agent/policy/pending-tool-results-registry.js +50 -0
  383. package/dist/smart-agent/policy/pending-tool-results-registry.js.map +1 -0
  384. package/dist/smart-agent/policy/streaming-llm-call-strategy.d.ts +6 -0
  385. package/dist/smart-agent/policy/streaming-llm-call-strategy.d.ts.map +1 -0
  386. package/dist/smart-agent/policy/streaming-llm-call-strategy.js +7 -0
  387. package/dist/smart-agent/policy/streaming-llm-call-strategy.js.map +1 -0
  388. package/dist/smart-agent/policy/tool-availability-registry.d.ts +21 -0
  389. package/dist/smart-agent/policy/tool-availability-registry.d.ts.map +1 -0
  390. package/dist/smart-agent/policy/tool-availability-registry.js +77 -0
  391. package/dist/smart-agent/policy/tool-availability-registry.js.map +1 -0
  392. package/dist/smart-agent/policy/tool-policy-guard.d.ts +8 -0
  393. package/dist/smart-agent/policy/tool-policy-guard.d.ts.map +1 -0
  394. package/dist/smart-agent/policy/tool-policy-guard.js +40 -0
  395. package/dist/smart-agent/policy/tool-policy-guard.js.map +1 -0
  396. package/dist/smart-agent/policy/types.d.ts +51 -0
  397. package/dist/smart-agent/policy/types.d.ts.map +1 -0
  398. package/dist/smart-agent/policy/types.js +17 -0
  399. package/dist/smart-agent/policy/types.js.map +1 -0
  400. package/dist/smart-agent/providers.d.ts +98 -0
  401. package/dist/smart-agent/providers.d.ts.map +1 -0
  402. package/dist/smart-agent/providers.js +245 -0
  403. package/dist/smart-agent/providers.js.map +1 -0
  404. package/dist/smart-agent/reranker/index.d.ts +4 -0
  405. package/dist/smart-agent/reranker/index.d.ts.map +1 -0
  406. package/dist/smart-agent/reranker/index.js +3 -0
  407. package/dist/smart-agent/reranker/index.js.map +1 -0
  408. package/dist/smart-agent/reranker/llm-reranker.d.ts +10 -0
  409. package/dist/smart-agent/reranker/llm-reranker.d.ts.map +1 -0
  410. package/dist/smart-agent/reranker/llm-reranker.js +55 -0
  411. package/dist/smart-agent/reranker/llm-reranker.js.map +1 -0
  412. package/dist/smart-agent/reranker/noop-reranker.d.ts +6 -0
  413. package/dist/smart-agent/reranker/noop-reranker.d.ts.map +1 -0
  414. package/dist/smart-agent/reranker/noop-reranker.js +6 -0
  415. package/dist/smart-agent/reranker/noop-reranker.js.map +1 -0
  416. package/dist/smart-agent/reranker/types.d.ts +5 -0
  417. package/dist/smart-agent/reranker/types.d.ts.map +1 -0
  418. package/dist/smart-agent/reranker/types.js +2 -0
  419. package/dist/smart-agent/reranker/types.js.map +1 -0
  420. package/dist/smart-agent/resilience/circuit-breaker-embedder.d.ts +16 -0
  421. package/dist/smart-agent/resilience/circuit-breaker-embedder.d.ts.map +1 -0
  422. package/dist/smart-agent/resilience/circuit-breaker-embedder.js +47 -0
  423. package/dist/smart-agent/resilience/circuit-breaker-embedder.js.map +1 -0
  424. package/dist/smart-agent/resilience/circuit-breaker-llm.d.ts +19 -0
  425. package/dist/smart-agent/resilience/circuit-breaker-llm.d.ts.map +1 -0
  426. package/dist/smart-agent/resilience/circuit-breaker-llm.js +72 -0
  427. package/dist/smart-agent/resilience/circuit-breaker-llm.js.map +1 -0
  428. package/dist/smart-agent/resilience/circuit-breaker.d.ts +36 -0
  429. package/dist/smart-agent/resilience/circuit-breaker.d.ts.map +1 -0
  430. package/dist/smart-agent/resilience/circuit-breaker.js +60 -0
  431. package/dist/smart-agent/resilience/circuit-breaker.js.map +1 -0
  432. package/dist/smart-agent/resilience/fallback-rag.d.ts +21 -0
  433. package/dist/smart-agent/resilience/fallback-rag.d.ts.map +1 -0
  434. package/dist/smart-agent/resilience/fallback-rag.js +80 -0
  435. package/dist/smart-agent/resilience/fallback-rag.js.map +1 -0
  436. package/dist/smart-agent/resilience/index.d.ts +5 -0
  437. package/dist/smart-agent/resilience/index.d.ts.map +1 -0
  438. package/dist/smart-agent/resilience/index.js +5 -0
  439. package/dist/smart-agent/resilience/index.js.map +1 -0
  440. package/dist/smart-agent/resilience/rate-limiter-llm.d.ts +17 -0
  441. package/dist/smart-agent/resilience/rate-limiter-llm.d.ts.map +1 -0
  442. package/dist/smart-agent/resilience/rate-limiter-llm.js +30 -0
  443. package/dist/smart-agent/resilience/rate-limiter-llm.js.map +1 -0
  444. package/dist/smart-agent/resilience/retry-llm.d.ts +32 -0
  445. package/dist/smart-agent/resilience/retry-llm.d.ts.map +1 -0
  446. package/dist/smart-agent/resilience/retry-llm.js +103 -0
  447. package/dist/smart-agent/resilience/retry-llm.js.map +1 -0
  448. package/dist/smart-agent/resilience/token-bucket-rate-limiter.d.ts +21 -0
  449. package/dist/smart-agent/resilience/token-bucket-rate-limiter.d.ts.map +1 -0
  450. package/dist/smart-agent/resilience/token-bucket-rate-limiter.js +32 -0
  451. package/dist/smart-agent/resilience/token-bucket-rate-limiter.js.map +1 -0
  452. package/dist/smart-agent/server.d.ts +19 -0
  453. package/dist/smart-agent/server.d.ts.map +1 -0
  454. package/dist/smart-agent/server.js +349 -0
  455. package/dist/smart-agent/server.js.map +1 -0
  456. package/dist/smart-agent/session/index.d.ts +4 -0
  457. package/dist/smart-agent/session/index.d.ts.map +1 -0
  458. package/dist/smart-agent/session/index.js +3 -0
  459. package/dist/smart-agent/session/index.js.map +1 -0
  460. package/dist/smart-agent/session/noop-session-manager.d.ts +8 -0
  461. package/dist/smart-agent/session/noop-session-manager.d.ts.map +1 -0
  462. package/dist/smart-agent/session/noop-session-manager.js +11 -0
  463. package/dist/smart-agent/session/noop-session-manager.js.map +1 -0
  464. package/dist/smart-agent/session/session-manager.d.ts +13 -0
  465. package/dist/smart-agent/session/session-manager.d.ts.map +1 -0
  466. package/dist/smart-agent/session/session-manager.js +20 -0
  467. package/dist/smart-agent/session/session-manager.js.map +1 -0
  468. package/dist/smart-agent/session/types.d.ts +7 -0
  469. package/dist/smart-agent/session/types.d.ts.map +1 -0
  470. package/dist/smart-agent/session/types.js +2 -0
  471. package/dist/smart-agent/session/types.js.map +1 -0
  472. package/dist/smart-agent/skills/claude-skill-manager.d.ts +24 -0
  473. package/dist/smart-agent/skills/claude-skill-manager.d.ts.map +1 -0
  474. package/dist/smart-agent/skills/claude-skill-manager.js +81 -0
  475. package/dist/smart-agent/skills/claude-skill-manager.js.map +1 -0
  476. package/dist/smart-agent/skills/codex-skill-manager.d.ts +20 -0
  477. package/dist/smart-agent/skills/codex-skill-manager.d.ts.map +1 -0
  478. package/dist/smart-agent/skills/codex-skill-manager.js +75 -0
  479. package/dist/smart-agent/skills/codex-skill-manager.js.map +1 -0
  480. package/dist/smart-agent/skills/filesystem-skill-manager.d.ts +17 -0
  481. package/dist/smart-agent/skills/filesystem-skill-manager.d.ts.map +1 -0
  482. package/dist/smart-agent/skills/filesystem-skill-manager.js +48 -0
  483. package/dist/smart-agent/skills/filesystem-skill-manager.js.map +1 -0
  484. package/dist/smart-agent/skills/filesystem-skill.d.ts +25 -0
  485. package/dist/smart-agent/skills/filesystem-skill.d.ts.map +1 -0
  486. package/dist/smart-agent/skills/filesystem-skill.js +110 -0
  487. package/dist/smart-agent/skills/filesystem-skill.js.map +1 -0
  488. package/dist/smart-agent/skills/index.d.ts +9 -0
  489. package/dist/smart-agent/skills/index.d.ts.map +1 -0
  490. package/dist/smart-agent/skills/index.js +9 -0
  491. package/dist/smart-agent/skills/index.js.map +1 -0
  492. package/dist/smart-agent/skills/skill-utils.d.ts +15 -0
  493. package/dist/smart-agent/skills/skill-utils.d.ts.map +1 -0
  494. package/dist/smart-agent/skills/skill-utils.js +46 -0
  495. package/dist/smart-agent/skills/skill-utils.js.map +1 -0
  496. package/dist/smart-agent/smart-server.d.ts +150 -0
  497. package/dist/smart-agent/smart-server.d.ts.map +1 -0
  498. package/dist/smart-agent/smart-server.js +903 -0
  499. package/dist/smart-agent/smart-server.js.map +1 -0
  500. package/dist/smart-agent/strategies/index.d.ts +4 -0
  501. package/dist/smart-agent/strategies/index.d.ts.map +1 -0
  502. package/dist/smart-agent/strategies/index.js +4 -0
  503. package/dist/smart-agent/strategies/index.js.map +1 -0
  504. package/dist/smart-agent/strategies/lazy-connection-strategy.d.ts +15 -0
  505. package/dist/smart-agent/strategies/lazy-connection-strategy.d.ts.map +1 -0
  506. package/dist/smart-agent/strategies/lazy-connection-strategy.js +82 -0
  507. package/dist/smart-agent/strategies/lazy-connection-strategy.js.map +1 -0
  508. package/dist/smart-agent/strategies/noop-connection-strategy.d.ts +6 -0
  509. package/dist/smart-agent/strategies/noop-connection-strategy.d.ts.map +1 -0
  510. package/dist/smart-agent/strategies/noop-connection-strategy.js +6 -0
  511. package/dist/smart-agent/strategies/noop-connection-strategy.js.map +1 -0
  512. package/dist/smart-agent/strategies/periodic-connection-strategy.d.ts +13 -0
  513. package/dist/smart-agent/strategies/periodic-connection-strategy.d.ts.map +1 -0
  514. package/dist/smart-agent/strategies/periodic-connection-strategy.js +40 -0
  515. package/dist/smart-agent/strategies/periodic-connection-strategy.js.map +1 -0
  516. package/dist/smart-agent/testing/index.d.ts +121 -0
  517. package/dist/smart-agent/testing/index.d.ts.map +1 -0
  518. package/dist/smart-agent/testing/index.js +354 -0
  519. package/dist/smart-agent/testing/index.js.map +1 -0
  520. package/dist/smart-agent/tracer/index.d.ts +3 -0
  521. package/dist/smart-agent/tracer/index.d.ts.map +1 -0
  522. package/dist/smart-agent/tracer/index.js +2 -0
  523. package/dist/smart-agent/tracer/index.js.map +1 -0
  524. package/dist/smart-agent/tracer/noop-tracer.d.ts +5 -0
  525. package/dist/smart-agent/tracer/noop-tracer.d.ts.map +1 -0
  526. package/dist/smart-agent/tracer/noop-tracer.js +16 -0
  527. package/dist/smart-agent/tracer/noop-tracer.js.map +1 -0
  528. package/dist/smart-agent/tracer/types.d.ts +17 -0
  529. package/dist/smart-agent/tracer/types.d.ts.map +1 -0
  530. package/dist/smart-agent/tracer/types.js +2 -0
  531. package/dist/smart-agent/tracer/types.js.map +1 -0
  532. package/dist/smart-agent/utils/external-tools-normalizer.d.ts +15 -0
  533. package/dist/smart-agent/utils/external-tools-normalizer.d.ts.map +1 -0
  534. package/dist/smart-agent/utils/external-tools-normalizer.js +146 -0
  535. package/dist/smart-agent/utils/external-tools-normalizer.js.map +1 -0
  536. package/dist/smart-agent/utils/lazy.d.ts +51 -0
  537. package/dist/smart-agent/utils/lazy.d.ts.map +1 -0
  538. package/dist/smart-agent/utils/lazy.js +127 -0
  539. package/dist/smart-agent/utils/lazy.js.map +1 -0
  540. package/dist/smart-agent/utils/parse-frontmatter.d.ts +15 -0
  541. package/dist/smart-agent/utils/parse-frontmatter.d.ts.map +1 -0
  542. package/dist/smart-agent/utils/parse-frontmatter.js +22 -0
  543. package/dist/smart-agent/utils/parse-frontmatter.js.map +1 -0
  544. package/dist/smart-agent/utils/tool-call-deltas.d.ts +4 -0
  545. package/dist/smart-agent/utils/tool-call-deltas.d.ts.map +1 -0
  546. package/dist/smart-agent/utils/tool-call-deltas.js +25 -0
  547. package/dist/smart-agent/utils/tool-call-deltas.js.map +1 -0
  548. package/dist/smart-agent/validator/index.d.ts +3 -0
  549. package/dist/smart-agent/validator/index.d.ts.map +1 -0
  550. package/dist/smart-agent/validator/index.js +2 -0
  551. package/dist/smart-agent/validator/index.js.map +1 -0
  552. package/dist/smart-agent/validator/noop-validator.d.ts +6 -0
  553. package/dist/smart-agent/validator/noop-validator.d.ts.map +1 -0
  554. package/dist/smart-agent/validator/noop-validator.js +6 -0
  555. package/dist/smart-agent/validator/noop-validator.js.map +1 -0
  556. package/dist/smart-agent/validator/types.d.ts +17 -0
  557. package/dist/smart-agent/validator/types.d.ts.map +1 -0
  558. package/dist/smart-agent/validator/types.js +8 -0
  559. package/dist/smart-agent/validator/types.js.map +1 -0
  560. package/dist/smoke-adapters.d.ts +17 -0
  561. package/dist/smoke-adapters.d.ts.map +1 -0
  562. package/dist/smoke-adapters.js +178 -0
  563. package/dist/smoke-adapters.js.map +1 -0
  564. package/package.json +89 -0
  565. package/tools/claude-via-agent.ps1 +83 -0
  566. package/tools/claude-via-agent.sh +96 -0
@@ -0,0 +1,1538 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { NoopToolCache } from './cache/noop-tool-cache.js';
3
+ import { LlmClassifier } from './classifier/llm-classifier.js';
4
+ import { StreamingLlmCallStrategy } from './policy/streaming-llm-call-strategy.js';
5
+ export { OrchestratorError, } from '@mcp-abap-adt/llm-agent';
6
+ import { NoopQueryExpander, OrchestratorError, QueryEmbedding, TextOnlyEmbedding, } from '@mcp-abap-adt/llm-agent';
7
+ import { NoopRequestLogger } from './logger/noop-request-logger.js';
8
+ import { NoopMetrics } from './metrics/noop-metrics.js';
9
+ import { fireInternalToolsAsync } from './policy/mixed-tool-call-handler.js';
10
+ import { PendingToolResultsRegistry } from './policy/pending-tool-results-registry.js';
11
+ import { isToolContextUnavailableError, ToolAvailabilityRegistry, } from './policy/tool-availability-registry.js';
12
+ import { NoopReranker } from './reranker/noop-reranker.js';
13
+ import { NoopSessionManager } from './session/noop-session-manager.js';
14
+ import { NoopTracer } from './tracer/noop-tracer.js';
15
+ import { normalizeExternalTools } from './utils/external-tools-normalizer.js';
16
+ import { getStreamToolCallName, toToolCallDelta, } from './utils/tool-call-deltas.js';
17
+ import { NoopValidator } from './validator/noop-validator.js';
18
+ function mergeSignals(...signals) {
19
+ const ctrl = new AbortController();
20
+ for (const s of signals) {
21
+ if (!s)
22
+ continue;
23
+ if (s.aborted) {
24
+ ctrl.abort(s.reason);
25
+ return ctrl;
26
+ }
27
+ s.addEventListener('abort', () => ctrl.abort(s.reason), { once: true });
28
+ }
29
+ return ctrl;
30
+ }
31
+ function createTimeoutSignal(ms) {
32
+ const ctrl = new AbortController();
33
+ const id = setTimeout(() => ctrl.abort(new Error('Timeout')), ms);
34
+ return { signal: ctrl.signal, clear: () => clearTimeout(id) };
35
+ }
36
+ export class SmartAgent {
37
+ deps;
38
+ config;
39
+ toolAvailabilityRegistry;
40
+ tracer;
41
+ metrics;
42
+ reranker;
43
+ queryExpander;
44
+ toolCache;
45
+ outputValidator;
46
+ sessionManager;
47
+ pendingToolResults;
48
+ requestLogger;
49
+ defaultLlmCallStrategy;
50
+ _activeClients;
51
+ _mainLlm;
52
+ _classifierLlm;
53
+ _helperLlm;
54
+ _classifier;
55
+ constructor(deps, config) {
56
+ this.deps = deps;
57
+ this.config = config;
58
+ this.toolAvailabilityRegistry = new ToolAvailabilityRegistry(this.config.toolUnavailableTtlMs);
59
+ this.tracer = deps.tracer ?? new NoopTracer();
60
+ this.metrics = deps.metrics ?? new NoopMetrics();
61
+ this.reranker = deps.reranker ?? new NoopReranker();
62
+ this.queryExpander = deps.queryExpander ?? new NoopQueryExpander();
63
+ this.toolCache = deps.toolCache ?? new NoopToolCache();
64
+ this.outputValidator = deps.outputValidator ?? new NoopValidator();
65
+ this.sessionManager = deps.sessionManager ?? new NoopSessionManager();
66
+ this.pendingToolResults = new PendingToolResultsRegistry();
67
+ this.requestLogger = deps.requestLogger ?? new NoopRequestLogger();
68
+ this.defaultLlmCallStrategy =
69
+ deps.llmCallStrategy ?? new StreamingLlmCallStrategy();
70
+ this._activeClients = [...deps.mcpClients];
71
+ this._mainLlm = deps.mainLlm;
72
+ this._helperLlm = deps.helperLlm;
73
+ this._classifier = deps.classifier;
74
+ this._classifierLlm = deps.classifierLlm;
75
+ }
76
+ /** Current main LLM instance. Use this for direct LLM calls that should respect hot-swap. */
77
+ get currentMainLlm() {
78
+ return this._mainLlm;
79
+ }
80
+ async _resolveActiveClients(opts) {
81
+ if (!this.deps.connectionStrategy)
82
+ return;
83
+ const result = await this.deps.connectionStrategy.resolve(this._activeClients, opts);
84
+ this._activeClients = result.clients;
85
+ if (result.toolsChanged) {
86
+ await this._revectorizeTools(result.clients, opts);
87
+ }
88
+ }
89
+ async _revectorizeTools(clients, opts) {
90
+ const toolsRag = this.deps.ragStores.tools ?? Object.values(this.deps.ragStores)[0];
91
+ if (!toolsRag)
92
+ return;
93
+ for (const client of clients) {
94
+ const result = await client.listTools(opts);
95
+ if (!result.ok)
96
+ continue;
97
+ for (const tool of result.value) {
98
+ const text = `Tool: ${tool.name} — ${tool.description}`;
99
+ await toolsRag.writer?.()?.upsertRaw(`tool:${tool.name}`, text, {});
100
+ }
101
+ }
102
+ }
103
+ /** Apply a partial config update at runtime (hot-reload). */
104
+ applyConfigUpdate(update) {
105
+ this.config = { ...this.config, ...update };
106
+ }
107
+ /**
108
+ * Replace active LLM instances at runtime.
109
+ * Changes apply to new requests only — in-flight requests continue
110
+ * using the dependency snapshot captured at request start.
111
+ * Reconfigured LLMs do not inherit builder-time wrappers (retry, circuit breaker, rate limiter).
112
+ *
113
+ * **Important:** This is the only supported way to hot-swap LLMs.
114
+ * Direct mutation of `deps` fields has no effect — SmartAgent copies
115
+ * deps into private fields at construction time.
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * const newLlm = makeLlm({ provider: 'openai', model: 'gpt-5.4-pro', ... });
120
+ * handle.agent.reconfigure({ mainLlm: newLlm });
121
+ * // handle.chat() and handle.streamChat() now use the new LLM
122
+ * ```
123
+ */
124
+ reconfigure(update) {
125
+ if (update.mainLlm) {
126
+ this._mainLlm = update.mainLlm;
127
+ }
128
+ if (update.helperLlm) {
129
+ this._helperLlm = update.helperLlm;
130
+ }
131
+ if (update.classifierLlm) {
132
+ this._classifierLlm = update.classifierLlm;
133
+ this._classifier = new LlmClassifier(update.classifierLlm, this.deps.classifierConfig, this.requestLogger);
134
+ }
135
+ }
136
+ /**
137
+ * Add a custom RAG store at runtime. Takes effect on the next request.
138
+ * Built-in store names ('tools', 'history') cannot be overwritten.
139
+ *
140
+ * @param options.translateQuery — when true, the pipeline translates the
141
+ * query to English before searching this store (useful for stores with
142
+ * English-only content like MCP tool descriptions).
143
+ */
144
+ addRagStore(name, store, options) {
145
+ if (name === 'tools' || name === 'history') {
146
+ throw new Error(`Cannot overwrite built-in RAG store "${name}" via addRagStore()`);
147
+ }
148
+ if (this.deps.ragRegistry) {
149
+ // Route through registry so the ragStores projection (and any listeners)
150
+ // see the change.
151
+ if (this.deps.ragRegistry.get(name)) {
152
+ this.deps.ragRegistry.unregister(name);
153
+ }
154
+ this.deps.ragRegistry.register(name, store, undefined, {
155
+ displayName: name,
156
+ scope: 'global',
157
+ });
158
+ }
159
+ else {
160
+ // Fallback for consumers that built SmartAgentDeps without a registry.
161
+ this.deps.ragStores[name] = store;
162
+ }
163
+ if (options?.translateQuery) {
164
+ if (!this.deps.translateQueryStores) {
165
+ this.deps.translateQueryStores = new Set();
166
+ }
167
+ this.deps.translateQueryStores.add(name);
168
+ }
169
+ this.deps.pipeline?.rebuildStages?.();
170
+ }
171
+ /**
172
+ * Remove a custom RAG store at runtime. Takes effect on the next request.
173
+ * Built-in store names ('tools', 'history') cannot be removed.
174
+ */
175
+ removeRagStore(name) {
176
+ if (name === 'tools' || name === 'history') {
177
+ throw new Error(`Cannot remove built-in RAG store "${name}" via removeRagStore()`);
178
+ }
179
+ if (this.deps.ragRegistry) {
180
+ this.deps.ragRegistry.unregister(name);
181
+ }
182
+ else {
183
+ delete this.deps.ragStores[name];
184
+ }
185
+ this.deps.translateQueryStores?.delete(name);
186
+ this.deps.pipeline?.rebuildStages?.();
187
+ }
188
+ /**
189
+ * Close a session: remove session-scoped RAG collections for the given
190
+ * sessionId and flush session-scoped history memory.
191
+ * Errors from registry cleanup are logged but not thrown — best-effort.
192
+ */
193
+ async closeSession(sessionId) {
194
+ if (this.deps.ragRegistry) {
195
+ const res = await this.deps.ragRegistry.closeSession(sessionId);
196
+ if (!res.ok) {
197
+ this.deps.logger?.log({
198
+ type: 'warning',
199
+ traceId: 'close_session',
200
+ message: `closeSession(${sessionId}) failed: ${res.error.message}`,
201
+ });
202
+ }
203
+ }
204
+ this.deps.historyMemory?.clear(sessionId);
205
+ }
206
+ /** Returns the model identifiers of the currently active LLM instances. */
207
+ getActiveConfig() {
208
+ return {
209
+ mainModel: this._mainLlm.model,
210
+ classifierModel: this._classifierLlm?.model,
211
+ helperModel: this._helperLlm?.model,
212
+ };
213
+ }
214
+ /** Returns whitelisted runtime-safe agent config fields (for HTTP DTO). */
215
+ getAgentConfig() {
216
+ return {
217
+ maxIterations: this.config.maxIterations,
218
+ maxToolCalls: this.config.maxToolCalls,
219
+ ragQueryK: this.config.ragQueryK,
220
+ toolUnavailableTtlMs: this.config.toolUnavailableTtlMs,
221
+ showReasoning: this.config.showReasoning,
222
+ historyAutoSummarizeLimit: this.config.historyAutoSummarizeLimit,
223
+ classificationEnabled: this.config.classificationEnabled,
224
+ };
225
+ }
226
+ async healthCheck(options) {
227
+ const HEALTH_TIMEOUT_MS = this.config.healthTimeoutMs ?? 5_000;
228
+ const { signal: timeoutSignal, clear: clearTimeout_ } = createTimeoutSignal(HEALTH_TIMEOUT_MS);
229
+ const merged = mergeSignals(timeoutSignal, options?.signal);
230
+ const healthOptions = {
231
+ ...options,
232
+ signal: merged.signal,
233
+ maxTokens: 1,
234
+ };
235
+ const results = {
236
+ llm: false,
237
+ rag: false,
238
+ mcp: [],
239
+ };
240
+ try {
241
+ if (this._mainLlm.healthCheck) {
242
+ const hc = await this._mainLlm.healthCheck(healthOptions);
243
+ results.llm = hc.ok && hc.value;
244
+ }
245
+ else {
246
+ // Fallback for ILlm implementations without healthCheck
247
+ const llmRes = await this._mainLlm.chat([{ role: 'user', content: 'ping' }], [], healthOptions);
248
+ results.llm = llmRes.ok;
249
+ }
250
+ }
251
+ catch {
252
+ results.llm = false;
253
+ }
254
+ try {
255
+ const firstStore = Object.values(this.deps.ragStores)[0];
256
+ const ragRes = firstStore
257
+ ? await firstStore.healthCheck(healthOptions)
258
+ : { ok: true, value: undefined };
259
+ results.rag = ragRes.ok;
260
+ }
261
+ catch {
262
+ results.rag = false;
263
+ }
264
+ try {
265
+ const mcpChecks = await Promise.all(this._activeClients.map(async (client) => {
266
+ try {
267
+ if (client.healthCheck) {
268
+ const hc = await client.healthCheck(healthOptions);
269
+ return {
270
+ name: 'mcp-client',
271
+ ok: hc.ok,
272
+ error: hc.ok || !hc.error
273
+ ? undefined
274
+ : hc.error instanceof Error
275
+ ? hc.error.message
276
+ : String(hc.error),
277
+ };
278
+ }
279
+ // Fallback for IMcpClient implementations without healthCheck
280
+ const tools = await client.listTools(healthOptions);
281
+ return {
282
+ name: 'mcp-client',
283
+ ok: tools.ok,
284
+ error: tools.ok || !tools.error
285
+ ? undefined
286
+ : tools.error instanceof Error
287
+ ? tools.error.message
288
+ : String(tools.error),
289
+ };
290
+ }
291
+ catch (err) {
292
+ return {
293
+ name: 'mcp-client',
294
+ ok: false,
295
+ error: err instanceof Error ? err.message : String(err),
296
+ };
297
+ }
298
+ }));
299
+ results.mcp = mcpChecks;
300
+ }
301
+ catch {
302
+ // AbortSignal timeout — leave mcp as empty
303
+ }
304
+ clearTimeout_();
305
+ return { ok: true, value: results };
306
+ }
307
+ async process(textOrMessages, options) {
308
+ let content = '';
309
+ const totalUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
310
+ let stopReason = 'stop';
311
+ const collectedToolCalls = [];
312
+ // Map streaming index → position in collectedToolCalls for delta correlation
313
+ const indexToPosition = new Map();
314
+ for await (const chunk of this.streamProcess(textOrMessages, options)) {
315
+ if (!chunk.ok)
316
+ return chunk;
317
+ if (chunk.value.content)
318
+ content += chunk.value.content;
319
+ if (chunk.value.toolCalls) {
320
+ for (const tc of chunk.value.toolCalls) {
321
+ const delta = toToolCallDelta(tc, collectedToolCalls.length);
322
+ // Try to find existing entry by index first (streaming deltas),
323
+ // then by id (non-streaming / first delta with id).
324
+ const posByIndex = indexToPosition.get(delta.index);
325
+ const existing = posByIndex !== undefined
326
+ ? collectedToolCalls[posByIndex]
327
+ : delta.id
328
+ ? collectedToolCalls.find((c) => c.id === delta.id)
329
+ : undefined;
330
+ if (existing) {
331
+ if (delta.arguments)
332
+ existing.function.arguments += delta.arguments;
333
+ }
334
+ else if (delta.name) {
335
+ const pos = collectedToolCalls.length;
336
+ collectedToolCalls.push({
337
+ id: delta.id || '',
338
+ type: 'function',
339
+ function: {
340
+ name: delta.name,
341
+ arguments: delta.arguments || '',
342
+ },
343
+ });
344
+ indexToPosition.set(delta.index, pos);
345
+ }
346
+ }
347
+ }
348
+ if (chunk.value.finishReason === 'tool_calls') {
349
+ stopReason = 'tool_calls';
350
+ }
351
+ if (chunk.value.usage) {
352
+ totalUsage.promptTokens += chunk.value.usage.promptTokens;
353
+ totalUsage.completionTokens += chunk.value.usage.completionTokens;
354
+ totalUsage.totalTokens += chunk.value.usage.totalTokens;
355
+ if (chunk.value.usage.models) {
356
+ totalUsage.models = chunk.value.usage.models;
357
+ }
358
+ }
359
+ }
360
+ return {
361
+ ok: true,
362
+ value: {
363
+ content,
364
+ iterations: 1,
365
+ toolCallCount: collectedToolCalls.length,
366
+ stopReason,
367
+ ...(collectedToolCalls.length > 0
368
+ ? { toolCalls: collectedToolCalls }
369
+ : {}),
370
+ usage: totalUsage,
371
+ },
372
+ };
373
+ }
374
+ async *streamProcess(textOrMessages, options) {
375
+ if (this.config.smartAgentEnabled === false) {
376
+ yield {
377
+ ok: false,
378
+ error: new OrchestratorError('SmartAgent is disabled', 'DISABLED'),
379
+ };
380
+ return;
381
+ }
382
+ this.metrics.requestCount.add();
383
+ const requestStart = Date.now();
384
+ const traceId = options?.trace?.traceId ?? randomUUID();
385
+ const rootSpan = this.tracer.startSpan('smart_agent.process', {
386
+ traceId,
387
+ attributes: { 'smart_agent.mode': this.config.mode || 'smart' },
388
+ });
389
+ let timeoutCleanup;
390
+ let opts = options;
391
+ if (this.config.timeoutMs) {
392
+ const { signal, clear } = createTimeoutSignal(this.config.timeoutMs);
393
+ timeoutCleanup = clear;
394
+ const merged = mergeSignals(options?.signal, signal);
395
+ opts = { ...options, signal: merged.signal };
396
+ }
397
+ const mode = this.config.mode || 'smart';
398
+ // Per-request client adapter detection from system prompt
399
+ let detectedAdapter;
400
+ const messages = typeof textOrMessages === 'string' ? undefined : textOrMessages;
401
+ if (messages && this.deps.clientAdapters?.length) {
402
+ const systemMsg = messages.find((m) => m.role === 'system');
403
+ if (systemMsg?.content) {
404
+ detectedAdapter = this.deps.clientAdapters.find((a) => a.detect(typeof systemMsg.content === 'string' ? systemMsg.content : ''));
405
+ }
406
+ }
407
+ const sessionId = options?.sessionId ?? 'default';
408
+ const externalTools = normalizeExternalTools(options?.externalTools);
409
+ opts?.sessionLogger?.logStep('external_tools_normalized', {
410
+ rawCount: options?.externalTools?.length ?? 0,
411
+ normalizedCount: externalTools.length,
412
+ normalizedNames: externalTools.map((t) => t.name),
413
+ });
414
+ opts?.sessionLogger?.logStep('pipeline_start', { mode, textOrMessages });
415
+ this.requestLogger.startRequest();
416
+ try {
417
+ if (mode === 'pass') {
418
+ const messages = typeof textOrMessages === 'string'
419
+ ? [{ role: 'user', content: textOrMessages }]
420
+ : textOrMessages;
421
+ opts?.sessionLogger?.logStep('client_request', { textOrMessages });
422
+ const stream = this._mainLlm.streamChat(messages, externalTools, opts);
423
+ let passContent = '';
424
+ const passToolCalls = [];
425
+ for await (const chunk of stream) {
426
+ if (chunk.ok) {
427
+ if (chunk.value.reset) {
428
+ passContent = '';
429
+ passToolCalls.length = 0;
430
+ continue;
431
+ }
432
+ if (chunk.value.content)
433
+ passContent += chunk.value.content;
434
+ if (chunk.value.toolCalls)
435
+ passToolCalls.push(...chunk.value.toolCalls);
436
+ }
437
+ yield chunk;
438
+ }
439
+ opts?.sessionLogger?.logStep('llm_response_pass', {
440
+ content: passContent,
441
+ toolCalls: passToolCalls.length > 0 ? passToolCalls : undefined,
442
+ });
443
+ rootSpan.setStatus('ok');
444
+ rootSpan.end();
445
+ return;
446
+ }
447
+ // Pipeline path (when configured via Builder)
448
+ if (this.deps.pipeline) {
449
+ const stream = this._runStructuredPipeline(textOrMessages, externalTools, opts, rootSpan, sessionId);
450
+ for await (const chunk of stream)
451
+ yield chunk;
452
+ rootSpan.setStatus('ok');
453
+ rootSpan.end();
454
+ return;
455
+ }
456
+ // 1. Unified Preparation (default hardcoded flow)
457
+ const initResult = await this._preparePipeline(textOrMessages, opts, rootSpan);
458
+ if (!initResult.ok) {
459
+ rootSpan.setStatus('error', initResult.error.message);
460
+ rootSpan.end();
461
+ yield initResult;
462
+ return;
463
+ }
464
+ let { processedHistory } = initResult.value;
465
+ const { subprompts, toolClientMap } = initResult.value;
466
+ // Token budget check — summarize if over budget
467
+ if (this.sessionManager.isOverBudget()) {
468
+ const sumResult = await this._summarizeHistory(processedHistory, opts);
469
+ if (sumResult.ok)
470
+ processedHistory = sumResult.value;
471
+ this.sessionManager.reset();
472
+ }
473
+ // 2. Decide context and tools for the WHOLE request
474
+ await this._resolveActiveClients(opts);
475
+ const actions = subprompts.filter((sp) => sp.type === 'action');
476
+ const hasActions = actions.length > 0;
477
+ const hasMcpClients = this._activeClients.length > 0;
478
+ const hasRagStores = Object.keys(this.deps.ragStores).length > 0;
479
+ const shouldRetrieve = mode === 'hard' || (hasActions && (hasMcpClients || hasRagStores));
480
+ let finalTools = [];
481
+ let retrieved = {
482
+ ragResults: {},
483
+ tools: [],
484
+ };
485
+ let skillContent = '';
486
+ if (shouldRetrieve) {
487
+ // Collect all action texts for RAG
488
+ const combinedActionText = actions.map((a) => a.text).join(' ');
489
+ // Translate + expand once (only used for stores in translateQueryStores)
490
+ const translateStores = this.deps.translateQueryStores;
491
+ let translatedText;
492
+ if (translateStores && translateStores.size > 0) {
493
+ translatedText = await this._toEnglishForRag(combinedActionText, opts);
494
+ if (this.config.queryExpansionEnabled) {
495
+ const expandResult = await this.queryExpander.expand(translatedText, opts);
496
+ if (expandResult.ok)
497
+ translatedText = expandResult.value;
498
+ }
499
+ }
500
+ const k = this.config.ragQueryK ?? 10;
501
+ const ragSpan = this.tracer.startSpan('smart_agent.rag_query', {
502
+ parent: rootSpan,
503
+ attributes: { 'rag.k': k },
504
+ });
505
+ const storeEntries = Object.entries(this.deps.ragStores);
506
+ // Build per-store embedding: translated for translateQuery stores, original for others
507
+ const mkEmbed = (text) => this.deps.embedder
508
+ ? new QueryEmbedding(text, this.deps.embedder, opts)
509
+ : new TextOnlyEmbedding(text);
510
+ // Cache embeddings to avoid duplicate embed calls
511
+ const originalEmbedding = mkEmbed(combinedActionText);
512
+ const translatedEmbedding = translatedText && translatedText !== combinedActionText
513
+ ? mkEmbed(translatedText)
514
+ : originalEmbedding;
515
+ const ragQueryResults = await Promise.all(storeEntries.map(([name, store]) => {
516
+ const emb = translateStores?.has(name) && translatedText
517
+ ? translatedEmbedding
518
+ : originalEmbedding;
519
+ return store.query(emb, k, opts).then((r) => ({ name, result: r }));
520
+ }));
521
+ ragSpan.end();
522
+ const ragResultsMap = {};
523
+ for (const { name, result: r } of ragQueryResults) {
524
+ ragResultsMap[name] = r.ok ? r.value : [];
525
+ this.metrics.ragQueryCount.add(1, {
526
+ store: name,
527
+ hit: String(r.ok && r.value.length > 0),
528
+ });
529
+ }
530
+ // Rerank results
531
+ // Rerank all stores in parallel, using matching query text per store
532
+ const rerankedEntries = await Promise.all(Object.entries(ragResultsMap).map(async ([name, results]) => {
533
+ if (results.length > 0) {
534
+ const rerankText = translateStores?.has(name) && translatedText
535
+ ? translatedText
536
+ : combinedActionText;
537
+ const rr = await this.reranker.rerank(rerankText, results, opts);
538
+ return { name, results: rr.ok ? rr.value : results };
539
+ }
540
+ return { name, results };
541
+ }));
542
+ const rerankedMap = {};
543
+ for (const { name, results } of rerankedEntries) {
544
+ rerankedMap[name] = results;
545
+ }
546
+ const { tools: mcpTools } = await this._listAllTools(opts);
547
+ // Collect all RAG results for tool discovery
548
+ const allRagResults = Object.values(rerankedMap).flat();
549
+ // Log RAG results with scores for diagnostics
550
+ for (const [storeName, results] of Object.entries(rerankedMap)) {
551
+ const logQuery = translateStores?.has(storeName) && translatedText
552
+ ? translatedText
553
+ : combinedActionText;
554
+ opts?.sessionLogger?.logStep(`rag_query_${storeName}`, {
555
+ query: logQuery.slice(0, 200),
556
+ k,
557
+ resultCount: results.length,
558
+ results: results.map((r) => ({
559
+ id: r.metadata.id,
560
+ score: r.score,
561
+ text: r.text.slice(0, 120),
562
+ })),
563
+ });
564
+ }
565
+ const ragToolNames = new Set(allRagResults
566
+ .map((r) => r.metadata.id)
567
+ .filter((id) => id?.startsWith('tool:'))
568
+ .map((id) => id.slice(5).replace(/:.*$/, '')));
569
+ const selectedMcpTools = ragToolNames.size > 0
570
+ ? mcpTools.filter((t) => ragToolNames.has(t.name))
571
+ : mode === 'hard'
572
+ ? mcpTools
573
+ : [];
574
+ // Log tool selection diagnostics
575
+ opts?.sessionLogger?.logStep('tools_selected', {
576
+ totalMcp: mcpTools.length,
577
+ ragMatchedTools: [...ragToolNames],
578
+ selectedCount: selectedMcpTools.length + externalTools.length,
579
+ selectedNames: [
580
+ ...selectedMcpTools.map((t) => t.name),
581
+ ...externalTools.map((t) => t.name),
582
+ ],
583
+ });
584
+ retrieved = {
585
+ ragResults: rerankedMap,
586
+ tools: selectedMcpTools,
587
+ };
588
+ finalTools =
589
+ mode === 'hard'
590
+ ? selectedMcpTools
591
+ : [...selectedMcpTools, ...externalTools];
592
+ opts?.sessionLogger?.logStep('external_tools_merge', {
593
+ mode,
594
+ mcpCount: selectedMcpTools.length,
595
+ externalCount: externalTools.length,
596
+ externalNames: externalTools.map((t) => t.name),
597
+ finalCount: finalTools.length,
598
+ });
599
+ // Skill injection (when enabled and skillManager configured)
600
+ if (this.config.skillInjectionEnabled !== false &&
601
+ this.deps.skillManager) {
602
+ const ragSkillNames = new Set(allRagResults
603
+ .map((r) => r.metadata.id)
604
+ .filter((id) => id?.startsWith('skill:'))
605
+ .map((id) => id.slice(6)));
606
+ // Fallback: dedicated RAG query when no skill:* in existing results
607
+ if (ragSkillNames.size === 0) {
608
+ const k = this.config.ragQueryK ?? 15;
609
+ const storeEntries = Object.entries(this.deps.ragStores);
610
+ const fallbackResults = await Promise.all(storeEntries.map(([name, store]) => {
611
+ const text = translateStores?.has(name) && translatedText
612
+ ? translatedText
613
+ : combinedActionText;
614
+ const emb = this.deps.embedder
615
+ ? new QueryEmbedding(text, this.deps.embedder, opts)
616
+ : new TextOnlyEmbedding(text);
617
+ return store.query(emb, k, opts);
618
+ }));
619
+ for (const result of fallbackResults) {
620
+ if (result.ok) {
621
+ for (const r of result.value) {
622
+ const id = r.metadata.id;
623
+ if (id?.startsWith('skill:')) {
624
+ ragSkillNames.add(id.slice(6));
625
+ }
626
+ }
627
+ }
628
+ }
629
+ if (ragSkillNames.size > 0) {
630
+ opts?.sessionLogger?.logStep('skill_select_rag_fallback', {
631
+ query: combinedActionText.slice(0, 200),
632
+ k,
633
+ matchedSkills: [...ragSkillNames],
634
+ });
635
+ }
636
+ }
637
+ const allSkillsResult = await this.deps.skillManager.listSkills(opts);
638
+ if (allSkillsResult.ok) {
639
+ const allSkills = allSkillsResult.value;
640
+ const matched = ragSkillNames.size > 0
641
+ ? allSkills.filter((s) => ragSkillNames.has(s.name))
642
+ : mode === 'hard'
643
+ ? allSkills
644
+ : [];
645
+ const contentParts = [];
646
+ for (const skill of matched) {
647
+ const contentResult = await skill.getContent(undefined, opts);
648
+ if (contentResult.ok && contentResult.value) {
649
+ contentParts.push(`### Skill: ${skill.name}\n${contentResult.value}`);
650
+ }
651
+ }
652
+ skillContent = contentParts.join('\n\n');
653
+ opts?.sessionLogger?.logStep('skills_selected', {
654
+ totalSkills: allSkills.length,
655
+ ragMatchedSkills: [...ragSkillNames],
656
+ selectedCount: matched.length,
657
+ selectedNames: matched.map((s) => s.name),
658
+ });
659
+ }
660
+ }
661
+ }
662
+ else {
663
+ // If we're here, mode is definitely 'smart' (not 'hard' or 'pass')
664
+ finalTools = externalTools;
665
+ }
666
+ const filteredTools = this.toolAvailabilityRegistry.filterTools(sessionId, finalTools);
667
+ finalTools = filteredTools.allowed;
668
+ if (filteredTools.blocked.length > 0) {
669
+ opts?.sessionLogger?.logStep('active_tools_filtered_by_registry', {
670
+ blocked: filteredTools.blocked,
671
+ });
672
+ }
673
+ // 3. Assemble Context once
674
+ const mainAction = actions.length > 1
675
+ ? {
676
+ type: 'action',
677
+ text: actions.map((a) => a.text).join('\n'),
678
+ context: actions.find((a) => a.context)?.context,
679
+ dependency: 'independent',
680
+ }
681
+ : actions.length === 1
682
+ ? actions[0]
683
+ : subprompts.find((sp) => sp.type === 'chat') || subprompts[0];
684
+ if (actions.length > 1) {
685
+ opts?.sessionLogger?.logStep('actions_merged', {
686
+ count: actions.length,
687
+ actions: actions.map((a) => ({
688
+ text: a.text,
689
+ dependency: a.dependency,
690
+ })),
691
+ });
692
+ }
693
+ const assembleSpan = this.tracer.startSpan('smart_agent.assemble', {
694
+ parent: rootSpan,
695
+ });
696
+ const assembleResult = await this.deps.assembler.assemble(mainAction, retrieved, processedHistory, opts);
697
+ if (!assembleResult.ok) {
698
+ assembleSpan.setStatus('error', assembleResult.error.message);
699
+ assembleSpan.end();
700
+ rootSpan.setStatus('error', assembleResult.error.message);
701
+ rootSpan.end();
702
+ yield {
703
+ ok: false,
704
+ error: new OrchestratorError(assembleResult.error.message, 'ASSEMBLER_ERROR'),
705
+ };
706
+ return;
707
+ }
708
+ assembleSpan.setStatus('ok');
709
+ assembleSpan.end();
710
+ // Inject skill content into system message (post-assembly)
711
+ if (skillContent) {
712
+ const sysMsg = assembleResult.value.find((m) => m.role === 'system');
713
+ if (sysMsg) {
714
+ sysMsg.content += `\n\n## Active Skills\n${skillContent}`;
715
+ }
716
+ else {
717
+ assembleResult.value.unshift({
718
+ role: 'system',
719
+ content: `## Active Skills\n${skillContent}`,
720
+ });
721
+ }
722
+ }
723
+ opts?.sessionLogger?.logStep(`final_context_assembled`, {
724
+ messages: assembleResult.value,
725
+ tools: finalTools.map((t) => t.name),
726
+ });
727
+ // 4. Single Streaming Loop
728
+ const stream = this._runStreamingToolLoop(mainAction, retrieved, assembleResult.value, toolClientMap, opts, rootSpan, sessionId, mode === 'hard' ? [] : externalTools, finalTools, detectedAdapter);
729
+ for await (const chunk of stream)
730
+ yield chunk;
731
+ rootSpan.setStatus('ok');
732
+ }
733
+ finally {
734
+ this.requestLogger.endRequest();
735
+ rootSpan.end();
736
+ timeoutCleanup?.();
737
+ this.metrics.requestLatency.record(Date.now() - requestStart);
738
+ }
739
+ }
740
+ async _preparePipeline(textOrMessages, opts, parentSpan) {
741
+ opts?.sessionLogger?.logStep('client_request', { textOrMessages });
742
+ const text = typeof textOrMessages === 'string'
743
+ ? textOrMessages
744
+ : (textOrMessages.filter((m) => m.role === 'user').slice(-1)[0]
745
+ ?.content ?? '');
746
+ const history = typeof textOrMessages === 'string' ? [] : textOrMessages;
747
+ let processedHistory = history;
748
+ const summarizeLimit = this.config.historyAutoSummarizeLimit ?? 10;
749
+ if (this._helperLlm && history.length > summarizeLimit) {
750
+ const res = await this._summarizeHistory(history, opts);
751
+ if (res.ok)
752
+ processedHistory = res.value;
753
+ }
754
+ let subprompts;
755
+ if (this.config.classificationEnabled === false) {
756
+ // Skip classification — treat entire input as a single action
757
+ subprompts = [
758
+ { type: 'action', text, dependency: 'independent' },
759
+ ];
760
+ opts?.sessionLogger?.logStep('classification_skipped', { text });
761
+ }
762
+ else {
763
+ const classifySpan = this.tracer.startSpan('smart_agent.classify', {
764
+ parent: parentSpan,
765
+ });
766
+ const classifyResult = await this._classifier.classify(text, opts);
767
+ if (!classifyResult.ok) {
768
+ classifySpan.setStatus('error', classifyResult.error.message);
769
+ classifySpan.end();
770
+ return {
771
+ ok: false,
772
+ error: new OrchestratorError(classifyResult.error.message, 'CLASSIFIER_ERROR'),
773
+ };
774
+ }
775
+ classifySpan.setStatus('ok');
776
+ classifySpan.end();
777
+ opts?.sessionLogger?.logStep('classifier_response', {
778
+ subprompts: classifyResult.value,
779
+ });
780
+ subprompts = classifyResult.value;
781
+ }
782
+ for (const sp of subprompts) {
783
+ this.metrics.classifierIntentCount.add(1, { intent: sp.type });
784
+ }
785
+ const { toolClientMap } = await this._listAllTools(opts);
786
+ return { ok: true, value: { subprompts, processedHistory, toolClientMap } };
787
+ }
788
+ async *_runStreamingToolLoop(_action, _retrieved, initialMessages, toolClientMap, opts, parentSpan, sessionId, externalTools, activeTools, clientAdapter) {
789
+ const toolLoopSpan = this.tracer.startSpan('smart_agent.tool_loop', {
790
+ parent: parentSpan,
791
+ });
792
+ let toolCallCount = 0;
793
+ let messages = initialMessages;
794
+ const usage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
795
+ const externalToolNames = new Set(externalTools.map((t) => t.name));
796
+ const timingLog = [];
797
+ const loopStart = Date.now();
798
+ let currentTools = activeTools;
799
+ // Inject tool priority instruction when external tools are present
800
+ if (externalTools.length > 0) {
801
+ const systemIdx = messages.findIndex((m) => m.role === 'system');
802
+ if (systemIdx >= 0) {
803
+ const sys = messages[systemIdx];
804
+ messages = [...messages];
805
+ messages[systemIdx] = {
806
+ ...sys,
807
+ content: `${sys.content}\n\nIMPORTANT: You have internal tools and client-provided tools (marked [client-provided] in their description). Always prefer internal tools when they can accomplish the task. Use client-provided tools only when no internal tool can do the job.`,
808
+ };
809
+ }
810
+ }
811
+ // Inject pending internal tool results from previous mixed-call request
812
+ if (this.pendingToolResults.has(sessionId)) {
813
+ const pending = await this.pendingToolResults.consume(sessionId);
814
+ if (pending) {
815
+ messages = [
816
+ ...messages,
817
+ pending.assistantMessage,
818
+ ...pending.results.map((r) => ({
819
+ role: 'tool',
820
+ content: r.text,
821
+ tool_call_id: r.toolCallId,
822
+ })),
823
+ ];
824
+ opts?.sessionLogger?.logStep('pending_tool_results_injected', {
825
+ toolNames: pending.results.map((r) => r.toolName),
826
+ });
827
+ }
828
+ }
829
+ for (let iteration = 0;; iteration++) {
830
+ let iterationBuffer = '';
831
+ if (opts?.signal?.aborted) {
832
+ toolLoopSpan.setStatus('error', 'Aborted');
833
+ toolLoopSpan.end();
834
+ yield { ok: false, error: new OrchestratorError('Aborted', 'ABORTED') };
835
+ return;
836
+ }
837
+ if (iteration >= this.config.maxIterations) {
838
+ timingLog.push({ phase: 'total', duration: Date.now() - loopStart });
839
+ toolLoopSpan.addEvent('iteration_limit_reached');
840
+ toolLoopSpan.end();
841
+ yield {
842
+ ok: true,
843
+ value: {
844
+ content: '',
845
+ finishReason: 'length',
846
+ usage: {
847
+ ...usage,
848
+ models: this.requestLogger.getSummary().byModel,
849
+ },
850
+ timing: timingLog,
851
+ },
852
+ };
853
+ return;
854
+ }
855
+ // Refresh MCP tools on each iteration (when enabled)
856
+ if (iteration > 0 && this.config.refreshToolsPerIteration !== false) {
857
+ const refreshSpan = this.tracer.startSpan('smart_agent.refresh_tools', {
858
+ parent: toolLoopSpan,
859
+ attributes: { 'llm.iteration': iteration + 1 },
860
+ });
861
+ const refreshed = await this._listAllTools(opts);
862
+ const prevNames = [...toolClientMap.keys()];
863
+ toolClientMap.clear();
864
+ for (const [name, client] of refreshed.toolClientMap) {
865
+ toolClientMap.set(name, client);
866
+ }
867
+ currentTools = [...refreshed.tools, ...externalTools];
868
+ opts?.sessionLogger?.logStep('tools_refreshed', {
869
+ iteration: iteration + 1,
870
+ previous: prevNames,
871
+ current: currentTools.map((t) => t.name),
872
+ });
873
+ refreshSpan.end();
874
+ }
875
+ // Per-iteration RAG tool re-selection (when enabled)
876
+ if (iteration > 0 &&
877
+ this.config.toolReselectPerIteration &&
878
+ this.deps.ragStores?.tools) {
879
+ const reselectSpan = this.tracer.startSpan('smart_agent.tool_reselect', {
880
+ parent: toolLoopSpan,
881
+ attributes: { 'llm.iteration': iteration + 1 },
882
+ });
883
+ try {
884
+ // Extract last tool calls
885
+ const lastAssistant = [...messages]
886
+ .reverse()
887
+ .find((m) => m.role === 'assistant');
888
+ const toolCallNames = [];
889
+ if (lastAssistant && 'tool_calls' in lastAssistant) {
890
+ const tcs = lastAssistant.tool_calls;
891
+ if (Array.isArray(tcs)) {
892
+ for (const tc of tcs) {
893
+ const name = tc?.function?.name || '';
894
+ if (name)
895
+ toolCallNames.push(name);
896
+ }
897
+ }
898
+ }
899
+ // Skip for read-only tools — they rarely need different tools on retry
900
+ const readOnlyPrefixes = [
901
+ 'Search',
902
+ 'Read',
903
+ 'Get',
904
+ 'List',
905
+ 'Describe',
906
+ ];
907
+ const allReadOnly = toolCallNames.length > 0 &&
908
+ toolCallNames.every((n) => readOnlyPrefixes.some((p) => n.startsWith(p)));
909
+ if (!allReadOnly) {
910
+ // Build context-aware query from error/result context
911
+ const lastToolMsg = [...messages]
912
+ .reverse()
913
+ .find((m) => m.role === 'tool');
914
+ const toolResult = typeof lastToolMsg?.content === 'string'
915
+ ? lastToolMsg.content.slice(0, 200)
916
+ : '';
917
+ const isError = toolResult.toLowerCase().includes('error') ||
918
+ toolResult.toLowerCase().includes('already exist') ||
919
+ toolResult.toLowerCase().includes('failed');
920
+ const inputText = _action.text;
921
+ let reSelectQuery;
922
+ if (toolCallNames.length > 0 && isError) {
923
+ const updateHints = toolCallNames
924
+ .filter((n) => n.startsWith('Create'))
925
+ .map((n) => n.replace(/^Create/, 'Update'))
926
+ .join(', ');
927
+ const hints = updateHints ? ` Need ${updateHints}.` : '';
928
+ reSelectQuery = `${toolCallNames.join(', ')} failed: ${toolResult.slice(0, 150)}.${hints} ${inputText.slice(0, 200)}`;
929
+ }
930
+ else if (toolCallNames.length > 0) {
931
+ reSelectQuery = `After ${toolCallNames.join(', ')}: ${toolResult}\n${inputText.slice(0, 200)}`;
932
+ }
933
+ else {
934
+ reSelectQuery = inputText;
935
+ }
936
+ // Query tools RAG
937
+ const embedding = this.deps.embedder
938
+ ? new QueryEmbedding(reSelectQuery, this.deps.embedder, opts)
939
+ : new TextOnlyEmbedding(reSelectQuery);
940
+ const ragK = this.config.ragQueryK ?? 20;
941
+ const ragResult = await this.deps.ragStores.tools.query(embedding, ragK, opts);
942
+ if (ragResult.ok && ragResult.value.length > 0) {
943
+ const newToolNames = new Set(ragResult.value
944
+ .map((r) => r.metadata?.id || '')
945
+ .filter((id) => id.startsWith('tool:'))
946
+ .map((id) => id.slice(5).replace(/:.*$/, '')));
947
+ if (newToolNames.size > 0) {
948
+ const refreshed = await this._listAllTools(opts);
949
+ const newMcpTools = refreshed.tools.filter((t) => newToolNames.has(t.name));
950
+ currentTools = [
951
+ ...newMcpTools,
952
+ ...externalTools,
953
+ ];
954
+ opts?.sessionLogger?.logStep('tools_reselected', {
955
+ iteration: iteration + 1,
956
+ query: reSelectQuery.slice(0, 100),
957
+ previousTools: toolCallNames,
958
+ newTools: [...newToolNames],
959
+ });
960
+ }
961
+ }
962
+ }
963
+ else {
964
+ opts?.sessionLogger?.logStep('tools_reselect_skipped', {
965
+ iteration: iteration + 1,
966
+ reason: 'read-only tools only',
967
+ tools: toolCallNames,
968
+ });
969
+ }
970
+ }
971
+ finally {
972
+ reselectSpan.end();
973
+ }
974
+ }
975
+ const filteredForIteration = this.toolAvailabilityRegistry.filterTools(sessionId, currentTools);
976
+ currentTools = filteredForIteration.allowed;
977
+ if (filteredForIteration.blocked.length > 0) {
978
+ opts?.sessionLogger?.logStep('active_tools_filtered_in_iteration', {
979
+ iteration: iteration + 1,
980
+ blocked: filteredForIteration.blocked,
981
+ });
982
+ }
983
+ opts?.sessionLogger?.logStep(`llm_request_iter_${iteration + 1}`, {
984
+ messages,
985
+ tools: currentTools,
986
+ });
987
+ const llmSpan = this.tracer.startSpan('smart_agent.llm_call', {
988
+ parent: toolLoopSpan,
989
+ attributes: { 'llm.iteration': iteration + 1 },
990
+ });
991
+ this.metrics.llmCallCount.add();
992
+ const llmCallStart = Date.now();
993
+ const stream = this.defaultLlmCallStrategy.call(this._mainLlm, messages, currentTools, opts);
994
+ let content = '';
995
+ let finishReason;
996
+ const toolCallsMap = new Map();
997
+ // Track which streaming indices belong to external tools so that
998
+ // argument-only continuation deltas (no name field) are forwarded too.
999
+ const externalToolIndices = new Set();
1000
+ for await (const chunkResult of stream) {
1001
+ if (!chunkResult.ok) {
1002
+ llmSpan.setStatus('error', chunkResult.error.message);
1003
+ llmSpan.end();
1004
+ toolLoopSpan.setStatus('error', chunkResult.error.message);
1005
+ toolLoopSpan.end();
1006
+ yield {
1007
+ ok: false,
1008
+ error: new OrchestratorError(chunkResult.error.message, 'LLM_ERROR'),
1009
+ };
1010
+ return;
1011
+ }
1012
+ const chunk = chunkResult.value;
1013
+ // Mid-stream retry: discard accumulated state and restart accumulation
1014
+ if (chunk.reset) {
1015
+ content = '';
1016
+ iterationBuffer = '';
1017
+ toolCallsMap.clear();
1018
+ externalToolIndices.clear();
1019
+ finishReason = undefined;
1020
+ continue;
1021
+ }
1022
+ if (chunk.content) {
1023
+ content += chunk.content;
1024
+ // When a client adapter is detected, buffer content — it will be wrapped after the stream completes
1025
+ if (!clientAdapter) {
1026
+ if (this.config.streamMode === 'final') {
1027
+ iterationBuffer += chunk.content;
1028
+ }
1029
+ else {
1030
+ yield { ok: true, value: { content: chunk.content } };
1031
+ }
1032
+ }
1033
+ }
1034
+ if (chunk.toolCalls) {
1035
+ // Register newly seen external tool indices
1036
+ for (const tc of chunk.toolCalls) {
1037
+ const name = getStreamToolCallName(tc);
1038
+ if (name && externalToolNames.has(name)) {
1039
+ const delta = toToolCallDelta(tc, 0);
1040
+ externalToolIndices.add(delta.index);
1041
+ }
1042
+ }
1043
+ const externalDeltas = chunk.toolCalls.filter((tc) => {
1044
+ const delta = toToolCallDelta(tc, 0);
1045
+ return externalToolIndices.has(delta.index);
1046
+ });
1047
+ if (externalDeltas.length > 0) {
1048
+ yield {
1049
+ ok: true,
1050
+ value: { content: '', toolCalls: externalDeltas },
1051
+ };
1052
+ }
1053
+ for (const [fallbackIndex, rawToolCall,] of chunk.toolCalls.entries()) {
1054
+ const tc = toToolCallDelta(rawToolCall, fallbackIndex);
1055
+ if (!toolCallsMap.has(tc.index)) {
1056
+ toolCallsMap.set(tc.index, {
1057
+ id: tc.id || '',
1058
+ name: tc.name || '',
1059
+ arguments: tc.arguments || '',
1060
+ });
1061
+ }
1062
+ else {
1063
+ const ex = toolCallsMap.get(tc.index);
1064
+ if (ex) {
1065
+ if (tc.id)
1066
+ ex.id = tc.id;
1067
+ if (tc.name)
1068
+ ex.name = tc.name;
1069
+ if (tc.arguments)
1070
+ ex.arguments += tc.arguments;
1071
+ }
1072
+ }
1073
+ }
1074
+ }
1075
+ if (chunk.finishReason)
1076
+ finishReason = chunk.finishReason;
1077
+ if (chunk.usage) {
1078
+ usage.promptTokens += chunk.usage.promptTokens;
1079
+ usage.completionTokens += chunk.usage.completionTokens;
1080
+ usage.totalTokens += chunk.usage.totalTokens;
1081
+ this.sessionManager.addTokens(chunk.usage.totalTokens);
1082
+ }
1083
+ }
1084
+ llmSpan.setStatus('ok');
1085
+ llmSpan.end();
1086
+ const llmCallDuration = Date.now() - llmCallStart;
1087
+ this.metrics.llmCallLatency.record(llmCallDuration);
1088
+ timingLog.push({
1089
+ phase: `llm_call_${iteration + 1}`,
1090
+ duration: llmCallDuration,
1091
+ });
1092
+ // In 'final' mode: yield buffered content only if this is the last iteration
1093
+ if (this.config.streamMode === 'final' && iterationBuffer) {
1094
+ if (finishReason !== 'tool_calls') {
1095
+ // Final iteration — stream the buffered content
1096
+ yield { ok: true, value: { content: iterationBuffer } };
1097
+ }
1098
+ iterationBuffer = '';
1099
+ }
1100
+ const toolCalls = Array.from(toolCallsMap.values()).map((tc) => {
1101
+ let args = {};
1102
+ try {
1103
+ args = JSON.parse(tc.arguments);
1104
+ }
1105
+ catch {
1106
+ args = {};
1107
+ }
1108
+ return { id: tc.id, name: tc.name, arguments: args };
1109
+ });
1110
+ opts?.sessionLogger?.logStep(`llm_response_iter_${iteration + 1}`, {
1111
+ content,
1112
+ toolCalls,
1113
+ finishReason,
1114
+ });
1115
+ if (finishReason !== 'tool_calls' || toolCalls.length === 0) {
1116
+ // Output validation
1117
+ const valResult = await this.outputValidator.validate(content, { messages, tools: currentTools }, opts);
1118
+ if (valResult.ok && !valResult.value.valid) {
1119
+ const correction = valResult.value.correctedContent ?? valResult.value.reason;
1120
+ messages = [
1121
+ ...messages,
1122
+ { role: 'assistant', content },
1123
+ {
1124
+ role: 'user',
1125
+ content: `Your previous response was rejected by validation: ${correction}. Please try again.`,
1126
+ },
1127
+ ];
1128
+ continue;
1129
+ }
1130
+ opts?.sessionLogger?.logStep('final_response', { content, usage });
1131
+ // onBeforeStream hook — consumer transforms content before streaming
1132
+ if (this.config.onBeforeStream) {
1133
+ const hookCtx = { messages };
1134
+ for await (const chunk of this.config.onBeforeStream(content, hookCtx)) {
1135
+ if (clientAdapter) {
1136
+ yield {
1137
+ ok: true,
1138
+ value: { content: clientAdapter.wrapResponse(chunk) },
1139
+ };
1140
+ }
1141
+ else {
1142
+ yield { ok: true, value: { content: chunk } };
1143
+ }
1144
+ }
1145
+ }
1146
+ else if (clientAdapter && content) {
1147
+ yield {
1148
+ ok: true,
1149
+ value: { content: clientAdapter.wrapResponse(content) },
1150
+ };
1151
+ }
1152
+ timingLog.push({ phase: 'total', duration: Date.now() - loopStart });
1153
+ toolLoopSpan.setStatus('ok');
1154
+ toolLoopSpan.end();
1155
+ const summary = this.requestLogger.getSummary();
1156
+ yield {
1157
+ ok: true,
1158
+ value: {
1159
+ content: '',
1160
+ finishReason: finishReason || 'stop',
1161
+ usage: {
1162
+ ...usage,
1163
+ models: summary.byModel,
1164
+ },
1165
+ timing: timingLog,
1166
+ },
1167
+ };
1168
+ return;
1169
+ }
1170
+ const internalCalls = toolCalls.filter((tc) => toolClientMap.has(tc.name));
1171
+ const validExternalCalls = toolCalls.filter((tc) => externalToolNames.has(tc.name));
1172
+ const blockedToolNames = this.toolAvailabilityRegistry.getBlockedToolNames(sessionId);
1173
+ const blockedCalls = toolCalls.filter((tc) => blockedToolNames.has(tc.name));
1174
+ const hallucinations = toolCalls.filter((tc) => !blockedToolNames.has(tc.name) &&
1175
+ !toolClientMap.has(tc.name) &&
1176
+ !externalToolNames.has(tc.name));
1177
+ if (blockedCalls.length > 0) {
1178
+ messages = [
1179
+ ...messages,
1180
+ {
1181
+ role: 'assistant',
1182
+ content: content || null,
1183
+ tool_calls: blockedCalls.map((tc) => ({
1184
+ id: tc.id,
1185
+ type: 'function',
1186
+ function: {
1187
+ name: tc.name,
1188
+ arguments: JSON.stringify(tc.arguments),
1189
+ },
1190
+ })),
1191
+ },
1192
+ ];
1193
+ for (const blocked of blockedCalls) {
1194
+ messages = [
1195
+ ...messages,
1196
+ {
1197
+ role: 'tool',
1198
+ content: `Error: Tool "${blocked.name}" is temporarily unavailable in this session.`,
1199
+ tool_call_id: blocked.id,
1200
+ },
1201
+ ];
1202
+ }
1203
+ opts?.sessionLogger?.logStep('blocked_tool_calls_intercepted', {
1204
+ toolNames: blockedCalls.map((tc) => tc.name),
1205
+ });
1206
+ continue;
1207
+ }
1208
+ if (hallucinations.length > 0) {
1209
+ messages = [
1210
+ ...messages,
1211
+ {
1212
+ role: 'assistant',
1213
+ content: content || null,
1214
+ tool_calls: toolCalls.map((tc) => ({
1215
+ id: tc.id,
1216
+ type: 'function',
1217
+ function: {
1218
+ name: tc.name,
1219
+ arguments: JSON.stringify(tc.arguments),
1220
+ },
1221
+ })),
1222
+ },
1223
+ ];
1224
+ for (const h of hallucinations) {
1225
+ messages = [
1226
+ ...messages,
1227
+ {
1228
+ role: 'tool',
1229
+ content: `Error: Tool "${h.name}" not found.`,
1230
+ tool_call_id: h.id,
1231
+ },
1232
+ ];
1233
+ }
1234
+ continue;
1235
+ }
1236
+ if (validExternalCalls.length > 0) {
1237
+ // Mixed calls: fire internal tools async, store pending results
1238
+ if (internalCalls.length > 0) {
1239
+ fireInternalToolsAsync(content, internalCalls, this.pendingToolResults, sessionId, {
1240
+ toolClientMap,
1241
+ toolCache: this.toolCache,
1242
+ metrics: this.metrics,
1243
+ options: opts,
1244
+ });
1245
+ opts?.sessionLogger?.logStep('mixed_tool_calls', {
1246
+ internal: internalCalls.map((tc) => tc.name),
1247
+ external: validExternalCalls.map((tc) => tc.name),
1248
+ });
1249
+ }
1250
+ timingLog.push({ phase: 'total', duration: Date.now() - loopStart });
1251
+ toolLoopSpan.setStatus('ok');
1252
+ toolLoopSpan.end();
1253
+ yield {
1254
+ ok: true,
1255
+ value: {
1256
+ content: '',
1257
+ finishReason: 'tool_calls',
1258
+ usage: {
1259
+ ...usage,
1260
+ models: this.requestLogger.getSummary().byModel,
1261
+ },
1262
+ timing: timingLog,
1263
+ },
1264
+ };
1265
+ return;
1266
+ }
1267
+ if (content || internalCalls.length > 0)
1268
+ messages = [
1269
+ ...messages,
1270
+ {
1271
+ role: 'assistant',
1272
+ content: content || null,
1273
+ tool_calls: internalCalls.map((tc) => ({
1274
+ id: tc.id,
1275
+ type: 'function',
1276
+ function: {
1277
+ name: tc.name,
1278
+ arguments: JSON.stringify(tc.arguments),
1279
+ },
1280
+ })),
1281
+ },
1282
+ ];
1283
+ // Truncate batch to remaining budget
1284
+ const remaining = this.config.maxToolCalls !== undefined
1285
+ ? this.config.maxToolCalls - toolCallCount
1286
+ : internalCalls.length;
1287
+ if (remaining <= 0) {
1288
+ timingLog.push({ phase: 'total', duration: Date.now() - loopStart });
1289
+ toolLoopSpan.addEvent('tool_call_limit_reached');
1290
+ toolLoopSpan.end();
1291
+ yield {
1292
+ ok: true,
1293
+ value: {
1294
+ content: '',
1295
+ finishReason: 'length',
1296
+ usage: {
1297
+ ...usage,
1298
+ models: this.requestLogger.getSummary().byModel,
1299
+ },
1300
+ timing: timingLog,
1301
+ },
1302
+ };
1303
+ return;
1304
+ }
1305
+ const batch = internalCalls.slice(0, remaining);
1306
+ const heartbeatMs = this.config.heartbeatIntervalMs ?? 5000;
1307
+ // Yield all progress messages before execution
1308
+ for (const tc of batch) {
1309
+ yield {
1310
+ ok: true,
1311
+ value: { content: `\n\n[SmartAgent: Executing ${tc.name}...]\n` },
1312
+ };
1313
+ }
1314
+ const toolExecPromises = batch.map(async (tc) => {
1315
+ const toolStart = Date.now();
1316
+ opts?.sessionLogger?.logStep(`mcp_call_${tc.name}`, {
1317
+ arguments: tc.arguments,
1318
+ });
1319
+ const client = toolClientMap.get(tc.name);
1320
+ if (!client)
1321
+ return { tc, text: '', res: null, duration: 0 };
1322
+ const toolSpan = this.tracer.startSpan('smart_agent.tool_call', {
1323
+ parent: toolLoopSpan,
1324
+ attributes: { 'tool.name': tc.name },
1325
+ });
1326
+ const cached = this.toolCache.get(tc.name, tc.arguments);
1327
+ const res = cached
1328
+ ? (() => {
1329
+ this.metrics.toolCacheHitCount.add();
1330
+ toolSpan.setAttribute('cache', 'hit');
1331
+ return { ok: true, value: cached };
1332
+ })()
1333
+ : await (async () => {
1334
+ const r = await client.callTool(tc.name, tc.arguments, opts);
1335
+ if (r.ok)
1336
+ this.toolCache.set(tc.name, tc.arguments, r.value);
1337
+ return r;
1338
+ })();
1339
+ const text = !res.ok
1340
+ ? res.error.message
1341
+ : typeof res.value.content === 'string'
1342
+ ? res.value.content
1343
+ : JSON.stringify(res.value.content);
1344
+ toolSpan.setStatus(res.ok ? 'ok' : 'error', res.ok ? undefined : text);
1345
+ toolSpan.end();
1346
+ return { tc, text, res, duration: Date.now() - toolStart };
1347
+ });
1348
+ // Race: tool execution vs periodic heartbeat
1349
+ const allDone = Promise.all(toolExecPromises);
1350
+ const pendingTools = new Set(batch.map((tc) => tc.name));
1351
+ const toolStartTime = Date.now();
1352
+ let results = [];
1353
+ let settled = false;
1354
+ // Mark individual tools as done when they resolve
1355
+ for (const [i, p] of toolExecPromises.entries()) {
1356
+ p.then(() => pendingTools.delete(batch[i].name));
1357
+ }
1358
+ while (!settled) {
1359
+ const winner = await Promise.race([
1360
+ allDone.then((r) => ({ tag: 'done', results: r })),
1361
+ new Promise((resolve) => setTimeout(() => resolve({ tag: 'tick' }), heartbeatMs)),
1362
+ ]);
1363
+ if (winner.tag === 'done') {
1364
+ results = winner.results;
1365
+ settled = true;
1366
+ }
1367
+ else {
1368
+ // Yield heartbeat for each still-pending tool
1369
+ for (const tool of pendingTools) {
1370
+ yield {
1371
+ ok: true,
1372
+ value: {
1373
+ content: '',
1374
+ heartbeat: {
1375
+ tool,
1376
+ elapsed: Date.now() - toolStartTime,
1377
+ },
1378
+ },
1379
+ };
1380
+ }
1381
+ }
1382
+ }
1383
+ // Collect per-tool timing into the shared timing log
1384
+ for (const r of results) {
1385
+ timingLog.push({
1386
+ phase: `tool_${r.tc.name}`,
1387
+ duration: r.duration,
1388
+ });
1389
+ }
1390
+ // Process results: update availability, metrics, messages
1391
+ const toolMessages = [];
1392
+ for (const { tc, text, res } of results) {
1393
+ if (!res)
1394
+ continue;
1395
+ if (!res.ok &&
1396
+ isToolContextUnavailableError(text) &&
1397
+ !externalToolNames.has(tc.name)) {
1398
+ const entry = this.toolAvailabilityRegistry.block(sessionId, tc.name, text);
1399
+ currentTools = currentTools.filter((t) => t.name !== tc.name);
1400
+ opts?.sessionLogger?.logStep(`tool_blacklisted_${tc.name}`, {
1401
+ reason: text,
1402
+ blockedUntil: entry.blockedUntil,
1403
+ });
1404
+ }
1405
+ opts?.sessionLogger?.logStep(`mcp_result_${tc.name}`, {
1406
+ result: text,
1407
+ });
1408
+ toolCallCount++;
1409
+ this.metrics.toolCallCount.add();
1410
+ toolMessages.push({
1411
+ role: 'tool',
1412
+ content: text,
1413
+ tool_call_id: tc.id,
1414
+ });
1415
+ }
1416
+ messages = [...messages, ...toolMessages];
1417
+ }
1418
+ }
1419
+ async _listAllTools(opts) {
1420
+ await this._resolveActiveClients(opts);
1421
+ const tools = [];
1422
+ const toolClientMap = new Map();
1423
+ const settled = await Promise.allSettled(this._activeClients.map(async (client) => ({
1424
+ client,
1425
+ result: await client.listTools(opts),
1426
+ })));
1427
+ for (const e of settled) {
1428
+ if (e.status === 'fulfilled' && e.value.result.ok) {
1429
+ for (const t of e.value.result.value) {
1430
+ if (!toolClientMap.has(t.name)) {
1431
+ tools.push(t);
1432
+ toolClientMap.set(t.name, e.value.client);
1433
+ }
1434
+ }
1435
+ }
1436
+ }
1437
+ return { tools, toolClientMap };
1438
+ }
1439
+ async _toEnglishForRag(text, opts) {
1440
+ if (/^[\p{ASCII}]+$/u.test(text) || text.length < 15)
1441
+ return text;
1442
+ const dp = 'Translate the user request to English for search purposes. Preserve technical terms if present. Reply with only the expanded English terms, no explanation.';
1443
+ const llm = this._helperLlm || this._mainLlm;
1444
+ const res = await llm.chat([
1445
+ {
1446
+ role: 'system',
1447
+ content: this.config.ragTranslatePrompt || dp,
1448
+ },
1449
+ { role: 'user', content: text },
1450
+ ], [], opts);
1451
+ return res.ok && res.value.content.trim() ? res.value.content.trim() : text;
1452
+ }
1453
+ async _summarizeHistory(h, opts) {
1454
+ if (!this._helperLlm)
1455
+ return { ok: true, value: h };
1456
+ const toS = h.slice(0, -5);
1457
+ const rec = h.slice(-5);
1458
+ if (toS.length === 0)
1459
+ return { ok: true, value: h };
1460
+ const dp = 'Summarize the conversation so far in 2-3 sentences. Focus on the user goals and the current status of the task. Keep technical SAP terms as is.';
1461
+ const summarizeStart = Date.now();
1462
+ const res = await this._helperLlm.chat([
1463
+ ...toS,
1464
+ {
1465
+ role: 'system',
1466
+ content: this.config.historySummaryPrompt || dp,
1467
+ },
1468
+ ], [], opts);
1469
+ this.requestLogger.logLlmCall({
1470
+ component: 'helper',
1471
+ model: this._helperLlm.model ?? 'unknown',
1472
+ promptTokens: res.ok ? (res.value.usage?.promptTokens ?? 0) : 0,
1473
+ completionTokens: res.ok ? (res.value.usage?.completionTokens ?? 0) : 0,
1474
+ totalTokens: res.ok ? (res.value.usage?.totalTokens ?? 0) : 0,
1475
+ durationMs: Date.now() - summarizeStart,
1476
+ });
1477
+ if (!res.ok)
1478
+ return { ok: true, value: h };
1479
+ return {
1480
+ ok: true,
1481
+ value: [
1482
+ {
1483
+ role: 'system',
1484
+ content: `Summary of previous conversation: ${res.value.content}`,
1485
+ },
1486
+ ...rec,
1487
+ ],
1488
+ };
1489
+ }
1490
+ async *_runStructuredPipeline(textOrMessages, externalTools, opts, _parentSpan, _sessionId) {
1491
+ if (!this.deps.pipeline)
1492
+ return;
1493
+ const history = typeof textOrMessages === 'string' ? [] : textOrMessages;
1494
+ const chunkQueue = [];
1495
+ let resolveWait = null;
1496
+ let done = false;
1497
+ const executorPromise = this.deps.pipeline
1498
+ .execute(textOrMessages, history, opts, (chunk) => {
1499
+ chunkQueue.push(chunk);
1500
+ if (resolveWait) {
1501
+ resolveWait();
1502
+ resolveWait = null;
1503
+ }
1504
+ }, externalTools)
1505
+ .then(() => {
1506
+ done = true;
1507
+ if (resolveWait) {
1508
+ resolveWait();
1509
+ resolveWait = null;
1510
+ }
1511
+ })
1512
+ .catch((err) => {
1513
+ chunkQueue.push({
1514
+ ok: false,
1515
+ error: new OrchestratorError(String(err), 'PIPELINE_ERROR'),
1516
+ });
1517
+ done = true;
1518
+ if (resolveWait) {
1519
+ resolveWait();
1520
+ resolveWait = null;
1521
+ }
1522
+ });
1523
+ while (!done || chunkQueue.length > 0) {
1524
+ if (chunkQueue.length > 0) {
1525
+ const chunk = chunkQueue.shift();
1526
+ if (chunk !== undefined)
1527
+ yield chunk;
1528
+ }
1529
+ else if (!done) {
1530
+ await new Promise((r) => {
1531
+ resolveWait = r;
1532
+ });
1533
+ }
1534
+ }
1535
+ await executorPromise;
1536
+ }
1537
+ }
1538
+ //# sourceMappingURL=agent.js.map