@dexto/core 1.2.6 → 1.4.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 (515) hide show
  1. package/README.md +55 -13
  2. package/dist/agent/DextoAgent.cjs +627 -228
  3. package/dist/agent/DextoAgent.d.ts +157 -34
  4. package/dist/agent/DextoAgent.d.ts.map +1 -1
  5. package/dist/agent/DextoAgent.js +625 -227
  6. package/dist/agent/agentCard.js +1 -1
  7. package/dist/agent/error-codes.cjs +1 -0
  8. package/dist/agent/error-codes.d.ts +2 -1
  9. package/dist/agent/error-codes.d.ts.map +1 -1
  10. package/dist/agent/error-codes.js +2 -1
  11. package/dist/agent/errors.cjs +13 -0
  12. package/dist/agent/errors.d.ts +4 -0
  13. package/dist/agent/errors.d.ts.map +1 -1
  14. package/dist/agent/errors.js +14 -1
  15. package/dist/agent/index.d.ts +1 -1
  16. package/dist/agent/index.d.ts.map +1 -1
  17. package/dist/agent/index.js +1 -1
  18. package/dist/agent/schemas.cjs +4 -1
  19. package/dist/agent/schemas.d.ts +92 -55
  20. package/dist/agent/schemas.d.ts.map +1 -1
  21. package/dist/agent/schemas.js +7 -3
  22. package/dist/agent/state-manager.cjs +5 -5
  23. package/dist/agent/state-manager.d.ts +4 -4
  24. package/dist/agent/state-manager.js +6 -6
  25. package/dist/agent/types.d.ts +24 -11
  26. package/dist/agent/types.d.ts.map +1 -1
  27. package/dist/approval/error-codes.js +1 -1
  28. package/dist/approval/errors.js +1 -1
  29. package/dist/approval/factory.js +1 -1
  30. package/dist/approval/index.js +1 -1
  31. package/dist/approval/manager.cjs +69 -3
  32. package/dist/approval/manager.d.ts +41 -3
  33. package/dist/approval/manager.d.ts.map +1 -1
  34. package/dist/approval/manager.js +70 -4
  35. package/dist/approval/schemas.cjs +20 -5
  36. package/dist/approval/schemas.d.ts +127 -52
  37. package/dist/approval/schemas.d.ts.map +1 -1
  38. package/dist/approval/schemas.js +21 -6
  39. package/dist/approval/types.d.ts +6 -0
  40. package/dist/approval/types.d.ts.map +1 -1
  41. package/dist/approval/types.js +1 -1
  42. package/dist/{chunk-C6A6W6XS.js → chunk-PTJYTZNU.js} +44 -1
  43. package/dist/{llm/tokenizer/factory.cjs → context/compression/overflow.cjs} +20 -21
  44. package/dist/context/compression/overflow.d.ts +33 -0
  45. package/dist/context/compression/overflow.d.ts.map +1 -0
  46. package/dist/context/compression/overflow.js +19 -0
  47. package/dist/context/compression/reactive-overflow.cjs +201 -0
  48. package/dist/context/compression/reactive-overflow.d.ts +81 -0
  49. package/dist/context/compression/reactive-overflow.d.ts.map +1 -0
  50. package/dist/context/compression/reactive-overflow.js +178 -0
  51. package/dist/context/compression/types.d.ts +9 -7
  52. package/dist/context/compression/types.d.ts.map +1 -1
  53. package/dist/context/error-codes.cjs +3 -0
  54. package/dist/context/error-codes.d.ts +4 -1
  55. package/dist/context/error-codes.d.ts.map +1 -1
  56. package/dist/context/error-codes.js +4 -1
  57. package/dist/context/errors.cjs +28 -0
  58. package/dist/context/errors.d.ts +7 -0
  59. package/dist/context/errors.d.ts.map +1 -1
  60. package/dist/context/errors.js +29 -1
  61. package/dist/context/index.js +1 -1
  62. package/dist/context/manager.cjs +287 -323
  63. package/dist/context/manager.d.ts +65 -111
  64. package/dist/context/manager.d.ts.map +1 -1
  65. package/dist/context/manager.js +287 -328
  66. package/dist/context/media-helpers.js +1 -1
  67. package/dist/context/types.cjs +49 -0
  68. package/dist/context/types.d.ts +185 -72
  69. package/dist/context/types.d.ts.map +1 -1
  70. package/dist/context/types.js +35 -0
  71. package/dist/context/utils.cjs +266 -283
  72. package/dist/context/utils.d.ts +32 -18
  73. package/dist/context/utils.d.ts.map +1 -1
  74. package/dist/context/utils.js +266 -283
  75. package/dist/errors/DextoBaseError.js +1 -1
  76. package/dist/errors/DextoRuntimeError.js +1 -1
  77. package/dist/errors/DextoValidationError.js +1 -1
  78. package/dist/errors/index.js +1 -1
  79. package/dist/errors/result-bridge.js +1 -1
  80. package/dist/errors/types.cjs +1 -0
  81. package/dist/errors/types.d.ts +4 -2
  82. package/dist/errors/types.d.ts.map +1 -1
  83. package/dist/errors/types.js +2 -1
  84. package/dist/events/index.cjs +22 -2
  85. package/dist/events/index.d.ts +170 -62
  86. package/dist/events/index.d.ts.map +1 -1
  87. package/dist/events/index.js +23 -3
  88. package/dist/filesystem/error-codes.js +1 -1
  89. package/dist/filesystem/errors.js +1 -1
  90. package/dist/filesystem/filesystem-service.js +1 -1
  91. package/dist/filesystem/index.js +1 -1
  92. package/dist/filesystem/path-validator.js +1 -1
  93. package/dist/index.browser.cjs +23 -8
  94. package/dist/index.browser.d.ts +4 -3
  95. package/dist/index.browser.d.ts.map +1 -1
  96. package/dist/index.browser.js +20 -3
  97. package/dist/index.js +1 -1
  98. package/dist/llm/error-codes.cjs +0 -1
  99. package/dist/llm/error-codes.d.ts +0 -1
  100. package/dist/llm/error-codes.d.ts.map +1 -1
  101. package/dist/llm/error-codes.js +1 -2
  102. package/dist/llm/errors.cjs +10 -10
  103. package/dist/llm/errors.d.ts +5 -6
  104. package/dist/llm/errors.d.ts.map +1 -1
  105. package/dist/llm/errors.js +12 -12
  106. package/dist/llm/executor/stream-processor.cjs +367 -0
  107. package/dist/llm/executor/stream-processor.d.ts +55 -0
  108. package/dist/llm/executor/stream-processor.d.ts.map +1 -0
  109. package/dist/llm/executor/stream-processor.js +344 -0
  110. package/dist/llm/executor/tool-output-truncator.cjs +75 -0
  111. package/dist/llm/executor/tool-output-truncator.d.ts +27 -0
  112. package/dist/llm/executor/tool-output-truncator.d.ts.map +1 -0
  113. package/dist/llm/executor/tool-output-truncator.js +48 -0
  114. package/dist/llm/executor/turn-executor.cjs +753 -0
  115. package/dist/llm/executor/turn-executor.d.ts +166 -0
  116. package/dist/llm/executor/turn-executor.d.ts.map +1 -0
  117. package/dist/llm/executor/turn-executor.js +684 -0
  118. package/dist/llm/executor/types.d.ts +27 -0
  119. package/dist/llm/executor/types.d.ts.map +1 -0
  120. package/dist/llm/formatters/vercel.cjs +20 -186
  121. package/dist/llm/formatters/vercel.d.ts +2 -14
  122. package/dist/llm/formatters/vercel.d.ts.map +1 -1
  123. package/dist/llm/formatters/vercel.js +19 -185
  124. package/dist/llm/registry.cjs +36 -45
  125. package/dist/llm/registry.d.ts +53 -39
  126. package/dist/llm/registry.d.ts.map +1 -1
  127. package/dist/llm/registry.js +34 -42
  128. package/dist/llm/resolver.cjs +1 -31
  129. package/dist/llm/resolver.d.ts.map +1 -1
  130. package/dist/llm/resolver.js +2 -34
  131. package/dist/llm/schemas.cjs +2 -17
  132. package/dist/llm/schemas.d.ts +10 -23
  133. package/dist/llm/schemas.d.ts.map +1 -1
  134. package/dist/llm/schemas.js +5 -22
  135. package/dist/llm/services/factory.cjs +3 -92
  136. package/dist/llm/services/factory.d.ts +14 -4
  137. package/dist/llm/services/factory.d.ts.map +1 -1
  138. package/dist/llm/services/factory.js +4 -83
  139. package/dist/llm/services/test-utils.integration.cjs +6 -8
  140. package/dist/llm/services/test-utils.integration.d.ts.map +1 -1
  141. package/dist/llm/services/test-utils.integration.js +7 -9
  142. package/dist/llm/services/types.d.ts +1 -28
  143. package/dist/llm/services/types.d.ts.map +1 -1
  144. package/dist/llm/services/vercel.cjs +54 -468
  145. package/dist/llm/services/vercel.d.ts +38 -21
  146. package/dist/llm/services/vercel.d.ts.map +1 -1
  147. package/dist/llm/services/vercel.js +56 -475
  148. package/dist/llm/types.cjs +0 -3
  149. package/dist/llm/types.d.ts +8 -8
  150. package/dist/llm/types.d.ts.map +1 -1
  151. package/dist/llm/types.js +1 -3
  152. package/dist/llm/validation.js +1 -1
  153. package/dist/logger/browser.js +1 -1
  154. package/dist/logger/factory.js +1 -1
  155. package/dist/logger/index.js +1 -1
  156. package/dist/logger/logger.js +1 -1
  157. package/dist/logger/v2/dexto-logger.cjs +34 -6
  158. package/dist/logger/v2/dexto-logger.d.ts +20 -2
  159. package/dist/logger/v2/dexto-logger.d.ts.map +1 -1
  160. package/dist/logger/v2/dexto-logger.js +35 -7
  161. package/dist/logger/v2/error-codes.js +1 -1
  162. package/dist/logger/v2/errors.js +1 -1
  163. package/dist/logger/v2/schemas.cjs +1 -1
  164. package/dist/logger/v2/schemas.js +2 -2
  165. package/dist/logger/v2/test-utils.cjs +70 -0
  166. package/dist/logger/v2/test-utils.d.ts +17 -0
  167. package/dist/logger/v2/test-utils.d.ts.map +1 -0
  168. package/dist/logger/v2/test-utils.js +46 -0
  169. package/dist/logger/v2/transport-factory.js +1 -1
  170. package/dist/logger/v2/transports/console-transport.js +1 -1
  171. package/dist/logger/v2/transports/file-transport.cjs +6 -0
  172. package/dist/logger/v2/transports/file-transport.d.ts +4 -0
  173. package/dist/logger/v2/transports/file-transport.d.ts.map +1 -1
  174. package/dist/logger/v2/transports/file-transport.js +7 -1
  175. package/dist/logger/v2/types.cjs +1 -0
  176. package/dist/logger/v2/types.d.ts +18 -2
  177. package/dist/logger/v2/types.d.ts.map +1 -1
  178. package/dist/logger/v2/types.js +2 -1
  179. package/dist/mcp/error-codes.cjs +1 -0
  180. package/dist/mcp/error-codes.d.ts +1 -0
  181. package/dist/mcp/error-codes.d.ts.map +1 -1
  182. package/dist/mcp/error-codes.js +2 -1
  183. package/dist/mcp/errors.cjs +13 -0
  184. package/dist/mcp/errors.d.ts +7 -0
  185. package/dist/mcp/errors.d.ts.map +1 -1
  186. package/dist/mcp/errors.js +14 -1
  187. package/dist/mcp/manager.cjs +4 -0
  188. package/dist/mcp/manager.d.ts.map +1 -1
  189. package/dist/mcp/manager.js +5 -1
  190. package/dist/mcp/mcp-client.js +1 -1
  191. package/dist/mcp/resolver.js +1 -1
  192. package/dist/mcp/schemas.cjs +6 -0
  193. package/dist/mcp/schemas.d.ts +52 -0
  194. package/dist/mcp/schemas.d.ts.map +1 -1
  195. package/dist/mcp/schemas.js +6 -1
  196. package/dist/memory/error-codes.js +1 -1
  197. package/dist/memory/errors.js +1 -1
  198. package/dist/memory/index.js +1 -1
  199. package/dist/memory/manager.js +1 -1
  200. package/dist/memory/schemas.d.ts +2 -2
  201. package/dist/memory/schemas.js +1 -1
  202. package/dist/plugins/builtins/content-policy.js +1 -1
  203. package/dist/plugins/builtins/response-sanitizer.js +1 -1
  204. package/dist/plugins/error-codes.cjs +1 -0
  205. package/dist/plugins/error-codes.d.ts +3 -1
  206. package/dist/plugins/error-codes.d.ts.map +1 -1
  207. package/dist/plugins/error-codes.js +2 -1
  208. package/dist/plugins/index.js +1 -1
  209. package/dist/plugins/loader.cjs +25 -5
  210. package/dist/plugins/loader.d.ts.map +1 -1
  211. package/dist/plugins/loader.js +26 -6
  212. package/dist/plugins/manager.js +1 -1
  213. package/dist/plugins/registrations/builtins.js +1 -1
  214. package/dist/plugins/schemas.d.ts +3 -3
  215. package/dist/plugins/schemas.js +1 -1
  216. package/dist/plugins/types.d.ts +0 -1
  217. package/dist/plugins/types.d.ts.map +1 -1
  218. package/dist/process/command-validator.js +1 -1
  219. package/dist/process/error-codes.js +1 -1
  220. package/dist/process/errors.js +1 -1
  221. package/dist/process/index.js +1 -1
  222. package/dist/process/process-service.cjs +78 -26
  223. package/dist/process/process-service.d.ts +6 -1
  224. package/dist/process/process-service.d.ts.map +1 -1
  225. package/dist/process/process-service.js +79 -27
  226. package/dist/process/types.d.ts +2 -2
  227. package/dist/process/types.d.ts.map +1 -1
  228. package/dist/prompts/error-codes.cjs +1 -0
  229. package/dist/prompts/error-codes.d.ts +2 -1
  230. package/dist/prompts/error-codes.d.ts.map +1 -1
  231. package/dist/prompts/error-codes.js +2 -1
  232. package/dist/prompts/errors.cjs +15 -0
  233. package/dist/prompts/errors.d.ts +4 -0
  234. package/dist/prompts/errors.d.ts.map +1 -1
  235. package/dist/prompts/errors.js +16 -1
  236. package/dist/prompts/index.js +1 -1
  237. package/dist/prompts/name-validation.js +1 -1
  238. package/dist/prompts/prompt-manager.cjs +13 -2
  239. package/dist/prompts/prompt-manager.d.ts +7 -0
  240. package/dist/prompts/prompt-manager.d.ts.map +1 -1
  241. package/dist/prompts/prompt-manager.js +14 -3
  242. package/dist/prompts/providers/config-prompt-provider.cjs +12 -3
  243. package/dist/prompts/providers/config-prompt-provider.d.ts +2 -1
  244. package/dist/prompts/providers/config-prompt-provider.d.ts.map +1 -1
  245. package/dist/prompts/providers/config-prompt-provider.js +13 -4
  246. package/dist/prompts/providers/custom-prompt-provider.cjs +2 -2
  247. package/dist/prompts/providers/custom-prompt-provider.d.ts +1 -1
  248. package/dist/prompts/providers/custom-prompt-provider.d.ts.map +1 -1
  249. package/dist/prompts/providers/custom-prompt-provider.js +3 -3
  250. package/dist/prompts/providers/mcp-prompt-provider.js +1 -1
  251. package/dist/prompts/schemas.d.ts +12 -0
  252. package/dist/prompts/schemas.d.ts.map +1 -1
  253. package/dist/prompts/schemas.js +1 -1
  254. package/dist/prompts/types.d.ts +2 -0
  255. package/dist/prompts/types.d.ts.map +1 -1
  256. package/dist/prompts/utils.js +1 -1
  257. package/dist/resources/error-codes.js +1 -1
  258. package/dist/resources/errors.js +1 -1
  259. package/dist/resources/handlers/blob-handler.js +1 -1
  260. package/dist/resources/handlers/factory.js +1 -1
  261. package/dist/resources/handlers/filesystem-handler.js +1 -1
  262. package/dist/resources/index.js +1 -1
  263. package/dist/resources/internal-provider.js +1 -1
  264. package/dist/resources/manager.js +1 -1
  265. package/dist/resources/reference-parser.js +1 -1
  266. package/dist/resources/schemas.js +1 -1
  267. package/dist/search/index.js +1 -1
  268. package/dist/search/search-service.js +1 -1
  269. package/dist/session/chat-session.cjs +149 -51
  270. package/dist/session/chat-session.d.ts +69 -29
  271. package/dist/session/chat-session.d.ts.map +1 -1
  272. package/dist/session/chat-session.js +150 -52
  273. package/dist/session/error-codes.js +1 -1
  274. package/dist/session/errors.js +1 -1
  275. package/dist/session/history/database.cjs +134 -21
  276. package/dist/session/history/database.d.ts +37 -8
  277. package/dist/session/history/database.d.ts.map +1 -1
  278. package/dist/session/history/database.js +135 -22
  279. package/dist/session/history/factory.js +1 -1
  280. package/dist/session/history/memory.cjs +18 -0
  281. package/dist/session/history/memory.d.ts +8 -0
  282. package/dist/session/history/memory.d.ts.map +1 -1
  283. package/dist/session/history/memory.js +19 -1
  284. package/dist/session/history/types.d.ts +13 -1
  285. package/dist/session/history/types.d.ts.map +1 -1
  286. package/dist/session/index.cjs +3 -0
  287. package/dist/session/index.d.ts +3 -0
  288. package/dist/session/index.d.ts.map +1 -1
  289. package/dist/session/index.js +3 -1
  290. package/dist/session/message-queue.cjs +201 -0
  291. package/dist/session/message-queue.d.ts +114 -0
  292. package/dist/session/message-queue.d.ts.map +1 -0
  293. package/dist/session/message-queue.js +178 -0
  294. package/dist/session/schemas.js +1 -1
  295. package/dist/session/session-manager.cjs +57 -7
  296. package/dist/session/session-manager.d.ts +18 -0
  297. package/dist/session/session-manager.d.ts.map +1 -1
  298. package/dist/session/session-manager.js +58 -8
  299. package/dist/session/title-generator.cjs +4 -8
  300. package/dist/session/title-generator.d.ts +1 -2
  301. package/dist/session/title-generator.d.ts.map +1 -1
  302. package/dist/session/title-generator.js +5 -9
  303. package/dist/session/types.cjs +16 -0
  304. package/dist/session/types.d.ts +14 -0
  305. package/dist/session/types.d.ts.map +1 -0
  306. package/dist/session/types.js +0 -0
  307. package/dist/storage/blob/factory.js +1 -1
  308. package/dist/storage/blob/local-blob-store.js +1 -1
  309. package/dist/storage/blob/memory-blob-store.js +1 -1
  310. package/dist/storage/blob/schemas.js +1 -1
  311. package/dist/storage/cache/factory.cjs +6 -2
  312. package/dist/storage/cache/factory.d.ts +2 -1
  313. package/dist/storage/cache/factory.d.ts.map +1 -1
  314. package/dist/storage/cache/factory.js +7 -3
  315. package/dist/storage/cache/memory-cache-store.js +1 -1
  316. package/dist/storage/cache/redis-store.js +1 -1
  317. package/dist/storage/cache/schemas.js +1 -1
  318. package/dist/storage/database/factory.cjs +11 -17
  319. package/dist/storage/database/factory.d.ts +2 -1
  320. package/dist/storage/database/factory.d.ts.map +1 -1
  321. package/dist/storage/database/factory.js +12 -18
  322. package/dist/storage/database/memory-database-store.js +1 -1
  323. package/dist/storage/database/postgres-store.cjs +12 -0
  324. package/dist/storage/database/postgres-store.d.ts.map +1 -1
  325. package/dist/storage/database/postgres-store.js +13 -1
  326. package/dist/storage/database/schemas.js +1 -1
  327. package/dist/storage/database/sqlite-store.cjs +8 -0
  328. package/dist/storage/database/sqlite-store.d.ts.map +1 -1
  329. package/dist/storage/database/sqlite-store.js +9 -1
  330. package/dist/storage/error-codes.cjs +1 -0
  331. package/dist/storage/error-codes.d.ts +1 -0
  332. package/dist/storage/error-codes.d.ts.map +1 -1
  333. package/dist/storage/error-codes.js +2 -1
  334. package/dist/storage/errors.cjs +17 -0
  335. package/dist/storage/errors.d.ts +9 -0
  336. package/dist/storage/errors.d.ts.map +1 -1
  337. package/dist/storage/errors.js +18 -1
  338. package/dist/storage/index.js +1 -1
  339. package/dist/storage/schemas.js +1 -1
  340. package/dist/storage/storage-manager.js +1 -1
  341. package/dist/systemPrompt/contributors.js +1 -1
  342. package/dist/systemPrompt/error-codes.js +1 -1
  343. package/dist/systemPrompt/errors.js +1 -1
  344. package/dist/systemPrompt/in-built-prompts.js +1 -1
  345. package/dist/systemPrompt/index.js +1 -1
  346. package/dist/systemPrompt/manager.js +1 -1
  347. package/dist/systemPrompt/registry.js +1 -1
  348. package/dist/systemPrompt/schemas.d.ts +5 -5
  349. package/dist/systemPrompt/schemas.js +1 -1
  350. package/dist/telemetry/decorators.js +1 -1
  351. package/dist/{llm/tokenizer/default.cjs → telemetry/error-codes.cjs} +14 -19
  352. package/dist/telemetry/error-codes.d.ts +13 -0
  353. package/dist/telemetry/error-codes.d.ts.map +1 -0
  354. package/dist/telemetry/error-codes.js +13 -0
  355. package/dist/telemetry/errors.cjs +105 -0
  356. package/dist/telemetry/errors.d.ts +28 -0
  357. package/dist/telemetry/errors.d.ts.map +1 -0
  358. package/dist/telemetry/errors.js +82 -0
  359. package/dist/telemetry/exporters.js +1 -1
  360. package/dist/telemetry/index.js +1 -1
  361. package/dist/telemetry/schemas.js +1 -1
  362. package/dist/telemetry/telemetry.cjs +92 -26
  363. package/dist/telemetry/telemetry.d.ts +1 -1
  364. package/dist/telemetry/telemetry.d.ts.map +1 -1
  365. package/dist/telemetry/telemetry.js +75 -19
  366. package/dist/telemetry/utils.js +1 -1
  367. package/dist/tools/bash-pattern-utils.cjs +91 -0
  368. package/dist/tools/bash-pattern-utils.d.ts +58 -0
  369. package/dist/tools/bash-pattern-utils.d.ts.map +1 -0
  370. package/dist/tools/bash-pattern-utils.js +64 -0
  371. package/dist/tools/confirmation/allowed-tools-provider/factory.js +1 -1
  372. package/dist/tools/confirmation/allowed-tools-provider/in-memory.js +1 -1
  373. package/dist/tools/confirmation/allowed-tools-provider/storage.js +1 -1
  374. package/dist/tools/display-types.cjs +60 -0
  375. package/dist/tools/display-types.d.ts +133 -0
  376. package/dist/tools/display-types.d.ts.map +1 -0
  377. package/dist/tools/display-types.js +32 -0
  378. package/dist/tools/error-codes.cjs +2 -0
  379. package/dist/tools/error-codes.d.ts +3 -1
  380. package/dist/tools/error-codes.d.ts.map +1 -1
  381. package/dist/tools/error-codes.js +3 -1
  382. package/dist/tools/errors.cjs +30 -0
  383. package/dist/tools/errors.d.ts +16 -0
  384. package/dist/tools/errors.d.ts.map +1 -1
  385. package/dist/tools/errors.js +31 -1
  386. package/dist/tools/index.cjs +2 -0
  387. package/dist/tools/index.d.ts +1 -0
  388. package/dist/tools/index.d.ts.map +1 -1
  389. package/dist/tools/index.js +2 -1
  390. package/dist/tools/internal-tools/constants.js +1 -1
  391. package/dist/tools/internal-tools/implementations/ask-user-tool.cjs +1 -1
  392. package/dist/tools/internal-tools/implementations/ask-user-tool.js +2 -2
  393. package/dist/tools/internal-tools/implementations/bash-exec-tool.cjs +42 -18
  394. package/dist/tools/internal-tools/implementations/bash-exec-tool.d.ts +3 -3
  395. package/dist/tools/internal-tools/implementations/bash-exec-tool.d.ts.map +1 -1
  396. package/dist/tools/internal-tools/implementations/bash-exec-tool.js +43 -19
  397. package/dist/tools/internal-tools/implementations/bash-output-tool.js +1 -1
  398. package/dist/tools/internal-tools/implementations/delegate-to-url-tool.js +1 -1
  399. package/dist/tools/internal-tools/implementations/edit-file-tool.cjs +66 -1
  400. package/dist/tools/internal-tools/implementations/edit-file-tool.d.ts.map +1 -1
  401. package/dist/tools/internal-tools/implementations/edit-file-tool.js +67 -2
  402. package/dist/tools/internal-tools/implementations/glob-files-tool.cjs +14 -1
  403. package/dist/tools/internal-tools/implementations/glob-files-tool.d.ts.map +1 -1
  404. package/dist/tools/internal-tools/implementations/glob-files-tool.js +15 -2
  405. package/dist/tools/internal-tools/implementations/grep-content-tool.cjs +16 -1
  406. package/dist/tools/internal-tools/implementations/grep-content-tool.d.ts.map +1 -1
  407. package/dist/tools/internal-tools/implementations/grep-content-tool.js +17 -2
  408. package/dist/tools/internal-tools/implementations/kill-process-tool.js +1 -1
  409. package/dist/tools/internal-tools/implementations/read-file-tool.cjs +9 -1
  410. package/dist/tools/internal-tools/implementations/read-file-tool.d.ts.map +1 -1
  411. package/dist/tools/internal-tools/implementations/read-file-tool.js +10 -2
  412. package/dist/tools/internal-tools/implementations/search-history-tool.js +1 -1
  413. package/dist/tools/internal-tools/implementations/write-file-tool.cjs +69 -1
  414. package/dist/tools/internal-tools/implementations/write-file-tool.d.ts.map +1 -1
  415. package/dist/tools/internal-tools/implementations/write-file-tool.js +72 -2
  416. package/dist/tools/internal-tools/provider.cjs +27 -10
  417. package/dist/tools/internal-tools/provider.d.ts +8 -5
  418. package/dist/tools/internal-tools/provider.d.ts.map +1 -1
  419. package/dist/tools/internal-tools/provider.js +28 -11
  420. package/dist/tools/internal-tools/registry.cjs +4 -3
  421. package/dist/tools/internal-tools/registry.d.ts +28 -7
  422. package/dist/tools/internal-tools/registry.d.ts.map +1 -1
  423. package/dist/tools/internal-tools/registry.js +5 -4
  424. package/dist/tools/schemas.cjs +17 -7
  425. package/dist/tools/schemas.d.ts +31 -4
  426. package/dist/tools/schemas.d.ts.map +1 -1
  427. package/dist/tools/schemas.js +15 -7
  428. package/dist/tools/tool-manager.cjs +140 -18
  429. package/dist/tools/tool-manager.d.ts +23 -1
  430. package/dist/tools/tool-manager.d.ts.map +1 -1
  431. package/dist/tools/tool-manager.js +145 -19
  432. package/dist/tools/types.d.ts +20 -11
  433. package/dist/tools/types.d.ts.map +1 -1
  434. package/dist/utils/api-key-resolver.js +1 -1
  435. package/dist/utils/async-context.js +1 -1
  436. package/dist/utils/debug.js +1 -1
  437. package/dist/{llm/tokenizer/types.cjs → utils/defer.cjs} +19 -10
  438. package/dist/utils/defer.d.ts +63 -0
  439. package/dist/utils/defer.d.ts.map +1 -0
  440. package/dist/utils/defer.js +19 -0
  441. package/dist/utils/env-file.js +1 -1
  442. package/dist/utils/error-conversion.js +1 -1
  443. package/dist/utils/execution-context.js +1 -1
  444. package/dist/utils/fs-walk.js +1 -1
  445. package/dist/utils/index.cjs +3 -1
  446. package/dist/utils/index.d.ts +1 -0
  447. package/dist/utils/index.d.ts.map +1 -1
  448. package/dist/utils/index.js +1 -0
  449. package/dist/utils/path.js +1 -1
  450. package/dist/utils/redactor.js +1 -1
  451. package/dist/utils/result.js +1 -1
  452. package/dist/utils/safe-stringify.js +1 -1
  453. package/dist/utils/schema-metadata.js +1 -1
  454. package/dist/utils/schema.d.ts +6 -0
  455. package/dist/utils/schema.d.ts.map +1 -1
  456. package/dist/utils/schema.js +1 -1
  457. package/dist/utils/service-initializer.cjs +6 -2
  458. package/dist/utils/service-initializer.d.ts.map +1 -1
  459. package/dist/utils/service-initializer.js +7 -3
  460. package/dist/utils/user-info.js +1 -1
  461. package/dist/utils/zod-schema-converter.js +1 -1
  462. package/package.json +54 -17
  463. package/dist/context/compression/middle-removal.cjs +0 -95
  464. package/dist/context/compression/middle-removal.d.ts +0 -47
  465. package/dist/context/compression/middle-removal.d.ts.map +0 -1
  466. package/dist/context/compression/middle-removal.js +0 -72
  467. package/dist/context/compression/oldest-removal.cjs +0 -83
  468. package/dist/context/compression/oldest-removal.d.ts +0 -42
  469. package/dist/context/compression/oldest-removal.d.ts.map +0 -1
  470. package/dist/context/compression/oldest-removal.js +0 -60
  471. package/dist/llm/formatters/anthropic.cjs +0 -257
  472. package/dist/llm/formatters/anthropic.d.ts +0 -46
  473. package/dist/llm/formatters/anthropic.d.ts.map +0 -1
  474. package/dist/llm/formatters/anthropic.js +0 -239
  475. package/dist/llm/formatters/factory.cjs +0 -50
  476. package/dist/llm/formatters/factory.d.ts +0 -10
  477. package/dist/llm/formatters/factory.d.ts.map +0 -1
  478. package/dist/llm/formatters/factory.js +0 -27
  479. package/dist/llm/formatters/openai.cjs +0 -196
  480. package/dist/llm/formatters/openai.d.ts +0 -39
  481. package/dist/llm/formatters/openai.d.ts.map +0 -1
  482. package/dist/llm/formatters/openai.js +0 -177
  483. package/dist/llm/formatters/types.d.ts +0 -41
  484. package/dist/llm/formatters/types.d.ts.map +0 -1
  485. package/dist/llm/services/anthropic.cjs +0 -511
  486. package/dist/llm/services/anthropic.d.ts +0 -48
  487. package/dist/llm/services/anthropic.d.ts.map +0 -1
  488. package/dist/llm/services/anthropic.js +0 -447
  489. package/dist/llm/services/openai.cjs +0 -611
  490. package/dist/llm/services/openai.d.ts +0 -48
  491. package/dist/llm/services/openai.d.ts.map +0 -1
  492. package/dist/llm/services/openai.js +0 -547
  493. package/dist/llm/tokenizer/anthropic.cjs +0 -43
  494. package/dist/llm/tokenizer/anthropic.d.ts +0 -19
  495. package/dist/llm/tokenizer/anthropic.d.ts.map +0 -1
  496. package/dist/llm/tokenizer/anthropic.js +0 -20
  497. package/dist/llm/tokenizer/default.d.ts +0 -14
  498. package/dist/llm/tokenizer/default.d.ts.map +0 -1
  499. package/dist/llm/tokenizer/default.js +0 -18
  500. package/dist/llm/tokenizer/factory.d.ts +0 -12
  501. package/dist/llm/tokenizer/factory.d.ts.map +0 -1
  502. package/dist/llm/tokenizer/factory.js +0 -21
  503. package/dist/llm/tokenizer/google.cjs +0 -52
  504. package/dist/llm/tokenizer/google.d.ts +0 -29
  505. package/dist/llm/tokenizer/google.d.ts.map +0 -1
  506. package/dist/llm/tokenizer/google.js +0 -29
  507. package/dist/llm/tokenizer/openai.cjs +0 -115
  508. package/dist/llm/tokenizer/openai.d.ts +0 -33
  509. package/dist/llm/tokenizer/openai.d.ts.map +0 -1
  510. package/dist/llm/tokenizer/openai.js +0 -91
  511. package/dist/llm/tokenizer/types.d.ts +0 -18
  512. package/dist/llm/tokenizer/types.d.ts.map +0 -1
  513. package/dist/llm/tokenizer/types.js +0 -10
  514. /package/dist/llm/{formatters → executor}/types.cjs +0 -0
  515. /package/dist/llm/{formatters → executor}/types.js +0 -0
