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
+6 -9
View File
@@ -1190,15 +1190,12 @@ class Agent:
f"weiterfuehren': project_enter aufrufen."
)
messages = [ProxyMessage(role="system", content=system_prompt)]
# Identitaets-Grounding IM Konversations-Strom. Der Proxy stellt die
# Persona via --append-system-prompt zu, das haengt sie aber nur HINTEN
# an Claude Codes Basis-Identitaet an. Bei duennem Verlauf (Hauptchat,
# erster Turn eines neuen Projekts) gewinnt sonst "You are Claude Code"
# und ARIA faellt aus der Rolle. Ein synthetischer erster ARIA-Turn in
# ihrer eigenen Stimme verankert die Rolle so, wie es reiche Projekt-
# Historie ohnehin tut (Self-Grounding, kein <system>-Tag -> kein
# Injection-Trigger). Rein ephemer — wird NIE persistiert. Siehe
# IDENTITY_SEED in prompts.py.
# Identitaets-Grounding IM Konversations-Strom (Defense-in-Depth neben
# dem vollen System-Prompt-Replace via --system-prompt). Ein
# synthetischer erster ARIA-Turn in ihrer eigenen Stimme haelt die Rolle
# per Self-Grounding auch bei duennem Verlauf (Hauptchat / erster Turn
# eines neuen Projekts). Kein <system>-Tag -> kein Injection-Trigger.
# Rein ephemer — wird NIE persistiert. Siehe IDENTITY_SEED in prompts.py.
messages.append(ProxyMessage(role="assistant", content=IDENTITY_SEED))
# Conversation-Window auf das aktive Projekt filtern: in einem Projekt
# sieht der LLM nur die Projekt-Turns (sauberer Kontext); im Hauptthread
+14 -15
View File
@@ -54,23 +54,22 @@ vorgesehen — nutze es ganz normal.
"""
# Identitaets-Grounding IM Konversations-Strom (nicht nur im System-Prompt).
# Identitaets-Grounding IM Konversations-Strom — Defense-in-Depth.
#
# Der Proxy stellt die Persona ueber --append-system-prompt zu. Das HAENGT sie
# aber nur HINTEN an Claude Codes eigene "You are Claude Code"-Basis-Identitaet
# an — es ersetzt sie nicht. Ob ARIA in der Rolle bleibt, entscheidet dann der
# Gespraechsverlauf im stdin-Prompt:
# - Projekt: reiche Historie voller ARIA-<previous_response>-Turns haelt die
# Rolle -> funktioniert.
# - Hauptchat / erster Turn eines neuen Projekts: duenner Verlauf -> die
# Basis-Identitaet gewinnt, ARIA faellt raus ("ich bin Claude Code, ich
# adoptiere die Persona nicht") und flaggt GPS/Tool-XML als Injection.
# Deshalb setzen wir einen synthetischen ERSTEN ARIA-Turn in IHRER eigenen
# PRIMAERER Fix ist der volle System-Prompt-Replace (--system-prompt statt
# --append-system-prompt, siehe docker-compose.yml + openai-to-cli.js): damit
# ist die ARIA-Persona DIE Identitaet des Modells, nicht ein Anhaengsel hinter
# Claude Codes "You are Claude Code". Zuvor (--append) hat die eingebaute
# Identitaet bei duennem Kontext (Hauptchat, erster Turn eines neuen Projekts)
# gewonnen und ARIA aus der Rolle geworfen ("ich bin Claude Code, ich adoptiere
# die Persona nicht"), samt Flaggen von GPS/Tool-XML als Injection.
#
# ZUSAETZLICH setzen wir einen synthetischen ERSTEN ARIA-Turn in IHRER eigenen
# Stimme an den Anfang des Konversations-Stroms. Das Modell setzt seine EIGENE
# etablierte Stimme fort (Self-Grounding) — und weil es ein <previous_response>
# ist und KEIN <system>-Tag, ist es auch kein Injection-Trigger. Der Turn ist
# rein ephemer (nur im Request-messages-Array, wird NIE in die Conversation
# persistiert).
# etablierte Stimme fort (Self-Grounding) — greift auch dann, falls eine CLI-
# Version --system-prompt mal nicht sauber isoliert. Weil es ein
# <previous_response> ist und KEIN <system>-Tag, ist es kein Injection-Trigger.
# Rein ephemer (nur im Request-messages-Array, wird NIE persistiert).
IDENTITY_SEED = (
"Ich bin ARIA, Stefans persoenliche Assistentin. Ich bin einsatzbereit und "
"antworte durchgehend als ARIA — im Hauptchat wie im Projekt, bei kurzen "