mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
fix: complete bugfixes for UI, OAuth fallbacks, cliRuntime Windows constraints and Codex non-streaming integration
This commit is contained in:
@@ -151,7 +151,7 @@ export function translateNonStreamingResponse(
|
||||
if (toolCalls.length > 0) {
|
||||
message.tool_calls = toolCalls;
|
||||
}
|
||||
if (!message.content && !message.tool_calls) {
|
||||
if (message.content === undefined) {
|
||||
message.content = "";
|
||||
}
|
||||
|
||||
@@ -352,7 +352,7 @@ export function translateNonStreamingResponse(
|
||||
if (toolCalls.length > 0) {
|
||||
message.tool_calls = toolCalls;
|
||||
}
|
||||
if (!message.content && !message.tool_calls) {
|
||||
if (message.content === undefined) {
|
||||
message.content = "";
|
||||
}
|
||||
|
||||
@@ -410,18 +410,31 @@ function convertOpenAINonStreamingToClaude(openaiResponse: JsonRecord): JsonReco
|
||||
|
||||
const content = [];
|
||||
|
||||
let hasTextOrReasoning = false;
|
||||
|
||||
if (messageObj.reasoning_content) {
|
||||
hasTextOrReasoning = true;
|
||||
content.push({
|
||||
type: "thinking",
|
||||
thinking: toString(messageObj.reasoning_content),
|
||||
});
|
||||
}
|
||||
|
||||
if (messageObj.content) {
|
||||
// Always include text if it exists (even empty string), or if there are no tool calls and no reasoning
|
||||
const hasToolCalls = Array.isArray(messageObj.tool_calls) && messageObj.tool_calls.length > 0;
|
||||
|
||||
if (messageObj.content !== undefined && messageObj.content !== null) {
|
||||
hasTextOrReasoning = true;
|
||||
content.push({
|
||||
type: "text",
|
||||
text: toString(messageObj.content),
|
||||
});
|
||||
} else if (!hasTextOrReasoning) {
|
||||
// Claude format expects a text block even before tool calls (or if empty)
|
||||
content.push({
|
||||
type: "text",
|
||||
text: "",
|
||||
});
|
||||
}
|
||||
|
||||
if (Array.isArray(messageObj.tool_calls)) {
|
||||
|
||||
@@ -211,7 +211,12 @@ export default function ProviderLimits() {
|
||||
USAGE_SUPPORTED_PROVIDERS.includes(conn.provider) &&
|
||||
(conn.authType === "oauth" || conn.authType === "apikey")
|
||||
);
|
||||
await Promise.all(usageConnections.map((conn) => fetchQuota(conn.id, conn.provider)));
|
||||
// Fix Issue #784: Fetch quotas in chunks of 5 to avoid spamming the backend/provider APIs and hanging the UI.
|
||||
const chunkSize = 5;
|
||||
for (let i = 0; i < usageConnections.length; i += chunkSize) {
|
||||
const chunk = usageConnections.slice(i, i + chunkSize);
|
||||
await Promise.all(chunk.map((conn) => fetchQuota(conn.id, conn.provider)));
|
||||
}
|
||||
setLastUpdated(new Date());
|
||||
} catch (error) {
|
||||
console.error("Error refreshing all:", error);
|
||||
|
||||
@@ -211,6 +211,8 @@ export default function OAuthModal({
|
||||
return;
|
||||
}
|
||||
|
||||
let forceManual = false;
|
||||
|
||||
// Codex: on localhost use callback server on port 1455,
|
||||
// on remote use standard auth code flow (callback server is unreachable)
|
||||
if (provider === "codex") {
|
||||
@@ -252,11 +254,13 @@ export default function OAuthModal({
|
||||
setPolling(false);
|
||||
throw new Error("Authorization timeout");
|
||||
} catch (codexErr) {
|
||||
console.warn(
|
||||
"Codex callback server failed, falling back to standard manual flow",
|
||||
codexErr
|
||||
);
|
||||
setPolling(false);
|
||||
setStep("input");
|
||||
setError(codexErr.message + " — You can paste the callback URL manually below.");
|
||||
forceManual = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Remote: fall through to standard auth code flow below
|
||||
}
|
||||
@@ -306,8 +310,8 @@ export default function OAuthModal({
|
||||
|
||||
setAuthData({ ...data, redirectUri });
|
||||
|
||||
// For non-true-localhost (LAN IPs, remote): use manual input mode (user pastes callback URL)
|
||||
if (!isTrueLocalhost) {
|
||||
// For non-true-localhost (LAN IPs, remote) or manual fallback: use manual input mode (user pastes callback URL)
|
||||
if (!isTrueLocalhost || forceManual) {
|
||||
setStep("input");
|
||||
window.open(data.authUrl, "oauth_auth");
|
||||
} else {
|
||||
|
||||
@@ -328,10 +328,7 @@ const getExpectedParentPaths = (): string[] => {
|
||||
const npmPrefix = getNpmGlobalPrefix();
|
||||
|
||||
// Add common user bin directories
|
||||
const userBinPaths = [
|
||||
path.join(home, "bin"),
|
||||
path.join(home, ".local", "bin"),
|
||||
];
|
||||
const userBinPaths = [path.join(home, "bin"), path.join(home, ".local", "bin")];
|
||||
|
||||
return [
|
||||
home,
|
||||
@@ -531,11 +528,15 @@ const locateCommand = async (command: string, env: Record<string, string | undef
|
||||
if (!located.ok || !located.stdout) {
|
||||
return { installed: false, commandPath: null, reason: "not_found" };
|
||||
}
|
||||
const first =
|
||||
located.stdout
|
||||
.split(/\r?\n/)
|
||||
.map((line) => normalizeMsys2Path(line.trim()))
|
||||
.find(Boolean) || null;
|
||||
const lines = located.stdout
|
||||
.split(/\r?\n/)
|
||||
.map((line) => normalizeMsys2Path(line.trim()))
|
||||
.filter(Boolean);
|
||||
|
||||
// Issue #809: Prioritize executable wrappers (.cmd, .exe, .bat) over extensionless bash scripts
|
||||
// that NPM often drops alongside the wrappers in global installs.
|
||||
const first = lines.find((line) => /\.(cmd|exe|bat)$/i.test(line)) || lines[0] || null;
|
||||
|
||||
return { installed: !!first, commandPath: first, reason: first ? null : "not_found" };
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user