From 4a4dfc8b4335e7d9b695023e9f93c64d1fb9e2e5 Mon Sep 17 00:00:00 2001 From: Yician Wang Date: Fri, 10 Jul 2026 00:07:47 +0800 Subject: [PATCH 1/2] fix(pi): avoid stale ctx.ui after async health check refreshStatus awaited getHealth() then accessed ctx.ui.setStatus. If the pi session was replaced or reloaded during that await, the extension context is invalidated and assertActive throws: This extension ctx is stale after session replacement or reload Capture setStatus while ctx is still active, and treat post-await status updates as best-effort. AI-Agent: Pi AI-Session-IDs: current --- integrations/pi/index.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/integrations/pi/index.ts b/integrations/pi/index.ts index 9c6cfc702..a2154bdf6 100644 --- a/integrations/pi/index.ts +++ b/integrations/pi/index.ts @@ -129,9 +129,23 @@ export default function agentmemoryExtension(pi: ExtensionAPI) { } async function refreshStatus(ctx: { ui: { setStatus: (key: string, text: string) => void } }) { + // Capture the setter while ctx is still active. After await getHealth(), the + // session may have been replaced/reloaded and ctx.ui would throw stale. + let setStatus: ((key: string, text: string) => void) | undefined; + try { + setStatus = ctx.ui.setStatus.bind(ctx.ui); + } catch { + return; + } + const health = await getHealth(); lastHealthOk = !!health && (health.status === "healthy" || health.health?.status === "healthy"); - ctx.ui.setStatus("agentmemory", lastHealthOk ? "🧠 agentmemory" : "🧠 agentmemory off"); + + try { + setStatus("agentmemory", lastHealthOk ? "🧠 agentmemory" : "🧠 agentmemory off"); + } catch { + // UI may already be gone after session replacement; status is best-effort. + } } pi.registerCommand("agentmemory-status", { From 3f877020ea223398a33e625c82fbadc8596a3102 Mon Sep 17 00:00:00 2001 From: Yician Wang Date: Fri, 10 Jul 2026 00:16:15 +0800 Subject: [PATCH 2/2] fix(pi): capture ui once before binding setStatus Address review feedback: avoid reading ctx.ui twice when capturing the status setter. Bind from a single local ui reference. AI-Agent: Pi AI-Session-IDs: current --- integrations/pi/index.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/integrations/pi/index.ts b/integrations/pi/index.ts index a2154bdf6..a9cc98100 100644 --- a/integrations/pi/index.ts +++ b/integrations/pi/index.ts @@ -131,9 +131,10 @@ export default function agentmemoryExtension(pi: ExtensionAPI) { async function refreshStatus(ctx: { ui: { setStatus: (key: string, text: string) => void } }) { // Capture the setter while ctx is still active. After await getHealth(), the // session may have been replaced/reloaded and ctx.ui would throw stale. - let setStatus: ((key: string, text: string) => void) | undefined; + let setStatus: (key: string, text: string) => void; try { - setStatus = ctx.ui.setStatus.bind(ctx.ui); + const ui = ctx.ui; + setStatus = ui.setStatus.bind(ui); } catch { return; }