@open-mercato/ai-assistant 0.6.7 → 0.6.8-develop.6874.1.982d6097d8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +12 -29
  3. package/dist/modules/ai_assistant/__integration__/TC-AI-MODERATION-008-settings-and-audit.spec.js +80 -0
  4. package/dist/modules/ai_assistant/__integration__/TC-AI-MODERATION-008-settings-and-audit.spec.js.map +7 -0
  5. package/dist/modules/ai_assistant/__integration__/TC-AI-MODERATION-009-ui.spec.js +124 -0
  6. package/dist/modules/ai_assistant/__integration__/TC-AI-MODERATION-009-ui.spec.js.map +7 -0
  7. package/dist/modules/ai_assistant/__integration__/helpers/aiAssistantFixtures.js +30 -0
  8. package/dist/modules/ai_assistant/__integration__/helpers/aiAssistantFixtures.js.map +2 -2
  9. package/dist/modules/ai_assistant/api/ai/chat/route.js +7 -0
  10. package/dist/modules/ai_assistant/api/ai/chat/route.js.map +2 -2
  11. package/dist/modules/ai_assistant/api/moderation-flags/route.js +121 -0
  12. package/dist/modules/ai_assistant/api/moderation-flags/route.js.map +7 -0
  13. package/dist/modules/ai_assistant/api/settings/allowlist/route.js +10 -10
  14. package/dist/modules/ai_assistant/api/settings/allowlist/route.js.map +2 -2
  15. package/dist/modules/ai_assistant/api/settings/route.js +34 -13
  16. package/dist/modules/ai_assistant/api/settings/route.js.map +2 -2
  17. package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/AiAgentSettingsPageClient.js +121 -15
  18. package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/AiAgentSettingsPageClient.js.map +2 -2
  19. package/dist/modules/ai_assistant/backend/config/ai-assistant/allowlist/AiTenantAllowlistPageClient.js +2 -2
  20. package/dist/modules/ai_assistant/backend/config/ai-assistant/allowlist/AiTenantAllowlistPageClient.js.map +2 -2
  21. package/dist/modules/ai_assistant/backend/config/ai-assistant/moderation-flags/AiModerationFlagsPageClient.js +139 -0
  22. package/dist/modules/ai_assistant/backend/config/ai-assistant/moderation-flags/AiModerationFlagsPageClient.js.map +7 -0
  23. package/dist/modules/ai_assistant/backend/config/ai-assistant/moderation-flags/page.js +10 -0
  24. package/dist/modules/ai_assistant/backend/config/ai-assistant/moderation-flags/page.js.map +7 -0
  25. package/dist/modules/ai_assistant/backend/config/ai-assistant/moderation-flags/page.meta.js +26 -0
  26. package/dist/modules/ai_assistant/backend/config/ai-assistant/moderation-flags/page.meta.js.map +7 -0
  27. package/dist/modules/ai_assistant/backend/config/ai-assistant/playground/AiPlaygroundPageClient.js +4 -4
  28. package/dist/modules/ai_assistant/backend/config/ai-assistant/playground/AiPlaygroundPageClient.js.map +2 -2
  29. package/dist/modules/ai_assistant/data/entities.js +42 -0
  30. package/dist/modules/ai_assistant/data/entities.js.map +2 -2
  31. package/dist/modules/ai_assistant/data/repositories/AiAgentRuntimeOverrideRepository.js +3 -1
  32. package/dist/modules/ai_assistant/data/repositories/AiAgentRuntimeOverrideRepository.js.map +2 -2
  33. package/dist/modules/ai_assistant/data/repositories/AiModerationFlagRepository.js +44 -0
  34. package/dist/modules/ai_assistant/data/repositories/AiModerationFlagRepository.js.map +7 -0
  35. package/dist/modules/ai_assistant/di.js +6 -2
  36. package/dist/modules/ai_assistant/di.js.map +2 -2
  37. package/dist/modules/ai_assistant/events.js +6 -0
  38. package/dist/modules/ai_assistant/events.js.map +2 -2
  39. package/dist/modules/ai_assistant/i18n/de.json +42 -0
  40. package/dist/modules/ai_assistant/i18n/en.json +42 -0
  41. package/dist/modules/ai_assistant/i18n/es.json +42 -0
  42. package/dist/modules/ai_assistant/i18n/ko.json +527 -0
  43. package/dist/modules/ai_assistant/i18n/pl.json +42 -0
  44. package/dist/modules/ai_assistant/lib/agent-runtime.js +158 -5
  45. package/dist/modules/ai_assistant/lib/agent-runtime.js.map +2 -2
  46. package/dist/modules/ai_assistant/lib/ai-agent-definition.js.map +2 -2
  47. package/dist/modules/ai_assistant/lib/auth.js +6 -7
  48. package/dist/modules/ai_assistant/lib/auth.js.map +2 -2
  49. package/dist/modules/ai_assistant/lib/entity-graph.js +3 -3
  50. package/dist/modules/ai_assistant/lib/entity-graph.js.map +2 -2
  51. package/dist/modules/ai_assistant/lib/llm-adapters/anthropic.js +3 -0
  52. package/dist/modules/ai_assistant/lib/llm-adapters/anthropic.js.map +2 -2
  53. package/dist/modules/ai_assistant/lib/llm-adapters/openai.js +8 -1
  54. package/dist/modules/ai_assistant/lib/llm-adapters/openai.js.map +2 -2
  55. package/dist/modules/ai_assistant/lib/model-factory.js +6 -1
  56. package/dist/modules/ai_assistant/lib/model-factory.js.map +2 -2
  57. package/dist/modules/ai_assistant/lib/moderation-flag-recorder.js +43 -0
  58. package/dist/modules/ai_assistant/lib/moderation-flag-recorder.js.map +7 -0
  59. package/dist/modules/ai_assistant/lib/moderation-policy.js +24 -0
  60. package/dist/modules/ai_assistant/lib/moderation-policy.js.map +7 -0
  61. package/dist/modules/ai_assistant/lib/moderation.js +109 -0
  62. package/dist/modules/ai_assistant/lib/moderation.js.map +7 -0
  63. package/dist/modules/ai_assistant/lib/openai-compatible-presets.js +2 -0
  64. package/dist/modules/ai_assistant/lib/openai-compatible-presets.js.map +2 -2
  65. package/dist/modules/ai_assistant/lib/tool-search.js +4 -12
  66. package/dist/modules/ai_assistant/lib/tool-search.js.map +2 -2
  67. package/dist/modules/ai_assistant/migrations/Migration20260610134045_ai_assistant.js +19 -0
  68. package/dist/modules/ai_assistant/migrations/Migration20260610134045_ai_assistant.js.map +7 -0
  69. package/generated/entities/ai_agent_runtime_override/index.ts +1 -0
  70. package/generated/entities/ai_moderation_flag/index.ts +9 -0
  71. package/generated/entities.ids.generated.ts +2 -1
  72. package/generated/entity-fields-registry.ts +13 -1
  73. package/package.json +13 -12
  74. package/src/modules/ai_assistant/__integration__/TC-AI-MODERATION-008-settings-and-audit.spec.ts +126 -0
  75. package/src/modules/ai_assistant/__integration__/TC-AI-MODERATION-009-ui.spec.ts +161 -0
  76. package/src/modules/ai_assistant/__integration__/helpers/aiAssistantFixtures.ts +48 -0
  77. package/src/modules/ai_assistant/api/ai/chat/route.ts +10 -0
  78. package/src/modules/ai_assistant/api/moderation-flags/__tests__/route.test.ts +122 -0
  79. package/src/modules/ai_assistant/api/moderation-flags/route.ts +137 -0
  80. package/src/modules/ai_assistant/api/settings/__tests__/route.test.ts +58 -8
  81. package/src/modules/ai_assistant/api/settings/allowlist/route.ts +10 -12
  82. package/src/modules/ai_assistant/api/settings/route.ts +33 -10
  83. package/src/modules/ai_assistant/backend/config/ai-assistant/agents/AiAgentSettingsPageClient.tsx +161 -15
  84. package/src/modules/ai_assistant/backend/config/ai-assistant/allowlist/AiTenantAllowlistPageClient.tsx +2 -2
  85. package/src/modules/ai_assistant/backend/config/ai-assistant/moderation-flags/AiModerationFlagsPageClient.tsx +186 -0
  86. package/src/modules/ai_assistant/backend/config/ai-assistant/moderation-flags/page.meta.ts +24 -0
  87. package/src/modules/ai_assistant/backend/config/ai-assistant/moderation-flags/page.tsx +12 -0
  88. package/src/modules/ai_assistant/backend/config/ai-assistant/playground/AiPlaygroundPageClient.tsx +4 -4
  89. package/src/modules/ai_assistant/data/entities.ts +56 -0
  90. package/src/modules/ai_assistant/data/repositories/AiAgentRuntimeOverrideRepository.ts +4 -0
  91. package/src/modules/ai_assistant/data/repositories/AiModerationFlagRepository.ts +79 -0
  92. package/src/modules/ai_assistant/di.ts +5 -1
  93. package/src/modules/ai_assistant/events.ts +21 -0
  94. package/src/modules/ai_assistant/i18n/de.json +42 -0
  95. package/src/modules/ai_assistant/i18n/en.json +42 -0
  96. package/src/modules/ai_assistant/i18n/es.json +42 -0
  97. package/src/modules/ai_assistant/i18n/ko.json +527 -0
  98. package/src/modules/ai_assistant/i18n/pl.json +42 -0
  99. package/src/modules/ai_assistant/lib/__tests__/auth.test.ts +2 -5
  100. package/src/modules/ai_assistant/lib/__tests__/input-moderation-gate.test.ts +121 -0
  101. package/src/modules/ai_assistant/lib/__tests__/llm-adapters-anthropic.test.ts +13 -0
  102. package/src/modules/ai_assistant/lib/__tests__/llm-adapters-openai.test.ts +41 -0
  103. package/src/modules/ai_assistant/lib/__tests__/model-factory.test.ts +60 -0
  104. package/src/modules/ai_assistant/lib/__tests__/moderation-flag-recorder.test.ts +76 -0
  105. package/src/modules/ai_assistant/lib/__tests__/moderation-policy.test.ts +86 -0
  106. package/src/modules/ai_assistant/lib/__tests__/moderation.test.ts +114 -0
  107. package/src/modules/ai_assistant/lib/agent-runtime.ts +259 -0
  108. package/src/modules/ai_assistant/lib/ai-agent-definition.ts +10 -0
  109. package/src/modules/ai_assistant/lib/auth.ts +6 -15
  110. package/src/modules/ai_assistant/lib/entity-graph.ts +3 -3
  111. package/src/modules/ai_assistant/lib/llm-adapters/anthropic.ts +10 -0
  112. package/src/modules/ai_assistant/lib/llm-adapters/openai.ts +32 -1
  113. package/src/modules/ai_assistant/lib/model-factory.ts +33 -0
  114. package/src/modules/ai_assistant/lib/moderation-flag-recorder.ts +75 -0
  115. package/src/modules/ai_assistant/lib/moderation-policy.ts +77 -0
  116. package/src/modules/ai_assistant/lib/moderation.ts +179 -0
  117. package/src/modules/ai_assistant/lib/openai-compatible-presets.ts +2 -0
  118. package/src/modules/ai_assistant/lib/tool-search.ts +4 -17
  119. package/src/modules/ai_assistant/migrations/.snapshot-open-mercato.json +388 -16
  120. package/src/modules/ai_assistant/migrations/Migration20260610134045_ai_assistant.ts +21 -0
