@open-mercato/ai-assistant 0.6.7-develop.6862.1.c11a64ce0a → 0.6.7
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 +29 -12
- package/dist/modules/ai_assistant/__integration__/helpers/aiAssistantFixtures.js +0 -30
- package/dist/modules/ai_assistant/__integration__/helpers/aiAssistantFixtures.js.map +2 -2
- package/dist/modules/ai_assistant/api/ai/chat/route.js +0 -7
- package/dist/modules/ai_assistant/api/ai/chat/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/settings/allowlist/route.js +10 -10
- package/dist/modules/ai_assistant/api/settings/allowlist/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/settings/route.js +13 -34
- package/dist/modules/ai_assistant/api/settings/route.js.map +2 -2
- package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/AiAgentSettingsPageClient.js +0 -106
- package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/AiAgentSettingsPageClient.js.map +2 -2
- package/dist/modules/ai_assistant/data/entities.js +0 -42
- package/dist/modules/ai_assistant/data/entities.js.map +2 -2
- package/dist/modules/ai_assistant/data/repositories/AiAgentRuntimeOverrideRepository.js +1 -3
- package/dist/modules/ai_assistant/data/repositories/AiAgentRuntimeOverrideRepository.js.map +2 -2
- package/dist/modules/ai_assistant/di.js +2 -6
- package/dist/modules/ai_assistant/di.js.map +2 -2
- package/dist/modules/ai_assistant/events.js +0 -6
- package/dist/modules/ai_assistant/events.js.map +2 -2
- package/dist/modules/ai_assistant/i18n/de.json +0 -42
- package/dist/modules/ai_assistant/i18n/en.json +0 -42
- package/dist/modules/ai_assistant/i18n/es.json +0 -42
- package/dist/modules/ai_assistant/i18n/pl.json +0 -42
- package/dist/modules/ai_assistant/lib/agent-runtime.js +5 -158
- package/dist/modules/ai_assistant/lib/agent-runtime.js.map +2 -2
- package/dist/modules/ai_assistant/lib/ai-agent-definition.js.map +2 -2
- package/dist/modules/ai_assistant/lib/auth.js +7 -6
- package/dist/modules/ai_assistant/lib/auth.js.map +2 -2
- package/dist/modules/ai_assistant/lib/entity-graph.js +3 -3
- package/dist/modules/ai_assistant/lib/entity-graph.js.map +2 -2
- package/dist/modules/ai_assistant/lib/llm-adapters/anthropic.js +0 -3
- package/dist/modules/ai_assistant/lib/llm-adapters/anthropic.js.map +2 -2
- package/dist/modules/ai_assistant/lib/llm-adapters/openai.js +1 -8
- package/dist/modules/ai_assistant/lib/llm-adapters/openai.js.map +2 -2
- package/dist/modules/ai_assistant/lib/model-factory.js +1 -6
- package/dist/modules/ai_assistant/lib/model-factory.js.map +2 -2
- package/dist/modules/ai_assistant/lib/openai-compatible-presets.js +0 -2
- package/dist/modules/ai_assistant/lib/openai-compatible-presets.js.map +2 -2
- package/dist/modules/ai_assistant/lib/tool-search.js +12 -4
- package/dist/modules/ai_assistant/lib/tool-search.js.map +2 -2
- package/generated/entities/ai_agent_runtime_override/index.ts +0 -1
- package/generated/entities.ids.generated.ts +1 -2
- package/generated/entity-fields-registry.ts +1 -13
- package/package.json +12 -13
- package/src/modules/ai_assistant/__integration__/helpers/aiAssistantFixtures.ts +0 -48
- package/src/modules/ai_assistant/api/ai/chat/route.ts +0 -10
- package/src/modules/ai_assistant/api/settings/__tests__/route.test.ts +8 -58
- package/src/modules/ai_assistant/api/settings/allowlist/route.ts +12 -10
- package/src/modules/ai_assistant/api/settings/route.ts +10 -33
- package/src/modules/ai_assistant/backend/config/ai-assistant/agents/AiAgentSettingsPageClient.tsx +0 -146
- package/src/modules/ai_assistant/data/entities.ts +0 -56
- package/src/modules/ai_assistant/data/repositories/AiAgentRuntimeOverrideRepository.ts +0 -4
- package/src/modules/ai_assistant/di.ts +1 -5
- package/src/modules/ai_assistant/events.ts +0 -21
- package/src/modules/ai_assistant/i18n/de.json +0 -42
- package/src/modules/ai_assistant/i18n/en.json +0 -42
- package/src/modules/ai_assistant/i18n/es.json +0 -42
- package/src/modules/ai_assistant/i18n/pl.json +0 -42
- package/src/modules/ai_assistant/lib/__tests__/auth.test.ts +5 -2
- package/src/modules/ai_assistant/lib/__tests__/llm-adapters-anthropic.test.ts +0 -13
- package/src/modules/ai_assistant/lib/__tests__/llm-adapters-openai.test.ts +0 -41
- package/src/modules/ai_assistant/lib/__tests__/model-factory.test.ts +0 -60
- package/src/modules/ai_assistant/lib/agent-runtime.ts +0 -259
- package/src/modules/ai_assistant/lib/ai-agent-definition.ts +0 -10
- package/src/modules/ai_assistant/lib/auth.ts +15 -6
- package/src/modules/ai_assistant/lib/entity-graph.ts +3 -3
- package/src/modules/ai_assistant/lib/llm-adapters/anthropic.ts +0 -10
- package/src/modules/ai_assistant/lib/llm-adapters/openai.ts +1 -32
- package/src/modules/ai_assistant/lib/model-factory.ts +0 -33
- package/src/modules/ai_assistant/lib/openai-compatible-presets.ts +0 -2
- package/src/modules/ai_assistant/lib/tool-search.ts +17 -4
- package/src/modules/ai_assistant/migrations/.snapshot-open-mercato.json +16 -388
- package/dist/modules/ai_assistant/__integration__/TC-AI-MODERATION-008-settings-and-audit.spec.js +0 -80
- package/dist/modules/ai_assistant/__integration__/TC-AI-MODERATION-008-settings-and-audit.spec.js.map +0 -7
- package/dist/modules/ai_assistant/__integration__/TC-AI-MODERATION-009-ui.spec.js +0 -124
- package/dist/modules/ai_assistant/__integration__/TC-AI-MODERATION-009-ui.spec.js.map +0 -7
- package/dist/modules/ai_assistant/api/moderation-flags/route.js +0 -121
- package/dist/modules/ai_assistant/api/moderation-flags/route.js.map +0 -7
- package/dist/modules/ai_assistant/backend/config/ai-assistant/moderation-flags/AiModerationFlagsPageClient.js +0 -139
- package/dist/modules/ai_assistant/backend/config/ai-assistant/moderation-flags/AiModerationFlagsPageClient.js.map +0 -7
- package/dist/modules/ai_assistant/backend/config/ai-assistant/moderation-flags/page.js +0 -10
- package/dist/modules/ai_assistant/backend/config/ai-assistant/moderation-flags/page.js.map +0 -7
- package/dist/modules/ai_assistant/backend/config/ai-assistant/moderation-flags/page.meta.js +0 -26
- package/dist/modules/ai_assistant/backend/config/ai-assistant/moderation-flags/page.meta.js.map +0 -7
- package/dist/modules/ai_assistant/data/repositories/AiModerationFlagRepository.js +0 -44
- package/dist/modules/ai_assistant/data/repositories/AiModerationFlagRepository.js.map +0 -7
- package/dist/modules/ai_assistant/i18n/ko.json +0 -527
- package/dist/modules/ai_assistant/lib/moderation-flag-recorder.js +0 -43
- package/dist/modules/ai_assistant/lib/moderation-flag-recorder.js.map +0 -7
- package/dist/modules/ai_assistant/lib/moderation-policy.js +0 -24
- package/dist/modules/ai_assistant/lib/moderation-policy.js.map +0 -7
- package/dist/modules/ai_assistant/lib/moderation.js +0 -109
- package/dist/modules/ai_assistant/lib/moderation.js.map +0 -7
- package/dist/modules/ai_assistant/migrations/Migration20260610134045_ai_assistant.js +0 -19
- package/dist/modules/ai_assistant/migrations/Migration20260610134045_ai_assistant.js.map +0 -7
- package/generated/entities/ai_moderation_flag/index.ts +0 -9
- package/src/modules/ai_assistant/__integration__/TC-AI-MODERATION-008-settings-and-audit.spec.ts +0 -126
- package/src/modules/ai_assistant/__integration__/TC-AI-MODERATION-009-ui.spec.ts +0 -161
- package/src/modules/ai_assistant/api/moderation-flags/__tests__/route.test.ts +0 -122
- package/src/modules/ai_assistant/api/moderation-flags/route.ts +0 -137
- package/src/modules/ai_assistant/backend/config/ai-assistant/moderation-flags/AiModerationFlagsPageClient.tsx +0 -186
- package/src/modules/ai_assistant/backend/config/ai-assistant/moderation-flags/page.meta.ts +0 -24
- package/src/modules/ai_assistant/backend/config/ai-assistant/moderation-flags/page.tsx +0 -12
- package/src/modules/ai_assistant/data/repositories/AiModerationFlagRepository.ts +0 -79
- package/src/modules/ai_assistant/i18n/ko.json +0 -527
- package/src/modules/ai_assistant/lib/__tests__/input-moderation-gate.test.ts +0 -121
- package/src/modules/ai_assistant/lib/__tests__/moderation-flag-recorder.test.ts +0 -76
- package/src/modules/ai_assistant/lib/__tests__/moderation-policy.test.ts +0 -86
- package/src/modules/ai_assistant/lib/__tests__/moderation.test.ts +0 -114
- package/src/modules/ai_assistant/lib/moderation-flag-recorder.ts +0 -75
- package/src/modules/ai_assistant/lib/moderation-policy.ts +0 -77
- package/src/modules/ai_assistant/lib/moderation.ts +0 -179
- package/src/modules/ai_assistant/migrations/Migration20260610134045_ai_assistant.ts +0 -21
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Input pre-moderation service.
|
|
3
|
-
*
|
|
4
|
-
* Wraps OpenAI's free `/v1/moderations` endpoint so the agent runtime can
|
|
5
|
-
* screen the current user turn BEFORE the model call on surfaces that opt in
|
|
6
|
-
* (or are forced on via `untrustedInput`). The service is intentionally pure:
|
|
7
|
-
* it performs the HTTP check and returns category flags + scores, or throws
|
|
8
|
-
* {@link AiModerationUnavailableError} when the endpoint is unreachable. It does
|
|
9
|
-
* NOT persist audit records, emit events, or throw the user-facing block — the
|
|
10
|
-
* runtime gate orchestrates those (see `agent-runtime.ts`).
|
|
11
|
-
*
|
|
12
|
-
* @see .ai/specs/2026-06-04-ai-input-moderation-and-safety-identifiers.md
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { z } from 'zod'
|
|
16
|
-
|
|
17
|
-
/** Default moderation model; override with `OM_AI_MODERATION_MODEL`. */
|
|
18
|
-
export const DEFAULT_MODERATION_MODEL = 'omni-moderation-latest'
|
|
19
|
-
|
|
20
|
-
const DEFAULT_OPENAI_BASE_URL = 'https://api.openai.com/v1'
|
|
21
|
-
const REQUEST_TIMEOUT_MS = 3000
|
|
22
|
-
|
|
23
|
-
/** Per-category moderation outcome: whether it tripped and the model's score. */
|
|
24
|
-
export interface ModerationCategoryResult {
|
|
25
|
-
flagged: boolean
|
|
26
|
-
score: number
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/** Result of an input moderation check — flags + scores only, never content. */
|
|
30
|
-
export interface ModerationResult {
|
|
31
|
-
flagged: boolean
|
|
32
|
-
categories: Record<string, ModerationCategoryResult>
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** Arguments for {@link ModerationService.checkInput}. */
|
|
36
|
-
export interface ModerationCheckInput {
|
|
37
|
-
/** The current user turn text to screen. */
|
|
38
|
-
text: string
|
|
39
|
-
/** Resolved OpenAI(-compatible) API key for the moderations endpoint. */
|
|
40
|
-
apiKey: string
|
|
41
|
-
/** Optional base URL override (defaults to the OpenAI public endpoint). */
|
|
42
|
-
baseURL?: string
|
|
43
|
-
/** Optional model override (defaults to {@link DEFAULT_MODERATION_MODEL}). */
|
|
44
|
-
model?: string
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Port resolved from the DI container by the agent runtime. */
|
|
48
|
-
export interface ModerationService {
|
|
49
|
-
checkInput(input: ModerationCheckInput): Promise<ModerationResult>
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Thrown by the runtime gate (NOT the service) when flagged input is rejected
|
|
54
|
-
* on an enabled/enforced surface. The SSE error path maps it to the
|
|
55
|
-
* `moderation_blocked` code; the raw categories are never sent to the client.
|
|
56
|
-
*/
|
|
57
|
-
export class AiModerationBlockedError extends Error {
|
|
58
|
-
readonly categories: Record<string, ModerationCategoryResult>
|
|
59
|
-
|
|
60
|
-
constructor(categories: Record<string, ModerationCategoryResult>) {
|
|
61
|
-
super('[internal] Input rejected by the content safety filter')
|
|
62
|
-
this.name = 'AiModerationBlockedError'
|
|
63
|
-
this.categories = categories
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Thrown by {@link ModerationService.checkInput} when the moderation endpoint
|
|
69
|
-
* is unreachable (timeout, network error, or non-2xx after one retry). The gate
|
|
70
|
-
* decides fail-closed (enforced surfaces) vs fail-open (opt-in surfaces).
|
|
71
|
-
*/
|
|
72
|
-
export class AiModerationUnavailableError extends Error {
|
|
73
|
-
readonly cause?: unknown
|
|
74
|
-
|
|
75
|
-
constructor(message: string, cause?: unknown) {
|
|
76
|
-
super(`[internal] ${message}`)
|
|
77
|
-
this.name = 'AiModerationUnavailableError'
|
|
78
|
-
this.cause = cause
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const moderationResponseSchema = z.object({
|
|
83
|
-
results: z
|
|
84
|
-
.array(
|
|
85
|
-
z.object({
|
|
86
|
-
flagged: z.boolean(),
|
|
87
|
-
categories: z.record(z.string(), z.boolean()),
|
|
88
|
-
category_scores: z.record(z.string(), z.number()),
|
|
89
|
-
}),
|
|
90
|
-
)
|
|
91
|
-
.min(1),
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
function mergeCategories(
|
|
95
|
-
categories: Record<string, boolean>,
|
|
96
|
-
scores: Record<string, number>,
|
|
97
|
-
): Record<string, ModerationCategoryResult> {
|
|
98
|
-
const merged: Record<string, ModerationCategoryResult> = {}
|
|
99
|
-
for (const [name, flagged] of Object.entries(categories)) {
|
|
100
|
-
merged[name] = { flagged, score: scores[name] ?? 0 }
|
|
101
|
-
}
|
|
102
|
-
return merged
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async function postModeration(input: ModerationCheckInput): Promise<Response> {
|
|
106
|
-
const baseURL = (input.baseURL ?? DEFAULT_OPENAI_BASE_URL).replace(/\/$/, '')
|
|
107
|
-
const controller = new AbortController()
|
|
108
|
-
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS)
|
|
109
|
-
try {
|
|
110
|
-
return await fetch(`${baseURL}/moderations`, {
|
|
111
|
-
method: 'POST',
|
|
112
|
-
headers: {
|
|
113
|
-
'Content-Type': 'application/json',
|
|
114
|
-
Authorization: `Bearer ${input.apiKey}`,
|
|
115
|
-
},
|
|
116
|
-
body: JSON.stringify({
|
|
117
|
-
model: input.model ?? DEFAULT_MODERATION_MODEL,
|
|
118
|
-
input: input.text,
|
|
119
|
-
}),
|
|
120
|
-
signal: controller.signal,
|
|
121
|
-
})
|
|
122
|
-
} finally {
|
|
123
|
-
clearTimeout(timer)
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Builds the default {@link ModerationService}. Stateless and DI-friendly —
|
|
129
|
-
* registered in `di.ts` and overridable by downstream apps.
|
|
130
|
-
*/
|
|
131
|
-
export function createModerationService(): ModerationService {
|
|
132
|
-
return {
|
|
133
|
-
async checkInput(input: ModerationCheckInput): Promise<ModerationResult> {
|
|
134
|
-
let lastError: unknown
|
|
135
|
-
// One short-timeout attempt + one retry (R: outage mitigation).
|
|
136
|
-
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
137
|
-
let response: Response
|
|
138
|
-
try {
|
|
139
|
-
response = await postModeration(input)
|
|
140
|
-
} catch (error) {
|
|
141
|
-
lastError = error
|
|
142
|
-
continue
|
|
143
|
-
}
|
|
144
|
-
if (response.status >= 500) {
|
|
145
|
-
lastError = new Error(`moderation endpoint returned ${response.status}`)
|
|
146
|
-
continue
|
|
147
|
-
}
|
|
148
|
-
if (!response.ok) {
|
|
149
|
-
// 4xx is a configuration/credential error — not transient; do not retry.
|
|
150
|
-
throw new AiModerationUnavailableError(
|
|
151
|
-
`moderation endpoint returned ${response.status}`,
|
|
152
|
-
)
|
|
153
|
-
}
|
|
154
|
-
let json: unknown
|
|
155
|
-
try {
|
|
156
|
-
json = await response.json()
|
|
157
|
-
} catch (error) {
|
|
158
|
-
throw new AiModerationUnavailableError('moderation response was not valid JSON', error)
|
|
159
|
-
}
|
|
160
|
-
const parsed = moderationResponseSchema.safeParse(json)
|
|
161
|
-
if (!parsed.success) {
|
|
162
|
-
throw new AiModerationUnavailableError(
|
|
163
|
-
'moderation response did not match the expected schema',
|
|
164
|
-
parsed.error,
|
|
165
|
-
)
|
|
166
|
-
}
|
|
167
|
-
const result = parsed.data.results[0]
|
|
168
|
-
return {
|
|
169
|
-
flagged: result.flagged,
|
|
170
|
-
categories: mergeCategories(result.categories, result.category_scores),
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
throw new AiModerationUnavailableError(
|
|
174
|
-
'moderation endpoint unreachable after retry',
|
|
175
|
-
lastError,
|
|
176
|
-
)
|
|
177
|
-
},
|
|
178
|
-
}
|
|
179
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { Migration } from '@mikro-orm/migrations';
|
|
2
|
-
|
|
3
|
-
export class Migration20260610134045_ai_assistant extends Migration {
|
|
4
|
-
|
|
5
|
-
override up(): void | Promise<void> {
|
|
6
|
-
this.addSql(`create table "ai_moderation_flags" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid null, "agent_id" text not null, "user_id" text not null, "provider_id" text not null, "model_id" text not null, "categories" jsonb not null, "created_at" timestamptz not null, primary key ("id"));`);
|
|
7
|
-
this.addSql(`create index "ai_moderation_flags_tenant_user_idx" on "ai_moderation_flags" ("tenant_id", "user_id");`);
|
|
8
|
-
this.addSql(`create index "ai_moderation_flags_tenant_created_idx" on "ai_moderation_flags" ("tenant_id", "created_at");`);
|
|
9
|
-
|
|
10
|
-
this.addSql(`alter table "ai_agent_runtime_overrides" add "input_moderation" boolean null;`);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
override down(): void | Promise<void> {
|
|
14
|
-
this.addSql(`alter table "ai_agent_runtime_overrides" drop column "input_moderation";`);
|
|
15
|
-
|
|
16
|
-
this.addSql(`drop index "ai_moderation_flags_tenant_created_idx";`);
|
|
17
|
-
this.addSql(`drop index "ai_moderation_flags_tenant_user_idx";`);
|
|
18
|
-
this.addSql(`drop table if exists "ai_moderation_flags" cascade;`);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
}
|