|
6 | 6 | isOutputLengthError, |
7 | 7 | createAuthenticationError, |
8 | 8 | createAPICallError, |
| 9 | + createEmptyResponseDataError, |
9 | 10 | createTimeoutError, |
10 | 11 | extractErrorMessage, |
11 | 12 | wrapError, |
@@ -240,6 +241,45 @@ describe("errors", () => { |
240 | 241 | }); |
241 | 242 | }); |
242 | 243 |
|
| 244 | + describe("createEmptyResponseDataError", () => { |
| 245 | + it("should create actionable error with model guidance", () => { |
| 246 | + const result = createEmptyResponseDataError(undefined, { |
| 247 | + sessionId: "session-123", |
| 248 | + modelId: "github-copilot/gpt-5", |
| 249 | + }); |
| 250 | + |
| 251 | + expect(result).toBeInstanceOf(APICallError); |
| 252 | + expect(result.message).toContain("OpenCode returned no response data"); |
| 253 | + expect(result.message).toContain('for model "github-copilot/gpt-5"'); |
| 254 | + expect(result.message).toContain("provider/model"); |
| 255 | + expect(result.message).toContain("opencode models"); |
| 256 | + expect(result.isRetryable).toBe(false); |
| 257 | + expect(result.data).toMatchObject({ |
| 258 | + errorType: "EmptyResponseData", |
| 259 | + sessionId: "session-123", |
| 260 | + modelId: "github-copilot/gpt-5", |
| 261 | + }); |
| 262 | + }); |
| 263 | + |
| 264 | + it("should omit model hint when modelId is missing", () => { |
| 265 | + const result = createEmptyResponseDataError(undefined); |
| 266 | + |
| 267 | + expect(result.message).toContain("OpenCode returned no response data"); |
| 268 | + expect(result.message).not.toContain("for model"); |
| 269 | + expect(result.message).not.toContain("Original error"); |
| 270 | + }); |
| 271 | + |
| 272 | + it("should include original error details when available", () => { |
| 273 | + const result = createEmptyResponseDataError( |
| 274 | + { message: "model not found", statusCode: 400 }, |
| 275 | + { modelId: "github-copilot/gpt-5" }, |
| 276 | + ); |
| 277 | + |
| 278 | + expect(result.message).toContain("Original error: model not found"); |
| 279 | + expect(result.statusCode).toBe(400); |
| 280 | + }); |
| 281 | + }); |
| 282 | + |
243 | 283 | describe("createTimeoutError", () => { |
244 | 284 | it("should create timeout error with duration", () => { |
245 | 285 | const result = createTimeoutError(5000); |
@@ -370,5 +410,19 @@ describe("errors", () => { |
370 | 410 | sessionId: "session-123", |
371 | 411 | }); |
372 | 412 | }); |
| 413 | + |
| 414 | + it("should return already-wrapped AI SDK errors unchanged", () => { |
| 415 | + const original = createEmptyResponseDataError(undefined, { |
| 416 | + sessionId: "session-123", |
| 417 | + modelId: "github-copilot/gpt-5", |
| 418 | + }); |
| 419 | + const result = wrapError(original, { sessionId: "other-session" }); |
| 420 | + |
| 421 | + expect(result).toBe(original); |
| 422 | + expect((result as APICallError).data).toMatchObject({ |
| 423 | + errorType: "EmptyResponseData", |
| 424 | + sessionId: "session-123", |
| 425 | + }); |
| 426 | + }); |
373 | 427 | }); |
374 | 428 | }); |
0 commit comments