@aituber-onair/chat 0.56.0 → 0.58.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/README.ja.md +27 -2
- package/README.md +31 -2
- package/dist/cjs/constants/claude.d.ts +1 -0
- package/dist/cjs/constants/claude.d.ts.map +1 -1
- package/dist/cjs/constants/claude.js +4 -1
- package/dist/cjs/constants/claude.js.map +1 -1
- package/dist/cjs/services/providers/claude/ClaudeChatServiceProvider.d.ts.map +1 -1
- package/dist/cjs/services/providers/claude/ClaudeChatServiceProvider.js +1 -0
- package/dist/cjs/services/providers/claude/ClaudeChatServiceProvider.js.map +1 -1
- package/dist/cjs/utils/index.d.ts +1 -0
- package/dist/cjs/utils/index.d.ts.map +1 -1
- package/dist/cjs/utils/index.js +1 -0
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/cjs/utils/openaiCompatibleEndpoint.d.ts +57 -0
- package/dist/cjs/utils/openaiCompatibleEndpoint.d.ts.map +1 -0
- package/dist/cjs/utils/openaiCompatibleEndpoint.js +193 -0
- package/dist/cjs/utils/openaiCompatibleEndpoint.js.map +1 -0
- package/dist/esm/constants/claude.d.ts +1 -0
- package/dist/esm/constants/claude.d.ts.map +1 -1
- package/dist/esm/constants/claude.js +3 -0
- package/dist/esm/constants/claude.js.map +1 -1
- package/dist/esm/services/providers/claude/ClaudeChatServiceProvider.d.ts.map +1 -1
- package/dist/esm/services/providers/claude/ClaudeChatServiceProvider.js +2 -1
- package/dist/esm/services/providers/claude/ClaudeChatServiceProvider.js.map +1 -1
- package/dist/esm/utils/index.d.ts +1 -0
- package/dist/esm/utils/index.d.ts.map +1 -1
- package/dist/esm/utils/index.js +1 -0
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/esm/utils/openaiCompatibleEndpoint.d.ts +57 -0
- package/dist/esm/utils/openaiCompatibleEndpoint.d.ts.map +1 -0
- package/dist/esm/utils/openaiCompatibleEndpoint.js +186 -0
- package/dist/esm/utils/openaiCompatibleEndpoint.js.map +1 -0
- package/dist/umd/aituber-onair-chat.js +199 -3
- package/dist/umd/aituber-onair-chat.min.js +8 -8
- package/package.json +1 -1
package/dist/esm/utils/index.js
CHANGED
|
@@ -7,6 +7,7 @@ export * from './screenplay';
|
|
|
7
7
|
export * from './emotionParser';
|
|
8
8
|
export * from './runOnce';
|
|
9
9
|
export * from './openaiCompatibleSse';
|
|
10
|
+
export * from './openaiCompatibleEndpoint';
|
|
10
11
|
export * from './openaiCompatibleTools';
|
|
11
12
|
export * from './processChatFlow';
|
|
12
13
|
export * from './visionModelResolver';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** A local server with an OpenAI-compatible Chat Completions endpoint. */
|
|
2
|
+
export type OpenAICompatibleLocalPresetId = 'ollama' | 'lmStudio' | 'llamaCpp' | 'vllm';
|
|
3
|
+
export interface OpenAICompatibleLocalPreset {
|
|
4
|
+
id: OpenAICompatibleLocalPresetId;
|
|
5
|
+
label: string;
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
docsUrl: string;
|
|
8
|
+
corsHint?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Default local URLs. Change the port when your server uses a custom one. */
|
|
11
|
+
export declare const OPENAI_COMPATIBLE_LOCAL_PRESETS: readonly OpenAICompatibleLocalPreset[];
|
|
12
|
+
export type OpenAICompatibleEndpointErrorCode = 'invalid-url' | 'network' | 'aborted' | 'timeout' | 'http' | 'invalid-response';
|
|
13
|
+
/** Error returned by endpoint resolution and model discovery. */
|
|
14
|
+
export declare class OpenAICompatibleEndpointError extends Error {
|
|
15
|
+
readonly code: OpenAICompatibleEndpointErrorCode;
|
|
16
|
+
readonly status?: number;
|
|
17
|
+
constructor(code: OpenAICompatibleEndpointErrorCode, message: string, status?: number);
|
|
18
|
+
}
|
|
19
|
+
export interface ResolvedOpenAICompatibleEndpoint {
|
|
20
|
+
baseUrl: string;
|
|
21
|
+
chatCompletionsUrl: string;
|
|
22
|
+
modelsUrl: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Accepts an origin, API base URL, or full Chat Completions URL.
|
|
26
|
+
* Query strings and fragments are rejected rather than discarded.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveOpenAICompatibleEndpoint(input: string): ResolvedOpenAICompatibleEndpoint;
|
|
29
|
+
export interface ListOpenAICompatibleModelsOptions {
|
|
30
|
+
endpoint: string;
|
|
31
|
+
apiKey?: string;
|
|
32
|
+
timeoutMs?: number;
|
|
33
|
+
fetch?: typeof fetch;
|
|
34
|
+
signal?: AbortSignal;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Lists model IDs from GET /models, preserving server order.
|
|
38
|
+
* @throws {RangeError} If timeoutMs is not a positive finite number.
|
|
39
|
+
*/
|
|
40
|
+
export declare function listOpenAICompatibleModels(options: ListOpenAICompatibleModelsOptions): Promise<string[]>;
|
|
41
|
+
export type OpenAICompatibleConnectionResult = {
|
|
42
|
+
ok: true;
|
|
43
|
+
latencyMs: number;
|
|
44
|
+
models: string[];
|
|
45
|
+
modelFound?: boolean;
|
|
46
|
+
} | {
|
|
47
|
+
ok: false;
|
|
48
|
+
error: OpenAICompatibleEndpointError;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Tests GET /models without generating tokens.
|
|
52
|
+
* @throws {RangeError} If timeoutMs is not a positive finite number.
|
|
53
|
+
*/
|
|
54
|
+
export declare function testOpenAICompatibleConnection(options: ListOpenAICompatibleModelsOptions & {
|
|
55
|
+
model?: string;
|
|
56
|
+
}): Promise<OpenAICompatibleConnectionResult>;
|
|
57
|
+
//# sourceMappingURL=openaiCompatibleEndpoint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openaiCompatibleEndpoint.d.ts","sourceRoot":"","sources":["../../../src/utils/openaiCompatibleEndpoint.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,MAAM,MAAM,6BAA6B,GACrC,QAAQ,GACR,UAAU,GACV,UAAU,GACV,MAAM,CAAC;AAEX,MAAM,WAAW,2BAA2B;IAC1C,EAAE,EAAE,6BAA6B,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,8EAA8E;AAC9E,eAAO,MAAM,+BAA+B,EAAE,SAAS,2BAA2B,EAmC/E,CAAC;AAEJ,MAAM,MAAM,iCAAiC,GACzC,aAAa,GACb,SAAS,GACT,SAAS,GACT,SAAS,GACT,MAAM,GACN,kBAAkB,CAAC;AAEvB,iEAAiE;AACjE,qBAAa,6BAA8B,SAAQ,KAAK;IACtD,QAAQ,CAAC,IAAI,EAAE,iCAAiC,CAAC;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;gBAGvB,IAAI,EAAE,iCAAiC,EACvC,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM;CAOlB;AAED,MAAM,WAAW,gCAAgC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,MAAM,GACZ,gCAAgC,CA4ClC;AAED,MAAM,WAAW,iCAAiC;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,iCAAiC,GACzC,OAAO,CAAC,MAAM,EAAE,CAAC,CA2GnB;AAED,MAAM,MAAM,gCAAgC,GACxC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GACvE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,6BAA6B,CAAA;CAAE,CAAC;AAExD;;;GAGG;AACH,wBAAsB,8BAA8B,CAClD,OAAO,EAAE,iCAAiC,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9D,OAAO,CAAC,gCAAgC,CAAC,CAyB3C"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/** Default local URLs. Change the port when your server uses a custom one. */
|
|
2
|
+
export const OPENAI_COMPATIBLE_LOCAL_PRESETS = [
|
|
3
|
+
{
|
|
4
|
+
id: 'ollama',
|
|
5
|
+
label: 'Ollama',
|
|
6
|
+
baseUrl: 'http://localhost:11434/v1',
|
|
7
|
+
docsUrl: 'https://docs.ollama.com/api/openai-compatibility',
|
|
8
|
+
corsHint: 'Set OLLAMA_ORIGINS to allow additional browser origins.',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: 'lmStudio',
|
|
12
|
+
label: 'LM Studio',
|
|
13
|
+
baseUrl: 'http://localhost:1234/v1',
|
|
14
|
+
docsUrl: 'https://lmstudio.ai/docs/developer/openai-compat',
|
|
15
|
+
corsHint: 'Start the server with lms server start --cors for browser access.',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: 'llamaCpp',
|
|
19
|
+
label: 'llama.cpp',
|
|
20
|
+
baseUrl: 'http://127.0.0.1:8080/v1',
|
|
21
|
+
docsUrl: 'https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md',
|
|
22
|
+
corsHint: 'All origins are allowed by default; use --cors-origins to restrict them.',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: 'vllm',
|
|
26
|
+
label: 'vLLM',
|
|
27
|
+
baseUrl: 'http://localhost:8000/v1',
|
|
28
|
+
docsUrl: 'https://docs.vllm.ai/en/latest/serving/online_serving/openai_compatible_server/',
|
|
29
|
+
corsHint: 'All origins are allowed by default; use --allowed-origins to restrict them.',
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
/** Error returned by endpoint resolution and model discovery. */
|
|
33
|
+
export class OpenAICompatibleEndpointError extends Error {
|
|
34
|
+
constructor(code, message, status) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.name = 'OpenAICompatibleEndpointError';
|
|
37
|
+
this.code = code;
|
|
38
|
+
this.status = status;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Accepts an origin, API base URL, or full Chat Completions URL.
|
|
43
|
+
* Query strings and fragments are rejected rather than discarded.
|
|
44
|
+
*/
|
|
45
|
+
export function resolveOpenAICompatibleEndpoint(input) {
|
|
46
|
+
let url;
|
|
47
|
+
try {
|
|
48
|
+
url = new URL(input.trim());
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
throw new OpenAICompatibleEndpointError('invalid-url', 'Enter a valid HTTP or HTTPS endpoint URL.');
|
|
52
|
+
}
|
|
53
|
+
if ((url.protocol !== 'http:' && url.protocol !== 'https:') ||
|
|
54
|
+
url.search ||
|
|
55
|
+
url.hash ||
|
|
56
|
+
url.username ||
|
|
57
|
+
url.password) {
|
|
58
|
+
throw new OpenAICompatibleEndpointError('invalid-url', 'Use an HTTP or HTTPS endpoint URL without credentials, a query, or a fragment.');
|
|
59
|
+
}
|
|
60
|
+
const path = url.pathname.replace(/\/+$/, '');
|
|
61
|
+
if (path.endsWith('/api/chat') || path.endsWith('/api/generate')) {
|
|
62
|
+
throw new OpenAICompatibleEndpointError('invalid-url', "This looks like Ollama's native API URL. Use the OpenAI-compatible base URL instead, e.g. http://localhost:11434/v1.");
|
|
63
|
+
}
|
|
64
|
+
const basePath = !path || path === '/'
|
|
65
|
+
? '/v1'
|
|
66
|
+
: path.endsWith('/chat/completions')
|
|
67
|
+
? path.slice(0, -'/chat/completions'.length)
|
|
68
|
+
: path;
|
|
69
|
+
const baseUrl = `${url.origin}${basePath}`;
|
|
70
|
+
return {
|
|
71
|
+
baseUrl,
|
|
72
|
+
chatCompletionsUrl: `${baseUrl}/chat/completions`,
|
|
73
|
+
modelsUrl: `${baseUrl}/models`,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Lists model IDs from GET /models, preserving server order.
|
|
78
|
+
* @throws {RangeError} If timeoutMs is not a positive finite number.
|
|
79
|
+
*/
|
|
80
|
+
export async function listOpenAICompatibleModels(options) {
|
|
81
|
+
const { modelsUrl } = resolveOpenAICompatibleEndpoint(options.endpoint);
|
|
82
|
+
const timeoutMs = options.timeoutMs ?? 8000;
|
|
83
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
84
|
+
throw new RangeError('timeoutMs must be a positive finite number.');
|
|
85
|
+
}
|
|
86
|
+
if (options.signal?.aborted) {
|
|
87
|
+
throw new OpenAICompatibleEndpointError('aborted', 'The models request was aborted by the caller.');
|
|
88
|
+
}
|
|
89
|
+
const controller = new AbortController();
|
|
90
|
+
let abortCause;
|
|
91
|
+
const onAbort = () => {
|
|
92
|
+
if (!abortCause)
|
|
93
|
+
abortCause = 'caller';
|
|
94
|
+
controller.abort();
|
|
95
|
+
};
|
|
96
|
+
options.signal?.addEventListener('abort', onAbort, { once: true });
|
|
97
|
+
if (options.signal?.aborted)
|
|
98
|
+
onAbort();
|
|
99
|
+
const timeout = setTimeout(() => {
|
|
100
|
+
if (!abortCause)
|
|
101
|
+
abortCause = 'timeout';
|
|
102
|
+
controller.abort();
|
|
103
|
+
}, timeoutMs);
|
|
104
|
+
try {
|
|
105
|
+
const headers = {};
|
|
106
|
+
if (options.apiKey?.trim()) {
|
|
107
|
+
headers.Authorization = `Bearer ${options.apiKey.trim()}`;
|
|
108
|
+
}
|
|
109
|
+
const response = await (options.fetch ?? fetch)(modelsUrl, {
|
|
110
|
+
method: 'GET',
|
|
111
|
+
headers,
|
|
112
|
+
signal: controller.signal,
|
|
113
|
+
});
|
|
114
|
+
if (abortCause) {
|
|
115
|
+
throw new OpenAICompatibleEndpointError('aborted', 'The models request was aborted by the caller.');
|
|
116
|
+
}
|
|
117
|
+
if (!response.ok) {
|
|
118
|
+
throw new OpenAICompatibleEndpointError('http', `Model listing failed with HTTP ${response.status}.`, response.status);
|
|
119
|
+
}
|
|
120
|
+
let body;
|
|
121
|
+
try {
|
|
122
|
+
body = await response.json();
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
throw new OpenAICompatibleEndpointError('invalid-response', 'The models endpoint did not return valid JSON.');
|
|
126
|
+
}
|
|
127
|
+
if (!body ||
|
|
128
|
+
typeof body !== 'object' ||
|
|
129
|
+
!('data' in body) ||
|
|
130
|
+
!Array.isArray(body.data) ||
|
|
131
|
+
!body.data.every((model) => model &&
|
|
132
|
+
typeof model === 'object' &&
|
|
133
|
+
'id' in model &&
|
|
134
|
+
typeof model.id === 'string')) {
|
|
135
|
+
throw new OpenAICompatibleEndpointError('invalid-response', 'The models response must contain data with model IDs.');
|
|
136
|
+
}
|
|
137
|
+
if (abortCause) {
|
|
138
|
+
throw new OpenAICompatibleEndpointError('aborted', 'The models request was aborted by the caller.');
|
|
139
|
+
}
|
|
140
|
+
return [...new Set(body.data.map((model) => model.id))];
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
if (abortCause === 'caller') {
|
|
144
|
+
throw new OpenAICompatibleEndpointError('aborted', 'The models request was aborted by the caller.');
|
|
145
|
+
}
|
|
146
|
+
if (abortCause === 'timeout') {
|
|
147
|
+
throw new OpenAICompatibleEndpointError('timeout', `The models request timed out after ${timeoutMs} ms.`);
|
|
148
|
+
}
|
|
149
|
+
if (error instanceof OpenAICompatibleEndpointError)
|
|
150
|
+
throw error;
|
|
151
|
+
throw new OpenAICompatibleEndpointError('network', 'Could not reach the models endpoint. In a browser, this is usually a CORS restriction or the server is not running.');
|
|
152
|
+
}
|
|
153
|
+
finally {
|
|
154
|
+
clearTimeout(timeout);
|
|
155
|
+
options.signal?.removeEventListener('abort', onAbort);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Tests GET /models without generating tokens.
|
|
160
|
+
* @throws {RangeError} If timeoutMs is not a positive finite number.
|
|
161
|
+
*/
|
|
162
|
+
export async function testOpenAICompatibleConnection(options) {
|
|
163
|
+
const startedAt = Date.now();
|
|
164
|
+
try {
|
|
165
|
+
const models = await listOpenAICompatibleModels(options);
|
|
166
|
+
return {
|
|
167
|
+
ok: true,
|
|
168
|
+
latencyMs: Date.now() - startedAt,
|
|
169
|
+
models,
|
|
170
|
+
...(options.model !== undefined
|
|
171
|
+
? { modelFound: models.includes(options.model) }
|
|
172
|
+
: {}),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
if (error instanceof RangeError)
|
|
177
|
+
throw error;
|
|
178
|
+
return {
|
|
179
|
+
ok: false,
|
|
180
|
+
error: error instanceof OpenAICompatibleEndpointError
|
|
181
|
+
? error
|
|
182
|
+
: new OpenAICompatibleEndpointError('network', 'Could not reach the models endpoint. In a browser, this is usually a CORS restriction or the server is not running.'),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=openaiCompatibleEndpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openaiCompatibleEndpoint.js","sourceRoot":"","sources":["../../../src/utils/openaiCompatibleEndpoint.ts"],"names":[],"mappings":"AAeA,8EAA8E;AAC9E,MAAM,CAAC,MAAM,+BAA+B,GAC1C;IACE;QACE,EAAE,EAAE,QAAQ;QACZ,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,2BAA2B;QACpC,OAAO,EAAE,kDAAkD;QAC3D,QAAQ,EAAE,yDAAyD;KACpE;IACD;QACE,EAAE,EAAE,UAAU;QACd,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,0BAA0B;QACnC,OAAO,EAAE,kDAAkD;QAC3D,QAAQ,EACN,mEAAmE;KACtE;IACD;QACE,EAAE,EAAE,UAAU;QACd,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,0BAA0B;QACnC,OAAO,EACL,0EAA0E;QAC5E,QAAQ,EACN,0EAA0E;KAC7E;IACD;QACE,EAAE,EAAE,MAAM;QACV,KAAK,EAAE,MAAM;QACb,OAAO,EAAE,0BAA0B;QACnC,OAAO,EACL,iFAAiF;QACnF,QAAQ,EACN,6EAA6E;KAChF;CACF,CAAC;AAUJ,iEAAiE;AACjE,MAAM,OAAO,6BAA8B,SAAQ,KAAK;IAItD,YACE,IAAuC,EACvC,OAAe,EACf,MAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,+BAA+B,CAAC;QAC5C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAQD;;;GAGG;AACH,MAAM,UAAU,+BAA+B,CAC7C,KAAa;IAEb,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,6BAA6B,CACrC,aAAa,EACb,2CAA2C,CAC5C,CAAC;IACJ,CAAC;IAED,IACE,CAAC,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;QACvD,GAAG,CAAC,MAAM;QACV,GAAG,CAAC,IAAI;QACR,GAAG,CAAC,QAAQ;QACZ,GAAG,CAAC,QAAQ,EACZ,CAAC;QACD,MAAM,IAAI,6BAA6B,CACrC,aAAa,EACb,gFAAgF,CACjF,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9C,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;QACjE,MAAM,IAAI,6BAA6B,CACrC,aAAa,EACb,sHAAsH,CACvH,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GACZ,CAAC,IAAI,IAAI,IAAI,KAAK,GAAG;QACnB,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC;YAClC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,mBAAmB,CAAC,MAAM,CAAC;YAC5C,CAAC,CAAC,IAAI,CAAC;IAEb,MAAM,OAAO,GAAG,GAAG,GAAG,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;IAC3C,OAAO;QACL,OAAO;QACP,kBAAkB,EAAE,GAAG,OAAO,mBAAmB;QACjD,SAAS,EAAE,GAAG,OAAO,SAAS;KAC/B,CAAC;AACJ,CAAC;AAUD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,OAA0C;IAE1C,MAAM,EAAE,SAAS,EAAE,GAAG,+BAA+B,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC;IAC5C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,UAAU,CAAC,6CAA6C,CAAC,CAAC;IACtE,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;QAC5B,MAAM,IAAI,6BAA6B,CACrC,SAAS,EACT,+CAA+C,CAChD,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,IAAI,UAA4C,CAAC;IACjD,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,IAAI,CAAC,UAAU;YAAE,UAAU,GAAG,QAAQ,CAAC;QACvC,UAAU,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC,CAAC;IACF,OAAO,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACnE,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO;QAAE,OAAO,EAAE,CAAC;IACvC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;QAC9B,IAAI,CAAC,UAAU;YAAE,UAAU,GAAG,SAAS,CAAC;QACxC,UAAU,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC,EAAE,SAAS,CAAC,CAAC;IAEd,IAAI,CAAC;QACH,MAAM,OAAO,GAA2B,EAAE,CAAC;QAC3C,IAAI,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC;YAC3B,OAAO,CAAC,aAAa,GAAG,UAAU,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QAC5D,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC,SAAS,EAAE;YACzD,MAAM,EAAE,KAAK;YACb,OAAO;YACP,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QACH,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,IAAI,6BAA6B,CACrC,SAAS,EACT,+CAA+C,CAChD,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,6BAA6B,CACrC,MAAM,EACN,kCAAkC,QAAQ,CAAC,MAAM,GAAG,EACpD,QAAQ,CAAC,MAAM,CAChB,CAAC;QACJ,CAAC;QAED,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,6BAA6B,CACrC,kBAAkB,EAClB,gDAAgD,CACjD,CAAC;QACJ,CAAC;QACD,IACE,CAAC,IAAI;YACL,OAAO,IAAI,KAAK,QAAQ;YACxB,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC;YACjB,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;YACzB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CACd,CAAC,KAAc,EAAE,EAAE,CACjB,KAAK;gBACL,OAAO,KAAK,KAAK,QAAQ;gBACzB,IAAI,IAAI,KAAK;gBACb,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,CAC/B,EACD,CAAC;YACD,MAAM,IAAI,6BAA6B,CACrC,kBAAkB,EAClB,uDAAuD,CACxD,CAAC;QACJ,CAAC;QACD,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,IAAI,6BAA6B,CACrC,SAAS,EACT,+CAA+C,CAChD,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAqB,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,UAAU,KAAK,QAAQ,EAAE,CAAC;YAC5B,MAAM,IAAI,6BAA6B,CACrC,SAAS,EACT,+CAA+C,CAChD,CAAC;QACJ,CAAC;QACD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,IAAI,6BAA6B,CACrC,SAAS,EACT,sCAAsC,SAAS,MAAM,CACtD,CAAC;QACJ,CAAC;QACD,IAAI,KAAK,YAAY,6BAA6B;YAAE,MAAM,KAAK,CAAC;QAChE,MAAM,IAAI,6BAA6B,CACrC,SAAS,EACT,qHAAqH,CACtH,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,OAAO,CAAC,CAAC;QACtB,OAAO,CAAC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACxD,CAAC;AACH,CAAC;AAMD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAClD,OAA+D;IAE/D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,0BAA0B,CAAC,OAAO,CAAC,CAAC;QACzD,OAAO;YACL,EAAE,EAAE,IAAI;YACR,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;YACjC,MAAM;YACN,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS;gBAC7B,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;gBAChD,CAAC,CAAC,EAAE,CAAC;SACR,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,UAAU;YAAE,MAAM,KAAK,CAAC;QAC7C,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EACH,KAAK,YAAY,6BAA6B;gBAC5C,CAAC,CAAC,KAAK;gBACP,CAAC,CAAC,IAAI,6BAA6B,CAC/B,SAAS,EACT,qHAAqH,CACtH;SACR,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -100,6 +100,7 @@ var AITuberOnAirChat = (() => {
|
|
|
100
100
|
MODEL_CLAUDE_4_SONNET: () => MODEL_CLAUDE_4_SONNET,
|
|
101
101
|
MODEL_CLAUDE_5_1_FABLE: () => MODEL_CLAUDE_5_1_FABLE,
|
|
102
102
|
MODEL_CLAUDE_5_5_OPUS: () => MODEL_CLAUDE_5_5_OPUS,
|
|
103
|
+
MODEL_CLAUDE_5_5_SONNET: () => MODEL_CLAUDE_5_5_SONNET,
|
|
103
104
|
MODEL_CLAUDE_5_FABLE: () => MODEL_CLAUDE_5_FABLE,
|
|
104
105
|
MODEL_CLAUDE_5_OPUS: () => MODEL_CLAUDE_5_OPUS,
|
|
105
106
|
MODEL_CLAUDE_5_SONNET: () => MODEL_CLAUDE_5_SONNET,
|
|
@@ -252,6 +253,7 @@ var AITuberOnAirChat = (() => {
|
|
|
252
253
|
MODEL_ZAI_GLM_5_3_FLASH: () => MODEL_ZAI_GLM_5_3_FLASH,
|
|
253
254
|
MistralChatService: () => MistralChatService,
|
|
254
255
|
MistralChatServiceProvider: () => MistralChatServiceProvider,
|
|
256
|
+
OPENAI_COMPATIBLE_LOCAL_PRESETS: () => OPENAI_COMPATIBLE_LOCAL_PRESETS,
|
|
255
257
|
OPENROUTER_CREDITS_THRESHOLD: () => OPENROUTER_CREDITS_THRESHOLD,
|
|
256
258
|
OPENROUTER_DEPRECATED_MODELS: () => OPENROUTER_DEPRECATED_MODELS,
|
|
257
259
|
OPENROUTER_FREE_DAILY_LIMIT_HIGH_CREDITS: () => OPENROUTER_FREE_DAILY_LIMIT_HIGH_CREDITS,
|
|
@@ -262,6 +264,7 @@ var AITuberOnAirChat = (() => {
|
|
|
262
264
|
OpenAIChatService: () => OpenAIChatService,
|
|
263
265
|
OpenAIChatServiceProvider: () => OpenAIChatServiceProvider,
|
|
264
266
|
OpenAICompatibleChatServiceProvider: () => OpenAICompatibleChatServiceProvider,
|
|
267
|
+
OpenAICompatibleEndpointError: () => OpenAICompatibleEndpointError,
|
|
265
268
|
OpenRouterChatService: () => OpenRouterChatService,
|
|
266
269
|
OpenRouterChatServiceProvider: () => OpenRouterChatServiceProvider,
|
|
267
270
|
PLAMO_API_BASE_URL: () => PLAMO_API_BASE_URL,
|
|
@@ -333,6 +336,7 @@ var AITuberOnAirChat = (() => {
|
|
|
333
336
|
isZaiReasoningEffortModel: () => isZaiReasoningEffortModel,
|
|
334
337
|
isZaiToolStreamModel: () => isZaiToolStreamModel,
|
|
335
338
|
isZaiVisionModel: () => isZaiVisionModel,
|
|
339
|
+
listOpenAICompatibleModels: () => listOpenAICompatibleModels,
|
|
336
340
|
normalizeClaudeReasoningEffort: () => normalizeClaudeReasoningEffort,
|
|
337
341
|
normalizeDeepSeekReasoningEffort: () => normalizeDeepSeekReasoningEffort,
|
|
338
342
|
normalizeGeminiReasoningEffort: () => normalizeGeminiReasoningEffort,
|
|
@@ -344,11 +348,13 @@ var AITuberOnAirChat = (() => {
|
|
|
344
348
|
parseOpenAICompatibleToolStream: () => parseOpenAICompatibleToolStream,
|
|
345
349
|
processChatWithOptionalTools: () => processChatWithOptionalTools,
|
|
346
350
|
refreshOpenRouterFreeModels: () => refreshOpenRouterFreeModels,
|
|
351
|
+
resolveOpenAICompatibleEndpoint: () => resolveOpenAICompatibleEndpoint,
|
|
347
352
|
resolveVisionModel: () => resolveVisionModel,
|
|
348
353
|
runOnceText: () => runOnceText,
|
|
349
354
|
safeJsonParse: () => safeJsonParse,
|
|
350
355
|
safeParseToolCallInput: () => safeParseToolCallInput,
|
|
351
356
|
screenplayToText: () => screenplayToText,
|
|
357
|
+
testOpenAICompatibleConnection: () => testOpenAICompatibleConnection,
|
|
352
358
|
textToScreenplay: () => textToScreenplay,
|
|
353
359
|
textsToScreenplay: () => textsToScreenplay
|
|
354
360
|
});
|
|
@@ -570,6 +576,7 @@ var AITuberOnAirChat = (() => {
|
|
|
570
576
|
var MODEL_CLAUDE_5_SONNET = "claude-sonnet-5";
|
|
571
577
|
var MODEL_CLAUDE_5_OPUS = "claude-opus-5";
|
|
572
578
|
var MODEL_CLAUDE_5_5_OPUS = "claude-opus-5-5";
|
|
579
|
+
var MODEL_CLAUDE_5_5_SONNET = "claude-sonnet-5-5";
|
|
573
580
|
var CLAUDE_DEPRECATED_MODELS = [
|
|
574
581
|
MODEL_CLAUDE_3_HAIKU,
|
|
575
582
|
MODEL_CLAUDE_3_5_HAIKU,
|
|
@@ -601,7 +608,8 @@ var AITuberOnAirChat = (() => {
|
|
|
601
608
|
[MODEL_CLAUDE_5_1_FABLE]: CLAUDE_XHIGH_REASONING_EFFORTS,
|
|
602
609
|
[MODEL_CLAUDE_5_FABLE]: CLAUDE_XHIGH_REASONING_EFFORTS,
|
|
603
610
|
[MODEL_CLAUDE_5_SONNET]: CLAUDE_XHIGH_REASONING_EFFORTS,
|
|
604
|
-
[MODEL_CLAUDE_5_OPUS]: CLAUDE_XHIGH_REASONING_EFFORTS
|
|
611
|
+
[MODEL_CLAUDE_5_OPUS]: CLAUDE_XHIGH_REASONING_EFFORTS,
|
|
612
|
+
[MODEL_CLAUDE_5_5_SONNET]: CLAUDE_XHIGH_REASONING_EFFORTS
|
|
605
613
|
};
|
|
606
614
|
var CLAUDE_VISION_SUPPORTED_MODELS = [
|
|
607
615
|
MODEL_CLAUDE_5_1_FABLE,
|
|
@@ -615,7 +623,8 @@ var AITuberOnAirChat = (() => {
|
|
|
615
623
|
MODEL_CLAUDE_5_FABLE,
|
|
616
624
|
MODEL_CLAUDE_5_SONNET,
|
|
617
625
|
MODEL_CLAUDE_5_OPUS,
|
|
618
|
-
MODEL_CLAUDE_5_5_OPUS
|
|
626
|
+
MODEL_CLAUDE_5_5_OPUS,
|
|
627
|
+
MODEL_CLAUDE_5_5_SONNET
|
|
619
628
|
];
|
|
620
629
|
function getClaudeSupportedReasoningEfforts(model) {
|
|
621
630
|
return CLAUDE_REASONING_EFFORTS_BY_MODEL[model] ?? [];
|
|
@@ -1826,6 +1835,192 @@ If it's in another language, summarize in that language.
|
|
|
1826
1835
|
};
|
|
1827
1836
|
}
|
|
1828
1837
|
|
|
1838
|
+
// src/utils/openaiCompatibleEndpoint.ts
|
|
1839
|
+
var OPENAI_COMPATIBLE_LOCAL_PRESETS = [
|
|
1840
|
+
{
|
|
1841
|
+
id: "ollama",
|
|
1842
|
+
label: "Ollama",
|
|
1843
|
+
baseUrl: "http://localhost:11434/v1",
|
|
1844
|
+
docsUrl: "https://docs.ollama.com/api/openai-compatibility",
|
|
1845
|
+
corsHint: "Set OLLAMA_ORIGINS to allow additional browser origins."
|
|
1846
|
+
},
|
|
1847
|
+
{
|
|
1848
|
+
id: "lmStudio",
|
|
1849
|
+
label: "LM Studio",
|
|
1850
|
+
baseUrl: "http://localhost:1234/v1",
|
|
1851
|
+
docsUrl: "https://lmstudio.ai/docs/developer/openai-compat",
|
|
1852
|
+
corsHint: "Start the server with lms server start --cors for browser access."
|
|
1853
|
+
},
|
|
1854
|
+
{
|
|
1855
|
+
id: "llamaCpp",
|
|
1856
|
+
label: "llama.cpp",
|
|
1857
|
+
baseUrl: "http://127.0.0.1:8080/v1",
|
|
1858
|
+
docsUrl: "https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md",
|
|
1859
|
+
corsHint: "All origins are allowed by default; use --cors-origins to restrict them."
|
|
1860
|
+
},
|
|
1861
|
+
{
|
|
1862
|
+
id: "vllm",
|
|
1863
|
+
label: "vLLM",
|
|
1864
|
+
baseUrl: "http://localhost:8000/v1",
|
|
1865
|
+
docsUrl: "https://docs.vllm.ai/en/latest/serving/online_serving/openai_compatible_server/",
|
|
1866
|
+
corsHint: "All origins are allowed by default; use --allowed-origins to restrict them."
|
|
1867
|
+
}
|
|
1868
|
+
];
|
|
1869
|
+
var OpenAICompatibleEndpointError = class extends Error {
|
|
1870
|
+
constructor(code, message, status) {
|
|
1871
|
+
super(message);
|
|
1872
|
+
this.name = "OpenAICompatibleEndpointError";
|
|
1873
|
+
this.code = code;
|
|
1874
|
+
this.status = status;
|
|
1875
|
+
}
|
|
1876
|
+
};
|
|
1877
|
+
function resolveOpenAICompatibleEndpoint(input) {
|
|
1878
|
+
let url;
|
|
1879
|
+
try {
|
|
1880
|
+
url = new URL(input.trim());
|
|
1881
|
+
} catch {
|
|
1882
|
+
throw new OpenAICompatibleEndpointError(
|
|
1883
|
+
"invalid-url",
|
|
1884
|
+
"Enter a valid HTTP or HTTPS endpoint URL."
|
|
1885
|
+
);
|
|
1886
|
+
}
|
|
1887
|
+
if (url.protocol !== "http:" && url.protocol !== "https:" || url.search || url.hash || url.username || url.password) {
|
|
1888
|
+
throw new OpenAICompatibleEndpointError(
|
|
1889
|
+
"invalid-url",
|
|
1890
|
+
"Use an HTTP or HTTPS endpoint URL without credentials, a query, or a fragment."
|
|
1891
|
+
);
|
|
1892
|
+
}
|
|
1893
|
+
const path = url.pathname.replace(/\/+$/, "");
|
|
1894
|
+
if (path.endsWith("/api/chat") || path.endsWith("/api/generate")) {
|
|
1895
|
+
throw new OpenAICompatibleEndpointError(
|
|
1896
|
+
"invalid-url",
|
|
1897
|
+
"This looks like Ollama's native API URL. Use the OpenAI-compatible base URL instead, e.g. http://localhost:11434/v1."
|
|
1898
|
+
);
|
|
1899
|
+
}
|
|
1900
|
+
const basePath = !path || path === "/" ? "/v1" : path.endsWith("/chat/completions") ? path.slice(0, -"/chat/completions".length) : path;
|
|
1901
|
+
const baseUrl = `${url.origin}${basePath}`;
|
|
1902
|
+
return {
|
|
1903
|
+
baseUrl,
|
|
1904
|
+
chatCompletionsUrl: `${baseUrl}/chat/completions`,
|
|
1905
|
+
modelsUrl: `${baseUrl}/models`
|
|
1906
|
+
};
|
|
1907
|
+
}
|
|
1908
|
+
async function listOpenAICompatibleModels(options) {
|
|
1909
|
+
const { modelsUrl } = resolveOpenAICompatibleEndpoint(options.endpoint);
|
|
1910
|
+
const timeoutMs = options.timeoutMs ?? 8e3;
|
|
1911
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
1912
|
+
throw new RangeError("timeoutMs must be a positive finite number.");
|
|
1913
|
+
}
|
|
1914
|
+
if (options.signal?.aborted) {
|
|
1915
|
+
throw new OpenAICompatibleEndpointError(
|
|
1916
|
+
"aborted",
|
|
1917
|
+
"The models request was aborted by the caller."
|
|
1918
|
+
);
|
|
1919
|
+
}
|
|
1920
|
+
const controller = new AbortController();
|
|
1921
|
+
let abortCause;
|
|
1922
|
+
const onAbort = () => {
|
|
1923
|
+
if (!abortCause) abortCause = "caller";
|
|
1924
|
+
controller.abort();
|
|
1925
|
+
};
|
|
1926
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
1927
|
+
if (options.signal?.aborted) onAbort();
|
|
1928
|
+
const timeout = setTimeout(() => {
|
|
1929
|
+
if (!abortCause) abortCause = "timeout";
|
|
1930
|
+
controller.abort();
|
|
1931
|
+
}, timeoutMs);
|
|
1932
|
+
try {
|
|
1933
|
+
const headers = {};
|
|
1934
|
+
if (options.apiKey?.trim()) {
|
|
1935
|
+
headers.Authorization = `Bearer ${options.apiKey.trim()}`;
|
|
1936
|
+
}
|
|
1937
|
+
const response = await (options.fetch ?? fetch)(modelsUrl, {
|
|
1938
|
+
method: "GET",
|
|
1939
|
+
headers,
|
|
1940
|
+
signal: controller.signal
|
|
1941
|
+
});
|
|
1942
|
+
if (abortCause) {
|
|
1943
|
+
throw new OpenAICompatibleEndpointError(
|
|
1944
|
+
"aborted",
|
|
1945
|
+
"The models request was aborted by the caller."
|
|
1946
|
+
);
|
|
1947
|
+
}
|
|
1948
|
+
if (!response.ok) {
|
|
1949
|
+
throw new OpenAICompatibleEndpointError(
|
|
1950
|
+
"http",
|
|
1951
|
+
`Model listing failed with HTTP ${response.status}.`,
|
|
1952
|
+
response.status
|
|
1953
|
+
);
|
|
1954
|
+
}
|
|
1955
|
+
let body;
|
|
1956
|
+
try {
|
|
1957
|
+
body = await response.json();
|
|
1958
|
+
} catch {
|
|
1959
|
+
throw new OpenAICompatibleEndpointError(
|
|
1960
|
+
"invalid-response",
|
|
1961
|
+
"The models endpoint did not return valid JSON."
|
|
1962
|
+
);
|
|
1963
|
+
}
|
|
1964
|
+
if (!body || typeof body !== "object" || !("data" in body) || !Array.isArray(body.data) || !body.data.every(
|
|
1965
|
+
(model) => model && typeof model === "object" && "id" in model && typeof model.id === "string"
|
|
1966
|
+
)) {
|
|
1967
|
+
throw new OpenAICompatibleEndpointError(
|
|
1968
|
+
"invalid-response",
|
|
1969
|
+
"The models response must contain data with model IDs."
|
|
1970
|
+
);
|
|
1971
|
+
}
|
|
1972
|
+
if (abortCause) {
|
|
1973
|
+
throw new OpenAICompatibleEndpointError(
|
|
1974
|
+
"aborted",
|
|
1975
|
+
"The models request was aborted by the caller."
|
|
1976
|
+
);
|
|
1977
|
+
}
|
|
1978
|
+
return [...new Set(body.data.map((model) => model.id))];
|
|
1979
|
+
} catch (error) {
|
|
1980
|
+
if (abortCause === "caller") {
|
|
1981
|
+
throw new OpenAICompatibleEndpointError(
|
|
1982
|
+
"aborted",
|
|
1983
|
+
"The models request was aborted by the caller."
|
|
1984
|
+
);
|
|
1985
|
+
}
|
|
1986
|
+
if (abortCause === "timeout") {
|
|
1987
|
+
throw new OpenAICompatibleEndpointError(
|
|
1988
|
+
"timeout",
|
|
1989
|
+
`The models request timed out after ${timeoutMs} ms.`
|
|
1990
|
+
);
|
|
1991
|
+
}
|
|
1992
|
+
if (error instanceof OpenAICompatibleEndpointError) throw error;
|
|
1993
|
+
throw new OpenAICompatibleEndpointError(
|
|
1994
|
+
"network",
|
|
1995
|
+
"Could not reach the models endpoint. In a browser, this is usually a CORS restriction or the server is not running."
|
|
1996
|
+
);
|
|
1997
|
+
} finally {
|
|
1998
|
+
clearTimeout(timeout);
|
|
1999
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
async function testOpenAICompatibleConnection(options) {
|
|
2003
|
+
const startedAt = Date.now();
|
|
2004
|
+
try {
|
|
2005
|
+
const models = await listOpenAICompatibleModels(options);
|
|
2006
|
+
return {
|
|
2007
|
+
ok: true,
|
|
2008
|
+
latencyMs: Date.now() - startedAt,
|
|
2009
|
+
models,
|
|
2010
|
+
...options.model !== void 0 ? { modelFound: models.includes(options.model) } : {}
|
|
2011
|
+
};
|
|
2012
|
+
} catch (error) {
|
|
2013
|
+
if (error instanceof RangeError) throw error;
|
|
2014
|
+
return {
|
|
2015
|
+
ok: false,
|
|
2016
|
+
error: error instanceof OpenAICompatibleEndpointError ? error : new OpenAICompatibleEndpointError(
|
|
2017
|
+
"network",
|
|
2018
|
+
"Could not reach the models endpoint. In a browser, this is usually a CORS restriction or the server is not running."
|
|
2019
|
+
)
|
|
2020
|
+
};
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
|
|
1829
2024
|
// src/utils/openaiCompatibleTools.ts
|
|
1830
2025
|
var buildOpenAICompatibleTools = (tools, format = "chat-completions") => {
|
|
1831
2026
|
if (tools.length === 0) return [];
|
|
@@ -2644,7 +2839,8 @@ If it's in another language, summarize in that language.
|
|
|
2644
2839
|
MODEL_CLAUDE_5_FABLE,
|
|
2645
2840
|
MODEL_CLAUDE_5_SONNET,
|
|
2646
2841
|
MODEL_CLAUDE_5_OPUS,
|
|
2647
|
-
MODEL_CLAUDE_5_5_OPUS
|
|
2842
|
+
MODEL_CLAUDE_5_5_OPUS,
|
|
2843
|
+
MODEL_CLAUDE_5_5_SONNET
|
|
2648
2844
|
];
|
|
2649
2845
|
}
|
|
2650
2846
|
/**
|