@mastra/mcp-docs-server 0.13.2-alpha.1 → 0.13.2-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/.docs/organized/changelogs/%40mastra%2Fastra.md +14 -14
  2. package/.docs/organized/changelogs/%40mastra%2Fchroma.md +14 -14
  3. package/.docs/organized/changelogs/%40mastra%2Fclickhouse.md +14 -14
  4. package/.docs/organized/changelogs/%40mastra%2Fclient-js.md +18 -18
  5. package/.docs/organized/changelogs/%40mastra%2Fcloudflare-d1.md +14 -14
  6. package/.docs/organized/changelogs/%40mastra%2Fcloudflare.md +14 -14
  7. package/.docs/organized/changelogs/%40mastra%2Fcore.md +15 -15
  8. package/.docs/organized/changelogs/%40mastra%2Fcouchbase.md +14 -14
  9. package/.docs/organized/changelogs/%40mastra%2Fdeployer-cloudflare.md +20 -20
  10. package/.docs/organized/changelogs/%40mastra%2Fdeployer-netlify.md +24 -24
  11. package/.docs/organized/changelogs/%40mastra%2Fdeployer-vercel.md +24 -24
  12. package/.docs/organized/changelogs/%40mastra%2Fdeployer.md +22 -22
  13. package/.docs/organized/changelogs/%40mastra%2Fdynamodb.md +14 -14
  14. package/.docs/organized/changelogs/%40mastra%2Flance.md +13 -0
  15. package/.docs/organized/changelogs/%40mastra%2Flibsql.md +14 -14
  16. package/.docs/organized/changelogs/%40mastra%2Fmcp-docs-server.md +10 -10
  17. package/.docs/organized/changelogs/%40mastra%2Fmcp.md +9 -9
  18. package/.docs/organized/changelogs/%40mastra%2Fmemory.md +22 -22
  19. package/.docs/organized/changelogs/%40mastra%2Fmongodb.md +14 -14
  20. package/.docs/organized/changelogs/%40mastra%2Fopensearch.md +13 -0
  21. package/.docs/organized/changelogs/%40mastra%2Fpg.md +14 -14
  22. package/.docs/organized/changelogs/%40mastra%2Fpinecone.md +14 -14
  23. package/.docs/organized/changelogs/%40mastra%2Fplayground-ui.md +20 -20
  24. package/.docs/organized/changelogs/%40mastra%2Fqdrant.md +14 -14
  25. package/.docs/organized/changelogs/%40mastra%2Fserver.md +20 -20
  26. package/.docs/organized/changelogs/%40mastra%2Fturbopuffer.md +14 -14
  27. package/.docs/organized/changelogs/%40mastra%2Fupstash.md +14 -14
  28. package/.docs/organized/changelogs/%40mastra%2Fvectorize.md +14 -14
  29. package/.docs/organized/changelogs/mastra.md +22 -22
  30. package/.docs/organized/code-examples/agent.md +182 -5
  31. package/.docs/organized/code-examples/assistant-ui.md +1 -1
  32. package/.docs/organized/code-examples/bird-checker-with-nextjs-and-eval.md +1 -1
  33. package/.docs/organized/code-examples/bird-checker-with-nextjs.md +1 -1
  34. package/.docs/organized/code-examples/crypto-chatbot.md +2 -2
  35. package/.docs/organized/code-examples/openapi-spec-writer.md +1 -1
  36. package/.docs/raw/agents/using-tools-and-mcp.mdx +3 -2
  37. package/.docs/raw/deployment/cloud-providers/digital-ocean.mdx +111 -0
  38. package/.docs/raw/deployment/cloud-providers/index.mdx +15 -0
  39. package/.docs/raw/memory/working-memory.mdx +56 -0
  40. package/.docs/raw/networks-vnext/complex-task-execution.mdx +137 -0
  41. package/.docs/raw/networks-vnext/overview.mdx +85 -0
  42. package/.docs/raw/networks-vnext/single-task-execution.mdx +131 -0
  43. package/.docs/raw/reference/client-js/agents.mdx +41 -0
  44. package/.docs/raw/reference/deployer/netlify.mdx +22 -68
  45. package/.docs/raw/reference/deployer/vercel.mdx +7 -77
  46. package/.docs/raw/reference/tools/mcp-client.mdx +244 -0
  47. package/.docs/raw/reference/tools/mcp-server.mdx +186 -0
  48. package/.docs/raw/reference/workflows/create-run.mdx +1 -1
  49. package/.docs/raw/reference/workflows/resume.mdx +1 -1
  50. package/.docs/raw/reference/workflows/start.mdx +1 -1
  51. package/.docs/raw/reference/workflows/stream.mdx +1 -1
  52. package/.docs/raw/reference/workflows/watch.mdx +1 -1
  53. package/.docs/raw/reference/workflows/workflow.mdx +6 -2
  54. package/.docs/raw/workflows/control-flow.mdx +42 -1
  55. package/.docs/raw/workflows/overview.mdx +73 -5
  56. package/.docs/raw/workflows/pausing-execution.mdx +1 -1
  57. package/.docs/raw/workflows/suspend-and-resume.mdx +68 -23
  58. package/.docs/raw/workflows/using-with-agents-and-tools.mdx +1 -1
  59. package/package.json +3 -3
