@dexto/core 1.3.0 → 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 (479) hide show
  1. package/README.md +17 -9
  2. package/dist/agent/DextoAgent.cjs +548 -207
  3. package/dist/agent/DextoAgent.d.ts +156 -33
  4. package/dist/agent/DextoAgent.d.ts.map +1 -1
  5. package/dist/agent/DextoAgent.js +545 -204
  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 +3 -0
  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 +6 -2
  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 -10
  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 +18 -4
  36. package/dist/approval/schemas.d.ts +106 -32
  37. package/dist/approval/schemas.d.ts.map +1 -1
  38. package/dist/approval/schemas.js +19 -5
  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/default.cjs → context/compression/overflow.cjs} +20 -18
  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 +280 -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 +280 -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 +181 -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.js +1 -1
  81. package/dist/events/index.cjs +18 -1
  82. package/dist/events/index.d.ts +149 -12
  83. package/dist/events/index.d.ts.map +1 -1
  84. package/dist/events/index.js +19 -2
  85. package/dist/filesystem/error-codes.js +1 -1
  86. package/dist/filesystem/errors.js +1 -1
  87. package/dist/filesystem/filesystem-service.js +1 -1
  88. package/dist/filesystem/index.js +1 -1
  89. package/dist/filesystem/path-validator.js +1 -1
  90. package/dist/index.browser.cjs +23 -8
  91. package/dist/index.browser.d.ts +4 -3
  92. package/dist/index.browser.d.ts.map +1 -1
  93. package/dist/index.browser.js +20 -3
  94. package/dist/index.js +1 -1
  95. package/dist/llm/error-codes.cjs +0 -1
  96. package/dist/llm/error-codes.d.ts +0 -1
  97. package/dist/llm/error-codes.d.ts.map +1 -1
  98. package/dist/llm/error-codes.js +1 -2
  99. package/dist/llm/errors.cjs +10 -10
  100. package/dist/llm/errors.d.ts +5 -6
  101. package/dist/llm/errors.d.ts.map +1 -1
  102. package/dist/llm/errors.js +12 -12
  103. package/dist/llm/executor/stream-processor.cjs +367 -0
  104. package/dist/llm/executor/stream-processor.d.ts +55 -0
  105. package/dist/llm/executor/stream-processor.d.ts.map +1 -0
  106. package/dist/llm/executor/stream-processor.js +344 -0
  107. package/dist/llm/executor/tool-output-truncator.cjs +75 -0
  108. package/dist/llm/executor/tool-output-truncator.d.ts +27 -0
  109. package/dist/llm/executor/tool-output-truncator.d.ts.map +1 -0
  110. package/dist/llm/executor/tool-output-truncator.js +48 -0
  111. package/dist/llm/executor/turn-executor.cjs +753 -0
  112. package/dist/llm/executor/turn-executor.d.ts +166 -0
  113. package/dist/llm/executor/turn-executor.d.ts.map +1 -0
  114. package/dist/llm/executor/turn-executor.js +684 -0
  115. package/dist/llm/executor/types.d.ts +27 -0
  116. package/dist/llm/executor/types.d.ts.map +1 -0
  117. package/dist/llm/formatters/vercel.cjs +20 -186
  118. package/dist/llm/formatters/vercel.d.ts +2 -14
  119. package/dist/llm/formatters/vercel.d.ts.map +1 -1
  120. package/dist/llm/formatters/vercel.js +19 -185
  121. package/dist/llm/registry.cjs +36 -45
  122. package/dist/llm/registry.d.ts +53 -39
  123. package/dist/llm/registry.d.ts.map +1 -1
  124. package/dist/llm/registry.js +34 -42
  125. package/dist/llm/resolver.cjs +1 -31
  126. package/dist/llm/resolver.d.ts.map +1 -1
  127. package/dist/llm/resolver.js +2 -34
  128. package/dist/llm/schemas.cjs +2 -17
  129. package/dist/llm/schemas.d.ts +10 -23
  130. package/dist/llm/schemas.d.ts.map +1 -1
  131. package/dist/llm/schemas.js +5 -22
  132. package/dist/llm/services/factory.cjs +3 -92
  133. package/dist/llm/services/factory.d.ts +14 -4
  134. package/dist/llm/services/factory.d.ts.map +1 -1
  135. package/dist/llm/services/factory.js +4 -83
  136. package/dist/llm/services/test-utils.integration.cjs +6 -8
  137. package/dist/llm/services/test-utils.integration.d.ts.map +1 -1
  138. package/dist/llm/services/test-utils.integration.js +7 -9
  139. package/dist/llm/services/types.d.ts +1 -28
  140. package/dist/llm/services/types.d.ts.map +1 -1
  141. package/dist/llm/services/vercel.cjs +54 -468
  142. package/dist/llm/services/vercel.d.ts +38 -21
  143. package/dist/llm/services/vercel.d.ts.map +1 -1
  144. package/dist/llm/services/vercel.js +56 -475
  145. package/dist/llm/types.cjs +0 -3
  146. package/dist/llm/types.d.ts +8 -8
  147. package/dist/llm/types.d.ts.map +1 -1
  148. package/dist/llm/types.js +1 -3
  149. package/dist/llm/validation.js +1 -1
  150. package/dist/logger/browser.js +1 -1
  151. package/dist/logger/factory.js +1 -1
  152. package/dist/logger/index.js +1 -1
  153. package/dist/logger/logger.js +1 -1
  154. package/dist/logger/v2/dexto-logger.cjs +34 -6
  155. package/dist/logger/v2/dexto-logger.d.ts +20 -2
  156. package/dist/logger/v2/dexto-logger.d.ts.map +1 -1
  157. package/dist/logger/v2/dexto-logger.js +35 -7
  158. package/dist/logger/v2/error-codes.js +1 -1
  159. package/dist/logger/v2/errors.js +1 -1
  160. package/dist/logger/v2/schemas.js +1 -1
  161. package/dist/logger/v2/test-utils.cjs +70 -0
  162. package/dist/logger/v2/test-utils.d.ts +17 -0
  163. package/dist/logger/v2/test-utils.d.ts.map +1 -0
  164. package/dist/logger/v2/test-utils.js +46 -0
  165. package/dist/logger/v2/transport-factory.js +1 -1
  166. package/dist/logger/v2/transports/console-transport.js +1 -1
  167. package/dist/logger/v2/transports/file-transport.cjs +6 -0
  168. package/dist/logger/v2/transports/file-transport.d.ts +4 -0
  169. package/dist/logger/v2/transports/file-transport.d.ts.map +1 -1
  170. package/dist/logger/v2/transports/file-transport.js +7 -1
  171. package/dist/logger/v2/types.cjs +1 -0
  172. package/dist/logger/v2/types.d.ts +18 -2
  173. package/dist/logger/v2/types.d.ts.map +1 -1
  174. package/dist/logger/v2/types.js +2 -1
  175. package/dist/mcp/error-codes.cjs +1 -0
  176. package/dist/mcp/error-codes.d.ts +1 -0
  177. package/dist/mcp/error-codes.d.ts.map +1 -1
  178. package/dist/mcp/error-codes.js +2 -1
  179. package/dist/mcp/errors.cjs +13 -0
  180. package/dist/mcp/errors.d.ts +7 -0
  181. package/dist/mcp/errors.d.ts.map +1 -1
  182. package/dist/mcp/errors.js +14 -1
  183. package/dist/mcp/manager.cjs +4 -0
  184. package/dist/mcp/manager.d.ts.map +1 -1
  185. package/dist/mcp/manager.js +5 -1
  186. package/dist/mcp/mcp-client.js +1 -1
  187. package/dist/mcp/resolver.js +1 -1
  188. package/dist/mcp/schemas.cjs +6 -0
  189. package/dist/mcp/schemas.d.ts +52 -0
  190. package/dist/mcp/schemas.d.ts.map +1 -1
  191. package/dist/mcp/schemas.js +6 -1
  192. package/dist/memory/error-codes.js +1 -1
  193. package/dist/memory/errors.js +1 -1
  194. package/dist/memory/index.js +1 -1
  195. package/dist/memory/manager.js +1 -1
  196. package/dist/memory/schemas.d.ts +2 -2
  197. package/dist/memory/schemas.js +1 -1
  198. package/dist/plugins/builtins/content-policy.js +1 -1
  199. package/dist/plugins/builtins/response-sanitizer.js +1 -1
  200. package/dist/plugins/error-codes.js +1 -1
  201. package/dist/plugins/index.js +1 -1
  202. package/dist/plugins/loader.js +1 -1
  203. package/dist/plugins/manager.js +1 -1
  204. package/dist/plugins/registrations/builtins.js +1 -1
  205. package/dist/plugins/schemas.d.ts +3 -3
  206. package/dist/plugins/schemas.js +1 -1
  207. package/dist/plugins/types.d.ts +0 -1
  208. package/dist/plugins/types.d.ts.map +1 -1
  209. package/dist/process/command-validator.js +1 -1
  210. package/dist/process/error-codes.js +1 -1
  211. package/dist/process/errors.js +1 -1
  212. package/dist/process/index.js +1 -1
  213. package/dist/process/process-service.cjs +78 -26
  214. package/dist/process/process-service.d.ts +6 -1
  215. package/dist/process/process-service.d.ts.map +1 -1
  216. package/dist/process/process-service.js +79 -27
  217. package/dist/process/types.d.ts +2 -2
  218. package/dist/process/types.d.ts.map +1 -1
  219. package/dist/prompts/error-codes.cjs +1 -0
  220. package/dist/prompts/error-codes.d.ts +2 -1
  221. package/dist/prompts/error-codes.d.ts.map +1 -1
  222. package/dist/prompts/error-codes.js +2 -1
  223. package/dist/prompts/errors.cjs +15 -0
  224. package/dist/prompts/errors.d.ts +4 -0
  225. package/dist/prompts/errors.d.ts.map +1 -1
  226. package/dist/prompts/errors.js +16 -1
  227. package/dist/prompts/index.js +1 -1
  228. package/dist/prompts/name-validation.js +1 -1
  229. package/dist/prompts/prompt-manager.cjs +13 -2
  230. package/dist/prompts/prompt-manager.d.ts +7 -0
  231. package/dist/prompts/prompt-manager.d.ts.map +1 -1
  232. package/dist/prompts/prompt-manager.js +14 -3
  233. package/dist/prompts/providers/config-prompt-provider.cjs +12 -3
  234. package/dist/prompts/providers/config-prompt-provider.d.ts +2 -1
  235. package/dist/prompts/providers/config-prompt-provider.d.ts.map +1 -1
  236. package/dist/prompts/providers/config-prompt-provider.js +13 -4
  237. package/dist/prompts/providers/custom-prompt-provider.js +1 -1
  238. package/dist/prompts/providers/mcp-prompt-provider.js +1 -1
  239. package/dist/prompts/schemas.d.ts +12 -0
  240. package/dist/prompts/schemas.d.ts.map +1 -1
  241. package/dist/prompts/schemas.js +1 -1
  242. package/dist/prompts/types.d.ts +2 -0
  243. package/dist/prompts/types.d.ts.map +1 -1
  244. package/dist/prompts/utils.js +1 -1
  245. package/dist/resources/error-codes.js +1 -1
  246. package/dist/resources/errors.js +1 -1
  247. package/dist/resources/handlers/blob-handler.js +1 -1
  248. package/dist/resources/handlers/factory.js +1 -1
  249. package/dist/resources/handlers/filesystem-handler.js +1 -1
  250. package/dist/resources/index.js +1 -1
  251. package/dist/resources/internal-provider.js +1 -1
  252. package/dist/resources/manager.js +1 -1
  253. package/dist/resources/reference-parser.js +1 -1
  254. package/dist/resources/schemas.js +1 -1
  255. package/dist/search/index.js +1 -1
  256. package/dist/search/search-service.js +1 -1
  257. package/dist/session/chat-session.cjs +149 -51
  258. package/dist/session/chat-session.d.ts +69 -29
  259. package/dist/session/chat-session.d.ts.map +1 -1
  260. package/dist/session/chat-session.js +150 -52
  261. package/dist/session/error-codes.js +1 -1
  262. package/dist/session/errors.js +1 -1
  263. package/dist/session/history/database.cjs +134 -21
  264. package/dist/session/history/database.d.ts +37 -8
  265. package/dist/session/history/database.d.ts.map +1 -1
  266. package/dist/session/history/database.js +135 -22
  267. package/dist/session/history/factory.js +1 -1
  268. package/dist/session/history/memory.cjs +18 -0
  269. package/dist/session/history/memory.d.ts +8 -0
  270. package/dist/session/history/memory.d.ts.map +1 -1
  271. package/dist/session/history/memory.js +19 -1
  272. package/dist/session/history/types.d.ts +13 -1
  273. package/dist/session/history/types.d.ts.map +1 -1
  274. package/dist/session/index.cjs +3 -0
  275. package/dist/session/index.d.ts +3 -0
  276. package/dist/session/index.d.ts.map +1 -1
  277. package/dist/session/index.js +3 -1
  278. package/dist/session/message-queue.cjs +201 -0
  279. package/dist/session/message-queue.d.ts +114 -0
  280. package/dist/session/message-queue.d.ts.map +1 -0
  281. package/dist/session/message-queue.js +178 -0
  282. package/dist/session/schemas.js +1 -1
  283. package/dist/session/session-manager.cjs +57 -7
  284. package/dist/session/session-manager.d.ts +18 -0
  285. package/dist/session/session-manager.d.ts.map +1 -1
  286. package/dist/session/session-manager.js +58 -8
  287. package/dist/session/title-generator.cjs +4 -8
  288. package/dist/session/title-generator.d.ts +1 -2
  289. package/dist/session/title-generator.d.ts.map +1 -1
  290. package/dist/session/title-generator.js +5 -9
  291. package/dist/session/types.cjs +16 -0
  292. package/dist/session/types.d.ts +14 -0
  293. package/dist/session/types.d.ts.map +1 -0
  294. package/dist/session/types.js +0 -0
  295. package/dist/storage/blob/factory.js +1 -1
  296. package/dist/storage/blob/local-blob-store.js +1 -1
  297. package/dist/storage/blob/memory-blob-store.js +1 -1
  298. package/dist/storage/blob/schemas.js +1 -1
  299. package/dist/storage/cache/factory.js +1 -1
  300. package/dist/storage/cache/memory-cache-store.js +1 -1
  301. package/dist/storage/cache/redis-store.js +1 -1
  302. package/dist/storage/cache/schemas.js +1 -1
  303. package/dist/storage/database/factory.js +1 -1
  304. package/dist/storage/database/memory-database-store.js +1 -1
  305. package/dist/storage/database/postgres-store.cjs +12 -0
  306. package/dist/storage/database/postgres-store.d.ts.map +1 -1
  307. package/dist/storage/database/postgres-store.js +13 -1
  308. package/dist/storage/database/schemas.js +1 -1
  309. package/dist/storage/database/sqlite-store.js +1 -1
  310. package/dist/storage/error-codes.js +1 -1
  311. package/dist/storage/errors.js +1 -1
  312. package/dist/storage/index.js +1 -1
  313. package/dist/storage/schemas.js +1 -1
  314. package/dist/storage/storage-manager.js +1 -1
  315. package/dist/systemPrompt/contributors.js +1 -1
  316. package/dist/systemPrompt/error-codes.js +1 -1
  317. package/dist/systemPrompt/errors.js +1 -1
  318. package/dist/systemPrompt/in-built-prompts.js +1 -1
  319. package/dist/systemPrompt/index.js +1 -1
  320. package/dist/systemPrompt/manager.js +1 -1
  321. package/dist/systemPrompt/registry.js +1 -1
  322. package/dist/systemPrompt/schemas.d.ts +5 -5
  323. package/dist/systemPrompt/schemas.js +1 -1
  324. package/dist/telemetry/decorators.js +1 -1
  325. package/dist/telemetry/error-codes.js +1 -1
  326. package/dist/telemetry/errors.js +1 -1
  327. package/dist/telemetry/exporters.js +1 -1
  328. package/dist/telemetry/index.js +1 -1
  329. package/dist/telemetry/schemas.js +1 -1
  330. package/dist/telemetry/telemetry.js +1 -1
  331. package/dist/telemetry/utils.js +1 -1
  332. package/dist/tools/bash-pattern-utils.cjs +91 -0
  333. package/dist/tools/bash-pattern-utils.d.ts +58 -0
  334. package/dist/tools/bash-pattern-utils.d.ts.map +1 -0
  335. package/dist/tools/bash-pattern-utils.js +64 -0
  336. package/dist/tools/confirmation/allowed-tools-provider/factory.js +1 -1
  337. package/dist/tools/confirmation/allowed-tools-provider/in-memory.js +1 -1
  338. package/dist/tools/confirmation/allowed-tools-provider/storage.js +1 -1
  339. package/dist/tools/display-types.cjs +60 -0
  340. package/dist/tools/display-types.d.ts +133 -0
  341. package/dist/tools/display-types.d.ts.map +1 -0
  342. package/dist/tools/display-types.js +32 -0
  343. package/dist/tools/error-codes.cjs +2 -0
  344. package/dist/tools/error-codes.d.ts +3 -1
  345. package/dist/tools/error-codes.d.ts.map +1 -1
  346. package/dist/tools/error-codes.js +3 -1
  347. package/dist/tools/errors.cjs +30 -0
  348. package/dist/tools/errors.d.ts +16 -0
  349. package/dist/tools/errors.d.ts.map +1 -1
  350. package/dist/tools/errors.js +31 -1
  351. package/dist/tools/index.cjs +2 -0
  352. package/dist/tools/index.d.ts +1 -0
  353. package/dist/tools/index.d.ts.map +1 -1
  354. package/dist/tools/index.js +2 -1
  355. package/dist/tools/internal-tools/constants.js +1 -1
  356. package/dist/tools/internal-tools/implementations/ask-user-tool.cjs +1 -1
  357. package/dist/tools/internal-tools/implementations/ask-user-tool.js +2 -2
  358. package/dist/tools/internal-tools/implementations/bash-exec-tool.cjs +42 -18
  359. package/dist/tools/internal-tools/implementations/bash-exec-tool.d.ts +3 -3
  360. package/dist/tools/internal-tools/implementations/bash-exec-tool.d.ts.map +1 -1
  361. package/dist/tools/internal-tools/implementations/bash-exec-tool.js +43 -19
  362. package/dist/tools/internal-tools/implementations/bash-output-tool.js +1 -1
  363. package/dist/tools/internal-tools/implementations/delegate-to-url-tool.js +1 -1
  364. package/dist/tools/internal-tools/implementations/edit-file-tool.cjs +66 -1
  365. package/dist/tools/internal-tools/implementations/edit-file-tool.d.ts.map +1 -1
  366. package/dist/tools/internal-tools/implementations/edit-file-tool.js +67 -2
  367. package/dist/tools/internal-tools/implementations/glob-files-tool.cjs +14 -1
  368. package/dist/tools/internal-tools/implementations/glob-files-tool.d.ts.map +1 -1
  369. package/dist/tools/internal-tools/implementations/glob-files-tool.js +15 -2
  370. package/dist/tools/internal-tools/implementations/grep-content-tool.cjs +16 -1
  371. package/dist/tools/internal-tools/implementations/grep-content-tool.d.ts.map +1 -1
  372. package/dist/tools/internal-tools/implementations/grep-content-tool.js +17 -2
  373. package/dist/tools/internal-tools/implementations/kill-process-tool.js +1 -1
  374. package/dist/tools/internal-tools/implementations/read-file-tool.cjs +9 -1
  375. package/dist/tools/internal-tools/implementations/read-file-tool.d.ts.map +1 -1
  376. package/dist/tools/internal-tools/implementations/read-file-tool.js +10 -2
  377. package/dist/tools/internal-tools/implementations/search-history-tool.js +1 -1
  378. package/dist/tools/internal-tools/implementations/write-file-tool.cjs +69 -1
  379. package/dist/tools/internal-tools/implementations/write-file-tool.d.ts.map +1 -1
  380. package/dist/tools/internal-tools/implementations/write-file-tool.js +72 -2
  381. package/dist/tools/internal-tools/provider.cjs +27 -10
  382. package/dist/tools/internal-tools/provider.d.ts +8 -5
  383. package/dist/tools/internal-tools/provider.d.ts.map +1 -1
  384. package/dist/tools/internal-tools/provider.js +28 -11
  385. package/dist/tools/internal-tools/registry.cjs +4 -3
  386. package/dist/tools/internal-tools/registry.d.ts +28 -7
  387. package/dist/tools/internal-tools/registry.d.ts.map +1 -1
  388. package/dist/tools/internal-tools/registry.js +5 -4
  389. package/dist/tools/schemas.cjs +16 -6
  390. package/dist/tools/schemas.d.ts +31 -4
  391. package/dist/tools/schemas.d.ts.map +1 -1
  392. package/dist/tools/schemas.js +14 -6
  393. package/dist/tools/tool-manager.cjs +140 -18
  394. package/dist/tools/tool-manager.d.ts +23 -1
  395. package/dist/tools/tool-manager.d.ts.map +1 -1
  396. package/dist/tools/tool-manager.js +145 -19
  397. package/dist/tools/types.d.ts +20 -0
  398. package/dist/tools/types.d.ts.map +1 -1
  399. package/dist/utils/api-key-resolver.js +1 -1
  400. package/dist/utils/async-context.js +1 -1
  401. package/dist/utils/debug.js +1 -1
  402. package/dist/{llm/tokenizer/types.cjs → utils/defer.cjs} +19 -10
  403. package/dist/utils/defer.d.ts +63 -0
  404. package/dist/utils/defer.d.ts.map +1 -0
  405. package/dist/utils/defer.js +19 -0
  406. package/dist/utils/env-file.js +1 -1
  407. package/dist/utils/error-conversion.js +1 -1
  408. package/dist/utils/execution-context.js +1 -1
  409. package/dist/utils/fs-walk.js +1 -1
  410. package/dist/utils/index.cjs +3 -1
  411. package/dist/utils/index.d.ts +1 -0
  412. package/dist/utils/index.d.ts.map +1 -1
  413. package/dist/utils/index.js +1 -0
  414. package/dist/utils/path.js +1 -1
  415. package/dist/utils/redactor.js +1 -1
  416. package/dist/utils/result.js +1 -1
  417. package/dist/utils/safe-stringify.js +1 -1
  418. package/dist/utils/schema-metadata.js +1 -1
  419. package/dist/utils/schema.js +1 -1
  420. package/dist/utils/service-initializer.cjs +6 -2
  421. package/dist/utils/service-initializer.d.ts.map +1 -1
  422. package/dist/utils/service-initializer.js +7 -3
  423. package/dist/utils/user-info.js +1 -1
  424. package/dist/utils/zod-schema-converter.js +1 -1
  425. package/package.json +6 -7
  426. package/dist/context/compression/middle-removal.cjs +0 -95
  427. package/dist/context/compression/middle-removal.d.ts +0 -47
  428. package/dist/context/compression/middle-removal.d.ts.map +0 -1
  429. package/dist/context/compression/middle-removal.js +0 -72
  430. package/dist/context/compression/oldest-removal.cjs +0 -83
  431. package/dist/context/compression/oldest-removal.d.ts +0 -42
  432. package/dist/context/compression/oldest-removal.d.ts.map +0 -1
  433. package/dist/context/compression/oldest-removal.js +0 -60
  434. package/dist/llm/formatters/anthropic.cjs +0 -257
  435. package/dist/llm/formatters/anthropic.d.ts +0 -46
  436. package/dist/llm/formatters/anthropic.d.ts.map +0 -1
  437. package/dist/llm/formatters/anthropic.js +0 -239
  438. package/dist/llm/formatters/factory.cjs +0 -50
  439. package/dist/llm/formatters/factory.d.ts +0 -10
  440. package/dist/llm/formatters/factory.d.ts.map +0 -1
  441. package/dist/llm/formatters/factory.js +0 -27
  442. package/dist/llm/formatters/openai.cjs +0 -203
  443. package/dist/llm/formatters/openai.d.ts +0 -39
  444. package/dist/llm/formatters/openai.d.ts.map +0 -1
  445. package/dist/llm/formatters/openai.js +0 -184
  446. package/dist/llm/formatters/types.d.ts +0 -41
  447. package/dist/llm/formatters/types.d.ts.map +0 -1
  448. package/dist/llm/services/anthropic.cjs +0 -511
  449. package/dist/llm/services/anthropic.d.ts +0 -48
  450. package/dist/llm/services/anthropic.d.ts.map +0 -1
  451. package/dist/llm/services/anthropic.js +0 -447
  452. package/dist/llm/services/openai.cjs +0 -611
  453. package/dist/llm/services/openai.d.ts +0 -48
  454. package/dist/llm/services/openai.d.ts.map +0 -1
  455. package/dist/llm/services/openai.js +0 -547
  456. package/dist/llm/tokenizer/anthropic.cjs +0 -43
  457. package/dist/llm/tokenizer/anthropic.d.ts +0 -19
  458. package/dist/llm/tokenizer/anthropic.d.ts.map +0 -1
  459. package/dist/llm/tokenizer/anthropic.js +0 -20
  460. package/dist/llm/tokenizer/default.d.ts +0 -14
  461. package/dist/llm/tokenizer/default.d.ts.map +0 -1
  462. package/dist/llm/tokenizer/default.js +0 -18
  463. package/dist/llm/tokenizer/factory.cjs +0 -44
  464. package/dist/llm/tokenizer/factory.d.ts +0 -12
  465. package/dist/llm/tokenizer/factory.d.ts.map +0 -1
  466. package/dist/llm/tokenizer/factory.js +0 -21
  467. package/dist/llm/tokenizer/google.cjs +0 -52
  468. package/dist/llm/tokenizer/google.d.ts +0 -29
  469. package/dist/llm/tokenizer/google.d.ts.map +0 -1
  470. package/dist/llm/tokenizer/google.js +0 -29
  471. package/dist/llm/tokenizer/openai.cjs +0 -115
  472. package/dist/llm/tokenizer/openai.d.ts +0 -41
  473. package/dist/llm/tokenizer/openai.d.ts.map +0 -1
  474. package/dist/llm/tokenizer/openai.js +0 -91
  475. package/dist/llm/tokenizer/types.d.ts +0 -18
  476. package/dist/llm/tokenizer/types.d.ts.map +0 -1
  477. package/dist/llm/tokenizer/types.js +0 -10
  478. /package/dist/llm/{formatters → executor}/types.cjs +0 -0
  479. /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";
