@joshuaswarren/openclaw-engram 9.1.17 → 9.1.18

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.
@@ -3,12 +3,12 @@ import {
3
3
  EngramAccessService,
4
4
  Orchestrator,
5
5
  parseConfig
6
- } from "./chunk-ZZF2FYBV.js";
7
- import "./chunk-MQ5EZ6VE.js";
6
+ } from "./chunk-HOO364J6.js";
7
+ import "./chunk-IEFSMVQV.js";
8
8
  import "./chunk-IMMYYNXG.js";
9
- import "./chunk-TS3YC3MY.js";
9
+ import "./chunk-DTCQ2KEX.js";
10
10
  import "./chunk-6KX4XLQJ.js";
11
- import "./chunk-5YCBFXXX.js";
11
+ import "./chunk-AVOL6JGC.js";
12
12
  import "./chunk-MKM2BCQH.js";
13
13
  import "./chunk-DEIBZP3O.js";
14
14
  import "./chunk-SSIIJJKA.js";
@@ -1,7 +1,7 @@
1
1
  // openclaw-engram: Local-first memory plugin
2
2
  import {
3
3
  FallbackLlmClient
4
- } from "./chunk-5YCBFXXX.js";
4
+ } from "./chunk-AVOL6JGC.js";
5
5
  import {
6
6
  listJsonFiles
7
7
  } from "./chunk-DEIBZP3O.js";
@@ -233,4 +233,4 @@ export {
233
233
  runCalibrationIfEnabled,
234
234
  synthesizeCalibrationRules
235
235
  };
236
- //# sourceMappingURL=calibration-JLSDBR4C.js.map
236
+ //# sourceMappingURL=calibration-WQM24F3Z.js.map
@@ -1,7 +1,7 @@
1
1
  // openclaw-engram: Local-first memory plugin
