From e49d4128c2f546b9f55e8e0a84ce57dc2de0cd92 Mon Sep 17 00:00:00 2001 From: dingtalk_jaepyd Date: Thu, 21 May 2026 19:44:10 +0800 Subject: [PATCH] loop: add reload_runtime tool and auto-resume on /reload When running a loop that modifies extension files, the agent previously had no way to trigger reload. After a manual /reload, the loop state was restored but the loop did not resume automatically. This adds: - reload_runtime tool: LLM-callable, queues "/reload-runtime" as followUp - reload-runtime command: executes ctx.reload() (only available in CommandContext) - Auto-resume: on session_start with reason="reload" and active loop, resume The LLM can now modify extensions during a loop, trigger reload, and the loop automatically continues with the new code loaded. --- extensions/loop.ts | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/extensions/loop.ts b/extensions/loop.ts index 343e53d..29f1246 100644 --- a/extensions/loop.ts +++ b/extensions/loop.ts @@ -337,6 +337,22 @@ export default function loopExtension(pi: ExtensionAPI): void { }, }); + // LLM-callable reload tool. Tools get ExtensionContext (no ctx.reload), + // so queue a follow-up user command that triggers the reload-runtime command. + pi.registerTool({ + name: "reload_runtime", + label: "Reload Runtime", + description: "Reload extensions, skills, prompts, and themes. Use this after modifying extension files so changes take effect during a loop.", + parameters: Type.Object({}), + async execute() { + pi.sendUserMessage("/reload-runtime", { deliverAs: "followUp" }); + return { + content: [{ type: "text", text: "Queued /reload-runtime as a follow-up command. Extensions will reload when the current turn completes." }], + details: {}, + }; + }, + }); + pi.registerCommand("loop", { description: "Start a follow-up loop until a breakout condition is met", handler: async (args, ctx) => { @@ -443,8 +459,21 @@ export default function loopExtension(pi: ExtensionAPI): void { } } + // Command entrypoint for reload. ctx.reload() is only available in CommandContext. + pi.registerCommand("reload-runtime", { + description: "Reload extensions, skills, prompts, and themes", + handler: async (_args, ctx) => { + await ctx.reload(); + return; + }, + }); + pi.on("session_start", async (_event, ctx) => { await restoreLoopState(ctx); + // If this is a reload (not first startup) and loop was active, auto-resume + if (loopState.active && _event.reason === "reload") { + triggerLoopPrompt(ctx); + } }); pi.on("session_switch", async (_event: SessionSwitchEvent, ctx) => {