import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { Type } from "typebox"; import type { ThreadStore } from "../core/types"; import { resumeThread, suspendThread } from "../core/thread-ops"; import type { Inbox } from "../inbox"; import { threadingTools } from "./index"; /** Self-control: pausing (On Hold) and resuming. Client-local (Layer 2) — * not protocol surface (§14/A.5). Scheduled wakes are ordinary sends with * deliverAfterSeconds (§12.2), not a control tool. */ export function registerControlTools(pi: ExtensionAPI, store: ThreadStore, inbox: Inbox) { pi.registerTool({ ...threadingTools.suspend, parameters: Type.Object({ reason: Type.Optional(Type.String()), }), async execute(_id, params, _signal, _onUpdate, ctx) { await suspendThread(store, params.reason ?? null, ctx); return { content: [ { type: "text" as const, text: `Thread suspended (On Hold)${params.reason ? `: ${params.reason}` : ""}. Inbox messages queue until resume.`, }, ], details: { ok: true, reason: params.reason ?? null }, }; }, }); pi.registerTool({ ...threadingTools.resume, parameters: Type.Object({}), async execute(_id, _params, _signal, _onUpdate, ctx) { if (!(await resumeThread(store, () => inbox.drain(ctx), ctx))) { return { content: [ { type: "text" as const, text: `Not on hold (state is ${store.state}) — nothing to resume.`, }, ], details: { ok: false }, }; } return { content: [{ type: "text" as const, text: "Thread resumed (Open). Queued inbox drained." }], details: { ok: true }, }; }, }); }