@@ -54,11 +54,12 @@ func TestStreamReaderReturnsErrTooManyEmptyStreamMessages(t *testing.T) {
54
54
55
55
func TestStreamReaderReturnsErrTestErrorAccumulatorWriteFailed (t * testing.T ) {
56
56
stream := & streamReader [ChatCompletionStreamResponse ]{
57
- reader : bufio .NewReader (bytes .NewReader ([]byte ("\n " ))),
57
+ reader : bufio .NewReader (bytes .NewReader ([]byte ("data: { \" error \" : { \" message \" : \" test error \" }} \n " ))),
58
58
errAccumulator : & utils.DefaultErrorAccumulator {
59
59
Buffer : & test.FailingErrorBuffer {},
60
60
},
61
- unmarshaler : & utils.JSONUnmarshaler {},
61
+ unmarshaler : & utils.JSONUnmarshaler {},
62
+ emptyMessagesLimit : 5 ,
62
63
}
63
64
_ , err := stream .Recv ()
64
65
checks .ErrorIs (t , err , test .ErrTestErrorAccumulatorWriteFailed , "Did not return error when write failed" , err .Error ())
@@ -76,3 +77,125 @@ func TestStreamReaderRecvRaw(t *testing.T) {
76
77
t .Fatalf ("Did not return raw line: %v" , string (rawLine ))
77
78
}
78
79
}
80
+
81
+ func TestStreamReaderParsesErrorEvents (t * testing.T ) {
82
+ // Test case simulating Groq's error event format
83
+ errorEvent := `event: error
84
+ data: {"error":{"message":"Invalid tool_call: tool \"name_unknown\" does not exist.","type":"invalid_request_error","code":"invalid_tool_call"}}
85
+
86
+ `
87
+ stream := & streamReader [ChatCompletionStreamResponse ]{
88
+ reader : bufio .NewReader (bytes .NewReader ([]byte (errorEvent ))),
89
+ errAccumulator : utils .NewErrorAccumulator (),
90
+ unmarshaler : & utils.JSONUnmarshaler {},
91
+ emptyMessagesLimit : 5 ,
92
+ }
93
+
94
+ // Process the error event
95
+ _ , err := stream .Recv ()
96
+ if err == nil {
97
+ t .Fatal ("Expected error but got nil" )
98
+ }
99
+
100
+ // Verify it's an APIError
101
+ apiErr , ok := err .(* APIError )
102
+ if ! ok {
103
+ t .Fatalf ("Expected APIError type but got %T: %v" , err , err )
104
+ }
105
+
106
+ // Verify the error fields are correctly parsed
107
+ if apiErr .Message != "Invalid tool_call: tool \" name_unknown\" does not exist." {
108
+ t .Errorf ("Unexpected error message: %s" , apiErr .Message )
109
+ }
110
+ if apiErr .Type != "invalid_request_error" {
111
+ t .Errorf ("Unexpected error type: %s" , apiErr .Type )
112
+ }
113
+ if apiErr .Code != "invalid_tool_call" {
114
+ t .Errorf ("Unexpected error code: %v" , apiErr .Code )
115
+ }
116
+ }
117
+
118
+ func TestStreamReaderHandlesErrorEventWithExtraData (t * testing.T ) {
119
+ // Test case with error event followed by more data
120
+ errorEvent := `data: {"id":"chatcmpl-123","choices":[{"delta":{"content":"Hello"}}]}
121
+ event: error
122
+ data: {"error":{"message":"Stream interrupted","type":"server_error"}}
123
+ data: [DONE]
124
+ `
125
+ stream := & streamReader [ChatCompletionStreamResponse ]{
126
+ reader : bufio .NewReader (bytes .NewReader ([]byte (errorEvent ))),
127
+ errAccumulator : utils .NewErrorAccumulator (),
128
+ unmarshaler : & utils.JSONUnmarshaler {},
129
+ emptyMessagesLimit : 5 ,
130
+ }
131
+
132
+ // First recv should return the chat completion
133
+ resp , err := stream .Recv ()
134
+ if err != nil {
135
+ t .Fatalf ("First recv failed: %v" , err )
136
+ }
137
+ if resp .ID != "chatcmpl-123" {
138
+ t .Errorf ("Unexpected response ID: %s" , resp .ID )
139
+ }
140
+
141
+ // Second recv should return the error
142
+ _ , err = stream .Recv ()
143
+ if err == nil {
144
+ t .Fatal ("Expected error but got nil" )
145
+ }
146
+
147
+ // Verify it's an APIError
148
+ apiErr , ok := err .(* APIError )
149
+ if ! ok {
150
+ t .Fatalf ("Expected APIError type but got %T: %v" , err , err )
151
+ }
152
+
153
+ if apiErr .Message != "Stream interrupted" {
154
+ t .Errorf ("Unexpected error message: %s" , apiErr .Message )
155
+ }
156
+ }
157
+
158
+ func TestStreamReaderResetsErrorAccumulator (t * testing.T ) {
159
+ // Test that error accumulator is reset after processing an error
160
+ multipleErrors := `event: error
161
+ data: {"error":{"message":"First error","type":"error_type_1"}}
162
+
163
+ event: error
164
+ data: {"error":{"message":"Second error","type":"error_type_2"}}
165
+ `
166
+ stream := & streamReader [ChatCompletionStreamResponse ]{
167
+ reader : bufio .NewReader (bytes .NewReader ([]byte (multipleErrors ))),
168
+ errAccumulator : utils .NewErrorAccumulator (),
169
+ unmarshaler : & utils.JSONUnmarshaler {},
170
+ emptyMessagesLimit : 5 ,
171
+ }
172
+
173
+ // First recv should return the first error
174
+ _ , err1 := stream .Recv ()
175
+ if err1 == nil {
176
+ t .Fatal ("Expected first error but got nil" )
177
+ }
178
+ apiErr1 , ok := err1 .(* APIError )
179
+ if ! ok {
180
+ t .Fatalf ("Expected APIError type but got %T: %v" , err1 , err1 )
181
+ }
182
+ if apiErr1 .Message != "First error" {
183
+ t .Errorf ("Unexpected first error message: %s" , apiErr1 .Message )
184
+ }
185
+
186
+ // Second recv should return the second error (not a concatenation)
187
+ _ , err2 := stream .Recv ()
188
+ if err2 == nil {
189
+ t .Fatal ("Expected second error but got nil" )
190
+ }
191
+ apiErr2 , ok := err2 .(* APIError )
192
+ if ! ok {
193
+ t .Fatalf ("Expected APIError type but got %T: %v" , err2 , err2 )
194
+ }
195
+ if apiErr2 .Message != "Second error" {
196
+ t .Errorf ("Unexpected second error message: %s" , apiErr2 .Message )
197
+ }
198
+ if apiErr2 .Type != "error_type_2" {
199
+ t .Errorf ("Unexpected second error type: %s" , apiErr2 .Type )
200
+ }
201
+ }
0 commit comments