@cogenta/agents 0.2.1 → 0.4.0
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/agents/builtins.d.ts +51 -0
- package/dist/agents/builtins.d.ts.map +1 -0
- package/dist/agents/builtins.js +190 -0
- package/dist/agents/builtins.js.map +1 -0
- package/dist/agents/orchestrator.d.ts +95 -0
- package/dist/agents/orchestrator.d.ts.map +1 -0
- package/dist/agents/orchestrator.js +285 -0
- package/dist/agents/orchestrator.js.map +1 -0
- package/dist/agents/store.d.ts +71 -0
- package/dist/agents/store.d.ts.map +1 -0
- package/dist/agents/store.js +211 -0
- package/dist/agents/store.js.map +1 -0
- package/dist/agents/types.d.ts +10 -0
- package/dist/agents/types.d.ts.map +1 -1
- package/dist/assist/agent-identity.d.ts +44 -0
- package/dist/assist/agent-identity.d.ts.map +1 -0
- package/dist/assist/agent-identity.js +136 -0
- package/dist/assist/agent-identity.js.map +1 -0
- package/dist/assist/chat.d.ts +2 -0
- package/dist/assist/chat.d.ts.map +1 -1
- package/dist/assist/chat.js +14 -5
- package/dist/assist/chat.js.map +1 -1
- package/dist/assist/classify.d.ts +3 -2
- package/dist/assist/classify.d.ts.map +1 -1
- package/dist/assist/classify.js +30 -11
- package/dist/assist/classify.js.map +1 -1
- package/dist/assist/faq.d.ts +3 -2
- package/dist/assist/faq.d.ts.map +1 -1
- package/dist/assist/faq.js +31 -13
- package/dist/assist/faq.js.map +1 -1
- package/dist/assist/runtime.d.ts +8 -2
- package/dist/assist/runtime.d.ts.map +1 -1
- package/dist/assist/runtime.js +2 -2
- package/dist/assist/runtime.js.map +1 -1
- package/dist/assist/toolset.d.ts +10 -0
- package/dist/assist/toolset.d.ts.map +1 -1
- package/dist/assist/toolset.js +36 -8
- package/dist/assist/toolset.js.map +1 -1
- package/dist/assist/usage.d.ts +58 -0
- package/dist/assist/usage.d.ts.map +1 -0
- package/dist/assist/usage.js +53 -0
- package/dist/assist/usage.js.map +1 -0
- package/dist/assist/writing.d.ts +10 -9
- package/dist/assist/writing.d.ts.map +1 -1
- package/dist/assist/writing.js +126 -58
- package/dist/assist/writing.js.map +1 -1
- package/dist/audit/with-audit.d.ts +13 -0
- package/dist/audit/with-audit.d.ts.map +1 -1
- package/dist/audit/with-audit.js +6 -0
- package/dist/audit/with-audit.js.map +1 -1
- package/dist/autonomy/levels.d.ts +37 -0
- package/dist/autonomy/levels.d.ts.map +1 -0
- package/dist/autonomy/levels.js +51 -0
- package/dist/autonomy/levels.js.map +1 -0
- package/dist/conversations/store.d.ts +62 -0
- package/dist/conversations/store.d.ts.map +1 -0
- package/dist/conversations/store.js +0 -0
- package/dist/conversations/store.js.map +1 -0
- package/dist/identity/context.d.ts +8 -0
- package/dist/identity/context.d.ts.map +1 -1
- package/dist/identity/context.js +19 -4
- package/dist/identity/context.js.map +1 -1
- package/dist/identity/markdown.d.ts +38 -0
- package/dist/identity/markdown.d.ts.map +1 -0
- package/dist/identity/markdown.js +85 -0
- package/dist/identity/markdown.js.map +1 -0
- package/dist/index.d.ts +56 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -3
- package/dist/index.js.map +1 -1
- package/dist/prompts/render.d.ts +23 -0
- package/dist/prompts/render.d.ts.map +1 -0
- package/dist/prompts/render.js +35 -0
- package/dist/prompts/render.js.map +1 -0
- package/dist/prompts/seeds.d.ts +34 -0
- package/dist/prompts/seeds.d.ts.map +1 -0
- package/dist/prompts/seeds.js +166 -0
- package/dist/prompts/seeds.js.map +1 -0
- package/dist/prompts/store.d.ts +8 -0
- package/dist/prompts/store.d.ts.map +1 -0
- package/dist/prompts/store.js +153 -0
- package/dist/prompts/store.js.map +1 -0
- package/dist/prompts/types.d.ts +51 -0
- package/dist/prompts/types.d.ts.map +1 -0
- package/dist/prompts/types.js +24 -0
- package/dist/prompts/types.js.map +1 -0
- package/dist/providers/anthropic.d.ts +21 -3
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +60 -12
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/catalog.d.ts +41 -0
- package/dist/providers/catalog.d.ts.map +1 -0
- package/dist/providers/catalog.js +85 -0
- package/dist/providers/catalog.js.map +1 -0
- package/dist/providers/content-parts.d.ts +12 -0
- package/dist/providers/content-parts.d.ts.map +1 -0
- package/dist/providers/content-parts.js +18 -0
- package/dist/providers/content-parts.js.map +1 -0
- package/dist/providers/defaults.d.ts +15 -0
- package/dist/providers/defaults.d.ts.map +1 -0
- package/dist/providers/defaults.js +15 -0
- package/dist/providers/defaults.js.map +1 -0
- package/dist/providers/google.d.ts +16 -3
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/google.js +54 -12
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/openai.d.ts +32 -4
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +114 -21
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/registry.d.ts +31 -20
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/registry.js +49 -7
- package/dist/providers/registry.js.map +1 -1
- package/dist/providers/request-signal.d.ts +23 -0
- package/dist/providers/request-signal.d.ts.map +1 -0
- package/dist/providers/request-signal.js +26 -0
- package/dist/providers/request-signal.js.map +1 -0
- package/dist/providers/resolve.d.ts +13 -0
- package/dist/providers/resolve.d.ts.map +1 -0
- package/dist/providers/resolve.js +30 -0
- package/dist/providers/resolve.js.map +1 -0
- package/dist/providers/store.d.ts +70 -0
- package/dist/providers/store.d.ts.map +1 -0
- package/dist/providers/store.js +308 -0
- package/dist/providers/store.js.map +1 -0
- package/dist/providers/tool-names.d.ts +9 -0
- package/dist/providers/tool-names.d.ts.map +1 -0
- package/dist/providers/tool-names.js +56 -0
- package/dist/providers/tool-names.js.map +1 -0
- package/dist/providers/types.d.ts +78 -3
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/rag/reference-documents/ingest.d.ts +22 -0
- package/dist/rag/reference-documents/ingest.d.ts.map +1 -0
- package/dist/rag/reference-documents/ingest.js +69 -0
- package/dist/rag/reference-documents/ingest.js.map +1 -0
- package/dist/rag/reference-documents/store.d.ts +23 -0
- package/dist/rag/reference-documents/store.d.ts.map +1 -0
- package/dist/rag/reference-documents/store.js +140 -0
- package/dist/rag/reference-documents/store.js.map +1 -0
- package/dist/rag/reference-documents/types.d.ts +52 -0
- package/dist/rag/reference-documents/types.d.ts.map +1 -0
- package/dist/rag/reference-documents/types.js +32 -0
- package/dist/rag/reference-documents/types.js.map +1 -0
- package/dist/runtime/loop.d.ts +29 -7
- package/dist/runtime/loop.d.ts.map +1 -1
- package/dist/runtime/loop.js +200 -42
- package/dist/runtime/loop.js.map +1 -1
- package/dist/runtime/types.d.ts +4 -3
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/site-plan/analyse-brief.d.ts +8 -0
- package/dist/site-plan/analyse-brief.d.ts.map +1 -1
- package/dist/site-plan/analyse-brief.js +18 -7
- package/dist/site-plan/analyse-brief.js.map +1 -1
- package/dist/site-plan/approval.d.ts +2 -2
- package/dist/site-plan/approval.d.ts.map +1 -1
- package/dist/site-plan/approval.js +34 -4
- package/dist/site-plan/approval.js.map +1 -1
- package/dist/site-plan/content-model.d.ts +14 -0
- package/dist/site-plan/content-model.d.ts.map +1 -1
- package/dist/site-plan/content-model.js +52 -8
- package/dist/site-plan/content-model.js.map +1 -1
- package/dist/site-plan/demo-content.js +2 -3
- package/dist/site-plan/demo-content.js.map +1 -1
- package/dist/site-plan/propose-plan.d.ts +10 -0
- package/dist/site-plan/propose-plan.d.ts.map +1 -1
- package/dist/site-plan/propose-plan.js +25 -1
- package/dist/site-plan/propose-plan.js.map +1 -1
- package/dist/site-plan/site-context.d.ts +81 -0
- package/dist/site-plan/site-context.d.ts.map +1 -0
- package/dist/site-plan/site-context.js +76 -0
- package/dist/site-plan/site-context.js.map +1 -0
- package/dist/site-plan/skin-candidates.d.ts +7 -0
- package/dist/site-plan/skin-candidates.d.ts.map +1 -1
- package/dist/site-plan/skin-candidates.js +6 -0
- package/dist/site-plan/skin-candidates.js.map +1 -1
- package/dist/site-plan/structural-gaps.d.ts +32 -0
- package/dist/site-plan/structural-gaps.d.ts.map +1 -0
- package/dist/site-plan/structural-gaps.js +77 -0
- package/dist/site-plan/structural-gaps.js.map +1 -0
- package/dist/site-plan/types.d.ts +7 -0
- package/dist/site-plan/types.d.ts.map +1 -1
- package/dist/skills/frontmatter.d.ts +19 -1
- package/dist/skills/frontmatter.d.ts.map +1 -1
- package/dist/skills/frontmatter.js +29 -5
- package/dist/skills/frontmatter.js.map +1 -1
- package/dist/skills/library.d.ts +133 -0
- package/dist/skills/library.d.ts.map +1 -0
- package/dist/skills/library.js +332 -0
- package/dist/skills/library.js.map +1 -0
- package/dist/skills/types.d.ts +8 -1
- package/dist/skills/types.d.ts.map +1 -1
- package/dist/skin/generate.d.ts +10 -0
- package/dist/skin/generate.d.ts.map +1 -1
- package/dist/skin/generate.js +43 -4
- package/dist/skin/generate.js.map +1 -1
- package/dist/theme-creator/propose-theme.d.ts +77 -0
- package/dist/theme-creator/propose-theme.d.ts.map +1 -0
- package/dist/theme-creator/propose-theme.js +228 -0
- package/dist/theme-creator/propose-theme.js.map +1 -0
- package/dist/tools/core/agent-delegate.d.ts +8 -5
- package/dist/tools/core/agent-delegate.d.ts.map +1 -1
- package/dist/tools/core/agent-delegate.js +16 -6
- package/dist/tools/core/agent-delegate.js.map +1 -1
- package/dist/tools/core/content-browse.d.ts +74 -0
- package/dist/tools/core/content-browse.d.ts.map +1 -0
- package/dist/tools/core/content-browse.js +63 -0
- package/dist/tools/core/content-browse.js.map +1 -0
- package/dist/tools/core/content-schema.d.ts +86 -0
- package/dist/tools/core/content-schema.d.ts.map +1 -0
- package/dist/tools/core/content-schema.js +83 -0
- package/dist/tools/core/content-schema.js.map +1 -0
- package/dist/tools/core/deps-scan.d.ts +25 -0
- package/dist/tools/core/deps-scan.d.ts.map +1 -0
- package/dist/tools/core/deps-scan.js +85 -0
- package/dist/tools/core/deps-scan.js.map +1 -0
- package/dist/tools/core/media.d.ts +18 -2
- package/dist/tools/core/media.d.ts.map +1 -1
- package/dist/tools/core/media.js +8 -2
- package/dist/tools/core/media.js.map +1 -1
- package/dist/tools/core/not-found-log.d.ts +44 -0
- package/dist/tools/core/not-found-log.d.ts.map +1 -0
- package/dist/tools/core/not-found-log.js +32 -0
- package/dist/tools/core/not-found-log.js.map +1 -0
- package/dist/tools/core/redirects.d.ts +51 -0
- package/dist/tools/core/redirects.d.ts.map +1 -0
- package/dist/tools/core/redirects.js +50 -0
- package/dist/tools/core/redirects.js.map +1 -0
- package/package.json +6 -4
package/dist/providers/google.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { CogentaError } from '@cogenta/core';
|
|
2
|
+
import { textOnlyContent } from './content-parts.js';
|
|
3
|
+
import { FALLBACK_MAX_OUTPUT_TOKENS } from './defaults.js';
|
|
4
|
+
import { DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS, requestSignalWithTimeout } from './request-signal.js';
|
|
5
|
+
import { createToolNameDecoder, encodeToolName } from './tool-names.js';
|
|
2
6
|
const DEFAULT_BASE_URL = 'https://generativelanguage.googleapis.com/v1beta/models';
|
|
3
7
|
const STOP_REASON = {
|
|
4
8
|
STOP: 'end_turn',
|
|
@@ -26,20 +30,41 @@ function toGoogleContent(message) {
|
|
|
26
30
|
}
|
|
27
31
|
return {
|
|
28
32
|
role: 'user',
|
|
29
|
-
|
|
33
|
+
// Encoded like the declaration Gemini matched the call against —
|
|
34
|
+
// idempotent on a toolCallId that already is the wire name.
|
|
35
|
+
parts: [
|
|
36
|
+
{
|
|
37
|
+
functionResponse: {
|
|
38
|
+
name: encodeToolName(name),
|
|
39
|
+
response: { result: textOnlyContent(message.content) ?? '' },
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
],
|
|
30
43
|
};
|
|
31
44
|
}
|
|
32
45
|
const role = message.role === 'assistant' ? 'model' : 'user';
|
|
33
46
|
const parts = [];
|
|
34
|
-
if (message.content
|
|
47
|
+
if (typeof message.content === 'string') {
|
|
35
48
|
parts.push({ text: message.content });
|
|
49
|
+
}
|
|
50
|
+
else if (message.content !== undefined) {
|
|
51
|
+
for (const part of message.content) {
|
|
52
|
+
parts.push(part.type === 'text'
|
|
53
|
+
? { text: part.text }
|
|
54
|
+
: { inlineData: { mimeType: part.mediaType, data: part.data } });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
36
57
|
for (const call of message.toolCalls ?? []) {
|
|
37
|
-
parts.push({ functionCall: { name: call.name, args: call.input } });
|
|
58
|
+
parts.push({ functionCall: { name: encodeToolName(call.name), args: call.input } });
|
|
38
59
|
}
|
|
39
60
|
return { role, parts };
|
|
40
61
|
}
|
|
41
|
-
/**
|
|
42
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Pure — no network. `fallbackMaxTokens` is the client's own resolved
|
|
64
|
+
* `maxOutputTokens` (the admin's per-provider value, or the built-in floor)
|
|
65
|
+
* — applied only when `request.maxTokens` itself is absent.
|
|
66
|
+
*/
|
|
67
|
+
export function buildGoogleRequest(request, fallbackMaxTokens = FALLBACK_MAX_OUTPUT_TOKENS) {
|
|
43
68
|
return {
|
|
44
69
|
contents: request.messages.map(toGoogleContent),
|
|
45
70
|
...(request.system === undefined
|
|
@@ -51,7 +76,7 @@ export function buildGoogleRequest(request) {
|
|
|
51
76
|
tools: [
|
|
52
77
|
{
|
|
53
78
|
functionDeclarations: request.tools.map((tool) => ({
|
|
54
|
-
name: tool.name,
|
|
79
|
+
name: encodeToolName(tool.name),
|
|
55
80
|
description: tool.description,
|
|
56
81
|
parameters: tool.inputSchema,
|
|
57
82
|
})),
|
|
@@ -59,13 +84,13 @@ export function buildGoogleRequest(request) {
|
|
|
59
84
|
],
|
|
60
85
|
}),
|
|
61
86
|
generationConfig: {
|
|
62
|
-
maxOutputTokens: request.maxTokens,
|
|
87
|
+
maxOutputTokens: request.maxTokens ?? fallbackMaxTokens,
|
|
63
88
|
...(request.temperature === undefined ? {} : { temperature: request.temperature }),
|
|
64
89
|
},
|
|
65
90
|
};
|
|
66
91
|
}
|
|
67
92
|
/** Pure — no network. */
|
|
68
|
-
export function parseGoogleResponse(body) {
|
|
93
|
+
export function parseGoogleResponse(body, decodeToolName = (wire) => wire) {
|
|
69
94
|
const candidate = body.candidates[0];
|
|
70
95
|
if (candidate === undefined) {
|
|
71
96
|
throw new CogentaError({
|
|
@@ -84,7 +109,7 @@ export function parseGoogleResponse(body) {
|
|
|
84
109
|
// so the name is the closest stable handle the rest of the runtime has.
|
|
85
110
|
toolCalls.push({
|
|
86
111
|
id: part.functionCall.name,
|
|
87
|
-
name: part.functionCall.name,
|
|
112
|
+
name: decodeToolName(part.functionCall.name),
|
|
88
113
|
input: part.functionCall.args,
|
|
89
114
|
});
|
|
90
115
|
}
|
|
@@ -104,16 +129,33 @@ export function createGoogleClient(config) {
|
|
|
104
129
|
const doFetch = config.fetchImpl ?? fetch;
|
|
105
130
|
const base = config.baseUrl ?? DEFAULT_BASE_URL;
|
|
106
131
|
const url = `${base}/${config.model}:generateContent?key=${config.apiKey}`;
|
|
132
|
+
const maxOutputTokens = config.maxOutputTokens ?? FALLBACK_MAX_OUTPUT_TOKENS;
|
|
133
|
+
const requestTimeoutMs = config.requestTimeoutMs ?? DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS;
|
|
107
134
|
return {
|
|
108
135
|
name: 'google',
|
|
109
136
|
model: config.model,
|
|
137
|
+
supportsVision: true,
|
|
138
|
+
maxOutputTokens,
|
|
139
|
+
requestTimeoutMs,
|
|
140
|
+
...(config.maxCorrectionAttempts === undefined
|
|
141
|
+
? {}
|
|
142
|
+
: { maxCorrectionAttempts: config.maxCorrectionAttempts }),
|
|
110
143
|
async chat(request, options) {
|
|
144
|
+
const signal = requestSignalWithTimeout(options?.signal, requestTimeoutMs);
|
|
111
145
|
const response = await doFetch(url, {
|
|
112
146
|
method: 'POST',
|
|
113
147
|
headers: { 'content-type': 'application/json' },
|
|
114
|
-
body: JSON.stringify(buildGoogleRequest(request)),
|
|
115
|
-
|
|
148
|
+
body: JSON.stringify(buildGoogleRequest(request, maxOutputTokens)),
|
|
149
|
+
signal,
|
|
116
150
|
}).catch((cause) => {
|
|
151
|
+
if (signal.aborted && options?.signal?.aborted !== true) {
|
|
152
|
+
throw new CogentaError({
|
|
153
|
+
code: 'PROVIDER_REQUEST_FAILED',
|
|
154
|
+
message: 'Google did not answer in time.',
|
|
155
|
+
hint: 'The vendor may be slow or unreachable right now; retry, or check its status page.',
|
|
156
|
+
cause,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
117
159
|
throw new CogentaError({
|
|
118
160
|
code: 'PROVIDER_REQUEST_FAILED',
|
|
119
161
|
message: 'The request to Google could not be sent.',
|
|
@@ -137,7 +179,7 @@ export function createGoogleClient(config) {
|
|
|
137
179
|
});
|
|
138
180
|
}
|
|
139
181
|
const body = (await response.json());
|
|
140
|
-
return parseGoogleResponse(body);
|
|
182
|
+
return parseGoogleResponse(body, createToolNameDecoder(request));
|
|
141
183
|
},
|
|
142
184
|
};
|
|
143
185
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google.js","sourceRoot":"","sources":["../../src/providers/google.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"google.js","sourceRoot":"","sources":["../../src/providers/google.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,9 +7,18 @@ interface OpenAiToolCall {
|
|
|
7
7
|
readonly arguments: string;
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
|
+
type OpenAiContentPart = {
|
|
11
|
+
readonly type: 'text';
|
|
12
|
+
readonly text: string;
|
|
13
|
+
} | {
|
|
14
|
+
readonly type: 'image_url';
|
|
15
|
+
readonly image_url: {
|
|
16
|
+
readonly url: string;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
10
19
|
interface OpenAiMessage {
|
|
11
20
|
readonly role: 'system' | 'user' | 'assistant' | 'tool';
|
|
12
|
-
readonly content: string | null;
|
|
21
|
+
readonly content: string | readonly OpenAiContentPart[] | null;
|
|
13
22
|
readonly tool_calls?: readonly OpenAiToolCall[];
|
|
14
23
|
readonly tool_call_id?: string;
|
|
15
24
|
}
|
|
@@ -40,15 +49,34 @@ interface OpenAiResponseBody {
|
|
|
40
49
|
readonly completion_tokens: number;
|
|
41
50
|
};
|
|
42
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Pure — no network. `fallbackMaxTokens` is the client's own resolved
|
|
54
|
+
* `maxOutputTokens` (the admin's per-provider value, or the built-in floor)
|
|
55
|
+
* — applied only when `request.maxTokens` itself is absent.
|
|
56
|
+
*/
|
|
57
|
+
export declare function buildOpenAiRequest(request: ChatRequest, fallbackMaxTokens?: number): OpenAiRequestBody;
|
|
43
58
|
/** Pure — no network. */
|
|
44
|
-
export declare function
|
|
45
|
-
/** Pure — no network. */
|
|
46
|
-
export declare function parseOpenAiResponse(body: OpenAiResponseBody): ChatResponse;
|
|
59
|
+
export declare function parseOpenAiResponse(body: OpenAiResponseBody, decodeToolName?: (wire: string) => string): ChatResponse;
|
|
47
60
|
export interface OpenAiClientConfig {
|
|
48
61
|
readonly apiKey: string;
|
|
49
62
|
readonly model: string;
|
|
50
63
|
readonly baseUrl?: string;
|
|
51
64
|
readonly fetchImpl?: typeof fetch;
|
|
65
|
+
/**
|
|
66
|
+
* The provider id this client reports itself as — `client.name`, used by
|
|
67
|
+
* the privacy allowlist (`assertProviderAllowed`) and by anything logging
|
|
68
|
+
* or citing "which provider answered". Defaults to `'openai'`, but every
|
|
69
|
+
* `wireFormat: 'openai-compatible'` catalog entry (fiche 56: OpenRouter,
|
|
70
|
+
* DeepSeek, Qwen, GLM, or an operator's custom endpoint) passes its own
|
|
71
|
+
* catalog id here — without this, every one of them would misreport
|
|
72
|
+
* itself as literally `'openai'`, silently defeating a "no data leaves
|
|
73
|
+
* this machine" policy scoped to a different vendor.
|
|
74
|
+
*/
|
|
75
|
+
readonly name?: string;
|
|
76
|
+
/** See `ProviderClient.maxOutputTokens`/`requestTimeoutMs`/`maxCorrectionAttempts`. */
|
|
77
|
+
readonly maxOutputTokens?: number;
|
|
78
|
+
readonly requestTimeoutMs?: number;
|
|
79
|
+
readonly maxCorrectionAttempts?: number;
|
|
52
80
|
}
|
|
53
81
|
/** API key injected at the runtime boundary — never in a prompt or tool input (rule R7). */
|
|
54
82
|
export declare function createOpenAiClient(config: OpenAiClientConfig): ProviderClient;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"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"}
|
package/dist/providers/openai.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { CogentaError } from '@cogenta/core';
|
|
2
|
+
import { textOnlyContent } from './content-parts.js';
|
|
3
|
+
import { FALLBACK_MAX_OUTPUT_TOKENS } from './defaults.js';
|
|
4
|
+
import { DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS, requestSignalWithTimeout } from './request-signal.js';
|
|
5
|
+
import { createToolNameDecoder, encodeToolName } from './tool-names.js';
|
|
2
6
|
const DEFAULT_BASE_URL = 'https://api.openai.com/v1/chat/completions';
|
|
3
7
|
const STOP_REASON = {
|
|
4
8
|
stop: 'end_turn',
|
|
@@ -6,6 +10,25 @@ const STOP_REASON = {
|
|
|
6
10
|
length: 'max_tokens',
|
|
7
11
|
content_filter: 'stop_sequence',
|
|
8
12
|
};
|
|
13
|
+
/**
|
|
14
|
+
* A plain string is passed through unchanged (byte-for-byte identical wire
|
|
15
|
+
* shape to before this adapter supported images); an array of
|
|
16
|
+
* `ChatContentPart` becomes OpenAI's multimodal content-part array, with
|
|
17
|
+
* each image re-encoded as a `data:` URL — the only form the Chat
|
|
18
|
+
* Completions API accepts for an inline image.
|
|
19
|
+
*/
|
|
20
|
+
function toOpenAiContent(content) {
|
|
21
|
+
if (content === undefined)
|
|
22
|
+
return null;
|
|
23
|
+
if (typeof content === 'string')
|
|
24
|
+
return content;
|
|
25
|
+
return content.map((part) => part.type === 'text'
|
|
26
|
+
? { type: 'text', text: part.text }
|
|
27
|
+
: {
|
|
28
|
+
type: 'image_url',
|
|
29
|
+
image_url: { url: `data:${part.mediaType};base64,${part.data}` },
|
|
30
|
+
});
|
|
31
|
+
}
|
|
9
32
|
function toOpenAiMessage(message) {
|
|
10
33
|
if (message.role === 'tool') {
|
|
11
34
|
if (message.toolCallId === undefined) {
|
|
@@ -15,25 +38,33 @@ function toOpenAiMessage(message) {
|
|
|
15
38
|
hint: "Set toolCallId to the id the model's tool call carried.",
|
|
16
39
|
});
|
|
17
40
|
}
|
|
18
|
-
return {
|
|
41
|
+
return {
|
|
42
|
+
role: 'tool',
|
|
43
|
+
content: textOnlyContent(message.content) ?? '',
|
|
44
|
+
tool_call_id: message.toolCallId,
|
|
45
|
+
};
|
|
19
46
|
}
|
|
20
47
|
const toolCalls = message.toolCalls ?? [];
|
|
21
48
|
return {
|
|
22
49
|
role: message.role,
|
|
23
|
-
content: message.content
|
|
50
|
+
content: toOpenAiContent(message.content),
|
|
24
51
|
...(toolCalls.length === 0
|
|
25
52
|
? {}
|
|
26
53
|
: {
|
|
27
54
|
tool_calls: toolCalls.map((call) => ({
|
|
28
55
|
id: call.id,
|
|
29
56
|
type: 'function',
|
|
30
|
-
function: { name: call.name, arguments: JSON.stringify(call.input) },
|
|
57
|
+
function: { name: encodeToolName(call.name), arguments: JSON.stringify(call.input) },
|
|
31
58
|
})),
|
|
32
59
|
}),
|
|
33
60
|
};
|
|
34
61
|
}
|
|
35
|
-
/**
|
|
36
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Pure — no network. `fallbackMaxTokens` is the client's own resolved
|
|
64
|
+
* `maxOutputTokens` (the admin's per-provider value, or the built-in floor)
|
|
65
|
+
* — applied only when `request.maxTokens` itself is absent.
|
|
66
|
+
*/
|
|
67
|
+
export function buildOpenAiRequest(request, fallbackMaxTokens = FALLBACK_MAX_OUTPUT_TOKENS) {
|
|
37
68
|
const messages = [];
|
|
38
69
|
if (request.system !== undefined) {
|
|
39
70
|
messages.push({ role: 'system', content: request.system });
|
|
@@ -41,7 +72,7 @@ export function buildOpenAiRequest(request) {
|
|
|
41
72
|
messages.push(...request.messages.map(toOpenAiMessage));
|
|
42
73
|
return {
|
|
43
74
|
model: request.model,
|
|
44
|
-
max_tokens: request.maxTokens,
|
|
75
|
+
max_tokens: request.maxTokens ?? fallbackMaxTokens,
|
|
45
76
|
messages,
|
|
46
77
|
...(request.tools === undefined
|
|
47
78
|
? {}
|
|
@@ -49,7 +80,7 @@ export function buildOpenAiRequest(request) {
|
|
|
49
80
|
tools: request.tools.map((tool) => ({
|
|
50
81
|
type: 'function',
|
|
51
82
|
function: {
|
|
52
|
-
name: tool.name,
|
|
83
|
+
name: encodeToolName(tool.name),
|
|
53
84
|
description: tool.description,
|
|
54
85
|
parameters: tool.inputSchema,
|
|
55
86
|
},
|
|
@@ -59,18 +90,18 @@ export function buildOpenAiRequest(request) {
|
|
|
59
90
|
};
|
|
60
91
|
}
|
|
61
92
|
/** Pure — no network. */
|
|
62
|
-
export function parseOpenAiResponse(body) {
|
|
93
|
+
export function parseOpenAiResponse(body, decodeToolName = (wire) => wire) {
|
|
63
94
|
const choice = body.choices[0];
|
|
64
95
|
if (choice === undefined) {
|
|
65
96
|
throw new CogentaError({
|
|
66
97
|
code: 'PROVIDER_RESPONSE_INVALID',
|
|
67
|
-
message: 'OpenAI returned no choices.',
|
|
98
|
+
message: 'The OpenAI-compatible endpoint returned no choices.',
|
|
68
99
|
hint: 'Retry the request; this is not something the caller can fix by itself.',
|
|
69
100
|
});
|
|
70
101
|
}
|
|
71
102
|
const toolCalls = (choice.message.tool_calls ?? []).map((call) => ({
|
|
72
103
|
id: call.id,
|
|
73
|
-
name: call.function.name,
|
|
104
|
+
name: decodeToolName(call.function.name),
|
|
74
105
|
input: parseArguments(call.function.arguments),
|
|
75
106
|
}));
|
|
76
107
|
return {
|
|
@@ -90,53 +121,115 @@ function parseArguments(raw) {
|
|
|
90
121
|
catch (cause) {
|
|
91
122
|
throw new CogentaError({
|
|
92
123
|
code: 'PROVIDER_RESPONSE_INVALID',
|
|
93
|
-
message: "
|
|
124
|
+
message: "The endpoint's tool call arguments were not valid JSON.",
|
|
94
125
|
hint: 'This is a vendor-side malformed response; retry the request.',
|
|
95
126
|
cause,
|
|
96
127
|
});
|
|
97
128
|
}
|
|
98
129
|
}
|
|
130
|
+
const MAX_REASON_LENGTH = 300;
|
|
131
|
+
/**
|
|
132
|
+
* The human-readable part of an OpenAI-shaped error body
|
|
133
|
+
* (`{ error: { message } }`), or the first line of a non-JSON body, capped
|
|
134
|
+
* so a vendor's HTML error page never becomes the message. `undefined` when
|
|
135
|
+
* there is nothing legible to show.
|
|
136
|
+
*/
|
|
137
|
+
async function readErrorReason(response) {
|
|
138
|
+
const text = await response.text().catch(() => '');
|
|
139
|
+
if (text.trim() === '')
|
|
140
|
+
return undefined;
|
|
141
|
+
let reason = text;
|
|
142
|
+
try {
|
|
143
|
+
const parsed = JSON.parse(text);
|
|
144
|
+
if (typeof parsed === 'object' && parsed !== null && 'error' in parsed) {
|
|
145
|
+
const error = parsed.error;
|
|
146
|
+
if (typeof error === 'string')
|
|
147
|
+
reason = error;
|
|
148
|
+
else if (typeof error === 'object' && error !== null && 'message' in error) {
|
|
149
|
+
const message = error.message;
|
|
150
|
+
if (typeof message === 'string')
|
|
151
|
+
reason = message;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// Not JSON — keep the raw text.
|
|
157
|
+
}
|
|
158
|
+
const firstLine = reason.split('\n')[0]?.trim() ?? '';
|
|
159
|
+
if (firstLine === '')
|
|
160
|
+
return undefined;
|
|
161
|
+
return firstLine.length > MAX_REASON_LENGTH
|
|
162
|
+
? `${firstLine.slice(0, MAX_REASON_LENGTH)}…`
|
|
163
|
+
: firstLine;
|
|
164
|
+
}
|
|
99
165
|
/** API key injected at the runtime boundary — never in a prompt or tool input (rule R7). */
|
|
100
166
|
export function createOpenAiClient(config) {
|
|
101
167
|
const doFetch = config.fetchImpl ?? fetch;
|
|
102
168
|
const url = config.baseUrl ?? DEFAULT_BASE_URL;
|
|
169
|
+
const name = config.name ?? 'openai';
|
|
170
|
+
const maxOutputTokens = config.maxOutputTokens ?? FALLBACK_MAX_OUTPUT_TOKENS;
|
|
171
|
+
const requestTimeoutMs = config.requestTimeoutMs ?? DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS;
|
|
103
172
|
return {
|
|
104
|
-
name
|
|
173
|
+
name,
|
|
105
174
|
model: config.model,
|
|
175
|
+
supportsVision: true,
|
|
176
|
+
maxOutputTokens,
|
|
177
|
+
requestTimeoutMs,
|
|
178
|
+
...(config.maxCorrectionAttempts === undefined
|
|
179
|
+
? {}
|
|
180
|
+
: { maxCorrectionAttempts: config.maxCorrectionAttempts }),
|
|
106
181
|
async chat(request, options) {
|
|
182
|
+
const signal = requestSignalWithTimeout(options?.signal, requestTimeoutMs);
|
|
107
183
|
const response = await doFetch(url, {
|
|
108
184
|
method: 'POST',
|
|
109
185
|
headers: {
|
|
110
186
|
'content-type': 'application/json',
|
|
111
187
|
authorization: `Bearer ${config.apiKey}`,
|
|
112
188
|
},
|
|
113
|
-
body: JSON.stringify(buildOpenAiRequest(request)),
|
|
114
|
-
|
|
189
|
+
body: JSON.stringify(buildOpenAiRequest(request, maxOutputTokens)),
|
|
190
|
+
signal,
|
|
115
191
|
}).catch((cause) => {
|
|
192
|
+
if (signal.aborted && options?.signal?.aborted !== true) {
|
|
193
|
+
throw new CogentaError({
|
|
194
|
+
code: 'PROVIDER_REQUEST_FAILED',
|
|
195
|
+
message: `"${name}" did not answer in time.`,
|
|
196
|
+
hint: 'The vendor may be slow or unreachable right now; retry, or check its status page.',
|
|
197
|
+
cause,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
116
200
|
throw new CogentaError({
|
|
117
201
|
code: 'PROVIDER_REQUEST_FAILED',
|
|
118
|
-
message:
|
|
119
|
-
hint:
|
|
202
|
+
message: `The request to "${name}" could not be sent.`,
|
|
203
|
+
hint: "Check network connectivity and this provider's saved API key.",
|
|
120
204
|
cause,
|
|
121
205
|
});
|
|
122
206
|
});
|
|
123
207
|
if (response.status === 429) {
|
|
124
208
|
throw new CogentaError({
|
|
125
209
|
code: 'PROVIDER_RATE_LIMITED',
|
|
126
|
-
message:
|
|
210
|
+
message: `"${name}" rate-limited this request.`,
|
|
127
211
|
hint: 'Retry with backoff, or lower callsPerHour for this agent.',
|
|
128
212
|
});
|
|
129
213
|
}
|
|
130
214
|
if (!response.ok) {
|
|
215
|
+
// The vendor's own error text is the only thing that tells a 400
|
|
216
|
+
// ("model does not exist", "unsupported parameter") from a 401 —
|
|
217
|
+
// dropping it left an operator staring at a bare status code with
|
|
218
|
+
// nothing to act on. It never carries the key; it is safe to quote.
|
|
219
|
+
const reason = await readErrorReason(response);
|
|
131
220
|
throw new CogentaError({
|
|
132
221
|
code: 'PROVIDER_REQUEST_FAILED',
|
|
133
|
-
message:
|
|
134
|
-
|
|
135
|
-
|
|
222
|
+
message: reason === undefined
|
|
223
|
+
? `"${name}" returned status ${response.status}.`
|
|
224
|
+
: `"${name}" returned status ${response.status}: ${reason}`,
|
|
225
|
+
hint: response.status === 400
|
|
226
|
+
? "Check the model name saved for this provider — it must be one this endpoint actually serves — then the request. The provider's own message above usually names the field."
|
|
227
|
+
: "Check the request and this provider's saved API key.",
|
|
228
|
+
details: { status: response.status, ...(reason === undefined ? {} : { reason }) },
|
|
136
229
|
});
|
|
137
230
|
}
|
|
138
231
|
const body = (await response.json());
|
|
139
|
-
return parseOpenAiResponse(body);
|
|
232
|
+
return parseOpenAiResponse(body, createToolNameDecoder(request));
|
|
140
233
|
},
|
|
141
234
|
};
|
|
142
235
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,23 +1,34 @@
|
|
|
1
1
|
import type { ProviderClient } from './types.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
readonly
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Fiche 56: `provider` used to be a closed 3-literal union
|
|
4
|
+
* (`'anthropic' | 'openai' | 'google'`) — every fourth vendor (OpenRouter,
|
|
5
|
+
* DeepSeek, Qwen, GLM, a self-hosted OpenAI-compatible endpoint) needed a
|
|
6
|
+
* code change to even be expressible. It is now a plain string, validated at
|
|
7
|
+
* the write boundary (`store.ts`'s `upsert` and the `/api/providers` router),
|
|
8
|
+
* not by a type. `@cogenta/core`'s own `llmSchema.provider` was already a
|
|
9
|
+
* free string before this fiche — this only catches the registry up to a
|
|
10
|
+
* looseness the config schema already had.
|
|
11
|
+
*/
|
|
12
|
+
export type ProviderName = string;
|
|
13
|
+
export interface ProviderEntryConfig {
|
|
14
|
+
readonly apiKey: string;
|
|
15
|
+
readonly model: string;
|
|
16
|
+
/**
|
|
17
|
+
* Overrides `catalog.ts`'s `defaultBaseUrl` for a known provider (e.g. a
|
|
18
|
+
* self-hosted proxy in front of OpenAI), or — for a provider id absent
|
|
19
|
+
* from the catalog entirely — is what makes it resolvable at all: an
|
|
20
|
+
* unknown id with no `baseUrl` cannot be turned into a client (see
|
|
21
|
+
* `buildClient` below).
|
|
22
|
+
*/
|
|
23
|
+
readonly baseUrl?: string;
|
|
24
|
+
/** See `ProviderClient.maxOutputTokens` — the admin's value for this provider, or absent for the built-in fallback. */
|
|
25
|
+
readonly maxOutputTokens?: number;
|
|
26
|
+
/** See `ProviderClient.requestTimeoutMs`. */
|
|
27
|
+
readonly requestTimeoutMs?: number;
|
|
28
|
+
/** See `ProviderClient.maxCorrectionAttempts`. */
|
|
29
|
+
readonly maxCorrectionAttempts?: number;
|
|
20
30
|
}
|
|
31
|
+
export type ProviderRegistryConfig = Readonly<Record<string, ProviderEntryConfig>>;
|
|
21
32
|
/**
|
|
22
33
|
* One client per configured vendor — a site with no LLM provider configured
|
|
23
34
|
* simply has an empty registry, which is exactly what rule R2 requires ("le
|
|
@@ -25,7 +36,7 @@ export interface ProviderRegistryConfig {
|
|
|
25
36
|
* refuses, and only once an agent actually tries to run.
|
|
26
37
|
*/
|
|
27
38
|
export declare function createProviderRegistry(config: ProviderRegistryConfig): {
|
|
28
|
-
readonly get: (name:
|
|
29
|
-
readonly has: (name:
|
|
39
|
+
readonly get: (name: string) => ProviderClient;
|
|
40
|
+
readonly has: (name: string) => boolean;
|
|
30
41
|
};
|
|
31
42
|
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD;;;;;;;;;GASG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAA;AAEjC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,uHAAuH;IACvH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,6CAA6C;IAC7C,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAClC,kDAAkD;IAClD,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAA;CACxC;AAED,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAAA;AAkDlF;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,sBAAsB,GAAG;IACtE,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,cAAc,CAAA;IAC9C,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAA;CACxC,CAoBA"}
|
|
@@ -1,8 +1,53 @@
|
|
|
1
1
|
import { CogentaError } from '@cogenta/core';
|
|
2
2
|
import { createAnthropicClient } from './anthropic.js';
|
|
3
|
+
import { findProviderCatalogEntry } from './catalog.js';
|
|
3
4
|
import { createGoogleClient } from './google.js';
|
|
4
5
|
import { createOpenAiClient } from './openai.js';
|
|
5
|
-
|
|
6
|
+
/**
|
|
7
|
+
* One provider entry → one client. A catalog id picks the adapter
|
|
8
|
+
* (`wireFormat`); a name the catalog does not know is only usable if the
|
|
9
|
+
* entry carries its own `baseUrl` — that is what "custom OpenAI-compatible
|
|
10
|
+
* endpoint" means structurally, not a separate `custom: true` flag to keep
|
|
11
|
+
* in sync with this lookup.
|
|
12
|
+
*/
|
|
13
|
+
function buildClient(name, entry) {
|
|
14
|
+
const catalogEntry = findProviderCatalogEntry(name);
|
|
15
|
+
const tuning = {
|
|
16
|
+
...(entry.maxOutputTokens === undefined ? {} : { maxOutputTokens: entry.maxOutputTokens }),
|
|
17
|
+
...(entry.requestTimeoutMs === undefined ? {} : { requestTimeoutMs: entry.requestTimeoutMs }),
|
|
18
|
+
...(entry.maxCorrectionAttempts === undefined
|
|
19
|
+
? {}
|
|
20
|
+
: { maxCorrectionAttempts: entry.maxCorrectionAttempts }),
|
|
21
|
+
};
|
|
22
|
+
if (catalogEntry?.wireFormat === 'anthropic') {
|
|
23
|
+
return createAnthropicClient({
|
|
24
|
+
apiKey: entry.apiKey,
|
|
25
|
+
model: entry.model,
|
|
26
|
+
...(entry.baseUrl === undefined ? {} : { baseUrl: entry.baseUrl }),
|
|
27
|
+
...tuning,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
if (catalogEntry?.wireFormat === 'google') {
|
|
31
|
+
return createGoogleClient({
|
|
32
|
+
apiKey: entry.apiKey,
|
|
33
|
+
model: entry.model,
|
|
34
|
+
...(entry.baseUrl === undefined ? {} : { baseUrl: entry.baseUrl }),
|
|
35
|
+
...tuning,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
// `wireFormat: 'openai-compatible'` (OpenAI itself, OpenRouter, DeepSeek,
|
|
39
|
+
// Qwen, GLM) and any id absent from the catalog share this one branch —
|
|
40
|
+
// exactly the "zero new network code" the fiche asks for.
|
|
41
|
+
const baseUrl = entry.baseUrl ?? catalogEntry?.defaultBaseUrl;
|
|
42
|
+
if (baseUrl === undefined) {
|
|
43
|
+
throw new CogentaError({
|
|
44
|
+
code: 'PROVIDER_CUSTOM_BASE_URL_REQUIRED',
|
|
45
|
+
message: `"${name}" is not a built-in provider and has no "baseUrl" configured.`,
|
|
46
|
+
hint: 'Set a baseUrl for a custom OpenAI-compatible endpoint, or use a catalog provider id.',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return createOpenAiClient({ apiKey: entry.apiKey, model: entry.model, baseUrl, name, ...tuning });
|
|
50
|
+
}
|
|
6
51
|
/**
|
|
7
52
|
* One client per configured vendor — a site with no LLM provider configured
|
|
8
53
|
* simply has an empty registry, which is exactly what rule R2 requires ("le
|
|
@@ -11,12 +56,9 @@ export const PROVIDER_NAMES = ['anthropic', 'openai', 'google'];
|
|
|
11
56
|
*/
|
|
12
57
|
export function createProviderRegistry(config) {
|
|
13
58
|
const clients = new Map();
|
|
14
|
-
|
|
15
|
-
clients.set(
|
|
16
|
-
|
|
17
|
-
clients.set('openai', createOpenAiClient(config.openai));
|
|
18
|
-
if (config.google !== undefined)
|
|
19
|
-
clients.set('google', createGoogleClient(config.google));
|
|
59
|
+
for (const [name, entry] of Object.entries(config)) {
|
|
60
|
+
clients.set(name, buildClient(name, entry));
|
|
61
|
+
}
|
|
20
62
|
return {
|
|
21
63
|
has: (name) => clients.has(name),
|
|
22
64
|
get(name) {
|