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  }