@gajae-code/ai 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (349) hide show
  1. package/CHANGELOG.md +2644 -0
  2. package/README.md +1181 -0
  3. package/dist/types/api-registry.d.ts +30 -0
  4. package/dist/types/auth-broker/client.d.ts +66 -0
  5. package/dist/types/auth-broker/index.d.ts +5 -0
  6. package/dist/types/auth-broker/refresher.d.ts +25 -0
  7. package/dist/types/auth-broker/remote-store.d.ts +96 -0
  8. package/dist/types/auth-broker/server.d.ts +32 -0
  9. package/dist/types/auth-broker/types.d.ts +105 -0
  10. package/dist/types/auth-broker/wire-schemas.d.ts +412 -0
  11. package/dist/types/auth-gateway/http.d.ts +39 -0
  12. package/dist/types/auth-gateway/index.d.ts +3 -0
  13. package/dist/types/auth-gateway/server.d.ts +17 -0
  14. package/dist/types/auth-gateway/types.d.ts +115 -0
  15. package/dist/types/auth-storage.d.ts +641 -0
  16. package/dist/types/cli.d.ts +2 -0
  17. package/dist/types/index.d.ts +49 -0
  18. package/dist/types/model-cache.d.ts +17 -0
  19. package/dist/types/model-manager.d.ts +62 -0
  20. package/dist/types/model-thinking.d.ts +71 -0
  21. package/dist/types/models.d.ts +12 -0
  22. package/dist/types/provider-details.d.ts +24 -0
  23. package/dist/types/provider-models/bundled-references.d.ts +4 -0
  24. package/dist/types/provider-models/descriptors.d.ts +48 -0
  25. package/dist/types/provider-models/google.d.ts +20 -0
  26. package/dist/types/provider-models/index.d.ts +5 -0
  27. package/dist/types/provider-models/ollama.d.ts +7 -0
  28. package/dist/types/provider-models/openai-compat.d.ts +237 -0
  29. package/dist/types/provider-models/special.d.ts +16 -0
  30. package/dist/types/providers/amazon-bedrock.d.ts +36 -0
  31. package/dist/types/providers/anthropic-messages-server-schema.d.ts +450 -0
  32. package/dist/types/providers/anthropic-messages-server.d.ts +17 -0
  33. package/dist/types/providers/anthropic.d.ts +188 -0
  34. package/dist/types/providers/aws-credentials.d.ts +43 -0
  35. package/dist/types/providers/aws-eventstream.d.ts +38 -0
  36. package/dist/types/providers/aws-sigv4.d.ts +55 -0
  37. package/dist/types/providers/azure-openai-responses.d.ts +15 -0
  38. package/dist/types/providers/cursor/gen/agent_pb.d.ts +13022 -0
  39. package/dist/types/providers/cursor.d.ts +42 -0
  40. package/dist/types/providers/error-message.d.ts +27 -0
  41. package/dist/types/providers/github-copilot-headers.d.ts +40 -0
  42. package/dist/types/providers/gitlab-duo.d.ts +27 -0
  43. package/dist/types/providers/google-auth.d.ts +24 -0
  44. package/dist/types/providers/google-gemini-cli.d.ts +72 -0
  45. package/dist/types/providers/google-gemini-headers.d.ts +18 -0
  46. package/dist/types/providers/google-shared.d.ts +163 -0
  47. package/dist/types/providers/google-types.d.ts +138 -0
  48. package/dist/types/providers/google-vertex.d.ts +7 -0
  49. package/dist/types/providers/google.d.ts +4 -0
  50. package/dist/types/providers/grammar.d.ts +1 -0
  51. package/dist/types/providers/kimi.d.ts +27 -0
  52. package/dist/types/providers/mock.d.ts +175 -0
  53. package/dist/types/providers/ollama.d.ts +6 -0
  54. package/dist/types/providers/openai-anthropic-shim.d.ts +31 -0
  55. package/dist/types/providers/openai-chat-server-schema.d.ts +814 -0
  56. package/dist/types/providers/openai-chat-server.d.ts +16 -0
  57. package/dist/types/providers/openai-codex/constants.d.ts +26 -0
  58. package/dist/types/providers/openai-codex/request-transformer.d.ts +49 -0
  59. package/dist/types/providers/openai-codex/response-handler.d.ts +17 -0
  60. package/dist/types/providers/openai-codex-responses.d.ts +67 -0
  61. package/dist/types/providers/openai-completions-compat.d.ts +25 -0
  62. package/dist/types/providers/openai-completions.d.ts +33 -0
  63. package/dist/types/providers/openai-responses-server-schema.d.ts +392 -0
  64. package/dist/types/providers/openai-responses-server.d.ts +17 -0
  65. package/dist/types/providers/openai-responses-shared.d.ts +89 -0
  66. package/dist/types/providers/openai-responses.d.ts +32 -0
  67. package/dist/types/providers/pi-native-client.d.ts +13 -0
  68. package/dist/types/providers/pi-native-server.d.ts +68 -0
  69. package/dist/types/providers/register-builtins.d.ts +31 -0
  70. package/dist/types/providers/synthetic.d.ts +26 -0
  71. package/dist/types/providers/transform-messages.d.ts +12 -0
  72. package/dist/types/providers/vision-guard.d.ts +8 -0
  73. package/dist/types/rate-limit-utils.d.ts +19 -0
  74. package/dist/types/stream.d.ts +24 -0
  75. package/dist/types/types.d.ts +746 -0
  76. package/dist/types/usage/claude.d.ts +3 -0
  77. package/dist/types/usage/gemini.d.ts +2 -0
  78. package/dist/types/usage/github-copilot.d.ts +7 -0
  79. package/dist/types/usage/google-antigravity.d.ts +2 -0
  80. package/dist/types/usage/kimi.d.ts +2 -0
  81. package/dist/types/usage/minimax-code.d.ts +2 -0
  82. package/dist/types/usage/openai-codex.d.ts +3 -0
  83. package/dist/types/usage/shared.d.ts +1 -0
  84. package/dist/types/usage/zai.d.ts +2 -0
  85. package/dist/types/usage.d.ts +258 -0
  86. package/dist/types/utils/abort.d.ts +19 -0
  87. package/dist/types/utils/anthropic-auth.d.ts +31 -0
  88. package/dist/types/utils/discovery/antigravity.d.ts +61 -0
  89. package/dist/types/utils/discovery/codex.d.ts +38 -0
  90. package/dist/types/utils/discovery/cursor.d.ts +23 -0
  91. package/dist/types/utils/discovery/gemini.d.ts +25 -0
  92. package/dist/types/utils/discovery/index.d.ts +4 -0
  93. package/dist/types/utils/discovery/openai-compatible.d.ts +72 -0
  94. package/dist/types/utils/event-stream.d.ts +28 -0
  95. package/dist/types/utils/fireworks-model-id.d.ts +10 -0
  96. package/dist/types/utils/foundry.d.ts +1 -0
  97. package/dist/types/utils/h2-fetch.d.ts +22 -0
  98. package/dist/types/utils/http-inspector.d.ts +31 -0
  99. package/dist/types/utils/idle-iterator.d.ts +67 -0
  100. package/dist/types/utils/json-parse.d.ts +10 -0
  101. package/dist/types/utils/oauth/alibaba-coding-plan.d.ts +18 -0
  102. package/dist/types/utils/oauth/anthropic.d.ts +22 -0
  103. package/dist/types/utils/oauth/api-key-login.d.ts +35 -0
  104. package/dist/types/utils/oauth/api-key-validation.d.ts +27 -0
  105. package/dist/types/utils/oauth/callback-server.d.ts +57 -0
  106. package/dist/types/utils/oauth/cerebras.d.ts +1 -0
  107. package/dist/types/utils/oauth/cloudflare-ai-gateway.d.ts +18 -0
  108. package/dist/types/utils/oauth/cursor.d.ts +15 -0
  109. package/dist/types/utils/oauth/deepseek.d.ts +10 -0
  110. package/dist/types/utils/oauth/firepass.d.ts +1 -0
  111. package/dist/types/utils/oauth/fireworks.d.ts +1 -0
  112. package/dist/types/utils/oauth/github-copilot.d.ts +38 -0
  113. package/dist/types/utils/oauth/gitlab-duo.d.ts +3 -0
  114. package/dist/types/utils/oauth/google-antigravity.d.ts +11 -0
  115. package/dist/types/utils/oauth/google-gemini-cli.d.ts +10 -0
  116. package/dist/types/utils/oauth/google-oauth-shared.d.ts +28 -0
  117. package/dist/types/utils/oauth/huggingface.d.ts +19 -0
  118. package/dist/types/utils/oauth/index.d.ts +38 -0
  119. package/dist/types/utils/oauth/kagi.d.ts +17 -0
  120. package/dist/types/utils/oauth/kilo.d.ts +5 -0
  121. package/dist/types/utils/oauth/kimi.d.ts +21 -0
  122. package/dist/types/utils/oauth/litellm.d.ts +18 -0
  123. package/dist/types/utils/oauth/lm-studio.d.ts +17 -0
  124. package/dist/types/utils/oauth/minimax-code.d.ts +28 -0
  125. package/dist/types/utils/oauth/moonshot.d.ts +1 -0
  126. package/dist/types/utils/oauth/nanogpt.d.ts +1 -0
  127. package/dist/types/utils/oauth/nvidia.d.ts +18 -0
  128. package/dist/types/utils/oauth/ollama-cloud.d.ts +2 -0
  129. package/dist/types/utils/oauth/ollama.d.ts +18 -0
  130. package/dist/types/utils/oauth/openai-codex.d.ts +21 -0
  131. package/dist/types/utils/oauth/opencode.d.ts +18 -0
  132. package/dist/types/utils/oauth/parallel.d.ts +17 -0
  133. package/dist/types/utils/oauth/perplexity.d.ts +9 -0
  134. package/dist/types/utils/oauth/pkce.d.ts +8 -0
  135. package/dist/types/utils/oauth/qianfan.d.ts +17 -0
  136. package/dist/types/utils/oauth/qwen-portal.d.ts +19 -0
  137. package/dist/types/utils/oauth/synthetic.d.ts +1 -0
  138. package/dist/types/utils/oauth/tavily.d.ts +17 -0
  139. package/dist/types/utils/oauth/together.d.ts +1 -0
  140. package/dist/types/utils/oauth/types.d.ts +44 -0
  141. package/dist/types/utils/oauth/venice.d.ts +18 -0
  142. package/dist/types/utils/oauth/vercel-ai-gateway.d.ts +18 -0
  143. package/dist/types/utils/oauth/vllm.d.ts +16 -0
  144. package/dist/types/utils/oauth/xiaomi.d.ts +19 -0
  145. package/dist/types/utils/oauth/zai.d.ts +18 -0
  146. package/dist/types/utils/oauth/zenmux.d.ts +1 -0
  147. package/dist/types/utils/overflow.d.ts +54 -0
  148. package/dist/types/utils/parse-bind.d.ts +23 -0
  149. package/dist/types/utils/provider-response.d.ts +3 -0
  150. package/dist/types/utils/retry-after.d.ts +3 -0
  151. package/dist/types/utils/retry.d.ts +26 -0
  152. package/dist/types/utils/schema/adapt.d.ts +24 -0
  153. package/dist/types/utils/schema/compatibility.d.ts +30 -0
  154. package/dist/types/utils/schema/dereference.d.ts +11 -0
  155. package/dist/types/utils/schema/draft.d.ts +10 -0
  156. package/dist/types/utils/schema/equality.d.ts +4 -0
  157. package/dist/types/utils/schema/fields.d.ts +49 -0
  158. package/dist/types/utils/schema/index.d.ts +13 -0
  159. package/dist/types/utils/schema/json-schema-validator.d.ts +12 -0
  160. package/dist/types/utils/schema/meta-validator.d.ts +2 -0
  161. package/dist/types/utils/schema/normalize.d.ts +93 -0
  162. package/dist/types/utils/schema/spill.d.ts +8 -0
  163. package/dist/types/utils/schema/stamps.d.ts +25 -0
  164. package/dist/types/utils/schema/types.d.ts +4 -0
  165. package/dist/types/utils/schema/wire.d.ts +54 -0
  166. package/dist/types/utils/schema/zod-decontaminate.d.ts +31 -0
  167. package/dist/types/utils/sse-debug.d.ts +10 -0
  168. package/dist/types/utils/tool-call-healing.d.ts +71 -0
  169. package/dist/types/utils/tool-choice.d.ts +50 -0
  170. package/dist/types/utils/validation.d.ts +17 -0
  171. package/dist/types/utils.d.ts +28 -0
  172. package/package.json +146 -0
  173. package/src/api-registry.ts +96 -0
  174. package/src/auth-broker/client.ts +358 -0
  175. package/src/auth-broker/index.ts +5 -0
  176. package/src/auth-broker/refresher.ts +127 -0
  177. package/src/auth-broker/remote-store.ts +623 -0
  178. package/src/auth-broker/server.ts +644 -0
  179. package/src/auth-broker/types.ts +127 -0
  180. package/src/auth-broker/wire-schemas.ts +200 -0
  181. package/src/auth-gateway/http.ts +194 -0
  182. package/src/auth-gateway/index.ts +3 -0
  183. package/src/auth-gateway/server.ts +717 -0
  184. package/src/auth-gateway/types.ts +134 -0
  185. package/src/auth-storage.ts +4104 -0
  186. package/src/cli.ts +262 -0
  187. package/src/index.ts +54 -0
  188. package/src/model-cache.ts +129 -0
  189. package/src/model-manager.ts +450 -0
  190. package/src/model-thinking.ts +691 -0
  191. package/src/models.json +73853 -0
  192. package/src/models.json.d.ts +9 -0
  193. package/src/models.ts +56 -0
  194. package/src/prompts/turn-aborted-guidance.md +4 -0
  195. package/src/provider-details.ts +90 -0
  196. package/src/provider-models/bundled-references.ts +38 -0
  197. package/src/provider-models/descriptors.ts +308 -0
  198. package/src/provider-models/google.ts +91 -0
  199. package/src/provider-models/index.ts +5 -0
  200. package/src/provider-models/ollama.ts +153 -0
  201. package/src/provider-models/openai-compat.ts +2275 -0
  202. package/src/provider-models/special.ts +67 -0
  203. package/src/providers/amazon-bedrock.ts +849 -0
  204. package/src/providers/anthropic-messages-server-schema.ts +229 -0
  205. package/src/providers/anthropic-messages-server.ts +677 -0
  206. package/src/providers/anthropic.ts +2696 -0
  207. package/src/providers/aws-credentials.ts +501 -0
  208. package/src/providers/aws-eventstream.ts +185 -0
  209. package/src/providers/aws-sigv4.ts +218 -0
  210. package/src/providers/azure-openai-responses.ts +337 -0
  211. package/src/providers/cursor/gen/agent_pb.ts +15274 -0
  212. package/src/providers/cursor/proto/agent.proto +3526 -0
  213. package/src/providers/cursor/proto/buf.gen.yaml +6 -0
  214. package/src/providers/cursor/proto/buf.yaml +17 -0
  215. package/src/providers/cursor.ts +2561 -0
  216. package/src/providers/error-message.ts +21 -0
  217. package/src/providers/github-copilot-headers.ts +140 -0
  218. package/src/providers/gitlab-duo.ts +372 -0
  219. package/src/providers/google-auth.ts +252 -0
  220. package/src/providers/google-gemini-cli.ts +795 -0
  221. package/src/providers/google-gemini-headers.ts +41 -0
  222. package/src/providers/google-shared.ts +902 -0
  223. package/src/providers/google-types.ts +167 -0
  224. package/src/providers/google-vertex.ts +88 -0
  225. package/src/providers/google.ts +41 -0
  226. package/src/providers/grammar.ts +70 -0
  227. package/src/providers/kimi.ts +52 -0
  228. package/src/providers/mock.ts +500 -0
  229. package/src/providers/ollama.ts +544 -0
  230. package/src/providers/openai-anthropic-shim.ts +138 -0
  231. package/src/providers/openai-chat-server-schema.ts +243 -0
  232. package/src/providers/openai-chat-server.ts +628 -0
  233. package/src/providers/openai-codex/constants.ts +43 -0
  234. package/src/providers/openai-codex/request-transformer.ts +161 -0
  235. package/src/providers/openai-codex/response-handler.ts +81 -0
  236. package/src/providers/openai-codex-responses.ts +2598 -0
  237. package/src/providers/openai-completions-compat.ts +279 -0
  238. package/src/providers/openai-completions.ts +1853 -0
  239. package/src/providers/openai-responses-server-schema.ts +290 -0
  240. package/src/providers/openai-responses-server.ts +1183 -0
  241. package/src/providers/openai-responses-shared.ts +800 -0
  242. package/src/providers/openai-responses.ts +621 -0
  243. package/src/providers/pi-native-client.ts +228 -0
  244. package/src/providers/pi-native-server.ts +210 -0
  245. package/src/providers/register-builtins.ts +412 -0
  246. package/src/providers/synthetic.ts +50 -0
  247. package/src/providers/transform-messages.ts +309 -0
  248. package/src/providers/vision-guard.ts +31 -0
  249. package/src/rate-limit-utils.ts +84 -0
  250. package/src/stream.ts +895 -0
  251. package/src/types.ts +884 -0
  252. package/src/usage/claude.ts +431 -0
  253. package/src/usage/gemini.ts +250 -0
  254. package/src/usage/github-copilot.ts +421 -0
  255. package/src/usage/google-antigravity.ts +201 -0
  256. package/src/usage/kimi.ts +271 -0
  257. package/src/usage/minimax-code.ts +31 -0
  258. package/src/usage/openai-codex.ts +503 -0
  259. package/src/usage/shared.ts +10 -0
  260. package/src/usage/zai.ts +247 -0
  261. package/src/usage.ts +183 -0
  262. package/src/utils/abort.ts +51 -0
  263. package/src/utils/anthropic-auth.ts +87 -0
  264. package/src/utils/discovery/antigravity.ts +261 -0
  265. package/src/utils/discovery/codex.ts +371 -0
  266. package/src/utils/discovery/cursor.ts +306 -0
  267. package/src/utils/discovery/gemini.ts +248 -0
  268. package/src/utils/discovery/index.ts +4 -0
  269. package/src/utils/discovery/openai-compatible.ts +224 -0
  270. package/src/utils/event-stream.ts +142 -0
  271. package/src/utils/fireworks-model-id.ts +30 -0
  272. package/src/utils/foundry.ts +8 -0
  273. package/src/utils/h2-fetch.ts +60 -0
  274. package/src/utils/http-inspector.ts +176 -0
  275. package/src/utils/idle-iterator.ts +250 -0
  276. package/src/utils/json-parse.ts +148 -0
  277. package/src/utils/oauth/alibaba-coding-plan.ts +59 -0
  278. package/src/utils/oauth/anthropic.ts +200 -0
  279. package/src/utils/oauth/api-key-login.ts +87 -0
  280. package/src/utils/oauth/api-key-validation.ts +92 -0
  281. package/src/utils/oauth/callback-server.ts +276 -0
  282. package/src/utils/oauth/cerebras.ts +16 -0
  283. package/src/utils/oauth/cloudflare-ai-gateway.ts +48 -0
  284. package/src/utils/oauth/cursor.ts +157 -0
  285. package/src/utils/oauth/deepseek.ts +53 -0
  286. package/src/utils/oauth/firepass.ts +24 -0
  287. package/src/utils/oauth/fireworks.ts +15 -0
  288. package/src/utils/oauth/github-copilot.ts +362 -0
  289. package/src/utils/oauth/gitlab-duo.ts +123 -0
  290. package/src/utils/oauth/google-antigravity.ts +200 -0
  291. package/src/utils/oauth/google-gemini-cli.ts +256 -0
  292. package/src/utils/oauth/google-oauth-shared.ts +110 -0
  293. package/src/utils/oauth/huggingface.ts +62 -0
  294. package/src/utils/oauth/index.ts +444 -0
  295. package/src/utils/oauth/kagi.ts +47 -0
  296. package/src/utils/oauth/kilo.ts +87 -0
  297. package/src/utils/oauth/kimi.ts +254 -0
  298. package/src/utils/oauth/litellm.ts +47 -0
  299. package/src/utils/oauth/lm-studio.ts +38 -0
  300. package/src/utils/oauth/minimax-code.ts +78 -0
  301. package/src/utils/oauth/moonshot.ts +16 -0
  302. package/src/utils/oauth/nanogpt.ts +15 -0
  303. package/src/utils/oauth/nvidia.ts +70 -0
  304. package/src/utils/oauth/oauth.html +199 -0
  305. package/src/utils/oauth/ollama-cloud.ts +28 -0
  306. package/src/utils/oauth/ollama.ts +47 -0
  307. package/src/utils/oauth/openai-codex.ts +299 -0
  308. package/src/utils/oauth/opencode.ts +49 -0
  309. package/src/utils/oauth/parallel.ts +46 -0
  310. package/src/utils/oauth/perplexity.ts +206 -0
  311. package/src/utils/oauth/pkce.ts +18 -0
  312. package/src/utils/oauth/qianfan.ts +58 -0
  313. package/src/utils/oauth/qwen-portal.ts +60 -0
  314. package/src/utils/oauth/synthetic.ts +16 -0
  315. package/src/utils/oauth/tavily.ts +46 -0
  316. package/src/utils/oauth/together.ts +16 -0
  317. package/src/utils/oauth/types.ts +94 -0
  318. package/src/utils/oauth/venice.ts +59 -0
  319. package/src/utils/oauth/vercel-ai-gateway.ts +47 -0
  320. package/src/utils/oauth/vllm.ts +40 -0
  321. package/src/utils/oauth/xiaomi.ts +137 -0
  322. package/src/utils/oauth/zai.ts +60 -0
  323. package/src/utils/oauth/zenmux.ts +15 -0
  324. package/src/utils/overflow.ts +137 -0
  325. package/src/utils/parse-bind.ts +54 -0
  326. package/src/utils/provider-response.ts +30 -0
  327. package/src/utils/retry-after.ts +110 -0
  328. package/src/utils/retry.ts +54 -0
  329. package/src/utils/schema/CONSTRAINTS.md +164 -0
  330. package/src/utils/schema/adapt.ts +36 -0
  331. package/src/utils/schema/compatibility.ts +435 -0
  332. package/src/utils/schema/dereference.ts +98 -0
  333. package/src/utils/schema/draft.ts +341 -0
  334. package/src/utils/schema/equality.ts +97 -0
  335. package/src/utils/schema/fields.ts +190 -0
  336. package/src/utils/schema/index.ts +13 -0
  337. package/src/utils/schema/json-schema-validator.ts +577 -0
  338. package/src/utils/schema/meta-validator.ts +167 -0
  339. package/src/utils/schema/normalize.ts +1588 -0
  340. package/src/utils/schema/spill.ts +43 -0
  341. package/src/utils/schema/stamps.ts +97 -0
  342. package/src/utils/schema/types.ts +11 -0
  343. package/src/utils/schema/wire.ts +213 -0
  344. package/src/utils/schema/zod-decontaminate.ts +331 -0
  345. package/src/utils/sse-debug.ts +289 -0
  346. package/src/utils/tool-call-healing.ts +271 -0
  347. package/src/utils/tool-choice.ts +99 -0
  348. package/src/utils/validation.ts +1019 -0
  349. package/src/utils.ts +166 -0
