When we started Mastra during YCombinator, we knew multi-agent coordination needed to be a core primitive. That first night, Sam, Shane, and I hacked together the initial version of what we called AgentNetwork
. It was rough, but it got us thinking about what multi-agent systems actually need.
The initial approach was straightforward but flawed. We used our Agent
primitive and gave each Agent
tools, letting the LLM decide everything. The instructions were entirely on the user to write, tool execution didn't bubble up into the main stream. The whole thing was pretty whack in the playground.
A few months later, Tony and I flew to Japan to meet with the amazing developer community out there. During that trip, between meetings and late-night coding sessions, we realized we needed a more structured approach to this multi-agent problem.
So we pivoted. We started using Mastra's workflow primitive as the foundation for the multi-agent loop, introducing NewAgentNetwork
as another strategy. This new network design looked like this:
We really liked this design because it introduced an explicit reasoning step through a "routing agent" and built-in execution loops that ran until task completion - all powered by Mastra workflows.
In Playground, it looked like this:
The Final Evolution: .network()
After adopting our agent loop within the Agent primitive itself, we made a bold decision: integrate the network behavior directly into the Agent primitive. The entire network API could be part of the Agent class.
So we deprecated AgentNetwork
and NewAgentNetwork
in favor of a simple .network()
method on the Agent class.
When you call .network()
, you transform your agent into a routing agent. Based on the primitives you pass in (tools, workflows, agents), the agent loop automatically goes through a reasoning step before delegating to the appropriate primitive:
1import { Agent } from '@mastra/core/agent';
2import { openai } from '@ai-sdk/openai';
3import { agent1, agent2 } from './agents';
4import { workflow1 } from './workflows';
5import { tool1, tool2 } from './tools';
6
7const agent = new Agent({
8 name: 'network-agent',
9 instructions: 'You are a network agent that can help users with a variety of tasks.',
10 model: openai('gpt-4o'),
11 agents: {
12 agent1,
13 agent2,
14 },
15 workflows: {
16 workflow1,
17 },
18 tools: {
19 tool1,
20 tool2,
21 },
22})
23
24await agent.network(`
25 Find me the weather in Tokyo.
26 Based on the weather, plan an activity for me.
27`);
Now the routing happens automatically. Your agent reasons about the task, decides which tools, workflows, or sub-agents to engage, and orchestrates the entire execution flow.
This evolution from separate AgentNetwork
classes to a unified .network()
method ended up being a natural fit. We love powerful primitives that compose naturally. You don't need to learn a separate networking API - just add .network()
to any agent.