@vibe-lark/larkpal 0.1.84 → 0.1.86
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/dist/account-id-BM1T6029-DYjVxojW.mjs +46 -0
- package/dist/activation-context--5yu1dPF-Bwsn3moT.mjs +172 -0
- package/dist/anthropic-TH8ERTXK.mjs +5962 -0
- package/dist/assistant-visible-text-DuFWokAt-CsbII5KS.mjs +596 -0
- package/dist/azure-openai-responses-Bt_Ag9Er.mjs +166 -0
- package/dist/boundary-file-read-BSd9MXPy--KThL5e6.mjs +594 -0
- package/dist/browser-lifecycle-cleanup-BdNsMhMD-O3tnAM4i.mjs +60 -0
- package/dist/build-DgTrEpge.mjs +3333 -0
- package/dist/bundled-compat-BpaDaAAu-D7oazKjD.mjs +5216 -0
- package/dist/bundled-dir-U738ay4K-DXK0q_TV.mjs +258 -0
- package/dist/call-DimWbpgJ-ColD4W-y.mjs +9993 -0
- package/dist/channel-bootstrap.runtime-BVclcGv1-DJv_Z-Kr.mjs +2 -0
- package/dist/channel-bootstrap.runtime-Cwcr38m2-VRfVCR-i.mjs +33 -0
- package/dist/chunk-D6SyT4dJ.mjs +36 -0
- package/dist/cli.mjs +6 -6
- package/dist/command-format-LSnUCVVF-BQ2SMKka.mjs +685 -0
- package/dist/config-Bim2pi8a-BQUdfiEi.mjs +9 -0
- package/dist/delivery-context.shared-j5hC5qb1-CI83RXXZ.mjs +72 -0
- package/dist/diagnostic-ClMwNnUA-D6nUtLnb.mjs +140 -0
- package/dist/dist-CEGw8-2W.mjs +429 -0
- package/dist/dist-DD2aJ2UL.mjs +125135 -0
- package/dist/env-api-keys-BVvSg7T2.mjs +68 -0
- package/dist/event-stream-xaQWmyas.mjs +15226 -0
- package/dist/facade-loader-DFzIYYt_-CIr4HKtE.mjs +194 -0
- package/dist/from-DF7cl2wz.mjs +3842 -0
- package/dist/gateway-method-policy-C7rf0SeV-CJQMEYIE.mjs +28 -0
- package/dist/github-copilot-headers-DjqWtUoP.mjs +22 -0
- package/dist/google-C2pVrgBZ.mjs +336 -0
- package/dist/google-gemini-cli-BBxgS5Ho.mjs +623 -0
- package/dist/google-shared-BsWgwEk1.mjs +22791 -0
- package/dist/google-vertex-BsVLJrrC.mjs +358 -0
- package/dist/hash-DAFtW_W7.mjs +16 -0
- package/dist/headers-R3HdCbAE.mjs +8 -0
- package/dist/home-dir-C44RaPME-CBRS4HLP.mjs +93 -0
- package/dist/ids-BPsM98Uu-CwuxvUai.mjs +77 -0
- package/dist/image-2w3cApg7-CxpHvoB5.mjs +207 -0
- package/dist/io-CH2g3vsv-BOGlLlB8.mjs +26218 -0
- package/dist/jiti-loader-cache-Bat69wam-D6hCxboy.mjs +5049 -0
- package/dist/json-file-BQRNuxmK-DhJM5NsG.mjs +108 -0
- package/dist/json-parse-v_HIJjjI.mjs +381 -0
- package/dist/jws-GFcTvvVT.mjs +2291 -0
- package/dist/{lark-cli-provider-7LvtOIF_.mjs → lark-cli-provider-BARgbbmo.mjs} +1 -1
- package/dist/{live-smoke-nvTUPtrv.mjs → live-smoke-BhkBOcH9.mjs} +3 -3
- package/dist/load-context-mb7uvLSn-B10MAi3I.mjs +29 -0
- package/dist/loader-708jrx4Y-BOswuvpe.mjs +5053 -0
- package/dist/main.mjs +56780 -476
- package/dist/manifest-registry-_hxKCS2K-CZdeyN0f.mjs +3512 -0
- package/dist/mcp-server.mjs +1 -1
- package/dist/message-channel-Bk_YHfQg-AeNrPPpp.mjs +50 -0
- package/dist/message-channel-core-DTA--Gjh-CY4Tkb7N.mjs +29 -0
- package/dist/message.config.runtime-K-k4XOyq-DZTmXomP.mjs +2 -0
- package/dist/message.gateway.runtime-DqHOHRTQ-DH4ml0YF.mjs +2 -0
- package/dist/mistral-CaR4DiLu.mjs +28657 -0
- package/dist/model-auth-env-oyg2Hexc-DU_rOUU5.mjs +1306 -0
- package/dist/models-config-BmpSQJQF-Gfvh1n3A.mjs +1282 -0
- package/dist/models-config.runtime-BsU_22xk.mjs +2 -0
- package/dist/multipart-parser-DedmaB5g.mjs +294 -0
- package/dist/oauth-DOJeGfcE.mjs +6392 -0
- package/dist/openai-BDtIh3Ja.mjs +6693 -0
- package/dist/openai-codex-responses-C5EORu31.mjs +664 -0
- package/dist/openai-completions-CR_cS6gX.mjs +669 -0
- package/dist/openai-responses-oGxwZyuC.mjs +184 -0
- package/dist/openai-responses-shared-BixMSDZE.mjs +398 -0
- package/dist/paths-D6msg0S1-C2lYuisN.mjs +189 -0
- package/dist/paths-D92DjaZ--CTOESW2b.mjs +192 -0
- package/dist/pi-model-discovery-Bd0TWzo8-BFsJmeMb.mjs +227 -0
- package/dist/pi-model-discovery-runtime-CCCZxkd8.mjs +2 -0
- package/dist/pi-tools.before-tool-call.runtime-Bn7uqKie-C5ewk8kK.mjs +399 -0
- package/dist/plugin-auto-enable-DdH3n9V8-DsA1isaF.mjs +1456 -0
- package/dist/process-scoped-map-B2cWkYET-CXwUZ8CZ.mjs +61 -0
- package/dist/provider-discovery.runtime-BPzz1PFj.mjs +58 -0
- package/dist/provider-model-compat-CFqcq0it-BDDuBI3A.mjs +118 -0
- package/dist/provider-runtime-C8rljsNs-CIT93zoy.mjs +2 -0
- package/dist/provider-runtime-CT50mNIX-BwEV6GyO.mjs +573 -0
- package/dist/provider-stream-COLujAAo-CbJPDngm.mjs +35449 -0
- package/dist/providers.runtime-Ba7tOlq7-CXkhkzU9.mjs +219 -0
- package/dist/public-surface-loader-BVl0NQAE-C0piXtsT.mjs +117 -0
- package/dist/resolve-C33B7eeu-BNvYTl6k.mjs +1041 -0
- package/dist/runtime-Cym-fqI8-DaSDMH-a.mjs +120 -0
- package/dist/runtime-channel-state-CohMybAh-hXR6y5Gx.mjs +19 -0
- package/dist/runtime-snapshot-C54O1-gI-40cbyi7P.mjs +677 -0
- package/dist/runtime-state-IBOIXKOx-Bf9tcLvc.mjs +10 -0
- package/dist/runtime-web-tools-fallback.runtime-Ca-qn1mj-BCVImm7a.mjs +39 -0
- package/dist/runtime-web-tools-manifest.runtime-BgxQTjmq-Cb4nJkRT.mjs +2 -0
- package/dist/runtime-web-tools-public-artifacts.runtime-D9qcoWIX-BrQdXzOQ.mjs +2 -0
- package/dist/session-archive.runtime-B52_5vs4-BG-_IwNJ.mjs +2 -0
- package/dist/session-key-Cn2QoOyX-CuHbJMgR.mjs +82 -0
- package/dist/session-transcript-files.fs-DEeFXruQ-B1PF6nLy.mjs +147 -0
- package/dist/src-BgCX0MLG.mjs +813 -0
- package/dist/src-DYbqlAqf.mjs +1177 -0
- package/dist/subagent-announce-L5WsQatW-CQWI9GMd.mjs +344 -0
- package/dist/subagent-announce.registry.runtime-DiqZyeTs-BKuniyi3.mjs +28 -0
- package/dist/subagent-registry-steer-runtime-DFgZFC0j-BhBz0roy.mjs +211 -0
- package/dist/subagent-system-prompt-C1qnN--K-DpnTFP47.mjs +3061 -0
- package/dist/target-parsing-loaded-DKkb6jJY-BMD4CkpS.mjs +1002 -0
- package/dist/task-registry-delivery-runtime-Dd1CUkZF-C8U40a3O.mjs +2950 -0
- package/dist/task-registry-delivery-runtime-ragbeVx5-CNbFAkjD.mjs +2 -0
- package/dist/thinking-Bh-7MqXz-D3woGbO7.mjs +2 -0
- package/dist/transcript-E_-ISOkD-DWCfZP2p.mjs +2019 -0
- package/dist/transcript.runtime-BqhvZZdl-BPy42vBP.mjs +2 -0
- package/dist/transform-messages-DbhIzTxq.mjs +207 -0
- package/dist/web-provider-public-artifacts-BlpRwIUS-CGPSV4W2.mjs +295 -0
- package/dist/web-search-providers.runtime--0aUtC3b-DyuhC95V.mjs +200 -0
- package/package.json +3 -3
- package/dist/rolldown-runtime-wcPFST8Q.mjs +0 -13
- /package/dist/{interactive-init-B6j8j_Ap.mjs → interactive-init-BXQBalNr.mjs} +0 -0
|
@@ -0,0 +1,1282 @@
|
|
|
1
|
+
import { c as normalizeOptionalString, o as normalizeLowercaseStringOrEmpty } from "./home-dir-C44RaPME-CBRS4HLP.mjs";
|
|
2
|
+
import { s as isRecord } from "./bundled-dir-U738ay4K-DXK0q_TV.mjs";
|
|
3
|
+
import { c as resolveProviderIdForAuth, n as loadConfig, r as projectConfigOntoRuntimeSourceSnapshot, w as createConfigRuntimeEnv } from "./io-CH2g3vsv-BOGlLlB8.mjs";
|
|
4
|
+
import { Mt as formatErrorMessage, St as createSubsystemLogger, V as MODEL_APIS, c as findNormalizedProviderValue, l as normalizeProviderId, vt as coerceSecretRef, xt as resolveSecretInputRef } from "./bundled-compat-BpaDaAAu-D7oazKjD.mjs";
|
|
5
|
+
import "./manifest-registry-_hxKCS2K-CZdeyN0f.mjs";
|
|
6
|
+
import "./jiti-loader-cache-Bat69wam-D6hCxboy.mjs";
|
|
7
|
+
import { n as getRuntimeConfigSourceSnapshot } from "./runtime-snapshot-C54O1-gI-40cbyi7P.mjs";
|
|
8
|
+
import "./thinking-Bh-7MqXz-D3woGbO7.mjs";
|
|
9
|
+
import "./config-Bim2pi8a-BQUdfiEi.mjs";
|
|
10
|
+
import { d as resolveOwningPluginIdsForProvider } from "./plugin-auto-enable-DdH3n9V8-DsA1isaF.mjs";
|
|
11
|
+
import { R as resolveProviderSyntheticAuthWithPlugin, g as normalizeProviderConfigWithPlugin, j as resolveProviderConfigApiKeyWithPlugin, r as applyProviderNativeStreamingUsageCompatWithPlugin } from "./provider-runtime-CT50mNIX-BwEV6GyO.mjs";
|
|
12
|
+
import { N as resolveOpenClawAgentDir, a as isNonSecretApiKeyMarker, c as resolveNonEnvSecretRefHeaderValueMarker, d as normalizeSecretInput, g as ensureAuthProfileStore, o as resolveEnvSecretRefHeaderValueMarker, s as resolveNonEnvSecretRefApiKeyMarker, t as resolveEnvApiKey, u as normalizeOptionalSecretInput } from "./model-auth-env-oyg2Hexc-DU_rOUU5.mjs";
|
|
13
|
+
import { createRequire } from "node:module";
|
|
14
|
+
import path from "node:path";
|
|
15
|
+
import fs from "node:fs/promises";
|
|
16
|
+
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/provider-model-id-normalize-DwRlLmru.js
|
|
17
|
+
function normalizeGooglePreviewModelId(id) {
|
|
18
|
+
if (id === "gemini-3-pro") return "gemini-3-pro-preview";
|
|
19
|
+
if (id === "gemini-3-flash") return "gemini-3-flash-preview";
|
|
20
|
+
if (id === "gemini-3.1-pro") return "gemini-3.1-pro-preview";
|
|
21
|
+
if (id === "gemini-3.1-flash-lite") return "gemini-3.1-flash-lite-preview";
|
|
22
|
+
if (id === "gemini-3.1-flash" || id === "gemini-3.1-flash-preview") return "gemini-3-flash-preview";
|
|
23
|
+
return id;
|
|
24
|
+
}
|
|
25
|
+
function normalizeNativeXaiModelId(id) {
|
|
26
|
+
if (id === "grok-4-fast-reasoning") return "grok-4-fast";
|
|
27
|
+
if (id === "grok-4-1-fast-reasoning") return "grok-4-1-fast";
|
|
28
|
+
if (id === "grok-4.20-experimental-beta-0304-reasoning") return "grok-4.20-beta-latest-reasoning";
|
|
29
|
+
if (id === "grok-4.20-experimental-beta-0304-non-reasoning") return "grok-4.20-beta-latest-non-reasoning";
|
|
30
|
+
if (id === "grok-4.20-reasoning") return "grok-4.20-beta-latest-reasoning";
|
|
31
|
+
if (id === "grok-4.20-non-reasoning") return "grok-4.20-beta-latest-non-reasoning";
|
|
32
|
+
return id;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/model-ref-shared-CWZQlO4A.js
|
|
36
|
+
function normalizeAnthropicModelId(model) {
|
|
37
|
+
const trimmed = model.trim();
|
|
38
|
+
if (!trimmed) return trimmed;
|
|
39
|
+
switch (normalizeLowercaseStringOrEmpty(trimmed)) {
|
|
40
|
+
case "opus-4.6": return "claude-opus-4-6";
|
|
41
|
+
case "opus-4.5": return "claude-opus-4-5";
|
|
42
|
+
case "sonnet-4.6": return "claude-sonnet-4-6";
|
|
43
|
+
case "sonnet-4.5": return "claude-sonnet-4-5";
|
|
44
|
+
default: return trimmed;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function normalizeHuggingfaceModelId(model) {
|
|
48
|
+
const trimmed = model.trim();
|
|
49
|
+
if (!trimmed) return trimmed;
|
|
50
|
+
return normalizeLowercaseStringOrEmpty(trimmed).startsWith("huggingface/") ? trimmed.slice(12) : trimmed;
|
|
51
|
+
}
|
|
52
|
+
function normalizeStaticProviderModelId(provider, model) {
|
|
53
|
+
if (provider === "anthropic") return normalizeAnthropicModelId(model);
|
|
54
|
+
if (provider === "huggingface") return normalizeHuggingfaceModelId(model);
|
|
55
|
+
if (provider === "google" || provider === "google-vertex") return normalizeGooglePreviewModelId(model);
|
|
56
|
+
if (provider === "openrouter" && !model.includes("/")) return `openrouter/${model}`;
|
|
57
|
+
if (provider === "xai") return normalizeNativeXaiModelId(model);
|
|
58
|
+
if (provider === "vercel-ai-gateway" && !model.includes("/")) {
|
|
59
|
+
const normalizedAnthropicModel = normalizeAnthropicModelId(model);
|
|
60
|
+
if (normalizedAnthropicModel.startsWith("claude-")) return `anthropic/${normalizedAnthropicModel}`;
|
|
61
|
+
}
|
|
62
|
+
return model;
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/model-selection-cli-BCNxTSmc.js
|
|
66
|
+
const require$1 = createRequire(import.meta.url);
|
|
67
|
+
const PROVIDER_RUNTIME_CANDIDATES = ["../plugins/provider-runtime.js", "../plugins/provider-runtime.ts"];
|
|
68
|
+
let providerRuntimeModule;
|
|
69
|
+
function loadProviderRuntime$1() {
|
|
70
|
+
if (providerRuntimeModule) return providerRuntimeModule;
|
|
71
|
+
for (const candidate of PROVIDER_RUNTIME_CANDIDATES) try {
|
|
72
|
+
providerRuntimeModule = require$1(candidate);
|
|
73
|
+
return providerRuntimeModule;
|
|
74
|
+
} catch {}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
function normalizeProviderModelIdWithRuntime(params) {
|
|
78
|
+
return loadProviderRuntime$1()?.normalizeProviderModelIdWithPlugin(params);
|
|
79
|
+
}
|
|
80
|
+
function normalizeProviderModelId(provider, model, options) {
|
|
81
|
+
const staticModelId = normalizeStaticProviderModelId(provider, model);
|
|
82
|
+
if (options?.allowPluginNormalization === false) return staticModelId;
|
|
83
|
+
return normalizeProviderModelIdWithRuntime({
|
|
84
|
+
provider,
|
|
85
|
+
context: {
|
|
86
|
+
provider,
|
|
87
|
+
modelId: staticModelId
|
|
88
|
+
}
|
|
89
|
+
}) ?? staticModelId;
|
|
90
|
+
}
|
|
91
|
+
function normalizeModelRef(provider, model, options) {
|
|
92
|
+
const normalizedProvider = normalizeProviderId(provider);
|
|
93
|
+
return {
|
|
94
|
+
provider: normalizedProvider,
|
|
95
|
+
model: normalizeProviderModelId(normalizedProvider, model.trim(), options)
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
createRequire(import.meta.url);
|
|
99
|
+
//#endregion
|
|
100
|
+
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/model-auth-runtime-shared-7xTwSNzs.js
|
|
101
|
+
const AWS_BEARER_ENV = "AWS_BEARER_TOKEN_BEDROCK";
|
|
102
|
+
const AWS_ACCESS_KEY_ENV = "AWS_ACCESS_KEY_ID";
|
|
103
|
+
const AWS_SECRET_KEY_ENV = "AWS_SECRET_ACCESS_KEY";
|
|
104
|
+
const AWS_PROFILE_ENV = "AWS_PROFILE";
|
|
105
|
+
function resolveAwsSdkEnvVarName(env = process.env) {
|
|
106
|
+
if (env[AWS_BEARER_ENV]?.trim()) return AWS_BEARER_ENV;
|
|
107
|
+
if (env[AWS_ACCESS_KEY_ENV]?.trim() && env[AWS_SECRET_KEY_ENV]?.trim()) return AWS_ACCESS_KEY_ENV;
|
|
108
|
+
if (env[AWS_PROFILE_ENV]?.trim()) return AWS_PROFILE_ENV;
|
|
109
|
+
}
|
|
110
|
+
function requireApiKey(auth, provider) {
|
|
111
|
+
const key = normalizeSecretInput(auth.apiKey);
|
|
112
|
+
if (key) return key;
|
|
113
|
+
throw new Error(`No API key resolved for provider "${provider}" (auth mode: ${auth.mode}).`);
|
|
114
|
+
}
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/models-config.providers.secrets-B3EhK11C.js
|
|
117
|
+
const ENV_VAR_NAME_RE = /^[A-Z_][A-Z0-9_]*$/;
|
|
118
|
+
function normalizeApiKeyConfig(value) {
|
|
119
|
+
const trimmed = value.trim();
|
|
120
|
+
return /^\$\{([A-Z0-9_]+)\}$/.exec(trimmed)?.[1] ?? trimmed;
|
|
121
|
+
}
|
|
122
|
+
function toDiscoveryApiKey(value) {
|
|
123
|
+
const trimmed = normalizeOptionalString(value);
|
|
124
|
+
if (!trimmed || isNonSecretApiKeyMarker(trimmed)) return;
|
|
125
|
+
return trimmed;
|
|
126
|
+
}
|
|
127
|
+
function resolveEnvApiKeyVarName(provider, env = process.env) {
|
|
128
|
+
const resolved = resolveEnvApiKey(provider, env);
|
|
129
|
+
if (!resolved) return;
|
|
130
|
+
const match = /^(?:env: |shell env: )([A-Z0-9_]+)$/.exec(resolved.source);
|
|
131
|
+
return match ? match[1] : void 0;
|
|
132
|
+
}
|
|
133
|
+
function resolveAwsSdkApiKeyVarName(env = process.env) {
|
|
134
|
+
return resolveAwsSdkEnvVarName(env);
|
|
135
|
+
}
|
|
136
|
+
function normalizeHeaderValues(params) {
|
|
137
|
+
const { headers } = params;
|
|
138
|
+
if (!headers) return {
|
|
139
|
+
headers,
|
|
140
|
+
mutated: false
|
|
141
|
+
};
|
|
142
|
+
let mutated = false;
|
|
143
|
+
const nextHeaders = {};
|
|
144
|
+
for (const [headerName, headerValue] of Object.entries(headers)) {
|
|
145
|
+
const resolvedRef = resolveSecretInputRef({
|
|
146
|
+
value: headerValue,
|
|
147
|
+
defaults: params.secretDefaults
|
|
148
|
+
}).ref;
|
|
149
|
+
if (!resolvedRef || !resolvedRef.id.trim()) {
|
|
150
|
+
nextHeaders[headerName] = headerValue;
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
mutated = true;
|
|
154
|
+
nextHeaders[headerName] = resolvedRef.source === "env" ? resolveEnvSecretRefHeaderValueMarker(resolvedRef.id) : resolveNonEnvSecretRefHeaderValueMarker(resolvedRef.source);
|
|
155
|
+
}
|
|
156
|
+
if (!mutated) return {
|
|
157
|
+
headers,
|
|
158
|
+
mutated: false
|
|
159
|
+
};
|
|
160
|
+
return {
|
|
161
|
+
headers: nextHeaders,
|
|
162
|
+
mutated: true
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function resolveApiKeyFromCredential(cred, env = process.env) {
|
|
166
|
+
if (!cred) return;
|
|
167
|
+
if (cred.type === "api_key") {
|
|
168
|
+
const keyRef = coerceSecretRef(cred.keyRef);
|
|
169
|
+
if (keyRef && keyRef.id.trim()) {
|
|
170
|
+
if (keyRef.source === "env") {
|
|
171
|
+
const envVar = keyRef.id.trim();
|
|
172
|
+
return {
|
|
173
|
+
apiKey: envVar,
|
|
174
|
+
source: "env-ref",
|
|
175
|
+
discoveryApiKey: toDiscoveryApiKey(env[envVar])
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
apiKey: resolveNonEnvSecretRefApiKeyMarker(keyRef.source),
|
|
180
|
+
source: "non-env-ref"
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
if (cred.key?.trim()) return {
|
|
184
|
+
apiKey: cred.key,
|
|
185
|
+
source: "plaintext",
|
|
186
|
+
discoveryApiKey: toDiscoveryApiKey(cred.key)
|
|
187
|
+
};
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (cred.type === "token") {
|
|
191
|
+
const tokenRef = coerceSecretRef(cred.tokenRef);
|
|
192
|
+
if (tokenRef && tokenRef.id.trim()) {
|
|
193
|
+
if (tokenRef.source === "env") {
|
|
194
|
+
const envVar = tokenRef.id.trim();
|
|
195
|
+
return {
|
|
196
|
+
apiKey: envVar,
|
|
197
|
+
source: "env-ref",
|
|
198
|
+
discoveryApiKey: toDiscoveryApiKey(env[envVar])
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
apiKey: resolveNonEnvSecretRefApiKeyMarker(tokenRef.source),
|
|
203
|
+
source: "non-env-ref"
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
if (cred.token?.trim()) return {
|
|
207
|
+
apiKey: cred.token,
|
|
208
|
+
source: "plaintext",
|
|
209
|
+
discoveryApiKey: toDiscoveryApiKey(cred.token)
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function listAuthProfilesForProvider(store, provider) {
|
|
214
|
+
const providerKey = resolveProviderIdForAuth(provider);
|
|
215
|
+
return Object.entries(store.profiles).filter(([, cred]) => resolveProviderIdForAuth(cred.provider) === providerKey).map(([id]) => id);
|
|
216
|
+
}
|
|
217
|
+
function resolveApiKeyFromProfiles(params) {
|
|
218
|
+
const ids = listAuthProfilesForProvider(params.store, params.provider);
|
|
219
|
+
for (const id of ids) {
|
|
220
|
+
const resolved = resolveApiKeyFromCredential(params.store.profiles[id], params.env);
|
|
221
|
+
if (resolved) return resolved;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function normalizeConfiguredProviderApiKey(params) {
|
|
225
|
+
const configuredApiKey = params.provider.apiKey;
|
|
226
|
+
const configuredApiKeyRef = resolveSecretInputRef({
|
|
227
|
+
value: configuredApiKey,
|
|
228
|
+
defaults: params.secretDefaults
|
|
229
|
+
}).ref;
|
|
230
|
+
if (configuredApiKeyRef && configuredApiKeyRef.id.trim()) {
|
|
231
|
+
const marker = configuredApiKeyRef.source === "env" ? configuredApiKeyRef.id.trim() : resolveNonEnvSecretRefApiKeyMarker(configuredApiKeyRef.source);
|
|
232
|
+
params.secretRefManagedProviders?.add(params.providerKey);
|
|
233
|
+
if (params.provider.apiKey === marker) return params.provider;
|
|
234
|
+
return {
|
|
235
|
+
...params.provider,
|
|
236
|
+
apiKey: marker
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
if (typeof configuredApiKey !== "string") return params.provider;
|
|
240
|
+
const normalizedConfiguredApiKey = normalizeApiKeyConfig(configuredApiKey);
|
|
241
|
+
if (isNonSecretApiKeyMarker(normalizedConfiguredApiKey)) params.secretRefManagedProviders?.add(params.providerKey);
|
|
242
|
+
if (params.profileApiKey && params.profileApiKey.source !== "plaintext" && normalizedConfiguredApiKey === params.profileApiKey.apiKey) params.secretRefManagedProviders?.add(params.providerKey);
|
|
243
|
+
if (normalizedConfiguredApiKey === configuredApiKey) return params.provider;
|
|
244
|
+
return {
|
|
245
|
+
...params.provider,
|
|
246
|
+
apiKey: normalizedConfiguredApiKey
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
function normalizeResolvedEnvApiKey(params) {
|
|
250
|
+
const currentApiKey = params.provider.apiKey;
|
|
251
|
+
if (typeof currentApiKey !== "string" || !currentApiKey.trim() || ENV_VAR_NAME_RE.test(currentApiKey.trim())) return params.provider;
|
|
252
|
+
const envVarName = resolveEnvApiKeyVarName(params.providerKey, params.env);
|
|
253
|
+
if (!envVarName || params.env[envVarName] !== currentApiKey) return params.provider;
|
|
254
|
+
params.secretRefManagedProviders?.add(params.providerKey);
|
|
255
|
+
return {
|
|
256
|
+
...params.provider,
|
|
257
|
+
apiKey: envVarName
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
function resolveMissingProviderApiKey(params) {
|
|
261
|
+
const hasModels = Array.isArray(params.provider.models) && params.provider.models.length > 0;
|
|
262
|
+
const normalizedApiKey = normalizeOptionalSecretInput(params.provider.apiKey);
|
|
263
|
+
const hasConfiguredApiKey = Boolean(normalizedApiKey || params.provider.apiKey);
|
|
264
|
+
if (!hasModels || hasConfiguredApiKey) return params.provider;
|
|
265
|
+
const authMode = params.provider.auth;
|
|
266
|
+
if (params.providerApiKeyResolver && (!authMode || authMode === "aws-sdk")) {
|
|
267
|
+
const resolvedApiKey = params.providerApiKeyResolver(params.env);
|
|
268
|
+
if (!resolvedApiKey) return params.provider;
|
|
269
|
+
return {
|
|
270
|
+
...params.provider,
|
|
271
|
+
apiKey: resolvedApiKey
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
if (authMode === "aws-sdk") {
|
|
275
|
+
const awsEnvVar = resolveAwsSdkApiKeyVarName(params.env);
|
|
276
|
+
if (!awsEnvVar) return params.provider;
|
|
277
|
+
return {
|
|
278
|
+
...params.provider,
|
|
279
|
+
apiKey: awsEnvVar
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
const apiKey = resolveEnvApiKeyVarName(params.providerKey, params.env) ?? params.profileApiKey?.apiKey;
|
|
283
|
+
if (!apiKey?.trim()) return params.provider;
|
|
284
|
+
if (params.profileApiKey && params.profileApiKey.source !== "plaintext") params.secretRefManagedProviders?.add(params.providerKey);
|
|
285
|
+
return {
|
|
286
|
+
...params.provider,
|
|
287
|
+
apiKey
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function resolveAuthProfileStoreInput(input) {
|
|
291
|
+
return typeof input === "function" ? input() : input;
|
|
292
|
+
}
|
|
293
|
+
function createProviderApiKeyResolver(env, authStoreInput, config) {
|
|
294
|
+
return (provider) => {
|
|
295
|
+
const authProvider = resolveProviderIdForAuth(provider, {
|
|
296
|
+
config,
|
|
297
|
+
env
|
|
298
|
+
});
|
|
299
|
+
const envVar = resolveEnvApiKeyVarName(authProvider, env);
|
|
300
|
+
if (envVar) return {
|
|
301
|
+
apiKey: envVar,
|
|
302
|
+
discoveryApiKey: toDiscoveryApiKey(env[envVar])
|
|
303
|
+
};
|
|
304
|
+
const fromConfig = resolveConfigBackedProviderAuth({
|
|
305
|
+
provider: authProvider,
|
|
306
|
+
config
|
|
307
|
+
});
|
|
308
|
+
if (fromConfig?.apiKey) return {
|
|
309
|
+
apiKey: fromConfig.apiKey,
|
|
310
|
+
discoveryApiKey: fromConfig.discoveryApiKey
|
|
311
|
+
};
|
|
312
|
+
const fromProfiles = resolveApiKeyFromProfiles({
|
|
313
|
+
provider: authProvider,
|
|
314
|
+
store: resolveAuthProfileStoreInput(authStoreInput),
|
|
315
|
+
env
|
|
316
|
+
});
|
|
317
|
+
return fromProfiles?.apiKey ? {
|
|
318
|
+
apiKey: fromProfiles.apiKey,
|
|
319
|
+
discoveryApiKey: fromProfiles.discoveryApiKey
|
|
320
|
+
} : {
|
|
321
|
+
apiKey: void 0,
|
|
322
|
+
discoveryApiKey: void 0
|
|
323
|
+
};
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
function createProviderAuthResolver(env, authStoreInput, config) {
|
|
327
|
+
return (provider, options) => {
|
|
328
|
+
const authProvider = resolveProviderIdForAuth(provider, {
|
|
329
|
+
config,
|
|
330
|
+
env
|
|
331
|
+
});
|
|
332
|
+
const authStore = resolveAuthProfileStoreInput(authStoreInput);
|
|
333
|
+
const ids = listAuthProfilesForProvider(authStore, authProvider);
|
|
334
|
+
let oauthCandidate;
|
|
335
|
+
for (const id of ids) {
|
|
336
|
+
const cred = authStore.profiles[id];
|
|
337
|
+
if (!cred) continue;
|
|
338
|
+
if (cred.type === "oauth") {
|
|
339
|
+
oauthCandidate ??= {
|
|
340
|
+
apiKey: options?.oauthMarker,
|
|
341
|
+
discoveryApiKey: toDiscoveryApiKey(cred.access),
|
|
342
|
+
mode: "oauth",
|
|
343
|
+
source: "profile",
|
|
344
|
+
profileId: id
|
|
345
|
+
};
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
const resolved = resolveApiKeyFromCredential(cred, env);
|
|
349
|
+
if (!resolved) continue;
|
|
350
|
+
return {
|
|
351
|
+
apiKey: resolved.apiKey,
|
|
352
|
+
discoveryApiKey: resolved.discoveryApiKey,
|
|
353
|
+
mode: cred.type,
|
|
354
|
+
source: "profile",
|
|
355
|
+
profileId: id
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
if (oauthCandidate) return oauthCandidate;
|
|
359
|
+
const envVar = resolveEnvApiKeyVarName(authProvider, env);
|
|
360
|
+
if (envVar) return {
|
|
361
|
+
apiKey: envVar,
|
|
362
|
+
discoveryApiKey: toDiscoveryApiKey(env[envVar]),
|
|
363
|
+
mode: "api_key",
|
|
364
|
+
source: "env"
|
|
365
|
+
};
|
|
366
|
+
const fromConfig = resolveConfigBackedProviderAuth({
|
|
367
|
+
provider: authProvider,
|
|
368
|
+
config
|
|
369
|
+
});
|
|
370
|
+
if (fromConfig) return {
|
|
371
|
+
apiKey: fromConfig.apiKey,
|
|
372
|
+
discoveryApiKey: fromConfig.discoveryApiKey,
|
|
373
|
+
mode: fromConfig.mode,
|
|
374
|
+
source: "none"
|
|
375
|
+
};
|
|
376
|
+
return {
|
|
377
|
+
apiKey: void 0,
|
|
378
|
+
discoveryApiKey: void 0,
|
|
379
|
+
mode: "none",
|
|
380
|
+
source: "none"
|
|
381
|
+
};
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
function resolveConfigBackedProviderAuth(params) {
|
|
385
|
+
const authProvider = resolveProviderIdForAuth(params.provider, { config: params.config });
|
|
386
|
+
const apiKey = resolveProviderSyntheticAuthWithPlugin({
|
|
387
|
+
provider: authProvider,
|
|
388
|
+
config: params.config,
|
|
389
|
+
context: {
|
|
390
|
+
config: params.config,
|
|
391
|
+
provider: authProvider,
|
|
392
|
+
providerConfig: params.config?.models?.providers?.[authProvider]
|
|
393
|
+
}
|
|
394
|
+
})?.apiKey?.trim();
|
|
395
|
+
if (!apiKey) return;
|
|
396
|
+
return isNonSecretApiKeyMarker(apiKey) ? {
|
|
397
|
+
apiKey,
|
|
398
|
+
discoveryApiKey: toDiscoveryApiKey(apiKey),
|
|
399
|
+
mode: "api_key",
|
|
400
|
+
source: "config"
|
|
401
|
+
} : {
|
|
402
|
+
apiKey: resolveNonEnvSecretRefApiKeyMarker("file"),
|
|
403
|
+
discoveryApiKey: toDiscoveryApiKey(apiKey),
|
|
404
|
+
mode: "api_key",
|
|
405
|
+
source: "config"
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
//#endregion
|
|
409
|
+
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/models-config-BmpSQJQF.js
|
|
410
|
+
const MODELS_JSON_STATE_KEY = Symbol.for("openclaw.modelsJsonState");
|
|
411
|
+
const MODELS_JSON_STATE = (() => {
|
|
412
|
+
const globalState = globalThis;
|
|
413
|
+
if (!globalState[MODELS_JSON_STATE_KEY]) globalState[MODELS_JSON_STATE_KEY] = {
|
|
414
|
+
writeLocks: /* @__PURE__ */ new Map(),
|
|
415
|
+
readyCache: /* @__PURE__ */ new Map()
|
|
416
|
+
};
|
|
417
|
+
return globalState[MODELS_JSON_STATE_KEY];
|
|
418
|
+
})();
|
|
419
|
+
function isPositiveFiniteTokenLimit(value) {
|
|
420
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
421
|
+
}
|
|
422
|
+
function resolvePreferredTokenLimit(params) {
|
|
423
|
+
if (params.explicitPresent && isPositiveFiniteTokenLimit(params.explicitValue)) return params.explicitValue;
|
|
424
|
+
if (isPositiveFiniteTokenLimit(params.implicitValue)) return params.implicitValue;
|
|
425
|
+
return isPositiveFiniteTokenLimit(params.explicitValue) ? params.explicitValue : void 0;
|
|
426
|
+
}
|
|
427
|
+
function getProviderModelId(model) {
|
|
428
|
+
if (!model || typeof model !== "object") return "";
|
|
429
|
+
const id = model.id;
|
|
430
|
+
return normalizeOptionalString(id) ?? "";
|
|
431
|
+
}
|
|
432
|
+
function mergeProviderModels(implicit, explicit) {
|
|
433
|
+
const implicitModels = Array.isArray(implicit.models) ? implicit.models : [];
|
|
434
|
+
const explicitModels = Array.isArray(explicit.models) ? explicit.models : [];
|
|
435
|
+
const implicitHeaders = implicit.headers && typeof implicit.headers === "object" && !Array.isArray(implicit.headers) ? implicit.headers : void 0;
|
|
436
|
+
const explicitHeaders = explicit.headers && typeof explicit.headers === "object" && !Array.isArray(explicit.headers) ? explicit.headers : void 0;
|
|
437
|
+
if (implicitModels.length === 0) return {
|
|
438
|
+
...implicit,
|
|
439
|
+
...explicit,
|
|
440
|
+
...implicitHeaders || explicitHeaders ? { headers: {
|
|
441
|
+
...implicitHeaders,
|
|
442
|
+
...explicitHeaders
|
|
443
|
+
} } : {}
|
|
444
|
+
};
|
|
445
|
+
const implicitById = new Map(implicitModels.map((model) => [getProviderModelId(model), model]).filter(([id]) => Boolean(id)));
|
|
446
|
+
const seen = /* @__PURE__ */ new Set();
|
|
447
|
+
const mergedModels = explicitModels.map((explicitModel) => {
|
|
448
|
+
const id = getProviderModelId(explicitModel);
|
|
449
|
+
if (!id) return explicitModel;
|
|
450
|
+
seen.add(id);
|
|
451
|
+
const implicitModel = implicitById.get(id);
|
|
452
|
+
if (!implicitModel) return explicitModel;
|
|
453
|
+
const contextWindow = resolvePreferredTokenLimit({
|
|
454
|
+
explicitPresent: "contextWindow" in explicitModel,
|
|
455
|
+
explicitValue: explicitModel.contextWindow,
|
|
456
|
+
implicitValue: implicitModel.contextWindow
|
|
457
|
+
});
|
|
458
|
+
const contextTokens = resolvePreferredTokenLimit({
|
|
459
|
+
explicitPresent: "contextTokens" in explicitModel,
|
|
460
|
+
explicitValue: explicitModel.contextTokens,
|
|
461
|
+
implicitValue: implicitModel.contextTokens
|
|
462
|
+
});
|
|
463
|
+
const maxTokens = resolvePreferredTokenLimit({
|
|
464
|
+
explicitPresent: "maxTokens" in explicitModel,
|
|
465
|
+
explicitValue: explicitModel.maxTokens,
|
|
466
|
+
implicitValue: implicitModel.maxTokens
|
|
467
|
+
});
|
|
468
|
+
return Object.assign({}, explicitModel, {
|
|
469
|
+
input: implicitModel.input,
|
|
470
|
+
reasoning: `reasoning` in explicitModel ? explicitModel.reasoning : implicitModel.reasoning
|
|
471
|
+
}, contextWindow === void 0 ? {} : { contextWindow }, contextTokens === void 0 ? {} : { contextTokens }, maxTokens === void 0 ? {} : { maxTokens });
|
|
472
|
+
});
|
|
473
|
+
for (const implicitModel of implicitModels) {
|
|
474
|
+
const id = getProviderModelId(implicitModel);
|
|
475
|
+
if (!id || seen.has(id)) continue;
|
|
476
|
+
seen.add(id);
|
|
477
|
+
mergedModels.push(implicitModel);
|
|
478
|
+
}
|
|
479
|
+
return {
|
|
480
|
+
...implicit,
|
|
481
|
+
...explicit,
|
|
482
|
+
...implicitHeaders || explicitHeaders ? { headers: {
|
|
483
|
+
...implicitHeaders,
|
|
484
|
+
...explicitHeaders
|
|
485
|
+
} } : {},
|
|
486
|
+
models: mergedModels
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
function mergeProviders(params) {
|
|
490
|
+
const out = params.implicit ? { ...params.implicit } : {};
|
|
491
|
+
for (const [key, explicit] of Object.entries(params.explicit ?? {})) {
|
|
492
|
+
const providerKey = normalizeOptionalString(key) ?? "";
|
|
493
|
+
if (!providerKey) continue;
|
|
494
|
+
const implicit = out[providerKey];
|
|
495
|
+
out[providerKey] = implicit ? mergeProviderModels(implicit, explicit) : explicit;
|
|
496
|
+
}
|
|
497
|
+
return out;
|
|
498
|
+
}
|
|
499
|
+
function resolveProviderApi(entry) {
|
|
500
|
+
return normalizeOptionalString(entry?.api);
|
|
501
|
+
}
|
|
502
|
+
function resolveModelApiSurface(entry) {
|
|
503
|
+
if (!Array.isArray(entry?.models)) return;
|
|
504
|
+
const apis = entry.models.flatMap((model) => {
|
|
505
|
+
if (!model || typeof model !== "object") return [];
|
|
506
|
+
const api = model.api;
|
|
507
|
+
const normalized = normalizeOptionalString(api);
|
|
508
|
+
return normalized ? [normalized] : [];
|
|
509
|
+
}).toSorted();
|
|
510
|
+
return apis.length > 0 ? JSON.stringify(apis) : void 0;
|
|
511
|
+
}
|
|
512
|
+
function resolveProviderApiSurface(entry) {
|
|
513
|
+
return resolveProviderApi(entry) ?? resolveModelApiSurface(entry);
|
|
514
|
+
}
|
|
515
|
+
function shouldPreserveExistingApiKey(params) {
|
|
516
|
+
const { providerKey, existing, nextEntry, secretRefManagedProviders } = params;
|
|
517
|
+
const nextApiKey = typeof nextEntry.apiKey === "string" ? nextEntry.apiKey : "";
|
|
518
|
+
if (nextApiKey && isNonSecretApiKeyMarker(nextApiKey)) return false;
|
|
519
|
+
return !secretRefManagedProviders.has(providerKey) && typeof existing.apiKey === "string" && existing.apiKey.length > 0 && !isNonSecretApiKeyMarker(existing.apiKey, { includeEnvVarName: false });
|
|
520
|
+
}
|
|
521
|
+
function shouldPreserveExistingBaseUrl(params) {
|
|
522
|
+
const { existing, nextEntry } = params;
|
|
523
|
+
if (typeof existing.baseUrl !== "string" || existing.baseUrl.length === 0) return false;
|
|
524
|
+
const existingApi = resolveProviderApiSurface(existing);
|
|
525
|
+
const nextApi = resolveProviderApiSurface(nextEntry);
|
|
526
|
+
return !existingApi || !nextApi || existingApi === nextApi;
|
|
527
|
+
}
|
|
528
|
+
function mergeWithExistingProviderSecrets(params) {
|
|
529
|
+
const { nextProviders, existingProviders, secretRefManagedProviders } = params;
|
|
530
|
+
const mergedProviders = {};
|
|
531
|
+
for (const [key, entry] of Object.entries(existingProviders)) mergedProviders[key] = entry;
|
|
532
|
+
for (const [key, newEntry] of Object.entries(nextProviders)) {
|
|
533
|
+
const existing = existingProviders[key];
|
|
534
|
+
if (!existing) {
|
|
535
|
+
mergedProviders[key] = newEntry;
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
const preserved = {};
|
|
539
|
+
if (shouldPreserveExistingApiKey({
|
|
540
|
+
providerKey: key,
|
|
541
|
+
existing,
|
|
542
|
+
nextEntry: newEntry,
|
|
543
|
+
secretRefManagedProviders
|
|
544
|
+
})) preserved.apiKey = existing.apiKey;
|
|
545
|
+
if (shouldPreserveExistingBaseUrl({
|
|
546
|
+
existing,
|
|
547
|
+
nextEntry: newEntry
|
|
548
|
+
})) preserved.baseUrl = existing.baseUrl;
|
|
549
|
+
mergedProviders[key] = {
|
|
550
|
+
...newEntry,
|
|
551
|
+
...preserved
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
return mergedProviders;
|
|
555
|
+
}
|
|
556
|
+
path.resolve(import.meta.dirname, "../..");
|
|
557
|
+
const DISCOVERY_ORDER = [
|
|
558
|
+
"simple",
|
|
559
|
+
"profile",
|
|
560
|
+
"paired",
|
|
561
|
+
"late"
|
|
562
|
+
];
|
|
563
|
+
const DANGEROUS_PROVIDER_KEYS = new Set([
|
|
564
|
+
"__proto__",
|
|
565
|
+
"prototype",
|
|
566
|
+
"constructor"
|
|
567
|
+
]);
|
|
568
|
+
let providerRuntimePromise;
|
|
569
|
+
function loadProviderRuntime() {
|
|
570
|
+
providerRuntimePromise ??= import("./provider-discovery.runtime-BPzz1PFj.mjs");
|
|
571
|
+
return providerRuntimePromise;
|
|
572
|
+
}
|
|
573
|
+
function resolveProviderCatalogHook(provider) {
|
|
574
|
+
return provider.catalog ?? provider.discovery;
|
|
575
|
+
}
|
|
576
|
+
function resolveProviderCatalogOrderHook(provider) {
|
|
577
|
+
return resolveProviderCatalogHook(provider) ?? provider.staticCatalog;
|
|
578
|
+
}
|
|
579
|
+
function createProviderConfigRecord() {
|
|
580
|
+
return Object.create(null);
|
|
581
|
+
}
|
|
582
|
+
function isSafeProviderConfigKey(value) {
|
|
583
|
+
return value !== "" && !DANGEROUS_PROVIDER_KEYS.has(value);
|
|
584
|
+
}
|
|
585
|
+
async function resolvePluginDiscoveryProviders(params) {
|
|
586
|
+
return (await loadProviderRuntime()).resolvePluginDiscoveryProvidersRuntime(params).filter((provider) => resolveProviderCatalogOrderHook(provider));
|
|
587
|
+
}
|
|
588
|
+
function groupPluginDiscoveryProvidersByOrder(providers) {
|
|
589
|
+
const grouped = {
|
|
590
|
+
simple: [],
|
|
591
|
+
profile: [],
|
|
592
|
+
paired: [],
|
|
593
|
+
late: []
|
|
594
|
+
};
|
|
595
|
+
for (const provider of providers) grouped[resolveProviderCatalogOrderHook(provider)?.order ?? "late"].push(provider);
|
|
596
|
+
for (const order of DISCOVERY_ORDER) grouped[order].sort((a, b) => a.label.localeCompare(b.label));
|
|
597
|
+
return grouped;
|
|
598
|
+
}
|
|
599
|
+
function normalizePluginDiscoveryResult(params) {
|
|
600
|
+
const result = params.result;
|
|
601
|
+
if (!result) return {};
|
|
602
|
+
if ("provider" in result) {
|
|
603
|
+
const normalized = createProviderConfigRecord();
|
|
604
|
+
for (const providerId of [
|
|
605
|
+
params.provider.id,
|
|
606
|
+
...params.provider.aliases ?? [],
|
|
607
|
+
...params.provider.hookAliases ?? []
|
|
608
|
+
]) {
|
|
609
|
+
const normalizedKey = normalizeProviderId(providerId);
|
|
610
|
+
if (!isSafeProviderConfigKey(normalizedKey)) continue;
|
|
611
|
+
normalized[normalizedKey] = result.provider;
|
|
612
|
+
}
|
|
613
|
+
return normalized;
|
|
614
|
+
}
|
|
615
|
+
const normalized = createProviderConfigRecord();
|
|
616
|
+
for (const [key, value] of Object.entries(result.providers)) {
|
|
617
|
+
const normalizedKey = normalizeProviderId(key);
|
|
618
|
+
if (!isSafeProviderConfigKey(normalizedKey) || !value) continue;
|
|
619
|
+
normalized[normalizedKey] = value;
|
|
620
|
+
}
|
|
621
|
+
return normalized;
|
|
622
|
+
}
|
|
623
|
+
function runProviderCatalog(params) {
|
|
624
|
+
return resolveProviderCatalogHook(params.provider)?.run({
|
|
625
|
+
config: params.config,
|
|
626
|
+
agentDir: params.agentDir,
|
|
627
|
+
workspaceDir: params.workspaceDir,
|
|
628
|
+
env: params.env,
|
|
629
|
+
resolveProviderApiKey: params.resolveProviderApiKey,
|
|
630
|
+
resolveProviderAuth: params.resolveProviderAuth
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
const log = createSubsystemLogger("agents/model-providers");
|
|
634
|
+
const PROVIDER_IMPLICIT_MERGERS = { ollama: ({ implicit }) => implicit };
|
|
635
|
+
const PLUGIN_DISCOVERY_ORDERS = [
|
|
636
|
+
"simple",
|
|
637
|
+
"profile",
|
|
638
|
+
"paired",
|
|
639
|
+
"late"
|
|
640
|
+
];
|
|
641
|
+
function resolveLiveProviderCatalogTimeoutMs(env) {
|
|
642
|
+
if (!(env.OPENCLAW_LIVE_TEST === "1" || env.OPENCLAW_LIVE_GATEWAY === "1" || env.LIVE === "1")) return null;
|
|
643
|
+
const raw = env.OPENCLAW_LIVE_PROVIDER_DISCOVERY_TIMEOUT_MS?.trim();
|
|
644
|
+
if (!raw) return 15e3;
|
|
645
|
+
const parsed = Number.parseInt(raw, 10);
|
|
646
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 15e3;
|
|
647
|
+
}
|
|
648
|
+
function resolveProviderDiscoveryFilter(params) {
|
|
649
|
+
const { config, workspaceDir, env } = params;
|
|
650
|
+
const testRaw = env.OPENCLAW_TEST_ONLY_PROVIDER_PLUGIN_IDS?.trim();
|
|
651
|
+
if (testRaw) {
|
|
652
|
+
const ids = testRaw.split(",").map((value) => value.trim()).filter(Boolean);
|
|
653
|
+
return ids.length > 0 ? [...new Set(ids)] : void 0;
|
|
654
|
+
}
|
|
655
|
+
if (!(env.OPENCLAW_LIVE_TEST === "1" || env.OPENCLAW_LIVE_GATEWAY === "1" || env.LIVE === "1")) return;
|
|
656
|
+
const rawValues = [env.OPENCLAW_LIVE_PROVIDERS?.trim(), env.OPENCLAW_LIVE_GATEWAY_PROVIDERS?.trim()].filter((value) => Boolean(value && value !== "all"));
|
|
657
|
+
if (rawValues.length === 0) return;
|
|
658
|
+
const ids = rawValues.flatMap((value) => value.split(",")).map((value) => value.trim()).filter(Boolean);
|
|
659
|
+
if (ids.length === 0) return;
|
|
660
|
+
const pluginIds = /* @__PURE__ */ new Set();
|
|
661
|
+
for (const id of ids) {
|
|
662
|
+
const owners = resolveOwningPluginIdsForProvider({
|
|
663
|
+
provider: id,
|
|
664
|
+
config,
|
|
665
|
+
workspaceDir,
|
|
666
|
+
env
|
|
667
|
+
}) ?? [];
|
|
668
|
+
if (owners.length > 0) {
|
|
669
|
+
for (const owner of owners) pluginIds.add(owner);
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
pluginIds.add(id);
|
|
673
|
+
}
|
|
674
|
+
return pluginIds.size > 0 ? [...pluginIds].toSorted((left, right) => left.localeCompare(right)) : void 0;
|
|
675
|
+
}
|
|
676
|
+
function mergeImplicitProviderSet(target, additions) {
|
|
677
|
+
if (!additions) return;
|
|
678
|
+
for (const [key, value] of Object.entries(additions)) target[key] = value;
|
|
679
|
+
}
|
|
680
|
+
function mergeImplicitProviderConfig(params) {
|
|
681
|
+
const { providerId, existing, implicit } = params;
|
|
682
|
+
if (!existing) return implicit;
|
|
683
|
+
const merge = PROVIDER_IMPLICIT_MERGERS[providerId];
|
|
684
|
+
if (merge) return merge({
|
|
685
|
+
existing,
|
|
686
|
+
implicit
|
|
687
|
+
});
|
|
688
|
+
return {
|
|
689
|
+
...implicit,
|
|
690
|
+
...existing,
|
|
691
|
+
models: Array.isArray(existing.models) && existing.models.length > 0 ? existing.models : implicit.models
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
function resolveConfiguredImplicitProvider(params) {
|
|
695
|
+
for (const providerId of params.providerIds) {
|
|
696
|
+
const configured = findNormalizedProviderValue(params.configuredProviders ?? void 0, providerId);
|
|
697
|
+
if (configured) return configured;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
function resolveExistingImplicitProviderFromContext(params) {
|
|
701
|
+
return resolveConfiguredImplicitProvider({
|
|
702
|
+
configuredProviders: params.ctx.explicitProviders,
|
|
703
|
+
providerIds: params.providerIds
|
|
704
|
+
}) ?? resolveConfiguredImplicitProvider({
|
|
705
|
+
configuredProviders: params.ctx.config?.models?.providers,
|
|
706
|
+
providerIds: params.providerIds
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
async function resolvePluginImplicitProviders(ctx, providers, order) {
|
|
710
|
+
const byOrder = groupPluginDiscoveryProvidersByOrder(providers);
|
|
711
|
+
const discovered = {};
|
|
712
|
+
const catalogConfig = buildPluginCatalogConfig(ctx);
|
|
713
|
+
for (const provider of byOrder[order]) {
|
|
714
|
+
const resolveCatalogProviderApiKey = (providerId) => {
|
|
715
|
+
const resolvedProviderId = providerId?.trim() || provider.id;
|
|
716
|
+
const resolved = ctx.resolveProviderApiKey(resolvedProviderId);
|
|
717
|
+
if (resolved.apiKey) return resolved;
|
|
718
|
+
if (!findNormalizedProviderValue({
|
|
719
|
+
[provider.id]: true,
|
|
720
|
+
...Object.fromEntries((provider.aliases ?? []).map((alias) => [alias, true])),
|
|
721
|
+
...Object.fromEntries((provider.hookAliases ?? []).map((alias) => [alias, true]))
|
|
722
|
+
}, resolvedProviderId)) return resolved;
|
|
723
|
+
const syntheticApiKey = (provider.resolveSyntheticAuth?.({
|
|
724
|
+
config: catalogConfig,
|
|
725
|
+
provider: resolvedProviderId,
|
|
726
|
+
providerConfig: catalogConfig.models?.providers?.[resolvedProviderId]
|
|
727
|
+
}))?.apiKey?.trim();
|
|
728
|
+
if (!syntheticApiKey) return resolved;
|
|
729
|
+
return {
|
|
730
|
+
apiKey: isNonSecretApiKeyMarker(syntheticApiKey) ? syntheticApiKey : resolveNonEnvSecretRefApiKeyMarker("file"),
|
|
731
|
+
discoveryApiKey: void 0
|
|
732
|
+
};
|
|
733
|
+
};
|
|
734
|
+
const result = await runProviderCatalogWithTimeout({
|
|
735
|
+
provider,
|
|
736
|
+
config: catalogConfig,
|
|
737
|
+
agentDir: ctx.agentDir,
|
|
738
|
+
workspaceDir: ctx.workspaceDir,
|
|
739
|
+
env: ctx.env,
|
|
740
|
+
resolveProviderApiKey: resolveCatalogProviderApiKey,
|
|
741
|
+
resolveProviderAuth: (providerId, options) => ctx.resolveProviderAuth(providerId?.trim() || provider.id, options),
|
|
742
|
+
timeoutMs: resolveLiveProviderCatalogTimeoutMs(ctx.env)
|
|
743
|
+
});
|
|
744
|
+
if (!result) continue;
|
|
745
|
+
const normalizedResult = normalizePluginDiscoveryResult({
|
|
746
|
+
provider,
|
|
747
|
+
result
|
|
748
|
+
});
|
|
749
|
+
for (const [providerId, implicitProvider] of Object.entries(normalizedResult)) discovered[providerId] = mergeImplicitProviderConfig({
|
|
750
|
+
providerId,
|
|
751
|
+
existing: discovered[providerId] ?? resolveExistingImplicitProviderFromContext({
|
|
752
|
+
ctx,
|
|
753
|
+
providerIds: [
|
|
754
|
+
providerId,
|
|
755
|
+
provider.id,
|
|
756
|
+
...provider.aliases ?? [],
|
|
757
|
+
...provider.hookAliases ?? []
|
|
758
|
+
]
|
|
759
|
+
}),
|
|
760
|
+
implicit: implicitProvider
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
return Object.keys(discovered).length > 0 ? discovered : void 0;
|
|
764
|
+
}
|
|
765
|
+
function buildPluginCatalogConfig(ctx) {
|
|
766
|
+
if (!ctx.explicitProviders || Object.keys(ctx.explicitProviders).length === 0) return ctx.config ?? {};
|
|
767
|
+
return {
|
|
768
|
+
...ctx.config,
|
|
769
|
+
models: {
|
|
770
|
+
...ctx.config?.models,
|
|
771
|
+
providers: {
|
|
772
|
+
...ctx.config?.models?.providers,
|
|
773
|
+
...ctx.explicitProviders
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
async function runProviderCatalogWithTimeout(params) {
|
|
779
|
+
const catalogRun = runProviderCatalog(params);
|
|
780
|
+
const timeoutMs = params.timeoutMs ?? void 0;
|
|
781
|
+
if (!timeoutMs) return await catalogRun;
|
|
782
|
+
let timer;
|
|
783
|
+
try {
|
|
784
|
+
return await Promise.race([catalogRun, new Promise((_, reject) => {
|
|
785
|
+
timer = setTimeout(() => {
|
|
786
|
+
reject(/* @__PURE__ */ new Error(`provider catalog timed out after ${timeoutMs}ms: ${params.provider.id}`));
|
|
787
|
+
}, timeoutMs);
|
|
788
|
+
timer.unref?.();
|
|
789
|
+
})]);
|
|
790
|
+
} catch (error) {
|
|
791
|
+
const message = formatErrorMessage(error);
|
|
792
|
+
if (message.includes("provider catalog timed out after")) {
|
|
793
|
+
log.warn(`${message}; skipping provider discovery`);
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
throw error;
|
|
797
|
+
} finally {
|
|
798
|
+
if (timer) clearTimeout(timer);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
async function resolveImplicitProviders(params) {
|
|
802
|
+
const providers = {};
|
|
803
|
+
const env = params.env ?? process.env;
|
|
804
|
+
let authStore;
|
|
805
|
+
const getAuthStore = () => authStore ??= ensureAuthProfileStore(params.agentDir, { allowKeychainPrompt: false });
|
|
806
|
+
const context = {
|
|
807
|
+
...params,
|
|
808
|
+
get authStore() {
|
|
809
|
+
return getAuthStore();
|
|
810
|
+
},
|
|
811
|
+
env,
|
|
812
|
+
resolveProviderApiKey: createProviderApiKeyResolver(env, getAuthStore, params.config),
|
|
813
|
+
resolveProviderAuth: createProviderAuthResolver(env, getAuthStore, params.config)
|
|
814
|
+
};
|
|
815
|
+
const discoveryProviders = await resolvePluginDiscoveryProviders({
|
|
816
|
+
config: params.config,
|
|
817
|
+
workspaceDir: params.workspaceDir,
|
|
818
|
+
env,
|
|
819
|
+
onlyPluginIds: resolveProviderDiscoveryFilter({
|
|
820
|
+
config: params.config,
|
|
821
|
+
workspaceDir: params.workspaceDir,
|
|
822
|
+
env
|
|
823
|
+
})
|
|
824
|
+
});
|
|
825
|
+
for (const order of PLUGIN_DISCOVERY_ORDERS) mergeImplicitProviderSet(providers, await resolvePluginImplicitProviders(context, discoveryProviders, order));
|
|
826
|
+
return providers;
|
|
827
|
+
}
|
|
828
|
+
const GENERIC_PROVIDER_APIS = new Set([
|
|
829
|
+
"openai-completions",
|
|
830
|
+
"openai-responses",
|
|
831
|
+
"anthropic-messages",
|
|
832
|
+
"google-generative-ai"
|
|
833
|
+
]);
|
|
834
|
+
function resolveProviderPluginLookupKey(providerKey, provider) {
|
|
835
|
+
const api = normalizeOptionalString(provider?.api) ?? "";
|
|
836
|
+
if (providerKey === "google-antigravity" || providerKey === "google-vertex" || api === "google-generative-ai") return "google";
|
|
837
|
+
if (provider?.models?.some((model) => normalizeOptionalString(model.api) === "google-generative-ai")) return "google";
|
|
838
|
+
if (api && MODEL_APIS.includes(api) && !GENERIC_PROVIDER_APIS.has(api)) return api;
|
|
839
|
+
return providerKey;
|
|
840
|
+
}
|
|
841
|
+
function applyProviderNativeStreamingUsagePolicy(providerKey, provider) {
|
|
842
|
+
return applyProviderNativeStreamingUsageCompatWithPlugin({
|
|
843
|
+
provider: resolveProviderPluginLookupKey(providerKey, provider),
|
|
844
|
+
context: {
|
|
845
|
+
provider: providerKey,
|
|
846
|
+
providerConfig: provider
|
|
847
|
+
}
|
|
848
|
+
}) ?? provider;
|
|
849
|
+
}
|
|
850
|
+
function normalizeProviderConfigPolicy(providerKey, provider) {
|
|
851
|
+
return normalizeProviderConfigWithPlugin({
|
|
852
|
+
provider: resolveProviderPluginLookupKey(providerKey, provider),
|
|
853
|
+
context: {
|
|
854
|
+
provider: providerKey,
|
|
855
|
+
providerConfig: provider
|
|
856
|
+
}
|
|
857
|
+
}) ?? provider;
|
|
858
|
+
}
|
|
859
|
+
function resolveProviderConfigApiKeyPolicy(providerKey, provider) {
|
|
860
|
+
const runtimeProviderKey = resolveProviderPluginLookupKey(providerKey, provider).trim();
|
|
861
|
+
return (env) => resolveProviderConfigApiKeyWithPlugin({
|
|
862
|
+
provider: runtimeProviderKey,
|
|
863
|
+
context: {
|
|
864
|
+
provider: providerKey,
|
|
865
|
+
env
|
|
866
|
+
}
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
function applyNativeStreamingUsageCompat(providers) {
|
|
870
|
+
let changed = false;
|
|
871
|
+
const nextProviders = {};
|
|
872
|
+
for (const [providerKey, provider] of Object.entries(providers)) {
|
|
873
|
+
const nextProvider = applyProviderNativeStreamingUsagePolicy(providerKey, provider);
|
|
874
|
+
nextProviders[providerKey] = nextProvider;
|
|
875
|
+
changed ||= nextProvider !== provider;
|
|
876
|
+
}
|
|
877
|
+
return changed ? nextProviders : providers;
|
|
878
|
+
}
|
|
879
|
+
function normalizeProviderSpecificConfig(providerKey, provider) {
|
|
880
|
+
const normalized = normalizeProviderConfigPolicy(providerKey, provider);
|
|
881
|
+
if (normalized && normalized !== provider) return normalized;
|
|
882
|
+
return provider;
|
|
883
|
+
}
|
|
884
|
+
function resolveProviderConfigApiKeyResolver(providerKey, provider) {
|
|
885
|
+
return resolveProviderConfigApiKeyPolicy(providerKey, provider);
|
|
886
|
+
}
|
|
887
|
+
function normalizeSourceProviderLookup(providers) {
|
|
888
|
+
if (!providers) return {};
|
|
889
|
+
const out = {};
|
|
890
|
+
for (const [key, provider] of Object.entries(providers)) {
|
|
891
|
+
const normalizedKey = key.trim();
|
|
892
|
+
if (!normalizedKey || !isRecord(provider)) continue;
|
|
893
|
+
out[normalizedKey] = provider;
|
|
894
|
+
}
|
|
895
|
+
return out;
|
|
896
|
+
}
|
|
897
|
+
function resolveSourceManagedApiKeyMarker(params) {
|
|
898
|
+
const sourceApiKeyRef = resolveSecretInputRef({
|
|
899
|
+
value: params.sourceProvider?.apiKey,
|
|
900
|
+
defaults: params.sourceSecretDefaults
|
|
901
|
+
}).ref;
|
|
902
|
+
if (!sourceApiKeyRef || !sourceApiKeyRef.id.trim()) return;
|
|
903
|
+
return sourceApiKeyRef.source === "env" ? sourceApiKeyRef.id.trim() : resolveNonEnvSecretRefApiKeyMarker(sourceApiKeyRef.source);
|
|
904
|
+
}
|
|
905
|
+
function resolveSourceManagedHeaderMarkers(params) {
|
|
906
|
+
const sourceHeaders = isRecord(params.sourceProvider?.headers) ? params.sourceProvider.headers : void 0;
|
|
907
|
+
if (!sourceHeaders) return {};
|
|
908
|
+
const markers = {};
|
|
909
|
+
for (const [headerName, headerValue] of Object.entries(sourceHeaders)) {
|
|
910
|
+
const sourceHeaderRef = resolveSecretInputRef({
|
|
911
|
+
value: headerValue,
|
|
912
|
+
defaults: params.sourceSecretDefaults
|
|
913
|
+
}).ref;
|
|
914
|
+
if (!sourceHeaderRef || !sourceHeaderRef.id.trim()) continue;
|
|
915
|
+
markers[headerName] = sourceHeaderRef.source === "env" ? resolveEnvSecretRefHeaderValueMarker(sourceHeaderRef.id) : resolveNonEnvSecretRefHeaderValueMarker(sourceHeaderRef.source);
|
|
916
|
+
}
|
|
917
|
+
return markers;
|
|
918
|
+
}
|
|
919
|
+
function enforceSourceManagedProviderSecrets(params) {
|
|
920
|
+
const { providers } = params;
|
|
921
|
+
if (!providers) return providers;
|
|
922
|
+
const sourceProvidersByKey = normalizeSourceProviderLookup(params.sourceProviders);
|
|
923
|
+
if (Object.keys(sourceProvidersByKey).length === 0) return providers;
|
|
924
|
+
let nextProviders = null;
|
|
925
|
+
for (const [providerKey, provider] of Object.entries(providers)) {
|
|
926
|
+
if (!isRecord(provider)) continue;
|
|
927
|
+
const sourceProvider = sourceProvidersByKey[providerKey.trim()];
|
|
928
|
+
if (!sourceProvider) continue;
|
|
929
|
+
let nextProvider = provider;
|
|
930
|
+
let providerMutated = false;
|
|
931
|
+
const sourceApiKeyMarker = resolveSourceManagedApiKeyMarker({
|
|
932
|
+
sourceProvider,
|
|
933
|
+
sourceSecretDefaults: params.sourceSecretDefaults
|
|
934
|
+
});
|
|
935
|
+
if (sourceApiKeyMarker) {
|
|
936
|
+
params.secretRefManagedProviders?.add(providerKey.trim());
|
|
937
|
+
if (nextProvider.apiKey !== sourceApiKeyMarker) {
|
|
938
|
+
providerMutated = true;
|
|
939
|
+
nextProvider = {
|
|
940
|
+
...nextProvider,
|
|
941
|
+
apiKey: sourceApiKeyMarker
|
|
942
|
+
};
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
const sourceHeaderMarkers = resolveSourceManagedHeaderMarkers({
|
|
946
|
+
sourceProvider,
|
|
947
|
+
sourceSecretDefaults: params.sourceSecretDefaults
|
|
948
|
+
});
|
|
949
|
+
if (Object.keys(sourceHeaderMarkers).length > 0) {
|
|
950
|
+
const currentHeaders = isRecord(nextProvider.headers) ? nextProvider.headers : void 0;
|
|
951
|
+
const nextHeaders = { ...currentHeaders };
|
|
952
|
+
let headersMutated = !currentHeaders;
|
|
953
|
+
for (const [headerName, marker] of Object.entries(sourceHeaderMarkers)) {
|
|
954
|
+
if (nextHeaders[headerName] === marker) continue;
|
|
955
|
+
headersMutated = true;
|
|
956
|
+
nextHeaders[headerName] = marker;
|
|
957
|
+
}
|
|
958
|
+
if (headersMutated) {
|
|
959
|
+
providerMutated = true;
|
|
960
|
+
nextProvider = {
|
|
961
|
+
...nextProvider,
|
|
962
|
+
headers: nextHeaders
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
if (!providerMutated) continue;
|
|
967
|
+
if (!nextProviders) nextProviders = { ...providers };
|
|
968
|
+
nextProviders[providerKey] = nextProvider;
|
|
969
|
+
}
|
|
970
|
+
return nextProviders ?? providers;
|
|
971
|
+
}
|
|
972
|
+
function normalizeProviders(params) {
|
|
973
|
+
const { providers } = params;
|
|
974
|
+
if (!providers) return providers;
|
|
975
|
+
const env = params.env ?? process.env;
|
|
976
|
+
let authStore;
|
|
977
|
+
const resolveProfileApiKey = (providerKey) => {
|
|
978
|
+
authStore ??= ensureAuthProfileStore(params.agentDir, { allowKeychainPrompt: false });
|
|
979
|
+
return resolveApiKeyFromProfiles({
|
|
980
|
+
provider: providerKey,
|
|
981
|
+
store: authStore,
|
|
982
|
+
env
|
|
983
|
+
});
|
|
984
|
+
};
|
|
985
|
+
let mutated = false;
|
|
986
|
+
const next = {};
|
|
987
|
+
for (const [key, provider] of Object.entries(providers)) {
|
|
988
|
+
const normalizedKey = key.trim();
|
|
989
|
+
if (!normalizedKey) {
|
|
990
|
+
mutated = true;
|
|
991
|
+
continue;
|
|
992
|
+
}
|
|
993
|
+
if (normalizedKey !== key) mutated = true;
|
|
994
|
+
let normalizedProvider = provider;
|
|
995
|
+
const normalizedHeaders = normalizeHeaderValues({
|
|
996
|
+
headers: normalizedProvider.headers,
|
|
997
|
+
secretDefaults: params.secretDefaults
|
|
998
|
+
});
|
|
999
|
+
if (normalizedHeaders.mutated) {
|
|
1000
|
+
mutated = true;
|
|
1001
|
+
normalizedProvider = {
|
|
1002
|
+
...normalizedProvider,
|
|
1003
|
+
headers: normalizedHeaders.headers
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
const providerWithConfiguredApiKey = normalizeConfiguredProviderApiKey({
|
|
1007
|
+
providerKey: normalizedKey,
|
|
1008
|
+
provider: normalizedProvider,
|
|
1009
|
+
secretDefaults: params.secretDefaults,
|
|
1010
|
+
profileApiKey: void 0,
|
|
1011
|
+
secretRefManagedProviders: params.secretRefManagedProviders
|
|
1012
|
+
});
|
|
1013
|
+
if (providerWithConfiguredApiKey !== normalizedProvider) {
|
|
1014
|
+
mutated = true;
|
|
1015
|
+
normalizedProvider = providerWithConfiguredApiKey;
|
|
1016
|
+
}
|
|
1017
|
+
const providerWithResolvedEnvApiKey = normalizeResolvedEnvApiKey({
|
|
1018
|
+
providerKey: normalizedKey,
|
|
1019
|
+
provider: normalizedProvider,
|
|
1020
|
+
env,
|
|
1021
|
+
secretRefManagedProviders: params.secretRefManagedProviders
|
|
1022
|
+
});
|
|
1023
|
+
if (providerWithResolvedEnvApiKey !== normalizedProvider) {
|
|
1024
|
+
mutated = true;
|
|
1025
|
+
normalizedProvider = providerWithResolvedEnvApiKey;
|
|
1026
|
+
}
|
|
1027
|
+
const needsProfileApiKey = Array.isArray(normalizedProvider.models) && normalizedProvider.models.length > 0 && !(typeof normalizedProvider.apiKey === "string" && normalizedProvider.apiKey.trim() || normalizedProvider.apiKey);
|
|
1028
|
+
const profileApiKey = needsProfileApiKey ? resolveProfileApiKey(normalizedKey) : void 0;
|
|
1029
|
+
const providerApiKeyResolver = needsProfileApiKey ? resolveProviderConfigApiKeyResolver(normalizedKey) : void 0;
|
|
1030
|
+
const providerWithApiKey = resolveMissingProviderApiKey({
|
|
1031
|
+
providerKey: normalizedKey,
|
|
1032
|
+
provider: normalizedProvider,
|
|
1033
|
+
env,
|
|
1034
|
+
profileApiKey,
|
|
1035
|
+
secretRefManagedProviders: params.secretRefManagedProviders,
|
|
1036
|
+
providerApiKeyResolver
|
|
1037
|
+
});
|
|
1038
|
+
if (providerWithApiKey !== normalizedProvider) {
|
|
1039
|
+
mutated = true;
|
|
1040
|
+
normalizedProvider = providerWithApiKey;
|
|
1041
|
+
}
|
|
1042
|
+
const providerSpecificNormalized = normalizeProviderSpecificConfig(normalizedKey, normalizedProvider);
|
|
1043
|
+
if (providerSpecificNormalized !== normalizedProvider) {
|
|
1044
|
+
mutated = true;
|
|
1045
|
+
normalizedProvider = providerSpecificNormalized;
|
|
1046
|
+
}
|
|
1047
|
+
const existing = next[normalizedKey];
|
|
1048
|
+
if (existing) {
|
|
1049
|
+
mutated = true;
|
|
1050
|
+
next[normalizedKey] = {
|
|
1051
|
+
...existing,
|
|
1052
|
+
...normalizedProvider,
|
|
1053
|
+
models: normalizedProvider.models ?? existing.models
|
|
1054
|
+
};
|
|
1055
|
+
continue;
|
|
1056
|
+
}
|
|
1057
|
+
next[normalizedKey] = normalizedProvider;
|
|
1058
|
+
}
|
|
1059
|
+
return enforceSourceManagedProviderSecrets({
|
|
1060
|
+
providers: mutated ? next : providers,
|
|
1061
|
+
sourceProviders: params.sourceProviders,
|
|
1062
|
+
sourceSecretDefaults: params.sourceSecretDefaults,
|
|
1063
|
+
secretRefManagedProviders: params.secretRefManagedProviders
|
|
1064
|
+
});
|
|
1065
|
+
}
|
|
1066
|
+
async function resolveProvidersForModelsJsonWithDeps(params, deps) {
|
|
1067
|
+
const { cfg, agentDir, env } = params;
|
|
1068
|
+
const explicitProviders = cfg.models?.providers ?? {};
|
|
1069
|
+
return mergeProviders({
|
|
1070
|
+
implicit: await (deps?.resolveImplicitProviders ?? resolveImplicitProviders)({
|
|
1071
|
+
agentDir,
|
|
1072
|
+
config: cfg,
|
|
1073
|
+
env,
|
|
1074
|
+
explicitProviders
|
|
1075
|
+
}),
|
|
1076
|
+
explicit: explicitProviders
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1079
|
+
function resolveProvidersForMode(params) {
|
|
1080
|
+
if (params.mode !== "merge") return params.providers;
|
|
1081
|
+
const existing = params.existingParsed;
|
|
1082
|
+
if (!isRecord(existing) || !isRecord(existing.providers)) return params.providers;
|
|
1083
|
+
const existingProviders = existing.providers;
|
|
1084
|
+
return mergeWithExistingProviderSecrets({
|
|
1085
|
+
nextProviders: params.providers,
|
|
1086
|
+
existingProviders,
|
|
1087
|
+
secretRefManagedProviders: params.secretRefManagedProviders
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
async function planOpenClawModelsJsonWithDeps(params, deps) {
|
|
1091
|
+
const { cfg, agentDir, env } = params;
|
|
1092
|
+
const providers = await resolveProvidersForModelsJsonWithDeps({
|
|
1093
|
+
cfg,
|
|
1094
|
+
agentDir,
|
|
1095
|
+
env
|
|
1096
|
+
}, deps);
|
|
1097
|
+
if (Object.keys(providers).length === 0) return { action: "skip" };
|
|
1098
|
+
const mode = cfg.models?.mode ?? "merge";
|
|
1099
|
+
const secretRefManagedProviders = /* @__PURE__ */ new Set();
|
|
1100
|
+
const normalizedProviders = normalizeProviders({
|
|
1101
|
+
providers,
|
|
1102
|
+
agentDir,
|
|
1103
|
+
env,
|
|
1104
|
+
secretDefaults: cfg.secrets?.defaults,
|
|
1105
|
+
sourceProviders: params.sourceConfigForSecrets?.models?.providers,
|
|
1106
|
+
sourceSecretDefaults: params.sourceConfigForSecrets?.secrets?.defaults,
|
|
1107
|
+
secretRefManagedProviders
|
|
1108
|
+
}) ?? providers;
|
|
1109
|
+
const mergedProviders = resolveProvidersForMode({
|
|
1110
|
+
mode,
|
|
1111
|
+
existingParsed: params.existingParsed,
|
|
1112
|
+
providers: normalizedProviders,
|
|
1113
|
+
secretRefManagedProviders
|
|
1114
|
+
});
|
|
1115
|
+
const finalProviders = applyNativeStreamingUsageCompat(enforceSourceManagedProviderSecrets({
|
|
1116
|
+
providers: mergedProviders,
|
|
1117
|
+
sourceProviders: params.sourceConfigForSecrets?.models?.providers,
|
|
1118
|
+
sourceSecretDefaults: params.sourceConfigForSecrets?.secrets?.defaults,
|
|
1119
|
+
secretRefManagedProviders
|
|
1120
|
+
}) ?? mergedProviders);
|
|
1121
|
+
const nextContents = `${JSON.stringify({ providers: finalProviders }, null, 2)}\n`;
|
|
1122
|
+
if (params.existingRaw === nextContents) return { action: "noop" };
|
|
1123
|
+
return {
|
|
1124
|
+
action: "write",
|
|
1125
|
+
contents: nextContents
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
async function planOpenClawModelsJson(params) {
|
|
1129
|
+
return planOpenClawModelsJsonWithDeps(params);
|
|
1130
|
+
}
|
|
1131
|
+
async function readFileMtimeMs(pathname) {
|
|
1132
|
+
try {
|
|
1133
|
+
const stat = await fs.stat(pathname);
|
|
1134
|
+
return Number.isFinite(stat.mtimeMs) ? stat.mtimeMs : null;
|
|
1135
|
+
} catch {
|
|
1136
|
+
return null;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
function stableStringify(value) {
|
|
1140
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
1141
|
+
if (Array.isArray(value)) return `[${value.map((entry) => stableStringify(entry)).join(",")}]`;
|
|
1142
|
+
return `{${Object.entries(value).toSorted(([a], [b]) => a.localeCompare(b)).map(([key, entry]) => `${JSON.stringify(key)}:${stableStringify(entry)}`).join(",")}}`;
|
|
1143
|
+
}
|
|
1144
|
+
async function buildModelsJsonFingerprint(params) {
|
|
1145
|
+
const authProfilesMtimeMs = await readFileMtimeMs(path.join(params.agentDir, "auth-profiles.json"));
|
|
1146
|
+
const modelsFileMtimeMs = await readFileMtimeMs(path.join(params.agentDir, "models.json"));
|
|
1147
|
+
const envShape = createConfigRuntimeEnv(params.config, {});
|
|
1148
|
+
return stableStringify({
|
|
1149
|
+
config: params.config,
|
|
1150
|
+
sourceConfigForSecrets: params.sourceConfigForSecrets,
|
|
1151
|
+
envShape,
|
|
1152
|
+
authProfilesMtimeMs,
|
|
1153
|
+
modelsFileMtimeMs
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
async function readExistingModelsFile(pathname) {
|
|
1157
|
+
try {
|
|
1158
|
+
const raw = await fs.readFile(pathname, "utf8");
|
|
1159
|
+
return {
|
|
1160
|
+
raw,
|
|
1161
|
+
parsed: JSON.parse(raw)
|
|
1162
|
+
};
|
|
1163
|
+
} catch {
|
|
1164
|
+
return {
|
|
1165
|
+
raw: "",
|
|
1166
|
+
parsed: null
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
async function ensureModelsFileModeForModelsJson(pathname) {
|
|
1171
|
+
await fs.chmod(pathname, 384).catch(() => {});
|
|
1172
|
+
}
|
|
1173
|
+
async function writeModelsFileAtomicForModelsJson(targetPath, contents) {
|
|
1174
|
+
const tempPath = `${targetPath}.${process.pid}.${Date.now()}.tmp`;
|
|
1175
|
+
await fs.writeFile(tempPath, contents, { mode: 384 });
|
|
1176
|
+
await fs.rename(tempPath, targetPath);
|
|
1177
|
+
}
|
|
1178
|
+
function resolveModelsConfigInput(config) {
|
|
1179
|
+
const runtimeSource = getRuntimeConfigSourceSnapshot();
|
|
1180
|
+
if (!config) {
|
|
1181
|
+
const loaded = loadConfig();
|
|
1182
|
+
return {
|
|
1183
|
+
config: runtimeSource ?? loaded,
|
|
1184
|
+
sourceConfigForSecrets: runtimeSource ?? loaded
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
1187
|
+
if (!runtimeSource) return {
|
|
1188
|
+
config,
|
|
1189
|
+
sourceConfigForSecrets: config
|
|
1190
|
+
};
|
|
1191
|
+
const projected = projectConfigOntoRuntimeSourceSnapshot(config);
|
|
1192
|
+
return {
|
|
1193
|
+
config: projected,
|
|
1194
|
+
sourceConfigForSecrets: projected === config ? runtimeSource : projected
|
|
1195
|
+
};
|
|
1196
|
+
}
|
|
1197
|
+
async function withModelsJsonWriteLock(targetPath, run) {
|
|
1198
|
+
const prior = MODELS_JSON_STATE.writeLocks.get(targetPath) ?? Promise.resolve();
|
|
1199
|
+
let release = () => {};
|
|
1200
|
+
const gate = new Promise((resolve) => {
|
|
1201
|
+
release = resolve;
|
|
1202
|
+
});
|
|
1203
|
+
const pending = prior.then(() => gate);
|
|
1204
|
+
MODELS_JSON_STATE.writeLocks.set(targetPath, pending);
|
|
1205
|
+
try {
|
|
1206
|
+
await prior;
|
|
1207
|
+
return await run();
|
|
1208
|
+
} finally {
|
|
1209
|
+
release();
|
|
1210
|
+
if (MODELS_JSON_STATE.writeLocks.get(targetPath) === pending) MODELS_JSON_STATE.writeLocks.delete(targetPath);
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
async function ensureOpenClawModelsJson(config, agentDirOverride) {
|
|
1214
|
+
const resolved = resolveModelsConfigInput(config);
|
|
1215
|
+
const cfg = resolved.config;
|
|
1216
|
+
const agentDir = agentDirOverride?.trim() ? agentDirOverride.trim() : resolveOpenClawAgentDir();
|
|
1217
|
+
const targetPath = path.join(agentDir, "models.json");
|
|
1218
|
+
const fingerprint = await buildModelsJsonFingerprint({
|
|
1219
|
+
config: cfg,
|
|
1220
|
+
sourceConfigForSecrets: resolved.sourceConfigForSecrets,
|
|
1221
|
+
agentDir
|
|
1222
|
+
});
|
|
1223
|
+
const cached = MODELS_JSON_STATE.readyCache.get(targetPath);
|
|
1224
|
+
if (cached) {
|
|
1225
|
+
const settled = await cached;
|
|
1226
|
+
if (settled.fingerprint === fingerprint) {
|
|
1227
|
+
await ensureModelsFileModeForModelsJson(targetPath);
|
|
1228
|
+
return settled.result;
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
const pending = withModelsJsonWriteLock(targetPath, async () => {
|
|
1232
|
+
const env = createConfigRuntimeEnv(cfg);
|
|
1233
|
+
const existingModelsFile = await readExistingModelsFile(targetPath);
|
|
1234
|
+
const plan = await planOpenClawModelsJson({
|
|
1235
|
+
cfg,
|
|
1236
|
+
sourceConfigForSecrets: resolved.sourceConfigForSecrets,
|
|
1237
|
+
agentDir,
|
|
1238
|
+
env,
|
|
1239
|
+
existingRaw: existingModelsFile.raw,
|
|
1240
|
+
existingParsed: existingModelsFile.parsed
|
|
1241
|
+
});
|
|
1242
|
+
if (plan.action === "skip") return {
|
|
1243
|
+
fingerprint,
|
|
1244
|
+
result: {
|
|
1245
|
+
agentDir,
|
|
1246
|
+
wrote: false
|
|
1247
|
+
}
|
|
1248
|
+
};
|
|
1249
|
+
if (plan.action === "noop") {
|
|
1250
|
+
await ensureModelsFileModeForModelsJson(targetPath);
|
|
1251
|
+
return {
|
|
1252
|
+
fingerprint,
|
|
1253
|
+
result: {
|
|
1254
|
+
agentDir,
|
|
1255
|
+
wrote: false
|
|
1256
|
+
}
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
await fs.mkdir(agentDir, {
|
|
1260
|
+
recursive: true,
|
|
1261
|
+
mode: 448
|
|
1262
|
+
});
|
|
1263
|
+
await writeModelsFileAtomicForModelsJson(targetPath, plan.contents);
|
|
1264
|
+
await ensureModelsFileModeForModelsJson(targetPath);
|
|
1265
|
+
return {
|
|
1266
|
+
fingerprint,
|
|
1267
|
+
result: {
|
|
1268
|
+
agentDir,
|
|
1269
|
+
wrote: true
|
|
1270
|
+
}
|
|
1271
|
+
};
|
|
1272
|
+
});
|
|
1273
|
+
MODELS_JSON_STATE.readyCache.set(targetPath, pending);
|
|
1274
|
+
try {
|
|
1275
|
+
return (await pending).result;
|
|
1276
|
+
} catch (error) {
|
|
1277
|
+
if (MODELS_JSON_STATE.readyCache.get(targetPath) === pending) MODELS_JSON_STATE.readyCache.delete(targetPath);
|
|
1278
|
+
throw error;
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
//#endregion
|
|
1282
|
+
export { requireApiKey as n, normalizeModelRef as r, ensureOpenClawModelsJson as t };
|