@gitkraken/core-gitlens 0.5.109 → 0.5.111

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 (416) hide show
  1. package/CHANGELOG.md +48 -1
  2. package/dist/git/cache.d.ts +111 -6
  3. package/dist/git/cache.d.ts.map +1 -1
  4. package/dist/git/cache.js +312 -43
  5. package/dist/git/cache.js.map +1 -1
  6. package/dist/git/context.d.ts +11 -0
  7. package/dist/git/context.d.ts.map +1 -1
  8. package/dist/git/context.js.map +1 -1
  9. package/dist/git/models/fileStatus.d.ts +1 -0
  10. package/dist/git/models/fileStatus.d.ts.map +1 -1
  11. package/dist/git/models/fileStatus.js +1 -0
  12. package/dist/git/models/fileStatus.js.map +1 -1
  13. package/dist/git/models/issue.d.ts +4 -0
  14. package/dist/git/models/issue.d.ts.map +1 -1
  15. package/dist/git/models/mergeConflicts.d.ts +2 -0
  16. package/dist/git/models/mergeConflicts.d.ts.map +1 -1
  17. package/dist/git/models/pullRequest.d.ts +119 -2
  18. package/dist/git/models/pullRequest.d.ts.map +1 -1
  19. package/dist/git/models/pullRequest.js +27 -1
  20. package/dist/git/models/pullRequest.js.map +1 -1
  21. package/dist/git/models/repository.d.ts +32 -5
  22. package/dist/git/models/repository.d.ts.map +1 -1
  23. package/dist/git/models/repository.js +58 -12
  24. package/dist/git/models/repository.js.map +1 -1
  25. package/dist/git/models/statusFile.d.ts.map +1 -1
  26. package/dist/git/models/statusFile.js +3 -0
  27. package/dist/git/models/statusFile.js.map +1 -1
  28. package/dist/git/providers/branches.d.ts +2 -0
  29. package/dist/git/providers/branches.d.ts.map +1 -1
  30. package/dist/git/providers/commits.d.ts +8 -0
  31. package/dist/git/providers/commits.d.ts.map +1 -1
  32. package/dist/git/providers/config.d.ts +19 -1
  33. package/dist/git/providers/config.d.ts.map +1 -1
  34. package/dist/git/providers/operations.d.ts +1 -0
  35. package/dist/git/providers/operations.d.ts.map +1 -1
  36. package/dist/git/providers/pausedOperations.d.ts +2 -0
  37. package/dist/git/providers/pausedOperations.d.ts.map +1 -1
  38. package/dist/git/providers/status.d.ts +1 -0
  39. package/dist/git/providers/status.d.ts.map +1 -1
  40. package/dist/git/utils/config.utils.d.ts +3 -0
  41. package/dist/git/utils/config.utils.d.ts.map +1 -0
  42. package/dist/git/utils/config.utils.js +8 -0
  43. package/dist/git/utils/config.utils.js.map +1 -0
  44. package/dist/git/utils/issue.utils.d.ts.map +1 -1
  45. package/dist/git/utils/issue.utils.js +2 -0
  46. package/dist/git/utils/issue.utils.js.map +1 -1
  47. package/dist/git/utils/pausedOperationStatus.utils.d.ts +14 -0
  48. package/dist/git/utils/pausedOperationStatus.utils.d.ts.map +1 -1
  49. package/dist/git/utils/pausedOperationStatus.utils.js +23 -0
  50. package/dist/git/utils/pausedOperationStatus.utils.js.map +1 -1
  51. package/dist/git/utils/pullRequest.utils.d.ts +24 -1
  52. package/dist/git/utils/pullRequest.utils.d.ts.map +1 -1
  53. package/dist/git/utils/pullRequest.utils.js +71 -0
  54. package/dist/git/utils/pullRequest.utils.js.map +1 -1
  55. package/dist/git/watching/changeEvent.d.ts +6 -1
  56. package/dist/git/watching/changeEvent.d.ts.map +1 -1
  57. package/dist/git/watching/classifyChange.d.ts.map +1 -1
  58. package/dist/git/watching/classifyChange.js +14 -1
  59. package/dist/git/watching/classifyChange.js.map +1 -1
  60. package/dist/git/watching/watchService.d.ts.map +1 -1
  61. package/dist/git/watching/watchService.js +18 -3
  62. package/dist/git/watching/watchService.js.map +1 -1
  63. package/dist/git/watching/watchSession.d.ts +8 -1
  64. package/dist/git/watching/watchSession.d.ts.map +1 -1
  65. package/dist/git/watching/watchSession.js +38 -6
  66. package/dist/git/watching/watchSession.js.map +1 -1
  67. package/dist/git/watching/watcherPatterns.d.ts +2 -2
  68. package/dist/git/watching/watcherPatterns.d.ts.map +1 -1
  69. package/dist/git/watching/watcherPatterns.js +1 -1
  70. package/dist/git/watching/watcherPatterns.js.map +1 -1
  71. package/dist/git-cli/exec/git.d.ts +1 -1
  72. package/dist/git-cli/exec/git.d.ts.map +1 -1
  73. package/dist/git-cli/exec/git.js +13 -3
  74. package/dist/git-cli/exec/git.js.map +1 -1
  75. package/dist/git-cli/providers/branches.d.ts +19 -0
  76. package/dist/git-cli/providers/branches.d.ts.map +1 -1
  77. package/dist/git-cli/providers/branches.js +282 -78
  78. package/dist/git-cli/providers/branches.js.map +1 -1
  79. package/dist/git-cli/providers/commits.d.ts +4 -0
  80. package/dist/git-cli/providers/commits.d.ts.map +1 -1
  81. package/dist/git-cli/providers/commits.js +84 -11
  82. package/dist/git-cli/providers/commits.js.map +1 -1
  83. package/dist/git-cli/providers/config.d.ts +42 -0
  84. package/dist/git-cli/providers/config.d.ts.map +1 -1
  85. package/dist/git-cli/providers/config.js +186 -5
  86. package/dist/git-cli/providers/config.js.map +1 -1
  87. package/dist/git-cli/providers/contributors.d.ts.map +1 -1
  88. package/dist/git-cli/providers/contributors.js +1 -1
  89. package/dist/git-cli/providers/contributors.js.map +1 -1
  90. package/dist/git-cli/providers/graph.d.ts +2 -2
  91. package/dist/git-cli/providers/graph.d.ts.map +1 -1
  92. package/dist/git-cli/providers/graph.js +27 -9
  93. package/dist/git-cli/providers/graph.js.map +1 -1
  94. package/dist/git-cli/providers/operations.d.ts.map +1 -1
  95. package/dist/git-cli/providers/operations.js +40 -12
  96. package/dist/git-cli/providers/operations.js.map +1 -1
  97. package/dist/git-cli/providers/pausedOperations.d.ts +5 -0
  98. package/dist/git-cli/providers/pausedOperations.d.ts.map +1 -1
  99. package/dist/git-cli/providers/pausedOperations.js +87 -16
  100. package/dist/git-cli/providers/pausedOperations.js.map +1 -1
  101. package/dist/git-cli/providers/refs.d.ts +5 -3
  102. package/dist/git-cli/providers/refs.d.ts.map +1 -1
  103. package/dist/git-cli/providers/refs.js +33 -4
  104. package/dist/git-cli/providers/refs.js.map +1 -1
  105. package/dist/git-cli/providers/status.d.ts +1 -0
  106. package/dist/git-cli/providers/status.d.ts.map +1 -1
  107. package/dist/git-cli/providers/status.js +18 -3
  108. package/dist/git-cli/providers/status.js.map +1 -1
  109. package/dist/git-cli/providers/worktrees.d.ts.map +1 -1
  110. package/dist/git-cli/providers/worktrees.js +4 -0
  111. package/dist/git-cli/providers/worktrees.js.map +1 -1
  112. package/dist/git-cli/service.d.ts.map +1 -1
  113. package/dist/git-cli/service.js.map +1 -1
  114. package/dist/plus/agents/providers/claudeCodeProvider.d.ts +39 -1
  115. package/dist/plus/agents/providers/claudeCodeProvider.d.ts.map +1 -1
  116. package/dist/plus/agents/providers/claudeCodeProvider.js +978 -71
  117. package/dist/plus/agents/providers/claudeCodeProvider.js.map +1 -1
  118. package/dist/plus/agents/providers/claudeCodeTranscript.d.ts +24 -2
  119. package/dist/plus/agents/providers/claudeCodeTranscript.d.ts.map +1 -1
  120. package/dist/plus/agents/providers/claudeCodeTranscript.js +84 -9
  121. package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -1
  122. package/dist/plus/agents/types.d.ts +37 -2
  123. package/dist/plus/agents/types.d.ts.map +1 -1
  124. package/dist/plus/agents/types.js +2 -0
  125. package/dist/plus/agents/types.js.map +1 -1
  126. package/dist/plus/ai/errors.d.ts +10 -0
  127. package/dist/plus/ai/errors.d.ts.map +1 -1
  128. package/dist/plus/ai/errors.js +29 -0
  129. package/dist/plus/ai/errors.js.map +1 -1
  130. package/dist/plus/ai/models/model.d.ts +4 -0
  131. package/dist/plus/ai/models/model.d.ts.map +1 -1
  132. package/dist/plus/ai/models/model.js +51 -6
  133. package/dist/plus/ai/models/model.js.map +1 -1
  134. package/dist/plus/ai/models/promptTemplates.d.ts +1 -1
  135. package/dist/plus/ai/models/promptTemplates.d.ts.map +1 -1
  136. package/dist/plus/ai/models/provider.d.ts +60 -2
  137. package/dist/plus/ai/models/provider.d.ts.map +1 -1
  138. package/dist/plus/ai/prompts.d.ts +12 -0
  139. package/dist/plus/ai/prompts.d.ts.map +1 -1
  140. package/dist/plus/ai/prompts.js +177 -61
  141. package/dist/plus/ai/prompts.js.map +1 -1
  142. package/dist/plus/ai/providers/anthropicProvider.d.ts +10 -2
  143. package/dist/plus/ai/providers/anthropicProvider.d.ts.map +1 -1
  144. package/dist/plus/ai/providers/anthropicProvider.js +139 -46
  145. package/dist/plus/ai/providers/anthropicProvider.js.map +1 -1
  146. package/dist/plus/ai/providers/deepSeekProvider.d.ts +2 -0
  147. package/dist/plus/ai/providers/deepSeekProvider.d.ts.map +1 -1
  148. package/dist/plus/ai/providers/deepSeekProvider.js +10 -21
  149. package/dist/plus/ai/providers/deepSeekProvider.js.map +1 -1
  150. package/dist/plus/ai/providers/geminiProvider.d.ts +1 -0
  151. package/dist/plus/ai/providers/geminiProvider.d.ts.map +1 -1
  152. package/dist/plus/ai/providers/geminiProvider.js +19 -0
  153. package/dist/plus/ai/providers/geminiProvider.js.map +1 -1
  154. package/dist/plus/ai/providers/gitkrakenProvider.d.ts +5 -1
  155. package/dist/plus/ai/providers/gitkrakenProvider.d.ts.map +1 -1
  156. package/dist/plus/ai/providers/gitkrakenProvider.js +118 -3
  157. package/dist/plus/ai/providers/gitkrakenProvider.js.map +1 -1
  158. package/dist/plus/ai/providers/huggingFaceProvider.d.ts +1 -0
  159. package/dist/plus/ai/providers/huggingFaceProvider.d.ts.map +1 -1
  160. package/dist/plus/ai/providers/huggingFaceProvider.js +5 -0
  161. package/dist/plus/ai/providers/huggingFaceProvider.js.map +1 -1
  162. package/dist/plus/ai/providers/mistralProvider.d.ts +3 -1
  163. package/dist/plus/ai/providers/mistralProvider.d.ts.map +1 -1
  164. package/dist/plus/ai/providers/mistralProvider.js +99 -19
  165. package/dist/plus/ai/providers/mistralProvider.js.map +1 -1
  166. package/dist/plus/ai/providers/ollamaProvider.d.ts +4 -3
  167. package/dist/plus/ai/providers/ollamaProvider.d.ts.map +1 -1
  168. package/dist/plus/ai/providers/ollamaProvider.js +38 -3
  169. package/dist/plus/ai/providers/ollamaProvider.js.map +1 -1
  170. package/dist/plus/ai/providers/openAICompatibleProvider.d.ts +1 -0
  171. package/dist/plus/ai/providers/openAICompatibleProvider.d.ts.map +1 -1
  172. package/dist/plus/ai/providers/openAICompatibleProvider.js +4 -0
  173. package/dist/plus/ai/providers/openAICompatibleProvider.js.map +1 -1
  174. package/dist/plus/ai/providers/openAICompatibleProviderBase.d.ts +154 -5
  175. package/dist/plus/ai/providers/openAICompatibleProviderBase.d.ts.map +1 -1
  176. package/dist/plus/ai/providers/openAICompatibleProviderBase.js +259 -10
  177. package/dist/plus/ai/providers/openAICompatibleProviderBase.js.map +1 -1
  178. package/dist/plus/ai/providers/openRouterProvider.d.ts +4 -0
  179. package/dist/plus/ai/providers/openRouterProvider.d.ts.map +1 -1
  180. package/dist/plus/ai/providers/openRouterProvider.js +9 -0
  181. package/dist/plus/ai/providers/openRouterProvider.js.map +1 -1
  182. package/dist/plus/ai/providers/openaiProvider.d.ts +1 -0
  183. package/dist/plus/ai/providers/openaiProvider.d.ts.map +1 -1
  184. package/dist/plus/ai/providers/openaiProvider.js +1 -0
  185. package/dist/plus/ai/providers/openaiProvider.js.map +1 -1
  186. package/dist/plus/ai/providers/responseFormatCache.d.ts +8 -0
  187. package/dist/plus/ai/providers/responseFormatCache.d.ts.map +1 -0
  188. package/dist/plus/ai/providers/responseFormatCache.js +25 -0
  189. package/dist/plus/ai/providers/responseFormatCache.js.map +1 -0
  190. package/dist/plus/ai/providers/xaiProvider.d.ts +1 -0
  191. package/dist/plus/ai/providers/xaiProvider.d.ts.map +1 -1
  192. package/dist/plus/ai/providers/xaiProvider.js +10 -1
  193. package/dist/plus/ai/providers/xaiProvider.js.map +1 -1
  194. package/dist/plus/ai/utils/ai.utils.d.ts +3 -0
  195. package/dist/plus/ai/utils/ai.utils.d.ts.map +1 -1
  196. package/dist/plus/ai/utils/ai.utils.js +13 -0
  197. package/dist/plus/ai/utils/ai.utils.js.map +1 -1
  198. package/dist/plus/ai/utils/results.utils.d.ts +16 -2
  199. package/dist/plus/ai/utils/results.utils.d.ts.map +1 -1
  200. package/dist/plus/ai/utils/results.utils.js +204 -28
  201. package/dist/plus/ai/utils/results.utils.js.map +1 -1
  202. package/dist/plus/git-github/api/github.d.ts +92 -4
  203. package/dist/plus/git-github/api/github.d.ts.map +1 -1
  204. package/dist/plus/git-github/api/github.js +324 -20
  205. package/dist/plus/git-github/api/github.js.map +1 -1
  206. package/dist/plus/git-github/api/pullRequestSearchQuery.d.ts +27 -1
  207. package/dist/plus/git-github/api/pullRequestSearchQuery.d.ts.map +1 -1
  208. package/dist/plus/git-github/api/pullRequestSearchQuery.js +73 -6
  209. package/dist/plus/git-github/api/pullRequestSearchQuery.js.map +1 -1
  210. package/dist/plus/git-github/models.d.ts +33 -5
  211. package/dist/plus/git-github/models.d.ts.map +1 -1
  212. package/dist/plus/git-github/models.js +43 -4
  213. package/dist/plus/git-github/models.js.map +1 -1
  214. package/dist/plus/git-github/providers/github/status.d.ts +1 -0
  215. package/dist/plus/git-github/providers/github/status.d.ts.map +1 -1
  216. package/dist/plus/git-github/providers/github/status.js.map +1 -1
  217. package/dist/plus/integrations/context.d.ts +4 -0
  218. package/dist/plus/integrations/context.d.ts.map +1 -1
  219. package/dist/plus/integrations/index.d.ts.map +1 -1
  220. package/dist/plus/integrations/index.js +2 -0
  221. package/dist/plus/integrations/index.js.map +1 -1
  222. package/dist/plus/integrations/integrationService.d.ts +16 -1
  223. package/dist/plus/integrations/integrationService.d.ts.map +1 -1
  224. package/dist/plus/integrations/integrationService.js +9 -1
  225. package/dist/plus/integrations/integrationService.js.map +1 -1
  226. package/dist/plus/integrations/manager.d.ts +45 -5
  227. package/dist/plus/integrations/manager.d.ts.map +1 -1
  228. package/dist/plus/integrations/models/gitHostIntegration.d.ts +18 -3
  229. package/dist/plus/integrations/models/gitHostIntegration.d.ts.map +1 -1
  230. package/dist/plus/integrations/models/gitHostIntegration.js +30 -2
  231. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
  232. package/dist/plus/integrations/models/integration.d.ts +4 -2
  233. package/dist/plus/integrations/models/integration.d.ts.map +1 -1
  234. package/dist/plus/integrations/models/integration.js +2 -2
  235. package/dist/plus/integrations/models/integration.js.map +1 -1
  236. package/dist/plus/integrations/providerFilters.d.ts +1 -1
  237. package/dist/plus/integrations/providerFilters.d.ts.map +1 -1
  238. package/dist/plus/integrations/providers/accounts.d.ts +6 -0
  239. package/dist/plus/integrations/providers/accounts.d.ts.map +1 -0
  240. package/dist/plus/integrations/providers/accounts.js +34 -0
  241. package/dist/plus/integrations/providers/accounts.js.map +1 -0
  242. package/dist/plus/integrations/providers/azure/models.d.ts.map +1 -1
  243. package/dist/plus/integrations/providers/azure/models.js +3 -0
  244. package/dist/plus/integrations/providers/azure/models.js.map +1 -1
  245. package/dist/plus/integrations/providers/bitbucket/models.d.ts.map +1 -1
  246. package/dist/plus/integrations/providers/bitbucket/models.js +1 -0
  247. package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -1
  248. package/dist/plus/integrations/providers/github.d.ts +23 -2
  249. package/dist/plus/integrations/providers/github.d.ts.map +1 -1
  250. package/dist/plus/integrations/providers/github.js +169 -138
  251. package/dist/plus/integrations/providers/github.js.map +1 -1
  252. package/dist/plus/integrations/providers/gitlab.d.ts +9 -0
  253. package/dist/plus/integrations/providers/gitlab.d.ts.map +1 -1
  254. package/dist/plus/integrations/providers/gitlab.js +23 -4
  255. package/dist/plus/integrations/providers/gitlab.js.map +1 -1
  256. package/dist/plus/integrations/providers/models.d.ts +14 -32
  257. package/dist/plus/integrations/providers/models.d.ts.map +1 -1
  258. package/dist/plus/integrations/providers/models.js +66 -109
  259. package/dist/plus/integrations/providers/models.js.map +1 -1
  260. package/dist/plus/integrations/providers/pullRequestReviews.d.ts +50 -0
  261. package/dist/plus/integrations/providers/pullRequestReviews.d.ts.map +1 -0
  262. package/dist/plus/integrations/providers/pullRequestReviews.js +99 -0
  263. package/dist/plus/integrations/providers/pullRequestReviews.js.map +1 -0
  264. package/dist/plus/integrations/reads/broaden.d.ts.map +1 -1
  265. package/dist/plus/integrations/reads/broaden.js +6 -1
  266. package/dist/plus/integrations/reads/broaden.js.map +1 -1
  267. package/dist/plus/integrations/reads/counts.d.ts +55 -0
  268. package/dist/plus/integrations/reads/counts.d.ts.map +1 -1
  269. package/dist/plus/integrations/reads/counts.js +146 -2
  270. package/dist/plus/integrations/reads/counts.js.map +1 -1
  271. package/dist/plus/integrations/reads/drains.d.ts +7 -1
  272. package/dist/plus/integrations/reads/drains.d.ts.map +1 -1
  273. package/dist/plus/integrations/reads/drains.js +20 -6
  274. package/dist/plus/integrations/reads/drains.js.map +1 -1
  275. package/dist/plus/integrations/reads/filters.d.ts.map +1 -1
  276. package/dist/plus/integrations/reads/filters.js +22 -0
  277. package/dist/plus/integrations/reads/filters.js.map +1 -1
  278. package/dist/plus/integrations/reads/hierarchy.d.ts.map +1 -1
  279. package/dist/plus/integrations/reads/hierarchy.js +3 -1
  280. package/dist/plus/integrations/reads/hierarchy.js.map +1 -1
  281. package/dist/plus/integrations/reads/issueTracker.d.ts.map +1 -1
  282. package/dist/plus/integrations/reads/issueTracker.js +8 -3
  283. package/dist/plus/integrations/reads/issueTracker.js.map +1 -1
  284. package/dist/plus/integrations/reads/issues.d.ts.map +1 -1
  285. package/dist/plus/integrations/reads/issues.js +9 -4
  286. package/dist/plus/integrations/reads/issues.js.map +1 -1
  287. package/dist/plus/integrations/reads/pullRequests.d.ts.map +1 -1
  288. package/dist/plus/integrations/reads/pullRequests.js +9 -4
  289. package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
  290. package/dist/plus/integrations/reads/searchPullRequests.d.ts +4 -3
  291. package/dist/plus/integrations/reads/searchPullRequests.d.ts.map +1 -1
  292. package/dist/plus/integrations/reads/searchPullRequests.js +6 -4
  293. package/dist/plus/integrations/reads/searchPullRequests.js.map +1 -1
  294. package/dist/plus/integrations/reads/sweeps.js +1 -1
  295. package/dist/plus/integrations/reads/sweeps.js.map +1 -1
  296. package/dist/plus/integrations/reads/warnings.d.ts +2 -2
  297. package/dist/plus/integrations/reads/warnings.d.ts.map +1 -1
  298. package/dist/plus/integrations/reads/warnings.js +11 -2
  299. package/dist/plus/integrations/reads/warnings.js.map +1 -1
  300. package/dist/plus/integrations/results.d.ts +6 -1
  301. package/dist/plus/integrations/results.d.ts.map +1 -1
  302. package/dist/plus/integrations/results.js.map +1 -1
  303. package/dist/utils/env/browser/base64.d.ts +1 -1
  304. package/dist/utils/env/browser/base64.d.ts.map +1 -1
  305. package/dist/utils/env/node/base64.d.ts +1 -1
  306. package/dist/utils/env/node/base64.d.ts.map +1 -1
  307. package/dist/utils/env/node/base64.js +2 -0
  308. package/dist/utils/env/node/base64.js.map +1 -1
  309. package/dist/utils/keys/chord.d.ts +52 -0
  310. package/dist/utils/keys/chord.d.ts.map +1 -0
  311. package/dist/utils/keys/chord.js +135 -0
  312. package/dist/utils/keys/chord.js.map +1 -0
  313. package/dist/utils/keys/keybinding.d.ts +53 -0
  314. package/dist/utils/keys/keybinding.d.ts.map +1 -0
  315. package/dist/utils/keys/keybinding.js +58 -0
  316. package/dist/utils/keys/keybinding.js.map +1 -0
  317. package/dist/utils/path.d.ts +11 -0
  318. package/dist/utils/path.d.ts.map +1 -1
  319. package/dist/utils/path.js +13 -0
  320. package/dist/utils/path.js.map +1 -1
  321. package/docs/integrations.md +76 -10
  322. package/docs/kepler-read-api-parity.md +9 -0
  323. package/package.json +13 -5
  324. package/src/git/cache.ts +383 -47
  325. package/src/git/context.ts +11 -0
  326. package/src/git/models/fileStatus.ts +1 -0
  327. package/src/git/models/issue.ts +4 -0
  328. package/src/git/models/mergeConflicts.ts +3 -2
  329. package/src/git/models/pullRequest.ts +117 -1
  330. package/src/git/models/repository.ts +58 -17
  331. package/src/git/models/statusFile.ts +3 -0
  332. package/src/git/providers/branches.ts +6 -0
  333. package/src/git/providers/commits.ts +11 -0
  334. package/src/git/providers/config.ts +18 -0
  335. package/src/git/providers/operations.ts +1 -0
  336. package/src/git/providers/pausedOperations.ts +2 -0
  337. package/src/git/providers/status.ts +1 -0
  338. package/src/git/utils/config.utils.ts +8 -0
  339. package/src/git/utils/issue.utils.ts +2 -0
  340. package/src/git/utils/pausedOperationStatus.utils.ts +28 -0
  341. package/src/git/utils/pullRequest.utils.ts +86 -0
  342. package/src/git/watching/changeEvent.ts +6 -1
  343. package/src/git/watching/classifyChange.ts +15 -1
  344. package/src/git/watching/watchService.ts +20 -3
  345. package/src/git/watching/watchSession.ts +41 -6
  346. package/src/git/watching/watcherPatterns.ts +1 -1
  347. package/src/git-cli/exec/git.ts +13 -3
  348. package/src/git-cli/providers/branches.ts +384 -132
  349. package/src/git-cli/providers/commits.ts +106 -15
  350. package/src/git-cli/providers/config.ts +229 -8
  351. package/src/git-cli/providers/contributors.ts +5 -1
  352. package/src/git-cli/providers/graph.ts +26 -13
  353. package/src/git-cli/providers/operations.ts +45 -20
  354. package/src/git-cli/providers/pausedOperations.ts +109 -17
  355. package/src/git-cli/providers/refs.ts +33 -3
  356. package/src/git-cli/providers/status.ts +25 -4
  357. package/src/git-cli/providers/worktrees.ts +5 -0
  358. package/src/git-cli/service.ts +0 -1
  359. package/src/plus/agents/providers/claudeCodeProvider.ts +1130 -87
  360. package/src/plus/agents/providers/claudeCodeTranscript.ts +95 -9
  361. package/src/plus/agents/types.ts +46 -2
  362. package/src/plus/ai/errors.ts +30 -0
  363. package/src/plus/ai/models/model.ts +56 -6
  364. package/src/plus/ai/models/promptTemplates.ts +1 -1
  365. package/src/plus/ai/models/provider.ts +69 -2
  366. package/src/plus/ai/prompts.ts +186 -61
  367. package/src/plus/ai/providers/anthropicProvider.ts +155 -47
  368. package/src/plus/ai/providers/deepSeekProvider.ts +11 -21
  369. package/src/plus/ai/providers/geminiProvider.ts +19 -0
  370. package/src/plus/ai/providers/gitkrakenProvider.ts +126 -3
  371. package/src/plus/ai/providers/huggingFaceProvider.ts +6 -0
  372. package/src/plus/ai/providers/mistralProvider.ts +102 -19
  373. package/src/plus/ai/providers/ollamaProvider.ts +55 -4
  374. package/src/plus/ai/providers/openAICompatibleProvider.ts +5 -0
  375. package/src/plus/ai/providers/openAICompatibleProviderBase.ts +360 -17
  376. package/src/plus/ai/providers/openRouterProvider.ts +17 -0
  377. package/src/plus/ai/providers/openaiProvider.ts +1 -0
  378. package/src/plus/ai/providers/responseFormatCache.ts +39 -0
  379. package/src/plus/ai/providers/xaiProvider.ts +10 -1
  380. package/src/plus/ai/utils/ai.utils.ts +14 -0
  381. package/src/plus/ai/utils/results.utils.ts +255 -31
  382. package/src/plus/git-github/api/github.ts +467 -23
  383. package/src/plus/git-github/api/pullRequestSearchQuery.ts +81 -7
  384. package/src/plus/git-github/models.ts +77 -7
  385. package/src/plus/git-github/providers/github/status.ts +1 -0
  386. package/src/plus/integrations/context.ts +4 -0
  387. package/src/plus/integrations/index.ts +2 -0
  388. package/src/plus/integrations/integrationService.ts +25 -2
  389. package/src/plus/integrations/manager.ts +50 -5
  390. package/src/plus/integrations/models/gitHostIntegration.ts +54 -2
  391. package/src/plus/integrations/models/integration.ts +24 -13
  392. package/src/plus/integrations/providerFilters.ts +6 -1
  393. package/src/plus/integrations/providers/accounts.ts +38 -0
  394. package/src/plus/integrations/providers/azure/models.ts +3 -0
  395. package/src/plus/integrations/providers/bitbucket/models.ts +1 -0
  396. package/src/plus/integrations/providers/github.ts +218 -145
  397. package/src/plus/integrations/providers/gitlab.ts +30 -20
  398. package/src/plus/integrations/providers/models.ts +99 -127
  399. package/src/plus/integrations/providers/pullRequestReviews.ts +122 -0
  400. package/src/plus/integrations/reads/broaden.ts +6 -1
  401. package/src/plus/integrations/reads/counts.ts +273 -2
  402. package/src/plus/integrations/reads/drains.ts +19 -6
  403. package/src/plus/integrations/reads/filters.ts +22 -0
  404. package/src/plus/integrations/reads/hierarchy.ts +3 -1
  405. package/src/plus/integrations/reads/issueTracker.ts +9 -3
  406. package/src/plus/integrations/reads/issues.ts +9 -4
  407. package/src/plus/integrations/reads/pullRequests.ts +9 -4
  408. package/src/plus/integrations/reads/searchPullRequests.ts +12 -4
  409. package/src/plus/integrations/reads/sweeps.ts +1 -1
  410. package/src/plus/integrations/reads/warnings.ts +12 -1
  411. package/src/plus/integrations/results.ts +6 -1
  412. package/src/utils/env/browser/base64.ts +1 -1
  413. package/src/utils/env/node/base64.ts +3 -1
  414. package/src/utils/keys/chord.ts +184 -0
  415. package/src/utils/keys/keybinding.ts +116 -0
  416. package/src/utils/path.ts +14 -0
