@full-self-developing/fsd 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1191) hide show
  1. package/.engine/engine-config.json +27 -0
  2. package/CODEBASE_CONTEXT.md +152 -0
  3. package/README.md +111 -0
  4. package/README_zh.md +111 -0
  5. package/UI_SPEC.md +57 -0
  6. package/agents/api-proxy.js +542 -0
  7. package/agents/base.js +280 -0
  8. package/agents/branch-manager.js +135 -0
  9. package/agents/cli-models.json +48 -0
  10. package/agents/coder.js +128 -0
  11. package/agents/core-request.js +174 -0
  12. package/agents/dispatcher.js +491 -0
  13. package/agents/drivers/.atomcode/graph.bin +0 -0
  14. package/agents/drivers/atomcode.js +143 -0
  15. package/agents/drivers/gemini-cli.js +195 -0
  16. package/agents/drivers/index.js +65 -0
  17. package/agents/drivers/openrouter.js +390 -0
  18. package/agents/engine-config.js +444 -0
  19. package/agents/log-fixer.js +72 -0
  20. package/agents/mcp-client-manager.js +159 -0
  21. package/agents/optimizer.js +54 -0
  22. package/agents/path-validator.js +43 -0
  23. package/agents/planner.js +81 -0
  24. package/agents/prompt-manager.js +170 -0
  25. package/agents/skeptic.js +79 -0
  26. package/agents/skills-manager.js +130 -0
  27. package/agents/summarizer.js +34 -0
  28. package/agents/test-runner.js +85 -0
  29. package/bin/cli.js +166 -0
  30. package/client/eslint.config.js +21 -0
  31. package/client/index.html +12 -0
  32. package/client/package-lock.json +3339 -0
  33. package/client/package.json +35 -0
  34. package/client/src/App.jsx +745 -0
  35. package/client/src/api.js +78 -0
  36. package/client/src/components/ChatPanel.jsx +277 -0
  37. package/client/src/components/ConfirmationModal.jsx +61 -0
  38. package/client/src/components/ErrorBoundary.jsx +66 -0
  39. package/client/src/components/FolderPicker.jsx +200 -0
  40. package/client/src/components/LoopPanel.jsx +863 -0
  41. package/client/src/components/NotFound.jsx +52 -0
  42. package/client/src/components/SettingsPanel.jsx +966 -0
  43. package/client/src/components/Sidebar.jsx +318 -0
  44. package/client/src/context/SettingsContext.jsx +353 -0
  45. package/client/src/i18n.js +462 -0
  46. package/client/src/index.css +31 -0
  47. package/client/src/main.jsx +17 -0
  48. package/client/vite.config.js +19 -0
  49. package/design.md +875 -0
  50. package/extensions/alibaba/index.ts +11 -0
  51. package/extensions/alibaba/openclaw.plugin.json +34 -0
  52. package/extensions/alibaba/package.json +15 -0
  53. package/extensions/alibaba/plugin-registration.contract.test.ts +7 -0
  54. package/extensions/alibaba/tsconfig.json +16 -0
  55. package/extensions/alibaba/video-generation-provider.test.ts +92 -0
  56. package/extensions/alibaba/video-generation-provider.ts +83 -0
  57. package/extensions/amazon-bedrock/api.ts +6 -0
  58. package/extensions/amazon-bedrock/aws-credential-refresh.ts +42 -0
  59. package/extensions/amazon-bedrock/config-api.ts +4 -0
  60. package/extensions/amazon-bedrock/config-compat.test.ts +81 -0
  61. package/extensions/amazon-bedrock/config-compat.ts +107 -0
  62. package/extensions/amazon-bedrock/discovery-shared.ts +28 -0
  63. package/extensions/amazon-bedrock/discovery.test.ts +608 -0
  64. package/extensions/amazon-bedrock/discovery.ts +616 -0
  65. package/extensions/amazon-bedrock/embedding-provider.test.ts +109 -0
  66. package/extensions/amazon-bedrock/embedding-provider.ts +470 -0
  67. package/extensions/amazon-bedrock/index.test.ts +1249 -0
  68. package/extensions/amazon-bedrock/index.ts +11 -0
  69. package/extensions/amazon-bedrock/lazy-import.test.ts +56 -0
  70. package/extensions/amazon-bedrock/memory-embedding-adapter.test.ts +105 -0
  71. package/extensions/amazon-bedrock/memory-embedding-adapter.ts +47 -0
  72. package/extensions/amazon-bedrock/npm-shrinkwrap.json +1241 -0
  73. package/extensions/amazon-bedrock/openclaw.plugin.json +80 -0
  74. package/extensions/amazon-bedrock/package.json +41 -0
  75. package/extensions/amazon-bedrock/provider-policy-api.test.ts +46 -0
  76. package/extensions/amazon-bedrock/provider-policy-api.ts +9 -0
  77. package/extensions/amazon-bedrock/register.sync.runtime.ts +659 -0
  78. package/extensions/amazon-bedrock/setup-api.ts +18 -0
  79. package/extensions/amazon-bedrock/thinking-policy.ts +32 -0
  80. package/extensions/amazon-bedrock/tsconfig.json +16 -0
  81. package/extensions/anthropic/api.ts +11 -0
  82. package/extensions/anthropic/claude-model-refs.ts +104 -0
  83. package/extensions/anthropic/cli-auth-seam.ts +13 -0
  84. package/extensions/anthropic/cli-backend-api.ts +6 -0
  85. package/extensions/anthropic/cli-backend.ts +83 -0
  86. package/extensions/anthropic/cli-catalog.ts +42 -0
  87. package/extensions/anthropic/cli-constants.ts +41 -0
  88. package/extensions/anthropic/cli-migration.test.ts +487 -0
  89. package/extensions/anthropic/cli-migration.ts +266 -0
  90. package/extensions/anthropic/cli-shared.test.ts +300 -0
  91. package/extensions/anthropic/cli-shared.ts +248 -0
  92. package/extensions/anthropic/config-defaults.ts +428 -0
  93. package/extensions/anthropic/contract-api.ts +9 -0
  94. package/extensions/anthropic/doctor-contract-api.ts +14 -0
  95. package/extensions/anthropic/index.test.ts +663 -0
  96. package/extensions/anthropic/index.ts +11 -0
  97. package/extensions/anthropic/media-understanding-provider.ts +15 -0
  98. package/extensions/anthropic/openclaw.plugin.json +112 -0
  99. package/extensions/anthropic/package.json +18 -0
  100. package/extensions/anthropic/provider-contract-api.ts +59 -0
  101. package/extensions/anthropic/provider-discovery.ts +35 -0
  102. package/extensions/anthropic/provider-policy-api.test.ts +135 -0
  103. package/extensions/anthropic/provider-policy-api.ts +24 -0
  104. package/extensions/anthropic/provider-runtime.contract.test.ts +3 -0
  105. package/extensions/anthropic/register.runtime.ts +668 -0
  106. package/extensions/anthropic/replay-policy.ts +9 -0
  107. package/extensions/anthropic/setup-api.ts +11 -0
  108. package/extensions/anthropic/stream-wrappers.test.ts +233 -0
  109. package/extensions/anthropic/stream-wrappers.ts +228 -0
  110. package/extensions/anthropic/test-api.ts +3 -0
  111. package/extensions/anthropic/tsconfig.json +16 -0
  112. package/extensions/arcee/api.ts +8 -0
  113. package/extensions/arcee/index.test.ts +195 -0
  114. package/extensions/arcee/index.ts +142 -0
  115. package/extensions/arcee/models.ts +68 -0
  116. package/extensions/arcee/onboard.ts +43 -0
  117. package/extensions/arcee/openclaw.plugin.json +46 -0
  118. package/extensions/arcee/package.json +15 -0
  119. package/extensions/arcee/provider-catalog.ts +54 -0
  120. package/extensions/arcee/tsconfig.json +16 -0
  121. package/extensions/azure-speech/azure-speech.live.test.ts +92 -0
  122. package/extensions/azure-speech/index.ts +11 -0
  123. package/extensions/azure-speech/openclaw.plugin.json +66 -0
  124. package/extensions/azure-speech/package.json +15 -0
  125. package/extensions/azure-speech/speech-provider.test.ts +242 -0
  126. package/extensions/azure-speech/speech-provider.ts +306 -0
  127. package/extensions/azure-speech/tsconfig.json +16 -0
  128. package/extensions/azure-speech/tts.test.ts +127 -0
  129. package/extensions/azure-speech/tts.ts +209 -0
  130. package/extensions/byteplus/api.ts +8 -0
  131. package/extensions/byteplus/index.test.ts +60 -0
  132. package/extensions/byteplus/index.ts +84 -0
  133. package/extensions/byteplus/live.test.ts +60 -0
  134. package/extensions/byteplus/models.ts +35 -0
  135. package/extensions/byteplus/openclaw.plugin.json +165 -0
  136. package/extensions/byteplus/package.json +15 -0
  137. package/extensions/byteplus/plugin-registration.contract.test.ts +8 -0
  138. package/extensions/byteplus/provider-catalog.ts +17 -0
  139. package/extensions/byteplus/provider-discovery.ts +31 -0
  140. package/extensions/byteplus/tsconfig.json +16 -0
  141. package/extensions/byteplus/video-generation-provider.test.ts +223 -0
  142. package/extensions/byteplus/video-generation-provider.ts +389 -0
  143. package/extensions/cerebras/api.ts +7 -0
  144. package/extensions/cerebras/index.ts +41 -0
  145. package/extensions/cerebras/models.ts +25 -0
  146. package/extensions/cerebras/onboard.ts +26 -0
  147. package/extensions/cerebras/openclaw.plugin.json +111 -0
  148. package/extensions/cerebras/package.json +15 -0
  149. package/extensions/cerebras/provider-catalog.ts +10 -0
  150. package/extensions/cerebras/tsconfig.json +16 -0
  151. package/extensions/chutes/api.ts +14 -0
  152. package/extensions/chutes/implicit-provider.test.ts +107 -0
  153. package/extensions/chutes/index.ts +194 -0
  154. package/extensions/chutes/model-discovery-env.ts +5 -0
  155. package/extensions/chutes/models.test.ts +289 -0
  156. package/extensions/chutes/models.ts +632 -0
  157. package/extensions/chutes/oauth.ts +235 -0
  158. package/extensions/chutes/onboard.ts +63 -0
  159. package/extensions/chutes/openclaw.plugin.json +726 -0
  160. package/extensions/chutes/package.json +15 -0
  161. package/extensions/chutes/provider-catalog.ts +29 -0
  162. package/extensions/chutes/tsconfig.json +16 -0
  163. package/extensions/cloudflare-ai-gateway/api.ts +14 -0
  164. package/extensions/cloudflare-ai-gateway/catalog-provider.ts +73 -0
  165. package/extensions/cloudflare-ai-gateway/index.test.ts +60 -0
  166. package/extensions/cloudflare-ai-gateway/index.ts +233 -0
  167. package/extensions/cloudflare-ai-gateway/models.ts +44 -0
  168. package/extensions/cloudflare-ai-gateway/onboard.ts +91 -0
  169. package/extensions/cloudflare-ai-gateway/openclaw.plugin.json +44 -0
  170. package/extensions/cloudflare-ai-gateway/package.json +15 -0
  171. package/extensions/cloudflare-ai-gateway/provider-discovery.contract.test.ts +3 -0
  172. package/extensions/cloudflare-ai-gateway/stream-wrappers.test.ts +160 -0
  173. package/extensions/cloudflare-ai-gateway/stream-wrappers.ts +32 -0
  174. package/extensions/cloudflare-ai-gateway/tsconfig.json +16 -0
  175. package/extensions/codex/doctor-contract-api.test.ts +44 -0
  176. package/extensions/codex/doctor-contract-api.ts +68 -0
  177. package/extensions/codex/harness.ts +85 -0
  178. package/extensions/codex/index.test.ts +230 -0
  179. package/extensions/codex/index.ts +125 -0
  180. package/extensions/codex/media-understanding-provider.test.ts +496 -0
  181. package/extensions/codex/media-understanding-provider.ts +524 -0
  182. package/extensions/codex/npm-shrinkwrap.json +1949 -0
  183. package/extensions/codex/openclaw.plugin.json +403 -0
  184. package/extensions/codex/package.json +41 -0
  185. package/extensions/codex/prompt-overlay-runtime-contract.test.ts +48 -0
  186. package/extensions/codex/prompt-overlay.ts +21 -0
  187. package/extensions/codex/provider-catalog.ts +83 -0
  188. package/extensions/codex/provider-discovery.ts +45 -0
  189. package/extensions/codex/provider.test.ts +384 -0
  190. package/extensions/codex/provider.ts +243 -0
  191. package/extensions/codex/src/app-server/app-inventory-cache.test.ts +176 -0
  192. package/extensions/codex/src/app-server/app-inventory-cache.ts +324 -0
  193. package/extensions/codex/src/app-server/approval-bridge.test.ts +1472 -0
  194. package/extensions/codex/src/app-server/approval-bridge.ts +1211 -0
  195. package/extensions/codex/src/app-server/auth-bridge.test.ts +1449 -0
  196. package/extensions/codex/src/app-server/auth-bridge.ts +614 -0
  197. package/extensions/codex/src/app-server/auth-profile-runtime-contract.test.ts +242 -0
  198. package/extensions/codex/src/app-server/capabilities.ts +27 -0
  199. package/extensions/codex/src/app-server/client-factory.ts +24 -0
  200. package/extensions/codex/src/app-server/client.test.ts +563 -0
  201. package/extensions/codex/src/app-server/client.ts +721 -0
  202. package/extensions/codex/src/app-server/compact.test.ts +1029 -0
  203. package/extensions/codex/src/app-server/compact.ts +662 -0
  204. package/extensions/codex/src/app-server/computer-use.test.ts +788 -0
  205. package/extensions/codex/src/app-server/computer-use.ts +683 -0
  206. package/extensions/codex/src/app-server/config.test.ts +948 -0
  207. package/extensions/codex/src/app-server/config.ts +1093 -0
  208. package/extensions/codex/src/app-server/context-engine-projection.test.ts +252 -0
  209. package/extensions/codex/src/app-server/context-engine-projection.ts +403 -0
  210. package/extensions/codex/src/app-server/delivery-no-reply-runtime-contract.test.ts +80 -0
  211. package/extensions/codex/src/app-server/dynamic-tool-diagnostics.ts +73 -0
  212. package/extensions/codex/src/app-server/dynamic-tool-profile.ts +70 -0
  213. package/extensions/codex/src/app-server/dynamic-tools.test.ts +1357 -0
  214. package/extensions/codex/src/app-server/dynamic-tools.ts +646 -0
  215. package/extensions/codex/src/app-server/elicitation-bridge.test.ts +1281 -0
  216. package/extensions/codex/src/app-server/elicitation-bridge.ts +828 -0
  217. package/extensions/codex/src/app-server/event-projector.test.ts +2885 -0
  218. package/extensions/codex/src/app-server/event-projector.ts +2047 -0
  219. package/extensions/codex/src/app-server/image-payload-sanitizer.test.ts +49 -0
  220. package/extensions/codex/src/app-server/image-payload-sanitizer.ts +195 -0
  221. package/extensions/codex/src/app-server/local-runtime-attribution.ts +39 -0
  222. package/extensions/codex/src/app-server/managed-binary.test.ts +141 -0
  223. package/extensions/codex/src/app-server/managed-binary.ts +193 -0
  224. package/extensions/codex/src/app-server/models.test.ts +246 -0
  225. package/extensions/codex/src/app-server/models.ts +172 -0
  226. package/extensions/codex/src/app-server/native-hook-relay.test.ts +274 -0
  227. package/extensions/codex/src/app-server/native-hook-relay.ts +150 -0
  228. package/extensions/codex/src/app-server/native-subagent-monitor.test.ts +1125 -0
  229. package/extensions/codex/src/app-server/native-subagent-monitor.ts +1061 -0
  230. package/extensions/codex/src/app-server/native-subagent-notification.test.ts +176 -0
  231. package/extensions/codex/src/app-server/native-subagent-notification.ts +222 -0
  232. package/extensions/codex/src/app-server/native-subagent-task-ids.ts +3 -0
  233. package/extensions/codex/src/app-server/native-subagent-task-mirror.test.ts +625 -0
  234. package/extensions/codex/src/app-server/native-subagent-task-mirror.ts +460 -0
  235. package/extensions/codex/src/app-server/notification-correlation.ts +91 -0
  236. package/extensions/codex/src/app-server/openclaw-owned-tool-runtime-contract.test.ts +456 -0
  237. package/extensions/codex/src/app-server/outcome-fallback-runtime-contract.test.ts +404 -0
  238. package/extensions/codex/src/app-server/plugin-activation.test.ts +336 -0
  239. package/extensions/codex/src/app-server/plugin-activation.ts +283 -0
  240. package/extensions/codex/src/app-server/plugin-app-cache-key.ts +74 -0
  241. package/extensions/codex/src/app-server/plugin-approval-roundtrip.ts +122 -0
  242. package/extensions/codex/src/app-server/plugin-inventory.test.ts +355 -0
  243. package/extensions/codex/src/app-server/plugin-inventory.ts +357 -0
  244. package/extensions/codex/src/app-server/plugin-thread-config.test.ts +865 -0
  245. package/extensions/codex/src/app-server/plugin-thread-config.ts +455 -0
  246. package/extensions/codex/src/app-server/protocol-generated/json/DynamicToolCallParams.json +33 -0
  247. package/extensions/codex/src/app-server/protocol-generated/json/v2/ErrorNotification.json +199 -0
  248. package/extensions/codex/src/app-server/protocol-generated/json/v2/GetAccountResponse.json +102 -0
  249. package/extensions/codex/src/app-server/protocol-generated/json/v2/ModelListResponse.json +227 -0
  250. package/extensions/codex/src/app-server/protocol-generated/json/v2/ThreadResumeResponse.json +2630 -0
  251. package/extensions/codex/src/app-server/protocol-generated/json/v2/ThreadStartResponse.json +2630 -0
  252. package/extensions/codex/src/app-server/protocol-generated/json/v2/TurnCompletedNotification.json +1659 -0
  253. package/extensions/codex/src/app-server/protocol-generated/json/v2/TurnStartResponse.json +1655 -0
  254. package/extensions/codex/src/app-server/protocol-validators.test.ts +75 -0
  255. package/extensions/codex/src/app-server/protocol-validators.ts +203 -0
  256. package/extensions/codex/src/app-server/protocol.ts +537 -0
  257. package/extensions/codex/src/app-server/rate-limit-cache.ts +48 -0
  258. package/extensions/codex/src/app-server/rate-limits.test.ts +202 -0
  259. package/extensions/codex/src/app-server/rate-limits.ts +583 -0
  260. package/extensions/codex/src/app-server/request.test.ts +68 -0
  261. package/extensions/codex/src/app-server/request.ts +90 -0
  262. package/extensions/codex/src/app-server/run-attempt-thread-cleanup.test.ts +197 -0
  263. package/extensions/codex/src/app-server/run-attempt.context-engine.test.ts +1246 -0
  264. package/extensions/codex/src/app-server/run-attempt.test.ts +10799 -0
  265. package/extensions/codex/src/app-server/run-attempt.ts +5264 -0
  266. package/extensions/codex/src/app-server/run-attempt.vision-tools.test.ts +35 -0
  267. package/extensions/codex/src/app-server/sandbox-exec-server/filesystem.ts +261 -0
  268. package/extensions/codex/src/app-server/sandbox-exec-server/fs-policy.ts +346 -0
  269. package/extensions/codex/src/app-server/sandbox-exec-server/http.ts +312 -0
  270. package/extensions/codex/src/app-server/sandbox-exec-server/json-rpc.ts +93 -0
  271. package/extensions/codex/src/app-server/sandbox-exec-server/processes.ts +411 -0
  272. package/extensions/codex/src/app-server/sandbox-exec-server/runtime.ts +22 -0
  273. package/extensions/codex/src/app-server/sandbox-exec-server/types.ts +80 -0
  274. package/extensions/codex/src/app-server/sandbox-exec-server.fs.test.ts +527 -0
  275. package/extensions/codex/src/app-server/sandbox-exec-server.http.test.ts +210 -0
  276. package/extensions/codex/src/app-server/sandbox-exec-server.test-helpers.ts +236 -0
  277. package/extensions/codex/src/app-server/sandbox-exec-server.test.ts +460 -0
  278. package/extensions/codex/src/app-server/sandbox-exec-server.ts +355 -0
  279. package/extensions/codex/src/app-server/sandbox-guard.ts +153 -0
  280. package/extensions/codex/src/app-server/schema-normalization-runtime-contract.test.ts +206 -0
  281. package/extensions/codex/src/app-server/session-binding.test.ts +303 -0
  282. package/extensions/codex/src/app-server/session-binding.ts +407 -0
  283. package/extensions/codex/src/app-server/session-history.ts +44 -0
  284. package/extensions/codex/src/app-server/shared-client.test.ts +591 -0
  285. package/extensions/codex/src/app-server/shared-client.ts +289 -0
  286. package/extensions/codex/src/app-server/side-question.test.ts +1243 -0
  287. package/extensions/codex/src/app-server/side-question.ts +1019 -0
  288. package/extensions/codex/src/app-server/test-support.ts +48 -0
  289. package/extensions/codex/src/app-server/thread-lifecycle.test.ts +447 -0
  290. package/extensions/codex/src/app-server/thread-lifecycle.ts +1004 -0
  291. package/extensions/codex/src/app-server/thread-lifecycle.user-mcp-servers.test.ts +442 -0
  292. package/extensions/codex/src/app-server/timeout.ts +9 -0
  293. package/extensions/codex/src/app-server/tool-progress-normalization.ts +77 -0
  294. package/extensions/codex/src/app-server/trajectory.test.ts +205 -0
  295. package/extensions/codex/src/app-server/trajectory.ts +368 -0
  296. package/extensions/codex/src/app-server/transcript-mirror.test.ts +527 -0
  297. package/extensions/codex/src/app-server/transcript-mirror.ts +208 -0
  298. package/extensions/codex/src/app-server/transcript-repair-runtime-contract.test.ts +44 -0
  299. package/extensions/codex/src/app-server/transport-stdio.test.ts +184 -0
  300. package/extensions/codex/src/app-server/transport-stdio.ts +107 -0
  301. package/extensions/codex/src/app-server/transport-websocket.test.ts +71 -0
  302. package/extensions/codex/src/app-server/transport-websocket.ts +90 -0
  303. package/extensions/codex/src/app-server/transport.ts +117 -0
  304. package/extensions/codex/src/app-server/user-input-bridge.test.ts +249 -0
  305. package/extensions/codex/src/app-server/user-input-bridge.ts +316 -0
  306. package/extensions/codex/src/app-server/version.ts +5 -0
  307. package/extensions/codex/src/app-server/vision-tools.ts +12 -0
  308. package/extensions/codex/src/command-account.ts +589 -0
  309. package/extensions/codex/src/command-formatters.ts +426 -0
  310. package/extensions/codex/src/command-handlers.ts +2092 -0
  311. package/extensions/codex/src/command-plugins-management.test.ts +172 -0
  312. package/extensions/codex/src/command-plugins-management.ts +137 -0
  313. package/extensions/codex/src/command-rpc.test.ts +16 -0
  314. package/extensions/codex/src/command-rpc.ts +146 -0
  315. package/extensions/codex/src/commands.test.ts +3737 -0
  316. package/extensions/codex/src/commands.ts +65 -0
  317. package/extensions/codex/src/conversation-binding-data.ts +124 -0
  318. package/extensions/codex/src/conversation-binding.test.ts +697 -0
  319. package/extensions/codex/src/conversation-binding.ts +575 -0
  320. package/extensions/codex/src/conversation-control.test.ts +126 -0
  321. package/extensions/codex/src/conversation-control.ts +303 -0
  322. package/extensions/codex/src/conversation-turn-collector.test.ts +191 -0
  323. package/extensions/codex/src/conversation-turn-collector.ts +190 -0
  324. package/extensions/codex/src/conversation-turn-input.test.ts +141 -0
  325. package/extensions/codex/src/conversation-turn-input.ts +106 -0
  326. package/extensions/codex/src/manifest.test.ts +20 -0
  327. package/extensions/codex/src/migration/apply.ts +501 -0
  328. package/extensions/codex/src/migration/helpers.ts +55 -0
  329. package/extensions/codex/src/migration/plan.ts +461 -0
  330. package/extensions/codex/src/migration/provider.test.ts +1741 -0
  331. package/extensions/codex/src/migration/provider.ts +41 -0
  332. package/extensions/codex/src/migration/source.ts +643 -0
  333. package/extensions/codex/src/migration/targets.ts +25 -0
  334. package/extensions/codex/src/node-cli-sessions.test.ts +180 -0
  335. package/extensions/codex/src/node-cli-sessions.ts +711 -0
  336. package/extensions/codex/test-api.ts +95 -0
  337. package/extensions/codex/tsconfig.json +16 -0
  338. package/extensions/comfy/comfy.live.test.ts +128 -0
  339. package/extensions/comfy/image-generation-provider.test.ts +457 -0
  340. package/extensions/comfy/image-generation-provider.ts +79 -0
  341. package/extensions/comfy/index.test.ts +51 -0
  342. package/extensions/comfy/index.ts +45 -0
  343. package/extensions/comfy/music-generation-provider.test.ts +101 -0
  344. package/extensions/comfy/music-generation-provider.ts +88 -0
  345. package/extensions/comfy/openclaw.plugin.json +268 -0
  346. package/extensions/comfy/package.json +15 -0
  347. package/extensions/comfy/plugin-registration.contract.test.ts +11 -0
  348. package/extensions/comfy/test-helpers.ts +113 -0
  349. package/extensions/comfy/tsconfig.json +16 -0
  350. package/extensions/comfy/video-generation-provider.test.ts +184 -0
  351. package/extensions/comfy/video-generation-provider.ts +104 -0
  352. package/extensions/comfy/workflow-runtime.ts +827 -0
  353. package/extensions/deepgram/audio.live.test.ts +75 -0
  354. package/extensions/deepgram/audio.test.ts +146 -0
  355. package/extensions/deepgram/audio.ts +109 -0
  356. package/extensions/deepgram/index.ts +13 -0
  357. package/extensions/deepgram/media-understanding-provider.ts +10 -0
  358. package/extensions/deepgram/openclaw.plugin.json +30 -0
  359. package/extensions/deepgram/package.json +15 -0
  360. package/extensions/deepgram/realtime-transcription-provider.test.ts +69 -0
  361. package/extensions/deepgram/realtime-transcription-provider.ts +283 -0
  362. package/extensions/deepgram/test-api.ts +2 -0
  363. package/extensions/deepgram/tsconfig.json +16 -0
  364. package/extensions/deepinfra/api.ts +8 -0
  365. package/extensions/deepinfra/embedding-provider.ts +33 -0
  366. package/extensions/deepinfra/image-generation-provider.test.ts +224 -0
  367. package/extensions/deepinfra/image-generation-provider.ts +89 -0
  368. package/extensions/deepinfra/index.test.ts +113 -0
  369. package/extensions/deepinfra/index.ts +84 -0
  370. package/extensions/deepinfra/media-models.ts +50 -0
  371. package/extensions/deepinfra/media-understanding-provider.test.ts +73 -0
  372. package/extensions/deepinfra/media-understanding-provider.ts +37 -0
  373. package/extensions/deepinfra/memory-embedding-adapter.test.ts +31 -0
  374. package/extensions/deepinfra/memory-embedding-adapter.ts +35 -0
  375. package/extensions/deepinfra/onboard.test.ts +172 -0
  376. package/extensions/deepinfra/onboard.ts +36 -0
  377. package/extensions/deepinfra/openclaw.plugin.json +203 -0
  378. package/extensions/deepinfra/package.json +15 -0
  379. package/extensions/deepinfra/provider-catalog.ts +24 -0
  380. package/extensions/deepinfra/provider-models.test.ts +217 -0
  381. package/extensions/deepinfra/provider-models.ts +167 -0
  382. package/extensions/deepinfra/provider-policy-api.test.ts +41 -0
  383. package/extensions/deepinfra/provider-policy-api.ts +21 -0
  384. package/extensions/deepinfra/provider.contract.test.ts +3 -0
  385. package/extensions/deepinfra/speech-provider.test.ts +169 -0
  386. package/extensions/deepinfra/speech-provider.ts +41 -0
  387. package/extensions/deepinfra/tsconfig.json +16 -0
  388. package/extensions/deepinfra/video-generation-provider.test.ts +194 -0
  389. package/extensions/deepinfra/video-generation-provider.ts +262 -0
  390. package/extensions/deepseek/api.ts +7 -0
  391. package/extensions/deepseek/deepseek.live.test.ts +232 -0
  392. package/extensions/deepseek/index.test.ts +488 -0
  393. package/extensions/deepseek/index.ts +58 -0
  394. package/extensions/deepseek/models.ts +33 -0
  395. package/extensions/deepseek/onboard.ts +31 -0
  396. package/extensions/deepseek/openclaw.plugin.json +132 -0
  397. package/extensions/deepseek/package.json +15 -0
  398. package/extensions/deepseek/provider-catalog.ts +14 -0
  399. package/extensions/deepseek/provider-discovery.ts +17 -0
  400. package/extensions/deepseek/provider-policy-api.test.ts +264 -0
  401. package/extensions/deepseek/provider-policy-api.ts +104 -0
  402. package/extensions/deepseek/stream.ts +14 -0
  403. package/extensions/deepseek/thinking.ts +19 -0
  404. package/extensions/deepseek/tsconfig.json +16 -0
  405. package/extensions/elevenlabs/config-api.ts +8 -0
  406. package/extensions/elevenlabs/config-compat.test.ts +75 -0
  407. package/extensions/elevenlabs/config-compat.ts +181 -0
  408. package/extensions/elevenlabs/contract-api.ts +8 -0
  409. package/extensions/elevenlabs/doctor-contract.ts +34 -0
  410. package/extensions/elevenlabs/elevenlabs.live.test.ts +91 -0
  411. package/extensions/elevenlabs/index.ts +15 -0
  412. package/extensions/elevenlabs/media-understanding-provider.test.ts +95 -0
  413. package/extensions/elevenlabs/media-understanding-provider.ts +85 -0
  414. package/extensions/elevenlabs/openclaw.plugin.json +40 -0
  415. package/extensions/elevenlabs/package.json +15 -0
  416. package/extensions/elevenlabs/realtime-transcription-provider.test.ts +60 -0
  417. package/extensions/elevenlabs/realtime-transcription-provider.ts +284 -0
  418. package/extensions/elevenlabs/setup-api.ts +11 -0
  419. package/extensions/elevenlabs/shared.ts +10 -0
  420. package/extensions/elevenlabs/speech-provider.test.ts +124 -0
  421. package/extensions/elevenlabs/speech-provider.ts +594 -0
  422. package/extensions/elevenlabs/test-api.ts +6 -0
  423. package/extensions/elevenlabs/tsconfig.json +16 -0
  424. package/extensions/elevenlabs/tts.test.ts +212 -0
  425. package/extensions/elevenlabs/tts.ts +198 -0
  426. package/extensions/fal/image-generation-provider.test.ts +710 -0
  427. package/extensions/fal/image-generation-provider.ts +463 -0
  428. package/extensions/fal/index.ts +19 -0
  429. package/extensions/fal/music-generation-provider.test.ts +200 -0
  430. package/extensions/fal/music-generation-provider.ts +219 -0
  431. package/extensions/fal/onboard.ts +21 -0
  432. package/extensions/fal/openclaw.plugin.json +42 -0
  433. package/extensions/fal/package.json +15 -0
  434. package/extensions/fal/plugin-registration.contract.test.ts +11 -0
  435. package/extensions/fal/provider-contract-api.ts +31 -0
  436. package/extensions/fal/provider-registration.ts +38 -0
  437. package/extensions/fal/test-api.ts +3 -0
  438. package/extensions/fal/tsconfig.json +16 -0
  439. package/extensions/fal/video-generation-provider.test.ts +566 -0
  440. package/extensions/fal/video-generation-provider.ts +648 -0
  441. package/extensions/fireworks/index.test.ts +181 -0
  442. package/extensions/fireworks/index.ts +85 -0
  443. package/extensions/fireworks/model-id.ts +5 -0
  444. package/extensions/fireworks/onboard.ts +30 -0
  445. package/extensions/fireworks/openclaw.plugin.json +73 -0
  446. package/extensions/fireworks/package.json +18 -0
  447. package/extensions/fireworks/provider-catalog.ts +50 -0
  448. package/extensions/fireworks/provider-policy-api.ts +8 -0
  449. package/extensions/fireworks/stream.test.ts +184 -0
  450. package/extensions/fireworks/stream.ts +39 -0
  451. package/extensions/fireworks/thinking-policy.ts +17 -0
  452. package/extensions/fireworks/tsconfig.json +16 -0
  453. package/extensions/github-copilot/api.ts +1 -0
  454. package/extensions/github-copilot/auth.test.ts +109 -0
  455. package/extensions/github-copilot/auth.ts +65 -0
  456. package/extensions/github-copilot/connection-bound-ids.live.test.ts +231 -0
  457. package/extensions/github-copilot/connection-bound-ids.test.ts +96 -0
  458. package/extensions/github-copilot/connection-bound-ids.ts +81 -0
  459. package/extensions/github-copilot/embeddings.test.ts +287 -0
  460. package/extensions/github-copilot/embeddings.ts +342 -0
  461. package/extensions/github-copilot/index.test.ts +660 -0
  462. package/extensions/github-copilot/index.ts +492 -0
  463. package/extensions/github-copilot/login.ts +323 -0
  464. package/extensions/github-copilot/model-metadata.ts +51 -0
  465. package/extensions/github-copilot/models-defaults.ts +61 -0
  466. package/extensions/github-copilot/models.test.ts +695 -0
  467. package/extensions/github-copilot/models.ts +274 -0
  468. package/extensions/github-copilot/openclaw.plugin.json +270 -0
  469. package/extensions/github-copilot/package.json +19 -0
  470. package/extensions/github-copilot/provider-auth.contract.test.ts +3 -0
  471. package/extensions/github-copilot/provider-discovery.contract.test.ts +7 -0
  472. package/extensions/github-copilot/provider-runtime.contract.test.ts +3 -0
  473. package/extensions/github-copilot/register.runtime.ts +24 -0
  474. package/extensions/github-copilot/replay-policy.ts +9 -0
  475. package/extensions/github-copilot/stream.test.ts +282 -0
  476. package/extensions/github-copilot/stream.ts +157 -0
  477. package/extensions/github-copilot/token.ts +6 -0
  478. package/extensions/github-copilot/tsconfig.json +16 -0
  479. package/extensions/github-copilot/usage.ts +68 -0
  480. package/extensions/google/api.test.ts +249 -0
  481. package/extensions/google/api.ts +91 -0
  482. package/extensions/google/cli-backend.ts +58 -0
  483. package/extensions/google/default-model.test.ts +115 -0
  484. package/extensions/google/doctor-contract-api.ts +18 -0
  485. package/extensions/google/embedding-batch.ts +379 -0
  486. package/extensions/google/embedding-provider.test.ts +264 -0
  487. package/extensions/google/embedding-provider.ts +441 -0
  488. package/extensions/google/gemini-auth.ts +20 -0
  489. package/extensions/google/gemini-cli-provider.ts +145 -0
  490. package/extensions/google/generation-provider-metadata.ts +121 -0
  491. package/extensions/google/google-genai-runtime.ts +8 -0
  492. package/extensions/google/google-shared.test-helpers.ts +99 -0
  493. package/extensions/google/google-shared.test.ts +380 -0
  494. package/extensions/google/google.live.test.ts +179 -0
  495. package/extensions/google/image-generation-provider.test.ts +503 -0
  496. package/extensions/google/image-generation-provider.ts +272 -0
  497. package/extensions/google/index.test.ts +310 -0
  498. package/extensions/google/index.ts +354 -0
  499. package/extensions/google/manifest.test.ts +104 -0
  500. package/extensions/google/media-understanding-provider.ts +164 -0
  501. package/extensions/google/media-understanding-provider.video.test.ts +158 -0
  502. package/extensions/google/memory-embedding-adapter.ts +79 -0
  503. package/extensions/google/model-id.test.ts +42 -0
  504. package/extensions/google/model-id.ts +35 -0
  505. package/extensions/google/music-generation-provider.test.ts +278 -0
  506. package/extensions/google/music-generation-provider.ts +176 -0
  507. package/extensions/google/oauth-token-shared.test.ts +39 -0
  508. package/extensions/google/oauth-token-shared.ts +42 -0
  509. package/extensions/google/oauth.credentials.ts +273 -0
  510. package/extensions/google/oauth.flow.ts +61 -0
  511. package/extensions/google/oauth.http.ts +24 -0
  512. package/extensions/google/oauth.project.ts +232 -0
  513. package/extensions/google/oauth.runtime.ts +1 -0
  514. package/extensions/google/oauth.settings.ts +72 -0
  515. package/extensions/google/oauth.shared.ts +44 -0
  516. package/extensions/google/oauth.test.ts +922 -0
  517. package/extensions/google/oauth.token.ts +138 -0
  518. package/extensions/google/oauth.ts +104 -0
  519. package/extensions/google/onboard.ts +78 -0
  520. package/extensions/google/openclaw.plugin.json +706 -0
  521. package/extensions/google/package.json +19 -0
  522. package/extensions/google/plugin-registration.contract.test.ts +12 -0
  523. package/extensions/google/provider-contract-api.ts +77 -0
  524. package/extensions/google/provider-hooks.ts +18 -0
  525. package/extensions/google/provider-models.test.ts +513 -0
  526. package/extensions/google/provider-models.ts +237 -0
  527. package/extensions/google/provider-policy-api.test.ts +201 -0
  528. package/extensions/google/provider-policy-api.ts +11 -0
  529. package/extensions/google/provider-policy.ts +208 -0
  530. package/extensions/google/provider-registration.ts +72 -0
  531. package/extensions/google/provider-runtime.contract.test.ts +3 -0
  532. package/extensions/google/realtime-voice-provider.test.ts +857 -0
  533. package/extensions/google/realtime-voice-provider.ts +952 -0
  534. package/extensions/google/runtime-api.ts +19 -0
  535. package/extensions/google/setup-api.test.ts +23 -0
  536. package/extensions/google/setup-api.ts +13 -0
  537. package/extensions/google/speech-provider.test.ts +682 -0
  538. package/extensions/google/speech-provider.ts +683 -0
  539. package/extensions/google/src/gemini-web-search-provider.runtime.ts +367 -0
  540. package/extensions/google/src/gemini-web-search-provider.shared.ts +45 -0
  541. package/extensions/google/src/gemini-web-search-provider.ts +151 -0
  542. package/extensions/google/test-api.ts +6 -0
  543. package/extensions/google/thinking-api.ts +14 -0
  544. package/extensions/google/thinking.test.ts +153 -0
  545. package/extensions/google/thinking.ts +14 -0
  546. package/extensions/google/transport-stream.test.ts +1726 -0
  547. package/extensions/google/transport-stream.ts +1396 -0
  548. package/extensions/google/tsconfig.json +16 -0
  549. package/extensions/google/vertex-adc.ts +188 -0
  550. package/extensions/google/video-generation-provider.test.ts +573 -0
  551. package/extensions/google/video-generation-provider.ts +591 -0
  552. package/extensions/google/web-search-contract-api.ts +1 -0
  553. package/extensions/google/web-search-provider.test.ts +548 -0
  554. package/extensions/google/web-search-provider.ts +1 -0
  555. package/extensions/groq/api.ts +60 -0
  556. package/extensions/groq/index.test.ts +90 -0
  557. package/extensions/groq/index.ts +21 -0
  558. package/extensions/groq/media-understanding-provider.ts +21 -0
  559. package/extensions/groq/openclaw.plugin.json +314 -0
  560. package/extensions/groq/package.json +15 -0
  561. package/extensions/groq/test-api.ts +1 -0
  562. package/extensions/groq/tsconfig.json +16 -0
  563. package/extensions/huggingface/api.ts +10 -0
  564. package/extensions/huggingface/index.test.ts +81 -0
  565. package/extensions/huggingface/index.ts +60 -0
  566. package/extensions/huggingface/model-discovery-env.ts +5 -0
  567. package/extensions/huggingface/models.test.ts +98 -0
  568. package/extensions/huggingface/models.ts +218 -0
  569. package/extensions/huggingface/onboard.ts +26 -0
  570. package/extensions/huggingface/openclaw.plugin.json +57 -0
  571. package/extensions/huggingface/package.json +15 -0
  572. package/extensions/huggingface/provider-catalog.ts +22 -0
  573. package/extensions/huggingface/tsconfig.json +16 -0
  574. package/extensions/image-generation-core/api.ts +30 -0
  575. package/extensions/image-generation-core/package.json +10 -0
  576. package/extensions/image-generation-core/runtime-api.ts +6 -0
  577. package/extensions/image-generation-core/src/runtime.test.ts +29 -0
  578. package/extensions/image-generation-core/src/runtime.ts +6 -0
  579. package/extensions/image-generation-core/tsconfig.json +16 -0
  580. package/extensions/kimi-coding/api.ts +8 -0
  581. package/extensions/kimi-coding/implicit-provider.test.ts +116 -0
  582. package/extensions/kimi-coding/index.test.ts +45 -0
  583. package/extensions/kimi-coding/index.ts +113 -0
  584. package/extensions/kimi-coding/onboard.test.ts +44 -0
  585. package/extensions/kimi-coding/onboard.ts +42 -0
  586. package/extensions/kimi-coding/openclaw.plugin.json +64 -0
  587. package/extensions/kimi-coding/package.json +18 -0
  588. package/extensions/kimi-coding/provider-catalog.test.ts +23 -0
  589. package/extensions/kimi-coding/provider-catalog.ts +58 -0
  590. package/extensions/kimi-coding/replay-policy.test.ts +10 -0
  591. package/extensions/kimi-coding/replay-policy.ts +3 -0
  592. package/extensions/kimi-coding/stream.test.ts +603 -0
  593. package/extensions/kimi-coding/stream.ts +399 -0
  594. package/extensions/kimi-coding/tsconfig.json +16 -0
  595. package/extensions/litellm/api.ts +8 -0
  596. package/extensions/litellm/image-generation-provider.test.ts +348 -0
  597. package/extensions/litellm/image-generation-provider.ts +142 -0
  598. package/extensions/litellm/index.test.ts +107 -0
  599. package/extensions/litellm/index.ts +108 -0
  600. package/extensions/litellm/onboard.test.ts +21 -0
  601. package/extensions/litellm/onboard.ts +55 -0
  602. package/extensions/litellm/openclaw.plugin.json +35 -0
  603. package/extensions/litellm/package.json +15 -0
  604. package/extensions/litellm/provider-catalog.ts +10 -0
  605. package/extensions/litellm/tsconfig.json +16 -0
  606. package/extensions/lmstudio/README.md +3 -0
  607. package/extensions/lmstudio/api.ts +36 -0
  608. package/extensions/lmstudio/index.test.ts +207 -0
  609. package/extensions/lmstudio/index.ts +137 -0
  610. package/extensions/lmstudio/memory-embedding-adapter.ts +36 -0
  611. package/extensions/lmstudio/openclaw.plugin.json +53 -0
  612. package/extensions/lmstudio/package.json +15 -0
  613. package/extensions/lmstudio/plugin-registration.contract.test.ts +6 -0
  614. package/extensions/lmstudio/runtime-api.ts +35 -0
  615. package/extensions/lmstudio/src/api.ts +42 -0
  616. package/extensions/lmstudio/src/defaults.ts +14 -0
  617. package/extensions/lmstudio/src/embedding-provider.ts +147 -0
  618. package/extensions/lmstudio/src/models.fetch.ts +277 -0
  619. package/extensions/lmstudio/src/models.test.ts +491 -0
  620. package/extensions/lmstudio/src/models.ts +536 -0
  621. package/extensions/lmstudio/src/plain-text-tool-calls.ts +24 -0
  622. package/extensions/lmstudio/src/provider-auth.ts +59 -0
  623. package/extensions/lmstudio/src/runtime.test.ts +357 -0
  624. package/extensions/lmstudio/src/runtime.ts +276 -0
  625. package/extensions/lmstudio/src/setup.test.ts +1543 -0
  626. package/extensions/lmstudio/src/setup.ts +878 -0
  627. package/extensions/lmstudio/src/stream.test.ts +658 -0
  628. package/extensions/lmstudio/src/stream.ts +493 -0
  629. package/extensions/media-understanding-core/image-ops.ts +137 -0
  630. package/extensions/media-understanding-core/package.json +14 -0
  631. package/extensions/media-understanding-core/runtime-api.ts +9 -0
  632. package/extensions/media-understanding-core/src/runtime.ts +9 -0
  633. package/extensions/media-understanding-core/tsconfig.json +16 -0
  634. package/extensions/microsoft/index.ts +11 -0
  635. package/extensions/microsoft/microsoft.live.test.ts +14 -0
  636. package/extensions/microsoft/openclaw.plugin.json +15 -0
  637. package/extensions/microsoft/package.json +18 -0
  638. package/extensions/microsoft/speech-provider.test.ts +298 -0
  639. package/extensions/microsoft/speech-provider.ts +295 -0
  640. package/extensions/microsoft/test-api.ts +1 -0
  641. package/extensions/microsoft/tsconfig.json +16 -0
  642. package/extensions/microsoft/tts.test.ts +193 -0
  643. package/extensions/microsoft/tts.ts +137 -0
  644. package/extensions/minimax/README.md +37 -0
  645. package/extensions/minimax/api.ts +27 -0
  646. package/extensions/minimax/image-generation-provider.test.ts +313 -0
  647. package/extensions/minimax/image-generation-provider.ts +216 -0
  648. package/extensions/minimax/index.test.ts +408 -0
  649. package/extensions/minimax/index.ts +39 -0
  650. package/extensions/minimax/media-understanding-provider.ts +23 -0
  651. package/extensions/minimax/minimax.live.test.ts +115 -0
  652. package/extensions/minimax/model-definitions.test.ts +101 -0
  653. package/extensions/minimax/model-definitions.ts +91 -0
  654. package/extensions/minimax/music-generation-provider.test.ts +198 -0
  655. package/extensions/minimax/music-generation-provider.ts +259 -0
  656. package/extensions/minimax/oauth.runtime.ts +1 -0
  657. package/extensions/minimax/oauth.ts +233 -0
  658. package/extensions/minimax/onboard.test.ts +126 -0
  659. package/extensions/minimax/onboard.ts +104 -0
  660. package/extensions/minimax/openclaw.plugin.json +133 -0
  661. package/extensions/minimax/package.json +15 -0
  662. package/extensions/minimax/plugin-registration.contract.test.ts +15 -0
  663. package/extensions/minimax/provider-catalog.ts +86 -0
  664. package/extensions/minimax/provider-contract-api.ts +84 -0
  665. package/extensions/minimax/provider-discovery.contract.test.ts +3 -0
  666. package/extensions/minimax/provider-http.test-helpers.ts +142 -0
  667. package/extensions/minimax/provider-models.ts +21 -0
  668. package/extensions/minimax/provider-registration.ts +285 -0
  669. package/extensions/minimax/speech-provider.test.ts +576 -0
  670. package/extensions/minimax/speech-provider.ts +312 -0
  671. package/extensions/minimax/src/minimax-web-search-provider.runtime.ts +270 -0
  672. package/extensions/minimax/src/minimax-web-search-provider.test.ts +177 -0
  673. package/extensions/minimax/src/minimax-web-search-provider.ts +64 -0
  674. package/extensions/minimax/test-api.ts +11 -0
  675. package/extensions/minimax/tsconfig.json +16 -0
  676. package/extensions/minimax/tts.ts +116 -0
  677. package/extensions/minimax/video-generation-provider.test.ts +214 -0
  678. package/extensions/minimax/video-generation-provider.ts +456 -0
  679. package/extensions/minimax/web-search-contract-api.ts +35 -0
  680. package/extensions/minimax/web-search-provider.ts +1 -0
  681. package/extensions/mistral/api.test.ts +195 -0
  682. package/extensions/mistral/api.ts +81 -0
  683. package/extensions/mistral/embedding-provider.ts +52 -0
  684. package/extensions/mistral/index.ts +61 -0
  685. package/extensions/mistral/media-understanding-provider.test.ts +46 -0
  686. package/extensions/mistral/media-understanding-provider.ts +21 -0
  687. package/extensions/mistral/memory-embedding-adapter.ts +35 -0
  688. package/extensions/mistral/mistral.live.test.ts +62 -0
  689. package/extensions/mistral/model-definitions.test.ts +65 -0
  690. package/extensions/mistral/model-definitions.ts +37 -0
  691. package/extensions/mistral/onboard.test.ts +54 -0
  692. package/extensions/mistral/onboard.ts +31 -0
  693. package/extensions/mistral/openclaw.plugin.json +180 -0
  694. package/extensions/mistral/package.json +15 -0
  695. package/extensions/mistral/provider-catalog.ts +10 -0
  696. package/extensions/mistral/provider-compat.ts +62 -0
  697. package/extensions/mistral/realtime-transcription-provider.test.ts +61 -0
  698. package/extensions/mistral/realtime-transcription-provider.ts +280 -0
  699. package/extensions/mistral/test-api.ts +2 -0
  700. package/extensions/mistral/tsconfig.json +16 -0
  701. package/extensions/moonshot/api.ts +9 -0
  702. package/extensions/moonshot/index.test.ts +73 -0
  703. package/extensions/moonshot/index.ts +81 -0
  704. package/extensions/moonshot/media-understanding-provider.test.ts +92 -0
  705. package/extensions/moonshot/media-understanding-provider.ts +85 -0
  706. package/extensions/moonshot/moonshot.live.test.ts +56 -0
  707. package/extensions/moonshot/onboard.ts +38 -0
  708. package/extensions/moonshot/openclaw.plugin.json +209 -0
  709. package/extensions/moonshot/package.json +15 -0
  710. package/extensions/moonshot/provider-catalog.test.ts +84 -0
  711. package/extensions/moonshot/provider-catalog.ts +34 -0
  712. package/extensions/moonshot/provider-contract-api.ts +33 -0
  713. package/extensions/moonshot/provider-discovery.ts +17 -0
  714. package/extensions/moonshot/src/kimi-web-search-provider.runtime.ts +513 -0
  715. package/extensions/moonshot/src/kimi-web-search-provider.test.ts +297 -0
  716. package/extensions/moonshot/src/kimi-web-search-provider.ts +71 -0
  717. package/extensions/moonshot/test-api.ts +2 -0
  718. package/extensions/moonshot/tsconfig.json +16 -0
  719. package/extensions/moonshot/web-search-contract-api.ts +28 -0
  720. package/extensions/moonshot/web-search-provider.ts +1 -0
  721. package/extensions/nvidia/api.ts +6 -0
  722. package/extensions/nvidia/index.test.ts +180 -0
  723. package/extensions/nvidia/index.ts +64 -0
  724. package/extensions/nvidia/onboard.test.ts +49 -0
  725. package/extensions/nvidia/onboard.ts +30 -0
  726. package/extensions/nvidia/openclaw.plugin.json +122 -0
  727. package/extensions/nvidia/package.json +15 -0
  728. package/extensions/nvidia/plugin-registration.contract.test.ts +14 -0
  729. package/extensions/nvidia/provider-catalog.test.ts +21 -0
  730. package/extensions/nvidia/provider-catalog.ts +15 -0
  731. package/extensions/nvidia/tsconfig.json +16 -0
  732. package/extensions/ollama/README.md +3 -0
  733. package/extensions/ollama/api.ts +34 -0
  734. package/extensions/ollama/index.test.ts +979 -0
  735. package/extensions/ollama/index.ts +336 -0
  736. package/extensions/ollama/ollama.live.test.ts +287 -0
  737. package/extensions/ollama/openclaw.plugin.json +67 -0
  738. package/extensions/ollama/package.json +19 -0
  739. package/extensions/ollama/plugin-registration.contract.test.ts +7 -0
  740. package/extensions/ollama/provider-discovery.import-guard.test.ts +29 -0
  741. package/extensions/ollama/provider-discovery.test.ts +657 -0
  742. package/extensions/ollama/provider-discovery.ts +69 -0
  743. package/extensions/ollama/provider-policy-api.test.ts +72 -0
  744. package/extensions/ollama/provider-policy-api.ts +59 -0
  745. package/extensions/ollama/runtime-api.ts +22 -0
  746. package/extensions/ollama/src/defaults.ts +14 -0
  747. package/extensions/ollama/src/discovery-shared.test.ts +41 -0
  748. package/extensions/ollama/src/discovery-shared.ts +322 -0
  749. package/extensions/ollama/src/embedding-provider.test.ts +557 -0
  750. package/extensions/ollama/src/embedding-provider.ts +393 -0
  751. package/extensions/ollama/src/media-understanding-provider.ts +18 -0
  752. package/extensions/ollama/src/memory-embedding-adapter.ts +30 -0
  753. package/extensions/ollama/src/model-id.ts +24 -0
  754. package/extensions/ollama/src/ollama-json.ts +143 -0
  755. package/extensions/ollama/src/provider-base-url.test.ts +44 -0
  756. package/extensions/ollama/src/provider-base-url.ts +23 -0
  757. package/extensions/ollama/src/provider-models.ssrf.test.ts +41 -0
  758. package/extensions/ollama/src/provider-models.test.ts +312 -0
  759. package/extensions/ollama/src/provider-models.ts +327 -0
  760. package/extensions/ollama/src/setup.test.ts +771 -0
  761. package/extensions/ollama/src/setup.ts +743 -0
  762. package/extensions/ollama/src/stream-runtime.test.ts +2218 -0
  763. package/extensions/ollama/src/stream.test.ts +252 -0
  764. package/extensions/ollama/src/stream.ts +1347 -0
  765. package/extensions/ollama/src/web-search-provider.test.ts +488 -0
  766. package/extensions/ollama/src/web-search-provider.ts +350 -0
  767. package/extensions/ollama/src/wsl2-crash-loop-check.test.ts +157 -0
  768. package/extensions/ollama/src/wsl2-crash-loop-check.ts +84 -0
  769. package/extensions/ollama/tsconfig.json +16 -0
  770. package/extensions/ollama/web-search-contract-api.ts +26 -0
  771. package/extensions/ollama/web-search-provider.ts +1 -0
  772. package/extensions/openai/api.ts +16 -0
  773. package/extensions/openai/auth-choice-copy.ts +33 -0
  774. package/extensions/openai/base-url.test.ts +60 -0
  775. package/extensions/openai/base-url.ts +23 -0
  776. package/extensions/openai/default-models.test.ts +36 -0
  777. package/extensions/openai/default-models.ts +40 -0
  778. package/extensions/openai/embedding-batch.test.ts +10 -0
  779. package/extensions/openai/embedding-batch.ts +274 -0
  780. package/extensions/openai/embedding-provider.test.ts +102 -0
  781. package/extensions/openai/embedding-provider.ts +110 -0
  782. package/extensions/openai/image-generation-provider.test.ts +1624 -0
  783. package/extensions/openai/image-generation-provider.ts +903 -0
  784. package/extensions/openai/index.test.ts +630 -0
  785. package/extensions/openai/index.ts +58 -0
  786. package/extensions/openai/media-understanding-provider.test.ts +119 -0
  787. package/extensions/openai/media-understanding-provider.ts +51 -0
  788. package/extensions/openai/memory-embedding-adapter.test.ts +82 -0
  789. package/extensions/openai/memory-embedding-adapter.ts +68 -0
  790. package/extensions/openai/native-web-search.ts +103 -0
  791. package/extensions/openai/openai-codex-auth-identity.test.ts +77 -0
  792. package/extensions/openai/openai-codex-auth-identity.ts +100 -0
  793. package/extensions/openai/openai-codex-catalog.ts +12 -0
  794. package/extensions/openai/openai-codex-device-code.test.ts +248 -0
  795. package/extensions/openai/openai-codex-device-code.ts +309 -0
  796. package/extensions/openai/openai-codex-oauth.runtime.ts +348 -0
  797. package/extensions/openai/openai-codex-provider.runtime.ts +45 -0
  798. package/extensions/openai/openai-codex-provider.test.ts +883 -0
  799. package/extensions/openai/openai-codex-provider.ts +636 -0
  800. package/extensions/openai/openai-codex-shared.ts +3 -0
  801. package/extensions/openai/openai-provider.live.test.ts +196 -0
  802. package/extensions/openai/openai-provider.test.ts +929 -0
  803. package/extensions/openai/openai-provider.ts +325 -0
  804. package/extensions/openai/openai-tts.live.test.ts +44 -0
  805. package/extensions/openai/openai.live.test.ts +493 -0
  806. package/extensions/openai/openclaw.plugin.json +897 -0
  807. package/extensions/openai/openclaw.plugin.test.ts +181 -0
  808. package/extensions/openai/package.json +19 -0
  809. package/extensions/openai/plugin-registration.contract.test.ts +9 -0
  810. package/extensions/openai/prompt-overlay.ts +51 -0
  811. package/extensions/openai/provider-auth.contract.test.ts +12 -0
  812. package/extensions/openai/provider-catalog.contract.test.ts +3 -0
  813. package/extensions/openai/provider-contract-api.ts +83 -0
  814. package/extensions/openai/provider-policy-api.ts +20 -0
  815. package/extensions/openai/provider-runtime.contract.test.ts +3 -0
  816. package/extensions/openai/realtime-provider-shared.ts +168 -0
  817. package/extensions/openai/realtime-transcription-provider.test.ts +356 -0
  818. package/extensions/openai/realtime-transcription-provider.ts +307 -0
  819. package/extensions/openai/realtime-voice-provider.test.ts +1924 -0
  820. package/extensions/openai/realtime-voice-provider.ts +1315 -0
  821. package/extensions/openai/register.runtime.ts +15 -0
  822. package/extensions/openai/replay-policy.ts +32 -0
  823. package/extensions/openai/setup-api.test.ts +29 -0
  824. package/extensions/openai/setup-api.ts +166 -0
  825. package/extensions/openai/shared.ts +131 -0
  826. package/extensions/openai/speech-provider.test.ts +324 -0
  827. package/extensions/openai/speech-provider.ts +347 -0
  828. package/extensions/openai/test-api.ts +9 -0
  829. package/extensions/openai/test-support/provider-catalog.contract-test-support.ts +134 -0
  830. package/extensions/openai/thinking-policy.ts +55 -0
  831. package/extensions/openai/transport-policy.test.ts +128 -0
  832. package/extensions/openai/transport-policy.ts +111 -0
  833. package/extensions/openai/tsconfig.json +16 -0
  834. package/extensions/openai/tts.test.ts +444 -0
  835. package/extensions/openai/tts.ts +184 -0
  836. package/extensions/openai/video-generation-provider.test.ts +254 -0
  837. package/extensions/openai/video-generation-provider.ts +382 -0
  838. package/extensions/opencode/api.ts +9 -0
  839. package/extensions/opencode/index.test.ts +84 -0
  840. package/extensions/opencode/index.ts +74 -0
  841. package/extensions/opencode/media-understanding-provider.test.ts +44 -0
  842. package/extensions/opencode/media-understanding-provider.ts +42 -0
  843. package/extensions/opencode/onboard.test.ts +25 -0
  844. package/extensions/opencode/onboard.ts +29 -0
  845. package/extensions/opencode/openclaw.plugin.json +55 -0
  846. package/extensions/opencode/package.json +15 -0
  847. package/extensions/opencode/plugin-registration.contract.test.ts +8 -0
  848. package/extensions/opencode/provider-policy-api.test.ts +44 -0
  849. package/extensions/opencode/provider-policy-api.ts +5 -0
  850. package/extensions/opencode/tsconfig.json +16 -0
  851. package/extensions/opencode-go/api.ts +27 -0
  852. package/extensions/opencode-go/index.test.ts +305 -0
  853. package/extensions/opencode-go/index.ts +101 -0
  854. package/extensions/opencode-go/media-understanding-provider.test.ts +12 -0
  855. package/extensions/opencode-go/media-understanding-provider.ts +15 -0
  856. package/extensions/opencode-go/onboard.test.ts +28 -0
  857. package/extensions/opencode-go/onboard.ts +17 -0
  858. package/extensions/opencode-go/openclaw.plugin.json +106 -0
  859. package/extensions/opencode-go/package.json +15 -0
  860. package/extensions/opencode-go/plugin-registration.contract.test.ts +8 -0
  861. package/extensions/opencode-go/provider-catalog.ts +135 -0
  862. package/extensions/opencode-go/stream.ts +51 -0
  863. package/extensions/opencode-go/tsconfig.json +16 -0
  864. package/extensions/openrouter/api.ts +12 -0
  865. package/extensions/openrouter/image-generation-provider.test.ts +361 -0
  866. package/extensions/openrouter/image-generation-provider.ts +345 -0
  867. package/extensions/openrouter/index.test.ts +650 -0
  868. package/extensions/openrouter/index.ts +184 -0
  869. package/extensions/openrouter/media-understanding-provider.test.ts +260 -0
  870. package/extensions/openrouter/media-understanding-provider.ts +176 -0
  871. package/extensions/openrouter/models.ts +18 -0
  872. package/extensions/openrouter/music-generation-provider.test.ts +226 -0
  873. package/extensions/openrouter/music-generation-provider.ts +344 -0
  874. package/extensions/openrouter/onboard.test.ts +27 -0
  875. package/extensions/openrouter/onboard.ts +32 -0
  876. package/extensions/openrouter/openclaw.plugin.json +81 -0
  877. package/extensions/openrouter/openrouter.live.test.ts +118 -0
  878. package/extensions/openrouter/package.json +15 -0
  879. package/extensions/openrouter/provider-catalog.ts +88 -0
  880. package/extensions/openrouter/provider-contract-api.ts +27 -0
  881. package/extensions/openrouter/provider-policy-api.ts +5 -0
  882. package/extensions/openrouter/provider-routing.ts +87 -0
  883. package/extensions/openrouter/provider-runtime.contract.test.ts +3 -0
  884. package/extensions/openrouter/speech-provider.test.ts +218 -0
  885. package/extensions/openrouter/speech-provider.ts +46 -0
  886. package/extensions/openrouter/stream.ts +247 -0
  887. package/extensions/openrouter/test-api.ts +4 -0
  888. package/extensions/openrouter/thinking-policy.ts +34 -0
  889. package/extensions/openrouter/tsconfig.json +16 -0
  890. package/extensions/openrouter/video-generation-provider.test.ts +722 -0
  891. package/extensions/openrouter/video-generation-provider.ts +530 -0
  892. package/extensions/openrouter/video-http.ts +48 -0
  893. package/extensions/openrouter/video-model-catalog.ts +299 -0
  894. package/extensions/openshell/index.ts +28 -0
  895. package/extensions/openshell/npm-shrinkwrap.json +24 -0
  896. package/extensions/openshell/openclaw.plugin.json +118 -0
  897. package/extensions/openshell/package.json +37 -0
  898. package/extensions/openshell/src/backend.e2e.test.ts +595 -0
  899. package/extensions/openshell/src/backend.test.ts +40 -0
  900. package/extensions/openshell/src/backend.ts +512 -0
  901. package/extensions/openshell/src/backend.types.ts +11 -0
  902. package/extensions/openshell/src/cli.ts +85 -0
  903. package/extensions/openshell/src/config.test.ts +80 -0
  904. package/extensions/openshell/src/config.ts +194 -0
  905. package/extensions/openshell/src/fs-bridge.ts +370 -0
  906. package/extensions/openshell/src/mirror.test.ts +194 -0
  907. package/extensions/openshell/src/mirror.ts +141 -0
  908. package/extensions/openshell/src/openshell-core.test.ts +529 -0
  909. package/extensions/openshell/tsconfig.json +16 -0
  910. package/extensions/perplexity/index.ts +11 -0
  911. package/extensions/perplexity/openclaw.plugin.json +52 -0
  912. package/extensions/perplexity/package.json +15 -0
  913. package/extensions/perplexity/src/perplexity-web-search-provider.runtime.ts +551 -0
  914. package/extensions/perplexity/src/perplexity-web-search-provider.shared.ts +124 -0
  915. package/extensions/perplexity/src/perplexity-web-search-provider.test.ts +151 -0
  916. package/extensions/perplexity/src/perplexity-web-search-provider.ts +127 -0
  917. package/extensions/perplexity/test-api.ts +1 -0
  918. package/extensions/perplexity/tsconfig.json +16 -0
  919. package/extensions/perplexity/web-search-contract-api.ts +13 -0
  920. package/extensions/perplexity/web-search-provider.ts +1 -0
  921. package/extensions/qianfan/api.ts +6 -0
  922. package/extensions/qianfan/index.test.ts +133 -0
  923. package/extensions/qianfan/index.ts +31 -0
  924. package/extensions/qianfan/onboard.ts +61 -0
  925. package/extensions/qianfan/openclaw.plugin.json +78 -0
  926. package/extensions/qianfan/package.json +15 -0
  927. package/extensions/qianfan/provider-catalog.ts +13 -0
  928. package/extensions/qianfan/tsconfig.json +16 -0
  929. package/extensions/qwen/api.ts +34 -0
  930. package/extensions/qwen/index.test.ts +31 -0
  931. package/extensions/qwen/index.ts +181 -0
  932. package/extensions/qwen/media-understanding-provider.test.ts +76 -0
  933. package/extensions/qwen/media-understanding-provider.ts +88 -0
  934. package/extensions/qwen/model-definitions.ts +20 -0
  935. package/extensions/qwen/models.ts +202 -0
  936. package/extensions/qwen/onboard.ts +73 -0
  937. package/extensions/qwen/openclaw.plugin.json +143 -0
  938. package/extensions/qwen/package.json +15 -0
  939. package/extensions/qwen/plugin-registration.contract.test.ts +10 -0
  940. package/extensions/qwen/provider-catalog.test.ts +62 -0
  941. package/extensions/qwen/provider-catalog.ts +13 -0
  942. package/extensions/qwen/provider-discovery.contract.test.ts +3 -0
  943. package/extensions/qwen/stream.test.ts +171 -0
  944. package/extensions/qwen/stream.ts +87 -0
  945. package/extensions/qwen/test-api.ts +2 -0
  946. package/extensions/qwen/tsconfig.json +16 -0
  947. package/extensions/qwen/video-generation-provider.test.ts +155 -0
  948. package/extensions/qwen/video-generation-provider.ts +111 -0
  949. package/extensions/runway/index.ts +11 -0
  950. package/extensions/runway/openclaw.plugin.json +34 -0
  951. package/extensions/runway/package.json +15 -0
  952. package/extensions/runway/plugin-registration.contract.test.ts +7 -0
  953. package/extensions/runway/tsconfig.json +16 -0
  954. package/extensions/runway/video-generation-provider.test.ts +248 -0
  955. package/extensions/runway/video-generation-provider.ts +462 -0
  956. package/extensions/senseaudio/index.ts +11 -0
  957. package/extensions/senseaudio/media-understanding-provider.test.ts +136 -0
  958. package/extensions/senseaudio/media-understanding-provider.ts +25 -0
  959. package/extensions/senseaudio/openclaw.plugin.json +18 -0
  960. package/extensions/senseaudio/package.json +15 -0
  961. package/extensions/senseaudio/test-api.ts +1 -0
  962. package/extensions/sglang/README.md +3 -0
  963. package/extensions/sglang/api.ts +7 -0
  964. package/extensions/sglang/defaults.ts +4 -0
  965. package/extensions/sglang/index.test.ts +34 -0
  966. package/extensions/sglang/index.ts +95 -0
  967. package/extensions/sglang/models.ts +23 -0
  968. package/extensions/sglang/openclaw.plugin.json +45 -0
  969. package/extensions/sglang/package.json +15 -0
  970. package/extensions/sglang/provider-discovery.contract.test.ts +7 -0
  971. package/extensions/sglang/tsconfig.json +16 -0
  972. package/extensions/skill-workshop/api.ts +3 -0
  973. package/extensions/skill-workshop/index.test.ts +990 -0
  974. package/extensions/skill-workshop/index.ts +170 -0
  975. package/extensions/skill-workshop/openclaw.plugin.json +83 -0
  976. package/extensions/skill-workshop/package.json +18 -0
  977. package/extensions/skill-workshop/src/config.ts +50 -0
  978. package/extensions/skill-workshop/src/prompt.ts +18 -0
  979. package/extensions/skill-workshop/src/reviewer.ts +290 -0
  980. package/extensions/skill-workshop/src/scanner.ts +69 -0
  981. package/extensions/skill-workshop/src/signals.ts +95 -0
  982. package/extensions/skill-workshop/src/skills.ts +186 -0
  983. package/extensions/skill-workshop/src/store.ts +184 -0
  984. package/extensions/skill-workshop/src/text.ts +59 -0
  985. package/extensions/skill-workshop/src/tool.ts +200 -0
  986. package/extensions/skill-workshop/src/types.ts +42 -0
  987. package/extensions/skill-workshop/src/workshop.ts +85 -0
  988. package/extensions/speech-core/api.ts +54 -0
  989. package/extensions/speech-core/package.json +10 -0
  990. package/extensions/speech-core/runtime-api.ts +42 -0
  991. package/extensions/speech-core/src/tts.test.ts +1025 -0
  992. package/extensions/speech-core/src/tts.ts +1929 -0
  993. package/extensions/speech-core/tsconfig.json +16 -0
  994. package/extensions/stepfun/index.ts +252 -0
  995. package/extensions/stepfun/onboard.ts +73 -0
  996. package/extensions/stepfun/openclaw.plugin.json +148 -0
  997. package/extensions/stepfun/package.json +15 -0
  998. package/extensions/stepfun/provider-catalog.ts +40 -0
  999. package/extensions/stepfun/tsconfig.json +16 -0
  1000. package/extensions/tencent/api.ts +7 -0
  1001. package/extensions/tencent/index.ts +64 -0
  1002. package/extensions/tencent/models.ts +25 -0
  1003. package/extensions/tencent/onboard.ts +38 -0
  1004. package/extensions/tencent/openclaw.plugin.json +86 -0
  1005. package/extensions/tencent/package.json +15 -0
  1006. package/extensions/tencent/provider-catalog.ts +14 -0
  1007. package/extensions/tencent/provider-discovery.ts +17 -0
  1008. package/extensions/tencent/tsconfig.json +16 -0
  1009. package/extensions/together/api.ts +7 -0
  1010. package/extensions/together/index.ts +42 -0
  1011. package/extensions/together/models.ts +23 -0
  1012. package/extensions/together/onboard.ts +26 -0
  1013. package/extensions/together/openclaw.plugin.json +160 -0
  1014. package/extensions/together/package.json +15 -0
  1015. package/extensions/together/plugin-registration.contract.test.ts +8 -0
  1016. package/extensions/together/provider-catalog.ts +10 -0
  1017. package/extensions/together/tsconfig.json +16 -0
  1018. package/extensions/together/video-generation-provider.test.ts +130 -0
  1019. package/extensions/together/video-generation-provider.ts +281 -0
  1020. package/extensions/tts-local-cli/index.ts +11 -0
  1021. package/extensions/tts-local-cli/openclaw.plugin.json +15 -0
  1022. package/extensions/tts-local-cli/package.json +15 -0
  1023. package/extensions/tts-local-cli/speech-provider.test.ts +307 -0
  1024. package/extensions/tts-local-cli/speech-provider.ts +455 -0
  1025. package/extensions/venice/api.ts +8 -0
  1026. package/extensions/venice/index.test.ts +109 -0
  1027. package/extensions/venice/index.ts +70 -0
  1028. package/extensions/venice/models.test.ts +291 -0
  1029. package/extensions/venice/models.ts +302 -0
  1030. package/extensions/venice/onboard.ts +27 -0
  1031. package/extensions/venice/openclaw.plugin.json +504 -0
  1032. package/extensions/venice/package.json +15 -0
  1033. package/extensions/venice/provider-catalog.ts +11 -0
  1034. package/extensions/venice/provider-runtime.contract.test.ts +3 -0
  1035. package/extensions/venice/stream.ts +37 -0
  1036. package/extensions/venice/tsconfig.json +16 -0
  1037. package/extensions/vercel-ai-gateway/api.ts +12 -0
  1038. package/extensions/vercel-ai-gateway/index.ts +41 -0
  1039. package/extensions/vercel-ai-gateway/models.ts +226 -0
  1040. package/extensions/vercel-ai-gateway/onboard.ts +32 -0
  1041. package/extensions/vercel-ai-gateway/openclaw.plugin.json +61 -0
  1042. package/extensions/vercel-ai-gateway/package.json +15 -0
  1043. package/extensions/vercel-ai-gateway/provider-catalog.test.ts +96 -0
  1044. package/extensions/vercel-ai-gateway/provider-catalog.ts +22 -0
  1045. package/extensions/vercel-ai-gateway/thinking.test.ts +100 -0
  1046. package/extensions/vercel-ai-gateway/thinking.ts +77 -0
  1047. package/extensions/vercel-ai-gateway/tsconfig.json +16 -0
  1048. package/extensions/vllm/README.md +3 -0
  1049. package/extensions/vllm/api.ts +8 -0
  1050. package/extensions/vllm/defaults.ts +4 -0
  1051. package/extensions/vllm/index.ts +96 -0
  1052. package/extensions/vllm/models.ts +23 -0
  1053. package/extensions/vllm/openclaw.plugin.json +45 -0
  1054. package/extensions/vllm/package.json +15 -0
  1055. package/extensions/vllm/provider-discovery.contract.test.ts +7 -0
  1056. package/extensions/vllm/register.runtime.ts +7 -0
  1057. package/extensions/vllm/stream.test.ts +282 -0
  1058. package/extensions/vllm/stream.ts +164 -0
  1059. package/extensions/vllm/tsconfig.json +16 -0
  1060. package/extensions/volcengine/api.ts +56 -0
  1061. package/extensions/volcengine/index.test.ts +92 -0
  1062. package/extensions/volcengine/index.ts +87 -0
  1063. package/extensions/volcengine/models.ts +28 -0
  1064. package/extensions/volcengine/openclaw.plugin.json +221 -0
  1065. package/extensions/volcengine/package.json +15 -0
  1066. package/extensions/volcengine/provider-catalog.ts +17 -0
  1067. package/extensions/volcengine/provider-discovery.ts +31 -0
  1068. package/extensions/volcengine/speech-provider.ts +229 -0
  1069. package/extensions/volcengine/tsconfig.json +16 -0
  1070. package/extensions/volcengine/tts.live.test.ts +30 -0
  1071. package/extensions/volcengine/tts.test.ts +279 -0
  1072. package/extensions/volcengine/tts.ts +266 -0
  1073. package/extensions/voyage/embedding-batch.ts +315 -0
  1074. package/extensions/voyage/embedding-provider.ts +90 -0
  1075. package/extensions/voyage/index.ts +11 -0
  1076. package/extensions/voyage/memory-embedding-adapter.ts +56 -0
  1077. package/extensions/voyage/openclaw.plugin.json +18 -0
  1078. package/extensions/voyage/package.json +15 -0
  1079. package/extensions/xai/.boundary-stubs/anthropic-vertex-api.d.ts +2 -0
  1080. package/extensions/xai/.boundary-stubs/ollama-api.d.ts +1 -0
  1081. package/extensions/xai/.boundary-stubs/ollama-runtime-api.d.ts +16 -0
  1082. package/extensions/xai/.boundary-stubs/speech-core-runtime-api.d.ts +33 -0
  1083. package/extensions/xai/api.test.ts +51 -0
  1084. package/extensions/xai/api.ts +119 -0
  1085. package/extensions/xai/code-execution.test.ts +262 -0
  1086. package/extensions/xai/code-execution.ts +146 -0
  1087. package/extensions/xai/image-generation-provider.test.ts +293 -0
  1088. package/extensions/xai/image-generation-provider.ts +124 -0
  1089. package/extensions/xai/index.test.ts +263 -0
  1090. package/extensions/xai/index.ts +233 -0
  1091. package/extensions/xai/model-compat.ts +34 -0
  1092. package/extensions/xai/model-definitions.ts +346 -0
  1093. package/extensions/xai/model-id.test.ts +32 -0
  1094. package/extensions/xai/model-id.ts +24 -0
  1095. package/extensions/xai/onboard.test.ts +91 -0
  1096. package/extensions/xai/onboard.ts +56 -0
  1097. package/extensions/xai/openclaw.plugin.json +274 -0
  1098. package/extensions/xai/package.json +20 -0
  1099. package/extensions/xai/plugin-registration.contract.test.ts +11 -0
  1100. package/extensions/xai/provider-catalog.ts +12 -0
  1101. package/extensions/xai/provider-contract-api.ts +22 -0
  1102. package/extensions/xai/provider-discovery.ts +27 -0
  1103. package/extensions/xai/provider-models.ts +45 -0
  1104. package/extensions/xai/provider-policy-api.test.ts +37 -0
  1105. package/extensions/xai/provider-policy-api.ts +18 -0
  1106. package/extensions/xai/realtime-transcription-provider.test.ts +273 -0
  1107. package/extensions/xai/realtime-transcription-provider.ts +306 -0
  1108. package/extensions/xai/runtime-model-compat.test.ts +60 -0
  1109. package/extensions/xai/runtime-model-compat.ts +72 -0
  1110. package/extensions/xai/setup-api.ts +22 -0
  1111. package/extensions/xai/speech-provider.test.ts +184 -0
  1112. package/extensions/xai/speech-provider.ts +275 -0
  1113. package/extensions/xai/src/code-execution-shared.ts +110 -0
  1114. package/extensions/xai/src/responses-tool-shared.test.ts +107 -0
  1115. package/extensions/xai/src/responses-tool-shared.ts +163 -0
  1116. package/extensions/xai/src/tool-auth-shared.test.ts +326 -0
  1117. package/extensions/xai/src/tool-auth-shared.ts +219 -0
  1118. package/extensions/xai/src/tool-config-shared.test.ts +36 -0
  1119. package/extensions/xai/src/tool-config-shared.ts +32 -0
  1120. package/extensions/xai/src/web-search-provider.runtime.ts +429 -0
  1121. package/extensions/xai/src/web-search-response.types.ts +25 -0
  1122. package/extensions/xai/src/web-search-shared.ts +124 -0
  1123. package/extensions/xai/src/x-search-config.ts +78 -0
  1124. package/extensions/xai/src/x-search-shared.ts +146 -0
  1125. package/extensions/xai/src/xai-user-agent.test.ts +59 -0
  1126. package/extensions/xai/src/xai-user-agent.ts +52 -0
  1127. package/extensions/xai/stream.test.ts +410 -0
  1128. package/extensions/xai/stream.ts +359 -0
  1129. package/extensions/xai/stt.test.ts +106 -0
  1130. package/extensions/xai/stt.ts +91 -0
  1131. package/extensions/xai/test-api.ts +1 -0
  1132. package/extensions/xai/test-helpers.ts +73 -0
  1133. package/extensions/xai/tsconfig.json +64 -0
  1134. package/extensions/xai/tts.test.ts +125 -0
  1135. package/extensions/xai/tts.ts +97 -0
  1136. package/extensions/xai/video-generation-provider.test.ts +443 -0
  1137. package/extensions/xai/video-generation-provider.ts +499 -0
  1138. package/extensions/xai/web-search-contract-api.ts +29 -0
  1139. package/extensions/xai/web-search.test.ts +1242 -0
  1140. package/extensions/xai/web-search.ts +68 -0
  1141. package/extensions/xai/x-search-tool-shared.ts +48 -0
  1142. package/extensions/xai/x-search.live.test.ts +76 -0
  1143. package/extensions/xai/x-search.test.ts +484 -0
  1144. package/extensions/xai/x-search.ts +230 -0
  1145. package/extensions/xai/xai-oauth.test.ts +387 -0
  1146. package/extensions/xai/xai-oauth.ts +752 -0
  1147. package/extensions/xai/xai.live.test.ts +323 -0
  1148. package/launcher.js +97 -0
  1149. package/logger.js +87 -0
  1150. package/package.json +21 -0
  1151. package/server.js +1800 -0
  1152. package/skills/ai-error-prevention/SKILL.md +105 -0
  1153. package/skills/api-design/SKILL.md +523 -0
  1154. package/skills/architecture-decision-records/SKILL.md +179 -0
  1155. package/skills/autonomous-loops/SKILL.md +610 -0
  1156. package/skills/backend-patterns/SKILL.md +598 -0
  1157. package/skills/codebase-onboarding/SKILL.md +233 -0
  1158. package/skills/coding-standards/SKILL.md +530 -0
  1159. package/skills/database-migrations/SKILL.md +429 -0
  1160. package/skills/deep-research/SKILL.md +155 -0
  1161. package/skills/error-prevention/SKILL.md +61 -0
  1162. package/skills/exa-search/SKILL.md +103 -0
  1163. package/skills/frontend-slides/SKILL.md +184 -0
  1164. package/skills/frontend-slides/STYLE_PRESETS.md +330 -0
  1165. package/skills/git-workflow/SKILL.md +715 -0
  1166. package/skills/iterative-retrieval/SKILL.md +211 -0
  1167. package/skills/php-security/SKILL.md +70 -0
  1168. package/skills/php-security/rules/thinkphp-security.rules +23 -0
  1169. package/skills/requirement-ears/SKILL.md +31 -0
  1170. package/skills/rules-distill/SKILL.md +264 -0
  1171. package/skills/rules-distill/scripts/scan-rules.sh +58 -0
  1172. package/skills/rules-distill/scripts/scan-skills.sh +129 -0
  1173. package/skills/search-first/SKILL.md +161 -0
  1174. package/skills/security-review/SKILL.md +495 -0
  1175. package/skills/security-review/cloud-infrastructure-security.md +361 -0
  1176. package/skills/security-scan/SKILL.md +68 -0
  1177. package/skills/security-scan/scripts/scan-config.ps1 +31 -0
  1178. package/skills/security-scan/scripts/scan-sqli.ps1 +21 -0
  1179. package/skills/skill-stocktake/SKILL.md +193 -0
  1180. package/skills/skill-stocktake/scripts/quick-diff.sh +87 -0
  1181. package/skills/skill-stocktake/scripts/save-results.sh +56 -0
  1182. package/skills/skill-stocktake/scripts/scan.sh +170 -0
  1183. package/skills/strategic-compact/SKILL.md +131 -0
  1184. package/skills/strategic-compact/suggest-compact.sh +54 -0
  1185. package/skills/tdd-workflow/SKILL.md +90 -0
  1186. package/skills/tdd-workflow/examples/IntegrationTestExample.php +35 -0
  1187. package/skills/tdd-workflow/examples/UnitTestExample.php +39 -0
  1188. package/skills/ui-spec-guider/ui-spec-guider/SKILL.md +37 -0
  1189. package/skills/ui-spec-guider/ui-spec-guider.skill +0 -0
  1190. package/skills/verification-loop/SKILL.md +126 -0
  1191. package/start.bat +29 -0
