@joshuaswarren/openclaw-engram 9.1.18 → 9.1.19

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-HOO364J6.js";
7
- import "./chunk-IEFSMVQV.js";
6
+ } from "./chunk-KZMICTC7.js";
7
+ import "./chunk-OLJAEA5I.js";
8
8
  import "./chunk-IMMYYNXG.js";
9
9
  import "./chunk-DTCQ2KEX.js";
10
10
  import "./chunk-6KX4XLQJ.js";
11
- import "./chunk-AVOL6JGC.js";
11
+ import "./chunk-KIA3HVQD.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-AVOL6JGC.js";
4
+ } from "./chunk-KIA3HVQD.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-WQM24F3Z.js.map
236
+ //# sourceMappingURL=calibration-OOOYE2ID.js.map
@@ -1,7 +1,7 @@
1
1
  // openclaw-engram: Local-first memory plugin
2
2
  import {
3
3
  FallbackLlmClient
4
- } from "./chunk-AVOL6JGC.js";
4
+ } from "./chunk-KIA3HVQD.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-GNGU4MUV.js.map
206
+ //# sourceMappingURL=causal-consolidation-BDMZMX2D.js.map
@@ -100,6 +100,34 @@ import { readFileSync, existsSync } from "fs";
100
100
  import path from "path";
101
101
  import os from "os";
102
102
  var resolvedCache = /* @__PURE__ */ new Map();