@@ -8,9 +8,14 @@ import { OpenAICompatibleProviderBase } from './openAICompatibleProviderBase.js'
8
8
 
9
9
  type GitKrakenModel = AIModel<typeof provider.id>;
10
10
 
11
+ /** Opt-out flag the models endpoint reports in `disabledAttributes` for models whose upstream
12
+ * translation doesn't cover native structured outputs */
13
+ const structuredOutputAttribute = 'structured_output';
14
+
11
15
  export class GitKrakenProvider extends OpenAICompatibleProviderBase<typeof provider.id> {
12
16
  readonly id = provider.id;
13
17
  readonly name = provider.name;
18
+ readonly supportsTools = true;
14
19
  protected readonly descriptor = provider;
15
20
  protected readonly config = {};
16
21
 
@@ -47,6 +52,7 @@ export class GitKrakenProvider extends OpenAICompatibleProviderBase<typeof provi
47
52
  preferred: boolean;
48
53
  maxInputTokens: number;
49
54
  maxOutputTokens: number;
55
+ disabledAttributes?: string[];
50
56
  consumptionRateLabel?: string;
51
57
  }[];
52
58
  error?: null;
@@ -67,6 +73,10 @@ export class GitKrakenProvider extends OpenAICompatibleProviderBase<typeof provi
67
73
  default: m.preferred,
