Merge remote-tracking branch 'origin/master' into gitea/feature/end

Resolved conflicts taking origin/master (v0.5.55) as canonical, with local
features re-applied:
- runtime log level (LOG_LEVEL env + dashboard Settings → Logging, applied
  immediately and persisted across restarts)
- free/noAuth provider enable/disable toggle via providerStrategies.enabled
- parallel model testing (Test All Models / Test Selected Keys)
This commit is contained in:
2026-08-17 00:38:31 +07:00
parent e7470e955e
commit 7e45ead2ac
557 changed files with 53396 additions and 6935 deletions

View File

@@ -19,9 +19,15 @@ function isAnthropicCompatible(provider) {
return typeof provider === "string" && provider.startsWith(ANTHROPIC_COMPATIBLE_PREFIX);
}
function getOpenAICompatibleType(provider) {
if (!isOpenAICompatible(provider)) return "chat";
return provider.includes("responses") ? "responses" : "chat";
// Resolve the API type (chat vs responses) for an openai-compatible node.
// The stored apiType on the connection's providerSpecificData (kept in sync with
// the node on create/update) is authoritative. Falls back to the node ID
// substring for legacy nodes created before apiType was persisted — their IDs
// embed the type: openai-compatible-<chat|responses>-<uuid>.
export function resolveOpenAICompatibleApiType(provider, credentials = null) {
const stored = credentials?.providerSpecificData?.apiType;
if (stored === "chat" || stored === "responses") return stored;
return typeof provider === "string" && provider.includes("responses") ? "responses" : "chat";
}
// Detect request format from body structure
@@ -105,9 +111,9 @@ export function detectFormat(body) {
}
// Get provider config (internal — no external runtime consumer)
function getProviderConfig(provider) {
function getProviderConfig(provider, credentials = null) {
if (isOpenAICompatible(provider)) {
const apiType = getOpenAICompatibleType(provider);
const apiType = resolveOpenAICompatibleApiType(provider, credentials);
return {
...PROVIDERS.openai,
format: apiType === "responses" ? "openai-responses" : "openai",
@@ -125,14 +131,14 @@ function getProviderConfig(provider) {
}
// Get target format for provider
export function getTargetFormat(provider) {
export function getTargetFormat(provider, credentials = null) {
if (isOpenAICompatible(provider)) {
return getOpenAICompatibleType(provider) === "responses" ? "openai-responses" : "openai";
return resolveOpenAICompatibleApiType(provider, credentials) === "responses" ? "openai-responses" : "openai";
}
if (isAnthropicCompatible(provider)) {
return "claude";
}
const config = getProviderConfig(provider);
const config = getProviderConfig(provider, credentials);
return config.format || "openai";
}