返回 DeepSeek-Reasonix
run_sink.go
根目录 / internal / cli / run_sink.go
1 package cli
2
3 import (
4 "os"
5 "time"
6
7 "golang.org/x/term"
8
9 "reasonix/internal/agent"
10 "reasonix/internal/config"
11 "reasonix/internal/event"
12 "reasonix/internal/telemetry"
13 "reasonix/internal/trajectory"
14 )
15
16 // runSinkChain is the assembled event pipeline for one `run` invocation, with
17 // handles to the decorators the command must finalize after the run.
18 type runSinkChain struct {
19 sink event.Sink
20 resultOutput *runOutputSink
21 metrics *metricsSink
22 trajectory *trajectory.Recorder
23 }
24
25 // buildRunSink assembles `run`'s sink chain: stdout rendering innermost, then
26 // metrics accumulation, then trajectory recording, then notifications and the
27 // telemetry reporter outermost. Markdown post-stream redraw (cursor moves) is
28 // enabled only on a TTY; piped / captured output keeps the raw stream.
29 func buildRunSink(format runOutputFormat, printOnly, showThinking bool, metricsPath, trajectoryPath string, cfg *config.Config, reporter *telemetry.Reporter) (runSinkChain, error) {
30 var chain runSinkChain
31 if printOnly || format != runOutputText {
32 chain.resultOutput = newRunOutputSink(os.Stdout, format)
33 chain.sink = chain.resultOutput
34 } else {
35 var renderer agent.Renderer
36 termW := 80
37 if isTTY(os.Stdout) {
38 if w, _, err := term.GetSize(int(os.Stdout.Fd())); err == nil && w > 0 {
39 termW = w
40 }
41 renderer = newMarkdownRenderer(termW)
42 }
43 textSink := agent.NewTextSink(os.Stdout, renderer, termW)
44 textSink.SetShowReasoning(showThinking)
45 chain.sink = textSink
46 }
47 if metricsPath != "" {
48 chain.metrics = &metricsSink{
49 inner: chain.sink,
50 partialPath: partialMetricsPath(metricsPath),
51 snapshotEvery: 2 * time.Second,
52 }
53 chain.sink = chain.metrics
54 }
55 if trajectoryPath != "" {
56 rec, err := trajectory.New(chain.sink, trajectoryPath, nil)
57 if err != nil {
58 return runSinkChain{}, err
59 }
60 chain.trajectory = rec
61 chain.sink = rec
62 }
63 chain.sink = withNotifications(chain.sink, cfg)
64 chain.sink = reporter.Wrap(chain.sink)
65 return chain, nil
66 }
67
67 lines GO