@@ -50,21 +50,147 @@
50
50
  ### client.ts
51
51
  ```typescript
52
52
  import { MCPClient } from '@mastra/mcp';
53
+ // import type { ElicitationHandler } from '@mastra/mcp';
54
+ import { createInterface } from 'readline';
55
+
56
+ // Create readline interface for user input
57
+ const readline = createInterface({
58
+ input: process.stdin,
59
+ output: process.stdout,
60
+ });
61
+
62
+ // Helper function to prompt user for input
63
+ function askQuestion(question: string): Promise<string> {
64
+ return new Promise(resolve => {
65
+ readline.question(question, answer => {
66
+ resolve(answer.trim());
67
+ });
68
+ });
69
+ }
70
+
71
+ // Elicitation handler that prompts the user for input
72
+ const elicitationHandler = async request => {
73
+ console.log('\nšŸ”” Elicitation Request Received:');
74
+ console.log(`Message: ${request.message}`);
75
+ console.log('Requested Schema:');
76
+ console.log(JSON.stringify(request.requestedSchema, null, 2));
77
+
78
+ const schema = request.requestedSchema;
79
+ const properties = schema.properties;
80
+ const required = schema.required || [];
81
+
82
+ console.log('\nPlease provide the following information:');
83
+
84
+ const content: Record<string, unknown> = {};
85
+
86
+ // Collect input for each field
87
+ for (const [fieldName, fieldSchema] of Object.entries(properties)) {
88
+ const field = fieldSchema as {
89
+ type?: string;
90
+ title?: string;
91
+ description?: string;
92
+ format?: string;
93
+ };
94
+
95
+ const isRequired = required.includes(fieldName);
96
+ let prompt = `${field.title || fieldName}`;
97
+
98
+ // Add helpful information to the prompt
99
+ if (field.description) {
100
+ prompt += ` (${field.description})`;
101
+ }
102
+ if (field.format) {
103
+ prompt += ` [format: ${field.format}]`;
104
+ }
105
+ if (isRequired) {
106
+ prompt += ' *required*';
107
+ }
108
+
109
+ prompt += ': ';
110
+
111
+ const answer = await askQuestion(prompt);
112
+
113
+ // Check for cancellation
114
+ if (answer.toLowerCase() === 'cancel' || answer.toLowerCase() === 'c') {
115
+ return { action: 'cancel' as const };
116
+ }
117
+
118
+ // Handle empty responses
119
+ if (answer === '' && isRequired) {
120
+ console.log(`āŒ Error: ${fieldName} is required`);
121
+ return { action: 'reject' as const };
122
+ } else if (answer !== '') {
123
+ content[fieldName] = answer;
124
+ }
125
+ }
126
+
127
+ // Show the collected data and ask for confirmation
128
+ console.log('\nāœ… Collected data:');
129
+ console.log(JSON.stringify(content, null, 2));
130
+
131
+ const confirmAnswer = await askQuestion('\nSubmit this information? (yes/no/cancel): ');
132
+
133
+ if (confirmAnswer.toLowerCase() === 'yes' || confirmAnswer.toLowerCase() === 'y') {
134
+ return {
135
+ action: 'accept' as const,
136
+ content,
137
+ };
138
+ } else if (confirmAnswer.toLowerCase() === 'cancel' || confirmAnswer.toLowerCase() === 'c') {
139
+ return { action: 'cancel' as const };
140
+ } else {
141
+ return { action: 'reject' as const };
142
+ }
143
+ };
53
144
 
54
145
  async function main() {
55
146
  const mcpClient = new MCPClient({
56
147
  servers: {
57
- myMcpServer: {
58
- url: new URL('http://localhost:4111/api/mcp/myMcpServer/mcp'),
148
+ myMcpServerTwo: {
149
+ url: new URL('http://localhost:4111/api/mcp/myMcpServerTwo/mcp'),
59
150
  },
60
151
  },
61
152
  });
62
153
 
63
- const tools = await mcpClient.getTools();
64
- console.log('Tools:', tools);
154
+ mcpClient.elicitation.onRequest('myMcpServerTwo', elicitationHandler);
155
+
156
+ try {
157
+ console.log('Connecting to MCP server...');
158
+ const tools = await mcpClient.getTools();
159
+ console.log('Available tools:', Object.keys(tools));
160
+
161
+ // Test the elicitation functionality
162
+ console.log('\n🧪 Testing elicitation functionality...');
163
+
164
+ // Find the collectContactInfo tool
165
+ const collectContactInfoTool = tools['myMcpServerTwo_collectContactInfo'];
166
+ if (collectContactInfoTool) {
167
+ console.log('\nCalling collectContactInfo tool...');
168
+
169
+ try {
170
+ const result = await collectContactInfoTool.execute({
171
+ context: {
172
+ reason: 'We need your contact information to send you updates about our service.',
173
+ },
174
+ });
175
+
176
+ console.log('\nšŸ“‹ Tool Result:');
177
+ console.log(result);
178
+ } catch (error) {
179
+ console.error('āŒ Error calling collectContactInfo tool:', error);
180
+ }
181
+ } else {
182
+ console.log('āŒ collectContactInfo tool not found');
183
+ console.log('Available tools:', Object.keys(tools));
184
+ }
185
+ } catch (error) {
186
+ console.error('āŒ Error:', error);
187
+ } finally {
188
+ readline.close();
189
+ await mcpClient.disconnect();
190
+ }
65
191
  }
66
192
 
67
- main();
193
+ main().catch(console.error);
68
194
 
69
195
  ```
