返回 DeepSeek-Reasonix
sink.go
根目录 / internal / event / sink.go
1 package event
2
3 import "reasonix/internal/nilutil"
4
5 // Sink consumes a turn's events. The agent calls Emit serially from its run
6 // loop (tool execution may fan out across goroutines, but emission does not),
7 // so an implementation need not be safe for concurrent Emit. Emit must not
8 // block indefinitely — a channel-backed sink should be buffered or drained by
9 // a live reader.
10 type Sink interface {
11 Emit(Event)
12 }
13
14 // CheckedSink is an optional durability-aware sink capability. Callers use it
15 // at side-effect boundaries (tool dispatch, user prompts, terminal commits)
16 // where continuing after a local journal failure would make runtime state
17 // impossible to recover safely. Ordinary display-only sinks keep implementing
18 // Sink; EmitChecked falls back to Emit for compatibility.
19 type CheckedSink interface {
20 EmitChecked(Event) error
21 }
22
23 // EmitChecked emits e and returns a durability failure when the sink exposes
24 // CheckedSink. It deliberately does not make every Sink fallible: most event
25 // consumers are renderers, while the session lifecycle decorator is the one
26 // owner that can provide a durable acknowledgement.
27 func EmitChecked(s Sink, e Event) error {
28 if nilutil.IsNil(s) {
29 return nil
30 }
31 if checked, ok := s.(CheckedSink); ok {
32 return checked.EmitChecked(e)
33 }
34 s.Emit(e)
35 return nil
36 }
37
38 // FuncSink adapts a plain function to a Sink.
39 type FuncSink func(Event)
40
41 // Emit calls the wrapped function.
42 func (f FuncSink) Emit(e Event) {
43 if f != nil {
44 f(e)
45 }
46 }
47
48 // Discard is a Sink that drops every event. Useful in tests and for runs that
49 // only care about the final session state.
50 var Discard Sink = FuncSink(func(Event) {})
51
51 lines GO