返回 DeepSeek-Reasonix
clientio.go
根目录 / internal / tool / builtin / clientio.go
1 package builtin
2
3 import (
4 "context"
5 "fmt"
6 "time"
7 )
8
9 // FileOverlay lets a host transport (an ACP client editor, say) serve file
10 // content instead of the local disk, so tools see unsaved editor buffers. A
11 // nil overlay or an ok=false answer falls back to direct disk I/O; the overlay
12 // is consulted only after the tool's own path resolution and confinement
13 // checks, so it never widens what a tool may touch.
14 type FileOverlay interface {
15 // ReadTextFile returns the current text of path as the host sees it
16 // (including unsaved changes). ok=false means the host cannot serve this
17 // path and the caller should read the local disk instead.
18 ReadTextFile(ctx context.Context, path string) (content string, ok bool)
19 // WriteTextFile asks the host to write content to path (updating any open
20 // buffer as well as the file). ok=false means the host cannot handle the
21 // write and the caller should write the local disk instead; err is only
22 // meaningful when ok is true.
23 WriteTextFile(ctx context.Context, path, content string) (ok bool, err error)
24 }
25
26 // FileOverlayIdentity is an optional strengthening implemented by transports
27 // that can name the buffer/session serving a read. It prevents observations
28 // from being reused after the host swaps to another unsaved-buffer source.
29 type FileOverlayIdentity interface {
30 FileOverlayIdentity() string
31 }
32
33 // TerminalRunner lets a host transport run a foreground shell command in a
34 // host-owned terminal (the ACP terminal/* methods, say) so the user watches it
35 // live. ok=false means the host cannot run it and the caller should execute
36 // locally; err is only meaningful when ok is true. Runners are only consulted
37 // when the local OS sandbox is not enforcing — a host terminal cannot honor
38 // the local confinement configuration.
39 //
40 // envOverrides, when non-nil, is a small map of environment variables the host
41 // terminal should set for the command (typically TMPDIR/TMP/TEMP for the
42 // session-private temporary directory). Callers must not pass a full host
43 // environment dump — only the overrides Reasonix owns.
44 //
45 // Prefer typed outcomes when possible:
46 // - TerminalExitError for a non-zero process exit (Code is the real exit code)
47 // - TerminalTimeoutError when the host-enforced timeout fired
48 // - context.Canceled / context.DeadlineExceeded for parent cancellation
49 //
50 // Plain fmt.Errorf strings remain accepted for older host runners.
51 type TerminalRunner interface {
52 RunCommand(ctx context.Context, command, cwd string, timeout time.Duration, envOverrides map[string]string) (output string, ok bool, err error)
53 }
54
55 // TerminalExitError is returned by a host TerminalRunner when the command ran
56 // and produced a non-zero exit status. bash.ExecuteDetailed preserves Code on
57 // ShellExecution.ExitCode.
58 type TerminalExitError struct {
59 Code int
60 }
61
62 func (e TerminalExitError) Error() string {
63 return fmt.Sprintf("exit status %d", e.Code)
64 }
65
66 // TerminalTimeoutError is returned when the host terminal killed the command
67 // after the tool-local timeout. bash.ExecuteDetailed maps this to
68 // state=timed_out / failurePhase=timeout.
69 type TerminalTimeoutError struct {
70 Timeout time.Duration
71 }
72
73 func (e TerminalTimeoutError) Error() string {
74 if e.Timeout > 0 {
75 return fmt.Sprintf("command timed out after %s (terminal killed)", e.Timeout)
76 }
77 return "command timed out (terminal killed)"
78 }
79
79 lines GO