fix: Resolve spawn E2BIG by passing Hermes prompt via --query-file
Linux execve limits arguments to 128KB, causing Paperclip to fail with spawn E2BIG on large prompts. Adds runtime patch to write prompt to /tmp/hermes-prompt-*.txt and pass via Hermes native --query-file flag, while cleaning up file after execution and filtering oversized env vars.
This commit is contained in:
1 parent
f4d8b10dfb
commit
ee101b4a73
3 files changed
+111
-7
No files matched your search
@@ -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
|
||||
|
||||
@@ -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.');
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user