diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-07-21 05:18:26 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-07-21 05:18:26 +0300 |
| commit | 44f2211608618e56d4bd80ef9c2bac4d9c8be4d2 (patch) | |
| tree | 9693da37f79634a832f450989c36f577797d10c6 /src/integration/assets/pi | |
| parent | 1f2487554b9fd42118f9e99ee06eb558bbb2391f (diff) | |
fix: use pi settled lifecycle event
Diffstat (limited to 'src/integration/assets/pi')
| -rw-r--r-- | src/integration/assets/pi/herdr-agent-state.ts | 118 |
1 files changed, 4 insertions, 114 deletions
diff --git a/src/integration/assets/pi/herdr-agent-state.ts b/src/integration/assets/pi/herdr-agent-state.ts index 218cede9..caa50ed9 100644 --- a/src/integration/assets/pi/herdr-agent-state.ts +++ b/src/integration/assets/pi/herdr-agent-state.ts @@ -61,10 +61,6 @@ type QueuedState = { seq: number; }; -const idleDebounceMs = parseDurationEnv("HERDR_PI_IDLE_DEBOUNCE_MS", 250); -const retryGraceMs = parseDurationEnv("HERDR_PI_RETRY_GRACE_MS", 2500); -const retryableErrorPattern = - /overloaded|provider.?returned.?error|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|network.?error|connection.?error|connection.?refused|connection.?lost|websocket.?closed|websocket.?error|other side closed|fetch failed|upstream.?connect|reset before headers|socket hang up|ended without|http2 request did not get a response|timed? out|timeout|terminated|retry delay/i; let reportSeq = Date.now() * 1000; let currentAgentSessionId: string | undefined; let currentAgentSessionPath: string | undefined; @@ -74,18 +70,6 @@ function nextReportSeq(): number { return reportSeq; } -function parseDurationEnv(name: string, fallback: number): number { - const raw = process.env[name]; - if (!raw) { - return fallback; - } - const parsed = Number.parseInt(raw, 10); - if (!Number.isFinite(parsed) || parsed < 0) { - return fallback; - } - return parsed; -} - function updateSessionRef(ctx: any): void { try { const file = ctx?.sessionManager?.getSessionFile?.(); @@ -211,74 +195,23 @@ async function drainStateQueue(): Promise<void> { } } -function lastAssistantMessage(messages: unknown[]): any | undefined { - for (let i = messages.length - 1; i >= 0; i -= 1) { - const message = messages[i] as any; - if (message?.role === "assistant") { - return message; - } - } - return undefined; -} - -function retryableErrorMessage(event: any): string | undefined { - const messages = Array.isArray(event?.messages) ? event.messages : []; - const assistant = lastAssistantMessage(messages); - if (assistant?.stopReason !== "error") { - return undefined; - } - - const errorMessage = String(assistant.errorMessage ?? ""); - if (!retryableErrorPattern.test(errorMessage)) { - return undefined; - } - return errorMessage || "retryable provider error"; -} - export default function (pi) { if (!enabled()) { return; } let agentActive = false; - let retryHoldActive = false; - let failureBlocked = false; - let failureMessage: string | undefined; let blockedCount = 0; let blockedMessage: string | undefined; let lastState: AgentState | undefined; let lastMessage: string | undefined; - let idleTimer: ReturnType<typeof setTimeout> | undefined; - let retryTimer: ReturnType<typeof setTimeout> | undefined; let rootSession = false; - function clearTimer(timer: ReturnType<typeof setTimeout> | undefined) { - if (timer) { - clearTimeout(timer); - } - } - - function clearPendingTimers() { - clearTimer(idleTimer); - clearTimer(retryTimer); - idleTimer = undefined; - retryTimer = undefined; - } - - function clearFailureState() { - retryHoldActive = false; - failureBlocked = false; - failureMessage = undefined; - } - function desiredState() { if (blockedCount > 0) { return { state: "blocked" as const, message: blockedMessage }; } - if (failureBlocked) { - return { state: "blocked" as const, message: failureMessage }; - } - if (agentActive || retryHoldActive) { + if (agentActive) { return { state: "working" as const, message: undefined }; } return { state: "idle" as const, message: undefined }; @@ -294,32 +227,6 @@ export default function (pi) { queueState(next.state, next.message); } - function scheduleIdle() { - clearPendingTimers(); - clearFailureState(); - idleTimer = setTimeout(() => { - idleTimer = undefined; - publishState(); - }, idleDebounceMs); - idleTimer.unref?.(); - } - - function holdForRetry(message: string) { - clearPendingTimers(); - retryHoldActive = true; - failureBlocked = false; - failureMessage = message; - publishState(); - - retryTimer = setTimeout(() => { - retryTimer = undefined; - retryHoldActive = false; - failureBlocked = true; - publishState(); - }, retryGraceMs); - retryTimer.unref?.(); - } - pi.events.on("herdr:blocked", (data) => { if (!rootSession) { return; @@ -333,7 +240,6 @@ export default function (pi) { return; } - clearPendingTimers(); blockedCount += 1; blockedMessage = data.label; publishState(); @@ -357,39 +263,23 @@ export default function (pi) { } updateSessionRef(ctx); void reportSession(); - clearPendingTimers(); - clearFailureState(); agentActive = true; publishState(); }); - pi.on("agent_end", (event) => { - if (!rootSession) { - return; - } - if (!agentActive) { - // Pi can emit duplicate/late end events while auto-retry is already - // holding the pane in Working. Do not let an unqualified duplicate end - // cancel the retry hold and publish a false Idle. + pi.on("agent_settled", (_event, ctx) => { + if (!rootSession || ctx?.isIdle?.() !== true) { return; } agentActive = false; - - const retryableMessage = retryableErrorMessage(event); - if (retryableMessage) { - holdForRetry(retryableMessage); - return; - } - - scheduleIdle(); + publishState(); }); pi.on("session_shutdown", async (event) => { if (!rootSession) { return; } - clearPendingTimers(); if (shouldReleaseOnSessionShutdown(event)) { await releaseAgent(); } |
