@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,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pending-action cancel executor (spec §9.4, Step 5.9).
|
|
3
|
+
*
|
|
4
|
+
* Flips an `AiPendingAction` from `pending → cancelled` and emits the
|
|
5
|
+
* typed `ai.action.cancelled` event via `emitAiAssistantEvent`. Unlike
|
|
6
|
+
* {@link executePendingActionConfirm} the tool handler is NEVER invoked —
|
|
7
|
+
* cancellation is a pure state-machine transition plus an event emission.
|
|
8
|
+
* Any other status short-circuits: already-`cancelled` is idempotent (no
|
|
9
|
+
* second emit, same row returned); `confirmed` / `executing` / `failed`
|
|
10
|
+
* are treated as invariant violations and bubble up as 409 via the route.
|
|
11
|
+
*
|
|
12
|
+
* If the row's `expiresAt` is in the past at the time of this call we
|
|
13
|
+
* flip it to `expired` (not `cancelled`) — the Step 5.12 cleanup worker
|
|
14
|
+
* races with this code path and we want a single canonical terminal
|
|
15
|
+
* status for a row that reached its TTL.
|
|
16
|
+
*
|
|
17
|
+
* Idempotency: the caller MUST handle the already-`cancelled` branch
|
|
18
|
+
* BEFORE invoking this helper so the event is emitted exactly once per
|
|
19
|
+
* cancellation.
|
|
20
|
+
*/
|
|
21
|
+
import { AiPendingActionRepository } from '../data/repositories/AiPendingActionRepository'
|
|
22
|
+
import type { AiPendingAction } from '../data/entities'
|
|
23
|
+
import { emitAiAssistantEvent } from '../events'
|
|
24
|
+
import type {
|
|
25
|
+
AiActionCancelledPayload,
|
|
26
|
+
AiActionExpiredPayload,
|
|
27
|
+
AiAssistantEventId,
|
|
28
|
+
} from '../events'
|
|
29
|
+
import type { AiPendingActionExecutionResult } from './pending-action-types'
|
|
30
|
+
|
|
31
|
+
export interface PendingActionCancelContext {
|
|
32
|
+
tenantId: string
|
|
33
|
+
organizationId: string | null
|
|
34
|
+
userId: string
|
|
35
|
+
container: import('awilix').AwilixContainer
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type CancelEmitter = (
|
|
39
|
+
eventId: Extract<AiAssistantEventId, 'ai.action.cancelled' | 'ai.action.expired'>,
|
|
40
|
+
payload: AiActionCancelledPayload | AiActionExpiredPayload,
|
|
41
|
+
) => Promise<void>
|
|
42
|
+
|
|
43
|
+
export interface PendingActionCancelInput {
|
|
44
|
+
action: AiPendingAction
|
|
45
|
+
ctx: PendingActionCancelContext
|
|
46
|
+
/** Optional, caller-supplied cancellation reason (already trimmed by the route). */
|
|
47
|
+
reason?: string | null
|
|
48
|
+
repo?: AiPendingActionRepository
|
|
49
|
+
/**
|
|
50
|
+
* Injection seam for unit tests. When omitted, emission is routed via
|
|
51
|
+
* the typed `emitAiAssistantEvent` helper (the normal production path).
|
|
52
|
+
*/
|
|
53
|
+
emitEvent?: CancelEmitter
|
|
54
|
+
now?: Date
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type PendingActionCancelStatus = 'cancelled' | 'expired'
|
|
58
|
+
|
|
59
|
+
export interface PendingActionCancelResult {
|
|
60
|
+
row: AiPendingAction
|
|
61
|
+
status: PendingActionCancelStatus
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const CANCELLED_EVENT_ID = 'ai.action.cancelled' as const
|
|
65
|
+
const EXPIRED_EVENT_ID = 'ai.action.expired' as const
|
|
66
|
+
|
|
67
|
+
const defaultCancelEmitter: CancelEmitter = async (eventId, payload) => {
|
|
68
|
+
await emitAiAssistantEvent(eventId, payload as unknown as Record<string, unknown>, {
|
|
69
|
+
persistent: true,
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function emitEventSafe(
|
|
74
|
+
emitter: CancelEmitter,
|
|
75
|
+
eventId: Parameters<CancelEmitter>[0],
|
|
76
|
+
payload: Parameters<CancelEmitter>[1],
|
|
77
|
+
): Promise<void> {
|
|
78
|
+
try {
|
|
79
|
+
await emitter(eventId, payload)
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.warn(`[AI Pending Action] Failed to emit ${eventId}:`, error)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Atomic `pending → cancelled` transition with TTL-race safety.
|
|
87
|
+
*
|
|
88
|
+
* - If `action.status === 'cancelled'`, returns the current row WITHOUT
|
|
89
|
+
* emitting a second event. Callers should typically short-circuit on
|
|
90
|
+
* this branch BEFORE invoking the helper (see the Step 5.9 route).
|
|
91
|
+
* - If `action.expiresAt <= now`, the row is flipped to `expired` and the
|
|
92
|
+
* `ai.action.expired` event is emitted via the typed
|
|
93
|
+
* `emitAiAssistantEvent` helper (see `../events`). Returns
|
|
94
|
+
* `{ status: 'expired' }` so the route can translate to a 409
|
|
95
|
+
* `expired` envelope.
|
|
96
|
+
* - Otherwise flips `pending → cancelled`, writes `resolvedAt` + the
|
|
97
|
+
* optional cancellation reason onto `executionResult.error`, and emits
|
|
98
|
+
* `ai.action.cancelled`.
|
|
99
|
+
*
|
|
100
|
+
* Any status other than `pending` / `cancelled` is treated as an
|
|
101
|
+
* invariant violation — the route returns 409 `invalid_status` before
|
|
102
|
+
* reaching this helper. If the caller invokes the helper on such a row
|
|
103
|
+
* it will throw via the repo's state-machine guard.
|
|
104
|
+
*/
|
|
105
|
+
export async function executePendingActionCancel(
|
|
106
|
+
input: PendingActionCancelInput,
|
|
107
|
+
): Promise<PendingActionCancelResult> {
|
|
108
|
+
const { action, ctx, now } = input
|
|
109
|
+
const repo = input.repo ?? new AiPendingActionRepository(ctx.container.resolve('em'))
|
|
110
|
+
const scope = {
|
|
111
|
+
tenantId: ctx.tenantId,
|
|
112
|
+
organizationId: ctx.organizationId,
|
|
113
|
+
userId: ctx.userId,
|
|
114
|
+
}
|
|
115
|
+
const clock = now ?? new Date()
|
|
116
|
+
const emitter: CancelEmitter = input.emitEvent ?? defaultCancelEmitter
|
|
117
|
+
|
|
118
|
+
if (action.status === 'cancelled') {
|
|
119
|
+
return { row: action, status: 'cancelled' }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const expiresAt =
|
|
123
|
+
action.expiresAt instanceof Date ? action.expiresAt : new Date(action.expiresAt)
|
|
124
|
+
if (expiresAt.getTime() <= clock.getTime()) {
|
|
125
|
+
const expiredRow = await repo.setStatus(action.id, 'expired', scope, { now: clock })
|
|
126
|
+
const resolvedAtIso =
|
|
127
|
+
(expiredRow.resolvedAt ?? clock).toISOString?.() ?? new Date(clock).toISOString()
|
|
128
|
+
const expiresAtIso =
|
|
129
|
+
(expiresAt ?? clock).toISOString?.() ?? new Date(clock).toISOString()
|
|
130
|
+
const expiredPayload: AiActionExpiredPayload = {
|
|
131
|
+
pendingActionId: expiredRow.id,
|
|
132
|
+
agentId: expiredRow.agentId,
|
|
133
|
+
toolName: expiredRow.toolName,
|
|
134
|
+
status: expiredRow.status,
|
|
135
|
+
tenantId: ctx.tenantId,
|
|
136
|
+
organizationId: ctx.organizationId ?? null,
|
|
137
|
+
userId: ctx.userId,
|
|
138
|
+
resolvedByUserId: null,
|
|
139
|
+
resolvedAt: resolvedAtIso,
|
|
140
|
+
expiresAt: expiresAtIso,
|
|
141
|
+
expiredAt: resolvedAtIso,
|
|
142
|
+
}
|
|
143
|
+
await emitEventSafe(emitter, EXPIRED_EVENT_ID, expiredPayload)
|
|
144
|
+
return { row: expiredRow, status: 'expired' }
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const trimmedReason = typeof input.reason === 'string' ? input.reason.trim() : ''
|
|
148
|
+
const executionResult: AiPendingActionExecutionResult = {
|
|
149
|
+
error: {
|
|
150
|
+
code: 'cancelled_by_user',
|
|
151
|
+
message: trimmedReason.length > 0 ? trimmedReason : 'Cancelled by user',
|
|
152
|
+
},
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const cancelledRow = await repo.setStatus(action.id, 'cancelled', scope, {
|
|
156
|
+
resolvedByUserId: ctx.userId,
|
|
157
|
+
executionResult,
|
|
158
|
+
now: clock,
|
|
159
|
+
})
|
|
160
|
+
const cancelledPayload: AiActionCancelledPayload = {
|
|
161
|
+
pendingActionId: cancelledRow.id,
|
|
162
|
+
agentId: cancelledRow.agentId,
|
|
163
|
+
toolName: cancelledRow.toolName,
|
|
164
|
+
status: cancelledRow.status,
|
|
165
|
+
tenantId: ctx.tenantId,
|
|
166
|
+
organizationId: ctx.organizationId ?? null,
|
|
167
|
+
userId: ctx.userId,
|
|
168
|
+
resolvedByUserId: ctx.userId,
|
|
169
|
+
resolvedAt: (cancelledRow.resolvedAt ?? clock).toISOString?.() ?? new Date(clock).toISOString(),
|
|
170
|
+
executionResult,
|
|
171
|
+
...(trimmedReason.length > 0 ? { reason: trimmedReason } : {}),
|
|
172
|
+
}
|
|
173
|
+
await emitEventSafe(emitter, CANCELLED_EVENT_ID, cancelledPayload)
|
|
174
|
+
|
|
175
|
+
return { row: cancelledRow, status: 'cancelled' }
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export const PENDING_ACTION_CANCELLED_EVENT_ID = CANCELLED_EVENT_ID
|
|
179
|
+
export const PENDING_ACTION_EXPIRED_EVENT_ID = EXPIRED_EVENT_ID
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whitelist-based client serializer for {@link AiPendingAction} (Phase 3 WS-C,
|
|
3
|
+
* Step 5.7). The pending-action table carries server-internal fields
|
|
4
|
+
* (`normalizedInput`, `createdByUserId`, `idempotencyKey`) that MUST NOT be
|
|
5
|
+
* exposed to the browser: `normalizedInput` can contain raw tool arguments
|
|
6
|
+
* including PII or credentials; `createdByUserId` leaks an internal principal
|
|
7
|
+
* when the UI never needs it (the `resolvedByUserId` field is the only
|
|
8
|
+
* actor the UI renders); `idempotencyKey` is a deterministic hash that,
|
|
9
|
+
* combined with `(tenantId, organizationId, agentId)`, lets an attacker
|
|
10
|
+
* collide deduplication windows by crafting identical normalized inputs.
|
|
11
|
+
*
|
|
12
|
+
* This helper is shared by the GET /api/ai/actions/:id reconnect route
|
|
13
|
+
* (Step 5.7) and re-used by the confirm (Step 5.8) and cancel (Step 5.9)
|
|
14
|
+
* response bodies so the UI always sees the same shape.
|
|
15
|
+
*
|
|
16
|
+
* The serializer is deliberately WHITELIST-based: adding a new internal
|
|
17
|
+
* column to the entity must never leak to the client as a side-effect of
|
|
18
|
+
* a generic `{...row}` copy. Any new client-visible field MUST be added
|
|
19
|
+
* here explicitly with a matching update to {@link SerializedPendingAction}.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type {
|
|
23
|
+
AiPendingActionExecutionResult,
|
|
24
|
+
AiPendingActionFailedRecord,
|
|
25
|
+
AiPendingActionFieldDiff,
|
|
26
|
+
AiPendingActionQueueMode,
|
|
27
|
+
AiPendingActionRecordDiff,
|
|
28
|
+
AiPendingActionStatus,
|
|
29
|
+
} from './pending-action-types'
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Client-visible subset of {@link AiPendingAction}. Never includes
|
|
33
|
+
* `normalizedInput`, `createdByUserId`, or `idempotencyKey` — see the
|
|
34
|
+
* module-level doc above.
|
|
35
|
+
*/
|
|
36
|
+
export interface SerializedPendingAction {
|
|
37
|
+
id: string
|
|
38
|
+
agentId: string
|
|
39
|
+
toolName: string
|
|
40
|
+
status: AiPendingActionStatus
|
|
41
|
+
fieldDiff: AiPendingActionFieldDiff[]
|
|
42
|
+
records: AiPendingActionRecordDiff[] | null
|
|
43
|
+
failedRecords: AiPendingActionFailedRecord[] | null
|
|
44
|
+
sideEffectsSummary: string | null
|
|
45
|
+
attachmentIds: string[]
|
|
46
|
+
targetEntityType: string | null
|
|
47
|
+
targetRecordId: string | null
|
|
48
|
+
recordVersion: string | null
|
|
49
|
+
queueMode: AiPendingActionQueueMode
|
|
50
|
+
executionResult: AiPendingActionExecutionResult | null
|
|
51
|
+
createdAt: string
|
|
52
|
+
expiresAt: string
|
|
53
|
+
resolvedAt: string | null
|
|
54
|
+
resolvedByUserId: string | null
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Minimal row shape the serializer accepts. Defined by name rather than
|
|
59
|
+
* importing the entity class directly so this module stays usable in test
|
|
60
|
+
* contexts that stub the ORM row without loading MikroORM decorators.
|
|
61
|
+
*/
|
|
62
|
+
export interface SerializablePendingActionRow {
|
|
63
|
+
id: string
|
|
64
|
+
agentId: string
|
|
65
|
+
toolName: string
|
|
66
|
+
status: AiPendingActionStatus
|
|
67
|
+
fieldDiff?: AiPendingActionFieldDiff[] | null
|
|
68
|
+
records?: AiPendingActionRecordDiff[] | null
|
|
69
|
+
failedRecords?: AiPendingActionFailedRecord[] | null
|
|
70
|
+
sideEffectsSummary?: string | null
|
|
71
|
+
attachmentIds?: string[] | null
|
|
72
|
+
targetEntityType?: string | null
|
|
73
|
+
targetRecordId?: string | null
|
|
74
|
+
recordVersion?: string | null
|
|
75
|
+
queueMode?: AiPendingActionQueueMode | null
|
|
76
|
+
executionResult?: AiPendingActionExecutionResult | null
|
|
77
|
+
createdAt: Date | string
|
|
78
|
+
expiresAt: Date | string
|
|
79
|
+
resolvedAt?: Date | string | null
|
|
80
|
+
resolvedByUserId?: string | null
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function dateToIso(value: Date | string): string {
|
|
84
|
+
if (value instanceof Date) return value.toISOString()
|
|
85
|
+
if (typeof value === 'string') return value
|
|
86
|
+
return new Date().toISOString()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function optionalDateToIso(value: Date | string | null | undefined): string | null {
|
|
90
|
+
if (value == null) return null
|
|
91
|
+
return dateToIso(value)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Build the client-facing view of a pending action. Strips server-internal
|
|
96
|
+
* fields (`normalizedInput`, `createdByUserId`, `idempotencyKey`) and
|
|
97
|
+
* normalizes Date instances to ISO-8601 strings so the result round-trips
|
|
98
|
+
* through JSON without losing precision.
|
|
99
|
+
*/
|
|
100
|
+
export function serializePendingActionForClient(
|
|
101
|
+
row: SerializablePendingActionRow,
|
|
102
|
+
): SerializedPendingAction {
|
|
103
|
+
return {
|
|
104
|
+
id: row.id,
|
|
105
|
+
agentId: row.agentId,
|
|
106
|
+
toolName: row.toolName,
|
|
107
|
+
status: row.status,
|
|
108
|
+
fieldDiff: Array.isArray(row.fieldDiff) ? row.fieldDiff : [],
|
|
109
|
+
records: Array.isArray(row.records) && row.records.length > 0 ? row.records : null,
|
|
110
|
+
failedRecords:
|
|
111
|
+
Array.isArray(row.failedRecords) && row.failedRecords.length > 0
|
|
112
|
+
? row.failedRecords
|
|
113
|
+
: null,
|
|
114
|
+
sideEffectsSummary: row.sideEffectsSummary ?? null,
|
|
115
|
+
attachmentIds: Array.isArray(row.attachmentIds) ? row.attachmentIds : [],
|
|
116
|
+
targetEntityType: row.targetEntityType ?? null,
|
|
117
|
+
targetRecordId: row.targetRecordId ?? null,
|
|
118
|
+
recordVersion: row.recordVersion ?? null,
|
|
119
|
+
queueMode: (row.queueMode ?? 'inline') as AiPendingActionQueueMode,
|
|
120
|
+
executionResult: row.executionResult ?? null,
|
|
121
|
+
createdAt: dateToIso(row.createdAt),
|
|
122
|
+
expiresAt: dateToIso(row.expiresAt),
|
|
123
|
+
resolvedAt: optionalDateToIso(row.resolvedAt),
|
|
124
|
+
resolvedByUserId: row.resolvedByUserId ?? null,
|
|
125
|
+
}
|
|
126
|
+
}
|