70
196
 
@@ -664,6 +790,57 @@ export const myMcpServerTwo = new MCPServer({
664
790
  return `Hello, ${context.name}! Welcome to the MCP server.`;
665
791
  },
666
792
  }),
793
+ collectContactInfo: createTool({
794
+ id: 'collectContactInfo',
795
+ description: 'Collects user contact information through elicitation.',
796
+ inputSchema: z.object({
797
+ reason: z.string().optional().describe('Optional reason for collecting contact info'),
798
+ }),
799
+ execute: async ({ context }, options) => {
800
+ const { reason } = context;
801
+
802
+ try {
803
+ // Use the session-aware elicitation functionality
804
+ const result = await options.elicitation.sendRequest({
805
+ message: reason
806
+ ? `Please provide your contact information. ${reason}`
807
+ : 'Please provide your contact information',
808
+ requestedSchema: {
809
+ type: 'object',
810
+ properties: {
811
+ name: {
812
+ type: 'string',
813
+ title: 'Full Name',
814
+ description: 'Your full name',
815
+ },
816
+ email: {
817
+ type: 'string',
818
+ title: 'Email Address',
819
+ description: 'Your email address',
820
+ format: 'email',
821
+ },
822
+ phone: {
823
+ type: 'string',
824
+ title: 'Phone Number',
825
+ description: 'Your phone number (optional)',
826
+ },
827
+ },
828
+ required: ['name', 'email'],
829
+ },
830
+ });
831
+
832
+ if (result.action === 'accept') {
833
+ return `Thank you! Contact information collected: ${JSON.stringify(result.content, null, 2)}`;
834
+ } else if (result.action === 'reject') {
835
+ return 'Contact information collection was declined by the user.';
836
+ } else {
837
+ return 'Contact information collection was cancelled by the user.';
838
+ }
839
+ } catch (error) {
840
+ return `Error collecting contact information: ${error}`;
841
+ }
842
+ },
843
+ }),
667
844
  },
668
845
  });
669
846
 
@@ -30,7 +30,7 @@
30
30
  "@types/node": "^20.17.57",
