返回 DeepSeek-Reasonix
run_completion.go
根目录 / internal / cli / run_completion.go
1 package cli
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7 "io"
8
9 "reasonix/internal/agent"
10 "reasonix/internal/event"
11 "reasonix/internal/i18n"
12 )
13
14 // reportRunFailure states why a run ended without a result. Text output — which
15 // -p/--print also selects — has nowhere else to carry that: its sink prints the
16 // final response and nothing else, so a failed run exited 1 with an empty
17 // stderr and a half-finished answer. Structured formats encode the failure in
18 // their own payload and need this only when no such sink was built.
19 func reportRunFailure(w io.Writer, format runOutputFormat, structured bool, completion runCompletion, runErr error) {
20 if runErr == nil {
21 return
22 }
23 switch {
24 case format != runOutputText:
25 if !structured {
26 fmt.Fprintln(w, "\n"+i18n.M.ErrorPrefix, runErr)
27 }
28 case completion.isError:
29 fmt.Fprintln(w, "\n"+i18n.M.ErrorPrefix, runErr)
30 default:
31 // A paused run is a reportable outcome, not a failure, and reads better
32 // without the error prefix.
33 fmt.Fprintln(w, "\n"+runErr.Error())
34 }
35 }
36
37 type runCompletion struct {
38 outcome string
39 subtype string
40 // class is the benchmark-facing failure taxonomy. It names which guard or
41 // transport ended the run and never affects the exit code or wire outcome.
42 class string
43 isError bool
44 exitCode int
45 }
46
47 func classifyRunCompletion(err error) runCompletion {
48 if err == nil {
49 return runCompletion{subtype: "success", class: "success"}
50 }
51 var readErr *agent.IncompleteReadError
52 if errors.As(err, &readErr) {
53 return runCompletion{outcome: event.TurnOutcomeIncompleteRead, subtype: event.TurnOutcomeIncompleteRead, class: event.TurnOutcomeIncompleteRead, exitCode: 1}
54 }
55 var pauseErr *agent.RecoveryPauseError
56 if errors.As(err, &pauseErr) {
57 return runCompletion{
58 outcome: event.TurnOutcomeRecoveryPaused,
59 subtype: event.TurnOutcomeRecoveryPaused,
60 class: event.TurnOutcomeRecoveryPaused,
61 exitCode: 0,
62 }
63 }
64 var completionErr *agent.CompletionUncertainError
65 if errors.As(err, &completionErr) {
66 return runCompletion{
67 outcome: event.TurnOutcomeCompletionUncertain,
68 subtype: event.TurnOutcomeCompletionUncertain,
69 class: event.TurnOutcomeCompletionUncertain,
70 exitCode: 1,
71 }
72 }
73 return runCompletion{
74 subtype: "error_during_execution",
75 class: runFailureClass(err),
76 isError: true,
77 exitCode: 1,
78 }
79 }
80
81 func runFailureClass(err error) string {
82 if class := agent.PauseClass(err); class != "" {
83 return class
84 }
85 switch {
86 case errors.Is(err, context.DeadlineExceeded):
87 return "timeout"
88 case errors.Is(err, context.Canceled):
89 return "cancelled"
90 }
91 return "error_during_execution"
92 }
93
93 lines GO