68
74
  temperature: null,
69
75
  consumptionRateLabel: m.consumptionRateLabel,
76
+ // The backend owns the per-upstream `response_format` translation, so it's the
77
+ // authority on which models it covers. A schema an upstream's converter still
78
+ // rejects is recovered per-request via isResponseFormatRejection below
79
+ supportsStructuredOutputs: !m.disabledAttributes?.includes(structuredOutputAttribute),
70
80
  }) satisfies GitKrakenModel,
71
81
  );
72
82
  return models;
@@ -84,6 +94,31 @@ export class GitKrakenProvider extends OpenAICompatibleProviderBase<typeof provi
84
94
  return 'chat/completions';
85
95
  }
86
96
 
97
+ protected override isToolsRejection(status: number, message: string | undefined): boolean {
98
+ if (super.isToolsRejection(status, message)) return true;
99
+ if (message == null) return false;
100
+
101
+ // The backend forwards an upstream refusal as its own envelope carrying only "upstream AI provider
102
+ // error (<provider> HTTP 400)", naming neither "tool" nor "function" — so the base's text match can
103
+ // never fire here. Treat any wrapped upstream 400 as a candidate and let the retry decide: `tools`
104
+ // is the only field a tool-using request sends that a plain completion doesn't, the probe costs one
105
+ // request, and the caller latches the rejection only when dropping tools actually fixes it. A
106
+ // misread therefore self-corrects — the same bargain `isResponseFormatRejection` below makes.
107
+ return getWrappedUpstreamStatus(message) === 400;
108
+ }
109
+
110
+ protected override isResponseFormatRejection(status: number, body: string): boolean {
111
+ if (super.isResponseFormatRejection(status, body)) return true;
112
+
113
+ // The backend wraps upstream schema rejections in its own envelope, carrying only the upstream
114
+ // status (e.g. its Gemini schema converter mangles null-union types → Gemini 400s). Match on the
115
+ // wrapper, NOT the envelope code — that varies by backend (500.1 on prod, 400.1 seen on staging),
116
+ // and keying off it means the probe silently stops firing. A non-schema upstream 400 also matches,
117
+ // which is fine: the strip-and-resend probe is cheap and rejection is only memoized when the
118
+ // resend succeeds, so misclassification self-corrects.
119
+ return getWrappedUpstreamStatus(body) === 400;
120
+ }
121
+
87
122
  protected override getHeaders<TAction extends AIActionType>(
88
123
  action: TAction,
89
124
  apiKey: string,
@@ -107,17 +142,27 @@ export class GitKrakenProvider extends OpenAICompatibleProviderBase<typeof provi
107
142
  _model: AIModel<typeof provider.id>,
108
143
  retries: number,
109
144
  maxInputTokens: number,
110
- ): Promise<{ retry: true; maxInputTokens: number }> {
145
+ body?: string,
146
+ sentTools?: boolean,
147
+ ): Promise<{ retry: true; maxInputTokens: number; withoutTools?: boolean }> {
111
148
  type ErrorResponse = {
112
149
  error?: { code: string; message: string; data?: any };
113
150
  };
114
151
 
115
152
  let json;
116
153
  try {
117
- json = (await rsp.json()) as ErrorResponse | undefined;
154
+ json = (body != null ? JSON.parse(body) : await rsp.json()) as ErrorResponse | undefined;
118
155
  } catch {}
119
156
 
157
+ // The backend's own prose says only "upstream AI provider error (<provider> HTTP <status>)" and
158
+ // puts the provider's actual complaint in `data`. Dropping it (as every branch but the
159
+ // entitlement one did) leaves nothing naming a cause, so a request the upstream rejected is
160
+ // indistinguishable from any other 400 — and the only way to find out is to guess.
120
161
  let message = json?.error?.message || rsp.statusText;
162
+ const detail = formatErrorData(json?.error?.data);
163
+ if (detail != null) {
164
+ message += `; ${detail}`;
165
+ }
121
166
 
122
167
  let status: string | number;
123
168
  let code: string | number;
@@ -126,6 +171,33 @@ export class GitKrakenProvider extends OpenAICompatibleProviderBase<typeof provi
126
171
  status = status ? parseInt(status, 10) : rsp.status;
127
172
  code = code ? parseInt(code, 10) : 0;
128
173
 
174
+ // Classify a wrapped upstream failure by the status it carries, not by the envelope's own code:
175
+ // prod reports these as 500.1, but staging has been seen using 400.1, and keying off the outer
176
+ // code means an upstream rate limit arrives as a bare Error with no reason — so no "Switch
177
+ // Model" action and no retry, just an opaque message.
178
+ const upstreamStatus = getWrappedUpstreamStatus(message);
179
+ if (upstreamStatus != null) {
180
+ const wrapped = new Error(`(${this.name}) ${status}.${code}: ${message}`);
181
+ switch (upstreamStatus) {
182
+ case 429:
183
+ throw new AIError(AIErrorReason.RateLimitExceeded, wrapped);
184
+ case 413:
185
+ throw new AIError(AIErrorReason.RequestTooLarge, wrapped);
186
+ case 401:
187
+ case 403:
188
+ throw new AIError(AIErrorReason.Unauthorized, wrapped);
189
+ // Anything else is the upstream refusing the request itself. There's nothing to recover
190
+ // automatically, so fall through and surface it with the detail folded in above.
191
+ }
192
+ }
193
+
194
+ // Recover a tools rejection BEFORE the switch below. This override owns the 400 case and throws,
195
+ // so it never reaches `super.handleFetchFailure` — which is the only place the base's
196
+ // retry-without-tools fallback lives, leaving it unreachable for this provider.
197
+ if (sentTools && this.isToolsRejection(status, message)) {
198
+ return { retry: true, maxInputTokens: maxInputTokens, withoutTools: true };
199
+ }
200
+
129
201
  switch (status) {
130
202
  case 400: // Bad Request
131
203
  // CodeValidation = "400.1"
@@ -201,9 +273,12 @@ export class GitKrakenProvider extends OpenAICompatibleProviderBase<typeof provi
201
273
  case 499:
202
274
  // CodeRequestCanceled = "499.1"
203
275
  throw new Error(`(${this.name}) ${status}.${code}: ${message}`);
204
- case 500:
276
+ case 500: {
205
277
  // CodeServerError = "500.1"
278
+ // Wrapped upstream failures are classified above, before this switch — the backend has
279
+ // used more than one envelope code for them, so that can't key off `status`.
206
280
  throw new Error(`(${this.name}) ${status}.${code}: ${message}`);
281
+ }
207
282
  case 503:
208
283
  // CodeServiceUnavailable = "503.1"
209
284
 
@@ -222,3 +297,51 @@ export class GitKrakenProvider extends OpenAICompatibleProviderBase<typeof provi
222
297
  }
223
298
  }
