fs: move tools to ctl commands, remove tools file

/tools        — lists loaded tools
/tool_load X  — loads a tool by name

System prompt updated to instruct the agent to use ctl for tool
management instead of writing to a tools file.
This commit is contained in:
Ollie Agent 2026-08-09 02:52:06 +02:00
parent 94088ccc94
commit 993d5a812a
4 changed files with 30 additions and 35 deletions

View File

@ -33,7 +33,7 @@ ROOT_ENTRIES="session bypass agents backends models help ctl eventwait complete
SESSION_FILES="env paused connected ctl name id bypass"
# Agent-level files (exist under session/{name}/agent/{name}/)
AGENT_FILES="prompt fifo chat chat.raw statewait log plan cfg ctl stats systemprompt tools name id proc"
AGENT_FILES="prompt fifo chat chat.raw statewait log plan cfg ctl stats systemprompt name id proc"
is_root_path() {
local path="$1"

View File

@ -712,6 +712,31 @@ func requestAgentCtl(ctx HandlerCtx, data []byte) ([]byte, error) {
return []byte(strings.Join(args, " ") + "\n"), nil
case "models":
return []byte(ctx.Session.CachedListModels() + "\n"), nil
case "tools":
if ctx.Session.ToolsConn() == nil {
return []byte("(no tool server)\n"), nil
}
loaded, err := ctx.Session.ToolsConn().ListTools()
if err != nil {
return nil, err
}
var sb strings.Builder
for _, ti := range loaded {
if ti.Description != "" {
fmt.Fprintf(&sb, "%-20s %s\n", ti.Name, ti.Description)
} else {
sb.WriteString(ti.Name + "\n")
}
}
return []byte(sb.String()), nil
case "tool_load":
if len(args) == 0 {
return nil, fmt.Errorf("tool_load requires a tool name")
}
if err := ctx.Session.LoadTool(args[0], ctx.Agent); err != nil {
return nil, err
}
return []byte(args[0] + "\n"), nil
case "backend":
if len(args) == 0 {
if be := ctx.Agent.Backend(); be != nil {
@ -753,29 +778,6 @@ func readAgentSystemprompt(ctx HandlerCtx) ([]byte, error) {
return []byte(ctx.Agent.SystemPrompt() + "\n"), nil
}
func readAgentTools(ctx HandlerCtx) ([]byte, error) {
if ctx.Session.ToolsConn() == nil {
return []byte("(no tool server)\n"), nil
}
loaded, err := ctx.Session.ToolsConn().ListTools()
if err != nil {
return []byte(fmt.Sprintf("(error: %v)\n", err)), nil
}
var sb strings.Builder
for _, ti := range loaded {
if ti.Description != "" {
fmt.Fprintf(&sb, "%-20s %s\n", ti.Name, ti.Description)
} else {
sb.WriteString(ti.Name + "\n")
}
}
return []byte(sb.String()), nil
}
func writeAgentTools(ctx HandlerCtx, data []byte) error {
return ctx.Session.LoadTool(string(data), ctx.Agent)
}
func readAgentName(ctx HandlerCtx) ([]byte, error) {
return []byte(ctx.Agent.Name() + "\n"), nil
}

View File

@ -279,12 +279,6 @@ FileNode("generate", 0666,
Read(readAgentSystemprompt),
),
FileNode("tools", 0666,
Doc("Tool management. Read: loaded tools. Write: tool name to load."),
Read(readAgentTools),
Write(writeAgentTools),
),
FileNode("name", 0666,
Doc("Agent display name. Read: current name. Write: rename agent."),
Read(readAgentName),

View File

@ -57,11 +57,10 @@ You have autonomous access to tools and skills. Proactively load what you need
## Tools
Tools are loaded into your session at startup (configured in the agent's `autoLoad` list). Additional tools can be loaded dynamically via the 9P filesystem:
Tools are loaded into your session at startup (configured in the agent's `autoLoad` list). Additional tools can be loaded dynamically via the agent's ctl file:
- **List available tools** — write to `session/{sname}/agent/{aname}/tools` (empty string lists all)
- **Load a tool** — write the tool name to `session/{sname}/agent/{aname}/tools`
- **See loaded tools** — read from `session/{sname}/agent/{aname}/tools`
- **List loaded tools** — write `tools` to `ctl`
- **Load a tool** — write `tool_load <name>` to `ctl`
Once loaded, a tool becomes a first-class function. Call it directly by name with JSON arguments matching its schema.
@ -182,7 +181,7 @@ Each agent has its own directory. The `{aname}` is the agent's numeric ID (stabl
| `chat.raw` | read | Conversation (full markup with block markers) |
| `statewait` | read | Blocks until state changes; returns new value |
| `cfg` | r/w | Agent config: backend, model, cwd, params (key=value) |
| `ctl` | write | Control: stop, compact, clear, inject, agent, model, cwd |
| `ctl` | rdwr | Control: stop, compact, clear, inject, agent, model, models, tools, tool_load, cwd, name |
| `stats` | read | Agent statistics (usage=, cost=, ctxsz=) |
| `models` | read | Available models for current backend |
| `systemprompt` | read | Fully rendered system prompt |