@open-mercato/ai-assistant 0.6.5-develop.5337.1.534b781eac → 0.6.5

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 (82) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +14 -2
  3. package/README.md +1 -1
  4. package/dist/modules/ai_assistant/ai-tools/meta-pack.js +3 -1
  5. package/dist/modules/ai_assistant/ai-tools/meta-pack.js.map +2 -2
  6. package/dist/modules/ai_assistant/api/mcp-key/route.js +95 -0
  7. package/dist/modules/ai_assistant/api/mcp-key/route.js.map +7 -0
  8. package/dist/modules/ai_assistant/cli.js +14 -6
  9. package/dist/modules/ai_assistant/cli.js.map +2 -2
  10. package/dist/modules/ai_assistant/components/McpConfigDialog.js +1 -1
  11. package/dist/modules/ai_assistant/components/McpConfigDialog.js.map +2 -2
  12. package/dist/modules/ai_assistant/data/entities.js +4 -0
  13. package/dist/modules/ai_assistant/data/entities.js.map +2 -2
  14. package/dist/modules/ai_assistant/lib/ai-api-operation-runner.js +3 -1
  15. package/dist/modules/ai_assistant/lib/ai-api-operation-runner.js.map +2 -2
  16. package/dist/modules/ai_assistant/lib/ai-overrides.js.map +1 -1
  17. package/dist/modules/ai_assistant/lib/ai-sdk.js.map +1 -1
  18. package/dist/modules/ai_assistant/lib/attachment-parts.js +10 -3
  19. package/dist/modules/ai_assistant/lib/attachment-parts.js.map +2 -2
  20. package/dist/modules/ai_assistant/lib/chat-config.js.map +1 -1
  21. package/dist/modules/ai_assistant/lib/client-factory.js +0 -8
  22. package/dist/modules/ai_assistant/lib/client-factory.js.map +2 -2
  23. package/dist/modules/ai_assistant/lib/codemode-tools.js +26 -0
  24. package/dist/modules/ai_assistant/lib/codemode-tools.js.map +2 -2
  25. package/dist/modules/ai_assistant/lib/generated-registry-loader.js +23 -3
  26. package/dist/modules/ai_assistant/lib/generated-registry-loader.js.map +2 -2
  27. package/dist/modules/ai_assistant/lib/llm-adapters/anthropic.js.map +1 -1
  28. package/dist/modules/ai_assistant/lib/llm-adapters/google.js.map +1 -1
  29. package/dist/modules/ai_assistant/lib/llm-adapters/openai.js.map +1 -1
  30. package/dist/modules/ai_assistant/lib/llm-bootstrap.js.map +1 -1
  31. package/dist/modules/ai_assistant/lib/mcp-client.js +2 -4
  32. package/dist/modules/ai_assistant/lib/mcp-client.js.map +2 -2
  33. package/dist/modules/ai_assistant/lib/mcp-dev-key-resolution.js +71 -0
  34. package/dist/modules/ai_assistant/lib/mcp-dev-key-resolution.js.map +7 -0
  35. package/dist/modules/ai_assistant/lib/mcp-dev-server.js +1 -30
  36. package/dist/modules/ai_assistant/lib/mcp-dev-server.js.map +2 -2
  37. package/dist/modules/ai_assistant/lib/mcp-server.js +29 -23
  38. package/dist/modules/ai_assistant/lib/mcp-server.js.map +2 -2
  39. package/dist/modules/ai_assistant/lib/openai-compatible-presets.js.map +1 -1
  40. package/dist/modules/ai_assistant/lib/task-plan-stream.js.map +1 -1
  41. package/dist/modules/ai_assistant/setup.js +9 -2
  42. package/dist/modules/ai_assistant/setup.js.map +2 -2
  43. package/package.json +11 -12
  44. package/src/modules/ai_assistant/__tests__/cli-mcp-serve-key.test.ts +63 -0
  45. package/src/modules/ai_assistant/__tests__/setup-schedules.test.ts +33 -0
  46. package/src/modules/ai_assistant/ai-tools/__tests__/meta-pack.test.ts +29 -0
  47. package/src/modules/ai_assistant/ai-tools/meta-pack.ts +7 -1
  48. package/src/modules/ai_assistant/api/mcp-key/__tests__/route.test.ts +144 -0
  49. package/src/modules/ai_assistant/api/mcp-key/route.ts +125 -0
  50. package/src/modules/ai_assistant/cli.ts +18 -5
  51. package/src/modules/ai_assistant/components/McpConfigDialog.tsx +5 -1
  52. package/src/modules/ai_assistant/data/__tests__/schema-unique-indexes.test.ts +39 -0
  53. package/src/modules/ai_assistant/data/entities.ts +5 -0
  54. package/src/modules/ai_assistant/lib/__tests__/ai-overrides.test.ts +1 -1
  55. package/src/modules/ai_assistant/lib/__tests__/attachment-parts.test.ts +112 -0
  56. package/src/modules/ai_assistant/lib/__tests__/client-factory.test.ts +42 -0
  57. package/src/modules/ai_assistant/lib/__tests__/codemode-tools.test.ts +107 -0
  58. package/src/modules/ai_assistant/lib/__tests__/generated-registry-loader.test.ts +30 -3
  59. package/src/modules/ai_assistant/lib/__tests__/mcp-client.test.ts +20 -1
  60. package/src/modules/ai_assistant/lib/__tests__/mcp-dev-key-resolution.test.ts +92 -0
  61. package/src/modules/ai_assistant/lib/__tests__/mcp-server-auth-fail-closed.test.ts +133 -0
  62. package/src/modules/ai_assistant/lib/__tests__/task-plan-stream.test.ts +1 -1
  63. package/src/modules/ai_assistant/lib/ai-api-operation-runner.ts +9 -0
  64. package/src/modules/ai_assistant/lib/ai-overrides.ts +1 -1
  65. package/src/modules/ai_assistant/lib/ai-sdk.ts +1 -1
  66. package/src/modules/ai_assistant/lib/attachment-parts.ts +26 -5
  67. package/src/modules/ai_assistant/lib/chat-config.ts +1 -1
  68. package/src/modules/ai_assistant/lib/client-factory.ts +3 -9
  69. package/src/modules/ai_assistant/lib/codemode-tools.ts +49 -0
  70. package/src/modules/ai_assistant/lib/generated-registry-loader.ts +35 -3
  71. package/src/modules/ai_assistant/lib/llm-adapters/anthropic.ts +1 -1
  72. package/src/modules/ai_assistant/lib/llm-adapters/google.ts +1 -1
  73. package/src/modules/ai_assistant/lib/llm-adapters/openai.ts +1 -1
  74. package/src/modules/ai_assistant/lib/llm-bootstrap.ts +1 -1
  75. package/src/modules/ai_assistant/lib/mcp-client.ts +9 -5
  76. package/src/modules/ai_assistant/lib/mcp-dev-key-resolution.ts +107 -0
  77. package/src/modules/ai_assistant/lib/mcp-dev-server.ts +1 -36
  78. package/src/modules/ai_assistant/lib/mcp-server.ts +47 -33
  79. package/src/modules/ai_assistant/lib/openai-compatible-presets.ts +1 -1
  80. package/src/modules/ai_assistant/lib/task-plan-stream.ts +1 -1
  81. package/src/modules/ai_assistant/lib/types.ts +7 -0
  82. package/src/modules/ai_assistant/setup.ts +11 -2
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/ai_assistant/data/entities.ts"],
4
- "sourcesContent": ["import { OptionalProps } from '@mikro-orm/core'\nimport {\n Entity,\n Index,\n PrimaryKey,\n Property,\n} from '@mikro-orm/decorators/legacy'\nimport type {\n AiPendingActionExecutionResult,\n AiPendingActionFailedRecord,\n AiPendingActionFieldDiff,\n AiPendingActionQueueMode,\n AiPendingActionRecordDiff,\n AiPendingActionStatus,\n} from '../lib/pending-action-types'\n\n/**\n * Versioned additive prompt-override for a registered AI agent (Step 5.3).\n *\n * Each write creates a new row with `version = latest + 1`. Rows are never\n * updated in place \u2014 history is preserved so operators can roll back by\n * reading an earlier `version`. Column set is tenant/org-scoped per the\n * standard Open Mercato RBAC contract.\n *\n * `sections` holds additive text keyed by prompt section id. The runtime\n * composes the final `systemPrompt` via `composeSystemPromptWithOverride`\n * (see `lib/prompt-override-merge.ts`), which NEVER replaces a built-in\n * section \u2014 overrides are append-only by contract.\n */\n@Entity({ tableName: 'ai_agent_prompt_overrides' })\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_org_agent_version_uq',\n expression:\n 'create unique index \"ai_agent_prompt_overrides_tenant_org_agent_version_uq\" on \"ai_agent_prompt_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\", \"version\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_agent_version_null_org_uq',\n expression:\n 'create unique index \"ai_agent_prompt_overrides_tenant_agent_version_null_org_uq\" on \"ai_agent_prompt_overrides\" (\"tenant_id\", \"agent_id\", \"version\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_agent_idx',\n properties: ['tenantId', 'agentId'],\n})\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_org_agent_version_idx',\n expression:\n 'create index \"ai_agent_prompt_overrides_tenant_org_agent_version_idx\" on \"ai_agent_prompt_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\", \"version\" desc)',\n})\nexport class AiAgentPromptOverride {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'organizationId' | 'createdByUserId' | 'notes'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'version', type: 'int' })\n version!: number\n\n @Property({ name: 'sections', type: 'jsonb' })\n sections!: Record<string, string>\n\n @Property({ name: 'notes', type: 'text', nullable: true })\n notes?: string | null\n\n @Property({ name: 'created_by_user_id', type: 'uuid', nullable: true })\n createdByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Persistent mutation-approval gate row backing the Phase 3 WS-C contract\n * (spec \u00A78 `AiPendingAction` + \u00A79 confirm/cancel flow, Step 5.5).\n *\n * One row is created by `prepareMutation` (Step 5.6) whenever the runtime\n * intercepts an `isMutation: true` tool call from a non-read-only agent.\n * The row stores the normalized tool input, a precomputed `fieldDiff` (or\n * per-record batch diff in `records[]`), the target record version, an\n * `idempotencyKey` that dedupes double-submits within the TTL, and a\n * `status` that walks the state machine defined in\n * {@link AI_PENDING_ACTION_ALLOWED_TRANSITIONS}.\n *\n * The cleanup worker (Step 5.12) sweeps `status='pending' AND expiresAt < now`\n * rows and transitions them to `expired`. The confirm route (Step 5.8)\n * walks `pending \u2192 confirmed \u2192 executing \u2192 (failed | terminal success)`.\n * Reads always flow through `findOneWithDecryption` /\n * `findWithDecryption`, even though no column is GDPR-flagged today, so\n * future encrypted columns (e.g. `normalizedInput`) are handled.\n */\n@Entity({ tableName: 'ai_pending_actions' })\n@Index({\n name: 'ai_pending_actions_tenant_org_idempotency_uq',\n expression:\n 'create unique index \"ai_pending_actions_tenant_org_idempotency_uq\" on \"ai_pending_actions\" (\"tenant_id\", \"organization_id\", \"idempotency_key\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_pending_actions_tenant_idem_null_org_uq',\n expression:\n 'create unique index \"ai_pending_actions_tenant_idem_null_org_uq\" on \"ai_pending_actions\" (\"tenant_id\", \"idempotency_key\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_pending_actions_tenant_org_status_expires_idx',\n properties: ['tenantId', 'organizationId', 'status', 'expiresAt'],\n})\n@Index({\n name: 'ai_pending_actions_tenant_org_agent_status_idx',\n properties: ['tenantId', 'organizationId', 'agentId', 'status'],\n})\nexport class AiPendingAction {\n [OptionalProps]?:\n | 'createdAt'\n | 'organizationId'\n | 'conversationId'\n | 'targetEntityType'\n | 'targetRecordId'\n | 'fieldDiff'\n | 'records'\n | 'failedRecords'\n | 'sideEffectsSummary'\n | 'recordVersion'\n | 'attachmentIds'\n | 'executionResult'\n | 'resolvedAt'\n | 'resolvedByUserId'\n | 'queueMode'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'tool_name', type: 'text' })\n toolName!: string\n\n @Property({ name: 'conversation_id', type: 'text', nullable: true })\n conversationId?: string | null\n\n @Property({ name: 'target_entity_type', type: 'text', nullable: true })\n targetEntityType?: string | null\n\n @Property({ name: 'target_record_id', type: 'text', nullable: true })\n targetRecordId?: string | null\n\n @Property({ name: 'normalized_input', type: 'jsonb' })\n normalizedInput!: Record<string, unknown>\n\n @Property({ name: 'field_diff', type: 'jsonb', default: [] })\n fieldDiff: AiPendingActionFieldDiff[] = []\n\n @Property({ name: 'records', type: 'jsonb', nullable: true })\n records?: AiPendingActionRecordDiff[] | null\n\n @Property({ name: 'failed_records', type: 'jsonb', nullable: true })\n failedRecords?: AiPendingActionFailedRecord[] | null\n\n @Property({ name: 'side_effects_summary', type: 'text', nullable: true })\n sideEffectsSummary?: string | null\n\n @Property({ name: 'record_version', type: 'text', nullable: true })\n recordVersion?: string | null\n\n @Property({ name: 'attachment_ids', type: 'jsonb', default: [] })\n attachmentIds: string[] = []\n\n @Property({ name: 'idempotency_key', type: 'text' })\n idempotencyKey!: string\n\n @Property({ name: 'created_by_user_id', type: 'uuid' })\n createdByUserId!: string\n\n @Property({ name: 'status', type: 'text' })\n status!: AiPendingActionStatus\n\n @Property({ name: 'queue_mode', type: 'text', default: 'inline' })\n queueMode: AiPendingActionQueueMode = 'inline'\n\n @Property({ name: 'execution_result', type: 'jsonb', nullable: true })\n executionResult?: AiPendingActionExecutionResult | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'expires_at', type: Date })\n expiresAt!: Date\n\n @Property({ name: 'resolved_at', type: Date, nullable: true })\n resolvedAt?: Date | null\n\n @Property({ name: 'resolved_by_user_id', type: 'uuid', nullable: true })\n resolvedByUserId?: string | null\n}\n\n/**\n * Per-tenant runtime override row that controls which provider, model, and\n * base URL the AI runtime uses for a given agent (or all agents when\n * `agent_id` is null).\n *\n * Resolution at query time: a non-null `agent_id` row takes precedence over\n * a null `agent_id` (tenant-wide) row for the same `(tenant_id,\n * organization_id)` scope. All value columns are nullable \u2014 an admin can\n * override just the provider, just the model, or any subset. A null value\n * means \"inherit from the next source in the factory resolution chain.\"\n *\n * Soft-delete via `deleted_at` so the unique partial index and audit trail\n * remain intact across upsert operations.\n *\n * Phase 4a of spec `2026-04-27-ai-agents-provider-model-baseurl-overrides`.\n */\n@Entity({ tableName: 'ai_agent_runtime_overrides' })\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_org_agent_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_org_agent_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\") where \"deleted_at\" is null and \"organization_id\" is not null and \"agent_id\" is not null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_agent_null_org_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_agent_null_org_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\", \"agent_id\") where \"deleted_at\" is null and \"organization_id\" is null and \"agent_id\" is not null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_null_agent_null_org_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_null_agent_null_org_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\") where \"deleted_at\" is null and \"organization_id\" is null and \"agent_id\" is null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_org_null_agent_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_org_null_agent_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\", \"organization_id\") where \"deleted_at\" is null and \"organization_id\" is not null and \"agent_id\" is null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_idx',\n properties: ['tenantId'],\n})\nexport class AiAgentRuntimeOverride {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'agentId'\n | 'providerId'\n | 'modelId'\n | 'baseUrl'\n | 'allowedOverrideProviders'\n | 'allowedOverrideModelsByProvider'\n | 'updatedByUserId'\n | 'deletedAt'\n | 'loopDisabled'\n | 'loopMaxSteps'\n | 'loopMaxToolCalls'\n | 'loopMaxWallClockMs'\n | 'loopMaxTokens'\n | 'loopStopWhenJson'\n | 'loopActiveToolsJson'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'string', columnType: 'varchar(128)', nullable: true })\n agentId?: string | null\n\n @Property({ name: 'provider_id', type: 'string', columnType: 'varchar(64)', nullable: true })\n providerId?: string | null\n\n @Property({ name: 'model_id', type: 'string', columnType: 'varchar(256)', nullable: true })\n modelId?: string | null\n\n @Property({ name: 'base_url', type: 'string', columnType: 'varchar(2048)', nullable: true })\n baseUrl?: string | null\n\n @Property({ name: 'allowed_override_providers', type: 'jsonb', nullable: true })\n allowedOverrideProviders?: string[] | null\n\n @Property({ name: 'allowed_override_models_by_provider', type: 'jsonb', default: '{}' })\n allowedOverrideModelsByProvider: Record<string, string[]> = {}\n\n @Property({ name: 'updated_by_user_id', type: 'uuid', nullable: true })\n updatedByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n\n /**\n * Kill switch \u2014 when `true`, runtime forces `stopWhen: stepCountIs(1)` and\n * ignores all other loop config. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_disabled', type: 'boolean', nullable: true })\n loopDisabled?: boolean | null\n\n /**\n * Override `loop.maxSteps`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_steps', type: 'int', nullable: true })\n loopMaxSteps?: number | null\n\n /**\n * Override `loop.budget.maxToolCalls`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_tool_calls', type: 'int', nullable: true })\n loopMaxToolCalls?: number | null\n\n /**\n * Override `loop.budget.maxWallClockMs`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_wall_clock_ms', type: 'int', nullable: true })\n loopMaxWallClockMs?: number | null\n\n /**\n * Override `loop.budget.maxTokens`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_tokens', type: 'int', nullable: true })\n loopMaxTokens?: number | null\n\n /**\n * Override `loop.stopWhen`. JSON-safe variants only (`stepCount`,\n * `hasToolCall`); validator rejects `kind: 'custom'`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_stop_when_json', type: 'jsonb', nullable: true })\n loopStopWhenJson?: unknown | null\n\n /**\n * Override `loop.activeTools` (must be subset of `agent.allowedTools`).\n * Phase 3 of spec `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_active_tools_json', type: 'jsonb', nullable: true })\n loopActiveToolsJson?: unknown | null\n}\n\n/**\n * Append-only event log for token usage per step (chat) or per turn (object).\n *\n * One row is created by `recordTokenUsage` (Phase 6.3) for every completed\n * AI SDK step. Indexed for the three read patterns: daily rollup, per-agent\n * report, and session drill-down.\n *\n * Retention: rows older than `AI_TOKEN_USAGE_EVENTS_RETENTION_DAYS` (default\n * 90) are swept by the `ai-token-usage-prune` worker (Phase 6.4).\n *\n * Phase 6.0 of spec `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n@Entity({ tableName: 'ai_token_usage_events' })\n@Index({\n name: 'ai_token_usage_events_tenant_created_idx',\n properties: ['tenantId', 'createdAt'],\n})\n@Index({\n name: 'ai_token_usage_events_tenant_agent_created_idx',\n properties: ['tenantId', 'agentId', 'createdAt'],\n})\n@Index({\n name: 'ai_token_usage_events_tenant_model_created_idx',\n properties: ['tenantId', 'modelId', 'createdAt'],\n})\n@Index({\n name: 'ai_token_usage_events_tenant_session_turn_step_idx',\n properties: ['tenantId', 'sessionId', 'turnId', 'stepIndex'],\n})\nexport class AiTokenUsageEvent {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'cachedInputTokens'\n | 'reasoningTokens'\n | 'finishReason'\n | 'loopAbortReason'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'user_id', type: 'uuid' })\n userId!: string\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'module_id', type: 'text' })\n moduleId!: string\n\n @Property({ name: 'session_id', type: 'uuid' })\n sessionId!: string\n\n @Property({ name: 'turn_id', type: 'uuid' })\n turnId!: string\n\n @Property({ name: 'step_index', type: 'int' })\n stepIndex!: number\n\n @Property({ name: 'provider_id', type: 'text' })\n providerId!: string\n\n @Property({ name: 'model_id', type: 'text' })\n modelId!: string\n\n @Property({ name: 'input_tokens', type: 'int' })\n inputTokens!: number\n\n @Property({ name: 'output_tokens', type: 'int' })\n outputTokens!: number\n\n @Property({ name: 'cached_input_tokens', type: 'int', nullable: true })\n cachedInputTokens?: number | null\n\n @Property({ name: 'reasoning_tokens', type: 'int', nullable: true })\n reasoningTokens?: number | null\n\n @Property({ name: 'finish_reason', type: 'text', nullable: true })\n finishReason?: string | null\n\n @Property({ name: 'loop_abort_reason', type: 'text', nullable: true })\n loopAbortReason?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Materialized daily rollup of token usage per `(tenant, day, agent, model)`.\n *\n * Updated incrementally by UPSERT on every `recordTokenUsage` call so the\n * rollup is always current even when the prune worker is behind. A daily\n * reconciliation worker (Phase 6.4) recomputes `session_count` from the events\n * table to correct any drift caused by event delivery delays or outages.\n *\n * `session_count` is maintained via a per-row LATERAL exists check at write\n * time (first event in a `(tenant, day, agent, model, session)` window\n * increments the counter). This counter may drift if events arrive out of\n * order; the daily worker corrects it.\n *\n * Phase 6.1 of spec `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n@Entity({ tableName: 'ai_token_usage_daily' })\n@Index({\n name: 'ai_token_usage_daily_tenant_day_agent_model_org_uq',\n expression:\n 'create unique index \"ai_token_usage_daily_tenant_day_agent_model_org_uq\" on \"ai_token_usage_daily\" (\"tenant_id\", \"day\", \"agent_id\", \"model_id\", \"organization_id\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_token_usage_daily_tenant_day_agent_model_null_org_uq',\n expression:\n 'create unique index \"ai_token_usage_daily_tenant_day_agent_model_null_org_uq\" on \"ai_token_usage_daily\" (\"tenant_id\", \"day\", \"agent_id\", \"model_id\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_token_usage_daily_tenant_day_idx',\n properties: ['tenantId', 'day'],\n})\nexport class AiTokenUsageDaily {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'organizationId'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'day', type: 'string', columnType: 'date' })\n day!: string\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'model_id', type: 'text' })\n modelId!: string\n\n @Property({ name: 'provider_id', type: 'text' })\n providerId!: string\n\n @Property({ name: 'input_tokens', type: 'string', columnType: 'bigint' })\n inputTokens!: string\n\n @Property({ name: 'output_tokens', type: 'string', columnType: 'bigint' })\n outputTokens!: string\n\n @Property({ name: 'cached_input_tokens', type: 'string', columnType: 'bigint' })\n cachedInputTokens!: string\n\n @Property({ name: 'reasoning_tokens', type: 'string', columnType: 'bigint' })\n reasoningTokens!: string\n\n @Property({ name: 'step_count', type: 'string', columnType: 'bigint' })\n stepCount!: string\n\n @Property({ name: 'turn_count', type: 'string', columnType: 'bigint' })\n turnCount!: string\n\n @Property({ name: 'session_count', type: 'string', columnType: 'bigint' })\n sessionCount!: string\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Tenant-scoped override of an agent's declared `mutationPolicy` (Step 5.4).\n *\n * Unlike {@link AiAgentPromptOverride}, this surface is NOT versioned \u2014 it is\n * a single-value policy switch per `(tenantId, organizationId, agentId)`. The\n * runtime enforces the override as a DOWNGRADE only: the effective policy\n * equals the MOST RESTRICTIVE of `{ code-declared, override }`. Escalation is\n * a code-level change and is rejected at the route layer.\n *\n * Hierarchy (most restrictive \u2192 least): `read-only` < `destructive-confirm-required`\n * < `confirm-required`. The route never allows an override to widen the\n * code-declared policy.\n */\n/**\n * Tenant-scoped allowlist clipping which providers and models the runtime is\n * permitted to use within the env-driven allowlist (Phase 1780-6 of spec\n * `2026-04-27-ai-agents-provider-model-baseurl-overrides`).\n *\n * Effective constraint chain (outer \u2192 inner): `OM_AI_AVAILABLE_*` env vars \u2192\n * this tenant allowlist \u2192 per-tenant runtime overrides \u2192 per-request overrides.\n * The tenant allowlist may NEVER widen the env allowlist; the runtime\n * intersects the two and surfaces the intersection through the settings GET\n * response so the UI never offers a value the runtime would refuse.\n *\n * `allowedProviders === null` means \"inherit env\" (no tenant-level restriction\n * beyond what the env imposes). `allowedModelsByProvider` keys are provider\n * ids; a missing key means \"inherit env\" for that provider; an empty array\n * means \"no models permitted for this provider\" (effectively disabling it).\n */\n@Entity({ tableName: 'ai_tenant_model_allowlists' })\n@Index({\n name: 'ai_tenant_model_allowlists_tenant_org_uq',\n expression:\n 'create unique index \"ai_tenant_model_allowlists_tenant_org_uq\" on \"ai_tenant_model_allowlists\" (\"tenant_id\", \"organization_id\") where \"deleted_at\" is null and \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_tenant_model_allowlists_tenant_null_org_uq',\n expression:\n 'create unique index \"ai_tenant_model_allowlists_tenant_null_org_uq\" on \"ai_tenant_model_allowlists\" (\"tenant_id\") where \"deleted_at\" is null and \"organization_id\" is null',\n})\n@Index({\n name: 'ai_tenant_model_allowlists_tenant_idx',\n properties: ['tenantId'],\n})\nexport class AiTenantModelAllowlist {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'allowedProviders'\n | 'allowedModelsByProvider'\n | 'updatedByUserId'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'allowed_providers', type: 'jsonb', nullable: true })\n allowedProviders?: string[] | null\n\n @Property({ name: 'allowed_models_by_provider', type: 'jsonb', default: '{}' })\n allowedModelsByProvider: Record<string, string[]> = {}\n\n @Property({ name: 'updated_by_user_id', type: 'uuid', nullable: true })\n updatedByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'ai_agent_mutation_policy_overrides' })\n@Index({\n name: 'ai_agent_mutation_policy_overrides_tenant_org_agent_uq',\n expression:\n 'create unique index \"ai_agent_mutation_policy_overrides_tenant_org_agent_uq\" on \"ai_agent_mutation_policy_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_agent_mutation_policy_overrides_tenant_agent_null_org_uq',\n expression:\n 'create unique index \"ai_agent_mutation_policy_overrides_tenant_agent_null_org_uq\" on \"ai_agent_mutation_policy_overrides\" (\"tenant_id\", \"agent_id\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_agent_mutation_policy_overrides_tenant_agent_idx',\n properties: ['tenantId', 'agentId'],\n})\nexport class AiAgentMutationPolicyOverride {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'organizationId' | 'createdByUserId' | 'notes'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'mutation_policy', type: 'text' })\n mutationPolicy!: string\n\n @Property({ name: 'notes', type: 'text', nullable: true })\n notes?: string | null\n\n @Property({ name: 'created_by_user_id', type: 'uuid', nullable: true })\n createdByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Tenant-scoped durable record of a typed AI chat session.\n *\n * Owner-only MVP per spec `2026-05-05-ai-chat-server-side-conversation-storage`.\n * The `participants` table prepares for future sharing without a schema\n * rewrite \u2014 the owner row is always written in the same transaction as the\n * conversation row (see `AiChatConversationRepository.createOrGet`).\n *\n * `conversationId` is the stable, client-visible identifier. It is unique\n * within `(tenant_id, organization_id)` so an idempotent `createOrGet` can\n * accept a client-generated UUID. Pending mutation approvals already store\n * the same id in `AiPendingAction.conversationId` \u2014 the chat-history schema\n * deliberately matches that contract so a future foreign key can be added\n * without churn.\n *\n * `imported_from_local_at` flags conversations that the UI lazily migrated\n * from `localStorage`. The flag is informational only; once a row exists it\n * is always the source of truth for that conversation.\n */\n@Entity({ tableName: 'ai_chat_conversations' })\n@Index({\n name: 'ai_chat_conversations_tenant_org_conv_uq',\n expression:\n 'create unique index \"ai_chat_conversations_tenant_org_conv_uq\" on \"ai_chat_conversations\" (\"tenant_id\", \"organization_id\", \"conversation_id\") where \"organization_id\" is not null and \"deleted_at\" is null',\n})\n@Index({\n name: 'ai_chat_conversations_tenant_conv_null_org_uq',\n expression:\n 'create unique index \"ai_chat_conversations_tenant_conv_null_org_uq\" on \"ai_chat_conversations\" (\"tenant_id\", \"conversation_id\") where \"organization_id\" is null and \"deleted_at\" is null',\n})\n@Index({\n name: 'ai_chat_conversations_tenant_org_owner_agent_idx',\n properties: ['tenantId', 'organizationId', 'ownerUserId', 'agentId', 'status', 'lastMessageAt'],\n})\n@Index({\n name: 'ai_chat_conversations_tenant_org_deleted_idx',\n properties: ['tenantId', 'organizationId', 'deletedAt'],\n})\nexport class AiChatConversation {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'title'\n | 'status'\n | 'visibility'\n | 'pageContext'\n | 'lastMessageAt'\n | 'importedFromLocalAt'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'conversation_id', type: 'text' })\n conversationId!: string\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'owner_user_id', type: 'uuid' })\n ownerUserId!: string\n\n @Property({ name: 'title', type: 'text', nullable: true })\n title?: string | null\n\n @Property({ name: 'status', type: 'text', default: 'open' })\n status: 'open' | 'closed' = 'open'\n\n @Property({ name: 'visibility', type: 'text', default: 'private' })\n visibility: 'private' | 'shared' | 'organization' = 'private'\n\n @Property({ name: 'page_context', type: 'jsonb', nullable: true })\n pageContext?: Record<string, unknown> | null\n\n @Property({ name: 'last_message_at', type: Date, nullable: true })\n lastMessageAt?: Date | null\n\n @Property({ name: 'imported_from_local_at', type: Date, nullable: true })\n importedFromLocalAt?: Date | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n/**\n * Membership row for an `AiChatConversation`.\n *\n * MVP always writes exactly one row per conversation with `role = 'owner'`,\n * written transactionally alongside the conversation. Sharing extensions\n * append additional rows with `role IN ('viewer', 'commenter', ...)`. The\n * access predicate is \"is the caller an undeleted participant\" \u2014 see\n * `AiChatConversationRepository.assertAccessible`.\n *\n * `last_read_at` is reserved for future unread/share UX and is unused in MVP.\n */\n@Entity({ tableName: 'ai_chat_conversation_participants' })\n@Index({\n name: 'ai_chat_conv_participants_tenant_org_conv_user_uq',\n expression:\n 'create unique index \"ai_chat_conv_participants_tenant_org_conv_user_uq\" on \"ai_chat_conversation_participants\" (\"tenant_id\", \"organization_id\", \"conversation_id\", \"user_id\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_chat_conv_participants_tenant_conv_user_null_org_uq',\n expression:\n 'create unique index \"ai_chat_conv_participants_tenant_conv_user_null_org_uq\" on \"ai_chat_conversation_participants\" (\"tenant_id\", \"conversation_id\", \"user_id\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_chat_conv_participants_tenant_org_user_conv_idx',\n properties: ['tenantId', 'organizationId', 'userId', 'conversationId'],\n})\nexport class AiChatConversationParticipant {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'role'\n | 'lastReadAt'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'conversation_id', type: 'text' })\n conversationId!: string\n\n @Property({ name: 'user_id', type: 'uuid' })\n userId!: string\n\n @Property({ name: 'role', type: 'text', default: 'owner' })\n role: 'owner' | 'viewer' | 'commenter' = 'owner'\n\n @Property({ name: 'last_read_at', type: Date, nullable: true })\n lastReadAt?: Date | null\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Append-only message row for an `AiChatConversation`.\n *\n * `client_message_id` is the idempotency key for retries and lazy imports\n * from `localStorage`. The partial unique index allows a non-null\n * `clientMessageId` to dedupe within the conversation while leaving\n * server-only rows (assistant turns persisted from the streaming dispatcher)\n * free of the constraint.\n *\n * `ui_parts` stores the serializable subset of `AiChatMessageUiPart[]` so the\n * chat surface can re-render record cards, mutation-preview cards, etc.\n * across reloads. Attachment previews (`data:` URLs and transient blob\n * URLs) MUST NOT be persisted here \u2014 the UI strips them before upload.\n */\n@Entity({ tableName: 'ai_chat_messages' })\n@Index({\n name: 'ai_chat_messages_tenant_org_conv_client_id_uq',\n expression:\n 'create unique index \"ai_chat_messages_tenant_org_conv_client_id_uq\" on \"ai_chat_messages\" (\"tenant_id\", \"organization_id\", \"conversation_id\", \"client_message_id\") where \"organization_id\" is not null and \"client_message_id\" is not null and \"deleted_at\" is null',\n})\n@Index({\n name: 'ai_chat_messages_tenant_conv_client_id_null_org_uq',\n expression:\n 'create unique index \"ai_chat_messages_tenant_conv_client_id_null_org_uq\" on \"ai_chat_messages\" (\"tenant_id\", \"conversation_id\", \"client_message_id\") where \"organization_id\" is null and \"client_message_id\" is not null and \"deleted_at\" is null',\n})\n@Index({\n name: 'ai_chat_messages_tenant_org_conv_created_idx',\n properties: ['tenantId', 'organizationId', 'conversationId', 'createdAt'],\n})\n@Index({\n name: 'ai_chat_messages_tenant_org_deleted_idx',\n properties: ['tenantId', 'organizationId', 'deletedAt'],\n})\nexport class AiChatMessage {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'clientMessageId'\n | 'uiParts'\n | 'attachmentIds'\n | 'filesMetadata'\n | 'model'\n | 'metadata'\n | 'createdByUserId'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'conversation_id', type: 'text' })\n conversationId!: string\n\n @Property({ name: 'client_message_id', type: 'text', nullable: true })\n clientMessageId?: string | null\n\n @Property({ name: 'role', type: 'text' })\n role!: 'user' | 'assistant' | 'system'\n\n @Property({ name: 'content', type: 'text' })\n content!: string\n\n @Property({ name: 'ui_parts', type: 'jsonb', nullable: true })\n uiParts?: unknown[] | null\n\n @Property({ name: 'attachment_ids', type: 'jsonb', nullable: true })\n attachmentIds?: string[] | null\n\n @Property({ name: 'files_metadata', type: 'jsonb', nullable: true })\n filesMetadata?: Array<Record<string, unknown>> | null\n\n @Property({ name: 'model', type: 'text', nullable: true })\n model?: string | null\n\n @Property({ name: 'metadata', type: 'jsonb', nullable: true })\n metadata?: Record<string, unknown> | null\n\n @Property({ name: 'created_by_user_id', type: 'uuid', nullable: true })\n createdByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { OptionalProps } from '@mikro-orm/core'\nimport {\n Entity,\n Index,\n PrimaryKey,\n Property,\n} from '@mikro-orm/decorators/legacy'\nimport type {\n AiPendingActionExecutionResult,\n AiPendingActionFailedRecord,\n AiPendingActionFieldDiff,\n AiPendingActionQueueMode,\n AiPendingActionRecordDiff,\n AiPendingActionStatus,\n} from '../lib/pending-action-types'\n\n/**\n * Versioned additive prompt-override for a registered AI agent (Step 5.3).\n *\n * Each write creates a new row with `version = latest + 1`. Rows are never\n * updated in place \u2014 history is preserved so operators can roll back by\n * reading an earlier `version`. Column set is tenant/org-scoped per the\n * standard Open Mercato RBAC contract.\n *\n * `sections` holds additive text keyed by prompt section id. The runtime\n * composes the final `systemPrompt` via `composeSystemPromptWithOverride`\n * (see `lib/prompt-override-merge.ts`), which NEVER replaces a built-in\n * section \u2014 overrides are append-only by contract.\n */\n@Entity({ tableName: 'ai_agent_prompt_overrides' })\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_org_agent_version_uq',\n expression:\n 'create unique index \"ai_agent_prompt_overrides_tenant_org_agent_version_uq\" on \"ai_agent_prompt_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\", \"version\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_agent_version_null_org_uq',\n expression:\n 'create unique index \"ai_agent_prompt_overrides_tenant_agent_version_null_org_uq\" on \"ai_agent_prompt_overrides\" (\"tenant_id\", \"agent_id\", \"version\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_agent_idx',\n properties: ['tenantId', 'agentId'],\n})\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_org_agent_version_idx',\n expression:\n 'create index \"ai_agent_prompt_overrides_tenant_org_agent_version_idx\" on \"ai_agent_prompt_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\", \"version\" desc)',\n})\nexport class AiAgentPromptOverride {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'organizationId' | 'createdByUserId' | 'notes'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'version', type: 'int' })\n version!: number\n\n @Property({ name: 'sections', type: 'jsonb' })\n sections!: Record<string, string>\n\n @Property({ name: 'notes', type: 'text', nullable: true })\n notes?: string | null\n\n @Property({ name: 'created_by_user_id', type: 'uuid', nullable: true })\n createdByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Persistent mutation-approval gate row backing the Phase 3 WS-C contract\n * (spec \u00A78 `AiPendingAction` + \u00A79 confirm/cancel flow, Step 5.5).\n *\n * One row is created by `prepareMutation` (Step 5.6) whenever the runtime\n * intercepts an `isMutation: true` tool call from a non-read-only agent.\n * The row stores the normalized tool input, a precomputed `fieldDiff` (or\n * per-record batch diff in `records[]`), the target record version, an\n * `idempotencyKey` that dedupes double-submits within the TTL, and a\n * `status` that walks the state machine defined in\n * {@link AI_PENDING_ACTION_ALLOWED_TRANSITIONS}.\n *\n * The cleanup worker (Step 5.12) sweeps `status='pending' AND expiresAt < now`\n * rows and transitions them to `expired`. The confirm route (Step 5.8)\n * walks `pending \u2192 confirmed \u2192 executing \u2192 (failed | terminal success)`.\n * Reads always flow through `findOneWithDecryption` /\n * `findWithDecryption`, even though no column is GDPR-flagged today, so\n * future encrypted columns (e.g. `normalizedInput`) are handled.\n */\n@Entity({ tableName: 'ai_pending_actions' })\n@Index({\n name: 'ai_pending_actions_tenant_org_idempotency_uq',\n expression:\n 'create unique index \"ai_pending_actions_tenant_org_idempotency_uq\" on \"ai_pending_actions\" (\"tenant_id\", \"organization_id\", \"idempotency_key\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_pending_actions_tenant_idem_null_org_uq',\n expression:\n 'create unique index \"ai_pending_actions_tenant_idem_null_org_uq\" on \"ai_pending_actions\" (\"tenant_id\", \"idempotency_key\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_pending_actions_tenant_org_status_expires_idx',\n properties: ['tenantId', 'organizationId', 'status', 'expiresAt'],\n})\n@Index({\n name: 'ai_pending_actions_tenant_org_agent_status_idx',\n properties: ['tenantId', 'organizationId', 'agentId', 'status'],\n})\nexport class AiPendingAction {\n [OptionalProps]?:\n | 'createdAt'\n | 'organizationId'\n | 'conversationId'\n | 'targetEntityType'\n | 'targetRecordId'\n | 'fieldDiff'\n | 'records'\n | 'failedRecords'\n | 'sideEffectsSummary'\n | 'recordVersion'\n | 'attachmentIds'\n | 'executionResult'\n | 'resolvedAt'\n | 'resolvedByUserId'\n | 'queueMode'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'tool_name', type: 'text' })\n toolName!: string\n\n @Property({ name: 'conversation_id', type: 'text', nullable: true })\n conversationId?: string | null\n\n @Property({ name: 'target_entity_type', type: 'text', nullable: true })\n targetEntityType?: string | null\n\n @Property({ name: 'target_record_id', type: 'text', nullable: true })\n targetRecordId?: string | null\n\n @Property({ name: 'normalized_input', type: 'jsonb' })\n normalizedInput!: Record<string, unknown>\n\n @Property({ name: 'field_diff', type: 'jsonb', default: [] })\n fieldDiff: AiPendingActionFieldDiff[] = []\n\n @Property({ name: 'records', type: 'jsonb', nullable: true })\n records?: AiPendingActionRecordDiff[] | null\n\n @Property({ name: 'failed_records', type: 'jsonb', nullable: true })\n failedRecords?: AiPendingActionFailedRecord[] | null\n\n @Property({ name: 'side_effects_summary', type: 'text', nullable: true })\n sideEffectsSummary?: string | null\n\n @Property({ name: 'record_version', type: 'text', nullable: true })\n recordVersion?: string | null\n\n @Property({ name: 'attachment_ids', type: 'jsonb', default: [] })\n attachmentIds: string[] = []\n\n @Property({ name: 'idempotency_key', type: 'text' })\n idempotencyKey!: string\n\n @Property({ name: 'created_by_user_id', type: 'uuid' })\n createdByUserId!: string\n\n @Property({ name: 'status', type: 'text' })\n status!: AiPendingActionStatus\n\n @Property({ name: 'queue_mode', type: 'text', default: 'inline' })\n queueMode: AiPendingActionQueueMode = 'inline'\n\n @Property({ name: 'execution_result', type: 'jsonb', nullable: true })\n executionResult?: AiPendingActionExecutionResult | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'expires_at', type: Date })\n expiresAt!: Date\n\n @Property({ name: 'resolved_at', type: Date, nullable: true })\n resolvedAt?: Date | null\n\n @Property({ name: 'resolved_by_user_id', type: 'uuid', nullable: true })\n resolvedByUserId?: string | null\n}\n\n/**\n * Per-tenant runtime override row that controls which provider, model, and\n * base URL the AI runtime uses for a given agent (or all agents when\n * `agent_id` is null).\n *\n * Resolution at query time: a non-null `agent_id` row takes precedence over\n * a null `agent_id` (tenant-wide) row for the same `(tenant_id,\n * organization_id)` scope. All value columns are nullable \u2014 an admin can\n * override just the provider, just the model, or any subset. A null value\n * means \"inherit from the next source in the factory resolution chain.\"\n *\n * Soft-delete via `deleted_at` so the unique partial index and audit trail\n * remain intact across upsert operations.\n *\n * Phase 4a of spec `2026-04-27-ai-agents-provider-model-baseurl-overrides`.\n */\n@Entity({ tableName: 'ai_agent_runtime_overrides' })\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_org_agent_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_org_agent_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\") where \"deleted_at\" is null and \"organization_id\" is not null and \"agent_id\" is not null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_agent_null_org_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_agent_null_org_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\", \"agent_id\") where \"deleted_at\" is null and \"organization_id\" is null and \"agent_id\" is not null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_null_agent_null_org_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_null_agent_null_org_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\") where \"deleted_at\" is null and \"organization_id\" is null and \"agent_id\" is null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_org_null_agent_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_org_null_agent_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\", \"organization_id\") where \"deleted_at\" is null and \"organization_id\" is not null and \"agent_id\" is null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_idx',\n properties: ['tenantId'],\n})\nexport class AiAgentRuntimeOverride {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'agentId'\n | 'providerId'\n | 'modelId'\n | 'baseUrl'\n | 'allowedOverrideProviders'\n | 'allowedOverrideModelsByProvider'\n | 'updatedByUserId'\n | 'deletedAt'\n | 'loopDisabled'\n | 'loopMaxSteps'\n | 'loopMaxToolCalls'\n | 'loopMaxWallClockMs'\n | 'loopMaxTokens'\n | 'loopStopWhenJson'\n | 'loopActiveToolsJson'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'string', columnType: 'varchar(128)', nullable: true })\n agentId?: string | null\n\n @Property({ name: 'provider_id', type: 'string', columnType: 'varchar(64)', nullable: true })\n providerId?: string | null\n\n @Property({ name: 'model_id', type: 'string', columnType: 'varchar(256)', nullable: true })\n modelId?: string | null\n\n @Property({ name: 'base_url', type: 'string', columnType: 'varchar(2048)', nullable: true })\n baseUrl?: string | null\n\n @Property({ name: 'allowed_override_providers', type: 'jsonb', nullable: true })\n allowedOverrideProviders?: string[] | null\n\n @Property({ name: 'allowed_override_models_by_provider', type: 'jsonb', default: '{}' })\n allowedOverrideModelsByProvider: Record<string, string[]> = {}\n\n @Property({ name: 'updated_by_user_id', type: 'uuid', nullable: true })\n updatedByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n\n /**\n * Kill switch \u2014 when `true`, runtime forces `stopWhen: stepCountIs(1)` and\n * ignores all other loop config. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_disabled', type: 'boolean', nullable: true })\n loopDisabled?: boolean | null\n\n /**\n * Override `loop.maxSteps`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_steps', type: 'int', nullable: true })\n loopMaxSteps?: number | null\n\n /**\n * Override `loop.budget.maxToolCalls`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_tool_calls', type: 'int', nullable: true })\n loopMaxToolCalls?: number | null\n\n /**\n * Override `loop.budget.maxWallClockMs`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_wall_clock_ms', type: 'int', nullable: true })\n loopMaxWallClockMs?: number | null\n\n /**\n * Override `loop.budget.maxTokens`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_tokens', type: 'int', nullable: true })\n loopMaxTokens?: number | null\n\n /**\n * Override `loop.stopWhen`. JSON-safe variants only (`stepCount`,\n * `hasToolCall`); validator rejects `kind: 'custom'`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_stop_when_json', type: 'jsonb', nullable: true })\n loopStopWhenJson?: unknown | null\n\n /**\n * Override `loop.activeTools` (must be subset of `agent.allowedTools`).\n * Phase 3 of spec `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_active_tools_json', type: 'jsonb', nullable: true })\n loopActiveToolsJson?: unknown | null\n}\n\n/**\n * Append-only event log for token usage per step (chat) or per turn (object).\n *\n * One row is created by `recordTokenUsage` (Phase 6.3) for every completed\n * AI SDK step. Indexed for the three read patterns: daily rollup, per-agent\n * report, and session drill-down.\n *\n * Retention: rows older than `AI_TOKEN_USAGE_EVENTS_RETENTION_DAYS` (default\n * 90) are swept by the `ai-token-usage-prune` worker (Phase 6.4).\n *\n * Phase 6.0 of spec `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n@Entity({ tableName: 'ai_token_usage_events' })\n@Index({\n name: 'ai_token_usage_events_tenant_created_idx',\n properties: ['tenantId', 'createdAt'],\n})\n@Index({\n name: 'ai_token_usage_events_tenant_agent_created_idx',\n properties: ['tenantId', 'agentId', 'createdAt'],\n})\n@Index({\n name: 'ai_token_usage_events_tenant_model_created_idx',\n properties: ['tenantId', 'modelId', 'createdAt'],\n})\n@Index({\n name: 'ai_token_usage_events_tenant_session_turn_step_idx',\n properties: ['tenantId', 'sessionId', 'turnId', 'stepIndex'],\n})\nexport class AiTokenUsageEvent {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'cachedInputTokens'\n | 'reasoningTokens'\n | 'finishReason'\n | 'loopAbortReason'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'user_id', type: 'uuid' })\n userId!: string\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'module_id', type: 'text' })\n moduleId!: string\n\n @Property({ name: 'session_id', type: 'uuid' })\n sessionId!: string\n\n @Property({ name: 'turn_id', type: 'uuid' })\n turnId!: string\n\n @Property({ name: 'step_index', type: 'int' })\n stepIndex!: number\n\n @Property({ name: 'provider_id', type: 'text' })\n providerId!: string\n\n @Property({ name: 'model_id', type: 'text' })\n modelId!: string\n\n @Property({ name: 'input_tokens', type: 'int' })\n inputTokens!: number\n\n @Property({ name: 'output_tokens', type: 'int' })\n outputTokens!: number\n\n @Property({ name: 'cached_input_tokens', type: 'int', nullable: true })\n cachedInputTokens?: number | null\n\n @Property({ name: 'reasoning_tokens', type: 'int', nullable: true })\n reasoningTokens?: number | null\n\n @Property({ name: 'finish_reason', type: 'text', nullable: true })\n finishReason?: string | null\n\n @Property({ name: 'loop_abort_reason', type: 'text', nullable: true })\n loopAbortReason?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Materialized daily rollup of token usage per `(tenant, day, agent, model)`.\n *\n * Updated incrementally by UPSERT on every `recordTokenUsage` call so the\n * rollup is always current even when the prune worker is behind. A daily\n * reconciliation worker (Phase 6.4) recomputes `session_count` from the events\n * table to correct any drift caused by event delivery delays or outages.\n *\n * `session_count` is maintained via a per-row LATERAL exists check at write\n * time (first event in a `(tenant, day, agent, model, session)` window\n * increments the counter). This counter may drift if events arrive out of\n * order; the daily worker corrects it.\n *\n * Phase 6.1 of spec `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n@Entity({ tableName: 'ai_token_usage_daily' })\n@Index({\n name: 'ai_token_usage_daily_tenant_day_agent_model_org_uq',\n expression:\n 'create unique index \"ai_token_usage_daily_tenant_day_agent_model_org_uq\" on \"ai_token_usage_daily\" (\"tenant_id\", \"day\", \"agent_id\", \"model_id\", \"organization_id\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_token_usage_daily_tenant_day_agent_model_null_org_uq',\n expression:\n 'create unique index \"ai_token_usage_daily_tenant_day_agent_model_null_org_uq\" on \"ai_token_usage_daily\" (\"tenant_id\", \"day\", \"agent_id\", \"model_id\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_token_usage_daily_tenant_day_idx',\n properties: ['tenantId', 'day'],\n})\nexport class AiTokenUsageDaily {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'organizationId'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'day', type: 'string', columnType: 'date' })\n day!: string\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'model_id', type: 'text' })\n modelId!: string\n\n @Property({ name: 'provider_id', type: 'text' })\n providerId!: string\n\n @Property({ name: 'input_tokens', type: 'string', columnType: 'bigint' })\n inputTokens!: string\n\n @Property({ name: 'output_tokens', type: 'string', columnType: 'bigint' })\n outputTokens!: string\n\n @Property({ name: 'cached_input_tokens', type: 'string', columnType: 'bigint' })\n cachedInputTokens!: string\n\n @Property({ name: 'reasoning_tokens', type: 'string', columnType: 'bigint' })\n reasoningTokens!: string\n\n @Property({ name: 'step_count', type: 'string', columnType: 'bigint' })\n stepCount!: string\n\n @Property({ name: 'turn_count', type: 'string', columnType: 'bigint' })\n turnCount!: string\n\n @Property({ name: 'session_count', type: 'string', columnType: 'bigint' })\n sessionCount!: string\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Tenant-scoped override of an agent's declared `mutationPolicy` (Step 5.4).\n *\n * Unlike {@link AiAgentPromptOverride}, this surface is NOT versioned \u2014 it is\n * a single-value policy switch per `(tenantId, organizationId, agentId)`. The\n * runtime enforces the override as a DOWNGRADE only: the effective policy\n * equals the MOST RESTRICTIVE of `{ code-declared, override }`. Escalation is\n * a code-level change and is rejected at the route layer.\n *\n * Hierarchy (most restrictive \u2192 least): `read-only` < `destructive-confirm-required`\n * < `confirm-required`. The route never allows an override to widen the\n * code-declared policy.\n */\n/**\n * Tenant-scoped allowlist clipping which providers and models the runtime is\n * permitted to use within the env-driven allowlist (Phase 1780-6 of spec\n * `2026-04-27-ai-agents-provider-model-baseurl-overrides`).\n *\n * Effective constraint chain (outer \u2192 inner): `OM_AI_AVAILABLE_*` env vars \u2192\n * this tenant allowlist \u2192 per-tenant runtime overrides \u2192 per-request overrides.\n * The tenant allowlist may NEVER widen the env allowlist; the runtime\n * intersects the two and surfaces the intersection through the settings GET\n * response so the UI never offers a value the runtime would refuse.\n *\n * `allowedProviders === null` means \"inherit env\" (no tenant-level restriction\n * beyond what the env imposes). `allowedModelsByProvider` keys are provider\n * ids; a missing key means \"inherit env\" for that provider; an empty array\n * means \"no models permitted for this provider\" (effectively disabling it).\n */\n@Entity({ tableName: 'ai_tenant_model_allowlists' })\n@Index({\n name: 'ai_tenant_model_allowlists_tenant_org_uq',\n expression:\n 'create unique index \"ai_tenant_model_allowlists_tenant_org_uq\" on \"ai_tenant_model_allowlists\" (\"tenant_id\", \"organization_id\") where \"deleted_at\" is null and \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_tenant_model_allowlists_tenant_null_org_uq',\n expression:\n 'create unique index \"ai_tenant_model_allowlists_tenant_null_org_uq\" on \"ai_tenant_model_allowlists\" (\"tenant_id\") where \"deleted_at\" is null and \"organization_id\" is null',\n})\n@Index({\n name: 'ai_tenant_model_allowlists_tenant_idx',\n properties: ['tenantId'],\n})\nexport class AiTenantModelAllowlist {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'allowedProviders'\n | 'allowedModelsByProvider'\n | 'updatedByUserId'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'allowed_providers', type: 'jsonb', nullable: true })\n allowedProviders?: string[] | null\n\n @Property({ name: 'allowed_models_by_provider', type: 'jsonb', default: '{}' })\n allowedModelsByProvider: Record<string, string[]> = {}\n\n @Property({ name: 'updated_by_user_id', type: 'uuid', nullable: true })\n updatedByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'ai_agent_mutation_policy_overrides' })\n@Index({\n name: 'ai_agent_mutation_policy_overrides_tenant_org_agent_uq',\n expression:\n 'create unique index \"ai_agent_mutation_policy_overrides_tenant_org_agent_uq\" on \"ai_agent_mutation_policy_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_agent_mutation_policy_overrides_tenant_agent_null_org_uq',\n expression:\n 'create unique index \"ai_agent_mutation_policy_overrides_tenant_agent_null_org_uq\" on \"ai_agent_mutation_policy_overrides\" (\"tenant_id\", \"agent_id\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_agent_mutation_policy_overrides_tenant_agent_idx',\n properties: ['tenantId', 'agentId'],\n})\nexport class AiAgentMutationPolicyOverride {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'organizationId' | 'createdByUserId' | 'notes'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'mutation_policy', type: 'text' })\n mutationPolicy!: string\n\n @Property({ name: 'notes', type: 'text', nullable: true })\n notes?: string | null\n\n @Property({ name: 'created_by_user_id', type: 'uuid', nullable: true })\n createdByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Tenant-scoped durable record of a typed AI chat session.\n *\n * Owner-only MVP per spec `2026-05-05-ai-chat-server-side-conversation-storage`.\n * The `participants` table prepares for future sharing without a schema\n * rewrite \u2014 the owner row is always written in the same transaction as the\n * conversation row (see `AiChatConversationRepository.createOrGet`).\n *\n * `conversationId` is the stable, client-visible identifier. It is unique\n * within `(tenant_id, organization_id)` so an idempotent `createOrGet` can\n * accept a client-generated UUID. Pending mutation approvals already store\n * the same id in `AiPendingAction.conversationId` \u2014 the chat-history schema\n * deliberately matches that contract so a future foreign key can be added\n * without churn.\n *\n * `imported_from_local_at` flags conversations that the UI lazily migrated\n * from `localStorage`. The flag is informational only; once a row exists it\n * is always the source of truth for that conversation.\n */\n@Entity({ tableName: 'ai_chat_conversations' })\n@Index({\n name: 'ai_chat_conversations_tenant_org_conv_uq',\n expression:\n 'create unique index \"ai_chat_conversations_tenant_org_conv_uq\" on \"ai_chat_conversations\" (\"tenant_id\", \"organization_id\", \"conversation_id\") where \"organization_id\" is not null and \"deleted_at\" is null',\n})\n@Index({\n name: 'ai_chat_conversations_tenant_conv_null_org_uq',\n expression:\n 'create unique index \"ai_chat_conversations_tenant_conv_null_org_uq\" on \"ai_chat_conversations\" (\"tenant_id\", \"conversation_id\") where \"organization_id\" is null and \"deleted_at\" is null',\n})\n@Index({\n name: 'ai_chat_conversations_tenant_org_owner_agent_idx',\n properties: ['tenantId', 'organizationId', 'ownerUserId', 'agentId', 'status', 'lastMessageAt'],\n})\n@Index({\n name: 'ai_chat_conversations_tenant_org_deleted_idx',\n properties: ['tenantId', 'organizationId', 'deletedAt'],\n})\nexport class AiChatConversation {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'title'\n | 'status'\n | 'visibility'\n | 'pageContext'\n | 'lastMessageAt'\n | 'importedFromLocalAt'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'conversation_id', type: 'text' })\n conversationId!: string\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'owner_user_id', type: 'uuid' })\n ownerUserId!: string\n\n @Property({ name: 'title', type: 'text', nullable: true })\n title?: string | null\n\n @Property({ name: 'status', type: 'text', default: 'open' })\n status: 'open' | 'closed' = 'open'\n\n @Property({ name: 'visibility', type: 'text', default: 'private' })\n visibility: 'private' | 'shared' | 'organization' = 'private'\n\n @Property({ name: 'page_context', type: 'jsonb', nullable: true })\n pageContext?: Record<string, unknown> | null\n\n @Property({ name: 'last_message_at', type: Date, nullable: true })\n lastMessageAt?: Date | null\n\n @Property({ name: 'imported_from_local_at', type: Date, nullable: true })\n importedFromLocalAt?: Date | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n/**\n * Membership row for an `AiChatConversation`.\n *\n * MVP always writes exactly one row per conversation with `role = 'owner'`,\n * written transactionally alongside the conversation. Sharing extensions\n * append additional rows with `role IN ('viewer', 'commenter', ...)`. The\n * access predicate is \"is the caller an undeleted participant\" \u2014 see\n * `AiChatConversationRepository.assertAccessible`.\n *\n * `last_read_at` is reserved for future unread/share UX and is unused in MVP.\n */\n@Entity({ tableName: 'ai_chat_conversation_participants' })\n@Index({\n name: 'ai_chat_conv_participants_tenant_org_conv_user_uq',\n expression:\n 'create unique index \"ai_chat_conv_participants_tenant_org_conv_user_uq\" on \"ai_chat_conversation_participants\" (\"tenant_id\", \"organization_id\", \"conversation_id\", \"user_id\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_chat_conv_participants_tenant_conv_user_null_org_uq',\n expression:\n 'create unique index \"ai_chat_conv_participants_tenant_conv_user_null_org_uq\" on \"ai_chat_conversation_participants\" (\"tenant_id\", \"conversation_id\", \"user_id\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_chat_conv_participants_active_conv_user_idx',\n expression:\n 'create index \"ai_chat_conv_participants_active_conv_user_idx\" on \"ai_chat_conversation_participants\" (\"tenant_id\", \"organization_id\", \"conversation_id\", \"user_id\") where \"deleted_at\" is null',\n})\n@Index({\n name: 'ai_chat_conv_participants_tenant_org_user_conv_idx',\n properties: ['tenantId', 'organizationId', 'userId', 'conversationId'],\n})\nexport class AiChatConversationParticipant {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'role'\n | 'lastReadAt'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'conversation_id', type: 'text' })\n conversationId!: string\n\n @Property({ name: 'user_id', type: 'uuid' })\n userId!: string\n\n @Property({ name: 'role', type: 'text', default: 'owner' })\n role: 'owner' | 'viewer' | 'commenter' = 'owner'\n\n @Property({ name: 'last_read_at', type: Date, nullable: true })\n lastReadAt?: Date | null\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Append-only message row for an `AiChatConversation`.\n *\n * `client_message_id` is the idempotency key for retries and lazy imports\n * from `localStorage`. The partial unique index allows a non-null\n * `clientMessageId` to dedupe within the conversation while leaving\n * server-only rows (assistant turns persisted from the streaming dispatcher)\n * free of the constraint.\n *\n * `ui_parts` stores the serializable subset of `AiChatMessageUiPart[]` so the\n * chat surface can re-render record cards, mutation-preview cards, etc.\n * across reloads. Attachment previews (`data:` URLs and transient blob\n * URLs) MUST NOT be persisted here \u2014 the UI strips them before upload.\n */\n@Entity({ tableName: 'ai_chat_messages' })\n@Index({\n name: 'ai_chat_messages_tenant_org_conv_client_id_uq',\n expression:\n 'create unique index \"ai_chat_messages_tenant_org_conv_client_id_uq\" on \"ai_chat_messages\" (\"tenant_id\", \"organization_id\", \"conversation_id\", \"client_message_id\") where \"organization_id\" is not null and \"client_message_id\" is not null and \"deleted_at\" is null',\n})\n@Index({\n name: 'ai_chat_messages_tenant_conv_client_id_null_org_uq',\n expression:\n 'create unique index \"ai_chat_messages_tenant_conv_client_id_null_org_uq\" on \"ai_chat_messages\" (\"tenant_id\", \"conversation_id\", \"client_message_id\") where \"organization_id\" is null and \"client_message_id\" is not null and \"deleted_at\" is null',\n})\n@Index({\n name: 'ai_chat_messages_tenant_org_conv_created_idx',\n properties: ['tenantId', 'organizationId', 'conversationId', 'createdAt'],\n})\n@Index({\n name: 'ai_chat_messages_tenant_org_deleted_idx',\n properties: ['tenantId', 'organizationId', 'deletedAt'],\n})\nexport class AiChatMessage {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'clientMessageId'\n | 'uiParts'\n | 'attachmentIds'\n | 'filesMetadata'\n | 'model'\n | 'metadata'\n | 'createdByUserId'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'conversation_id', type: 'text' })\n conversationId!: string\n\n @Property({ name: 'client_message_id', type: 'text', nullable: true })\n clientMessageId?: string | null\n\n @Property({ name: 'role', type: 'text' })\n role!: 'user' | 'assistant' | 'system'\n\n @Property({ name: 'content', type: 'text' })\n content!: string\n\n @Property({ name: 'ui_parts', type: 'jsonb', nullable: true })\n uiParts?: unknown[] | null\n\n @Property({ name: 'attachment_ids', type: 'jsonb', nullable: true })\n attachmentIds?: string[] | null\n\n @Property({ name: 'files_metadata', type: 'jsonb', nullable: true })\n filesMetadata?: Array<Record<string, unknown>> | null\n\n @Property({ name: 'model', type: 'text', nullable: true })\n model?: string | null\n\n @Property({ name: 'metadata', type: 'jsonb', nullable: true })\n metadata?: Record<string, unknown> | null\n\n @Property({ name: 'created_by_user_id', type: 'uuid', nullable: true })\n createdByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -37,13 +37,15 @@ function buildAuthEnvelope(ctx) {
37
37
  if (!userId) {
38
38
  return { auth: null, status: "invalid" };
39
39
  }
40
+ const apiKeyId = userId.startsWith("api_key:") ? userId.slice("api_key:".length) : void 0;
40
41
  const auth = {
41
42
  sub: userId,
42
43
  userId,
43
44
  tenantId: ctx.tenantId,
44
45
  orgId: ctx.organizationId,
45
46
  roles: [],
46
- isSuperAdmin: ctx.isSuperAdmin
47
+ isSuperAdmin: ctx.isSuperAdmin,
48
+ ...apiKeyId ? { keyId: apiKeyId } : {}
47
49
  };
48
50
  return { auth, status: "authenticated" };
49
51
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/ai_assistant/lib/ai-api-operation-runner.ts"],
4
- "sourcesContent": ["// Phase 1 of spec 2026-04-27-ai-tools-api-backed-dry-refactor.md.\n//\n// In-process API operation runner used by typed AI tools to reuse existing\n// API route handlers without HTTP, fetch, or a second RBAC pass. The runner\n// resolves the matched route entry from the generated `apiRoutes` manifest,\n// validates that the route is documented (`openApi`) and that mutation routes\n// declare `requiredFeatures`, asserts the route's required features are\n// covered by the tool definition, then invokes the route handler directly with\n// a synthetic Request that carries a Symbol-keyed trusted-auth envelope so the\n// shared auth resolver short-circuits cookie/JWT/API-key parsing.\nimport {\n attachTrustedAuthContext,\n type AuthContext,\n type TrustedAuthContextEnvelope,\n} from '@open-mercato/shared/lib/auth/server'\nimport {\n findApiRouteManifestMatch,\n getApiRouteManifests,\n type ApiRouteManifestEntry,\n type RouteMatchParams,\n} from '@open-mercato/shared/modules/registry'\nimport { hasAllFeatures } from '@open-mercato/shared/security/features'\nimport type { AiToolDefinition, McpToolContext } from './types'\n\nexport type AiApiHttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n\nconst MUTATION_METHODS: ReadonlySet<AiApiHttpMethod> = new Set(['POST', 'PUT', 'PATCH', 'DELETE'])\n\nconst SYNTHETIC_ORIGIN = 'http://internal.local'\n\nexport type AiApiOperationRequest = {\n method: AiApiHttpMethod\n path: string\n query?: Record<string, string | number | boolean | null | undefined>\n body?: Record<string, unknown>\n allowFeaturelessMutation?: boolean\n}\n\nexport type AiApiOperationResponse<T = unknown> = {\n success: boolean\n statusCode: number\n data?: T\n error?: string\n details?: unknown\n}\n\nexport interface AiToolExecutionContext extends McpToolContext {\n tool: AiToolDefinition\n}\n\nexport type AiApiOperationRunnerOptions = {\n /** Optional override of the API route manifest (used by tests). */\n apiRoutes?: ApiRouteManifestEntry[]\n /** Custom loader for the API route manifest (used by tests). */\n loadApiRoutes?: () => Promise<ApiRouteManifestEntry[]>\n}\n\nexport type AiApiOperationRunner = {\n run<T = unknown>(request: AiApiOperationRequest): Promise<AiApiOperationResponse<T>>\n}\n\ntype ResolvedHandler = (req: Request, ctx?: { params: RouteMatchParams }) => Promise<Response> | Response\n\ntype LoadedRouteModule = Record<string, unknown>\n\ntype MethodMetadata = {\n requireAuth?: boolean\n requireFeatures?: string[]\n}\n\nfunction normalizeMethod(method: string): AiApiHttpMethod {\n const upper = method.toUpperCase()\n if (upper === 'GET' || upper === 'POST' || upper === 'PUT' || upper === 'PATCH' || upper === 'DELETE') {\n return upper\n }\n throw new Error(`Unsupported method \"${method}\"`)\n}\n\n// Exported for unit testing \u2014 see __tests__/ai-api-operation-runner.test.ts.\n// `path` arrives from agent tool inputs (LLM-controlled), so trailing-slash\n// stripping is implemented as a linear character-code scan rather than the\n// /\\/+$/ regex (CodeQL js/polynomial-redos: regex exhibits polynomial\n// backtracking on long runs of `/`). The loop is O(n) regardless of input.\nexport function normalizePath(path: string): string {\n if (typeof path !== 'string' || path.length === 0) return '/'\n const trimmed = path.startsWith('/') ? path : `/${path}`\n let end = trimmed.length\n while (end > 1 && trimmed.charCodeAt(end - 1) === 47 /* '/' */) end--\n return trimmed.slice(0, end)\n}\n\nfunction buildUrl(path: string, query?: AiApiOperationRequest['query']): URL {\n const url = new URL(`${SYNTHETIC_ORIGIN}/api${normalizePath(path)}`)\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value === null || value === undefined) continue\n url.searchParams.append(key, String(value))\n }\n }\n return url\n}\n\nfunction buildAuthEnvelope(ctx: AiToolExecutionContext): TrustedAuthContextEnvelope {\n const userId = ctx.userId\n if (!userId) {\n return { auth: null, status: 'invalid' }\n }\n const auth: AuthContext = {\n sub: userId,\n userId,\n tenantId: ctx.tenantId,\n orgId: ctx.organizationId,\n roles: [],\n isSuperAdmin: ctx.isSuperAdmin,\n }\n return { auth, status: 'authenticated' }\n}\n\nfunction pickHandler(entry: ApiRouteManifestEntry, mod: LoadedRouteModule, method: AiApiHttpMethod): ResolvedHandler | null {\n const direct = mod[method]\n if (typeof direct === 'function') return direct as ResolvedHandler\n if (entry.kind === 'legacy') {\n const fallback = mod.default ?? mod.handler\n if (typeof fallback === 'function') return fallback as ResolvedHandler\n }\n return null\n}\n\nfunction extractMethodMetadata(metadata: unknown, method: AiApiHttpMethod): MethodMetadata | null {\n if (!metadata || typeof metadata !== 'object') return null\n const record = metadata as Record<string, unknown>\n const perMethod = record[method]\n const source: Record<string, unknown> = perMethod && typeof perMethod === 'object'\n ? (perMethod as Record<string, unknown>)\n : record\n const result: MethodMetadata = {}\n if (typeof source.requireAuth === 'boolean') {\n result.requireAuth = source.requireAuth\n }\n if (Array.isArray(source.requireFeatures)) {\n const features = source.requireFeatures.filter((entry): entry is string => typeof entry === 'string' && entry.length > 0)\n if (features.length > 0) result.requireFeatures = features\n }\n return result\n}\n\nasync function readResponseBody(res: Response): Promise<unknown> {\n const contentType = res.headers.get('content-type') ?? ''\n if (contentType.includes('application/json')) {\n try {\n return await res.json()\n } catch {\n return null\n }\n }\n try {\n const text = await res.text()\n if (!text) return null\n try {\n return JSON.parse(text)\n } catch {\n return text\n }\n } catch {\n return null\n }\n}\n\nfunction failure(statusCode: number, error: string, details?: unknown): AiApiOperationResponse {\n const response: AiApiOperationResponse = { success: false, statusCode, error }\n if (details !== undefined) response.details = details\n return response\n}\n\nfunction normalizeError(body: unknown): { error: string; details?: unknown } {\n if (body && typeof body === 'object' && !Array.isArray(body)) {\n const record = body as Record<string, unknown>\n const message = typeof record.error === 'string'\n ? record.error\n : typeof record.message === 'string'\n ? record.message\n : null\n if (message) {\n const { error: _ignored, message: _ignoredMessage, ...rest } = record\n void _ignored\n void _ignoredMessage\n return Object.keys(rest).length > 0 ? { error: message, details: rest } : { error: message }\n }\n }\n if (typeof body === 'string' && body.length > 0) {\n return { error: body }\n }\n return { error: 'Request failed' }\n}\n\nexport function createAiApiOperationRunner(\n ctx: AiToolExecutionContext,\n options: AiApiOperationRunnerOptions = {},\n): AiApiOperationRunner {\n let manifestPromise: Promise<ApiRouteManifestEntry[]> | null = null\n\n const loadManifest = async (): Promise<ApiRouteManifestEntry[]> => {\n if (options.apiRoutes) return options.apiRoutes\n if (manifestPromise) return manifestPromise\n const loader = options.loadApiRoutes ?? defaultLoadApiRoutes\n manifestPromise = loader()\n try {\n return await manifestPromise\n } catch (error) {\n manifestPromise = null\n throw error\n }\n }\n\n return {\n async run<T = unknown>(request: AiApiOperationRequest): Promise<AiApiOperationResponse<T>> {\n let method: AiApiHttpMethod\n try {\n method = normalizeMethod(request.method)\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Invalid method'\n return failure(400, message) as AiApiOperationResponse<T>\n }\n const path = normalizePath(request.path)\n\n let routes: ApiRouteManifestEntry[]\n try {\n routes = await loadManifest()\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to load API route manifest'\n return failure(500, `Operation runner manifest unavailable: ${message}`) as AiApiOperationResponse<T>\n }\n\n const match = findApiRouteManifestMatch(routes, method, path)\n if (!match) {\n return failure(\n 404,\n `No documented API route matches ${method} ${path}`,\n ) as AiApiOperationResponse<T>\n }\n\n let mod: LoadedRouteModule\n try {\n mod = (await match.route.load()) as LoadedRouteModule\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to load route module'\n return failure(500, `Failed to load route module: ${message}`) as AiApiOperationResponse<T>\n }\n\n if (!('openApi' in mod) || mod.openApi === undefined || mod.openApi === null) {\n return failure(\n 501,\n `Route ${method} ${path} is undocumented (missing openApi export); refusing to call from AI tool`,\n ) as AiApiOperationResponse<T>\n }\n\n const handler = pickHandler(match.route, mod, method)\n if (!handler) {\n return failure(\n 405,\n `Route ${path} does not export a handler for method ${method}`,\n ) as AiApiOperationResponse<T>\n }\n\n const methodMetadata = extractMethodMetadata(mod.metadata, method)\n const routeFeatures = methodMetadata?.requireFeatures ?? []\n const isMutation = MUTATION_METHODS.has(method)\n\n if (isMutation && routeFeatures.length === 0 && !request.allowFeaturelessMutation) {\n return failure(\n 403,\n `Mutation route ${method} ${path} declares no requiredFeatures; refusing to call without allowFeaturelessMutation opt-in`,\n ) as AiApiOperationResponse<T>\n }\n\n const toolFeatures = ctx.tool.requiredFeatures ?? []\n if (routeFeatures.length > 0 && !hasAllFeatures(toolFeatures, routeFeatures)) {\n return failure(\n 403,\n `AI tool \"${ctx.tool.name}\" requiredFeatures do not cover route ${method} ${path} requiredFeatures`,\n { toolFeatures, routeFeatures },\n ) as AiApiOperationResponse<T>\n }\n\n const url = buildUrl(path, request.query)\n const headers = new Headers()\n const requestInit: RequestInit = { method, headers }\n if (request.body !== undefined && method !== 'GET') {\n headers.set('content-type', 'application/json')\n requestInit.body = JSON.stringify(request.body)\n }\n\n const syntheticRequest = new Request(url, requestInit)\n attachTrustedAuthContext(syntheticRequest, buildAuthEnvelope(ctx))\n\n let response: Response\n try {\n response = await handler(syntheticRequest, { params: match.params })\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Route handler threw'\n return failure(500, message) as AiApiOperationResponse<T>\n }\n\n const status = response.status\n const body = await readResponseBody(response)\n if (status >= 200 && status < 300) {\n return {\n success: true,\n statusCode: status,\n data: body as T,\n }\n }\n const normalized = normalizeError(body)\n return {\n success: false,\n statusCode: status,\n error: normalized.error,\n ...(normalized.details !== undefined ? { details: normalized.details } : {}),\n }\n },\n }\n}\n\nasync function defaultLoadApiRoutes(): Promise<ApiRouteManifestEntry[]> {\n const registered = getApiRouteManifests()\n if (registered.length === 0) {\n throw new Error(\n 'No API route manifest registered. Call registerApiRouteManifests(...) at app bootstrap or pass apiRoutes/loadApiRoutes to createAiApiOperationRunner.',\n )\n }\n return registered\n}\n\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["// Phase 1 of spec 2026-04-27-ai-tools-api-backed-dry-refactor.md.\n//\n// In-process API operation runner used by typed AI tools to reuse existing\n// API route handlers without HTTP, fetch, or a second RBAC pass. The runner\n// resolves the matched route entry from the generated `apiRoutes` manifest,\n// validates that the route is documented (`openApi`) and that mutation routes\n// declare `requiredFeatures`, asserts the route's required features are\n// covered by the tool definition, then invokes the route handler directly with\n// a synthetic Request that carries a Symbol-keyed trusted-auth envelope so the\n// shared auth resolver short-circuits cookie/JWT/API-key parsing.\nimport {\n attachTrustedAuthContext,\n type AuthContext,\n type TrustedAuthContextEnvelope,\n} from '@open-mercato/shared/lib/auth/server'\nimport {\n findApiRouteManifestMatch,\n getApiRouteManifests,\n type ApiRouteManifestEntry,\n type RouteMatchParams,\n} from '@open-mercato/shared/modules/registry'\nimport { hasAllFeatures } from '@open-mercato/shared/security/features'\nimport type { AiToolDefinition, McpToolContext } from './types'\n\nexport type AiApiHttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n\nconst MUTATION_METHODS: ReadonlySet<AiApiHttpMethod> = new Set(['POST', 'PUT', 'PATCH', 'DELETE'])\n\nconst SYNTHETIC_ORIGIN = 'http://internal.local'\n\nexport type AiApiOperationRequest = {\n method: AiApiHttpMethod\n path: string\n query?: Record<string, string | number | boolean | null | undefined>\n body?: Record<string, unknown>\n allowFeaturelessMutation?: boolean\n}\n\nexport type AiApiOperationResponse<T = unknown> = {\n success: boolean\n statusCode: number\n data?: T\n error?: string\n details?: unknown\n}\n\nexport interface AiToolExecutionContext extends McpToolContext {\n tool: AiToolDefinition\n}\n\nexport type AiApiOperationRunnerOptions = {\n /** Optional override of the API route manifest (used by tests). */\n apiRoutes?: ApiRouteManifestEntry[]\n /** Custom loader for the API route manifest (used by tests). */\n loadApiRoutes?: () => Promise<ApiRouteManifestEntry[]>\n}\n\nexport type AiApiOperationRunner = {\n run<T = unknown>(request: AiApiOperationRequest): Promise<AiApiOperationResponse<T>>\n}\n\ntype ResolvedHandler = (req: Request, ctx?: { params: RouteMatchParams }) => Promise<Response> | Response\n\ntype LoadedRouteModule = Record<string, unknown>\n\ntype MethodMetadata = {\n requireAuth?: boolean\n requireFeatures?: string[]\n}\n\nfunction normalizeMethod(method: string): AiApiHttpMethod {\n const upper = method.toUpperCase()\n if (upper === 'GET' || upper === 'POST' || upper === 'PUT' || upper === 'PATCH' || upper === 'DELETE') {\n return upper\n }\n throw new Error(`Unsupported method \"${method}\"`)\n}\n\n// Exported for unit testing \u2014 see __tests__/ai-api-operation-runner.test.ts.\n// `path` arrives from agent tool inputs (LLM-controlled), so trailing-slash\n// stripping is implemented as a linear character-code scan rather than the\n// /\\/+$/ regex (CodeQL js/polynomial-redos: regex exhibits polynomial\n// backtracking on long runs of `/`). The loop is O(n) regardless of input.\nexport function normalizePath(path: string): string {\n if (typeof path !== 'string' || path.length === 0) return '/'\n const trimmed = path.startsWith('/') ? path : `/${path}`\n let end = trimmed.length\n while (end > 1 && trimmed.charCodeAt(end - 1) === 47 /* '/' */) end--\n return trimmed.slice(0, end)\n}\n\nfunction buildUrl(path: string, query?: AiApiOperationRequest['query']): URL {\n const url = new URL(`${SYNTHETIC_ORIGIN}/api${normalizePath(path)}`)\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value === null || value === undefined) continue\n url.searchParams.append(key, String(value))\n }\n }\n return url\n}\n\nfunction buildAuthEnvelope(ctx: AiToolExecutionContext): TrustedAuthContextEnvelope {\n const userId = ctx.userId\n if (!userId) {\n return { auth: null, status: 'invalid' }\n }\n // MCP api-key contexts use an `api_key:<uuid>` subject (see auth.ts). Surface\n // the bare key UUID as `keyId` so downstream actor logging resolves to a valid\n // UUID \u2014 the CRUD factory computes `actorUserId = auth.keyId ?? auth.sub`, and\n // the access-log schema rejects a non-UUID `actorUserId`. This matches real\n // HTTP api-key auth, where `keyId` is the api key record id.\n const apiKeyId = userId.startsWith('api_key:')\n ? userId.slice('api_key:'.length)\n : undefined\n const auth: AuthContext = {\n sub: userId,\n userId,\n tenantId: ctx.tenantId,\n orgId: ctx.organizationId,\n roles: [],\n isSuperAdmin: ctx.isSuperAdmin,\n ...(apiKeyId ? { keyId: apiKeyId } : {}),\n }\n return { auth, status: 'authenticated' }\n}\n\nfunction pickHandler(entry: ApiRouteManifestEntry, mod: LoadedRouteModule, method: AiApiHttpMethod): ResolvedHandler | null {\n const direct = mod[method]\n if (typeof direct === 'function') return direct as ResolvedHandler\n if (entry.kind === 'legacy') {\n const fallback = mod.default ?? mod.handler\n if (typeof fallback === 'function') return fallback as ResolvedHandler\n }\n return null\n}\n\nfunction extractMethodMetadata(metadata: unknown, method: AiApiHttpMethod): MethodMetadata | null {\n if (!metadata || typeof metadata !== 'object') return null\n const record = metadata as Record<string, unknown>\n const perMethod = record[method]\n const source: Record<string, unknown> = perMethod && typeof perMethod === 'object'\n ? (perMethod as Record<string, unknown>)\n : record\n const result: MethodMetadata = {}\n if (typeof source.requireAuth === 'boolean') {\n result.requireAuth = source.requireAuth\n }\n if (Array.isArray(source.requireFeatures)) {\n const features = source.requireFeatures.filter((entry): entry is string => typeof entry === 'string' && entry.length > 0)\n if (features.length > 0) result.requireFeatures = features\n }\n return result\n}\n\nasync function readResponseBody(res: Response): Promise<unknown> {\n const contentType = res.headers.get('content-type') ?? ''\n if (contentType.includes('application/json')) {\n try {\n return await res.json()\n } catch {\n return null\n }\n }\n try {\n const text = await res.text()\n if (!text) return null\n try {\n return JSON.parse(text)\n } catch {\n return text\n }\n } catch {\n return null\n }\n}\n\nfunction failure(statusCode: number, error: string, details?: unknown): AiApiOperationResponse {\n const response: AiApiOperationResponse = { success: false, statusCode, error }\n if (details !== undefined) response.details = details\n return response\n}\n\nfunction normalizeError(body: unknown): { error: string; details?: unknown } {\n if (body && typeof body === 'object' && !Array.isArray(body)) {\n const record = body as Record<string, unknown>\n const message = typeof record.error === 'string'\n ? record.error\n : typeof record.message === 'string'\n ? record.message\n : null\n if (message) {\n const { error: _ignored, message: _ignoredMessage, ...rest } = record\n void _ignored\n void _ignoredMessage\n return Object.keys(rest).length > 0 ? { error: message, details: rest } : { error: message }\n }\n }\n if (typeof body === 'string' && body.length > 0) {\n return { error: body }\n }\n return { error: 'Request failed' }\n}\n\nexport function createAiApiOperationRunner(\n ctx: AiToolExecutionContext,\n options: AiApiOperationRunnerOptions = {},\n): AiApiOperationRunner {\n let manifestPromise: Promise<ApiRouteManifestEntry[]> | null = null\n\n const loadManifest = async (): Promise<ApiRouteManifestEntry[]> => {\n if (options.apiRoutes) return options.apiRoutes\n if (manifestPromise) return manifestPromise\n const loader = options.loadApiRoutes ?? defaultLoadApiRoutes\n manifestPromise = loader()\n try {\n return await manifestPromise\n } catch (error) {\n manifestPromise = null\n throw error\n }\n }\n\n return {\n async run<T = unknown>(request: AiApiOperationRequest): Promise<AiApiOperationResponse<T>> {\n let method: AiApiHttpMethod\n try {\n method = normalizeMethod(request.method)\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Invalid method'\n return failure(400, message) as AiApiOperationResponse<T>\n }\n const path = normalizePath(request.path)\n\n let routes: ApiRouteManifestEntry[]\n try {\n routes = await loadManifest()\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to load API route manifest'\n return failure(500, `Operation runner manifest unavailable: ${message}`) as AiApiOperationResponse<T>\n }\n\n const match = findApiRouteManifestMatch(routes, method, path)\n if (!match) {\n return failure(\n 404,\n `No documented API route matches ${method} ${path}`,\n ) as AiApiOperationResponse<T>\n }\n\n let mod: LoadedRouteModule\n try {\n mod = (await match.route.load()) as LoadedRouteModule\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to load route module'\n return failure(500, `Failed to load route module: ${message}`) as AiApiOperationResponse<T>\n }\n\n if (!('openApi' in mod) || mod.openApi === undefined || mod.openApi === null) {\n return failure(\n 501,\n `Route ${method} ${path} is undocumented (missing openApi export); refusing to call from AI tool`,\n ) as AiApiOperationResponse<T>\n }\n\n const handler = pickHandler(match.route, mod, method)\n if (!handler) {\n return failure(\n 405,\n `Route ${path} does not export a handler for method ${method}`,\n ) as AiApiOperationResponse<T>\n }\n\n const methodMetadata = extractMethodMetadata(mod.metadata, method)\n const routeFeatures = methodMetadata?.requireFeatures ?? []\n const isMutation = MUTATION_METHODS.has(method)\n\n if (isMutation && routeFeatures.length === 0 && !request.allowFeaturelessMutation) {\n return failure(\n 403,\n `Mutation route ${method} ${path} declares no requiredFeatures; refusing to call without allowFeaturelessMutation opt-in`,\n ) as AiApiOperationResponse<T>\n }\n\n const toolFeatures = ctx.tool.requiredFeatures ?? []\n if (routeFeatures.length > 0 && !hasAllFeatures(toolFeatures, routeFeatures)) {\n return failure(\n 403,\n `AI tool \"${ctx.tool.name}\" requiredFeatures do not cover route ${method} ${path} requiredFeatures`,\n { toolFeatures, routeFeatures },\n ) as AiApiOperationResponse<T>\n }\n\n const url = buildUrl(path, request.query)\n const headers = new Headers()\n const requestInit: RequestInit = { method, headers }\n if (request.body !== undefined && method !== 'GET') {\n headers.set('content-type', 'application/json')\n requestInit.body = JSON.stringify(request.body)\n }\n\n const syntheticRequest = new Request(url, requestInit)\n attachTrustedAuthContext(syntheticRequest, buildAuthEnvelope(ctx))\n\n let response: Response\n try {\n response = await handler(syntheticRequest, { params: match.params })\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Route handler threw'\n return failure(500, message) as AiApiOperationResponse<T>\n }\n\n const status = response.status\n const body = await readResponseBody(response)\n if (status >= 200 && status < 300) {\n return {\n success: true,\n statusCode: status,\n data: body as T,\n }\n }\n const normalized = normalizeError(body)\n return {\n success: false,\n statusCode: status,\n error: normalized.error,\n ...(normalized.details !== undefined ? { details: normalized.details } : {}),\n }\n },\n }\n}\n\nasync function defaultLoadApiRoutes(): Promise<ApiRouteManifestEntry[]> {\n const registered = getApiRouteManifests()\n if (registered.length === 0) {\n throw new Error(\n 'No API route manifest registered. Call registerApiRouteManifests(...) at app bootstrap or pass apiRoutes/loadApiRoutes to createAiApiOperationRunner.',\n )\n }\n return registered\n}\n\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/ai_assistant/lib/ai-overrides.ts"],
4
- "sourcesContent": ["import {\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/2026-04-30-ai-overrides-and-module-disable.md\n */\nimport type { AiAgentDefinition, AiAgentExtension } from './ai-agent-definition'\nimport type { AiToolDefinition } from './types'\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 console.warn(\n `[AI Overrides] Override registers a new agent \"${id}\" \u2014 no base entry to replace.`,\n )\n }\n if (value === null) {\n byId.delete(id)\n continue\n }\n if (!value || typeof value.id !== 'string' || value.id !== id) {\n console.warn(\n `[AI Overrides] Skipping malformed agent override for id \"${id}\" \u2014 id mismatch or missing fields.`,\n )\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 console.warn(\n `[AI Overrides] Skipping malformed tool override for name \"${name}\" \u2014 name mismatch or missing fields.`,\n )\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 {\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\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 console.warn(\n `[AI Overrides] Override registers a new agent \"${id}\" \u2014 no base entry to replace.`,\n )\n }\n if (value === null) {\n byId.delete(id)\n continue\n }\n if (!value || typeof value.id !== 'string' || value.id !== id) {\n console.warn(\n `[AI Overrides] Skipping malformed agent override for id \"${id}\" \u2014 id mismatch or missing fields.`,\n )\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 console.warn(\n `[AI Overrides] Skipping malformed tool override for name \"${name}\" \u2014 name mismatch or missing fields.`,\n )\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
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/ai_assistant/lib/ai-sdk.ts"],
4
- "sourcesContent": ["// Re-export AI SDK functions from the ai-assistant package\nexport { streamText, generateObject, stepCountIs } from 'ai'\nexport { createOpenAI } from '@ai-sdk/openai'\nexport { createAnthropic } from '@ai-sdk/anthropic'\nexport { createGoogleGenerativeAI } from '@ai-sdk/google'\n\n// Side-effect import: registers built-in LLM providers (Anthropic, Google,\n// OpenAI + OpenAI-compatible presets for DeepInfra, Groq, Together, etc.)\n// with the shared `llmProviderRegistry` singleton. Consumers that import\n// from `./ai-sdk` transitively trigger provider bootstrap, so any module\n// using `generateObject` / `streamText` already has the registry populated.\n//\n// @see ./llm-bootstrap.ts\n// @see .ai/specs/2026-04-14-llm-provider-ports-and-adapters.md\nimport './llm-bootstrap'\n"],
4
+ "sourcesContent": ["// Re-export AI SDK functions from the ai-assistant package\nexport { streamText, generateObject, stepCountIs } from 'ai'\nexport { createOpenAI } from '@ai-sdk/openai'\nexport { createAnthropic } from '@ai-sdk/anthropic'\nexport { createGoogleGenerativeAI } from '@ai-sdk/google'\n\n// Side-effect import: registers built-in LLM providers (Anthropic, Google,\n// OpenAI + OpenAI-compatible presets for DeepInfra, Groq, Together, etc.)\n// with the shared `llmProviderRegistry` singleton. Consumers that import\n// from `./ai-sdk` transitively trigger provider bootstrap, so any module\n// using `generateObject` / `streamText` already has the registry populated.\n//\n// @see ./llm-bootstrap.ts\n// @see .ai/specs/implemented/2026-04-14-llm-provider-ports-and-adapters.md\nimport './llm-bootstrap'\n"],
5
5
  "mappings": "AACA,SAAS,YAAY,gBAAgB,mBAAmB;AACxD,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB;AAChC,SAAS,gCAAgC;AAUzC,OAAO;",
6
6
  "names": []
7
7
  }
@@ -46,10 +46,17 @@ function resolveSigner(container) {
46
46
  }
47
47
  async function loadAttachmentRow(em, attachmentId, authContext) {
48
48
  const { Attachment } = await import("@open-mercato/core/modules/attachments/data/entities");
49
+ const where = { id: attachmentId };
50
+ if (!authContext.isSuperAdmin) {
51
+ where.tenantId = authContext.tenantId;
52
+ if (authContext.organizationId != null) {
53
+ where.organizationId = authContext.organizationId;
54
+ }
55
+ }
49
56
  const record = await findOneWithDecryption(
50
57
  em,
51
58
  Attachment,
52
- { id: attachmentId },
59
+ where,
53
60
  void 0,
54
61
  {
55
62
  tenantId: authContext.tenantId,
@@ -74,8 +81,8 @@ async function loadAttachmentRow(em, attachmentId, authContext) {
74
81
  }
75
82
  function rowBelongsToCaller(row, authContext) {
76
83
  if (authContext.isSuperAdmin) return true;
77
- if (row.tenantId && row.tenantId !== authContext.tenantId) return false;
78
- if (row.organizationId && row.organizationId !== authContext.organizationId) return false;
84
+ if (authContext.tenantId == null || row.tenantId !== authContext.tenantId) return false;
85
+ if (authContext.organizationId != null && row.organizationId !== authContext.organizationId) return false;
79
86
  return true;
80
87
  }
81
88
  async function readAttachmentBytes(row) {