224
299
  }
300
+
301
+ /** Max characters of `error.data` folded into a message — enough to name a cause, bounded so a large
302
+ * payload can't dominate a notification or a log line. */
303
+ const maxErrorDetailLength = 500;
304
+
305
+ /**
306
+ * Renders the backend's `error.data` as a short detail string. This is where the upstream provider's
307
+ * own complaint arrives, so it's the difference between "upstream AI provider error (OpenAI HTTP 400)"
308
+ * and knowing which field it rejected.
309
+ *
310
+ * Strings pass through; objects are JSON-encoded. A common shape is the upstream's own error envelope,
311
+ * so a nested `message` is preferred when present rather than dumping the whole object.
312
+ */
313
+ function formatErrorData(data: unknown): string | undefined {
314
+ if (data == null) return undefined;
315
+
316
+ let text: string | undefined;
317
+ if (typeof data === 'string') {
318
+ text = data;
319
+ } else if (typeof data === 'object') {
320
+ const nested =
321
+ (data as { error?: { message?: unknown }; message?: unknown }).error?.message ??
322
+ (data as { message?: unknown }).message;
323
+ if (typeof nested === 'string' && nested) {
324
+ text = nested;
325
+ } else {
326
+ try {
327
+ text = JSON.stringify(data);
328
+ } catch {
329
+ return undefined;
330
+ }
331
+ }
332
+ } else if (typeof data === 'number' || typeof data === 'boolean') {
333
+ text = String(data);
334
+ }
335
+
336
+ text = text?.trim();
337
+ if (!text || text === '{}' || text === 'null') return undefined;
338
+
339
+ return text.length > maxErrorDetailLength ? `${text.slice(0, maxErrorDetailLength)}…` : text;
340
+ }
341
+
342
+ /** Extracts the upstream HTTP status from the backend's upstream-error prose wrapper. The envelope code
343
+ * varies (500.1 on prod, 400.1 seen on staging), so callers must key off this, not the outer code. */
344
+ function getWrappedUpstreamStatus(text: string): number | undefined {
345
+ const status = /upstream ai provider error[\s\S]*?http (\d{3})/i.exec(text)?.[1];
346
+ return status != null ? parseInt(status, 10) : undefined;
347
+ }
@@ -55,4 +55,10 @@ export class HuggingFaceProvider extends OpenAICompatibleProviderBase<typeof pro
55
55
  protected getUrl(_model: AIModel<typeof provider.id>): string {
56
56
  return 'https://router.huggingface.co/v1/chat/completions';
57
57
  }
