diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-24 23:47:13 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-24 23:47:13 +0200 |
| commit | 9731b82818a2a199a8d826ae3e406c61572c2b6f (patch) | |
| tree | 195b1d1e6fe42847fb7bd6fe2bce15398f95f8ce /pi | |
| parent | 9f45954847e7aa904ebda55e3c23277d7c7a3079 (diff) | |
reload-runtime: fix reload loop by calling ctx.reload() directly
The tool previously used pi.sendUserMessage("/reload-runtime", { deliverAs: "followUp" }),
which injected a user message that started a new AI turn and could cause the agent to
call reload_runtime again — resulting in a loop. Now the tool calls ctx.reload() directly
via a captured lastCtx, avoiding any follow-up message. Also tightened the tool description
to discourage repeated calls in the same turn.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'pi')
| -rw-r--r-- | pi/agent/extensions/reload-runtime/index.ts | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/pi/agent/extensions/reload-runtime/index.ts b/pi/agent/extensions/reload-runtime/index.ts index ebe6b7f..aceeddc 100644 --- a/pi/agent/extensions/reload-runtime/index.ts +++ b/pi/agent/extensions/reload-runtime/index.ts @@ -1,10 +1,19 @@ -import type { ExtensionAPI } from "@mariozechner/pi-coding-agent"; +import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent"; import { Type } from "@sinclair/typebox"; export default function (pi: ExtensionAPI) { + // Capture ctx so the tool can call ctx.reload() directly, avoiding a + // follow-up user message that would re-trigger the AI and cause a reload loop. + let lastCtx: ExtensionContext | undefined; + + pi.on("session_start", async (_event, ctx) => { + lastCtx = ctx; + }); + pi.registerCommand("reload-runtime", { description: "Reload extensions, skills, prompts, and themes", handler: async (_args, ctx) => { + lastCtx = ctx; await ctx.reload(); return; }, @@ -13,9 +22,20 @@ export default function (pi: ExtensionAPI) { pi.registerTool({ name: "reload_runtime", label: "Reload Runtime", - description: "Reload extensions, skills, prompts, and themes", + // Explicit single-use guidance prevents the AI from calling this in a loop. + description: "Reload extensions, skills, prompts, and themes. Call this once after editing extension files. Do not call it again in the same turn.", parameters: Type.Object({}), async execute() { + if (lastCtx) { + // Direct reload via ctx avoids injecting a follow-up user message, + // which would start a new AI turn and risk a reload loop. + await lastCtx.reload(); + return { + content: [{ type: "text", text: "Runtime reloaded." }], + details: {}, + }; + } + // Fallback if ctx is not yet available (should not happen in practice). pi.sendUserMessage("/reload-runtime", { deliverAs: "followUp" }); return { content: [{ type: "text", text: "Queued /reload-runtime as a follow-up command." }], |