@@ -103,6 +106,8 @@ class DextoAgent {
103
106
  // Approval handler for manual tool confirmation and elicitation
104
107
  // Set via setApprovalHandler() before start() if needed
105
108
  approvalHandler;
109
+ // Active stream controllers per session - allows cancel() to abort iterators
110
+ activeStreamControllers = /* @__PURE__ */ new Map();
106
111
  // Logger instance for this agent (dependency injection)
107
112
  logger;
108
113
  /**
@@ -178,10 +183,6 @@ Either:
178
183
  for (const subscriber of this.eventSubscribers) {
179
184
  subscriber.subscribe(this.agentEventBus);
180
185
  }
181
- const fileTransport = this.config.logger?.transports?.find((t) => t.type === "file");
182
- if (fileTransport && "path" in fileTransport) {
183
- console.log(`\u{1F4CB} Logs available at: ${fileTransport.path}`);
184
- }
185
186
  } catch (error) {
186
187
  this.logger.error("Failed to start DextoAgent", {
187
188
  error: error instanceof Error ? error.message : String(error)
@@ -312,173 +313,88 @@ Either:
312
313
  }
313
314
  // ============= CORE AGENT FUNCTIONALITY =============
314
315
  /**
315
- * Main method for processing user input.
316
- * 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.
317
320
  *
318
- * @param textInput - The user's text message or query to process
319
- * @param imageDataInput - Optional image data and MIME type for multimodal input
320
- * @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
321
324
  * @param sessionId - Session ID for the conversation (required)
322
- * @param stream - Whether to stream the response (default: false)
323
- * @returns Promise that resolves to the AI's response text, or null if no significant response
324
- * @throws Error if processing fails
325
+ * @param _stream - Ignored (streaming is handled internally)
326
+ * @returns Promise that resolves to the AI's response text
325
327
  */
326
- async run(textInput, imageDataInput, fileDataInput, sessionId, stream = false) {
327
- this.ensureStarted();
328
- if (!sessionId || typeof sessionId !== "string") {
329
- 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 });
330
332
  }
