@open-mercato/ai-assistant 0.6.8-develop.6891.1.4dca3f1ad3 → 0.6.8-develop.6892.1.f179677788

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/ai_assistant/lib/ai-overrides.ts"],
4
- "sourcesContent": ["import { createLogger } from '@open-mercato/shared/lib/logger'\nimport {\n registerModuleOverrideApplier,\n type ModuleOverrideEntry,\n} from '@open-mercato/shared/modules/overrides'\n\n/**\n * Module-to-module override pipeline for AI agents and AI tools.\n *\n * Modules contribute overrides through two surfaces:\n *\n * 1. Per-module: declare additional `aiAgentOverrides` / `aiToolOverrides`\n * exports in the existing `<module>/ai-agents.ts` / `<module>/ai-tools.ts`\n * files (no separate `ai-overrides.ts` file). The generator picks the\n * exports up alongside `aiAgents` / `aiTools` and emits override entries\n * inside `apps/<app>/.mercato/generated/ai-agents.generated.ts`\n * (`aiAgentOverrideEntries`) and `ai-tools.generated.ts`\n * (`aiToolOverrideEntries`).\n *\n * 2. App-level: declare `aiAgentOverrides` / `aiToolOverrides` directly on a\n * `ModuleEntry` inside the app's `src/modules.ts`. {@link\n * applyAiOverridesFromEnabledModules} feeds these into the runtime; they\n * sit one tier higher than the per-module file-based entries but below\n * explicit programmatic calls.\n *\n * Tests and bootstrap code can also override imperatively via\n * {@link applyAiAgentOverrides} and {@link applyAiToolOverrides}, which\n * supersede every other tier and persist for the process lifetime.\n *\n * `null` always means \"remove from the registry\"; a definition replaces.\n *\n * @see ../../../../../../.ai/specs/implemented/2026-04-30-ai-overrides-and-module-disable.md\n */\nimport type { AiAgentDefinition, AiAgentExtension } from './ai-agent-definition'\nimport type { AiToolDefinition } from './types'\n\nconst logger = createLogger('ai_assistant')\n\n/** Override for a single agent: replace with a definition or remove with `null`. */\nexport type AiAgentOverride = AiAgentDefinition | null\n\n/** Override for a single tool: replace with a definition or remove with `null`. */\nexport type AiToolOverride = AiToolDefinition | null\n\n/** Map of agent id \u2192 override. Used in the per-module `ai-agents.ts` file. */\nexport type AiAgentOverridesMap = Record<string, AiAgentOverride>\n\n/** Map of tool name \u2192 override. Used in the per-module `ai-tools.ts` file. */\nexport type AiToolOverridesMap = Record<string, AiToolOverride>\n\n/**\n * Per-entry shape produced by the agent generator. Mirrors the per-module\n * record format used elsewhere in the registry generators so the file\n * stays grep-friendly.\n */\nexport interface AiAgentOverrideConfigEntry {\n moduleId: string\n overrides: AiAgentOverridesMap\n}\n\nexport interface AiAgentExtensionConfigEntry {\n moduleId: string\n extensions: AiAgentExtension[]\n}\n\n/**\n * Per-entry shape produced by the tool generator. Same record format as\n * {@link AiAgentOverrideConfigEntry}, but with tool definitions.\n */\nexport interface AiToolOverrideConfigEntry {\n moduleId: string\n overrides: AiToolOverridesMap\n}\n\n/** Shape of the `entry.overrides.ai` sub-tree on a `modules.ts` entry. */\nexport interface AiModuleOverridesShape {\n agents?: AiAgentOverridesMap\n tools?: AiToolOverridesMap\n extensions?: AiAgentExtension[]\n}\n\n/** Shape of a `modules.ts` `ModuleEntry` with the umbrella `overrides.ai`. */\nexport interface EnabledModuleAiOverrides {\n id: string\n overrides?: { ai?: AiModuleOverridesShape }\n}\n\nconst programmaticAgentOverrides: AiAgentOverridesMap = {}\nconst programmaticToolOverrides: AiToolOverridesMap = {}\nconst programmaticAgentExtensions: AiAgentExtension[] = []\n\nconst modulesConfigAgentOverrides: AiAgentOverridesMap = {}\nconst modulesConfigToolOverrides: AiToolOverridesMap = {}\nconst modulesConfigAgentExtensions: AiAgentExtension[] = []\n\n/**\n * Apply programmatic agent overrides \u2014 survive after the registries load\n * and take precedence over both file-based and `modules.ts`-tier overrides\n * for the same id.\n *\n * @example\n * ```ts\n * applyAiAgentOverrides({\n * 'catalog.catalog_assistant': null, // disable\n * 'catalog.merchandising_assistant': customAgent, // replace\n * })\n * ```\n */\nexport function applyAiAgentOverrides(overrides: AiAgentOverridesMap): void {\n for (const [id, value] of Object.entries(overrides)) {\n programmaticAgentOverrides[id] = value\n }\n}\n\n/**\n * Apply programmatic tool overrides \u2014 survive after the registries load\n * and take precedence over both file-based and `modules.ts`-tier overrides\n * for the same name.\n */\nexport function applyAiToolOverrides(overrides: AiToolOverridesMap): void {\n for (const [name, value] of Object.entries(overrides)) {\n programmaticToolOverrides[name] = value\n }\n}\n\n/**\n * Apply programmatic additive agent extensions. Extensions append to an\n * already-registered agent after replacements/disable overrides resolve.\n */\nexport function applyAiAgentExtensions(extensions: readonly AiAgentExtension[]): void {\n programmaticAgentExtensions.push(...extensions)\n}\n\n/**\n * Walk a list of `enabledModules` entries (the `apps/<app>/src/modules.ts`\n * shape) and register their `overrides.ai.agents` / `overrides.ai.tools`\n * into the `modules.ts` tier. Tier precedence (highest first):\n *\n * 1. {@link applyAiAgentOverrides} / {@link applyAiToolOverrides}\n * 2. `modules.ts` inline (this function)\n * 3. `<module>/ai-agents.ts` `aiAgentOverrides` / `<module>/ai-tools.ts`\n * `aiToolOverrides`\n * 4. base `aiAgents` / `aiTools`\n *\n * Calling this multiple times is additive: later calls overlay on the\n * existing tier (last wins per id). Use only at boot time \u2014 re-entering\n * mid-request blurs the resolution order.\n *\n * In practice this is invoked from `applyModuleOverridesFromEnabledModules`\n * (the umbrella dispatcher in `@open-mercato/shared/modules/overrides`)\n * via the registered `'ai'` applier; downstream apps call the dispatcher\n * once from `bootstrap.ts`. The standalone signature is kept for tests\n * and ad-hoc use.\n */\nexport function applyAiOverridesFromEnabledModules(\n modules: ReadonlyArray<EnabledModuleAiOverrides>,\n): void {\n for (const entry of modules) {\n if (!entry || typeof entry.id !== 'string' || !entry.id) continue\n const ai = entry.overrides?.ai\n if (!ai || typeof ai !== 'object') continue\n if (ai.agents && typeof ai.agents === 'object') {\n for (const [id, value] of Object.entries(ai.agents)) {\n modulesConfigAgentOverrides[id] = value as AiAgentOverride\n }\n }\n if (ai.tools && typeof ai.tools === 'object') {\n for (const [name, value] of Object.entries(ai.tools)) {\n modulesConfigToolOverrides[name] = value as AiToolOverride\n }\n }\n if (Array.isArray(ai.extensions)) {\n modulesConfigAgentExtensions.push(...ai.extensions)\n }\n }\n}\n\n/**\n * Bucketed entry shape passed to the umbrella dispatcher's per-domain\n * applier. Each entry carries one module's `overrides.ai` sub-tree.\n */\ntype AiOverrideEntryFromDispatcher = {\n moduleId: string\n overrides: AiModuleOverridesShape\n}\n\n/**\n * Applier registered with `@open-mercato/shared/modules/overrides` for\n * the `'ai'` domain. The dispatcher hands us per-module entries already\n * scoped to `overrides.ai`; we re-shape into `EnabledModuleAiOverrides`\n * and reuse {@link applyAiOverridesFromEnabledModules} so the AI tier\n * has exactly one code path.\n */\nexport function applyAiOverridesDispatcherEntries(\n entries: ReadonlyArray<AiOverrideEntryFromDispatcher>,\n): void {\n applyAiOverridesFromEnabledModules(\n entries.map((entry) => ({\n id: entry.moduleId,\n overrides: { ai: entry.overrides },\n })),\n )\n}\n\n// Side-effect: register the `'ai'` applier on first module load so the\n// umbrella dispatcher in `@open-mercato/shared/modules/overrides` can\n// route `entry.overrides.ai` here. Any consumer that imports\n// `@open-mercato/ai-assistant` (which apps do via `bootstrap.ts`) gets\n// the registration for free \u2014 no second import needed.\nregisterModuleOverrideApplier<AiModuleOverridesShape>(\n 'ai',\n (entries: ReadonlyArray<ModuleOverrideEntry<AiModuleOverridesShape>>) => {\n applyAiOverridesDispatcherEntries(entries)\n },\n)\n\n/** @__internal Test-only hook \u2014 reset programmatic + modules.ts override state. */\nexport function resetProgrammaticOverridesForTests(): void {\n for (const key of Object.keys(programmaticAgentOverrides)) {\n delete programmaticAgentOverrides[key]\n }\n for (const key of Object.keys(programmaticToolOverrides)) {\n delete programmaticToolOverrides[key]\n }\n for (const key of Object.keys(modulesConfigAgentOverrides)) {\n delete modulesConfigAgentOverrides[key]\n }\n for (const key of Object.keys(modulesConfigToolOverrides)) {\n delete modulesConfigToolOverrides[key]\n }\n programmaticAgentExtensions.length = 0\n modulesConfigAgentExtensions.length = 0\n}\n\n/**\n * Resolve the final agent override map from a list of file-based entries\n * plus the `modules.ts` and programmatic state.\n *\n * Resolution order (lowest precedence \u2192 highest):\n * 1. file entries in module load order\n * 2. modules.ts entries\n * 3. programmatic\n */\nexport function composeAgentOverrideMap(\n fileEntries: readonly AiAgentOverrideConfigEntry[],\n): AiAgentOverridesMap {\n const out: AiAgentOverridesMap = {}\n for (const entry of fileEntries) {\n const overrides = entry?.overrides\n if (!overrides || typeof overrides !== 'object') continue\n for (const [id, value] of Object.entries(overrides)) {\n if (typeof id !== 'string' || !id) continue\n out[id] = value as AiAgentOverride\n }\n }\n for (const [id, value] of Object.entries(modulesConfigAgentOverrides)) {\n out[id] = value\n }\n for (const [id, value] of Object.entries(programmaticAgentOverrides)) {\n out[id] = value\n }\n return out\n}\n\n/**\n * Resolve the final tool override map from a list of file-based entries\n * plus the `modules.ts` and programmatic state.\n */\nexport function composeToolOverrideMap(\n fileEntries: readonly AiToolOverrideConfigEntry[],\n): AiToolOverridesMap {\n const out: AiToolOverridesMap = {}\n for (const entry of fileEntries) {\n const overrides = entry?.overrides\n if (!overrides || typeof overrides !== 'object') continue\n for (const [name, value] of Object.entries(overrides)) {\n if (typeof name !== 'string' || !name) continue\n out[name] = value as AiToolOverride\n }\n }\n for (const [name, value] of Object.entries(modulesConfigToolOverrides)) {\n out[name] = value\n }\n for (const [name, value] of Object.entries(programmaticToolOverrides)) {\n out[name] = value\n }\n return out\n}\n\nexport function composeAgentExtensionEntries(\n fileEntries: readonly AiAgentExtensionConfigEntry[],\n): AiAgentExtension[] {\n const out: AiAgentExtension[] = []\n for (const entry of fileEntries) {\n if (Array.isArray(entry?.extensions)) out.push(...entry.extensions)\n }\n out.push(...modulesConfigAgentExtensions)\n out.push(...programmaticAgentExtensions)\n return out\n}\n\n/**\n * Apply an agent override map to a base list. Returns a new array.\n * `null` removes the entry; a non-null override replaces it. Override\n * entries naming an id that is not in `base` log a structured warning so\n * an operator can spot stale override files.\n */\nexport function applyAgentOverrideMap(\n base: readonly AiAgentDefinition[],\n overrides: AiAgentOverridesMap,\n): AiAgentDefinition[] {\n if (!overrides || Object.keys(overrides).length === 0) return base.slice()\n const byId = new Map<string, AiAgentDefinition>()\n for (const agent of base) {\n if (agent && typeof agent.id === 'string' && agent.id) {\n byId.set(agent.id, agent)\n }\n }\n for (const [id, value] of Object.entries(overrides)) {\n if (!byId.has(id) && value !== null) {\n // Allow registering a brand-new agent through the override surface\n // \u2014 useful for app-level \"synthetic\" agents without authoring a\n // module file. Warn at the structured logger so the operator\n // notices a stale id slipping through.\n logger.warn('Override registers a new agent \u2014 no base entry to replace', { agentId: id })\n }\n if (value === null) {\n byId.delete(id)\n continue\n }\n if (!value || typeof value.id !== 'string' || value.id !== id) {\n logger.warn('Skipping malformed agent override \u2014 id mismatch or missing fields', { agentId: id })\n continue\n }\n byId.set(id, value)\n }\n return Array.from(byId.values())\n}\n\n/**\n * Apply a tool override map to a base map. Returns a new Map.\n * `null` removes the entry; a non-null override replaces it.\n */\nexport function applyToolOverrideMap<TTool extends { name: string }>(\n base: ReadonlyMap<string, TTool>,\n overrides: Record<string, TTool | null | undefined>,\n): Map<string, TTool> {\n const out = new Map<string, TTool>(base)\n if (!overrides) return out\n for (const [name, value] of Object.entries(overrides)) {\n if (value === null) {\n out.delete(name)\n continue\n }\n if (value === undefined) continue\n if (!value || typeof (value as TTool).name !== 'string' || (value as TTool).name !== name) {\n logger.warn('Skipping malformed tool override \u2014 name mismatch or missing fields', { toolName: name })\n continue\n }\n out.set(name, value as TTool)\n }\n return out\n}\n\n/**\n * @__internal \u2014 read the snapshot of programmatic + modules.ts overrides.\n * Used by tests and by the diagnostic helper that reports which overrides\n * are in effect.\n */\nexport function snapshotProgrammaticOverrides(): {\n agents: Readonly<AiAgentOverridesMap>\n tools: Readonly<AiToolOverridesMap>\n modulesConfigAgents: Readonly<AiAgentOverridesMap>\n modulesConfigTools: Readonly<AiToolOverridesMap>\n agentExtensions: readonly AiAgentExtension[]\n modulesConfigAgentExtensions: readonly AiAgentExtension[]\n} {\n return {\n agents: { ...programmaticAgentOverrides },\n tools: { ...programmaticToolOverrides },\n modulesConfigAgents: { ...modulesConfigAgentOverrides },\n modulesConfigTools: { ...modulesConfigToolOverrides },\n agentExtensions: programmaticAgentExtensions.slice(),\n modulesConfigAgentExtensions: modulesConfigAgentExtensions.slice(),\n }\n}\n"],
4
+ "sourcesContent": ["import { createLogger } from '@open-mercato/shared/lib/logger'\nimport {\n registerModuleOverrideApplier,\n type ModuleOverrideEntry,\n} from '@open-mercato/shared/modules/overrides'\n\n/**\n * Module-to-module override pipeline for AI agents and AI tools.\n *\n * Modules contribute overrides through two surfaces:\n *\n * 1. Per-module: declare additional `aiAgentOverrides` / `aiToolOverrides`\n * exports in the existing `<module>/ai-agents.ts` / `<module>/ai-tools.ts`\n * files (no separate `ai-overrides.ts` file). The generator picks the\n * exports up alongside `aiAgents` / `aiTools` and emits override entries\n * inside `apps/<app>/.mercato/generated/ai-agents.generated.ts`\n * (`aiAgentOverrideEntries`) and `ai-tools.generated.ts`\n * (`aiToolOverrideEntries`).\n *\n * 2. App-level: declare `aiAgentOverrides` / `aiToolOverrides` directly on a\n * `ModuleEntry` inside the app's `src/modules.ts`. {@link\n * applyAiOverridesFromEnabledModules} feeds these into the runtime; they\n * sit one tier higher than the per-module file-based entries but below\n * explicit programmatic calls.\n *\n * Tests and bootstrap code can also override imperatively via\n * {@link applyAiAgentOverrides} and {@link applyAiToolOverrides}, which\n * supersede every other tier and persist for the process lifetime.\n *\n * `null` always means \"remove from the registry\"; a definition replaces.\n *\n * @see ../../../../../../.ai/specs/implemented/2026-04-30-ai-overrides-and-module-disable.md\n */\nimport type { AiAgentDefinition, AiAgentExtension } from './ai-agent-definition'\nimport type { AiToolDefinition } from './types'\n\nconst logger = createLogger('ai_assistant')\n\n/** Override for a single agent: replace with a definition or remove with `null`. */\nexport type AiAgentOverride = AiAgentDefinition | null\n\n/** Override for a single tool: replace with a definition or remove with `null`. */\nexport type AiToolOverride = AiToolDefinition | null\n\n/** Map of agent id \u2192 override. Used in the per-module `ai-agents.ts` file. */\nexport type AiAgentOverridesMap = Record<string, AiAgentOverride>\n\n/** Map of tool name \u2192 override. Used in the per-module `ai-tools.ts` file. */\nexport type AiToolOverridesMap = Record<string, AiToolOverride>\n\n/**\n * Per-entry shape produced by the agent generator. Mirrors the per-module\n * record format used elsewhere in the registry generators so the file\n * stays grep-friendly.\n */\nexport interface AiAgentOverrideConfigEntry {\n moduleId: string\n overrides: AiAgentOverridesMap\n}\n\nexport interface AiAgentExtensionConfigEntry {\n moduleId: string\n extensions: AiAgentExtension[]\n}\n\n/**\n * Per-entry shape produced by the tool generator. Same record format as\n * {@link AiAgentOverrideConfigEntry}, but with tool definitions.\n */\nexport interface AiToolOverrideConfigEntry {\n moduleId: string\n overrides: AiToolOverridesMap\n}\n\n/** Shape of the `entry.overrides.ai` sub-tree on a `modules.ts` entry. */\nexport interface AiModuleOverridesShape {\n agents?: AiAgentOverridesMap\n tools?: AiToolOverridesMap\n extensions?: AiAgentExtension[]\n}\n\n/** Shape of a `modules.ts` `ModuleEntry` with the umbrella `overrides.ai`. */\nexport interface EnabledModuleAiOverrides {\n id: string\n overrides?: { ai?: AiModuleOverridesShape }\n}\n\nconst programmaticAgentOverrides: AiAgentOverridesMap = {}\nconst programmaticToolOverrides: AiToolOverridesMap = {}\nconst programmaticAgentExtensions: AiAgentExtension[] = []\n\nconst modulesConfigAgentOverrides: AiAgentOverridesMap = {}\nconst modulesConfigToolOverrides: AiToolOverridesMap = {}\nconst modulesConfigAgentExtensions: AiAgentExtension[] = []\n\n/**\n * Apply programmatic agent overrides \u2014 survive after the registries load\n * and take precedence over both file-based and `modules.ts`-tier overrides\n * for the same id.\n *\n * @example\n * ```ts\n * applyAiAgentOverrides({\n * 'catalog.catalog_assistant': null, // disable\n * 'catalog.merchandising_assistant': customAgent, // replace\n * })\n * ```\n */\nexport function applyAiAgentOverrides(overrides: AiAgentOverridesMap): void {\n for (const [id, value] of Object.entries(overrides)) {\n programmaticAgentOverrides[id] = value\n }\n}\n\n/**\n * Apply programmatic tool overrides \u2014 survive after the registries load\n * and take precedence over both file-based and `modules.ts`-tier overrides\n * for the same name.\n */\nexport function applyAiToolOverrides(overrides: AiToolOverridesMap): void {\n for (const [name, value] of Object.entries(overrides)) {\n programmaticToolOverrides[name] = value\n }\n}\n\n/**\n * Apply programmatic additive agent extensions. Extensions append to an\n * already-registered agent after replacements/disable overrides resolve.\n */\nexport function applyAiAgentExtensions(extensions: readonly AiAgentExtension[]): void {\n programmaticAgentExtensions.push(...extensions)\n}\n\n/**\n * Walk a list of `enabledModules` entries (the `apps/<app>/src/modules.ts`\n * shape) and register their `overrides.ai.agents` / `overrides.ai.tools`\n * into the `modules.ts` tier. Tier precedence (highest first):\n *\n * 1. {@link applyAiAgentOverrides} / {@link applyAiToolOverrides}\n * 2. `modules.ts` inline (this function)\n * 3. `<module>/ai-agents.ts` `aiAgentOverrides` / `<module>/ai-tools.ts`\n * `aiToolOverrides`\n * 4. base `aiAgents` / `aiTools`\n *\n * Calling this multiple times is additive: later calls overlay on the\n * existing tier (last wins per id). Use only at boot time \u2014 re-entering\n * mid-request blurs the resolution order.\n *\n * In practice this is invoked from `applyModuleOverridesFromEnabledModules`\n * (the umbrella dispatcher in `@open-mercato/shared/modules/overrides`)\n * via the registered `'ai'` applier; downstream apps call the dispatcher\n * once from `bootstrap.ts`. The standalone signature is kept for tests\n * and ad-hoc use.\n */\nexport function applyAiOverridesFromEnabledModules(\n modules: ReadonlyArray<EnabledModuleAiOverrides>,\n): void {\n for (const entry of modules) {\n if (!entry || typeof entry.id !== 'string' || !entry.id) continue\n const ai = entry.overrides?.ai\n if (!ai || typeof ai !== 'object') continue\n if (ai.agents && typeof ai.agents === 'object') {\n for (const [id, value] of Object.entries(ai.agents)) {\n modulesConfigAgentOverrides[id] = value as AiAgentOverride\n }\n }\n if (ai.tools && typeof ai.tools === 'object') {\n for (const [name, value] of Object.entries(ai.tools)) {\n modulesConfigToolOverrides[name] = value as AiToolOverride\n }\n }\n if (Array.isArray(ai.extensions)) {\n modulesConfigAgentExtensions.push(...ai.extensions)\n }\n }\n}\n\n/**\n * Bucketed entry shape passed to the umbrella dispatcher's per-domain\n * applier. Each entry carries one module's `overrides.ai` sub-tree.\n */\ntype AiOverrideEntryFromDispatcher = {\n moduleId: string\n overrides: AiModuleOverridesShape\n}\n\n/**\n * Applier registered with `@open-mercato/shared/modules/overrides` for\n * the `'ai'` domain. The dispatcher hands us per-module entries already\n * scoped to `overrides.ai`; we re-shape into `EnabledModuleAiOverrides`\n * and reuse {@link applyAiOverridesFromEnabledModules} so the AI tier\n * has exactly one code path.\n */\nexport function applyAiOverridesDispatcherEntries(\n entries: ReadonlyArray<AiOverrideEntryFromDispatcher>,\n): void {\n applyAiOverridesFromEnabledModules(\n entries.map((entry) => ({\n id: entry.moduleId,\n overrides: { ai: entry.overrides },\n })),\n )\n}\n\n// Side-effect: register the `'ai'` applier on first module load so the\n// umbrella dispatcher in `@open-mercato/shared/modules/overrides` can\n// route `entry.overrides.ai` here. Apps import this focused module from\n// `bootstrap-common.ts` so they register the applier without tracing the\n// package's MCP/provider umbrella into every server runtime.\nregisterModuleOverrideApplier<AiModuleOverridesShape>(\n 'ai',\n (entries: ReadonlyArray<ModuleOverrideEntry<AiModuleOverridesShape>>) => {\n applyAiOverridesDispatcherEntries(entries)\n },\n)\n\n/** @__internal Test-only hook \u2014 reset programmatic + modules.ts override state. */\nexport function resetProgrammaticOverridesForTests(): void {\n for (const key of Object.keys(programmaticAgentOverrides)) {\n delete programmaticAgentOverrides[key]\n }\n for (const key of Object.keys(programmaticToolOverrides)) {\n delete programmaticToolOverrides[key]\n }\n for (const key of Object.keys(modulesConfigAgentOverrides)) {\n delete modulesConfigAgentOverrides[key]\n }\n for (const key of Object.keys(modulesConfigToolOverrides)) {\n delete modulesConfigToolOverrides[key]\n }\n programmaticAgentExtensions.length = 0\n modulesConfigAgentExtensions.length = 0\n}\n\n/**\n * Resolve the final agent override map from a list of file-based entries\n * plus the `modules.ts` and programmatic state.\n *\n * Resolution order (lowest precedence \u2192 highest):\n * 1. file entries in module load order\n * 2. modules.ts entries\n * 3. programmatic\n */\nexport function composeAgentOverrideMap(\n fileEntries: readonly AiAgentOverrideConfigEntry[],\n): AiAgentOverridesMap {\n const out: AiAgentOverridesMap = {}\n for (const entry of fileEntries) {\n const overrides = entry?.overrides\n if (!overrides || typeof overrides !== 'object') continue\n for (const [id, value] of Object.entries(overrides)) {\n if (typeof id !== 'string' || !id) continue\n out[id] = value as AiAgentOverride\n }\n }\n for (const [id, value] of Object.entries(modulesConfigAgentOverrides)) {\n out[id] = value\n }\n for (const [id, value] of Object.entries(programmaticAgentOverrides)) {\n out[id] = value\n }\n return out\n}\n\n/**\n * Resolve the final tool override map from a list of file-based entries\n * plus the `modules.ts` and programmatic state.\n */\nexport function composeToolOverrideMap(\n fileEntries: readonly AiToolOverrideConfigEntry[],\n): AiToolOverridesMap {\n const out: AiToolOverridesMap = {}\n for (const entry of fileEntries) {\n const overrides = entry?.overrides\n if (!overrides || typeof overrides !== 'object') continue\n for (const [name, value] of Object.entries(overrides)) {\n if (typeof name !== 'string' || !name) continue\n out[name] = value as AiToolOverride\n }\n }\n for (const [name, value] of Object.entries(modulesConfigToolOverrides)) {\n out[name] = value\n }\n for (const [name, value] of Object.entries(programmaticToolOverrides)) {\n out[name] = value\n }\n return out\n}\n\nexport function composeAgentExtensionEntries(\n fileEntries: readonly AiAgentExtensionConfigEntry[],\n): AiAgentExtension[] {\n const out: AiAgentExtension[] = []\n for (const entry of fileEntries) {\n if (Array.isArray(entry?.extensions)) out.push(...entry.extensions)\n }\n out.push(...modulesConfigAgentExtensions)\n out.push(...programmaticAgentExtensions)\n return out\n}\n\n/**\n * Apply an agent override map to a base list. Returns a new array.\n * `null` removes the entry; a non-null override replaces it. Override\n * entries naming an id that is not in `base` log a structured warning so\n * an operator can spot stale override files.\n */\nexport function applyAgentOverrideMap(\n base: readonly AiAgentDefinition[],\n overrides: AiAgentOverridesMap,\n): AiAgentDefinition[] {\n if (!overrides || Object.keys(overrides).length === 0) return base.slice()\n const byId = new Map<string, AiAgentDefinition>()\n for (const agent of base) {\n if (agent && typeof agent.id === 'string' && agent.id) {\n byId.set(agent.id, agent)\n }\n }\n for (const [id, value] of Object.entries(overrides)) {\n if (!byId.has(id) && value !== null) {\n // Allow registering a brand-new agent through the override surface\n // \u2014 useful for app-level \"synthetic\" agents without authoring a\n // module file. Warn at the structured logger so the operator\n // notices a stale id slipping through.\n logger.warn('Override registers a new agent \u2014 no base entry to replace', { agentId: id })\n }\n if (value === null) {\n byId.delete(id)\n continue\n }\n if (!value || typeof value.id !== 'string' || value.id !== id) {\n logger.warn('Skipping malformed agent override \u2014 id mismatch or missing fields', { agentId: id })\n continue\n }\n byId.set(id, value)\n }\n return Array.from(byId.values())\n}\n\n/**\n * Apply a tool override map to a base map. Returns a new Map.\n * `null` removes the entry; a non-null override replaces it.\n */\nexport function applyToolOverrideMap<TTool extends { name: string }>(\n base: ReadonlyMap<string, TTool>,\n overrides: Record<string, TTool | null | undefined>,\n): Map<string, TTool> {\n const out = new Map<string, TTool>(base)\n if (!overrides) return out\n for (const [name, value] of Object.entries(overrides)) {\n if (value === null) {\n out.delete(name)\n continue\n }\n if (value === undefined) continue\n if (!value || typeof (value as TTool).name !== 'string' || (value as TTool).name !== name) {\n logger.warn('Skipping malformed tool override \u2014 name mismatch or missing fields', { toolName: name })\n continue\n }\n out.set(name, value as TTool)\n }\n return out\n}\n\n/**\n * @__internal \u2014 read the snapshot of programmatic + modules.ts overrides.\n * Used by tests and by the diagnostic helper that reports which overrides\n * are in effect.\n */\nexport function snapshotProgrammaticOverrides(): {\n agents: Readonly<AiAgentOverridesMap>\n tools: Readonly<AiToolOverridesMap>\n modulesConfigAgents: Readonly<AiAgentOverridesMap>\n modulesConfigTools: Readonly<AiToolOverridesMap>\n agentExtensions: readonly AiAgentExtension[]\n modulesConfigAgentExtensions: readonly AiAgentExtension[]\n} {\n return {\n agents: { ...programmaticAgentOverrides },\n tools: { ...programmaticToolOverrides },\n modulesConfigAgents: { ...modulesConfigAgentOverrides },\n modulesConfigTools: { ...modulesConfigToolOverrides },\n agentExtensions: programmaticAgentExtensions.slice(),\n modulesConfigAgentExtensions: modulesConfigAgentExtensions.slice(),\n }\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/ai-assistant",
3
- "version": "0.6.8-develop.6891.1.4dca3f1ad3",
3
+ "version": "0.6.8-develop.6892.1.f179677788",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "engines": {
@@ -99,16 +99,16 @@
99
99
  "zod-to-json-schema": "^3.25.2"
100
100
  },
101
101
  "peerDependencies": {
102
- "@open-mercato/shared": "0.6.8-develop.6891.1.4dca3f1ad3",
103
- "@open-mercato/ui": "0.6.8-develop.6891.1.4dca3f1ad3",
102
+ "@open-mercato/shared": "0.6.8-develop.6892.1.f179677788",
103
+ "@open-mercato/ui": "0.6.8-develop.6892.1.f179677788",
104
104
  "react": "^19.0.0",
105
105
  "react-dom": "^19.0.0",
106
106
  "zod": ">=3.23.0"
107
107
  },
108
108
  "devDependencies": {
109
- "@open-mercato/cli": "0.6.8-develop.6891.1.4dca3f1ad3",
110
- "@open-mercato/shared": "0.6.8-develop.6891.1.4dca3f1ad3",
111
- "@open-mercato/ui": "0.6.8-develop.6891.1.4dca3f1ad3",
109
+ "@open-mercato/cli": "0.6.8-develop.6892.1.f179677788",
110
+ "@open-mercato/shared": "0.6.8-develop.6892.1.f179677788",
111
+ "@open-mercato/ui": "0.6.8-develop.6892.1.f179677788",
112
112
  "@types/react": "^19.2.17",
113
113
  "@types/react-dom": "^19.2.3",
114
114
  "react": "19.2.8",
@@ -204,9 +204,9 @@ export function applyAiOverridesDispatcherEntries(
204
204
 
205
205
  // Side-effect: register the `'ai'` applier on first module load so the
206
206
  // umbrella dispatcher in `@open-mercato/shared/modules/overrides` can
207
- // route `entry.overrides.ai` here. Any consumer that imports
208
- // `@open-mercato/ai-assistant` (which apps do via `bootstrap.ts`) gets
209
- // the registration for free — no second import needed.
207
+ // route `entry.overrides.ai` here. Apps import this focused module from
208
+ // `bootstrap-common.ts` so they register the applier without tracing the
209
+ // package's MCP/provider umbrella into every server runtime.
210
210
  registerModuleOverrideApplier<AiModuleOverridesShape>(
211
211
  'ai',
212
212
  (entries: ReadonlyArray<ModuleOverrideEntry<AiModuleOverridesShape>>) => {