feat: auto-fallback to Haiku when Sonnet is rate-limited
This commit is contained in:
52
server.js
52
server.js
@@ -30,13 +30,34 @@ function getAccessToken() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SYSTEM_PROMPT = "You are Claude Code, Anthropic's official CLI for Claude.\n\nAnswer in the same language as the user. Give the shortest possible correct answer. No greetings, no filler, no emojis, no markdown formatting unless the user explicitly asks for code. Do not restate the question. Do not add caveats or disclaimers. Respond with just the answer — nothing else.";
|
||||||
|
|
||||||
|
async function callClaude(modelId, text, accessToken) {
|
||||||
|
return fetch('https://api.anthropic.com/v1/messages', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${accessToken}`,
|
||||||
|
'anthropic-version': '2023-06-01',
|
||||||
|
'anthropic-beta': 'claude-code-20250219,oauth-2025-04-20,interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14',
|
||||||
|
'x-app': 'cli',
|
||||||
|
'User-Agent': 'claude-cli/2.1.114',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
model: modelId,
|
||||||
|
max_tokens: 8192,
|
||||||
|
stream: true,
|
||||||
|
system: SYSTEM_PROMPT,
|
||||||
|
messages: [{ role: 'user', content: text }],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
app.post('/api/chat', async (req, res) => {
|
app.post('/api/chat', async (req, res) => {
|
||||||
const { text, model = 'sonnet' } = req.body;
|
const { text, model = 'sonnet' } = req.body;
|
||||||
if (!text?.trim()) return res.status(400).json({ error: 'text required' });
|
if (!text?.trim()) return res.status(400).json({ error: 'text required' });
|
||||||
|
|
||||||
const modelId = MODELS[model] || MODELS.sonnet;
|
|
||||||
const accessToken = getAccessToken();
|
const accessToken = getAccessToken();
|
||||||
|
|
||||||
if (!accessToken) {
|
if (!accessToken) {
|
||||||
return res.status(500).json({ error: 'No credentials in ' + (process.env.CLAUDE_CONFIG_DIR || '~/.claude') });
|
return res.status(500).json({ error: 'No credentials in ' + (process.env.CLAUDE_CONFIG_DIR || '~/.claude') });
|
||||||
}
|
}
|
||||||
@@ -48,25 +69,16 @@ app.post('/api/chat', async (req, res) => {
|
|||||||
|
|
||||||
const heartbeat = setInterval(() => res.write(': ping\n\n'), 15000);
|
const heartbeat = setInterval(() => res.write(': ping\n\n'), 15000);
|
||||||
|
|
||||||
|
const primaryId = MODELS[model] || MODELS.sonnet;
|
||||||
|
const fallbackId = MODELS.haiku;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const apiResp = await fetch('https://api.anthropic.com/v1/messages', {
|
let apiResp = await callClaude(primaryId, text, accessToken);
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
// Fallback to Haiku on rate limit
|
||||||
'Content-Type': 'application/json',
|
if (apiResp.status === 429 && primaryId !== fallbackId) {
|
||||||
'Authorization': `Bearer ${accessToken}`,
|
apiResp = await callClaude(fallbackId, text, accessToken);
|
||||||
'anthropic-version': '2023-06-01',
|
}
|
||||||
'anthropic-beta': 'claude-code-20250219,oauth-2025-04-20,interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14',
|
|
||||||
'x-app': 'cli',
|
|
||||||
'User-Agent': 'claude-cli/2.1.114',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
model: modelId,
|
|
||||||
max_tokens: 8192,
|
|
||||||
stream: true,
|
|
||||||
system: "You are Claude Code, Anthropic's official CLI for Claude.\n\nAnswer in the same language as the user. Give the shortest possible correct answer. No greetings, no filler, no emojis, no markdown formatting unless the user explicitly asks for code. Do not restate the question. Do not add caveats or disclaimers. Respond with just the answer — nothing else.",
|
|
||||||
messages: [{ role: 'user', content: text }],
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!apiResp.ok) {
|
if (!apiResp.ok) {
|
||||||
const errText = await apiResp.text();
|
const errText = await apiResp.text();
|
||||||
|
|||||||
Reference in New Issue
Block a user