返回 DeepSeek-Reasonix
goal_diagnostics.go
根目录 / internal / serve / goal_diagnostics.go
1 package serve
2
3 import (
4 "context"
5 "io"
6 "net/http"
7
8 "reasonix/internal/control"
9 )
10
11 type goalDiagnosticExporter interface {
12 ExportGoalDiagnostics(context.Context, control.GoalDiagnosticMetadata) ([]byte, error)
13 }
14
15 type goalDiagnosticStreamExporter interface {
16 WriteGoalDiagnostics(context.Context, io.Writer, control.GoalDiagnosticMetadata) error
17 }
18
19 // goalDiagnostics exports the authoritative, fully flushed v3 event stream.
20 // It is session-fenced but read-only and therefore remains available to a
21 // spectator inspecting a session owned by another Reasonix surface.
22 func (s *Server) goalDiagnostics(w http.ResponseWriter, r *http.Request) {
23 s.bindMu.Lock()
24 defer s.bindMu.Unlock()
25 if !s.validateExpectedSessionLocked(w, r) {
26 return
27 }
28 controller := s.ctl()
29 streamer, streamOK := controller.(goalDiagnosticStreamExporter)
30 exporter, exportOK := controller.(goalDiagnosticExporter)
31 if !streamOK && !exportOK {
32 http.Error(w, "goal diagnostics require goal-lifecycle-v2", http.StatusNotImplemented)
33 return
34 }
35 w.Header().Set("Content-Type", "application/json")
36 w.Header().Set("Content-Disposition", `attachment; filename="reasonix-goal-diagnostics.json"`)
37 metadata := control.GoalDiagnosticMetadata{Capabilities: s.capabilities()}
38 if streamOK {
39 if err := streamer.WriteGoalDiagnostics(r.Context(), w, metadata); err != nil {
40 // The response may already contain a valid prefix. Closing the body is
41 // the only honest signal once streaming has started; never append a
42 // second JSON error document to the artifact.
43 return
44 }
45 return
46 }
47 payload, err := exporter.ExportGoalDiagnostics(r.Context(), metadata)
48 if err != nil {
49 http.Error(w, err.Error(), http.StatusConflict)
50 return
51 }
52 _, _ = w.Write(payload)
53 }
54
54 lines GO