@open-mercato/ai-assistant 0.5.1-develop.3036.f02c281f23 → 0.5.1-develop.3045.b4b3320cc2
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.
- package/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +361 -0
- package/README.md +5 -0
- package/dist/index.js +154 -0
- package/dist/index.js.map +2 -2
- package/dist/modules/ai_assistant/__integration__/TC-AI-002-agent-policy.spec.js +73 -0
- package/dist/modules/ai_assistant/__integration__/TC-AI-002-agent-policy.spec.js.map +7 -0
- package/dist/modules/ai_assistant/__integration__/TC-AI-AGENT-SETTINGS-005-settings-page.spec.js +484 -0
- package/dist/modules/ai_assistant/__integration__/TC-AI-AGENT-SETTINGS-005-settings-page.spec.js.map +7 -0
- package/dist/modules/ai_assistant/__integration__/TC-AI-PLAYGROUND-004-playground.spec.js +251 -0
- package/dist/modules/ai_assistant/__integration__/TC-AI-PLAYGROUND-004-playground.spec.js.map +7 -0
- package/dist/modules/ai_assistant/__integration__/TC-INT-AI-TOOLS.spec.js +91 -0
- package/dist/modules/ai_assistant/__integration__/TC-INT-AI-TOOLS.spec.js.map +7 -0
- package/dist/modules/ai_assistant/ai-tools/attachments-pack.js +202 -0
- package/dist/modules/ai_assistant/ai-tools/attachments-pack.js.map +7 -0
- package/dist/modules/ai_assistant/ai-tools/meta-pack.js +121 -0
- package/dist/modules/ai_assistant/ai-tools/meta-pack.js.map +7 -0
- package/dist/modules/ai_assistant/ai-tools/search-pack.js +94 -0
- package/dist/modules/ai_assistant/ai-tools/search-pack.js.map +7 -0
- package/dist/modules/ai_assistant/ai-tools.js +14 -0
- package/dist/modules/ai_assistant/ai-tools.js.map +7 -0
- package/dist/modules/ai_assistant/api/ai/actions/[id]/cancel/route.js +175 -0
- package/dist/modules/ai_assistant/api/ai/actions/[id]/cancel/route.js.map +7 -0
- package/dist/modules/ai_assistant/api/ai/actions/[id]/confirm/route.js +174 -0
- package/dist/modules/ai_assistant/api/ai/actions/[id]/confirm/route.js.map +7 -0
- package/dist/modules/ai_assistant/api/ai/actions/[id]/route.js +101 -0
- package/dist/modules/ai_assistant/api/ai/actions/[id]/route.js.map +7 -0
- package/dist/modules/ai_assistant/api/ai/agents/[agentId]/mutation-policy/route.js +311 -0
- package/dist/modules/ai_assistant/api/ai/agents/[agentId]/mutation-policy/route.js.map +7 -0
- package/dist/modules/ai_assistant/api/ai/agents/[agentId]/prompt-override/route.js +246 -0
- package/dist/modules/ai_assistant/api/ai/agents/[agentId]/prompt-override/route.js.map +7 -0
- package/dist/modules/ai_assistant/api/ai/agents/route.js +94 -0
- package/dist/modules/ai_assistant/api/ai/agents/route.js.map +7 -0
- package/dist/modules/ai_assistant/api/ai/chat/route.js +173 -0
- package/dist/modules/ai_assistant/api/ai/chat/route.js.map +7 -0
- package/dist/modules/ai_assistant/api/ai/run-object/route.js +167 -0
- package/dist/modules/ai_assistant/api/ai/run-object/route.js.map +7 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/AiAgentSettingsPageClient.js +1111 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/AiAgentSettingsPageClient.js.map +7 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/page.js +10 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/page.js.map +7 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/page.meta.js +28 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/page.meta.js.map +7 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/legacy/page.js +10 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/legacy/page.js.map +7 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/legacy/page.meta.js +30 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/legacy/page.meta.js.map +7 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/page.js +4 -6
- package/dist/modules/ai_assistant/backend/config/ai-assistant/page.js.map +2 -2
- package/dist/modules/ai_assistant/backend/config/ai-assistant/page.meta.js +1 -21
- package/dist/modules/ai_assistant/backend/config/ai-assistant/page.meta.js.map +2 -2
- package/dist/modules/ai_assistant/backend/config/ai-assistant/playground/AiPlaygroundPageClient.js +462 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/playground/AiPlaygroundPageClient.js.map +7 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/playground/page.js +10 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/playground/page.js.map +7 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/playground/page.meta.js +28 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/playground/page.meta.js.map +7 -0
- package/dist/modules/ai_assistant/cli.js +78 -12
- package/dist/modules/ai_assistant/cli.js.map +2 -2
- package/dist/modules/ai_assistant/data/entities/AiAgentMutationPolicyOverride.js +5 -0
- package/dist/modules/ai_assistant/data/entities/AiAgentMutationPolicyOverride.js.map +7 -0
- package/dist/modules/ai_assistant/data/entities/AiAgentPromptOverride.js +5 -0
- package/dist/modules/ai_assistant/data/entities/AiAgentPromptOverride.js.map +7 -0
- package/dist/modules/ai_assistant/data/entities/AiPendingAction.js +5 -0
- package/dist/modules/ai_assistant/data/entities/AiPendingAction.js.map +7 -0
- package/dist/modules/ai_assistant/data/entities.js +228 -0
- package/dist/modules/ai_assistant/data/entities.js.map +7 -0
- package/dist/modules/ai_assistant/data/repositories/AiAgentMutationPolicyOverrideRepository.js +95 -0
- package/dist/modules/ai_assistant/data/repositories/AiAgentMutationPolicyOverrideRepository.js.map +7 -0
- package/dist/modules/ai_assistant/data/repositories/AiAgentPromptOverrideRepository.js +95 -0
- package/dist/modules/ai_assistant/data/repositories/AiAgentPromptOverrideRepository.js.map +7 -0
- package/dist/modules/ai_assistant/data/repositories/AiPendingActionRepository.js +223 -0
- package/dist/modules/ai_assistant/data/repositories/AiPendingActionRepository.js.map +7 -0
- package/dist/modules/ai_assistant/events.js +33 -0
- package/dist/modules/ai_assistant/events.js.map +7 -0
- package/dist/modules/ai_assistant/i18n/de.json +252 -0
- package/dist/modules/ai_assistant/i18n/en.json +252 -0
- package/dist/modules/ai_assistant/i18n/es.json +252 -0
- package/dist/modules/ai_assistant/i18n/pl.json +252 -0
- package/dist/modules/ai_assistant/lib/agent-policy.js +168 -0
- package/dist/modules/ai_assistant/lib/agent-policy.js.map +7 -0
- package/dist/modules/ai_assistant/lib/agent-registry.js +195 -0
- package/dist/modules/ai_assistant/lib/agent-registry.js.map +7 -0
- package/dist/modules/ai_assistant/lib/agent-runtime.js +451 -0
- package/dist/modules/ai_assistant/lib/agent-runtime.js.map +7 -0
- package/dist/modules/ai_assistant/lib/agent-tools.js +223 -0
- package/dist/modules/ai_assistant/lib/agent-tools.js.map +7 -0
- package/dist/modules/ai_assistant/lib/agent-transport.js +25 -0
- package/dist/modules/ai_assistant/lib/agent-transport.js.map +7 -0
- package/dist/modules/ai_assistant/lib/ai-agent-definition.js +11 -0
- package/dist/modules/ai_assistant/lib/ai-agent-definition.js.map +7 -0
- package/dist/modules/ai_assistant/lib/ai-agents-generated.d.js +1 -0
- package/dist/modules/ai_assistant/lib/ai-agents-generated.d.js.map +7 -0
- package/dist/modules/ai_assistant/lib/ai-api-operation-runner.js +239 -0
- package/dist/modules/ai_assistant/lib/ai-api-operation-runner.js.map +7 -0
- package/dist/modules/ai_assistant/lib/ai-overrides.js +189 -0
- package/dist/modules/ai_assistant/lib/ai-overrides.js.map +7 -0
- package/dist/modules/ai_assistant/lib/ai-tool-definition.js +7 -0
- package/dist/modules/ai_assistant/lib/ai-tool-definition.js.map +7 -0
- package/dist/modules/ai_assistant/lib/ai-tools-generated.d.js +1 -0
- package/dist/modules/ai_assistant/lib/ai-tools-generated.d.js.map +7 -0
- package/dist/modules/ai_assistant/lib/api-backed-tool.js +48 -0
- package/dist/modules/ai_assistant/lib/api-backed-tool.js.map +7 -0
- package/dist/modules/ai_assistant/lib/attachment-bridge-types.js +1 -0
- package/dist/modules/ai_assistant/lib/attachment-bridge-types.js.map +7 -0
- package/dist/modules/ai_assistant/lib/attachment-parts.js +276 -0
- package/dist/modules/ai_assistant/lib/attachment-parts.js.map +7 -0
- package/dist/modules/ai_assistant/lib/model-factory.js +68 -0
- package/dist/modules/ai_assistant/lib/model-factory.js.map +7 -0
- package/dist/modules/ai_assistant/lib/pending-action-cancel.js +86 -0
- package/dist/modules/ai_assistant/lib/pending-action-cancel.js.map +7 -0
- package/dist/modules/ai_assistant/lib/pending-action-client.js +35 -0
- package/dist/modules/ai_assistant/lib/pending-action-client.js.map +7 -0
- package/dist/modules/ai_assistant/lib/pending-action-executor.js +243 -0
- package/dist/modules/ai_assistant/lib/pending-action-executor.js.map +7 -0
- package/dist/modules/ai_assistant/lib/pending-action-recheck.js +246 -0
- package/dist/modules/ai_assistant/lib/pending-action-recheck.js.map +7 -0
- package/dist/modules/ai_assistant/lib/pending-action-types.js +70 -0
- package/dist/modules/ai_assistant/lib/pending-action-types.js.map +7 -0
- package/dist/modules/ai_assistant/lib/prepare-mutation.js +315 -0
- package/dist/modules/ai_assistant/lib/prepare-mutation.js.map +7 -0
- package/dist/modules/ai_assistant/lib/prompt-composition-types.js +7 -0
- package/dist/modules/ai_assistant/lib/prompt-composition-types.js.map +7 -0
- package/dist/modules/ai_assistant/lib/prompt-override-merge.js +175 -0
- package/dist/modules/ai_assistant/lib/prompt-override-merge.js.map +7 -0
- package/dist/modules/ai_assistant/lib/schema-utils.js +5 -1
- package/dist/modules/ai_assistant/lib/schema-utils.js.map +2 -2
- package/dist/modules/ai_assistant/lib/tool-executor.js +13 -2
- package/dist/modules/ai_assistant/lib/tool-executor.js.map +2 -2
- package/dist/modules/ai_assistant/lib/tool-loader.js +86 -11
- package/dist/modules/ai_assistant/lib/tool-loader.js.map +2 -2
- package/dist/modules/ai_assistant/lib/tool-test-fixtures.js +120 -0
- package/dist/modules/ai_assistant/lib/tool-test-fixtures.js.map +7 -0
- package/dist/modules/ai_assistant/lib/tool-test-runner.js +418 -0
- package/dist/modules/ai_assistant/lib/tool-test-runner.js.map +7 -0
- package/dist/modules/ai_assistant/migrations/Migration20260419100521.js +17 -0
- package/dist/modules/ai_assistant/migrations/Migration20260419100521.js.map +7 -0
- package/dist/modules/ai_assistant/migrations/Migration20260419132948.js +16 -0
- package/dist/modules/ai_assistant/migrations/Migration20260419132948.js.map +7 -0
- package/dist/modules/ai_assistant/migrations/Migration20260419134235.js +17 -0
- package/dist/modules/ai_assistant/migrations/Migration20260419134235.js.map +7 -0
- package/dist/modules/ai_assistant/setup.js +36 -0
- package/dist/modules/ai_assistant/setup.js.map +2 -2
- package/dist/modules/ai_assistant/workers/ai-pending-action-cleanup.js +161 -0
- package/dist/modules/ai_assistant/workers/ai-pending-action-cleanup.js.map +7 -0
- package/generated/entities/ai_agent_mutation_policy_override/index.ts +9 -0
- package/generated/entities/ai_agent_prompt_override/index.ts +10 -0
- package/generated/entities/ai_pending_action/index.ts +24 -0
- package/generated/entities.ids.generated.ts +13 -0
- package/generated/entity-fields-registry.ts +57 -0
- package/jest.config.cjs +7 -0
- package/package.json +4 -4
- package/src/index.ts +215 -0
- package/src/modules/ai_assistant/__integration__/README.md +5 -0
- package/src/modules/ai_assistant/__integration__/TC-AI-002-agent-policy.spec.ts +115 -0
- package/src/modules/ai_assistant/__integration__/TC-AI-AGENT-SETTINGS-005-settings-page.spec.ts +574 -0
- package/src/modules/ai_assistant/__integration__/TC-AI-PLAYGROUND-004-playground.spec.ts +333 -0
- package/src/modules/ai_assistant/__integration__/TC-INT-AI-TOOLS.spec.ts +135 -0
- package/src/modules/ai_assistant/__tests__/events.test.ts +145 -0
- package/src/modules/ai_assistant/__tests__/integration/pending-action-contract.test.ts +1015 -0
- package/src/modules/ai_assistant/__tests__/integration/ws-c-attachment-bridge.test.ts +235 -0
- package/src/modules/ai_assistant/__tests__/integration/ws-c-policy-and-tools.test.ts +330 -0
- package/src/modules/ai_assistant/__tests__/integration/ws-c-tool-pack-coverage.test.ts +285 -0
- package/src/modules/ai_assistant/ai-tools/__tests__/attachments-pack.test.ts +322 -0
- package/src/modules/ai_assistant/ai-tools/__tests__/meta-pack.test.ts +218 -0
- package/src/modules/ai_assistant/ai-tools/__tests__/search-pack.test.ts +192 -0
- package/src/modules/ai_assistant/ai-tools/attachments-pack.ts +269 -0
- package/src/modules/ai_assistant/ai-tools/meta-pack.ts +140 -0
- package/src/modules/ai_assistant/ai-tools/search-pack.ts +122 -0
- package/src/modules/ai_assistant/ai-tools.ts +21 -0
- package/src/modules/ai_assistant/api/ai/actions/[id]/__tests__/route.test.ts +222 -0
- package/src/modules/ai_assistant/api/ai/actions/[id]/cancel/__tests__/route.test.ts +286 -0
- package/src/modules/ai_assistant/api/ai/actions/[id]/cancel/route.ts +237 -0
- package/src/modules/ai_assistant/api/ai/actions/[id]/confirm/__tests__/route.test.ts +339 -0
- package/src/modules/ai_assistant/api/ai/actions/[id]/confirm/route.ts +229 -0
- package/src/modules/ai_assistant/api/ai/actions/[id]/route.ts +142 -0
- package/src/modules/ai_assistant/api/ai/agents/[agentId]/mutation-policy/__tests__/route.test.ts +367 -0
- package/src/modules/ai_assistant/api/ai/agents/[agentId]/mutation-policy/route.ts +380 -0
- package/src/modules/ai_assistant/api/ai/agents/[agentId]/prompt-override/__tests__/route.test.ts +333 -0
- package/src/modules/ai_assistant/api/ai/agents/[agentId]/prompt-override/route.ts +307 -0
- package/src/modules/ai_assistant/api/ai/agents/route.ts +107 -0
- package/src/modules/ai_assistant/api/ai/chat/__tests__/route.test.ts +282 -0
- package/src/modules/ai_assistant/api/ai/chat/route.ts +207 -0
- package/src/modules/ai_assistant/api/ai/run-object/__tests__/route.test.ts +282 -0
- package/src/modules/ai_assistant/api/ai/run-object/route.ts +204 -0
- package/src/modules/ai_assistant/backend/config/ai-assistant/agents/AiAgentSettingsPageClient.tsx +1419 -0
- package/src/modules/ai_assistant/backend/config/ai-assistant/agents/page.meta.ts +26 -0
- package/src/modules/ai_assistant/backend/config/ai-assistant/agents/page.tsx +12 -0
- package/src/modules/ai_assistant/backend/config/ai-assistant/legacy/page.meta.ts +28 -0
- package/src/modules/ai_assistant/backend/config/ai-assistant/legacy/page.tsx +12 -0
- package/src/modules/ai_assistant/backend/config/ai-assistant/page.meta.ts +8 -23
- package/src/modules/ai_assistant/backend/config/ai-assistant/page.tsx +15 -10
- package/src/modules/ai_assistant/backend/config/ai-assistant/playground/AiPlaygroundPageClient.tsx +604 -0
- package/src/modules/ai_assistant/backend/config/ai-assistant/playground/page.meta.ts +26 -0
- package/src/modules/ai_assistant/backend/config/ai-assistant/playground/page.tsx +12 -0
- package/src/modules/ai_assistant/cli.ts +99 -24
- package/src/modules/ai_assistant/data/__tests__/schema-unique-indexes.test.ts +69 -0
- package/src/modules/ai_assistant/data/entities/AiAgentMutationPolicyOverride.ts +7 -0
- package/src/modules/ai_assistant/data/entities/AiAgentPromptOverride.ts +7 -0
- package/src/modules/ai_assistant/data/entities/AiPendingAction.ts +7 -0
- package/src/modules/ai_assistant/data/entities.ts +270 -0
- package/src/modules/ai_assistant/data/repositories/AiAgentMutationPolicyOverrideRepository.ts +129 -0
- package/src/modules/ai_assistant/data/repositories/AiAgentPromptOverrideRepository.ts +132 -0
- package/src/modules/ai_assistant/data/repositories/AiPendingActionRepository.ts +334 -0
- package/src/modules/ai_assistant/data/repositories/__tests__/AiAgentMutationPolicyOverrideRepository.test.ts +195 -0
- package/src/modules/ai_assistant/data/repositories/__tests__/AiAgentPromptOverrideRepository.test.ts +197 -0
- package/src/modules/ai_assistant/data/repositories/__tests__/AiPendingActionRepository.test.ts +357 -0
- package/src/modules/ai_assistant/events.ts +112 -0
- package/src/modules/ai_assistant/i18n/de.json +252 -0
- package/src/modules/ai_assistant/i18n/en.json +252 -0
- package/src/modules/ai_assistant/i18n/es.json +252 -0
- package/src/modules/ai_assistant/i18n/pl.json +252 -0
- package/src/modules/ai_assistant/lib/__tests__/agent-policy.mutation-override.test.ts +203 -0
- package/src/modules/ai_assistant/lib/__tests__/agent-policy.test.ts +385 -0
- package/src/modules/ai_assistant/lib/__tests__/agent-registry.test.ts +217 -0
- package/src/modules/ai_assistant/lib/__tests__/agent-runtime-object.test.ts +329 -0
- package/src/modules/ai_assistant/lib/__tests__/agent-runtime-parity.test.ts +573 -0
- package/src/modules/ai_assistant/lib/__tests__/agent-runtime.test.ts +291 -0
- package/src/modules/ai_assistant/lib/__tests__/agent-tools.test.ts +172 -0
- package/src/modules/ai_assistant/lib/__tests__/agent-transport.test.ts +41 -0
- package/src/modules/ai_assistant/lib/__tests__/ai-agent-definition.test.ts +183 -0
- package/src/modules/ai_assistant/lib/__tests__/ai-api-operation-runner.test.ts +432 -0
- package/src/modules/ai_assistant/lib/__tests__/ai-overrides.test.ts +308 -0
- package/src/modules/ai_assistant/lib/__tests__/api-backed-tool.test.ts +302 -0
- package/src/modules/ai_assistant/lib/__tests__/attachment-bridge-and-prompt-types.test.ts +188 -0
- package/src/modules/ai_assistant/lib/__tests__/attachment-parts.test.ts +531 -0
- package/src/modules/ai_assistant/lib/__tests__/max-steps-budget.integration.test.ts +263 -0
- package/src/modules/ai_assistant/lib/__tests__/model-factory.integration.test.ts +183 -0
- package/src/modules/ai_assistant/lib/__tests__/model-factory.test.ts +168 -0
- package/src/modules/ai_assistant/lib/__tests__/pending-action-cancel.test.ts +235 -0
- package/src/modules/ai_assistant/lib/__tests__/pending-action-client.test.ts +148 -0
- package/src/modules/ai_assistant/lib/__tests__/pending-action-executor.test.ts +348 -0
- package/src/modules/ai_assistant/lib/__tests__/pending-action-recheck.test.ts +378 -0
- package/src/modules/ai_assistant/lib/__tests__/phase-0-additive-contract.test.ts +299 -0
- package/src/modules/ai_assistant/lib/__tests__/prepare-mutation.test.ts +610 -0
- package/src/modules/ai_assistant/lib/__tests__/prompt-override-merge.test.ts +136 -0
- package/src/modules/ai_assistant/lib/__tests__/tool-loader.test.ts +125 -0
- package/src/modules/ai_assistant/lib/agent-policy.ts +270 -0
- package/src/modules/ai_assistant/lib/agent-registry.ts +277 -0
- package/src/modules/ai_assistant/lib/agent-runtime.ts +751 -0
- package/src/modules/ai_assistant/lib/agent-tools.ts +396 -0
- package/src/modules/ai_assistant/lib/agent-transport.ts +51 -0
- package/src/modules/ai_assistant/lib/ai-agent-definition.ts +86 -0
- package/src/modules/ai_assistant/lib/ai-agents-generated.d.ts +18 -0
- package/src/modules/ai_assistant/lib/ai-api-operation-runner.ts +333 -0
- package/src/modules/ai_assistant/lib/ai-overrides.ts +389 -0
- package/src/modules/ai_assistant/lib/ai-tool-definition.ts +7 -0
- package/src/modules/ai_assistant/lib/ai-tools-generated.d.ts +7 -0
- package/src/modules/ai_assistant/lib/api-backed-tool.ts +85 -0
- package/src/modules/ai_assistant/lib/attachment-bridge-types.ts +24 -0
- package/src/modules/ai_assistant/lib/attachment-parts.ts +433 -0
- package/src/modules/ai_assistant/lib/model-factory.ts +212 -0
- package/src/modules/ai_assistant/lib/pending-action-cancel.ts +179 -0
- package/src/modules/ai_assistant/lib/pending-action-client.ts +126 -0
- package/src/modules/ai_assistant/lib/pending-action-executor.ts +424 -0
- package/src/modules/ai_assistant/lib/pending-action-recheck.ts +410 -0
- package/src/modules/ai_assistant/lib/pending-action-types.ts +194 -0
- package/src/modules/ai_assistant/lib/prepare-mutation.ts +448 -0
- package/src/modules/ai_assistant/lib/prompt-composition-types.ts +24 -0
- package/src/modules/ai_assistant/lib/prompt-override-merge.ts +253 -0
- package/src/modules/ai_assistant/lib/schema-utils.ts +14 -2
- package/src/modules/ai_assistant/lib/tool-executor.ts +25 -3
- package/src/modules/ai_assistant/lib/tool-loader.ts +159 -13
- package/src/modules/ai_assistant/lib/tool-test-fixtures.ts +160 -0
- package/src/modules/ai_assistant/lib/tool-test-runner.ts +596 -0
- package/src/modules/ai_assistant/lib/types.ts +105 -2
- package/src/modules/ai_assistant/migrations/.snapshot-open-mercato.json +871 -0
- package/src/modules/ai_assistant/migrations/Migration20260419100521.ts +17 -0
- package/src/modules/ai_assistant/migrations/Migration20260419132948.ts +16 -0
- package/src/modules/ai_assistant/migrations/Migration20260419134235.ts +17 -0
- package/src/modules/ai_assistant/setup.ts +53 -0
- package/src/modules/ai_assistant/workers/__tests__/ai-pending-action-cleanup.test.ts +333 -0
- package/src/modules/ai_assistant/workers/ai-pending-action-cleanup.ts +269 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
+
import type { JobContext, QueuedJob, WorkerMeta } from '@open-mercato/queue'
|
|
3
|
+
import { AiPendingActionRepository } from '../data/repositories/AiPendingActionRepository'
|
|
4
|
+
import type { AiPendingAction } from '../data/entities'
|
|
5
|
+
import {
|
|
6
|
+
emitAiAssistantEvent,
|
|
7
|
+
type AiActionExpiredPayload,
|
|
8
|
+
type AiAssistantEventId,
|
|
9
|
+
} from '../events'
|
|
10
|
+
import { AiPendingActionStateError } from '../lib/pending-action-types'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Periodic cleanup worker for the Phase 3 WS-C mutation approval gate
|
|
14
|
+
* (Step 5.12).
|
|
15
|
+
*
|
|
16
|
+
* Responsibilities:
|
|
17
|
+
* - Sweep every tenant for rows where `status = 'pending'` AND
|
|
18
|
+
* `expires_at < now`. Pending actions expire after
|
|
19
|
+
* `AI_PENDING_ACTION_TTL_SECONDS` (default 15 minutes) — confirm/cancel
|
|
20
|
+
* routes flip them opportunistically, but rows nobody touches again
|
|
21
|
+
* would otherwise sit in `pending` forever.
|
|
22
|
+
* - Atomically transition each expired row `pending → expired` via the
|
|
23
|
+
* repository's state-machine guard. `resolvedByUserId` is `null`
|
|
24
|
+
* because the worker (not a user) is the actor; `resolvedAt` is `now`.
|
|
25
|
+
* - Emit the typed `ai.action.expired` event via
|
|
26
|
+
* {@link emitAiAssistantEvent} for each successful transition so
|
|
27
|
+
* downstream subscribers (UI, audit, metrics) see a single canonical
|
|
28
|
+
* terminal signal.
|
|
29
|
+
*
|
|
30
|
+
* Race safety:
|
|
31
|
+
* - `AiPendingActionRepository.setStatus` enforces the state machine
|
|
32
|
+
* from `pending-action-types.ts`; the legal exits for `pending` are
|
|
33
|
+
* `confirmed`, `cancelled`, `expired`. If a concurrent confirm raced
|
|
34
|
+
* us and flipped the row to `confirmed` (or `executing`), the repo
|
|
35
|
+
* throws {@link AiPendingActionStateError} — we catch, log, and skip,
|
|
36
|
+
* WITHOUT emitting an event for that row (the confirm path already
|
|
37
|
+
* emitted the canonical signal). Same behaviour if the cancel helper
|
|
38
|
+
* beat us via its TTL short-circuit.
|
|
39
|
+
* - Single-row failures NEVER abort the batch — the worker logs and
|
|
40
|
+
* continues to the next row.
|
|
41
|
+
* - Running the worker twice on an already-`expired` row is a no-op:
|
|
42
|
+
* `setStatus(expired)` short-circuits on `existing.status === nextStatus`
|
|
43
|
+
* (see repo), so no second emit.
|
|
44
|
+
*
|
|
45
|
+
* Tenant scoping:
|
|
46
|
+
* - `listExpired` is tenant-scoped, so the worker first discovers the
|
|
47
|
+
* distinct set of `tenant_id` values that have expired pending rows
|
|
48
|
+
* via a narrow native SELECT (no row contents read). It then iterates
|
|
49
|
+
* per tenant, reusing the repo and therefore the encrypted-read
|
|
50
|
+
* contract. Each `setStatus` write carries the row's own tenant
|
|
51
|
+
* scope — there is no cross-tenant write.
|
|
52
|
+
*
|
|
53
|
+
* Pagination:
|
|
54
|
+
* - `listExpired` is called with a bounded page size and looped until
|
|
55
|
+
* the tenant's expired queue drains. A per-tenant loop cap prevents
|
|
56
|
+
* runaway behaviour if new rows keep expiring during the sweep (the
|
|
57
|
+
* next scheduled tick picks up any leftovers).
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
export const metadata: WorkerMeta = {
|
|
61
|
+
queue: 'ai-pending-action-cleanup',
|
|
62
|
+
id: 'ai_assistant:cleanup-expired-pending-actions',
|
|
63
|
+
concurrency: 1,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const DEFAULT_PAGE_SIZE = 100
|
|
67
|
+
const MAX_PAGES_PER_TENANT = 50
|
|
68
|
+
|
|
69
|
+
export type PendingActionCleanupEmitter = (
|
|
70
|
+
eventId: Extract<AiAssistantEventId, 'ai.action.expired'>,
|
|
71
|
+
payload: AiActionExpiredPayload,
|
|
72
|
+
) => Promise<void>
|
|
73
|
+
|
|
74
|
+
const defaultEmitter: PendingActionCleanupEmitter = async (eventId, payload) => {
|
|
75
|
+
await emitAiAssistantEvent(eventId, payload as unknown as Record<string, unknown>, {
|
|
76
|
+
persistent: true,
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface PendingActionCleanupRunOptions {
|
|
81
|
+
em: EntityManager
|
|
82
|
+
repo?: AiPendingActionRepository
|
|
83
|
+
emitEvent?: PendingActionCleanupEmitter
|
|
84
|
+
now?: Date
|
|
85
|
+
pageSize?: number
|
|
86
|
+
/** Injectable tenant-discovery seam for unit tests. */
|
|
87
|
+
discoverTenants?: (em: EntityManager, now: Date) => Promise<TenantScope[]>
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface PendingActionCleanupSummary {
|
|
91
|
+
tenantsScanned: number
|
|
92
|
+
rowsProcessed: number
|
|
93
|
+
rowsExpired: number
|
|
94
|
+
rowsSkipped: number
|
|
95
|
+
rowsErrored: number
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface TenantScope {
|
|
99
|
+
tenantId: string
|
|
100
|
+
organizationId: string | null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function discoverTenantsDefault(
|
|
104
|
+
em: EntityManager,
|
|
105
|
+
now: Date,
|
|
106
|
+
): Promise<TenantScope[]> {
|
|
107
|
+
const connection = em.getConnection()
|
|
108
|
+
const rows = await connection.execute(
|
|
109
|
+
`select distinct "tenant_id", "organization_id"
|
|
110
|
+
from "ai_pending_actions"
|
|
111
|
+
where "status" = 'pending'
|
|
112
|
+
and "expires_at" < ?`,
|
|
113
|
+
[now],
|
|
114
|
+
'all',
|
|
115
|
+
)
|
|
116
|
+
if (!Array.isArray(rows)) return []
|
|
117
|
+
const out: TenantScope[] = []
|
|
118
|
+
for (const row of rows as Array<Record<string, unknown>>) {
|
|
119
|
+
const tenantId = typeof row.tenant_id === 'string' ? row.tenant_id : null
|
|
120
|
+
if (!tenantId) continue
|
|
121
|
+
const organizationId =
|
|
122
|
+
typeof row.organization_id === 'string' ? row.organization_id : null
|
|
123
|
+
out.push({ tenantId, organizationId })
|
|
124
|
+
}
|
|
125
|
+
return out
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function toIso(value: Date | string | null | undefined, fallback: Date): string {
|
|
129
|
+
if (value instanceof Date) return value.toISOString()
|
|
130
|
+
if (typeof value === 'string') {
|
|
131
|
+
const parsed = new Date(value)
|
|
132
|
+
if (!Number.isNaN(parsed.getTime())) return parsed.toISOString()
|
|
133
|
+
}
|
|
134
|
+
return fallback.toISOString()
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function buildExpiredPayload(
|
|
138
|
+
row: AiPendingAction,
|
|
139
|
+
scope: TenantScope,
|
|
140
|
+
clock: Date,
|
|
141
|
+
): AiActionExpiredPayload {
|
|
142
|
+
const resolvedAtIso = toIso(row.resolvedAt ?? clock, clock)
|
|
143
|
+
const expiresAtIso = toIso(row.expiresAt ?? clock, clock)
|
|
144
|
+
return {
|
|
145
|
+
pendingActionId: row.id,
|
|
146
|
+
agentId: row.agentId,
|
|
147
|
+
toolName: row.toolName,
|
|
148
|
+
status: row.status,
|
|
149
|
+
tenantId: scope.tenantId,
|
|
150
|
+
organizationId: scope.organizationId ?? null,
|
|
151
|
+
userId: row.createdByUserId ?? null,
|
|
152
|
+
resolvedByUserId: null,
|
|
153
|
+
resolvedAt: resolvedAtIso,
|
|
154
|
+
expiresAt: expiresAtIso,
|
|
155
|
+
expiredAt: resolvedAtIso,
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export async function runPendingActionCleanup(
|
|
160
|
+
options: PendingActionCleanupRunOptions,
|
|
161
|
+
): Promise<PendingActionCleanupSummary> {
|
|
162
|
+
const clock = options.now ?? new Date()
|
|
163
|
+
const repo = options.repo ?? new AiPendingActionRepository(options.em)
|
|
164
|
+
const emitter = options.emitEvent ?? defaultEmitter
|
|
165
|
+
const pageSize = Math.max(1, Math.min(500, options.pageSize ?? DEFAULT_PAGE_SIZE))
|
|
166
|
+
const discoverTenants = options.discoverTenants ?? discoverTenantsDefault
|
|
167
|
+
|
|
168
|
+
const summary: PendingActionCleanupSummary = {
|
|
169
|
+
tenantsScanned: 0,
|
|
170
|
+
rowsProcessed: 0,
|
|
171
|
+
rowsExpired: 0,
|
|
172
|
+
rowsSkipped: 0,
|
|
173
|
+
rowsErrored: 0,
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
let tenants: TenantScope[] = []
|
|
177
|
+
try {
|
|
178
|
+
tenants = await discoverTenants(options.em, clock)
|
|
179
|
+
} catch (error) {
|
|
180
|
+
console.error(
|
|
181
|
+
'[ai-pending-action-cleanup] Failed to discover tenants:',
|
|
182
|
+
error,
|
|
183
|
+
)
|
|
184
|
+
return summary
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (!tenants.length) return summary
|
|
188
|
+
|
|
189
|
+
for (const scope of tenants) {
|
|
190
|
+
summary.tenantsScanned += 1
|
|
191
|
+
for (let page = 0; page < MAX_PAGES_PER_TENANT; page += 1) {
|
|
192
|
+
let expiredRows: AiPendingAction[]
|
|
193
|
+
try {
|
|
194
|
+
expiredRows = await repo.listExpired(
|
|
195
|
+
{
|
|
196
|
+
tenantId: scope.tenantId,
|
|
197
|
+
organizationId: scope.organizationId,
|
|
198
|
+
userId: null,
|
|
199
|
+
},
|
|
200
|
+
clock,
|
|
201
|
+
pageSize,
|
|
202
|
+
)
|
|
203
|
+
} catch (error) {
|
|
204
|
+
console.error(
|
|
205
|
+
`[ai-pending-action-cleanup] listExpired failed for tenant ${scope.tenantId}:`,
|
|
206
|
+
error,
|
|
207
|
+
)
|
|
208
|
+
break
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (!expiredRows.length) break
|
|
212
|
+
|
|
213
|
+
for (const row of expiredRows) {
|
|
214
|
+
summary.rowsProcessed += 1
|
|
215
|
+
try {
|
|
216
|
+
const updated = await repo.setStatus(
|
|
217
|
+
row.id,
|
|
218
|
+
'expired',
|
|
219
|
+
{
|
|
220
|
+
tenantId: scope.tenantId,
|
|
221
|
+
organizationId: scope.organizationId,
|
|
222
|
+
userId: null,
|
|
223
|
+
},
|
|
224
|
+
{ resolvedByUserId: null, now: clock },
|
|
225
|
+
)
|
|
226
|
+
summary.rowsExpired += 1
|
|
227
|
+
const payload = buildExpiredPayload(updated, scope, clock)
|
|
228
|
+
try {
|
|
229
|
+
await emitter('ai.action.expired', payload)
|
|
230
|
+
} catch (emitError) {
|
|
231
|
+
console.warn(
|
|
232
|
+
`[ai-pending-action-cleanup] Failed to emit ai.action.expired for ${row.id}:`,
|
|
233
|
+
emitError,
|
|
234
|
+
)
|
|
235
|
+
}
|
|
236
|
+
} catch (error) {
|
|
237
|
+
if (error instanceof AiPendingActionStateError) {
|
|
238
|
+
summary.rowsSkipped += 1
|
|
239
|
+
console.info(
|
|
240
|
+
`[ai-pending-action-cleanup] Skipping ${row.id}: concurrent transition ${error.from} → ${error.to} already occurred`,
|
|
241
|
+
)
|
|
242
|
+
continue
|
|
243
|
+
}
|
|
244
|
+
summary.rowsErrored += 1
|
|
245
|
+
console.error(
|
|
246
|
+
`[ai-pending-action-cleanup] Failed to expire ${row.id}:`,
|
|
247
|
+
error,
|
|
248
|
+
)
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (expiredRows.length < pageSize) break
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return summary
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
type HandlerContext = JobContext & {
|
|
260
|
+
resolve: <T = unknown>(name: string) => T
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export default async function handle(
|
|
264
|
+
_job: QueuedJob,
|
|
265
|
+
ctx: HandlerContext,
|
|
266
|
+
): Promise<void> {
|
|
267
|
+
const em = ctx.resolve<EntityManager>('em')
|
|
268
|
+
await runPendingActionCleanup({ em })
|
|
269
|
+
}
|