fix(proxy): ARIA-Persona als VOLLER System-Prompt-Replace (--system-prompt)

Der Self-Grounding-Ansatz (268636c) allein reichte nicht: Sonnet 5 in Claude
Code haelt seine eingebaute "You are Claude Code"-Identitaet hart und liest den
synthetischen <previous_response> als "fabricated". Ursache bleibt der Kanal:
--append-system-prompt HAENGT ARIAs Persona nur hinten an Claude Codes Basis-
Identitaet an — bei duennem Kontext (Hauptchat) gewinnt die Basis und wehrt die
Persona als Injection ab. Anhaengen ist gegen das Anti-Injection-Training des
Modells nicht durchsetzbar.

Fix: System-Prompt VOLL ersetzen statt anhaengen — sed-Patch in docker-compose
schaltet manager.js buildArgs von --append-system-prompt auf --system-prompt.
Damit ist die ARIA-Persona DIE Identitaet des Modells (kein Anhaengsel), und
Claude Codes dynamische Sektionen (cwd '/', git, platform) — die "ich bin ein
Coding-Agent"-Signale — fallen weg. Bestaetigt per claude-code-guide: die CLI
isoliert bei --system-prompt vollstaendig, die eingebaute Identitaet leakt nicht.

extractSystemPrompt liefert weiterhin einen selbsttragenden Prompt (Persona +
Anker + Memory + Skills + Tool-Block); er darf bei --system-prompt nie leer sein
(Brain schickt immer System-Message + Tools -> real nie leer). Der IDENTITY_SEED
aus 268636c bleibt als Defense-in-Depth drin. Kommentare in openai-to-cli.js,
routes.js, agent.py, prompts.py entsprechend nachgezogen.

Deploy: Proxy UND Brain neu (--force-recreate; routes.js/openai-to-cli.js werden
frisch in den Proxy-Container ge-cp't). Verifikation am Container:
docker exec aria-proxy sh -c 'grep -o "\-\-system-prompt" /usr/local/lib/*/claude-max-api-proxy/dist/subprocess/manager.js'

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-10 22:44:02 +02:00
co-authored by Claude Opus 4.8
parent 268636c030
commit 2284c1a780
5 changed files with 37 additions and 35 deletions
+14 -8
View File
@@ -153,9 +153,12 @@ export function messagesToPrompt(messages, tools) {
/**
* Extrahiert NUR den System-Anteil (System-Messages + Tool-Use-Block) als
* rohen Text — OHNE <system>-Tags. Fuer den ECHTEN System-Prompt-Kanal der
* Claude-CLI (--append-system-prompt), damit die ARIA-Persona nicht als
* <system>-getaggter User-Content ankommt (den das Modell als Injection wertet),
* sondern als genuine System-Instruktion.
* Claude-CLI (--system-prompt, VOLLER Replace — nicht --append). Damit ist
* die ARIA-Persona DIE Identitaet des Modells und nicht ein Anhaengsel hinter
* Claude Codes eigener "You are Claude Code"-Identitaet (die bei duennem
* Kontext sonst gewinnt und die Persona als Injection abwehrt). Der Output
* muss deshalb SELBSTTRAGEND sein — er ersetzt Claude Codes System-Prompt
* komplett inkl. dynamischer Sektionen (cwd, git, platform).
* Reihenfolge: erst der Tool-Use-Block (Format-Anweisung), dann die
* System-Messages in Original-Reihenfolge.
*/
@@ -217,12 +220,15 @@ export function conversationToPrompt(messages) {
export function openaiToCli(request) {
// Persona/System + Tool-Block gehen ueber den ECHTEN System-Prompt-Kanal
// (--append-system-prompt, siehe manager.js buildArgs-Patch). Der Prompt
// enthaelt nur noch den Gespraechsverlauf — so kann das Modell die
// ARIA-Vorgaben nicht mehr als <system>-getaggten User-Content und damit als
// Prompt-Injection fehldeuten.
// (--system-prompt = VOLLER Replace, siehe manager.js buildArgs-Patch in
// docker-compose.yml). Der Prompt enthaelt nur noch den Gespraechsverlauf.
// Voller Replace statt --append, weil Anhaengen Claude Codes eingebaute
// "You are Claude Code"-Identitaet stehen laesst — die bei duennem Kontext
// (Hauptchat) gewinnt und die ARIA-Persona als Injection abwehrt.
// systemPrompt ist immer ein String (extractSystemPrompt liefert "" statt
// undefined) → --append-system-prompt "" ist harmlos, kein spawn-Crash.
// undefined). ACHTUNG: bei --system-prompt darf er NIE leer sein, sonst
// laeuft das Modell ganz ohne System-Prompt — der Brain schickt aber immer
// eine System-Message + Tool-Block, also ist er real nie leer.
return {
prompt: conversationToPrompt(request.messages),
systemPrompt: extractSystemPrompt(request.messages, request.tools),
+2 -2
View File
@@ -363,8 +363,8 @@ async function handleStreamingResponse(req, res, subprocess, cliInput, requestId
model: cliInput.model,
sessionId: cliInput.sessionId,
// ARIA: echter System-Prompt-Kanal — manager.js reicht das (sobald
// gepatcht) als --append-system-prompt an die CLI. Aktuell ignoriert
// ein ungepatchter manager diese Extra-Option gefahrlos.
// gepatcht) als --system-prompt (VOLLER Replace) an die CLI. Aktuell
// ignoriert ein ungepatchter manager diese Extra-Option gefahrlos.
systemPrompt: cliInput.systemPrompt,
}).catch((err) => {
console.error("[Streaming] Subprocess start error:", err);