Compare commits
2 Commits
ddfa789a31
...
38ff11ee16
| Author | SHA1 | Date | |
|---|---|---|---|
| 38ff11ee16 | |||
| e3ba5d2207 |
8
.gitignore
vendored
8
.gitignore
vendored
@@ -88,4 +88,10 @@ graphify-out/*
|
|||||||
.next-analyze/*
|
.next-analyze/*
|
||||||
|
|
||||||
# Kiro local workspace state
|
# Kiro local workspace state
|
||||||
.kiro/
|
.kiro/
|
||||||
|
|
||||||
|
# CommandCode CLI local state (auth/taste/projects)
|
||||||
|
.commandcode/
|
||||||
|
|
||||||
|
# Pi subagent run artifacts
|
||||||
|
.pi-subagents/
|
||||||
@@ -476,6 +476,9 @@ export function getCapabilitiesForModel(provider, model) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Floor
|
// 4. Floor (upstream-validated gateways keep vision on for unknown models)
|
||||||
|
if (provider && TRUST_UPSTREAM_VISION.has(provider)) {
|
||||||
|
return { ...refine(null, provider, model), vision: true };
|
||||||
|
}
|
||||||
return refine(null, provider, model);
|
return refine(null, provider, model);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { getXaiUsage } from "./usage/xai.js";
|
|||||||
import { getGrokCliUsage } from "./usage/grok-cli.js";
|
import { getGrokCliUsage } from "./usage/grok-cli.js";
|
||||||
import { getKimiUsage } from "./usage/kimi.js";
|
import { getKimiUsage } from "./usage/kimi.js";
|
||||||
import { getDeepseekUsage } from "./usage/deepseek.js";
|
import { getDeepseekUsage } from "./usage/deepseek.js";
|
||||||
|
import { getCommandCodeUsage } from "./usage/commandcode.js";
|
||||||
import { getOpenCodeGoUsage } from "./usage/opencode-go.js";
|
import { getOpenCodeGoUsage } from "./usage/opencode-go.js";
|
||||||
import { getGroqUsage } from "./usage/groq.js";
|
import { getGroqUsage } from "./usage/groq.js";
|
||||||
import { getZedUsage } from "./usage/zed.js";
|
import { getZedUsage } from "./usage/zed.js";
|
||||||
@@ -60,6 +61,7 @@ const USAGE_HANDLERS = {
|
|||||||
kimi: (c) => getKimiUsage(c.accessToken, c.apiKey, c.proxyOptions, c.providerSpecificData),
|
kimi: (c) => getKimiUsage(c.accessToken, c.apiKey, c.proxyOptions, c.providerSpecificData),
|
||||||
"opencode-go": (c) => getOpenCodeGoUsage(c.apiKey, c.proxyOptions),
|
"opencode-go": (c) => getOpenCodeGoUsage(c.apiKey, c.proxyOptions),
|
||||||
deepseek: (c) => getDeepseekUsage(c.apiKey, c.proxyOptions),
|
deepseek: (c) => getDeepseekUsage(c.apiKey, c.proxyOptions),
|
||||||
|
commandcode: (c) => getCommandCodeUsage(c.apiKey, c.proxyOptions),
|
||||||
groq: (c) => getGroqUsage(c.apiKey, c.proxyOptions),
|
groq: (c) => getGroqUsage(c.apiKey, c.proxyOptions),
|
||||||
zed: (c) => getZedUsage(c.accessToken, c.providerSpecificData, c.proxyOptions),
|
zed: (c) => getZedUsage(c.accessToken, c.providerSpecificData, c.proxyOptions),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -295,7 +295,9 @@ export default function ProfilePage() {
|
|||||||
const handleGlobalTimeoutChange = async (e) => {
|
const handleGlobalTimeoutChange = async (e) => {
|
||||||
const raw = e.target.value.replace(/[^0-9]/g, "");
|
const raw = e.target.value.replace(/[^0-9]/g, "");
|
||||||
const numTimeout = parseInt(raw, 10);
|
const numTimeout = parseInt(raw, 10);
|
||||||
const patchValue = (raw !== "" && Number.isFinite(numTimeout) && numTimeout > 0) ? numTimeout : null;
|
// Enforce a sane minimum (1s) so a stray "60" never becomes a 60ms
|
||||||
|
// connect timeout — same guard as the per-provider timeout input.
|
||||||
|
const patchValue = (raw !== "" && Number.isFinite(numTimeout) && numTimeout > 0) ? Math.max(1000, numTimeout) : null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch("/api/settings", {
|
const res = await fetch("/api/settings", {
|
||||||
|
|||||||
@@ -326,7 +326,7 @@ export default function ProviderDetailPage() {
|
|||||||
setProviderStrategy(override.fallbackStrategy || null);
|
setProviderStrategy(override.fallbackStrategy || null);
|
||||||
setProviderStickyLimit(override.stickyRoundRobinLimit != null ? String(override.stickyRoundRobinLimit) : "1");
|
setProviderStickyLimit(override.stickyRoundRobinLimit != null ? String(override.stickyRoundRobinLimit) : "1");
|
||||||
setProviderNoAuthEnabled(override.enabled !== false);
|
setProviderNoAuthEnabled(override.enabled !== false);
|
||||||
// Load per-provider connect timeout
|
// Load per-provider connect timeout (ms)
|
||||||
const timeoutCfg = (settingsData.providerTimeouts || {})[providerId] || {};
|
const timeoutCfg = (settingsData.providerTimeouts || {})[providerId] || {};
|
||||||
setProviderTimeout(timeoutCfg.timeoutMs != null ? String(timeoutCfg.timeoutMs) : "");
|
setProviderTimeout(timeoutCfg.timeoutMs != null ? String(timeoutCfg.timeoutMs) : "");
|
||||||
// Load per-provider thinking config
|
// Load per-provider thinking config
|
||||||
@@ -478,8 +478,10 @@ export default function ProviderDetailPage() {
|
|||||||
delete updated[providerId];
|
delete updated[providerId];
|
||||||
} else {
|
} else {
|
||||||
const timeoutMs = parseInt(ms, 10);
|
const timeoutMs = parseInt(ms, 10);
|
||||||
|
// Stored in ms; enforce a sane minimum (1s) so a stray "60" means
|
||||||
|
// 60 SECONDS-worth of protection — never a 60ms connect timeout.
|
||||||
if (Number.isFinite(timeoutMs) && timeoutMs > 0) {
|
if (Number.isFinite(timeoutMs) && timeoutMs > 0) {
|
||||||
updated[providerId] = { timeoutMs };
|
updated[providerId] = { timeoutMs: Math.max(1000, timeoutMs) };
|
||||||
} else {
|
} else {
|
||||||
delete updated[providerId];
|
delete updated[providerId];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -648,6 +648,24 @@ export function parseQuotaData(provider, data) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "commandcode":
|
||||||
|
// CommandCode reports currency credits (5-hour/weekly windows + monthly
|
||||||
|
// credits) with used/total in dollars. Forward remainingPercentage (the
|
||||||
|
// UI would otherwise render "$0.05" balances as "0%") and unit "$".
|
||||||
|
if (data.quotas) {
|
||||||
|
Object.entries(data.quotas).forEach(([name, quota]) => {
|
||||||
|
normalizedQuotas.push({
|
||||||
|
name,
|
||||||
|
used: quota.used || 0,
|
||||||
|
total: quota.total || 0,
|
||||||
|
unit: quota.unit || "$",
|
||||||
|
resetAt: quota.resetAt || null,
|
||||||
|
remainingPercentage: quota.remainingPercentage,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Generic fallback for unknown providers
|
// Generic fallback for unknown providers
|
||||||
if (data.quotas) {
|
if (data.quotas) {
|
||||||
|
|||||||
@@ -10,8 +10,9 @@ import {
|
|||||||
isModelAllowedForKey,
|
isModelAllowedForKey,
|
||||||
} from "../services/auth.js";
|
} from "../services/auth.js";
|
||||||
import { handleAntigravityQuotaError, clearAntigravityStrikes } from "../services/antigravityQuota.js";
|
import { handleAntigravityQuotaError, clearAntigravityStrikes } from "../services/antigravityQuota.js";
|
||||||
import { getSettings } from "@/lib/localDb";
|
import { getSettings, getCustomModels } from "@/lib/localDb";
|
||||||
import { getModelInfo, getComboModels } from "../services/model.js";
|
import { getModelInfo, getComboModels } from "../services/model.js";
|
||||||
|
import { capabilitiesFromServiceKind } from "open-sse/providers/capabilities.js";
|
||||||
import { handleChatCore } from "open-sse/handlers/chatCore.js";
|
import { handleChatCore } from "open-sse/handlers/chatCore.js";
|
||||||
import { DEFAULT_HEADROOM_URL } from "@/lib/headroom/detect";
|
import { DEFAULT_HEADROOM_URL } from "@/lib/headroom/detect";
|
||||||
import { getTransform as getPxpipeTransform } from "@/lib/pxpipe/loader.js";
|
import { getTransform as getPxpipeTransform } from "@/lib/pxpipe/loader.js";
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ const authMocks = vi.hoisted(() => ({
|
|||||||
clearAccountError: vi.fn(async () => {}),
|
clearAccountError: vi.fn(async () => {}),
|
||||||
extractApiKey: vi.fn(() => null),
|
extractApiKey: vi.fn(() => null),
|
||||||
isValidApiKey: vi.fn(async () => true),
|
isValidApiKey: vi.fn(async () => true),
|
||||||
|
isModelAllowedForKey: vi.fn(() => true),
|
||||||
}));
|
}));
|
||||||
const tokenMocks = vi.hoisted(() => ({
|
const tokenMocks = vi.hoisted(() => ({
|
||||||
checkAndRefreshToken: vi.fn(async (_p, creds) => creds),
|
checkAndRefreshToken: vi.fn(async (_p, creds) => creds),
|
||||||
|
|||||||
Reference in New Issue
Block a user