# Proxy Implementierungsanalyse ## Was der Proxy macht Übersetzt **Anthropic API** (`POST /v1/messages`) → **Ollama API** (`POST /api/chat`) - Empfängt Anthropic SSE-Format - Gibt Anthropic SSE-Format zurück - Routing: `localhost:11435` → `https://ollama.aquantico.de/api/chat` --- ## Korrekte Implementierungen ✓ ### 1. Model-Substitution (korrekt) ```js if (anthropicBody.model?.startsWith('claude-')) { anthropicBody.model = 'qwen3.6:35b-a3b-q4_K_M'; } ``` Alle `claude-*` Modelle werden durch das lokale Modell ersetzt. ### 2. Think-Modus deaktiviert (korrekt) ```js think: false ``` Hardcoded in `convertAnthropicToOllama()`. ### 3. Tool-Schema-Konvertierung (korrekt) Anthropic `input_schema` → Ollama `function.parameters`: ```js { type: 'function', function: { name, description, parameters: sanitizeToolSchema(tool.input_schema) } } ``` ### 4. Tool-Call-Parsing in Response (korrekt) Ollama gibt `tc.function.name` und `tc.function.arguments` zurück — genau das liest der Proxy: ```js const toolName = tc.function?.name; const toolInput = parseToolArguments(tc.function?.arguments); ``` ### 5. SSE-Event-Sequenz (korrekt) Ausgabe entspricht Anthropic-Spec: `message_start` → `content_block_start` → `content_block_delta` → `content_block_stop` → `message_delta` → `message_stop` ### 6. stop_reason (korrekt) ```js stop_reason: emittedToolUse ? 'tool_use' : 'end_turn' ``` ### 7. Tool-Deduplizierung (korrekt) Verhindert doppelte Tool-Calls via `seenToolCalls` Set mit Key `name:args`. --- ## Bekannte Bugs / Schwachstellen ⚠️ ### BUG 1: Leerer finaler Buffer-Handler (app.js:350-358) ```js if (buffer.trim()) { try { const data = JSON.parse(buffer.trim()); // gleichen Handling-Code wie oben ausführen ← LEER, nie ausgeführt! } catch (e) { ... } } ``` **Problem**: Wenn das letzte NDJSON-Chunk von Ollama nicht mit `\n` endet (was bei einigen Ollama-Versionen vorkommt), bleibt die finale `done: true`-Zeile im Buffer und wird nicht verarbeitet. **Auswirkung**: `messageFinished` bleibt `false`, Fallback-Code (Zeile 360-381) sendet die Abschluss-Events ohne `eval_count` (output_tokens=0). **Fix**: Den gleichen Parsing-Code aus der while-Schleife in den finalen Buffer-Handler kopieren. ### BUG 2: message_start ohne usage.input_tokens (app.js:200-209) ```js res.write(`event: message_start\ndata: ${JSON.stringify({ type: 'message_start', message: { id: messageId, type: 'message', role: 'assistant', content: [], model: anthropicBody.model // fehlt: stop_reason: null, usage: { input_tokens: 0, output_tokens: 0 } } })}\n\n`); ``` **Auswirkung**: Anthropic-kompatible Clients erwarten `usage.input_tokens` in `message_start`. Kann bei strikten Clients zu Parse-Fehlern führen. ### BUG 3: tool_use/tool_result als Text im Nachrichten-Verlauf Wenn Anthropic-Clients `tool_use` (in Assistant-Nachrichten) und `tool_result` (in User-Nachrichten) im History senden, werden diese als Text-Strings in den Ollama-Messages eingebettet: ``` "Previous assistant tool call already made.\nTool name: ...\n..." ``` **Korrekt wäre**: Assistant-Nachrichten mit `tool_calls` senden, Tool-Results als `role: "tool"` Nachricht. **Auswirkung**: Das Modell versteht den Tool-Call-Verlauf semantisch nicht korrekt. Die bestehende Deduplizierungs-Logik kompensiert dies teilweise. --- ## Architektur-Übersicht ``` Client (Claude SDK) │ POST /v1/messages (Anthropic Format) ▼ noThinkProxy :11435 │ convertAnthropicToOllama() │ - system → messages[0] role:system │ - tool_use → text string │ - tool_result → text string │ - model: claude-* → qwen3.6:35b-a3b-q4_K_M │ - think: false │ - options: { num_ctx:131072, num_predict, temperature:0.7 } │ │ POST /api/chat (Ollama NDJSON) ▼ Ollama https://ollama.aquantico.de │ NDJSON stream: {message:{content, tool_calls}, done} ▼ noThinkProxy │ handleResponse() │ - text → content_block_delta (text_delta) │ - tool_calls → content_block_start/delta/stop (tool_use) │ - done → message_delta + message_stop ▼ Client (Anthropic SSE) ```