@open-mercato/ai-assistant 0.6.5-develop.4863.1.169bfbb3a3 → 0.6.5-develop.4964.1.ae0edca575
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/dist/modules/ai_assistant/__integration__/TC-AI-RUNTIME-OVERRIDES-006-model-picker.spec.js +7 -0
- package/dist/modules/ai_assistant/__integration__/TC-AI-RUNTIME-OVERRIDES-006-model-picker.spec.js.map +2 -2
- package/package.json +6 -6
- package/src/modules/ai_assistant/__integration__/TC-AI-RUNTIME-OVERRIDES-006-model-picker.spec.ts +8 -0
package/dist/modules/ai_assistant/__integration__/TC-AI-RUNTIME-OVERRIDES-006-model-picker.spec.js
CHANGED
|
@@ -136,6 +136,13 @@ test.describe("TC-AI-RUNTIME-OVERRIDES-006: runtime model overrides", () => {
|
|
|
136
136
|
body: JSON.stringify(settingsPayload)
|
|
137
137
|
});
|
|
138
138
|
});
|
|
139
|
+
await page.route("**/api/ai_assistant/ai/agents", async (route) => {
|
|
140
|
+
await route.fulfill({
|
|
141
|
+
status: 200,
|
|
142
|
+
contentType: "application/json",
|
|
143
|
+
body: JSON.stringify(agentsPayload)
|
|
144
|
+
});
|
|
145
|
+
});
|
|
139
146
|
await page.route("**/api/ai_assistant/health", async (route) => {
|
|
140
147
|
await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ status: "ok", url: "http://localhost", mcpUrl: "http://localhost:3001" }) });
|
|
141
148
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/ai_assistant/__integration__/TC-AI-RUNTIME-OVERRIDES-006-model-picker.spec.ts"],
|
|
4
|
-
"sourcesContent": ["import { test, expect } from '@playwright/test';\nimport { login } from '@open-mercato/core/modules/core/__integration__/helpers/auth';\n\n/**\n * TC-AI-RUNTIME-OVERRIDES-006: Phase 4b \u2014 runtime model overrides (ModelPicker,\n * editable settings form, playground resolution panel).\n *\n * Coverage:\n * - /backend/config/ai-assistant/settings page loads with override form\n * - GlobalOverrideForm: provider + model selects, save, clear\n * - PerAgentOverrideList: table rows, source column, Clear override button\n * - /backend/config/ai-assistant/playground: ModelResolutionPanel renders\n * - ModelPicker renders in the playground's <AiChat> composer when the\n * agent allows runtime model override\n * - ModelPicker is absent when allowRuntimeOverride === false\n *\n * All API calls that would hit a real LLM or require a configured provider\n * are intercepted via page.route() stubs.\n */\ntest.describe('TC-AI-RUNTIME-OVERRIDES-006: runtime model overrides', () => {\n const settingsPath = '/backend/config/ai-assistant/settings';\n const playgroundPath = '/backend/config/ai-assistant/playground';\n\n // ---------------------------------------------------------------------------\n // Shared stubs\n // ---------------------------------------------------------------------------\n const settingsPayload = {\n provider: {\n id: 'anthropic',\n name: 'Anthropic',\n model: 'claude-haiku-4-5',\n defaultModel: 'claude-haiku-4-5',\n envKey: 'ANTHROPIC_API_KEY',\n configured: true,\n defaultModels: [\n { id: 'claude-haiku-4-5', name: 'Claude Haiku 4.5' },\n { id: 'claude-sonnet-4-5', name: 'Claude Sonnet 4.5' },\n ],\n },\n availableProviders: [\n {\n id: 'anthropic',\n name: 'Anthropic',\n model: 'claude-haiku-4-5',\n defaultModel: 'claude-haiku-4-5',\n envKey: 'ANTHROPIC_API_KEY',\n configured: true,\n defaultModels: [\n { id: 'claude-haiku-4-5', name: 'Claude Haiku 4.5' },\n { id: 'claude-sonnet-4-5', name: 'Claude Sonnet 4.5' },\n ],\n },\n {\n id: 'openai',\n name: 'OpenAI',\n model: 'gpt-5-mini',\n defaultModel: 'gpt-5-mini',\n envKey: 'OPENAI_API_KEY',\n configured: false,\n defaultModels: [{ id: 'gpt-5-mini', name: 'GPT-5 Mini' }],\n },\n ],\n mcpKeyConfigured: true,\n resolvedDefault: {\n providerId: 'anthropic',\n modelId: 'claude-haiku-4-5',\n baseURL: null,\n source: 'provider_default',\n },\n tenantOverride: null,\n agents: [\n {\n agentId: 'catalog.merchandising_assistant',\n moduleId: 'catalog',\n allowRuntimeOverride: true,\n providerId: 'anthropic',\n modelId: 'claude-haiku-4-5',\n baseURL: null,\n source: 'provider_default',\n },\n {\n agentId: 'customers.account_assistant',\n moduleId: 'customers',\n allowRuntimeOverride: false,\n providerId: 'anthropic',\n modelId: 'claude-sonnet-4-5',\n baseURL: null,\n source: 'tenant_override',\n },\n ],\n };\n\n const agentsPayload = {\n agents: [\n {\n id: 'catalog.merchandising_assistant',\n moduleId: 'catalog',\n label: 'Merchandising Assistant',\n description: 'Catalog merchandising tool.',\n systemPrompt: 'You are a merchandising assistant.',\n executionMode: 'chat',\n mutationPolicy: 'confirm-required',\n readOnly: false,\n maxSteps: 10,\n allowedTools: ['catalog.list_products'],\n tools: [{ name: 'catalog.list_products', displayName: 'List products', isMutation: false, registered: true }],\n requiredFeatures: ['catalog.view'],\n acceptedMediaTypes: [],\n hasOutputSchema: false,\n },\n ],\n total: 1,\n };\n\n // ---------------------------------------------------------------------------\n // Settings page\n // ---------------------------------------------------------------------------\n test.describe('Settings page (/backend/config/ai-assistant/settings)', () => {\n test('renders override form and per-agent resolution table', async ({ page }) => {\n test.setTimeout(120_000);\n await login(page, 'superadmin');\n\n await page.route('**/api/ai_assistant/settings', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify(settingsPayload),\n });\n });\n\n await page.route('**/api/ai_assistant/health', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify({ status: 'ok', url: 'http://localhost', mcpUrl: 'http://localhost:3001' }),\n });\n });\n\n await page.route('**/api/ai_assistant/tools', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify({ tools: [] }),\n });\n });\n\n await page.goto(settingsPath, { waitUntil: 'domcontentloaded' });\n\n // The main settings container should be visible\n const settingsContainer = page.locator('[data-ai-assistant-settings]');\n await expect(settingsContainer).toBeVisible({ timeout: 30_000 });\n\n // Global override form\n const overrideForm = page.locator('[data-ai-settings-override-form]');\n await expect(overrideForm).toBeVisible({ timeout: 15_000 });\n\n // Per-agent override table\n const agentOverridesTable = page.locator('[data-ai-settings-agent-overrides]');\n await expect(agentOverridesTable).toBeVisible({ timeout: 15_000 });\n\n // Both registered agents appear as rows\n const catalogRow = page.locator('[data-ai-settings-agent-row=\"catalog.merchandising_assistant\"]');\n await expect(catalogRow).toBeVisible();\n\n const customersRow = page.locator('[data-ai-settings-agent-row=\"customers.account_assistant\"]');\n await expect(customersRow).toBeVisible();\n });\n\n test('shows Clear override button only for agents with non-default source', async ({ page }) => {\n test.setTimeout(120_000);\n await login(page, 'superadmin');\n\n await page.route('**/api/ai_assistant/settings', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify(settingsPayload),\n });\n });\n\n await page.route('**/api/ai_assistant/health', async (route) => {\n await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ status: 'ok', url: 'http://localhost', mcpUrl: 'http://localhost:3001' }) });\n });\n\n await page.route('**/api/ai_assistant/tools', async (route) => {\n await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ tools: [] }) });\n });\n\n await page.goto(settingsPath, { waitUntil: 'domcontentloaded' });\n\n const agentOverridesTable = page.locator('[data-ai-settings-agent-overrides]');\n await expect(agentOverridesTable).toBeVisible({ timeout: 30_000 });\n\n // customers.account_assistant has source='tenant_override' \u2192 should have Clear button\n const customersClear = page.locator('[data-ai-settings-clear-agent-override=\"customers.account_assistant\"]');\n await expect(customersClear).toBeVisible();\n\n // catalog.merchandising_assistant has source='provider_default' \u2192 no Clear button\n const catalogClear = page.locator('[data-ai-settings-clear-agent-override=\"catalog.merchandising_assistant\"]');\n await expect(catalogClear).not.toBeVisible();\n });\n\n test('save override calls PUT /api/ai_assistant/settings', async ({ page }) => {\n test.setTimeout(120_000);\n await login(page, 'superadmin');\n\n let putCalls = 0;\n await page.route('**/api/ai_assistant/settings', async (route) => {\n if (route.request().method() === 'PUT') {\n putCalls += 1;\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify({\n id: 'row-1',\n tenantId: 'tenant-1',\n organizationId: 'org-1',\n agentId: null,\n providerId: 'anthropic',\n modelId: 'claude-sonnet-4-5',\n baseUrl: null,\n updatedAt: new Date().toISOString(),\n }),\n });\n return;\n }\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify(settingsPayload),\n });\n });\n\n await page.route('**/api/ai_assistant/health', async (route) => {\n await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ status: 'ok', url: 'http://localhost', mcpUrl: 'http://localhost:3001' }) });\n });\n\n await page.route('**/api/ai_assistant/tools', async (route) => {\n await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ tools: [] }) });\n });\n\n await page.goto(settingsPath, { waitUntil: 'domcontentloaded' });\n\n const overrideForm = page.locator('[data-ai-settings-override-form]');\n await expect(overrideForm).toBeVisible({ timeout: 30_000 });\n\n // Select provider\n const providerSelect = page.locator('[data-ai-settings-provider-select]');\n await providerSelect.click();\n const anthropicOption = page.getByRole('option', { name: 'Anthropic' });\n await anthropicOption.click();\n\n // Select model\n const modelSelect = page.locator('[data-ai-settings-model-select]');\n await modelSelect.click();\n const sonnetOption = page.getByRole('option', { name: 'Claude Sonnet 4.5' });\n await sonnetOption.click();\n\n // Save\n const saveButton = page.locator('[data-ai-settings-save-override]');\n await saveButton.click();\n\n await page.waitForTimeout(500);\n expect(putCalls).toBeGreaterThanOrEqual(1);\n });\n\n test('clear override calls DELETE /api/ai_assistant/settings', async ({ page }) => {\n test.setTimeout(120_000);\n await login(page, 'superadmin');\n\n const settingsWithOverride = {\n ...settingsPayload,\n tenantOverride: {\n providerId: 'anthropic',\n modelId: 'claude-sonnet-4-5',\n baseURL: null,\n agentId: null,\n updatedAt: new Date().toISOString(),\n },\n };\n\n let deleteCalls = 0;\n await page.route('**/api/ai_assistant/settings', async (route) => {\n if (route.request().method() === 'DELETE') {\n deleteCalls += 1;\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify({ cleared: true }),\n });\n return;\n }\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify(settingsWithOverride),\n });\n });\n\n await page.route('**/api/ai_assistant/health', async (route) => {\n await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ status: 'ok', url: 'http://localhost', mcpUrl: 'http://localhost:3001' }) });\n });\n\n await page.route('**/api/ai_assistant/tools', async (route) => {\n await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ tools: [] }) });\n });\n\n await page.goto(settingsPath, { waitUntil: 'domcontentloaded' });\n\n // The \"Clear override\" button for the active override\n const clearButton = page.locator('[data-ai-settings-clear-override]');\n await expect(clearButton).toBeVisible({ timeout: 30_000 });\n await clearButton.click();\n\n await page.waitForTimeout(500);\n expect(deleteCalls).toBeGreaterThanOrEqual(1);\n });\n });\n\n // ---------------------------------------------------------------------------\n // Playground page \u2014 ModelResolutionPanel\n // ---------------------------------------------------------------------------\n test.describe('Playground page (/backend/config/ai-assistant/playground)', () => {\n test('renders ModelResolutionPanel with provider/model/source for the selected agent', async ({\n page,\n }) => {\n test.setTimeout(120_000);\n await login(page, 'superadmin');\n\n await page.route('**/api/ai_assistant/ai/agents', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify(agentsPayload),\n });\n });\n\n await page.route('**/api/ai_assistant/settings', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify(settingsPayload),\n });\n });\n\n await page.goto(playgroundPath, { waitUntil: 'domcontentloaded' });\n\n // Wait for agent list to load\n const agentSection = page.locator('[data-ai-playground-chat=\"catalog.merchandising_assistant\"]');\n await expect(agentSection).toBeVisible({ timeout: 30_000 });\n\n // The resolution panel should show provider info\n const resolutionPanel = page.locator('[data-ai-playground-model-resolution=\"catalog.merchandising_assistant\"]');\n await expect(resolutionPanel).toBeVisible({ timeout: 15_000 });\n\n // Provider field should be present\n const providerField = page.locator('[data-ai-playground-resolution-provider]');\n await expect(providerField).toBeVisible();\n\n // Model field should be present\n const modelField = page.locator('[data-ai-playground-resolution-model]');\n await expect(modelField).toBeVisible();\n\n // Source field should be present\n const sourceField = page.locator('[data-ai-playground-resolution-source]');\n await expect(sourceField).toBeVisible();\n });\n\n test('ModelPicker is present in AiChat composer when allowRuntimeOverride is true', async ({\n page,\n }) => {\n test.setTimeout(120_000);\n await login(page, 'superadmin');\n\n await page.route('**/api/ai_assistant/ai/agents', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify(agentsPayload),\n });\n });\n\n await page.route('**/api/ai_assistant/settings', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify(settingsPayload),\n });\n });\n\n // Stub the models endpoint\n await page.route('**/api/ai_assistant/ai/agents/*/models', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify({\n agentId: 'catalog.merchandising_assistant',\n allowRuntimeOverride: true,\n defaultProviderId: 'anthropic',\n defaultModelId: 'claude-haiku-4-5',\n providers: [\n {\n id: 'anthropic',\n name: 'Anthropic',\n isDefault: true,\n models: [\n { id: 'claude-haiku-4-5', name: 'Claude Haiku 4.5', isDefault: true },\n ],\n },\n ],\n }),\n });\n });\n\n await page.goto(playgroundPath, { waitUntil: 'domcontentloaded' });\n\n // Wait for the chat area to be visible under the selected agent\n const chatContainer = page.locator('[data-ai-playground-chat=\"catalog.merchandising_assistant\"]');\n await expect(chatContainer).toBeVisible({ timeout: 30_000 });\n\n // The ModelPicker trigger should be visible inside the chat container\n const modelPickerTrigger = chatContainer.locator('[data-ai-model-picker-trigger]');\n // Use a soft assertion \u2014 the picker requires the models endpoint to resolve;\n // if the CI environment skips the endpoint, we verify the playground itself loaded.\n const pickerVisible = await modelPickerTrigger.isVisible().catch(() => false);\n if (pickerVisible) {\n await expect(modelPickerTrigger).toBeVisible();\n } else {\n // At minimum the chat area must be visible\n await expect(chatContainer).toBeVisible();\n }\n });\n });\n\n // ---------------------------------------------------------------------------\n // API contract tests (no browser needed)\n // ---------------------------------------------------------------------------\n test.describe('API contract \u2014 GET /api/ai_assistant/settings', () => {\n test('unauthenticated request returns 401 or redirect', async ({ request }) => {\n const response = await request.get('/api/ai_assistant/settings');\n expect([200, 401, 302, 403]).toContain(response.status());\n });\n });\n\n test.describe('API contract \u2014 PUT /api/ai_assistant/settings', () => {\n test('unauthenticated PUT returns 401', async ({ request }) => {\n const response = await request.put('/api/ai_assistant/settings', {\n data: { providerId: 'anthropic', modelId: 'claude-haiku-4-5' },\n headers: { 'content-type': 'application/json' },\n });\n expect([400, 401, 403]).toContain(response.status());\n });\n });\n\n test.describe('API contract \u2014 DELETE /api/ai_assistant/settings', () => {\n test('unauthenticated DELETE returns 401', async ({ request }) => {\n const response = await request.delete('/api/ai_assistant/settings', {\n data: {},\n headers: { 'content-type': 'application/json' },\n });\n expect([400, 401, 403]).toContain(response.status());\n });\n });\n\n test.describe('API contract \u2014 GET /api/ai_assistant/ai/agents/:agentId/models', () => {\n test('route is mounted and returns 401 or JSON payload', async ({ request }) => {\n const response = await request.get('/api/ai_assistant/ai/agents/catalog.merchandising_assistant/models');\n expect([200, 401, 403]).toContain(response.status());\n if (response.status() === 200) {\n const body = await response.json();\n expect(body).toHaveProperty('agentId');\n expect(body).toHaveProperty('allowRuntimeOverride');\n expect(body).toHaveProperty('providers');\n }\n });\n });\n});\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { test, expect } from '@playwright/test';\nimport { login } from '@open-mercato/core/modules/core/__integration__/helpers/auth';\n\n/**\n * TC-AI-RUNTIME-OVERRIDES-006: Phase 4b \u2014 runtime model overrides (ModelPicker,\n * editable settings form, playground resolution panel).\n *\n * Coverage:\n * - /backend/config/ai-assistant/settings page loads with override form\n * - GlobalOverrideForm: provider + model selects, save, clear\n * - PerAgentOverrideList: table rows, source column, Clear override button\n * - /backend/config/ai-assistant/playground: ModelResolutionPanel renders\n * - ModelPicker renders in the playground's <AiChat> composer when the\n * agent allows runtime model override\n * - ModelPicker is absent when allowRuntimeOverride === false\n *\n * All API calls that would hit a real LLM or require a configured provider\n * are intercepted via page.route() stubs.\n */\ntest.describe('TC-AI-RUNTIME-OVERRIDES-006: runtime model overrides', () => {\n const settingsPath = '/backend/config/ai-assistant/settings';\n const playgroundPath = '/backend/config/ai-assistant/playground';\n\n // ---------------------------------------------------------------------------\n // Shared stubs\n // ---------------------------------------------------------------------------\n const settingsPayload = {\n provider: {\n id: 'anthropic',\n name: 'Anthropic',\n model: 'claude-haiku-4-5',\n defaultModel: 'claude-haiku-4-5',\n envKey: 'ANTHROPIC_API_KEY',\n configured: true,\n defaultModels: [\n { id: 'claude-haiku-4-5', name: 'Claude Haiku 4.5' },\n { id: 'claude-sonnet-4-5', name: 'Claude Sonnet 4.5' },\n ],\n },\n availableProviders: [\n {\n id: 'anthropic',\n name: 'Anthropic',\n model: 'claude-haiku-4-5',\n defaultModel: 'claude-haiku-4-5',\n envKey: 'ANTHROPIC_API_KEY',\n configured: true,\n defaultModels: [\n { id: 'claude-haiku-4-5', name: 'Claude Haiku 4.5' },\n { id: 'claude-sonnet-4-5', name: 'Claude Sonnet 4.5' },\n ],\n },\n {\n id: 'openai',\n name: 'OpenAI',\n model: 'gpt-5-mini',\n defaultModel: 'gpt-5-mini',\n envKey: 'OPENAI_API_KEY',\n configured: false,\n defaultModels: [{ id: 'gpt-5-mini', name: 'GPT-5 Mini' }],\n },\n ],\n mcpKeyConfigured: true,\n resolvedDefault: {\n providerId: 'anthropic',\n modelId: 'claude-haiku-4-5',\n baseURL: null,\n source: 'provider_default',\n },\n tenantOverride: null,\n agents: [\n {\n agentId: 'catalog.merchandising_assistant',\n moduleId: 'catalog',\n allowRuntimeOverride: true,\n providerId: 'anthropic',\n modelId: 'claude-haiku-4-5',\n baseURL: null,\n source: 'provider_default',\n },\n {\n agentId: 'customers.account_assistant',\n moduleId: 'customers',\n allowRuntimeOverride: false,\n providerId: 'anthropic',\n modelId: 'claude-sonnet-4-5',\n baseURL: null,\n source: 'tenant_override',\n },\n ],\n };\n\n const agentsPayload = {\n agents: [\n {\n id: 'catalog.merchandising_assistant',\n moduleId: 'catalog',\n label: 'Merchandising Assistant',\n description: 'Catalog merchandising tool.',\n systemPrompt: 'You are a merchandising assistant.',\n executionMode: 'chat',\n mutationPolicy: 'confirm-required',\n readOnly: false,\n maxSteps: 10,\n allowedTools: ['catalog.list_products'],\n tools: [{ name: 'catalog.list_products', displayName: 'List products', isMutation: false, registered: true }],\n requiredFeatures: ['catalog.view'],\n acceptedMediaTypes: [],\n hasOutputSchema: false,\n },\n ],\n total: 1,\n };\n\n // ---------------------------------------------------------------------------\n // Settings page\n // ---------------------------------------------------------------------------\n test.describe('Settings page (/backend/config/ai-assistant/settings)', () => {\n test('renders override form and per-agent resolution table', async ({ page }) => {\n test.setTimeout(120_000);\n await login(page, 'superadmin');\n\n await page.route('**/api/ai_assistant/settings', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify(settingsPayload),\n });\n });\n\n await page.route('**/api/ai_assistant/health', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify({ status: 'ok', url: 'http://localhost', mcpUrl: 'http://localhost:3001' }),\n });\n });\n\n await page.route('**/api/ai_assistant/tools', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify({ tools: [] }),\n });\n });\n\n await page.goto(settingsPath, { waitUntil: 'domcontentloaded' });\n\n // The main settings container should be visible\n const settingsContainer = page.locator('[data-ai-assistant-settings]');\n await expect(settingsContainer).toBeVisible({ timeout: 30_000 });\n\n // Global override form\n const overrideForm = page.locator('[data-ai-settings-override-form]');\n await expect(overrideForm).toBeVisible({ timeout: 15_000 });\n\n // Per-agent override table\n const agentOverridesTable = page.locator('[data-ai-settings-agent-overrides]');\n await expect(agentOverridesTable).toBeVisible({ timeout: 15_000 });\n\n // Both registered agents appear as rows\n const catalogRow = page.locator('[data-ai-settings-agent-row=\"catalog.merchandising_assistant\"]');\n await expect(catalogRow).toBeVisible();\n\n const customersRow = page.locator('[data-ai-settings-agent-row=\"customers.account_assistant\"]');\n await expect(customersRow).toBeVisible();\n });\n\n test('shows Clear override button only for agents with non-default source', async ({ page }) => {\n test.setTimeout(120_000);\n await login(page, 'superadmin');\n\n await page.route('**/api/ai_assistant/settings', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify(settingsPayload),\n });\n });\n\n await page.route('**/api/ai_assistant/ai/agents', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify(agentsPayload),\n });\n });\n\n await page.route('**/api/ai_assistant/health', async (route) => {\n await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ status: 'ok', url: 'http://localhost', mcpUrl: 'http://localhost:3001' }) });\n });\n\n await page.route('**/api/ai_assistant/tools', async (route) => {\n await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ tools: [] }) });\n });\n\n await page.goto(settingsPath, { waitUntil: 'domcontentloaded' });\n\n const agentOverridesTable = page.locator('[data-ai-settings-agent-overrides]');\n await expect(agentOverridesTable).toBeVisible({ timeout: 30_000 });\n\n // customers.account_assistant has source='tenant_override' \u2192 should have Clear button\n const customersClear = page.locator('[data-ai-settings-clear-agent-override=\"customers.account_assistant\"]');\n await expect(customersClear).toBeVisible();\n\n // catalog.merchandising_assistant has source='provider_default' \u2192 no Clear button\n const catalogClear = page.locator('[data-ai-settings-clear-agent-override=\"catalog.merchandising_assistant\"]');\n await expect(catalogClear).not.toBeVisible();\n });\n\n test('save override calls PUT /api/ai_assistant/settings', async ({ page }) => {\n test.setTimeout(120_000);\n await login(page, 'superadmin');\n\n let putCalls = 0;\n await page.route('**/api/ai_assistant/settings', async (route) => {\n if (route.request().method() === 'PUT') {\n putCalls += 1;\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify({\n id: 'row-1',\n tenantId: 'tenant-1',\n organizationId: 'org-1',\n agentId: null,\n providerId: 'anthropic',\n modelId: 'claude-sonnet-4-5',\n baseUrl: null,\n updatedAt: new Date().toISOString(),\n }),\n });\n return;\n }\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify(settingsPayload),\n });\n });\n\n await page.route('**/api/ai_assistant/health', async (route) => {\n await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ status: 'ok', url: 'http://localhost', mcpUrl: 'http://localhost:3001' }) });\n });\n\n await page.route('**/api/ai_assistant/tools', async (route) => {\n await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ tools: [] }) });\n });\n\n await page.goto(settingsPath, { waitUntil: 'domcontentloaded' });\n\n const overrideForm = page.locator('[data-ai-settings-override-form]');\n await expect(overrideForm).toBeVisible({ timeout: 30_000 });\n\n // Select provider\n const providerSelect = page.locator('[data-ai-settings-provider-select]');\n await providerSelect.click();\n const anthropicOption = page.getByRole('option', { name: 'Anthropic' });\n await anthropicOption.click();\n\n // Select model\n const modelSelect = page.locator('[data-ai-settings-model-select]');\n await modelSelect.click();\n const sonnetOption = page.getByRole('option', { name: 'Claude Sonnet 4.5' });\n await sonnetOption.click();\n\n // Save\n const saveButton = page.locator('[data-ai-settings-save-override]');\n await saveButton.click();\n\n await page.waitForTimeout(500);\n expect(putCalls).toBeGreaterThanOrEqual(1);\n });\n\n test('clear override calls DELETE /api/ai_assistant/settings', async ({ page }) => {\n test.setTimeout(120_000);\n await login(page, 'superadmin');\n\n const settingsWithOverride = {\n ...settingsPayload,\n tenantOverride: {\n providerId: 'anthropic',\n modelId: 'claude-sonnet-4-5',\n baseURL: null,\n agentId: null,\n updatedAt: new Date().toISOString(),\n },\n };\n\n let deleteCalls = 0;\n await page.route('**/api/ai_assistant/settings', async (route) => {\n if (route.request().method() === 'DELETE') {\n deleteCalls += 1;\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify({ cleared: true }),\n });\n return;\n }\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify(settingsWithOverride),\n });\n });\n\n await page.route('**/api/ai_assistant/health', async (route) => {\n await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ status: 'ok', url: 'http://localhost', mcpUrl: 'http://localhost:3001' }) });\n });\n\n await page.route('**/api/ai_assistant/tools', async (route) => {\n await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ tools: [] }) });\n });\n\n await page.goto(settingsPath, { waitUntil: 'domcontentloaded' });\n\n // The \"Clear override\" button for the active override\n const clearButton = page.locator('[data-ai-settings-clear-override]');\n await expect(clearButton).toBeVisible({ timeout: 30_000 });\n await clearButton.click();\n\n await page.waitForTimeout(500);\n expect(deleteCalls).toBeGreaterThanOrEqual(1);\n });\n });\n\n // ---------------------------------------------------------------------------\n // Playground page \u2014 ModelResolutionPanel\n // ---------------------------------------------------------------------------\n test.describe('Playground page (/backend/config/ai-assistant/playground)', () => {\n test('renders ModelResolutionPanel with provider/model/source for the selected agent', async ({\n page,\n }) => {\n test.setTimeout(120_000);\n await login(page, 'superadmin');\n\n await page.route('**/api/ai_assistant/ai/agents', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify(agentsPayload),\n });\n });\n\n await page.route('**/api/ai_assistant/settings', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify(settingsPayload),\n });\n });\n\n await page.goto(playgroundPath, { waitUntil: 'domcontentloaded' });\n\n // Wait for agent list to load\n const agentSection = page.locator('[data-ai-playground-chat=\"catalog.merchandising_assistant\"]');\n await expect(agentSection).toBeVisible({ timeout: 30_000 });\n\n // The resolution panel should show provider info\n const resolutionPanel = page.locator('[data-ai-playground-model-resolution=\"catalog.merchandising_assistant\"]');\n await expect(resolutionPanel).toBeVisible({ timeout: 15_000 });\n\n // Provider field should be present\n const providerField = page.locator('[data-ai-playground-resolution-provider]');\n await expect(providerField).toBeVisible();\n\n // Model field should be present\n const modelField = page.locator('[data-ai-playground-resolution-model]');\n await expect(modelField).toBeVisible();\n\n // Source field should be present\n const sourceField = page.locator('[data-ai-playground-resolution-source]');\n await expect(sourceField).toBeVisible();\n });\n\n test('ModelPicker is present in AiChat composer when allowRuntimeOverride is true', async ({\n page,\n }) => {\n test.setTimeout(120_000);\n await login(page, 'superadmin');\n\n await page.route('**/api/ai_assistant/ai/agents', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify(agentsPayload),\n });\n });\n\n await page.route('**/api/ai_assistant/settings', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify(settingsPayload),\n });\n });\n\n // Stub the models endpoint\n await page.route('**/api/ai_assistant/ai/agents/*/models', async (route) => {\n await route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify({\n agentId: 'catalog.merchandising_assistant',\n allowRuntimeOverride: true,\n defaultProviderId: 'anthropic',\n defaultModelId: 'claude-haiku-4-5',\n providers: [\n {\n id: 'anthropic',\n name: 'Anthropic',\n isDefault: true,\n models: [\n { id: 'claude-haiku-4-5', name: 'Claude Haiku 4.5', isDefault: true },\n ],\n },\n ],\n }),\n });\n });\n\n await page.goto(playgroundPath, { waitUntil: 'domcontentloaded' });\n\n // Wait for the chat area to be visible under the selected agent\n const chatContainer = page.locator('[data-ai-playground-chat=\"catalog.merchandising_assistant\"]');\n await expect(chatContainer).toBeVisible({ timeout: 30_000 });\n\n // The ModelPicker trigger should be visible inside the chat container\n const modelPickerTrigger = chatContainer.locator('[data-ai-model-picker-trigger]');\n // Use a soft assertion \u2014 the picker requires the models endpoint to resolve;\n // if the CI environment skips the endpoint, we verify the playground itself loaded.\n const pickerVisible = await modelPickerTrigger.isVisible().catch(() => false);\n if (pickerVisible) {\n await expect(modelPickerTrigger).toBeVisible();\n } else {\n // At minimum the chat area must be visible\n await expect(chatContainer).toBeVisible();\n }\n });\n });\n\n // ---------------------------------------------------------------------------\n // API contract tests (no browser needed)\n // ---------------------------------------------------------------------------\n test.describe('API contract \u2014 GET /api/ai_assistant/settings', () => {\n test('unauthenticated request returns 401 or redirect', async ({ request }) => {\n const response = await request.get('/api/ai_assistant/settings');\n expect([200, 401, 302, 403]).toContain(response.status());\n });\n });\n\n test.describe('API contract \u2014 PUT /api/ai_assistant/settings', () => {\n test('unauthenticated PUT returns 401', async ({ request }) => {\n const response = await request.put('/api/ai_assistant/settings', {\n data: { providerId: 'anthropic', modelId: 'claude-haiku-4-5' },\n headers: { 'content-type': 'application/json' },\n });\n expect([400, 401, 403]).toContain(response.status());\n });\n });\n\n test.describe('API contract \u2014 DELETE /api/ai_assistant/settings', () => {\n test('unauthenticated DELETE returns 401', async ({ request }) => {\n const response = await request.delete('/api/ai_assistant/settings', {\n data: {},\n headers: { 'content-type': 'application/json' },\n });\n expect([400, 401, 403]).toContain(response.status());\n });\n });\n\n test.describe('API contract \u2014 GET /api/ai_assistant/ai/agents/:agentId/models', () => {\n test('route is mounted and returns 401 or JSON payload', async ({ request }) => {\n const response = await request.get('/api/ai_assistant/ai/agents/catalog.merchandising_assistant/models');\n expect([200, 401, 403]).toContain(response.status());\n if (response.status() === 200) {\n const body = await response.json();\n expect(body).toHaveProperty('agentId');\n expect(body).toHaveProperty('allowRuntimeOverride');\n expect(body).toHaveProperty('providers');\n }\n });\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/ai-assistant",
|
|
3
|
-
"version": "0.6.5-develop.
|
|
3
|
+
"version": "0.6.5-develop.4964.1.ae0edca575",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.0.0"
|
|
@@ -98,16 +98,16 @@
|
|
|
98
98
|
"zod-to-json-schema": "^3.25.2"
|
|
99
99
|
},
|
|
100
100
|
"peerDependencies": {
|
|
101
|
-
"@open-mercato/shared": "0.6.5-develop.
|
|
102
|
-
"@open-mercato/ui": "0.6.5-develop.
|
|
101
|
+
"@open-mercato/shared": "0.6.5-develop.4964.1.ae0edca575",
|
|
102
|
+
"@open-mercato/ui": "0.6.5-develop.4964.1.ae0edca575",
|
|
103
103
|
"react": "^19.0.0",
|
|
104
104
|
"react-dom": "^19.0.0",
|
|
105
105
|
"zod": ">=3.23.0"
|
|
106
106
|
},
|
|
107
107
|
"devDependencies": {
|
|
108
|
-
"@open-mercato/cli": "0.6.5-develop.
|
|
109
|
-
"@open-mercato/shared": "0.6.5-develop.
|
|
110
|
-
"@open-mercato/ui": "0.6.5-develop.
|
|
108
|
+
"@open-mercato/cli": "0.6.5-develop.4964.1.ae0edca575",
|
|
109
|
+
"@open-mercato/shared": "0.6.5-develop.4964.1.ae0edca575",
|
|
110
|
+
"@open-mercato/ui": "0.6.5-develop.4964.1.ae0edca575",
|
|
111
111
|
"@types/react": "^19.2.16",
|
|
112
112
|
"@types/react-dom": "^19.2.3",
|
|
113
113
|
"react": "19.2.7",
|
package/src/modules/ai_assistant/__integration__/TC-AI-RUNTIME-OVERRIDES-006-model-picker.spec.ts
CHANGED
|
@@ -178,6 +178,14 @@ test.describe('TC-AI-RUNTIME-OVERRIDES-006: runtime model overrides', () => {
|
|
|
178
178
|
});
|
|
179
179
|
});
|
|
180
180
|
|
|
181
|
+
await page.route('**/api/ai_assistant/ai/agents', async (route) => {
|
|
182
|
+
await route.fulfill({
|
|
183
|
+
status: 200,
|
|
184
|
+
contentType: 'application/json',
|
|
185
|
+
body: JSON.stringify(agentsPayload),
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
181
189
|
await page.route('**/api/ai_assistant/health', async (route) => {
|
|
182
190
|
await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ status: 'ok', url: 'http://localhost', mcpUrl: 'http://localhost:3001' }) });
|
|
183
191
|
});
|