github.com/anthropics/anthropic-sdk-go@v1.70.1/packages/ssestream/ssestream.go (about) 1 // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 3 package ssestream 4 5 import ( 6 "bufio" 7 "bytes" 8 "encoding/json" 9 "fmt" 10 "io" 11 "net/http" 12 "strings" 13 14 "github.com/anthropics/anthropic-sdk-go/internal/apierror" 15 ) 16 17 type Decoder interface { 18 Event() Event 19 Next() bool 20 Close() error 21 Err() error 22 } 23 24 func NewDecoder(res *http.Response) Decoder { 25 if res == nil || res.Body == nil { 26 return nil 27 } 28 29 var decoder Decoder 30 contentType := res.Header.Get("content-type") 31 if t, ok := decoderTypes[contentType]; ok { 32 decoder = t(res.Body) 33 } else { 34 scn := bufio.NewScanner(res.Body) 35 scn.Buffer(nil, bufio.MaxScanTokenSize<<9) 36 decoder = &eventStreamDecoder{rc: res.Body, scn: scn} 37 } 38 39 // richDecoder needs the http request to provide helpful errors 40 // Aside from the error case there should be no difference 41 // from the underlying decoder. 42 if res.Request != nil { 43 return richErrorDecoder{Decoder: decoder, resp: res} 44 } 45 46 return decoder 47 } 48 49 // richErrorDecoder wraps a Decoder and carries the original [*http.Response] 50 // so that it can construct rich API errors from SSE error events. 51 // 52 // A richErrorDecoder is used by [Stream] to construct errors whenever possible. 53 // [Stream] needs to rely on the underlying decoder, because the [Stream] has 54 // no access to the original http request. 55 // 56 // There should be no other differences from the underlying decoder. 57 type richErrorDecoder struct { 58 Decoder 59 resp *http.Response 60 } 61 62 func (d *richErrorDecoder) newAPIError(errorJSON []byte) error { 63 aerr := &apierror.Error{} 64 if d.resp != nil { 65 aerr.Request = d.resp.Request 66 aerr.Response = d.resp 67 aerr.StatusCode = d.resp.StatusCode 68 aerr.RequestID = d.resp.Header.Get("request-id") 69 aerr.WorkspaceID = d.resp.Header.Get("anthropic-workspace-id") 70 } 71 if aerr.UnmarshalJSON(errorJSON) != nil { 72 return fmt.Errorf("received error while streaming: %s", string(errorJSON)) 73 } 74 return aerr 75 } 76 77 var decoderTypes = map[string](func(io.ReadCloser) Decoder){} 78 79 func RegisterDecoder(contentType string, decoder func(io.ReadCloser) Decoder) { 80 decoderTypes[strings.ToLower(contentType)] = decoder 81 } 82 83 type Event struct { 84 Type string 85 Data []byte 86 } 87 88 // A base implementation of a Decoder for text/event-stream. 89 type eventStreamDecoder struct { 90 evt Event 91 rc io.ReadCloser 92 scn *bufio.Scanner 93 err error 94 } 95 96 func (s *eventStreamDecoder) Next() bool { 97 if s.err != nil { 98 return false 99 } 100 101 event := "" 102 data := bytes.NewBuffer(nil) 103 104 for s.scn.Scan() { 105 txt := s.scn.Bytes() 106 107 // Dispatch event on an empty line 108 if len(txt) == 0 { 109 s.evt = Event{ 110 Type: event, 111 Data: data.Bytes(), 112 } 113 return true 114 } 115 116 // Split a string like "event: bar" into name="event" and value=" bar". 117 name, value, _ := bytes.Cut(txt, []byte(":")) 118 119 // Consume an optional space after the colon if it exists. 120 if len(value) > 0 && value[0] == ' ' { 121 value = value[1:] 122 } 123 124 switch string(name) { 125 case "": 126 // An empty line in the for ": something" is a comment and should be ignored. 127 continue 128 case "event": 129 event = string(value) 130 case "data": 131 _, s.err = data.Write(value) 132 if s.err != nil { 133 break 134 } 135 _, s.err = data.WriteRune('\n') 136 if s.err != nil { 137 break 138 } 139 } 140 } 141 142 if s.scn.Err() != nil { 143 s.err = s.scn.Err() 144 } 145 146 return false 147 } 148 149 func (s *eventStreamDecoder) Event() Event { 150 return s.evt 151 } 152 153 func (s *eventStreamDecoder) Close() error { 154 return s.rc.Close() 155 } 156 157 func (s *eventStreamDecoder) Err() error { 158 return s.err 159 } 160 161 type Stream[T any] struct { 162 decoder Decoder 163 cur T 164 err error 165 } 166 167 func NewStream[T any](decoder Decoder, err error) *Stream[T] { 168 return &Stream[T]{ 169 decoder: decoder, 170 err: err, 171 } 172 } 173 174 // Next returns false if the stream has ended or an error occurred. 175 // Call Stream.Current() to get the current value. 176 // Call Stream.Err() to get the error. 177 // 178 // for stream.Next() { 179 // data := stream.Current() 180 // } 181 // 182 // if stream.Err() != nil { 183 // ... 184 // } 185 func (s *Stream[T]) Next() bool { 186 if s.err != nil { 187 return false 188 } 189 190 for s.decoder.Next() { 191 switch s.decoder.Event().Type { 192 case "completion": 193 var nxt T 194 s.err = json.Unmarshal(s.decoder.Event().Data, &nxt) 195 if s.err != nil { 196 return false 197 } 198 s.cur = nxt 199 return true 200 case "message_start", "message_delta", "message_stop", "content_block_start", "content_block_delta", "content_block_stop", "message", "user.message", "user.interrupt", "user.tool_confirmation", "user.custom_tool_result", "user.tool_result", "agent.message", "agent.thinking", "agent.tool_use", "agent.tool_result", "agent.mcp_tool_use", "agent.mcp_tool_result", "agent.custom_tool_use", "agent.thread_context_compacted", "session.status_running", "session.status_idle", "session.status_rescheduled", "session.status_terminated", "session.error", "session.deleted", "session.updated", "span.model_request_start", "span.model_request_end", "span.outcome_evaluation_start", "span.outcome_evaluation_ongoing", "span.outcome_evaluation_end", "user.define_outcome", "agent.thread_message_received", "agent.thread_message_sent", "agent.session_thread_message_received", "agent.session_thread_message_sent", "session.thread_created", "session.thread_status_created", "session.thread_status_running", "session.thread_status_idle", "session.thread_status_rescheduled", "session.thread_status_terminated", "event_start", "event_delta", "system.message": 201 var nxt T 202 s.err = json.Unmarshal(s.decoder.Event().Data, &nxt) 203 if s.err != nil { 204 return false 205 } 206 s.cur = nxt 207 return true 208 case "ping": 209 continue 210 case "error": 211 data := s.decoder.Event().Data 212 if ed, ok := s.decoder.(richErrorDecoder); ok { 213 s.err = ed.newAPIError(data) 214 } else { 215 s.err = fmt.Errorf("received error while streaming: %s", string(data)) 216 } 217 return false 218 } 219 } 220 221 // decoder.Next() may be false because of an error 222 s.err = s.decoder.Err() 223 224 return false 225 } 226 227 func (s *Stream[T]) Current() T { 228 return s.cur 229 } 230 231 func (s *Stream[T]) Err() error { 232 return s.err 233 } 234 235 func (s *Stream[T]) Close() error { 236 if s.decoder == nil { 237 // already closed 238 return nil 239 } 240 return s.decoder.Close() 241 }