@@ -36,21 +36,44 @@
36
36
  "ai_assistant.agents.meta.readOnlyYes": "Tak",
37
37
  "ai_assistant.agents.meta.unlimited": "Bez limitu",
38
38
  "ai_assistant.agents.model_override.allowlistCustom": "niestandardowe",
39
+ "ai_assistant.agents.model_override.allowlistEmpty": "Brak skonfigurowanych dostawców dostępnych do nadpisań w czacie.",
40
+ "ai_assistant.agents.model_override.allowlistHelp": "Ogranicz, które nadpisania dostawcy i modelu użytkownicy mogą wybrać w stopce czatu dla tego agenta.",
39
41
  "ai_assistant.agents.model_override.allowlistInherited": "dziedziczone",
40
42
  "ai_assistant.agents.model_override.allowlistReset": "Dziedzicz",
41
43
  "ai_assistant.agents.model_override.allowlistSave": "Zapisz wybór",
44
+ "ai_assistant.agents.model_override.allowlistSaved": "Zapisano dozwolone opcje nadpisań w czacie.",
45
+ "ai_assistant.agents.model_override.allowlistTitle": "Dozwolone opcje nadpisań w czacie",
42
46
  "ai_assistant.agents.model_override.anyProvider": "pierwszy skonfigurowany",
