doc+fix: background procs force timeout=0, update docs
- Background procs get timeout=0 (no deadline) set by toolsrv at the execution layer — not injected as an arg from olliesrv. Foreground default remains 30s. User can still override via args. - Timeout logic simplified: caller sets default, ExecuteTool honors it. - System prompt: clarify background has no timeout, uses 'stop' not 'kill' - architecture.md: document lifecycle (connection-based ownership) - evolution.md: update interrupt section with streaming, lifecycle, id= format - README.md: add parallel execution to capabilities table
This commit is contained in:
parent
97c208fa39
commit
391465be77
|
|
@ -58,7 +58,8 @@ Everything lives under `$XDG_CONFIG_HOME/ollie/` (default: `~/.config/ollie/`)
|
|||
| **One-shot LLM** | `o generate "explain monads"` or `echo "prompt" \| o generate` |
|
||||
| **Run an agent** | Create a session + agent via 9P — then connect with any frontend ([ellie](doc/ellie.md), KDE (GUI/KRunner/Kate), `o tui`) |
|
||||
| **Remote execution** | Set `remote=user@host` in session config |
|
||||
| **Background processes** | Pass `"background": true` to any tool — output auto-injected into context |
|
||||
| **Background processes** | Pass `"background": true` to any tool — runs with no timeout, output auto-injected, lifecycle tied to session |
|
||||
| **Parallel execution** | Non-conflicting tool calls within a turn run in parallel (scope-based conflict scheduling) |
|
||||
| **Agents** | Write a JSON config in `data/agents/` with agent prompt in `data/prompts/` |
|
||||
| **Tools** | Drop an executable + `.meta` in `~/.config/ollie/tools/` — load at runtime via `/tool_load` |
|
||||
| **Domain skills** | Load markdown skill modules at runtime |
|
||||
|
|
|
|||
|
|
@ -52,9 +52,11 @@ Run long-running commands in the background by passing `"background": true` to s
|
|||
|
||||
The result is a `<system-proc-background>` tag containing the process ID. You do NOT need to poll for output — background process updates are automatically injected into your context as `<system-proc-interrupt>` blocks alongside tool results. These include status (running/exited), exit code, and the last 20 lines of output.
|
||||
|
||||
Background processes have no timeout — they run until they exit, you stop them, or the session ends.
|
||||
|
||||
**Rules**:
|
||||
- Use background for long operations (builds, test suites, deployments, log tailing). Do NOT background short commands (< 5s).
|
||||
- React to `<system-proc-interrupt>` naturally. If a build fails, fix it. If output is irrelevant, kill the process.
|
||||
- React to `<system-proc-interrupt>` naturally. If a build fails, fix it. If output is irrelevant, stop the process.
|
||||
- Stop background processes when done: `echo term | ollie-9p write session/$OLLIE_SESSION_ID/agent/$OLLIE_UNAME/proc/<id>/ctl` (use `kill` instead of `term` to force-kill)
|
||||
- Read full output: `ollie-9p read session/$OLLIE_SESSION_ID/agent/$OLLIE_UNAME/proc/<id>/out`
|
||||
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ type Config struct {
|
|||
CWD string
|
||||
Env map[string]string
|
||||
Yolo bool
|
||||
Timeout int
|
||||
Output io.Writer // if set, stream stdout/stderr here in real-time
|
||||
Timeout int // 0 = no timeout
|
||||
Output io.Writer // if set, stream stdout/stderr here in real-time
|
||||
Started chan *os.Process // if set, receives the os.Process after Start()
|
||||
}
|
||||
|
||||
|
|
@ -56,11 +56,7 @@ func ExecuteTool(ctx context.Context, info toolsrv.ToolInfo, args json.RawMessag
|
|||
|
||||
// Extract dispatch-level flags from args
|
||||
bypassed := false
|
||||
timeout := cfg.Timeout
|
||||
timeoutExplicit := timeout > 0
|
||||
if !timeoutExplicit {
|
||||
timeout = 30
|
||||
}
|
||||
timeout := cfg.Timeout // 0 = no timeout; caller sets default
|
||||
sandboxName := "default"
|
||||
|
||||
var argMap map[string]interface{}
|
||||
|
|
@ -75,7 +71,6 @@ func ExecuteTool(ctx context.Context, info toolsrv.ToolInfo, args json.RawMessag
|
|||
delete(argMap, "bypass")
|
||||
}
|
||||
if t, ok := argMap["timeout"]; ok {
|
||||
timeoutExplicit = true
|
||||
switch v := t.(type) {
|
||||
case float64:
|
||||
timeout = int(v)
|
||||
|
|
|
|||
|
|
@ -247,9 +247,11 @@ func (st *State) NewProc(ctx context.Context, payload string, background bool) (
|
|||
// For foreground, use nil (local buffer in exec path).
|
||||
var outputWriter io.Writer
|
||||
var startedCh chan *os.Process
|
||||
timeout := 30 // default for foreground
|
||||
if background {
|
||||
outputWriter = &procWriter{proc: proc}
|
||||
startedCh = make(chan *os.Process, 1)
|
||||
timeout = 0 // background procs never timeout
|
||||
}
|
||||
|
||||
// Execute in goroutine
|
||||
|
|
@ -257,7 +259,7 @@ func (st *State) NewProc(ctx context.Context, payload string, background bool) (
|
|||
defer close(proc.done)
|
||||
defer cancel()
|
||||
|
||||
out, exitCode := st.executeTool(procCtx, info, args, cwd, envCopy, yolo, outputWriter, startedCh)
|
||||
out, exitCode := st.executeTool(procCtx, info, args, cwd, envCopy, yolo, timeout, outputWriter, startedCh)
|
||||
|
||||
proc.mu.Lock()
|
||||
if !background {
|
||||
|
|
@ -299,7 +301,8 @@ func (st *State) NewProc(ctx context.Context, payload string, background bool) (
|
|||
}
|
||||
|
||||
// executeTool runs a tool and returns output + exit code.
|
||||
func (st *State) executeTool(ctx context.Context, info toolsrv.ToolInfo, args map[string]string, cwd string, envExtra map[string]string, yolo bool, output io.Writer, started chan *os.Process) (string, int) {
|
||||
// timeout: 0 = no timeout, >0 = seconds.
|
||||
func (st *State) executeTool(ctx context.Context, info toolsrv.ToolInfo, args map[string]string, cwd string, envExtra map[string]string, yolo bool, timeout int, output io.Writer, started chan *os.Process) (string, int) {
|
||||
// Convert args map to JSON for the execution path
|
||||
jsonArgs := argsToJSON(args)
|
||||
|
||||
|
|
@ -307,6 +310,7 @@ func (st *State) executeTool(ctx context.Context, info toolsrv.ToolInfo, args ma
|
|||
CWD: cwd,
|
||||
Env: envExtra,
|
||||
Yolo: yolo,
|
||||
Timeout: timeout,
|
||||
Output: output,
|
||||
Started: started,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,12 +156,14 @@ Tool calls within a single turn are dispatched in parallel using resource-based
|
|||
This means N file edits on different paths complete in one round-trip instead of N sequential calls. Shell is always a barrier (global scope) since its effects are opaque.
|
||||
|
||||
#### Background Processes
|
||||
Any tool call can include `"background": true` to execute asynchronously. The result is an immediate PID; the tool runs in toolsrv's `proc/new.bg`. Background process output is automatically injected into the model's context as `<system-proc-interrupt>` blocks at safe points (alongside subsequent tool results). The model can react to build failures, log events, etc. without polling.
|
||||
Any tool call can include `"background": true` to execute asynchronously. The result is an immediate process ID; the tool runs in toolsrv's `proc/new.bg` with no timeout. Output streams in real-time into `proc/{id}/out` and is automatically injected into the model's context as `<system-proc-interrupt>` blocks alongside subsequent tool results. The model can react to build failures, log events, etc. without polling.
|
||||
|
||||
Process lifecycle is connection-based: toolsrv owns all procs, and session death (toolsrv exit) kills everything via `KillAll()` + `Pdeathsig`. Exited procs remain in the tree for 10 minutes after last read, then are garbage collected. The model controls procs via `proc/{id}/ctl` (term, kill, dismiss).
|
||||
|
||||
#### Dispatch Flags
|
||||
All tools automatically receive four optional parameters (injected into schemas at runtime):
|
||||
- `bypass` — run outside sandbox via bypass broker
|
||||
- `timeout` — execution timeout in seconds
|
||||
- `timeout` — execution timeout in seconds (0 = no timeout; background forces 0)
|
||||
- `sandbox` — sandbox profile name
|
||||
- `background` — run asynchronously, auto-inject output
|
||||
|
||||
|
|
|
|||
|
|
@ -1188,20 +1188,28 @@ opt in to parallelism.
|
|||
### Background Process Interrupts
|
||||
|
||||
Any tool call can include `"background": true` to execute asynchronously
|
||||
via `proc/new.bg`. The model receives a PID immediately and continues working.
|
||||
Background process output is automatically injected into the model's context
|
||||
as `<system-proc-interrupt>` blocks alongside subsequent tool results:
|
||||
via `proc/new.bg`. The model receives a process ID immediately and continues working.
|
||||
Background processes have no timeout — they run until they exit naturally,
|
||||
are stopped via `proc/{id}/ctl`, or die with the session.
|
||||
|
||||
Output is streamed in real-time into `proc/{id}/out` and automatically injected
|
||||
into the model's context as `<system-proc-interrupt>` blocks alongside
|
||||
subsequent tool results:
|
||||
|
||||
```xml
|
||||
<system-proc-interrupt pid="42" cmd="go test ./..." status="exited" exit="1">
|
||||
<system-proc-interrupt id="42" cmd="go test ./..." status="exited" exit="1">
|
||||
--- FAIL: TestFoo (0.00s)
|
||||
foo_test.go:12: expected 3, got 2
|
||||
FAIL
|
||||
</system-proc-interrupt>
|
||||
```
|
||||
|
||||
The model sees these naturally — no polling, no explicit `process_output` calls.
|
||||
It can react to failures or kill processes by PID when done.
|
||||
The model sees these naturally — no polling needed. It can react to failures
|
||||
or stop processes via the proc ctl file (`term`, `kill`, `dismiss`).
|
||||
|
||||
**Process lifecycle**: toolsrv owns all procs. Session death (toolsrv exit)
|
||||
kills all procs via `KillAll()` + `Pdeathsig`. Exited procs remain in the
|
||||
tree for 10 minutes after last read, then are garbage collected.
|
||||
|
||||
### Universal Dispatch Flags
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue