@burtson-labs/stealth-core-runtime 1.4.7

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 (415) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +46 -0
  3. package/dist/banditEngineProvider.d.ts +48 -0
  4. package/dist/banditEngineProvider.d.ts.map +1 -0
  5. package/dist/banditEngineProvider.js +1021 -0
  6. package/dist/banditEngineProvider.js.map +1 -0
  7. package/dist/embeddingCache.d.ts +23 -0
  8. package/dist/embeddingCache.d.ts.map +1 -0
  9. package/dist/embeddingCache.js +196 -0
  10. package/dist/embeddingCache.js.map +1 -0
  11. package/dist/embeddingClient.d.ts +35 -0
  12. package/dist/embeddingClient.d.ts.map +1 -0
  13. package/dist/embeddingClient.js +162 -0
  14. package/dist/embeddingClient.js.map +1 -0
  15. package/dist/executorAgent.d.ts +7 -0
  16. package/dist/executorAgent.d.ts.map +1 -0
  17. package/dist/executorAgent.js +95 -0
  18. package/dist/executorAgent.js.map +1 -0
  19. package/dist/extensionSystemPrompt.d.ts +80 -0
  20. package/dist/extensionSystemPrompt.d.ts.map +1 -0
  21. package/dist/extensionSystemPrompt.js +208 -0
  22. package/dist/extensionSystemPrompt.js.map +1 -0
  23. package/dist/gatewaySearchAdapter.d.ts +69 -0
  24. package/dist/gatewaySearchAdapter.d.ts.map +1 -0
  25. package/dist/gatewaySearchAdapter.js +131 -0
  26. package/dist/gatewaySearchAdapter.js.map +1 -0
  27. package/dist/goalInference.d.ts +26 -0
  28. package/dist/goalInference.d.ts.map +1 -0
  29. package/dist/goalInference.js +605 -0
  30. package/dist/goalInference.js.map +1 -0
  31. package/dist/hostTypes.d.ts +86 -0
  32. package/dist/hostTypes.d.ts.map +1 -0
  33. package/dist/hostTypes.js +3 -0
  34. package/dist/hostTypes.js.map +1 -0
  35. package/dist/index.d.ts +37 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +83 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/internalTypes.d.ts +16 -0
  40. package/dist/internalTypes.d.ts.map +1 -0
  41. package/dist/internalTypes.js +20 -0
  42. package/dist/internalTypes.js.map +1 -0
  43. package/dist/ollamaEmbeddingClient.d.ts +45 -0
  44. package/dist/ollamaEmbeddingClient.d.ts.map +1 -0
  45. package/dist/ollamaEmbeddingClient.js +143 -0
  46. package/dist/ollamaEmbeddingClient.js.map +1 -0
  47. package/dist/pdfjsShim.d.ts +2 -0
  48. package/dist/pdfjsShim.d.ts.map +1 -0
  49. package/dist/pdfjsShim.js +80 -0
  50. package/dist/pdfjsShim.js.map +1 -0
  51. package/dist/runtime/actionRuntime.d.ts +13 -0
  52. package/dist/runtime/actionRuntime.d.ts.map +1 -0
  53. package/dist/runtime/actionRuntime.js +15 -0
  54. package/dist/runtime/actionRuntime.js.map +1 -0
  55. package/dist/runtime/actionServices.d.ts +72 -0
  56. package/dist/runtime/actionServices.d.ts.map +1 -0
  57. package/dist/runtime/actionServices.js +53 -0
  58. package/dist/runtime/actionServices.js.map +1 -0
  59. package/dist/runtime/adapters/connectorBus.d.ts +9 -0
  60. package/dist/runtime/adapters/connectorBus.d.ts.map +1 -0
  61. package/dist/runtime/adapters/connectorBus.js +20 -0
  62. package/dist/runtime/adapters/connectorBus.js.map +1 -0
  63. package/dist/runtime/adapters/fsAdapter.d.ts +6 -0
  64. package/dist/runtime/adapters/fsAdapter.d.ts.map +1 -0
  65. package/dist/runtime/adapters/fsAdapter.js +144 -0
  66. package/dist/runtime/adapters/fsAdapter.js.map +1 -0
  67. package/dist/runtime/adapters/llmAdapter.d.ts +4 -0
  68. package/dist/runtime/adapters/llmAdapter.d.ts.map +1 -0
  69. package/dist/runtime/adapters/llmAdapter.js +12 -0
  70. package/dist/runtime/adapters/llmAdapter.js.map +1 -0
  71. package/dist/runtime/adapters/shellAdapter.d.ts +6 -0
  72. package/dist/runtime/adapters/shellAdapter.d.ts.map +1 -0
  73. package/dist/runtime/adapters/shellAdapter.js +118 -0
  74. package/dist/runtime/adapters/shellAdapter.js.map +1 -0
  75. package/dist/runtime/additionalWrites.d.ts +22 -0
  76. package/dist/runtime/additionalWrites.d.ts.map +1 -0
  77. package/dist/runtime/additionalWrites.js +148 -0
  78. package/dist/runtime/additionalWrites.js.map +1 -0
  79. package/dist/runtime/artifactManager.d.ts +32 -0
  80. package/dist/runtime/artifactManager.d.ts.map +1 -0
  81. package/dist/runtime/artifactManager.js +154 -0
  82. package/dist/runtime/artifactManager.js.map +1 -0
  83. package/dist/runtime/autoHealer.d.ts +27 -0
  84. package/dist/runtime/autoHealer.d.ts.map +1 -0
  85. package/dist/runtime/autoHealer.js +583 -0
  86. package/dist/runtime/autoHealer.js.map +1 -0
  87. package/dist/runtime/changeTracker.d.ts +20 -0
  88. package/dist/runtime/changeTracker.d.ts.map +1 -0
  89. package/dist/runtime/changeTracker.js +147 -0
  90. package/dist/runtime/changeTracker.js.map +1 -0
  91. package/dist/runtime/contextBuilder.d.ts +85 -0
  92. package/dist/runtime/contextBuilder.d.ts.map +1 -0
  93. package/dist/runtime/contextBuilder.js +159 -0
  94. package/dist/runtime/contextBuilder.js.map +1 -0
  95. package/dist/runtime/coreRuntime.d.ts +7 -0
  96. package/dist/runtime/coreRuntime.d.ts.map +1 -0
  97. package/dist/runtime/coreRuntime.js +173 -0
  98. package/dist/runtime/coreRuntime.js.map +1 -0
  99. package/dist/runtime/createStealthRuntime.d.ts +4 -0
  100. package/dist/runtime/createStealthRuntime.d.ts.map +1 -0
  101. package/dist/runtime/createStealthRuntime.js +514 -0
  102. package/dist/runtime/createStealthRuntime.js.map +1 -0
  103. package/dist/runtime/diagnostics.d.ts +53 -0
  104. package/dist/runtime/diagnostics.d.ts.map +1 -0
  105. package/dist/runtime/diagnostics.js +396 -0
  106. package/dist/runtime/diagnostics.js.map +1 -0
  107. package/dist/runtime/diagnosticsServices.d.ts +51 -0
  108. package/dist/runtime/diagnosticsServices.d.ts.map +1 -0
  109. package/dist/runtime/diagnosticsServices.js +46 -0
  110. package/dist/runtime/diagnosticsServices.js.map +1 -0
  111. package/dist/runtime/diffManager.d.ts +20 -0
  112. package/dist/runtime/diffManager.d.ts.map +1 -0
  113. package/dist/runtime/diffManager.js +172 -0
  114. package/dist/runtime/diffManager.js.map +1 -0
  115. package/dist/runtime/diffPresenter.d.ts +8 -0
  116. package/dist/runtime/diffPresenter.d.ts.map +1 -0
  117. package/dist/runtime/diffPresenter.js +57 -0
  118. package/dist/runtime/diffPresenter.js.map +1 -0
  119. package/dist/runtime/embeddingClientResolver.d.ts +14 -0
  120. package/dist/runtime/embeddingClientResolver.d.ts.map +1 -0
  121. package/dist/runtime/embeddingClientResolver.js +54 -0
  122. package/dist/runtime/embeddingClientResolver.js.map +1 -0
  123. package/dist/runtime/embeddingManager.d.ts +22 -0
  124. package/dist/runtime/embeddingManager.d.ts.map +1 -0
  125. package/dist/runtime/embeddingManager.js +224 -0
  126. package/dist/runtime/embeddingManager.js.map +1 -0
  127. package/dist/runtime/eventBus.d.ts +7 -0
  128. package/dist/runtime/eventBus.d.ts.map +1 -0
  129. package/dist/runtime/eventBus.js +28 -0
  130. package/dist/runtime/eventBus.js.map +1 -0
  131. package/dist/runtime/executorServices.d.ts +46 -0
  132. package/dist/runtime/executorServices.d.ts.map +1 -0
  133. package/dist/runtime/executorServices.js +47 -0
  134. package/dist/runtime/executorServices.js.map +1 -0
  135. package/dist/runtime/extractionService.d.ts +11 -0
  136. package/dist/runtime/extractionService.d.ts.map +1 -0
  137. package/dist/runtime/extractionService.js +282 -0
  138. package/dist/runtime/extractionService.js.map +1 -0
  139. package/dist/runtime/feedbackService.d.ts +12 -0
  140. package/dist/runtime/feedbackService.d.ts.map +1 -0
  141. package/dist/runtime/feedbackService.js +111 -0
  142. package/dist/runtime/feedbackService.js.map +1 -0
  143. package/dist/runtime/goalEngine.d.ts +10 -0
  144. package/dist/runtime/goalEngine.d.ts.map +1 -0
  145. package/dist/runtime/goalEngine.js +429 -0
  146. package/dist/runtime/goalEngine.js.map +1 -0
  147. package/dist/runtime/goalFlowServices.d.ts +49 -0
  148. package/dist/runtime/goalFlowServices.d.ts.map +1 -0
  149. package/dist/runtime/goalFlowServices.js +45 -0
  150. package/dist/runtime/goalFlowServices.js.map +1 -0
  151. package/dist/runtime/goalReplay.d.ts +33 -0
  152. package/dist/runtime/goalReplay.d.ts.map +1 -0
  153. package/dist/runtime/goalReplay.js +58 -0
  154. package/dist/runtime/goalReplay.js.map +1 -0
  155. package/dist/runtime/goalRunner.d.ts +35 -0
  156. package/dist/runtime/goalRunner.d.ts.map +1 -0
  157. package/dist/runtime/goalRunner.js +42 -0
  158. package/dist/runtime/goalRunner.js.map +1 -0
  159. package/dist/runtime/healingEngine.d.ts +72 -0
  160. package/dist/runtime/healingEngine.d.ts.map +1 -0
  161. package/dist/runtime/healingEngine.js +969 -0
  162. package/dist/runtime/healingEngine.js.map +1 -0
  163. package/dist/runtime/healingServices.d.ts +62 -0
  164. package/dist/runtime/healingServices.d.ts.map +1 -0
  165. package/dist/runtime/healingServices.js +45 -0
  166. package/dist/runtime/healingServices.js.map +1 -0
  167. package/dist/runtime/helpers.d.ts +22 -0
  168. package/dist/runtime/helpers.d.ts.map +1 -0
  169. package/dist/runtime/helpers.js +694 -0
  170. package/dist/runtime/helpers.js.map +1 -0
  171. package/dist/runtime/hosts/actionHost.d.ts +82 -0
  172. package/dist/runtime/hosts/actionHost.d.ts.map +1 -0
  173. package/dist/runtime/hosts/actionHost.js +61 -0
  174. package/dist/runtime/hosts/actionHost.js.map +1 -0
  175. package/dist/runtime/hosts/baseServices.d.ts +51 -0
  176. package/dist/runtime/hosts/baseServices.d.ts.map +1 -0
  177. package/dist/runtime/hosts/baseServices.js +73 -0
  178. package/dist/runtime/hosts/baseServices.js.map +1 -0
  179. package/dist/runtime/hosts/embeddingServices.d.ts +25 -0
  180. package/dist/runtime/hosts/embeddingServices.d.ts.map +1 -0
  181. package/dist/runtime/hosts/embeddingServices.js +34 -0
  182. package/dist/runtime/hosts/embeddingServices.js.map +1 -0
  183. package/dist/runtime/hosts/goalFlowHost.d.ts +34 -0
  184. package/dist/runtime/hosts/goalFlowHost.d.ts.map +1 -0
  185. package/dist/runtime/hosts/goalFlowHost.js +35 -0
  186. package/dist/runtime/hosts/goalFlowHost.js.map +1 -0
  187. package/dist/runtime/hosts/goalFlowRuntime.d.ts +41 -0
  188. package/dist/runtime/hosts/goalFlowRuntime.d.ts.map +1 -0
  189. package/dist/runtime/hosts/goalFlowRuntime.js +31 -0
  190. package/dist/runtime/hosts/goalFlowRuntime.js.map +1 -0
  191. package/dist/runtime/hosts/providerHost.d.ts +19 -0
  192. package/dist/runtime/hosts/providerHost.d.ts.map +1 -0
  193. package/dist/runtime/hosts/providerHost.js +18 -0
  194. package/dist/runtime/hosts/providerHost.js.map +1 -0
  195. package/dist/runtime/hosts/rewriteHost.d.ts +84 -0
  196. package/dist/runtime/hosts/rewriteHost.d.ts.map +1 -0
  197. package/dist/runtime/hosts/rewriteHost.js +64 -0
  198. package/dist/runtime/hosts/rewriteHost.js.map +1 -0
  199. package/dist/runtime/hosts/workspaceHost.d.ts +113 -0
  200. package/dist/runtime/hosts/workspaceHost.d.ts.map +1 -0
  201. package/dist/runtime/hosts/workspaceHost.js +76 -0
  202. package/dist/runtime/hosts/workspaceHost.js.map +1 -0
  203. package/dist/runtime/index.d.ts +78 -0
  204. package/dist/runtime/index.d.ts.map +1 -0
  205. package/dist/runtime/index.js +95 -0
  206. package/dist/runtime/index.js.map +1 -0
  207. package/dist/runtime/insight.d.ts +16 -0
  208. package/dist/runtime/insight.d.ts.map +1 -0
  209. package/dist/runtime/insight.js +11 -0
  210. package/dist/runtime/insight.js.map +1 -0
  211. package/dist/runtime/internalActions.d.ts +16 -0
  212. package/dist/runtime/internalActions.d.ts.map +1 -0
  213. package/dist/runtime/internalActions.js +302 -0
  214. package/dist/runtime/internalActions.js.map +1 -0
  215. package/dist/runtime/modelBehavior.d.ts +69 -0
  216. package/dist/runtime/modelBehavior.d.ts.map +1 -0
  217. package/dist/runtime/modelBehavior.js +514 -0
  218. package/dist/runtime/modelBehavior.js.map +1 -0
  219. package/dist/runtime/modelCapabilities.d.ts +139 -0
  220. package/dist/runtime/modelCapabilities.d.ts.map +1 -0
  221. package/dist/runtime/modelCapabilities.js +458 -0
  222. package/dist/runtime/modelCapabilities.js.map +1 -0
  223. package/dist/runtime/modelsDevCatalog.d.ts +34 -0
  224. package/dist/runtime/modelsDevCatalog.d.ts.map +1 -0
  225. package/dist/runtime/modelsDevCatalog.js +263 -0
  226. package/dist/runtime/modelsDevCatalog.js.map +1 -0
  227. package/dist/runtime/pendingInference.d.ts +18 -0
  228. package/dist/runtime/pendingInference.d.ts.map +1 -0
  229. package/dist/runtime/pendingInference.js +121 -0
  230. package/dist/runtime/pendingInference.js.map +1 -0
  231. package/dist/runtime/persistence.d.ts +21 -0
  232. package/dist/runtime/persistence.d.ts.map +1 -0
  233. package/dist/runtime/persistence.js +73 -0
  234. package/dist/runtime/persistence.js.map +1 -0
  235. package/dist/runtime/planContext.d.ts +42 -0
  236. package/dist/runtime/planContext.d.ts.map +1 -0
  237. package/dist/runtime/planContext.js +246 -0
  238. package/dist/runtime/planContext.js.map +1 -0
  239. package/dist/runtime/planGenerator.d.ts +21 -0
  240. package/dist/runtime/planGenerator.d.ts.map +1 -0
  241. package/dist/runtime/planGenerator.js +89 -0
  242. package/dist/runtime/planGenerator.js.map +1 -0
  243. package/dist/runtime/planPreparation.d.ts +64 -0
  244. package/dist/runtime/planPreparation.d.ts.map +1 -0
  245. package/dist/runtime/planPreparation.js +173 -0
  246. package/dist/runtime/planPreparation.js.map +1 -0
  247. package/dist/runtime/projectSummary.d.ts +3 -0
  248. package/dist/runtime/projectSummary.d.ts.map +1 -0
  249. package/dist/runtime/projectSummary.js +42 -0
  250. package/dist/runtime/projectSummary.js.map +1 -0
  251. package/dist/runtime/providerSettings.d.ts +28 -0
  252. package/dist/runtime/providerSettings.d.ts.map +1 -0
  253. package/dist/runtime/providerSettings.js +93 -0
  254. package/dist/runtime/providerSettings.js.map +1 -0
  255. package/dist/runtime/pythonActions.d.ts +78 -0
  256. package/dist/runtime/pythonActions.d.ts.map +1 -0
  257. package/dist/runtime/pythonActions.js +392 -0
  258. package/dist/runtime/pythonActions.js.map +1 -0
  259. package/dist/runtime/pythonBridge.d.ts +13 -0
  260. package/dist/runtime/pythonBridge.d.ts.map +1 -0
  261. package/dist/runtime/pythonBridge.js +117 -0
  262. package/dist/runtime/pythonBridge.js.map +1 -0
  263. package/dist/runtime/rewriteEngine.d.ts +46 -0
  264. package/dist/runtime/rewriteEngine.d.ts.map +1 -0
  265. package/dist/runtime/rewriteEngine.js +259 -0
  266. package/dist/runtime/rewriteEngine.js.map +1 -0
  267. package/dist/runtime/rewriteGenerator.d.ts +29 -0
  268. package/dist/runtime/rewriteGenerator.d.ts.map +1 -0
  269. package/dist/runtime/rewriteGenerator.js +1527 -0
  270. package/dist/runtime/rewriteGenerator.js.map +1 -0
  271. package/dist/runtime/rewriteHydration.d.ts +22 -0
  272. package/dist/runtime/rewriteHydration.d.ts.map +1 -0
  273. package/dist/runtime/rewriteHydration.js +265 -0
  274. package/dist/runtime/rewriteHydration.js.map +1 -0
  275. package/dist/runtime/rewriteOrchestration.d.ts +105 -0
  276. package/dist/runtime/rewriteOrchestration.d.ts.map +1 -0
  277. package/dist/runtime/rewriteOrchestration.js +130 -0
  278. package/dist/runtime/rewriteOrchestration.js.map +1 -0
  279. package/dist/runtime/rewritePayload.d.ts +18 -0
  280. package/dist/runtime/rewritePayload.d.ts.map +1 -0
  281. package/dist/runtime/rewritePayload.js +166 -0
  282. package/dist/runtime/rewritePayload.js.map +1 -0
  283. package/dist/runtime/rewriteRuntime.d.ts +13 -0
  284. package/dist/runtime/rewriteRuntime.d.ts.map +1 -0
  285. package/dist/runtime/rewriteRuntime.js +21 -0
  286. package/dist/runtime/rewriteRuntime.js.map +1 -0
  287. package/dist/runtime/rewriteServices.d.ts +70 -0
  288. package/dist/runtime/rewriteServices.d.ts.map +1 -0
  289. package/dist/runtime/rewriteServices.js +50 -0
  290. package/dist/runtime/rewriteServices.js.map +1 -0
  291. package/dist/runtime/runtimeHelpers.d.ts +9 -0
  292. package/dist/runtime/runtimeHelpers.d.ts.map +1 -0
  293. package/dist/runtime/runtimeHelpers.js +86 -0
  294. package/dist/runtime/runtimeHelpers.js.map +1 -0
  295. package/dist/runtime/sessionData.d.ts +4 -0
  296. package/dist/runtime/sessionData.d.ts.map +1 -0
  297. package/dist/runtime/sessionData.js +45 -0
  298. package/dist/runtime/sessionData.js.map +1 -0
  299. package/dist/runtime/sessionRuntime.d.ts +47 -0
  300. package/dist/runtime/sessionRuntime.d.ts.map +1 -0
  301. package/dist/runtime/sessionRuntime.js +128 -0
  302. package/dist/runtime/sessionRuntime.js.map +1 -0
  303. package/dist/runtime/stealthRuntimeTypes.d.ts +12 -0
  304. package/dist/runtime/stealthRuntimeTypes.d.ts.map +1 -0
  305. package/dist/runtime/stealthRuntimeTypes.js +3 -0
  306. package/dist/runtime/stealthRuntimeTypes.js.map +1 -0
  307. package/dist/runtime/stepExecutor.d.ts +22 -0
  308. package/dist/runtime/stepExecutor.d.ts.map +1 -0
  309. package/dist/runtime/stepExecutor.js +83 -0
  310. package/dist/runtime/stepExecutor.js.map +1 -0
  311. package/dist/runtime/stepLifecycle.d.ts +29 -0
  312. package/dist/runtime/stepLifecycle.d.ts.map +1 -0
  313. package/dist/runtime/stepLifecycle.js +122 -0
  314. package/dist/runtime/stepLifecycle.js.map +1 -0
  315. package/dist/runtime/stepMetadata.d.ts +6 -0
  316. package/dist/runtime/stepMetadata.d.ts.map +1 -0
  317. package/dist/runtime/stepMetadata.js +87 -0
  318. package/dist/runtime/stepMetadata.js.map +1 -0
  319. package/dist/runtime/taskQueue.d.ts +16 -0
  320. package/dist/runtime/taskQueue.d.ts.map +1 -0
  321. package/dist/runtime/taskQueue.js +103 -0
  322. package/dist/runtime/taskQueue.js.map +1 -0
  323. package/dist/runtime/telemetry.d.ts +6 -0
  324. package/dist/runtime/telemetry.d.ts.map +1 -0
  325. package/dist/runtime/telemetry.js +42 -0
  326. package/dist/runtime/telemetry.js.map +1 -0
  327. package/dist/runtime/telemetryHub.d.ts +61 -0
  328. package/dist/runtime/telemetryHub.d.ts.map +1 -0
  329. package/dist/runtime/telemetryHub.js +190 -0
  330. package/dist/runtime/telemetryHub.js.map +1 -0
  331. package/dist/runtime/textSanitizer.d.ts +4 -0
  332. package/dist/runtime/textSanitizer.d.ts.map +1 -0
  333. package/dist/runtime/textSanitizer.js +86 -0
  334. package/dist/runtime/textSanitizer.js.map +1 -0
  335. package/dist/runtime/typeCheckRunner.d.ts +33 -0
  336. package/dist/runtime/typeCheckRunner.d.ts.map +1 -0
  337. package/dist/runtime/typeCheckRunner.js +357 -0
  338. package/dist/runtime/typeCheckRunner.js.map +1 -0
  339. package/dist/runtime/types.d.ts +334 -0
  340. package/dist/runtime/types.d.ts.map +1 -0
  341. package/dist/runtime/types.js +3 -0
  342. package/dist/runtime/types.js.map +1 -0
  343. package/dist/runtime/typescriptValidator.d.ts +18 -0
  344. package/dist/runtime/typescriptValidator.d.ts.map +1 -0
  345. package/dist/runtime/typescriptValidator.js +363 -0
  346. package/dist/runtime/typescriptValidator.js.map +1 -0
  347. package/dist/runtime/undoManager.d.ts +7 -0
  348. package/dist/runtime/undoManager.d.ts.map +1 -0
  349. package/dist/runtime/undoManager.js +56 -0
  350. package/dist/runtime/undoManager.js.map +1 -0
  351. package/dist/runtime/validationController.d.ts +11 -0
  352. package/dist/runtime/validationController.d.ts.map +1 -0
  353. package/dist/runtime/validationController.js +29 -0
  354. package/dist/runtime/validationController.js.map +1 -0
  355. package/dist/runtime/validationUtils.d.ts +17 -0
  356. package/dist/runtime/validationUtils.d.ts.map +1 -0
  357. package/dist/runtime/validationUtils.js +121 -0
  358. package/dist/runtime/validationUtils.js.map +1 -0
  359. package/dist/runtime/workspaceAssertions.d.ts +21 -0
  360. package/dist/runtime/workspaceAssertions.d.ts.map +1 -0
  361. package/dist/runtime/workspaceAssertions.js +183 -0
  362. package/dist/runtime/workspaceAssertions.js.map +1 -0
  363. package/dist/runtime/workspaceIndexService.d.ts +24 -0
  364. package/dist/runtime/workspaceIndexService.d.ts.map +1 -0
  365. package/dist/runtime/workspaceIndexService.js +133 -0
  366. package/dist/runtime/workspaceIndexService.js.map +1 -0
  367. package/dist/runtime/workspaceIndexer.d.ts +21 -0
  368. package/dist/runtime/workspaceIndexer.d.ts.map +1 -0
  369. package/dist/runtime/workspaceIndexer.js +95 -0
  370. package/dist/runtime/workspaceIndexer.js.map +1 -0
  371. package/dist/runtime/workspacePackages.d.ts +22 -0
  372. package/dist/runtime/workspacePackages.d.ts.map +1 -0
  373. package/dist/runtime/workspacePackages.js +198 -0
  374. package/dist/runtime/workspacePackages.js.map +1 -0
  375. package/dist/runtime/workspaceRuntime.d.ts +58 -0
  376. package/dist/runtime/workspaceRuntime.d.ts.map +1 -0
  377. package/dist/runtime/workspaceRuntime.js +86 -0
  378. package/dist/runtime/workspaceRuntime.js.map +1 -0
  379. package/dist/runtime/workspaceService.d.ts +14 -0
  380. package/dist/runtime/workspaceService.d.ts.map +1 -0
  381. package/dist/runtime/workspaceService.js +88 -0
  382. package/dist/runtime/workspaceService.js.map +1 -0
  383. package/dist/runtime/workspaceServices.d.ts +114 -0
  384. package/dist/runtime/workspaceServices.d.ts.map +1 -0
  385. package/dist/runtime/workspaceServices.js +114 -0
  386. package/dist/runtime/workspaceServices.js.map +1 -0
  387. package/dist/runtime/writeServices.d.ts +34 -0
  388. package/dist/runtime/writeServices.d.ts.map +1 -0
  389. package/dist/runtime/writeServices.js +32 -0
  390. package/dist/runtime/writeServices.js.map +1 -0
  391. package/dist/sharedPromptSections.d.ts +58 -0
  392. package/dist/sharedPromptSections.d.ts.map +1 -0
  393. package/dist/sharedPromptSections.js +94 -0
  394. package/dist/sharedPromptSections.js.map +1 -0
  395. package/dist/statusTypes.d.ts +13 -0
  396. package/dist/statusTypes.d.ts.map +1 -0
  397. package/dist/statusTypes.js +3 -0
  398. package/dist/statusTypes.js.map +1 -0
  399. package/dist/streamIdleTimeout.d.ts +38 -0
  400. package/dist/streamIdleTimeout.d.ts.map +1 -0
  401. package/dist/streamIdleTimeout.js +44 -0
  402. package/dist/streamIdleTimeout.js.map +1 -0
  403. package/dist/types/bandit.d.ts +113 -0
  404. package/dist/types/bandit.d.ts.map +1 -0
  405. package/dist/types/bandit.js +3 -0
  406. package/dist/types/bandit.js.map +1 -0
  407. package/dist/types.d.ts +152 -0
  408. package/dist/types.d.ts.map +1 -0
  409. package/dist/types.js +3 -0
  410. package/dist/types.js.map +1 -0
  411. package/dist/workspaceIndex.d.ts +44 -0
  412. package/dist/workspaceIndex.d.ts.map +1 -0
  413. package/dist/workspaceIndex.js +258 -0
  414. package/dist/workspaceIndex.js.map +1 -0
  415. package/package.json +36 -0