43
47
  "ai_assistant.agents.model_override.clear": "Wyczyść nadpisanie",
48
+ "ai_assistant.agents.model_override.cleared": "Nadpisanie modelu zostało wyczyszczone; agent korzysta ze standardowego łańcucha rozwiązywania.",
44
49
  "ai_assistant.agents.model_override.codeDefault": "Domyślne z kodu",
45
50
  "ai_assistant.agents.model_override.defaultBadge": "domyślne",
51
+ "ai_assistant.agents.model_override.envAlsoNarrows": "dodatkowo zawęża tę listę na podstawie zmiennych środowiskowych.",
52
+ "ai_assistant.agents.model_override.loadErrorTitle": "Nie udało się wczytać katalogu dostawców",
53
+ "ai_assistant.agents.model_override.loading": "Wczytywanie katalogu dostawców…",
46
54
  "ai_assistant.agents.model_override.model": "Model",
47
55
  "ai_assistant.agents.model_override.noOverride": "Brak nadpisania dla agenta",
48
56
  "ai_assistant.agents.model_override.provider": "Dostawca",
49
57
  "ai_assistant.agents.model_override.providerDefault": "domyślne dostawcy",
50
58
  "ai_assistant.agents.model_override.save": "Zapisz nadpisanie",
51
59
  "ai_assistant.agents.model_override.saved": "Nadpisanie modelu zapisane.",
