@mseep/clawdcursor 1.5.5

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 (354) hide show
  1. package/CHANGELOG.md +2264 -0
  2. package/LICENSE +21 -0
  3. package/README.md +385 -0
  4. package/SECURITY.md +44 -0
  5. package/SKILL.md +503 -0
  6. package/dist/core/agent-loop/agent.d.ts +42 -0
  7. package/dist/core/agent-loop/agent.js +1023 -0
  8. package/dist/core/agent-loop/agent.js.map +1 -0
  9. package/dist/core/agent-loop/batch-tool.d.ts +25 -0
  10. package/dist/core/agent-loop/batch-tool.js +218 -0
  11. package/dist/core/agent-loop/batch-tool.js.map +1 -0
  12. package/dist/core/agent-loop/coord-scale.d.ts +72 -0
  13. package/dist/core/agent-loop/coord-scale.js +89 -0
  14. package/dist/core/agent-loop/coord-scale.js.map +1 -0
  15. package/dist/core/agent-loop/focus-guard.d.ts +24 -0
  16. package/dist/core/agent-loop/focus-guard.js +29 -0
  17. package/dist/core/agent-loop/focus-guard.js.map +1 -0
  18. package/dist/core/agent-loop/project-mcp.d.ts +97 -0
  19. package/dist/core/agent-loop/project-mcp.js +253 -0
  20. package/dist/core/agent-loop/project-mcp.js.map +1 -0
  21. package/dist/core/agent-loop/prompt.d.ts +45 -0
  22. package/dist/core/agent-loop/prompt.js +426 -0
  23. package/dist/core/agent-loop/prompt.js.map +1 -0
  24. package/dist/core/agent-loop/tool-meta.d.ts +93 -0
  25. package/dist/core/agent-loop/tool-meta.js +651 -0
  26. package/dist/core/agent-loop/tool-meta.js.map +1 -0
  27. package/dist/core/agent-loop/tools.d.ts +38 -0
  28. package/dist/core/agent-loop/tools.js +2134 -0
  29. package/dist/core/agent-loop/tools.js.map +1 -0
  30. package/dist/core/agent-loop/types.d.ts +170 -0
  31. package/dist/core/agent-loop/types.js +12 -0
  32. package/dist/core/agent-loop/types.js.map +1 -0
  33. package/dist/core/agent.d.ts +51 -0
  34. package/dist/core/agent.js +245 -0
  35. package/dist/core/agent.js.map +1 -0
  36. package/dist/core/app-categories.d.ts +67 -0
  37. package/dist/core/app-categories.js +108 -0
  38. package/dist/core/app-categories.js.map +1 -0
  39. package/dist/core/banner.d.ts +70 -0
  40. package/dist/core/banner.js +245 -0
  41. package/dist/core/banner.js.map +1 -0
  42. package/dist/core/classify/capability.d.ts +45 -0
  43. package/dist/core/classify/capability.js +78 -0
  44. package/dist/core/classify/capability.js.map +1 -0
  45. package/dist/core/decompose/llm-decomposer.d.ts +35 -0
  46. package/dist/core/decompose/llm-decomposer.js +156 -0
  47. package/dist/core/decompose/llm-decomposer.js.map +1 -0
  48. package/dist/core/decompose/parser.d.ts +27 -0
  49. package/dist/core/decompose/parser.js +101 -0
  50. package/dist/core/decompose/parser.js.map +1 -0
  51. package/dist/core/observability/correlation.d.ts +19 -0
  52. package/dist/core/observability/correlation.js +36 -0
  53. package/dist/core/observability/correlation.js.map +1 -0
  54. package/dist/core/observability/cost-meter.d.ts +51 -0
  55. package/dist/core/observability/cost-meter.js +134 -0
  56. package/dist/core/observability/cost-meter.js.map +1 -0
  57. package/dist/core/observability/logger.d.ts +61 -0
  58. package/dist/core/observability/logger.js +550 -0
  59. package/dist/core/observability/logger.js.map +1 -0
  60. package/dist/core/router/aliases.d.ts +50 -0
  61. package/dist/core/router/aliases.js +104 -0
  62. package/dist/core/router/aliases.js.map +1 -0
  63. package/dist/core/router/normalize.d.ts +41 -0
  64. package/dist/core/router/normalize.js +80 -0
  65. package/dist/core/router/normalize.js.map +1 -0
  66. package/dist/core/safety.d.ts +126 -0
  67. package/dist/core/safety.js +568 -0
  68. package/dist/core/safety.js.map +1 -0
  69. package/dist/core/sense/a11y-resolver.d.ts +73 -0
  70. package/dist/core/sense/a11y-resolver.js +76 -0
  71. package/dist/core/sense/a11y-resolver.js.map +1 -0
  72. package/dist/core/sense/fingerprint.d.ts +41 -0
  73. package/dist/core/sense/fingerprint.js +123 -0
  74. package/dist/core/sense/fingerprint.js.map +1 -0
  75. package/dist/core/sense/rank.d.ts +70 -0
  76. package/dist/core/sense/rank.js +192 -0
  77. package/dist/core/sense/rank.js.map +1 -0
  78. package/dist/core/sense/reactive-check.d.ts +40 -0
  79. package/dist/core/sense/reactive-check.js +48 -0
  80. package/dist/core/sense/reactive-check.js.map +1 -0
  81. package/dist/core/sense/snapshot.d.ts +19 -0
  82. package/dist/core/sense/snapshot.js +100 -0
  83. package/dist/core/sense/snapshot.js.map +1 -0
  84. package/dist/core/sense/types.d.ts +66 -0
  85. package/dist/core/sense/types.js +9 -0
  86. package/dist/core/sense/types.js.map +1 -0
  87. package/dist/core/sense/ui-map-anchors.d.ts +7 -0
  88. package/dist/core/sense/ui-map-anchors.js +24 -0
  89. package/dist/core/sense/ui-map-anchors.js.map +1 -0
  90. package/dist/core/sense/ui-map-elements.d.ts +5 -0
  91. package/dist/core/sense/ui-map-elements.js +33 -0
  92. package/dist/core/sense/ui-map-elements.js.map +1 -0
  93. package/dist/core/sense/ui-map-find.d.ts +56 -0
  94. package/dist/core/sense/ui-map-find.js +153 -0
  95. package/dist/core/sense/ui-map-find.js.map +1 -0
  96. package/dist/core/sense/ui-map-fuse.d.ts +4 -0
  97. package/dist/core/sense/ui-map-fuse.js +44 -0
  98. package/dist/core/sense/ui-map-fuse.js.map +1 -0
  99. package/dist/core/sense/ui-map-geom.d.ts +3 -0
  100. package/dist/core/sense/ui-map-geom.js +16 -0
  101. package/dist/core/sense/ui-map-geom.js.map +1 -0
  102. package/dist/core/sense/ui-map-holder.d.ts +58 -0
  103. package/dist/core/sense/ui-map-holder.js +87 -0
  104. package/dist/core/sense/ui-map-holder.js.map +1 -0
  105. package/dist/core/sense/ui-map-normalize.d.ts +19 -0
  106. package/dist/core/sense/ui-map-normalize.js +65 -0
  107. package/dist/core/sense/ui-map-normalize.js.map +1 -0
  108. package/dist/core/sense/ui-map-render.d.ts +4 -0
  109. package/dist/core/sense/ui-map-render.js +34 -0
  110. package/dist/core/sense/ui-map-render.js.map +1 -0
  111. package/dist/core/sense/ui-map-resolve.d.ts +41 -0
  112. package/dist/core/sense/ui-map-resolve.js +59 -0
  113. package/dist/core/sense/ui-map-resolve.js.map +1 -0
  114. package/dist/core/sense/ui-map-types.d.ts +66 -0
  115. package/dist/core/sense/ui-map-types.js +11 -0
  116. package/dist/core/sense/ui-map-types.js.map +1 -0
  117. package/dist/core/sense/ui-map.d.ts +29 -0
  118. package/dist/core/sense/ui-map.js +113 -0
  119. package/dist/core/sense/ui-map.js.map +1 -0
  120. package/dist/core/verify/assertions.d.ts +132 -0
  121. package/dist/core/verify/assertions.js +284 -0
  122. package/dist/core/verify/assertions.js.map +1 -0
  123. package/dist/index.d.ts +21 -0
  124. package/dist/index.js +24 -0
  125. package/dist/index.js.map +1 -0
  126. package/dist/llm/browser-config.d.ts +36 -0
  127. package/dist/llm/browser-config.js +83 -0
  128. package/dist/llm/browser-config.js.map +1 -0
  129. package/dist/llm/client.d.ts +268 -0
  130. package/dist/llm/client.js +1094 -0
  131. package/dist/llm/client.js.map +1 -0
  132. package/dist/llm/config.d.ts +79 -0
  133. package/dist/llm/config.js +375 -0
  134. package/dist/llm/config.js.map +1 -0
  135. package/dist/llm/credentials.d.ts +35 -0
  136. package/dist/llm/credentials.js +491 -0
  137. package/dist/llm/credentials.js.map +1 -0
  138. package/dist/llm/external-creds.d.ts +42 -0
  139. package/dist/llm/external-creds.js +169 -0
  140. package/dist/llm/external-creds.js.map +1 -0
  141. package/dist/llm/providers.d.ts +123 -0
  142. package/dist/llm/providers.js +717 -0
  143. package/dist/llm/providers.js.map +1 -0
  144. package/dist/paths.d.ts +31 -0
  145. package/dist/paths.js +147 -0
  146. package/dist/paths.js.map +1 -0
  147. package/dist/platform/accessibility.d.ts +139 -0
  148. package/dist/platform/accessibility.js +670 -0
  149. package/dist/platform/accessibility.js.map +1 -0
  150. package/dist/platform/cdp-driver.d.ts +318 -0
  151. package/dist/platform/cdp-driver.js +1179 -0
  152. package/dist/platform/cdp-driver.js.map +1 -0
  153. package/dist/platform/index.d.ts +11 -0
  154. package/dist/platform/index.js +69 -0
  155. package/dist/platform/index.js.map +1 -0
  156. package/dist/platform/keys.d.ts +17 -0
  157. package/dist/platform/keys.js +129 -0
  158. package/dist/platform/keys.js.map +1 -0
  159. package/dist/platform/launch-poll.d.ts +101 -0
  160. package/dist/platform/launch-poll.js +177 -0
  161. package/dist/platform/launch-poll.js.map +1 -0
  162. package/dist/platform/linux.d.ts +173 -0
  163. package/dist/platform/linux.js +1253 -0
  164. package/dist/platform/linux.js.map +1 -0
  165. package/dist/platform/macos.d.ts +136 -0
  166. package/dist/platform/macos.js +976 -0
  167. package/dist/platform/macos.js.map +1 -0
  168. package/dist/platform/native-desktop.d.ts +145 -0
  169. package/dist/platform/native-desktop.js +936 -0
  170. package/dist/platform/native-desktop.js.map +1 -0
  171. package/dist/platform/native-helper.d.ts +130 -0
  172. package/dist/platform/native-helper.js +592 -0
  173. package/dist/platform/native-helper.js.map +1 -0
  174. package/dist/platform/ocr-engine.d.ts +78 -0
  175. package/dist/platform/ocr-engine.js +363 -0
  176. package/dist/platform/ocr-engine.js.map +1 -0
  177. package/dist/platform/ps-runner.d.ts +28 -0
  178. package/dist/platform/ps-runner.js +228 -0
  179. package/dist/platform/ps-runner.js.map +1 -0
  180. package/dist/platform/types.d.ts +397 -0
  181. package/dist/platform/types.js +15 -0
  182. package/dist/platform/types.js.map +1 -0
  183. package/dist/platform/uri-handler.d.ts +75 -0
  184. package/dist/platform/uri-handler.js +273 -0
  185. package/dist/platform/uri-handler.js.map +1 -0
  186. package/dist/platform/wayland-backend.d.ts +53 -0
  187. package/dist/platform/wayland-backend.js +348 -0
  188. package/dist/platform/wayland-backend.js.map +1 -0
  189. package/dist/platform/windows.d.ts +232 -0
  190. package/dist/platform/windows.js +1210 -0
  191. package/dist/platform/windows.js.map +1 -0
  192. package/dist/postbuild.d.ts +10 -0
  193. package/dist/postbuild.js +98 -0
  194. package/dist/postbuild.js.map +1 -0
  195. package/dist/schema/snapshot.d.ts +33 -0
  196. package/dist/schema/snapshot.js +90 -0
  197. package/dist/schema/snapshot.js.map +1 -0
  198. package/dist/shortcuts.d.ts +30 -0
  199. package/dist/shortcuts.js +261 -0
  200. package/dist/shortcuts.js.map +1 -0
  201. package/dist/surface/cli.d.ts +7 -0
  202. package/dist/surface/cli.js +1556 -0
  203. package/dist/surface/cli.js.map +1 -0
  204. package/dist/surface/dashboard.d.ts +8 -0
  205. package/dist/surface/dashboard.js +1193 -0
  206. package/dist/surface/dashboard.js.map +1 -0
  207. package/dist/surface/doctor.d.ts +29 -0
  208. package/dist/surface/doctor.js +1514 -0
  209. package/dist/surface/doctor.js.map +1 -0
  210. package/dist/surface/format.d.ts +10 -0
  211. package/dist/surface/format.js +37 -0
  212. package/dist/surface/format.js.map +1 -0
  213. package/dist/surface/http-utility.d.ts +65 -0
  214. package/dist/surface/http-utility.js +336 -0
  215. package/dist/surface/http-utility.js.map +1 -0
  216. package/dist/surface/mcp-server.d.ts +91 -0
  217. package/dist/surface/mcp-server.js +280 -0
  218. package/dist/surface/mcp-server.js.map +1 -0
  219. package/dist/surface/onboarding.d.ts +15 -0
  220. package/dist/surface/onboarding.js +184 -0
  221. package/dist/surface/onboarding.js.map +1 -0
  222. package/dist/surface/pidfile.d.ts +79 -0
  223. package/dist/surface/pidfile.js +263 -0
  224. package/dist/surface/pidfile.js.map +1 -0
  225. package/dist/surface/readiness.d.ts +45 -0
  226. package/dist/surface/readiness.js +230 -0
  227. package/dist/surface/readiness.js.map +1 -0
  228. package/dist/surface/report.d.ts +68 -0
  229. package/dist/surface/report.js +341 -0
  230. package/dist/surface/report.js.map +1 -0
  231. package/dist/surface/skill-register.d.ts +14 -0
  232. package/dist/surface/skill-register.js +150 -0
  233. package/dist/surface/skill-register.js.map +1 -0
  234. package/dist/surface/version.d.ts +6 -0
  235. package/dist/surface/version.js +27 -0
  236. package/dist/surface/version.js.map +1 -0
  237. package/dist/tools/a11y.d.ts +8 -0
  238. package/dist/tools/a11y.js +545 -0
  239. package/dist/tools/a11y.js.map +1 -0
  240. package/dist/tools/a11y_depth.d.ts +19 -0
  241. package/dist/tools/a11y_depth.js +455 -0
  242. package/dist/tools/a11y_depth.js.map +1 -0
  243. package/dist/tools/agent.d.ts +15 -0
  244. package/dist/tools/agent.js +248 -0
  245. package/dist/tools/agent.js.map +1 -0
  246. package/dist/tools/batch.d.ts +46 -0
  247. package/dist/tools/batch.js +230 -0
  248. package/dist/tools/batch.js.map +1 -0
  249. package/dist/tools/cdp.d.ts +8 -0
  250. package/dist/tools/cdp.js +233 -0
  251. package/dist/tools/cdp.js.map +1 -0
  252. package/dist/tools/compact.d.ts +63 -0
  253. package/dist/tools/compact.js +418 -0
  254. package/dist/tools/compact.js.map +1 -0
  255. package/dist/tools/cost-class.d.ts +38 -0
  256. package/dist/tools/cost-class.js +117 -0
  257. package/dist/tools/cost-class.js.map +1 -0
  258. package/dist/tools/desktop.d.ts +9 -0
  259. package/dist/tools/desktop.js +346 -0
  260. package/dist/tools/desktop.js.map +1 -0
  261. package/dist/tools/electron_bridge.d.ts +41 -0
  262. package/dist/tools/electron_bridge.js +261 -0
  263. package/dist/tools/electron_bridge.js.map +1 -0
  264. package/dist/tools/extras.d.ts +22 -0
  265. package/dist/tools/extras.js +942 -0
  266. package/dist/tools/extras.js.map +1 -0
  267. package/dist/tools/favorites.d.ts +13 -0
  268. package/dist/tools/favorites.js +137 -0
  269. package/dist/tools/favorites.js.map +1 -0
  270. package/dist/tools/introspection.d.ts +13 -0
  271. package/dist/tools/introspection.js +55 -0
  272. package/dist/tools/introspection.js.map +1 -0
  273. package/dist/tools/ocr.d.ts +8 -0
  274. package/dist/tools/ocr.js +66 -0
  275. package/dist/tools/ocr.js.map +1 -0
  276. package/dist/tools/orchestration.d.ts +7 -0
  277. package/dist/tools/orchestration.js +377 -0
  278. package/dist/tools/orchestration.js.map +1 -0
  279. package/dist/tools/playbooks/extract-compose.d.ts +22 -0
  280. package/dist/tools/playbooks/extract-compose.js +85 -0
  281. package/dist/tools/playbooks/extract-compose.js.map +1 -0
  282. package/dist/tools/playbooks/find-replace.d.ts +11 -0
  283. package/dist/tools/playbooks/find-replace.js +56 -0
  284. package/dist/tools/playbooks/find-replace.js.map +1 -0
  285. package/dist/tools/playbooks/index.d.ts +63 -0
  286. package/dist/tools/playbooks/index.js +70 -0
  287. package/dist/tools/playbooks/index.js.map +1 -0
  288. package/dist/tools/playbooks/keys-blocklist.d.ts +24 -0
  289. package/dist/tools/playbooks/keys-blocklist.js +89 -0
  290. package/dist/tools/playbooks/keys-blocklist.js.map +1 -0
  291. package/dist/tools/registry.d.ts +40 -0
  292. package/dist/tools/registry.js +560 -0
  293. package/dist/tools/registry.js.map +1 -0
  294. package/dist/tools/safety-gate.d.ts +16 -0
  295. package/dist/tools/safety-gate.js +70 -0
  296. package/dist/tools/safety-gate.js.map +1 -0
  297. package/dist/tools/scheduler.d.ts +76 -0
  298. package/dist/tools/scheduler.js +413 -0
  299. package/dist/tools/scheduler.js.map +1 -0
  300. package/dist/tools/shortcuts.d.ts +13 -0
  301. package/dist/tools/shortcuts.js +205 -0
  302. package/dist/tools/shortcuts.js.map +1 -0
  303. package/dist/tools/smart.d.ts +15 -0
  304. package/dist/tools/smart.js +785 -0
  305. package/dist/tools/smart.js.map +1 -0
  306. package/dist/tools/types.d.ts +174 -0
  307. package/dist/tools/types.js +67 -0
  308. package/dist/tools/types.js.map +1 -0
  309. package/dist/tools/window-text.d.ts +15 -0
  310. package/dist/tools/window-text.js +39 -0
  311. package/dist/tools/window-text.js.map +1 -0
  312. package/dist/types.d.ts +122 -0
  313. package/dist/types.js +41 -0
  314. package/dist/types.js.map +1 -0
  315. package/native/Package.swift +38 -0
  316. package/native/README.md +113 -0
  317. package/native/Sources/ClawdCursorHelper/main.swift +602 -0
  318. package/native/Sources/ClawdCursorHost/main.swift +182 -0
  319. package/native/Sources/PermissionCheck/main.swift +53 -0
  320. package/native/Sources/ScreenshotHelper/main.swift +219 -0
  321. package/native/build.sh +139 -0
  322. package/native/entitlements.plist +12 -0
  323. package/package.json +115 -0
  324. package/scripts/banner.ps1 +112 -0
  325. package/scripts/coord-accuracy.ps1 +140 -0
  326. package/scripts/coord-uwp.ps1 +80 -0
  327. package/scripts/edge-glow.ps1 +180 -0
  328. package/scripts/find-element.ps1 +198 -0
  329. package/scripts/get-foreground-window.ps1 +71 -0
  330. package/scripts/get-screen-context.ps1 +183 -0
  331. package/scripts/get-windows.ps1 +66 -0
  332. package/scripts/install-panic-hotkey.ps1 +46 -0
  333. package/scripts/interact-element.ps1 +431 -0
  334. package/scripts/invoke-element.ps1 +314 -0
  335. package/scripts/linux/atspi-bridge.py +356 -0
  336. package/scripts/linux/ocr-recognize.py +154 -0
  337. package/scripts/mac/_window-picker.jxa +163 -0
  338. package/scripts/mac/find-element.jxa +0 -0
  339. package/scripts/mac/find-element.sh +161 -0
  340. package/scripts/mac/focus-window.jxa +284 -0
  341. package/scripts/mac/get-focused-element.jxa +102 -0
  342. package/scripts/mac/get-foreground-window.jxa +173 -0
  343. package/scripts/mac/get-screen-context.jxa +197 -0
  344. package/scripts/mac/get-ui-tree.sh +141 -0
  345. package/scripts/mac/get-windows.jxa +117 -0
  346. package/scripts/mac/interact-element.sh +235 -0
  347. package/scripts/mac/invoke-element.jxa +408 -0
  348. package/scripts/mac/ocr-recognize.swift +124 -0
  349. package/scripts/ocr-recognize.ps1 +102 -0
  350. package/scripts/postinstall-native.js +48 -0
  351. package/scripts/ps-bridge.ps1 +830 -0
  352. package/scripts/smoke-mcp.ps1 +119 -0
  353. package/scripts/sync-version.ts +178 -0
  354. package/scripts/verify-install.js +81 -0