331
- const targetSessionId = sessionId;
332
- const activeContext = context.active();
333
- const span = trace.getActiveSpan();
334
- if (span) {
335
- span.setAttribute("sessionId", targetSessionId);
333
+ if (imageDataInput) {
334
+ parts.push({
335
+ type: "image",
336
+ image: imageDataInput.image,
337
+ mimeType: imageDataInput.mimeType
338
+ });
336
339
  }
337
- const existingBaggage = propagation.getBaggage(activeContext);
338
- const baggageEntries = {};
339
- if (existingBaggage) {
340
- existingBaggage.getAllEntries().forEach(([key, entry]) => {
341
- 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 }
342
346
  });
343
347
  }
344
- baggageEntries.sessionId = { ...baggageEntries.sessionId, value: targetSessionId };
345
- const updatedContext = propagation.setBaggage(
346
- activeContext,
347
- propagation.createBaggage(baggageEntries)
348
- );
349
- const verifyBaggage = propagation.getBaggage(updatedContext);
350
- this.logger.debug(
351
- `Baggage after setting sessionId: ${JSON.stringify(
352
- Array.from(verifyBaggage?.getAllEntries() || [])
353
- )}`
354
- );
355
- return await context.with(updatedContext, async () => {
356
- try {
357
- const llmConfig = this.stateManager.getLLMConfig(targetSessionId);
358
- const validation = validateInputForLLM(
359
- {
360
- text: textInput,
361
- ...imageDataInput && { imageData: imageDataInput },
362
- ...fileDataInput && { fileData: fileDataInput }
363
- },
364
- {
365
- provider: llmConfig.provider,
366
- model: llmConfig.model
367
- },
368
- this.logger
369
- );
370
- ensureOk(validation, this.logger);
371
- const session = await this.sessionManager.getSession(targetSessionId) || await this.sessionManager.createSession(targetSessionId);
372
- this.logger.debug(
373
- `DextoAgent.run: sessionId=${targetSessionId}, textLength=${textInput?.length ?? 0}, hasImage=${Boolean(
374
- imageDataInput
375
- )}, hasFile=${Boolean(fileDataInput)}`
376
- );
377
- let finalText = textInput;
378
- let finalImageData = imageDataInput;
379
- if (textInput && textInput.includes("@")) {
380
- try {
381
- const resources = await this.resourceManager.list();
382
- const expansion = await expandMessageReferences(
383
- textInput,
384
- resources,
385
- (uri) => this.resourceManager.read(uri)
386
- );
387
- if (expansion.unresolvedReferences.length > 0) {
388
- const unresolvedNames = expansion.unresolvedReferences.map((ref) => ref.originalRef).join(", ");
389
- this.logger.warn(
390
- `Could not resolve ${expansion.unresolvedReferences.length} resource reference(s): ${unresolvedNames}`
391
- );
392
- }
393
- const MAX_EXPANDED_SIZE = 5 * 1024 * 1024;
394
- const expandedSize = Buffer.byteLength(expansion.expandedMessage, "utf-8");
395
- if (expandedSize > MAX_EXPANDED_SIZE) {
396
- this.logger.warn(
397
- `Expanded message size (${(expandedSize / 1024 / 1024).toFixed(2)}MB) exceeds limit (${MAX_EXPANDED_SIZE / 1024 / 1024}MB). Content may be truncated.`
398
- );
399
- }
400
- finalText = expansion.expandedMessage;
401
- if (expansion.extractedImages.length > 0 && !imageDataInput) {
402
- const firstImage = expansion.extractedImages[0];
403
- if (firstImage) {
404
- finalImageData = {
405
- image: firstImage.image,
406
- mimeType: firstImage.mimeType
407
- };
408
- this.logger.debug(
409
- `Using extracted image: ${firstImage.name} (${firstImage.mimeType})`
410
- );
411
- }
412
- }
413
- } catch (error) {
414
- this.logger.error(
415
- `Failed to expand resource references: ${error instanceof Error ? error.message : String(error)}. Continuing with original message.`
416
- );
417
- }
418
- }
419
- if (!finalText.trim() && !finalImageData && !fileDataInput) {
420
- this.logger.warn(
421
- "Resource expansion resulted in empty content. Using original message."
422
- );
423
- finalText = textInput;
424
- }
425
- const response = await session.run(
426
- finalText,
427
- finalImageData,
428
- fileDataInput,
429
- stream
430
- );
431
- this.sessionManager.incrementMessageCount(session.id).catch(
432
- (error) => this.logger.warn(
433
- `Failed to increment message count: ${error instanceof Error ? error.message : String(error)}`
434
- )
435
- );
436
- return response;
437
- } catch (error) {
438
- this.logger.error(
439
- `Error during DextoAgent.run: ${error instanceof Error ? error.message : JSON.stringify(error)}`
440
- );
441
- throw error;
442
- }
443
- });
348
+ const response = await this.generate(parts.length > 0 ? parts : textInput, sessionId);
349
+ return response.content;
444
350
  }