60
+ "ai_assistant.agents.model_override.selectModel": "Wybierz model",
61
+ "ai_assistant.agents.model_override.selectProvider": "Wybierz dostawcę",
62
+ "ai_assistant.agents.model_override.subtitle": "Nadpisz domyślnego dostawcę i model dla tego najemcy i agenta.",
52
63
  "ai_assistant.agents.model_override.tenantOverride": "Nadpisanie tenant",
53
64
  "ai_assistant.agents.model_override.title": "Dostawca i model",
65
+ "ai_assistant.agents.moderation.controlLabel": "Moderacja",
66
+ "ai_assistant.agents.moderation.effectiveEnforced": "Wymuszona",
67
+ "ai_assistant.agents.moderation.effectiveOff": "Wyłączona",
68
+ "ai_assistant.agents.moderation.effectiveOn": "Włączona",
69
+ "ai_assistant.agents.moderation.enforcedBadge": "Wymuszona",
70
+ "ai_assistant.agents.moderation.enforcedHint": "Ten agent przyjmuje niezaufane dane wejściowe, więc moderacja jest zawsze włączona i nie można jej tutaj wyłączyć.",
71
+ "ai_assistant.agents.moderation.inheritLabel": "Dziedzicz",
72
+ "ai_assistant.agents.moderation.offLabel": "Wyłączona",
73
+ "ai_assistant.agents.moderation.onLabel": "Włączona",
74
+ "ai_assistant.agents.moderation.saved": "Zapisano ustawienie moderacji danych wejściowych.",
75
+ "ai_assistant.agents.moderation.subtitle": "Filtruj dane wejściowe użytkownika pod kątem niebezpiecznych treści przed uruchomieniem modelu. Działa tylko, gdy wybrany dostawca obsługuje moderację.",
76
+ "ai_assistant.agents.moderation.title": "Moderacja danych wejściowych",
54
77
  "ai_assistant.agents.mutation_policy.clear": "Wyczyść nadpisanie",
55
78
  "ai_assistant.agents.mutation_policy.clearedMessage": "Nadpisanie polityki mutacji usunięte; agent korzysta z polityki zadeklarowanej w kodzie.",
56
79
  "ai_assistant.agents.mutation_policy.codeDeclared": "Zadeklarowane w kodzie",
@@ -275,7 +298,9 @@
275
298
  "ai_assistant.chat.toolRunning": "w toku…",
276
299
  "ai_assistant.chat.transcriptLabel": "Transkrypcja czatu",
277
300
  "ai_assistant.chat.uiPartPending": "Oczekująca część UI:",
301
+ "ai_assistant.chat.uploadingHint": "Trwa przesyłanie załączników… Wysyłanie jest zablokowane do zakończenia.",
278
302
  "ai_assistant.chat.userRoleLabel": "Ty",
