@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.
- package/CHANGELOG.md +2264 -0
- package/LICENSE +21 -0
- package/README.md +385 -0
- package/SECURITY.md +44 -0
- package/SKILL.md +503 -0
- package/dist/core/agent-loop/agent.d.ts +42 -0
- package/dist/core/agent-loop/agent.js +1023 -0
- package/dist/core/agent-loop/agent.js.map +1 -0
- package/dist/core/agent-loop/batch-tool.d.ts +25 -0
- package/dist/core/agent-loop/batch-tool.js +218 -0
- package/dist/core/agent-loop/batch-tool.js.map +1 -0
- package/dist/core/agent-loop/coord-scale.d.ts +72 -0
- package/dist/core/agent-loop/coord-scale.js +89 -0
- package/dist/core/agent-loop/coord-scale.js.map +1 -0
- package/dist/core/agent-loop/focus-guard.d.ts +24 -0
- package/dist/core/agent-loop/focus-guard.js +29 -0
- package/dist/core/agent-loop/focus-guard.js.map +1 -0
- package/dist/core/agent-loop/project-mcp.d.ts +97 -0
- package/dist/core/agent-loop/project-mcp.js +253 -0
- package/dist/core/agent-loop/project-mcp.js.map +1 -0
- package/dist/core/agent-loop/prompt.d.ts +45 -0
- package/dist/core/agent-loop/prompt.js +426 -0
- package/dist/core/agent-loop/prompt.js.map +1 -0
- package/dist/core/agent-loop/tool-meta.d.ts +93 -0
- package/dist/core/agent-loop/tool-meta.js +651 -0
- package/dist/core/agent-loop/tool-meta.js.map +1 -0
- package/dist/core/agent-loop/tools.d.ts +38 -0
- package/dist/core/agent-loop/tools.js +2134 -0
- package/dist/core/agent-loop/tools.js.map +1 -0
- package/dist/core/agent-loop/types.d.ts +170 -0
- package/dist/core/agent-loop/types.js +12 -0
- package/dist/core/agent-loop/types.js.map +1 -0
- package/dist/core/agent.d.ts +51 -0
- package/dist/core/agent.js +245 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/app-categories.d.ts +67 -0
- package/dist/core/app-categories.js +108 -0
- package/dist/core/app-categories.js.map +1 -0
- package/dist/core/banner.d.ts +70 -0
- package/dist/core/banner.js +245 -0
- package/dist/core/banner.js.map +1 -0
- package/dist/core/classify/capability.d.ts +45 -0
- package/dist/core/classify/capability.js +78 -0
- package/dist/core/classify/capability.js.map +1 -0
- package/dist/core/decompose/llm-decomposer.d.ts +35 -0
- package/dist/core/decompose/llm-decomposer.js +156 -0
- package/dist/core/decompose/llm-decomposer.js.map +1 -0
- package/dist/core/decompose/parser.d.ts +27 -0
- package/dist/core/decompose/parser.js +101 -0
- package/dist/core/decompose/parser.js.map +1 -0
- package/dist/core/observability/correlation.d.ts +19 -0
- package/dist/core/observability/correlation.js +36 -0
- package/dist/core/observability/correlation.js.map +1 -0
- package/dist/core/observability/cost-meter.d.ts +51 -0
- package/dist/core/observability/cost-meter.js +134 -0
- package/dist/core/observability/cost-meter.js.map +1 -0
- package/dist/core/observability/logger.d.ts +61 -0
- package/dist/core/observability/logger.js +550 -0
- package/dist/core/observability/logger.js.map +1 -0
- package/dist/core/router/aliases.d.ts +50 -0
- package/dist/core/router/aliases.js +104 -0
- package/dist/core/router/aliases.js.map +1 -0
- package/dist/core/router/normalize.d.ts +41 -0
- package/dist/core/router/normalize.js +80 -0
- package/dist/core/router/normalize.js.map +1 -0
- package/dist/core/safety.d.ts +126 -0
- package/dist/core/safety.js +568 -0
- package/dist/core/safety.js.map +1 -0
- package/dist/core/sense/a11y-resolver.d.ts +73 -0
- package/dist/core/sense/a11y-resolver.js +76 -0
- package/dist/core/sense/a11y-resolver.js.map +1 -0
- package/dist/core/sense/fingerprint.d.ts +41 -0
- package/dist/core/sense/fingerprint.js +123 -0
- package/dist/core/sense/fingerprint.js.map +1 -0
- package/dist/core/sense/rank.d.ts +70 -0
- package/dist/core/sense/rank.js +192 -0
- package/dist/core/sense/rank.js.map +1 -0
- package/dist/core/sense/reactive-check.d.ts +40 -0
- package/dist/core/sense/reactive-check.js +48 -0
- package/dist/core/sense/reactive-check.js.map +1 -0
- package/dist/core/sense/snapshot.d.ts +19 -0
- package/dist/core/sense/snapshot.js +100 -0
- package/dist/core/sense/snapshot.js.map +1 -0
- package/dist/core/sense/types.d.ts +66 -0
- package/dist/core/sense/types.js +9 -0
- package/dist/core/sense/types.js.map +1 -0
- package/dist/core/sense/ui-map-anchors.d.ts +7 -0
- package/dist/core/sense/ui-map-anchors.js +24 -0
- package/dist/core/sense/ui-map-anchors.js.map +1 -0
- package/dist/core/sense/ui-map-elements.d.ts +5 -0
- package/dist/core/sense/ui-map-elements.js +33 -0
- package/dist/core/sense/ui-map-elements.js.map +1 -0
- package/dist/core/sense/ui-map-find.d.ts +56 -0
- package/dist/core/sense/ui-map-find.js +153 -0
- package/dist/core/sense/ui-map-find.js.map +1 -0
- package/dist/core/sense/ui-map-fuse.d.ts +4 -0
- package/dist/core/sense/ui-map-fuse.js +44 -0
- package/dist/core/sense/ui-map-fuse.js.map +1 -0
- package/dist/core/sense/ui-map-geom.d.ts +3 -0
- package/dist/core/sense/ui-map-geom.js +16 -0
- package/dist/core/sense/ui-map-geom.js.map +1 -0
- package/dist/core/sense/ui-map-holder.d.ts +58 -0
- package/dist/core/sense/ui-map-holder.js +87 -0
- package/dist/core/sense/ui-map-holder.js.map +1 -0
- package/dist/core/sense/ui-map-normalize.d.ts +19 -0
- package/dist/core/sense/ui-map-normalize.js +65 -0
- package/dist/core/sense/ui-map-normalize.js.map +1 -0
- package/dist/core/sense/ui-map-render.d.ts +4 -0
- package/dist/core/sense/ui-map-render.js +34 -0
- package/dist/core/sense/ui-map-render.js.map +1 -0
- package/dist/core/sense/ui-map-resolve.d.ts +41 -0
- package/dist/core/sense/ui-map-resolve.js +59 -0
- package/dist/core/sense/ui-map-resolve.js.map +1 -0
- package/dist/core/sense/ui-map-types.d.ts +66 -0
- package/dist/core/sense/ui-map-types.js +11 -0
- package/dist/core/sense/ui-map-types.js.map +1 -0
- package/dist/core/sense/ui-map.d.ts +29 -0
- package/dist/core/sense/ui-map.js +113 -0
- package/dist/core/sense/ui-map.js.map +1 -0
- package/dist/core/verify/assertions.d.ts +132 -0
- package/dist/core/verify/assertions.js +284 -0
- package/dist/core/verify/assertions.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/browser-config.d.ts +36 -0
- package/dist/llm/browser-config.js +83 -0
- package/dist/llm/browser-config.js.map +1 -0
- package/dist/llm/client.d.ts +268 -0
- package/dist/llm/client.js +1094 -0
- package/dist/llm/client.js.map +1 -0
- package/dist/llm/config.d.ts +79 -0
- package/dist/llm/config.js +375 -0
- package/dist/llm/config.js.map +1 -0
- package/dist/llm/credentials.d.ts +35 -0
- package/dist/llm/credentials.js +491 -0
- package/dist/llm/credentials.js.map +1 -0
- package/dist/llm/external-creds.d.ts +42 -0
- package/dist/llm/external-creds.js +169 -0
- package/dist/llm/external-creds.js.map +1 -0
- package/dist/llm/providers.d.ts +123 -0
- package/dist/llm/providers.js +717 -0
- package/dist/llm/providers.js.map +1 -0
- package/dist/paths.d.ts +31 -0
- package/dist/paths.js +147 -0
- package/dist/paths.js.map +1 -0
- package/dist/platform/accessibility.d.ts +139 -0
- package/dist/platform/accessibility.js +670 -0
- package/dist/platform/accessibility.js.map +1 -0
- package/dist/platform/cdp-driver.d.ts +318 -0
- package/dist/platform/cdp-driver.js +1179 -0
- package/dist/platform/cdp-driver.js.map +1 -0
- package/dist/platform/index.d.ts +11 -0
- package/dist/platform/index.js +69 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/platform/keys.d.ts +17 -0
- package/dist/platform/keys.js +129 -0
- package/dist/platform/keys.js.map +1 -0
- package/dist/platform/launch-poll.d.ts +101 -0
- package/dist/platform/launch-poll.js +177 -0
- package/dist/platform/launch-poll.js.map +1 -0
- package/dist/platform/linux.d.ts +173 -0
- package/dist/platform/linux.js +1253 -0
- package/dist/platform/linux.js.map +1 -0
- package/dist/platform/macos.d.ts +136 -0
- package/dist/platform/macos.js +976 -0
- package/dist/platform/macos.js.map +1 -0
- package/dist/platform/native-desktop.d.ts +145 -0
- package/dist/platform/native-desktop.js +936 -0
- package/dist/platform/native-desktop.js.map +1 -0
- package/dist/platform/native-helper.d.ts +130 -0
- package/dist/platform/native-helper.js +592 -0
- package/dist/platform/native-helper.js.map +1 -0
- package/dist/platform/ocr-engine.d.ts +78 -0
- package/dist/platform/ocr-engine.js +363 -0
- package/dist/platform/ocr-engine.js.map +1 -0
- package/dist/platform/ps-runner.d.ts +28 -0
- package/dist/platform/ps-runner.js +228 -0
- package/dist/platform/ps-runner.js.map +1 -0
- package/dist/platform/types.d.ts +397 -0
- package/dist/platform/types.js +15 -0
- package/dist/platform/types.js.map +1 -0
- package/dist/platform/uri-handler.d.ts +75 -0
- package/dist/platform/uri-handler.js +273 -0
- package/dist/platform/uri-handler.js.map +1 -0
- package/dist/platform/wayland-backend.d.ts +53 -0
- package/dist/platform/wayland-backend.js +348 -0
- package/dist/platform/wayland-backend.js.map +1 -0
- package/dist/platform/windows.d.ts +232 -0
- package/dist/platform/windows.js +1210 -0
- package/dist/platform/windows.js.map +1 -0
- package/dist/postbuild.d.ts +10 -0
- package/dist/postbuild.js +98 -0
- package/dist/postbuild.js.map +1 -0
- package/dist/schema/snapshot.d.ts +33 -0
- package/dist/schema/snapshot.js +90 -0
- package/dist/schema/snapshot.js.map +1 -0
- package/dist/shortcuts.d.ts +30 -0
- package/dist/shortcuts.js +261 -0
- package/dist/shortcuts.js.map +1 -0
- package/dist/surface/cli.d.ts +7 -0
- package/dist/surface/cli.js +1556 -0
- package/dist/surface/cli.js.map +1 -0
- package/dist/surface/dashboard.d.ts +8 -0
- package/dist/surface/dashboard.js +1193 -0
- package/dist/surface/dashboard.js.map +1 -0
- package/dist/surface/doctor.d.ts +29 -0
- package/dist/surface/doctor.js +1514 -0
- package/dist/surface/doctor.js.map +1 -0
- package/dist/surface/format.d.ts +10 -0
- package/dist/surface/format.js +37 -0
- package/dist/surface/format.js.map +1 -0
- package/dist/surface/http-utility.d.ts +65 -0
- package/dist/surface/http-utility.js +336 -0
- package/dist/surface/http-utility.js.map +1 -0
- package/dist/surface/mcp-server.d.ts +91 -0
- package/dist/surface/mcp-server.js +280 -0
- package/dist/surface/mcp-server.js.map +1 -0
- package/dist/surface/onboarding.d.ts +15 -0
- package/dist/surface/onboarding.js +184 -0
- package/dist/surface/onboarding.js.map +1 -0
- package/dist/surface/pidfile.d.ts +79 -0
- package/dist/surface/pidfile.js +263 -0
- package/dist/surface/pidfile.js.map +1 -0
- package/dist/surface/readiness.d.ts +45 -0
- package/dist/surface/readiness.js +230 -0
- package/dist/surface/readiness.js.map +1 -0
- package/dist/surface/report.d.ts +68 -0
- package/dist/surface/report.js +341 -0
- package/dist/surface/report.js.map +1 -0
- package/dist/surface/skill-register.d.ts +14 -0
- package/dist/surface/skill-register.js +150 -0
- package/dist/surface/skill-register.js.map +1 -0
- package/dist/surface/version.d.ts +6 -0
- package/dist/surface/version.js +27 -0
- package/dist/surface/version.js.map +1 -0
- package/dist/tools/a11y.d.ts +8 -0
- package/dist/tools/a11y.js +545 -0
- package/dist/tools/a11y.js.map +1 -0
- package/dist/tools/a11y_depth.d.ts +19 -0
- package/dist/tools/a11y_depth.js +455 -0
- package/dist/tools/a11y_depth.js.map +1 -0
- package/dist/tools/agent.d.ts +15 -0
- package/dist/tools/agent.js +248 -0
- package/dist/tools/agent.js.map +1 -0
- package/dist/tools/batch.d.ts +46 -0
- package/dist/tools/batch.js +230 -0
- package/dist/tools/batch.js.map +1 -0
- package/dist/tools/cdp.d.ts +8 -0
- package/dist/tools/cdp.js +233 -0
- package/dist/tools/cdp.js.map +1 -0
- package/dist/tools/compact.d.ts +63 -0
- package/dist/tools/compact.js +418 -0
- package/dist/tools/compact.js.map +1 -0
- package/dist/tools/cost-class.d.ts +38 -0
- package/dist/tools/cost-class.js +117 -0
- package/dist/tools/cost-class.js.map +1 -0
- package/dist/tools/desktop.d.ts +9 -0
- package/dist/tools/desktop.js +346 -0
- package/dist/tools/desktop.js.map +1 -0
- package/dist/tools/electron_bridge.d.ts +41 -0
- package/dist/tools/electron_bridge.js +261 -0
- package/dist/tools/electron_bridge.js.map +1 -0
- package/dist/tools/extras.d.ts +22 -0
- package/dist/tools/extras.js +942 -0
- package/dist/tools/extras.js.map +1 -0
- package/dist/tools/favorites.d.ts +13 -0
- package/dist/tools/favorites.js +137 -0
- package/dist/tools/favorites.js.map +1 -0
- package/dist/tools/introspection.d.ts +13 -0
- package/dist/tools/introspection.js +55 -0
- package/dist/tools/introspection.js.map +1 -0
- package/dist/tools/ocr.d.ts +8 -0
- package/dist/tools/ocr.js +66 -0
- package/dist/tools/ocr.js.map +1 -0
- package/dist/tools/orchestration.d.ts +7 -0
- package/dist/tools/orchestration.js +377 -0
- package/dist/tools/orchestration.js.map +1 -0
- package/dist/tools/playbooks/extract-compose.d.ts +22 -0
- package/dist/tools/playbooks/extract-compose.js +85 -0
- package/dist/tools/playbooks/extract-compose.js.map +1 -0
- package/dist/tools/playbooks/find-replace.d.ts +11 -0
- package/dist/tools/playbooks/find-replace.js +56 -0
- package/dist/tools/playbooks/find-replace.js.map +1 -0
- package/dist/tools/playbooks/index.d.ts +63 -0
- package/dist/tools/playbooks/index.js +70 -0
- package/dist/tools/playbooks/index.js.map +1 -0
- package/dist/tools/playbooks/keys-blocklist.d.ts +24 -0
- package/dist/tools/playbooks/keys-blocklist.js +89 -0
- package/dist/tools/playbooks/keys-blocklist.js.map +1 -0
- package/dist/tools/registry.d.ts +40 -0
- package/dist/tools/registry.js +560 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/safety-gate.d.ts +16 -0
- package/dist/tools/safety-gate.js +70 -0
- package/dist/tools/safety-gate.js.map +1 -0
- package/dist/tools/scheduler.d.ts +76 -0
- package/dist/tools/scheduler.js +413 -0
- package/dist/tools/scheduler.js.map +1 -0
- package/dist/tools/shortcuts.d.ts +13 -0
- package/dist/tools/shortcuts.js +205 -0
- package/dist/tools/shortcuts.js.map +1 -0
- package/dist/tools/smart.d.ts +15 -0
- package/dist/tools/smart.js +785 -0
- package/dist/tools/smart.js.map +1 -0
- package/dist/tools/types.d.ts +174 -0
- package/dist/tools/types.js +67 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/window-text.d.ts +15 -0
- package/dist/tools/window-text.js +39 -0
- package/dist/tools/window-text.js.map +1 -0
- package/dist/types.d.ts +122 -0
- package/dist/types.js +41 -0
- package/dist/types.js.map +1 -0
- package/native/Package.swift +38 -0
- package/native/README.md +113 -0
- package/native/Sources/ClawdCursorHelper/main.swift +602 -0
- package/native/Sources/ClawdCursorHost/main.swift +182 -0
- package/native/Sources/PermissionCheck/main.swift +53 -0
- package/native/Sources/ScreenshotHelper/main.swift +219 -0
- package/native/build.sh +139 -0
- package/native/entitlements.plist +12 -0
- package/package.json +115 -0
- package/scripts/banner.ps1 +112 -0
- package/scripts/coord-accuracy.ps1 +140 -0
- package/scripts/coord-uwp.ps1 +80 -0
- package/scripts/edge-glow.ps1 +180 -0
- package/scripts/find-element.ps1 +198 -0
- package/scripts/get-foreground-window.ps1 +71 -0
- package/scripts/get-screen-context.ps1 +183 -0
- package/scripts/get-windows.ps1 +66 -0
- package/scripts/install-panic-hotkey.ps1 +46 -0
- package/scripts/interact-element.ps1 +431 -0
- package/scripts/invoke-element.ps1 +314 -0
- package/scripts/linux/atspi-bridge.py +356 -0
- package/scripts/linux/ocr-recognize.py +154 -0
- package/scripts/mac/_window-picker.jxa +163 -0
- package/scripts/mac/find-element.jxa +0 -0
- package/scripts/mac/find-element.sh +161 -0
- package/scripts/mac/focus-window.jxa +284 -0
- package/scripts/mac/get-focused-element.jxa +102 -0
- package/scripts/mac/get-foreground-window.jxa +173 -0
- package/scripts/mac/get-screen-context.jxa +197 -0
- package/scripts/mac/get-ui-tree.sh +141 -0
- package/scripts/mac/get-windows.jxa +117 -0
- package/scripts/mac/interact-element.sh +235 -0
- package/scripts/mac/invoke-element.jxa +408 -0
- package/scripts/mac/ocr-recognize.swift +124 -0
- package/scripts/ocr-recognize.ps1 +102 -0
- package/scripts/postinstall-native.js +48 -0
- package/scripts/ps-bridge.ps1 +830 -0
- package/scripts/smoke-mcp.ps1 +119 -0
- package/scripts/sync-version.ts +178 -0
- 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
|