Download packages/coding-agent/examples/extensions/tools.ts from SaylorTwift/pi: direct link, hf CLI and curl.
- Browser
- Download file 3.87 kB
-
https://huggingface.co/SaylorTwift/pi/resolve/main/packages/coding-agent/examples/extensions/tools.ts
- Command line
-
hf download hf://SaylorTwift/pi/packages/coding-agent/examples/extensions/tools.ts
-
curl -L -o tools.ts https://huggingface.co/SaylorTwift/pi/resolve/main/packages/coding-agent/examples/extensions/tools.ts
3.87 kB
| /** | |
| * Tools Extension | |
| * | |
| * Provides a /tools command to enable/disable tools interactively. | |
| * Tool selection persists across session reloads and respects branch navigation. | |
| * | |
| * Usage: | |
| * 1. Copy this file to ~/.pi/agent/extensions/ or your project's .pi/extensions/ | |
| * 2. Use /tools to open the tool selector | |
| */ | |
| import type { ExtensionAPI, ExtensionContext, ToolInfo } from "@earendil-works/pi-coding-agent"; | |
| import { getSettingsListTheme } from "@earendil-works/pi-coding-agent"; | |
| import { Container, type SettingItem, SettingsList } from "@earendil-works/pi-tui"; | |
| // State persisted to session | |
| interface ToolsState { | |
| enabledTools: string[]; | |
| } | |
| export default function toolsExtension(pi: ExtensionAPI) { | |
| // Track enabled tools | |
| let enabledTools: Set<string> = new Set(); | |
| let allTools: ToolInfo[] = []; | |
| // Persist current state | |
| function persistState() { | |
| pi.appendEntry<ToolsState>("tools-config", { | |
| enabledTools: Array.from(enabledTools), | |
| }); | |
| } | |
| // Apply current tool selection | |
| function applyTools() { | |
| pi.setActiveTools(Array.from(enabledTools)); | |
| } | |
| // Find the last tools-config entry in the current branch | |
| function restoreFromBranch(ctx: ExtensionContext) { | |
| allTools = pi.getAllTools(); | |
| // Get entries in current branch only | |
| const branchEntries = ctx.sessionManager.getBranch(); | |
| let savedTools: string[] | undefined; | |
| for (const entry of branchEntries) { | |
| if (entry.type === "custom" && entry.customType === "tools-config") { | |
| const data = entry.data as ToolsState | undefined; | |
| if (data?.enabledTools) { | |
| savedTools = data.enabledTools; | |
| } | |
| } | |
| } | |
| if (savedTools) { | |
| // Restore saved tool selection (filter to only tools that still exist) | |
| const allToolNames = allTools.map((t) => t.name); | |
| enabledTools = new Set(savedTools.filter((t: string) => allToolNames.includes(t))); | |
| applyTools(); | |
| } else { | |
| // No saved state - sync with currently active tools | |
| enabledTools = new Set(pi.getActiveTools()); | |
| } | |
| } | |
| // Register /tools command | |
| pi.registerCommand("tools", { | |
| description: "Enable/disable tools", | |
| handler: async (_args, ctx) => { | |
| if (ctx.mode !== "tui") { | |
| ctx.ui.notify("/tools requires TUI mode", "error"); | |
| return; | |
| } | |
| // Refresh tool list | |
| allTools = pi.getAllTools(); | |
| await ctx.ui.custom((tui, theme, _kb, done) => { | |
| // Build settings items for each tool | |
| const items: SettingItem[] = allTools.map((tool) => ({ | |
| id: tool.name, | |
| label: tool.name, | |
| currentValue: enabledTools.has(tool.name) ? "enabled" : "disabled", | |
| values: ["enabled", "disabled"], | |
| })); | |
| const container = new Container(); | |
| container.addChild( | |
| new (class { | |
| render(_width: number) { | |
| return [theme.fg("accent", theme.bold("Tool Configuration")), ""]; | |
| } | |
| invalidate() {} | |
| })(), | |
| ); | |
| const settingsList = new SettingsList( | |
| items, | |
| Math.min(items.length + 2, 15), | |
| getSettingsListTheme(), | |
| (id, newValue) => { | |
| // Update enabled state and apply immediately | |
| if (newValue === "enabled") { | |
| enabledTools.add(id); | |
| } else { | |
| enabledTools.delete(id); | |
| } | |
| applyTools(); | |
| persistState(); | |
| }, | |
| () => { | |
| // Close dialog | |
| done(undefined); | |
| }, | |
| ); | |
| container.addChild(settingsList); | |
| const component = { | |
| render(width: number) { | |
| return container.render(width); | |
| }, | |
| invalidate() { | |
| container.invalidate(); | |
| }, | |
| handleInput(data: string) { | |
| settingsList.handleInput?.(data); | |
| tui.requestRender(); | |
| }, | |
| }; | |
| return component; | |
| }); | |
| }, | |
| }); | |
| // Restore state on session start | |
| pi.on("session_start", async (_event, ctx) => { | |
| restoreFromBranch(ctx); | |
| }); | |
| // Restore state when navigating the session tree | |
| pi.on("session_tree", async (_event, ctx) => { | |
| restoreFromBranch(ctx); | |
| }); | |
| } | |