WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit c6fd6fe

Browse files
authored
fix(agent): pass toolCallId in context.agent for network tool execution (#10951)
**Critical Issue**: When tools are executed through the agent network, the `context.agent.toolCallId` property is **undefined** despite being required by the TypeScript type definitions. This creates a type safety gap where the runtime behavior does not match the type contract. ### Type Definition vs Implementation Mismatch The `AgentToolExecutionContext` type (from `packages/core/src/tools/types.ts`) defines toolCallId as a required string property: ```typescript export interface AgentToolExecutionContext { toolCallId: string; // ← Required, non-optional messages: any[]; threadId?: string; resourceId?: string; } ``` However, when tools execute through the network loop, `toolCallId` was never passed to the context, violating the type contract and leaving tools without access to a critical identifier. ### The Fix This PR brings the runtime implementation into alignment with TypeScript type definitions by passing the `toolCallId` generated during network tool execution through to `context.agent`. Tools can now reliably access: - `context.agent.toolCallId` - Unique identifier for this tool call - `context.agent.threadId` - Memory thread identifier - `context.agent.resourceId` - Memory resource identifier All three properties now properly propagate through network execution, matching their type definitions. ## Related Issue(s) Brings runtime implementation into alignment with type definitions for AgentToolExecutionContext ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Code refactoring - [ ] Performance improvement - [ ] Test update ## Checklist - [x] I have made corresponding changes to the documentation (if applicable) - [x] I have added tests that prove my fix is effective or that my feature works <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Added validation tests to confirm tools receive a complete agent context (including call identifiers) during network execution. * **Improvements** * Tools now receive the call identifier (toolCallId) in their execution context for improved tracking and visibility at runtime. * **Chores** * Recorded a patch changeset documenting the fix. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 0364624 commit c6fd6fe

File tree

3 files changed

+91
-1
lines changed

3 files changed

+91
-1
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@mastra/core': patch
3+
---
4+
5+
Fix toolCallId propagation in agent network tool execution. The toolCallId property was undefined at runtime despite being required by TypeScript type definitions in AgentToolExecutionContext. Now properly passes the toolCallId through to the tool's context during network tool execution.

packages/core/src/agent/agent-network.test.ts

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { openai } from '@ai-sdk/openai-v5';
2-
import { describe, expect, it } from 'vitest';
2+
import { MockLanguageModelV2, convertArrayToReadableStream } from 'ai-v5/test';
3+
import { describe, expect, it, vi } from 'vitest';
34
import { z } from 'zod';
45
import { MastraError } from '../error';
56
import { MockMemory } from '../memory/mock';
@@ -697,3 +698,86 @@ describe('Agent - network - updateWorkingMemory', () => {
697698
expect(thread?.resourceId).toBe(resourceId);
698699
});
699700
}, 120e3);
701+
702+
describe('Agent - network - tool context validation', () => {
703+
it('should pass toolCallId, threadId, and resourceId in context.agent when network executes a tool', async () => {
704+
const mockExecute = vi.fn(async (_inputData, _context) => {
705+
return { result: 'context captured' };
706+
});
707+
708+
const tool = createTool({
709+
id: 'context-check-tool',
710+
description: 'Tool to validate context.agent properties from network',
711+
inputSchema: z.object({
712+
message: z.string(),
713+
}),
714+
execute: mockExecute,
715+
});
716+
717+
// Mock model returns routing agent selection schema
718+
// The network's routing agent uses structuredOutput expecting: { primitiveId, primitiveType, prompt, selectionReason }
719+
const routingResponse = JSON.stringify({
720+
primitiveId: 'tool',
721+
primitiveType: 'tool',
722+
prompt: JSON.stringify({ message: 'validate context' }),
723+
selectionReason: 'Test context propagation through network',
724+
});
725+
726+
const mockModel = new MockLanguageModelV2({
727+
doGenerate: async () => ({
728+
rawCall: { rawPrompt: null, rawSettings: {} },
729+
finishReason: 'stop',
730+
usage: { inputTokens: 10, outputTokens: 20, totalTokens: 30 },
731+
content: [{ type: 'text', text: routingResponse }],
732+
warnings: [],
733+
}),
734+
doStream: async () => ({
735+
stream: convertArrayToReadableStream([
736+
{ type: 'stream-start', warnings: [] },
737+
{ type: 'response-metadata', id: 'id-0', modelId: 'mock-model-id', timestamp: new Date(0) },
738+
{ type: 'text-delta', id: 'id-0', delta: routingResponse },
739+
{ type: 'finish', finishReason: 'stop', usage: { inputTokens: 10, outputTokens: 20, totalTokens: 30 } },
740+
]),
741+
}),
742+
});
743+
744+
const memory = new MockMemory();
745+
746+
const agent = new Agent({
747+
id: 'context-network-agent',
748+
name: 'Context Test Network',
749+
instructions: 'Use the context-check-tool to validate context properties.',
750+
model: mockModel,
751+
tools: { tool },
752+
memory,
753+
});
754+
755+
const threadId = 'context-test-thread';
756+
const resourceId = 'context-test-resource';
757+
758+
const anStream = await agent.network('Validate context by using the context-check-tool', {
759+
memory: {
760+
thread: threadId,
761+
resource: resourceId,
762+
},
763+
});
764+
765+
// Consume the stream to trigger tool execution through network
766+
for await (const _chunk of anStream) {
767+
// Stream events are processed
768+
}
769+
770+
// Verify the tool was called with context containing toolCallId, threadId, and resourceId
771+
expect(mockExecute).toHaveBeenCalled();
772+
expect(mockExecute).toHaveBeenCalledWith(
773+
expect.objectContaining({ message: 'validate context' }),
774+
expect.objectContaining({
775+
agent: expect.objectContaining({
776+
toolCallId: expect.any(String),
777+
threadId,
778+
resourceId,
779+
}),
780+
}),
781+
);
782+
});
783+
});

packages/core/src/loop/network/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,7 @@ export async function createNetworkLoop({
957957
mastra: agent.getMastraInstance(),
958958
agent: {
959959
resourceId: initData.threadResourceId || networkName,
960+
toolCallId,
960961
threadId: initData.threadId,
961962
},
962963
runId,

0 commit comments

Comments
 (0)