# Agent networks

> **Deprecated — Use supervisor agents:** Agent networks are deprecated and will be removed in a future major release. [Supervisor agents](https://mastra.ai/docs/agents/supervisor-agents) using `agent.stream()` or `agent.generate()` are now the recommended approach. It provides the same multi-agent coordination with better control, a simpler API, and easier debugging.
>
> See the [migration guide](https://mastra.ai/guides/migrations/network-to-supervisor) to upgrade.

A **routing agent** uses an LLM to interpret a request and decide which primitives (subagents, workflows, or tools) to call, in what order, and with what data.

## Create an agent network

Configure a routing agent with `agents`, `workflows`, and `tools`. Memory is required as `.network()` uses it to store task history and determine when a task is complete.

Each primitive needs a clear `description` so the routing agent can decide which to use. For workflows and tools, `inputSchema` and `outputSchema` also help the router determine the right inputs.

```typescript
import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'
import { LibSQLStore } from '@mastra/libsql'

import { researchAgent } from './research-agent'
import { writingAgent } from './writing-agent'
import { cityWorkflow } from '../workflows/city-workflow'
import { weatherTool } from '../tools/weather-tool'

export const routingAgent = new Agent({
  id: 'routing-agent',
  name: 'Routing Agent',
  instructions: `
    You are a network of writers and researchers. The user will ask you to research a topic. Always respond with a complete report—no bullet points. Write in full paragraphs, like a blog post. Do not answer with incomplete or uncertain information.`,
  model: 'openai/gpt-5.4',
  agents: {
    researchAgent,
    writingAgent,
  },
  workflows: {
    cityWorkflow,
  },
  tools: {
    weatherTool,
  },
  memory: new Memory({
    storage: new LibSQLStore({
      id: 'mastra-storage',
      url: 'file:../mastra.db',
    }),
  }),
})
```

> **Note:** Subagents need a `description` on the `Agent` instance. Workflows and tools need a `description` plus `inputSchema` and `outputSchema` on `createWorkflow()` or `createTool()`.

## Call the network

Call `.network()` with a user message. The method returns a stream of events you can iterate over.

```typescript
const result = await routingAgent.network('Tell me three cool ways to use Mastra')

for await (const chunk of result) {
  console.log(chunk.type)
  if (chunk.type === 'network-execution-event-step-finish') {
    console.log(chunk.payload.result)
  }
}
```

## Structured output

Pass `structuredOutput` to get typed, validated results. Use `objectStream` for partial objects as they generate.

```typescript
import { z } from 'zod'

const resultSchema = z.object({
  summary: z.string().describe('A brief summary of the findings'),
  recommendations: z.array(z.string()).describe('List of recommendations'),
  confidence: z.number().min(0).max(1).describe('Confidence score'),
})

const stream = await routingAgent.network('Research AI trends', {
  structuredOutput: { schema: resultSchema },
})

for await (const partial of stream.objectStream) {
  console.log('Building result:', partial)
}

const final = await stream.object
console.log(final?.summary)
```

## Approve and decline tool calls

When a primitive requires approval, the stream emits an `agent-execution-approval` or `tool-execution-approval` chunk. Use `approveNetworkToolCall()` or `declineNetworkToolCall()` to respond.

Network approval uses snapshots to capture execution state. Ensure a [storage provider](https://mastra.ai/docs/memory/storage) is enabled in your Mastra instance.

```typescript
const stream = await routingAgent.network('Perform some sensitive action', {
  memory: {
    thread: 'user-123',
    resource: 'my-app',
  },
})

for await (const chunk of stream) {
  if (chunk.type === 'agent-execution-approval' || chunk.type === 'tool-execution-approval') {
    // Approve
    const approvedStream = await routingAgent.approveNetworkToolCall(chunk.payload.toolCallId, {
      runId: stream.runId,
      memory: { thread: 'user-123', resource: 'my-app' },
    })

    for await (const c of approvedStream) {
      if (c.type === 'network-execution-event-step-finish') {
        console.log(c.payload.result)
      }
    }
  }
}
```

To decline instead, call `declineNetworkToolCall()` with the same arguments.

## Suspend and resume

When a primitive calls `suspend()`, the stream emits a suspension chunk (e.g., `tool-execution-suspended`). Use `resumeNetwork()` to provide the requested data and continue execution.

```typescript
const stream = await routingAgent.network('Delete the old records', {
  memory: { thread: 'user-123', resource: 'my-app' },
})

for await (const chunk of stream) {
  if (chunk.type === 'workflow-execution-suspended') {
    console.log(chunk.payload.suspendPayload)
  }
}

// Resume with user confirmation
const resumedStream = await routingAgent.resumeNetwork(
  { confirmed: true },
  {
    runId: stream.runId,
    memory: { thread: 'user-123', resource: 'my-app' },
  },
)

for await (const chunk of resumedStream) {
  if (chunk.type === 'network-execution-event-step-finish') {
    console.log(chunk.payload.result)
  }
}
```

### Automatic resumption

Set `autoResumeSuspendedTools` to `true` so the network resumes suspended primitives based on the user's next message. This creates a conversational flow where users provide the required information naturally.

```typescript
const stream = await routingAgent.network('Delete the old records', {
  autoResumeSuspendedTools: true,
  memory: { thread: 'user-123', resource: 'my-app' },
})
```

Requirements for automatic resumption:

- **Memory configured**: The agent needs memory to track suspended tools across messages.
- **Same thread**: The follow-up message must use the same `thread` and `resource` identifiers.
- **`resumeSchema` defined**: The tool must define a `resumeSchema` so the network can extract data from the user's message.

|          | Manual (`resumeNetwork`)                       | Automatic (`autoResumeSuspendedTools`)    |
| -------- | ---------------------------------------------- | ----------------------------------------- |
| Best for | Custom UIs with approval buttons               | Chat-style interfaces                     |
| Control  | Full control over resume timing and data       | Network extracts data from user's message |
| Setup    | Handle suspension chunks, call `resumeNetwork` | Set flag, define `resumeSchema` on tools  |

## Related

- [Supervisor agents](https://mastra.ai/docs/agents/supervisor-agents)
- [Migration: `.network()` to supervisor agents](https://mastra.ai/guides/migrations/network-to-supervisor)