diff --git a/services/hermes/setup_hermes.sh b/services/hermes/setup_hermes.sh index a6d1f7d..899c025 100644 --- a/services/hermes/setup_hermes.sh +++ b/services/hermes/setup_hermes.sh @@ -130,6 +130,14 @@ else docker exec -u node "${PAPERCLIP_CONTAINER}" hermes config set model.provider auto 2>/dev/null || true fi + # PaperClip Runtime-Patches anwenden (spawn E2BIG Fix für Hermes) + PATCH_SCRIPT="${SERVICES_DIR}/paperclip/patch_paperclip.js" + if [[ -f "${PATCH_SCRIPT}" ]]; then + log "Wende PaperClip-Patches im Container an (spawn E2BIG Fix)..." + docker cp "${PATCH_SCRIPT}" "${PAPERCLIP_CONTAINER}:/tmp/patch_paperclip.js" + docker exec -u root "${PAPERCLIP_CONTAINER}" node /tmp/patch_paperclip.js || true + fi + # Verifikation im Container log "Verifiziere Hermes im PaperClip-Container:" docker exec -u node "${PAPERCLIP_CONTAINER}" hermes --version 2>&1 || true diff --git a/services/paperclip/patch_paperclip.js b/services/paperclip/patch_paperclip.js new file mode 100644 index 0000000..e7126da --- /dev/null +++ b/services/paperclip/patch_paperclip.js @@ -0,0 +1,94 @@ +const fs = require('fs'); +const path = require('path'); + +console.log('[Patch PaperClip] Starting runtime patches...'); + +// --------------------------------------------------------------------------- +// 1. Fix Hermes E2BIG: Write prompt to --query-file instead of passing in argv +// --------------------------------------------------------------------------- +const hermesExecutePath = '/app/packages/adapters/hermes/src/server/execute.ts'; +if (fs.existsSync(hermesExecutePath)) { + let content = fs.readFileSync(hermesExecutePath, 'utf8'); + + // Replace "-q", prompt with --query-file + const oldArgs = 'const args: string[] = ["chat", "-q", prompt];'; + const newArgs = `const promptFile = path.join("/tmp", \`hermes-prompt-\${ctx.runId || Date.now()}.txt\`); + await fs.writeFile(promptFile, prompt, "utf-8"); + const args: string[] = ["chat", "--query-file", promptFile];`; + + if (content.includes(oldArgs)) { + content = content.replace(oldArgs, newArgs); + + // Add cleanup in finally block + const oldRun = ` const result = await runChildProcess(ctx.runId, hermesCmd, args, { + cwd, + env, + timeoutSec, + graceSec, + onLog: wrappedOnLog, + onSpawn: ctx.onSpawn, + });`; + + const newRun = ` let result; + try { + result = await runChildProcess(ctx.runId, hermesCmd, args, { + cwd, + env, + timeoutSec, + graceSec, + onLog: wrappedOnLog, + onSpawn: ctx.onSpawn, + }); + } finally { + await fs.unlink(promptFile).catch(() => {}); + }`; + + if (content.includes(oldRun)) { + content = content.replace(oldRun, newRun); + } + + fs.writeFileSync(hermesExecutePath, content, 'utf8'); + console.log('[Patch PaperClip] Successfully patched hermes execute.ts for --query-file (fixes spawn E2BIG)!'); + } else { + console.log('[Patch PaperClip] hermes execute.ts already patched or target pattern not found.'); + } +} + +// --------------------------------------------------------------------------- +// 2. Fix server-utils E2BIG: filter monster environment variables (>32KB) +// --------------------------------------------------------------------------- +const serverUtilsPath = '/app/packages/adapter-utils/src/server-utils.ts'; +if (fs.existsSync(serverUtilsPath)) { + let content = fs.readFileSync(serverUtilsPath, 'utf8'); + const oldEnvLoop = ` for (const [key, value] of Object.entries(childEnv)) { + if (value === undefined) delete childEnv[key]; + }`; + const newEnvLoop = ` for (const [key, value] of Object.entries(childEnv)) { + if (value === undefined || (typeof value === "string" && value.length > 32768)) delete childEnv[key]; + }`; + + if (content.includes(oldEnvLoop)) { + content = content.replace(oldEnvLoop, newEnvLoop); + fs.writeFileSync(serverUtilsPath, content, 'utf8'); + console.log('[Patch PaperClip] Successfully patched server-utils.ts to guard against env E2BIG!'); + } else { + console.log('[Patch PaperClip] server-utils.ts already patched or target pattern not found.'); + } +} + +// --------------------------------------------------------------------------- +// 3. Fix AI Connection endpoint for OpenRouter / custom base URLs +// --------------------------------------------------------------------------- +const aiConnPath = '/app/server/dist/routes/ai-connections.js'; +if (fs.existsSync(aiConnPath)) { + let content = fs.readFileSync(aiConnPath, 'utf8'); + const target = '"https://api.openai.com/v1/models"'; + const replacement = 'process.env.OPENAI_BASE_URL ? process.env.OPENAI_BASE_URL + "/models" : "https://api.openai.com/v1/models"'; + if (content.includes(target)) { + content = content.split(target).join(replacement); + fs.writeFileSync(aiConnPath, content, 'utf8'); + console.log('[Patch PaperClip] Successfully patched ai-connections.js for OPENAI_BASE_URL!'); + } +} + +console.log('[Patch PaperClip] All patches completed.'); diff --git a/services/paperclip/service.init b/services/paperclip/service.init index d968c04..6fd304b 100644 --- a/services/paperclip/service.init +++ b/services/paperclip/service.init @@ -26,14 +26,16 @@ notify() { } ############################################################################### -# 1. LLM-Validierungs-Endpunkt patchen (OpenRouter/Mistral Workaround) -# Verhindert, dass das Onboarding-UI OPENAI_BASE_URL ignoriert. +# 1. PaperClip Patches anwenden (spawn E2BIG Fix + LLM Validierung) ############################################################################### -log "Patching LLM validation endpoint in Paperclip container..." -docker exec -u root "${CONTAINER}" sed -i \ - 's|"https://api.openai.com/v1/models"|process.env.OPENAI_BASE_URL ? process.env.OPENAI_BASE_URL + "/models" : "https://api.openai.com/v1/models"|g' \ - /app/server/dist/routes/ai-connections.js || true -docker restart "${CONTAINER}" +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PATCH_SCRIPT="${SCRIPT_DIR}/patch_paperclip.js" +if [[ -f "${PATCH_SCRIPT}" ]]; then + log "Applying runtime patches to Paperclip container (fixes spawn E2BIG and AI validation)..." + docker cp "${PATCH_SCRIPT}" "${CONTAINER}:/tmp/patch_paperclip.js" + docker exec -u root "${CONTAINER}" node /tmp/patch_paperclip.js || warn "Patch script failed (non-fatal)" + docker restart "${CONTAINER}" +fi ############################################################################### # 2. Auf PaperClip warten