@falai/agent 2.2.4 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (390) hide show
  1. package/README.md +2 -2
  2. package/dist/adapters/MemoryAdapter.d.ts.map +1 -1
  3. package/dist/adapters/MemoryAdapter.js +10 -1
  4. package/dist/adapters/MemoryAdapter.js.map +1 -1
  5. package/dist/adapters/MongoAdapter.d.ts.map +1 -1
  6. package/dist/adapters/MongoAdapter.js +33 -2
  7. package/dist/adapters/MongoAdapter.js.map +1 -1
  8. package/dist/adapters/OpenSearchAdapter.d.ts.map +1 -1
  9. package/dist/adapters/OpenSearchAdapter.js +15 -1
  10. package/dist/adapters/OpenSearchAdapter.js.map +1 -1
  11. package/dist/adapters/PostgreSQLAdapter.d.ts.map +1 -1
  12. package/dist/adapters/PostgreSQLAdapter.js +35 -5
  13. package/dist/adapters/PostgreSQLAdapter.js.map +1 -1
  14. package/dist/adapters/PrismaAdapter.d.ts.map +1 -1
  15. package/dist/adapters/PrismaAdapter.js +58 -15
  16. package/dist/adapters/PrismaAdapter.js.map +1 -1
  17. package/dist/adapters/RedisAdapter.d.ts.map +1 -1
  18. package/dist/adapters/RedisAdapter.js +10 -1
  19. package/dist/adapters/RedisAdapter.js.map +1 -1
  20. package/dist/adapters/SQLiteAdapter.d.ts.map +1 -1
  21. package/dist/adapters/SQLiteAdapter.js +38 -6
  22. package/dist/adapters/SQLiteAdapter.js.map +1 -1
  23. package/dist/cjs/adapters/MemoryAdapter.d.ts.map +1 -1
  24. package/dist/cjs/adapters/MemoryAdapter.js +10 -1
  25. package/dist/cjs/adapters/MemoryAdapter.js.map +1 -1
  26. package/dist/cjs/adapters/MongoAdapter.d.ts.map +1 -1
  27. package/dist/cjs/adapters/MongoAdapter.js +33 -2
  28. package/dist/cjs/adapters/MongoAdapter.js.map +1 -1
  29. package/dist/cjs/adapters/OpenSearchAdapter.d.ts.map +1 -1
  30. package/dist/cjs/adapters/OpenSearchAdapter.js +15 -1
  31. package/dist/cjs/adapters/OpenSearchAdapter.js.map +1 -1
  32. package/dist/cjs/adapters/PostgreSQLAdapter.d.ts.map +1 -1
  33. package/dist/cjs/adapters/PostgreSQLAdapter.js +35 -5
  34. package/dist/cjs/adapters/PostgreSQLAdapter.js.map +1 -1
  35. package/dist/cjs/adapters/PrismaAdapter.d.ts.map +1 -1
  36. package/dist/cjs/adapters/PrismaAdapter.js +58 -15
  37. package/dist/cjs/adapters/PrismaAdapter.js.map +1 -1
  38. package/dist/cjs/adapters/RedisAdapter.d.ts.map +1 -1
  39. package/dist/cjs/adapters/RedisAdapter.js +10 -1
  40. package/dist/cjs/adapters/RedisAdapter.js.map +1 -1
  41. package/dist/cjs/adapters/SQLiteAdapter.d.ts.map +1 -1
  42. package/dist/cjs/adapters/SQLiteAdapter.js +38 -6
  43. package/dist/cjs/adapters/SQLiteAdapter.js.map +1 -1
  44. package/dist/cjs/core/Agent.d.ts +28 -18
  45. package/dist/cjs/core/Agent.d.ts.map +1 -1
  46. package/dist/cjs/core/Agent.js +58 -68
  47. package/dist/cjs/core/Agent.js.map +1 -1
  48. package/dist/cjs/core/AutoChainExecutor.d.ts.map +1 -1
  49. package/dist/cjs/core/AutoChainExecutor.js +14 -20
  50. package/dist/cjs/core/AutoChainExecutor.js.map +1 -1
  51. package/dist/cjs/core/BranchEvaluator.d.ts +4 -3
  52. package/dist/cjs/core/BranchEvaluator.d.ts.map +1 -1
  53. package/dist/cjs/core/BranchEvaluator.js +18 -23
  54. package/dist/cjs/core/BranchEvaluator.js.map +1 -1
  55. package/dist/cjs/core/Flow.d.ts +2 -1
  56. package/dist/cjs/core/Flow.d.ts.map +1 -1
  57. package/dist/cjs/core/Flow.js +10 -3
  58. package/dist/cjs/core/Flow.js.map +1 -1
  59. package/dist/cjs/core/FlowRouter.d.ts +1 -0
  60. package/dist/cjs/core/FlowRouter.d.ts.map +1 -1
  61. package/dist/cjs/core/FlowRouter.js +28 -5
  62. package/dist/cjs/core/FlowRouter.js.map +1 -1
  63. package/dist/cjs/core/PersistenceManager.d.ts +3 -0
  64. package/dist/cjs/core/PersistenceManager.d.ts.map +1 -1
  65. package/dist/cjs/core/PersistenceManager.js +57 -5
  66. package/dist/cjs/core/PersistenceManager.js.map +1 -1
  67. package/dist/cjs/core/PromptComposer.d.ts.map +1 -1
  68. package/dist/cjs/core/PromptComposer.js +24 -10
  69. package/dist/cjs/core/PromptComposer.js.map +1 -1
  70. package/dist/cjs/core/ResponseGenerationError.d.ts +30 -0
  71. package/dist/cjs/core/ResponseGenerationError.d.ts.map +1 -0
  72. package/dist/cjs/core/ResponseGenerationError.js +37 -0
  73. package/dist/cjs/core/ResponseGenerationError.js.map +1 -0
  74. package/dist/cjs/core/ResponseModal.d.ts +43 -102
  75. package/dist/cjs/core/ResponseModal.d.ts.map +1 -1
  76. package/dist/cjs/core/ResponseModal.js +178 -1194
  77. package/dist/cjs/core/ResponseModal.js.map +1 -1
  78. package/dist/cjs/core/ResponsePipeline.d.ts +58 -152
  79. package/dist/cjs/core/ResponsePipeline.d.ts.map +1 -1
  80. package/dist/cjs/core/ResponsePipeline.js +408 -457
  81. package/dist/cjs/core/ResponsePipeline.js.map +1 -1
  82. package/dist/cjs/core/SessionFinalizer.d.ts +34 -0
  83. package/dist/cjs/core/SessionFinalizer.d.ts.map +1 -0
  84. package/dist/cjs/core/SessionFinalizer.js +61 -0
  85. package/dist/cjs/core/SessionFinalizer.js.map +1 -0
  86. package/dist/cjs/core/SessionManager.d.ts +1 -1
  87. package/dist/cjs/core/SessionManager.d.ts.map +1 -1
  88. package/dist/cjs/core/SessionManager.js +18 -7
  89. package/dist/cjs/core/SessionManager.js.map +1 -1
  90. package/dist/cjs/core/SignalCoordinator.d.ts +103 -0
  91. package/dist/cjs/core/SignalCoordinator.d.ts.map +1 -0
  92. package/dist/cjs/core/SignalCoordinator.js +207 -0
  93. package/dist/cjs/core/SignalCoordinator.js.map +1 -0
  94. package/dist/cjs/core/SignalEvaluator.d.ts +2 -2
  95. package/dist/cjs/core/SignalEvaluator.d.ts.map +1 -1
  96. package/dist/cjs/core/SignalEvaluator.js +11 -26
  97. package/dist/cjs/core/SignalEvaluator.js.map +1 -1
  98. package/dist/cjs/core/Step.d.ts +3 -1
  99. package/dist/cjs/core/Step.d.ts.map +1 -1
  100. package/dist/cjs/core/Step.js +10 -3
  101. package/dist/cjs/core/Step.js.map +1 -1
  102. package/dist/cjs/core/StepLifecycle.d.ts +33 -0
  103. package/dist/cjs/core/StepLifecycle.d.ts.map +1 -0
  104. package/dist/cjs/core/StepLifecycle.js +97 -0
  105. package/dist/cjs/core/StepLifecycle.js.map +1 -0
  106. package/dist/cjs/core/ToolLoopExecutor.d.ts +104 -0
  107. package/dist/cjs/core/ToolLoopExecutor.d.ts.map +1 -0
  108. package/dist/cjs/core/ToolLoopExecutor.js +391 -0
  109. package/dist/cjs/core/ToolLoopExecutor.js.map +1 -0
  110. package/dist/cjs/core/ToolManager.d.ts +1 -1
  111. package/dist/cjs/core/ToolManager.d.ts.map +1 -1
  112. package/dist/cjs/core/ToolManager.js.map +1 -1
  113. package/dist/cjs/index.d.ts +4 -5
  114. package/dist/cjs/index.d.ts.map +1 -1
  115. package/dist/cjs/index.js +7 -6
  116. package/dist/cjs/index.js.map +1 -1
  117. package/dist/cjs/providers/AnthropicProvider.d.ts +2 -0
  118. package/dist/cjs/providers/AnthropicProvider.d.ts.map +1 -1
  119. package/dist/cjs/providers/AnthropicProvider.js +28 -56
  120. package/dist/cjs/providers/AnthropicProvider.js.map +1 -1
  121. package/dist/cjs/providers/DeepSeekProvider.d.ts +25 -21
  122. package/dist/cjs/providers/DeepSeekProvider.d.ts.map +1 -1
  123. package/dist/cjs/providers/DeepSeekProvider.js +48 -407
  124. package/dist/cjs/providers/DeepSeekProvider.js.map +1 -1
  125. package/dist/cjs/providers/GeminiProvider.d.ts +2 -0
  126. package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
  127. package/dist/cjs/providers/GeminiProvider.js +27 -56
  128. package/dist/cjs/providers/GeminiProvider.js.map +1 -1
  129. package/dist/cjs/providers/OpenAICompatibleProvider.d.ts +129 -0
  130. package/dist/cjs/providers/OpenAICompatibleProvider.d.ts.map +1 -0
  131. package/dist/cjs/providers/OpenAICompatibleProvider.js +485 -0
  132. package/dist/cjs/providers/OpenAICompatibleProvider.js.map +1 -0
  133. package/dist/cjs/providers/OpenAIProvider.d.ts +9 -28
  134. package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
  135. package/dist/cjs/providers/OpenAIProvider.js +23 -417
  136. package/dist/cjs/providers/OpenAIProvider.js.map +1 -1
  137. package/dist/cjs/providers/OpenRouterProvider.d.ts +10 -27
  138. package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
  139. package/dist/cjs/providers/OpenRouterProvider.js +28 -417
  140. package/dist/cjs/providers/OpenRouterProvider.js.map +1 -1
  141. package/dist/cjs/providers/errorClassification.d.ts +61 -0
  142. package/dist/cjs/providers/errorClassification.d.ts.map +1 -0
  143. package/dist/cjs/providers/errorClassification.js +123 -0
  144. package/dist/cjs/providers/errorClassification.js.map +1 -0
  145. package/dist/cjs/providers/index.d.ts +4 -0
  146. package/dist/cjs/providers/index.d.ts.map +1 -1
  147. package/dist/cjs/providers/index.js +7 -1
  148. package/dist/cjs/providers/index.js.map +1 -1
  149. package/dist/cjs/types/agent.d.ts +2 -1
  150. package/dist/cjs/types/agent.d.ts.map +1 -1
  151. package/dist/cjs/types/ai.d.ts +20 -0
  152. package/dist/cjs/types/ai.d.ts.map +1 -1
  153. package/dist/cjs/types/errors.d.ts +33 -0
  154. package/dist/cjs/types/errors.d.ts.map +1 -1
  155. package/dist/cjs/types/errors.js +37 -1
  156. package/dist/cjs/types/errors.js.map +1 -1
  157. package/dist/cjs/types/flow.d.ts +10 -5
  158. package/dist/cjs/types/flow.d.ts.map +1 -1
  159. package/dist/cjs/types/history.d.ts +1 -1
  160. package/dist/cjs/types/history.d.ts.map +1 -1
  161. package/dist/cjs/types/index.d.ts +5 -4
  162. package/dist/cjs/types/index.d.ts.map +1 -1
  163. package/dist/cjs/types/index.js +3 -1
  164. package/dist/cjs/types/index.js.map +1 -1
  165. package/dist/cjs/types/persistence.d.ts +43 -2
  166. package/dist/cjs/types/persistence.d.ts.map +1 -1
  167. package/dist/cjs/types/session.d.ts +8 -0
  168. package/dist/cjs/types/session.d.ts.map +1 -1
  169. package/dist/cjs/types/signals.d.ts +12 -2
  170. package/dist/cjs/types/signals.d.ts.map +1 -1
  171. package/dist/cjs/types/template.d.ts +3 -1
  172. package/dist/cjs/types/template.d.ts.map +1 -1
  173. package/dist/cjs/types/tool.d.ts +4 -4
  174. package/dist/cjs/types/tool.d.ts.map +1 -1
  175. package/dist/cjs/utils/condition.d.ts +19 -0
  176. package/dist/cjs/utils/condition.d.ts.map +1 -1
  177. package/dist/cjs/utils/condition.js +86 -15
  178. package/dist/cjs/utils/condition.js.map +1 -1
  179. package/dist/cjs/utils/session.d.ts +1 -0
  180. package/dist/cjs/utils/session.d.ts.map +1 -1
  181. package/dist/cjs/utils/session.js +1 -0
  182. package/dist/cjs/utils/session.js.map +1 -1
  183. package/dist/core/Agent.d.ts +28 -18
  184. package/dist/core/Agent.d.ts.map +1 -1
  185. package/dist/core/Agent.js +58 -68
  186. package/dist/core/Agent.js.map +1 -1
  187. package/dist/core/AutoChainExecutor.d.ts.map +1 -1
  188. package/dist/core/AutoChainExecutor.js +14 -20
  189. package/dist/core/AutoChainExecutor.js.map +1 -1
  190. package/dist/core/BranchEvaluator.d.ts +4 -3
  191. package/dist/core/BranchEvaluator.d.ts.map +1 -1
  192. package/dist/core/BranchEvaluator.js +18 -23
  193. package/dist/core/BranchEvaluator.js.map +1 -1
  194. package/dist/core/Flow.d.ts +2 -1
  195. package/dist/core/Flow.d.ts.map +1 -1
  196. package/dist/core/Flow.js +10 -3
  197. package/dist/core/Flow.js.map +1 -1
  198. package/dist/core/FlowRouter.d.ts +1 -0
  199. package/dist/core/FlowRouter.d.ts.map +1 -1
  200. package/dist/core/FlowRouter.js +28 -5
  201. package/dist/core/FlowRouter.js.map +1 -1
  202. package/dist/core/PersistenceManager.d.ts +3 -0
  203. package/dist/core/PersistenceManager.d.ts.map +1 -1
  204. package/dist/core/PersistenceManager.js +58 -6
  205. package/dist/core/PersistenceManager.js.map +1 -1
  206. package/dist/core/PromptComposer.d.ts.map +1 -1
  207. package/dist/core/PromptComposer.js +24 -10
  208. package/dist/core/PromptComposer.js.map +1 -1
  209. package/dist/core/ResponseGenerationError.d.ts +30 -0
  210. package/dist/core/ResponseGenerationError.d.ts.map +1 -0
  211. package/dist/core/ResponseGenerationError.js +33 -0
  212. package/dist/core/ResponseGenerationError.js.map +1 -0
  213. package/dist/core/ResponseModal.d.ts +43 -102
  214. package/dist/core/ResponseModal.d.ts.map +1 -1
  215. package/dist/core/ResponseModal.js +171 -1186
  216. package/dist/core/ResponseModal.js.map +1 -1
  217. package/dist/core/ResponsePipeline.d.ts +58 -152
  218. package/dist/core/ResponsePipeline.d.ts.map +1 -1
  219. package/dist/core/ResponsePipeline.js +409 -458
  220. package/dist/core/ResponsePipeline.js.map +1 -1
  221. package/dist/core/SessionFinalizer.d.ts +34 -0
  222. package/dist/core/SessionFinalizer.d.ts.map +1 -0
  223. package/dist/core/SessionFinalizer.js +57 -0
  224. package/dist/core/SessionFinalizer.js.map +1 -0
  225. package/dist/core/SessionManager.d.ts +1 -1
  226. package/dist/core/SessionManager.d.ts.map +1 -1
  227. package/dist/core/SessionManager.js +18 -7
  228. package/dist/core/SessionManager.js.map +1 -1
  229. package/dist/core/SignalCoordinator.d.ts +103 -0
  230. package/dist/core/SignalCoordinator.d.ts.map +1 -0
  231. package/dist/core/SignalCoordinator.js +203 -0
  232. package/dist/core/SignalCoordinator.js.map +1 -0
  233. package/dist/core/SignalEvaluator.d.ts +2 -2
  234. package/dist/core/SignalEvaluator.d.ts.map +1 -1
  235. package/dist/core/SignalEvaluator.js +11 -26
  236. package/dist/core/SignalEvaluator.js.map +1 -1
  237. package/dist/core/Step.d.ts +3 -1
  238. package/dist/core/Step.d.ts.map +1 -1
  239. package/dist/core/Step.js +10 -3
  240. package/dist/core/Step.js.map +1 -1
  241. package/dist/core/StepLifecycle.d.ts +33 -0
  242. package/dist/core/StepLifecycle.d.ts.map +1 -0
  243. package/dist/core/StepLifecycle.js +93 -0
  244. package/dist/core/StepLifecycle.js.map +1 -0
  245. package/dist/core/ToolLoopExecutor.d.ts +104 -0
  246. package/dist/core/ToolLoopExecutor.d.ts.map +1 -0
  247. package/dist/core/ToolLoopExecutor.js +387 -0
  248. package/dist/core/ToolLoopExecutor.js.map +1 -0
  249. package/dist/core/ToolManager.d.ts +1 -1
  250. package/dist/core/ToolManager.d.ts.map +1 -1
  251. package/dist/core/ToolManager.js.map +1 -1
  252. package/dist/index.d.ts +4 -5
  253. package/dist/index.d.ts.map +1 -1
  254. package/dist/index.js +3 -3
  255. package/dist/index.js.map +1 -1
  256. package/dist/providers/AnthropicProvider.d.ts +2 -0
  257. package/dist/providers/AnthropicProvider.d.ts.map +1 -1
  258. package/dist/providers/AnthropicProvider.js +22 -50
  259. package/dist/providers/AnthropicProvider.js.map +1 -1
  260. package/dist/providers/DeepSeekProvider.d.ts +25 -21
  261. package/dist/providers/DeepSeekProvider.d.ts.map +1 -1
  262. package/dist/providers/DeepSeekProvider.js +49 -408
  263. package/dist/providers/DeepSeekProvider.js.map +1 -1
  264. package/dist/providers/GeminiProvider.d.ts +2 -0
  265. package/dist/providers/GeminiProvider.d.ts.map +1 -1
  266. package/dist/providers/GeminiProvider.js +21 -50
  267. package/dist/providers/GeminiProvider.js.map +1 -1
  268. package/dist/providers/OpenAICompatibleProvider.d.ts +129 -0
  269. package/dist/providers/OpenAICompatibleProvider.d.ts.map +1 -0
  270. package/dist/providers/OpenAICompatibleProvider.js +481 -0
  271. package/dist/providers/OpenAICompatibleProvider.js.map +1 -0
  272. package/dist/providers/OpenAIProvider.d.ts +9 -28
  273. package/dist/providers/OpenAIProvider.d.ts.map +1 -1
  274. package/dist/providers/OpenAIProvider.js +23 -417
  275. package/dist/providers/OpenAIProvider.js.map +1 -1
  276. package/dist/providers/OpenRouterProvider.d.ts +10 -27
  277. package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
  278. package/dist/providers/OpenRouterProvider.js +28 -417
  279. package/dist/providers/OpenRouterProvider.js.map +1 -1
  280. package/dist/providers/errorClassification.d.ts +61 -0
  281. package/dist/providers/errorClassification.d.ts.map +1 -0
  282. package/dist/providers/errorClassification.js +116 -0
  283. package/dist/providers/errorClassification.js.map +1 -0
  284. package/dist/providers/index.d.ts +4 -0
  285. package/dist/providers/index.d.ts.map +1 -1
  286. package/dist/providers/index.js +2 -0
  287. package/dist/providers/index.js.map +1 -1
  288. package/dist/types/agent.d.ts +2 -1
  289. package/dist/types/agent.d.ts.map +1 -1
  290. package/dist/types/ai.d.ts +20 -0
  291. package/dist/types/ai.d.ts.map +1 -1
  292. package/dist/types/errors.d.ts +33 -0
  293. package/dist/types/errors.d.ts.map +1 -1
  294. package/dist/types/errors.js +34 -0
  295. package/dist/types/errors.js.map +1 -1
  296. package/dist/types/flow.d.ts +10 -5
  297. package/dist/types/flow.d.ts.map +1 -1
  298. package/dist/types/history.d.ts +1 -1
  299. package/dist/types/history.d.ts.map +1 -1
  300. package/dist/types/index.d.ts +5 -4
  301. package/dist/types/index.d.ts.map +1 -1
  302. package/dist/types/index.js +1 -1
  303. package/dist/types/index.js.map +1 -1
  304. package/dist/types/persistence.d.ts +43 -2
  305. package/dist/types/persistence.d.ts.map +1 -1
  306. package/dist/types/session.d.ts +8 -0
  307. package/dist/types/session.d.ts.map +1 -1
  308. package/dist/types/signals.d.ts +12 -2
  309. package/dist/types/signals.d.ts.map +1 -1
  310. package/dist/types/template.d.ts +3 -1
  311. package/dist/types/template.d.ts.map +1 -1
  312. package/dist/types/tool.d.ts +4 -4
  313. package/dist/types/tool.d.ts.map +1 -1
  314. package/dist/utils/condition.d.ts +19 -0
  315. package/dist/utils/condition.d.ts.map +1 -1
  316. package/dist/utils/condition.js +84 -15
  317. package/dist/utils/condition.js.map +1 -1
  318. package/dist/utils/session.d.ts +1 -0
  319. package/dist/utils/session.d.ts.map +1 -1
  320. package/dist/utils/session.js +1 -0
  321. package/dist/utils/session.js.map +1 -1
  322. package/docs/README.md +1 -1
  323. package/docs/guides/branching.md +1 -1
  324. package/docs/guides/compaction.md +12 -5
  325. package/docs/guides/conditions.md +15 -2
  326. package/docs/guides/error-handling.md +59 -9
  327. package/docs/guides/instructions.md +2 -2
  328. package/docs/guides/persistence.md +69 -2
  329. package/docs/guides/streaming.md +2 -0
  330. package/docs/migration/README.md +5 -1
  331. package/docs/migration/v2-3-to-v2-4.md +316 -0
  332. package/docs/reference/adapters.md +55 -7
  333. package/docs/reference/branches.md +2 -2
  334. package/docs/reference/create-agent.md +3 -3
  335. package/docs/reference/errors.md +66 -1
  336. package/docs/reference/flow.md +1 -1
  337. package/docs/reference/instruction.md +4 -4
  338. package/docs/reference/providers.md +100 -3
  339. package/docs/reference/signals.md +11 -3
  340. package/docs/reference/step.md +2 -2
  341. package/docs/reference/tool.md +3 -1
  342. package/docs/start/05-go-to-production.md +3 -0
  343. package/package.json +1 -1
  344. package/src/adapters/MemoryAdapter.ts +15 -1
  345. package/src/adapters/MongoAdapter.ts +41 -2
  346. package/src/adapters/OpenSearchAdapter.ts +24 -1
  347. package/src/adapters/PostgreSQLAdapter.ts +45 -5
  348. package/src/adapters/PrismaAdapter.ts +82 -16
  349. package/src/adapters/RedisAdapter.ts +19 -1
  350. package/src/adapters/SQLiteAdapter.ts +47 -5
  351. package/src/core/Agent.ts +70 -85
  352. package/src/core/AutoChainExecutor.ts +27 -57
  353. package/src/core/BranchEvaluator.ts +24 -30
  354. package/src/core/Flow.ts +10 -3
  355. package/src/core/FlowRouter.ts +36 -4
  356. package/src/core/PersistenceManager.ts +79 -10
  357. package/src/core/PromptComposer.ts +25 -12
  358. package/src/core/ResponseGenerationError.ts +56 -0
  359. package/src/core/ResponseModal.ts +233 -1482
  360. package/src/core/ResponsePipeline.ts +492 -662
  361. package/src/core/SessionFinalizer.ts +78 -0
  362. package/src/core/SessionManager.ts +21 -9
  363. package/src/core/SignalCoordinator.ts +263 -0
  364. package/src/core/SignalEvaluator.ts +12 -29
  365. package/src/core/Step.ts +11 -3
  366. package/src/core/StepLifecycle.ts +139 -0
  367. package/src/core/ToolLoopExecutor.ts +492 -0
  368. package/src/core/ToolManager.ts +2 -1
  369. package/src/index.ts +7 -5
  370. package/src/providers/AnthropicProvider.ts +30 -72
  371. package/src/providers/DeepSeekProvider.ts +74 -586
  372. package/src/providers/GeminiProvider.ts +29 -70
  373. package/src/providers/OpenAICompatibleProvider.ts +738 -0
  374. package/src/providers/OpenAIProvider.ts +29 -602
  375. package/src/providers/OpenRouterProvider.ts +38 -596
  376. package/src/providers/errorClassification.ts +172 -0
  377. package/src/providers/index.ts +13 -0
  378. package/src/types/agent.ts +2 -1
  379. package/src/types/ai.ts +22 -0
  380. package/src/types/errors.ts +57 -0
  381. package/src/types/flow.ts +10 -5
  382. package/src/types/history.ts +1 -2
  383. package/src/types/index.ts +5 -1
  384. package/src/types/persistence.ts +50 -2
  385. package/src/types/session.ts +9 -0
  386. package/src/types/signals.ts +14 -2
  387. package/src/types/template.ts +3 -1
  388. package/src/types/tool.ts +10 -10
  389. package/src/utils/condition.ts +115 -18
  390. package/src/utils/session.ts +2 -0
