diff --git a/cmd/olliesrv/internal/fs/spec.go b/cmd/olliesrv/internal/fs/spec.go index 549a69d..93719d5 100644 --- a/cmd/olliesrv/internal/fs/spec.go +++ b/cmd/olliesrv/internal/fs/spec.go @@ -16,7 +16,6 @@ import ( "ollie/cmd/olliesrv/internal/backend" "ollie/cmd/olliesrv/internal/session" "ollie/paths" - "ollie/toolsrv" "ollie/virtfs" ) @@ -95,20 +94,6 @@ func buildTreeSpec(cfg *Config) virtfs.FsNodeDecl { return []byte(sb.String()), nil }), ), - virtfs.FileNode("tools", 0444, - virtfs.Doc("Available tools. Format: namedescription per line."), - virtfs.Read(func() ([]byte, error) { - tools := toolsrv.DiscoverTools() - if len(tools) == 0 { - return []byte("(no tools found)\n"), nil - } - var sb strings.Builder - for _, ti := range tools { - fmt.Fprintf(&sb, "%-24s %s\n", ti.Name, ti.Description) - } - return []byte(sb.String()), nil - }), - ), virtfs.FileNode("ctl", 0666, virtfs.Doc("Server control. Write: 'invalidate', 'kill'"), virtfs.Request(func(_ context.Context, data []byte) ([]byte, error) { @@ -619,6 +604,13 @@ func buildAgentChildren(a *agent.Agent, s *session.Session) []virtfs.FsNodeDecl a.RefreshTools() return []byte(args[0] + "\n"), nil }, + "tools_all": func(args []string) ([]byte, error) { + ts := a.ToolServer() + if ts == nil { + return nil, fmt.Errorf("no tool server") + } + return ts.ListAllTools() + }, "tool_unload": func(args []string) ([]byte, error) { if len(args) == 0 { return nil, fmt.Errorf("tool_unload requires a tool name") diff --git a/cmd/olliesrv/internal/prompts/system_prompt.md b/cmd/olliesrv/internal/prompts/system_prompt.md index f6e3344..b825046 100644 --- a/cmd/olliesrv/internal/prompts/system_prompt.md +++ b/cmd/olliesrv/internal/prompts/system_prompt.md @@ -32,6 +32,12 @@ Tools are loaded at startup. Additional tools can be loaded at runtime via ctl: echo "tool_load file_read" | ollie-9p write session/$OLLIE_SESSION_ID/agent/$OLLIE_UNAME/ctl ``` +To list all available tools (not just loaded ones): + +```bash +echo "tools_all" | ollie-9p rdwr session/$OLLIE_SESSION_ID/agent/$OLLIE_UNAME/ctl +``` + Once loaded, a tool is a first-class function — call it directly by name. **Important**: Use native tool calls, not shell. For example: @@ -122,7 +128,7 @@ Your world model is a 9P filesystem. Your session ID is `${OLLIE_SESSION_ID}`. U | `chat.raw` | read | Full conversation with block markers | | `statewait` | read | Blocks until state changes; returns new value | | `cfg` | r/w | Agent config (key=value: backend, model, cwd, temperature, etc.) | -| `ctl` | rdwr | Control: stop, compact, clear, inject, agent, model, tools, tool_load, tool_unload, cwd, name | +| `ctl` | rdwr | Control: stop, compact, clear, inject, agent, model, tools, tools_all, tool_load, tool_unload, cwd, name | | `stats` | read | Usage, cost, context size | | `tools` | r/w | Write: load tool by name. Read: list loaded tools. | | `proc/` | dir | Detached background processes | diff --git a/cmd/toolsrv/internal/server/server.go b/cmd/toolsrv/internal/server/server.go index c2f6081..8475907 100644 --- a/cmd/toolsrv/internal/server/server.go +++ b/cmd/toolsrv/internal/server/server.go @@ -15,6 +15,7 @@ import ( "ollie/cmd/toolsrv/internal/bypass" "ollie/cmd/toolsrv/internal/registry" + "ollie/toolsrv" "ollie/virtfs" ) @@ -125,6 +126,17 @@ func Spec(srv *Server) virtfs.FsNodeDecl { return []byte(srv.Fs.HandleToolsRequest(agentID)), nil }), ), + virtfs.FileNode("all", 0444, + virtfs.Doc("All available tools on disk: namedescription per line"), + virtfs.Read(func() ([]byte, error) { + tools := toolsrv.DiscoverTools() + var sb strings.Builder + for _, ti := range tools { + fmt.Fprintf(&sb, "%s\t%s\n", ti.Name, ti.Description) + } + return []byte(sb.String()), nil + }), + ), virtfs.FileNode("info", 0444, virtfs.Doc("Host info: platform, arch"), virtfs.Read(func() ([]byte, error) { diff --git a/toolsrv/client9p.go b/toolsrv/client9p.go index 601cd8e..172f5e9 100644 --- a/toolsrv/client9p.go +++ b/toolsrv/client9p.go @@ -245,6 +245,16 @@ func (c *Conn) LoadTool(name string) error { return err } +// ListAllTools reads the full catalog of available tools from toolsrv. +func (c *Conn) ListAllTools() ([]byte, error) { + fid, err := c.fsys.Open("all", plan9.OREAD) + if err != nil { + return nil, err + } + defer fid.Close() + return io.ReadAll(fid) +} + // UnloadTool unloads a tool by name. func (c *Conn) UnloadTool(name string) error { fid, err := c.fsys.Open("ctl", plan9.OWRITE)