@happyvertical/smrt-inference 0.0.0-stage → 0.60.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/AGENTS.md +206 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +7 -0
  4. package/README.md +73 -2
  5. package/agents/fusions.md +105 -0
  6. package/agents/hosted.md +161 -0
  7. package/agents/resolver.md +65 -0
  8. package/agents/settings.md +107 -0
  9. package/dist/__smrt-register__.d.ts +2 -0
  10. package/dist/__smrt-register__.d.ts.map +1 -0
  11. package/dist/chunks/InferenceOverrideCollection-Dat4TrK5.js +423 -0
  12. package/dist/chunks/InferenceOverrideCollection-Dat4TrK5.js.map +1 -0
  13. package/dist/chunks/provider-config-BSpIQRVM.js +1873 -0
  14. package/dist/chunks/provider-config-BSpIQRVM.js.map +1 -0
  15. package/dist/classify.d.ts +32 -0
  16. package/dist/classify.d.ts.map +1 -0
  17. package/dist/config.d.ts +89 -0
  18. package/dist/config.d.ts.map +1 -0
  19. package/dist/errors.d.ts +51 -0
  20. package/dist/errors.d.ts.map +1 -0
  21. package/dist/executor.d.ts +45 -0
  22. package/dist/executor.d.ts.map +1 -0
  23. package/dist/fusion-store.d.ts +16 -0
  24. package/dist/fusion-store.d.ts.map +1 -0
  25. package/dist/fusion.d.ts +155 -0
  26. package/dist/fusion.d.ts.map +1 -0
  27. package/dist/gate.d.ts +143 -0
  28. package/dist/gate.d.ts.map +1 -0
  29. package/dist/gate.js +94 -0
  30. package/dist/gate.js.map +1 -0
  31. package/dist/hosted.d.ts +461 -0
  32. package/dist/hosted.d.ts.map +1 -0
  33. package/dist/index.d.ts +9 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +8 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/manifest.json +453 -0
  38. package/dist/models/InferenceOverride.d.ts +38 -0
  39. package/dist/models/InferenceOverride.d.ts.map +1 -0
  40. package/dist/models/InferenceOverrideCollection.d.ts +35 -0
  41. package/dist/models/InferenceOverrideCollection.d.ts.map +1 -0
  42. package/dist/models.d.ts +11 -0
  43. package/dist/models.d.ts.map +1 -0
  44. package/dist/models.js +2 -0
  45. package/dist/node.d.ts +110 -0
  46. package/dist/node.d.ts.map +1 -0
  47. package/dist/node.js +1414 -0
  48. package/dist/node.js.map +1 -0
  49. package/dist/provider-config.d.ts +113 -0
  50. package/dist/provider-config.d.ts.map +1 -0
  51. package/dist/register.d.ts +30 -0
  52. package/dist/register.d.ts.map +1 -0
  53. package/dist/resolver.d.ts +166 -0
  54. package/dist/resolver.d.ts.map +1 -0
  55. package/dist/resolver.js +291 -0
  56. package/dist/resolver.js.map +1 -0
  57. package/dist/server.d.ts +25 -0
  58. package/dist/server.d.ts.map +1 -0
  59. package/dist/server.js +1138 -0
  60. package/dist/server.js.map +1 -0
  61. package/dist/settings/cache.d.ts +5 -0
  62. package/dist/settings/cache.d.ts.map +1 -0
  63. package/dist/settings/keys.d.ts +70 -0
  64. package/dist/settings/keys.d.ts.map +1 -0
  65. package/dist/settings/layers.d.ts +68 -0
  66. package/dist/settings/layers.d.ts.map +1 -0
  67. package/dist/settings/override-service.d.ts +119 -0
  68. package/dist/settings/override-service.d.ts.map +1 -0
  69. package/dist/settings/preferences.d.ts +137 -0
  70. package/dist/settings/preferences.d.ts.map +1 -0
  71. package/dist/settings/resolver.d.ts +41 -0
  72. package/dist/settings/resolver.d.ts.map +1 -0
  73. package/dist/settings/settings-service.d.ts +355 -0
  74. package/dist/settings/settings-service.d.ts.map +1 -0
  75. package/dist/settings/targets.d.ts +112 -0
  76. package/dist/settings/targets.d.ts.map +1 -0
  77. package/dist/settings/transcripts.d.ts +33 -0
  78. package/dist/settings/transcripts.d.ts.map +1 -0
  79. package/dist/smrt-knowledge.json +341 -0
  80. package/dist/smrt-knowledge.okf.md +80 -0
  81. package/dist/svelte/components/InferenceAliasEditor.svelte +210 -0
  82. package/dist/svelte/components/InferenceAliasEditor.svelte.d.ts +13 -0
  83. package/dist/svelte/components/InferenceAliasEditor.svelte.d.ts.map +1 -0
  84. package/dist/svelte/components/InferenceDefaultView.svelte +330 -0
  85. package/dist/svelte/components/InferenceDefaultView.svelte.d.ts +15 -0
  86. package/dist/svelte/components/InferenceDefaultView.svelte.d.ts.map +1 -0
  87. package/dist/svelte/components/InferenceFusionList.svelte +141 -0
  88. package/dist/svelte/components/InferenceFusionList.svelte.d.ts +16 -0
  89. package/dist/svelte/components/InferenceFusionList.svelte.d.ts.map +1 -0
  90. package/dist/svelte/components/InferenceSettingsPanel.svelte +392 -0
  91. package/dist/svelte/components/InferenceSettingsPanel.svelte.d.ts +84 -0
  92. package/dist/svelte/components/InferenceSettingsPanel.svelte.d.ts.map +1 -0
  93. package/dist/svelte/components/InferenceTierRow.svelte +199 -0
  94. package/dist/svelte/components/InferenceTierRow.svelte.d.ts +14 -0
  95. package/dist/svelte/components/InferenceTierRow.svelte.d.ts.map +1 -0
  96. package/dist/svelte/components/InferenceTranscriptSettings.svelte +165 -0
  97. package/dist/svelte/components/InferenceTranscriptSettings.svelte.d.ts +18 -0
  98. package/dist/svelte/components/InferenceTranscriptSettings.svelte.d.ts.map +1 -0
  99. package/dist/svelte/components/InferenceUsageTable.svelte +177 -0
  100. package/dist/svelte/components/InferenceUsageTable.svelte.d.ts +21 -0
  101. package/dist/svelte/components/InferenceUsageTable.svelte.d.ts.map +1 -0
  102. package/dist/svelte/index.d.ts +17 -0
  103. package/dist/svelte/index.d.ts.map +1 -0
  104. package/dist/svelte/index.js +14 -0
  105. package/dist/svelte/types.d.ts +262 -0
  106. package/dist/svelte/types.d.ts.map +1 -0
  107. package/dist/svelte/types.js +124 -0
  108. package/dist/types.d.ts +47 -0
  109. package/dist/types.d.ts.map +1 -0
  110. package/dist/types.js +13 -0
  111. package/dist/types.js.map +1 -0
  112. package/package.json +105 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-config-BSpIQRVM.js","names":["target"],"sources":["../../src/errors.ts","../../src/fusion-store.ts","../../src/config.ts","../../src/classify.ts","../../src/executor.ts","../../src/fusion.ts","../../src/register.ts","../../src/provider-config.ts"],"sourcesContent":["import { SmrtError } from '@happyvertical/smrt-core/smrt-error';\nimport type {\n InferenceConfigIssue,\n InferenceSubstitution,\n InferenceSubstitutionReason,\n} from './types.js';\n\n/** An `inference` config block that cannot bind (`INFERENCE_CONFIG_INVALID`). */\nexport class InferenceConfigError extends SmrtError {\n readonly issues: InferenceConfigIssue[];\n\n constructor(issues: InferenceConfigIssue[]) {\n super(\n `Invalid inference config: ${issues.map((issue) => issue.message).join('; ')}`,\n 'INFERENCE_CONFIG_INVALID',\n 'configuration',\n { issues },\n );\n this.issues = issues;\n }\n}\n\n/**\n * A chain call that never produced a complete answer\n * (`INFERENCE_EXHAUSTED`): every candidate failed, or one streamed text and\n * then failed without `allowPartial`. `cause` is the last provider error.\n */\nexport class InferenceExhaustedError extends SmrtError {\n /** The failure that ended the walk. */\n readonly reason: InferenceSubstitutionReason;\n /** The full fallback trail, ending with `to: null`. */\n readonly substitutions: InferenceSubstitution[];\n /** Text already streamed to the caller, for a `partial` ending. */\n readonly partialText?: string;\n\n constructor(input: {\n reason: InferenceSubstitutionReason;\n substitutions: InferenceSubstitution[];\n tierRequested: string;\n partialText?: string;\n cause?: unknown;\n }) {\n const last = input.substitutions.at(-1);\n super(\n input.reason === 'partial'\n ? `Inference candidate ${last?.from ?? 'unknown'} failed after streaming; no other candidate may extend its reply.`\n : `No inference candidate answered tier \"${input.tierRequested}\" (last failure: ${input.reason}).`,\n 'INFERENCE_EXHAUSTED',\n 'ai',\n {\n reason: input.reason,\n tierRequested: input.tierRequested,\n substitutions: input.substitutions,\n },\n input.cause instanceof Error ? input.cause : undefined,\n );\n this.reason = input.reason;\n this.substitutions = input.substitutions;\n if (input.partialText !== undefined) this.partialText = input.partialText;\n }\n}\n\n/** The result shape {@link InferenceFusionError} carries (fusion.ts). */\ninterface FailedFusionRun {\n runId: string;\n fusionKey: string;\n seats: Array<{\n name: string;\n status: string;\n failure?: { reason: string; message: string };\n }>;\n}\n\n/**\n * A fusion run that produced no answer (`INFERENCE_FUSION_FAILED`, #4753):\n * every seat that ran died, or the run stopped on an unexpected error. The\n * run is recorded as `failed`; `result` holds every seat's outcome.\n */\nexport class InferenceFusionError extends SmrtError {\n readonly result: FailedFusionRun;\n\n constructor(result: FailedFusionRun, cause?: unknown) {\n const failures = result.seats\n .filter((seat) => seat.failure)\n .map((seat) => `${seat.name}: ${seat.failure?.reason}`);\n super(\n `Fusion \"${result.fusionKey}\" produced no answer (run ${result.runId}${\n failures.length > 0 ? `; ${failures.join(', ')}` : ''\n }).`,\n 'INFERENCE_FUSION_FAILED',\n 'ai',\n { runId: result.runId, fusionKey: result.fusionKey, failures },\n cause instanceof Error ? cause : undefined,\n );\n this.result = result;\n }\n}\n","/**\n * Process registry for code-defined fusions (#4753), on `globalThis` so it\n * survives HMR and duplicate package copies like core's registries. Storage\n * only: `defineFusion()` (fusion.ts) validates before it stores.\n */\nimport type {\n InferenceConfig,\n InferenceFusionDefinition,\n} from '@happyvertical/smrt-core';\n\nconst STORE_KEY = Symbol.for('smrt.inference.fusions');\n\ntype StoreHolder = {\n [STORE_KEY]?: Map<string, InferenceFusionDefinition>;\n};\n\n/** The registry map (created on first use). */\nexport function fusionStore(): Map<string, InferenceFusionDefinition> {\n const holder = globalThis as StoreHolder;\n holder[STORE_KEY] ??= new Map();\n return holder[STORE_KEY];\n}\n\n/**\n * The definition a fusion key runs: `inference.fusions.<key>` from config\n * when present (the app's layer wins), else the `defineFusion()` one.\n */\nexport function lookupFusion(\n key: string,\n config: InferenceConfig | undefined,\n): InferenceFusionDefinition | undefined {\n const fromConfig = config?.fusions;\n if (fromConfig && Object.hasOwn(fromConfig, key)) return fromConfig[key];\n return fusionStore().get(key);\n}\n\n/** True when the smrt-prompts process registry holds `key`. */\nexport function isPromptRegistered(key: string): boolean {\n const registry = (globalThis as { __smrtPromptRegistry?: unknown })\n .__smrtPromptRegistry;\n return registry instanceof Map && registry.has(key);\n}\n","/**\n * Alias config validation and chain expansion (#4752). Browser-safe: reads\n * the environment through `globalThis.process` when one exists.\n */\nimport {\n INFERENCE_FUSION_MODES,\n INFERENCE_PRESETS,\n INFERENCE_TIERS,\n type InferenceAlias,\n type InferenceCandidate,\n type InferenceConfig,\n type InferenceTarget,\n type InferenceTier,\n inferenceTargetKind,\n isInferencePresetId,\n isInferenceTierRequest,\n} from '@happyvertical/smrt-core';\nimport { InferenceConfigError } from './errors.js';\nimport { isPromptRegistered, lookupFusion } from './fusion-store.js';\nimport type { InferenceConfigIssue, InferenceFailureClass } from './types.js';\n\n/** Target kinds this package runs. */\nexport const CHAIN_KINDS = ['alias', 'candidates'] as const;\n\n/** Placeholder key for keyless endpoints, matching core's presets. */\nconst KEYLESS_PLACEHOLDER = 'smrt-local';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction text(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() !== ''\n ? value.trim()\n : undefined;\n}\n\n/** Target kinds the executor runs: the chains plus `fusion` (#4753). */\nexport const EXECUTOR_KINDS = [...CHAIN_KINDS, 'fusion'] as const;\n\n/**\n * True when the config binds anything this package validates: aliases,\n * fusions, or a chain or fusion tier target.\n */\nexport function hasInferenceChains(config: InferenceConfig | undefined) {\n if (!config) return false;\n if (isRecord(config.aliases) && Object.keys(config.aliases).length > 0) {\n return true;\n }\n if (isRecord(config.fusions) && Object.keys(config.fusions).length > 0) {\n return true;\n }\n return Object.values(config.tiers ?? {}).some((target) =>\n (EXECUTOR_KINDS as readonly string[]).includes(\n inferenceTargetKind(target as InferenceTarget),\n ),\n );\n}\n\nfunction checkCandidate(\n candidate: unknown,\n path: string,\n aliases: Record<string, unknown>,\n issues: InferenceConfigIssue[],\n): void {\n if (!isRecord(candidate)) {\n issues.push({\n path,\n code: 'candidate-invalid',\n message: `${path} must be an object`,\n });\n return;\n }\n const alias = text(candidate.alias);\n if (candidate.alias !== undefined) {\n if (!alias) {\n issues.push({\n path,\n code: 'candidate-invalid',\n message: `${path}.alias must be a non-empty string`,\n });\n } else if (!Object.hasOwn(aliases, alias)) {\n issues.push({\n path,\n code: 'alias-unknown',\n message: `${path} references unknown alias \"${alias}\"`,\n });\n }\n const extra = ['provider', 'model', 'preset', 'baseUrl', 'apiKeyEnv'].find(\n (key) => candidate[key] !== undefined,\n );\n if (extra) {\n issues.push({\n path,\n code: 'candidate-invalid',\n message: `${path} names an alias and \"${extra}\"; an alias candidate takes nothing else`,\n });\n }\n return;\n }\n const preset = text(candidate.preset);\n if (candidate.preset !== undefined) {\n if (!preset || !isInferencePresetId(preset)) {\n issues.push({\n path,\n code: 'preset-unknown',\n message: `${path} names unknown preset \"${String(candidate.preset)}\"; expected one of ${Object.keys(INFERENCE_PRESETS).join(', ')}`,\n });\n }\n if (!text(candidate.model)) {\n issues.push({\n path,\n code: 'candidate-invalid',\n message: `${path} names preset \"${String(candidate.preset)}\" without a model`,\n });\n }\n if (candidate.provider !== undefined) {\n issues.push({\n path,\n code: 'candidate-invalid',\n message: `${path} names both a preset and a provider`,\n });\n }\n return;\n }\n if (!text(candidate.provider) && !text(candidate.model)) {\n issues.push({\n path,\n code: 'candidate-invalid',\n message: `${path} needs an alias, a preset, or a provider and model`,\n });\n return;\n }\n if (\n (text(candidate.apiKeyEnv) || text(candidate.apiKey)) &&\n !text(candidate.baseUrl)\n ) {\n issues.push({\n path,\n code: 'candidate-key-without-endpoint',\n message: `${path} brings its own key without a baseUrl; a key travels only with its own endpoint (name the provider's baseUrl, or drop apiKeyEnv to use the provider's own key variable)`,\n });\n }\n}\n\nfunction checkCandidateList(\n list: unknown,\n path: string,\n aliases: Record<string, unknown>,\n issues: InferenceConfigIssue[],\n): void {\n if (!Array.isArray(list) || list.length === 0) {\n issues.push({\n path,\n code: 'alias-empty',\n message: `${path} has no candidates`,\n });\n return;\n }\n list.forEach((candidate, index) => {\n checkCandidate(candidate, `${path}[${index}]`, aliases, issues);\n });\n}\n\nfunction checkTarget(\n target: InferenceTarget,\n path: string,\n aliases: Record<string, unknown>,\n issues: InferenceConfigIssue[],\n config?: InferenceConfig,\n): void {\n const kind = inferenceTargetKind(target);\n if (kind === 'alias') {\n const name = text(target.alias);\n if (!name) {\n issues.push({\n path,\n code: 'candidate-invalid',\n message: `${path} has kind \"alias\" without an alias name`,\n });\n } else if (!Object.hasOwn(aliases, name)) {\n issues.push({\n path,\n code: 'alias-unknown',\n message: `${path} points at unknown alias \"${name}\"`,\n });\n }\n } else if (kind === 'candidates') {\n checkCandidateList(\n target.candidates,\n `${path}.candidates`,\n aliases,\n issues,\n );\n } else if (kind === 'fusion') {\n const name = text(target.fusion);\n if (!name) {\n issues.push({\n path,\n code: 'fusion-invalid',\n message: `${path} has kind \"fusion\" without a fusion key`,\n });\n } else if (!lookupFusion(name, config)) {\n issues.push({\n path,\n code: 'fusion-unknown',\n message: `${path} points at unknown fusion \"${name}\" (define it with defineFusion() or inference.fusions)`,\n });\n }\n }\n}\n\n/** Seats per mode: each mode's call count is fixed (#4753). */\nexport const FUSION_SEAT_COUNTS = {\n single: 1,\n pair: 3,\n handoff: 2,\n} as const;\n\n/** The gate's other choice label: run the remaining stage. */\nexport const FUSION_GATE_CONTINUE = 'continue';\n\n/** The `seat` tag of the gate's decision usage row; no seat may use it. */\nexport const FUSION_GATE_SEAT = 'gate';\n\n/**\n * Structural problems of one fusion definition, named by path (`path` is\n * `inference.fusions.<key>` or `fusions.<key>` for `defineFusion()`).\n * Prompt registration is checked separately ({@link findFusionPromptIssues})\n * because the doctor runs without the app's prompts loaded.\n */\nexport function findFusionDefinitionIssues(\n definition: unknown,\n path: string,\n config: InferenceConfig | undefined,\n): InferenceConfigIssue[] {\n const issues: InferenceConfigIssue[] = [];\n const invalid = (at: string, message: string) =>\n issues.push({ path: at, code: 'fusion-invalid', message });\n if (!isRecord(definition)) {\n invalid(path, `${path} must be an object with mode and seats`);\n return issues;\n }\n const mode = definition.mode;\n const known = (INFERENCE_FUSION_MODES as readonly unknown[]).includes(mode);\n if (!known) {\n invalid(\n `${path}.mode`,\n `${path}.mode must be one of ${INFERENCE_FUSION_MODES.join(', ')}; got \"${String(mode)}\"`,\n );\n }\n if (\n definition.description !== undefined &&\n typeof definition.description !== 'string'\n ) {\n invalid(`${path}.description`, `${path}.description must be a string`);\n }\n const seats = definition.seats;\n if (!Array.isArray(seats)) {\n invalid(`${path}.seats`, `${path}.seats must be an array of seats`);\n } else {\n const expected = known\n ? FUSION_SEAT_COUNTS[mode as keyof typeof FUSION_SEAT_COUNTS]\n : undefined;\n if (expected !== undefined && seats.length !== expected) {\n invalid(\n `${path}.seats`,\n `${path}.seats must hold exactly ${expected} seat(s) for mode \"${String(mode)}\"; got ${seats.length}`,\n );\n }\n const aliases: Record<string, unknown> = isRecord(config?.aliases)\n ? config.aliases\n : {};\n const names = new Map<string, number>();\n seats.forEach((seat, index) => {\n const at = `${path}.seats[${index}]`;\n if (!isRecord(seat)) {\n invalid(at, `${at} must be an object with prompt and target`);\n return;\n }\n const prompt = text(seat.prompt);\n if (!prompt) {\n invalid(\n `${at}.prompt`,\n `${at}.prompt must name a registered prompt key`,\n );\n }\n if (seat.name !== undefined && !text(seat.name)) {\n invalid(`${at}.name`, `${at}.name must be a non-empty string`);\n }\n const name = text(seat.name) ?? prompt;\n if (name) {\n const first = names.get(name);\n if (name === FUSION_GATE_SEAT) {\n invalid(\n `${at}.name`,\n `${at}.name \"${FUSION_GATE_SEAT}\" is reserved for the decision gate's usage row`,\n );\n } else if (first !== undefined) {\n invalid(\n `${at}.name`,\n `${at} has the same name \"${name}\" as seats[${first}]; name each seat (the name defaults to the prompt key)`,\n );\n } else {\n names.set(name, index);\n }\n }\n if (\n seat.temperature !== undefined &&\n (typeof seat.temperature !== 'number' ||\n !Number.isFinite(seat.temperature))\n ) {\n invalid(`${at}.temperature`, `${at}.temperature must be a number`);\n }\n if (\n seat.output !== undefined &&\n seat.output !== 'text' &&\n seat.output !== 'json'\n ) {\n invalid(`${at}.output`, `${at}.output must be \"text\" or \"json\"`);\n }\n const target = seat.target;\n if (typeof target === 'string') {\n if (!isInferenceTierRequest(target)) {\n invalid(\n `${at}.target`,\n `${at}.target \"${target}\" is not a tier (auto, ${INFERENCE_TIERS.join(', ')})`,\n );\n }\n } else if (isRecord(target)) {\n if (inferenceTargetKind(target as InferenceTarget) === 'fusion') {\n issues.push({\n path: `${at}.target`,\n code: 'fusion-nested',\n message: `${at}.target names another fusion; seats run a tier, an alias or a model, never a fusion`,\n });\n } else {\n checkTarget(\n target as InferenceTarget,\n `${at}.target`,\n aliases,\n issues,\n config,\n );\n }\n } else {\n invalid(\n `${at}.target`,\n `${at}.target must be a tier name or a target ({ alias }, { candidates } or { provider, model })`,\n );\n }\n });\n }\n const gate = definition.gate;\n if (gate !== undefined) {\n if (mode !== 'pair' && mode !== 'handoff') {\n invalid(`${path}.gate`, `${path}.gate applies to pair and handoff only`);\n } else if (!isRecord(gate)) {\n invalid(`${path}.gate`, `${path}.gate must be an object`);\n } else {\n if (!text(gate.criteria)) {\n invalid(\n `${path}.gate.criteria`,\n `${path}.gate.criteria must be a non-empty string`,\n );\n }\n const when = gate.sufficientWhen;\n if (!isRecord(when)) {\n invalid(\n `${path}.gate.sufficientWhen`,\n `${path}.gate.sufficientWhen must be { choice, minConfidence }`,\n );\n } else {\n const choice = text(when.choice);\n if (!choice || choice === FUSION_GATE_CONTINUE) {\n invalid(\n `${path}.gate.sufficientWhen.choice`,\n `${path}.gate.sufficientWhen.choice must be a non-empty label other than \"${FUSION_GATE_CONTINUE}\"`,\n );\n }\n const min = when.minConfidence;\n if (\n typeof min !== 'number' ||\n !Number.isFinite(min) ||\n min < 0 ||\n min > 1\n ) {\n invalid(\n `${path}.gate.sufficientWhen.minConfidence`,\n `${path}.gate.sufficientWhen.minConfidence must be a number in [0, 1]`,\n );\n }\n }\n }\n }\n return issues;\n}\n\n/** Seats of `definition` whose prompt key no `definePrompt()` registered. */\nexport function findFusionDefinitionPromptIssues(\n definition: unknown,\n path: string,\n): InferenceConfigIssue[] {\n if (!isRecord(definition) || !Array.isArray(definition.seats)) return [];\n const issues: InferenceConfigIssue[] = [];\n definition.seats.forEach((seat, index) => {\n const prompt = isRecord(seat) ? text(seat.prompt) : undefined;\n if (prompt && !isPromptRegistered(prompt)) {\n const at = `${path}.seats[${index}].prompt`;\n issues.push({\n path: at,\n code: 'fusion-prompt-unknown',\n message: `${at} names prompt \"${prompt}\", which no definePrompt() registered`,\n });\n }\n });\n return issues;\n}\n\n/**\n * Seats of `inference.fusions` whose prompt key is not registered. A load\n * error: the validating resolver and the executor refuse such a config.\n */\nexport function findFusionPromptIssues(\n config: InferenceConfig | undefined,\n): InferenceConfigIssue[] {\n if (!isRecord(config?.fusions)) return [];\n return Object.entries(config.fusions).flatMap(([key, definition]) =>\n findFusionDefinitionPromptIssues(definition, `inference.fusions.${key}`),\n );\n}\n\n/**\n * Validate one resolved target against the config's aliases. A resolver\n * (#4666 per-user bindings) can return chains that never appear in config,\n * so the executor checks every target it runs, not only the config block.\n */\nexport function validateInferenceTarget(\n target: InferenceTarget,\n path: string,\n config: InferenceConfig | undefined,\n): void {\n const issues: InferenceConfigIssue[] = [];\n const aliases: Record<string, unknown> = isRecord(config?.aliases)\n ? config.aliases\n : {};\n checkTarget(target, path, aliases, issues, config);\n if (issues.length > 0) throw new InferenceConfigError(issues);\n}\n\n/** Alias names a chain references directly (its `alias` candidates). */\nfunction aliasEdges(alias: unknown): string[] {\n if (!isRecord(alias) || !Array.isArray(alias.candidates)) return [];\n return alias.candidates\n .map((candidate) =>\n isRecord(candidate) ? text(candidate.alias) : undefined,\n )\n .filter((name): name is string => !!name);\n}\n\n/**\n * Every problem in an `inference` block's chains: an alias with no\n * candidates, a reference to an unknown alias, an alias cycle, a malformed\n * candidate. Each issue names its offender by config path.\n */\nexport function findInferenceConfigIssues(\n config: InferenceConfig | undefined,\n): InferenceConfigIssue[] {\n const issues: InferenceConfigIssue[] = [];\n if (!config) return issues;\n const aliases: Record<string, unknown> = isRecord(config.aliases)\n ? config.aliases\n : {};\n\n for (const [name, alias] of Object.entries(aliases)) {\n const path = `inference.aliases.${name}`;\n if (!isRecord(alias)) {\n issues.push({\n path,\n code: 'alias-empty',\n message: `${path} must be an object with candidates`,\n });\n continue;\n }\n checkCandidateList(alias.candidates, `${path}.candidates`, aliases, issues);\n }\n\n for (const tier of INFERENCE_TIERS) {\n const target = config.tiers?.[tier];\n if (!target) continue;\n checkTarget(target, `inference.tiers.${tier}`, aliases, issues, config);\n }\n\n if (config.fusions !== undefined && !isRecord(config.fusions)) {\n issues.push({\n path: 'inference.fusions',\n code: 'fusion-invalid',\n message: 'inference.fusions must be an object of named fusions',\n });\n } else {\n for (const [key, definition] of Object.entries(config.fusions ?? {})) {\n issues.push(\n ...findFusionDefinitionIssues(\n definition,\n `inference.fusions.${key}`,\n config,\n ),\n );\n }\n }\n\n // Cycles: depth-first over alias → alias edges, reported once each.\n const state = new Map<string, 'visiting' | 'done'>();\n const reported = new Set<string>();\n const visit = (name: string, stack: string[]) => {\n if (state.get(name) === 'done') return;\n if (state.get(name) === 'visiting') {\n const cycle = [...stack.slice(stack.indexOf(name)), name];\n const key = [...cycle.slice(0, -1)].sort().join('|');\n if (!reported.has(key)) {\n reported.add(key);\n issues.push({\n path: `inference.aliases.${name}`,\n code: 'alias-cycle',\n message: `inference.aliases has a cycle: ${cycle.join(' -> ')}`,\n });\n }\n return;\n }\n state.set(name, 'visiting');\n for (const next of aliasEdges(aliases[name])) {\n if (Object.hasOwn(aliases, next)) visit(next, [...stack, name]);\n }\n state.set(name, 'done');\n };\n for (const name of Object.keys(aliases)) visit(name, []);\n\n return issues;\n}\n\n/**\n * Throw an {@link InferenceConfigError} naming every offender, including\n * fusion seats whose prompt key is not registered (a load error).\n */\nexport function validateInferenceConfig(\n config: InferenceConfig | undefined,\n): void {\n const issues = [\n ...findInferenceConfigIssues(config),\n ...findFusionPromptIssues(config),\n ];\n if (issues.length > 0) throw new InferenceConfigError(issues);\n}\n\n/** One expanded chain entry, ready to bind. */\nexport interface ChainStep {\n /** The tier whose chain this step belongs to. */\n tier: InferenceTier;\n /** Stable, key-free label used in substitution records. */\n label: string;\n /** A `single` target for core's `clientFor()`. */\n target: InferenceTarget;\n /** Per-call defaults for this candidate. */\n params?: Record<string, unknown>;\n /** Dedupe key: provider, model, endpoint and credential source. */\n identity: string;\n /** Set when the step cannot run (missing key); it is skipped, recorded. */\n unavailable?: InferenceFailureClass;\n /** The alias the step came from, if any. */\n alias?: string;\n}\n\nfunction readEnv(name: string): string | undefined {\n const env = (\n globalThis as { process?: { env?: Record<string, string | undefined> } }\n ).process?.env;\n return text(env?.[name]);\n}\n\n/** Label for a candidate: `provider/model`, `preset:<id>/model`, `default`. */\nexport function candidateLabel(candidate: InferenceCandidate): string {\n const model = text(candidate.model);\n const preset = text(candidate.preset);\n if (preset) return `preset:${preset}/${model ?? 'default'}`;\n const provider = text(candidate.provider);\n if (!provider && !model) return 'default';\n return `${provider ?? 'default'}/${model ?? 'default'}`;\n}\n\n/**\n * Bind one candidate to a `single` target. Keys come from `apiKey` or the\n * variable named by `apiKeyEnv` at call time; a named variable that is unset\n * makes the step `unavailable: 'credential'` (skipped and recorded, never\n * sent keyless to a key-requiring endpoint).\n */\nexport function candidateToStep(\n candidate: InferenceCandidate,\n tier: InferenceTier,\n alias?: string,\n): ChainStep {\n const label = candidateLabel(candidate);\n const model = text(candidate.model);\n const params = isRecord(candidate.params) ? candidate.params : undefined;\n const keyEnv = text(candidate.apiKeyEnv);\n const key = text(candidate.apiKey) ?? (keyEnv ? readEnv(keyEnv) : undefined);\n const missingKey = !!keyEnv && !key && !text(candidate.apiKey);\n const preset = text(candidate.preset);\n let target: InferenceTarget;\n if (preset && isInferencePresetId(preset)) {\n const definition = INFERENCE_PRESETS[preset];\n target = {\n provider: 'openai',\n baseUrl: text(candidate.baseUrl) ?? definition.baseUrl,\n ...(model ? { model } : {}),\n apiKey: key ?? KEYLESS_PLACEHOLDER,\n };\n const presetNeedsKey = definition.requiresApiKey && !key;\n return {\n tier,\n label,\n target,\n ...(params ? { params } : {}),\n // Call-local only, never logged: two keys are two routes.\n identity: JSON.stringify(['preset', preset, model, target.baseUrl, key]),\n ...(missingKey || presetNeedsKey\n ? { unavailable: 'credential' as const }\n : {}),\n ...(alias ? { alias } : {}),\n };\n }\n const provider = text(candidate.provider);\n const baseUrl = text(candidate.baseUrl);\n target = {\n ...(provider ? { provider } : {}),\n ...(model ? { model } : {}),\n ...(baseUrl ? { baseUrl } : {}),\n // A key is never dropped: without its own baseUrl, core's pair rule\n // refuses the target rather than running it on the configured key.\n ...(key ? { apiKey: key } : baseUrl ? { apiKey: KEYLESS_PLACEHOLDER } : {}),\n };\n return {\n tier,\n label,\n target,\n ...(params ? { params } : {}),\n // Call-local only, never logged: two keys are two routes.\n identity: JSON.stringify([provider, model, baseUrl, key ?? keyEnv]),\n ...(missingKey ? { unavailable: 'credential' as const } : {}),\n ...(alias ? { alias } : {}),\n };\n}\n\nfunction expandCandidates(\n candidates: readonly InferenceCandidate[],\n tier: InferenceTier,\n aliases: Record<string, InferenceAlias>,\n owner: string | undefined,\n visiting: Set<string>,\n out: ChainStep[],\n): void {\n for (const candidate of candidates) {\n const nested = text(candidate.alias);\n if (nested) expandAlias(nested, tier, aliases, visiting, out);\n else out.push(candidateToStep(candidate, tier, owner));\n }\n}\n\nfunction expandAlias(\n name: string,\n tier: InferenceTier,\n aliases: Record<string, InferenceAlias>,\n visiting: Set<string>,\n out: ChainStep[],\n): void {\n if (visiting.has(name)) {\n throw new InferenceConfigError([\n {\n path: `inference.aliases.${name}`,\n code: 'alias-cycle',\n message: `inference.aliases has a cycle through \"${name}\"`,\n },\n ]);\n }\n const alias = aliases[name];\n if (!alias || !Array.isArray(alias.candidates)) {\n throw new InferenceConfigError([\n {\n path: `inference.aliases.${name}`,\n code: 'alias-unknown',\n message: `unknown alias \"${name}\"`,\n },\n ]);\n }\n visiting.add(name);\n expandCandidates(alias.candidates, tier, aliases, name, visiting, out);\n visiting.delete(name);\n}\n\n/**\n * Expand a tier's target into ordered steps. A `single` target is one step\n * (an empty one is the configured client, labelled `default`); unknown\n * kinds expand to nothing (another executor's).\n */\nexport function expandTarget(\n target: InferenceTarget,\n tier: InferenceTier,\n config: InferenceConfig | undefined,\n): ChainStep[] {\n const aliases = (config?.aliases ?? {}) as Record<string, InferenceAlias>;\n const kind = inferenceTargetKind(target);\n const out: ChainStep[] = [];\n if (kind === 'alias') {\n expandAlias(String(target.alias ?? ''), tier, aliases, new Set(), out);\n } else if (kind === 'candidates') {\n expandCandidates(\n target.candidates ?? [],\n tier,\n aliases,\n undefined,\n new Set(),\n out,\n );\n } else if (kind === 'single') {\n const { kind: _kind, latency: _latency, params, ...single } = target;\n const provider = text(single.provider);\n const model = text(single.model);\n out.push({\n tier,\n label: candidateLabel({ provider, model }),\n target: { ...single },\n ...(isRecord(params) ? { params } : {}),\n identity: JSON.stringify([\n provider,\n model,\n text(single.baseUrl),\n // Per-call only, never logged: two inline keys are two routes.\n text(single.apiKey),\n ]),\n });\n }\n // A chain stamped with a binding origin as a whole (a resolver's hosted\n // chain, #4760) hands it to every candidate step that names none, so core\n // gates each hosted attempt in `clientFor()` and its usage meters as\n // hosted, on a ladder step too.\n const source = target.source;\n if (kind !== 'single' && source !== undefined) {\n for (const step of out) {\n if (step.target.source === undefined) {\n step.target = { ...step.target, source };\n }\n }\n }\n return out;\n}\n","/**\n * Failure classification for the chain walk (#4752).\n *\n * Classifies from structured facts only — the SDK error class name, its\n * `code`, `retryable`, and HTTP `status` — collected across the whole cause\n * chain (`cause`, `error`, `context.originalError`), the way core's\n * `db-errors.ts` classifies database failures. Message text is never read:\n * a provider rewording its error must not change routing.\n *\n * `@happyvertical/ai` maps provider failures onto `AIError` subclasses\n * (`AuthenticationError` AUTH_ERROR, `RateLimitError` RATE_LIMIT with the\n * provider error as `cause`, `ModelNotFoundError` MODEL_NOT_FOUND,\n * `ContentFilterError` CONTENT_FILTERED, AI_TIMEOUT, AI_ABORTED). It maps\n * other HTTP failures (5xx, 400) to `API_ERROR` / `UNKNOWN_ERROR` without the\n * status or cause; those classify as `transient` so a route outage still\n * advances, bounded by one retry per candidate. When a status survives in the\n * chain, a client error (other 4xx, `invalid_request_error`, context length)\n * stops the walk instead.\n */\nimport type { InferenceFailureClass } from './types.js';\n\ninterface ErrorFacts {\n names: Set<string>;\n codes: Set<string>;\n statuses: Set<number>;\n /** A rate-limit error that reports it will not reset soon. */\n rateLimitNotSoon: boolean;\n /** Any SDK error marked retryable. */\n retryable: boolean;\n}\n\nconst MAX_CAUSE_DEPTH = 8;\n\nconst QUOTA_CODES = new Set([\n 'insufficient_quota',\n 'billing_hard_limit_reached',\n 'billing_not_active',\n 'quota_exceeded',\n 'subscription_sharing_usage_limit_exceeded',\n]);\nconst QUOTA_NAMES = new Set(['ChatGPTPlanUsageLimitError']);\n\nconst CREDENTIAL_CODES = new Set([\n 'AUTH_ERROR',\n // Core refused to bind the candidate before sending anything (pair rule,\n // HAVE_AI_* fallbacks, injected client): this route has no usable key.\n 'INFERENCE_TARGET_UNBOUND',\n 'invalid_api_key',\n 'authentication_error',\n 'permission_error',\n 'subscription_sharing_invalid_user',\n]);\nconst CREDENTIAL_NAMES = new Set([\n 'AuthenticationError',\n 'PermissionDeniedError',\n 'AIProviderNotConfiguredError',\n 'ChatGPTPlanSessionRevokedError',\n]);\n\nconst MISSING_MODEL_CODES = new Set(['MODEL_NOT_FOUND', 'model_not_found']);\nconst MISSING_MODEL_NAMES = new Set(['ModelNotFoundError', 'NotFoundError']);\n\nconst REFUSAL_CODES = new Set(['CONTENT_FILTERED', 'content_filter']);\nconst REFUSAL_NAMES = new Set(['ContentFilterError']);\n\nconst RATE_LIMIT_CODES = new Set(['RATE_LIMIT', 'rate_limit_exceeded']);\nconst RATE_LIMIT_NAMES = new Set(['RateLimitError']);\n\nconst TRANSIENT_CODES = new Set([\n 'AI_TIMEOUT',\n 'AI_INTERRUPTED',\n 'STREAM_INTERRUPTED',\n // SDK mapping of other HTTP failures; the status is dropped (see above).\n 'API_ERROR',\n 'UNKNOWN_ERROR',\n 'overloaded_error',\n 'ECONNRESET',\n 'ECONNREFUSED',\n 'ECONNABORTED',\n 'ETIMEDOUT',\n 'EPIPE',\n 'EAI_AGAIN',\n 'ENOTFOUND',\n 'ENETUNREACH',\n 'EHOSTUNREACH',\n 'UND_ERR_SOCKET',\n 'UND_ERR_CONNECT_TIMEOUT',\n 'UND_ERR_HEADERS_TIMEOUT',\n 'UND_ERR_BODY_TIMEOUT',\n]);\nconst TRANSIENT_NAMES = new Set([\n 'TimeoutError',\n 'APIConnectionError',\n 'APIConnectionTimeoutError',\n 'InternalServerError',\n]);\nconst TRANSIENT_STATUSES = new Set([408, 409, 425, 500, 502, 503, 504, 529]);\n\n/**\n * Client errors a provider answers the same way on every route (bad\n * parameters, oversized input): never a routing failure. Statuses the\n * taxonomy names are decided before this check.\n */\nconst REQUEST_ERROR_CODES = new Set([\n 'invalid_request_error',\n 'CONTEXT_LENGTH_EXCEEDED',\n 'context_length_exceeded',\n 'INVALID_INPUT',\n]);\n\nconst ABORT_CODES = new Set(['AI_ABORTED', 'ABORT_ERR']);\nconst ABORT_NAMES = new Set(['AbortError']);\n\nfunction asObject(value: unknown): Record<string, unknown> | undefined {\n return value !== null && typeof value === 'object'\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction collectFacts(error: unknown): ErrorFacts {\n const facts: ErrorFacts = {\n names: new Set(),\n codes: new Set(),\n statuses: new Set(),\n rateLimitNotSoon: false,\n retryable: false,\n };\n const seen = new Set<unknown>();\n const queue: Array<{ value: unknown; depth: number }> = [\n { value: error, depth: 0 },\n ];\n while (queue.length > 0) {\n const { value, depth } = queue.shift() as {\n value: unknown;\n depth: number;\n };\n const record = asObject(value);\n if (!record || seen.has(record) || depth > MAX_CAUSE_DEPTH) continue;\n seen.add(record);\n\n const name =\n typeof record.name === 'string'\n ? record.name\n : (value as object).constructor?.name;\n if (typeof name === 'string' && name !== 'Error' && name !== 'Object') {\n facts.names.add(name);\n }\n for (const key of ['code', 'type']) {\n const code = record[key];\n if (typeof code === 'string' && code !== '') facts.codes.add(code);\n }\n for (const key of ['status', 'statusCode']) {\n const status = record[key];\n if (typeof status === 'number' && Number.isInteger(status)) {\n facts.statuses.add(status);\n }\n }\n const response = asObject(record.response);\n if (typeof response?.status === 'number') {\n facts.statuses.add(response.status);\n }\n if (record.retryable === true) facts.retryable = true;\n if (\n (RATE_LIMIT_NAMES.has(String(name)) || record.code === 'RATE_LIMIT') &&\n record.retryable === false\n ) {\n facts.rateLimitNotSoon = true;\n }\n\n for (const next of [\n record.cause,\n record.error,\n asObject(record.context)?.originalError,\n ]) {\n if (next !== undefined) queue.push({ value: next, depth: depth + 1 });\n }\n }\n return facts;\n}\n\nfunction hasAny(set: Set<string>, members: Set<string>): boolean {\n for (const value of set) if (members.has(value)) return true;\n return false;\n}\n\n/**\n * True for a caller abort (`AI_ABORTED`, `AbortError`): never a routing\n * failure, so the walk stops and rethrows.\n */\nexport function isInferenceAbort(error: unknown): boolean {\n const facts = collectFacts(error);\n return hasAny(facts.codes, ABORT_CODES) || hasAny(facts.names, ABORT_NAMES);\n}\n\n/**\n * Classify a provider failure, or `undefined` when it is not a routing\n * failure (a caller abort, a programming error, invalid input the SDK did\n * not map). Unclassified errors end the walk and are rethrown.\n */\nexport function classifyInferenceFailure(\n error: unknown,\n): InferenceFailureClass | undefined {\n // Core's typed capability refusal (#4758): the candidate cannot run the\n // request's shape (required tools, an oversized prompt). Advance.\n const unavailable = error as { code?: unknown; reason?: unknown } | null;\n if (\n unavailable &&\n typeof unavailable === 'object' &&\n unavailable.code === 'AI_UNAVAILABLE' &&\n unavailable.reason === 'capability'\n ) {\n return 'missing-capability';\n }\n const facts = collectFacts(error);\n const { names, codes, statuses } = facts;\n\n if (hasAny(codes, ABORT_CODES) || hasAny(names, ABORT_NAMES)) {\n return undefined;\n }\n if (\n hasAny(codes, QUOTA_CODES) ||\n hasAny(names, QUOTA_NAMES) ||\n statuses.has(402)\n ) {\n return 'quota';\n }\n if (\n hasAny(codes, CREDENTIAL_CODES) ||\n hasAny(names, CREDENTIAL_NAMES) ||\n statuses.has(401) ||\n statuses.has(403)\n ) {\n return 'credential';\n }\n if (\n hasAny(codes, MISSING_MODEL_CODES) ||\n hasAny(names, MISSING_MODEL_NAMES) ||\n statuses.has(404)\n ) {\n return 'missing-model';\n }\n if (hasAny(codes, REFUSAL_CODES) || hasAny(names, REFUSAL_NAMES)) {\n return 'refusal';\n }\n if (\n hasAny(codes, RATE_LIMIT_CODES) ||\n hasAny(names, RATE_LIMIT_NAMES) ||\n statuses.has(429)\n ) {\n return facts.rateLimitNotSoon ? 'quota' : 'transient';\n }\n for (const status of statuses) {\n if (TRANSIENT_STATUSES.has(status)) return 'transient';\n }\n // A definitive client error stops the walk: every candidate would refuse\n // the same request, so advancing only fans the prompt out (#4752 review).\n for (const status of statuses) {\n if (status >= 400 && status < 500) return undefined;\n }\n if (hasAny(codes, REQUEST_ERROR_CODES)) return undefined;\n if (\n hasAny(codes, TRANSIENT_CODES) ||\n hasAny(names, TRANSIENT_NAMES) ||\n facts.retryable\n ) {\n return 'transient';\n }\n return undefined;\n}\n","/**\n * The chain executor (#4752): runs `alias` and `candidates` tier targets.\n *\n * Per call it expands the resolved target into ordered candidates and tries\n * them in turn. A failure is classified (`classify.ts`); `transient` retries\n * the same candidate once after a jittered delay, every class then advances.\n * When a tier's chain is spent and `inference.degrade !== false`, the walk\n * moves down the ladder (never up), stopping at `minimumTier`. Each move is\n * a substitution `{ from, to, reason }` carried in the answering call's\n * `substitutions` usage tag with `tierResolved` set to the tier that\n * answered; a call that never answered records one zero-token row through\n * core's usage pipeline and throws {@link InferenceExhaustedError}.\n *\n * Text already streamed to the caller is never extended by another\n * candidate: a candidate that emitted text and then failed ends the walk\n * with a `partial` substitution (the caller gets the error unless\n * `allowPartial`).\n *\n * Before calling a candidate the walk checks its capabilities (#4758,\n * `context.capabilitiesFor()`) against the request: JSON mode for a\n * `responseFormat`, tool calling for `tools`. A mismatch the caller permits\n * a fallback for (`capabilityFallback`) runs the candidate without the\n * feature, tagged `capabilityFallback`; any other mismatch is a\n * `missing-capability` substitution and the walk advances without a call.\n *\n * The executor imports no SDK: it drives the clients core builds through\n * `context.clientFor()`, so tests run it with fake clients.\n */\nimport {\n compareInferenceTiers,\n INFERENCE_TIERS,\n type InferenceCallOptions,\n type InferenceCapabilityFallbackOption,\n type InferenceExecutionContext,\n type InferenceModelClient,\n type InferenceTarget,\n type InferenceTier,\n isInferenceUnavailableError,\n} from '@happyvertical/smrt-core';\nimport { classifyInferenceFailure, isInferenceAbort } from './classify.js';\nimport {\n type ChainStep,\n expandTarget,\n validateInferenceConfig,\n validateInferenceTarget,\n} from './config.js';\nimport { InferenceExhaustedError } from './errors.js';\nimport type {\n InferenceFailureClass,\n InferenceSubstitution,\n InferenceSubstitutionReason,\n} from './types.js';\n\n/** Test seams for the executor; production uses the defaults. */\nexport interface ChainExecutorOptions {\n /** Delay before the one transient retry. Default 200–500 ms, jittered. */\n retryDelayMs?: () => number;\n /** Sleep implementation. */\n sleep?: (ms: number) => Promise<void>;\n /** Clock for the failure row's duration. */\n now?: () => number;\n}\n\ntype Outcome<T> =\n | { ok: true; value: T }\n | {\n ok: false;\n cls: InferenceFailureClass | undefined;\n error: unknown;\n emitted: string;\n };\n\n/** A refusal that arrived as a finish reason, not an error. */\nclass RefusalSignal extends Error {\n readonly code = 'CONTENT_FILTERED';\n}\n\n/** A candidate skipped before its call for a missing capability (#4758). */\nclass MissingCapabilitySignal extends Error {\n readonly code = 'MISSING_CAPABILITY';\n constructor(\n label: string,\n readonly missing: string[],\n readonly source: string,\n ) {\n super(`${label} lacks ${missing.join(' and ')} (capabilities: ${source})`);\n this.name = 'MissingCapabilitySignal';\n }\n}\n\n/** How one candidate's call is reshaped for its capabilities. */\ninterface CapabilityAdjustment {\n dropJson?: boolean;\n dropTools?: boolean;\n /** `capabilityFallback` tag values. */\n fallbacks: string[];\n}\n\ntype CapabilityFit =\n | { ok: true; adjust?: CapabilityAdjustment }\n | { ok: false; error: MissingCapabilitySignal };\n\nfunction wantsJson(options: InferenceCallOptions): boolean {\n const type = (options.responseFormat as { type?: unknown } | undefined)?.type;\n return type === 'json_object' || type === 'json_schema';\n}\n\nfunction wantsTools(options: InferenceCallOptions): boolean {\n return Array.isArray(options.tools) && options.tools.length > 0;\n}\n\nconst REFUSAL_FINISH = new Set(['refusal', 'content_filter']);\n\nfunction lowerTier(tier: InferenceTier): InferenceTier | undefined {\n const index = INFERENCE_TIERS.indexOf(tier);\n return index > 0 ? INFERENCE_TIERS[index - 1] : undefined;\n}\n\nfunction defaultSleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\ntype Invoke<T> = (\n client: InferenceModelClient,\n options: InferenceCallOptions,\n emit: (chunk: string) => void,\n) => Promise<T>;\n\nfunction method(\n client: InferenceModelClient,\n name: string,\n): (...args: unknown[]) => unknown {\n const fn = client[name];\n if (typeof fn !== 'function') {\n throw new TypeError(`Inference client does not implement ${name}().`);\n }\n return (fn as (...args: unknown[]) => unknown).bind(client);\n}\n\nclass ChainCall {\n private readonly started: number;\n private readonly substitutions: InferenceSubstitution[] = [];\n private lastStep: ChainStep | undefined;\n\n constructor(\n private readonly context: InferenceExecutionContext,\n private readonly options: Required<ChainExecutorOptions>,\n private readonly operation: string,\n private readonly callerOptions: InferenceCallOptions,\n ) {\n this.started = options.now();\n }\n\n private get tierRequested(): string {\n return (\n this.callerOptions.usageTags?.tierRequested ?? this.context.request.tier\n );\n }\n\n /**\n * Check a candidate's capabilities against the request before calling it\n * (#4758). Without a detector (older core) or a requirement, it fits.\n */\n private async capabilityFit(step: ChainStep): Promise<CapabilityFit> {\n // The options the candidate would receive: its params under the caller's.\n const effective: InferenceCallOptions = {\n ...(step.params ?? {}),\n ...this.callerOptions,\n };\n const json = wantsJson(effective);\n const tools = wantsTools(effective);\n if ((!json && !tools) || !this.context.capabilitiesFor) return { ok: true };\n let capabilities: Awaited<\n ReturnType<NonNullable<InferenceExecutionContext['capabilitiesFor']>>\n >;\n try {\n capabilities = await this.context.capabilitiesFor(step.target);\n } catch {\n // Detection never decides a failure: the call itself will surface a\n // real problem (an unbound key, an unreachable endpoint), classified.\n return { ok: true };\n }\n const fallback: InferenceCapabilityFallbackOption =\n this.callerOptions.capabilityFallback ?? {};\n const adjust: CapabilityAdjustment = { fallbacks: [] };\n const missing: string[] = [];\n if (json && !capabilities.json) {\n if (fallback.json === 'text') {\n adjust.dropJson = true;\n adjust.fallbacks.push('json→text');\n } else missing.push('json');\n }\n if (tools && !capabilities.tools) {\n if (fallback.tools === 'drop') {\n adjust.dropTools = true;\n adjust.fallbacks.push('tools→none');\n } else missing.push('tools');\n }\n if (missing.length > 0) {\n return {\n ok: false,\n error: new MissingCapabilitySignal(\n step.label,\n missing,\n capabilities.source,\n ),\n };\n }\n return adjust.fallbacks.length > 0 ? { ok: true, adjust } : { ok: true };\n }\n\n private callOptions(\n step: ChainStep,\n emit: (chunk: string) => void,\n finish: { reason?: string; replay: Array<() => void> },\n adjust?: CapabilityAdjustment,\n ): InferenceCallOptions {\n const {\n usageTags: callerTags,\n onProgress,\n onFinishReason,\n onRefusal,\n // Executor-only: never reaches a provider.\n capabilityFallback: _capabilityFallback,\n ...rest\n } = this.callerOptions as InferenceCallOptions & {\n onProgress?: (chunk: string) => void;\n onFinishReason?: (reason: string) => void;\n onRefusal?: (refusal: unknown) => void;\n };\n const model =\n typeof step.target.model === 'string' ? step.target.model : undefined;\n const options: InferenceCallOptions = {\n ...(step.params ?? {}),\n ...rest,\n // A candidate names its own model; a caller model cannot follow the\n // call onto another provider.\n ...(model ? { model } : {}),\n usageTags: {\n ...(callerTags ?? {}),\n // The candidate's own binding origin wins over the chain's (#4760):\n // a hosted candidate's spend must meter as hosted.\n ...(typeof step.target.source === 'string' && step.target.source\n ? { source: step.target.source }\n : {}),\n tierRequested: this.tierRequested,\n tierResolved: step.tier,\n ...(this.substitutions.length > 0\n ? { substitutions: JSON.stringify(this.substitutions) }\n : {}),\n ...(adjust && adjust.fallbacks.length > 0\n ? { capabilityFallback: adjust.fallbacks.join(',') }\n : {}),\n },\n ...(onProgress\n ? {\n onProgress: (chunk: string) => {\n emit(chunk);\n onProgress(chunk);\n },\n }\n : {}),\n // Finish callbacks are held until this candidate's answer is kept, so\n // a refused candidate the walk skips never reaches the caller.\n onFinishReason: (reason: string) => {\n finish.reason = reason;\n if (onFinishReason) finish.replay.push(() => onFinishReason(reason));\n },\n ...(onRefusal\n ? {\n onRefusal: (refusal: unknown) => {\n finish.replay.push(() => onRefusal(refusal));\n },\n }\n : {}),\n };\n // After the merge, so a candidate's own params cannot bring back a\n // feature its fallback removed (#4758).\n if (adjust?.dropJson) delete options.responseFormat;\n if (adjust?.dropTools) delete options.tools;\n return options;\n }\n\n private async attemptOnce<T>(\n step: ChainStep,\n invoke: Invoke<T>,\n isRefusal: ((value: T) => boolean) | undefined,\n adjust?: CapabilityAdjustment,\n ): Promise<Outcome<T>> {\n let emitted = '';\n const emit = (chunk: string) => {\n emitted += chunk;\n };\n const finish: { reason?: string; replay: Array<() => void> } = {\n replay: [],\n };\n try {\n const client = await this.context.clientFor(step.target);\n const value = await invoke(\n client,\n this.callOptions(step, emit, finish, adjust),\n emit,\n );\n const refused =\n (finish.reason !== undefined && REFUSAL_FINISH.has(finish.reason)) ||\n (isRefusal?.(value) ?? false);\n if (refused && emitted === '') {\n return {\n ok: false,\n cls: 'refusal',\n error: new RefusalSignal(`${step.label} declined the request`),\n emitted,\n };\n }\n for (const replay of finish.replay) replay();\n return { ok: true, value };\n } catch (error) {\n return {\n ok: false,\n cls: classifyInferenceFailure(error),\n error,\n emitted,\n };\n }\n }\n\n private async attempt<T>(\n step: ChainStep,\n invoke: Invoke<T>,\n isRefusal: ((value: T) => boolean) | undefined,\n adjust?: CapabilityAdjustment,\n ): Promise<Outcome<T>> {\n const first = await this.attemptOnce(step, invoke, isRefusal, adjust);\n if (first.ok || first.cls !== 'transient' || first.emitted !== '') {\n return first;\n }\n await this.options.sleep(this.options.retryDelayMs());\n return this.attemptOnce(step, invoke, isRefusal, adjust);\n }\n\n private async recordFailure(\n outcome: 'failed' | 'partial',\n reason: InferenceSubstitutionReason | 'unclassified',\n ): Promise<void> {\n const step = this.lastStep;\n // Nothing answered, so no tier resolved: drop the tag core added up\n // front, or #4751 would lift a failed tier into tier_resolved.\n const { tierResolved: _unanswered, ...callerTags } =\n this.callerOptions.usageTags ?? {};\n try {\n await this.context.recordUsage({\n ...(typeof step?.target.provider === 'string'\n ? { provider: step.target.provider }\n : {}),\n ...(typeof step?.target.model === 'string'\n ? { model: step.target.model }\n : {}),\n operation: this.operation,\n duration: Math.max(0, this.options.now() - this.started),\n tags: {\n ...callerTags,\n tierRequested: this.tierRequested,\n outcome,\n reason,\n substitutions: JSON.stringify(this.substitutions),\n },\n });\n } catch {\n // Recording must never mask the call's own failure.\n }\n }\n\n async run<T>(\n invoke: Invoke<T>,\n isRefusal?: (value: T) => boolean,\n partialValue?: (text: string) => T,\n ): Promise<T> {\n const { context } = this;\n const attempted = new Set<string>();\n let pending:\n | { label: string; reason: InferenceFailureClass; error?: unknown }\n | undefined;\n let tier = context.resolution.tierResolved;\n let steps = expandResolved(context.resolution.target, tier, context.config);\n\n for (;;) {\n for (const step of steps) {\n if (attempted.has(step.identity)) continue;\n attempted.add(step.identity);\n if (pending) {\n this.substitutions.push({\n from: pending.label,\n to: step.label,\n reason: pending.reason,\n });\n }\n pending = undefined;\n this.lastStep = step;\n if (step.unavailable) {\n pending = { label: step.label, reason: step.unavailable };\n continue;\n }\n const fit = await this.capabilityFit(step);\n if (!fit.ok) {\n // Skipped before the call: no model ran for this candidate.\n pending = {\n label: step.label,\n reason: 'missing-capability',\n error: fit.error,\n };\n continue;\n }\n\n const outcome = await this.attempt(step, invoke, isRefusal, fit.adjust);\n if (outcome.ok) return outcome.value;\n\n if (outcome.emitted !== '') {\n this.substitutions.push({\n from: step.label,\n to: null,\n reason: 'partial',\n });\n await this.recordFailure('partial', outcome.cls ?? 'unclassified');\n if (context.allowPartial && partialValue) {\n return partialValue(outcome.emitted);\n }\n throw new InferenceExhaustedError({\n reason: 'partial',\n substitutions: [...this.substitutions],\n tierRequested: this.tierRequested,\n partialText: outcome.emitted,\n cause: outcome.error,\n });\n }\n if (outcome.cls === undefined) {\n // Not a routing failure: a caller abort records nothing (nothing\n // ran to completion by choice), nor does a hosted-gate block\n // (`AI_UNAVAILABLE`, #4760: core already wrote its `blocked`\n // row); anything else is recorded and rethrown as the caller's\n // own error.\n if (\n !isInferenceAbort(outcome.error) &&\n !isInferenceUnavailableError(outcome.error)\n ) {\n // The trail always ends with `to: null` on a failure row.\n this.substitutions.push({\n from: step.label,\n to: null,\n reason: 'unclassified',\n });\n await this.recordFailure('failed', 'unclassified');\n }\n throw outcome.error;\n }\n pending = {\n label: step.label,\n reason: outcome.cls,\n error: outcome.error,\n };\n }\n\n if (context.config?.degrade === false) break;\n const next = lowerTier(tier);\n if (!next) break;\n if (\n context.minimumTier &&\n compareInferenceTiers(next, context.minimumTier) < 0\n ) {\n break;\n }\n const resolution = await context.resolveTier(next);\n // A lower tier that may not run (#4757: explicit mode with no binding\n // of its kind, or `off`) ends the ladder. Its empty target would\n // otherwise expand to the configured client and send the call to a\n // provider the principal's mode excludes.\n if (resolution.unavailable) break;\n tier = resolution.tierResolved;\n steps = expandResolved(resolution.target, tier, context.config);\n }\n\n if (pending) {\n this.substitutions.push({\n from: pending.label,\n to: null,\n reason: pending.reason,\n });\n }\n const reason = pending?.reason ?? 'unclassified';\n await this.recordFailure('failed', reason);\n throw new InferenceExhaustedError({\n reason,\n substitutions: [...this.substitutions],\n tierRequested: this.tierRequested,\n cause: pending?.error,\n });\n }\n}\n\n/** Validate a resolved target (config or resolver-sourced), then expand it. */\nfunction expandResolved(\n target: InferenceTarget,\n tier: InferenceTier,\n config: InferenceExecutionContext['config'],\n): ChainStep[] {\n validateInferenceTarget(target, `resolution.${tier}`, config);\n return expandTarget(target, tier, config);\n}\n\n/** Async queue backing `stream()`; closing it stops the producer. */\nfunction createChunkQueue(onClose: () => void) {\n const chunks: string[] = [];\n let wake: (() => void) | undefined;\n let done = false;\n let closed = false;\n let failure: { error: unknown } | undefined;\n return {\n /** True once the consumer stopped reading. */\n get closed() {\n return closed;\n },\n push(chunk: string) {\n if (closed) return;\n chunks.push(chunk);\n wake?.();\n },\n end(error?: { error: unknown }) {\n done = true;\n failure = error;\n wake?.();\n },\n async *drain(): AsyncGenerator<string> {\n try {\n for (;;) {\n if (chunks.length > 0) {\n yield chunks.shift() as string;\n continue;\n }\n if (done) {\n if (failure) throw failure.error;\n return;\n }\n await new Promise<void>((resolve) => {\n wake = resolve;\n });\n wake = undefined;\n }\n } finally {\n // The consumer finished, threw, or broke out early: stop the\n // provider stream instead of reading (and paying for) the rest.\n if (!done) {\n closed = true;\n chunks.length = 0;\n onClose();\n }\n }\n },\n };\n}\n\nfunction isRefusalResponse(value: unknown): boolean {\n const reason = (value as { finishReason?: unknown } | null)?.finishReason;\n return typeof reason === 'string' && REFUSAL_FINISH.has(reason);\n}\n\nlet lastValidated: string | undefined;\n\nfunction validateChainConfig(config: InferenceExecutionContext['config']) {\n const key = JSON.stringify(config ?? null);\n if (key === lastValidated) return;\n validateInferenceConfig(config);\n lastValidated = key;\n}\n\n/**\n * A client whose calls walk the chain in `context.resolution`. `message`,\n * `chat`, `complete` and `stream` walk; `embed` uses the first candidate\n * that can run.\n */\nexport function createChainClient(\n context: InferenceExecutionContext,\n options: ChainExecutorOptions = {},\n): InferenceModelClient {\n // Validate here too, not only in the resolver: a resolver registered after\n // this package replaces ours, and a chain must never run half-configured.\n validateChainConfig(context.config);\n const resolved: Required<ChainExecutorOptions> = {\n retryDelayMs: options.retryDelayMs ?? (() => 200 + Math.random() * 300),\n sleep: options.sleep ?? defaultSleep,\n now: options.now ?? (() => Date.now()),\n };\n const call = (operation: string, callerOptions?: InferenceCallOptions) =>\n new ChainCall(context, resolved, operation, callerOptions ?? {});\n\n return {\n message(text: string, callerOptions?: InferenceCallOptions) {\n return call('message', callerOptions).run<string>(\n (client, opts) => client.message(text, opts),\n undefined,\n (partial) => partial,\n );\n },\n chat(messages: unknown, callerOptions?: InferenceCallOptions) {\n return call('chat', callerOptions).run<unknown>(\n (client, opts) =>\n Promise.resolve(method(client, 'chat')(messages, opts)),\n isRefusalResponse,\n );\n },\n complete(prompt: string, callerOptions?: InferenceCallOptions) {\n return call('complete', callerOptions).run<unknown>(\n (client, opts) =>\n Promise.resolve(method(client, 'complete')(prompt, opts)),\n isRefusalResponse,\n );\n },\n stream(messages: unknown, callerOptions?: InferenceCallOptions) {\n const controller = new AbortController();\n const queue = createChunkQueue(() => controller.abort());\n const callerSignal = (callerOptions as { signal?: AbortSignal })?.signal;\n const signal = callerSignal\n ? AbortSignal.any([callerSignal, controller.signal])\n : controller.signal;\n call('stream', { ...(callerOptions ?? {}), signal })\n .run<void>(\n async (client, opts, emit) => {\n const iterable = method(client, 'stream')(\n messages,\n opts,\n ) as AsyncIterable<string>;\n // Breaking out of for-await calls the provider iterator's\n // return(), which ends its request.\n for await (const chunk of iterable) {\n if (queue.closed) break;\n emit(chunk);\n queue.push(chunk);\n }\n },\n undefined,\n () => undefined,\n )\n .then(\n () => queue.end(),\n (error: unknown) => queue.end({ error }),\n );\n return queue.drain();\n },\n async embed(...args: unknown[]) {\n const steps = expandTarget(\n context.resolution.target,\n context.resolution.tierResolved,\n context.config,\n );\n const step = steps.find((candidate) => !candidate.unavailable);\n if (!step) {\n throw new InferenceExhaustedError({\n reason: steps[0]?.unavailable ?? 'unclassified',\n substitutions: [],\n tierRequested: context.request.tier,\n });\n }\n const client = await context.clientFor(step.target);\n return method(client, 'embed')(...args);\n },\n };\n}\n","/**\n * Consumer-defined fusions (#4753): the interpreter for `{ fusion: '<key>' }`\n * tier targets. SMRT ships the interpreter and the vocabulary, never a\n * fusion: modes are code, fusions are config.\n *\n * Each seat is a registered prompt key (its resolved template is the seat's\n * instructions) run on a target through the chain executor\n * ({@link createChainClient}), so alias chains, classified fallback and the\n * ladder apply per seat, and every seat's usage row comes from core's usage\n * pipeline tagged `runId`, `fusionKey` and `seat`. The run itself is one\n * `_smrt_ai_runs` row through `context.recordRun()`.\n *\n * Model calls per mode are fixed: `single` 1, `pair` 3, `handoff` 2. A gate\n * adds one typed-decision call and can only remove the remaining stage\n * (recorded `skipped`); a seat's fallback candidates are substitutions of\n * that seat, recorded in its tags, not extra seats.\n *\n * Like the executor, this module imports no SDK: tests drive it with fake\n * clients through `context.clientFor()`.\n */\nimport {\n type InferenceCallOptions,\n type InferenceCapabilityFallbackOption,\n type InferenceExecutionContext,\n type InferenceExecutor,\n type InferenceFusionDefinition,\n type InferenceFusionGate,\n type InferenceFusionSeat,\n type InferenceModelClient,\n type InferenceResolution,\n type InferenceRunStatus,\n type InferenceTarget,\n type InferenceTier,\n InferenceUnavailableError,\n importOptionalDependency,\n inferenceTargetKind,\n resolveAutoTier,\n} from '@happyvertical/smrt-core';\nimport { classifyInferenceFailure, isInferenceAbort } from './classify.js';\nimport {\n candidateLabel,\n EXECUTOR_KINDS,\n FUSION_GATE_CONTINUE,\n FUSION_GATE_SEAT,\n findFusionDefinitionIssues,\n findFusionDefinitionPromptIssues,\n} from './config.js';\nimport {\n InferenceConfigError,\n InferenceExhaustedError,\n InferenceFusionError,\n} from './errors.js';\nimport { type ChainExecutorOptions, createChainClient } from './executor.js';\nimport { fusionStore, lookupFusion } from './fusion-store.js';\nimport type { InferenceSubstitution } from './types.js';\n\n// ---------------------------------------------------------------------------\n// Definition\n// ---------------------------------------------------------------------------\n\n/** Input to {@link defineFusion}: a definition plus its key. */\nexport interface DefineFusionInput extends InferenceFusionDefinition {\n key: string;\n}\n\n/**\n * Register a fusion in the process registry. Throws\n * {@link InferenceConfigError} naming every offender by path\n * (`fusions.<key>...`), including a seat whose prompt key no\n * `definePrompt()` registered (define prompts first). Alias references are\n * checked when the fusion runs, against the config of that call. Same\n * definition again is a no-op; a different one under the same key throws.\n * `inference.fusions.<key>` in app config wins over a registered fusion.\n */\nexport function defineFusion(\n input: DefineFusionInput,\n): InferenceFusionDefinition {\n const key = typeof input?.key === 'string' ? input.key.trim() : '';\n if (!key) {\n throw new InferenceConfigError([\n {\n path: 'fusions',\n code: 'fusion-invalid',\n message: 'defineFusion() needs a non-empty key',\n },\n ]);\n }\n const { key: _key, ...definition } = input;\n const path = `fusions.${key}`;\n // Aliases are app config, unknown here: they are checked at run time.\n const issues = findFusionDefinitionIssues(definition, path, undefined).filter(\n (issue) => issue.code !== 'alias-unknown',\n );\n issues.push(...findFusionDefinitionPromptIssues(definition, path));\n if (issues.length > 0) throw new InferenceConfigError(issues);\n\n const store = fusionStore();\n const existing = store.get(key);\n if (existing) {\n if (JSON.stringify(existing) !== JSON.stringify(definition)) {\n throw new InferenceConfigError([\n {\n path,\n code: 'fusion-invalid',\n message: `fusion \"${key}\" is already defined with a different definition`,\n },\n ]);\n }\n return existing;\n }\n const frozen = structuredClone(definition) as InferenceFusionDefinition;\n store.set(key, frozen);\n return frozen;\n}\n\n/** The registered (code-defined) fusion for `key`, if any. */\nexport function getFusion(key: string): InferenceFusionDefinition | undefined {\n return fusionStore().get(key);\n}\n\n/** Registered fusion keys. */\nexport function listFusions(): string[] {\n return [...fusionStore().keys()];\n}\n\n/** Remove every registered fusion (tests). */\nexport function clearFusions(): void {\n fusionStore().clear();\n}\n\n// ---------------------------------------------------------------------------\n// Seat prompts\n// ---------------------------------------------------------------------------\n\n/** A seat's resolved instructions. */\nexport interface FusionSeatPrompt {\n /** The rendered template, sent as the seat's system message. */\n instructions: string;\n /** `promptKey`, `promptLayer`, `templateHash` (#4751). */\n usageTags?: Record<string, string>;\n /** Prompt-level defaults (`temperature`, `maxTokens`); the seat wins. */\n params?: Record<string, unknown>;\n}\n\n/** Resolves a seat's prompt key; the default uses smrt-prompts. */\nexport type FusionPromptResolver = (\n key: string,\n options: { tenantId?: string | null; db?: unknown },\n) => Promise<FusionSeatPrompt>;\n\nconst RESOLVER_KEY = Symbol.for('smrt.inference.fusionPromptResolver');\n\ntype ResolverHolder = { [RESOLVER_KEY]?: FusionPromptResolver };\n\n/**\n * Replace the seat prompt resolver (tests, or hosts that bundle without\n * `@happyvertical/smrt-prompts` resolvable at runtime). `undefined` restores\n * the default.\n */\nexport function setFusionPromptResolver(\n resolver: FusionPromptResolver | undefined,\n): void {\n const holder = globalThis as ResolverHolder;\n if (resolver) holder[RESOLVER_KEY] = resolver;\n else delete holder[RESOLVER_KEY];\n}\n\ninterface PromptsModule {\n resolvePrompt(\n key: string,\n options: { tenantId?: string | null; db?: unknown },\n ): Promise<{\n text: string;\n ai: {\n usageTags?: Record<string, string>;\n temperature?: number;\n maxTokens?: number;\n };\n }>;\n}\n\n/**\n * Default resolver: smrt-prompts' `resolvePrompt()` (code default, config,\n * app and tenant overrides), loaded without a static edge so this entry\n * stays browser-safe (smrt-prompts pulls in smrt-config and the SDKs).\n */\nconst PROMPTS_SPECIFIER = '@happyvertical/smrt-prompts';\n\nasync function loadPrompts(): Promise<PromptsModule> {\n try {\n // Resolved from this package (a dependency), so strict layouts\n // (no hoisting, PnP) find it. A variable specifier keeps\n // bundlers from following it into the browser-safe graph.\n const specifier = PROMPTS_SPECIFIER;\n return (await import(/* @vite-ignore */ specifier)) as PromptsModule;\n } catch {\n // Bundled builds: a module registered with core's\n // registerOptionalDependency(), else core's actionable error.\n return (await importOptionalDependency(\n PROMPTS_SPECIFIER,\n 'Fusion seats resolve prompts through @happyvertical/smrt-prompts; install it, register it with registerOptionalDependency(), or call setFusionPromptResolver().',\n )) as PromptsModule;\n }\n}\n\nconst defaultPromptResolver: FusionPromptResolver = async (key, options) => {\n const prompts = await loadPrompts();\n const resolved = await prompts.resolvePrompt(key, {\n ...(options.tenantId !== undefined ? { tenantId: options.tenantId } : {}),\n ...(options.db ? { db: options.db } : {}),\n });\n const params: Record<string, unknown> = {};\n if (typeof resolved.ai.temperature === 'number') {\n params.temperature = resolved.ai.temperature;\n }\n if (typeof resolved.ai.maxTokens === 'number') {\n params.maxTokens = resolved.ai.maxTokens;\n }\n return {\n instructions: resolved.text,\n ...(resolved.ai.usageTags ? { usageTags: resolved.ai.usageTags } : {}),\n params,\n };\n};\n\nfunction promptResolver(): FusionPromptResolver {\n return (globalThis as ResolverHolder)[RESOLVER_KEY] ?? defaultPromptResolver;\n}\n\n// ---------------------------------------------------------------------------\n// Results\n// ---------------------------------------------------------------------------\n\n/** Token totals observed for one seat. */\nexport interface FusionSeatUsage {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n /** Sum of recorded estimates; absent when no event carried one. */\n estimatedCost?: number;\n}\n\n/** How one seat went. */\nexport type FusionSeatStatus = 'ok' | 'failed' | 'skipped' | 'not-run';\n\n/** One seat of a {@link FusionRunResult}. */\nexport interface FusionSeatResult {\n /** Persona: the seat name (default the prompt key). */\n name: string;\n prompt: string;\n status: FusionSeatStatus;\n /** Target label: `tier:<tier>`, `alias:<name>`, `candidates`, `provider/model`. */\n target: string;\n /** The candidate that answered (`provider/model`, `default`, ...). */\n model?: string;\n /** The seat's text (text seats, and JSON seats that parsed). */\n text?: string;\n /** A JSON seat's parsed value. */\n json?: unknown;\n /**\n * A JSON seat whose text did not parse keeps the text here (never\n * dropped), with the parse error in `parseError`.\n */\n raw?: string;\n parseError?: string;\n /** Why a seat died: failure class (or `unclassified`) and message. */\n failure?: { reason: string; message: string; code?: string };\n substitutions?: InferenceSubstitution[];\n usage?: FusionSeatUsage;\n durationMs?: number;\n}\n\n/** The decision gate's verdict. */\nexport interface FusionGateResult {\n /**\n * `sufficient` skipped the remaining stage; `insufficient` ran it;\n * `unavailable` (no decision client) and `error` ran it too; `not-run`\n * when no output existed to judge.\n */\n status: 'sufficient' | 'insufficient' | 'unavailable' | 'error' | 'not-run';\n choice?: string;\n confidence?: number;\n /** Decision provider and model. */\n model?: string;\n message?: string;\n}\n\n/** A finished (or failed) fusion run. */\nexport interface FusionRunResult {\n runId: string;\n fusionKey: string;\n mode: InferenceFusionDefinition['mode'];\n status: InferenceRunStatus;\n /** The answer: the final seat's text (see the mode rules). */\n text: string;\n seats: FusionSeatResult[];\n gate?: FusionGateResult;\n durationMs: number;\n}\n\n/**\n * Per-call options a fusion client reads (and strips) besides the usual\n * `ai.message()` options, which reach the final seat.\n */\nexport interface FusionCallOptions {\n /** Receives the structured result (per-seat outputs, `raw` JSON text). */\n onFusionResult?: (result: FusionRunResult) => void;\n}\n\n// ---------------------------------------------------------------------------\n// Interpreter\n// ---------------------------------------------------------------------------\n\n/** Caller tags that describe the entry call, not a seat's own call. */\nconst ENTRY_TAGS = new Set([\n 'promptKey',\n 'promptLayer',\n 'templateHash',\n 'tierRequested',\n 'tierResolved',\n 'substitutions',\n 'runId',\n 'fusionKey',\n 'seat',\n]);\n\n/** Caller options that apply to every seat (transport, not generation). */\nconst TRANSPORT_OPTIONS = ['signal', 'timeout'] as const;\n\nconst MAX_MESSAGE = 300;\n\nfunction seatName(seat: InferenceFusionSeat): string {\n return (seat.name ?? seat.prompt).trim();\n}\n\nfunction targetLabel(target: InferenceFusionSeat['target']): string {\n if (typeof target === 'string') return `tier:${target}`;\n const kind = inferenceTargetKind(target);\n if (kind === 'alias') return `alias:${String(target.alias)}`;\n if (kind === 'candidates') return 'candidates';\n return candidateLabel({\n ...(typeof target.provider === 'string'\n ? { provider: target.provider }\n : {}),\n ...(typeof target.model === 'string' ? { model: target.model } : {}),\n });\n}\n\nfunction shortMessage(error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n return message.length > MAX_MESSAGE\n ? `${message.slice(0, MAX_MESSAGE)}…`\n : message;\n}\n\nfunction errorCode(error: unknown): string | undefined {\n const code = (error as { code?: unknown } | null)?.code;\n return typeof code === 'string' ? code : undefined;\n}\n\nfunction parseSubstitutions(\n value: unknown,\n): InferenceSubstitution[] | undefined {\n if (typeof value !== 'string' || value === '') return undefined;\n try {\n const parsed = JSON.parse(value);\n return Array.isArray(parsed) && parsed.length > 0 ? parsed : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction newRunId(): string {\n const crypto = (globalThis as { crypto?: { randomUUID?: () => string } })\n .crypto;\n if (crypto?.randomUUID) return crypto.randomUUID();\n return `run-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/** What a seat hands the next stage: its text, or its raw text. */\nfunction seatOutputText(seat: FusionSeatResult): string {\n if (seat.raw !== undefined) return seat.raw;\n return seat.text ?? '';\n}\n\nfunction seatHeading(seat: FusionSeatResult): string {\n return `seat \"${seat.name}\" (${seat.model ?? seat.target})`;\n}\n\n/** One labelled block of a prior seat for a merge or answer seat. */\nfunction describeSeat(seat: FusionSeatResult, role: string): string {\n if (seat.status === 'failed') {\n const failure = seat.failure;\n return `--- ${role} ${seatHeading(seat)} FAILED (${failure?.reason ?? 'unclassified'}): ${failure?.message ?? 'no answer'} ---\\nThis seat produced no output; answer from the other material.`;\n }\n const note =\n seat.raw !== undefined\n ? ' (asked for JSON; the reply did not parse, raw text follows)'\n : '';\n return `--- ${role} ${seatHeading(seat)}${note} ---\\n${seatOutputText(seat)}\\n--- end of ${seat.name} ---`;\n}\n\nclass FusionRun {\n private readonly runId = newRunId();\n private readonly seats: FusionSeatResult[];\n private readonly usage = new Map<string, FusionSeatUsage>();\n private gate: FusionGateResult | undefined;\n private readonly started: number;\n private readonly callerTags: Record<string, string>;\n private readonly finalOptions: Record<string, unknown>;\n private readonly transport: Record<string, unknown>;\n private readonly signal: AbortSignal | undefined;\n private readonly entryPromptKey: string | undefined;\n\n constructor(\n private readonly context: InferenceExecutionContext,\n private readonly key: string,\n private readonly definition: InferenceFusionDefinition,\n callerOptions: InferenceCallOptions,\n private readonly options: Required<ChainExecutorOptions>,\n ) {\n this.started = options.now();\n const { usageTags, model: _model, ...rest } = callerOptions;\n this.callerTags = Object.fromEntries(\n Object.entries(usageTags ?? {}).filter(([tag]) => !ENTRY_TAGS.has(tag)),\n );\n this.finalOptions = rest;\n this.transport = {};\n for (const name of TRANSPORT_OPTIONS) {\n if (rest[name] !== undefined) this.transport[name] = rest[name];\n }\n this.signal = rest.signal as AbortSignal | undefined;\n // The entry call's prompt: the resolver request's, else its usage tag.\n this.entryPromptKey =\n context.request.promptKey ??\n (typeof usageTags?.promptKey === 'string' && usageTags.promptKey !== ''\n ? usageTags.promptKey\n : undefined);\n this.seats = definition.seats.map((seat) => ({\n name: seatName(seat),\n prompt: seat.prompt,\n status: 'not-run',\n target: targetLabel(seat.target),\n }));\n }\n\n /** Resolve a seat's target into the context its chain runs in. */\n private async seatContext(\n seat: InferenceFusionSeat,\n index: number,\n track: (target: InferenceTarget, options: InferenceCallOptions) => void,\n ): Promise<InferenceExecutionContext> {\n const { context } = this;\n let resolution: InferenceResolution;\n let config = context.config;\n let tier: InferenceTier = context.resolution.tierResolved;\n const resolveTier = (next: InferenceTier) =>\n context.resolveTier(next, { promptKey: seat.prompt });\n if (typeof seat.target === 'string') {\n tier =\n seat.target === 'auto' ? resolveAutoTier(context.config) : seat.target;\n resolution = await resolveTier(tier);\n if (resolution.unavailable) {\n // #4757: this seat's tier may not run for the principal; the seat\n // dies (never falls back to the configured client).\n throw new InferenceUnavailableError({\n reason: resolution.unavailable,\n ...(resolution.mode ? { mode: resolution.mode } : {}),\n tier: resolution.tierResolved,\n owner: `fusion \"${this.key}\" seat \"${seatName(seat)}\"`,\n });\n }\n } else {\n // An alias, candidates or inline model: no ladder (the seat named\n // what it runs), recorded under the fusion's tier.\n resolution = {\n tierResolved: tier,\n target: { ...seat.target },\n via: 'config',\n };\n config = { ...(context.config ?? {}), degrade: false };\n }\n if (inferenceTargetKind(resolution.target) === 'fusion') {\n throw new InferenceConfigError([\n {\n path: `fusions.${this.key}.seats[${index}].target`,\n code: 'fusion-nested',\n message: `fusion \"${this.key}\" seat \"${seatName(seat)}\" resolved tier \"${resolution.tierResolved}\" to another fusion; a seat never runs a fusion`,\n },\n ]);\n }\n return {\n ...context,\n request: { ...context.request, tier, promptKey: seat.prompt },\n resolution,\n config,\n resolveTier,\n // Fusion seats never stream partial answers into each other.\n allowPartial: false,\n clientFor: async (target) => {\n const client = await context.clientFor(target);\n return {\n ...client,\n message: async (text: string, callOptions?: InferenceCallOptions) => {\n const answer = await client.message(text, callOptions);\n track(target, callOptions ?? {});\n return answer;\n },\n } as InferenceModelClient;\n },\n };\n }\n\n /**\n * Run one seat. A model failure kills the seat (recorded, never thrown);\n * a config error, a caller abort, or a final seat that already streamed\n * text rethrows.\n */\n private async runSeat(\n index: number,\n input: string,\n final: boolean,\n ): Promise<FusionSeatResult> {\n const seat = this.definition.seats[index] as InferenceFusionSeat;\n const result = this.seats[index] as FusionSeatResult;\n const started = this.options.now();\n let answered: { target: InferenceTarget; tags: Record<string, string> } = {\n target: {},\n tags: {},\n };\n let options: InferenceCallOptions = {};\n result.status = 'ok';\n try {\n // Setup failures (a prompt override read, a seat tier's resolver) kill\n // this seat like a model failure; only config errors and aborts end\n // the run.\n const prompt = await promptResolver()(seat.prompt, {\n ...(this.context.request.tenantId !== undefined\n ? { tenantId: this.context.request.tenantId }\n : {}),\n ...(this.context.db ? { db: this.context.db } : {}),\n });\n const seatContext = await this.seatContext(\n seat,\n index,\n (target, opts) => {\n answered = { target, tags: opts.usageTags ?? {} };\n },\n );\n const chain = createChainClient(seatContext, this.options);\n const passed = final ? this.finalOptions : this.transport;\n options = {\n ...(prompt.params ?? {}),\n ...passed,\n ...(seat.temperature !== undefined\n ? { temperature: seat.temperature }\n : {}),\n // A JSON seat on a candidate without JSON mode runs in text and\n // takes the raw recovery path below (#4758), instead of skipping\n // the candidate.\n ...(seat.output === 'json'\n ? {\n responseFormat: { type: 'json_object' },\n capabilityFallback: {\n ...((passed.capabilityFallback as\n | InferenceCapabilityFallbackOption\n | undefined) ?? {}),\n json: 'text',\n },\n }\n : {}),\n history: [{ role: 'system', content: prompt.instructions }],\n usageTags: {\n ...this.callerTags,\n ...(prompt.usageTags ?? {}),\n promptKey: seat.prompt,\n runId: this.runId,\n fusionKey: this.key,\n seat: result.name,\n },\n };\n const text = await chain.message(input, options);\n const target = answered.target;\n result.model = candidateLabel({\n ...(typeof target.provider === 'string'\n ? { provider: target.provider }\n : {}),\n ...(typeof target.model === 'string'\n ? { model: target.model }\n : typeof options.model === 'string'\n ? { model: options.model }\n : {}),\n });\n const substitutions = parseSubstitutions(answered.tags.substitutions);\n if (substitutions) result.substitutions = substitutions;\n if (seat.output === 'json') {\n try {\n result.json = JSON.parse(text);\n result.text = text;\n } catch (error) {\n result.raw = text;\n result.parseError = shortMessage(error);\n }\n } else {\n result.text = text;\n }\n } catch (error) {\n if (\n error instanceof InferenceConfigError ||\n isInferenceAbort(error) ||\n (final &&\n error instanceof InferenceExhaustedError &&\n error.reason === 'partial')\n ) {\n result.status = 'failed';\n result.failure = {\n reason:\n error instanceof InferenceExhaustedError\n ? error.reason\n : error instanceof InferenceConfigError\n ? 'config'\n : 'aborted',\n message: shortMessage(error),\n };\n throw error;\n }\n result.status = 'failed';\n const code = errorCode(error);\n result.failure = {\n reason:\n error instanceof InferenceExhaustedError\n ? error.reason\n : (classifyInferenceFailure(error) ?? 'unclassified'),\n message: shortMessage(error),\n ...(code ? { code } : {}),\n };\n if (error instanceof InferenceExhaustedError) {\n result.substitutions = error.substitutions;\n }\n } finally {\n result.durationMs = Math.max(0, this.options.now() - started);\n }\n return result;\n }\n\n /** The gate: one typed-decision call over the outputs so far. */\n private async runGate(\n gate: InferenceFusionGate,\n input: string,\n outputs: FusionSeatResult[],\n ): Promise<FusionGateResult> {\n const live = outputs.filter((seat) => seat.status === 'ok');\n if (live.length === 0) return { status: 'not-run' };\n if (!this.context.decide) return { status: 'unavailable' };\n const choice = gate.sufficientWhen.choice;\n try {\n const result = await this.context.decide(\n {\n state: {\n input,\n outputs: live.map((seat) => ({\n seat: seat.name,\n model: seat.model ?? seat.target,\n text: seatOutputText(seat),\n })),\n },\n questions: {\n gate: {\n type: 'choice',\n instructions: gate.criteria,\n criteria: {\n [choice]:\n 'The outputs so far already satisfy the instructions; the remaining stage is not needed.',\n [FUSION_GATE_CONTINUE]: 'The remaining stage is still needed.',\n },\n },\n },\n },\n {\n usageTags: {\n ...this.callerTags,\n runId: this.runId,\n fusionKey: this.key,\n seat: FUSION_GATE_SEAT,\n },\n ...(this.signal ? { signal: this.signal } : {}),\n },\n );\n if (!result) return { status: 'unavailable' };\n const answer = result.answers.gate;\n if (!answer || answer.type !== 'choice') {\n return {\n status: 'error',\n message: 'decision provider returned no choice for the gate',\n };\n }\n const sufficient =\n answer.choice === choice &&\n answer.confidence >= gate.sufficientWhen.minConfidence;\n return {\n status: sufficient ? 'sufficient' : 'insufficient',\n choice: answer.choice,\n confidence: answer.confidence,\n model: `${result.provenance.provider}/${result.provenance.model}`,\n };\n } catch (error) {\n if (isInferenceAbort(error)) throw error;\n return { status: 'error', message: shortMessage(error) };\n }\n }\n\n private skip(index: number): void {\n const seat = this.seats[index] as FusionSeatResult;\n seat.status = 'skipped';\n }\n\n private firstLive(...indices: number[]): FusionSeatResult | undefined {\n return indices\n .map((index) => this.seats[index] as FusionSeatResult)\n .find((seat) => seat.status === 'ok');\n }\n\n private async interpret(input: string): Promise<string | undefined> {\n const { definition } = this;\n if (definition.mode === 'single') {\n const seat = await this.runSeat(0, input, true);\n return seat.status === 'ok' ? seatOutputText(seat) : undefined;\n }\n if (definition.mode === 'pair') {\n // Settle both before rethrowing a config error or abort, so the run\n // record never misses a seat that was still spending.\n const settled = await Promise.allSettled([\n this.runSeat(0, input, false),\n this.runSeat(1, input, false),\n ]);\n const rejected = settled.find((entry) => entry.status === 'rejected');\n if (rejected) throw rejected.reason;\n const [first, second] = settled.map(\n (entry) => (entry as PromiseFulfilledResult<FusionSeatResult>).value,\n ) as [FusionSeatResult, FusionSeatResult];\n if (first.status !== 'ok' && second.status !== 'ok') return undefined;\n if (definition.gate) {\n this.gate = await this.runGate(definition.gate, input, [first, second]);\n if (this.gate.status === 'sufficient') {\n this.skip(2);\n return seatOutputText(this.firstLive(0, 1) as FusionSeatResult);\n }\n }\n const merge = await this.runSeat(\n 2,\n [\n input,\n '',\n 'Two seats answered the request above in parallel. Merge their outputs into one answer.',\n describeSeat(first, 'Output of'),\n describeSeat(second, 'Output of'),\n ].join('\\n'),\n true,\n );\n if (merge.status === 'ok') return seatOutputText(merge);\n // The merge died: answer with the first live input, reported degraded.\n return seatOutputText(this.firstLive(0, 1) as FusionSeatResult);\n }\n // handoff\n const draft = await this.runSeat(0, input, false);\n if (definition.gate) {\n this.gate = await this.runGate(definition.gate, input, [draft]);\n if (this.gate.status === 'sufficient') {\n this.skip(1);\n return seatOutputText(draft);\n }\n }\n const answer = await this.runSeat(\n 1,\n [\n input,\n '',\n 'Another seat drafted an answer to the request above. Review the draft and give the final answer.',\n describeSeat(draft, 'Draft from'),\n ].join('\\n'),\n true,\n );\n if (answer.status === 'ok') return seatOutputText(answer);\n if (draft.status === 'ok') return seatOutputText(draft);\n return undefined;\n }\n\n private result(status: InferenceRunStatus, text: string): FusionRunResult {\n for (const seat of this.seats) {\n const usage = this.usage.get(seat.name);\n if (usage) seat.usage = usage;\n }\n return {\n runId: this.runId,\n fusionKey: this.key,\n mode: this.definition.mode,\n status,\n text,\n seats: this.seats.map((seat) => ({ ...seat })),\n ...(this.gate ? { gate: this.gate } : {}),\n durationMs: Math.max(0, this.options.now() - this.started),\n };\n }\n\n private async record(result: FusionRunResult): Promise<void> {\n if (!this.context.recordRun) return;\n const ran = result.seats.filter(\n (seat) => seat.status === 'ok' || seat.status === 'failed',\n );\n try {\n await this.context.recordRun({\n id: result.runId,\n fusionKey: result.fusionKey,\n mode: result.mode,\n ...(this.entryPromptKey ? { promptKey: this.entryPromptKey } : {}),\n seats: ran.length,\n degradedSeats: ran.filter(isDegraded).length,\n status: result.status,\n duration: result.durationMs,\n // Identities and totals only: never prompts, inputs or outputs.\n details: {\n seats: result.seats.map((seat) => ({\n persona: seat.name,\n prompt: seat.prompt,\n status: seat.status,\n target: seat.target,\n ...(seat.model ? { model: seat.model } : {}),\n ...(seat.usage ? { usage: seat.usage } : {}),\n ...(seat.substitutions\n ? { substitutions: seat.substitutions }\n : {}),\n ...(seat.failure\n ? {\n failure: {\n reason: seat.failure.reason,\n ...(seat.failure.code ? { code: seat.failure.code } : {}),\n },\n }\n : {}),\n ...(seat.raw !== undefined ? { json: 'unparsed' } : {}),\n ...(seat.json !== undefined ? { json: 'parsed' } : {}),\n ...(seat.durationMs !== undefined\n ? { durationMs: seat.durationMs }\n : {}),\n })),\n ...(result.gate\n ? {\n gate: {\n status: result.gate.status,\n ...(result.gate.choice ? { choice: result.gate.choice } : {}),\n ...(result.gate.confidence !== undefined\n ? { confidence: result.gate.confidence }\n : {}),\n ...(result.gate.model ? { model: result.gate.model } : {}),\n },\n }\n : {}),\n },\n });\n } catch {\n // Recording must never mask the run's own outcome.\n }\n }\n\n async run(input: string): Promise<FusionRunResult> {\n const stop = this.context.observeUsage?.(this.runId, (event) => {\n const seat = event.tags.seat;\n if (!seat) return;\n const usage = this.usage.get(seat) ?? {\n promptTokens: 0,\n completionTokens: 0,\n totalTokens: 0,\n };\n usage.promptTokens += event.promptTokens;\n usage.completionTokens += event.completionTokens;\n usage.totalTokens += event.totalTokens;\n if (event.estimatedCost !== undefined) {\n usage.estimatedCost = (usage.estimatedCost ?? 0) + event.estimatedCost;\n }\n this.usage.set(seat, usage);\n });\n try {\n let text: string | undefined;\n try {\n text = await this.interpret(input);\n } catch (error) {\n const failed = this.result('failed', '');\n await this.record(failed);\n if (error instanceof InferenceConfigError || isInferenceAbort(error)) {\n throw error;\n }\n throw new InferenceFusionError(failed, error);\n }\n if (text === undefined) {\n const failed = this.result('failed', '');\n await this.record(failed);\n throw new InferenceFusionError(failed);\n }\n const degraded = this.seats.some(isDegraded);\n const done = this.result(degraded ? 'degraded' : 'ok', text);\n await this.record(done);\n return done;\n } finally {\n stop?.();\n }\n }\n}\n\n/** A seat that died, or answered through a substitution. */\nfunction isDegraded(seat: FusionSeatResult): boolean {\n return (\n seat.status === 'failed' ||\n (seat.status === 'ok' && (seat.substitutions?.length ?? 0) > 0)\n );\n}\n\n/** A fusion a target names, validated. */\ninterface ResolvedFusion {\n key: string;\n definition: InferenceFusionDefinition;\n}\n\n/** Where a fusion definition was found, for validation paths. */\ntype FusionOrigin = 'resolver' | 'config' | 'registry';\n\nfunction unknownFusion(\n context: InferenceExecutionContext,\n key: string,\n): InferenceConfigError {\n return new InferenceConfigError([\n {\n path: `resolution.${context.resolution.tierResolved}`,\n code: 'fusion-unknown',\n message: `tier \"${context.resolution.tierResolved}\" names unknown fusion \"${key}\"`,\n },\n ]);\n}\n\n/**\n * Validate a definition before it runs, whatever its origin: structure\n * against the call's config (aliases) and every seat's prompt key. A\n * resolver's stored definition (an app override row, #4800) gets the same\n * checks as config, so an invalid stored row is a load error, never a run.\n */\nfunction validatedFusion(\n context: InferenceExecutionContext,\n key: string,\n definition: InferenceFusionDefinition,\n origin: FusionOrigin,\n): ResolvedFusion {\n const path =\n origin === 'config'\n ? `inference.fusions.${key}`\n : origin === 'resolver'\n ? `resolver.fusions.${key}`\n : `fusions.${key}`;\n const issues = [\n ...findFusionDefinitionIssues(definition, path, context.config),\n ...findFusionDefinitionPromptIssues(definition, path),\n ];\n if (issues.length > 0) throw new InferenceConfigError(issues);\n return { key, definition };\n}\n\n/**\n * Resolve and validate the fusion a target names without the context's\n * lookup (older cores, direct executor contexts): config, then registry.\n */\nfunction fusionForSync(context: InferenceExecutionContext): ResolvedFusion {\n const key = String(context.resolution.target.fusion ?? '').trim();\n const definition = key ? lookupFusion(key, context.config) : undefined;\n if (!definition) throw unknownFusion(context, key);\n const origin: FusionOrigin = Object.hasOwn(context.config?.fusions ?? {}, key)\n ? 'config'\n : 'registry';\n return validatedFusion(context, key, definition, origin);\n}\n\n/**\n * Resolve and validate the fusion a target names (#4800). With core's\n * `context.lookupFusion()`, precedence is: the registered resolver's stored\n * layer (app override rows), then `inference.fusions`, then the\n * `defineFusion()` registry; each source replaces a lower one whole.\n */\nasync function fusionFor(\n context: InferenceExecutionContext,\n): Promise<ResolvedFusion> {\n if (typeof context.lookupFusion !== 'function') return fusionForSync(context);\n const key = String(context.resolution.target.fusion ?? '').trim();\n if (!key) throw unknownFusion(context, key);\n const found = await context.lookupFusion(key);\n if (found) {\n return validatedFusion(context, key, found.definition, found.source);\n }\n const registered = fusionStore().get(key);\n if (!registered) throw unknownFusion(context, key);\n return validatedFusion(context, key, registered, 'registry');\n}\n\n/**\n * Run a fusion for one input and return the structured result. Throws\n * {@link InferenceFusionError} (`INFERENCE_FUSION_FAILED`) when every seat\n * died, with the run recorded as `failed`.\n */\nexport async function runFusion(\n context: InferenceExecutionContext,\n input: string,\n callerOptions: InferenceCallOptions = {},\n options: ChainExecutorOptions = {},\n): Promise<FusionRunResult> {\n return runResolvedFusion(\n context,\n await fusionFor(context),\n input,\n callerOptions,\n options,\n );\n}\n\nfunction runResolvedFusion(\n context: InferenceExecutionContext,\n { key, definition }: ResolvedFusion,\n input: string,\n callerOptions: InferenceCallOptions,\n options: ChainExecutorOptions,\n): Promise<FusionRunResult> {\n const resolved: Required<ChainExecutorOptions> = {\n retryDelayMs: options.retryDelayMs ?? (() => 200 + Math.random() * 300),\n sleep:\n options.sleep ??\n ((ms: number) => new Promise((resolve) => setTimeout(resolve, ms))),\n now: options.now ?? (() => Date.now()),\n };\n return new FusionRun(context, key, definition, callerOptions, resolved).run(\n input,\n );\n}\n\nfunction unsupported(method: string): never {\n throw new TypeError(\n `A fusion target runs through message(); ${method}() is not supported (#4753).`,\n );\n}\n\n/**\n * The client core receives for a `{ fusion }` target: `message()` runs the\n * fusion and resolves the final seat's text; `onFusionResult` in the call\n * options receives the structured result.\n */\nexport function createFusionClient(\n context: InferenceExecutionContext,\n options: ChainExecutorOptions = {},\n): InferenceModelClient {\n // Without core's lookup the definition is known now: fail at bind time.\n // With it (#4800) the lookup may read stored rows, so it starts now, once\n // per client, and an unknown or invalid fusion fails the first call before\n // any seat runs (nothing is recorded).\n let fusion: Promise<ResolvedFusion>;\n if (typeof context.lookupFusion === 'function') {\n fusion = fusionFor(context);\n fusion.catch(() => {}); // surfaced by message(); never unhandled\n } else {\n fusion = Promise.resolve(fusionForSync(context));\n }\n return {\n async message(text: string, callerOptions?: InferenceCallOptions) {\n const { onFusionResult, ...rest } = (callerOptions ?? {}) as\n | (InferenceCallOptions & FusionCallOptions)\n | Record<string, never>;\n const result = await runResolvedFusion(\n context,\n await fusion,\n text,\n rest,\n options,\n );\n if (typeof onFusionResult === 'function') onFusionResult(result);\n return result.text;\n },\n chat: () => unsupported('chat'),\n complete: () => unsupported('complete'),\n stream: () => unsupported('stream'),\n embed: () => unsupported('embed'),\n };\n}\n\n/**\n * The executor registered into core's seam: `alias` / `candidates` chains\n * and `fusion` targets (#4753), one `kinds` table.\n */\nexport function createChainExecutor(\n options: ChainExecutorOptions = {},\n): InferenceExecutor {\n return {\n kinds: EXECUTOR_KINDS,\n createClient: (context) =>\n inferenceTargetKind(context.resolution.target) === 'fusion'\n ? createFusionClient(context, options)\n : createChainClient(context, options),\n };\n}\n","/**\n * Registration into core's inference seam (#4752).\n *\n * The resolver binds nothing itself: it validates chain config (naming every\n * offender) and then defers, either to a resolver registered before this\n * package (a per-user binding resolver, #4666) or to core's built-in config\n * resolution. With no aliases and no chain targets it adds nothing, so an app\n * that imports this package without configuring chains is unchanged.\n */\nimport {\n builtInInferenceResolver,\n getInferenceExecutor,\n getInferenceResolver,\n type InferenceConfig,\n type InferenceResolver,\n setInferenceExecutor,\n setInferenceResolver,\n} from '@happyvertical/smrt-core';\nimport { hasInferenceChains, validateInferenceConfig } from './config.js';\nimport type { ChainExecutorOptions } from './executor.js';\nimport { createChainExecutor } from './fusion.js';\n\nconst OWN_RESOLVER = Symbol.for('smrt.inference.chainResolver');\n\ntype MarkedResolver = InferenceResolver & { [OWN_RESOLVER]?: true };\n\n/**\n * A resolver that validates chain config before deferring to `base` (or to\n * core's built-in resolution). Validation is memoized per distinct config.\n */\nexport function createInferenceResolver(\n base?: InferenceResolver,\n): InferenceResolver {\n let validated: string | undefined;\n const validate = (config: InferenceConfig | undefined) => {\n if (!hasInferenceChains(config)) return;\n const key = JSON.stringify(config);\n if (key === validated) return;\n validateInferenceConfig(config);\n validated = key;\n };\n const resolver: MarkedResolver = {\n async resolve(request, context) {\n validate(context.config);\n return base ? base.resolve(request, context) : undefined;\n },\n };\n // Forward the optional #4757 mode hook only when the base has one, so a\n // resolver without it keeps untiered calls free of resolver work.\n if (base && typeof base.mode === 'function') {\n const mode = base.mode.bind(base);\n resolver.mode = (request) => mode(request);\n }\n // Forward the #4800 fusion lookup the same way: stored fusions (app\n // override rows) reach the executor through core's `lookupFusion()`.\n if (base && typeof base.lookupFusion === 'function') {\n const lookupFusion = base.lookupFusion.bind(base);\n resolver.lookupFusion = (key, request, context) =>\n lookupFusion(key, request, context);\n }\n resolver[OWN_RESOLVER] = true;\n return resolver;\n}\n\n/** Options for {@link registerInference}. */\nexport interface RegisterInferenceOptions {\n /** Executor test seams (retry delay, sleep, clock). */\n executor?: ChainExecutorOptions;\n}\n\n/**\n * Register the chain executor and the validating resolver. Idempotent: a\n * resolver registered earlier by another package is kept as the base this\n * one defers to; re-registering replaces only this package's own pieces.\n */\nexport function registerInference(\n options: RegisterInferenceOptions = {},\n): void {\n setInferenceExecutor(createChainExecutor(options.executor));\n const current = getInferenceResolver() as MarkedResolver;\n if (current[OWN_RESOLVER]) return;\n setInferenceResolver(\n createInferenceResolver(\n current === builtInInferenceResolver ? undefined : current,\n ),\n );\n}\n\n/** True when this package's executor is the registered one. */\nexport function isInferenceRegistered(): boolean {\n const executor = getInferenceExecutor();\n return !!executor && executor.kinds.includes('alias');\n}\n","/**\n * The stored inference provider config (#4756): one smrt-secrets type,\n * `inference.provider-config`, holding a user's or a tenant's provider\n * options. The hosted wave (#4759) writes the same type with\n * `source: 'hosted'`.\n *\n * Browser-safe (core types and presets only) so a settings panel can share\n * the shape and the redacted view; reading and writing secrets lives in the\n * Node-only `./resolver` entry.\n */\n\nimport {\n INFERENCE_MODES,\n INFERENCE_PRESETS,\n INFERENCE_TIERS,\n type InferenceMode,\n type InferenceTarget,\n type InferenceTier,\n isInferenceMode,\n isInferencePresetId,\n isInferenceTier,\n} from '@happyvertical/smrt-core';\nimport { SmrtError } from '@happyvertical/smrt-core/smrt-error';\n\n/** The smrt-secrets category (and name prefix) of a stored provider config. */\nexport const INFERENCE_PROVIDER_CONFIG_SECRET_TYPE =\n 'inference.provider-config';\n\n/** Sources a stored config may declare; `app` belongs to app config only. */\nexport const INFERENCE_PROVIDER_CONFIG_SOURCES = [\n 'byo',\n 'local',\n 'hosted',\n] as const;\n\nexport type InferenceProviderConfigSource =\n (typeof INFERENCE_PROVIDER_CONFIG_SOURCES)[number];\n\n/** One binding: provider options for every tier, or for one tier. */\nexport interface InferenceProviderBinding {\n /** Provider name (`openai`, `anthropic`, `ollama`, ...). */\n provider?: string;\n /** Endpoint. Required with `apiKey` unless `preset` supplies it. */\n baseUrl?: string;\n model?: string;\n /** The credential. Never logged, tagged, or returned redacted. */\n apiKey?: string;\n /** A #4674 preset id (`openrouter`, `lemonade`, ...); needs `model`. */\n preset?: string;\n /**\n * Per-call generation defaults; caller options win. Only\n * {@link INFERENCE_PROVIDER_PARAM_KEYS} with scalar values are accepted,\n * so no credential or header can hide here.\n */\n params?: Record<string, unknown>;\n}\n\n/**\n * The value of an `inference.provider-config` secret. The top-level binding\n * is the default for every tier; `tiers` binds tiers individually (#4754\n * Advanced) and wins for the tiers it names.\n */\nexport interface InferenceProviderConfig extends InferenceProviderBinding {\n version?: 1;\n /** Declared origin; derived (`local` / `byo`) when absent. */\n source?: InferenceProviderConfigSource;\n /**\n * The chosen inference mode (#4757). `off` turns every call off for this\n * scope; `byo` / `local` / `hosted` use only a stored binding of that\n * source. Absent: the fall-through order (user, tenant, app). A config may\n * hold only a mode (no binding, no key).\n */\n mode?: InferenceMode;\n /**\n * Hosted inference (#4759): the gateway virtual key's alias, a non-secret\n * handle recorded as the `gatewayKeyAlias` usage tag on every call this\n * config answers. Only valid with `source: 'hosted'`; never the key.\n */\n gatewayKeyAlias?: string;\n tiers?: Partial<Record<InferenceTier, InferenceProviderBinding>>;\n}\n\n/** A binding with its key removed: what a settings panel may read. */\nexport type RedactedInferenceProviderBinding = Omit<\n InferenceProviderBinding,\n 'apiKey'\n> & { hasApiKey: boolean };\n\n/** {@link InferenceProviderConfig} with every key removed. */\nexport interface RedactedInferenceProviderConfig\n extends RedactedInferenceProviderBinding {\n version?: 1;\n source?: InferenceProviderConfigSource;\n mode?: InferenceMode;\n gatewayKeyAlias?: string;\n tiers?: Partial<Record<InferenceTier, RedactedInferenceProviderBinding>>;\n}\n\n/**\n * A stored config that cannot bind (`INFERENCE_PROVIDER_CONFIG_INVALID`).\n * Messages name fields by path, never values.\n */\nexport class InferenceProviderConfigError extends SmrtError {\n readonly issues: string[];\n\n constructor(issues: string[]) {\n super(\n `Invalid inference provider config: ${issues.join('; ')}`,\n 'INFERENCE_PROVIDER_CONFIG_INVALID',\n 'configuration',\n { issues },\n );\n this.issues = issues;\n }\n}\n\n/** Generation options a stored binding may carry in `params`. */\nexport const INFERENCE_PROVIDER_PARAM_KEYS = [\n 'temperature',\n 'maxTokens',\n 'topP',\n 'topK',\n 'frequencyPenalty',\n 'presencePenalty',\n 'seed',\n 'stop',\n] as const;\n\nconst PARAM_KEYS: readonly string[] = INFERENCE_PROVIDER_PARAM_KEYS;\n\nfunction isParamValue(value: unknown): boolean {\n if (typeof value === 'number') return Number.isFinite(value);\n if (typeof value === 'string') return true;\n return (\n Array.isArray(value) &&\n value.length <= 16 &&\n value.every((entry) => typeof entry === 'string')\n );\n}\n\n/** Only the allowed scalar generation options (defence for legacy rows). */\nfunction safeParams(\n params: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined {\n if (!params) return undefined;\n const out: Record<string, unknown> = {};\n for (const key of PARAM_KEYS) {\n const value = params[key];\n if (value !== undefined && isParamValue(value)) {\n out[key] = Array.isArray(value) ? [...value] : value;\n }\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nconst BINDING_FIELDS = [\n 'provider',\n 'baseUrl',\n 'model',\n 'apiKey',\n 'preset',\n] as const;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction text(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() !== ''\n ? value.trim()\n : undefined;\n}\n\nfunction hasBinding(binding: InferenceProviderBinding | undefined): boolean {\n return !!binding && (!!binding.provider || !!binding.preset);\n}\n\nfunction parseBinding(\n value: unknown,\n path: string,\n issues: string[],\n): InferenceProviderBinding | undefined {\n if (value === undefined) return undefined;\n if (!isRecord(value)) {\n issues.push(`${path} must be an object`);\n return undefined;\n }\n const binding: InferenceProviderBinding = {};\n for (const field of BINDING_FIELDS) {\n const raw = value[field];\n if (raw === undefined || raw === null || raw === '') continue;\n const parsed = text(raw);\n if (!parsed) {\n issues.push(`${path}.${field} must be a non-empty string`);\n continue;\n }\n binding[field] = parsed;\n }\n if (value.params !== undefined) {\n if (!isRecord(value.params)) {\n issues.push(`${path}.params must be an object`);\n } else {\n for (const [key, param] of Object.entries(value.params)) {\n if (!PARAM_KEYS.includes(key)) {\n issues.push(\n `${path}.params.${key} is not a supported generation option (${INFERENCE_PROVIDER_PARAM_KEYS.join(', ')})`,\n );\n } else if (!isParamValue(param)) {\n issues.push(`${path}.params.${key} must be a number or string`);\n }\n }\n const params = safeParams(value.params);\n if (params) binding.params = params;\n }\n }\n if (binding.preset) {\n if (!isInferencePresetId(binding.preset)) {\n issues.push(`${path}.preset is not a known preset`);\n } else {\n if (!binding.model) issues.push(`${path}.model is required with preset`);\n if (INFERENCE_PRESETS[binding.preset].requiresApiKey && !binding.apiKey) {\n issues.push(`${path}.apiKey is required by preset`);\n }\n }\n if (binding.provider) {\n issues.push(`${path} names both provider and preset`);\n }\n } else if (Object.keys(binding).length > 0 && !binding.provider) {\n issues.push(`${path}.provider is required`);\n }\n if (binding.baseUrl && !isPlainEndpoint(binding.baseUrl)) {\n issues.push(\n `${path}.baseUrl must be an http(s) URL without credentials, query or fragment`,\n );\n }\n // A stored binding is self-contained: its own endpoint and its own key\n // (core's pair rule), so it never borrows the server's environment\n // credentials (`OPENAI_API_KEY`, `HAVE_AI_*`, ...) for another provider.\n if (binding.provider && !binding.preset) {\n if (!binding.baseUrl) {\n issues.push(\n `${path}.baseUrl is required (a stored binding names its own endpoint)`,\n );\n }\n if (!binding.apiKey) {\n issues.push(\n `${path}.apiKey is required (a placeholder such as 'smrt-local' for a keyless local server)`,\n );\n }\n }\n return binding;\n}\n\n/**\n * Validate a stored value (an object, or its JSON text). Throws\n * {@link InferenceProviderConfigError} naming every offending path.\n */\nexport function parseInferenceProviderConfig(\n value: unknown,\n): InferenceProviderConfig {\n let raw = value;\n if (typeof raw === 'string') {\n try {\n raw = JSON.parse(raw);\n } catch {\n throw new InferenceProviderConfigError(['value is not JSON']);\n }\n }\n if (!isRecord(raw)) {\n throw new InferenceProviderConfigError(['value must be an object']);\n }\n const issues: string[] = [];\n const config: InferenceProviderConfig = {\n ...(parseBinding(\n Object.fromEntries(\n Object.entries(raw).filter(\n ([key]) =>\n key !== 'tiers' &&\n key !== 'source' &&\n key !== 'version' &&\n key !== 'mode' &&\n key !== 'gatewayKeyAlias',\n ),\n ),\n 'config',\n issues,\n ) ?? {}),\n };\n if (raw.version !== undefined && raw.version !== 1) {\n issues.push('version must be 1');\n } else if (raw.version === 1) {\n config.version = 1;\n }\n if (raw.source !== undefined) {\n if (\n (INFERENCE_PROVIDER_CONFIG_SOURCES as readonly unknown[]).includes(\n raw.source,\n )\n ) {\n config.source = raw.source as InferenceProviderConfigSource;\n } else {\n issues.push(\n `source must be one of ${INFERENCE_PROVIDER_CONFIG_SOURCES.join(', ')}`,\n );\n }\n }\n if (raw.mode !== undefined) {\n if (isInferenceMode(raw.mode)) {\n config.mode = raw.mode;\n } else {\n issues.push(`mode must be one of ${INFERENCE_MODES.join(', ')}`);\n }\n }\n if (raw.gatewayKeyAlias !== undefined) {\n const alias = text(raw.gatewayKeyAlias);\n if (!alias || alias.length > 200) {\n issues.push(\n 'gatewayKeyAlias must be a non-empty string of at most 200 characters',\n );\n } else if (config.source !== 'hosted') {\n issues.push(\"gatewayKeyAlias needs source 'hosted'\");\n } else {\n config.gatewayKeyAlias = alias;\n }\n }\n if (raw.tiers !== undefined) {\n if (!isRecord(raw.tiers)) {\n issues.push('tiers must be an object');\n } else {\n const tiers: Partial<Record<InferenceTier, InferenceProviderBinding>> =\n {};\n for (const [tier, binding] of Object.entries(raw.tiers)) {\n if (!isInferenceTier(tier)) {\n issues.push(\n `tiers.${tier} is not a tier (${INFERENCE_TIERS.join(', ')})`,\n );\n continue;\n }\n const parsed = parseBinding(binding, `tiers.${tier}`, issues);\n if (parsed && hasBinding(parsed)) tiers[tier] = parsed;\n }\n if (Object.keys(tiers).length > 0) config.tiers = tiers;\n }\n }\n for (const known of Object.keys(raw)) {\n if (\n ![\n ...BINDING_FIELDS,\n 'params',\n 'tiers',\n 'source',\n 'version',\n 'mode',\n 'gatewayKeyAlias',\n ].includes(known)\n ) {\n issues.push(`config.${known} is not a provider config field`);\n }\n }\n if (issues.length > 0) throw new InferenceProviderConfigError(issues);\n return config;\n}\n\n/** An http(s) URL with no userinfo, query or fragment (no hidden secrets). */\nfunction isPlainEndpoint(baseUrl: string): boolean {\n try {\n const url = new URL(baseUrl);\n return (\n (url.protocol === 'http:' || url.protocol === 'https:') &&\n !url.username &&\n !url.password &&\n !url.search &&\n !url.hash\n );\n } catch {\n return false;\n }\n}\n\nfunction isLoopbackUrl(baseUrl: string | undefined): boolean {\n if (!baseUrl) return false;\n try {\n const host = new URL(baseUrl).hostname.toLowerCase();\n return (\n host === 'localhost' ||\n host.endsWith('.localhost') ||\n host === '[::1]' ||\n host === '::1' ||\n host === '0.0.0.0' ||\n /^127\\.\\d+\\.\\d+\\.\\d+$/.test(host)\n );\n } catch {\n return false;\n }\n}\n\n/**\n * The origin a binding reports as its `source` usage tag: the config's\n * declared source, else `local` for a keyless preset or a loopback endpoint,\n * else `byo`.\n */\nexport function inferenceProviderSource(\n config: Pick<InferenceProviderConfig, 'source'>,\n binding: InferenceProviderBinding,\n): InferenceProviderConfigSource {\n if (config.source) return config.source;\n if (binding.preset && isInferencePresetId(binding.preset)) {\n return INFERENCE_PRESETS[binding.preset].requiresApiKey ? 'byo' : 'local';\n }\n if (binding.provider?.toLowerCase() === 'ollama') return 'local';\n return isLoopbackUrl(binding.baseUrl) ? 'local' : 'byo';\n}\n\n/** Keyless placeholder core's pair rule accepts for a local server. */\nconst KEYLESS_PLACEHOLDER = 'smrt-local';\n\nfunction bindingToTarget(\n config: InferenceProviderConfig,\n binding: InferenceProviderBinding,\n): InferenceTarget {\n const source = inferenceProviderSource(config, binding);\n // Hosted keys are tagged by alias (never the key) so metering can join\n // usage rows to the gateway's own key ledger (#4759).\n const usageTags = config.gatewayKeyAlias\n ? { usageTags: { gatewayKeyAlias: config.gatewayKeyAlias } }\n : {};\n if (binding.preset && isInferencePresetId(binding.preset)) {\n return {\n provider: 'openai',\n baseUrl: binding.baseUrl ?? INFERENCE_PRESETS[binding.preset].baseUrl,\n ...(binding.model ? { model: binding.model } : {}),\n apiKey: binding.apiKey ?? KEYLESS_PLACEHOLDER,\n ...(safeParams(binding.params)\n ? { params: safeParams(binding.params) }\n : {}),\n source,\n ...usageTags,\n };\n }\n return {\n ...(binding.provider ? { provider: binding.provider } : {}),\n ...(binding.model ? { model: binding.model } : {}),\n ...(binding.baseUrl ? { baseUrl: binding.baseUrl } : {}),\n ...(binding.apiKey ? { apiKey: binding.apiKey } : {}),\n ...(safeParams(binding.params)\n ? { params: safeParams(binding.params) }\n : {}),\n source,\n ...usageTags,\n };\n}\n\n/** The binding a config applies to `tier`, if any. */\nexport function inferenceProviderBindingFor(\n config: InferenceProviderConfig | undefined,\n tier: InferenceTier,\n): InferenceProviderBinding | undefined {\n if (!config) return undefined;\n const own = config.tiers?.[tier];\n if (hasBinding(own)) return own;\n return hasBinding(config) ? config : undefined;\n}\n\n/**\n * The tier → target map a config binds. A tier the config does not bind is\n * absent (the next layer answers it). Targets carry the key: server-only.\n */\nexport function inferenceProviderTargets(\n config: InferenceProviderConfig | undefined,\n): Partial<Record<InferenceTier, InferenceTarget>> {\n const targets: Partial<Record<InferenceTier, InferenceTarget>> = {};\n if (!config) return targets;\n for (const tier of INFERENCE_TIERS) {\n const binding = inferenceProviderBindingFor(config, tier);\n if (binding) targets[tier] = bindingToTarget(config, binding);\n }\n return targets;\n}\n\nfunction redactBinding(\n binding: InferenceProviderBinding,\n): RedactedInferenceProviderBinding {\n // Copy known non-secret fields only: nothing unexpected in a stored row\n // (legacy or hand-written) can reach the settings view.\n const params = safeParams(binding.params);\n return {\n ...(binding.provider ? { provider: binding.provider } : {}),\n ...(binding.preset ? { preset: binding.preset } : {}),\n ...(binding.baseUrl ? { baseUrl: binding.baseUrl } : {}),\n ...(binding.model ? { model: binding.model } : {}),\n ...(params ? { params } : {}),\n hasApiKey: !!binding.apiKey && binding.apiKey !== KEYLESS_PLACEHOLDER,\n };\n}\n\n/** The config without any key: the shape a settings panel reads. */\nexport function redactInferenceProviderConfig(\n config: InferenceProviderConfig,\n): RedactedInferenceProviderConfig {\n const { tiers, version, source, mode, gatewayKeyAlias, ...binding } = config;\n const redacted: RedactedInferenceProviderConfig = {\n ...redactBinding(binding),\n ...(version ? { version } : {}),\n ...(source ? { source } : {}),\n ...(mode ? { mode } : {}),\n ...(gatewayKeyAlias ? { gatewayKeyAlias } : {}),\n };\n if (tiers) {\n redacted.tiers = {};\n for (const [tier, value] of Object.entries(tiers)) {\n if (value) redacted.tiers[tier as InferenceTier] = redactBinding(value);\n }\n }\n return redacted;\n}\n\n/** A target without its key (`hasApiKey` says whether one is bound). */\nexport function redactInferenceTarget(\n target: InferenceTarget,\n): Omit<InferenceTarget, 'apiKey'> & { hasApiKey: boolean } {\n const params = safeParams(target.params);\n return {\n ...(target.provider ? { provider: target.provider } : {}),\n ...(target.baseUrl ? { baseUrl: target.baseUrl } : {}),\n ...(target.model ? { model: target.model } : {}),\n ...(target.latency ? { latency: target.latency } : {}),\n ...(target.source ? { source: target.source } : {}),\n ...(params ? { params } : {}),\n ...(target.usageTags ? { usageTags: { ...target.usageTags } } : {}),\n hasApiKey: !!target.apiKey && target.apiKey !== KEYLESS_PLACEHOLDER,\n };\n}\n\n/**\n * The secret name for a scope: user configs are user-qualified, the tenant\n * config is one name; both live under `context = tenantId`.\n */\nexport function inferenceProviderConfigSecretName(scope: {\n userId?: string | null;\n}): string {\n const userId = text(scope.userId);\n return userId\n ? `${INFERENCE_PROVIDER_CONFIG_SECRET_TYPE}:user:${userId}`\n : `${INFERENCE_PROVIDER_CONFIG_SECRET_TYPE}:tenant`;\n}\n"],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Failure classification for the chain walk (#4752).
3
+ *
4
+ * Classifies from structured facts only — the SDK error class name, its
5
+ * `code`, `retryable`, and HTTP `status` — collected across the whole cause
6
+ * chain (`cause`, `error`, `context.originalError`), the way core's
7
+ * `db-errors.ts` classifies database failures. Message text is never read:
8
+ * a provider rewording its error must not change routing.
9
+ *
10
+ * `@happyvertical/ai` maps provider failures onto `AIError` subclasses
11
+ * (`AuthenticationError` AUTH_ERROR, `RateLimitError` RATE_LIMIT with the
12
+ * provider error as `cause`, `ModelNotFoundError` MODEL_NOT_FOUND,
13
+ * `ContentFilterError` CONTENT_FILTERED, AI_TIMEOUT, AI_ABORTED). It maps
14
+ * other HTTP failures (5xx, 400) to `API_ERROR` / `UNKNOWN_ERROR` without the
15
+ * status or cause; those classify as `transient` so a route outage still
16
+ * advances, bounded by one retry per candidate. When a status survives in the
17
+ * chain, a client error (other 4xx, `invalid_request_error`, context length)
18
+ * stops the walk instead.
19
+ */
20
+ import type { InferenceFailureClass } from './types.js';
21
+ /**
22
+ * True for a caller abort (`AI_ABORTED`, `AbortError`): never a routing
23
+ * failure, so the walk stops and rethrows.
24
+ */
25
+ export declare function isInferenceAbort(error: unknown): boolean;
26
+ /**
27
+ * Classify a provider failure, or `undefined` when it is not a routing
28
+ * failure (a caller abort, a programming error, invalid input the SDK did
29
+ * not map). Unclassified errors end the walk and are rethrown.
30
+ */
31
+ export declare function classifyInferenceFailure(error: unknown): InferenceFailureClass | undefined;
32
+ //# sourceMappingURL=classify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../src/classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAsKxD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAGxD;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,OAAO,GACb,qBAAqB,GAAG,SAAS,CAmEnC"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Alias config validation and chain expansion (#4752). Browser-safe: reads
3
+ * the environment through `globalThis.process` when one exists.
4
+ */
5
+ import { type InferenceCandidate, type InferenceConfig, type InferenceTarget, type InferenceTier } from '@happyvertical/smrt-core';
6
+ import type { InferenceConfigIssue, InferenceFailureClass } from './types.js';
7
+ /** Target kinds this package runs. */
8
+ export declare const CHAIN_KINDS: readonly ["alias", "candidates"];
9
+ /** Target kinds the executor runs: the chains plus `fusion` (#4753). */
10
+ export declare const EXECUTOR_KINDS: readonly ["alias", "candidates", "fusion"];
11
+ /**
12
+ * True when the config binds anything this package validates: aliases,
13
+ * fusions, or a chain or fusion tier target.
14
+ */
15
+ export declare function hasInferenceChains(config: InferenceConfig | undefined): boolean;
16
+ /** Seats per mode: each mode's call count is fixed (#4753). */
17
+ export declare const FUSION_SEAT_COUNTS: {
18
+ readonly single: 1;
19
+ readonly pair: 3;
20
+ readonly handoff: 2;
21
+ };
22
+ /** The gate's other choice label: run the remaining stage. */
23
+ export declare const FUSION_GATE_CONTINUE = "continue";
24
+ /** The `seat` tag of the gate's decision usage row; no seat may use it. */
25
+ export declare const FUSION_GATE_SEAT = "gate";
26
+ /**
27
+ * Structural problems of one fusion definition, named by path (`path` is
28
+ * `inference.fusions.<key>` or `fusions.<key>` for `defineFusion()`).
29
+ * Prompt registration is checked separately ({@link findFusionPromptIssues})
30
+ * because the doctor runs without the app's prompts loaded.
31
+ */
32
+ export declare function findFusionDefinitionIssues(definition: unknown, path: string, config: InferenceConfig | undefined): InferenceConfigIssue[];
33
+ /** Seats of `definition` whose prompt key no `definePrompt()` registered. */
34
+ export declare function findFusionDefinitionPromptIssues(definition: unknown, path: string): InferenceConfigIssue[];
35
+ /**
36
+ * Seats of `inference.fusions` whose prompt key is not registered. A load
37
+ * error: the validating resolver and the executor refuse such a config.
38
+ */
39
+ export declare function findFusionPromptIssues(config: InferenceConfig | undefined): InferenceConfigIssue[];
40
+ /**
41
+ * Validate one resolved target against the config's aliases. A resolver
42
+ * (#4666 per-user bindings) can return chains that never appear in config,
43
+ * so the executor checks every target it runs, not only the config block.
44
+ */
45
+ export declare function validateInferenceTarget(target: InferenceTarget, path: string, config: InferenceConfig | undefined): void;
46
+ /**
47
+ * Every problem in an `inference` block's chains: an alias with no
48
+ * candidates, a reference to an unknown alias, an alias cycle, a malformed
49
+ * candidate. Each issue names its offender by config path.
50
+ */
51
+ export declare function findInferenceConfigIssues(config: InferenceConfig | undefined): InferenceConfigIssue[];
52
+ /**
53
+ * Throw an {@link InferenceConfigError} naming every offender, including
54
+ * fusion seats whose prompt key is not registered (a load error).
55
+ */
56
+ export declare function validateInferenceConfig(config: InferenceConfig | undefined): void;
57
+ /** One expanded chain entry, ready to bind. */
58
+ export interface ChainStep {
59
+ /** The tier whose chain this step belongs to. */
60
+ tier: InferenceTier;
61
+ /** Stable, key-free label used in substitution records. */
62
+ label: string;
63
+ /** A `single` target for core's `clientFor()`. */
64
+ target: InferenceTarget;
65
+ /** Per-call defaults for this candidate. */
66
+ params?: Record<string, unknown>;
67
+ /** Dedupe key: provider, model, endpoint and credential source. */
68
+ identity: string;
69
+ /** Set when the step cannot run (missing key); it is skipped, recorded. */
70
+ unavailable?: InferenceFailureClass;
71
+ /** The alias the step came from, if any. */
72
+ alias?: string;
73
+ }
74
+ /** Label for a candidate: `provider/model`, `preset:<id>/model`, `default`. */
75
+ export declare function candidateLabel(candidate: InferenceCandidate): string;
76
+ /**
77
+ * Bind one candidate to a `single` target. Keys come from `apiKey` or the
78
+ * variable named by `apiKeyEnv` at call time; a named variable that is unset
79
+ * makes the step `unavailable: 'credential'` (skipped and recorded, never
80
+ * sent keyless to a key-requiring endpoint).
81
+ */
82
+ export declare function candidateToStep(candidate: InferenceCandidate, tier: InferenceTier, alias?: string): ChainStep;
83
+ /**
84
+ * Expand a tier's target into ordered steps. A `single` target is one step
85
+ * (an empty one is the configured client, labelled `default`); unknown
86
+ * kinds expand to nothing (another executor's).
87
+ */
88
+ export declare function expandTarget(target: InferenceTarget, tier: InferenceTier, config: InferenceConfig | undefined): ChainStep[];
89
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAKL,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,aAAa,EAInB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,KAAK,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAE9E,sCAAsC;AACtC,eAAO,MAAM,WAAW,kCAAmC,CAAC;AAe5D,wEAAwE;AACxE,eAAO,MAAM,cAAc,4CAAsC,CAAC;AAElE;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,WAarE;AA2JD,+DAA+D;AAC/D,eAAO,MAAM,kBAAkB;;;;CAIrB,CAAC;AAEX,8DAA8D;AAC9D,eAAO,MAAM,oBAAoB,aAAa,CAAC;AAE/C,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB,SAAS,CAAC;AAEvC;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,OAAO,EACnB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,eAAe,GAAG,SAAS,GAClC,oBAAoB,EAAE,CAiKxB;AAED,6EAA6E;AAC7E,wBAAgB,gCAAgC,CAC9C,UAAU,EAAE,OAAO,EACnB,IAAI,EAAE,MAAM,GACX,oBAAoB,EAAE,CAexB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,eAAe,GAAG,SAAS,GAClC,oBAAoB,EAAE,CAKxB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,eAAe,GAAG,SAAS,GAClC,IAAI,CAON;AAYD;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,eAAe,GAAG,SAAS,GAClC,oBAAoB,EAAE,CAuExB;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,eAAe,GAAG,SAAS,GAClC,IAAI,CAMN;AAED,+CAA+C;AAC/C,MAAM,WAAW,SAAS;IACxB,iDAAiD;IACjD,IAAI,EAAE,aAAa,CAAC;IACpB,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,MAAM,EAAE,eAAe,CAAC;IACxB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,mEAAmE;IACnE,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AASD,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,SAAS,EAAE,kBAAkB,GAAG,MAAM,CAOpE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,kBAAkB,EAC7B,IAAI,EAAE,aAAa,EACnB,KAAK,CAAC,EAAE,MAAM,GACb,SAAS,CAmDX;AAgDD;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,eAAe,GAAG,SAAS,GAClC,SAAS,EAAE,CA8Cb"}
@@ -0,0 +1,51 @@
1
+ import { SmrtError } from '@happyvertical/smrt-core/smrt-error';
2
+ import type { InferenceConfigIssue, InferenceSubstitution, InferenceSubstitutionReason } from './types.js';
3
+ /** An `inference` config block that cannot bind (`INFERENCE_CONFIG_INVALID`). */
4
+ export declare class InferenceConfigError extends SmrtError {
5
+ readonly issues: InferenceConfigIssue[];
6
+ constructor(issues: InferenceConfigIssue[]);
7
+ }
8
+ /**
9
+ * A chain call that never produced a complete answer
10
+ * (`INFERENCE_EXHAUSTED`): every candidate failed, or one streamed text and
11
+ * then failed without `allowPartial`. `cause` is the last provider error.
12
+ */
13
+ export declare class InferenceExhaustedError extends SmrtError {
14
+ /** The failure that ended the walk. */
15
+ readonly reason: InferenceSubstitutionReason;
16
+ /** The full fallback trail, ending with `to: null`. */
17
+ readonly substitutions: InferenceSubstitution[];
18
+ /** Text already streamed to the caller, for a `partial` ending. */
19
+ readonly partialText?: string;
20
+ constructor(input: {
21
+ reason: InferenceSubstitutionReason;
22
+ substitutions: InferenceSubstitution[];
23
+ tierRequested: string;
24
+ partialText?: string;
25
+ cause?: unknown;
26
+ });
27
+ }
28
+ /** The result shape {@link InferenceFusionError} carries (fusion.ts). */
29
+ interface FailedFusionRun {
30
+ runId: string;
31
+ fusionKey: string;
32
+ seats: Array<{
33
+ name: string;
34
+ status: string;
35
+ failure?: {
36
+ reason: string;
37
+ message: string;
38
+ };
39
+ }>;
40
+ }
41
+ /**
42
+ * A fusion run that produced no answer (`INFERENCE_FUSION_FAILED`, #4753):
43
+ * every seat that ran died, or the run stopped on an unexpected error. The
44
+ * run is recorded as `failed`; `result` holds every seat's outcome.
45
+ */
46
+ export declare class InferenceFusionError extends SmrtError {
47
+ readonly result: FailedFusionRun;
48
+ constructor(result: FailedFusionRun, cause?: unknown);
49
+ }
50
+ export {};
51
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AAChE,OAAO,KAAK,EACV,oBAAoB,EACpB,qBAAqB,EACrB,2BAA2B,EAC5B,MAAM,YAAY,CAAC;AAEpB,iFAAiF;AACjF,qBAAa,oBAAqB,SAAQ,SAAS;IACjD,QAAQ,CAAC,MAAM,EAAE,oBAAoB,EAAE,CAAC;gBAE5B,MAAM,EAAE,oBAAoB,EAAE;CAS3C;AAED;;;;GAIG;AACH,qBAAa,uBAAwB,SAAQ,SAAS;IACpD,uCAAuC;IACvC,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAC;IAC7C,uDAAuD;IACvD,QAAQ,CAAC,aAAa,EAAE,qBAAqB,EAAE,CAAC;IAChD,mEAAmE;IACnE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;gBAElB,KAAK,EAAE;QACjB,MAAM,EAAE,2BAA2B,CAAC;QACpC,aAAa,EAAE,qBAAqB,EAAE,CAAC;QACvC,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB;CAmBF;AAED,yEAAyE;AACzE,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC;KAC/C,CAAC,CAAC;CACJ;AAED;;;;GAIG;AACH,qBAAa,oBAAqB,SAAQ,SAAS;IACjD,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;gBAErB,MAAM,EAAE,eAAe,EAAE,KAAK,CAAC,EAAE,OAAO;CAerD"}