@@ -2,8 +2,10 @@ import {
2
2
  __decorateElement,
3
3
  __decoratorStart,
4
4
  __runInitializers
5
- } from "../chunk-C6A6W6XS.js";
5
+ } from "../chunk-PTJYTZNU.js";
6
6
  var _DextoAgent_decorators, _init;
7
+ import { randomUUID } from "crypto";
8
+ import { setMaxListeners } from "events";
7
9
  import { expandMessageReferences } from "../resources/index.js";
8
10
  import { expandBlobReferences } from "../context/utils.js";
9
11
  import { PromptManager } from "../prompts/index.js";
@@ -19,6 +21,7 @@ import { LLMError } from "../llm/errors.js";
19
21
  import { AgentError } from "./errors.js";
20
22
  import { MCPError } from "../mcp/errors.js";
21
23
  import { DextoRuntimeError } from "../errors/DextoRuntimeError.js";
24
+ import { DextoValidationError } from "../errors/DextoValidationError.js";
22
25
  import { ensureOk } from "../errors/result-bridge.js";
23
26
  import { fail, zodToIssues } from "../utils/result.js";
24
27
  import { resolveAndValidateMcpServerConfig } from "../mcp/resolver.js";
@@ -31,8 +34,7 @@ import {
31
34
  import { createAgentServices } from "../utils/service-initializer.js";
32
35
  import { AgentConfigSchema } from "./schemas.js";
33
36
  import {
34
- AgentEventBus,
35
- STREAMING_EVENTS
37
+ AgentEventBus
36
38
  } from "../events/index.js";
37
39
  import { safeStringify } from "../utils/safe-stringify.js";
38
40
  import { deriveHeuristicTitle, generateSessionTitle } from "../session/title-generator.js";
@@ -104,6 +106,8 @@ class DextoAgent {
104
106
  // Approval handler for manual tool confirmation and elicitation
105
107
  // Set via setApprovalHandler() before start() if needed
106
108
  approvalHandler;
109
+ // Active stream controllers per session - allows cancel() to abort iterators
110
+ activeStreamControllers = /* @__PURE__ */ new Map();
107
111
  // Logger instance for this agent (dependency injection)
108
112
  logger;
109
113
  /**
@@ -179,10 +183,6 @@ Either:
179
183
  for (const subscriber of this.eventSubscribers) {
180
184
  subscriber.subscribe(this.agentEventBus);
181
185
  }
182
- const fileTransport = this.config.logger?.transports?.find((t) => t.type === "file");
183
- if (fileTransport && "path" in fileTransport) {
184
- console.log(`\u{1F4CB} Logs available at: ${fileTransport.path}`);
185
- }
186
186
  } catch (error) {
187
187
  this.logger.error("Failed to start DextoAgent", {
188
188
  error: error instanceof Error ? error.message : String(error)
@@ -313,173 +313,88 @@ Either:
313
313
  }
314
314
  // ============= CORE AGENT FUNCTIONALITY =============
315
315
  /**
316
- * Main method for processing user input.
317
- * Processes user input through the agent's LLM service and returns the response.
316
+ * Process user input and return the response.
317
+ *
318
+ * @deprecated Use generate() or stream() instead for multi-image support.
319
+ * This method is kept for backward compatibility and only supports single image/file.
318
320
  *
319
- * @param textInput - The user's text message or query to process
320
- * @param imageDataInput - Optional image data and MIME type for multimodal input
321
- * @param fileDataInput - Optional file data and MIME type for file input
321
+ * @param textInput - The user's text message
322
+ * @param imageDataInput - Optional single image data
323
+ * @param fileDataInput - Optional single file data
322
324
  * @param sessionId - Session ID for the conversation (required)
323
- * @param stream - Whether to stream the response (default: false)
324
- * @returns Promise that resolves to the AI's response text, or null if no significant response
325
- * @throws Error if processing fails
325
+ * @param _stream - Ignored (streaming is handled internally)
326
+ * @returns Promise that resolves to the AI's response text
326
327
  */
327
- async run(textInput, imageDataInput, fileDataInput, sessionId, stream = false) {
328
- this.ensureStarted();
329
- if (!sessionId || typeof sessionId !== "string") {
330
- throw new Error("sessionId is required and must be a non-empty string");
328
+ async run(textInput, imageDataInput, fileDataInput, sessionId, _stream = false) {
329
+ const parts = [];
330
+ if (textInput) {
331
+ parts.push({ type: "text", text: textInput });
331
332
  }
332
- const targetSessionId = sessionId;
333
- const activeContext = context.active();
334
- const span = trace.getActiveSpan();
335
- if (span) {
336
- span.setAttribute("sessionId", targetSessionId);
333
+ if (imageDataInput) {
334
+ parts.push({
335
+ type: "image",
336
+ image: imageDataInput.image,
337
+ mimeType: imageDataInput.mimeType
338
+ });
337
339
  }
338
- const existingBaggage = propagation.getBaggage(activeContext);
339
- const baggageEntries = {};
340
- if (existingBaggage) {
341
- existingBaggage.getAllEntries().forEach(([key, entry]) => {
342
- baggageEntries[key] = { ...entry };
340
+ if (fileDataInput) {
341
+ parts.push({
342
+ type: "file",
343
+ data: fileDataInput.data,
344
+ mimeType: fileDataInput.mimeType,
345
+ ...fileDataInput.filename && { filename: fileDataInput.filename }
343
346
  });
344
347
  }
345
- baggageEntries.sessionId = { ...baggageEntries.sessionId, value: targetSessionId };
346
- const updatedContext = propagation.setBaggage(
347
- activeContext,
348
- propagation.createBaggage(baggageEntries)
349
- );
350
- const verifyBaggage = propagation.getBaggage(updatedContext);
351
- this.logger.debug(
352
- `Baggage after setting sessionId: ${JSON.stringify(
353
- Array.from(verifyBaggage?.getAllEntries() || [])
354
- )}`
355
- );
356
- return await context.with(updatedContext, async () => {
357
- try {
358
- const llmConfig = this.stateManager.getLLMConfig(targetSessionId);
359
- const validation = validateInputForLLM(
360
- {
361
- text: textInput,
362
- ...imageDataInput && { imageData: imageDataInput },
363
- ...fileDataInput && { fileData: fileDataInput }
364
- },
365
- {
366
- provider: llmConfig.provider,
367
- model: llmConfig.model
368
- },
369
- this.logger
370
- );
371
- ensureOk(validation, this.logger);
372
- const session = await this.sessionManager.getSession(targetSessionId) || await this.sessionManager.createSession(targetSessionId);
373
- this.logger.debug(
374
- `DextoAgent.run: sessionId=${targetSessionId}, textLength=${textInput?.length ?? 0}, hasImage=${Boolean(
375
- imageDataInput
376
- )}, hasFile=${Boolean(fileDataInput)}`
377
- );
378
- let finalText = textInput;
379
- let finalImageData = imageDataInput;
380
- if (textInput && textInput.includes("@")) {
381
- try {
382
- const resources = await this.resourceManager.list();
383
- const expansion = await expandMessageReferences(
384
- textInput,
385
- resources,
386
- (uri) => this.resourceManager.read(uri)
387
- );
388
- if (expansion.unresolvedReferences.length > 0) {
389
- const unresolvedNames = expansion.unresolvedReferences.map((ref) => ref.originalRef).join(", ");
390
- this.logger.warn(
391
- `Could not resolve ${expansion.unresolvedReferences.length} resource reference(s): ${unresolvedNames}`
392
- );
393
- }
394
- const MAX_EXPANDED_SIZE = 5 * 1024 * 1024;
395
- const expandedSize = Buffer.byteLength(expansion.expandedMessage, "utf-8");
396
- if (expandedSize > MAX_EXPANDED_SIZE) {
397
- this.logger.warn(
398
- `Expanded message size (${(expandedSize / 1024 / 1024).toFixed(2)}MB) exceeds limit (${MAX_EXPANDED_SIZE / 1024 / 1024}MB). Content may be truncated.`
399
- );
400
- }
401
- finalText = expansion.expandedMessage;
402
- if (expansion.extractedImages.length > 0 && !imageDataInput) {
403
- const firstImage = expansion.extractedImages[0];
404
- if (firstImage) {
405
- finalImageData = {
406
- image: firstImage.image,
407
- mimeType: firstImage.mimeType
408
- };
409
- this.logger.debug(
410
- `Using extracted image: ${firstImage.name} (${firstImage.mimeType})`
411
- );
412
- }
413
- }
414
- } catch (error) {
415
- this.logger.error(
416
- `Failed to expand resource references: ${error instanceof Error ? error.message : String(error)}. Continuing with original message.`
417
- );
418
- }
419
- }
420
- if (!finalText.trim() && !finalImageData && !fileDataInput) {
421
- this.logger.warn(
422
- "Resource expansion resulted in empty content. Using original message."
423
- );
424
- finalText = textInput;
425
- }
426
- const response = await session.run(
427
- finalText,
428
- finalImageData,
429
- fileDataInput,
430
- stream
431
- );
432
- this.sessionManager.incrementMessageCount(session.id).catch(
433
- (error) => this.logger.warn(
434
- `Failed to increment message count: ${error instanceof Error ? error.message : String(error)}`
435
- )
436
- );
437
- return response;
438
- } catch (error) {
439
- this.logger.error(
440
- `Error during DextoAgent.run: ${error instanceof Error ? error.message : JSON.stringify(error)}`
441
- );
442
- throw error;
443
- }
444
- });
348
+ const response = await this.generate(parts.length > 0 ? parts : textInput, sessionId);
349
+ return response.content;
445
350
  }
446
351
  /**
447
352
  * Generate a complete response (waits for full completion).
448
353
  * This is the recommended method for non-streaming use cases.
449
354
  *
450
- * @param message The user's message
451
- * @param options Configuration options (sessionId is required, imageData, fileData, signal are optional)
355
+ * @param content String message or array of content parts (text, images, files)
356
+ * @param sessionId Session ID for the conversation
357
+ * @param options Optional configuration (signal for cancellation)
452
358
  * @returns Promise that resolves to the complete response
453
359
  *
454
360
  * @example
455
361
  * ```typescript
456
- * const response = await agent.generate("What is 2+2?", { sessionId: "default" });
362
+ * // Simple text message
363
+ * const response = await agent.generate('What is 2+2?', 'session-1');
457
364
  * console.log(response.content); // "4"
458
- * console.log(response.usage.totalTokens); // 50
365
+ *
366
+ * // Multimodal with image
367
+ * const response = await agent.generate(
368
+ * [
369
+ * { type: 'text', text: 'Describe this image' },
370
+ * { type: 'image', image: base64Data, mimeType: 'image/png' }
371
+ * ],
372
+ * 'session-1'
373
+ * );
459
374
  * ```
460
375
  */
461
- async generate(message, options) {
376
+ async generate(content, sessionId, options) {
462
377
  const events = [];
463
- for await (const event of await this.stream(message, options)) {
378
+ for await (const event of await this.stream(content, sessionId, options)) {
464
379
  events.push(event);
465
380
  }
466
- const errorEvent = events.find(
467
- (e) => e.type === "llm:error"
381
+ const fatalErrorEvent = events.find(
382
+ (e) => e.name === "llm:error" && e.recoverable !== true
468
383
  );
469
- if (errorEvent) {
470
- if (errorEvent.error instanceof DextoRuntimeError) {
471
- throw errorEvent.error;
384
+ if (fatalErrorEvent) {
385
+ if (fatalErrorEvent.error instanceof DextoRuntimeError || fatalErrorEvent.error instanceof DextoValidationError) {
386
+ throw fatalErrorEvent.error;
472
387
  }
473
- const llmConfig = this.stateManager.getLLMConfig(options.sessionId);
388
+ const llmConfig = this.stateManager.getLLMConfig(sessionId);
474
389
  throw LLMError.generationFailed(
475
- errorEvent.error.message,
390
+ fatalErrorEvent.error.message,
476
391
  llmConfig.provider,
477
392
  llmConfig.model
478
393
  );
479
394
  }
480
- const responseEvent = events.find((e) => e.type === "llm:response");
481
- if (!responseEvent || responseEvent.type !== "llm:response") {
482
- const llmConfig = this.stateManager.getLLMConfig(options.sessionId);
395
+ const responseEvent = events.find((e) => e.name === "llm:response");
396
+ if (!responseEvent || responseEvent.name !== "llm:response") {
397
+ const llmConfig = this.stateManager.getLLMConfig(sessionId);
483
398
  throw LLMError.generationFailed(
484
399
  "Stream did not complete successfully - no response received",
485
400
  llmConfig.provider,
@@ -487,10 +402,10 @@ Either:
487
402
  );
488
403
  }
489
404
  const toolCallEvents = events.filter(
490
- (e) => e.type === "llm:tool-call"
405
+ (e) => e.name === "llm:tool-call"
491
406
  );
492
407
  const toolResultEvents = events.filter(
493
- (e) => e.type === "llm:tool-result"
408
+ (e) => e.name === "llm:tool-result"
494
409
  );
495
410
  const toolCalls = toolCallEvents.map((tc) => {
496
411
  const toolResult = toolResultEvents.find((tr) => tr.callId === tc.callId);
@@ -504,7 +419,6 @@ Either:
504
419
  } : void 0
505
420
  };
506
421
  });
507
- const messageId = `msg_${Date.now()}_${Math.random().toString(36).substring(7)}`;
508
422
  const defaultUsage = {
509
423
  inputTokens: 0,
510
424
  outputTokens: 0,
@@ -516,8 +430,7 @@ Either:
516
430
  reasoning: responseEvent.reasoning,
517
431
  usage,
518
432
  toolCalls,
519
- sessionId: options.sessionId,
520
- messageId
433
+ sessionId
521
434
  };
522
435
  }
523
436
  /**
@@ -531,45 +444,51 @@ Either:
531
444
  * Events are forwarded directly from the AgentEventBus with no mapping layer,
532
445
  * providing a unified event system across all API layers.
533
446
  *
534
- * @param message The user's message
535
- * @param options Configuration options (sessionId is required, imageData, fileData, signal are optional)
536
- * @returns AsyncIterator that yields StreamingEvent objects (core events with type property)
447
+ * @param content String message or array of content parts (text, images, files)
448
+ * @param sessionId Session ID for the conversation
449
+ * @param options Optional configuration (signal for cancellation)
450
+ * @returns AsyncIterator that yields StreamingEvent objects (core events with name property)
537
451
  *
538
452
  * @example
539
453
  * ```typescript
540
- * for await (const event of await agent.stream("Write a poem", { sessionId: "default" })) {
541
- * if (event.type === 'llm:chunk') {
542
- * process.stdout.write(event.content);
543
- * }
544
- * if (event.type === 'llm:tool-call') {
545
- * console.log(`\n[Using ${event.toolName}]\n`);
546
- * }
454
+ * // Simple text
455
+ * for await (const event of await agent.stream('Write a poem', 'session-1')) {
456
+ * if (event.name === 'llm:chunk') process.stdout.write(event.content);
547
457
  * }
458
+ *
459
+ * // Multimodal
460
+ * for await (const event of await agent.stream(
461
+ * [{ type: 'text', text: 'Describe this' }, { type: 'image', image: data, mimeType: 'image/png' }],
462
+ * 'session-1'
463
+ * )) { ... }
548
464
  * ```
549
465
  */
550
- async stream(message, options) {
466
+ async stream(content, sessionId, options) {
551
467
  this.ensureStarted();
552
- if (!options.sessionId) {
553
- throw new Error("sessionId is required in StreamOptions");
468
+ if (!sessionId) {
469
+ throw AgentError.apiValidationError("sessionId is required");
554
470
  }
555
- const sessionId = options.sessionId;
556
- const imageData = options.imageData;
557
- const fileData = options.fileData;
558
- const signal = options.signal;
471
+ const signal = options?.signal;
472
+ let contentParts = typeof content === "string" ? [{ type: "text", text: content }] : [...content];
559
473
  const eventQueue = [];
560
474
  let completed = false;
561
- let _streamError = null;
562
475
  const controller = new AbortController();
563
476
  const cleanupSignal = controller.signal;
477
+ this.activeStreamControllers.set(sessionId, controller);
478
+ setMaxListeners(30, cleanupSignal);
564
479
  const listeners = [];
565
480
  const cleanupListeners = () => {
566
481
  if (listeners.length === 0) {
567
482
  return;
568
483
  }
569
484
  for (const { event, listener } of listeners) {
570
- this.agentEventBus.off(event, listener);
485
+ this.agentEventBus.off(
486
+ event,
487
+ listener
488
+ );
571
489
  }
572
490
  listeners.length = 0;
491
+ this.activeStreamControllers.delete(sessionId);
573
492
  };
574
493
  if (signal) {
575
494
  const abortHandler = () => {
@@ -578,49 +497,262 @@ Either:
578
497
  };
579
498
  signal.addEventListener("abort", abortHandler, { once: true });
580
499
  }
581
- for (const eventName of STREAMING_EVENTS) {
582
- const listener = (data) => {
583
- if (data.sessionId !== void 0 && data.sessionId !== sessionId) {
584
- return;
585
- }
586
- eventQueue.push({ type: eventName, ...data });
587
- if (eventName === "llm:response" || eventName === "llm:error" && !data.recoverable) {
588
- completed = true;
589
- }
590
- };
591
- this.agentEventBus.on(eventName, listener, {
592
- signal: cleanupSignal
593
- });
594
- listeners.push({ event: eventName, listener });
595
- }
596
- const imageDataForRun = imageData ? {
597
- image: typeof imageData.image === "string" ? imageData.image : imageData.image.toString(),
598
- mimeType: imageData.mimeType || "image/png"
599
- } : void 0;
600
- const fileDataForRun = fileData ? {
601
- data: typeof fileData.data === "string" ? fileData.data : fileData.data.toString(),
602
- mimeType: fileData.mimeType,
603
- ...fileData.filename && { filename: fileData.filename }
604
- } : void 0;
605
- this.run(message, imageDataForRun, fileDataForRun, sessionId, true).catch((error) => {
606
- _streamError = error;
500
+ const thinkingListener = (data) => {
501
+ if (data.sessionId !== sessionId) return;
502
+ eventQueue.push({ name: "llm:thinking", ...data });
503
+ };
504
+ this.agentEventBus.on("llm:thinking", thinkingListener, { signal: cleanupSignal });
505
+ listeners.push({ event: "llm:thinking", listener: thinkingListener });
506
+ const chunkListener = (data) => {
507
+ if (data.sessionId !== sessionId) return;
508
+ eventQueue.push({ name: "llm:chunk", ...data });
509
+ };
510
+ this.agentEventBus.on("llm:chunk", chunkListener, { signal: cleanupSignal });
511
+ listeners.push({ event: "llm:chunk", listener: chunkListener });
512
+ const responseListener = (data) => {
513
+ if (data.sessionId !== sessionId) return;
514
+ eventQueue.push({ name: "llm:response", ...data });
515
+ };
516
+ this.agentEventBus.on("llm:response", responseListener, { signal: cleanupSignal });
517
+ listeners.push({ event: "llm:response", listener: responseListener });
518
+ const toolCallListener = (data) => {
519
+ if (data.sessionId !== sessionId) return;
520
+ eventQueue.push({ name: "llm:tool-call", ...data });
521
+ };
522
+ this.agentEventBus.on("llm:tool-call", toolCallListener, { signal: cleanupSignal });
523
+ listeners.push({ event: "llm:tool-call", listener: toolCallListener });
524
+ const toolResultListener = (data) => {
525
+ if (data.sessionId !== sessionId) return;
526
+ eventQueue.push({ name: "llm:tool-result", ...data });
527
+ };
528
+ this.agentEventBus.on("llm:tool-result", toolResultListener, { signal: cleanupSignal });
529
+ listeners.push({ event: "llm:tool-result", listener: toolResultListener });
530
+ const errorListener = (data) => {
531
+ if (data.sessionId !== sessionId) return;
532
+ eventQueue.push({ name: "llm:error", ...data });
533
+ if (!data.recoverable) {
534
+ completed = true;
535
+ }
536
+ };
537
+ this.agentEventBus.on("llm:error", errorListener, { signal: cleanupSignal });
538
+ listeners.push({ event: "llm:error", listener: errorListener });
539
+ const unsupportedInputListener = (data) => {
540
+ if (data.sessionId !== sessionId) return;
541
+ eventQueue.push({ name: "llm:unsupported-input", ...data });
542
+ };
543
+ this.agentEventBus.on("llm:unsupported-input", unsupportedInputListener, {
544
+ signal: cleanupSignal
545
+ });
546
+ listeners.push({ event: "llm:unsupported-input", listener: unsupportedInputListener });
547
+ const titleUpdatedListener = (data) => {
548
+ if (data.sessionId !== sessionId) return;
549
+ eventQueue.push({ name: "session:title-updated", ...data });
550
+ };
551
+ this.agentEventBus.on("session:title-updated", titleUpdatedListener, {
552
+ signal: cleanupSignal
553
+ });
554
+ listeners.push({ event: "session:title-updated", listener: titleUpdatedListener });
555
+ const approvalRequestListener = (data) => {
556
+ if (data.sessionId !== sessionId) return;
557
+ eventQueue.push({ name: "approval:request", ...data });
558
+ };
559
+ this.agentEventBus.on("approval:request", approvalRequestListener, {
560
+ signal: cleanupSignal
561
+ });
562
+ listeners.push({ event: "approval:request", listener: approvalRequestListener });
563
+ const approvalResponseListener = (data) => {
564
+ if (data.sessionId !== sessionId) return;
565
+ eventQueue.push({ name: "approval:response", ...data });
566
+ };
567
+ this.agentEventBus.on("approval:response", approvalResponseListener, {
568
+ signal: cleanupSignal
569
+ });
570
+ listeners.push({ event: "approval:response", listener: approvalResponseListener });
571
+ const toolRunningListener = (data) => {
572
+ if (data.sessionId !== sessionId) return;
573
+ eventQueue.push({ name: "tool:running", ...data });
574
+ };
575
+ this.agentEventBus.on("tool:running", toolRunningListener, {
576
+ signal: cleanupSignal
577
+ });
578
+ listeners.push({ event: "tool:running", listener: toolRunningListener });
579
+ const messageQueuedListener = (data) => {
580
+ if (data.sessionId !== sessionId) return;
581
+ eventQueue.push({ name: "message:queued", ...data });
582
+ };
583
+ this.agentEventBus.on("message:queued", messageQueuedListener, {
584
+ signal: cleanupSignal
585
+ });
586
+ listeners.push({ event: "message:queued", listener: messageQueuedListener });
587
+ const messageDequeuedListener = (data) => {
588
+ if (data.sessionId !== sessionId) return;
589
+ eventQueue.push({ name: "message:dequeued", ...data });
590
+ };
591
+ this.agentEventBus.on("message:dequeued", messageDequeuedListener, {
592
+ signal: cleanupSignal
593
+ });
594
+ listeners.push({ event: "message:dequeued", listener: messageDequeuedListener });
595
+ const runCompleteListener = (data) => {
596
+ if (data.sessionId !== sessionId) return;
597
+ eventQueue.push({ name: "run:complete", ...data });
607
598
  completed = true;
608
- this.logger.error(
609
- `Error in DextoAgent.stream: ${error instanceof Error ? error.message : String(error)}`
599
+ };
600
+ this.agentEventBus.on("run:complete", runCompleteListener, {
601
+ signal: cleanupSignal
602
+ });
603
+ listeners.push({ event: "run:complete", listener: runCompleteListener });
604
+ (async () => {
605
+ const activeContext = context.active();
606
+ const activeSpan = trace.getActiveSpan();
607
+ if (activeSpan) {
608
+ activeSpan.setAttribute("sessionId", sessionId);
609
+ }
610
+ const existingBaggage = propagation.getBaggage(activeContext);
611
+ const baggageEntries = {};
612
+ if (existingBaggage) {
613
+ existingBaggage.getAllEntries().forEach(([key, entry]) => {
614
+ baggageEntries[key] = { ...entry };
615
+ });
616
+ }
617
+ baggageEntries.sessionId = { ...baggageEntries.sessionId, value: sessionId };
618
+ const updatedContext = propagation.setBaggage(
619
+ activeContext,
620
+ propagation.createBaggage(baggageEntries)
610
621
  );
611
- eventQueue.push({
612
- type: "llm:error",
613
- error,
614
- recoverable: false,
615
- context: "run_failed",
616
- sessionId
622
+ await context.with(updatedContext, async () => {
623
+ try {
624
+ const llmConfig = this.stateManager.getLLMConfig(sessionId);
625
+ const textParts = contentParts.filter(
626
+ (p) => p.type === "text"
627
+ );
628
+ const textContent = textParts.map((p) => p.text).join("\n");
629
+ const imageParts = contentParts.filter(
630
+ (p) => p.type === "image"
631
+ );
632
+ const fileParts = contentParts.filter(
633
+ (p) => p.type === "file"
634
+ );
635
+ this.logger.debug(
636
+ `DextoAgent.stream: sessionId=${sessionId}, textLength=${textContent?.length ?? 0}, imageCount=${imageParts.length}, fileCount=${fileParts.length}`
637
+ );
638
+ const textValidation = validateInputForLLM(
639
+ { text: textContent },
640
+ { provider: llmConfig.provider, model: llmConfig.model },
641
+ this.logger
642
+ );
643
+ ensureOk(textValidation, this.logger);
644
+ for (const imagePart of imageParts) {
645
+ const imageValidation = validateInputForLLM(
646
+ {
647
+ imageData: {
648
+ image: typeof imagePart.image === "string" ? imagePart.image : imagePart.image.toString(),
649
+ mimeType: imagePart.mimeType || "image/png"
650
+ }
651
+ },
652
+ { provider: llmConfig.provider, model: llmConfig.model },
653
+ this.logger
654
+ );
655
+ ensureOk(imageValidation, this.logger);
656
+ }
657
+ for (const filePart of fileParts) {
658
+ const fileValidation = validateInputForLLM(
659
+ {
660
+ fileData: {
661
+ data: typeof filePart.data === "string" ? filePart.data : filePart.data.toString(),
662
+ mimeType: filePart.mimeType
663
+ }
664
+ },
665
+ { provider: llmConfig.provider, model: llmConfig.model },
666
+ this.logger
667
+ );
668
+ ensureOk(fileValidation, this.logger);
669
+ }
670
+ if (textContent.includes("@")) {
671
+ try {
672
+ const resources = await this.resourceManager.list();
673
+ const expansion = await expandMessageReferences(
674
+ textContent,
675
+ resources,
676
+ (uri) => this.resourceManager.read(uri)
677
+ );
678
+ if (expansion.unresolvedReferences.length > 0) {
679
+ const unresolvedNames = expansion.unresolvedReferences.map((ref) => ref.originalRef).join(", ");
680
+ this.logger.warn(
681
+ `Could not resolve ${expansion.unresolvedReferences.length} resource reference(s): ${unresolvedNames}`
682
+ );
683
+ }
684
+ const MAX_EXPANDED_SIZE = 5 * 1024 * 1024;
685
+ const expandedSize = Buffer.byteLength(
686
+ expansion.expandedMessage,
687
+ "utf-8"
688
+ );
689
+ if (expandedSize > MAX_EXPANDED_SIZE) {
690
+ this.logger.warn(
691
+ `Expanded message size (${(expandedSize / 1024 / 1024).toFixed(2)}MB) exceeds limit (${MAX_EXPANDED_SIZE / 1024 / 1024}MB). Content may be truncated.`
692
+ );
693
+ }
694
+ contentParts = contentParts.filter((p) => p.type !== "text");
695
+ if (expansion.expandedMessage.trim()) {
696
+ contentParts.unshift({
697
+ type: "text",
698
+ text: expansion.expandedMessage
699
+ });
700
+ }
701
+ for (const img of expansion.extractedImages) {
702
+ contentParts.push({
703
+ type: "image",
704
+ image: img.image,
705
+ mimeType: img.mimeType
706
+ });
707
+ this.logger.debug(
708
+ `Added extracted image: ${img.name} (${img.mimeType})`
709
+ );
710
+ }
711
+ } catch (error) {
712
+ this.logger.error(
713
+ `Failed to expand resource references: ${error instanceof Error ? error.message : String(error)}. Continuing with original message.`
714
+ );
715
+ }
716
+ }
717
+ const hasTextContent = contentParts.some(
718
+ (p) => p.type === "text" && p.text.trim()
719
+ );
720
+ const hasMediaContent = contentParts.some(
721
+ (p) => p.type === "image" || p.type === "file"
722
+ );
723
+ if (!hasTextContent && !hasMediaContent) {
724
+ this.logger.warn(
725
+ "Resource expansion resulted in empty content. Using original message."
726
+ );
727
+ contentParts = [{ type: "text", text: textContent }];
728
+ }
729
+ const session = await this.sessionManager.getSession(sessionId) || await this.sessionManager.createSession(sessionId);
730
+ await session.stream(contentParts, signal ? { signal } : void 0);
731
+ this.sessionManager.incrementMessageCount(session.id).catch(
732
+ (error) => this.logger.warn(
733
+ `Failed to increment message count: ${error instanceof Error ? error.message : String(error)}`
734
+ )
735
+ );
736
+ } catch (err) {
737
+ const error = err instanceof DextoRuntimeError || err instanceof DextoValidationError ? err : err instanceof Error ? err : AgentError.streamFailed(String(err));
738
+ completed = true;
739
+ this.logger.error(`Error in DextoAgent.stream: ${error.message}`);
740
+ const errorEvent = {
741
+ name: "llm:error",
742
+ error,
743
+ recoverable: false,
744
+ context: "run_failed",
745
+ sessionId
746
+ };
747
+ eventQueue.push(errorEvent);
748
+ }
617
749
  });
618
- });
750
+ })();
619
751
  const iterator = {
620
752
  async next() {
621
753
  while (!completed && eventQueue.length === 0) {
622
754
  await new Promise((resolve) => setTimeout(resolve, 0));
623
- if (signal?.aborted) {
755
+ if (signal?.aborted || cleanupSignal.aborted) {
624
756
  cleanupListeners();
625
757
  controller.abort();
626
758
  return { done: true, value: void 0 };
@@ -648,6 +780,73 @@ Either:
648
780
  };
649
781
  return iterator;
650
782
  }
783
+ /**
784
+ * Check if a session is currently processing a message.
785
+ * @param sessionId Session id
786
+ * @returns true if the session is busy processing; false otherwise
787
+ */
788
+ async isSessionBusy(sessionId) {
789
+ this.ensureStarted();
790
+ const session = await this.sessionManager.getSession(sessionId, false);
791
+ return session?.isBusy() ?? false;
792
+ }
793
+ /**
794
+ * Queue a message for processing when a session is busy.
795
+ * The message will be injected into the conversation when the current turn completes.
796
+ *
797
+ * @param sessionId Session id
798
+ * @param message The user message to queue
799
+ * @returns Queue position and message ID
800
+ * @throws Error if session doesn't support message queueing
801
+ */
802
+ async queueMessage(sessionId, message) {
803
+ this.ensureStarted();
804
+ const session = await this.sessionManager.getSession(sessionId, false);
805
+ if (!session) {
806
+ throw SessionError.notFound(sessionId);
807
+ }
808
+ return session.queueMessage(message);
809
+ }
810
+ /**
811
+ * Get all queued messages for a session.
812
+ * @param sessionId Session id
813
+ * @returns Array of queued messages
814
+ */
815
+ async getQueuedMessages(sessionId) {
816
+ this.ensureStarted();
817
+ const session = await this.sessionManager.getSession(sessionId, false);
818
+ if (!session) {
819
+ throw SessionError.notFound(sessionId);
820
+ }
821
+ return session.getQueuedMessages();
822
+ }
823
+ /**
824
+ * Remove a queued message.
825
+ * @param sessionId Session id
826
+ * @param messageId The ID of the queued message to remove
827
+ * @returns true if message was found and removed, false otherwise
828
+ */
829
+ async removeQueuedMessage(sessionId, messageId) {
830
+ this.ensureStarted();
831
+ const session = await this.sessionManager.getSession(sessionId, false);
832
+ if (!session) {
833
+ throw SessionError.notFound(sessionId);
834
+ }
835
+ return session.removeQueuedMessage(messageId);
836
+ }
837
+ /**
838
+ * Clear all queued messages for a session.
839
+ * @param sessionId Session id
840
+ * @returns Number of messages that were cleared
841
+ */
842
+ async clearMessageQueue(sessionId) {
843
+ this.ensureStarted();
844
+ const session = await this.sessionManager.getSession(sessionId, false);
845
+ if (!session) {
846
+ throw SessionError.notFound(sessionId);
847
+ }
848
+ return session.clearMessageQueue();
849
+ }
651
850
  /**
652
851
  * Cancels the currently running turn for a session.
653
852
  * Safe to call even if no run is in progress.
@@ -657,13 +856,20 @@ Either:
657
856
  async cancel(sessionId) {
658
857
  this.ensureStarted();
659
858
  if (!sessionId || typeof sessionId !== "string") {
660
- throw new Error("sessionId is required and must be a non-empty string");
859
+ throw AgentError.apiValidationError(
860
+ "sessionId is required and must be a non-empty string"
861
+ );
862
+ }
863
+ const streamController = this.activeStreamControllers.get(sessionId);
864
+ if (streamController) {
865
+ streamController.abort();
866
+ this.activeStreamControllers.delete(sessionId);
661
867
  }
662
868
  const existing = await this.sessionManager.getSession(sessionId, false);
663
869
  if (existing) {
664
870
  return existing.cancel();
665
871
  }
666
- return false;
872
+ return !!streamController;
667
873
  }
668
874
  // ============= SESSION MANAGEMENT =============
669
875
  /**
@@ -770,7 +976,6 @@ Either:
770
976
  const llmConfig = this.getEffectiveConfig(sessionId).llm;
771
977
  const result = await generateSessionTitle(
772
978
  llmConfig,
773
- llmConfig.router,
774
979
  this.toolManager,
775
980
  this.systemPromptManager,
776
981
  this.resourceManager,
@@ -853,7 +1058,9 @@ Either:
853
1058
  async resetConversation(sessionId) {
854
1059
  this.ensureStarted();
855
1060
  if (!sessionId || typeof sessionId !== "string") {
856
- throw new Error("sessionId is required and must be a non-empty string");
1061
+ throw AgentError.apiValidationError(
1062
+ "sessionId is required and must be a non-empty string"
1063
+ );
857
1064
  }
858
1065
  try {
859
1066
  await this.sessionManager.resetSession(sessionId);
@@ -868,6 +1075,37 @@ Either:
868
1075
  throw error;
869
1076
  }
870
1077
  }
1078
+ /**
1079
+ * Clears the context window for a session without deleting history.
1080
+ *
1081
+ * This adds a "context clear" marker to the conversation history. When the
1082
+ * context is loaded for LLM, messages before this marker are filtered out
1083
+ * (via filterCompacted). The full history remains in the database for
1084
+ * review via /resume or session history.
1085
+ *
1086
+ * Use this for /clear command - it preserves history but gives a fresh
1087
+ * context window to the LLM.
1088
+ *
1089
+ * @param sessionId Session ID (required)
1090
+ */
1091
+ async clearContext(sessionId) {
1092
+ this.ensureStarted();
1093
+ if (!sessionId || typeof sessionId !== "string") {
1094
+ throw AgentError.apiValidationError(
1095
+ "sessionId is required and must be a non-empty string"
1096
+ );
1097
+ }
1098
+ const session = await this.sessionManager.getSession(sessionId);
1099
+ if (!session) {
1100
+ throw SessionError.notFound(sessionId);
1101
+ }
1102
+ const contextManager = session.getContextManager();
1103
+ await contextManager.clearContext();
1104
+ this.logger.info(`Context cleared for session: ${sessionId}`);
1105
+ this.agentEventBus.emit("context:cleared", {
1106
+ sessionId
1107
+ });
1108
+ }
871
1109
  // ============= LLM MANAGEMENT =============
872
1110
  /**
873
1111
  * Gets the current LLM configuration with all defaults applied.
@@ -882,7 +1120,7 @@ Either:
882
1120
  * This is a comprehensive method that handles ALL validation, configuration building, and switching internally.
883
1121
  *
884
1122
  * Design:
885
- * - Input: Partial<LLMConfig> (allows optional fields like maxIterations?, router?)
1123
+ * - Input: Partial<LLMConfig> (allows optional fields like maxIterations?)
886
1124
  * - Output: LLMConfig (user-friendly type with all defaults applied)
887
1125
  *
888
1126
  * Key features:
@@ -907,8 +1145,8 @@ Either:
907
1145
  * // Switch to a different provider with explicit API key
908
1146
  * await agent.switchLLM({ provider: 'anthropic', model: 'claude-4-sonnet-20250514', apiKey: 'sk-ant-...' });
909
1147
  *
910
- * // Switch with router and session options
911
- * await agent.switchLLM({ provider: 'anthropic', model: 'claude-4-sonnet-20250514', router: 'in-built' }, 'user-123');
1148
+ * // Switch with session options
1149
+ * await agent.switchLLM({ provider: 'anthropic', model: 'claude-4-sonnet-20250514' }, 'user-123');
912
1150
  *
913
1151
  * // Switch for all sessions
914
1152
  * await agent.switchLLM({ model: 'gpt-5' }, '*');
@@ -1060,19 +1298,23 @@ Either:
1060
1298
  }
1061
1299
  // ============= MCP SERVER MANAGEMENT =============
1062
1300
  /**
1063
- * Connects a new MCP server and adds it to the runtime configuration.
1301
+ * Adds a new MCP server to the runtime configuration and connects it if enabled.
1064
1302
  * This method handles validation, state management, and establishing the connection.
1065
1303
  *
1066
- * @param name The name of the server to connect.
1304
+ * @param name The name of the server to add.
1067
1305
  * @param config The configuration object for the server.
1068
1306
  * @throws DextoError if validation fails or connection fails
1069
1307
  */
1070
- async connectMcpServer(name, config) {
1308
+ async addMcpServer(name, config) {
1071
1309
  this.ensureStarted();
1072
1310
  const existingServerNames = Object.keys(this.stateManager.getRuntimeConfig().mcpServers);
1073
1311
  const validation = resolveAndValidateMcpServerConfig(name, config, existingServerNames);
1074
1312
  const validatedConfig = ensureOk(validation, this.logger);
1075
- this.stateManager.addMcpServer(name, validatedConfig);
1313
+ this.stateManager.setMcpServer(name, validatedConfig);
1314
+ if (validatedConfig.enabled === false) {
1315
+ this.logger.info(`MCP server '${name}' added but not connected (disabled)`);
1316
+ return;
1317
+ }
1076
1318
  try {
1077
1319
  await this.mcpManager.connectServer(name, validatedConfig);
1078
1320
  await this.toolManager.refresh();
@@ -1084,9 +1326,7 @@ Either:
1084
1326
  tools: Object.keys(await this.toolManager.getAllTools()),
1085
1327
  source: "mcp"
1086
1328
  });
1087
- this.logger.info(
1088
- `DextoAgent: Successfully added and connected to MCP server '${name}'.`
1089
- );
1329
+ this.logger.info(`MCP server '${name}' added and connected successfully`);
1090
1330
  const warnings = validation.issues.filter((i) => i.severity === "warning");
1091
1331
  if (warnings.length > 0) {
1092
1332
  this.logger.warn(
@@ -1095,9 +1335,7 @@ Either:
1095
1335
  }
1096
1336
  } catch (error) {
1097
1337
  const errorMessage = error instanceof Error ? error.message : String(error);
1098
- this.logger.error(
1099
- `DextoAgent: Failed to connect to MCP server '${name}': ${errorMessage}`
1100
- );
1338
+ this.logger.error(`Failed to connect MCP server '${name}': ${errorMessage}`);
1101
1339
  this.stateManager.removeMcpServer(name);
1102
1340
  this.agentEventBus.emit("mcp:server-connected", {
1103
1341
  name,
@@ -1108,14 +1346,81 @@ Either:
1108
1346
  }
1109
1347
  }
1110
1348
  /**
1111
- * Removes and disconnects an MCP server.
1349
+ * @deprecated Use `addMcpServer` instead. This method will be removed in a future version.
1350
+ */
1351
+ async connectMcpServer(name, config) {
1352
+ return this.addMcpServer(name, config);
1353
+ }
1354
+ /**
1355
+ * Enables a disabled MCP server and connects it.
1356
+ * Updates the runtime state to enabled=true and establishes the connection.
1357
+ *
1358
+ * @param name The name of the server to enable.
1359
+ * @throws MCPError if server is not found or connection fails
1360
+ */
1361
+ async enableMcpServer(name) {
1362
+ this.ensureStarted();
1363
+ const currentConfig = this.stateManager.getRuntimeConfig().mcpServers[name];
1364
+ if (!currentConfig) {
1365
+ throw MCPError.serverNotFound(name);
1366
+ }
1367
+ const updatedConfig = { ...currentConfig, enabled: true };
1368
+ this.stateManager.setMcpServer(name, updatedConfig);
1369
+ try {
1370
+ await this.mcpManager.connectServer(name, updatedConfig);
1371
+ await this.toolManager.refresh();
1372
+ this.agentEventBus.emit("mcp:server-connected", { name, success: true });
1373
+ this.logger.info(`MCP server '${name}' enabled and connected`);
1374
+ } catch (error) {
1375
+ this.stateManager.setMcpServer(name, currentConfig);
1376
+ const errorMessage = error instanceof Error ? error.message : String(error);
1377
+ this.logger.error(`Failed to enable MCP server '${name}': ${errorMessage}`);
1378
+ throw MCPError.connectionFailed(name, errorMessage);
1379
+ }
1380
+ }
1381
+ /**
1382
+ * Disables an MCP server and disconnects it.
1383
+ * Updates the runtime state to enabled=false and closes the connection.
1384
+ *
1385
+ * @param name The name of the server to disable.
1386
+ * @throws MCPError if server is not found or disconnect fails
1387
+ */
1388
+ async disableMcpServer(name) {
1389
+ this.ensureStarted();
1390
+ const currentConfig = this.stateManager.getRuntimeConfig().mcpServers[name];
1391
+ if (!currentConfig) {
1392
+ throw MCPError.serverNotFound(name);
1393
+ }
1394
+ const updatedConfig = { ...currentConfig, enabled: false };
1395
+ this.stateManager.setMcpServer(name, updatedConfig);
1396
+ try {
1397
+ await this.mcpManager.removeClient(name);
1398
+ await this.toolManager.refresh();
1399
+ this.logger.info(`MCP server '${name}' disabled and disconnected`);
1400
+ } catch (error) {
1401
+ this.stateManager.setMcpServer(name, currentConfig);
1402
+ const errorMessage = error instanceof Error ? error.message : String(error);
1403
+ this.logger.error(`Failed to disable MCP server '${name}': ${errorMessage}`);
1404
+ throw MCPError.disconnectionFailed(name, errorMessage);
1405
+ }
1406
+ }
1407
+ /**
1408
+ * Removes and disconnects an MCP server completely.
1409
+ * Use this for deleting a server - removes from both runtime state and disconnects.
1112
1410
  * @param name The name of the server to remove.
1411
+ * @throws MCPError if disconnection fails
1113
1412
  */
1114
1413
  async removeMcpServer(name) {
1115
1414
  this.ensureStarted();
1116
- await this.mcpManager.removeClient(name);
1117
- this.stateManager.removeMcpServer(name);
1118
- await this.toolManager.refresh();
1415
+ try {
1416
+ await this.mcpManager.removeClient(name);
1417
+ this.stateManager.removeMcpServer(name);
1418
+ await this.toolManager.refresh();
1419
+ } catch (error) {
1420
+ const errorMessage = error instanceof Error ? error.message : String(error);
1421
+ this.logger.error(`Failed to remove MCP server '${name}': ${errorMessage}`);
1422
+ throw MCPError.disconnectionFailed(name, errorMessage);
1423
+ }
1119
1424
  }
1120
1425
  /**
1121
1426
  * Restarts an MCP server by disconnecting and reconnecting with its original configuration.
@@ -1148,13 +1453,18 @@ Either:
1148
1453
  /**
1149
1454
  * Executes a tool from any source (MCP servers, custom tools, or internal tools).
1150
1455
  * This is the unified interface for tool execution that can handle all tool types.
1456
+ *
1457
+ * Note: This is for direct/programmatic tool execution outside of LLM flow.
1458
+ * A toolCallId is generated automatically for tracking purposes.
1459
+ *
1151
1460
  * @param toolName The name of the tool to execute
1152
1461
  * @param args The arguments to pass to the tool
1153
1462
  * @returns The result of the tool execution
1154
1463
  */
1155
1464
  async executeTool(toolName, args) {
1156
1465
  this.ensureStarted();
1157
- return await this.toolManager.executeTool(toolName, args);
1466
+ const toolCallId = `direct-${randomUUID()}`;
1467
+ return await this.toolManager.executeTool(toolName, args, toolCallId);
1158
1468
  }
1159
1469
  /**
1160
1470
  * Gets all available tools from all connected MCP servers.
@@ -1192,6 +1502,79 @@ Either:
1192
1502
  this.ensureStarted();
1193
1503
  return this.mcpManager.getFailedConnections();
1194
1504
  }
1505
+ /**
1506
+ * Gets the connection status of a single MCP server.
1507
+ * @param name The server name
1508
+ * @returns The connection status, or undefined if server not configured
1509
+ *
1510
+ * TODO: Move to MCPManager once it has access to server configs (enabled state).
1511
+ * Currently here because MCPManager only tracks connections, not config.
1512
+ */
1513
+ getMcpServerStatus(name) {
1514
+ this.ensureStarted();
1515
+ const config = this.stateManager.getRuntimeConfig();
1516
+ const serverConfig = config.mcpServers[name];
1517
+ if (!serverConfig) return void 0;
1518
+ const enabled = serverConfig.enabled !== false;
1519
+ const connectedClients = this.mcpManager.getClients();
1520
+ const failedConnections = this.mcpManager.getFailedConnections();
1521
+ let status;
1522
+ if (!enabled) {
1523
+ status = "disconnected";
1524
+ } else if (connectedClients.has(name)) {
1525
+ status = "connected";
1526
+ } else {
1527
+ status = "error";
1528
+ }
1529
+ const result = {
1530
+ name,
1531
+ type: serverConfig.type,
1532
+ enabled,
1533
+ status
1534
+ };
1535
+ if (failedConnections[name]) {
1536
+ result.error = failedConnections[name];
1537
+ }
1538
+ return result;
1539
+ }
1540
+ /**
1541
+ * Gets all configured MCP servers with their connection status.
1542
+ * Centralizes the status computation logic used by CLI, server, and webui.
1543
+ * @returns Array of server info with computed status
1544
+ *
1545
+ * TODO: Move to MCPManager once it has access to server configs (enabled state).
1546
+ * Currently here because MCPManager only tracks connections, not config.
1547
+ */
1548
+ getMcpServersWithStatus() {
1549
+ this.ensureStarted();
1550
+ const config = this.stateManager.getRuntimeConfig();
1551
+ const mcpServers = config.mcpServers || {};
1552
+ const connectedClients = this.mcpManager.getClients();
1553
+ const failedConnections = this.mcpManager.getFailedConnections();
1554
+ const servers = [];
1555
+ for (const [name, serverConfig] of Object.entries(mcpServers)) {
1556
+ const enabled = serverConfig.enabled !== false;
1557
+ let status;
1558
+ if (!enabled) {
1559
+ status = "disconnected";
1560
+ } else if (connectedClients.has(name)) {
1561
+ status = "connected";
1562
+ } else {
1563
+ status = "error";
1564
+ }
1565
+ const server = {
1566
+ name,
1567
+ type: serverConfig.type,
1568
+ enabled,
1569
+ status
1570
+ };
1571
+ if (failedConnections[name]) {
1572
+ server.error = failedConnections[name];
1573
+ }
1574
+ servers.push(server);
1575
+ }
1576
+ return servers;
1577
+ }
1195
1578
  // ============= RESOURCE MANAGEMENT =============
1196
1579
  /**
1197
1580
  * Lists all available resources with their info.
@@ -1287,6 +1670,21 @@ Either:
1287
1670
  this.ensureStarted();
1288
1671
  return await this.promptManager.has(name);
1289
1672
  }
1673
+ /**
1674
+ * Refreshes the prompts cache, reloading from all providers.
1675
+ * Call this after adding/deleting prompts to make them immediately available.
1676
+ *
1677
+ * @param newPrompts Optional - if provided, updates the config prompts before refreshing.
1678
+ * Use this when you've modified the agent config file and need to
1679
+ * update both the runtime config and refresh the cache.
1680
+ */
1681
+ async refreshPrompts(newPrompts) {
1682
+ this.ensureStarted();
1683
+ if (newPrompts) {
1684
+ this.promptManager.updateConfigPrompts(newPrompts);
1685
+ }
1686
+ await this.promptManager.refresh();
1687
+ }
1290
1688
  /**
1291
1689
  * Gets a prompt with its messages.
1292
1690
  * @param name The name of the prompt