feat: Claude auto-ping to warm 5h window after reset

Auto-sends a minimal request right after each Claude OAuth connection's 5h quota window resets, so a fresh window starts immediately without waiting. Per-connection toggle on providers and quota dashboards.

- claudeAutoPing scheduler (server-side, 60s tick) hooked into initializeApp
- per-connection enable map in settings.claudeAutoPing.connections
- toggle + tooltip in ConnectionRow and ProviderLimits (Claude OAuth only)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
decoluaandCursor committed 2026-06-17 09:31:46 +07:00
1 parent d03f9fb823
commit 740093d852
6 files changed
+204 -2

No files matched your search

@@ -56,6 +56,7 @@ export default function ProviderDetailPage() {
const [providerStrategy, setProviderStrategy] = useState(null);
const [providerStickyLimit, setProviderStickyLimit] = useState("");
const [thinkingMode, setThinkingMode] = useState("auto");
const [autoPing, setAutoPing] = useState({ enabled: false, connections: {} });
const [suggestedModels, setSuggestedModels] = useState([]);
const [kiloFreeModels, setKiloFreeModels] = useState([]);
const [disabledModelIds, setDisabledModelIds] = useState([]);
@@ -258,6 +259,8 @@ export default function ProviderDetailPage() {
// Load per-provider thinking config
const thinkingCfg = (settingsData.providerThinking || {})[providerId] || {};
setThinkingMode(thinkingCfg.mode || "auto");
const apCfg = settingsData.claudeAutoPing || {};
setAutoPing({ enabled: apCfg.enabled === true, connections: apCfg.connections || {} });
if (nodesRes.ok) {
let node = (nodesData.nodes || []).find((entry) => entry.id === providerId) || null;
@@ -370,6 +373,23 @@ export default function ProviderDetailPage() {
saveThinkingConfig(mode);
};
const saveAutoPing = async (next) => {
setAutoPing(next);
try {
await fetch("/api/settings", {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ claudeAutoPing: next }),
});
} catch (error) {
console.log("Error saving auto-ping config:", error);
}
};
const handleAutoPingConnection = (connectionId, on) => {
saveAutoPing({ ...autoPing, connections: { ...autoPing.connections, [connectionId]: on } });
};
useEffect(() => {
fetchConnections();
fetchAliases();
@@ -793,6 +813,10 @@ export default function ProviderDetailPage() {
onMoveUp={() => handleSwapPriority(index, index - 1)}
onMoveDown={() => handleSwapPriority(index, index + 1)}
onToggleActive={(isActive) => handleUpdateConnectionStatus(conn.id, isActive)}
autoPing={providerId === "claude" && conn.authType === "oauth" ? {
on: autoPing.connections[conn.id] === true,
onToggle: (on) => handleAutoPingConnection(conn.id, on),
} : null}
onUpdateProxy={async (proxyPoolId) => {
try {
const res = await fetch(`/api/providers/${conn.id}`, {