303
+ "ai_assistant.chat.welcomeDescription": "Zapytaj mnie o cokolwiek z Twoich danych. Oto kilka rzeczy, które potrafię:",
279
304
  "ai_assistant.chat.welcomeTitle": "W czym mogę pomóc?",
280
305
  "ai_assistant.chat.zoomImage": "Otwórz podgląd {name}",
281
306
  "ai_assistant.dock.bottom": "Dokuj na dole",
@@ -284,13 +309,17 @@
284
309
  "ai_assistant.dock.left": "Dokuj po lewej",
285
310
  "ai_assistant.dock.minimize": "Minimalizuj",
286
311
  "ai_assistant.dock.right": "Dokuj po prawej",
312
+ "ai_assistant.errors.moderationBlocked": "Twoja wiadomość została zablokowana przez filtr bezpieczeństwa treści. Przeformułuj ją i spróbuj ponownie.",
313
+ "ai_assistant.errors.moderationUnavailable": "Sprawdzanie bezpieczeństwa treści jest chwilowo niedostępne. Spróbuj ponownie za chwilę.",
287
314
  "ai_assistant.launcher.composerPlaceholder": "Zapytaj o cokolwiek…",
315
+ "ai_assistant.launcher.dialogDescription": "Wybierz asystenta. Nawiguj klawiszami ↑/↓, Enter uruchamia, Esc zamyka.",
288
316
  "ai_assistant.launcher.dialogTitle": "Asystenci AI",
289
317
  "ai_assistant.launcher.dock.subtitle": "Asystent AI",
290
318
  "ai_assistant.launcher.empty": "Żaden asystent nie pasuje do wyszukiwania.",
291
319
  "ai_assistant.launcher.hint.close": "Zamknij",
292
320
  "ai_assistant.launcher.hint.launch": "Uruchom",
293
321
  "ai_assistant.launcher.hint.navigate": "Nawigacja",
322
+ "ai_assistant.launcher.none": "Dla Twojego konta nie są dostępni żadni asystenci.",
294
323
  "ai_assistant.launcher.searchPlaceholder": "Szukaj asystentów...",
295
324
  "ai_assistant.launcher.setup.body": "Asystenci AI są zainstalowani, ale nie skonfigurowano klucza dostawcy. Ustaw OM_AI_PROVIDER oraz pasujący klucz API w pliku .env, a następnie uruchom aplikację ponownie.",
296
325
  "ai_assistant.launcher.setup.docs": "Dokumentacja asystenta AI",
@@ -299,6 +328,7 @@
299
328
  "ai_assistant.launcher.sheet.dock": "Przypnij z boku",
300
329
  "ai_assistant.launcher.triggerAriaLabel": "Otwórz asystenta AI",
301
330
  "ai_assistant.launcher.triggerLabel": "AI",
331
+ "ai_assistant.launcher.welcome.fallback": "W czym mogę pomóc?",
302
332
  "ai_assistant.launcher.welcome.suggestion1": "W czym możesz mi pomóc?",
303
333
  "ai_assistant.launcher.welcome.suggestion2": "Pokaż, do jakich danych masz dostęp",
304
334
  "ai_assistant.launcher.welcome.suggestion3": "Zaproponuj, co mogę wypróbować",
@@ -326,6 +356,18 @@
326
356
  "ai_assistant.modelPicker.triggerAriaLabel": "Wybierz model AI",
327
357
  "ai_assistant.modelPicker.useDefault": "Użyj domyślnego agenta",
328
358
  "ai_assistant.modelPicker.useDefaultWithModel": "Użyj domyślnego agenta: {{model}}",
359
+ "ai_assistant.moderationFlags.columns.agent": "Agent",
360
+ "ai_assistant.moderationFlags.columns.categories": "Kategorie",
361
+ "ai_assistant.moderationFlags.columns.createdAt": "Oznaczono",
362
+ "ai_assistant.moderationFlags.columns.user": "Użytkownik",
363
+ "ai_assistant.moderationFlags.empty": "Brak oznaczonych wiadomości.",
364
+ "ai_assistant.moderationFlags.filters.agentPlaceholder": "moduł.agent",
365
+ "ai_assistant.moderationFlags.filters.apply": "Zastosuj",
366
+ "ai_assistant.moderationFlags.filters.from": "Od",
367
+ "ai_assistant.moderationFlags.filters.to": "Do",
368
+ "ai_assistant.moderationFlags.navTitle": "Flagi moderacji",
369
+ "ai_assistant.moderationFlags.subtitle": "Dane wejściowe zablokowane przez filtr bezpieczeństwa treści. Tylko flagi kategorii i wyniki — treść promptu nie jest przechowywana.",
370
+ "ai_assistant.moderationFlags.title": "Flagi moderacji",
329
371
  "ai_assistant.notifications.conversation_shared.body": "Udostępniono Ci konwersację z asystentem AI.",
