From 52b2ca78aed7950af27d4865aee65da781514a99 Mon Sep 17 00:00:00 2001 From: T Date: Sun, 26 Apr 2026 11:09:37 -0600 Subject: Initial work, and name change to pantograph --- docs/phase-3.md | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'docs/phase-3.md') diff --git a/docs/phase-3.md b/docs/phase-3.md index 51e1341..1b9d83a 100644 --- a/docs/phase-3.md +++ b/docs/phase-3.md @@ -2,14 +2,14 @@ ## Goal -Introduce a Lua extension runtime and tool registration/execution, transforming `awl` from a chat client into an agent that can act on the world. The extension system is the primary mechanism for adding capability — tools are extensions, not built-ins. +Introduce a Lua extension runtime and tool registration/execution, transforming `pantograph` from a chat client into an agent that can act on the world. The extension system is the primary mechanism for adding capability — tools are extensions, not built-ins. ## Deliverable A working extension system where Lua scripts can register tools and handle tool-use requests. The agent loop detects ToolUse blocks in LLM responses, executes the corresponding tool handlers, and feeds ToolResult blocks back. At the end of this phase, you can: - Write a Lua extension that registers a tool and handles invocations. -- Place it in `~/.config/awl/extensions/` (or `.awl/extensions/`) and have `awl` discover and load it. +- Place it in `~/.config/panto/extensions/` (or `.panto/extensions/`) and have `pantograph` discover and load it. - Have a conversation where the LLM calls your tool and receives the result. - See tool calls execute in parallel when the LLM returns multiple ToolUse blocks. - See a meaningful error message when an extension crashes, instead of a process abort. @@ -18,9 +18,9 @@ A working extension system where Lua scripts can register tools and handle tool- | Capability | How to exercise it | |---|---| -| Write a tool extension | Create `~/.config/awl/extensions/mytool.lua` calling `awl.register_tool(...)` | -| Discover extensions | Place `.lua` files or directories in extension directories; `awl` loads them on startup | -| LLM calls a tool | Ask the LLM to use a registered tool; it emits a ToolUse block; awl executes the handler | +| Write a tool extension | Create `~/.config/panto/extensions/mytool.lua` calling `panto.register_tool(...)` | +| Discover extensions | Place `.lua` files or directories in extension directories; `pantograph` loads them on startup | +| LLM calls a tool | Ask the LLM to use a registered tool; it emits a ToolUse block; pantograph executes the handler | | Tool result fed back | The tool handler's return value becomes a ToolResult block sent back to the LLM | | Parallel tool calls | LLM returns multiple ToolUse blocks; they execute concurrently | | Extension crash handling | A crashing tool handler prints `the "mytool" extension crashed: ` and aborts the turn | @@ -29,7 +29,7 @@ A working extension system where Lua scripts can register tools and handle tool- - Core tools as extensions (phase 5 — `std.read`, `std.write`, etc.) - Conversation serialization / disk persistence (phase 4) -- C ABI distribution of libawl for external consumers (future) +- C ABI distribution of libpanto for external consumers (future) - GitHub or luarocks extension loaders (future — local filesystem only in phase 3) - Shared-object extensions (future) - Extension sandboxing beyond `xpcall` crash protection (future) @@ -41,10 +41,10 @@ A working extension system where Lua scripts can register tools and handle tool- ### Directory locations -`awl` scans two directories in order: +`pantograph` scans two directories in order: -1. `.awl/extensions/` — project-local extensions (relative to current working directory) -2. `~/.config/awl/extensions/` — user-level extensions +1. `.panto/extensions/` — project-local extensions (relative to current working directory) +2. `~/.config/panto/extensions/` — user-level extensions ### Naming and structure @@ -58,25 +58,25 @@ Names can be hierarchical using dots as separators, mapping to directory nesting - `utils/json.lua` → extension name is `utils.json` - `coding/edit/init.lua` → extension name is `coding.edit` -This convention mirrors Lua's `require("a.b.c")` path resolution. Extension sub-modules (e.g., `coding/edit/helpers.lua`) are the extension's internal business — awl only loads the top-level entry point (`init.lua` or the single file). +This convention mirrors Lua's `require("a.b.c")` path resolution. Extension sub-modules (e.g., `coding/edit/helpers.lua`) are the extension's internal business — pantograph only loads the top-level entry point (`init.lua` or the single file). ### Loading behavior - Scan both directories recursively. - Construct extension names from relative paths using dot separators. - Load each discovered entry point file into a fresh `lua_State`. -- After loading, the extension's top-level code runs, which should call `awl.register_tool(...)` to register its tools. +- After loading, the extension's top-level code runs, which should call `panto.register_tool(...)` to register its tools. - Duplicate extension names: project-local takes precedence over user-level. --- ## Lua Bridge -The Lua bridge is a Zig module (`lua_bridge.zig`) that registers awl functions into the Lua state and handles translation between Zig types and Lua types. It is compiled into the `awl` binary — it is not a separate library. +The Lua bridge is a Zig module (`lua_bridge.zig`) that registers panto functions into the Lua state and handles translation between Zig types and Lua types. It is compiled into the `panto` binary — it is not a separate library. ### Functions exposed to Lua -#### `awl.register_tool(name, schema, handler)` +#### `panto.register_tool(name, schema, handler)` Registers a tool with the agent. @@ -87,7 +87,7 @@ Registers a tool with the agent. Example: ```lua -awl.register_tool("echo", { +panto.register_tool("echo", { type = "object", properties = { message = { type = "string", description = "The message to echo back" } @@ -100,17 +100,17 @@ end) ### Input parsing at the bridge boundary -Tool input arrives in libawl as raw JSON bytes (stored in the ToolUseBlock's TextualBlock). At the Lua bridge boundary, libawl parses these bytes into a Lua table using `std.json`, then passes the table to the handler. This is a convenience service for extension authors — internally, libawl still treats tool input as opaque bytes. The round-trip guarantee: the JSON bytes the provider sent are faithfully represented in the Lua table. +Tool input arrives in libpanto as raw JSON bytes (stored in the ToolUseBlock's TextualBlock). At the Lua bridge boundary, libpanto parses these bytes into a Lua table using `std.json`, then passes the table to the handler. This is a convenience service for extension authors — internally, libpanto still treats tool input as opaque bytes. The round-trip guarantee: the JSON bytes the provider sent are faithfully represented in the Lua table. ### Output from handlers -The handler returns a string. This string becomes the `content` of a ToolResult block. It is stored as raw bytes; libawl does not interpret or parse it. +The handler returns a string. This string becomes the `content` of a ToolResult block. It is stored as raw bytes; libpanto does not interpret or parse it. --- ## Tool Registration (Internal) -When `awl.register_tool()` is called from Lua, the bridge stores: +When `panto.register_tool()` is called from Lua, the bridge stores: ``` RegisteredTool = struct { @@ -185,7 +185,7 @@ end, input_table) If the handler crashes: - The error and stack trace are captured as a string. -- awl prints: `the "" extension crashed: ` +- pantograph prints: `the "" extension crashed: ` - The current LLM turn is aborted — no ToolResult is generated for this tool call. - Other concurrent tool calls in the same batch are not affected (they run in separate `lua_State` instances). @@ -283,7 +283,7 @@ src/extension_loader.zig // Directory scanning, extension discovery and loading ### External dependency -Lua interpreter linked into the `awl` binary. Zig's build system can fetch and compile Lua from source (Lua is a small C codebase, ~30KLOC). No system dependency required. +Lua interpreter linked into the `panto` binary. Zig's build system can fetch and compile Lua from source (Lua is a small C codebase, ~30KLOC). No system dependency required. --- @@ -302,7 +302,7 @@ Lua interpreter linked into the `awl` binary. Zig's build system can fetch and c ### Integration test (manual) - Write a simple `echo.lua` extension, place it in extension directory -- Start `awl`, ask the LLM to use the echo tool +- Start `panto`, ask the LLM to use the echo tool - Verify the tool is called, result is fed back, LLM continues - Write a `crash.lua` extension that throws an error - Verify the crash is caught and printed with context, turn aborts gracefully @@ -315,4 +315,4 @@ Lua interpreter linked into the `awl` binary. Zig's build system can fetch and c 1. **Lua version**: Lua 5.4 is current. Luau (Roblox's fork) has performance improvements but diverges. Stick with standard Lua 5.4 for compatibility with luarocks and existing ecosystem? 2. **Handler timeout**: Should tool handlers have a timeout? A hung tool call blocks the agent loop. Could add a configurable timeout with abort. 3. **Streaming tool results**: Some tools (e.g., `bash` running a long command) produce output incrementally. Phase 3 handlers return a single string. Streaming results would require a different handler interface — possibly a callback the handler calls to emit partial output. Defer to a later phase? -4. **Tool description field**: The `awl.register_tool()` call in phase 3 includes a schema but no explicit description string. Provider APIs require a description. Options: add a `description` parameter, or extract it from the schema. Probably simplest to add it as a parameter. +4. **Tool description field**: The `panto.register_tool()` call in phase 3 includes a schema but no explicit description string. Provider APIs require a description. Options: add a `description` parameter, or extract it from the schema. Probably simplest to add it as a parameter. -- cgit v1.3