445
351
  /**
446
352
  * Generate a complete response (waits for full completion).
447
353
  * This is the recommended method for non-streaming use cases.
448
354
  *
449
- * @param message The user's message
450
- * @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)
451
358
  * @returns Promise that resolves to the complete response
452
359
  *
453
360
  * @example
454
361
  * ```typescript
455
- * 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');
456
364
  * console.log(response.content); // "4"
457
- * 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
+ * );
458
374
  * ```
459
375
  */
460
- async generate(message, options) {
376
+ async generate(content, sessionId, options) {
461
377
  const events = [];
462
- for await (const event of await this.stream(message, options)) {
378
+ for await (const event of await this.stream(content, sessionId, options)) {
463
379
  events.push(event);
464
380
  }
465
- const errorEvent = events.find(
466
- (e) => e.name === "llm:error"
381
+ const fatalErrorEvent = events.find(
382
+ (e) => e.name === "llm:error" && e.recoverable !== true
467
383
  );
468
- if (errorEvent) {
469
- if (errorEvent.error instanceof DextoRuntimeError) {
470
- throw errorEvent.error;
384
+ if (fatalErrorEvent) {
385
+ if (fatalErrorEvent.error instanceof DextoRuntimeError || fatalErrorEvent.error instanceof DextoValidationError) {
386
+ throw fatalErrorEvent.error;
471
387
  }
472
- const llmConfig = this.stateManager.getLLMConfig(options.sessionId);
388
+ const llmConfig = this.stateManager.getLLMConfig(sessionId);
473
389
  throw LLMError.generationFailed(
474
- errorEvent.error.message,
390
+ fatalErrorEvent.error.message,
475
391
  llmConfig.provider,
476
392
  llmConfig.model
477
393
  );
478
394
  }
479
395
  const responseEvent = events.find((e) => e.name === "llm:response");
480
396
  if (!responseEvent || responseEvent.name !== "llm:response") {
481
- const llmConfig = this.stateManager.getLLMConfig(options.sessionId);
397
+ const llmConfig = this.stateManager.getLLMConfig(sessionId);
482
398
  throw LLMError.generationFailed(
483
399
  "Stream did not complete successfully - no response received",
484
400
  llmConfig.provider,
@@ -514,7 +430,7 @@ Either:
514
430
  reasoning: responseEvent.reasoning,
515
431
  usage,
516
432
  toolCalls,
517
- sessionId: options.sessionId
433
+ sessionId
518
434
  };
519
435
  }
520
436
  /**
@@ -528,36 +444,38 @@ Either:
528
444
  * Events are forwarded directly from the AgentEventBus with no mapping layer,
529
445
  * providing a unified event system across all API layers.
530
446
  *
531
- * @param message The user's message
532
- * @param options Configuration options (sessionId is required, imageData, fileData, signal are optional)
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)
533
450
  * @returns AsyncIterator that yields StreamingEvent objects (core events with name property)
534
451
  *
535
452
  * @example
536
453
  * ```typescript
537
- * for await (const event of await agent.stream("Write a poem", { sessionId: "default" })) {
538
- * if (event.name === 'llm:chunk') {
539
- * process.stdout.write(event.content);
540
- * }
541
- * if (event.name === 'llm:tool-call') {
542
- * console.log(`\n[Using ${event.toolName}]\n`);
543
- * }
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);
544
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
+ * )) { ... }
545
464
  * ```
546
465
  */
547
- async stream(message, options) {
466
+ async stream(content, sessionId, options) {
548
467
  this.ensureStarted();
549
- if (!options.sessionId) {
550
- throw new Error("sessionId is required in StreamOptions");
468
+ if (!sessionId) {
469
+ throw AgentError.apiValidationError("sessionId is required");
551
470
  }
552
- const sessionId = options.sessionId;
553
- const imageData = options.imageData;
554
- const fileData = options.fileData;
555
- const signal = options.signal;
471
+ const signal = options?.signal;
472
+ let contentParts = typeof content === "string" ? [{ type: "text", text: content }] : [...content];
556
473
  const eventQueue = [];
557
474
  let completed = false;
558
- let _streamError = null;
559
475
  const controller = new AbortController();
560
476
  const cleanupSignal = controller.signal;
477
+ this.activeStreamControllers.set(sessionId, controller);
478
+ setMaxListeners(30, cleanupSignal);
561
479
  const listeners = [];
562
480
  const cleanupListeners = () => {
563
481
  if (listeners.length === 0) {
@@ -570,6 +488,7 @@ Either:
570
488
  );
571
489
  }
572
490
  listeners.length = 0;
491
+ this.activeStreamControllers.delete(sessionId);
573
492
  };
574
493
  if (signal) {
575
494
  const abortHandler = () => {
@@ -593,7 +512,6 @@ Either:
593
512
  const responseListener = (data) => {
594
513
  if (data.sessionId !== sessionId) return;
595
514
  eventQueue.push({ name: "llm:response", ...data });
596
- completed = true;
597
515
  };
598
516
  this.agentEventBus.on("llm:response", responseListener, { signal: cleanupSignal });
599
517
  listeners.push({ event: "llm:response", listener: responseListener });
@@ -650,34 +568,191 @@ Either:
650
568
  signal: cleanupSignal
651
569
  });
652
570
  listeners.push({ event: "approval:response", listener: approvalResponseListener });
653
- const imageDataForRun = imageData ? {
654
- image: typeof imageData.image === "string" ? imageData.image : imageData.image.toString(),
655
- mimeType: imageData.mimeType || "image/png"
656
- } : void 0;
657
- const fileDataForRun = fileData ? {
658
- data: typeof fileData.data === "string" ? fileData.data : fileData.data.toString(),
659
- mimeType: fileData.mimeType,
660
- ...fileData.filename && { filename: fileData.filename }
661
- } : void 0;
662
- this.run(message, imageDataForRun, fileDataForRun, sessionId, true).catch((err) => {
663
- const error = err instanceof Error ? err : new Error(String(err));
664
- _streamError = error;
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 });
665
598
  completed = true;
666
- this.logger.error(`Error in DextoAgent.stream: ${error.message}`);
667
- const errorEvent = {
668
- name: "llm:error",
669
- error,
670
- recoverable: false,
671
- context: "run_failed",
672
- sessionId
673
- };
674
- eventQueue.push(errorEvent);
599
+ };
600
+ this.agentEventBus.on("run:complete", runCompleteListener, {
601
+ signal: cleanupSignal
675
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)
621
+ );
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
+ }
749
+ });
750
+ })();
676
751
  const iterator = {
677
752
  async next() {
678
753
  while (!completed && eventQueue.length === 0) {
679
754
  await new Promise((resolve) => setTimeout(resolve, 0));
680
- if (signal?.aborted) {
755
+ if (signal?.aborted || cleanupSignal.aborted) {
681
756
  cleanupListeners();
682
757
  controller.abort();
683
758
  return { done: true, value: void 0 };
@@ -705,6 +780,73 @@ Either:
705
780
  };
706
781
  return iterator;
707
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
+ }
708
850
  /**
709
851
  * Cancels the currently running turn for a session.
710
852
  * Safe to call even if no run is in progress.
@@ -714,13 +856,20 @@ Either:
714
856
  async cancel(sessionId) {
715
857
  this.ensureStarted();
716
858
  if (!sessionId || typeof sessionId !== "string") {
717
- 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);
718
867
  }
719
868
  const existing = await this.sessionManager.getSession(sessionId, false);
720
869
  if (existing) {
721
870
  return existing.cancel();
722
871
  }
723
- return false;
872
+ return !!streamController;
724
873
  }
725
874
  // ============= SESSION MANAGEMENT =============
726
875
  /**
@@ -827,7 +976,6 @@ Either:
827
976
  const llmConfig = this.getEffectiveConfig(sessionId).llm;
828
977
  const result = await generateSessionTitle(
829
978
  llmConfig,
830
- llmConfig.router,
831
979
  this.toolManager,
832
980
  this.systemPromptManager,
833
981
  this.resourceManager,
@@ -910,7 +1058,9 @@ Either:
910
1058
  async resetConversation(sessionId) {
911
1059
  this.ensureStarted();
912
1060
  if (!sessionId || typeof sessionId !== "string") {
913
- 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
+ );
914
1064
  }
915
1065
  try {
916
1066
  await this.sessionManager.resetSession(sessionId);
@@ -925,6 +1075,37 @@ Either:
925
1075
  throw error;
926
1076
  }
927
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
+ }
928
1109
  // ============= LLM MANAGEMENT =============
929
1110
  /**
930
1111
  * Gets the current LLM configuration with all defaults applied.
@@ -939,7 +1120,7 @@ Either:
939
1120
  * This is a comprehensive method that handles ALL validation, configuration building, and switching internally.
940
1121
  *
941
1122
  * Design:
942
- * - Input: Partial<LLMConfig> (allows optional fields like maxIterations?, router?)
1123
+ * - Input: Partial<LLMConfig> (allows optional fields like maxIterations?)
943
1124
  * - Output: LLMConfig (user-friendly type with all defaults applied)
944
1125
  *
945
1126
  * Key features:
@@ -964,8 +1145,8 @@ Either:
964
1145
  * // Switch to a different provider with explicit API key
965
1146
  * await agent.switchLLM({ provider: 'anthropic', model: 'claude-4-sonnet-20250514', apiKey: 'sk-ant-...' });
966
1147
  *
967
- * // Switch with router and session options
968
- * 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');
969
1150
  *
970
1151
  * // Switch for all sessions
971
1152
  * await agent.switchLLM({ model: 'gpt-5' }, '*');
@@ -1117,19 +1298,23 @@ Either:
1117
1298
  }
1118
1299
  // ============= MCP SERVER MANAGEMENT =============
1119
1300
  /**
1120
- * 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.
1121
1302
  * This method handles validation, state management, and establishing the connection.
1122
1303
  *
1123
- * @param name The name of the server to connect.
1304
+ * @param name The name of the server to add.
1124
1305
  * @param config The configuration object for the server.
1125
1306
  * @throws DextoError if validation fails or connection fails
1126
1307
  */
1127
- async connectMcpServer(name, config) {
1308
+ async addMcpServer(name, config) {
1128
1309
  this.ensureStarted();
1129
1310
  const existingServerNames = Object.keys(this.stateManager.getRuntimeConfig().mcpServers);
1130
1311
  const validation = resolveAndValidateMcpServerConfig(name, config, existingServerNames);
1131
1312
  const validatedConfig = ensureOk(validation, this.logger);
1132
- 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
+ }
1133
1318
  try {
1134
1319
  await this.mcpManager.connectServer(name, validatedConfig);
1135
1320
  await this.toolManager.refresh();
@@ -1141,9 +1326,7 @@ Either:
1141
1326
  tools: Object.keys(await this.toolManager.getAllTools()),
1142
1327
  source: "mcp"
1143
1328
  });
1144
- this.logger.info(
1145
- `DextoAgent: Successfully added and connected to MCP server '${name}'.`
1146
- );
1329
+ this.logger.info(`MCP server '${name}' added and connected successfully`);
1147
1330
  const warnings = validation.issues.filter((i) => i.severity === "warning");
1148
1331
  if (warnings.length > 0) {
1149
1332
  this.logger.warn(
@@ -1152,9 +1335,7 @@ Either:
1152
1335
  }
1153
1336
  } catch (error) {
1154
1337
  const errorMessage = error instanceof Error ? error.message : String(error);
1155
- this.logger.error(
1156
- `DextoAgent: Failed to connect to MCP server '${name}': ${errorMessage}`
1157
- );
1338
+ this.logger.error(`Failed to connect MCP server '${name}': ${errorMessage}`);
1158
1339
  this.stateManager.removeMcpServer(name);
1159
1340
  this.agentEventBus.emit("mcp:server-connected", {
1160
1341
  name,
@@ -1165,14 +1346,81 @@ Either:
1165
1346
  }
1166
1347
  }
1167
1348
  /**
1168
- * 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.
1169
1410
  * @param name The name of the server to remove.
1411
+ * @throws MCPError if disconnection fails
1170
1412
  */
1171
1413
  async removeMcpServer(name) {
1172
1414
  this.ensureStarted();
1173
- await this.mcpManager.removeClient(name);
1174
- this.stateManager.removeMcpServer(name);
1175
- 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
+ }
1176
1424
  }
1177
1425
  /**
1178
1426
  * Restarts an MCP server by disconnecting and reconnecting with its original configuration.
@@ -1205,13 +1453,18 @@ Either:
1205
1453
  /**
1206
1454
  * Executes a tool from any source (MCP servers, custom tools, or internal tools).
1207
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
+ *
1208
1460
  * @param toolName The name of the tool to execute
1209
1461
  * @param args The arguments to pass to the tool
1210
1462
  * @returns The result of the tool execution
1211
1463
  */
1212
1464
  async executeTool(toolName, args) {
1213
1465
  this.ensureStarted();
1214
- return await this.toolManager.executeTool(toolName, args);
1466
+ const toolCallId = `direct-${randomUUID()}`;
1467
+ return await this.toolManager.executeTool(toolName, args, toolCallId);
1215
1468
  }
1216
1469
  /**
1217
1470
  * Gets all available tools from all connected MCP servers.
@@ -1249,6 +1502,79 @@ Either:
1249
1502
  this.ensureStarted();
1250
1503
  return this.mcpManager.getFailedConnections();
1251
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
+ }
1252
1578
  // ============= RESOURCE MANAGEMENT =============
1253
1579
  /**
1254
1580
  * Lists all available resources with their info.
@@ -1344,6 +1670,21 @@ Either:
1344
1670
  this.ensureStarted();
1345
1671
  return await this.promptManager.has(name);
1346
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
+ }
1347
1688
  /**
1348
1689
  * Gets a prompt with its messages.
1349
1690
  * @param name The name of the prompt