330
372
  "ai_assistant.notifications.conversation_shared.title": "Udostępniono Ci konwersację",
331
373
  "ai_assistant.notifications.conversation_shared.view_button": "Otwórz konwersację",
@@ -11,6 +11,18 @@ import {
11
11
  Experimental_Agent as ToolLoopAgent
12
12
  } from "ai";
13
13
  import { createModelFactory, resolveAllowRuntimeOverride } from "./model-factory.js";
14
+ import { computeEndUserIdentifier } from "@open-mercato/shared/lib/ai/safety-identifier";
15
+ import { llmProviderRegistry } from "@open-mercato/shared/lib/ai/llm-provider-registry";
16
+ import {
17
+ AiModerationBlockedError,
18
+ AiModerationUnavailableError
19
+ } from "./moderation.js";
20
+ import {
21
+ isModerationActive,
22
+ resolveModerationPolicy,
23
+ shouldFailClosed
24
+ } from "./moderation-policy.js";
25
+ import { recordModerationFlag } from "./moderation-flag-recorder.js";
14
26
  import {
15
27
  resolveAiAgentTools,
16
28
  AgentPolicyError,
@@ -397,7 +409,7 @@ function assertLoopObjectModeCompatible(loopConfig) {
397
409
  );
398
410
  }
399
411
  }
