Skip to content

Commit 2a77585

Browse files
authored
fix(agents-extensions): improve AI (#740)
1 parent dd1a813 commit 2a77585

File tree

3 files changed

+147
-12
lines changed

3 files changed

+147
-12
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@openai/agents-extensions': patch
3+
---
4+
5+
Improve AI SDK error messages in tracing to include comprehensive error details like responseBody, statusCode, and responseHeaders when tracing is enabled.

packages/agents-extensions/src/aiSdk.ts

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -784,22 +784,38 @@ export class AiSdkModel implements Model {
784784
data: {
785785
error:
786786
request.tracing === true
787-
? String(error)
788-
: error instanceof Error
789-
? error.name
790-
: undefined,
787+
? {
788+
name: error.name,
789+
message: error.message,
790+
// Include AI SDK specific error fields if they exist.
791+
...(typeof error === 'object' && error !== null
792+
? {
793+
...('responseBody' in error
794+
? { responseBody: (error as any).responseBody }
795+
: {}),
796+
...('responseHeaders' in error
797+
? {
798+
responseHeaders: (error as any)
799+
.responseHeaders,
800+
}
801+
: {}),
802+
...('statusCode' in error
803+
? { statusCode: (error as any).statusCode }
804+
: {}),
805+
...('cause' in error
806+
? { cause: (error as any).cause }
807+
: {}),
808+
}
809+
: {}),
810+
}
811+
: error.name,
791812
},
792813
});
793814
} else {
794815
span.setError({
795816
message: 'Unknown error',
796817
data: {
797-
error:
798-
request.tracing === true
799-
? String(error)
800-
: error instanceof Error
801-
? error.name
802-
: undefined,
818+
error: request.tracing === true ? String(error) : undefined,
803819
},
804820
});
805821
}
@@ -999,11 +1015,37 @@ export class AiSdkModel implements Model {
9991015
} catch (error) {
10001016
if (span) {
10011017
span.setError({
1002-
message: 'Error streaming response',
1018+
message:
1019+
error instanceof Error ? error.message : 'Error streaming response',
10031020
data: {
10041021
error:
10051022
request.tracing === true
1006-
? String(error)
1023+
? error instanceof Error
1024+
? {
1025+
name: error.name,
1026+
message: error.message,
1027+
// Include AI SDK specific error fields if they exist.
1028+
...(typeof error === 'object' && error !== null
1029+
? {
1030+
...('responseBody' in error
1031+
? { responseBody: (error as any).responseBody }
1032+
: {}),
1033+
...('responseHeaders' in error
1034+
? {
1035+
responseHeaders: (error as any)
1036+
.responseHeaders,
1037+
}
1038+
: {}),
1039+
...('statusCode' in error
1040+
? { statusCode: (error as any).statusCode }
1041+
: {}),
1042+
...('cause' in error
1043+
? { cause: (error as any).cause }
1044+
: {}),
1045+
}
1046+
: {}),
1047+
}
1048+
: String(error)
10071049
: error instanceof Error
10081050
? error.name
10091051
: undefined,

packages/agents-extensions/test/aiSdk.test.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,4 +1376,92 @@ describe('AiSdkModel', () => {
13761376
expect(parseArguments('{"a":1,"b":"c"}')).toEqual({ a: 1, b: 'c' });
13771377
});
13781378
});
1379+
1380+
describe('Error handling with tracing', () => {
1381+
test('captures comprehensive AI SDK error details when tracing enabled', async () => {
1382+
// Simulate an AI SDK error with responseBody and other fields.
1383+
const aiSdkError = new Error('API call failed');
1384+
aiSdkError.name = 'AI_APICallError';
1385+
(aiSdkError as any).responseBody = {
1386+
error: {
1387+
message: 'Rate limit exceeded',
1388+
code: 'rate_limit_exceeded',
1389+
type: 'insufficient_quota',
1390+
},
1391+
};
1392+
(aiSdkError as any).responseHeaders = {
1393+
'x-request-id': 'req_abc123',
1394+
'retry-after': '60',
1395+
};
1396+
(aiSdkError as any).statusCode = 429;
1397+
1398+
const model = new AiSdkModel(
1399+
stubModel({
1400+
async doGenerate() {
1401+
throw aiSdkError;
1402+
},
1403+
}),
1404+
);
1405+
1406+
try {
1407+
await withTrace('test-trace', () =>
1408+
model.getResponse({
1409+
input: 'test input',
1410+
tools: [],
1411+
handoffs: [],
1412+
modelSettings: {},
1413+
outputType: 'text',
1414+
tracing: true,
1415+
} as any),
1416+
);
1417+
expect.fail('Should have thrown error');
1418+
} catch (error: any) {
1419+
// Error should be re-thrown.
1420+
expect(error.message).toBe('API call failed');
1421+
// Verify error has the AI SDK fields.
1422+
expect((error as any).responseBody).toBeDefined();
1423+
expect((error as any).statusCode).toBe(429);
1424+
}
1425+
});
1426+
1427+
test('propagates error with AI SDK fields in streaming mode', async () => {
1428+
const aiSdkError = new Error('Stream failed');
1429+
aiSdkError.name = 'AI_StreamError';
1430+
(aiSdkError as any).responseBody = {
1431+
error: { message: 'Connection timeout', code: 'timeout' },
1432+
};
1433+
(aiSdkError as any).statusCode = 504;
1434+
1435+
const model = new AiSdkModel(
1436+
stubModel({
1437+
async doStream() {
1438+
throw aiSdkError;
1439+
},
1440+
}),
1441+
);
1442+
1443+
try {
1444+
await withTrace('test-stream', async () => {
1445+
const iter = model.getStreamedResponse({
1446+
input: 'test',
1447+
tools: [],
1448+
handoffs: [],
1449+
modelSettings: {},
1450+
outputType: 'text',
1451+
tracing: true,
1452+
} as any);
1453+
1454+
for await (const _ of iter) {
1455+
// Should not get here.
1456+
}
1457+
});
1458+
expect.fail('Should have thrown error');
1459+
} catch (error: any) {
1460+
expect(error.message).toBe('Stream failed');
1461+
// Verify error has the AI SDK fields.
1462+
expect((error as any).responseBody).toBeDefined();
1463+
expect((error as any).statusCode).toBe(504);
1464+
}
1465+
});
1466+
});
13791467
});

0 commit comments

Comments
 (0)