summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-24 23:47:13 +0200
committerPaul Buetow <paul@buetow.org>2026-03-24 23:47:13 +0200
commit9731b82818a2a199a8d826ae3e406c61572c2b6f (patch)
tree195b1d1e6fe42847fb7bd6fe2bce15398f95f8ce
parent9f45954847e7aa904ebda55e3c23277d7c7a3079 (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.ts24
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." }],