31
31
  "@types/react": "^19.1.8",
32
32
  "@types/react-dom": "^19.1.6",
33
- "eslint": "^8.57.1",
33
+ "eslint": "^9.29.0",
34
34
  "eslint-config-next": "15.3.3",
35
35
  "postcss": "^8.5.3",
36
36
  "tailwindcss": "^3.4.17",
@@ -39,7 +39,7 @@
39
39
  "@types/node": "^20.17.57",
40
40
  "@types/react": "^18.3.23",
41
41
  "@types/react-dom": "^18.3.7",
42
- "eslint": "^8.57.1",
42
+ "eslint": "^9.29.0",
43
43
  "eslint-config-next": "15.3.3",
44
44
  "postcss": "^8.5.3",
45
45
  "tailwindcss": "^3.4.17",
@@ -38,7 +38,7 @@
38
38
  "@types/node": "^20.17.57",
39
39
  "@types/react": "^19.1.8",
40
40
  "@types/react-dom": "^19.1.6",
41
- "eslint": "^8.57.1",
41
+ "eslint": "^9.29.0",
42
42
  "eslint-config-next": "15.3.3",
43
43
  "postcss": "^8.5.3",
44
44
  "tailwindcss": "^3.4.17",
@@ -91,8 +91,8 @@
91
91
  "drizzle-kit": "^0.31.0",
92
92
  "eslint": "^9.29.0",
93
93
  "eslint-config-next": "15.3.3",
94
- "eslint-config-prettier": "^9.1.0",
95
- "eslint-import-resolver-typescript": "^3.10.1",
94
+ "eslint-config-prettier": "^10.1.5",
95
+ "eslint-import-resolver-typescript": "^4.4.3",
96
96
  "eslint-plugin-import": "^2.31.0",
97
97
  "eslint-plugin-tailwindcss": "^3.18.0",
98
98
  "postcss": "^8.5.3",
@@ -41,7 +41,7 @@
41
41
  "@types/react": "^19.1.8",
42
42
  "@types/react-dom": "^19.1.6",
43
43
  "@types/react-syntax-highlighter": "^15.5.13",
44
- "eslint": "^8.57.1",
44
+ "eslint": "^9.29.0",
45
45
  "eslint-config-next": "15.3.3",
46
46
  "postcss": "^8.5.3",
47
47
  "tailwindcss": "^3.4.17",
@@ -75,8 +75,6 @@ Once you have a server you want to use with your agent, import the Mastra `MCPCl
75
75
 
76
76
  ```typescript filename="src/mastra/mcp.ts" {1,7-16}
77
77
  import { MCPClient } from "@mastra/mcp";
78
- import { Agent } from "@mastra/core/agent";
79
- import { openai } from "@ai-sdk/openai";
80
78
 
81
79
  // Configure MCPClient to connect to your server(s)