103
+ var DEFAULT_OP_VAULT = "OpenClaw";
104
+ var OP_SERVICE_ACCOUNT_TOKEN_PATH = path.join(os.homedir(), ".openclaw", "secrets", "op-service-account-token");
105
+ var OP_VAULT_PATH = path.join(os.homedir(), ".openclaw", "secrets", "op-vault-name");
106
+ function getOpVault() {
107
+ try {
108
+ if (existsSync(OP_VAULT_PATH)) {
109
+ const vault = readFileSync(OP_VAULT_PATH, "utf-8").trim();
110
+ if (vault) return vault;
111
+ }
112
+ } catch {
113
+ }
114
+ return process.env.OP_VAULT ?? DEFAULT_OP_VAULT;
115
+ }
116
+ function buildOpEnv() {
117
+ if (process.env.OP_SERVICE_ACCOUNT_TOKEN) {
118
+ return process.env;
119
+ }
120
+ try {
121
+ if (existsSync(OP_SERVICE_ACCOUNT_TOKEN_PATH)) {
122
+ const token = readFileSync(OP_SERVICE_ACCOUNT_TOKEN_PATH, "utf-8").trim();
123
+ if (token) {
124
+ return { ...process.env, OP_SERVICE_ACCOUNT_TOKEN: token };
125
+ }
126
+ }
127
+ } catch {
128
+ }
129
+ return process.env;
130
+ }
103
131
  async function resolveProviderApiKey(providerId, apiKeyValue, gatewayConfig) {
104
132
  if (typeof apiKeyValue === "string") {
105
133
  if (apiKeyValue === "secretref-managed") {
@@ -157,11 +185,13 @@ function resolveExecSecret(ref) {
157
185
  return void 0;
158
186
  }
159
187
  const args = ref.args ?? (ref.provider === "op" ? ["read", ref.id] : [ref.id]);
188
+ const env = ref.provider === "op" ? buildOpEnv() : process.env;
160
189
  try {
161
190
  const result = execFileSync(command, args, {
162
191
  encoding: "utf-8",
163
- timeout: 1e4,
164
- stdio: ["pipe", "pipe", "pipe"]
192
+ timeout: 15e3,
193
+ stdio: ["pipe", "pipe", "pipe"],
194
+ env
165
195
  }).trim();
166
196
  return result || void 0;
167
197
  } catch (err) {
@@ -171,6 +201,55 @@ function resolveExecSecret(ref) {
171
201
  }
172
202
  function resolveFileSecret(ref) {
173
203
  if (ref.provider === "op") {
204
+ const env = buildOpEnv();
205
+ if (ref.id.startsWith("op://")) {
206
+ try {
207
+ const result = execFileSync("op", ["read", ref.id], {
208
+ encoding: "utf-8",
209
+ timeout: 15e3,
210
+ stdio: ["pipe", "pipe", "pipe"],
211
+ env
212
+ }).trim();
213
+ return result || void 0;
214
+ } catch {
215
+ }
216
+ } else {
217
+ const itemName = ref.id.replace(/^\//, "");
218
+ const vault = getOpVault();
219
+ try {
220
+ const result = execFileSync("op", [
221
+ "item",
222
+ "get",
223
+ itemName,
224
+ "--vault",
225
+ vault,
226
+ "--fields",
227
+ "credential",
228
+ "--format",
229
+ "json"
230
+ ], {
231
+ encoding: "utf-8",
232
+ timeout: 15e3,
233
+ stdio: ["pipe", "pipe", "pipe"],
234
+ env
235
+ }).trim();
236
+ if (result) {
237
+ try {
238
+ const parsed = JSON.parse(result);
239
+ const field = Array.isArray(parsed) ? parsed[0] : parsed;
240
+ const value = field?.value ?? field;
241
+ if (typeof value === "string" && value.length > 0) {
242
+ return value;
243
+ }
244
+ } catch {
245
+ if (result.length > 0 && !result.startsWith("{") && !result.startsWith("[")) {
246
+ return result;
247
+ }
248
+ }
249
+ }
250
+ } catch {
251
+ }
252
+ }
174
253
  const secretsDir = path.join(os.homedir(), ".openclaw", "secrets");
175
254
  const filePath = path.join(secretsDir, ref.id.replace(/^\//, ""));
176
255
  if (existsSync(filePath)) {
@@ -179,15 +258,6 @@ function resolveFileSecret(ref) {
179
258
  } catch {
180
259
  }
181
260
  }
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
261
  } else {
192
262
  const filePath = path.isAbsolute(ref.id) ? ref.id : path.join(os.homedir(), ".openclaw", "secrets", ref.id.replace(/^\//, ""));
193
263
  if (existsSync(filePath)) {
@@ -597,4 +667,4 @@ export {
597
667
  buildChatCompletionTokenLimit,
598
668
  FallbackLlmClient
599
669
  };
600
- //# sourceMappingURL=chunk-AVOL6JGC.js.map
670
+ //# sourceMappingURL=chunk-KIA3HVQD.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>();\nconst DEFAULT_OP_VAULT = \"OpenClaw\";\nconst OP_SERVICE_ACCOUNT_TOKEN_PATH = path.join(os.homedir(), \".openclaw\", \"secrets\", \"op-service-account-token\");\nconst OP_VAULT_PATH = path.join(os.homedir(), \".openclaw\", \"secrets\", \"op-vault-name\");\n\nfunction getOpVault(): string {\n try {\n if (existsSync(OP_VAULT_PATH)) {\n const vault = readFileSync(OP_VAULT_PATH, \"utf-8\").trim();\n if (vault) return vault;\n }\n } catch { /* silent */ }\n return process.env.OP_VAULT ?? DEFAULT_OP_VAULT;\n}\n\n/**\n * Build an env object with the 1Password service account token set,\n * so op CLI works without desktop app integration.\n */\nfunction buildOpEnv(): NodeJS.ProcessEnv {\n // If already set in env, use it\n if (process.env.OP_SERVICE_ACCOUNT_TOKEN) {\n return process.env;\n }\n // Read from the standard OpenClaw secrets file\n try {\n if (existsSync(OP_SERVICE_ACCOUNT_TOKEN_PATH)) {\n const token = readFileSync(OP_SERVICE_ACCOUNT_TOKEN_PATH, \"utf-8\").trim();\n if (token) {\n return { ...process.env, OP_SERVICE_ACCOUNT_TOKEN: token };\n }\n }\n } catch {\n // Silent — fall through to default env\n }\n return process.env;\n}\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 const env = ref.provider === \"op\" ? buildOpEnv() : process.env;\n try {\n const result = execFileSync(command, args, {\n encoding: \"utf-8\",\n timeout: 15_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env,\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 // OpenClaw's auto-migrate-secrets stores API keys as 1Password items.\n // ref.id can be:\n // - An item title (e.g., \"/agent-models-fireworks-apiKey\") → use `op item get`\n // - An op:// URI (e.g., \"op://vault/item/field\") → use `op read`\n const env = buildOpEnv();\n\n if (ref.id.startsWith(\"op://\")) {\n // Direct op:// secret reference — use `op read`\n try {\n const result = execFileSync(\"op\", [\"read\", ref.id], {\n encoding: \"utf-8\",\n timeout: 15_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env,\n }).trim();\n return result || undefined;\n } catch {\n // Silent — op may not be available\n }\n } else {\n // Item title — use `op item get` with vault\n const itemName = ref.id.replace(/^\\//, \"\");\n const vault = getOpVault();\n try {\n const result = execFileSync(\"op\", [\n \"item\", \"get\", itemName,\n \"--vault\", vault,\n \"--fields\", \"credential\",\n \"--format\", \"json\",\n ], {\n encoding: \"utf-8\",\n timeout: 15_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env,\n }).trim();\n if (result) {\n try {\n const parsed = JSON.parse(result);\n // op returns various shapes:\n // - Single field object: {\"value\": \"sk-...\", ...}\n // - Array of field objects: [{\"value\": \"sk-...\", ...}]\n // - Plain string (older op versions)\n const field = Array.isArray(parsed) ? parsed[0] : parsed;\n const value = field?.value ?? field;\n if (typeof value === \"string\" && value.length > 0) {\n return value;\n }\n } catch {\n if (result.length > 0 && !result.startsWith(\"{\") && !result.startsWith(\"[\")) {\n return result;\n }\n }\n }\n } catch {\n // Silent — op may not be available or item not found\n }\n }\n\n // Fallback: try reading from a local secrets file\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 // Silent\n }\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":[]}
@@ -3,7 +3,7 @@ import {
3
3
  CompoundingEngine,
4
4
  SharedContextManager,
5
5
  defaultTierMigrationCycleBudget
6
- } from "./chunk-IEFSMVQV.js";
6
+ } from "./chunk-OLJAEA5I.js";
7
7
  import {
8
8
  searchCausalTrajectories
9
9
  } from "./chunk-IMMYYNXG.js";
@@ -36,7 +36,7 @@ import {
36
36
  buildChatCompletionTokenLimit,
37
37
  extractJsonCandidates,
38
38
  shouldAssumeOpenAiChatCompletions
39
- } from "./chunk-AVOL6JGC.js";
39
+ } from "./chunk-KIA3HVQD.js";
40
40
  import {
41
41
  BoxBuilder,
42
42
  assertIsoRecordedAt,
@@ -22309,7 +22309,7 @@ var Orchestrator = class _Orchestrator {
22309
22309
  );
22310
22310
  return result;
22311
22311
  }
22312
- const { FallbackLlmClient: FallbackLlmClient2 } = await import("./fallback-llm-GF6NMVWP.js");
22312
+ const { FallbackLlmClient: FallbackLlmClient2 } = await import("./fallback-llm-46JU5PST.js");
22313
22313
  const useGateway = this.config.modelSource === "gateway";
22314
22314
  const modelSetting = this.config.semanticConsolidationModel;
22315
22315
  if (modelSetting === "fast" && this.fastLlm && !useGateway) {
@@ -24546,7 +24546,7 @@ ${trimmedBody}`;
24546
24546
  return null;
24547
24547
  }
24548
24548
  try {
24549
- const { getCalibrationRulesForRecall, buildCalibrationRecallSection } = await import("./calibration-WQM24F3Z.js");
24549
+ const { getCalibrationRulesForRecall, buildCalibrationRecallSection } = await import("./calibration-OOOYE2ID.js");
24550
24550
  const rules = await getCalibrationRulesForRecall(this.config.memoryDir);
24551
24551
  if (rules.length === 0) {
24552
24552
  recordRecallSectionMetric({
@@ -31534,4 +31534,4 @@ export {
31534
31534
  EngramAccessInputError,
31535
31535
  EngramAccessService
31536
31536
  };
31537
- //# sourceMappingURL=chunk-HOO364J6.js.map
31537
+ //# sourceMappingURL=chunk-KZMICTC7.js.map
@@ -830,7 +830,7 @@ var CompoundingEngine = class {
830
830
  let promotionCandidates = this.config.compoundingSemanticEnabled ? this.derivePromotionCandidates(outcomeSummary, mistakes.registry, rubrics) : [];
831
831
  if (this.config.cmcConsolidationEnabled) {
832
832
  try {
833
- const { deriveCausalPromotionCandidates } = await import("./causal-consolidation-GNGU4MUV.js");
833
+ const { deriveCausalPromotionCandidates } = await import("./causal-consolidation-BDMZMX2D.js");
834
834
  const causalCandidates = await deriveCausalPromotionCandidates({
835
835
  memoryDir: this.config.memoryDir,
836
836
  causalTrajectoryStoreDir: this.config.causalTrajectoryStoreDir,
@@ -851,7 +851,7 @@ var CompoundingEngine = class {
851
851
  }
852
852
  if (this.config.calibrationEnabled) {
853
853
  try {
854
- const { runCalibrationConsolidation } = await import("./calibration-WQM24F3Z.js");
854
+ const { runCalibrationConsolidation } = await import("./calibration-OOOYE2ID.js");
855
855
  const calRules = await runCalibrationConsolidation({
856
856
  memoryDir: this.config.memoryDir,
857
857
  gatewayConfig: this.config.gatewayConfig,
@@ -1839,4 +1839,4 @@ export {
1839
1839
  defaultTierMigrationCycleBudget,
1840
1840
  CompoundingEngine
1841
1841
  };
1842
- //# sourceMappingURL=chunk-IEFSMVQV.js.map
1842
+ //# sourceMappingURL=chunk-OLJAEA5I.js.map
@@ -2,11 +2,11 @@
2
2
  import {
3
3
  CompoundingEngine,
4
4
  defaultTierMigrationCycleBudget
5
- } from "./chunk-IEFSMVQV.js";
5
+ } from "./chunk-OLJAEA5I.js";
6
6
  import "./chunk-DTCQ2KEX.js";
7
7
  import "./chunk-SSIIJJKA.js";
8
8
  export {
9
9
  CompoundingEngine,
10
10
  defaultTierMigrationCycleBudget
11
11
  };
12
- //# sourceMappingURL=engine-CNQZ35RB.js.map
12
+ //# sourceMappingURL=engine-63EMTVP7.js.map
@@ -1,9 +1,9 @@
1
1
  // openclaw-engram: Local-first memory plugin
2
2
  import {
3
3
  FallbackLlmClient
4
- } from "./chunk-AVOL6JGC.js";
4
+ } from "./chunk-KIA3HVQD.js";
5
5
  import "./chunk-SSIIJJKA.js";
6
6
  export {
7
7
  FallbackLlmClient
8
8
  };
9
- //# sourceMappingURL=fallback-llm-GF6NMVWP.js.map
9
+ //# sourceMappingURL=fallback-llm-46JU5PST.js.map
package/dist/index.js CHANGED
@@ -83,8 +83,8 @@ import {
83
83
  validateRouteTarget,
84
84
  validateWorkProductLedgerEntry,
85
85
  wrapWorkLayerContext
86
- } from "./chunk-HOO364J6.js";
87
- import "./chunk-IEFSMVQV.js";
86
+ } from "./chunk-KZMICTC7.js";
87
+ import "./chunk-OLJAEA5I.js";
88
88
  import {
89
89
  getCausalTrajectoryStoreStatus
90
90
  } from "./chunk-IMMYYNXG.js";
@@ -111,7 +111,7 @@ import {
111
111
  import {
112
112
  analyzeGraphHealth
113
113
  } from "./chunk-6KX4XLQJ.js";
114
- import "./chunk-AVOL6JGC.js";
114
+ import "./chunk-KIA3HVQD.js";
115
115
  import {
116
116
  assertIsoRecordedAt,
117
117
  assertSafePathSegment,
@@ -9441,7 +9441,7 @@ async function runSemanticRulePromoteCliCommand(options) {
9441
9441
  });
9442
9442
  }
9443
9443
  async function runCompoundingPromoteCliCommand(options) {
9444
- const { CompoundingEngine } = await import("./engine-CNQZ35RB.js");
9444
+ const { CompoundingEngine } = await import("./engine-63EMTVP7.js");
9445
9445
  const config = parseConfig({
9446
9446
  memoryDir: options.memoryDir,
9447
9447
  qmdEnabled: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@joshuaswarren/openclaw-engram",
3
- "version": "9.1.18",
3
+ "version": "9.1.19",
4
4
  "type": "module",
5
5
  "description": "Local-first memory plugin for OpenClaw. LLM-powered extraction, markdown storage, hybrid search via QMD.",
6
6
  "keywords": [
@@ -1 +0,0 @@
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":[]}