@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,396 @@
|
|
|
1
|
+
import { dynamicTool, type Tool } from 'ai'
|
|
2
|
+
import type { AwilixContainer } from 'awilix'
|
|
3
|
+
import type { ZodType } from 'zod'
|
|
4
|
+
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
5
|
+
import type { AiAgentDefinition, AiAgentMutationPolicy } from './ai-agent-definition'
|
|
6
|
+
import type { AiChatRequestContext, AiUiPart } from './attachment-bridge-types'
|
|
7
|
+
import type { AiToolDefinition, McpToolContext } from './types'
|
|
8
|
+
import { loadAgentRegistry } from './agent-registry'
|
|
9
|
+
import {
|
|
10
|
+
checkAgentPolicy,
|
|
11
|
+
resolveEffectiveMutationPolicy,
|
|
12
|
+
type AgentPolicyDenyCode,
|
|
13
|
+
} from './agent-policy'
|
|
14
|
+
import { toolRegistry } from './tool-registry'
|
|
15
|
+
import { toSafeZodSchema } from './schema-utils'
|
|
16
|
+
import { prepareMutation } from './prepare-mutation'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Error thrown by `resolveAiAgentTools` (and downstream `runAiAgentText`) when
|
|
20
|
+
* the agent-level policy check denies a request. Carries the structured deny
|
|
21
|
+
* code so HTTP dispatchers can map it to a stable status and JSON body.
|
|
22
|
+
*/
|
|
23
|
+
export class AgentPolicyError extends Error {
|
|
24
|
+
readonly code: AgentPolicyDenyCode
|
|
25
|
+
|
|
26
|
+
constructor(code: AgentPolicyDenyCode, message: string) {
|
|
27
|
+
super(message)
|
|
28
|
+
this.name = 'AgentPolicyError'
|
|
29
|
+
this.code = code
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ResolveAiAgentToolsInput {
|
|
34
|
+
agentId: string
|
|
35
|
+
authContext: AiChatRequestContext
|
|
36
|
+
pageContext?: Record<string, unknown>
|
|
37
|
+
attachmentIds?: string[]
|
|
38
|
+
/**
|
|
39
|
+
* Execution mode the caller intends to run the agent in. Defaults to
|
|
40
|
+
* `'chat'` to preserve the existing chat dispatcher contract. Object-mode
|
|
41
|
+
* callers (see `runAiAgentObject`) MUST pass `'object'` so the policy gate
|
|
42
|
+
* can reject chat-only agents early with `execution_mode_not_supported`.
|
|
43
|
+
*/
|
|
44
|
+
requestedExecutionMode?: 'chat' | 'object'
|
|
45
|
+
/**
|
|
46
|
+
* Optional tenant-scoped mutation-policy DOWNGRADE. When supplied, the
|
|
47
|
+
* effective policy evaluated by `checkAgentPolicy` is the most restrictive
|
|
48
|
+
* of `{ agent.mutationPolicy, mutationPolicyOverride }`. Escalation is
|
|
49
|
+
* rejected at the route layer; this helper trusts callers to pass only
|
|
50
|
+
* values produced by the override repository.
|
|
51
|
+
*/
|
|
52
|
+
mutationPolicyOverride?: AiAgentMutationPolicy | null
|
|
53
|
+
/**
|
|
54
|
+
* DI container used by the `prepareMutation` tool-call wrapper (Step 5.6).
|
|
55
|
+
* When present AND the agent's effective mutation policy is non-read-only,
|
|
56
|
+
* `isMutation: true` tools are intercepted: the runtime creates an
|
|
57
|
+
* `AiPendingAction` row and enqueues a `mutation-preview-card` UI part in
|
|
58
|
+
* the returned {@link ResolvedAgentTools.uiPartQueue} instead of running the
|
|
59
|
+
* tool's handler. When absent, mutation tools degrade-gracefully to the
|
|
60
|
+
* pre-5.6 pass-through adapter — existing read-only agents are unaffected.
|
|
61
|
+
*/
|
|
62
|
+
container?: AwilixContainer
|
|
63
|
+
/**
|
|
64
|
+
* Optional chat-turn correlation id used when hashing the
|
|
65
|
+
* `AiPendingAction.idempotencyKey` so retries of the same mutation collapse
|
|
66
|
+
* to a single row. The chat dispatcher supplies the OpenCode / AI SDK turn
|
|
67
|
+
* id here; when omitted the hash falls back to `null` which still preserves
|
|
68
|
+
* per-tenant/org uniqueness within the TTL window.
|
|
69
|
+
*/
|
|
70
|
+
conversationId?: string | null
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Queue of UI parts the mutation-preview wrapper accumulates during a turn.
|
|
75
|
+
* The chat/object dispatcher flushes these on the next emission boundary
|
|
76
|
+
* (spec §9 allows either direct streaming or this queue pattern — we ship the
|
|
77
|
+
* queue in Step 5.6 and the chat dispatcher will drain it in Step 5.10 when
|
|
78
|
+
* the `mutation-preview-card` component registers). BC: callers that ignore
|
|
79
|
+
* the field are unaffected.
|
|
80
|
+
*/
|
|
81
|
+
export interface AiUiPartQueue {
|
|
82
|
+
/** Pushed by the mutation wrapper; drained by the dispatcher in order. */
|
|
83
|
+
enqueue: (part: AiUiPart) => void
|
|
84
|
+
drain: () => AiUiPart[]
|
|
85
|
+
size: () => number
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function createAiUiPartQueue(): AiUiPartQueue {
|
|
89
|
+
const buffer: AiUiPart[] = []
|
|
90
|
+
return {
|
|
91
|
+
enqueue: (part) => {
|
|
92
|
+
buffer.push(part)
|
|
93
|
+
},
|
|
94
|
+
drain: () => {
|
|
95
|
+
const snapshot = buffer.slice()
|
|
96
|
+
buffer.length = 0
|
|
97
|
+
return snapshot
|
|
98
|
+
},
|
|
99
|
+
size: () => buffer.length,
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface ResolvedAgentTools {
|
|
104
|
+
agent: AiAgentDefinition
|
|
105
|
+
tools: Record<string, Tool<unknown, unknown>>
|
|
106
|
+
/**
|
|
107
|
+
* Per-request UI-part queue the chat dispatcher drains between streamText
|
|
108
|
+
* chunks (Step 5.10 contract). Always present; empty when no mutation-tool
|
|
109
|
+
* calls fire during the turn.
|
|
110
|
+
*/
|
|
111
|
+
uiPartQueue: AiUiPartQueue
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function toPolicyAuthContext(ctx: AiChatRequestContext): {
|
|
115
|
+
userFeatures: string[]
|
|
116
|
+
isSuperAdmin: boolean
|
|
117
|
+
} {
|
|
118
|
+
return {
|
|
119
|
+
userFeatures: ctx.features,
|
|
120
|
+
isSuperAdmin: ctx.isSuperAdmin,
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Sanitize a dotted tool name (e.g. `search.hybrid_search`) into a format
|
|
126
|
+
* accepted by all major LLM providers. OpenAI requires tool names to match
|
|
127
|
+
* `^[a-zA-Z0-9_-]+$`; dots are replaced with double underscores (`__`).
|
|
128
|
+
* Anthropic and Google accept both formats, so this is safe across providers.
|
|
129
|
+
*/
|
|
130
|
+
function sanitizeToolNameForModel(name: string): string {
|
|
131
|
+
return name.replace(/\./g, '__')
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function formatToolResult(result: unknown): string {
|
|
135
|
+
if (result === null || result === undefined) return 'No result returned'
|
|
136
|
+
if (typeof result === 'string') return result
|
|
137
|
+
if (typeof result === 'number' || typeof result === 'boolean') return String(result)
|
|
138
|
+
try {
|
|
139
|
+
return JSON.stringify(result, null, 2)
|
|
140
|
+
} catch {
|
|
141
|
+
return String(result)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function buildToolHandlerContext(
|
|
146
|
+
ctx: AiChatRequestContext,
|
|
147
|
+
container?: AwilixContainer,
|
|
148
|
+
tool?: AiToolDefinition,
|
|
149
|
+
): McpToolContext {
|
|
150
|
+
return {
|
|
151
|
+
tenantId: ctx.tenantId,
|
|
152
|
+
organizationId: ctx.organizationId,
|
|
153
|
+
userId: ctx.userId,
|
|
154
|
+
container: (container ?? undefined) as unknown as McpToolContext['container'],
|
|
155
|
+
userFeatures: ctx.features,
|
|
156
|
+
isSuperAdmin: ctx.isSuperAdmin,
|
|
157
|
+
...(tool ? { tool } : {}),
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
interface MutationInterceptorOptions {
|
|
162
|
+
agent: AiAgentDefinition
|
|
163
|
+
tool: AiToolDefinition
|
|
164
|
+
container: AwilixContainer
|
|
165
|
+
ctx: AiChatRequestContext
|
|
166
|
+
mutationPolicyOverride: AiAgentMutationPolicy | null
|
|
167
|
+
conversationId: string | null
|
|
168
|
+
uiPartQueue: AiUiPartQueue
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function formatPendingActionToolResult(
|
|
172
|
+
agent: AiAgentDefinition,
|
|
173
|
+
tool: AiToolDefinition,
|
|
174
|
+
pendingActionId: string,
|
|
175
|
+
expiresAt: Date,
|
|
176
|
+
): string {
|
|
177
|
+
return formatToolResult({
|
|
178
|
+
status: 'pending-confirmation',
|
|
179
|
+
agentId: agent.id,
|
|
180
|
+
toolName: tool.name,
|
|
181
|
+
pendingActionId,
|
|
182
|
+
expiresAt: expiresAt.toISOString(),
|
|
183
|
+
message: `Awaiting user confirmation for mutation "${tool.name}". The action will NOT run until the user approves it.`,
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Per-call gating decision for the destructive-confirm-required policy.
|
|
189
|
+
* Honors a static boolean OR a predicate evaluated against the actual
|
|
190
|
+
* tool-call args, so a multi-operation tool (e.g.
|
|
191
|
+
* `customers.manage_deal_comment` with `operation: 'create' | 'update'
|
|
192
|
+
* | 'delete'`) can gate only its destructive branches without being
|
|
193
|
+
* split into multiple tools.
|
|
194
|
+
*/
|
|
195
|
+
function resolveIsDestructive(
|
|
196
|
+
isDestructive: boolean | ((input: unknown) => boolean) | undefined,
|
|
197
|
+
args: unknown,
|
|
198
|
+
): boolean {
|
|
199
|
+
if (typeof isDestructive === 'function') {
|
|
200
|
+
try {
|
|
201
|
+
return isDestructive(args) === true
|
|
202
|
+
} catch {
|
|
203
|
+
// If the predicate throws (e.g. unexpected input shape), default to
|
|
204
|
+
// gating — fail-safe for destructive policy.
|
|
205
|
+
return true
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return isDestructive === true
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function adaptToolToAiSdk(
|
|
212
|
+
tool: AiToolDefinition,
|
|
213
|
+
ctx: AiChatRequestContext,
|
|
214
|
+
mutation: MutationInterceptorOptions | null,
|
|
215
|
+
container?: AwilixContainer,
|
|
216
|
+
effectiveMutationPolicy?: 'read-only' | 'confirm-required' | 'destructive-confirm-required',
|
|
217
|
+
): Tool<unknown, unknown> {
|
|
218
|
+
const safeSchema = toSafeZodSchema(tool.inputSchema as ZodType)
|
|
219
|
+
const handlerContext = buildToolHandlerContext(ctx, container, tool)
|
|
220
|
+
return dynamicTool({
|
|
221
|
+
description: tool.description,
|
|
222
|
+
inputSchema: safeSchema,
|
|
223
|
+
execute: async (args: unknown) => {
|
|
224
|
+
// Per-call gating decision. Under `destructive-confirm-required`,
|
|
225
|
+
// tools with a predicate `isDestructive(args)` may flip per call —
|
|
226
|
+
// e.g. comment delete gates while comment create runs direct.
|
|
227
|
+
const requiresApprovalNow = (() => {
|
|
228
|
+
if (!mutation) return false
|
|
229
|
+
if (effectiveMutationPolicy === 'confirm-required') return true
|
|
230
|
+
if (effectiveMutationPolicy === 'destructive-confirm-required') {
|
|
231
|
+
return resolveIsDestructive(mutation.tool.isDestructive, args)
|
|
232
|
+
}
|
|
233
|
+
return false
|
|
234
|
+
})()
|
|
235
|
+
if (mutation && requiresApprovalNow) {
|
|
236
|
+
try {
|
|
237
|
+
const toolCallArgs =
|
|
238
|
+
args && typeof args === 'object' && !Array.isArray(args)
|
|
239
|
+
? { ...(args as Record<string, unknown>) }
|
|
240
|
+
: {}
|
|
241
|
+
const { uiPart, pendingAction } = await prepareMutation(
|
|
242
|
+
{
|
|
243
|
+
agent: mutation.agent,
|
|
244
|
+
tool: mutation.tool,
|
|
245
|
+
toolCallArgs,
|
|
246
|
+
conversationId: mutation.conversationId,
|
|
247
|
+
mutationPolicyOverride: mutation.mutationPolicyOverride,
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
tenantId: mutation.ctx.tenantId,
|
|
251
|
+
organizationId: mutation.ctx.organizationId,
|
|
252
|
+
userId: mutation.ctx.userId,
|
|
253
|
+
features: mutation.ctx.features,
|
|
254
|
+
isSuperAdmin: mutation.ctx.isSuperAdmin,
|
|
255
|
+
container: mutation.container,
|
|
256
|
+
},
|
|
257
|
+
)
|
|
258
|
+
mutation.uiPartQueue.enqueue(uiPart)
|
|
259
|
+
return formatPendingActionToolResult(
|
|
260
|
+
mutation.agent,
|
|
261
|
+
mutation.tool,
|
|
262
|
+
pendingAction.id,
|
|
263
|
+
pendingAction.expiresAt,
|
|
264
|
+
)
|
|
265
|
+
} catch (error) {
|
|
266
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
267
|
+
throw new Error(
|
|
268
|
+
`Tool "${tool.name}" could not be prepared for confirmation: ${message}`,
|
|
269
|
+
)
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
try {
|
|
273
|
+
// Create a fresh container per tool call so the EM is never stale.
|
|
274
|
+
const freshContainer = await createRequestContainer()
|
|
275
|
+
const freshContext: McpToolContext = {
|
|
276
|
+
...handlerContext,
|
|
277
|
+
container: freshContainer as unknown as McpToolContext['container'],
|
|
278
|
+
}
|
|
279
|
+
const { executeTool } = await import('./tool-executor')
|
|
280
|
+
const execResult = await executeTool(tool.name, args, freshContext)
|
|
281
|
+
if (!execResult.success) {
|
|
282
|
+
throw new Error(execResult.error || 'Tool execution failed')
|
|
283
|
+
}
|
|
284
|
+
return formatToolResult(execResult.result)
|
|
285
|
+
} catch (error) {
|
|
286
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
287
|
+
throw new Error(`Tool "${tool.name}" failed: ${message}`)
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
})
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Resolves the agent's whitelisted tools into an AI SDK `tools` map, enforcing
|
|
295
|
+
* the same policy gate as the HTTP dispatcher. Throws {@link AgentPolicyError}
|
|
296
|
+
* on agent-level deny; tool-level denies are skipped with a `console.warn`
|
|
297
|
+
* because the agent author whitelisted a tool the caller is not currently
|
|
298
|
+
* permitted to execute (deterministic non-failure — the remaining tools still
|
|
299
|
+
* reach the model).
|
|
300
|
+
*/
|
|
301
|
+
export async function resolveAiAgentTools(
|
|
302
|
+
input: ResolveAiAgentToolsInput,
|
|
303
|
+
): Promise<ResolvedAgentTools> {
|
|
304
|
+
await loadAgentRegistry()
|
|
305
|
+
|
|
306
|
+
const policyAuth = toPolicyAuthContext(input.authContext)
|
|
307
|
+
const mutationPolicyOverride = input.mutationPolicyOverride ?? null
|
|
308
|
+
const agentDecision = checkAgentPolicy({
|
|
309
|
+
agentId: input.agentId,
|
|
310
|
+
authContext: policyAuth,
|
|
311
|
+
requestedExecutionMode: input.requestedExecutionMode ?? 'chat',
|
|
312
|
+
mutationPolicyOverride,
|
|
313
|
+
})
|
|
314
|
+
if (!agentDecision.ok) {
|
|
315
|
+
throw new AgentPolicyError(agentDecision.code, agentDecision.message)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const { agent } = agentDecision
|
|
319
|
+
const tools: Record<string, Tool<unknown, unknown>> = {}
|
|
320
|
+
const uiPartQueue = createAiUiPartQueue()
|
|
321
|
+
const effectiveMutationPolicy = resolveEffectiveMutationPolicy(
|
|
322
|
+
agent.mutationPolicy,
|
|
323
|
+
mutationPolicyOverride,
|
|
324
|
+
agent.id,
|
|
325
|
+
)
|
|
326
|
+
const canInterceptMutations =
|
|
327
|
+
effectiveMutationPolicy !== 'read-only' && typeof input.container !== 'undefined'
|
|
328
|
+
|
|
329
|
+
for (const toolName of agent.allowedTools) {
|
|
330
|
+
const toolDecision = checkAgentPolicy({
|
|
331
|
+
agentId: input.agentId,
|
|
332
|
+
authContext: policyAuth,
|
|
333
|
+
toolName,
|
|
334
|
+
mutationPolicyOverride,
|
|
335
|
+
})
|
|
336
|
+
if (!toolDecision.ok) {
|
|
337
|
+
console.warn(
|
|
338
|
+
`[AI Agents] Skipping tool "${toolName}" for agent "${agent.id}": ${toolDecision.message}`,
|
|
339
|
+
)
|
|
340
|
+
continue
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const record = (toolDecision.tool ?? toolRegistry.getTool(toolName)) as
|
|
344
|
+
| AiToolDefinition
|
|
345
|
+
| undefined
|
|
346
|
+
if (!record) {
|
|
347
|
+
console.warn(
|
|
348
|
+
`[AI Agents] Tool "${toolName}" vanished from registry between policy checks; skipping.`,
|
|
349
|
+
)
|
|
350
|
+
continue
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
try {
|
|
354
|
+
// For any mutation tool whose policy isn't read-only, prepare the
|
|
355
|
+
// interceptor options once. The actual gate-vs-run-direct decision
|
|
356
|
+
// happens at call time inside `adaptToolToAiSdk` because under
|
|
357
|
+
// `destructive-confirm-required` `isDestructive` may be a predicate
|
|
358
|
+
// evaluated against the per-call args (e.g. a multi-operation
|
|
359
|
+
// tool with `operation: 'create' | 'update' | 'delete'` gates only
|
|
360
|
+
// the destructive branch).
|
|
361
|
+
const mutationOptions: MutationInterceptorOptions | null =
|
|
362
|
+
record.isMutation === true && canInterceptMutations && input.container
|
|
363
|
+
? {
|
|
364
|
+
agent,
|
|
365
|
+
tool: record,
|
|
366
|
+
container: input.container,
|
|
367
|
+
ctx: input.authContext,
|
|
368
|
+
mutationPolicyOverride,
|
|
369
|
+
conversationId: input.conversationId ?? null,
|
|
370
|
+
uiPartQueue,
|
|
371
|
+
}
|
|
372
|
+
: null
|
|
373
|
+
// Sanitize tool name for model API compatibility: OpenAI requires
|
|
374
|
+
// names matching ^[a-zA-Z0-9_-]+$ (no dots). Replace dots with
|
|
375
|
+
// double underscores so `search.hybrid_search` becomes
|
|
376
|
+
// `search__hybrid_search`. The AI SDK uses the record key as the
|
|
377
|
+
// tool name sent to the model; the original dotted name stays on
|
|
378
|
+
// the `tool` object for logging and prepareMutation hashing.
|
|
379
|
+
const modelSafeToolName = sanitizeToolNameForModel(toolName)
|
|
380
|
+
tools[modelSafeToolName] = adaptToolToAiSdk(
|
|
381
|
+
record,
|
|
382
|
+
input.authContext,
|
|
383
|
+
mutationOptions,
|
|
384
|
+
input.container,
|
|
385
|
+
effectiveMutationPolicy,
|
|
386
|
+
)
|
|
387
|
+
} catch (error) {
|
|
388
|
+
console.error(
|
|
389
|
+
`[AI Agents] Failed to adapt tool "${toolName}" for agent "${agent.id}":`,
|
|
390
|
+
error,
|
|
391
|
+
)
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return { agent, tools, uiPartQueue }
|
|
396
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { DefaultChatTransport, type ChatTransport, type UIMessage } from 'ai'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Default dispatcher URL. Mirrors the module-id-prefixed layout emitted by the
|
|
5
|
+
* app router — the spec shorthand `/api/ai/chat` appears in the source spec
|
|
6
|
+
* but the generator maps it to `/api/ai_assistant/ai/chat`. Downstream
|
|
7
|
+
* consumers should import this helper rather than hardcoding the literal.
|
|
8
|
+
*/
|
|
9
|
+
const DEFAULT_ENDPOINT = '/api/ai_assistant/ai/chat'
|
|
10
|
+
|
|
11
|
+
export interface CreateAiAgentTransportInput {
|
|
12
|
+
agentId: string
|
|
13
|
+
endpoint?: string
|
|
14
|
+
body?: Record<string, unknown>
|
|
15
|
+
debug?: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function buildEndpointWithAgentQuery(endpoint: string, agentId: string): string {
|
|
19
|
+
if (!agentId) return endpoint
|
|
20
|
+
const separator = endpoint.includes('?') ? '&' : '?'
|
|
21
|
+
return `${endpoint}${separator}agent=${encodeURIComponent(agentId)}`
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Thin wrapper around `DefaultChatTransport` that binds the agent id as a
|
|
26
|
+
* query parameter and merges any agent-specific body fields into every
|
|
27
|
+
* outbound request. Returned value conforms to the AI SDK's `ChatTransport`
|
|
28
|
+
* contract so consumers can plug it directly into `useChat({ transport })`.
|
|
29
|
+
*
|
|
30
|
+
* TODO: when the AI SDK standardizes agent-binding as a first-class input,
|
|
31
|
+
* this helper can collapse into a one-liner. Until then it owns the
|
|
32
|
+
* endpoint-URL convention so UI callers do not hardcode dispatcher paths.
|
|
33
|
+
*/
|
|
34
|
+
export function createAiAgentTransport<UI_MESSAGE extends UIMessage = UIMessage>(
|
|
35
|
+
input: CreateAiAgentTransportInput,
|
|
36
|
+
): ChatTransport<UI_MESSAGE> {
|
|
37
|
+
const endpoint = buildEndpointWithAgentQuery(
|
|
38
|
+
input.endpoint && input.endpoint.length > 0 ? input.endpoint : DEFAULT_ENDPOINT,
|
|
39
|
+
input.agentId,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
const extraBody: Record<string, unknown> = { ...(input.body ?? {}) }
|
|
43
|
+
if (typeof input.debug === 'boolean') {
|
|
44
|
+
extraBody.debug = input.debug
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return new DefaultChatTransport<UI_MESSAGE>({
|
|
48
|
+
api: endpoint,
|
|
49
|
+
body: extraBody,
|
|
50
|
+
})
|
|
51
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { AwilixContainer } from 'awilix'
|
|
2
|
+
import type { ZodTypeAny } from 'zod'
|
|
3
|
+
|
|
4
|
+
export type AiAgentExecutionMode = 'chat' | 'object'
|
|
5
|
+
|
|
6
|
+
export type AiAgentMutationPolicy =
|
|
7
|
+
| 'read-only'
|
|
8
|
+
| 'confirm-required'
|
|
9
|
+
| 'destructive-confirm-required'
|
|
10
|
+
|
|
11
|
+
export type AiAgentAcceptedMediaType = 'image' | 'pdf' | 'file'
|
|
12
|
+
|
|
13
|
+
export type AiAgentDataOperation = 'read' | 'search' | 'aggregate'
|
|
14
|
+
|
|
15
|
+
export interface AiAgentPageContextInput {
|
|
16
|
+
entityType: string
|
|
17
|
+
recordId: string
|
|
18
|
+
container: AwilixContainer
|
|
19
|
+
tenantId: string | null
|
|
20
|
+
organizationId: string | null
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface AiAgentStructuredOutput<TSchema = ZodTypeAny> {
|
|
24
|
+
schemaName: string
|
|
25
|
+
schema: TSchema
|
|
26
|
+
mode?: 'generate' | 'stream'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface AiAgentDataCapabilities {
|
|
30
|
+
entities?: string[]
|
|
31
|
+
operations?: AiAgentDataOperation[]
|
|
32
|
+
searchableFields?: string[]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface AiAgentSuggestion {
|
|
36
|
+
label: string
|
|
37
|
+
prompt: string
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface AiAgentDefinition {
|
|
41
|
+
id: string
|
|
42
|
+
moduleId: string
|
|
43
|
+
label: string
|
|
44
|
+
description: string
|
|
45
|
+
systemPrompt: string
|
|
46
|
+
allowedTools: string[]
|
|
47
|
+
suggestions?: AiAgentSuggestion[]
|
|
48
|
+
executionMode?: AiAgentExecutionMode
|
|
49
|
+
defaultModel?: string
|
|
50
|
+
acceptedMediaTypes?: AiAgentAcceptedMediaType[]
|
|
51
|
+
requiredFeatures?: string[]
|
|
52
|
+
uiParts?: string[]
|
|
53
|
+
readOnly?: boolean
|
|
54
|
+
mutationPolicy?: AiAgentMutationPolicy
|
|
55
|
+
maxSteps?: number
|
|
56
|
+
output?: AiAgentStructuredOutput
|
|
57
|
+
resolvePageContext?: (ctx: AiAgentPageContextInput) => Promise<string | null>
|
|
58
|
+
keywords?: string[]
|
|
59
|
+
domain?: string
|
|
60
|
+
dataCapabilities?: AiAgentDataCapabilities
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface AiAgentExtension {
|
|
64
|
+
targetAgentId: string
|
|
65
|
+
replaceAllowedTools?: string[]
|
|
66
|
+
deleteAllowedTools?: string[]
|
|
67
|
+
appendAllowedTools?: string[]
|
|
68
|
+
replaceSystemPrompt?: string
|
|
69
|
+
appendSystemPrompt?: string
|
|
70
|
+
replaceSuggestions?: AiAgentSuggestion[]
|
|
71
|
+
deleteSuggestions?: string[]
|
|
72
|
+
appendSuggestions?: AiAgentSuggestion[]
|
|
73
|
+
/**
|
|
74
|
+
* @deprecated Use `appendSuggestions` for new code. Preserved as the
|
|
75
|
+
* original append-only field for backward compatibility.
|
|
76
|
+
*/
|
|
77
|
+
suggestions?: AiAgentSuggestion[]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function defineAiAgent(definition: AiAgentDefinition): AiAgentDefinition {
|
|
81
|
+
return definition
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function defineAiAgentExtension(extension: AiAgentExtension): AiAgentExtension {
|
|
85
|
+
return extension
|
|
86
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
declare module '@/.mercato/generated/ai-agents.generated' {
|
|
2
|
+
export const aiAgentConfigEntries: Array<{
|
|
3
|
+
moduleId: string
|
|
4
|
+
agents: unknown[]
|
|
5
|
+
overrides?: Record<string, unknown>
|
|
6
|
+
extensions?: unknown[]
|
|
7
|
+
}>
|
|
8
|
+
export const allAiAgents: unknown[]
|
|
9
|
+
export const allAiAgentExtensions: unknown[]
|
|
10
|
+
export const aiAgentExtensionEntries: Array<{
|
|
11
|
+
moduleId: string
|
|
12
|
+
extensions: unknown[]
|
|
13
|
+
}>
|
|
14
|
+
export const aiAgentOverrideEntries: Array<{
|
|
15
|
+
moduleId: string
|
|
16
|
+
overrides: Record<string, unknown>
|
|
17
|
+
}>
|
|
18
|
+
}
|