@@ -0,0 +1,717 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.PROVIDER_ENV_VARS = exports.PROVIDERS = exports.MIN_RECOMMENDED_CONTEXT = void 0;
37
+ exports.detectProvider = detectProvider;
38
+ exports.buildPipeline = buildPipeline;
39
+ exports.supportsOpenAiJsonMode = supportsOpenAiJsonMode;
40
+ exports.supportsOpenAiToolCalls = supportsOpenAiToolCalls;
41
+ exports.scanProviders = scanProviders;
42
+ exports.buildMixedPipeline = buildMixedPipeline;
43
+ const credentials_1 = require("./credentials");
44
+ /** Minimum context window in tokens for reliable desktop automation.
45
+ * Models below this cannot handle web pages (200+ elements). */
46
+ exports.MIN_RECOMMENDED_CONTEXT = 16000;
47
+ exports.PROVIDERS = {
48
+ anthropic: {
49
+ name: 'Anthropic',
50
+ baseUrl: 'https://api.anthropic.com/v1',
51
+ authHeader: (key) => ({
52
+ 'x-api-key': key,
53
+ 'anthropic-version': '2023-06-01',
54
+ }),
55
+ textModel: 'claude-haiku-4-5',
56
+ visionModel: 'claude-sonnet-4-20250514',
57
+ textContextWindow: 200000,
58
+ openaiCompat: false,
59
+ computerUse: true,
60
+ supportsJsonMode: false,
61
+ supportsToolCalls: false,
62
+ },
63
+ openai: {
64
+ name: 'OpenAI',
65
+ baseUrl: 'https://api.openai.com/v1',
66
+ authHeader: (key) => ({ 'Authorization': `Bearer ${key}` }),
67
+ textModel: 'gpt-4o-mini',
68
+ visionModel: 'gpt-4o',
69
+ textContextWindow: 128000,
70
+ openaiCompat: true,
71
+ computerUse: false,
72
+ supportsJsonMode: true,
73
+ supportsToolCalls: true,
74
+ },
75
+ ollama: {
76
+ name: 'Ollama (Local)',
77
+ baseUrl: 'http://localhost:11434/v1',
78
+ authHeader: () => ({}),
79
+ textModel: '',
80
+ visionModel: '',
81
+ textContextWindow: 32000, // varies by model, conservative default
82
+ openaiCompat: true,
83
+ computerUse: false,
84
+ supportsJsonMode: true,
85
+ supportsToolCalls: true,
86
+ },
87
+ kimi: {
88
+ name: 'Kimi (Moonshot)',
89
+ baseUrl: 'https://api.moonshot.ai/v1',
90
+ authHeader: (key) => ({ 'Authorization': `Bearer ${key}` }),
91
+ textModel: 'moonshot-v1-32k',
92
+ visionModel: 'kimi-k2.5',
93
+ textContextWindow: 32000,
94
+ openaiCompat: true,
95
+ computerUse: false,
96
+ supportsJsonMode: true,
97
+ supportsToolCalls: true,
98
+ reasoningVisionModel: true,
99
+ },
100
+ groq: {
101
+ name: 'Groq',
102
+ baseUrl: 'https://api.groq.com/openai/v1',
103
+ authHeader: (key) => ({ 'Authorization': `Bearer ${key}` }),
104
+ textModel: 'llama-3.3-70b-versatile',
105
+ visionModel: 'llama-3.2-90b-vision-preview',
106
+ textContextWindow: 128000,
107
+ openaiCompat: true,
108
+ computerUse: false,
109
+ supportsJsonMode: true,
110
+ supportsToolCalls: true,
111
+ },
112
+ together: {
113
+ name: 'Together AI',
114
+ baseUrl: 'https://api.together.xyz/v1',
115
+ authHeader: (key) => ({ 'Authorization': `Bearer ${key}` }),
116
+ textModel: 'meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo',
117
+ visionModel: 'meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo',
118
+ textContextWindow: 128000,
119
+ openaiCompat: true,
120
+ computerUse: false,
121
+ supportsJsonMode: true,
122
+ supportsToolCalls: true,
123
+ },
124
+ deepseek: {
125
+ name: 'DeepSeek',
126
+ baseUrl: 'https://api.deepseek.com/v1',
127
+ authHeader: (key) => ({ 'Authorization': `Bearer ${key}` }),
128
+ textModel: 'deepseek-chat',
129
+ visionModel: 'deepseek-chat',
130
+ textContextWindow: 64000,
131
+ openaiCompat: true,
132
+ computerUse: false,
133
+ supportsJsonMode: true,
134
+ supportsToolCalls: true,
135
+ },
136
+ gemini: {
137
+ name: 'Google (Gemini)',
138
+ baseUrl: 'https://generativelanguage.googleapis.com/v1beta/openai',
139
+ authHeader: (key) => ({ 'Authorization': `Bearer ${key}` }),
140
+ textModel: 'gemini-2.5-flash',
141
+ visionModel: 'gemini-2.5-flash',
142
+ textContextWindow: 1000000,
143
+ openaiCompat: true,
144
+ computerUse: false,
145
+ supportsJsonMode: true,
146
+ supportsToolCalls: true,
147
+ },
148
+ mistral: {
149
+ name: 'Mistral AI',
150
+ baseUrl: 'https://api.mistral.ai/v1',
151
+ authHeader: (key) => ({ 'Authorization': `Bearer ${key}` }),
152
+ textModel: 'mistral-small-latest',
153
+ visionModel: 'pixtral-large-latest',
154
+ textContextWindow: 32000,
155
+ openaiCompat: true,
156
+ computerUse: false,
157
+ supportsJsonMode: true,
158
+ supportsToolCalls: true,
159
+ },
160
+ xai: {
161
+ name: 'xAI (Grok)',
162
+ baseUrl: 'https://api.x.ai/v1',
163
+ authHeader: (key) => ({ 'Authorization': `Bearer ${key}` }),
164
+ textModel: 'grok-3-mini',
165
+ visionModel: 'grok-2-vision-1212',
166
+ textContextWindow: 131072,
167
+ openaiCompat: true,
168
+ computerUse: false,
169
+ supportsJsonMode: true,
170
+ supportsToolCalls: true,
171
+ },
172
+ alibaba: {
173
+ name: 'Alibaba (Qwen/DashScope)',
174
+ baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
175
+ authHeader: (key) => ({ 'Authorization': `Bearer ${key}` }),
176
+ textModel: 'qwen-turbo',
177
+ visionModel: 'qwen-vl-max',
178
+ textContextWindow: 128000,
179
+ openaiCompat: true,
180
+ computerUse: false,
181
+ supportsJsonMode: true,
182
+ supportsToolCalls: true,
183
+ },
184
+ fireworks: {
185
+ name: 'Fireworks AI',
186
+ baseUrl: 'https://api.fireworks.ai/inference/v1',
187
+ authHeader: (key) => ({ 'Authorization': `Bearer ${key}` }),
188
+ textModel: 'accounts/fireworks/models/llama-v3p1-70b-instruct',
189
+ visionModel: 'accounts/fireworks/models/llama-v3p2-90b-vision-instruct',
190
+ textContextWindow: 128000,
191
+ openaiCompat: true,
192
+ computerUse: false,
193
+ supportsJsonMode: true,
194
+ supportsToolCalls: true,
195
+ },
196
+ cohere: {
197
+ name: 'Cohere',
198
+ baseUrl: 'https://api.cohere.com/v2',
199
+ authHeader: (key) => ({ 'Authorization': `Bearer ${key}` }),
200
+ textModel: 'command-r',
201
+ visionModel: 'command-r-plus',
202
+ textContextWindow: 128000,
203
+ openaiCompat: true,
204
+ computerUse: false,
205
+ supportsJsonMode: false,
206
+ supportsToolCalls: false,
207
+ },
208
+ perplexity: {
209
+ name: 'Perplexity',
210
+ baseUrl: 'https://api.perplexity.ai',
211
+ authHeader: (key) => ({ 'Authorization': `Bearer ${key}` }),
212
+ textModel: 'llama-3.1-sonar-small-128k-online',
213
+ visionModel: 'llama-3.1-sonar-large-128k-online',
214
+ textContextWindow: 128000,
215
+ openaiCompat: true,
216
+ computerUse: false,
217
+ supportsJsonMode: false,
218
+ supportsToolCalls: false,
219
+ },
220
+ generic: {
221
+ name: 'OpenAI-Compatible',
222
+ baseUrl: '',
223
+ authHeader: (key) => ({ 'Authorization': `Bearer ${key}` }),
224
+ textModel: '',
225
+ visionModel: '',
226
+ openaiCompat: true,
227
+ computerUse: false,
228
+ supportsJsonMode: true,
229
+ supportsToolCalls: true,
230
+ },
231
+ };
232
+ /**
233
+ * Auto-detect provider from API key format or explicit provider name.
234
+ */
235
+ function detectProvider(apiKey, explicitProvider) {
236
+ if (explicitProvider) {
237
+ // Accept ANY provider name — if it's in PROVIDERS use it, otherwise treat as generic
238
+ if (exports.PROVIDERS[explicitProvider])
239
+ return explicitProvider;
240
+ return 'generic';
241
+ }
242
+ if (!apiKey)
243
+ return 'ollama'; // No key = local mode
244
+ if (apiKey.startsWith('sk-ant-'))
245
+ return 'anthropic';
246
+ if (apiKey.startsWith('AIza'))
247
+ return 'gemini'; // Google Gemini API keys start with AIza
248
+ if (apiKey.startsWith('xai-'))
249
+ return 'xai'; // xAI Grok
250
+ if (apiKey.startsWith('pplx-'))
251
+ return 'perplexity'; // Perplexity
252
+ if (apiKey.startsWith('fw_'))
253
+ return 'fireworks'; // Fireworks AI
254
+ if (apiKey.startsWith('sk-') && apiKey.length > 60)
255
+ return 'kimi'; // Kimi keys are longer than OpenAI
256
+ if (apiKey.startsWith('sk-'))
257
+ return 'openai';
258
+ if (apiKey.startsWith('gsk_'))
259
+ return 'groq';
260
+ return 'openai'; // Default fallback — most providers use OpenAI-compatible API
261
+ }
262
+ /**
263
+ * Build the optimal pipeline config from test results.
264
+ */
265
+ function buildPipeline(providerKey, apiKey, textModelWorks, visionModelWorks, textModelOverride, visionModelOverride) {
266
+ const provider = exports.PROVIDERS[providerKey] || exports.PROVIDERS['ollama'];
267
+ return {
268
+ provider,
269
+ providerKey,
270
+ apiKey,
271
+ layer1: true,
272
+ layer2: {
273
+ enabled: textModelWorks,
274
+ model: textModelOverride || provider.textModel,
275
+ baseUrl: provider.baseUrl,
276
+ },
277
+ layer3: {
278
+ enabled: visionModelWorks,
279
+ model: visionModelOverride || provider.visionModel,
280
+ baseUrl: provider.baseUrl,
281
+ computerUse: provider.computerUse,
282
+ },
283
+ };
284
+ }
285
+ function supportsOpenAiJsonMode(provider) {
286
+ return provider?.supportsJsonMode !== false;
287
+ }
288
+ function supportsOpenAiToolCalls(provider) {
289
+ return provider?.supportsToolCalls !== false;
290
+ }
291
+ // ─── Multi-Provider Scanning ──────────────────────────────────────
292
+ /** Well-known vision-capable Ollama model name prefixes */
293
+ const OLLAMA_VISION_PREFIXES = [
294
+ 'llava', 'bakllava', 'llava-llama3', 'llava-phi3', 'moondream',
295
+ 'minicpm-v', 'cogvlm', 'yi-vl', 'obsidian',
296
+ ];
297
+ /**
298
+ * Mask an API key for display: show first 8 chars + "..."
299
+ */
300
+ function maskKey(key) {
301
+ if (key.length <= 12)
302
+ return key.substring(0, 4) + '...';
303
+ return key.substring(0, 8) + '...';
304
+ }
305
+ /**
306
+ * Check if an Ollama model name is likely vision-capable.
307
+ */
308
+ function isOllamaVisionModel(modelId) {
309
+ const lower = modelId.toLowerCase();
310
+ return OLLAMA_VISION_PREFIXES.some(prefix => lower.startsWith(prefix));
311
+ }
312
+ /**
313
+ * Env var names we check per provider key.
314
+ * AI_API_KEY is a generic fallback; external config provider hints are preferred.
315
+ */
316
+ exports.PROVIDER_ENV_VARS = {
317
+ anthropic: ['ANTHROPIC_API_KEY'],
318
+ openai: ['OPENAI_API_KEY'],
319
+ kimi: ['KIMI_API_KEY', 'MOONSHOT_API_KEY'],
320
+ groq: ['GROQ_API_KEY'],
321
+ together: ['TOGETHER_API_KEY'],
322
+ deepseek: ['DEEPSEEK_API_KEY'],
323
+ gemini: ['GEMINI_API_KEY', 'GOOGLE_API_KEY'],
324
+ mistral: ['MISTRAL_API_KEY'],
325
+ xai: ['XAI_API_KEY', 'GROK_API_KEY'],
326
+ alibaba: ['DASHSCOPE_API_KEY', 'ALIBABA_API_KEY', 'QWEN_API_KEY'],
327
+ fireworks: ['FIREWORKS_API_KEY'],
328
+ cohere: ['COHERE_API_KEY', 'CO_API_KEY'],
329
+ perplexity: ['PERPLEXITY_API_KEY', 'PPLX_API_KEY'],
330
+ };
331
+ /**
332
+ * Scan ALL available AI providers in parallel.
333
+ *
334
+ * Returns which providers are available (have keys / are reachable),
335
+ * discovered Ollama models, etc.
336
+ */
337
+ async function scanProviders() {
338
+ const results = [];
339
+ // Collect the generic AI_API_KEY — we'll assign it to the matching provider later
340
+ const resolvedApi = (0, credentials_1.resolveApiConfig)();
341
+ const genericKey = resolvedApi.apiKey || process.env.AI_API_KEY || '';
342
+ const genericProviderHint = resolvedApi.provider || '';
343
+ const isExternalSource = resolvedApi.source === 'external';
344
+ // When credentials come from external config, load ALL provider keys from config files
345
+ const externalProviderKeys = {};
346
+ if (resolvedApi.source === 'external') {
347
+ // resolveApiConfig only returns the "best" provider.
348
+ // We need ALL of them for scanning. Read auth-profiles directly.
349
+ try {
350
+ const os = await Promise.resolve().then(() => __importStar(require('os')));
351
+ const fs = await Promise.resolve().then(() => __importStar(require('fs')));
352
+ const path = await Promise.resolve().then(() => __importStar(require('path')));
353
+ const home = os.homedir();
354
+ const roots = [path.join(home, '.openclaw'), path.join(home, '.openclaw-dev')];
355
+ for (const root of roots) {
356
+ // Read auth-profiles for API keys
357
+ const authPaths = [
358
+ path.join(root, 'agents', 'main', 'agent', 'auth-profiles.json'),
359
+ path.join(root, 'agents', 'main', 'auth-profiles.json'),
360
+ ];
361
+ for (const authPath of authPaths) {
362
+ try {
363
+ if (!fs.existsSync(authPath))
364
+ continue;
365
+ const auth = JSON.parse(fs.readFileSync(authPath, 'utf-8'));
366
+ const profiles = auth?.profiles || auth;
367
+ if (!profiles || typeof profiles !== 'object')
368
+ continue;
369
+ for (const [profileKey, profileValue] of Object.entries(profiles)) {
370
+ const providerName = profileKey.split(':')[0].toLowerCase();
371
+ const val = profileValue;
372
+ const apiKey = val?.key || val?.apiKey || val?.api_key || '';
373
+ if (!apiKey)
374
+ continue;
375
+ // Map external provider names to Clawd Cursor provider keys
376
+ const providerMap = {
377
+ 'anthropic': 'anthropic',
378
+ 'openai': 'openai',
379
+ 'moonshot': 'kimi',
380
+ 'kimi': 'kimi',
381
+ 'groq': 'groq',
382
+ 'together': 'together',
383
+ 'deepseek': 'deepseek',
384
+ 'gemini': 'gemini',
385
+ 'google': 'gemini',
386
+ 'mistral': 'mistral',
387
+ 'xai': 'xai',
388
+ 'grok': 'xai',
389
+ 'alibaba': 'alibaba',
390
+ 'qwen': 'alibaba',
391
+ 'dashscope': 'alibaba',
392
+ 'fireworks': 'fireworks',
393
+ 'cohere': 'cohere',
394
+ 'perplexity': 'perplexity',
395
+ 'pplx': 'perplexity',
396
+ };
397
+ const clawdKey = providerMap[providerName];
398
+ if (clawdKey && !externalProviderKeys[clawdKey]) {
399
+ externalProviderKeys[clawdKey] = { apiKey };
400
+ }
401
+ }
402
+ }
403
+ catch { /* skip */ }
404
+ }
405
+ // Read openclaw.json for base URLs
406
+ const configPaths = [
407
+ path.join(root, 'openclaw.json'),
408
+ path.join(root, 'agents', 'main', 'openclaw.json'),
409
+ ];
410
+ for (const configPath of configPaths) {
411
+ try {
412
+ if (!fs.existsSync(configPath))
413
+ continue;
414
+ const cfg = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
415
+ const providers = cfg?.models?.providers || {};
416
+ for (const [provName, provConfig] of Object.entries(providers)) {
417
+ const pConfig = provConfig;
418
+ const baseUrl = pConfig?.baseUrl;
419
+ const providerMap = {
420
+ 'anthropic': 'anthropic',
421
+ 'openai': 'openai',
422
+ 'moonshot': 'kimi',
423
+ 'kimi': 'kimi',
424
+ 'groq': 'groq',
425
+ 'together': 'together',
426
+ 'deepseek': 'deepseek',
427
+ 'nvidia': 'nvidia',
428
+ 'ollama': 'ollama',
429
+ 'gemini': 'gemini',
430
+ 'google': 'gemini',
431
+ 'mistral': 'mistral',
432
+ 'xai': 'xai',
433
+ 'grok': 'xai',
434
+ 'alibaba': 'alibaba',
435
+ 'qwen': 'alibaba',
436
+ 'dashscope': 'alibaba',
437
+ 'fireworks': 'fireworks',
438
+ 'cohere': 'cohere',
439
+ 'perplexity': 'perplexity',
440
+ 'pplx': 'perplexity',
441
+ };
442
+ const clawdKey = providerMap[provName.toLowerCase()];
443
+ if (clawdKey && externalProviderKeys[clawdKey] && baseUrl) {
444
+ externalProviderKeys[clawdKey].baseUrl = baseUrl;
445
+ }
446
+ }
447
+ }
448
+ catch { /* skip */ }
449
+ }
450
+ }
451
+ }
452
+ catch { /* External config read failed, continue with existing logic */ }
453
+ if (Object.keys(externalProviderKeys).length > 0) {
454
+ console.log(` 🔗 External providers detected: ${Object.keys(externalProviderKeys).join(', ')}`);
455
+ }
456
+ }
457
+ // ── Check key-based providers ─────────────────────────────────
458
+ for (const providerKey of Object.keys(exports.PROVIDER_ENV_VARS)) {
459
+ const envVars = exports.PROVIDER_ENV_VARS[providerKey];
460
+ let key = '';
461
+ if (genericProviderHint === providerKey && genericKey) {
462
+ key = genericKey;
463
+ }
464
+ else if (isExternalSource && !genericProviderHint && providerKey === 'openai' && genericKey) {
465
+ // External config may provide an OpenAI-compatible endpoint without a provider label.
466
+ key = genericKey;
467
+ }
468
+ for (const envVar of envVars) {
469
+ if (key)
470
+ break;
471
+ if (process.env[envVar]) {
472
+ key = process.env[envVar];
473
+ break;
474
+ }
475
+ }
476
+ // External multi-provider keys
477
+ if (!key && externalProviderKeys[providerKey]) {
478
+ key = externalProviderKeys[providerKey].apiKey;
479
+ }
480
+ // For standalone AI_API_KEY, infer provider by key format as a best-effort fallback.
481
+ if (!key && genericKey && !(isExternalSource && !genericProviderHint)) {
482
+ const detected = detectProvider(genericKey);
483
+ if (detected === providerKey) {
484
+ key = genericKey;
485
+ }
486
+ }
487
+ results.push({
488
+ key: providerKey,
489
+ name: exports.PROVIDERS[providerKey].name,
490
+ available: !!key,
491
+ detail: key ? `key found (${maskKey(key)})` : 'no key',
492
+ apiKey: key,
493
+ });
494
+ }
495
+ // ── Check Ollama ──────────────────────────────────────────────
496
+ const ollamaResult = {
497
+ key: 'ollama',
498
+ name: exports.PROVIDERS['ollama'].name,
499
+ available: false,
500
+ detail: 'not reachable',
501
+ apiKey: '',
502
+ ollamaModels: [],
503
+ ollamaVisionModels: [],
504
+ };
505
+ try {
506
+ const controller = new AbortController();
507
+ const timeout = setTimeout(() => controller.abort(), 5000);
508
+ const res = await fetch('http://localhost:11434/v1/models', {
509
+ signal: controller.signal,
510
+ });
511
+ clearTimeout(timeout);
512
+ if (res.ok) {
513
+ const data = await res.json();
514
+ // /v1/models returns { data: [{ id: "model-name", ... }] }
515
+ const models = (data.data || []).map((m) => m.id).filter(Boolean);
516
+ const visionModels = models.filter(isOllamaVisionModel);
517
+ ollamaResult.available = true;
518
+ ollamaResult.ollamaModels = models;
519
+ ollamaResult.ollamaVisionModels = visionModels;
520
+ if (models.length > 0) {
521
+ const modelList = models.slice(0, 5).join(', ') + (models.length > 5 ? `, +${models.length - 5} more` : '');
522
+ ollamaResult.detail = `running (${modelList})`;
523
+ }
524
+ else {
525
+ ollamaResult.detail = 'running (no models pulled)';
526
+ }
527
+ }
528
+ else {
529
+ ollamaResult.detail = `responded with HTTP ${res.status}`;
530
+ }
531
+ }
532
+ catch (err) {
533
+ if (err.name === 'AbortError') {
534
+ ollamaResult.detail = 'timeout (5s)';
535
+ }
536
+ else if (err.cause && err.cause.code === 'ECONNREFUSED') {
537
+ ollamaResult.detail = 'not installed / not running';
538
+ }
539
+ else if (err.message?.includes('ECONNREFUSED') || err.message?.includes('fetch failed')) {
540
+ ollamaResult.detail = 'not installed / not running';
541
+ }
542
+ else {
543
+ ollamaResult.detail = `error: ${err.message || err}`;
544
+ }
545
+ }
546
+ results.push(ollamaResult);
547
+ // ── Create dynamic provider entries for unknown external providers ──────
548
+ if (resolvedApi.source === 'external') {
549
+ try {
550
+ const os = await Promise.resolve().then(() => __importStar(require('os')));
551
+ const fs = await Promise.resolve().then(() => __importStar(require('fs')));
552
+ const path = await Promise.resolve().then(() => __importStar(require('path')));
553
+ const home = os.homedir();
554
+ const roots = [path.join(home, '.openclaw'), path.join(home, '.openclaw-dev')];
555
+ for (const root of roots) {
556
+ const configPaths = [
557
+ path.join(root, 'openclaw.json'),
558
+ path.join(root, 'agents', 'main', 'openclaw.json'),
559
+ ];
560
+ for (const configPath of configPaths) {
561
+ try {
562
+ if (!fs.existsSync(configPath))
563
+ continue;
564
+ const cfg = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
565
+ const providers = cfg?.models?.providers || {};
566
+ for (const [provName, provConfig] of Object.entries(providers)) {
567
+ const providerNameLower = provName.toLowerCase();
568
+ const pConfig = provConfig;
569
+ const baseUrl = pConfig?.baseUrl;
570
+ const models = pConfig?.models || {};
571
+ // Skip providers we already handle
572
+ const knownProvider = Object.values(exports.PROVIDERS).some(p => p.baseUrl === baseUrl || providerNameLower.includes(p.name.toLowerCase().split(' ')[0]));
573
+ if (knownProvider)
574
+ continue;
575
+ if (!baseUrl)
576
+ continue;
577
+ // Find API key for this provider
578
+ const authPaths = [
579
+ path.join(root, 'agents', 'main', 'agent', 'auth-profiles.json'),
580
+ path.join(root, 'agents', 'main', 'auth-profiles.json'),
581
+ ];
582
+ let apiKey = '';
583
+ for (const authPath of authPaths) {
584
+ try {
585
+ if (!fs.existsSync(authPath))
586
+ continue;
587
+ const auth = JSON.parse(fs.readFileSync(authPath, 'utf-8'));
588
+ const profiles = auth?.profiles || auth;
589
+ if (!profiles || typeof profiles !== 'object')
590
+ continue;
591
+ for (const [profileKey, profileValue] of Object.entries(profiles)) {
592
+ const profileProviderName = profileKey.split(':')[0].toLowerCase();
593
+ if (profileProviderName === providerNameLower) {
594
+ const val = profileValue;
595
+ apiKey = val?.key || val?.apiKey || val?.api_key || '';
596
+ break;
597
+ }
598
+ }
599
+ if (apiKey)
600
+ break;
601
+ }
602
+ catch { /* skip */ }
603
+ }
604
+ if (!apiKey)
605
+ continue;
606
+ // Extract model names from external config
607
+ const textModels = Object.keys(models).filter(m => !m.toLowerCase().includes('vision') &&
608
+ !m.toLowerCase().includes('dall-e') &&
609
+ !m.toLowerCase().includes('tts'));
610
+ const visionModels = Object.keys(models).filter(m => m.toLowerCase().includes('vision') ||
611
+ m.toLowerCase().includes('4o') ||
612
+ m.toLowerCase().includes('claude'));
613
+ const textModel = textModels[0] || Object.keys(models)[0] || '';
614
+ const visionModel = visionModels[0] || textModel;
615
+ if (!textModel)
616
+ continue;
617
+ // Create dynamic provider entry
618
+ const dynamicProviderKey = providerNameLower.replace(/[^a-z0-9]/g, '');
619
+ // Add to PROVIDERS map dynamically (but don't mutate the original)
620
+ // Assumption: most external providers expose an OpenAI-compatible API.
621
+ // This has NOT been verified via a live probe — set probed: false so
622
+ // callers can distinguish assumed vs confirmed capabilities.
623
+ const dynamicProvider = {
624
+ name: provName,
625
+ baseUrl: baseUrl,
626
+ authHeader: (key) => ({ 'Authorization': `Bearer ${key}` }),
627
+ textModel: textModel,
628
+ visionModel: visionModel,
629
+ openaiCompat: true,
630
+ computerUse: false,
631
+ probed: false,
632
+ };
633
+ // Don't add to PROVIDERS directly (immutable), but create scan result
634
+ if (!results.find(r => r.key === dynamicProviderKey)) {
635
+ results.push({
636
+ key: dynamicProviderKey,
637
+ name: provName,
638
+ available: true,
639
+ detail: `external config (${maskKey(apiKey)})`,
640
+ apiKey: apiKey,
641
+ });
642
+ // Store the dynamic provider for later use
643
+ exports.PROVIDERS[dynamicProviderKey] = dynamicProvider;
644
+ }
645
+ }
646
+ }
647
+ catch { /* skip */ }
648
+ }
649
+ }
650
+ }
651
+ catch { /* External dynamic provider creation failed, continue */ }
652
+ }
653
+ // Apply external base URLs to custom providers (e.g., moonshot uses api.moonshot.cn, not openai.com)
654
+ for (const result of results) {
655
+ if (externalProviderKeys[result.key]?.baseUrl && result.available) {
656
+ // Store for later use in pipeline building
657
+ result.externalBaseUrl = externalProviderKeys[result.key].baseUrl;
658
+ }
659
+ }
660
+ return results;
661
+ }
662
+ /** Text model preference: fastest/most-reliable first */
663
+ const TEXT_MODEL_PREFERENCE = ['ollama', 'groq', 'fireworks', 'together', 'deepseek', 'alibaba', 'cohere', 'perplexity', 'anthropic', 'openai', 'kimi', 'gemini', 'mistral', 'xai'];
664
+ /** Vision model preference: best vision capability first */
665
+ const VISION_MODEL_PREFERENCE = ['anthropic', 'openai', 'gemini', 'mistral', 'groq', 'fireworks', 'together', 'alibaba', 'cohere', 'perplexity', 'kimi', 'xai', 'deepseek', 'ollama'];
666
+ /**
667
+ * Given scan results and model test results, build the optimal mixed pipeline.
668
+ */
669
+ function buildMixedPipeline(scanResults, modelTests) {
670
+ const workingText = modelTests.filter(t => t.role === 'text' && t.ok);
671
+ const workingVision = modelTests.filter(t => t.role === 'vision' && t.ok);
672
+ // Pick cheapest working text model
673
+ let bestText;
674
+ for (const pref of TEXT_MODEL_PREFERENCE) {
675
+ const match = workingText.find(t => t.providerKey === pref);
676
+ if (match) {
677
+ bestText = match;
678
+ break;
679
+ }
680
+ }
681
+ // Pick best working vision model
682
+ let bestVision;
683
+ for (const pref of VISION_MODEL_PREFERENCE) {
684
+ const match = workingVision.find(t => t.providerKey === pref);
685
+ if (match) {
686
+ bestVision = match;
687
+ break;
688
+ }
689
+ }
690
+ // Determine primary provider key (prefer vision provider for the "main" provider)
691
+ const primaryKey = bestVision?.providerKey || bestText?.providerKey || 'ollama';
692
+ const scanForPrimary = scanResults.find(s => s.key === primaryKey);
693
+ const primaryProvider = exports.PROVIDERS[primaryKey] || exports.PROVIDERS['ollama'];
694
+ const primaryApiKey = scanForPrimary?.apiKey || '';
695
+ const textProviderKey = bestText?.providerKey || primaryKey;
696
+ const textProvider = exports.PROVIDERS[textProviderKey] || exports.PROVIDERS['ollama'];
697
+ const visionProviderKey = bestVision?.providerKey || primaryKey;
698
+ const visionProvider = exports.PROVIDERS[visionProviderKey] || exports.PROVIDERS['ollama'];
699
+ return {
700
+ provider: primaryProvider,
701
+ providerKey: primaryKey,
702
+ apiKey: primaryApiKey,
703
+ layer1: true,
704
+ layer2: {
705
+ enabled: !!bestText,
706
+ model: bestText?.model || textProvider.textModel,
707
+ baseUrl: textProvider.baseUrl,
708
+ },
709
+ layer3: {
710
+ enabled: !!bestVision,
711
+ model: bestVision?.model || visionProvider.visionModel,
712
+ baseUrl: visionProvider.baseUrl,
713
+ computerUse: visionProvider.computerUse,
714
+ },
715
+ };
716
+ }
717
+ //# sourceMappingURL=providers.js.map