@@ -0,0 +1,1021 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeOllamaMessages = normalizeOllamaMessages;
4
+ exports.createProvider = createProvider;
5
+ exports.serializeBanditPayload = serializeBanditPayload;
6
+ const modelCapabilities_1 = require("./runtime/modelCapabilities");
7
+ const streamIdleTimeout_1 = require("./streamIdleTimeout");
8
+ const DEFAULT_BANDIT_COMPLETIONS_URL = 'https://api.burtson.ai/completions';
9
+ const DEFAULT_OLLAMA_URL = 'http://localhost:11434';
10
+ const DEFAULT_OLLAMA_MODEL = 'gemma3:12b';
11
+ /** Control tokens emitted by Gemma3, Llama, and other local models that must be stripped. */
12
+ const CONTROL_TOKEN_PATTERNS = [
13
+ /<\/?end_of_turn>/g,
14
+ /<\/?start_of_turn>/g,
15
+ /<\|eot_id\|>/g,
16
+ /<\|start_header_id\|>/g,
17
+ /<\|end_header_id\|>/g,
18
+ /<\|begin_of_text\|>/g,
19
+ /\[INST\]/g,
20
+ /\[\/INST\]/g,
21
+ /<<SYS>>/g,
22
+ /<\/SYS>>/g,
23
+ ];
24
+ function sanitizeOllamaOutput(text) {
25
+ // NOTE: called per streamed chunk — do NOT trim here. Word-break whitespace
26
+ // lives on chunk boundaries ("Hello", " world"); trimming each chunk
27
+ // collapses them into "Helloworld". Only control tokens are removed.
28
+ let result = text;
29
+ for (const pattern of CONTROL_TOKEN_PATTERNS) {
30
+ result = result.replace(pattern, '');
31
+ }
32
+ result = stripBase64BlobsInline(result);
33
+ return result;
34
+ }
35
+ /**
36
+ * Stream-safe base64 blob stripper. A single streamed chunk may contain
37
+ * the start of a base64 blob; replacing the partial contents would make
38
+ * the blob detectable again when the next chunk arrives. We only strip
39
+ * when we can prove the blob is fully contained in the current chunk
40
+ * (bounded by whitespace or string edges). Partial blobs pass through
41
+ * and the next chunk's sanitizer catches them when the whitespace hits.
42
+ *
43
+ * In practice, multimodal echos from the gateway arrive in a small
44
+ * number of large chunks so the full-blob case is the common one.
45
+ */
46
+ function stripBase64BlobsInline(text) {
47
+ const BLOB = /(?:data:[\w/.+-]+;base64,)?[A-Za-z0-9+/]{120,}={0,2}/g;
48
+ return text.replace(BLOB, (match) => `[base64 stripped: ${match.length} chars]`);
49
+ }
50
+ /**
51
+ * Returns true if the request looks like a plan-generation call that needs
52
+ * structured JSON output. This is intentionally conservative to avoid forcing
53
+ * JSON mode for normal conversational replies.
54
+ */
55
+ function detectJsonRequest(request) {
56
+ const getLowerText = (content) => {
57
+ const text = typeof content === 'string'
58
+ ? content
59
+ : content.map(p => p.type === 'text' ? p.text : '').join(' ');
60
+ return text.toLowerCase();
61
+ };
62
+ const systemText = request.messages
63
+ .filter(message => message.role === 'system')
64
+ .map(message => getLowerText(message.content))
65
+ .join('\n');
66
+ const lastUserText = [...request.messages]
67
+ .reverse()
68
+ .find(message => message.role === 'user');
69
+ const combined = `${systemText}\n${lastUserText ? getLowerText(lastUserText.content) : ''}`;
70
+ const hasJsonDirective = /\b(respond with json(?: only)?|return (?:valid )?json|output (?:valid )?json|json only|format\s*[:=]\s*"?json"?|strictly json)\b/.test(combined);
71
+ if (!hasJsonDirective) {
72
+ return false;
73
+ }
74
+ const hasPlanSignal = /\b(plan|planning|steps?)\b|execution plan|agent plan|schema|"steps"|"id"|"title"|"description"/.test(combined);
75
+ return hasPlanSignal;
76
+ }
77
+ function extractTextContent(content) {
78
+ return splitMessageContent(content).text;
79
+ }
80
+ function splitMessageContent(content) {
81
+ if (typeof content === 'string') {
82
+ return { text: content, imageUrls: [] };
83
+ }
84
+ if (!Array.isArray(content)) {
85
+ return { text: '', imageUrls: [] };
86
+ }
87
+ const textParts = [];
88
+ const imageUrls = [];
89
+ for (const part of content) {
90
+ if (!part) {
91
+ continue;
92
+ }
93
+ if (part.type === 'text') {
94
+ const text = typeof part.text === 'string' ? part.text : part.text != null ? String(part.text) : '';
95
+ if (text.length > 0) {
96
+ textParts.push(text);
97
+ }
98
+ continue;
99
+ }
100
+ if (part.type === 'image_url') {
101
+ const url = extractImageUrl(part);
102
+ if (url) {
103
+ imageUrls.push(url);
104
+ }
105
+ }
106
+ }
107
+ return {
108
+ text: textParts.join('\n'),
109
+ imageUrls: dedupeStrings(imageUrls)
110
+ };
111
+ }
112
+ function dedupeStrings(values) {
113
+ const seen = new Set();
114
+ const deduped = [];
115
+ for (const value of values) {
116
+ const normalized = value.trim();
117
+ if (!normalized || seen.has(normalized)) {
118
+ continue;
119
+ }
120
+ seen.add(normalized);
121
+ deduped.push(normalized);
122
+ }
123
+ return deduped;
124
+ }
125
+ function normalizeOllamaImage(candidate) {
126
+ const normalized = normalizeImageUrl(candidate);
127
+ if (!normalized) {
128
+ return undefined;
129
+ }
130
+ if (/^https?:/i.test(normalized)) {
131
+ return undefined;
132
+ }
133
+ if (!/^data:/i.test(normalized)) {
134
+ return normalized;
135
+ }
136
+ const commaIndex = normalized.indexOf(',');
137
+ if (commaIndex < 0 || commaIndex === normalized.length - 1) {
138
+ return undefined;
139
+ }
140
+ return normalized.slice(commaIndex + 1).trim();
141
+ }
142
+ function normalizeOllamaMessages(request) {
143
+ const normalizedMessages = request.messages.map((message) => {
144
+ const { text, imageUrls } = splitMessageContent(message.content);
145
+ const images = imageUrls
146
+ .map((url) => normalizeOllamaImage(url))
147
+ .filter((image) => Boolean(image));
148
+ if (images.length > 0) {
149
+ return { role: message.role, content: text, images };
150
+ }
151
+ return { role: message.role, content: text };
152
+ });
153
+ const requestImages = (Array.isArray(request.images) ? request.images : [])
154
+ .map((image) => normalizeOllamaImage(image))
155
+ .filter((image) => Boolean(image));
156
+ if (requestImages.length === 0) {
157
+ return normalizedMessages;
158
+ }
159
+ for (let index = normalizedMessages.length - 1; index >= 0; index -= 1) {
160
+ if (normalizedMessages[index]?.role !== 'user') {
161
+ continue;
162
+ }
163
+ const existing = normalizedMessages[index].images ?? [];
164
+ normalizedMessages[index].images = dedupeStrings([...existing, ...requestImages]);
165
+ return normalizedMessages;
166
+ }
167
+ normalizedMessages.push({
168
+ role: 'user',
169
+ content: '',
170
+ images: requestImages
171
+ });
172
+ return normalizedMessages;
173
+ }
174
+ function collectBanditPayloadImages(request) {
175
+ const requestImages = (Array.isArray(request.images) ? request.images : [])
176
+ .map((image) => normalizeImageUrl(image))
177
+ .filter((image) => Boolean(image));
178
+ const lastUserMessage = [...request.messages]
179
+ .reverse()
180
+ .find((message) => message.role === 'user');
181
+ const messageImages = lastUserMessage
182
+ ? splitMessageContent(lastUserMessage.content).imageUrls
183
+ : [];
184
+ return dedupeStrings([...requestImages, ...messageImages]);
185
+ }
186
+ async function* streamOllamaResponse(response) {
187
+ const body = response.body;
188
+ if (!body)
189
+ throw new Error('Ollama response has no body.');
190
+ const reader = body.getReader();
191
+ const decoder = new TextDecoder();
192
+ let buffer = '';
193
+ let stallWarned = false;
194
+ for (;;) {
195
+ const { value, done } = await (0, streamIdleTimeout_1.readWithIdleTimeout)(reader, {
196
+ idleMs: streamIdleTimeout_1.DEFAULT_STREAM_IDLE_MS,
197
+ warnAfterMs: streamIdleTimeout_1.DEFAULT_STREAM_WARN_MS,
198
+ abortLabel: 'Ollama stream',
199
+ onWarn: (elapsedMs) => {
200
+ if (stallWarned)
201
+ return;
202
+ stallWarned = true;
203
+ console.warn(`[banditEngineProvider] Ollama stream went quiet at ${elapsedMs}ms — still waiting…`);
204
+ }
205
+ });
206
+ if (done)
207
+ break;
208
+ buffer += decoder.decode(value, { stream: true });
209
+ const lines = buffer.split('\n');
210
+ buffer = lines.pop() ?? '';
211
+ for (const line of lines) {
212
+ const trimmed = line.trim();
213
+ if (!trimmed)
214
+ continue;
215
+ try {
216
+ const chunk = JSON.parse(trimmed);
217
+ const content = sanitizeOllamaOutput(chunk.message?.content ?? '');
218
+ const thinking = chunk.message?.thinking;
219
+ if (content || thinking) {
220
+ yield {
221
+ message: {
222
+ content,
223
+ role: 'assistant',
224
+ ...(thinking ? { thinking } : {})
225
+ },
226
+ done: false
227
+ };
228
+ }
229
+ if (chunk.done) {
230
+ yield { message: { content: '', role: 'assistant' }, done: true };
231
+ return;
232
+ }
233
+ }
234
+ catch {
235
+ // skip malformed lines
236
+ }
237
+ }
238
+ }
239
+ yield { message: { content: '', role: 'assistant' }, done: true };
240
+ }
241
+ function createDirectOllamaProvider(baseUrl, defaultModel, extraHeaders) {
242
+ // Caller-supplied headers (Authorization, Cloudflare Access, etc.) are
243
+ // merged once here; Content-Type always wins to avoid breaking the API.
244
+ const mergedHeaders = {
245
+ ...(extraHeaders ?? {}),
246
+ 'Content-Type': 'application/json'
247
+ };
248
+ return {
249
+ chat(request) {
250
+ const iterator = async function* () {
251
+ const model = request.model || defaultModel;
252
+ const wantsJson = detectJsonRequest(request);
253
+ // Tier-derived defaults for num_ctx + keep_alive. Without these
254
+ // Ollama falls back to a 2048-token chat window — too small for
255
+ // our agent system prompt (~3-4k tokens) plus tool results, so
256
+ // the framework framing gets sheared off and the model replies
257
+ // from its raw conversational persona. Caller-supplied
258
+ // request.options override these per-request (so tests / power
259
+ // users can still opt out or up the window).
260
+ const runtimeDefaults = (0, modelCapabilities_1.resolveOllamaRuntimeOptions)(model);
261
+ const payload = {
262
+ model,
263
+ messages: normalizeOllamaMessages(request),
264
+ stream: request.stream !== false,
265
+ keep_alive: runtimeDefaults.keep_alive,
266
+ options: {
267
+ temperature: request.temperature ?? 0.2,
268
+ num_ctx: runtimeDefaults.num_ctx,
269
+ ...(request.options ?? {})
270
+ }
271
+ };
272
+ // `think` is a top-level request field in Ollama, not nested
273
+ // under `options` (Ollama rejects `PARAMETER think` in Modelfiles
274
+ // — it's a per-request toggle only). Reasoning-capable models
275
+ // like Qwen 3.6 ship thinking ON by default; for agent tool-use
276
+ // we disable it via resolveOllamaRuntimeOptions to save the
277
+ // 8-30s thinking preamble per turn. Per-request `request.think`
278
+ // (explicitly passed by the host for `/think on` / extension
279
+ // setting overrides) wins over the runtime default.
280
+ if (request.think !== undefined) {
281
+ payload.think = request.think;
282
+ }
283
+ else if (runtimeDefaults.think !== undefined) {
284
+ payload.think = runtimeDefaults.think;
285
+ }
286
+ if (wantsJson) {
287
+ payload.format = 'json';
288
+ }
289
+ // Native tool calling: when the caller provides `tools`, pass
290
+ // them through to Ollama so the model's chat template serializes
291
+ // the schemas efficiently (30-50% fewer tokens than our text
292
+ // XML block). Streaming is DISABLED for native-tools requests
293
+ // because Ollama's streaming path currently emits tool_calls
294
+ // only on the terminal chunk and interleaving that with partial
295
+ // content makes the downstream translator brittle. Non-native
296
+ // requests keep streaming as before.
297
+ const hasNativeTools = Array.isArray(request.tools) && request.tools.length > 0;
298
+ if (hasNativeTools) {
299
+ payload.tools = request.tools;
300
+ payload.stream = false;
301
+ }
302
+ const response = await fetchWithRetry(`${baseUrl}/api/chat`, {
303
+ method: 'POST',
304
+ headers: mergedHeaders,
305
+ body: JSON.stringify(payload)
306
+ });
307
+ if (!response.ok) {
308
+ const detail = await safeReadText(response);
309
+ throw new Error(`Ollama request failed: ${response.status} ${response.statusText}${detail ? ` – ${detail}` : ''}`);
310
+ }
311
+ if (payload.stream !== false) {
312
+ yield* streamOllamaResponse(response);
313
+ }
314
+ else {
315
+ const data = await response.json();
316
+ let content = sanitizeOllamaOutput(data.message?.content ?? '');
317
+ // Translate Ollama's native tool_calls into inline text
318
+ // markup so the ToolUseLoop's existing parseToolCalls()
319
+ // picks them up without any downstream change. Each call
320
+ // becomes one `<tool_call>{...}</tool_call>` block appended
321
+ // to the response text.
322
+ const toolCalls = data.message?.tool_calls;
323
+ if (Array.isArray(toolCalls) && toolCalls.length > 0) {
324
+ const markers = toolCalls.map(tc => {
325
+ const name = tc.function?.name ?? '';
326
+ const args = tc.function?.arguments ?? {};
327
+ // Ollama returns arguments as an already-parsed object;
328
+ // stringify to match the wire format our parser expects.
329
+ // Stringify values to strings — ToolRegistry schemas
330
+ // declare every param as type: 'string' and our tools
331
+ // read String(params.path), etc.
332
+ const params = {};
333
+ if (args && typeof args === 'object') {
334
+ for (const [k, v] of Object.entries(args)) {
335
+ params[k] = typeof v === 'string' ? v : JSON.stringify(v);
336
+ }
337
+ }
338
+ return `<tool_call>${JSON.stringify({ name, params })}</tool_call>`;
339
+ }).join('\n');
340
+ content = content ? `${content}\n${markers}` : markers;
341
+ }
342
+ yield { message: { content, role: 'assistant' }, done: true };
343
+ }
344
+ };
345
+ return iterator();
346
+ }
347
+ };
348
+ }
349
+ async function createProvider(settings) {
350
+ if (settings.kind === 'bandit') {
351
+ const apiUrl = normalizeBanditApiUrl(settings.apiUrl);
352
+ const apiKey = settings.apiKey?.trim();
353
+ return createDirectBanditProvider(apiUrl, apiKey);
354
+ }
355
+ if (settings.kind === 'ollama') {
356
+ // Use node URL (RTX 5090) if configured, otherwise fall back to local Ollama
357
+ const rawUrl = settings.ollamaNodeUrl?.trim()
358
+ ? settings.ollamaNodeUrl.trim()
359
+ : settings.ollamaUrl;
360
+ const baseUrl = normalizeUrl(rawUrl, DEFAULT_OLLAMA_URL);
361
+ const model = settings.ollamaModel?.trim() || DEFAULT_OLLAMA_MODEL;
362
+ return createDirectOllamaProvider(baseUrl, model, settings.ollamaHeaders);
363
+ }
364
+ if (settings.kind === 'openai-compatible') {
365
+ const rawBase = settings.openaiBaseUrl?.trim();
366
+ if (!rawBase) {
367
+ throw new Error('openai-compatible provider requires `openaiBaseUrl` (e.g. http://localhost:1234/v1, https://api.together.xyz/v1).');
368
+ }
369
+ const baseUrl = rawBase.replace(/\/+$/, '');
370
+ const apiUrl = `${baseUrl}/chat/completions`;
371
+ const apiKey = settings.openaiApiKey?.trim();
372
+ return createDirectOpenAICompatibleProvider(apiUrl, apiKey, settings.openaiHeaders);
373
+ }
374
+ throw new Error(`Unsupported provider kind: ${settings.kind}`);
375
+ }
376
+ /**
377
+ * Generic OpenAI-compatible chat provider.
378
+ *
379
+ * Reuses the same payload shape and SSE streaming helpers as the Bandit
380
+ * gateway path — every endpoint we care about (LM Studio, llama.cpp,
381
+ * vLLM, OpenAI, OpenRouter, Together, Groq, DeepSeek, xAI) speaks the
382
+ * `POST /v1/chat/completions` shape with `data: {…}` SSE chunks. The
383
+ * Bandit-specific bits (`X-Bandit-Source`/`X-Skip-Seed-Pack` headers,
384
+ * 429 rate-limit special-case JSON parsing) are intentionally NOT
385
+ * forwarded here — those are gateway-specific. Errors fall through to a
386
+ * generic message so the host shows the upstream provider's actual
387
+ * status text.
388
+ */
389
+ function createDirectOpenAICompatibleProvider(apiUrl, apiKey, extraHeaders) {
390
+ return {
391
+ chat(request) {
392
+ const controller = new AbortController();
393
+ const iterator = async function* () {
394
+ try {
395
+ const payload = serializeBanditPayload(request);
396
+ const response = await fetchWithRetry(apiUrl, {
397
+ method: 'POST',
398
+ headers: buildOpenAICompatibleHeaders(apiKey, extraHeaders),
399
+ body: JSON.stringify(payload),
400
+ signal: controller.signal
401
+ });
402
+ if (!response.ok) {
403
+ const detail = await safeReadText(response);
404
+ throw new Error(`openai-compatible request failed: ${response.status} ${response.statusText}${detail ? ` – ${detail}` : ''}`);
405
+ }
406
+ if (payload.stream) {
407
+ yield* streamBanditResponse(response);
408
+ }
409
+ else {
410
+ const data = (await response.json());
411
+ if (data.error?.message) {
412
+ throw new Error(data.error.message);
413
+ }
414
+ const text = extractTextFromBanditResponse(data);
415
+ const thinking = typeof data.choices?.[0]?.message?.thinking === 'string'
416
+ ? data.choices[0].message.thinking
417
+ : undefined;
418
+ yield {
419
+ message: {
420
+ content: text,
421
+ role: 'assistant',
422
+ ...(thinking ? { thinking } : {})
423
+ },
424
+ done: true
425
+ };
426
+ }
427
+ }
428
+ finally {
429
+ controller.abort();
430
+ }
431
+ };
432
+ return iterator();
433
+ }
434
+ };
435
+ }
436
+ function buildOpenAICompatibleHeaders(apiKey, extra) {
437
+ const headers = { 'Content-Type': 'application/json' };
438
+ if (apiKey)
439
+ headers.Authorization = `Bearer ${apiKey}`;
440
+ if (extra) {
441
+ for (const [key, value] of Object.entries(extra)) {
442
+ if (!key || typeof key !== 'string' || typeof value !== 'string')
443
+ continue;
444
+ if (key.toLowerCase() === 'content-type')
445
+ continue;
446
+ headers[key] = value;
447
+ }
448
+ }
449
+ return headers;
450
+ }
451
+ function createDirectBanditProvider(apiUrl, apiKey) {
452
+ return {
453
+ chat(request) {
454
+ const controller = new AbortController();
455
+ const iterator = async function* () {
456
+ try {
457
+ const payload = serializeBanditPayload(request);
458
+ // (Multimodal debug dump removed — it was writing the full
459
+ // base64 image payload to stderr on every image turn, which
460
+ // leaked into users' terminals and looked like 100KB of
461
+ // gibberish before the actual response arrived.)
462
+ const response = await fetchWithRetry(apiUrl, {
463
+ method: 'POST',
464
+ headers: buildHeaders(apiKey),
465
+ body: JSON.stringify(payload),
466
+ signal: controller.signal
467
+ });
468
+ if (!response.ok) {
469
+ const detail = await safeReadText(response);
470
+ // Special-case 429 (rate limit). Parse the JSON body so the
471
+ // host can relay the window/resetsAt details to the user
472
+ // instead of just showing a generic "request failed." The
473
+ // thrown Error name is inspected by the host to toast
474
+ // differently for rate limits vs generic failures.
475
+ if (response.status === 429) {
476
+ let rateMessage = 'Rate limit reached. Email team@burtson.ai to upgrade.';
477
+ let window = 'session';
478
+ let resetsAtUnix;
479
+ try {
480
+ const parsed = JSON.parse(detail);
481
+ if (parsed?.message)
482
+ rateMessage = parsed.message;
483
+ if (parsed?.window)
484
+ window = parsed.window;
485
+ if (typeof parsed?.resetsAtUnix === 'number')
486
+ resetsAtUnix = parsed.resetsAtUnix;
487
+ }
488
+ catch {
489
+ // Non-JSON 429 body — fall through with defaults.
490
+ }
491
+ const err = new Error(rateMessage);
492
+ err.isRateLimit = true;
493
+ err.window = window;
494
+ err.resetsAtUnix = resetsAtUnix;
495
+ throw err;
496
+ }
497
+ throw new Error(`Bandit request failed: ${response.status} ${response.statusText}${detail ? ` – ${detail}` : ''}`);
498
+ }
499
+ // Gateway-side workaround signal — when the Ollama 0.24.0 qwen3.5
500
+ // parser 500s on bandit-logic, the gateway retries upstream with
501
+ // tools[] stripped and sets this header. The retry succeeded if we
502
+ // got here; just surface the fact so traces show how often the
503
+ // upstream parser bug is firing. Remove this log once the upstream
504
+ // qwen3.6 parser ships and the gateway workaround is reverted.
505
+ if (response.headers.get('x-upstream-retry-without-tools') === 'true') {
506
+ console.warn('[banditEngineProvider] gateway stripped tools[] this turn (qwen3.6 parser workaround).');
507
+ }
508
+ if (payload.stream) {
509
+ yield* streamBanditResponse(response);
510
+ }
511
+ else {
512
+ const data = (await response.json());
513
+ if (data.error?.message) {
514
+ throw new Error(data.error.message);
515
+ }
516
+ const text = extractTextFromBanditResponse(data);
517
+ const thinking = typeof data.choices?.[0]?.message?.thinking === 'string'
518
+ ? data.choices[0].message.thinking
519
+ : undefined;
520
+ yield {
521
+ message: {
522
+ content: text,
523
+ role: 'assistant',
524
+ ...(thinking ? { thinking } : {})
525
+ },
526
+ done: true
527
+ };
528
+ }
529
+ }
530
+ finally {
531
+ controller.abort();
532
+ }
533
+ };
534
+ return iterator();
535
+ }
536
+ };
537
+ }
538
+ function buildHeaders(apiKey) {
539
+ const headers = {
540
+ 'Content-Type': 'application/json',
541
+ // Agent framework requests carry structured tool-call escape rules in
542
+ // the system prompt. Injecting an additional RAG system message at the
543
+ // gateway dilutes those instructions and causes malformed JSON on long
544
+ // content strings (verified root cause — see v1.5.24 changelog).
545
+ // The gateway's SeedPackContextService should short-circuit when this
546
+ // header is present.
547
+ 'X-Bandit-Source': 'agent-framework',
548
+ 'X-Skip-Seed-Pack': 'true'
549
+ };
550
+ if (apiKey) {
551
+ headers.Authorization = `Bearer ${apiKey}`;
552
+ }
553
+ return headers;
554
+ }
555
+ function serializeBanditPayload(request) {
556
+ const payloadImages = collectBanditPayloadImages(request);
557
+ const messages = request.messages.map((message) => ({
558
+ role: message.role,
559
+ content: normalizeBanditMessageContent(message.content)
560
+ }));
561
+ // Promote top-level `request.images` onto the last user message as
562
+ // content parts. The tool-use adapter (extension.ts) attaches
563
+ // images via `request.images` since ToolLoopMessage is a plain
564
+ // { role, content: string } — it has no notion of content parts.
565
+ // Without this splice, the Bandit gateway (OpenAI-compatible)
566
+ // reads message.content only and the image silently never reaches
567
+ // the model. Ollama's normalizeOllamaMessages does the equivalent
568
+ // splice onto message.images; this is the symmetric fix for the
569
+ // hosted path.
570
+ if (payloadImages.length > 0) {
571
+ for (let i = messages.length - 1; i >= 0; i--) {
572
+ if (messages[i].role !== 'user')
573
+ continue;
574
+ const existingUrls = new Set(messages[i].content
575
+ .filter((part) => part.type === 'image_url')
576
+ .map((part) => part.image_url.url));
577
+ for (const url of payloadImages) {
578
+ if (!existingUrls.has(url)) {
579
+ messages[i].content.push({ type: 'image_url', image_url: { url } });
580
+ }
581
+ }
582
+ break;
583
+ }
584
+ }
585
+ const payload = {
586
+ model: request.model,
587
+ messages,
588
+ temperature: request.temperature,
589
+ top_p: typeof request.options?.top_p === 'number' ? request.options.top_p : undefined,
590
+ stream: request.stream !== false
591
+ };
592
+ // Forward native tool-calling schemas on the cloud path. The
593
+ // Gateway's BuildOllamaRequestPayloadAsync lets unknown top-level
594
+ // keys flow through via AdditionalProperties, so `tools` reaches
595
+ // the upstream Ollama /api/chat and the model gets structured tool
596
+ // calling. Without this, bandit-logic (Qwen 2.5 Coder) had neither
597
+ // the text-prompt tool block (skipped when nativeTools=true) NOR
598
+ // the native tools field, and emitted bare JSON tool-call prose
599
+ // that the downstream parser couldn't extract.
600
+ if (Array.isArray(request.tools) && request.tools.length > 0) {
601
+ payload.tools = request.tools;
602
+ // Ollama streams tool_calls only on the terminal chunk for native
603
+ // tool calling — disable streaming for these requests so the
604
+ // provider's non-streaming translator (see ollama path at ~line
605
+ // 334) can pair tool_calls back to inline <tool_call> markup.
606
+ payload.stream = false;
607
+ }
608
+ // Keep the top-level images field too for backward compat with any
609
+ // consumer that has been reading them there historically.
610
+ if (payloadImages.length > 0) {
611
+ payload.images = payloadImages;
612
+ }
613
+ // Forward the thinking override to the gateway. Symmetric to the
614
+ // direct Ollama path — per-request `think` overrides runtime
615
+ // defaults, and AdditionalProperties pass-through on the gateway
616
+ // side means it reaches upstream Ollama as a top-level field.
617
+ if (request.think !== undefined) {
618
+ payload.think = request.think;
619
+ }
620
+ else {
621
+ const runtimeDefaults = (0, modelCapabilities_1.resolveOllamaRuntimeOptions)(request.model);
622
+ if (runtimeDefaults.think !== undefined) {
623
+ payload.think = runtimeDefaults.think;
624
+ }
625
+ }
626
+ return payload;
627
+ }
628
+ function normalizeBanditMessageContent(content) {
629
+ if (Array.isArray(content)) {
630
+ const normalized = [];
631
+ for (const part of content) {
632
+ if (!part) {
633
+ continue;
634
+ }
635
+ if (part.type === 'text') {
636
+ const text = typeof part.text === 'string' ? part.text : part.text != null ? String(part.text) : '';
637
+ if (text.length > 0) {
638
+ normalized.push({ type: 'text', text });
639
+ }
640
+ continue;
641
+ }
642
+ if (part.type === 'image_url') {
643
+ const url = extractImageUrl(part);
644
+ if (url) {
645
+ normalized.push({ type: 'image_url', image_url: { url } });
646
+ }
647
+ }
648
+ }
649
+ if (normalized.length > 0) {
650
+ return normalized;
651
+ }
652
+ }
653
+ const text = typeof content === 'string' ? content : content != null ? String(content) : '';
654
+ return [{ type: 'text', text }];
655
+ }
656
+ function extractImageUrl(part) {
657
+ if (!part || part.type !== 'image_url') {
658
+ return undefined;
659
+ }
660
+ const imageField = part.image_url;
661
+ if (typeof imageField === 'string') {
662
+ return normalizeImageUrl(imageField);
663
+ }
664
+ if (imageField && typeof imageField.url === 'string') {
665
+ return normalizeImageUrl(imageField.url);
666
+ }
667
+ return undefined;
668
+ }
669
+ function normalizeImageUrl(candidate) {
670
+ if (typeof candidate !== 'string') {
671
+ return undefined;
672
+ }
673
+ const trimmed = candidate.trim();
674
+ if (!trimmed) {
675
+ return undefined;
676
+ }
677
+ if (/^data:/i.test(trimmed) || /^https?:/i.test(trimmed)) {
678
+ return trimmed;
679
+ }
680
+ return `data:image/png;base64,${trimmed}`;
681
+ }
682
+ function extractTextFromBanditResponse(response) {
683
+ const [firstChoice] = response.choices ?? [];
684
+ if (!firstChoice) {
685
+ throw new Error('Bandit response missing choices.');
686
+ }
687
+ if (firstChoice.text) {
688
+ return firstChoice.text;
689
+ }
690
+ const message = firstChoice.message;
691
+ if (!message) {
692
+ throw new Error('Bandit response missing message content.');
693
+ }
694
+ // Native tool-call translation for the cloud path. When the gateway
695
+ // forwarded a `tools` field, Ollama upstream returns `tool_calls` on
696
+ // the terminal message. We translate each call into inline
697
+ // `<tool_call>{"name":...,"params":{...}}</tool_call>` markup so the
698
+ // ToolUseLoop's existing parser picks them up unchanged — same
699
+ // contract the direct-Ollama path uses at line ~358.
700
+ //
701
+ // `arguments` arrives as either:
702
+ // - a JSON STRING (OpenAI-compat convention — what our gateway
703
+ // emits, what any OpenAI SDK client expects)
704
+ // - an object (Ollama's native shape, passed through if the
705
+ // gateway wasn't the translator)
706
+ // Handle both so the cloud and direct-Ollama paths stay symmetric.
707
+ let toolCallMarkup = '';
708
+ const toolCalls = message.tool_calls;
709
+ if (Array.isArray(toolCalls) && toolCalls.length > 0) {
710
+ const markers = toolCalls.map(tc => {
711
+ const name = tc.function?.name ?? '';
712
+ let args = tc.function?.arguments ?? {};
713
+ if (typeof args === 'string') {
714
+ try {
715
+ args = JSON.parse(args);
716
+ }
717
+ catch {
718
+ args = {};
719
+ }
720
+ }
721
+ const params = {};
722
+ if (args && typeof args === 'object') {
723
+ for (const [k, v] of Object.entries(args)) {
724
+ params[k] = typeof v === 'string' ? v : JSON.stringify(v);
725
+ }
726
+ }
727
+ return `<tool_call>${JSON.stringify({ name, params })}</tool_call>`;
728
+ });
729
+ toolCallMarkup = markers.join('\n');
730
+ }
731
+ let baseText = '';
732
+ if (typeof message.content === 'string') {
733
+ baseText = message.content;
734
+ }
735
+ else if (Array.isArray(message.content)) {
736
+ const parts = message.content
737
+ .filter((block) => block.type === 'text' && typeof block.text === 'string')
738
+ .map((block) => block.text ?? '');
739
+ baseText = parts.join('\n\n');
740
+ }
741
+ if (!baseText && !toolCallMarkup) {
742
+ // Soft-fail with forensics. The previous behaviour (throw) bubbled
743
+ // up to the user as a hard error mid-conversation when the gateway
744
+ // emitted an unusual response shape — a `tool_calls`-only response
745
+ // where the gateway dropped the array, a `thinking`-only response,
746
+ // a content-parts array with no text blocks, etc. The tool-use loop
747
+ // already has an empty-response retry path that handles "" cleanly,
748
+ // so returning empty here lets the model recover on its own turn
749
+ // instead of crashing the whole run.
750
+ //
751
+ // The console warn captures the full message shape for the next
752
+ // diagnostic pass — without this we have no idea what the gateway
753
+ // actually sent. Truncated to 500 chars so a runaway response
754
+ // doesn't flood the log.
755
+ try {
756
+ const shape = JSON.stringify(message).slice(0, 500);
757
+ console.warn(`[banditEngineProvider] empty response from gateway, soft-recovering. shape=${shape}`);
758
+ }
759
+ catch {
760
+ console.warn('[banditEngineProvider] empty response from gateway, soft-recovering. (shape unserializable)');
761
+ }
762
+ return '';
763
+ }
764
+ return toolCallMarkup
765
+ ? (baseText ? `${baseText}\n${toolCallMarkup}` : toolCallMarkup)
766
+ : baseText;
767
+ }
768
+ function normalizeBanditApiUrl(value) {
769
+ const trimmed = value?.trim();
770
+ if (!trimmed) {
771
+ return DEFAULT_BANDIT_COMPLETIONS_URL;
772
+ }
773
+ const stripped = trimmed.replace(/\/+$/, '');
774
+ // If the user gave only a base URL (no path beyond "/"), auto-append the
775
+ // standard `/completions` endpoint. Anyone with a real custom path keeps
776
+ // it untouched. Covers the common "they set apiUrl to their host" case.
777
+ try {
778
+ const parsed = new URL(stripped);
779
+ if (parsed.pathname === '' || parsed.pathname === '/') {
780
+ return `${stripped}/completions`;
781
+ }
782
+ }
783
+ catch {
784
+ // Not a valid URL — let the fetch call surface the error itself.
785
+ }
786
+ return stripped;
787
+ }
788
+ function normalizeUrl(value, fallback) {
789
+ const trimmed = value?.trim();
790
+ return trimmed && trimmed.length > 0 ? trimmed.replace(/\/+$/, '') : fallback;
791
+ }
792
+ async function* streamBanditResponse(response) {
793
+ const body = response.body;
794
+ if (!body) {
795
+ throw new Error('Bandit response did not include a readable stream.');
796
+ }
797
+ const reader = body.getReader();
798
+ const decoder = new TextDecoder();
799
+ let buffer = '';
800
+ let emittedDone = false;
801
+ const readChunkText = (chunk) => {
802
+ const readContent = (content) => {
803
+ if (!content) {
804
+ return '';
805
+ }
806
+ if (typeof content === 'string') {
807
+ return content;
808
+ }
809
+ if (!Array.isArray(content)) {
810
+ return '';
811
+ }
812
+ return content
813
+ .map((part) => (part && typeof part.text === 'string' ? part.text : ''))
814
+ .filter((part) => part.length > 0)
815
+ .join('');
816
+ };
817
+ const choice = chunk.choices?.[0];
818
+ const fromDelta = readContent(choice?.delta?.content);
819
+ if (fromDelta) {
820
+ return fromDelta;
821
+ }
822
+ const fromChoiceMessage = readContent(choice?.message?.content);
823
+ if (fromChoiceMessage) {
824
+ return fromChoiceMessage;
825
+ }
826
+ const fromChoiceText = typeof choice?.text === 'string' ? choice.text : '';
827
+ if (fromChoiceText) {
828
+ return fromChoiceText;
829
+ }
830
+ const fromMessage = readContent(chunk.message?.content);
831
+ if (fromMessage) {
832
+ return fromMessage;
833
+ }
834
+ return typeof chunk.response === 'string' ? chunk.response : '';
835
+ };
836
+ /** Extract chain-of-thought reasoning from any of the standard
837
+ * positions the gateway might emit it — delta.thinking (streaming
838
+ * OpenAI-compat), message.thinking (non-streaming fallback), or the
839
+ * top-level message.thinking (direct Ollama pass-through). */
840
+ const readChunkThinking = (chunk) => {
841
+ const choice = chunk.choices?.[0];
842
+ const fromDelta = typeof choice?.delta?.thinking === 'string' ? choice.delta.thinking : '';
843
+ if (fromDelta) {
844
+ return fromDelta;
845
+ }
846
+ const fromChoiceMessage = typeof choice?.message?.thinking === 'string' ? choice.message.thinking : '';
847
+ if (fromChoiceMessage) {
848
+ return fromChoiceMessage;
849
+ }
850
+ return typeof chunk.message?.thinking === 'string' ? chunk.message.thinking : '';
851
+ };
852
+ const isDoneChunk = (chunk) => {
853
+ if (chunk.done === true) {
854
+ return true;
855
+ }
856
+ const finishReason = chunk.choices?.[0]?.finish_reason;
857
+ return typeof finishReason === 'string' && finishReason.length > 0;
858
+ };
859
+ const parseLine = (rawLine) => {
860
+ const line = rawLine.trim();
861
+ if (!line || line.startsWith('event:')) {
862
+ return { done: false, responses: [] };
863
+ }
864
+ const payload = line.startsWith('data:') ? line.slice(5).trim() : line;
865
+ if (!payload) {
866
+ return { done: false, responses: [] };
867
+ }
868
+ if (payload === '[DONE]') {
869
+ const responses = [];
870
+ if (!emittedDone) {
871
+ emittedDone = true;
872
+ responses.push({ message: { content: '', role: 'assistant' }, done: true });
873
+ }
874
+ return { done: true, responses };
875
+ }
876
+ try {
877
+ const chunk = JSON.parse(payload);
878
+ const responses = [];
879
+ const errorMessage = typeof chunk.error === 'string'
880
+ ? chunk.error
881
+ : chunk.error?.message;
882
+ if (errorMessage) {
883
+ return {
884
+ done: true,
885
+ responses,
886
+ error: new Error(errorMessage)
887
+ };
888
+ }
889
+ const text = stripBase64BlobsInline(readChunkText(chunk));
890
+ const thinking = readChunkThinking(chunk);
891
+ if (text || thinking) {
892
+ responses.push({
893
+ message: {
894
+ content: text,
895
+ role: 'assistant',
896
+ ...(thinking ? { thinking } : {})
897
+ },
898
+ done: false
899
+ });
900
+ }
901
+ if (isDoneChunk(chunk)) {
902
+ if (!emittedDone) {
903
+ emittedDone = true;
904
+ responses.push({ message: { content: '', role: 'assistant' }, done: true });
905
+ }
906
+ return { done: true, responses };
907
+ }
908
+ return { done: false, responses };
909
+ }
910
+ catch {
911
+ // Ignore malformed keep-alive or non-JSON lines and continue streaming.
912
+ return { done: false, responses: [] };
913
+ }
914
+ };
915
+ // Stream until the reader indicates completion.
916
+ let stallWarned = false;
917
+ for (;;) {
918
+ const { value, done } = await (0, streamIdleTimeout_1.readWithIdleTimeout)(reader, {
919
+ idleMs: streamIdleTimeout_1.DEFAULT_STREAM_IDLE_MS,
920
+ warnAfterMs: streamIdleTimeout_1.DEFAULT_STREAM_WARN_MS,
921
+ abortLabel: 'Bandit stream',
922
+ onWarn: (elapsedMs) => {
923
+ if (stallWarned)
924
+ return;
925
+ stallWarned = true;
926
+ console.warn(`[banditEngineProvider] Bandit stream went quiet at ${elapsedMs}ms — still waiting…`);
927
+ }
928
+ });
929
+ if (value) {
930
+ buffer += decoder.decode(value, { stream: true });
931
+ }
932
+ const lines = buffer.split('\n');
933
+ if (done) {
934
+ buffer = '';
935
+ }
936
+ else {
937
+ buffer = lines.pop() ?? '';
938
+ }
939
+ for (const rawLine of lines) {
940
+ const parsed = parseLine(rawLine);
941
+ if (parsed.error) {
942
+ throw parsed.error;
943
+ }
944
+ for (const responseChunk of parsed.responses) {
945
+ yield responseChunk;
946
+ }
947
+ if (parsed.done) {
948
+ return;
949
+ }
950
+ }
951
+ if (done) {
952
+ break;
953
+ }
954
+ }
955
+ if (!emittedDone) {
956
+ yield { message: { content: '', role: 'assistant' }, done: true };
957
+ }
958
+ }
959
+ async function safeReadText(response) {
960
+ try {
961
+ return await response.text();
962
+ }
963
+ catch {
964
+ return '';
965
+ }
966
+ }
967
+ /**
968
+ * Fetch with retry on transient gateway/network failures. Retries on 5xx
969
+ * status (502/503/504 are the gateway's typical "upstream had a hiccup"
970
+ * codes; 500 from the bandit cloud has been observed once in a session
971
+ * after a long compaction-heavy turn) and on transient network errors
972
+ * (ECONNREFUSED, socket hang up, fetch-failed). Does NOT retry on:
973
+ * - AbortError — the caller cancelled (Esc / signal); honour that.
974
+ * - 429 — rate limited; the caller has its own special-case handling.
975
+ * - 4xx — request-shape problems won't get better by replaying.
976
+ *
977
+ * Backoff is exponential (500ms, 1s, 2s) to a max of 3 retries. The
978
+ * bandit auto-evaluation turn that died with `Bandit request failed: 500
979
+ * Internal Server Error` after compacting 19 messages on iteration 7
980
+ * (2026-05-06 22:24Z) would have survived a single retry — same applies
981
+ * to the "1 failed" subagent, which loses its LLM call to the same kind
982
+ * of transient gateway 5xx.
983
+ */
984
+ async function fetchWithRetry(apiUrl, init, opts) {
985
+ const retries = opts?.retries ?? 3;
986
+ const baseMs = opts?.baseMs ?? 500;
987
+ const transientNetworkRe = /fetch failed|ECONNREFUSED|ETIMEDOUT|EAI_AGAIN|socket hang up|network error/i;
988
+ let lastError;
989
+ for (let attempt = 0; attempt <= retries; attempt++) {
990
+ try {
991
+ const response = await fetch(apiUrl, init);
992
+ if (response.status >= 500 && response.status <= 599) {
993
+ if (attempt < retries) {
994
+ // Drain and discard the body so the connection can be reused
995
+ // by the next attempt; otherwise fetch may keep it pinned.
996
+ try {
997
+ await response.body?.cancel();
998
+ }
999
+ catch { /* ignore */ }
1000
+ await new Promise(r => setTimeout(r, baseMs * Math.pow(2, attempt)));
1001
+ continue;
1002
+ }
1003
+ }
1004
+ return response;
1005
+ }
1006
+ catch (err) {
1007
+ // AbortError = caller pulled the rip-cord. Don't retry.
1008
+ if (err instanceof Error && err.name === 'AbortError')
1009
+ throw err;
1010
+ const msg = err instanceof Error ? err.message : String(err);
1011
+ if (!transientNetworkRe.test(msg) || attempt >= retries)
1012
+ throw err;
1013
+ lastError = err;
1014
+ await new Promise(r => setTimeout(r, baseMs * Math.pow(2, attempt)));
1015
+ }
1016
+ }
1017
+ // Loop guarantees one of the branches above returns or throws; this
1018
+ // line is purely for the type-checker's benefit.
1019
+ throw lastError ?? new Error('fetchWithRetry: exhausted attempts');
1020
+ }
1021
+ //# sourceMappingURL=banditEngineProvider.js.map