docs: clarify tool usage in system prompt, add cancellation flow doc
- Explicitly tell model not to invoke tool scripts via filesystem path - Add concrete examples of native tool calls vs shell - Document context cancellation flow from interrupt to process kill
This commit is contained in:
parent
aedfdec564
commit
9057d36f05
|
|
@ -26,9 +26,16 @@ Proactively load what you need — don't wait to be told.
|
|||
|
||||
## Tools
|
||||
|
||||
Tools are loaded at startup. Additional tools can be loaded at runtime via the `tool_load` tool. Once loaded, a tool is a first-class function — call it directly by name. Do not invoke tools through `shell`.
|
||||
Tools are loaded at startup. Additional tools can be loaded at runtime via the `tool_load` tool. Once loaded, a tool is a first-class function — call it directly by name.
|
||||
|
||||
To see all available tools (loaded and unloaded): `ollie-9p read tools`
|
||||
**Important**: Use native tool calls, not shell. For example:
|
||||
- To read a file: call `file_read` directly, NOT `cat` or `shell` with any command
|
||||
- To search: call `file_grep` directly, NOT `grep` via shell
|
||||
- To edit: call `file_edit` directly, NOT `sed` via shell
|
||||
|
||||
The tool scripts in `~/.config/ollie/tools/` are already exposed as callable functions. Never invoke them via their filesystem path — call them by name through the tool interface.
|
||||
|
||||
Shell is for system commands that have no native tool equivalent: builds, git, package managers, interpreters, etc.
|
||||
|
||||
## Parallel Calls
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,161 @@
|
|||
# Context Cancellation Flow
|
||||
|
||||
This document traces context cancellation from user interrupt to tool process termination.
|
||||
|
||||
## Overview
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ OLLIESRV │
|
||||
│ │
|
||||
│ User sends "stop" to agent ctl │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────┐ │
|
||||
│ │ Agent.Interrupt │ Loads currentAction (actionHandle) │
|
||||
│ │ (cause) │ Calls h.cancel(cause) │
|
||||
│ └────────┬────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────┐ │
|
||||
│ │ actCtx (context.WithCancelCause) │ Created in Agent.Run() │
|
||||
│ │ │ at turn start (turn.go:95) │
|
||||
│ └────────┬────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────┐ │
|
||||
│ │ TurnCtx (embeds │ Passed to loop.go, execOne(), etc. │
|
||||
│ │ context.Context)│ │
|
||||
│ └────────┬────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────┐ │
|
||||
│ │ execOne() checks ctx.Err() │ loop.go:540 │
|
||||
│ │ If cancelled → returns immediately │ │
|
||||
│ │ with status:"cancelled" │ │
|
||||
│ └────────┬────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ │ If not cancelled, calls rt.Exec(ctx, name, args) │
|
||||
│ │ which wraps srv.CallTool(ctx, ...) (runtime.go:181) │
|
||||
│ ▼ │
|
||||
└───────────┼──────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
│ UNIX SOCKET (9P PROTOCOL)
|
||||
│
|
||||
┌───────────┼──────────────────────────────────────────────────────────────────┐
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ toolsrv/client9p.go: CallTool() │ │
|
||||
│ │ │ │
|
||||
│ │ 1. Opens "proc/new" file (9P fid) │ │
|
||||
│ │ │ │
|
||||
│ │ 2. Starts goroutine watching ctx.Done(): │ │
|
||||
│ │ go func() { │ │
|
||||
│ │ select { │ │
|
||||
│ │ case <-ctx.Done(): │ │
|
||||
│ │ fid.Close() // ← Force close to unblock read │ │
|
||||
│ │ case <-done: │ │
|
||||
│ │ } │ │
|
||||
│ │ }() │ │
|
||||
│ │ │ │
|
||||
│ │ 3. Writes payload to fid (Twrite) │ │
|
||||
│ │ 4. Reads result from fid (Tread) — BLOCKS │ │
|
||||
│ │ 5. If read fails AND ctx.Err() != nil → return ctx.Err() │ │
|
||||
│ └────────┬────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ │ fid.Close() sends Tclunk to toolsrv │
|
||||
│ ▼ │
|
||||
└───────────┼──────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
┌───────────┼──────────────────────────────────────────────────────────────────┐
|
||||
│ │ TOOLSRV │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ p9.go: handleClunk() receives Tclunk │ │
|
||||
│ │ │ │
|
||||
│ │ 1. Removes fid from map │ │
|
||||
│ │ 2. Calls f.entry.Close() (p9.go:550) │ │
|
||||
│ └────────┬────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ virtfs/builder.go: closeFn() for Request mode │ │
|
||||
│ │ │ │
|
||||
│ │ closeFn := func() error { │ │
|
||||
│ │ if reqCancel != nil { │ │
|
||||
│ │ reqCancel() // ← Cancels the request context │ │
|
||||
│ │ } │ │
|
||||
│ │ return nil │ │
|
||||
│ │ } │ │
|
||||
│ │ │ │
|
||||
│ │ This cancels reqCtx created in writeFn (builder.go:274) │ │
|
||||
│ └────────┬────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ server/proc.go: HandleProcNew() receives cancelled context │ │
|
||||
│ │ │ │
|
||||
│ │ The Request handler was called with reqCtx: │ │
|
||||
│ │ virtfs.Request(func(ctx context.Context, data []byte) ...) │ │
|
||||
│ │ │ │
|
||||
│ │ When reqCancel() is called, ctx.Done() becomes readable │ │
|
||||
│ └────────┬────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ exec/exec.go: ExecuteTool() sees context cancellation │ │
|
||||
│ │ │ │
|
||||
│ │ The exec code should check ctx.Done() and: │ │
|
||||
│ │ 1. Send SIGKILL to the child process │ │
|
||||
│ │ 2. Return error to caller │ │
|
||||
│ └─────────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Key Files
|
||||
|
||||
| Location | Responsibility |
|
||||
|----------|----------------|
|
||||
| `cmd/olliesrv/internal/agent/agent.go:308` | `Interrupt()` calls `h.cancel(cause)` |
|
||||
| `cmd/olliesrv/internal/agent/turn.go:95` | Creates `actCtx` with `WithCancelCause` |
|
||||
| `cmd/olliesrv/internal/agent/loop.go:540` | `execOne()` checks `ctx.Err()` early |
|
||||
| `cmd/olliesrv/internal/agent/runtime.go:181` | `rt.Exec` calls `srv.CallTool(ctx, ...)` |
|
||||
| `toolsrv/client9p.go:140-155` | `CallTool()` goroutine closes fid on ctx.Done() |
|
||||
| `cmd/toolsrv/p9.go:549-551` | `handleClunk()` calls `f.entry.Close()` |
|
||||
| `virtfs/builder.go:282-286` | `closeFn` cancels `reqCtx` |
|
||||
| `cmd/toolsrv/internal/exec/exec.go` | Should kill process on context cancellation |
|
||||
|
||||
## Sequence Diagram
|
||||
|
||||
```
|
||||
User Agent CallTool 9P Server virtfs exec
|
||||
│ │ │ │ │ │
|
||||
│──"stop"────▶│ │ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │──cancel()─────▶│ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │──fid.Close()──▶│ │ │
|
||||
│ │ │ (Tclunk) │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │──Close()─────▶│ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ │──reqCancel()─▶│
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ │ │──SIGKILL──▶[process]
|
||||
│ │ │ │ │ │
|
||||
│ │◀───ctx.Err()───│ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│◀──cancelled─│ │ │ │ │
|
||||
```
|
||||
|
||||
## Potential Issues
|
||||
|
||||
1. **Race condition**: The Tclunk might arrive after the tool has already completed
|
||||
- This is benign: cancelling a completed context is a no-op
|
||||
|
||||
2. **Long cleanup**: If the tool doesn't respond to SIGKILL quickly, the cancellation
|
||||
may appear to hang briefly
|
||||
|
||||
3. **Background processes**: Background tools (via `proc/new.bg`) are NOT cancelled
|
||||
by this mechanism - they run until completion or explicit kill
|
||||
Loading…
Reference in New Issue