Skip to content

Commit bdbc87d

Browse files
authored
fix: event data adjustment for #749 (#764)
1 parent 2cb61b0 commit bdbc87d

File tree

4 files changed

+62
-45
lines changed

4 files changed

+62
-45
lines changed

.changeset/two-terms-walk.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@openai/agents-core': patch
3+
---
4+
5+
fix: event data adjustment for #749

examples/agent-patterns/agents-as-tools-streaming.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ async function main() {
3636
// When you pass onStream handler, the agent is executed in streaming mode.
3737
onStream: (event) => {
3838
console.log(
39-
`### onStream method streaming event from ${event.agentName} in streaming mode:\n\n` +
39+
`### onStream method streaming event from ${event.agent.name} in streaming mode:\n\n` +
4040
JSON.stringify(event) +
4141
'\n',
4242
);
@@ -47,7 +47,7 @@ async function main() {
4747
/*
4848
billingAgentTool.on('raw_model_stream_event', (event) => {
4949
console.log(
50-
`### on method streaming event from ${event.agentName} in streaming mode:\n\n` +
50+
`### on method streaming event from ${event.agent.name} in streaming mode:\n\n` +
5151
JSON.stringify(event) +
5252
'\n',
5353
);

packages/agents-core/src/agent.ts

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,25 +51,26 @@ type CompletedRunResult<TContext, TAgent extends Agent<TContext, any>> = (
5151

5252
type AgentToolRunOptions<TContext> = Omit<StreamRunOptions<TContext>, 'stream'>;
5353

54-
type AgentToolStreamEvent = {
54+
type AgentToolStreamEvent<TAgent extends Agent<any, any>> = {
5555
// Raw stream event emitted by the nested agent run.
5656
event: RunStreamEvent;
57-
// Convenience metadata so callers can correlate to the invoking tool call/agent.
58-
agentName: string;
59-
toolCallId?: string;
57+
// The agent instance being executed as a tool.
58+
agent: TAgent;
59+
// The tool call item that triggered this nested run (when available).
60+
toolCall?: protocol.FunctionCallItem;
6061
};
61-
type AgentToolEventName = AgentToolStreamEvent['event']['type'] | '*';
62-
type AgentToolEventHandler = (
63-
event: AgentToolStreamEvent,
62+
type AgentToolEventName = RunStreamEvent['type'] | '*';
63+
type AgentToolEventHandler<TAgent extends Agent<any, any>> = (
64+
event: AgentToolStreamEvent<TAgent>,
6465
) => void | Promise<void>;
65-
type AgentTool<TContext> = FunctionTool<
66+
type AgentTool<TContext, TAgent extends Agent<TContext, any>> = FunctionTool<
6667
TContext,
6768
typeof AgentAsToolNeedApprovalSchame
6869
> & {
6970
on: (
7071
name: AgentToolEventName,
71-
handler: AgentToolEventHandler,
72-
) => AgentTool<TContext>;
72+
handler: AgentToolEventHandler<TAgent>,
73+
) => AgentTool<TContext, TAgent>;
7374
};
7475

7576
// Per-process, ephemeral map linking a function tool call to its nested
@@ -566,9 +567,9 @@ export class Agent<
566567
/**
567568
* Optional hook to receive streamed events from the nested agent run.
568569
*/
569-
onStream?: (event: AgentToolStreamEvent) => void | Promise<void>;
570+
onStream?: (event: AgentToolStreamEvent<TAgent>) => void | Promise<void>;
570571
},
571-
): AgentTool<TContext> {
572+
): AgentTool<TContext, TAgent> {
572573
const {
573574
toolName,
574575
toolDescription,
@@ -582,9 +583,9 @@ export class Agent<
582583
// Event handlers are scoped to this agent tool instance and are not shared; we only support registration (no removal) to keep the API surface small.
583584
const eventHandlers = new Map<
584585
AgentToolEventName,
585-
Set<AgentToolEventHandler>
586+
Set<AgentToolEventHandler<TAgent>>
586587
>();
587-
const emitEvent = async (event: AgentToolStreamEvent) => {
588+
const emitEvent = async (event: AgentToolStreamEvent<TAgent>) => {
588589
// We intentionally keep only add semantics (no off) to reduce surface area; handlers are scoped to this agent tool instance.
589590
const specific = eventHandlers.get(event.event.type);
590591
const wildcard = eventHandlers.get('*');
@@ -627,9 +628,8 @@ export class Agent<
627628
...(runOptions ?? {}),
628629
});
629630
const streamPayload = {
630-
agentName: this.name,
631-
// Tool calls should carry IDs, but direct invocation or provider quirks can omit it, so keep this optional.
632-
toolCallId: details?.toolCall?.callId,
631+
agent: this,
632+
toolCall: details?.toolCall,
633633
};
634634

635635
if (shouldStream) {
@@ -682,10 +682,11 @@ export class Agent<
682682
},
683683
});
684684

685-
const agentTool: AgentTool<TContext> = {
685+
const agentTool: AgentTool<TContext, TAgent> = {
686686
...baseTool,
687687
on: (name, handler) => {
688-
const set = eventHandlers.get(name) ?? new Set<AgentToolEventHandler>();
688+
const set =
689+
eventHandlers.get(name) ?? new Set<AgentToolEventHandler<TAgent>>();
689690
set.add(handler);
690691
eventHandlers.set(name, set);
691692
return agentTool;

packages/agents-core/test/agent.test.ts

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -344,18 +344,21 @@ describe('Agent', () => {
344344
expect.objectContaining({ stream: true }),
345345
);
346346
expect(onStream).toHaveBeenCalledTimes(streamEvents.length);
347-
expect(onStream).toHaveBeenCalledWith({
348-
event: streamEvents[0],
349-
agentName: agent.name,
350-
toolCallId: undefined,
351-
});
347+
expect(onStream).toHaveBeenCalledWith(
348+
expect.objectContaining({
349+
event: streamEvents[0],
350+
agent,
351+
toolCall: undefined,
352+
}),
353+
);
352354
});
353355

354-
it('includes toolCallId and agentName when streaming from nested agent tools', async () => {
356+
it('includes toolCall when streaming from nested agent tools', async () => {
355357
const agent = new Agent({
356358
name: 'Streamer Agent',
357359
instructions: 'Stream things.',
358360
});
361+
const toolCall = { callId: 'call-123' } as any;
359362
const streamEvents = [
360363
{ type: 'raw_model_stream_event', data: { type: 'response_started' } },
361364
] as any[];
@@ -392,7 +395,7 @@ describe('Agent', () => {
392395
const output = await tool.invoke(
393396
new RunContext(),
394397
'{"input":"run streaming"}',
395-
{ toolCall: { callId: 'call-123' } as any },
398+
{ toolCall },
396399
);
397400

398401
expect(output).toBe('tool output');
@@ -401,11 +404,13 @@ describe('Agent', () => {
401404
'run streaming',
402405
expect.objectContaining({ stream: true }),
403406
);
404-
expect(onStream).toHaveBeenCalledWith({
405-
agentName: 'Streamer Agent',
406-
event: streamEvents[0],
407-
toolCallId: 'call-123',
408-
});
407+
expect(onStream).toHaveBeenCalledWith(
408+
expect.objectContaining({
409+
agent,
410+
toolCall,
411+
event: streamEvents[0],
412+
}),
413+
);
409414
});
410415

411416
it('supports event handlers registered via on (agent tool only) and wildcard handlers', async () => {
@@ -453,10 +458,11 @@ describe('Agent', () => {
453458

454459
tool.on('raw_model_stream_event', rawHandler).on('*', wildcardHandler);
455460

461+
const toolCall = { callId: 'call-abc' } as any;
456462
const output = await tool.invoke(
457463
new RunContext(),
458464
'{"input":"run streaming"}',
459-
{ toolCall: { callId: 'call-abc' } as any },
465+
{ toolCall },
460466
);
461467

462468
expect(output).toBe('tool output');
@@ -466,11 +472,13 @@ describe('Agent', () => {
466472
expect.objectContaining({ stream: true }),
467473
);
468474
expect(rawHandler).toHaveBeenCalledTimes(1);
469-
expect(rawHandler).toHaveBeenCalledWith({
470-
agentName: 'Streamer Agent',
471-
event: streamEvents[0],
472-
toolCallId: 'call-abc',
473-
});
475+
expect(rawHandler).toHaveBeenCalledWith(
476+
expect.objectContaining({
477+
agent,
478+
toolCall,
479+
event: streamEvents[0],
480+
}),
481+
);
474482
expect(wildcardHandler).toHaveBeenCalledTimes(streamEvents.length);
475483
});
476484

@@ -513,10 +521,11 @@ describe('Agent', () => {
513521

514522
tool.on('raw_model_stream_event', handler);
515523

524+
const toolCall = { callId: 'call-xyz' } as any;
516525
const output = await tool.invoke(
517526
new RunContext(),
518527
'{"input":"run streaming"}',
519-
{ toolCall: { callId: 'call-xyz' } as any },
528+
{ toolCall },
520529
);
521530

522531
expect(output).toBe('tool output');
@@ -525,11 +534,13 @@ describe('Agent', () => {
525534
'run streaming',
526535
expect.objectContaining({ stream: true }),
527536
);
528-
expect(handler).toHaveBeenCalledWith({
529-
agentName: 'Handler Agent',
530-
event: streamEvents[0],
531-
toolCallId: 'call-xyz',
532-
});
537+
expect(handler).toHaveBeenCalledWith(
538+
expect.objectContaining({
539+
agent,
540+
toolCall,
541+
event: streamEvents[0],
542+
}),
543+
);
533544
});
534545

535546
it('filters tools using isEnabled predicates', async () => {

0 commit comments

Comments
 (0)