@@ -0,0 +1,1347 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import type { StreamFn } from "@earendil-works/pi-agent-core";
3
+ import type {
4
+ AssistantMessage,
5
+ StopReason,
6
+ TextContent,
7
+ ThinkingContent,
8
+ ToolCall,
9
+ Tool,
10
+ Usage,
11
+ } from "@earendil-works/pi-ai";
12
+ import { createAssistantMessageEventStream, streamSimple } from "@earendil-works/pi-ai";
13
+ import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
14
+ import type {
15
+ OpenClawConfig,
16
+ ProviderRuntimeModel,
17
+ ProviderWrapStreamFnContext,
18
+ } from "openclaw/plugin-sdk/plugin-entry";
19
+ import { isNonSecretApiKeyMarker } from "openclaw/plugin-sdk/provider-auth";
20
+ import {
21
+ DEFAULT_CONTEXT_TOKENS,
22
+ normalizeProviderId,
23
+ } from "openclaw/plugin-sdk/provider-model-shared";
24
+ import {
25
+ createMoonshotThinkingWrapper,
26
+ resolveMoonshotThinkingType,
27
+ streamWithPayloadPatch,
28
+ } from "openclaw/plugin-sdk/provider-stream-shared";
29
+ import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
30
+ import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
31
+ import {
32
+ normalizeLowercaseStringOrEmpty,
33
+ readStringValue,
34
+ } from "openclaw/plugin-sdk/string-coerce-runtime";
35
+ import { OLLAMA_DEFAULT_BASE_URL } from "./defaults.js";
36
+ import { normalizeOllamaWireModelId } from "./model-id.js";
37
+ import {
38
+ parseJsonObjectPreservingUnsafeIntegers,
39
+ parseJsonPreservingUnsafeIntegers,
40
+ } from "./ollama-json.js";
41
+ import { buildOllamaBaseUrlSsrFPolicy } from "./provider-models.js";
42
+
43
+ const log = createSubsystemLogger("ollama-stream");
44
+
45
+ export const OLLAMA_NATIVE_BASE_URL = OLLAMA_DEFAULT_BASE_URL;
46
+
47
+ const GARBLED_VISIBLE_TEXT_MODEL_RE = /\b(?:glm|kimi)\b/i;
48
+ const GARBLED_VISIBLE_TEXT_MIN_CHARS = 80;
49
+ const GARBLED_VISIBLE_TEXT_SYMBOL_RE = /[$#%&="'_~`^|\\/*+\-[\]{}()<>:;,.!?]/gu;
50
+ const LETTER_OR_DIGIT_RE = /[\p{L}\p{N}]/gu;
51
+
52
+ function countMatches(text: string, re: RegExp): number {
53
+ re.lastIndex = 0;
54
+ return Array.from(text.matchAll(re)).length;
55
+ }
56
+
57
+ function maxCharacterFrequency(text: string): number {
58
+ const counts = new Map<string, number>();
59
+ let max = 0;
60
+ for (const char of text) {
61
+ const count = (counts.get(char) ?? 0) + 1;
62
+ counts.set(char, count);
63
+ max = Math.max(max, count);
64
+ }
65
+ return max;
66
+ }
67
+
68
+ function isKnownOllamaGarbledVisibleTextModel(modelId: string): boolean {
69
+ return GARBLED_VISIBLE_TEXT_MODEL_RE.test(modelId);
70
+ }
71
+
72
+ function isLikelyGarbledVisibleText(params: { text: string; modelId: string }): boolean {
73
+ if (!isKnownOllamaGarbledVisibleTextModel(params.modelId)) {
74
+ return false;
75
+ }
76
+ const compact = params.text.replace(/\s+/g, "");
77
+ if (compact.length < GARBLED_VISIBLE_TEXT_MIN_CHARS) {
78
+ return false;
79
+ }
80
+
81
+ const letterOrDigitCount = countMatches(compact, LETTER_OR_DIGIT_RE);
82
+ const symbolCount = countMatches(compact, GARBLED_VISIBLE_TEXT_SYMBOL_RE);
83
+ const maxFrequency = maxCharacterFrequency(compact);
84
+ const letterOrDigitRatio = letterOrDigitCount / compact.length;
85
+ const symbolRatio = symbolCount / compact.length;
86
+ const dominantCharacterRatio = maxFrequency / compact.length;
87
+
88
+ return (
89
+ letterOrDigitRatio < 0.08 &&
90
+ symbolRatio > 0.6 &&
91
+ (dominantCharacterRatio > 0.22 || /[$#%&="'_~`^|\\/*+\-[\]{}()<>:;,.!?]{12,}/u.test(compact))
92
+ );
93
+ }
94
+
95
+ export function resolveOllamaBaseUrlForRun(params: {
96
+ modelBaseUrl?: string;
97
+ providerBaseUrl?: string;
98
+ }): string {
99
+ const providerBaseUrl = params.providerBaseUrl?.trim();
100
+ if (providerBaseUrl) {
101
+ return providerBaseUrl;
102
+ }
103
+ const modelBaseUrl = params.modelBaseUrl?.trim();
104
+ if (modelBaseUrl) {
105
+ return modelBaseUrl;
106
+ }
107
+ return OLLAMA_NATIVE_BASE_URL;
108
+ }
109
+
110
+ export function resolveConfiguredOllamaProviderConfig(params: {
111
+ config?: OpenClawConfig;
112
+ providerId?: string;
113
+ }) {
114
+ const providerId = params.providerId?.trim();
115
+ if (!providerId) {
116
+ return undefined;
117
+ }
118
+ const providers = params.config?.models?.providers;
119
+ if (!providers) {
120
+ return undefined;
121
+ }
122
+ const direct = providers[providerId];
123
+ if (direct) {
124
+ return direct;
125
+ }
126
+ const normalized = normalizeProviderId(providerId);
127
+ for (const [candidateId, candidate] of Object.entries(providers)) {
128
+ if (normalizeProviderId(candidateId) === normalized) {
129
+ return candidate;
130
+ }
131
+ }
132
+ return undefined;
133
+ }
134
+
135
+ export function isOllamaCompatProvider(model: {
136
+ provider?: string;
137
+ baseUrl?: string;
138
+ api?: string;
139
+ }): boolean {
140
+ const providerId = normalizeProviderId(model.provider ?? "");
141
+ if (providerId === "ollama") {
142
+ return true;
143
+ }
144
+ if (!model.baseUrl) {
145
+ return false;
146
+ }
147
+ try {
148
+ const parsed = new URL(model.baseUrl);
149
+ const hostname = normalizeLowercaseStringOrEmpty(parsed.hostname);
150
+ const isLocalhost =
151
+ hostname === "localhost" ||
152
+ hostname === "127.0.0.1" ||
153
+ hostname === "::1" ||
154
+ hostname === "[::1]";
155
+ if (isLocalhost && parsed.port === "11434") {
156
+ return true;
157
+ }
158
+
159
+ // Allow remote/LAN Ollama OpenAI-compatible endpoints when the provider id
160
+ // itself indicates Ollama usage (for example "my-ollama").
161
+ const providerHintsOllama = providerId.includes("ollama");
162
+ const isOllamaPort = parsed.port === "11434";
163
+ const isOllamaCompatPath = parsed.pathname === "/" || /^\/v1\/?$/i.test(parsed.pathname);
164
+ return providerHintsOllama && isOllamaPort && isOllamaCompatPath;
165
+ } catch {
166
+ return false;
167
+ }
168
+ }
169
+
170
+ export function resolveOllamaCompatNumCtxEnabled(params: {
171
+ config?: OpenClawConfig;
172
+ providerId?: string;
173
+ }): boolean {
174
+ return resolveConfiguredOllamaProviderConfig(params)?.injectNumCtxForOpenAICompat ?? true;
175
+ }
176
+
177
+ export function shouldInjectOllamaCompatNumCtx(params: {
178
+ model: { api?: string; provider?: string; baseUrl?: string };
179
+ config?: OpenClawConfig;
180
+ providerId?: string;
181
+ }): boolean {
182
+ if (params.model.api !== "openai-completions") {
183
+ return false;
184
+ }
185
+ if (!isOllamaCompatProvider(params.model)) {
186
+ return false;
187
+ }
188
+ return resolveOllamaCompatNumCtxEnabled({
189
+ config: params.config,
190
+ providerId: params.providerId,
191
+ });
192
+ }
193
+
194
+ export function wrapOllamaCompatNumCtx(baseFn: StreamFn | undefined, numCtx: number): StreamFn {
195
+ const streamFn = baseFn ?? streamSimple;
196
+ return (model, context, options) =>
197
+ streamWithPayloadPatch(streamFn, model, context, options, (payloadRecord) => {
198
+ if (!payloadRecord.options || typeof payloadRecord.options !== "object") {
199
+ payloadRecord.options = {};
200
+ }
201
+ (payloadRecord.options as Record<string, unknown>).num_ctx = numCtx;
202
+ normalizeOllamaCompatMessageToolArgs(payloadRecord);
203
+ });
204
+ }
205
+
206
+ type OllamaThinkValue = boolean | "low" | "medium" | "high";
207
+
208
+ const OLLAMA_OPTION_PARAM_KEYS = new Set([
209
+ "num_keep",
210
+ "seed",
211
+ "num_predict",
212
+ "top_k",
213
+ "top_p",
214
+ "min_p",
215
+ "typical_p",
216
+ "repeat_last_n",
217
+ "temperature",
218
+ "repeat_penalty",
219
+ "presence_penalty",
220
+ "frequency_penalty",
221
+ "stop",
222
+ "num_ctx",
223
+ "num_batch",
224
+ "num_gpu",
225
+ "main_gpu",
226
+ "use_mmap",
227
+ "num_thread",
228
+ ]);
229
+
230
+ const OLLAMA_TOP_LEVEL_PARAM_KEYS = new Set(["format", "keep_alive", "truncate", "shift"]);
231
+
232
+ function createOllamaThinkingWrapper(
233
+ baseFn: StreamFn | undefined,
234
+ think: OllamaThinkValue,
235
+ ): StreamFn {
236
+ const streamFn = baseFn ?? streamSimple;
237
+ return (model, context, options) =>
238
+ streamWithPayloadPatch(streamFn, model, context, options, (payloadRecord) => {
239
+ payloadRecord.think = think;
240
+ });
241
+ }
242
+
243
+ function resolveOllamaThinkValue(thinkingLevel: unknown): OllamaThinkValue | undefined {
244
+ if (thinkingLevel === "off") {
245
+ return false;
246
+ }
247
+ if (thinkingLevel === "low" || thinkingLevel === "medium" || thinkingLevel === "high") {
248
+ return thinkingLevel;
249
+ }
250
+ if (thinkingLevel === "minimal") {
251
+ return "low";
252
+ }
253
+ if (thinkingLevel === "xhigh" || thinkingLevel === "adaptive" || thinkingLevel === "max") {
254
+ return "high";
255
+ }
256
+ return undefined;
257
+ }
258
+
259
+ function resolveOllamaThinkParamValue(
260
+ params: Record<string, unknown> | undefined,
261
+ ): OllamaThinkValue | undefined {
262
+ const raw = params?.think ?? params?.thinking;
263
+ if (typeof raw === "boolean") {
264
+ return raw;
265
+ }
266
+ if (raw === "off") {
267
+ return false;
268
+ }
269
+ if (raw === "low" || raw === "medium" || raw === "high") {
270
+ return raw;
271
+ }
272
+ if (raw === "minimal") {
273
+ return "low";
274
+ }
275
+ if (raw === "xhigh" || raw === "adaptive" || raw === "max") {
276
+ return "high";
277
+ }
278
+ return undefined;
279
+ }
280
+
281
+ function shouldForwardNativeOllamaThink(
282
+ model: ProviderRuntimeModel | undefined,
283
+ think: OllamaThinkValue,
284
+ ): boolean {
285
+ // Ollama accepts top-level `think` as the native chat contract, but rejects
286
+ // truthy values for models known not to expose thinking support.
287
+ return think === false || model?.reasoning !== false;
288
+ }
289
+
290
+ function resolveOllamaConfiguredNumCtx(model: ProviderRuntimeModel): number | undefined {
291
+ const raw = model.params?.num_ctx;
292
+ if (typeof raw !== "number" || !Number.isFinite(raw) || raw <= 0) {
293
+ return undefined;
294
+ }
295
+ return Math.floor(raw);
296
+ }
297
+
298
+ function resolveOllamaNumCtx(model: ProviderRuntimeModel): number {
299
+ return (
300
+ resolveOllamaConfiguredNumCtx(model) ??
301
+ Math.max(1, Math.floor(model.contextWindow ?? model.maxTokens ?? DEFAULT_CONTEXT_TOKENS))
302
+ );
303
+ }
304
+
305
+ /**
306
+ * Resolves num_ctx for native /api/chat requests:
307
+ * 1. explicit `params.num_ctx` set on the model wins,
308
+ * 2. otherwise return undefined so Ollama's model, OLLAMA_CONTEXT_LENGTH,
309
+ * VRAM, or Modelfile policy decides.
310
+ *
311
+ * This intentionally differs from `resolveOllamaNumCtx` by not falling back
312
+ * to `DEFAULT_CONTEXT_TOKENS`: that constant is a sane wrapper-side guess for
313
+ * the OpenAI-compat path, but native `/api/chat` should not force the full
314
+ * advertised catalog context for local models unless the operator opted in.
315
+ */
316
+ function resolveOllamaNativeNumCtx(model: ProviderRuntimeModel): number | undefined {
317
+ return resolveOllamaConfiguredNumCtx(model);
318
+ }
319
+
320
+ function resolveOllamaModelOptions(model: ProviderRuntimeModel): Record<string, unknown> {
321
+ const options: Record<string, unknown> = {};
322
+ const params = model.params;
323
+ if (params && typeof params === "object" && !Array.isArray(params)) {
324
+ for (const [key, value] of Object.entries(params)) {
325
+ if (key === "num_ctx") {
326
+ continue;
327
+ }
328
+ if (value !== undefined && OLLAMA_OPTION_PARAM_KEYS.has(key)) {
329
+ options[key] = value;
330
+ }
331
+ }
332
+ }
333
+ const numCtx = resolveOllamaNativeNumCtx(model);
334
+ if (numCtx !== undefined) {
335
+ options.num_ctx = numCtx;
336
+ }
337
+ return options;
338
+ }
339
+
340
+ function resolveOllamaTopLevelParams(
341
+ model: ProviderRuntimeModel,
342
+ ): Record<string, unknown> | undefined {
343
+ const requestParams: Record<string, unknown> = {};
344
+ const params = model.params;
345
+ if (params && typeof params === "object" && !Array.isArray(params)) {
346
+ for (const [key, value] of Object.entries(params)) {
347
+ if (value !== undefined && OLLAMA_TOP_LEVEL_PARAM_KEYS.has(key)) {
348
+ requestParams[key] = value;
349
+ }
350
+ }
351
+ }
352
+ const think = resolveOllamaThinkParamValue(params);
353
+ if (think !== undefined && shouldForwardNativeOllamaThink(model, think)) {
354
+ requestParams.think = think;
355
+ }
356
+ return Object.keys(requestParams).length > 0 ? requestParams : undefined;
357
+ }
358
+
359
+ function isOllamaCloudKimiModelRef(modelId: string): boolean {
360
+ const normalizedModelId = normalizeLowercaseStringOrEmpty(modelId);
361
+ return normalizedModelId.startsWith("kimi-k") && normalizedModelId.includes(":cloud");
362
+ }
363
+
364
+ export function createConfiguredOllamaCompatStreamWrapper(
365
+ ctx: ProviderWrapStreamFnContext,
366
+ ): StreamFn | undefined {
367
+ let streamFn = ctx.streamFn;
368
+ const model = ctx.model;
369
+ let injectNumCtx = false;
370
+ const isNativeOllamaTransport = model?.api === "ollama";
371
+
372
+ if (model) {
373
+ const providerId =
374
+ typeof model.provider === "string" && model.provider.trim().length > 0
375
+ ? model.provider
376
+ : ctx.provider;
377
+ if (
378
+ shouldInjectOllamaCompatNumCtx({
379
+ model,
380
+ config: ctx.config,
381
+ providerId,
382
+ })
383
+ ) {
384
+ injectNumCtx = true;
385
+ }
386
+ }
387
+
388
+ if (injectNumCtx && model) {
389
+ streamFn = wrapOllamaCompatNumCtx(streamFn, resolveOllamaNumCtx(model));
390
+ }
391
+
392
+ const configuredThinkValue = model ? resolveOllamaThinkParamValue(model.params) : undefined;
393
+ const runtimeThinkValue = isNativeOllamaTransport
394
+ ? resolveOllamaThinkValue(ctx.thinkingLevel)
395
+ : undefined;
396
+ // "off" is also the implicit agent default. Preserve explicit native Ollama
397
+ // model config unless the active run requests a non-off thinking level.
398
+ const ollamaThinkValue =
399
+ runtimeThinkValue === false && configuredThinkValue !== undefined
400
+ ? undefined
401
+ : runtimeThinkValue;
402
+ if (ollamaThinkValue !== undefined && shouldForwardNativeOllamaThink(model, ollamaThinkValue)) {
403
+ streamFn = createOllamaThinkingWrapper(streamFn, ollamaThinkValue);
404
+ }
405
+
406
+ if (normalizeProviderId(ctx.provider) === "ollama" && isOllamaCloudKimiModelRef(ctx.modelId)) {
407
+ const thinkingType = resolveMoonshotThinkingType({
408
+ configuredThinking: ctx.extraParams?.thinking,
409
+ thinkingLevel: ctx.thinkingLevel,
410
+ });
411
+ streamFn = createMoonshotThinkingWrapper(streamFn, thinkingType);
412
+ }
413
+
414
+ return streamFn;
415
+ }
416
+
417
+ /** @deprecated Use createConfiguredOllamaCompatStreamWrapper. */
418
+ export const createConfiguredOllamaCompatNumCtxWrapper = createConfiguredOllamaCompatStreamWrapper;
419
+
420
+ export function buildOllamaChatRequest(params: {
421
+ modelId: string;
422
+ providerId?: string;
423
+ messages: OllamaChatMessage[];
424
+ tools?: OllamaTool[];
425
+ options?: Record<string, unknown>;
426
+ requestParams?: Record<string, unknown>;
427
+ stream?: boolean;
428
+ }): OllamaChatRequest {
429
+ return {
430
+ model: normalizeOllamaWireModelId(params.modelId, params.providerId),
431
+ messages: params.messages,
432
+ stream: params.stream ?? true,
433
+ ...(params.tools && params.tools.length > 0 ? { tools: params.tools } : {}),
434
+ ...(params.options ? { options: params.options } : {}),
435
+ ...params.requestParams,
436
+ };
437
+ }
438
+
439
+ type StreamModelDescriptor = {
440
+ api: string;
441
+ provider: string;
442
+ id: string;
443
+ };
444
+
445
+ type OllamaUsageFallback = {
446
+ input?: number;
447
+ output?: number;
448
+ };
449
+
450
+ const CHARS_PER_TOKEN_ESTIMATE = 4;
451
+
452
+ function buildUsageWithNoCost(params: {
453
+ input?: number;
454
+ output?: number;
455
+ cacheRead?: number;
456
+ cacheWrite?: number;
457
+ totalTokens?: number;
458
+ }): Usage {
459
+ const input = params.input ?? 0;
460
+ const output = params.output ?? 0;
461
+ const cacheRead = params.cacheRead ?? 0;
462
+ const cacheWrite = params.cacheWrite ?? 0;
463
+ return {
464
+ input,
465
+ output,
466
+ cacheRead,
467
+ cacheWrite,
468
+ totalTokens: params.totalTokens ?? input + output,
469
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
470
+ };
471
+ }
472
+
473
+ function buildStreamAssistantMessage(params: {
474
+ model: StreamModelDescriptor;
475
+ content: AssistantMessage["content"];
476
+ stopReason: StopReason;
477
+ usage: Usage;
478
+ timestamp?: number;
479
+ }): AssistantMessage {
480
+ return {
481
+ role: "assistant",
482
+ content: params.content,
483
+ stopReason: params.stopReason,
484
+ api: params.model.api,
485
+ provider: params.model.provider,
486
+ model: params.model.id,
487
+ usage: params.usage,
488
+ timestamp: params.timestamp ?? Date.now(),
489
+ };
490
+ }
491
+
492
+ function buildStreamErrorAssistantMessage(params: {
493
+ model: StreamModelDescriptor;
494
+ errorMessage: string;
495
+ timestamp?: number;
496
+ }): AssistantMessage & { stopReason: "error"; errorMessage: string } {
497
+ return {
498
+ ...buildStreamAssistantMessage({
499
+ model: params.model,
500
+ content: [],
501
+ stopReason: "error",
502
+ usage: buildUsageWithNoCost({}),
503
+ timestamp: params.timestamp,
504
+ }),
505
+ stopReason: "error",
506
+ errorMessage: params.errorMessage,
507
+ };
508
+ }
509
+
510
+ interface OllamaChatRequest {
511
+ model: string;
512
+ messages: OllamaChatMessage[];
513
+ stream: boolean;
514
+ tools?: OllamaTool[];
515
+ options?: Record<string, unknown>;
516
+ think?: OllamaThinkValue;
517
+ }
518
+
519
+ interface OllamaChatMessage {
520
+ role: "system" | "user" | "assistant" | "tool";
521
+ content: string;
522
+ images?: string[];
523
+ tool_calls?: OllamaToolCall[];
524
+ tool_name?: string;
525
+ }
526
+
527
+ interface OllamaTool {
528
+ type: "function";
529
+ function: {
530
+ name: string;
531
+ description: string;
532
+ parameters: Record<string, unknown>;
533
+ };
534
+ }
535
+
536
+ interface OllamaToolCall {
537
+ id?: string;
538
+ function: {
539
+ name: string;
540
+ arguments: Record<string, unknown> | string;
541
+ };
542
+ }
543
+
544
+ interface OllamaChatResponse {
545
+ model: string;
546
+ created_at: string;
547
+ message: {
548
+ role: "assistant";
549
+ content: string;
550
+ thinking?: string;
551
+ reasoning?: string;
552
+ tool_calls?: OllamaToolCall[];
553
+ };
554
+ done: boolean;
555
+ done_reason?: string;
556
+ total_duration?: number;
557
+ load_duration?: number;
558
+ prompt_eval_count?: number;
559
+ prompt_eval_duration?: number;
560
+ eval_count?: number;
561
+ eval_duration?: number;
562
+ }
563
+
564
+ function safeJsonLength(value: unknown): number {
565
+ try {
566
+ const serialized = JSON.stringify(value);
567
+ return typeof serialized === "string" ? serialized.length : 0;
568
+ } catch {
569
+ return 0;
570
+ }
571
+ }
572
+
573
+ function estimateTokensFromChars(chars: number): number {
574
+ if (!Number.isFinite(chars) || chars <= 0) {
575
+ return 0;
576
+ }
577
+ return Math.max(1, Math.round(chars / CHARS_PER_TOKEN_ESTIMATE));
578
+ }
579
+
580
+ function estimateOllamaPromptTokens(params: {
581
+ messages: OllamaChatMessage[];
582
+ tools: OllamaTool[];
583
+ }): number {
584
+ let chars = 0;
585
+ for (const message of params.messages) {
586
+ chars += message.content.length;
587
+ chars += safeJsonLength(message.images);
588
+ chars += safeJsonLength(message.tool_calls);
589
+ chars += message.tool_name?.length ?? 0;
590
+ }
591
+ chars += safeJsonLength(params.tools);
592
+ return estimateTokensFromChars(chars);
593
+ }
594
+
595
+ function estimateOllamaCompletionTokens(response: OllamaChatResponse): number {
596
+ const chars =
597
+ response.message.content.length +
598
+ (response.message.thinking?.length ?? 0) +
599
+ (response.message.reasoning?.length ?? 0) +
600
+ safeJsonLength(response.message.tool_calls);
601
+ return estimateTokensFromChars(chars);
602
+ }
603
+
604
+ function resolveUsageCount(value: number | undefined, fallback: number | undefined): number {
605
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
606
+ return value;
607
+ }
608
+ if (typeof fallback === "number" && Number.isFinite(fallback) && fallback > 0) {
609
+ return fallback;
610
+ }
611
+ return 0;
612
+ }
613
+
614
+ type InputContentPart =
615
+ | { type: "text"; text: string }
616
+ | { type: "image"; data: string }
617
+ | { type: "toolCall"; id: string; name: string; arguments: unknown }
618
+ | { type: "tool_use"; id: string; name: string; input: unknown };
619
+
620
+ function extractTextContent(content: unknown): string {
621
+ if (typeof content === "string") {
622
+ return content;
623
+ }
624
+ if (!Array.isArray(content)) {
625
+ return "";
626
+ }
627
+ return (content as InputContentPart[])
628
+ .filter((part): part is { type: "text"; text: string } => part.type === "text")
629
+ .map((part) => part.text)
630
+ .join("");
631
+ }
632
+
633
+ function extractOllamaImages(content: unknown): string[] {
634
+ if (!Array.isArray(content)) {
635
+ return [];
636
+ }
637
+ return (content as InputContentPart[])
638
+ .filter((part): part is { type: "image"; data: string } => part.type === "image")
639
+ .map((part) => part.data);
640
+ }
641
+
642
+ function ensureArgsObject(value: unknown): Record<string, unknown> {
643
+ return parseJsonObjectPreservingUnsafeIntegers(value) ?? {};
644
+ }
645
+
646
+ function normalizeOllamaToolCallArguments(value: unknown): Record<string, unknown> {
647
+ return ensureArgsObject(value);
648
+ }
649
+
650
+ function normalizeOllamaCompatMessageToolArgs(payloadRecord: Record<string, unknown>): void {
651
+ const messages = payloadRecord.messages;
652
+ if (!Array.isArray(messages)) {
653
+ return;
654
+ }
655
+
656
+ for (const message of messages) {
657
+ if (!message || typeof message !== "object" || Array.isArray(message)) {
658
+ continue;
659
+ }
660
+ const messageRecord = message as Record<string, unknown>;
661
+
662
+ const functionCall = messageRecord.function_call;
663
+ if (functionCall && typeof functionCall === "object" && !Array.isArray(functionCall)) {
664
+ const functionCallRecord = functionCall as Record<string, unknown>;
665
+ if (Object.hasOwn(functionCallRecord, "arguments")) {
666
+ functionCallRecord.arguments = ensureArgsObject(functionCallRecord.arguments);
667
+ }
668
+ }
669
+
670
+ const toolCalls = messageRecord.tool_calls;
671
+ if (!Array.isArray(toolCalls)) {
672
+ continue;
673
+ }
674
+ for (const toolCall of toolCalls) {
675
+ if (!toolCall || typeof toolCall !== "object" || Array.isArray(toolCall)) {
676
+ continue;
677
+ }
678
+ const functionSpec = (toolCall as Record<string, unknown>).function;
679
+ if (!functionSpec || typeof functionSpec !== "object" || Array.isArray(functionSpec)) {
680
+ continue;
681
+ }
682
+ const functionRecord = functionSpec as Record<string, unknown>;
683
+ if (Object.hasOwn(functionRecord, "arguments")) {
684
+ functionRecord.arguments = ensureArgsObject(functionRecord.arguments);
685
+ }
686
+ }
687
+ }
688
+ }
689
+
690
+ function isRecord(value: unknown): value is Record<string, unknown> {
691
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
692
+ }
693
+
694
+ function inferOllamaSchemaType(schema: Record<string, unknown>): string | undefined {
695
+ if (schema.properties && isRecord(schema.properties)) {
696
+ return "object";
697
+ }
698
+ if (schema.items) {
699
+ return "array";
700
+ }
701
+ if (Array.isArray(schema.enum) && schema.enum.length > 0) {
702
+ const values = schema.enum.filter((value) => value !== null);
703
+ if (values.length > 0 && values.every((value) => typeof value === "string")) {
704
+ return "string";
705
+ }
706
+ if (values.length > 0 && values.every((value) => typeof value === "number")) {
707
+ return "number";
708
+ }
709
+ if (values.length > 0 && values.every((value) => typeof value === "boolean")) {
710
+ return "boolean";
711
+ }
712
+ }
713
+ for (const unionKey of ["anyOf", "oneOf"] as const) {
714
+ const variants = schema[unionKey];
715
+ if (!Array.isArray(variants)) {
716
+ continue;
717
+ }
718
+ for (const variant of variants) {
719
+ if (!isRecord(variant)) {
720
+ continue;
721
+ }
722
+ const variantType = variant.type;
723
+ if (typeof variantType === "string" && variantType !== "null") {
724
+ return variantType;
725
+ }
726
+ if (Array.isArray(variantType)) {
727
+ const firstType = variantType.find(
728
+ (entry): entry is string => typeof entry === "string" && entry !== "null",
729
+ );
730
+ if (firstType) {
731
+ return firstType;
732
+ }
733
+ }
734
+ const inferred = inferOllamaSchemaType(variant);
735
+ if (inferred) {
736
+ return inferred;
737
+ }
738
+ }
739
+ }
740
+ return undefined;
741
+ }
742
+
743
+ function normalizeOllamaToolSchema(schema: unknown, isRoot = false): Record<string, unknown> {
744
+ if (!isRecord(schema)) {
745
+ return {
746
+ type: "object",
747
+ properties: {},
748
+ };
749
+ }
750
+
751
+ const normalized: Record<string, unknown> = {};
752
+ for (const [key, value] of Object.entries(schema)) {
753
+ if (key === "properties" && isRecord(value)) {
754
+ normalized.properties = Object.fromEntries(
755
+ Object.entries(value).map(([propertyName, propertySchema]) => [
756
+ propertyName,
757
+ normalizeOllamaToolSchema(propertySchema),
758
+ ]),
759
+ );
760
+ continue;
761
+ }
762
+ if (key === "items") {
763
+ normalized.items = Array.isArray(value)
764
+ ? value.map((entry) => normalizeOllamaToolSchema(entry))
765
+ : normalizeOllamaToolSchema(value);
766
+ continue;
767
+ }
768
+ if ((key === "anyOf" || key === "oneOf" || key === "allOf") && Array.isArray(value)) {
769
+ normalized[key] = value.map((entry) => normalizeOllamaToolSchema(entry));
770
+ continue;
771
+ }
772
+ normalized[key] = value;
773
+ }
774
+
775
+ const schemaType = normalized.type;
776
+ if (
777
+ typeof schemaType !== "string" &&
778
+ (!Array.isArray(schemaType) ||
779
+ !schemaType.some((entry) => typeof entry === "string" && entry !== "null"))
780
+ ) {
781
+ normalized.type = inferOllamaSchemaType(normalized) ?? (isRoot ? "object" : "string");
782
+ }
783
+ if (normalized.type === "object" && !isRecord(normalized.properties)) {
784
+ normalized.properties = {};
785
+ }
786
+ return normalized;
787
+ }
788
+
789
+ type OllamaToolCallNameOptions = {
790
+ availableToolNames?: ReadonlySet<string>;
791
+ };
792
+
793
+ function readOllamaToolCallId(value: unknown): string | undefined {
794
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
795
+ }
796
+
797
+ function extractToolCalls(
798
+ content: unknown,
799
+ options: OllamaToolCallNameOptions = {},
800
+ ): OllamaToolCall[] {
801
+ if (!Array.isArray(content)) {
802
+ return [];
803
+ }
804
+ const parts = content as InputContentPart[];
805
+ const result: OllamaToolCall[] = [];
806
+ for (const part of parts) {
807
+ if (part.type === "toolCall") {
808
+ const id = readOllamaToolCallId(part.id);
809
+ result.push({
810
+ ...(id ? { id } : {}),
811
+ function: {
812
+ name: normalizeOllamaToolCallName(part.name, options),
813
+ arguments: ensureArgsObject(part.arguments),
814
+ },
815
+ });
816
+ } else if (part.type === "tool_use") {
817
+ const id = readOllamaToolCallId(part.id);
818
+ result.push({
819
+ ...(id ? { id } : {}),
820
+ function: {
821
+ name: normalizeOllamaToolCallName(part.name, options),
822
+ arguments: ensureArgsObject(part.input),
823
+ },
824
+ });
825
+ }
826
+ }
827
+ return result;
828
+ }
829
+
830
+ function buildOllamaToolNameSet(tools: Tool[] | undefined): ReadonlySet<string> | undefined {
831
+ if (!tools || !Array.isArray(tools)) {
832
+ return undefined;
833
+ }
834
+ const names = new Set<string>();
835
+ for (const tool of tools) {
836
+ if (typeof tool.name === "string" && tool.name.trim()) {
837
+ names.add(tool.name.trim());
838
+ }
839
+ }
840
+ return names.size > 0 ? names : undefined;
841
+ }
842
+
843
+ function normalizeOllamaToolCallName(
844
+ rawName: string,
845
+ options: OllamaToolCallNameOptions = {},
846
+ ): string {
847
+ const trimmed = rawName.trim();
848
+ if (!trimmed) {
849
+ return trimmed;
850
+ }
851
+ const availableToolNames = options.availableToolNames;
852
+ if (availableToolNames?.has(trimmed)) {
853
+ return trimmed;
854
+ }
855
+
856
+ const strippedAnySeparator = trimmed.replace(/^(?:functions?|tools?)[./_-]+/iu, "").trim();
857
+ if (
858
+ availableToolNames &&
859
+ strippedAnySeparator !== trimmed &&
860
+ availableToolNames.has(strippedAnySeparator)
861
+ ) {
862
+ return strippedAnySeparator;
863
+ }
864
+ if (availableToolNames) {
865
+ return trimmed;
866
+ }
867
+
868
+ return trimmed.replace(/^(?:functions?|tools?)[./]+/iu, "").trim();
869
+ }
870
+
871
+ export function convertToOllamaMessages(
872
+ messages: Array<{ role: string; content: unknown }>,
873
+ system?: string,
874
+ options: OllamaToolCallNameOptions = {},
875
+ ): OllamaChatMessage[] {
876
+ const result: OllamaChatMessage[] = [];
877
+
878
+ if (system) {
879
+ result.push({ role: "system", content: system });
880
+ }
881
+
882
+ for (const msg of messages) {
883
+ if (msg.role === "user") {
884
+ const text = extractTextContent(msg.content);
885
+ const images = extractOllamaImages(msg.content);
886
+ result.push({
887
+ role: "user",
888
+ content: text,
889
+ ...(images.length > 0 ? { images } : {}),
890
+ });
891
+ continue;
892
+ }
893
+
894
+ if (msg.role === "assistant") {
895
+ const text = extractTextContent(msg.content);
896
+ const toolCalls = extractToolCalls(msg.content, options);
897
+ result.push({
898
+ role: "assistant",
899
+ content: text,
900
+ ...(toolCalls.length > 0 ? { tool_calls: toolCalls } : {}),
901
+ });
902
+ continue;
903
+ }
904
+
905
+ if (msg.role === "tool" || msg.role === "toolResult") {
906
+ const text = extractTextContent(msg.content);
907
+ const toolName =
908
+ typeof (msg as { toolName?: unknown }).toolName === "string"
909
+ ? (msg as { toolName?: string }).toolName
910
+ : undefined;
911
+ result.push({
912
+ role: "tool",
913
+ content: text,
914
+ ...(toolName ? { tool_name: toolName } : {}),
915
+ });
916
+ }
917
+ }
918
+
919
+ return result;
920
+ }
921
+
922
+ function extractOllamaTools(tools: Tool[] | undefined): OllamaTool[] {
923
+ if (!tools || !Array.isArray(tools)) {
924
+ return [];
925
+ }
926
+ const result: OllamaTool[] = [];
927
+ for (const tool of tools) {
928
+ if (typeof tool.name !== "string" || !tool.name) {
929
+ continue;
930
+ }
931
+ result.push({
932
+ type: "function",
933
+ function: {
934
+ name: tool.name,
935
+ description: typeof tool.description === "string" ? tool.description : "",
936
+ parameters: normalizeOllamaToolSchema(tool.parameters, true),
937
+ },
938
+ });
939
+ }
940
+ return result;
941
+ }
942
+
943
+ export function buildAssistantMessage(
944
+ response: OllamaChatResponse,
945
+ modelInfo: StreamModelDescriptor,
946
+ usageFallback?: OllamaUsageFallback,
947
+ options: OllamaToolCallNameOptions = {},
948
+ ): AssistantMessage {
949
+ const content: (TextContent | ThinkingContent | ToolCall)[] = [];
950
+ const thinking = response.message.thinking ?? response.message.reasoning ?? "";
951
+ if (thinking) {
952
+ content.push({ type: "thinking", thinking });
953
+ }
954
+ const text = response.message.content || "";
955
+ if (text) {
956
+ content.push({ type: "text", text });
957
+ }
958
+
959
+ const toolCalls = response.message.tool_calls;
960
+ if (toolCalls && toolCalls.length > 0) {
961
+ for (const toolCall of toolCalls) {
962
+ content.push({
963
+ type: "toolCall",
964
+ id: readOllamaToolCallId(toolCall.id) ?? `ollama_call_${randomUUID()}`,
965
+ name: normalizeOllamaToolCallName(toolCall.function.name, options),
966
+ arguments: normalizeOllamaToolCallArguments(toolCall.function.arguments),
967
+ });
968
+ }
969
+ }
970
+
971
+ return buildStreamAssistantMessage({
972
+ model: modelInfo,
973
+ content,
974
+ stopReason: toolCalls && toolCalls.length > 0 ? "toolUse" : "stop",
975
+ usage: buildUsageWithNoCost({
976
+ input: resolveUsageCount(response.prompt_eval_count, usageFallback?.input),
977
+ output: resolveUsageCount(response.eval_count, usageFallback?.output),
978
+ }),
979
+ });
980
+ }
981
+
982
+ export async function* parseNdjsonStream(
983
+ reader: ReadableStreamDefaultReader<Uint8Array>,
984
+ ): AsyncGenerator<OllamaChatResponse> {
985
+ const decoder = new TextDecoder();
986
+ let buffer = "";
987
+
988
+ while (true) {
989
+ const { done, value } = await reader.read();
990
+ if (done) {
991
+ break;
992
+ }
993
+ buffer += decoder.decode(value, { stream: true });
994
+ const lines = buffer.split("\n");
995
+ buffer = lines.pop() ?? "";
996
+
997
+ for (const line of lines) {
998
+ const trimmed = line.trim();
999
+ if (!trimmed) {
1000
+ continue;
1001
+ }
1002
+ try {
1003
+ yield parseJsonPreservingUnsafeIntegers(trimmed) as OllamaChatResponse;
1004
+ } catch {
1005
+ log.warn(`Skipping malformed NDJSON line: ${trimmed.slice(0, 120)}`);
1006
+ }
1007
+ }
1008
+ }
1009
+
1010
+ if (buffer.trim()) {
1011
+ try {
1012
+ yield parseJsonPreservingUnsafeIntegers(buffer.trim()) as OllamaChatResponse;
1013
+ } catch {
1014
+ log.warn(`Skipping malformed trailing data: ${buffer.trim().slice(0, 120)}`);
1015
+ }
1016
+ }
1017
+ }
1018
+
1019
+ function resolveOllamaChatUrl(baseUrl: string): string {
1020
+ const trimmed = baseUrl.trim().replace(/\/+$/, "");
1021
+ const normalizedBase = trimmed.replace(/\/v1$/i, "");
1022
+ return `${normalizedBase || OLLAMA_NATIVE_BASE_URL}/api/chat`;
1023
+ }
1024
+
1025
+ function resolveOllamaModelHeaders(model: {
1026
+ headers?: unknown;
1027
+ }): Record<string, string> | undefined {
1028
+ if (!model.headers || typeof model.headers !== "object" || Array.isArray(model.headers)) {
1029
+ return undefined;
1030
+ }
1031
+ return model.headers as Record<string, string>;
1032
+ }
1033
+
1034
+ function resolveOllamaRequestTimeoutMs(
1035
+ model: object,
1036
+ options: { requestTimeoutMs?: unknown; timeoutMs?: unknown } | undefined,
1037
+ ): number | undefined {
1038
+ const raw =
1039
+ options?.requestTimeoutMs ??
1040
+ options?.timeoutMs ??
1041
+ (model as { requestTimeoutMs?: unknown }).requestTimeoutMs;
1042
+ return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : undefined;
1043
+ }
1044
+
1045
+ export function createOllamaStreamFn(
1046
+ baseUrl: string,
1047
+ defaultHeaders?: Record<string, string>,
1048
+ ): StreamFn {
1049
+ const chatUrl = resolveOllamaChatUrl(baseUrl);
1050
+ const ssrfPolicy = buildOllamaBaseUrlSsrFPolicy(chatUrl);
1051
+
1052
+ return (model, context, options) => {
1053
+ const stream = createAssistantMessageEventStream();
1054
+
1055
+ const run = async () => {
1056
+ try {
1057
+ const availableToolNames = buildOllamaToolNameSet(context.tools);
1058
+ const toolCallNameOptions: OllamaToolCallNameOptions = availableToolNames
1059
+ ? { availableToolNames }
1060
+ : {};
1061
+ const ollamaMessages = convertToOllamaMessages(
1062
+ context.messages ?? [],
1063
+ context.systemPrompt,
1064
+ toolCallNameOptions,
1065
+ );
1066
+ const ollamaTools = extractOllamaTools(context.tools);
1067
+
1068
+ const ollamaOptions: Record<string, unknown> = resolveOllamaModelOptions(model);
1069
+ if (typeof options?.temperature === "number") {
1070
+ ollamaOptions.temperature = options.temperature;
1071
+ }
1072
+ if (typeof options?.maxTokens === "number") {
1073
+ ollamaOptions.num_predict = options.maxTokens;
1074
+ }
1075
+
1076
+ const body = buildOllamaChatRequest({
1077
+ modelId: model.id,
1078
+ providerId: model.provider,
1079
+ messages: ollamaMessages,
1080
+ stream: true,
1081
+ tools: ollamaTools,
1082
+ options: ollamaOptions,
1083
+ requestParams: resolveOllamaTopLevelParams(model),
1084
+ });
1085
+ options?.onPayload?.(body, model);
1086
+ const headers: Record<string, string> = {
1087
+ "Content-Type": "application/json",
1088
+ ...defaultHeaders,
1089
+ ...options?.headers,
1090
+ };
1091
+ if (
1092
+ options?.apiKey &&
1093
+ (!headers.Authorization || !isNonSecretApiKeyMarker(options.apiKey))
1094
+ ) {
1095
+ headers.Authorization = `Bearer ${options.apiKey}`;
1096
+ }
1097
+
1098
+ const { response, release } = await fetchWithSsrFGuard({
1099
+ url: chatUrl,
1100
+ init: {
1101
+ method: "POST",
1102
+ headers,
1103
+ body: JSON.stringify(body),
1104
+ },
1105
+ policy: ssrfPolicy,
1106
+ ...(options?.signal ? { signal: options.signal } : {}),
1107
+ timeoutMs: resolveOllamaRequestTimeoutMs(
1108
+ model,
1109
+ options as { requestTimeoutMs?: unknown; timeoutMs?: unknown } | undefined,
1110
+ ),
1111
+ auditContext: "ollama-stream.chat",
1112
+ });
1113
+
1114
+ try {
1115
+ if (!response.ok) {
1116
+ const errorText = await response.text().catch(() => "unknown error");
1117
+ throw new Error(`${response.status} ${errorText}`);
1118
+ }
1119
+ if (!response.body) {
1120
+ throw new Error("Ollama API returned empty response body");
1121
+ }
1122
+
1123
+ const reader = response.body.getReader();
1124
+ let accumulatedContent = "";
1125
+ let accumulatedThinking = "";
1126
+ const accumulatedToolCalls: OllamaToolCall[] = [];
1127
+ let finalResponse: OllamaChatResponse | undefined;
1128
+ const modelInfo = { api: model.api, provider: model.provider, id: model.id };
1129
+ let streamStarted = false;
1130
+ let thinkingStarted = false;
1131
+ let thinkingEnded = false;
1132
+ let textBlockStarted = false;
1133
+ let textBlockClosed = false;
1134
+ const textContentIndex = () => (thinkingStarted ? 1 : 0);
1135
+
1136
+ const buildCurrentContent = (): (TextContent | ThinkingContent | ToolCall)[] => {
1137
+ const parts: (TextContent | ThinkingContent | ToolCall)[] = [];
1138
+ if (accumulatedThinking) {
1139
+ parts.push({
1140
+ type: "thinking",
1141
+ thinking: accumulatedThinking,
1142
+ });
1143
+ }
1144
+ if (accumulatedContent) {
1145
+ parts.push({ type: "text", text: accumulatedContent });
1146
+ }
1147
+ return parts;
1148
+ };
1149
+
1150
+ const closeThinkingBlock = () => {
1151
+ if (!thinkingStarted || thinkingEnded) {
1152
+ return;
1153
+ }
1154
+ thinkingEnded = true;
1155
+ const partial = buildStreamAssistantMessage({
1156
+ model: modelInfo,
1157
+ content: buildCurrentContent(),
1158
+ stopReason: "stop",
1159
+ usage: buildUsageWithNoCost({}),
1160
+ });
1161
+ stream.push({
1162
+ type: "thinking_end",
1163
+ contentIndex: 0,
1164
+ content: accumulatedThinking,
1165
+ partial,
1166
+ });
1167
+ };
1168
+
1169
+ const closeTextBlock = () => {
1170
+ if (!textBlockStarted || textBlockClosed) {
1171
+ return;
1172
+ }
1173
+ textBlockClosed = true;
1174
+ const partial = buildStreamAssistantMessage({
1175
+ model: modelInfo,
1176
+ content: buildCurrentContent(),
1177
+ stopReason: "stop",
1178
+ usage: buildUsageWithNoCost({}),
1179
+ });
1180
+ stream.push({
1181
+ type: "text_end",
1182
+ contentIndex: textContentIndex(),
1183
+ content: accumulatedContent,
1184
+ partial,
1185
+ });
1186
+ };
1187
+
1188
+ for await (const chunk of parseNdjsonStream(reader)) {
1189
+ const thinkingDelta = chunk.message?.thinking ?? chunk.message?.reasoning;
1190
+ if (thinkingDelta) {
1191
+ if (!streamStarted) {
1192
+ streamStarted = true;
1193
+ const emptyPartial = buildStreamAssistantMessage({
1194
+ model: modelInfo,
1195
+ content: [],
1196
+ stopReason: "stop",
1197
+ usage: buildUsageWithNoCost({}),
1198
+ });
1199
+ stream.push({ type: "start", partial: emptyPartial });
1200
+ }
1201
+ if (!thinkingStarted) {
1202
+ thinkingStarted = true;
1203
+ const partial = buildStreamAssistantMessage({
1204
+ model: modelInfo,
1205
+ content: buildCurrentContent(),
1206
+ stopReason: "stop",
1207
+ usage: buildUsageWithNoCost({}),
1208
+ });
1209
+ stream.push({ type: "thinking_start", contentIndex: 0, partial });
1210
+ }
1211
+ accumulatedThinking += thinkingDelta;
1212
+ const partial = buildStreamAssistantMessage({
1213
+ model: modelInfo,
1214
+ content: buildCurrentContent(),
1215
+ stopReason: "stop",
1216
+ usage: buildUsageWithNoCost({}),
1217
+ });
1218
+ stream.push({
1219
+ type: "thinking_delta",
1220
+ contentIndex: 0,
1221
+ delta: thinkingDelta,
1222
+ partial,
1223
+ });
1224
+ }
1225
+
1226
+ if (chunk.message?.content) {
1227
+ const delta = chunk.message.content;
1228
+ if (thinkingStarted && !thinkingEnded) {
1229
+ closeThinkingBlock();
1230
+ }
1231
+
1232
+ if (!streamStarted) {
1233
+ streamStarted = true;
1234
+ const emptyPartial = buildStreamAssistantMessage({
1235
+ model: modelInfo,
1236
+ content: [],
1237
+ stopReason: "stop",
1238
+ usage: buildUsageWithNoCost({}),
1239
+ });
1240
+ stream.push({ type: "start", partial: emptyPartial });
1241
+ }
1242
+ if (!textBlockStarted) {
1243
+ textBlockStarted = true;
1244
+ const partial = buildStreamAssistantMessage({
1245
+ model: modelInfo,
1246
+ content: buildCurrentContent(),
1247
+ stopReason: "stop",
1248
+ usage: buildUsageWithNoCost({}),
1249
+ });
1250
+ stream.push({ type: "text_start", contentIndex: textContentIndex(), partial });
1251
+ }
1252
+
1253
+ accumulatedContent += delta;
1254
+ const partial = buildStreamAssistantMessage({
1255
+ model: modelInfo,
1256
+ content: buildCurrentContent(),
1257
+ stopReason: "stop",
1258
+ usage: buildUsageWithNoCost({}),
1259
+ });
1260
+ stream.push({
1261
+ type: "text_delta",
1262
+ contentIndex: textContentIndex(),
1263
+ delta,
1264
+ partial,
1265
+ });
1266
+ }
1267
+ if (chunk.message?.tool_calls) {
1268
+ closeThinkingBlock();
1269
+ closeTextBlock();
1270
+ accumulatedToolCalls.push(...chunk.message.tool_calls);
1271
+ }
1272
+ if (chunk.done) {
1273
+ finalResponse = chunk;
1274
+ break;
1275
+ }
1276
+ }
1277
+
1278
+ if (!finalResponse) {
1279
+ throw new Error("Ollama API stream ended without a final response");
1280
+ }
1281
+
1282
+ if (isLikelyGarbledVisibleText({ text: accumulatedContent, modelId: model.id })) {
1283
+ throw new Error(
1284
+ `Ollama returned non-linguistic garbled visible text for ${model.id}; retry or switch models`,
1285
+ );
1286
+ }
1287
+
1288
+ finalResponse.message.content = accumulatedContent;
1289
+ if (accumulatedThinking) {
1290
+ finalResponse.message.thinking = accumulatedThinking;
1291
+ }
1292
+ if (accumulatedToolCalls.length > 0) {
1293
+ finalResponse.message.tool_calls = accumulatedToolCalls;
1294
+ }
1295
+
1296
+ const usageFallback = {
1297
+ input: estimateOllamaPromptTokens({ messages: ollamaMessages, tools: ollamaTools }),
1298
+ output: estimateOllamaCompletionTokens(finalResponse),
1299
+ };
1300
+ const assistantMessage = buildAssistantMessage(
1301
+ finalResponse,
1302
+ modelInfo,
1303
+ usageFallback,
1304
+ toolCallNameOptions,
1305
+ );
1306
+ closeThinkingBlock();
1307
+ closeTextBlock();
1308
+
1309
+ stream.push({
1310
+ type: "done",
1311
+ reason: assistantMessage.stopReason === "toolUse" ? "toolUse" : "stop",
1312
+ message: assistantMessage,
1313
+ });
1314
+ } finally {
1315
+ await release();
1316
+ }
1317
+ } catch (err) {
1318
+ stream.push({
1319
+ type: "error",
1320
+ reason: "error",
1321
+ error: buildStreamErrorAssistantMessage({
1322
+ model,
1323
+ errorMessage: formatErrorMessage(err),
1324
+ }),
1325
+ });
1326
+ } finally {
1327
+ stream.end();
1328
+ }
1329
+ };
1330
+
1331
+ queueMicrotask(() => void run());
1332
+ return stream;
1333
+ };
1334
+ }
1335
+
1336
+ export function createConfiguredOllamaStreamFn(params: {
1337
+ model: { baseUrl?: string; headers?: unknown };
1338
+ providerBaseUrl?: string;
1339
+ }): StreamFn {
1340
+ return createOllamaStreamFn(
1341
+ resolveOllamaBaseUrlForRun({
1342
+ modelBaseUrl: readStringValue(params.model.baseUrl),
1343
+ providerBaseUrl: params.providerBaseUrl,
1344
+ }),
1345
+ resolveOllamaModelHeaders(params.model),
1346
+ );
1347
+ }