@@ -0,0 +1,544 @@
1
+ import { extractHttpStatusFromError, fetchWithRetry } from "@gajae-code/utils";
2
+ import { getEnvApiKey } from "../stream";
3
+ import type {
4
+ Api,
5
+ AssistantMessage,
6
+ Context,
7
+ DeveloperMessage,
8
+ Message,
9
+ Model,
10
+ StreamFunction,
11
+ StreamOptions,
12
+ Tool,
13
+ ToolChoice,
14
+ ToolResultMessage,
15
+ UserMessage,
16
+ } from "../types";
17
+ import { normalizeSystemPrompts } from "../utils";
18
+ import { AssistantMessageEventStream } from "../utils/event-stream";
19
+ import { finalizeErrorMessage, type RawHttpRequestDump } from "../utils/http-inspector";
20
+ import { parseStreamingJson } from "../utils/json-parse";
21
+ import { toolWireSchema } from "../utils/schema/wire";
22
+ import { transformMessages } from "./transform-messages";
23
+
24
+ export interface OllamaChatOptions extends StreamOptions {
25
+ reasoning?: "minimal" | "low" | "medium" | "high" | "xhigh";
26
+ toolChoice?: ToolChoice;
27
+ }
28
+
29
+ type OllamaFunctionTool = {
30
+ type: "function";
31
+ function: {
32
+ name: string;
33
+ description: string;
34
+ parameters: Record<string, unknown>;
35
+ };
36
+ };
37
+
38
+ type OllamaMessage = {
39
+ role: "system" | "user" | "assistant" | "tool";
40
+ content: string;
41
+ images?: string[];
42
+ thinking?: string;
43
+ tool_calls?: Array<{
44
+ type: "function";
45
+ function: {
46
+ index?: number;
47
+ name: string;
48
+ arguments: Record<string, unknown>;
49
+ };
50
+ }>;
51
+ tool_name?: string;
52
+ };
53
+
54
+ type OllamaChatChunk = {
55
+ message?: {
56
+ role?: string;
57
+ content?: string;
58
+ thinking?: string;
59
+ tool_calls?: Array<{
60
+ type?: string;
61
+ function?: {
62
+ index?: number;
63
+ name?: string;
64
+ arguments?: Record<string, unknown> | string;
65
+ };
66
+ }>;
67
+ };
68
+ done?: boolean;
69
+ done_reason?: string;
70
+ prompt_eval_count?: number;
71
+ eval_count?: number;
72
+ };
73
+
74
+ type InternalToolCallBlock = AssistantMessage["content"][number] & {
75
+ type: "toolCall";
76
+ partialJson?: string;
77
+ };
78
+
79
+ function normalizeBaseUrl(baseUrl?: string): string {
80
+ const value = baseUrl?.trim();
81
+ if (!value) {
82
+ return "https://ollama.com";
83
+ }
84
+ const trimmed = value.endsWith("/") ? value.slice(0, -1) : value;
85
+ return trimmed.endsWith("/api") ? trimmed.slice(0, -4) : trimmed;
86
+ }
87
+
88
+ function mapReasoning(reasoning: OllamaChatOptions["reasoning"]): boolean | "low" | "medium" | "high" | undefined {
89
+ switch (reasoning) {
90
+ case "minimal":
91
+ case "low":
92
+ return "low";
93
+ case "medium":
94
+ return "medium";
95
+ case "high":
96
+ case "xhigh":
97
+ return "high";
98
+ default:
99
+ return undefined;
100
+ }
101
+ }
102
+
103
+ function mapToolChoice(toolChoice: ToolChoice | undefined): "auto" | "none" | "required" | undefined {
104
+ if (!toolChoice || toolChoice === "auto") {
105
+ return undefined;
106
+ }
107
+ if (toolChoice === "none") {
108
+ return "none";
109
+ }
110
+ if (toolChoice === "required" || toolChoice === "any") {
111
+ return "required";
112
+ }
113
+ if (typeof toolChoice === "object") {
114
+ return "required";
115
+ }
116
+ return undefined;
117
+ }
118
+
119
+ function getNamedToolChoiceName(toolChoice: ToolChoice | undefined): string | undefined {
120
+ if (!toolChoice || typeof toolChoice === "string") {
121
+ return undefined;
122
+ }
123
+ if ("function" in toolChoice) {
124
+ return toolChoice.function.name;
125
+ }
126
+ return toolChoice.name;
127
+ }
128
+
129
+ function selectToolsForToolChoice(tools: Tool[] | undefined, toolChoice: ToolChoice | undefined): Tool[] | undefined {
130
+ const toolName = getNamedToolChoiceName(toolChoice);
131
+ if (!toolName || !tools) {
132
+ return tools;
133
+ }
134
+ for (const tool of tools) {
135
+ if (tool.name === toolName) {
136
+ return [tool];
137
+ }
138
+ }
139
+ return [];
140
+ }
141
+
142
+ function toPlainContent(content: string | Array<{ type: "text" | "image"; text?: string; data?: string }>): {
143
+ content: string;
144
+ images?: string[];
145
+ } {
146
+ if (typeof content === "string") {
147
+ return { content };
148
+ }
149
+ const textParts: string[] = [];
150
+ const images: string[] = [];
151
+ for (const block of content) {
152
+ if (block.type === "text" && typeof block.text === "string") {
153
+ textParts.push(block.text);
154
+ }
155
+ if (block.type === "image" && typeof block.data === "string") {
156
+ images.push(block.data);
157
+ }
158
+ }
159
+ return {
160
+ content: textParts.join("\n"),
161
+ ...(images.length > 0 ? { images } : {}),
162
+ };
163
+ }
164
+
165
+ function convertMessage(message: Message): OllamaMessage {
166
+ if (message.role === "user") {
167
+ const converted = toPlainContent(message.content as UserMessage["content"]);
168
+ return { role: "user", ...converted };
169
+ }
170
+ if (message.role === "developer") {
171
+ const converted = toPlainContent(message.content as DeveloperMessage["content"]);
172
+ return { role: "system", ...converted };
173
+ }
174
+ if (message.role === "toolResult") {
175
+ const converted = toPlainContent(message.content as ToolResultMessage["content"]);
176
+ return {
177
+ role: "tool",
178
+ tool_name: message.toolName,
179
+ ...converted,
180
+ };
181
+ }
182
+ const text: string[] = [];
183
+ const thinking: string[] = [];
184
+ const toolCalls: NonNullable<OllamaMessage["tool_calls"]> = [];
185
+ for (const block of message.content) {
186
+ if (block.type === "text") {
187
+ text.push(block.text);
188
+ continue;
189
+ }
190
+ if (block.type === "thinking") {
191
+ thinking.push(block.thinking);
192
+ continue;
193
+ }
194
+ if (block.type === "toolCall") {
195
+ toolCalls.push({
196
+ type: "function",
197
+ function: {
198
+ name: block.name,
199
+ arguments: block.arguments,
200
+ },
201
+ });
202
+ }
203
+ }
204
+ return {
205
+ role: "assistant",
206
+ content: text.join("\n"),
207
+ ...(thinking.length > 0 ? { thinking: thinking.join("\n") } : {}),
208
+ ...(toolCalls.length > 0 ? { tool_calls: toolCalls } : {}),
209
+ };
210
+ }
211
+
212
+ function convertMessages(model: Model<"ollama-chat">, context: Context): OllamaMessage[] {
213
+ const messages: Message[] = [];
214
+ // Emit one developer message per ordered system prompt. The wire role is mapped to "system"
215
+ // by `convertMessage`, but keeping the prompts separate preserves prefix-cache stability:
216
+ // if only the trailing prompt changes between calls, the leading system messages keep
217
+ // their identical token prefix so KV-cache reuse covers them.
218
+ for (const systemPrompt of normalizeSystemPrompts(context.systemPrompt)) {
219
+ messages.push({
220
+ role: "developer",
221
+ content: systemPrompt,
222
+ timestamp: Date.now(),
223
+ });
224
+ }
225
+ messages.push(...context.messages);
226
+ const isCloud = model.provider === "ollama-cloud";
227
+ return transformMessages(messages, model).map(msg => {
228
+ const converted = convertMessage(msg);
229
+ // Ollama cloud rejects requests when assistant history messages contain the `thinking`
230
+ // field — it's valid in model responses but not accepted as a history input. Strip it
231
+ // to prevent HTTP 400 errors. Local Ollama instances are unaffected.
232
+ if (isCloud && converted.role === "assistant" && converted.thinking) {
233
+ const { thinking: _t, ...rest } = converted;
234
+ return rest;
235
+ }
236
+ return converted;
237
+ });
238
+ }
239
+
240
+ function convertTools(tools: Tool[] | undefined): OllamaFunctionTool[] | undefined {
241
+ if (!tools || tools.length === 0) {
242
+ return undefined;
243
+ }
244
+ return tools.map(tool => ({
245
+ type: "function",
246
+ function: {
247
+ name: tool.name,
248
+ description: tool.description,
249
+ parameters: toolWireSchema(tool),
250
+ },
251
+ }));
252
+ }
253
+
254
+ function createChatBody(model: Model<"ollama-chat">, context: Context, options: OllamaChatOptions | undefined) {
255
+ const think = mapReasoning(options?.reasoning);
256
+ const toolChoice = mapToolChoice(options?.toolChoice);
257
+ const selectedTools = selectToolsForToolChoice(context.tools, options?.toolChoice);
258
+ const tools = convertTools(selectedTools);
259
+ return {
260
+ model: model.id,
261
+ messages: convertMessages(model, context),
262
+ ...(tools ? { tools } : {}),
263
+ ...(think !== undefined ? { think } : {}),
264
+ ...(toolChoice !== undefined ? { tool_choice: toolChoice } : {}),
265
+ ...(options?.maxTokens !== undefined ? { options: { num_predict: options.maxTokens } } : {}),
266
+ stream: true,
267
+ };
268
+ }
269
+
270
+ async function* iterateNdjson(stream: ReadableStream<Uint8Array>): AsyncGenerator<OllamaChatChunk> {
271
+ const reader = stream.getReader();
272
+ const decoder = new TextDecoder();
273
+ let buffer = "";
274
+ while (true) {
275
+ const { done, value } = await reader.read();
276
+ if (done) {
277
+ break;
278
+ }
279
+ buffer += decoder.decode(value, { stream: true });
280
+ while (true) {
281
+ const newlineIndex = buffer.indexOf("\n");
282
+ if (newlineIndex < 0) {
283
+ break;
284
+ }
285
+ const line = buffer.slice(0, newlineIndex).trim();
286
+ buffer = buffer.slice(newlineIndex + 1);
287
+ if (!line) {
288
+ continue;
289
+ }
290
+ yield JSON.parse(line) as OllamaChatChunk;
291
+ }
292
+ }
293
+ buffer += decoder.decode();
294
+ const tail = buffer.trim();
295
+ if (tail) {
296
+ yield JSON.parse(tail) as OllamaChatChunk;
297
+ }
298
+ }
299
+
300
+ function createEmptyOutput(model: Model<"ollama-chat">): AssistantMessage {
301
+ return {
302
+ role: "assistant",
303
+ content: [],
304
+ api: "ollama-chat" as Api,
305
+ provider: model.provider,
306
+ model: model.id,
307
+ usage: {
308
+ input: 0,
309
+ output: 0,
310
+ cacheRead: 0,
311
+ cacheWrite: 0,
312
+ totalTokens: 0,
313
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
314
+ },
315
+ stopReason: "stop",
316
+ timestamp: Date.now(),
317
+ };
318
+ }
319
+
320
+ function endThinkingBlock(stream: AssistantMessageEventStream, output: AssistantMessage, index: number): void {
321
+ const block = output.content[index];
322
+ if (block?.type === "thinking") {
323
+ stream.push({ type: "thinking_end", contentIndex: index, content: block.thinking, partial: output });
324
+ }
325
+ }
326
+
327
+ function endTextBlock(stream: AssistantMessageEventStream, output: AssistantMessage, index: number): void {
328
+ const block = output.content[index];
329
+ if (block?.type === "text") {
330
+ stream.push({ type: "text_end", contentIndex: index, content: block.text, partial: output });
331
+ }
332
+ }
333
+
334
+ function endToolCallBlock(stream: AssistantMessageEventStream, output: AssistantMessage, index: number): void {
335
+ const block = output.content[index];
336
+ if (block?.type !== "toolCall") {
337
+ return;
338
+ }
339
+ const toolCall = block as InternalToolCallBlock;
340
+ if (toolCall.partialJson) {
341
+ toolCall.arguments = parseStreamingJson<Record<string, unknown>>(toolCall.partialJson);
342
+ delete toolCall.partialJson;
343
+ }
344
+ stream.push({ type: "toolcall_end", contentIndex: index, toolCall, partial: output });
345
+ }
346
+
347
+ function mapDoneReason(doneReason: string | undefined, output: AssistantMessage): AssistantMessage["stopReason"] {
348
+ if (doneReason === "length") {
349
+ return "length";
350
+ }
351
+ if (doneReason === "tool_calls") {
352
+ return "toolUse";
353
+ }
354
+ if (doneReason === undefined && output.content.some(block => block.type === "toolCall")) {
355
+ return "toolUse";
356
+ }
357
+ return "stop";
358
+ }
359
+
360
+ const OLLAMA_RETRY_DELAYS_MS = [2_000, 5_000, 10_000];
361
+
362
+ export const streamOllama: StreamFunction<"ollama-chat"> = (
363
+ model: Model<"ollama-chat">,
364
+ context: Context,
365
+ options: OllamaChatOptions,
366
+ ): AssistantMessageEventStream => {
367
+ const stream = new AssistantMessageEventStream();
368
+ void (async () => {
369
+ const startTime = Date.now();
370
+ let firstTokenTime: number | undefined;
371
+ const output = createEmptyOutput(model);
372
+ let rawRequestDump: RawHttpRequestDump | undefined;
373
+ let activeThinkingIndex: number | undefined;
374
+ let activeTextIndex: number | undefined;
375
+ const activeToolIndices = new Set<number>();
376
+ try {
377
+ const apiKey = options.apiKey || getEnvApiKey(model.provider);
378
+ if (!apiKey) {
379
+ throw new Error(`No API key for provider: ${model.provider}`);
380
+ }
381
+ const baseUrl = normalizeBaseUrl(model.baseUrl);
382
+ let body = createChatBody(model, context, options);
383
+ const replacementPayload = await options.onPayload?.(body, model);
384
+ if (replacementPayload !== undefined) {
385
+ body = replacementPayload as typeof body;
386
+ }
387
+ rawRequestDump = {
388
+ provider: model.provider,
389
+ api: model.api,
390
+ model: model.id,
391
+ method: "POST",
392
+ url: `${baseUrl}/api/chat`,
393
+ body,
394
+ };
395
+ const response = await fetchWithRetry(`${baseUrl}/api/chat`, {
396
+ method: "POST",
397
+ headers: {
398
+ ...model.headers,
399
+ ...options.headers,
400
+ Authorization: `Bearer ${apiKey}`,
401
+ "Content-Type": "application/json",
402
+ },
403
+ body: JSON.stringify(body),
404
+ signal: options.signal,
405
+ defaultDelayMs: OLLAMA_RETRY_DELAYS_MS,
406
+ fetch: options.fetch,
407
+ });
408
+ if (!response.ok) {
409
+ throw new Error(`HTTP ${response.status} from ${baseUrl}/api/chat`);
410
+ }
411
+ if (!response.body) {
412
+ throw new Error("Ollama returned an empty response body");
413
+ }
414
+ stream.push({ type: "start", partial: output });
415
+ for await (const chunk of iterateNdjson(response.body)) {
416
+ if (chunk.message?.thinking) {
417
+ if (activeTextIndex !== undefined) {
418
+ endTextBlock(stream, output, activeTextIndex);
419
+ activeTextIndex = undefined;
420
+ }
421
+ if (activeThinkingIndex === undefined) {
422
+ output.content.push({ type: "thinking", thinking: "" });
423
+ activeThinkingIndex = output.content.length - 1;
424
+ stream.push({ type: "thinking_start", contentIndex: activeThinkingIndex, partial: output });
425
+ }
426
+ const block = output.content[activeThinkingIndex];
427
+ if (block?.type === "thinking") {
428
+ block.thinking += chunk.message.thinking;
429
+ stream.push({
430
+ type: "thinking_delta",
431
+ contentIndex: activeThinkingIndex,
432
+ delta: chunk.message.thinking,
433
+ partial: output,
434
+ });
435
+ }
436
+ if (!firstTokenTime) {
437
+ firstTokenTime = Date.now();
438
+ }
439
+ }
440
+ if (chunk.message?.content) {
441
+ if (activeThinkingIndex !== undefined) {
442
+ endThinkingBlock(stream, output, activeThinkingIndex);
443
+ activeThinkingIndex = undefined;
444
+ }
445
+ if (activeTextIndex === undefined) {
446
+ output.content.push({ type: "text", text: "" });
447
+ activeTextIndex = output.content.length - 1;
448
+ stream.push({ type: "text_start", contentIndex: activeTextIndex, partial: output });
449
+ }
450
+ const block = output.content[activeTextIndex];
451
+ if (block?.type === "text") {
452
+ block.text += chunk.message.content;
453
+ stream.push({
454
+ type: "text_delta",
455
+ contentIndex: activeTextIndex,
456
+ delta: chunk.message.content,
457
+ partial: output,
458
+ });
459
+ }
460
+ if (!firstTokenTime) {
461
+ firstTokenTime = Date.now();
462
+ }
463
+ }
464
+ if (chunk.message?.tool_calls?.length) {
465
+ if (activeThinkingIndex !== undefined) {
466
+ endThinkingBlock(stream, output, activeThinkingIndex);
467
+ activeThinkingIndex = undefined;
468
+ }
469
+ if (activeTextIndex !== undefined) {
470
+ endTextBlock(stream, output, activeTextIndex);
471
+ activeTextIndex = undefined;
472
+ }
473
+ for (const call of chunk.message.tool_calls) {
474
+ const name = call.function?.name ?? "unknown_tool";
475
+ const rawArgs = call.function?.arguments;
476
+ const partialJson = typeof rawArgs === "string" ? rawArgs : JSON.stringify(rawArgs ?? {});
477
+ const toolCall: InternalToolCallBlock = {
478
+ type: "toolCall",
479
+ id: `ollama:${output.content.length}:${name}`,
480
+ name,
481
+ arguments: parseStreamingJson<Record<string, unknown>>(partialJson),
482
+ partialJson,
483
+ };
484
+ output.content.push(toolCall);
485
+ const index = output.content.length - 1;
486
+ activeToolIndices.add(index);
487
+ stream.push({ type: "toolcall_start", contentIndex: index, partial: output });
488
+ stream.push({
489
+ type: "toolcall_delta",
490
+ contentIndex: index,
491
+ delta: partialJson,
492
+ partial: output,
493
+ });
494
+ if (!firstTokenTime) {
495
+ firstTokenTime = Date.now();
496
+ }
497
+ }
498
+ }
499
+ if (chunk.done) {
500
+ if (activeThinkingIndex !== undefined) {
501
+ endThinkingBlock(stream, output, activeThinkingIndex);
502
+ activeThinkingIndex = undefined;
503
+ }
504
+ if (activeTextIndex !== undefined) {
505
+ endTextBlock(stream, output, activeTextIndex);
506
+ activeTextIndex = undefined;
507
+ }
508
+ for (const index of activeToolIndices) {
509
+ endToolCallBlock(stream, output, index);
510
+ }
511
+ activeToolIndices.clear();
512
+ output.stopReason = mapDoneReason(chunk.done_reason, output);
513
+ output.usage.input = chunk.prompt_eval_count ?? 0;
514
+ output.usage.output = chunk.eval_count ?? 0;
515
+ output.usage.totalTokens = output.usage.input + output.usage.output;
516
+ }
517
+ }
518
+ output.duration = Date.now() - startTime;
519
+ if (firstTokenTime) {
520
+ output.ttft = firstTokenTime - startTime;
521
+ }
522
+ const doneReason =
523
+ output.stopReason === "length" ? "length" : output.stopReason === "toolUse" ? "toolUse" : "stop";
524
+ stream.push({ type: "done", reason: doneReason, message: output });
525
+ stream.end();
526
+ } catch (error) {
527
+ for (const block of output.content) {
528
+ if (block.type === "toolCall") {
529
+ delete (block as InternalToolCallBlock).partialJson;
530
+ }
531
+ }
532
+ output.stopReason = options.signal?.aborted ? "aborted" : "error";
533
+ output.errorStatus = extractHttpStatusFromError(error);
534
+ output.errorMessage = await finalizeErrorMessage(error, rawRequestDump);
535
+ output.duration = Date.now() - startTime;
536
+ if (firstTokenTime) {
537
+ output.ttft = firstTokenTime - startTime;
538
+ }
539
+ stream.push({ type: "error", reason: output.stopReason, error: output });
540
+ stream.end();
541
+ }
542
+ })();
543
+ return stream;
544
+ };
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Shared implementation for providers that expose BOTH an OpenAI-compatible
3
+ * and an Anthropic-compatible API surface against the same model catalog
4
+ * (currently Kimi Code and Synthetic).
5
+ *
6
+ * Each call site supplies the provider-specific bits (base URLs, default
7
+ * format, optional extra headers); the streaming/forwarding plumbing lives
8
+ * here once.
9
+ */
10
+
11
+ import { ANTHROPIC_THINKING } from "../stream";
12
+ import type { Context, Model, SimpleStreamOptions } from "../types";
13
+ import { AssistantMessageEventStream } from "../utils/event-stream";
14
+ import { createProviderErrorMessage } from "./error-message";
15
+ import { streamAnthropic, streamOpenAICompletions } from "./register-builtins";
16
+
17
+ export type OpenAIAnthropicApiFormat = "openai" | "anthropic";
18
+
19
+ export interface OpenAIAnthropicShimOptions extends SimpleStreamOptions {
20
+ /** API format: "openai" or "anthropic". */
21
+ format?: OpenAIAnthropicApiFormat;
22
+ }
23
+
24
+ export interface OpenAIAnthropicShimConfig {
25
+ /** Base URL for the Anthropic-compatible endpoint (without trailing /v1/messages). */
26
+ anthropicBaseUrl: string;
27
+ /** Optional override for the OpenAI-compatible base URL. If omitted, `model.baseUrl` is used as-is. */
28
+ openaiBaseUrl?: string;
29
+ /** Default API format when caller does not specify one. */
30
+ defaultFormat: OpenAIAnthropicApiFormat;
31
+ /** Provider-specific headers (e.g. auth/session) merged ahead of user-supplied headers. */
32
+ extraHeaders?: () => Record<string, string>;
33
+ }
34
+
35
+ /**
36
+ * Stream from an OpenAI-or-Anthropic compatible provider. Returns synchronously;
37
+ * async header fetching and stream piping happen internally.
38
+ */
39
+ export function streamOpenAIAnthropicShim(
40
+ model: Model<"openai-completions">,
41
+ context: Context,
42
+ options: OpenAIAnthropicShimOptions | undefined,
43
+ config: OpenAIAnthropicShimConfig,
44
+ ): AssistantMessageEventStream {
45
+ const stream = new AssistantMessageEventStream();
46
+ const format = options?.format ?? config.defaultFormat;
47
+
48
+ (async () => {
49
+ try {
50
+ const mergedHeaders = {
51
+ ...(config.extraHeaders?.() ?? {}),
52
+ ...options?.headers,
53
+ };
54
+
55
+ if (format === "anthropic") {
56
+ const anthropicModel: Model<"anthropic-messages"> = {
57
+ id: model.id,
58
+ name: model.name,
59
+ api: "anthropic-messages",
60
+ provider: model.provider,
61
+ baseUrl: config.anthropicBaseUrl,
62
+ headers: mergedHeaders,
63
+ contextWindow: model.contextWindow,
64
+ maxTokens: model.maxTokens,
65
+ reasoning: model.reasoning,
66
+ input: model.input,
67
+ cost: model.cost,
68
+ };
69
+
70
+ const reasoningEffort = options?.reasoning;
71
+ const thinkingEnabled = !!reasoningEffort && model.reasoning;
72
+ const thinkingBudget = reasoningEffort
73
+ ? (options?.thinkingBudgets?.[reasoningEffort] ?? ANTHROPIC_THINKING[reasoningEffort])
74
+ : undefined;
75
+
76
+ const innerStream = streamAnthropic(anthropicModel, context, {
77
+ apiKey: options?.apiKey,
78
+ temperature: options?.temperature,
79
+ topP: options?.topP,
80
+ topK: options?.topK,
81
+ minP: options?.minP,
82
+ presencePenalty: options?.presencePenalty,
83
+ repetitionPenalty: options?.repetitionPenalty,
84
+ maxTokens: options?.maxTokens ?? Math.min(model.maxTokens, 32000),
85
+ signal: options?.signal,
86
+ headers: mergedHeaders,
87
+ sessionId: options?.sessionId,
88
+ onPayload: options?.onPayload,
89
+ onResponse: options?.onResponse,
90
+ onSseEvent: options?.onSseEvent,
91
+ fetch: options?.fetch,
92
+ thinkingEnabled,
93
+ thinkingBudgetTokens: thinkingBudget,
94
+ });
95
+
96
+ for await (const event of innerStream) {
97
+ stream.push(event);
98
+ }
99
+ } else {
100
+ const openaiModel: Model<"openai-completions"> = config.openaiBaseUrl
101
+ ? { ...model, baseUrl: config.openaiBaseUrl, headers: mergedHeaders }
102
+ : model;
103
+
104
+ const reasoningEffort = options?.reasoning;
105
+ const innerStream = streamOpenAICompletions(openaiModel, context, {
106
+ apiKey: options?.apiKey,
107
+ temperature: options?.temperature,
108
+ topP: options?.topP,
109
+ topK: options?.topK,
110
+ minP: options?.minP,
111
+ presencePenalty: options?.presencePenalty,
112
+ repetitionPenalty: options?.repetitionPenalty,
113
+ maxTokens: options?.maxTokens ?? model.maxTokens,
114
+ signal: options?.signal,
115
+ headers: mergedHeaders,
116
+ sessionId: options?.sessionId,
117
+ onPayload: options?.onPayload,
118
+ onResponse: options?.onResponse,
119
+ onSseEvent: options?.onSseEvent,
120
+ fetch: options?.fetch,
121
+ reasoning: reasoningEffort,
122
+ });
123
+
124
+ for await (const event of innerStream) {
125
+ stream.push(event);
126
+ }
127
+ }
128
+ } catch (err) {
129
+ stream.push({
130
+ type: "error",
131
+ reason: "error",
132
+ error: createProviderErrorMessage(model, err),
133
+ });
134
+ }
135
+ })();
136
+
137
+ return stream;
138
+ }