execute: add detach field for autonomous background processes
When detach: true is set on a CodeStep, the process is immediately backgrounded after start. Its stdout/stderr are captured in a 64KB ring buffer accessible via GetDetachedOutput. The agent can then inspect and manage the process via process_list/process_output tools.
This commit is contained in:
parent
b6d0653d0b
commit
c1124b588d
|
|
@ -19,6 +19,7 @@ import (
|
|||
// CodeStep is one stage in an execution pipeline.
|
||||
// Set Code/Language for inline code, Tool/Args for a named script, or Parallel for concurrent fan-out.
|
||||
// Set Elevated to run the step outside the sandbox via the configured elevation backend.
|
||||
// Set Detach to immediately background the process and return its PID.
|
||||
type CodeStep struct {
|
||||
Code string `json:"code"`
|
||||
Language string `json:"language"`
|
||||
|
|
@ -26,6 +27,7 @@ type CodeStep struct {
|
|||
Args []string `json:"args"`
|
||||
Parallel []CodeStep `json:"parallel"`
|
||||
Elevated bool `json:"elevated"`
|
||||
Detach bool `json:"detach"`
|
||||
}
|
||||
|
||||
// resolveCodeStep loads a CodeStep into executable (code, language, trusted).
|
||||
|
|
@ -267,7 +269,7 @@ func (e *Server) dispatchSteps(ctx context.Context, steps []CodeStep, timeout in
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return e.executeWithStdin(ctx, code, lang, timeout, sandboxName, trusted, "")
|
||||
return e.executeWithStdin(ctx, code, lang, timeout, sandboxName, trusted, "", steps[0].Detach)
|
||||
}
|
||||
|
||||
// Multiple steps: auto-batch consecutive read-safe steps in parallel;
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ func (e *Server) runStage(ctx context.Context, idx int, stage CodeStep, timeout
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return e.executeWithStdin(ctx, code, lang, timeout, sandboxName, trusted, stdinData)
|
||||
return e.executeWithStdin(ctx, code, lang, timeout, sandboxName, trusted, stdinData, stage.Detach)
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("stage %d: requires code, tool, or parallel", idx)
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ No stdout chaining between steps — use pipe for that.
|
|||
Each step is one of:
|
||||
- {code, language} — inline code (default language: bash)
|
||||
- {elevated: true, code} — run outside sandbox via elevation backend (bash only)
|
||||
- {detach: true, code} — start process and immediately background it; returns PID
|
||||
- {parallel: [{code/language}...]} — concurrent fan-out; outputs concatenated in submission order
|
||||
|
||||
Supported languages: bash, python3, perl, lua, awk, sed, jq, ed, expect, bc.
|
||||
|
|
@ -179,6 +180,7 @@ Examples:
|
|||
"code": {"type": "string", "description": "Inline code to execute."},
|
||||
"language": {"type": "string", "description": "Language interpreter (default: bash)."},
|
||||
"elevated": {"type": "boolean", "description": "Run outside the sandbox via the elevation backend. Only bash is supported."},
|
||||
"detach": {"type": "boolean", "description": "Start the process and immediately background it. Returns the PID. Use process_list/process_output to inspect."},
|
||||
"parallel": {
|
||||
"type": "array",
|
||||
"description": "Fan-out: steps run concurrently, outputs concatenated in submission order.",
|
||||
|
|
@ -486,7 +488,7 @@ func (e *Server) Execute(ctx context.Context, code, language string, timeout int
|
|||
|
||||
// executeWithStdin is like Execute but feeds stdinData to the command's stdin.
|
||||
// For languages where code is itself passed via stdin (ed, expect, bc), stdinData is ignored.
|
||||
func (e *Server) executeWithStdin(ctx context.Context, code, language string, timeout int, sandboxName string, trusted bool, stdinData string) (string, error) {
|
||||
func (e *Server) executeWithStdin(ctx context.Context, code, language string, timeout int, sandboxName string, trusted bool, stdinData string, detach ...bool) (string, error) {
|
||||
if timeout < 0 {
|
||||
timeout = 30
|
||||
}
|
||||
|
|
@ -640,6 +642,11 @@ func (e *Server) executeWithStdin(ctx context.Context, code, language string, ti
|
|||
return "", fmt.Errorf("execution failed: %v", err)
|
||||
}
|
||||
|
||||
// If detach requested, immediately signal the detach channel
|
||||
if len(detach) > 0 && detach[0] {
|
||||
close(detachCh)
|
||||
}
|
||||
|
||||
// Wait for completion, context cancellation, or detach signal
|
||||
waitCh := make(chan error, 1)
|
||||
go func() { waitCh <- cmd.Wait() }()
|
||||
|
|
|
|||
Reference in New Issue