From 14c47ecd0187a35d50d7ec8d022459a597e00ab0 Mon Sep 17 00:00:00 2001 From: dschlueter Date: Wed, 20 May 2026 21:44:37 +0200 Subject: [PATCH] fix: sendAndWait-Retry + Judge-Server-Bereitschaftscheck vor Loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - sendAndWait(): fängt "Agent is already processing" mit exponentiellem Backoff ab (5 Versuche: 500ms, 1s, 2s, 4s). Race Condition zwischen waitForIdle() und sendUserMessage() wird damit toleriert. - /optimize: prüft Port 8002 vor dem Loop (20× alle 3s = max. 60s). Bei 503 "Loading model" wird gewartet statt sofort zu scheitern. Ist der Server nach 60s nicht erreichbar: Abbruch mit Hinweis. Co-Authored-By: Claude Sonnet 4.6 --- pi-coder-judge-extension.ts | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/pi-coder-judge-extension.ts b/pi-coder-judge-extension.ts index aa10824..f79cd24 100644 --- a/pi-coder-judge-extension.ts +++ b/pi-coder-judge-extension.ts @@ -389,14 +389,25 @@ async function switchModel( } // Sendet eine Nachricht und wartet bis der Agent fertig ist. -// Erst idle abwarten, dann als followUp einstellen — verhindert "Agent is already processing". +// Retry-Schleife fängt "Agent is already processing" ab — tritt auf wenn +// waitForIdle() zu früh zurückkehrt (Race Condition im pi-Agent). async function sendAndWait( pi: ExtensionAPI, ctx: ExtensionCommandContext, content: string ): Promise { await ctx.waitForIdle(); - pi.sendUserMessage(content, { deliverAs: "followUp" }); + for (let attempt = 1; attempt <= 5; attempt++) { + try { + pi.sendUserMessage(content, { deliverAs: "followUp" }); + break; + } catch (e: any) { + if (attempt === 5) throw e; + // Exponentieller Backoff: 500ms, 1s, 2s, 4s + await new Promise(r => setTimeout(r, 500 * Math.pow(2, attempt - 1))); + await ctx.waitForIdle(); + } + } await new Promise(r => setTimeout(r, 400)); await ctx.waitForIdle(); } @@ -738,6 +749,22 @@ export default function (pi: ExtensionAPI) { if (cancelRequested) { cancelRequested = false; finalNotify(ctx, "⛔ Abgebrochen", "Nach Implementierung"); return; } } + // Judge-Server-Bereitschaft prüfen — bei 503 (Modell lädt noch) bis zu 60s warten. + ctx.ui.setStatus("optimize", "Judge-Server wird geprüft…"); + let serverReady = false; + for (let i = 0; i < 20; i++) { + const hc = await pi.exec("bash", ["-c", + "curl -sf --max-time 3 http://localhost:8002/health || " + + "curl -sf --max-time 3 http://localhost:8002/v1/models" + ], { cwd: ctx.cwd }); + if (hc.code === 0) { serverReady = true; break; } + await new Promise(r => setTimeout(r, 3000)); + } + if (!serverReady) { + finalNotify(ctx, "⛔ Judge nicht erreichbar", "Port 8002 antwortet nicht — start-judge.sh ausführen"); + return; + } + // Test-Suiten einmalig ermitteln: --test-cmd überschreibt Auto-Erkennung. // Läuft nach Coder, damit neu angelegte Test-Dateien bereits erkannt werden. ctx.ui.setStatus("optimize", "Test-Suiten werden erkannt…");