@flowselections/ai-authenticatie 1.0.14 → 1.1.1
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-lib/components/AiAuthenticatiePage.d.ts.map +1 -1
- package/dist-lib/components/AiAuthenticatiePage.js +6 -3
- package/dist-lib/hooks/useAiForGoal.d.ts +2 -2
- package/dist-lib/hooks/useAiForGoal.d.ts.map +1 -1
- package/dist-lib/hooks/useAiForGoal.js +1 -1
- package/dist-lib/hooks/useIsAiAdmin.d.ts +1 -0
- package/dist-lib/hooks/useIsAiAdmin.d.ts.map +1 -1
- package/dist-lib/hooks/useIsAiAdmin.js +22 -3
- package/dist-lib/index.d.ts +6 -1
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +4 -0
- package/dist-lib/integrations/supabase/types.d.ts +1544 -15
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/aiAttachments.d.ts +22 -0
- package/dist-lib/lib/aiAttachments.d.ts.map +1 -0
- package/dist-lib/lib/aiAttachments.js +105 -0
- package/dist-lib/lib/aiChat.functions.d.ts +3 -2
- package/dist-lib/lib/aiChat.functions.d.ts.map +1 -1
- package/dist-lib/lib/aiChat.functions.js +6 -1
- package/dist-lib/lib/aiChat.server.d.ts +8 -1
- package/dist-lib/lib/aiChat.server.d.ts.map +1 -1
- package/dist-lib/lib/aiChat.server.js +37 -17
- package/dist-lib/lib/aiChat.stream.server.d.ts.map +1 -1
- package/dist-lib/lib/aiChat.stream.server.js +3 -1
- package/dist-lib/lib/aiChat.types.d.ts +8 -1
- package/dist-lib/lib/aiChat.types.d.ts.map +1 -1
- package/dist-lib/lib/aiModules.server.d.ts +4 -0
- package/dist-lib/lib/aiModules.server.d.ts.map +1 -1
- package/dist-lib/lib/aiModules.server.js +6 -3
- package/dist-lib/lib/aiRegistry.d.ts +31 -0
- package/dist-lib/lib/aiRegistry.d.ts.map +1 -0
- package/dist-lib/lib/aiRegistry.functions.d.ts +25 -0
- package/dist-lib/lib/aiRegistry.functions.d.ts.map +1 -0
- package/dist-lib/lib/aiRegistry.functions.js +25 -0
- package/dist-lib/lib/aiRegistry.js +46 -0
- package/dist-lib/lib/aiRegistry.server.d.ts +13 -0
- package/dist-lib/lib/aiRegistry.server.d.ts.map +1 -0
- package/dist-lib/lib/aiRegistry.server.js +21 -0
- package/dist-lib/lib/aiUsageByModule.functions.d.ts.map +1 -1
- package/dist-lib/lib/aiUsageByModule.functions.js +1 -4
- package/dist-lib/lib/modules.server.d.ts.map +1 -1
- package/dist-lib/lib/modules.server.js +7 -7
- package/package.json +14 -4
- package/schema/ai-authenticatie.sql +124 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers voor pdf-bijlagen in AI-aanroepen. Geen netwerk, geen Supabase:
|
|
3
|
+
* zo zijn de opgebouwde verzoeken per provider los te testen.
|
|
4
|
+
*/
|
|
5
|
+
import type { AiChatAttachment, AiChatMessage } from './aiChat.types.js';
|
|
6
|
+
export type AiProviderKind = 'openai' | 'anthropic' | 'gemini' | 'unknown';
|
|
7
|
+
export declare const MAX_ATTACHMENT_BYTES: number;
|
|
8
|
+
export declare const MAX_ATTACHMENTS = 5;
|
|
9
|
+
export declare function providerKind(slug: string): AiProviderKind;
|
|
10
|
+
/**
|
|
11
|
+
* Of dit model pdf-bestanden kan lezen. Null = ondersteund, anders een Nederlandse reden.
|
|
12
|
+
*/
|
|
13
|
+
export declare function pdfSupportProblem(kind: AiProviderKind, modelSlug: string): string | null;
|
|
14
|
+
/** Valideer ruwe invoer tot nette bijlagen; gooit een Nederlandse fout bij ongeldige invoer. */
|
|
15
|
+
export declare function normalizeAttachments(raw: unknown): AiChatAttachment[];
|
|
16
|
+
/** OpenAI chat/completions: bijlagen als `file`-onderdelen in het laatste gebruikersbericht. */
|
|
17
|
+
export declare function buildOpenAIMessages(messages: AiChatMessage[], attachments: AiChatAttachment[]): unknown[];
|
|
18
|
+
/** Anthropic messages: bijlagen als `document`-blokken (zonder system-rol). */
|
|
19
|
+
export declare function buildAnthropicMessages(messages: AiChatMessage[], attachments: AiChatAttachment[]): unknown[];
|
|
20
|
+
/** Gemini generateContent: bijlagen als `inlineData` in de laatste gebruikersbeurt. */
|
|
21
|
+
export declare function buildGeminiContents(messages: AiChatMessage[], attachments: AiChatAttachment[]): unknown[];
|
|
22
|
+
//# sourceMappingURL=aiAttachments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aiAttachments.d.ts","sourceRoot":"","sources":["../../src/lib/aiAttachments.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEtE,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE3E,eAAO,MAAM,oBAAoB,QAAmB,CAAC;AACrD,eAAO,MAAM,eAAe,IAAI,CAAC;AAEjC,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAMzD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgBxF;AAED,gGAAgG;AAChG,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,EAAE,CAcrE;AAOD,gGAAgG;AAChG,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,WAAW,EAAE,gBAAgB,EAAE,GAAG,OAAO,EAAE,CAazG;AAED,+EAA+E;AAC/E,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,WAAW,EAAE,gBAAgB,EAAE,GAAG,OAAO,EAAE,CAc5G;AAED,uFAAuF;AACvF,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,WAAW,EAAE,gBAAgB,EAAE,GAAG,OAAO,EAAE,CASzG"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
export const MAX_ATTACHMENT_BYTES = 20 * 1024 * 1024;
|
|
2
|
+
export const MAX_ATTACHMENTS = 5;
|
|
3
|
+
export function providerKind(slug) {
|
|
4
|
+
const s = (slug || '').toLowerCase();
|
|
5
|
+
if (s.includes('openai') || s.includes('gpt'))
|
|
6
|
+
return 'openai';
|
|
7
|
+
if (s.includes('anthropic') || s.includes('claude'))
|
|
8
|
+
return 'anthropic';
|
|
9
|
+
if (s.includes('gemini') || s.includes('google'))
|
|
10
|
+
return 'gemini';
|
|
11
|
+
return 'unknown';
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Of dit model pdf-bestanden kan lezen. Null = ondersteund, anders een Nederlandse reden.
|
|
15
|
+
*/
|
|
16
|
+
export function pdfSupportProblem(kind, modelSlug) {
|
|
17
|
+
const m = (modelSlug || '').toLowerCase();
|
|
18
|
+
if (kind === 'gemini')
|
|
19
|
+
return null;
|
|
20
|
+
if (kind === 'anthropic') {
|
|
21
|
+
if (/claude-(instant|2)/.test(m) || /claude-3-haiku-20240307/.test(m)) {
|
|
22
|
+
return `Het Claude-model "${modelSlug}" kan geen pdf-bestanden lezen. Kies een nieuwer Claude-model.`;
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
if (kind === 'openai') {
|
|
27
|
+
if (/gpt-3\.5|gpt-4(-\d{4}|-turbo-preview)?$|^o1-mini|^o3-mini|davinci|babbage/.test(m)) {
|
|
28
|
+
return `Het OpenAI-model "${modelSlug}" kan geen pdf-bestanden lezen. Kies bijvoorbeeld gpt-4o, gpt-4.1 of nieuwer.`;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return 'Deze provider ondersteunt geen pdf-bijlagen.';
|
|
33
|
+
}
|
|
34
|
+
/** Valideer ruwe invoer tot nette bijlagen; gooit een Nederlandse fout bij ongeldige invoer. */
|
|
35
|
+
export function normalizeAttachments(raw) {
|
|
36
|
+
if (raw == null)
|
|
37
|
+
return [];
|
|
38
|
+
if (!Array.isArray(raw))
|
|
39
|
+
throw new Error('attachments moet een lijst zijn');
|
|
40
|
+
if (raw.length > MAX_ATTACHMENTS)
|
|
41
|
+
throw new Error(`Maximaal ${MAX_ATTACHMENTS} bijlagen per aanroep`);
|
|
42
|
+
return raw.map((a, i) => {
|
|
43
|
+
const v = (a ?? {});
|
|
44
|
+
const mimeType = typeof v.mimeType === 'string' ? v.mimeType.trim().toLowerCase() : '';
|
|
45
|
+
const data = typeof v.data === 'string' ? v.data.replace(/^data:[^;]+;base64,/, '').replace(/\s+/g, '') : '';
|
|
46
|
+
const filename = typeof v.filename === 'string' && v.filename.trim() ? v.filename.trim() : `bijlage-${i + 1}.pdf`;
|
|
47
|
+
if (mimeType !== 'application/pdf')
|
|
48
|
+
throw new Error(`Bijlage ${i + 1}: alleen pdf (application/pdf) wordt ondersteund`);
|
|
49
|
+
if (!data || !/^[A-Za-z0-9+/]+=*$/.test(data))
|
|
50
|
+
throw new Error(`Bijlage ${i + 1}: data moet base64 zijn`);
|
|
51
|
+
if (Math.floor((data.length * 3) / 4) > MAX_ATTACHMENT_BYTES)
|
|
52
|
+
throw new Error(`Bijlage ${i + 1} is groter dan 20 MB`);
|
|
53
|
+
return { mimeType: 'application/pdf', data, filename };
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function lastUserIndex(messages) {
|
|
57
|
+
for (let i = messages.length - 1; i >= 0; i--)
|
|
58
|
+
if (messages[i].role === 'user')
|
|
59
|
+
return i;
|
|
60
|
+
return -1;
|
|
61
|
+
}
|
|
62
|
+
/** OpenAI chat/completions: bijlagen als `file`-onderdelen in het laatste gebruikersbericht. */
|
|
63
|
+
export function buildOpenAIMessages(messages, attachments) {
|
|
64
|
+
if (!attachments.length)
|
|
65
|
+
return messages;
|
|
66
|
+
const idx = lastUserIndex(messages);
|
|
67
|
+
return messages.map((m, i) => i !== idx ? m : {
|
|
68
|
+
role: 'user',
|
|
69
|
+
content: [
|
|
70
|
+
...attachments.map(a => ({
|
|
71
|
+
type: 'file',
|
|
72
|
+
file: { filename: a.filename, file_data: `data:${a.mimeType};base64,${a.data}` },
|
|
73
|
+
})),
|
|
74
|
+
{ type: 'text', text: m.content },
|
|
75
|
+
],
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/** Anthropic messages: bijlagen als `document`-blokken (zonder system-rol). */
|
|
79
|
+
export function buildAnthropicMessages(messages, attachments) {
|
|
80
|
+
const rest = messages.filter(m => m.role !== 'system');
|
|
81
|
+
if (!attachments.length)
|
|
82
|
+
return rest.map(m => ({ role: m.role, content: m.content }));
|
|
83
|
+
const idx = lastUserIndex(rest);
|
|
84
|
+
return rest.map((m, i) => i !== idx ? { role: m.role, content: m.content } : {
|
|
85
|
+
role: 'user',
|
|
86
|
+
content: [
|
|
87
|
+
...attachments.map(a => ({
|
|
88
|
+
type: 'document',
|
|
89
|
+
source: { type: 'base64', media_type: a.mimeType, data: a.data },
|
|
90
|
+
})),
|
|
91
|
+
{ type: 'text', text: m.content },
|
|
92
|
+
],
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/** Gemini generateContent: bijlagen als `inlineData` in de laatste gebruikersbeurt. */
|
|
96
|
+
export function buildGeminiContents(messages, attachments) {
|
|
97
|
+
const rest = messages.filter(m => m.role !== 'system');
|
|
98
|
+
const idx = attachments.length ? lastUserIndex(rest) : -1;
|
|
99
|
+
return rest.map((m, i) => ({
|
|
100
|
+
role: m.role === 'assistant' ? 'model' : 'user',
|
|
101
|
+
parts: i === idx
|
|
102
|
+
? [...attachments.map(a => ({ inlineData: { mimeType: a.mimeType, data: a.data } })), { text: m.content }]
|
|
103
|
+
: [{ text: m.content }],
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type { AiChatMessage, AiChatOptions, AiChatResult, AiChatBindingInfo } from './aiChat.types.js';
|
|
2
|
-
export type { AiChatMessage, AiChatOptions, AiChatResult, AiChatBindingInfo, AiChatSuccess, AiChatError, AiChatUsage, AiChatRole } from './aiChat.types.js';
|
|
1
|
+
import type { AiChatAttachment, AiChatMessage, AiChatOptions, AiChatResult, AiChatBindingInfo } from './aiChat.types.js';
|
|
2
|
+
export type { AiChatAttachment, AiChatMessage, AiChatOptions, AiChatResult, AiChatBindingInfo, AiChatSuccess, AiChatError, AiChatUsage, AiChatRole } from './aiChat.types.js';
|
|
3
3
|
declare function validate(input: unknown): {
|
|
4
4
|
consumerModuleId: string;
|
|
5
5
|
messages: AiChatMessage[];
|
|
6
6
|
options?: AiChatOptions;
|
|
7
|
+
attachments?: AiChatAttachment[];
|
|
7
8
|
};
|
|
8
9
|
export declare const runAiChat: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
|
|
9
10
|
supabase: import("../integrations/supabase/auth-middleware.js").AuthedSupabaseClient;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aiChat.functions.d.ts","sourceRoot":"","sources":["../../src/lib/aiChat.functions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"aiChat.functions.d.ts","sourceRoot":"","sources":["../../src/lib/aiChat.functions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEtH,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAI3K,iBAAS,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,aAAa,CAAC;IAAC,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAA;CAAE,CA6BpJ;AAED,eAAO,MAAM,SAAS;;;;6EAMlB,CAAC;AAEL,eAAO,MAAM,iBAAiB;;;;8CAEJ,OAAO;;8BAS7B,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createServerFn } from '@tanstack/react-start';
|
|
2
2
|
import { requireSupabaseAuth } from '../integrations/supabase/auth-middleware.js';
|
|
3
|
+
import { normalizeAttachments } from './aiAttachments.js';
|
|
3
4
|
const ALLOWED_ROLES = new Set(['system', 'user', 'assistant']);
|
|
4
5
|
function validate(input) {
|
|
5
6
|
const v = (input ?? {});
|
|
@@ -27,7 +28,11 @@ function validate(input) {
|
|
|
27
28
|
options.maxTokens = rawOpts.maxTokens;
|
|
28
29
|
if (typeof rawOpts.topP === 'number')
|
|
29
30
|
options.topP = rawOpts.topP;
|
|
30
|
-
|
|
31
|
+
const attachments = normalizeAttachments(v.attachments);
|
|
32
|
+
if (attachments.length && !messages.some(m => m.role === 'user')) {
|
|
33
|
+
throw new Error('Een bijlage vereist minimaal één gebruikersbericht');
|
|
34
|
+
}
|
|
35
|
+
return attachments.length ? { consumerModuleId, messages, options, attachments } : { consumerModuleId, messages, options };
|
|
31
36
|
}
|
|
32
37
|
export const runAiChat = createServerFn({ method: 'POST' })
|
|
33
38
|
.middleware([requireSupabaseAuth])
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AiChatMessage, AiChatOptions, AiChatResult, AiChatBindingInfo } from './aiChat.types.js';
|
|
1
|
+
import type { AiChatAttachment, AiChatMessage, AiChatOptions, AiChatResult, AiChatBindingInfo } from './aiChat.types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Zelfherstel: als de koppeling geen (geldige) sleutel meer heeft, pak dan de
|
|
4
4
|
* actieve sleutel van DEZELFDE provider en leg die keuze vast in de koppeling.
|
|
@@ -10,10 +10,17 @@ export declare function adoptActiveCredential(bindingId: string, providerId: str
|
|
|
10
10
|
active: boolean;
|
|
11
11
|
label: string;
|
|
12
12
|
} | null>;
|
|
13
|
+
/**
|
|
14
|
+
* Vangnet: een module die AI vraagt maar nog niet bekend is, wordt hier (server-side,
|
|
15
|
+
* service role) aangemeld. Hij verschijnt dan met "Nog geen AI-agent" in het beheerscherm;
|
|
16
|
+
* zonder koppeling gaat er nooit een aanroep naar een provider.
|
|
17
|
+
*/
|
|
18
|
+
export declare function registerRuntimeConsumer(consumerModuleId: string): Promise<void>;
|
|
13
19
|
export declare function runAiChatForRequest(input: {
|
|
14
20
|
consumerModuleId: string;
|
|
15
21
|
messages: AiChatMessage[];
|
|
16
22
|
options?: AiChatOptions;
|
|
23
|
+
attachments?: AiChatAttachment[];
|
|
17
24
|
}): Promise<AiChatResult>;
|
|
18
25
|
export declare function describeBindingForRequest(consumerModuleId: string): Promise<AiChatBindingInfo>;
|
|
19
26
|
//# sourceMappingURL=aiChat.server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aiChat.server.d.ts","sourceRoot":"","sources":["../../src/lib/aiChat.server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"aiChat.server.d.ts","sourceRoot":"","sources":["../../src/lib/aiChat.server.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,gBAAgB,EAEhB,aAAa,EACb,aAAa,EACb,YAAY,EAEZ,iBAAiB,EAClB,MAAM,gBAAgB,CAAC;AAoQxB;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAYjF;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMrF;AAuFD,wBAAsB,mBAAmB,CACvC,KAAK,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,aAAa,CAAC;IAAC,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAA;CAAE,GACxH,OAAO,CAAC,YAAY,CAAC,CAuDvB;AAED,wBAAsB,yBAAyB,CAC7C,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,iBAAiB,CAAC,CAW5B"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { supabaseAdmin } from '../integrations/supabase/client.server.js';
|
|
2
|
+
import { buildAnthropicMessages, buildGeminiContents, buildOpenAIMessages, pdfSupportProblem, providerKind, } from './aiAttachments.js';
|
|
2
3
|
function isChatError(v) {
|
|
3
4
|
return !!v && typeof v === 'object' && v.ok === false;
|
|
4
5
|
}
|
|
@@ -55,7 +56,7 @@ function trimBase(url) {
|
|
|
55
56
|
return url.trim().replace(/\/+$/, '');
|
|
56
57
|
}
|
|
57
58
|
// ─── Provider adapters ────────────────────────────────────────────────
|
|
58
|
-
async function callOpenAI(apiKey, baseUrl, modelSlug, messages, options) {
|
|
59
|
+
async function callOpenAI(apiKey, baseUrl, modelSlug, messages, options, attachments = []) {
|
|
59
60
|
const base = trimBase(baseUrl || OPENAI_DEFAULT);
|
|
60
61
|
const url = `${base}/chat/completions`;
|
|
61
62
|
const { signal, done } = withTimeout();
|
|
@@ -69,7 +70,7 @@ async function callOpenAI(apiKey, baseUrl, modelSlug, messages, options) {
|
|
|
69
70
|
},
|
|
70
71
|
body: JSON.stringify({
|
|
71
72
|
model: modelSlug,
|
|
72
|
-
messages,
|
|
73
|
+
messages: buildOpenAIMessages(messages, attachments),
|
|
73
74
|
...(options.temperature != null ? { temperature: options.temperature } : {}),
|
|
74
75
|
...(options.maxTokens != null ? { max_tokens: options.maxTokens } : {}),
|
|
75
76
|
...(options.topP != null ? { top_p: options.topP } : {}),
|
|
@@ -98,14 +99,12 @@ async function callOpenAI(apiKey, baseUrl, modelSlug, messages, options) {
|
|
|
98
99
|
done();
|
|
99
100
|
}
|
|
100
101
|
}
|
|
101
|
-
async function callAnthropic(apiKey, baseUrl, modelSlug, messages, options) {
|
|
102
|
+
async function callAnthropic(apiKey, baseUrl, modelSlug, messages, options, attachments = []) {
|
|
102
103
|
const base = trimBase(baseUrl || ANTHROPIC_DEFAULT);
|
|
103
104
|
const url = `${base}/v1/messages`;
|
|
104
105
|
// Anthropic vereist system als top-level string en messages zonder system-rol.
|
|
105
106
|
const systemParts = messages.filter(m => m.role === 'system').map(m => m.content).filter(Boolean);
|
|
106
|
-
const rest = messages
|
|
107
|
-
.filter(m => m.role !== 'system')
|
|
108
|
-
.map(m => ({ role: m.role, content: m.content }));
|
|
107
|
+
const rest = buildAnthropicMessages(messages, attachments);
|
|
109
108
|
const { signal, done } = withTimeout();
|
|
110
109
|
try {
|
|
111
110
|
const res = await fetch(url, {
|
|
@@ -167,17 +166,12 @@ function normalizeGeminiBase(baseUrl) {
|
|
|
167
166
|
return GEMINI_DEFAULT;
|
|
168
167
|
}
|
|
169
168
|
}
|
|
170
|
-
async function callGemini(apiKey, baseUrl, modelSlug, messages, options) {
|
|
169
|
+
async function callGemini(apiKey, baseUrl, modelSlug, messages, options, attachments = []) {
|
|
171
170
|
const base = normalizeGeminiBase(baseUrl);
|
|
172
171
|
const modelPath = modelSlug.startsWith('models/') ? modelSlug : `models/${modelSlug}`;
|
|
173
172
|
const url = `${base}/${modelPath}:generateContent?key=${encodeURIComponent(apiKey)}`;
|
|
174
173
|
const systemParts = messages.filter(m => m.role === 'system').map(m => m.content).filter(Boolean);
|
|
175
|
-
const contents = messages
|
|
176
|
-
.filter(m => m.role !== 'system')
|
|
177
|
-
.map(m => ({
|
|
178
|
-
role: m.role === 'assistant' ? 'model' : 'user',
|
|
179
|
-
parts: [{ text: m.content }],
|
|
180
|
-
}));
|
|
174
|
+
const contents = buildGeminiContents(messages, attachments);
|
|
181
175
|
const body = {
|
|
182
176
|
contents,
|
|
183
177
|
generationConfig: {
|
|
@@ -240,13 +234,30 @@ export async function adoptActiveCredential(bindingId, providerId) {
|
|
|
240
234
|
await supabaseAdmin.from('ai_module_bindings').update({ credential_id: cred.id }).eq('id', bindingId);
|
|
241
235
|
return { id: cred.id, api_key: cred.api_key, active: cred.active, label: cred.label };
|
|
242
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* Vangnet: een module die AI vraagt maar nog niet bekend is, wordt hier (server-side,
|
|
239
|
+
* service role) aangemeld. Hij verschijnt dan met "Nog geen AI-agent" in het beheerscherm;
|
|
240
|
+
* zonder koppeling gaat er nooit een aanroep naar een provider.
|
|
241
|
+
*/
|
|
242
|
+
export async function registerRuntimeConsumer(consumerModuleId) {
|
|
243
|
+
try {
|
|
244
|
+
await supabaseAdmin.rpc('ai_register_runtime_consumer', { _module_key: consumerModuleId });
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
// registratie mag een aanroep nooit blokkeren
|
|
248
|
+
}
|
|
249
|
+
}
|
|
243
250
|
async function moduleAiEnabled(consumerModuleId) {
|
|
244
251
|
const { data } = await supabaseAdmin
|
|
245
252
|
.from('ai_modules')
|
|
246
253
|
.select('module_key, ai_enabled')
|
|
247
254
|
.eq('module_key', consumerModuleId)
|
|
248
255
|
.maybeSingle();
|
|
249
|
-
|
|
256
|
+
if (!data) {
|
|
257
|
+
await registerRuntimeConsumer(consumerModuleId);
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
return data.ai_enabled === true;
|
|
250
261
|
}
|
|
251
262
|
async function resolveBinding(consumerModuleId) {
|
|
252
263
|
if (!(await moduleAiEnabled(consumerModuleId))) {
|
|
@@ -327,15 +338,24 @@ export async function runAiChatForRequest(input) {
|
|
|
327
338
|
const { provider, model, credential } = resolved;
|
|
328
339
|
const slug = provider.slug.toLowerCase();
|
|
329
340
|
const options = input.options ?? {};
|
|
341
|
+
const attachments = Array.isArray(input.attachments) ? input.attachments : [];
|
|
342
|
+
if (attachments.length) {
|
|
343
|
+
const problem = pdfSupportProblem(providerKind(provider.slug), model.slug);
|
|
344
|
+
if (problem) {
|
|
345
|
+
const r = err(400, 'unsupported_attachment', problem);
|
|
346
|
+
await logCall({ consumerModuleId: input.consumerModuleId, providerSlug: provider.slug, modelSlug: model.slug, result: r, durationMs: Date.now() - started });
|
|
347
|
+
return r;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
330
350
|
let providerRes;
|
|
331
351
|
if (slug.includes('openai') || slug.includes('gpt')) {
|
|
332
|
-
providerRes = await callOpenAI(credential.api_key, provider.base_url, model.slug, input.messages, options);
|
|
352
|
+
providerRes = await callOpenAI(credential.api_key, provider.base_url, model.slug, input.messages, options, attachments);
|
|
333
353
|
}
|
|
334
354
|
else if (slug.includes('anthropic') || slug.includes('claude')) {
|
|
335
|
-
providerRes = await callAnthropic(credential.api_key, provider.base_url, model.slug, input.messages, options);
|
|
355
|
+
providerRes = await callAnthropic(credential.api_key, provider.base_url, model.slug, input.messages, options, attachments);
|
|
336
356
|
}
|
|
337
357
|
else if (slug.includes('gemini') || slug.includes('google')) {
|
|
338
|
-
providerRes = await callGemini(credential.api_key, provider.base_url, model.slug, input.messages, options);
|
|
358
|
+
providerRes = await callGemini(credential.api_key, provider.base_url, model.slug, input.messages, options, attachments);
|
|
339
359
|
}
|
|
340
360
|
else {
|
|
341
361
|
const r = err(400, 'unsupported_provider', `Provider "${provider.name}" wordt niet ondersteund voor chat.`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aiChat.stream.server.d.ts","sourceRoot":"","sources":["../../src/lib/aiChat.stream.server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7F;;;GAGG;AAEH,KAAK,WAAW,GACZ;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACxG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC7E;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB,wBAAuB,sBAAsB,CAAC,KAAK,EAAE;IACnD,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,GAAG,cAAc,CAAC,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"aiChat.stream.server.d.ts","sourceRoot":"","sources":["../../src/lib/aiChat.stream.server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7F;;;GAGG;AAEH,KAAK,WAAW,GACZ;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACxG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC7E;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB,wBAAuB,sBAAsB,CAAC,KAAK,EAAE;IACnD,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,GAAG,cAAc,CAAC,WAAW,CAAC,CAqG9B"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { supabaseAdmin } from '../integrations/supabase/client.server.js';
|
|
2
|
-
import { adoptActiveCredential } from './aiChat.server.js';
|
|
2
|
+
import { adoptActiveCredential, registerRuntimeConsumer } from './aiChat.server.js';
|
|
3
3
|
export async function* streamAiChatForRequest(input) {
|
|
4
4
|
const started = Date.now();
|
|
5
5
|
const { data: moduleRow } = await supabaseAdmin.from('ai_modules').select('module_key, ai_enabled').eq('module_key', input.consumerModuleId).maybeSingle();
|
|
6
|
+
if (!moduleRow)
|
|
7
|
+
await registerRuntimeConsumer(input.consumerModuleId);
|
|
6
8
|
if (!moduleRow || moduleRow.ai_enabled !== true) {
|
|
7
9
|
yield { type: 'error', code: 'no_binding', status: 404, message: `Module "${input.consumerModuleId}" heeft geen AI ingeschakeld.` };
|
|
8
10
|
return;
|
|
@@ -3,6 +3,12 @@ export type AiChatMessage = {
|
|
|
3
3
|
role: AiChatRole;
|
|
4
4
|
content: string;
|
|
5
5
|
};
|
|
6
|
+
/** Pdf-bijlage (base64, zonder data:-voorvoegsel). */
|
|
7
|
+
export type AiChatAttachment = {
|
|
8
|
+
mimeType: 'application/pdf';
|
|
9
|
+
data: string;
|
|
10
|
+
filename?: string;
|
|
11
|
+
};
|
|
6
12
|
export type AiChatOptions = {
|
|
7
13
|
temperature?: number;
|
|
8
14
|
maxTokens?: number;
|
|
@@ -43,8 +49,9 @@ export type AiChatError = {
|
|
|
43
49
|
* - `network` — netwerk/timeout
|
|
44
50
|
* - `unsupported_provider` — providerslug niet herkend
|
|
45
51
|
* - `forbidden` — 403
|
|
52
|
+
* - `unsupported_attachment` — provider/model kan deze bijlage niet lezen
|
|
46
53
|
*/
|
|
47
|
-
code: 'no_binding' | 'not_configured' | 'unauthorized' | 'rate_limited' | 'quota_exceeded' | 'bad_request' | 'provider_error' | 'network' | 'unsupported_provider' | 'forbidden';
|
|
54
|
+
code: 'no_binding' | 'not_configured' | 'unauthorized' | 'rate_limited' | 'quota_exceeded' | 'bad_request' | 'provider_error' | 'network' | 'unsupported_provider' | 'forbidden' | 'unsupported_attachment';
|
|
48
55
|
message: string;
|
|
49
56
|
};
|
|
50
57
|
export type AiChatResult = AiChatSuccess | AiChatError;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aiChat.types.d.ts","sourceRoot":"","sources":["../../src/lib/aiChat.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;AAEzD,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,IAAI,CAAC;IACT,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf
|
|
1
|
+
{"version":3,"file":"aiChat.types.d.ts","sourceRoot":"","sources":["../../src/lib/aiChat.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;AAEzD,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,sDAAsD;AACtD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,IAAI,CAAC;IACT,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;;OAaG;IACH,IAAI,EACA,YAAY,GACZ,gBAAgB,GAChB,cAAc,GACd,cAAc,GACd,gBAAgB,GAChB,aAAa,GACb,gBAAgB,GAChB,SAAS,GACT,sBAAsB,GACtB,WAAW,GACX,wBAAwB,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,WAAW,CAAC;AAEvD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAChD,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACpD,wDAAwD;IACxD,UAAU,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC"}
|
|
@@ -4,6 +4,10 @@ export type AiModuleRow = {
|
|
|
4
4
|
module_key: string;
|
|
5
5
|
module_name: string;
|
|
6
6
|
ai_enabled: boolean;
|
|
7
|
+
declared_ai?: boolean;
|
|
8
|
+
ai_source?: string | null;
|
|
9
|
+
last_declared_at?: string | null;
|
|
10
|
+
is_in_use?: boolean;
|
|
7
11
|
};
|
|
8
12
|
export type AiModuleStats = {
|
|
9
13
|
module_key: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aiModules.server.d.ts","sourceRoot":"","sources":["../../src/lib/aiModules.server.ts"],"names":[],"mappings":"AAAA,wFAAwF;AAExF,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,kBAAkB,EAAE,MAAM,CAAC;IAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAErF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQtD;AAMD,wBAAsB,WAAW,CAAC,QAAQ,EAAE,GAAG,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"aiModules.server.d.ts","sourceRoot":"","sources":["../../src/lib/aiModules.server.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,10 +14,13 @@ function emptyStats(module_key) {
|
|
|
14
14
|
export async function listModules(supabase) {
|
|
15
15
|
const { data, error } = await supabase
|
|
16
16
|
.from('ai_modules')
|
|
17
|
-
.select('id, module_key, module_name, ai_enabled')
|
|
17
|
+
.select('id, module_key, module_name, ai_enabled, declared_ai, ai_source, last_declared_at, is_in_use')
|
|
18
18
|
.order('module_name');
|
|
19
|
-
if (error)
|
|
20
|
-
|
|
19
|
+
if (error) {
|
|
20
|
+
// Oudere database zonder de nieuwe kolommen: val terug op de basisvelden.
|
|
21
|
+
const fb = await supabase.from('ai_modules').select('id, module_key, module_name, ai_enabled').order('module_name');
|
|
22
|
+
return (Array.isArray(fb.data) ? fb.data : []);
|
|
23
|
+
}
|
|
21
24
|
return (Array.isArray(data) ? data : []);
|
|
22
25
|
}
|
|
23
26
|
export async function upsertModule(supabase, input) {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers voor het `flowselections.ai`-veld in package.json van modules.
|
|
3
|
+
* Gebruikt door shell-setup en update dashboard (via registerAiConsumers) en getest zonder database.
|
|
4
|
+
*
|
|
5
|
+
* "flowselections": { "ai": [{ "moduleKey": "werkbon-postvak", "name": "Postvak Werkbonnen", "description": "..." }] }
|
|
6
|
+
*/
|
|
7
|
+
export type AiConsumerDeclaration = {
|
|
8
|
+
moduleKey: string;
|
|
9
|
+
name: string;
|
|
10
|
+
description?: string | null;
|
|
11
|
+
};
|
|
12
|
+
/** Resultaat van het lezen van alle geïnstalleerde pakketten in een shell. */
|
|
13
|
+
export type InstalledPackageRead = {
|
|
14
|
+
packageName: string;
|
|
15
|
+
ok: boolean;
|
|
16
|
+
/** Ruwe inhoud van package.json (alleen bij ok). */
|
|
17
|
+
manifest?: unknown;
|
|
18
|
+
};
|
|
19
|
+
export declare function normalizeAiDeclarations(raw: unknown): AiConsumerDeclaration[];
|
|
20
|
+
/** Haal de AI-declaraties uit één package.json (`flowselections.ai`). */
|
|
21
|
+
export declare function declarationsFromManifest(manifest: unknown): AiConsumerDeclaration[];
|
|
22
|
+
/**
|
|
23
|
+
* Bouw de registratie-aanvraag uit alle gelezen pakketten.
|
|
24
|
+
* `fullList` is alleen waar als ÉLK pakket zonder fout is gelezen en er minstens één
|
|
25
|
+
* declaratie is; anders wordt in de database nooit iets op "niet meer in gebruik" gezet.
|
|
26
|
+
*/
|
|
27
|
+
export declare function buildRegistration(reads: InstalledPackageRead[]): {
|
|
28
|
+
modules: AiConsumerDeclaration[];
|
|
29
|
+
fullList: boolean;
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=aiRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aiRegistry.d.ts","sourceRoot":"","sources":["../../src/lib/aiRegistry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,CAAC;AAEF,8EAA8E;AAC9E,MAAM,MAAM,oBAAoB,GAAG;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,EAAE,EAAE,OAAO,CAAC;IACZ,oDAAoD;IACpD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAIF,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,qBAAqB,EAAE,CAa7E;AAED,yEAAyE;AACzE,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,OAAO,GAAG,qBAAqB,EAAE,CAGnF;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,oBAAoB,EAAE,GAAG;IAChE,OAAO,EAAE,qBAAqB,EAAE,CAAC;IACjC,QAAQ,EAAE,OAAO,CAAC;CACnB,CAUA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type AiConsumerDeclaration } from './aiRegistry.js';
|
|
2
|
+
export type { AiConsumerDeclaration };
|
|
3
|
+
export type AiRegistrationResult = {
|
|
4
|
+
ok: boolean;
|
|
5
|
+
message: string;
|
|
6
|
+
registered?: number;
|
|
7
|
+
retired?: number;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Meld AI-gebruikende modules aan in de database van deze shell.
|
|
11
|
+
* Alleen beheerders (controle in de database-functie). Nooit verwijderen;
|
|
12
|
+
* `fullList` alleen meegeven als de complete lijst geïnstalleerde modules zonder fouten is gelezen.
|
|
13
|
+
*/
|
|
14
|
+
export declare const registerAiConsumers: import("@tanstack/start-client-core").RequiredFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
|
|
15
|
+
supabase: import("../integrations/supabase/auth-middleware.js").AuthedSupabaseClient;
|
|
16
|
+
userId: string;
|
|
17
|
+
claims: import("@supabase/auth-js").User;
|
|
18
|
+
}, undefined, undefined, undefined>], (data: {
|
|
19
|
+
modules: AiConsumerDeclaration[];
|
|
20
|
+
fullList?: boolean;
|
|
21
|
+
}) => {
|
|
22
|
+
modules: AiConsumerDeclaration[];
|
|
23
|
+
fullList: boolean;
|
|
24
|
+
}, Promise<AiRegistrationResult>>;
|
|
25
|
+
//# sourceMappingURL=aiRegistry.functions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aiRegistry.functions.d.ts","sourceRoot":"","sources":["../../src/lib/aiRegistry.functions.ts"],"names":[],"mappings":"AAEA,OAAO,EAA2B,KAAK,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAEnF,YAAY,EAAE,qBAAqB,EAAE,CAAC;AACtC,MAAM,MAAM,oBAAoB,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3G;;;;GAIG;AACH,eAAO,MAAM,mBAAmB;;;;6CAEP;IAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE;;;iCAa7E,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createServerFn } from '@tanstack/react-start';
|
|
2
|
+
import { requireSupabaseAuth } from '../integrations/supabase/auth-middleware.js';
|
|
3
|
+
import { normalizeAiDeclarations } from './aiRegistry.js';
|
|
4
|
+
/**
|
|
5
|
+
* Meld AI-gebruikende modules aan in de database van deze shell.
|
|
6
|
+
* Alleen beheerders (controle in de database-functie). Nooit verwijderen;
|
|
7
|
+
* `fullList` alleen meegeven als de complete lijst geïnstalleerde modules zonder fouten is gelezen.
|
|
8
|
+
*/
|
|
9
|
+
export const registerAiConsumers = createServerFn({ method: 'POST' })
|
|
10
|
+
.middleware([requireSupabaseAuth])
|
|
11
|
+
.inputValidator((data) => ({
|
|
12
|
+
modules: normalizeAiDeclarations(data?.modules),
|
|
13
|
+
fullList: data?.fullList === true,
|
|
14
|
+
}))
|
|
15
|
+
.handler(async ({ data, context }) => {
|
|
16
|
+
const { data: res, error } = await context.supabase.rpc('ai_register_consumers', {
|
|
17
|
+
_modules: data.modules,
|
|
18
|
+
_full_list: data.fullList && data.modules.length > 0,
|
|
19
|
+
_source: 'manifest',
|
|
20
|
+
});
|
|
21
|
+
if (error)
|
|
22
|
+
return { ok: false, message: `Registreren mislukt: ${error.message}` };
|
|
23
|
+
const r = (res ?? {});
|
|
24
|
+
return { ok: true, message: 'AI-modules bijgewerkt.', registered: Number(r.registered ?? 0), retired: Number(r.retired ?? 0) };
|
|
25
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers voor het `flowselections.ai`-veld in package.json van modules.
|
|
3
|
+
* Gebruikt door shell-setup en update dashboard (via registerAiConsumers) en getest zonder database.
|
|
4
|
+
*
|
|
5
|
+
* "flowselections": { "ai": [{ "moduleKey": "werkbon-postvak", "name": "Postvak Werkbonnen", "description": "..." }] }
|
|
6
|
+
*/
|
|
7
|
+
const KEY_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
8
|
+
export function normalizeAiDeclarations(raw) {
|
|
9
|
+
const list = Array.isArray(raw) ? raw : raw && typeof raw === 'object' ? [raw] : [];
|
|
10
|
+
const out = new Map();
|
|
11
|
+
for (const item of list) {
|
|
12
|
+
if (!item || typeof item !== 'object')
|
|
13
|
+
continue;
|
|
14
|
+
const v = item;
|
|
15
|
+
const key = String(v.moduleKey ?? v.module_key ?? '').trim().toLowerCase();
|
|
16
|
+
if (!KEY_RE.test(key))
|
|
17
|
+
continue;
|
|
18
|
+
const name = String(v.name ?? v.module_name ?? '').trim() || key;
|
|
19
|
+
const description = typeof v.description === 'string' && v.description.trim() ? v.description.trim() : null;
|
|
20
|
+
out.set(key, { moduleKey: key, name, description });
|
|
21
|
+
}
|
|
22
|
+
return Array.from(out.values());
|
|
23
|
+
}
|
|
24
|
+
/** Haal de AI-declaraties uit één package.json (`flowselections.ai`). */
|
|
25
|
+
export function declarationsFromManifest(manifest) {
|
|
26
|
+
const fs = manifest?.flowselections;
|
|
27
|
+
return normalizeAiDeclarations(fs?.ai);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Bouw de registratie-aanvraag uit alle gelezen pakketten.
|
|
31
|
+
* `fullList` is alleen waar als ÉLK pakket zonder fout is gelezen en er minstens één
|
|
32
|
+
* declaratie is; anders wordt in de database nooit iets op "niet meer in gebruik" gezet.
|
|
33
|
+
*/
|
|
34
|
+
export function buildRegistration(reads) {
|
|
35
|
+
const safe = Array.isArray(reads) ? reads : [];
|
|
36
|
+
const allOk = safe.length > 0 && safe.every(r => r && r.ok === true);
|
|
37
|
+
const merged = new Map();
|
|
38
|
+
for (const r of safe) {
|
|
39
|
+
if (!r?.ok)
|
|
40
|
+
continue;
|
|
41
|
+
for (const d of declarationsFromManifest(r.manifest))
|
|
42
|
+
merged.set(d.moduleKey, d);
|
|
43
|
+
}
|
|
44
|
+
const modules = Array.from(merged.values());
|
|
45
|
+
return { modules, fullList: allOk && modules.length > 0 };
|
|
46
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-only: registratie met de service role, voor shell-setup en update dashboard
|
|
3
|
+
* die zonder ingelogde gebruiker draaien. Nooit vanuit de browser importeren.
|
|
4
|
+
*/
|
|
5
|
+
import { type InstalledPackageRead } from './aiRegistry.js';
|
|
6
|
+
export declare function registerAiConsumersFromPackages(reads: InstalledPackageRead[]): Promise<{
|
|
7
|
+
ok: boolean;
|
|
8
|
+
message: string;
|
|
9
|
+
registered: number;
|
|
10
|
+
retired: number;
|
|
11
|
+
fullList: boolean;
|
|
12
|
+
}>;
|
|
13
|
+
//# sourceMappingURL=aiRegistry.server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aiRegistry.server.d.ts","sourceRoot":"","sources":["../../src/lib/aiRegistry.server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAqB,KAAK,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAE5E,wBAAsB,+BAA+B,CACnD,KAAK,EAAE,oBAAoB,EAAE,GAC5B,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,CAcnG"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-only: registratie met de service role, voor shell-setup en update dashboard
|
|
3
|
+
* die zonder ingelogde gebruiker draaien. Nooit vanuit de browser importeren.
|
|
4
|
+
*/
|
|
5
|
+
import { buildRegistration } from './aiRegistry.js';
|
|
6
|
+
export async function registerAiConsumersFromPackages(reads) {
|
|
7
|
+
const { modules, fullList } = buildRegistration(reads);
|
|
8
|
+
if (modules.length === 0) {
|
|
9
|
+
return { ok: true, message: 'Geen AI-declaraties gevonden; niets gewijzigd.', registered: 0, retired: 0, fullList: false };
|
|
10
|
+
}
|
|
11
|
+
const { supabaseAdmin } = await import('../integrations/supabase/client.server.js');
|
|
12
|
+
const { data, error } = await supabaseAdmin.rpc('ai_register_consumers', {
|
|
13
|
+
_modules: modules,
|
|
14
|
+
_full_list: fullList,
|
|
15
|
+
_source: 'manifest',
|
|
16
|
+
});
|
|
17
|
+
if (error)
|
|
18
|
+
return { ok: false, message: `Registreren mislukt: ${error.message}`, registered: 0, retired: 0, fullList };
|
|
19
|
+
const r = (data ?? {});
|
|
20
|
+
return { ok: true, message: 'AI-modules bijgewerkt.', registered: Number(r.registered ?? 0), retired: Number(r.retired ?? 0), fullList };
|
|
21
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aiUsageByModule.functions.d.ts","sourceRoot":"","sources":["../../src/lib/aiUsageByModule.functions.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,kBAAkB;;;;8CAEL,OAAO;;iCAsB7B,CAAC;AAEL,eAAO,MAAM,SAAS;;;;;QAEwB,OAAO;
|
|
1
|
+
{"version":3,"file":"aiUsageByModule.functions.d.ts","sourceRoot":"","sources":["../../src/lib/aiUsageByModule.functions.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,kBAAkB;;;;8CAEL,OAAO;;iCAsB7B,CAAC;AAEL,eAAO,MAAM,SAAS;;;;;QAEwB,OAAO;GAGjD,CAAC"}
|
|
@@ -29,9 +29,6 @@ export const getAiUsageByModule = createServerFn({ method: 'POST' })
|
|
|
29
29
|
export const isAiAdmin = createServerFn({ method: 'GET' })
|
|
30
30
|
.middleware([requireSupabaseAuth])
|
|
31
31
|
.handler(async ({ context }) => {
|
|
32
|
-
const { data } = await context.supabase.rpc('
|
|
33
|
-
_user_id: context.userId,
|
|
34
|
-
_role: 'ai_admin',
|
|
35
|
-
});
|
|
32
|
+
const { data } = await context.supabase.rpc('ai_is_admin', { _uid: context.userId });
|
|
36
33
|
return { ok: data === true };
|
|
37
34
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modules.server.d.ts","sourceRoot":"","sources":["../../src/lib/modules.server.ts"],"names":[],"mappings":"AAAA,yFAAyF;AAEzF,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQtD;AAED,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,GAAG,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAc/E;AAED,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,GAAG,EACb,KAAK,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC/E,OAAO,CAAC,oBAAoB,CAAC,
|
|
1
|
+
{"version":3,"file":"modules.server.d.ts","sourceRoot":"","sources":["../../src/lib/modules.server.ts"],"names":[],"mappings":"AAAA,yFAAyF;AAEzF,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQtD;AAED,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,GAAG,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAc/E;AAED,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,GAAG,EACb,KAAK,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC/E,OAAO,CAAC,oBAAoB,CAAC,CAe/B;AAED,wBAAsB,eAAe,CACnC,QAAQ,EAAE,GAAG,EACb,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,OAAO,GACjB,OAAO,CAAC,oBAAoB,CAAC,CAK/B"}
|