58
+
59
+ // Router support varies by partner provider with no capability metadata and auto-routing —
60
+ // the prompt-described JSON fallback is the only reliable path
61
+ protected override supportsResponseFormat(_model: AIModel<typeof provider.id>): boolean {
62
+ return false;
63
+ }
58
64
  }
@@ -8,10 +8,17 @@ type MistralModel = AIModel<typeof provider.id>;
8
8
  const models: MistralModel[] = [
9
9
  {
10
10
  id: 'mistral-medium-latest',
11
- name: 'Mistral Medium',
12
- maxTokens: { input: 131072, output: 4096 },
11
+ name: 'Mistral Medium 3.5',
12
+ maxTokens: { input: 262144, output: 4096 },
13
13
  provider: provider,
14
14
  },
15
+ {
16
+ id: 'mistral-medium-3-5',
17
+ name: 'Mistral Medium 3.5',
18
+ maxTokens: { input: 262144, output: 4096 },
19
+ provider: provider,
20
+ hidden: true,
21
+ },
15
22
  {
16
23
  id: 'mistral-medium-2505',
17
24
  name: 'Mistral Medium',
@@ -20,24 +27,44 @@ const models: MistralModel[] = [
20
27
  hidden: true,
21
28
  },
22
29
  {
23
- id: 'codestral-latest',
24
- name: 'Codestral',
30
+ id: 'zai-glm-5-2',
31
+ name: 'GLM 5.2',
32
+ maxTokens: { input: 1000000, output: 128000 },
33
+ provider: provider,
34
+ },
35
+ {
36
+ id: 'mistral-small-latest',
37
+ name: 'Mistral Small 4',
25
38
  maxTokens: { input: 262144, output: 4096 },
26
39
  provider: provider,
27
40
  default: true,
28
41
  },
29
42
  {
30
- id: 'codestral-2501',
31
- name: 'Codestral',
43
+ id: 'mistral-small-2603',
44
+ name: 'Mistral Small 4',
32
45
  maxTokens: { input: 262144, output: 4096 },
33
46
  provider: provider,
34
47
  hidden: true,
35
48
  },
36
49
  {
37
- id: 'mistral-large-latest',
38
- name: 'Mistral Large',
50
+ id: 'mistral-small-2503',
51
+ name: 'Mistral Small',
39
52
  maxTokens: { input: 131072, output: 4096 },
40
53
  provider: provider,
54
+ hidden: true,
55
+ },
56
+ {
57
+ id: 'mistral-large-latest',
58
+ name: 'Mistral Large 3',
59
+ maxTokens: { input: 262144, output: 4096 },
60
+ provider: provider,
61
+ },
62
+ {
63
+ id: 'mistral-large-2512',
64
+ name: 'Mistral Large 3',
65
+ maxTokens: { input: 262144, output: 4096 },
66
+ provider: provider,
67
+ hidden: true,
41
68
  },
42
69
  {
43
70
  id: 'mistral-large-2411',
@@ -47,27 +74,74 @@ const models: MistralModel[] = [
47
74
  hidden: true,
48
75
  },
49
76
  {
50
- id: 'devstral-small-latest',
51
- name: 'Devstral Small',
77
+ id: 'ministral-14b-latest',
78
+ name: 'Ministral 3 14B',
79
+ maxTokens: { input: 262144, output: 4096 },
80
+ provider: provider,
81
+ },
82
+ {
83
+ id: 'ministral-14b-2512',
84
+ name: 'Ministral 3 14B',
85
+ maxTokens: { input: 262144, output: 4096 },
86
+ provider: provider,
87
+ hidden: true,
88
+ },
89
+ {
90
+ id: 'ministral-8b-latest',
91
+ name: 'Ministral 3 8B',
92
+ maxTokens: { input: 262144, output: 4096 },
93
+ provider: provider,
94
+ },
95
+ {
96
+ id: 'ministral-8b-2512',
97
+ name: 'Ministral 3 8B',
98
+ maxTokens: { input: 262144, output: 4096 },
99
+ provider: provider,
100
+ hidden: true,
101
+ },
102
+ {
103
+ id: 'ministral-3b-latest',
104
+ name: 'Ministral 3 3B',
105
+ maxTokens: { input: 262144, output: 4096 },
106
+ provider: provider,
107
+ },
108
+ {
109
+ id: 'ministral-3b-2512',
110
+ name: 'Ministral 3 3B',
111
+ maxTokens: { input: 262144, output: 4096 },
112
+ provider: provider,
113
+ hidden: true,
114
+ },
115
+ {
116
+ id: 'codestral-latest',
117
+ name: 'Codestral',
52
118
  maxTokens: { input: 131072, output: 4096 },
53
119
  provider: provider,
54
120
  },
55
121
  {
56
- id: 'devstral-small-2505',
57
- name: 'Devstral Small',
122
+ id: 'codestral-2508',
123
+ name: 'Codestral',
58
124
  maxTokens: { input: 131072, output: 4096 },
59
125
  provider: provider,
60
126
  hidden: true,
61
127
  },
62
128
  {
63
- id: 'mistral-small-latest',
64
- name: 'Mistral Small',
129
+ id: 'codestral-2501',
130
+ name: 'Codestral',
131
+ maxTokens: { input: 262144, output: 4096 },
132
+ provider: provider,
133
+ hidden: true,
134
+ },
135
+ {
136
+ id: 'devstral-small-latest',
137
+ name: 'Devstral Small',
65
138
  maxTokens: { input: 131072, output: 4096 },
66
139
  provider: provider,
140
+ hidden: true,
67
141
  },
68
142
  {
69
- id: 'mistral-small-2503',
70
- name: 'Mistral Small',
143
+ id: 'devstral-small-2505',
144
+ name: 'Devstral Small',
71
145
  maxTokens: { input: 131072, output: 4096 },
72
146
  provider: provider,
73
147
  hidden: true,
@@ -77,6 +151,7 @@ const models: MistralModel[] = [
77
151
  export class MistralProvider extends OpenAICompatibleProviderBase<typeof provider.id> {
78
152
  readonly id = provider.id;
79
153
  readonly name = provider.name;
154
+ readonly supportsTools = true;
80
155
  protected readonly descriptor = provider;
81
156
  protected readonly config = {
82
157
  keyUrl: 'https://console.mistral.ai/api-keys',
@@ -111,11 +186,13 @@ export class MistralProvider extends OpenAICompatibleProviderBase<typeof provide
111
186
  model: AIModel<typeof provider.id>,
112
187
  retries: number,
113
188
  maxInputTokens: number,
114
- ): Promise<{ retry: true; maxInputTokens: number }> {
189
+ body?: string,
190
+ sentTools?: boolean,
191
+ ): Promise<{ retry: true; maxInputTokens: number; withoutTools?: boolean }> {
115
192
  if (rsp.status !== 404 && rsp.status !== 429) {
116
193
  let json;
117
194
  try {
118
- json = (await rsp.json()) as MistralError | undefined;
195
+ json = (body != null ? JSON.parse(body) : await rsp.json()) as MistralError | undefined;
119
196
  } catch {}
120
197
 
121
198
  debugger;
@@ -137,10 +214,16 @@ export class MistralProvider extends OpenAICompatibleProviderBase<typeof provide
137
214
  }
138
215
  }
139
216
 
217
+ // This override throws for every non-404/429 status, so the base class's tools-rejection
218
+ // recovery would never run for Mistral — check it here to keep the text-only fallback
219
+ if (sentTools && this.isToolsRejection(rsp.status, message)) {
220
+ return { retry: true, maxInputTokens: maxInputTokens, withoutTools: true };
221
+ }
222
+
140
223
  throw new Error(`(${this.name}) ${rsp.status}: ${message || rsp.statusText}`);
141
224
  }
142
225
 
143
- return super.handleFetchFailure(rsp, action, model, retries, maxInputTokens);
226
+ return super.handleFetchFailure(rsp, action, model, retries, maxInputTokens, body, sentTools);
144
227
  }
145
228
  }
146
229
 
@@ -1,7 +1,14 @@
1
1
  import { uuid } from '../../../utils/crypto.js';
2
+ import { Logger } from '../../../utils/logger.js';
2
3
  import { ollamaProviderDescriptor as provider } from '../constants.js';
3
4
  import type { AIActionType, AIModel } from '../models/model.js';
4
- import type { AIChatMessage, AIProviderResponse } from '../models/provider.js';
5
+ import type {
6
+ AIChatMessage,
7
+ AIChatMessageRole,
8
+ AIProviderResponse,
9
+ AIResponseFormat,
10
+ JSONSchema,
11
+ } from '../models/provider.js';
5
12
  import { OpenAICompatibleProviderBase } from './openAICompatibleProviderBase.js';
6
13
 
7
14
  type OllamaModel = AIModel<typeof provider.id>;
@@ -122,6 +129,11 @@ export class OllamaProvider extends OpenAICompatibleProviderBase<typeof provider
122
129
  return url ? `${url}/api/chat` : undefined;
123
130
  }
124
131
 
132
+ // Ollama < 0.5.0 rejects a schema-valued `format` (accepts only 'json')
133
+ protected override isResponseFormatRejection(status: number, body: string): boolean {
134
+ return status === 400 && /format/i.test(body);
135
+ }
136
+
125
137
  protected override getHeaders<TAction extends AIActionType>(
126
138
  _action: TAction,
127
139
  _apiKey: string,
@@ -138,8 +150,9 @@ export class OllamaProvider extends OpenAICompatibleProviderBase<typeof provider
138
150
  action: TAction,
139
151
  model: AIModel<typeof provider.id>,
140
152
  apiKey: string,
141
- messages: (maxInputTokens: number, retries: number) => Promise<AIChatMessage[]>,
153
+ messages: (maxInputTokens: number, retries: number) => Promise<AIChatMessage<AIChatMessageRole>[]>,
142
154
  modelOptions?: { outputTokens?: number; temperature?: number },
155
+ responseFormat?: AIResponseFormat,
143
156
  signal?: AbortSignal,
144
157
  ): Promise<AIProviderResponse<void>> {
145
158
  let retries = 0;
@@ -158,10 +171,19 @@ export class OllamaProvider extends OpenAICompatibleProviderBase<typeof provider
158
171
  // Ensure temperature is within valid range for Ollama (0.0-1.0)
159
172
  const temperature = Math.min(Math.max(modelOptions?.temperature ?? 0.7, 0), 1);
160
173
 
174
+ const format =
175
+ responseFormat != null &&
176
+ !this.isResponseFormatSessionRejected(model, responseFormat) &&
177
+ this.supportsResponseFormat(model)
178
+ ? responseFormat.schema
179
+ : undefined;
180
+
161
181
  const request: OllamaChatRequest = {
162
182
  model: model.id,
163
183
  messages: ollamaMessages,
164
184
  stream: false,
185
+ // Ollama takes the bare JSON schema (grammar-constrained sampling, any model)
186
+ format: format,
165
187
  options: {
166
188
  temperature: temperature,
167
189
  // Add num_predict if outputTokens is specified
@@ -169,9 +191,34 @@ export class OllamaProvider extends OpenAICompatibleProviderBase<typeof provider
169
191
  },
170
192
  };
171
193
 
172
- const rsp = await this.fetchCore(action, model, apiKey, request, signal);
194
+ let rsp = await this.fetchCore(action, model, apiKey, request, signal);
195
+ let errorBody: string | undefined;
196
+ if (!rsp.ok && rsp.status === 400 && request.format != null) {
197
+ // If the schema-valued format was rejected (Ollama < 0.5.0 accepts only 'json'),
198
+ // resend the same request without it — the prompt still describes the JSON
199
+ // Leave it `undefined` (not '') when the read fails, so `handleFetchFailure` falls
200
+ // back to reading the still-unconsumed response instead of parsing an empty string
201
+ errorBody = await rsp
202
+ .clone()
203
+ .text()
204
+ .catch(() => undefined);
205
+ if (this.isResponseFormatRejection(rsp.status, errorBody ?? '')) {
206
+ Logger.warn(
207
+ `(${this.name}) ${model.id}: native response format was rejected (${rsp.status}); retrying without it`,
208
+ );
209
+ const rejected = responseFormat;
210
+ responseFormat = undefined;
211
+ delete request.format;
212
+ rsp = await this.fetchCore(action, model, apiKey, request, signal);
213
+ errorBody = undefined;
214
+ if (rsp.ok && rejected != null) {
215
+ this.rememberResponseFormatRejection(model, rejected);
216
+ }
217
+ }
218
+ }
219
+
173
220
  if (!rsp.ok) {
174
- const result = await this.handleFetchFailure(rsp, action, model, retries, maxInputTokens);
221
+ const result = await this.handleFetchFailure(rsp, action, model, retries, maxInputTokens, errorBody);
175
222
  if (result.retry) {
176
223
  maxInputTokens = result.maxInputTokens;
177
224
  retries++;
@@ -190,6 +237,7 @@ export class OllamaProvider extends OpenAICompatibleProviderBase<typeof provider
190
237
  return {
191
238
  id: uuid(),
192
239
  content: data.message.content,
240
+ finishReason: data.done_reason === 'length' ? 'length' : undefined,
193
241
  model: model,
194
242
  usage: {
195
243
  promptTokens: data.prompt_eval_count ?? 0,
@@ -216,6 +264,8 @@ interface OllamaChatRequest {
216
264
  content: string;
217
265
  }>;
218
266
  stream: boolean;
267
+ /** 'json' for JSON mode, or a JSON schema object for structured output (Ollama ≥0.5.0) */
268
+ format?: 'json' | JSONSchema;
219
269
  options?: {
220
270
  temperature?: number;
221
271
  top_p?: number;
@@ -232,6 +282,7 @@ interface OllamaChatResponse {
232
282
  content: string;
233
283
  };
234
284
  done: boolean;
285
+ done_reason?: string;
235
286
  total_duration?: number;
236
287
  load_duration?: number;
237
288
  prompt_eval_count?: number;
@@ -27,6 +27,11 @@ export class OpenAICompatibleProvider extends OpenAICompatibleProviderBase<typeo
27
27
  return cfg.url || undefined;
28
28
  }
29
29
 
30
+ // Unknown user-configured backend — fall back to prompt-described JSON
31
+ protected override supportsResponseFormat(_model: AIModel<typeof provider.id>): boolean {
32
+ return false;
33
+ }
34
+
30
35
  private async getOrPromptBaseUrl(silent: boolean, hasApiKey: boolean): Promise<string | undefined> {
31
36
  const orgConf = this.context.getProviderConfig(this.id);
32
37
  if (!orgConf.enabled) return undefined;