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 | 6eb999e2fafc7a9731155f69c696993dbf67da94 (patch) | |
| tree | a960304ff6d82ab6ed18a628d0c6208332bc2ddd | |
| parent | f50d8dcb7515e7f12cf80d04fed93f15b87c4102 (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>
| -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." }], |