400
- function resolveAgentModel(agent, modelOverride, providerOverride, container, baseUrlOverride, tenantOverride, requestOverride, tenantAllowlist) {
412
+ function resolveAgentModel(agent, modelOverride, providerOverride, container, baseUrlOverride, tenantOverride, requestOverride, tenantAllowlist, endUserIdentifier) {
401
413
  const effectiveContainer = container ?? createContainer();
402
414
  const resolution = createModelFactory(effectiveContainer).resolveModel({
403
415
  moduleId: agent.moduleId,
@@ -410,14 +422,88 @@ function resolveAgentModel(agent, modelOverride, providerOverride, container, ba
410
422
  allowRuntimeOverride: resolveAllowRuntimeOverride(agent),
411
423
  tenantOverride: tenantOverride ?? void 0,
412
424
  requestOverride: requestOverride ?? void 0,
413
- tenantAllowlist: tenantAllowlist ?? null
425
+ tenantAllowlist: tenantAllowlist ?? null,
426
+ endUserIdentifier
414
427
  });
415
428
  return {
416
429
  model: resolution.model,
417
430
  modelId: resolution.modelId,
418
- providerId: resolution.providerId
431
+ providerId: resolution.providerId,
432
+ providerOptions: resolution.providerOptions,
433
+ supportsInputModeration: resolution.supportsInputModeration === true,
434
+ baseURL: resolution.baseURL
419
435
  };
420
436
  }
437
+ function extractLatestUserText(messages) {
438
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
439
+ const raw = messages[index];
440
+ if (raw.role !== "user") continue;
441
+ if (Array.isArray(raw.parts)) {
442
+ return raw.parts.filter((part) => part?.type === "text" && typeof part.text === "string").map((part) => part.text).join("\n");
443
+ }
444
+ return typeof raw.content === "string" ? raw.content : "";
445
+ }
446
+ return "";
447
+ }
448
+ async function runInputModerationGate(params) {
449
+ const policy = resolveModerationPolicy({
450
+ untrustedInput: params.untrustedInput,
451
+ perAgentOverride: params.perAgentOverride,
452
+ tenantWideOverride: params.tenantWideOverride,
453
+ env: params.env
454
+ });
455
+ if (!isModerationActive(policy)) return;
456
+ if (!params.supportsInputModeration) return;
457
+ const text = params.userText.trim();
458
+ if (!text) return;
459
+ const failClosed = shouldFailClosed(policy);
460
+ const failOpenOrThrow = (reason, error) => {
461
+ if (failClosed) {
462
+ if (error instanceof AiModerationUnavailableError) throw error;
463
+ throw new AiModerationUnavailableError(reason, error);
464
+ }
465
+ logger.warn("Input moderation unavailable; failing open for opt-in surface", { reason });
466
+ };
467
+ if (!params.service) {
468
+ return failOpenOrThrow("moderation service is not available in the container");
469
+ }
470
+ const apiKey = params.resolveApiKey();
471
+ if (!apiKey) {
472
+ return failOpenOrThrow("no API key available for the moderation provider");
473
+ }
474
+ let result;
475
+ try {
476
+ result = await params.service.checkInput({
477
+ text,
478
+ apiKey,
479
+ baseURL: params.baseURL,
480
+ model: params.moderationModel
481
+ });
482
+ } catch (error) {
483
+ if (error instanceof AiModerationUnavailableError) {
484
+ return failOpenOrThrow(error.message, error);
485
+ }
486
+ throw error;
487
+ }
488
+ if (result.flagged) {
489
+ if (params.onFlagged) {
490
+ try {
491
+ await params.onFlagged(result.categories);
492
+ } catch (error) {
493
+ logger.error("Moderation flag side effect failed (rejection still applies)", { err: error });
494
+ }
495
+ }
496
+ throw new AiModerationBlockedError(result.categories);
497
+ }
498
+ }
499
+ function resolveEndUserIdentifier(authContext) {
500
+ try {
501
+ return computeEndUserIdentifier(authContext.tenantId, authContext.userId);
502
+ } catch (error) {
503
+ logger.warn("Failed to derive end-user safety identifier", { err: error });
504
+ return void 0;
505
+ }
506
+ }
421
507
  async function resolveTenantAllowlistSnapshot(container, tenantId, organizationId) {
422
508
  if (!tenantId || !container) return null;
423
509
  let em = null;
@@ -550,6 +636,31 @@ async function resolveRuntimeModelOverride(agentId, container, tenantId, organiz
550
636
  return null;
551
637
  }
552
638
  }
639
+ async function resolveModerationOverrideValues(container, tenantId, organizationId, agentId) {
640
+ const empty = { perAgentOverride: null, tenantWideOverride: null };
641
+ if (!tenantId || !container) return empty;
642
+ let em = null;
643
+ try {
644
+ em = container.resolve("em");
645
+ } catch {
646
+ em = null;
647
+ }
648
+ if (!em) return empty;
649
+ try {
650
+ const repo = new AiAgentRuntimeOverrideRepository(em);
651
+ const [agentRow, tenantRow] = await Promise.all([
652
+ repo.getExact({ tenantId, organizationId: organizationId ?? null, agentId }),
653
+ repo.getDefault({ tenantId, organizationId: organizationId ?? null, agentId: null })
654
+ ]);
655
+ return {
656
+ perAgentOverride: agentRow?.inputModeration ?? null,
657
+ tenantWideOverride: tenantRow?.inputModeration ?? null
658
+ };
659
+ } catch (error) {
660
+ logger.warn("Moderation override lookup failed; falling back to env default", { agentId, err: error });
661
+ return empty;
662
+ }
663
+ }
553
664
  function ensureUiMessageShape(messages) {
554
665
  return messages.map((message, index) => {
555
666
  const raw = message;
@@ -750,10 +861,47 @@ async function runAiAgentText(input) {
750
861
  input.baseUrlOverride,
751
862
  tenantRuntimeOverride,
752
863
  input.requestOverride,
753
- tenantAllowlistSnapshot
864
+ tenantAllowlistSnapshot,
865
+ resolveEndUserIdentifier(input.authContext)
754
866
  );
755
867
  const { model } = resolvedModel;
868
+ const modelProviderOptions = resolvedModel.providerOptions;
756
869
  const normalizedMessages = ensureUiMessageShape(input.messages);
870
+ let moderationService = null;
871
+ try {
872
+ moderationService = input.container?.resolve("moderationService") ?? null;
873
+ } catch {
874
+ moderationService = null;
875
+ }
876
+ const moderationOverrides = resolvedModel.supportsInputModeration && agent.untrustedInput !== true ? await resolveModerationOverrideValues(
877
+ input.container,
878
+ input.authContext.tenantId,
879
+ input.authContext.organizationId,
880
+ agent.id
881
+ ) : { perAgentOverride: null, tenantWideOverride: null };
882
+ await runInputModerationGate({
883
+ untrustedInput: agent.untrustedInput,
884
+ supportsInputModeration: resolvedModel.supportsInputModeration,
885
+ perAgentOverride: moderationOverrides.perAgentOverride,
886
+ tenantWideOverride: moderationOverrides.tenantWideOverride,
887
+ userText: extractLatestUserText(normalizedMessages),
888
+ service: moderationService,
889
+ resolveApiKey: () => llmProviderRegistry.get(resolvedModel.providerId)?.resolveApiKey() ?? null,
890
+ baseURL: resolvedModel.baseURL,
891
+ moderationModel: process.env.OM_AI_MODERATION_MODEL,
892
+ onFlagged: (categories) => recordModerationFlag(
893
+ {
894
+ tenantId: input.authContext.tenantId,
895
+ organizationId: input.authContext.organizationId,
896
+ agentId: agent.id,
897
+ userId: input.authContext.userId,
898
+ providerId: resolvedModel.providerId,
899
+ modelId: resolvedModel.modelId,
900
+ categories
901
+ },
902
+ input.container
903
+ )
904
+ });
757
905
  const hydratedMessages = attachAttachmentsToMessages(normalizedMessages, resolvedAttachments);
758
906
  const modelMessages = await convertToModelMessages(hydratedMessages);
759
907
  const effectiveLoop = resolveEffectiveLoopConfig(agent, input.loop, WRAPPER_DEFAULT_LOOP_CHAT);
@@ -814,7 +962,8 @@ async function runAiAgentText(input) {
814
962
  onStepFinish: wiredOnStepFinish,
815
963
  ...effectiveLoop.repairToolCall !== void 0 ? { experimental_repairToolCall: effectiveLoop.repairToolCall } : {},
816
964
  ...sdkActiveTools !== void 0 ? { activeTools: sdkActiveTools } : {},
817
- ...sdkToolChoice !== void 0 ? { toolChoice: sdkToolChoice } : {}
965
+ ...sdkToolChoice !== void 0 ? { toolChoice: sdkToolChoice } : {},
966
+ ...modelProviderOptions !== void 0 ? { providerOptions: modelProviderOptions } : {}
818
967
  };
819
968
  builtToolLoopAgent = new ToolLoopAgent(agentSettings);
820
969
  }
@@ -835,6 +984,7 @@ async function runAiAgentText(input) {
835
984
  toolChoice: sdkToolChoice,
836
985
  abortSignal: abortController.signal,
837
986
  finalizeLoopTrace: () => loopTraceCollector.finalize(budgetEnforcer.abortReason),
987
+ ...modelProviderOptions !== void 0 ? { providerOptions: modelProviderOptions } : {},
838
988
  ...builtToolLoopAgent !== void 0 ? { toolLoopAgent: builtToolLoopAgent } : {}
839
989
  };
840
990
  const taskPlanId = `turn_${turnId}`;
@@ -894,6 +1044,7 @@ async function runAiAgentText(input) {
894
1044
  experimental_repairToolCall: effectiveLoop.repairToolCall,
895
1045
  ...sdkActiveTools !== void 0 ? { activeTools: sdkActiveTools } : {},
896
1046
  ...sdkToolChoice !== void 0 ? { toolChoice: sdkToolChoice } : {},
1047
+ ...modelProviderOptions !== void 0 ? { providerOptions: modelProviderOptions } : {},
897
1048
  abortSignal: abortController.signal
898
1049
  });
899
1050
  if (wallClockTimer !== void 0) {
@@ -1101,11 +1252,13 @@ export {
1101
1252
  buildLoopTraceCollector,
1102
1253
  buildWrapperPrepareStep,
1103
1254
  composeSystemPrompt,
1255
+ extractLatestUserText,
1104
1256
  mergeStepOverrides,
1105
1257
  resolveEffectiveLoopConfig,
1106
1258
  resolveLoopBudgetPreset,
1107
1259
  runAiAgentObject,
1108
1260
  runAiAgentText,
1261
+ runInputModerationGate,
1109
1262
  translateStopConditions
1110
1263
  };
1111
1264
  //# sourceMappingURL=agent-runtime.js.map