@aituber-onair/chat 0.56.0 → 0.57.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 +20 -0
- package/README.md +24 -0
- 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/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 +191 -0
- package/dist/umd/aituber-onair-chat.min.js +8 -8
- package/package.json +1 -1
|
@@ -252,6 +252,7 @@ var AITuberOnAirChat = (() => {
|
|
|
252
252
|
MODEL_ZAI_GLM_5_3_FLASH: () => MODEL_ZAI_GLM_5_3_FLASH,
|
|
253
253
|
MistralChatService: () => MistralChatService,
|
|
254
254
|
MistralChatServiceProvider: () => MistralChatServiceProvider,
|
|
255
|
+
OPENAI_COMPATIBLE_LOCAL_PRESETS: () => OPENAI_COMPATIBLE_LOCAL_PRESETS,
|
|
255
256
|
OPENROUTER_CREDITS_THRESHOLD: () => OPENROUTER_CREDITS_THRESHOLD,
|
|
256
257
|
OPENROUTER_DEPRECATED_MODELS: () => OPENROUTER_DEPRECATED_MODELS,
|
|
257
258
|
OPENROUTER_FREE_DAILY_LIMIT_HIGH_CREDITS: () => OPENROUTER_FREE_DAILY_LIMIT_HIGH_CREDITS,
|
|
@@ -262,6 +263,7 @@ var AITuberOnAirChat = (() => {
|
|
|
262
263
|
OpenAIChatService: () => OpenAIChatService,
|
|
263
264
|
OpenAIChatServiceProvider: () => OpenAIChatServiceProvider,
|
|
264
265
|
OpenAICompatibleChatServiceProvider: () => OpenAICompatibleChatServiceProvider,
|
|
266
|
+
OpenAICompatibleEndpointError: () => OpenAICompatibleEndpointError,
|
|
265
267
|
OpenRouterChatService: () => OpenRouterChatService,
|
|
266
268
|
OpenRouterChatServiceProvider: () => OpenRouterChatServiceProvider,
|
|
267
269
|
PLAMO_API_BASE_URL: () => PLAMO_API_BASE_URL,
|
|
@@ -333,6 +335,7 @@ var AITuberOnAirChat = (() => {
|
|
|
333
335
|
isZaiReasoningEffortModel: () => isZaiReasoningEffortModel,
|
|
334
336
|
isZaiToolStreamModel: () => isZaiToolStreamModel,
|
|
335
337
|
isZaiVisionModel: () => isZaiVisionModel,
|
|
338
|
+
listOpenAICompatibleModels: () => listOpenAICompatibleModels,
|
|
336
339
|
normalizeClaudeReasoningEffort: () => normalizeClaudeReasoningEffort,
|
|
337
340
|
normalizeDeepSeekReasoningEffort: () => normalizeDeepSeekReasoningEffort,
|
|
338
341
|
normalizeGeminiReasoningEffort: () => normalizeGeminiReasoningEffort,
|
|
@@ -344,11 +347,13 @@ var AITuberOnAirChat = (() => {
|
|
|
344
347
|
parseOpenAICompatibleToolStream: () => parseOpenAICompatibleToolStream,
|
|
345
348
|
processChatWithOptionalTools: () => processChatWithOptionalTools,
|
|
346
349
|
refreshOpenRouterFreeModels: () => refreshOpenRouterFreeModels,
|
|
350
|
+
resolveOpenAICompatibleEndpoint: () => resolveOpenAICompatibleEndpoint,
|
|
347
351
|
resolveVisionModel: () => resolveVisionModel,
|
|
348
352
|
runOnceText: () => runOnceText,
|
|
349
353
|
safeJsonParse: () => safeJsonParse,
|
|
350
354
|
safeParseToolCallInput: () => safeParseToolCallInput,
|
|
351
355
|
screenplayToText: () => screenplayToText,
|
|
356
|
+
testOpenAICompatibleConnection: () => testOpenAICompatibleConnection,
|
|
352
357
|
textToScreenplay: () => textToScreenplay,
|
|
353
358
|
textsToScreenplay: () => textsToScreenplay
|
|
354
359
|
});
|
|
@@ -1826,6 +1831,192 @@ If it's in another language, summarize in that language.
|
|
|
1826
1831
|
};
|
|
1827
1832
|
}
|
|
1828
1833
|
|
|
1834
|
+
// src/utils/openaiCompatibleEndpoint.ts
|
|
1835
|
+
var OPENAI_COMPATIBLE_LOCAL_PRESETS = [
|
|
1836
|
+
{
|
|
1837
|
+
id: "ollama",
|
|
1838
|
+
label: "Ollama",
|
|
1839
|
+
baseUrl: "http://localhost:11434/v1",
|
|
1840
|
+
docsUrl: "https://docs.ollama.com/api/openai-compatibility",
|
|
1841
|
+
corsHint: "Set OLLAMA_ORIGINS to allow additional browser origins."
|
|
1842
|
+
},
|
|
1843
|
+
{
|
|
1844
|
+
id: "lmStudio",
|
|
1845
|
+
label: "LM Studio",
|
|
1846
|
+
baseUrl: "http://localhost:1234/v1",
|
|
1847
|
+
docsUrl: "https://lmstudio.ai/docs/developer/openai-compat",
|
|
1848
|
+
corsHint: "Start the server with lms server start --cors for browser access."
|
|
1849
|
+
},
|
|
1850
|
+
{
|
|
1851
|
+
id: "llamaCpp",
|
|
1852
|
+
label: "llama.cpp",
|
|
1853
|
+
baseUrl: "http://127.0.0.1:8080/v1",
|
|
1854
|
+
docsUrl: "https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md",
|
|
1855
|
+
corsHint: "All origins are allowed by default; use --cors-origins to restrict them."
|
|
1856
|
+
},
|
|
1857
|
+
{
|
|
1858
|
+
id: "vllm",
|
|
1859
|
+
label: "vLLM",
|
|
1860
|
+
baseUrl: "http://localhost:8000/v1",
|
|
1861
|
+
docsUrl: "https://docs.vllm.ai/en/latest/serving/online_serving/openai_compatible_server/",
|
|
1862
|
+
corsHint: "All origins are allowed by default; use --allowed-origins to restrict them."
|
|
1863
|
+
}
|
|
1864
|
+
];
|
|
1865
|
+
var OpenAICompatibleEndpointError = class extends Error {
|
|
1866
|
+
constructor(code, message, status) {
|
|
1867
|
+
super(message);
|
|
1868
|
+
this.name = "OpenAICompatibleEndpointError";
|
|
1869
|
+
this.code = code;
|
|
1870
|
+
this.status = status;
|
|
1871
|
+
}
|
|
1872
|
+
};
|
|
1873
|
+
function resolveOpenAICompatibleEndpoint(input) {
|
|
1874
|
+
let url;
|
|
1875
|
+
try {
|
|
1876
|
+
url = new URL(input.trim());
|
|
1877
|
+
} catch {
|
|
1878
|
+
throw new OpenAICompatibleEndpointError(
|
|
1879
|
+
"invalid-url",
|
|
1880
|
+
"Enter a valid HTTP or HTTPS endpoint URL."
|
|
1881
|
+
);
|
|
1882
|
+
}
|
|
1883
|
+
if (url.protocol !== "http:" && url.protocol !== "https:" || url.search || url.hash || url.username || url.password) {
|
|
1884
|
+
throw new OpenAICompatibleEndpointError(
|
|
1885
|
+
"invalid-url",
|
|
1886
|
+
"Use an HTTP or HTTPS endpoint URL without credentials, a query, or a fragment."
|
|
1887
|
+
);
|
|
1888
|
+
}
|
|
1889
|
+
const path = url.pathname.replace(/\/+$/, "");
|
|
1890
|
+
if (path.endsWith("/api/chat") || path.endsWith("/api/generate")) {
|
|
1891
|
+
throw new OpenAICompatibleEndpointError(
|
|
1892
|
+
"invalid-url",
|
|
1893
|
+
"This looks like Ollama's native API URL. Use the OpenAI-compatible base URL instead, e.g. http://localhost:11434/v1."
|
|
1894
|
+
);
|
|
1895
|
+
}
|
|
1896
|
+
const basePath = !path || path === "/" ? "/v1" : path.endsWith("/chat/completions") ? path.slice(0, -"/chat/completions".length) : path;
|
|
1897
|
+
const baseUrl = `${url.origin}${basePath}`;
|
|
1898
|
+
return {
|
|
1899
|
+
baseUrl,
|
|
1900
|
+
chatCompletionsUrl: `${baseUrl}/chat/completions`,
|
|
1901
|
+
modelsUrl: `${baseUrl}/models`
|
|
1902
|
+
};
|
|
1903
|
+
}
|
|
1904
|
+
async function listOpenAICompatibleModels(options) {
|
|
1905
|
+
const { modelsUrl } = resolveOpenAICompatibleEndpoint(options.endpoint);
|
|
1906
|
+
const timeoutMs = options.timeoutMs ?? 8e3;
|
|
1907
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
1908
|
+
throw new RangeError("timeoutMs must be a positive finite number.");
|
|
1909
|
+
}
|
|
1910
|
+
if (options.signal?.aborted) {
|
|
1911
|
+
throw new OpenAICompatibleEndpointError(
|
|
1912
|
+
"aborted",
|
|
1913
|
+
"The models request was aborted by the caller."
|
|
1914
|
+
);
|
|
1915
|
+
}
|
|
1916
|
+
const controller = new AbortController();
|
|
1917
|
+
let abortCause;
|
|
1918
|
+
const onAbort = () => {
|
|
1919
|
+
if (!abortCause) abortCause = "caller";
|
|
1920
|
+
controller.abort();
|
|
1921
|
+
};
|
|
1922
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
1923
|
+
if (options.signal?.aborted) onAbort();
|
|
1924
|
+
const timeout = setTimeout(() => {
|
|
1925
|
+
if (!abortCause) abortCause = "timeout";
|
|
1926
|
+
controller.abort();
|
|
1927
|
+
}, timeoutMs);
|
|
1928
|
+
try {
|
|
1929
|
+
const headers = {};
|
|
1930
|
+
if (options.apiKey?.trim()) {
|
|
1931
|
+
headers.Authorization = `Bearer ${options.apiKey.trim()}`;
|
|
1932
|
+
}
|
|
1933
|
+
const response = await (options.fetch ?? fetch)(modelsUrl, {
|
|
1934
|
+
method: "GET",
|
|
1935
|
+
headers,
|
|
1936
|
+
signal: controller.signal
|
|
1937
|
+
});
|
|
1938
|
+
if (abortCause) {
|
|
1939
|
+
throw new OpenAICompatibleEndpointError(
|
|
1940
|
+
"aborted",
|
|
1941
|
+
"The models request was aborted by the caller."
|
|
1942
|
+
);
|
|
1943
|
+
}
|
|
1944
|
+
if (!response.ok) {
|
|
1945
|
+
throw new OpenAICompatibleEndpointError(
|
|
1946
|
+
"http",
|
|
1947
|
+
`Model listing failed with HTTP ${response.status}.`,
|
|
1948
|
+
response.status
|
|
1949
|
+
);
|
|
1950
|
+
}
|
|
1951
|
+
let body;
|
|
1952
|
+
try {
|
|
1953
|
+
body = await response.json();
|
|
1954
|
+
} catch {
|
|
1955
|
+
throw new OpenAICompatibleEndpointError(
|
|
1956
|
+
"invalid-response",
|
|
1957
|
+
"The models endpoint did not return valid JSON."
|
|
1958
|
+
);
|
|
1959
|
+
}
|
|
1960
|
+
if (!body || typeof body !== "object" || !("data" in body) || !Array.isArray(body.data) || !body.data.every(
|
|
1961
|
+
(model) => model && typeof model === "object" && "id" in model && typeof model.id === "string"
|
|
1962
|
+
)) {
|
|
1963
|
+
throw new OpenAICompatibleEndpointError(
|
|
1964
|
+
"invalid-response",
|
|
1965
|
+
"The models response must contain data with model IDs."
|
|
1966
|
+
);
|
|
1967
|
+
}
|
|
1968
|
+
if (abortCause) {
|
|
1969
|
+
throw new OpenAICompatibleEndpointError(
|
|
1970
|
+
"aborted",
|
|
1971
|
+
"The models request was aborted by the caller."
|
|
1972
|
+
);
|
|
1973
|
+
}
|
|
1974
|
+
return [...new Set(body.data.map((model) => model.id))];
|
|
1975
|
+
} catch (error) {
|
|
1976
|
+
if (abortCause === "caller") {
|
|
1977
|
+
throw new OpenAICompatibleEndpointError(
|
|
1978
|
+
"aborted",
|
|
1979
|
+
"The models request was aborted by the caller."
|
|
1980
|
+
);
|
|
1981
|
+
}
|
|
1982
|
+
if (abortCause === "timeout") {
|
|
1983
|
+
throw new OpenAICompatibleEndpointError(
|
|
1984
|
+
"timeout",
|
|
1985
|
+
`The models request timed out after ${timeoutMs} ms.`
|
|
1986
|
+
);
|
|
1987
|
+
}
|
|
1988
|
+
if (error instanceof OpenAICompatibleEndpointError) throw error;
|
|
1989
|
+
throw new OpenAICompatibleEndpointError(
|
|
1990
|
+
"network",
|
|
1991
|
+
"Could not reach the models endpoint. In a browser, this is usually a CORS restriction or the server is not running."
|
|
1992
|
+
);
|
|
1993
|
+
} finally {
|
|
1994
|
+
clearTimeout(timeout);
|
|
1995
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
async function testOpenAICompatibleConnection(options) {
|
|
1999
|
+
const startedAt = Date.now();
|
|
2000
|
+
try {
|
|
2001
|
+
const models = await listOpenAICompatibleModels(options);
|
|
2002
|
+
return {
|
|
2003
|
+
ok: true,
|
|
2004
|
+
latencyMs: Date.now() - startedAt,
|
|
2005
|
+
models,
|
|
2006
|
+
...options.model !== void 0 ? { modelFound: models.includes(options.model) } : {}
|
|
2007
|
+
};
|
|
2008
|
+
} catch (error) {
|
|
2009
|
+
if (error instanceof RangeError) throw error;
|
|
2010
|
+
return {
|
|
2011
|
+
ok: false,
|
|
2012
|
+
error: error instanceof OpenAICompatibleEndpointError ? error : new OpenAICompatibleEndpointError(
|
|
2013
|
+
"network",
|
|
2014
|
+
"Could not reach the models endpoint. In a browser, this is usually a CORS restriction or the server is not running."
|
|
2015
|
+
)
|
|
2016
|
+
};
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
|
|
1829
2020
|
// src/utils/openaiCompatibleTools.ts
|
|
1830
2021
|
var buildOpenAICompatibleTools = (tools, format = "chat-completions") => {
|
|
1831
2022
|
if (tools.length === 0) return [];
|