dm / commit
fix: remove anthropic-beta header, add comprehensive logging
public/index.html | 87 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 21 deletions(-) diff --git a/public/index.html b/public/index.html index fb75dc0..27169c9 100644 --- a/public/index.html +++ b/public/index.html @@ -1654,30 +1654,64 @@ async function sendMessage(text, showAsPlayer = true) { let apiMessages = [...conversationHistory]; let statUpdate = null; let firstChunk = true; + let loopIteration = 0; while (true) { - const response = await fetch('https://api.anthropic.com/v1/messages', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-api-key': gameState.apiKey, - 'anthropic-version': '2023-06-01', - 'anthropic-beta': 'prompt-caching-2024-07-31', - 'anthropic-dangerous-allow-browser': 'true', - }, - body: JSON.stringify({ - model: 'claude-opus-4-7', - max_tokens: 1500, - stream: true, - system: [{ type: 'text', text: buildSystemPrompt(gameState.character, gameState.theme), cache_control: { type: 'ephemeral' } }], - tools: [UPDATE_TOOL], - messages: apiMessages, - }), - }); + loopIteration++; + const keyHint = gameState.apiKey.slice(0, 10) + '…' + gameState.apiKey.slice(-4); + const requestBody = { + model: 'claude-opus-4-7', + max_tokens: 1500, + stream: true, + system: buildSystemPrompt(gameState.character, gameState.theme), + tools: [UPDATE_TOOL], + messages: apiMessages, + }; + + console.group(`🎲 DM API call #${loopIteration} (turn ${conversationHistory.length})`); + console.log('key:', keyHint); + console.log('messages:', apiMessages.length); + console.log('model:', requestBody.model); + console.log('secure context:', window.isSecureContext); + console.groupEnd(); + + let response; + try { + response = await fetch('https://api.anthropic.com/v1/messages', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'x-api-key': gameState.apiKey, + 'anthropic-version': '2023-06-01', + 'anthropic-dangerous-allow-browser': 'true', + }, + body: JSON.stringify(requestBody), + }); + } catch (fetchErr) { + // fetch() itself threw — almost always a CORS preflight failure or network issue + console.error('🔴 fetch() threw (CORS / network):', fetchErr); + throw new Error( + `Network error — could not reach Anthropic. Likely causes:\n` + + `• Invalid or revoked API key\n` + + `• No internet connection\n` + + `• CORS preflight blocked (check console)\n` + + `(${fetchErr.message})` + ); + } + + console.log(`↩ Response: HTTP ${response.status} ${response.statusText}`); if (!response.ok) { - const err = await response.json().catch(() => ({})); - throw new Error(err.error?.message || `API error ${response.status}`); + let errBody = {}; + try { errBody = await response.json(); } catch { /* CORS may block reading error body */ } + console.error('🔴 API error body:', errBody); + const msg = errBody.error?.message || errBody.message; + throw new Error( + msg + ? `Anthropic API error (${response.status}): ${msg}` + : `Anthropic returned HTTP ${response.status}. ` + + `Check your API key and account credits. (CORS may be hiding the full error — open Network tab)` + ); } const reader = response.body.getReader(); @@ -1685,6 +1719,7 @@ async function sendMessage(text, showAsPlayer = true) { let buf = ''; let blocks = {}; let stopReason = null; + let eventCount = 0; while (true) { const { done, value } = await reader.read(); @@ -1698,9 +1733,11 @@ async function sendMessage(text, showAsPlayer = true) { if (!line.startsWith('data: ')) continue; let data; try { data = JSON.parse(line.slice(6)); } catch { continue; } + eventCount++; if (data.type === 'content_block_start') { blocks[data.index] = { ...data.content_block, _buf: '' }; + console.log(` ▶ block_start [${data.index}] type=${data.content_block.type}`); } else if (data.type === 'content_block_delta') { const block = blocks[data.index]; if (!block) continue; @@ -1716,9 +1753,13 @@ async function sendMessage(text, showAsPlayer = true) { const block = blocks[data.index]; if (block?.type === 'tool_use') { try { block.input = JSON.parse(block._buf || '{}'); } catch { block.input = {}; } + console.log(` 🛠 tool_use: ${block.name}`, block.input); } } else if (data.type === 'message_delta') { stopReason = data.delta.stop_reason; + console.log(` ✓ message_delta stop_reason=${stopReason} events=${eventCount}`); + } else if (data.type === 'error') { + console.error(' 🔴 stream error event:', data); } } } @@ -1732,6 +1773,7 @@ async function sendMessage(text, showAsPlayer = true) { if (stopReason !== 'tool_use' || toolBlocks.length === 0) break; + console.log(` ↺ tool_use loop: adding tool_result and continuing`); const assistantContent = allBlocks.map(b => b.type === 'text' ? { type: 'text', text: b._buf } @@ -1755,9 +1797,12 @@ async function sendMessage(text, showAsPlayer = true) { finalizeDMMessage(dmEl, rawText); if (statUpdate) applyStatUpdate(statUpdate); conversationHistory.push({ role: 'assistant', content: rawText }); + console.log(`✅ Turn complete. History length: ${conversationHistory.length}`); } catch (err) { - dmEl.innerHTML = `<span style="color:#e74c3c">⚠️ ${err.message}</span>`; + console.error('🔴 sendMessage error:', err); + const lines = err.message.split('\n'); + dmEl.innerHTML = `<span style="color:#e74c3c">⚠️ ${lines.map(escHtml).join('<br>')}</span>`; conversationHistory.pop(); }