82
80
  export const mcp = new MCPClient({
@@ -96,7 +94,10 @@ export const mcp = new MCPClient({
96
94
  Then connect your agent to the server tools:
97
95
 
98
96
  ```typescript filename="src/mastra/agents/mcpAgent.ts" {7}
97
+ import { Agent } from "@mastra/core/agent";
98
+ import { openai } from "@ai-sdk/openai";
99
99
  import { mcp } from "../mcp";
100
+
100
101
  // Create an agent and add tools from the MCP client
101
102
  const agent = new Agent({
102
103
  name: "Agent with MCP Tools",
@@ -0,0 +1,111 @@
1
+ ---
2
+ title: "Digital Ocean"
3
+ description: "Deploy your Mastra applications to Digital Ocean."
4
+ ---
5
+
6
+ import { Callout, Steps, Tabs } from "nextra/components";
7
+ import ServerConfig from "@/components/content-blocks/server-config.mdx";
8
+
9
+ ## Digital Ocean
10
+
11
+ Deploy your Mastra applications to Digital Ocean's App Platform and Droplets.
12
+
13
+ <Callout>
14
+ This guide assumes your Mastra application has been created using the default
15
+ `npx create-mastra@latest` command.
16
+ For more information on how to create a new Mastra application,
17
+ refer to our [getting started guide](./../../getting-started/installation.mdx)
18
+ </Callout>
19
+
20
+ <Tabs items={["App Platform", "Droplets"]}>
21
+
22
+ <Tabs.Tab>
23
+
24
+ ### App Platform
25
+
26
+ #### Prerequisites [#app-platform-prerequisites]
27
+
28
+ - A Git repository containing your Mastra application. This can be a GitHub repository, GitLab repository, or any other compatible source provider.
29
+ - A Digital Ocean account
30
+
31
+ #### Deployment Steps
32
+
33
+ <Steps>
34
+
35
+ #### Create a new App
36
+
37
+ - Log in to your Digital Ocean dashboard.
38
+ - Navigate to the App Platform service.
39
+ - Select your source provider and create a new app.
40
+
41
+ #### Configure Deployment Source
42
+
43
+ - Connect and select your repository. You may also choose a container image or a sample app.
44
+ - Select the branch you want to deploy from.
45
+ - Configure the source directory if necessary. If your Mastra application uses the default directory structure, no action is required here.
46
+ - Head to the next step.
47
+
48
+ #### Configure Resource Settings and Environment Variables
49
+
50
+ - A Node.js build should be detected automatically.
51
+ - Add any required environment variables for your Mastra application. This includes API keys, database URLs, and other configuration values.
52
+ - You may choose to configure the size of your resource here.
53
+ - Other things you may optionally configure include, the region of your resource, the unique app name, and what project the resource belongs to.
54
+ - Once you're done, you may create the app after reviewing your configuration and pricing estimates.
55
+
56
+ #### Deployment
57
+
58
+ - Your app will be built and deployed automatically.
59
+ - Digital Ocean will provide you with a URL to access your deployed application.
60
+
61
+ </Steps>
62
+
63
+ You can now access your deployed application at the URL provided by Digital Ocean.
64
+
65
+ <Callout>
66
+ The Digital Ocean App Platform uses an ephemeral file system,
67
+ meaning that any files written to the file system are short-lived and may be lost.
68
+ Avoid using a Mastra storage provider that uses the file system,
69
+ such as `LibSQLStore` with a file URL.
70
+ </Callout>
71
+
72
+ </Tabs.Tab>
73
+
74
+ <Tabs.Tab>
75
+
76
+ ### Droplets
77
+
78
+ Deploy your Mastra application to Digital Ocean's Droplets.
79
+ This guide will cover setting up a droplet, a reverse proxy using Nginx, and running your Mastra application.
80
+
81
+ <Callout>
82
+ The guide assumes your droplet runs Ubuntu 24+.
83
+ </Callout>
84
+
85
+ #### Prerequisites [#droplets-prerequisites]
86
+
87
+ - A Digital Ocean account
88
+ - A droplet running Ubuntu 24+
89
+ - A domain name with an A record pointing to your droplet
90
+
91
+ #### Setting up the droplet
92
+
93
+ <ServerConfig />
94
+
95
+ </Tabs.Tab>
96
+
97
+ </Tabs>
98
+
99
+ ### Connect to your Mastra server
100
+
101
+ You can now connect to your Mastra server from your client application using a `MastraClient` from the `@mastra/client-js` package.
102
+
103
+ Refer to the [`MastraClient` documentation](../../client-js/overview.mdx) for more information.
104
+
105
+ ```typescript copy showLineNumbers
106
+ import { MastraClient } from "@mastra/client-js";
107
+
108
+ const mastraClient = new MastraClient({
109
+ baseUrl: "https://<your-domain-name>",
110
+ });
111
+ ```
@@ -0,0 +1,15 @@
1
+ ---
2
+ title: "Cloud Providers"
3
+ description: "Deploy your Mastra applications to popular cloud providers."
4
+ asIndexPage: true
5
+ ---
6
+
7
+ import { CardGrid, CardGridItem } from "@/components/cards/card-grid";
8
+
9
+ ## Cloud Providers
10
+
11
+ Deploy your Mastra applicaitons to popular cloud providers.
12
+
13
+ <CardGrid>
14
+ <CardGridItem title="Digital Ocean" description="Deploy your Mastra applications to Digital Ocean" href="./cloud-providers/digital-ocean" />
15
+ </CardGrid>
@@ -208,6 +208,61 @@ const paragraphMemory = new Memory({
208
208
  });
209
209
  ```
210
210
 
211
+ ## Structured Working Memory
212
+
213
+ Working memory can also be defined using a structured schema instead of a Markdown template. This allows you to specify the exact fields and types that should be tracked, using a [Zod](https://zod.dev/) schema. When using a schema, the agent will see and update working memory as a JSON object matching your schema.
214
+
215
+ **Important:** You must specify either `template` or `schema`, but not both.
216
+
217
+ ### Example: Schema-Based Working Memory
218
+
219
+ ```typescript
220
+ import { z } from 'zod';
221
+ import { Memory } from '@mastra/memory';
222
+
223
+ const userProfileSchema = z.object({
224
+ name: z.string().optional(),
225
+ location: z.string().optional(),
226
+ timezone: z.string().optional(),
227
+ preferences: z.object({
228
+ communicationStyle: z.string().optional(),
229
+ projectGoal: z.string().optional(),
230
+ deadlines: z.array(z.string()).optional(),
231
+ }).optional(),
232
+ });
233
+
234
+ const memory = new Memory({
235
+ options: {
236
+ workingMemory: {
237
+ enabled: true,
238
+ schema: userProfileSchema,
239
+ // template: ... (do not set)
240
+ },
241
+ },
242
+ });
243
+ ```
244
+
245
+ When a schema is provided, the agent receives the working memory as a JSON object. For example:
246
+
247
+ ```json
248
+ {
249
+ "name": "Sam",
250
+ "location": "Berlin",
251
+ "timezone": "CET",
252
+ "preferences": {
253
+ "communicationStyle": "Formal",
254
+ "projectGoal": "Launch MVP",
255
+ "deadlines": ["2025-07-01"]
256
+ }
257
+ }
258
+ ```
259
+
260
+ ## Choosing Between Template and Schema
261
+
262
+ - Use a **template** (Markdown) if you want the agent to maintain memory as a free-form text block, such as a user profile or scratchpad.
263
+ - Use a **schema** if you need structured, type-safe data that can be validated and programmatically accessed as JSON.
264
+ - Only one mode can be active at a time: setting both `template` and `schema` is not supported.
265
+
211
266
  ## Example: Multi-step Retention
212
267
 
213
268
  Below is a simplified view of how the `User Profile` template updates across a short user
@@ -247,4 +302,5 @@ instructions on _how_ and _when_ to use this template in your agent's `instructi
247
302
 
248
303
  - [Streaming working memory](/examples/memory/streaming-working-memory)
249
304
  - [Using a working memory template](/examples/memory/streaming-working-memory-advanced)
305
+ - [Using a working memory schema](/examples/memory/streaming-working-memory-structured)
250
306
  - [Per-resource working memory](https://github.com/mastra-ai/mastra/tree/main/examples/memory-per-resource-example) - Complete example showing resource-scoped memory persistence
@@ -0,0 +1,137 @@
1
+ ## Complex tasks requiring multiple primitives
2
+
3
+ As an example, we have an AgentNetwork with 3 primitives at its disposal:
4
+
5
+ - `agent1`: A general research agent that can do research on a given topic.
6
+ - `agent2`: A general writing agent that can write a full report based on the researched material.
7
+ - `workflow1`: A workflow that can research a given city and write a full report based on the researched material (using both agent1 and agent2).
8
+
9
+ We use the `loop` method to create a task that requires multiple primitives. The AgentNetwork will, using memory, figure out which primitives to call and in which order, as well as when the task is complete.
10
+
11
+ ```typescript
12
+ import { NewAgentNetwork } from '@mastra/core/network/vNext';
13
+ import { Agent } from '@mastra/core/agent';
14
+ import { createStep, createWorkflow } from '@mastra/core/workflows';
15
+ import { Memory } from '@mastra/memory';
16
+ import { openai } from '@ai-sdk/openai';
17
+ import { LibSQLStore } from '@mastra/libsql';
18
+ import { z } from 'zod';
19
+ import { RuntimeContext } from '@mastra/core/runtime-context';
20
+
21
+ const memory = new Memory({
22
+ storage: new LibSQLStore({
23
+ url: 'file:../mastra.db', // Or your database URL
24
+ }),
25
+ });
26
+
27
+ const agentStep1 = createStep({
28
+ id: 'agent-step',
29
+ description: 'This step is used to do research and text synthesis.',
30
+ inputSchema: z.object({
31
+ city: z.string().describe('The city to research'),
32
+ }),
33
+ outputSchema: z.object({
34
+ text: z.string(),
35
+ }),
36
+ execute: async ({ inputData }) => {
37
+ const resp = await agent1.generate(inputData.city, {
38
+ output: z.object({
39
+ text: z.string(),
40
+ }),
41
+ });
42
+
43
+ return { text: resp.object.text };
44
+ },
45
+ });
46
+
47
+ const agentStep2 = createStep({
48
+ id: 'agent-step-two',
49
+ description: 'This step is used to do research and text synthesis.',
50
+ inputSchema: z.object({
51
+ text: z.string().describe('The city to research'),
52
+ }),
53
+ outputSchema: z.object({
54
+ text: z.string(),
55
+ }),
56
+ execute: async ({ inputData }) => {
57
+ const resp = await agent2.generate(inputData.text, {
58
+ output: z.object({
59
+ text: z.string(),
60
+ }),
61
+ });
62
+
63
+ return { text: resp.object.text };
64
+ },
65
+ });
66
+
67
+ const workflow1 = createWorkflow({
68
+ id: 'workflow1',
69
+ description:
70
+ 'This workflow is perfect for researching a specific city. It should be used when you have a city in mind to research.',
71
+ steps: [],
72
+ inputSchema: z.object({
73
+ city: z.string(),
74
+ }),
75
+ outputSchema: z.object({
76
+ text: z.string(),
77
+ }),
78
+ })
79
+ .then(agentStep1)
80
+ .then(agentStep2)
81
+ .commit();
82
+
83
+ const agent1 = new Agent({
84
+ name: 'agent1',
85
+ instructions:
86
+ 'This agent is used to do research, but not create full responses. Answer in bullet points only and be concise.',
87
+ description:
88
+ 'This agent is used to do research, but not create full responses. Answer in bullet points only and be concise.',
89
+ model: openai('gpt-4o'),
90
+ });
91
+
92
+ const agent2 = new Agent({
93
+ name: 'agent2',
94
+ description:
95
+ 'This agent is used to do text synthesis on researched material. Write a full report based on the researched material. Writes reports in full paragraphs. Should be used to synthesize text from different sources together as a final report.',
96
+ instructions:
97
+ 'This agent is used to do text synthesis on researched material. Write a full report based on the researched material. Do not use bullet points. Write full paragraphs. There should not be a single bullet point in the final report.',
98
+ model: openai('gpt-4o'),
99
+ });
100
+
101
+ const network = new NewAgentNetwork({
102
+ id: 'test-network',
103
+ name: 'Test Network',
104
+ instructions:
105
+ 'You are a network of writers and researchers. The user will ask you to research a topic. You always need to answer with a full report. Bullet points are NOT a full report. WRITE FULL PARAGRAPHS like this is a blog post or something similar. You should not rely on partial information.',
106
+ model: openai('gpt-4o'),
107
+ agents: {
108
+ agent1,
109
+ agent2,
110
+ },
111
+ workflows: {
112
+ workflow1,
113
+ },
114
+ memory: memory,
115
+ });
116
+
117
+ const runtimeContext = new RuntimeContext();
118
+
119
+ console.log(
120
+ // specifying the task, note that there is a mention here about using an agent for synthesis. This is because the routing agent can actually do some synthesis on results on its own, so this will force it to use agent2 instead
121
+ await network.loop(
122
+ 'What are the biggest cities in France? Give me 3. How are they like? Find cities, then do thorough research on each city, and give me a final full report synthesizing all that information. Make sure to use an agent for synthesis.',
123
+ { runtimeContext },
124
+ ),
125
+ );
126
+ ```
127
+
128
+ For the given task (research 3 biggest cities in France and write a full report), the AgentNetwork will call the following primitives:
129
+
130
+ 1. `agent1` to find the 3 biggest cities in France.
131
+ 2. `workflow1` to research each city one by one. The workflow uses `memory` to figure out which cities have already been researched and makes sure it has researched all of them before proceeding.
132
+ 3. `agent2` to synthesize the final report.
133
+
134
+ ### How It Works
135
+
136
+ - The underlying engine is a Mastra workflow that wraps the single call `generate` workflow.
137
+ - The workflow will repeatedly call the network execution workflow with a `dountil` structure, until the routing model determines the task is complete. This check is used as the `dountil` condition.