2
2
  import {
3
3
  FallbackLlmClient
4
- } from "./chunk-5YCBFXXX.js";
4
+ } from "./chunk-AVOL6JGC.js";
5
5
  import {
6
6
  readChainIndex,
7
7
  resolveChainsDir
@@ -203,4 +203,4 @@ export {
203
203
  deriveCausalPromotionCandidates,
204
204
  synthesizeCausalPreferencesViaLlm
205
205
  };
206
- //# sourceMappingURL=causal-consolidation-HCZHJO2J.js.map
206
+ //# sourceMappingURL=causal-consolidation-GNGU4MUV.js.map
@@ -94,6 +94,202 @@ function buildChatCompletionTokenLimit(model, maxTokens, options) {
94
94
  return { max_tokens: safeMaxTokens };
95
95
  }
96
96
 
97
+ // src/resolve-provider-secret.ts
98
+ import { execFileSync } from "child_process";
99
+ import { readFileSync, existsSync } from "fs";
100
+ import path from "path";
101
+ import os from "os";
102
+ var resolvedCache = /* @__PURE__ */ new Map();
103
+ async function resolveProviderApiKey(providerId, apiKeyValue, gatewayConfig) {
104
+ if (typeof apiKeyValue === "string") {
105
+ if (apiKeyValue === "secretref-managed") {
106
+ return resolveSecretRefManaged(providerId, gatewayConfig);
107
+ }
108
+ if (apiKeyValue.endsWith("-oauth") || apiKeyValue.endsWith("-local") || apiKeyValue === "lm-studio" || apiKeyValue.startsWith("gcp-")) {
109
+ return void 0;
110
+ }
111
+ return apiKeyValue;
112
+ }
113
+ if (isSecretRefObject(apiKeyValue)) {
114
+ return resolveSecretRef(providerId, apiKeyValue);
115
+ }
116
+ return void 0;
117
+ }
118
+ function isSecretRefObject(value) {
119
+ return typeof value === "object" && value !== null && "source" in value && "id" in value && typeof value.source === "string" && typeof value.id === "string";
120
+ }
121
+ async function resolveSecretRef(providerId, ref) {
122
+ const cacheKey = `ref:${ref.source}:${ref.provider ?? ""}:${ref.id}:${ref.command ?? ""}:${(ref.args ?? []).join(",")}`;
123
+ const cached = resolvedCache.get(cacheKey);
124
+ if (cached !== void 0) {
125
+ if (cached !== null) return cached;
126
+ }
127
+ let resolved;
128
+ try {
129
+ switch (ref.source) {
130
+ case "exec":
131
+ resolved = resolveExecSecret(ref);
132
+ break;
133
+ case "file":
134
+ resolved = resolveFileSecret(ref);
135
+ break;
136
+ case "env":
137
+ resolved = process.env[ref.id] ?? void 0;
138
+ break;
139
+ }
140
+ } catch (err) {
141
+ log.warn(
142
+ `secret resolution failed for provider "${providerId}" (${ref.source}/${ref.provider}): ${err instanceof Error ? err.message : String(err)}`
143
+ );
144
+ }
145
+ if (resolved) {
146
+ resolvedCache.set(cacheKey, resolved);
147
+ }
148
+ if (resolved) {
149
+ log.debug(`resolved API key for provider "${providerId}" via ${ref.source}/${ref.provider ?? "default"}`);
150
+ }
151
+ return resolved;
152
+ }
153
+ function resolveExecSecret(ref) {
154
+ const command = ref.command ?? (ref.provider === "op" ? "op" : void 0);
155
+ if (!command) {
156
+ log.warn(`exec secret ref has no command and provider "${ref.provider}" is not a known exec provider`);
157
+ return void 0;
158
+ }
159
+ const args = ref.args ?? (ref.provider === "op" ? ["read", ref.id] : [ref.id]);
160
+ try {
161
+ const result = execFileSync(command, args, {
162
+ encoding: "utf-8",
163
+ timeout: 1e4,
164
+ stdio: ["pipe", "pipe", "pipe"]
165
+ }).trim();
166
+ return result || void 0;
167
+ } catch (err) {
168
+ log.warn(`exec secret resolution failed (${command}): ${err instanceof Error ? err.message : String(err)}`);
169
+ return void 0;
170
+ }
171
+ }
172
+ function resolveFileSecret(ref) {
173
+ if (ref.provider === "op") {
174
+ const secretsDir = path.join(os.homedir(), ".openclaw", "secrets");
175
+ const filePath = path.join(secretsDir, ref.id.replace(/^\//, ""));
176
+ if (existsSync(filePath)) {
177
+ try {
178
+ return readFileSync(filePath, "utf-8").trim() || void 0;
179
+ } catch {
180
+ }
181
+ }
182
+ try {
183
+ const result = execFileSync("op", ["read", ref.id], {
184
+ encoding: "utf-8",
185
+ timeout: 1e4,
186
+ stdio: ["pipe", "pipe", "pipe"]
187
+ }).trim();
188
+ return result || void 0;
189
+ } catch {
190
+ }
191
+ } else {
192
+ const filePath = path.isAbsolute(ref.id) ? ref.id : path.join(os.homedir(), ".openclaw", "secrets", ref.id.replace(/^\//, ""));
193
+ if (existsSync(filePath)) {
194
+ try {
195
+ return readFileSync(filePath, "utf-8").trim() || void 0;
196
+ } catch {
197
+ }
198
+ }
199
+ }
200
+ return void 0;
201
+ }
202
+ function resolveSecretRefManaged(providerId, gatewayConfig) {
203
+ const cacheKey = `managed:${providerId}`;
204
+ const cached = resolvedCache.get(cacheKey);
205
+ if (cached !== void 0 && cached !== null) {
206
+ return cached;
207
+ }
208
+ let resolved;
209
+ const profiles = gatewayConfig?.auth?.profiles;
210
+ if (profiles) {
211
+ const candidates = [
212
+ `${providerId}:default`,
213
+ `${providerId}:manual`,
214
+ providerId
215
+ ];
216
+ for (const profileKey of candidates) {
217
+ const raw = profiles[profileKey];
218
+ if (!raw || typeof raw !== "object") continue;
219
+ const profile = raw;
220
+ if (profile.token) {
221
+ if (typeof profile.token === "string" && !profile.token.startsWith("{")) {
222
+ resolved = profile.token;
223
+ break;
224
+ }
225
+ if (isSecretRefObject(profile.token)) {
226
+ try {
227
+ resolved = resolveSecretRefSync(providerId, profile.token);
228
+ } catch {
229
+ }
230
+ if (resolved) break;
231
+ }
232
+ }
233
+ if (profile.apiKey && typeof profile.apiKey === "string") {
234
+ resolved = profile.apiKey;
235
+ break;
236
+ }
237
+ if (profile.access && typeof profile.access === "string") {
238
+ resolved = profile.access;
239
+ break;
240
+ }
241
+ }
242
+ }
243
+ if (!resolved) {
244
+ const envCandidates = [
245
+ `${providerId.toUpperCase().replace(/-/g, "_")}_API_KEY`,
246
+ `${providerId.toUpperCase().replace(/-/g, "_")}_TOKEN`
247
+ ];
248
+ for (const envVar of envCandidates) {
249
+ if (process.env[envVar]) {
250
+ resolved = process.env[envVar];
251
+ break;
252
+ }
253
+ }
254
+ }
255
+ if (resolved) {
256
+ resolvedCache.set(cacheKey, resolved);
257
+ log.debug(`resolved managed API key for provider "${providerId}" via auth profile`);
258
+ } else {
259
+ log.debug(`could not resolve managed API key for provider "${providerId}"`);
260
+ }
261
+ return resolved;
262
+ }
263
+ function resolveSecretRefSync(providerId, ref) {
264
+ const cacheKey = `ref:${ref.source}:${ref.provider ?? ""}:${ref.id}:${ref.command ?? ""}:${(ref.args ?? []).join(",")}`;
265
+ const cached = resolvedCache.get(cacheKey);
266
+ if (cached !== void 0 && cached !== null) {
267
+ return cached;
268
+ }
269
+ let resolved;
270
+ try {
271
+ switch (ref.source) {
272
+ case "exec":
273
+ resolved = resolveExecSecret(ref);
274
+ break;
275
+ case "file":
276
+ resolved = resolveFileSecret(ref);
277
+ break;
278
+ case "env":
279
+ resolved = process.env[ref.id] ?? void 0;
280
+ break;
281
+ }
282
+ } catch (err) {
283
+ log.warn(
284
+ `sync secret resolution failed for provider "${providerId}": ${err instanceof Error ? err.message : String(err)}`
285
+ );
286
+ }
287
+ if (resolved) {
288
+ resolvedCache.set(cacheKey, resolved);
289
+ }
290
+ return resolved;
291
+ }
292
+
97
293
  // src/fallback-llm.ts
98
294
  var FallbackLlmClient = class {
99
295
  gatewayConfig;
@@ -260,17 +456,35 @@ var FallbackLlmClient = class {
260
456
  }
261
457
  return { providerId, modelId, providerConfig, modelString };
262
458
  }
459
+ /**
460
+ * Resolve the API key for a provider, handling OpenClaw secret ref formats.
461
+ * Results are cached per provider so exec calls only happen once.
462
+ */
463
+ async resolveApiKey(providerId, providerConfig) {
464
+ return resolveProviderApiKey(
465
+ providerId,
466
+ providerConfig.apiKey,
467
+ this.gatewayConfig
468
+ );
469
+ }
263
470
  /**
264
471
  * Try to call a single model.
265
472
  */
266
473
  async tryModel(model, messages, options) {
474
+ const rawKey = model.providerConfig.apiKey;
475
+ const needsResolution = rawKey === "secretref-managed" || typeof rawKey === "object" && rawKey !== null;
476
+ const resolvedApiKey = await this.resolveApiKey(model.providerId, model.providerConfig);
477
+ if (needsResolution && !resolvedApiKey) {
478
+ throw new Error(`API key for provider "${model.providerId}" could not be resolved from secret ref`);
479
+ }
480
+ const configWithResolvedKey = resolvedApiKey ? { ...model.providerConfig, apiKey: resolvedApiKey } : model.providerConfig;
267
481
  switch (model.providerConfig.api) {
268
482
  case "anthropic-messages":
269
- return await this.callAnthropic(model.providerConfig, model.modelId, messages, options);
483
+ return await this.callAnthropic(configWithResolvedKey, model.modelId, messages, options);
270
484
  case "openai-completions":
271
485
  default:
272
486
  return await this.callOpenAI(
273
- model.providerConfig,
487
+ configWithResolvedKey,
274
488
  model.modelId,
275
489
  messages,
276
490
  options,
@@ -288,7 +502,7 @@ var FallbackLlmClient = class {
288
502
  "Content-Type": "application/json",
289
503
  ...config.headers
290
504
  };
291
- if (config.apiKey) {
505
+ if (config.apiKey && typeof config.apiKey === "string") {
292
506
  if (config.authHeader !== false) {
293
507
  headers["Authorization"] = `Bearer ${config.apiKey}`;
294
508
  }
@@ -334,7 +548,7 @@ var FallbackLlmClient = class {
334
548
  "anthropic-version": "2023-06-01",
335
549
  ...config.headers
336
550
  };
337
- if (config.apiKey) {
551
+ if (config.apiKey && typeof config.apiKey === "string") {
338
552
  headers["x-api-key"] = config.apiKey;
339
553
  }
340
554
  const systemMessage = messages.find((m) => m.role === "system")?.content;
@@ -383,4 +597,4 @@ export {
383
597
  buildChatCompletionTokenLimit,
384
598
  FallbackLlmClient
385
599
  };
386
- //# sourceMappingURL=chunk-5YCBFXXX.js.map
600
+ //# sourceMappingURL=chunk-AVOL6JGC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/json-extract.ts","../src/openai-chat-compat.ts","../src/resolve-provider-secret.ts","../src/fallback-llm.ts"],"sourcesContent":["/**\n * Utilities for extracting JSON payloads from LLM outputs.\n *\n * We see common failure modes:\n * - \"Here's an example: {..}\\nHere's the real answer: {..}\" (multiple JSON blocks)\n * - fenced ```json blocks\n * - leading/trailing prose around JSON\n *\n * These helpers attempt multiple candidates and let callers validate with schemas.\n */\n\nexport function stripCodeFences(text: string): string {\n return text.replace(/```(?:json)?\\s*([\\s\\S]*?)```/gi, (_m, inner) => String(inner).trim());\n}\n\nexport function extractJsonCandidates(text: string): string[] {\n const trimmed = text.trim();\n const cleaned = stripCodeFences(trimmed);\n const candidates: string[] = [];\n\n if (cleaned.length > 0) candidates.push(cleaned);\n candidates.push(...scanBalancedJsonBlocks(cleaned));\n\n // Legacy regex fallback (single object)\n const objMatch = cleaned.match(/\\{[\\s\\S]*\\}/);\n if (objMatch) candidates.push(objMatch[0]);\n\n const seen = new Set<string>();\n return candidates\n .map((c) => c.trim())\n .filter((c) => c.length > 0)\n .filter((c) => {\n if (seen.has(c)) return false;\n seen.add(c);\n return true;\n });\n}\n\nfunction scanBalancedJsonBlocks(text: string): string[] {\n const out: string[] = [];\n const opens = new Set([\"{\", \"[\"]);\n const closes: Record<string, string> = { \"{\": \"}\", \"[\": \"]\" };\n\n for (let i = 0; i < text.length; i++) {\n const start = text[i];\n if (!opens.has(start)) continue;\n\n const expectedClose = closes[start];\n let depth = 0;\n let inString = false;\n let escape = false;\n\n for (let j = i; j < text.length; j++) {\n const ch = text[j];\n\n if (inString) {\n if (escape) {\n escape = false;\n } else if (ch === \"\\\\\") {\n escape = true;\n } else if (ch === \"\\\"\") {\n inString = false;\n }\n continue;\n }\n\n if (ch === \"\\\"\") {\n inString = true;\n continue;\n }\n\n if (ch === start) depth++;\n if (ch === expectedClose) depth--;\n\n if (depth === 0) {\n out.push(text.slice(i, j + 1).trim());\n i = j;\n break;\n }\n }\n }\n\n return out;\n}\n\n","function normalizedModel(model: string): string {\n return model.trim().toLowerCase();\n}\n\nfunction matchesModelFamily(normalized: string, familyPattern: RegExp): boolean {\n return familyPattern.test(normalized);\n}\n\nexport function shouldAssumeOpenAiChatCompletions(baseUrl?: string): boolean {\n if (!baseUrl) return true;\n try {\n return new URL(baseUrl).hostname.toLowerCase() === \"api.openai.com\";\n } catch {\n return false;\n }\n}\n\nexport function usesMaxCompletionTokens(model: string, options?: { assumeOpenAI?: boolean }): boolean {\n const normalized = normalizedModel(model);\n if (options?.assumeOpenAI !== true) return false;\n if (matchesModelFamily(normalized, /^gpt-5(?:$|[-.])/)) return true;\n if (matchesModelFamily(normalized, /^gpt-4o(?:$|[-.])/)) return true;\n if (matchesModelFamily(normalized, /^gpt-4\\.1(?:$|[-.])/)) return true;\n if (matchesModelFamily(normalized, /^o1(?:$|[-.])/)) return true;\n if (matchesModelFamily(normalized, /^o3(?:$|[-.])/)) return true;\n return matchesModelFamily(normalized, /^o4-mini(?:$|[-.])/);\n}\n\nexport function buildChatCompletionTokenLimit(\n model: string,\n maxTokens: number,\n options?: { assumeOpenAI?: boolean },\n): { max_tokens: number } | { max_completion_tokens: number } {\n const safeMaxTokens = Math.max(0, Math.floor(maxTokens));\n if (usesMaxCompletionTokens(model, options)) {\n return { max_completion_tokens: safeMaxTokens };\n }\n return { max_tokens: safeMaxTokens };\n}\n","import { log } from \"./logger.js\";\nimport { execFileSync } from \"node:child_process\";\nimport { readFileSync, existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\n/**\n * Secret reference object format used by OpenClaw's models.json.\n */\ninterface SecretRef {\n source: \"exec\" | \"file\" | \"env\";\n provider?: string;\n id: string;\n command?: string;\n args?: string[];\n}\n\n/**\n * Auth profile entry from agent auth-profiles.json files.\n */\ninterface AuthProfile {\n type?: string;\n provider?: string;\n token?: string | SecretRef;\n access?: string;\n apiKey?: string;\n}\n\nconst resolvedCache = new Map<string, string | null>();\n\n/**\n * Resolve a provider API key from various OpenClaw secret formats.\n *\n * Supported formats:\n * - Plain string (not a marker) → used as-is\n * - SecretRef object (`{ source, provider, id }`) → resolved via exec/file/env\n * - `\"secretref-managed\"` → looked up from auth profiles and openclaw.json auth config\n * - `\"minimax-oauth\"`, `\"ollama-local\"`, etc. → treated as non-secret markers, skipped\n *\n * Results are cached per provider to avoid repeated exec calls.\n */\nexport async function resolveProviderApiKey(\n providerId: string,\n apiKeyValue: unknown,\n gatewayConfig?: { auth?: { profiles?: Record<string, unknown> } },\n): Promise<string | undefined> {\n // Fast path: plain string that isn't a marker\n if (typeof apiKeyValue === \"string\") {\n if (apiKeyValue === \"secretref-managed\") {\n return resolveSecretRefManaged(providerId, gatewayConfig);\n }\n // Known non-secret markers — skip\n if (\n apiKeyValue.endsWith(\"-oauth\") ||\n apiKeyValue.endsWith(\"-local\") ||\n apiKeyValue === \"lm-studio\" ||\n apiKeyValue.startsWith(\"gcp-\")\n ) {\n return undefined;\n }\n // Looks like an actual key\n return apiKeyValue;\n }\n\n // SecretRef object\n if (isSecretRefObject(apiKeyValue)) {\n return resolveSecretRef(providerId, apiKeyValue as SecretRef);\n }\n\n return undefined;\n}\n\nfunction isSecretRefObject(value: unknown): value is SecretRef {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"source\" in value &&\n \"id\" in value &&\n typeof (value as SecretRef).source === \"string\" &&\n typeof (value as SecretRef).id === \"string\"\n );\n}\n\nasync function resolveSecretRef(\n providerId: string,\n ref: SecretRef,\n): Promise<string | undefined> {\n const cacheKey = `ref:${ref.source}:${ref.provider ?? \"\"}:${ref.id}:${ref.command ?? \"\"}:${(ref.args ?? []).join(\",\")}`;\n const cached = resolvedCache.get(cacheKey);\n if (cached !== undefined) {\n // Don't cache failures permanently — only cache successes\n if (cached !== null) return cached;\n }\n\n let resolved: string | undefined;\n\n try {\n switch (ref.source) {\n case \"exec\":\n resolved = resolveExecSecret(ref);\n break;\n case \"file\":\n resolved = resolveFileSecret(ref);\n break;\n case \"env\":\n resolved = process.env[ref.id] ?? undefined;\n break;\n }\n } catch (err) {\n log.warn(\n `secret resolution failed for provider \"${providerId}\" (${ref.source}/${ref.provider}): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n // Only cache successful resolutions; failures are retried next time\n if (resolved) {\n resolvedCache.set(cacheKey, resolved);\n }\n\n if (resolved) {\n log.debug(`resolved API key for provider \"${providerId}\" via ${ref.source}/${ref.provider ?? \"default\"}`);\n }\n\n return resolved;\n}\n\nfunction resolveExecSecret(ref: SecretRef): string | undefined {\n const command = ref.command ?? (ref.provider === \"op\" ? \"op\" : undefined);\n if (!command) {\n log.warn(`exec secret ref has no command and provider \"${ref.provider}\" is not a known exec provider`);\n return undefined;\n }\n\n // Use execFileSync (not execSync) to avoid shell injection —\n // arguments are passed as an array, never interpolated into a shell string.\n const args = ref.args ?? (ref.provider === \"op\" ? [\"read\", ref.id] : [ref.id]);\n try {\n const result = execFileSync(command, args, {\n encoding: \"utf-8\",\n timeout: 10_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim();\n return result || undefined;\n } catch (err) {\n log.warn(`exec secret resolution failed (${command}): ${err instanceof Error ? err.message : String(err)}`);\n return undefined;\n }\n}\n\nfunction resolveFileSecret(ref: SecretRef): string | undefined {\n if (ref.provider === \"op\") {\n // Try reading from the OpenClaw secrets directory\n const secretsDir = path.join(os.homedir(), \".openclaw\", \"secrets\");\n const filePath = path.join(secretsDir, ref.id.replace(/^\\//, \"\"));\n if (existsSync(filePath)) {\n try {\n return readFileSync(filePath, \"utf-8\").trim() || undefined;\n } catch {\n // Fall through to op exec\n }\n }\n\n // Fall back to `op read` via execFileSync (no shell injection)\n try {\n const result = execFileSync(\"op\", [\"read\", ref.id], {\n encoding: \"utf-8\",\n timeout: 10_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim();\n return result || undefined;\n } catch {\n // Silent — op may not be available\n }\n } else {\n // Non-OP file provider: treat ref.id as a file path (absolute or relative to secrets dir)\n const filePath = path.isAbsolute(ref.id)\n ? ref.id\n : path.join(os.homedir(), \".openclaw\", \"secrets\", ref.id.replace(/^\\//, \"\"));\n if (existsSync(filePath)) {\n try {\n return readFileSync(filePath, \"utf-8\").trim() || undefined;\n } catch {\n // Silent\n }\n }\n }\n\n return undefined;\n}\n\nfunction resolveSecretRefManaged(\n providerId: string,\n gatewayConfig?: { auth?: { profiles?: Record<string, unknown> } },\n): string | undefined {\n const cacheKey = `managed:${providerId}`;\n const cached = resolvedCache.get(cacheKey);\n if (cached !== undefined && cached !== null) {\n return cached;\n }\n\n let resolved: string | undefined;\n\n // Look up auth profiles for this provider\n const profiles = gatewayConfig?.auth?.profiles;\n if (profiles) {\n // Try provider:default, provider:manual, etc.\n const candidates = [\n `${providerId}:default`,\n `${providerId}:manual`,\n providerId,\n ];\n\n for (const profileKey of candidates) {\n const raw = profiles[profileKey];\n if (!raw || typeof raw !== \"object\") continue;\n const profile = raw as AuthProfile;\n\n // Token-based auth\n if (profile.token) {\n if (typeof profile.token === \"string\" && !profile.token.startsWith(\"{\")) {\n resolved = profile.token;\n break;\n }\n if (isSecretRefObject(profile.token)) {\n // Synchronously resolve — this is at init time\n try {\n resolved = resolveSecretRefSync(providerId, profile.token as SecretRef);\n } catch {\n // Continue to next profile\n }\n if (resolved) break;\n }\n }\n\n // API key auth\n if (profile.apiKey && typeof profile.apiKey === \"string\") {\n resolved = profile.apiKey;\n break;\n }\n\n // Access token (OAuth)\n if (profile.access && typeof profile.access === \"string\") {\n resolved = profile.access;\n break;\n }\n }\n }\n\n // Fall back to environment variables\n if (!resolved) {\n const envCandidates = [\n `${providerId.toUpperCase().replace(/-/g, \"_\")}_API_KEY`,\n `${providerId.toUpperCase().replace(/-/g, \"_\")}_TOKEN`,\n ];\n for (const envVar of envCandidates) {\n if (process.env[envVar]) {\n resolved = process.env[envVar];\n break;\n }\n }\n }\n\n // Only cache successful resolutions; failures are retried next time\n if (resolved) {\n resolvedCache.set(cacheKey, resolved);\n log.debug(`resolved managed API key for provider \"${providerId}\" via auth profile`);\n } else {\n log.debug(`could not resolve managed API key for provider \"${providerId}\"`);\n }\n\n return resolved;\n}\n\nfunction resolveSecretRefSync(\n providerId: string,\n ref: SecretRef,\n): string | undefined {\n const cacheKey = `ref:${ref.source}:${ref.provider ?? \"\"}:${ref.id}:${ref.command ?? \"\"}:${(ref.args ?? []).join(\",\")}`;\n const cached = resolvedCache.get(cacheKey);\n if (cached !== undefined && cached !== null) {\n return cached;\n }\n\n let resolved: string | undefined;\n\n try {\n switch (ref.source) {\n case \"exec\":\n resolved = resolveExecSecret(ref);\n break;\n case \"file\":\n resolved = resolveFileSecret(ref);\n break;\n case \"env\":\n resolved = process.env[ref.id] ?? undefined;\n break;\n }\n } catch (err) {\n log.warn(\n `sync secret resolution failed for provider \"${providerId}\": ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n if (resolved) {\n resolvedCache.set(cacheKey, resolved);\n }\n return resolved;\n}\n\n/**\n * Clear the resolution cache (useful for testing or key rotation).\n */\nexport function clearSecretCache(): void {\n resolvedCache.clear();\n}\n","import { log } from \"./logger.js\";\nimport type { GatewayConfig, ModelProviderConfig, AgentPersona } from \"./types.js\";\nimport { extractJsonCandidates } from \"./json-extract.js\";\nimport {\n buildChatCompletionTokenLimit,\n shouldAssumeOpenAiChatCompletions,\n} from \"./openai-chat-compat.js\";\nimport { resolveProviderApiKey } from \"./resolve-provider-secret.js\";\n\nexport interface FallbackLlmOptions {\n temperature?: number;\n maxTokens?: number;\n timeoutMs?: number;\n /** Override which agent persona's model chain to use (by ID from agents.list[]). */\n agentId?: string;\n}\n\nexport interface FallbackLlmResponse {\n content: string;\n modelUsed: string;\n usage?: {\n inputTokens?: number;\n outputTokens?: number;\n totalTokens?: number;\n };\n}\n\ninterface ModelRef {\n providerId: string;\n modelId: string;\n providerConfig: ModelProviderConfig;\n modelString: string;\n}\n\n/**\n * Generic fallback LLM client that uses the gateway's default AI configuration\n * and walks through the full fallback chain (primary + fallbacks).\n * Supports OpenAI and Anthropic API formats.\n */\nexport class FallbackLlmClient {\n private gatewayConfig: GatewayConfig | undefined;\n\n constructor(gatewayConfig?: GatewayConfig) {\n this.gatewayConfig = gatewayConfig;\n }\n\n /**\n * Check if fallback is available (gateway config has at least one model).\n */\n isAvailable(agentId?: string): boolean {\n const models = this.getModelChain(agentId);\n return models.length > 0;\n }\n\n /**\n * Make a chat completion request using the gateway's default AI chain.\n * Tries primary first, then each fallback in order.\n * When agentId is provided, uses that agent persona's model chain instead of defaults.\n */\n async chatCompletion(\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions = {},\n ): Promise<FallbackLlmResponse | null> {\n const models = this.getModelChain(options.agentId);\n if (models.length === 0) {\n log.warn(\"fallback LLM: no models configured in gateway\");\n return null;\n }\n\n const runChain = async (): Promise<FallbackLlmResponse | null> => {\n // Try each model in the chain\n for (let i = 0; i < models.length; i++) {\n const model = models[i];\n const isFallback = i > 0;\n\n try {\n const result = await this.tryModel(model, messages, options);\n if (result) {\n if (isFallback) {\n log.info(`fallback LLM: succeeded using ${model.modelString} (fallback ${i})`);\n }\n return {\n content: result.content,\n modelUsed: model.modelString,\n usage: result.usage,\n };\n }\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n log.debug(`fallback LLM: ${model.modelString} failed (${errorMsg}), trying next...`);\n // Continue to next model in chain\n }\n }\n\n log.warn(`fallback LLM: all ${models.length} models in chain failed`);\n return null;\n };\n\n if (typeof options.timeoutMs === \"number\") {\n if (options.timeoutMs <= 0) {\n log.warn(\"fallback LLM: timed out before request started\");\n return null;\n }\n let timeoutHandle: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n runChain(),\n new Promise<null>((resolve) => {\n timeoutHandle = setTimeout(() => {\n log.warn(`fallback LLM: timed out after ${options.timeoutMs}ms`);\n resolve(null);\n }, options.timeoutMs);\n }),\n ]);\n } finally {\n if (timeoutHandle) clearTimeout(timeoutHandle);\n }\n }\n\n return await runChain();\n }\n\n /**\n * Make a request with structured output (Zod schema).\n * Returns parsed JSON or null on failure.\n */\n async parseWithSchema<T>(\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n schema: { parse: (data: unknown) => T },\n options: FallbackLlmOptions = {},\n ): Promise<T | null> {\n const detailed = await this.parseWithSchemaDetailed(messages, schema, options);\n return detailed?.result ?? null;\n }\n\n /**\n * Like parseWithSchema but also returns the model that was used,\n * so callers can emit accurate trace events.\n */\n async parseWithSchemaDetailed<T>(\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n schema: { parse: (data: unknown) => T },\n options: FallbackLlmOptions = {},\n ): Promise<{ result: T; modelUsed: string } | null> {\n const response = await this.chatCompletion(messages, options);\n if (!response?.content) return null;\n\n try {\n const candidates = extractJsonCandidates(response.content);\n for (const c of candidates) {\n try {\n const parsed = JSON.parse(c);\n return { result: schema.parse(parsed), modelUsed: response.modelUsed };\n } catch {\n // keep trying other candidates\n }\n }\n return null;\n } catch (err) {\n log.warn(\"fallback LLM: failed to parse structured output:\", err);\n return null;\n }\n }\n\n /**\n * Get the full model chain from gateway config.\n * Returns array of models in order: [primary, fallback1, fallback2, ...]\n *\n * When agentId is provided, looks up the matching entry in agents.list[]\n * and uses that persona's model chain. Falls back to agents.defaults.model\n * if agentId is not found or not provided.\n */\n private getModelChain(agentId?: string): ModelRef[] {\n const chain: ModelRef[] = [];\n const providers = this.gatewayConfig?.models?.providers;\n\n if (!providers) return chain;\n\n // Resolve the model config: agent persona chain or global defaults\n let modelConfig: { primary?: string; fallbacks?: string[] } | undefined;\n\n if (agentId) {\n const persona = this.gatewayConfig?.agents?.list?.find(\n (a) => a.id === agentId,\n );\n if (persona?.model) {\n modelConfig = persona.model;\n log.debug(`fallback LLM: using agent persona \"${agentId}\" model chain`);\n } else {\n log.warn(\n `fallback LLM: agent persona \"${agentId}\" not found or has no model config, falling back to defaults`,\n );\n }\n }\n\n if (!modelConfig) {\n modelConfig = this.gatewayConfig?.agents?.defaults?.model;\n }\n\n // Build list of model strings: primary + fallbacks\n const modelStrings: string[] = [];\n\n if (modelConfig?.primary) {\n modelStrings.push(modelConfig.primary);\n }\n\n if (Array.isArray(modelConfig?.fallbacks)) {\n for (const fb of modelConfig.fallbacks) {\n if (typeof fb === \"string\" && !modelStrings.includes(fb)) {\n modelStrings.push(fb);\n }\n }\n }\n\n // Parse each model string and look up provider config\n for (const modelString of modelStrings) {\n const modelRef = this.parseModelString(modelString, providers);\n if (modelRef) {\n chain.push(modelRef);\n }\n }\n\n return chain;\n }\n\n /**\n * Parse a \"provider/model\" string and look up its config.\n */\n private parseModelString(\n modelString: string,\n providers: Record<string, ModelProviderConfig>,\n ): ModelRef | null {\n // Parse \"provider/model\" format (e.g., \"openai/gpt-5.2\", \"anthropic/claude-opus-4-6\")\n const parts = modelString.split(\"/\");\n if (parts.length < 2) {\n log.warn(`fallback LLM: invalid model format: ${modelString}`);\n return null;\n }\n\n const providerId = parts[0];\n const modelId = parts.slice(1).join(\"/\"); // Handle cases like \"openai/gpt-5.2-turbo\"\n\n const providerConfig = providers[providerId];\n if (!providerConfig) {\n log.warn(`fallback LLM: provider not found: ${providerId}`);\n return null;\n }\n\n return { providerId, modelId, providerConfig, modelString };\n }\n\n /**\n * Resolve the API key for a provider, handling OpenClaw secret ref formats.\n * Results are cached per provider so exec calls only happen once.\n */\n private async resolveApiKey(\n providerId: string,\n providerConfig: ModelProviderConfig,\n ): Promise<string | undefined> {\n return resolveProviderApiKey(\n providerId,\n providerConfig.apiKey,\n this.gatewayConfig as { auth?: { profiles?: Record<string, unknown> } } | undefined,\n );\n }\n\n /**\n * Try to call a single model.\n */\n private async tryModel(\n model: ModelRef,\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions,\n ): Promise<{ content: string; usage?: FallbackLlmResponse[\"usage\"] } | null> {\n // Resolve the API key from secret refs before making the call.\n // If the raw key looks like an unresolved secret ref and resolution fails,\n // skip this provider entirely so the chain falls through to the next.\n const rawKey = model.providerConfig.apiKey;\n const needsResolution = rawKey === \"secretref-managed\"\n || (typeof rawKey === \"object\" && rawKey !== null);\n const resolvedApiKey = await this.resolveApiKey(model.providerId, model.providerConfig);\n\n if (needsResolution && !resolvedApiKey) {\n throw new Error(`API key for provider \"${model.providerId}\" could not be resolved from secret ref`);\n }\n\n const configWithResolvedKey = resolvedApiKey\n ? { ...model.providerConfig, apiKey: resolvedApiKey }\n : model.providerConfig;\n\n switch (model.providerConfig.api) {\n case \"anthropic-messages\":\n return await this.callAnthropic(configWithResolvedKey, model.modelId, messages, options);\n case \"openai-completions\":\n default:\n return await this.callOpenAI(\n configWithResolvedKey,\n model.modelId,\n messages,\n options,\n shouldAssumeOpenAiChatCompletions(model.providerConfig.baseUrl),\n );\n }\n }\n\n /**\n * Call OpenAI-compatible API.\n */\n private async callOpenAI(\n config: ModelProviderConfig,\n modelId: string,\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions,\n assumeOpenAI: boolean,\n ): Promise<{ content: string; usage?: FallbackLlmResponse[\"usage\"] } | null> {\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const url = base.endsWith(\"/v1\")\n ? `${base}/chat/completions`\n : `${base}/v1/chat/completions`;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...config.headers,\n };\n\n // Handle auth — apiKey is already resolved to a string by tryModel()\n if (config.apiKey && typeof config.apiKey === \"string\") {\n if (config.authHeader !== false) {\n headers[\"Authorization\"] = `Bearer ${config.apiKey}`;\n }\n }\n\n const body = {\n model: modelId,\n messages,\n temperature: options.temperature ?? 0.3,\n ...buildChatCompletionTokenLimit(modelId, options.maxTokens ?? 4096, {\n assumeOpenAI,\n }),\n };\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`OpenAI API error: ${response.status} ${error}`);\n }\n\n const data = (await response.json()) as {\n choices: Array<{\n message: {\n content: string;\n };\n }>;\n usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n };\n };\n\n const content = data.choices?.[0]?.message?.content;\n if (!content) {\n throw new Error(\"Empty response from OpenAI API\");\n }\n\n return {\n content,\n usage: data.usage\n ? {\n inputTokens: data.usage.prompt_tokens,\n outputTokens: data.usage.completion_tokens,\n totalTokens: data.usage.total_tokens,\n }\n : undefined,\n };\n }\n\n /**\n * Call Anthropic Messages API.\n */\n private async callAnthropic(\n config: ModelProviderConfig,\n modelId: string,\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions,\n ): Promise<{ content: string; usage?: FallbackLlmResponse[\"usage\"] } | null> {\n const url = `${config.baseUrl.replace(/\\/$/, \"\")}/messages`;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"anthropic-version\": \"2023-06-01\",\n ...config.headers,\n };\n\n // Handle auth - Anthropic uses x-api-key header (apiKey resolved by tryModel)\n if (config.apiKey && typeof config.apiKey === \"string\") {\n headers[\"x-api-key\"] = config.apiKey;\n }\n\n // Extract system message (Anthropic handles it separately)\n const systemMessage = messages.find((m) => m.role === \"system\")?.content;\n const nonSystemMessages = messages.filter((m) => m.role !== \"system\");\n\n // Convert messages to Anthropic format\n const anthropicMessages = nonSystemMessages.map((m) => ({\n role: m.role,\n content: m.content,\n }));\n\n const body: Record<string, unknown> = {\n model: modelId,\n messages: anthropicMessages,\n max_tokens: options.maxTokens ?? 4096,\n temperature: options.temperature ?? 0.3,\n };\n\n if (systemMessage) {\n body.system = systemMessage;\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Anthropic API error: ${response.status} ${error}`);\n }\n\n const data = (await response.json()) as {\n content: Array<{\n type: string;\n text: string;\n }>;\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n };\n };\n\n const content = data.content?.[0]?.text;\n if (!content) {\n throw new Error(\"Empty response from Anthropic API\");\n }\n\n return {\n content,\n usage: data.usage\n ? {\n inputTokens: data.usage.input_tokens,\n outputTokens: data.usage.output_tokens,\n totalTokens: (data.usage.input_tokens ?? 0) + (data.usage.output_tokens ?? 0),\n }\n : undefined,\n };\n }\n}\n"],"mappings":"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","names":[]}
@@ -4088,4 +4088,4 @@ export {
4088
4088
  serializeEntityFile,
4089
4089
  StorageManager
4090
4090
  };
4091
- //# sourceMappingURL=chunk-TS3YC3MY.js.map
4091
+ //# sourceMappingURL=chunk-DTCQ2KEX.js.map