UNPKG

pi-lens

Version:

Real-time code feedback for pi — LSP, linters, formatters, type-checking, structural analysis & booboo

73 lines (72 loc) • 3.57 kB
/** * pi_lens_activate_tools — the loader tool that bootstraps pi's dynamic * tooling (registered-but-inactive tools activated via `pi.setActiveTools`). * * A handful of pi-lens tools are situational (structural ast-grep * search/replace/outline/dump, LSP go-to-definition/references/rename) — * useful on many turns, but not every turn. On hosts that support it, pi * lets an extension register such tools inactive and expose a small * always-active loader the model calls to activate a subset by name * (docs: https://github.com/earendil-works/pi, packages/coding-agent/docs/ * extensions.md, "Dynamic Tool Loading"). Newly activated tools appear * starting the NEXT turn — no reload needed. * * This tool stays always-active (it has to, to bootstrap activation). It is * a no-op catalog lookup on hosts where the caller never wired * `setActiveTools`/`getActiveTools` (see the feature-detected gating in * index.ts) — the situational tools are registered statically active there * instead, so calling this tool is harmless, just unnecessary. */ import { Type } from "../clients/deps/typebox.js"; export function createActivateToolsTool(pi, lazyTools) { const lazyNames = lazyTools.map((t) => t.name); const lazyNameSet = new Set(lazyNames); const catalog = lazyTools.map((t) => `${t.name} — ${t.summary}`).join("\n"); return { name: "pi_lens_activate_tools", label: "Activate pi-lens Tools", description: "Activate one or more situational pi-lens tools that stay registered but inactive by default, so the default tool list stays lean. " + "Call this ONCE with the tools you need before using them — they become callable starting the NEXT turn. " + `Available:\n${catalog}`, promptSnippet: "Activate situational ast-grep / lsp_navigation tools before using them", parameters: Type.Object({ tools: Type.Array(Type.String({ enum: lazyNames }), { minItems: 1, description: "Names of situational tools to activate (see this tool's description for the catalog).", }), }), async execute(_toolCallId, params, _signal, _onUpdate) { const requested = Array.isArray(params.tools) ? params.tools.filter((t) => typeof t === "string" && lazyNameSet.has(t)) : []; if (requested.length === 0) { return { content: [ { type: "text", text: `No valid tool names given. Available: ${lazyNames.join(", ")}`, }, ], isError: true, details: { matches: [], added: [] }, }; } // Additive only, per the docs' contract: never drop currently active // tools in the same call. const active = typeof pi.getActiveTools === "function" ? pi.getActiveTools() : []; const merged = [...new Set([...active, ...requested])]; if (typeof pi.setActiveTools === "function") { pi.setActiveTools(merged); } return { content: [ { type: "text", text: `Activated: ${requested.join(", ")}. Available starting next turn.`, }, ], details: { matches: requested, added: requested }, }; }, }; }