@@ -0,0 +1,738 @@
1
+ /**
2
+ * Shared base class for OpenAI-compatible chat-completions providers
3
+ * (OpenAI, DeepSeek, OpenRouter).
4
+ *
5
+ * Handles message/history building, tool-call parsing, streaming chunk
6
+ * handling, backup-model fallback, retry wiring, schema passthrough and
7
+ * normalized error wrapping. Subclasses supply the configured client,
8
+ * naming, capabilities and any genuinely provider-specific behavior via
9
+ * the protected hooks.
10
+ */
11
+
12
+ import OpenAI from "openai";
13
+ import type {
14
+ ChatCompletionChunk,
15
+ ChatCompletionCreateParamsNonStreaming,
16
+ ChatCompletionCreateParamsStreaming,
17
+ } from "openai/resources/chat/completions";
18
+ import { FunctionParameters } from "openai/resources/shared.mjs";
19
+
20
+ import type {
21
+ AiProvider,
22
+ GenerateMessageInput,
23
+ GenerateMessageOutput,
24
+ GenerateMessageStreamChunk,
25
+ AgentStructuredResponse,
26
+ StructuredSchema,
27
+ } from "../types";
28
+ import type { ProviderCapabilities } from "../types/ai";
29
+ import type { HistoryItem } from "../types/history";
30
+ import { withTimeoutAndRetry, logger } from "../utils";
31
+ import {
32
+ classifyProviderError,
33
+ getErrorMessage,
34
+ isBackupEligible,
35
+ toProviderError,
36
+ type ErrorClassificationOptions,
37
+ } from "./errorClassification";
38
+
39
+ const DEFAULT_RETRY_CONFIG = {
40
+ timeout: 60000,
41
+ retries: 3,
42
+ };
43
+
44
+ /**
45
+ * Default request parameters shared by OpenAI-compatible providers
46
+ */
47
+ export type OpenAICompatibleRequestConfig = Partial<
48
+ Omit<ChatCompletionCreateParamsNonStreaming, "model" | "messages">
49
+ >;
50
+
51
+ /**
52
+ * Initialization values supplied by subclasses
53
+ */
54
+ export interface OpenAICompatibleProviderInit {
55
+ /** Configured OpenAI SDK client (subclass sets API key, base URL, headers) */
56
+ client: OpenAI;
57
+ /** Primary model */
58
+ model: string;
59
+ /** Backup models to try if primary fails (default: []) */
60
+ backupModels?: string[];
61
+ /** Default request parameters */
62
+ config?: OpenAICompatibleRequestConfig;
63
+ /** Retry configuration */
64
+ retryConfig?: {
65
+ timeout?: number;
66
+ retries?: number;
67
+ };
68
+ }
69
+
70
+ /**
71
+ * Base implementation of AiProvider for OpenAI-compatible APIs with
72
+ * backup models and retry logic.
73
+ */
74
+ export abstract class OpenAICompatibleProvider implements AiProvider {
75
+ public abstract readonly name: string;
76
+ public abstract readonly capabilities: ProviderCapabilities;
77
+
78
+ /** Uppercase tag used in log lines, e.g. "OPENAI" */
79
+ protected abstract readonly logLabel: string;
80
+ /** Human-readable name used in retry/error messages, e.g. "OpenAI" */
81
+ protected abstract readonly displayName: string;
82
+
83
+ protected readonly client: OpenAI;
84
+ protected readonly primaryModel: string;
85
+ protected readonly backupModels: string[];
86
+ protected readonly config?: OpenAICompatibleRequestConfig;
87
+ protected readonly retryConfig: { timeout: number; retries: number };
88
+
89
+ /**
90
+ * Provider-specific error classification signals.
91
+ * model_not_found/model_overloaded historically triggered backup models.
92
+ */
93
+ protected readonly classificationOptions: ErrorClassificationOptions = {
94
+ overloadedCodes: ["model_not_found", "model_overloaded"],
95
+ };
96
+
97
+ protected constructor(init: OpenAICompatibleProviderInit) {
98
+ this.client = init.client;
99
+ this.primaryModel = init.model;
100
+ this.backupModels = init.backupModels ?? [];
101
+ this.config = init.config;
102
+ this.retryConfig = {
103
+ timeout: init.retryConfig?.timeout || DEFAULT_RETRY_CONFIG.timeout,
104
+ retries: init.retryConfig?.retries || DEFAULT_RETRY_CONFIG.retries,
105
+ };
106
+ }
107
+
108
+ // ---------------------------------------------------------------------
109
+ // Public API
110
+ // ---------------------------------------------------------------------
111
+
112
+ async generateMessage<
113
+ TContext = unknown,
114
+ TStructured = AgentStructuredResponse
115
+ >(
116
+ input: GenerateMessageInput<TContext>
117
+ ): Promise<GenerateMessageOutput<TStructured>> {
118
+ return this.generateWithBackup<TContext, TStructured>(input);
119
+ }
120
+
121
+ async *generateMessageStream<
122
+ TContext = unknown,
123
+ TStructured = AgentStructuredResponse
124
+ >(
125
+ input: GenerateMessageInput<TContext>
126
+ ): AsyncGenerator<GenerateMessageStreamChunk<TStructured>> {
127
+ yield* this.generateStreamWithBackup<TContext, TStructured>(input);
128
+ }
129
+
130
+ // ---------------------------------------------------------------------
131
+ // Provider-specific hooks
132
+ // ---------------------------------------------------------------------
133
+
134
+ /**
135
+ * Generate a structured (JSON schema) response. Default uses the
136
+ * responses.parse API (OpenAI, OpenRouter). Subclasses whose API lacks
137
+ * responses.parse (e.g. DeepSeek) override this to use chat completions
138
+ * with a structured response_format instead.
139
+ */
140
+ protected async executeStructuredGenerate(
141
+ model: string,
142
+ input: GenerateMessageInput<unknown>,
143
+ jsonSchema: StructuredSchema
144
+ ): Promise<GenerateMessageOutput> {
145
+ const response = await this.client.responses.parse({
146
+ model,
147
+ instructions: input.prompt,
148
+ input: "",
149
+ reasoning: {
150
+ effort: input.parameters?.reasoning?.effort || "low",
151
+ },
152
+ text: {
153
+ format: {
154
+ type: "json_schema",
155
+ name: input.parameters?.schemaName || "structured_output",
156
+ // Adapt common schema format to the provider's format
157
+ schema: this.adaptSchema(jsonSchema),
158
+ },
159
+ },
160
+ });
161
+
162
+ if (!response.output_parsed) {
163
+ throw new Error(`No parsed output returned from ${this.displayName}`);
164
+ }
165
+
166
+ const structured = response.output_parsed as AgentStructuredResponse;
167
+ const message = structured.message;
168
+
169
+ return {
170
+ message,
171
+ metadata: {
172
+ model: response.model,
173
+ tokensUsed: response.usage?.total_tokens,
174
+ promptTokens: response.usage?.input_tokens,
175
+ completionTokens: response.usage?.output_tokens,
176
+ },
177
+ structured,
178
+ };
179
+ }
180
+
181
+ /**
182
+ * response_format applied to chat-completions requests when a JSON
183
+ * schema is present. Default requests a generic JSON object (parsed at
184
+ * the end); subclasses with native json_schema support in chat
185
+ * completions (e.g. DeepSeek) override this.
186
+ */
187
+ protected structuredResponseFormat(
188
+ _jsonSchema: StructuredSchema,
189
+ _schemaName: string | undefined
190
+ ): ChatCompletionCreateParamsNonStreaming["response_format"] {
191
+ return { type: "json_object" };
192
+ }
193
+
194
+ /**
195
+ * Hook for provider-specific streaming request parameters
196
+ * (e.g. DeepSeek's stream_options.include_usage).
197
+ */
198
+ protected configureStreamParams(
199
+ _params: ChatCompletionCreateParamsStreaming
200
+ ): void {
201
+ // Default: no extra parameters
202
+ }
203
+
204
+ /**
205
+ * Hook for provider-specific stream delta handling
206
+ * (e.g. DeepSeek's reasoning_content).
207
+ */
208
+ protected onStreamDelta(_delta: ChatCompletionChunk.Choice.Delta): void {
209
+ // Default: no extra handling
210
+ }
211
+
212
+ // ---------------------------------------------------------------------
213
+ // Shared building blocks
214
+ // ---------------------------------------------------------------------
215
+
216
+ /**
217
+ * Adapt common schema format to the provider's format.
218
+ * OpenAI-compatible APIs use standard JSON Schema, so this is a
219
+ * passthrough.
220
+ */
221
+ protected adaptSchema(schema: StructuredSchema): Record<string, unknown> {
222
+ // Our StructuredSchema is already JSON Schema compatible
223
+ return schema;
224
+ }
225
+
226
+ /**
227
+ * Build OpenAI-formatted messages from HistoryItem[] array.
228
+ * Maps directly to ChatCompletionMessageParam format.
229
+ */
230
+ protected buildChatMessages(history: HistoryItem[]): Array<unknown> {
231
+ const messages: Array<unknown> = [];
232
+
233
+ for (const item of history) {
234
+ switch (item.role) {
235
+ case "system":
236
+ messages.push({ role: "system", content: item.content });
237
+ break;
238
+ case "user":
239
+ messages.push({ role: "user", content: item.content });
240
+ break;
241
+ case "assistant":
242
+ if (item.tool_calls && item.tool_calls.length > 0) {
243
+ messages.push({
244
+ role: "assistant",
245
+ content: item.content || null,
246
+ tool_calls: item.tool_calls.map((tc) => ({
247
+ id: tc.id,
248
+ type: "function",
249
+ function: {
250
+ name: tc.name,
251
+ arguments: JSON.stringify(tc.arguments),
252
+ },
253
+ })),
254
+ });
255
+ } else {
256
+ messages.push({ role: "assistant", content: item.content || "" });
257
+ }
258
+ break;
259
+ case "tool":
260
+ messages.push({
261
+ role: "tool",
262
+ tool_call_id: item.tool_call_id,
263
+ content:
264
+ typeof item.content === "string"
265
+ ? item.content
266
+ : JSON.stringify(item.content),
267
+ });
268
+ break;
269
+ }
270
+ }
271
+
272
+ return messages;
273
+ }
274
+
275
+ /**
276
+ * Map framework tool definitions to OpenAI function tools.
277
+ */
278
+ private buildToolParams(
279
+ tools: NonNullable<GenerateMessageInput<unknown>["tools"]>
280
+ ): ChatCompletionCreateParamsNonStreaming["tools"] {
281
+ return tools.map((tool) => ({
282
+ type: "function" as const,
283
+ function: {
284
+ name: tool.name || tool.id,
285
+ description: tool.description,
286
+ parameters: tool.parameters as FunctionParameters, // JSON schema
287
+ },
288
+ }));
289
+ }
290
+
291
+ /**
292
+ * Parse tool calls from a (complete or delta) tool_calls array,
293
+ * tolerating malformed JSON arguments.
294
+ */
295
+ private parseToolCallArguments(
296
+ rawArguments: string | undefined,
297
+ streaming: boolean
298
+ ): Record<string, unknown> {
299
+ if (!rawArguments) {
300
+ return {};
301
+ }
302
+ try {
303
+ return JSON.parse(rawArguments) as Record<string, unknown>;
304
+ } catch (error) {
305
+ logger.warn(
306
+ `[${this.logLabel}] Failed to parse tool call arguments${
307
+ streaming ? " in stream" : ""
308
+ }: ${getErrorMessage(error)}`
309
+ );
310
+ return {};
311
+ }
312
+ }
313
+
314
+ /**
315
+ * Determines if an error should trigger backup model usage.
316
+ * Derived from the normalized error classification.
317
+ */
318
+ protected shouldUseBackupModel(error: unknown): boolean {
319
+ return isBackupEligible(
320
+ classifyProviderError(error, this.classificationOptions)
321
+ );
322
+ }
323
+
324
+ /**
325
+ * Wrap a terminal failure in a normalized ProviderError.
326
+ */
327
+ protected wrapTerminalError(error: unknown): Error {
328
+ return toProviderError(error, this.name, this.classificationOptions);
329
+ }
330
+
331
+ // ---------------------------------------------------------------------
332
+ // Generation with backup models
333
+ // ---------------------------------------------------------------------
334
+
335
+ private async generateWithBackup<
336
+ TContext = unknown,
337
+ TStructured = AgentStructuredResponse
338
+ >(
339
+ input: GenerateMessageInput<TContext>
340
+ ): Promise<GenerateMessageOutput<TStructured>> {
341
+ // Try primary model first
342
+ try {
343
+ return await this.generateWithModel<TContext, TStructured>(
344
+ this.primaryModel,
345
+ input
346
+ );
347
+ } catch (primaryError: unknown) {
348
+ const primaryErrMsg = getErrorMessage(primaryError);
349
+ logger.warn(
350
+ `[${this.logLabel}] Primary model ${this.primaryModel} failed: ${primaryErrMsg}`
351
+ );
352
+
353
+ if (!this.shouldUseBackupModel(primaryError)) {
354
+ throw this.wrapTerminalError(primaryError);
355
+ }
356
+
357
+ logger.debug(`[${this.logLabel}] Trying backup models`);
358
+
359
+ let lastBackupError: unknown = primaryError;
360
+
361
+ for (let i = 0; i < this.backupModels.length; i++) {
362
+ const backupModel = this.backupModels[i];
363
+ logger.debug(
364
+ `[${this.logLabel}] Trying backup model ${i + 1}/${
365
+ this.backupModels.length
366
+ }: ${backupModel}`
367
+ );
368
+
369
+ try {
370
+ const result = await this.generateWithModel<TContext, TStructured>(
371
+ backupModel,
372
+ input
373
+ );
374
+ logger.debug(`[${this.logLabel}] Backup model ${backupModel} succeeded`);
375
+ return result;
376
+ } catch (backupError: unknown) {
377
+ const backupErrMsg = getErrorMessage(backupError);
378
+ logger.warn(
379
+ `[${this.logLabel}] Backup model ${backupModel} failed: ${backupErrMsg}`
380
+ );
381
+ lastBackupError = backupError;
382
+
383
+ if (
384
+ !this.shouldUseBackupModel(backupError) &&
385
+ i < this.backupModels.length - 1
386
+ ) {
387
+ logger.debug(
388
+ `[${this.logLabel}] Backup model error doesn't qualify for further attempts`
389
+ );
390
+ break;
391
+ }
392
+ }
393
+ }
394
+
395
+ const lastBackupErrMsg = getErrorMessage(lastBackupError);
396
+ logger.error(
397
+ `[${this.logLabel}] All models failed. Primary: ${primaryErrMsg}, Last backup: ${lastBackupErrMsg}`
398
+ );
399
+ throw this.wrapTerminalError(lastBackupError);
400
+ }
401
+ }
402
+
403
+ private async *generateStreamWithBackup<
404
+ TContext = unknown,
405
+ TStructured = AgentStructuredResponse
406
+ >(
407
+ input: GenerateMessageInput<TContext>
408
+ ): AsyncGenerator<GenerateMessageStreamChunk<TStructured>> {
409
+ // Try primary model first
410
+ try {
411
+ yield* this.generateStreamWithModel<TContext, TStructured>(
412
+ this.primaryModel,
413
+ input
414
+ );
415
+ } catch (primaryError: unknown) {
416
+ const primaryErrMsg = getErrorMessage(primaryError);
417
+ logger.warn(
418
+ `[${this.logLabel}] Primary model ${this.primaryModel} failed: ${primaryErrMsg}`
419
+ );
420
+
421
+ if (!this.shouldUseBackupModel(primaryError)) {
422
+ throw this.wrapTerminalError(primaryError);
423
+ }
424
+
425
+ logger.debug(`[${this.logLabel}] Trying backup models for streaming`);
426
+
427
+ let lastBackupError: unknown = primaryError;
428
+
429
+ for (let i = 0; i < this.backupModels.length; i++) {
430
+ const backupModel = this.backupModels[i];
431
+ logger.debug(
432
+ `[${this.logLabel}] Trying backup model ${i + 1}/${
433
+ this.backupModels.length
434
+ }: ${backupModel}`
435
+ );
436
+
437
+ try {
438
+ yield* this.generateStreamWithModel<TContext, TStructured>(
439
+ backupModel,
440
+ input
441
+ );
442
+ logger.debug(`[${this.logLabel}] Backup model ${backupModel} succeeded`);
443
+ return;
444
+ } catch (backupError: unknown) {
445
+ const backupErrMsg = getErrorMessage(backupError);
446
+ logger.warn(
447
+ `[${this.logLabel}] Backup model ${backupModel} failed: ${backupErrMsg}`
448
+ );
449
+ lastBackupError = backupError;
450
+
451
+ if (
452
+ !this.shouldUseBackupModel(backupError) &&
453
+ i < this.backupModels.length - 1
454
+ ) {
455
+ logger.debug(
456
+ `[${this.logLabel}] Backup model error doesn't qualify for further attempts`
457
+ );
458
+ break;
459
+ }
460
+ }
461
+ }
462
+
463
+ const lastBackupErrMsg = getErrorMessage(lastBackupError);
464
+ logger.error(
465
+ `[${this.logLabel}] All models failed. Primary: ${primaryErrMsg}, Last backup: ${lastBackupErrMsg}`
466
+ );
467
+ throw this.wrapTerminalError(lastBackupError);
468
+ }
469
+ }
470
+
471
+ // ---------------------------------------------------------------------
472
+ // Non-streaming generation
473
+ // ---------------------------------------------------------------------
474
+
475
+ private async generateWithModel<
476
+ TContext = unknown,
477
+ TStructured = AgentStructuredResponse
478
+ >(
479
+ model: string,
480
+ input: GenerateMessageInput<TContext>
481
+ ): Promise<GenerateMessageOutput<TStructured>> {
482
+ const operation = async (): Promise<GenerateMessageOutput> => {
483
+ // Use structured output path if JSON schema is provided
484
+ if (input.parameters?.jsonSchema) {
485
+ return this.executeStructuredGenerate(
486
+ model,
487
+ input,
488
+ input.parameters.jsonSchema
489
+ );
490
+ }
491
+ return this.executeChatCompletion(model, input);
492
+ };
493
+
494
+ return withTimeoutAndRetry(
495
+ operation,
496
+ this.retryConfig.timeout,
497
+ this.retryConfig.retries,
498
+ `${this.displayName} ${model}`
499
+ ) as Promise<GenerateMessageOutput<TStructured>>;
500
+ }
501
+
502
+ /**
503
+ * Non-streaming chat-completions request: builds messages/tools,
504
+ * extracts text and tool calls, and merges structured output.
505
+ */
506
+ protected async executeChatCompletion(
507
+ model: string,
508
+ input: GenerateMessageInput<unknown>
509
+ ): Promise<GenerateMessageOutput> {
510
+ const historyMessages = this.buildChatMessages(input.history);
511
+ historyMessages.push({ role: "user", content: input.prompt });
512
+
513
+ const params: ChatCompletionCreateParamsNonStreaming = {
514
+ model,
515
+ messages:
516
+ historyMessages as ChatCompletionCreateParamsNonStreaming["messages"],
517
+ ...this.config,
518
+ };
519
+
520
+ // Override with input parameters if provided
521
+ if (input.parameters?.maxOutputTokens !== undefined) {
522
+ params.max_tokens = input.parameters.maxOutputTokens;
523
+ }
524
+
525
+ // Add tools if provided
526
+ if (input.tools && input.tools.length > 0) {
527
+ params.tools = this.buildToolParams(input.tools);
528
+ params.tool_choice = "auto";
529
+ }
530
+
531
+ // Use structured output format if JSON schema is provided
532
+ if (input.parameters?.jsonSchema) {
533
+ params.response_format = this.structuredResponseFormat(
534
+ input.parameters.jsonSchema,
535
+ input.parameters.schemaName
536
+ );
537
+ }
538
+
539
+ const response = await this.client.chat.completions.create(params);
540
+
541
+ const message = response.choices[0]?.message?.content || "";
542
+
543
+ let toolCalls: Array<{
544
+ toolName: string;
545
+ arguments: Record<string, unknown>;
546
+ }> = [];
547
+ if (response.choices?.[0]?.message?.tool_calls) {
548
+ toolCalls = response.choices[0].message.tool_calls
549
+ .filter((toolCall) => toolCall.type === "function")
550
+ .map((toolCall) => ({
551
+ toolName: toolCall.function.name,
552
+ arguments: this.parseToolCallArguments(
553
+ toolCall.function.arguments,
554
+ false
555
+ ),
556
+ }));
557
+ }
558
+
559
+ // Only throw error if we have no text AND no function calls
560
+ if (!message && toolCalls.length === 0) {
561
+ throw new Error(`No response from ${this.displayName}`);
562
+ }
563
+
564
+ // Parse structured output if schema was provided
565
+ let structured: AgentStructuredResponse | undefined;
566
+ if (input.parameters?.jsonSchema && message) {
567
+ try {
568
+ structured = JSON.parse(message) as AgentStructuredResponse;
569
+ } catch (error) {
570
+ logger.warn(`[${this.logLabel}] Failed to parse JSON response:`, error);
571
+ }
572
+ }
573
+
574
+ // If tools were used, include them in structured response
575
+ if (toolCalls.length > 0) {
576
+ structured = {
577
+ ...(structured || {}),
578
+ message: structured?.message || message,
579
+ toolCalls,
580
+ } as AgentStructuredResponse;
581
+ }
582
+
583
+ return {
584
+ message,
585
+ metadata: {
586
+ model: response.model,
587
+ finishReason: response.choices[0]?.finish_reason,
588
+ tokensUsed: response.usage?.total_tokens,
589
+ promptTokens: response.usage?.prompt_tokens,
590
+ completionTokens: response.usage?.completion_tokens,
591
+ },
592
+ structured,
593
+ };
594
+ }
595
+
596
+ // ---------------------------------------------------------------------
597
+ // Streaming generation
598
+ // ---------------------------------------------------------------------
599
+
600
+ private async *generateStreamWithModel<
601
+ TContext = unknown,
602
+ TStructured = AgentStructuredResponse
603
+ >(
604
+ model: string,
605
+ input: GenerateMessageInput<TContext>
606
+ ): AsyncGenerator<GenerateMessageStreamChunk<TStructured>> {
607
+ // Build messages from history and append prompt as final user message
608
+ const historyMessages = this.buildChatMessages(input.history);
609
+ historyMessages.push({ role: "user" as const, content: input.prompt });
610
+
611
+ const params: ChatCompletionCreateParamsStreaming = {
612
+ ...this.config,
613
+ model,
614
+ messages:
615
+ historyMessages as ChatCompletionCreateParamsNonStreaming["messages"],
616
+ stream: true as const,
617
+ };
618
+ this.configureStreamParams(params);
619
+
620
+ // Override with input parameters if provided
621
+ if (input.parameters?.maxOutputTokens !== undefined) {
622
+ params.max_tokens = input.parameters.maxOutputTokens;
623
+ }
624
+
625
+ // Add tools if provided
626
+ if (input.tools && input.tools.length > 0) {
627
+ params.tools = this.buildToolParams(input.tools);
628
+ params.tool_choice = "auto";
629
+ }
630
+
631
+ // Streaming path does not support responses.parse; if schema present,
632
+ // request structured output and parse at the end.
633
+ if (input.parameters?.jsonSchema) {
634
+ params.response_format = this.structuredResponseFormat(
635
+ input.parameters.jsonSchema,
636
+ input.parameters.schemaName
637
+ );
638
+ }
639
+
640
+ const stream = await this.client.chat.completions.create(params);
641
+
642
+ let accumulated = "";
643
+ let currentModel = model;
644
+ let finishReason: string | undefined;
645
+ let promptTokens: number | undefined;
646
+ let completionTokens: number | undefined;
647
+ let totalTokens: number | undefined;
648
+ const toolCalls: Array<{
649
+ toolName: string;
650
+ arguments: Record<string, unknown>;
651
+ }> = [];
652
+
653
+ for await (const chunk of stream) {
654
+ currentModel = chunk.model;
655
+
656
+ // Some providers include usage in (possibly choice-less) chunks
657
+ if (chunk.usage) {
658
+ promptTokens = chunk.usage.prompt_tokens;
659
+ completionTokens = chunk.usage.completion_tokens;
660
+ totalTokens = chunk.usage.total_tokens;
661
+ }
662
+
663
+ const choice = chunk.choices?.[0];
664
+ if (!choice) continue;
665
+
666
+ // Extract tool calls from delta
667
+ if (choice.delta?.tool_calls) {
668
+ for (const toolCall of choice.delta.tool_calls) {
669
+ if (toolCall.function) {
670
+ toolCalls.push({
671
+ toolName: toolCall.function.name || "",
672
+ arguments: this.parseToolCallArguments(
673
+ toolCall.function.arguments,
674
+ true
675
+ ),
676
+ });
677
+ }
678
+ }
679
+ }
680
+
681
+ // Provider-specific delta handling (e.g. DeepSeek reasoning_content)
682
+ this.onStreamDelta(choice.delta);
683
+
684
+ const delta = choice.delta?.content || "";
685
+ if (delta) {
686
+ accumulated += delta;
687
+ yield {
688
+ delta,
689
+ accumulated,
690
+ done: false,
691
+ };
692
+ }
693
+
694
+ if (choice.finish_reason) {
695
+ finishReason = choice.finish_reason;
696
+ }
697
+ }
698
+
699
+ // Parse JSON response if schema was provided
700
+ let structured: TStructured | undefined;
701
+ if (input.parameters?.jsonSchema && accumulated) {
702
+ try {
703
+ structured = JSON.parse(accumulated) as TStructured;
704
+ } catch (error) {
705
+ logger.warn(
706
+ `[${this.logLabel}] Failed to parse JSON response in stream:`,
707
+ error
708
+ );
709
+ }
710
+ }
711
+
712
+ // Include tool calls in structured response (even without JSON schema)
713
+ if (toolCalls.length > 0) {
714
+ structured = {
715
+ ...(structured || {}),
716
+ message:
717
+ (structured as AgentStructuredResponse | undefined)?.message ||
718
+ accumulated,
719
+ toolCalls,
720
+ } as TStructured;
721
+ }
722
+
723
+ // Yield final chunk
724
+ yield {
725
+ delta: "",
726
+ accumulated,
727
+ done: true,
728
+ metadata: {
729
+ model: currentModel,
730
+ finishReason,
731
+ tokensUsed: totalTokens,
732
+ promptTokens,
733
+ completionTokens,
734
+ },
735
+ structured,
736
+ };
737
+ }
738
+ }