From 36641e6519239f7a0be6c923116b4128052a32f2 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Wed, 30 Sep 2026 10:58:45 +0200 Subject: [PATCH] =?UTF-8?q?fix(proxy):=20'spawn=20E2BIG'=20=E2=80=94=20Sys?= =?UTF-8?q?tem-Prompt=20ueber=20Datei=20statt=20Kommandozeile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gefunden ueber die Brain-Logs: mehrere Nachrichten blieben unbeantwortet, weil POST /chat mit 502 endete. Ursache: Proxy HTTP 500: {"error":{"message":"spawn E2BIG"}} execve() begrenzt argv+envp ZUSAMMEN auf ARG_MAX — im Proxy-Container nur 131072 Bytes (getconf ARG_MAX). Der System-Prompt wurde als einzelnes Argument uebergeben und war im Fehlerfall 76881 Zeichen gross (gepinnte Erinnerungen + Skills + Projektkontext) -> Start scheitert, Turn verloren, App bekommt 502. 11 solcher Faelle im aktuellen Log. Fix: --system-prompt-file statt --system-prompt (die CLI unterstuetzt das). Damit faellt die Groessengrenze praktisch weg. Die Temp-Datei wird bei close/error/catch wieder entfernt; schlaegt das Schreiben fehl, wird wie bisher das Argument genutzt (kleine Prompts laufen weiter). Co-Authored-By: Claude Opus 4.8 --- proxy-patches/manager.js | 44 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/proxy-patches/manager.js b/proxy-patches/manager.js index 2ad1181..0decebb 100644 --- a/proxy-patches/manager.js +++ b/proxy-patches/manager.js @@ -18,6 +18,9 @@ */ import { spawn } from "child_process"; import { EventEmitter } from "events"; +import fs from "fs"; +import os from "os"; +import path from "path"; import { isAssistantMessage, isResultMessage, isContentDelta } from "../types/claude-cli.js"; const DEFAULT_TIMEOUT = 86400000; // 24h — lange Agent-Loops (Pentests etc.) export class ClaudeSubprocess extends EventEmitter { @@ -26,6 +29,8 @@ export class ClaudeSubprocess extends EventEmitter { timeoutId = null; isKilled = false; _stdinClosed = false; + _systemPromptFile = null; + _systemPromptDir = null; /** * Start the Claude CLI subprocess with the given prompt */ @@ -51,6 +56,7 @@ export class ClaudeSubprocess extends EventEmitter { // Handle spawn errors (e.g., claude not found) this.process.on("error", (err) => { this.clearTimeout(); + this._cleanupSystemPrompt(); if (err.message.includes("ENOENT")) { reject(new Error("Claude CLI not found. Install with: npm install -g @anthropic-ai/claude-code")); } @@ -85,6 +91,7 @@ export class ClaudeSubprocess extends EventEmitter { this.process.on("close", (code) => { console.error(`[Subprocess] Process closed with code: ${code}`); this.clearTimeout(); + this._cleanupSystemPrompt(); // Process any remaining buffer if (this.buffer.trim()) { this.processBuffer(); @@ -96,6 +103,7 @@ export class ClaudeSubprocess extends EventEmitter { } catch (err) { this.clearTimeout(); + this._cleanupSystemPrompt(); reject(err); } }); @@ -114,13 +122,47 @@ export class ClaudeSubprocess extends EventEmitter { "stream-json", // ARIA: User-Messages via stdin (Zwischenruf) "--model", options.model, // Model alias (opus/sonnet/haiku) - "--no-session-persistence", "--dangerously-skip-permissions", "--system-prompt", options.systemPrompt, "--safe-mode", + "--no-session-persistence", "--dangerously-skip-permissions", "--safe-mode", ]; + // ARIA: System-Prompt ueber eine DATEI statt als Kommandozeilen-Argument. + // Grund: execve() begrenzt argv+envp zusammen auf ARG_MAX — im Container + // nur 128 KiB. Ein gewachsener System-Prompt (gepinnte Erinnerungen, + // Skills, Projektkontext; real gesehen ~77k Zeichen) sprengte das und der + // Start brach mit "spawn E2BIG" ab: der Turn ging verloren, die App bekam + // 502 und die Nachricht blieb unbeantwortet. Ueber die Datei gibt es + // praktisch keine Groessengrenze mehr. + this._systemPromptFile = null; + const sysPrompt = options.systemPrompt || ""; + if (sysPrompt) { + try { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "aria-sysprompt-")); + const file = path.join(dir, "system-prompt.txt"); + fs.writeFileSync(file, sysPrompt, "utf-8"); + this._systemPromptFile = file; + this._systemPromptDir = dir; + args.push("--system-prompt-file", file); + } + catch (err) { + // Notfalls wie bisher (kleine Prompts funktionieren so weiterhin). + console.error(`[Subprocess] System-Prompt-Datei fehlgeschlagen (${err.message}) — nutze Argument`); + args.push("--system-prompt", sysPrompt); + } + } if (options.sessionId) { args.push("--session-id", options.sessionId); } return args; } + /** Temporaere System-Prompt-Datei wieder entfernen. */ + _cleanupSystemPrompt() { + try { + if (this._systemPromptFile) + fs.rmSync(this._systemPromptDir || this._systemPromptFile, { recursive: true, force: true }); + } + catch (_) { } + this._systemPromptFile = null; + this._systemPromptDir = null; + } /** * Eine User-Message im stream-json-Input-Format an stdin schreiben. * Genutzt fuer den initialen Prompt UND fuer Zwischenrufe (sendMessage).