fix(proxy): Streaming-Pfad parst <tool_call>-Tags nie -> Tool-Calls wirkungslos

Root Cause (verifiziert am echten npm-Paket claude-max-api-proxy@dist):
handleStreamingResponse() in server/routes.js baut SSE-Chunks komplett
inline aus den rohen content_delta-Tokens und ruft dabei NIE den
<tool_call name="X">{json}</tool_call>-Parser aus adapter/cli-to-openai.js
auf (_parseToolCalls / cliResultToOpenai) -- der laeuft bisher nur im
Non-Streaming-Pfad (handleNonStreamingResponse). Hermes fragt aber immer
mit stream:true an. Folge: Claude gibt die Tool-Call-Tags korrekt als Text
aus (das hatten wir zuletzt gefixt), aber sie kommen nie als echtes OpenAI
tool_calls[]-Array bei Hermes an -- kein Tool wird ausgefuehrt, kein
Ergebnis geht zurueck in die Session, Claude haeuft neue <tool_call>-
Bloecke an weil nie eine Antwort kommt ("es passiert nicht viel", vier
Tags in einer Antwort).

Bisher gab's fuer routes.js nur einen minimalen sed-Patch (systemPrompt
durchreichen), bewusst ohne ARIAs vollen routes.js-Patch (der haengt an
ARIA-Bridge-spezifischen Extras wie Killswitch/Live-Stream). Der Fehler
sitzt aber strukturell in handleStreamingResponse selbst, sed reicht nicht
mehr.

Fix: proxy-patches/routes.js -- eigene schlanke Variante ohne Bridge-
Extras, komplett per cp ersetzt statt sed. handleStreamingResponse
streamt keine rohen Tokens mehr live, sondern wartet auf das volle
"result"-Event und baut daraus per cliResultToOpenai() (dieselbe Logik
wie Non-Streaming) den finalen Chunk inkl. tool_calls[]/finish_reason.
Kostet den Live-Tipp-Effekt, aber Tool-Calls funktionieren jetzt
ueberhaupt erst. systemPrompt-Fix ist in der neuen Datei bereits
enthalten (ersetzt den alten sed dafuer).

Lokal verifiziert: node --check auf der neuen Datei, und
cliResultToOpenai() gegen Stefans exakten Beispiel-Text (vier
zusammenhaengende <tool_call>-Tags) getestet -- liefert korrekt 4
tool_calls + finish_reason=tool_calls.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
ARIA
2026-07-20 07:55:55 +00:00
co-authored by Claude Sonnet 5
parent e00b406e23
commit 4710e4071b
2 changed files with 306 additions and 7 deletions
+19 -7
View File
@@ -60,12 +60,24 @@ services:
# - cli-to-openai.js: parsed genau dieses Format aus Claudes Antwort
# wieder raus und baut daraus OpenAI-konforme tool_calls[]
#
# BEWUSST NICHT uebernommen: ARIAs routes.js-Patch. Der haengt zusaetzlich
# an aria-bridge:8090 (Live-Tool-Stream + Not-Aus-Killswitch) und liest
# /shared/config/models.json — beides ARIA-Bridge-spezifisch. Hier laeuft
# die NPM-Stock-Version von routes.js (macht die Kern-Route trotzdem,
# nur ohne die Bridge-Extras). Falls Hermes spaeter auch Live-Stream/
# Killswitch braucht: sag Bescheid, dann bauen wir das nach.
# ARIAs routes.js-Patch wurde bewusst NICHT 1:1 uebernommen (haengt
# zusaetzlich an aria-bridge:8090 fuer Live-Tool-Stream + Not-Aus-
# Killswitch sowie /shared/config/models.json — beides ARIA-Bridge-
# spezifisch, hier nicht vorhanden).
#
# ABER: proxy-patches/routes.js (eigene, schlanke Variante ohne Bridge-
# Extras) ist inzwischen Pflicht, kein reiner sed-Patch mehr moeglich.
# Grund: die NPM-Stock-Version von handleStreamingResponse() baut SSE-
# Chunks komplett inline und ruft NIE den <tool_call>-Parser aus
# cli-to-openai.js auf (der laeuft nur im Non-Streaming-Pfad). Hermes
# nutzt aber immer stream:true -> Claude gibt <tool_call name="...">
# {...}</tool_call> brav als Text aus, aber es kommt nie als echtes
# OpenAI tool_calls[] an, wird nie ausgefuehrt, Claude haeuft neue
# Calls an weil nie ein Ergebnis zurueckkommt ("es passiert nicht viel").
# proxy-patches/routes.js wartet deshalb im Streaming-Pfad auf das volle
# "result"-Event und jagt es durch dieselbe cliResultToOpenai()-Logik
# wie der Non-Streaming-Pfad (kostet den Live-Tipp-Effekt, aber Tool-
# Calls funktionieren). Enthaelt den systemPrompt-Fix bereits mit.
hermes-proxy:
image: node:22-alpine
container_name: hermes-proxy
@@ -79,9 +91,9 @@ services:
sed -i 's/const DEFAULT_TIMEOUT = 300000;/const DEFAULT_TIMEOUT = 86400000;/' $$DIST/subprocess/manager.js &&
sed -i '/prompt, \\/\\/ Pass prompt as argument/d' $$DIST/subprocess/manager.js &&
sed -i 's|this\\.process\\.stdin?\\.end();|this.process.stdin?.end(prompt);|' $$DIST/subprocess/manager.js &&
sed -i 's/model: cliInput\\.model,/model: cliInput.model, systemPrompt: cliInput.systemPrompt,/' $$DIST/server/routes.js &&
cp /proxy-patches/openai-to-cli.js $$DIST/adapter/openai-to-cli.js &&
cp /proxy-patches/cli-to-openai.js $$DIST/adapter/cli-to-openai.js &&
cp /proxy-patches/routes.js $$DIST/server/routes.js &&
claude-max-api"
volumes:
# WICHTIG: eigenes, von ARIA getrenntes Volume fuer die Claude-CLI-Session.