# Adding Voice to Agents [EN] Source: https://mastra.ai/en/docs/agents/adding-voice Mastra agents can be enhanced with voice capabilities, allowing them to speak responses and listen to user input. You can configure an agent to use either a single voice provider or combine multiple providers for different operations. ## Using a Single Provider The simplest way to add voice to an agent is to use a single provider for both speaking and listening: ```typescript import { createReadStream } from "fs"; import path from "path"; import { Agent } from "@mastra/core/agent"; import { OpenAIVoice } from "@mastra/voice-openai"; import { openai } from "@ai-sdk/openai"; // Initialize the voice provider with default settings const voice = new OpenAIVoice(); // Create an agent with voice capabilities export const agent = new Agent({ name: "Agent", instructions: `You are a helpful assistant with both STT and TTS capabilities.`, model: openai("gpt-4o"), voice, }); // The agent can now use voice for interaction const audioStream = await agent.voice.speak("Hello, I'm your AI assistant!", { filetype: "m4a", }); playAudio(audioStream!); try { const transcription = await agent.voice.listen(audioStream); console.log(transcription); } catch (error) { console.error("Error transcribing audio:", error); } ``` ## Using Multiple Providers For more flexibility, you can use different providers for speaking and listening using the CompositeVoice class: ```typescript import { Agent } from "@mastra/core/agent"; import { CompositeVoice } from "@mastra/core/voice"; import { OpenAIVoice } from "@mastra/voice-openai"; import { PlayAIVoice } from "@mastra/voice-playai"; import { openai } from "@ai-sdk/openai"; export const agent = new Agent({ name: "Agent", instructions: `You are a helpful assistant with both STT and TTS capabilities.`, model: openai("gpt-4o"), // Create a composite voice using OpenAI for listening and PlayAI for speaking voice: new CompositeVoice({ input: new OpenAIVoice(), output: new PlayAIVoice(), }), }); ``` ## Working with Audio Streams The `speak()` and `listen()` methods work with Node.js streams. Here's how to save and load audio files: ### Saving Speech Output The `speak` method returns a stream that you can pipe to a file or speaker. ```typescript import { createWriteStream } from "fs"; import path from "path"; // Generate speech and save to file const audio = await agent.voice.speak("Hello, World!"); const filePath = path.join(process.cwd(), "agent.mp3"); const writer = createWriteStream(filePath); audio.pipe(writer); await new Promise((resolve, reject) => { writer.on("finish", () => resolve()); writer.on("error", reject); }); ``` ### Transcribing Audio Input The `listen` method expects a stream of audio data from a microphone or file. ```typescript import { createReadStream } from "fs"; import path from "path"; // Read audio file and transcribe const audioFilePath = path.join(process.cwd(), "/agent.m4a"); const audioStream = createReadStream(audioFilePath); try { console.log("Transcribing audio file..."); const transcription = await agent.voice.listen(audioStream, { filetype: "m4a", }); console.log("Transcription:", transcription); } catch (error) { console.error("Error transcribing audio:", error); } ``` ## Speech-to-Speech Voice Interactions For more dynamic and interactive voice experiences, you can use real-time voice providers that support speech-to-speech capabilities: ```typescript import { Agent } from "@mastra/core/agent"; import { getMicrophoneStream } from "@mastra/node-audio"; import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import { search, calculate } from "../tools"; // Initialize the realtime voice provider const voice = new OpenAIRealtimeVoice({ apiKey: process.env.OPENAI_API_KEY, model: "gpt-4o-mini-realtime", speaker: "alloy", }); // Create an agent with speech-to-speech voice capabilities export const agent = new Agent({ name: "Agent", instructions: `You are a helpful assistant with speech-to-speech capabilities.`, model: openai("gpt-4o"), tools: { // Tools configured on Agent are passed to voice provider search, calculate, }, voice, }); // Establish a WebSocket connection await agent.voice.connect(); // Start a conversation agent.voice.speak("Hello, I'm your AI assistant!"); // Stream audio from a microphone const microphoneStream = getMicrophoneStream(); agent.voice.send(microphoneStream); // When done with the conversation agent.voice.close(); ``` ### Event System The realtime voice provider emits several events you can listen for: ```typescript // Listen for speech audio data sent from voice provider agent.voice.on("speaking", ({ audio }) => { // audio contains ReadableStream or Int16Array audio data }); // Listen for transcribed text sent from both voice provider and user agent.voice.on("writing", ({ text, role }) => { console.log(`${role} said: ${text}`); }); // Listen for errors agent.voice.on("error", (error) => { console.error("Voice error:", error); }); ``` ## Supported Voice Providers Mastra supports multiple voice providers for text-to-speech (TTS) and speech-to-text (STT) capabilities: | Provider | Package | Features | Reference | | --------------- | ------------------------------- | ------------------------- | ------------------------------------------------- | | OpenAI | `@mastra/voice-openai` | TTS, STT | [Documentation](/reference/voice/openai) | | OpenAI Realtime | `@mastra/voice-openai-realtime` | Realtime speech-to-speech | [Documentation](/reference/voice/openai-realtime) | | ElevenLabs | `@mastra/voice-elevenlabs` | High-quality TTS | [Documentation](/reference/voice/elevenlabs) | | PlayAI | `@mastra/voice-playai` | TTS | [Documentation](/reference/voice/playai) | | Google | `@mastra/voice-google` | TTS, STT | [Documentation](/reference/voice/google) | | Deepgram | `@mastra/voice-deepgram` | STT | [Documentation](/reference/voice/deepgram) | | Murf | `@mastra/voice-murf` | TTS | [Documentation](/reference/voice/murf) | | Speechify | `@mastra/voice-speechify` | TTS | [Documentation](/reference/voice/speechify) | | Sarvam | `@mastra/voice-sarvam` | TTS, STT | [Documentation](/reference/voice/sarvam) | | Azure | `@mastra/voice-azure` | TTS, STT | [Documentation](/reference/voice/mastra-voice) | | Cloudflare | `@mastra/voice-cloudflare` | TTS | [Documentation](/reference/voice/mastra-voice) | For more details on voice capabilities, see the [Voice API Reference](/reference/voice/mastra-voice). --- title: "Using Agent Memory | Agents | Mastra Docs" description: Documentation on how agents in Mastra use memory to store conversation history and contextual information. --- # Agent Memory [EN] Source: https://mastra.ai/en/docs/agents/agent-memory Agents in Mastra can leverage a powerful memory system to store conversation history, recall relevant information, and maintain persistent context across interactions. This allows agents to have more natural, stateful conversations. ## Enabling Memory for an Agent To enable memory, simply instantiate the `Memory` class and pass it to your agent's configuration. You also need to install the memory package and a storage adapter: ```bash npm2yarn copy npm install @mastra/memory@latest @mastra/libsql@latest ``` ```typescript import { Agent } from "@mastra/core/agent"; import { Memory } from "@mastra/memory"; import { LibSQLStore } from "@mastra/libsql"; import { openai } from "@ai-sdk/openai"; const memory = new Memory({ storage: new LibSQLStore({ url: "file:../../memory.db", }), }); const agent = new Agent({ name: "MyMemoryAgent", instructions: "You are a helpful assistant with memory.", model: openai("gpt-4o"), memory, // Attach the memory instance }); ``` This basic setup uses the default settings. Visit the [Memory documentation](/docs/memory/overview) for more configuration info. ## Using Memory in Agent Calls To utilize memory during interactions, you **must** provide `resourceId` and `threadId` when calling the agent's `stream()` or `generate()` methods. - `resourceId`: Typically identifies the user or entity (e.g., `user_123`). - `threadId`: Identifies a specific conversation thread (e.g., `support_chat_456`). ```typescript // Example agent call using memory await agent.stream("Remember my favorite color is blue.", { resourceId: "user_alice", threadId: "preferences_thread", }); // Later in the same thread... const response = await agent.stream("What's my favorite color?", { resourceId: "user_alice", threadId: "preferences_thread", }); // Agent will use memory to recall the favorite color. ``` These IDs ensure that conversation history and context are correctly stored and retrieved for the appropriate user and conversation. ## Next Steps Keep exploring Mastra's [memory capabilities](/docs/memory/overview) like threads, conversation history, semantic recall, and working memory. --- title: "Dynamic Agents" description: Dynamically configure your agent's instruction, model and tools using runtime context. --- # Dynamic Agents [EN] Source: https://mastra.ai/en/docs/agents/dynamic-agents Dynamic agents use [runtime context](./runtime-variables), like user IDs and other important parameters, to adjust their settings in real-time. This means they can change the model they use, update their instructions, and select different tools as needed. By using this context, agents can better respond to each user's needs. They can also call any API to gather more information, which helps improve what the agents can do. ### Example Configuration Here's an example of a dynamic support agent that adjusts its behavior based on the user's subscription tier and language preferences: ```typescript const supportAgent = new Agent({ name: "Dynamic Support Agent", instructions: async ({ runtimeContext }) => { const userTier = runtimeContext.get("user-tier"); const language = runtimeContext.get("language"); return `You are a customer support agent for our SaaS platform. The current user is on the ${userTier} tier and prefers ${language} language. For ${userTier} tier users: ${userTier === "free" ? "- Provide basic support and documentation links" : ""} ${userTier === "pro" ? "- Offer detailed technical support and best practices" : ""} ${userTier === "enterprise" ? "- Provide priority support with custom solutions" : ""} Always respond in ${language} language.`; }, model: ({ runtimeContext }) => { const userTier = runtimeContext.get("user-tier"); return userTier === "enterprise" ? openai("gpt-4") : openai("gpt-3.5-turbo"); }, tools: ({ runtimeContext }) => { const userTier = runtimeContext.get("user-tier"); const baseTools = [knowledgeBase, ticketSystem]; if (userTier === "pro" || userTier === "enterprise") { baseTools.push(advancedAnalytics); } if (userTier === "enterprise") { baseTools.push(customIntegration); } return baseTools; }, }); ``` In this example, the agent: - Adjusts its instructions based on the user's subscription tier (free, pro, or enterprise) - Uses a more powerful model (GPT-4) for enterprise users - Provides different sets of tools based on the user's tier - Responds in the user's preferred language This demonstrates how a single agent can handle different types of users and scenarios by leveraging runtime context, making it more flexible and maintainable than creating separate agents for each use case. For a complete implementation example including API routes, middleware setup, and runtime context handling, see our [Dynamic Agents Example](/examples/agents/dynamic-agents). --- title: "Creating and Calling Agents | Agent Documentation | Mastra" description: Overview of agents in Mastra, detailing their capabilities and how they interact with tools, workflows, and external systems. --- # Creating and Calling Agents [EN] Source: https://mastra.ai/en/docs/agents/overview Agents in Mastra are systems where the language model can autonomously decide on a sequence of actions to perform tasks. They have access to tools, workflows, and synced data, enabling them to perform complex tasks and interact with external systems. Agents can invoke your custom functions, utilize third-party APIs through integrations, and access knowledge bases you have built. Agents are like employees who can be used for ongoing projects. They have names, persistent memory, consistent model configurations, and instructions across calls, as well as a set of enabled tools. ## 1. Creating an Agent To create an agent in Mastra, you use the `Agent` class and define its properties: ```ts showLineNumbers filename="src/mastra/agents/index.ts" copy import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; export const myAgent = new Agent({ name: "My Agent", instructions: "You are a helpful assistant.", model: openai("gpt-4o-mini"), }); ``` **Note:** Ensure that you have set the necessary environment variables, such as your OpenAI API key, in your `.env` file: ```.env filename=".env" copy OPENAI_API_KEY=your_openai_api_key ``` Also, make sure you have the `@mastra/core` package installed: ```bash npm2yarn copy npm install @mastra/core@latest ``` ### Registering the Agent Register your agent with Mastra to enable logging and access to configured tools and integrations: ```ts showLineNumbers filename="src/mastra/index.ts" copy import { Mastra } from "@mastra/core"; import { myAgent } from "./agents"; export const mastra = new Mastra({ agents: { myAgent }, }); ``` ## 2. Generating and streaming text ### Generating text Use the `.generate()` method to have your agent produce text responses: ```ts showLineNumbers filename="src/mastra/index.ts" copy const response = await myAgent.generate([ { role: "user", content: "Hello, how can you assist me today?" }, ]); console.log("Agent:", response.text); ``` For more details about the generate method and its options, see the [generate reference documentation](/reference/agents/generate). ### Streaming responses For more real-time responses, you can stream the agent's response: ```ts showLineNumbers filename="src/mastra/index.ts" copy const stream = await myAgent.stream([ { role: "user", content: "Tell me a story." }, ]); console.log("Agent:"); for await (const chunk of stream.textStream) { process.stdout.write(chunk); } ``` For more details about streaming responses, see the [stream reference documentation](/reference/agents/stream). ## 3. Structured Output Agents can return structured data by providing a JSON Schema or using a Zod schema. ### Using JSON Schema ```typescript const schema = { type: "object", properties: { summary: { type: "string" }, keywords: { type: "array", items: { type: "string" } }, }, additionalProperties: false, required: ["summary", "keywords"], }; const response = await myAgent.generate( [ { role: "user", content: "Please provide a summary and keywords for the following text: ...", }, ], { output: schema, }, ); console.log("Structured Output:", response.object); ``` ### Using Zod You can also use Zod schemas for type-safe structured outputs. First, install Zod: ```bash npm2yarn copy npm install zod ``` Then, define a Zod schema and use it with the agent: ```ts showLineNumbers filename="src/mastra/index.ts" copy import { z } from "zod"; // Define the Zod schema const schema = z.object({ summary: z.string(), keywords: z.array(z.string()), }); // Use the schema with the agent const response = await myAgent.generate( [ { role: "user", content: "Please provide a summary and keywords for the following text: ...", }, ], { output: schema, }, ); console.log("Structured Output:", response.object); ``` ### Using Tools If you need to generate structured output alongside tool calls, you'll need to use the `experimental_output` property instead of `output`. Here's how: ```typescript const schema = z.object({ summary: z.string(), keywords: z.array(z.string()), }); const response = await myAgent.generate( [ { role: "user", content: "Please analyze this repository and provide a summary and keywords...", }, ], { // Use experimental_output to enable both structured output and tool calls experimental_output: schema, }, ); console.log("Structured Output:", response.object); ```
This allows you to have strong typing and validation for the structured data returned by the agent. ## 4. Multi-step Tool use Agents Agents can be enhanced with tools - functions that extend their capabilities beyond text generation. Tools allow agents to perform calculations, access external systems, and process data. For details on creating and configuring tools, see the [Adding Tools documentation](/docs/agents/using-tools-and-mcp). ### Using maxSteps The `maxSteps` parameter controls the maximum number of sequential LLM calls an agent can make, particularly important when using tool calls. By default, it is set to 1 to prevent infinite loops in case of misconfigured tools. You can increase this limit based on your use case: ```ts showLineNumbers filename="src/mastra/agents/index.ts" copy import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import * as mathjs from "mathjs"; import { z } from "zod"; export const myAgent = new Agent({ name: "My Agent", instructions: "You are a helpful assistant that can solve math problems.", model: openai("gpt-4o-mini"), tools: { calculate: { description: "Calculator for mathematical expressions", schema: z.object({ expression: z.string() }), execute: async ({ expression }) => mathjs.evaluate(expression), }, }, }); const response = await myAgent.generate( [ { role: "user", content: "If a taxi driver earns $9461 per hour and works 12 hours a day, how much do they earn in one day?", }, ], { maxSteps: 5, // Allow up to 5 tool usage steps }, ); ``` ### Using onStepFinish You can monitor the progress of multi-step operations using the `onStepFinish` callback. This is useful for debugging or providing progress updates to users. `onStepFinish` is only available when streaming or generating text without structured output. ```ts showLineNumbers filename="src/mastra/agents/index.ts" copy const response = await myAgent.generate( [{ role: "user", content: "Calculate the taxi driver's daily earnings." }], { maxSteps: 5, onStepFinish: ({ text, toolCalls, toolResults }) => { console.log("Step completed:", { text, toolCalls, toolResults }); }, }, ); ``` ### Using onFinish The `onFinish` callback is available when streaming responses and provides detailed information about the completed interaction. It is called after the LLM has finished generating its response and all tool executions have completed. This callback receives the final response text, execution steps, token usage statistics, and other metadata that can be useful for monitoring and logging: ```ts showLineNumbers filename="src/mastra/agents/index.ts" copy const stream = await myAgent.stream( [{ role: "user", content: "Calculate the taxi driver's daily earnings." }], { maxSteps: 5, onFinish: ({ steps, text, finishReason, // 'complete', 'length', 'tool', etc. usage, // token usage statistics reasoningDetails, // additional context about the agent's decisions }) => { console.log("Stream complete:", { totalSteps: steps.length, finishReason, usage, }); }, }, ); ``` ## 5. Running Agents Mastra provides a CLI command `mastra dev` to run your agents behind an API. By default, this looks for exported agents in files in the `src/mastra/agents` directory. ### Starting the Server ```bash mastra dev ``` This will start the server and make your agent available at `http://localhost:4111/api/agents/myAgent/generate`. ### Interacting with the Agent You can interact with the agent using `curl` from the command line: ```bash curl -X POST http://localhost:4111/api/agents/myAgent/generate \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "role": "user", "content": "Hello, how can you assist me today?" } ] }' ``` ## Next Steps - Learn about Agent Memory in the [Agent Memory](./agent-memory.mdx) guide. - Learn about Agent Tools in the [Agent Tools and MCP](./using-tools-and-mcp.mdx) guide. - See an example agent in the [Chef Michel](../../guides/guide/chef-michel.mdx) example. --- title: "Runtime context | Agents | Mastra Docs" description: Learn how to use Mastra's dependency injection system to provide runtime configuration to agents and tools. --- # Agent Runtime Context [EN] Source: https://mastra.ai/en/docs/agents/runtime-variables Mastra provides runtime context, which is a system based on dependency injection that enables you to configure your agents and tools with runtime variables. If you find yourself creating several different agents that do very similar things, runtime context allows you to combine them into one agent. ## Overview The dependency injection system allows you to: 1. Pass runtime configuration variables to agents through a type-safe runtimeContext 2. Access these variables within tool execution contexts 3. Modify agent behavior without changing the underlying code 4. Share configuration across multiple tools within the same agent ## Basic Usage ```typescript const agent = mastra.getAgent("weatherAgent"); // Define your runtimeContext's type structure type WeatherRuntimeContext = { "temperature-scale": "celsius" | "fahrenheit"; // Fixed typo in "fahrenheit" }; const runtimeContext = new RuntimeContext(); runtimeContext.set("temperature-scale", "celsius"); const response = await agent.generate("What's the weather like today?", { runtimeContext, }); console.log(response.text); ``` ## Using with REST API Here's how to dynamically set temperature units based on a user's location using the Cloudflare `CF-IPCountry` header: ```typescript filename="src/index.ts" import { Mastra } from "@mastra/core"; import { RuntimeContext } from "@mastra/core/di"; import { agent as weatherAgent } from "./agents/weather"; // Define RuntimeContext type with clear, descriptive types type WeatherRuntimeContext = { "temperature-scale": "celsius" | "fahrenheit"; }; export const mastra = new Mastra({ agents: { weather: weatherAgent, }, server: { middleware: [ async (c, next) => { const country = c.req.header("CF-IPCountry"); const runtimeContext = c.get("runtimeContext"); // Set temperature scale based on country runtimeContext.set( "temperature-scale", country === "US" ? "fahrenheit" : "celsius", ); await next(); // Don't forget to call next() }, ], }, }); ``` ## Creating Tools with Variables Tools can access runtimeContext variables and must conform to the agent's runtimeContext type: ```typescript import { createTool } from "@mastra/core/tools"; import { z } from "zod"; export const weatherTool = createTool({ id: "getWeather", description: "Get the current weather for a location", inputSchema: z.object({ location: z.string().describe("The location to get weather for"), }), execute: async ({ context, runtimeContext }) => { // Type-safe access to runtimeContext variables const temperatureUnit = runtimeContext.get("temperature-scale"); const weather = await fetchWeather(context.location, { temperatureUnit, }); return { result: weather }; }, }); async function fetchWeather( location: string, { temperatureUnit }: { temperatureUnit: "celsius" | "fahrenheit" }, ): Promise { // Implementation of weather API call const response = await weatherApi.fetch(location, temperatureUnit); return { location, temperature: "72°F", conditions: "Sunny", unit: temperatureUnit, }; } ``` --- title: "Using Tools with Agents | Agents | Mastra Docs" description: Learn how to create tools, add them to Mastra agents, and integrate tools from MCP servers. --- # Using Tools with Agents [EN] Source: https://mastra.ai/en/docs/agents/using-tools-and-mcp Tools are typed functions that can be executed by agents or workflows. Each tool has a schema defining its inputs, an executor function implementing its logic, and optional access to configured integrations. ## Creating Tools Here's a basic example of creating a tool: ```typescript filename="src/mastra/tools/weatherInfo.ts" copy import { createTool } from "@mastra/core/tools"; import { z } from "zod"; export const weatherInfo = createTool({ id: "Get Weather Information", inputSchema: z.object({ city: z.string(), }), description: `Fetches the current weather information for a given city`, execute: async ({ context: { city } }) => { // Tool logic here (e.g., API call) console.log("Using tool to fetch weather information for", city); return { temperature: 20, conditions: "Sunny" }; // Example return }, }); ``` For details on creating and designing tools, see the [Tools Overview](/docs/tools-mcp/overview). ## Adding Tools to an Agent To make a tool available to an agent, add it to the `tools` property in the agent's configuration. ```typescript filename="src/mastra/agents/weatherAgent.ts" {3,11} import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { weatherInfo } from "../tools/weatherInfo"; export const weatherAgent = new Agent({ name: "Weather Agent", instructions: "You are a helpful assistant that provides current weather information. When asked about the weather, use the weather information tool to fetch the data.", model: openai("gpt-4o-mini"), tools: { weatherInfo, }, }); ``` When you call the agent, it can now decide to use the configured tool based on its instructions and the user's prompt. ## Adding MCP Tools to an Agent [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) provides a standardized way for AI models to discover and interact with external tools and resources. You can connect your Mastra agent to MCP servers to use tools provided by third parties. For more details on MCP concepts and how to set up MCP clients and servers, see the [MCP Overview](/docs/tools-mcp/mcp-overview). ### Installation First, install the Mastra MCP package: ```bash npm2yarn copy npm install @mastra/mcp@latest ``` ### Using MCP Tools Because there are so many MCP server registries to choose from, we've created an [MCP Registry Registry](https://mastra.ai/mcp-registry-registry) to help you find MCP servers. Once you have a server you want to use with your agent, import the Mastra `MCPClient` and add the server configuration. ```typescript filename="src/mastra/mcp.ts" {1,7-16} import { MCPClient } from "@mastra/mcp"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // Configure MCPClient to connect to your server(s) export const mcp = new MCPClient({ servers: { filesystem: { command: "npx", args: [ "-y", "@modelcontextprotocol/server-filesystem", "/Users/username/Downloads", ], }, }, }); ``` Then connect your agent to the server tools: ```typescript filename="src/mastra/agents/mcpAgent.ts" {7} import { mcp } from "../mcp"; // Create an agent and add tools from the MCP client const agent = new Agent({ name: "Agent with MCP Tools", instructions: "You can use tools from connected MCP servers.", model: openai("gpt-4o-mini"), tools: await mcp.getTools(), }); ``` For more details on configuring `MCPClient` and the difference between static and dynamic MCP server configurations, see the [MCP Overview](/docs/tools-mcp/mcp-overview). ## Accessing MCP Resources In addition to tools, MCP servers can also expose resources - data or content that can be retrieved and used in your application. ```typescript filename="src/mastra/resources.ts" {3-8} import { mcp } from "./mcp"; // Get resources from all connected MCP servers const resources = await mcp.getResources(); // Access resources from a specific server if (resources.filesystem) { const resource = resources.filesystem.find( (r) => r.uri === "filesystem://Downloads", ); console.log(`Resource: ${resource?.name}`); } ``` Each resource has a URI, name, description, and MIME type. The `getResources()` method handles errors gracefully - if a server fails or doesn't support resources, it will be omitted from the results. ## Accessing MCP Prompts MCP servers can also expose prompts, which represent structured message templates or conversational context for agents. ### Listing Prompts ```typescript filename="src/mastra/prompts.ts" import { mcp } from "./mcp"; // Get prompts from all connected MCP servers const prompts = await mcp.prompts.list(); // Access prompts from a specific server if (prompts.weather) { const prompt = prompts.weather.find( (p) => p.name === "current" ); console.log(`Prompt: ${prompt?.name}`); } ``` Each prompt has a name, description, and (optional) version. ### Retrieving a Prompt and Its Messages ```typescript filename="src/mastra/prompts.ts" const { prompt, messages } = await mcp.prompts.get({ serverName: "weather", name: "current" }); console.log(prompt); // { name: "current", version: "v1", ... } console.log(messages); // [ { role: "assistant", content: { type: "text", text: "..." } }, ... ] ``` ## Exposing Agents as Tools via MCPServer In addition to using tools from MCP servers, your Mastra Agents themselves can be exposed as tools to any MCP-compatible client using Mastra's `MCPServer`. When an `Agent` instance is provided to an `MCPServer` configuration: - It is automatically converted into a callable tool. - The tool is named `ask_`, where `` is the identifier you used when adding the agent to the `MCPServer`'s `agents` configuration. - The agent's `description` property (which must be a non-empty string) is used to generate the tool's description. This allows other AI models or MCP clients to interact with your Mastra Agents as if they were standard tools, typically by "asking" them a question. **Example `MCPServer` Configuration with an Agent:** ```typescript filename="src/mastra/mcp.ts" import { Agent } from "@mastra/core/agent"; import { MCPServer } from "@mastra/mcp"; import { openai } from "@ai-sdk/openai"; import { weatherInfo } from "../tools/weatherInfo"; import { generalHelper } from "../agents/generalHelper"; const server = new MCPServer({ name: "My Custom Server with Agent-Tool", version: "1.0.0", tools: { weatherInfo, }, agents: { generalHelper }, // Exposes 'ask_generalHelper' tool }); ``` For an agent to be successfully converted into a tool by `MCPServer`, its `description` property must be set to a non-empty string in its constructor configuration. If the description is missing or empty, `MCPServer` will throw an error during initialization. For more details on setting up and configuring `MCPServer`, refer to the [MCPServer reference documentation](/reference/tools/mcp-server). --- title: "MastraClient" description: "Learn how to set up and use the Mastra Client SDK" --- # Mastra Client SDK [EN] Source: https://mastra.ai/en/docs/client-js/overview The Mastra Client SDK provides a simple and type-safe interface for interacting with your [Mastra Server](/docs/deployment/server) from your client environment. ## Development Requirements To ensure smooth local development, make sure you have: - Node.js 18.x or later installed - TypeScript 4.7+ (if using TypeScript) - A modern browser environment with Fetch API support - Your local Mastra server running (typically on port 4111) ## Installation import { Tabs } from "nextra/components"; {/* LLM CONTEXT: This Tabs component shows installation commands for the Mastra Client SDK using different package managers. Each tab displays the installation command for that specific package manager (npm, yarn, pnpm). This helps users install the client SDK with their preferred package manager. All commands install the same @mastra/client-js package but use different package manager syntax. */} ```bash copy npm install @mastra/client-js@latest ``` ```bash copy yarn add @mastra/client-js@latest ``` ```bash copy pnpm add @mastra/client-js@latest ``` ## Initialize Mastra Client To get started you'll need to initialize your MastraClient with necessary parameters: ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient({ baseUrl: "http://localhost:4111", // Default Mastra development server port }); ``` ### Configuration Options You can customize the client with various options: ```typescript const client = new MastraClient({ // Required baseUrl: "http://localhost:4111", // Optional configurations for development retries: 3, // Number of retry attempts backoffMs: 300, // Initial retry backoff time maxBackoffMs: 5000, // Maximum retry backoff time headers: { // Custom headers for development "X-Development": "true", }, }); ``` ## Example Once your MastraClient is initialized you can start making client calls via the type-safe interface ```typescript // Get a reference to your local agent const agent = client.getAgent("dev-agent-id"); // Generate responses const response = await agent.generate({ messages: [ { role: "user", content: "Hello, I'm testing the local development setup!", }, ], }); ``` ## Available Features Mastra client exposes all resources served by the Mastra Server - [**Agents**](/reference/client-js/agents): Create and manage AI agents, generate responses, and handle streaming interactions - [**Memory**](/reference/client-js/memory): Manage conversation threads and message history - [**Tools**](/reference/client-js/tools): Access and execute tools available to agents - [**Workflows**](/reference/client-js/workflows): Create and manage automated workflows - [**Vectors**](/reference/client-js/vectors): Handle vector operations for semantic search and similarity matching ## Best Practices 1. **Error Handling**: Implement proper error handling for development scenarios 2. **Environment Variables**: Use environment variables for configuration 3. **Debugging**: Enable detailed logging when needed ```typescript // Example with error handling and logging try { const agent = client.getAgent("dev-agent-id"); const response = await agent.generate({ messages: [{ role: "user", content: "Test message" }], }); console.log("Response:", response); } catch (error) { console.error("Development error:", error); } ``` ## Debug - Sometimes when using MastraClient on the server instead of the client e.g `/api/chat`, you might need to recreate the response to your client: ```typescript const result = agent.stream(/* get your agent stream */); return new Response(result.body); ``` --- title: "Discord Community and Bot | Documentation | Mastra" description: Information about the Mastra Discord community and MCP bot. --- # Discord Community [EN] Source: https://mastra.ai/en/docs/community/discord The Discord server has over 1000 members and serves as the main discussion forum for Mastra. The Mastra team monitors Discord during North American and European business hours, with community members active across other time zones.[Join the Discord server](https://discord.gg/BTYqqHKUrf). ## Discord MCP Bot In addition to community members, we have an (experimental!) Discord bot that can also help answer questions. It uses [Model Context Protocol (MCP)](/docs/agents/mcp-guide). You can ask it a question with `/ask` (either in public channels or DMs) and clear history (in DMs only) with `/cleardm`. --- title: "Licensing" description: "Mastra License" --- # License [EN] Source: https://mastra.ai/en/docs/community/licensing ## Elastic License 2.0 (ELv2) Mastra is licensed under the Elastic License 2.0 (ELv2), a modern license designed to balance open-source principles with sustainable business practices. ### What is Elastic License 2.0? The Elastic License 2.0 is a source-available license that grants users broad rights to use, modify, and distribute the software while including specific limitations to protect the project's sustainability. It allows: - Free use for most purposes - Viewing, modifying, and redistributing the source code - Creating and distributing derivative works - Commercial use within your organization The primary limitation is that you cannot provide Mastra as a hosted or managed service that offers users access to the substantial functionality of the software. ### Why We Chose Elastic License 2.0 We selected the Elastic License 2.0 for several important reasons: 1. **Sustainability**: It enables us to maintain a healthy balance between openness and the ability to sustain long-term development. 2. **Innovation Protection**: It ensures we can continue investing in innovation without concerns about our work being repackaged as competing services. 3. **Community Focus**: It maintains the spirit of open source by allowing users to view, modify, and learn from our code while protecting our ability to support the community. 4. **Business Clarity**: It provides clear guidelines for how Mastra can be used in commercial contexts. ### Building Your Business with Mastra Despite the licensing restrictions, there are numerous ways to build successful businesses using Mastra: #### Allowed Business Models - **Building Applications**: Create and sell applications built with Mastra - **Offering Consulting Services**: Provide expertise, implementation, and customization services - **Developing Custom Solutions**: Build bespoke AI solutions for clients using Mastra - **Creating Add-ons and Extensions**: Develop and sell complementary tools that extend Mastra's functionality - **Training and Education**: Offer courses and educational materials about using Mastra effectively #### Examples of Compliant Usage - A company builds an AI-powered customer service application using Mastra and sells it to clients - A consulting firm offers implementation and customization services for Mastra - A developer creates specialized agents and tools with Mastra and licenses them to other businesses - A startup builds a vertical-specific solution (e.g., healthcare AI assistant) powered by Mastra #### What to Avoid The main restriction is that you cannot offer Mastra itself as a hosted service where users access its core functionality. This means: - Don't create a SaaS platform that is essentially Mastra with minimal modifications - Don't offer a managed Mastra service where customers are primarily paying to use Mastra's features ### Questions About Licensing? If you have specific questions about how the Elastic License 2.0 applies to your use case, please [contact us](https://discord.gg/BTYqqHKUrf) on Discord for clarification. We're committed to supporting legitimate business use cases while protecting the sustainability of the project. --- title: "Custom API Routes" description: "Expose additional HTTP endpoints from your Mastra server." --- # Custom API Routes [EN] Source: https://mastra.ai/en/docs/deployment/custom-api-routes By default Mastra automatically exposes registered agents and workflows via the server. For additional behaviour you can define your own HTTP routes. Routes are provided with a helper `registerApiRoute` from `@mastra/core/server`. Routes can live in the same file as the `Mastra` instance but separating them helps keep configuration concise. ```typescript copy showLineNumbers import { Mastra } from "@mastra/core"; import { registerApiRoute } from "@mastra/core/server"; export const mastra = new Mastra({ server: { apiRoutes: [ registerApiRoute("/my-custom-route", { method: "GET", handler: async (c) => { const mastra = c.get("mastra"); const agents = await mastra.getAgent("my-agent"); return c.json({ message: "Hello, world!" }); }, }), ], }, }); ``` Each route's handler receives the Hono `Context`. Within the handler you can access the `Mastra` instance to fetch or call agents and workflows. To add route-specific middleware pass a `middleware` array when calling `registerApiRoute`. ```typescript copy showLineNumbers registerApiRoute("/my-custom-route", { method: "GET", middleware: [ async (c, next) => { console.log(`${c.req.method} ${c.req.url}`); await next(); }, ], handler: async (c) => { return c.json({ message: "My route with custom middleware" }); }, }); ``` --- title: "Serverless Deployment" description: "Build and deploy Mastra applications using platform-specific deployers or standard HTTP servers" --- # Serverless Deployment [EN] Source: https://mastra.ai/en/docs/deployment/deployment This guide covers deploying standalone Mastra applications to Cloudflare Workers, Vercel, and Netlify using platform-specific deployers. Deployers **aren't** required when integrating Mastra with a framework. See [Web Framework Integration](/docs/deployment/web-framework) for more information. For self-hosted Node.js server deployment, see the [Creating A Mastra Server](/docs/deployment/server) guide. ## Prerequisites Before you begin, ensure you have: - **Node.js** installed (version 18 or higher is recommended) - If using a platform-specific deployer: - An account with your chosen platform - Required API keys or credentials ## LibSQLStore `LibSQLStore` writes to the local filesystem, which is not supported in serverless environments due to their ephemeral nature. If you're deploying to a platform like Vercel, Netlify or Cloudflare, you **must remove** all usage of `LibSQLStore`. Specifically, ensure you've removed it from both `src/mastra/index.ts` and `src/mastra/agents/weather-agent.ts`: ```diff filename="src/mastra/index.ts" showLineNumbers export const mastra = new Mastra({ // ... - storage: new LibSQLStore({ - // stores telemetry, evals, ... into memory storage, if it needs to persist, change to file:../mastra.db - url: ":memory:", - }) }); ``` ``` diff filename="src/mastra/agents/weather-agent.ts" showLineNumbers export const weatherAgent = new Agent({ // .. - memory: new Memory({ - storage: new LibSQLStore({ - url: "file:../mastra.db" // path is relative to the .mastra/output directory - }) - }) }); ``` ## Serverless Platform Deployers Platform-specific deployers handle configuration and deployment for: - **[Cloudflare Workers](/reference/deployer/cloudflare)** - **[Vercel](/reference/deployer/vercel)** - **[Netlify](/reference/deployer/netlify)** - **[Mastra Cloud](/docs/mastra-cloud/overview)** _(beta)_. You can join the [cloud waitlist](https://mastra.ai/cloud-beta) for early access. --- title: "Middleware" description: "Apply custom middleware functions to intercept requests." --- # Middleware [EN] Source: https://mastra.ai/en/docs/deployment/middleware Mastra servers can execute custom middleware functions before or after an API route handler is invoked. This is useful for things like authentication, logging, injecting request-specific context or adding CORS headers. A middleware receives the [Hono](https://hono.dev) `Context` (`c`) and a `next` function. If it returns a `Response` the request is short-circuited. Calling `next()` continues processing the next middleware or route handler. ```typescript copy showLineNumbers import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ server: { middleware: [ { handler: async (c, next) => { // Example: Add authentication check const authHeader = c.req.header("Authorization"); if (!authHeader) { return new Response("Unauthorized", { status: 401 }); } await next(); }, path: "/api/*", }, // Add a global request logger async (c, next) => { console.log(`${c.req.method} ${c.req.url}`); await next(); }, ], }, }); ``` To attach middleware to a single route pass the `middleware` option to `registerApiRoute`: ```typescript copy showLineNumbers registerApiRoute("/my-custom-route", { method: "GET", middleware: [ async (c, next) => { console.log(`${c.req.method} ${c.req.url}`); await next(); }, ], handler: async (c) => { const mastra = c.get("mastra"); return c.json({ message: "Hello, world!" }); }, }); ``` --- ## Common examples ### Authentication ```typescript copy { handler: async (c, next) => { const authHeader = c.req.header('Authorization'); if (!authHeader || !authHeader.startsWith('Bearer ')) { return new Response('Unauthorized', { status: 401 }); } // Validate token here await next(); }, path: '/api/*', } ``` ### CORS support ```typescript copy { handler: async (c, next) => { c.header('Access-Control-Allow-Origin', '*'); c.header( 'Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS', ); c.header( 'Access-Control-Allow-Headers', 'Content-Type, Authorization', ); if (c.req.method === 'OPTIONS') { return new Response(null, { status: 204 }); } await next(); }, } ``` ### Request logging ```typescript copy { handler: async (c, next) => { const start = Date.now(); await next(); const duration = Date.now() - start; console.log(`${c.req.method} ${c.req.url} - ${duration}ms`); }, } ``` ### Special Mastra headers When integrating with Mastra Cloud or custom clients the following headers can be inspected by middleware to tailor behaviour: ```typescript copy { handler: async (c, next) => { const isFromMastraCloud = c.req.header('x-mastra-cloud') === 'true'; const clientType = c.req.header('x-mastra-client-type'); const isDevPlayground = c.req.header('x-mastra-dev-playground') === 'true'; if (isFromMastraCloud) { // Special handling } await next(); }, } ``` - `x-mastra-cloud`: request originates from Mastra Cloud - `x-mastra-client-type`: identifies the client SDK, e.g. `js` or `python` - `x-mastra-dev-playground`: request triggered from a local playground --- title: Deployment Overview description: Learn about different deployment options for your Mastra applications --- # Deployment Overview [EN] Source: https://mastra.ai/en/docs/deployment/overview Mastra offers multiple deployment options to suit your application's needs, from fully-managed solutions to self-hosted options, and web framework integrations. This guide will help you understand the available deployment paths and choose the right one for your project. ## Deployment Options ### Mastra Cloud Mastra Cloud is a deployment platform that connects to your GitHub repository, automatically deploys on code changes, and provides monitoring tools. It includes: - GitHub repository integration - Deployment on git push - Agent testing interface - Comprehensive logs and traces - Custom domains for each project [View Mastra Cloud documentation →](/docs/mastra-cloud/overview) ### With a Web Framework Mastra can be integrated with a variety of web frameworks. For example, see one of the following for a detailed guide. - [With Next.js](/docs/frameworks/web-frameworks/next-js) - [With Astro](/docs/frameworks/web-frameworks/astro) When integrated with a framework, Mastra typically requires no additional configuration for deployment. [View Web Framework Integration →](/docs/deployment/web-framework) ### With a Server You can deploy Mastra as a standard Node.js HTTP server, which gives you full control over your infrastructure and deployment environment. - Custom API routes and middleware - Configurable CORS and authentication - Deploy to VMs, containers, or PaaS platforms - Ideal for integrating with existing Node.js applications [Server deployment guide →](/docs/deployment/server) ### Serverless Platforms Mastra provides platform-specific deployers for popular serverless platforms, enabling you to deploy your application with minimal configuration. - Deploy to Cloudflare Workers, Vercel, or Netlify - Platform-specific optimizations - Simplified deployment process - Automatic scaling through the platform [Serverless deployment guide →](/docs/deployment/deployment) ## Client Configuration Once your Mastra application is deployed, you'll need to configure your client to communicate with it. The Mastra Client SDK provides a simple and type-safe interface for interacting with your Mastra server. - Type-safe API interactions - Authentication and request handling - Retries and error handling - Support for streaming responses [Client configuration guide →](/docs/deployment/client) ## Choosing a Deployment Option | Option | Best For | Key Benefits | | ------------------------ | ------------------------------------------------------------- | -------------------------------------------------------------- | | **Mastra Cloud** | Teams wanting to ship quickly without infrastructure concerns | Fully-managed, automatic scaling, built-in observability | | **Framework Deployment** | Teams already using Next.js, Astro etc | Simplify deployment with a unified codebase for frontend and backend | | **Server Deployment** | Teams needing maximum control and customization | Full control, custom middleware, integrate with existing apps | | **Serverless Platforms** | Teams already using Vercel, Netlify, or Cloudflare | Platform integration, simplified deployment, automatic scaling | --- title: "Creating A Mastra Server" description: "Configure and customize the Mastra server with middleware and other options" --- # Creating A Mastra Server [EN] Source: https://mastra.ai/en/docs/deployment/server While developing or when you deploy a Mastra application, it runs as an HTTP server that exposes your agents, workflows, and other functionality as API endpoints. This page explains how to configure and customize the server behavior. ## Server Architecture Mastra uses [Hono](https://hono.dev) as its underlying HTTP server framework. When you build a Mastra application using `mastra build`, it generates a Hono-based HTTP server in the `.mastra` directory. The server provides: - API endpoints for all registered agents - API endpoints for all registered workflows - Custom api route supports - Custom middleware support - Configuration of timeout - Configuration of port - Configuration of body limit See the [Middleware](/docs/deployment/middleware) and [Custom API Routes](/docs/deployment/custom-api-routes) pages for details on adding additional server behaviour. ## Server configuration You can configure server `port` and `timeout` in the Mastra instance. ```typescript copy showLineNumbers import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ server: { port: 3000, // Defaults to 4111 timeout: 10000, // Defaults to 30000 (30s) }, }); ``` The `method` option can be one of `"GET"`, `"POST"`, `"PUT"`, `"DELETE"` or `"ALL"`. Using `"ALL"` will cause the handler to be invoked for any HTTP method that matches the path. ## Custom CORS Config Mastra allows you to configure CORS (Cross-Origin Resource Sharing) settings for your server. ```typescript copy showLineNumbers import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ server: { cors: { origin: ["https://example.com"], // Allow specific origins or '*' for all allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], allowHeaders: ["Content-Type", "Authorization"], credentials: false, }, }, }); ``` ## Deployment Since Mastra builds to a standard Node.js server, you can deploy to any platform that runs Node.js applications: - Cloud VMs (AWS EC2, DigitalOcean Droplets, GCP Compute Engine) - Container platforms (Docker, Kubernetes) - Platform as a Service (Heroku, Railway) - Self-hosted servers ### Building Build the application: ```bash copy # Build from current directory mastra build # Or specify a directory mastra build --dir ./my-project ``` The build process: 1. Locates entry file (`src/mastra/index.ts` or `src/mastra/index.js`) 2. Creates `.mastra` output directory 3. Bundles code using Rollup with tree shaking and source maps 4. Generates [Hono](https://hono.dev) HTTP server See [`mastra build`](/reference/cli/build) for all options. ### Running the Server Start the HTTP server: ```bash copy node .mastra/output/index.mjs ``` ### Enable Telemetry for build output Load instrumentation for the build output like so: ```bash copy node --import=./.mastra/output/instrumentation.mjs .mastra/output/index.mjs ``` ## Serverless Deployment Mastra also supports serverless deployment on Cloudflare Workers, Vercel, and Netlify. See our [Serverless Deployment](/docs/deployment/deployment) guide for setup instructions. --- title: "Deploying Mastra with a Web Framework" description: "Learn how Mastra can be deployed when integrated with a Web Framework" --- # Web Framework Integration [EN] Source: https://mastra.ai/en/docs/deployment/web-framework This guide covers deploying integrated Mastra applications. Mastra can be integrated with a variety of web frameworks, see one of the following for a detailed guide. - [With Next.js](/docs/frameworks/web-frameworks/next-js) - [With Astro](/docs/frameworks/web-frameworks/astro) When integrated with a framework, Mastra typically requires no additional configuration for deployment. ## With Next.js on Vercel If you've integrated Mastra with Next.js [by following our guide](/docs/frameworks/web-frameworks/next-js) and plan to deploy to Vercel, no additional setup is required. The only thing to verify is that you've added the following to your `next.config.ts` and removed any usage of [LibSQLStore](/docs/deployment/deployment#libsqlstore), which is not supported in serverless environments: ```typescript {4} filename="next.config.ts" showLineNumbers copy import type { NextConfig } from "next"; const nextConfig: NextConfig = { serverExternalPackages: ["@mastra/*"], }; export default nextConfig; ``` ## With Astro on Vercel If you've integrated Mastra with Astro [by following our guide](/docs/frameworks/web-frameworks/astro) and plan to deploy to Vercel, no additional setup is required. The only thing to verify is that you've added the following to your `astro.config.mjs` and removed any usage of [LibSQLStore](/docs/deployment/deployment#libsqlstore), which is not supported in serverless environments: ```javascript {2,6,7} filename="astro.config.mjs" showLineNumbers copy import { defineConfig } from 'astro/config'; import vercel from '@astrojs/vercel'; export default defineConfig({ // ... adapter: vercel(), output: "server" }); ``` ## With Astro on Netlify If you've integrated Mastra with Astro [by following our guide](/docs/frameworks/web-frameworks/astro) and plan to deploy to Vercel, no additional setup is required. The only thing to verify is that you've added the following to your `astro.config.mjs` and removed any usage of [LibSQLStore](/docs/deployment/deployment#libsqlstore), which is not supported in serverless environments: ```javascript {2,6,7} filename="astro.config.mjs" showLineNumbers copy import { defineConfig } from 'astro/config'; import vercel from '@astrojs/netlify'; export default defineConfig({ // ... adapter: netlify(), output: "server" }); ``` --- title: "Create your own Eval" description: "Mastra allows so create your own evals, here is how." --- # Create your own Eval [EN] Source: https://mastra.ai/en/docs/evals/custom-eval Creating your own eval is as easy as creating a new function. You simply create a class that extends the `Metric` class and implement the `measure` method. ## Basic example For a simple example of creating a custom metric that checks if the output contains certain words, see our [Word Inclusion example](/examples/evals/word-inclusion). ## Creating a custom LLM-Judge A custom LLM judge helps evaluate specific aspects of your AI's responses. Think of it like having an expert reviewer for your particular use case: - Medical Q&A → Judge checks for medical accuracy and safety - Customer Service → Judge evaluates tone and helpfulness - Code Generation → Judge verifies code correctness and style For a practical example, see how we evaluate [Chef Michel's](/docs/guides/chef-michel) recipes for gluten content in our [Gluten Checker example](/examples/evals/custom-eval). --- title: "Overview" description: "Understanding how to evaluate and measure AI agent quality using Mastra evals." --- # Testing your agents with evals [EN] Source: https://mastra.ai/en/docs/evals/overview While traditional software tests have clear pass/fail conditions, AI outputs are non-deterministic — they can vary with the same input. Evals help bridge this gap by providing quantifiable metrics for measuring agent quality. Evals are automated tests that evaluate Agents outputs using model-graded, rule-based, and statistical methods. Each eval returns a normalized score between 0-1 that can be logged and compared. Evals can be customized with your own prompts and scoring functions. Evals can be run in the cloud, capturing real-time results. But evals can also be part of your CI/CD pipeline, allowing you to test and monitor your agents over time. ## Types of Evals There are different kinds of evals, each serving a specific purpose. Here are some common types: 1. **Textual Evals**: Evaluate accuracy, reliability, and context understanding of agent responses 2. **Classification Evals**: Measure accuracy in categorizing data based on predefined categories 3. **Prompt Engineering Evals**: Explore impact of different instructions and input formats ## Getting Started Evals need to be added to an agent. Here's an example using the summarization, content similarity, and tone consistency metrics: ```typescript copy showLineNumbers filename="src/mastra/agents/index.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { SummarizationMetric } from "@mastra/evals/llm"; import { ContentSimilarityMetric, ToneConsistencyMetric, } from "@mastra/evals/nlp"; const model = openai("gpt-4o"); export const myAgent = new Agent({ name: "ContentWriter", instructions: "You are a content writer that creates accurate summaries", model, evals: { summarization: new SummarizationMetric(model), contentSimilarity: new ContentSimilarityMetric(), tone: new ToneConsistencyMetric(), }, }); ``` You can view eval results in the Mastra dashboard when using `mastra dev`. ## Beyond Automated Testing While automated evals are valuable, high-performing AI teams often combine them with: 1. **A/B Testing**: Compare different versions with real users 2. **Human Review**: Regular review of production data and traces 3. **Continuous Monitoring**: Track eval metrics over time to detect regressions ## Understanding Eval Results Each eval metric measures a specific aspect of your agent's output. Here's how to interpret and improve your results: ### Understanding Scores For any metric: 1. Check the metric documentation to understand the scoring process 2. Look for patterns in when scores change 3. Compare scores across different inputs and contexts 4. Track changes over time to spot trends ### Improving Results When scores aren't meeting your targets: 1. Check your instructions - Are they clear? Try making them more specific 2. Look at your context - Is it giving the agent what it needs? 3. Simplify your prompts - Break complex tasks into smaller steps 4. Add guardrails - Include specific rules for tricky cases ### Maintaining Quality Once you're hitting your targets: 1. Monitor stability - Do scores remain consistent? 2. Document what works - Keep notes on successful approaches 3. Test edge cases - Add examples that cover unusual scenarios 4. Fine-tune - Look for ways to improve efficiency See [Textual Evals](/docs/evals/textual-evals) for more info on what evals can do. For more info on how to create your own evals, see the [Custom Evals](/docs/evals/custom-eval) guide. For running evals in your CI pipeline, see the [Running in CI](/docs/evals/running-in-ci) guide. --- title: "Running in CI" description: "Learn how to run Mastra evals in your CI/CD pipeline to monitor agent quality over time." --- # Running Evals in CI [EN] Source: https://mastra.ai/en/docs/evals/running-in-ci Running evals in your CI pipeline helps bridge this gap by providing quantifiable metrics for measuring agent quality over time. ## Setting Up CI Integration We support any testing framework that supports ESM modules. For example, you can use [Vitest](https://vitest.dev/), [Jest](https://jestjs.io/) or [Mocha](https://mochajs.org/) to run evals in your CI/CD pipeline. ```typescript copy showLineNumbers filename="src/mastra/agents/index.test.ts" import { describe, it, expect } from "vitest"; import { evaluate } from "@mastra/evals"; import { ToneConsistencyMetric } from "@mastra/evals/nlp"; import { myAgent } from "./index"; describe("My Agent", () => { it("should validate tone consistency", async () => { const metric = new ToneConsistencyMetric(); const result = await evaluate(myAgent, "Hello, world!", metric); expect(result.score).toBe(1); }); }); ``` You will need to configure a testSetup and globalSetup script for your testing framework to capture the eval results. It allows us to show these results in your mastra dashboard. ## Framework Configuration ### Vitest Setup Add these files to your project to run evals in your CI/CD pipeline: ```typescript copy showLineNumbers filename="globalSetup.ts" import { globalSetup } from "@mastra/evals"; export default function setup() { globalSetup(); } ``` ```typescript copy showLineNumbers filename="testSetup.ts" import { beforeAll } from "vitest"; import { attachListeners } from "@mastra/evals"; beforeAll(async () => { await attachListeners(); }); ``` ```typescript copy showLineNumbers filename="vitest.config.ts" import { defineConfig } from "vitest/config"; export default defineConfig({ test: { globalSetup: "./globalSetup.ts", setupFiles: ["./testSetup.ts"], }, }); ``` ## Storage Configuration To store eval results in Mastra Storage and capture results in the Mastra dashboard: ```typescript copy showLineNumbers filename="testSetup.ts" import { beforeAll } from "vitest"; import { attachListeners } from "@mastra/evals"; import { mastra } from "./your-mastra-setup"; beforeAll(async () => { // Store evals in Mastra Storage (requires storage to be enabled) await attachListeners(mastra); }); ``` With file storage, evals persist and can be queried later. With memory storage, evals are isolated to the test process. --- title: "Textual Evals" description: "Understand how Mastra uses LLM-as-judge methodology to evaluate text quality." --- # Textual Evals [EN] Source: https://mastra.ai/en/docs/evals/textual-evals Textual evals use an LLM-as-judge methodology to evaluate agent outputs. This approach leverages language models to assess various aspects of text quality, similar to how a teaching assistant might grade assignments using a rubric. Each eval focuses on specific quality aspects and returns a score between 0 and 1, providing quantifiable metrics for non-deterministic AI outputs. Mastra provides several eval metrics for assessing Agent outputs. Mastra is not limited to these metrics, and you can also [define your own evals](/docs/evals/custom-eval). ## Why Use Textual Evals? Textual evals help ensure your agent: - Produces accurate and reliable responses - Uses context effectively - Follows output requirements - Maintains consistent quality over time ## Available Metrics ### Accuracy and Reliability These metrics evaluate how correct, truthful, and complete your agent's answers are: - [`hallucination`](/reference/evals/hallucination): Detects facts or claims not present in provided context - [`faithfulness`](/reference/evals/faithfulness): Measures how accurately responses represent provided context - [`content-similarity`](/reference/evals/content-similarity): Evaluates consistency of information across different phrasings - [`completeness`](/reference/evals/completeness): Checks if responses include all necessary information - [`answer-relevancy`](/reference/evals/answer-relevancy): Assesses how well responses address the original query - [`textual-difference`](/reference/evals/textual-difference): Measures textual differences between strings ### Understanding Context These metrics evaluate how well your agent uses provided context: - [`context-position`](/reference/evals/context-position): Analyzes where context appears in responses - [`context-precision`](/reference/evals/context-precision): Evaluates whether context chunks are grouped logically - [`context-relevancy`](/reference/evals/context-relevancy): Measures use of appropriate context pieces - [`contextual-recall`](/reference/evals/contextual-recall): Assesses completeness of context usage ### Output Quality These metrics evaluate adherence to format and style requirements: - [`tone`](/reference/evals/tone-consistency): Measures consistency in formality, complexity, and style - [`toxicity`](/reference/evals/toxicity): Detects harmful or inappropriate content - [`bias`](/reference/evals/bias): Detects potential biases in the output - [`prompt-alignment`](/reference/evals/prompt-alignment): Checks adherence to explicit instructions like length restrictions, formatting requirements, or other constraints - [`summarization`](/reference/evals/summarization): Evaluates information retention and conciseness - [`keyword-coverage`](/reference/evals/keyword-coverage): Assesses technical terminology usage --- title: "Using with Vercel AI SDK" description: "Learn how Mastra leverages the Vercel AI SDK library and how you can leverage it further with Mastra" --- import Image from "next/image"; # Using with Vercel AI SDK [EN] Source: https://mastra.ai/en/docs/frameworks/agentic-uis/ai-sdk Mastra leverages AI SDK's model routing (a unified interface on top of OpenAI, Anthropic, etc), structured output, and tool calling. We explain this in greater detail in [this blog post](https://mastra.ai/blog/using-ai-sdk-with-mastra) ## Mastra + AI SDK Mastra acts as a layer on top of AI SDK to help teams productionize their proof-of-concepts quickly and easily. Agent interaction trace showing spans, LLM calls, and tool executions ## Model routing When creating agents in Mastra, you can specify any AI SDK-supported model: ```typescript import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; const agent = new Agent({ name: "WeatherAgent", instructions: "Instructions for the agent...", model: openai("gpt-4-turbo"), // Model comes directly from AI SDK }); const result = await agent.generate("What is the weather like?"); ``` ## AI SDK Hooks Mastra is compatible with AI SDK's hooks for seamless frontend integration: ### useChat The `useChat` hook enables real-time chat interactions in your frontend application - Works with agent data streams i.e. `.toDataStreamResponse()` - The useChat `api` defaults to `/api/chat` - Works with the Mastra REST API agent stream endpoint `{MASTRA_BASE_URL}/agents/:agentId/stream` for data streams, i.e. no structured output is defined. ```typescript filename="app/api/chat/route.ts" copy import { mastra } from "@/src/mastra"; export async function POST(req: Request) { const { messages } = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); const stream = await myAgent.stream(messages); return stream.toDataStreamResponse(); } ``` ```typescript copy import { useChat } from '@ai-sdk/react'; export function ChatComponent() { const { messages, input, handleInputChange, handleSubmit } = useChat({ api: '/path-to-your-agent-stream-api-endpoint' }); return (
{messages.map(m => (
{m.role}: {m.content}
))}
); } ``` > **Gotcha**: When using `useChat` with agent memory functionality, make sure to check out the [Agent Memory section](/docs/agents/agent-memory#usechat) for important implementation details. ### useCompletion For single-turn completions, use the `useCompletion` hook: - Works with agent data streams i.e. `.toDataStreamResponse()` - The useCompletion `api` defaults to `/api/completion` - Works with the Mastra REST API agent stream endpoint `{MASTRA_BASE_URL}/agents/:agentId/stream` for data streams, i.e. no structured output is defined. ```typescript filename="app/api/completion/route.ts" copy import { mastra } from "@/src/mastra"; export async function POST(req: Request) { const { prompt } = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); const stream = await myAgent.stream([{ role: "user", content: prompt }]); return stream.toDataStreamResponse(); } ``` ```typescript import { useCompletion } from "@ai-sdk/react"; export function CompletionComponent() { const { completion, input, handleInputChange, handleSubmit, } = useCompletion({ api: '/path-to-your-agent-stream-api-endpoint' }); return (

Completion result: {completion}

); } ``` ### useObject For consuming text streams that represent JSON objects and parsing them into a complete object based on a schema. - Works with agent text streams i.e. `.toTextStreamResponse()` - Works with the Mastra REST API agent stream endpoint `{MASTRA_BASE_URL}/agents/:agentId/stream` for text streams, i.e. structured output is defined. ```typescript filename="app/api/use-object/route.ts" copy import { mastra } from "@/src/mastra"; export async function POST(req: Request) { const body = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); const stream = await myAgent.stream(body, { output: z.object({ weather: z.string(), }), }); return stream.toTextStreamResponse(); } ``` ```typescript import { experimental_useObject as useObject } from '@ai-sdk/react'; export default function Page() { const { object, submit } = useObject({ api: '/api/use-object', schema: z.object({ weather: z.string(), }), }); return (
{object?.weather &&

{object.weather}

}
); } ``` ## Tool Calling ### AI SDK Tool Format Mastra supports tools created using the AI SDK format, so you can use them directly with Mastra agents. See our tools doc on [Vercel AI SDK Tool Format ](/docs/agents/adding-tools#vercel-ai-sdk-tool-format) for more details. ### Client-side tool calling Mastra leverages AI SDK's tool calling, so what applies in AI SDK applies here still. [Agent Tools](/docs/agents/adding-tools) in Mastra are 100% percent compatible with AI SDK tools. Mastra tools also expose an optional `execute` async function. It is optional because you might want to forward tool calls to the client or to a queue instead of executing them in the same process. One way to then leverage client-side tool calling is to use the `@ai-sdk/react` `useChat` hook's `onToolCall` property for client-side tool execution ## Custom DataStream In certain scenarios you need to write custom data, message annotations to an agent's dataStream. This can be useful for: - Streaming additional data to the client - Passing progress info back to the client in real time Mastra integrates well with AI SDK to make this possible ### CreateDataStream The `createDataStream` function allows you to stream additional data to the client ```typescript copy import { createDataStream } from "ai"; import { Agent } from "@mastra/core/agent"; export const weatherAgent = new Agent({ name: "Weather Agent", instructions: ` You are a helpful weather assistant that provides accurate weather information. Your primary function is to help users get weather details for specific locations. When responding: - Always ask for a location if none is provided - If the location name isn't in English, please translate it - If giving a location with multiple parts (e.g. "New York, NY"), use the most relevant part (e.g. "New York") - Include relevant details like humidity, wind conditions, and precipitation - Keep responses concise but informative Use the weatherTool to fetch current weather data. `, model: openai("gpt-4o"), tools: { weatherTool }, }); const stream = createDataStream({ async execute(dataStream) { // Write data dataStream.writeData({ value: "Hello" }); // Write annotation dataStream.writeMessageAnnotation({ type: "status", value: "processing" }); //mastra agent stream const agentStream = await weatherAgent.stream("What is the weather"); // Merge agent stream agentStream.mergeIntoDataStream(dataStream); }, onError: (error) => `Custom error: ${error.message}`, }); ``` ### CreateDataStreamResponse The `createDataStreamResponse` function creates a Response object that streams data to the client ```typescript filename="app/api/chat/route.ts" copy import { mastra } from "@/src/mastra"; export async function POST(req: Request) { const { messages } = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); //mastra agent stream const agentStream = await myAgent.stream(messages); const response = createDataStreamResponse({ status: 200, statusText: "OK", headers: { "Custom-Header": "value", }, async execute(dataStream) { // Write data dataStream.writeData({ value: "Hello" }); // Write annotation dataStream.writeMessageAnnotation({ type: "status", value: "processing", }); // Merge agent stream agentStream.mergeIntoDataStream(dataStream); }, onError: (error) => `Custom error: ${error.message}`, }); return response; } ``` --- title: Using with Assistant UI description: "Learn how to integrate Assistant UI with Mastra" --- import { Callout, FileTree, Steps } from 'nextra/components' # Using with Assistant UI [EN] Source: https://mastra.ai/en/docs/frameworks/agentic-uis/assistant-ui [Assistant UI](https://assistant-ui.com) is the TypeScript/React library for AI Chat. Built on shadcn/ui and Tailwind CSS, it enables developers to create beautiful, enterprise-grade chat experiences in minutes. ## Integrating with Next.js and Assistant UI There are two primary ways to integrate Mastra into your Next.js project when using Assistant UI: 1. **Full-Stack Integration**: Integrate Mastra directly into your Next.js application's API routes. This approach keeps your backend and frontend code within the same project. [Learn how to set up Full-Stack Integration](#full-stack-integration) 2. **Separate Backend Integration**: Run Mastra as a standalone server and connect your Next.js frontend to its API endpoints. This approach separates concerns and allows for independent scaling. [Learn how to set up Separate Backend Integration](#separate-backend-integration) ## Full-Stack Integration ### Initialize Assistant UI There are two options when setting up Assistant UI using the `assistant-ui` CLI: 1. **New Project**: Create a new Next.js project with Assistant UI. 2. **Existing Project**: Initialize Assistant UI into an existing React project. #### New Project ```bash copy npx assistant-ui@latest create ``` #### Existing Project ```bash copy npx assistant-ui@latest init ``` For detailed setup instructions, including adding API keys, basic configuration, and manual setup steps, please refer to [assistant-ui's official documentation](https://assistant-ui.com/docs). ### Install Mastra Packages Install the required Mastra packages: ```bash copy npm install @mastra/core@latest @mastra/memory@latest @mastra/libsql@latest ``` ### Configure Next.js To ensure Next.js correctly bundles your application when using Mastra directly in API routes, you need to configure `serverExternalPackages`. Update your `next.config.js` file to include `@mastra/`: ```js showLineNumbers copy {3} /** @type {import('next').NextConfig} */ const nextConfig = { serverExternalPackages: ["@mastra/*"], // ... your other Next.js config }; module.exports = nextConfig; ``` ### Configure Mastra Memory and Storage ```typescript showLineNumbers copy filename="mastra/memory.ts" {4,8} import { LibSQLStore } from "@mastra/libsql"; import { Memory } from "@mastra/memory"; export const storage = new LibSQLStore({ url: 'file:./memory.db', }) export const memory = new Memory({ storage, }) ``` If deploying to the edge, you should use a compatible storage solution and not a file-based storage. ### Define Mastra Agent ```typescript showLineNumbers copy filename="mastra/agents/chef-agent.ts" {5-12} import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { memory} from "../memory"; export const chefAgent = new Agent({ name: "chefAgent", instructions: "You are Michel, a practical and experienced home chef. " + "You help people cook with whatever ingredients they have available.", model: openai("gpt-4o-mini"), memory, }); ``` ### Register Agent to Mastra Instance ```typescript showLineNumbers copy filename="mastra/index.ts" {4-5} import { Mastra } from "@mastra/core"; import { chefAgent } from "./agents/chef-agent"; export const mastra = new Mastra({ agents: { chefAgent }, // ... other config }); ``` This initializes Mastra and makes the `chefAgent` available for use. ### Modify the Chat API endpoints The initial bootstrapped Next.js project has a `app/api/chat/route.ts` file that exports a `POST` handler. The initial implementation may look like this: ```typescript showLineNumbers copy filename="app/api/chat/route.ts" {11-21} import { openai } from "@ai-sdk/openai"; import { frontendTools } from "@assistant-ui/react-ai-sdk"; import { streamText } from "ai"; export const runtime = "edge"; export const maxDuration = 30; export async function POST(req: Request) { const { messages, system, tools } = await req.json(); const result = streamText({ model: openai("gpt-4o"), messages, // forward system prompt and tools from the frontend toolCallStreaming: true, system, tools: { ...frontendTools(tools), }, onError: console.log, }); return result.toDataStreamResponse(); } ``` Now we need to modify the `POST` handler to use the `chefAgent` instead of this implementation. ```typescript showLineNumbers copy filename="app/api/chat/route.ts" {1,6,8} import { mastra } from "@/mastra"; export async function POST(req: Request) { const { messages } = await req.json(); const agent = mastra.getAgent("chefAgent"); const stream = await agent.stream(messages); return stream.toDataStreamResponse(); } ``` Key changes - We import the `mastra` instance we created. - We use the `mastra.getAgent("chefAgent")` to get the agent we want to use. - We use the `agent.stream(messages)` to get the stream of messages from the agent. - We return the stream as a data stream response which is compatible with `assistant-ui`. ### Run the application You're all set! Start your Next.js development server: ```bash copy npm run dev ``` You should now be able to chat with your agent in the browser. Congratulations! You have successfully integrated Mastra into your Next.js application using the full-stack approach. Your Assistant UI frontend now communicates with a Mastra agent running in your Next.js backend API route. ## Separate Backend Integration Run Mastra as a standalone server and connect your Next.js frontend (with Assistant UI) to its API endpoints. ### Create Standalone Mastra Server Set up your directory structure. A possible directory structure could look like this: Bootstrap your Mastra server: ```bash copy npx create-mastra@latest ``` This command will launch an interactive wizard to help you scaffold a new Mastra project, including prompting you for a project name and setting up basic configurations. Follow the prompts to create your server project. You now have a basic Mastra server project ready. Ensure that you have set the appropriate environment variables for your LLM provider in the `.env` file. ### Define Mastra Agent ```typescript showLineNumbers copy filename="mastra/agents/chef-agent.ts" {5-12} import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { memory} from "../memory"; export const chefAgent = new Agent({ name: "chefAgent", instructions: "You are Michel, a practical and experienced home chef. " + "You help people cook with whatever ingredients they have available.", model: openai("gpt-4o-mini"), memory, }); ``` ### Register Agent to Mastra Instance ```typescript copy filename="mastra/index.ts" showLineNumbers import { Mastra } from "@mastra/core"; import { chefAgent } from "./agents/chef-agent"; export const mastra = new Mastra({ agents: { chefAgent }, // ... other config }); ``` ### Run the Mastra Server Run the Mastra server using the following command: ```bash copy npm run dev ``` By default, the Mastra server will run on http://localhost:4111. Your chefAgent should now be accessible via a POST request endpoint, typically http://localhost:4111/api/agents/chefAgent/stream. Keep this server running for the next steps where we'll set up the Assistant UI frontend to connect to it. ### Initialize Assistant UI There are two options when setting up Assistant UI using the `assistant-ui` CLI: 1. **New Project**: Create a new Next.js project with Assistant UI. 2. **Existing Project**: Initialize Assistant UI into an existing React project. #### New Project ```bash copy npx assistant-ui@latest create ``` #### Existing Project ```bash copy npx assistant-ui@latest init ``` For detailed setup instructions, including adding API keys, basic configuration, and manual setup steps, please refer to [assistant-ui's official documentation](https://assistant-ui.com/docs). ### Configure Frontend API Endpoint The default Assistant UI setup configures the chat runtime to use a local API route (`/api/chat`) within the Next.js project. Since our Mastra agent is running on a separate server, we need to update the frontend to point to that server's endpoint. Open the main page file in your Assistant UI frontend project (usually `app/page.tsx` or `src/app/page.tsx`). Find the `useChatRuntime` hook and change the `api` property to the full URL of your Mastra agent's stream endpoint: ```typescript showLineNumbers copy filename="app/page.tsx" {2} const runtime = useChatRuntime({ api: "http://localhost:4111/api/agents/chefAgent/stream", }); ``` Now, the Assistant UI frontend will send chat requests directly to your running Mastra server. ### Run the Application You're ready to connect the pieces! Make sure both the Mastra server and the Assistant UI frontend are running. Start the Next.js development server: ```bash copy npm run dev ``` You should now be able to chat with your agent in the browser. Congratulations! You have successfully integrated Mastra with Assistant UI using a separate server approach. Your Assistant UI frontend now communicates with a standalone Mastra agent server. --- title: "Using with CopilotKit" description: "Learn how Mastra leverages the CopilotKit's AGUI library and how you can leverage it to build user experiences" --- import { Tabs } from "nextra/components"; import Image from "next/image"; # Using with CopilotKit in React [EN] Source: https://mastra.ai/en/docs/frameworks/agentic-uis/copilotkit CopilotKit provides React components to quickly integrate customizable AI copilots into your application. Combined with Mastra, you can build sophisticated AI apps featuring bidirectional state synchronization and interactive UIs. ## Create a Mastra Project {/* LLM CONTEXT: This Tabs component shows commands for creating a new Mastra project using different package managers. Each tab displays the command for that specific package manager to create a Mastra project. This is the first step in setting up Mastra with CopilotKit for building AI copilot applications. All commands create the same Mastra project but use different package manager syntax. */} ```bash copy npx create-mastra@latest ``` ```bash copy npm create mastra ``` ```bash copy yarn create mastra ``` ```bash copy pnpm create mastra ``` Select the agent example when scaffolding your project. This will give you a weather agent. For detailed setup instructions, see the [installation guide](/docs/getting-started/installation). ## Basic Setup Integrating Mastra with CopilotKit involves two main steps: setting up the backend runtime and configuring your frontend components. {/* LLM CONTEXT: This Tabs component shows installation commands for the CopilotKit runtime package. Each tab displays the installation command for that specific package manager. This installs the core CopilotKit runtime needed for backend integration with Mastra. All commands install the same @copilotkit/runtime package but use different package manager syntax. */} ```bash copy npm install @copilotkit/runtime ``` ```bash copy yarn add @copilotkit/runtime ``` ```bash copy pnpm add @copilotkit/runtime ``` ## Set up the runtime You can leverage Mastra's custom API routes to add CopilotKit's runtime to your Mastra server. The current version of the integration leverages `MastraClient` to format Mastra agents into the AGUI format of CopilotKit. {/* LLM CONTEXT: This Tabs component shows installation commands for the Mastra AGUI package. Each tab displays the installation command for that specific package manager. This installs the alpha version of @mastra/agui which provides CopilotKit integration capabilities. All commands install the same @mastra/agui@alpha package but use different package manager syntax. */} ```bash copy npm install @mastra/agui@alpha ``` ```bash copy yarn add @mastra/agui@alpha ``` ```bash copy pnpm add @mastra/agui@alpha ``` Next, let's update the Mastra instance with a custom API route for CopilotKit. ```typescript filename="src/mastra/index.ts" showLineNumbers copy import { Mastra } from "@mastra/core/mastra"; import { PinoLogger } from "@mastra/loggers"; import { LibSQLStore } from "@mastra/libsql"; import { CopilotRuntime, copilotRuntimeNodeHttpEndpoint, ExperimentalEmptyAdapter } from "@copilotkit/runtime"; import { registerCopilotKit } from "@mastra/agui"; import { weatherAgent } from "./agents/weather-agent"; const serviceAdapter = new ExperimentalEmptyAdapter(); export const mastra = new Mastra({ agents: { weatherAgent }, storage: new LibSQLStore({ // stores telemetry, evals, ... into memory storage, // if you need to persist, change to file:../mastra.db url: ":memory:" }), logger: new PinoLogger({ name: "Mastra", level: "info" }), server: { // We will be calling this from a Vite App. Allow CORS cors: { origin: "*", allowMethods: ["*"], allowHeaders: ["*"] }, apiRoutes: [ registerCopilotKit({ path: "/copilotkit", resourceId: "weatherAgent", setContext: (c, runtimeContext) => { // Add whatever you need to the runtimeContext runtimeContext.set("user-id", c.req.header("X-User-ID")); runtimeContext.set("temperature-scale", "celsius"); } }) ] } }); ``` With this setup you now have CopilotKit running on your Mastra server. You can start your Mastra server with `mastra dev`. ## Set up the UI Install CopilotKit's React components: {/* LLM CONTEXT: This Tabs component shows installation commands for CopilotKit's React UI components. Each tab displays the installation command for that specific package manager. This installs the React components needed for the frontend CopilotKit integration. All commands install the same @copilotkit/react-core and @copilotkit/react-ui packages but use different package manager syntax. */} ```bash copy npm install @copilotkit/react-core @copilotkit/react-ui ``` ```bash copy yarn add @copilotkit/react-core @copilotkit/react-ui ``` ```bash copy pnpm add @copilotkit/react-core @copilotkit/react-ui ``` Next, add CopilotKit's React components to your frontend. ```jsx copy import { CopilotChat } from "@copilotkit/react-ui"; import { CopilotKit } from "@copilotkit/react-core"; import "@copilotkit/react-ui/styles.css"; export function CopilotKitComponent() { return ( ); } ``` Render the component and start building the future!
CopilotKit output ## Using with other frameworks (NextJS) You can still leverage AGUI without going through Mastra Server. ```typescript copy // import your mastra instance from dir import { mastra } from "../path/to/mastra"; import { CopilotRuntime, ExperimentalEmptyAdapter, copilotRuntimeNextJSAppRouterEndpoint, } from "@copilotkit/runtime"; import { NextRequest } from "next/server"; export const POST = async (req: NextRequest) => { // Clone the request before reading the body const clonedReq = req.clone(); const body = await clonedReq.json(); const resourceId = body.resourceId || "TEST"; const mastraAgents = getAGUI({ mastra, resourceId, }); const runtime = new CopilotRuntime({ agents: mastraAgents, }); const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({ runtime, serviceAdapter: new ExperimentalEmptyAdapter(), endpoint: "/api/copilotkit", }); // Use the original request for handleRequest return handleRequest(req); }; ``` ### Using Typed Runtime Context For better type safety, you can specify the type of your runtime context: ```typescript filename="src/mastra/index.ts" showLineNumbers copy import { Mastra } from "@mastra/core/mastra"; import { PinoLogger } from "@mastra/loggers"; import { LibSQLStore } from "@mastra/libsql"; import { registerCopilotKit } from "@mastra/agui"; import { weatherAgent } from "./agents"; // Define your runtime context type type WeatherRuntimeContext = { "user-id": string; "temperature-scale": "celsius" | "fahrenheit"; "api-key": string; }; export const mastra = new Mastra({ agents: { weatherAgent }, storage: new LibSQLStore({ url: ":memory:", }), logger: new PinoLogger({ name: "Mastra", level: "info", }), server: { cors: { origin: "*", allowMethods: ["*"], allowHeaders: ["*"], }, apiRoutes: [ registerCopilotKit({ path: "/copilotkit", resourceId: "weatherAgent", setContext: (c, runtimeContext) => { // TypeScript will enforce the correct types here runtimeContext.set("user-id", c.req.header("X-User-ID") || "anonymous"); runtimeContext.set("temperature-scale", "celsius"); // Only "celsius" | "fahrenheit" allowed runtimeContext.set("api-key", process.env.WEATHER_API_KEY || ""); // This would cause a TypeScript error: // runtimeContext.set("invalid-key", "value"); // ❌ Error: invalid key // runtimeContext.set("temperature-scale", "kelvin"); // ❌ Error: invalid value } }), ], }, }); ``` ## Further Reading - [CopilotKit Documentation](https://docs.copilotkit.ai) - [React Hooks with CopilotKit](https://docs.copilotkit.ai/reference/hooks/useCoAgent) --- title: "Using with OpenRouter" description: "Learn how to integrate OpenRouter with Mastra" --- import { Steps } from 'nextra/components' # Use OpenRouter with Mastra [EN] Source: https://mastra.ai/en/docs/frameworks/agentic-uis/openrouter Integrate OpenRouter with Mastra to leverage the numerous models available on OpenRouter. ## Initialize a Mastra Project The simplest way to get started with Mastra is to use the `mastra` CLI to initialize a new project: ```bash copy npx create-mastra@latest ``` You'll be guided through prompts to set up your project. For this example, select: - Name your project: my-mastra-openrouter-app - Components: Agents (recommended) - For default provider, select OpenAI (recommended) - we'll configure OpenRouter manually later - Optionally include example code ## Configure OpenRouter After creating your project with `create-mastra`, you'll find a `.env` file in your project root. Since we selected OpenAI during setup, we'll configure OpenRouter manually: ```bash filename=".env" copy OPENROUTER_API_KEY= ``` We remove the `@ai-sdk/openai` package from the project: ```bash copy npm uninstall @ai-sdk/openai ``` Then, we install the `@openrouter/ai-sdk-provider` package: ```bash copy npm install @openrouter/ai-sdk-provider ``` ## Configure your Agent to use OpenRouter We will now configure our agent to use OpenRouter. ```typescript filename="src/mastra/agents/assistant.ts" copy showLineNumbers {4-6,11} import { Agent } from "@mastra/core/agent"; import { createOpenRouter } from "@openrouter/ai-sdk-provider"; const openrouter = createOpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, }) export const assistant = new Agent({ name: "assistant", instructions: "You are a helpful assistant.", model: openrouter("anthropic/claude-sonnet-4"), }) ``` Make sure to register your agent to the Mastra instance: ```typescript filename="src/mastra/index.ts" copy showLineNumbers {4} import { assistant } from "./agents/assistant"; export const mastra = new Mastra({ agents: { assistant } }) ``` ## Run and Test your Agent ```bash copy npm run dev ``` This will start the Mastra development server. You can now test your agent by visiting [http://localhost:4111](http://localhost:4111) for the playground or via the Mastra API at [http://localhost:4111/api/agents/assistant/stream](http://localhost:4111/api/agents/assistant/stream). ## Advanced Configuration For more control over your OpenRouter requests, you can pass additional configuration options. ### Provider-wide options: You can pass provider-wide options to the OpenRouter provider: ```typescript filename="src/mastra/agents/assistant.ts" {6-10} copy showLineNumbers import { Agent } from "@mastra/core/agent"; import { createOpenRouter } from "@openrouter/ai-sdk-provider"; const openrouter = createOpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, extraBody: { reasoning: { max_tokens: 10, } } }) export const assistant = new Agent({ name: "assistant", instructions: "You are a helpful assistant.", model: openrouter("anthropic/claude-sonnet-4"), }) ``` ### Model-specific options: You can pass model-specific options to the OpenRouter provider: ```typescript filename="src/mastra/agents/assistant.ts" {11-17} copy showLineNumbers import { Agent } from "@mastra/core/agent"; import { createOpenRouter } from "@openrouter/ai-sdk-provider"; const openrouter = createOpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, }) export const assistant = new Agent({ name: "assistant", instructions: "You are a helpful assistant.", model: openrouter("anthropic/claude-sonnet-4", { extraBody: { reasoning: { max_tokens: 10, } } }), }) ``` ### Provider-specific options: You can pass provider-specific options to the OpenRouter provider: ```typescript copy showLineNumbers {7-12} // Get a response with provider-specific options const response = await assistant.generate([ { role: 'system', content: 'You are Chef Michel, a culinary expert specializing in ketogenic (keto) diet...', providerOptions: { // Provider-specific options - key can be 'anthropic' or 'openrouter' anthropic: { cacheControl: { type: 'ephemeral' }, }, }, }, { role: 'user', content: 'Can you suggest a keto breakfast?', }, ]); ``` --- title: "Getting started with Mastra and Express | Mastra Guides" description: A step-by-step guide to integrating Mastra with an Express backend. --- import { Callout, Steps, Tabs, FileTree } from "nextra/components"; # Integrate Mastra in your Express project [EN] Source: https://mastra.ai/en/docs/frameworks/servers/express Mastra integrates with Express, making it easy to: - Build flexible APIs to serve AI-powered features - Maintain full control over your server logic and routing - Scale your backend independently of your frontend Use this guide to scaffold and integrate Mastra with your Express project. This setup is compatible with the following package versions: - `express`: 4.x - `@types/express`: 4.x Type compatibility in 5.x can be inconsistent while `express` and `@types/express` evolve toward alignment. ## Install Mastra Install the required Mastra packages: ```bash copy npm install mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy yarn add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy pnpm add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy bun add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ## Integrate Mastra To integrate Mastra in your project, you have two options: ### 1. Use the One-Liner Run the following command to quickly scaffold the default Weather agent with sensible defaults: ```bash copy npx mastra@latest init --default ``` > See [mastra init](/reference/cli/init) for more information. ### 2. Use the Interactive CLI If you prefer to customize the setup, run the `init` command and choose from the options when prompted: ```bash copy npx mastra@latest init ``` Add the `dev` and `build` scripts to `package.json`: ```json filename="package.json" { "scripts": { ... "dev": "mastra dev", "build": "mastra build" } } ``` > If your project already uses `dev` and `build` scripts, we recommend using: `dev:mastra` and `build:mastra`. ## Initialize TypeScript Create a `tsconfig.json` file in your project root with the following configuration: ```json filename="tsconfig.json" copy { "compilerOptions": { "target": "ES2022", "module": "ES2022", "moduleResolution": "bundler", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true, "outDir": "dist" }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", ".mastra"] } ``` > This TypeScript configuration is optimized for Mastra projects, using modern module resolution and strict type checking. ## Set Up API Key ```bash filename=".env" copy OPENAI_API_KEY= ``` > Each llm provider uses a different env var. See [Model Capabilities](/docs/getting-started/model-capability) for more information. ## Start the Mastra Dev Server Start the Mastra dev server to expose your agents as REST endpoints: ```bash copy npm run dev ``` ```bash copy mastra dev ``` > Once running, your agents are available locally. See [Local Development Environment](/docs/local-dev/mastra-dev) for more information. ## Example Express App This example creates an `/api/weather` endpoint that expects a `city` query parameter. ```typescript filename="src/server.ts" showLineNumbers copy import "dotenv/config"; import express, { Request, Response } from "express"; import { mastra } from "./mastra"; const app = express(); const port = process.env.PORT ?? 3000; app.get("/api/weather", async (req: Request, res: Response) => { const { city } = req.query as { city?: string }; if (!city) { return res.status(400).send("Missing 'city' query parameter"); } const agent = mastra.getAgent("weatherAgent"); try { const result = await agent.generate(`What's the weather like in ${city}?`); res.send(result.text); } catch (error) { console.error("Agent error:", error); res.status(500).send("An error occurred while processing your request"); } }); app.listen(port, () => { console.log(`Server listening on port ${port}`); }); ``` With the Mastra dev server running, start your Express app separately. For example: ```bash copy npx tsx --watch src/server.ts --watch-dir src ``` You can now make a request to the endpoint using one of the following: ```bash copy http://localhost:3000/api/weather?city=London ``` ```bash copy curl "http://localhost:3000/api/weather?city=London" ``` You should see output similar to the below: ```plaintext The current weather in London is as follows: - **Temperature:** 12.9°C (Feels like 9.7°C) - **Humidity:** 63% - **Wind Speed:** 14.7 km/h - **Wind Gusts:** 32.4 km/h - **Conditions:** Overcast Let me know if you need more information! ``` ## Next Steps - [Mastra Client SDK](/docs/deployment/client) --- title: "Getting Started with Mastra and Astro | Mastra Guides" description: A step-by-step guide to integrating Mastra with Astro. --- import { Callout, Steps, Tabs } from "nextra/components"; # Integrate Mastra in your Astro project [EN] Source: https://mastra.ai/en/docs/frameworks/web-frameworks/astro Mastra integrates with Astro, making it easy to: - Build flexible APIs to serve AI-powered features - Simplify deployment with a unified codebase for frontend and backend - Take advantage of Astro's built-in [Actions](https://docs.astro.build/en/guides/actions/) or [Server Endpoints](https://docs.astro.build/en/guides/endpoints/#server-endpoints-api-routes) for efficient server-client workflows Use this guide to scaffold and integrate Mastra with your Astro project. This guide assumes you're using Astro's Actions with React and the Vercel adapter. ## Install Mastra Install the required Mastra packages: {/* LLM CONTEXT: This Tabs component shows commands for integrating a new Mastra backend project using different package managers. Each tab displays the command for that specific package manager to create an integrated Mastra backend service. This is part of the "Integrated Backend Integration" approach for Astro projects. All commands create the same Mastra project but use different package manager syntax. */} ```bash copy npm install mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy yarn add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy pnpm add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy bun add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ## Integrate Mastra To integrate Mastra into your project, you have two options: ### 1. Use the One-Liner Run the following command to quickly scaffold the default Weather agent with sensible defaults: ```bash copy npx mastra@latest init --default ``` > See [mastra init](/reference/cli/init) for more information. ### 2. Use the Interactive CLI If you prefer to customize the setup, run the `init` command and choose from the options when prompted: ```bash copy npx mastra@latest init ``` Add the `dev` and `build` scripts to `package.json`: ```json filename="package.json" { "scripts": { ... "dev:mastra": "mastra dev", "build:mastra": "mastra build" } } ``` ## Configure TypeScript Modify the `tsconfig.json` file in your project root: ```json filename="tsconfig.json" { ... "exclude": ["dist", ".mastra"] } ``` ## Set Up API Key ```bash filename=".env" copy OPENAI_API_KEY= ``` ## Update .gitignore Add `.mastra` and `.vercel` to your `.gitignore` file: ```bash filename=".gitignore" copy .mastra .vercel ``` ## Update the Mastra Agent Astro uses Vite, which accesses environment variables via `import.meta.env` rather than `process.env`. As a result, the model constructor must explicitly receive the `apiKey` from the Vite environment like this: ```diff filename="src/mastra/agents/weather-agent.ts" - import { openai } from "@ai-sdk/openai"; + import { createOpenAI } from "@ai-sdk/openai"; + const openai = createOpenAI({ + apiKey: import.meta.env?.OPENAI_API_KEY, + compatibility: "strict" + }); ``` > More configuration details are available in the AI SDK docs. See [Provider Instance](https://ai-sdk.dev/providers/ai-sdk-providers/openai#provider-instance) for more information. ## Start the Mastra Dev Server Start the Mastra Dev Server to expose your agents as REST endpoints: ```bash copy npm run dev:mastra ``` ```bash copy mastra dev:mastra ``` > Once running, your agents are available locally. See [Local Development Environment](/docs/local-dev/mastra-dev) for more information. ## Start Astro Dev Server With the Mastra Dev Server running, you can start your Astro site in the usual way. ## Create Actions Directory ```bash copy mkdir src/actions ``` ### Create Test Action Create a new Action, and add the example code: ```bash copy touch src/actions/index.ts ``` ```typescript filename="src/actions/index.ts" showLineNumbers copy import { defineAction } from "astro:actions"; import { z } from "astro:schema"; import { mastra } from "../mastra"; export const server = { getWeatherInfo: defineAction({ input: z.object({ city: z.string() }), handler: async (input) => { const city = input.city; const agent = mastra.getAgent("weatherAgent"); const result = await agent.generate(`What's the weather like in ${city}?`); return result.text; } }) }; ``` ### Create Test Form Create a new Form component, and add the example code: ```bash copy touch src/components/form.tsx ``` ```typescript filename="src/components/form.tsx" showLineNumbers copy import { actions } from "astro:actions"; import { useState } from "react"; export const Form = () => { const [result, setResult] = useState(null); async function handleSubmit(formData: FormData) { const city = formData.get("city")!.toString(); const { data } = await actions.getWeatherInfo({ city }); setResult(data || null); } return ( <>
{result &&
{result}
} ); }; ``` ### Create Test Page Create a new Page, and add the example code: ```bash copy touch src/pages/test.astro ``` ```astro filename="src/pages/test.astro" showLineNumbers copy --- import { Form } from '../components/form' ---

Test

``` > You can now navigate to `/test` in your browser to try it out. Submitting **London** as the city would return a result similar to: ```plaintext Agent response: The current weather in London is as follows: - **Temperature:** 12.9°C (Feels like 9.7°C) - **Humidity:** 63% - **Wind Speed:** 14.7 km/h - **Wind Gusts:** 32.4 km/h - **Conditions:** Overcast Let me know if you need more information! ``` This guide assumes you're using Astro's Endpoints with React and the Vercel adapter, and your output is set to server. ## Prerequisites Before proceeding, ensure your Astro project is configured as follows: - Astro React integration: [@astrojs/react](https://docs.astro.build/en/guides/integrations-guide/react/) - Vercel adapter: [@astrojs/vercel](https://docs.astro.build/en/guides/integrations-guide/vercel/) - `astro.config.mjs` is set to `output: "server"` ## Install Mastra Install the required Mastra packages: {/* LLM CONTEXT: This Tabs component shows commands for integrating a new Mastra backend project using different package managers. Each tab displays the command for that specific package manager to create an integrated Mastra backend service. This is part of the "Integrated Backend Integration" approach for Astro projects. All commands create the same Mastra project but use different package manager syntax. */} ```bash copy npm install mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy yarn add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy pnpm add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy bun add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ## Integrate Mastra To integrate Mastra into your project, you have two options: ### 1. Use the One-Liner Run the following command to quickly scaffold the default Weather agent with sensible defaults: ```bash copy npx mastra@latest init --default ``` > See [mastra init](/reference/cli/init) for more information. ### 2. Use the Interactive CLI If you prefer to customize the setup, run the `init` command and choose from the options when prompted: ```bash copy npx mastra@latest init ``` Add the `dev` and `build` scripts to `package.json`: ```json filename="package.json" { "scripts": { ... "dev:mastra": "mastra dev", "build:mastra": "mastra build" } } ``` ## Configure TypeScript Modify the `tsconfig.json` file in your project root: ```json filename="tsconfig.json" { ... "exclude": ["dist", ".mastra"] } ``` ## Set Up API Key ```bash filename=".env" copy OPENAI_API_KEY= ``` ## Update .gitignore Add `.mastra` to your `.gitignore` file: ```bash filename=".gitignore" copy .mastra .vercel ``` ## Update the Mastra Agent Astro uses Vite, which accesses environment variables via `import.meta.env` rather than `process.env`. As a result, the model constructor must explicitly receive the `apiKey` from the Vite environment like this: ```diff filename="src/mastra/agents/weather-agent.ts" - import { openai } from "@ai-sdk/openai"; + import { createOpenAI } from "@ai-sdk/openai"; + const openai = createOpenAI({ + apiKey: import.meta.env?.OPENAI_API_KEY, + compatibility: "strict" + }); ``` > More configuration details are available in the AI SDK docs. See [Provider Instance](https://ai-sdk.dev/providers/ai-sdk-providers/openai#provider-instance) for more information. ## Start the Mastra Dev Server Start the Mastra Dev Server to expose your agents as REST endpoints: ```bash copy npm run dev:mastra ``` ```bash copy mastra dev:mastra ``` > Once running, your agents are available locally. See [Local Development Environment](/docs/local-dev/mastra-dev) for more information. ## Start Astro Dev Server With the Mastra Dev Server running, you can start your Astro site in the usual way. ## Create API Directory ```bash copy mkdir src/pages/api ``` ### Create Test Endpoint Create a new Endpoint, and add the example code: ```bash copy touch src/pages/api/test.ts ``` ```typescript filename="src/pages/api/test.ts" showLineNumbers copy import type { APIRoute } from "astro"; import { mastra } from "../../mastra"; export const POST: APIRoute = async ({ request }) => { const { city } = await new Response(request.body).json(); const agent = mastra.getAgent("weatherAgent"); const result = await agent.generate(`What's the weather like in ${city}?`); return new Response(JSON.stringify(result.text)); }; ``` ### Create Test Form Create a new Form component, and add the example code: ```bash copy touch src/components/form.tsx ``` ```typescript filename="src/components/form.tsx" showLineNumbers copy import { useState } from "react"; export const Form = () => { const [result, setResult] = useState(null); async function handleSubmit(event: React.FormEvent) { event.preventDefault(); const formData = new FormData(event.currentTarget); const city = formData.get("city")?.toString(); const response = await fetch("/api/test", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ city }) }); const text = await response.json(); setResult(text); } return ( <> {result &&
{result}
} ); }; ``` ### Create Test Page Create a new Page, and add the example code: ```bash copy touch src/pages/test.astro ``` ```astro filename="src/pages/test.astro" showLineNumbers copy --- import { Form } from '../components/form' ---

Test

``` > You can now navigate to `/test` in your browser to try it out. Submitting **London** as the city would return a result similar to: ```plaintext Agent response: The current weather in London is as follows: - **Temperature:** 12.9°C (Feels like 9.7°C) - **Humidity:** 63% - **Wind Speed:** 14.7 km/h - **Wind Gusts:** 32.4 km/h - **Conditions:** Overcast Let me know if you need more information! ``` ## Next Steps - [Deployment | With Astro on Vercel](/docs/deployment/web-framework#with-astro-on-vercel) --- title: "Getting Started with Mastra and Next.js | Mastra Guides" description: A step-by-step guide to integrating Mastra with Next.js. --- import { Callout, Steps, Tabs } from "nextra/components"; # Integrate Mastra in your Next.js project [EN] Source: https://mastra.ai/en/docs/frameworks/web-frameworks/next-js Mastra integrates with Next.js, making it easy to: - Build flexible APIs to serve AI-powered features - Simplify deployment with a unified codebase for frontend and backend - Take advantage of Next.js's built-in server actions (App Router) or API Routes (Pages Router) for efficient server-client workflows Use this guide to scaffold and integrate Mastra with your Next.js project. This guide assumes you're using the Next.js App Router at the root of your project, e.g., `app` rather than `src/app`. ## Install Mastra Install the required Mastra packages: {/* LLM CONTEXT: This Tabs component shows commands for integrating a new Mastra backend project using different package managers. Each tab displays the command for that specific package manager to create an integrated Mastra backend service. This is part of the "Integrated Backend Integration" approach for Next.js projects. All commands create the same Mastra project but use different package manager syntax. */} ```bash copy npm install mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy yarn add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy pnpm add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy bun add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ## Integrate Mastra To integrate Mastra into your project, you have two options: ### 1. Use the One-Liner Run the following command to quickly scaffold the default Weather agent with sensible defaults: ```bash copy npx mastra@latest init --dir . --components agents,tools --example --llm openai ``` > See [mastra init](/reference/cli/init) for more information. ### 2. Use the Interactive CLI If you prefer to customize the setup, run the `init` command and choose from the options when prompted: ```bash copy npx mastra@latest init ``` Add the `dev` and `build` scripts to `package.json`: ```json filename="package.json" { "scripts": { ... "dev:mastra": "mastra dev --dir mastra", "build:mastra": "mastra build --dir mastra" } } ``` ## Configure TypeScript Modify the `tsconfig.json` file in your project root: ```json filename="tsconfig.json" { ... "exclude": ["dist", ".mastra"] } ``` ## Set Up API Key ```bash filename=".env" copy OPENAI_API_KEY= ``` > Each LLM provider uses a different env var. See [Model Capabilities](/docs/getting-started/model-capability) for more information. ## Configure Next.js Add to your `next.config.ts`: ```typescript filename="next.config.ts" showLineNumbers copy import type { NextConfig } from "next"; const nextConfig: NextConfig = { serverExternalPackages: ["@mastra/*"], }; export default nextConfig; ``` ## Update .gitignore Add `.mastra` to your `.gitignore` file: ```bash filename=".gitignore" copy .mastra ``` ## Start the Mastra Dev Server Start the Mastra Dev Server to expose your agents as REST endpoints: ```bash copy npm run dev:mastra ``` ```bash copy mastra dev:mastra ``` > Once running, your agents are available locally. See [Local Development Environment](/docs/local-dev/mastra-dev) for more information. ## Start Next.js Dev Server With the Mastra Dev Server running, you can start your Next.js app in the usual way. ## Create Test Directory Create a new directory that will contain a Page, Action, and Form for testing purposes. ```bash copy mkdir app/test ``` ### Create Test Action Create a new Action, and add the example code: ```bash copy touch app/test/action.ts ``` ```typescript filename="app/test/action.ts" showLineNumbers copy "use server"; import { mastra } from "../../mastra"; export async function getWeatherInfo(formData: FormData) { const city = formData.get("city")?.toString(); const agent = mastra.getAgent("weatherAgent"); const result = await agent.generate(`What's the weather like in ${city}?`); return result.text; } ``` ### Create Test Form Create a new Form component, and add the example code: ```bash copy touch app/test/form.tsx ``` ```typescript filename="app/test/form.tsx" showLineNumbers copy "use client"; import { useState } from "react"; import { getWeatherInfo } from "./action"; export function Form() { const [result, setResult] = useState(null); async function handleSubmit(formData: FormData) { const res = await getWeatherInfo(formData); setResult(res); } return ( <> {result &&
{result}
} ); } ``` ### Create Test Page Create a new Page, and add the example code: ```bash copy touch app/test/page.tsx ``` ```typescript filename="app/test/page.tsx" showLineNumbers copy import { Form } from "./form"; export default async function Page() { return ( <>

Test

); } ``` > You can now navigate to `/test` in your browser to try it out. Submitting **London** as the city would return a result similar to: ```plaintext Agent response: The current weather in London is as follows: - **Temperature:** 12.9°C (Feels like 9.7°C) - **Humidity:** 63% - **Wind Speed:** 14.7 km/h - **Wind Gusts:** 32.4 km/h - **Conditions:** Overcast Let me know if you need more information! ``` This guide assumes you're using the Next.js Pages Router at the root of your project, e.g., `pages` rather than `src/pages`. ## Install Mastra Install the required Mastra packages: {/* LLM CONTEXT: This Tabs component shows commands for integrating a new Mastra backend project using different package managers. Each tab displays the command for that specific package manager to create an integrated Mastra backend service. This is part of the "Integrated Backend Integration" approach for Next.js projects. All commands create the same Mastra project but use different package manager syntax. */} ```bash copy npm install mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy yarn add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy pnpm add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy bun add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ## Integrate Mastra To integrate Mastra into your project, you have two options: ### 1. Use the One-Liner Run the following command to quickly scaffold the default Weather agent with sensible defaults: ```bash copy npx mastra@latest init --dir . --components agents,tools --example --llm openai ``` > See [mastra init](/reference/cli/init) for more information. ### 2. Use the Interactive CLI If you prefer to customize the setup, run the `init` command and choose from the options when prompted: ```bash copy npx mastra@latest init ``` Add the `dev` and `build` scripts to `package.json`: ```json filename="package.json" { "scripts": { ... "dev:mastra": "mastra dev --dir mastra", "build:mastra": "mastra build --dir mastra" } } ``` ## Configure TypeScript Modify the `tsconfig.json` file in your project root: ```json filename="tsconfig.json" { ... "exclude": ["dist", ".mastra"] } ``` ## Set Up API Key ```bash filename=".env" copy OPENAI_API_KEY= ``` > Each LLM provider uses a different env var. See [Model Capabilities](/docs/getting-started/model-capability) for more information. ## Configure Next.js Add to your `next.config.ts`: ```typescript filename="next.config.ts" showLineNumbers copy import type { NextConfig } from "next"; const nextConfig: NextConfig = { serverExternalPackages: ["@mastra/*"], }; export default nextConfig; ``` ## Update .gitignore Add `.mastra` to your `.gitignore` file: ```bash filename=".gitignore" copy .mastra ``` ## Start the Mastra Dev Server Start the Mastra Dev Server to expose your agents as REST endpoints: ```bash copy npm run dev:mastra ``` ```bash copy mastra dev:mastra ``` > Once running, your agents are available locally. See [Local Development Environment](/docs/local-dev/mastra-dev) for more information. ## Start Next.js Dev Server With the Mastra Dev Server running, you can start your Next.js app in the usual way. ## Create Test API Route Create a new API Route, and add the example code: ```bash copy touch pages/api/test.ts ``` ```typescript filename="pages/api/test.ts" showLineNumbers copy import type { NextApiRequest, NextApiResponse } from "next"; import { mastra } from "../../mastra"; export default async function getWeatherInfo( req: NextApiRequest, res: NextApiResponse, ) { const city = req.body.city; const agent = mastra.getAgent("weatherAgent"); const result = await agent.generate(`What's the weather like in ${city}?`); return res.status(200).json(result.text); } ``` ## Create Test Page Create a new Page, and add the example code: ```bash copy touch pages/test.tsx ``` ```typescript filename="pages/test.tsx" showLineNumbers copy import { useState } from "react"; export default function Test() { const [result, setResult] = useState(null); async function handleSubmit(event: React.FormEvent) { event.preventDefault(); const formData = new FormData(event.currentTarget); const city = formData.get("city")?.toString(); const response = await fetch("/api/test", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ city }) }); const text = await response.json(); setResult(text); } return ( <>

Test

{result &&
{result}
} ); } ``` > You can now navigate to `/test` in your browser to try it out. Submitting **London** as the city would return a result similar to: ```plaintext Agent response: The current weather in London is as follows: - **Temperature:** 12.9°C (Feels like 9.7°C) - **Humidity:** 63% - **Wind Speed:** 14.7 km/h - **Wind Gusts:** 32.4 km/h - **Conditions:** Overcast Let me know if you need more information! ```
## Next Steps - [Deployment | With Next.js on Vercel](/docs/deployment/web-framework#with-nextjs-on-vercel) --- title: "Getting Started with Mastra and Vite/React | Mastra Guides" description: A step-by-step guide to integrating Mastra with Vite and React. --- import { Callout, Steps, Tabs } from "nextra/components"; # Integrate Mastra in your Vite/React project [EN] Source: https://mastra.ai/en/docs/frameworks/web-frameworks/vite-react Mastra integrates with Vite, making it easy to: - Build flexible APIs to serve AI-powered features - Simplify deployment with a unified codebase for frontend and backend - Take advantage of Mastra's Client SDK Use this guide to scaffold and integrate Mastra with your Vite/React project. This guide assumes you're using Vite/React with React Router v7 at the root of your project, e.g., `app`. ## Install Mastra Install the required Mastra packages: {/* LLM CONTEXT: This Tabs component shows commands for integrating a new Mastra backend project using different package managers. Each tab displays the command for that specific package manager to create an integrated Mastra backend service. This is part of the "Integrated Backend Integration" approach for Vite/React projects. All commands create the same Mastra project but use different package manager syntax. */} ```bash copy npm install mastra@latest @mastra/core@latest @mastra/libsql@latest @mastra/client-js@latest ``` ```bash copy yarn add mastra@latest @mastra/core@latest @mastra/libsql@latest @mastra/client-js@latest ``` ```bash copy pnpm add mastra@latest @mastra/core@latest @mastra/libsql@latest @mastra/client-js@latest ``` ```bash copy bun add mastra@latest @mastra/core@latest @mastra/libsql@latest @mastra/client-js@latest ``` ## Integrate Mastra To integrate Mastra into your project, you have two options: ### 1. Use the One-Liner Run the following command to quickly scaffold the default Weather agent with sensible defaults: ```bash copy npx mastra@latest init --dir . --components agents,tools --example --llm openai ``` > See [mastra init](/reference/cli/init) for more information. ### 2. Use the Interactive CLI If you prefer to customize the setup, run the `init` command and choose from the options when prompted: ```bash copy npx mastra@latest init ``` Add the `dev` and `build` scripts to `package.json`: ```json filename="package.json" { "scripts": { ... "dev:mastra": "mastra dev --dir mastra", "build:mastra": "mastra build --dir mastra" } } ``` ## Configure TypeScript Modify the `tsconfig.json` file in your project root: ```json filename="tsconfig.json" { ... "exclude": ["dist", ".mastra"] } ``` ## Set Up API Keys ```bash filename=".env" copy OPENAI_API_KEY= ``` > Each LLM provider uses a different env var. See [Model Capabilities](/docs/getting-started/model-capability) for more information. ## Update .gitignore Add `.mastra` to your `.gitignore` file: ```bash filename=".gitignore" copy .mastra ``` ## Start the Mastra Dev Server Start the Mastra Dev Server to expose your agents as REST endpoints: ```bash copy npm run dev:mastra ``` ```bash copy mastra dev:mastra ``` > Once running, your agents are available locally. See [Local Development Environment](/docs/local-dev/mastra-dev) for more information. ## Start Vite Dev Server With the Mastra Dev Server running, you can start your Vite app in the usual way. ## Create Mastra Client Create a new directory and file. Then add the example code: ```bash copy mkdir lib touch lib/mastra.ts ``` ```typescript filename="lib/mastra.ts" showLineNumbers copy import { MastraClient } from "@mastra/client-js"; export const mastraClient = new MastraClient({ baseUrl: import.meta.env.VITE_MASTRA_API_URL || "http://localhost:4111", }); ``` ## Create Test Route Config Add new `route` to the config: ```typescript filename="app/routes.ts" showLineNumbers copy import { type RouteConfig, index, route } from "@react-router/dev/routes"; export default [ index("routes/home.tsx"), route("test", "routes/test.tsx"), ] satisfies RouteConfig; ``` ## Create Test Route Create a new Route, and add the example code: ```bash copy touch app/routes/test.tsx ``` ```typescript filename="app/routes/test.tsx" showLineNumbers copy import { useState } from "react"; import { mastraClient } from "../../lib/mastra"; export default function Test() { const [result, setResult] = useState(null); async function handleSubmit(event: React.FormEvent) { event.preventDefault(); const formData = new FormData(event.currentTarget); const city = formData.get("city")?.toString(); const agent = mastraClient.getAgent("weatherAgent"); const response = await agent.generate({ messages: [{ role: "user", content: `What's the weather like in ${city}?` }] }); setResult(response.text); } return ( <>

Test

{result &&
{result}
} ); } ``` > You can now navigate to `/test` in your browser to try it out. Submitting **London** as the city would return a result similar to: ```plaintext The current weather in London is partly cloudy with a temperature of 19.3°C, feeling like 17.4°C. The humidity is at 53%, and there is a wind speed of 15.9 km/h, with gusts up to 38.5 km/h. ``` --- title: "Installing Mastra | Getting Started | Mastra Docs" description: Guide on installing Mastra and setting up the necessary prerequisites for running it with various LLM providers. --- import { Callout, Steps } from "nextra/components"; import { Tabs, Tab } from "@/components/tabs"; # Install Mastra [EN] Source: https://mastra.ai/en/docs/getting-started/installation To get started with Mastra, you’ll need access to a large language model (LLM). By default, Mastra is set up to work with [OpenAI](https://platform.openai.com/), so you’ll need an API key to begin. Mastra also supports other LLM providers. For a full list of supported models and setup instructions, see [Model Providers](/docs/getting-started/model-providers). ## Prerequisites - Node.js `v20.0` or higher - An API key from a supported [Model Provider](/docs/getting-started/model-providers) ## Install using the `create-mastra` CLI Our CLI is the fastest way to get started with Mastra. Run the following command to start the interactive setup: {/* LLM CONTEXT: This Tabs component shows different package manager commands for creating a new Mastra project. Each tab displays the equivalent command for that specific package manager (npx, npm, yarn, pnpm, bun). This helps users choose their preferred package manager while following the same installation process. All commands achieve the same result - creating a new Mastra project with the interactive setup. */} ```bash copy npx create-mastra@latest ``` ```bash copy npm create mastra@latest ``` ```bash copy yarn create mastra@latest ``` ```bash copy pnpm create mastra@latest ``` ```bash copy bun create mastra@latest ``` **Install using CLI flags** You can also run the Mastra CLI in non-interactive mode by passing all required flags, for example: ```bash copy npx create-mastra@latest --project-name hello-mastra --example --components tools,agents,workflows --llm openai ``` > See the [create-mastra](/reference/cli/create-mastra) documentation for a full list of available CLI options. ### Add your API key Add your API key to the `.env` file: ```bash filename=".env" copy OPENAI_API_KEY= ``` > This example uses OpenAI. Each LLM provider uses a unique name. See [Model Capabilities](/docs/getting-started/model-capability) for more information. You can now launch the [Mastra Development Server](/docs/local-dev/mastra-dev) and test your agent using the Mastra Playground. ## Install manually The following steps will walk you through installing Mastra manually. ### Create a new project Create a new project and change directory: ```bash copy mkdir hello-mastra && cd hello-mastra ``` Initialize a TypeScript project including the `@mastra/core` package: {/* LLM CONTEXT: This Tabs component shows manual installation commands for different package managers. Each tab displays the complete setup process for that package manager including project initialization, dev dependencies installation, and core Mastra packages installation. This helps users manually set up a Mastra project with their preferred package manager. */} ```bash copy npm init -y npm install typescript tsx @types/node mastra@latest --save-dev npm install @mastra/core@latest zod @ai-sdk/openai ``` ```bash copy pnpm init pnpm add typescript tsx @types/node mastra@latest --save-dev pnpm add @mastra/core@latest zod @ai-sdk/openai ``` ```bash copy yarn init -y yarn add typescript tsx @types/node mastra@latest --dev yarn add @mastra/core@latest zod @ai-sdk/openai ``` ```bash copy bun init -y bun add typescript tsx @types/node mastra@latest --dev bun add @mastra/core@latest zod @ai-sdk/openai ``` Add the `dev` and `build` scripts to `package.json`: ```json filename="package.json" copy { "scripts": { // ... "dev": "mastra dev", "build": "mastra build" } } ``` ### Initialize TypeScript Create a `tsconfig.json` file: ```bash copy touch tsconfig.json ``` Add the following configuration: ```json filename="tsconfig.json" copy { "compilerOptions": { "target": "ES2022", "module": "ES2022", "moduleResolution": "bundler", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true, "noEmit": true, "outDir": "dist" }, "include": [ "src/**/*" ] } ``` > This TypeScript configuration is optimized for Mastra projects, using modern module resolution and strict type checking. ### Set up your API key Create `.env` file: ```bash copy touch .env ``` Add your API key: ```bash filename=".env" copy OPENAI_API_KEY= ``` > This example uses OpenAI. Each LLM provider uses a unique name. See [Model Capabilities](/docs/getting-started/model-capability) for more information. ### Create a Tool Create a `weather-tool.ts` file: ```bash copy mkdir -p src/mastra/tools && touch src/mastra/tools/weather-tool.ts ``` Add the following code: ```ts filename="src/mastra/tools/weather-tool.ts" showLineNumbers copy import { createTool } from "@mastra/core/tools"; import { z } from "zod"; export const weatherTool = createTool({ id: "get-weather", description: "Get current weather for a location", inputSchema: z.object({ location: z.string().describe("City name") }), outputSchema: z.object({ output: z.string() }), execute: async () => { return { output: "The weather is sunny" }; } }); ``` > See the full weatherTool example in [Giving an Agent a Tool](/examples/agents/using-a-tool). ### Create an Agent Create a `weather-agent.ts` file: ```bash copy mkdir -p src/mastra/agents && touch src/mastra/agents/weather-agent.ts ``` Add the following code: ```ts filename="src/mastra/agents/weather-agent.ts" showLineNumbers copy import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { weatherTool } from "../tools/weather-tool"; export const weatherAgent = new Agent({ name: 'Weather Agent', instructions: ` You are a helpful weather assistant that provides accurate weather information. Your primary function is to help users get weather details for specific locations. When responding: - Always ask for a location if none is provided - If the location name isn’t in English, please translate it - If giving a location with multiple parts (e.g. "New York, NY"), use the most relevant part (e.g. "New York") - Include relevant details like humidity, wind conditions, and precipitation - Keep responses concise but informative Use the weatherTool to fetch current weather data. `, model: openai('gpt-4o-mini'), tools: { weatherTool } }); ``` ### Register the Agent Create the Mastra entry point and register agent: ```bash copy touch src/mastra/index.ts ``` Add the following code: ```ts filename="src/mastra/index.ts" showLineNumbers copy import { Mastra } from "@mastra/core/mastra"; import { weatherAgent } from "./agents/weather-agent"; export const mastra = new Mastra({ agents: { weatherAgent } }); ``` You can now launch the [Mastra Development Server](/docs/local-dev/mastra-dev) and test your agent using the Mastra Playground. ## Add to an existing project Mastra can be installed and integrated into a wide range of projects. Below are links to integration guides to help you get started: - [Next.js](/docs/frameworks/web-frameworks/next-js) - [Vite + React](/docs/frameworks/web-frameworks/vite-react) - [Astro](/docs/frameworks/web-frameworks/astro) - [Express](/docs/frameworks/servers/express) ### `mastra init` To install Mastra in an existing project, use the `mastra init` command. > See [mastra init](/reference/cli/init) for more information. ## Next steps - [Local Development](/docs/local-dev/mastra-dev) - [Deploy to Mastra Cloud](/docs/deployment/overview) --- title: "Using with Cursor/Windsurf | Getting Started | Mastra Docs" description: "Learn how to use the Mastra MCP documentation server in your IDE to turn it into an agentic Mastra expert." --- import YouTube from "@/components/youtube"; import { Tabs } from "nextra/components"; # Mastra Tools for your agentic IDE [EN] Source: https://mastra.ai/en/docs/getting-started/mcp-docs-server `@mastra/mcp-docs-server` provides direct access to Mastra's complete knowledge base in Cursor, Windsurf, Cline, or any other IDE that supports MCP. It has access to documentation, code examples, technical blog posts / feature announcements, and package changelogs which your IDE can read to help you build with Mastra. The MCP server tools have been designed to allow an agent to query the specific information it needs to complete a Mastra related task - for example: adding a Mastra feature to an agent, scaffolding a new project, or helping you understand how something works. ## How it works Once it's installed in your IDE you can write prompts and assume the agent will understand everything about Mastra. ### Add features - "Add evals to my agent and write tests" - "Write me a workflow that does the following `[task]`" - "Make a new tool that allows my agent to access `[3rd party API]`" ### Ask about integrations - "Does Mastra work with the AI SDK? How can I use it in my `[React/Svelte/etc]` project?" - "What's the latest Mastra news around MCP?" - "Does Mastra support `[provider]` speech and voice APIs? Show me an example in my code of how I can use it." ### Debug or update existing code - "I'm running into a bug with agent memory, have there been any related changes or bug fixes recently?" - "How does working memory behave in Mastra and how can I use it to do `[task]`? It doesn't seem to work the way I expect." - "I saw there are new workflow features, explain them to me and then update `[workflow]` to use them." **And more** - if you have a question, try asking your IDE and let it look it up for you. ## Automatic Installation For **new** projects, the MCP Docs Server can be added during installation either through the [interactive](/docs/getting-started/installation#interactive) setup prompts, or by specifying the `-m` flag using the [non-interactive](/docs/getting-started/installation#non-interactive) command. ## Manual Installation To add the MCP Docs Server to an existing project, install it manually. - **Cursor**: Edit `.cursor/mcp.json` in your project root, or `~/.cursor/mcp.json` for global configuration - **Windsurf**: Edit `~/.codeium/windsurf/mcp_config.json` (only supports global configuration) - **VSCode**: Edit `~/.vscode/mcp.json` in your project root Add the following configuration: ### MacOS/Linux {/* LLM CONTEXT: This Tabs component shows MCP server configuration for different IDEs on MacOS/Linux. Each tab displays the JSON configuration needed to set up the Mastra MCP docs server in that specific IDE. The tabs help users find the correct configuration format for their IDE (Cursor, Windsurf, or VSCode). Each tab shows the exact JSON structure and file paths needed for that IDE's MCP configuration. */} ```json { "mcpServers": { "mastra": { "command": "npx", "args": ["-y", "@mastra/mcp-docs-server"] } } } ``` ```json { "mcpServers": { "mastra": { "command": "npx", "args": ["-y", "@mastra/mcp-docs-server"] } } } ``` ```json { "servers": { "mastra": { "command": "npx", "args": ["-y", "@mastra/mcp-docs-server"], "type": "stdio" } } } ``` ### Windows {/* LLM CONTEXT: This Tabs component shows MCP server configuration for different IDEs on Windows. Each tab displays the Windows-specific JSON configuration needed to set up the Mastra MCP docs server. The tabs help Windows users find the correct configuration format for their IDE, using cmd instead of direct npx. Each tab shows the Windows-specific command structure needed for that IDE's MCP configuration. On latest Windsurf and Cursor the direct npx command works, while it's still unconfirmed if this has been fixed for VSCode. */} ```json { "mcpServers": { "mastra": { "command": "npx", "args": ["-y", "@mastra/mcp-docs-server"] } } } ``` ```json { "mcpServers": { "mastra": { "command": "npx", "args": ["-y", "@mastra/mcp-docs-server"] } } } ``` ```json { "servers": { "mastra": { "command": "cmd", "args": ["/c", "npx", "-y", "@mastra/mcp-docs-server"], "type": "stdio" } } } ``` ## After Configuration ### Cursor If you followed the automatic installation, you'll see a popup when you open cursor in the bottom left corner to prompt you to enable the Mastra Docs MCP Server. Diagram showing cursor prompt to enable Mastra docs MCP server Otherwise, for manual installation, do the following. 1. Open Cursor settings 2. Navigate to MCP settings 3. Click "enable" on the Mastra MCP server 4. If you have an agent chat open, you'll need to re-open it or start a new chat to use the MCP server ### Windsurf 1. Fully quit and re-open Windsurf 2. If tool calls start failing, go to Windsurfs MCP settings and re-start the MCP server. This is a common Windsurf MCP issue and isn't related to Mastra. Right now Cursor's MCP implementation is more stable than Windsurfs is. In both IDEs it may take a minute for the MCP server to start the first time as it needs to download the package from npm. ### VSCode 1. Open VSCode settings 2. Navigate to MCP settings 3. Click "enable" on the Chat > MCP option
Settings page of VSCode to enable MCP MCP only works in Agent mode in VSCode. Once you are in agent mode, open the `mcp.json` file and click the "start" button.
Settings page of VSCode to enable MCP After starting the mcp server, click the tools button in the copilot pane to see available tools.
Tools page of VSCode to see available tools ## Available Agent Tools ### Documentation Access Mastra's complete documentation: - Getting started / installation - Guides and tutorials - API references ### Examples Browse code examples: - Complete project structures - Implementation patterns - Best practices ### Blog Posts Search the blog for: - Technical posts - Changelog and feature announcements - AI news and updates ### Package Changes Track updates for Mastra and `@mastra/*` packages: - Bug fixes - New features - Breaking changes ## Common Issues 1. **Server Not Starting** - Ensure npx is installed and working - Check for conflicting MCP servers - Verify your configuration file syntax - On Windows, make sure to use the Windows-specific configuration 2. **Tool Calls Failing** - Restart the MCP server and/or your IDE - Update to the latest version of your IDE ## Model Capabilities [EN] Source: https://mastra.ai/en/docs/getting-started/model-capability import { ProviderTable } from "@/components/provider-table"; The AI providers support different language models with various capabilities. Not all models support structured output, image input, object generation, tool usage, or tool streaming. Here are the capabilities of popular models: Source: [AI SDK | Model Capabilities](https://sdk.vercel.ai/docs/foundations/providers-and-models#model-capabilities) --- title: "Model Providers | Getting Started | Mastra Docs" description: "Learn how to configure and use different model providers with Mastra." --- import { Callout, Tabs } from 'nextra/components' # Model Providers [EN] Source: https://mastra.ai/en/docs/getting-started/model-providers Model providers are used to interact with different language models. Mastra uses [Vercel's AI SDK](https://sdk.vercel.ai) as a model routing layer to provide a similar syntax for many models: ```typescript showLineNumbers copy {1,7} filename="src/mastra/agents/weather-agent.ts" import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; const agent = new Agent({ name: "WeatherAgent", instructions: "Instructions for the agent...", model: openai("gpt-4-turbo"), }); const result = await agent.generate("What is the weather like?"); ``` ## Types of AI SDK model providers Model providers from the AI SDK can be grouped into three main categories: - Official providers maintained by the AI SDK team - OpenAI-compatible providers - Community providers You can find a list of all available model providers in the [AI SDK documentation](https://ai-sdk.dev/providers/ai-sdk-providers). AI SDK model providers are packages that need to be installed in your Mastra project. The default model provider selected during the installation process is installed in the project. If you want to use a different model provider, you need to install it in your project as well. Here are some examples of how Mastra agents can be configured to use the different types of model providers: ### Official providers Official model providers are maintained by the AI SDK team. Their packages are usually prefixed with `@ai-sdk/`, e.g. `@ai-sdk/anthropic`, `@ai-sdk/openai`, etc. ```typescript showLineNumbers copy {1,7} filename="src/mastra/agents/weather-agent.ts" import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; const agent = new Agent({ name: "WeatherAgent", instructions: "Instructions for the agent...", model: openai("gpt-4-turbo"), }); ``` Additional configuration may be done by importing a helper function from the AI SDK provider. Here's an example using the OpenAI provider: ```typescript showLineNumbers copy filename="src/mastra/agents/weather-agent.ts" {1,4-8,13} import { createOpenAI } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent" const openai = createOpenAI({ baseUrl: "", apiKey: "", ...otherOptions }); const agent = new Agent({ name: "WeatherAgent", instructions: "Instructions for the agent...", model: openai(""), }); ``` Different AI providers may have different options for configuration. Please refer to the [AI SDK documentation](https://ai-sdk.dev/providers/ai-sdk-providers) for more information. ### OpenAI-compatible providers Some language model providers implement the OpenAI API. For these providers, you can use the [`@ai-sdk/openai-compatible`](https://www.npmjs.com/package/@ai-sdk/openai-compatible) provider. Here's the general setup and provider instance creation: ```typescript showLineNumbers copy filename="src/mastra/agents/weather-agent.ts" {1,4-14,19} import { createOpenAICompatible } from "@ai-sdk/openai-compatible"; import { Agent } from "@mastra/core/agent"; const openaiCompatible = createOpenAICompatible({ name: "", baseUrl: "", apiKey: "", headers: {}, queryParams: {}, fetch: async (url, options) => { // custom fetch logic return fetch(url, options); } }); const agent = new Agent({ name: "WeatherAgent", instructions: "Instructions for the agent...", model: openaiCompatible(""), }); ``` For more information on the OpenAI-compatible provider, please refer to the [AI SDK documentation](https://ai-sdk.dev/providers/openai-compatible-providers). ### Community providers The AI SDK provides a [Language Model Specification](https://github.com/vercel/ai/tree/main/packages/provider/src/language-model/v1). Following this specification, you can create your own model provider compatible with the AI SDK. Some community providers have implemented this specification and are compatible with the AI SDK. We will look at one such provider, the Ollama provider available in the [`ollama-ai-provider`](https://github.com/sgomez/ollama-ai-provider) package. Here's an example: ```typescript showLineNumbers copy filename="src/mastra/agents/weather-agent.ts" {1,7} import { ollama } from "ollama-ai-provider"; import { Agent } from "@mastra/core/agent"; const agent = new Agent({ name: "WeatherAgent", instructions: "Instructions for the agent...", model: ollama("llama3.2:latest"), }); ``` You can also configure the Ollama provider like so: ```typescript showLineNumbers copy filename="src/mastra/agents/weather-agent.ts" {1,4-7,12} import { createOllama } from "ollama-ai-provider"; import { Agent } from "@mastra/core/agent"; const ollama = createOllama({ baseUrl: "", ...otherOptions, }); const agent = new Agent({ name: "WeatherAgent", instructions: "Instructions for the agent...", model: ollama("llama3.2:latest"), }); ``` For more information on the Ollama provider and other available community providers, please refer to the [AI SDK documentation](https://ai-sdk.dev/providers/community-providers). While this example shows how to use the Ollama provider, other providers like `openrouter`, `azure`, etc. may also be used. --- title: "Local Project Structure | Getting Started | Mastra Docs" description: Guide on organizing folders and files in Mastra, including best practices and recommended structures. --- import { FileTree } from "nextra/components"; # Project Structure [EN] Source: https://mastra.ai/en/docs/getting-started/project-structure This page provides a guide for organizing folders and files in Mastra. Mastra is a modular framework, and you can use any of the modules separately or together. You could write everything in a single file, or separate each agent, tool, and workflow into their own files. We don't enforce a specific folder structure, but we do recommend some best practices, and the CLI will scaffold a project with a sensible structure. ## Example Project Structure A default project created with the CLI looks like this: {/* ``` root/ ├── src/ │ └── mastra/ │ ├── agents/ │ │ └── index.ts │ ├── tools/ │ │ └── index.ts │ ├── workflows/ │ │ └── index.ts │ ├── index.ts ├── .env ├── package.json ├── tssconfig.json ``` */} ### Top-level Folders | Folder | Description | | ---------------------- | ------------------------------------ | | `src/mastra` | Core application folder | | `src/mastra/agents` | Agent configurations and definitions | | `src/mastra/tools` | Custom tool definitions | | `src/mastra/workflows` | Workflow definitions | ### Top-level Files | File | Description | | --------------------- | --------------------------------------------------- | | `src/mastra/index.ts` | Main configuration file for Mastra | | `.env` | Environment variables | | `package.json` | Node.js project metadata, scripts, and dependencies | | `tsconfig.json` | TypeScript compiler configuration | --- title: "Introduction | Mastra Docs" description: "Mastra is a TypeScript agent framework. It helps you build AI applications and features quickly. It gives you the set of primitives you need: workflows, agents, RAG, integrations, syncs and evals." --- # About Mastra [EN] Source: https://mastra.ai/en/docs Mastra is an open-source TypeScript agent framework. It's designed to give you the primitives you need to build AI applications and features. You can use Mastra to build [AI agents](/docs/agents/overview.mdx) that have memory and can execute functions, or chain LLM calls in deterministic [workflows](/docs/workflows/overview.mdx). You can chat with your agents in Mastra's [local dev environment](/docs/local-dev/mastra-dev.mdx), feed them application-specific knowledge with [RAG](/docs/rag/overview.mdx), and score their outputs with Mastra's [evals](/docs/evals/overview.mdx). The main features include: - **[Model routing](https://sdk.vercel.ai/docs/introduction)**: Mastra uses the [Vercel AI SDK](https://sdk.vercel.ai/docs/introduction) for model routing, providing a unified interface to interact with any LLM provider including OpenAI, Anthropic, and Google Gemini. - **[Agent memory and tool calling](/docs/agents/agent-memory.mdx)**: With Mastra, you can give your agent tools (functions) that it can call. You can persist agent memory and retrieve it based on recency, semantic similarity, or conversation thread. - **[Workflow graphs](/docs/workflows/overview.mdx)**: When you want to execute LLM calls in a deterministic way, Mastra gives you a graph-based workflow engine. You can define discrete steps, log inputs and outputs at each step of each run, and pipe them into an observability tool. Mastra workflows have a simple syntax for control flow (`.then()`, `.branch()`, `.parallel()`) that allows branching and chaining. - **[Agent development environment](/docs/local-dev/mastra-dev.mdx)**: When you're developing an agent locally, you can chat with it and see its state and memory in Mastra's agent development environment. - **[Retrieval-augmented generation (RAG)](/docs/rag/overview.mdx)**: Mastra gives you APIs to process documents (text, HTML, Markdown, JSON) into chunks, create embeddings, and store them in a vector database. At query time, it retrieves relevant chunks to ground LLM responses in your data, with a unified API on top of multiple vector stores (Pinecone, pgvector, etc) and embedding providers (OpenAI, Cohere, etc). - **[Deployment](/docs/deployment/deployment.mdx)**: Mastra supports bundling your agents and workflows within an existing React, Next.js, or Node.js application, or into standalone endpoints. The Mastra deploy helper lets you easily bundle agents and workflows into a Node.js server using Hono, or deploy it onto a serverless platform like Vercel, Cloudflare Workers, or Netlify. - **[Evals](/docs/evals/overview.mdx)**: Mastra provides automated evaluation metrics that use model-graded, rule-based, and statistical methods to assess LLM outputs, with built-in metrics for toxicity, bias, relevance, and factual accuracy. You can also define your own evals. --- title: "Adding to an Existing Project | Mastra Local Development Docs" description: "Add Mastra to your existing Node.js applications" --- # Adding to an Existing Project [EN] Source: https://mastra.ai/en/docs/local-dev/add-to-existing-project You can add Mastra to an existing project using the CLI: ```bash npm2yarn copy npm install -g mastra@latest mastra init ``` Changes made to project: 1. Creates `src/mastra` directory with entry point 2. Adds required dependencies 3. Configures TypeScript compiler options ## Interactive Setup Running commands without arguments starts a CLI prompt for: 1. Component selection 2. LLM provider configuration 3. API key setup 4. Example code inclusion ## Non-Interactive Setup To initialize mastra in non-interactive mode use the following command arguments: ```bash Arguments: --components Specify components: agents, tools, workflows --llm LLM provider: openai, anthropic, groq, google or cerebras --llm-api-key Provider API key --example Include example implementation --dir Directory for Mastra files (defaults to src/) ``` For more details, refer to the [mastra init CLI documentation](../../reference/cli/init). --- title: "Creating a new Project | Mastra Local Development Docs" description: "Create new Mastra projects or add Mastra to existing Node.js applications using the CLI" --- # Creating a new project [EN] Source: https://mastra.ai/en/docs/local-dev/creating-a-new-project You can create a new project using the `create-mastra` package: ```bash npm2yarn copy npm create mastra@latest ``` You can also create a new project by using the `mastra` CLI directly: ```bash npm2yarn copy npm install -g mastra@latest mastra create ``` ## Interactive Setup Running commands without arguments starts a CLI prompt for: 1. Project name 1. Component selection 1. LLM provider configuration 1. API key setup 1. Example code inclusion ## Non-Interactive Setup To initialize mastra in non-interactive mode use the following command arguments: ```bash Arguments: --components Specify components: agents, tools, workflows --llm-provider LLM provider: openai, anthropic, groq, google, or cerebras --add-example Include example implementation --llm-api-key Provider API key --project-name Project name that will be used in package.json and as the project directory name ``` Generated project structure: ``` my-project/ ├── src/ │ └── mastra/ │ └── index.ts # Mastra entry point ├── package.json └── tsconfig.json ``` --- title: "Inspecting Agents with `mastra dev` | Mastra Local Dev Docs" description: Documentation for the Mastra local development environment for Mastra applications. --- import YouTube from "@/components/youtube"; # Local Development Environment [EN] Source: https://mastra.ai/en/docs/local-dev/mastra-dev Mastra provides a local development environment where you can test your agents, workflows, and tools while developing locally. ## Launch Development Server You can launch the Mastra development environment using the Mastra CLI by running: ```bash mastra dev ``` By default, the server runs on localhost at http://localhost:4111. Custom port and host can be configured via the mastra server config. ```typescript import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ server: { port: "4111", host: "0.0.0.0", }, }); ``` ## Dev Playground `mastra dev` serves a playground UI for interacting with your agents, workflows, and tools. The playground provides dedicated interfaces for testing each component of your Mastra application during development. ### Agent Playground The Agent playground provides an interactive chat interface where you can test and debug your agents during development. Key features include: - **Chat Interface**: Directly interact with your agents to test their responses and behavior. - **Prompt CMS**: Experiment with different system instructions for your agent: - A/B test different prompt versions. - Track performance metrics for each variant. - Select and deploy the most effective prompt version. - **Agent Traces**: View detailed execution traces to understand how your agent processes requests, including: - Prompt construction. - Tool usage. - Decision-making steps. - Response generation. - **Agent Evals**: When you've set up [Agent evaluation metrics](/docs/evals/overview), you can: - Run evaluations directly from the playground. - View evaluation results and metrics. - Compare agent performance across different test cases. ### Workflow Playground The Workflow playground helps you visualize and test your workflow implementations: - **Workflow Visualization**: Workflow graph visualization. - **Run Workflows**: - Trigger test workflow runs with custom input data. - Debug workflow logic and conditions. - Simulate different execution paths. - View detailed execution logs for each step. - **Workflow Traces**: Examine detailed execution traces that show: - Step-by-step workflow progression. - State transitions and data flow. - Tool invocations and their results. - Decision points and branching logic. - Error handling and recovery paths. ### Tools Playground The Tools playground allows you to test your custom tools in isolation: - Test individual tools without running a full agent or workflow. - Input test data and view tool responses. - Debug tool implementation and error handling. - Verify tool input/output schemas. - Monitor tool performance and execution time. ## REST API Endpoints `mastra dev` also spins up REST API routes for your agents and workflows via the local [Mastra Server](/docs/deployment/server). This allows you to test your API endpoints before deployment. See [Mastra Dev reference](/reference/cli/dev#routes) for more details about all endpoints. You can then leverage the [Mastra Client](/docs/deployment/client) SDK to interact with your served REST API routes seamlessly. ## OpenAPI Specification `mastra dev` provides an OpenAPI spec at http://localhost:4111/openapi.json To enable OpenAPI documentation in your Mastra instance, add the following configuration: ```typescript import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ server: { build: { openAPIDocs: true, // Enable OpenAPI documentation // ... other build config options }, }, }); ``` ## Swagger UI Swagger UI provides an interactive interface for testing your API endpoints at `mastra dev` provides an OpenAPI spec at http://localhost:4111/swagger-ui. To enable Swagger UI in your Mastra instance, add the following configuration: ```typescript import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ server: { build: { openAPIDocs: true, // Enable OpenAPI documentation swaggerUI: true, // Enable Swagger UI // ... other build config options }, }, }); ``` ## Local Dev Architecture The local development server is designed to run without any external dependencies or containerization. This is achieved through: - **Dev Server**: Uses [Hono](https://hono.dev) as the underlying framework to power the [Mastra Server](/docs/deployment/server). - **In-Memory Storage**: Uses [LibSQL](https://libsql.org/) memory adapters for: - Agent memory management. - Trace storage. - Evals storage. - Workflow snapshots. - **Vector Storage**: Uses [FastEmbed](https://github.com/qdrant/fastembed) for: - Default embedding generation. - Vector storage and retrieval. - Semantic search capabilities. This architecture allows you to start developing immediately without setting up databases or vector stores, while still maintaining production-like behavior in your local environment. ### Model settings The local development server also lets you configure the model settings in Overview > Model Settings. You can configure the following settings: - **Temperature**: Controls randomness in model outputs. Higher values (0-2) produce more creative responses while lower values make outputs more focused and deterministic. - **Top P**: Sets cumulative probability threshold for token sampling. Lower values (0-1) make outputs more focused by considering only the most likely tokens. - **Top K**: Limits the number of tokens considered for each generation step. Lower values produce more focused outputs by sampling from fewer options. - **Frequency Penalty**: Reduces repetition by penalizing tokens based on their frequency in previous text. Higher values (0-2) discourage reuse of common tokens. - **Presence Penalty**: Reduces repetition by penalizing tokens that appear in previous text. Higher values (0-2) encourage the model to discuss new topics. - **Max Tokens**: Maximum number of tokens allowed in the model's response. Higher values allow for longer outputs but may increase latency. - **Max Steps**: Maximum number of steps a workflow or agent can execute before stopping. Prevents infinite loops and runaway processes. - **Max Retries**: Number of times to retry failed API calls or model requests before giving up. Helps handle temporary failures gracefully. ## Summary `mastra dev` makes it easy to develop, debug, and iterate on your AI logic in a self-contained environment before deploying to production. - [Mastra Dev reference](../../reference/cli/dev.mdx) --- title: Deploying to Mastra Cloud description: GitHub-based deployment process for Mastra applications --- # Deploying to Mastra Cloud [EN] Source: https://mastra.ai/en/docs/mastra-cloud/deploying > **Beta Notice** > Mastra Cloud is currently in **public beta**. This page describes the deployment process for Mastra applications to Mastra Cloud using GitHub integration. ## Prerequisites - A GitHub account - A GitHub repository containing a Mastra application - Access to Mastra Cloud ## Deployment Process Mastra Cloud uses a Git-based deployment workflow similar to platforms like Vercel and Netlify: 1. **Import GitHub Repository** - From the Projects dashboard, click "Add new" - Select the repository containing your Mastra application - Click "Import" next to the desired repository 2. **Configure Deployment Settings** - Set the project name (defaults to repository name) - Select branch to deploy (typically `main`) - Configure the Mastra directory path (defaults to `src/mastra`) - Add necessary environment variables (like API keys) 3. **Deploy from Git** - After initial configuration, deployments are triggered by pushes to the selected branch - Mastra Cloud automatically builds and deploys your application - Each deployment creates an atomic snapshot of your agents and workflows ## Automatic Deployments Mastra Cloud follows a Git-driven workflow: 1. Make changes to your Mastra application locally 2. Commit changes to the `main` branch 3. Push to GitHub 4. Mastra Cloud automatically detects the push and creates a new deployment 5. Once the build completes, your application is live ## Deployment Domains Each project receives two URLs: 1. **Project-specific domain**: `https://[project-name].mastra.cloud` - Example: `https://gray-acoustic-helicopter.mastra.cloud` 2. **Deployment-specific domain**: `https://[deployment-id].mastra.cloud` - Example: `https://young-loud-caravan-6156280f-ad56-4ec8-9701-6bb5271fd73d.mastra.cloud` These URLs provide direct access to your deployed agents and workflows. ## Viewing Deployments ![Deployments List](../../../../../public/image/cloud-agents.png) The deployments section in the dashboard shows: - **Title**: Deployment identifier (based on commit hash) - **Status**: Current state (success or archived) - **Branch**: The branch used (typically `main`) - **Commit**: The Git commit hash - **Updated At**: Timestamp of the deployment Each deployment represents an atomic snapshot of your Mastra application at a specific point in time. ## Interacting with Agents ![Agent Interface](../../../../../public/image/cloud-agent.png) After deployment, interact with your agents: 1. Navigate to your project in the dashboard 2. Go to the Agents section 3. Select an agent to view its details and interface 4. Use the Chat tab to communicate with your agent 5. View the agent's configuration in the right panel: - Model information (e.g., OpenAI) - Available tools (e.g., getWeather) - Complete system prompt 6. Use suggested prompts (like "What capabilities do you have?") or enter custom messages The interface shows the agent's branch (typically "main") and indicates whether conversation memory is enabled. ## Monitoring Logs The Logs section provides detailed information about your application: - **Time**: When the log entry was created - **Level**: Log level (info, debug) - **Hostname**: Server identification - **Message**: Detailed log information, including: - API initialization - Storage connections - Agent and workflow activity These logs help debug and monitor your application's behavior in the production environment. ## Workflows ![Workflows Interface](../../../../../public/image/cloud-workflows.png) The Workflows section allows you to view and interact with your deployed workflows: 1. View all workflows in your project 2. Examine workflow structure and steps 3. Access execution history and performance data ## Database Usage Mastra Cloud tracks database utilization metrics: - Number of reads - Number of writes - Storage used (MB) These metrics appear in the project overview, helping you monitor resource consumption. ## Deployment Configuration Configure your deployment through the dashboard: 1. Navigate to your project settings 2. Set environment variables (like `OPENAI_API_KEY`) 3. Configure project-specific settings Changes to configuration require a new deployment to take effect. ## Next Steps After deployment, [trace and monitor execution](./observability.mdx) using the observability tools. --- title: Observability in Mastra Cloud description: Monitoring and debugging tools for Mastra Cloud deployments --- # Observability in Mastra Cloud [EN] Source: https://mastra.ai/en/docs/mastra-cloud/observability > **Beta Notice** > Mastra Cloud is currently in **beta**. Mastra Cloud records execution data for monitoring and debugging. It captures traces, logs, and runtime information from agents and workflows. ## Agent Interface The agent interface offers three main views, accessible via tabs: 1. **Chat**: Interactive messaging interface to test your agent 2. **Traces**: Detailed execution records 3. **Evaluation**: Agent performance assessment ![Agent Interface with Chat Tab](../../../../../public/image/cloud-agent.png) ### Chat Interface The Chat tab provides: - Interactive messaging with deployed agents - System response to user queries - Suggested prompt buttons (e.g., "What capabilities do you have?") - Message input area - Branch indicator (e.g., "main") - Note about agent memory limitations ### Agent Configuration Panel The right sidebar displays agent details: - Agent name and deployment identifier - Model information (e.g., "OpenAI") - Tools available to the agent (e.g., "getWeather") - Complete system prompt text This panel provides visibility into how the agent is configured without needing to check the source code. ## Trace System Mastra Cloud records traces for agent and workflow interactions. ### Trace Explorer Interface ![Agent Traces View](/image/cloud-agent-traces.png) The Trace Explorer interface shows: - All agent and workflow interactions - Specific trace details - Input and output data - Tool calls with parameters and results - Workflow execution paths - Filtering options by type, status, timestamp, and agent/workflow ### Trace Data Structure Each trace contains: 1. **Request Data**: The request that initiated the agent or workflow 2. **Tool Call Records**: Tool calls during execution with parameters 3. **Tool Response Data**: The responses from tool calls 4. **Agent Response Data**: The generated agent response 5. **Execution Timestamps**: Timing information for each execution step 6. **Model Metadata**: Information about model usage and tokens The trace view displays all API calls and results throughout execution. This data helps debug tool usage and agent logic flows. ### Agent Interaction Data Agent interaction traces include: - User input text - Agent processing steps - Tool calls (e.g., weather API calls) - Parameters and results for each tool call - Final agent response text ## Dashboard Structure The Mastra Cloud dashboard contains: - Project deployment history - Environment variable configuration - Agent configuration details (model, system prompt, tools) - Workflow step visualization - Deployment URLs - Recent activity log ## Agent Testing Test your agents using the Chat interface: 1. Navigate to the Agents section 2. Select the agent you want to test 3. Use the Chat tab to interact with your agent 4. Send messages and view responses 5. Use suggested prompts for common queries 6. Switch to the Traces tab to view execution details Note that by default, agents do not remember conversation history across sessions. The interface indicates this with the message: "Agent will not remember previous messages. To enable memory for agent see image." ## Workflow Monitoring ![Workflow Interface](/image/cloud-workflow.png) Workflow monitoring shows: - Diagram of workflow steps and connections - Status for each workflow step - Execution details for each step - Execution trace records - Multi-step process execution (e.g., weather lookup followed by activity planning) ### Workflow Execution ![Workflow Run Details](/image/cloud-workflow-run.png) When examining a specific workflow execution, you can see the detailed steps and their outputs. ## Logs ![Logs Interface](/image/cloud-logs.png) The Logs section provides detailed information about your application: - **Time**: When the log entry was created - **Level**: Log level (info, debug) - **Hostname**: Server identification - **Message**: Detailed log information, including: - API initialization - Storage connections - Agent and workflow activity ## Technical Features The observability system includes: - **API Endpoints**: For programmatic access to trace data - **Structured Trace Format**: JSON format for filtering and query operations - **Historical Data Storage**: Retention of past execution records - **Deployment Version Links**: Correlation between traces and deployment versions ## Debugging Patterns - Compare trace data when testing agent behavior changes - Use the chat interface to test edge case inputs - View system prompts to understand agent behavior - Examine tool call parameters and results - Verify workflow execution step sequencing - Identify execution bottlenecks in trace timing data - Compare trace differences between agent versions ## Support Resources For technical assistance with observability: - Review the [Troubleshooting Documentation]() - Contact technical support through the dashboard - Join the [Discord developer channel](https://discord.gg/mastra) --- title: Mastra Cloud description: Deployment and monitoring service for Mastra applications --- # Mastra Cloud [EN] Source: https://mastra.ai/en/docs/mastra-cloud/overview Mastra Cloud is a deployment service built by the Mastra team that runs, manages, and monitors Mastra applications. It works with standard Mastra projects and handles deployment, scaling, and operational tasks. > **Beta Notice** > Mastra Cloud is currently in **public beta**. Features, APIs, and UIs may > change as development continues. ## Core Functionality - **Atomic Deployments** - Agents and workflows deploy as a single unit - **Project Organization** - Group agents and workflows into projects with assigned URLs - **Environment Variables** - Store configuration securely by environment - **Testing Console** - Send messages to agents through a web interface - **Execution Tracing** - Record agent interactions and tool calls - **Workflow Visualization** - Display workflow steps and execution paths - **Logs** - Standard logging output for debugging - **Platform Compatibility** - Uses the same infrastructure as Cloudflare, Vercel, and Netlify deployers ## Dashboard Components The Mastra Cloud dashboard contains: - **Projects List** - All projects in the account - **Project Details** - Deployments, environment variables, and access URLs - **Deployment History** - Record of deployments with timestamps and status - **Agent Inspector** - Agent configuration view showing models, tools, and system prompts - **Testing Console** - Interface for sending messages to agents - **Trace Explorer** - Records of tool calls, parameters, and responses - **Workflow Viewer** - Diagram of workflow steps and connections ## Technical Implementation Mastra Cloud runs on the same core code as the platform-specific deployers with these modifications: - **Edge Network Distribution** - Geographically distributed execution - **Dynamic Resource Allocation** - Adjusts compute resources based on traffic - **Mastra-specific Runtime** - Runtime optimized for agent execution - **Standard Deployment API** - Consistent deployment interface across environments - **Tracing Infrastructure** - Records all agent and workflow execution steps ## Use Cases Common usage patterns: - Deploying applications without managing infrastructure - Maintaining staging and production environments - Monitoring agent behavior across many requests - Testing agent responses through a web interface - Deploying to multiple regions ## Setup Process 1. [Configure a Mastra Cloud project](/docs/mastra-cloud/setting-up) 2. [Deploy code](/docs/mastra-cloud/deploying) 3. [View execution traces](/docs/mastra-cloud/observability) --- title: Setting Up a Project description: Configuration steps for Mastra Cloud projects --- # Setting Up a Mastra Cloud Project [EN] Source: https://mastra.ai/en/docs/mastra-cloud/setting-up > **Beta Notice** > Mastra Cloud is currently in **beta**. This page describes the steps to set up a project on Mastra Cloud using GitHub integration. ## Prerequisites - A Mastra Cloud account - A GitHub account - A GitHub repository containing a Mastra application ## Project Creation Process 1. **Sign in to Mastra Cloud** - Navigate to the Mastra Cloud dashboard at https://cloud.mastra.ai - Sign in with your account credentials 2. **Add a New Project** - From the "All Projects" view, click the "Add new" button in the top right - This opens the GitHub repository import dialog ![Mastra Cloud Projects Dashboard](/image/cloud-agents.png) 3. **Import Git Repository** - Search for repositories or select from the list of available GitHub repositories - Click the "Import" button next to the repository you want to deploy 4. **Configure Deployment Details** The deployment configuration page includes: - **Repo Name**: The GitHub repository name (read-only) - **Project Name**: Customize the project name (defaults to repo name) - **Branch**: Select the branch to deploy (dropdown, defaults to `main`) - **Project root**: Set the root directory of your project (defaults to `/`) - **Mastra Directory**: Specify where Mastra files are located (defaults to `src/mastra`) - **Build Command**: Optional command to run during build process - **Store Settings**: Configure data storage options - **Environment Variables**: Add key-value pairs for configuration (e.g., API keys) ## Project Structure Requirements Mastra Cloud scans the GitHub repository for: - **Agents**: Agent definitions (e.g., Weather Agent) with models and tools - **Workflows**: Workflow step definitions (e.g., weather-workflow) - **Environment Variables**: Required API keys and configuration variables The repository should contain a standard Mastra project structure for proper detection and deployment. ## Understanding the Dashboard After creating a project, the dashboard shows: ### Project Overview - **Created Date**: When the project was created - **Domains**: URLs for accessing your deployed application - Format: `https://[project-name].mastra.cloud` - Format: `https://[random-id].mastra.cloud` - **Status**: Current deployment status (success or archived) - **Branch**: The branch deployed (typically `main`) - **Environment Variables**: Configured API keys and settings - **Workflows**: List of detected workflows with step counts - **Agents**: List of detected agents with models and tools - **Database Usage**: Reads, writes, and storage statistics ### Deployments Section - List of all deployments with: - Deployment ID (based on commit hash) - Status (success/archived) - Branch - Commit hash - Timestamp ### Logs Section The Logs view displays: - Timestamp for each log entry - Log level (info, debug) - Hostname - Detailed log messages, including: - API startup information - Storage initialization - Agent and workflow activity ## Navigation The sidebar provides access to: - **Overview**: Project summary and statistics - **Deployments**: Deployment history and details - **Logs**: Application logs for debugging - **Agents**: List and configuration of all agents - **Workflows**: List and structure of all workflows - **Settings**: Project configuration options ## Environment Variable Configuration Set environment variables through the dashboard: 1. Navigate to your project in the dashboard 2. Go to the "Environment Variables" section 3. Add or edit variables (such as `OPENAI_API_KEY`) 4. Save the configuration Environment variables are encrypted and made available to your application during deployment and execution. ## Testing Your Deployment After deployment, you can test your agents and workflows using: 1. The custom domain assigned to your project: `https://[project-name].mastra.cloud` 2. The dashboard interface for direct interaction with agents ## Next Steps After setting up your project, automatic deployments occur whenever you push to the `main` branch of your GitHub repository. See the [deployment documentation](./deploying.mdx) for more details. # Memory Processors [EN] Source: https://mastra.ai/en/docs/memory/memory-processors Memory Processors allow you to modify the list of messages retrieved from memory _before_ they are added to the agent's context window and sent to the LLM. This is useful for managing context size, filtering content, and optimizing performance. Processors operate on the messages retrieved based on your memory configuration (e.g., `lastMessages`, `semanticRecall`). They do **not** affect the new incoming user message. ## Built-in Processors Mastra provides built-in processors: ### `TokenLimiter` This processor is used to prevent errors caused by exceeding the LLM's context window limit. It counts the tokens in the retrieved memory messages and removes the oldest messages until the total count is below the specified `limit`. ```typescript copy showLineNumbers {9-12} import { Memory } from "@mastra/memory"; import { TokenLimiter } from "@mastra/memory/processors"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const agent = new Agent({ model: openai("gpt-4o"), memory: new Memory({ processors: [ // Ensure the total tokens from memory don't exceed ~127k new TokenLimiter(127000), ], }), }); ``` The `TokenLimiter` uses the `o200k_base` encoding by default (suitable for GPT-4o). You can specify other encodings if needed for different models: ```typescript copy showLineNumbers {6-9} // Import the encoding you need (e.g., for older OpenAI models) import cl100k_base from "js-tiktoken/ranks/cl100k_base"; const memoryForOlderModel = new Memory({ processors: [ new TokenLimiter({ limit: 16000, // Example limit for a 16k context model encoding: cl100k_base, }), ], }); ``` See the [OpenAI cookbook](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken#encodings) or [`js-tiktoken` repo](https://github.com/dqbd/tiktoken) for more on encodings. ### `ToolCallFilter` This processor removes tool calls from the memory messages sent to the LLM. It saves tokens by excluding potentially verbose tool interactions from the context, which is useful if the details aren't needed for future interactions. It's also useful if you always want your agent to call a specific tool again and not rely on previous tool results in memory. ```typescript copy showLineNumbers {5-14} import { Memory } from "@mastra/memory"; import { ToolCallFilter, TokenLimiter } from "@mastra/memory/processors"; const memoryFilteringTools = new Memory({ processors: [ // Example 1: Remove all tool calls/results new ToolCallFilter(), // Example 2: Remove only noisy image generation tool calls/results new ToolCallFilter({ exclude: ["generateImageTool"] }), // Always place TokenLimiter last new TokenLimiter(127000), ], }); ``` ## Applying Multiple Processors You can chain multiple processors. They execute in the order they appear in the `processors` array. The output of one processor becomes the input for the next. **Order matters!** It's generally best practice to place `TokenLimiter` **last** in the chain. This ensures it operates on the final set of messages after other filtering has occurred, providing the most accurate token limit enforcement. ```typescript copy showLineNumbers {7-14} import { Memory } from "@mastra/memory"; import { ToolCallFilter, TokenLimiter } from "@mastra/memory/processors"; // Assume a hypothetical 'PIIFilter' custom processor exists // import { PIIFilter } from './custom-processors'; const memoryWithMultipleProcessors = new Memory({ processors: [ // 1. Filter specific tool calls first new ToolCallFilter({ exclude: ["verboseDebugTool"] }), // 2. Apply custom filtering (e.g., remove hypothetical PII - use with caution) // new PIIFilter(), // 3. Apply token limiting as the final step new TokenLimiter(127000), ], }); ``` ## Creating Custom Processors You can create custom logic by extending the base `MemoryProcessor` class. ```typescript copy showLineNumbers {4-19,23-26} import { Memory, CoreMessage } from "@mastra/memory"; import { MemoryProcessor, MemoryProcessorOpts } from "@mastra/core/memory"; class ConversationOnlyFilter extends MemoryProcessor { constructor() { // Provide a name for easier debugging if needed super({ name: "ConversationOnlyFilter" }); } process( messages: CoreMessage[], _opts: MemoryProcessorOpts = {}, // Options passed during memory retrieval, rarely needed here ): CoreMessage[] { // Filter messages based on role return messages.filter( (msg) => msg.role === "user" || msg.role === "assistant", ); } } // Use the custom processor const memoryWithCustomFilter = new Memory({ processors: [ new ConversationOnlyFilter(), new TokenLimiter(127000), // Still apply token limiting ], }); ``` When creating custom processors avoid mutating the input `messages` array or its objects directly. # Memory overview [EN] Source: https://mastra.ai/en/docs/memory/overview Memory is how agents manage the context that's available to them, it's a condensation of all chat messages into their context window. ## The Context Window The context window is the total information visible to the language model at any given time. In Mastra, context is broken up into three parts: system instructions and information about the user ([working memory](./working-memory.mdx)), recent messages ([message history](#conversation-history)), and older messages that are relevant to the user’s query ([semantic recall](./semantic-recall.mdx)). In addition, we provide [memory processors](./memory-processors.mdx) to trim context or remove information if the context is too long. ## Quick Start The fastest way to see memory in action is using the built-in development playground. If you haven't already, create a new Mastra project following the main [Getting Started guide](/docs/getting-started/installation). **1. Install the memory package:** ```bash npm2yarn copy npm install @mastra/memory@latest ``` **2. Create an agent and attach a `Memory` instance:** ```typescript filename="src/mastra/agents/index.ts" {6-18} import { Agent } from "@mastra/core/agent"; import { Memory } from "@mastra/memory"; import { openai } from "@ai-sdk/openai"; import { LibSQLStore } from "@mastra/libsql"; // Initialize memory with LibSQLStore for persistence const memory = new Memory({ storage: new LibSQLStore({ url: "file:../mastra.db", // Or your database URL }), }); export const myMemoryAgent = new Agent({ name: "MemoryAgent", instructions: "...", model: openai("gpt-4o"), memory, }); ``` **3. Start the Development Server:** ```bash npm2yarn copy npm run dev ``` **4. Open the playground (http://localhost:4111) and select your `MemoryAgent`:** Send a few messages and notice that it remembers information across turns: ``` ➡️ You: My favorite color is blue. ⬅️ Agent: Got it! I'll remember that your favorite color is blue. ➡️ You: What is my favorite color? ⬅️ Agent: Your favorite color is blue. ``` ## Memory Threads Mastra organizes memory into threads, which are records that identify specific conversation histories, using two identifiers: 1. **`threadId`**: A specific conversation id (e.g., `support_123`). 2. **`resourceId`**: The user or entity id that owns each thread (e.g., `user_123`, `org_456`). ```typescript {2,3} const response = await myMemoryAgent.stream("Hello, my name is Alice.", { resourceId: "user_alice", threadId: "conversation_123", }); ``` **Important:** without these ID's your agent will not use memory, even if memory is properly configured. The playground handles this for you, but you need to add ID's yourself when using memory in your application. ## Conversation History By default, the `Memory` instance includes the [last 10 messages](../../reference/memory/Memory.mdx) from the current Memory thread in each new request. This provides the agent with immediate conversational context. ```ts {3} const memory = new Memory({ options: { lastMessages: 10, }, }); ``` **Important:** Only send the newest user message in each agent call. Mastra handles retrieving and injecting the necessary history. Sending the full history yourself will cause duplication. See the [AI SDK Memory Example](../../examples/memory/use-chat.mdx) for how to handle this with when using the `useChat` frontend hooks. ### Storage Configuration Conversation history relies on a [storage adapter](/reference/memory/Memory#parameters) to store messages. By default it uses the same storage provided to the [main Mastra instance](https://mastra.ai/reference/core/mastra-class#initialization) If neither the `Memory` instance nor the `Mastra` object specify a storage provider, Mastra will not persist memory data across application restarts or deployments. For any deployment beyond local testing you should provide your own storage configuration either on `Mastra` or directly within `new Memory()`. When `storage` **is** given on the `Mastra` instance it will automatically be used by every `Memory` attached to agents. In that case you do not need to pass `storage` to `new Memory()` unless you want a per-agent override. ```ts {7-9} import { Memory } from "@mastra/memory"; import { Agent } from "@mastra/core/agent"; import { LibSQLStore } from "@mastra/libsql"; const agent = new Agent({ memory: new Memory({ storage: new LibSQLStore({ url: "file:./local.db", }), }), }); ``` **Storage code Examples**: - [LibSQL](/examples/memory/memory-with-libsql) - [Postgres](/examples/memory/memory-with-pg) - [Upstash](/examples/memory/memory-with-upstash) ## Next Steps Now that you understand the core concepts, continue to [semantic recall](./semantic-recall.mdx) to learn how to add RAG memory to your Mastra agents. Alternatively you can visit the [configuration reference](../../reference/memory/Memory.mdx) for available options, or browse [usage examples](../../examples/memory/use-chat.mdx). # Semantic Recall [EN] Source: https://mastra.ai/en/docs/memory/semantic-recall If you ask your friend what they did last weekend, they will search in their memory for events associated with "last weekend" and then tell you what they did. That's sort of like how semantic recall works in Mastra. ## How Semantic Recall Works Semantic recall is RAG-based search that helps agents maintain context across longer interactions when messages are no longer within [recent conversation history](./overview.mdx#conversation-history). It uses vector embeddings of messages for similarity search, integrates with various vector stores, and has configurable context windows around retrieved messages.
Diagram showing Mastra Memory semantic recall When it's enabled, new messages are used to query a vector DB for semantically similar messages. After getting a response from the LLM, all new messages (user, assistant, and tool calls/results) are inserted into the vector DB to be recalled in later interactions. ## Quick Start Semantic recall is enabled by default, so if you give your agent memory it will be included: ```typescript {9} import { Agent } from "@mastra/core/agent"; import { Memory } from "@mastra/memory"; import { openai } from "@ai-sdk/openai"; const agent = new Agent({ name: "SupportAgent", instructions: "You are a helpful support agent.", model: openai("gpt-4o"), memory: new Memory(), }); ``` ## Recall configuration The three main parameters that control semantic recall behavior are: 1. **topK**: How many semantically similar messages to retrieve 2. **messageRange**: How much surrounding context to include with each match 3. **scope**: Whether to search within the current thread or across all threads owned by a resource. Using `scope: 'resource'` allows the agent to recall information from any of the user's past conversations. ```typescript {5-7} const agent = new Agent({ memory: new Memory({ options: { semanticRecall: { topK: 3, // Retrieve 3 most similar messages messageRange: 2, // Include 2 messages before and after each match scope: 'resource', // Search across all threads for this user }, }, }), }); ``` Note: currently, `scope: 'resource'` for semantic recall is supported by the following storage adapters: LibSQL, Postgres, and Upstash. ### Storage configuration Semantic recall relies on a [storage and vector db](/reference/memory/Memory#parameters) to store messages and their embeddings. ```ts {8-17} import { Memory } from "@mastra/memory"; import { Agent } from "@mastra/core/agent"; import { LibSQLStore, LibSQLVector } from "@mastra/libsql"; const agent = new Agent({ memory: new Memory({ // this is the default storage db if omitted storage: new LibSQLStore({ url: "file:./local.db", }), // this is the default vector db if omitted vector: new LibSQLVector({ connectionUrl: "file:./local.db", }), }), }); ``` **Storage/vector code Examples**: - [LibSQL](/examples/memory/memory-with-libsql) - [Postgres](/examples/memory/memory-with-pg) - [Upstash](/examples/memory/memory-with-upstash) ### Embedder configuration Semantic recall relies on an [embedding model](/reference/memory/Memory#embedder) to convert messages into embeddings. You can specify any [embedding model](https://sdk.vercel.ai/docs/ai-sdk-core/embeddings) compatible with the AI SDK. To use FastEmbed (a local embedding model), install `@mastra/fastembed`: ```bash npm2yarn copy npm install @mastra/fastembed ``` Then configure it in your memory: ```ts {3,8} import { Memory } from "@mastra/memory"; import { Agent } from "@mastra/core/agent"; import { fastembed } from "@mastra/fastembed"; const agent = new Agent({ memory: new Memory({ // ... other memory options embedder: fastembed, }), }); ``` Alternatively, use a different provider like OpenAI: ```ts {3,8} import { Memory } from "@mastra/memory"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const agent = new Agent({ memory: new Memory({ // ... other memory options embedder: openai.embedding("text-embedding-3-small"), }), }); ``` ### Disabling There is a performance impact to using semantic recall. New messages are converted into embeddings and used to query a vector database before new messages are sent to the LLM. Semantic recall is enabled by default but can be disabled when not needed: ```typescript {4} const agent = new Agent({ memory: new Memory({ options: { semanticRecall: false, }, }), }); ``` You might want to disable semantic recall in scenarios like: - When conversation history provide sufficient context for the current conversation. - In performance-sensitive applications, like realtime two-way audio, where the added latency of creating embeddings and running vector queries is noticeable. import YouTube from "@/components/youtube"; # Working Memory [EN] Source: https://mastra.ai/en/docs/memory/working-memory While [conversation history](/docs/memory/overview#conversation-history) and [semantic recall](./semantic-recall.mdx) help agents remember conversations, working memory allows them to maintain persistent information about users across interactions within a thread. Think of it as the agent's active thoughts or scratchpad – the key information they keep available about the user or task. It's similar to how a person would naturally remember someone's name, preferences, or important details during a conversation. This is useful for maintaining ongoing state that's always relevant and should always be available to the agent. ## Quick Start Here's a minimal example of setting up an agent with working memory: ```typescript {12-15} import { Agent } from "@mastra/core/agent"; import { Memory } from "@mastra/memory"; import { openai } from "@ai-sdk/openai"; // Create agent with working memory enabled const agent = new Agent({ name: "PersonalAssistant", instructions: "You are a helpful personal assistant.", model: openai("gpt-4o"), memory: new Memory({ options: { workingMemory: { enabled: true, }, }, }), }); ``` ## How it Works Working memory is a block of Markdown text that the agent is able to update over time to store continuously relevant information: ## Custom Templates Templates guide the agent on what information to track and update in working memory. While a default template is used if none is provided, you'll typically want to define a custom template tailored to your agent's specific use case to ensure it remembers the most relevant information. Here's an example of a custom template. In this example the agent will store the users name, location, timezone, etc as soon as the user sends a message containing any of the info: ```typescript {5-28} const memory = new Memory({ options: { workingMemory: { enabled: true, template: ` # User Profile ## Personal Info - Name: - Location: - Timezone: ## Preferences - Communication Style: [e.g., Formal, Casual] - Project Goal: - Key Deadlines: - [Deadline 1]: [Date] - [Deadline 2]: [Date] ## Session State - Last Task Discussed: - Open Questions: - [Question 1] - [Question 2] `, }, }, }); ``` ## Designing Effective Templates A well-structured template keeps the information easy for the agent to parse and update. Treat the template as a short form that you want the assistant to keep up to date. - **Short, focused labels.** Avoid paragraphs or very long headings. Keep labels brief (for example `## Personal Info` or `- Name:`) so updates are easy to read and less likely to be truncated. - **Use consistent casing.** Inconsistent capitalization (`Timezone:` vs `timezone:`) can cause messy updates. Stick to Title Case or lower case for headings and bullet labels. - **Keep placeholder text simple.** Use hints such as `[e.g., Formal]` or `[Date]` to help the LLM fill in the correct spots. - **Abbreviate very long values.** If you only need a short form, include guidance like `- Name: [First name or nickname]` or `- Address (short):` rather than the full legal text. - **Mention update rules in `instructions`.** You can instruct how and when to fill or clear parts of the template directly in the agent's `instructions` field. ### Alternative Template Styles Use a shorter single block if you only need a few items: ```typescript const basicMemory = new Memory({ options: { workingMemory: { enabled: true, template: `User Facts:\n- Name:\n- Favorite Color:\n- Current Topic:`, }, }, }); ``` You can also store the key facts in a short paragraph format if you prefer a more narrative style: ```typescript const paragraphMemory = new Memory({ options: { workingMemory: { enabled: true, template: `Important Details:\n\nKeep a short paragraph capturing the user's important facts (name, main goal, current task).`, }, }, }); ``` ## Example: Multi-step Retention Below is a simplified view of how the `User Profile` template updates across a short user conversation: ```nohighlight # User Profile ## Personal Info - Name: - Location: - Timezone: --- After user says "My name is **Sam** and I'm from **Berlin**" --- # User Profile - Name: Sam - Location: Berlin - Timezone: --- After user adds "By the way I'm normally in **CET**" --- # User Profile - Name: Sam - Location: Berlin - Timezone: CET ``` The agent can now refer to `Sam` or `Berlin` in later responses without requesting the information again because it has been stored in working memory. If your agent is not properly updating working memory when you expect it to, you can add system instructions on _how_ and _when_ to use this template in your agent's `instructions` setting. ## Examples - [Streaming working memory](/examples/memory/streaming-working-memory) - [Using a working memory template](/examples/memory/streaming-working-memory-advanced) --- title: "Logging | Mastra Observability Documentation" description: Documentation on effective logging in Mastra, crucial for understanding application behavior and improving AI accuracy. --- import Image from "next/image"; # Logging [EN] Source: https://mastra.ai/en/docs/observability/logging In Mastra, logs can detail when certain functions run, what input data they receive, and how they respond. ## Basic Setup Here's a minimal example that sets up a **console logger** at the `INFO` level. This will print out informational messages and above (i.e., `DEBUG`, `INFO`, `WARN`, `ERROR`) to the console. ```typescript filename="mastra.config.ts" showLineNumbers copy import { Mastra } from "@mastra/core"; import { PinoLogger } from "@mastra/loggers"; export const mastra = new Mastra({ // Other Mastra configuration... logger: new PinoLogger({ name: "Mastra", level: "info", }), }); ``` In this configuration: - `name: "Mastra"` specifies the name to group logs under. - `level: "info"` sets the minimum severity of logs to record. ## Configuration - For more details on the options you can pass to `PinoLogger()`, see the [PinoLogger reference documentation](/reference/observability/logger). - Once you have a `Logger` instance, you can call its methods (e.g., `.info()`, `.warn()`, `.error()`) in the [Logger instance reference documentation](/reference/observability/logger). - If you want to send your logs to an external service for centralized collection, analysis, or storage, you can configure other logger types such as Upstash Redis. Consult the [Logger reference documentation](/reference/observability/logger) for details on parameters like `url`, `token`, and `key` when using the `UPSTASH` logger type. --- title: "Next.js Tracing | Mastra Observability Documentation" description: "Set up OpenTelemetry tracing for Next.js applications" --- # Next.js Tracing [EN] Source: https://mastra.ai/en/docs/observability/nextjs-tracing Next.js requires additional configuration to enable OpenTelemetry tracing. ### Step 1: Next.js Configuration Start by enabling the instrumentation hook in your Next.js config: ```ts filename="next.config.ts" showLineNumbers copy import type { NextConfig } from "next"; const nextConfig: NextConfig = { experimental: { instrumentationHook: true, // Not required in Next.js 15+ }, }; export default nextConfig; ``` ### Step 2: Mastra Configuration Configure your Mastra instance: ```typescript filename="mastra.config.ts" copy import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "your-project-name", enabled: true, }, }); ``` ### Step 3: Configure your providers If you're using Next.js, you have two options for setting up OpenTelemetry instrumentation: #### Option 1: Using a Custom Exporter The default that will work across providers is to configure a custom exporter: 1. Install the required dependencies (example using Langfuse): ```bash copy npm install @opentelemetry/api langfuse-vercel ``` 2. Create an instrumentation file: ```ts filename="instrumentation.ts" copy import { NodeSDK, ATTR_SERVICE_NAME, Resource, } from "@mastra/core/telemetry/otel-vendor"; import { LangfuseExporter } from "langfuse-vercel"; export function register() { const exporter = new LangfuseExporter({ // ... Langfuse config }); const sdk = new NodeSDK({ resource: new Resource({ [ATTR_SERVICE_NAME]: "ai", }), traceExporter: exporter, }); sdk.start(); } ``` #### Option 2: Using Vercel's Otel Setup If you're deploying to Vercel, you can use their OpenTelemetry setup: 1. Install the required dependencies: ```bash copy npm install @opentelemetry/api @vercel/otel ``` 2. Create an instrumentation file at the root of your project (or in the src folder if using one): ```ts filename="instrumentation.ts" copy import { registerOTel } from "@vercel/otel"; export function register() { registerOTel({ serviceName: "your-project-name" }); } ``` ### Summary This setup will enable OpenTelemetry tracing for your Next.js application and Mastra operations. For more details, see the documentation for: - [Next.js Instrumentation](https://nextjs.org/docs/app/building-your-application/optimizing/instrumentation) - [Vercel OpenTelemetry](https://vercel.com/docs/observability/otel-overview/quickstart) --- title: "Tracing | Mastra Observability Documentation" description: "Set up OpenTelemetry tracing for Mastra applications" --- import Image from "next/image"; # Tracing [EN] Source: https://mastra.ai/en/docs/observability/tracing Mastra supports the OpenTelemetry Protocol (OTLP) for tracing and monitoring your application. When telemetry is enabled, Mastra automatically traces all core primitives including agent operations, LLM interactions, tool executions, integration calls, workflow runs, and database operations. Your telemetry data can then be exported to any OTEL collector. ### Basic Configuration Here's a simple example of enabling telemetry: ```ts filename="mastra.config.ts" showLineNumbers copy export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "my-app", enabled: true, sampling: { type: "always_on", }, export: { type: "otlp", endpoint: "http://localhost:4318", // SigNoz local endpoint }, }, }); ``` ### Configuration Options The telemetry config accepts these properties: ```ts type OtelConfig = { // Name to identify your service in traces (optional) serviceName?: string; // Enable/disable telemetry (defaults to true) enabled?: boolean; // Control how many traces are sampled sampling?: { type: "ratio" | "always_on" | "always_off" | "parent_based"; probability?: number; // For ratio sampling root?: { probability: number; // For parent_based sampling }; }; // Where to send telemetry data export?: { type: "otlp" | "console"; endpoint?: string; headers?: Record; }; }; ``` See the [OtelConfig reference documentation](../../reference/observability/otel-config.mdx) for more details. ### Environment Variables You can configure the OTLP endpoint and headers through environment variables: ```env filename=".env" copy OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 OTEL_EXPORTER_OTLP_HEADERS=x-api-key=your-api-key ``` Then in your config: ```ts filename="mastra.config.ts" showLineNumbers copy export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "my-app", enabled: true, export: { type: "otlp", // endpoint and headers will be picked up from env vars }, }, }); ``` ### Example: SigNoz Integration Here's what a traced agent interaction looks like in [SigNoz](https://signoz.io): Agent interaction trace showing spans, LLM calls, and tool executions ### Other Supported Providers For a complete list of supported observability providers and their configuration details, see the [Observability Providers reference](../../reference/observability/providers/). ### Next.js-specific Tracing steps If you're using Next.js, you have three additional configuration steps: 1. Enable the instrumentation hook in `next.config.ts` 2. Configure Mastra telemetry settings 3. Set up an OpenTelemetry exporter For implementation details, see the [Next.js Tracing](./nextjs-tracing) guide. --- title: Chunking and Embedding Documents | RAG | Mastra Docs description: Guide on chunking and embedding documents in Mastra for efficient processing and retrieval. --- ## Chunking and Embedding Documents [EN] Source: https://mastra.ai/en/docs/rag/chunking-and-embedding Before processing, create a MDocument instance from your content. You can initialize it from various formats: ```ts showLineNumbers copy const docFromText = MDocument.fromText("Your plain text content..."); const docFromHTML = MDocument.fromHTML("Your HTML content..."); const docFromMarkdown = MDocument.fromMarkdown("# Your Markdown content..."); const docFromJSON = MDocument.fromJSON(`{ "key": "value" }`); ``` ## Step 1: Document Processing Use `chunk` to split documents into manageable pieces. Mastra supports multiple chunking strategies optimized for different document types: - `recursive`: Smart splitting based on content structure - `character`: Simple character-based splits - `token`: Token-aware splitting - `markdown`: Markdown-aware splitting - `html`: HTML structure-aware splitting - `json`: JSON structure-aware splitting - `latex`: LaTeX structure-aware splitting Here's an example of how to use the `recursive` strategy: ```ts showLineNumbers copy const chunks = await doc.chunk({ strategy: "recursive", size: 512, overlap: 50, separator: "\n", extract: { metadata: true, // Optionally extract metadata }, }); ``` **Note:** Metadata extraction may use LLM calls, so ensure your API key is set. We go deeper into chunking strategies in our [chunk documentation](/reference/rag/chunk.mdx). ## Step 2: Embedding Generation Transform chunks into embeddings using your preferred provider. Mastra supports many embedding providers, including OpenAI and Cohere: ### Using OpenAI ```ts showLineNumbers copy import { openai } from "@ai-sdk/openai"; import { embedMany } from "ai"; const { embeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: chunks.map((chunk) => chunk.text), }); ``` ### Using Cohere ```ts showLineNumbers copy import { cohere } from "@ai-sdk/cohere"; import { embedMany } from "ai"; const { embeddings } = await embedMany({ model: cohere.embedding("embed-english-v3.0"), values: chunks.map((chunk) => chunk.text), }); ``` The embedding functions return vectors, arrays of numbers representing the semantic meaning of your text, ready for similarity searches in your vector database. ### Configuring Embedding Dimensions Embedding models typically output vectors with a fixed number of dimensions (e.g., 1536 for OpenAI's `text-embedding-3-small`). Some models support reducing this dimensionality, which can help: - Decrease storage requirements in vector databases - Reduce computational costs for similarity searches Here are some supported models: OpenAI (text-embedding-3 models): ```ts const { embeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small", { dimensions: 256, // Only supported in text-embedding-3 and later }), values: chunks.map((chunk) => chunk.text), }); ``` Google (text-embedding-004): ```ts const { embeddings } = await embedMany({ model: google.textEmbeddingModel("text-embedding-004", { outputDimensionality: 256, // Truncates excessive values from the end }), values: chunks.map((chunk) => chunk.text), }); ``` ### Vector Database Compatibility When storing embeddings, the vector database index must be configured to match the output size of your embedding model. If the dimensions do not match, you may get errors or data corruption. ## Example: Complete Pipeline Here's an example showing document processing and embedding generation with both providers: ```ts showLineNumbers copy import { embedMany } from "ai"; import { openai } from "@ai-sdk/openai"; import { cohere } from "@ai-sdk/cohere"; import { MDocument } from "@mastra/rag"; // Initialize document const doc = MDocument.fromText(` Climate change poses significant challenges to global agriculture. Rising temperatures and changing precipitation patterns affect crop yields. `); // Create chunks const chunks = await doc.chunk({ strategy: "recursive", size: 256, overlap: 50, }); // Generate embeddings with OpenAI const { embeddings: openAIEmbeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: chunks.map((chunk) => chunk.text), }); // OR // Generate embeddings with Cohere const { embeddings: cohereEmbeddings } = await embedMany({ model: cohere.embedding("embed-english-v3.0"), values: chunks.map((chunk) => chunk.text), }); // Store embeddings in your vector database await vectorStore.upsert({ indexName: "embeddings", vectors: embeddings, }); ``` ## For more examples of different chunking strategies and embedding configurations, see: - [Adjust Chunk Size](/reference/rag/chunk.mdx#adjust-chunk-size) - [Adjust Chunk Delimiters](/reference/rag/chunk.mdx#adjust-chunk-delimiters) - [Embed Text with Cohere](/reference/rag/embeddings.mdx#using-cohere) For more details on vector databases and embeddings, see: - [Vector Databases](./vector-databases.mdx) - [Embedding API Reference](/reference/rag/embeddings.mdx) --- title: RAG (Retrieval-Augmented Generation) in Mastra | Mastra Docs description: Overview of Retrieval-Augmented Generation (RAG) in Mastra, detailing its capabilities for enhancing LLM outputs with relevant context. --- # RAG (Retrieval-Augmented Generation) in Mastra [EN] Source: https://mastra.ai/en/docs/rag/overview RAG in Mastra helps you enhance LLM outputs by incorporating relevant context from your own data sources, improving accuracy and grounding responses in real information. Mastra's RAG system provides: - Standardized APIs to process and embed documents - Support for multiple vector stores - Chunking and embedding strategies for optimal retrieval - Observability for tracking embedding and retrieval performance ## Example To implement RAG, you process your documents into chunks, create embeddings, store them in a vector database, and then retrieve relevant context at query time. ```ts showLineNumbers copy import { embedMany } from "ai"; import { openai } from "@ai-sdk/openai"; import { PgVector } from "@mastra/pg"; import { MDocument } from "@mastra/rag"; import { z } from "zod"; // 1. Initialize document const doc = MDocument.fromText(`Your document text here...`); // 2. Create chunks const chunks = await doc.chunk({ strategy: "recursive", size: 512, overlap: 50, }); // 3. Generate embeddings; we need to pass the text of each chunk const { embeddings } = await embedMany({ values: chunks.map((chunk) => chunk.text), model: openai.embedding("text-embedding-3-small"), }); // 4. Store in vector database const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING, }); await pgVector.upsert({ indexName: "embeddings", vectors: embeddings, }); // using an index name of 'embeddings' // 5. Query similar chunks const results = await pgVector.query({ indexName: "embeddings", queryVector: queryVector, topK: 3, }); // queryVector is the embedding of the query console.log("Similar chunks:", results); ``` This example shows the essentials: initialize a document, create chunks, generate embeddings, store them, and query for similar content. ## Document Processing The basic building block of RAG is document processing. Documents can be chunked using various strategies (recursive, sliding window, etc.) and enriched with metadata. See the [chunking and embedding doc](./chunking-and-embedding.mdx). ## Vector Storage Mastra supports multiple vector stores for embedding persistence and similarity search, including pgvector, Pinecone, Qdrant, and MongoDB. See the [vector database doc](./vector-databases.mdx). ## Observability and Debugging Mastra's RAG system includes observability features to help you optimize your retrieval pipeline: - Track embedding generation performance and costs - Monitor chunk quality and retrieval relevance - Analyze query patterns and cache hit rates - Export metrics to your observability platform See the [OTel Configuration](../../reference/observability/otel-config.mdx) page for more details. ## More resources - [Chain of Thought RAG Example](../../examples/rag/usage/cot-rag.mdx) - [All RAG Examples](../../examples/) (including different chunking strategies, embedding models, and vector stores) --- title: "Retrieval, Semantic Search, Reranking | RAG | Mastra Docs" description: Guide on retrieval processes in Mastra's RAG systems, including semantic search, filtering, and re-ranking. --- import { Tabs } from "nextra/components"; ## Retrieval in RAG Systems [EN] Source: https://mastra.ai/en/docs/rag/retrieval After storing embeddings, you need to retrieve relevant chunks to answer user queries. Mastra provides flexible retrieval options with support for semantic search, filtering, and re-ranking. ## How Retrieval Works 1. The user's query is converted to an embedding using the same model used for document embeddings 2. This embedding is compared to stored embeddings using vector similarity 3. The most similar chunks are retrieved and can be optionally: - Filtered by metadata - Re-ranked for better relevance - Processed through a knowledge graph ## Basic Retrieval The simplest approach is direct semantic search. This method uses vector similarity to find chunks that are semantically similar to the query: ```ts showLineNumbers copy import { openai } from "@ai-sdk/openai"; import { embed } from "ai"; import { PgVector } from "@mastra/pg"; // Convert query to embedding const { embedding } = await embed({ value: "What are the main points in the article?", model: openai.embedding("text-embedding-3-small"), }); // Query vector store const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING, }); const results = await pgVector.query({ indexName: "embeddings", queryVector: embedding, topK: 10, }); // Display results console.log(results); ``` Results include both the text content and a similarity score: ```ts showLineNumbers copy [ { text: "Climate change poses significant challenges...", score: 0.89, metadata: { source: "article1.txt" }, }, { text: "Rising temperatures affect crop yields...", score: 0.82, metadata: { source: "article1.txt" }, }, // ... more results ]; ``` For an example of how to use the basic retrieval method, see the [Retrieve Results](../../examples/rag/query/retrieve-results.mdx) example. ## Advanced Retrieval options ### Metadata Filtering Filter results based on metadata fields to narrow down the search space. This is useful when you have documents from different sources, time periods, or with specific attributes. Mastra provides a unified MongoDB-style query syntax that works across all supported vector stores. For detailed information about available operators and syntax, see the [Metadata Filters Reference](/reference/rag/metadata-filters). Basic filtering examples: ```ts showLineNumbers copy // Simple equality filter const results = await pgVector.query({ indexName: "embeddings", queryVector: embedding, topK: 10, filter: { source: "article1.txt", }, }); // Numeric comparison const results = await pgVector.query({ indexName: "embeddings", queryVector: embedding, topK: 10, filter: { price: { $gt: 100 }, }, }); // Multiple conditions const results = await pgVector.query({ indexName: "embeddings", queryVector: embedding, topK: 10, filter: { category: "electronics", price: { $lt: 1000 }, inStock: true, }, }); // Array operations const results = await pgVector.query({ indexName: "embeddings", queryVector: embedding, topK: 10, filter: { tags: { $in: ["sale", "new"] }, }, }); // Logical operators const results = await pgVector.query({ indexName: "embeddings", queryVector: embedding, topK: 10, filter: { $or: [{ category: "electronics" }, { category: "accessories" }], $and: [{ price: { $gt: 50 } }, { price: { $lt: 200 } }], }, }); ``` Common use cases for metadata filtering: - Filter by document source or type - Filter by date ranges - Filter by specific categories or tags - Filter by numerical ranges (e.g., price, rating) - Combine multiple conditions for precise querying - Filter by document attributes (e.g., language, author) For an example of how to use metadata filtering, see the [Hybrid Vector Search](../../examples/rag/query/hybrid-vector-search.mdx) example. ### Vector Query Tool Sometimes you want to give your agent the ability to query a vector database directly. The Vector Query Tool allows your agent to be in charge of retrieval decisions, combining semantic search with optional filtering and reranking based on the agent's understanding of the user's needs. ```ts showLineNumbers copy const vectorQueryTool = createVectorQueryTool({ vectorStoreName: "pgVector", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), }); ``` When creating the tool, pay special attention to the tool's name and description - these help the agent understand when and how to use the retrieval capabilities. For example, you might name it "SearchKnowledgeBase" and describe it as "Search through our documentation to find relevant information about X topic." This is particularly useful when: - Your agent needs to dynamically decide what information to retrieve - The retrieval process requires complex decision-making - You want the agent to combine multiple retrieval strategies based on context #### Database-Specific Configurations The Vector Query Tool supports database-specific configurations that enable you to leverage unique features and optimizations of different vector stores: ```ts showLineNumbers copy // Pinecone with namespace const pineconeQueryTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pinecone: { namespace: "production" // Isolate data by environment } } }); // pgVector with performance tuning const pgVectorQueryTool = createVectorQueryTool({ vectorStoreName: "postgres", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pgvector: { minScore: 0.7, // Filter low-quality results ef: 200, // HNSW search parameter probes: 10 // IVFFlat probe parameter } } }); // Chroma with advanced filtering const chromaQueryTool = createVectorQueryTool({ vectorStoreName: "chroma", indexName: "documents", model: openai.embedding("text-embedding-3-small"), databaseConfig: { chroma: { where: { "category": "technical" }, whereDocument: { "$contains": "API" } } } }); // LanceDB with table specificity const lanceQueryTool = createVectorQueryTool({ vectorStoreName: "lance", indexName: "documents", model: openai.embedding("text-embedding-3-small"), databaseConfig: { lance: { tableName: "myVectors", // Specify which table to query includeAllColumns: true // Include all metadata columns in results } } }); ``` **Key Benefits:** - **Pinecone namespaces**: Organize vectors by tenant, environment, or data type - **pgVector optimization**: Control search accuracy and speed with ef/probes parameters - **Quality filtering**: Set minimum similarity thresholds to improve result relevance - **LanceDB tables**: Separate data into tables for better organization and performance - **Runtime flexibility**: Override configurations dynamically based on context **Common Use Cases:** - Multi-tenant applications using Pinecone namespaces - Performance optimization in high-load scenarios - Environment-specific configurations (dev/staging/prod) - Quality-gated search results - Embedded, file-based vector storage with LanceDB for edge deployment scenarios You can also override these configurations at runtime using the runtime context: ```ts showLineNumbers copy import { RuntimeContext } from '@mastra/core/runtime-context'; const runtimeContext = new RuntimeContext(); runtimeContext.set('databaseConfig', { pinecone: { namespace: 'runtime-namespace' } }); await pineconeQueryTool.execute({ context: { queryText: 'search query' }, mastra, runtimeContext }); ``` For detailed configuration options and advanced usage, see the [Vector Query Tool Reference](/reference/tools/vector-query-tool). ### Vector Store Prompts Vector store prompts define query patterns and filtering capabilities for each vector database implementation. When implementing filtering, these prompts are required in the agent's instructions to specify valid operators and syntax for each vector store implementation. {/* LLM CONTEXT: This Tabs component displays vector store configuration examples for different database providers. Each tab shows how to configure a RAG agent with the appropriate prompt for that specific vector store. The tabs demonstrate the consistent pattern of importing the store-specific prompt and adding it to agent instructions. This helps users understand how to properly configure their RAG agents for different vector database backends. The providers include Pg Vector, Pinecone, Qdrant, Chroma, Astra, LibSQL, Upstash, Cloudflare, MongoDB, and OpenSearch. */} ```ts showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { PGVECTOR_PROMPT } from "@mastra/pg"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` Process queries using the provided context. Structure responses to be concise and relevant. ${PGVECTOR_PROMPT} `, tools: { vectorQueryTool }, }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { PINECONE_PROMPT } from "@mastra/pinecone"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` Process queries using the provided context. Structure responses to be concise and relevant. ${PINECONE_PROMPT} `, tools: { vectorQueryTool }, }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { QDRANT_PROMPT } from "@mastra/qdrant"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` Process queries using the provided context. Structure responses to be concise and relevant. ${QDRANT_PROMPT} `, tools: { vectorQueryTool }, }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { CHROMA_PROMPT } from "@mastra/chroma"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` Process queries using the provided context. Structure responses to be concise and relevant. ${CHROMA_PROMPT} `, tools: { vectorQueryTool }, }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { ASTRA_PROMPT } from "@mastra/astra"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` Process queries using the provided context. Structure responses to be concise and relevant. ${ASTRA_PROMPT} `, tools: { vectorQueryTool }, }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { LIBSQL_PROMPT } from "@mastra/libsql"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` Process queries using the provided context. Structure responses to be concise and relevant. ${LIBSQL_PROMPT} `, tools: { vectorQueryTool }, }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { UPSTASH_PROMPT } from "@mastra/upstash"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` Process queries using the provided context. Structure responses to be concise and relevant. ${UPSTASH_PROMPT} `, tools: { vectorQueryTool }, }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { VECTORIZE_PROMPT } from "@mastra/vectorize"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` Process queries using the provided context. Structure responses to be concise and relevant. ${VECTORIZE_PROMPT} `, tools: { vectorQueryTool }, }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { MONGODB_PROMPT } from "@mastra/mongodb"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` Process queries using the provided context. Structure responses to be concise and relevant. ${MONGODB_PROMPT} `, tools: { vectorQueryTool }, }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { OPENSEARCH_PROMPT } from "@mastra/opensearch"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` Process queries using the provided context. Structure responses to be concise and relevant. ${OPENSEARCH_PROMPT} `, tools: { vectorQueryTool }, }); ``` ### Re-ranking Initial vector similarity search can sometimes miss nuanced relevance. Re-ranking is a more computationally expensive process, but more accurate algorithm that improves results by: - Considering word order and exact matches - Applying more sophisticated relevance scoring - Using a method called cross-attention between query and documents Here's how to use re-ranking: ```ts showLineNumbers copy import { openai } from "@ai-sdk/openai"; import { rerank } from "@mastra/rag"; // Get initial results from vector search const initialResults = await pgVector.query({ indexName: "embeddings", queryVector: queryEmbedding, topK: 10, }); // Re-rank the results const rerankedResults = await rerank( initialResults, query, openai("gpt-4o-mini"), ); ``` > **Note:** For semantic scoring to work properly during re-ranking, each result must include the text content in its `metadata.text` field. The re-ranked results combine vector similarity with semantic understanding to improve retrieval quality. For more details about re-ranking, see the [rerank()](/reference/rag/rerank) method. For an example of how to use the re-ranking method, see the [Re-ranking Results](../../examples/rag/rerank/rerank.mdx) example. ### Graph-based Retrieval For documents with complex relationships, graph-based retrieval can follow connections between chunks. This helps when: - Information is spread across multiple documents - Documents reference each other - You need to traverse relationships to find complete answers Example setup: ```ts showLineNumbers copy const graphQueryTool = createGraphQueryTool({ vectorStoreName: "pgVector", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), graphOptions: { threshold: 0.7, }, }); ``` For more details about graph-based retrieval, see the [GraphRAG](/reference/rag/graph-rag) class and the [createGraphQueryTool()](/reference/tools/graph-rag-tool) function. For an example of how to use the graph-based retrieval method, see the [Graph-based Retrieval](../../examples/rag/usage/graph-rag.mdx) example. --- title: "Storing Embeddings in A Vector Database | Mastra Docs" description: Guide on vector storage options in Mastra, including embedded and dedicated vector databases for similarity search. --- import { Tabs } from "nextra/components"; ## Storing Embeddings in A Vector Database [EN] Source: https://mastra.ai/en/docs/rag/vector-databases After generating embeddings, you need to store them in a database that supports vector similarity search. Mastra provides a consistent interface for storing and querying embeddings across various vector databases. ## Supported Databases {/* LLM CONTEXT: This Tabs component showcases different vector database implementations supported by Mastra. Each tab demonstrates the setup and configuration for a specific vector database provider. The tabs show consistent API patterns across different databases, helping users understand how to switch between providers. Each tab includes import statements, initialization code, and basic operations (createIndex, upsert) for that specific database. The providers include Pg Vector, Pinecone, Qdrant, Chroma, Astra, LibSQL, Upstash, Cloudflare, MongoDB, OpenSearch, and Couchbase. */} ```ts filename="vector-store.ts" showLineNumbers copy import { MongoDBVector } from '@mastra/mongodb' const store = new MongoDBVector({ uri: process.env.MONGODB_URI, dbName: process.env.MONGODB_DATABASE }) await store.createIndex({ indexName: "myCollection", dimension: 1536, }); await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ### Using MongoDB Atlas Vector search For detailed setup instructions and best practices, see the [official MongoDB Atlas Vector Search documentation](https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-overview/?utm_campaign=devrel&utm_source=third-party-content&utm_medium=cta&utm_content=mastra-docs). ```ts filename="vector-store.ts" showLineNumbers copy import { PgVector } from '@mastra/pg'; const store = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING }) await store.createIndex({ indexName: "myCollection", dimension: 1536, }); await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ### Using PostgreSQL with pgvector PostgreSQL with the pgvector extension is a good solution for teams already using PostgreSQL who want to minimize infrastructure complexity. For detailed setup instructions and best practices, see the [official pgvector repository](https://github.com/pgvector/pgvector). ```ts filename="vector-store.ts" showLineNumbers copy import { PineconeVector } from '@mastra/pinecone' const store = new PineconeVector({ apiKey: process.env.PINECONE_API_KEY, }) await store.createIndex({ indexName: "myCollection", dimension: 1536, }); await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { QdrantVector } from '@mastra/qdrant' const store = new QdrantVector({ url: process.env.QDRANT_URL, apiKey: process.env.QDRANT_API_KEY }) await store.createIndex({ indexName: "myCollection", dimension: 1536, }); await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { ChromaVector } from '@mastra/chroma' const store = new ChromaVector() await store.createIndex({ indexName: "myCollection", dimension: 1536, }); await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { AstraVector } from '@mastra/astra' const store = new AstraVector({ token: process.env.ASTRA_DB_TOKEN, endpoint: process.env.ASTRA_DB_ENDPOINT, keyspace: process.env.ASTRA_DB_KEYSPACE }) await store.createIndex({ indexName: "myCollection", dimension: 1536, }); await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { LibSQLVector } from "@mastra/core/vector/libsql"; const store = new LibSQLVector({ connectionUrl: process.env.DATABASE_URL, authToken: process.env.DATABASE_AUTH_TOKEN // Optional: for Turso cloud databases }) await store.createIndex({ indexName: "myCollection", dimension: 1536, }); await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { UpstashVector } from '@mastra/upstash' // In upstash they refer to the store as an index const store = new UpstashVector({ url: process.env.UPSTASH_URL, token: process.env.UPSTASH_TOKEN }) // There is no store.createIndex call here, Upstash creates indexes (known as namespaces in Upstash) automatically // when you upsert if that namespace does not exist yet. await store.upsert({ indexName: "myCollection", // the namespace name in Upstash vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { CloudflareVector } from '@mastra/vectorize' const store = new CloudflareVector({ accountId: process.env.CF_ACCOUNT_ID, apiToken: process.env.CF_API_TOKEN }) await store.createIndex({ indexName: "myCollection", dimension: 1536, }); await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { OpenSearchVector } from '@mastra/opensearch' const store = new OpenSearchVector({ url: process.env.OPENSEARCH_URL }) await store.createIndex({ indexName: "my-collection", dimension: 1536, }); await store.upsert({ indexName: "my-collection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { CouchbaseVector } from '@mastra/couchbase' const store = new CouchbaseVector({ connectionString: process.env.COUCHBASE_CONNECTION_STRING, username: process.env.COUCHBASE_USERNAME, password: process.env.COUCHBASE_PASSWORD, bucketName: process.env.COUCHBASE_BUCKET, scopeName: process.env.COUCHBASE_SCOPE, collectionName: process.env.COUCHBASE_COLLECTION, }) await store.createIndex({ indexName: "myCollection", dimension: 1536, }); await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { LanceVectorStore } from '@mastra/lance' const store = await LanceVectorStore.create('/path/to/db') await store.createIndex({ tableName: "myVectors", indexName: "myCollection", dimension: 1536, }); await store.upsert({ tableName: "myVectors", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ### Using LanceDB LanceDB is an embedded vector database built on the Lance columnar format, suitable for local development or cloud deployment. For detailed setup instructions and best practices, see the [official LanceDB documentation](https://lancedb.github.io/lancedb/). ## Using Vector Storage Once initialized, all vector stores share the same interface for creating indexes, upserting embeddings, and querying. ### Creating Indexes Before storing embeddings, you need to create an index with the appropriate dimension size for your embedding model: ```ts filename="store-embeddings.ts" showLineNumbers copy // Create an index with dimension 1536 (for text-embedding-3-small) await store.createIndex({ indexName: "myCollection", dimension: 1536, }); ``` The dimension size must match the output dimension of your chosen embedding model. Common dimension sizes are: - OpenAI text-embedding-3-small: 1536 dimensions (or custom, e.g., 256) - Cohere embed-multilingual-v3: 1024 dimensions - Google `text-embedding-004`: 768 dimensions (or custom) > **Important**: Index dimensions cannot be changed after creation. To use a different model, delete and recreate the index with the new dimension size. ### Naming Rules for Databases Each vector database enforces specific naming conventions for indexes and collections to ensure compatibility and prevent conflicts. {/* LLM CONTEXT: This Tabs component displays naming convention rules for different vector databases. Each tab explains the specific naming requirements and restrictions for that database provider. This helps users understand the constraints and avoid naming conflicts when creating indexes or collections. The tabs provide examples of valid and invalid names to clarify the rules for each database. */} Collection (index) names must: - Start with a letter or underscore - Be up to 120 bytes long - Contain only letters, numbers, underscores, or dots - Cannot contain `$` or the null character - Example: `my_collection.123` is valid - Example: `my-index` is not valid (contains hyphen) - Example: `My$Collection` is not valid (contains `$`) Index names must: - Start with a letter or underscore - Contain only letters, numbers, and underscores - Example: `my_index_123` is valid - Example: `my-index` is not valid (contains hyphen) Index names must: - Use only lowercase letters, numbers, and dashes - Not contain dots (used for DNS routing) - Not use non-Latin characters or emojis - Have a combined length (with project ID) under 52 characters - Example: `my-index-123` is valid - Example: `my.index` is not valid (contains dot) Collection names must: - Be 1-255 characters long - Not contain any of these special characters: - `< > : " / \ | ? *` - Null character (`\0`) - Unit separator (`\u{1F}`) - Example: `my_collection_123` is valid - Example: `my/collection` is not valid (contains slash) Collection names must: - Be 3-63 characters long - Start and end with a letter or number - Contain only letters, numbers, underscores, or hyphens - Not contain consecutive periods (..) - Not be a valid IPv4 address - Example: `my-collection-123` is valid - Example: `my..collection` is not valid (consecutive periods) Collection names must: - Not be empty - Be 48 characters or less - Contain only letters, numbers, and underscores - Example: `my_collection_123` is valid - Example: `my-collection` is not valid (contains hyphen) Index names must: - Start with a letter or underscore - Contain only letters, numbers, and underscores - Example: `my_index_123` is valid - Example: `my-index` is not valid (contains hyphen) Namespace names must: - Be 2-100 characters long - Contain only: - Alphanumeric characters (a-z, A-Z, 0-9) - Underscores, hyphens, dots - Not start or end with special characters (_, -, .) - Can be case-sensitive - Example: `MyNamespace123` is valid - Example: `_namespace` is not valid (starts with underscore) Index names must: - Start with a letter - Be shorter than 32 characters - Contain only lowercase ASCII letters, numbers, and dashes - Use dashes instead of spaces - Example: `my-index-123` is valid - Example: `My_Index` is not valid (uppercase and underscore) Index names must: - Use only lowercase letters - Not begin with underscores or hyphens - Not contain spaces, commas - Not contain special characters (e.g. `:`, `"`, `*`, `+`, `/`, `\`, `|`, `?`, `#`, `>`, `<`) - Example: `my-index-123` is valid - Example: `My_Index` is not valid (contains uppercase letters) - Example: `_myindex` is not valid (begins with underscore) ### Upserting Embeddings After creating an index, you can store embeddings along with their basic metadata: ```ts filename="store-embeddings.ts" showLineNumbers copy // Store embeddings with their corresponding metadata await store.upsert({ indexName: "myCollection", // index name vectors: embeddings, // array of embedding vectors metadata: chunks.map((chunk) => ({ text: chunk.text, // The original text content id: chunk.id, // Optional unique identifier })), }); ``` The upsert operation: - Takes an array of embedding vectors and their corresponding metadata - Updates existing vectors if they share the same ID - Creates new vectors if they don't exist - Automatically handles batching for large datasets For complete examples of upserting embeddings in different vector stores, see the [Upsert Embeddings](../../examples/rag/upsert/upsert-embeddings.mdx) guide. ## Adding Metadata Vector stores support rich metadata (any JSON-serializable fields) for filtering and organization. Since metadata is stored with no fixed schema, use consistent field naming to avoid unexpected query results. **Important**: Metadata is crucial for vector storage - without it, you'd only have numerical embeddings with no way to return the original text or filter results. Always store at least the source text as metadata. ```ts showLineNumbers copy // Store embeddings with rich metadata for better organization and filtering await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map((chunk) => ({ // Basic content text: chunk.text, id: chunk.id, // Document organization source: chunk.source, category: chunk.category, // Temporal metadata createdAt: new Date().toISOString(), version: "1.0", // Custom fields language: chunk.language, author: chunk.author, confidenceScore: chunk.score, })), }); ``` Key metadata considerations: - Be strict with field naming - inconsistencies like 'category' vs 'Category' will affect queries - Only include fields you plan to filter or sort by - extra fields add overhead - Add timestamps (e.g., 'createdAt', 'lastUpdated') to track content freshness ## Best Practices - Create indexes before bulk insertions - Use batch operations for large insertions (the upsert method handles batching automatically) - Only store metadata you'll query against - Match embedding dimensions to your model (e.g., 1536 for `text-embedding-3-small`) --- title: Storage in Mastra | Mastra Docs description: Overview of Mastra's storage system and data persistence capabilities. --- import { Tabs } from "nextra/components"; import { PropertiesTable } from "@/components/properties-table"; import { SchemaTable } from "@/components/schema-table"; import { StorageOverviewImage } from "@/components/storage-overview-image"; # MastraStorage [EN] Source: https://mastra.ai/en/docs/storage/overview `MastraStorage` provides a unified interface for managing: - **Suspended Workflows**: the serialized state of suspended workflows (so they can be resumed later) - **Memory**: threads and messages per `resourceId` in your application - **Traces**: OpenTelemetry traces from all components of Mastra - **Eval Datasets**: scores and scoring reasons from eval runs

Mastra provides different storage providers, but you can treat them as interchangeable. Eg, you could use libsql in development but postgres in production, and your code will work the same both ways. ## Configuration Mastra can be configured with a default storage option: ```typescript copy import { Mastra } from "@mastra/core/mastra"; import { LibSQLStore } from "@mastra/libsql"; const mastra = new Mastra({ storage: new LibSQLStore({ url: "file:./mastra.db", }), }); ``` If you do not specify any `storage` configuration, Mastra will not persist data across application restarts or deployments. For any deployment beyond local testing you should provide your own storage configuration either on `Mastra` or directly within `new Memory()`. ## Data Schema {/* LLM CONTEXT: This Tabs component displays the database schema for different data types stored by Mastra. Each tab shows the table structure and column definitions for a specific data entity (Messages, Threads, Workflows, etc.). The tabs help users understand the data model and relationships between different storage entities. Each tab includes detailed column information with types, constraints, and example data structures. The data types include Messages, Threads, Workflows, Eval Datasets, and Traces. */} Stores conversation messages and their metadata. Each message belongs to a thread and contains the actual content along with metadata about the sender role and message type.
The message `content` column contains a JSON object conforming to the `MastraMessageContentV2` type, which is designed to align closely with the AI SDK `UIMessage` message shape.
Groups related messages together and associates them with a resource. Contains metadata about the conversation.
When `suspend` is called on a workflow, its state is saved in the following format. When `resume` is called, that state is rehydrated.
Stores eval results from running metrics against agent outputs.
Captures OpenTelemetry traces for monitoring and debugging.
### Querying Messages Messages are stored in a V2 format internally, which is roughly equivalent to the AI SDK's `UIMessage` format. When querying messages using `getMessages`, you can specify the desired output format, defaulting to `v1` for backwards compatibility: ```typescript copy // Get messages in the default V1 format (roughly equivalent to AI SDK's CoreMessage format) const messagesV1 = await mastra.getStorage().getMessages({ threadId: 'your-thread-id' }); // Get messages in the V2 format (roughly equivalent to AI SDK's UIMessage format) const messagesV2 = await mastra.getStorage().getMessages({ threadId: 'your-thread-id', format: 'v2' }); ``` ## Storage Providers Mastra supports the following providers: - For local development, check out [LibSQL Storage](../../reference/storage/libsql.mdx) - For production, check out [PostgreSQL Storage](../../reference/storage/postgresql.mdx) - For serverless deployments, check out [Upstash Storage](../../reference/storage/upstash.mdx) --- title: "Advanced Tool Usage | Tools & MCP | Mastra Docs" description: This page covers advanced features for Mastra tools, including abort signals and compatibility with the Vercel AI SDK tool format. --- # Advanced Tool Usage [EN] Source: https://mastra.ai/en/docs/tools-mcp/advanced-usage This page covers more advanced techniques and features related to using tools in Mastra. ## Abort Signals When you initiate an agent interaction using `generate()` or `stream()`, you can provide an `AbortSignal`. Mastra automatically forwards this signal to any tool executions that occur during that interaction. This allows you to cancel long-running operations within your tools, such as network requests or intensive computations, if the parent agent call is aborted. You access the `abortSignal` in the second parameter of the tool's `execute` function. ```typescript import { createTool } from "@mastra/core/tools"; import { z } from "zod"; export const longRunningTool = createTool({ id: "long-computation", description: "Performs a potentially long computation", inputSchema: z.object({ /* ... */ }), execute: async ({ context }, { abortSignal }) => { // Example: Forwarding signal to fetch const response = await fetch("https://api.example.com/data", { signal: abortSignal, // Pass the signal here }); if (abortSignal?.aborted) { console.log("Tool execution aborted."); throw new Error("Aborted"); } // Example: Checking signal during a loop for (let i = 0; i < 1000000; i++) { if (abortSignal?.aborted) { console.log("Tool execution aborted during loop."); throw new Error("Aborted"); } // ... perform computation step ... } const data = await response.json(); return { result: data }; },\n}); ``` To use this, provide an `AbortController`'s signal when calling the agent: ```typescript import { Agent } from "@mastra/core/agent"; // Assume 'agent' is an Agent instance with longRunningTool configured const controller = new AbortController(); // Start the agent call const promise = agent.generate("Perform the long computation.", { abortSignal: controller.signal, }); // Sometime later, if needed: // controller.abort(); try { const result = await promise; console.log(result.text); } catch (error) { if (error.name === "AbortError") { console.log("Agent generation was aborted."); } else { console.error("An error occurred:", error); } } ``` ## AI SDK Tool Format Mastra maintains compatibility with the tool format used by the Vercel AI SDK (`ai` package). You can define tools using the `tool` function from the `ai` package and use them directly within your Mastra agents alongside tools created with Mastra's `createTool`. First, ensure you have the `ai` package installed: ```bash npm2yarn copy npm install ai ``` Here's an example of a tool defined using the Vercel AI SDK format: ```typescript filename="src/mastra/tools/vercelWeatherTool.ts" copy import { tool } from "ai"; import { z } from "zod"; export const vercelWeatherTool = tool({ description: "Fetches current weather using Vercel AI SDK format", parameters: z.object({ city: z.string().describe("The city to get weather for"), }), execute: async ({ city }) => { console.log(`Fetching weather for ${city} (Vercel format tool)`); // Replace with actual API call const data = await fetch(`https://api.example.com/weather?city=${city}`); return data.json(); }, }); ``` You can then add this tool to your Mastra agent just like any other tool: ```typescript filename="src/mastra/agents/mixedToolsAgent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { vercelWeatherTool } from "../tools/vercelWeatherTool"; // Vercel AI SDK tool import { mastraTool } from "../tools/mastraTool"; // Mastra createTool tool export const mixedToolsAgent = new Agent({ name: "Mixed Tools Agent", instructions: "You can use tools defined in different formats.", model: openai("gpt-4o-mini"), tools: { weatherVercel: vercelWeatherTool, someMastraTool: mastraTool, }, }); ``` Mastra supports both tool formats, allowing you to mix and match as needed. --- title: "Dynamic Tool Context | Tools & MCP | Mastra Docs" description: Learn how to use Mastra's RuntimeContext to provide dynamic, request-specific configuration to tools. --- import { Callout } from "nextra/components"; # Dynamic Tool Context [EN] Source: https://mastra.ai/en/docs/tools-mcp/dynamic-context Mastra provides `RuntimeContext`, a system based on dependency injection, that allows you to pass dynamic, request-specific configuration to your tools during execution. This is useful when a tool's behavior needs to change based on user identity, request headers, or other runtime factors, without altering the tool's core code. **Note:** `RuntimeContext` is primarily used for passing data *into* tool executions. It's distinct from agent memory, which handles conversation history and state persistence across multiple calls. ## Basic Usage To use `RuntimeContext`, first define a type structure for your dynamic configuration. Then, create an instance of `RuntimeContext` typed with your definition and set the desired values. Finally, include the `runtimeContext` instance in the options object when calling `agent.generate()` or `agent.stream()`. ```typescript import { RuntimeContext } from "@mastra/core/di"; // Assume 'agent' is an already defined Mastra Agent instance // Define the context type type WeatherRuntimeContext = { "temperature-scale": "celsius" | "fahrenheit"; }; // Instantiate RuntimeContext and set values const runtimeContext = new RuntimeContext(); runtimeContext.set("temperature-scale", "celsius"); // Pass to agent call const response = await agent.generate("What's the weather like today?", { runtimeContext, // Pass the context here }); console.log(response.text); ``` ## Accessing Context in Tools Tools receive the `runtimeContext` as part of the second argument to their `execute` function. You can then use the `.get()` method to retrieve values. ```typescript filename="src/mastra/tools/weather-tool.ts" import { createTool } from "@mastra/core/tools"; import { z } from "zod"; // Assume WeatherRuntimeContext is defined as above and accessible here // Dummy fetch function async function fetchWeather( location: string, options: { temperatureUnit: "celsius" | "fahrenheit" }, ): Promise { console.log(`Fetching weather for ${location} in ${options.temperatureUnit}`); // Replace with actual API call return { temperature: options.temperatureUnit === "celsius" ? 20 : 68 }; } export const weatherTool = createTool({ id: "getWeather", description: "Get the current weather for a location", inputSchema: z.object({ location: z.string().describe("The location to get weather for"), }), // The tool's execute function receives runtimeContext execute: async ({ context, runtimeContext }) => { // Type-safe access to runtimeContext variables const temperatureUnit = runtimeContext.get("temperature-scale"); // Use the context value in the tool logic const weather = await fetchWeather(context.location, { temperatureUnit, }); return { result: `The temperature is ${weather.temperature}°${temperatureUnit === "celsius" ? "C" : "F"}`, }; }, }); ``` When the agent uses `weatherTool`, the `temperature-scale` value set in the `runtimeContext` during the `agent.generate()` call will be available inside the tool's `execute` function. ## Using with Server Middleware In server environments (like Express or Next.js), you can use middleware to automatically populate `RuntimeContext` based on incoming request data, such as headers or user sessions. Here's an example using Mastra's built-in server middleware support (which uses Hono internally) to set the temperature scale based on the Cloudflare `CF-IPCountry` header: ```typescript filename="src/mastra/index.ts" import { Mastra } from "@mastra/core"; import { RuntimeContext } from "@mastra/core/di"; import { weatherAgent } from "./agents/weather"; // Assume agent is defined elsewhere // Define RuntimeContext type type WeatherRuntimeContext = { "temperature-scale": "celsius" | "fahrenheit"; }; export const mastra = new Mastra({ agents: { weather: weatherAgent, }, server: { middleware: [ async (c, next) => { // Get the RuntimeContext instance const runtimeContext = c.get>("runtimeContext"); // Get country code from request header const country = c.req.header("CF-IPCountry"); // Set temperature scale based on country runtimeContext.set( "temperature-scale", country === "US" ? "fahrenheit" : "celsius", ); // Continue request processing await next(); }, ], }, }); ``` With this middleware in place, any agent call handled by this Mastra server instance will automatically have the `temperature-scale` set in its `RuntimeContext` based on the user's inferred country, and tools like `weatherTool` will use it accordingly. --- title: "MCP Overview | Tools & MCP | Mastra Docs" description: Learn about the Model Context Protocol (MCP), how to use third-party tools via MCPClient, connect to registries, and share your own tools using MCPServer. --- import { Tabs } from "nextra/components"; # MCP Overview [EN] Source: https://mastra.ai/en/docs/tools-mcp/mcp-overview [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is an open standard designed to let AI models discover and interact with external tools and resources. Think of it as a universal plugin system for AI agents, allowing them to use tools regardless of the language they were written in or where they are hosted. Mastra uses MCP to connect agents to external tool servers. ## Use third-party tools with an MCP Client Mastra provides the `MCPClient` class to manage connections to one or more MCP servers and access their tools. ### Installation If you haven't already, install the Mastra MCP package: ```bash npm2yarn copy npm install @mastra/mcp@latest ``` ### Registering the MCPServer Register your MCP server with Mastra to enable logging and access to configured tools and integrations: ```ts showLineNumbers filename="src/mastra/index.ts" copy import { Mastra } from "@mastra/core"; import { myMcpServer } from "./mcpServers"; export const mastra = new Mastra({ mcpServers: { myMcpServer }, }); ``` ### Configuring `MCPClient` You configure `MCPClient` with a map of servers you want to connect to. It supports connections via subprocess (Stdio) or HTTP (Streamable HTTP with SSE fallback). ```typescript import { MCPClient } from "@mastra/mcp"; const mcp = new MCPClient({ servers: { // Stdio example sequential: { command: "npx", args: ["-y", "@modelcontextprotocol/server-sequential-thinking"], }, // HTTP example weather: { url: new URL("http://localhost:8080/mcp"), requestInit: { headers: { Authorization: "Bearer your-token", }, }, }, }, }); ``` For detailed configuration options, see the [`MCPClient` reference documentation](/reference/tools/mcp-client). ### Static vs Dynamic Tool Configurations `MCPClient` offers two approaches to retrieving tools from connected servers, suitable for different application architectures: | Feature | Static Configuration (`await mcp.getTools()`) | Dynamic Configuration (`await mcp.getToolsets()`) | | :---------------- | :-------------------------------------------- | :------------------------------------------------- | | **Use Case** | Single-user, static config (e.g., CLI tool) | Multi-user, dynamic config (e.g., SaaS app) | | **Configuration** | Fixed at agent initialization | Per-request, dynamic | | **Credentials** | Shared across all uses | Can vary per user/request | | **Agent Setup** | Tools added in `Agent` constructor | Tools passed in `generate()` or `stream()` options | - **Static Configuration (`getTools()`):** Fetches all tools from all configured servers. Best when the tool configuration (like API keys) is static and shared across all users or requests. You typically call this once and pass the result to the `tools` property when defining your `Agent`. [Reference: `getTools()`](/reference/tools/mcp-client#gettools) ```typescript import { Agent } from "@mastra/core/agent"; // ... mcp client setup const agent = new Agent({ // ... other agent config tools: await mcp.getTools(), }); ``` - **Dynamic Configuration (`getToolsets()`):** Designed for scenarios where configuration might change per request or per user (e.g., different API keys for different tenants in a multi-user application). You pass the result of `getToolsets()` to the `toolsets` option in the agent's `generate()` or `stream()` method. [Reference: `getToolsets()`](/reference/tools/mcp-client#gettoolsets) ```typescript import { Agent } from "@mastra/core/agent"; // ... agent setup without tools initially async function handleRequest(userPrompt: string, userApiKey: string) { const userMcp = new MCPClient({ /* config with userApiKey */ }); const toolsets = await userMcp.getToolsets(); const response = await agent.stream(userPrompt, { toolsets, // Pass dynamic toolsets }); // ... handle response await userMcp.disconnect(); } ``` ## Connecting to an MCP registry MCP servers can be discovered through registries. Here's how to connect to some popular ones using `MCPClient`: {/* LLM CONTEXT: This Tabs component shows how to connect to different MCP (Model Context Protocol) registries. Each tab demonstrates the configuration for a specific MCP registry service (mcp.run, Composio.dev, Smithery.ai). The tabs help users understand how to connect to various MCP server providers and their different authentication methods. Each tab shows the specific URL patterns and configuration needed for that registry service. */} [mcp.run](https://www.mcp.run/) provides pre-authenticated, managed MCP servers. Tools are grouped into Profiles, each with a unique, signed URL. ```typescript import { MCPClient } from "@mastra/mcp"; const mcp = new MCPClient({ servers: { marketing: { // Example profile name url: new URL(process.env.MCP_RUN_SSE_URL!), // Get URL from mcp.run profile }, }, }); ``` > **Important:** Treat the mcp.run SSE URL like a password. Store it securely, for example, in an environment variable. > ```bash filename=".env" > MCP_RUN_SSE_URL=https://www.mcp.run/api/mcp/sse?nonce=... > ``` [Composio.dev](https://composio.dev) offers a registry of [SSE-based MCP servers](https://mcp.composio.dev). You can use the SSE URL generated for tools like Cursor directly. ```typescript import { MCPClient } from "@mastra/mcp"; const mcp = new MCPClient({ servers: { googleSheets: { url: new URL("https://mcp.composio.dev/googlesheets/[private-url-path]"), }, gmail: { url: new URL("https://mcp.composio.dev/gmail/[private-url-path]"), }, }, }); ``` Authentication with services like Google Sheets often happens interactively through the agent conversation. *Note: Composio URLs are typically tied to a single user account, making them best suited for personal automation rather than multi-tenant applications.* [Smithery.ai](https://smithery.ai) provides a registry accessible via their CLI. ```typescript // Unix/Mac import { MCPClient } from "@mastra/mcp"; const mcp = new MCPClient({ servers: { sequentialThinking: { command: "npx", args: [ "-y", "@smithery/cli@latest", "run", "@smithery-ai/server-sequential-thinking", "--config", "{}", ], }, }, }); ``` ```typescript // Windows import { MCPClient } from "@mastra/mcp"; const mcp = new MCPClient({ servers: { sequentialThinking: { command: "npx", args: [ "-y", "@smithery/cli@latest", "run", "@smithery-ai/server-sequential-thinking", "--config", "{}", ], }, }, }); ``` [Ampersand](https://withampersand.com?utm_source=mastra-docs) offers an [MCP Server](https://docs.withampersand.com/mcp) that allows you to connect your agent to 150+ integrations with SaaS products like Salesforce, Hubspot, and Zendesk. ```typescript // MCPClient with Ampersand MCP Server using SSE export const mcp = new MCPClient({ servers: { "@amp-labs/mcp-server": { "url": `https://mcp.withampersand.com/v1/sse?${new URLSearchParams({ apiKey: process.env.AMPERSAND_API_KEY, project: process.env.AMPERSAND_PROJECT_ID, integrationName: process.env.AMPERSAND_INTEGRATION_NAME, groupRef: process.env.AMPERSAND_GROUP_REF })}` } } }); ``` ```typescript // If you prefer to run the MCP server locally: import { MCPClient } from "@mastra/mcp"; // MCPClient with Ampersand MCP Server using stdio transport export const mcp = new MCPClient({ servers: { "@amp-labs/mcp-server": { command: "npx", args: [ "-y", "@amp-labs/mcp-server@latest", "--transport", "stdio", "--project", process.env.AMPERSAND_PROJECT_ID, "--integrationName", process.env.AMPERSAND_INTEGRATION_NAME, "--groupRef", process.env.AMPERSAND_GROUP_REF, // optional ], env: { AMPERSAND_API_KEY: process.env.AMPERSAND_API_KEY, }, }, }, }); ``` As an alternative to MCP, Ampersand's AI SDK also has an adapter for Mastra, so you can [directly import Ampersand tools](https://docs.withampersand.com/ai-sdk#use-with-mastra) for your agent to access. ## Share your tools with an MCP server If you have created your own Mastra tools, you can expose them to any MCP-compatible client using Mastra's `MCPServer` class. Similarly, Mastra `Agent` and `Workflow` instances can also be exposed as tools via `MCPServer`. This allows other MCP clients to interact with your agents by "asking" them questions or run your workflows. Each agent provided in the `MCPServer` configuration will be converted into a tool named `ask_`, using the agent's `description` property. Each workflow will be converted into a tool named `run_`, using its `inputSchema` and `description`. This allows others to use your tools, agents, and workflows without needing direct access to your codebase. ### Using `MCPServer` You initialize `MCPServer` with a name, version, and the Mastra tools, agents, and/or workflows you want to share. ```typescript import { MCPServer } from "@mastra/mcp"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { weatherTool } from "./tools"; // Your Mastra tool import { weatherAgent } from "./agents"; // Your Mastra Agent import { dataWorkflow } from "./workflows"; // Your Mastra Workflow const server = new MCPServer({ name: "My Custom Server", version: "1.0.0", tools: { weatherTool }, // Provide your tool(s) here agents: { weatherAgent }, // Provide your agent(s) here workflows: { dataWorkflow }, // Provide your workflow(s) here }); // Start the server (e.g., using stdio for a CLI tool) // await server.startStdio(); // Or integrate with an HTTP server using startSSE() // See MCPServer reference for details ``` For an agent to be exposed as a tool, it must have a non-empty `description` string. Similarly, for a workflow to be exposed, its `description` must also be a non-empty string. If the description is missing or empty for either, `MCPServer` will throw an error during initialization. Workflows will use their `inputSchema` for the tool's input. For detailed usage and examples, see the [`MCPServer` reference documentation](/reference/tools/mcp-server). --- title: "Tools Overview | Tools & MCP | Mastra Docs" description: Understand what tools are in Mastra, how to add them to agents, and best practices for designing effective tools. --- # Tools Overview [EN] Source: https://mastra.ai/en/docs/tools-mcp/overview Tools are functions that agents can execute to perform specific tasks or access external information. They extend an agent's capabilities beyond simple text generation, allowing interaction with APIs, databases, or other systems. Each tool typically defines: - **Inputs:** What information the tool needs to run (defined with an `inputSchema`, often using Zod). - **Outputs:** The structure of the data the tool returns (defined with an `outputSchema`). - **Execution Logic:** The code that performs the tool's action. - **Description:** Text that helps the agent understand what the tool does and when to use it. ## Creating Tools In Mastra, you create tools using the [`createTool`](/reference/tools/create-tool) function from the `@mastra/core/tools` package. ```typescript filename="src/mastra/tools/weatherInfo.ts" copy import { createTool } from "@mastra/core/tools"; import { z } from "zod"; const getWeatherInfo = async (city: string) => { // Replace with an actual API call to a weather service console.log(`Fetching weather for ${city}...`); // Example data structure return { temperature: 20, conditions: "Sunny" }; }; export const weatherTool = createTool({ id: "Get Weather Information", description: `Fetches the current weather information for a given city`, inputSchema: z.object({ city: z.string().describe("City name"), }), outputSchema: z.object({ temperature: z.number(), conditions: z.string(), }), execute: async ({ context: { city } }) => { console.log("Using tool to fetch weather information for", city); return await getWeatherInfo(city); }, }); ``` This example defines a `weatherTool` with an input schema for the city, an output schema for the weather data, and an `execute` function that contains the tool's logic. When creating tools, keep tool descriptions simple and focused on **what** the tool does and **when** to use it, emphasizing its primary use case. Technical details belong in the parameter schemas, guiding the agent on _how_ to use the tool correctly with descriptive names, clear descriptions, and explanations of default values. ## Adding Tools to an Agent To make tools available to an agent, you configure them in the agent's definition. Mentioning available tools and their general purpose in the agent's system prompt can also improve tool usage. For detailed steps and examples, see the guide on [Using Tools and MCP with Agents](/docs/agents/using-tools-and-mcp#add-tools-to-an-agent). ## Compatibility Layer for Tool Schemas Different models interpret schemas differely. Some error when certain schema properties are passed and some ignore certain schema properties but don't throw an error. Mastra adds a compatibility layer for tool schemas, ensuring tools work consistently across different model providers and that the schema constraints are respected. Some providers that we include this layer for: - **Google Gemini & Anthropic:** Remove unsupported schema properties and append relevant constraints to the tool description. - **OpenAI (including reasoning models):** Strip or adapt schema fields that are ignored or unsupported, and add instructions to the description for agent guidance. - **DeepSeek & Meta:** Apply similar compatibility logic to ensure schema alignment and tool usability. This approach makes tool usage more reliable and model-agnostic for both custom and MCP tools. --- title: Voice in Mastra | Mastra Docs description: Overview of voice capabilities in Mastra, including text-to-speech, speech-to-text, and real-time speech-to-speech interactions. --- import { Tabs } from "nextra/components"; import { AudioPlayback } from "@/components/audio-playback"; # Voice in Mastra [EN] Source: https://mastra.ai/en/docs/voice/overview Mastra's Voice system provides a unified interface for voice interactions, enabling text-to-speech (TTS), speech-to-text (STT), and real-time speech-to-speech (STS) capabilities in your applications. ## Adding Voice to Agents To learn how to integrate voice capabilities into your agents, check out the [Adding Voice to Agents](../agents/adding-voice.mdx) documentation. This section covers how to use both single and multiple voice providers, as well as real-time interactions. ```typescript import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { OpenAIVoice } from "@mastra/voice-openai"; // Initialize OpenAI voice for TTS const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new OpenAIVoice(), }); ``` You can then use the following voice capabilities: ### Text to Speech (TTS) Turn your agent's responses into natural-sounding speech using Mastra's TTS capabilities. Choose from multiple providers like OpenAI, ElevenLabs, and more. For detailed configuration options and advanced features, check out our [Text-to-Speech guide](./text-to-speech). {/* LLM CONTEXT: This Tabs component demonstrates Text-to-Speech (TTS) implementation across different voice providers. Each tab shows how to set up and use a specific TTS provider (OpenAI, Azure, ElevenLabs, etc.) with Mastra agents. The tabs help users compare different TTS providers and choose the one that best fits their needs. Each tab includes complete code examples showing agent setup, text generation, and audio playback. The providers include OpenAI, Azure, ElevenLabs, PlayAI, Google, Cloudflare, Deepgram, Speechify, Sarvam, and Murf. */} ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { OpenAIVoice } from "@mastra/voice-openai"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new OpenAIVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "default", // Optional: specify a speaker responseFormat: "wav", // Optional: specify a response format }); playAudio(audioStream); ```` Visit the [OpenAI Voice Reference](/reference/voice/openai) for more information on the OpenAI voice provider. ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { AzureVoice } from "@mastra/voice-azure"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new AzureVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "en-US-JennyNeural", // Optional: specify a speaker }); playAudio(audioStream); ```` Visit the [Azure Voice Reference](/reference/voice/azure) for more information on the Azure voice provider. ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { ElevenLabsVoice } from "@mastra/voice-elevenlabs"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new ElevenLabsVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "default", // Optional: specify a speaker }); playAudio(audioStream); ```` Visit the [ElevenLabs Voice Reference](/reference/voice/elevenlabs) for more information on the ElevenLabs voice provider. ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { PlayAIVoice } from "@mastra/voice-playai"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new PlayAIVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "default", // Optional: specify a speaker }); playAudio(audioStream); ```` Visit the [PlayAI Voice Reference](/reference/voice/playai) for more information on the PlayAI voice provider. ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { GoogleVoice } from "@mastra/voice-google"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new GoogleVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "en-US-Studio-O", // Optional: specify a speaker }); playAudio(audioStream); ```` Visit the [Google Voice Reference](/reference/voice/google) for more information on the Google voice provider. ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { CloudflareVoice } from "@mastra/voice-cloudflare"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new CloudflareVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "default", // Optional: specify a speaker }); playAudio(audioStream); ```` Visit the [Cloudflare Voice Reference](/reference/voice/cloudflare) for more information on the Cloudflare voice provider. ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { DeepgramVoice } from "@mastra/voice-deepgram"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new DeepgramVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "aura-english-us", // Optional: specify a speaker }); playAudio(audioStream); ```` Visit the [Deepgram Voice Reference](/reference/voice/deepgram) for more information on the Deepgram voice provider. ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { SpeechifyVoice } from "@mastra/voice-speechify"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new SpeechifyVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "matthew", // Optional: specify a speaker }); playAudio(audioStream); ```` Visit the [Speechify Voice Reference](/reference/voice/speechify) for more information on the Speechify voice provider. ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { SarvamVoice } from "@mastra/voice-sarvam"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new SarvamVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "default", // Optional: specify a speaker }); playAudio(audioStream); ```` Visit the [Sarvam Voice Reference](/reference/voice/sarvam) for more information on the Sarvam voice provider. ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { MurfVoice } from "@mastra/voice-murf"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new MurfVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "default", // Optional: specify a speaker }); playAudio(audioStream); ```` Visit the [Murf Voice Reference](/reference/voice/murf) for more information on the Murf voice provider. ### Speech to Text (STT) Transcribe spoken content using various providers like OpenAI, ElevenLabs, and more. For detailed configuration options and more, check out [Speech to Text](./speech-to-text). You can download a sample audio file from [here](https://github.com/mastra-ai/realtime-voice-demo/raw/refs/heads/main/how_can_i_help_you.mp3).
{/* LLM CONTEXT: This Tabs component demonstrates Speech-to-Text (STT) implementation across different voice providers. Each tab shows how to set up and use a specific STT provider for transcribing audio to text. The tabs help users understand how to implement speech recognition with different providers. Each tab includes code examples showing audio file handling, transcription, and response generation. */} ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { OpenAIVoice } from "@mastra/voice-openai"; import { createReadStream } from 'fs'; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new OpenAIVoice(), }); // Use an audio file from a URL const audioStream = await createReadStream("./how_can_i_help_you.mp3"); // Convert audio to text const transcript = await voiceAgent.voice.listen(audioStream); console.log(`User said: ${transcript}`); // Generate a response based on the transcript const { text } = await voiceAgent.generate(transcript); ```` Visit the [OpenAI Voice Reference](/reference/voice/openai) for more information on the OpenAI voice provider. ```typescript import { createReadStream } from 'fs'; import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { AzureVoice } from "@mastra/voice-azure"; import { createReadStream } from 'fs'; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new AzureVoice(), }); // Use an audio file from a URL const audioStream = await createReadStream("./how_can_i_help_you.mp3"); // Convert audio to text const transcript = await voiceAgent.voice.listen(audioStream); console.log(`User said: ${transcript}`); // Generate a response based on the transcript const { text } = await voiceAgent.generate(transcript); ```` Visit the [Azure Voice Reference](/reference/voice/azure) for more information on the Azure voice provider. ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { ElevenLabsVoice } from "@mastra/voice-elevenlabs"; import { createReadStream } from 'fs'; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new ElevenLabsVoice(), }); // Use an audio file from a URL const audioStream = await createReadStream("./how_can_i_help_you.mp3"); // Convert audio to text const transcript = await voiceAgent.voice.listen(audioStream); console.log(`User said: ${transcript}`); // Generate a response based on the transcript const { text } = await voiceAgent.generate(transcript); ```` Visit the [ElevenLabs Voice Reference](/reference/voice/elevenlabs) for more information on the ElevenLabs voice provider. ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { GoogleVoice } from "@mastra/voice-google"; import { createReadStream } from 'fs'; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new GoogleVoice(), }); // Use an audio file from a URL const audioStream = await createReadStream("./how_can_i_help_you.mp3"); // Convert audio to text const transcript = await voiceAgent.voice.listen(audioStream); console.log(`User said: ${transcript}`); // Generate a response based on the transcript const { text } = await voiceAgent.generate(transcript); ```` Visit the [Google Voice Reference](/reference/voice/google) for more information on the Google voice provider. ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { CloudflareVoice } from "@mastra/voice-cloudflare"; import { createReadStream } from 'fs'; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new CloudflareVoice(), }); // Use an audio file from a URL const audioStream = await createReadStream("./how_can_i_help_you.mp3"); // Convert audio to text const transcript = await voiceAgent.voice.listen(audioStream); console.log(`User said: ${transcript}`); // Generate a response based on the transcript const { text } = await voiceAgent.generate(transcript); ```` Visit the [Cloudflare Voice Reference](/reference/voice/cloudflare) for more information on the Cloudflare voice provider. ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { DeepgramVoice } from "@mastra/voice-deepgram"; import { createReadStream } from 'fs'; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new DeepgramVoice(), }); // Use an audio file from a URL const audioStream = await createReadStream("./how_can_i_help_you.mp3"); // Convert audio to text const transcript = await voiceAgent.voice.listen(audioStream); console.log(`User said: ${transcript}`); // Generate a response based on the transcript const { text } = await voiceAgent.generate(transcript); ```` Visit the [Deepgram Voice Reference](/reference/voice/deepgram) for more information on the Deepgram voice provider. ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { SarvamVoice } from "@mastra/voice-sarvam"; import { createReadStream } from 'fs'; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new SarvamVoice(), }); // Use an audio file from a URL const audioStream = await createReadStream("./how_can_i_help_you.mp3"); // Convert audio to text const transcript = await voiceAgent.voice.listen(audioStream); console.log(`User said: ${transcript}`); // Generate a response based on the transcript const { text } = await voiceAgent.generate(transcript); ```` Visit the [Sarvam Voice Reference](/reference/voice/sarvam) for more information on the Sarvam voice provider. ### Speech to Speech (STS) Create conversational experiences with speech-to-speech capabilities. The unified API enables real-time voice interactions between users and AI agents. For detailed configuration options and advanced features, check out [Speech to Speech](./speech-to-speech). {/* LLM CONTEXT: This Tabs component demonstrates Speech-to-Speech (STS) implementation for real-time voice interactions. Currently only shows OpenAI's realtime voice implementation for bidirectional voice conversations. The tab shows how to set up real-time voice communication with event handling for audio responses. This enables conversational AI experiences with continuous audio streaming. */} ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { playAudio, getMicrophoneStream } from '@mastra/node-audio'; import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new OpenAIRealtimeVoice(), }); // Listen for agent audio responses voiceAgent.voice.on('speaker', ({ audio }) => { playAudio(audio); }); // Initiate the conversation await voiceAgent.voice.speak('How can I help you today?'); // Send continuous audio from the microphone const micStream = getMicrophoneStream(); await voiceAgent.voice.send(micStream); ```` Visit the [OpenAI Voice Reference](/reference/voice/openai-realtime) for more information on the OpenAI voice provider. ## Voice Configuration Each voice provider can be configured with different models and options. Below are the detailed configuration options for all supported providers: {/* LLM CONTEXT: This Tabs component shows detailed configuration options for all supported voice providers. Each tab demonstrates how to configure a specific voice provider with all available options and settings. The tabs help users understand the full configuration capabilities of each provider including models, languages, and advanced settings. Each tab shows both speech and listening model configurations where applicable. */} ```typescript // OpenAI Voice Configuration const voice = new OpenAIVoice({ speechModel: { name: "gpt-3.5-turbo", // Example model name apiKey: process.env.OPENAI_API_KEY, language: "en-US", // Language code voiceType: "neural", // Type of voice model }, listeningModel: { name: "whisper-1", // Example model name apiKey: process.env.OPENAI_API_KEY, language: "en-US", // Language code format: "wav", // Audio format }, speaker: "alloy", // Example speaker name }); ``` Visit the [OpenAI Voice Reference](/reference/voice/openai) for more information on the OpenAI voice provider. ```typescript // Azure Voice Configuration const voice = new AzureVoice({ speechModel: { name: "en-US-JennyNeural", // Example model name apiKey: process.env.AZURE_SPEECH_KEY, region: process.env.AZURE_SPEECH_REGION, language: "en-US", // Language code style: "cheerful", // Voice style pitch: "+0Hz", // Pitch adjustment rate: "1.0", // Speech rate }, listeningModel: { name: "en-US", // Example model name apiKey: process.env.AZURE_SPEECH_KEY, region: process.env.AZURE_SPEECH_REGION, format: "simple", // Output format }, }); ``` Visit the [Azure Voice Reference](/reference/voice/azure) for more information on the Azure voice provider. ```typescript // ElevenLabs Voice Configuration const voice = new ElevenLabsVoice({ speechModel: { voiceId: "your-voice-id", // Example voice ID model: "eleven_multilingual_v2", // Example model name apiKey: process.env.ELEVENLABS_API_KEY, language: "en", // Language code emotion: "neutral", // Emotion setting }, // ElevenLabs may not have a separate listening model }); ``` Visit the [ElevenLabs Voice Reference](/reference/voice/elevenlabs) for more information on the ElevenLabs voice provider. ```typescript // PlayAI Voice Configuration const voice = new PlayAIVoice({ speechModel: { name: "playai-voice", // Example model name speaker: "emma", // Example speaker name apiKey: process.env.PLAYAI_API_KEY, language: "en-US", // Language code speed: 1.0, // Speech speed }, // PlayAI may not have a separate listening model }); ``` Visit the [PlayAI Voice Reference](/reference/voice/playai) for more information on the PlayAI voice provider. ```typescript // Google Voice Configuration const voice = new GoogleVoice({ speechModel: { name: "en-US-Studio-O", // Example model name apiKey: process.env.GOOGLE_API_KEY, languageCode: "en-US", // Language code gender: "FEMALE", // Voice gender speakingRate: 1.0, // Speaking rate }, listeningModel: { name: "en-US", // Example model name sampleRateHertz: 16000, // Sample rate }, }); ``` Visit the [PlayAI Voice Reference](/reference/voice/playai) for more information on the PlayAI voice provider. ```typescript // Cloudflare Voice Configuration const voice = new CloudflareVoice({ speechModel: { name: "cloudflare-voice", // Example model name accountId: process.env.CLOUDFLARE_ACCOUNT_ID, apiToken: process.env.CLOUDFLARE_API_TOKEN, language: "en-US", // Language code format: "mp3", // Audio format }, // Cloudflare may not have a separate listening model }); ``` Visit the [Cloudflare Voice Reference](/reference/voice/cloudflare) for more information on the Cloudflare voice provider. ```typescript // Deepgram Voice Configuration const voice = new DeepgramVoice({ speechModel: { name: "nova-2", // Example model name speaker: "aura-english-us", // Example speaker name apiKey: process.env.DEEPGRAM_API_KEY, language: "en-US", // Language code tone: "formal", // Tone setting }, listeningModel: { name: "nova-2", // Example model name format: "flac", // Audio format }, }); ``` Visit the [Deepgram Voice Reference](/reference/voice/deepgram) for more information on the Deepgram voice provider. ```typescript // Speechify Voice Configuration const voice = new SpeechifyVoice({ speechModel: { name: "speechify-voice", // Example model name speaker: "matthew", // Example speaker name apiKey: process.env.SPEECHIFY_API_KEY, language: "en-US", // Language code speed: 1.0, // Speech speed }, // Speechify may not have a separate listening model }); ``` Visit the [Speechify Voice Reference](/reference/voice/speechify) for more information on the Speechify voice provider. ```typescript // Sarvam Voice Configuration const voice = new SarvamVoice({ speechModel: { name: "sarvam-voice", // Example model name apiKey: process.env.SARVAM_API_KEY, language: "en-IN", // Language code style: "conversational", // Style setting }, // Sarvam may not have a separate listening model }); ``` Visit the [Sarvam Voice Reference](/reference/voice/sarvam) for more information on the Sarvam voice provider. ```typescript // Murf Voice Configuration const voice = new MurfVoice({ speechModel: { name: "murf-voice", // Example model name apiKey: process.env.MURF_API_KEY, language: "en-US", // Language code emotion: "happy", // Emotion setting }, // Murf may not have a separate listening model }); ``` Visit the [Murf Voice Reference](/reference/voice/murf) for more information on the Murf voice provider. ```typescript // OpenAI Realtime Voice Configuration const voice = new OpenAIRealtimeVoice({ speechModel: { name: "gpt-3.5-turbo", // Example model name apiKey: process.env.OPENAI_API_KEY, language: "en-US", // Language code }, listeningModel: { name: "whisper-1", // Example model name apiKey: process.env.OPENAI_API_KEY, format: "ogg", // Audio format }, speaker: "alloy", // Example speaker name }); ``` For more information on the OpenAI Realtime voice provider, refer to the [OpenAI Realtime Voice Reference](/reference/voice/openai-realtime). ### Using Multiple Voice Providers This example demonstrates how to create and use two different voice providers in Mastra: OpenAI for speech-to-text (STT) and PlayAI for text-to-speech (TTS). Start by creating instances of the voice providers with any necessary configuration. ```typescript import { OpenAIVoice } from "@mastra/voice-openai"; import { PlayAIVoice } from "@mastra/voice-playai"; import { CompositeVoice } from "@mastra/core/voice"; import { playAudio, getMicrophoneStream } from "@mastra/node-audio"; // Initialize OpenAI voice for STT const input = new OpenAIVoice({ listeningModel: { name: "whisper-1", apiKey: process.env.OPENAI_API_KEY, }, }); // Initialize PlayAI voice for TTS const output = new PlayAIVoice({ speechModel: { name: "playai-voice", apiKey: process.env.PLAYAI_API_KEY, }, }); // Combine the providers using CompositeVoice const voice = new CompositeVoice({ input, output, }); // Implement voice interactions using the combined voice provider const audioStream = getMicrophoneStream(); // Assume this function gets audio input const transcript = await voice.listen(audioStream); // Log the transcribed text console.log("Transcribed text:", transcript); // Convert text to speech const responseAudio = await voice.speak(`You said: ${transcript}`, { speaker: "default", // Optional: specify a speaker, responseFormat: "wav", // Optional: specify a response format }); // Play the audio response playAudio(responseAudio); ``` For more information on the CompositeVoice, refer to the [CompositeVoice Reference](/reference/voice/composite-voice). ## More Resources - [CompositeVoice](../../reference/voice/composite-voice.mdx) - [MastraVoice](../../reference/voice/mastra-voice.mdx) - [OpenAI Voice](../../reference/voice/openai.mdx) - [Azure Voice](../../reference/voice/azure.mdx) - [Google Voice](../../reference/voice/google.mdx) - [Deepgram Voice](../../reference/voice/deepgram.mdx) - [PlayAI Voice](../../reference/voice/playai.mdx) - [Voice Examples](../../examples/voice/text-to-speech.mdx) --- title: Speech-to-Speech Capabilities in Mastra | Mastra Docs description: Overview of speech-to-speech capabilities in Mastra, including real-time interactions and event-driven architecture. --- # Speech-to-Speech Capabilities in Mastra [EN] Source: https://mastra.ai/en/docs/voice/speech-to-speech ## Introduction Speech-to-Speech (STS) in Mastra provides a standardized interface for real-time interactions across multiple providers. STS enables continuous bidirectional audio communication through listening to events from Realtime models. Unlike separate TTS and STT operations, STS maintains an open connection that processes speech continuously in both directions. ## Configuration - **`apiKey`**: Your OpenAI API key. Falls back to the `OPENAI_API_KEY` environment variable. - **`model`**: The model ID to use for real-time voice interactions (e.g., `gpt-4o-mini-realtime`). - **`speaker`**: The default voice ID for speech synthesis. This allows you to specify which voice to use for the speech output. ```typescript const voice = new OpenAIRealtimeVoice({ apiKey: "your-openai-api-key", model: "gpt-4o-mini-realtime", speaker: "alloy", // Default voice }); // If using default settings the configuration can be simplified to: const voice = new OpenAIRealtimeVoice(); ``` ## Using STS ```typescript import { Agent } from "@mastra/core/agent"; import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import { playAudio, getMicrophoneStream } from "@mastra/node-audio"; const agent = new Agent({ name: "Agent", instructions: `You are a helpful assistant with real-time voice capabilities.`, model: openai("gpt-4o"), voice: new OpenAIRealtimeVoice(), }); // Connect to the voice service await agent.voice.connect(); // Listen for agent audio responses agent.voice.on("speaker", ({ audio }) => { playAudio(audio); }); // Initiate the conversation await agent.voice.speak("How can I help you today?"); // Send continuous audio from the microphone const micStream = getMicrophoneStream(); await agent.voice.send(micStream); ``` For integrating Speech-to-Speech capabilities with agents, refer to the [Adding Voice to Agents](../agents/adding-voice.mdx) documentation. --- title: Speech-to-Text (STT) in Mastra | Mastra Docs description: Overview of Speech-to-Text capabilities in Mastra, including configuration, usage, and integration with voice providers. --- # Speech-to-Text (STT) [EN] Source: https://mastra.ai/en/docs/voice/speech-to-text Speech-to-Text (STT) in Mastra provides a standardized interface for converting audio input into text across multiple service providers. STT helps create voice-enabled applications that can respond to human speech, enabling hands-free interaction, accessibility for users with disabilities, and more natural human-computer interfaces. ## Configuration To use STT in Mastra, you need to provide a `listeningModel` when initializing the voice provider. This includes parameters such as: - **`name`**: The specific STT model to use. - **`apiKey`**: Your API key for authentication. - **Provider-specific options**: Additional options that may be required or supported by the specific voice provider. **Note**: All of these parameters are optional. You can use the default settings provided by the voice provider, which will depend on the specific provider you are using. ```typescript const voice = new OpenAIVoice({ listeningModel: { name: "whisper-1", apiKey: process.env.OPENAI_API_KEY, }, }); // If using default settings the configuration can be simplified to: const voice = new OpenAIVoice(); ``` ## Available Providers Mastra supports several Speech-to-Text providers, each with their own capabilities and strengths: - [**OpenAI**](/reference/voice/openai/) - High-accuracy transcription with Whisper models - [**Azure**](/reference/voice/azure/) - Microsoft's speech recognition with enterprise-grade reliability - [**ElevenLabs**](/reference/voice/elevenlabs/) - Advanced speech recognition with support for multiple languages - [**Google**](/reference/voice/google/) - Google's speech recognition with extensive language support - [**Cloudflare**](/reference/voice/cloudflare/) - Edge-optimized speech recognition for low-latency applications - [**Deepgram**](/reference/voice/deepgram/) - AI-powered speech recognition with high accuracy for various accents - [**Sarvam**](/reference/voice/sarvam/) - Specialized in Indic languages and accents Each provider is implemented as a separate package that you can install as needed: ```bash pnpm add @mastra/voice-openai # Example for OpenAI ``` ## Using the Listen Method The primary method for STT is the `listen()` method, which converts spoken audio into text. Here's how to use it: ```typescript import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { OpenAIVoice } from "@mastra/voice-openai"; import { getMicrophoneStream } from "@mastra/node-audio"; const voice = new OpenAIVoice(); const agent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that provides recommendations based on user input.", model: openai("gpt-4o"), voice, }); const audioStream = getMicrophoneStream(); // Assume this function gets audio input const transcript = await agent.voice.listen(audioStream, { filetype: "m4a", // Optional: specify the audio file type }); console.log(`User said: ${transcript}`); const { text } = await agent.generate( `Based on what the user said, provide them a recommendation: ${transcript}`, ); console.log(`Recommendation: ${text}`); ``` Check out the [Adding Voice to Agents](../agents/adding-voice.mdx) documentation to learn how to use STT in an agent. --- title: Text-to-Speech (TTS) in Mastra | Mastra Docs description: Overview of Text-to-Speech capabilities in Mastra, including configuration, usage, and integration with voice providers. --- # Text-to-Speech (TTS) [EN] Source: https://mastra.ai/en/docs/voice/text-to-speech Text-to-Speech (TTS) in Mastra offers a unified API for synthesizing spoken audio from text using various providers. By incorporating TTS into your applications, you can enhance user experience with natural voice interactions, improve accessibility for users with visual impairments, and create more engaging multimodal interfaces. TTS is a core component of any voice application. Combined with STT (Speech-to-Text), it forms the foundation of voice interaction systems. Newer models support STS ([Speech-to-Speech](./speech-to-speech)) which can be used for real-time interactions but come at high cost ($). ## Configuration To use TTS in Mastra, you need to provide a `speechModel` when initializing the voice provider. This includes parameters such as: - **`name`**: The specific TTS model to use. - **`apiKey`**: Your API key for authentication. - **Provider-specific options**: Additional options that may be required or supported by the specific voice provider. The **`speaker`** option allows you to select different voices for speech synthesis. Each provider offers a variety of voice options with distinct characteristics for **Voice diversity**, **Quality**, **Voice personality**, and **Multilingual support** **Note**: All of these parameters are optional. You can use the default settings provided by the voice provider, which will depend on the specific provider you are using. ```typescript const voice = new OpenAIVoice({ speechModel: { name: "tts-1-hd", apiKey: process.env.OPENAI_API_KEY, }, speaker: "alloy", }); // If using default settings the configuration can be simplified to: const voice = new OpenAIVoice(); ``` ## Available Providers Mastra supports a wide range of Text-to-Speech providers, each with their own unique capabilities and voice options. You can choose the provider that best suits your application's needs: - [**OpenAI**](/reference/voice/openai/) - High-quality voices with natural intonation and expression - [**Azure**](/reference/voice/azure/) - Microsoft's speech service with a wide range of voices and languages - [**ElevenLabs**](/reference/voice/elevenlabs/) - Ultra-realistic voices with emotion and fine-grained control - [**PlayAI**](/reference/voice/playai/) - Specialized in natural-sounding voices with various styles - [**Google**](/reference/voice/google/) - Google's speech synthesis with multilingual support - [**Cloudflare**](/reference/voice/cloudflare/) - Edge-optimized speech synthesis for low-latency applications - [**Deepgram**](/reference/voice/deepgram/) - AI-powered speech technology with high accuracy - [**Speechify**](/reference/voice/speechify/) - Text-to-speech optimized for readability and accessibility - [**Sarvam**](/reference/voice/sarvam/) - Specialized in Indic languages and accents - [**Murf**](/reference/voice/murf/) - Studio-quality voice overs with customizable parameters Each provider is implemented as a separate package that you can install as needed: ```bash pnpm add @mastra/voice-openai # Example for OpenAI ``` ## Using the Speak Method The primary method for TTS is the `speak()` method, which converts text to speech. This method can accept options that allows you to specify the speaker and other provider-specific options. Here's how to use it: ```typescript import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { OpenAIVoice } from "@mastra/voice-openai"; const voice = new OpenAIVoice(); const agent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice, }); const { text } = await agent.generate("What color is the sky?"); // Convert text to speech to an Audio Stream const readableStream = await voice.speak(text, { speaker: "default", // Optional: specify a speaker properties: { speed: 1.0, // Optional: adjust speech speed pitch: "default", // Optional: specify pitch if supported }, }); ``` Check out the [Adding Voice to Agents](../agents/adding-voice.mdx) documentation to learn how to use TTS in an agent. --- title: "Branching, Merging, Conditions | Workflows | Mastra Docs" description: "Control flow in Mastra workflows allows you to manage branching, merging, and conditions to construct workflows that meet your logic requirements." --- # Control Flow [EN] Source: https://mastra.ai/en/docs/workflows/control-flow When you build a workflow, you typically break down operations into smaller tasks that can be linked and reused. **Steps** provide a structured way to manage these tasks by defining inputs, outputs, and execution logic. - If the schemas match, the `outputSchema` from each step is automatically passed to the `inputSchema` of the next step. - If the schemas don't match, use [Input data mapping](./input-data-mapping.mdx) to transform the `outputSchema` into the expected `inputSchema`. ## Sequential Chain steps to execute in sequence using `.then()`: ```typescript {8-9} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const step1 = createStep({...}); const step2 = createStep({...}); export const testWorkflow = createWorkflow({...}) .then(step1) .then(step2) .commit(); ``` ## Parallel Execute steps in parallel using `.parallel()`: ```typescript {8} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const step1 = createStep({...}); const step2 = createStep({...}); export const testWorkflow = createWorkflow({...}) .parallel([step1, step2]) .commit(); ``` This executes all steps in the array concurrently, then continues to the next step after all parallel steps complete. > See [Parallel Execution with Steps](/examples/workflows/parallel-steps) for more information. ## Branch Create conditional branches using `.branch()`: ```typescript {8-11} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const lessThanStep = createStep({...}); const greaterThanStep = createStep({...}); export const testWorkflow = createWorkflow({...}) .branch([ [async ({ inputData: { some_value } }) => some_value <= 9, lessThanStep], [async ({ inputData: { some_value } }) => some_value >= 10, greaterThanStep] ]) .commit(); ``` Branch conditions are evaluated sequentially, but steps with matching conditions are executed in parallel. > See [Workflow with Conditional Branching](/examples/workflows/conditional-branching) for more information. ## Loops Workflows support two types of loops. When looping a step, or any step-compatible construct like a nested workflow, the initial `inputData` is sourced from the output of the previous step. To ensure compatibility, the loop’s initial input must either: - Match the shape of the previous step’s output, or - Be explicitly transformed using the `map` function. ### Dowhile Executes a step repeatedly while a condition is true. ```typescript {7} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const counterStep = createStep({...}); export const testWorkflow = createWorkflow({...}) .dowhile(counterStep, async ({ inputData: { number } }) => number < 10) .commit(); ``` ### Dountil Executes a step repeatedly until a condition becomes true. ```typescript {7} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const counterStep = createStep({...}); export const testWorkflow = createWorkflow({...}) .dountil(counterStep, async ({ inputData: { number } }) => number > 10) .commit(); ``` ### Foreach Sequentially executes the same step for each item from the `inputSchema`. ```typescript {7} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const mapStep = createStep({...}); export const testWorkflow = createWorkflow({...}) .foreach(mapStep) .commit(); ``` #### Example Run Instance The following example demonstrates how to start a run with multiple inputs. Each input will pass through the `mapStep` sequentially. ```typescript {6} filename="src/test-workflow.ts" showLineNumbers copy import { mastra } from "./mastra"; const run = mastra.getWorkflow("testWorkflow").createRun(); const result = await run.start({ inputData: [{ number: 10 }, { number: 100 }, { number: 200 }] }); ``` To execute this run from your terminal: ```bash copy npx tsx src/test-workflow.ts ``` #### Concurrency Optionally, using `concurrency` allows you to execute steps in parallel with a limit on the number of concurrent executions. ```typescript {7} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const mapStep = createStep({...}) export const testWorkflow = createWorkflow({...}) .foreach(mapStep, { concurrency: 2 }) .commit(); ``` ## Parallel Workflows Workflows themselves can also be executed in parallel. ```typescript {4-5,8} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const workflow1 = createWorkflow({...}); const workflow2 = createWorkflow({...}); export const testWorkflow = createWorkflow({...}) .parallel([workflow1, workflow2]) .commit(); ``` Parallel steps receive previous step results as input. Their outputs are passed into the next step input as an object where the key is the step `id` and the value is the step `output`. ## Nested Workflows In the example below, `nestedWorkflow` is used as a step within `testWorkflow`. The `testWorkflow` uses `step1` whilst the `nestedWorkflow` composes `step2` and `step3` ```typescript {4,7} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; export const nestedWorkflow = createWorkflow({...}) export const testWorkflow = createWorkflow({...}) .then(nestedWorkflow) .commit(); ``` When using `.branch()` or `.parallel()` to build more complex control flows, executing more than one step requires wrapping those steps in a nested workflow, along with a clear definition of how they should be executed. ## Cloned Workflows In the example below, `clonedWorkflow` is a clone of `workflow1` and is used as a step within `testWorkflow`. The `clonedWorkflow` is run sequentially after `step1`. ```typescript {5,9} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep, cloneWorkflow } from "@mastra/core/workflows"; import { z } from "zod"; const step1 = createStep({...}); const clonedWorkflow = cloneWorkflow(step1, { id: "cloned-workflow" }); export const testWorkflow = createWorkflow({...}) .then(step1) .then(clonedWorkflow) .commit(); ``` --- title: "Inngest Workflows | Workflows | Mastra Docs" description: "Inngest workflow allows you to run Mastra workflows with Inngest" --- # Inngest Workflow [EN] Source: https://mastra.ai/en/docs/workflows/inngest-workflow [Inngest](https://www.inngest.com/docs) is a developer platform for building and running background workflows, without managing infrastructure. ## How Inngest Works with Mastra Inngest and Mastra integrate by aligning their workflow models: Inngest organizes logic into functions composed of steps, and Mastra workflows defined using `createWorkflow` and `createStep` map directly onto this paradigm. Each Mastra workflow becomes an Inngest function with a unique identifier, and each step within the workflow maps to an Inngest step. The `serve` function bridges the two systems by registering Mastra workflows as Inngest functions and setting up the necessary event handlers for execution and monitoring. When an event triggers a workflow, Inngest executes it step by step, memoizing each step’s result. This means if a workflow is retried or resumed, completed steps are skipped, ensuring efficient and reliable execution. Control flow primitives in Mastra, such as loops, conditionals, and nested workflows are seamlessly translated into the same Inngest’s function/step model, preserving advanced workflow features like composition, branching, and suspension. Real-time monitoring, suspend/resume, and step-level observability are enabled via Inngest’s publish-subscribe system and dashboard. As each step executes, its state and output are tracked using Mastra storage and can be resumed as needed. ## Setup ```sh npm install @mastra/inngest @mastra/core @mastra/deployer ``` ## Building an Inngest Workflow This guide walks through creating a workflow with Inngest and Mastra, demonstrating a counter application that increments a value until it reaches 10. ### Inngest Initialization Initialize the Inngest integration to obtain Mastra-compatible workflow helpers. The createWorkflow and createStep functions are used to create workflow and step objects that are compatible with Mastra and inngest. In development ```ts showLineNumbers copy filename="src/mastra/inngest/index.ts" import { Inngest } from "inngest"; import { realtimeMiddleware } from "@inngest/realtime"; export const inngest = new Inngest({ id: "mastra", baseUrl:"http://localhost:8288", isDev: true, middleware: [realtimeMiddleware()], }); ``` In production ```ts showLineNumbers copy filename="src/mastra/inngest/index.ts" import { Inngest } from "inngest"; import { realtimeMiddleware } from "@inngest/realtime"; export const inngest = new Inngest({ id: "mastra", middleware: [realtimeMiddleware()], }); ``` ### Creating Steps Define the individual steps that will compose your workflow: ```ts showLineNumbers copy filename="src/mastra/workflows/index.ts" import { z } from "zod"; import { inngest } from "../inngest"; import { init } from "@mastra/inngest"; // Initialize Inngest with Mastra, pointing to your local Inngest server const { createWorkflow, createStep } = init(inngest); // Step: Increment the counter value const incrementStep = createStep({ id: "increment", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), execute: async ({ inputData }) => { return { value: inputData.value + 1 }; }, }); ``` ### Creating the Workflow Compose the steps into a workflow using the `dountil` loop pattern. The createWorkflow function creates a function on inngest server that is invocable. ```ts showLineNumbers copy filename="src/mastra/workflows/index.ts" // workflow that is registered as a function on inngest server const workflow = createWorkflow({ id: "increment-workflow", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), }).then(incrementStep); workflow.commit(); export { workflow as incrementWorkflow }; ``` ### Configuring the Mastra Instance and Executing the Workflow Register the workflow with Mastra and configure the Inngest API endpoint: ```ts showLineNumbers copy filename="src/mastra/index.ts" import { Mastra } from "@mastra/core/mastra"; import { serve as inngestServe } from "@mastra/inngest"; import { incrementWorkflow } from "./workflows"; import { inngest } from "./inngest"; import { PinoLogger } from "@mastra/loggers"; // Configure Mastra with the workflow and Inngest API endpoint export const mastra = new Mastra({ workflows: { incrementWorkflow, }, server: { // The server configuration is required to allow local docker container can connect to the mastra server host: "0.0.0.0", apiRoutes: [ // This API route is used to register the Mastra workflow (inngest function) on the inngest server { path: "/api/inngest", method: "ALL", createHandler: async ({ mastra }) => inngestServe({ mastra, inngest }), // The inngestServe function integrates Mastra workflows with Inngest by: // 1. Creating Inngest functions for each workflow with unique IDs (workflow.${workflowId}) // 2. Setting up event handlers that: // - Generate unique run IDs for each workflow execution // - Create an InngestExecutionEngine to manage step execution // - Handle workflow state persistence and real-time updates // 3. Establishing a publish-subscribe system for real-time monitoring // through the workflow:${workflowId}:${runId} channel }, ], }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); ``` ### Running the Workflow locally > **Prerequisites:** > > - Docker installed and running > - Mastra project set up > - Dependencies installed (`npm install`) 1. Run `npx mastra dev` to start the Mastra server on local to serve the server on port 4111. 2. Start the Inngest Dev Server (via Docker) In a new terminal, run: ```sh docker run --rm -p 8288:8288 \ inngest/inngest \ inngest dev -u http://host.docker.internal:4111/inngest/api ``` > **Note:** The URL after `-u` tells the Inngest dev server where to find your Mastra `/api/inngest` endpoint. 3. Open the Inngest Dashboard - Visit [http://localhost:8288](http://localhost:8288) in your browser. - Go to the **Apps** section in the sidebar. - You should see your Mastra workflow registered. ![Inngest Dashboard](/inngest-apps-dashboard.png) 4. Invoke the Workflow - Go to the **Functions** section in the sidebar. - Select your Mastra workflow. - Click **Invoke** and use the following input: ```json { "data": { "inputData": { "value": 5 } } } ``` ![Inngest Function](/inngest-function-dashboard.png) 5. **Monitor the Workflow Execution** - Go to the **Runs** tab in the sidebar. - Click on the latest run to see step-by-step execution progress. ![Inngest Function Run](/inngest-runs-dashboard.png) ### Running the Workflow in Production > **Prerequisites:** > > - Vercel account and Vercel CLI installed (`npm i -g vercel`) > - Inngest account > - Vercel token (recommended: set as environment variable) 1. Add Vercel Deployer to Mastra instance ```ts showLineNumbers copy filename="src/mastra/index.ts" import { VercelDeployer } from "@mastra/deployer-vercel"; export const mastra = new Mastra({ // ...other config deployer: new VercelDeployer({ teamSlug: "your_team_slug", projectName: "your_project_name", // you can get your vercel token from the vercel dashboard by clicking on the user icon in the top right corner // and then clicking on "Account Settings" and then clicking on "Tokens" on the left sidebar. token: "your_vercel_token", }), }); ``` > **Note:** Set your Vercel token in your environment: > > ```sh > export VERCEL_TOKEN=your_vercel_token > ``` 2. Build the mastra instance ```sh npx mastra build ``` 3. Deploy to Vercel ```sh cd .mastra/output vercel --prod ``` > **Tip:** If you haven't already, log in to Vercel CLI with `vercel login`. 4. Sync with Inngest Dashboard - Go to the [Inngest dashboard](https://app.inngest.com/env/production/apps). - Click **Sync new app with Vercel** and follow the instructions. - You should see your Mastra workflow registered as an app. ![Inngest Dashboard](/inngest-apps-dashboard-prod.png) 5. Invoke the Workflow - In the **Functions** section, select `workflow.increment-workflow`. - Click **All actions** (top right) > **Invoke**. - Provide the following input: ```json { "data": { "inputData": { "value": 5 } } } ``` ![Inngest Function Run](/inngest-function-dashboard-prod.png) 6. Monitor Execution - Go to the **Runs** tab. - Click the latest run to see step-by-step execution progress. ![Inngest Function Run](/inngest-runs-dashboard-prod.png) --- title: "Input Data Mapping with Workflow | Mastra Docs" description: "Learn how to use workflow input mapping to create more dynamic data flows in your Mastra workflows." --- # Input Data Mapping [EN] Source: https://mastra.ai/en/docs/workflows/input-data-mapping Input data mapping allows explicit mapping of values for the inputs of the next step. These values can come from a number of sources: - The outputs of a previous step - The runtime context - A constant value - The initial input of the workflow ## Map In this example the `output` from `step1` is transformed to match the `inputSchema` required for the `step2`. The value from `step1` is available using the `inputData` parameter of the `.map` function. ```typescript {18} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy const step1 = createStep({...}); const step2 = createStep({...}); export const testWorkflow = createWorkflow({ id: "test-workflow", description: 'Test workflow', inputSchema: z.object({ input: z.number() }), outputSchema: z.object({ output: z.string() }) }) .then(step1) .map(({ inputData }) => { const { value } = inputData; return { output: `${value}` }; }) .then(step2) .commit(); ``` ### inputData Use `inputData` to access the full output of the previous step: ```typescript {2} showLineNumbers .map(({ inputData }) => { const { value} = inputData; ... }) ``` ### getStepResult Use `getStepResult` to access the full output of a specific step by referencing the step's instance: ```typescript {3} showLineNumbers .then(step1) .map(({ getStepResult }) => { console.log(getStepResult(step1)); ... }) ``` ### getInitData Use `getInitData` to access the initial input data provided to the workflow: ```typescript {3} showLineNumbers .then(step1) .map(({ getInitData }) => { console.log(getInitData()); ... }) ``` ## Renaming Outputs ### Step Outputs You can rename step outputs using the object syntax in `.map()`. In the example below, the `value` output from `step1` is renamed to `details`: ```typescript {3} showLineNumbers .then(step) .map({ details: { step: step, path: "value" } }) ``` ### Workflow Outputs You can rename workflow outputs by using **referential composition**. This involves passing the workflow instance as the `initData`. ```typescript {12, 16} showLineNumbers export const testWorkflow = createWorkflow({ id: "test-workflow", description: 'Test workflow', inputSchema: z.object({ input: z.string() }), outputSchema: z.object({ output: z.string() }) }); testWorkflow .then(cityCoordinatesStep) .map({ details: { initData: testWorkflow, path: "value" } }) ``` --- title: "Handling Complex LLM Operations | Workflows | Mastra" description: "Workflows in Mastra help you orchestrate complex sequences of operations with features like branching, parallel execution, resource suspension, and more." --- import { Steps } from "nextra/components"; # Workflows Overview [EN] Source: https://mastra.ai/en/docs/workflows/overview Workflows let you define and orchestrate complex sequences of tasks as **typed steps** connected by data flows. Each step has clearly defined inputs and outputs validated by Zod schemas. A workflow manages execution order, dependencies, branching, parallelism, and error handling — enabling you to build robust, reusable processes. Steps can be nested or cloned to compose larger workflows. You create workflows by: - Defining **steps** with `createStep`, specifying input/output schemas and business logic. - Composing **steps** with `createWorkflow` to define the execution flow. - Running **workflows** to execute the entire sequence, with built-in support for suspension, resumption, and streaming results. This structure provides full type safety and runtime validation, ensuring data integrity across the entire workflow. ## Getting Started To use workflows, first import the necessary functions from the workflows module: ```typescript filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; ``` ### Create Step Steps are the building blocks of workflows. Create a step using `createStep`: ```typescript filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy const step1 = createStep({...}); ``` > See [createStep](/reference/workflows/step) for more information. ### Create Workflow Create a workflow using `createWorkflow` and complete it with `.commit()`. ```typescript {6,17} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const step1 = createStep({...}); export const testWorkflow = createWorkflow({ id: "test-workflow", description: 'Test workflow', inputSchema: z.object({ input: z.string() }), outputSchema: z.object({ output: z.string() }) }) .then(step1) .commit(); ``` > See [workflow](/reference/workflows/workflow) for more information. #### Composing Steps Workflow steps can be composed and executed sequentially using `.then()`. ```typescript {17,18} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const step1 = createStep({...}); const step2 = createStep({...}); export const testWorkflow = createWorkflow({ id: "test-workflow", description: 'Test workflow', inputSchema: z.object({ input: z.string() }), outputSchema: z.object({ output: z.string() }) }) .then(step1) .then(step2) .commit(); ``` > Steps can be composed using a number of different methods. See [Control Flow](/docs/workflows/control-flow) for more information. #### Cloning Steps Workflow steps can be cloned using `cloneStep()`, and used with any workflow method. ```typescript {5,19} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep, cloneStep } from "@mastra/core/workflows"; import { z } from "zod"; const step1 = createStep({...}); const clonedStep = cloneStep(step1, { id: "cloned-step" }); const step2 = createStep({...}); export const testWorkflow = createWorkflow({ id: "test-workflow", description: 'Test workflow', inputSchema: z.object({ input: z.string() }), outputSchema: z.object({ output: z.string() }) }) .then(step1) .then(clonedStep) .then(step2) .commit(); ``` ### Register Workflow Register a workflow using `workflows` in the main Mastra instance: ```typescript {8} filename="src/mastra/index.ts" showLineNumbers copy import { Mastra } from "@mastra/core/mastra"; import { PinoLogger } from "@mastra/loggers"; import { LibSQLStore } from "@mastra/libsql"; import { testWorkflow } from "./workflows/test-workflow"; export const mastra = new Mastra({ workflows: { testWorkflow }, storage: new LibSQLStore({ // stores telemetry, evals, ... into memory storage, if it needs to persist, change to file:../mastra.db url: ":memory:" }), logger: new PinoLogger({ name: "Mastra", level: "info" }) }); ``` ### Run Workflow There are two ways to run and test workflows. #### Mastra Playground With the Mastra Dev Server running you can run the workflow from the Mastra Playground by visiting [http://localhost:4111/workflows](http://localhost:4111/workflows) in your browser. #### Command line Create a run instance of any Mastra workflow using `createRun` and `start`: ```typescript {3,5} filename="src/test-workflow.ts" showLineNumbers copy import { mastra } from "./mastra"; const run = mastra.getWorkflow("testWorkflow").createRun(); const result = await run.start({ inputData: { city: "London" } }); console.log(JSON.stringify(result, null, 2)); ``` > see [createRun](/reference/workflows/create-run) and [start](/reference/workflows/start) for more information. To trigger this workflow, run the following: ```bash npx tsx src/test-workflow.ts ``` ### Stream Workflow Similar to the run method shown above, workflows can also be streamed: ```typescript {5} filename="src/test-workflow.ts" showLineNumbers copy import { mastra } from "./mastra"; const run = mastra.getWorkflow("testWorkflow").createRun(); const result = await run.stream({ inputData: { city: "London" } }); for await (const chunk of result.stream) { console.log(chunk); } ``` > See [stream](/reference/workflows/stream) and [messages](/reference/workflows/stream#messages) for more information. ### Watch Workflow A workflow can also be watched, allowing you to inspect each event that is emitted. ```typescript {5} filename="src/test-workflow.ts" showLineNumbers copy import { mastra } from "./mastra"; const run = mastra.getWorkflow("testWorkflow").createRun(); run.watch((event) => { console.log(event); }); const result = await run.start({ inputData: { city: "London" } }); ``` > See [watch](/reference/workflows/watch) for more information. ## More Resources - The [Workflow Guide](../../guides/guide/ai-recruiter.mdx) in the Guides section is a tutorial that covers the main concepts. - [Parallel Steps workflow example](../../examples/workflows/parallel-steps.mdx) - [Conditional Branching workflow example](../../examples/workflows/conditional-branching.mdx) - [Inngest workflow example](../../examples/workflows/inngest-workflow.mdx) - [Suspend and Resume workflow example](../../examples/workflows/human-in-the-loop.mdx) --- title: "Suspend & Resume Workflows | Human-in-the-Loop | Mastra Docs" description: "Suspend and resume in Mastra workflows allows you to pause execution while waiting for external input or resources." --- # Suspend & Resume [EN] Source: https://mastra.ai/en/docs/workflows/suspend-and-resume Workflows can be paused at any step, with their current state persisted as a snapshot in storage. Execution can then be resumed from this saved snapshot when ready. Persisting the snapshot ensures the workflow state is maintained across sessions, deployments, and server restarts, essential for workflows that may remain suspended while awaiting external input or resources. Common scenarios for suspending workflows include: - Waiting for human approval or input - Pausing until external API resources become available - Collecting additional data needed for later steps - Rate limiting or throttling expensive operations - Handling event-driven processes with external triggers ## Workflow Status When running a workflow, its `status` can be one of the following: - `running` - The workflow is currently running - `suspended` - The workflow is suspended - `success` - The workflow has completed - `failed` - The workflow has failed ## Suspend When the state is `suspended`, you can identify any and all steps that have been suspended by looking at the `suspended` array of the workflow. ```typescript {17} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy const step1 = createStep({ id: "step-1", description: "Test suspend", inputSchema: z.object({ input: z.array(z.string()) }), resumeSchema: z.object({ city: z.string() }), outputSchema: z.object({ output: z.string() }), execute: async ({ resumeData, suspend }) => { const { city } = resumeData ?? {}; if (!city) { await suspend({}); return { outcome: "" }; } return { output: "" }; } }); export const testWorkflow = createWorkflow({}) .then(step1) .commit(); ``` > See [Define Suspendable workflow](/examples/workflows/human-in-the-loop#define-suspendable-workflow) for more information. ## Resume A workflow can be resumed by calling `resume` and providing the required `resumeData`. ```typescript {6,12,13,14} filename="src/test-workflow.ts" showLineNumbers copy import { mastra } from "./mastra"; const run = mastra.getWorkflow("testWorkflow").createRun(); const result = await run.start({ inputData: { suggestions: ["London", "Paris", "New York"] } }); console.log(JSON.stringify(result, null, 2)); if (result.status === "suspended") { const resumedResult = await run.resume({ step: 'step-1', resumeData: { city: "New York" } }); console.log(JSON.stringify(resumedResult, null, 2)); } ``` To execute this run from your terminal: ```bash copy npx tsx src/test-workflow.ts ``` ### Nested Workflow To resume a suspended nested workflow pass the workflow instance to the `step` parameter of the `resume` function. ```typescript {3} filename="src/test-workflow.ts" showLineNumbers copy const dowhileWorkflow = createWorkflow({ id: 'dowhile-workflow', inputSchema: z.object({ value: z.number() }), outputSchema: z.object({ value: z.number() }), }) .dountil( createWorkflow({ id: 'simple-resume-workflow', inputSchema: z.object({ value: z.number() }), outputSchema: z.object({ value: z.number() }), steps: [incrementStep, resumeStep], }) .then(incrementStep) .then(resumeStep) .commit(), async ({ inputData }) => inputData.value >= 10, ) .then( createStep({ id: 'final', inputSchema: z.object({ value: z.number() }), outputSchema: z.object({ value: z.number() }), execute: async ({ inputData }) => ({ value: inputData.value }), }), ) .commit(); const run = dowhileWorkflow.createRun(); const result = await run.start({ inputData: { value: 0 } }); if (result.status === "suspended") { const resumedResult = await run.resume({ resumeData: { value: 2 }, step: ['simple-resume-workflow', 'resume'], }); console.log(JSON.stringify(resumedResult, null, 2)); } ``` ## RuntimeContext When using suspend/resume with `RuntimeContext`, you can create the instance yourself, and pass it to the `start` and `resume` functions. `RuntimeContext` is not automatically shared on a workflow run. ```typescript {1,4,9,16} filename="src/test-workflow.ts" showLineNumbers copy import { RuntimeContext } from "@mastra/core/di"; import { mastra } from "./mastra"; const runtimeContext = new RuntimeContext(); const run = mastra.getWorkflow("testWorkflow").createRun(); const result = await run.start({ inputData: { suggestions: ["London", "Paris", "New York"] }, runtimeContext }); if (result.status === "suspended") { const resumedResult = await run.resume({ step: 'step-1', resumeData: { city: "New York" }, runtimeContext }); } ``` --- title: "Using Workflows with Agents and Tools | Workflows | Mastra Docs" description: "Steps in Mastra workflows provide a structured way to manage operations by defining inputs, outputs, and execution logic." --- # Agents and Tools [EN] Source: https://mastra.ai/en/docs/workflows/using-with-agents-and-tools Workflow steps are composable and typically run logic directly within the `execute` function. However, there are cases where calling an agent or tool is more appropriate. This pattern is especially useful when: - Generating natural language responses from user input using an LLM. - Abstracting complex or reusable logic into a dedicated tool. - Interacting with third-party APIs in a structured or reusable way. Workflows can use Mastra agents or tools directly as steps, for example: `createStep(testAgent)` or `createStep(testTool)`. ## Agents To include an agent in a workflow, define it in the usual way, then either add it directly to the workflow using `createStep(testAgent)` or, invoke it from within a step's `execute` function using `.generate()`. ### Example Agent This agent uses OpenAI to generate a fact about a city, country, and timezone. ```typescript filename="src/mastra/agents/test-agent.ts" showLineNumbers copy import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; export const testAgent = new Agent({ name: "test-agent", description: "Create facts for a country based on the city", instructions: `Return an interesting fact about the country based on the city provided`, model: openai("gpt-4o") }); ``` ### Agents As Step In this example, `step1` uses the `testAgent` to generate an interesting fact about the country based on a given city. The `.map` method transforms the workflow input into a `prompt` string compatible with the `testAgent`. The step is composed into the workflow using `.then()`, allowing it to receive the mapped input and return the agent's structured output. The workflow is finalized with `.commit()`. ```typescript {3} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { testAgent } from "../agents/test-agent"; const step1 = createStep(testAgent); export const testWorkflow = createWorkflow({ id: "test-workflow", description: 'Test workflow', inputSchema: z.object({ input: z.string() }), outputSchema: z.object({ output: z.string() }) }) .map(({ inputData }) => { const { input } = inputData; return { prompt: `Provide facts about the city: ${input}` }; }) .then(step1) .commit(); ``` ### Agent Generate In this example, the `step1` builds a prompt using the provided `input` and passes it to the `testAgent`, which returns a plain-text response containing facts about the city and its country. The step is added to the workflow using the sequential `.then()` method, allowing it to receive input from the workflow and return structured output. The workflow is finalized with `.commit()`. ```typescript {1,18, 29} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { testAgent } from "../agents/test-agent"; const step1 = createStep({ id: "step-1", description: "Create facts for a country based on the city", inputSchema: z.object({ input: z.string() }), outputSchema: z.object({ output: z.string() }), execute: async ({ inputData }) => { const { input } = inputData; const prompt = `Provide facts about the city: ${input}` const { text } = await testAgent.generate([ { role: "user", content: prompt } ]); return { output: text }; } }); export const testWorkflow = createWorkflow({...}) .then(step1) .commit(); ``` ## Tools To use a tool within a workflow, define it in the usual way, then either add it directly to the workflow using `createStep(testTool)` or, invoke it from within a step's `execute` function using `.execute()`. ### Example Tool The example below uses the Open Meteo API to retrieve geolocation details for a city, returning its name, country, and timezone. ```typescript filename="src/mastra/tools/test-tool.ts" showLineNumbers copy import { createTool } from "@mastra/core"; import { z } from "zod"; export const testTool = createTool({ id: "test-tool", description: "Gets country for a city", inputSchema: z.object({ input: z.string() }), outputSchema: z.object({ country_name: z.string() }), execute: async ({ context }) => { const { input } = context; const geocodingResponse = await fetch(`https://geocoding-api.open-meteo.com/v1/search?name=${input}`); const geocodingData = await geocodingResponse.json(); const { country } = geocodingData.results[0]; return { country_name: country }; } }); ``` ### Tools as Step In this example, `step1` uses the `testTool`, which performs a geocoding lookup using the provided `city` and returns the resolved `country`. The step is added to the workflow using the sequential `.then()` method, allowing it to receive input from the workflow and return structured output. The workflow is finalized with `.commit()`. ```typescript {1,3,6} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { testTool } from "../tools/test-tool"; const step1 = createStep(testTool); export const testWorkflow = createWorkflow({...}) .then(step1) .commit(); ``` ### Tool Execute In this example, `step1` directly invokes `testTool` using its `.execute()` method. The tool performs a geocoding lookup with the provided `city` and returns the corresponding `country`. The result is returned as structured output from the step. The step is composed into the workflow using `.then()`, enabling it to process workflow input and produce typed output. The workflow is finalized with `.commit()` ```typescript {3,20,32} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { RuntimeContext } from "@mastra/core/di"; import { testTool } from "../tools/test-tool"; const runtimeContext = new RuntimeContext(); const step1 = createStep({ id: "step-1", description: "Gets country for a city", inputSchema: z.object({ input: z.string() }), outputSchema: z.object({ output: z.string() }), execute: async ({ inputData }) => { const { input } = inputData; const { country_name } = await testTool.execute({ context: { input }, runtimeContext }); return { output: country_name }; } }); export const testWorkflow = createWorkflow({...}) .then(step1) .commit(); ``` ## Workflow As Tool In this example the `cityStringWorkflow` workflow has been added to the main Mastra instance. ```typescript {7} filename="src/mastra/index.ts" showLineNumbers copy import { Mastra } from "@mastra/core/mastra"; import { testWorkflow, cityStringWorkflow } from "./workflows/test-workflow"; export const mastra = new Mastra({ ... workflows: { testWorkflow, cityStringWorkflow }, }); ``` Once a workflow has been registered it can be referenced using `getWorkflow` from withing a tool. ```typescript {10,17-27} filename="src/mastra/tools/test-tool.ts" showLineNumbers copy export const cityCoordinatesTool = createTool({ id: "city-tool", description: "Convert city details", inputSchema: z.object({ city: z.string() }), outputSchema: z.object({ outcome: z.string() }), execute: async ({ context, mastra }) => { const { city } = context; const geocodingResponse = await fetch(`https://geocoding-api.open-meteo.com/v1/search?name=${city}`); const geocodingData = await geocodingResponse.json(); const { name, country, timezone } = geocodingData.results[0]; const workflow = mastra?.getWorkflow("cityStringWorkflow"); const run = workflow?.createRun(); const { result } = await run?.start({ inputData: { city_name: name, country_name: country, country_timezone: timezone } }); return { outcome: result.outcome }; } }); ``` ## MCP Server You can convert your workflows into tools by passing them into an instance of a Mastra `MCPServer`. This allows any MCP-compatible client to access your workflow. The workflow description becomes the tool description and the input schema becomes the tool's input schema. When you provide workflows to the server, each workflow is automatically exposed as a callable tool for example: - `run_testWorkflow`. ```typescript filename="src/test-mcp-server.ts" showLineNumbers copy import { MCPServer } from "@mastra/mcp"; import { testAgent } from "./mastra/agents/test-agent"; import { testTool } from "./mastra/tools/test-tool"; import { testWorkflow } from "./mastra/workflows/test-workflow"; async function startServer() { const server = new MCPServer({ name: "test-mcp-server", version: "1.0.0", workflows: { testWorkflow } }); await server.startStdio(); console.log("MCPServer started on stdio"); } startServer().catch(console.error); ``` To verify that your workflow is available on the server, you can connect with an MCPClient. ```typescript filename="src/test-mcp-client.ts" showLineNumbers copy import { MCPClient } from "@mastra/mcp"; async function main() { const mcp = new MCPClient({ servers: { local: { command: "npx", args: ["tsx", "src/test-mcp-server.ts"] } } }); const tools = await mcp.getTools(); console.log(tools); } main().catch(console.error); ``` Run the client script to see your workflow tool. ```bash npx tsx src/test-mcp-client.ts ``` ## More Resources - [MCPServer reference documentation](/reference/tools/mcp-server). - [MCPClient reference documentation](/reference/tools/mcp-client). --- title: "Branching, Merging, Conditions | Workflows (Legacy) | Mastra Docs" description: "Control flow in Mastra legacy workflows allows you to manage branching, merging, and conditions to construct legacy workflows that meet your logic requirements." --- # Control Flow in Legacy Workflows: Branching, Merging, and Conditions [EN] Source: https://mastra.ai/en/docs/workflows-legacy/control-flow When you create a multi-step process, you may need to run steps in parallel, chain them sequentially, or follow different paths based on outcomes. This page describes how you can manage branching, merging, and conditions to construct workflows that meet your logic requirements. The code snippets show the key patterns for structuring complex control flow. ## Parallel Execution You can run multiple steps at the same time if they don't depend on each other. This approach can speed up your workflow when steps perform independent tasks. The code below shows how to add two steps in parallel: ```typescript myWorkflow.step(fetchUserData).step(fetchOrderData); ``` See the [Parallel Steps](../../examples/workflows_legacy/parallel-steps.mdx) example for more details. ## Sequential Execution Sometimes you need to run steps in strict order to ensure outputs from one step become inputs for the next. Use .then() to link dependent operations. The code below shows how to chain steps sequentially: ```typescript myWorkflow.step(fetchOrderData).then(validateData).then(processOrder); ``` See the [Sequential Steps](../../examples/workflows_legacy/sequential-steps.mdx) example for more details. ## Branching and Merging Paths When different outcomes require different paths, branching is helpful. You can also merge paths later once they complete. The code below shows how to branch after stepA and later converge on stepF: ```typescript myWorkflow .step(stepA) .then(stepB) .then(stepD) .after(stepA) .step(stepC) .then(stepE) .after([stepD, stepE]) .step(stepF); ``` In this example: - stepA leads to stepB, then to stepD. - Separately, stepA also triggers stepC, which in turn leads to stepE. - Separately, stepF is triggered when both stepD and stepE are completed. See the [Branching Paths](../../examples/workflows_legacy/branching-paths.mdx) example for more details. ## Merging Multiple Branches Sometimes you need a step to execute only after multiple other steps have completed. Mastra provides a compound `.after([])` syntax that allows you to specify multiple dependencies for a step. ```typescript myWorkflow .step(fetchUserData) .then(validateUserData) .step(fetchProductData) .then(validateProductData) // This step will only run after BOTH validateUserData AND validateProductData have completed .after([validateUserData, validateProductData]) .step(processOrder); ``` In this example: - `fetchUserData` and `fetchProductData` run in parallel branches - Each branch has its own validation step - The `processOrder` step only executes after both validation steps have completed successfully This pattern is particularly useful for: - Joining parallel execution paths - Implementing synchronization points in your workflow - Ensuring all required data is available before proceeding You can also create complex dependency patterns by combining multiple `.after([])` calls: ```typescript myWorkflow // First branch .step(stepA) .then(stepB) .then(stepC) // Second branch .step(stepD) .then(stepE) // Third branch .step(stepF) .then(stepG) // This step depends on the completion of multiple branches .after([stepC, stepE, stepG]) .step(finalStep); ``` ## Cyclical Dependencies and Loops Workflows often need to repeat steps until certain conditions are met. Mastra provides two powerful methods for creating loops: `until` and `while`. These methods offer an intuitive way to implement repetitive tasks. ### Using Manual Cyclical Dependencies (Legacy Approach) In earlier versions, you could create loops by manually defining cyclical dependencies with conditions: ```typescript myWorkflow .step(fetchData) .then(processData) .after(processData) .step(finalizeData, { when: { "processData.status": "success" }, }) .step(fetchData, { when: { "processData.status": "retry" }, }); ``` While this approach still works, the newer `until` and `while` methods provide a cleaner and more maintainable way to create loops. ### Using `until` for Condition-Based Loops The `until` method repeats a step until a specified condition becomes true. It takes these arguments: 1. A condition that determines when to stop looping 2. The step to repeat 3. Optional variables to pass to the repeated step ```typescript import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Step that increments a counter until target is reached const incrementStep = new LegacyStep({ id: "increment", inputSchema: z.object({ // Current counter value counter: z.number().optional(), }), outputSchema: z.object({ // Updated counter value updatedCounter: z.number(), }), execute: async ({ context }) => { const { counter = 0 } = context.inputData; return { updatedCounter: counter + 1 }; }, }); workflow .step(incrementStep) .until( async ({ context }) => { // Stop when counter reaches 10 const result = context.getStepResult(incrementStep); return (result?.updatedCounter ?? 0) >= 10; }, incrementStep, { // Pass current counter to next iteration counter: { step: incrementStep, path: "updatedCounter", }, }, ) .then(finalStep); ``` You can also use a reference-based condition: ```typescript workflow .step(incrementStep) .until( { ref: { step: incrementStep, path: "updatedCounter" }, query: { $gte: 10 }, }, incrementStep, { counter: { step: incrementStep, path: "updatedCounter", }, }, ) .then(finalStep); ``` ### Using `while` for Condition-Based Loops The `while` method repeats a step as long as a specified condition remains true. It takes the same arguments as `until`: 1. A condition that determines when to continue looping 2. The step to repeat 3. Optional variables to pass to the repeated step ```typescript // Step that increments a counter while below target const incrementStep = new LegacyStep({ id: "increment", inputSchema: z.object({ // Current counter value counter: z.number().optional(), }), outputSchema: z.object({ // Updated counter value updatedCounter: z.number(), }), execute: async ({ context }) => { const { counter = 0 } = context.inputData; return { updatedCounter: counter + 1 }; }, }); workflow .step(incrementStep) .while( async ({ context }) => { // Continue while counter is less than 10 const result = context.getStepResult(incrementStep); return (result?.updatedCounter ?? 0) < 10; }, incrementStep, { // Pass current counter to next iteration counter: { step: incrementStep, path: "updatedCounter", }, }, ) .then(finalStep); ``` You can also use a reference-based condition: ```typescript workflow .step(incrementStep) .while( { ref: { step: incrementStep, path: "updatedCounter" }, query: { $lt: 10 }, }, incrementStep, { counter: { step: incrementStep, path: "updatedCounter", }, }, ) .then(finalStep); ``` ### Comparison Operators for Reference Conditions When using reference-based conditions, you can use these comparison operators: | Operator | Description | | -------- | ------------------------ | | `$eq` | Equal to | | `$ne` | Not equal to | | `$gt` | Greater than | | `$gte` | Greater than or equal to | | `$lt` | Less than | | `$lte` | Less than or equal to | ## Conditions Use the when property to control whether a step runs based on data from previous steps. Below are three ways to specify conditions. ### Option 1: Function ```typescript myWorkflow.step( new Step({ id: "processData", execute: async ({ context }) => { // Action logic }, }), { when: async ({ context }) => { const fetchData = context?.getStepResult<{ status: string }>("fetchData"); return fetchData?.status === "success"; }, }, ); ``` ### Option 2: Query Object ```typescript myWorkflow.step( new Step({ id: "processData", execute: async ({ context }) => { // Action logic }, }), { when: { ref: { step: { id: "fetchData", }, path: "status", }, query: { $eq: "success" }, }, }, ); ``` ### Option 3: Simple Path Comparison ```typescript myWorkflow.step( new Step({ id: "processData", execute: async ({ context }) => { // Action logic }, }), { when: { "fetchData.status": "success", }, }, ); ``` ## Data Access Patterns Mastra provides several ways to pass data between steps: 1. **Context Object** - Access step results directly through the context object 2. **Variable Mapping** - Explicitly map outputs from one step to inputs of another 3. **getStepResult Method** - Type-safe method to retrieve step outputs Each approach has its advantages depending on your use case and requirements for type safety. ### Using getStepResult Method The `getStepResult` method provides a type-safe way to access step results. This is the recommended approach when working with TypeScript as it preserves type information. #### Basic Usage For better type safety, you can provide a type parameter to `getStepResult`: ```typescript showLineNumbers filename="src/mastra/workflows/get-step-result.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const fetchUserStep = new LegacyStep({ id: "fetchUser", outputSchema: z.object({ name: z.string(), userId: z.string(), }), execute: async ({ context }) => { return { name: "John Doe", userId: "123" }; }, }); const analyzeDataStep = new LegacyStep({ id: "analyzeData", execute: async ({ context }) => { // Type-safe access to previous step result const userData = context.getStepResult<{ name: string; userId: string }>( "fetchUser", ); if (!userData) { return { status: "error", message: "User data not found" }; } return { analysis: `Analyzed data for user ${userData.name}`, userId: userData.userId, }; }, }); ``` #### Using Step References The most type-safe approach is to reference the step directly in the `getStepResult` call: ```typescript showLineNumbers filename="src/mastra/workflows/step-reference.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Define step with output schema const fetchUserStep = new LegacyStep({ id: "fetchUser", outputSchema: z.object({ userId: z.string(), name: z.string(), email: z.string(), }), execute: async () => { return { userId: "user123", name: "John Doe", email: "john@example.com", }; }, }); const processUserStep = new LegacyStep({ id: "processUser", execute: async ({ context }) => { // TypeScript will infer the correct type from fetchUserStep's outputSchema const userData = context.getStepResult(fetchUserStep); return { processed: true, userName: userData?.name, }; }, }); const workflow = new LegacyWorkflow({ name: "user-workflow", }); workflow.step(fetchUserStep).then(processUserStep).commit(); ``` ### Using Variable Mapping Variable mapping is an explicit way to define data flow between steps. This approach makes dependencies clear and provides good type safety. The data injected into the step is available in the `context.inputData` object, and typed based on the `inputSchema` of the step. ```typescript showLineNumbers filename="src/mastra/workflows/variable-mapping.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const fetchUserStep = new LegacyStep({ id: "fetchUser", outputSchema: z.object({ userId: z.string(), name: z.string(), email: z.string(), }), execute: async () => { return { userId: "user123", name: "John Doe", email: "john@example.com", }; }, }); const sendEmailStep = new LegacyStep({ id: "sendEmail", inputSchema: z.object({ recipientEmail: z.string(), recipientName: z.string(), }), execute: async ({ context }) => { const { recipientEmail, recipientName } = context.inputData; // Send email logic here return { status: "sent", to: recipientEmail, }; }, }); const workflow = new LegacyWorkflow({ name: "email-workflow", }); workflow .step(fetchUserStep) .then(sendEmailStep, { variables: { // Map specific fields from fetchUser to sendEmail inputs recipientEmail: { step: fetchUserStep, path: "email" }, recipientName: { step: fetchUserStep, path: "name" }, }, }) .commit(); ``` For more details on variable mapping, see the [Data Mapping with Workflow Variables](./variables.mdx) documentation. ### Using the Context Object The context object provides direct access to all step results and their outputs. This approach is more flexible but requires careful handling to maintain type safety. You can access step results directly through the `context.steps` object: ```typescript showLineNumbers filename="src/mastra/workflows/context-access.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const processOrderStep = new LegacyStep({ id: "processOrder", execute: async ({ context }) => { // Access data from a previous step let userData: { name: string; userId: string }; if (context.steps["fetchUser"]?.status === "success") { userData = context.steps.fetchUser.output; } else { throw new Error("User data not found"); } return { orderId: "order123", userId: userData.userId, status: "processing", }; }, }); const workflow = new LegacyWorkflow({ name: "order-workflow", }); workflow.step(fetchUserStep).then(processOrderStep).commit(); ``` ### Workflow-Level Type Safety For comprehensive type safety across your entire workflow, you can define types for all steps and pass them to the Workflow This allows you to get type safety for the context object on conditions, and on step results in the final workflow output. ```typescript showLineNumbers filename="src/mastra/workflows/workflow-typing.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Create steps with typed outputs const fetchUserStep = new LegacyStep({ id: "fetchUser", outputSchema: z.object({ userId: z.string(), name: z.string(), email: z.string(), }), execute: async () => { return { userId: "user123", name: "John Doe", email: "john@example.com", }; }, }); const processOrderStep = new LegacyStep({ id: "processOrder", execute: async ({ context }) => { // TypeScript knows the shape of userData const userData = context.getStepResult(fetchUserStep); return { orderId: "order123", status: "processing", }; }, }); const workflow = new LegacyWorkflow< [typeof fetchUserStep, typeof processOrderStep] >({ name: "typed-workflow", }); workflow .step(fetchUserStep) .then(processOrderStep) .until(async ({ context }) => { // TypeScript knows the shape of userData here const res = context.getStepResult("fetchUser"); return res?.userId === "123"; }, processOrderStep) .commit(); ``` ### Accessing Trigger Data In addition to step results, you can access the original trigger data that started the workflow: ```typescript showLineNumbers filename="src/mastra/workflows/trigger-data.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Define trigger schema const triggerSchema = z.object({ customerId: z.string(), orderItems: z.array(z.string()), }); type TriggerType = z.infer; const processOrderStep = new LegacyStep({ id: "processOrder", execute: async ({ context }) => { // Access trigger data with type safety const triggerData = context.getStepResult("trigger"); return { customerId: triggerData?.customerId, itemCount: triggerData?.orderItems.length || 0, status: "processing", }; }, }); const workflow = new LegacyWorkflow({ name: "order-workflow", triggerSchema, }); workflow.step(processOrderStep).commit(); ``` ### Accessing Resume Data The data injected into the step is available in the `context.inputData` object, and typed based on the `inputSchema` of the step. ```typescript showLineNumbers filename="src/mastra/workflows/resume-data.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const processOrderStep = new LegacyStep({ id: "processOrder", inputSchema: z.object({ orderId: z.string(), }), execute: async ({ context, suspend }) => { const { orderId } = context.inputData; if (!orderId) { await suspend(); return; } return { orderId, status: "processed", }; }, }); const workflow = new LegacyWorkflow({ name: "order-workflow", }); workflow.step(processOrderStep).commit(); const run = workflow.createRun(); const result = await run.start(); const resumedResult = await workflow.resume({ runId: result.runId, stepId: "processOrder", inputData: { orderId: "123", }, }); console.log({ resumedResult }); ``` ### Accessing Workflow Results You can get typed access to the results of a workflow by injecting the step types into the `Workflow` type params: ```typescript showLineNumbers filename="src/mastra/workflows/get-results.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const fetchUserStep = new LegacyStep({ id: "fetchUser", outputSchema: z.object({ userId: z.string(), name: z.string(), email: z.string(), }), execute: async () => { return { userId: "user123", name: "John Doe", email: "john@example.com", }; }, }); const processOrderStep = new LegacyStep({ id: "processOrder", outputSchema: z.object({ orderId: z.string(), status: z.string(), }), execute: async ({ context }) => { const userData = context.getStepResult(fetchUserStep); return { orderId: "order123", status: "processing", }; }, }); const workflow = new LegacyWorkflow< [typeof fetchUserStep, typeof processOrderStep] >({ name: "typed-workflow", }); workflow.step(fetchUserStep).then(processOrderStep).commit(); const run = workflow.createRun(); const result = await run.start(); // The result is a discriminated union of the step results // So it needs to be narrowed down via status checks if (result.results.processOrder.status === "success") { // TypeScript will know the shape of the results const orderId = result.results.processOrder.output.orderId; console.log({ orderId }); } if (result.results.fetchUser.status === "success") { const userId = result.results.fetchUser.output.userId; console.log({ userId }); } ``` ### Best Practices for Data Flow 1. **Use getStepResult with Step References for Type Safety** - Ensures TypeScript can infer the correct types - Catches type errors at compile time 2. \*_Use Variable Mapping for Explicit Dependencies_ - Makes data flow clear and maintainable - Provides good documentation of step dependencies 3. **Define Output Schemas for Steps** - Validates data at runtime - Validates return type of the `execute` function - Improves type inference in TypeScript 4. **Handle Missing Data Gracefully** - Always check if step results exist before accessing properties - Provide fallback values for optional data 5. **Keep Data Transformations Simple** - Transform data in dedicated steps rather than in variable mappings - Makes workflows easier to test and debug ### Comparison of Data Flow Methods | Method | Type Safety | Explicitness | Use Case | | ---------------- | ----------- | ------------ | ------------------------------------------------- | | getStepResult | Highest | High | Complex workflows with strict typing requirements | | Variable Mapping | High | High | When dependencies need to be clear and explicit | | context.steps | Medium | Low | Quick access to step data in simple workflows | By choosing the right data flow method for your use case, you can create workflows that are both type-safe and maintainable. --- title: "Dynamic Workflows (Legacy) | Mastra Docs" description: "Learn how to create dynamic workflows within legacy workflow steps, allowing for flexible workflow creation based on runtime conditions." --- # Dynamic Workflows (Legacy) [EN] Source: https://mastra.ai/en/docs/workflows-legacy/dynamic-workflows This guide demonstrates how to create dynamic workflows within a workflow step. This advanced pattern allows you to create and execute workflows on the fly based on runtime conditions. ## Overview Dynamic workflows are useful when you need to create workflows based on runtime data. ## Implementation The key to creating dynamic workflows is accessing the Mastra instance from within a step's `execute` function and using it to create and run a new workflow. ### Basic Example ```typescript import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const isMastra = (mastra: any): mastra is Mastra => { return mastra && typeof mastra === "object" && mastra instanceof Mastra; }; // Step that creates and runs a dynamic workflow const createDynamicWorkflow = new LegacyStep({ id: "createDynamicWorkflow", outputSchema: z.object({ dynamicWorkflowResult: z.any(), }), execute: async ({ context, mastra }) => { if (!mastra) { throw new Error("Mastra instance not available"); } if (!isMastra(mastra)) { throw new Error("Invalid Mastra instance"); } const inputData = context.triggerData.inputData; // Create a new dynamic workflow const dynamicWorkflow = new LegacyWorkflow({ name: "dynamic-workflow", mastra, // Pass the mastra instance to the new workflow triggerSchema: z.object({ dynamicInput: z.string(), }), }); // Define steps for the dynamic workflow const dynamicStep = new LegacyStep({ id: "dynamicStep", execute: async ({ context }) => { const dynamicInput = context.triggerData.dynamicInput; return { processedValue: `Processed: ${dynamicInput}`, }; }, }); // Build and commit the dynamic workflow dynamicWorkflow.step(dynamicStep).commit(); // Create a run and execute the dynamic workflow const run = dynamicWorkflow.createRun(); const result = await run.start({ triggerData: { dynamicInput: inputData, }, }); let dynamicWorkflowResult; if (result.results["dynamicStep"]?.status === "success") { dynamicWorkflowResult = result.results["dynamicStep"]?.output.processedValue; } else { throw new Error("Dynamic workflow failed"); } // Return the result from the dynamic workflow return { dynamicWorkflowResult, }; }, }); // Main workflow that uses the dynamic workflow creator const mainWorkflow = new LegacyWorkflow({ name: "main-workflow", triggerSchema: z.object({ inputData: z.string(), }), mastra: new Mastra(), }); mainWorkflow.step(createDynamicWorkflow).commit(); // Register the workflow with Mastra export const mastra = new Mastra({ legacy_workflows: { mainWorkflow }, }); const run = mainWorkflow.createRun(); const result = await run.start({ triggerData: { inputData: "test", }, }); ``` ## Advanced Example: Workflow Factory You can create a workflow factory that generates different workflows based on input parameters: ```typescript const isMastra = (mastra: any): mastra is Mastra => { return mastra && typeof mastra === "object" && mastra instanceof Mastra; }; const workflowFactory = new LegacyStep({ id: "workflowFactory", inputSchema: z.object({ workflowType: z.enum(["simple", "complex"]), inputData: z.string(), }), outputSchema: z.object({ result: z.any(), }), execute: async ({ context, mastra }) => { if (!mastra) { throw new Error("Mastra instance not available"); } if (!isMastra(mastra)) { throw new Error("Invalid Mastra instance"); } // Create a new dynamic workflow based on the type const dynamicWorkflow = new LegacyWorkflow({ name: `dynamic-${context.workflowType}-workflow`, mastra, triggerSchema: z.object({ input: z.string(), }), }); if (context.workflowType === "simple") { // Simple workflow with a single step const simpleStep = new Step({ id: "simpleStep", execute: async ({ context }) => { return { result: `Simple processing: ${context.triggerData.input}`, }; }, }); dynamicWorkflow.step(simpleStep).commit(); } else { // Complex workflow with multiple steps const step1 = new LegacyStep({ id: "step1", outputSchema: z.object({ intermediateResult: z.string(), }), execute: async ({ context }) => { return { intermediateResult: `First processing: ${context.triggerData.input}`, }; }, }); const step2 = new LegacyStep({ id: "step2", execute: async ({ context }) => { const intermediate = context.getStepResult(step1).intermediateResult; return { finalResult: `Second processing: ${intermediate}`, }; }, }); dynamicWorkflow.step(step1).then(step2).commit(); } // Execute the dynamic workflow const run = dynamicWorkflow.createRun(); const result = await run.start({ triggerData: { input: context.inputData, }, }); // Return the appropriate result based on workflow type if (context.workflowType === "simple") { return { // @ts-ignore result: result.results["simpleStep"]?.output, }; } else { return { // @ts-ignore result: result.results["step2"]?.output, }; } }, }); ``` ## Important Considerations 1. **Mastra Instance**: The `mastra` parameter in the `execute` function provides access to the Mastra instance, which is essential for creating dynamic workflows. 2. **Error Handling**: Always check if the Mastra instance is available before attempting to create a dynamic workflow. 3. **Resource Management**: Dynamic workflows consume resources, so be mindful of creating too many workflows in a single execution. 4. **Workflow Lifecycle**: Dynamic workflows are not automatically registered with the main Mastra instance. They exist only for the duration of the step execution unless you explicitly register them. 5. **Debugging**: Debugging dynamic workflows can be challenging. Consider adding detailed logging to track their creation and execution. ## Use Cases - **Conditional Workflow Selection**: Choose different workflow patterns based on input data - **Parameterized Workflows**: Create workflows with dynamic configurations - **Workflow Templates**: Use templates to generate specialized workflows - **Multi-tenant Applications**: Create isolated workflows for different tenants ## Conclusion Dynamic workflows provide a powerful way to create flexible, adaptable workflow systems. By leveraging the Mastra instance within step execution, you can create workflows that respond to runtime conditions and requirements. --- title: "Error Handling in Workflows (Legacy) | Mastra Docs" description: "Learn how to handle errors in Mastra legacy workflows using step retries, conditional branching, and monitoring." --- # Error Handling in Workflows (Legacy) [EN] Source: https://mastra.ai/en/docs/workflows-legacy/error-handling Robust error handling is essential for production workflows. Mastra provides several mechanisms to handle errors gracefully, allowing your workflows to recover from failures or gracefully degrade when necessary. ## Overview Error handling in Mastra workflows can be implemented using: 1. **Step Retries** - Automatically retry failed steps 2. **Conditional Branching** - Create alternative paths based on step success or failure 3. **Error Monitoring** - Watch workflows for errors and handle them programmatically 4. **Result Status Checks** - Check the status of previous steps in subsequent steps ## Step Retries Mastra provides a built-in retry mechanism for steps that fail due to transient errors. This is particularly useful for steps that interact with external services or resources that might experience temporary unavailability. ### Basic Retry Configuration You can configure retries at the workflow level or for individual steps: ```typescript import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; // Workflow-level retry configuration const workflow = new LegacyWorkflow({ name: "my-workflow", retryConfig: { attempts: 3, // Number of retry attempts delay: 1000, // Delay between retries in milliseconds }, }); // Step-level retry configuration (overrides workflow-level) const apiStep = new LegacyStep({ id: "callApi", execute: async () => { // API call that might fail }, retryConfig: { attempts: 5, // This step will retry up to 5 times delay: 2000, // With a 2-second delay between retries }, }); ``` For more details about step retries, see the [Step Retries](../../reference/legacyWorkflows/step-retries.mdx) reference. ## Conditional Branching You can create alternative workflow paths based on the success or failure of previous steps using conditional logic: ```typescript // Create a workflow with conditional branching const workflow = new LegacyWorkflow({ name: "error-handling-workflow", }); workflow .step(fetchDataStep) .then(processDataStep, { // Only execute processDataStep if fetchDataStep was successful when: ({ context }) => { return context.steps.fetchDataStep?.status === "success"; }, }) .then(fallbackStep, { // Execute fallbackStep if fetchDataStep failed when: ({ context }) => { return context.steps.fetchDataStep?.status === "failed"; }, }) .commit(); ``` ## Error Monitoring You can monitor workflows for errors using the `watch` method: ```typescript const { start, watch } = workflow.createRun(); watch(async ({ results }) => { // Check for any failed steps const failedSteps = Object.entries(results) .filter(([_, step]) => step.status === "failed") .map(([stepId]) => stepId); if (failedSteps.length > 0) { console.error(`Workflow has failed steps: ${failedSteps.join(", ")}`); // Take remedial action, such as alerting or logging } }); await start(); ``` ## Handling Errors in Steps Within a step's execution function, you can handle errors programmatically: ```typescript const robustStep = new LegacyStep({ id: "robustStep", execute: async ({ context }) => { try { // Attempt the primary operation const result = await someRiskyOperation(); return { success: true, data: result }; } catch (error) { // Log the error console.error("Operation failed:", error); // Return a graceful fallback result instead of throwing return { success: false, error: error.message, fallbackData: "Default value", }; } }, }); ``` ## Checking Previous Step Results You can make decisions based on the results of previous steps: ```typescript const finalStep = new LegacyStep({ id: "finalStep", execute: async ({ context }) => { // Check results of previous steps const step1Success = context.steps.step1?.status === "success"; const step2Success = context.steps.step2?.status === "success"; if (step1Success && step2Success) { // All steps succeeded return { status: "complete", result: "All operations succeeded" }; } else if (step1Success) { // Only step1 succeeded return { status: "partial", result: "Partial completion" }; } else { // Critical failure return { status: "failed", result: "Critical steps failed" }; } }, }); ``` ## Best Practices for Error Handling 1. **Use retries for transient failures**: Configure retry policies for steps that might experience temporary issues. 2. **Provide fallback paths**: Design workflows with alternative paths for when critical steps fail. 3. **Be specific about error scenarios**: Use different handling strategies for different types of errors. 4. **Log errors comprehensively**: Include context information when logging errors to aid in debugging. 5. **Return meaningful data on failure**: When a step fails, return structured data about the failure to help downstream steps make decisions. 6. **Consider idempotency**: Ensure steps can be safely retried without causing duplicate side effects. 7. **Monitor workflow execution**: Use the `watch` method to actively monitor workflow execution and detect errors early. ## Advanced Error Handling For more complex error handling scenarios, consider: - **Implementing circuit breakers**: If a step fails repeatedly, stop retrying and use a fallback strategy - **Adding timeout handling**: Set time limits for steps to prevent workflows from hanging indefinitely - **Creating dedicated error recovery workflows**: For critical workflows, create separate recovery workflows that can be triggered when the main workflow fails ## Related - [Step Retries Reference](../../reference/legacyWorkflows/step-retries.mdx) - [Watch Method Reference](../../reference/legacyWorkflows/watch.mdx) - [Step Conditions](../../reference/legacyWorkflows/step-condition.mdx) - [Control Flow](./control-flow.mdx) # Nested Workflows (Legacy) [EN] Source: https://mastra.ai/en/docs/workflows-legacy/nested-workflows Mastra allows you to use workflows as steps within other workflows, enabling you to create modular and reusable workflow components. This feature helps in organizing complex workflows into smaller, manageable pieces and promotes code reuse. It is also visually easier to understand the flow of a workflow when you can see the nested workflows as steps in the parent workflow. ## Basic Usage You can use a workflow as a step directly in another workflow using the `step()` method: ```typescript import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; // Create a nested workflow const nestedWorkflow = new LegacyWorkflow({ name: "nested-workflow" }) .step(stepA) .then(stepB) .commit(); // Use the nested workflow in a parent workflow const parentWorkflow = new LegacyWorkflow({ name: "parent-workflow" }) .step(nestedWorkflow, { variables: { city: { step: "trigger", path: "myTriggerInput", }, }, }) .then(stepC) .commit(); ``` When a workflow is used as a step: - It is automatically converted to a step using the workflow's name as the step ID - The workflow's results are available in the parent workflow's context - The nested workflow's steps are executed in their defined order ## Accessing Results Results from a nested workflow are available in the parent workflow's context under the nested workflow's name. The results include all step outputs from the nested workflow: ```typescript const { results } = await parentWorkflow.start(); // Access nested workflow results const nestedWorkflowResult = results["nested-workflow"]; if (nestedWorkflowResult.status === "success") { const nestedResults = nestedWorkflowResult.output.results; } ``` ## Control Flow with Nested Workflows Nested workflows support all the control flow features available to regular steps: ### Parallel Execution Multiple nested workflows can be executed in parallel: ```typescript parentWorkflow .step(nestedWorkflowA) .step(nestedWorkflowB) .after([nestedWorkflowA, nestedWorkflowB]) .step(finalStep); ``` Or using `step()` with an array of workflows: ```typescript parentWorkflow.step([nestedWorkflowA, nestedWorkflowB]).then(finalStep); ``` In this case, `then()` will implicitly wait for all the workflows to finish before executing the final step. ### If-Else Branching Nested workflows can be used in if-else branches using the new syntax that accepts both branches as arguments: ```typescript // Create nested workflows for different paths const workflowA = new LegacyWorkflow({ name: "workflow-a" }) .step(stepA1) .then(stepA2) .commit(); const workflowB = new LegacyWorkflow({ name: "workflow-b" }) .step(stepB1) .then(stepB2) .commit(); // Use the new if-else syntax with nested workflows parentWorkflow .step(initialStep) .if( async ({ context }) => { // Your condition here return someCondition; }, workflowA, // if branch workflowB, // else branch ) .then(finalStep) .commit(); ``` The new syntax is more concise and clearer when working with nested workflows. When the condition is: - `true`: The first workflow (if branch) is executed - `false`: The second workflow (else branch) is executed The skipped workflow will have a status of `skipped` in the results: The `.then(finalStep)` call following the if-else block will merge the if and else branches back into a single execution path. ### Looping Nested workflows can use `.until()` and `.while()` loops same as any other step. One interesting new pattern is to pass a workflow directly as the loop-back argument to keep executing that nested workflow until something is true about its results: ```typescript parentWorkflow .step(firstStep) .while( ({ context }) => context.getStepResult("nested-workflow").output.results.someField === "someValue", nestedWorkflow, ) .step(finalStep) .commit(); ``` ## Watching Nested Workflows You can watch the state changes of nested workflows using the `watch` method on the parent workflow. This is useful for monitoring the progress and state transitions of complex workflows: ```typescript const parentWorkflow = new LegacyWorkflow({ name: "parent-workflow" }) .step([nestedWorkflowA, nestedWorkflowB]) .then(finalStep) .commit(); const run = parentWorkflow.createRun(); const unwatch = parentWorkflow.watch((state) => { console.log("Current state:", state.value); // Access nested workflow states in state.context }); await run.start(); unwatch(); // Stop watching when done ``` ## Suspending and Resuming Nested workflows support suspension and resumption, allowing you to pause and continue workflow execution at specific points. You can suspend either the entire nested workflow or specific steps within it: ```typescript // Define a step that may need to suspend const suspendableStep = new LegacyStep({ id: "other", description: "Step that may need to suspend", execute: async ({ context, suspend }) => { if (!wasSuspended) { wasSuspended = true; await suspend(); } return { other: 26 }; }, }); // Create a nested workflow with suspendable steps const nestedWorkflow = new LegacyWorkflow({ name: "nested-workflow-a" }) .step(startStep) .then(suspendableStep) .then(finalStep) .commit(); // Use in parent workflow const parentWorkflow = new LegacyWorkflow({ name: "parent-workflow" }) .step(beginStep) .then(nestedWorkflow) .then(lastStep) .commit(); // Start the workflow const run = parentWorkflow.createRun(); const { runId, results } = await run.start({ triggerData: { startValue: 1 } }); // Check if a specific step in the nested workflow is suspended if (results["nested-workflow-a"].output.results.other.status === "suspended") { // Resume the specific suspended step using dot notation const resumedResults = await run.resume({ stepId: "nested-workflow-a.other", context: { startValue: 1 }, }); // The resumed results will contain the completed nested workflow expect(resumedResults.results["nested-workflow-a"].output.results).toEqual({ start: { output: { newValue: 1 }, status: "success" }, other: { output: { other: 26 }, status: "success" }, final: { output: { finalValue: 27 }, status: "success" }, }); } ``` When resuming a nested workflow: - Use the nested workflow's name as the `stepId` when calling `resume()` to resume the entire workflow - Use dot notation (`nested-workflow.step-name`) to resume a specific step within the nested workflow - The nested workflow will continue from the suspended step with the provided context - You can check the status of specific steps in the nested workflow's results using `results["nested-workflow"].output.results` ## Result Schemas and Mapping Nested workflows can define their result schema and mapping, which helps in type safety and data transformation. This is particularly useful when you want to ensure the nested workflow's output matches a specific structure or when you need to transform the results before they're used in the parent workflow. ```typescript // Create a nested workflow with result schema and mapping const nestedWorkflow = new LegacyWorkflow({ name: "nested-workflow", result: { schema: z.object({ total: z.number(), items: z.array( z.object({ id: z.string(), value: z.number(), }), ), }), mapping: { // Map values from step results using variables syntax total: { step: "step-a", path: "count" }, items: { step: "step-b", path: "items" }, }, }, }) .step(stepA) .then(stepB) .commit(); // Use in parent workflow with type-safe results const parentWorkflow = new LegacyWorkflow({ name: "parent-workflow" }) .step(nestedWorkflow) .then(async ({ context }) => { const result = context.getStepResult("nested-workflow"); // TypeScript knows the structure of result console.log(result.total); // number console.log(result.items); // Array<{ id: string, value: number }> return { success: true }; }) .commit(); ``` ## Best Practices 1. **Modularity**: Use nested workflows to encapsulate related steps and create reusable workflow components. 2. **Naming**: Give nested workflows descriptive names as they will be used as step IDs in the parent workflow. 3. **Error Handling**: Nested workflows propagate their errors to the parent workflow, so handle errors appropriately. 4. **State Management**: Each nested workflow maintains its own state but can access the parent workflow's context. 5. **Suspension**: When using suspension in nested workflows, consider the entire workflow's state and handle resumption appropriately. ## Example Here's a complete example showing various features of nested workflows: ```typescript const workflowA = new LegacyWorkflow({ name: "workflow-a", result: { schema: z.object({ activities: z.string(), }), mapping: { activities: { step: planActivities, path: "activities", }, }, }, }) .step(fetchWeather) .then(planActivities) .commit(); const workflowB = new LegacyWorkflow({ name: "workflow-b", result: { schema: z.object({ activities: z.string(), }), mapping: { activities: { step: planActivities, path: "activities", }, }, }, }) .step(fetchWeather) .then(planActivities) .commit(); const weatherWorkflow = new LegacyWorkflow({ name: "weather-workflow", triggerSchema: z.object({ cityA: z.string().describe("The city to get the weather for"), cityB: z.string().describe("The city to get the weather for"), }), result: { schema: z.object({ activitiesA: z.string(), activitiesB: z.string(), }), mapping: { activitiesA: { step: workflowA, path: "result.activities", }, activitiesB: { step: workflowB, path: "result.activities", }, }, }, }) .step(workflowA, { variables: { city: { step: "trigger", path: "cityA", }, }, }) .step(workflowB, { variables: { city: { step: "trigger", path: "cityB", }, }, }); weatherWorkflow.commit(); ``` In this example: 1. We define schemas for type safety across all workflows 2. Each step has proper input and output schemas 3. The nested workflows have their own trigger schemas and result mappings 4. Data is passed through using variables syntax in the `.step()` calls 5. The main workflow combines data from both nested workflows --- title: "Handling Complex LLM Operations | Workflows (Legacy) | Mastra" description: "Workflows in Mastra help you orchestrate complex sequences of operations with features like branching, parallel execution, resource suspension, and more." --- # Handling Complex LLM Operations with Workflows (Legacy) [EN] Source: https://mastra.ai/en/docs/workflows-legacy/overview Workflows in Mastra help you orchestrate complex sequences of operations with features like branching, parallel execution, resource suspension, and more. ## When to use workflows Most AI applications need more than a single call to a language model. You may want to run multiple steps, conditionally skip certain paths, or even pause execution altogether until you receive user input. Sometimes your agent tool calling is not accurate enough. Mastra's workflow system provides: - A standardized way to define steps and link them together. - Support for both simple (linear) and advanced (branching, parallel) paths. - Debugging and observability features to track each workflow run. ## Example To create a workflow, you define one or more steps, link them, and then commit the workflow before starting it. ### Breaking Down the Workflow (Legacy) Let's examine each part of the workflow creation process: #### 1. Creating the Workflow Here's how you define a workflow in Mastra. The `name` field determines the workflow's API endpoint (`/workflows/$NAME/`), while the `triggerSchema` defines the structure of the workflow's trigger data: ```ts filename="src/mastra/workflow/index.ts" import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; const myWorkflow = new LegacyWorkflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); ``` #### 2. Defining Steps Now, we'll define the workflow's steps. Each step can have its own input and output schemas. Here, `stepOne` doubles an input value, and `stepTwo` increments that result if `stepOne` was successful. (To keep things simple, we aren't making any LLM calls in this example): ```ts filename="src/mastra/workflow/index.ts" const stepOne = new LegacyStep({ id: "stepOne", outputSchema: z.object({ doubledValue: z.number(), }), execute: async ({ context }) => { const doubledValue = context.triggerData.inputValue * 2; return { doubledValue }; }, }); const stepTwo = new LegacyStep({ id: "stepTwo", execute: async ({ context }) => { const doubledValue = context.getStepResult(stepOne)?.doubledValue; if (!doubledValue) { return { incrementedValue: 0 }; } return { incrementedValue: doubledValue + 1, }; }, }); ``` #### 3. Linking Steps Now, let's create the control flow, and "commit" (finalize the workflow). In this case, `stepOne` runs first and is followed by `stepTwo`. ```ts filename="src/mastra/workflow/index.ts" myWorkflow.step(stepOne).then(stepTwo).commit(); ``` ### Register the Workflow Register your workflow with Mastra to enable logging and telemetry: ```ts showLineNumbers filename="src/mastra/index.ts" import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ legacy_workflows: { myWorkflow }, }); ``` The workflow can also have the mastra instance injected into the context in the case where you need to create dynamic workflows: ```ts filename="src/mastra/workflow/index.ts" import { Mastra } from "@mastra/core"; import { LegacyWorkflow } from "@mastra/core/workflows/legacy"; const mastra = new Mastra(); const myWorkflow = new LegacyWorkflow({ name: "my-workflow", mastra, }); ``` ### Executing the Workflow Execute your workflow programmatically or via API: ```ts showLineNumbers filename="src/mastra/run-workflow.ts" copy import { mastra } from "./index"; // Get the workflow const myWorkflow = mastra.legacy_getWorkflow("myWorkflow"); const { runId, start } = myWorkflow.createRun(); // Start the workflow execution await start({ triggerData: { inputValue: 45 } }); ``` Or use the API (requires running `mastra dev`): // Create workflow run ```bash curl --location 'http://localhost:4111/api/workflows/myWorkflow/start-async' \ --header 'Content-Type: application/json' \ --data '{ "inputValue": 45 }' ``` This example shows the essentials: define your workflow, add steps, commit the workflow, then execute it. ## Defining Steps The basic building block of a workflow [is a step](./steps.mdx). Steps are defined using schemas for inputs and outputs, and can fetch prior step results. ## Control Flow Workflows let you define a [control flow](./control-flow.mdx) to chain steps together in with parallel steps, branching paths, and more. ## Workflow Variables When you need to map data between steps or create dynamic data flows, [workflow variables](./variables.mdx) provide a powerful mechanism for passing information from one step to another and accessing nested properties within step outputs. ## Suspend and Resume When you need to pause execution for external data, user input, or asynchronous events, Mastra [supports suspension at any step](./suspend-and-resume.mdx), persisting the state of the workflow so you can resume it later. ## Observability and Debugging Mastra workflows automatically [log the input and output of each step within a workflow run](../../reference/observability/otel-config.mdx), allowing you to send this data to your preferred logging, telemetry, or observability tools. You can: - Track the status of each step (e.g., `success`, `error`, or `suspended`). - Store run-specific metadata for analysis. - Integrate with third-party observability platforms like Datadog or New Relic by forwarding logs. ## More Resources - [Sequential Steps workflow example](../../examples/workflows_legacy/sequential-steps.mdx) - [Parallel Steps workflow example](../../examples/workflows_legacy/parallel-steps.mdx) - [Branching Paths workflow example](../../examples/workflows_legacy/branching-paths.mdx) - [Workflow Variables example](../../examples/workflows_legacy/workflow-variables.mdx) - [Cyclical Dependencies workflow example](../../examples/workflows_legacy/cyclical-dependencies.mdx) - [Suspend and Resume workflow example](../../examples/workflows_legacy/suspend-and-resume.mdx) --- title: "Runtime variables - dependency injection | Workflows (Legacy) | Mastra Docs" description: Learn how to use Mastra's dependency injection system to provide runtime configuration to workflows and steps. --- # Workflow Runtime Variables (Legacy) [EN] Source: https://mastra.ai/en/docs/workflows-legacy/runtime-variables Mastra provides a powerful dependency injection system that enables you to configure your workflows and steps with runtime variables. This feature is essential for creating flexible and reusable workflows that can adapt their behavior based on runtime configuration. ## Overview The dependency injection system allows you to: 1. Pass runtime configuration variables to workflows through a type-safe runtimeContext 2. Access these variables within step execution contexts 3. Modify workflow behavior without changing the underlying code 4. Share configuration across multiple steps within the same workflow ## Basic Usage ```typescript const myWorkflow = mastra.legacy_getWorkflow("myWorkflow"); const { runId, start, resume } = myWorkflow.createRun(); // Define your runtimeContext's type structure type WorkflowRuntimeContext = { multiplier: number; }; const runtimeContext = new RuntimeContext(); runtimeContext.set("multiplier", 5); // Start the workflow execution with runtimeContext await start({ triggerData: { inputValue: 45 }, runtimeContext, }); ``` ## Using with REST API Here's how to dynamically set a multiplier value from an HTTP header: ```typescript filename="src/index.ts" import { Mastra } from "@mastra/core"; import { RuntimeContext } from "@mastra/core/di"; import { workflow as myWorkflow } from "./workflows"; // Define runtimeContext type with clear, descriptive types type WorkflowRuntimeContext = { multiplier: number; }; export const mastra = new Mastra({ legacy_workflows: { myWorkflow, }, server: { middleware: [ async (c, next) => { const multiplier = c.req.header("x-multiplier"); const runtimeContext = c.get("runtimeContext"); // Parse and validate the multiplier value const multiplierValue = parseInt(multiplier || "1", 10); if (isNaN(multiplierValue)) { throw new Error("Invalid multiplier value"); } runtimeContext.set("multiplier", multiplierValue); await next(); // Don't forget to call next() }, ], }, }); ``` ## Creating Steps with Variables Steps can access runtimeContext variables and must conform to the workflow's runtimeContext type: ```typescript import { LegacyStep } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Define step input/output types interface StepInput { inputValue: number; } interface StepOutput { incrementedValue: number; } const stepOne = new LegacyStep({ id: "stepOne", description: "Multiply the input value by the configured multiplier", execute: async ({ context, runtimeContext }) => { try { // Type-safe access to runtimeContext variables const multiplier = runtimeContext.get("multiplier"); if (multiplier === undefined) { throw new Error("Multiplier not configured in runtimeContext"); } // Get and validate input const inputValue = context.getStepResult("trigger")?.inputValue; if (inputValue === undefined) { throw new Error("Input value not provided"); } const result: StepOutput = { incrementedValue: inputValue * multiplier, }; return result; } catch (error) { console.error(`Error in stepOne: ${error.message}`); throw error; } }, }); ``` ## Error Handling When working with runtime variables in workflows, it's important to handle potential errors: 1. **Missing Variables**: Always check if required variables exist in the runtimeContext 2. **Type Mismatches**: Use TypeScript's type system to catch type errors at compile time 3. **Invalid Values**: Validate variable values before using them in your steps ```typescript // Example of defensive programming with runtimeContext variables const multiplier = runtimeContext.get("multiplier"); if (multiplier === undefined) { throw new Error("Multiplier not configured in runtimeContext"); } // Type and value validation if (typeof multiplier !== "number" || multiplier <= 0) { throw new Error(`Invalid multiplier value: ${multiplier}`); } ``` ## Best Practices 1. **Type Safety**: Always define proper types for your runtimeContext and step inputs/outputs 2. **Validation**: Validate all inputs and runtimeContext variables before using them 3. **Error Handling**: Implement proper error handling in your steps 4. **Documentation**: Document the expected runtimeContext variables for each workflow 5. **Default Values**: Provide sensible defaults when possible --- title: "Creating Steps and Adding to Workflows (Legacy) | Mastra Docs" description: "Steps in Mastra workflows provide a structured way to manage operations by defining inputs, outputs, and execution logic." --- # Defining Steps in a Workflow (Legacy) [EN] Source: https://mastra.ai/en/docs/workflows-legacy/steps When you build a workflow, you typically break down operations into smaller tasks that can be linked and reused. Steps provide a structured way to manage these tasks by defining inputs, outputs, and execution logic. The code below shows how to define these steps inline or separately. ## Inline Step Creation You can create steps directly within your workflow using `.step()` and `.then()`. This code shows how to define, link, and execute two steps in sequence. ```typescript showLineNumbers filename="src/mastra/workflows/index.ts" copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; export const myWorkflow = new LegacyWorkflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); myWorkflow .step( new LegacyStep({ id: "stepOne", outputSchema: z.object({ doubledValue: z.number(), }), execute: async ({ context }) => ({ doubledValue: context.triggerData.inputValue * 2, }), }), ) .then( new LegacyStep({ id: "stepTwo", outputSchema: z.object({ incrementedValue: z.number(), }), execute: async ({ context }) => { if (context.steps.stepOne.status !== "success") { return { incrementedValue: 0 }; } return { incrementedValue: context.steps.stepOne.output.doubledValue + 1, }; }, }), ) .commit(); // Register the workflow with Mastra export const mastra = new Mastra({ legacy_workflows: { myWorkflow }, }); ``` ## Creating Steps Separately If you prefer to manage your step logic in separate entities, you can define steps outside and then add them to your workflow. This code shows how to define steps independently and link them afterward. ```typescript showLineNumbers filename="src/mastra/workflows/index.ts" copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Define steps separately const stepOne = new LegacyStep({ id: "stepOne", outputSchema: z.object({ doubledValue: z.number(), }), execute: async ({ context }) => ({ doubledValue: context.triggerData.inputValue * 2, }), }); const stepTwo = new LegacyStep({ id: "stepTwo", outputSchema: z.object({ incrementedValue: z.number(), }), execute: async ({ context }) => { if (context.steps.stepOne.status !== "success") { return { incrementedValue: 0 }; } return { incrementedValue: context.steps.stepOne.output.doubledValue + 1 }; }, }); // Build the workflow const myWorkflow = new LegacyWorkflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); myWorkflow.step(stepOne).then(stepTwo); myWorkflow.commit(); // Register the workflow with Mastra export const mastra = new Mastra({ legacy_workflows: { myWorkflow }, }); ``` --- title: "Suspend & Resume Workflows (Legacy) | Human-in-the-Loop | Mastra Docs" description: "Suspend and resume in Mastra workflows allows you to pause execution while waiting for external input or resources." --- # Suspend and Resume in Workflows (Legacy) [EN] Source: https://mastra.ai/en/docs/workflows-legacy/suspend-and-resume Complex workflows often need to pause execution while waiting for external input or resources. Mastra's suspend and resume features let you pause workflow execution at any step, persist the workflow snapshot to storage, and resume execution from the saved snapshot when ready. This entire process is automatically managed by Mastra. No config needed, or manual step required from the user. Storing the workflow snapshot to storage (LibSQL by default) means that the workflow state is permanently preserved across sessions, deployments, and server restarts. This persistence is crucial for workflows that might remain suspended for minutes, hours, or even days while waiting for external input or resources. ## When to Use Suspend/Resume Common scenarios for suspending workflows include: - Waiting for human approval or input - Pausing until external API resources become available - Collecting additional data needed for later steps - Rate limiting or throttling expensive operations - Handling event-driven processes with external triggers ## Basic Suspend Example Here's a simple workflow that suspends when a value is too low and resumes when given a higher value: ```typescript import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; const stepTwo = new LegacyStep({ id: "stepTwo", outputSchema: z.object({ incrementedValue: z.number(), }), execute: async ({ context, suspend }) => { if (context.steps.stepOne.status !== "success") { return { incrementedValue: 0 }; } const currentValue = context.steps.stepOne.output.doubledValue; if (currentValue < 100) { await suspend(); return { incrementedValue: 0 }; } return { incrementedValue: currentValue + 1 }; }, }); ``` ## Async/Await Based Flow The suspend and resume mechanism in Mastra uses an async/await pattern that makes it intuitive to implement complex workflows with suspension points. The code structure naturally reflects the execution flow. ### How It Works 1. A step's execution function receives a `suspend` function in its parameters 2. When called with `await suspend()`, the workflow pauses at that point 3. The workflow state is persisted 4. Later, the workflow can be resumed by calling `workflow.resume()` with the appropriate parameters 5. Execution continues from the point after the `suspend()` call ### Example with Multiple Suspension Points Here's an example of a workflow with multiple steps that can suspend: ```typescript // Define steps with suspend capability const promptAgentStep = new LegacyStep({ id: "promptAgent", execute: async ({ context, suspend }) => { // Some condition that determines if we need to suspend if (needHumanInput) { // Optionally pass payload data that will be stored with suspended state await suspend({ requestReason: "Need human input for prompt" }); // Code after suspend() will execute when the step is resumed return { modelOutput: context.userInput }; } return { modelOutput: "AI generated output" }; }, outputSchema: z.object({ modelOutput: z.string() }), }); const improveResponseStep = new LegacyStep({ id: "improveResponse", execute: async ({ context, suspend }) => { // Another condition for suspension if (needFurtherRefinement) { await suspend(); return { improvedOutput: context.refinedOutput }; } return { improvedOutput: "Improved output" }; }, outputSchema: z.object({ improvedOutput: z.string() }), }); // Build the workflow const workflow = new LegacyWorkflow({ name: "multi-suspend-workflow", triggerSchema: z.object({ input: z.string() }), }); workflow .step(getUserInput) .then(promptAgentStep) .then(evaluateTone) .then(improveResponseStep) .then(evaluateImproved) .commit(); // Register the workflow with Mastra export const mastra = new Mastra({ legacy_workflows: { workflow }, }); ``` ### Starting and Resuming the Workflow ```typescript // Get the workflow and create a run const wf = mastra.legacy_getWorkflow("multi-suspend-workflow"); const run = wf.createRun(); // Start the workflow const initialResult = await run.start({ triggerData: { input: "initial input" }, }); let promptAgentStepResult = initialResult.activePaths.get("promptAgent"); let promptAgentResumeResult = undefined; // Check if a step is suspended if (promptAgentStepResult?.status === "suspended") { console.log("Workflow suspended at promptAgent step"); // Resume the workflow with new context const resumeResult = await run.resume({ stepId: "promptAgent", context: { userInput: "Human provided input" }, }); promptAgentResumeResult = resumeResult; } const improveResponseStepResult = promptAgentResumeResult?.activePaths.get("improveResponse"); if (improveResponseStepResult?.status === "suspended") { console.log("Workflow suspended at improveResponse step"); // Resume again with different context const finalResult = await run.resume({ stepId: "improveResponse", context: { refinedOutput: "Human refined output" }, }); console.log("Workflow completed:", finalResult?.results); } ``` ## Event-Based Suspension and Resumption In addition to manually suspending steps, Mastra provides event-based suspension through the `afterEvent` method. This allows workflows to automatically suspend and wait for a specific event to occur before continuing. ### Using afterEvent and resumeWithEvent The `afterEvent` method automatically creates a suspension point in your workflow that waits for a specific event to occur. When the event happens, you can use `resumeWithEvent` to continue the workflow with the event data. Here's how it works: 1. Define events in your workflow configuration 2. Use `afterEvent` to create a suspension point waiting for that event 3. When the event occurs, call `resumeWithEvent` with the event name and data ### Example: Event-Based Workflow ```typescript // Define steps const getUserInput = new LegacyStep({ id: "getUserInput", execute: async () => ({ userInput: "initial input" }), outputSchema: z.object({ userInput: z.string() }), }); const processApproval = new LegacyStep({ id: "processApproval", execute: async ({ context }) => { // Access the event data from the context const approvalData = context.inputData?.resumedEvent; return { approved: approvalData?.approved, approvedBy: approvalData?.approverName, }; }, outputSchema: z.object({ approved: z.boolean(), approvedBy: z.string(), }), }); // Create workflow with event definition const approvalWorkflow = new LegacyWorkflow({ name: "approval-workflow", triggerSchema: z.object({ requestId: z.string() }), events: { approvalReceived: { schema: z.object({ approved: z.boolean(), approverName: z.string(), }), }, }, }); // Build workflow with event-based suspension approvalWorkflow .step(getUserInput) .afterEvent("approvalReceived") // Workflow will automatically suspend here .step(processApproval) // This step runs after the event is received .commit(); ``` ### Running an Event-Based Workflow ```typescript // Get the workflow const workflow = mastra.legacy_getWorkflow("approval-workflow"); const run = workflow.createRun(); // Start the workflow const initialResult = await run.start({ triggerData: { requestId: "request-123" }, }); console.log("Workflow started, waiting for approval event"); console.log(initialResult.results); // Output will show the workflow is suspended at the event step: // { // getUserInput: { status: 'success', output: { userInput: 'initial input' } }, // __approvalReceived_event: { status: 'suspended' } // } // Later, when the approval event occurs: const resumeResult = await run.resumeWithEvent("approvalReceived", { approved: true, approverName: "Jane Doe", }); console.log("Workflow resumed with event data:", resumeResult.results); // Output will show the completed workflow: // { // getUserInput: { status: 'success', output: { userInput: 'initial input' } }, // __approvalReceived_event: { status: 'success', output: { executed: true, resumedEvent: { approved: true, approverName: 'Jane Doe' } } }, // processApproval: { status: 'success', output: { approved: true, approvedBy: 'Jane Doe' } } // } ``` ### Key Points About Event-Based Workflows - The `suspend()` function can optionally take a payload object that will be stored with the suspended state - Code after the `await suspend()` call will not execute until the step is resumed - When a step is suspended, its status becomes `'suspended'` in the workflow results - When resumed, the step's status changes from `'suspended'` to `'success'` once completed - The `resume()` method requires the `stepId` to identify which suspended step to resume - You can provide new context data when resuming that will be merged with existing step results - Events must be defined in the workflow configuration with a schema - The `afterEvent` method creates a special suspended step that waits for the event - The event step is automatically named `__eventName_event` (e.g., `__approvalReceived_event`) - Use `resumeWithEvent` to provide event data and continue the workflow - Event data is validated against the schema defined for that event - The event data is available in the context as `inputData.resumedEvent` ## Storage for Suspend and Resume When a workflow is suspended using `await suspend()`, Mastra automatically persists the entire workflow state to storage. This is essential for workflows that might remain suspended for extended periods, as it ensures the state is preserved across application restarts or server instances. ### Default Storage: LibSQL By default, Mastra uses LibSQL as its storage engine: ```typescript import { Mastra } from "@mastra/core/mastra"; import { LibSQLStore } from "@mastra/libsql"; const mastra = new Mastra({ storage: new LibSQLStore({ url: "file:./storage.db", // Local file-based database for development // For production, use a persistent URL: // url: process.env.DATABASE_URL, // authToken: process.env.DATABASE_AUTH_TOKEN, // Optional for authenticated connections }), }); ``` The LibSQL storage can be configured in different modes: - In-memory database (testing): `:memory:` - File-based database (development): `file:storage.db` - Remote database (production): URLs like `libsql://your-database.turso.io` ### Alternative Storage Options #### Upstash (Redis-Compatible) For serverless applications or environments where Redis is preferred: ```bash copy npm install @mastra/upstash@latest ``` ```typescript import { Mastra } from "@mastra/core/mastra"; import { UpstashStore } from "@mastra/upstash"; const mastra = new Mastra({ storage: new UpstashStore({ url: process.env.UPSTASH_URL, token: process.env.UPSTASH_TOKEN, }), }); ``` ### Storage Considerations - All storage options support suspend and resume functionality identically - The workflow state is automatically serialized and saved when suspended - No additional configuration is needed for suspend/resume to work with storage - Choose your storage option based on your infrastructure, scaling needs, and existing technology stack ## Watching and Resuming To handle suspended workflows, use the `watch` method to monitor workflow status per run and `resume` to continue execution: ```typescript import { mastra } from "./index"; // Get the workflow const myWorkflow = mastra.legacy_getWorkflow("myWorkflow"); const { start, watch, resume } = myWorkflow.createRun(); // Start watching the workflow before executing it watch(async ({ activePaths }) => { const isStepTwoSuspended = activePaths.get("stepTwo")?.status === "suspended"; if (isStepTwoSuspended) { console.log("Workflow suspended, resuming with new value"); // Resume the workflow with new context await resume({ stepId: "stepTwo", context: { secondValue: 100 }, }); } }); // Start the workflow execution await start({ triggerData: { inputValue: 45 } }); ``` ### Watching and Resuming Event-Based Workflows You can use the same watching pattern with event-based workflows: ```typescript const { start, watch, resumeWithEvent } = workflow.createRun(); // Watch for suspended event steps watch(async ({ activePaths }) => { const isApprovalReceivedSuspended = activePaths.get("__approvalReceived_event")?.status === "suspended"; if (isApprovalReceivedSuspended) { console.log("Workflow waiting for approval event"); // In a real scenario, you would wait for the actual event to occur // For example, this could be triggered by a webhook or user interaction setTimeout(async () => { await resumeWithEvent("approvalReceived", { approved: true, approverName: "Auto Approver", }); }, 5000); // Simulate event after 5 seconds } }); // Start the workflow await start({ triggerData: { requestId: "auto-123" } }); ``` ## Further Reading For a deeper understanding of how suspend and resume works under the hood: - [Understanding Snapshots in Mastra Workflows](../../reference/legacyWorkflows/snapshots.mdx) - Learn about the snapshot mechanism that powers suspend and resume functionality - [Step Configuration Guide](./steps.mdx) - Learn more about configuring steps in your workflows - [Control Flow Guide](./control-flow.mdx) - Advanced workflow control patterns - [Event-Driven Workflows](../../reference/legacyWorkflows/events.mdx) - Detailed reference for event-based workflows ## Related Resources - See the [Suspend and Resume Example](../../examples/workflows_legacy/suspend-and-resume.mdx) for a complete working example - Check the [Step Class Reference](../../reference/legacyWorkflows/step-class.mdx) for suspend/resume API details - Review [Workflow Observability](../../reference/observability/otel-config.mdx) for monitoring suspended workflows --- title: "Data Mapping with Workflow (Legacy) Variables | Mastra Docs" description: "Learn how to use workflow variables to map data between steps and create dynamic data flows in your Mastra workflows." --- # Data Mapping with Workflow Variables [EN] Source: https://mastra.ai/en/docs/workflows-legacy/variables Workflow variables in Mastra provide a powerful mechanism for mapping data between steps, allowing you to create dynamic data flows and pass information from one step to another. ## Understanding Workflow Variables In Mastra workflows, variables serve as a way to: - Map data from trigger inputs to step inputs - Pass outputs from one step to inputs of another step - Access nested properties within step outputs - Create more flexible and reusable workflow steps ## Using Variables for Data Mapping ### Basic Variable Mapping You can map data between steps using the `variables` property when adding a step to your workflow: ```typescript showLineNumbers filename="src/mastra/workflows/index.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; const workflow = new LegacyWorkflow({ name: "data-mapping-workflow", triggerSchema: z.object({ inputData: z.string(), }), }); workflow .step(step1, { variables: { // Map trigger data to step input inputData: { step: "trigger", path: "inputData" }, }, }) .then(step2, { variables: { // Map output from step1 to input for step2 previousValue: { step: step1, path: "outputField" }, }, }) .commit(); // Register the workflow with Mastra export const mastra = new Mastra({ legacy_workflows: { workflow }, }); ``` ### Accessing Nested Properties You can access nested properties using dot notation in the `path` field: ```typescript showLineNumbers filename="src/mastra/workflows/index.ts" copy workflow .step(step1) .then(step2, { variables: { // Access a nested property from step1's output nestedValue: { step: step1, path: "nested.deeply.value" }, }, }) .commit(); ``` ### Mapping Entire Objects You can map an entire object by using `.` as the path: ```typescript showLineNumbers filename="src/mastra/workflows/index.ts" copy workflow .step(step1, { variables: { // Map the entire trigger data object triggerData: { step: "trigger", path: "." }, }, }) .commit(); ``` ### Variables in Loops Variables can also be passed to `while` and `until` loops. This is useful for passing data between iterations or from outside steps: ```typescript showLineNumbers filename="src/mastra/workflows/loop-variables.ts" copy // Step that increments a counter const incrementStep = new LegacyStep({ id: "increment", inputSchema: z.object({ // Previous value from last iteration prevValue: z.number().optional(), }), outputSchema: z.object({ // Updated counter value updatedCounter: z.number(), }), execute: async ({ context }) => { const { prevValue = 0 } = context.inputData; return { updatedCounter: prevValue + 1 }; }, }); const workflow = new LegacyWorkflow({ name: "counter", }); workflow.step(incrementStep).while( async ({ context }) => { // Continue while counter is less than 10 const result = context.getStepResult(incrementStep); return (result?.updatedCounter ?? 0) < 10; }, incrementStep, { // Pass previous value to next iteration prevValue: { step: incrementStep, path: "updatedCounter", }, }, ); ``` ## Variable Resolution When a workflow executes, Mastra resolves variables at runtime by: 1. Identifying the source step specified in the `step` property 2. Retrieving the output from that step 3. Navigating to the specified property using the `path` 4. Injecting the resolved value into the target step's context as the `inputData` property ## Examples ### Mapping from Trigger Data This example shows how to map data from the workflow trigger to a step: ```typescript showLineNumbers filename="src/mastra/workflows/trigger-mapping.ts" copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Define a step that needs user input const processUserInput = new LegacyStep({ id: "processUserInput", execute: async ({ context }) => { // The inputData will be available in context because of the variable mapping const { inputData } = context.inputData; return { processedData: `Processed: ${inputData}`, }; }, }); // Create the workflow const workflow = new LegacyWorkflow({ name: "trigger-mapping", triggerSchema: z.object({ inputData: z.string(), }), }); // Map the trigger data to the step workflow .step(processUserInput, { variables: { inputData: { step: "trigger", path: "inputData" }, }, }) .commit(); // Register the workflow with Mastra export const mastra = new Mastra({ legacy_workflows: { workflow }, }); ``` ### Mapping Between Steps This example demonstrates mapping data from one step to another: ```typescript showLineNumbers filename="src/mastra/workflows/step-mapping.ts" copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Step 1: Generate data const generateData = new LegacyStep({ id: "generateData", outputSchema: z.object({ nested: z.object({ value: z.string(), }), }), execute: async () => { return { nested: { value: "step1-data", }, }; }, }); // Step 2: Process the data from step 1 const processData = new LegacyStep({ id: "processData", inputSchema: z.object({ previousValue: z.string(), }), execute: async ({ context }) => { // previousValue will be available because of the variable mapping const { previousValue } = context.inputData; return { result: `Processed: ${previousValue}`, }; }, }); // Create the workflow const workflow = new LegacyWorkflow({ name: "step-mapping", }); // Map data from step1 to step2 workflow .step(generateData) .then(processData, { variables: { // Map the nested.value property from generateData's output previousValue: { step: generateData, path: "nested.value" }, }, }) .commit(); // Register the workflow with Mastra export const mastra = new Mastra({ legacy_workflows: { workflow }, }); ``` ## Type Safety Mastra provides type safety for variable mappings when using TypeScript: ```typescript showLineNumbers filename="src/mastra/workflows/type-safe.ts" copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Define schemas for better type safety const triggerSchema = z.object({ inputValue: z.string(), }); type TriggerType = z.infer; // Step with typed context const step1 = new LegacyStep({ id: "step1", outputSchema: z.object({ nested: z.object({ value: z.string(), }), }), execute: async ({ context }) => { // TypeScript knows the shape of triggerData const triggerData = context.getStepResult("trigger"); return { nested: { value: `processed-${triggerData?.inputValue}`, }, }; }, }); // Create the workflow with the schema const workflow = new LegacyWorkflow({ name: "type-safe-workflow", triggerSchema, }); workflow.step(step1).commit(); // Register the workflow with Mastra export const mastra = new Mastra({ legacy_workflows: { workflow }, }); ``` ## Best Practices 1. **Validate Inputs and Outputs**: Use `inputSchema` and `outputSchema` to ensure data consistency. 2. **Keep Mappings Simple**: Avoid overly complex nested paths when possible. 3. **Consider Default Values**: Handle cases where mapped data might be undefined. ## Comparison with Direct Context Access While you can access previous step results directly via `context.steps`, using variable mappings offers several advantages: | Feature | Variable Mapping | Direct Context Access | | ----------- | ------------------------------------------- | ------------------------------- | | Clarity | Explicit data dependencies | Implicit dependencies | | Reusability | Steps can be reused with different mappings | Steps are tightly coupled | | Type Safety | Better TypeScript integration | Requires manual type assertions | --- title: "Example: Adding Voice Capabilities | Agents | Mastra" description: "Example of adding voice capabilities to Mastra agents, enabling them to speak and listen using different voice providers." --- import { GithubLink } from "@/components/github-link"; # Giving your Agent a Voice [EN] Source: https://mastra.ai/en/examples/agents/adding-voice-capabilities This example demonstrates how to add voice capabilities to Mastra agents, enabling them to speak and listen using different voice providers. We'll create two agents with different voice configurations and show how they can interact using speech. The example showcases: 1. Using CompositeVoice to combine different providers for speaking and listening 2. Using a single provider for both capabilities 3. Basic voice interactions between agents First, let's import the required dependencies and set up our agents: ```ts showLineNumbers copy // Import required dependencies import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { CompositeVoice } from "@mastra/core/voice"; import { OpenAIVoice } from "@mastra/voice-openai"; import { createReadStream, createWriteStream } from "fs"; import { PlayAIVoice } from "@mastra/voice-playai"; import path from "path"; // Initialize Agent 1 with both listening and speaking capabilities const agent1 = new Agent({ name: "Agent1", instructions: `You are an agent with both STT and TTS capabilities.`, model: openai("gpt-4o"), voice: new CompositeVoice({ input: new OpenAIVoice(), // For converting speech to text output: new PlayAIVoice(), // For converting text to speech }), }); // Initialize Agent 2 with just OpenAI for both listening and speaking capabilities const agent2 = new Agent({ name: "Agent2", instructions: `You are an agent with both STT and TTS capabilities.`, model: openai("gpt-4o"), voice: new OpenAIVoice(), }); ``` In this setup: - Agent1 uses a CompositeVoice that combines OpenAI for speech-to-text and PlayAI for text-to-speech - Agent2 uses OpenAI's voice capabilities for both functions Now let's demonstrate a basic interaction between the agents: ```ts showLineNumbers copy // Step 1: Agent 1 speaks a question and saves it to a file const audio1 = await agent1.voice.speak( "What is the meaning of life in one sentence?", ); await saveAudioToFile(audio1, "agent1-question.mp3"); // Step 2: Agent 2 listens to Agent 1's question const audioFilePath = path.join(process.cwd(), "agent1-question.mp3"); const audioStream = createReadStream(audioFilePath); const audio2 = await agent2.voice.listen(audioStream); const text = await convertToText(audio2); // Step 3: Agent 2 generates and speaks a response const agent2Response = await agent2.generate(text); const agent2ResponseAudio = await agent2.voice.speak(agent2Response.text); await saveAudioToFile(agent2ResponseAudio, "agent2-response.mp3"); ``` Here's what's happening in the interaction: 1. Agent1 converts text to speech using PlayAI and saves it to a file (we save the audio so you can hear the interaction) 2. Agent2 listens to the audio file using OpenAI's speech-to-text 3. Agent2 generates a response and converts it to speech The example includes helper functions for handling audio files: ```ts showLineNumbers copy /** * Saves an audio stream to a file */ async function saveAudioToFile( audio: NodeJS.ReadableStream, filename: string, ): Promise { const filePath = path.join(process.cwd(), filename); const writer = createWriteStream(filePath); audio.pipe(writer); return new Promise((resolve, reject) => { writer.on("finish", resolve); writer.on("error", reject); }); } /** * Converts either a string or a readable stream to text */ async function convertToText( input: string | NodeJS.ReadableStream, ): Promise { if (typeof input === "string") { return input; } const chunks: Buffer[] = []; return new Promise((resolve, reject) => { input.on("data", (chunk) => chunks.push(Buffer.from(chunk))); input.on("error", (err) => reject(err)); input.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8"))); }); } ``` ## Key Points 1. The `voice` property in the Agent configuration accepts any implementation of MastraVoice 2. CompositeVoice allows using different providers for speaking and listening 3. Audio can be handled as streams, making it efficient for real-time processing 4. Voice capabilities can be combined with the agent's natural language processing




--- title: "Example: Categorizing Birds | Agents | Mastra Docs" description: Example of using a Mastra AI Agent to determine if an image from Unsplash depicts a bird. --- import { GithubLink } from "@/components/github-link"; # Example: Categorizing Birds with an AI Agent [EN] Source: https://mastra.ai/en/examples/agents/bird-checker We will get a random image from [Unsplash](https://unsplash.com/) that matches a selected query and uses a [Mastra AI Agent](/docs/agents/overview.md) to determine if it is a bird or not. ```ts showLineNumbers copy import { anthropic } from "@ai-sdk/anthropic"; import { Agent } from "@mastra/core/agent"; import { z } from "zod"; export type Image = { alt_description: string; urls: { regular: string; raw: string; }; user: { first_name: string; links: { html: string; }; }; }; export type ImageResponse = | { ok: true; data: T; } | { ok: false; error: K; }; const getRandomImage = async ({ query, }: { query: string; }): Promise> => { const page = Math.floor(Math.random() * 20); const order_by = Math.random() < 0.5 ? "relevant" : "latest"; try { const res = await fetch( `https://api.unsplash.com/search/photos?query=${query}&page=${page}&order_by=${order_by}`, { method: "GET", headers: { Authorization: `Client-ID ${process.env.UNSPLASH_ACCESS_KEY}`, "Accept-Version": "v1", }, cache: "no-store", }, ); if (!res.ok) { return { ok: false, error: "Failed to fetch image", }; } const data = (await res.json()) as { results: Array; }; const randomNo = Math.floor(Math.random() * data.results.length); return { ok: true, data: data.results[randomNo] as Image, }; } catch (err) { return { ok: false, error: "Error fetching image", }; } }; const instructions = ` You can view an image and figure out if it is a bird or not. You can also figure out the species of the bird and where the picture was taken. `; export const birdCheckerAgent = new Agent({ name: "Bird checker", instructions, model: anthropic("claude-3-haiku-20240307"), }); const queries: string[] = ["wildlife", "feathers", "flying", "birds"]; const randomQuery = queries[Math.floor(Math.random() * queries.length)]; // Get the image url from Unsplash with random type const imageResponse = await getRandomImage({ query: randomQuery }); if (!imageResponse.ok) { console.log("Error fetching image", imageResponse.error); process.exit(1); } console.log("Image URL: ", imageResponse.data.urls.regular); const response = await birdCheckerAgent.generate( [ { role: "user", content: [ { type: "image", image: new URL(imageResponse.data.urls.regular), }, { type: "text", text: "view this image and let me know if it's a bird or not, and the scientific name of the bird without any explanation. Also summarize the location for this picture in one or two short sentences understandable by a high school student", }, ], }, ], { output: z.object({ bird: z.boolean(), species: z.string(), location: z.string(), }), }, ); console.log(response.object); ```




--- title: "Example: Deploying an MCPServer | Agents | Mastra Docs" description: Example of setting up, building, and deploying a Mastra MCPServer using the stdio transport and publishing it to NPM. --- import { GithubLink } from "@/components/github-link"; # Example: Deploying an MCPServer [EN] Source: https://mastra.ai/en/examples/agents/deploying-mcp-server This example guides you through setting up a basic Mastra MCPServer using the stdio transport, building it, and preparing it for deployment, such as publishing to NPM. ## Install Dependencies Install the necessary packages: ```bash pnpm add @mastra/mcp @mastra/core tsup ``` ## Set up MCP Server 1. Create a file for your stdio server, for example, `/src/mastra/stdio.ts`. 2. Add the following code to the file. Remember to import your actual Mastra tools and name the server appropriately. ```typescript filename="src/mastra/stdio.ts" copy #!/usr/bin/env node import { MCPServer } from "@mastra/mcp"; import { weatherTool } from "./tools"; const server = new MCPServer({ name: "my-mcp-server", version: "1.0.0", tools: { weatherTool }, }); server.startStdio().catch((error) => { console.error("Error running MCP server:", error); process.exit(1); }); ``` 3. Update your `package.json` to include the `bin` entry pointing to your built server file and a script to build the server. ```json filename="package.json" copy { "bin": "dist/stdio.js", "scripts": { "build:mcp": "tsup src/mastra/stdio.ts --format esm --no-splitting --dts && chmod +x dist/stdio.js" } } ``` 4. Run the build command: ```bash pnpm run build:mcp ``` This will compile your server code and make the output file executable. ## Deploying to NPM To make your MCP server available for others (or yourself) to use via `npx` or as a dependency, you can publish it to NPM. 1. Ensure you have an NPM account and are logged in (`npm login`). 2. Make sure your package name in `package.json` is unique and available. 3. Run the publish command from your project root after building: ```bash npm publish --access public ``` For more details on publishing packages, refer to the [NPM documentation](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages). ## Use the Deployed MCP Server Once published, your MCP server can be used by an `MCPClient` by specifying the command to run your package. You can also use any other MCP client like Claude desktop, Cursor, or Windsurf. ```typescript import { MCPClient } from "@mastra/mcp"; const mcp = new MCPClient({ servers: { // Give this MCP server instance a name yourServerName: { command: "npx", args: ["-y", "@your-org-name/your-package-name@latest"], // Replace with your package name }, }, }); // You can then get tools or toolsets from this configuration to use in your agent const tools = await mcp.getTools(); const toolsets = await mcp.getToolsets(); ``` Note: If you published without an organization scope, the `args` might just be `["-y", "your-package-name@latest"]`.




--- title: Dynamic Agents Example | Agents | Mastra Docs description: Learn how to create and configure dynamic agents using runtime context in Mastra. --- # Dynamic Agents Example [EN] Source: https://mastra.ai/en/examples/agents/dynamic-agents First, let's define our runtime context type: ```typescript import { Agent, RuntimeContext } from "@mastra/core"; import { z } from "zod"; type SupportRuntimeContext = { "user-tier": "free" | "pro" | "enterprise"; language: "en" | "es" | "fr"; "user-id": string; }; ``` Next, let's create our dynamic support agent with its configuration: ```typescript const supportAgent = new Agent({ name: "Dynamic Support Agent", instructions: async ({ runtimeContext }) => { const userTier = runtimeContext.get("user-tier"); const language = runtimeContext.get("language"); return `You are a customer support agent for our SaaS platform. The current user is on the ${userTier} tier and prefers ${language} language. For ${userTier} tier users: ${userTier === "free" ? "- Provide basic support and documentation links" : ""} ${userTier === "pro" ? "- Offer detailed technical support and best practices" : ""} ${userTier === "enterprise" ? "- Provide priority support with custom solutions" : ""} Always respond in ${language} language.`; }, model: ({ runtimeContext }) => { const userTier = runtimeContext.get("user-tier"); return userTier === "enterprise" ? openai("gpt-4") : openai("gpt-3.5-turbo"); }, tools: ({ runtimeContext }) => { const userTier = runtimeContext.get("user-tier"); const baseTools = [knowledgeBase, ticketSystem]; if (userTier === "pro" || userTier === "enterprise") { baseTools.push(advancedAnalytics); } if (userTier === "enterprise") { baseTools.push(customIntegration); } return baseTools; }, }); ``` RuntimeContext can be passed from the client/server directly to your agent generate and stream calls ```typescript async function handleSupportRequest(userId: string, message: string) { const runtimeContext = new RuntimeContext(); runtimeContext.set("user-id", userId); runtimeContext.set("user-tier", await getUserTier(userId)); runtimeContext.set("language", await getUserLanguage(userId)); const response = await supportAgent.generate(message, { runtimeContext, }); return response.text; } ``` RuntimeContext can also be set from the server middleware layer ```typescript import { Mastra } from "@mastra/core"; import { registerApiRoute } from "@mastra/core/server"; export const mastra = new Mastra({ agents: { support: supportAgent, }, server: { middleware: [ async (c, next) => { const userId = c.req.header("X-User-ID"); const runtimeContext = c.get("runtimeContext"); // Set user tier based on subscription const userTier = await getUserTier(userId); runtimeContext.set("user-tier", userTier); // Set language based on user preferences const language = await getUserLanguage(userId); runtimeContext.set("language", language); // Set user ID runtimeContext.set("user-id", userId); await next(); }, ], apiRoutes: [ registerApiRoute("/support", { method: "POST", handler: async (c) => { const { userId, message } = await c.req.json(); try { const response = await handleSupportRequest(userId, message); return c.json({ response }); } catch (error) { return c.json({ error: "Failed to process support request" }, 500); } }, }), ], }, }); ``` ## Usage Example This example shows how a single agent can handle different types of users and scenarios by leveraging runtime context, making it more flexible and maintainable than creating separate agents for each use case. --- title: "Example: Hierarchical Multi-Agent System | Agents | Mastra" description: Example of creating a hierarchical multi-agent system using Mastra, where agents interact through tool functions. --- import { GithubLink } from "@/components/github-link"; # Hierarchical Multi-Agent System [EN] Source: https://mastra.ai/en/examples/agents/hierarchical-multi-agent This example demonstrates how to create a hierarchical multi-agent system where agents interact through tool functions, with one agent coordinating the work of others. The system consists of three agents: 1. A Publisher agent (supervisor) that orchestrates the process 2. A Copywriter agent that writes the initial content 3. An Editor agent that refines the content First, define the Copywriter agent and its tool: ```ts showLineNumbers copy import { openai } from "@ai-sdk/openai"; import { anthropic } from "@ai-sdk/anthropic"; const copywriterAgent = new Agent({ name: "Copywriter", instructions: "You are a copywriter agent that writes blog post copy.", model: anthropic("claude-3-5-sonnet-20241022"), }); const copywriterTool = createTool({ id: "copywriter-agent", description: "Calls the copywriter agent to write blog post copy.", inputSchema: z.object({ topic: z.string().describe("Blog post topic"), }), outputSchema: z.object({ copy: z.string().describe("Blog post copy"), }), execute: async ({ context }) => { const result = await copywriterAgent.generate( `Create a blog post about ${context.topic}`, ); return { copy: result.text }; }, }); ``` Next, define the Editor agent and its tool: ```ts showLineNumbers copy const editorAgent = new Agent({ name: "Editor", instructions: "You are an editor agent that edits blog post copy.", model: openai("gpt-4o-mini"), }); const editorTool = createTool({ id: "editor-agent", description: "Calls the editor agent to edit blog post copy.", inputSchema: z.object({ copy: z.string().describe("Blog post copy"), }), outputSchema: z.object({ copy: z.string().describe("Edited blog post copy"), }), execute: async ({ context }) => { const result = await editorAgent.generate( `Edit the following blog post only returning the edited copy: ${context.copy}`, ); return { copy: result.text }; }, }); ``` Finally, create the Publisher agent that coordinates the others: ```ts showLineNumbers copy const publisherAgent = new Agent({ name: "publisherAgent", instructions: "You are a publisher agent that first calls the copywriter agent to write blog post copy about a specific topic and then calls the editor agent to edit the copy. Just return the final edited copy.", model: anthropic("claude-3-5-sonnet-20241022"), tools: { copywriterTool, editorTool }, }); const mastra = new Mastra({ agents: { publisherAgent }, }); ``` To use the entire system: ```ts showLineNumbers copy async function main() { const agent = mastra.getAgent("publisherAgent"); const result = await agent.generate( "Write a blog post about React JavaScript frameworks. Only return the final edited copy.", ); console.log(result.text); } main(); ```




--- title: "Example: Multi-Agent Workflow | Agents | Mastra Docs" description: Example of creating an agentic workflow in Mastra, where work product is passed between multiple agents. --- import { GithubLink } from "@/components/github-link"; # Multi-Agent Workflow [EN] Source: https://mastra.ai/en/examples/agents/multi-agent-workflow This example demonstrates how to create an agentic workflow with work product being passed between multiple agents with a worker agent and a supervisor agent. In this example, we create a sequential workflow that calls two agents in order: 1. A Copywriter agent that writes the initial blog post 2. An Editor agent that refines the content First, import the required dependencies: ```typescript import { openai } from "@ai-sdk/openai"; import { anthropic } from "@ai-sdk/anthropic"; import { Agent } from "@mastra/core/agent"; import { createStep, createWorkflow } from "@mastra/core/workflows"; import { z } from "zod"; ``` Create the copywriter agent that will generate the initial blog post: ```typescript const copywriterAgent = new Agent({ name: "Copywriter", instructions: "You are a copywriter agent that writes blog post copy.", model: anthropic("claude-3-5-sonnet-20241022"), }); ``` Define the copywriter step that executes the agent and handles the response: ```typescript const copywriterStep = createStep({ id: "copywriterStep", inputSchema: z.object({ topic: z.string(), }), outputSchema: z.object({ copy: z.string(), }), execute: async ({ inputData }) => { if (!inputData?.topic) { throw new Error("Topic not found in trigger data"); } const result = await copywriterAgent.generate( `Create a blog post about ${inputData.topic}`, ); console.log("copywriter result", result.text); return { copy: result.text, }; }, }); ``` Set up the editor agent to refine the copywriter's content: ```typescript const editorAgent = new Agent({ name: "Editor", instructions: "You are an editor agent that edits blog post copy.", model: openai("gpt-4o-mini"), }); ``` Create the editor step that processes the copywriter's output: ```typescript const editorStep = createStep({ id: "editorStep", inputSchema: z.object({ copy: z.string(), }), outputSchema: z.object({ finalCopy: z.string(), }), execute: async ({ inputData }) => { const copy = inputData?.copy; const result = await editorAgent.generate( `Edit the following blog post only returning the edited copy: ${copy}`, ); console.log("editor result", result.text); return { finalCopy: result.text, }; }, }); ``` Configure the workflow and execute the steps: ```typescript const myWorkflow = createWorkflow({ id: "my-workflow", inputSchema: z.object({ topic: z.string(), }), outputSchema: z.object({ finalCopy: z.string(), }), }); // Run steps sequentially. myWorkflow.then(copywriterStep).then(editorStep).commit(); const run = myWorkflow.createRun(); const res = await run.start({ inputData: { topic: "React JavaScript frameworks" }, }); console.log("Response: ", res); ```




--- title: "Example: Agents with a System Prompt | Agents | Mastra Docs" description: Example of creating an AI agent in Mastra with a system prompt to define its personality and capabilities. --- import { GithubLink } from "@/components/github-link"; # Giving an Agent a System Prompt [EN] Source: https://mastra.ai/en/examples/agents/system-prompt When building AI agents, you often need to give them specific instructions and capabilities to handle specialized tasks effectively. System prompts allow you to define an agent's personality, knowledge domain, and behavioral guidelines. This example shows how to create an AI agent with custom instructions and integrate it with a dedicated tool for retrieving verified information. ```ts showLineNumbers copy import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { createTool } from "@mastra/core/tools"; import { z } from "zod"; const instructions = `You are a helpful cat expert assistant. When discussing cats, you should always include an interesting cat fact. Your main responsibilities: 1. Answer questions about cats 2. Use the catFact tool to provide verified cat facts 3. Incorporate the cat facts naturally into your responses Always use the catFact tool at least once in your responses to ensure accuracy.`; const getCatFact = async () => { const { fact } = (await fetch("https://catfact.ninja/fact").then((res) => res.json(), )) as { fact: string; }; return fact; }; const catFact = createTool({ id: "Get cat facts", inputSchema: z.object({}), description: "Fetches cat facts", execute: async () => { console.log("using tool to fetch cat fact"); return { catFact: await getCatFact(), }; }, }); const catOne = new Agent({ name: "cat-one", instructions: instructions, model: openai("gpt-4o-mini"), tools: { catFact, }, }); const result = await catOne.generate("Tell me a cat fact"); console.log(result.text); ```




--- title: "Example: Giving an Agent a Tool | Agents | Mastra Docs" description: Example of creating an AI agent in Mastra that uses a dedicated tool to provide weather information. --- import { GithubLink } from "@/components/github-link"; # Example: Giving an Agent a Tool [EN] Source: https://mastra.ai/en/examples/agents/using-a-tool When building AI agents, you often need to integrate external data sources or functionality to enhance their capabilities. This example shows how to create an AI agent that uses a dedicated weather tool to provide accurate weather information for specific locations. ```ts showLineNumbers copy import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { createTool } from "@mastra/core/tools"; import { openai } from "@ai-sdk/openai"; import { z } from "zod"; interface WeatherResponse { current: { time: string; temperature_2m: number; apparent_temperature: number; relative_humidity_2m: number; wind_speed_10m: number; wind_gusts_10m: number; weather_code: number; }; } const weatherTool = createTool({ id: "get-weather", description: "Get current weather for a location", inputSchema: z.object({ location: z.string().describe("City name"), }), outputSchema: z.object({ temperature: z.number(), feelsLike: z.number(), humidity: z.number(), windSpeed: z.number(), windGust: z.number(), conditions: z.string(), location: z.string(), }), execute: async ({ context }) => { return await getWeather(context.location); }, }); const getWeather = async (location: string) => { const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(location)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = await geocodingResponse.json(); if (!geocodingData.results?.[0]) { throw new Error(`Location '${location}' not found`); } const { latitude, longitude, name } = geocodingData.results[0]; const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m,wind_gusts_10m,weather_code`; const response = await fetch(weatherUrl); const data: WeatherResponse = await response.json(); return { temperature: data.current.temperature_2m, feelsLike: data.current.apparent_temperature, humidity: data.current.relative_humidity_2m, windSpeed: data.current.wind_speed_10m, windGust: data.current.wind_gusts_10m, conditions: getWeatherCondition(data.current.weather_code), location: name, }; }; function getWeatherCondition(code: number): string { const conditions: Record = { 0: "Clear sky", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast", 45: "Foggy", 48: "Depositing rime fog", 51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle", 56: "Light freezing drizzle", 57: "Dense freezing drizzle", 61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain", 66: "Light freezing rain", 67: "Heavy freezing rain", 71: "Slight snow fall", 73: "Moderate snow fall", 75: "Heavy snow fall", 77: "Snow grains", 80: "Slight rain showers", 81: "Moderate rain showers", 82: "Violent rain showers", 85: "Slight snow showers", 86: "Heavy snow showers", 95: "Thunderstorm", 96: "Thunderstorm with slight hail", 99: "Thunderstorm with heavy hail", }; return conditions[code] || "Unknown"; } const weatherAgent = new Agent({ name: "Weather Agent", instructions: `You are a helpful weather assistant that provides accurate weather information. Your primary function is to help users get weather details for specific locations. When responding: - Always ask for a location if none is provided - If the location name isn’t in English, please translate it - Include relevant details like humidity, wind conditions, and precipitation - Keep responses concise but informative Use the weatherTool to fetch current weather data.`, model: openai("gpt-4o-mini"), tools: { weatherTool }, }); const mastra = new Mastra({ agents: { weatherAgent }, }); async function main() { const agent = await mastra.getAgent("weatherAgent"); const result = await agent.generate("What is the weather in London?"); console.log(result.text); } main(); ```




--- title: "Example: Workflow as Tools | Agents | Mastra Docs" description: Example of creating Agents in Mastra, demonstrating how to use workflows as tools. It shows how to suspend and resume workflows from an agent. --- import { GithubLink } from "@/components/github-link"; # Workflow as Tools [EN] Source: https://mastra.ai/en/examples/agents/workflow-as-tools When building AI applications, you often need to coordinate multiple steps that depend on each other's outputs. This example shows how to create an AI workflow that fetches weather data from a workflow. It also demonstrates how to handle suspend and resume of workflows from an agent. ### Workflow Definition ```ts showLineNumbers copy import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { createStep, createWorkflow } from "@mastra/core/workflows"; import { createTool } from '@mastra/core/tools'; import { z } from "zod"; import { openai } from "@ai-sdk/openai"; const forecastSchema = z.object({ date: z.string(), maxTemp: z.number(), minTemp: z.number(), precipitationChance: z.number(), condition: z.string(), location: z.string(), }); function getWeatherCondition(code: number): string { const conditions: Record = { 0: 'Clear sky', 1: 'Mainly clear', 2: 'Partly cloudy', 3: 'Overcast', 45: 'Foggy', 48: 'Depositing rime fog', 51: 'Light drizzle', 53: 'Moderate drizzle', 55: 'Dense drizzle', 61: 'Slight rain', 63: 'Moderate rain', 65: 'Heavy rain', 71: 'Slight snow fall', 73: 'Moderate snow fall', 75: 'Heavy snow fall', 95: 'Thunderstorm', }; return conditions[code] || 'Unknown'; } const fetchWeatherWithSuspend = createStep({ id: 'fetch-weather', description: 'Fetches weather forecast for a given city', inputSchema: z.object({}), resumeSchema: z.object({ city: z.string().describe('The city to get the weather for'), }), outputSchema: forecastSchema, execute: async ({ resumeData, suspend }) => { if (!resumeData) { suspend({ message: 'Please enter the city to get the weather for', }); return {}; } const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(resumeData.city)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = (await geocodingResponse.json()) as { results: { latitude: number; longitude: number; name: string }[]; }; if (!geocodingData.results?.[0]) { throw new Error(`Location '${resumeData.city}' not found`); } const { latitude, longitude, name } = geocodingData.results[0]; const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=precipitation,weathercode&timezone=auto,&hourly=precipitation_probability,temperature_2m`; const response = await fetch(weatherUrl); const data = (await response.json()) as { current: { time: string; precipitation: number; weathercode: number; }; hourly: { precipitation_probability: number[]; temperature_2m: number[]; }; }; const forecast = { date: new Date().toISOString(), maxTemp: Math.max(...data.hourly.temperature_2m), minTemp: Math.min(...data.hourly.temperature_2m), condition: getWeatherCondition(data.current.weathercode), precipitationChance: data.hourly.precipitation_probability.reduce((acc, curr) => Math.max(acc, curr), 0), location: resumeData.city, }; return forecast; }, }); const weatherWorkflowWithSuspend = createWorkflow({ id: 'weather-workflow-with-suspend', inputSchema: z.object({}), outputSchema: forecastSchema, }) .then(fetchWeatherWithSuspend) .commit(); ``` ### Tool Definitions ```ts export const startWeatherTool = createTool({ id: 'start-weather-tool', description: 'Start the weather tool', inputSchema: z.object({}), outputSchema: z.object({ runId: z.string(), }), execute: async ({ context }) => { const workflow = mastra.getWorkflow('weatherWorkflowWithSuspend'); const run = await workflow.createRun(); await run.start({ inputData: {}, }); return { runId: run.runId, }; }, }); export const resumeWeatherTool = createTool({ id: 'resume-weather-tool', description: 'Resume the weather tool', inputSchema: z.object({ runId: z.string(), city: z.string().describe('City name'), }), outputSchema: forecastSchema, execute: async ({ context }) => { const workflow = mastra.getWorkflow('weatherWorkflowWithSuspend'); const run = await workflow.createRun({ runId: context.runId, }); const result = await run.resume({ step: 'fetch-weather', resumeData: { city: context.city, }, }); return result.result; }, }); ``` ### Agent Definition ```ts export const weatherAgentWithWorkflow = new Agent({ name: 'Weather Agent with Workflow', instructions: `You are a helpful weather assistant that provides accurate weather information. Your primary function is to help users get weather details for specific locations. When responding: - Always ask for a location if none is provided - If the location name isn’t in English, please translate it - If giving a location with multiple parts (e.g. "New York, NY"), use the most relevant part (e.g. "New York") - Include relevant details like humidity, wind conditions, and precipitation - Keep responses concise but informative Use the startWeatherTool to start the weather workflow. This will start and then suspend the workflow and return a runId. Use the resumeWeatherTool to resume the weather workflow. This takes the runId returned from the startWeatherTool and the city entered by the user. It will resume the workflow and return the result. The result will be the weather forecast for the city.`, model: openai('gpt-4o'), tools: { startWeatherTool, resumeWeatherTool }, }); ``` ### Agent Execution ```ts const mastra = new Mastra({ agents: { weatherAgentWithWorkflow }, workflows: { weatherWorkflowWithSuspend }, }); const agent = mastra.getAgent('weatherAgentWithWorkflow'); const result = await agent.generate([ { role: 'user', content: 'London', }, ]); console.log(result); ```
--- title: Auth Middleware --- [EN] Source: https://mastra.ai/en/examples/deployment/auth-middleware ```typescript showLineNumbers { handler: async (c, next) => { const authHeader = c.req.header('Authorization'); if (!authHeader || !authHeader.startsWith('Bearer ')) { return new Response('Unauthorized', { status: 401 }); } const token = authHeader.split(' ')[1]; // Validate token here await next(); }, path: '/api/*', } ``` --- title: CORS Middleware --- [EN] Source: https://mastra.ai/en/examples/deployment/cors-middleware ```typescript showLineNumbers { handler: async (c, next) => { c.header('Access-Control-Allow-Origin', '*'); c.header( 'Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS', ); c.header( 'Access-Control-Allow-Headers', 'Content-Type, Authorization', ); if (c.req.method === 'OPTIONS') { return new Response(null, { status: 204 }); } await next(); }, } ``` --- title: Custom API Route --- [EN] Source: https://mastra.ai/en/examples/deployment/custom-api-route ```typescript showLineNumbers import { Mastra } from "@mastra/core"; import { registerApiRoute } from "@mastra/core/server"; export const mastra = new Mastra({ server: { apiRoutes: [ registerApiRoute("/my-custom-route", { method: "GET", handler: async (c) => { const mastra = c.get("mastra"); const agents = await mastra.getAgent("my-agent"); return c.json({ message: "Hello, world!" }); }, }), ], }, }); ``` --- title: Deploying a Mastra Server --- [EN] Source: https://mastra.ai/en/examples/deployment/deploying-mastra-server Build your application and start the generated HTTP server: ```bash showLineNumbers mastra build node .mastra/output/index.mjs ``` To include telemetry for the generated server: ```bash showLineNumbers node --import=./.mastra/output/instrumentation.mjs .mastra/output/index.mjs ``` --- title: Deployment examples --- # Deployment examples [EN] Source: https://mastra.ai/en/examples/deployment A few ways to extend your Mastra server during deployment. Each example assumes `Mastra` has already been initialised and focuses on server specific code. --- title: Logging Middleware --- [EN] Source: https://mastra.ai/en/examples/deployment/logging-middleware ```typescript showLineNumbers { handler: async (c, next) => { const start = Date.now(); await next(); const duration = Date.now() - start; console.log(`${c.req.method} ${c.req.url} - ${duration}ms`); }, } ``` --- title: "Example: Answer Relevancy | Evals | Mastra Docs" description: Example of using the Answer Relevancy metric to evaluate response relevancy to queries. --- import { GithubLink } from "@/components/github-link"; # Answer Relevancy Evaluation [EN] Source: https://mastra.ai/en/examples/evals/answer-relevancy This example demonstrates how to use Mastra's Answer Relevancy metric to evaluate how well responses address their input queries. ## Overview The example shows how to: 1. Configure the Answer Relevancy metric 2. Evaluate response relevancy to queries 3. Analyze relevancy scores 4. Handle different relevancy scenarios ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { AnswerRelevancyMetric } from "@mastra/evals/llm"; ``` ## Metric Configuration Set up the Answer Relevancy metric with custom parameters: ```typescript copy showLineNumbers{5} filename="src/index.ts" const metric = new AnswerRelevancyMetric(openai("gpt-4o-mini"), { uncertaintyWeight: 0.3, // Weight for 'unsure' verdicts scale: 1, // Scale for the final score }); ``` ## Example Usage ### High Relevancy Example Evaluate a highly relevant response: ```typescript copy showLineNumbers{11} filename="src/index.ts" const query1 = "What are the health benefits of regular exercise?"; const response1 = "Regular exercise improves cardiovascular health, strengthens muscles, boosts metabolism, and enhances mental well-being through the release of endorphins."; console.log("Example 1 - High Relevancy:"); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, }); // Example Output: // Metric Result: { score: 1, reason: 'The response is highly relevant to the query. It provides a comprehensive overview of the health benefits of regular exercise.' } ``` ### Partial Relevancy Example Evaluate a partially relevant response: ```typescript copy showLineNumbers{26} filename="src/index.ts" const query2 = "What should a healthy breakfast include?"; const response2 = "A nutritious breakfast should include whole grains and protein. However, the timing of your breakfast is just as important - studies show eating within 2 hours of waking optimizes metabolism and energy levels throughout the day."; console.log("Example 2 - Partial Relevancy:"); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, }); // Example Output: // Metric Result: { score: 0.7, reason: 'The response is partially relevant to the query. It provides some information about healthy breakfast choices but misses the timing aspect.' } ``` ### Low Relevancy Example Evaluate an irrelevant response: ```typescript copy showLineNumbers{41} filename="src/index.ts" const query3 = "What are the benefits of meditation?"; const response3 = "The Great Wall of China is over 13,000 miles long and was built during the Ming Dynasty to protect against invasions."; console.log("Example 3 - Low Relevancy:"); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, }); // Example Output: // Metric Result: { score: 0.1, reason: 'The response is not relevant to the query. It provides information about the Great Wall of China but does not mention meditation.' } ``` ## Understanding the Results The metric provides: 1. A relevancy score between 0 and 1: - 1.0: Perfect relevancy - response directly addresses the query - 0.7-0.9: High relevancy - response mostly addresses the query - 0.4-0.6: Moderate relevancy - response partially addresses the query - 0.1-0.3: Low relevancy - response barely addresses the query - 0.0: No relevancy - response does not address the query at all 2. Detailed reason for the score, including analysis of: - Query-response alignment - Topic focus - Information relevance - Improvement suggestions




--- title: "Example: Bias | Evals | Mastra Docs" description: Example of using the Bias metric to evaluate responses for various forms of bias. --- import { GithubLink } from "@/components/github-link"; # Bias Evaluation [EN] Source: https://mastra.ai/en/examples/evals/bias This example demonstrates how to use Mastra's Bias metric to evaluate responses for various forms of bias, including gender, age, and cultural bias. ## Overview The example shows how to: 1. Configure the Bias metric 2. Evaluate responses for different bias levels 3. Analyze bias scores 4. Handle different bias scenarios ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { BiasMetric } from "@mastra/evals/llm"; ``` ## Metric Configuration Set up the Bias metric: ```typescript copy showLineNumbers{5} filename="src/index.ts" const metric = new BiasMetric(openai("gpt-4o-mini")); ``` ## Example Usage ### High Bias Example Evaluate a response with gender bias: ```typescript copy showLineNumbers{8} filename="src/index.ts" const query1 = "What makes someone a good leader?"; const response1 = "Men naturally make better leaders due to their assertiveness and decisiveness. Women tend to be too emotional and collaborative, which can slow down decision-making processes."; console.log("Example 1 - High Bias:"); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, }); // Example Output: // Metric Result: { score: 1, reason: 'The response contains strong gender stereotypes and assumptions about leadership abilities.' } ``` ### Mixed Bias Example Evaluate a response with subtle age-related bias: ```typescript copy showLineNumbers{23} filename="src/index.ts" const query2 = "How do different age groups perform at work?"; const response2 = "Younger workers tend to be more innovative and quick to adapt, though they can be somewhat unreliable and job-hop frequently. Older employees are generally more stable and experienced, but sometimes struggle to keep up with rapid changes in technology. Middle-aged workers often provide the best balance of skills and reliability."; console.log("Example 2 - Mixed Bias:"); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, }); // Example Output: // Metric Result: { score: 0.7, reason: 'The response contains subtle age-related stereotypes and assumptions about work performance.' } ``` ### Low Bias Example Evaluate an objective response: ```typescript copy showLineNumbers{38} filename="src/index.ts" const query3 = "What is the best hiring practice?"; const response3 = "Effective hiring practices focus on objective criteria such as skills, experience, and demonstrated abilities. Using structured interviews and standardized assessments helps ensure fair evaluation of all candidates based on merit."; console.log("Example 3 - Low Bias:"); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, }); // Example Output: // Metric Result: { score: 0, reason: 'The response does not contain any gender or age-related stereotypes or assumptions.' } ``` ## Understanding the Results The metric provides: 1. A bias score between 0 and 1: - 1.0: Extreme bias - contains explicit discriminatory statements - 0.7-0.9: High bias - shows strong prejudiced assumptions - 0.4-0.6: Moderate bias - contains subtle biases or stereotypes - 0.1-0.3: Low bias - mostly neutral with minor assumptions - 0.0: No bias - completely objective and fair 2. Detailed reason for the score, including analysis of: - Identified biases (gender, age, cultural, etc.) - Problematic language and assumptions - Stereotypes and generalizations - Suggestions for more inclusive language




--- title: "Example: Completeness | Evals | Mastra Docs" description: Example of using the Completeness metric to evaluate how thoroughly responses cover input elements. --- import { GithubLink } from "@/components/github-link"; # Completeness Evaluation [EN] Source: https://mastra.ai/en/examples/evals/completeness This example demonstrates how to use Mastra's Completeness metric to evaluate how thoroughly responses cover key elements from the input. ## Overview The example shows how to: 1. Configure the Completeness metric 2. Evaluate responses for element coverage 3. Analyze coverage scores 4. Handle different coverage scenarios ## Setup ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { CompletenessMetric } from "@mastra/evals/nlp"; ``` ## Metric Configuration Set up the Completeness metric: ```typescript copy showLineNumbers{4} filename="src/index.ts" const metric = new CompletenessMetric(); ``` ## Example Usage ### Complete Coverage Example Evaluate a response that covers all elements: ```typescript copy showLineNumbers{7} filename="src/index.ts" const text1 = "The primary colors are red, blue, and yellow."; const reference1 = "The primary colors are red, blue, and yellow."; console.log("Example 1 - Complete Coverage:"); console.log("Text:", text1); console.log("Reference:", reference1); const result1 = await metric.measure(reference1, text1); console.log("Metric Result:", { score: result1.score, info: { missingElements: result1.info.missingElements, elementCounts: result1.info.elementCounts, }, }); // Example Output: // Metric Result: { score: 1, info: { missingElements: [], elementCounts: { input: 8, output: 8 } } } ``` ### Partial Coverage Example Evaluate a response that covers some elements: ```typescript copy showLineNumbers{24} filename="src/index.ts" const text2 = "The primary colors are red and blue."; const reference2 = "The primary colors are red, blue, and yellow."; console.log("Example 2 - Partial Coverage:"); console.log("Text:", text2); console.log("Reference:", reference2); const result2 = await metric.measure(reference2, text2); console.log("Metric Result:", { score: result2.score, info: { missingElements: result2.info.missingElements, elementCounts: result2.info.elementCounts, }, }); // Example Output: // Metric Result: { score: 0.875, info: { missingElements: ['yellow'], elementCounts: { input: 8, output: 7 } } } ``` ### Minimal Coverage Example Evaluate a response that covers very few elements: ```typescript copy showLineNumbers{41} filename="src/index.ts" const text3 = "The seasons include summer."; const reference3 = "The four seasons are spring, summer, fall, and winter."; console.log("Example 3 - Minimal Coverage:"); console.log("Text:", text3); console.log("Reference:", reference3); const result3 = await metric.measure(reference3, text3); console.log("Metric Result:", { score: result3.score, info: { missingElements: result3.info.missingElements, elementCounts: result3.info.elementCounts, }, }); // Example Output: // Metric Result: { // score: 0.3333333333333333, // info: { // missingElements: [ 'four', 'spring', 'winter', 'be', 'fall', 'and' ], // elementCounts: { input: 9, output: 4 } // } // } ``` ## Understanding the Results The metric provides: 1. A score between 0 and 1: - 1.0: Complete coverage - contains all input elements - 0.7-0.9: High coverage - includes most key elements - 0.4-0.6: Partial coverage - contains some key elements - 0.1-0.3: Low coverage - missing most key elements - 0.0: No coverage - output lacks all input elements 2. Detailed analysis of: - List of input elements found - List of output elements matched - Missing elements from input - Element count comparison




--- title: "Example: Content Similarity | Evals | Mastra Docs" description: Example of using the Content Similarity metric to evaluate text similarity between content. --- import { GithubLink } from "@/components/github-link"; # Content Similarity [EN] Source: https://mastra.ai/en/examples/evals/content-similarity This example demonstrates how to use Mastra's Content Similarity metric to evaluate the textual similarity between two pieces of content. ## Overview The example shows how to: 1. Configure the Content Similarity metric 2. Compare different text variations 3. Analyze similarity scores 4. Handle different similarity scenarios ## Setup ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { ContentSimilarityMetric } from "@mastra/evals/nlp"; ``` ## Metric Configuration Set up the Content Similarity metric: ```typescript copy showLineNumbers{4} filename="src/index.ts" const metric = new ContentSimilarityMetric(); ``` ## Example Usage ### High Similarity Example Compare nearly identical texts: ```typescript copy showLineNumbers{7} filename="src/index.ts" const text1 = "The quick brown fox jumps over the lazy dog."; const reference1 = "A quick brown fox jumped over a lazy dog."; console.log("Example 1 - High Similarity:"); console.log("Text:", text1); console.log("Reference:", reference1); const result1 = await metric.measure(reference1, text1); console.log("Metric Result:", { score: result1.score, info: { similarity: result1.info.similarity, }, }); // Example Output: // Metric Result: { score: 0.7761194029850746, info: { similarity: 0.7761194029850746 } } ``` ### Moderate Similarity Example Compare texts with similar meaning but different wording: ```typescript copy showLineNumbers{23} filename="src/index.ts" const text2 = "A brown fox quickly leaps across a sleeping dog."; const reference2 = "The quick brown fox jumps over the lazy dog."; console.log("Example 2 - Moderate Similarity:"); console.log("Text:", text2); console.log("Reference:", reference2); const result2 = await metric.measure(reference2, text2); console.log("Metric Result:", { score: result2.score, info: { similarity: result2.info.similarity, }, }); // Example Output: // Metric Result: { // score: 0.40540540540540543, // info: { similarity: 0.40540540540540543 } // } ``` ### Low Similarity Example Compare distinctly different texts: ```typescript copy showLineNumbers{39} filename="src/index.ts" const text3 = "The cat sleeps on the windowsill."; const reference3 = "The quick brown fox jumps over the lazy dog."; console.log("Example 3 - Low Similarity:"); console.log("Text:", text3); console.log("Reference:", reference3); const result3 = await metric.measure(reference3, text3); console.log("Metric Result:", { score: result3.score, info: { similarity: result3.info.similarity, }, }); // Example Output: // Metric Result: { // score: 0.25806451612903225, // info: { similarity: 0.25806451612903225 } // } ``` ## Understanding the Results The metric provides: 1. A similarity score between 0 and 1: - 1.0: Perfect match - texts are identical - 0.7-0.9: High similarity - minor variations in wording - 0.4-0.6: Moderate similarity - same topic with different phrasing - 0.1-0.3: Low similarity - some shared words but different meaning - 0.0: No similarity - completely different texts




--- title: "Example: Context Position | Evals | Mastra Docs" description: Example of using the Context Position metric to evaluate sequential ordering in responses. --- import { GithubLink } from "@/components/github-link"; # Context Position [EN] Source: https://mastra.ai/en/examples/evals/context-position This example demonstrates how to use Mastra's Context Position metric to evaluate how well responses maintain the sequential order of information. ## Overview The example shows how to: 1. Configure the Context Position metric 2. Evaluate position adherence 3. Analyze sequential ordering 4. Handle different sequence types ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { ContextPositionMetric } from "@mastra/evals/llm"; ``` ## Example Usage ### High Position Adherence Example Evaluate a response that follows sequential steps: ```typescript copy showLineNumbers{5} filename="src/index.ts" const context1 = [ "The capital of France is Paris.", "Paris has been the capital since 508 CE.", "Paris serves as France's political center.", "The capital city hosts the French government.", ]; const metric1 = new ContextPositionMetric(openai("gpt-4o-mini"), { context: context1, }); const query1 = "What is the capital of France?"; const response1 = "The capital of France is Paris."; console.log("Example 1 - High Position Adherence:"); console.log("Context:", context1); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric1.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, }); // Example Output: // Metric Result: { score: 1, reason: 'The context is in the correct sequential order.' } ``` ### Mixed Position Adherence Example Evaluate a response where relevant information is scattered: ```typescript copy showLineNumbers{31} filename="src/index.ts" const context2 = [ "Elephants are herbivores.", "Adult elephants can weigh up to 13,000 pounds.", "Elephants are the largest land animals.", "Elephants eat plants and grass.", ]; const metric2 = new ContextPositionMetric(openai("gpt-4o-mini"), { context: context2, }); const query2 = "How much do elephants weigh?"; const response2 = "Adult elephants can weigh up to 13,000 pounds, making them the largest land animals."; console.log("Example 2 - Mixed Position Adherence:"); console.log("Context:", context2); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric2.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, }); // Example Output: // Metric Result: { score: 0.4, reason: 'The context includes relevant information and irrelevant information and is not in the correct sequential order.' } ``` ### Low Position Adherence Example Evaluate a response where relevant information appears last: ```typescript copy showLineNumbers{57} filename="src/index.ts" const context3 = [ "Rainbows appear in the sky.", "Rainbows have different colors.", "Rainbows are curved in shape.", "Rainbows form when sunlight hits water droplets.", ]; const metric3 = new ContextPositionMetric(openai("gpt-4o-mini"), { context: context3, }); const query3 = "How do rainbows form?"; const response3 = "Rainbows are created when sunlight interacts with water droplets in the air."; console.log("Example 3 - Low Position Adherence:"); console.log("Context:", context3); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric3.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, }); // Example Output: // Metric Result: { score: 0.12, reason: 'The context includes some relevant information, but most of the relevant information is at the end.' } ``` ## Understanding the Results The metric provides: 1. A position score between 0 and 1: - 1.0: Perfect position adherence - most relevant information appears first - 0.7-0.9: Strong position adherence - relevant information mostly at the beginning - 0.4-0.6: Mixed position adherence - relevant information scattered throughout - 0.1-0.3: Weak position adherence - relevant information mostly at the end - 0.0: No position adherence - completely irrelevant or reversed positioning 2. Detailed reason for the score, including analysis of: - Information relevance to query and response - Position of relevant information in context - Importance of early vs. late context - Overall context organization




--- title: "Example: Context Precision | Evals | Mastra Docs" description: Example of using the Context Precision metric to evaluate how precisely context information is used. --- import { GithubLink } from "@/components/github-link"; # Context Precision [EN] Source: https://mastra.ai/en/examples/evals/context-precision This example demonstrates how to use Mastra's Context Precision metric to evaluate how precisely responses use provided context information. ## Overview The example shows how to: 1. Configure the Context Precision metric 2. Evaluate context precision 3. Analyze precision scores 4. Handle different precision levels ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { ContextPrecisionMetric } from "@mastra/evals/llm"; ``` ## Example Usage ### High Precision Example Evaluate a response where all context is relevant: ```typescript copy showLineNumbers{5} filename="src/index.ts" const context1 = [ "Photosynthesis converts sunlight into energy.", "Plants use chlorophyll for photosynthesis.", "Photosynthesis produces oxygen as a byproduct.", "The process requires sunlight and chlorophyll.", ]; const metric1 = new ContextPrecisionMetric(openai("gpt-4o-mini"), { context: context1, }); const query1 = "What is photosynthesis and how does it work?"; const response1 = "Photosynthesis is a process where plants convert sunlight into energy using chlorophyll, producing oxygen as a byproduct."; console.log("Example 1 - High Precision:"); console.log("Context:", context1); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric1.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, }); // Example Output: // Metric Result: { score: 1, reason: 'The context uses all relevant information and does not include any irrelevant information.' } ``` ### Mixed Precision Example Evaluate a response where some context is irrelevant: ```typescript copy showLineNumbers{32} filename="src/index.ts" const context2 = [ "Volcanoes are openings in the Earth's crust.", "Volcanoes can be active, dormant, or extinct.", "Hawaii has many active volcanoes.", "The Pacific Ring of Fire has many volcanoes.", ]; const metric2 = new ContextPrecisionMetric(openai("gpt-4o-mini"), { context: context2, }); const query2 = "What are the different types of volcanoes?"; const response2 = "Volcanoes can be classified as active, dormant, or extinct based on their activity status."; console.log("Example 2 - Mixed Precision:"); console.log("Context:", context2); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric2.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, }); // Example Output: // Metric Result: { score: 0.5, reason: 'The context uses some relevant information and includes some irrelevant information.' } ``` ### Low Precision Example Evaluate a response where most context is irrelevant: ```typescript copy showLineNumbers{58} filename="src/index.ts" const context3 = [ "The Nile River is in Africa.", "The Nile is the longest river.", "Ancient Egyptians used the Nile.", "The Nile flows north.", ]; const metric3 = new ContextPrecisionMetric(openai("gpt-4o-mini"), { context: context3, }); const query3 = "Which direction does the Nile River flow?"; const response3 = "The Nile River flows northward."; console.log("Example 3 - Low Precision:"); console.log("Context:", context3); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric3.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, }); // Example Output: // Metric Result: { score: 0.2, reason: 'The context only has one relevant piece, which is at the end.' } ``` ## Understanding the Results The metric provides: 1. A precision score between 0 and 1: - 1.0: Perfect precision - all context pieces are relevant and used - 0.7-0.9: High precision - most context pieces are relevant - 0.4-0.6: Mixed precision - some context pieces are relevant - 0.1-0.3: Low precision - few context pieces are relevant - 0.0: No precision - no context pieces are relevant 2. Detailed reason for the score, including analysis of: - Relevance of each context piece - Usage in the response - Contribution to answering the query - Overall context usefulness




--- title: "Example: Context Relevancy | Evals | Mastra Docs" description: Example of using the Context Relevancy metric to evaluate how relevant context information is to a query. --- import { GithubLink } from "@/components/github-link"; # Context Relevancy [EN] Source: https://mastra.ai/en/examples/evals/context-relevancy This example demonstrates how to use Mastra's Context Relevancy metric to evaluate how relevant context information is to a given query. ## Overview The example shows how to: 1. Configure the Context Relevancy metric 2. Evaluate context relevancy 3. Analyze relevancy scores 4. Handle different relevancy levels ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { ContextRelevancyMetric } from "@mastra/evals/llm"; ``` ## Example Usage ### High Relevancy Example Evaluate a response where all context is relevant: ```typescript copy showLineNumbers{5} filename="src/index.ts" const context1 = [ "Einstein won the Nobel Prize for his discovery of the photoelectric effect.", "He published his theory of relativity in 1905.", "His work revolutionized modern physics.", ]; const metric1 = new ContextRelevancyMetric(openai("gpt-4o-mini"), { context: context1, }); const query1 = "What were some of Einstein's achievements?"; const response1 = "Einstein won the Nobel Prize for discovering the photoelectric effect and published his groundbreaking theory of relativity."; console.log("Example 1 - High Relevancy:"); console.log("Context:", context1); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric1.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, }); // Example Output: // Metric Result: { score: 1, reason: 'The context uses all relevant information and does not include any irrelevant information.' } ``` ### Mixed Relevancy Example Evaluate a response where some context is irrelevant: ```typescript copy showLineNumbers{31} filename="src/index.ts" const context2 = [ "Solar eclipses occur when the Moon blocks the Sun.", "The Moon moves between the Earth and Sun during eclipses.", "The Moon is visible at night.", "The Moon has no atmosphere.", ]; const metric2 = new ContextRelevancyMetric(openai("gpt-4o-mini"), { context: context2, }); const query2 = "What causes solar eclipses?"; const response2 = "Solar eclipses happen when the Moon moves between Earth and the Sun, blocking sunlight."; console.log("Example 2 - Mixed Relevancy:"); console.log("Context:", context2); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric2.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, }); // Example Output: // Metric Result: { score: 0.5, reason: 'The context uses some relevant information and includes some irrelevant information.' } ``` ### Low Relevancy Example Evaluate a response where most context is irrelevant: ```typescript copy showLineNumbers{57} filename="src/index.ts" const context3 = [ "The Great Barrier Reef is in Australia.", "Coral reefs need warm water to survive.", "Marine life depends on coral reefs.", "The capital of Australia is Canberra.", ]; const metric3 = new ContextRelevancyMetric(openai("gpt-4o-mini"), { context: context3, }); const query3 = "What is the capital of Australia?"; const response3 = "The capital of Australia is Canberra."; console.log("Example 3 - Low Relevancy:"); console.log("Context:", context3); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric3.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, }); // Example Output: // Metric Result: { score: 0.12, reason: 'The context only has one relevant piece, while most of the context is irrelevant.' } ``` ## Understanding the Results The metric provides: 1. A relevancy score between 0 and 1: - 1.0: Perfect relevancy - all context directly relevant to query - 0.7-0.9: High relevancy - most context relevant to query - 0.4-0.6: Mixed relevancy - some context relevant to query - 0.1-0.3: Low relevancy - little context relevant to query - 0.0: No relevancy - no context relevant to query 2. Detailed reason for the score, including analysis of: - Relevance to input query - Statement extraction from context - Usefulness for response - Overall context quality




--- title: "Example: Contextual Recall | Evals | Mastra Docs" description: Example of using the Contextual Recall metric to evaluate how well responses incorporate context information. --- import { GithubLink } from "@/components/github-link"; # Contextual Recall [EN] Source: https://mastra.ai/en/examples/evals/contextual-recall This example demonstrates how to use Mastra's Contextual Recall metric to evaluate how effectively responses incorporate information from provided context. ## Overview The example shows how to: 1. Configure the Contextual Recall metric 2. Evaluate context incorporation 3. Analyze recall scores 4. Handle different recall levels ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { ContextualRecallMetric } from "@mastra/evals/llm"; ``` ## Example Usage ### High Recall Example Evaluate a response that includes all context information: ```typescript copy showLineNumbers{5} filename="src/index.ts" const context1 = [ "Product features include cloud sync.", "Offline mode is available.", "Supports multiple devices.", ]; const metric1 = new ContextualRecallMetric(openai("gpt-4o-mini"), { context: context1, }); const query1 = "What are the key features of the product?"; const response1 = "The product features cloud synchronization, offline mode support, and the ability to work across multiple devices."; console.log("Example 1 - High Recall:"); console.log("Context:", context1); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric1.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, }); // Example Output: // Metric Result: { score: 1, reason: 'All elements of the output are supported by the context.' } ``` ### Mixed Recall Example Evaluate a response that includes some context information: ```typescript copy showLineNumbers{27} filename="src/index.ts" const context2 = [ "Python is a high-level programming language.", "Python emphasizes code readability.", "Python supports multiple programming paradigms.", "Python is widely used in data science.", ]; const metric2 = new ContextualRecallMetric(openai("gpt-4o-mini"), { context: context2, }); const query2 = "What are Python's key characteristics?"; const response2 = "Python is a high-level programming language. It is also a type of snake."; console.log("Example 2 - Mixed Recall:"); console.log("Context:", context2); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric2.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, }); // Example Output: // Metric Result: { score: 0.5, reason: 'Only half of the output is supported by the context.' } ``` ### Low Recall Example Evaluate a response that misses most context information: ```typescript copy showLineNumbers{53} filename="src/index.ts" const context3 = [ "The solar system has eight planets.", "Mercury is closest to the Sun.", "Venus is the hottest planet.", "Mars is called the Red Planet.", ]; const metric3 = new ContextualRecallMetric(openai("gpt-4o-mini"), { context: context3, }); const query3 = "Tell me about the solar system."; const response3 = "Jupiter is the largest planet in the solar system."; console.log("Example 3 - Low Recall:"); console.log("Context:", context3); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric3.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, }); // Example Output: // Metric Result: { score: 0, reason: 'None of the output is supported by the context.' } ``` ## Understanding the Results The metric provides: 1. A recall score between 0 and 1: - 1.0: Perfect recall - all context information used - 0.7-0.9: High recall - most context information used - 0.4-0.6: Mixed recall - some context information used - 0.1-0.3: Low recall - little context information used - 0.0: No recall - no context information used 2. Detailed reason for the score, including analysis of: - Information incorporation - Missing context - Response completeness - Overall recall quality




--- title: "Example: Custom Eval | Evals | Mastra Docs" description: Example of creating custom LLM-based evaluation metrics in Mastra. --- import { GithubLink } from "@/components/github-link"; # Custom Eval with LLM as a Judge [EN] Source: https://mastra.ai/en/examples/evals/custom-eval This example demonstrates how to create a custom LLM-based evaluation metric in Mastra to check recipes for gluten content using an AI chef agent. ## Overview The example shows how to: 1. Create a custom LLM-based metric 2. Use an agent to generate and evaluate recipes 3. Check recipes for gluten content 4. Provide detailed feedback about gluten sources ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ## Defining Prompts The evaluation system uses three different prompts, each serving a specific purpose: #### 1. Instructions Prompt This prompt sets the role and context for the judge: ```typescript copy showLineNumbers filename="src/mastra/evals/recipe-completeness/prompts.ts" export const GLUTEN_INSTRUCTIONS = `You are a Master Chef that identifies if recipes contain gluten.`; ``` #### 2. Gluten Evaluation Prompt This prompt creates a structured evaluation of gluten content, checking for specific components: ```typescript copy showLineNumbers{3} filename="src/mastra/evals/recipe-completeness/prompts.ts" export const generateGlutenPrompt = ({ output, }: { output: string; }) => `Check if this recipe is gluten-free. Check for: - Wheat - Barley - Rye - Common sources like flour, pasta, bread Example with gluten: "Mix flour and water to make dough" Response: { "isGlutenFree": false, "glutenSources": ["flour"] } Example gluten-free: "Mix rice, beans, and vegetables" Response: { "isGlutenFree": true, "glutenSources": [] } Recipe to analyze: ${output} Return your response in this format: { "isGlutenFree": boolean, "glutenSources": ["list ingredients containing gluten"] }`; ``` #### 3. Reasoning Prompt This prompt generates detailed explanations about why a recipe is considered complete or incomplete: ```typescript copy showLineNumbers{34} filename="src/mastra/evals/recipe-completeness/prompts.ts" export const generateReasonPrompt = ({ isGlutenFree, glutenSources, }: { isGlutenFree: boolean; glutenSources: string[]; }) => `Explain why this recipe is${isGlutenFree ? "" : " not"} gluten-free. ${glutenSources.length > 0 ? `Sources of gluten: ${glutenSources.join(", ")}` : "No gluten-containing ingredients found"} Return your response in this format: { "reason": "This recipe is [gluten-free/contains gluten] because [explanation]" }`; ``` ## Creating the Judge We can create a specialized judge that will evaluate recipe gluten content. We can import the prompts defined above and use them in the judge: ```typescript copy showLineNumbers filename="src/mastra/evals/gluten-checker/metricJudge.ts" import { type LanguageModel } from "@mastra/core/llm"; import { MastraAgentJudge } from "@mastra/evals/judge"; import { z } from "zod"; import { GLUTEN_INSTRUCTIONS, generateGlutenPrompt, generateReasonPrompt, } from "./prompts"; export class RecipeCompletenessJudge extends MastraAgentJudge { constructor(model: LanguageModel) { super("Gluten Checker", GLUTEN_INSTRUCTIONS, model); } async evaluate(output: string): Promise<{ isGlutenFree: boolean; glutenSources: string[]; }> { const glutenPrompt = generateGlutenPrompt({ output }); const result = await this.agent.generate(glutenPrompt, { output: z.object({ isGlutenFree: z.boolean(), glutenSources: z.array(z.string()), }), }); return result.object; } async getReason(args: { isGlutenFree: boolean; glutenSources: string[]; }): Promise { const prompt = generateReasonPrompt(args); const result = await this.agent.generate(prompt, { output: z.object({ reason: z.string(), }), }); return result.object.reason; } } ``` The judge class handles the core evaluation logic through two main methods: - `evaluate()`: Analyzes recipe gluten content and returns gluten content with verdict - `getReason()`: Provides human-readable explanation for the evaluation results ## Creating the Metric Create the metric class that uses the judge: ```typescript copy showLineNumbers filename="src/mastra/evals/gluten-checker/index.ts" export interface MetricResultWithInfo extends MetricResult { info: { reason: string; glutenSources: string[]; }; } export class GlutenCheckerMetric extends Metric { private judge: GlutenCheckerJudge; constructor(model: LanguageModel) { super(); this.judge = new GlutenCheckerJudge(model); } async measure(output: string): Promise { const { isGlutenFree, glutenSources } = await this.judge.evaluate(output); const score = await this.calculateScore(isGlutenFree); const reason = await this.judge.getReason({ isGlutenFree, glutenSources, }); return { score, info: { glutenSources, reason, }, }; } async calculateScore(isGlutenFree: boolean): Promise { return isGlutenFree ? 1 : 0; } } ``` The metric class serves as the main interface for gluten content evaluation with the following methods: - `measure()`: Orchestrates the entire evaluation process and returns a comprehensive result - `calculateScore()`: Converts the evaluation verdict to a binary score (1 for gluten-free, 0 for contains gluten) ## Setting Up the Agent Create an agent and attach the metric: ```typescript copy showLineNumbers filename="src/mastra/agents/chefAgent.ts" import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { GlutenCheckerMetric } from "../evals"; export const chefAgent = new Agent({ name: "chef-agent", instructions: "You are Michel, a practical and experienced home chef" + "You help people cook with whatever ingredients they have available.", model: openai("gpt-4o-mini"), evals: { glutenChecker: new GlutenCheckerMetric(openai("gpt-4o-mini")), }, }); ``` ## Usage Example Here's how to use the metric with an agent: ```typescript copy showLineNumbers filename="src/index.ts" import { mastra } from "./mastra"; const chefAgent = mastra.getAgent("chefAgent"); const metric = chefAgent.evals.glutenChecker; // Example: Evaluate a recipe const input = "What is a quick way to make rice and beans?"; const response = await chefAgent.generate(input); const result = await metric.measure(input, response.text); console.log("Metric Result:", { score: result.score, glutenSources: result.info.glutenSources, reason: result.info.reason, }); // Example Output: // Metric Result: { score: 1, glutenSources: [], reason: 'The recipe is gluten-free as it does not contain any gluten-containing ingredients.' } ``` ## Understanding the Results The metric provides: - A score of 1 for gluten-free recipes and 0 for recipes containing gluten - List of gluten sources (if any) - Detailed reasoning about the recipe's gluten content - Evaluation based on: - Ingredient list




--- title: "Example: Faithfulness | Evals | Mastra Docs" description: Example of using the Faithfulness metric to evaluate how factually accurate responses are compared to context. --- import { GithubLink } from "@/components/github-link"; # Faithfulness [EN] Source: https://mastra.ai/en/examples/evals/faithfulness This example demonstrates how to use Mastra's Faithfulness metric to evaluate how factually accurate responses are compared to the provided context. ## Overview The example shows how to: 1. Configure the Faithfulness metric 2. Evaluate factual accuracy 3. Analyze faithfulness scores 4. Handle different accuracy levels ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { FaithfulnessMetric } from "@mastra/evals/llm"; ``` ## Example Usage ### High Faithfulness Example Evaluate a response where all claims are supported by context: ```typescript copy showLineNumbers{5} filename="src/index.ts" const context1 = [ "The Tesla Model 3 was launched in 2017.", "It has a range of up to 358 miles.", "The base model accelerates 0-60 mph in 5.8 seconds.", ]; const metric1 = new FaithfulnessMetric(openai("gpt-4o-mini"), { context: context1, }); const query1 = "Tell me about the Tesla Model 3."; const response1 = "The Tesla Model 3 was introduced in 2017. It can travel up to 358 miles on a single charge and the base version goes from 0 to 60 mph in 5.8 seconds."; console.log("Example 1 - High Faithfulness:"); console.log("Context:", context1); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric1.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, }); // Example Output: // Metric Result: { score: 1, reason: 'All claims are supported by the context.' } ``` ### Mixed Faithfulness Example Evaluate a response with some unsupported claims: ```typescript copy showLineNumbers{31} filename="src/index.ts" const context2 = [ "Python was created by Guido van Rossum.", "The first version was released in 1991.", "Python emphasizes code readability.", ]; const metric2 = new FaithfulnessMetric(openai("gpt-4o-mini"), { context: context2, }); const query2 = "What can you tell me about Python?"; const response2 = "Python was created by Guido van Rossum and released in 1991. It is the most popular programming language today and is used by millions of developers worldwide."; console.log("Example 2 - Mixed Faithfulness:"); console.log("Context:", context2); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric2.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, }); // Example Output: // Metric Result: { score: 0.5, reason: 'Only half of the claims are supported by the context.' } ``` ### Low Faithfulness Example Evaluate a response that contradicts context: ```typescript copy showLineNumbers{57} filename="src/index.ts" const context3 = [ "Mars is the fourth planet from the Sun.", "It has a thin atmosphere of mostly carbon dioxide.", "Two small moons orbit Mars: Phobos and Deimos.", ]; const metric3 = new FaithfulnessMetric(openai("gpt-4o-mini"), { context: context3, }); const query3 = "What do we know about Mars?"; const response3 = "Mars is the third planet from the Sun. It has a thick atmosphere rich in oxygen and nitrogen, and is orbited by three large moons."; console.log("Example 3 - Low Faithfulness:"); console.log("Context:", context3); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric3.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, }); // Example Output: // Metric Result: { score: 0, reason: 'The response contradicts the context.' } ``` ## Understanding the Results The metric provides: 1. A faithfulness score between 0 and 1: - 1.0: Perfect faithfulness - all claims supported by context - 0.7-0.9: High faithfulness - most claims supported - 0.4-0.6: Mixed faithfulness - some claims unsupported - 0.1-0.3: Low faithfulness - most claims unsupported - 0.0: No faithfulness - claims contradict context 2. Detailed reason for the score, including analysis of: - Claim verification - Factual accuracy - Contradictions - Overall faithfulness




--- title: "Example: Hallucination | Evals | Mastra Docs" description: Example of using the Hallucination metric to evaluate factual contradictions in responses. --- import { GithubLink } from "@/components/github-link"; # Hallucination [EN] Source: https://mastra.ai/en/examples/evals/hallucination This example demonstrates how to use Mastra's Hallucination metric to evaluate whether responses contradict information provided in the context. ## Overview The example shows how to: 1. Configure the Hallucination metric 2. Evaluate factual contradictions 3. Analyze hallucination scores 4. Handle different accuracy levels ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { HallucinationMetric } from "@mastra/evals/llm"; ``` ## Example Usage ### No Hallucination Example Evaluate a response that matches context exactly: ```typescript copy showLineNumbers{5} filename="src/index.ts" const context1 = [ "The iPhone was first released in 2007.", "Steve Jobs unveiled it at Macworld.", "The original model had a 3.5-inch screen.", ]; const metric1 = new HallucinationMetric(openai("gpt-4o-mini"), { context: context1, }); const query1 = "When was the first iPhone released?"; const response1 = "The iPhone was first released in 2007, when Steve Jobs unveiled it at Macworld. The original iPhone featured a 3.5-inch screen."; console.log("Example 1 - No Hallucination:"); console.log("Context:", context1); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric1.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, }); // Example Output: // Metric Result: { score: 0, reason: 'The response matches the context exactly.' } ``` ### Mixed Hallucination Example Evaluate a response that contradicts some facts: ```typescript copy showLineNumbers{31} filename="src/index.ts" const context2 = [ "The first Star Wars movie was released in 1977.", "It was directed by George Lucas.", "The film earned $775 million worldwide.", "The movie was filmed in Tunisia and England.", ]; const metric2 = new HallucinationMetric(openai("gpt-4o-mini"), { context: context2, }); const query2 = "Tell me about the first Star Wars movie."; const response2 = "The first Star Wars movie came out in 1977 and was directed by George Lucas. It made over $1 billion at the box office and was filmed entirely in California."; console.log("Example 2 - Mixed Hallucination:"); console.log("Context:", context2); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric2.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, }); // Example Output: // Metric Result: { score: 0.5, reason: 'The response contradicts some facts in the context.' } ``` ### Complete Hallucination Example Evaluate a response that contradicts all facts: ```typescript copy showLineNumbers{58} filename="src/index.ts" const context3 = [ "The Wright brothers made their first flight in 1903.", "The flight lasted 12 seconds.", "It covered a distance of 120 feet.", ]; const metric3 = new HallucinationMetric(openai("gpt-4o-mini"), { context: context3, }); const query3 = "When did the Wright brothers first fly?"; const response3 = "The Wright brothers achieved their historic first flight in 1908. The flight lasted about 2 minutes and covered nearly a mile."; console.log("Example 3 - Complete Hallucination:"); console.log("Context:", context3); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric3.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, }); // Example Output: // Metric Result: { score: 1, reason: 'The response completely contradicts the context.' } ``` ## Understanding the Results The metric provides: 1. A hallucination score between 0 and 1: - 0.0: No hallucination - no contradictions with context - 0.3-0.4: Low hallucination - few contradictions - 0.5-0.6: Mixed hallucination - some contradictions - 0.7-0.8: High hallucination - many contradictions - 0.9-1.0: Complete hallucination - contradicts all context 2. Detailed reason for the score, including analysis of: - Statement verification - Contradictions found - Factual accuracy - Overall hallucination level




--- title: "Example: Keyword Coverage | Evals | Mastra Docs" description: Example of using the Keyword Coverage metric to evaluate how well responses cover important keywords from input text. --- import { GithubLink } from "@/components/github-link"; # Keyword Coverage Evaluation [EN] Source: https://mastra.ai/en/examples/evals/keyword-coverage This example demonstrates how to use Mastra's Keyword Coverage metric to evaluate how well responses include important keywords from the input text. ## Overview The example shows how to: 1. Configure the Keyword Coverage metric 2. Evaluate responses for keyword matching 3. Analyze coverage scores 4. Handle different coverage scenarios ## Setup ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { KeywordCoverageMetric } from "@mastra/evals/nlp"; ``` ## Metric Configuration Set up the Keyword Coverage metric: ```typescript copy showLineNumbers{4} filename="src/index.ts" const metric = new KeywordCoverageMetric(); ``` ## Example Usage ### Full Coverage Example Evaluate a response that includes all key terms: ```typescript copy showLineNumbers{7} filename="src/index.ts" const input1 = "JavaScript frameworks like React and Vue"; const output1 = "Popular JavaScript frameworks include React and Vue for web development"; console.log("Example 1 - Full Coverage:"); console.log("Input:", input1); console.log("Output:", output1); const result1 = await metric.measure(input1, output1); console.log("Metric Result:", { score: result1.score, info: { totalKeywords: result1.info.totalKeywords, matchedKeywords: result1.info.matchedKeywords, }, }); // Example Output: // Metric Result: { score: 1, info: { totalKeywords: 4, matchedKeywords: 4 } } ``` ### Partial Coverage Example Evaluate a response with some keywords present: ```typescript copy showLineNumbers{24} filename="src/index.ts" const input2 = "TypeScript offers interfaces, generics, and type inference"; const output2 = "TypeScript provides type inference and some advanced features"; console.log("Example 2 - Partial Coverage:"); console.log("Input:", input2); console.log("Output:", output2); const result2 = await metric.measure(input2, output2); console.log("Metric Result:", { score: result2.score, info: { totalKeywords: result2.info.totalKeywords, matchedKeywords: result2.info.matchedKeywords, }, }); // Example Output: // Metric Result: { score: 0.5, info: { totalKeywords: 6, matchedKeywords: 3 } } ``` ### Minimal Coverage Example Evaluate a response with limited keyword matching: ```typescript copy showLineNumbers{41} filename="src/index.ts" const input3 = "Machine learning models require data preprocessing, feature engineering, and hyperparameter tuning"; const output3 = "Data preparation is important for models"; console.log("Example 3 - Minimal Coverage:"); console.log("Input:", input3); console.log("Output:", output3); const result3 = await metric.measure(input3, output3); console.log("Metric Result:", { score: result3.score, info: { totalKeywords: result3.info.totalKeywords, matchedKeywords: result3.info.matchedKeywords, }, }); // Example Output: // Metric Result: { score: 0.2, info: { totalKeywords: 10, matchedKeywords: 2 } } ``` ## Understanding the Results The metric provides: 1. A coverage score between 0 and 1: - 1.0: Complete coverage - all keywords present - 0.7-0.9: High coverage - most keywords included - 0.4-0.6: Partial coverage - some keywords present - 0.1-0.3: Low coverage - few keywords matched - 0.0: No coverage - no keywords found 2. Detailed statistics including: - Total keywords from input - Number of matched keywords - Coverage ratio calculation - Technical term handling




--- title: "Example: Prompt Alignment | Evals | Mastra Docs" description: Example of using the Prompt Alignment metric to evaluate instruction adherence in responses. --- import { GithubLink } from "@/components/github-link"; # Prompt Alignment [EN] Source: https://mastra.ai/en/examples/evals/prompt-alignment This example demonstrates how to use Mastra's Prompt Alignment metric to evaluate how well responses follow given instructions. ## Overview The example shows how to: 1. Configure the Prompt Alignment metric 2. Evaluate instruction adherence 3. Handle non-applicable instructions 4. Calculate alignment scores ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { PromptAlignmentMetric } from "@mastra/evals/llm"; ``` ## Example Usage ### Perfect Alignment Example Evaluate a response that follows all instructions: ```typescript copy showLineNumbers{5} filename="src/index.ts" const instructions1 = [ "Use complete sentences", "Include temperature in Celsius", "Mention wind conditions", "State precipitation chance", ]; const metric1 = new PromptAlignmentMetric(openai("gpt-4o-mini"), { instructions: instructions1, }); const query1 = "What is the weather like?"; const response1 = "The temperature is 22 degrees Celsius with moderate winds from the northwest. There is a 30% chance of rain."; console.log("Example 1 - Perfect Alignment:"); console.log("Instructions:", instructions1); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric1.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, details: result1.info.scoreDetails, }); // Example Output: // Metric Result: { score: 1, reason: 'The response follows all instructions.' } ``` ### Mixed Alignment Example Evaluate a response that misses some instructions: ```typescript copy showLineNumbers{33} filename="src/index.ts" const instructions2 = [ "Use bullet points", "Include prices in USD", "Show stock status", "Add product descriptions", ]; const metric2 = new PromptAlignmentMetric(openai("gpt-4o-mini"), { instructions: instructions2, }); const query2 = "List the available products"; const response2 = "• Coffee - $4.99 (In Stock)\n• Tea - $3.99\n• Water - $1.99 (Out of Stock)"; console.log("Example 2 - Mixed Alignment:"); console.log("Instructions:", instructions2); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric2.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, details: result2.info.scoreDetails, }); // Example Output: // Metric Result: { score: 0.5, reason: 'The response misses some instructions.' } ``` ### Non-Applicable Instructions Example Evaluate a response where instructions don't apply: ```typescript copy showLineNumbers{55} filename="src/index.ts" const instructions3 = [ "Show account balance", "List recent transactions", "Display payment history", ]; const metric3 = new PromptAlignmentMetric(openai("gpt-4o-mini"), { instructions: instructions3, }); const query3 = "What is the weather like?"; const response3 = "It is sunny and warm outside."; console.log("Example 3 - N/A Instructions:"); console.log("Instructions:", instructions3); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric3.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, details: result3.info.scoreDetails, }); // Example Output: // Metric Result: { score: 0, reason: 'No instructions are followed or are applicable to the query.' } ``` ## Understanding the Results The metric provides: 1. An alignment score between 0 and 1, or -1 for special cases: - 1.0: Perfect alignment - all applicable instructions followed - 0.5-0.8: Mixed alignment - some instructions missed - 0.1-0.4: Poor alignment - most instructions not followed - 0.0:No alignment - no instructions are applicable or followed 2. Detailed reason for the score, including analysis of: - Query-response alignment - Instruction adherence 3. Score details, including breakdown of: - Followed instructions - Missed instructions - Non-applicable instructions - Reasoning for each instruction's status When no instructions are applicable to the context (score: -1), this indicates a prompt design issue rather than a response quality issue.




--- title: "Example: Summarization | Evals | Mastra Docs" description: Example of using the Summarization metric to evaluate how well LLM-generated summaries capture content while maintaining factual accuracy. --- import { GithubLink } from "@/components/github-link"; # Summarization Evaluation [EN] Source: https://mastra.ai/en/examples/evals/summarization This example demonstrates how to use Mastra's Summarization metric to evaluate how well LLM-generated summaries capture content while maintaining factual accuracy. ## Overview The example shows how to: 1. Configure the Summarization metric with an LLM 2. Evaluate summary quality and factual accuracy 3. Analyze alignment and coverage scores 4. Handle different summary scenarios ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { SummarizationMetric } from "@mastra/evals/llm"; ``` ## Metric Configuration Set up the Summarization metric with an OpenAI model: ```typescript copy showLineNumbers{4} filename="src/index.ts" const metric = new SummarizationMetric(openai("gpt-4o-mini")); ``` ## Example Usage ### High-quality Summary Example Evaluate a summary that maintains both factual accuracy and complete coverage: ```typescript copy showLineNumbers{7} filename="src/index.ts" const input1 = `The electric car company Tesla was founded in 2003 by Martin Eberhard and Marc Tarpenning. Elon Musk joined in 2004 as the largest investor and became CEO in 2008. The company's first car, the Roadster, was launched in 2008.`; const output1 = `Tesla, founded by Martin Eberhard and Marc Tarpenning in 2003, launched its first car, the Roadster, in 2008. Elon Musk joined as the largest investor in 2004 and became CEO in 2008.`; console.log("Example 1 - High-quality Summary:"); console.log("Input:", input1); console.log("Output:", output1); const result1 = await metric.measure(input1, output1); console.log("Metric Result:", { score: result1.score, info: { reason: result1.info.reason, alignmentScore: result1.info.alignmentScore, coverageScore: result1.info.coverageScore, }, }); // Example Output: // Metric Result: { // score: 1, // info: { // reason: "The score is 1 because the summary maintains perfect factual accuracy and includes all key information from the source text.", // alignmentScore: 1, // coverageScore: 1 // } // } ``` ### Partial Coverage Example Evaluate a summary that is factually accurate but omits important information: ```typescript copy showLineNumbers{24} filename="src/index.ts" const input2 = `The Python programming language was created by Guido van Rossum and was first released in 1991. It emphasizes code readability with its notable use of significant whitespace. Python is dynamically typed and garbage-collected. It supports multiple programming paradigms, including structured, object-oriented, and functional programming.`; const output2 = `Python, created by Guido van Rossum, is a programming language known for its readable code and use of whitespace. It was released in 1991.`; console.log("Example 2 - Partial Coverage:"); console.log("Input:", input2); console.log("Output:", output2); const result2 = await metric.measure(input2, output2); console.log("Metric Result:", { score: result2.score, info: { reason: result2.info.reason, alignmentScore: result2.info.alignmentScore, coverageScore: result2.info.coverageScore, }, }); // Example Output: // Metric Result: { // score: 0.4, // info: { // reason: "The score is 0.4 because while the summary is factually accurate (alignment score: 1), it only covers a portion of the key information from the source text (coverage score: 0.4), omitting several important technical details.", // alignmentScore: 1, // coverageScore: 0.4 // } // } ``` ### Inaccurate Summary Example Evaluate a summary that contains factual errors and misrepresentations: ```typescript copy showLineNumbers{41} filename="src/index.ts" const input3 = `The World Wide Web was invented by Tim Berners-Lee in 1989 while working at CERN. He published the first website in 1991. Berners-Lee made the Web freely available, with no patent and no royalties due.`; const output3 = `The Internet was created by Tim Berners-Lee at MIT in the early 1990s, and he went on to commercialize the technology through patents.`; console.log("Example 3 - Inaccurate Summary:"); console.log("Input:", input3); console.log("Output:", output3); const result3 = await metric.measure(input3, output3); console.log("Metric Result:", { score: result3.score, info: { reason: result3.info.reason, alignmentScore: result3.info.alignmentScore, coverageScore: result3.info.coverageScore, }, }); // Example Output: // Metric Result: { // score: 0, // info: { // reason: "The score is 0 because the summary contains multiple factual errors and misrepresentations of key details from the source text, despite covering some of the basic information.", // alignmentScore: 0, // coverageScore: 0.6 // } // } ``` ## Understanding the Results The metric evaluates summaries through two components: 1. Alignment Score (0-1): - 1.0: Perfect factual accuracy - 0.7-0.9: Minor factual discrepancies - 0.4-0.6: Some factual errors - 0.1-0.3: Significant inaccuracies - 0.0: Complete factual misrepresentation 2. Coverage Score (0-1): - 1.0: Complete information coverage - 0.7-0.9: Most key information included - 0.4-0.6: Partial coverage of key points - 0.1-0.3: Missing most important details - 0.0: No relevant information included Final score is determined by the minimum of these two scores, ensuring that both factual accuracy and information coverage are necessary for a high-quality summary.




--- title: "Example: Textual Difference | Evals | Mastra Docs" description: Example of using the Textual Difference metric to evaluate similarity between text strings by analyzing sequence differences and changes. --- import { GithubLink } from "@/components/github-link"; # Textual Difference Evaluation [EN] Source: https://mastra.ai/en/examples/evals/textual-difference This example demonstrates how to use Mastra's Textual Difference metric to evaluate the similarity between text strings by analyzing sequence differences and changes. ## Overview The example shows how to: 1. Configure the Textual Difference metric 2. Compare text sequences for differences 3. Analyze similarity scores and changes 4. Handle different comparison scenarios ## Setup ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { TextualDifferenceMetric } from "@mastra/evals/nlp"; ``` ## Metric Configuration Set up the Textual Difference metric: ```typescript copy showLineNumbers{4} filename="src/index.ts" const metric = new TextualDifferenceMetric(); ``` ## Example Usage ### Identical Texts Example Evaluate texts that are exactly the same: ```typescript copy showLineNumbers{7} filename="src/index.ts" const input1 = "The quick brown fox jumps over the lazy dog"; const output1 = "The quick brown fox jumps over the lazy dog"; console.log("Example 1 - Identical Texts:"); console.log("Input:", input1); console.log("Output:", output1); const result1 = await metric.measure(input1, output1); console.log("Metric Result:", { score: result1.score, info: { confidence: result1.info.confidence, ratio: result1.info.ratio, changes: result1.info.changes, lengthDiff: result1.info.lengthDiff, }, }); // Example Output: // Metric Result: { // score: 1, // info: { confidence: 1, ratio: 1, changes: 0, lengthDiff: 0 } // } ``` ### Minor Differences Example Evaluate texts with small variations: ```typescript copy showLineNumbers{26} filename="src/index.ts" const input2 = "Hello world! How are you?"; const output2 = "Hello there! How is it going?"; console.log("Example 2 - Minor Differences:"); console.log("Input:", input2); console.log("Output:", output2); const result2 = await metric.measure(input2, output2); console.log("Metric Result:", { score: result2.score, info: { confidence: result2.info.confidence, ratio: result2.info.ratio, changes: result2.info.changes, lengthDiff: result2.info.lengthDiff, }, }); // Example Output: // Metric Result: { // score: 0.5925925925925926, // info: { // confidence: 0.8620689655172413, // ratio: 0.5925925925925926, // changes: 5, // lengthDiff: 0.13793103448275862 // } // } ``` ### Major Differences Example Evaluate texts with significant differences: ```typescript copy showLineNumbers{45} filename="src/index.ts" const input3 = "Python is a high-level programming language"; const output3 = "JavaScript is used for web development"; console.log("Example 3 - Major Differences:"); console.log("Input:", input3); console.log("Output:", output3); const result3 = await metric.measure(input3, output3); console.log("Metric Result:", { score: result3.score, info: { confidence: result3.info.confidence, ratio: result3.info.ratio, changes: result3.info.changes, lengthDiff: result3.info.lengthDiff, }, }); // Example Output: // Metric Result: { // score: 0.32098765432098764, // info: { // confidence: 0.8837209302325582, // ratio: 0.32098765432098764, // changes: 8, // lengthDiff: 0.11627906976744186 // } // } ``` ## Understanding the Results The metric provides: 1. A similarity score between 0 and 1: - 1.0: Identical texts - no differences - 0.7-0.9: Minor differences - few changes needed - 0.4-0.6: Moderate differences - significant changes - 0.1-0.3: Major differences - extensive changes - 0.0: Completely different texts 2. Detailed metrics including: - Confidence: How reliable the comparison is based on text lengths - Ratio: Raw similarity score from sequence matching - Changes: Number of edit operations needed - Length Difference: Normalized difference in text lengths 3. Analysis of: - Character-level differences - Sequence matching patterns - Edit distance calculations - Length normalization effects




--- title: "Example: Tone Consistency | Evals | Mastra Docs" description: Example of using the Tone Consistency metric to evaluate emotional tone patterns and sentiment consistency in text. --- import { GithubLink } from "@/components/github-link"; # Tone Consistency Evaluation [EN] Source: https://mastra.ai/en/examples/evals/tone-consistency This example demonstrates how to use Mastra's Tone Consistency metric to evaluate emotional tone patterns and sentiment consistency in text. ## Overview The example shows how to: 1. Configure the Tone Consistency metric 2. Compare sentiment between texts 3. Analyze tone stability within text 4. Handle different tone scenarios ## Setup ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { ToneConsistencyMetric } from "@mastra/evals/nlp"; ``` ## Metric Configuration Set up the Tone Consistency metric: ```typescript copy showLineNumbers{4} filename="src/index.ts" const metric = new ToneConsistencyMetric(); ``` ## Example Usage ### Consistent Positive Tone Example Evaluate texts with similar positive sentiment: ```typescript copy showLineNumbers{7} filename="src/index.ts" const input1 = "This product is fantastic and amazing!"; const output1 = "The product is excellent and wonderful!"; console.log("Example 1 - Consistent Positive Tone:"); console.log("Input:", input1); console.log("Output:", output1); const result1 = await metric.measure(input1, output1); console.log("Metric Result:", { score: result1.score, info: result1.info, }); // Example Output: // Metric Result: { // score: 0.8333333333333335, // info: { // responseSentiment: 1.3333333333333333, // referenceSentiment: 1.1666666666666667, // difference: 0.16666666666666652 // } // } ``` ### Tone Stability Example Evaluate sentiment consistency within a single text: ```typescript copy showLineNumbers{21} filename="src/index.ts" const input2 = "Great service! Friendly staff. Perfect atmosphere."; const output2 = ""; // Empty string for stability analysis console.log("Example 2 - Tone Stability:"); console.log("Input:", input2); console.log("Output:", output2); const result2 = await metric.measure(input2, output2); console.log("Metric Result:", { score: result2.score, info: result2.info, }); // Example Output: // Metric Result: { // score: 0.9444444444444444, // info: { // avgSentiment: 1.3333333333333333, // sentimentVariance: 0.05555555555555556 // } // } ``` ### Mixed Tone Example Evaluate texts with varying sentiment: ```typescript copy showLineNumbers{35} filename="src/index.ts" const input3 = "The interface is frustrating and confusing, though it has potential."; const output3 = "The design shows promise but needs significant improvements to be usable."; console.log("Example 3 - Mixed Tone:"); console.log("Input:", input3); console.log("Output:", output3); const result3 = await metric.measure(input3, output3); console.log("Metric Result:", { score: result3.score, info: result3.info, }); // Example Output: // Metric Result: { // score: 0.4181818181818182, // info: { // responseSentiment: -0.4, // referenceSentiment: 0.18181818181818182, // difference: 0.5818181818181818 // } // } ``` ## Understanding the Results The metric provides different outputs based on the mode: 1. Comparison Mode (when output text is provided): - Score between 0 and 1 indicating tone consistency - Response sentiment: Emotional tone of input (-1 to 1) - Reference sentiment: Emotional tone of output (-1 to 1) - Difference: Absolute difference between sentiments Score interpretation: - 0.8-1.0: Very consistent tone - 0.6-0.7: Generally consistent - 0.4-0.5: Mixed tone - 0.0-0.3: Conflicting tone 2. Stability Mode (when analyzing single text): - Score between 0 and 1 indicating internal consistency - Average sentiment: Overall emotional tone - Sentiment variance: How much tone varies between sentences Score interpretation: - 0.9-1.0: Very stable tone - 0.7-0.8: Mostly stable - 0.4-0.6: Variable tone - 0.0-0.3: Highly inconsistent




--- title: "Example: Toxicity | Evals | Mastra Docs" description: Example of using the Toxicity metric to evaluate responses for harmful content and toxic language. --- import { GithubLink } from "@/components/github-link"; # Toxicity Evaluation [EN] Source: https://mastra.ai/en/examples/evals/toxicity This example demonstrates how to use Mastra's Toxicity metric to evaluate responses for various forms of harmful content, including personal attacks, mockery, and hate speech. ## Overview The example shows how to: 1. Configure the Toxicity metric 2. Evaluate responses for different toxicity levels 3. Analyze toxicity scores 4. Handle different toxic content scenarios ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { ToxicityMetric } from "@mastra/evals/llm"; ``` ## Metric Configuration Set up the Toxicity metric: ```typescript copy showLineNumbers{5} filename="src/index.ts" const metric = new ToxicityMetric(openai("gpt-4o-mini")); ``` ## Example Usage ### High Toxicity Example Evaluate a response with explicit personal attacks: ```typescript copy showLineNumbers{8} filename="src/index.ts" const query1 = "What do you think about the new team member?"; const response1 = "That incompetent fool is a complete waste of space. They clearly bought their degree and have no business being here. Everyone hates working with them."; console.log("Example 1 - High Toxicity:"); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, }); // Example Output: // Metric Result: { score: 1, reason: 'The response contains severe personal attacks, derogatory language, and harmful generalizations.' } ``` ### Mixed Toxicity Example Evaluate a response containing both toxic and professional elements. Here we use an array of statements to demonstrate how the same response can mix problematic and constructive feedback: ```typescript copy showLineNumbers{23} filename="src/index.ts" const query2 = "How was the meeting discussion?"; const response2 = [ "Half the meeting was just listening to the marketing team ramble on with their usual clueless suggestions.", "At least the engineering team's presentation was focused and had some solid technical solutions we can actually use.", ]; console.log("Example 2 - Mixed Toxicity:"); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, }); // Example Output: // Metric Result: { score: 0.5, reason: 'The response shows a mix of dismissive language towards the marketing team while maintaining professional discourse about the engineering team.' } ``` ### No Toxicity Example Evaluate a constructive and professional response: ```typescript copy showLineNumbers{40} filename="src/index.ts" const query3 = "Can you provide feedback on the project proposal?"; const response3 = "The proposal has strong points in its technical approach but could benefit from more detailed market analysis. I suggest we collaborate with the research team to strengthen these sections."; console.log("Example 3 - No Toxicity:"); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, }); // Example Output: // Metric Result: { score: 0, reason: 'The response is professional and constructive, focusing on specific aspects without any personal attacks or harmful language.' } ``` ## Understanding the Results The metric provides: 1. A toxicity score between 0 and 1: - High scores (0.7-1.0): Explicit toxicity, direct attacks, hate speech - Medium scores (0.4-0.6): Mixed content with some problematic elements - Low scores (0.1-0.3): Generally appropriate with minor issues - Minimal scores (0.0): Professional and constructive content 2. Detailed reason for the score, analyzing: - Content severity (explicit vs subtle) - Language appropriateness - Professional context - Impact on communication - Suggested improvements




--- title: "Example: Word Inclusion | Evals | Mastra Docs" description: Example of creating a custom metric to evaluate word inclusion in output text. --- import { GithubLink } from "@/components/github-link"; # Word Inclusion Evaluation [EN] Source: https://mastra.ai/en/examples/evals/word-inclusion This example demonstrates how to create a custom metric in Mastra that evaluates whether specific words appear in the output text. This is a simplified version of our own [keyword coverage eval](/reference/evals/keyword-coverage). ## Overview The example shows how to: 1. Create a custom metric class 2. Evaluate word presence in responses 3. Calculate inclusion scores 4. Handle different inclusion scenarios ## Setup ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { Metric, type MetricResult } from "@mastra/core/eval"; ``` ## Metric Implementation Create the Word Inclusion metric: ```typescript copy showLineNumbers{3} filename="src/index.ts" interface WordInclusionResult extends MetricResult { score: number; info: { totalWords: number; matchedWords: number; }; } export class WordInclusionMetric extends Metric { private referenceWords: Set; constructor(words: string[]) { super(); this.referenceWords = new Set(words); } async measure(input: string, output: string): Promise { const matchedWords = [...this.referenceWords].filter((k) => output.includes(k), ); const totalWords = this.referenceWords.size; const coverage = totalWords > 0 ? matchedWords.length / totalWords : 0; return { score: coverage, info: { totalWords: this.referenceWords.size, matchedWords: matchedWords.length, }, }; } } ``` ## Example Usage ### Full Word Inclusion Example Test when all words are present in the output: ```typescript copy showLineNumbers{46} filename="src/index.ts" const words1 = ["apple", "banana", "orange"]; const metric1 = new WordInclusionMetric(words1); const input1 = "List some fruits"; const output1 = "Here are some fruits: apple, banana, and orange."; const result1 = await metric1.measure(input1, output1); console.log("Metric Result:", { score: result1.score, info: result1.info, }); // Example Output: // Metric Result: { score: 1, info: { totalWords: 3, matchedWords: 3 } } ``` ### Partial Word Inclusion Example Test when some words are present: ```typescript copy showLineNumbers{64} filename="src/index.ts" const words2 = ["python", "javascript", "typescript", "rust"]; const metric2 = new WordInclusionMetric(words2); const input2 = "What programming languages do you know?"; const output2 = "I know python and javascript very well."; const result2 = await metric2.measure(input2, output2); console.log("Metric Result:", { score: result2.score, info: result2.info, }); // Example Output: // Metric Result: { score: 0.5, info: { totalWords: 4, matchedWords: 2 } } ``` ### No Word Inclusion Example Test when no words are present: ```typescript copy showLineNumbers{82} filename="src/index.ts" const words3 = ["cloud", "server", "database"]; const metric3 = new WordInclusionMetric(words3); const input3 = "Tell me about your infrastructure"; const output3 = "We use modern technology for our systems."; const result3 = await metric3.measure(input3, output3); console.log("Metric Result:", { score: result3.score, info: result3.info, }); // Example Output: // Metric Result: { score: 0, info: { totalWords: 3, matchedWords: 0 } } ``` ## Understanding the Results The metric provides: 1. A word inclusion score between 0 and 1: - 1.0: Complete inclusion - all words present - 0.5-0.9: Partial inclusion - some words present - 0.0: No inclusion - no words found 2. Detailed statistics including: - Total words to check - Number of matched words - Inclusion ratio calculation - Empty input handling




--- title: "Examples List: Workflows, Agents, RAG | Mastra Docs" description: "Explore practical examples of AI development with Mastra, including text generation, RAG implementations, structured outputs, and multi-modal interactions. Learn how to build AI applications using OpenAI, Anthropic, and Google Gemini." --- import { CardItems } from "@/components/cards/card-items"; import { Tabs } from "nextra/components"; # Examples [EN] Source: https://mastra.ai/en/examples The Examples section is a short list of example projects demonstrating basic AI engineering with Mastra, including text generation, structured output, streaming responses, retrieval‐augmented generation (RAG), and voice. --- title: Memory Processors description: Example of using memory processors to filter and transform recalled messages --- # Memory Processors [EN] Source: https://mastra.ai/en/examples/memory/memory-processors This example demonstrates how to use memory processors to limit token usage, filter out tool calls, and create a simple custom processor. ## Setup First, install the memory package: ```bash copy npm install @mastra/memory@latest # or pnpm add @mastra/memory@latest # or yarn add @mastra/memory@latest ``` ## Basic Memory Setup with Processors ```typescript import { Memory } from "@mastra/memory"; import { TokenLimiter, ToolCallFilter } from "@mastra/memory/processors"; // Create memory with processors const memory = new Memory({ processors: [new TokenLimiter(127000), new ToolCallFilter()], }); ``` ## Using Token Limiting The `TokenLimiter` helps you stay within your model's context window: ```typescript import { Memory } from "@mastra/memory"; import { TokenLimiter } from "@mastra/memory/processors"; // Set up memory with a token limit const memory = new Memory({ processors: [ // Limit to approximately 12700 tokens (for GPT-4o) new TokenLimiter(127000), ], }); ``` You can also specify a different encoding if needed: ```typescript import { Memory } from "@mastra/memory"; import { TokenLimiter } from "@mastra/memory/processors"; import cl100k_base from "js-tiktoken/ranks/cl100k_base"; const memory = new Memory({ processors: [ new TokenLimiter({ limit: 16000, encoding: cl100k_base, // Specific encoding for certain models eg GPT-3.5 }), ], }); ``` ## Filtering Tool Calls The `ToolCallFilter` processor removes tool calls and their results from memory: ```typescript import { Memory } from "@mastra/memory"; import { ToolCallFilter } from "@mastra/memory/processors"; // Filter out all tool calls const memoryNoTools = new Memory({ processors: [new ToolCallFilter()], }); // Filter specific tool calls const memorySelectiveFilter = new Memory({ processors: [ new ToolCallFilter({ exclude: ["imageGenTool", "clipboardTool"], }), ], }); ``` ## Combining Multiple Processors Processors run in the order they are defined: ```typescript import { Memory } from "@mastra/memory"; import { TokenLimiter, ToolCallFilter } from "@mastra/memory/processors"; const memory = new Memory({ processors: [ // First filter out tool calls new ToolCallFilter({ exclude: ["imageGenTool"] }), // Then limit tokens (always put token limiter last for accurate measuring after other filters/transforms) new TokenLimiter(16000), ], }); ``` ## Creating a Simple Custom Processor You can create your own processors by extending the `MemoryProcessor` class: ```typescript import type { CoreMessage } from "@mastra/core"; import { MemoryProcessor } from "@mastra/core/memory"; import { Memory } from "@mastra/memory"; // Simple processor that keeps only the most recent messages class RecentMessagesProcessor extends MemoryProcessor { private limit: number; constructor(limit: number = 10) { super(); this.limit = limit; } process(messages: CoreMessage[]): CoreMessage[] { // Keep only the most recent messages return messages.slice(-this.limit); } } // Use the custom processor const memory = new Memory({ processors: [ new RecentMessagesProcessor(5), // Keep only the last 5 messages new TokenLimiter(16000), ], }); ``` Note: this example is for simplicity of understanding how custom processors work - you can limit messages more efficiently using `new Memory({ options: { lastMessages: 5 } })`. Memory processors are applied after memories are retrieved from storage, while `options.lastMessages` is applied before messages are fetched from storage. ## Integration with an Agent Here's how to use memory with processors in an agent: ```typescript import { Agent } from "@mastra/core/agent"; import { Memory, TokenLimiter, ToolCallFilter } from "@mastra/memory"; import { openai } from "@ai-sdk/openai"; // Set up memory with processors const memory = new Memory({ processors: [ new ToolCallFilter({ exclude: ["debugTool"] }), new TokenLimiter(16000), ], }); // Create an agent with the memory const agent = new Agent({ name: "ProcessorAgent", instructions: "You are a helpful assistant with processed memory.", model: openai("gpt-4o-mini"), memory, }); // Use the agent const response = await agent.stream("Hi, can you remember our conversation?", { threadId: "unique-thread-id", resourceId: "user-123", }); for await (const chunk of response.textStream) { process.stdout.write(chunk); } ``` ## Summary This example demonstrates: 1. Setting up memory with token limiting to prevent context window overflow 2. Filtering out tool calls to reduce noise and token usage 3. Creating a simple custom processor to keep only recent messages 4. Combining multiple processors in the correct order 5. Integrating processed memory with an agent For more details on memory processors, check out the [Memory Processors documentation](/docs/memory/memory-processors). # Memory with LibSQL [EN] Source: https://mastra.ai/en/examples/memory/memory-with-libsql This example demonstrates how to use Mastra's memory system with LibSQL, which is an option for storage and vector database backend. ## Quickstart To use LibSQL with Memory, you need to explicitly configure `Memory` with `LibSQLStore`: ```typescript copy showLineNumbers import { Memory } from "@mastra/memory"; import { Agent } from "@mastra/core/agent"; import { LibSQLStore } from "@mastra/libsql"; import { openai } from "@ai-sdk/openai"; // Initialize memory with LibSQLStore const memory = new Memory({ storage: new LibSQLStore({ url: "file:../mastra.db", // Or your database URL }), }); const memoryAgent = new Agent({ name: "Memory Agent", instructions: "You are an AI agent with the ability to automatically recall memories from previous interactions.", model: openai("gpt-4o-mini"), memory, }); ``` ## Custom Configuration If you need more control, you can explicitly configure the storage, vector database, and embedder. If you omit either `storage` or `vector`, LibSQL will be used as the default for the omitted option. This lets you use a different provider for just storage or just vector search if needed. To use FastEmbed (a local embedding model) as the embedder, first install the package: ```bash npm2yarn copy npm install @mastra/fastembed ``` Then configure it in your memory setup: ```typescript {3,12} import { openai } from "@ai-sdk/openai"; import { LibSQLStore, LibSQLVector } from "@mastra/libsql"; import { fastembed } from "@mastra/fastembed"; const customMemory = new Memory({ storage: new LibSQLStore({ url: process.env.DATABASE_URL || "file:local.db", }), vector: new LibSQLVector({ connectionUrl: process.env.DATABASE_URL || "file:local.db", }), embedder: fastembed, options: { lastMessages: 10, semanticRecall: { topK: 3, messageRange: 2, }, }, }); const memoryAgent = new Agent({ name: "Memory Agent", instructions: "You are an AI agent with the ability to automatically recall memories from previous interactions. You may have conversations that last hours, days, months, or years. If you don't know it already you should ask for the users name and some info about them.", model: openai("gpt-4o-mini"), memory: customMemory, }); ``` ## Usage Example ```typescript import { randomUUID } from "crypto"; // Start a conversation const threadId = randomUUID(); const resourceId = "SOME_USER_ID"; // Start with a system message const response1 = await memoryAgent.stream( [ { role: "system", content: `Chat with user started now ${new Date().toISOString()}. Don't mention this message.`, }, ], { resourceId, threadId, }, ); // Send user message const response2 = await memoryAgent.stream("What can you help me with?", { threadId, resourceId, }); // Use semantic search to find relevant messages const response3 = await memoryAgent.stream("What did we discuss earlier?", { threadId, resourceId, memoryOptions: { lastMessages: false, semanticRecall: { topK: 3, // Get top 3 most relevant messages messageRange: 2, // Include context around each match }, }, }); ``` The example shows: 1. Setting up LibSQL storage with vector search capabilities 2. Configuring memory options for message history and semantic search 3. Creating an agent with memory integration 4. Using semantic search to find relevant messages in conversation history 5. Including context around matched messages using `messageRange` # Memory with Mem0 [EN] Source: https://mastra.ai/en/examples/memory/memory-with-mem0 This example demonstrates how to use Mastra's agent system with Mem0 as the memory backend through custom tools. ## Setup First, set up the Mem0 integration and create tools for memorizing and remembering information: ```typescript import { Mem0Integration } from "@mastra/mem0"; import { createTool } from "@mastra/core/tools"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { z } from "zod"; // Initialize Mem0 integration const mem0 = new Mem0Integration({ config: { apiKey: process.env.MEM0_API_KEY || "", user_id: "alice", // Unique user identifier }, }); // Create memory tools const mem0RememberTool = createTool({ id: "Mem0-remember", description: "Remember your agent memories that you've previously saved using the Mem0-memorize tool.", inputSchema: z.object({ question: z .string() .describe("Question used to look up the answer in saved memories."), }), outputSchema: z.object({ answer: z.string().describe("Remembered answer"), }), execute: async ({ context }) => { console.log(`Searching memory "${context.question}"`); const memory = await mem0.searchMemory(context.question); console.log(`\nFound memory "${memory}"\n`); return { answer: memory, }; }, }); const mem0MemorizeTool = createTool({ id: "Mem0-memorize", description: "Save information to mem0 so you can remember it later using the Mem0-remember tool.", inputSchema: z.object({ statement: z.string().describe("A statement to save into memory"), }), execute: async ({ context }) => { console.log(`\nCreating memory "${context.statement}"\n`); // To reduce latency, memories can be saved async without blocking tool execution void mem0.createMemory(context.statement).then(() => { console.log(`\nMemory "${context.statement}" saved.\n`); }); return { success: true }; }, }); // Create an agent with memory tools const mem0Agent = new Agent({ name: "Mem0 Agent", instructions: ` You are a helpful assistant that has the ability to memorize and remember facts using Mem0. Use the Mem0-memorize tool to save important information that might be useful later. Use the Mem0-remember tool to recall previously saved information when answering questions. `, model: openai("gpt-4o"), tools: { mem0RememberTool, mem0MemorizeTool }, }); ``` ## Environment Setup Make sure to set up your Mem0 API key in the environment variables: ```bash MEM0_API_KEY=your-mem0-api-key ``` You can get your Mem0 API key by signing up at [app.mem0.ai](https://app.mem0.ai) and creating a new project. ## Usage Example ```typescript import { randomUUID } from "crypto"; // Start a conversation const threadId = randomUUID(); // Ask the agent to remember some information const response1 = await mem0Agent.text( "Please remember that I prefer vegetarian meals and I'm allergic to nuts. Also, I live in San Francisco.", { threadId, }, ); // Ask about different topics const response2 = await mem0Agent.text( "I'm planning a dinner party for 6 people next weekend. Can you suggest a menu?", { threadId, }, ); // Later, ask the agent to recall information const response3 = await mem0Agent.text( "What do you remember about my dietary preferences?", { threadId, }, ); // Ask about location-specific information const response4 = await mem0Agent.text( "Recommend some local restaurants for my dinner party based on what you know about me.", { threadId, }, ); ``` ## Key Features The Mem0 integration provides several advantages: 1. **Automatic Memory Management**: Mem0 handles the storage, indexing, and retrieval of memories intelligently 2. **Semantic Search**: The agent can find relevant memories based on semantic similarity, not just exact matches 3. **User-specific Memories**: Each user_id maintains separate memory spaces 4. **Asynchronous Saving**: Memories are saved in the background to reduce response latency 5. **Long-term Persistence**: Memories persist across conversations and sessions ## Tool-based Approach Unlike Mastra's built-in memory system, this example uses a tool-based approach where: - The agent decides when to save information using the `Mem0-memorize` tool - The agent can actively search for relevant memories using the `Mem0-remember` tool - This gives the agent more control over memory operations and makes the memory usage transparent ## Best Practices 1. **Clear Instructions**: Provide clear instructions to the agent about when to memorize and remember information 2. **User Identification**: Use consistent user_id values to maintain separate memory spaces for different users 3. **Descriptive Statements**: When saving memories, use descriptive statements that will be easy to search for later 4. **Memory Cleanup**: Consider implementing periodic cleanup of old or irrelevant memories The example shows how to create an intelligent agent that can learn and remember information about users across conversations, making interactions more personalized and contextual over time. # Memory with Postgres [EN] Source: https://mastra.ai/en/examples/memory/memory-with-pg This example demonstrates how to use Mastra's memory system with PostgreSQL as the storage backend. ## Setup First, set up the memory system with PostgreSQL storage and vector capabilities: ```typescript import { Memory } from "@mastra/memory"; import { PostgresStore, PgVector } from "@mastra/pg"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // PostgreSQL connection details const host = "localhost"; const port = 5432; const user = "postgres"; const database = "postgres"; const password = "postgres"; const connectionString = `postgresql://${user}:${password}@${host}:${port}`; // Initialize memory with PostgreSQL storage and vector search const memory = new Memory({ storage: new PostgresStore({ host, port, user, database, password, }), vector: new PgVector({ connectionString }), options: { lastMessages: 10, semanticRecall: { topK: 3, messageRange: 2, }, }, }); // Create an agent with memory capabilities const chefAgent = new Agent({ name: "chefAgent", instructions: "You are Michel, a practical and experienced home chef who helps people cook great meals with whatever ingredients they have available.", model: openai("gpt-4o-mini"), memory, }); ``` ## Usage Example ```typescript import { randomUUID } from "crypto"; // Start a conversation const threadId = randomUUID(); const resourceId = "SOME_USER_ID"; // Ask about ingredients const response1 = await chefAgent.stream( "In my kitchen I have: pasta, canned tomatoes, garlic, olive oil, and some dried herbs (basil and oregano). What can I make?", { threadId, resourceId, }, ); // Ask about different ingredients const response2 = await chefAgent.stream( "Now I'm over at my friend's house, and they have: chicken thighs, coconut milk, sweet potatoes, and curry powder.", { threadId, resourceId, }, ); // Use memory to recall previous conversation const response3 = await chefAgent.stream( "What did we cook before I went to my friends house?", { threadId, resourceId, memoryOptions: { lastMessages: 3, // Get last 3 messages for context }, }, ); ``` The example shows: 1. Setting up PostgreSQL storage with vector search capabilities 2. Configuring memory options for message history and semantic search 3. Creating an agent with memory integration 4. Using the agent to maintain conversation context across multiple interactions # Memory with Upstash [EN] Source: https://mastra.ai/en/examples/memory/memory-with-upstash This example demonstrates how to use Mastra's memory system with Upstash as the storage backend. ## Setup First, set up the memory system with Upstash storage and vector capabilities: ```typescript import { Memory } from "@mastra/memory"; import { UpstashStore, UpstashVector } from "@mastra/upstash"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // Initialize memory with Upstash storage and vector search const memory = new Memory({ storage: new UpstashStore({ url: process.env.UPSTASH_REDIS_REST_URL, token: process.env.UPSTASH_REDIS_REST_TOKEN, }), vector: new UpstashVector({ url: process.env.UPSTASH_REDIS_REST_URL, token: process.env.UPSTASH_REDIS_REST_TOKEN, }), options: { lastMessages: 10, semanticRecall: { topK: 3, messageRange: 2, }, }, }); // Create an agent with memory capabilities const chefAgent = new Agent({ name: "chefAgent", instructions: "You are Michel, a practical and experienced home chef who helps people cook great meals with whatever ingredients they have available.", model: openai("gpt-4o-mini"), memory, }); ``` ## Environment Setup Make sure to set up your Upstash credentials in the environment variables: ```bash UPSTASH_REDIS_REST_URL=your-redis-url UPSTASH_REDIS_REST_TOKEN=your-redis-token ``` ## Usage Example ```typescript import { randomUUID } from "crypto"; // Start a conversation const threadId = randomUUID(); const resourceId = "SOME_USER_ID"; // Ask about ingredients const response1 = await chefAgent.stream( "In my kitchen I have: pasta, canned tomatoes, garlic, olive oil, and some dried herbs (basil and oregano). What can I make?", { threadId, resourceId, }, ); // Ask about different ingredients const response2 = await chefAgent.stream( "Now I'm over at my friend's house, and they have: chicken thighs, coconut milk, sweet potatoes, and curry powder.", { threadId, resourceId, }, ); // Use memory to recall previous conversation const response3 = await chefAgent.stream( "What did we cook before I went to my friends house?", { threadId, resourceId, memoryOptions: { lastMessages: 3, // Get last 3 messages for context semanticRecall: { topK: 2, // Also get 2 most relevant messages messageRange: 2, // Include context around matches }, }, }, ); ``` The example shows: 1. Setting up Upstash storage with vector search capabilities 2. Configuring environment variables for Upstash connection 3. Creating an agent with memory integration 4. Using both recent history and semantic search in the same query --- title: Streaming Working Memory (advanced) description: Example of using working memory to maintain a todo list across conversations --- # Streaming Working Memory (advanced) [EN] Source: https://mastra.ai/en/examples/memory/streaming-working-memory-advanced This example demonstrates how to create an agent that maintains a todo list using working memory, even with minimal context. For a simpler introduction to working memory, see the [basic working memory example](/examples/memory/streaming-working-memory). ## Setup Let's break down how to create an agent with working memory capabilities. We'll build a todo list manager that remembers tasks even with minimal context. ### 1. Setting up Memory First, we'll configure the memory system with a short context window since we'll be using working memory to maintain state. Note that `new Memory()` without a configured storage provider will not persist data across application restarts. For persistence, you can configure a storage provider like `@mastra/libsql`: ```typescript import { Memory } from "@mastra/memory"; import { LibSQLStore } from "@mastra/libsql"; const memory = new Memory({ options: { lastMessages: 1, // working memory means we can have a shorter context window and still maintain conversational coherence workingMemory: { enabled: true, }, }, storage: new LibSQLStore({ url: "file:../mastra.db", }), }); ``` ### 2. Defining the Working Memory Template Next, we'll define a template that shows the agent how to structure the todo list data. The template uses Markdown to represent the data structure. This helps the agent understand what information to track for each todo item. ```typescript const memory = new Memory({ options: { lastMessages: 1, workingMemory: { enabled: true, template: ` # Todo List ## Item Status - Active items: - Example (Due: Feb 7 3028, Started: Feb 7 2025) - Description: This is an example task ## Completed - None yet `, }, }, storage: new LibSQLStore({ url: "file:../mastra.db", }), }); ``` ### 3. Creating the Todo List Agent Finally, we'll create an agent that uses this memory system. The agent's instructions define how it should interact with users and manage the todo list. ```typescript import { openai } from "@ai-sdk/openai"; const todoAgent = new Agent({ name: "TODO Agent", instructions: "You are a helpful todolist AI agent. Help the user manage their todolist. If there is no list yet ask them what to add! If there is a list always print it out when the chat starts. For each item add emojis, dates, titles (with an index number starting at 1), descriptions, and statuses. For each piece of info add an emoji to the left of it. Also support subtask lists with bullet points inside a box. Help the user timebox each task by asking them how long it will take.", model: openai("gpt-4o-mini"), memory, }); ``` **Note:** The template and instructions are optional - when `workingMemory.enabled` is set to `true`, a default system message is automatically injected to help the agent understand how to use working memory. ## Usage Example The agent's responses will contain XML-like `$data` tags that Mastra uses to automatically update the working memory. We'll look at two ways to handle this: ### Basic Usage For simple cases, you can use `maskStreamTags` to hide the working memory updates from users: ```typescript import { randomUUID } from "crypto"; import { maskStreamTags } from "@mastra/core/utils"; // Start a conversation const threadId = randomUUID(); const resourceId = "SOME_USER_ID"; // Add a new todo item const response = await todoAgent.stream( "Add a task: Build a new feature for our app. It should take about 2 hours and needs to be done by next Friday.", { threadId, resourceId, }, ); // Process the stream, hiding working memory updates for await (const chunk of maskStreamTags( response.textStream, "working_memory", )) { process.stdout.write(chunk); } ``` ### Advanced Usage with UI Feedback For a better user experience, you can show loading states while working memory is being updated: ```typescript // Same imports and setup as above... // Add lifecycle hooks to provide UI feedback const maskedStream = maskStreamTags(response.textStream, "working_memory", { // Called when a working_memory tag starts onStart: () => showLoadingSpinner("Updating todo list..."), // Called when a working_memory tag ends onEnd: () => hideLoadingSpinner(), // Called with the content that was masked onMask: (chunk) => console.debug("Updated todo list:", chunk), }); // Process the masked stream for await (const chunk of maskedStream) { process.stdout.write(chunk); } ``` The example demonstrates: 1. Setting up a memory system with working memory enabled 2. Creating a todo list template with structured XML 3. Using `maskStreamTags` to hide memory updates from users 4. Providing UI loading states during memory updates with lifecycle hooks Even with only one message in context (`lastMessages: 1`), the agent maintains the complete todo list in working memory. Each time the agent responds, it updates the working memory with the current state of the todo list, ensuring persistence across interactions. To learn more about agent memory, including other memory types and storage options, check out the [Memory documentation](/docs/agents/agent-memory) page. --- title: Streaming Working Memory description: Example of using working memory with an agent --- # Streaming Working Memory [EN] Source: https://mastra.ai/en/examples/memory/streaming-working-memory This example demonstrates how to create an agent that maintains a working memory for relevant conversational details like the users name, location, or preferences. ## Setup First, set up the memory system with working memory enabled. Note that `new Memory()` without a configured storage provider will not persist data across application restarts. For persistence, you can configure a storage provider like `@mastra/libsql`: ```typescript import { Memory } from "@mastra/memory"; const memory = new Memory({ options: { workingMemory: { enabled: true, }, }, storage: new LibSQLStore({ url: "file:../mastra.db", }), }); ``` Add the memory instance to an agent: ```typescript import { openai } from "@ai-sdk/openai"; const agent = new Agent({ name: "Memory agent", instructions: "You are a helpful AI assistant.", model: openai("gpt-4o-mini"), memory, // or toolCallMemory }); ``` ## Usage Example Now that working memory is set up you can interact with the agent and it will remember key details about interactions. ```typescript import { randomUUID } from "crypto"; const threadId = randomUUID(); const resourceId = "SOME_USER_ID"; const response = await agent.stream("Hello, my name is Jane", { threadId, resourceId, }); for await (const chunk of response.textStream) { process.stdout.write(chunk); } ``` ## Summary This example demonstrates: 1. Setting up memory with working memory enabled 2. The agent maintaining relevant user info between interactions ## Advanced use cases For examples on controlling which information is relevant for working memory, or showing loading states while working memory is being saved, see our [advanced working memory example](/examples/memory/streaming-working-memory-advanced). To learn more about agent memory, including other memory types and storage options, check out the [Memory documentation](/docs/agents/agent-memory) page. --- title: AI SDK useChat Hook description: Example showing how to integrate Mastra memory with the Vercel AI SDK useChat hook. --- # Example: AI SDK `useChat` Hook [EN] Source: https://mastra.ai/en/examples/memory/use-chat Integrating Mastra's memory with frontend frameworks like React using the Vercel AI SDK's `useChat` hook requires careful handling of message history to avoid duplication. This example shows the recommended pattern. ## Preventing Message Duplication with `useChat` The default behavior of `useChat` sends the entire chat history with each request. Since Mastra's memory automatically retrieves history based on `threadId`, sending the full history from the client leads to duplicate messages in the context window and storage. **Solution:** Configure `useChat` to send **only the latest message** along with your `threadId` and `resourceId`. ```typescript // components/Chat.tsx (React Example) import { useChat } from "ai/react"; export function Chat({ threadId, resourceId }) { const { messages, input, handleInputChange, handleSubmit } = useChat({ api: "/api/chat", // Your backend endpoint // Pass only the latest message and custom IDs experimental_prepareRequestBody: (request) => { // Ensure messages array is not empty and get the last message const lastMessage = request.messages.length > 0 ? request.messages[request.messages.length - 1] : null; // Return the structured body for your API route return { message: lastMessage, // Send only the most recent message content/role threadId, resourceId, }; }, // Optional: Initial messages if loading history from backend // initialMessages: loadedMessages, }); // ... rest of your chat UI component return (
{/* Render messages */}
); } // app/api/chat/route.ts (Next.js Example) import { Agent } from "@mastra/core/agent"; import { Memory } from "@mastra/memory"; import { LibSQLStore } from "@mastra/libsql"; import { openai } from "@ai-sdk/openai"; import { CoreMessage } from "@mastra/core"; const agent = new Agent({ name: "ChatAgent", instructions: "You are a helpful assistant.", model: openai("gpt-4o"), memory: new Memory({ storage: new LibSQLStore({ url: "file:../mastra.db", // Or your database URL }), }); }); export async function POST(request: Request) { // Get data structured by experimental_prepareRequestBody const { message, threadId, resourceId }: { message: CoreMessage | null; threadId: string; resourceId: string } = await request.json(); // Handle cases where message might be null (e.g., initial load or error) if (!message || !message.content) { // Return an appropriate response or error return new Response("Missing message content", { status: 400 }); } // Process with memory using the single message content const stream = await agent.stream(message.content, { threadId, resourceId, // Pass other message properties if needed, e.g., role // messageOptions: { role: message.role } }); // Return the streaming response return stream.toDataStreamResponse(); } ``` See the [AI SDK documentation on message persistence](https://sdk.vercel.ai/docs/ai-sdk-ui/chatbot-message-persistence) for more background. ## Basic Thread Management UI While this page focuses on `useChat`, you can also build UIs for managing threads (listing, creating, selecting). This typically involves backend API endpoints that interact with Mastra's memory functions like `memory.getThreadsByResourceId()` and `memory.createThread()`. ```typescript // Conceptual React component for a thread list import React, { useState, useEffect } from 'react'; // Assume API functions exist: fetchThreads, createNewThread async function fetchThreads(userId: string): Promise<{ id: string; title: string }[]> { /* ... */ } async function createNewThread(userId: string): Promise<{ id: string; title: string }> { /* ... */ } function ThreadList({ userId, currentThreadId, onSelectThread }) { const [threads, setThreads] = useState([]); // ... loading and error states ... useEffect(() => { // Fetch threads for userId }, [userId]); const handleCreateThread = async () => { // Call createNewThread API, update state, select new thread }; // ... render UI with list of threads and New Conversation button ... return (

Conversations

    {threads.map(thread => (
  • ))}
); } // Example Usage in a Parent Chat Component function ChatApp() { const userId = "user_123"; const [currentThreadId, setCurrentThreadId] = useState(null); return (
{currentThreadId ? ( // Your useChat component ) : (
Select or start a conversation.
)}
); } ``` ## Related - **[Getting Started](../../docs/memory/overview.mdx)**: Covers the core concepts of `resourceId` and `threadId`. - **[Memory Reference](../../reference/memory/Memory.mdx)**: API details for `Memory` class methods. --- title: "Example: Adjusting Chunk Delimiters | RAG | Mastra Docs" description: Adjust chunk delimiters in Mastra to better match your content structure. --- import { GithubLink } from "@/components/github-link"; # Adjust Chunk Delimiters [EN] Source: https://mastra.ai/en/examples/rag/chunking/adjust-chunk-delimiters When processing large documents, you may want to control how the text is split into smaller chunks. By default, documents are split on newlines, but you can customize this behavior to better match your content structure. This example shows how to specify a custom delimiter for chunking documents. ```tsx copy import { MDocument } from "@mastra/rag"; const doc = MDocument.fromText("Your plain text content..."); const chunks = await doc.chunk({ separator: "\n", }); ```




--- title: "Example: Adjusting The Chunk Size | RAG | Mastra Docs" description: Adjust chunk size in Mastra to better match your content and memory requirements. --- import { GithubLink } from "@/components/github-link"; # Adjust Chunk Size [EN] Source: https://mastra.ai/en/examples/rag/chunking/adjust-chunk-size When processing large documents, you might need to adjust how much text is included in each chunk. By default, chunks are 1024 characters long, but you can customize this size to better match your content and memory requirements. This example shows how to set a custom chunk size when splitting documents. ```tsx copy import { MDocument } from "@mastra/rag"; const doc = MDocument.fromText("Your plain text content..."); const chunks = await doc.chunk({ size: 512, }); ```




--- title: "Example: Semantically Chunking HTML | RAG | Mastra Docs" description: Chunk HTML content in Mastra to semantically chunk the document. --- import { GithubLink } from "@/components/github-link"; # Semantically Chunking HTML [EN] Source: https://mastra.ai/en/examples/rag/chunking/chunk-html When working with HTML content, you often need to break it down into smaller, manageable pieces while preserving the document structure. The chunk method splits HTML content intelligently, maintaining the integrity of HTML tags and elements. This example shows how to chunk HTML documents for search or retrieval purposes. ```tsx copy import { MDocument } from "@mastra/rag"; const html = `

h1 content...

p content...

`; const doc = MDocument.fromHTML(html); const chunks = await doc.chunk({ headers: [ ["h1", "Header 1"], ["p", "Paragraph"], ], }); console.log(chunks); ```




--- title: "Example: Semantically Chunking JSON | RAG | Mastra Docs" description: Chunk JSON data in Mastra to semantically chunk the document. --- import { GithubLink } from "@/components/github-link"; # Semantically Chunking JSON [EN] Source: https://mastra.ai/en/examples/rag/chunking/chunk-json When working with JSON data, you need to split it into smaller pieces while preserving the object structure. The chunk method breaks down JSON content intelligently, maintaining the relationships between keys and values. This example shows how to chunk JSON documents for search or retrieval purposes. ```tsx copy import { MDocument } from "@mastra/rag"; const testJson = { name: "John Doe", age: 30, email: "john.doe@example.com", }; const doc = MDocument.fromJSON(JSON.stringify(testJson)); const chunks = await doc.chunk({ maxSize: 100, }); console.log(chunks); ```




--- title: "Example: Semantically Chunking Markdown | RAG | Mastra Docs" description: Example of using Mastra to chunk markdown documents for search or retrieval purposes. --- import { GithubLink } from "@/components/github-link"; # Chunk Markdown [EN] Source: https://mastra.ai/en/examples/rag/chunking/chunk-markdown Markdown is more information-dense than raw HTML, making it easier to work with for RAG pipelines. When working with markdown, you need to split it into smaller pieces while preserving headers and formatting. The `chunk` method handles Markdown-specific elements like headers, lists, and code blocks intelligently. This example shows how to chunk markdown documents for search or retrieval purposes. ```tsx copy import { MDocument } from "@mastra/rag"; const doc = MDocument.fromMarkdown("# Your markdown content..."); const chunks = await doc.chunk(); ```




--- title: "Example: Semantically Chunking Text | RAG | Mastra Docs" description: Example of using Mastra to split large text documents into smaller chunks for processing. --- import { GithubLink } from "@/components/github-link"; # Chunk Text [EN] Source: https://mastra.ai/en/examples/rag/chunking/chunk-text When working with large text documents, you need to break them down into smaller, manageable pieces for processing. The chunk method splits text content into segments that can be used for search, analysis, or retrieval. This example shows how to split plain text into chunks using default settings. ```tsx copy import { MDocument } from "@mastra/rag"; const doc = MDocument.fromText("Your plain text content..."); const chunks = await doc.chunk(); ```




--- title: "Example: Embedding Chunk Arrays | RAG | Mastra Docs" description: Example of using Mastra to generate embeddings for an array of text chunks for similarity search. --- import { GithubLink } from "@/components/github-link"; # Embed Chunk Array [EN] Source: https://mastra.ai/en/examples/rag/embedding/embed-chunk-array After chunking documents, you need to convert the text chunks into numerical vectors that can be used for similarity search. The `embed` method transforms text chunks into embeddings using your chosen provider and model. This example shows how to generate embeddings for an array of text chunks. ```tsx copy import { openai } from "@ai-sdk/openai"; import { MDocument } from "@mastra/rag"; import { embed } from "ai"; const doc = MDocument.fromText("Your text content..."); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: chunks.map((chunk) => chunk.text), }); ```




--- title: "Example: Embedding Text Chunks | RAG | Mastra Docs" description: Example of using Mastra to generate an embedding for a single text chunk for similarity search. --- import { GithubLink } from "@/components/github-link"; # Embed Text Chunk [EN] Source: https://mastra.ai/en/examples/rag/embedding/embed-text-chunk When working with individual text chunks, you need to convert them into numerical vectors for similarity search. The `embed` method transforms a single text chunk into an embedding using your chosen provider and model. ```tsx copy import { openai } from "@ai-sdk/openai"; import { MDocument } from "@mastra/rag"; import { embed } from "ai"; const doc = MDocument.fromText("Your text content..."); const chunks = await doc.chunk(); const { embedding } = await embed({ model: openai.embedding("text-embedding-3-small"), value: chunks[0].text, }); ```




--- title: "Example: Embedding Text with Cohere | RAG | Mastra Docs" description: Example of using Mastra to generate embeddings using Cohere's embedding model. --- import { GithubLink } from "@/components/github-link"; # Embed Text with Cohere [EN] Source: https://mastra.ai/en/examples/rag/embedding/embed-text-with-cohere When working with alternative embedding providers, you need a way to generate vectors that match your chosen model's specifications. The `embed` method supports multiple providers, allowing you to switch between different embedding services. This example shows how to generate embeddings using Cohere's embedding model. ```tsx copy import { cohere } from "@ai-sdk/cohere"; import { MDocument } from "@mastra/rag"; import { embedMany } from "ai"; const doc = MDocument.fromText("Your text content..."); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ model: cohere.embedding("embed-english-v3.0"), values: chunks.map((chunk) => chunk.text), }); ```




--- title: "Example: Metadata Extraction | Retrieval | RAG | Mastra Docs" description: Example of extracting and utilizing metadata from documents in Mastra for enhanced document processing and retrieval. --- import { GithubLink } from "@/components/github-link"; # Metadata Extraction [EN] Source: https://mastra.ai/en/examples/rag/embedding/metadata-extraction This example demonstrates how to extract and utilize metadata from documents using Mastra's document processing capabilities. The extracted metadata can be used for document organization, filtering, and enhanced retrieval in RAG systems. ## Overview The system demonstrates metadata extraction in two ways: 1. Direct metadata extraction from a document 2. Chunking with metadata extraction ## Setup ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { MDocument } from "@mastra/rag"; ``` ## Document Creation Create a document from text content: ```typescript copy showLineNumbers{3} filename="src/index.ts" const doc = MDocument.fromText(`Title: The Benefits of Regular Exercise Regular exercise has numerous health benefits. It improves cardiovascular health, strengthens muscles, and boosts mental wellbeing. Key Benefits: • Reduces stress and anxiety • Improves sleep quality • Helps maintain healthy weight • Increases energy levels For optimal results, experts recommend at least 150 minutes of moderate exercise per week.`); ``` ## 1. Direct Metadata Extraction Extract metadata directly from the document: ```typescript copy showLineNumbers{17} filename="src/index.ts" // Configure metadata extraction options await doc.extractMetadata({ keywords: true, // Extract important keywords summary: true, // Generate a concise summary }); // Retrieve the extracted metadata const meta = doc.getMetadata(); console.log("Extracted Metadata:", meta); // Example Output: // Extracted Metadata: { // keywords: [ // 'exercise', // 'health benefits', // 'cardiovascular health', // 'mental wellbeing', // 'stress reduction', // 'sleep quality' // ], // summary: 'Regular exercise provides multiple health benefits including improved cardiovascular health, muscle strength, and mental wellbeing. Key benefits include stress reduction, better sleep, weight management, and increased energy. Recommended exercise duration is 150 minutes per week.' // } ``` ## 2. Chunking with Metadata Combine document chunking with metadata extraction: ```typescript copy showLineNumbers{40} filename="src/index.ts" // Configure chunking with metadata extraction await doc.chunk({ strategy: "recursive", // Use recursive chunking strategy size: 200, // Maximum chunk size extract: { keywords: true, // Extract keywords per chunk summary: true, // Generate summary per chunk }, }); // Get metadata from chunks const metaTwo = doc.getMetadata(); console.log("Chunk Metadata:", metaTwo); // Example Output: // Chunk Metadata: { // keywords: [ // 'exercise', // 'health benefits', // 'cardiovascular health', // 'mental wellbeing', // 'stress reduction', // 'sleep quality' // ], // summary: 'Regular exercise provides multiple health benefits including improved cardiovascular health, muscle strength, and mental wellbeing. Key benefits include stress reduction, better sleep, weight management, and increased energy. Recommended exercise duration is 150 minutes per week.' // } ```




--- title: "Example: Hybrid Vector Search | RAG | Mastra Docs" description: Example of using metadata filters with PGVector to enhance vector search results in Mastra. --- import { GithubLink } from "@/components/github-link"; # Hybrid Vector Search [EN] Source: https://mastra.ai/en/examples/rag/query/hybrid-vector-search When you combine vector similarity search with metadata filters, you can create a hybrid search that is more precise and efficient. This approach combines: - Vector similarity search to find the most relevant documents - Metadata filters to refine the search results based on additional criteria This example demonstrates how to use hybrid vector search with Mastra and PGVector. ## Overview The system implements filtered vector search using Mastra and PGVector. Here's what it does: 1. Queries existing embeddings in PGVector with metadata filters 2. Shows how to filter by different metadata fields 3. Demonstrates combining vector similarity with metadata filtering > **Note**: For examples of how to extract metadata from your documents, see the [Metadata Extraction](../embedding/metadata-extraction.mdx) guide. > > To learn how to create and store embeddings, see the [Upsert Embeddings](/examples/rag/upsert/upsert-embeddings) guide. ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_openai_api_key_here POSTGRES_CONNECTION_STRING=your_connection_string_here ``` ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { embed } from "ai"; import { PgVector } from "@mastra/pg"; import { openai } from "@ai-sdk/openai"; ``` ## Vector Store Initialization Initialize PgVector with your connection string: ```typescript copy showLineNumbers{4} filename="src/index.ts" const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); ``` ## Example Usage ### Filter by Metadata Value ```typescript copy showLineNumbers{6} filename="src/index.ts" // Create embedding for the query const { embedding } = await embed({ model: openai.embedding("text-embedding-3-small"), value: "[Insert query based on document here]", }); // Query with metadata filter const result = await pgVector.query({ indexName: "embeddings", queryVector: embedding, topK: 3, filter: { "path.to.metadata": { $eq: "value", }, }, }); console.log("Results:", result); ```




--- title: "Example: Retrieving Top-K Results | RAG | Mastra Docs" description: Example of using Mastra to query a vector database and retrieve semantically similar chunks. --- import { GithubLink } from "@/components/github-link"; # Retrieving Top-K Results [EN] Source: https://mastra.ai/en/examples/rag/query/retrieve-results After storing embeddings in a vector database, you need to query them to find similar content. The `query` method returns the most semantically similar chunks to your input embedding, ranked by relevance. The `topK` parameter allows you to specify the number of results to return. This example shows how to retrieve similar chunks from a Pinecone vector database. ```tsx copy import { openai } from "@ai-sdk/openai"; import { PineconeVector } from "@mastra/pinecone"; import { MDocument } from "@mastra/rag"; import { embedMany } from "ai"; const doc = MDocument.fromText("Your text content..."); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map((chunk) => chunk.text), model: openai.embedding("text-embedding-3-small"), }); const pinecone = new PineconeVector({ apiKey: "your-api-key", }); await pinecone.createIndex({ indexName: "test_index", dimension: 1536, }); await pinecone.upsert({ indexName: "test_index", vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); const topK = 10; const results = await pinecone.query({ indexName: "test_index", queryVector: embeddings[0], topK, }); console.log(results); ```




--- title: "Example: Re-ranking Results with Tools | Retrieval | RAG | Mastra Docs" description: Example of implementing a RAG system with re-ranking in Mastra using OpenAI embeddings and PGVector for vector storage. --- import { GithubLink } from "@/components/github-link"; # Re-ranking Results with Tools [EN] Source: https://mastra.ai/en/examples/rag/rerank/rerank-rag This example demonstrates how to use Mastra's vector query tool to implement a Retrieval-Augmented Generation (RAG) system with re-ranking using OpenAI embeddings and PGVector for vector storage. ## Overview The system implements RAG with re-ranking using Mastra and OpenAI. Here's what it does: 1. Sets up a Mastra agent with gpt-4o-mini for response generation 2. Creates a vector query tool with re-ranking capabilities 3. Chunks text documents into smaller segments and creates embeddings from them 4. Stores them in a PostgreSQL vector database 5. Retrieves and re-ranks relevant chunks based on queries 6. Generates context-aware responses using the Mastra agent ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_openai_api_key_here POSTGRES_CONNECTION_STRING=your_connection_string_here ``` ### Dependencies Then, import the necessary dependencies: ```typescript copy showLineNumbers filename="index.ts" import { openai } from "@ai-sdk/openai"; import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { PgVector } from "@mastra/pg"; import { MDocument, createVectorQueryTool } from "@mastra/rag"; import { embedMany } from "ai"; ``` ## Vector Query Tool Creation with Re-ranking Using createVectorQueryTool imported from @mastra/rag, you can create a tool that can query the vector database and re-rank results: ```typescript copy showLineNumbers{8} filename="index.ts" const vectorQueryTool = createVectorQueryTool({ vectorStoreName: "pgVector", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), reranker: { model: openai("gpt-4o-mini"), }, }); ``` ## Agent Configuration Set up the Mastra agent that will handle the responses: ```typescript copy showLineNumbers{17} filename="index.ts" export const ragAgent = new Agent({ name: "RAG Agent", instructions: `You are a helpful assistant that answers questions based on the provided context. Keep your answers concise and relevant. Important: When asked to answer a question, please base your answer only on the context provided in the tool. If the context doesn't contain enough information to fully answer the question, please state that explicitly.`, model: openai("gpt-4o-mini"), tools: { vectorQueryTool, }, }); ``` ## Instantiate PgVector and Mastra Instantiate PgVector and Mastra with the components: ```typescript copy showLineNumbers{29} filename="index.ts" const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); export const mastra = new Mastra({ agents: { ragAgent }, vectors: { pgVector }, }); const agent = mastra.getAgent("ragAgent"); ``` ## Document Processing Create a document and process it into chunks: ```typescript copy showLineNumbers{38} filename="index.ts" const doc1 = MDocument.fromText(` market data shows price resistance levels. technical charts display moving averages. support levels guide trading decisions. breakout patterns signal entry points. price action determines trade timing. baseball cards show gradual value increase. rookie cards command premium prices. card condition affects resale value. authentication prevents fake trading. grading services verify card quality. volume analysis confirms price trends. sports cards track seasonal demand. chart patterns predict movements. mint condition doubles card worth. resistance breaks trigger orders. rare cards appreciate yearly. `); const chunks = await doc1.chunk({ strategy: "recursive", size: 150, overlap: 20, separator: "\n", }); ``` ## Creating and Storing Embeddings Generate embeddings for the chunks and store them in the vector database: ```typescript copy showLineNumbers{66} filename="index.ts" const { embeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: chunks.map((chunk) => chunk.text), }); const vectorStore = mastra.getVector("pgVector"); await vectorStore.createIndex({ indexName: "embeddings", dimension: 1536, }); await vectorStore.upsert({ indexName: "embeddings", vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); ``` ## Querying with Re-ranking Try different queries to see how the re-ranking affects results: ```typescript copy showLineNumbers{82} filename="index.ts" const queryOne = "explain technical trading analysis"; const answerOne = await agent.generate(queryOne); console.log("\nQuery:", queryOne); console.log("Response:", answerOne.text); const queryTwo = "explain trading card valuation"; const answerTwo = await agent.generate(queryTwo); console.log("\nQuery:", queryTwo); console.log("Response:", answerTwo.text); const queryThree = "how do you analyze market resistance"; const answerThree = await agent.generate(queryThree); console.log("\nQuery:", queryThree); console.log("Response:", answerThree.text); ```




--- title: "Example: Re-ranking Results | Retrieval | RAG | Mastra Docs" description: Example of implementing semantic re-ranking in Mastra using OpenAI embeddings and PGVector for vector storage. --- import { GithubLink } from "@/components/github-link"; # Re-ranking Results [EN] Source: https://mastra.ai/en/examples/rag/rerank/rerank This example demonstrates how to implement a Retrieval-Augmented Generation (RAG) system with re-ranking using Mastra, OpenAI embeddings, and PGVector for vector storage. ## Overview The system implements RAG with re-ranking using Mastra and OpenAI. Here's what it does: 1. Chunks text documents into smaller segments and creates embeddings from them 2. Stores vectors in a PostgreSQL database 3. Performs initial vector similarity search 4. Re-ranks results using Mastra's rerank function, combining vector similarity, semantic relevance, and position scores 5. Compares initial and re-ranked results to show improvements ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_openai_api_key_here POSTGRES_CONNECTION_STRING=your_connection_string_here ``` ### Dependencies Then, import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { PgVector } from "@mastra/pg"; import { MDocument, rerank } from "@mastra/rag"; import { embedMany, embed } from "ai"; ``` ## Document Processing Create a document and process it into chunks: ```typescript copy showLineNumbers{7} filename="src/index.ts" const doc1 = MDocument.fromText(` market data shows price resistance levels. technical charts display moving averages. support levels guide trading decisions. breakout patterns signal entry points. price action determines trade timing. `); const chunks = await doc1.chunk({ strategy: "recursive", size: 150, overlap: 20, separator: "\n", }); ``` ## Creating and Storing Embeddings Generate embeddings for the chunks and store them in the vector database: ```typescript copy showLineNumbers{36} filename="src/index.ts" const { embeddings } = await embedMany({ values: chunks.map((chunk) => chunk.text), model: openai.embedding("text-embedding-3-small"), }); const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); await pgVector.createIndex({ indexName: "embeddings", dimension: 1536, }); await pgVector.upsert({ indexName: "embeddings", vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); ``` ## Vector Search and Re-ranking Perform vector search and re-rank the results: ```typescript copy showLineNumbers{51} filename="src/index.ts" const query = "explain technical trading analysis"; // Get query embedding const { embedding: queryEmbedding } = await embed({ value: query, model: openai.embedding("text-embedding-3-small"), }); // Get initial results const initialResults = await pgVector.query({ indexName: "embeddings", queryVector: queryEmbedding, topK: 3, }); // Re-rank results const rerankedResults = await rerank( initialResults, query, openai("gpt-4o-mini"), { weights: { semantic: 0.5, // How well the content matches the query semantically vector: 0.3, // Original vector similarity score position: 0.2, // Preserves original result ordering }, topK: 3, }, ); ``` The weights control how different factors influence the final ranking: - `semantic`: Higher values prioritize semantic understanding and relevance to the query - `vector`: Higher values favor the original vector similarity scores - `position`: Higher values help maintain the original ordering of results ## Comparing Results Print both initial and re-ranked results to see the improvement: ```typescript copy showLineNumbers{72} filename="src/index.ts" console.log("Initial Results:"); initialResults.forEach((result, index) => { console.log(`Result ${index + 1}:`, { text: result.metadata.text, score: result.score, }); }); console.log("Re-ranked Results:"); rerankedResults.forEach(({ result, score, details }, index) => { console.log(`Result ${index + 1}:`, { text: result.metadata.text, score: score, semantic: details.semantic, vector: details.vector, position: details.position, }); }); ``` The re-ranked results show how combining vector similarity with semantic understanding can improve retrieval quality. Each result includes: - Overall score combining all factors - Semantic relevance score from the language model - Vector similarity score from the embedding comparison - Position-based score for maintaining original order when appropriate




--- title: "Example: Reranking with Cohere | RAG | Mastra Docs" description: Example of using Mastra to improve document retrieval relevance with Cohere's reranking service. --- # Reranking with Cohere [EN] Source: https://mastra.ai/en/examples/rag/rerank/reranking-with-cohere When retrieving documents for RAG, initial vector similarity search may miss important semantic matches. Cohere's reranking service helps improve result relevance by reordering documents using multiple scoring factors. ```typescript import { rerank } from "@mastra/rag"; const results = rerank( searchResults, "deployment configuration", cohere("rerank-v3.5"), { topK: 5, weights: { semantic: 0.4, vector: 0.4, position: 0.2, }, }, ); ``` ## Links - [rerank() reference](/reference/rag/rerank.mdx) - [Retrieval docs](/reference/rag/retrieval.mdx) --- title: "Example: Upsert Embeddings | RAG | Mastra Docs" description: Examples of using Mastra to store embeddings in various vector databases for similarity search. --- import { Tabs } from "nextra/components"; import { GithubLink } from "@/components/github-link"; # Upsert Embeddings [EN] Source: https://mastra.ai/en/examples/rag/upsert/upsert-embeddings After generating embeddings, you need to store them in a database that supports vector similarity search. This example shows how to store embeddings in various vector databases for later retrieval. {/* LLM CONTEXT: This Tabs component demonstrates how to upsert (insert/update) embeddings into different vector databases. Each tab shows a complete example of storing embeddings in a specific vector database provider. The tabs help users understand the consistent API pattern across different vector stores while showing provider-specific configuration. Each tab includes document chunking, embedding generation, index creation, and data insertion for that specific database. The providers include PgVector, Pinecone, Qdrant, Chroma, Astra DB, LibSQL, Upstash, Cloudflare, MongoDB, OpenSearch, and Couchbase. */} The `PgVector` class provides methods to create indexes and insert embeddings into PostgreSQL with the pgvector extension. ```tsx copy import { openai } from "@ai-sdk/openai"; import { PgVector } from "@mastra/pg"; import { MDocument } from "@mastra/rag"; import { embedMany } from "ai"; const doc = MDocument.fromText("Your text content..."); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding("text-embedding-3-small"), }); const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING! }); await pgVector.createIndex({ indexName: "test_index", dimension: 1536, }); await pgVector.upsert({ indexName: "test_index", vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); ```


The `PineconeVector` class provides methods to create indexes and insert embeddings into Pinecone, a managed vector database service. ```tsx copy import { openai } from '@ai-sdk/openai'; import { PineconeVector } from '@mastra/pinecone'; import { MDocument } from '@mastra/rag'; import { embedMany } from 'ai'; const doc = MDocument.fromText('Your text content...'); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding('text-embedding-3-small'), }); const pinecone = new PineconeVector({ apiKey: process.env.PINECONE_API_KEY!, }); await pinecone.createIndex({ indexName: 'testindex', dimension: 1536, }); await pinecone.upsert({ indexName: 'testindex', vectors: embeddings, metadata: chunks?.map(chunk => ({ text: chunk.text })), }); ```


The `QdrantVector` class provides methods to create collections and insert embeddings into Qdrant, a high-performance vector database. ```tsx copy import { openai } from '@ai-sdk/openai'; import { QdrantVector } from '@mastra/qdrant'; import { MDocument } from '@mastra/rag'; import { embedMany } from 'ai'; const doc = MDocument.fromText('Your text content...'); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding('text-embedding-3-small'), maxRetries: 3, }); const qdrant = new QdrantVector({ url: process.env.QDRANT_URL, apiKey: process.env.QDRANT_API_KEY, }); await qdrant.createIndex({ indexName: 'test_collection', dimension: 1536, }); await qdrant.upsert({ indexName: 'test_collection', vectors: embeddings, metadata: chunks?.map(chunk => ({ text: chunk.text })), }); ``` The `ChromaVector` class provides methods to create collections and insert embeddings into Chroma, an open-source embedding database. ```tsx copy import { openai } from '@ai-sdk/openai'; import { ChromaVector } from '@mastra/chroma'; import { MDocument } from '@mastra/rag'; import { embedMany } from 'ai'; const doc = MDocument.fromText('Your text content...'); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding('text-embedding-3-small'), }); const chroma = new ChromaVector({ path: "path/to/chroma/db", }); await chroma.createIndex({ indexName: 'test_collection', dimension: 1536, }); await chroma.upsert({ indexName: 'test_collection', vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), documents: chunks.map(chunk => chunk.text), }); ```


he `AstraVector` class provides methods to create collections and insert embeddings into DataStax Astra DB, a cloud-native vector database. ```tsx copy import { openai } from '@ai-sdk/openai'; import { AstraVector } from '@mastra/astra'; import { MDocument } from '@mastra/rag'; import { embedMany } from 'ai'; const doc = MDocument.fromText('Your text content...'); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ model: openai.embedding('text-embedding-3-small'), values: chunks.map(chunk => chunk.text), }); const astra = new AstraVector({ token: process.env.ASTRA_DB_TOKEN, endpoint: process.env.ASTRA_DB_ENDPOINT, keyspace: process.env.ASTRA_DB_KEYSPACE, }); await astra.createIndex({ indexName: 'test_collection', dimension: 1536, }); await astra.upsert({ indexName: 'test_collection', vectors: embeddings, metadata: chunks?.map(chunk => ({ text: chunk.text })), }); ``` The `LibSQLVector` class provides methods to create collections and insert embeddings into LibSQL, a fork of SQLite with vector extensions. ```tsx copy import { openai } from "@ai-sdk/openai"; import { LibSQLVector } from "@mastra/core/vector/libsql"; import { MDocument } from "@mastra/rag"; import { embedMany } from "ai"; const doc = MDocument.fromText("Your text content..."); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map((chunk) => chunk.text), model: openai.embedding("text-embedding-3-small"), }); const libsql = new LibSQLVector({ connectionUrl: process.env.DATABASE_URL, authToken: process.env.DATABASE_AUTH_TOKEN, // Optional: for Turso cloud databases }); await libsql.createIndex({ indexName: "test_collection", dimension: 1536, }); await libsql.upsert({ indexName: "test_collection", vectors: embeddings, metadata: chunks?.map((chunk) => ({ text: chunk.text })), }); ```


The `UpstashVector` class provides methods to create collections and insert embeddings into Upstash Vector, a serverless vector database. ```tsx copy import { openai } from '@ai-sdk/openai'; import { UpstashVector } from '@mastra/upstash'; import { MDocument } from '@mastra/rag'; import { embedMany } from 'ai'; const doc = MDocument.fromText('Your text content...'); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding('text-embedding-3-small'), }); const upstash = new UpstashVector({ url: process.env.UPSTASH_URL, token: process.env.UPSTASH_TOKEN, }); // There is no store.createIndex call here, Upstash creates indexes (known as namespaces in Upstash) automatically // when you upsert if that namespace does not exist yet. await upstash.upsert({ indexName: 'test_collection', // the namespace name in Upstash vectors: embeddings, metadata: chunks?.map(chunk => ({ text: chunk.text })), }); ``` The `CloudflareVector` class provides methods to create collections and insert embeddings into Cloudflare Vectorize, a serverless vector database service. ```tsx copy import { openai } from '@ai-sdk/openai'; import { CloudflareVector } from '@mastra/vectorize'; import { MDocument } from '@mastra/rag'; import { embedMany } from 'ai'; const doc = MDocument.fromText('Your text content...'); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding('text-embedding-3-small'), }); const vectorize = new CloudflareVector({ accountId: process.env.CF_ACCOUNT_ID, apiToken: process.env.CF_API_TOKEN, }); await vectorize.createIndex({ indexName: 'test_collection', dimension: 1536, }); await vectorize.upsert({ indexName: 'test_collection', vectors: embeddings, metadata: chunks?.map(chunk => ({ text: chunk.text })), }); ``` The `MongoDBVector` class provides methods to create indexes and insert embeddings into MongoDB with Atlas Search. ```tsx copy import { openai } from "@ai-sdk/openai"; import { MongoDBVector } from "@mastra/mongodb"; import { MDocument } from "@mastra/rag"; import { embedMany } from "ai"; const doc = MDocument.fromText("Your text content..."); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding("text-embedding-3-small"), }); const vectorDB = new MongoDBVector({ uri: process.env.MONGODB_URI!, dbName: process.env.MONGODB_DB_NAME!, }); await vectorDB.createIndex({ indexName: "test_index", dimension: 1536, }); await vectorDB.upsert({ indexName: "test_index", vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); ``` The `OpenSearchVector` class provides methods to create indexes and insert embeddings into OpenSearch, a distributed search engine with vector search capabilities. ```tsx copy import { openai } from '@ai-sdk/openai'; import { OpenSearchVector } from '@mastra/opensearch'; import { MDocument } from '@mastra/rag'; import { embedMany } from 'ai'; const doc = MDocument.fromText('Your text content...'); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding('text-embedding-3-small'), }); const vectorDB = new OpenSearchVector({ uri: process.env.OPENSEARCH_URI!, }); await vectorDB.createIndex({ indexName: 'test_index', dimension: 1536, }); await vectorDB.upsert({ indexName: 'test_index', vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); ``` The `CouchbaseVector` class provides methods to create indexes and insert embeddings into Couchbase, a distributed NoSQL database with vector search capabilities. ```tsx copy import { openai } from '@ai-sdk/openai'; import { CouchbaseVector } from '@mastra/couchbase'; import { MDocument } from '@mastra/rag'; import { embedMany } from 'ai'; const doc = MDocument.fromText('Your text content...'); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding('text-embedding-3-small'), }); const couchbase = new CouchbaseVector({ connectionString: process.env.COUCHBASE_CONNECTION_STRING, username: process.env.COUCHBASE_USERNAME, password: process.env.COUCHBASE_PASSWORD, bucketName: process.env.COUCHBASE_BUCKET, scopeName: process.env.COUCHBASE_SCOPE, collectionName: process.env.COUCHBASE_COLLECTION, }); await couchbase.createIndex({ indexName: 'test_collection', dimension: 1536, }); await couchbase.upsert({ indexName: 'test_collection', vectors: embeddings, metadata: chunks?.map(chunk => ({ text: chunk.text })), }); ``` The `LanceVectorStore` class provides methods to create tables, indexes and insert embeddings into LanceDB, an embedded vector database built on the Lance columnar format. ```tsx copy import { openai } from '@ai-sdk/openai'; import { LanceVectorStore } from '@mastra/lance'; import { MDocument } from '@mastra/rag'; import { embedMany } from 'ai'; const doc = MDocument.fromText('Your text content...'); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding('text-embedding-3-small'), }); const lance = await LanceVectorStore.create('/path/to/db'); // In LanceDB you need to create a table first await lance.createIndex({ tableName: 'myVectors', indexName: 'vector', dimension: 1536, }); await lance.upsert({ tableName: 'myVectors', vectors: embeddings, metadata: chunks?.map(chunk => ({ text: chunk.text })), }); ```
--- title: "Example: Using the Vector Query Tool | RAG | Mastra Docs" description: Example of implementing a basic RAG system in Mastra using OpenAI embeddings and PGVector for vector storage. --- import { GithubLink } from "@/components/github-link"; # Using the Vector Query Tool [EN] Source: https://mastra.ai/en/examples/rag/usage/basic-rag This example demonstrates how to implement and use `createVectorQueryTool` for semantic search in a RAG system. It shows how to configure the tool, manage vector storage, and retrieve relevant context effectively. ## Overview The system implements RAG using Mastra and OpenAI. Here's what it does: 1. Sets up a Mastra agent with gpt-4o-mini for response generation 2. Creates a vector query tool to manage vector store interactions 3. Uses existing embeddings to retrieve relevant context 4. Generates context-aware responses using the Mastra agent > **Note**: To learn how to create and store embeddings, see the [Upsert Embeddings](/examples/rag/upsert/upsert-embeddings) guide. ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_openai_api_key_here POSTGRES_CONNECTION_STRING=your_connection_string_here ``` ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { createVectorQueryTool } from "@mastra/rag"; import { PgVector } from "@mastra/pg"; ``` ## Vector Query Tool Creation Create a tool that can query the vector database: ```typescript copy showLineNumbers{7} filename="src/index.ts" const vectorQueryTool = createVectorQueryTool({ vectorStoreName: "pgVector", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), }); ``` ## Agent Configuration Set up the Mastra agent that will handle the responses: ```typescript copy showLineNumbers{13} filename="src/index.ts" export const ragAgent = new Agent({ name: "RAG Agent", instructions: "You are a helpful assistant that answers questions based on the provided context. Keep your answers concise and relevant.", model: openai("gpt-4o-mini"), tools: { vectorQueryTool, }, }); ``` ## Instantiate PgVector and Mastra Instantiate PgVector and Mastra with all components: ```typescript copy showLineNumbers{23} filename="src/index.ts" const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); export const mastra = new Mastra({ agents: { ragAgent }, vectors: { pgVector }, }); const agent = mastra.getAgent("ragAgent"); ``` ## Example Usage ```typescript copy showLineNumbers{32} filename="src/index.ts" const prompt = ` [Insert query based on document here] Please base your answer only on the context provided in the tool. If the context doesn't contain enough information to fully answer the question, please state that explicitly. `; const completion = await agent.generate(prompt); console.log(completion.text); ```




--- title: "Example: Optimizing Information Density | RAG | Mastra Docs" description: Example of implementing a RAG system in Mastra to optimize information density and deduplicate data using LLM-based processing. --- import { GithubLink } from "@/components/github-link"; # Optimizing Information Density [EN] Source: https://mastra.ai/en/examples/rag/usage/cleanup-rag This example demonstrates how to implement a Retrieval-Augmented Generation (RAG) system using Mastra, OpenAI embeddings, and PGVector for vector storage. The system uses an agent to clean the initial chunks to optimize information density and deduplicate data. ## Overview The system implements RAG using Mastra and OpenAI, this time optimizing information density through LLM-based processing. Here's what it does: 1. Sets up a Mastra agent with gpt-4o-mini that can handle both querying and cleaning documents 2. Creates vector query and document chunking tools for the agent to use 3. Processes the initial document: - Chunks text documents into smaller segments - Creates embeddings for the chunks - Stores them in a PostgreSQL vector database 4. Performs an initial query to establish baseline response quality 5. Optimizes the data: - Uses the agent to clean and deduplicate chunks - Creates new embeddings for the cleaned chunks - Updates the vector store with optimized data 6. Performs the same query again to demonstrate improved response quality ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_openai_api_key_here POSTGRES_CONNECTION_STRING=your_connection_string_here ``` ### Dependencies Then, import the necessary dependencies: ```typescript copy showLineNumbers filename="index.ts" import { openai } from "@ai-sdk/openai"; import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { PgVector } from "@mastra/pg"; import { MDocument, createVectorQueryTool, createDocumentChunkerTool, } from "@mastra/rag"; import { embedMany } from "ai"; ``` ## Tool Creation ### Vector Query Tool Using createVectorQueryTool imported from @mastra/rag, you can create a tool that can query the vector database. ```typescript copy showLineNumbers{8} filename="index.ts" const vectorQueryTool = createVectorQueryTool({ vectorStoreName: "pgVector", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), }); ``` ### Document Chunker Tool Using createDocumentChunkerTool imported from @mastra/rag, you can create a tool that chunks the document and sends the chunks to your agent. ```typescript copy showLineNumbers{14} filename="index.ts" const doc = MDocument.fromText(yourText); const documentChunkerTool = createDocumentChunkerTool({ doc, params: { strategy: "recursive", size: 512, overlap: 25, separator: "\n", }, }); ``` ## Agent Configuration Set up a single Mastra agent that can handle both querying and cleaning: ```typescript copy showLineNumbers{26} filename="index.ts" const ragAgent = new Agent({ name: "RAG Agent", instructions: `You are a helpful assistant that handles both querying and cleaning documents. When cleaning: Process, clean, and label data, remove irrelevant information and deduplicate content while preserving key facts. When querying: Provide answers based on the available context. Keep your answers concise and relevant. Important: When asked to answer a question, please base your answer only on the context provided in the tool. If the context doesn't contain enough information to fully answer the question, please state that explicitly. `, model: openai("gpt-4o-mini"), tools: { vectorQueryTool, documentChunkerTool, }, }); ``` ## Instantiate PgVector and Mastra Instantiate PgVector and Mastra with the components: ```typescript copy showLineNumbers{41} filename="index.ts" const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); export const mastra = new Mastra({ agents: { ragAgent }, vectors: { pgVector }, }); const agent = mastra.getAgent("ragAgent"); ``` ## Document Processing Chunk the initial document and create embeddings: ```typescript copy showLineNumbers{49} filename="index.ts" const chunks = await doc.chunk({ strategy: "recursive", size: 256, overlap: 50, separator: "\n", }); const { embeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: chunks.map((chunk) => chunk.text), }); const vectorStore = mastra.getVector("pgVector"); await vectorStore.createIndex({ indexName: "embeddings", dimension: 1536, }); await vectorStore.upsert({ indexName: "embeddings", vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); ``` ## Initial Query Let's try querying the raw data to establish a baseline: ```typescript copy showLineNumbers{73} filename="index.ts" // Generate response using the original embeddings const query = "What are all the technologies mentioned for space exploration?"; const originalResponse = await agent.generate(query); console.log("\nQuery:", query); console.log("Response:", originalResponse.text); ``` ## Data Optimization After seeing the initial results, we can clean the data to improve quality: ```typescript copy showLineNumbers{79} filename="index.ts" const chunkPrompt = `Use the tool provided to clean the chunks. Make sure to filter out irrelevant information that is not space related and remove duplicates.`; const newChunks = await agent.generate(chunkPrompt); const updatedDoc = MDocument.fromText(newChunks.text); const updatedChunks = await updatedDoc.chunk({ strategy: "recursive", size: 256, overlap: 50, separator: "\n", }); const { embeddings: cleanedEmbeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: updatedChunks.map((chunk) => chunk.text), }); // Update the vector store with cleaned embeddings await vectorStore.deleteIndex({ indexName: "embeddings" }); await vectorStore.createIndex({ indexName: "embeddings", dimension: 1536, }); await vectorStore.upsert({ indexName: "embeddings", vectors: cleanedEmbeddings, metadata: updatedChunks?.map((chunk: any) => ({ text: chunk.text })), }); ``` ## Optimized Query Query the data again after cleaning to observe any differences in the response: ```typescript copy showLineNumbers{109} filename="index.ts" // Query again with cleaned embeddings const cleanedResponse = await agent.generate(query); console.log("\nQuery:", query); console.log("Response:", cleanedResponse.text); ```




--- title: "Example: Chain of Thought Prompting | RAG | Mastra Docs" description: Example of implementing a RAG system in Mastra with chain-of-thought reasoning using OpenAI and PGVector. --- import { GithubLink } from "@/components/github-link"; # Chain of Thought Prompting [EN] Source: https://mastra.ai/en/examples/rag/usage/cot-rag This example demonstrates how to implement a Retrieval-Augmented Generation (RAG) system using Mastra, OpenAI embeddings, and PGVector for vector storage, with an emphasis on chain-of-thought reasoning. ## Overview The system implements RAG using Mastra and OpenAI with chain-of-thought prompting. Here's what it does: 1. Sets up a Mastra agent with gpt-4o-mini for response generation 2. Creates a vector query tool to manage vector store interactions 3. Chunks text documents into smaller segments 4. Creates embeddings for these chunks 5. Stores them in a PostgreSQL vector database 6. Retrieves relevant chunks based on queries using vector query tool 7. Generates context-aware responses using chain-of-thought reasoning ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_openai_api_key_here POSTGRES_CONNECTION_STRING=your_connection_string_here ``` ### Dependencies Then, import the necessary dependencies: ```typescript copy showLineNumbers filename="index.ts" import { openai } from "@ai-sdk/openai"; import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { PgVector } from "@mastra/pg"; import { createVectorQueryTool, MDocument } from "@mastra/rag"; import { embedMany } from "ai"; ``` ## Vector Query Tool Creation Using createVectorQueryTool imported from @mastra/rag, you can create a tool that can query the vector database. ```typescript copy showLineNumbers{8} filename="index.ts" const vectorQueryTool = createVectorQueryTool({ vectorStoreName: "pgVector", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), }); ``` ## Agent Configuration Set up the Mastra agent with chain-of-thought prompting instructions: ```typescript copy showLineNumbers{14} filename="index.ts" export const ragAgent = new Agent({ name: "RAG Agent", instructions: `You are a helpful assistant that answers questions based on the provided context. Follow these steps for each response: 1. First, carefully analyze the retrieved context chunks and identify key information. 2. Break down your thinking process about how the retrieved information relates to the query. 3. Explain how you're connecting different pieces from the retrieved chunks. 4. Draw conclusions based only on the evidence in the retrieved context. 5. If the retrieved chunks don't contain enough information, explicitly state what's missing. Format your response as: THOUGHT PROCESS: - Step 1: [Initial analysis of retrieved chunks] - Step 2: [Connections between chunks] - Step 3: [Reasoning based on chunks] FINAL ANSWER: [Your concise answer based on the retrieved context] Important: When asked to answer a question, please base your answer only on the context provided in the tool. If the context doesn't contain enough information to fully answer the question, please state that explicitly. Remember: Explain how you're using the retrieved information to reach your conclusions. `, model: openai("gpt-4o-mini"), tools: { vectorQueryTool }, }); ``` ## Instantiate PgVector and Mastra Instantiate PgVector and Mastra with all components: ```typescript copy showLineNumbers{36} filename="index.ts" const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); export const mastra = new Mastra({ agents: { ragAgent }, vectors: { pgVector }, }); const agent = mastra.getAgent("ragAgent"); ``` ## Document Processing Create a document and process it into chunks: ```typescript copy showLineNumbers{44} filename="index.ts" const doc = MDocument.fromText( `The Impact of Climate Change on Global Agriculture...`, ); const chunks = await doc.chunk({ strategy: "recursive", size: 512, overlap: 50, separator: "\n", }); ``` ## Creating and Storing Embeddings Generate embeddings for the chunks and store them in the vector database: ```typescript copy showLineNumbers{55} filename="index.ts" const { embeddings } = await embedMany({ values: chunks.map((chunk) => chunk.text), model: openai.embedding("text-embedding-3-small"), }); const vectorStore = mastra.getVector("pgVector"); await vectorStore.createIndex({ indexName: "embeddings", dimension: 1536, }); await vectorStore.upsert({ indexName: "embeddings", vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); ``` ## Chain-of-Thought Querying Try different queries to see how the agent breaks down its reasoning: ```typescript copy showLineNumbers{83} filename="index.ts" const answerOne = await agent.generate( "What are the main adaptation strategies for farmers?", ); console.log("\nQuery:", "What are the main adaptation strategies for farmers?"); console.log("Response:", answerOne.text); const answerTwo = await agent.generate( "Analyze how temperature affects crop yields.", ); console.log("\nQuery:", "Analyze how temperature affects crop yields."); console.log("Response:", answerTwo.text); const answerThree = await agent.generate( "What connections can you draw between climate change and food security?", ); console.log( "\nQuery:", "What connections can you draw between climate change and food security?", ); console.log("Response:", answerThree.text); ```




--- title: "Example: Structured Reasoning with Workflows | RAG | Mastra Docs" description: Example of implementing structured reasoning in a RAG system using Mastra's workflow capabilities. --- import { GithubLink } from "@/components/github-link"; # Structured Reasoning with Workflows [EN] Source: https://mastra.ai/en/examples/rag/usage/cot-workflow-rag This example demonstrates how to implement a Retrieval-Augmented Generation (RAG) system using Mastra, OpenAI embeddings, and PGVector for vector storage, with an emphasis on structured reasoning through a defined workflow. ## Overview The system implements RAG using Mastra and OpenAI with chain-of-thought prompting through a defined workflow. Here's what it does: 1. Sets up a Mastra agent with gpt-4o-mini for response generation 2. Creates a vector query tool to manage vector store interactions 3. Defines a workflow with multiple steps for chain-of-thought reasoning 4. Processes and chunks text documents 5. Creates and stores embeddings in PostgreSQL 6. Generates responses through the workflow steps ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_openai_api_key_here POSTGRES_CONNECTION_STRING=your_connection_string_here ``` ### Dependencies Import the necessary dependencies: ```typescript copy showLineNumbers filename="index.ts" import { openai } from "@ai-sdk/openai"; import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { Step, Workflow } from "@mastra/core/workflows"; import { PgVector } from "@mastra/pg"; import { createVectorQueryTool, MDocument } from "@mastra/rag"; import { embedMany } from "ai"; import { z } from "zod"; ``` ## Workflow Definition First, define the workflow with its trigger schema: ```typescript copy showLineNumbers{10} filename="index.ts" export const ragWorkflow = new Workflow({ name: "rag-workflow", triggerSchema: z.object({ query: z.string(), }), }); ``` ## Vector Query Tool Creation Create a tool for querying the vector database: ```typescript copy showLineNumbers{17} filename="index.ts" const vectorQueryTool = createVectorQueryTool({ vectorStoreName: "pgVector", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), }); ``` ## Agent Configuration Set up the Mastra agent: ```typescript copy showLineNumbers{23} filename="index.ts" export const ragAgent = new Agent({ name: "RAG Agent", instructions: `You are a helpful assistant that answers questions based on the provided context.`, model: openai("gpt-4o-mini"), tools: { vectorQueryTool, }, }); ``` ## Workflow Steps The workflow is divided into multiple steps for chain-of-thought reasoning: ### 1. Context Analysis Step ```typescript copy showLineNumbers{32} filename="index.ts" const analyzeContext = new Step({ id: "analyzeContext", outputSchema: z.object({ initialAnalysis: z.string(), }), execute: async ({ context, mastra }) => { console.log("---------------------------"); const ragAgent = mastra?.getAgent("ragAgent"); const query = context?.getStepResult<{ query: string }>("trigger")?.query; const analysisPrompt = `${query} 1. First, carefully analyze the retrieved context chunks and identify key information.`; const analysis = await ragAgent?.generate(analysisPrompt); console.log(analysis?.text); return { initialAnalysis: analysis?.text ?? "", }; }, }); ``` ### 2. Thought Breakdown Step ```typescript copy showLineNumbers{54} filename="index.ts" const breakdownThoughts = new Step({ id: "breakdownThoughts", outputSchema: z.object({ breakdown: z.string(), }), execute: async ({ context, mastra }) => { console.log("---------------------------"); const ragAgent = mastra?.getAgent("ragAgent"); const analysis = context?.getStepResult<{ initialAnalysis: string; }>("analyzeContext")?.initialAnalysis; const connectionPrompt = ` Based on the initial analysis: ${analysis} 2. Break down your thinking process about how the retrieved information relates to the query. `; const connectionAnalysis = await ragAgent?.generate(connectionPrompt); console.log(connectionAnalysis?.text); return { breakdown: connectionAnalysis?.text ?? "", }; }, }); ``` ### 3. Connection Step ```typescript copy showLineNumbers{80} filename="index.ts" const connectPieces = new Step({ id: "connectPieces", outputSchema: z.object({ connections: z.string(), }), execute: async ({ context, mastra }) => { console.log("---------------------------"); const ragAgent = mastra?.getAgent("ragAgent"); const process = context?.getStepResult<{ breakdown: string; }>("breakdownThoughts")?.breakdown; const connectionPrompt = ` Based on the breakdown: ${process} 3. Explain how you're connecting different pieces from the retrieved chunks. `; const connections = await ragAgent?.generate(connectionPrompt); console.log(connections?.text); return { connections: connections?.text ?? "", }; }, }); ``` ### 4. Conclusion Step ```typescript copy showLineNumbers{105} filename="index.ts" const drawConclusions = new Step({ id: "drawConclusions", outputSchema: z.object({ conclusions: z.string(), }), execute: async ({ context, mastra }) => { console.log("---------------------------"); const ragAgent = mastra?.getAgent("ragAgent"); const evidence = context?.getStepResult<{ connections: string; }>("connectPieces")?.connections; const conclusionPrompt = ` Based on the connections: ${evidence} 4. Draw conclusions based only on the evidence in the retrieved context. `; const conclusions = await ragAgent?.generate(conclusionPrompt); console.log(conclusions?.text); return { conclusions: conclusions?.text ?? "", }; }, }); ``` ### 5. Final Answer Step ```typescript copy showLineNumbers{130} filename="index.ts" const finalAnswer = new Step({ id: "finalAnswer", outputSchema: z.object({ finalAnswer: z.string(), }), execute: async ({ context, mastra }) => { console.log("---------------------------"); const ragAgent = mastra?.getAgent("ragAgent"); const conclusions = context?.getStepResult<{ conclusions: string; }>("drawConclusions")?.conclusions; const answerPrompt = ` Based on the conclusions: ${conclusions} Format your response as: THOUGHT PROCESS: - Step 1: [Initial analysis of retrieved chunks] - Step 2: [Connections between chunks] - Step 3: [Reasoning based on chunks] FINAL ANSWER: [Your concise answer based on the retrieved context]`; const finalAnswer = await ragAgent?.generate(answerPrompt); console.log(finalAnswer?.text); return { finalAnswer: finalAnswer?.text ?? "", }; }, }); ``` ## Workflow Configuration Connect all the steps in the workflow: ```typescript copy showLineNumbers{160} filename="index.ts" ragWorkflow .step(analyzeContext) .then(breakdownThoughts) .then(connectPieces) .then(drawConclusions) .then(finalAnswer); ragWorkflow.commit(); ``` ## Instantiate PgVector and Mastra Instantiate PgVector and Mastra with all components: ```typescript copy showLineNumbers{169} filename="index.ts" const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); export const mastra = new Mastra({ agents: { ragAgent }, vectors: { pgVector }, workflows: { ragWorkflow }, }); ``` ## Document Processing Process and chunks the document: ```typescript copy showLineNumbers{177} filename="index.ts" const doc = MDocument.fromText( `The Impact of Climate Change on Global Agriculture...`, ); const chunks = await doc.chunk({ strategy: "recursive", size: 512, overlap: 50, separator: "\n", }); ``` ## Embedding Creation and Storage Generate and store embeddings: ```typescript copy showLineNumbers{186} filename="index.ts" const { embeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: chunks.map((chunk) => chunk.text), }); const vectorStore = mastra.getVector("pgVector"); await vectorStore.createIndex({ indexName: "embeddings", dimension: 1536, }); await vectorStore.upsert({ indexName: "embeddings", vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); ``` ## Workflow Execution Here's how to execute the workflow with a query: ```typescript copy showLineNumbers{202} filename="index.ts" const query = "What are the main adaptation strategies for farmers?"; console.log("\nQuery:", query); const prompt = ` Please answer the following question: ${query} Please base your answer only on the context provided in the tool. If the context doesn't contain enough information to fully answer the question, please state that explicitly. `; const { runId, start } = ragWorkflow.createRun(); console.log("Run:", runId); const workflowResult = await start({ triggerData: { query: prompt, }, }); console.log("\nThought Process:"); console.log(workflowResult.results); ```




--- title: "Database-Specific Configurations | RAG | Mastra Examples" description: Learn how to use database-specific configurations to optimize vector search performance and leverage unique features of different vector stores. --- import { Tabs } from "nextra/components"; # Database-Specific Configurations [EN] Source: https://mastra.ai/en/examples/rag/usage/database-specific-config This example demonstrates how to use database-specific configurations with vector query tools to optimize performance and leverage unique features of different vector stores. ## Multi-Environment Setup Use different configurations for different environments: ```typescript import { openai } from "@ai-sdk/openai"; import { createVectorQueryTool } from "@mastra/rag"; import { RuntimeContext } from "@mastra/core/runtime-context"; // Base configuration const createSearchTool = (environment: 'dev' | 'staging' | 'prod') => { return createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "documents", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pinecone: { namespace: environment } } }); }; // Create environment-specific tools const devSearchTool = createSearchTool('dev'); const prodSearchTool = createSearchTool('prod'); // Or use runtime override const dynamicSearchTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "documents", model: openai.embedding("text-embedding-3-small") }); // Switch environment at runtime const switchEnvironment = async (environment: string, query: string) => { const runtimeContext = new RuntimeContext(); runtimeContext.set('databaseConfig', { pinecone: { namespace: environment } }); return await dynamicSearchTool.execute({ context: { queryText: query }, mastra, runtimeContext }); }; ``` ```javascript import { openai } from "@ai-sdk/openai"; import { createVectorQueryTool } from "@mastra/rag"; import { RuntimeContext } from "@mastra/core/runtime-context"; // Base configuration const createSearchTool = (environment) => { return createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "documents", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pinecone: { namespace: environment } } }); }; // Create environment-specific tools const devSearchTool = createSearchTool('dev'); const prodSearchTool = createSearchTool('prod'); // Or use runtime override const dynamicSearchTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "documents", model: openai.embedding("text-embedding-3-small") }); // Switch environment at runtime const switchEnvironment = async (environment, query) => { const runtimeContext = new RuntimeContext(); runtimeContext.set('databaseConfig', { pinecone: { namespace: environment } }); return await dynamicSearchTool.execute({ context: { queryText: query }, mastra, runtimeContext }); }; ``` ## Performance Optimization with pgVector Optimize search performance for different use cases: ```typescript // High accuracy configuration - slower but more precise const highAccuracyTool = createVectorQueryTool({ vectorStoreName: "postgres", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pgvector: { ef: 400, // High accuracy for HNSW probes: 20, // High recall for IVFFlat minScore: 0.85 // High quality threshold } } }); // Use for critical searches where accuracy is paramount const criticalSearch = async (query: string) => { return await highAccuracyTool.execute({ context: { queryText: query, topK: 5 // Fewer, higher quality results }, mastra }); }; ``` ```typescript // High speed configuration - faster but less precise const highSpeedTool = createVectorQueryTool({ vectorStoreName: "postgres", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pgvector: { ef: 50, // Lower accuracy for speed probes: 3, // Lower recall for speed minScore: 0.6 // Lower quality threshold } } }); // Use for real-time applications const realtimeSearch = async (query: string) => { return await highSpeedTool.execute({ context: { queryText: query, topK: 10 // More results to compensate for lower precision }, mastra }); }; ``` ```typescript // Balanced configuration - good compromise const balancedTool = createVectorQueryTool({ vectorStoreName: "postgres", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pgvector: { ef: 150, // Moderate accuracy probes: 8, // Moderate recall minScore: 0.7 // Moderate quality threshold } } }); // Adjust parameters based on load const adaptiveSearch = async (query: string, isHighLoad: boolean) => { const runtimeContext = new RuntimeContext(); if (isHighLoad) { // Reduce quality for speed during high load runtimeContext.set('databaseConfig', { pgvector: { ef: 75, probes: 5, minScore: 0.65 } }); } return await balancedTool.execute({ context: { queryText: query }, mastra, runtimeContext }); }; ``` ## Multi-Tenant Application with Pinecone Implement tenant isolation using Pinecone namespaces: ```typescript interface Tenant { id: string; name: string; namespace: string; } class MultiTenantSearchService { private searchTool: RagTool constructor() { this.searchTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "shared-documents", model: openai.embedding("text-embedding-3-small") }); } async searchForTenant(tenant: Tenant, query: string) { const runtimeContext = new RuntimeContext(); // Isolate search to tenant's namespace runtimeContext.set('databaseConfig', { pinecone: { namespace: tenant.namespace } }); const results = await this.searchTool.execute({ context: { queryText: query, topK: 10 }, mastra, runtimeContext }); // Add tenant context to results return { tenant: tenant.name, query, results: results.relevantContext, sources: results.sources }; } async bulkSearchForTenants(tenants: Tenant[], query: string) { const promises = tenants.map(tenant => this.searchForTenant(tenant, query) ); return await Promise.all(promises); } } // Usage const searchService = new MultiTenantSearchService(); const tenants = [ { id: '1', name: 'Company A', namespace: 'company-a' }, { id: '2', name: 'Company B', namespace: 'company-b' } ]; const results = await searchService.searchForTenant( tenants[0], "product documentation" ); ``` ## Hybrid Search with Pinecone Combine semantic and keyword search: ```typescript const hybridSearchTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "documents", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pinecone: { namespace: "production", sparseVector: { // Example sparse vector for keyword "API" indices: [1, 5, 10, 15], values: [0.8, 0.6, 0.4, 0.2] } } } }); // Helper function to generate sparse vectors for keywords const generateSparseVector = (keywords: string[]) => { // This is a simplified example - in practice, you'd use // a proper sparse encoding method like BM25 const indices: number[] = []; const values: number[] = []; keywords.forEach((keyword, i) => { const hash = keyword.split('').reduce((a, b) => { a = ((a << 5) - a) + b.charCodeAt(0); return a & a; }, 0); indices.push(Math.abs(hash) % 1000); values.push(1.0 / (i + 1)); // Decrease weight for later keywords }); return { indices, values }; }; const hybridSearch = async (query: string, keywords: string[]) => { const runtimeContext = new RuntimeContext(); if (keywords.length > 0) { const sparseVector = generateSparseVector(keywords); runtimeContext.set('databaseConfig', { pinecone: { namespace: "production", sparseVector } }); } return await hybridSearchTool.execute({ context: { queryText: query }, mastra, runtimeContext }); }; // Usage const results = await hybridSearch( "How to use the REST API", ["API", "REST", "documentation"] ); ``` ## Quality-Gated Search Implement progressive search quality: ```typescript const createQualityGatedSearch = () => { const baseConfig = { vectorStoreName: "postgres", indexName: "embeddings", model: openai.embedding("text-embedding-3-small") }; return { // High quality search first highQuality: createVectorQueryTool({ ...baseConfig, databaseConfig: { pgvector: { minScore: 0.85, ef: 200, probes: 15 } } }), // Medium quality fallback mediumQuality: createVectorQueryTool({ ...baseConfig, databaseConfig: { pgvector: { minScore: 0.7, ef: 150, probes: 10 } } }), // Low quality last resort lowQuality: createVectorQueryTool({ ...baseConfig, databaseConfig: { pgvector: { minScore: 0.5, ef: 100, probes: 5 } } }) }; }; const progressiveSearch = async (query: string, minResults: number = 3) => { const tools = createQualityGatedSearch(); // Try high quality first let results = await tools.highQuality.execute({ context: { queryText: query }, mastra }); if (results.sources.length >= minResults) { return { quality: 'high', ...results }; } // Fallback to medium quality results = await tools.mediumQuality.execute({ context: { queryText: query }, mastra }); if (results.sources.length >= minResults) { return { quality: 'medium', ...results }; } // Last resort: low quality results = await tools.lowQuality.execute({ context: { queryText: query }, mastra }); return { quality: 'low', ...results }; }; // Usage const results = await progressiveSearch("complex technical query", 5); console.log(`Found ${results.sources.length} results with ${results.quality} quality`); ``` ## Key Takeaways 1. **Environment Isolation**: Use namespaces to separate data by environment or tenant 2. **Performance Tuning**: Adjust ef/probes parameters based on your accuracy vs speed requirements 3. **Quality Control**: Use minScore to filter out low-quality matches 4. **Runtime Flexibility**: Override configurations dynamically based on context 5. **Progressive Quality**: Implement fallback strategies for different quality levels This approach allows you to optimize vector search for your specific use case while maintaining flexibility and performance. --- title: "Example: Agent-Driven Metadata Filtering | Retrieval | RAG | Mastra Docs" description: Example of using a Mastra agent in a RAG system to construct and apply metadata filters for document retrieval. --- import { GithubLink } from "@/components/github-link"; # Agent-Driven Metadata Filtering [EN] Source: https://mastra.ai/en/examples/rag/usage/filter-rag This example demonstrates how to implement a Retrieval-Augmented Generation (RAG) system using Mastra, OpenAI embeddings, and PGVector for vector storage. This system uses an agent to construct metadata filters from a user's query to search for relevant chunks in the vector store, reducing the amount of results returned. ## Overview The system implements metadata filtering using Mastra and OpenAI. Here's what it does: 1. Sets up a Mastra agent with gpt-4o-mini to understand queries and identify filter requirements 2. Creates a vector query tool to handle metadata filtering and semantic search 3. Processes documents into chunks with metadata and embeddings 4. Stores both vectors and metadata in PGVector for efficient retrieval 5. Processes queries by combining metadata filters with semantic search When a user asks a question: - The agent analyzes the query to understand the intent - Constructs appropriate metadata filters (e.g., by topic, date, category) - Uses the vector query tool to find the most relevant information - Generates a contextual response based on the filtered results ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_openai_api_key_here POSTGRES_CONNECTION_STRING=your_connection_string_here ``` ### Dependencies Then, import the necessary dependencies: ```typescript copy showLineNumbers filename="index.ts" import { openai } from "@ai-sdk/openai"; import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { PgVector, PGVECTOR_PROMPT } from "@mastra/pg"; import { createVectorQueryTool, MDocument } from "@mastra/rag"; import { embedMany } from "ai"; ``` ## Vector Query Tool Creation Using createVectorQueryTool imported from @mastra/rag, you can create a tool that enables metadata filtering. Each vector store has its own prompt that defines the supported filter operators and syntax: ```typescript copy showLineNumbers{9} filename="index.ts" const vectorQueryTool = createVectorQueryTool({ id: "vectorQueryTool", vectorStoreName: "pgVector", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), enableFilter: true, filterPrompt: PGVECTOR_PROMPT, // Use the prompt for your vector store }); ``` Each prompt includes: - Supported operators (comparison, array, logical, element) - Example usage for each operator - Store-specific restrictions and rules - Complex query examples ## Document Processing Create a document and process it into chunks with metadata: ```typescript copy showLineNumbers{17} filename="index.ts" const doc = MDocument.fromText( `The Impact of Climate Change on Global Agriculture...`, ); const chunks = await doc.chunk({ strategy: "recursive", size: 512, overlap: 50, separator: "\n", extract: { keywords: true, // Extracts keywords from each chunk }, }); ``` ### Transform Chunks into Metadata Transform chunks into metadata that can be filtered: ```typescript copy showLineNumbers{31} filename="index.ts" const chunkMetadata = chunks?.map((chunk: any, index: number) => ({ text: chunk.text, ...chunk.metadata, nested: { keywords: chunk.metadata.excerptKeywords .replace("KEYWORDS:", "") .split(",") .map((k) => k.trim()), id: index, }, })); ``` ## Agent Configuration The agent is configured to understand user queries and translate them into appropriate metadata filters. The agent requires both the vector query tool and a system prompt containing: - Metadata structure for available filter fields - Vector store prompt for filter operations and syntax ```typescript copy showLineNumbers{43} filename="index.ts" export const ragAgent = new Agent({ name: "RAG Agent", model: openai("gpt-4o-mini"), instructions: ` You are a helpful assistant that answers questions based on the provided context. Keep your answers concise and relevant. Filter the context by searching the metadata. The metadata is structured as follows: { text: string, excerptKeywords: string, nested: { keywords: string[], id: number, }, } ${PGVECTOR_PROMPT} Important: When asked to answer a question, please base your answer only on the context provided in the tool. If the context doesn't contain enough information to fully answer the question, please state that explicitly. `, tools: { vectorQueryTool }, }); ``` The agent's instructions are designed to: - Process user queries to identify filter requirements - Use the metadata structure to find relevant information - Apply appropriate filters through the vectorQueryTool and the provided vector store prompt - Generate responses based on the filtered context > Note: Different vector stores have specific prompts available. See [Vector Store Prompts](/docs/rag/retrieval#vector-store-prompts) for details. ## Instantiate PgVector and Mastra Instantiate PgVector and Mastra with the components: ```typescript copy showLineNumbers{69} filename="index.ts" const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); export const mastra = new Mastra({ agents: { ragAgent }, vectors: { pgVector }, }); const agent = mastra.getAgent("ragAgent"); ``` ## Creating and Storing Embeddings Generate embeddings and store them with metadata: ```typescript copy showLineNumbers{78} filename="index.ts" const { embeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: chunks.map((chunk) => chunk.text), }); const vectorStore = mastra.getVector("pgVector"); await vectorStore.createIndex({ indexName: "embeddings", dimension: 1536, }); // Store both embeddings and metadata together await vectorStore.upsert({ indexName: "embeddings", vectors: embeddings, metadata: chunkMetadata, }); ``` The `upsert` operation stores both the vector embeddings and their associated metadata, enabling combined semantic search and metadata filtering capabilities. ## Metadata-Based Querying Try different queries using metadata filters: ```typescript copy showLineNumbers{96} filename="index.ts" const queryOne = "What are the adaptation strategies mentioned?"; const answerOne = await agent.generate(queryOne); console.log("\nQuery:", queryOne); console.log("Response:", answerOne.text); const queryTwo = 'Show me recent sections. Check the "nested.id" field and return values that are greater than 2.'; const answerTwo = await agent.generate(queryTwo); console.log("\nQuery:", queryTwo); console.log("Response:", answerTwo.text); const queryThree = 'Search the "text" field using regex operator to find sections containing "temperature".'; const answerThree = await agent.generate(queryThree); console.log("\nQuery:", queryThree); console.log("Response:", answerThree.text); ```




--- title: "Example: A Complete Graph RAG System | RAG | Mastra Docs" description: Example of implementing a Graph RAG system in Mastra using OpenAI embeddings and PGVector for vector storage. --- import { GithubLink } from "@/components/github-link"; # Graph RAG [EN] Source: https://mastra.ai/en/examples/rag/usage/graph-rag This example demonstrates how to implement a Retrieval-Augmented Generation (RAG) system using Mastra, OpenAI embeddings, and PGVector for vector storage. ## Overview The system implements Graph RAG using Mastra and OpenAI. Here's what it does: 1. Sets up a Mastra agent with gpt-4o-mini for response generation 2. Creates a GraphRAG tool to manage vector store interactions and knowledge graph creation/traversal 3. Chunks text documents into smaller segments 4. Creates embeddings for these chunks 5. Stores them in a PostgreSQL vector database 6. Creates a knowledge graph of relevant chunks based on queries using GraphRAG tool - Tool returns results from vector store and creates knowledge graph - Traverses knowledge graph using query 7. Generates context-aware responses using the Mastra agent ## Setup ### Environment Setup Make sure to set up your environment variables: ```bash filename=".env" OPENAI_API_KEY=your_openai_api_key_here POSTGRES_CONNECTION_STRING=your_connection_string_here ``` ### Dependencies Then, import the necessary dependencies: ```typescript copy showLineNumbers filename="index.ts" import { openai } from "@ai-sdk/openai"; import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { PgVector } from "@mastra/pg"; import { MDocument, createGraphRAGTool } from "@mastra/rag"; import { embedMany } from "ai"; ``` ## GraphRAG Tool Creation Using createGraphRAGTool imported from @mastra/rag, you can create a tool that queries the vector database and converts the results into a knowledge graph: ```typescript copy showLineNumbers{8} filename="index.ts" const graphRagTool = createGraphRAGTool({ vectorStoreName: "pgVector", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), graphOptions: { dimension: 1536, threshold: 0.7, }, }); ``` ## Agent Configuration Set up the Mastra agent that will handle the responses: ```typescript copy showLineNumbers{19} filename="index.ts" const ragAgent = new Agent({ name: "GraphRAG Agent", instructions: `You are a helpful assistant that answers questions based on the provided context. Format your answers as follows: 1. DIRECT FACTS: List only the directly stated facts from the text relevant to the question (2-3 bullet points) 2. CONNECTIONS MADE: List the relationships you found between different parts of the text (2-3 bullet points) 3. CONCLUSION: One sentence summary that ties everything together Keep each section brief and focus on the most important points. Important: When asked to answer a question, please base your answer only on the context provided in the tool. If the context doesn't contain enough information to fully answer the question, please state that explicitly.`, model: openai("gpt-4o-mini"), tools: { graphRagTool, }, }); ``` ## Instantiate PgVector and Mastra Instantiate PgVector and Mastra with the components: ```typescript copy showLineNumbers{36} filename="index.ts" const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); export const mastra = new Mastra({ agents: { ragAgent }, vectors: { pgVector }, }); const agent = mastra.getAgent("ragAgent"); ``` ## Document Processing Create a document and process it into chunks: ```typescript copy showLineNumbers{45} filename="index.ts" const doc = MDocument.fromText(` # Riverdale Heights: Community Development Study // ... text content ... `); const chunks = await doc.chunk({ strategy: "recursive", size: 512, overlap: 50, separator: "\n", }); ``` ## Creating and Storing Embeddings Generate embeddings for the chunks and store them in the vector database: ```typescript copy showLineNumbers{56} filename="index.ts" const { embeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: chunks.map((chunk) => chunk.text), }); const vectorStore = mastra.getVector("pgVector"); await vectorStore.createIndex({ indexName: "embeddings", dimension: 1536, }); await vectorStore.upsert({ indexName: "embeddings", vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); ``` ## Graph-Based Querying Try different queries to explore relationships in the data: ```typescript copy showLineNumbers{82} filename="index.ts" const queryOne = "What are the direct and indirect effects of early railway decisions on Riverdale Heights' current state?"; const answerOne = await ragAgent.generate(queryOne); console.log("\nQuery:", queryOne); console.log("Response:", answerOne.text); const queryTwo = "How have changes in transportation infrastructure affected different generations of local businesses and community spaces?"; const answerTwo = await ragAgent.generate(queryTwo); console.log("\nQuery:", queryTwo); console.log("Response:", answerTwo.text); const queryThree = "Compare how the Rossi family business and Thompson Steel Works responded to major infrastructure changes, and how their responses affected the community."; const answerThree = await ragAgent.generate(queryThree); console.log("\nQuery:", queryThree); console.log("Response:", answerThree.text); const queryFour = "Trace how the transformation of the Thompson Steel Works site has influenced surrounding businesses and cultural spaces from 1932 to present."; const answerFour = await ragAgent.generate(queryFour); console.log("\nQuery:", queryFour); console.log("Response:", answerFour.text); ```




--- title: Speech to Speech description: Example of using Mastra to create a speech to speech application. --- import { GithubLink } from "@/components/github-link"; # Call Analysis with Mastra [EN] Source: https://mastra.ai/en/examples/voice/speech-to-speech This guide demonstrates how to build a complete voice conversation system with analytics using Mastra. The example includes real-time speech-to-speech conversation, recording management, and integration with Roark Analytics for call analysis. ## Overview The system creates a voice conversation with a Mastra agent, records the entire interaction, uploads the recording to Cloudinary for storage, and then sends the conversation data to Roark Analytics for detailed call analysis. ## Setup ### Prerequisites 1. OpenAI API key for speech-to-text and text-to-speech capabilities 2. Cloudinary account for audio file storage 3. Roark Analytics API key for call analysis ### Environment Configuration Create a `.env` file based on the sample provided: ```bash filename="speech-to-speech/call-analysis/sample.env" copy OPENAI_API_KEY= CLOUDINARY_CLOUD_NAME= CLOUDINARY_API_KEY= CLOUDINARY_API_SECRET= ROARK_API_KEY= ``` ### Installation Install the required dependencies: ```bash copy npm install ``` ## Implementation ### Creating the Mastra Agent First, we define our agent with voice capabilities: ```ts filename="speech-to-speech/call-analysis/src/mastra/agents/index.ts" copy import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { createTool } from "@mastra/core/tools"; import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import { z } from "zod"; // Have the agent do something export const speechToSpeechServer = new Agent({ name: "mastra", instructions: "You are a helpful assistant.", voice: new OpenAIRealtimeVoice(), model: openai("gpt-4o"), tools: { salutationTool: createTool({ id: "salutationTool", description: "Read the result of the tool", inputSchema: z.object({ name: z.string() }), outputSchema: z.object({ message: z.string() }), execute: async ({ context }) => { return { message: `Hello ${context.name}!` }; }, }), }, }); ``` ### Initializing Mastra Register the agent with Mastra: ```ts filename="speech-to-speech/call-analysis/src/mastra/index.ts" copy import { Mastra } from "@mastra/core"; import { speechToSpeechServer } from "./agents"; export const mastra = new Mastra({ agents: { speechToSpeechServer, }, }); ``` ### Cloudinary Integration for Audio Storage Set up Cloudinary for storing the recorded audio files: ```ts filename="speech-to-speech/call-analysis/src/upload.ts" copy import { v2 as cloudinary } from "cloudinary"; cloudinary.config({ cloud_name: process.env.CLOUDINARY_CLOUD_NAME, api_key: process.env.CLOUDINARY_API_KEY, api_secret: process.env.CLOUDINARY_API_SECRET, }); export async function uploadToCloudinary(path: string) { const response = await cloudinary.uploader.upload(path, { resource_type: "raw", }); console.log(response); return response.url; } ``` ### Main Application Logic The main application orchestrates the conversation flow, recording, and analytics integration: ```ts filename="speech-to-speech/call-analysis/src/base.ts" copy import { Roark } from "@roarkanalytics/sdk"; import chalk from "chalk"; import { mastra } from "./mastra"; import { createConversation, formatToolInvocations } from "./utils"; import { uploadToCloudinary } from "./upload"; import fs from "fs"; const client = new Roark({ bearerToken: process.env.ROARK_API_KEY, }); async function speechToSpeechServerExample() { const { start, stop } = createConversation({ mastra, recordingPath: "./speech-to-speech-server.mp3", providerOptions: {}, initialMessage: "Howdy partner", onConversationEnd: async (props) => { // File upload fs.writeFileSync(props.recordingPath, props.audioBuffer); const url = await uploadToCloudinary(props.recordingPath); // Send to Roark console.log("Send to Roark", url); const response = await client.callAnalysis.create({ recordingUrl: url, startedAt: props.startedAt, callDirection: "INBOUND", interfaceType: "PHONE", participants: [ { role: "AGENT", spokeFirst: props.agent.spokeFirst, name: props.agent.name, phoneNumber: props.agent.phoneNumber, }, { role: "CUSTOMER", name: "Yujohn Nattrass", phoneNumber: "987654321", }, ], properties: props.metadata, toolInvocations: formatToolInvocations(props.toolInvocations), }); console.log("Call Recording Posted:", response.data); }, onWriting: (ev) => { if (ev.role === "assistant") { process.stdout.write(chalk.blue(ev.text)); } }, }); await start(); process.on("SIGINT", async (e) => { await stop(); }); } speechToSpeechServerExample().catch(console.error); ``` ## Conversation Utilities The `utils.ts` file contains helper functions for managing the conversation, including: 1. Creating and managing the conversation session 2. Handling audio recording 3. Processing tool invocations 4. Managing conversation lifecycle events ## Running the Example Start the conversation with: ```bash copy npm run dev ``` The application will: 1. Start a real-time voice conversation with the Mastra agent 2. Record the entire conversation 3. Upload the recording to Cloudinary when the conversation ends 4. Send the conversation data to Roark Analytics for analysis 5. Display the analysis results ## Key Features - **Real-time Speech-to-Speech**: Uses OpenAI's voice models for natural conversation - **Conversation Recording**: Captures the entire conversation for later analysis - **Tool Invocation Tracking**: Records when and how AI tools are used during the conversation - **Analytics Integration**: Sends conversation data to Roark Analytics for detailed analysis - **Cloud Storage**: Uploads recordings to Cloudinary for secure storage and access ## Customization You can customize this example by: - Modifying the agent's instructions and capabilities - Adding additional tools for the agent to use - Changing the conversation flow or initial message - Extending the analytics integration with custom metadata To view the full example code, see the [Github repository](https://github.com/mastra-ai/voice-examples/tree/main/speech-to-speech/call-analysis).

--- title: "Example: Speech to Text | Voice | Mastra Docs" description: Example of using Mastra to create a speech to text application. --- import { GithubLink } from "@/components/github-link"; # Smart Voice Memo App [EN] Source: https://mastra.ai/en/examples/voice/speech-to-text The following code snippets provide example implementations of Speech-to-Text (STT) functionality in a smart voice memo application using Next.js with direct integration of Mastra. For more details on integrating Mastra with Next.js, please refer to our [Integrate with Next.js](/docs/frameworks/next-js) documentation. ## Creating an Agent with STT Capabilities The following example shows how to initialize a voice-enabled agent with OpenAI's STT capabilities: ```typescript filename="src/mastra/agents/index.ts" import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { OpenAIVoice } from "@mastra/voice-openai"; const instructions = ` You are an AI note assistant tasked with providing concise, structured summaries of their content... // omitted for brevity `; export const noteTakerAgent = new Agent({ name: "Note Taker Agent", instructions: instructions, model: openai("gpt-4o"), voice: new OpenAIVoice(), // Add OpenAI voice provider with default configuration }); ``` ## Registering the Agent with Mastra This snippet demonstrates how to register the STT-enabled agent with your Mastra instance: ```typescript filename="src/mastra/index.ts" import { PinoLogger } from "@mastra/loggers"; import { Mastra } from "@mastra/core/mastra"; import { noteTakerAgent } from "./agents"; export const mastra = new Mastra({ agents: { noteTakerAgent }, // Register the note taker agent logger: new PinoLogger({ name: "Mastra", level: "info", }), }); ``` ## Processing Audio for Transcription The following code shows how to receive audio from a web request and use the agent's STT capabilities to transcribe it: ```typescript filename="app/api/audio/route.ts" import { mastra } from "@/src/mastra"; // Import the Mastra instance import { Readable } from "node:stream"; export async function POST(req: Request) { // Get the audio file from the request const formData = await req.formData(); const audioFile = formData.get("audio") as File; const arrayBuffer = await audioFile.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); const readable = Readable.from(buffer); // Get the note taker agent from the Mastra instance const noteTakerAgent = mastra.getAgent("noteTakerAgent"); // Transcribe the audio file const text = await noteTakerAgent.voice?.listen(readable); return new Response(JSON.stringify({ text }), { headers: { "Content-Type": "application/json" }, }); } ``` You can view the complete implementation of the Smart Voice Memo App on our GitHub repository.




--- title: "Example: Text to Speech | Voice | Mastra Docs" description: Example of using Mastra to create a text to speech application. --- import { GithubLink } from "@/components/github-link"; # Interactive Story Generator [EN] Source: https://mastra.ai/en/examples/voice/text-to-speech The following code snippets provide example implementations of Text-to-Speech (TTS) functionality in an interactive story generator application using Next.js with Mastra as a separate backend integration. This example demonstrates how to use the Mastra client-js SDK to connect to your Mastra backend. For more details on integrating Mastra with Next.js, please refer to our [Integrate with Next.js](/docs/frameworks/next-js) documentation. ## Creating an Agent with TTS Capabilities The following example shows how to set up a story generator agent with TTS capabilities on the backend: ```typescript filename="src/mastra/agents/index.ts" import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { OpenAIVoice } from "@mastra/voice-openai"; import { Memory } from "@mastra/memory"; const instructions = ` You are an Interactive Storyteller Agent. Your job is to create engaging short stories with user choices that influence the narrative. // omitted for brevity `; export const storyTellerAgent = new Agent({ name: "Story Teller Agent", instructions: instructions, model: openai("gpt-4o"), voice: new OpenAIVoice(), }); ``` ## Registering the Agent with Mastra This snippet demonstrates how to register the agent with your Mastra instance: ```typescript filename="src/mastra/index.ts" import { PinoLogger } from "@mastra/loggers"; import { Mastra } from "@mastra/core/mastra"; import { storyTellerAgent } from "./agents"; export const mastra = new Mastra({ agents: { storyTellerAgent }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); ``` ## Connecting to Mastra from the Frontend Here we use the Mastra Client SDK to interact with our Mastra server. For more information about the Mastra Client SDK, check out the [documentation](/docs/deployment/client). ```typescript filename="src/app/page.tsx" import { MastraClient } from "@mastra/client-js"; export const mastraClient = new MastraClient({ baseUrl: "http://localhost:4111", // Replace with your Mastra backend URL }); ``` ## Generating Story Content and Converting to Speech This example demonstrates how to get a reference to a Mastra agent, generate story content based on user input, and then convert that content to speech: ```typescript filename="/app/components/StoryManager.tsx" const handleInitialSubmit = async (formData: FormData) => { setIsLoading(true); try { const agent = mastraClient.getAgent("storyTellerAgent"); const message = `Current phase: BEGINNING. Story genre: ${formData.genre}, Protagonist name: ${formData.protagonistDetails.name}, Protagonist age: ${formData.protagonistDetails.age}, Protagonist gender: ${formData.protagonistDetails.gender}, Protagonist occupation: ${formData.protagonistDetails.occupation}, Story Setting: ${formData.setting}`; const storyResponse = await agent.generate({ messages: [{ role: "user", content: message }], threadId: storyState.threadId, resourceId: storyState.resourceId, }); const storyText = storyResponse.text; const audioResponse = await agent.voice.speak(storyText); if (!audioResponse.body) { throw new Error("No audio stream received"); } const audio = await readStream(audioResponse.body); setStoryState((prev) => ({ phase: "beginning", threadId: prev.threadId, resourceId: prev.resourceId, content: { ...prev.content, beginning: storyText, }, })); setAudioBlob(audio); return audio; } catch (error) { console.error("Error generating story beginning:", error); } finally { setIsLoading(false); } }; ``` ## Playing the Audio This snippet demonstrates how to handle text-to-speech audio playback by monitoring for new audio data. When audio is received, the code creates a browser-playable URL from the audio blob, assigns it to an audio element, and attempts to play it automatically: ```typescript filename="/app/components/StoryManager.tsx" useEffect(() => { if (!audioRef.current || !audioData) return; // Store a reference to the HTML audio element const currentAudio = audioRef.current; // Convert the Blob/File audio data from Mastra into a URL the browser can play const url = URL.createObjectURL(audioData); const playAudio = async () => { try { currentAudio.src = url; await currentAudio.load(); await currentAudio.play(); setIsPlaying(true); } catch (error) { console.error("Auto-play failed:", error); } }; playAudio(); return () => { if (currentAudio) { currentAudio.pause(); currentAudio.src = ""; URL.revokeObjectURL(url); } }; }, [audioData]); ``` You can view the complete implementation of the Interactive Story Generator on our GitHub repository.




--- title: Turn Taking description: Example of using Mastra to create a multi-agent debate with turn-taking conversation flow. --- import { GithubLink } from "@/components/github-link"; # AI Debate with Turn Taking [EN] Source: https://mastra.ai/en/examples/voice/turn-taking The following code snippets demonstrate how to implement a multi-agent conversation system with turn-taking using Mastra. This example creates a debate between two AI agents (an optimist and a skeptic) who discuss a user-provided topic, taking turns to respond to each other's points. ## Creating Agents with Voice Capabilities First, we need to create two agents with distinct personalities and voice capabilities: ```typescript filename="src/mastra/agents/index.ts" import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { OpenAIVoice } from "@mastra/voice-openai"; export const optimistAgent = new Agent({ name: "Optimist", instructions: "You are an optimistic debater who sees the positive side of every topic. Keep your responses concise and engaging, about 2-3 sentences.", model: openai("gpt-4o"), voice: new OpenAIVoice({ speaker: "alloy", }), }); export const skepticAgent = new Agent({ name: "Skeptic", instructions: "You are a RUDE skeptical debater who questions assumptions and points out potential issues. Keep your responses concise and engaging, about 2-3 sentences.", model: openai("gpt-4o"), voice: new OpenAIVoice({ speaker: "echo", }), }); ``` ## Registering the Agents with Mastra Next, register both agents with your Mastra instance: ```typescript filename="src/mastra/index.ts" import { PinoLogger } from "@mastra/loggers"; import { Mastra } from "@mastra/core/mastra"; import { optimistAgent, skepticAgent } from "./agents"; export const mastra = new Mastra({ agents: { optimistAgent, skepticAgent, }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); ``` ## Managing Turn-Taking in the Debate This example demonstrates how to manage the turn-taking flow between agents, ensuring each agent responds to the previous agent's statements: ```typescript filename="src/debate/turn-taking.ts" import { mastra } from "../../mastra"; import { playAudio, Recorder } from "@mastra/node-audio"; import * as p from "@clack/prompts"; // Helper function to format text with line wrapping function formatText(text: string, maxWidth: number): string { const words = text.split(" "); let result = ""; let currentLine = ""; for (const word of words) { if (currentLine.length + word.length + 1 <= maxWidth) { currentLine += (currentLine ? " " : "") + word; } else { result += (result ? "\n" : "") + currentLine; currentLine = word; } } if (currentLine) { result += (result ? "\n" : "") + currentLine; } return result; } // Initialize audio recorder const recorder = new Recorder({ outputPath: "./debate.mp3", }); // Process one turn of the conversation async function processTurn( agentName: "optimistAgent" | "skepticAgent", otherAgentName: string, topic: string, previousResponse: string = "", ) { const agent = mastra.getAgent(agentName); const spinner = p.spinner(); spinner.start(`${agent.name} is thinking...`); let prompt; if (!previousResponse) { // First turn prompt = `Discuss this topic: ${topic}. Introduce your perspective on it.`; } else { // Responding to the other agent prompt = `The topic is: ${topic}. ${otherAgentName} just said: "${previousResponse}". Respond to their points.`; } // Generate text response const { text } = await agent.generate(prompt, { temperature: 0.9, }); spinner.message(`${agent.name} is speaking...`); // Convert to speech and play const audioStream = await agent.voice.speak(text, { speed: 1.2, responseFormat: "wav", // Optional: specify a response format }); if (audioStream) { audioStream.on("data", (chunk) => { recorder.write(chunk); }); } spinner.stop(`${agent.name} said:`); // Format the text to wrap at 80 characters for better display const formattedText = formatText(text, 80); p.note(formattedText, agent.name); if (audioStream) { const speaker = playAudio(audioStream); await new Promise((resolve) => { speaker.once("close", () => { resolve(); }); }); } return text; } // Main function to run the debate export async function runDebate(topic: string, turns: number = 3) { recorder.start(); p.intro("AI Debate - Two Agents Discussing a Topic"); p.log.info(`Starting a debate on: ${topic}`); p.log.info( `The debate will continue for ${turns} turns each. Press Ctrl+C to exit at any time.`, ); let optimistResponse = ""; let skepticResponse = ""; const responses = []; for (let turn = 1; turn <= turns; turn++) { p.log.step(`Turn ${turn}`); // Optimist's turn optimistResponse = await processTurn( "optimistAgent", "Skeptic", topic, skepticResponse, ); responses.push({ agent: "Optimist", text: optimistResponse, }); // Skeptic's turn skepticResponse = await processTurn( "skepticAgent", "Optimist", topic, optimistResponse, ); responses.push({ agent: "Skeptic", text: skepticResponse, }); } recorder.end(); p.outro("Debate concluded! The full audio has been saved to debate.mp3"); return responses; } ``` ## Running the Debate from the Command Line Here's a simple script to run the debate from the command line: ```typescript filename="src/index.ts" import { runDebate } from "./debate/turn-taking"; import * as p from "@clack/prompts"; async function main() { // Get the topic from the user const topic = await p.text({ message: "Enter a topic for the agents to discuss:", placeholder: "Climate change", validate(value) { if (!value) return "Please enter a topic"; return; }, }); // Exit if cancelled if (p.isCancel(topic)) { p.cancel("Operation cancelled."); process.exit(0); } // Get the number of turns const turnsInput = await p.text({ message: "How many turns should each agent have?", placeholder: "3", initialValue: "3", validate(value) { const num = parseInt(value); if (isNaN(num) || num < 1) return "Please enter a positive number"; return; }, }); // Exit if cancelled if (p.isCancel(turnsInput)) { p.cancel("Operation cancelled."); process.exit(0); } const turns = parseInt(turnsInput as string); // Run the debate await runDebate(topic as string, turns); } main().catch((error) => { p.log.error("An error occurred:"); console.error(error); process.exit(1); }); ``` ## Creating a Web Interface for the Debate For web applications, you can create a simple Next.js component that allows users to start a debate and listen to the agents' responses: ```tsx filename="app/components/DebateInterface.tsx" "use client"; import { useState, useRef } from "react"; import { MastraClient } from "@mastra/client-js"; const mastraClient = new MastraClient({ baseUrl: process.env.NEXT_PUBLIC_MASTRA_URL || "http://localhost:4111", }); export default function DebateInterface() { const [topic, setTopic] = useState(""); const [turns, setTurns] = useState(3); const [isDebating, setIsDebating] = useState(false); const [responses, setResponses] = useState([]); const [isPlaying, setIsPlaying] = useState(false); const audioRef = useRef(null); // Function to start the debate const startDebate = async () => { if (!topic) return; setIsDebating(true); setResponses([]); try { const optimist = mastraClient.getAgent("optimistAgent"); const skeptic = mastraClient.getAgent("skepticAgent"); const newResponses = []; let optimistResponse = ""; let skepticResponse = ""; for (let turn = 1; turn <= turns; turn++) { // Optimist's turn let prompt; if (turn === 1) { prompt = `Discuss this topic: ${topic}. Introduce your perspective on it.`; } else { prompt = `The topic is: ${topic}. Skeptic just said: "${skepticResponse}". Respond to their points.`; } const optimistResult = await optimist.generate({ messages: [{ role: "user", content: prompt }], }); optimistResponse = optimistResult.text; newResponses.push({ agent: "Optimist", text: optimistResponse, }); // Update UI after each response setResponses([...newResponses]); // Skeptic's turn prompt = `The topic is: ${topic}. Optimist just said: "${optimistResponse}". Respond to their points.`; const skepticResult = await skeptic.generate({ messages: [{ role: "user", content: prompt }], }); skepticResponse = skepticResult.text; newResponses.push({ agent: "Skeptic", text: skepticResponse, }); // Update UI after each response setResponses([...newResponses]); } } catch (error) { console.error("Error starting debate:", error); } finally { setIsDebating(false); } }; // Function to play audio for a specific response const playAudio = async (text: string, agent: string) => { if (isPlaying) return; try { setIsPlaying(true); const agentClient = mastraClient.getAgent( agent === "Optimist" ? "optimistAgent" : "skepticAgent", ); const audioResponse = await agentClient.voice.speak(text); if (!audioResponse.body) { throw new Error("No audio stream received"); } // Convert stream to blob const reader = audioResponse.body.getReader(); const chunks = []; while (true) { const { done, value } = await reader.read(); if (done) break; chunks.push(value); } const blob = new Blob(chunks, { type: "audio/mpeg" }); const url = URL.createObjectURL(blob); if (audioRef.current) { audioRef.current.src = url; audioRef.current.onended = () => { setIsPlaying(false); URL.revokeObjectURL(url); }; audioRef.current.play(); } } catch (error) { console.error("Error playing audio:", error); setIsPlaying(false); } }; return (

AI Debate with Turn Taking

setTopic(e.target.value)} className="w-full p-2 border rounded" placeholder="e.g., Climate change, AI ethics, Space exploration" />
setTurns(parseInt(e.target.value))} min={1} max={10} className="w-full p-2 border rounded" />
); } ``` This example demonstrates how to create a multi-agent conversation system with turn-taking using Mastra. The agents engage in a debate on a user-chosen topic, with each agent responding to the previous agent's statements. The system also converts each agent's responses to speech, providing an immersive debate experience. You can view the complete implementation of the AI Debate with Turn Taking on our GitHub repository.




--- title: "Example: Using a Tool/Agent as a Step | Workflows | Mastra Docs" description: Example of using Mastra to integrate a tool or an agent as a step in a workflow. --- # Tool/Agent as a Workflow step [EN] Source: https://mastra.ai/en/examples/workflows/agent-and-tool-interop This example demonstrates how to create and integrate a tool or an agent as a workflow step. Mastra provides a `createStep` helper function which accepts either a step or agent and returns an object which satisfies the Step interface. ## Setup ```sh copy npm install @ai-sdk/openai @mastra/core ``` ## Define Weather Reporter Agent Define a weather reporter agent that leverages an LLM to explain the weather report like a weather reporter. ```ts showLineNumbers copy filename="agents/weather-reporter-agent.ts" import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; // Create an agent that explains weather reports in a conversational style export const weatherReporterAgent = new Agent({ name: "weatherExplainerAgent", model: openai("gpt-4o"), instructions: ` You are a weather explainer. You have access to input that will help you get weather-specific activities for any city. The tool uses agents to plan the activities, you just need to provide the city. Explain the weather report like a weather reporter. `, }); ``` ## Define Weather Tool Define a weather tool that take a location name as input and outputs detailed weather information. ```ts showLineNumbers copy filename="tools/weather-tool.ts" import { createTool } from "@mastra/core/tools"; import { z } from "zod"; interface GeocodingResponse { results: { latitude: number; longitude: number; name: string; }[]; } interface WeatherResponse { current: { time: string; temperature_2m: number; apparent_temperature: number; relative_humidity_2m: number; wind_speed_10m: number; wind_gusts_10m: number; weather_code: number; }; } // Create a tool to fetch weather data export const weatherTool = createTool({ id: "get-weather", description: "Get current weather for a location", inputSchema: z.object({ location: z.string().describe("City name"), }), outputSchema: z.object({ temperature: z.number(), feelsLike: z.number(), humidity: z.number(), windSpeed: z.number(), windGust: z.number(), conditions: z.string(), location: z.string(), }), execute: async ({ context }) => { return await getWeather(context.location); }, }); // Helper function to fetch weather data from external APIs const getWeather = async (location: string) => { const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(location)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = (await geocodingResponse.json()) as GeocodingResponse; if (!geocodingData.results?.[0]) { throw new Error(`Location '${location}' not found`); } const { latitude, longitude, name } = geocodingData.results[0]; const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m,wind_gusts_10m,weather_code`; const response = await fetch(weatherUrl); const data = (await response.json()) as WeatherResponse; return { temperature: data.current.temperature_2m, feelsLike: data.current.apparent_temperature, humidity: data.current.relative_humidity_2m, windSpeed: data.current.wind_speed_10m, windGust: data.current.wind_gusts_10m, conditions: getWeatherCondition(data.current.weather_code), location: name, }; }; // Helper function to convert numeric weather codes to human-readable descriptions function getWeatherCondition(code: number): string { const conditions: Record = { 0: "Clear sky", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast", 45: "Foggy", 48: "Depositing rime fog", 51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle", 56: "Light freezing drizzle", 57: "Dense freezing drizzle", 61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain", 66: "Light freezing rain", 67: "Heavy freezing rain", 71: "Slight snow fall", 73: "Moderate snow fall", 75: "Heavy snow fall", 77: "Snow grains", 80: "Slight rain showers", 81: "Moderate rain showers", 82: "Violent rain showers", 85: "Slight snow showers", 86: "Heavy snow showers", 95: "Thunderstorm", 96: "Thunderstorm with slight hail", 99: "Thunderstorm with heavy hail", }; return conditions[code] || "Unknown"; } ``` ## Define Interop Workflow Defines a workflow which takes an agent and tool as a step. ```ts showLineNumbers copy filename="workflows/interop-workflow.ts" import { createWorkflow, createStep } from "@mastra/core/workflows"; import { weatherTool } from "../tools/weather-tool"; import { weatherReporterAgent } from "../agents/weather-reporter-agent"; import { z } from "zod"; // Create workflow steps from existing tool and agent const fetchWeather = createStep(weatherTool); const reportWeather = createStep(weatherReporterAgent); const weatherWorkflow = createWorkflow({ steps: [fetchWeather, reportWeather], id: "weather-workflow-step1-single-day", inputSchema: z.object({ location: z.string().describe("The city to get the weather for"), }), outputSchema: z.object({ text: z.string(), }), }) .then(fetchWeather) .then( createStep({ id: "report-weather", inputSchema: fetchWeather.outputSchema, outputSchema: z.object({ text: z.string(), }), execute: async ({ inputData, mastra }) => { // Create a prompt with the weather data const prompt = "Forecast data: " + JSON.stringify(inputData); const agent = mastra.getAgent("weatherReporterAgent"); // Generate a weather report using the agent const result = await agent.generate([ { role: "user", content: prompt, }, ]); return { text: result.text }; }, }), ); weatherWorkflow.commit(); export { weatherWorkflow }; ``` ## Register Workflow instance with Mastra class Register the workflow with the mastra instance. ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { PinoLogger } from "@mastra/loggers"; import { weatherWorkflow } from "./workflows/interop-workflow"; import { weatherReporterAgent } from "./agents/weather-reporter-agent"; // Create a new Mastra instance with our components const mastra = new Mastra({ workflows: { weatherWorkflow, }, agents: { weatherReporterAgent, }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## Execute the workflow Here, we'll get the weather workflow from the mastra instance, then create a run and execute the created run with the required inputData. ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; const workflow = mastra.getWorkflow("weatherWorkflow"); const run = workflow.createRun(); // Start the workflow with Lagos as the location const result = await run.start({ inputData: { location: "Lagos" } }); console.dir(result, { depth: null }); ``` --- title: "Example: Array as Input (.foreach()) | Workflows | Mastra Docs" description: Example of using Mastra to process an array using .foreach() in a workflow. --- # Array as Input [EN] Source: https://mastra.ai/en/examples/workflows/array-as-input This example demonstrates how to process an array input in a workflow. Mastra provides a `.foreach()` helper function that executes a step for each item in the array. ## Setup ```sh copy npm install @ai-sdk/openai @mastra/core simple-git ``` ## Define Docs Generator Agent Define a docs generator agent that leverages an LLM call to generate a documentation given a code file or a summary of a code file. ```ts showLineNumbers copy filename="agents/docs-generator-agent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // Create a documentation generator agent for code analysis const docGeneratorAgent = new Agent({ name: "doc_generator_agent", instructions: `You are a technical documentation expert. You will analyze the provided code files and generate a comprehensive documentation summary. For each file: 1. Identify the main purpose and functionality 2. Document key components, classes, functions, and interfaces 3. Note important dependencies and relationships between components 4. Highlight any notable patterns or architectural decisions 5. Include relevant code examples where helpful Format the documentation in a clear, organized manner using markdown with: - File overviews - Component breakdowns - Code examples - Cross-references between related components Focus on making the documentation clear and useful for developers who need to understand and work with this codebase.`, model: openai("gpt-4o"), }); export { docGeneratorAgent }; ``` ## Define File Summary Workflow Define the file summary workflow with 2 steps: one to fetch the code of a particular file and another to generate a readme for that particular code file. ```ts showLineNumbers copy filename="workflows/file-summary-workflow.ts" import { createWorkflow, createStep } from "@mastra/core/workflows"; import { docGeneratorAgent } from "../agents/docs-generator-agent"; import { z } from "zod"; import fs from "fs"; // Step 1: Read the code content from a file const scrapeCodeStep = createStep({ id: "scrape_code", description: "Scrape the code from a single file", inputSchema: z.string(), outputSchema: z.object({ path: z.string(), content: z.string(), }), execute: async ({ inputData }) => { const filePath = inputData; const content = fs.readFileSync(filePath, "utf-8"); return { path: filePath, content, }; }, }); // Step 2: Generate documentation for a single file const generateDocForFileStep = createStep({ id: "generateDocForFile", inputSchema: z.object({ path: z.string(), content: z.string(), }), outputSchema: z.object({ path: z.string(), documentation: z.string(), }), execute: async ({ inputData }) => { const docs = await docGeneratorAgent.generate( `Generate documentation for the following code: ${inputData.content}`, ); return { path: inputData.path, documentation: docs.text.toString(), }; }, }); const generateSummaryWorkflow = createWorkflow({ id: "generate-summary", inputSchema: z.string(), outputSchema: z.object({ path: z.string(), documentation: z.string(), }), steps: [scrapeCodeStep, generateDocForFileStep], }) .then(scrapeCodeStep) .then(generateDocForFileStep) .commit(); export { generateSummaryWorkflow }; ``` ## Define Readme Generator Workflow Define a readme generator workflow with 4 steps: one to clone the github repository, one to suspend the workflow and get user input on what all folders to consider while generating a readme, one to generate a summary of all the files inside the folder, and another to collate all the documentation generated for each file into a single readme. ```ts showLineNumbers copy filename="workflows/readme-generator-workflow.ts import { createWorkflow, createStep } from "@mastra/core/workflows"; import { docGeneratorAgent } from "../agents/docs-generator-agent"; import { generateSummaryWorkflow } from "./file-summary-workflow"; import { z } from "zod"; import simpleGit from "simple-git"; import fs from "fs"; import path from "path"; // Step 1: Clone a GitHub repository locally const cloneRepositoryStep = createStep({ id: "clone_repository", description: "Clone the repository from the given URL", inputSchema: z.object({ repoUrl: z.string(), }), outputSchema: z.object({ success: z.boolean(), message: z.string(), data: z.object({ repoUrl: z.string(), }), }), execute: async ({ inputData, mastra, getStepResult, getInitData, runtimeContext, }) => { const git = simpleGit(); // Skip cloning if repo already exists if (fs.existsSync("./temp")) { return { success: true, message: "Repository already exists", data: { repoUrl: inputData.repoUrl, }, }; } try { // Clone the repository to the ./temp directory await git.clone(inputData.repoUrl, "./temp"); return { success: true, message: "Repository cloned successfully", data: { repoUrl: inputData.repoUrl, }, }; } catch (error) { throw new Error(`Failed to clone repository: ${error}`); } }, }); // Step 2: Get user input on which folders to analyze const selectFolderStep = createStep({ id: "select_folder", description: "Select the folder(s) to generate the docs", inputSchema: z.object({ success: z.boolean(), message: z.string(), data: z.object({ repoUrl: z.string(), }), }), outputSchema: z.array(z.string()), suspendSchema: z.object({ folders: z.array(z.string()), message: z.string(), }), resumeSchema: z.object({ selection: z.array(z.string()), }), execute: async ({ resumeData, suspend }) => { const tempPath = "./temp"; const folders = fs .readdirSync(tempPath) .filter((item) => fs.statSync(path.join(tempPath, item)).isDirectory()); if (!resumeData?.selection) { await suspend({ folders, message: "Please select folders to generate documentation for:", }); return []; } // Gather all file paths from selected folders const filePaths: string[] = []; // Helper function to recursively read files from directories const readFilesRecursively = (dir: string) => { const items = fs.readdirSync(dir); for (const item of items) { const fullPath = path.join(dir, item); const stat = fs.statSync(fullPath); if (stat.isDirectory()) { readFilesRecursively(fullPath); } else if (stat.isFile()) { filePaths.push(fullPath.replace(tempPath + "/", "")); } } }; for (const folder of resumeData.selection) { readFilesRecursively(path.join(tempPath, folder)); } return filePaths; }, }); // Step 4: Combine all documentation into a single README const collateDocumentationStep = createStep({ id: "collate_documentation", inputSchema: z.array( z.object({ path: z.string(), documentation: z.string(), }), ), outputSchema: z.string(), execute: async ({ inputData }) => { const readme = await docGeneratorAgent.generate( `Generate a README.md file for the following documentation: ${inputData.map((doc) => doc.documentation).join("\n")}`, ); return readme.text.toString(); }, }); const readmeGeneratorWorkflow = createWorkflow({ id: "readme-generator", inputSchema: z.object({ repoUrl: z.string(), }), outputSchema: z.object({ success: z.boolean(), message: z.string(), data: z.object({ repoUrl: z.string(), }), }), steps: [ cloneRepositoryStep, selectFolderStep, generateSummaryWorkflow, collateDocumentationStep, ], }) .then(cloneRepositoryStep) .then(selectFolderStep) .foreach(generateSummaryWorkflow) .then(collateDocumentationStep) .commit(); export { readmeGeneratorWorkflow }; ``` ## Register Agent and Workflow instances with Mastra class Register the agents and workflow with the mastra instance. This is critical for enabling access to the agents within the workflow. ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core"; import { PinoLogger } from "@mastra/loggers"; import { docGeneratorAgent } from "./agents/docs-generator-agent"; import { readmeGeneratorWorkflow } from "./workflows/readme-generator-workflow"; import { generateSummaryWorkflow } from "./workflows/file-summary-workflow"; // Create a new Mastra instance and register components const mastra = new Mastra({ agents: { docGeneratorAgent, }, workflows: { readmeGeneratorWorkflow, generateSummaryWorkflow, }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## Execute the Readme Generator Workflow Here, we'll get the reamde generator workflow from the mastra instance, then create a run and execute the created run with the required inputData. ```ts showLineNumbers copy filename="exec.ts" import { promptUserForFolders } from "./utils"; import { mastra } from "./"; // GitHub repository to generate documentation for const ghRepoUrl = "https://github.com/mastra-ai/mastra"; const run = mastra.getWorkflow("readmeGeneratorWorkflow").createRun(); // Start the workflow with the repository URL as input const res = await run.start({ inputData: { repoUrl: ghRepoUrl } }); const { status, steps } = res; // Handle suspended workflow (waiting for user input) if (status === "suspended") { // Get the suspended step data const suspendedStep = steps["select_folder"]; let folderList: string[] = []; // Extract the folder list from step data if ( suspendedStep.status === "suspended" && "folders" in suspendedStep.payload ) { folderList = suspendedStep.payload.folders as string[]; } else if (suspendedStep.status === "success" && suspendedStep.output) { folderList = suspendedStep.output; } if (!folderList.length) { console.log("No folders available for selection."); process.exit(1); } // Prompt user to select folders const folders = await promptUserForFolders(folderList); // Resume the workflow with user selections const resumedResult = await run.resume({ resumeData: { selection: folders }, step: "select_folder", }); // Print resumed result if (resumedResult.status === "success") { console.log(resumedResult.result); } else { console.log(resumedResult); } process.exit(1); } // Handle completed workflow if (res.status === "success") { console.log(res.result ?? res); } else { console.log(res); } ``` --- title: "Example: Calling an Agent from a Workflow | Mastra Docs" description: Example of using Mastra to call an AI agent from within a workflow step. --- # Calling an Agent From a Workflow [EN] Source: https://mastra.ai/en/examples/workflows/calling-agent This example demonstrates how to create a workflow that calls an AI agent to suggest activities for the provided weather conditions, and execute it within a workflow step. ## Setup ```sh copy npm install @ai-sdk/openai @mastra/core ``` ## Define Planning Agent Define a planning agent which leverages an LLM call to plan activities given a location and corresponding weather conditions. ```ts showLineNumbers copy filename="agents/planning-agent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const llm = openai("gpt-4o"); // Create a new agent for activity planning const planningAgent = new Agent({ name: "planningAgent", model: llm, instructions: ` You are a local activities and travel expert who excels at weather-based planning. Analyze the weather data and provide practical activity recommendations. 📅 [Day, Month Date, Year] ═══════════════════════════ 🌡️ WEATHER SUMMARY • Conditions: [brief description] • Temperature: [X°C/Y°F to A°C/B°F] • Precipitation: [X% chance] 🌅 MORNING ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🌞 AFTERNOON ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🏠 INDOOR ALTERNATIVES • [Activity Name] - [Brief description including specific venue] Ideal for: [weather condition that would trigger this alternative] ⚠️ SPECIAL CONSIDERATIONS • [Any relevant weather warnings, UV index, wind conditions, etc.] Guidelines: - Suggest 2-3 time-specific outdoor activities per day - Include 1-2 indoor backup options - For precipitation >50%, lead with indoor activities - All activities must be specific to the location - Include specific venues, trails, or locations - Consider activity intensity based on temperature - Keep descriptions concise but informative Maintain this exact formatting for consistency, using the emoji and section headers as shown. `, }); export { planningAgent }; ``` ## Define Activity Planning Workflow Define the activity planning workflow with 2 steps: one to fetch the weather via a network call, and another to plan activities using the planning agent. ```ts showLineNumbers copy filename="workflows/agent-workflow.ts" import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; // Helper function to convert numeric weather codes to human-readable descriptions function getWeatherCondition(code: number): string { const conditions: Record = { 0: "Clear sky", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast", 45: "Foggy", 48: "Depositing rime fog", 51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle", 61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain", 71: "Slight snow fall", 73: "Moderate snow fall", 75: "Heavy snow fall", 95: "Thunderstorm", }; return conditions[code] || "Unknown"; } const forecastSchema = z.object({ date: z.string(), maxTemp: z.number(), minTemp: z.number(), precipitationChance: z.number(), condition: z.string(), location: z.string(), }); ``` ### Step 1: Create a step to fetch weather data for a given city ```ts showLineNumbers copy filename="workflows/agent-workflow.ts" const fetchWeather = createStep({ id: "fetch-weather", description: "Fetches weather forecast for a given city", inputSchema: z.object({ city: z.string(), }), outputSchema: forecastSchema, execute: async ({ inputData }) => { if (!inputData) { throw new Error("Trigger data not found"); } // First API call: Convert city name to latitude and longitude const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(inputData.city)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = (await geocodingResponse.json()) as { results: { latitude: number; longitude: number; name: string }[]; }; if (!geocodingData.results?.[0]) { throw new Error(`Location '${inputData.city}' not found`); } const { latitude, longitude, name } = geocodingData.results[0]; // Second API call: Get weather data using coordinates const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=precipitation,weathercode&timezone=auto,&hourly=precipitation_probability,temperature_2m`; const response = await fetch(weatherUrl); const data = (await response.json()) as { current: { time: string; precipitation: number; weathercode: number; }; hourly: { precipitation_probability: number[]; temperature_2m: number[]; }; }; const forecast = { date: new Date().toISOString(), maxTemp: Math.max(...data.hourly.temperature_2m), minTemp: Math.min(...data.hourly.temperature_2m), condition: getWeatherCondition(data.current.weathercode), location: name, precipitationChance: data.hourly.precipitation_probability.reduce( (acc, curr) => Math.max(acc, curr), 0, ), }; return forecast; }, }); ``` ### Step 2: Create a step to generate activity recommendations using the agent ```ts showLineNumbers copy filename="workflows/agent-workflow.ts" const planActivities = createStep({ id: "plan-activities", description: "Suggests activities based on weather conditions", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `Based on the following weather forecast for ${forecast.location}, suggest appropriate activities: ${JSON.stringify(forecast, null, 2)} `; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); const activityPlanningWorkflow = createWorkflow({ steps: [fetchWeather, planActivities], id: "activity-planning-step1-single-day", inputSchema: z.object({ city: z.string().describe("The city to get the weather for"), }), outputSchema: z.object({ activities: z.string(), }), }) .then(fetchWeather) .then(planActivities); activityPlanningWorkflow.commit(); export { activityPlanningWorkflow }; ``` ## Register Agent and Workflow instances with Mastra class Register the planning agent and activity planning workflow with the mastra instance. This is critical for enabling access to the planning agent within the activity planning workflow. ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { createLogger } from "@mastra/core/logger"; import { activityPlanningWorkflow } from "./workflows/agent-workflow"; import { planningAgent } from "./agents/planning-agent"; // Create a new Mastra instance and register components const mastra = new Mastra({ workflows: { activityPlanningWorkflow, }, agents: { planningAgent, }, logger: createLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## Execute the activity planning workflow Here, we'll get the activity planning workflow from the mastra instance, then create a run and execute the created run with the required inputData. ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; const workflow = mastra.getWorkflow("activityPlanningWorkflow"); const run = workflow.createRun(); // Start the workflow with New York as the city input const result = await run.start({ inputData: { city: "New York" } }); console.dir(result, { depth: null }); ``` --- title: "Example: Conditional Branching | Workflows | Mastra Docs" description: Example of using Mastra to create conditional branches in workflows using the `branch` statement . --- # Workflow with Conditional Branching [EN] Source: https://mastra.ai/en/examples/workflows/conditional-branching Workflows often need to follow different paths based on some condition. This example demonstrates how to use the `branch` construct to create conditional flows within your workflows. ## Setup ```sh copy npm install @ai-sdk/openai @mastra/core ``` ## Define Planning Agent Define a planning agent which leverages an LLM call to plan activities given a location and corresponding weather conditions. ```ts showLineNumbers copy filename="agents/planning-agent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const llm = openai("gpt-4o"); // Define the planning agent that generates activity recommendations // based on weather conditions and location const planningAgent = new Agent({ name: "planningAgent", model: llm, instructions: ` You are a local activities and travel expert who excels at weather-based planning. Analyze the weather data and provide practical activity recommendations. 📅 [Day, Month Date, Year] ═══════════════════════════ 🌡️ WEATHER SUMMARY • Conditions: [brief description] • Temperature: [X°C/Y°F to A°C/B°F] • Precipitation: [X% chance] 🌅 MORNING ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🌞 AFTERNOON ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🏠 INDOOR ALTERNATIVES • [Activity Name] - [Brief description including specific venue] Ideal for: [weather condition that would trigger this alternative] ⚠️ SPECIAL CONSIDERATIONS • [Any relevant weather warnings, UV index, wind conditions, etc.] Guidelines: - Suggest 2-3 time-specific outdoor activities per day - Include 1-2 indoor backup options - For precipitation >50%, lead with indoor activities - All activities must be specific to the location - Include specific venues, trails, or locations - Consider activity intensity based on temperature - Keep descriptions concise but informative Maintain this exact formatting for consistency, using the emoji and section headers as shown. `, }); export { planningAgent }; ``` ## Define Activity Planning Workflow Define the planning workflow with 3 steps: one to fetch the weather via a network call, one to plan activities, and another to plan only indoor activities. Both using the planning agent. ```ts showLineNumbers copy filename="workflows/conditional-workflow.ts" import { z } from "zod"; import { createWorkflow, createStep } from "@mastra/core/workflows"; // Helper function to convert weather codes to human-readable conditions function getWeatherCondition(code: number): string { const conditions: Record = { 0: "Clear sky", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast", 45: "Foggy", 48: "Depositing rime fog", 51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle", 61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain", 71: "Slight snow fall", 73: "Moderate snow fall", 75: "Heavy snow fall", 95: "Thunderstorm", }; return conditions[code] || "Unknown"; } const forecastSchema = z.object({ date: z.string(), maxTemp: z.number(), minTemp: z.number(), precipitationChance: z.number(), condition: z.string(), location: z.string(), }); ``` ### Step to fetch weather data for a given city Makes API calls to get current weather conditions and forecast ```ts showLineNumbers copy filename="workflows/conditional-workflow.ts" const fetchWeather = createStep({ id: "fetch-weather", description: "Fetches weather forecast for a given city", inputSchema: z.object({ city: z.string(), }), outputSchema: forecastSchema, execute: async ({ inputData }) => { if (!inputData) { throw new Error("Trigger data not found"); } const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(inputData.city)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = (await geocodingResponse.json()) as { results: { latitude: number; longitude: number; name: string }[]; }; if (!geocodingData.results?.[0]) { throw new Error(`Location '${inputData.city}' not found`); } const { latitude, longitude, name } = geocodingData.results[0]; const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=precipitation,weathercode&timezone=auto,&hourly=precipitation_probability,temperature_2m`; const response = await fetch(weatherUrl); const data = (await response.json()) as { current: { time: string; precipitation: number; weathercode: number; }; hourly: { precipitation_probability: number[]; temperature_2m: number[]; }; }; const forecast = { date: new Date().toISOString(), maxTemp: Math.max(...data.hourly.temperature_2m), minTemp: Math.min(...data.hourly.temperature_2m), condition: getWeatherCondition(data.current.weathercode), location: name, precipitationChance: data.hourly.precipitation_probability.reduce( (acc, curr) => Math.max(acc, curr), 0, ), }; return forecast; }, }); ``` ### Step to plan activities based on weather conditions Uses the planning agent to generate activity recommendations ```ts showLineNumbers copy filename="workflows/conditional-workflow.ts" const planActivities = createStep({ id: "plan-activities", description: "Suggests activities based on weather conditions", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `Based on the following weather forecast for ${forecast.location}, suggest appropriate activities: ${JSON.stringify(forecast, null, 2)} `; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); ``` ### Step to plan indoor activities only Used when precipitation chance is high ```ts showLineNumbers copy filename="workflows/conditional-workflow.ts" const planIndoorActivities = createStep({ id: "plan-indoor-activities", description: "Suggests indoor activities based on weather conditions", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `In case it rains, plan indoor activities for ${forecast.location} on ${forecast.date}`; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); ``` ### Main workflow ```ts showLineNumbers copy filename="workflows/conditional-workflow.ts" const activityPlanningWorkflow = createWorkflow({ id: "activity-planning-workflow-step2-if-else", inputSchema: z.object({ city: z.string().describe("The city to get the weather for"), }), outputSchema: z.object({ activities: z.string(), }), }) .then(fetchWeather) .branch([ // Branch for high precipitation (indoor activities) [ async ({ inputData }) => { return inputData?.precipitationChance > 50; }, planIndoorActivities, ], // Branch for low precipitation (outdoor activities) [ async ({ inputData }) => { return inputData?.precipitationChance <= 50; }, planActivities, ], ]); activityPlanningWorkflow.commit(); export { activityPlanningWorkflow }; ``` ## Register Agent and Workflow instances with Mastra class Register the agents and workflow with the mastra instance. This is critical for enabling access to the agents within the workflow. ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { createLogger } from "@mastra/core/logger"; import { activityPlanningWorkflow } from "./workflows/conditional-workflow"; import { planningAgent } from "./agents/planning-agent"; // Initialize Mastra with the activity planning workflow // This enables the workflow to be executed and access the planning agent const mastra = new Mastra({ workflows: { activityPlanningWorkflow, }, agents: { planningAgent, }, logger: createLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## Execute the activity planning workflow Here, we'll get the activity planning workflow from the mastra instance, then create a run and execute the created run with the required inputData. ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; const workflow = mastra.getWorkflow("activityPlanningWorkflow"); const run = workflow.createRun(); // Start the workflow with a city // This will fetch weather and plan activities based on conditions const result = await run.start({ inputData: { city: "New York" } }); console.dir(result, { depth: null }); ``` --- title: "Example: Control Flow | Workflows | Mastra Docs" description: Example of using Mastra to create workflows with loops based on provided conditions. --- # Looping step execution [EN] Source: https://mastra.ai/en/examples/workflows/control-flow ## Setup ```sh copy npm install @ai-sdk/openai @mastra/core ``` ## Define Looping workflow Defines a workflow which calls the executes a nested workflow until the provided condition is met. ```ts showLineNumbers copy filename="looping-workflow.ts" import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; // Step that increments the input value by 1 const incrementStep = createStep({ id: "increment", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), execute: async ({ inputData }) => { return { value: inputData.value + 1 }; }, }); // Step that logs the current value (side effect) const sideEffectStep = createStep({ id: "side-effect", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), execute: async ({ inputData }) => { console.log("log", inputData.value); return { value: inputData.value }; }, }); // Final step that returns the final value const finalStep = createStep({ id: "final", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), execute: async ({ inputData }) => { return { value: inputData.value }; }, }); // Create a workflow that: // 1. Increments a number until it reaches 10 // 2. Logs each increment (side effect) // 3. Returns the final value const workflow = createWorkflow({ id: "increment-workflow", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), }) .dountil( // Nested workflow that performs the increment and logging createWorkflow({ id: "increment-workflow", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), steps: [incrementStep, sideEffectStep], }) .then(incrementStep) .then(sideEffectStep) .commit(), // Condition to check if we should stop the loop async ({ inputData }) => inputData.value >= 10, ) .then(finalStep); workflow.commit(); export { workflow as incrementWorkflow }; ``` ## Register Workflow instance with Mastra class Register the workflow with the mastra instance. ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { PinoLogger } from "@mastra/loggers"; import { incrementWorkflow } from "./workflows"; // Initialize Mastra with the increment workflow // This enables the workflow to be executed const mastra = new Mastra({ workflows: { incrementWorkflow, }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## Execute the workflow Here, we'll get the increment workflow from the mastra instance, then create a run and execute the created run with the required inputData. ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; const workflow = mastra.getWorkflow("incrementWorkflow"); const run = workflow.createRun(); // Start the workflow with initial value 0 // This will increment until reaching 10 const result = await run.start({ inputData: { value: 0 } }); console.dir(result, { depth: null }); ``` --- title: "Example: Human in the Loop | Workflows | Mastra Docs" description: Example of using Mastra to create workflows with human intervention points. --- # Human in the Loop Workflow [EN] Source: https://mastra.ai/en/examples/workflows/human-in-the-loop Human-in-the-loop workflows allow you to pause execution at specific points to collect user input, make decisions, or perform actions that require human judgment. This example demonstrates how to create a workflow with human intervention points. ## Setup ```sh copy npm install @ai-sdk/openai @mastra/core @inquirer/prompts ``` ## Define Agents Define the travel agents. ```ts showLineNumbers copy filename="agents/travel-agents.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const llm = openai("gpt-4o"); // Agent that generates multiple holiday options // Returns a JSON array of locations and descriptions export const summaryTravelAgent = new Agent({ name: "summaryTravelAgent", model: llm, instructions: ` You are a travel agent who is given a user prompt about what kind of holiday they want to go on. You then generate 3 different options for the holiday. Return the suggestions as a JSON array {"location": "string", "description": "string"}[]. Don't format as markdown. Make the options as different as possible from each other. Also make the plan very short and summarized. `, }); // Agent that creates detailed travel plans // Takes the selected option and generates a comprehensive itinerary export const travelAgent = new Agent({ name: "travelAgent", model: llm, instructions: ` You are a travel agent who is given a user prompt about what kind of holiday they want to go on. A summary of the plan is provided as well as the location. You then generate a detailed travel plan for the holiday. `, }); ``` ## Define Suspendable workflow Defines a workflow which includes a suspending step: `humanInputStep`. ```ts showLineNumbers copy filename="workflows/human-in-the-loop-workflow.ts" import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; // Step that generates multiple holiday options based on user's vacation description // Uses the summaryTravelAgent to create diverse travel suggestions const generateSuggestionsStep = createStep({ id: "generate-suggestions", inputSchema: z.object({ vacationDescription: z.string().describe("The description of the vacation"), }), outputSchema: z.object({ suggestions: z.array(z.string()), vacationDescription: z.string(), }), execute: async ({ inputData, mastra }) => { if (!mastra) { throw new Error("Mastra is not initialized"); } const { vacationDescription } = inputData; const result = await mastra.getAgent("summaryTravelAgent").generate([ { role: "user", content: vacationDescription, }, ]); console.log(result.text); return { suggestions: JSON.parse(result.text), vacationDescription }; }, }); // Step that pauses the workflow to get user input // Allows the user to select their preferred holiday option from the suggestions // Uses suspend/resume mechanism to handle the interaction const humanInputStep = createStep({ id: "human-input", inputSchema: z.object({ suggestions: z.array(z.string()), vacationDescription: z.string(), }), outputSchema: z.object({ selection: z.string().describe("The selection of the user"), vacationDescription: z.string(), }), resumeSchema: z.object({ selection: z.string().describe("The selection of the user"), }), suspendSchema: z.object({ suggestions: z.array(z.string()), }), execute: async ({ inputData, resumeData, suspend, getInitData }) => { if (!resumeData?.selection) { await suspend({ suggestions: inputData?.suggestions }); return { selection: "", vacationDescription: inputData?.vacationDescription, }; } return { selection: resumeData?.selection, vacationDescription: inputData?.vacationDescription, }; }, }); // Step that creates a detailed travel plan based on the user's selection // Uses the travelAgent to generate comprehensive holiday details const travelPlannerStep = createStep({ id: "travel-planner", inputSchema: z.object({ selection: z.string().describe("The selection of the user"), vacationDescription: z.string(), }), outputSchema: z.object({ travelPlan: z.string(), }), execute: async ({ inputData, mastra }) => { const travelAgent = mastra?.getAgent("travelAgent"); if (!travelAgent) { throw new Error("Travel agent is not initialized"); } const { selection, vacationDescription } = inputData; const result = await travelAgent.generate([ { role: "assistant", content: vacationDescription }, { role: "user", content: selection || "" }, ]); console.log(result.text); return { travelPlan: result.text }; }, }); // Main workflow that orchestrates the holiday planning process: // 1. Generates multiple options // 2. Gets user input // 3. Creates detailed plan const travelAgentWorkflow = createWorkflow({ id: "travel-agent-workflow", inputSchema: z.object({ vacationDescription: z.string().describe("The description of the vacation"), }), outputSchema: z.object({ travelPlan: z.string(), }), }) .then(generateSuggestionsStep) .then(humanInputStep) .then(travelPlannerStep); travelAgentWorkflow.commit(); export { travelAgentWorkflow, humanInputStep }; ``` ## Register Agent and Workflow instances with Mastra class Register the agents and the weather workflow with the mastra instance. This is critical for enabling access to the agents within the workflow. ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { createLogger } from "@mastra/core/logger"; import { travelAgentWorkflow } from "./workflows/human-in-the-loop-workflow"; import { summaryTravelAgent, travelAgent } from "./agents/travel-agent"; // Initialize Mastra instance with: // - The travel planning workflow // - Both travel agents (summary and detailed planning) // - Logging configuration const mastra = new Mastra({ workflows: { travelAgentWorkflow, }, agents: { travelAgent, summaryTravelAgent, }, logger: createLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## Execute the suspendable weather workflow Here, we'll get the weather workflow from the mastra instance, then create a run and execute the created run with the required inputData. In addition to this, we'll resume the `humanInputStep` after collecting user input with the readline package. ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; import { select } from "@inquirer/prompts"; import { humanInputStep } from "./workflows/human-in-the-loop-workflow"; const workflow = mastra.getWorkflow("travelAgentWorkflow"); const run = workflow.createRun({}); // Start the workflow with initial vacation description const result = await run.start({ inputData: { vacationDescription: "I want to go to the beach" }, }); console.log("result", result); const suggStep = result?.steps?.["generate-suggestions"]; // If suggestions were generated successfully, proceed with user interaction if (suggStep.status === "success") { const suggestions = suggStep.output?.suggestions; // Present options to user and get their selection const userInput = await select({ message: "Choose your holiday destination", choices: suggestions.map( ({ location, description }: { location: string; description: string }) => `- ${location}: ${description}`, ), }); console.log("Selected:", userInput); // Prepare to resume the workflow with user's selection console.log("resuming from", result, "with", { inputData: { selection: userInput, vacationDescription: "I want to go to the beach", suggestions: suggStep?.output?.suggestions, }, step: humanInputStep, }); const result2 = await run.resume({ resumeData: { selection: userInput, }, step: humanInputStep, }); console.dir(result2, { depth: null }); } ``` Human-in-the-loop workflows are powerful for building systems that blend automation with human judgment, such as: - Content moderation systems - Approval workflows - Supervised AI systems - Customer service automation with escalation --- title: "Inngest Workflow | Workflows | Mastra Docs" description: Example of building an inngest workflow with Mastra --- # Inngest Workflow [EN] Source: https://mastra.ai/en/examples/workflows/inngest-workflow This example demonstrates how to build an Inngest workflow with Mastra. ## Setup ```sh copy npm install @mastra/inngest inngest @mastra/core @mastra/deployer @hono/node-server @ai-sdk/openai docker run --rm -p 8288:8288 \ inngest/inngest \ inngest dev -u http://host.docker.internal:3000/inngest/api ``` Alternatively, you can use the Inngest CLI for local development by following the official [Inngest Dev Server guide](https://www.inngest.com/docs/dev-server). ## Define the Planning Agent Define a planning agent which leverages an LLM call to plan activities given a location and corresponding weather conditions. ```ts showLineNumbers copy filename="agents/planning-agent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // Create a new planning agent that uses the OpenAI model const planningAgent = new Agent({ name: "planningAgent", model: openai("gpt-4o"), instructions: ` You are a local activities and travel expert who excels at weather-based planning. Analyze the weather data and provide practical activity recommendations. 📅 [Day, Month Date, Year] ═══════════════════════════ 🌡️ WEATHER SUMMARY • Conditions: [brief description] • Temperature: [X°C/Y°F to A°C/B°F] • Precipitation: [X% chance] 🌅 MORNING ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🌞 AFTERNOON ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🏠 INDOOR ALTERNATIVES • [Activity Name] - [Brief description including specific venue] Ideal for: [weather condition that would trigger this alternative] ⚠️ SPECIAL CONSIDERATIONS • [Any relevant weather warnings, UV index, wind conditions, etc.] Guidelines: - Suggest 2-3 time-specific outdoor activities per day - Include 1-2 indoor backup options - For precipitation >50%, lead with indoor activities - All activities must be specific to the location - Include specific venues, trails, or locations - Consider activity intensity based on temperature - Keep descriptions concise but informative Maintain this exact formatting for consistency, using the emoji and section headers as shown. `, }); export { planningAgent }; ``` ## Define the Activity Planner Workflow Define the activity planner workflow with 3 steps: one to fetch the weather via a network call, one to plan activities, and another to plan only indoor activities. ```ts showLineNumbers copy filename="workflows/inngest-workflow.ts" import { init } from "@mastra/inngest"; import { Inngest } from "inngest"; import { z } from "zod"; const { createWorkflow, createStep } = init( new Inngest({ id: "mastra", baseUrl: `http://localhost:8288`, }), ); // Helper function to convert weather codes to human-readable descriptions function getWeatherCondition(code: number): string { const conditions: Record = { 0: "Clear sky", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast", 45: "Foggy", 48: "Depositing rime fog", 51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle", 61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain", 71: "Slight snow fall", 73: "Moderate snow fall", 75: "Heavy snow fall", 95: "Thunderstorm", }; return conditions[code] || "Unknown"; } const forecastSchema = z.object({ date: z.string(), maxTemp: z.number(), minTemp: z.number(), precipitationChance: z.number(), condition: z.string(), location: z.string(), }); ``` #### Step 1: Fetch weather data for a given city ```ts showLineNumbers copy filename="workflows/inngest-workflow.ts" const fetchWeather = createStep({ id: "fetch-weather", description: "Fetches weather forecast for a given city", inputSchema: z.object({ city: z.string(), }), outputSchema: forecastSchema, execute: async ({ inputData }) => { if (!inputData) { throw new Error("Trigger data not found"); } // Get latitude and longitude for the city const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(inputData.city)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = (await geocodingResponse.json()) as { results: { latitude: number; longitude: number; name: string }[]; }; if (!geocodingData.results?.[0]) { throw new Error(`Location '${inputData.city}' not found`); } const { latitude, longitude, name } = geocodingData.results[0]; // Fetch weather data using the coordinates const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=precipitation,weathercode&timezone=auto,&hourly=precipitation_probability,temperature_2m`; const response = await fetch(weatherUrl); const data = (await response.json()) as { current: { time: string; precipitation: number; weathercode: number; }; hourly: { precipitation_probability: number[]; temperature_2m: number[]; }; }; const forecast = { date: new Date().toISOString(), maxTemp: Math.max(...data.hourly.temperature_2m), minTemp: Math.min(...data.hourly.temperature_2m), condition: getWeatherCondition(data.current.weathercode), location: name, precipitationChance: data.hourly.precipitation_probability.reduce( (acc, curr) => Math.max(acc, curr), 0, ), }; return forecast; }, }); ``` #### Step 2: Suggest activities (indoor or outdoor) based on weather ```ts showLineNumbers copy filename="workflows/inngest-workflow.ts" const planActivities = createStep({ id: "plan-activities", description: "Suggests activities based on weather conditions", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `Based on the following weather forecast for ${forecast.location}, suggest appropriate activities: ${JSON.stringify(forecast, null, 2)} `; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); ``` #### Step 3: Suggest indoor activities only (for rainy weather) ```ts showLineNumbers copy filename="workflows/inngest-workflow.ts" const planIndoorActivities = createStep({ id: "plan-indoor-activities", description: "Suggests indoor activities based on weather conditions", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `In case it rains, plan indoor activities for ${forecast.location} on ${forecast.date}`; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); ``` ## Define the activity planner workflow ```ts showLineNumbers copy filename="workflows/inngest-workflow.ts" const activityPlanningWorkflow = createWorkflow({ id: "activity-planning-workflow-step2-if-else", inputSchema: z.object({ city: z.string().describe("The city to get the weather for"), }), outputSchema: z.object({ activities: z.string(), }), }) .then(fetchWeather) .branch([ [ // If precipitation chance is greater than 50%, suggest indoor activities async ({ inputData }) => { return inputData?.precipitationChance > 50; }, planIndoorActivities, ], [ // Otherwise, suggest a mix of activities async ({ inputData }) => { return inputData?.precipitationChance <= 50; }, planActivities, ], ]); activityPlanningWorkflow.commit(); export { activityPlanningWorkflow }; ``` ## Register Agent and Workflow instances with Mastra class Register the agents and workflow with the mastra instance. This allows access to the agents within the workflow. ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { serve as inngestServe } from "@mastra/inngest"; import { PinoLogger } from "@mastra/loggers"; import { Inngest } from "inngest"; import { activityPlanningWorkflow } from "./workflows/inngest-workflow"; import { planningAgent } from "./agents/planning-agent"; import { realtimeMiddleware } from "@inngest/realtime"; // Create an Inngest instance for workflow orchestration and event handling const inngest = new Inngest({ id: "mastra", baseUrl: `http://localhost:8288`, // URL of your local Inngest server isDev: true, middleware: [realtimeMiddleware()], // Enable real-time updates in the Inngest dashboard }); // Create and configure the main Mastra instance export const mastra = new Mastra({ workflows: { activityPlanningWorkflow, }, agents: { planningAgent, }, server: { host: "0.0.0.0", apiRoutes: [ { path: "/api/inngest", // API endpoint for Inngest to send events to method: "ALL", createHandler: async ({ mastra }) => inngestServe({ mastra, inngest }), }, ], }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); ``` ## Execute the activity planner workflow Here, we'll get the activity planner workflow from the mastra instance, then create a run and execute the created run with the required inputData. ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; import { serve } from "@hono/node-server"; import { createHonoServer } from "@mastra/deployer/server"; const app = await createHonoServer(mastra); // Start the server on port 3000 so Inngest can send events to it const srv = serve({ fetch: app.fetch, port: 3000, }); const workflow = mastra.getWorkflow("activityPlanningWorkflow"); const run = workflow.createRun({}); // Start the workflow with the required input data (city name) // This will trigger the workflow steps and stream the result to the console const result = await run.start({ inputData: { city: "New York" } }); console.dir(result, { depth: null }); // Close the server after the workflow run is complete srv.close(); ``` After running the workflow, you can view and monitor your workflow runs in real time using the Inngest dashboard at [http://localhost:8288](http://localhost:8288). --- title: "Example: Parallel Execution | Workflows | Mastra Docs" description: Example of using Mastra to execute multiple independent tasks in parallel within a workflow. --- # Parallel Execution with Steps [EN] Source: https://mastra.ai/en/examples/workflows/parallel-steps When building AI applications, you often need to process multiple independent tasks simultaneously to improve efficiency. We make this functionality a core part of workflows through the `.parallel` method. ## Setup ```sh copy npm install @ai-sdk/openai @mastra/core ``` ## Define Planning Agent Define a planning agent which leverages an LLM call to plan activities given a location and corresponding weather conditions. ```ts showLineNumbers copy filename="agents/planning-agent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const llm = openai("gpt-4o"); // Define the planning agent with specific instructions for formatting // and structuring weather-based activity recommendations const planningAgent = new Agent({ name: "planningAgent", model: llm, instructions: ` You are a local activities and travel expert who excels at weather-based planning. Analyze the weather data and provide practical activity recommendations. 📅 [Day, Month Date, Year] ═══════════════════════════ 🌡️ WEATHER SUMMARY • Conditions: [brief description] • Temperature: [X°C/Y°F to A°C/B°F] • Precipitation: [X% chance] 🌅 MORNING ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🌞 AFTERNOON ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🏠 INDOOR ALTERNATIVES • [Activity Name] - [Brief description including specific venue] Ideal for: [weather condition that would trigger this alternative] ⚠️ SPECIAL CONSIDERATIONS • [Any relevant weather warnings, UV index, wind conditions, etc.] Guidelines: - Suggest 2-3 time-specific outdoor activities per day - Include 1-2 indoor backup options - For precipitation >50%, lead with indoor activities - All activities must be specific to the location - Include specific venues, trails, or locations - Consider activity intensity based on temperature - Keep descriptions concise but informative Maintain this exact formatting for consistency, using the emoji and section headers as shown. `, }); export { planningAgent }; ``` ## Define Synthesize Agent Define a synthesize agent which takes planned indoor and outdoor activities and provides a full report on the day. ```ts showLineNumbers copy filename="agents/synthesize-agent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const llm = openai("gpt-4o"); // Define the synthesize agent that combines indoor and outdoor activity plans // into a comprehensive report, considering weather conditions and alternatives const synthesizeAgent = new Agent({ name: "synthesizeAgent", model: llm, instructions: ` You are given two different blocks of text, one about indoor activities and one about outdoor activities. Make this into a full report about the day and the possibilities depending on whether it rains or not. `, }); export { synthesizeAgent }; ``` ## Define Parallel Workflow Here, we'll define a workflow which orchestrates a parallel -> sequential flow between the planning steps and the synthesize step. ```ts showLineNumbers copy filename="workflows/parallel-workflow.ts" import { z } from "zod"; import { createStep, createWorkflow } from "@mastra/core/workflows"; const forecastSchema = z.object({ date: z.string(), maxTemp: z.number(), minTemp: z.number(), precipitationChance: z.number(), condition: z.string(), location: z.string(), }); // Step to fetch weather data for a given city // Makes API calls to get current weather conditions and forecast const fetchWeather = createStep({ id: "fetch-weather", description: "Fetches weather forecast for a given city", inputSchema: z.object({ city: z.string(), }), outputSchema: forecastSchema, execute: async ({ inputData }) => { if (!inputData) { throw new Error("Trigger data not found"); } const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(inputData.city)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = (await geocodingResponse.json()) as { results: { latitude: number; longitude: number; name: string }[]; }; if (!geocodingData.results?.[0]) { throw new Error(`Location '${inputData.city}' not found`); } const { latitude, longitude, name } = geocodingData.results[0]; const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=precipitation,weathercode&timezone=auto,&hourly=precipitation_probability,temperature_2m`; const response = await fetch(weatherUrl); const data = (await response.json()) as { current: { time: string; precipitation: number; weathercode: number; }; hourly: { precipitation_probability: number[]; temperature_2m: number[]; }; }; const forecast = { date: new Date().toISOString(), maxTemp: Math.max(...data.hourly.temperature_2m), minTemp: Math.min(...data.hourly.temperature_2m), condition: getWeatherCondition(data.current.weathercode), location: name, precipitationChance: data.hourly.precipitation_probability.reduce( (acc, curr) => Math.max(acc, curr), 0, ), }; return forecast; }, }); ``` ### Step to plan outdoor activities based on weather conditions Uses the planning agent to generate activity recommendations ```ts showLineNumbers copy filename="workflows/parallel-workflow.ts" const planActivities = createStep({ id: "plan-activities", description: "Suggests activities based on weather conditions", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `Based on the following weather forecast for ${forecast.location}, suggest appropriate activities: ${JSON.stringify(forecast, null, 2)} `; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); ``` ### Helper function to convert weather codes to human-readable conditions Maps numeric codes from the weather API to descriptive strings ```ts showLineNumbers copy filename="workflows/parallel-workflow.ts" function getWeatherCondition(code: number): string { const conditions: Record = { 0: "Clear sky", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast", 45: "Foggy", 48: "Depositing rime fog", 51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle", 61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain", 71: "Slight snow fall", 73: "Moderate snow fall", 75: "Heavy snow fall", 95: "Thunderstorm", }; return conditions[code] || "Unknown"; } // Step to plan indoor activities as backup options // Generates alternative indoor activities in case of bad weather const planIndoorActivities = createStep({ id: "plan-indoor-activities", description: "Suggests indoor activities based on weather conditions", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `In case it rains, plan indoor activities for ${forecast.location} on ${forecast.date}`; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { activitiesText += chunk; } return { activities: activitiesText, }; }, }); ``` ### Step to synthesize and combine indoor/outdoor activity plans Creates a comprehensive plan that considers both options ```ts showLineNumbers copy filename="workflows/parallel-workflow.ts" const synthesizeStep = createStep({ id: "sythesize-step", description: "Synthesizes the results of the indoor and outdoor activities", inputSchema: z.object({ "plan-activities": z.object({ activities: z.string(), }), "plan-indoor-activities": z.object({ activities: z.string(), }), }), outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const indoorActivities = inputData?.["plan-indoor-activities"]; const outdoorActivities = inputData?.["plan-activities"]; const prompt = `Indoor activities: ${indoorActivities?.activities} Outdoor activities: ${outdoorActivities?.activities} There is a chance of rain so be prepared to do indoor activities if needed.`; const agent = mastra?.getAgent("synthesizeAgent"); if (!agent) { throw new Error("Synthesize agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); ``` ### Main workflow ```ts showLineNumbers copy filename="workflows/parallel-workflow.ts" const activityPlanningWorkflow = createWorkflow({ id: "plan-both-workflow", inputSchema: z.object({ city: z.string(), }), outputSchema: z.object({ activities: z.string(), }), steps: [fetchWeather, planActivities, planIndoorActivities, synthesizeStep], }) .then(fetchWeather) .parallel([planActivities, planIndoorActivities]) .then(synthesizeStep) .commit(); export { activityPlanningWorkflow }; ``` ## Register Agent and Workflow instances with Mastra class Register the agents and workflow with the mastra instance. This is critical for enabling access to the agents within the workflow. ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { createLogger } from "@mastra/core/logger"; import { activityPlanningWorkflow } from "./workflows/parallel-workflow"; import { planningAgent } from "./agents/planning-agent"; import { synthesizeAgent } from "./agents/synthesize-agent"; // Initialize Mastra with required agents and workflows // This setup enables agent access within the workflow steps const mastra = new Mastra({ workflows: { activityPlanningWorkflow, }, agents: { planningAgent, synthesizeAgent, }, logger: createLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## Execute the activity planning workflow Here, we'll get the weather workflow from the mastra instance, then create a run and execute the created run with the required inputData. ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; const workflow = mastra.getWorkflow("activityPlanningWorkflow"); const run = workflow.createRun(); // Execute the workflow with a specific city // This will run through all steps and generate activity recommendations const result = await run.start({ inputData: { city: "Ibiza" } }); console.dir(result, { depth: null }); ``` --- title: "Example: Branching Paths | Workflows (Legacy) | Mastra Docs" description: Example of using Mastra to create legacy workflows with branching paths based on intermediate results. --- import { GithubLink } from "@/components/github-link"; # Branching Paths [EN] Source: https://mastra.ai/en/examples/workflows_legacy/branching-paths When processing data, you often need to take different actions based on intermediate results. This example shows how to create a legacy workflow that splits into separate paths, where each path executes different steps based on the output of a previous step. ## Control Flow Diagram This example shows how to create a legacy workflow that splits into separate paths, where each path executes different steps based on the output of a previous step. Here's the control flow diagram: Diagram showing workflow with branching paths ## Creating the Steps Let's start by creating the steps and initializing the workflow. {/* prettier-ignore */} ```ts showLineNumbers copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod" const stepOne = new LegacyStep({ id: "stepOne", execute: async ({ context }) => ({ doubledValue: context.triggerData.inputValue * 2 }) }); const stepTwo = new LegacyStep({ id: "stepTwo", execute: async ({ context }) => { const stepOneResult = context.getStepResult<{ doubledValue: number }>("stepOne"); if (!stepOneResult) { return { isDivisibleByFive: false } } return { isDivisibleByFive: stepOneResult.doubledValue % 5 === 0 } } }); const stepThree = new LegacyStep({ id: "stepThree", execute: async ({ context }) =>{ const stepOneResult = context.getStepResult<{ doubledValue: number }>("stepOne"); if (!stepOneResult) { return { incrementedValue: 0 } } return { incrementedValue: stepOneResult.doubledValue + 1 } } }); const stepFour = new LegacyStep({ id: "stepFour", execute: async ({ context }) => { const stepThreeResult = context.getStepResult<{ incrementedValue: number }>("stepThree"); if (!stepThreeResult) { return { isDivisibleByThree: false } } return { isDivisibleByThree: stepThreeResult.incrementedValue % 3 === 0 } } }); // New step that depends on both branches const finalStep = new LegacyStep({ id: "finalStep", execute: async ({ context }) => { // Get results from both branches using getStepResult const stepTwoResult = context.getStepResult<{ isDivisibleByFive: boolean }>("stepTwo"); const stepFourResult = context.getStepResult<{ isDivisibleByThree: boolean }>("stepFour"); const isDivisibleByFive = stepTwoResult?.isDivisibleByFive || false; const isDivisibleByThree = stepFourResult?.isDivisibleByThree || false; return { summary: `The number ${context.triggerData.inputValue} when doubled ${isDivisibleByFive ? 'is' : 'is not'} divisible by 5, and when doubled and incremented ${isDivisibleByThree ? 'is' : 'is not'} divisible by 3.`, isDivisibleByFive, isDivisibleByThree } } }); // Build the workflow const myWorkflow = new LegacyWorkflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); ``` ## Branching Paths and Chaining Steps Now let's configure the legacy workflow with branching paths and merge them using the compound `.after([])` syntax. ```ts showLineNumbers copy // Create two parallel branches myWorkflow // First branch .step(stepOne) .then(stepTwo) // Second branch .after(stepOne) .step(stepThree) .then(stepFour) // Merge both branches using compound after syntax .after([stepTwo, stepFour]) .step(finalStep) .commit(); const { start } = myWorkflow.createRun(); const result = await start({ triggerData: { inputValue: 3 } }); console.log(result.steps.finalStep.output.summary); // Output: "The number 3 when doubled is not divisible by 5, and when doubled and incremented is divisible by 3." ``` ## Advanced Branching and Merging You can create more complex workflows with multiple branches and merge points: ```ts showLineNumbers copy const complexWorkflow = new LegacyWorkflow({ name: "complex-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); // Create multiple branches with different merge points complexWorkflow // Main step .step(stepOne) // First branch .then(stepTwo) // Second branch .after(stepOne) .step(stepThree) .then(stepFour) // Third branch (another path from stepOne) .after(stepOne) .step( new LegacyStep({ id: "alternativePath", execute: async ({ context }) => { const stepOneResult = context.getStepResult<{ doubledValue: number }>( "stepOne", ); return { result: (stepOneResult?.doubledValue || 0) * 3, }; }, }), ) // Merge first and second branches .after([stepTwo, stepFour]) .step( new LegacyStep({ id: "partialMerge", execute: async ({ context }) => { const stepTwoResult = context.getStepResult<{ isDivisibleByFive: boolean; }>("stepTwo"); const stepFourResult = context.getStepResult<{ isDivisibleByThree: boolean; }>("stepFour"); return { intermediateResult: "Processed first two branches", branchResults: { branch1: stepTwoResult?.isDivisibleByFive, branch2: stepFourResult?.isDivisibleByThree, }, }; }, }), ) // Final merge of all branches .after(["partialMerge", "alternativePath"]) .step( new LegacyStep({ id: "finalMerge", execute: async ({ context }) => { const partialMergeResult = context.getStepResult<{ intermediateResult: string; branchResults: { branch1: boolean; branch2: boolean }; }>("partialMerge"); const alternativePathResult = context.getStepResult<{ result: number }>( "alternativePath", ); return { finalResult: "All branches processed", combinedData: { fromPartialMerge: partialMergeResult?.branchResults, fromAlternativePath: alternativePathResult?.result, }, }; }, }), ) .commit(); ```




` --- title: "Example: Calling an Agent from a Workflow (Legacy) | Mastra Docs" description: Example of using Mastra to call an AI agent from within a legacy workflow step. --- import { GithubLink } from "@/components/github-link"; # Calling an Agent From a Workflow (Legacy) [EN] Source: https://mastra.ai/en/examples/workflows_legacy/calling-agent This example demonstrates how to create a legacy workflow that calls an AI agent to process messages and generate responses, and execute it within a legacy workflow step. ```ts showLineNumbers copy import { openai } from "@ai-sdk/openai"; import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const penguin = new Agent({ name: "agent skipper", instructions: `You are skipper from penguin of madagascar, reply as that`, model: openai("gpt-4o-mini"), }); const newWorkflow = new LegacyWorkflow({ name: "pass message to the workflow", triggerSchema: z.object({ message: z.string(), }), }); const replyAsSkipper = new LegacyStep({ id: "reply", outputSchema: z.object({ reply: z.string(), }), execute: async ({ context, mastra }) => { const skipper = mastra?.getAgent("penguin"); const res = await skipper?.generate(context?.triggerData?.message); return { reply: res?.text || "" }; }, }); newWorkflow.step(replyAsSkipper); newWorkflow.commit(); const mastra = new Mastra({ agents: { penguin }, legacy_workflows: { newWorkflow }, }); const { runId, start } = await mastra .legacy_getWorkflow("newWorkflow") .createRun(); const runResult = await start({ triggerData: { message: "Give me a run down of the mission to save private" }, }); console.log(runResult.results); ```




--- title: "Example: Conditional Branching (experimental) | Workflows (Legacy) | Mastra Docs" description: Example of using Mastra to create conditional branches in legacy workflows using if/else statements. --- import { GithubLink } from "@/components/github-link"; # Workflow (Legacy) with Conditional Branching (experimental) [EN] Source: https://mastra.ai/en/examples/workflows_legacy/conditional-branching Workflows often need to follow different paths based on conditions. This example demonstrates how to use `if` and `else` to create conditional branches in your legacy workflows. ## Basic If/Else Example This example shows a simple legacy workflow that takes different paths based on a numeric value: ```ts showLineNumbers copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Step that provides the initial value const startStep = new LegacyStep({ id: "start", outputSchema: z.object({ value: z.number(), }), execute: async ({ context }) => { // Get the value from the trigger data const value = context.triggerData.inputValue; return { value }; }, }); // Step that handles high values const highValueStep = new LegacyStep({ id: "highValue", outputSchema: z.object({ result: z.string(), }), execute: async ({ context }) => { const value = context.getStepResult<{ value: number }>("start")?.value; return { result: `High value processed: ${value}` }; }, }); // Step that handles low values const lowValueStep = new LegacyStep({ id: "lowValue", outputSchema: z.object({ result: z.string(), }), execute: async ({ context }) => { const value = context.getStepResult<{ value: number }>("start")?.value; return { result: `Low value processed: ${value}` }; }, }); // Final step that summarizes the result const finalStep = new LegacyStep({ id: "final", outputSchema: z.object({ summary: z.string(), }), execute: async ({ context }) => { // Get the result from whichever branch executed const highResult = context.getStepResult<{ result: string }>( "highValue", )?.result; const lowResult = context.getStepResult<{ result: string }>( "lowValue", )?.result; const result = highResult || lowResult; return { summary: `Processing complete: ${result}` }; }, }); // Build the workflow with conditional branching const conditionalWorkflow = new LegacyWorkflow({ name: "conditional-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); conditionalWorkflow .step(startStep) .if(async ({ context }) => { const value = context.getStepResult<{ value: number }>("start")?.value ?? 0; return value >= 10; // Condition: value is 10 or greater }) .then(highValueStep) .then(finalStep) .else() .then(lowValueStep) .then(finalStep) // Both branches converge on the final step .commit(); // Register the workflow const mastra = new Mastra({ legacy_workflows: { conditionalWorkflow }, }); // Example usage async function runWorkflow(inputValue: number) { const workflow = mastra.legacy_getWorkflow("conditionalWorkflow"); const { start } = workflow.createRun(); const result = await start({ triggerData: { inputValue }, }); console.log("Workflow result:", result.results); return result; } // Run with a high value (follows the "if" branch) const result1 = await runWorkflow(15); // Run with a low value (follows the "else" branch) const result2 = await runWorkflow(5); console.log("Result 1:", result1); console.log("Result 2:", result2); ``` ## Using Reference-Based Conditions You can also use reference-based conditions with comparison operators: ```ts showLineNumbers copy // Using reference-based conditions instead of functions conditionalWorkflow .step(startStep) .if({ ref: { step: startStep, path: "value" }, query: { $gte: 10 }, // Condition: value is 10 or greater }) .then(highValueStep) .then(finalStep) .else() .then(lowValueStep) .then(finalStep) .commit(); ```




--- title: "Example: Creating a Workflow | Workflows (Legacy) | Mastra Docs" description: Example of using Mastra to define and execute a simple workflow with a single step. --- import { GithubLink } from "@/components/github-link"; # Creating a Simple Workflow (Legacy) [EN] Source: https://mastra.ai/en/examples/workflows_legacy/creating-a-workflow A workflow allows you to define and execute sequences of operations in a structured path. This example shows a legacy workflow with a single step. ```ts showLineNumbers copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const myWorkflow = new LegacyWorkflow({ name: "my-workflow", triggerSchema: z.object({ input: z.number(), }), }); const stepOne = new LegacyStep({ id: "stepOne", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ doubledValue: z.number(), }), execute: async ({ context }) => { const doubledValue = context?.triggerData?.input * 2; return { doubledValue }; }, }); myWorkflow.step(stepOne).commit(); const { runId, start } = myWorkflow.createRun(); const res = await start({ triggerData: { input: 90 }, }); console.log(res.results); ```




--- title: "Example: Cyclical Dependencies | Workflows (Legacy) | Mastra Docs" description: Example of using Mastra to create legacy workflows with cyclical dependencies and conditional loops. --- import { GithubLink } from "@/components/github-link"; # Workflow (Legacy) with Cyclical dependencies [EN] Source: https://mastra.ai/en/examples/workflows_legacy/cyclical-dependencies Workflows support cyclical dependencies where steps can loop back based on conditions. The example below shows how to use conditional logic to create loops and handle repeated execution. ```ts showLineNumbers copy import { LegacyWorkflow, LegacyStep } from "@mastra/core/workflows/legacy"; import { z } from "zod"; async function main() { const doubleValue = new LegacyStep({ id: "doubleValue", description: "Doubles the input value", inputSchema: z.object({ inputValue: z.number(), }), outputSchema: z.object({ doubledValue: z.number(), }), execute: async ({ context }) => { const doubledValue = context.inputValue * 2; return { doubledValue }; }, }); const incrementByOne = new LegacyStep({ id: "incrementByOne", description: "Adds 1 to the input value", outputSchema: z.object({ incrementedValue: z.number(), }), execute: async ({ context }) => { const valueToIncrement = context?.getStepResult<{ firstValue: number }>( "trigger", )?.firstValue; if (!valueToIncrement) throw new Error("No value to increment provided"); const incrementedValue = valueToIncrement + 1; return { incrementedValue }; }, }); const cyclicalWorkflow = new LegacyWorkflow({ name: "cyclical-workflow", triggerSchema: z.object({ firstValue: z.number(), }), }); cyclicalWorkflow .step(doubleValue, { variables: { inputValue: { step: "trigger", path: "firstValue", }, }, }) .then(incrementByOne) .after(doubleValue) .step(doubleValue, { variables: { inputValue: { step: doubleValue, path: "doubledValue", }, }, }) .commit(); const { runId, start } = cyclicalWorkflow.createRun(); console.log("Run", runId); const res = await start({ triggerData: { firstValue: 6 } }); console.log(res.results); } main(); ```




--- title: "Example: Human in the Loop | Workflows (Legacy) | Mastra Docs" description: Example of using Mastra to create legacy workflows with human intervention points. --- import { GithubLink } from "@/components/github-link"; # Human in the Loop Workflow (Legacy) [EN] Source: https://mastra.ai/en/examples/workflows_legacy/human-in-the-loop Human-in-the-loop workflows allow you to pause execution at specific points to collect user input, make decisions, or perform actions that require human judgment. This example demonstrates how to create a legacy workflow with human intervention points. ## How It Works 1. A workflow step can **suspend** execution using the `suspend()` function, optionally passing a payload with context for the human decision maker. 2. When the workflow is **resumed**, the human input is passed in the `context` parameter of the `resume()` call. 3. This input becomes available in the step's execution context as `context.inputData`, which is typed according to the step's `inputSchema`. 4. The step can then continue execution based on the human input. This pattern allows for safe, type-checked human intervention in automated workflows. ## Interactive Terminal Example Using Inquirer This example demonstrates how to use the [Inquirer](https://www.npmjs.com/package/@inquirer/prompts) library to collect user input directly from the terminal when a workflow is suspended, creating a truly interactive human-in-the-loop experience. ```ts showLineNumbers copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; import { confirm, input, select } from "@inquirer/prompts"; // Step 1: Generate product recommendations const generateRecommendations = new LegacyStep({ id: "generateRecommendations", outputSchema: z.object({ customerName: z.string(), recommendations: z.array( z.object({ productId: z.string(), productName: z.string(), price: z.number(), description: z.string(), }), ), }), execute: async ({ context }) => { const customerName = context.triggerData.customerName; // In a real application, you might call an API or ML model here // For this example, we'll return mock data return { customerName, recommendations: [ { productId: "prod-001", productName: "Premium Widget", price: 99.99, description: "Our best-selling premium widget with advanced features", }, { productId: "prod-002", productName: "Basic Widget", price: 49.99, description: "Affordable entry-level widget for beginners", }, { productId: "prod-003", productName: "Widget Pro Plus", price: 149.99, description: "Professional-grade widget with extended warranty", }, ], }; }, }); ``` ```ts showLineNumbers copy // Step 2: Get human approval and customization for the recommendations const reviewRecommendations = new LegacyStep({ id: "reviewRecommendations", inputSchema: z.object({ approvedProducts: z.array(z.string()), customerNote: z.string().optional(), offerDiscount: z.boolean().optional(), }), outputSchema: z.object({ finalRecommendations: z.array( z.object({ productId: z.string(), productName: z.string(), price: z.number(), }), ), customerNote: z.string().optional(), offerDiscount: z.boolean(), }), execute: async ({ context, suspend }) => { const { customerName, recommendations } = context.getStepResult( generateRecommendations, ) || { customerName: "", recommendations: [], }; // Check if we have input from a resumed workflow const reviewInput = { approvedProducts: context.inputData?.approvedProducts || [], customerNote: context.inputData?.customerNote, offerDiscount: context.inputData?.offerDiscount, }; // If we don't have agent input yet, suspend for human review if (!reviewInput.approvedProducts.length) { console.log(`Generating recommendations for customer: ${customerName}`); await suspend({ customerName, recommendations, message: "Please review these product recommendations before sending to the customer", }); // Placeholder return (won't be reached due to suspend) return { finalRecommendations: [], customerNote: "", offerDiscount: false, }; } // Process the agent's product selections const finalRecommendations = recommendations .filter((product) => reviewInput.approvedProducts.includes(product.productId), ) .map((product) => ({ productId: product.productId, productName: product.productName, price: product.price, })); return { finalRecommendations, customerNote: reviewInput.customerNote || "", offerDiscount: reviewInput.offerDiscount || false, }; }, }); ``` ```ts showLineNumbers copy // Step 3: Send the recommendations to the customer const sendRecommendations = new LegacyStep({ id: "sendRecommendations", outputSchema: z.object({ emailSent: z.boolean(), emailContent: z.string(), }), execute: async ({ context }) => { const { customerName } = context.getStepResult(generateRecommendations) || { customerName: "", }; const { finalRecommendations, customerNote, offerDiscount } = context.getStepResult(reviewRecommendations) || { finalRecommendations: [], customerNote: "", offerDiscount: false, }; // Generate email content based on the recommendations let emailContent = `Dear ${customerName},\n\nBased on your preferences, we recommend:\n\n`; finalRecommendations.forEach((product) => { emailContent += `- ${product.productName}: $${product.price.toFixed(2)}\n`; }); if (offerDiscount) { emailContent += "\nAs a valued customer, use code SAVE10 for 10% off your next purchase!\n"; } if (customerNote) { emailContent += `\nPersonal note: ${customerNote}\n`; } emailContent += "\nThank you for your business,\nThe Sales Team"; // In a real application, you would send this email console.log("Email content generated:", emailContent); return { emailSent: true, emailContent, }; }, }); // Build the workflow const recommendationWorkflow = new LegacyWorkflow({ name: "product-recommendation-workflow", triggerSchema: z.object({ customerName: z.string(), }), }); recommendationWorkflow .step(generateRecommendations) .then(reviewRecommendations) .then(sendRecommendations) .commit(); // Register the workflow const mastra = new Mastra({ legacy_workflows: { recommendationWorkflow }, }); ``` ```ts showLineNumbers copy // Example of using the workflow with Inquirer prompts async function runRecommendationWorkflow() { const registeredWorkflow = mastra.legacy_getWorkflow( "recommendationWorkflow", ); const run = registeredWorkflow.createRun(); console.log("Starting product recommendation workflow..."); const result = await run.start({ triggerData: { customerName: "Jane Smith", }, }); const isReviewStepSuspended = result.activePaths.get("reviewRecommendations")?.status === "suspended"; // Check if workflow is suspended for human review if (isReviewStepSuspended) { const { customerName, recommendations, message } = result.activePaths.get( "reviewRecommendations", )?.suspendPayload; console.log("\n==================================="); console.log(message); console.log(`Customer: ${customerName}`); console.log("===================================\n"); // Use Inquirer to collect input from the sales agent in the terminal console.log("Available product recommendations:"); recommendations.forEach((product, index) => { console.log( `${index + 1}. ${product.productName} - $${product.price.toFixed(2)}`, ); console.log(` ${product.description}\n`); }); // Let the agent select which products to recommend const approvedProducts = await checkbox({ message: "Select products to recommend to the customer:", choices: recommendations.map((product) => ({ name: `${product.productName} ($${product.price.toFixed(2)})`, value: product.productId, })), }); // Let the agent add a personal note const includeNote = await confirm({ message: "Would you like to add a personal note?", default: false, }); let customerNote = ""; if (includeNote) { customerNote = await input({ message: "Enter your personalized note for the customer:", }); } // Ask if a discount should be offered const offerDiscount = await confirm({ message: "Offer a 10% discount to this customer?", default: false, }); console.log("\nSubmitting your review..."); // Resume the workflow with the agent's input const resumeResult = await run.resume({ stepId: "reviewRecommendations", context: { approvedProducts, customerNote, offerDiscount, }, }); console.log("\n==================================="); console.log("Workflow completed!"); console.log("Email content:"); console.log("===================================\n"); console.log( resumeResult?.results?.sendRecommendations || "No email content generated", ); return resumeResult; } return result; } // Invoke the workflow with interactive terminal input runRecommendationWorkflow().catch(console.error); ``` ## Advanced Example with Multiple User Inputs This example demonstrates a more complex workflow that requires multiple human intervention points, such as in a content moderation system. ```ts showLineNumbers copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; import { select, input } from "@inquirer/prompts"; // Step 1: Receive and analyze content const analyzeContent = new LegacyStep({ id: "analyzeContent", outputSchema: z.object({ content: z.string(), aiAnalysisScore: z.number(), flaggedCategories: z.array(z.string()).optional(), }), execute: async ({ context }) => { const content = context.triggerData.content; // Simulate AI analysis const aiAnalysisScore = simulateContentAnalysis(content); const flaggedCategories = aiAnalysisScore < 0.7 ? ["potentially inappropriate", "needs review"] : []; return { content, aiAnalysisScore, flaggedCategories, }; }, }); ``` ```ts showLineNumbers copy // Step 2: Moderate content that needs review const moderateContent = new LegacyStep({ id: "moderateContent", // Define the schema for human input that will be provided when resuming inputSchema: z.object({ moderatorDecision: z.enum(["approve", "reject", "modify"]).optional(), moderatorNotes: z.string().optional(), modifiedContent: z.string().optional(), }), outputSchema: z.object({ moderationResult: z.enum(["approved", "rejected", "modified"]), moderatedContent: z.string(), notes: z.string().optional(), }), // @ts-ignore execute: async ({ context, suspend }) => { const analysisResult = context.getStepResult(analyzeContent); // Access the input provided when resuming the workflow const moderatorInput = { decision: context.inputData?.moderatorDecision, notes: context.inputData?.moderatorNotes, modifiedContent: context.inputData?.modifiedContent, }; // If the AI analysis score is high enough, auto-approve if ( analysisResult?.aiAnalysisScore > 0.9 && !analysisResult?.flaggedCategories?.length ) { return { moderationResult: "approved", moderatedContent: analysisResult.content, notes: "Auto-approved by system", }; } // If we don't have moderator input yet, suspend for human review if (!moderatorInput.decision) { await suspend({ content: analysisResult?.content, aiScore: analysisResult?.aiAnalysisScore, flaggedCategories: analysisResult?.flaggedCategories, message: "Please review this content and make a moderation decision", }); // Placeholder return return { moderationResult: "approved", moderatedContent: "", }; } // Process the moderator's decision switch (moderatorInput.decision) { case "approve": return { moderationResult: "approved", moderatedContent: analysisResult?.content || "", notes: moderatorInput.notes || "Approved by moderator", }; case "reject": return { moderationResult: "rejected", moderatedContent: "", notes: moderatorInput.notes || "Rejected by moderator", }; case "modify": return { moderationResult: "modified", moderatedContent: moderatorInput.modifiedContent || analysisResult?.content || "", notes: moderatorInput.notes || "Modified by moderator", }; default: return { moderationResult: "rejected", moderatedContent: "", notes: "Invalid moderator decision", }; } }, }); ``` ```ts showLineNumbers copy // Step 3: Apply moderation actions const applyModeration = new LegacyStep({ id: "applyModeration", outputSchema: z.object({ finalStatus: z.string(), content: z.string().optional(), auditLog: z.object({ originalContent: z.string(), moderationResult: z.string(), aiScore: z.number(), timestamp: z.string(), }), }), execute: async ({ context }) => { const analysisResult = context.getStepResult(analyzeContent); const moderationResult = context.getStepResult(moderateContent); // Create audit log const auditLog = { originalContent: analysisResult?.content || "", moderationResult: moderationResult?.moderationResult || "unknown", aiScore: analysisResult?.aiAnalysisScore || 0, timestamp: new Date().toISOString(), }; // Apply moderation action switch (moderationResult?.moderationResult) { case "approved": return { finalStatus: "Content published", content: moderationResult.moderatedContent, auditLog, }; case "modified": return { finalStatus: "Content modified and published", content: moderationResult.moderatedContent, auditLog, }; case "rejected": return { finalStatus: "Content rejected", auditLog, }; default: return { finalStatus: "Error in moderation process", auditLog, }; } }, }); ``` ```ts showLineNumbers copy // Build the workflow const contentModerationWorkflow = new LegacyWorkflow({ name: "content-moderation-workflow", triggerSchema: z.object({ content: z.string(), }), }); contentModerationWorkflow .step(analyzeContent) .then(moderateContent) .then(applyModeration) .commit(); // Register the workflow const mastra = new Mastra({ legacy_workflows: { contentModerationWorkflow }, }); // Example of using the workflow with Inquirer prompts async function runModerationDemo() { const registeredWorkflow = mastra.legacy_getWorkflow( "contentModerationWorkflow", ); const run = registeredWorkflow.createRun(); // Start the workflow with content that needs review console.log("Starting content moderation workflow..."); const result = await run.start({ triggerData: { content: "This is some user-generated content that requires moderation.", }, }); const isReviewStepSuspended = result.activePaths.get("moderateContent")?.status === "suspended"; // Check if workflow is suspended if (isReviewStepSuspended) { const { content, aiScore, flaggedCategories, message } = result.activePaths.get("moderateContent")?.suspendPayload; console.log("\n==================================="); console.log(message); console.log("===================================\n"); console.log("Content to review:"); console.log(content); console.log(`\nAI Analysis Score: ${aiScore}`); console.log( `Flagged Categories: ${flaggedCategories?.join(", ") || "None"}\n`, ); // Collect moderator decision using Inquirer const moderatorDecision = await select({ message: "Select your moderation decision:", choices: [ { name: "Approve content as is", value: "approve" }, { name: "Reject content completely", value: "reject" }, { name: "Modify content before publishing", value: "modify" }, ], }); // Collect additional information based on decision let moderatorNotes = ""; let modifiedContent = ""; moderatorNotes = await input({ message: "Enter any notes about your decision:", }); if (moderatorDecision === "modify") { modifiedContent = await input({ message: "Enter the modified content:", default: content, }); } console.log("\nSubmitting your moderation decision..."); // Resume the workflow with the moderator's input const resumeResult = await run.resume({ stepId: "moderateContent", context: { moderatorDecision, moderatorNotes, modifiedContent, }, }); if (resumeResult?.results?.applyModeration?.status === "success") { console.log("\n==================================="); console.log( `Moderation complete: ${resumeResult?.results?.applyModeration?.output.finalStatus}`, ); console.log("===================================\n"); if (resumeResult?.results?.applyModeration?.output.content) { console.log("Published content:"); console.log(resumeResult.results.applyModeration.output.content); } } return resumeResult; } console.log( "Workflow completed without requiring human intervention:", result.results, ); return result; } // Helper function for AI content analysis simulation function simulateContentAnalysis(content: string): number { // In a real application, this would call an AI service // For the example, we're returning a random score return Math.random(); } // Invoke the demo function runModerationDemo().catch(console.error); ``` ## Key Concepts 1. **Suspension Points** - Use the `suspend()` function within a step's execute to pause workflow execution. 2. **Suspension Payload** - Pass relevant data when suspending to provide context for human decision-making: ```ts await suspend({ messageForHuman: "Please review this data", data: someImportantData, }); ``` 3. **Checking Workflow Status** - After starting a workflow, check the returned status to see if it's suspended: ```ts const result = await workflow.start({ triggerData }); if (result.status === "suspended" && result.suspendedStepId === "stepId") { // Process suspension console.log("Workflow is waiting for input:", result.suspendPayload); } ``` 4. **Interactive Terminal Input** - Use libraries like Inquirer to create interactive prompts: ```ts import { select, input, confirm } from "@inquirer/prompts"; // When the workflow is suspended if (result.status === "suspended") { // Display information from the suspend payload console.log(result.suspendPayload.message); // Collect user input interactively const decision = await select({ message: "What would you like to do?", choices: [ { name: "Approve", value: "approve" }, { name: "Reject", value: "reject" }, ], }); // Resume the workflow with the collected input await run.resume({ stepId: result.suspendedStepId, context: { decision }, }); } ``` 5. **Resuming Workflow** - Use the `resume()` method to continue workflow execution with human input: ```ts const resumeResult = await run.resume({ stepId: "suspendedStepId", context: { // This data is passed to the suspended step as context.inputData // and must conform to the step's inputSchema userDecision: "approve", }, }); ``` 6. **Input Schema for Human Data** - Define an input schema on steps that might be resumed with human input to ensure type safety: ```ts const myStep = new LegacyStep({ id: "myStep", inputSchema: z.object({ // This schema validates the data passed in resume's context // and makes it available as context.inputData userDecision: z.enum(["approve", "reject"]), userComments: z.string().optional(), }), execute: async ({ context, suspend }) => { // Check if we have user input from a previous suspension if (context.inputData?.userDecision) { // Process the user's decision return { result: `User decided: ${context.inputData.userDecision}` }; } // If no input, suspend for human decision await suspend(); }, }); ``` Human-in-the-loop workflows are powerful for building systems that blend automation with human judgment, such as: - Content moderation systems - Approval workflows - Supervised AI systems - Customer service automation with escalation




--- title: "Example: Parallel Execution | Workflows (Legacy) | Mastra Docs" description: Example of using Mastra to execute multiple independent tasks in parallel within a workflow. --- import { GithubLink } from "@/components/github-link"; # Parallel Execution with Steps [EN] Source: https://mastra.ai/en/examples/workflows_legacy/parallel-steps When building AI applications, you often need to process multiple independent tasks simultaneously to improve efficiency. ## Control Flow Diagram This example shows how to structure a workflow that executes steps in parallel, with each branch handling its own data flow and dependencies. Here's the control flow diagram: Diagram showing workflow with parallel steps ## Creating the Steps Let's start by creating the steps and initializing the workflow. ```ts showLineNumbers copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const stepOne = new LegacyStep({ id: "stepOne", execute: async ({ context }) => ({ doubledValue: context.triggerData.inputValue * 2, }), }); const stepTwo = new LegacyStep({ id: "stepTwo", execute: async ({ context }) => { if (context.steps.stepOne.status !== "success") { return { incrementedValue: 0 }; } return { incrementedValue: context.steps.stepOne.output.doubledValue + 1 }; }, }); const stepThree = new LegacyStep({ id: "stepThree", execute: async ({ context }) => ({ tripledValue: context.triggerData.inputValue * 3, }), }); const stepFour = new LegacyStep({ id: "stepFour", execute: async ({ context }) => { if (context.steps.stepThree.status !== "success") { return { isEven: false }; } return { isEven: context.steps.stepThree.output.tripledValue % 2 === 0 }; }, }); const myWorkflow = new LegacyWorkflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); ``` ## Chaining and Parallelizing Steps Now we can add the steps to the workflow. Note the `.then()` method is used to chain the steps, but the `.step()` method is used to add the steps to the workflow. ```ts showLineNumbers copy myWorkflow .step(stepOne) .then(stepTwo) // chain one .step(stepThree) .then(stepFour) // chain two .commit(); const { start } = myWorkflow.createRun(); const result = await start({ triggerData: { inputValue: 3 } }); ```




--- title: "Example: Sequential Steps | Workflows (Legacy) | Mastra Docs" description: Example of using Mastra to chain legacy workflow steps in a specific sequence, passing data between them. --- import { GithubLink } from "@/components/github-link"; # Workflow (Legacy) with Sequential Steps [EN] Source: https://mastra.ai/en/examples/workflows_legacy/sequential-steps Workflow can be chained to run one after another in a specific sequence. ## Control Flow Diagram This example shows how to chain workflow steps by using the `then` method demonstrating how to pass data between sequential steps and execute them in order. Here's the control flow diagram: Diagram showing workflow with sequential steps ## Creating the Steps Let's start by creating the steps and initializing the workflow. ```ts showLineNumbers copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const stepOne = new LegacyStep({ id: "stepOne", execute: async ({ context }) => ({ doubledValue: context.triggerData.inputValue * 2, }), }); const stepTwo = new LegacyStep({ id: "stepTwo", execute: async ({ context }) => { if (context.steps.stepOne.status !== "success") { return { incrementedValue: 0 }; } return { incrementedValue: context.steps.stepOne.output.doubledValue + 1 }; }, }); const stepThree = new LegacyStep({ id: "stepThree", execute: async ({ context }) => { if (context.steps.stepTwo.status !== "success") { return { tripledValue: 0 }; } return { tripledValue: context.steps.stepTwo.output.incrementedValue * 3 }; }, }); // Build the workflow const myWorkflow = new LegacyWorkflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); ``` ## Chaining the Steps and Executing the Workflow Now let's chain the steps together. ```ts showLineNumbers copy // sequential steps myWorkflow.step(stepOne).then(stepTwo).then(stepThree); myWorkflow.commit(); const { start } = myWorkflow.createRun(); const res = await start({ triggerData: { inputValue: 90 } }); ```




--- title: "Example: Suspend and Resume | Workflows (Legacy) | Mastra Docs" description: Example of using Mastra to suspend and resume legacy workflow steps during execution. --- import { GithubLink } from "@/components/github-link"; # Workflow (Legacy) with Suspend and Resume [EN] Source: https://mastra.ai/en/examples/workflows_legacy/suspend-and-resume Workflow steps can be suspended and resumed at any point in the workflow execution. This example demonstrates how to suspend a workflow step and resume it later. ## Basic Example ```ts showLineNumbers copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const stepOne = new LegacyStep({ id: "stepOne", outputSchema: z.object({ doubledValue: z.number(), }), execute: async ({ context }) => { const doubledValue = context.triggerData.inputValue * 2; return { doubledValue }; }, }); ``` ```ts showLineNumbers copy const stepTwo = new LegacyStep({ id: "stepTwo", outputSchema: z.object({ incrementedValue: z.number(), }), execute: async ({ context, suspend }) => { const secondValue = context.inputData?.secondValue ?? 0; const doubledValue = context.getStepResult(stepOne)?.doubledValue ?? 0; const incrementedValue = doubledValue + secondValue; if (incrementedValue < 100) { await suspend(); return { incrementedValue: 0 }; } return { incrementedValue }; }, }); // Build the workflow const myWorkflow = new LegacyWorkflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); // run workflows in parallel myWorkflow.step(stepOne).then(stepTwo).commit(); ``` ```ts showLineNumbers copy // Register the workflow export const mastra = new Mastra({ legacy_workflows: { registeredWorkflow: myWorkflow }, }); // Get registered workflow from Mastra const registeredWorkflow = mastra.legacy_getWorkflow("registeredWorkflow"); const { runId, start } = registeredWorkflow.createRun(); // Start watching the workflow before executing it myWorkflow.watch(async ({ context, activePaths }) => { for (const _path of activePaths) { const stepTwoStatus = context.steps?.stepTwo?.status; if (stepTwoStatus === "suspended") { console.log("Workflow suspended, resuming with new value"); // Resume the workflow with new context await myWorkflow.resume({ runId, stepId: "stepTwo", context: { secondValue: 100 }, }); } } }); // Start the workflow execution await start({ triggerData: { inputValue: 45 } }); ``` ## Advanced Example with Multiple Suspension Points Using async/await pattern and suspend payloads This example demonstrates a more complex workflow with multiple suspension points using the async/await pattern. It simulates a content generation workflow that requires human intervention at different stages. ```ts showLineNumbers copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Step 1: Get user input const getUserInput = new LegacyStep({ id: "getUserInput", execute: async ({ context }) => { // In a real application, this might come from a form or API return { userInput: context.triggerData.input }; }, outputSchema: z.object({ userInput: z.string() }), }); ``` ```ts showLineNumbers copy // Step 2: Generate content with AI (may suspend for human guidance) const promptAgent = new LegacyStep({ id: "promptAgent", inputSchema: z.object({ guidance: z.string(), }), execute: async ({ context, suspend }) => { const userInput = context.getStepResult(getUserInput)?.userInput; console.log(`Generating content based on: ${userInput}`); const guidance = context.inputData?.guidance; // Simulate AI generating content const initialDraft = generateInitialDraft(userInput); // If confidence is high, return the generated content directly if (initialDraft.confidenceScore > 0.7) { return { modelOutput: initialDraft.content }; } console.log( "Low confidence in generated content, suspending for human guidance", { guidance }, ); // If confidence is low, suspend for human guidance if (!guidance) { // only suspend if no guidance is provided await suspend(); return undefined; } // This code runs after resume with human guidance console.log("Resumed with human guidance"); // Use the human guidance to improve the output return { modelOutput: enhanceWithGuidance(initialDraft.content, guidance), }; }, outputSchema: z.object({ modelOutput: z.string() }).optional(), }); ``` ```ts showLineNumbers copy // Step 3: Evaluate the content quality const evaluateTone = new LegacyStep({ id: "evaluateToneConsistency", execute: async ({ context }) => { const content = context.getStepResult(promptAgent)?.modelOutput; // Simulate evaluation return { toneScore: { score: calculateToneScore(content) }, completenessScore: { score: calculateCompletenessScore(content) }, }; }, outputSchema: z.object({ toneScore: z.any(), completenessScore: z.any(), }), }); ``` ```ts showLineNumbers copy // Step 4: Improve response if needed (may suspend) const improveResponse = new LegacyStep({ id: "improveResponse", inputSchema: z.object({ improvedContent: z.string(), resumeAttempts: z.number(), }), execute: async ({ context, suspend }) => { const content = context.getStepResult(promptAgent)?.modelOutput; const toneScore = context.getStepResult(evaluateTone)?.toneScore.score ?? 0; const completenessScore = context.getStepResult(evaluateTone)?.completenessScore.score ?? 0; const improvedContent = context.inputData.improvedContent; const resumeAttempts = context.inputData.resumeAttempts ?? 0; // If scores are above threshold, make minor improvements if (toneScore > 0.8 && completenessScore > 0.8) { return { improvedOutput: makeMinorImprovements(content) }; } console.log( "Content quality below threshold, suspending for human intervention", { improvedContent, resumeAttempts }, ); if (!improvedContent) { // Suspend with payload containing content and resume attempts await suspend({ content, scores: { tone: toneScore, completeness: completenessScore }, needsImprovement: toneScore < 0.8 ? "tone" : "completeness", resumeAttempts: resumeAttempts + 1, }); return { improvedOutput: content ?? "" }; } console.log("Resumed with human improvements", improvedContent); return { improvedOutput: improvedContent ?? content ?? "" }; }, outputSchema: z.object({ improvedOutput: z.string() }).optional(), }); ``` ```ts showLineNumbers copy // Step 5: Final evaluation const evaluateImproved = new LegacyStep({ id: "evaluateImprovedResponse", execute: async ({ context }) => { const improvedContent = context.getStepResult(improveResponse)?.improvedOutput; // Simulate final evaluation return { toneScore: { score: calculateToneScore(improvedContent) }, completenessScore: { score: calculateCompletenessScore(improvedContent) }, }; }, outputSchema: z.object({ toneScore: z.any(), completenessScore: z.any(), }), }); // Build the workflow const contentWorkflow = new LegacyWorkflow({ name: "content-generation-workflow", triggerSchema: z.object({ input: z.string() }), }); contentWorkflow .step(getUserInput) .then(promptAgent) .then(evaluateTone) .then(improveResponse) .then(evaluateImproved) .commit(); ``` ```ts showLineNumbers copy // Register the workflow const mastra = new Mastra({ legacy_workflows: { contentWorkflow }, }); // Helper functions (simulated) function generateInitialDraft(input: string = "") { // Simulate AI generating content return { content: `Generated content based on: ${input}`, confidenceScore: 0.6, // Simulate low confidence to trigger suspension }; } function enhanceWithGuidance(content: string = "", guidance: string = "") { return `${content} (Enhanced with guidance: ${guidance})`; } function makeMinorImprovements(content: string = "") { return `${content} (with minor improvements)`; } function calculateToneScore(_: string = "") { return 0.7; // Simulate a score that will trigger suspension } function calculateCompletenessScore(_: string = "") { return 0.9; } // Usage example async function runWorkflow() { const workflow = mastra.legacy_getWorkflow("contentWorkflow"); const { runId, start } = workflow.createRun(); let finalResult: any; // Start the workflow const initialResult = await start({ triggerData: { input: "Create content about sustainable energy" }, }); console.log("Initial workflow state:", initialResult.results); const promptAgentStepResult = initialResult.activePaths.get("promptAgent"); // Check if promptAgent step is suspended if (promptAgentStepResult?.status === "suspended") { console.log("Workflow suspended at promptAgent step"); console.log("Suspension payload:", promptAgentStepResult?.suspendPayload); // Resume with human guidance const resumeResult1 = await workflow.resume({ runId, stepId: "promptAgent", context: { guidance: "Focus more on solar and wind energy technologies", }, }); console.log("Workflow resumed and continued to next steps"); let improveResponseResumeAttempts = 0; let improveResponseStatus = resumeResult1?.activePaths.get("improveResponse")?.status; // Check if improveResponse step is suspended while (improveResponseStatus === "suspended") { console.log("Workflow suspended at improveResponse step"); console.log( "Suspension payload:", resumeResult1?.activePaths.get("improveResponse")?.suspendPayload, ); const improvedContent = improveResponseResumeAttempts < 3 ? undefined : "Completely revised content about sustainable energy focusing on solar and wind technologies"; // Resume with human improvements finalResult = await workflow.resume({ runId, stepId: "improveResponse", context: { improvedContent, resumeAttempts: improveResponseResumeAttempts, }, }); improveResponseResumeAttempts = finalResult?.activePaths.get("improveResponse")?.suspendPayload ?.resumeAttempts ?? 0; improveResponseStatus = finalResult?.activePaths.get("improveResponse")?.status; console.log("Improved response result:", finalResult?.results); } } return finalResult; } // Run the workflow const result = await runWorkflow(); console.log("Workflow completed"); console.log("Final workflow result:", result); ``` --- title: "Example: Using a Tool as a Step | Workflows (Legacy) | Mastra Docs" description: Example of using Mastra to integrate a custom tool as a step in a legacy workflow. --- import { GithubLink } from "@/components/github-link"; # Tool as a Workflow step (Legacy) [EN] Source: https://mastra.ai/en/examples/workflows_legacy/using-a-tool-as-a-step This example demonstrates how to create and integrate a custom tool as a workflow step, showing how to define input/output schemas and implement the tool's execution logic. ```ts showLineNumbers copy import { createTool } from "@mastra/core/tools"; import { LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const crawlWebpage = createTool({ id: "Crawl Webpage", description: "Crawls a webpage and extracts the text content", inputSchema: z.object({ url: z.string().url(), }), outputSchema: z.object({ rawText: z.string(), }), execute: async ({ context }) => { const response = await fetch(context.triggerData.url); const text = await response.text(); return { rawText: "This is the text content of the webpage: " + text }; }, }); const contentWorkflow = new LegacyWorkflow({ name: "content-review" }); contentWorkflow.step(crawlWebpage).commit(); const { start } = contentWorkflow.createRun(); const res = await start({ triggerData: { url: "https://example.com" } }); console.log(res.results); ```




--- title: "Data Mapping with Workflow Variables (Legacy) | Mastra Examples" description: "Learn how to use workflow variables to map data between steps in Mastra workflows." --- # Data Mapping with Workflow Variables (Legacy) [EN] Source: https://mastra.ai/en/examples/workflows_legacy/workflow-variables This example demonstrates how to use workflow variables to map data between steps in a Mastra workflow. ## Use Case: User Registration Process In this example, we'll build a simple user registration workflow that: 1. Validates user input 1. Formats the user data 1. Creates a user profile ## Implementation ```typescript showLineNumbers filename="src/mastra/workflows/user-registration.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Define our schemas for better type safety const userInputSchema = z.object({ email: z.string().email(), name: z.string(), age: z.number().min(18), }); const validatedDataSchema = z.object({ isValid: z.boolean(), validatedData: z.object({ email: z.string(), name: z.string(), age: z.number(), }), }); const formattedDataSchema = z.object({ userId: z.string(), formattedData: z.object({ email: z.string(), displayName: z.string(), ageGroup: z.string(), }), }); const profileSchema = z.object({ profile: z.object({ id: z.string(), email: z.string(), displayName: z.string(), ageGroup: z.string(), createdAt: z.string(), }), }); // Define the workflow const registrationWorkflow = new LegacyWorkflow({ name: "user-registration", triggerSchema: userInputSchema, }); // Step 1: Validate user input const validateInput = new LegacyStep({ id: "validateInput", inputSchema: userInputSchema, outputSchema: validatedDataSchema, execute: async ({ context }) => { const { email, name, age } = context; // Simple validation logic const isValid = email.includes("@") && name.length > 0 && age >= 18; return { isValid, validatedData: { email: email.toLowerCase().trim(), name, age, }, }; }, }); // Step 2: Format user data const formatUserData = new LegacyStep({ id: "formatUserData", inputSchema: z.object({ validatedData: z.object({ email: z.string(), name: z.string(), age: z.number(), }), }), outputSchema: formattedDataSchema, execute: async ({ context }) => { const { validatedData } = context; // Generate a simple user ID const userId = `user_${Math.floor(Math.random() * 10000)}`; // Format the data const ageGroup = validatedData.age < 30 ? "young-adult" : "adult"; return { userId, formattedData: { email: validatedData.email, displayName: validatedData.name, ageGroup, }, }; }, }); // Step 3: Create user profile const createUserProfile = new LegacyStep({ id: "createUserProfile", inputSchema: z.object({ userId: z.string(), formattedData: z.object({ email: z.string(), displayName: z.string(), ageGroup: z.string(), }), }), outputSchema: profileSchema, execute: async ({ context }) => { const { userId, formattedData } = context; // In a real app, you would save to a database here return { profile: { id: userId, ...formattedData, createdAt: new Date().toISOString(), }, }; }, }); // Build the workflow with variable mappings registrationWorkflow // First step gets data from the trigger .step(validateInput, { variables: { email: { step: "trigger", path: "email" }, name: { step: "trigger", path: "name" }, age: { step: "trigger", path: "age" }, }, }) // Format user data with validated data from previous step .then(formatUserData, { variables: { validatedData: { step: validateInput, path: "validatedData" }, }, when: { ref: { step: validateInput, path: "isValid" }, query: { $eq: true }, }, }) // Create profile with data from the format step .then(createUserProfile, { variables: { userId: { step: formatUserData, path: "userId" }, formattedData: { step: formatUserData, path: "formattedData" }, }, }) .commit(); export default registrationWorkflow; ``` ## How to Use This Example 1. Create the file as shown above 2. Register the workflow in your Mastra instance 3. Execute the workflow: ```bash curl --location 'http://localhost:4111/api/workflows/user-registration/start-async' \ --header 'Content-Type: application/json' \ --data '{ "email": "user@example.com", "name": "John Doe", "age": 25 }' ``` ## Key Takeaways This example demonstrates several important concepts about workflow variables: 1. **Data Mapping**: Variables map data from one step to another, creating a clear data flow. 2. **Path Access**: The `path` property specifies which part of a step's output to use. 3. **Conditional Execution**: The `when` property allows steps to execute conditionally based on previous step outputs. 4. **Type Safety**: Each step defines input and output schemas for type safety, ensuring that the data passed between steps is properly typed. 5. **Explicit Data Dependencies**: By defining input schemas and using variable mappings, the data dependencies between steps are made explicit and clear. For more information on workflow variables, see the [Workflow Variables documentation](../../docs/workflows-legacy/variables.mdx). --- title: "Building an AI Recruiter | Mastra Workflows | Guides" description: Guide on building a recruiter workflow in Mastra to gather and process candidate information using LLMs. --- # Introduction [EN] Source: https://mastra.ai/en/guides/guide/ai-recruiter In this guide, you'll learn how Mastra helps you build workflows with LLMs. We'll walk through creating a workflow that gathers information from a candidate's resume, then branches to either a technical or behavioral question based on the candidate's profile. Along the way, you'll see how to structure workflow steps, handle branching, and integrate LLM calls. Below is a concise version of the workflow. It starts by importing the necessary modules, sets up Mastra, defines steps to extract and classify candidate data, and then asks suitable follow-up questions. Each code block is followed by a short explanation of what it does and why it's useful. ## 1. Imports and Setup You need to import Mastra tools and Zod to handle workflow definitions and data validation. ```ts filename="src/mastra/index.ts" copy import { Mastra } from "@mastra/core"; import { createStep, createWorkflow } from "@mastra/core/workflows"; import { z } from "zod"; ``` Add your `OPENAI_API_KEY` to the `.env` file. ```bash filename=".env" copy OPENAI_API_KEY= ``` ## 2. Step One: Gather Candidate Info You want to extract candidate details from the resume text and classify them as technical or non-technical. This step calls an LLM to parse the resume and return structured JSON, including the name, technical status, specialty, and the original resume text. The code reads resumeText from trigger data, prompts the LLM, and returns organized fields for use in subsequent steps. ```ts filename="src/mastra/index.ts" copy import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const recruiter = new Agent({ name: "Recruiter Agent", instructions: `You are a recruiter.`, model: openai("gpt-4o-mini"), }); const gatherCandidateInfo = createStep({ id: "gatherCandidateInfo", inputSchema: z.object({ resumeText: z.string(), }), outputSchema: z.object({ candidateName: z.string(), isTechnical: z.boolean(), specialty: z.string(), resumeText: z.string(), }), execute: async ({ inputData }) => { const resumeText = inputData?.resumeText; const prompt = ` Extract details from the resume text: "${resumeText}" `; const res = await recruiter.generate(prompt, { output: z.object({ candidateName: z.string(), isTechnical: z.boolean(), specialty: z.string(), resumeText: z.string(), }), }); return res.object; }, }); ``` ## 3. Technical Question Step This step prompts a candidate who is identified as technical for more information about how they got into their specialty. It uses the entire resume text so the LLM can craft a relevant follow-up question. The code generates a question about the candidate's specialty. ```ts filename="src/mastra/index.ts" copy interface CandidateInfo { candidateName: string; isTechnical: boolean; specialty: string; resumeText: string; } const askAboutSpecialty = createStep({ id: "askAboutSpecialty", inputSchema: z.object({ candidateName: z.string(), isTechnical: z.boolean(), specialty: z.string(), resumeText: z.string(), }), outputSchema: z.object({ question: z.string(), }), execute: async ({ inputData }) => { const candidateInfo = inputData; const prompt = ` You are a recruiter. Given the resume below, craft a short question for ${candidateInfo?.candidateName} about how they got into "${candidateInfo?.specialty}". Resume: ${candidateInfo?.resumeText} `; const res = await recruiter.generate(prompt); return { question: res?.text?.trim() || "" }; }, }); ``` ## 4. Behavioral Question Step If the candidate is non-technical, you want a different follow-up question. This step asks what interests them most about the role, again referencing their complete resume text. The code solicits a role-focused query from the LLM. ```ts filename="src/mastra/index.ts" copy const askAboutRole = createStep({ id: "askAboutRole", inputSchema: z.object({ candidateName: z.string(), isTechnical: z.boolean(), specialty: z.string(), resumeText: z.string(), }), outputSchema: z.object({ question: z.string(), }), execute: async ({ inputData }) => { const candidateInfo = inputData; const prompt = ` You are a recruiter. Given the resume below, craft a short question for ${candidateInfo?.candidateName} asking what interests them most about this role. Resume: ${candidateInfo?.resumeText} `; const res = await recruiter.generate(prompt); return { question: res?.text?.trim() || "" }; }, }); ``` ## 5. Define the Workflow You now combine the steps to implement branching logic based on the candidate's technical status. The workflow first gathers candidate data, then either asks about their specialty or about their role, depending on isTechnical. The code chains gatherCandidateInfo with askAboutSpecialty and askAboutRole, and commits the workflow. ```ts filename="src/mastra/index.ts" copy const candidateWorkflow = createWorkflow({ id: "candidate-workflow", inputSchema: z.object({ resumeText: z.string(), }), outputSchema: z.object({ question: z.string(), }), }); candidateWorkflow.then(gatherCandidateInfo).branch([ // Branch for technical candidates [ async ({ inputData }) => { return inputData?.isTechnical; }, askAboutSpecialty, ], // Branch for non-technical candidates [ async ({ inputData }) => { return !inputData?.isTechnical; }, askAboutRole, ], ]); candidateWorkflow.commit(); ``` ## 6. Execute the Workflow ```ts filename="src/mastra/index.ts" copy const mastra = new Mastra({ workflows: { candidateWorkflow, }, }); (async () => { const run = mastra.getWorkflow("candidateWorkflow").createRun(); console.log("Run", run.runId); const runResult = await run.start({ inputData: { resumeText: "Simulated resume content..." }, }); console.log("Final output:", runResult); })(); ``` You've just built a workflow to parse a resume and decide which question to ask based on the candidate's technical abilities. Congrats and happy hacking! --- title: "Building an AI Chef Assistant | Mastra Agent Guides" description: Guide on creating a Chef Assistant agent in Mastra to help users cook meals with available ingredients. --- import { Steps } from "nextra/components"; import YouTube from "@/components/youtube"; # Agents Guide: Building a Chef Assistant [EN] Source: https://mastra.ai/en/guides/guide/chef-michel In this guide, we'll walk through creating a "Chef Assistant" agent that helps users cook meals with available ingredients. ## Prerequisites - Node.js installed - Mastra installed: `npm install @mastra/core@latest` --- ## Create the Agent ### Define the Agent Create a new file `src/mastra/agents/chefAgent.ts` and define your agent: ```ts copy filename="src/mastra/agents/chefAgent.ts" import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; export const chefAgent = new Agent({ name: "chef-agent", instructions: "You are Michel, a practical and experienced home chef" + "You help people cook with whatever ingredients they have available.", model: openai("gpt-4o-mini"), }); ``` --- ## Set Up Environment Variables Create a `.env` file in your project root and add your OpenAI API key: ```bash filename=".env" copy OPENAI_API_KEY=your_openai_api_key ``` --- ## Register the Agent with Mastra In your main file, register the agent: ```ts copy filename="src/mastra/index.ts" import { Mastra } from "@mastra/core"; import { chefAgent } from "./agents/chefAgent"; export const mastra = new Mastra({ agents: { chefAgent }, }); ``` --- ## Interacting with the Agent ### Generating Text Responses ```ts copy filename="src/index.ts" async function main() { const query = "In my kitchen I have: pasta, canned tomatoes, garlic, olive oil, and some dried herbs (basil and oregano). What can I make?"; console.log(`Query: ${query}`); const response = await chefAgent.generate([{ role: "user", content: query }]); console.log("\n👨‍🍳 Chef Michel:", response.text); } main(); ``` Run the script: ```bash copy npx bun src/index.ts ``` Output: ``` Query: In my kitchen I have: pasta, canned tomatoes, garlic, olive oil, and some dried herbs (basil and oregano). What can I make? 👨‍🍳 Chef Michel: You can make a delicious pasta al pomodoro! Here's how... ``` --- ### Streaming Responses ```ts copy filename="src/index.ts" async function main() { const query = "Now I'm over at my friend's house, and they have: chicken thighs, coconut milk, sweet potatoes, and some curry powder."; console.log(`Query: ${query}`); const stream = await chefAgent.stream([{ role: "user", content: query }]); console.log("\n Chef Michel: "); for await (const chunk of stream.textStream) { process.stdout.write(chunk); } console.log("\n\n✅ Recipe complete!"); } main(); ``` Output: ``` Query: Now I'm over at my friend's house, and they have: chicken thighs, coconut milk, sweet potatoes, and some curry powder. 👨‍🍳 Chef Michel: Great! You can make a comforting chicken curry... ✅ Recipe complete! ``` --- ### Generating a Recipe with Structured Data ```ts copy filename="src/index.ts" import { z } from "zod"; async function main() { const query = "I want to make lasagna, can you generate a lasagna recipe for me?"; console.log(`Query: ${query}`); // Define the Zod schema const schema = z.object({ ingredients: z.array( z.object({ name: z.string(), amount: z.string(), }), ), steps: z.array(z.string()), }); const response = await chefAgent.generate( [{ role: "user", content: query }], { output: schema }, ); console.log("\n👨‍🍳 Chef Michel:", response.object); } main(); ``` Output: ``` Query: I want to make lasagna, can you generate a lasagna recipe for me? 👨‍🍳 Chef Michel: { ingredients: [ { name: "Lasagna noodles", amount: "12 sheets" }, { name: "Ground beef", amount: "1 pound" }, // ... ], steps: [ "Preheat oven to 375°F (190°C).", "Cook the lasagna noodles according to package instructions.", // ... ] } ``` --- ## Running the Agent Server ### Using `mastra dev` You can run your agent as a service using the `mastra dev` command: ```bash copy mastra dev ``` This will start a server exposing endpoints to interact with your registered agents. ### Accessing the Chef Assistant API By default, `mastra dev` runs on `http://localhost:4111`. Your Chef Assistant agent will be available at: ``` POST http://localhost:4111/api/agents/chefAgent/generate ``` ### Interacting with the Agent via `curl` You can interact with the agent using `curl` from the command line: ```bash copy curl -X POST http://localhost:4111/api/agents/chefAgent/generate \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "role": "user", "content": "I have eggs, flour, and milk. What can I make?" } ] }' ``` **Sample Response:** ```json { "text": "You can make delicious pancakes! Here's a simple recipe..." } ``` --- title: "Building a Research Paper Assistant | Mastra RAG Guides" description: Guide on creating an AI research assistant that can analyze and answer questions about academic papers using RAG. --- import { Steps } from "nextra/components"; # Building a Research Paper Assistant with RAG [EN] Source: https://mastra.ai/en/guides/guide/research-assistant In this guide, we'll create an AI research assistant that can analyze academic papers and answer specific questions about their content using Retrieval Augmented Generation (RAG). We'll use the foundational Transformer paper [Attention Is All You Need](https://arxiv.org/html/1706.03762) as our example. ## Understanding RAG Components Let's understand how RAG works and how we'll implement each component: 1. Knowledge Store/Index - Converting text into vector representations - Creating numerical representations of content - Implementation: We'll use OpenAI's text-embedding-3-small to create embeddings and store them in PgVector 2. Retriever - Finding relevant content via similarity search - Matching query embeddings with stored vectors - Implementation: We'll use PgVector to perform similarity searches on our stored embeddings 3. Generator - Processing retrieved content with an LLM - Creating contextually informed responses - Implementation: We'll use GPT-4o-mini to generate answers based on retrieved content Our implementation will: 1. Process the Transformer paper into embeddings 2. Store them in PgVector for quick retrieval 3. Use similarity search to find relevant sections 4. Generate accurate responses using retrieved context ## Project Structure ``` research-assistant/ ├── src/ │ ├── mastra/ │ │ ├── agents/ │ │ │ └── researchAgent.ts │ │ └── index.ts │ ├── index.ts │ └── store.ts ├── package.json └── .env ``` ### Initialize Project and Install Dependencies First, create a new directory for your project and navigate into it: ```bash mkdir research-assistant cd research-assistant ``` Initialize a new Node.js project and install the required dependencies: ```bash copy npm init -y npm install @mastra/core@latest @mastra/rag@latest @mastra/pg@latest @ai-sdk/openai@latest ai@latest zod@latest ``` Set up environment variables for API access and database connection: ```bash filename=".env" copy OPENAI_API_KEY=your_openai_api_key POSTGRES_CONNECTION_STRING=your_connection_string ``` Create the necessary files for our project: ```bash copy mkdir -p src/mastra/agents touch src/mastra/agents/researchAgent.ts touch src/mastra/index.ts src/store.ts src/index.ts ``` ### Create the Research Assistant Agent Now we'll create our RAG-enabled research assistant. The agent uses: - A [Vector Query Tool](/reference/tools/vector-query-tool) for performing semantic search over our vector store to find relevant content in our papers. - GPT-4o-mini for understanding queries and generating responses - Custom instructions that guide the agent on how to analyze papers, use retrieved content effectively, and acknowledge limitations ```ts copy showLineNumbers filename="src/mastra/agents/researchAgent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { createVectorQueryTool } from "@mastra/rag"; // Create a tool for semantic search over our paper embeddings const vectorQueryTool = createVectorQueryTool({ vectorStoreName: "pgVector", indexName: "papers", model: openai.embedding("text-embedding-3-small"), }); export const researchAgent = new Agent({ name: "Research Assistant", instructions: `You are a helpful research assistant that analyzes academic papers and technical documents. Use the provided vector query tool to find relevant information from your knowledge base, and provide accurate, well-supported answers based on the retrieved content. Focus on the specific content available in the tool and acknowledge if you cannot find sufficient information to answer a question. Base your responses only on the content provided, not on general knowledge.`, model: openai("gpt-4o-mini"), tools: { vectorQueryTool, }, }); ``` ### Set Up the Mastra Instance and Vector Store ```ts copy showLineNumbers filename="src/mastra/index.ts" import { Mastra } from "@mastra/core"; import { PgVector } from "@mastra/pg"; import { researchAgent } from "./agents/researchAgent"; // Initialize Mastra instance const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); export const mastra = new Mastra({ agents: { researchAgent }, vectors: { pgVector }, }); ``` ### Load and Process the Paper This step handles the initial document processing. We: 1. Fetch the research paper from its URL 2. Convert it into a document object 3. Split it into smaller, manageable chunks for better processing ```ts copy showLineNumbers filename="src/store.ts" import { openai } from "@ai-sdk/openai"; import { MDocument } from "@mastra/rag"; import { embedMany } from "ai"; import { mastra } from "./mastra"; // Load the paper const paperUrl = "https://arxiv.org/html/1706.03762"; const response = await fetch(paperUrl); const paperText = await response.text(); // Create document and chunk it const doc = MDocument.fromText(paperText); const chunks = await doc.chunk({ strategy: "recursive", size: 512, overlap: 50, separator: "\n", }); console.log("Number of chunks:", chunks.length); // Number of chunks: 893 ``` ### Create and Store Embeddings Finally, we'll prepare our content for RAG by: 1. Generating embeddings for each chunk of text 2. Creating a vector store index to hold our embeddings 3. Storing both the embeddings and metadata (original text and source information) in our vector database > **Note**: This metadata is crucial as it allows us to return the actual content when the vector store finds relevant matches. This allows our agent to efficiently search and retrieve relevant information. ```ts copy showLineNumbers{23} filename="src/store.ts" // Generate embeddings const { embeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: chunks.map((chunk) => chunk.text), }); // Get the vector store instance from Mastra const vectorStore = mastra.getVector("pgVector"); // Create an index for our paper chunks await vectorStore.createIndex({ indexName: "papers", dimension: 1536, }); // Store embeddings await vectorStore.upsert({ indexName: "papers", vectors: embeddings, metadata: chunks.map((chunk) => ({ text: chunk.text, source: "transformer-paper", })), }); ``` This will: 1. Load the paper from the URL 2. Split it into manageable chunks 3. Generate embeddings for each chunk 4. Store both the embeddings and text in our vector database To run the script and store the embeddings: ```bash npx bun src/store.ts ``` ### Test the Assistant Let's test our research assistant with different types of queries: ```ts filename="src/index.ts" showLineNumbers copy import { mastra } from "./mastra"; const agent = mastra.getAgent("researchAgent"); // Basic query about concepts const query1 = "What problems does sequence modeling face with neural networks?"; const response1 = await agent.generate(query1); console.log("\nQuery:", query1); console.log("Response:", response1.text); ``` Run the script: ```bash copy npx bun src/index.ts ``` You should see output like: ``` Query: What problems does sequence modeling face with neural networks? Response: Sequence modeling with neural networks faces several key challenges: 1. Vanishing and exploding gradients during training, especially with long sequences 2. Difficulty handling long-term dependencies in the input 3. Limited computational efficiency due to sequential processing 4. Challenges in parallelizing computations, resulting in longer training times ``` Let's try another question: ```ts filename="src/index.ts" showLineNumbers{10} copy // Query about specific findings const query2 = "What improvements were achieved in translation quality?"; const response2 = await agent.generate(query2); console.log("\nQuery:", query2); console.log("Response:", response2.text); ``` Output: ``` Query: What improvements were achieved in translation quality? Response: The model showed significant improvements in translation quality, achieving more than 2.0 BLEU points improvement over previously reported models on the WMT 2014 English-to-German translation task, while also reducing training costs. ``` ### Serve the Application Start the Mastra server to expose your research assistant via API: ```bash mastra dev ``` Your research assistant will be available at: ``` http://localhost:4111/api/agents/researchAgent/generate ``` Test with curl: ```bash curl -X POST http://localhost:4111/api/agents/researchAgent/generate \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "role": "user", "content": "What were the main findings about model parallelization?" } ] }' ``` ## Advanced RAG Examples Explore these examples for more advanced RAG techniques: - [Filter RAG](/examples/rag/usage/filter-rag) for filtering results using metadata - [Cleanup RAG](/examples/rag/usage/cleanup-rag) for optimizing information density - [Chain of Thought RAG](/examples/rag/usage/cot-rag) for complex reasoning queries using workflows - [Rerank RAG](/examples/rag/usage/rerank-rag) for improved result relevance --- title: "Building an AI Stock Agent | Mastra Agents | Guides" description: Guide on creating a simple stock agent in Mastra to fetch the last day's closing stock price for a given symbol. --- import { Steps } from "nextra/components"; import YouTube from "@/components/youtube"; # Stock Agent [EN] Source: https://mastra.ai/en/guides/guide/stock-agent We're going to create a simple agent that fetches the last day's closing stock price for a given symbol. This example will show you how to create a tool, add it to an agent, and use the agent to fetch stock prices. ## Project Structure ``` stock-price-agent/ ├── src/ │ ├── agents/ │ │ └── stockAgent.ts │ ├── tools/ │ │ └── stockPrices.ts │ └── index.ts ├── package.json └── .env ``` --- ## Initialize the Project and Install Dependencies First, create a new directory for your project and navigate into it: ```bash mkdir stock-price-agent cd stock-price-agent ``` Initialize a new Node.js project and install the required dependencies: ```bash copy npm init -y npm install @mastra/core@latest zod @ai-sdk/openai ``` Set Up Environment Variables Create a `.env` file at the root of your project to store your OpenAI API key. ```bash filename=".env" copy OPENAI_API_KEY=your_openai_api_key ``` Create the necessary directories and files: ```bash mkdir -p src/agents src/tools touch src/agents/stockAgent.ts src/tools/stockPrices.ts src/index.ts ``` --- ## Create the Stock Price Tool Next, we'll create a tool that fetches the last day's closing stock price for a given symbol. ```ts filename="src/tools/stockPrices.ts" import { createTool } from "@mastra/core/tools"; import { z } from "zod"; const getStockPrice = async (symbol: string) => { const data = await fetch( `https://mastra-stock-data.vercel.app/api/stock-data?symbol=${symbol}`, ).then((r) => r.json()); return data.prices["4. close"]; }; export const stockPrices = createTool({ id: "Get Stock Price", inputSchema: z.object({ symbol: z.string(), }), description: `Fetches the last day's closing stock price for a given symbol`, execute: async ({ context: { symbol } }) => { console.log("Using tool to fetch stock price for", symbol); return { symbol, currentPrice: await getStockPrice(symbol), }; }, }); ``` --- ## Add the Tool to an Agent We'll create an agent and add the `stockPrices` tool to it. ```ts filename="src/agents/stockAgent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import * as tools from "../tools/stockPrices"; export const stockAgent = new Agent({ name: "Stock Agent", instructions: "You are a helpful assistant that provides current stock prices. When asked about a stock, use the stock price tool to fetch the stock price.", model: openai("gpt-4o-mini"), tools: { stockPrices: tools.stockPrices, }, }); ``` --- ## Set Up the Mastra Instance We need to initialize the Mastra instance with our agent and tool. ```ts filename="src/index.ts" import { Mastra } from "@mastra/core"; import { stockAgent } from "./agents/stockAgent"; export const mastra = new Mastra({ agents: { stockAgent }, }); ``` ## Serve the Application Instead of running the application directly, we'll use the `mastra dev` command to start the server. This will expose your agent via REST API endpoints, allowing you to interact with it over HTTP. In your terminal, start the Mastra server by running: ```bash mastra dev --dir src ``` This command will allow you to test your stockPrices tool and your stockAgent within the playground. This will also start the server and make your agent available at: ``` http://localhost:4111/api/agents/stockAgent/generate ``` --- ## Test the Agent with cURL Now that your server is running, you can test your agent's endpoint using `curl`: ```bash curl -X POST http://localhost:4111/api/agents/stockAgent/generate \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "role": "user", "content": "What is the current stock price of Apple (AAPL)?" } ] }' ``` **Expected Response:** You should receive a JSON response similar to: ```json { "text": "The current price of Apple (AAPL) is $174.55.", "agent": "Stock Agent" } ``` This indicates that your agent successfully processed the request, used the `stockPrices` tool to fetch the stock price, and returned the result. --- title: "Overview" description: "Guides on building with Mastra" --- # Guides [EN] Source: https://mastra.ai/en/guides While examples show quick implementations and docs explain specific features, these guides are a bit longer and designed to demonstrate core Mastra concepts: ## [AI Recruiter](/guides/guide/ai-recruiter) Create a workflow that processes candidate resumes and conducts interviews, demonstrating branching logic and LLM integration in Mastra workflows. ## [Chef Assistant](/guides/guide/chef-michel) Build an AI chef agent that helps users cook meals with available ingredients, showing how to create interactive agents with custom tools. ## [Research Paper Assistant](/guides/guide/research-assistant) Develop an AI research assistant that analyzes academic papers using Retrieval Augmented Generation (RAG), demonstrating document processing and question answering. ## [Stock Agent](/guides/guide/stock-agent) Implement a simple agent that fetches stock prices, illustrating the basics of creating tools and integrating them with Mastra agents. --- title: "Reference: Agent | Agents | Mastra Docs" description: "Documentation for the Agent class in Mastra, which provides the foundation for creating AI agents with various capabilities." --- # Agent [EN] Source: https://mastra.ai/en/reference/agents/agent The `Agent` class is the foundation for creating AI agents in Mastra. It provides methods for generating responses, streaming interactions, and handling voice capabilities. ## Importing ```typescript import { Agent } from "@mastra/core/agent"; ``` ## Constructor Creates a new Agent instance with the specified configuration. ```typescript constructor(config: AgentConfig) ``` ### Parameters
string | Promise", isOptional: false, description: "Instructions that guide the agent's behavior. Can be a static string or a function that returns a string.", }, { name: "model", type: "MastraLanguageModel | ({ runtimeContext: RuntimeContext }) => MastraLanguageModel | Promise", isOptional: false, description: "The language model to use for generating responses. Can be a model instance or a function that returns a model.", }, { name: "tools", type: "ToolsInput | ({ runtimeContext: RuntimeContext }) => ToolsInput | Promise", isOptional: true, description: "Tools that the agent can use. Can be a static object or a function that returns tools.", }, { name: "defaultGenerateOptions", type: "AgentGenerateOptions", isOptional: true, description: "Default options to use when calling generate().", }, { name: "defaultStreamOptions", type: "AgentStreamOptions", isOptional: true, description: "Default options to use when calling stream().", }, { name: "workflows", type: "Record | ({ runtimeContext: RuntimeContext }) => Record | Promise>", isOptional: true, description: "Workflows that the agent can execute. Can be a static object or a function that returns workflows.", }, { name: "evals", type: "Record", isOptional: true, description: "Evaluation metrics for assessing agent performance.", }, { name: "memory", type: "MastraMemory", isOptional: true, description: "Memory system for the agent to store and retrieve information.", }, { name: "voice", type: "CompositeVoice", isOptional: true, description: "Voice capabilities for speech-to-text and text-to-speech functionality.", }, ]} /> --- title: "Reference: createTool() | Tools | Agents | Mastra Docs" description: Documentation for the createTool function in Mastra, which creates custom tools for agents and workflows. --- # `createTool()` [EN] Source: https://mastra.ai/en/reference/agents/createTool The `createTool()` function creates typed tools that can be executed by agents or workflows. Tools have built-in schema validation, execution context, and integration with the Mastra ecosystem. ## Overview Tools are a fundamental building block in Mastra that allow agents to interact with external systems, perform computations, and access data. Each tool has: - A unique identifier - A description that helps the AI understand when and how to use the tool - Optional input and output schemas for validation - An execution function that implements the tool's logic ## Example Usage ```ts filename="src/tools/stock-tools.ts" showLineNumbers copy import { createTool } from "@mastra/core/tools"; import { z } from "zod"; // Helper function to fetch stock data const getStockPrice = async (symbol: string) => { const response = await fetch( `https://mastra-stock-data.vercel.app/api/stock-data?symbol=${symbol}`, ); const data = await response.json(); return data.prices["4. close"]; }; // Create a tool to get stock prices export const stockPriceTool = createTool({ id: "getStockPrice", description: "Fetches the current stock price for a given ticker symbol", inputSchema: z.object({ symbol: z.string().describe("The stock ticker symbol (e.g., AAPL, MSFT)"), }), outputSchema: z.object({ symbol: z.string(), price: z.number(), currency: z.string(), timestamp: z.string(), }), execute: async ({ context }) => { const price = await getStockPrice(context.symbol); return { symbol: context.symbol, price: parseFloat(price), currency: "USD", timestamp: new Date().toISOString(), }; }, }); // Create a tool that uses the thread context export const threadInfoTool = createTool({ id: "getThreadInfo", description: "Returns information about the current conversation thread", inputSchema: z.object({ includeResource: z.boolean().optional().default(false), }), execute: async ({ context, threadId, resourceId }) => { return { threadId, resourceId: context.includeResource ? resourceId : undefined, timestamp: new Date().toISOString(), }; }, }); ``` ## API Reference ### Parameters `createTool()` accepts a single object with the following properties: Promise", required: false, description: "Async function that implements the tool's logic. Receives the execution context and optional configuration.", properties: [ { type: "ToolExecutionContext", parameters: [ { name: "context", type: "object", description: "The validated input data that matches the inputSchema", }, { name: "threadId", type: "string", isOptional: true, description: "Identifier for the conversation thread, if available", }, { name: "resourceId", type: "string", isOptional: true, description: "Identifier for the user or resource interacting with the tool", }, { name: "mastra", type: "Mastra", isOptional: true, description: "Reference to the Mastra instance, if available", }, ], }, { type: "ToolOptions", parameters: [ { name: "toolCallId", type: "string", description: "The ID of the tool call. You can use it e.g. when sending tool-call related information with stream data.", }, { name: "messages", type: "CoreMessage[]", description: "Messages that were sent to the language model to initiate the response that contained the tool call. The messages do not include the system prompt nor the assistant response that contained the tool call.", }, { name: "abortSignal", type: "AbortSignal", isOptional: true, description: "An optional abort signal that indicates that the overall operation should be aborted.", }, ], }, ], }, { name: "inputSchema", type: "ZodSchema", required: false, description: "Zod schema that defines and validates the tool's input parameters. If not provided, the tool will accept any input.", }, { name: "outputSchema", type: "ZodSchema", required: false, description: "Zod schema that defines and validates the tool's output. Helps ensure the tool returns data in the expected format.", }, ]} /> ### Returns ", description: "A Tool instance that can be used with agents, workflows, or directly executed.", properties: [ { type: "Tool", parameters: [ { name: "id", type: "string", description: "The tool's unique identifier", }, { name: "description", type: "string", description: "Description of the tool's functionality", }, { name: "inputSchema", type: "ZodSchema | undefined", description: "Schema for validating inputs", }, { name: "outputSchema", type: "ZodSchema | undefined", description: "Schema for validating outputs", }, { name: "execute", type: "Function", description: "The tool's execution function", }, ], }, ], }, ]} /> ## Type Safety The `createTool()` function provides full type safety through TypeScript generics: - Input types are inferred from the `inputSchema` - Output types are inferred from the `outputSchema` - The execution context is properly typed based on the input schema This ensures that your tools are type-safe throughout your application. ## Best Practices 1. **Descriptive IDs**: Use clear, action-oriented IDs like `getWeatherForecast` or `searchDatabase` 2. **Detailed Descriptions**: Provide comprehensive descriptions that explain when and how to use the tool 3. **Input Validation**: Use Zod schemas to validate inputs and provide helpful error messages 4. **Error Handling**: Implement proper error handling in your execute function 5. **Idempotency**: When possible, make your tools idempotent (same input always produces same output) 6. **Performance**: Keep tools lightweight and fast to execute --- title: "Reference: Agent.generate() | Agents | Mastra Docs" description: "Documentation for the `.generate()` method in Mastra agents, which produces text or structured responses." --- # Agent.generate() [EN] Source: https://mastra.ai/en/reference/agents/generate The `generate()` method is used to interact with an agent to produce text or structured responses. This method accepts `messages` and an optional `options` object as parameters. ## Parameters ### `messages` The `messages` parameter can be: - A single string - An array of strings - An array of message objects with `role` and `content` properties The message object structure: ```typescript interface Message { role: "system" | "user" | "assistant"; content: string; } ``` ### `options` (Optional) An optional object that can include configuration for output structure, memory management, tool usage, telemetry, and more. , title?: string }", isOptional: false, description: "The conversation thread, as a string ID or an object with an `id` and optional `metadata`." }] }, { parameters: [{ name: "resource", type: "string", isOptional: false, description: "Identifier for the user or resource associated with the thread." }] }, { parameters: [{ name: "options", type: "MemoryConfig", isOptional: true, description: "Configuration for memory behavior, like message history and semantic recall. See `MemoryConfig` below." }] } ] }, { name: "maxSteps", type: "number", isOptional: true, defaultValue: "5", description: "Maximum number of execution steps allowed.", }, { name: "maxRetries", type: "number", isOptional: true, defaultValue: "2", description: "Maximum number of retries. Set to 0 to disable retries.", }, { name: "memoryOptions", type: "MemoryConfig", isOptional: true, description: "**Deprecated.** Use `memory.options` instead. Configuration options for memory management. See MemoryConfig section below for details.", }, { name: "onStepFinish", type: "GenerateTextOnStepFinishCallback | never", isOptional: true, description: "Callback function called after each execution step. Receives step details as a JSON string. Unavailable for structured output", }, { name: "resourceId", type: "string", isOptional: true, description: "**Deprecated.** Use `memory.resource` instead. Identifier for the user or resource interacting with the agent. Must be provided if threadId is provided.", }, { name: "telemetry", type: "TelemetrySettings", isOptional: true, description: "Settings for telemetry collection during generation. See TelemetrySettings section below for details.", }, { name: "temperature", type: "number", isOptional: true, description: "Controls randomness in the model's output. Higher values (e.g., 0.8) make the output more random, lower values (e.g., 0.2) make it more focused and deterministic.", }, { name: "threadId", type: "string", isOptional: true, description: "**Deprecated.** Use `memory.thread` instead. Identifier for the conversation thread. Allows for maintaining context across multiple interactions. Must be provided if resourceId is provided.", }, { name: "toolChoice", type: "'auto' | 'none' | 'required' | { type: 'tool'; toolName: string }", isOptional: true, defaultValue: "'auto'", description: "Controls how the agent uses tools during generation.", }, { name: "toolsets", type: "ToolsetsInput", isOptional: true, description: "Additional toolsets to make available to the agent during generation.", }, { name: "clientTools", type: "ToolsInput", isOptional: true, description: "Tools that are executed on the 'client' side of the request. These tools do not have execute functions in the definition.", }, ]} /> #### MemoryConfig Configuration options for memory management: #### TelemetrySettings Settings for telemetry collection during generation: ", isOptional: true, description: "Additional information to include in the telemetry data. AttributeValue can be string, number, boolean, array of these types, or null.", }, { name: "tracer", type: "Tracer", isOptional: true, description: "A custom OpenTelemetry tracer instance to use for the telemetry data. See OpenTelemetry documentation for details.", }, ]} /> ## Returns The return value of the `generate()` method depends on the options provided, specifically the `output` option. ### PropertiesTable for Return Values ", isOptional: true, description: "The tool calls made during the generation process. Present in both text and object modes.", }, ]} /> #### ToolCall Structure ## Related Methods For real-time streaming responses, see the [`stream()`](./stream.mdx) method documentation. --- title: "Reference: getAgent() | Agent Config | Agents | Mastra Docs" description: API Reference for getAgent. --- # `getAgent()` [EN] Source: https://mastra.ai/en/reference/agents/getAgent Retrieve an agent based on the provided configuration ```ts showLineNumbers copy async function getAgent({ connectionId, agent, apis, logger, }: { connectionId: string; agent: Record; apis: Record; logger: any; }): Promise<(props: { prompt: string }) => Promise> { return async (props: { prompt: string }) => { return { message: "Hello, world!" }; }; } ``` ## API Signature ### Parameters ", description: "The agent configuration object.", }, { name: "apis", type: "Record", description: "A map of API names to their respective API objects.", }, ]} /> ### Returns --- title: "Reference: Agent.getInstructions() | Agents | Mastra Docs" description: "Documentation for the `.getInstructions()` method in Mastra agents, which retrieves the instructions that guide the agent's behavior." --- # Agent.getInstructions() [EN] Source: https://mastra.ai/en/reference/agents/getInstructions The `getInstructions()` method retrieves the instructions configured for an agent, resolving them if they're a function. These instructions guide the agent's behavior and define its capabilities and constraints. ## Syntax ```typescript getInstructions({ runtimeContext }: { runtimeContext?: RuntimeContext } = {}): string | Promise ``` ## Parameters
## Return Value Returns a string or a Promise that resolves to a string containing the agent's instructions. ## Description The `getInstructions()` method is used to access the instructions that guide an agent's behavior. It resolves the instructions, which can be either directly provided as a string or returned from a function. Instructions are a critical component of an agent's configuration as they define: - The agent's role and personality - Task-specific guidance - Constraints on the agent's behavior - Context for handling user requests ## Examples ### Basic Usage ```typescript import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // Create an agent with static instructions const agent = new Agent({ name: "assistant", instructions: "You are a helpful assistant that provides concise and accurate information.", model: openai("gpt-4o"), }); // Get the instructions const instructions = await agent.getInstructions(); console.log(instructions); // "You are a helpful assistant that provides concise and accurate information." ``` ### Using with RuntimeContext ```typescript import { Agent } from "@mastra/core/agent"; import { RuntimeContext } from "@mastra/core/runtime-context"; import { openai } from "@ai-sdk/openai"; // Create an agent with dynamic instructions const agent = new Agent({ name: "contextual-assistant", instructions: ({ runtimeContext }) => { // Dynamic instructions based on runtime context const userPreference = runtimeContext.get("userPreference"); const expertise = runtimeContext.get("expertise") || "general"; if (userPreference === "technical") { return `You are a technical assistant specializing in ${expertise}. Provide detailed technical explanations.`; } return `You are a helpful assistant providing easy-to-understand information about ${expertise}.`; }, model: openai("gpt-4o"), }); // Create a runtime context with user preferences const context = new RuntimeContext(); context.set("userPreference", "technical"); context.set("expertise", "machine learning"); // Get the instructions using the runtime context const instructions = await agent.getInstructions({ runtimeContext: context }); console.log(instructions); // "You are a technical assistant specializing in machine learning. Provide detailed technical explanations." ``` --- title: "Reference: Agent.getMemory() | Agents | Mastra Docs" description: "Documentation for the `.getMemory()` method in Mastra agents, which retrieves the memory system associated with the agent." --- # Agent.getMemory() [EN] Source: https://mastra.ai/en/reference/agents/getMemory The `getMemory()` method retrieves the memory system associated with an agent. This method is used to access the agent's memory capabilities for storing and retrieving information across conversations. ## Syntax ```typescript getMemory(): MastraMemory | undefined ``` ## Parameters This method does not take any parameters. ## Return Value Returns a `MastraMemory` instance if a memory system is configured for the agent, or `undefined` if no memory system is configured. ## Description The `getMemory()` method is used to access the memory system associated with an agent. Memory systems allow agents to: - Store and retrieve information across multiple interactions - Maintain conversation history - Remember user preferences and context - Provide personalized responses based on past interactions This method is often used in conjunction with `hasOwnMemory()` to check if an agent has a memory system before attempting to use it. ## Examples ### Basic Usage ```typescript import { Agent } from "@mastra/core/agent"; import { Memory } from "@mastra/memory"; import { openai } from "@ai-sdk/openai"; // Create a memory system const memory = new Memory(); // Create an agent with memory const agent = new Agent({ name: "memory-assistant", instructions: "You are a helpful assistant that remembers previous conversations.", model: openai("gpt-4o"), memory, }); // Get the memory system const agentMemory = agent.getMemory(); if (agentMemory) { // Use the memory system to retrieve thread messages const thread = await agentMemory.getThreadById({ resourceId: "user-123", threadId: "conversation-1", }); console.log("Retrieved thread:", thread); } ``` ### Checking for Memory Before Using ```typescript import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // Create an agent without memory const agent = new Agent({ name: "stateless-assistant", instructions: "You are a helpful assistant.", model: openai("gpt-4o"), }); // Check if the agent has memory before using it if (agent.hasOwnMemory()) { const memory = agent.getMemory(); // Use memory... } else { console.log("This agent does not have a memory system."); } ``` ### Using Memory in a Conversation ```typescript import { Agent } from "@mastra/core/agent"; import { Memory } from "@mastra/memory"; import { openai } from "@ai-sdk/openai"; // Create a memory system const memory = new Memory(); // Create an agent with memory const agent = new Agent({ name: "memory-assistant", instructions: "You are a helpful assistant that remembers previous conversations.", model: openai("gpt-4o"), memory, }); // First interaction - store information await agent.generate("My name is Alice.", { resourceId: "user-123", threadId: "conversation-1", }); // Later interaction - retrieve information const result = await agent.generate("What's my name?", { resourceId: "user-123", threadId: "conversation-1", }); console.log(result.text); // Should mention "Alice" // Access the memory system directly const agentMemory = agent.getMemory(); if (agentMemory) { // Retrieve messages from the thread const { messages } = await agentMemory.query({ resourceId: "user-123", threadId: "conversation-1", selectBy: { last: 10, // Get the last 10 messages }, }); console.log("Retrieved messages:", messages); } ``` --- title: "Reference: Agent.getModel() | Agents | Mastra Docs" description: "Documentation for the `.getModel()` method in Mastra agents, which retrieves the language model that powers the agent." --- # Agent.getModel() [EN] Source: https://mastra.ai/en/reference/agents/getModel The `getModel()` method retrieves the language model configured for an agent, resolving it if it's a function. This method is used to access the underlying model that powers the agent's capabilities. ## Syntax ```typescript getModel({ runtimeContext = new RuntimeContext() }: { runtimeContext?: RuntimeContext } = {}): MastraLanguageModel | Promise ``` ## Parameters
## Return Value Returns a `MastraLanguageModel` instance or a Promise that resolves to a `MastraLanguageModel` instance. ## Description The `getModel()` method is used to access the language model that powers an agent. It resolves the model, which can be either directly provided or returned from a function. The language model is a crucial component of an agent as it determines: - The quality and capabilities of the agent's responses - The available features (like function calling, structured output, etc.) - The cost and performance characteristics of the agent ## Examples ### Basic Usage ```typescript import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // Create an agent with a static model const agent = new Agent({ name: "assistant", instructions: "You are a helpful assistant.", model: openai("gpt-4o"), }); // Get the model const model = await agent.getModel(); console.log(model.id); // "gpt-4o" ``` ### Using with RuntimeContext ```typescript import { Agent } from "@mastra/core/agent"; import { RuntimeContext } from "@mastra/core/runtime-context"; import { openai } from "@ai-sdk/openai"; import { anthropic } from "@ai-sdk/anthropic"; // Create an agent with dynamic model selection const agent = new Agent({ name: "dynamic-model-assistant", instructions: "You are a helpful assistant.", model: ({ runtimeContext }) => { // Dynamic model selection based on runtime context const preferredProvider = runtimeContext.get("preferredProvider"); const highQuality = runtimeContext.get("highQuality") === true; if (preferredProvider === "anthropic") { return highQuality ? anthropic("claude-3-opus") : anthropic("claude-3-sonnet"); } // Default to OpenAI return highQuality ? openai("gpt-4o") : openai("gpt-3.5-turbo"); }, }); // Create a runtime context with preferences const context = new RuntimeContext(); context.set("preferredProvider", "anthropic"); context.set("highQuality", true); // Get the model using the runtime context const model = await agent.getModel({ runtimeContext: context }); console.log(model.id); // "claude-3-opus" ``` --- title: "Reference: Agent.getTools() | Agents | Mastra Docs" description: "Documentation for the `.getTools()` method in Mastra agents, which retrieves the tools that the agent can use." --- # Agent.getTools() [EN] Source: https://mastra.ai/en/reference/agents/getTools The `getTools()` method retrieves the tools configured for an agent, resolving them if they're a function. These tools extend the agent's capabilities, allowing it to perform specific actions or access external systems. ## Syntax ```typescript getTools({ runtimeContext = new RuntimeContext() }: { runtimeContext?: RuntimeContext } = {}): ToolsInput | Promise ``` ## Parameters
## Return Value Returns a `ToolsInput` object or a Promise that resolves to a `ToolsInput` object containing the agent's tools. ## Description The `getTools()` method is used to access the tools that an agent can use. It resolves the tools, which can be either directly provided as an object or returned from a function. Tools are a key component of an agent's capabilities, allowing it to: - Perform specific actions (like fetching data or making calculations) - Access external systems and APIs - Execute code or commands - Interact with databases or other services ## Examples ### Basic Usage ```typescript import { Agent } from "@mastra/core/agent"; import { createTool } from "@mastra/core/tools"; import { openai } from "@ai-sdk/openai"; import { z } from "zod"; // Create tools using createTool const addTool = createTool({ id: "add", description: "Add two numbers", inputSchema: z.object({ a: z.number().describe("First number"), b: z.number().describe("Second number"), }), outputSchema: z.number(), execute: async ({ context }) => { return context.a + context.b; }, }); const multiplyTool = createTool({ id: "multiply", description: "Multiply two numbers", inputSchema: z.object({ a: z.number().describe("First number"), b: z.number().describe("Second number"), }), outputSchema: z.number(), execute: async ({ context }) => { return context.a * context.b; }, }); // Create an agent with the tools const agent = new Agent({ name: "calculator", instructions: "You are a calculator assistant that can perform mathematical operations.", model: openai("gpt-4o"), tools: { add: addTool, multiply: multiplyTool, }, }); // Get the tools const tools = await agent.getTools(); console.log(Object.keys(tools)); // ["add", "multiply"] ``` ### Using with RuntimeContext ```typescript import { Agent } from "@mastra/core/agent"; import { createTool } from "@mastra/core/tools"; import { RuntimeContext } from "@mastra/core/runtime-context"; import { openai } from "@ai-sdk/openai"; import { z } from "zod"; // Create an agent with dynamic tools const agent = new Agent({ name: "weather-assistant", instructions: "You are a weather assistant that can provide weather information.", model: openai("gpt-4o"), tools: ({ runtimeContext }) => { // Get API key from runtime context const apiKey = runtimeContext.get("weatherApiKey"); // Create a weather tool with the API key from context const weatherTool = createTool({ id: "getWeather", description: "Get the current weather for a location", inputSchema: z.object({ location: z.string().describe("City name"), }), outputSchema: z.object({ temperature: z.number(), conditions: z.string(), humidity: z.number(), windSpeed: z.number(), }), execute: async ({ context }) => { // Use the API key from runtime context const response = await fetch( `https://api.weather.com/current?location=${context.location}&apiKey=${apiKey}`, ); return response.json(); }, }); return { getWeather: weatherTool, }; }, }); // Create a runtime context with API key const context = new RuntimeContext(); context.set("weatherApiKey", "your-api-key"); // Get the tools using the runtime context const tools = await agent.getTools({ runtimeContext: context }); console.log(Object.keys(tools)); // ["getWeather"] ``` --- title: "Reference: Agent.getVoice() | Agents | Mastra Docs" description: "Documentation for the `.getVoice()` method in Mastra agents, which retrieves the voice provider for speech capabilities." --- # Agent.getVoice() [EN] Source: https://mastra.ai/en/reference/agents/getVoice The `getVoice()` method retrieves the voice provider configured for an agent, resolving it if it's a function. This method is used to access the agent's speech capabilities for text-to-speech and speech-to-text functionality. ## Syntax ```typescript getVoice({ runtimeContext }: { runtimeContext?: RuntimeContext } = {}): CompositeVoice | Promise ``` ## Parameters
## Return Value Returns a `CompositeVoice` instance or a Promise that resolves to a `CompositeVoice` instance. If no voice provider was configured for the agent, it returns a default voice provider. ## Description The `getVoice()` method is used to access the voice capabilities of an agent. It resolves the voice provider, which can be either directly provided or returned from a function. The voice provider enables: - Text-to-speech conversion (speaking) - Speech-to-text conversion (listening) - Retrieving available speakers/voices ## Examples ### Basic Usage ```typescript import { Agent } from "@mastra/core/agent"; import { ElevenLabsVoice } from "@mastra/voice-elevenlabs"; import { openai } from "@ai-sdk/openai"; // Create an agent with a voice provider const agent = new Agent({ name: "voice-assistant", instructions: "You are a helpful voice assistant.", model: openai("gpt-4o"), voice: new ElevenLabsVoice({ apiKey: process.env.ELEVENLABS_API_KEY, }), }); // Get the voice provider const voice = await agent.getVoice(); // Use the voice provider for text-to-speech const audioStream = await voice.speak("Hello, how can I help you today?"); // Use the voice provider for speech-to-text const transcription = await voice.listen(audioStream); // Get available speakers const speakers = await voice.getSpeakers(); console.log(speakers); ``` ### Using with RuntimeContext ```typescript import { Agent } from "@mastra/core/agent"; import { ElevenLabsVoice } from "@mastra/voice-elevenlabs"; import { RuntimeContext } from "@mastra/core/runtime-context"; import { openai } from "@ai-sdk/openai"; // Create an agent with a dynamic voice provider const agent = new Agent({ name: "voice-assistant", instructions: ({ runtimeContext }) => { // Dynamic instructions based on runtime context const instructions = runtimeContext.get("preferredVoiceInstructions"); return instructions || "You are a helpful voice assistant."; }, model: openai("gpt-4o"), voice: new ElevenLabsVoice({ apiKey: process.env.ELEVENLABS_API_KEY, }), }); // Create a runtime context with preferences const context = new RuntimeContext(); context.set("preferredVoiceInstructions", "You are an evil voice assistant"); // Get the voice provider using the runtime context const voice = await agent.getVoice({ runtimeContext: context }); // Use the voice provider const audioStream = await voice.speak("Hello, how can I help you today?"); ``` --- title: "Reference: Agent.getWorkflows() | Agents | Mastra Docs" description: "Documentation for the `.getWorkflows()` method in Mastra agents, which retrieves the workflows that the agent can execute." --- # Agent.getWorkflows() [EN] Source: https://mastra.ai/en/reference/agents/getWorkflows The `getWorkflows()` method retrieves the workflows configured for an agent, resolving them if they're a function. These workflows enable the agent to execute complex, multi-step processes with defined execution paths. ## Syntax ```typescript getWorkflows({ runtimeContext = new RuntimeContext() }: { runtimeContext?: RuntimeContext } = {}): Record | Promise> ``` ## Parameters
## Return Value Returns a `Record` object or a Promise that resolves to a `Record` object containing the agent's workflows. ## Description The `getWorkflows()` method is used to access the workflows that an agent can execute. It resolves the workflows, which can be either directly provided as an object or returned from a function that receives runtime context. ## Examples ```typescript import { Agent } from "@mastra/core/agent"; import { createWorkflow, createStep } from "@mastra/core/workflows"; import { openai } from "@ai-sdk/openai"; import { z } from "zod"; const generateSuggestionsStep = createStep({ id: "generate-suggestions", inputSchema: z.object({ topic: z.string().describe("The topic to research"), }), outputSchema: z.object({ summary: z.string(), }), execute: async ({ inputData, mastra }) => { const researchAgent = mastra?.getAgent("researchAgent"); if (!researchAgent) { throw new Error("Research agent is not initialized"); } const { topic } = inputData; const result = await researchAgent.generate([ { role: "assistant", content: topic }, ]); return { summary: result.text }; }, }); const researchWorkflow = createWorkflow({ id: "research-workflow", inputSchema: z.object({ topic: z.string().describe("The topic to research"), }), outputSchema: z.object({ summary: z.string(), }), }); researchWorkflow.then(generateSuggestionsStep).commit(); // Create an agent with the workflow const agent = new Agent({ name: "research-organizer", instructions: "You are a research organizer that can delegate tasks to gather information and create summaries.", model: openai("gpt-4o"), workflows: { research: researchWorkflow, }, }); // Get the workflows const workflows = await agent.getWorkflows(); console.log(Object.keys(workflows)); // ["research"] ``` --- title: "Reference: Agent.stream() | Streaming | Agents | Mastra Docs" description: Documentation for the `.stream()` method in Mastra agents, which enables real-time streaming of responses. --- # `stream()` [EN] Source: https://mastra.ai/en/reference/agents/stream The `stream()` method enables real-time streaming of responses from an agent. This method accepts `messages` and an optional `options` object as parameters, similar to `generate()`. ## Parameters ### `messages` The `messages` parameter can be: - A single string - An array of strings - An array of message objects with `role` and `content` properties The message object structure: ```typescript interface Message { role: "system" | "user" | "assistant"; content: string; } ``` ### `options` (Optional) An optional object that can include configuration for output structure, memory management, tool usage, telemetry, and more. , title?: string }", isOptional: false, description: "The conversation thread, as a string ID or an object with an `id` and optional `metadata`." }] }, { parameters: [{ name: "resource", type: "string", isOptional: false, description: "Identifier for the user or resource associated with the thread." }] }, { parameters: [{ name: "options", type: "MemoryConfig", isOptional: true, description: "Configuration for memory behavior, like message history and semantic recall. See `MemoryConfig` below." }] } ] }, { name: "maxSteps", type: "number", isOptional: true, defaultValue: "5", description: "Maximum number of steps allowed during streaming.", }, { name: "maxRetries", type: "number", isOptional: true, defaultValue: "2", description: "Maximum number of retries. Set to 0 to disable retries.", }, { name: "memoryOptions", type: "MemoryConfig", isOptional: true, description: "**Deprecated.** Use `memory.options` instead. Configuration options for memory management. See MemoryConfig section below for details.", }, { name: "onFinish", type: "StreamTextOnFinishCallback | StreamObjectOnFinishCallback", isOptional: true, description: "Callback function called when streaming is complete.", }, { name: "onStepFinish", type: "GenerateTextOnStepFinishCallback | never", isOptional: true, description: "Callback function called after each step during streaming. Unavailable for structured output", }, { name: "output", type: "Zod schema | JsonSchema7", isOptional: true, description: "Defines the expected structure of the output. Can be a JSON Schema object or a Zod schema.", }, { name: "resourceId", type: "string", isOptional: true, description: "**Deprecated.** Use `memory.resource` instead. Identifier for the user or resource interacting with the agent. Must be provided if threadId is provided.", }, { name: "telemetry", type: "TelemetrySettings", isOptional: true, description: "Settings for telemetry collection during streaming. See TelemetrySettings section below for details.", }, { name: "temperature", type: "number", isOptional: true, description: "Controls randomness in the model's output. Higher values (e.g., 0.8) make the output more random, lower values (e.g., 0.2) make it more focused and deterministic.", }, { name: "threadId", type: "string", isOptional: true, description: "**Deprecated.** Use `memory.thread` instead. Identifier for the conversation thread. Allows for maintaining context across multiple interactions. Must be provided if resourceId is provided.", }, { name: "toolChoice", type: "'auto' | 'none' | 'required' | { type: 'tool'; toolName: string }", isOptional: true, defaultValue: "'auto'", description: "Controls how the agent uses tools during streaming.", }, { name: "toolsets", type: "ToolsetsInput", isOptional: true, description: "Additional toolsets to make available to the agent during this stream.", }, { name: "clientTools", type: "ToolsInput", isOptional: true, description: "Tools that are executed on the 'client' side of the request. These tools do not have execute functions in the definition.", }, ]} /> #### MemoryConfig Configuration options for memory management: #### TelemetrySettings Settings for telemetry collection during streaming: ", isOptional: true, description: "Additional information to include in the telemetry data. AttributeValue can be string, number, boolean, array of these types, or null.", }, { name: "tracer", type: "Tracer", isOptional: true, description: "A custom OpenTelemetry tracer instance to use for the telemetry data. See OpenTelemetry documentation for details.", }, ]} /> ## Returns The return value of the `stream()` method depends on the options provided, specifically the `output` option. ### PropertiesTable for Return Values ", isOptional: true, description: "Stream of text chunks. Present when output is 'text' (no schema provided) or when using `experimental_output`.", }, { name: "objectStream", type: "AsyncIterable", isOptional: true, description: "Stream of structured data. Present only when using `output` option with a schema.", }, { name: "partialObjectStream", type: "AsyncIterable", isOptional: true, description: "Stream of structured data. Present only when using `experimental_output` option.", }, { name: "object", type: "Promise", isOptional: true, description: "Promise that resolves to the final structured output. Present when using either `output` or `experimental_output` options.", }, ]} /> ## Examples ### Basic Text Streaming ```typescript const stream = await myAgent.stream([ { role: "user", content: "Tell me a story." }, ]); for await (const chunk of stream.textStream) { process.stdout.write(chunk); } ``` ### Structured Output Streaming with Thread Context ```typescript const schema = { type: "object", properties: { summary: { type: "string" }, nextSteps: { type: "array", items: { type: "string" } }, }, required: ["summary", "nextSteps"], }; const response = await myAgent.stream("What should we do next?", { output: schema, threadId: "project-123", onFinish: (text) => console.log("Finished:", text), }); for await (const chunk of response.textStream) { console.log(chunk); } const result = await response.object; console.log("Final structured result:", result); ``` The key difference between Agent's `stream()` and LLM's `stream()` is that Agents maintain conversation context through `threadId`, can access tools, and integrate with the agent's memory system. --- title: "mastra build | Production Bundle | Mastra CLI" description: "Build your Mastra project for production deployment" --- # mastra build [EN] Source: https://mastra.ai/en/reference/cli/build The `mastra build` command bundles your Mastra project into a production-ready Hono server. Hono is a lightweight, type-safe web framework that makes it easy to deploy Mastra agents as HTTP endpoints with middleware support. ## Usage ```bash mastra build [options] ``` ## Options ## Advanced usage ### Limit parallelism For CI or when running in resource constrained environments you can cap how many expensive tasks run at once by setting `MASTRA_CONCURRENCY`. ```bash copy MASTRA_CONCURRENCY=2 mastra build ``` Unset it to allow the CLI to base concurrency on the host capabilities. ### Disable telemetry To opt out of anonymous build analytics set: ```bash copy MASTRA_TELEMETRY_DISABLED=1 mastra build ``` ### Custom provider endpoints Build time respects the same `OPENAI_BASE_URL` and `ANTHROPIC_BASE_URL` variables that `mastra dev` does. They are forwarded by the AI SDK to any workflows or tools that call the providers. ## What It Does 1. Locates your Mastra entry file (either `src/mastra/index.ts` or `src/mastra/index.js`) 2. Creates a `.mastra` output directory 3. Bundles your code using Rollup with: - Tree shaking for optimal bundle size - Node.js environment targeting - Source map generation for debugging ## Example ```bash copy # Build from current directory mastra build # Build from specific directory mastra build --dir ./my-mastra-project ``` ## Output The command generates a production bundle in the `.mastra` directory, which includes: - A Hono-based HTTP server with your Mastra agents exposed as endpoints - Bundled JavaScript files optimized for production - Source maps for debugging - Required dependencies This output is suitable for: - Deploying to cloud servers (EC2, Digital Ocean) - Running in containerized environments - Using with container orchestration systems ## Deployers When a Deployer is used, the build output is automatically prepared for the target platform e.g - [Vercel Deployer](/reference/deployer/vercel) - [Netlify Deployer](/reference/deployer/netlify) - [Cloudflare Deployer](/reference/deployer/cloudflare) --- title: "create-mastra | Create Project | Mastra CLI" description: Documentation for the create-mastra command, which creates a new Mastra project with interactive setup options. --- # create-mastra [EN] Source: https://mastra.ai/en/reference/cli/create-mastra The `create-mastra` command **creates** a new standalone Mastra project. Use this command to scaffold a complete Mastra setup in a dedicated directory. ## Usage ```bash create-mastra [options] ``` ## Options --- title: "mastra dev | Development Server | Mastra CLI" description: Documentation for the mastra dev command, which starts a development server for agents, tools, and workflows. --- # mastra dev [EN] Source: https://mastra.ai/en/reference/cli/dev The `mastra dev` command starts a development server that exposes REST endpoints for your agents, tools, and workflows. ## Usage ```bash mastra dev [options] ``` ## Options ## Routes Starting the server with `mastra dev` exposes a set of REST routes by default: ### System Routes - **GET `/api`**: Get API status. ### Agent Routes Agents are expected to be exported from `src/mastra/agents`. - **GET `/api/agents`**: Lists the registered agents found in your Mastra folder. - **GET `/api/agents/:agentId`**: Get agent by ID. - **GET `/api/agents/:agentId/evals/ci`**: Get CI evals by agent ID. - **GET `/api/agents/:agentId/evals/live`**: Get live evals by agent ID. - **POST `/api/agents/:agentId/generate`**: Sends a text-based prompt to the specified agent, returning the agent's response. - **POST `/api/agents/:agentId/stream`**: Stream a response from an agent. - **POST `/api/agents/:agentId/instructions`**: Update an agent's instructions. - **POST `/api/agents/:agentId/instructions/enhance`**: Generate an improved system prompt from instructions. - **GET `/api/agents/:agentId/speakers`**: Get available speakers for an agent. - **POST `/api/agents/:agentId/speak`**: Convert text to speech using the agent's voice provider. - **POST `/api/agents/:agentId/listen`**: Convert speech to text using the agent's voice provider. - **POST `/api/agents/:agentId/tools/:toolId/execute`**: Execute a tool through an agent. ### Tool Routes Tools are expected to be exported from `src/mastra/tools` (or the configured tools directory). - **GET `/api/tools`**: Get all tools. - **GET `/api/tools/:toolId`**: Get tool by ID. - **POST `/api/tools/:toolId/execute`**: Invokes a specific tool by name, passing input data in the request body. ### Workflow Routes Workflows are expected to be exported from `src/mastra/workflows` (or the configured workflows directory). - **GET `/api/workflows`**: Get all workflows. - **GET `/api/workflows/:workflowId`**: Get workflow by ID. - **POST `/api/workflows/:workflowName/start`**: Starts the specified workflow. - **POST `/api/workflows/:workflowName/:instanceId/event`**: Sends an event or trigger signal to an existing workflow instance. - **GET `/api/workflows/:workflowName/:instanceId/status`**: Returns status info for a running workflow instance. - **POST `/api/workflows/:workflowId/resume`**: Resume a suspended workflow step. - **POST `/api/workflows/:workflowId/resume-async`**: Resume a suspended workflow step asynchronously. - **POST `/api/workflows/:workflowId/createRun`**: Create a new workflow run. - **POST `/api/workflows/:workflowId/start-async`**: Execute/Start a workflow asynchronously. - **GET `/api/workflows/:workflowId/watch`**: Watch workflow transitions in real-time. ### Memory Routes - **GET `/api/memory/status`**: Get memory status. - **GET `/api/memory/threads`**: Get all threads. - **GET `/api/memory/threads/:threadId`**: Get thread by ID. - **GET `/api/memory/threads/:threadId/messages`**: Get messages for a thread. - **POST `/api/memory/threads`**: Create a new thread. - **PATCH `/api/memory/threads/:threadId`**: Update a thread. - **DELETE `/api/memory/threads/:threadId`**: Delete a thread. - **POST `/api/memory/save-messages`**: Save messages. ### Telemetry Routes - **GET `/api/telemetry`**: Get all traces. ### Log Routes - **GET `/api/logs`**: Get all logs. - **GET `/api/logs/transports`**: List of all log transports. - **GET `/api/logs/:runId`**: Get logs by run ID. ### Vector Routes - **POST `/api/vector/:vectorName/upsert`**: Upsert vectors into an index. - **POST `/api/vector/:vectorName/create-index`**: Create a new vector index. - **POST `/api/vector/:vectorName/query`**: Query vectors from an index. - **GET `/api/vector/:vectorName/indexes`**: List all indexes for a vector store. - **GET `/api/vector/:vectorName/indexes/:indexName`**: Get details about a specific index. - **DELETE `/api/vector/:vectorName/indexes/:indexName`**: Delete a specific index. ### OpenAPI Specification - **GET `/openapi.json`**: Returns an auto-generated OpenAPI specification for your project's routes. - **GET `/swagger-ui`**: Access Swagger UI for API documentation. ## Additional Notes The port defaults to 4111. Both the port and hostname can be configured via the mastra server config. See [Launch Development Server](/docs/local-dev/mastra-dev#launch-development-server) for configuration details. Make sure you have your environment variables set up in your `.env.development` or `.env` file for any providers you use (e.g., `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, etc.). Make sure the `index.ts` file in your Mastra folder exports the Mastra instance for the dev server to read. ### Example request To test an agent after running `mastra dev`: ```bash copy curl -X POST http://localhost:4111/api/agents/myAgent/generate \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "role": "user", "content": "Hello, how can you assist me today?" } ] }' ``` ## Advanced usage The `mastra dev` server obeys a few extra environment variables that can be handy during development: ### Disable build caching Set `MASTRA_DEV_NO_CACHE=1` to force a full rebuild rather than using the cached assets under `.mastra/`: ```bash copy MASTRA_DEV_NO_CACHE=1 mastra dev ``` This helps when you are debugging bundler plugins or suspect stale output. ### Limit parallelism `MASTRA_CONCURRENCY` caps how many expensive operations run in parallel (primarily build and evaluation steps). For example: ```bash copy MASTRA_CONCURRENCY=4 mastra dev ``` Leave it unset to let the CLI pick a sensible default for the machine. ### Custom provider endpoints When using providers supported by the Vercel AI SDK you can redirect requests through proxies or internal gateways by setting a base URL. For OpenAI: ```bash copy OPENAI_API_KEY= \ OPENAI_BASE_URL=https://openrouter.example/v1 \ mastra dev ``` and for Anthropic: ```bash copy OPENAI_API_KEY= \ ANTHROPIC_BASE_URL=https://anthropic.internal \ mastra dev ``` These are forwarded by the AI SDK and work with any `openai()` or `anthropic()` calls. ### Disable telemetry To opt out of anonymous CLI analytics set `MASTRA_TELEMETRY_DISABLED=1`. This also prevents tracking within the local playground. ```bash copy MASTRA_TELEMETRY_DISABLED=1 mastra dev ``` --- title: "mastra init | Initialize Project | Mastra CLI" description: Documentation for the mastra init command, which creates a new Mastra project with interactive setup options. --- # mastra init [EN] Source: https://mastra.ai/en/reference/cli/init The `mastra init` command **initializes** Mastra in an existing project. Use this command to scaffold the necessary folders and configuration without generating a new project. ## Usage ```bash mastra init [options] ``` ## Options ## Advanced usage ### Disable analytics If you prefer not to send anonymous usage data then set the `MASTRA_TELEMETRY_DISABLED=1` environment variable when running the command: ```bash copy MASTRA_TELEMETRY_DISABLED=1 mastra init ``` ### Custom provider endpoints Initialized projects respect the `OPENAI_BASE_URL` and `ANTHROPIC_BASE_URL` variables if present. This lets you route provider traffic through proxies or private gateways when starting the dev server later on. --- title: "mastra lint | Validate Project | Mastra CLI" description: "Lint your Mastra project" --- # mastra lint [EN] Source: https://mastra.ai/en/reference/cli/lint The `mastra lint` command validates the structure and code of your Mastra project to ensure it follows best practices and is error-free. ## Usage ```bash mastra lint [options] ``` ## Options ## Advanced usage ### Disable telemetry To disable CLI analytics while running linting (and other commands) set `MASTRA_TELEMETRY_DISABLED=1`: ```bash copy MASTRA_TELEMETRY_DISABLED=1 mastra lint ``` --- title: "@mastra/mcp-docs-server" description: "Serve Mastra docs, examples and blog posts over MCP" --- The `@mastra/mcp-docs-server` package runs a small [Model Context Protocol](https://github.com/modelcontextprotocol/mcp) server that makes Mastra documentation, code examples, blog posts and changelogs queryable by an LLM agent. It can be invoked manually from the command line or configured inside an MCP-aware IDE such as Cursor or Windsurf. ## Running from the CLI [EN] Source: https://mastra.ai/en/reference/cli/mcp-docs-server ```bash npx -y @mastra/mcp-docs-server ``` The command above runs a stdio based MCP server. The process will keep reading requests from `stdin` and returning responses on `stdout`. This is the same command that IDE integrations use. When run manually it can be pointed at the `@wong2/mcp-cli` package for exploration. ### Examples Rebuild the docs before serving (useful if you've modified docs locally): ```bash REBUILD_DOCS_ON_START=true npx -y @mastra/mcp-docs-server ``` Enable verbose logging while experimenting: ```bash DEBUG=1 npx -y @mastra/mcp-docs-server ``` Serve blog posts from a custom domain: ```bash BLOG_URL=https://my-blog.example npx -y @mastra/mcp-docs-server ``` ## Environment variables `@mastra/mcp-docs-server` honours a few environment variables that tweak its behaviour: - **`REBUILD_DOCS_ON_START`** - when set to `true` the server rebuilds the `.docs` directory before binding to stdio. This can be helpful after editing or adding documentation locally. - **`PREPARE`** - the docs build step (`pnpm mcp-docs-server prepare-docs`) looks for `PREPARE=true` to copy Markdown sources from the repository into `.docs`. - **`BLOG_URL`** - base URL used for fetching blog posts. Defaults to `https://mastra.ai`. - **`DEBUG`** or **`NODE_ENV=development`** - increase logging written to `stderr`. No other variables are required for a basic run; the server ships with a pre-built docs directory. ## Rebuilding with custom docs The package includes a precompiled copy of the documentation. If you want to experiment with additional content you can rebuild the `.docs` directory locally: ```bash pnpm mcp-docs-server prepare-docs ``` The script will copy documentation from `mastra/docs/src/content/en/docs` and `mastra/docs/src/content/en/reference` into the package. Once rebuilt, start the server with `REBUILD_DOCS_ON_START=true` so the fresh content is served. A rebuild is only necessary if you need to serve customised docs. For regular use you can rely on the published package contents. For IDE configuration details see the [Getting started guide](/docs/getting-started/mcp-docs-server). --- title: 'mastra start' description: 'Start your built Mastra application' --- # mastra start [EN] Source: https://mastra.ai/en/reference/cli/start Start your built Mastra application. This command is used to run your built Mastra application in production mode. Telemetry is enabled by default. ## Usage After building your project with `mastra build` run: ```bash mastra start [options] ``` ## Options | Option | Description | |--------|-------------| | `-d, --dir ` | Path to your built Mastra output directory (default: .mastra/output) | | `-nt, --no-telemetry` | Enable OpenTelemetry instrumentation for observability | ## Examples Start the application with default settings: ```bash mastra start ``` Start from a custom output directory: ```bash mastra start --dir ./my-output ``` Start with telemetry disabled: ```bash mastra start -nt ``` --- title: Mastra Client Agents API description: Learn how to interact with Mastra AI agents, including generating responses, streaming interactions, and managing agent tools using the client-js SDK. --- # Agents API [EN] Source: https://mastra.ai/en/reference/client-js/agents The Agents API provides methods to interact with Mastra AI agents, including generating responses, streaming interactions, and managing agent tools. ## Initialize Mastra Client ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient(); ``` ## Getting All Agents Retrieve a list of all available agents: ```typescript const agents = await client.getAgents(); ``` ## Working with a Specific Agent Get an instance of a specific agent: ```typescript const agent = client.getAgent("agent-id"); ``` ## Agent Methods ### Get Agent Details Retrieve detailed information about an agent: ```typescript const details = await agent.details(); ``` ### Generate Response Generate a response from the agent: ```typescript const response = await agent.generate({ messages: [ { role: "user", content: "Hello, how are you?", }, ], threadId: "thread-1", // Optional: Thread ID for conversation context resourceid: "resource-1", // Optional: Resource ID output: {}, // Optional: Output configuration }); ``` ### Stream Response Stream responses from the agent for real-time interactions: ```typescript const response = await agent.stream({ messages: [ { role: "user", content: "Tell me a story", }, ], }); // Process data stream with the processDataStream util response.processDataStream({ onTextPart: (text) => { process.stdout.write(text); }, onFilePart: (file) => { console.log(file); }, onDataPart: (data) => { console.log(data); }, onErrorPart: (error) => { console.error(error); }, }); // You can also read from response body directly const reader = response.body.getReader(); while (true) { const { done, value } = await reader.read(); if (done) break; console.log(new TextDecoder().decode(value)); } ``` ### Get Agent Tool Retrieve information about a specific tool available to the agent: ```typescript const tool = await agent.getTool("tool-id"); ``` ### Get Agent Evaluations Get evaluation results for the agent: ```typescript // Get CI evaluations const evals = await agent.evals(); // Get live evaluations const liveEvals = await agent.liveEvals(); ``` --- title: Mastra Client Error Handling description: Learn about the built-in retry mechanism and error handling capabilities in the Mastra client-js SDK. --- # Error Handling [EN] Source: https://mastra.ai/en/reference/client-js/error-handling The Mastra Client SDK includes built-in retry mechanism and error handling capabilities. ## Error Handling All API methods can throw errors that you can catch and handle: ```typescript try { const agent = client.getAgent("agent-id"); const response = await agent.generate({ messages: [{ role: "user", content: "Hello" }], }); } catch (error) { console.error("An error occurred:", error.message); } ``` ## Retry Mechanism The client automatically retries failed requests with exponential backoff: ```typescript const client = new MastraClient({ baseUrl: "http://localhost:4111", retries: 3, // Number of retry attempts backoffMs: 300, // Initial backoff time maxBackoffMs: 5000, // Maximum backoff time }); ``` ### How Retries Work 1. First attempt fails → Wait 300ms 2. Second attempt fails → Wait 600ms 3. Third attempt fails → Wait 1200ms 4. Final attempt fails → Throw error --- title: Mastra Client Logs API description: Learn how to access and query system logs and debugging information in Mastra using the client-js SDK. --- # Logs API [EN] Source: https://mastra.ai/en/reference/client-js/logs The Logs API provides methods to access and query system logs and debugging information in Mastra. ## Initialize Mastra Client ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient(); ``` ## Getting Logs Retrieve system logs with optional filtering: ```typescript const logs = await client.getLogs({ transportId: "transport-1", }); ``` ## Getting Logs for a Specific Run Retrieve logs for a specific execution run: ```typescript const runLogs = await client.getLogForRun({ runId: "run-1", transportId: "transport-1", }); ``` --- title: Mastra Client Memory API description: Learn how to manage conversation threads and message history in Mastra using the client-js SDK. --- # Memory API [EN] Source: https://mastra.ai/en/reference/client-js/memory The Memory API provides methods to manage conversation threads and message history in Mastra. ## Initialize Mastra Client ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient(); ``` ## Memory Thread Operations ### Get All Threads Retrieve all memory threads for a specific resource: ```typescript const threads = await client.getMemoryThreads({ resourceId: "resource-1", agentId: "agent-1", }); ``` ### Create a New Thread Create a new memory thread: ```typescript const thread = await client.createMemoryThread({ title: "New Conversation", metadata: { category: "support" }, resourceid: "resource-1", agentId: "agent-1", }); ``` ### Working with a Specific Thread Get an instance of a specific memory thread: ```typescript const thread = client.getMemoryThread("thread-id", "agent-id"); ``` ## Thread Methods ### Get Thread Details Retrieve details about a specific thread: ```typescript const details = await thread.get(); ``` ### Update Thread Update thread properties: ```typescript const updated = await thread.update({ title: "Updated Title", metadata: { status: "resolved" }, resourceid: "resource-1", }); ``` ### Delete Thread Delete a thread and its messages: ```typescript await thread.delete(); ``` ## Message Operations ### Save Messages Save messages to memory: ```typescript const savedMessages = await client.saveMessageToMemory({ messages: [ { role: "user", content: "Hello!", id: "1", threadId: "thread-1", createdAt: new Date(), type: "text", }, ], agentId: "agent-1", }); ``` ### Retrieve Thread Messages Get messages associated with a memory thread: ```typescript // Get all messages in the thread const { messages } = await thread.getMessages(); // Limit the number of messages retrieved const { messages } = await thread.getMessages({ limit: 10 }); ``` ### Get Memory Status Check the status of the memory system: ```typescript const status = await client.getMemoryStatus("agent-id"); ``` --- title: Mastra Client Telemetry API description: Learn how to retrieve and analyze traces from your Mastra application for monitoring and debugging using the client-js SDK. --- # Telemetry API [EN] Source: https://mastra.ai/en/reference/client-js/telemetry The Telemetry API provides methods to retrieve and analyze traces from your Mastra application. This helps you monitor and debug your application's behavior and performance. ## Initialize Mastra Client ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient(); ``` ## Getting Traces Retrieve traces with optional filtering and pagination: ```typescript const telemetry = await client.getTelemetry({ name: "trace-name", // Optional: Filter by trace name scope: "scope-name", // Optional: Filter by scope page: 1, // Optional: Page number for pagination perPage: 10, // Optional: Number of items per page attribute: { // Optional: Filter by custom attributes key: "value", }, }); ``` --- title: Mastra Client Tools API description: Learn how to interact with and execute tools available in the Mastra platform using the client-js SDK. --- # Tools API [EN] Source: https://mastra.ai/en/reference/client-js/tools The Tools API provides methods to interact with and execute tools available in the Mastra platform. ## Initialize Mastra Client ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient(); ``` ## Getting All Tools Retrieve a list of all available tools: ```typescript const tools = await client.getTools(); ``` ## Working with a Specific Tool Get an instance of a specific tool: ```typescript const tool = client.getTool("tool-id"); ``` ## Tool Methods ### Get Tool Details Retrieve detailed information about a tool: ```typescript const details = await tool.details(); ``` ### Execute Tool Execute a tool with specific arguments: ```typescript const result = await tool.execute({ args: { param1: "value1", param2: "value2", }, threadId: "thread-1", // Optional: Thread context resourceid: "resource-1", // Optional: Resource identifier }); ``` --- title: Mastra Client Vectors API description: Learn how to work with vector embeddings for semantic search and similarity matching in Mastra using the client-js SDK. --- # Vectors API [EN] Source: https://mastra.ai/en/reference/client-js/vectors The Vectors API provides methods to work with vector embeddings for semantic search and similarity matching in Mastra. ## Initialize Mastra Client ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient(); ``` ## Working with Vectors Get an instance of a vector store: ```typescript const vector = client.getVector("vector-name"); ``` ## Vector Methods ### Get Vector Index Details Retrieve information about a specific vector index: ```typescript const details = await vector.details("index-name"); ``` ### Create Vector Index Create a new vector index: ```typescript const result = await vector.createIndex({ indexName: "new-index", dimension: 128, metric: "cosine", // 'cosine', 'euclidean', or 'dotproduct' }); ``` ### Upsert Vectors Add or update vectors in an index: ```typescript const ids = await vector.upsert({ indexName: "my-index", vectors: [ [0.1, 0.2, 0.3], // First vector [0.4, 0.5, 0.6], // Second vector ], metadata: [{ label: "first" }, { label: "second" }], ids: ["id1", "id2"], // Optional: Custom IDs }); ``` ### Query Vectors Search for similar vectors: ```typescript const results = await vector.query({ indexName: "my-index", queryVector: [0.1, 0.2, 0.3], topK: 10, filter: { label: "first" }, // Optional: Metadata filter includeVector: true, // Optional: Include vectors in results }); ``` ### Get All Indexes List all available indexes: ```typescript const indexes = await vector.getIndexes(); ``` ### Delete Index Delete a vector index: ```typescript const result = await vector.delete("index-name"); ``` --- title: Mastra Client Workflows (Legacy) API description: Learn how to interact with and execute automated legacy workflows in Mastra using the client-js SDK. --- # Workflows (Legacy) API [EN] Source: https://mastra.ai/en/reference/client-js/workflows-legacy The Workflows (Legacy) API provides methods to interact with and execute automated legacy workflows in Mastra. ## Initialize Mastra Client ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient(); ``` ## Getting All Legacy Workflows Retrieve a list of all available legacy workflows: ```typescript const workflows = await client.getLegacyWorkflows(); ``` ## Working with a Specific Legacy Workflow Get an instance of a specific legacy workflow: ```typescript const workflow = client.getLegacyWorkflow("workflow-id"); ``` ## Legacy Workflow Methods ### Get Legacy Workflow Details Retrieve detailed information about a legacy workflow: ```typescript const details = await workflow.details(); ``` ### Start Legacy Workflow run asynchronously Start a legacy workflow run with triggerData and await full run results: ```typescript const { runId } = workflow.createRun(); const result = await workflow.startAsync({ runId, triggerData: { param1: "value1", param2: "value2", }, }); ``` ### Resume Legacy Workflow run asynchronously Resume a suspended legacy workflow step and await full run result: ```typescript const { runId } = createRun({ runId: prevRunId }); const result = await workflow.resumeAsync({ runId, stepId: "step-id", contextData: { key: "value" }, }); ``` ### Watch Legacy Workflow Watch legacy workflow transitions ```typescript try { // Get workflow instance const workflow = client.getLegacyWorkflow("workflow-id"); // Create a workflow run const { runId } = workflow.createRun(); // Watch workflow run workflow.watch({ runId }, (record) => { // Every new record is the latest transition state of the workflow run console.log({ activePaths: record.activePaths, results: record.results, timestamp: record.timestamp, runId: record.runId, }); }); // Start workflow run workflow.start({ runId, triggerData: { city: "New York", }, }); } catch (e) { console.error(e); } ``` ### Resume Legacy Workflow Resume legacy workflow run and watch legacy workflow step transitions ```typescript try { //To resume a workflow run, when a step is suspended const { run } = createRun({ runId: prevRunId }); //Watch run workflow.watch({ runId }, (record) => { // Every new record is the latest transition state of the workflow run console.log({ activePaths: record.activePaths, results: record.results, timestamp: record.timestamp, runId: record.runId, }); }); //resume run workflow.resume({ runId, stepId: "step-id", contextData: { key: "value" }, }); } catch (e) { console.error(e); } ``` ### Legacy Workflow run result A legacy workflow run result yields the following: | Field | Type | Description | | ------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------ | | `activePaths` | `Record` | Currently active paths in the workflow with their execution status | | `results` | `LegacyWorkflowRunResult['results']` | Results from the workflow execution | | `timestamp` | `number` | Unix timestamp of when this transition occurred | | `runId` | `string` | Unique identifier for this workflow run instance | --- title: Mastra Client Workflows API description: Learn how to interact with and execute automated workflows in Mastra using the client-js SDK. --- # Workflows API [EN] Source: https://mastra.ai/en/reference/client-js/workflows The Workflows API provides methods to interact with and execute automated workflows in Mastra. ## Initialize Mastra Client ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient(); ``` ## Getting All Workflows Retrieve a list of all available workflows: ```typescript const workflows = await client.getWorkflows(); ``` ## Working with a Specific Workflow Get an instance of a specific workflow as defined by the const name: ```typescript filename="src/mastra/workflows/test-workflow.ts" export const testWorkflow = createWorkflow({ id: 'city-workflow' }) ``` ```typescript const workflow = client.getWorkflow("testWorkflow"); ``` ## Workflow Methods ### Get Workflow Details Retrieve detailed information about a workflow: ```typescript const details = await workflow.details(); ``` ### Start workflow run asynchronously Start a workflow run with inputData and await full run results: ```typescript const run = await workflow.createRun(); const result = await workflow.startAsync({ runId: run.runId, inputData: { city: "New York", }, }); ``` ### Resume Workflow run asynchronously Resume a suspended workflow step and await full run result: ```typescript const run = await workflow.createRun(); const result = await workflow.resumeAsync({ runId: run.runId, step: "step-id", resumeData: { key: "value" }, }); ``` ### Watch Workflow Watch workflow transitions: ```typescript try { const workflow = client.getWorkflow("testWorkflow"); const run = await workflow.createRun(); workflow.watch({ runId: run.runId }, (record) => { console.log(record); }); const result = await workflow.start({ runId: run.runId, inputData: { city: "New York", }, }); } catch (e) { console.error(e); } ``` ### Resume Workflow Resume workflow run and watch workflow step transitions: ```typescript try { const workflow = client.getWorkflow("testWorkflow"); const run = await workflow.createRun({ runId: prevRunId }); workflow.watch({ runId: run.runId }, (record) => { console.log(record); }); workflow.resume({ runId: run.runId, step: "step-id", resumeData: { key: "value" }, }); } catch (e) { console.error(e); } ``` ### Get Workflow Run result Get the result of a workflow run: ```typescript try { const workflow = client.getWorkflow("testWorkflow"); const run = await workflow.createRun(); // start the workflow run const startResult = await workflow.start({ runId: run.runId, inputData: { city: "New York", }, }); const result = await workflow.runExecutionResult(run.runId); console.log(result); } catch (e) { console.error(e); } ``` This is useful when dealing with long running workflows. You can use this to poll the result of the workflow run. ### Workflow run result A workflow run result yields the following: | Field | Type | Description | | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | | `payload` | `{currentStep?: {id: string, status: string, output?: Record, payload?: Record}, workflowState: {status: string, steps: Record, payload?: Record}>}}` | The current step and workflow state of the run | | `eventTimestamp` | `Date` | The timestamp of the event | | `runId` | `string` | Unique identifier for this workflow run instance | --- title: "Mastra Core" description: Documentation for the Mastra Class, the core entry point for managing agents, workflows, MCP servers, and server endpoints. --- # The Mastra Class [EN] Source: https://mastra.ai/en/reference/core/mastra-class The `Mastra` class is the central orchestrator in any Mastra application, managing agents, workflows, storage, logging, telemetry, and more. Typically, you create a single instance of `Mastra` to coordinate your application. Think of `Mastra` as a top-level registry: - Registering **integrations** makes them accessible to **agents**, **workflows**, and **tools** alike. - **tools** aren’t registered on `Mastra` directly but are associated with agents and discovered automatically. ## Importing ```typescript import { Mastra } from "@mastra/core"; ``` ## Constructor Creates a new `Mastra` instance with the specified configuration. ```typescript constructor(config?: Config); ``` ## Initialization The Mastra class is typically initialized in your `src/mastra/index.ts` file: ```typescript filename="src/mastra/index.ts" showLineNumbers copy import { Mastra } from "@mastra/core"; import { LibSQLStore } from "@mastra/libsql"; import { weatherAgent } from "./agents/weather-agent"; export const mastra = new Mastra({ agents: { weatherAgent }, storage: new LibSQLStore({ url: ":memory:", }), }); ``` ## Configuration Object The constructor accepts an optional `Config` object to customize its behavior and integrate various Mastra components. All properties on the `Config` object are optional. ### Properties ", description: "Custom tools to register. Structured as a key-value pair, with keys being the tool name and values being the tool function.", isOptional: true, defaultValue: "{}", }, { name: "storage", type: "MastraStorage", description: "Storage engine instance for persisting data", isOptional: true, }, { name: "vectors", type: "Record", description: "Vector store instance, used for semantic search and vector-based tools (eg Pinecone, PgVector or Qdrant)", isOptional: true, }, { name: "logger", type: "Logger", description: "Logger instance created with new PinoLogger()", isOptional: true, defaultValue: "Console logger with INFO level", }, { name: "workflows", type: "Record", description: "Workflows to register. Structured as a key-value pair, with keys being the workflow name and values being the workflow instance.", isOptional: true, defaultValue: "{}", }, { name: "tts", type: "Record", isOptional: true, description: "An object for registering Text-To-Speech services.", }, { name: "telemetry", type: "OtelConfig", isOptional: true, description: "Configuration for OpenTelemetry integration.", }, { name: "deployer", type: "MastraDeployer", isOptional: true, description: "An instance of a MastraDeployer for managing deployments.", }, { name: "server", type: "ServerConfig", description: "Server configuration including port, host, timeout, API routes, middleware, CORS settings, and build options for Swagger UI, API request logging, and OpenAPI docs.", isOptional: true, defaultValue: "{ port: 4111, host: localhost, cors: { origin: '*', allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], allowHeaders: ['Content-Type', 'Authorization', 'x-mastra-client-type'], exposeHeaders: ['Content-Length', 'X-Requested-With'], credentials: false } }", }, { name: "mcpServers", type: "Record", isOptional: true, description: "An object where keys are unique server identifiers and values are instances of MCPServer or classes extending MCPServerBase. This allows Mastra to be aware of and potentially manage these MCP servers.", }, { name: "bundler", type: "BundlerConfig", description: "Configuration for the asset bundler.", }, ]} /> ## Usage Any of the below methods can be used with the Mastra class, for example: ```typescript {3} filename="example.ts" showLineNumbers import { mastra } from "./mastra"; const agent = mastra.getAgent("weatherAgent"); const result = await agent.generate("What's the weather like in London?"); ``` ### Methods ", description: "Returns all registered agents as a key-value object.", example: "const agents = mastra.getAgents();", }, { name: "getWorkflow(id, { serialized })", type: "Workflow", description: "Returns a workflow instance by id. The serialized option (default: false) returns a simplified representation with just the name.", example: 'const workflow = mastra.getWorkflow("myWorkflow");', }, { name: "getWorkflows({ serialized })", type: "Record", description: "Returns all registered workflows. The serialized option (default: false) returns simplified representations.", example: "const workflows = mastra.getWorkflows();", }, { name: "getVector(name)", type: "MastraVector", description: "Returns a vector store instance by name. Throws if not found.", example: 'const vectorStore = mastra.getVector("myVectorStore");', }, { name: "getVectors()", type: "Record", description: "Returns all registered vector stores as a key-value object.", example: "const vectorStores = mastra.getVectors();", }, { name: "getDeployer()", type: "MastraDeployer | undefined", description: "Returns the configured deployer instance, if any.", example: "const deployer = mastra.getDeployer();", }, { name: "getStorage()", type: "MastraStorage | undefined", description: "Returns the configured storage instance.", example: "const storage = mastra.getStorage();", }, { name: "getMemory()", type: "MastraMemory | undefined", description: "Returns the configured memory instance. Note: This is deprecated, memory should be added to agents directly.", example: "const memory = mastra.getMemory();", }, { name: "getServer()", type: "ServerConfig | undefined", description: "Returns the server configuration including port, timeout, API routes, middleware, CORS settings, and build options.", example: "const serverConfig = mastra.getServer();", }, { name: "setStorage(storage)", type: "void", description: "Sets the storage instance for the Mastra instance.", example: "mastra.setStorage(new DefaultStorage());", }, { name: "setLogger({ logger })", type: "void", description: "Sets the logger for all components (agents, workflows, etc.).", example: 'mastra.setLogger({ logger: new PinoLogger({ name: "MyLogger" }) });', }, { name: "setTelemetry(telemetry)", type: "void", description: "Sets the telemetry configuration for all components.", example: 'mastra.setTelemetry({ export: { type: "console" } });', }, { name: "getLogger()", type: "Logger", description: "Gets the configured logger instance.", example: "const logger = mastra.getLogger();", }, { name: "getTelemetry()", type: "Telemetry | undefined", description: "Gets the configured telemetry instance.", example: "const telemetry = mastra.getTelemetry();", }, { name: "getLogsByRunId({ runId, transportId })", type: "Promise", description: "Retrieves logs for a specific run ID and transport ID.", example: 'const logs = await mastra.getLogsByRunId({ runId: "123", transportId: "456" });', }, { name: "getLogs(transportId)", type: "Promise", description: "Retrieves all logs for a specific transport ID.", example: 'const logs = await mastra.getLogs("transportId");', }, { name: "getMCPServers()", type: "Record | undefined", description: "Retrieves all registered MCP server instances.", example: "const mcpServers = mastra.getMCPServers();", }, ]} /> ## Error Handling The Mastra class methods throw typed errors that can be caught: ```typescript {8} filename="example.ts" showLineNumbers import { mastra } from "./mastra"; try { const agent = mastra.getAgent("weatherAgent"); const result = await agent.generate("What's the weather like in London?"); } catch (error) { if (error instanceof Error) { console.log(error.message); } } ``` --- title: "Cloudflare Deployer" description: "Documentation for the CloudflareDeployer class, which deploys Mastra applications to Cloudflare Workers." --- # CloudflareDeployer [EN] Source: https://mastra.ai/en/reference/deployer/cloudflare The CloudflareDeployer deploys standalone Mastra applications to Cloudflare Workers, handling configuration, environment variables, and route management. It extends the abstract Deployer class to provide Cloudflare-specific deployment functionality. ## Installation ```bash copy npm install @mastra/deployer-cloudflare@latest ``` ## Usage Example ```typescript filename="src/mastra/index.ts" showLineNumbers copy import { Mastra } from "@mastra/core"; import { CloudflareDeployer } from "@mastra/deployer-cloudflare"; const mastra = new Mastra({ // ... deployer: new CloudflareDeployer({ scope: "your-account-id", projectName: "your-project-name", routes: [ { pattern: "example.com/*", zone_name: "example.com", custom_domain: true, }, ], workerNamespace: "your-namespace", auth: { apiToken: "your-api-token", apiEmail: "your-email", }, d1Databases: [ { binding: "binding-name", database_name: "database-name", database_id: "database-id", }, ], kvNamespaces: [ { binding: "binding-name", id: "namespace-id", }, ], }), }); ``` ## Parameters ### Constructor Parameters ", description: "Environment variables to be included in the worker configuration.", isOptional: true, }, { name: "auth", type: "object", description: "Cloudflare authentication details.", isOptional: false, }, { name: "d1Databases", type: "D1DatabaseBinding[]", description: "Array of D1 database bindings for your worker.", isOptional: true, }, { name: "kvNamespaces", type: "KVNamespaceBinding[]", description: "Array of KV namespace bindings for your worker.", isOptional: true, }, ]} /> ### auth Object ### CFRoute Object ### D1DatabaseBinding Object ### KVNamespaceBinding Object ### Environment Variables The CloudflareDeployer handles environment variables from multiple sources: 1. **Environment Files**: Variables from `.env.production` and `.env` files. 2. **Configuration**: Variables passed through the `env` parameter. ## Lint Mastra Project Lint your Mastra project to make sure it's fine to build ```bash npx mastra lint ``` ## Build Mastra Project To build your Mastra project for cloudflare deployment: ```bash npx mastra build ``` The build process generates the following output structure in the `.mastra/output` directory: ``` .mastra/output/ ├── index.mjs # Main worker entry point ├── wrangler.json # Cloudflare Worker configuration └── assets/ # Static assets and dependencies ``` ### Wrangler Configuration The CloudflareDeployer automatically generates a `wrangler.json` configuration file with the following settings: ```json { "name": "your-project-name", "main": "./output/index.mjs", "compatibility_date": "2024-12-02", "compatibility_flags": [ "nodejs_compat", "nodejs_compat_populate_process_env" ], "observability": { "logs": { "enabled": true } }, "vars": { // Environment variables from .env files and configuration }, "routes": [ // Route configurations if specified ], "d1_databases": [ // D1 database bindings if specified ], "kv_namespaces": [ // KV namespace bindings if specified ] } ``` Compatibility flags: - `nodejs_compat`: Enables Node.js compatibility in Workers. - `nodejs_compat_populate_process_env`: Populates `process.env` with variables from `vars`. ### Route Configuration Routes can be configured to direct traffic to your worker based on URL patterns and domains: ```typescript const routes = [ { pattern: "api.example.com/*", zone_name: "example.com", custom_domain: true, }, { pattern: "example.com/api/*", zone_name: "example.com", }, ]; ``` ## Deployment Options After building, you can deploy your Mastra application `.mastra/output` to Cloudflare Workers using any of these methods: 1. **Wrangler CLI**: Deploy directly using Cloudflare's official CLI tool - Install the CLI: `npm install -g wrangler` - Navigate to the output directory: `cd .mastra/output` - Login to your Cloudflare account: `wrangler login` - Deploy to preview environment: `wrangler deploy` - For production deployment: `wrangler deploy --env production` 2. **Cloudflare Dashboard**: Upload the build output manually through the Cloudflare dashboard > You can also run `wrangler dev` in your output directory `.mastra/output` to test your Mastra application locally. ## Platform Documentation - [Cloudflare Workers](https://developers.cloudflare.com/workers/) --- title: "Mastra Deployer" description: Documentation for the Deployer abstract class, which handles packaging and deployment of Mastra applications. --- # Deployer [EN] Source: https://mastra.ai/en/reference/deployer/deployer The Deployer handles the deployment of standalone Mastra applications by packaging code, managing environment files, and serving applications using the Hono framework. Concrete implementations must define the deploy method for specific deployment targets. ## Usage Example ```typescript import { Deployer } from "@mastra/deployer"; // Create a custom deployer by extending the abstract Deployer class class CustomDeployer extends Deployer { constructor() { super({ name: "custom-deployer" }); } // Implement the abstract deploy method async deploy(outputDirectory: string): Promise { // Prepare the output directory await this.prepare(outputDirectory); // Bundle the application await this._bundle("server.ts", "mastra.ts", outputDirectory); // Custom deployment logic // ... } } ``` ## Parameters ### Constructor Parameters ### deploy Parameters ## Methods Promise", description: "Returns a list of environment files to be used during deployment. By default, it looks for '.env.production' and '.env' files.", }, { name: "deploy", type: "(outputDirectory: string) => Promise", description: "Abstract method that must be implemented by subclasses. Handles the deployment process to the specified output directory.", }, ]} /> ## Inherited Methods from Bundler The Deployer class inherits the following key methods from the Bundler class: Promise", description: "Prepares the output directory by cleaning it and creating necessary subdirectories.", }, { name: "writeInstrumentationFile", type: "(outputDirectory: string) => Promise", description: "Writes an instrumentation file to the output directory for telemetry purposes.", }, { name: "writePackageJson", type: "(outputDirectory: string, dependencies: Map) => Promise", description: "Generates a package.json file in the output directory with the specified dependencies.", }, { name: "_bundle", type: "(serverFile: string, mastraEntryFile: string, outputDirectory: string, bundleLocation?: string) => Promise", description: "Bundles the application using the specified server and Mastra entry files.", }, ]} /> ## Core Concepts ### Deployment Lifecycle The Deployer abstract class implements a structured deployment lifecycle: 1. **Initialization**: The deployer is initialized with a name and creates a Deps instance for dependency management. 2. **Environment Setup**: The `getEnvFiles` method identifies environment files (.env.production, .env) to be used during deployment. 3. **Preparation**: The `prepare` method (inherited from Bundler) cleans the output directory and creates necessary subdirectories. 4. **Bundling**: The `_bundle` method (inherited from Bundler) packages the application code and its dependencies. 5. **Deployment**: The abstract `deploy` method is implemented by subclasses to handle the actual deployment process. ### Environment File Management The Deployer class includes built-in support for environment file management through the `getEnvFiles` method. This method: - Looks for environment files in a predefined order (.env.production, .env) - Uses the FileService to find the first existing file - Returns an array of found environment files - Returns an empty array if no environment files are found ```typescript getEnvFiles(): Promise { const possibleFiles = ['.env.production', '.env.local', '.env']; try { const fileService = new FileService(); const envFile = fileService.getFirstExistingFile(possibleFiles); return Promise.resolve([envFile]); } catch {} return Promise.resolve([]); } ``` ### Bundling and Deployment Relationship The Deployer class extends the Bundler class, establishing a clear relationship between bundling and deployment: 1. **Bundling as a Prerequisite**: Bundling is a prerequisite step for deployment, where the application code is packaged into a deployable format. 2. **Shared Infrastructure**: Both bundling and deployment share common infrastructure like dependency management and file system operations. 3. **Specialized Deployment Logic**: While bundling focuses on code packaging, deployment adds environment-specific logic for deploying the bundled code. 4. **Extensibility**: The abstract `deploy` method allows for creating specialized deployers for different target environments. --- title: "Netlify Deployer" description: "Documentation for the NetlifyDeployer class, which deploys Mastra applications to Netlify Functions." --- # NetlifyDeployer [EN] Source: https://mastra.ai/en/reference/deployer/netlify The NetlifyDeployer deploys standalone Mastra applications to Netlify Functions, handling site creation, configuration, and deployment processes. It extends the abstract Deployer class to provide Netlify-specific deployment functionality. ## Installation ```bash copy npm install @mastra/deployer-netlify@latest ``` ## Usage Example ```typescript filename="src/mastra/index.ts" showLineNumbers copy import { Mastra } from "@mastra/core"; import { NetlifyDeployer } from "@mastra/deployer-netlify"; const mastra = new Mastra({ // ... deployer: new NetlifyDeployer({ scope: "your-team-slug", projectName: "your-project-name", token: "your-netlify-token", }) }); ``` ## Parameters ### Constructor Parameters ### Environment Variables The NetlifyDeployer handles environment variables from multiple sources: 1. **Environment Files**: Variables from `.env.production` and `.env` files. 2. **Configuration**: Variables passed through the Mastra configuration. 3. **Netlify Dashboard**: Variables can also be managed through Netlify's web interface. ## Lint Mastra Project Lint your Mastra project to make sure it's fine to build ```bash npx mastra lint ``` ## Build Mastra Project To build your Mastra project for Netlify deployment: ```bash npx mastra build ``` The build process generates the following output structure in the `.mastra/output` directory: ``` .mastra/output/ ├── netlify/ │ └── functions/ │ └── api/ │ └── index.mjs # Application entry point └── netlify.toml # Netlify configuration ``` ### Netlify Configuration The NetlifyDeployer automatically generates a `netlify.toml` configuration file in `.mastra/output` with the following settings: ```toml [functions] node_bundler = "esbuild" directory = "netlify/functions" [[redirects]] force = true from = "/*" status = 200 to = "/.netlify/functions/api/:splat" ``` ## Deployment Options After building, you can deploy your Mastra application `.mastra/output` to Netlify using any of these methods: 1. **Netlify CLI**: Deploy directly using Netlify's official CLI tool - Install the CLI: `npm install -g netlify-cli` - Navigate to the output directory: `cd .mastra/output` - Deploy with functions directory specified: `netlify deploy --dir . --functions ./netlify/functions` - For production deployment add `--prod` flag: `netlify deploy --prod --dir . --functions ./netlify/functions` 2. **Netlify Dashboard**: Connect your Git repository or drag-and-drop the build output through the Netlify dashboard When connecting a Mastra project Git repository to Netlify, use these recommended build settings since Netlify resolves paths relative to the project root: ```bash # Build command npm run build # Publish directory .mastra/output # Functions directory .mastra/output/netlify/functions ``` 3. **Netlify Dev**: Run your Mastra application locally with Netlify's development environment > You can also run `netlify dev` in your output directory `.mastra/output` to test your Mastra application locally. ## Platform Documentation - [Netlify](https://docs.netlify.com/) --- title: "Vercel Deployer" description: "Documentation for the VercelDeployer class, which deploys Mastra applications to Vercel." --- # VercelDeployer [EN] Source: https://mastra.ai/en/reference/deployer/vercel The VercelDeployer deploys standalone Mastra applications to Vercel, handling configuration, environment variable synchronization, and deployment processes. It extends the abstract Deployer class to provide Vercel-specific deployment functionality. ## Installation ```bash copy npm install @mastra/deployer-vercel@latest ``` ## Usage Example ```typescript filename="src/mastra/index.ts" showLineNumbers copy import { Mastra } from "@mastra/core"; import { VercelDeployer } from "@mastra/deployer-vercel"; const mastra = new Mastra({ // ... deployer: new VercelDeployer({ teamSlug: "your-team-slug", projectName: "your-project-name", token: "your-vercel-token", }) }); ``` ## Parameters ### Constructor Parameters ### Environment Variables The VercelDeployer handles environment variables from multiple sources: 1. **Environment Files**: Variables from `.env.production` and `.env` files. 2. **Configuration**: Variables passed through the Mastra configuration. 3. **Vercel Dashboard**: Variables can also be managed through Vercel's web interface. The deployer automatically synchronizes environment variables between your local development environment and Vercel's environment variable system, ensuring consistency across all deployment environments (production, preview, and development). ## Lint Mastra Project Lint your Mastra project to make sure it's fine to build ```bash npx mastra lint ``` ## Build Mastra Project To build your Mastra project for Vercel deployment: ```bash npx mastra build ``` The build process generates the following output structure in the `.mastra/output` directory: ``` .mastra/output/ ├── vercel.json # Vercel configuration └── index.mjs # Application entry point ``` ### Vercel Configuration The VercelDeployer automatically generates a `vercel.json` configuration file in `.mastra/output` with the following settings: ```json { "version": 2, "installCommand": "npm install --omit=dev", "builds": [ { "src": "index.mjs", "use": "@vercel/node", "config": { "includeFiles": ["**"] } } ], "routes": [ { "src": "/(.*)", "dest": "index.mjs" } ] } ``` ## Deployment Options After building, you can deploy your Mastra application `.mastra/output` to Vercel using any of these methods: 1. **Vercel CLI**: Deploy directly using Vercel's official CLI tool - Install the CLI: `npm install -g vercel` - Navigate to the output directory: `cd .mastra/output` - Deploy to preview environment: `vercel` - For production deployment: `vercel --prod` 2. **Vercel Dashboard**: Connect your Git repository or drag-and-drop the build output through the Vercel dashboard > You can also run `vercel dev` in your output directory `.mastra/output` to test your Mastra application locally. ## Platform Documentation - [Vercel](https://vercel.com/docs) --- title: "Reference: Answer Relevancy | Metrics | Evals | Mastra Docs" description: Documentation for the Answer Relevancy Metric in Mastra, which evaluates how well LLM outputs address the input query. --- # AnswerRelevancyMetric [EN] Source: https://mastra.ai/en/reference/evals/answer-relevancy The `AnswerRelevancyMetric` class evaluates how well an LLM's output answers or addresses the input query. It uses a judge-based system to determine relevancy and provides detailed scoring and reasoning. ## Basic Usage ```typescript import { openai } from "@ai-sdk/openai"; import { AnswerRelevancyMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new AnswerRelevancyMetric(model, { uncertaintyWeight: 0.3, scale: 1, }); const result = await metric.measure( "What is the capital of France?", "Paris is the capital of France.", ); console.log(result.score); // Score from 0-1 console.log(result.info.reason); // Explanation of the score ``` ## Constructor Parameters ### AnswerRelevancyMetricOptions ## measure() Parameters ## Returns ## Scoring Details The metric evaluates relevancy through query-answer alignment, considering completeness, accuracy, and detail level. ### Scoring Process 1. Statement Analysis: - Breaks output into meaningful statements while preserving context - Evaluates each statement against query requirements 2. Evaluates relevance of each statement: - "yes": Full weight for direct matches - "unsure": Partial weight (default: 0.3) for approximate matches - "no": Zero weight for irrelevant content Final score: `((direct + uncertainty * partial) / total_statements) * scale` ### Score interpretation (0 to scale, default 0-1) - 1.0: Perfect relevance - complete and accurate - 0.7-0.9: High relevance - minor gaps or imprecisions - 0.4-0.6: Moderate relevance - significant gaps - 0.1-0.3: Low relevance - major issues - 0.0: No relevance - incorrect or off-topic ## Example with Custom Configuration ```typescript import { openai } from "@ai-sdk/openai"; import { AnswerRelevancyMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new AnswerRelevancyMetric(model, { uncertaintyWeight: 0.5, // Higher weight for uncertain verdicts scale: 5, // Use 0-5 scale instead of 0-1 }); const result = await metric.measure( "What are the benefits of exercise?", "Regular exercise improves cardiovascular health, builds strength, and boosts mental wellbeing.", ); // Example output: // { // score: 4.5, // info: { // reason: "The score is 4.5 out of 5 because the response directly addresses the query // with specific, accurate benefits of exercise. It covers multiple aspects // (cardiovascular, muscular, and mental health) in a clear and concise manner. // The answer is highly relevant and provides appropriate detail without // including unnecessary information." // } // } ``` ## Related - [Prompt Alignment Metric](./prompt-alignment) - [Context Precision Metric](./context-precision) - [Faithfulness Metric](./faithfulness) --- title: "Reference: Bias | Output Metrics | Evals | Mastra Docs" description: Documentation for the Bias Metric in Mastra, which evaluates LLM outputs for various forms of bias, including gender, political, racial/ethnic, or geographical bias. --- # BiasMetric [EN] Source: https://mastra.ai/en/reference/evals/bias The `BiasMetric` class evaluates whether an LLM's output contains various forms of bias, including gender, political, racial/ethnic, or geographical bias. This metric is particularly useful for detecting unintended biases that may emerge after fine-tuning models or applying optimizations. ## Basic Usage ```typescript import { openai } from "@ai-sdk/openai"; import { BiasMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new BiasMetric(model, { scale: 1, }); const result = await metric.measure( "Describe leadership qualities in the workplace", "Strong leaders are typically men who can make tough decisions...", ); console.log(result.score); // Score from 0-1, higher means more biased ``` ## Constructor Parameters ### BiasMetricOptions ## measure() Parameters ## Returns ## Bias Categories The metric evaluates several types of bias: 1. **Gender Bias**: Discrimination or stereotypes based on gender 2. **Political Bias**: Prejudice against political ideologies or beliefs 3. **Racial/Ethnic Bias**: Discrimination based on race, ethnicity, or national origin 4. **Geographical Bias**: Prejudice based on location or regional stereotypes ## Scoring Details The metric evaluates bias through opinion analysis based on: - Opinion identification and extraction - Presence of discriminatory language - Use of stereotypes or generalizations - Balance in perspective presentation - Loaded or prejudicial terminology ### Scoring Process 1. Extracts opinions from text: - Identifies subjective statements - Excludes factual claims - Includes cited opinions 2. Evaluates each opinion: - Checks for discriminatory language - Assesses stereotypes and generalizations - Analyzes perspective balance Final score: `(biased_opinions / total_opinions) * scale` ### Score interpretation (0 to scale, default 0-1) - 1.0: Complete bias - all opinions contain bias - 0.7-0.9: Significant bias - majority of opinions show bias - 0.4-0.6: Moderate bias - mix of biased and neutral opinions - 0.1-0.3: Minimal bias - most opinions show balanced perspective - 0.0: No detectable bias - opinions are balanced and neutral ## Example with Different Types of Bias ```typescript import { openai } from "@ai-sdk/openai"; import { BiasMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new BiasMetric(model); // Testing for different types of bias const results = await Promise.all([ metric.measure( "Describe voting patterns", "These radical right-wing voters consistently vote against their interests...", ), metric.measure( "Describe workplace dynamics", "Modern offices have diverse teams working together based on merit...", ), ]); // Example outputs: // Political bias example: { score: 1.0 } // Unbiased example: { score: 0.0 } ``` ## Related - [Toxicity Metric](./toxicity) - [Faithfulness Metric](./faithfulness) - [Hallucination Metric](./hallucination) - [Context Relevancy Metric](./context-relevancy) --- title: "Reference: Completeness | Metrics | Evals | Mastra Docs" description: Documentation for the Completeness Metric in Mastra, which evaluates how thoroughly LLM outputs cover key elements present in the input. --- # CompletenessMetric [EN] Source: https://mastra.ai/en/reference/evals/completeness The `CompletenessMetric` class evaluates how thoroughly an LLM's output covers the key elements present in the input. It analyzes nouns, verbs, topics, and terms to determine coverage and provides a detailed completeness score. ## Basic Usage ```typescript import { CompletenessMetric } from "@mastra/evals/nlp"; const metric = new CompletenessMetric(); const result = await metric.measure( "Explain how photosynthesis works in plants using sunlight, water, and carbon dioxide.", "Plants use sunlight to convert water and carbon dioxide into glucose through photosynthesis.", ); console.log(result.score); // Coverage score from 0-1 console.log(result.info); // Object containing detailed metrics about element coverage ``` ## measure() Parameters ## Returns ## Element Extraction Details The metric extracts and analyzes several types of elements: - Nouns: Key objects, concepts, and entities - Verbs: Actions and states (converted to infinitive form) - Topics: Main subjects and themes - Terms: Individual significant words The extraction process includes: - Normalization of text (removing diacritics, converting to lowercase) - Splitting camelCase words - Handling of word boundaries - Special handling of short words (3 characters or less) - Deduplication of elements ## Scoring Details The metric evaluates completeness through linguistic element coverage analysis. ### Scoring Process 1. Extracts key elements: - Nouns and named entities - Action verbs - Topic-specific terms - Normalized word forms 2. Calculates coverage of input elements: - Exact matches for short terms (≤3 chars) - Substantial overlap (>60%) for longer terms Final score: `(covered_elements / total_input_elements) * scale` ### Score interpretation (0 to scale, default 0-1) - 1.0: Complete coverage - contains all input elements - 0.7-0.9: High coverage - includes most key elements - 0.4-0.6: Partial coverage - contains some key elements - 0.1-0.3: Low coverage - missing most key elements - 0.0: No coverage - output lacks all input elements ## Example with Analysis ```typescript import { CompletenessMetric } from "@mastra/evals/nlp"; const metric = new CompletenessMetric(); const result = await metric.measure( "The quick brown fox jumps over the lazy dog", "A brown fox jumped over a dog", ); // Example output: // { // score: 0.75, // info: { // inputElements: ["quick", "brown", "fox", "jump", "lazy", "dog"], // outputElements: ["brown", "fox", "jump", "dog"], // missingElements: ["quick", "lazy"], // elementCounts: { input: 6, output: 4 } // } // } ``` ## Related - [Answer Relevancy Metric](./answer-relevancy) - [Content Similarity Metric](./content-similarity) - [Textual Difference Metric](./textual-difference) - [Keyword Coverage Metric](./keyword-coverage) --- title: "Reference: Content Similarity | Evals | Mastra Docs" description: Documentation for the Content Similarity Metric in Mastra, which measures textual similarity between strings and provides a matching score. --- # ContentSimilarityMetric [EN] Source: https://mastra.ai/en/reference/evals/content-similarity The `ContentSimilarityMetric` class measures the textual similarity between two strings, providing a score that indicates how closely they match. It supports configurable options for case sensitivity and whitespace handling. ## Basic Usage ```typescript import { ContentSimilarityMetric } from "@mastra/evals/nlp"; const metric = new ContentSimilarityMetric({ ignoreCase: true, ignoreWhitespace: true, }); const result = await metric.measure("Hello, world!", "hello world"); console.log(result.score); // Similarity score from 0-1 console.log(result.info); // Detailed similarity metrics ``` ## Constructor Parameters ### ContentSimilarityOptions ## measure() Parameters ## Returns ## Scoring Details The metric evaluates textual similarity through character-level matching and configurable text normalization. ### Scoring Process 1. Normalizes text: - Case normalization (if ignoreCase: true) - Whitespace normalization (if ignoreWhitespace: true) 2. Compares processed strings using string-similarity algorithm: - Analyzes character sequences - Aligns word boundaries - Considers relative positions - Accounts for length differences Final score: `similarity_value * scale` ### Score interpretation (0 to scale, default 0-1) - 1.0: Perfect match - identical texts - 0.7-0.9: High similarity - mostly matching content - 0.4-0.6: Moderate similarity - partial matches - 0.1-0.3: Low similarity - few matching patterns - 0.0: No similarity - completely different texts ## Example with Different Options ```typescript import { ContentSimilarityMetric } from "@mastra/evals/nlp"; // Case-sensitive comparison const caseSensitiveMetric = new ContentSimilarityMetric({ ignoreCase: false, ignoreWhitespace: true, }); const result1 = await caseSensitiveMetric.measure("Hello World", "hello world"); // Lower score due to case difference // Example output: // { // score: 0.75, // info: { similarity: 0.75 } // } // Strict whitespace comparison const strictWhitespaceMetric = new ContentSimilarityMetric({ ignoreCase: true, ignoreWhitespace: false, }); const result2 = await strictWhitespaceMetric.measure( "Hello World", "Hello World", ); // Lower score due to whitespace difference // Example output: // { // score: 0.85, // info: { similarity: 0.85 } // } ``` ## Related - [Completeness Metric](./completeness) - [Textual Difference Metric](./textual-difference) - [Answer Relevancy Metric](./answer-relevancy) - [Keyword Coverage Metric](./keyword-coverage) --- title: "Reference: Context Position | Metrics | Evals | Mastra Docs" description: Documentation for the Context Position Metric in Mastra, which evaluates the ordering of context nodes based on their relevance to the query and output. --- # ContextPositionMetric [EN] Source: https://mastra.ai/en/reference/evals/context-position The `ContextPositionMetric` class evaluates how well context nodes are ordered based on their relevance to the query and output. It uses position-weighted scoring to emphasize the importance of having the most relevant context pieces appear earlier in the sequence. ## Basic Usage ```typescript import { openai } from "@ai-sdk/openai"; import { ContextPositionMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new ContextPositionMetric(model, { context: [ "Photosynthesis is a biological process used by plants to create energy from sunlight.", "The process of photosynthesis produces oxygen as a byproduct.", "Plants need water and nutrients from the soil to grow.", ], }); const result = await metric.measure( "What is photosynthesis?", "Photosynthesis is the process by which plants convert sunlight into energy.", ); console.log(result.score); // Position score from 0-1 console.log(result.info.reason); // Explanation of the score ``` ## Constructor Parameters ### ContextPositionMetricOptions ## measure() Parameters ## Returns ## Scoring Details The metric evaluates context positioning through binary relevance assessment and position-based weighting. ### Scoring Process 1. Evaluates context relevance: - Assigns binary verdict (yes/no) to each piece - Records position in sequence - Documents relevance reasoning 2. Applies position weights: - Earlier positions weighted more heavily (weight = 1/(position + 1)) - Sums weights of relevant pieces - Normalizes by maximum possible score Final score: `(weighted_sum / max_possible_sum) * scale` ### Score interpretation (0 to scale, default 0-1) - 1.0: Optimal - most relevant context first - 0.7-0.9: Good - relevant context mostly early - 0.4-0.6: Mixed - relevant context scattered - 0.1-0.3: Suboptimal - relevant context mostly later - 0.0: Poor ordering - relevant context at end or missing ## Example with Analysis ```typescript import { openai } from "@ai-sdk/openai"; import { ContextPositionMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new ContextPositionMetric(model, { context: [ "A balanced diet is important for health.", "Exercise strengthens the heart and improves blood circulation.", "Regular physical activity reduces stress and anxiety.", "Exercise equipment can be expensive.", ], }); const result = await metric.measure( "What are the benefits of exercise?", "Regular exercise improves cardiovascular health and mental wellbeing.", ); // Example output: // { // score: 0.5, // info: { // reason: "The score is 0.5 because while the second and third contexts are highly // relevant to the benefits of exercise, they are not optimally positioned at // the beginning of the sequence. The first and last contexts are not relevant // to the query, which impacts the position-weighted scoring." // } // } ``` ## Related - [Context Precision Metric](./context-precision) - [Answer Relevancy Metric](./answer-relevancy) - [Completeness Metric](./completeness) * [Context Relevancy Metric](./context-relevancy) --- title: "Reference: Context Precision | Metrics | Evals | Mastra Docs" description: Documentation for the Context Precision Metric in Mastra, which evaluates the relevance and precision of retrieved context nodes for generating expected outputs. --- # ContextPrecisionMetric [EN] Source: https://mastra.ai/en/reference/evals/context-precision The `ContextPrecisionMetric` class evaluates how relevant and precise the retrieved context nodes are for generating the expected output. It uses a judge-based system to analyze each context piece's contribution and provides weighted scoring based on position. ## Basic Usage ```typescript import { openai } from "@ai-sdk/openai"; import { ContextPrecisionMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new ContextPrecisionMetric(model, { context: [ "Photosynthesis is a biological process used by plants to create energy from sunlight.", "Plants need water and nutrients from the soil to grow.", "The process of photosynthesis produces oxygen as a byproduct.", ], }); const result = await metric.measure( "What is photosynthesis?", "Photosynthesis is the process by which plants convert sunlight into energy.", ); console.log(result.score); // Precision score from 0-1 console.log(result.info.reason); // Explanation of the score ``` ## Constructor Parameters ### ContextPrecisionMetricOptions ## measure() Parameters ## Returns ## Scoring Details The metric evaluates context precision through binary relevance assessment and Mean Average Precision (MAP) scoring. ### Scoring Process 1. Assigns binary relevance scores: - Relevant context: 1 - Irrelevant context: 0 2. Calculates Mean Average Precision: - Computes precision at each position - Weights earlier positions more heavily - Normalizes to configured scale Final score: `Mean Average Precision * scale` ### Score interpretation (0 to scale, default 0-1) - 1.0: All relevant context in optimal order - 0.7-0.9: Mostly relevant context with good ordering - 0.4-0.6: Mixed relevance or suboptimal ordering - 0.1-0.3: Limited relevance or poor ordering - 0.0: No relevant context ## Example with Analysis ```typescript import { openai } from "@ai-sdk/openai"; import { ContextPrecisionMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new ContextPrecisionMetric(model, { context: [ "Exercise strengthens the heart and improves blood circulation.", "A balanced diet is important for health.", "Regular physical activity reduces stress and anxiety.", "Exercise equipment can be expensive.", ], }); const result = await metric.measure( "What are the benefits of exercise?", "Regular exercise improves cardiovascular health and mental wellbeing.", ); // Example output: // { // score: 0.75, // info: { // reason: "The score is 0.75 because the first and third contexts are highly relevant // to the benefits mentioned in the output, while the second and fourth contexts // are not directly related to exercise benefits. The relevant contexts are well-positioned // at the beginning and middle of the sequence." // } // } ``` ## Related - [Answer Relevancy Metric](./answer-relevancy) - [Context Position Metric](./context-position) - [Completeness Metric](./completeness) - [Context Relevancy Metric](./context-relevancy) --- title: "Reference: Context Relevancy | Evals | Mastra Docs" description: Documentation for the Context Relevancy Metric, which evaluates the relevance of retrieved context in RAG pipelines. --- # ContextRelevancyMetric [EN] Source: https://mastra.ai/en/reference/evals/context-relevancy The `ContextRelevancyMetric` class evaluates the quality of your RAG (Retrieval-Augmented Generation) pipeline's retriever by measuring how relevant the retrieved context is to the input query. It uses an LLM-based evaluation system that first extracts statements from the context and then assesses their relevance to the input. ## Basic Usage ```typescript import { openai } from "@ai-sdk/openai"; import { ContextRelevancyMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new ContextRelevancyMetric(model, { context: [ "All data is encrypted at rest and in transit", "Two-factor authentication is mandatory", "The platform supports multiple languages", "Our offices are located in San Francisco", ], }); const result = await metric.measure( "What are our product's security features?", "Our product uses encryption and requires 2FA.", ); console.log(result.score); // Score from 0-1 console.log(result.info.reason); // Explanation of the relevancy assessment ``` ## Constructor Parameters ### ContextRelevancyMetricOptions ## measure() Parameters ## Returns ## Scoring Details The metric evaluates how well retrieved context matches the query through binary relevance classification. ### Scoring Process 1. Extracts statements from context: - Breaks down context into meaningful units - Preserves semantic relationships 2. Evaluates statement relevance: - Assesses each statement against query - Counts relevant statements - Calculates relevance ratio Final score: `(relevant_statements / total_statements) * scale` ### Score interpretation (0 to scale, default 0-1) - 1.0: Perfect relevancy - all retrieved context is relevant - 0.7-0.9: High relevancy - most context is relevant with few irrelevant pieces - 0.4-0.6: Moderate relevancy - a mix of relevant and irrelevant context - 0.1-0.3: Low relevancy - mostly irrelevant context - 0.0: No relevancy - completely irrelevant context ## Example with Custom Configuration ```typescript import { openai } from "@ai-sdk/openai"; import { ContextRelevancyMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new ContextRelevancyMetric(model, { scale: 100, // Use 0-100 scale instead of 0-1 context: [ "Basic plan costs $10/month", "Pro plan includes advanced features at $30/month", "Enterprise plan has custom pricing", "Our company was founded in 2020", "We have offices worldwide", ], }); const result = await metric.measure( "What are our pricing plans?", "We offer Basic, Pro, and Enterprise plans.", ); // Example output: // { // score: 60, // info: { // reason: "3 out of 5 statements are relevant to pricing plans. The statements about // company founding and office locations are not relevant to the pricing query." // } // } ``` ## Related - [Contextual Recall Metric](./contextual-recall) - [Context Precision Metric](./context-precision) - [Context Position Metric](./context-position) --- title: "Reference: Contextual Recall | Metrics | Evals | Mastra Docs" description: Documentation for the Contextual Recall Metric, which evaluates the completeness of LLM responses in incorporating relevant context. --- # ContextualRecallMetric [EN] Source: https://mastra.ai/en/reference/evals/contextual-recall The `ContextualRecallMetric` class evaluates how effectively an LLM's response incorporates all relevant information from the provided context. It measures whether important information from the reference documents was successfully included in the response, focusing on completeness rather than precision. ## Basic Usage ```typescript import { openai } from "@ai-sdk/openai"; import { ContextualRecallMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new ContextualRecallMetric(model, { context: [ "Product features: cloud synchronization capability", "Offline mode available for all users", "Supports multiple devices simultaneously", "End-to-end encryption for all data", ], }); const result = await metric.measure( "What are the key features of the product?", "The product includes cloud sync, offline mode, and multi-device support.", ); console.log(result.score); // Score from 0-1 ``` ## Constructor Parameters ### ContextualRecallMetricOptions ## measure() Parameters ## Returns ## Scoring Details The metric evaluates recall through comparison of response content against relevant context items. ### Scoring Process 1. Evaluates information recall: - Identifies relevant items in context - Tracks correctly recalled information - Measures completeness of recall 2. Calculates recall score: - Counts correctly recalled items - Compares against total relevant items - Computes coverage ratio Final score: `(correctly_recalled_items / total_relevant_items) * scale` ### Score interpretation (0 to scale, default 0-1) - 1.0: Perfect recall - all relevant information included - 0.7-0.9: High recall - most relevant information included - 0.4-0.6: Moderate recall - some relevant information missed - 0.1-0.3: Low recall - significant information missed - 0.0: No recall - no relevant information included ## Example with Custom Configuration ```typescript import { openai } from "@ai-sdk/openai"; import { ContextualRecallMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new ContextualRecallMetric(model, { scale: 100, // Use 0-100 scale instead of 0-1 context: [ "All data is encrypted at rest and in transit", "Two-factor authentication (2FA) is mandatory", "Regular security audits are performed", "Incident response team available 24/7", ], }); const result = await metric.measure( "Summarize the company's security measures", "The company implements encryption for data protection and requires 2FA for all users.", ); // Example output: // { // score: 50, // Only half of the security measures were mentioned // info: { // reason: "The score is 50 because only half of the security measures were mentioned // in the response. The response missed the regular security audits and incident // response team information." // } // } ``` ## Related - [Context Relevancy Metric](./context-relevancy) - [Completeness Metric](./completeness) - [Summarization Metric](./summarization) --- title: "Reference: Faithfulness | Metrics | Evals | Mastra Docs" description: Documentation for the Faithfulness Metric in Mastra, which evaluates the factual accuracy of LLM outputs compared to the provided context. --- # FaithfulnessMetric Reference [EN] Source: https://mastra.ai/en/reference/evals/faithfulness The `FaithfulnessMetric` in Mastra evaluates how factually accurate an LLM's output is compared to the provided context. It extracts claims from the output and verifies them against the context, making it essential to measure RAG pipeline responses' reliability. ## Basic Usage ```typescript import { openai } from "@ai-sdk/openai"; import { FaithfulnessMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new FaithfulnessMetric(model, { context: [ "The company was established in 1995.", "Currently employs around 450-550 people.", ], }); const result = await metric.measure( "Tell me about the company.", "The company was founded in 1995 and has 500 employees.", ); console.log(result.score); // 1.0 console.log(result.info.reason); // "All claims are supported by the context." ``` ## Constructor Parameters ### FaithfulnessMetricOptions ## measure() Parameters ## Returns ## Scoring Details The metric evaluates faithfulness through claim verification against provided context. ### Scoring Process 1. Analyzes claims and context: - Extracts all claims (factual and speculative) - Verifies each claim against context - Assigns one of three verdicts: - "yes" - claim supported by context - "no" - claim contradicts context - "unsure" - claim unverifiable 2. Calculates faithfulness score: - Counts supported claims - Divides by total claims - Scales to configured range Final score: `(supported_claims / total_claims) * scale` ### Score interpretation (0 to scale, default 0-1) - 1.0: All claims supported by context - 0.7-0.9: Most claims supported, few unverifiable - 0.4-0.6: Mixed support with some contradictions - 0.1-0.3: Limited support, many contradictions - 0.0: No supported claims ## Advanced Example ```typescript import { openai } from "@ai-sdk/openai"; import { FaithfulnessMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new FaithfulnessMetric(model, { context: [ "The company had 100 employees in 2020.", "Current employee count is approximately 500.", ], }); // Example with mixed claim types const result = await metric.measure( "What's the company's growth like?", "The company has grown from 100 employees in 2020 to 500 now, and might expand to 1000 by next year.", ); // Example output: // { // score: 0.67, // info: { // reason: "The score is 0.67 because two claims are supported by the context // (initial employee count of 100 in 2020 and current count of 500), // while the future expansion claim is marked as unsure as it cannot // be verified against the context." // } // } ``` ### Related - [Answer Relevancy Metric](./answer-relevancy) - [Hallucination Metric](./hallucination) - [Context Relevancy Metric](./context-relevancy) --- title: "Reference: Hallucination | Metrics | Evals | Mastra Docs" description: Documentation for the Hallucination Metric in Mastra, which evaluates the factual correctness of LLM outputs by identifying contradictions with provided context. --- # HallucinationMetric [EN] Source: https://mastra.ai/en/reference/evals/hallucination The `HallucinationMetric` evaluates whether an LLM generates factually correct information by comparing its output against the provided context. This metric measures hallucination by identifying direct contradictions between the context and the output. ## Basic Usage ```typescript import { openai } from "@ai-sdk/openai"; import { HallucinationMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new HallucinationMetric(model, { context: [ "Tesla was founded in 2003 by Martin Eberhard and Marc Tarpenning in San Carlos, California.", ], }); const result = await metric.measure( "Tell me about Tesla's founding.", "Tesla was founded in 2004 by Elon Musk in California.", ); console.log(result.score); // Score from 0-1 console.log(result.info.reason); // Explanation of the score // Example output: // { // score: 0.67, // info: { // reason: "The score is 0.67 because two out of three statements from the context // (founding year and founders) were contradicted by the output, while the // location statement was not contradicted." // } // } ``` ## Constructor Parameters ### HallucinationMetricOptions ## measure() Parameters ## Returns ## Scoring Details The metric evaluates hallucination through contradiction detection and unsupported claim analysis. ### Scoring Process 1. Analyzes factual content: - Extracts statements from context - Identifies numerical values and dates - Maps statement relationships 2. Analyzes output for hallucinations: - Compares against context statements - Marks direct conflicts as hallucinations - Identifies unsupported claims as hallucinations - Evaluates numerical accuracy - Considers approximation context 3. Calculates hallucination score: - Counts hallucinated statements (contradictions and unsupported claims) - Divides by total statements - Scales to configured range Final score: `(hallucinated_statements / total_statements) * scale` ### Important Considerations - Claims not present in context are treated as hallucinations - Subjective claims are hallucinations unless explicitly supported - Speculative language ("might", "possibly") about facts IN context is allowed - Speculative language about facts NOT in context is treated as hallucination - Empty outputs result in zero hallucinations - Numerical evaluation considers: - Scale-appropriate precision - Contextual approximations - Explicit precision indicators ### Score interpretation (0 to scale, default 0-1) - 1.0: Complete hallucination - contradicts all context statements - 0.75: High hallucination - contradicts 75% of context statements - 0.5: Moderate hallucination - contradicts half of context statements - 0.25: Low hallucination - contradicts 25% of context statements - 0.0: No hallucination - output aligns with all context statements **Note:** The score represents the degree of hallucination - lower scores indicate better factual alignment with the provided context ## Example with Analysis ```typescript import { openai } from "@ai-sdk/openai"; import { HallucinationMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new HallucinationMetric(model, { context: [ "OpenAI was founded in December 2015 by Sam Altman, Greg Brockman, and others.", "The company launched with a $1 billion investment commitment.", "Elon Musk was an early supporter but left the board in 2018.", ], }); const result = await metric.measure({ input: "What are the key details about OpenAI?", output: "OpenAI was founded in 2015 by Elon Musk and Sam Altman with a $2 billion investment.", }); // Example output: // { // score: 0.33, // info: { // reason: "The score is 0.33 because one out of three statements from the context // was contradicted (the investment amount was stated as $2 billion instead // of $1 billion). The founding date was correct, and while the output's // description of founders was incomplete, it wasn't strictly contradictory." // } // } ``` ## Related - [Faithfulness Metric](./faithfulness) - [Answer Relevancy Metric](./answer-relevancy) - [Context Precision Metric](./context-precision) - [Context Relevancy Metric](./context-relevancy) --- title: "Reference: Keyword Coverage | Metrics | Evals | Mastra Docs" description: Documentation for the Keyword Coverage Metric in Mastra, which evaluates how well LLM outputs cover important keywords from the input. --- # KeywordCoverageMetric [EN] Source: https://mastra.ai/en/reference/evals/keyword-coverage The `KeywordCoverageMetric` class evaluates how well an LLM's output covers the important keywords from the input. It analyzes keyword presence and matches while ignoring common words and stop words. ## Basic Usage ```typescript import { KeywordCoverageMetric } from "@mastra/evals/nlp"; const metric = new KeywordCoverageMetric(); const result = await metric.measure( "What are the key features of Python programming language?", "Python is a high-level programming language known for its simple syntax and extensive libraries.", ); console.log(result.score); // Coverage score from 0-1 console.log(result.info); // Object containing detailed metrics about keyword coverage ``` ## measure() Parameters ## Returns ## Scoring Details The metric evaluates keyword coverage by matching keywords with the following features: - Common word and stop word filtering (e.g., "the", "a", "and") - Case-insensitive matching - Word form variation handling - Special handling of technical terms and compound words ### Scoring Process 1. Processes keywords from input and output: - Filters out common words and stop words - Normalizes case and word forms - Handles special terms and compounds 2. Calculates keyword coverage: - Matches keywords between texts - Counts successful matches - Computes coverage ratio Final score: `(matched_keywords / total_keywords) * scale` ### Score interpretation (0 to scale, default 0-1) - 1.0: Perfect keyword coverage - 0.7-0.9: Good coverage with most keywords present - 0.4-0.6: Moderate coverage with some keywords missing - 0.1-0.3: Poor coverage with many keywords missing - 0.0: No keyword matches ## Examples with Analysis ```typescript import { KeywordCoverageMetric } from "@mastra/evals/nlp"; const metric = new KeywordCoverageMetric(); // Perfect coverage example const result1 = await metric.measure( "The quick brown fox jumps over the lazy dog", "A quick brown fox jumped over a lazy dog", ); // { // score: 1.0, // info: { // matchedKeywords: 6, // totalKeywords: 6 // } // } // Partial coverage example const result2 = await metric.measure( "Python features include easy syntax, dynamic typing, and extensive libraries", "Python has simple syntax and many libraries", ); // { // score: 0.67, // info: { // matchedKeywords: 4, // totalKeywords: 6 // } // } // Technical terms example const result3 = await metric.measure( "Discuss React.js component lifecycle and state management", "React components have lifecycle methods and manage state", ); // { // score: 1.0, // info: { // matchedKeywords: 4, // totalKeywords: 4 // } // } ``` ## Special Cases The metric handles several special cases: - Empty input/output: Returns score of 1.0 if both empty, 0.0 if only one is empty - Single word: Treated as a single keyword - Technical terms: Preserves compound technical terms (e.g., "React.js", "machine learning") - Case differences: "JavaScript" matches "javascript" - Common words: Ignored in scoring to focus on meaningful keywords ## Related - [Completeness Metric](./completeness) - [Content Similarity Metric](./content-similarity) - [Answer Relevancy Metric](./answer-relevancy) - [Textual Difference Metric](./textual-difference) - [Context Relevancy Metric](./context-relevancy) --- title: "Reference: Prompt Alignment | Metrics | Evals | Mastra Docs" description: Documentation for the Prompt Alignment Metric in Mastra, which evaluates how well LLM outputs adhere to given prompt instructions. --- # PromptAlignmentMetric [EN] Source: https://mastra.ai/en/reference/evals/prompt-alignment The `PromptAlignmentMetric` class evaluates how strictly an LLM's output follows a set of given prompt instructions. It uses a judge-based system to verify each instruction is followed exactly and provides detailed reasoning for any deviations. ## Basic Usage ```typescript import { openai } from "@ai-sdk/openai"; import { PromptAlignmentMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const instructions = [ "Start sentences with capital letters", "End each sentence with a period", "Use present tense", ]; const metric = new PromptAlignmentMetric(model, { instructions, scale: 1, }); const result = await metric.measure( "describe the weather", "The sun is shining. Clouds float in the sky. A gentle breeze blows.", ); console.log(result.score); // Alignment score from 0-1 console.log(result.info.reason); // Explanation of the score ``` ## Constructor Parameters ### PromptAlignmentOptions ## measure() Parameters ## Returns ## Scoring Details The metric evaluates instruction alignment through: - Applicability assessment for each instruction - Strict compliance evaluation for applicable instructions - Detailed reasoning for all verdicts - Proportional scoring based on applicable instructions ### Instruction Verdicts Each instruction receives one of three verdicts: - "yes": Instruction is applicable and completely followed - "no": Instruction is applicable but not followed or only partially followed - "n/a": Instruction is not applicable to the given context ### Scoring Process 1. Evaluates instruction applicability: - Determines if each instruction applies to the context - Marks irrelevant instructions as "n/a" - Considers domain-specific requirements 2. Assesses compliance for applicable instructions: - Evaluates each applicable instruction independently - Requires complete compliance for "yes" verdict - Documents specific reasons for all verdicts 3. Calculates alignment score: - Counts followed instructions ("yes" verdicts) - Divides by total applicable instructions (excluding "n/a") - Scales to configured range Final score: `(followed_instructions / applicable_instructions) * scale` ### Important Considerations - Empty outputs: - All formatting instructions are considered applicable - Marked as "no" since they cannot satisfy requirements - Domain-specific instructions: - Always applicable if about the queried domain - Marked as "no" if not followed, not "n/a" - "n/a" verdicts: - Only used for completely different domains - Do not affect the final score calculation ### Score interpretation (0 to scale, default 0-1) - 1.0: All applicable instructions followed perfectly - 0.7-0.9: Most applicable instructions followed - 0.4-0.6: Mixed compliance with applicable instructions - 0.1-0.3: Limited compliance with applicable instructions - 0.0: No applicable instructions followed ## Example with Analysis ```typescript import { openai } from "@ai-sdk/openai"; import { PromptAlignmentMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new PromptAlignmentMetric(model, { instructions: [ "Use bullet points for each item", "Include exactly three examples", "End each point with a semicolon" ], scale: 1 }); const result = await metric.measure( "List three fruits", "• Apple is red and sweet; • Banana is yellow and curved; • Orange is citrus and round." ); // Example output: // { // score: 1.0, // info: { // reason: "The score is 1.0 because all instructions were followed exactly: // bullet points were used, exactly three examples were provided, and // each point ends with a semicolon." // } // } const result2 = await metric.measure( "List three fruits", "1. Apple 2. Banana 3. Orange and Grape" ); // Example output: // { // score: 0.33, // info: { // reason: "The score is 0.33 because: numbered lists were used instead of bullet points, // no semicolons were used, and four fruits were listed instead of exactly three." // } // } ``` ## Related - [Answer Relevancy Metric](./answer-relevancy) - [Keyword Coverage Metric](./keyword-coverage) --- title: "Reference: Summarization | Metrics | Evals | Mastra Docs" description: Documentation for the Summarization Metric in Mastra, which evaluates the quality of LLM-generated summaries for content and factual accuracy. --- # SummarizationMetric [EN] Source: https://mastra.ai/en/reference/evals/summarization , The `SummarizationMetric` evaluates how well an LLM's summary captures the original text's content while maintaining factual accuracy. It combines two aspects: alignment (factual correctness) and coverage (inclusion of key information), using the minimum scores to ensure both qualities are necessary for a good summary. ## Basic Usage ```typescript import { openai } from "@ai-sdk/openai"; import { SummarizationMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new SummarizationMetric(model); const result = await metric.measure( "The company was founded in 1995 by John Smith. It started with 10 employees and grew to 500 by 2020. The company is based in Seattle.", "Founded in 1995 by John Smith, the company grew from 10 to 500 employees by 2020.", ); console.log(result.score); // Score from 0-1 console.log(result.info); // Object containing detailed metrics about the summary ``` ## Constructor Parameters ### SummarizationMetricOptions ## measure() Parameters ## Returns ## Scoring Details The metric evaluates summaries through two essential components: 1. **Alignment Score**: Measures factual correctness - Extracts claims from the summary - Verifies each claim against the original text - Assigns "yes", "no", or "unsure" verdicts 2. **Coverage Score**: Measures inclusion of key information - Generates key questions from the original text - Check if the summary answers these questions - Checks information inclusion and assesses comprehensiveness ### Scoring Process 1. Calculates alignment score: - Extracts claims from summary - Verifies against source text - Computes: `supported_claims / total_claims` 2. Determines coverage score: - Generates questions from source - Checks summary for answers - Evaluates completeness - Calculates: `answerable_questions / total_questions` Final score: `min(alignment_score, coverage_score) * scale` ### Score interpretation (0 to scale, default 0-1) - 1.0: Perfect summary - completely factual and covers all key information - 0.7-0.9: Strong summary with minor omissions or slight inaccuracies - 0.4-0.6: Moderate quality with significant gaps or inaccuracies - 0.1-0.3: Poor summary with major omissions or factual errors - 0.0: Invalid summary - either completely inaccurate or missing critical information ## Example with Analysis ```typescript import { openai } from "@ai-sdk/openai"; import { SummarizationMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new SummarizationMetric(model); const result = await metric.measure( "The electric car company Tesla was founded in 2003 by Martin Eberhard and Marc Tarpenning. Elon Musk joined in 2004 as the largest investor and became CEO in 2008. The company's first car, the Roadster, was launched in 2008.", "Tesla, founded by Elon Musk in 2003, revolutionized the electric car industry starting with the Roadster in 2008.", ); // Example output: // { // score: 0.5, // info: { // reason: "The score is 0.5 because while the coverage is good (0.75) - mentioning the founding year, // first car model, and launch date - the alignment score is lower (0.5) due to incorrectly // attributing the company's founding to Elon Musk instead of Martin Eberhard and Marc Tarpenning. // The final score takes the minimum of these two scores to ensure both factual accuracy and // coverage are necessary for a good summary." // alignmentScore: 0.5, // coverageScore: 0.75, // } // } ``` ## Related - [Faithfulness Metric](./faithfulness) - [Completeness Metric](./completeness) - [Contextual Recall Metric](./contextual-recall) - [Hallucination Metric](./hallucination) --- title: "Reference: Textual Difference | Evals | Mastra Docs" description: Documentation for the Textual Difference Metric in Mastra, which measures textual differences between strings using sequence matching. --- # TextualDifferenceMetric [EN] Source: https://mastra.ai/en/reference/evals/textual-difference The `TextualDifferenceMetric` class uses sequence matching to measure the textual differences between two strings. It provides detailed information about changes, including the number of operations needed to transform one text into another. ## Basic Usage ```typescript import { TextualDifferenceMetric } from "@mastra/evals/nlp"; const metric = new TextualDifferenceMetric(); const result = await metric.measure( "The quick brown fox", "The fast brown fox", ); console.log(result.score); // Similarity ratio from 0-1 console.log(result.info); // Detailed change metrics ``` ## measure() Parameters ## Returns ## Scoring Details The metric calculates several measures: - **Similarity Ratio**: Based on sequence matching between texts (0-1) - **Changes**: Count of non-matching operations needed - **Length Difference**: Normalized difference in text lengths - **Confidence**: Inversely proportional to length difference ### Scoring Process 1. Analyzes textual differences: - Performs sequence matching between input and output - Counts the number of change operations required - Measures length differences 2. Calculates metrics: - Computes similarity ratio - Determines confidence score - Combines into weighted score Final score: `(similarity_ratio * confidence) * scale` ### Score interpretation (0 to scale, default 0-1) - 1.0: Identical texts - no differences - 0.7-0.9: Minor differences - few changes needed - 0.4-0.6: Moderate differences - significant changes - 0.1-0.3: Major differences - extensive changes - 0.0: Completely different texts ## Example with Analysis ```typescript import { TextualDifferenceMetric } from "@mastra/evals/nlp"; const metric = new TextualDifferenceMetric(); const result = await metric.measure( "Hello world! How are you?", "Hello there! How is it going?", ); // Example output: // { // score: 0.65, // info: { // confidence: 0.95, // ratio: 0.65, // changes: 2, // lengthDiff: 0.05 // } // } ``` ## Related - [Content Similarity Metric](./content-similarity) - [Completeness Metric](./completeness) - [Keyword Coverage Metric](./keyword-coverage) --- title: "Reference: Tone Consistency | Metrics | Evals | Mastra Docs" description: Documentation for the Tone Consistency Metric in Mastra, which evaluates emotional tone and sentiment consistency in text. --- # ToneConsistencyMetric [EN] Source: https://mastra.ai/en/reference/evals/tone-consistency The `ToneConsistencyMetric` class evaluates the text's emotional tone and sentiment consistency. It can operate in two modes: comparing tone between input/output pairs or analyzing tone stability within a single text. ## Basic Usage ```typescript import { ToneConsistencyMetric } from "@mastra/evals/nlp"; const metric = new ToneConsistencyMetric(); // Compare tone between input and output const result1 = await metric.measure( "I love this amazing product!", "This product is wonderful and fantastic!", ); // Analyze tone stability in a single text const result2 = await metric.measure( "The service is excellent. The staff is friendly. The atmosphere is perfect.", "", // Empty string for single-text analysis ); console.log(result1.score); // Tone consistency score from 0-1 console.log(result2.score); // Tone stability score from 0-1 ``` ## measure() Parameters ## Returns ### info Object (Tone Comparison) ### info Object (Tone Stability) ## Scoring Details The metric evaluates sentiment consistency through tone pattern analysis and mode-specific scoring. ### Scoring Process 1. Analyzes tone patterns: - Extracts sentiment features - Computes sentiment scores - Measures tone variations 2. Calculates mode-specific score: **Tone Consistency** (input and output): - Compares sentiment between texts - Calculates sentiment difference - Score = 1 - (sentiment_difference / max_difference) **Tone Stability** (single input): - Analyzes sentiment across sentences - Calculates sentiment variance - Score = 1 - (sentiment_variance / max_variance) Final score: `mode_specific_score * scale` ### Score interpretation (0 to scale, default 0-1) - 1.0: Perfect tone consistency/stability - 0.7-0.9: Strong consistency with minor variations - 0.4-0.6: Moderate consistency with noticeable shifts - 0.1-0.3: Poor consistency with major tone changes - 0.0: No consistency - completely different tones ## Example with Both Modes ```typescript import { ToneConsistencyMetric } from "@mastra/evals/nlp"; const metric = new ToneConsistencyMetric(); // Tone Consistency Mode const consistencyResult = await metric.measure( "This product is fantastic and amazing!", "The product is excellent and wonderful!", ); // Example output: // { // score: 0.95, // info: { // responseSentiment: 0.8, // referenceSentiment: 0.75, // difference: 0.05 // } // } // Tone Stability Mode const stabilityResult = await metric.measure( "Great service! Friendly staff. Perfect atmosphere.", "", ); // Example output: // { // score: 0.9, // info: { // avgSentiment: 0.6, // sentimentVariance: 0.1 // } // } ``` ## Related - [Content Similarity Metric](./content-similarity) - [Toxicity Metric](./toxicity) --- title: "Reference: Toxicity | Metrics | Evals | Mastra Docs" description: Documentation for the Toxicity Metric in Mastra, which evaluates LLM outputs for racist, biased, or toxic elements. --- # ToxicityMetric [EN] Source: https://mastra.ai/en/reference/evals/toxicity The `ToxicityMetric` class evaluates whether an LLM's output contains racist, biased, or toxic elements. It uses a judge-based system to analyze responses for various forms of toxicity including personal attacks, mockery, hate speech, dismissive statements, and threats. ## Basic Usage ```typescript import { openai } from "@ai-sdk/openai"; import { ToxicityMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new ToxicityMetric(model, { scale: 1, // Default scale is 0-1 }); const result = await metric.measure( "How is Sarah as a person?", "Sarah is a dedicated team member who always delivers quality work.", ); console.log(result.score); // Score from 0-1 (0 = not toxic, 1 = toxic) console.log(result.info.reason); // Explanation of the toxicity assessment ``` ## Constructor Parameters ### ToxicityMetricOptions ## measure() Parameters ## Returns ## Scoring Details The metric evaluates toxicity through multiple aspects: - Personal attacks - Mockery or sarcasm - Hate speech - Dismissive statements - Threats or intimidation ### Scoring Process 1. Analyzes toxic elements: - Identifies personal attacks and mockery - Detects hate speech and threats - Evaluates dismissive statements - Assesses severity levels 2. Calculates toxicity score: - Weighs detected elements - Combines severity ratings - Normalizes to scale Final score: `(toxicity_weighted_sum / max_toxicity) * scale` ### Score interpretation (0 to scale, default 0-1) - 0.8-1.0: Severe toxicity - 0.4-0.7: Moderate toxicity - 0.1-0.3: Mild toxicity - 0.0: No toxic elements detected ## Example with Custom Configuration ```typescript import { openai } from "@ai-sdk/openai"; const model = openai("gpt-4o-mini"); const metric = new ToxicityMetric(model, { scale: 10, // Use 0-10 scale instead of 0-1 }); const result = await metric.measure( "What do you think about the new team member?", "The new team member shows promise but needs significant improvement in basic skills.", ); ``` ## Related - [Tone Consistency Metric](./tone-consistency) - [Bias Metric](./bias) --- title: "API Reference" description: "Mastra API Reference" --- import { ReferenceCards } from "@/components/reference-cards"; # Reference [EN] Source: https://mastra.ai/en/reference The Reference section provides documentation of Mastra's API, including parameters, types and usage examples. --- title: "Reference: .after() | Building Workflows (Legacy) | Mastra Docs" description: Documentation for the `after()` method in workflows (legacy), enabling branching and merging paths. --- # .after() [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/after The `.after()` method defines explicit dependencies between workflow steps, enabling branching and merging paths in your workflow execution. ## Usage ### Basic Branching ```typescript workflow .step(stepA) .then(stepB) .after(stepA) // Create new branch after stepA completes .step(stepC); ``` ### Merging Multiple Branches ```typescript workflow .step(stepA) .then(stepB) .step(stepC) .then(stepD) .after([stepB, stepD]) // Create a step that depends on multiple steps .step(stepE); ``` ## Parameters ## Returns ## Examples ### Single Dependency ```typescript workflow .step(fetchData) .then(processData) .after(fetchData) // Branch after fetchData .step(logData); ``` ### Multiple Dependencies (Merging Branches) ```typescript workflow .step(fetchUserData) .then(validateUserData) .step(fetchProductData) .then(validateProductData) .after([validateUserData, validateProductData]) // Wait for both validations to complete .step(processOrder); ``` ## Related - [Branching Paths example](../../examples/workflows_legacy/branching-paths.mdx) - [Workflow Class Reference](./workflow.mdx) - [Step Reference](./step-class.mdx) - [Control Flow Guide](../../docs/workflows-legacy/control-flow.mdx) --- title: ".afterEvent() Method | Mastra Docs" description: "Reference for the afterEvent method in Mastra workflows that creates event-based suspension points." --- # afterEvent() [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/afterEvent The `afterEvent()` method creates a suspension point in your workflow that waits for a specific event to occur before continuing execution. ## Syntax ```typescript workflow.afterEvent(eventName: string): Workflow ``` ## Parameters | Parameter | Type | Description | | --------- | ------ | -------------------------------------------------------------------------------------------------------- | | eventName | string | The name of the event to wait for. Must match an event defined in the workflow's `events` configuration. | ## Return Value Returns the workflow instance for method chaining. ## Description The `afterEvent()` method is used to create an automatic suspension point in your workflow that waits for a specific named event. It's essentially a declarative way to define a point where your workflow should pause and wait for an external event to occur. When you call `afterEvent()`, Mastra: 1. Creates a special step with ID `__eventName_event` 2. This step automatically suspends the workflow execution 3. The workflow remains suspended until the specified event is triggered via `resumeWithEvent()` 4. When the event occurs, execution continues with the step following the `afterEvent()` call This method is part of Mastra's event-driven workflow capabilities, allowing you to create workflows that coordinate with external systems or user interactions without manually implementing suspension logic. ## Usage Notes - The event specified in `afterEvent()` must be defined in the workflow's `events` configuration with a schema - The special step created has a predictable ID format: `__eventName_event` (e.g., `__approvalReceived_event`) - Any step following `afterEvent()` can access the event data via `context.inputData.resumedEvent` - Event data is validated against the schema defined for that event when `resumeWithEvent()` is called ## Examples ### Basic Usage ```typescript import { LegacyWorkflow } from "@mastra/core/workflows/legacy"; // Define workflow with events const workflow = new LegacyWorkflow({ name: "approval-workflow", events: { approval: { schema: z.object({ approved: z.boolean(), approverName: z.string(), }), }, }, }); // Build workflow with event suspension point workflow .step(submitRequest) .afterEvent("approval") // Workflow suspends here .step(processApproval) // This step runs after the event occurs .commit(); ``` ## Related - [Event-Driven Workflows](./events.mdx) - [resumeWithEvent()](./resumeWithEvent.mdx) - [Suspend and Resume](../../docs/workflows-legacy/suspend-and-resume.mdx) - [Workflow Class](./workflow.mdx) --- title: "Reference: Workflow.commit() | Running Workflows (Legacy) | Mastra Docs" description: Documentation for the `.commit()` method in workflows, which re-initializes the workflow machine with the current step configuration. --- # Workflow.commit() [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/commit The `.commit()` method re-initializes the workflow's state machine with the current step configuration. ## Usage ```typescript workflow.step(stepA).then(stepB).commit(); ``` ## Returns ## Related - [Branching Paths example](../../examples/workflows_legacy/branching-paths.mdx) - [Workflow Class Reference](./workflow.mdx) - [Step Reference](./step-class.mdx) - [Control Flow Guide](../../docs/workflows-legacy/control-flow.mdx) --- title: "Reference: Workflow.createRun() | Running Workflows (Legacy) | Mastra Docs" description: "Documentation for the `.createRun()` method in workflows (legacy), which initializes a new workflow run instance." --- # Workflow.createRun() [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/createRun The `.createRun()` method initializes a new workflow run instance. It generates a unique run ID for tracking and returns a start function that begins workflow execution when called. One reason to use `.createRun()` vs `.execute()` is to get a unique run ID for tracking, logging, or subscribing via `.watch()`. ## Usage ```typescript const { runId, start, watch } = workflow.createRun(); const result = await start(); ``` ## Returns Promise", description: "Function that begins workflow execution when called", }, { name: "watch", type: "(callback: (record: LegacyWorkflowResult) => void) => () => void", description: "Function that accepts a callback function that will be called with each transition of the workflow run", }, { name: "resume", type: "({stepId: string, context: Record}) => Promise", description: "Function that resumes a workflow run from a given step ID and context", }, { name: "resumeWithEvent", type: "(eventName: string, data: any) => Promise", description: "Function that resumes a workflow run from a given event name and data", }, ]} /> ## Error Handling The start function may throw validation errors if the workflow configuration is invalid: ```typescript try { const { runId, start, watch, resume, resumeWithEvent } = workflow.createRun(); await start({ triggerData: data }); } catch (error) { if (error instanceof ValidationError) { // Handle validation errors console.log(error.type); // 'circular_dependency' | 'no_terminal_path' | 'unreachable_step' console.log(error.details); } } ``` ## Related - [Workflow Class Reference](./workflow.mdx) - [Step Class Reference](./step-class.mdx) - See the [Creating a Workflow](../../examples/workflows_legacy/creating-a-workflow.mdx) example for complete usage ``` ``` --- title: "Reference: Workflow.else() | Conditional Branching | Mastra Docs" description: "Documentation for the `.else()` method in Mastra workflows, which creates an alternative branch when an if condition is false." --- # Workflow.else() [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/else > Experimental The `.else()` method creates an alternative branch in the workflow that executes when the preceding `if` condition evaluates to false. This enables workflows to follow different paths based on conditions. ## Usage ```typescript copy showLineNumbers workflow .step(startStep) .if(async ({ context }) => { const value = context.getStepResult<{ value: number }>("start")?.value; return value < 10; }) .then(ifBranchStep) .else() // Alternative branch when the condition is false .then(elseBranchStep) .commit(); ``` ## Parameters The `else()` method does not take any parameters. ## Returns ## Behavior - The `else()` method must follow an `if()` branch in the workflow definition - It creates a branch that executes only when the preceding `if` condition evaluates to false - You can chain multiple steps after an `else()` using `.then()` - You can nest additional `if`/`else` conditions within an `else` branch ## Error Handling The `else()` method requires a preceding `if()` statement. If you try to use it without a preceding `if`, an error will be thrown: ```typescript try { // This will throw an error workflow.step(someStep).else().then(anotherStep).commit(); } catch (error) { console.error(error); // "No active condition found" } ``` ## Related - [if Reference](./if.mdx) - [then Reference](./then.mdx) - [Control Flow Guide](../../docs/workflows-legacy/control-flow.mdx) - [Step Condition Reference](./step-condition.mdx) --- title: "Event-Driven Workflows (Legacy) | Mastra Docs" description: "Learn how to create event-driven workflows using afterEvent and resumeWithEvent methods in Mastra." --- # Event-Driven Workflows [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/events Mastra provides built-in support for event-driven workflows through the `afterEvent` and `resumeWithEvent` methods. These methods allow you to create workflows that pause execution while waiting for specific events to occur, then resume with the event data when it's available. ## Overview Event-driven workflows are useful for scenarios where: - You need to wait for external systems to complete processing - User approval or input is required at specific points - Asynchronous operations need to be coordinated - Long-running processes need to break up execution across different services ## Defining Events Before using event-driven methods, you must define the events your workflow will listen for in the workflow configuration: ```typescript import { LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const workflow = new LegacyWorkflow({ name: "approval-workflow", triggerSchema: z.object({ requestId: z.string() }), events: { // Define events with their validation schemas approvalReceived: { schema: z.object({ approved: z.boolean(), approverName: z.string(), comment: z.string().optional(), }), }, documentUploaded: { schema: z.object({ documentId: z.string(), documentType: z.enum(["invoice", "receipt", "contract"]), metadata: z.record(z.string()).optional(), }), }, }, }); ``` Each event must have a name and a schema that defines the structure of data expected when the event occurs. ## afterEvent() The `afterEvent` method creates a suspension point in your workflow that automatically waits for a specific event. ### Syntax ```typescript workflow.afterEvent(eventName: string): LegacyWorkflow ``` ### Parameters - `eventName`: The name of the event to wait for (must be defined in the workflow's `events` configuration) ### Return Value Returns the workflow instance for method chaining. ### How It Works When `afterEvent` is called, Mastra: 1. Creates a special step with ID `__eventName_event` 2. Configures this step to automatically suspend workflow execution 3. Sets up the continuation point after the event is received ### Usage Example ```typescript workflow .step(initialProcessStep) .afterEvent("approvalReceived") // Workflow suspends here .step(postApprovalStep) // This runs after event is received .then(finalStep) .commit(); ``` ## resumeWithEvent() The `resumeWithEvent` method resumes a suspended workflow by providing data for a specific event. ### Syntax ```typescript run.resumeWithEvent(eventName: string, data: any): Promise ``` ### Parameters - `eventName`: The name of the event being triggered - `data`: The event data (must conform to the schema defined for this event) ### Return Value Returns a Promise that resolves to the workflow execution results after resumption. ### How It Works When `resumeWithEvent` is called, Mastra: 1. Validates the event data against the schema defined for that event 2. Loads the workflow snapshot 3. Updates the context with the event data 4. Resumes execution from the event step 5. Continues workflow execution with the subsequent steps ### Usage Example ```typescript // Create a workflow run const run = workflow.createRun(); // Start the workflow await run.start({ triggerData: { requestId: "req-123" } }); // Later, when the event occurs: const result = await run.resumeWithEvent("approvalReceived", { approved: true, approverName: "John Doe", comment: "Looks good to me!", }); console.log(result.results); ``` ## Accessing Event Data When a workflow is resumed with event data, that data is available in the step context as `context.inputData.resumedEvent`: ```typescript const processApprovalStep = new LegacyStep({ id: "processApproval", execute: async ({ context }) => { // Access the event data const eventData = context.inputData.resumedEvent; return { processingResult: `Processed approval from ${eventData.approverName}`, wasApproved: eventData.approved, }; }, }); ``` ## Multiple Events You can create workflows that wait for multiple different events at various points: ```typescript workflow .step(createRequest) .afterEvent("approvalReceived") .step(processApproval) .afterEvent("documentUploaded") .step(processDocument) .commit(); ``` When resuming a workflow with multiple event suspension points, you need to provide the correct event name and data for the current suspension point. ## Practical Example This example shows a complete workflow that requires both approval and document upload: ```typescript import { LegacyWorkflow, LegacyStep } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Define steps const createRequest = new LegacyStep({ id: "createRequest", execute: async () => ({ requestId: `req-${Date.now()}` }), }); const processApproval = new LegacyStep({ id: "processApproval", execute: async ({ context }) => { const approvalData = context.inputData.resumedEvent; return { approved: approvalData.approved, approver: approvalData.approverName, }; }, }); const processDocument = new LegacyStep({ id: "processDocument", execute: async ({ context }) => { const documentData = context.inputData.resumedEvent; return { documentId: documentData.documentId, processed: true, type: documentData.documentType, }; }, }); const finalizeRequest = new LegacyStep({ id: "finalizeRequest", execute: async ({ context }) => { const requestId = context.steps.createRequest.output.requestId; const approved = context.steps.processApproval.output.approved; const documentId = context.steps.processDocument.output.documentId; return { finalized: true, summary: `Request ${requestId} was ${approved ? "approved" : "rejected"} with document ${documentId}`, }; }, }); // Create workflow const requestWorkflow = new LegacyWorkflow({ name: "document-request-workflow", events: { approvalReceived: { schema: z.object({ approved: z.boolean(), approverName: z.string(), }), }, documentUploaded: { schema: z.object({ documentId: z.string(), documentType: z.enum(["invoice", "receipt", "contract"]), }), }, }, }); // Build workflow requestWorkflow .step(createRequest) .afterEvent("approvalReceived") .step(processApproval) .afterEvent("documentUploaded") .step(processDocument) .then(finalizeRequest) .commit(); // Export workflow export { requestWorkflow }; ``` ### Running the Example Workflow ```typescript import { requestWorkflow } from "./workflows"; import { mastra } from "./mastra"; async function runWorkflow() { // Get the workflow const workflow = mastra.legacy_getWorkflow("document-request-workflow"); const run = workflow.createRun(); // Start the workflow const initialResult = await run.start(); console.log("Workflow started:", initialResult.results); // Simulate receiving approval const afterApprovalResult = await run.resumeWithEvent("approvalReceived", { approved: true, approverName: "Jane Smith", }); console.log("After approval:", afterApprovalResult.results); // Simulate document upload const finalResult = await run.resumeWithEvent("documentUploaded", { documentId: "doc-456", documentType: "invoice", }); console.log("Final result:", finalResult.results); } runWorkflow().catch(console.error); ``` ## Best Practices 1. **Define Clear Event Schemas**: Use Zod to create precise schemas for event data validation 2. **Use Descriptive Event Names**: Choose event names that clearly communicate their purpose 3. **Handle Missing Events**: Ensure your workflow can handle cases where events don't occur or time out 4. **Include Monitoring**: Use the `watch` method to monitor suspended workflows waiting for events 5. **Consider Timeouts**: Implement timeout mechanisms for events that may never occur 6. **Document Events**: Clearly document the events your workflow depends on for other developers ## Related - [Suspend and Resume in Workflows](../../docs/workflows-legacy/suspend-and-resume.mdx) - [Workflow Class Reference](./workflow.mdx) - [Resume Method Reference](./resume.mdx) - [Watch Method Reference](./watch.mdx) - [After Event Reference](./afterEvent.mdx) - [Resume With Event Reference](./resumeWithEvent.mdx) --- title: "Reference: Workflow.execute() | Workflows (Legacy) | Mastra Docs" description: "Documentation for the `.execute()` method in Mastra workflows, which runs workflow steps and returns results." --- # Workflow.execute() [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/execute Executes a workflow with the provided trigger data and returns the results. The workflow must be committed before execution. ## Usage Example ```typescript const workflow = new LegacyWorkflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); workflow.step(stepOne).then(stepTwo).commit(); const result = await workflow.execute({ triggerData: { inputValue: 42 }, }); ``` ## Parameters ## Returns ", description: "Results from each completed step", }, { name: "status", type: "WorkflowStatus", description: "Final status of the workflow run", }, ], }, ]} /> ## Additional Examples Execute with run ID: ```typescript const result = await workflow.execute({ runId: "custom-run-id", triggerData: { inputValue: 42 }, }); ``` Handle execution results: ```typescript const { runId, results, status } = await workflow.execute({ triggerData: { inputValue: 42 }, }); if (status === "COMPLETED") { console.log("Step results:", results); } ``` ### Related - [Workflow.createRun()](./createRun.mdx) - [Workflow.commit()](./commit.mdx) - [Workflow.start()](./start.mdx) --- title: "Reference: Workflow.if() | Conditional Branching | Mastra Docs" description: "Documentation for the `.if()` method in Mastra workflows, which creates conditional branches based on specified conditions." --- # Workflow.if() [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/if > Experimental The `.if()` method creates a conditional branch in the workflow, allowing steps to execute only when a specified condition is true. This enables dynamic workflow paths based on the results of previous steps. ## Usage ```typescript copy showLineNumbers workflow .step(startStep) .if(async ({ context }) => { const value = context.getStepResult<{ value: number }>("start")?.value; return value < 10; // If true, execute the "if" branch }) .then(ifBranchStep) .else() .then(elseBranchStep) .commit(); ``` ## Parameters ## Condition Types ### Function Condition You can use a function that returns a boolean: ```typescript workflow .step(startStep) .if(async ({ context }) => { const result = context.getStepResult<{ status: string }>("start"); return result?.status === "success"; // Execute "if" branch when status is "success" }) .then(successStep) .else() .then(failureStep); ``` ### Reference Condition You can use a reference-based condition with comparison operators: ```typescript workflow .step(startStep) .if({ ref: { step: startStep, path: "value" }, query: { $lt: 10 }, // Execute "if" branch when value is less than 10 }) .then(ifBranchStep) .else() .then(elseBranchStep); ``` ## Returns ## Error Handling The `if` method requires a previous step to be defined. If you try to use it without a preceding step, an error will be thrown: ```typescript try { // This will throw an error workflow .if(async ({ context }) => true) .then(someStep) .commit(); } catch (error) { console.error(error); // "Condition requires a step to be executed after" } ``` ## Related - [else Reference](./else.mdx) - [then Reference](./then.mdx) - [Control Flow Guide](../../docs/workflows-legacy/control-flow.mdx) - [Step Condition Reference](./step-condition.mdx) --- title: "Reference: run.resume() | Running Workflows (Legacy) | Mastra Docs" description: Documentation for the `.resume()` method in workflows, which continues execution of a suspended workflow step. --- # run.resume() [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/resume The `.resume()` method continues execution of a suspended workflow step, optionally providing new context data that can be accessed by the step on the inputData property. ## Usage ```typescript copy showLineNumbers await run.resume({ runId: "abc-123", stepId: "stepTwo", context: { secondValue: 100, }, }); ``` ## Parameters ### config ", description: "New context data to inject into the step's inputData property", isOptional: true, }, ]} /> ## Returns ", type: "object", description: "Result of the resumed workflow execution", }, ]} /> ## Async/Await Flow When a workflow is resumed, execution continues from the point immediately after the `suspend()` call in the step's execution function. This creates a natural flow in your code: ```typescript // Step definition with suspend point const reviewStep = new LegacyStep({ id: "review", execute: async ({ context, suspend }) => { // First part of execution const initialAnalysis = analyzeData(context.inputData.data); if (initialAnalysis.needsReview) { // Suspend execution here await suspend({ analysis: initialAnalysis }); // This code runs after resume() is called // context.inputData now contains any data provided during resume return { reviewedData: enhanceWithFeedback( initialAnalysis, context.inputData.feedback, ), }; } return { reviewedData: initialAnalysis }; }, }); const { runId, resume, start } = workflow.createRun(); await start({ inputData: { data: "some data", }, }); // Later, resume the workflow const result = await resume({ runId: "workflow-123", stepId: "review", context: { // This data will be available in `context.inputData` feedback: "Looks good, but improve section 3", }, }); ``` ### Execution Flow 1. The workflow runs until it hits `await suspend()` in the `review` step 2. The workflow state is persisted and execution pauses 3. Later, `run.resume()` is called with new context data 4. Execution continues from the point after `suspend()` in the `review` step 5. The new context data (`feedback`) is available to the step on the `inputData` property 6. The step completes and returns its result 7. The workflow continues with subsequent steps ## Error Handling The resume function may throw several types of errors: ```typescript try { await run.resume({ runId, stepId: "stepTwo", context: newData, }); } catch (error) { if (error.message === "No snapshot found for workflow run") { // Handle missing workflow state } if (error.message === "Failed to parse workflow snapshot") { // Handle corrupted workflow state } } ``` ## Related - [Suspend and Resume](../../docs/workflows-legacy/suspend-and-resume.mdx) - [`suspend` Reference](./suspend.mdx) - [`watch` Reference](./watch.mdx) - [Workflow Class Reference](./workflow.mdx) --- title: ".resumeWithEvent() Method | Mastra Docs" description: "Reference for the resumeWithEvent method that resumes suspended workflows using event data." --- # resumeWithEvent() [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/resumeWithEvent The `resumeWithEvent()` method resumes workflow execution by providing data for a specific event that the workflow is waiting for. ## Syntax ```typescript const run = workflow.createRun(); // After the workflow has started and suspended at an event step await run.resumeWithEvent(eventName: string, data: any): Promise ``` ## Parameters | Parameter | Type | Description | | --------- | ------ | ------------------------------------------------------------------------------------------------------- | | eventName | string | The name of the event to trigger. Must match an event defined in the workflow's `events` configuration. | | data | any | The event data to provide. Must conform to the schema defined for that event. | ## Return Value Returns a Promise that resolves to a `WorkflowRunResult` object, containing: - `results`: The result status and output of each step in the workflow - `activePaths`: A map of active workflow paths and their states - `value`: The current state value of the workflow - Other workflow execution metadata ## Description The `resumeWithEvent()` method is used to resume a workflow that has been suspended at an event step created by the `afterEvent()` method. When called, this method: 1. Validates the provided event data against the schema defined for that event 2. Loads the workflow snapshot from storage 3. Updates the context with the event data in the `resumedEvent` field 4. Resumes execution from the event step 5. Continues workflow execution with the subsequent steps This method is part of Mastra's event-driven workflow capabilities, allowing you to create workflows that can respond to external events or user interactions. ## Usage Notes - The workflow must be in a suspended state, specifically at the event step created by `afterEvent(eventName)` - The event data must conform to the schema defined for that event in the workflow configuration - The workflow will continue execution from the point it was suspended - If the workflow is not suspended or is suspended at a different step, this method may throw an error - The event data is made available to subsequent steps via `context.inputData.resumedEvent` ## Examples ### Basic Usage ```typescript // Define and start a workflow const workflow = mastra.legacy_getWorkflow("approval-workflow"); const run = workflow.createRun(); // Start the workflow await run.start({ triggerData: { requestId: "req-123" } }); // Later, when the approval event occurs: const result = await run.resumeWithEvent("approval", { approved: true, approverName: "John Doe", comment: "Looks good to me!", }); console.log(result.results); ``` ### With Error Handling ```typescript try { const result = await run.resumeWithEvent("paymentReceived", { amount: 100.5, transactionId: "tx-456", paymentMethod: "credit-card", }); console.log("Workflow resumed successfully:", result.results); } catch (error) { console.error("Failed to resume workflow with event:", error); // Handle error - could be invalid event data, workflow not suspended, etc. } ``` ### Monitoring and Auto-Resuming ```typescript // Start a workflow const { start, watch, resumeWithEvent } = workflow.createRun(); // Watch for suspended event steps watch(async ({ activePaths }) => { const isApprovalEventSuspended = activePaths.get("__approval_event")?.status === "suspended"; // Check if suspended at the approval event step if (isApprovalEventSuspended) { console.log("Workflow waiting for approval"); // In a real scenario, you would wait for the actual event // Here we're simulating with a timeout setTimeout(async () => { try { await resumeWithEvent("approval", { approved: true, approverName: "Auto Approver", }); } catch (error) { console.error("Failed to auto-resume workflow:", error); } }, 5000); // Wait 5 seconds before auto-approving } }); // Start the workflow await start({ triggerData: { requestId: "auto-123" } }); ``` ## Related - [Event-Driven Workflows](./events.mdx) - [afterEvent()](./afterEvent.mdx) - [Suspend and Resume](../../docs/workflows-legacy/suspend-and-resume.mdx) - [resume()](./resume.mdx) - [watch()](./watch.mdx) --- title: "Reference: Snapshots | Workflow State Persistence (Legacy) | Mastra Docs" description: "Technical reference on snapshots in Mastra - the serialized workflow state that enables suspend and resume functionality" --- # Snapshots [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/snapshots In Mastra, a snapshot is a serializable representation of a workflow's complete execution state at a specific point in time. Snapshots capture all the information needed to resume a workflow from exactly where it left off, including: - The current state of each step in the workflow - The outputs of completed steps - The execution path taken through the workflow - Any suspended steps and their metadata - The remaining retry attempts for each step - Additional contextual data needed to resume execution Snapshots are automatically created and managed by Mastra whenever a workflow is suspended, and are persisted to the configured storage system. ## The Role of Snapshots in Suspend and Resume Snapshots are the key mechanism enabling Mastra's suspend and resume capabilities. When a workflow step calls `await suspend()`: 1. The workflow execution is paused at that exact point 2. The current state of the workflow is captured as a snapshot 3. The snapshot is persisted to storage 4. The workflow step is marked as "suspended" with a status of `'suspended'` 5. Later, when `resume()` is called on the suspended step, the snapshot is retrieved 6. The workflow execution resumes from exactly where it left off This mechanism provides a powerful way to implement human-in-the-loop workflows, handle rate limiting, wait for external resources, and implement complex branching workflows that may need to pause for extended periods. ## Snapshot Anatomy A Mastra workflow snapshot consists of several key components: ```typescript export interface LegacyWorkflowRunState { // Core state info value: Record; // Current state machine value context: { // Workflow context steps: Record< string, { // Step execution results status: "success" | "failed" | "suspended" | "waiting" | "skipped"; payload?: any; // Step-specific data error?: string; // Error info if failed } >; triggerData: Record; // Initial trigger data attempts: Record; // Remaining retry attempts inputData: Record; // Initial input data }; activePaths: Array<{ // Currently active execution paths stepPath: string[]; stepId: string; status: string; }>; // Metadata runId: string; // Unique run identifier timestamp: number; // Time snapshot was created // For nested workflows and suspended steps childStates?: Record; // Child workflow states suspendedSteps?: Record; // Mapping of suspended steps } ``` ## How Snapshots Are Saved and Retrieved Mastra persists snapshots to the configured storage system. By default, snapshots are saved to a LibSQL database, but can be configured to use other storage providers like Upstash. The snapshots are stored in the `workflow_snapshots` table and identified uniquely by the `run_id` for the associated run when using libsql. Utilizing a persistence layer allows for the snapshots to be persisted across workflow runs, allowing for advanced human-in-the-loop functionality. Read more about [libsql storage](../storage/libsql.mdx) and [upstash storage](../storage/upstash.mdx) here. ### Saving Snapshots When a workflow is suspended, Mastra automatically persists the workflow snapshot with these steps: 1. The `suspend()` function in a step execution triggers the snapshot process 2. The `WorkflowInstance.suspend()` method records the suspended machine 3. `persistWorkflowSnapshot()` is called to save the current state 4. The snapshot is serialized and stored in the configured database in the `workflow_snapshots` table 5. The storage record includes the workflow name, run ID, and the serialized snapshot ### Retrieving Snapshots When a workflow is resumed, Mastra retrieves the persisted snapshot with these steps: 1. The `resume()` method is called with a specific step ID 2. The snapshot is loaded from storage using `loadWorkflowSnapshot()` 3. The snapshot is parsed and prepared for resumption 4. The workflow execution is recreated with the snapshot state 5. The suspended step is resumed, and execution continues ## Storage Options for Snapshots Mastra provides multiple storage options for persisting snapshots. A `storage` instance is configured on the `Mastra` class, and is used to setup a snapshot persistence layer for all workflows registered on the `Mastra` instance. This means that storage is shared across all workflows registered with the same `Mastra` instance. ### LibSQL (Default) The default storage option is LibSQL, a SQLite-compatible database: ```typescript import { Mastra } from "@mastra/core/mastra"; import { DefaultStorage } from "@mastra/core/storage/libsql"; const mastra = new Mastra({ storage: new DefaultStorage({ config: { url: "file:storage.db", // Local file-based database // For production: // url: process.env.DATABASE_URL, // authToken: process.env.DATABASE_AUTH_TOKEN, }, }), legacy_workflows: { weatherWorkflow, travelWorkflow, }, }); ``` ### Upstash (Redis-Compatible) For serverless environments: ```typescript import { Mastra } from "@mastra/core/mastra"; import { UpstashStore } from "@mastra/upstash"; const mastra = new Mastra({ storage: new UpstashStore({ url: process.env.UPSTASH_URL, token: process.env.UPSTASH_TOKEN, }), workflows: { weatherWorkflow, travelWorkflow, }, }); ``` ## Best Practices for Working with Snapshots 1. **Ensure Serializability**: Any data that needs to be included in the snapshot must be serializable (convertible to JSON). 2. **Minimize Snapshot Size**: Avoid storing large data objects directly in the workflow context. Instead, store references to them (like IDs) and retrieve the data when needed. 3. **Handle Resume Context Carefully**: When resuming a workflow, carefully consider what context to provide. This will be merged with the existing snapshot data. 4. **Set Up Proper Monitoring**: Implement monitoring for suspended workflows, especially long-running ones, to ensure they are properly resumed. 5. **Consider Storage Scaling**: For applications with many suspended workflows, ensure your storage solution is appropriately scaled. ## Advanced Snapshot Patterns ### Custom Snapshot Metadata When suspending a workflow, you can include custom metadata that can help when resuming: ```typescript await suspend({ reason: "Waiting for customer approval", requiredApprovers: ["manager", "finance"], requestedBy: currentUser, urgency: "high", expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), }); ``` This metadata is stored with the snapshot and available when resuming. ### Conditional Resumption You can implement conditional logic based on the suspend payload when resuming: ```typescript run.watch(async ({ activePaths }) => { const isApprovalStepSuspended = activePaths.get("approval")?.status === "suspended"; if (isApprovalStepSuspended) { const payload = activePaths.get("approval")?.suspendPayload; if (payload.urgency === "high" && currentUser.role === "manager") { await resume({ stepId: "approval", context: { approved: true, approver: currentUser.id }, }); } } }); ``` ## Related - [Suspend Function Reference](./suspend.mdx) - [Resume Function Reference](./resume.mdx) - [Watch Function Reference](./watch.mdx) - [Suspend and Resume Guide](../../docs/workflows-legacy/suspend-and-resume.mdx) --- title: "Reference: start() | Running Workflows (Legacy) | Mastra Docs" description: "Documentation for the `start()` method in workflows, which begins execution of a workflow run." --- # start() [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/start The start function begins execution of a workflow run. It processes all steps in the defined workflow order, handling parallel execution, branching logic, and step dependencies. ## Usage ```typescript copy showLineNumbers const { runId, start } = workflow.createRun(); const result = await start({ triggerData: { inputValue: 42 }, }); ``` ## Parameters ### config ", description: "Initial data that matches the workflow's triggerSchema", isOptional: false, }, ]} /> ## Returns ", description: "Combined output from all completed workflow steps", }, { name: "status", type: "'completed' | 'error' | 'suspended'", description: "Final status of the workflow run", }, ]} /> ## Error Handling The start function may throw several types of validation errors: ```typescript copy showLineNumbers try { const result = await start({ triggerData: data }); } catch (error) { if (error instanceof ValidationError) { console.log(error.type); // 'circular_dependency' | 'no_terminal_path' | 'unreachable_step' console.log(error.details); } } ``` ## Related - [Example: Creating a Workflow](../../examples/workflows_legacy/creating-a-workflow.mdx) - [Example: Suspend and Resume](../../examples/workflows_legacy/suspend-and-resume.mdx) - [createRun Reference](./createRun.mdx) - [Workflow Class Reference](./workflow.mdx) - [Step Class Reference](./step-class.mdx) ``` ``` --- title: "Reference: Step | Building Workflows (Legacy) | Mastra Docs" description: Documentation for the Step class, which defines individual units of work within a workflow. --- # Step [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/step-class The Step class defines individual units of work within a workflow, encapsulating execution logic, data validation, and input/output handling. ## Usage ```typescript const processOrder = new LegacyStep({ id: "processOrder", inputSchema: z.object({ orderId: z.string(), userId: z.string(), }), outputSchema: z.object({ status: z.string(), orderId: z.string(), }), execute: async ({ context, runId }) => { return { status: "processed", orderId: context.orderId, }; }, }); ``` ## Constructor Parameters ", description: "Static data to be merged with variables", required: false, }, { name: "execute", type: "(params: ExecuteParams) => Promise", description: "Async function containing step logic", required: true, }, ]} /> ### ExecuteParams Promise", description: "Function to suspend step execution", }, { name: "mastra", type: "Mastra", description: "Access to Mastra instance", }, ]} /> ## Related - [Workflow Reference](./workflow.mdx) - [Step Configuration Guide](../../docs/workflows-legacy/steps.mdx) - [Control Flow Guide](../../docs/workflows-legacy/control-flow.mdx) --- title: "Reference: StepCondition | Building Workflows (Legacy) | Mastra" description: Documentation for the step condition class in workflows, which determines whether a step should execute based on the output of previous steps or trigger data. --- # StepCondition [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/step-condition Conditions determine whether a step should execute based on the output of previous steps or trigger data. ## Usage There are three ways to specify conditions: function, query object, and simple path comparison. ### 1. Function Condition ```typescript copy showLineNumbers workflow.step(processOrder, { when: async ({ context }) => { const auth = context?.getStepResult<{ status: string }>("auth"); return auth?.status === "authenticated"; }, }); ``` ### 2. Query Object ```typescript copy showLineNumbers workflow.step(processOrder, { when: { ref: { step: "auth", path: "status" }, query: { $eq: "authenticated" }, }, }); ``` ### 3. Simple Path Comparison ```typescript copy showLineNumbers workflow.step(processOrder, { when: { "auth.status": "authenticated", }, }); ``` Based on the type of condition, the workflow runner will try to match the condition to one of these types. 1. Simple Path Condition (when there's a dot in the key) 2. Base/Query Condition (when there's a 'ref' property) 3. Function Condition (when it's an async function) ## StepCondition ", description: "MongoDB-style query using sift operators ($eq, $gt, etc)", isOptional: false, }, ]} /> ## Query The Query object provides MongoDB-style query operators for comparing values from previous steps or trigger data. It supports basic comparison operators like `$eq`, `$gt`, `$lt` as well as array operators like `$in` and `$nin`, and can be combined with and/or operators for complex conditions. This query syntax allows for readable conditional logic for determining whether a step should execute. ## Related - [Step Options Reference](./step-options.mdx) - [Step Function Reference](./step-function.mdx) - [Control Flow Guide](../../docs/workflows-legacy/control-flow.mdx) --- title: "Reference: Workflow.step() | Workflows (Legacy) | Mastra Docs" description: Documentation for the `.step()` method in workflows, which adds a new step to the workflow. --- # Workflow.step() [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/step-function The `.step()` method adds a new step to the workflow, optionally configuring its variables and execution conditions. ## Usage ```typescript workflow.step({ id: "stepTwo", outputSchema: z.object({ result: z.number(), }), execute: async ({ context }) => { return { result: 42 }; }, }); ``` ## Parameters ### StepDefinition Promise", description: "Function containing step logic", isOptional: false, }, ]} /> ### StepOptions ", description: "Map of variable names to their source references", isOptional: true, }, { name: "when", type: "StepCondition", description: "Condition that must be met for step to execute", isOptional: true, }, ]} /> ## Related - [Basic Usage with Step Instance](../../docs/workflows-legacy/steps.mdx) - [Step Class Reference](./step-class.mdx) - [Workflow Class Reference](./workflow.mdx) - [Control Flow Guide](../../docs/workflows-legacy/control-flow.mdx) --- title: "Reference: StepOptions | Building Workflows (Legacy) | Mastra Docs" description: Documentation for the step options in workflows, which control variable mapping, execution conditions, and other runtime behavior. --- # StepOptions [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/step-options Configuration options for workflow steps that control variable mapping, execution conditions, and other runtime behavior. ## Usage ```typescript workflow.step(processOrder, { variables: { orderId: { step: "trigger", path: "id" }, userId: { step: "auth", path: "user.id" }, }, when: { ref: { step: "auth", path: "status" }, query: { $eq: "authenticated" }, }, }); ``` ## Properties ", description: "Maps step input variables to values from other steps", isOptional: true, }, { name: "when", type: "StepCondition", description: "Condition that must be met for step execution", isOptional: true, }, ]} /> ### VariableRef ## Related - [Path Comparison](../../docs/workflows-legacy/control-flow.mdx) - [Step Function Reference](./step-function.mdx) - [Step Class Reference](./step-class.mdx) - [Workflow Class Reference](./workflow.mdx) - [Control Flow Guide](../../docs/workflows-legacy/control-flow.mdx) --- title: "Step Retries | Error Handling | Mastra Docs" description: "Automatically retry failed steps in Mastra workflows with configurable retry policies." --- # Step Retries [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/step-retries Mastra provides built-in retry mechanisms to handle transient failures in workflow steps. This allows workflows to recover gracefully from temporary issues without requiring manual intervention. ## Overview When a step in a workflow fails (throws an exception), Mastra can automatically retry the step execution based on a configurable retry policy. This is useful for handling: - Network connectivity issues - Service unavailability - Rate limiting - Temporary resource constraints - Other transient failures ## Default Behavior By default, steps do not retry when they fail. This means: - A step will execute once - If it fails, it will immediately mark the step as failed - The workflow will continue to execute any subsequent steps that don't depend on the failed step ## Configuration Options Retries can be configured at two levels: ### 1. Workflow-level Configuration You can set a default retry configuration for all steps in a workflow: ```typescript const workflow = new LegacyWorkflow({ name: "my-workflow", retryConfig: { attempts: 3, // Number of retries (in addition to the initial attempt) delay: 1000, // Delay between retries in milliseconds }, }); ``` ### 2. Step-level Configuration You can also configure retries on individual steps, which will override the workflow-level configuration for that specific step: ```typescript const fetchDataStep = new LegacyStep({ id: "fetchData", execute: async () => { // Fetch data from external API }, retryConfig: { attempts: 5, // This step will retry up to 5 times delay: 2000, // With a 2-second delay between retries }, }); ``` ## Retry Parameters The `retryConfig` object supports the following parameters: | Parameter | Type | Default | Description | | ---------- | ------ | ------- | ----------------------------------------------------------------- | | `attempts` | number | 0 | The number of retry attempts (in addition to the initial attempt) | | `delay` | number | 1000 | Time in milliseconds to wait between retries | ## How Retries Work When a step fails, Mastra's retry mechanism: 1. Checks if the step has retry attempts remaining 2. If attempts remain: - Decrements the attempt counter - Transitions the step to a "waiting" state - Waits for the configured delay period - Retries the step execution 3. If no attempts remain or all attempts have been exhausted: - Marks the step as "failed" - Continues workflow execution (for steps that don't depend on the failed step) During retry attempts, the workflow execution remains active but paused for the specific step that is being retried. ## Examples ### Basic Retry Example ```typescript import { LegacyWorkflow, LegacyStep } from "@mastra/core/workflows/legacy"; // Define a step that might fail const unreliableApiStep = new LegacyStep({ id: "callUnreliableApi", execute: async () => { // Simulate an API call that might fail const random = Math.random(); if (random < 0.7) { throw new Error("API call failed"); } return { data: "API response data" }; }, retryConfig: { attempts: 3, // Retry up to 3 times delay: 2000, // Wait 2 seconds between attempts }, }); // Create a workflow with the unreliable step const workflow = new LegacyWorkflow({ name: "retry-demo-workflow", }); workflow.step(unreliableApiStep).then(processResultStep).commit(); ``` ### Workflow-level Retries with Step Override ```typescript import { LegacyWorkflow, LegacyStep } from "@mastra/core/workflows/legacy"; // Create a workflow with default retry configuration const workflow = new LegacyWorkflow({ name: "multi-retry-workflow", retryConfig: { attempts: 2, // All steps will retry twice by default delay: 1000, // With a 1-second delay }, }); // This step uses the workflow's default retry configuration const standardStep = new LegacyStep({ id: "standardStep", execute: async () => { // Some operation that might fail }, }); // This step overrides the workflow's retry configuration const criticalStep = new LegacyStep({ id: "criticalStep", execute: async () => { // Critical operation that needs more retry attempts }, retryConfig: { attempts: 5, // Override with 5 retry attempts delay: 5000, // And a longer 5-second delay }, }); // This step disables retries const noRetryStep = new LegacyStep({ id: "noRetryStep", execute: async () => { // Operation that should not retry }, retryConfig: { attempts: 0, // Explicitly disable retries }, }); workflow.step(standardStep).then(criticalStep).then(noRetryStep).commit(); ``` ## Monitoring Retries You can monitor retry attempts in your logs. Mastra logs retry-related events at the `debug` level: ``` [DEBUG] Step fetchData failed (runId: abc-123) [DEBUG] Attempt count for step fetchData: 2 remaining attempts (runId: abc-123) [DEBUG] Step fetchData waiting (runId: abc-123) [DEBUG] Step fetchData finished waiting (runId: abc-123) [DEBUG] Step fetchData pending (runId: abc-123) ``` ## Best Practices 1. **Use Retries for Transient Failures**: Only configure retries for operations that might experience transient failures. For deterministic errors (like validation failures), retries won't help. 2. **Set Appropriate Delays**: Consider using longer delays for external API calls to allow time for services to recover. 3. **Limit Retry Attempts**: Don't set extremely high retry counts as this could cause workflows to run for excessive periods during outages. 4. **Implement Idempotent Operations**: Ensure your step's `execute` function is idempotent (can be called multiple times without side effects) since it may be retried. 5. **Consider Backoff Strategies**: For more advanced scenarios, consider implementing exponential backoff in your step's logic for operations that might be rate-limited. ## Related - [Step Class Reference](./step-class.mdx) - [Workflow Configuration](./workflow.mdx) - [Error Handling in Workflows](../../docs/workflows-legacy/error-handling.mdx) --- title: "Reference: suspend() | Control Flow | Mastra Docs" description: "Documentation for the suspend function in Mastra workflows, which pauses execution until resumed." --- # suspend() [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/suspend Pauses workflow execution at the current step until explicitly resumed. The workflow state is persisted and can be continued later. ## Usage Example ```typescript const approvalStep = new LegacyStep({ id: "needsApproval", execute: async ({ context, suspend }) => { if (context.steps.amount > 1000) { await suspend(); } return { approved: true }; }, }); ``` ## Parameters ", description: "Optional data to store with the suspended state", isOptional: true, }, ]} /> ## Returns ", type: "Promise", description: "Resolves when the workflow is successfully suspended", }, ]} /> ## Additional Examples Suspend with metadata: ```typescript const reviewStep = new LegacyStep({ id: "review", execute: async ({ context, suspend }) => { await suspend({ reason: "Needs manager approval", requestedBy: context.user, }); return { reviewed: true }; }, }); ``` ### Related - [Suspend & Resume Workflows](../../docs/workflows-legacy/suspend-and-resume.mdx) - [.resume()](./resume.mdx) - [.watch()](./watch.mdx) --- title: "Reference: Workflow.then() | Building Workflows (Legacy) | Mastra Docs" description: Documentation for the `.then()` method in workflows, which creates sequential dependencies between steps. --- # Workflow.then() [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/then The `.then()` method creates a sequential dependency between workflow steps, ensuring steps execute in a specific order. ## Usage ```typescript workflow.step(stepOne).then(stepTwo).then(stepThree); ``` ## Parameters ## Returns ## Validation When using `then`: - The previous step must exist in the workflow - Steps cannot form circular dependencies - Each step can only appear once in a sequential chain ## Error Handling ```typescript try { workflow .step(stepA) .then(stepB) .then(stepA) // Will throw error - circular dependency .commit(); } catch (error) { if (error instanceof ValidationError) { console.log(error.type); // 'circular_dependency' console.log(error.details); } } ``` ## Related - [step Reference](./step-class.mdx) - [after Reference](./after.mdx) - [Sequential Steps Example](../../examples/workflows_legacy/sequential-steps.mdx) - [Control Flow Guide](../../docs/workflows-legacy/control-flow.mdx) --- title: "Reference: Workflow.until() | Looping in Workflows (Legacy) | Mastra Docs" description: "Documentation for the `.until()` method in Mastra workflows, which repeats a step until a specified condition becomes true." --- # Workflow.until() [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/until The `.until()` method repeats a step until a specified condition becomes true. This creates a loop that continues executing the specified step until the condition is satisfied. ## Usage ```typescript workflow.step(incrementStep).until(condition, incrementStep).then(finalStep); ``` ## Parameters ## Condition Types ### Function Condition You can use a function that returns a boolean: ```typescript workflow .step(incrementStep) .until(async ({ context }) => { const result = context.getStepResult<{ value: number }>("increment"); return (result?.value ?? 0) >= 10; // Stop when value reaches or exceeds 10 }, incrementStep) .then(finalStep); ``` ### Reference Condition You can use a reference-based condition with comparison operators: ```typescript workflow .step(incrementStep) .until( { ref: { step: incrementStep, path: "value" }, query: { $gte: 10 }, // Stop when value is greater than or equal to 10 }, incrementStep, ) .then(finalStep); ``` ## Comparison Operators When using reference-based conditions, you can use these comparison operators: | Operator | Description | Example | | -------- | ------------------------ | -------------- | | `$eq` | Equal to | `{ $eq: 10 }` | | `$ne` | Not equal to | `{ $ne: 0 }` | | `$gt` | Greater than | `{ $gt: 5 }` | | `$gte` | Greater than or equal to | `{ $gte: 10 }` | | `$lt` | Less than | `{ $lt: 20 }` | | `$lte` | Less than or equal to | `{ $lte: 15 }` | ## Returns ## Example ```typescript import { LegacyWorkflow, LegacyStep } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Create a step that increments a counter const incrementStep = new LegacyStep({ id: "increment", description: "Increments the counter by 1", outputSchema: z.object({ value: z.number(), }), execute: async ({ context }) => { // Get current value from previous execution or start at 0 const currentValue = context.getStepResult<{ value: number }>("increment")?.value || context.getStepResult<{ startValue: number }>("trigger")?.startValue || 0; // Increment the value const value = currentValue + 1; console.log(`Incrementing to ${value}`); return { value }; }, }); // Create a final step const finalStep = new LegacyStep({ id: "final", description: "Final step after loop completes", execute: async ({ context }) => { const finalValue = context.getStepResult<{ value: number }>( "increment", )?.value; console.log(`Loop completed with final value: ${finalValue}`); return { finalValue }; }, }); // Create the workflow const counterWorkflow = new LegacyWorkflow({ name: "counter-workflow", triggerSchema: z.object({ startValue: z.number(), targetValue: z.number(), }), }); // Configure the workflow with an until loop counterWorkflow .step(incrementStep) .until(async ({ context }) => { const targetValue = context.triggerData.targetValue; const currentValue = context.getStepResult<{ value: number }>("increment")?.value ?? 0; return currentValue >= targetValue; }, incrementStep) .then(finalStep) .commit(); // Execute the workflow const run = counterWorkflow.createRun(); const result = await run.start({ triggerData: { startValue: 0, targetValue: 5 }, }); // Will increment from 0 to 5, then stop and execute finalStep ``` ## Related - [.while()](./while.mdx) - Loop while a condition is true - [Control Flow Guide](../../docs/workflows-legacy/control-flow.mdx) - [Workflow Class Reference](./workflow.mdx) --- title: "Reference: run.watch() | Workflows (Legacy) | Mastra Docs" description: Documentation for the `.watch()` method in workflows, which monitors the status of a workflow run. --- # run.watch() [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/watch The `.watch()` function subscribes to state changes on a mastra run, allowing you to monitor execution progress and react to state updates. ## Usage Example ```typescript import { LegacyWorkflow } from "@mastra/core/workflows/legacy"; const workflow = new LegacyWorkflow({ name: "document-processor", }); const run = workflow.createRun(); // Subscribe to state changes const unsubscribe = run.watch(({ results, activePaths }) => { console.log("Results:", results); console.log("Active paths:", activePaths); }); // Run the workflow await run.start({ input: { text: "Process this document" }, }); // Stop watching unsubscribe(); ``` ## Parameters void", description: "Function called whenever the workflow state changes", isOptional: false, }, ]} /> ### LegacyWorkflowState Properties ", description: "Outputs from completed workflow steps", isOptional: false, }, { name: "activePaths", type: "Map", description: "Current status of each step", isOptional: false, }, { name: "runId", type: "string", description: "ID of the workflow run", isOptional: false, }, { name: "timestamp", type: "number", description: "Timestamp of the workflow run", isOptional: false, }, ]} /> ## Returns void", description: "Function to stop watching workflow state changes", }, ]} /> ## Additional Examples Monitor specific step completion: ```typescript run.watch(({ results, activePaths }) => { if (activePaths.get("processDocument")?.status === "completed") { console.log( "Document processing output:", results["processDocument"].output, ); } }); ``` Error handling: ```typescript run.watch(({ results, activePaths }) => { if (activePaths.get("processDocument")?.status === "failed") { console.error( "Document processing failed:", results["processDocument"].error, ); // Implement error recovery logic } }); ``` ### Related - [Workflow Creation](./createRun.mdx) - [Step Configuration](./step-class.mdx) --- title: "Reference: Workflow.while() | Looping in Workflows (Legacy) | Mastra Docs" description: "Documentation for the `.while()` method in Mastra workflows, which repeats a step as long as a specified condition remains true." --- # Workflow.while() [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/while The `.while()` method repeats a step as long as a specified condition remains true. This creates a loop that continues executing the specified step until the condition becomes false. ## Usage ```typescript workflow.step(incrementStep).while(condition, incrementStep).then(finalStep); ``` ## Parameters ## Condition Types ### Function Condition You can use a function that returns a boolean: ```typescript workflow .step(incrementStep) .while(async ({ context }) => { const result = context.getStepResult<{ value: number }>("increment"); return (result?.value ?? 0) < 10; // Continue as long as value is less than 10 }, incrementStep) .then(finalStep); ``` ### Reference Condition You can use a reference-based condition with comparison operators: ```typescript workflow .step(incrementStep) .while( { ref: { step: incrementStep, path: "value" }, query: { $lt: 10 }, // Continue as long as value is less than 10 }, incrementStep, ) .then(finalStep); ``` ## Comparison Operators When using reference-based conditions, you can use these comparison operators: | Operator | Description | Example | | -------- | ------------------------ | -------------- | | `$eq` | Equal to | `{ $eq: 10 }` | | `$ne` | Not equal to | `{ $ne: 0 }` | | `$gt` | Greater than | `{ $gt: 5 }` | | `$gte` | Greater than or equal to | `{ $gte: 10 }` | | `$lt` | Less than | `{ $lt: 20 }` | | `$lte` | Less than or equal to | `{ $lte: 15 }` | ## Returns ## Example ```typescript import { LegacyWorkflow, LegacyStep } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Create a step that increments a counter const incrementStep = new LegacyStep({ id: "increment", description: "Increments the counter by 1", outputSchema: z.object({ value: z.number(), }), execute: async ({ context }) => { // Get current value from previous execution or start at 0 const currentValue = context.getStepResult<{ value: number }>("increment")?.value || context.getStepResult<{ startValue: number }>("trigger")?.startValue || 0; // Increment the value const value = currentValue + 1; console.log(`Incrementing to ${value}`); return { value }; }, }); // Create a final step const finalStep = new LegacyStep({ id: "final", description: "Final step after loop completes", execute: async ({ context }) => { const finalValue = context.getStepResult<{ value: number }>( "increment", )?.value; console.log(`Loop completed with final value: ${finalValue}`); return { finalValue }; }, }); // Create the workflow const counterWorkflow = new LegacyWorkflow({ name: "counter-workflow", triggerSchema: z.object({ startValue: z.number(), targetValue: z.number(), }), }); // Configure the workflow with a while loop counterWorkflow .step(incrementStep) .while(async ({ context }) => { const targetValue = context.triggerData.targetValue; const currentValue = context.getStepResult<{ value: number }>("increment")?.value ?? 0; return currentValue < targetValue; }, incrementStep) .then(finalStep) .commit(); // Execute the workflow const run = counterWorkflow.createRun(); const result = await run.start({ triggerData: { startValue: 0, targetValue: 5 }, }); // Will increment from 0 to 4, then stop and execute finalStep ``` ## Related - [.until()](./until.mdx) - Loop until a condition becomes true - [Control Flow Guide](../../docs/workflows-legacy/control-flow.mdx) - [Workflow Class Reference](./workflow.mdx) --- title: "Reference: Workflow Class | Building Workflows (Legacy) | Mastra Docs" description: Documentation for the Workflow class in Mastra, which enables you to create state machines for complex sequences of operations with conditional branching and data validation. --- # Workflow Class [EN] Source: https://mastra.ai/en/reference/legacyWorkflows/workflow The Workflow class enables you to create state machines for complex sequences of operations with conditional branching and data validation. ```ts copy import { LegacyWorkflow } from "@mastra/core/workflows/legacy"; const workflow = new LegacyWorkflow({ name: "my-workflow" }); ``` ## API Reference ### Constructor ", isOptional: true, description: "Optional logger instance for workflow execution details", }, { name: "steps", type: "Step[]", description: "Array of steps to include in the workflow", }, { name: "triggerSchema", type: "z.Schema", description: "Optional schema for validating workflow trigger data", }, ]} /> ### Core Methods #### `step()` Adds a [Step](./step-class.mdx) to the workflow, including transitions to other steps. Returns the workflow instance for chaining. [Learn more about steps](./step-class.mdx). #### `commit()` Validates and finalizes the workflow configuration. Must be called after adding all steps. #### `execute()` Executes the workflow with optional trigger data. Typed based on the [trigger schema](./workflow.mdx#trigger-schemas). ## Trigger Schemas Trigger schemas validate the initial data passed to a workflow using Zod. ```ts showLineNumbers copy const workflow = new LegacyWorkflow({ name: "order-process", triggerSchema: z.object({ orderId: z.string(), customer: z.object({ id: z.string(), email: z.string().email(), }), }), }); ``` The schema: - Validates data passed to `execute()` - Provides TypeScript types for your workflow input ## Validation Workflow validation happens at two key times: ### 1. At Commit Time When you call `.commit()`, the workflow validates: ```ts showLineNumbers copy workflow .step('step1', {...}) .step('step2', {...}) .commit(); // Validates workflow structure ``` - Circular dependencies between steps - Terminal paths (every path must end) - Unreachable steps - Variable references to non-existent steps - Duplicate step IDs ### 2. During Execution When you call `start()`, it validates: ```ts showLineNumbers copy const { runId, start } = workflow.createRun(); // Validates trigger data against schema await start({ triggerData: { orderId: "123", customer: { id: "cust_123", email: "invalid-email", // Will fail validation }, }, }); ``` - Trigger data against trigger schema - Each step's input data against its inputSchema - Variable paths exist in referenced step outputs - Required variables are present ## Workflow Status A workflow's status indicates its current execution state. The possible values are: ### Example: Handling Different Statuses ```typescript showLineNumbers copy const { runId, start, watch } = workflow.createRun(); watch(async ({ status }) => { switch (status) { case "SUSPENDED": // Handle suspended state break; case "COMPLETED": // Process results break; case "FAILED": // Handle error state break; } }); await start({ triggerData: data }); ``` ## Error Handling ```ts showLineNumbers copy try { const { runId, start, watch, resume } = workflow.createRun(); await start({ triggerData: data }); } catch (error) { if (error instanceof ValidationError) { // Handle validation errors console.log(error.type); // 'circular_dependency' | 'no_terminal_path' | 'unreachable_step' console.log(error.details); // { stepId?: string, path?: string[] } } } ``` ## Passing Context Between Steps Steps can access data from previous steps in the workflow through the context object. Each step receives the accumulated context from all previous steps that have executed. ```typescript showLineNumbers copy workflow .step({ id: "getData", execute: async ({ context }) => { return { data: { id: "123", value: "example" }, }; }, }) .step({ id: "processData", execute: async ({ context }) => { // Access data from previous step through context.steps const previousData = context.steps.getData.output.data; // Process previousData.id and previousData.value }, }); ``` The context object: - Contains results from all completed steps in `context.steps` - Provides access to step outputs through `context.steps.[stepId].output` - Is typed based on step output schemas - Is immutable to ensure data consistency ## Related Documentation - [Step](./step-class.mdx) - [.then()](./then.mdx) - [.step()](./step-function.mdx) - [.after()](./after.mdx) # Memory Class Reference [EN] Source: https://mastra.ai/en/reference/memory/Memory The `Memory` class provides a robust system for managing conversation history and thread-based message storage in Mastra. It enables persistent storage of conversations, semantic search capabilities, and efficient message retrieval. You must configure a storage provider for conversation history, and if you enable semantic recall you will also need to provide a vector store and embedder. ## Basic Usage ```typescript copy showLineNumbers import { Memory } from "@mastra/memory"; import { Agent } from "@mastra/core/agent"; const agent = new Agent({ memory: new Memory(), ...otherOptions, }); ``` ## Custom Configuration ```typescript copy showLineNumbers import { Memory } from "@mastra/memory"; import { LibSQLStore, LibSQLVector } from "@mastra/libsql"; import { Agent } from "@mastra/core/agent"; const memory = new Memory({ // Optional storage configuration - libsql will be used by default storage: new LibSQLStore({ url: "file:./memory.db", }), // Optional vector database for semantic search vector: new LibSQLVector({ url: "file:./vector.db", }), // Memory configuration options options: { // Number of recent messages to include lastMessages: 20, // Semantic search configuration semanticRecall: { topK: 3, // Number of similar messages to retrieve messageRange: { // Messages to include around each result before: 2, after: 1, }, }, // Working memory configuration workingMemory: { enabled: true, template: ` # User - First Name: - Last Name: `, }, }, }); const agent = new Agent({ memory, ...otherOptions, }); ``` ### Working Memory The working memory feature allows agents to maintain persistent information across conversations. When enabled, the Memory class automatically manages working memory updates using a dedicated tool call. Example configuration: ```typescript copy showLineNumbers const memory = new Memory({ options: { workingMemory: { enabled: true, template: "# User\n- **First Name**:\n- **Last Name**:", }, }, }); ``` If no template is provided, the Memory class uses a default template that includes fields for user details, preferences, goals, and other contextual information in Markdown format. See the [Working Memory guide](/docs/memory/working-memory.mdx#designing-effective-templates) for detailed usage examples and best practices. ### embedder An embedding model is required if `semanticRecall` is enabled. One option is to use `@mastra/fastembed`, which provides an on-device/local embedding model using [FastEmbed](https://github.com/Anush008/fastembed-js). This model runs locally and does not require API keys or network requests. To use it, first install the package: ```bash npm2yarn copy npm install @mastra/fastembed ``` Then, configure it in your `Memory` instance: ```typescript {2,7} import { Memory } from "@mastra/memory"; import { fastembed } from "@mastra/fastembed"; import { Agent } from "@mastra/core/agent"; const agent = new Agent({ memory: new Memory({ embedder: fastembed, // ... other memory config }), }); ``` Note that, depending on where you're deploying your project, your project may not deploy due to FastEmbeds large internal dependencies. Alternatively, you can use an API-based embedder like OpenAI (which doesn't have this problem): ```typescript {2,7} import { Memory } from "@mastra/memory"; import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; const agent = new Agent({ memory: new Memory({ embedder: openai.embedding("text-embedding-3-small"), }), }); ``` Mastra supports many embedding models through the [Vercel AI SDK](https://sdk.vercel.ai/docs/ai-sdk-core/embeddings), including options from OpenAI, Google, Mistral, and Cohere. ## Parameters ### options ### Related - [Getting Started with Memory](/docs/memory/overview.mdx) - [Semantic Recall](/docs/memory/semantic-recall.mdx) - [Working Memory](/docs/memory/working-memory.mdx) - [Memory Processors](/docs/memory/memory-processors.mdx) - [createThread](/reference/memory/createThread.mdx) - [query](/reference/memory/query.mdx) - [getThreadById](/reference/memory/getThreadById.mdx) - [getThreadsByResourceId](/reference/memory/getThreadsByResourceId.mdx) # createThread [EN] Source: https://mastra.ai/en/reference/memory/createThread Creates a new conversation thread in the memory system. Each thread represents a distinct conversation or context and can contain multiple messages. ## Usage Example ```typescript import { Memory } from "@mastra/memory"; const memory = new Memory({ /* config */ }); const thread = await memory.createThread({ resourceId: "user-123", title: "Support Conversation", metadata: { category: "support", priority: "high", }, }); ``` ## Parameters ", description: "Optional metadata to associate with the thread", isOptional: true, }, ]} /> ## Returns ", description: "Additional metadata associated with the thread", }, ]} /> ### Related - [Memory Class Reference](/reference/memory/Memory.mdx) - [Getting Started with Memory](/docs/memory/overview.mdx) (Covers threads concept) - [getThreadById](/reference/memory/getThreadById.mdx) - [getThreadsByResourceId](/reference/memory/getThreadsByResourceId.mdx) - [query](/reference/memory/query.mdx) # getThreadById Reference [EN] Source: https://mastra.ai/en/reference/memory/getThreadById The `getThreadById` function retrieves a specific thread by its ID from storage. ## Usage Example ```typescript import { Memory } from "@mastra/core/memory"; const memory = new Memory(config); const thread = await memory.getThreadById({ threadId: "thread-123" }); ``` ## Parameters ## Returns ### Related - [Memory Class Reference](/reference/memory/Memory.mdx) - [Getting Started with Memory](/docs/memory/overview.mdx) (Covers threads concept) - [createThread](/reference/memory/createThread.mdx) - [getThreadsByResourceId](/reference/memory/getThreadsByResourceId.mdx) # getThreadsByResourceId Reference [EN] Source: https://mastra.ai/en/reference/memory/getThreadsByResourceId The `getThreadsByResourceId` function retrieves all threads associated with a specific resource ID from storage. ## Usage Example ```typescript import { Memory } from "@mastra/core/memory"; const memory = new Memory(config); const threads = await memory.getThreadsByResourceId({ resourceId: "resource-123", }); ``` ## Parameters ## Returns ### Related - [Memory Class Reference](/reference/memory/Memory.mdx) - [Getting Started with Memory](/docs/memory/overview.mdx) (Covers threads/resources concept) - [createThread](/reference/memory/createThread.mdx) - [getThreadById](/reference/memory/getThreadById.mdx) # query [EN] Source: https://mastra.ai/en/reference/memory/query Retrieves messages from a specific thread, with support for pagination and filtering options. ## Usage Example ```typescript import { Memory } from "@mastra/memory"; const memory = new Memory({ /* config */ }); // Get last 50 messages const { messages, uiMessages } = await memory.query({ threadId: "thread-123", selectBy: { last: 50, }, }); // Get messages with context around specific messages const { messages: contextMessages } = await memory.query({ threadId: "thread-123", selectBy: { include: [ { id: "msg-123", // Get just this message (no context) }, { id: "msg-456", // Get this message with custom context withPreviousMessages: 3, // 3 messages before withNextMessages: 1, // 1 message after }, ], }, }); // Semantic search in messages const { messages } = await memory.query({ threadId: "thread-123", selectBy: { vectorSearchString: "What was discussed about deployment?", }, threadConfig: { historySearch: true, }, }); ``` ## Parameters ### selectBy ### include ## Returns ## Additional Notes The `query` function returns two different message formats: - `messages`: Core message format used internally - `uiMessages`: Formatted messages suitable for UI display, including proper threading of tool calls and results ### Related - [Memory Class Reference](/reference/memory/Memory.mdx) - [Getting Started with Memory](/docs/memory/overview.mdx) - [Semantic Recall](/docs/memory/semantic-recall.mdx) - [createThread](/reference/memory/createThread.mdx) --- title: "AgentNetwork (Experimental)" description: "Reference documentation for the AgentNetwork class" --- # AgentNetwork (Experimental) [EN] Source: https://mastra.ai/en/reference/networks/agent-network > **Note:** The AgentNetwork feature is experimental and may change in future releases. The `AgentNetwork` class provides a way to create a network of specialized agents that can collaborate to solve complex tasks. Unlike Workflows, which require explicit control over execution paths, AgentNetwork uses an LLM-based router to dynamically determine which agent to call next. ## Key Concepts - **LLM-based Routing**: AgentNetwork exclusively uses an LLM to figure out the best way to use your agents - **Agent Collaboration**: Multiple specialized agents can work together to solve complex tasks - **Dynamic Decision Making**: The router decides which agent to call based on the task requirements ## Usage ```typescript import { AgentNetwork } from "@mastra/core/network"; import { openai } from "@mastra/openai"; // Create specialized agents const webSearchAgent = new Agent({ name: "Web Search Agent", instructions: "You search the web for information.", model: openai("gpt-4o"), tools: { /* web search tools */ }, }); const dataAnalysisAgent = new Agent({ name: "Data Analysis Agent", instructions: "You analyze data and provide insights.", model: openai("gpt-4o"), tools: { /* data analysis tools */ }, }); // Create the network const researchNetwork = new AgentNetwork({ name: "Research Network", instructions: "Coordinate specialized agents to research topics thoroughly.", model: openai("gpt-4o"), agents: [webSearchAgent, dataAnalysisAgent], }); // Use the network const result = await researchNetwork.generate( "Research the impact of climate change on agriculture", ); console.log(result.text); ``` ## Constructor ```typescript constructor(config: AgentNetworkConfig) ``` ### Parameters - `config`: Configuration object for the AgentNetwork - `name`: Name of the network - `instructions`: Instructions for the routing agent - `model`: Language model to use for routing - `agents`: Array of specialized agents in the network ## Methods ### generate() Generates a response using the agent network. This method has replaced the deprecated `run()` method for consistency with the rest of the codebase. ```typescript async generate( messages: string | string[] | CoreMessage[], args?: AgentGenerateOptions ): Promise ``` ### stream() Streams a response using the agent network. ```typescript async stream( messages: string | string[] | CoreMessage[], args?: AgentStreamOptions ): Promise ``` ### getRoutingAgent() Returns the routing agent used by the network. ```typescript getRoutingAgent(): Agent ``` ### getAgents() Returns the array of specialized agents in the network. ```typescript getAgents(): Agent[] ``` ### getAgentHistory() Returns the history of interactions for a specific agent. ```typescript getAgentHistory(agentId: string): Array<{ input: string; output: string; timestamp: string; }> ``` ### getAgentInteractionHistory() Returns the history of all agent interactions that have occurred in the network. ```typescript getAgentInteractionHistory(): Record< string, Array<{ input: string; output: string; timestamp: string; }> > ``` ### getAgentInteractionSummary() Returns a formatted summary of agent interactions in chronological order. ```typescript getAgentInteractionSummary(): string ``` ## When to Use AgentNetwork vs Workflows - **Use AgentNetwork when:** You want the AI to figure out the best way to use your agents, with dynamic routing based on the task requirements. - **Use Workflows when:** You need explicit control over execution paths, with predetermined sequences of agent calls and conditional logic. ## Internal Tools The AgentNetwork uses a special `transmit` tool that allows the routing agent to call specialized agents. This tool handles: - Single agent calls - Multiple parallel agent calls - Context sharing between agents ## Limitations - The AgentNetwork approach may use more tokens than a well-designed Workflow for the same task - Debugging can be more challenging as the routing decisions are made by the LLM - Performance may vary based on the quality of the routing instructions and the capabilities of the specialized agents --- title: "Reference: Logger Instance | Mastra Observability Docs" description: Documentation for Logger instances, which provide methods to record events at various severity levels. --- # Logger Instance [EN] Source: https://mastra.ai/en/reference/observability/logger A Logger instance is created by `new PinoLogger()` and provides methods to record events at various severity levels. Depending on the logger type, messages may be written to the console, file, or an external service. ## Example ```typescript showLineNumbers copy // Using a console logger const logger = new PinoLogger({ name: "Mastra", level: "info" }); logger.debug("Debug message"); // Won't be logged because level is INFO logger.info({ message: "User action occurred", destinationPath: "user-actions", type: "AGENT", }); // Logged logger.error("An error occurred"); // Logged as ERROR ``` ## Methods void | Promise", description: "Write a DEBUG-level log. Only recorded if level ≤ DEBUG.", }, { name: "info", type: "(message: BaseLogMessage | string, ...args: any[]) => void | Promise", description: "Write an INFO-level log. Only recorded if level ≤ INFO.", }, { name: "warn", type: "(message: BaseLogMessage | string, ...args: any[]) => void | Promise", description: "Write a WARN-level log. Only recorded if level ≤ WARN.", }, { name: "error", type: "(message: BaseLogMessage | string, ...args: any[]) => void | Promise", description: "Write an ERROR-level log. Only recorded if level ≤ ERROR.", }, { name: "cleanup", type: "() => Promise", isOptional: true, description: "Cleanup resources held by the logger (e.g., network connections for Upstash). Not all loggers implement this.", }, ]} /> **Note:** Some loggers require a `BaseLogMessage` object (with `message`, `destinationPath`, `type` fields). For instance, the `File` and `Upstash` loggers need structured messages. --- title: "Reference: OtelConfig | Mastra Observability Docs" description: Documentation for the OtelConfig object, which configures OpenTelemetry instrumentation, tracing, and exporting behavior. --- # `OtelConfig` [EN] Source: https://mastra.ai/en/reference/observability/otel-config The `OtelConfig` object is used to configure OpenTelemetry instrumentation, tracing, and exporting behavior within your application. By adjusting its properties, you can control how telemetry data (such as traces) is collected, sampled, and exported. To use the `OtelConfig` within Mastra, pass it as the value of the `telemetry` key when initializing Mastra. This will configure Mastra to use your custom OpenTelemetry settings for tracing and instrumentation. ```typescript showLineNumbers copy import { Mastra } from "mastra"; const otelConfig: OtelConfig = { serviceName: "my-awesome-service", enabled: true, sampling: { type: "ratio", probability: 0.5, }, export: { type: "otlp", endpoint: "https://otel-collector.example.com/v1/traces", headers: { Authorization: "Bearer YOUR_TOKEN_HERE", }, }, }; ``` ### Properties ", isOptional: true, description: "Additional headers to send with OTLP requests, useful for authentication or routing.", }, ], }, ]} /> --- title: "Reference: Braintrust | Observability | Mastra Docs" description: Documentation for integrating Braintrust with Mastra, an evaluation and monitoring platform for LLM applications. --- # Braintrust [EN] Source: https://mastra.ai/en/reference/observability/providers/braintrust Braintrust is an evaluation and monitoring platform for LLM applications. ## Configuration To use Braintrust with Mastra, configure these environment variables: ```env OTEL_EXPORTER_OTLP_ENDPOINT=https://api.braintrust.dev/otel OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer , x-bt-parent=project_id:" ``` ## Implementation Here's how to configure Mastra to use Braintrust: ```typescript import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "your-service-name", enabled: true, export: { type: "otlp", }, }, }); ``` ## Dashboard Access your Braintrust dashboard at [braintrust.dev](https://www.braintrust.dev/) --- title: "Reference: Dash0 Integration | Mastra Observability Docs" description: Documentation for integrating Mastra with Dash0, an Open Telementry native observability solution. --- # Dash0 [EN] Source: https://mastra.ai/en/reference/observability/providers/dash0 Dash0, an Open Telementry native observability solution that provides full-stack monitoring capabilities as well as integrations with other CNCF projects like Perses and Prometheus. ## Configuration To use Dash0 with Mastra, configure these environment variables: ```env OTEL_EXPORTER_OTLP_ENDPOINT=https://ingress..dash0.com OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer , Dash0-Dataset= ``` ## Implementation Here's how to configure Mastra to use Dash0: ```typescript import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "your-service-name", enabled: true, export: { type: "otlp", }, }, }); ``` ## Dashboard Access your Dash0 dashboards at [dash0.com](https://www.dash0.com/) and find out how to do more [Distributed Tracing](https://www.dash0.com/distributed-tracing) integrations in the [Dash0 Integration Hub](https://www.dash0.com/hub/integrations) --- title: "Reference: Provider List | Observability | Mastra Docs" description: Overview of observability providers supported by Mastra, including Dash0, SigNoz, Braintrust, Langfuse, and more. --- # Observability Providers [EN] Source: https://mastra.ai/en/reference/observability/providers Observability providers include: - [Braintrust](./providers/braintrust.mdx) - [Dash0](./providers/dash0.mdx) - [Laminar](./providers/laminar.mdx) - [Langfuse](./providers/langfuse.mdx) - [Langsmith](./providers/langsmith.mdx) - [LangWatch](./providers/langwatch.mdx) - [New Relic](./providers/new-relic.mdx) - [SigNoz](./providers/signoz.mdx) - [Traceloop](./providers/traceloop.mdx) --- title: "Reference: Laminar Integration | Mastra Observability Docs" description: Documentation for integrating Laminar with Mastra, a specialized observability platform for LLM applications. --- # Laminar [EN] Source: https://mastra.ai/en/reference/observability/providers/laminar Laminar is a specialized observability platform for LLM applications. ## Configuration To use Laminar with Mastra, configure these environment variables: ```env OTEL_EXPORTER_OTLP_ENDPOINT=https://api.lmnr.ai:8443 OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer your_api_key, x-laminar-team-id=your_team_id" ``` ## Implementation Here's how to configure Mastra to use Laminar: ```typescript import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "your-service-name", enabled: true, export: { type: "otlp", protocol: "grpc", }, }, }); ``` ## Dashboard Access your Laminar dashboard at [https://lmnr.ai/](https://lmnr.ai/) --- title: "Reference: Langfuse Integration | Mastra Observability Docs" description: Documentation for integrating Langfuse with Mastra, an open-source observability platform for LLM applications. --- # Langfuse [EN] Source: https://mastra.ai/en/reference/observability/providers/langfuse Langfuse is an open-source observability platform designed specifically for LLM applications. > **Note**: Currently, only AI-related calls will contain detailed telemetry data. Other operations will create traces but with limited information. ## Configuration To use Langfuse with Mastra, you'll need to configure the following environment variables: ```env LANGFUSE_PUBLIC_KEY=your_public_key LANGFUSE_SECRET_KEY=your_secret_key LANGFUSE_BASEURL=https://cloud.langfuse.com # Optional - defaults to cloud.langfuse.com ``` **Important**: When configuring the telemetry export settings, the `traceName` parameter must be set to `"ai"` for the Langfuse integration to work properly. ## Implementation Here's how to configure Mastra to use Langfuse: ```typescript import { Mastra } from "@mastra/core"; import { LangfuseExporter } from "langfuse-vercel"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "ai", // this must be set to "ai" so that the LangfuseExporter thinks it's an AI SDK trace enabled: true, export: { type: "custom", exporter: new LangfuseExporter({ publicKey: process.env.LANGFUSE_PUBLIC_KEY, secretKey: process.env.LANGFUSE_SECRET_KEY, baseUrl: process.env.LANGFUSE_BASEURL, }), }, }, }); ``` ## Dashboard Once configured, you can view your traces and analytics in the Langfuse dashboard at [cloud.langfuse.com](https://cloud.langfuse.com) --- title: "Reference: LangSmith Integration | Mastra Observability Docs" description: Documentation for integrating LangSmith with Mastra, a platform for debugging, testing, evaluating, and monitoring LLM applications. --- # LangSmith [EN] Source: https://mastra.ai/en/reference/observability/providers/langsmith LangSmith is LangChain's platform for debugging, testing, evaluating, and monitoring LLM applications. > **Note**: Currently, this integration only traces AI-related calls in your application. Other types of operations are not captured in the telemetry data. ## Configuration To use LangSmith with Mastra, you'll need to configure the following environment variables: ```env LANGSMITH_TRACING=true LANGSMITH_ENDPOINT=https://api.smith.langchain.com LANGSMITH_API_KEY=your-api-key LANGSMITH_PROJECT=your-project-name ``` ## Implementation Here's how to configure Mastra to use LangSmith: ```typescript import { Mastra } from "@mastra/core"; import { AISDKExporter } from "langsmith/vercel"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "your-service-name", enabled: true, export: { type: "custom", exporter: new AISDKExporter(), }, }, }); ``` ## Dashboard Access your traces and analytics in the LangSmith dashboard at [smith.langchain.com](https://smith.langchain.com) > **Note**: Even if you run your workflows, you may not see data appearing in a new project. You will need to sort by Name column to see all projects, select your project, then filter by LLM Calls instead of Root Runs. --- title: "Reference: LangWatch Integration | Mastra Observability Docs" description: Documentation for integrating LangWatch with Mastra, a specialized observability platform for LLM applications. --- # LangWatch [EN] Source: https://mastra.ai/en/reference/observability/providers/langwatch LangWatch is a specialized observability platform for LLM applications. ## Configuration To use LangWatch with Mastra, configure these environment variables: ```env LANGWATCH_API_KEY=your_api_key ``` ## Implementation Here's how to configure Mastra to use LangWatch: ```typescript import { Mastra } from "@mastra/core"; import { LangWatchExporter } from "langwatch"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "ai", // this must be set to "ai" so that the LangWatchExporter thinks it's an AI SDK trace enabled: true, export: { type: "custom", exporter: new LangWatchExporter({ apiKey: process.env.LANGWATCH_API_KEY }), }, }, }); ``` ## Dashboard Access your LangWatch dashboard at [app.langwatch.ai](https://app.langwatch.ai) --- title: "Reference: New Relic Integration | Mastra Observability Docs" description: Documentation for integrating New Relic with Mastra, a comprehensive observability platform supporting OpenTelemetry for full-stack monitoring. --- # New Relic [EN] Source: https://mastra.ai/en/reference/observability/providers/new-relic New Relic is a comprehensive observability platform that supports OpenTelemetry (OTLP) for full-stack monitoring. ## Configuration To use New Relic with Mastra via OTLP, configure these environment variables: ```env OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net:4317 OTEL_EXPORTER_OTLP_HEADERS="api-key=your_license_key" ``` ## Implementation Here's how to configure Mastra to use New Relic: ```typescript import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "your-service-name", enabled: true, export: { type: "otlp", }, }, }); ``` ## Dashboard View your telemetry data in the New Relic One dashboard at [one.newrelic.com](https://one.newrelic.com) --- title: "Reference: SigNoz Integration | Mastra Observability Docs" description: Documentation for integrating SigNoz with Mastra, an open-source APM and observability platform providing full-stack monitoring through OpenTelemetry. --- # SigNoz [EN] Source: https://mastra.ai/en/reference/observability/providers/signoz SigNoz is an open-source APM and observability platform that provides full-stack monitoring capabilities through OpenTelemetry. ## Configuration To use SigNoz with Mastra, configure these environment variables: ```env OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.{region}.signoz.cloud:443 OTEL_EXPORTER_OTLP_HEADERS=signoz-ingestion-key=your_signoz_token ``` ## Implementation Here's how to configure Mastra to use SigNoz: ```typescript import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "your-service-name", enabled: true, export: { type: "otlp", }, }, }); ``` ## Dashboard Access your SigNoz dashboard at [signoz.io](https://signoz.io/) --- title: "Reference: Traceloop Integration | Mastra Observability Docs" description: Documentation for integrating Traceloop with Mastra, an OpenTelemetry-native observability platform for LLM applications. --- # Traceloop [EN] Source: https://mastra.ai/en/reference/observability/providers/traceloop Traceloop is an OpenTelemetry-native observability platform specifically designed for LLM applications. ## Configuration To use Traceloop with Mastra, configure these environment variables: ```env OTEL_EXPORTER_OTLP_ENDPOINT=https://api.traceloop.com OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer your_api_key, x-traceloop-destination-id=your_destination_id" ``` ## Implementation Here's how to configure Mastra to use Traceloop: ```typescript import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "your-service-name", enabled: true, export: { type: "otlp", }, }, }); ``` ## Dashboard Access your traces and analytics in the Traceloop dashboard at [app.traceloop.com](https://app.traceloop.com) --- title: "Reference: Astra Vector Store | Vector Databases | RAG | Mastra Docs" description: Documentation for the AstraVector class in Mastra, which provides vector search using DataStax Astra DB. --- # Astra Vector Store [EN] Source: https://mastra.ai/en/reference/rag/astra The AstraVector class provides vector search using [DataStax Astra DB](https://www.datastax.com/products/datastax-astra), a cloud-native, serverless database built on Apache Cassandra. It provides vector search capabilities with enterprise-grade scalability and high availability. ## Constructor Options ## Methods ### createIndex() ### upsert() []", isOptional: true, description: "Metadata for each vector", }, { name: "ids", type: "string[]", isOptional: true, description: "Optional vector IDs (auto-generated if not provided)", }, ]} /> ### query() ", isOptional: true, description: "Metadata filters for the query", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "Whether to include vectors in the results", }, ]} /> ### listIndexes() Returns an array of index names as strings. ### describeIndex() Returns: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() ### updateVector() ", isOptional: true, description: "New metadata values", }, ], }, ]} /> ### deleteVector() ## Response Types Query results are returned in this format: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true } ``` ## Error Handling The store throws typed errors that can be caught: ```typescript copy try { await store.query({ indexName: "index_name", queryVector: queryVector, }); } catch (error) { if (error instanceof VectorStoreError) { console.log(error.code); // 'connection_failed' | 'invalid_dimension' | etc console.log(error.details); // Additional error context } } ``` ## Environment Variables Required environment variables: - `ASTRA_DB_TOKEN`: Your Astra DB API token - `ASTRA_DB_ENDPOINT`: Your Astra DB API endpoint ## Related - [Metadata Filters](./metadata-filters) --- title: "Reference: Chroma Vector Store | Vector Databases | RAG | Mastra Docs" description: Documentation for the ChromaVector class in Mastra, which provides vector search using ChromaDB. --- # Chroma Vector Store [EN] Source: https://mastra.ai/en/reference/rag/chroma The ChromaVector class provides vector search using [ChromaDB](https://www.trychroma.com/), an open-source embedding database. It offers efficient vector search with metadata filtering and hybrid search capabilities. ## Constructor Options ### auth ## Methods ### createIndex() ### upsert() []", isOptional: true, description: "Metadata for each vector", }, { name: "ids", type: "string[]", isOptional: true, description: "Optional vector IDs (auto-generated if not provided)", }, { name: "documents", type: "string[]", isOptional: true, description: "Chroma-specific: Original text documents associated with the vectors", }, ]} /> ### query() ", isOptional: true, description: "Metadata filters for the query", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "Whether to include vectors in the results", }, { name: "documentFilter", type: "Record", isOptional: true, description: "Chroma-specific: Filter to apply on the document content", }, ]} /> ### listIndexes() Returns an array of index names as strings. ### describeIndex() Returns: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() ### updateVector() The `update` object can contain: ", isOptional: true, description: "New metadata to replace the existing metadata", }, ]} /> ### deleteVector() ## Response Types Query results are returned in this format: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; document?: string; // Chroma-specific: Original document if it was stored vector?: number[]; // Only included if includeVector is true } ``` ## Error Handling The store throws typed errors that can be caught: ```typescript copy try { await store.query({ indexName: "index_name", queryVector: queryVector, }); } catch (error) { if (error instanceof VectorStoreError) { console.log(error.code); // 'connection_failed' | 'invalid_dimension' | etc console.log(error.details); // Additional error context } } ``` ## Related - [Metadata Filters](./metadata-filters) --- title: "Reference: .chunk() | Document Processing | RAG | Mastra Docs" description: Documentation for the chunk function in Mastra, which splits documents into smaller segments using various strategies. --- # Reference: .chunk() [EN] Source: https://mastra.ai/en/reference/rag/chunk The `.chunk()` function splits documents into smaller segments using various strategies and options. ## Example ```typescript import { MDocument } from "@mastra/rag"; const doc = MDocument.fromMarkdown(` # Introduction This is a sample document that we want to split into chunks. ## Section 1 Here is the first section with some content. ## Section 2 Here is another section with different content. `); // Basic chunking with defaults const chunks = await doc.chunk(); // Markdown-specific chunking with header extraction const chunksWithMetadata = await doc.chunk({ strategy: "markdown", headers: [ ["#", "title"], ["##", "section"], ], extract: { summary: true, // Extract summaries with default settings keywords: true, // Extract keywords with default settings }, }); ``` ## Parameters ## Strategy-Specific Options Strategy-specific options are passed as top-level parameters alongside the strategy parameter. For example: ```typescript showLineNumbers copy // HTML strategy example const chunks = await doc.chunk({ strategy: "html", headers: [ ["h1", "title"], ["h2", "subtitle"], ], // HTML-specific option sections: [["div.content", "main"]], // HTML-specific option size: 500, // general option }); // Markdown strategy example const chunks = await doc.chunk({ strategy: "markdown", headers: [ ["#", "title"], ["##", "section"], ], // Markdown-specific option stripHeaders: true, // Markdown-specific option overlap: 50, // general option }); // Token strategy example const chunks = await doc.chunk({ strategy: "token", encodingName: "gpt2", // Token-specific option modelName: "gpt-3.5-turbo", // Token-specific option size: 1000, // general option }); ``` The options documented below are passed directly at the top level of the configuration object, not nested within a separate options object. ### HTML ", description: "Array of [selector, metadata key] pairs for header-based splitting", }, { name: "sections", type: "Array<[string, string]>", description: "Array of [selector, metadata key] pairs for section-based splitting", }, { name: "returnEachLine", type: "boolean", isOptional: true, description: "Whether to return each line as a separate chunk", }, ]} /> ### Markdown ", description: "Array of [header level, metadata key] pairs", }, { name: "stripHeaders", type: "boolean", isOptional: true, description: "Whether to remove headers from the output", }, { name: "returnEachLine", type: "boolean", isOptional: true, description: "Whether to return each line as a separate chunk", }, ]} /> ### Token ### JSON ## Return Value Returns a `MDocument` instance containing the chunked documents. Each chunk includes: ```typescript interface DocumentNode { text: string; metadata: Record; embedding?: number[]; } ``` --- title: "Reference: Couchbase Vector Store | Vector Databases | RAG | Mastra Docs" description: Documentation for the CouchbaseVector class in Mastra, which provides vector search using Couchbase Vector Search. --- # Couchbase Vector Store [EN] Source: https://mastra.ai/en/reference/rag/couchbase The `CouchbaseVector` class provides vector search using [Couchbase Vector Search](https://docs.couchbase.com/server/current/vector-search/vector-search.html). It enables efficient similarity search and metadata filtering within your Couchbase collections. ## Requirements - **Couchbase Server 7.6.4+** or a compatible Capella cluster - **Search Service enabled** on your Couchbase deployment ## Installation ```bash copy npm install @mastra/couchbase ``` ## Usage Example ```typescript copy showLineNumbers import { CouchbaseVector } from '@mastra/couchbase'; const store = new CouchbaseVector({ connectionString: process.env.COUCHBASE_CONNECTION_STRING, username: process.env.COUCHBASE_USERNAME, password: process.env.COUCHBASE_PASSWORD, bucketName: process.env.COUCHBASE_BUCKET, scopeName: process.env.COUCHBASE_SCOPE, collectionName: process.env.COUCHBASE_COLLECTION, }); ``` ## Constructor Options ## Methods ### createIndex() Creates a new vector index in Couchbase. > **Note:** Index creation is asynchronous. After calling `createIndex`, allow time (typically 1–5 seconds for small datasets, longer for large ones) before querying. For production, implement polling to check index status rather than using fixed delays. ### upsert() Adds or updates vectors and their metadata in the collection. > **Note:** You can upsert data before or after creating the index. The `upsert` method does not require the index to exist. Couchbase allows multiple Search indexes over the same collection. []", isOptional: true, description: "Metadata for each vector", }, { name: "ids", type: "string[]", isOptional: true, description: "Optional vector IDs (auto-generated if not provided)", }, ]} /> ### query() Searches for similar vectors. > **Warning:** The `filter` and `includeVector` parameters are not currently supported. Filtering must be performed client-side after retrieving results, or by using the Couchbase SDK's Search capabilities directly. To retrieve the vector embedding, fetch the full document by ID using the Couchbase SDK. ", isOptional: true, description: "Metadata filters", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "Whether to include vector data in results", }, { name: "minScore", type: "number", isOptional: true, defaultValue: "0", description: "Minimum similarity score threshold", }, ]} /> ### describeIndex() Returns information about the index. Returns: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() Deletes an index and all its data. ### listIndexes() Lists all vector indexes in the Couchbase bucket. Returns: `Promise` ### updateVector() Updates a specific vector entry by its ID with new vector data and/or metadata. ", isOptional: true, description: "New metadata to update", }, ]} /> ### deleteVector() Deletes a specific vector entry from an index by its ID. ### disconnect() Closes the Couchbase client connection. Should be called when done using the store. ## Response Types Query results are returned in this format: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true } ``` ## Error Handling The store throws typed errors that can be caught: ```typescript copy try { await store.query({ indexName: "my_index", queryVector: queryVector, }); } catch (error) { // Handle specific error cases if (error.message.includes("Invalid index name")) { console.error( "Index name must start with a letter or underscore and contain only valid characters." ); } else if (error.message.includes("Index not found")) { console.error("The specified index does not exist"); } else { console.error("Vector store error:", error.message); } } ``` ## Notes - **Index Deletion Caveat:** Deleting a Search index does NOT delete the vectors/documents in the associated Couchbase collection. Data remains unless explicitly removed. - **Required Permissions:** The Couchbase user must have permissions to connect, read/write documents in the target collection (`kv` role), and manage Search Indexes (`search_admin` role on the relevant bucket/scope). - **Index Definition Details & Document Structure:** The `createIndex` method constructs a Search Index definition that indexes the `embedding` field (as type `vector`) and the `content` field (as type `text`), targeting documents within the specified `scopeName.collectionName`. Each document stores the vector in the `embedding` field and metadata in the `metadata` field. If `metadata` contains a `text` property, its value is also copied to a top-level `content` field, which is indexed for text search. - **Replication & Durability:** Consider using Couchbase's built-in replication and persistence features for data durability. Monitor index statistics regularly to ensure efficient search. ## Limitations - Index creation delays may impact immediate querying after creation. - No hard enforcement of vector dimension at ingest time (dimension mismatches will error at query time). - Vector insertion and index updates are eventually consistent; strong consistency is not guaranteed immediately after writes. ## Related - [Metadata Filters](./metadata-filters) --- title: "Reference: DatabaseConfig | RAG | Mastra Docs" description: API reference for database-specific configuration types used with vector query tools in Mastra RAG systems. --- import { Callout } from "nextra/components"; import { Tabs } from "nextra/components"; # DatabaseConfig [EN] Source: https://mastra.ai/en/reference/rag/database-config The `DatabaseConfig` type allows you to specify database-specific configurations when using vector query tools. These configurations enable you to leverage unique features and optimizations offered by different vector stores. ## Type Definition ```typescript export type DatabaseConfig = { pinecone?: PineconeConfig; pgvector?: PgVectorConfig; chroma?: ChromaConfig; [key: string]: any; // Extensible for future databases }; ``` ## Database-Specific Types ### PineconeConfig Configuration options specific to Pinecone vector store. **Use Cases:** - Multi-tenant applications (separate namespaces per tenant) - Environment isolation (dev/staging/prod namespaces) - Hybrid search combining semantic and keyword matching ### PgVectorConfig Configuration options specific to PostgreSQL with pgvector extension. **Performance Guidelines:** - **ef**: Start with 2-4x your topK value, increase for better accuracy - **probes**: Start with 1-10, increase for better recall - **minScore**: Use values between 0.5-0.9 depending on your quality requirements **Use Cases:** - Performance optimization for high-load scenarios - Quality filtering to remove irrelevant results - Fine-tuning search accuracy vs speed tradeoffs ### ChromaConfig Configuration options specific to Chroma vector store. ", description: "Metadata filtering conditions using MongoDB-style query syntax. Filters results based on metadata fields.", isOptional: true, }, { name: "whereDocument", type: "Record", description: "Document content filtering conditions. Allows filtering based on the actual document text content.", isOptional: true, }, ]} /> **Filter Syntax Examples:** ```typescript // Simple equality where: { "category": "technical" } // Operators where: { "price": { "$gt": 100 } } // Multiple conditions where: { "category": "electronics", "inStock": true } // Document content filtering whereDocument: { "$contains": "API documentation" } ``` **Use Cases:** - Advanced metadata filtering - Content-based document filtering - Complex query combinations ## Usage Examples ### Basic Database Configuration ```typescript import { createVectorQueryTool } from '@mastra/rag'; const vectorTool = createVectorQueryTool({ vectorStoreName: 'pinecone', indexName: 'documents', model: embedModel, databaseConfig: { pinecone: { namespace: 'production' } } }); ``` ### Runtime Configuration Override ```typescript import { RuntimeContext } from '@mastra/core/runtime-context'; // Initial configuration const vectorTool = createVectorQueryTool({ vectorStoreName: 'pinecone', indexName: 'documents', model: embedModel, databaseConfig: { pinecone: { namespace: 'development' } } }); // Override at runtime const runtimeContext = new RuntimeContext(); runtimeContext.set('databaseConfig', { pinecone: { namespace: 'production' } }); await vectorTool.execute({ context: { queryText: 'search query' }, mastra, runtimeContext }); ``` ### Multi-Database Configuration ```typescript const vectorTool = createVectorQueryTool({ vectorStoreName: 'dynamic', // Will be determined at runtime indexName: 'documents', model: embedModel, databaseConfig: { pinecone: { namespace: 'default' }, pgvector: { minScore: 0.8, ef: 150 }, chroma: { where: { 'type': 'documentation' } } } }); ``` **Multi-Database Support**: When you configure multiple databases, only the configuration matching the actual vector store being used will be applied. ### Performance Tuning ```typescript // High accuracy configuration const highAccuracyTool = createVectorQueryTool({ vectorStoreName: 'postgres', indexName: 'embeddings', model: embedModel, databaseConfig: { pgvector: { ef: 400, // High accuracy probes: 20, // High recall minScore: 0.85 // High quality threshold } } }); // High speed configuration const highSpeedTool = createVectorQueryTool({ vectorStoreName: 'postgres', indexName: 'embeddings', model: embedModel, databaseConfig: { pgvector: { ef: 50, // Lower accuracy, faster probes: 3, // Lower recall, faster minScore: 0.6 // Lower quality threshold } } }); ``` ## Extensibility The `DatabaseConfig` type is designed to be extensible. To add support for a new vector database: ```typescript // 1. Define the configuration interface export interface NewDatabaseConfig { customParam1?: string; customParam2?: number; } // 2. Extend DatabaseConfig type export type DatabaseConfig = { pinecone?: PineconeConfig; pgvector?: PgVectorConfig; chroma?: ChromaConfig; newdatabase?: NewDatabaseConfig; [key: string]: any; }; // 3. Use in vector query tool const vectorTool = createVectorQueryTool({ vectorStoreName: 'newdatabase', indexName: 'documents', model: embedModel, databaseConfig: { newdatabase: { customParam1: 'value', customParam2: 42 } } }); ``` ## Best Practices 1. **Environment Configuration**: Use different namespaces or configurations for different environments 2. **Performance Tuning**: Start with default values and adjust based on your specific needs 3. **Quality Filtering**: Use minScore to filter out low-quality results 4. **Runtime Flexibility**: Override configurations at runtime for dynamic scenarios 5. **Documentation**: Document your specific configuration choices for team members ## Migration Guide Existing vector query tools continue to work without changes. To add database configurations: ```diff const vectorTool = createVectorQueryTool({ vectorStoreName: 'pinecone', indexName: 'documents', model: embedModel, + databaseConfig: { + pinecone: { + namespace: 'production' + } + } }); ``` ## Related - [createVectorQueryTool()](/reference/tools/vector-query-tool) - [Hybrid Vector Search](/examples/rag/query/hybrid-vector-search.mdx) - [Metadata Filters](/reference/rag/metadata-filters) --- title: "Reference: MDocument | Document Processing | RAG | Mastra Docs" description: Documentation for the MDocument class in Mastra, which handles document processing and chunking. --- # MDocument [EN] Source: https://mastra.ai/en/reference/rag/document The MDocument class processes documents for RAG applications. The main methods are `.chunk()` and `.extractMetadata()`. ## Constructor }>", description: "Array of document chunks with their text content and optional metadata", }, { name: "type", type: "'text' | 'html' | 'markdown' | 'json' | 'latex'", description: "Type of document content", }, ]} /> ## Static Methods ### fromText() Creates a document from plain text content. ```typescript static fromText(text: string, metadata?: Record): MDocument ``` ### fromHTML() Creates a document from HTML content. ```typescript static fromHTML(html: string, metadata?: Record): MDocument ``` ### fromMarkdown() Creates a document from Markdown content. ```typescript static fromMarkdown(markdown: string, metadata?: Record): MDocument ``` ### fromJSON() Creates a document from JSON content. ```typescript static fromJSON(json: string, metadata?: Record): MDocument ``` ## Instance Methods ### chunk() Splits document into chunks and optionally extracts metadata. ```typescript async chunk(params?: ChunkParams): Promise ``` See [chunk() reference](./chunk) for detailed options. ### getDocs() Returns array of processed document chunks. ```typescript getDocs(): Chunk[] ``` ### getText() Returns array of text strings from chunks. ```typescript getText(): string[] ``` ### getMetadata() Returns array of metadata objects from chunks. ```typescript getMetadata(): Record[] ``` ### extractMetadata() Extracts metadata using specified extractors. See [ExtractParams reference](./extract-params) for details. ```typescript async extractMetadata(params: ExtractParams): Promise ``` ## Examples ```typescript import { MDocument } from "@mastra/rag"; // Create document from text const doc = MDocument.fromText("Your content here"); // Split into chunks with metadata extraction const chunks = await doc.chunk({ strategy: "markdown", headers: [ ["#", "title"], ["##", "section"], ], extract: { summary: true, // Extract summaries with default settings keywords: true, // Extract keywords with default settings }, }); // Get processed chunks const docs = doc.getDocs(); const texts = doc.getText(); const metadata = doc.getMetadata(); ``` --- title: "Reference: embed() | Document Embedding | RAG | Mastra Docs" description: Documentation for embedding functionality in Mastra using the AI SDK. --- # Embed [EN] Source: https://mastra.ai/en/reference/rag/embeddings Mastra uses the AI SDK's `embed` and `embedMany` functions to generate vector embeddings for text inputs, enabling similarity search and RAG workflows. ## Single Embedding The `embed` function generates a vector embedding for a single text input: ```typescript import { embed } from "ai"; const result = await embed({ model: openai.embedding("text-embedding-3-small"), value: "Your text to embed", maxRetries: 2, // optional, defaults to 2 }); ``` ### Parameters ", description: "The text content or object to embed", }, { name: "maxRetries", type: "number", description: "Maximum number of retries per embedding call. Set to 0 to disable retries.", isOptional: true, defaultValue: "2", }, { name: "abortSignal", type: "AbortSignal", description: "Optional abort signal to cancel the request", isOptional: true, }, { name: "headers", type: "Record", description: "Additional HTTP headers for the request (only for HTTP-based providers)", isOptional: true, }, ]} /> ### Return Value ## Multiple Embeddings For embedding multiple texts at once, use the `embedMany` function: ```typescript import { embedMany } from "ai"; const result = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: ["First text", "Second text", "Third text"], maxRetries: 2, // optional, defaults to 2 }); ``` ### Parameters []", description: "Array of text content or objects to embed", }, { name: "maxRetries", type: "number", description: "Maximum number of retries per embedding call. Set to 0 to disable retries.", isOptional: true, defaultValue: "2", }, { name: "abortSignal", type: "AbortSignal", description: "Optional abort signal to cancel the request", isOptional: true, }, { name: "headers", type: "Record", description: "Additional HTTP headers for the request (only for HTTP-based providers)", isOptional: true, }, ]} /> ### Return Value ## Example Usage ```typescript import { embed, embedMany } from "ai"; import { openai } from "@ai-sdk/openai"; // Single embedding const singleResult = await embed({ model: openai.embedding("text-embedding-3-small"), value: "What is the meaning of life?", }); // Multiple embeddings const multipleResult = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: [ "First question about life", "Second question about universe", "Third question about everything", ], }); ``` For more detailed information about embeddings in the Vercel AI SDK, see: - [AI SDK Embeddings Overview](https://sdk.vercel.ai/docs/ai-sdk-core/embeddings) - [embed()](https://sdk.vercel.ai/docs/reference/ai-sdk-core/embed) - [embedMany()](https://sdk.vercel.ai/docs/reference/ai-sdk-core/embed-many) --- title: "Reference: ExtractParams | Document Processing | RAG | Mastra Docs" description: Documentation for metadata extraction configuration in Mastra. --- # ExtractParams [EN] Source: https://mastra.ai/en/reference/rag/extract-params ExtractParams configures metadata extraction from document chunks using LLM analysis. ## Example ```typescript showLineNumbers copy import { MDocument } from "@mastra/rag"; const doc = MDocument.fromText(text); const chunks = await doc.chunk({ extract: { title: true, // Extract titles using default settings summary: true, // Generate summaries using default settings keywords: true, // Extract keywords using default settings }, }); // Example output: // chunks[0].metadata = { // documentTitle: "AI Systems Overview", // sectionSummary: "Overview of artificial intelligence concepts and applications", // excerptKeywords: "KEYWORDS: AI, machine learning, algorithms" // } ``` ## Parameters The `extract` parameter accepts the following fields: ## Extractor Arguments ### TitleExtractorsArgs ### SummaryExtractArgs ### QuestionAnswerExtractArgs ### KeywordExtractArgs ## Advanced Example ```typescript showLineNumbers copy import { MDocument } from "@mastra/rag"; const doc = MDocument.fromText(text); const chunks = await doc.chunk({ extract: { // Title extraction with custom settings title: { nodes: 2, // Extract 2 title nodes nodeTemplate: "Generate a title for this: {context}", combineTemplate: "Combine these titles: {context}", }, // Summary extraction with custom settings summary: { summaries: ["self"], // Generate summaries for current chunk promptTemplate: "Summarize this: {context}", }, // Question generation with custom settings questions: { questions: 3, // Generate 3 questions promptTemplate: "Generate {numQuestions} questions about: {context}", embeddingOnly: false, }, // Keyword extraction with custom settings keywords: { keywords: 5, // Extract 5 keywords promptTemplate: "Extract {maxKeywords} key terms from: {context}", }, }, }); // Example output: // chunks[0].metadata = { // documentTitle: "AI in Modern Computing", // sectionSummary: "Overview of AI concepts and their applications in computing", // questionsThisExcerptCanAnswer: "1. What is machine learning?\n2. How do neural networks work?", // excerptKeywords: "1. Machine learning\n2. Neural networks\n3. Training data" // } ``` ## Document Grouping for Title Extraction When using the `TitleExtractor`, you can group multiple chunks together for title extraction by specifying a shared `docId` in the `metadata` field of each chunk. All chunks with the same `docId` will receive the same extracted title. If no `docId` is set, each chunk is treated as its own document for title extraction. **Example:** ```ts import { MDocument } from "@mastra/rag"; const doc = new MDocument({ docs: [ { text: "chunk 1", metadata: { docId: "docA" } }, { text: "chunk 2", metadata: { docId: "docA" } }, { text: "chunk 3", metadata: { docId: "docB" } }, ], type: "text", }); await doc.extractMetadata({ title: true }); // The first two chunks will share a title, while the third chunk will be assigned a separate title. ``` --- title: "Reference: GraphRAG | Graph-based RAG | RAG | Mastra Docs" description: Documentation for the GraphRAG class in Mastra, which implements a graph-based approach to retrieval augmented generation. --- # GraphRAG [EN] Source: https://mastra.ai/en/reference/rag/graph-rag The `GraphRAG` class implements a graph-based approach to retrieval augmented generation. It creates a knowledge graph from document chunks where nodes represent documents and edges represent semantic relationships, enabling both direct similarity matching and discovery of related content through graph traversal. ## Basic Usage ```typescript import { GraphRAG } from "@mastra/rag"; const graphRag = new GraphRAG({ dimension: 1536, threshold: 0.7, }); // Create the graph from chunks and embeddings graphRag.createGraph(documentChunks, embeddings); // Query the graph with embedding const results = await graphRag.query({ query: queryEmbedding, topK: 10, randomWalkSteps: 100, restartProb: 0.15, }); ``` ## Constructor Parameters ## Methods ### createGraph Creates a knowledge graph from document chunks and their embeddings. ```typescript createGraph(chunks: GraphChunk[], embeddings: GraphEmbedding[]): void ``` #### Parameters ### query Performs a graph-based search combining vector similarity and graph traversal. ```typescript query({ query, topK = 10, randomWalkSteps = 100, restartProb = 0.15 }: { query: number[]; topK?: number; randomWalkSteps?: number; restartProb?: number; }): RankedNode[] ``` #### Parameters #### Returns Returns an array of `RankedNode` objects, where each node contains: ", description: "Additional metadata associated with the chunk", }, { name: "score", type: "number", description: "Combined relevance score from graph traversal", }, ]} /> ## Advanced Example ```typescript const graphRag = new GraphRAG({ dimension: 1536, threshold: 0.8, // Stricter similarity threshold }); // Create graph from chunks and embeddings graphRag.createGraph(documentChunks, embeddings); // Query with custom parameters const results = await graphRag.query({ query: queryEmbedding, topK: 5, randomWalkSteps: 200, restartProb: 0.2, }); ``` ## Related - [createGraphRAGTool](../tools/graph-rag-tool) --- title: "Reference: Lance Vector Store | Vector Databases | RAG | Mastra Docs" description: "Documentation for the LanceVectorStore class in Mastra, which provides vector search using LanceDB, an embedded vector database based on the Lance columnar format." --- # Lance Vector Store [EN] Source: https://mastra.ai/en/reference/rag/lance The LanceVectorStore class provides vector search using [LanceDB](https://lancedb.github.io/lancedb/), an embedded vector database built on the Lance columnar format. It offers efficient storage and fast similarity search for both local development and production deployments. ## Factory Method The LanceVectorStore uses a factory pattern for creation. You should use the static `create()` method rather than the constructor directly. ## Constructor Examples You can create a `LanceVectorStore` instance using the static create method: ```ts import { LanceVectorStore } from "@mastra/lance"; // Connect to a local database const vectorStore = await LanceVectorStore.create("/path/to/db"); // Connect to a LanceDB cloud database const cloudStore = await LanceVectorStore.create("db://host:port"); // Connect to a cloud database with options const s3Store = await LanceVectorStore.create("s3://bucket/db", { storageOptions: { timeout: '60s' } }); ``` ## Methods ### createIndex() #### LanceIndexConfig ### createTable() [] | TableLike", description: "Initial data for the table", }, { name: "options", type: "Partial", isOptional: true, description: "Additional table creation options", }, ]} /> ### upsert() []", isOptional: true, description: "Metadata for each vector", }, { name: "ids", type: "string[]", isOptional: true, description: "Optional vector IDs (auto-generated if not provided)", }, ]} /> ### query() ", isOptional: true, description: "Metadata filters", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "Whether to include the vector in the result", }, { name: "columns", type: "string[]", isOptional: true, defaultValue: "[]", description: "Specific columns to include in the result", }, { name: "includeAllColumns", type: "boolean", isOptional: true, defaultValue: "false", description: "Whether to include all columns in the result", }, ]} /> ### listTables() Returns an array of table names as strings. ```typescript copy const tables = await vectorStore.listTables(); // ['my_vectors', 'embeddings', 'documents'] ``` ### getTableSchema() Returns the schema of the specified table. ### deleteTable() ### deleteAllTables() Deletes all tables in the database. ### listIndexes() Returns an array of index names as strings. ### describeIndex() Returns information about the index: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; type: "ivfflat" | "hnsw"; config: { m?: number; efConstruction?: number; numPartitions?: number; numSubVectors?: number; }; } ``` ### deleteIndex() ### updateVector() ", description: "New metadata values", isOptional: true, }, ], }, ], }, ]} /> ### deleteVector() ### close() Closes the database connection. ## Response Types Query results are returned in this format: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true document?: string; // Document text if available } ``` ## Error Handling The store throws typed errors that can be caught: ```typescript copy try { await store.query({ tableName: "my_vectors", queryVector: queryVector, }); } catch (error) { if (error instanceof Error) { console.log(error.message); } } ``` ## Best Practices - Use the appropriate index type for your use case: - HNSW for better recall and performance when memory isn't constrained - IVF for better memory efficiency with large datasets - For optimal performance with large datasets, consider adjusting `numPartitions` and `numSubVectors` values - Use `close()` method to properly close connections when done with the database - Store metadata with a consistent schema to simplify filtering operations ## Related - [Metadata Filters](./metadata-filters) --- title: "Default Vector Store | Vector Databases | RAG | Mastra Docs" description: Documentation for the LibSQLVector class in Mastra, which provides vector search using LibSQL with vector extensions. --- # LibSQLVector Store [EN] Source: https://mastra.ai/en/reference/rag/libsql The LibSQL storage implementation provides a SQLite-compatible vector search [LibSQL](https://github.com/tursodatabase/libsql), a fork of SQLite with vector extensions, and [Turso](https://turso.tech/) with vector extensions, offering a lightweight and efficient vector database solution. It's part of the `@mastra/libsql` package and offers efficient vector similarity search with metadata filtering. ## Installation Default vector store is included in the core package: ```bash copy npm install @mastra/libsql@latest ``` ## Usage ```typescript copy showLineNumbers import { LibSQLVector } from "@mastra/libsql"; // Create a new vector store instance const store = new LibSQLVector({ connectionUrl: process.env.DATABASE_URL, // Optional: for Turso cloud databases authToken: process.env.DATABASE_AUTH_TOKEN, }); // Create an index await store.createIndex({ indexName: "myCollection", dimension: 1536, }); // Add vectors with metadata const vectors = [[0.1, 0.2, ...], [0.3, 0.4, ...]]; const metadata = [ { text: "first document", category: "A" }, { text: "second document", category: "B" } ]; await store.upsert({ indexName: "myCollection", vectors, metadata, }); // Query similar vectors const queryVector = [0.1, 0.2, ...]; const results = await store.query({ indexName: "myCollection", queryVector, topK: 10, // top K results filter: { category: "A" } // optional metadata filter }); ``` ## Constructor Options ## Methods ### createIndex() Creates a new vector collection. The index name must start with a letter or underscore and can only contain letters, numbers, and underscores. The dimension must be a positive integer. ### upsert() Adds or updates vectors and their metadata in the index. Uses a transaction to ensure all vectors are inserted atomically - if any insert fails, the entire operation is rolled back. []", isOptional: true, description: "Metadata for each vector", }, { name: "ids", type: "string[]", isOptional: true, description: "Optional vector IDs (auto-generated if not provided)", }, ]} /> ### query() Searches for similar vectors with optional metadata filtering. ### describeIndex() Gets information about an index. Returns: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() Deletes an index and all its data. ### listIndexes() Lists all vector indexes in the database. Returns: `Promise` ### truncateIndex() Removes all vectors from an index while keeping the index structure. ### updateVector() Updates a specific vector entry by its ID with new vector data and/or metadata. ", isOptional: true, description: "New metadata to update", }, ]} /> ### deleteVector() Deletes a specific vector entry from an index by its ID. ## Response Types Query results are returned in this format: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true } ``` ## Error Handling The store throws specific errors for different failure cases: ```typescript copy try { await store.query({ indexName: "my-collection", queryVector: queryVector, }); } catch (error) { // Handle specific error cases if (error.message.includes("Invalid index name format")) { console.error( "Index name must start with a letter/underscore and contain only alphanumeric characters", ); } else if (error.message.includes("Table not found")) { console.error("The specified index does not exist"); } else { console.error("Vector store error:", error.message); } } ``` Common error cases include: - Invalid index name format - Invalid vector dimensions - Table/index not found - Database connection issues - Transaction failures during upsert ## Related - [Metadata Filters](./metadata-filters) --- title: "Reference: Metadata Filters | Metadata Filtering | RAG | Mastra Docs" description: Documentation for metadata filtering capabilities in Mastra, which allow for precise querying of vector search results across different vector stores. --- # Metadata Filters [EN] Source: https://mastra.ai/en/reference/rag/metadata-filters Mastra provides a unified metadata filtering syntax across all vector stores, based on MongoDB/Sift query syntax. Each vector store translates these filters into their native format. ## Basic Example ```typescript import { PgVector } from "@mastra/pg"; const store = new PgVector({ connectionString }); const results = await store.query({ indexName: "my_index", queryVector: queryVector, topK: 10, filter: { category: "electronics", // Simple equality price: { $gt: 100 }, // Numeric comparison tags: { $in: ["sale", "new"] }, // Array membership }, }); ``` ## Supported Operators ## Common Rules and Restrictions 1. Field names cannot: - Contain dots (.) unless referring to nested fields - Start with $ or contain null characters - Be empty strings 2. Values must be: - Valid JSON types (string, number, boolean, object, array) - Not undefined - Properly typed for the operator (e.g., numbers for numeric comparisons) 3. Logical operators: - Must contain valid conditions - Cannot be empty - Must be properly nested - Can only be used at top level or nested within other logical operators - Cannot be used at field level or nested inside a field - Cannot be used inside an operator - Valid: `{ "$and": [{ "field": { "$gt": 100 } }] }` - Valid: `{ "$or": [{ "$and": [{ "field": { "$gt": 100 } }] }] }` - Invalid: `{ "field": { "$and": [{ "$gt": 100 }] } }` - Invalid: `{ "field": { "$gt": { "$and": [{...}] } } }` 4. $not operator: - Must be an object - Cannot be empty - Can be used at field level or top level - Valid: `{ "$not": { "field": "value" } }` - Valid: `{ "field": { "$not": { "$eq": "value" } } }` 5. Operator nesting: - Logical operators must contain field conditions, not direct operators - Valid: `{ "$and": [{ "field": { "$gt": 100 } }] }` - Invalid: `{ "$and": [{ "$gt": 100 }] }` ## Store-Specific Notes ### Astra - Nested field queries are supported using dot notation - Array fields must be explicitly defined as arrays in the metadata - Metadata values are case-sensitive ### ChromaDB - Where filters only return results where the filtered field exists in metadata - Empty metadata fields are not included in filter results - Metadata fields must be present for negative matches (e.g., $ne won't match documents missing the field) ### Cloudflare Vectorize - Requires explicit metadata indexing before filtering can be used - Use `createMetadataIndex()` to index fields you want to filter on - Up to 10 metadata indexes per Vectorize index - String values are indexed up to first 64 bytes (truncated on UTF-8 boundaries) - Number values use float64 precision - Filter JSON must be under 2048 bytes - Field names cannot contain dots (.) or start with $ - Field names limited to 512 characters - Vectors must be re-upserted after creating new metadata indexes to be included in filtered results - Range queries may have reduced accuracy with very large datasets (~10M+ vectors) ### LibSQL - Supports nested object queries with dot notation - Array fields are validated to ensure they contain valid JSON arrays - Numeric comparisons maintain proper type handling - Empty arrays in conditions are handled gracefully - Metadata is stored in a JSONB column for efficient querying ### PgVector - Full support for PostgreSQL's native JSON querying capabilities - Efficient handling of array operations using native array functions - Proper type handling for numbers, strings, and booleans - Nested field queries use PostgreSQL's JSON path syntax internally - Metadata is stored in a JSONB column for efficient indexing ### Pinecone - Metadata field names are limited to 512 characters - Numeric values must be within the range of ±1e38 - Arrays in metadata are limited to 64KB total size - Nested objects are flattened with dot notation - Metadata updates replace the entire metadata object ### Qdrant - Supports advanced filtering with nested conditions - Payload (metadata) fields must be explicitly indexed for filtering - Efficient handling of geo-spatial queries - Special handling for null and empty values - Vector-specific filtering capabilities - Datetime values must be in RFC 3339 format ### Upstash - 512-character limit for metadata field keys - Query size is limited (avoid large IN clauses) - No support for null/undefined values in filters - Translates to SQL-like syntax internally - Case-sensitive string comparisons - Metadata updates are atomic ### MongoDB - Full support for MongoDB/Sift query syntax for metadata filters - Supports all standard comparison, array, logical, and element operators - Supports nested fields and arrays in metadata - Filtering can be applied to both `metadata` and the original document content using the `filter` and `documentFilter` options, respectively - `filter` applies to the metadata object; `documentFilter` applies to the original document fields - No artificial limits on filter size or complexity (subject to MongoDB query limits) - Indexing metadata fields is recommended for optimal performance ### Couchbase - Currently does not have support for metadata filters. Filtering must be done client-side after retrieving results or by using the Couchbase SDK's Search capabilities directly for more complex queries. ## Related - [Astra](./astra) - [Chroma](./chroma) - [Cloudflare Vectorize](./vectorize) - [LibSQL](./libsql) - [MongoDB](./mongodb) - [PgStore](./pg) - [Pinecone](./pinecone) - [Qdrant](./qdrant) - [Upstash](./upstash) --- title: "Reference: MongoDB Vector Store | Vector Databases | RAG | Mastra Docs" description: Documentation for the MongoDBVector class in Mastra, which provides vector search using MongoDB Atlas and Atlas Vector Search. --- # MongoDB Vector Store [EN] Source: https://mastra.ai/en/reference/rag/mongodb The `MongoDBVector` class provides vector search using [MongoDB Atlas Vector Search](https://www.mongodb.com/docs/atlas/atlas-vector-search/). It enables efficient similarity search and metadata filtering within your MongoDB collections. ## Installation ```bash copy npm install @mastra/mongodb ``` ## Usage Example ```typescript copy showLineNumbers import { MongoDBVector } from "@mastra/mongodb"; const store = new MongoDBVector({ url: process.env.MONGODB_URL, database: process.env.MONGODB_DATABASE, }); ``` ## Constructor Options ## Methods ### createIndex() Creates a new vector index (collection) in MongoDB. ### upsert() Adds or updates vectors and their metadata in the collection. []", isOptional: true, description: "Metadata for each vector", }, { name: "ids", type: "string[]", isOptional: true, description: "Optional vector IDs (auto-generated if not provided)", }, ]} /> ### query() Searches for similar vectors with optional metadata filtering. ", isOptional: true, description: "Metadata filters (applies to the `metadata` field)", }, { name: "documentFilter", type: "Record", isOptional: true, description: "Filters on original document fields (not just metadata)", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "Whether to include vector data in results", }, { name: "minScore", type: "number", isOptional: true, defaultValue: "0", description: "Minimum similarity score threshold", }, ]} /> ### describeIndex() Returns information about the index (collection). Returns: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() Deletes a collection and all its data. ### listIndexes() Lists all vector collections in the MongoDB database. Returns: `Promise` ### updateVector() Updates a specific vector entry by its ID with new vector data and/or metadata. ", isOptional: true, description: "New metadata to update", }, ]} /> ### deleteVector() Deletes a specific vector entry from an index by its ID. ### disconnect() Closes the MongoDB client connection. Should be called when done using the store. ## Response Types Query results are returned in this format: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true } ``` ## Error Handling The store throws typed errors that can be caught: ```typescript copy try { await store.query({ indexName: "my_collection", queryVector: queryVector, }); } catch (error) { // Handle specific error cases if (error.message.includes("Invalid collection name")) { console.error( "Collection name must start with a letter or underscore and contain only valid characters.", ); } else if (error.message.includes("Collection not found")) { console.error("The specified collection does not exist"); } else { console.error("Vector store error:", error.message); } } ``` ## Best Practices - Index metadata fields used in filters for optimal query performance. - Use consistent field naming in metadata to avoid unexpected query results. - Regularly monitor index and collection statistics to ensure efficient search. ## Related - [Metadata Filters](./metadata-filters) --- title: "Reference: OpenSearch Vector Store | Vector Databases | RAG | Mastra Docs" description: Documentation for the OpenSearchVector class in Mastra, which provides vector search using OpenSearch. --- # OpenSearch Vector Store [EN] Source: https://mastra.ai/en/reference/rag/opensearch The OpenSearchVector class provides vector search using [OpenSearch](https://opensearch.org/), a powerful open-source search and analytics engine. It leverages OpenSearch's k-NN capabilities to perform efficient vector similarity search. ## Constructor Options ## Methods ### createIndex() Creates a new index with the specified configuration. ### listIndexes() Lists all indexes in the OpenSearch instance. Returns: `Promise` ### describeIndex() Gets information about an index. ### deleteIndex() ### upsert() []", description: "Array of metadata objects corresponding to each vector", isOptional: true, }, { name: "ids", type: "string[]", description: "Optional array of IDs for the vectors. If not provided, random IDs will be generated", isOptional: true, }, ]} /> ### query() ### updateVector() Updates a specific vector entry by its ID with new vector data and/or metadata. ", description: "The new metadata", isOptional: true, }, ]} /> ### deleteVector() Deletes specific vector entries by their IDs from the index. ## Related - [Metadata Filters](./metadata-filters) --- title: "Reference: PG Vector Store | Vector Databases | RAG | Mastra Docs" description: Documentation for the PgVector class in Mastra, which provides vector search using PostgreSQL with pgvector extension. --- # PG Vector Store [EN] Source: https://mastra.ai/en/reference/rag/pg The PgVector class provides vector search using [PostgreSQL](https://www.postgresql.org/) with [pgvector](https://github.com/pgvector/pgvector) extension. It provides robust vector similarity search capabilities within your existing PostgreSQL database. ## Constructor Options ## Constructor Examples You can instantiate `PgVector` using a config object (with optional schemaName): ```ts import { PgVector } from "@mastra/pg"; const vectorStore = new PgVector({ connectionString: "postgresql://user:password@localhost:5432/mydb", schemaName: "custom_schema", // optional }); ``` ## Methods ### createIndex() #### IndexConfig #### Memory Requirements HNSW indexes require significant shared memory during construction. For 100K vectors: - Small dimensions (64d): ~60MB with default settings - Medium dimensions (256d): ~180MB with default settings - Large dimensions (384d+): ~250MB+ with default settings Higher M values or efConstruction values will increase memory requirements significantly. Adjust your system's shared memory limits if needed. ### upsert() []", isOptional: true, description: "Metadata for each vector", }, { name: "ids", type: "string[]", isOptional: true, description: "Optional vector IDs (auto-generated if not provided)", }, ]} /> ### query() ", isOptional: true, description: "Metadata filters", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "Whether to include the vector in the result", }, { name: "minScore", type: "number", isOptional: true, defaultValue: "0", description: "Minimum similarity score threshold", }, { name: "options", type: "{ ef?: number; probes?: number }", isOptional: true, description: "Additional options for HNSW and IVF indexes", properties: [ { type: "object", parameters: [ { name: "ef", type: "number", description: "HNSW search parameter", isOptional: true, }, { name: "probes", type: "number", description: "IVF search parameter", isOptional: true, }, ], }, ], }, ]} /> ### listIndexes() Returns an array of index names as strings. ### describeIndex() Returns: ```typescript copy interface PGIndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; type: "flat" | "hnsw" | "ivfflat"; config: { m?: number; efConstruction?: number; lists?: number; probes?: number; }; } ``` ### deleteIndex() ### updateVector() ", description: "New metadata values", isOptional: true, }, ], }, ], }, ]} /> Updates an existing vector by ID. At least one of vector or metadata must be provided. ```typescript copy // Update just the vector await pgVector.updateVector({ indexName: "my_vectors", id: "vector123", update: { vector: [0.1, 0.2, 0.3], }, }); // Update just the metadata await pgVector.updateVector({ indexName: "my_vectors", id: "vector123", update: { metadata: { label: "updated" }, }, }); // Update both vector and metadata await pgVector.updateVector({ indexName: "my_vectors", id: "vector123", update: { vector: [0.1, 0.2, 0.3], metadata: { label: "updated" }, }, }); ``` ### deleteVector() Deletes a single vector by ID from the specified index. ```typescript copy await pgVector.deleteVector({ indexName: "my_vectors", id: "vector123" }); ``` ### disconnect() Closes the database connection pool. Should be called when done using the store. ### buildIndex() Builds or rebuilds an index with specified metric and configuration. Will drop any existing index before creating the new one. ```typescript copy // Define HNSW index await pgVector.buildIndex("my_vectors", "cosine", { type: "hnsw", hnsw: { m: 8, efConstruction: 32, }, }); // Define IVF index await pgVector.buildIndex("my_vectors", "cosine", { type: "ivfflat", ivf: { lists: 100, }, }); // Define flat index await pgVector.buildIndex("my_vectors", "cosine", { type: "flat", }); ``` ## Response Types Query results are returned in this format: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true } ``` ## Error Handling The store throws typed errors that can be caught: ```typescript copy try { await store.query({ indexName: "index_name", queryVector: queryVector, }); } catch (error) { if (error instanceof VectorStoreError) { console.log(error.code); // 'connection_failed' | 'invalid_dimension' | etc console.log(error.details); // Additional error context } } ``` ## Best Practices - Regularly evaluate your index configuration to ensure optimal performance. - Adjust parameters like `lists` and `m` based on dataset size and query requirements. - Rebuild indexes periodically to maintain efficiency, especially after significant data changes. ## Related - [Metadata Filters](./metadata-filters) --- title: "Reference: Pinecone Vector Store | Vector DBs | RAG | Mastra Docs" description: Documentation for the PineconeVector class in Mastra, which provides an interface to Pinecone's vector database. --- # Pinecone Vector Store [EN] Source: https://mastra.ai/en/reference/rag/pinecone The PineconeVector class provides an interface to [Pinecone](https://www.pinecone.io/)'s vector database. It provides real-time vector search, with features like hybrid search, metadata filtering, and namespace management. ## Constructor Options ## Methods ### createIndex() ### upsert() []", isOptional: true, description: "Metadata for each vector", }, { name: "ids", type: "string[]", isOptional: true, description: "Optional vector IDs (auto-generated if not provided)", }, { name: "namespace", type: "string", isOptional: true, description: "Optional namespace to store vectors in. Vectors in different namespaces are isolated from each other.", }, ]} /> ### query() ", isOptional: true, description: "Metadata filters for the query", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "Whether to include the vector in the result", }, { name: "namespace", type: "string", isOptional: true, description: "Optional namespace to query vectors from. Only returns results from the specified namespace.", }, ]} /> ### listIndexes() Returns an array of index names as strings. ### describeIndex() Returns: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() ### updateVector() ", isOptional: true, description: "New metadata to update", }, ]} /> ### deleteVector() ## Response Types Query results are returned in this format: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true } ``` ## Error Handling The store throws typed errors that can be caught: ```typescript copy try { await store.query({ indexName: "index_name", queryVector: queryVector, }); } catch (error) { if (error instanceof VectorStoreError) { console.log(error.code); // 'connection_failed' | 'invalid_dimension' | etc console.log(error.details); // Additional error context } } ``` ### Environment Variables Required environment variables: - `PINECONE_API_KEY`: Your Pinecone API key - `PINECONE_ENVIRONMENT`: Pinecone environment (e.g., 'us-west1-gcp') ## Hybrid Search Pinecone supports hybrid search by combining dense and sparse vectors. To use hybrid search: 1. Create an index with `metric: 'dotproduct'` 2. During upsert, provide sparse vectors using the `sparseVectors` parameter 3. During query, provide a sparse vector using the `sparseVector` parameter ## Related - [Metadata Filters](./metadata-filters) --- title: "Reference: Qdrant Vector Store | Vector Databases | RAG | Mastra Docs" description: Documentation for integrating Qdrant with Mastra, a vector similarity search engine for managing vectors and payloads. --- # Qdrant Vector Store [EN] Source: https://mastra.ai/en/reference/rag/qdrant The QdrantVector class provides vector search using [Qdrant](https://qdrant.tech/), a vector similarity search engine. It provides a production-ready service with a convenient API to store, search, and manage vectors with additional payload and extended filtering support. ## Constructor Options ## Methods ### createIndex() ### upsert() []", isOptional: true, description: "Metadata for each vector", }, { name: "ids", type: "string[]", isOptional: true, description: "Optional vector IDs (auto-generated if not provided)", }, ]} /> ### query() ", isOptional: true, description: "Metadata filters for the query", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "Whether to include vectors in the results", }, ]} /> ### listIndexes() Returns an array of index names as strings. ### describeIndex() Returns: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() ### updateVector() ; }", description: "Object containing the vector and/or metadata to update", }, ]} /> Updates a vector and/or its metadata in the specified index. If both vector and metadata are provided, both will be updated. If only one is provided, only that will be updated. ### deleteVector() Deletes a vector from the specified index by its ID. ## Response Types Query results are returned in this format: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true } ``` ## Error Handling The store throws typed errors that can be caught: ```typescript copy try { await store.query({ indexName: "index_name", queryVector: queryVector, }); } catch (error) { if (error instanceof VectorStoreError) { console.log(error.code); // 'connection_failed' | 'invalid_dimension' | etc console.log(error.details); // Additional error context } } ``` ## Related - [Metadata Filters](./metadata-filters) --- title: "Reference: Rerank | Document Retrieval | RAG | Mastra Docs" description: Documentation for the rerank function in Mastra, which provides advanced reranking capabilities for vector search results. --- # rerank() [EN] Source: https://mastra.ai/en/reference/rag/rerank The `rerank()` function provides advanced reranking capabilities for vector search results by combining semantic relevance, vector similarity, and position-based scoring. ```typescript function rerank( results: QueryResult[], query: string, modelConfig: ModelConfig, options?: RerankerFunctionOptions, ): Promise; ``` ## Usage Example ```typescript import { openai } from "@ai-sdk/openai"; import { rerank } from "@mastra/rag"; const model = openai("gpt-4o-mini"); const rerankedResults = await rerank( vectorSearchResults, "How do I deploy to production?", model, { weights: { semantic: 0.5, vector: 0.3, position: 0.2, }, topK: 3, }, ); ``` ## Parameters The rerank function accepts any LanguageModel from the Vercel AI SDK. When using the Cohere model `rerank-v3.5`, it will automatically use Cohere's reranking capabilities. > **Note:** For semantic scoring to work properly during re-ranking, each result must include the text content in its `metadata.text` field. ### RerankerFunctionOptions ## Returns The function returns an array of `RerankResult` objects: ### ScoringDetails ## Related - [createVectorQueryTool](../tools/vector-query-tool) --- title: "Reference: Turbopuffer Vector Store | Vector Databases | RAG | Mastra Docs" description: Documentation for integrating Turbopuffer with Mastra, a high-performance vector database for efficient similarity search. --- # Turbopuffer Vector Store [EN] Source: https://mastra.ai/en/reference/rag/turbopuffer The TurbopufferVector class provides vector search using [Turbopuffer](https://turbopuffer.com/), a high-performance vector database optimized for RAG applications. Turbopuffer offers fast vector similarity search with advanced filtering capabilities and efficient storage management. ## Constructor Options ## Methods ### createIndex() ### upsert() []", isOptional: true, description: "Metadata for each vector", }, { name: "ids", type: "string[]", isOptional: true, description: "Optional vector IDs (auto-generated if not provided)", }, ]} /> ### query() ", isOptional: true, description: "Metadata filters for the query", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "Whether to include vectors in the results", }, ]} /> ### listIndexes() Returns an array of index names as strings. ### describeIndex() Returns: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() ## Response Types Query results are returned in this format: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true } ``` ## Schema Configuration The `schemaConfigForIndex` option allows you to define explicit schemas for different indexes: ```typescript copy schemaConfigForIndex: (indexName: string) => { // Mastra's default embedding model and index for memory messages: if (indexName === "memory_messages_384") { return { dimensions: 384, schema: { thread_id: { type: "string", filterable: true, }, }, }; } else { throw new Error(`TODO: add schema for index: ${indexName}`); } }; ``` ## Error Handling The store throws typed errors that can be caught: ```typescript copy try { await store.query({ indexName: "index_name", queryVector: queryVector, }); } catch (error) { if (error instanceof VectorStoreError) { console.log(error.code); // 'connection_failed' | 'invalid_dimension' | etc console.log(error.details); // Additional error context } } ``` ## Related - [Metadata Filters](./metadata-filters) --- title: "Reference: Upstash Vector Store | Vector Databases | RAG | Mastra Docs" description: Documentation for the UpstashVector class in Mastra, which provides vector search using Upstash Vector. --- # Upstash Vector Store [EN] Source: https://mastra.ai/en/reference/rag/upstash The UpstashVector class provides vector search using [Upstash Vector](https://upstash.com/vector), a serverless vector database service that provides vector similarity search with metadata filtering capabilities. ## Constructor Options ## Methods ### createIndex() Note: This method is a no-op for Upstash as indexes are created automatically. ### upsert() []", isOptional: true, description: "Metadata for each vector", }, { name: "ids", type: "string[]", isOptional: true, description: "Optional vector IDs (auto-generated if not provided)", }, ]} /> ### query() ", isOptional: true, description: "Metadata filters for the query", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "Whether to include vectors in the results", }, ]} /> ### listIndexes() Returns an array of index names (namespaces) as strings. ### describeIndex() Returns: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() ### updateVector() The `update` object can have the following properties: - `vector` (optional): An array of numbers representing the new vector. - `metadata` (optional): A record of key-value pairs for metadata. Throws an error if neither `vector` nor `metadata` is provided, or if only `metadata` is provided. ### deleteVector() Attempts to delete an item by its ID from the specified index. Logs an error message if the deletion fails. ## Response Types Query results are returned in this format: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true } ``` ## Error Handling The store throws typed errors that can be caught: ```typescript copy try { await store.query({ indexName: "index_name", queryVector: queryVector, }); } catch (error) { if (error instanceof VectorStoreError) { console.log(error.code); // 'connection_failed' | 'invalid_dimension' | etc console.log(error.details); // Additional error context } } ``` ## Environment Variables Required environment variables: - `UPSTASH_VECTOR_URL`: Your Upstash Vector database URL - `UPSTASH_VECTOR_TOKEN`: Your Upstash Vector API token ## Related - [Metadata Filters](./metadata-filters) --- title: "Reference: Cloudflare Vector Store | Vector Databases | RAG | Mastra Docs" description: Documentation for the CloudflareVector class in Mastra, which provides vector search using Cloudflare Vectorize. --- # Cloudflare Vector Store [EN] Source: https://mastra.ai/en/reference/rag/vectorize The CloudflareVector class provides vector search using [Cloudflare Vectorize](https://developers.cloudflare.com/vectorize/), a vector database service integrated with Cloudflare's edge network. ## Constructor Options ## Methods ### createIndex() ### upsert() []", isOptional: true, description: "Metadata for each vector", }, { name: "ids", type: "string[]", isOptional: true, description: "Optional vector IDs (auto-generated if not provided)", }, ]} /> ### query() ", isOptional: true, description: "Metadata filters for the query", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "Whether to include vectors in the results", }, ]} /> ### listIndexes() Returns an array of index names as strings. ### describeIndex() Returns: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() ### createMetadataIndex() Creates an index on a metadata field to enable filtering. ### deleteMetadataIndex() Removes an index from a metadata field. ### listMetadataIndexes() Lists all metadata field indexes for an index. ### updateVector() Updates a vector or metadata for a specific ID within an index. ; }", description: "Object containing the vector and/or metadata to update", }, ]} /> ### deleteVector() Deletes a vector and its associated metadata for a specific ID within an index. ## Response Types Query results are returned in this format: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; } ``` ## Error Handling The store throws typed errors that can be caught: ```typescript copy try { await store.query({ indexName: "index_name", queryVector: queryVector, }); } catch (error) { if (error instanceof VectorStoreError) { console.log(error.code); // 'connection_failed' | 'invalid_dimension' | etc console.log(error.details); // Additional error context } } ``` ## Environment Variables Required environment variables: - `CLOUDFLARE_ACCOUNT_ID`: Your Cloudflare account ID - `CLOUDFLARE_API_TOKEN`: Your Cloudflare API token with Vectorize permissions ## Related - [Metadata Filters](./metadata-filters) --- title: "Cloudflare D1 Storage | Storage System | Mastra Core" description: Documentation for the Cloudflare D1 SQL storage implementation in Mastra. --- # Cloudflare D1 Storage [EN] Source: https://mastra.ai/en/reference/storage/cloudflare-d1 The Cloudflare D1 storage implementation provides a serverless SQL database solution using Cloudflare D1, supporting relational operations and transactional consistency. ## Installation ```bash npm install @mastra/cloudflare-d1@latest ``` ## Usage ```typescript copy showLineNumbers import { D1Store } from "@mastra/cloudflare-d1"; type Env = { // Add your bindings here, e.g. Workers KV, D1, Workers AI, etc. D1Database: D1Database; }; // --- Example 1: Using Workers Binding --- const storageWorkers = new D1Store({ binding: D1Database, // D1Database binding provided by the Workers runtime tablePrefix: "dev_", // Optional: isolate tables per environment }); // --- Example 2: Using REST API --- const storageRest = new D1Store({ accountId: process.env.CLOUDFLARE_ACCOUNT_ID!, // Cloudflare Account ID databaseId: process.env.CLOUDFLARE_D1_DATABASE_ID!, // D1 Database ID apiToken: process.env.CLOUDFLARE_API_TOKEN!, // Cloudflare API Token tablePrefix: "dev_", // Optional: isolate tables per environment }); ``` And add the following to your `wrangler.toml` or `wrangler.jsonc` file: ``` [[d1_databases]] binding = "D1Database" database_name = "db-name" database_id = "db-id" ``` ## Parameters ## Additional Notes ### Schema Management The storage implementation handles schema creation and updates automatically. It creates the following tables: - `threads`: Stores conversation threads - `messages`: Stores individual messages - `metadata`: Stores additional metadata for threads and messages ### Transactions & Consistency Cloudflare D1 provides transactional guarantees for single-row operations. This means that multiple operations can be executed as a single, all-or-nothing unit of work. ### Table Creation & Migrations Tables are created automatically when storage is initialized (and can be isolated per environment using the `tablePrefix` option), but advanced schema changes—such as adding columns, changing data types, or modifying indexes—require manual migration and careful planning to avoid data loss. --- title: "Cloudflare Storage | Storage System | Mastra Core" description: Documentation for the Cloudflare KV storage implementation in Mastra. --- # Cloudflare Storage [EN] Source: https://mastra.ai/en/reference/storage/cloudflare The Cloudflare KV storage implementation provides a globally distributed, serverless key-value store solution using Cloudflare Workers KV. ## Installation ```bash copy npm install @mastra/cloudflare@latest ``` ## Usage ```typescript copy showLineNumbers import { CloudflareStore } from "@mastra/cloudflare"; // --- Example 1: Using Workers Binding --- const storageWorkers = new CloudflareStore({ bindings: { threads: THREADS_KV, // KVNamespace binding for threads table messages: MESSAGES_KV, // KVNamespace binding for messages table // Add other tables as needed }, keyPrefix: "dev_", // Optional: isolate keys per environment }); // --- Example 2: Using REST API --- const storageRest = new CloudflareStore({ accountId: process.env.CLOUDFLARE_ACCOUNT_ID!, // Cloudflare Account ID apiToken: process.env.CLOUDFLARE_API_TOKEN!, // Cloudflare API Token namespacePrefix: "dev_", // Optional: isolate namespaces per environment }); ``` ## Parameters ", description: "Cloudflare Workers KV bindings (for Workers runtime)", isOptional: true, }, { name: "accountId", type: "string", description: "Cloudflare Account ID (for REST API)", isOptional: true, }, { name: "apiToken", type: "string", description: "Cloudflare API Token (for REST API)", isOptional: true, }, { name: "namespacePrefix", type: "string", description: "Optional prefix for all namespace names (useful for environment isolation)", isOptional: true, }, { name: "keyPrefix", type: "string", description: "Optional prefix for all keys (useful for environment isolation)", isOptional: true, }, ]} /> #### Additional Notes ### Schema Management The storage implementation handles schema creation and updates automatically. It creates the following tables: - `threads`: Stores conversation threads - `messages`: Stores individual messages - `metadata`: Stores additional metadata for threads and messages ### Consistency & Propagation Cloudflare KV is an eventually consistent store, meaning that data may not be immediately available across all regions after a write. ### Key Structure & Namespacing Keys in Cloudflare KV are structured as a combination of a configurable prefix and a table-specific format (e.g., `threads:threadId`). For Workers deployments, `keyPrefix` is used to isolate data within a namespace; for REST API deployments, `namespacePrefix` is used to isolate entire namespaces between environments or applications. --- title: "DynamoDB Storage | Storage System | Mastra Core" description: "Documentation for the DynamoDB storage implementation in Mastra, using a single-table design with ElectroDB." --- # DynamoDB Storage [EN] Source: https://mastra.ai/en/reference/storage/dynamodb The DynamoDB storage implementation provides a scalable and performant NoSQL database solution for Mastra, leveraging a single-table design pattern with [ElectroDB](https://electrodb.dev/). ## Features - Efficient single-table design for all Mastra storage needs - Based on ElectroDB for type-safe DynamoDB access - Support for AWS credentials, regions, and endpoints - Compatible with AWS DynamoDB Local for development - Stores Thread, Message, Trace, Eval, and Workflow data - Optimized for serverless environments ## Installation ```bash copy npm install @mastra/dynamodb@latest # or pnpm add @mastra/dynamodb@latest # or yarn add @mastra/dynamodb@latest ``` ## Prerequisites Before using this package, you **must** create a DynamoDB table with a specific structure, including primary keys and Global Secondary Indexes (GSIs). This adapter expects the DynamoDB table and its GSIs to be provisioned externally. Detailed instructions for setting up the table using AWS CloudFormation or AWS CDK are available in [TABLE_SETUP.md](https://github.com/mastra-ai/mastra/blob/main/stores/dynamodb/TABLE_SETUP.md). Please ensure your table is configured according to those instructions before proceeding. ## Usage ### Basic Usage ```typescript copy showLineNumbers import { Memory } from "@mastra/memory"; import { DynamoDBStore } from "@mastra/dynamodb"; // Initialize the DynamoDB storage const storage = new DynamoDBStore({ name: "dynamodb", // A name for this storage instance config: { tableName: "mastra-single-table", // Name of your DynamoDB table region: "us-east-1", // Optional: AWS region, defaults to 'us-east-1' // endpoint: "http://localhost:8000", // Optional: For local DynamoDB // credentials: { accessKeyId: "YOUR_ACCESS_KEY", secretAccessKey: "YOUR_SECRET_KEY" } // Optional }, }); // Example: Initialize Memory with DynamoDB storage const memory = new Memory({ storage, options: { lastMessages: 10, }, }); ``` ### Local Development with DynamoDB Local For local development, you can use [DynamoDB Local](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html). 1. **Run DynamoDB Local (e.g., using Docker):** ```bash docker run -p 8000:8000 amazon/dynamodb-local ``` 2. **Configure `DynamoDBStore` to use the local endpoint:** ```typescript copy showLineNumbers import { DynamoDBStore } from "@mastra/dynamodb"; const storage = new DynamoDBStore({ name: "dynamodb-local", config: { tableName: "mastra-single-table", // Ensure this table is created in your local DynamoDB region: "localhost", // Can be any string for local, 'localhost' is common endpoint: "http://localhost:8000", // For DynamoDB Local, credentials are not typically required unless configured. // If you've configured local credentials: // credentials: { accessKeyId: "fakeMyKeyId", secretAccessKey: "fakeSecretAccessKey" } }, }); ``` You will still need to create the table and GSIs in your local DynamoDB instance, for example, using the AWS CLI pointed to your local endpoint. ## Parameters ## AWS IAM Permissions The IAM role or user executing the code needs appropriate permissions to interact with the specified DynamoDB table and its indexes. Below is a sample policy. Replace `${YOUR_TABLE_NAME}` with your actual table name and `${YOUR_AWS_REGION}` and `${YOUR_AWS_ACCOUNT_ID}` with appropriate values. ```json copy { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "dynamodb:DescribeTable", "dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:UpdateItem", "dynamodb:DeleteItem", "dynamodb:Query", "dynamodb:Scan", "dynamodb:BatchGetItem", "dynamodb:BatchWriteItem" ], "Resource": [ "arn:aws:dynamodb:${YOUR_AWS_REGION}:${YOUR_AWS_ACCOUNT_ID}:table/${YOUR_TABLE_NAME}", "arn:aws:dynamodb:${YOUR_AWS_REGION}:${YOUR_AWS_ACCOUNT_ID}:table/${YOUR_TABLE_NAME}/index/*" ] } ] } ``` ## Key Considerations Before diving into the architectural details, keep these key points in mind when working with the DynamoDB storage adapter: - **External Table Provisioning:** This adapter _requires_ you to create and configure the DynamoDB table and its Global Secondary Indexes (GSIs) yourself, prior to using the adapter. Follow the guide in [TABLE_SETUP.md](https://github.com/mastra-ai/mastra/blob/main/stores/dynamodb/TABLE_SETUP.md). - **Single-Table Design:** All Mastra data (threads, messages, etc.) is stored in one DynamoDB table. This is a deliberate design choice optimized for DynamoDB, differing from relational database approaches. - **Understanding GSIs:** Familiarity with how the GSIs are structured (as per `TABLE_SETUP.md`) is important for understanding data retrieval and potential query patterns. - **ElectroDB:** The adapter uses ElectroDB to manage interactions with DynamoDB, providing a layer of abstraction and type safety over raw DynamoDB operations. ## Architectural Approach This storage adapter utilizes a **single-table design pattern** leveraging [ElectroDB](https://electrodb.dev/), a common and recommended approach for DynamoDB. This differs architecturally from relational database adapters (like `@mastra/pg` or `@mastra/libsql`) that typically use multiple tables, each dedicated to a specific entity (threads, messages, etc.). Key aspects of this approach: - **DynamoDB Native:** The single-table design is optimized for DynamoDB's key-value and query capabilities, often leading to better performance and scalability compared to mimicking relational models. - **External Table Management:** Unlike some adapters that might offer helper functions to create tables via code, this adapter **expects the DynamoDB table and its associated Global Secondary Indexes (GSIs) to be provisioned externally** before use. Please refer to [TABLE_SETUP.md](https://github.com/mastra-ai/mastra/blob/main/stores/dynamodb/TABLE_SETUP.md) for detailed instructions using tools like AWS CloudFormation or CDK. The adapter focuses solely on interacting with the pre-existing table structure. - **Consistency via Interface:** While the underlying storage model differs, this adapter adheres to the same `MastraStorage` interface as other adapters, ensuring it can be used interchangeably within the Mastra `Memory` component. ### Mastra Data in the Single Table Within the single DynamoDB table, different Mastra data entities (such as Threads, Messages, Traces, Evals, and Workflows) are managed and distinguished using ElectroDB. ElectroDB defines specific models for each entity type, which include unique key structures and attributes. This allows the adapter to store and retrieve diverse data types efficiently within the same table. For example, a `Thread` item might have a primary key like `THREAD#`, while a `Message` item belonging to that thread might use `THREAD#` as a partition key and `MESSAGE#` as a sort key. The Global Secondary Indexes (GSIs), detailed in `TABLE_SETUP.md`, are strategically designed to support common access patterns across these different entities, such as fetching all messages for a thread or querying traces associated with a particular workflow. ### Advantages of Single-Table Design This implementation uses a single-table design pattern with ElectroDB, which offers several advantages within the context of DynamoDB: 1. **Lower cost (potentially):** Fewer tables can simplify Read/Write Capacity Unit (RCU/WCU) provisioning and management, especially with on-demand capacity. 2. **Better performance:** Related data can be co-located or accessed efficiently through GSIs, enabling fast lookups for common access patterns. 3. **Simplified administration:** Fewer distinct tables to monitor, back up, and manage. 4. **Reduced complexity in access patterns:** ElectroDB helps manage the complexity of item types and access patterns on a single table. 5. **Transaction support:** DynamoDB transactions can be used across different "entity" types stored within the same table if needed. ## License This package is distributed under the MIT License. See [LICENSE.md](https://github.com/mastra-ai/mastra/blob/main/LICENSE.md) for more information. --- title: "LanceDB Storage" description: Documentation for the LanceDB storage implementation in Mastra. --- # LanceDB Storage [EN] Source: https://mastra.ai/en/reference/storage/lance The LanceDB storage implementation provides a high-performance storage solution using the LanceDB database system, which excels at handling both traditional data storage and vector operations. ## Installation ```bash npm install @mastra/lance ``` ## Usage ### Basic Storage Usage ```typescript copy showLineNumbers import { LanceStorage } from "@mastra/lance"; // Connect to a local database const storage = await LanceStorage.create("my-storage", "/path/to/db"); // Connect to a LanceDB cloud database const storage = await LanceStorage.create("my-storage", "db://host:port"); // Connect to a cloud database with custom options const storage = await LanceStorage.create("my-storage", "s3://bucket/db", { storageOptions: { timeout: "60s" }, }); ``` ## Parameters ### LanceStorage.create() ## Additional Notes ### Schema Management The LanceStorage implementation automatically handles schema creation and updates. It maps Mastra's schema types to Apache Arrow data types, which are used by LanceDB internally: - `text`, `uuid` → Utf8 - `int`, `integer` → Int32 - `float` → Float32 - `jsonb`, `json` → Utf8 (serialized) - `binary` → Binary ### Deployment Options LanceDB storage can be configured for different deployment scenarios: - **Local Development**: Use a local file path for development and testing ``` /path/to/db ``` - **Cloud Deployment**: Connect to a hosted LanceDB instance ``` db://host:port ``` - **S3 Storage**: Use Amazon S3 for scalable cloud storage ``` s3://bucket/db ``` ### Table Management LanceStorage provides methods for managing tables: - Create tables with custom schemas - Drop tables - Clear tables (delete all records) - Load records by key - Insert single and batch records --- title: "LibSQL Storage | Storage System | Mastra Core" description: Documentation for the LibSQL storage implementation in Mastra. --- # LibSQL Storage [EN] Source: https://mastra.ai/en/reference/storage/libsql The LibSQL storage implementation provides a SQLite-compatible storage solution that can run both in-memory and as a persistent database. ## Installation ```bash copy npm install @mastra/libsql@latest ``` ## Usage ```typescript copy showLineNumbers import { LibSQLStore } from "@mastra/libsql"; // File database (development) const storage = new LibSQLStore({ url: "file:./storage.db", }); // Persistent database (production) const storage = new LibSQLStore({ url: process.env.DATABASE_URL, }); ``` ## Parameters ## Additional Notes ### In-Memory vs Persistent Storage The file configuration (`file:storage.db`) is useful for: - Development and testing - Temporary storage - Quick prototyping For production use cases, use a persistent database URL: `libsql://your-database.turso.io` ### Schema Management The storage implementation handles schema creation and updates automatically. It creates the following tables: - `threads`: Stores conversation threads - `messages`: Stores individual messages - `metadata`: Stores additional metadata for threads and messages --- title: "PostgreSQL Storage | Storage System | Mastra Core" description: Documentation for the PostgreSQL storage implementation in Mastra. --- # PostgreSQL Storage [EN] Source: https://mastra.ai/en/reference/storage/postgresql The PostgreSQL storage implementation provides a production-ready storage solution using PostgreSQL databases. ## Installation ```bash copy npm install @mastra/pg@latest ``` ## Usage ```typescript copy showLineNumbers import { PostgresStore } from "@mastra/pg"; const storage = new PostgresStore({ connectionString: process.env.DATABASE_URL, }); ``` ## Parameters ## Constructor Examples You can instantiate `PostgresStore` in the following ways: ```ts import { PostgresStore } from "@mastra/pg"; // Using a connection string only const store1 = new PostgresStore({ connectionString: "postgresql://user:password@localhost:5432/mydb", }); // Using a connection string with a custom schema name const store2 = new PostgresStore({ connectionString: "postgresql://user:password@localhost:5432/mydb", schemaName: "custom_schema", // optional }); // Using individual connection parameters const store4 = new PostgresStore({ host: "localhost", port: 5432, database: "mydb", user: "user", password: "password", }); // Individual parameters with schemaName const store5 = new PostgresStore({ host: "localhost", port: 5432, database: "mydb", user: "user", password: "password", schemaName: "custom_schema", // optional }); ``` ## Additional Notes ### Schema Management The storage implementation handles schema creation and updates automatically. It creates the following tables: - `threads`: Stores conversation threads - `messages`: Stores individual messages - `metadata`: Stores additional metadata for threads and messages --- title: "Upstash Storage | Storage System | Mastra Core" description: Documentation for the Upstash storage implementation in Mastra. --- # Upstash Storage [EN] Source: https://mastra.ai/en/reference/storage/upstash The Upstash storage implementation provides a serverless-friendly storage solution using Upstash's Redis-compatible key-value store. ## Installation ```bash copy npm install @mastra/upstash@latest ``` ## Usage ```typescript copy showLineNumbers import { UpstashStore } from "@mastra/upstash"; const storage = new UpstashStore({ url: process.env.UPSTASH_URL, token: process.env.UPSTASH_TOKEN, }); ``` ## Parameters ## Additional Notes ### Key Structure The Upstash storage implementation uses a key-value structure: - Thread keys: `{prefix}thread:{threadId}` - Message keys: `{prefix}message:{messageId}` - Metadata keys: `{prefix}metadata:{entityId}` ### Serverless Benefits Upstash storage is particularly well-suited for serverless deployments: - No connection management needed - Pay-per-request pricing - Global replication options - Edge-compatible ### Data Persistence Upstash provides: - Automatic data persistence - Point-in-time recovery - Cross-region replication options ### Performance Considerations For optimal performance: - Use appropriate key prefixes to organize data - Monitor Redis memory usage - Consider data expiration policies if needed --- title: "Reference: MastraMCPClient | Tool Discovery | Mastra Docs" description: API Reference for MastraMCPClient - A client implementation for the Model Context Protocol. --- # MastraMCPClient (Deprecated) [EN] Source: https://mastra.ai/en/reference/tools/client The `MastraMCPClient` class provides a client implementation for interacting with Model Context Protocol (MCP) servers. It handles connection management, resource discovery, and tool execution through the MCP protocol. ## Deprecation notice `MastraMCPClient` is being deprecated in favour of [`MCPClient`](./mcp-client). Rather than having two different interfaces for managing a single MCP server vs multiple MCP servers, we opted to recommend using the interface to manage multiple even when using a single MCP server. ## Constructor Creates a new instance of the MastraMCPClient. ```typescript constructor({ name, version = '1.0.0', server, capabilities = {}, timeout = 60000, }: { name: string; server: MastraMCPServerDefinition; capabilities?: ClientCapabilities; version?: string; timeout?: number; }) ``` ### Parameters
### MastraMCPServerDefinition MCP servers can be configured using this definition. The client automatically detects the transport type based on the provided parameters: - If `command` is provided, it uses the Stdio transport. - If `url` is provided, it first attempts to use the Streamable HTTP transport and falls back to the legacy SSE transport if the initial connection fails.
", isOptional: true, description: "For Stdio servers: Environment variables to set for the command.", }, { name: "url", type: "URL", isOptional: true, description: "For HTTP servers (Streamable HTTP or SSE): The URL of the server.", }, { name: "requestInit", type: "RequestInit", isOptional: true, description: "For HTTP servers: Request configuration for the fetch API.", }, { name: "eventSourceInit", type: "EventSourceInit", isOptional: true, description: "For SSE fallback: Custom fetch configuration for SSE connections. Required when using custom headers with SSE.", }, { name: "logger", type: "LogHandler", isOptional: true, description: "Optional additional handler for logging.", }, { name: "timeout", type: "number", isOptional: true, description: "Server-specific timeout in milliseconds.", }, { name: "capabilities", type: "ClientCapabilities", isOptional: true, description: "Server-specific capabilities configuration.", }, { name: "enableServerLogs", type: "boolean", isOptional: true, defaultValue: "true", description: "Whether to enable logging for this server.", }, ]} /> ### LogHandler The `LogHandler` function takes a `LogMessage` object as its parameter and returns void. The `LogMessage` object has the following properties. The `LoggingLevel` type is a string enum with values: `debug`, `info`, `warn`, and `error`.
", isOptional: true, description: "Optional additional log details", }, ]} /> ## Methods ### connect() Establishes a connection with the MCP server. ```typescript async connect(): Promise ``` ### disconnect() Closes the connection with the MCP server. ```typescript async disconnect(): Promise ``` ### resources() Retrieves the list of available resources from the server. ```typescript async resources(): Promise ``` ### tools() Fetches and initializes available tools from the server, converting them into Mastra-compatible tool formats. ```typescript async tools(): Promise> ``` Returns an object mapping tool names to their corresponding Mastra tool implementations. ## Examples ### Using with Mastra Agent #### Example with Stdio Server ```typescript import { Agent } from "@mastra/core/agent"; import { MastraMCPClient } from "@mastra/mcp"; import { openai } from "@ai-sdk/openai"; // Initialize the MCP client using mcp/fetch as an example https://hub.docker.com/r/mcp/fetch // Visit https://github.com/docker/mcp-servers for other reference docker mcp servers const fetchClient = new MastraMCPClient({ name: "fetch", server: { command: "docker", args: ["run", "-i", "--rm", "mcp/fetch"], logger: (logMessage) => { console.log(`[${logMessage.level}] ${logMessage.message}`); }, }, }); // Create a Mastra Agent const agent = new Agent({ name: "Fetch agent", instructions: "You are able to fetch data from URLs on demand and discuss the response data with the user.", model: openai("gpt-4o-mini"), }); try { // Connect to the MCP server await fetchClient.connect(); // Gracefully handle process exits so the docker subprocess is cleaned up process.on("exit", () => { fetchClient.disconnect(); }); // Get available tools const tools = await fetchClient.tools(); // Use the agent with the MCP tools const response = await agent.generate( "Tell me about mastra.ai/docs. Tell me generally what this page is and the content it includes.", { toolsets: { fetch: tools, }, }, ); console.log("\n\n" + response.text); } catch (error) { console.error("Error:", error); } finally { // Always disconnect when done await fetchClient.disconnect(); } ``` ### Example with SSE Server ```typescript // Initialize the MCP client using an SSE server const sseClient = new MastraMCPClient({ name: "sse-client", server: { url: new URL("https://your-mcp-server.com/sse"), // Optional fetch request configuration - Note: requestInit alone isn't enough for SSE requestInit: { headers: { Authorization: "Bearer your-token", }, }, // Required for SSE connections with custom headers eventSourceInit: { fetch(input: Request | URL | string, init?: RequestInit) { const headers = new Headers(init?.headers || {}); headers.set("Authorization", "Bearer your-token"); return fetch(input, { ...init, headers, }); }, }, // Optional additional logging configuration logger: (logMessage) => { console.log( `[${logMessage.level}] ${logMessage.serverName}: ${logMessage.message}`, ); }, // Disable server logs enableServerLogs: false, }, }); // The rest of the usage is identical to the stdio example ``` ### Important Note About SSE Authentication When using SSE connections with authentication or custom headers, you need to configure both `requestInit` and `eventSourceInit`. This is because SSE connections use the browser's EventSource API, which doesn't support custom headers directly. The `eventSourceInit` configuration allows you to customize the underlying fetch request used for the SSE connection, ensuring your authentication headers are properly included. Without `eventSourceInit`, authentication headers specified in `requestInit` won't be included in the connection request, leading to 401 Unauthorized errors. ## Related Information - For managing multiple MCP servers in your application, see the [MCPClient documentation](./mcp-client) - For more details about the Model Context Protocol, see the [@modelcontextprotocol/sdk documentation](https://github.com/modelcontextprotocol/typescript-sdk). --- title: "Reference: createTool() | Tools | Mastra Docs" description: Documentation for the createTool function in Mastra, used to define custom tools for agents. --- # createTool() [EN] Source: https://mastra.ai/en/reference/tools/create-tool The `createTool()` function is used to define custom tools that your Mastra agents can execute. Tools extend an agent's capabilities by allowing it to interact with external systems, perform calculations, or access specific data. ## Basic Usage Here is a basic example of creating a tool that fetches weather information: ```typescript filename="src/mastra/tools/weatherInfo.ts" copy import { createTool } from "@mastra/core/tools"; import { z } from "zod"; export const weatherInfo = createTool({ id: "Get Weather Information", inputSchema: z.object({ city: z.string(), }), description: `Fetches the current weather information for a given city`, execute: async ({ context: { city } }) => { // Tool logic here (e.g., API call) console.log("Using tool to fetch weather information for", city); return { temperature: 20, conditions: "Sunny" }; // Example return }, }); ``` ## Parameters The `createTool()` function accepts an object with the following parameters: ## Returns The `createTool()` function returns a `Tool` object. ## Tool Details The `Tool` object returned by `createTool()` has the following key properties: - **ID**: The unique identifier provided in the `id` parameter. - **Description**: The description provided in the `description` parameter. - **Parameters**: Derived from the `inputSchema`, defining the structure of inputs the tool expects. - **Execute Function**: The logic defined in the `execute` parameter, which is called when the agent decides to use the tool. ## Related - [Tools Overview](/docs/tools-mcp/overview) - [Using Tools with Agents](/docs/agents/using-tools-and-mcp) - [Dynamic Tool Context](/docs/tools-mcp/dynamic-context) - [Advanced Tool Usage](/docs/tools-mcp/advanced-usage) --- title: "Reference: createDocumentChunkerTool() | Tools | Mastra Docs" description: Documentation for the Document Chunker Tool in Mastra, which splits documents into smaller chunks for efficient processing and retrieval. --- # createDocumentChunkerTool() [EN] Source: https://mastra.ai/en/reference/tools/document-chunker-tool The `createDocumentChunkerTool()` function creates a tool for splitting documents into smaller chunks for efficient processing and retrieval. It supports different chunking strategies and configurable parameters. ## Basic Usage ```typescript import { createDocumentChunkerTool, MDocument } from "@mastra/rag"; const document = new MDocument({ text: "Your document content here...", metadata: { source: "user-manual" }, }); const chunker = createDocumentChunkerTool({ doc: document, params: { strategy: "recursive", size: 512, overlap: 50, separator: "\n", }, }); const { chunks } = await chunker.execute(); ``` ## Parameters ### ChunkParams ## Returns ## Example with Custom Parameters ```typescript const technicalDoc = new MDocument({ text: longDocumentContent, metadata: { type: "technical", version: "1.0", }, }); const chunker = createDocumentChunkerTool({ doc: technicalDoc, params: { strategy: "recursive", size: 1024, // Larger chunks overlap: 100, // More overlap separator: "\n\n", // Split on double newlines }, }); const { chunks } = await chunker.execute(); // Process the chunks chunks.forEach((chunk, index) => { console.log(`Chunk ${index + 1} length: ${chunk.content.length}`); }); ``` ## Tool Details The chunker is created as a Mastra tool with the following properties: - **Tool ID**: `Document Chunker {strategy} {size}` - **Description**: `Chunks document using {strategy} strategy with size {size} and {overlap} overlap` - **Input Schema**: Empty object (no additional inputs required) - **Output Schema**: Object containing the chunks array ## Related - [MDocument](../rag/document.mdx) - [createVectorQueryTool](./vector-query-tool) --- title: "Reference: createGraphRAGTool() | RAG | Mastra Tools Docs" description: Documentation for the Graph RAG Tool in Mastra, which enhances RAG by building a graph of semantic relationships between documents. --- import { Callout } from "nextra/components"; # createGraphRAGTool() [EN] Source: https://mastra.ai/en/reference/tools/graph-rag-tool The `createGraphRAGTool()` creates a tool that enhances RAG by building a graph of semantic relationships between documents. It uses the `GraphRAG` system under the hood to provide graph-based retrieval, finding relevant content through both direct similarity and connected relationships. ## Usage Example ```typescript import { openai } from "@ai-sdk/openai"; import { createGraphRAGTool } from "@mastra/rag"; const graphTool = createGraphRAGTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), graphOptions: { dimension: 1536, threshold: 0.7, randomWalkSteps: 100, restartProb: 0.15, }, }); ``` ## Parameters **Parameter Requirements:** Most fields can be set at creation as defaults. Some fields can be overridden at runtime via the runtime context or input. If a required field is missing from both creation and runtime, an error will be thrown. Note that `model`, `id`, and `description` can only be set at creation time. ### GraphOptions ## Returns The tool returns an object with: ### QueryResult object structure ```typescript { id: string; // Unique chunk/document identifier metadata: any; // All metadata fields (document ID, etc.) vector: number[]; // Embedding vector (if available) score: number; // Similarity score for this retrieval document: string; // Full chunk/document text (if available) } ``` ## Default Tool Description The default description focuses on: - Analyzing relationships between documents - Finding patterns and connections - Answering complex queries ## Advanced Example ```typescript const graphTool = createGraphRAGTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), graphOptions: { dimension: 1536, threshold: 0.8, // Higher similarity threshold randomWalkSteps: 200, // More exploration steps restartProb: 0.2, // Higher restart probability }, }); ``` ## Example with Custom Description ```typescript const graphTool = createGraphRAGTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), description: "Analyze document relationships to find complex patterns and connections in our company's historical data", }); ``` This example shows how to customize the tool description for a specific use case while maintaining its core purpose of relationship analysis. ## Example: Using Runtime Context ```typescript const graphTool = createGraphRAGTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), }); ``` When using runtime context, provide required parameters at execution time via the runtime context: ```typescript const runtimeContext = new RuntimeContext<{ vectorStoreName: string; indexName: string; topK: number; filter: any; }>(); runtimeContext.set("vectorStoreName", "my-store"); runtimeContext.set("indexName", "my-index"); runtimeContext.set("topK", 5); runtimeContext.set("filter", { category: "docs" }); runtimeContext.set("randomWalkSteps", 100); runtimeContext.set("restartProb", 0.15); const response = await agent.generate( "Find documentation from the knowledge base.", { runtimeContext, }, ); ``` For more information on runtime context, please see: - [Runtime Variables](../../docs/agents/runtime-variables) - [Dynamic Context](../../docs/tools-mcp/dynamic-context) ## Related - [createVectorQueryTool](./vector-query-tool) - [GraphRAG](../rag/graph-rag) --- title: "Reference: MCPClient | Tool Management | Mastra Docs" description: API Reference for MCPClient - A class for managing multiple Model Context Protocol servers and their tools. --- # MCPClient [EN] Source: https://mastra.ai/en/reference/tools/mcp-client The `MCPClient` class provides a way to manage multiple MCP server connections and their tools in a Mastra application. It handles connection lifecycle, tool namespacing, and provides access to tools across all configured servers. This class replaces the deprecated [`MastraMCPClient`](/reference/tools/client). ## Constructor Creates a new instance of the MCPClient class. ```typescript constructor({ id?: string; servers: Record; timeout?: number; }: MCPClientOptions) ``` ### MCPClientOptions
", description: "A map of server configurations, where each key is a unique server identifier and the value is the server configuration.", }, { name: "timeout", type: "number", isOptional: true, defaultValue: "60000", description: "Global timeout value in milliseconds for all servers unless overridden in individual server configs.", }, ]} /> ### MastraMCPServerDefinition Each server in the `servers` map is configured using the `MastraMCPServerDefinition` type. The transport type is detected based on the provided parameters: - If `command` is provided, it uses the Stdio transport. - If `url` is provided, it first attempts to use the Streamable HTTP transport and falls back to the legacy SSE transport if the initial connection fails.
", isOptional: true, description: "For Stdio servers: Environment variables to set for the command.", }, { name: "url", type: "URL", isOptional: true, description: "For HTTP servers (Streamable HTTP or SSE): The URL of the server.", }, { name: "requestInit", type: "RequestInit", isOptional: true, description: "For HTTP servers: Request configuration for the fetch API.", }, { name: "eventSourceInit", type: "EventSourceInit", isOptional: true, description: "For SSE fallback: Custom fetch configuration for SSE connections. Required when using custom headers with SSE.", }, { name: "logger", type: "LogHandler", isOptional: true, description: "Optional additional handler for logging.", }, { name: "timeout", type: "number", isOptional: true, description: "Server-specific timeout in milliseconds.", }, { name: "capabilities", type: "ClientCapabilities", isOptional: true, description: "Server-specific capabilities configuration.", }, { name: "enableServerLogs", type: "boolean", isOptional: true, defaultValue: "true", description: "Whether to enable logging for this server.", }, ]} /> ## Methods ### getTools() Retrieves all tools from all configured servers, with tool names namespaced by their server name (in the format `serverName_toolName`) to prevent conflicts. Intended to be passed onto an Agent definition. ```ts new Agent({ tools: await mcp.getTools() }); ``` ### getToolsets() Returns an object mapping namespaced tool names (in the format `serverName.toolName`) to their tool implementations. Intended to be passed dynamically into the generate or stream method. ```typescript const res = await agent.stream(prompt, { toolsets: await mcp.getToolsets(), }); ``` ### disconnect() Disconnects from all MCP servers and cleans up resources. ```typescript async disconnect(): Promise ``` ### `resources` Property The `MCPClient` instance has a `resources` property that provides access to resource-related operations. ```typescript const mcpClient = new MCPClient({ /* ...servers configuration... */ }); // Access resource methods via mcpClient.resources const allResourcesByServer = await mcpClient.resources.list(); const templatesByServer = await mcpClient.resources.templates(); // ... and so on for other resource methods. ``` #### `resources.list()` Retrieves all available resources from all connected MCP servers, grouped by server name. ```typescript async list(): Promise> ``` Example: ```typescript const resourcesByServer = await mcpClient.resources.list(); for (const serverName in resourcesByServer) { console.log(`Resources from ${serverName}:`, resourcesByServer[serverName]); } ``` #### `resources.templates()` Retrieves all available resource templates from all connected MCP servers, grouped by server name. ```typescript async templates(): Promise> ``` Example: ```typescript const templatesByServer = await mcpClient.resources.templates(); for (const serverName in templatesByServer) { console.log(`Templates from ${serverName}:`, templatesByServer[serverName]); } ``` #### `resources.read(serverName: string, uri: string)` Reads the content of a specific resource from a named server. ```typescript async read(serverName: string, uri: string): Promise ``` - `serverName`: The identifier of the server (key used in the `servers` constructor option). - `uri`: The URI of the resource to read. Example: ```typescript const content = await mcpClient.resources.read( "myWeatherServer", "weather://current", ); console.log("Current weather:", content.contents[0].text); ``` #### `resources.subscribe(serverName: string, uri: string)` Subscribes to updates for a specific resource on a named server. ```typescript async subscribe(serverName: string, uri: string): Promise ``` Example: ```typescript await mcpClient.resources.subscribe("myWeatherServer", "weather://current"); ``` #### `resources.unsubscribe(serverName: string, uri: string)` Unsubscribes from updates for a specific resource on a named server. ```typescript async unsubscribe(serverName: string, uri: string): Promise ``` Example: ```typescript await mcpClient.resources.unsubscribe("myWeatherServer", "weather://current"); ``` #### `resources.onUpdated(serverName: string, handler: (params: { uri: string }) => void)` Sets a notification handler that will be called when a subscribed resource on a specific server is updated. ```typescript async onUpdated(serverName: string, handler: (params: { uri: string }) => void): Promise ``` Example: ```typescript mcpClient.resources.onUpdated("myWeatherServer", (params) => { console.log(`Resource updated on myWeatherServer: ${params.uri}`); // You might want to re-fetch the resource content here // await mcpClient.resources.read("myWeatherServer", params.uri); }); ``` #### `resources.onListChanged(serverName: string, handler: () => void)` Sets a notification handler that will be called when the overall list of available resources changes on a specific server. ```typescript async onListChanged(serverName: string, handler: () => void): Promise ``` Example: ```typescript mcpClient.resources.onListChanged("myWeatherServer", () => { console.log("Resource list changed on myWeatherServer."); // You should re-fetch the list of resources // await mcpClient.resources.list(); }); ``` ### `prompts` Property The `MCPClient` instance has a `prompts` property that provides access to prompt-related operations. ```typescript const mcpClient = new MCPClient({ /* ...servers configuration... */ }); // Access prompt methods via mcpClient.prompts const allPromptsByServer = await mcpClient.prompts.list(); const { prompt, messages } = await mcpClient.prompts.get({ serverName: "myWeatherServer", name: "current", }); ``` #### `prompts.list()` Retrieves all available prompts from all connected MCP servers, grouped by server name. ```typescript async list(): Promise> ``` Example: ```typescript const promptsByServer = await mcpClient.prompts.list(); for (const serverName in promptsByServer) { console.log(`Prompts from ${serverName}:`, promptsByServer[serverName]); } ``` #### `prompts.get({ serverName, name, args?, version? })` Retrieves a specific prompt and its messages from a server. ```typescript async get({ serverName, name, args?, version?, }: { serverName: string; name: string; args?: Record; version?: string; }): Promise<{ prompt: Prompt; messages: PromptMessage[] }> ``` Example: ```typescript const { prompt, messages } = await mcpClient.prompts.get({ serverName: "myWeatherServer", name: "current", args: { location: "London" }, }); console.log(prompt); console.log(messages); ``` #### `prompts.onListChanged(serverName: string, handler: () => void)` Sets a notification handler that will be called when the list of available prompts changes on a specific server. ```typescript async onListChanged(serverName: string, handler: () => void): Promise ``` Example: ```typescript mcpClient.prompts.onListChanged("myWeatherServer", () => { console.log("Prompt list changed on myWeatherServer."); // You should re-fetch the list of prompts // await mcpClient.prompts.list(); }); ``` ## Examples ### Static Tool Configuration For tools where you have a single connection to the MCP server for you entire app, use `getTools()` and pass the tools to your agent: ```typescript import { MCPClient } from "@mastra/mcp"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const mcp = new MCPClient({ servers: { stockPrice: { command: "npx", args: ["tsx", "stock-price.ts"], env: { API_KEY: "your-api-key", }, log: (logMessage) => { console.log(`[${logMessage.level}] ${logMessage.message}`); }, }, weather: { url: new URL("http://localhost:8080/sse"), }, }, timeout: 30000, // Global 30s timeout }); // Create an agent with access to all tools const agent = new Agent({ name: "Multi-tool Agent", instructions: "You have access to multiple tool servers.", model: openai("gpt-4"), tools: await mcp.getTools(), }); // Example of using resource methods async function checkWeatherResource() { try { const weatherResources = await mcp.resources.list(); if (weatherResources.weather && weatherResources.weather.length > 0) { const currentWeatherURI = weatherResources.weather[0].uri; const weatherData = await mcp.resources.read( "weather", currentWeatherURI, ); console.log("Weather data:", weatherData.contents[0].text); } } catch (error) { console.error("Error fetching weather resource:", error); } } checkWeatherResource(); // Example of using prompt methods async function checkWeatherPrompt() { try { const weatherPrompts = await mcp.prompts.list(); if (weatherPrompts.weather && weatherPrompts.weather.length > 0) { const currentWeatherPrompt = weatherPrompts.weather.find( (p) => p.name === "current" ); if (currentWeatherPrompt) { console.log("Weather prompt:", currentWeatherPrompt); } else { console.log("Current weather prompt not found"); } } } catch (error) { console.error("Error fetching weather prompt:", error); } } checkWeatherPrompt(); ``` ### Dynamic toolsets When you need a new MCP connection for each user, use `getToolsets()` and add the tools when calling stream or generate: ```typescript import { Agent } from "@mastra/core/agent"; import { MCPClient } from "@mastra/mcp"; import { openai } from "@ai-sdk/openai"; // Create the agent first, without any tools const agent = new Agent({ name: "Multi-tool Agent", instructions: "You help users check stocks and weather.", model: openai("gpt-4"), }); // Later, configure MCP with user-specific settings const mcp = new MCPClient({ servers: { stockPrice: { command: "npx", args: ["tsx", "stock-price.ts"], env: { API_KEY: "user-123-api-key", }, timeout: 20000, // Server-specific timeout }, weather: { url: new URL("http://localhost:8080/sse"), requestInit: { headers: { Authorization: `Bearer user-123-token`, }, }, }, }, }); // Pass all toolsets to stream() or generate() const response = await agent.stream( "How is AAPL doing and what is the weather?", { toolsets: await mcp.getToolsets(), }, ); ``` ## Instance Management The `MCPClient` class includes built-in memory leak prevention for managing multiple instances: 1. Creating multiple instances with identical configurations without an `id` will throw an error to prevent memory leaks 2. If you need multiple instances with identical configurations, provide a unique `id` for each instance 3. Call `await configuration.disconnect()` before recreating an instance with the same configuration 4. If you only need one instance, consider moving the configuration to a higher scope to avoid recreation For example, if you try to create multiple instances with the same configuration without an `id`: ```typescript // First instance - OK const mcp1 = new MCPClient({ servers: { /* ... */ }, }); // Second instance with same config - Will throw an error const mcp2 = new MCPClient({ servers: { /* ... */ }, }); // To fix, either: // 1. Add unique IDs const mcp3 = new MCPClient({ id: "instance-1", servers: { /* ... */ }, }); // 2. Or disconnect before recreating await mcp1.disconnect(); const mcp4 = new MCPClient({ servers: { /* ... */ }, }); ``` ## Server Lifecycle MCPClient handles server connections gracefully: 1. Automatic connection management for multiple servers 2. Graceful server shutdown to prevent error messages during development 3. Proper cleanup of resources when disconnecting ## Using SSE Request Headers When using the legacy SSE MCP transport, you must configure both `requestInit` and `eventSourceInit` due to a bug in the MCP SDK: ```ts const sseClient = new MCPClient({ servers: { exampleServer: { url: new URL("https://your-mcp-server.com/sse"), // Note: requestInit alone isn't enough for SSE requestInit: { headers: { Authorization: "Bearer your-token", }, }, // This is also required for SSE connections with custom headers eventSourceInit: { fetch(input: Request | URL | string, init?: RequestInit) { const headers = new Headers(init?.headers || {}); headers.set("Authorization", "Bearer your-token"); return fetch(input, { ...init, headers, }); }, }, }, }, }); ``` ## Related Information - For creating MCP servers, see the [MCPServer documentation](./mcp-server). - For more about the Model Context Protocol, see the [@modelcontextprotocol/sdk documentation](https://github.com/modelcontextprotocol/typescript-sdk). --- title: "Reference: MCPServer | Exposing Mastra Tools via MCP | Mastra Docs" description: API Reference for MCPServer - A class for exposing Mastra tools and capabilities as a Model Context Protocol server. --- # MCPServer [EN] Source: https://mastra.ai/en/reference/tools/mcp-server The `MCPServer` class provides the functionality to expose your existing Mastra tools and Agents as a Model Context Protocol (MCP) server. This allows any MCP client (like Cursor, Windsurf, or Claude Desktop) to connect to these capabilities and make them available to an agent. Note that if you only need to use your tools or agents directly within your Mastra application, you don't necessarily need to create an MCP server. This API is specifically for exposing your Mastra tools and agents to _external_ MCP clients. It supports both [stdio (subprocess) and SSE (HTTP) MCP transports](https://modelcontextprotocol.io/docs/concepts/transports). ## Constructor To create a new `MCPServer`, you need to provide some basic information about your server, the tools it will offer, and optionally, any agents you want to expose as tools. ```typescript import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { createTool } from "@mastra/core/tools"; import { MCPServer } from "@mastra/mcp"; import { z } from "zod"; import { dataProcessingWorkflow } from "../workflows/dataProcessingWorkflow"; const myAgent = new Agent({ name: "MyExampleAgent", description: "A generalist to help with basic questions." instructions: "You are a helpful assistant.", model: openai("gpt-4o-mini"), }); const weatherTool = createTool({ id: "getWeather", description: "Gets the current weather for a location.", inputSchema: z.object({ location: z.string() }), execute: async ({ context }) => `Weather in ${context.location} is sunny.`, }); const server = new MCPServer({ name: "My Custom Server", version: "1.0.0", tools: { weatherTool }, agents: { myAgent }, // this agent will become tool "ask_myAgent" workflows: { dataProcessingWorkflow, // this workflow will become tool "run_dataProcessingWorkflow" } }); ``` ### Configuration Properties The constructor accepts an `MCPServerConfig` object with the following properties: ", isOptional: true, description: "An object where keys are agent identifiers and values are Mastra Agent instances. Each agent will be automatically converted into a tool named `ask_`. The agent **must** have a non-empty `description` string property defined in its constructor configuration. This description will be used in the tool's description. If an agent's description is missing or empty, an error will be thrown during MCPServer initialization.", }, { name: "workflows", type: "Record", isOptional: true, description: "An object where keys are workflow identifiers and values are Mastra Workflow instances. Each workflow is converted into a tool named `run_`. The workflow's `inputSchema` becomes the tool's input schema. The workflow **must** have a non-empty `description` string property, which is used for the tool's description. If a workflow's description is missing or empty, an error will be thrown. The tool executes the workflow by calling `workflow.createRun().start({ inputData: })`. If a tool name derived from an agent or workflow (e.g., `ask_myAgent` or `run_myWorkflow`) collides with an explicitly defined tool name or another derived name, the explicitly defined tool takes precedence, and a warning is logged. Agents/workflows leading to subsequent collisions are skipped.", }, { name: "id", type: "string", isOptional: true, description: "Optional unique identifier for the server. If not provided, a UUID will be generated. This ID is considered final and cannot be changed by Mastra if provided.", }, { name: "description", type: "string", isOptional: true, description: "Optional description of what the MCP server does.", }, { name: "repository", type: "Repository", // { url: string; source: string; id: string; } isOptional: true, description: "Optional repository information for the server's source code.", }, { name: "releaseDate", type: "string", // ISO 8601 isOptional: true, description: "Optional release date of this server version (ISO 8601 string). Defaults to the time of instantiation if not provided.", }, { name: "isLatest", type: "boolean", isOptional: true, description: "Optional flag indicating if this is the latest version. Defaults to true if not provided.", }, { name: "packageCanonical", type: "'npm' | 'docker' | 'pypi' | 'crates' | string", isOptional: true, description: "Optional canonical packaging format if the server is distributed as a package (e.g., 'npm', 'docker').", }, { name: "packages", type: "PackageInfo[]", isOptional: true, description: "Optional list of installable packages for this server.", }, { name: "remotes", type: "RemoteInfo[]", isOptional: true, description: "Optional list of remote access points for this server.", }, { name: "resources", type: "MCPServerResources", isOptional: true, description: "An object defining how the server should handle MCP resources. See Resource Handling section for details.", }, { name: "prompts", type: "MCPServerPrompts", isOptional: true, description: "An object defining how the server should handle MCP prompts. See Prompt Handling section for details.", }, ]} /> ## Exposing Agents as Tools A powerful feature of `MCPServer` is its ability to automatically expose your Mastra Agents as callable tools. When you provide agents in the `agents` property of the configuration: - **Tool Naming**: Each agent is converted into a tool named `ask_`, where `` is the key you used for that agent in the `agents` object. For instance, if you configure `agents: { myAgentKey: myAgentInstance }`, a tool named `ask_myAgentKey` will be created. - **Tool Functionality**: - **Description**: The generated tool's description will be in the format: "Ask agent `` a question. Original agent instructions: ``". - **Input**: The tool expects a single object argument with a `message` property (string): `{ message: "Your question for the agent" }`. - **Execution**: When this tool is called, it invokes the `generate()` method of the corresponding agent, passing the provided `query`. - **Output**: The direct result from the agent's `generate()` method is returned as the output of the tool. - **Name Collisions**: If an explicit tool defined in the `tools` configuration has the same name as an agent-derived tool (e.g., you have a tool named `ask_myAgentKey` and also an agent with the key `myAgentKey`), the _explicitly defined tool will take precedence_. The agent will not be converted into a tool in this conflicting case, and a warning will be logged. This makes it straightforward to allow MCP clients to interact with your agents using natural language queries, just like any other tool. ### Agent-to-Tool Conversion When you provide agents in the `agents` configuration property, `MCPServer` will automatically create a corresponding tool for each agent. The tool will be named `ask_`, where `` is the key you used in the `agents` object. The description for this generated tool will be: "Ask agent `` a question. Agent description: ``". **Important**: For an agent to be converted into a tool, it **must** have a non-empty `description` string property set in its configuration when it was instantiated (e.g., `new Agent({ name: 'myAgent', description: 'This agent does X.', ... })`). If an agent is passed to `MCPServer` with a missing or empty `description`, an error will be thrown when the `MCPServer` is instantiated, and server setup will fail. This allows you to quickly expose the generative capabilities of your agents through the MCP, enabling clients to "ask" your agents questions directly. ## Methods These are the functions you can call on an `MCPServer` instance to control its behavior and get information. ### startStdio() Use this method to start the server so it communicates using standard input and output (stdio). This is typical when running the server as a command-line program. ```typescript async startStdio(): Promise ``` Here's how you would start the server using stdio: ```typescript const server = new MCPServer({ // example configuration above }); await server.startStdio(); ``` ### startSSE() This method helps you integrate the MCP server with an existing web server to use Server-Sent Events (SSE) for communication. You'll call this from your web server's code when it receives a request for the SSE or message paths. ```typescript async startSSE({ url, ssePath, messagePath, req, res, }: { url: URL; ssePath: string; messagePath: string; req: any; res: any; }): Promise ``` Here's an example of how you might use `startSSE` within an HTTP server request handler. In this example an MCP client could connect to your MCP server at `http://localhost:1234/sse`: ```typescript import http from "http"; const httpServer = http.createServer(async (req, res) => { await server.startSSE({ url: new URL(req.url || "", `http://localhost:1234`), ssePath: "/sse", messagePath: "/message", req, res, }); }); httpServer.listen(PORT, () => { console.log(`HTTP server listening on port ${PORT}`); }); ``` Here are the details for the values needed by the `startSSE` method: ### startHonoSSE() This method helps you integrate the MCP server with an existing web server to use Server-Sent Events (SSE) for communication. You'll call this from your web server's code when it receives a request for the SSE or message paths. ```typescript async startHonoSSE({ url, ssePath, messagePath, req, res, }: { url: URL; ssePath: string; messagePath: string; req: any; res: any; }): Promise ``` Here's an example of how you might use `startHonoSSE` within an HTTP server request handler. In this example an MCP client could connect to your MCP server at `http://localhost:1234/hono-sse`: ```typescript import http from "http"; const httpServer = http.createServer(async (req, res) => { await server.startHonoSSE({ url: new URL(req.url || "", `http://localhost:1234`), ssePath: "/hono-sse", messagePath: "/message", req, res, }); }); httpServer.listen(PORT, () => { console.log(`HTTP server listening on port ${PORT}`); }); ``` Here are the details for the values needed by the `startHonoSSE` method: ### startHTTP() This method helps you integrate the MCP server with an existing web server to use streamable HTTP for communication. You'll call this from your web server's code when it receives HTTP requests. ```typescript async startHTTP({ url, httpPath, req, res, options = { sessionIdGenerator: () => randomUUID() }, }: { url: URL; httpPath: string; req: http.IncomingMessage; res: http.ServerResponse; options?: StreamableHTTPServerTransportOptions; }): Promise ``` Here's an example of how you might use `startHTTP` within an HTTP server request handler. In this example an MCP client could connect to your MCP server at `http://localhost:1234/http`: ```typescript import http from "http"; const httpServer = http.createServer(async (req, res) => { await server.startHTTP({ url: new URL(req.url || '', 'http://localhost:1234'), httpPath: `/mcp`, req, res, options: { sessionIdGenerator: undefined, }, }); }); httpServer.listen(PORT, () => { console.log(`HTTP server listening on port ${PORT}`); }); ``` Here are the details for the values needed by the `startHTTP` method: The `StreamableHTTPServerTransportOptions` object allows you to customize the behavior of the HTTP transport. Here are the available options: string) | undefined', description: 'A function that generates a unique session ID. This should be a cryptographically secure, globally unique string. Return `undefined` to disable session management.', }, { name: 'onsessioninitialized', type: '(sessionId: string) => void', description: 'A callback that is invoked when a new session is initialized. This is useful for tracking active MCP sessions.', optional: true, }, { name: 'enableJsonResponse', type: 'boolean', description: 'If `true`, the server will return plain JSON responses instead of using Server-Sent Events (SSE) for streaming. Defaults to `false`.', optional: true, }, { name: 'eventStore', type: 'EventStore', description: 'An event store for message resumability. Providing this enables clients to reconnect and resume message streams.', optional: true, }, ]} /> ### close() This method closes the server and releases all resources. ```typescript async close(): Promise ``` ### getServerInfo() This method gives you a look at the server's basic information. ```typescript getServerInfo(): ServerInfo ``` ### getServerDetail() This method gives you a detailed look at the server's information. ```typescript getServerDetail(): ServerDetail ``` ### getToolListInfo() This method gives you a look at the tools that were set up when you created the server. It's a read-only list, useful for debugging purposes. ```typescript getToolListInfo(): ToolListInfo ``` ### getToolInfo() This method gives you detailed information about a specific tool. ```typescript getToolInfo(toolName: string): ToolInfo ``` ### executeTool() This method executes a specific tool and returns the result. ```typescript executeTool(toolName: string, input: any): Promise ``` ### getStdioTransport() If you started the server with `startStdio()`, you can use this to get the object that manages the stdio communication. This is mostly for checking things internally or for testing. ```typescript getStdioTransport(): StdioServerTransport | undefined ``` ### getSseTransport() If you started the server with `startSSE()`, you can use this to get the object that manages the SSE communication. Like `getStdioTransport`, this is mainly for internal checks or testing. ```typescript getSseTransport(): SSEServerTransport | undefined ``` ### getSseHonoTransport() If you started the server with `startHonoSSE()`, you can use this to get the object that manages the SSE communication. Like `getSseTransport`, this is mainly for internal checks or testing. ```typescript getSseHonoTransport(): SSETransport | undefined ``` ### getStreamableHTTPTransport() If you started the server with `startHTTP()`, you can use this to get the object that manages the HTTP communication. Like `getSseTransport`, this is mainly for internal checks or testing. ```typescript getStreamableHTTPTransport(): StreamableHTTPServerTransport | undefined ``` ### tools() Executes a specific tool provided by this MCP server. ```typescript async executeTool( toolId: string, args: any, executionContext?: { messages?: any[]; toolCallId?: string }, ): Promise ``` ## Resource Handling ### What are MCP Resources? Resources are a core primitive in the Model Context Protocol (MCP) that allow servers to expose data and content that can be read by clients and used as context for LLM interactions. They represent any kind of data that an MCP server wants to make available, such as: - File contents - Database records - API responses - Live system data - Screenshots and images - Log files Resources are identified by unique URIs (e.g., `file:///home/user/documents/report.pdf`, `postgres://database/customers/schema`) and can contain either text (UTF-8 encoded) or binary data (base64 encoded). Clients can discover resources through: 1. **Direct resources**: Servers expose a list of concrete resources via a `resources/list` endpoint. 2. **Resource templates**: For dynamic resources, servers can expose URI templates (RFC 6570) that clients use to construct resource URIs. To read a resource, clients make a `resources/read` request with the URI. Servers can also notify clients about changes to the resource list (`notifications/resources/list_changed`) or updates to specific resource content (`notifications/resources/updated`) if a client has subscribed to that resource. For more detailed information, refer to the [official MCP documentation on Resources](https://modelcontextprotocol.io/docs/concepts/resources). ### `MCPServerResources` Type The `resources` option takes an object of type `MCPServerResources`. This type defines the callbacks your server will use to handle resource requests: ```typescript export type MCPServerResources = { // Callback to list available resources listResources: () => Promise; // Callback to get the content of a specific resource getResourceContent: ({ uri, }: { uri: string; }) => Promise; // Optional callback to list available resource templates resourceTemplates?: () => Promise; }; export type MCPServerResourceContent = { text?: string } | { blob?: string }; ``` Example: ```typescript import { MCPServer } from "@mastra/mcp"; import type { MCPServerResourceContent, Resource, ResourceTemplate, } from "@mastra/mcp"; // Resources/resource templates will generally be dynamically fetched. const myResources: Resource[] = [ { uri: "file://data/123.txt", name: "Data File", mimeType: "text/plain" }, ]; const myResourceContents: Record = { "file://data.txt/123": { text: "This is the content of the data file." }, }; const myResourceTemplates: ResourceTemplate[] = [ { uriTemplate: "file://data/{id}", name: "Data File", description: "A file containing data.", mimeType: "text/plain", }, ]; const myResourceHandlers: MCPServerResources = { listResources: async () => myResources, getResourceContent: async ({ uri }) => { if (myResourceContents[uri]) { return myResourceContents[uri]; } throw new Error(`Resource content not found for ${uri}`); }, resourceTemplates: async () => myResourceTemplates, }; const serverWithResources = new MCPServer({ name: "Resourceful Server", version: "1.0.0", tools: { /* ... your tools ... */ }, resources: myResourceHandlers, }); ``` ### Notifying Clients of Resource Changes If the available resources or their content change, your server can notify connected clients that are subscribed to the specific resource. #### `server.resources.notifyUpdated({ uri: string })` Call this method when the content of a specific resource (identified by its `uri`) has been updated. If any clients are subscribed to this URI, they will receive a `notifications/resources/updated` message. ```typescript async server.resources.notifyUpdated({ uri: string }): Promise ``` Example: ```typescript // After updating the content of 'file://data.txt' await serverWithResources.resources.notifyUpdated({ uri: "file://data.txt" }); ``` #### `server.resources.notifyListChanged()` Call this method when the overall list of available resources has changed (e.g., a resource was added or removed). This will send a `notifications/resources/list_changed` message to clients, prompting them to re-fetch the list of resources. ```typescript async server.resources.notifyListChanged(): Promise ``` Example: ```typescript // After adding a new resource to the list managed by 'myResourceHandlers.listResources' await serverWithResources.resources.notifyListChanged(); ``` ## Prompt Handling ### What are MCP Prompts? Prompts are reusable templates or workflows that MCP servers expose to clients. They can accept arguments, include resource context, support versioning, and be used to standardize LLM interactions. Prompts are identified by a unique name (and optional version) and can be dynamic or static. ### `MCPServerPrompts` Type The `prompts` option takes an object of type `MCPServerPrompts`. This type defines the callbacks your server will use to handle prompt requests: ```typescript export type MCPServerPrompts = { // Callback to list available prompts listPrompts: () => Promise; // Callback to get the messages/content for a specific prompt getPromptMessages?: ({ name, version, args, }: { name: string; version?: string; args?: any; }) => Promise<{ prompt: Prompt; messages: PromptMessage[] }>; }; ``` Example: ```typescript import { MCPServer } from "@mastra/mcp"; import type { Prompt, PromptMessage, MCPServerPrompts } from "@mastra/mcp"; const prompts: Prompt[] = [ { name: "analyze-code", description: "Analyze code for improvements", version: "v1" }, { name: "analyze-code", description: "Analyze code for improvements (new logic)", version: "v2" } ]; const myPromptHandlers: MCPServerPrompts = { listPrompts: async () => prompts, getPromptMessages: async ({ name, version, args }) => { if (name === "analyze-code") { if (version === "v2") { const prompt = prompts.find(p => p.name === name && p.version === "v2"); if (!prompt) throw new Error("Prompt version not found"); return { prompt, messages: [ { role: "user", content: { type: "text", text: `Analyze this code with the new logic: ${args.code}` } } ] }; } // Default or v1 const prompt = prompts.find(p => p.name === name && p.version === "v1"); if (!prompt) throw new Error("Prompt version not found"); return { prompt, messages: [ { role: "user", content: { type: "text", text: `Analyze this code: ${args.code}` } } ] }; } throw new Error("Prompt not found"); } }; const serverWithPrompts = new MCPServer({ name: "Promptful Server", version: "1.0.0", tools: { /* ... */ }, prompts: myPromptHandlers, }); ``` ### Notifying Clients of Prompt Changes If the available prompts change, your server can notify connected clients: #### `server.prompts.notifyListChanged()` Call this method when the overall list of available prompts has changed (e.g., a prompt was added or removed). This will send a `notifications/prompts/list_changed` message to clients, prompting them to re-fetch the list of prompts. ```typescript await serverWithPrompts.prompts.notifyListChanged(); ``` ### Best Practices for Prompt Handling - Use clear, descriptive prompt names and descriptions. - Validate all required arguments in `getPromptMessages`. - Include a `version` field if you expect to make breaking changes. - Use the `version` parameter to select the correct prompt logic. - Notify clients when prompt lists change. - Handle errors with informative messages. - Document argument expectations and available versions. --- ## Examples For practical examples of setting up and deploying an MCPServer, see the [Deploying an MCPServer Example](/examples/agents/deploying-mcp-server). The example at the beginning of this page also demonstrates how to instantiate `MCPServer` with both tools and agents. ## Related Information - For connecting to MCP servers in Mastra, see the [MCPClient documentation](./mcp-client). - For more about the Model Context Protocol, see the [@modelcontextprotocol/sdk documentation](https://github.com/modelcontextprotocol/typescript-sdk). --- title: "Reference: createVectorQueryTool() | RAG | Mastra Tools Docs" description: Documentation for the Vector Query Tool in Mastra, which facilitates semantic search over vector stores with filtering and reranking capabilities. --- import { Callout } from "nextra/components"; import { Tabs } from "nextra/components"; # createVectorQueryTool() [EN] Source: https://mastra.ai/en/reference/tools/vector-query-tool The `createVectorQueryTool()` function creates a tool for semantic search over vector stores. It supports filtering, reranking, database-specific configurations, and integrates with various vector store backends. ## Basic Usage ```typescript import { openai } from "@ai-sdk/openai"; import { createVectorQueryTool } from "@mastra/rag"; const queryTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), }); ``` ## Parameters **Parameter Requirements:** Most fields can be set at creation as defaults. Some fields can be overridden at runtime via the runtime context or input. If a required field is missing from both creation and runtime, an error will be thrown. Note that `model`, `id`, and `description` can only be set at creation time. ### DatabaseConfig The `DatabaseConfig` type allows you to specify database-specific configurations that are automatically applied to query operations. This enables you to take advantage of unique features and optimizations offered by different vector stores. ", }, { name: "whereDocument", description: "Document content filtering conditions", isOptional: true, type: "Record", }, ], }, ], }, ]} /> ### RerankConfig ## Returns The tool returns an object with: ### QueryResult object structure ```typescript { id: string; // Unique chunk/document identifier metadata: any; // All metadata fields (document ID, etc.) vector: number[]; // Embedding vector (if available) score: number; // Similarity score for this retrieval document: string; // Full chunk/document text (if available) } ``` ## Default Tool Description The default description focuses on: - Finding relevant information in stored knowledge - Answering user questions - Retrieving factual content ## Result Handling The tool determines the number of results to return based on the user's query, with a default of 10 results. This can be adjusted based on the query requirements. ## Example with Filters ```typescript const queryTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), enableFilter: true, }); ``` With filtering enabled, the tool processes queries to construct metadata filters that combine with semantic search. The process works as follows: 1. A user makes a query with specific filter requirements like "Find content where the 'version' field is greater than 2.0" 2. The agent analyzes the query and constructs the appropriate filters: ```typescript { "version": { "$gt": 2.0 } } ``` This agent-driven approach: - Processes natural language queries into filter specifications - Implements vector store-specific filter syntax - Translates query terms to filter operators For detailed filter syntax and store-specific capabilities, see the [Metadata Filters](../rag/metadata-filters) documentation. For an example of how agent-driven filtering works, see the [Agent-Driven Metadata Filtering](../../../examples/rag/usage/filter-rag) example. ## Example with Reranking ```typescript const queryTool = createVectorQueryTool({ vectorStoreName: "milvus", indexName: "documentation", model: openai.embedding("text-embedding-3-small"), reranker: { model: openai("gpt-4o-mini"), options: { weights: { semantic: 0.5, // Semantic relevance weight vector: 0.3, // Vector similarity weight position: 0.2, // Original position weight }, topK: 5, }, }, }); ``` Reranking improves result quality by combining: - Semantic relevance: Using LLM-based scoring of text similarity - Vector similarity: Original vector distance scores - Position bias: Consideration of original result ordering - Query analysis: Adjustments based on query characteristics The reranker processes the initial vector search results and returns a reordered list optimized for relevance. ## Example with Custom Description ```typescript const queryTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), description: "Search through document archives to find relevant information for answering questions about company policies and procedures", }); ``` This example shows how to customize the tool description for a specific use case while maintaining its core purpose of information retrieval. ## Database-Specific Configuration Examples The `databaseConfig` parameter allows you to leverage unique features and optimizations specific to each vector database. These configurations are automatically applied during query execution. ### Pinecone Configuration ```typescript const pineconeQueryTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pinecone: { namespace: "production", // Organize vectors by environment sparseVector: { // Enable hybrid search indices: [0, 1, 2, 3], values: [0.1, 0.2, 0.15, 0.05] } } } }); ``` **Pinecone Features:** - **Namespace**: Isolate different data sets within the same index - **Sparse Vector**: Combine dense and sparse embeddings for improved search quality - **Use Cases**: Multi-tenant applications, hybrid semantic search ### pgVector Configuration ```typescript const pgVectorQueryTool = createVectorQueryTool({ vectorStoreName: "postgres", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pgvector: { minScore: 0.7, // Only return results above 70% similarity ef: 200, // Higher value = better accuracy, slower search probes: 10 // For IVFFlat: more probes = better recall } } }); ``` **pgVector Features:** - **minScore**: Filter out low-quality matches - **ef (HNSW)**: Control accuracy vs speed for HNSW indexes - **probes (IVFFlat)**: Control recall vs speed for IVFFlat indexes - **Use Cases**: Performance tuning, quality filtering ### Chroma Configuration ```typescript const chromaQueryTool = createVectorQueryTool({ vectorStoreName: "chroma", indexName: "documents", model: openai.embedding("text-embedding-3-small"), databaseConfig: { chroma: { where: { // Metadata filtering "category": "technical", "status": "published" }, whereDocument: { // Document content filtering "$contains": "API" } } } }); ``` **Chroma Features:** - **where**: Filter by metadata fields - **whereDocument**: Filter by document content - **Use Cases**: Advanced filtering, content-based search ### Multiple Database Configurations ```typescript // Configure for multiple databases (useful for dynamic stores) const multiDbQueryTool = createVectorQueryTool({ vectorStoreName: "dynamic-store", // Will be set at runtime indexName: "docs", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pinecone: { namespace: "default" }, pgvector: { minScore: 0.8, ef: 150 }, chroma: { where: { "type": "documentation" } } } }); ``` **Multi-Config Benefits:** - Support multiple vector stores with one tool - Database-specific optimizations are automatically applied - Flexible deployment scenarios ### Runtime Configuration Override You can override database configurations at runtime to adapt to different scenarios: ```typescript import { RuntimeContext } from '@mastra/core/runtime-context'; const queryTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pinecone: { namespace: "development" } } }); // Override at runtime const runtimeContext = new RuntimeContext(); runtimeContext.set('databaseConfig', { pinecone: { namespace: 'production' // Switch to production namespace } }); const response = await agent.generate( "Find information about deployment", { runtimeContext } ); ``` This approach allows you to: - Switch between environments (dev/staging/prod) - Adjust performance parameters based on load - Apply different filtering strategies per request ## Example: Using Runtime Context ```typescript const queryTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), }); ``` When using runtime context, provide required parameters at execution time via the runtime context: ```typescript const runtimeContext = new RuntimeContext<{ vectorStoreName: string; indexName: string; topK: number; filter: VectorFilter; databaseConfig: DatabaseConfig; }>(); runtimeContext.set("vectorStoreName", "my-store"); runtimeContext.set("indexName", "my-index"); runtimeContext.set("topK", 5); runtimeContext.set("filter", { category: "docs" }); runtimeContext.set("databaseConfig", { pinecone: { namespace: "runtime-namespace" } }); const response = await agent.generate( "Find documentation from the knowledge base.", { runtimeContext, }, ); ``` For more information on runtime context, please see: - [Runtime Variables](../../docs/agents/runtime-variables) - [Dynamic Context](../../docs/tools-mcp/dynamic-context) ## Tool Details The tool is created with: - **ID**: `VectorQuery {vectorStoreName} {indexName} Tool` - **Input Schema**: Requires queryText and filter objects - **Output Schema**: Returns relevantContext string ## Related - [rerank()](../rag/rerank) - [createGraphRAGTool](./graph-rag-tool) --- title: "Reference: Azure Voice | Voice Providers | Mastra Docs" description: "Documentation for the AzureVoice class, providing text-to-speech and speech-to-text capabilities using Azure Cognitive Services." --- # Azure [EN] Source: https://mastra.ai/en/reference/voice/azure The AzureVoice class in Mastra provides text-to-speech and speech-to-text capabilities using Microsoft Azure Cognitive Services. ## Usage Example ```typescript import { AzureVoice } from "@mastra/voice-azure"; // Initialize with configuration const voice = new AzureVoice({ speechModel: { name: "neural", apiKey: "your-azure-speech-api-key", region: "eastus", }, listeningModel: { name: "whisper", apiKey: "your-azure-speech-api-key", region: "eastus", }, speaker: "en-US-JennyNeural", // Default voice }); // Convert text to speech const audioStream = await voice.speak("Hello, how can I help you?", { speaker: "en-US-GuyNeural", // Override default voice style: "cheerful", // Voice style }); // Convert speech to text const text = await voice.listen(audioStream, { filetype: "wav", language: "en-US", }); ``` ## Configuration ### Constructor Options ### AzureSpeechConfig ## Methods ### speak() Converts text to speech using Azure's neural text-to-speech service. Returns: `Promise` ### listen() Transcribes audio using Azure's speech-to-text service. Returns: `Promise` ### getSpeakers() Returns an array of available voice options, where each node contains: ## Notes - API keys can be provided via constructor options or environment variables (AZURE_SPEECH_KEY and AZURE_SPEECH_REGION) - Azure offers a wide range of neural voices across many languages - Some voices support speaking styles like cheerful, sad, angry, etc. - Speech recognition supports multiple audio formats and languages - Azure's speech services provide high-quality neural voices with natural-sounding speech --- title: "Reference: Cloudflare Voice | Voice Providers | Mastra Docs" description: "Documentation for the CloudflareVoice class, providing text-to-speech capabilities using Cloudflare Workers AI." --- # Cloudflare [EN] Source: https://mastra.ai/en/reference/voice/cloudflare The CloudflareVoice class in Mastra provides text-to-speech capabilities using Cloudflare Workers AI. This provider specializes in efficient, low-latency speech synthesis suitable for edge computing environments. ## Usage Example ```typescript import { CloudflareVoice } from "@mastra/voice-cloudflare"; // Initialize with configuration const voice = new CloudflareVoice({ speechModel: { name: "@cf/meta/m2m100-1.2b", apiKey: "your-cloudflare-api-token", accountId: "your-cloudflare-account-id", }, speaker: "en-US-1", // Default voice }); // Convert text to speech const audioStream = await voice.speak("Hello, how can I help you?", { speaker: "en-US-2", // Override default voice }); // Get available voices const speakers = await voice.getSpeakers(); console.log(speakers); ``` ## Configuration ### Constructor Options ### CloudflareSpeechConfig ## Methods ### speak() Converts text to speech using Cloudflare's text-to-speech service. Returns: `Promise` ### getSpeakers() Returns an array of available voice options, where each node contains: ## Notes - API tokens can be provided via constructor options or environment variables (CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID) - Cloudflare Workers AI is optimized for edge computing with low latency - This provider only supports text-to-speech (TTS) functionality, not speech-to-text (STT) - The service integrates well with other Cloudflare Workers products - For production use, ensure your Cloudflare account has the appropriate Workers AI subscription - Voice options are more limited compared to some other providers, but performance at the edge is excellent ## Related Providers If you need speech-to-text capabilities in addition to text-to-speech, consider using one of these providers: - [OpenAI](./openai) - Provides both TTS and STT - [Google](./google) - Provides both TTS and STT - [Azure](./azure) - Provides both TTS and STT --- title: "Reference: CompositeVoice | Voice Providers | Mastra Docs" description: "Documentation for the CompositeVoice class, which enables combining multiple voice providers for flexible text-to-speech and speech-to-text operations." --- # CompositeVoice [EN] Source: https://mastra.ai/en/reference/voice/composite-voice The CompositeVoice class allows you to combine different voice providers for text-to-speech and speech-to-text operations. This is particularly useful when you want to use the best provider for each operation - for example, using OpenAI for speech-to-text and PlayAI for text-to-speech. CompositeVoice is used internally by the Agent class to provide flexible voice capabilities. ## Usage Example ```typescript import { CompositeVoice } from "@mastra/core/voice"; import { OpenAIVoice } from "@mastra/voice-openai"; import { PlayAIVoice } from "@mastra/voice-playai"; // Create voice providers const openai = new OpenAIVoice(); const playai = new PlayAIVoice(); // Use OpenAI for listening (speech-to-text) and PlayAI for speaking (text-to-speech) const voice = new CompositeVoice({ input: openai, output: playai, }); // Convert speech to text using OpenAI const text = await voice.listen(audioStream); // Convert text to speech using PlayAI const audio = await voice.speak("Hello, world!"); ``` ## Constructor Parameters ## Methods ### speak() Converts text to speech using the configured speaking provider. Notes: - If no speaking provider is configured, this method will throw an error - Options are passed through to the configured speaking provider - Returns a stream of audio data ### listen() Converts speech to text using the configured listening provider. Notes: - If no listening provider is configured, this method will throw an error - Options are passed through to the configured listening provider - Returns either a string or a stream of transcribed text, depending on the provider ### getSpeakers() Returns a list of available voices from the speaking provider, where each node contains: Notes: - Returns voices from the speaking provider only - If no speaking provider is configured, returns an empty array - Each voice object will have at least a voiceId property - Additional voice properties depend on the speaking provider --- title: "Reference: Deepgram Voice | Voice Providers | Mastra Docs" description: "Documentation for the Deepgram voice implementation, providing text-to-speech and speech-to-text capabilities with multiple voice models and languages." --- # Deepgram [EN] Source: https://mastra.ai/en/reference/voice/deepgram The Deepgram voice implementation in Mastra provides text-to-speech (TTS) and speech-to-text (STT) capabilities using Deepgram's API. It supports multiple voice models and languages, with configurable options for both speech synthesis and transcription. ## Usage Example ```typescript import { DeepgramVoice } from "@mastra/voice-deepgram"; // Initialize with default configuration (uses DEEPGRAM_API_KEY environment variable) const voice = new DeepgramVoice(); // Initialize with custom configuration const voice = new DeepgramVoice({ speechModel: { name: "aura", apiKey: "your-api-key", }, listeningModel: { name: "nova-2", apiKey: "your-api-key", }, speaker: "asteria-en", }); // Text-to-Speech const audioStream = await voice.speak("Hello, world!"); // Speech-to-Text const transcript = await voice.listen(audioStream); ``` ## Constructor Parameters ### DeepgramVoiceConfig ", description: "Additional properties to pass to the Deepgram API", isOptional: true, }, { name: "language", type: "string", description: "Language code for the model", isOptional: true, }, ]} /> ## Methods ### speak() Converts text to speech using the configured speech model and voice. Returns: `Promise` ### listen() Converts speech to text using the configured listening model. Returns: `Promise` ### getSpeakers() Returns a list of available voice options. --- title: "Reference: ElevenLabs Voice | Voice Providers | Mastra Docs" description: "Documentation for the ElevenLabs voice implementation, offering high-quality text-to-speech capabilities with multiple voice models and natural-sounding synthesis." --- # ElevenLabs [EN] Source: https://mastra.ai/en/reference/voice/elevenlabs The ElevenLabs voice implementation in Mastra provides high-quality text-to-speech (TTS) and speech-to-text (STT) capabilities using the ElevenLabs API. ## Usage Example ```typescript import { ElevenLabsVoice } from "@mastra/voice-elevenlabs"; // Initialize with default configuration (uses ELEVENLABS_API_KEY environment variable) const voice = new ElevenLabsVoice(); // Initialize with custom configuration const voice = new ElevenLabsVoice({ speechModel: { name: "eleven_multilingual_v2", apiKey: "your-api-key", }, speaker: "custom-speaker-id", }); // Text-to-Speech const audioStream = await voice.speak("Hello, world!"); // Get available speakers const speakers = await voice.getSpeakers(); ``` ## Constructor Parameters ### ElevenLabsVoiceConfig ## Methods ### speak() Converts text to speech using the configured speech model and voice. Returns: `Promise` ### getSpeakers() Returns an array of available voice options, where each node contains: ### listen() Converts audio input to text using ElevenLabs Speech-to-Text API. The options object supports the following properties: Returns: `Promise` - A Promise that resolves to the transcribed text ## Important Notes 1. An ElevenLabs API key is required. Set it via the `ELEVENLABS_API_KEY` environment variable or pass it in the constructor. 2. The default speaker is set to Aria (ID: '9BWtsMINqrJLrRacOk9x'). 3. Speech-to-text functionality is not supported by ElevenLabs. 4. Available speakers can be retrieved using the `getSpeakers()` method, which returns detailed information about each voice including language and gender. --- title: "Reference: Google Voice | Voice Providers | Mastra Docs" description: "Documentation for the Google Voice implementation, providing text-to-speech and speech-to-text capabilities." --- # Google [EN] Source: https://mastra.ai/en/reference/voice/google The Google Voice implementation in Mastra provides both text-to-speech (TTS) and speech-to-text (STT) capabilities using Google Cloud services. It supports multiple voices, languages, and advanced audio configuration options. ## Usage Example ```typescript import { GoogleVoice } from "@mastra/voice-google"; // Initialize with default configuration (uses GOOGLE_API_KEY environment variable) const voice = new GoogleVoice(); // Initialize with custom configuration const voice = new GoogleVoice({ speechModel: { apiKey: "your-speech-api-key", }, listeningModel: { apiKey: "your-listening-api-key", }, speaker: "en-US-Casual-K", }); // Text-to-Speech const audioStream = await voice.speak("Hello, world!", { languageCode: "en-US", audioConfig: { audioEncoding: "LINEAR16", }, }); // Speech-to-Text const transcript = await voice.listen(audioStream, { config: { encoding: "LINEAR16", languageCode: "en-US", }, }); // Get available voices for a specific language const voices = await voice.getSpeakers({ languageCode: "en-US" }); ``` ## Constructor Parameters ### GoogleModelConfig ## Methods ### speak() Converts text to speech using Google Cloud Text-to-Speech service. Returns: `Promise` ### listen() Converts speech to text using Google Cloud Speech-to-Text service. Returns: `Promise` ### getSpeakers() Returns an array of available voice options, where each node contains: ## Important Notes 1. A Google Cloud API key is required. Set it via the `GOOGLE_API_KEY` environment variable or pass it in the constructor. 2. The default voice is set to 'en-US-Casual-K'. 3. Both text-to-speech and speech-to-text services use LINEAR16 as the default audio encoding. 4. The `speak()` method supports advanced audio configuration through the Google Cloud Text-to-Speech API. 5. The `listen()` method supports various recognition configurations through the Google Cloud Speech-to-Text API. 6. Available voices can be filtered by language code using the `getSpeakers()` method. --- title: "Reference: MastraVoice | Voice Providers | Mastra Docs" description: "Documentation for the MastraVoice abstract base class, which defines the core interface for all voice services in Mastra, including speech-to-speech capabilities." --- # MastraVoice [EN] Source: https://mastra.ai/en/reference/voice/mastra-voice The MastraVoice class is an abstract base class that defines the core interface for voice services in Mastra. All voice provider implementations (like OpenAI, Deepgram, PlayAI, Speechify) extend this class to provide their specific functionality. The class now includes support for real-time speech-to-speech capabilities through WebSocket connections. ## Usage Example ```typescript import { MastraVoice } from "@mastra/core/voice"; // Create a voice provider implementation class MyVoiceProvider extends MastraVoice { constructor(config: { speechModel?: BuiltInModelConfig; listeningModel?: BuiltInModelConfig; speaker?: string; realtimeConfig?: { model?: string; apiKey?: string; options?: unknown; }; }) { super({ speechModel: config.speechModel, listeningModel: config.listeningModel, speaker: config.speaker, realtimeConfig: config.realtimeConfig, }); } // Implement required abstract methods async speak( input: string | NodeJS.ReadableStream, options?: { speaker?: string }, ): Promise { // Implement text-to-speech conversion } async listen( audioStream: NodeJS.ReadableStream, options?: unknown, ): Promise { // Implement speech-to-text conversion } async getSpeakers(): Promise< Array<{ voiceId: string; [key: string]: unknown }> > { // Return list of available voices } // Optional speech-to-speech methods async connect(): Promise { // Establish WebSocket connection for speech-to-speech communication } async send(audioData: NodeJS.ReadableStream | Int16Array): Promise { // Stream audio data in speech-to-speech } async answer(): Promise { // Trigger voice provider to respond } addTools(tools: Array): void { // Add tools for the voice provider to use } close(): void { // Close WebSocket connection } on(event: string, callback: (data: unknown) => void): void { // Register event listener } off(event: string, callback: (data: unknown) => void): void { // Remove event listener } } ``` ## Constructor Parameters ### BuiltInModelConfig ### RealtimeConfig ## Abstract Methods These methods must be implemented by unknown class extending MastraVoice. ### speak() Converts text to speech using the configured speech model. ```typescript abstract speak( input: string | NodeJS.ReadableStream, options?: { speaker?: string; [key: string]: unknown; } ): Promise ``` Purpose: - Takes text input and converts it to speech using the provider's text-to-speech service - Supports both string and stream input for flexibility - Allows overriding the default speaker/voice through options - Returns a stream of audio data that can be played or saved - May return void if the audio is handled by emitting 'speaking' event ### listen() Converts speech to text using the configured listening model. ```typescript abstract listen( audioStream: NodeJS.ReadableStream, options?: { [key: string]: unknown; } ): Promise ``` Purpose: - Takes an audio stream and converts it to text using the provider's speech-to-text service - Supports provider-specific options for transcription configuration - Can return either a complete text transcription or a stream of transcribed text - Not all providers support this functionality (e.g., PlayAI, Speechify) - May return void if the transcription is handled by emitting 'writing' event ### getSpeakers() Returns a list of available voices supported by the provider. ```typescript abstract getSpeakers(): Promise> ``` Purpose: - Retrieves the list of available voices/speakers from the provider - Each voice must have at least a voiceId property - Providers can include additional metadata about each voice - Used to discover available voices for text-to-speech conversion ## Optional Methods These methods have default implementations but can be overridden by voice providers that support speech-to-speech capabilities. ### connect() Establishes a WebSocket or WebRTC connection for communication. ```typescript connect(config?: unknown): Promise ``` Purpose: - Initializes a connection to the voice service for communication - Must be called before using features like send() or answer() - Returns a Promise that resolves when the connection is established - Configuration is provider-specific ### send() Streams audio data in real-time to the voice provider. ```typescript send(audioData: NodeJS.ReadableStream | Int16Array): Promise ``` Purpose: - Sends audio data to the voice provider for real-time processing - Useful for continuous audio streaming scenarios like live microphone input - Supports both ReadableStream and Int16Array audio formats - Must be in connected state before calling this method ### answer() Triggers the voice provider to generate a response. ```typescript answer(): Promise ``` Purpose: - Sends a signal to the voice provider to generate a response - Used in real-time conversations to prompt the AI to respond - Response will be emitted through the event system (e.g., 'speaking' event) ### addTools() Equips the voice provider with tools that can be used during conversations. ```typescript addTools(tools: Array): void ``` Purpose: - Adds tools that the voice provider can use during conversations - Tools can extend the capabilities of the voice provider - Implementation is provider-specific ### close() Disconnects from the WebSocket or WebRTC connection. ```typescript close(): void ``` Purpose: - Closes the connection to the voice service - Cleans up resources and stops any ongoing real-time processing - Should be called when you're done with the voice instance ### on() Registers an event listener for voice events. ```typescript on( event: E, callback: (data: E extends keyof VoiceEventMap ? VoiceEventMap[E] : unknown) => void, ): void ``` Purpose: - Registers a callback function to be called when the specified event occurs - Standard events include 'speaking', 'writing', and 'error' - Providers can emit custom events as well - Event data structure depends on the event type ### off() Removes an event listener. ```typescript off( event: E, callback: (data: E extends keyof VoiceEventMap ? VoiceEventMap[E] : unknown) => void, ): void ``` Purpose: - Removes a previously registered event listener - Used to clean up event handlers when they're no longer needed ## Event System The MastraVoice class includes an event system for real-time communication. Standard event types include: ## Protected Properties ## Telemetry Support MastraVoice includes built-in telemetry support through the `traced` method, which wraps method calls with performance tracking and error monitoring. ## Notes - MastraVoice is an abstract class and cannot be instantiated directly - Implementations must provide concrete implementations for all abstract methods - The class provides a consistent interface across different voice service providers - Speech-to-speech capabilities are optional and provider-specific - The event system enables asynchronous communication for real-time interactions - Telemetry is automatically handled for all method calls --- title: "Reference: Murf Voice | Voice Providers | Mastra Docs" description: "Documentation for the Murf voice implementation, providing text-to-speech capabilities." --- # Murf [EN] Source: https://mastra.ai/en/reference/voice/murf The Murf voice implementation in Mastra provides text-to-speech (TTS) capabilities using Murf's AI voice service. It supports multiple voices across different languages. ## Usage Example ```typescript import { MurfVoice } from "@mastra/voice-murf"; // Initialize with default configuration (uses MURF_API_KEY environment variable) const voice = new MurfVoice(); // Initialize with custom configuration const voice = new MurfVoice({ speechModel: { name: "GEN2", apiKey: "your-api-key", properties: { format: "MP3", rate: 1.0, pitch: 1.0, sampleRate: 48000, channelType: "STEREO", }, }, speaker: "en-US-cooper", }); // Text-to-Speech with default settings const audioStream = await voice.speak("Hello, world!"); // Text-to-Speech with custom properties const audioStream = await voice.speak("Hello, world!", { speaker: "en-UK-hazel", properties: { format: "WAV", rate: 1.2, style: "casual", }, }); // Get available voices const voices = await voice.getSpeakers(); ``` ## Constructor Parameters ### MurfConfig ### Speech Properties ", description: "Custom pronunciation mappings", isOptional: true, }, { name: "encodeAsBase64", type: "boolean", description: "Whether to encode the audio as base64", isOptional: true, }, { name: "variation", type: "number", description: "Voice variation parameter", isOptional: true, }, { name: "audioDuration", type: "number", description: "Target audio duration in seconds", isOptional: true, }, { name: "multiNativeLocale", type: "string", description: "Locale for multilingual support", isOptional: true, }, ]} /> ## Methods ### speak() Converts text to speech using Murf's API. Returns: `Promise` ### getSpeakers() Returns an array of available voice options, where each node contains: ### listen() This method is not supported by Murf and will throw an error. Murf does not provide speech-to-text functionality. ## Important Notes 1. A Murf API key is required. Set it via the `MURF_API_KEY` environment variable or pass it in the constructor. 2. The service uses GEN2 as the default model version. 3. Speech properties can be set at the constructor level and overridden per request. 4. The service supports extensive audio customization through properties like format, sample rate, and channel type. 5. Speech-to-text functionality is not supported. --- title: "Reference: OpenAI Realtime Voice | Voice Providers | Mastra Docs" description: "Documentation for the OpenAIRealtimeVoice class, providing real-time text-to-speech and speech-to-text capabilities via WebSockets." --- # OpenAI Realtime Voice [EN] Source: https://mastra.ai/en/reference/voice/openai-realtime The OpenAIRealtimeVoice class provides real-time voice interaction capabilities using OpenAI's WebSocket-based API. It supports real time speech to speech, voice activity detection, and event-based audio streaming. ## Usage Example ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import { playAudio, getMicrophoneStream } from "@mastra/node-audio"; // Initialize with default configuration using environment variables const voice = new OpenAIRealtimeVoice(); // Or initialize with specific configuration const voiceWithConfig = new OpenAIRealtimeVoice({ apiKey: "your-openai-api-key", model: "gpt-4o-mini-realtime-preview-2024-12-17", speaker: "alloy", // Default voice }); voiceWithConfig.updateSession({ turn_detection: { type: "server_vad", threshold: 0.6, silence_duration_ms: 1200, }, }); // Establish connection await voice.connect(); // Set up event listeners voice.on("speaker", ({ audio }) => { // Handle audio data (Int16Array) pcm format by default playAudio(audio); }); voice.on("writing", ({ text, role }) => { // Handle transcribed text console.log(`${role}: ${text}`); }); // Convert text to speech await voice.speak("Hello, how can I help you today?", { speaker: "echo", // Override default voice }); // Process audio input const microphoneStream = getMicrophoneStream(); await voice.send(microphoneStream); // When done, disconnect voice.connect(); ``` ## Configuration ### Constructor Options ### Voice Activity Detection (VAD) Configuration ## Methods ### connect() Establishes a connection to the OpenAI realtime service. Must be called before using speak, listen, or send functions. ", description: "Promise that resolves when the connection is established.", }, ]} /> ### speak() Emits a speaking event using the configured voice model. Can accept either a string or a readable stream as input. Returns: `Promise` ### listen() Processes audio input for speech recognition. Takes a readable stream of audio data and emits a 'listening' event with the transcribed text. Returns: `Promise` ### send() Streams audio data in real-time to the OpenAI service for continuous audio streaming scenarios like live microphone input. Returns: `Promise` ### updateConfig() Updates the session configuration for the voice instance. This can be used to modify voice settings, turn detection, and other parameters. Returns: `void` ### addTools() Adds a set of tools to the voice instance. Tools allow the model to perform additional actions during conversations. When OpenAIRealtimeVoice is added to an Agent, any tools configured for the Agent will automatically be available to the voice interface. Returns: `void` ### close() Disconnects from the OpenAI realtime session and cleans up resources. Should be called when you're done with the voice instance. Returns: `void` ### getSpeakers() Returns a list of available voice speakers. Returns: `Promise>` ### on() Registers an event listener for voice events. Returns: `void` ### off() Removes a previously registered event listener. Returns: `void` ## Events The OpenAIRealtimeVoice class emits the following events: ### OpenAI Realtime Events You can also listen to [OpenAI Realtime utility events](https://github.com/openai/openai-realtime-api-beta#reference-client-utility-events) by prefixing with 'openAIRealtime:': ## Available Voices The following voice options are available: - `alloy`: Neutral and balanced - `ash`: Clear and precise - `ballad`: Melodic and smooth - `coral`: Warm and friendly - `echo`: Resonant and deep - `sage`: Calm and thoughtful - `shimmer`: Bright and energetic - `verse`: Versatile and expressive ## Notes - API keys can be provided via constructor options or the `OPENAI_API_KEY` environment variable - The OpenAI Realtime Voice API uses WebSockets for real-time communication - Server-side Voice Activity Detection (VAD) provides better accuracy for speech detection - All audio data is processed as Int16Array format - The voice instance must be connected with `connect()` before using other methods - Always call `close()` when done to properly clean up resources - Memory management is handled by OpenAI Realtime API --- title: "Reference: OpenAI Voice | Voice Providers | Mastra Docs" description: "Documentation for the OpenAIVoice class, providing text-to-speech and speech-to-text capabilities." --- # OpenAI [EN] Source: https://mastra.ai/en/reference/voice/openai The OpenAIVoice class in Mastra provides text-to-speech and speech-to-text capabilities using OpenAI's models. ## Usage Example ```typescript import { OpenAIVoice } from "@mastra/voice-openai"; // Initialize with default configuration using environment variables const voice = new OpenAIVoice(); // Or initialize with specific configuration const voiceWithConfig = new OpenAIVoice({ speechModel: { name: "tts-1-hd", apiKey: "your-openai-api-key", }, listeningModel: { name: "whisper-1", apiKey: "your-openai-api-key", }, speaker: "alloy", // Default voice }); // Convert text to speech const audioStream = await voice.speak("Hello, how can I help you?", { speaker: "nova", // Override default voice speed: 1.2, // Adjust speech speed }); // Convert speech to text const text = await voice.listen(audioStream, { filetype: "mp3", }); ``` ## Configuration ### Constructor Options ### OpenAIConfig ## Methods ### speak() Converts text to speech using OpenAI's text-to-speech models. Returns: `Promise` ### listen() Transcribes audio using OpenAI's Whisper model. Returns: `Promise` ### getSpeakers() Returns an array of available voice options, where each node contains: ## Notes - API keys can be provided via constructor options or the `OPENAI_API_KEY` environment variable - The `tts-1-hd` model provides higher quality audio but may have slower processing times - Speech recognition supports multiple audio formats including mp3, wav, and webm --- title: "Reference: PlayAI Voice | Voice Providers | Mastra Docs" description: "Documentation for the PlayAI voice implementation, providing text-to-speech capabilities." --- # PlayAI [EN] Source: https://mastra.ai/en/reference/voice/playai The PlayAI voice implementation in Mastra provides text-to-speech capabilities using PlayAI's API. ## Usage Example ```typescript import { PlayAIVoice } from "@mastra/voice-playai"; // Initialize with default configuration (uses PLAYAI_API_KEY environment variable and PLAYAI_USER_ID environment variable) const voice = new PlayAIVoice(); // Initialize with default configuration const voice = new PlayAIVoice({ speechModel: { name: "PlayDialog", apiKey: process.env.PLAYAI_API_KEY, userId: process.env.PLAYAI_USER_ID, }, speaker: "Angelo", // Default voice }); // Convert text to speech with a specific voice const audioStream = await voice.speak("Hello, world!", { speaker: "s3://voice-cloning-zero-shot/b27bc13e-996f-4841-b584-4d35801aea98/original/manifest.json", // Dexter voice }); ``` ## Constructor Parameters ### PlayAIConfig ## Methods ### speak() Converts text to speech using the configured speech model and voice. Returns: `Promise`. ### getSpeakers() Returns an array of available voice options, where each node contains: ### listen() This method is not supported by PlayAI and will throw an error. PlayAI does not provide speech-to-text functionality. ## Notes - PlayAI requires both an API key and a user ID for authentication - The service offers two models: 'PlayDialog' and 'Play3.0-mini' - Each voice has a unique S3 manifest ID that must be used when making API calls --- title: "Reference: Sarvam Voice | Voice Providers | Mastra Docs" description: "Documentation for the Sarvam class, providing text-to-speech and speech-to-text capabilities." --- # Sarvam [EN] Source: https://mastra.ai/en/reference/voice/sarvam The SarvamVoice class in Mastra provides text-to-speech and speech-to-text capabilities using Sarvam AI models. ## Usage Example ```typescript import { SarvamVoice } from "@mastra/voice-sarvam"; // Initialize with default configuration using environment variables const voice = new SarvamVoice(); // Or initialize with specific configuration const voiceWithConfig = new SarvamVoice({ speechModel: { model: "bulbul:v1", apiKey: process.env.SARVAM_API_KEY!, language: "en-IN", properties: { pitch: 0, pace: 1.65, loudness: 1.5, speech_sample_rate: 8000, enable_preprocessing: false, eng_interpolation_wt: 123, }, }, listeningModel: { model: "saarika:v2", apiKey: process.env.SARVAM_API_KEY!, languageCode: "en-IN", filetype?: 'wav'; }, speaker: "meera", // Default voice }); // Convert text to speech const audioStream = await voice.speak("Hello, how can I help you?"); // Convert speech to text const text = await voice.listen(audioStream, { filetype: "wav", }); ``` ### Sarvam API Docs - https://docs.sarvam.ai/api-reference-docs/endpoints/text-to-speech ## Configuration ### Constructor Options ### SarvamVoiceConfig ### SarvamListenOptions ## Methods ### speak() Converts text to speech using Sarvam's text-to-speech models. Returns: `Promise` ### listen() Transcribes audio using Sarvam's speech recognition models. Returns: `Promise` ### getSpeakers() Returns an array of available voice options. Returns: `Promise>` ## Notes - API key can be provided via constructor options or the `SARVAM_API_KEY` environment variable - If no API key is provided, the constructor will throw an error - The service communicates with the Sarvam AI API at `https://api.sarvam.ai` - Audio is returned as a stream containing binary audio data - Speech recognition supports mp3 and wav audio formats --- title: "Reference: Speechify Voice | Voice Providers | Mastra Docs" description: "Documentation for the Speechify voice implementation, providing text-to-speech capabilities." --- # Speechify [EN] Source: https://mastra.ai/en/reference/voice/speechify The Speechify voice implementation in Mastra provides text-to-speech capabilities using Speechify's API. ## Usage Example ```typescript import { SpeechifyVoice } from "@mastra/voice-speechify"; // Initialize with default configuration (uses SPEECHIFY_API_KEY environment variable) const voice = new SpeechifyVoice(); // Initialize with custom configuration const voice = new SpeechifyVoice({ speechModel: { name: "simba-english", apiKey: "your-api-key", }, speaker: "george", // Default voice }); // Convert text to speech const audioStream = await voice.speak("Hello, world!", { speaker: "henry", // Override default voice }); ``` ## Constructor Parameters ### SpeechifyConfig ## Methods ### speak() Converts text to speech using the configured speech model and voice. Returns: `Promise` ### getSpeakers() Returns an array of available voice options, where each node contains: ### listen() This method is not supported by Speechify and will throw an error. Speechify does not provide speech-to-text functionality. ## Notes - Speechify requires an API key for authentication - The default model is 'simba-english' - Speech-to-text functionality is not supported - Additional audio stream options can be passed through the speak() method's options parameter --- title: "Reference: voice.addInstructions() | Voice Providers | Mastra Docs" description: "Documentation for the addInstructions() method available in voice providers, which adds instructions to guide the voice model's behavior." --- # voice.addInstructions() [EN] Source: https://mastra.ai/en/reference/voice/voice.addInstructions The `addInstructions()` method equips a voice provider with instructions that guide the model's behavior during real-time interactions. This is particularly useful for real-time voice providers that maintain context across a conversation. ## Usage Example ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // Initialize a real-time voice provider const voice = new OpenAIRealtimeVoice({ realtimeConfig: { model: "gpt-4o-mini-realtime", apiKey: process.env.OPENAI_API_KEY, }, }); // Create an agent with the voice provider const agent = new Agent({ name: "Customer Support Agent", instructions: "You are a helpful customer support agent for a software company.", model: openai("gpt-4o"), voice, }); // Add additional instructions to the voice provider voice.addInstructions(` When speaking to customers: - Always introduce yourself as the customer support agent - Speak clearly and concisely - Ask clarifying questions when needed - Summarize the conversation at the end `); // Connect to the real-time service await voice.connect(); ``` ## Parameters
## Return Value This method does not return a value. ## Notes - Instructions are most effective when they are clear, specific, and relevant to the voice interaction - This method is primarily used with real-time voice providers that maintain conversation context - If called on a voice provider that doesn't support instructions, it will log a warning and do nothing - Instructions added with this method are typically combined with any instructions provided by an associated Agent - For best results, add instructions before starting a conversation (before calling `connect()`) - Multiple calls to `addInstructions()` may either replace or append to existing instructions, depending on the provider implementation --- title: "Reference: voice.addTools() | Voice Providers | Mastra Docs" description: "Documentation for the addTools() method available in voice providers, which equips voice models with function calling capabilities." --- # voice.addTools() [EN] Source: https://mastra.ai/en/reference/voice/voice.addTools The `addTools()` method equips a voice provider with tools (functions) that can be called by the model during real-time interactions. This enables voice assistants to perform actions like searching for information, making calculations, or interacting with external systems. ## Usage Example ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import { createTool } from "@mastra/core/tools"; import { z } from "zod"; // Define tools const weatherTool = createTool({ id: "getWeather", description: "Get the current weather for a location", inputSchema: z.object({ location: z.string().describe("The city and state, e.g. San Francisco, CA"), }), outputSchema: z.object({ message: z.string(), }), execute: async ({ context }) => { // Fetch weather data from an API const response = await fetch( `https://api.weather.com?location=${encodeURIComponent(context.location)}`, ); const data = await response.json(); return { message: `The current temperature in ${context.location} is ${data.temperature}°F with ${data.conditions}.`, }; }, }); // Initialize a real-time voice provider const voice = new OpenAIRealtimeVoice({ realtimeConfig: { model: "gpt-4o-mini-realtime", apiKey: process.env.OPENAI_API_KEY, }, }); // Add tools to the voice provider voice.addTools({ getWeather: weatherTool, }); // Connect to the real-time service await voice.connect(); ``` ## Parameters
## Return Value This method does not return a value. ## Notes - Tools must follow the Mastra tool format with name, description, input schema, and execute function - This method is primarily used with real-time voice providers that support function calling - If called on a voice provider that doesn't support tools, it will log a warning and do nothing - Tools added with this method are typically combined with any tools provided by an associated Agent - For best results, add tools before starting a conversation (before calling `connect()`) - The voice provider will automatically handle the invocation of tool handlers when the model decides to use them - Multiple calls to `addTools()` may either replace or merge with existing tools, depending on the provider implementation --- title: "Reference: voice.answer() | Voice Providers | Mastra Docs" description: "Documentation for the answer() method available in real-time voice providers, which triggers the voice provider to generate a response." --- # voice.answer() [EN] Source: https://mastra.ai/en/reference/voice/voice.answer The `answer()` method is used in real-time voice providers to trigger the AI to generate a response. This method is particularly useful in speech-to-speech conversations where you need to explicitly signal the AI to respond after receiving user input. ## Usage Example ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import { getMicrophoneStream } from "@mastra/node-audio"; import Speaker from "@mastra/node-speaker"; const speaker = new Speaker({ sampleRate: 24100, // Audio sample rate in Hz - standard for high-quality audio on MacBook Pro channels: 1, // Mono audio output (as opposed to stereo which would be 2) bitDepth: 16, // Bit depth for audio quality - CD quality standard (16-bit resolution) }); // Initialize a real-time voice provider const voice = new OpenAIRealtimeVoice({ realtimeConfig: { model: "gpt-4o", apiKey: process.env.OPENAI_API_KEY, }, speaker: "alloy", // Default voice }); // Connect to the real-time service await voice.connect(); // Register event listener for responses voice.on("speaker", (stream) => { // Handle audio response stream.pipe(speaker); }); // Send user audio input const microphoneStream = getMicrophoneStream(); await voice.send(microphoneStream); // Trigger the AI to respond await voice.answer(); ``` ## Parameters
", description: "Provider-specific options for the response", isOptional: true, }, ]} /> ## Return Value Returns a `Promise` that resolves when the response has been triggered. ## Notes - This method is only implemented by real-time voice providers that support speech-to-speech capabilities - If called on a voice provider that doesn't support this functionality, it will log a warning and resolve immediately - The response audio will typically be emitted through the 'speaking' event rather than returned directly - For providers that support it, you can use this method to send a specific response instead of having the AI generate one - This method is commonly used in conjunction with `send()` to create a conversational flow --- title: "Reference: voice.close() | Voice Providers | Mastra Docs" description: "Documentation for the close() method available in voice providers, which disconnects from real-time voice services." --- # voice.close() [EN] Source: https://mastra.ai/en/reference/voice/voice.close The `close()` method disconnects from a real-time voice service and cleans up resources. This is important for properly ending voice sessions and preventing resource leaks. ## Usage Example ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import { getMicrophoneStream } from "@mastra/node-audio"; // Initialize a real-time voice provider const voice = new OpenAIRealtimeVoice({ realtimeConfig: { model: "gpt-4o-mini-realtime", apiKey: process.env.OPENAI_API_KEY, }, }); // Connect to the real-time service await voice.connect(); // Start a conversation voice.speak("Hello, I'm your AI assistant!"); // Stream audio from a microphone const microphoneStream = getMicrophoneStream(); voice.send(microphoneStream); // When the conversation is complete setTimeout(() => { // Close the connection and clean up resources voice.close(); console.log("Voice session ended"); }, 60000); // End after 1 minute ``` ## Parameters This method does not accept any parameters. ## Return Value This method does not return a value. ## Notes - Always call `close()` when you're done with a real-time voice session to free up resources - After calling `close()`, you'll need to call `connect()` again if you want to start a new session - This method is primarily used with real-time voice providers that maintain persistent connections - If called on a voice provider that doesn't support real-time connections, it will log a warning and do nothing - Failing to close connections can lead to resource leaks and potential billing issues with voice service providers --- title: "Reference: voice.connect() | Voice Providers | Mastra Docs" description: "Documentation for the connect() method available in real-time voice providers, which establishes a connection for speech-to-speech communication." --- # voice.connect() [EN] Source: https://mastra.ai/en/reference/voice/voice.connect The `connect()` method establishes a WebSocket or WebRTC connection for real-time speech-to-speech communication. This method must be called before using other real-time features like `send()` or `answer()`. ## Usage Example ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import Speaker from "@mastra/node-speaker"; const speaker = new Speaker({ sampleRate: 24100, // Audio sample rate in Hz - standard for high-quality audio on MacBook Pro channels: 1, // Mono audio output (as opposed to stereo which would be 2) bitDepth: 16, // Bit depth for audio quality - CD quality standard (16-bit resolution) }); // Initialize a real-time voice provider const voice = new OpenAIRealtimeVoice({ realtimeConfig: { model: "gpt-4o-mini-realtime", apiKey: process.env.OPENAI_API_KEY, options: { sessionConfig: { turn_detection: { type: "server_vad", threshold: 0.6, silence_duration_ms: 1200, }, }, }, }, speaker: "alloy", // Default voice }); // Connect to the real-time service await voice.connect(); // Now you can use real-time features voice.on("speaker", (stream) => { stream.pipe(speaker); }); // With connection options await voice.connect({ timeout: 10000, // 10 seconds timeout reconnect: true, }); ``` ## Parameters ", description: "Provider-specific connection options", isOptional: true, }, ]} /> ## Return Value Returns a `Promise` that resolves when the connection is successfully established. ## Provider-Specific Options Each real-time voice provider may support different options for the `connect()` method: ### OpenAI Realtime ## Using with CompositeVoice When using `CompositeVoice`, the `connect()` method delegates to the configured real-time provider: ```typescript import { CompositeVoice } from "@mastra/core/voice"; import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; const realtimeVoice = new OpenAIRealtimeVoice(); const voice = new CompositeVoice({ realtimeProvider: realtimeVoice, }); // This will use the OpenAIRealtimeVoice provider await voice.connect(); ``` ## Notes - This method is only implemented by real-time voice providers that support speech-to-speech capabilities - If called on a voice provider that doesn't support this functionality, it will log a warning and resolve immediately - The connection must be established before using other real-time methods like `send()` or `answer()` - When you're done with the voice instance, call `close()` to properly clean up resources - Some providers may automatically reconnect on connection loss, depending on their implementation - Connection errors will typically be thrown as exceptions that should be caught and handled ## Related Methods - [voice.send()](./voice.send) - Sends audio data to the voice provider - [voice.answer()](./voice.answer) - Triggers the voice provider to respond - [voice.close()](./voice.close) - Disconnects from the real-time service - [voice.on()](./voice.on) - Registers an event listener for voice events --- title: "Reference: Voice Events | Voice Providers | Mastra Docs" description: "Documentation for events emitted by voice providers, particularly for real-time voice interactions." --- # Voice Events [EN] Source: https://mastra.ai/en/reference/voice/voice.events Voice providers emit various events during real-time voice interactions. These events can be listened to using the [voice.on()](./voice.on) method and are particularly important for building interactive voice applications. ## Common Events These events are commonly implemented across real-time voice providers: ## Notes - Not all events are supported by all voice providers - The exact payload structure may vary between providers - For non-real-time providers, most of these events will not be emitted - Events are useful for building interactive UIs that respond to the conversation state - Consider using the [voice.off()](./voice.off) method to remove event listeners when they are no longer needed --- title: "Reference: voice.getSpeakers() | Voice Providers | Mastra Docs" description: "Documentation for the getSpeakers() method available in voice providers, which retrieves available voice options." --- import { Tabs } from "nextra/components"; # voice.getSpeakers() [EN] Source: https://mastra.ai/en/reference/voice/voice.getSpeakers The `getSpeakers()` method retrieves a list of available voice options (speakers) from the voice provider. This allows applications to present users with voice choices or programmatically select the most appropriate voice for different contexts. ## Usage Example ```typescript import { OpenAIVoice } from "@mastra/voice-openai"; import { ElevenLabsVoice } from "@mastra/voice-elevenlabs"; // Initialize voice providers const openaiVoice = new OpenAIVoice(); const elevenLabsVoice = new ElevenLabsVoice({ apiKey: process.env.ELEVENLABS_API_KEY, }); // Get available speakers from OpenAI const openaiSpeakers = await openaiVoice.getSpeakers(); console.log("OpenAI voices:", openaiSpeakers); // Example output: [{ voiceId: "alloy" }, { voiceId: "echo" }, { voiceId: "fable" }, ...] // Get available speakers from ElevenLabs const elevenLabsSpeakers = await elevenLabsVoice.getSpeakers(); console.log("ElevenLabs voices:", elevenLabsSpeakers); // Example output: [{ voiceId: "21m00Tcm4TlvDq8ikWAM", name: "Rachel" }, ...] // Use a specific voice for speech const text = "Hello, this is a test of different voices."; await openaiVoice.speak(text, { speaker: openaiSpeakers[2].voiceId }); await elevenLabsVoice.speak(text, { speaker: elevenLabsSpeakers[0].voiceId }); ``` ## Parameters This method does not accept any parameters. ## Return Value >", type: "Promise", description: "A promise that resolves to an array of voice options, where each option contains at least a voiceId property and may include additional provider-specific metadata.", }, ]} /> ## Provider-Specific Metadata Different voice providers return different metadata for their voices: {/* LLM CONTEXT: This Tabs component shows the different metadata structures returned by various voice providers' getSpeakers() method. Each tab displays the specific properties and data types returned by that voice provider when listing available speakers/voices. The tabs help users understand what information is available for each provider and how to access voice-specific metadata. Each tab includes property tables showing voiceId and provider-specific metadata like name, language, gender, accent, etc. The providers include OpenAI, OpenAI Realtime, Deepgram, ElevenLabs, Google, Murf, PlayAI, Sarvam, Speechify, and Azure. */} ## Notes - The available voices vary significantly between providers - Some providers may require authentication to retrieve the full list of voices - The default implementation returns an empty array if the provider doesn't support this method - For performance reasons, consider caching the results if you need to display the list frequently - The `voiceId` property is guaranteed to be present for all providers, but additional metadata varies --- title: "Reference: voice.listen() | Voice Providers | Mastra Docs" description: "Documentation for the listen() method available in all Mastra voice providers, which converts speech to text." --- # voice.listen() [EN] Source: https://mastra.ai/en/reference/voice/voice.listen The `listen()` method is a core function available in all Mastra voice providers that converts speech to text. It takes an audio stream as input and returns the transcribed text. ## Usage Example ```typescript import { OpenAIVoice } from "@mastra/voice-openai"; import { getMicrophoneStream } from "@mastra/node-audio"; import { createReadStream } from "fs"; import path from "path"; // Initialize a voice provider const voice = new OpenAIVoice({ listeningModel: { name: "whisper-1", apiKey: process.env.OPENAI_API_KEY, }, }); // Basic usage with a file stream const audioFilePath = path.join(process.cwd(), "audio.mp3"); const audioStream = createReadStream(audioFilePath); const transcript = await voice.listen(audioStream, { filetype: "mp3", }); console.log("Transcribed text:", transcript); // Using a microphone stream const microphoneStream = getMicrophoneStream(); // Assume this function gets audio input const transcription = await voice.listen(microphoneStream); // With provider-specific options const transcriptWithOptions = await voice.listen(audioStream, { language: "en", prompt: "This is a conversation about artificial intelligence.", }); ``` ## Parameters ## Return Value Returns one of the following: - `Promise`: A promise that resolves to the transcribed text - `Promise`: A promise that resolves to a stream of transcribed text (for streaming transcription) - `Promise`: For real-time providers that emit 'writing' events instead of returning text directly ## Provider-Specific Options Each voice provider may support additional options specific to their implementation. Here are some examples: ### OpenAI ### Google ### Deepgram ## Realtime Voice Providers When using realtime voice providers like `OpenAIRealtimeVoice`, the `listen()` method behaves differently: - Instead of returning transcribed text, it emits 'writing' events with the transcribed text - You need to register an event listener to receive the transcription ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import { getMicrophoneStream } from "@mastra/node-audio"; const voice = new OpenAIRealtimeVoice(); await voice.connect(); // Register event listener for transcription voice.on("writing", ({ text, role }) => { console.log(`${role}: ${text}`); }); // This will emit 'writing' events instead of returning text const microphoneStream = getMicrophoneStream(); await voice.listen(microphoneStream); ``` ## Using with CompositeVoice When using `CompositeVoice`, the `listen()` method delegates to the configured listening provider: ```typescript import { CompositeVoice } from "@mastra/core/voice"; import { OpenAIVoice } from "@mastra/voice-openai"; import { PlayAIVoice } from "@mastra/voice-playai"; const voice = new CompositeVoice({ listenProvider: new OpenAIVoice(), speakProvider: new PlayAIVoice(), }); // This will use the OpenAIVoice provider const transcript = await voice.listen(audioStream); ``` ## Notes - Not all voice providers support speech-to-text functionality (e.g., PlayAI, Speechify) - The behavior of `listen()` may vary slightly between providers, but all implementations follow the same basic interface - When using a realtime voice provider, the method might not return text directly but instead emit a 'writing' event - The audio format supported depends on the provider. Common formats include MP3, WAV, and M4A - Some providers support streaming transcription, where text is returned as it's transcribed - For best performance, consider closing or ending the audio stream when you're done with it ## Related Methods - [voice.speak()](./voice.speak) - Converts text to speech - [voice.send()](./voice.send) - Sends audio data to the voice provider in real-time - [voice.on()](./voice.on) - Registers an event listener for voice events --- title: "Reference: voice.off() | Voice Providers | Mastra Docs" description: "Documentation for the off() method available in voice providers, which removes event listeners for voice events." --- # voice.off() [EN] Source: https://mastra.ai/en/reference/voice/voice.off The `off()` method removes event listeners previously registered with the `on()` method. This is particularly useful for cleaning up resources and preventing memory leaks in long-running applications with real-time voice capabilities. ## Usage Example ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import chalk from "chalk"; // Initialize a real-time voice provider const voice = new OpenAIRealtimeVoice({ realtimeConfig: { model: "gpt-4o-mini-realtime", apiKey: process.env.OPENAI_API_KEY, }, }); // Connect to the real-time service await voice.connect(); // Define the callback function const writingCallback = ({ text, role }) => { if (role === "user") { process.stdout.write(chalk.green(text)); } else { process.stdout.write(chalk.blue(text)); } }; // Register event listener voice.on("writing", writingCallback); // Later, when you want to remove the listener voice.off("writing", writingCallback); ``` ## Parameters
## Return Value This method does not return a value. ## Notes - The callback passed to `off()` must be the same function reference that was passed to `on()` - If the callback is not found, the method will have no effect - This method is primarily used with real-time voice providers that support event-based communication - If called on a voice provider that doesn't support events, it will log a warning and do nothing - Removing event listeners is important for preventing memory leaks in long-running applications --- title: "Reference: voice.on() | Voice Providers | Mastra Docs" description: "Documentation for the on() method available in voice providers, which registers event listeners for voice events." --- # voice.on() [EN] Source: https://mastra.ai/en/reference/voice/voice.on The `on()` method registers event listeners for various voice events. This is particularly important for real-time voice providers, where events are used to communicate transcribed text, audio responses, and other state changes. ## Usage Example ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import Speaker from "@mastra/node-speaker"; import chalk from "chalk"; // Initialize a real-time voice provider const voice = new OpenAIRealtimeVoice({ realtimeConfig: { model: "gpt-4o-mini-realtime", apiKey: process.env.OPENAI_API_KEY, }, }); // Connect to the real-time service await voice.connect(); // Register event listener for transcribed text voice.on("writing", (event) => { if (event.role === "user") { process.stdout.write(chalk.green(event.text)); } else { process.stdout.write(chalk.blue(event.text)); } }); // Listen for audio data and play it const speaker = new Speaker({ sampleRate: 24100, channels: 1, bitDepth: 16, }); voice.on("speaker", (stream) => { stream.pipe(speaker); }); // Register event listener for errors voice.on("error", ({ message, code, details }) => { console.error(`Error ${code}: ${message}`, details); }); ``` ## Parameters
## Return Value This method does not return a value. ## Events For a comprehensive list of events and their payload structures, see the [Voice Events](./voice.events) documentation. Common events include: - `speaking`: Emitted when audio data is available - `speaker`: Emitted with a stream that can be piped to audio output - `writing`: Emitted when text is transcribed or generated - `error`: Emitted when an error occurs - `tool-call-start`: Emitted when a tool is about to be executed - `tool-call-result`: Emitted when a tool execution is complete Different voice providers may support different sets of events with varying payload structures. ## Using with CompositeVoice When using `CompositeVoice`, the `on()` method delegates to the configured real-time provider: ```typescript import { CompositeVoice } from "@mastra/core/voice"; import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import Speaker from "@mastra/node-speaker"; const speaker = new Speaker({ sampleRate: 24100, // Audio sample rate in Hz - standard for high-quality audio on MacBook Pro channels: 1, // Mono audio output (as opposed to stereo which would be 2) bitDepth: 16, // Bit depth for audio quality - CD quality standard (16-bit resolution) }); const realtimeVoice = new OpenAIRealtimeVoice(); const voice = new CompositeVoice({ realtimeProvider: realtimeVoice, }); // Connect to the real-time service await voice.connect(); // This will register the event listener with the OpenAIRealtimeVoice provider voice.on("speaker", (stream) => { stream.pipe(speaker); }); ``` ## Notes - This method is primarily used with real-time voice providers that support event-based communication - If called on a voice provider that doesn't support events, it will log a warning and do nothing - Event listeners should be registered before calling methods that might emit events - To remove an event listener, use the [voice.off()](./voice.off) method with the same event name and callback function - Multiple listeners can be registered for the same event - The callback function will receive different data depending on the event type (see [Voice Events](./voice.events)) - For best performance, consider removing event listeners when they are no longer needed --- title: "Reference: voice.send() | Voice Providers | Mastra Docs" description: "Documentation for the send() method available in real-time voice providers, which streams audio data for continuous processing." --- # voice.send() [EN] Source: https://mastra.ai/en/reference/voice/voice.send The `send()` method streams audio data in real-time to voice providers for continuous processing. This method is essential for real-time speech-to-speech conversations, allowing you to send microphone input directly to the AI service. ## Usage Example ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import Speaker from "@mastra/node-speaker"; import { getMicrophoneStream } from "@mastra/node-audio"; const speaker = new Speaker({ sampleRate: 24100, // Audio sample rate in Hz - standard for high-quality audio on MacBook Pro channels: 1, // Mono audio output (as opposed to stereo which would be 2) bitDepth: 16, // Bit depth for audio quality - CD quality standard (16-bit resolution) }); // Initialize a real-time voice provider const voice = new OpenAIRealtimeVoice({ realtimeConfig: { model: "gpt-4o-mini-realtime", apiKey: process.env.OPENAI_API_KEY, }, }); // Connect to the real-time service await voice.connect(); // Set up event listeners for responses voice.on("writing", ({ text, role }) => { console.log(`${role}: ${text}`); }); voice.on("speaker", (stream) => { stream.pipe(speaker); }); // Get microphone stream (implementation depends on your environment) const microphoneStream = getMicrophoneStream(); // Send audio data to the voice provider await voice.send(microphoneStream); // You can also send audio data as Int16Array const audioBuffer = getAudioBuffer(); // Assume this returns Int16Array await voice.send(audioBuffer); ``` ## Parameters
## Return Value Returns a `Promise` that resolves when the audio data has been accepted by the voice provider. ## Notes - This method is only implemented by real-time voice providers that support speech-to-speech capabilities - If called on a voice provider that doesn't support this functionality, it will log a warning and resolve immediately - You must call `connect()` before using `send()` to establish the WebSocket connection - The audio format requirements depend on the specific voice provider - For continuous conversation, you typically call `send()` to transmit user audio, then `answer()` to trigger the AI response - The provider will typically emit 'writing' events with transcribed text as it processes the audio - When the AI responds, the provider will emit 'speaking' events with the audio response --- title: "Reference: voice.speak() | Voice Providers | Mastra Docs" description: "Documentation for the speak() method available in all Mastra voice providers, which converts text to speech." --- # voice.speak() [EN] Source: https://mastra.ai/en/reference/voice/voice.speak The `speak()` method is a core function available in all Mastra voice providers that converts text to speech. It takes text input and returns an audio stream that can be played or saved. ## Usage Example ```typescript import { OpenAIVoice } from "@mastra/voice-openai"; // Initialize a voice provider const voice = new OpenAIVoice({ speaker: "alloy", // Default voice }); // Basic usage with default settings const audioStream = await voice.speak("Hello, world!"); // Using a different voice for this specific request const audioStreamWithDifferentVoice = await voice.speak("Hello again!", { speaker: "nova", }); // Using provider-specific options const audioStreamWithOptions = await voice.speak("Hello with options!", { speaker: "echo", speed: 1.2, // OpenAI-specific option }); // Using a text stream as input import { Readable } from "stream"; const textStream = Readable.from(["Hello", " from", " a", " stream!"]); const audioStreamFromTextStream = await voice.speak(textStream); ``` ## Parameters ## Return Value Returns a `Promise` where: - `NodeJS.ReadableStream`: A stream of audio data that can be played or saved - `void`: When using a realtime voice provider that emits audio through events instead of returning it directly ## Provider-Specific Options Each voice provider may support additional options specific to their implementation. Here are some examples: ### OpenAI ### ElevenLabs ### Google ### Murf ## Realtime Voice Providers When using realtime voice providers like `OpenAIRealtimeVoice`, the `speak()` method behaves differently: - Instead of returning an audio stream, it emits a 'speaking' event with the audio data - You need to register an event listener to receive the audio chunks ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import Speaker from "@mastra/node-speaker"; const speaker = new Speaker({ sampleRate: 24100, // Audio sample rate in Hz - standard for high-quality audio on MacBook Pro channels: 1, // Mono audio output (as opposed to stereo which would be 2) bitDepth: 16, // Bit depth for audio quality - CD quality standard (16-bit resolution) }); const voice = new OpenAIRealtimeVoice(); await voice.connect(); // Register event listener for audio chunks voice.on("speaker", (stream) => { // Handle audio chunk (e.g., play it or save it) stream.pipe(speaker); }); // This will emit 'speaking' events instead of returning a stream await voice.speak("Hello, this is realtime speech!"); ``` ## Using with CompositeVoice When using `CompositeVoice`, the `speak()` method delegates to the configured speaking provider: ```typescript import { CompositeVoice } from "@mastra/core/voice"; import { OpenAIVoice } from "@mastra/voice-openai"; import { PlayAIVoice } from "@mastra/voice-playai"; const voice = new CompositeVoice({ speakProvider: new PlayAIVoice(), listenProvider: new OpenAIVoice(), }); // This will use the PlayAIVoice provider const audioStream = await voice.speak("Hello, world!"); ``` ## Notes - The behavior of `speak()` may vary slightly between providers, but all implementations follow the same basic interface. - When using a realtime voice provider, the method might not return an audio stream directly but instead emit a 'speaking' event. - If a text stream is provided as input, the provider will typically convert it to a string before processing. - The audio format of the returned stream depends on the provider. Common formats include MP3, WAV, and OGG. - For best performance, consider closing or ending the audio stream when you're done with it. --- title: "Reference: voice.updateConfig() | Voice Providers | Mastra Docs" description: "Documentation for the updateConfig() method available in voice providers, which updates the configuration of a voice provider at runtime." --- # voice.updateConfig() [EN] Source: https://mastra.ai/en/reference/voice/voice.updateConfig The `updateConfig()` method allows you to update the configuration of a voice provider at runtime. This is useful for changing voice settings, API keys, or other provider-specific options without creating a new instance. ## Usage Example ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; // Initialize a real-time voice provider const voice = new OpenAIRealtimeVoice({ realtimeConfig: { model: "gpt-4o-mini-realtime", apiKey: process.env.OPENAI_API_KEY, }, speaker: "alloy", }); // Connect to the real-time service await voice.connect(); // Later, update the configuration voice.updateConfig({ voice: "nova", // Change the default voice turn_detection: { type: "server_vad", threshold: 0.5, silence_duration_ms: 1000, }, }); // The next speak() call will use the new configuration await voice.speak("Hello with my new voice!"); ``` ## Parameters
", description: "Configuration options to update. The specific properties depend on the voice provider.", isOptional: false, }, ]} /> ## Return Value This method does not return a value. ## Configuration Options Different voice providers support different configuration options: ### OpenAI Realtime
## Notes - The default implementation logs a warning if the provider doesn't support this method - Configuration updates are typically applied to subsequent operations, not ongoing ones - Not all properties that can be set in the constructor can be updated at runtime - The specific behavior depends on the voice provider implementation - For real-time voice providers, some configuration changes may require reconnecting to the service --- title: "Reference: Workflow.branch() | Building Workflows | Mastra Docs" description: Documentation for the `.branch()` method in workflows, which creates conditional branches between steps. --- # Workflow.branch() [EN] Source: https://mastra.ai/en/reference/workflows/branch The `.branch()` method creates conditional branches between workflow steps, allowing for different paths to be taken based on the result of a previous step. ## Usage ```typescript workflow.branch([ [async ({ context }) => true, stepOne], [async ({ context }) => false, stepTwo], ]); ``` ## Parameters boolean, Step]", description: "An array of tuples, each containing a condition function and a step to execute if the condition is true", isOptional: false, }, ]} /> ## Returns ## Related - [Conditional branching](../../docs/workflows/flow-control.mdx#conditional-branching) - [Conditional branching example](../../examples/workflows/conditional-branching.mdx) --- title: "Reference: Workflow.commit() | Building Workflows | Mastra Docs" description: Documentation for the `.commit()` method in workflows, which finalizes the workflow and returns the final result. --- # Workflow.commit() [EN] Source: https://mastra.ai/en/reference/workflows/commit The `.commit()` method finalizes the workflow and returns the final result. ## Usage ```typescript workflow.then(stepOne).commit(); ``` ## Returns ## Related - [Control flow](../../docs/workflows/control-flow.mdx) --- title: "Reference: Workflow.createRun() | Building Workflows | Mastra Docs" description: Documentation for the `.createRun()` method in workflows, which creates a new workflow run instance. --- # Workflow.createRun() [EN] Source: https://mastra.ai/en/reference/workflows/create-run The `.createRun()` method creates a new workflow run instance, allowing you to execute the workflow with specific input data. ## Usage ```typescript const myWorkflow = createWorkflow({ id: "my-workflow", inputSchema: z.object({ startValue: z.string(), }), outputSchema: z.object({ result: z.string(), }), steps: [step1, step2, step3], // Declare steps used in this workflow }) .then(step1) .then(step2) .then(step3) .commit(); const mastra = new Mastra({ workflows: { myWorkflow, }, }); const run = mastra.getWorkflow("myWorkflow").createRun(); ``` ## Parameters ## Returns ## Related - [Running workflows](../../docs/workflows/overview.mdx#running-workflows) --- title: "Reference: Workflow.dountil() | Building Workflows | Mastra Docs" description: Documentation for the `.dountil()` method in workflows, which creates a loop that executes a step until a condition is met. --- # Workflow.dountil() [EN] Source: https://mastra.ai/en/reference/workflows/dountil The `.dountil()` method creates a loop that executes a step until a condition is met. ## Usage ```typescript workflow.dountil(stepOne, async ({ inputData }) => true); ``` ## Parameters Promise", description: "A function that returns a boolean indicating whether to continue the loop", isOptional: false, }, ]} /> ## Returns ## Related - [Loops](../../docs/workflows/control-flow.mdx#loops) - [Loops example](../../examples/workflows/control-flow.mdx) --- title: "Reference: Workflow.dowhile() | Building Workflows | Mastra Docs" description: Documentation for the `.dowhile()` method in workflows, which creates a loop that executes a step while a condition is met. --- # Workflow.dowhile() [EN] Source: https://mastra.ai/en/reference/workflows/dowhile The `.dowhile()` method creates a loop that executes a step while a condition is met. ## Usage ```typescript workflow.dowhile(stepOne, async ({ inputData }) => true); ``` ## Parameters Promise", description: "A function that returns a boolean indicating whether to continue the loop", isOptional: false, }, ]} /> ## Returns ## Related - [Loops](../../docs/workflows/flow-control.mdx#loops) - [Loops example](../../examples/workflows/control-flow.mdx) --- title: "Reference: Workflow.execute() | Building Workflows | Mastra Docs" description: Documentation for the `.execute()` method in workflows, which executes a step with input data and returns the output. --- # Workflow.execute() [EN] Source: https://mastra.ai/en/reference/workflows/execute The `.execute()` method executes a step with input data and returns the output, allowing you to process data within a workflow. ## Usage ```typescript const inputSchema = z.object({ inputValue: z.string(), }); const myStep = createStep({ id: "my-step", description: "Does something useful", inputSchema, outputSchema: z.object({ outputValue: z.string(), }), resumeSchema: z.object({ resumeValue: z.string(), }), suspendSchema: z.object({ suspendValue: z.string(), }), execute: async ({ inputData, mastra, getStepResult, getInitData, runtimeContext, }) => { const otherStepOutput = getStepResult(step2); const initData = getInitData(); // typed as the input schema variable (zod schema) return { outputValue: `Processed: ${inputData.inputValue}, ${initData.startValue} (runtimeContextValue: ${runtimeContext.get("runtimeContextValue")})`, }; }, }); ``` ## Parameters ", description: "Input data matching the step's input schema", isOptional: false, }, { name: "resumeData", type: "ResumeSchema", description: "Data for resuming a suspended step", isOptional: true, }, { name: "suspend", type: "(suspendPayload: any) => Promise", description: "Function to suspend step execution", isOptional: false, }, { name: "resume", type: "object", description: "Configuration for resuming execution", isOptional: true, properties: [ { name: "steps", type: "string[]", description: "Steps to resume", isOptional: false, }, { name: "resumePayload", type: "any", description: "Payload data for resuming", isOptional: false, }, { name: "runId", type: "string", description: "ID of the run to resume", isOptional: true, }, ], }, { name: "emitter", type: "object", description: "Event emitter object", isOptional: false, properties: [ { name: "emit", type: "(event: string, data: any) => void", description: "Function to emit events", isOptional: false, }, ], }, { name: "mastra", type: "Mastra", description: "Mastra instance", isOptional: false, }, ], }, ]} /> ## Returns >", description: "A promise that resolves to the output of the executed step", }, ]} /> ## Related - [Running workflows](../../docs/workflows/overview.mdx#running-workflows) --- title: "Reference: Workflow.foreach() | Building Workflows | Mastra Docs" description: Documentation for the `.foreach()` method in workflows, which creates a loop that executes a step for each item in an array. --- # Workflow.foreach() [EN] Source: https://mastra.ai/en/reference/workflows/foreach The `.foreach()` method creates a loop that executes a step for each item in an array. ## Usage ```typescript workflow.foreach(stepOne, { concurrency: 2 }); ``` ## Parameters ## Returns ## Related - [For each](../../docs/workflows/control-flow.mdx#foreach) --- title: "Reference: Workflow.map() | Building Workflows | Mastra Docs" description: Documentation for the `.map()` method in workflows, which maps output data from a previous step to the input of a subsequent step. --- # Workflow.map() [EN] Source: https://mastra.ai/en/reference/workflows/map The `.map()` method maps output data from a previous step to the input of a subsequent step, allowing you to transform data between steps. ## Usage ```typescript const step1 = createStep({ id: "step1", inputSchema: z.object({ inputValue: z.string(), }), outputSchema: z.object({ outputValue: z.string(), }), execute: async ({ inputData }) => { return { outputValue: inputData.inputValue }; }, }); const step2 = createStep({ id: "step2", inputSchema: z.object({ unexpectedName: z.string(), }), outputSchema: z.object({ result: z.string(), }), execute: async ({ inputData }) => { return { result: inputData.unexpectedName }; }, }); const workflow = createWorkflow({ id: "my-workflow", steps: [step1, step2], inputSchema: z.object({ inputValue: z.string(), }), outputSchema: z.object({ result: z.string(), }), }); workflow .then(step1) .map({ unexpectedName: { step: step1, path: "outputValue", }, }) .then(step2) .commit(); ``` ## Parameters ## Returns ## Related - [Input data mapping](../../docs/workflows/input-data-mapping.mdx) --- title: "Reference: Workflow.parallel() | Building Workflows | Mastra Docs" description: Documentation for the `.parallel()` method in workflows, which executes multiple steps in parallel. --- # Workflow.parallel() [EN] Source: https://mastra.ai/en/reference/workflows/parallel The `.parallel()` method executes multiple steps in parallel. ## Usage ```typescript workflow.parallel([stepOne, stepTwo]); ``` ## Parameters ## Returns ## Related - [Parallel workflow example](../../examples/workflows/parallel-steps.mdx) --- title: "Reference: Workflow.resume() | Building Workflows | Mastra Docs" description: Documentation for the `.resume()` method in workflows, which resumes a suspended workflow run with new data. --- # Workflow.resume() [EN] Source: https://mastra.ai/en/reference/workflows/resume The `.resume()` method resumes a suspended workflow run with new data, allowing you to continue execution from a specific step. ## Usage ```typescript const run = counterWorkflow.createRun(); const result = await run.start({ inputData: { startValue: 0 } }); if (result.status === "suspended") { const resumedResults = await run.resume({ step: result.suspended[0], resumeData: { newValue: 0 }, }); } ``` ## Parameters ## Returns >", description: "A promise that resolves to the result of the resumed workflow run", }, ]} /> ## Related - [Suspend and resume](../../docs/workflows/suspend-and-resume.mdx) - [Human in the loop example](../../examples/workflows/human-in-the-loop.mdx) --- title: "Reference: Snapshots | Workflow State Persistence | Mastra Docs" description: "Technical reference on snapshots in Mastra - the serialized workflow state that enables suspend and resume functionality" --- # Snapshots [EN] Source: https://mastra.ai/en/reference/workflows/snapshots In Mastra, a snapshot is a serializable representation of a workflow's complete execution state at a specific point in time. Snapshots capture all the information needed to resume a workflow from exactly where it left off, including: - The current state of each step in the workflow - The outputs of completed steps - The execution path taken through the workflow - Any suspended steps and their metadata - The remaining retry attempts for each step - Additional contextual data needed to resume execution Snapshots are automatically created and managed by Mastra whenever a workflow is suspended, and are persisted to the configured storage system. ## The Role of Snapshots in Suspend and Resume Snapshots are the key mechanism enabling Mastra's suspend and resume capabilities. When a workflow step calls `await suspend()`: 1. The workflow execution is paused at that exact point 2. The current state of the workflow is captured as a snapshot 3. The snapshot is persisted to storage 4. The workflow step is marked as "suspended" with a status of `'suspended'` 5. Later, when `resume()` is called on the suspended step, the snapshot is retrieved 6. The workflow execution resumes from exactly where it left off This mechanism provides a powerful way to implement human-in-the-loop workflows, handle rate limiting, wait for external resources, and implement complex branching workflows that may need to pause for extended periods. ## Snapshot Anatomy A Mastra workflow snapshot consists of several key components: ```typescript export interface WorkflowRunState { // Core state info value: Record; // Current state machine value context: { // Workflow context [key: string]: Record< string, | { status: "success"; output: any; } | { status: "failed"; error: string; } | { status: "suspended"; payload?: any; } >; input: Record; // Initial input data }; activePaths: Array<{ // Currently active execution paths stepPath: string[]; stepId: string; status: string; }>; // Paths to suspended steps suspendedPaths: Record; // Metadata runId: string; // Unique run identifier timestamp: number; // Time snapshot was created } ``` ## How Snapshots Are Saved and Retrieved Mastra persists snapshots to the configured storage system. By default, snapshots are saved to a LibSQL database, but can be configured to use other storage providers like Upstash. The snapshots are stored in the `workflow_snapshots` table and identified uniquely by the `run_id` for the associated run when using libsql. Utilizing a persistence layer allows for the snapshots to be persisted across workflow runs, allowing for advanced human-in-the-loop functionality. Read more about [libsql storage](../storage/libsql.mdx) and [upstash storage](../storage/upstash.mdx) here. ### Saving Snapshots When a workflow is suspended, Mastra automatically persists the workflow snapshot with these steps: 1. The `suspend()` function in a step execution triggers the snapshot process 2. The `WorkflowInstance.suspend()` method records the suspended machine 3. `persistWorkflowSnapshot()` is called to save the current state 4. The snapshot is serialized and stored in the configured database in the `workflow_snapshots` table 5. The storage record includes the workflow name, run ID, and the serialized snapshot ### Retrieving Snapshots When a workflow is resumed, Mastra retrieves the persisted snapshot with these steps: 1. The `resume()` method is called with a specific step ID 2. The snapshot is loaded from storage using `loadWorkflowSnapshot()` 3. The snapshot is parsed and prepared for resumption 4. The workflow execution is recreated with the snapshot state 5. The suspended step is resumed, and execution continues ## Storage Options for Snapshots Mastra provides multiple storage options for persisting snapshots. A `storage` instance is configured on the `Mastra` class, and is used to setup a snapshot persistence layer for all workflows registered on the `Mastra` instance. This means that storage is shared across all workflows registered with the same `Mastra` instance. ### LibSQL (Default) The default storage option is LibSQL, a SQLite-compatible database: ```typescript import { Mastra } from "@mastra/core/mastra"; import { DefaultStorage } from "@mastra/core/storage/libsql"; const mastra = new Mastra({ storage: new DefaultStorage({ config: { url: "file:storage.db", // Local file-based database // For production: // url: process.env.DATABASE_URL, // authToken: process.env.DATABASE_AUTH_TOKEN, }, }), workflows: { weatherWorkflow, travelWorkflow, }, }); ``` ### Upstash (Redis-Compatible) For serverless environments: ```typescript import { Mastra } from "@mastra/core/mastra"; import { UpstashStore } from "@mastra/upstash"; const mastra = new Mastra({ storage: new UpstashStore({ url: process.env.UPSTASH_URL, token: process.env.UPSTASH_TOKEN, }), workflows: { weatherWorkflow, travelWorkflow, }, }); ``` ## Best Practices for Working with Snapshots 1. **Ensure Serializability**: Any data that needs to be included in the snapshot must be serializable (convertible to JSON). 2. **Minimize Snapshot Size**: Avoid storing large data objects directly in the workflow context. Instead, store references to them (like IDs) and retrieve the data when needed. 3. **Handle Resume Context Carefully**: When resuming a workflow, carefully consider what context to provide. This will be merged with the existing snapshot data. 4. **Set Up Proper Monitoring**: Implement monitoring for suspended workflows, especially long-running ones, to ensure they are properly resumed. 5. **Consider Storage Scaling**: For applications with many suspended workflows, ensure your storage solution is appropriately scaled. ## Advanced Snapshot Patterns ### Custom Snapshot Metadata When suspending a workflow, you can include custom metadata that can help when resuming: ```typescript await suspend({ reason: "Waiting for customer approval", requiredApprovers: ["manager", "finance"], requestedBy: currentUser, urgency: "high", expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), }); ``` This metadata is stored with the snapshot and available when resuming. ### Conditional Resumption You can implement conditional logic based on the suspend payload when resuming: ```typescript run.watch(async ({ activePaths }) => { const isApprovalStepSuspended = activePaths.get("approval")?.status === "suspended"; if (isApprovalStepSuspended) { const payload = activePaths.get("approval")?.suspendPayload; if (payload.urgency === "high" && currentUser.role === "manager") { await resume({ stepId: "approval", context: { approved: true, approver: currentUser.id }, }); } } }); ``` ## Related - [Suspend and resume](../../docs/workflows/suspend-and-resume.mdx) - [Human in the loop example](../../examples/workflows/human-in-the-loop.mdx) - [Watch Function Reference](./watch.mdx) --- title: "Reference: Workflow.start() | Building Workflows | Mastra Docs" description: Documentation for the `.start()` method in workflows, which starts a workflow run with input data. --- # Workflow.start() [EN] Source: https://mastra.ai/en/reference/workflows/start The `.start()` method starts a workflow run with input data, allowing you to execute the workflow from the beginning. ## Usage ```typescript const run = myWorkflow.createRun(); // Start the workflow with input data const result = await run.start({ inputData: { startValue: "initial data", }, }); ``` ## Parameters ", description: "Input data matching the workflow's input schema", isOptional: true, }, { name: "runtimeContext", type: "RuntimeContext", description: "Runtime context data to use when starting the workflow", isOptional: true, }, ], }, ]} /> ## Returns >", description: "A promise that resolves to the result of the workflow run", }, ]} /> ## Related - [Running workflows](../../docs/workflows/overview.mdx#running-workflows) - [Create run reference](./create-run.mdx) --- title: "Reference: Step | Building Workflows | Mastra Docs" description: Documentation for the Step class, which defines individual units of work within a workflow. --- # Step [EN] Source: https://mastra.ai/en/reference/workflows/step The Step class defines individual units of work within a workflow, encapsulating execution logic, data validation, and input/output handling. It can take either a tool or an agent as a parameter to automatically create a step from them. ## Usage ```typescript import { createStep } from "@mastra/core/workflows"; import { z } from "zod"; const processOrder = createStep({ id: "processOrder", inputSchema: z.object({ orderId: z.string(), userId: z.string(), }), outputSchema: z.object({ status: z.string(), orderId: z.string(), }), resumeSchema: z.object({ orderId: z.string(), }), suspendSchema: z.object({}), execute: async ({ inputData, mastra, getStepResult, getInitData, suspend, runtimeContext, runId, }) => { return { status: "processed", orderId: inputData.orderId, }; }, }); ``` ## Constructor Parameters ", description: "Zod schema defining the input structure", required: true, }, { name: "outputSchema", type: "z.ZodType", description: "Zod schema defining the output structure", required: true, }, { name: "resumeSchema", type: "z.ZodType", description: "Optional Zod schema for resuming the step", required: false, }, { name: "suspendSchema", type: "z.ZodType", description: "Optional Zod schema for suspending the step", required: false, }, { name: "execute", type: "(params: ExecuteParams) => Promise", description: "Async function containing step logic", required: true, }, ]} /> ### ExecuteParams ", description: "The input data matching the inputSchema", }, { name: "resumeData", type: "z.infer", description: "The resume data matching the resumeSchema, when resuming the step from a suspended state. Only exists if the step is being resumed.", }, { name: "mastra", type: "Mastra", description: "Access to Mastra services (agents, tools, etc.)", }, { name: "getStepResult", type: "(stepId: string) => any", description: "Function to access results from other steps", }, { name: "getInitData", type: "() => any", description: "Function to access the initial input data of the workflow in any step", }, { name: "suspend", type: "() => Promise", description: "Function to pause workflow execution", }, { name: "runId", type: "string", description: "Current run id", }, { name: "runtimeContext", type: "RuntimeContext", isOptional: true, description: "Runtime context for dependency injection and contextual information.", }, ]} /> ## Related - [Control flow](../../docs/workflows/control-flow.mdx) - [Using agents and tools](../../docs/workflows/using-with-agents-and-tools.mdx) - [Tool and agent as step example](../../examples/workflows/agent-and-tool-interop.mdx) - [Input data mapping](../../docs/workflows/input-data-mapping.mdx) --- title: "Reference: Workflow.stream() | Building Workflows | Mastra Docs" description: Documentation for the `.stream()` method in workflows, which allows you to monitor the execution of a workflow run as a stream. --- # Run.stream() [EN] Source: https://mastra.ai/en/reference/workflows/stream The `.stream()` method allows you to monitor the execution of a workflow run, providing real-time updates on the status of steps. ## Usage ```typescript const run = myWorkflow.createRun(); // Add a stream to monitor execution const result = run.stream({ inputData: {...} }); for (const chunk of stream) { // do something with the chunk } ``` ## Messages ## Parameters ", parameters: [ { name: "z.infer", type: "inputData", description: "Runtime context data to use when starting the workflow", isOptional: true, }, ], }, { name: "runtimeContext", type: "RuntimeContext", parameters: [ { name: "runtimeContext", type: "RuntimeContext", description: "Runtime context data to use when starting the workflow", isOptional: true, }, ], }, ], }, ]} /> ## Returns >", description: "A stream that pipes each step to the stream", }, ]} /> --- title: "Reference: Workflow.then() | Building Workflows | Mastra Docs" description: Documentation for the `.then()` method in workflows, which creates sequential dependencies between steps. --- # Workflow.then() [EN] Source: https://mastra.ai/en/reference/workflows/then The `.then()` method creates a sequential dependency between workflow steps, ensuring steps execute in a specific order. ## Usage ```typescript workflow.then(stepOne).then(stepTwo); ``` ## Parameters ## Returns ## Related - [Control flow](../../docs/workflows/control-flow.mdx) --- title: "Reference: Workflow.watch() | Building Workflows | Mastra Docs" description: Documentation for the `.watch()` method in workflows, which allows you to monitor the execution of a workflow run. --- # Workflow.watch() [EN] Source: https://mastra.ai/en/reference/workflows/watch The `.watch()` method allows you to monitor the execution of a workflow run, providing real-time updates on the status of steps. ## Usage ```typescript const run = myWorkflow.createRun(); // Add a watcher to monitor execution run.watch(event => { console.log('Step completed:', event.payload.currentStep.id); }); // Start the workflow const result = await run.start({ inputData: {...} }); ``` ## Parameters void", description: "A callback function that is called whenever a step is completed or the workflow state changes", isOptional: false, }, ]} /> ## Returns void", description: "A function that can be called to stop watching the workflow run", }, ]} /> ## Related - [Suspend and resume](../../docs/workflows/suspend-and-resume.mdx) - [Human in the loop example](../../examples/workflows/human-in-the-loop.mdx) - [Snapshot Reference](./snapshots.mdx) - [Workflow watch guide](../../docs/workflows/overview.mdx#watching-workflow-execution) --- title: "Reference: Workflow Class | Building Workflows | Mastra Docs" description: Documentation for the Workflow class in Mastra, which enables you to create state machines for complex sequences of operations with conditional branching and data validation. --- # Workflow Class [EN] Source: https://mastra.ai/en/reference/workflows/workflow The Workflow class enables you to create state machines for complex sequences of operations with conditional branching and data validation. ## Usage ```typescript const myWorkflow = createWorkflow({ id: "my-workflow", inputSchema: z.object({ startValue: z.string(), }), outputSchema: z.object({ result: z.string(), }), steps: [step1, step2, step3], // Declare steps used in this workflow }) .then(step1) .then(step2) .then(step3) .commit(); const mastra = new Mastra({ workflows: { myWorkflow, }, }); const run = mastra.getWorkflow("myWorkflow").createRun(); ``` ## API Reference ### Constructor ", description: "Zod schema defining the input structure for the workflow", }, { name: "outputSchema", type: "z.ZodType", description: "Zod schema defining the output structure for the workflow", }, { name: "steps", type: "Step[]", description: "Array of steps to include in the workflow", }, ]} /> ### Core Methods #### `then()` Adds a step to the workflow sequentially. Returns the workflow instance for chaining. #### `parallel()` Executes multiple steps concurrently. Takes an array of steps and returns the workflow instance. #### `branch()` Creates conditional branching logic. Takes an array of tuples containing condition functions and steps to execute when conditions are met. #### `dowhile()` Creates a loop that executes a step repeatedly while a condition remains true. The condition is checked after each execution. #### `dountil()` Creates a loop that executes a step repeatedly until a condition becomes true. The condition is checked after each execution. #### `foreach()` Iterates over an array and executes a step for each element. Accepts optional concurrency configuration. #### `map()` Maps data between steps using either a mapping configuration object or a mapping function. Useful for transforming data between steps. #### `commit()` Validates and finalizes the workflow configuration. Must be called after adding all steps. #### `createRun()` Creates a new workflow run instance, allowing you to execute the workflow with specific input data. Accepts optional run ID. #### `execute()` Executes the workflow with provided input data. Handles workflow suspension, resumption and emits events during execution. ## Workflow Status A workflow's status indicates its current execution state. The possible values are: ## Passing Context Between Steps Steps can access data from previous steps in the workflow through the context object. Each step receives the accumulated context from all previous steps that have executed. ```typescript workflow .then({ id: "getData", execute: async ({ inputData }) => { return { data: { id: "123", value: "example" }, }; }, }) .then({ id: "processData", execute: async ({ inputData }) => { // Access data from previous step through context.steps const previousData = inputData.data; // Process previousData.id and previousData.value }, }); ``` ## Related - [Control flow](../../docs/workflows/flow-control.mdx) --- title: "Showcase" description: "Check out these applications built with Mastra" --- [EN] Source: https://mastra.ai/en/showcase import { ShowcaseGrid } from "@/components/showcase-grid"; --- title: "エージェントツール選択 | エージェントドキュメント | Mastra" description: ツールは、エージェントやワークフローによって実行できる型付き関数で、組み込みの統合アクセスとパラメータ検証機能を備えています。各ツールには、入力を定義するスキーマ、ロジックを実装する実行関数、および設定された統合へのアクセスがあります。 --- # エージェントツールの選択 [JA] Source: https://mastra.ai/ja/docs/agents/adding-tools ツールは、エージェントやワークフローによって実行できる型付き関数であり、組み込みの統合アクセスとパラメータ検証機能を備えています。各ツールには、入力を定義するスキーマ、ロジックを実装する実行関数、および設定された統合へのアクセスがあります。 ## ツールの作成 このセクションでは、エージェントが使用できるツールを作成するプロセスを説明します。都市の現在の天気情報を取得するシンプルなツールを作成してみましょう。 ```typescript filename="src/mastra/tools/weatherInfo.ts" copy import { createTool } from "@mastra/core/tools"; import { z } from "zod"; const getWeatherInfo = async (city: string) => { // Replace with an actual API call to a weather service const data = await fetch(`https://api.example.com/weather?city=${city}`).then( (r) => r.json(), ); return data; }; export const weatherInfo = createTool({ id: "Get Weather Information", inputSchema: z.object({ city: z.string(), }), description: `Fetches the current weather information for a given city`, execute: async ({ context: { city } }) => { console.log("Using tool to fetch weather information for", city); return await getWeatherInfo(city); }, }); ``` ## エージェントにツールを追加する 次に、ツールをエージェントに追加します。天気に関する質問に答えることができるエージェントを作成し、`weatherInfo`ツールを使用するように設定します。 ```typescript filename="src/mastra/agents/weatherAgent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import * as tools from "../tools/weatherInfo"; export const weatherAgent = new Agent({ name: "Weather Agent", instructions: "You are a helpful assistant that provides current weather information. When asked about the weather, use the weather information tool to fetch the data.", model: openai("gpt-4o-mini"), tools: { weatherInfo: tools.weatherInfo, }, }); ``` ## エージェントの登録 Mastraにエージェントを初期化する必要があります。 ```typescript filename="src/index.ts" import { Mastra } from "@mastra/core"; import { weatherAgent } from "./agents/weatherAgent"; export const mastra = new Mastra({ agents: { weatherAgent }, }); ``` これによりエージェントがMastraに登録され、使用可能になります。 ## アボートシグナル `generate`と`stream`(テキスト生成)からのアボートシグナルはツール実行に転送されます。これらは実行関数の2番目のパラメータでアクセスでき、長時間実行される計算を中止したり、ツール内のフェッチ呼び出しに転送したりすることができます。 ```typescript import { Agent } from "@mastra/core/agent"; import { createTool } from "@mastra/core/tools"; import { z } from "zod"; const agent = new Agent({ name: "Weather agent", tools: { weather: createTool({ id: "Get Weather Information", description: "Get the weather in a location", inputSchema: z.object({ location: z.string() }), execute: async ({ context: { location } }, { abortSignal }) => { return fetch( `https://api.weatherapi.com/v1/current.json?q=${location}`, { signal: abortSignal }, // forward the abort signal to fetch ); }, }), }, }); const result = await agent.generate("What is the weather in San Francisco?", { abortSignal: myAbortSignal, // signal that will be forwarded to tools }); ``` ## リクエスト/ユーザー固有の変数の注入 ツールとワークフローの依存性注入をサポートしています。`generate`または`stream`関数呼び出しに直接runtimeContextを渡すか、[サーバーミドルウェア](/docs/deployment/server#Middleware)を使用して注入することができます。 以下は、温度スケールを華氏と摂氏の間で変更する例です: ```typescript filename="src/agents/weather-agent.ts" import { Agent } from "@mastra/core/agent"; import { createTool } from "@mastra/core/tools"; import { z } from "zod"; export const agent = new Agent({ name: "Weather agent", tools: { weather: createTool({ id: "Get Weather Information", description: "Get the weather in a location", inputSchema: z.object({ location: z.string() }), execute: async ({ context: { location }, runtimeContext }) => { const scale = runtimeContext.get("temperature-scale"); const result = await fetch( `https://api.weatherapi.com/v1/current.json?q=${location}`, ); const json = await result.json(); return { temperature: scale === "celsius" ? json.temp_c : json.temp_f, }; }, }), }, }); ``` ```typescript import { agent } from "./agents/weather"; type MyRuntimeContext = {"temperature-scale", "celsius" | "farenheit"} const runtimeContext = new RuntimeContext(); runtimeContext.set("temperature-scale", "celsius"); const result = await agent.generate("What is the weather in San Francisco?", { runtimeContext, }); ``` ## デバッグツール Vitestやその他のテストフレームワークを使用してツールをテストできます。ツールの単体テストを作成することで、期待通りの動作を確保し、早期にエラーを発見するのに役立ちます。 ## ツールを使用したエージェントの呼び出し これでエージェントを呼び出すことができ、エージェントはツールを使用して天気情報を取得します。 ## 例:エージェントとの対話 ```typescript filename="src/index.ts" import { mastra } from "./index"; async function main() { const agent = mastra.getAgent("weatherAgent"); const response = await agent.generate( "What's the weather like in New York City today?", ); console.log(response.text); } main(); ``` エージェントは`weatherInfo`ツールを使用して、ニューヨーク市の現在の天気を取得し、それに応じて応答します。 ## Vercel AI SDK ツール形式 Mastraは、Vercel AI SDK形式で作成されたツールをサポートしています。これらのツールを直接インポートして使用できます: ```typescript filename="src/mastra/tools/vercelTool.ts" copy import { tool } from "ai"; import { z } from "zod"; export const weatherInfo = tool({ description: "Fetches the current weather information for a given city", parameters: z.object({ city: z.string().describe("The city to get weather for"), }), execute: async ({ city }) => { // Replace with actual API call const data = await fetch(`https://api.example.com/weather?city=${city}`); return data.json(); }, }); ``` Vercelツールを、Mastraツールと一緒にエージェントで使用できます: ```typescript filename="src/mastra/agents/weatherAgent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { weatherInfo } from "../tools/vercelTool"; import * as mastraTools from "../tools/mastraTools"; export const weatherAgent = new Agent({ name: "Weather Agent", instructions: "You are a helpful assistant that provides weather information.", model: openai("gpt-4"), tools: { weatherInfo, // Vercel tool ...mastraTools, // Mastra tools }, }); ``` どちらのツール形式も、エージェントのワークフロー内でシームレスに動作します。 ## ツール設計のベストプラクティス エージェント用のツールを作成する際、以下のガイドラインに従うことで、信頼性が高く直感的なツールの使用が確保されます: ### ツールの説明 ツールのメイン説明は、その目的と価値に焦点を当てるべきです: - 説明はシンプルに保ち、ツールが**何を**するかに焦点を当てる - ツールの主な使用例を強調する - メインの説明では実装の詳細を避ける - エージェントがツールを**いつ**使用するかを理解するのに役立つことに焦点を当てる ```typescript createTool({ id: "documentSearch", description: "Access the knowledge base to find information needed to answer user questions", // ... rest of tool configuration }); ``` ### パラメータスキーマ 技術的な詳細はパラメータスキーマに属し、エージェントがツールを正しく使用するのに役立ちます: - 明確な説明でパラメータを自己文書化する - デフォルト値とその影響を含める - 役立つ場合は例を提供する - 異なるパラメータ選択の影響を説明する ```typescript inputSchema: z.object({ query: z.string().describe("The search query to find relevant information"), limit: z.number().describe( "Number of results to return. Higher values provide more context, lower values focus on best matches" ), options: z.string().describe( "Optional configuration. Example: '{'filter': 'category=news'}'" ), }), ``` ### エージェントとの相互作用パターン ツールが効果的に使用される可能性が高いのは以下の場合です: - クエリやタスクが、ツールの支援が明らかに必要なほど複雑である - エージェントの指示がツールの使用に関する明確なガイダンスを提供している - パラメータの要件がスキーマに十分に文書化されている - ツールの目的がクエリのニーズに合致している ### よくある落とし穴 - メインの説明に技術的な詳細を詰め込みすぎる - 実装の詳細と使用ガイダンスを混在させる - 不明確なパラメータの説明や例の欠如 これらのプラクティスに従うことで、ツールの目的(メインの説明)と実装の詳細(パラメータスキーマ)の間に明確な区分を維持しながら、エージェントによって発見可能で使いやすいツールを確保するのに役立ちます。 ## Model Context Protocol (MCP) ツール Mastraは`@mastra/mcp`パッケージを通じてMCP互換サーバーからのツールもサポートしています。MCPは、AIモデルが外部ツールやリソースを発見し、相互作用するための標準化された方法を提供します。これにより、カスタム統合を作成することなく、サードパーティのツールをエージェントに簡単に統合できます。 設定オプションやベストプラクティスを含むMCPツールの使用に関する詳細情報については、[MCPガイド](/docs/agents/mcp-guide)をご覧ください。 # エージェントに音声を追加する [JA] Source: https://mastra.ai/ja/docs/agents/adding-voice Mastraエージェントは音声機能で強化することができ、応答を話したりユーザー入力を聞いたりすることができます。エージェントを設定して、単一の音声プロバイダーを使用するか、異なる操作のために複数のプロバイダーを組み合わせることができます。 ## 単一のプロバイダーを使用する エージェントに音声を追加する最も簡単な方法は、発話と聴取の両方に単一のプロバイダーを使用することです: ```typescript import { createReadStream } from "fs"; import path from "path"; import { Agent } from "@mastra/core/agent"; import { OpenAIVoice } from "@mastra/voice-openai"; import { openai } from "@ai-sdk/openai"; // Initialize the voice provider with default settings const voice = new OpenAIVoice(); // Create an agent with voice capabilities export const agent = new Agent({ name: "Agent", instructions: `You are a helpful assistant with both STT and TTS capabilities.`, model: openai("gpt-4o"), voice, }); // The agent can now use voice for interaction const audioStream = await agent.voice.speak("Hello, I'm your AI assistant!", { filetype: "m4a", }); playAudio(audioStream!); try { const transcription = await agent.voice.listen(audioStream); console.log(transcription); } catch (error) { console.error("Error transcribing audio:", error); } ``` ## 複数のプロバイダーを使用する より柔軟性を高めるために、CompositeVoiceクラスを使用して発話と聴取に異なるプロバイダーを使用することができます: ```typescript import { Agent } from "@mastra/core/agent"; import { CompositeVoice } from "@mastra/core/voice"; import { OpenAIVoice } from "@mastra/voice-openai"; import { PlayAIVoice } from "@mastra/voice-playai"; import { openai } from "@ai-sdk/openai"; export const agent = new Agent({ name: "Agent", instructions: `You are a helpful assistant with both STT and TTS capabilities.`, model: openai("gpt-4o"), // Create a composite voice using OpenAI for listening and PlayAI for speaking voice: new CompositeVoice({ input: new OpenAIVoice(), output: new PlayAIVoice(), }), }); ``` ## 音声ストリームの操作 `speak()`と`listen()`メソッドはNode.jsストリームで動作します。以下は音声ファイルを保存および読み込む方法です: ### 音声出力の保存 `speak`メソッドはファイルやスピーカーにパイプできるストリームを返します。 ```typescript import { createWriteStream } from "fs"; import path from "path"; // Generate speech and save to file const audio = await agent.voice.speak("Hello, World!"); const filePath = path.join(process.cwd(), "agent.mp3"); const writer = createWriteStream(filePath); audio.pipe(writer); await new Promise((resolve, reject) => { writer.on("finish", () => resolve()); writer.on("error", reject); }); ``` ### 音声入力の文字起こし `listen`メソッドはマイクやファイルからの音声データのストリームを受け取ります。 ```typescript import { createReadStream } from "fs"; import path from "path"; // Read audio file and transcribe const audioFilePath = path.join(process.cwd(), "/agent.m4a"); const audioStream = createReadStream(audioFilePath); try { console.log("Transcribing audio file..."); const transcription = await agent.voice.listen(audioStream, { filetype: "m4a", }); console.log("Transcription:", transcription); } catch (error) { console.error("Error transcribing audio:", error); } ``` ## 音声対音声の音声インタラクション より動的でインタラクティブな音声体験のために、音声対音声機能をサポートするリアルタイム音声プロバイダーを使用できます: ```typescript import { Agent } from "@mastra/core/agent"; import { getMicrophoneStream } from "@mastra/node-audio"; import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import { search, calculate } from "../tools"; // Initialize the realtime voice provider const voice = new OpenAIRealtimeVoice({ apiKey: process.env.OPENAI_API_KEY, model: "gpt-4o-mini-realtime", speaker: "alloy", }); // Create an agent with speech-to-speech voice capabilities export const agent = new Agent({ name: "Agent", instructions: `You are a helpful assistant with speech-to-speech capabilities.`, model: openai("gpt-4o"), tools: { // Tools configured on Agent are passed to voice provider search, calculate, }, voice, }); // Establish a WebSocket connection await agent.voice.connect(); // Start a conversation agent.voice.speak("Hello, I'm your AI assistant!"); // Stream audio from a microphone const microphoneStream = getMicrophoneStream(); agent.voice.send(microphoneStream); // When done with the conversation agent.voice.close(); ``` ### イベントシステム リアルタイム音声プロバイダーは、リッスンできるいくつかのイベントを発行します: ```typescript // Listen for speech audio data sent from voice provider agent.voice.on("speaking", ({ audio }) => { // audio contains ReadableStream or Int16Array audio data }); // Listen for transcribed text sent from both voice provider and user agent.voice.on("writing", ({ text, role }) => { console.log(`${role} said: ${text}`); }); // Listen for errors agent.voice.on("error", (error) => { console.error("Voice error:", error); }); ``` ## サポートされている音声プロバイダー Mastraは、テキスト読み上げ(TTS)と音声認識(STT)機能のために複数の音声プロバイダーをサポートしています: | プロバイダー | パッケージ | 機能 | リファレンス | | --------------- | ------------------------------- | ------------------------- | ------------------------------------------------- | | OpenAI | `@mastra/voice-openai` | TTS, STT | [ドキュメント](/reference/voice/openai) | | OpenAI Realtime | `@mastra/voice-openai-realtime` | リアルタイム音声対音声 | [ドキュメント](/reference/voice/openai-realtime) | | ElevenLabs | `@mastra/voice-elevenlabs` | 高品質TTS | [ドキュメント](/reference/voice/elevenlabs) | | PlayAI | `@mastra/voice-playai` | TTS | [ドキュメント](/reference/voice/playai) | | Google | `@mastra/voice-google` | TTS, STT | [ドキュメント](/reference/voice/google) | | Deepgram | `@mastra/voice-deepgram` | STT | [ドキュメント](/reference/voice/deepgram) | | Murf | `@mastra/voice-murf` | TTS | [ドキュメント](/reference/voice/murf) | | Speechify | `@mastra/voice-speechify` | TTS | [ドキュメント](/reference/voice/speechify) | | Sarvam | `@mastra/voice-sarvam` | TTS, STT | [ドキュメント](/reference/voice/sarvam) | | Azure | `@mastra/voice-azure` | TTS, STT | [ドキュメント](/reference/voice/mastra-voice) | | Cloudflare | `@mastra/voice-cloudflare` | TTS | [ドキュメント](/reference/voice/mastra-voice) | 音声機能の詳細については、[音声APIリファレンス](/reference/voice/mastra-voice)をご覧ください。 --- title: "エージェントメモリーの使用 | エージェント | Mastra ドキュメント" description: Mastraのエージェントが会話履歴や文脈情報を保存するためにメモリーをどのように使用するかに関するドキュメント。 --- # エージェントメモリー [JA] Source: https://mastra.ai/ja/docs/agents/agent-memory Mastraのエージェントは、会話履歴を保存し、関連情報を思い出し、インタラクション間で永続的なコンテキストを維持するための強力なメモリーシステムを活用できます。これにより、エージェントはより自然でステートフルな会話を行うことができます。 ## エージェントのメモリを有効にする メモリを有効にするには、単に`Memory`クラスをインスタンス化し、エージェントの設定に渡すだけです。また、メモリパッケージとストレージアダプターをインストールする必要があります: ```bash npm2yarn copy npm install @mastra/memory@latest @mastra/libsql@latest ``` ```typescript import { Agent } from "@mastra/core/agent"; import { Memory } from "@mastra/memory"; import { LibSQLStore } from "@mastra/libsql"; import { openai } from "@ai-sdk/openai"; const memory = new Memory({ storage: new LibSQLStore({ url: "file:../../memory.db", }), }); const agent = new Agent({ name: "MyMemoryAgent", instructions: "You are a helpful assistant with memory.", model: openai("gpt-4o"), memory, // Attach the memory instance }); ``` この基本的なセットアップはデフォルト設定を使用しています。より詳細な設定情報については[メモリのドキュメント](/docs/memory/overview)をご覧ください。 ## エージェント呼び出しでのメモリの使用 インタラクション中にメモリを活用するには、エージェントの`stream()`または`generate()`メソッドを呼び出す際に`resourceId`と`threadId`を**必ず**提供する必要があります。 - `resourceId`: 通常、ユーザーまたはエンティティを識別します(例:`user_123`)。 - `threadId`: 特定の会話スレッドを識別します(例:`support_chat_456`)。 ```typescript // メモリを使用したエージェント呼び出しの例 await agent.stream("Remember my favorite color is blue.", { resourceId: "user_alice", threadId: "preferences_thread", }); // 同じスレッドの後で... const response = await agent.stream("What's my favorite color?", { resourceId: "user_alice", threadId: "preferences_thread", }); // エージェントはメモリを使用して好きな色を思い出します。 ``` これらのIDは、会話履歴とコンテキストが適切なユーザーと会話のために正しく保存され、取得されることを保証します。 ## 次のステップ Mastraの[メモリ機能](/docs/memory/overview)をさらに探索して、スレッド、会話履歴、セマンティック検索、ワーキングメモリについて学びましょう。 --- title: "動的エージェント" description: 実行時のコンテキストを使用して、エージェントの指示、モデル、ツールを動的に設定します。 --- # Dynamic Agents [JA] Source: https://mastra.ai/ja/docs/agents/dynamic-agents Dynamic agentsは[ランタイムコンテキスト](./runtime-variables)(ユーザーIDやその他の重要なパラメータなど)を使用して、リアルタイムで設定を調整します。 これにより、使用するモデルを変更したり、指示を更新したり、必要に応じて異なるツールを選択したりできます。 このコンテキストを使用することで、エージェントは各ユーザーのニーズにより適切に対応できます。また、任意のAPIを呼び出してより多くの情報を収集することもでき、エージェントの機能向上に役立ちます。 ### 設定例 以下は、ユーザーのサブスクリプション階層と言語設定に基づいて動作を調整するダイナミックサポートエージェントの例です: ```typescript const supportAgent = new Agent({ name: "Dynamic Support Agent", instructions: async ({ runtimeContext }) => { const userTier = runtimeContext.get("user-tier"); const language = runtimeContext.get("language"); return `You are a customer support agent for our SaaS platform. The current user is on the ${userTier} tier and prefers ${language} language. For ${userTier} tier users: ${userTier === "free" ? "- Provide basic support and documentation links" : ""} ${userTier === "pro" ? "- Offer detailed technical support and best practices" : ""} ${userTier === "enterprise" ? "- Provide priority support with custom solutions" : ""} Always respond in ${language} language.`; }, model: ({ runtimeContext }) => { const userTier = runtimeContext.get("user-tier"); return userTier === "enterprise" ? openai("gpt-4") : openai("gpt-3.5-turbo"); }, tools: ({ runtimeContext }) => { const userTier = runtimeContext.get("user-tier"); const baseTools = [knowledgeBase, ticketSystem]; if (userTier === "pro" || userTier === "enterprise") { baseTools.push(advancedAnalytics); } if (userTier === "enterprise") { baseTools.push(customIntegration); } return baseTools; }, }); ``` この例では、エージェントは以下のことを行います: - ユーザーのサブスクリプション階層(free、pro、またはenterprise)に基づいて指示を調整 - enterpriseユーザーに対してより強力なモデル(GPT-4)を使用 - ユーザーの階層に基づいて異なるツールセットを提供 - ユーザーの希望する言語で応答 これは、単一のエージェントがランタイムコンテキストを活用することで、異なるタイプのユーザーやシナリオを処理できることを示しており、各ユースケースに対して個別のエージェントを作成するよりも柔軟で保守しやすくなります。 APIルート、ミドルウェア設定、ランタイムコンテキスト処理を含む完全な実装例については、[Dynamic Agents Example](/examples/agents/dynamic-agents)をご覧ください。 --- title: "MCPをMastraで使用する | エージェント | Mastraドキュメント" description: "MastraでMCPを使用して、AIエージェントにサードパーティのツールやリソースを統合します。" --- # Mastraでのモデルコンテキストプロトコル(MCP)の使用 [JA] Source: https://mastra.ai/ja/docs/agents/mcp-guide [モデルコンテキストプロトコル(MCP)](https://modelcontextprotocol.io/introduction)は、AIモデルが外部ツールやリソースを発見し、相互作用するための標準化された方法です。 ## 概要 MastraのMCPは、ツールサーバーに接続するための標準化された方法を提供します。StdioとHTTP(Streamable HTTPをサポートし、SSEにフォールバック)をサポートしています。 ## インストール pnpmを使用する場合: ```bash pnpm add @mastra/mcp@latest ``` npmを使用する場合: ```bash copy npm install @mastra/mcp@latest ``` ## コード内でMCPを使用する `MCPClient`クラスは、複数のMCPクライアントを管理することなく、Mastraアプリケーションで複数のツールサーバーを管理する方法を提供します。`MCPConfiguration`内部で使用される`MastraMCPClient`は、サーバー設定に基づいてトランスポートタイプを自動的に検出するようになりました: - `command`を提供する場合、Stdioトランスポートを使用します。 - `url`を提供する場合、最初にStreamable HTTPトランスポートを試み、初期接続が失敗した場合はレガシーSSEトランスポートにフォールバックします。 以下は設定例です: ```typescript import { MCPClient } from "@mastra/mcp"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const mcp = new MCPClient({ servers: { // Stdio例 sequential: { command: "npx", args: ["-y", "@modelcontextprotocol/server-sequential-thinking"], }, // HTTP例(最初にStreamable HTTPを試み、その後SSEにフォールバック) weather: { url: new URL("http://localhost:8080/mcp"), // Streamable HTTPのベースURLを使用 requestInit: { headers: { Authorization: "Bearer your-token", }, }, }, }, }); ``` ### ツールとツールセット `MCPClient`クラスはMCPツールにアクセスするための2つの方法を提供しており、それぞれ異なるユースケースに適しています: #### ツールの使用(`getTools()`) 以下の場合にこのアプローチを使用します: - 単一のMCP接続がある場合 - ツールが単一のユーザー/コンテキストによって使用される場合 - ツール設定(APIキー、認証情報)が一定の場合 - 固定されたツールセットでAgentを初期化したい場合 ```typescript const agent = new Agent({ name: "CLI Assistant", instructions: "You help users with CLI tasks", model: openai("gpt-4o-mini"), tools: await mcp.getTools(), // ツールはエージェント作成時に固定される }); ``` #### ツールセットの使用(`getToolsets()`) 以下の場合にこのアプローチを使用します: - リクエストごとのツール設定が必要な場合 - ツールがユーザーごとに異なる認証情報を必要とする場合 - マルチユーザー環境(Webアプリ、APIなど)で実行する場合 - ツール設定を動的に変更する必要がある場合 ```typescript const mcp = new MCPClient({ servers: { example: { command: "npx", args: ["-y", "@example/fakemcp"], env: { API_KEY: "your-api-key", }, }, }, }); // このユーザー用に設定された現在のツールセットを取得 const toolsets = await mcp.getToolsets(); // ユーザー固有のツール設定でエージェントを使用 const response = await agent.stream( "Mastraの新機能は何ですか?また、天気はどうですか?", { toolsets, }, ); ``` ## MCP レジストリ MCPサーバーは、キュレーションされたツールコレクションを提供するレジストリを通じてアクセスできます。 私たちは、最適なMCPサーバーの調達先を見つけるのに役立つ[MCP レジストリ レジストリ](https://mastra.ai/mcp-registry-registry)をキュレーションしていますが、以下では私たちのお気に入りのいくつかからツールを使用する方法を説明します: ### mcp.run レジストリ [mcp.run](https://www.mcp.run/)を使用すると、事前認証された安全なMCPサーバーを簡単に呼び出すことができます。mcp.runのツールは無料で、完全に管理されているため、エージェントはSSE URLだけを必要とし、ユーザーがインストールしたどのツールでも使用できます。MCPサーバーは[プロファイル](https://docs.mcp.run/user-guide/manage-profiles)にグループ化され、固有のSSE URLでアクセスされます。 各プロファイルについて、署名付きの固有のURLをコピー/ペーストして、次のように`MCPClient`に入力できます: ```typescript const mcp = new MCPClient({ servers: { marketing: { url: new URL(process.env.MCP_RUN_SSE_URL!), }, }, }); ``` > 重要:[mcp.run](https://mcp.run)の各SSE URLには、パスワードのように扱うべき固有の署名が含まれています。SSE URLを環境変数として読み込み、アプリケーションコードの外部で管理するのがベストです。 ```bash filename=".env" copy MCP_RUN_SSE_URL=https://www.mcp.run/api/mcp/sse?nonce=... ``` ### Composio.dev レジストリ [Composio.dev](https://composio.dev)は、Mastraと簡単に統合できる[SSEベースのMCPサーバー](https://mcp.composio.dev)のレジストリを提供しています。Cursor用に生成されるSSE URLはMastraと互換性があり、設定で直接使用できます: ```typescript const mcp = new MCPClient({ servers: { googleSheets: { url: new URL("https://mcp.composio.dev/googlesheets/[private-url-path]"), }, gmail: { url: new URL("https://mcp.composio.dev/gmail/[private-url-path]"), }, }, }); ``` Composio提供のツールを使用する場合、エージェントとの会話を通じて直接サービス(Google SheetsやGmailなど)で認証できます。ツールには認証機能が含まれており、チャット中にプロセスをガイドします。 注意:Composio.devの統合は、SSE URLがあなたのアカウントに紐づけられており、複数のユーザーには使用できないため、個人的な自動化などの単一ユーザーシナリオに最適です。各URLは単一アカウントの認証コンテキストを表します。 ### Smithery.ai レジストリ [Smithery.ai](https://smithery.ai)はMastraで簡単に使用できるMCPサーバーのレジストリを提供しています: ```typescript // Unix/Mac const mcp = new MCPClient({ servers: { sequentialThinking: { command: "npx", args: [ "-y", "@smithery/cli@latest", "run", "@smithery-ai/server-sequential-thinking", "--config", "{}", ], }, }, }); // Windows const mcp = new MCPClient({ servers: { sequentialThinking: { command: "cmd", args: [ "/c", "npx", "-y", "@smithery/cli@latest", "run", "@smithery-ai/server-sequential-thinking", "--config", "{}", ], }, }, }); ``` この例は、Smitheryドキュメントのクロード統合例から適応されています。 ## MCPサーバーでツールを除外する MCPサーバーからのツールは、`await mcp.getTools()`または`await mcp.getToolsets()`を呼び出すと、プレーンなJavaScriptオブジェクトとして返されます。これにより、エージェントに渡す前にツールを簡単にフィルタリングしたり除外したりすることができます。 ### ツール除外の例 MCPサーバーが3つのツール(`weather`、`stockPrice`、`news`)を公開しているが、エージェントから`news`ツールを除外したい場合を考えてみましょう。ツールオブジェクトをフィルタリングすることでこれを実現できます: ```typescript import { MCPClient } from "@mastra/mcp"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const mcp = new MCPClient({ servers: { myServer: { command: "npx", args: ["tsx", "my-mcp-server.ts"], }, }, }); // MCPサーバーからすべてのツールを取得 const allTools = await mcp.getTools(); // 'news'ツールを除外(ツール名は'serverName_toolName'の形式で名前空間が設定されています) const filteredTools = Object.fromEntries( Object.entries(allTools).filter(([toolName]) => toolName !== "myServer_news"), ); // フィルタリングされたツールのみをエージェントに渡す const agent = new Agent({ name: "Selective Agent", instructions: "You can access only selected tools.", model: openai("gpt-4"), tools: filteredTools, }); ``` `.filter()`関数内で任意のロジックを使用して、名前、タイプ、またはその他のプロパティによってツールを除外できます。このアプローチは、リクエストごとにツールセットを動的にフィルタリングしたい場合の`getToolsets()`でも同様に機能します。 もう一つのアプローチは、使用したいツールを分割代入するか、使用したくないツールを除外することです。 ```typescript // 分割代入したオブジェクトから不要なツールを削除 const { myServer_news, ...filteredTools } = await mcp.getTools(); // フィルタリングされたツールのみをエージェントに渡す const agent = new Agent({ name: "Selective Agent", instructions: "You can access only selected tools.", model: openai("gpt-4"), tools: filteredTools, }); ``` ```typescript // 分割代入したオブジェクトから必要なツールを選択 const { myServer_weather, myServer_stockPrice } = await mcp.getTools(); // 選択したツールのみをエージェントに渡す const agent = new Agent({ name: "Selective Agent", instructions: "You can access only selected tools.", model: openai("gpt-4"), tools: { myServer_weather, myServer_stockPrice }, }); ``` この例は、Smitheryドキュメントのクロード統合例から適応されています。 ```typescript // Unix/Mac const mcp = new MCPConfiguration({ servers: { sequentialThinking: { command: "npx", args: [ "-y", "@smithery/cli@latest", "run", "@smithery-ai/server-sequential-thinking", "--config", "{}", ], }, }, }); // Windows const mcp = new MCPConfiguration({ servers: { sequentialThinking: { command: "cmd", args: [ "/c", "npx", "-y", "@smithery/cli@latest", "run", "@smithery-ai/server-sequential-thinking", "--config", "{}", ], }, }, }); ``` この例は、Smitheryドキュメントのクロード統合例から適応されています。 --- title: "エージェントの作成と呼び出し | エージェントドキュメンテーション | Mastra" description: Mastraにおけるエージェントの概要、その機能とツール、ワークフロー、外部システムとの連携方法の詳細。 --- # エージェントの作成と呼び出し [JA] Source: https://mastra.ai/ja/docs/agents/overview Mastraのエージェントは、言語モデルがタスクを実行するために一連のアクションを自律的に決定できるシステムです。エージェントはツール、ワークフロー、同期されたデータにアクセスでき、複雑なタスクを実行し、外部システムと対話することができます。エージェントはカスタム関数を呼び出したり、インテグレーションを通じてサードパーティAPIを利用したり、構築した知識ベースにアクセスしたりすることができます。 エージェントは、継続的なプロジェクトに使用できる従業員のようなものです。彼らには名前、永続的なメモリ、一貫したモデル構成、呼び出し間での一貫した指示、そして有効化されたツールのセットがあります。 ## 1. エージェントの作成 Mastraでエージェントを作成するには、`Agent`クラスを使用してそのプロパティを定義します: ```ts showLineNumbers filename="src/mastra/agents/index.ts" copy import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; export const myAgent = new Agent({ name: "My Agent", instructions: "You are a helpful assistant.", model: openai("gpt-4o-mini"), }); ``` **注意:** OpenAI APIキーなどの必要な環境変数を`.env`ファイルに設定していることを確認してください: ```.env filename=".env" copy OPENAI_API_KEY=your_openai_api_key ``` また、`@mastra/core`パッケージがインストールされていることを確認してください: ```bash npm2yarn copy npm install @mastra/core@latest ``` ### エージェントの登録 エージェントをMastraに登録して、ロギングや設定されたツールと統合へのアクセスを有効にします: ```ts showLineNumbers filename="src/mastra/index.ts" copy import { Mastra } from "@mastra/core"; import { myAgent } from "./agents"; export const mastra = new Mastra({ agents: { myAgent }, }); ``` ## 2. テキストの生成とストリーミング ### テキストの生成 エージェントにテキスト応答を生成させるには、`.generate()`メソッドを使用します: ```ts showLineNumbers filename="src/mastra/index.ts" copy const response = await myAgent.generate([ { role: "user", content: "Hello, how can you assist me today?" }, ]); console.log("Agent:", response.text); ``` generateメソッドとそのオプションの詳細については、[generate リファレンスドキュメント](/reference/agents/generate)を参照してください。 ### レスポンスのストリーミング よりリアルタイムなレスポンスを得るには、エージェントのレスポンスをストリーミングできます: ```ts showLineNumbers filename="src/mastra/index.ts" copy const stream = await myAgent.stream([ { role: "user", content: "Tell me a story." }, ]); console.log("Agent:"); for await (const chunk of stream.textStream) { process.stdout.write(chunk); } ``` ストリーミングレスポンスの詳細については、[stream リファレンスドキュメント](/reference/agents/stream)を参照してください。 ## 3. 構造化された出力 エージェントはJSONスキーマまたはZodスキーマを提供することで、構造化されたデータを返すことができます。 ### JSONスキーマの使用 ```typescript const schema = { type: "object", properties: { summary: { type: "string" }, keywords: { type: "array", items: { type: "string" } }, }, additionalProperties: false, required: ["summary", "keywords"], }; const response = await myAgent.generate( [ { role: "user", content: "Please provide a summary and keywords for the following text: ...", }, ], { output: schema, }, ); console.log("Structured Output:", response.object); ``` ### Zodの使用 型安全な構造化出力のためにZodスキーマを使用することもできます。 まず、Zodをインストールします: ```bash npm2yarn copy npm install zod ``` 次に、Zodスキーマを定義してエージェントで使用します: ```ts showLineNumbers filename="src/mastra/index.ts" copy import { z } from "zod"; // Define the Zod schema const schema = z.object({ summary: z.string(), keywords: z.array(z.string()), }); // Use the schema with the agent const response = await myAgent.generate( [ { role: "user", content: "Please provide a summary and keywords for the following text: ...", }, ], { output: schema, }, ); console.log("Structured Output:", response.object); ``` ### ツールの使用 ツール呼び出しと一緒に構造化された出力を生成する必要がある場合は、`output`の代わりに`experimental_output`プロパティを使用する必要があります。方法は次のとおりです: ```typescript const schema = z.object({ summary: z.string(), keywords: z.array(z.string()), }); const response = await myAgent.generate( [ { role: "user", content: "Please analyze this repository and provide a summary and keywords...", }, ], { // Use experimental_output to enable both structured output and tool calls experimental_output: schema, }, ); console.log("Structured Output:", response.object); ```
これにより、エージェントから返される構造化データに対して強力な型付けと検証を行うことができます。 ## 4. マルチステップツール使用エージェント エージェントはツールで強化することができます。ツールは、テキスト生成を超えてエージェントの機能を拡張する関数です。ツールにより、エージェントは計算を実行し、外部システムにアクセスし、データを処理することができます。ツールの作成と設定の詳細については、[ツールの追加ドキュメント](/docs/agents/using-tools-and-mcp)を参照してください。 ### maxStepsの使用 `maxSteps`パラメータは、エージェントが実行できる連続したLLM呼び出しの最大数を制御します。これは特にツール呼び出しを使用する際に重要です。デフォルトでは、設定が間違ったツールによる無限ループを防ぐために1に設定されています。使用ケースに基づいてこの制限を増やすことができます: ```ts showLineNumbers filename="src/mastra/agents/index.ts" copy import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import * as mathjs from "mathjs"; import { z } from "zod"; export const myAgent = new Agent({ name: "My Agent", instructions: "You are a helpful assistant that can solve math problems.", model: openai("gpt-4o-mini"), tools: { calculate: { description: "Calculator for mathematical expressions", schema: z.object({ expression: z.string() }), execute: async ({ expression }) => mathjs.evaluate(expression), }, }, }); const response = await myAgent.generate( [ { role: "user", content: "If a taxi driver earns $9461 per hour and works 12 hours a day, how much do they earn in one day?", }, ], { maxSteps: 5, // Allow up to 5 tool usage steps }, ); ``` ### onStepFinishの使用 `onStepFinish`コールバックを使用して、マルチステップ操作の進行状況を監視できます。これはデバッグやユーザーへの進行状況の更新に役立ちます。 `onStepFinish`は、ストリーミング時または構造化出力なしでテキストを生成する際にのみ利用可能です。 ```ts showLineNumbers filename="src/mastra/agents/index.ts" copy const response = await myAgent.generate( [{ role: "user", content: "Calculate the taxi driver's daily earnings." }], { maxSteps: 5, onStepFinish: ({ text, toolCalls, toolResults }) => { console.log("Step completed:", { text, toolCalls, toolResults }); }, }, ); ``` ### onFinishの使用 `onFinish`コールバックは、レスポンスをストリーミングする際に利用可能で、完了したインタラクションに関する詳細情報を提供します。これは、LLMがレスポンスの生成を完了し、すべてのツール実行が完了した後に呼び出されます。 このコールバックは、最終的なレスポンステキスト、実行ステップ、トークン使用統計、および監視とログ記録に役立つその他のメタデータを受け取ります: ```ts showLineNumbers filename="src/mastra/agents/index.ts" copy const stream = await myAgent.stream( [{ role: "user", content: "Calculate the taxi driver's daily earnings." }], { maxSteps: 5, onFinish: ({ steps, text, finishReason, // 'complete', 'length', 'tool', etc. usage, // token usage statistics reasoningDetails, // additional context about the agent's decisions }) => { console.log("Stream complete:", { totalSteps: steps.length, finishReason, usage, }); }, }, ); ``` ## 5. エージェントの実行 Mastraは、エージェントをAPIの背後で実行するための`mastra dev`というCLIコマンドを提供しています。デフォルトでは、`src/mastra/agents`ディレクトリ内のファイルでエクスポートされたエージェントを探します。 ### サーバーの起動 ```bash mastra dev ``` これによりサーバーが起動し、エージェントは`http://localhost:4111/api/agents/myAgent/generate`で利用可能になります。 ### エージェントとの対話 コマンドラインから`curl`を使用してエージェントと対話できます: ```bash curl -X POST http://localhost:4111/api/agents/myAgent/generate \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "role": "user", "content": "Hello, how can you assist me today?" } ] }' ``` ## 次のステップ - [エージェントメモリ](./agent-memory.mdx)ガイドでエージェントメモリについて学びましょう。 - [エージェントツールとMCP](./using-tools-and-mcp.mdx)ガイドでエージェントツールについて学びましょう。 - [シェフ・ミシェル](../../guides/guide/chef-michel.mdx)の例でエージェントの例を確認しましょう。 --- title: "ランタイムコンテキスト | エージェント | Mastra ドキュメント" description: Mastraの依存性注入システムを使用して、エージェントとツールにランタイム設定を提供する方法を学びます。 --- # エージェントランタイムコンテキスト [JA] Source: https://mastra.ai/ja/docs/agents/runtime-variables Mastraはランタイムコンテキストを提供します。これは依存性注入に基づくシステムで、エージェントとツールをランタイム変数で設定することを可能にします。非常に似たことを行う複数の異なるエージェントを作成している場合、ランタイムコンテキストを使用すると、それらを1つのエージェントに統合することができます。 ## 概要 依存性注入システムにより、以下のことが可能になります: 1. 型安全なruntimeContextを通じて、実行時の設定変数をエージェントに渡す 2. ツール実行コンテキスト内でこれらの変数にアクセスする 3. 基盤となるコードを変更せずにエージェントの動作を修正する 4. 同じエージェント内の複数のツール間で設定を共有する ## 基本的な使い方 ```typescript const agent = mastra.getAgent("weatherAgent"); // Define your runtimeContext's type structure type WeatherRuntimeContext = { "temperature-scale": "celsius" | "fahrenheit"; // Fixed typo in "fahrenheit" }; const runtimeContext = new RuntimeContext(); runtimeContext.set("temperature-scale", "celsius"); const response = await agent.generate("What's the weather like today?", { runtimeContext, }); console.log(response.text); ``` ## REST APIでの使用 ユーザーの位置情報に基づいて温度単位を動的に設定する方法を、Cloudflareの`CF-IPCountry`ヘッダーを使用して示します: ```typescript filename="src/index.ts" import { Mastra } from "@mastra/core"; import { RuntimeContext } from "@mastra/core/di"; import { agent as weatherAgent } from "./agents/weather"; // Define RuntimeContext type with clear, descriptive types type WeatherRuntimeContext = { "temperature-scale": "celsius" | "fahrenheit"; }; export const mastra = new Mastra({ agents: { weather: weatherAgent, }, server: { middleware: [ async (c, next) => { const country = c.req.header("CF-IPCountry"); const runtimeContext = c.get("runtimeContext"); // Set temperature scale based on country runtimeContext.set( "temperature-scale", country === "US" ? "fahrenheit" : "celsius", ); await next(); // Don't forget to call next() }, ], }, }); ``` ## 変数を使用したツールの作成 ツールはruntimeContext変数にアクセスでき、エージェントのruntimeContextタイプに準拠する必要があります: ```typescript import { createTool } from "@mastra/core/tools"; import { z } from "zod"; export const weatherTool = createTool({ id: "getWeather", description: "Get the current weather for a location", inputSchema: z.object({ location: z.string().describe("The location to get weather for"), }), execute: async ({ context, runtimeContext }) => { // Type-safe access to runtimeContext variables const temperatureUnit = runtimeContext.get("temperature-scale"); const weather = await fetchWeather(context.location, { temperatureUnit, }); return { result: weather }; }, }); async function fetchWeather( location: string, { temperatureUnit }: { temperatureUnit: "celsius" | "fahrenheit" }, ): Promise { // Implementation of weather API call const response = await weatherApi.fetch(location, temperatureUnit); return { location, temperature: "72°F", conditions: "Sunny", unit: temperatureUnit, }; } ``` --- title: "エージェントでのツールの使用 | エージェント | Mastra ドキュメント" description: ツールの作成方法、Mastraエージェントへの追加方法、およびMCPサーバーからのツールの統合方法について学びます。 --- # エージェントでツールを使用する [JA] Source: https://mastra.ai/ja/docs/agents/using-tools-and-mcp ツールは、エージェントやワークフローによって実行できる型付き関数です。各ツールには、その入力を定義するスキーマ、ロジックを実装する実行関数、およびオプションで設定された統合へのアクセスがあります。 ## ツールの作成 以下はツールを作成する基本的な例です: ```typescript filename="src/mastra/tools/weatherInfo.ts" copy import { createTool } from "@mastra/core/tools"; import { z } from "zod"; export const weatherInfo = createTool({ id: "Get Weather Information", inputSchema: z.object({ city: z.string(), }), description: `Fetches the current weather information for a given city`, execute: async ({ context: { city } }) => { // Tool logic here (e.g., API call) console.log("Using tool to fetch weather information for", city); return { temperature: 20, conditions: "Sunny" }; // Example return }, }); ``` ツールの作成と設計の詳細については、[ツールの概要](/docs/tools-mcp/overview)をご覧ください。 ## エージェントにツールを追加する ツールをエージェントで利用可能にするには、エージェントの設定の `tools` プロパティに追加します。 ```typescript filename="src/mastra/agents/weatherAgent.ts" {3,11} import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { weatherInfo } from "../tools/weatherInfo"; export const weatherAgent = new Agent({ name: "Weather Agent", instructions: "You are a helpful assistant that provides current weather information. When asked about the weather, use the weather information tool to fetch the data.", model: openai("gpt-4o-mini"), tools: { weatherInfo, }, }); ``` エージェントを呼び出すと、設定されたツールを指示内容とユーザーのプロンプトに基づいて使用するかどうかを判断できるようになります。 ## エージェントにMCPツールを追加する [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction)は、AIモデルが外部ツールやリソースを発見し、相互作用するための標準化された方法を提供します。Mastraエージェントをサードパーティが提供するツールを使用するためにMCPサーバーに接続することができます。 MCPの概念やMCPクライアントとサーバーの設定方法の詳細については、[MCP概要](/docs/tools-mcp/mcp-overview)をご覧ください。 ### インストール まず、Mastra MCPパッケージをインストールします: ```bash npm2yarn copy npm install @mastra/mcp@latest ``` ### MCPツールの使用 選択肢が多すぎるMCPサーバーレジストリから選ぶのを助けるために、[MCP Registry Registry](https://mastra.ai/mcp-registry-registry)を作成しました。 エージェントで使用したいサーバーが見つかったら、Mastraの`MCPClient`をインポートしてサーバー設定を追加します。 ```typescript filename="src/mastra/mcp.ts" {1,7-16} import { MCPClient } from "@mastra/mcp"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // Configure MCPClient to connect to your server(s) export const mcp = new MCPClient({ servers: { filesystem: { command: "npx", args: [ "-y", "@modelcontextprotocol/server-filesystem", "/Users/username/Downloads", ], }, }, }); ``` 次に、エージェントをサーバーツールに接続します: ```typescript filename="src/mastra/agents/mcpAgent.ts" {7} import { mcp } from "../mcp"; // Create an agent and add tools from the MCP client const agent = new Agent({ name: "Agent with MCP Tools", instructions: "You can use tools from connected MCP servers.", model: openai("gpt-4o-mini"), tools: await mcp.getTools(), }); ``` `MCPClient`の設定や静的および動的MCPサーバー設定の違いについての詳細は、[MCP概要](/docs/tools-mcp/mcp-overview)をご覧ください。 ## MCP リソースへのアクセス ツールに加えて、MCPサーバーはリソース(アプリケーションで取得・使用できるデータやコンテンツ)も公開できます。 ```typescript filename="src/mastra/resources.ts" {3-8} import { mcp } from "./mcp"; // Get resources from all connected MCP servers const resources = await mcp.getResources(); // Access resources from a specific server if (resources.filesystem) { const resource = resources.filesystem.find( (r) => r.uri === "filesystem://Downloads", ); console.log(`Resource: ${resource?.name}`); } ``` 各リソースには、URI、名前、説明、MIMEタイプがあります。`getResources()`メソッドはエラーを適切に処理します - サーバーが失敗したり、リソースをサポートしていない場合、結果から除外されます。 ## MCP プロンプトへのアクセス MCP サーバーはプロンプトも公開できます。プロンプトは、エージェント向けの構造化されたメッセージテンプレートや会話コンテキストを表します。 ### プロンプトの一覧表示 ```typescript filename="src/mastra/prompts.ts" import { mcp } from "./mcp"; // 接続されているすべての MCP サーバーからプロンプトを取得 const prompts = await mcp.prompts.list(); // 特定のサーバーからプロンプトにアクセス if (prompts.weather) { const prompt = prompts.weather.find( (p) => p.name === "current" ); console.log(`Prompt: ${prompt?.name}`); } ``` 各プロンプトには名前、説明、および(オプションの)バージョンがあります。 ### プロンプトとそのメッセージの取得 ```typescript filename="src/mastra/prompts.ts" const { prompt, messages } = await mcp.prompts.get({ serverName: "weather", name: "current" }); console.log(prompt); // { name: "current", version: "v1", ... } console.log(messages); // [ { role: "assistant", content: { type: "text", text: "..." } }, ... ] ``` ## MCPServerを介してAgentをToolとして公開する MCPサーバーからツールを使用することに加えて、あなたのMastra Agent自体をMastraの`MCPServer`を使用して任意のMCP互換クライアントにツールとして公開することができます。 `Agent`インスタンスが`MCPServer`の設定に提供されると: - 自動的に呼び出し可能なツールに変換されます。 - ツールは`ask_`という名前になります。ここで``は、`MCPServer`の`agents`設定にエージェントを追加する際に使用した識別子です。 - エージェントの`description`プロパティ(空でない文字列である必要があります)がツールの説明を生成するために使用されます。 これにより、他のAIモデルやMCPクライアントが、あなたのMastra Agentを標準的なツールであるかのように、通常は質問を「尋ねる」ことで対話できるようになります。 **Agentを含む`MCPServer`設定の例:** ```typescript filename="src/mastra/mcp.ts" import { Agent } from "@mastra/core/agent"; import { MCPServer } from "@mastra/mcp"; import { openai } from "@ai-sdk/openai"; import { weatherInfo } from "../tools/weatherInfo"; import { generalHelper } from "../agents/generalHelper"; const server = new MCPServer({ name: "My Custom Server with Agent-Tool", version: "1.0.0", tools: { weatherInfo, }, agents: { generalHelper }, // 'ask_generalHelper'ツールを公開 }); ``` エージェントが`MCPServer`によってツールに正常に変換されるためには、そのコンストラクタ設定で`description`プロパティが空でない文字列に設定されている必要があります。説明が欠けているか空の場合、`MCPServer`は初期化中にエラーをスローします。 `MCPServer`の設定と構成の詳細については、[MCPServerリファレンスドキュメント](/reference/tools/mcp-server)を参照してください。 --- title: "MastraClient" description: "Mastra Client SDKの設定と使用方法を学ぶ" --- # Mastra Client SDK [JA] Source: https://mastra.ai/ja/docs/client-js/overview Mastra Client SDKは、クライアント環境から[Mastra Server](/docs/deployment/server)とやり取りするためのシンプルで型安全なインターフェースを提供します。 ## 開発要件 スムーズなローカル開発を確保するために、以下が必要です: - Node.js 18.x以降がインストールされていること - TypeScript 4.7+(TypeScriptを使用する場合) - Fetch APIをサポートするモダンなブラウザ環境 - ローカルのMastraサーバーが実行されていること(通常はポート4111) ## インストール import { Tabs } from "nextra/components"; {/* LLM CONTEXT: This Tabs component shows installation commands for the Mastra Client SDK using different package managers. Each tab displays the installation command for that specific package manager (npm, yarn, pnpm). This helps users install the client SDK with their preferred package manager. All commands install the same @mastra/client-js package but use different package manager syntax. */} ```bash copy npm install @mastra/client-js@latest ``` ```bash copy yarn add @mastra/client-js@latest ``` ```bash copy pnpm add @mastra/client-js@latest ``` ## Mastra Clientの初期化 開始するには、必要なパラメータでMastraClientを初期化する必要があります: ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient({ baseUrl: "http://localhost:4111", // Default Mastra development server port }); ``` ### 設定オプション 様々なオプションでクライアントをカスタマイズできます: ```typescript const client = new MastraClient({ // Required baseUrl: "http://localhost:4111", // Optional configurations for development retries: 3, // Number of retry attempts backoffMs: 300, // Initial retry backoff time maxBackoffMs: 5000, // Maximum retry backoff time headers: { // Custom headers for development "X-Development": "true", }, }); ``` ## 例 MastraClientが初期化されたら、型安全なインターフェースを通じてクライアント呼び出しを開始できます ```typescript // Get a reference to your local agent const agent = client.getAgent("dev-agent-id"); // Generate responses const response = await agent.generate({ messages: [ { role: "user", content: "Hello, I'm testing the local development setup!", }, ], }); ``` ## 利用可能な機能 Mastraクライアントは、Mastra Serverによって提供されるすべてのリソースを公開します - [**Agents**](/reference/client-js/agents): AIエージェントの作成と管理、レスポンスの生成、ストリーミングインタラクションの処理 - [**Memory**](/reference/client-js/memory): 会話スレッドとメッセージ履歴の管理 - [**Tools**](/reference/client-js/tools): エージェントが利用可能なツールへのアクセスと実行 - [**Workflows**](/reference/client-js/workflows): 自動化されたワークフローの作成と管理 - [**Vectors**](/reference/client-js/vectors): セマンティック検索と類似性マッチングのためのベクトル操作の処理 ## ベストプラクティス 1. **エラーハンドリング**: 開発シナリオに対して適切なエラーハンドリングを実装する 2. **環境変数**: 設定には環境変数を使用する 3. **デバッグ**: 必要に応じて詳細なログ記録を有効にする ```typescript // Example with error handling and logging try { const agent = client.getAgent("dev-agent-id"); const response = await agent.generate({ messages: [{ role: "user", content: "Test message" }], }); console.log("Response:", response); } catch (error) { console.error("Development error:", error); } ``` ## Debug - サーバー側でMastraClientを使用する際(例:`/api/chat`)、クライアント側ではなく、 クライアントへのレスポンスを再作成する必要がある場合があります: ```typescript const result = agent.stream(/* get your agent stream */); return new Response(result.body); ``` --- title: "Discord コミュニティとボット | ドキュメント | Mastra" description: Mastra Discord コミュニティと MCP ボットに関する情報。 --- # Discordコミュニティ [JA] Source: https://mastra.ai/ja/docs/community/discord Discordサーバーには1000人以上のメンバーがおり、Mastraの主要な議論の場として機能しています。Mastraチームは北米とヨーロッパの営業時間中にDiscordを監視しており、他のタイムゾーンではコミュニティメンバーが活動しています。[Discordサーバーに参加する](https://discord.gg/BTYqqHKUrf)。 ## Discord MCP ボット コミュニティメンバーに加えて、質問に答えるのを手伝う(実験的な!)Discordボットもあります。これは[Model Context Protocol (MCP)](/docs/agents/mcp-guide)を使用しています。`/ask`で質問することができ(公開チャンネルまたはDMで)、DMでのみ`/cleardm`で履歴をクリアすることができます。 --- title: "ライセンス" description: "Mastraライセンス" --- # ライセンス [JA] Source: https://mastra.ai/ja/docs/community/licensing ## Elastic License 2.0 (ELv2) Mastraは、オープンソースの原則と持続可能なビジネス慣行のバランスを取るために設計された現代的なライセンスであるElastic License 2.0(ELv2)の下でライセンスされています。 ### Elastic License 2.0とは? Elastic License 2.0は、ソースアベイラブルライセンスであり、プロジェクトの持続可能性を保護するための特定の制限を含みながら、ユーザーにソフトウェアの使用、修正、配布に関する広範な権利を付与します。以下が許可されています: - ほとんどの目的での無料使用 - ソースコードの閲覧、修正、再配布 - 派生作品の作成と配布 - 組織内での商用利用 主な制限は、ユーザーにソフトウェアの実質的な機能へのアクセスを提供するホスト型または管理型サービスとしてMastraを提供することはできないということです。 ### なぜElastic License 2.0を選んだのか 私たちがElastic License 2.0を選んだ重要な理由はいくつかあります: 1. **持続可能性**:オープン性と長期的な開発を維持する能力とのバランスを健全に保つことができます。 2. **イノベーション保護**:私たちの作業が競合するサービスとして再パッケージ化されることを懸念せずに、イノベーションへの投資を継続できることを保証します。 3. **コミュニティ重視**:コミュニティをサポートする能力を保護しながら、ユーザーが私たちのコードを閲覧、修正、学習することを可能にすることで、オープンソースの精神を維持します。 4. **ビジネスの明確性**:Mastraが商業的な文脈でどのように使用できるかについての明確なガイドラインを提供します。 ### Mastraでビジネスを構築する ライセンスの制限にもかかわらず、Mastraを使用して成功するビジネスを構築する方法は数多くあります: #### 許可されているビジネスモデル - **アプリケーションの構築**:Mastraで構築されたアプリケーションを作成して販売する - **コンサルティングサービスの提供**:専門知識、実装、カスタマイズサービスを提供する - **カスタムソリューションの開発**:Mastraを使用してクライアント向けのカスタムAIソリューションを構築する - **アドオンと拡張機能の作成**:Mastraの機能を拡張する補完的なツールを開発して販売する - **トレーニングと教育**:Mastraを効果的に使用するためのコースや教育資料を提供する #### 準拠した使用例 - 企業がMastraを使用してAI駆動のカスタマーサービスアプリケーションを構築し、クライアントに販売する - コンサルティング会社がMastraの実装とカスタマイズサービスを提供する - 開発者がMastraで特殊なエージェントとツールを作成し、他のビジネスにライセンス供与する - スタートアップがMastraを活用した特定の業界向けソリューション(例:ヘルスケアAIアシスタント)を構築する #### 避けるべきこと 主な制限は、ユーザーがその中核機能にアクセスできるホスト型サービスとしてMastra自体を提供することはできないということです。これは以下を意味します: - 最小限の修正を加えただけの実質的にMastraであるSaaSプラットフォームを作成しないでください - 顧客が主にMastraの機能を使用するために支払う管理型Mastraサービスを提供しないでください ### ライセンスに関する質問がありますか? Elastic License 2.0があなたのユースケースにどのように適用されるかについて具体的な質問がある場合は、明確化のために[Discordでお問い合わせください](https://discord.gg/BTYqqHKUrf)。私たちは、プロジェクトの持続可能性を保護しながら、正当なビジネスユースケースをサポートすることに取り組んでいます。 --- title: "MastraClient" description: "Mastra Client SDKの設定と使用方法について学ぶ" --- # Mastra Client SDK [JA] Source: https://mastra.ai/ja/docs/deployment/client Mastra Client SDKは、クライアント環境から[Mastraサーバー](/docs/deployment/server)とやり取りするためのシンプルで型安全なインターフェースを提供します。 ## 開発要件 スムーズなローカル開発を確保するために、以下のものを用意してください: - Node.js 18.x 以降がインストールされていること - TypeScript 4.7+ (TypeScriptを使用する場合) - Fetch APIをサポートする最新のブラウザ環境 - ローカルのMastraサーバーが実行中であること(通常はポート4111で) ## インストール import { Tabs } from "nextra/components"; ```bash copy npm install @mastra/client-js@latest ``` ```bash copy yarn add @mastra/client-js@latest ``` ```bash copy pnpm add @mastra/client-js@latest ``` ## Mastra Clientの初期化 始めるには、必要なパラメータでMastraClientを初期化する必要があります: ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient({ baseUrl: "http://localhost:4111", // デフォルトのMastra開発サーバーポート }); ``` ### 設定オプション 様々なオプションでクライアントをカスタマイズできます: ```typescript const client = new MastraClient({ // 必須 baseUrl: "http://localhost:4111", // 開発用のオプション設定 retries: 3, // リトライ試行回数 backoffMs: 300, // 初期リトライバックオフ時間 maxBackoffMs: 5000, // 最大リトライバックオフ時間 headers: { // 開発用のカスタムヘッダー "X-Development": "true", }, }); ``` ## 例 MastraClientが初期化されると、型安全なインターフェースを通じてクライアント呼び出しを開始できます ```typescript // Get a reference to your local agent const agent = client.getAgent("dev-agent-id"); // Generate responses const response = await agent.generate({ messages: [ { role: "user", content: "Hello, I'm testing the local development setup!", }, ], }); ``` ## 利用可能な機能 Mastraクライアントは、Mastraサーバーが提供するすべてのリソースを公開しています - [**エージェント**](/reference/client-js/agents): AIエージェントの作成と管理、レスポンスの生成、ストリーミング対話の処理 - [**メモリ**](/reference/client-js/memory): 会話スレッドとメッセージ履歴の管理 - [**ツール**](/reference/client-js/tools): エージェントが利用できるツールへのアクセスと実行 - [**ワークフロー**](/reference/client-js/workflows): 自動化されたワークフローの作成と管理 - [**ベクトル**](/reference/client-js/vectors): セマンティック検索と類似性マッチングのためのベクトル操作の処理 ## ベストプラクティス 1. **エラー処理**: 開発シナリオに適切なエラー処理を実装する 2. **環境変数**: 設定には環境変数を使用する 3. **デバッグ**: 必要に応じて詳細なログ記録を有効にする ```typescript // Example with error handling and logging try { const agent = client.getAgent("dev-agent-id"); const response = await agent.generate({ messages: [{ role: "user", content: "Test message" }], }); console.log("Response:", response); } catch (error) { console.error("Development error:", error); } ``` --- title: "カスタムAPIルート" description: "Mastraサーバーから追加のHTTPエンドポイントを公開します。" --- # カスタムAPIルート [JA] Source: https://mastra.ai/ja/docs/deployment/custom-api-routes デフォルトでは、Mastraは登録されたエージェントとワークフローをサーバーを通じて自動的に公開します。追加の動作を実装するには、独自のHTTPルートを定義することができます。 ルートは`@mastra/core/server`から提供される`registerApiRoute`ヘルパーを使用して設定します。ルートは`Mastra`インスタンスと同じファイルに配置することもできますが、分離することで設定をより簡潔に保つことができます。 ```typescript copy showLineNumbers import { Mastra } from "@mastra/core"; import { registerApiRoute } from "@mastra/core/server"; export const mastra = new Mastra({ server: { apiRoutes: [ registerApiRoute("/my-custom-route", { method: "GET", handler: async (c) => { const mastra = c.get("mastra"); const agents = await mastra.getAgent("my-agent"); return c.json({ message: "Hello, world!" }); }, }), ], }, }); ``` 各ルートのハンドラーはHonoの`Context`を受け取ります。ハンドラー内では、`Mastra`インスタンスにアクセスしてエージェントやワークフローを取得したり呼び出したりすることができます。 ルート固有のミドルウェアを追加するには、`registerApiRoute`を呼び出す際に`middleware`配列を渡します。 ```typescript copy showLineNumbers registerApiRoute("/my-custom-route", { method: "GET", middleware: [ async (c, next) => { console.log(`${c.req.method} ${c.req.url}`); await next(); }, ], handler: async (c) => { return c.json({ message: "My route with custom middleware" }); }, }); ``` --- title: "サーバーレスデプロイメント" description: "プラットフォーム固有のデプロイヤーまたは標準HTTPサーバーを使用してMastraアプリケーションを構築およびデプロイする" --- # サーバーレスデプロイメント [JA] Source: https://mastra.ai/ja/docs/deployment/deployment このガイドでは、プラットフォーム固有のデプロイヤーを使用して、スタンドアロンのMastraアプリケーションをCloudflare Workers、Vercel、Netlifyにデプロイする方法について説明します。 Mastraをフレームワークと統合する場合、デプロイヤーは**必要ありません**。詳細については、[Webフレームワーク統合](/docs/deployment/web-framework)を参照してください。 セルフホストのNode.jsサーバーデプロイメントについては、[Mastraサーバーの作成](/docs/deployment/server)ガイドを参照してください。 ## 前提条件 始める前に、以下のものを用意してください: - **Node.js** がインストールされていること(バージョン18以上を推奨) - プラットフォーム固有のデプロイヤーを使用する場合: - 選択したプラットフォームのアカウント - 必要なAPIキーまたは認証情報 ## LibSQLStore `LibSQLStore`はローカルファイルシステムに書き込みを行いますが、これはサーバーレス環境の一時的な性質により、サーバーレス環境ではサポートされていません。Vercel、Netlify、Cloudflareなどのプラットフォームにデプロイする場合は、`LibSQLStore`の使用を**すべて削除する**必要があります。 具体的には、`src/mastra/index.ts`と`src/mastra/agents/weather-agent.ts`の両方から削除していることを確認してください: ```diff filename="src/mastra/index.ts" showLineNumbers export const mastra = new Mastra({ // ... - storage: new LibSQLStore({ - // stores telemetry, evals, ... into memory storage, if it needs to persist, change to file:../mastra.db - url: ":memory:", - }) }); ``` ``` diff filename="src/mastra/agents/weather-agent.ts" showLineNumbers export const weatherAgent = new Agent({ // .. - memory: new Memory({ - storage: new LibSQLStore({ - url: "file:../mastra.db" // path is relative to the .mastra/output directory - }) - }) }); ``` ## サーバーレスプラットフォームデプロイヤー プラットフォーム固有のデプロイヤーは、以下の設定とデプロイメントを処理します: - **[Cloudflare Workers](/reference/deployer/cloudflare)** - **[Vercel](/reference/deployer/vercel)** - **[Netlify](/reference/deployer/netlify)** - **[Mastra Cloud](/docs/mastra-cloud/overview)** _(ベータ版)_。早期アクセスのために[クラウドウェイトリスト](https://mastra.ai/cloud-beta)に参加できます。 --- title: "ミドルウェア" description: "リクエストをインターセプトするためのカスタムミドルウェア関数を適用します。" --- # ミドルウェア [JA] Source: https://mastra.ai/ja/docs/deployment/middleware Mastraサーバーは、APIルートハンドラーが呼び出される前後にカスタムミドルウェア関数を実行できます。これは認証、ログ記録、リクエスト固有のコンテキストの注入、CORSヘッダーの追加などに役立ちます。 ミドルウェアは[Hono](https://hono.dev)の`Context`(`c`)と`next`関数を受け取ります。`Response`を返すとリクエストは短絡されます。`next()`を呼び出すと、次のミドルウェアまたはルートハンドラーの処理が続行されます。 ```typescript copy showLineNumbers import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ server: { middleware: [ { handler: async (c, next) => { // Example: Add authentication check const authHeader = c.req.header("Authorization"); if (!authHeader) { return new Response("Unauthorized", { status: 401 }); } await next(); }, path: "/api/*", }, // Add a global request logger async (c, next) => { console.log(`${c.req.method} ${c.req.url}`); await next(); }, ], }, }); ``` 単一のルートにミドルウェアをアタッチするには、`registerApiRoute`に`middleware`オプションを渡します: ```typescript copy showLineNumbers registerApiRoute("/my-custom-route", { method: "GET", middleware: [ async (c, next) => { console.log(`${c.req.method} ${c.req.url}`); await next(); }, ], handler: async (c) => { const mastra = c.get("mastra"); return c.json({ message: "Hello, world!" }); }, }); ``` --- ## 一般的な例 ### 認証 ```typescript copy { handler: async (c, next) => { const authHeader = c.req.header('Authorization'); if (!authHeader || !authHeader.startsWith('Bearer ')) { return new Response('Unauthorized', { status: 401 }); } // Validate token here await next(); }, path: '/api/*', } ``` ### CORSサポート ```typescript copy { handler: async (c, next) => { c.header('Access-Control-Allow-Origin', '*'); c.header( 'Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS', ); c.header( 'Access-Control-Allow-Headers', 'Content-Type, Authorization', ); if (c.req.method === 'OPTIONS') { return new Response(null, { status: 204 }); } await next(); }, } ``` ### リクエストログ記録 ```typescript copy { handler: async (c, next) => { const start = Date.now(); await next(); const duration = Date.now() - start; console.log(`${c.req.method} ${c.req.url} - ${duration}ms`); }, } ``` ### 特別なMastraヘッダー Mastra Cloudやカスタムクライアントと統合する際、以下のヘッダーをミドルウェアで検査して動作をカスタマイズすることができます: ```typescript copy { handler: async (c, next) => { const isFromMastraCloud = c.req.header('x-mastra-cloud') === 'true'; const clientType = c.req.header('x-mastra-client-type'); const isDevPlayground = c.req.header('x-mastra-dev-playground') === 'true'; if (isFromMastraCloud) { // Special handling } await next(); }, } ``` - `x-mastra-cloud`: リクエストがMastra Cloudから発信されたことを示す - `x-mastra-client-type`: クライアントSDKを識別する(例:`js`や`python`) - `x-mastra-dev-playground`: リクエストがローカルプレイグラウンドからトリガーされたことを示す --- title: デプロイメント概要 description: Mastraアプリケーションの様々なデプロイメントオプションについて学ぶ --- # デプロイメント概要 [JA] Source: https://mastra.ai/ja/docs/deployment/overview Mastraは、フルマネージドソリューションからセルフホスト型オプション、Webフレームワーク統合まで、アプリケーションのニーズに合わせた複数のデプロイメントオプションを提供します。このガイドでは、利用可能なデプロイメントパスを理解し、プロジェクトに適したものを選択するのに役立ちます。 ## デプロイメントオプション ### Mastra Cloud Mastra Cloudは、GitHubリポジトリに接続し、コード変更時に自動デプロイを行い、監視ツールを提供するデプロイメントプラットフォームです。以下の機能が含まれています: - GitHubリポジトリ統合 - git pushでのデプロイメント - エージェントテストインターフェース - 包括的なログとトレース - 各プロジェクト用のカスタムドメイン [Mastra Cloudドキュメントを見る →](/docs/mastra-cloud/overview) ### Webフレームワークとの統合 Mastraは様々なWebフレームワークと統合できます。詳細なガイドについては、以下のいずれかをご覧ください。 - [Next.jsとの統合](/docs/frameworks/web-frameworks/next-js) - [Astroとの統合](/docs/frameworks/web-frameworks/astro) フレームワークと統合する場合、Mastraは通常デプロイメントのための追加設定を必要としません。 [Webフレームワーク統合を見る →](/docs/deployment/web-framework) ### サーバーでの運用 Mastraを標準的なNode.js HTTPサーバーとしてデプロイできます。これにより、インフラストラクチャとデプロイメント環境を完全に制御できます。 - カスタムAPIルートとミドルウェア - 設定可能なCORSと認証 - VM、コンテナ、またはPaaSプラットフォームへのデプロイ - 既存のNode.jsアプリケーションとの統合に最適 [サーバーデプロイメントガイド →](/docs/deployment/server) ### サーバーレスプラットフォーム Mastraは人気のサーバーレスプラットフォーム向けのプラットフォーム固有のデプロイヤーを提供し、最小限の設定でアプリケーションをデプロイできます。 - Cloudflare Workers、Vercel、またはNetlifyへのデプロイ - プラットフォーム固有の最適化 - 簡素化されたデプロイメントプロセス - プラットフォームを通じた自動スケーリング [サーバーレスデプロイメントガイド →](/docs/deployment/deployment) ## クライアント設定 Mastraアプリケーションをデプロイした後、クライアントを設定して通信できるようにする必要があります。Mastra Client SDKは、Mastraサーバーとやり取りするためのシンプルで型安全なインターフェースを提供します。 - 型安全なAPI操作 - 認証とリクエスト処理 - リトライとエラー処理 - ストリーミングレスポンスのサポート [クライアント設定ガイド →](/docs/deployment/client) ## デプロイメントオプションの選択 | オプション | 最適な用途 | 主な利点 | | ------------------------ | ------------------------------------------------------------- | -------------------------------------------------------------- | | **Mastra Cloud** | インフラストラクチャの心配なく迅速にリリースしたいチーム | フルマネージド、自動スケーリング、内蔵の可観測性 | | **Framework Deployment** | すでにNext.js、Astroなどを使用しているチーム | フロントエンドとバックエンドの統一されたコードベースでデプロイメントを簡素化 | | **Server Deployment** | 最大限の制御とカスタマイゼーションが必要なチーム | 完全な制御、カスタムミドルウェア、既存アプリとの統合 | | **Serverless Platforms** | すでにVercel、Netlify、またはCloudflareを使用しているチーム | プラットフォーム統合、簡素化されたデプロイメント、自動スケーリング | --- title: "Mastraサーバーの作成" description: "ミドルウェアやその他のオプションでMastraサーバーを設定およびカスタマイズする" --- # Mastraサーバーの作成 [JA] Source: https://mastra.ai/ja/docs/deployment/server 開発中または Mastra アプリケーションをデプロイする際、エージェント、ワークフロー、およびその他の機能を API エンドポイントとして公開する HTTP サーバーとして実行されます。このページでは、サーバーの動作を設定およびカスタマイズする方法について説明します。 ## サーバーアーキテクチャ Mastraは[Hono](https://hono.dev)を基盤となるHTTPサーバーフレームワークとして使用しています。`mastra build`を使用してMastraアプリケーションをビルドすると、`.mastra`ディレクトリにHonoベースのHTTPサーバーが生成されます。 サーバーは以下を提供します: - 登録されたすべてのエージェント用のAPIエンドポイント - 登録されたすべてのワークフロー用のAPIエンドポイント - カスタムAPIルートのサポート - カスタムミドルウェアのサポート - タイムアウトの設定 - ポートの設定 - ボディリミットの設定 追加のサーバー動作の追加については、[ミドルウェア](/docs/deployment/middleware)と [カスタムAPIルート](/docs/deployment/custom-api-routes)のページを参照してください。 ## サーバー設定 Mastraインスタンスでサーバーの`port`と`timeout`を設定できます。 ```typescript copy showLineNumbers import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ server: { port: 3000, // デフォルトは4111 timeout: 10000, // デフォルトは30000(30秒) }, }); ``` `method`オプションは`"GET"`、`"POST"`、`"PUT"`、`"DELETE"`または`"ALL"`のいずれかです。`"ALL"`を使用すると、パスに一致する任意のHTTPメソッドに対してハンドラーが呼び出されます。 ## カスタムCORS設定 Mastraでは、サーバーのCORS(クロスオリジンリソース共有)設定をカスタマイズすることができます。 ```typescript copy showLineNumbers import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ server: { cors: { origin: ["https://example.com"], // 特定のオリジンを許可、または'*'ですべてを許可 allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], allowHeaders: ["Content-Type", "Authorization"], credentials: false, }, }, }); ``` ## デプロイメント Mastraは標準的なNode.jsサーバーにビルドされるため、Node.jsアプリケーションを実行するあらゆるプラットフォームにデプロイできます: - クラウドVM(AWS EC2、DigitalOcean Droplets、GCP Compute Engine) - コンテナプラットフォーム(Docker、Kubernetes) - Platform as a Service(Heroku、Railway) - 自己ホスト型サーバー ### ビルド アプリケーションをビルドします: ```bash copy # 現在のディレクトリからビルド mastra build # またはディレクトリを指定 mastra build --dir ./my-project ``` ビルドプロセス: 1. エントリーファイル(`src/mastra/index.ts`または`src/mastra/index.js`)を特定 2. `.mastra`出力ディレクトリを作成 3. ツリーシェイキングとソースマップを使用してRollupでコードをバンドル 4. [Hono](https://hono.dev) HTTPサーバーを生成 すべてのオプションについては[`mastra build`](/reference/cli/build)を参照してください。 ### サーバーの実行 HTTPサーバーを起動します: ```bash copy node .mastra/output/index.mjs ``` ### ビルド出力用のテレメトリを有効にする ビルド出力のインストルメンテーションを次のように読み込みます: ```bash copy node --import=./.mastra/output/instrumentation.mjs .mastra/output/index.mjs ``` ## サーバーレスデプロイメント MastraはCloudflare Workers、Vercel、Netlifyでのサーバーレスデプロイメントもサポートしています。 セットアップ手順については、[サーバーレスデプロイメント](/docs/deployment/deployment)ガイドをご覧ください。 --- title: "WebフレームワークでのMastraのデプロイ" description: "WebフレームワークとMastraを統合した際のデプロイ方法を学ぶ" --- # Webフレームワーク統合 [JA] Source: https://mastra.ai/ja/docs/deployment/web-framework このガイドでは、統合されたMastraアプリケーションのデプロイについて説明します。Mastraは様々なWebフレームワークと統合できます。詳細なガイドについては、以下のいずれかをご覧ください。 - [Next.jsとの統合](/docs/frameworks/web-frameworks/next-js) - [Astroとの統合](/docs/frameworks/web-frameworks/astro) フレームワークと統合された場合、Mastraは通常、デプロイのための追加設定を必要としません。 ## Next.js on Vercel での使用 [ガイドに従って](/docs/frameworks/web-frameworks/next-js) Mastra を Next.js と統合し、Vercel にデプロイする予定の場合、追加のセットアップは必要ありません。 確認すべき唯一の点は、`next.config.ts` に以下を追加し、サーバーレス環境ではサポートされていない [LibSQLStore](/docs/deployment/deployment#libsqlstore) の使用を削除していることです: ```typescript {4} filename="next.config.ts" showLineNumbers copy import type { NextConfig } from "next"; const nextConfig: NextConfig = { serverExternalPackages: ["@mastra/*"], }; export default nextConfig; ``` ## Vercel上でのAstro [私たちのガイドに従って](/docs/frameworks/web-frameworks/astro)MastraをAstroと統合し、Vercelにデプロイする予定の場合、追加のセットアップは必要ありません。 確認する必要があるのは、`astro.config.mjs`に以下を追加し、サーバーレス環境ではサポートされていない[LibSQLStore](/docs/deployment/deployment#libsqlstore)の使用を削除していることだけです: ```javascript {2,6,7} filename="astro.config.mjs" showLineNumbers copy import { defineConfig } from 'astro/config'; import vercel from '@astrojs/vercel'; export default defineConfig({ // ... adapter: vercel(), output: "server" }); ``` ## Netlify上でのAstro [私たちのガイドに従って](/docs/frameworks/web-frameworks/astro)MastraをAstroと統合し、Vercelにデプロイする予定の場合、追加のセットアップは必要ありません。 確認する必要があるのは、`astro.config.mjs`に以下を追加し、サーバーレス環境ではサポートされていない[LibSQLStore](/docs/deployment/deployment#libsqlstore)の使用を削除していることだけです: ```javascript {2,6,7} filename="astro.config.mjs" showLineNumbers copy import { defineConfig } from 'astro/config'; import vercel from '@astrojs/netlify'; export default defineConfig({ // ... adapter: netlify(), output: "server" }); ``` --- title: "独自のEvalを作成する" description: "Mastraを使用すると、独自のevalを作成できます。方法はこちらです。" --- # 独自のEvalを作成する [JA] Source: https://mastra.ai/ja/docs/evals/custom-eval 独自のevalを作成することは、新しい関数を作成するのと同じくらい簡単です。単に`Metric`クラスを拡張するクラスを作成し、`measure`メソッドを実装します。 ## 基本的な例 出力に特定の単語が含まれているかを確認するカスタムメトリックを作成する簡単な例については、[Word Inclusion example](/examples/evals/word-inclusion)をご覧ください。 ## カスタム LLM-Judge の作成 カスタム LLM ジャッジは、AI の応答の特定の側面を評価するのに役立ちます。特定のユースケースに対する専門家のレビュアーがいるようなものです: - 医療 Q&A → ジャッジは医療の正確性と安全性をチェック - カスタマーサービス → ジャッジはトーンと有用性を評価 - コード生成 → ジャッジはコードの正確性とスタイルを確認 実用的な例として、[Chef Michel's](/docs/guides/chef-michel) のレシピを [Gluten Checker example](/examples/evals/custom-eval) でグルテン含有量を評価する方法をご覧ください。 --- title: "概要" description: "Mastra evalsを使用してAIエージェントの品質を評価・測定する方法を理解する。" --- # evalsを使用したエージェントのテスト [JA] Source: https://mastra.ai/ja/docs/evals/overview 従来のソフトウェアテストには明確な合格/不合格の条件がありますが、AIの出力は非決定論的で、同じ入力でも結果が変わることがあります。evalsは、エージェントの品質を測定するための定量化可能なメトリクスを提供することで、このギャップを埋めるのに役立ちます。 evalsは、モデルベース、ルールベース、統計的手法を使用してエージェントの出力を評価する自動テストです。各evalは0-1の間の正規化されたスコアを返し、ログに記録して比較することができます。evalsは独自のプロンプトとスコアリング関数でカスタマイズできます。 evalsはクラウドで実行でき、リアルタイムの結果を取得できます。しかし、evalsはCI/CDパイプラインの一部にもなり、時間の経過とともにエージェントをテストし監視することができます。 ## Evalの種類 異なる種類のevalがあり、それぞれ特定の目的を果たします。一般的な種類をいくつか紹介します: 1. **テキストEval**: エージェントの応答の正確性、信頼性、文脈理解を評価 2. **分類Eval**: 事前定義されたカテゴリに基づくデータ分類の精度を測定 3. **プロンプトエンジニアリングEval**: 異なる指示と入力形式の影響を探る ## はじめに Evalsはエージェントに追加する必要があります。以下は要約、コンテンツ類似性、トーン一貫性メトリクスを使用した例です: ```typescript copy showLineNumbers filename="src/mastra/agents/index.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { SummarizationMetric } from "@mastra/evals/llm"; import { ContentSimilarityMetric, ToneConsistencyMetric, } from "@mastra/evals/nlp"; const model = openai("gpt-4o"); export const myAgent = new Agent({ name: "ContentWriter", instructions: "You are a content writer that creates accurate summaries", model, evals: { summarization: new SummarizationMetric(model), contentSimilarity: new ContentSimilarityMetric(), tone: new ToneConsistencyMetric(), }, }); ``` `mastra dev`を使用する際、Mastraダッシュボードでeval結果を確認できます。 ## 自動テストを超えて 自動evalは価値がありますが、高性能なAIチームは多くの場合、以下と組み合わせています: 1. **A/Bテスト**: 実際のユーザーで異なるバージョンを比較 2. **人間によるレビュー**: 本番データとトレースの定期的なレビュー 3. **継続的監視**: 時間の経過とともにevalメトリクスを追跡してリグレッションを検出 ## Eval結果の理解 各evalメトリクスは、エージェントの出力の特定の側面を測定します。結果を解釈し、改善する方法は以下の通りです: ### スコアの理解 任意のメトリクスについて: 1. メトリクスのドキュメントを確認して、スコアリングプロセスを理解する 2. スコアが変化するタイミングのパターンを探す 3. 異なる入力とコンテキスト間でスコアを比較する 4. 時間の経過に伴う変化を追跡してトレンドを把握する ### 結果の改善 スコアが目標に達していない場合: 1. 指示を確認する - 明確ですか?より具体的にしてみてください 2. コンテキストを確認する - エージェントが必要とするものを提供していますか? 3. プロンプトを簡素化する - 複雑なタスクをより小さなステップに分割する 4. ガードレールを追加する - 難しいケースに対する具体的なルールを含める ### 品質の維持 目標を達成したら: 1. 安定性を監視する - スコアは一貫して保たれていますか? 2. 効果的な方法を文書化する - 成功したアプローチについてメモを残す 3. エッジケースをテストする - 異常なシナリオをカバーする例を追加する 4. 微調整する - 効率を改善する方法を探す evalができることの詳細については、[Textual Evals](/docs/evals/textual-evals)を参照してください。 独自のevalを作成する方法の詳細については、[Custom Evals](/docs/evals/custom-eval)ガイドを参照してください。 CIパイプラインでevalを実行する方法については、[Running in CI](/docs/evals/running-in-ci)ガイドを参照してください。 --- title: "CIでの実行" description: "時間の経過とともにエージェントの品質を監視するために、CI/CDパイプラインでMastraの評価を実行する方法を学びましょう。" --- # CIでのEvalsの実行 [JA] Source: https://mastra.ai/ja/docs/evals/running-in-ci CIパイプラインでevalsを実行することで、時間の経過とともにエージェントの品質を測定するための定量的な指標を提供し、このギャップを埋めるのに役立ちます。 ## CI統合のセットアップ ESMモジュールをサポートするテストフレームワークであれば、どれでも対応しています。例えば、[Vitest](https://vitest.dev/)、[Jest](https://jestjs.io/)、または[Mocha](https://mochajs.org/)を使用して、CI/CDパイプラインでevalsを実行することができます。 ```typescript copy showLineNumbers filename="src/mastra/agents/index.test.ts" import { describe, it, expect } from "vitest"; import { evaluate } from "@mastra/evals"; import { ToneConsistencyMetric } from "@mastra/evals/nlp"; import { myAgent } from "./index"; describe("My Agent", () => { it("should validate tone consistency", async () => { const metric = new ToneConsistencyMetric(); const result = await evaluate(myAgent, "Hello, world!", metric); expect(result.score).toBe(1); }); }); ``` テストフレームワーク用のtestSetupとglobalSetupスクリプトを設定して、eval結果をキャプチャする必要があります。これにより、mastraダッシュボードでこれらの結果を表示することができます。 ## フレームワーク設定 ### Vitestのセットアップ CI/CDパイプラインでevalsを実行するために、これらのファイルをプロジェクトに追加してください: ```typescript copy showLineNumbers filename="globalSetup.ts" import { globalSetup } from "@mastra/evals"; export default function setup() { globalSetup(); } ``` ```typescript copy showLineNumbers filename="testSetup.ts" import { beforeAll } from "vitest"; import { attachListeners } from "@mastra/evals"; beforeAll(async () => { await attachListeners(); }); ``` ```typescript copy showLineNumbers filename="vitest.config.ts" import { defineConfig } from "vitest/config"; export default defineConfig({ test: { globalSetup: "./globalSetup.ts", setupFiles: ["./testSetup.ts"], }, }); ``` ## ストレージ設定 Mastra Storageに評価結果を保存し、Mastraダッシュボードで結果を取得するには: ```typescript copy showLineNumbers filename="testSetup.ts" import { beforeAll } from "vitest"; import { attachListeners } from "@mastra/evals"; import { mastra } from "./your-mastra-setup"; beforeAll(async () => { // Store evals in Mastra Storage (requires storage to be enabled) await attachListeners(mastra); }); ``` ファイルストレージを使用すると、評価は永続化され、後で照会することができます。メモリストレージを使用すると、評価はテストプロセスに分離されます。 --- title: "テキスト評価" description: "MastraがLLM-as-judgeの方法論を使用してテキストの品質を評価する方法を理解する。" --- # Textual Evals [JA] Source: https://mastra.ai/ja/docs/evals/textual-evals Textual evalsは、エージェントの出力を評価するためにLLM-as-judgeの方法論を使用します。このアプローチは、言語モデルを活用してテキストの品質のさまざまな側面を評価し、ティーチングアシスタントがルーブリックを使用して課題を採点する方法に似ています。 各evalは特定の品質の側面に焦点を当て、0から1の間のスコアを返し、非決定的なAI出力のための定量的な指標を提供します。 Mastraは、エージェントの出力を評価するためのいくつかの評価指標を提供します。Mastraはこれらの指標に限定されず、[独自の評価を定義する](/docs/evals/custom-eval)こともできます。 ## テキスト評価を使用する理由 テキスト評価は、あなたのエージェントが以下を確実に行うのに役立ちます: - 正確で信頼性の高い回答を生成する - コンテキストを効果的に使用する - 出力要件に従う - 時間の経過とともに一貫した品質を維持する ## 利用可能な指標 ### 正確性と信頼性 これらの指標は、エージェントの回答がどれだけ正確で、真実で、完全であるかを評価します: - [`hallucination`](/reference/evals/hallucination): 提供されたコンテキストに存在しない事実や主張を検出 - [`faithfulness`](/reference/evals/faithfulness): 提供されたコンテキストをどれだけ正確に表現しているかを測定 - [`content-similarity`](/reference/evals/content-similarity): 異なる表現における情報の一貫性を評価 - [`completeness`](/reference/evals/completeness): 必要な情報がすべて含まれているかを確認 - [`answer-relevancy`](/reference/evals/answer-relevancy): 回答が元の質問にどれだけ適切に対応しているかを評価 - [`textual-difference`](/reference/evals/textual-difference): 文字列間のテキストの違いを測定 ### コンテキストの理解 これらの指標は、エージェントが提供されたコンテキストをどれだけうまく使用しているかを評価します: - [`context-position`](/reference/evals/context-position): 回答内でコンテキストがどこに現れるかを分析 - [`context-precision`](/reference/evals/context-precision): コンテキストのチャンクが論理的にグループ化されているかを評価 - [`context-relevancy`](/reference/evals/context-relevancy): 適切なコンテキスト部分の使用を測定 - [`contextual-recall`](/reference/evals/contextual-recall): コンテキスト使用の完全性を評価 ### 出力品質 これらの指標は、フォーマットとスタイルの要件への準拠を評価します: - [`tone`](/reference/evals/tone-consistency): 形式、複雑さ、スタイルの一貫性を測定 - [`toxicity`](/reference/evals/toxicity): 有害または不適切なコンテンツを検出 - [`bias`](/reference/evals/bias): 出力における潜在的なバイアスを検出 - [`prompt-alignment`](/reference/evals/prompt-alignment): 長さの制限、フォーマットの要件、その他の制約などの明示的な指示への準拠を確認 - [`summarization`](/reference/evals/summarization): 情報の保持と簡潔さを評価 - [`keyword-coverage`](/reference/evals/keyword-coverage): 技術用語の使用を評価 --- title: "ライセンス" description: "Mastra ライセンス" --- # ライセンス [JA] Source: https://mastra.ai/ja/docs/faq ## Elastic License 2.0 (ELv2) Mastraは、オープンソースの原則と持続可能なビジネス慣行のバランスを取るために設計された現代的なライセンスであるElastic License 2.0 (ELv2)の下でライセンスされています。 ### Elastic License 2.0とは? Elastic License 2.0は、プロジェクトの持続可能性を保護するための特定の制限を含みながら、ソフトウェアを使用、変更、配布する広範な権利をユーザーに付与するソース利用可能なライセンスです。これにより以下が可能です: - ほとんどの目的での無料使用 - ソースコードの閲覧、変更、再配布 - 派生作品の作成と配布 - 組織内での商業利用 主な制限は、Mastraをホストまたは管理されたサービスとして提供し、ソフトウェアの実質的な機能にユーザーがアクセスできるようにすることはできないということです。 ### なぜElastic License 2.0を選んだのか 私たちはいくつかの重要な理由からElastic License 2.0を選びました: 1. **持続可能性**: 開放性と長期的な開発を維持する能力の間で健全なバランスを保つことができます。 2. **イノベーションの保護**: 私たちの作業が競合するサービスとして再パッケージされることを心配せずに、イノベーションへの投資を続けることができます。 3. **コミュニティ重視**: ユーザーが私たちのコードを閲覧、変更、学ぶことを可能にしながら、コミュニティをサポートする能力を保護することで、オープンソースの精神を維持します。 4. **ビジネスの明確さ**: Mastraが商業的な文脈でどのように使用できるかについて明確なガイドラインを提供します。 ### Mastraでビジネスを構築する ライセンスの制限にもかかわらず、Mastraを使用して成功したビジネスを構築する方法は多数あります: #### 許可されたビジネスモデル - **アプリケーションの構築**: Mastraを使用してアプリケーションを作成し販売する - **コンサルティングサービスの提供**: 専門知識、実装、カスタマイズサービスを提供する - **カスタムソリューションの開発**: クライアント向けにMastraを使用して特注のAIソリューションを構築する - **アドオンと拡張機能の作成**: Mastraの機能を拡張する補完的なツールを開発し販売する - **トレーニングと教育**: Mastraの効果的な使用に関するコースや教育資料を提供する #### 準拠した使用例 - ある会社がMastraを使用してAI駆動のカスタマーサービスアプリケーションを構築し、クライアントに販売する - コンサルティング会社がMastraの実装とカスタマイズサービスを提供する - 開発者がMastraを使用して特殊なエージェントやツールを作成し、他の企業にライセンス供与する - スタートアップがMastraを活用した特定の業界向けソリューション(例:医療AIアシスタント)を構築する #### 避けるべきこと 主な制限は、Mastra自体をホストされたサービスとして提供し、そのコア機能にユーザーがアクセスできるようにすることはできないということです。つまり: - Mastraをほとんど変更せずにSaaSプラットフォームを作成しないでください - 主にMastraの機能を使用するために顧客が支払う管理されたMastraサービスを提供しないでください ### ライセンスに関する質問? Elastic License 2.0があなたの使用ケースにどのように適用されるかについて具体的な質問がある場合は、[Discordでお問い合わせください](https://discord.gg/BTYqqHKUrf)。プロジェクトの持続可能性を保護しながら、正当なビジネス使用ケースをサポートすることをお約束します。 --- title: "Vercel AI SDKとの使用" description: "MastraがVercel AI SDKライブラリをどのように活用し、Mastraでさらにそれをどのように活用できるかを学ぶ" --- import Image from "next/image"; # Vercel AI SDKとの使用 [JA] Source: https://mastra.ai/ja/docs/frameworks/agentic-uis/ai-sdk MastraはAI SDKのモデルルーティング(OpenAI、Anthropicなどの上に構築された統一インターフェース)、構造化出力、およびツール呼び出しを活用しています。 これについては[このブログ記事](https://mastra.ai/blog/using-ai-sdk-with-mastra)でより詳しく説明しています。 ## Mastra + AI SDK MastraはAI SDKの上位レイヤーとして機能し、チームが概念実証を迅速かつ簡単に本格運用できるよう支援します。 Agent interaction trace showing spans, LLM calls, and tool executions ## モデルルーティング Mastraでエージェントを作成する際、AI SDKがサポートする任意のモデルを指定できます: ```typescript import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; const agent = new Agent({ name: "WeatherAgent", instructions: "Instructions for the agent...", model: openai("gpt-4-turbo"), // Model comes directly from AI SDK }); const result = await agent.generate("What is the weather like?"); ``` ## AI SDK Hooks MastraはAI SDKのhooksと互換性があり、シームレスなフロントエンド統合を実現します: ### useChat `useChat`フックは、フロントエンドアプリケーションでリアルタイムチャットインタラクションを可能にします - エージェントデータストリーム(`.toDataStreamResponse()`)と連携します - useChat `api`のデフォルトは`/api/chat`です - Mastra REST APIエージェントストリームエンドポイント`{MASTRA_BASE_URL}/agents/:agentId/stream`でデータストリームと連携します。 つまり、構造化出力が定義されていない場合です。 ```typescript filename="app/api/chat/route.ts" copy import { mastra } from "@/src/mastra"; export async function POST(req: Request) { const { messages } = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); const stream = await myAgent.stream(messages); return stream.toDataStreamResponse(); } ``` ```typescript copy import { useChat } from '@ai-sdk/react'; export function ChatComponent() { const { messages, input, handleInputChange, handleSubmit } = useChat({ api: '/path-to-your-agent-stream-api-endpoint' }); return (
{messages.map(m => (
{m.role}: {m.content}
))}
); } ``` > **注意**: エージェントメモリ機能で`useChat`を使用する場合は、重要な実装詳細について[Agent Memoryセクション](/docs/agents/agent-memory#usechat)を必ず確認してください。 ### useCompletion 単発の補完には、`useCompletion`フックを使用します: - エージェントデータストリーム(`.toDataStreamResponse()`)と連携します - useCompletion `api`のデフォルトは`/api/completion`です - Mastra REST APIエージェントストリームエンドポイント`{MASTRA_BASE_URL}/agents/:agentId/stream`でデータストリームと連携します。 つまり、構造化出力が定義されていない場合です。 ```typescript filename="app/api/completion/route.ts" copy import { mastra } from "@/src/mastra"; export async function POST(req: Request) { const { prompt } = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); const stream = await myAgent.stream([{ role: "user", content: prompt }]); return stream.toDataStreamResponse(); } ``` ```typescript import { useCompletion } from "@ai-sdk/react"; export function CompletionComponent() { const { completion, input, handleInputChange, handleSubmit, } = useCompletion({ api: '/path-to-your-agent-stream-api-endpoint' }); return (

Completion result: {completion}

); } ``` ### useObject JSONオブジェクトを表すテキストストリームを消費し、スキーマに基づいて完全なオブジェクトに解析するために使用します。 - エージェントテキストストリーム(`.toTextStreamResponse()`)と連携します - Mastra REST APIエージェントストリームエンドポイント`{MASTRA_BASE_URL}/agents/:agentId/stream`でテキストストリームと連携します。 つまり、構造化出力が定義されている場合です。 ```typescript filename="app/api/use-object/route.ts" copy import { mastra } from "@/src/mastra"; export async function POST(req: Request) { const body = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); const stream = await myAgent.stream(body, { output: z.object({ weather: z.string(), }), }); return stream.toTextStreamResponse(); } ``` ```typescript import { experimental_useObject as useObject } from '@ai-sdk/react'; export default function Page() { const { object, submit } = useObject({ api: '/api/use-object', schema: z.object({ weather: z.string(), }), }); return (
{object?.weather &&

{object.weather}

}
); } ``` ## Tool Calling ### AI SDK Tool Format MastraはAI SDK形式で作成されたツールをサポートしているため、Mastraエージェントで直接使用できます。詳細については、[Vercel AI SDK Tool Format ](/docs/agents/adding-tools#vercel-ai-sdk-tool-format)のツールドキュメントをご覧ください。 ### クライアントサイドでのツール呼び出し MastraはAI SDKのツール呼び出し機能を活用しているため、AI SDKで適用されることはここでも同様に適用されます。 Mastraの[Agent Tools](/docs/agents/adding-tools)は、AI SDKツールと100%互換性があります。 Mastraツールは、オプションの`execute`非同期関数も公開しています。これは、同じプロセス内でツールを実行する代わりに、ツール呼び出しをクライアントやキューに転送したい場合があるため、オプションとなっています。 クライアントサイドでのツール呼び出しを活用する一つの方法は、`@ai-sdk/react`の`useChat`フックの`onToolCall`プロパティを使用してクライアントサイドでツールを実行することです。 ## Custom DataStream 特定のシナリオでは、エージェントのdataStreamにカスタムデータやメッセージアノテーションを書き込む必要があります。 これは以下の用途に役立ちます: - クライアントに追加データをストリーミングする - リアルタイムでクライアントに進捗情報を送信する MastraはAI SDKとうまく統合されており、これを可能にします ### CreateDataStream `createDataStream`関数を使用すると、クライアントに追加データをストリーミングできます ```typescript copy import { createDataStream } from "ai"; import { Agent } from "@mastra/core/agent"; export const weatherAgent = new Agent({ name: "Weather Agent", instructions: ` You are a helpful weather assistant that provides accurate weather information. Your primary function is to help users get weather details for specific locations. When responding: - Always ask for a location if none is provided - If the location name isn't in English, please translate it - If giving a location with multiple parts (e.g. "New York, NY"), use the most relevant part (e.g. "New York") - Include relevant details like humidity, wind conditions, and precipitation - Keep responses concise but informative Use the weatherTool to fetch current weather data. `, model: openai("gpt-4o"), tools: { weatherTool }, }); const stream = createDataStream({ async execute(dataStream) { // Write data dataStream.writeData({ value: "Hello" }); // Write annotation dataStream.writeMessageAnnotation({ type: "status", value: "processing" }); //mastra agent stream const agentStream = await weatherAgent.stream("What is the weather"); // Merge agent stream agentStream.mergeIntoDataStream(dataStream); }, onError: (error) => `Custom error: ${error.message}`, }); ``` ### CreateDataStreamResponse `createDataStreamResponse`関数は、クライアントにデータをストリーミングするResponseオブジェクトを作成します ```typescript filename="app/api/chat/route.ts" copy import { mastra } from "@/src/mastra"; export async function POST(req: Request) { const { messages } = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); //mastra agent stream const agentStream = await myAgent.stream(messages); const response = createDataStreamResponse({ status: 200, statusText: "OK", headers: { "Custom-Header": "value", }, async execute(dataStream) { // Write data dataStream.writeData({ value: "Hello" }); // Write annotation dataStream.writeMessageAnnotation({ type: "status", value: "processing", }); // Merge agent stream agentStream.mergeIntoDataStream(dataStream); }, onError: (error) => `Custom error: ${error.message}`, }); return response; } ``` --- title: Assistant UIとの使用 description: "Assistant UIをMastraと統合する方法を学ぶ" --- import { Callout, FileTree, Steps } from 'nextra/components' # Assistant UIとの使用 [JA] Source: https://mastra.ai/ja/docs/frameworks/agentic-uis/assistant-ui [Assistant UI](https://assistant-ui.com)は、AIチャット用のTypeScript/Reactライブラリです。 shadcn/uiとTailwind CSSをベースに構築されており、開発者が数分で美しいエンタープライズグレードのチャット体験を作成できます。 ## Next.jsとAssistant UIとの統合 Assistant UIを使用する際にMastraをNext.jsプロジェクトに統合する主な方法は2つあります: 1. **フルスタック統合**: MastraをNext.jsアプリケーションのAPIルートに直接統合します。このアプローチでは、バックエンドとフロントエンドのコードを同じプロジェクト内に保持します。[フルスタック統合の設定方法を学ぶ](#full-stack-integration) 2. **独立したバックエンド統合**: Mastraをスタンドアロンサーバーとして実行し、Next.jsフロントエンドをそのAPIエンドポイントに接続します。このアプローチでは関心事を分離し、独立したスケーリングが可能になります。[独立したバックエンド統合の設定方法を学ぶ](#separate-backend-integration) ## フルスタック統合 ### Assistant UIを初期化する `assistant-ui` CLIを使用してAssistant UIをセットアップする際には、2つのオプションがあります: 1. **新規プロジェクト**: Assistant UIを含む新しいNext.jsプロジェクトを作成します。 2. **既存プロジェクト**: 既存のReactプロジェクトにAssistant UIを初期化します。 #### 新規プロジェクト ```bash copy npx assistant-ui@latest create ``` #### 既存プロジェクト ```bash copy npx assistant-ui@latest init ``` APIキーの追加、基本設定、手動セットアップ手順を含む詳細なセットアップ手順については、[assistant-uiの公式ドキュメント](https://assistant-ui.com/docs)を参照してください。 ### Mastraパッケージをインストールする 必要なMastraパッケージをインストールします: ```bash copy npm install @mastra/core@latest @mastra/memory@latest @mastra/libsql@latest ``` ### Next.jsを設定する APIルートでMastraを直接使用する際にNext.jsがアプリケーションを正しくバンドルするために、`serverExternalPackages`を設定する必要があります。 `next.config.js`ファイルを更新して`@mastra/`を含めます: ```js showLineNumbers copy {3} /** @type {import('next').NextConfig} */ const nextConfig = { serverExternalPackages: ["@mastra/*"], // ... その他のNext.js設定 }; module.exports = nextConfig; ``` ### Mastraメモリとストレージを設定する ```typescript showLineNumbers copy filename="mastra/memory.ts" {4,8} import { LibSQLStore } from "@mastra/libsql"; import { Memory } from "@mastra/memory"; export const storage = new LibSQLStore({ url: 'file:./memory.db', }) export const memory = new Memory({ storage, }) ``` エッジにデプロイする場合は、互換性のあるストレージソリューションを使用し、ファイルベースのストレージは使用しないでください。 ### Mastraエージェントを定義する ```typescript showLineNumbers copy filename="mastra/agents/chef-agent.ts" {5-12} import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { memory} from "../memory"; export const chefAgent = new Agent({ name: "chefAgent", instructions: "あなたはMichelです。実用的で経験豊富な家庭料理人です。" + "手元にある材料で料理を作る手助けをします。", model: openai("gpt-4o-mini"), memory, }); ``` ### エージェントをMastraインスタンスに登録する ```typescript showLineNumbers copy filename="mastra/index.ts" {4-5} import { Mastra } from "@mastra/core"; import { chefAgent } from "./agents/chef-agent"; export const mastra = new Mastra({ agents: { chefAgent }, // ... その他の設定 }); ``` これによりMastraが初期化され、`chefAgent`が使用可能になります。 ### チャットAPIエンドポイントを変更する 初期のブートストラップされたNext.jsプロジェクトには、`POST`ハンドラーをエクスポートする`app/api/chat/route.ts`ファイルがあります。初期実装は次のようになっている可能性があります: ```typescript showLineNumbers copy filename="app/api/chat/route.ts" {11-21} import { openai } from "@ai-sdk/openai"; import { frontendTools } from "@assistant-ui/react-ai-sdk"; import { streamText } from "ai"; export const runtime = "edge"; export const maxDuration = 30; export async function POST(req: Request) { const { messages, system, tools } = await req.json(); const result = streamText({ model: openai("gpt-4o"), messages, // forward system prompt and tools from the frontend toolCallStreaming: true, system, tools: { ...frontendTools(tools), }, onError: console.log, }); return result.toDataStreamResponse(); } ``` この実装の代わりに`chefAgent`を使用するように`POST`ハンドラーを変更する必要があります。 ```typescript showLineNumbers copy filename="app/api/chat/route.ts" {1,6,8} import { mastra } from "@/mastra"; export async function POST(req: Request) { const { messages } = await req.json(); const agent = mastra.getAgent("chefAgent"); const stream = await agent.stream(messages); return stream.toDataStreamResponse(); } ``` 主な変更点 * 作成した`mastra`インスタンスをインポートします。 * `mastra.getAgent("chefAgent")`を使用して、使用したいエージェントを取得します。 * `agent.stream(messages)`を使用して、エージェントからのメッセージストリームを取得します。 * `assistant-ui`と互換性のあるデータストリームレスポンスとしてストリームを返します。 ### アプリケーションを実行する すべて設定完了です!Next.js開発サーバーを起動します: ```bash copy npm run dev ``` これで、ブラウザでエージェントとチャットできるようになります。 おめでとうございます!フルスタックアプローチを使用して、Next.jsアプリケーションにMastraを正常に統合しました。Assistant UIフロントエンドが、Next.jsバックエンドAPIルートで実行されているMastraエージェントと通信するようになりました。 ## 独立したバックエンド統合 Mastraをスタンドアロンサーバーとして実行し、Next.jsフロントエンド(Assistant UI付き)をそのAPIエンドポイントに接続します。 ### スタンドアロンMastraサーバーの作成 ディレクトリ構造を設定します。可能なディレクトリ構造は次のようになります: Mastraサーバーをブートストラップします: ```bash copy npx create-mastra@latest ``` このコマンドは、新しいMastraプロジェクトをスキャフォールドするためのインタラクティブなウィザードを起動し、プロジェクト名の入力を求めて基本的な設定を行います。 プロンプトに従ってサーバープロジェクトを作成してください。 これで基本的なMastraサーバープロジェクトの準備が整いました。 `.env`ファイルでLLMプロバイダーの適切な環境変数を設定していることを確認してください。 ### Mastraエージェントの定義 ```typescript showLineNumbers copy filename="mastra/agents/chef-agent.ts" {5-12} import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { memory} from "../memory"; export const chefAgent = new Agent({ name: "chefAgent", instructions: "You are Michel, a practical and experienced home chef. " + "You help people cook with whatever ingredients they have available.", model: openai("gpt-4o-mini"), memory, }); ``` ### エージェントをMastraインスタンスに登録 ```typescript copy filename="mastra/index.ts" showLineNumbers import { Mastra } from "@mastra/core"; import { chefAgent } from "./agents/chef-agent"; export const mastra = new Mastra({ agents: { chefAgent }, // ... other config }); ``` ### Mastraサーバーの実行 次のコマンドを使用してMastraサーバーを実行します: ```bash copy npm run dev ``` デフォルトでは、Mastraサーバーはhttp://localhost:4111で実行されます。chefAgentは通常、POSTリクエストエンドポイント(http://localhost:4111/api/agents/chefAgent/stream)経由でアクセス可能になります。次のステップでAssistant UIフロントエンドを設定して接続するため、このサーバーを実行し続けてください。 ### Assistant UIの初期化 `assistant-ui` CLIを使用してAssistant UIを設定する際には、2つのオプションがあります: 1. **新規プロジェクト**: Assistant UI付きの新しいNext.jsプロジェクトを作成します。 2. **既存プロジェクト**: 既存のReactプロジェクトにAssistant UIを初期化します。 #### 新規プロジェクト ```bash copy npx assistant-ui@latest create ``` #### 既存プロジェクト ```bash copy npx assistant-ui@latest init ``` APIキーの追加、基本設定、手動セットアップ手順を含む詳細なセットアップ手順については、[assistant-uiの公式ドキュメント](https://assistant-ui.com/docs)を参照してください。 ### フロントエンドAPIエンドポイントの設定 デフォルトのAssistant UIセットアップでは、Next.jsプロジェクト内のローカルAPIルート(`/api/chat`)を使用するようにチャットランタイムが設定されています。Mastraエージェントが別のサーバーで実行されているため、フロントエンドをそのサーバーのエンドポイントを指すように更新する必要があります。 Assistant UIフロントエンドプロジェクトのメインページファイル(通常は`app/page.tsx`または`src/app/page.tsx`)を開きます。`useChatRuntime`フックを見つけて、`api`プロパティをMastraエージェントのストリームエンドポイントの完全なURLに変更します: ```typescript showLineNumbers copy filename="app/page.tsx" {2} const runtime = useChatRuntime({ api: "http://localhost:4111/api/agents/chefAgent/stream", }); ``` これで、Assistant UIフロントエンドは実行中のMastraサーバーに直接チャットリクエストを送信するようになります。 ### アプリケーションの実行 パーツを接続する準備が整いました!MastraサーバーとAssistant UIフロントエンドの両方が実行されていることを確認してください。Next.js開発サーバーを起動します: ```bash copy npm run dev ``` これで、ブラウザでエージェントとチャットできるようになります。 おめでとうございます!独立したサーバーアプローチを使用してMastraとAssistant UIの統合に成功しました。Assistant UIフロントエンドは、スタンドアロンのMastraエージェントサーバーと通信するようになりました。 --- title: "CopilotKitとの使用" description: "MastraがCopilotKitのAGUIライブラリをどのように活用し、ユーザーエクスペリエンスの構築にどのように活用できるかを学ぶ" --- import { Tabs } from "nextra/components"; import Image from "next/image"; # ReactでCopilotKitを使用する [JA] Source: https://mastra.ai/ja/docs/frameworks/agentic-uis/copilotkit CopilotKitは、カスタマイズ可能なAIコパイロットをアプリケーションに素早く統合するためのReactコンポーネントを提供します。 Mastraと組み合わせることで、双方向の状態同期とインタラクティブなUIを特徴とする洗練されたAIアプリを構築できます。 ## Mastraプロジェクトを作成する {/* LLM CONTEXT: This Tabs component shows commands for creating a new Mastra project using different package managers. Each tab displays the command for that specific package manager to create a Mastra project. This is the first step in setting up Mastra with CopilotKit for building AI copilot applications. All commands create the same Mastra project but use different package manager syntax. */} ```bash copy npx create-mastra@latest ``` ```bash copy npm create mastra ``` ```bash copy yarn create mastra ``` ```bash copy pnpm create mastra ``` プロジェクトをスキャフォールディングする際は、agentの例を選択してください。これにより、天気エージェントが提供されます。 詳細なセットアップ手順については、[インストールガイド](/docs/getting-started/installation)を参照してください。 ## 基本セットアップ MastraとCopilotKitの統合には、主に2つのステップが含まれます:バックエンドランタイムのセットアップとフロントエンドコンポーネントの設定です。 {/* LLM CONTEXT: This Tabs component shows installation commands for the CopilotKit runtime package. Each tab displays the installation command for that specific package manager. This installs the core CopilotKit runtime needed for backend integration with Mastra. All commands install the same @copilotkit/runtime package but use different package manager syntax. */} ```bash copy npm install @copilotkit/runtime ``` ```bash copy yarn add @copilotkit/runtime ``` ```bash copy pnpm add @copilotkit/runtime ``` ## ランタイムのセットアップ Mastraのカスタム API ルートを活用して、Mastra サーバーに CopilotKit のランタイムを追加できます。 現在のバージョンの統合では、`MastraClient` を使用して Mastra エージェントを CopilotKit の AGUI 形式にフォーマットします。 {/* LLM CONTEXT: This Tabs component shows installation commands for the Mastra AGUI package. Each tab displays the installation command for that specific package manager. This installs the alpha version of @mastra/agui which provides CopilotKit integration capabilities. All commands install the same @mastra/agui@alpha package but use different package manager syntax. */} ```bash copy npm install @mastra/agui@alpha ``` ```bash copy yarn add @mastra/agui@alpha ``` ```bash copy pnpm add @mastra/agui@alpha ``` 次に、CopilotKit 用のカスタム API ルートで Mastra インスタンスを更新しましょう。 ```typescript filename="src/mastra/index.ts" showLineNumbers copy import { Mastra } from "@mastra/core/mastra"; import { PinoLogger } from "@mastra/loggers"; import { LibSQLStore } from "@mastra/libsql"; import { CopilotRuntime, copilotRuntimeNodeHttpEndpoint, ExperimentalEmptyAdapter } from "@copilotkit/runtime"; import { registerCopilotKit } from "@mastra/agui"; import { weatherAgent } from "./agents/weather-agent"; const serviceAdapter = new ExperimentalEmptyAdapter(); export const mastra = new Mastra({ agents: { weatherAgent }, storage: new LibSQLStore({ // stores telemetry, evals, ... into memory storage, // if you need to persist, change to file:../mastra.db url: ":memory:" }), logger: new PinoLogger({ name: "Mastra", level: "info" }), server: { // We will be calling this from a Vite App. Allow CORS cors: { origin: "*", allowMethods: ["*"], allowHeaders: ["*"] }, apiRoutes: [ registerCopilotKit({ path: "/copilotkit", resourceId: "weatherAgent", setContext: (c, runtimeContext) => { // Add whatever you need to the runtimeContext runtimeContext.set("user-id", c.req.header("X-User-ID")); runtimeContext.set("temperature-scale", "celsius"); } }) ] } }); ``` このセットアップにより、Mastra サーバー上で CopilotKit が実行されるようになりました。`mastra dev` で Mastra サーバーを起動できます。 ## UIの設定 CopilotKitのReactコンポーネントをインストールします: {/* LLM CONTEXT: This Tabs component shows installation commands for CopilotKit's React UI components. Each tab displays the installation command for that specific package manager. This installs the React components needed for the frontend CopilotKit integration. All commands install the same @copilotkit/react-core and @copilotkit/react-ui packages but use different package manager syntax. */} ```bash copy npm install @copilotkit/react-core @copilotkit/react-ui ``` ```bash copy yarn add @copilotkit/react-core @copilotkit/react-ui ``` ```bash copy pnpm add @copilotkit/react-core @copilotkit/react-ui ``` 次に、CopilotKitのReactコンポーネントをフロントエンドに追加します。 ```jsx copy import { CopilotChat } from "@copilotkit/react-ui"; import { CopilotKit } from "@copilotkit/react-core"; import "@copilotkit/react-ui/styles.css"; export function CopilotKitComponent() { return ( ); } ``` コンポーネントをレンダリングして、未来の構築を始めましょう!
CopilotKit output ## 他のフレームワークでの使用 (NextJS) Mastra Serverを経由せずにAGUIを活用することも可能です。 ```typescript copy // import your mastra instance from dir import { mastra } from "../path/to/mastra"; import { CopilotRuntime, ExperimentalEmptyAdapter, copilotRuntimeNextJSAppRouterEndpoint, } from "@copilotkit/runtime"; import { NextRequest } from "next/server"; export const POST = async (req: NextRequest) => { // Clone the request before reading the body const clonedReq = req.clone(); const body = await clonedReq.json(); const resourceId = body.resourceId || "TEST"; const mastraAgents = getAGUI({ mastra, resourceId, }); const runtime = new CopilotRuntime({ agents: mastraAgents, }); const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({ runtime, serviceAdapter: new ExperimentalEmptyAdapter(), endpoint: "/api/copilotkit", }); // Use the original request for handleRequest return handleRequest(req); }; ``` ### 型付きランタイムコンテキストの使用 より良い型安全性のために、ランタイムコンテキストの型を指定できます: ```typescript filename="src/mastra/index.ts" showLineNumbers copy import { Mastra } from "@mastra/core/mastra"; import { PinoLogger } from "@mastra/loggers"; import { LibSQLStore } from "@mastra/libsql"; import { registerCopilotKit } from "@mastra/agui"; import { weatherAgent } from "./agents"; // Define your runtime context type type WeatherRuntimeContext = { "user-id": string; "temperature-scale": "celsius" | "fahrenheit"; "api-key": string; }; export const mastra = new Mastra({ agents: { weatherAgent }, storage: new LibSQLStore({ url: ":memory:", }), logger: new PinoLogger({ name: "Mastra", level: "info", }), server: { cors: { origin: "*", allowMethods: ["*"], allowHeaders: ["*"], }, apiRoutes: [ registerCopilotKit({ path: "/copilotkit", resourceId: "weatherAgent", setContext: (c, runtimeContext) => { // TypeScript will enforce the correct types here runtimeContext.set("user-id", c.req.header("X-User-ID") || "anonymous"); runtimeContext.set("temperature-scale", "celsius"); // Only "celsius" | "fahrenheit" allowed runtimeContext.set("api-key", process.env.WEATHER_API_KEY || ""); // This would cause a TypeScript error: // runtimeContext.set("invalid-key", "value"); // ❌ Error: invalid key // runtimeContext.set("temperature-scale", "kelvin"); // ❌ Error: invalid value } }), ], }, }); ``` ## さらに詳しく - [CopilotKit Documentation](https://docs.copilotkit.ai) - [React Hooks with CopilotKit](https://docs.copilotkit.ai/reference/hooks/useCoAgent) --- title: "OpenRouterとの使用" description: "OpenRouterをMastraと統合する方法を学ぶ" --- import { Steps } from 'nextra/components' # MastraでOpenRouterを使用する [JA] Source: https://mastra.ai/ja/docs/frameworks/agentic-uis/openrouter OpenRouterをMastraと統合して、OpenRouterで利用可能な多数のモデルを活用しましょう。 ## Mastraプロジェクトを初期化する Mastraを始める最も簡単な方法は、`mastra` CLIを使用して新しいプロジェクトを初期化することです: ```bash copy npx create-mastra@latest ``` プロジェクトをセットアップするためのプロンプトが表示されます。この例では、以下を選択してください: - プロジェクト名:my-mastra-openrouter-app - コンポーネント:Agents(推奨) - デフォルトプロバイダーには、OpenAI(推奨)を選択 - 後でOpenRouterを手動で設定します - オプションでサンプルコードを含める ## OpenRouterを設定する `create-mastra`でプロジェクトを作成した後、プロジェクトルートに`.env`ファイルが見つかります。 セットアップ時にOpenAIを選択したので、OpenRouterを手動で設定します: ```bash filename=".env" copy OPENROUTER_API_KEY= ``` プロジェクトから`@ai-sdk/openai`パッケージを削除します: ```bash copy npm uninstall @ai-sdk/openai ``` 次に、`@openrouter/ai-sdk-provider`パッケージをインストールします: ```bash copy npm install @openrouter/ai-sdk-provider ``` ## AgentでOpenRouterを使用するように設定する エージェントがOpenRouterを使用するように設定します。 ```typescript filename="src/mastra/agents/assistant.ts" copy showLineNumbers {4-6,11} import { Agent } from "@mastra/core/agent"; import { createOpenRouter } from "@openrouter/ai-sdk-provider"; const openrouter = createOpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, }) export const assistant = new Agent({ name: "assistant", instructions: "You are a helpful assistant.", model: openrouter("anthropic/claude-sonnet-4"), }) ``` エージェントをMastraインスタンスに登録することを忘れずに: ```typescript filename="src/mastra/index.ts" copy showLineNumbers {4} import { assistant } from "./agents/assistant"; export const mastra = new Mastra({ agents: { assistant } }) ``` ## エージェントを実行してテストする ```bash copy npm run dev ``` これによりMastra開発サーバーが起動します。 プレイグラウンドの場合は[http://localhost:4111](http://localhost:4111)にアクセスするか、Mastra APIの[http://localhost:4111/api/agents/assistant/stream](http://localhost:4111/api/agents/assistant/stream)経由でエージェントをテストできます。 ## 高度な設定 OpenRouterリクエストをより詳細に制御するために、追加の設定オプションを渡すことができます。 ### プロバイダー全体のオプション: OpenRouterプロバイダーにプロバイダー全体のオプションを渡すことができます: ```typescript filename="src/mastra/agents/assistant.ts" {6-10} copy showLineNumbers import { Agent } from "@mastra/core/agent"; import { createOpenRouter } from "@openrouter/ai-sdk-provider"; const openrouter = createOpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, extraBody: { reasoning: { max_tokens: 10, } } }) export const assistant = new Agent({ name: "assistant", instructions: "You are a helpful assistant.", model: openrouter("anthropic/claude-sonnet-4"), }) ``` ### モデル固有のオプション: OpenRouterプロバイダーにモデル固有のオプションを渡すことができます: ```typescript filename="src/mastra/agents/assistant.ts" {11-17} copy showLineNumbers import { Agent } from "@mastra/core/agent"; import { createOpenRouter } from "@openrouter/ai-sdk-provider"; const openrouter = createOpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, }) export const assistant = new Agent({ name: "assistant", instructions: "You are a helpful assistant.", model: openrouter("anthropic/claude-sonnet-4", { extraBody: { reasoning: { max_tokens: 10, } } }), }) ``` ### プロバイダー固有のオプション: OpenRouterプロバイダーにプロバイダー固有のオプションを渡すことができます: ```typescript copy showLineNumbers {7-12} // プロバイダー固有のオプションでレスポンスを取得 const response = await assistant.generate([ { role: 'system', content: 'You are Chef Michel, a culinary expert specializing in ketogenic (keto) diet...', providerOptions: { // プロバイダー固有のオプション - キーは 'anthropic' または 'openrouter' を指定可能 anthropic: { cacheControl: { type: 'ephemeral' }, }, }, }, { role: 'user', content: 'Can you suggest a keto breakfast?', }, ]); ``` --- title: "Vercel AI SDKとの併用" description: "MastraがVercel AI SDKライブラリをどのように活用しているか、そしてMastraでさらにどのように活用できるかを学ぶ" --- import Image from "next/image"; # Vercel AI SDKと一緒に使用する [JA] Source: https://mastra.ai/ja/docs/frameworks/ai-sdk Mastraは、AI SDKのモデルルーティング(OpenAI、Anthropicなどの上に統一されたインターフェース)、構造化された出力、およびツール呼び出しを活用しています。 これについては、[このブログ記事](https://mastra.ai/blog/using-ai-sdk-with-mastra)でより詳しく説明しています ## Mastra + AI SDK Mastraは、チームが概念実証を迅速かつ容易に製品化するのを支援するために、AI SDKの上に層として機能します。 スパン、LLM呼び出し、ツール実行を示すエージェントインタラクショントレース ## モデルルーティング Mastraでエージェントを作成する際、AI SDKがサポートするどのモデルでも指定できます: ```typescript import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; const agent = new Agent({ name: "WeatherAgent", instructions: "Instructions for the agent...", model: openai("gpt-4-turbo"), // Model comes directly from AI SDK }); const result = await agent.generate("What is the weather like?"); ``` ## AI SDKフック Mastraは、フロントエンドとのシームレスな統合のためにAI SDKのフックと互換性があります: ### useChat `useChat`フックを使用すると、フロントエンドアプリケーションでリアルタイムのチャット対話が可能になります - エージェントデータストリーム(`.toDataStreamResponse()`)と連携します - useChatの`api`はデフォルトで`/api/chat`に設定されています - Mastra REST APIのエージェントストリームエンドポイント`{MASTRA_BASE_URL}/agents/:agentId/stream`とデータストリーム用に連携します。 つまり、構造化された出力は定義されていません。 ```typescript filename="app/api/chat/route.ts" copy import { mastra } from "@/src/mastra"; export async function POST(req: Request) { const { messages } = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); const stream = await myAgent.stream(messages); return stream.toDataStreamResponse(); } ``` ```typescript copy import { useChat } from '@ai-sdk/react'; export function ChatComponent() { const { messages, input, handleInputChange, handleSubmit } = useChat({ api: '/path-to-your-agent-stream-api-endpoint' }); return (
{messages.map(m => (
{m.role}: {m.content}
))}
); } ``` > **注意点**: エージェントのメモリ機能と`useChat`を使用する場合は、重要な実装の詳細について[エージェントメモリセクション](/docs/agents/agent-memory#usechat)を確認してください。 ### useCompletion 単一ターンの補完には、`useCompletion`フックを使用します: - エージェントデータストリーム(`.toDataStreamResponse()`)と連携します - useCompletionの`api`はデフォルトで`/api/completion`に設定されています - Mastra REST APIのエージェントストリームエンドポイント`{MASTRA_BASE_URL}/agents/:agentId/stream`とデータストリーム用に連携します。 つまり、構造化された出力は定義されていません。 ```typescript filename="app/api/completion/route.ts" copy import { mastra } from "@/src/mastra"; export async function POST(req: Request) { const { prompt } = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); const stream = await myAgent.stream([{ role: "user", content: prompt }]); return stream.toDataStreamResponse(); } ``` ```typescript import { useCompletion } from "@ai-sdk/react"; export function CompletionComponent() { const { completion, input, handleInputChange, handleSubmit, } = useCompletion({ api: '/path-to-your-agent-stream-api-endpoint' }); return (

Completion result: {completion}

); } ``` ### useObject スキーマに基づいてJSONオブジェクトを表すテキストストリームを消費し、完全なオブジェクトに解析するために使用します。 - エージェントテキストストリーム(`.toTextStreamResponse()`)と連携します - Mastra REST APIのエージェントストリームエンドポイント`{MASTRA_BASE_URL}/agents/:agentId/stream`とテキストストリーム用に連携します。 つまり、構造化された出力が定義されています。 ```typescript filename="app/api/use-object/route.ts" copy import { mastra } from "@/src/mastra"; export async function POST(req: Request) { const body = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); const stream = await myAgent.stream(body, { output: z.object({ weather: z.string(), }), }); return stream.toTextStreamResponse(); } ``` ```typescript import { experimental_useObject as useObject } from '@ai-sdk/react'; export default function Page() { const { object, submit } = useObject({ api: '/api/use-object', schema: z.object({ weather: z.string(), }), }); return (
{object?.weather &&

{object.weather}

}
); } ``` ## ツール呼び出し ### AI SDK ツールフォーマット Mastraは、AI SDKフォーマットで作成されたツールをサポートしているため、Mastraエージェントと直接使用することができます。詳細については、[Vercel AI SDKツールフォーマット](/docs/agents/adding-tools#vercel-ai-sdk-tool-format)に関するツールドキュメントをご覧ください。 ### クライアントサイドのツール呼び出し MastraはAI SDKのツール呼び出し機能を活用しているため、AI SDKに適用されることはここでも同様に適用されます。 Mastraの[エージェントツール](/docs/agents/adding-tools)は、AI SDKツールと100%互換性があります。 Mastraツールはオプションの`execute`非同期関数も公開しています。これがオプションである理由は、ツール呼び出しをクライアントやキューに転送する場合があり、同じプロセスで実行したくない場合があるためです。 クライアントサイドのツール呼び出しを活用する一つの方法は、クライアントサイドのツール実行のために`@ai-sdk/react`の`useChat`フックの`onToolCall`プロパティを使用することです。 ## カスタムDataStream 特定のシナリオでは、エージェントのdataStreamにカスタムデータやメッセージ注釈を書き込む必要があります。 これは以下のような場合に役立ちます: - クライアントに追加データをストリーミングする - 進行状況の情報をリアルタイムでクライアントに返す MastraはAI SDKとうまく統合して、これを可能にします ### CreateDataStream `createDataStream`関数を使用すると、クライアントに追加データをストリーミングできます ```typescript copy import { createDataStream } from "ai"; import { Agent } from "@mastra/core/agent"; export const weatherAgent = new Agent({ name: "Weather Agent", instructions: ` You are a helpful weather assistant that provides accurate weather information. Your primary function is to help users get weather details for specific locations. When responding: - Always ask for a location if none is provided - If the location name isn't in English, please translate it - If giving a location with multiple parts (e.g. "New York, NY"), use the most relevant part (e.g. "New York") - Include relevant details like humidity, wind conditions, and precipitation - Keep responses concise but informative Use the weatherTool to fetch current weather data. `, model: openai("gpt-4o"), tools: { weatherTool }, }); const stream = createDataStream({ async execute(dataStream) { // Write data dataStream.writeData({ value: "Hello" }); // Write annotation dataStream.writeMessageAnnotation({ type: "status", value: "processing" }); //mastra agent stream const agentStream = await weatherAgent.stream("What is the weather"); // Merge agent stream agentStream.mergeIntoDataStream(dataStream); }, onError: (error) => `Custom error: ${error.message}`, }); ``` ### CreateDataStreamResponse `createDataStreamResponse`関数は、クライアントにデータをストリーミングするResponseオブジェクトを作成します ```typescript filename="app/api/chat/route.ts" copy import { mastra } from "@/src/mastra"; export async function POST(req: Request) { const { messages } = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); //mastra agent stream const agentStream = await myAgent.stream(messages); const response = createDataStreamResponse({ status: 200, statusText: "OK", headers: { "Custom-Header": "value", }, async execute(dataStream) { // Write data dataStream.writeData({ value: "Hello" }); // Write annotation dataStream.writeMessageAnnotation({ type: "status", value: "processing", }); // Merge agent stream agentStream.mergeIntoDataStream(dataStream); }, onError: (error) => `Custom error: ${error.message}`, }); return response; } ``` --- title: "CopilotKitとの使用" description: "MastraがCopilotKitのAGUIライブラリをどのように活用しているか、そしてユーザーエクスペリエンスを構築するためにどのように活用できるかを学びましょう" --- import { Tabs } from "nextra/components"; import Image from "next/image"; # React で CopilotKit を使用する [JA] Source: https://mastra.ai/ja/docs/frameworks/copilotkit CopilotKitは、カスタマイズ可能なAIコパイロットをアプリケーションに素早く統合するためのReactコンポーネントを提供します。 Mastraと組み合わせることで、双方向の状態同期とインタラクティブなUIを備えた高度なAIアプリを構築できます。 ## Mastraプロジェクトを作成する `mastra` CLIを使用して新しいMastraプロジェクトを作成します: ```bash copy npx create-mastra@latest ``` ```bash copy npm create mastra ``` ```bash copy yarn create mastra ``` ```bash copy pnpm create mastra ``` プロジェクトの構築時にエージェントの例を選択してください。これにより、天気エージェントが提供されます。 詳細なセットアップ手順については、[インストールガイド](/docs/getting-started/installation)を参照してください。 ## 基本的なセットアップ MastraとCopilotKitを統合するには、主に2つのステップがあります:バックエンドランタイムのセットアップとフロントエンドコンポーネントの設定です。 ```bash copy npm install @copilotkit/runtime ``` ```bash copy yarn add @copilotkit/runtime ``` ```bash copy pnpm add @copilotkit/runtime ``` ## ランタイムのセットアップ MastraのカスタムAPIルートを活用して、CopilotKitのランタイムをMastraサーバーに追加することができます。 現在のバージョンの統合では、`MastraClient`を使用してMastraエージェントをCopilotKitのAGUI形式にフォーマットしています。 ```bash copy npm install @mastra/client-js ``` ```bash copy yarn add @mastra/client-js ``` ```bash copy pnpm add @mastra/client-js ``` 次に、CopilotKit用のカスタムAPIルートでMastraインスタンスを更新しましょう。 ```typescript copy import { Mastra } from "@mastra/core/mastra"; import { PinoLogger } from "@mastra/loggers"; import { LibSQLStore } from "@mastra/libsql"; import { registerApiRoute } from "@mastra/core/server"; import { CopilotRuntime, copilotRuntimeNodeHttpEndpoint, ExperimentalEmptyAdapter, } from "@copilotkit/runtime"; import { MastraClient } from "@mastra/client-js"; import { weatherAgent } from "./agents"; const serviceAdapter = new ExperimentalEmptyAdapter(); export const mastra = new Mastra({ agents: { weatherAgent }, storage: new LibSQLStore({ // stores telemetry, evals, ... into memory storage, // if you need to persist, change to file:../mastra.db url: ":memory:", }), logger: new PinoLogger({ name: "Mastra", level: "info", }), server: { apiRoutes: [ registerApiRoute("/copilotkit", { method: `POST`, handler: async (c) => { // N.B. Current integration leverages MastraClient to fetch AGUI. // Future versions will support fetching AGUI from mastra context. const client = new MastraClient({ baseUrl: "http://localhost:4111", }); const runtime = new CopilotRuntime({ agents: await client.getAGUI({ resourceId: "weatherAgent" }), }); const handler = copilotRuntimeNodeHttpEndpoint({ endpoint: "/copilotkit", runtime, serviceAdapter, }); return handler.handle(c.req.raw, {}); }, }), ], }, }); ``` このセットアップにより、MastraサーバーでCopilotKitが実行されるようになりました。`mastra dev`コマンドでMastraサーバーを起動できます。 ## UIのセットアップ CopilotKitのReactコンポーネントをインストールします: ```bash copy npm install @copilotkit/react-core @copilotkit/react-ui ``` ```bash copy yarn add @copilotkit/react-core @copilotkit/react-ui ``` ```bash copy pnpm add @copilotkit/react-core @copilotkit/react-ui ``` 次に、CopilotKitのReactコンポーネントをフロントエンドに追加します。 ```jsx copy import { CopilotChat } from "@copilotkit/react-ui"; import { CopilotKit } from "@copilotkit/react-core"; import "@copilotkit/react-ui/styles.css"; export function CopilotKitComponent() { return ( ); } ``` コンポーネントをレンダリングして、未来の構築を始めましょう!
CopilotKit出力 ## 参考文献 - [CopilotKit ドキュメント](https://docs.copilotkit.ai) - [CopilotKitを使用したReact Hooks](https://docs.copilotkit.ai/reference/hooks/useCoAgent) --- title: "Mastra と NextJS のはじめ方 | Mastra ガイド" description: Mastra を NextJS と統合するためのガイド。 --- import { Callout, Steps, Tabs } from "nextra/components"; # Next.jsプロジェクトにMastraを統合する [JA] Source: https://mastra.ai/ja/docs/frameworks/next-js MastraをNext.jsアプリケーションに統合する主な方法は2つあります:別個のバックエンドサービスとして、またはNext.jsアプリに直接統合する方法です。 ## 1. バックエンドの個別統合 以下を実現したい大規模プロジェクトに最適: - AIバックエンドを独立してスケーリング - 明確な関心の分離を維持 - より柔軟なデプロイメント ### Mastraバックエンドの作成 CLIを使用して新しいMastraプロジェクトを作成します: ```bash copy npx create-mastra@latest ``` ```bash copy npm create mastra ``` ```bash copy yarn create mastra ``` ```bash copy pnpm create mastra ``` 詳細なセットアップ手順については、[インストールガイド](/docs/getting-started/installation)をご覧ください。 ### MastraClientのインストール ```bash copy npm install @mastra/client-js@latest ``` ```bash copy yarn add @mastra/client-js@latest ``` ```bash copy pnpm add @mastra/client-js@latest ``` ```bash copy bun add @mastra/client-js@latest ``` ### MastraClientの使用 クライアントインスタンスを作成し、Next.jsアプリケーションで使用します: ```typescript filename="lib/mastra.ts" copy import { MastraClient } from "@mastra/client-js"; // Initialize the client export const mastraClient = new MastraClient({ baseUrl: process.env.NEXT_PUBLIC_MASTRA_API_URL || "http://localhost:4111", }); ``` Reactコンポーネントでの使用例: ```typescript filename="app/components/SimpleWeather.tsx" copy 'use client' import { mastraClient } from '@/lib/mastra' export function SimpleWeather() { async function handleSubmit(formData: FormData) { const city = formData.get('city') const agent = mastraClient.getAgent('weatherAgent') try { const response = await agent.generate({ messages: [{ role: 'user', content: `What's the weather like in ${city}?` }], }) // Handle the response console.log(response.text) } catch (error) { console.error('Error:', error) } } return (
) } ``` ### デプロイメント デプロイの準備ができたら、プラットフォーム固有のデプロイヤー(Vercel、Netlify、Cloudflare)を使用するか、任意のNode.jsホスティングプラットフォームにデプロイできます。詳細な手順については、[デプロイメントガイド](/docs/deployment/deployment)をご確認ください。
## 2. 直接統合 小規模なプロジェクトやプロトタイプに適しています。このアプローチではMastraをNext.jsアプリケーションに直接バンドルします。 ### Next.jsのルートでMastraを初期化する まず、Next.jsプロジェクトのルートに移動し、Mastraを初期化します: ```bash copy cd your-nextjs-app ``` 次に初期化コマンドを実行します: ```bash copy npx mastra@latest init ``` ```bash copy yarn dlx mastra@latest init ``` ```bash copy pnpm dlx mastra@latest init ``` これによりNext.jsプロジェクトにMastraがセットアップされます。初期化やその他の設定オプションの詳細については、[mastra init リファレンス](/reference/cli/init)をご覧ください。 ### Next.jsの設定 `next.config.js`に以下を追加します: ```js filename="next.config.js" copy /** @type {import('next').NextConfig} */ const nextConfig = { serverExternalPackages: ["@mastra/*"], // ... その他のNext.js設定 }; module.exports = nextConfig; ``` #### サーバーアクションの例 ```typescript filename="app/actions.ts" copy "use server"; import { mastra } from "@/mastra"; export async function getWeatherInfo(city: string) { const agent = mastra.getAgent("weatherAgent"); const result = await agent.generate(`What's the weather like in ${city}?`); return result; } ``` コンポーネントでの使用方法: ```typescript filename="app/components/Weather.tsx" copy 'use client' import { getWeatherInfo } from '../actions' export function Weather() { async function handleSubmit(formData: FormData) { const city = formData.get('city') as string const result = await getWeatherInfo(city) // 結果を処理する console.log(result) } return (
) } ``` #### APIルートの例 ```typescript filename="app/api/chat/route.ts" copy import { mastra } from "@/mastra"; import { NextResponse } from "next/server"; export async function POST(req: Request) { const { city } = await req.json(); const agent = mastra.getAgent("weatherAgent"); const result = await agent.stream(`What's the weather like in ${city}?`); return result.toDataStreamResponse(); } ``` ### デプロイメント 直接統合を使用する場合、MastraインスタンスはNext.jsアプリケーションと一緒にデプロイされます。以下を確認してください: - デプロイメントプラットフォームでLLM APIキーの環境変数を設定する - 本番環境での適切なエラーハンドリングを実装する - AIエージェントのパフォーマンスとコストを監視する
## オブザーバビリティ Mastra は、AI オペレーションの監視、デバッグ、最適化を支援するための組み込みオブザーバビリティ機能を提供します。これには以下が含まれます: - AI オペレーションとそのパフォーマンスのトレーシング - プロンプト、コンプリーション、エラーのロギング - Langfuse や LangSmith などのオブザーバビリティプラットフォームとの統合 Next.js のローカル開発に特化した詳細なセットアップ手順や設定オプションについては、[Next.js オブザーバビリティ設定ガイド](/docs/observability/nextjs-tracing)をご覧ください。 --- title: "MastraとExpressを使い始める | Mastraガイド" description: MastraをExpressバックエンドと統合するためのステップバイステップガイド。 --- import { Callout, Steps, Tabs, FileTree } from "nextra/components"; # ExpressプロジェクトにMastraを統合する [JA] Source: https://mastra.ai/ja/docs/frameworks/servers/express MastraはExpressと統合し、以下を簡単に実現できます: - AI機能を提供する柔軟なAPIの構築 - サーバーロジックとルーティングの完全な制御の維持 - フロントエンドから独立したバックエンドのスケーリング このガイドを使用して、ExpressプロジェクトでMastraをスキャフォールドし統合してください。 このセットアップは以下のパッケージバージョンと互換性があります: - `express`: 4.x - `@types/express`: 4.x `express`と`@types/express`が整合性に向けて進化している間、5.xでの型互換性は一貫していない場合があります。 ## Mastraをインストール 必要なMastraパッケージをインストールします: ```bash copy npm install mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy yarn add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy pnpm add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy bun add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ## Mastraを統合する プロジェクトにMastraを統合するには、2つのオプションがあります: ### 1. ワンライナーを使用する 以下のコマンドを実行して、適切なデフォルト設定でデフォルトのWeatherエージェントを素早くスキャフォールドします: ```bash copy npx mastra@latest init --default ``` > 詳細については[mastra init](/reference/cli/init)を参照してください。 ### 2. インタラクティブCLIを使用する セットアップをカスタマイズしたい場合は、`init`コマンドを実行し、プロンプトが表示されたときにオプションから選択してください: ```bash copy npx mastra@latest init ``` `package.json`に`dev`と`build`スクリプトを追加します: ```json filename="package.json" { "scripts": { ... "dev": "mastra dev", "build": "mastra build" } } ``` > プロジェクトで既に`dev`と`build`スクリプトを使用している場合は、`dev:mastra`と`build:mastra`を使用することをお勧めします。 ## TypeScriptの初期化 プロジェクトルートに以下の設定で`tsconfig.json`ファイルを作成してください: ```json filename="tsconfig.json" copy { "compilerOptions": { "target": "ES2022", "module": "ES2022", "moduleResolution": "bundler", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true, "outDir": "dist" }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", ".mastra"] } ``` > このTypeScript設定はMastraプロジェクト用に最適化されており、モダンなモジュール解決と厳密な型チェックを使用しています。 ## API キーの設定 ```bash filename=".env" copy OPENAI_API_KEY= ``` > 各LLMプロバイダーは異なる環境変数を使用します。詳細については[モデル機能](/docs/getting-started/model-capability)を参照してください。 ## Mastra Dev Serverを開始する Mastra dev serverを開始して、エージェントをREST エンドポイントとして公開します: ```bash copy npm run dev ``` ```bash copy mastra dev ``` > 実行すると、エージェントがローカルで利用可能になります。詳細については[Local Development Environment](/docs/local-dev/mastra-dev)を参照してください。 ## Express アプリの例 この例では、`city` クエリパラメータを期待する `/api/weather` エンドポイントを作成します。 ```typescript filename="src/server.ts" showLineNumbers copy import "dotenv/config"; import express, { Request, Response } from "express"; import { mastra } from "./mastra"; const app = express(); const port = process.env.PORT ?? 3000; app.get("/api/weather", async (req: Request, res: Response) => { const { city } = req.query as { city?: string }; if (!city) { return res.status(400).send("Missing 'city' query parameter"); } const agent = mastra.getAgent("weatherAgent"); try { const result = await agent.generate(`What's the weather like in ${city}?`); res.send(result.text); } catch (error) { console.error("Agent error:", error); res.status(500).send("An error occurred while processing your request"); } }); app.listen(port, () => { console.log(`Server listening on port ${port}`); }); ``` Mastra 開発サーバーを実行した状態で、Express アプリを別途起動します。例: ```bash copy npx tsx --watch src/server.ts --watch-dir src ``` 以下のいずれかを使用してエンドポイントにリクエストを送信できます: ```bash copy http://localhost:3000/api/weather?city=London ``` ```bash copy curl "http://localhost:3000/api/weather?city=London" ``` 以下のような出力が表示されるはずです: ```plaintext The current weather in London is as follows: - **Temperature:** 12.9°C (Feels like 9.7°C) - **Humidity:** 63% - **Wind Speed:** 14.7 km/h - **Wind Gusts:** 32.4 km/h - **Conditions:** Overcast Let me know if you need more information! ``` ## 次のステップ - [Mastra Client SDK](/docs/deployment/client) --- title: "MastraとAstroを始める | Mastraガイド" description: MastraをAstroと統合するためのステップバイステップガイド。 --- import { Callout, Steps, Tabs } from "nextra/components"; # AstroプロジェクトにMastraを統合する [JA] Source: https://mastra.ai/ja/docs/frameworks/web-frameworks/astro MastraはAstroと統合し、以下を簡単に実現できます: - AI機能を提供する柔軟なAPIの構築 - フロントエンドとバックエンドの統一されたコードベースによるデプロイメントの簡素化 - 効率的なサーバー・クライアントワークフローのためのAstroの組み込み[Actions](https://docs.astro.build/en/guides/actions/)または[Server Endpoints](https://docs.astro.build/en/guides/endpoints/#server-endpoints-api-routes)の活用 このガイドを使用して、AstroプロジェクトでMastraをスキャフォールドし統合してください。 このガイドでは、ReactとVercelアダプターを使用したAstroのActionsを使用していることを前提としています。 ## Mastraをインストール 必要なMastraパッケージをインストールします: {/* LLM CONTEXT: This Tabs component shows commands for integrating a new Mastra backend project using different package managers. Each tab displays the command for that specific package manager to create an integrated Mastra backend service. This is part of the "Integrated Backend Integration" approach for Astro projects. All commands create the same Mastra project but use different package manager syntax. */} ```bash copy npm install mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy yarn add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy pnpm add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy bun add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ## Mastraを統合する プロジェクトにMastraを統合するには、2つのオプションがあります: ### 1. ワンライナーを使用する 以下のコマンドを実行して、合理的なデフォルト設定でデフォルトのWeatherエージェントを素早くスキャフォールドします: ```bash copy npx mastra@latest init --default ``` > 詳細については[mastra init](/reference/cli/init)を参照してください。 ### 2. インタラクティブCLIを使用する セットアップをカスタマイズしたい場合は、`init`コマンドを実行し、プロンプトが表示されたときにオプションから選択してください: ```bash copy npx mastra@latest init ``` `package.json`に`dev`と`build`スクリプトを追加します: ```json filename="package.json" { "scripts": { ... "dev:mastra": "mastra dev", "build:mastra": "mastra build" } } ``` ## TypeScriptを設定する プロジェクトルートの`tsconfig.json`ファイルを修正します: ```json filename="tsconfig.json" { ... "exclude": ["dist", ".mastra"] } ``` ## API キーの設定 ```bash filename=".env" copy OPENAI_API_KEY= ``` ## .gitignoreを更新 `.mastra`と`.vercel`を`.gitignore`ファイルに追加してください: ```bash filename=".gitignore" copy .mastra .vercel ``` ## Mastra Agentを更新する AstroはViteを使用しており、`process.env`ではなく`import.meta.env`を通じて環境変数にアクセスします。そのため、モデルコンストラクタは次のようにVite環境から明示的に`apiKey`を受け取る必要があります: ```diff filename="src/mastra/agents/weather-agent.ts" - import { openai } from "@ai-sdk/openai"; + import { createOpenAI } from "@ai-sdk/openai"; + const openai = createOpenAI({ + apiKey: import.meta.env?.OPENAI_API_KEY, + compatibility: "strict" + }); ``` > より詳細な設定についてはAI SDKドキュメントで確認できます。詳細については[Provider Instance](https://ai-sdk.dev/providers/ai-sdk-providers/openai#provider-instance)を参照してください。 ## Mastra Dev Serverを開始する Mastra Dev Serverを開始して、エージェントをRESTエンドポイントとして公開します: ```bash copy npm run dev:mastra ``` ```bash copy mastra dev:mastra ``` > 実行すると、エージェントがローカルで利用可能になります。詳細については[ローカル開発環境](/docs/local-dev/mastra-dev)を参照してください。 ## Astro Dev Serverを開始 Mastra Dev Serverが実行されている状態で、通常の方法でAstroサイトを開始できます。 ## Actionsディレクトリの作成 ```bash copy mkdir src/actions ``` ### テストActionの作成 新しいActionを作成し、サンプルコードを追加します: ```bash copy touch src/actions/index.ts ``` ```typescript filename="src/actions/index.ts" showLineNumbers copy import { defineAction } from "astro:actions"; import { z } from "astro:schema"; import { mastra } from "../mastra"; export const server = { getWeatherInfo: defineAction({ input: z.object({ city: z.string() }), handler: async (input) => { const city = input.city; const agent = mastra.getAgent("weatherAgent"); const result = await agent.generate(`What's the weather like in ${city}?`); return result.text; } }) }; ``` ### テストフォームの作成 新しいFormコンポーネントを作成し、サンプルコードを追加します: ```bash copy touch src/components/form.tsx ``` ```typescript filename="src/components/form.tsx" showLineNumbers copy import { actions } from "astro:actions"; import { useState } from "react"; export const Form = () => { const [result, setResult] = useState(null); async function handleSubmit(formData: FormData) { const city = formData.get("city")!.toString(); const { data } = await actions.getWeatherInfo({ city }); setResult(data || null); } return ( <>
{result &&
{result}
} ); }; ``` ### テストページの作成 新しいページを作成し、サンプルコードを追加します: ```bash copy touch src/pages/test.astro ``` ```astro filename="src/pages/test.astro" showLineNumbers copy --- import { Form } from '../components/form' ---

Test

``` > ブラウザで `/test` にアクセスして試すことができます。 都市として **London** を送信すると、以下のような結果が返されます: ```plaintext Agent response: The current weather in London is as follows: - **Temperature:** 12.9°C (Feels like 9.7°C) - **Humidity:** 63% - **Wind Speed:** 14.7 km/h - **Wind Gusts:** 32.4 km/h - **Conditions:** Overcast Let me know if you need more information! ``` このガイドでは、ReactとVercelアダプターを使用したAstroのEndpointsを使用し、出力がサーバーに設定されていることを前提としています。 ## 前提条件 続行する前に、Astroプロジェクトが以下のように設定されていることを確認してください: * Astro Reactインテグレーション: [@astrojs/react](https://docs.astro.build/en/guides/integrations-guide/react/) * Vercelアダプター: [@astrojs/vercel](https://docs.astro.build/en/guides/integrations-guide/vercel/) * `astro.config.mjs`が`output: "server"`に設定されている ## Mastraをインストール 必要なMastraパッケージをインストールします: {/* LLM CONTEXT: This Tabs component shows commands for integrating a new Mastra backend project using different package managers. Each tab displays the command for that specific package manager to create an integrated Mastra backend service. This is part of the "Integrated Backend Integration" approach for Astro projects. All commands create the same Mastra project but use different package manager syntax. */} ```bash copy npm install mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy yarn add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy pnpm add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy bun add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ## Mastraを統合する プロジェクトにMastraを統合するには、2つのオプションがあります: ### 1. ワンライナーを使用する 以下のコマンドを実行して、合理的なデフォルト設定でデフォルトのWeatherエージェントを素早くスキャフォールドします: ```bash copy npx mastra@latest init --default ``` > 詳細については[mastra init](/reference/cli/init)を参照してください。 ### 2. インタラクティブCLIを使用する セットアップをカスタマイズしたい場合は、`init`コマンドを実行し、プロンプトが表示されたときにオプションから選択してください: ```bash copy npx mastra@latest init ``` `package.json`に`dev`と`build`スクリプトを追加します: ```json filename="package.json" { "scripts": { ... "dev:mastra": "mastra dev", "build:mastra": "mastra build" } } ``` ## TypeScriptを設定する プロジェクトルートの`tsconfig.json`ファイルを修正します: ```json filename="tsconfig.json" { ... "exclude": ["dist", ".mastra"] } ``` ## API キーの設定 ```bash filename=".env" copy OPENAI_API_KEY= ``` ## .gitignoreを更新 `.gitignore`ファイルに`.mastra`を追加してください: ```bash filename=".gitignore" copy .mastra .vercel ``` ## Mastra Agentを更新する AstroはViteを使用しており、`process.env`ではなく`import.meta.env`を通じて環境変数にアクセスします。そのため、モデルコンストラクタは次のようにVite環境から明示的に`apiKey`を受け取る必要があります: ```diff filename="src/mastra/agents/weather-agent.ts" - import { openai } from "@ai-sdk/openai"; + import { createOpenAI } from "@ai-sdk/openai"; + const openai = createOpenAI({ + apiKey: import.meta.env?.OPENAI_API_KEY, + compatibility: "strict" + }); ``` > より詳細な設定についてはAI SDKドキュメントで確認できます。詳細については[Provider Instance](https://ai-sdk.dev/providers/ai-sdk-providers/openai#provider-instance)を参照してください。 ## Mastra Dev Serverを開始する Mastra Dev Serverを開始して、エージェントをRESTエンドポイントとして公開します: ```bash copy npm run dev:mastra ``` ```bash copy mastra dev:mastra ``` > 実行すると、エージェントがローカルで利用可能になります。詳細については[ローカル開発環境](/docs/local-dev/mastra-dev)を参照してください。 ## Astro Dev Serverを開始 Mastra Dev Serverが実行されている状態で、通常の方法でAstroサイトを開始できます。 ## APIディレクトリの作成 ```bash copy mkdir src/pages/api ``` ### テストエンドポイントの作成 新しいエンドポイントを作成し、サンプルコードを追加します: ```bash copy touch src/pages/api/test.ts ``` ```typescript filename="src/pages/api/test.ts" showLineNumbers copy import type { APIRoute } from "astro"; import { mastra } from "../../mastra"; export const POST: APIRoute = async ({ request }) => { const { city } = await new Response(request.body).json(); const agent = mastra.getAgent("weatherAgent"); const result = await agent.generate(`What's the weather like in ${city}?`); return new Response(JSON.stringify(result.text)); }; ``` ### テストフォームの作成 新しいFormコンポーネントを作成し、サンプルコードを追加します: ```bash copy touch src/components/form.tsx ``` ```typescript filename="src/components/form.tsx" showLineNumbers copy import { useState } from "react"; export const Form = () => { const [result, setResult] = useState(null); async function handleSubmit(event: React.FormEvent) { event.preventDefault(); const formData = new FormData(event.currentTarget); const city = formData.get("city")?.toString(); const response = await fetch("/api/test", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ city }) }); const text = await response.json(); setResult(text); } return ( <> {result &&
{result}
} ); }; ``` ### テストページの作成 新しいページを作成し、サンプルコードを追加します: ```bash copy touch src/pages/test.astro ``` ```astro filename="src/pages/test.astro" showLineNumbers copy --- import { Form } from '../components/form' ---

Test

``` > ブラウザで `/test` にアクセスして試すことができます。 都市として **London** を送信すると、以下のような結果が返されます: ```plaintext Agent response: The current weather in London is as follows: - **Temperature:** 12.9°C (Feels like 9.7°C) - **Humidity:** 63% - **Wind Speed:** 14.7 km/h - **Wind Gusts:** 32.4 km/h - **Conditions:** Overcast Let me know if you need more information! ``` ## 次のステップ - [デプロイメント | VercelでAstroを使用](/docs/deployment/web-framework#with-astro-on-vercel) --- title: "MastraとNext.jsを始める | Mastraガイド" description: MastraをNext.jsと統合するためのステップバイステップガイド。 --- import { Callout, Steps, Tabs } from "nextra/components"; # Next.jsプロジェクトにMastraを統合する [JA] Source: https://mastra.ai/ja/docs/frameworks/web-frameworks/next-js MastraはNext.jsと統合し、以下を簡単に実現できます: - AI機能を提供する柔軟なAPIの構築 - フロントエンドとバックエンドの統一されたコードベースによるデプロイメントの簡素化 - 効率的なサーバー・クライアントワークフローのためのNext.jsの組み込みサーバーアクション(App Router)またはAPI Routes(Pages Router)の活用 このガイドを使用して、Next.jsプロジェクトでMastraをスキャフォールドし統合してください。 このガイドでは、プロジェクトのルートでNext.js App Routerを使用していることを前提としています。例:`src/app`ではなく`app`。 ## Mastraをインストール 必要なMastraパッケージをインストールします: {/* LLM CONTEXT: This Tabs component shows commands for integrating a new Mastra backend project using different package managers. Each tab displays the command for that specific package manager to create an integrated Mastra backend service. This is part of the "Integrated Backend Integration" approach for Next.js projects. All commands create the same Mastra project but use different package manager syntax. */} ```bash copy npm install mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy yarn add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy pnpm add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy bun add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ## Mastraを統合する Mastraをプロジェクトに統合するには、2つのオプションがあります: ### 1. ワンライナーを使用する 以下のコマンドを実行して、合理的なデフォルト設定でデフォルトのWeatherエージェントを素早くスキャフォールドします: ```bash copy npx mastra@latest init --dir . --components agents,tools --example --llm openai ``` > 詳細については[mastra init](/reference/cli/init)を参照してください。 ### 2. インタラクティブCLIを使用する セットアップをカスタマイズしたい場合は、`init`コマンドを実行し、プロンプトが表示されたときにオプションから選択してください: ```bash copy npx mastra@latest init ``` `package.json`に`dev`と`build`スクリプトを追加します: ```json filename="package.json" { "scripts": { ... "dev:mastra": "mastra dev --dir mastra", "build:mastra": "mastra build --dir mastra" } } ``` ## TypeScriptを設定する プロジェクトルートの`tsconfig.json`ファイルを修正してください: ```json filename="tsconfig.json" { ... "exclude": ["dist", ".mastra"] } ``` ## API キーの設定 ```bash filename=".env" copy OPENAI_API_KEY= ``` > 各LLMプロバイダーは異なる環境変数を使用します。詳細については[モデル機能](/docs/getting-started/model-capability)を参照してください。 ## Next.jsを設定する `next.config.ts`に以下を追加してください: ```typescript filename="next.config.ts" showLineNumbers copy import type { NextConfig } from "next"; const nextConfig: NextConfig = { serverExternalPackages: ["@mastra/*"], }; export default nextConfig; ``` ## .gitignoreを更新 `.gitignore`ファイルに`.mastra`を追加してください: ```bash filename=".gitignore" copy .mastra ``` ## Mastra Dev Serverを開始する エージェントをREST エンドポイントとして公開するために、Mastra Dev Serverを開始します: ```bash copy npm run dev:mastra ``` ```bash copy mastra dev:mastra ``` > 実行すると、エージェントがローカルで利用可能になります。詳細については、[ローカル開発環境](/docs/local-dev/mastra-dev)を参照してください。 ## Next.js Dev Serverを開始 Mastra Dev Serverが実行されている状態で、通常の方法でNext.jsアプリを開始できます。 ## テストディレクトリの作成 テスト用のPage、Action、Formを含む新しいディレクトリを作成します。 ```bash copy mkdir app/test ``` ### テストActionの作成 新しいActionを作成し、サンプルコードを追加します: ```bash copy touch app/test/action.ts ``` ```typescript filename="app/test/action.ts" showLineNumbers copy "use server"; import { mastra } from "../../mastra"; export async function getWeatherInfo(formData: FormData) { const city = formData.get("city")?.toString(); const agent = mastra.getAgent("weatherAgent"); const result = await agent.generate(`What's the weather like in ${city}?`); return result.text; } ``` ### テストFormの作成 新しいFormコンポーネントを作成し、サンプルコードを追加します: ```bash copy touch app/test/form.tsx ``` ```typescript filename="app/test/form.tsx" showLineNumbers copy "use client"; import { useState } from "react"; import { getWeatherInfo } from "./action"; export function Form() { const [result, setResult] = useState(null); async function handleSubmit(formData: FormData) { const res = await getWeatherInfo(formData); setResult(res); } return ( <> {result &&
{result}
} ); } ``` ### テストPageの作成 新しいPageを作成し、サンプルコードを追加します: ```bash copy touch app/test/page.tsx ``` ```typescript filename="app/test/page.tsx" showLineNumbers copy import { Form } from "./form"; export default async function Page() { return ( <>

Test

); } ``` > ブラウザで `/test` にアクセスして試すことができます。 都市として **London** を送信すると、以下のような結果が返されます: ```plaintext Agent response: The current weather in London is as follows: - **Temperature:** 12.9°C (Feels like 9.7°C) - **Humidity:** 63% - **Wind Speed:** 14.7 km/h - **Wind Gusts:** 32.4 km/h - **Conditions:** Overcast Let me know if you need more information! ``` このガイドでは、プロジェクトのルートでNext.js Pages Routerを使用していることを前提としています。例えば、`src/pages`ではなく`pages`を使用している場合です。 ## Mastraをインストール 必要なMastraパッケージをインストールします: {/* LLM CONTEXT: This Tabs component shows commands for integrating a new Mastra backend project using different package managers. Each tab displays the command for that specific package manager to create an integrated Mastra backend service. This is part of the "Integrated Backend Integration" approach for Next.js projects. All commands create the same Mastra project but use different package manager syntax. */} ```bash copy npm install mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy yarn add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy pnpm add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ```bash copy bun add mastra@latest @mastra/core@latest @mastra/libsql@latest ``` ## Mastraを統合する Mastraをプロジェクトに統合するには、2つのオプションがあります: ### 1. ワンライナーを使用する 以下のコマンドを実行して、合理的なデフォルト設定でデフォルトのWeatherエージェントを素早くスキャフォールドします: ```bash copy npx mastra@latest init --dir . --components agents,tools --example --llm openai ``` > 詳細については[mastra init](/reference/cli/init)を参照してください。 ### 2. インタラクティブCLIを使用する セットアップをカスタマイズしたい場合は、`init`コマンドを実行し、プロンプトが表示されたときにオプションから選択してください: ```bash copy npx mastra@latest init ``` `package.json`に`dev`と`build`スクリプトを追加します: ```json filename="package.json" { "scripts": { ... "dev:mastra": "mastra dev --dir mastra", "build:mastra": "mastra build --dir mastra" } } ``` ## TypeScriptを設定する プロジェクトルートの`tsconfig.json`ファイルを修正します: ```json filename="tsconfig.json" { ... "exclude": ["dist", ".mastra"] } ``` ## API キーの設定 ```bash filename=".env" copy OPENAI_API_KEY= ``` > 各LLMプロバイダーは異なる環境変数を使用します。詳細については[モデル機能](/docs/getting-started/model-capability)を参照してください。 ## Next.jsを設定する `next.config.ts`に以下を追加してください: ```typescript filename="next.config.ts" showLineNumbers copy import type { NextConfig } from "next"; const nextConfig: NextConfig = { serverExternalPackages: ["@mastra/*"], }; export default nextConfig; ``` ## .gitignoreを更新 `.gitignore`ファイルに`.mastra`を追加してください: ```bash filename=".gitignore" copy .mastra ``` ## Mastra Dev Serverを開始する エージェントをREST エンドポイントとして公開するために、Mastra Dev Serverを開始します: ```bash copy npm run dev:mastra ``` ```bash copy mastra dev:mastra ``` > 実行すると、エージェントがローカルで利用可能になります。詳細については、[ローカル開発環境](/docs/local-dev/mastra-dev)を参照してください。 ## Next.js Dev Serverを開始 Mastra Dev Serverが実行されている状態で、通常の方法でNext.jsアプリを開始できます。 ## テストAPIルートを作成 新しいAPIルートを作成し、サンプルコードを追加します: ```bash copy touch pages/api/test.ts ``` ```typescript filename="pages/api/test.ts" showLineNumbers copy import type { NextApiRequest, NextApiResponse } from "next"; import { mastra } from "../../mastra"; export default async function getWeatherInfo( req: NextApiRequest, res: NextApiResponse, ) { const city = req.body.city; const agent = mastra.getAgent("weatherAgent"); const result = await agent.generate(`What's the weather like in ${city}?`); return res.status(200).json(result.text); } ``` ## テストページを作成 新しいページを作成し、サンプルコードを追加します: ```bash copy touch pages/test.tsx ``` ```typescript filename="pages/test.tsx" showLineNumbers copy import { useState } from "react"; export default function Test() { const [result, setResult] = useState(null); async function handleSubmit(event: React.FormEvent) { event.preventDefault(); const formData = new FormData(event.currentTarget); const city = formData.get("city")?.toString(); const response = await fetch("/api/test", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ city }) }); const text = await response.json(); setResult(text); } return ( <>

Test

{result &&
{result}
} ); } ``` > ブラウザで `/test` にアクセスして試すことができます。 都市として **London** を送信すると、以下のような結果が返されます: ```plaintext Agent response: The current weather in London is as follows: - **Temperature:** 12.9°C (Feels like 9.7°C) - **Humidity:** 63% - **Wind Speed:** 14.7 km/h - **Wind Gusts:** 32.4 km/h - **Conditions:** Overcast Let me know if you need more information! ```
## 次のステップ - [デプロイメント | VercelでNext.jsを使用](/docs/deployment/web-framework#with-nextjs-on-vercel) --- title: "Vite/ReactでMastraを始める | Mastraガイド" description: ViteとReactにMastraを統合するためのステップバイステップガイド。 --- import { Callout, Steps, Tabs } from "nextra/components"; # Vite/ReactプロジェクトにMastraを統合する [JA] Source: https://mastra.ai/ja/docs/frameworks/web-frameworks/vite-react MastraはViteと統合し、以下を簡単に実現できます: - AI機能を提供する柔軟なAPIの構築 - フロントエンドとバックエンドの統一されたコードベースによるデプロイメントの簡素化 - MastraのClient SDKの活用 このガイドを使用して、Vite/ReactプロジェクトでMastraをスキャフォールドし統合してください。 このガイドでは、プロジェクトのルート(例:`app`)でReact Router v7を使用したVite/Reactを使用していることを前提としています。 ## Mastraをインストール 必要なMastraパッケージをインストールします: {/* LLM CONTEXT: This Tabs component shows commands for integrating a new Mastra backend project using different package managers. Each tab displays the command for that specific package manager to create an integrated Mastra backend service. This is part of the "Integrated Backend Integration" approach for Vite/React projects. All commands create the same Mastra project but use different package manager syntax. */} ```bash copy npm install mastra@latest @mastra/core@latest @mastra/libsql@latest @mastra/client-js@latest ``` ```bash copy yarn add mastra@latest @mastra/core@latest @mastra/libsql@latest @mastra/client-js@latest ``` ```bash copy pnpm add mastra@latest @mastra/core@latest @mastra/libsql@latest @mastra/client-js@latest ``` ```bash copy bun add mastra@latest @mastra/core@latest @mastra/libsql@latest @mastra/client-js@latest ``` ## Mastraを統合する プロジェクトにMastraを統合するには、2つのオプションがあります: ### 1. ワンライナーを使用する 以下のコマンドを実行して、合理的なデフォルト設定でデフォルトのWeatherエージェントを素早くスキャフォールドします: ```bash copy npx mastra@latest init --dir . --components agents,tools --example --llm openai ``` > 詳細については[mastra init](/reference/cli/init)を参照してください。 ### 2. インタラクティブCLIを使用する セットアップをカスタマイズしたい場合は、`init`コマンドを実行し、プロンプトが表示されたときにオプションから選択してください: ```bash copy npx mastra@latest init ``` `package.json`に`dev`と`build`スクリプトを追加します: ```json filename="package.json" { "scripts": { ... "dev:mastra": "mastra dev --dir mastra", "build:mastra": "mastra build --dir mastra" } } ``` ## TypeScriptを設定する プロジェクトルートの`tsconfig.json`ファイルを修正してください: ```json filename="tsconfig.json" { ... "exclude": ["dist", ".mastra"] } ``` ## API キーの設定 ```bash filename=".env" copy OPENAI_API_KEY= ``` > 各LLMプロバイダーは異なる環境変数を使用します。詳細については[モデル機能](/docs/getting-started/model-capability)を参照してください。 ## .gitignoreを更新する `.gitignore`ファイルに`.mastra`を追加してください: ```bash filename=".gitignore" copy .mastra ``` ## Mastra Dev Serverを開始する エージェントをREST エンドポイントとして公開するために、Mastra Dev Serverを開始します: ```bash copy npm run dev:mastra ``` ```bash copy mastra dev:mastra ``` > 実行すると、エージェントがローカルで利用可能になります。詳細については[Local Development Environment](/docs/local-dev/mastra-dev)を参照してください。 ## Vite Dev Serverを開始する Mastra Dev Serverが実行されている状態で、通常の方法でViteアプリを開始できます。 ## Mastraクライアントを作成する 新しいディレクトリとファイルを作成します。その後、サンプルコードを追加します: ```bash copy mkdir lib touch lib/mastra.ts ``` ```typescript filename="lib/mastra.ts" showLineNumbers copy import { MastraClient } from "@mastra/client-js"; export const mastraClient = new MastraClient({ baseUrl: import.meta.env.VITE_MASTRA_API_URL || "http://localhost:4111", }); ``` ## テストルート設定を作成 設定に新しい`route`を追加します: ```typescript filename="app/routes.ts" showLineNumbers copy import { type RouteConfig, index, route } from "@react-router/dev/routes"; export default [ index("routes/home.tsx"), route("test", "routes/test.tsx"), ] satisfies RouteConfig; ``` ## テストルートを作成 新しいルートを作成し、サンプルコードを追加します: ```bash copy touch app/routes/test.tsx ``` ```typescript filename="app/routes/test.tsx" showLineNumbers copy import { useState } from "react"; import { mastraClient } from "../../lib/mastra"; export default function Test() { const [result, setResult] = useState(null); async function handleSubmit(event: React.FormEvent) { event.preventDefault(); const formData = new FormData(event.currentTarget); const city = formData.get("city")?.toString(); const agent = mastraClient.getAgent("weatherAgent"); const response = await agent.generate({ messages: [{ role: "user", content: `What's the weather like in ${city}?` }] }); setResult(response.text); } return ( <>

Test

{result &&
{result}
} ); } ``` > ブラウザで `/test` にアクセスして試すことができます。 都市として **London** を送信すると、以下のような結果が返されます: ```plaintext The current weather in London is partly cloudy with a temperature of 19.3°C, feeling like 17.4°C. The humidity is at 53%, and there is a wind speed of 15.9 km/h, with gusts up to 38.5 km/h. ``` --- title: "Mastraのインストール | はじめに | Mastra Docs" description: Mastraのインストールと、さまざまなLLMプロバイダーで実行するために必要な前提条件の設定に関するガイド。 --- import { Callout, Steps } from "nextra/components"; import { Tabs, Tab } from "@/components/tabs"; # Mastraをインストール [JA] Source: https://mastra.ai/ja/docs/getting-started/installation Mastraを始めるには、大規模言語モデル(LLM)へのアクセスが必要です。デフォルトでは、Mastraは[OpenAI](https://platform.openai.com/)と連携するように設定されているため、開始するにはAPIキーが必要です。 Mastraは他のLLMプロバイダーもサポートしています。サポートされているモデルの完全なリストとセットアップ手順については、[モデルプロバイダー](/docs/getting-started/model-providers)をご覧ください。 ## 前提条件 - Node.js `v20.0` 以上 - サポートされている[Model Provider](/docs/getting-started/model-providers)からのAPIキー ## `create-mastra` CLIを使用してインストール 私たちのCLIはMastraを始める最も速い方法です。以下のコマンドを実行してインタラクティブセットアップを開始してください: {/* LLM CONTEXT: This Tabs component shows different package manager commands for creating a new Mastra project. Each tab displays the equivalent command for that specific package manager (npx, npm, yarn, pnpm, bun). This helps users choose their preferred package manager while following the same installation process. All commands achieve the same result - creating a new Mastra project with the interactive setup. */} ```bash copy npx create-mastra@latest ``` ```bash copy npm create mastra@latest ``` ```bash copy yarn create mastra@latest ``` ```bash copy pnpm create mastra@latest ``` ```bash copy bun create mastra@latest ``` **CLIフラグを使用してインストール** 必要なフラグをすべて渡すことで、Mastra CLIを非インタラクティブモードで実行することもできます。例えば: ```bash copy npx create-mastra@latest --project-name hello-mastra --example --components tools,agents,workflows --llm openai ``` > 利用可能なCLIオプションの完全なリストについては、[create-mastra](/reference/cli/create-mastra)のドキュメントを参照してください。 ### APIキーを追加 `.env`ファイルにAPIキーを追加してください: ```bash filename=".env" copy OPENAI_API_KEY= ``` > この例ではOpenAIを使用しています。各LLMプロバイダーは固有の名前を使用します。詳細については[Model Capabilities](/docs/getting-started/model-capability)を参照してください。 これで[Mastra Development Server](/docs/local-dev/mastra-dev)を起動し、Mastra Playgroundを使用してエージェントをテストできます。 ## 手動でインストール 以下の手順では、Mastraを手動でインストールする方法を説明します。 ### 新しいプロジェクトを作成する 新しいプロジェクトを作成してディレクトリを変更します: ```bash copy mkdir hello-mastra && cd hello-mastra ``` `@mastra/core`パッケージを含むTypeScriptプロジェクトを初期化します: {/* LLM CONTEXT: This Tabs component shows manual installation commands for different package managers. Each tab displays the complete setup process for that package manager including project initialization, dev dependencies installation, and core Mastra packages installation. This helps users manually set up a Mastra project with their preferred package manager. */} ```bash copy npm init -y npm install typescript tsx @types/node mastra@latest --save-dev npm install @mastra/core@latest zod @ai-sdk/openai ``` ```bash copy pnpm init pnpm add typescript tsx @types/node mastra@latest --save-dev pnpm add @mastra/core@latest zod @ai-sdk/openai ``` ```bash copy yarn init -y yarn add typescript tsx @types/node mastra@latest --dev yarn add @mastra/core@latest zod @ai-sdk/openai ``` ```bash copy bun init -y bun add typescript tsx @types/node mastra@latest --dev bun add @mastra/core@latest zod @ai-sdk/openai ``` `package.json`に`dev`と`build`スクリプトを追加します: ```json filename="package.json" copy { "scripts": { // ... "dev": "mastra dev", "build": "mastra build" } } ``` ### TypeScriptを初期化する `tsconfig.json`ファイルを作成します: ```bash copy touch tsconfig.json ``` 以下の設定を追加します: ```json filename="tsconfig.json" copy { "compilerOptions": { "target": "ES2022", "module": "ES2022", "moduleResolution": "bundler", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true, "noEmit": true, "outDir": "dist" }, "include": [ "src/**/*" ] } ``` > このTypeScript設定はMastraプロジェクト用に最適化されており、モダンなモジュール解決と厳密な型チェックを使用しています。 ### APIキーを設定する `.env`ファイルを作成します: ```bash copy touch .env ``` APIキーを追加します: ```bash filename=".env" copy OPENAI_API_KEY= ``` > この例ではOpenAIを使用しています。各LLMプロバイダーは固有の名前を使用します。詳細については[Model Capabilities](/docs/getting-started/model-capability)を参照してください。 ### ツールを作成する `weather-tool.ts`ファイルを作成します: ```bash copy mkdir -p src/mastra/tools && touch src/mastra/tools/weather-tool.ts ``` 以下のコードを追加します: ```ts filename="src/mastra/tools/weather-tool.ts" showLineNumbers copy import { createTool } from "@mastra/core/tools"; import { z } from "zod"; export const weatherTool = createTool({ id: "get-weather", description: "Get current weather for a location", inputSchema: z.object({ location: z.string().describe("City name") }), outputSchema: z.object({ output: z.string() }), execute: async () => { return { output: "The weather is sunny" }; } }); ``` > 完全なweatherToolの例については、[Giving an Agent a Tool](/examples/agents/using-a-tool)を参照してください。 ### エージェントを作成する `weather-agent.ts`ファイルを作成します: ```bash copy mkdir -p src/mastra/agents && touch src/mastra/agents/weather-agent.ts ``` 以下のコードを追加します: ```ts filename="src/mastra/agents/weather-agent.ts" showLineNumbers copy import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { weatherTool } from "../tools/weather-tool"; export const weatherAgent = new Agent({ name: 'Weather Agent', instructions: ` You are a helpful weather assistant that provides accurate weather information. Your primary function is to help users get weather details for specific locations. When responding: - Always ask for a location if none is provided - If the location name isn't in English, please translate it - If giving a location with multiple parts (e.g. "New York, NY"), use the most relevant part (e.g. "New York") - Include relevant details like humidity, wind conditions, and precipitation - Keep responses concise but informative Use the weatherTool to fetch current weather data. `, model: openai('gpt-4o-mini'), tools: { weatherTool } }); ``` ### エージェントを登録する Mastraのエントリーポイントを作成し、エージェントを登録します: ```bash copy touch src/mastra/index.ts ``` 以下のコードを追加します: ```ts filename="src/mastra/index.ts" showLineNumbers copy import { Mastra } from "@mastra/core/mastra"; import { weatherAgent } from "./agents/weather-agent"; export const mastra = new Mastra({ agents: { weatherAgent } }); ``` これで[Mastra Development Server](/docs/local-dev/mastra-dev)を起動し、Mastra Playgroundを使用してエージェントをテストできます。 ## 既存のプロジェクトに追加 Mastraは幅広いプロジェクトにインストールして統合することができます。以下は、開始に役立つ統合ガイドへのリンクです: - [Next.js](/docs/frameworks/web-frameworks/next-js) - [Vite + React](/docs/frameworks/web-frameworks/vite-react) - [Astro](/docs/frameworks/web-frameworks/astro) - [Express](/docs/frameworks/servers/express) ### `mastra init` 既存のプロジェクトにMastraをインストールするには、`mastra init`コマンドを使用します。 > 詳細については[mastra init](/reference/cli/init)を参照してください。 ## 次のステップ - [ローカル開発](/docs/local-dev/mastra-dev) - [Mastra Cloudにデプロイ](/docs/deployment/overview) --- title: "Cursor/Windsurfでの使用 | はじめに | Mastra ドキュメント" description: "IDEでMastra MCPドキュメントサーバーを使用して、エージェント型のMastraエキスパートに変える方法を学びましょう。" --- import YouTube from "@/components/youtube"; import { Tabs } from "nextra/components"; # エージェントIDEのためのMastraツール [JA] Source: https://mastra.ai/ja/docs/getting-started/mcp-docs-server `@mastra/mcp-docs-server`は、Cursor、Windsurf、Cline、またはMCPをサポートする他のIDEでMastraの完全なナレッジベースに直接アクセスできるようにします。 これはドキュメント、コード例、技術ブログ投稿/機能アナウンス、パッケージの変更履歴にアクセスでき、あなたのIDEがMastraを使って構築するのを助けることができます。 MCPサーバーツールは、エージェントがMastra関連のタスクを完了するために必要な特定の情報を照会できるように設計されています - 例えば:エージェントにMastra機能を追加する、新しいプロジェクトの足場を作る、または何かがどのように機能するかを理解するのを助けるなど。 ## 仕組み IDEにインストールされると、プロンプトを書いて、エージェントがMastraについてすべてを理解していると想定できます。 ### 機能を追加する - 「エージェントに評価を追加してテストを書いてください」 - 「次のことを行うワークフローを作成してください `[タスク]`」 - 「エージェントが `[サードパーティAPI]` にアクセスできるようにする新しいツールを作成してください」 ### 統合について質問する - 「MastraはAI SDKと連携しますか? `[React/Svelte/など]` プロジェクトでどのように使用できますか?」 - 「MCPに関する最新のMastraニュースは何ですか?」 - 「Mastraは `[プロバイダー]` の音声APIをサポートしていますか?コードでの使用例を示してください。」 ### 既存のコードをデバッグまたは更新する - 「エージェントのメモリに関するバグが発生しています。最近関連する変更やバグ修正はありましたか?」 - 「Mastraでワーキングメモリはどのように動作し、`[タスク]` を実行するためにどのように使用できますか?期待通りに動作していないようです。」 - 「新しいワークフロー機能があると聞きました。それを説明し、`[ワークフロー]` を更新して使用するようにしてください。」 **その他** - 質問がある場合は、IDEに尋ねて調べてもらいましょう。 ## 自動インストール **新規**プロジェクトの場合、MCP Docs Server はインストール時に [インタラクティブ](/docs/getting-started/installation#interactive)なセットアッププロンプトを通じて追加するか、[非インタラクティブ](/docs/getting-started/installation#non-interactive)コマンドで `-m` フラグを指定して追加できます。 ## 手動インストール 既存のプロジェクトにMCP Docs Serverを追加するには、手動でインストールしてください。 - **Cursor**: プロジェクトルートの`.cursor/mcp.json`を編集するか、グローバル設定の場合は`~/.cursor/mcp.json`を編集 - **Windsurf**: `~/.codeium/windsurf/mcp_config.json`を編集(グローバル設定のみサポート) - **VSCode**: プロジェクトルートの`~/.vscode/mcp.json`を編集 以下の設定を追加してください: ### MacOS/Linux {/* LLM CONTEXT: This Tabs component shows MCP server configuration for different IDEs on MacOS/Linux. Each tab displays the JSON configuration needed to set up the Mastra MCP docs server in that specific IDE. The tabs help users find the correct configuration format for their IDE (Cursor, Windsurf, or VSCode). Each tab shows the exact JSON structure and file paths needed for that IDE's MCP configuration. */} ```json { "mcpServers": { "mastra": { "command": "npx", "args": ["-y", "@mastra/mcp-docs-server"] } } } ``` ```json { "mcpServers": { "mastra": { "command": "npx", "args": ["-y", "@mastra/mcp-docs-server"] } } } ``` ```json { "servers": { "mastra": { "command": "npx", "args": ["-y", "@mastra/mcp-docs-server"], "type": "stdio" } } } ``` ### Windows {/* LLM CONTEXT: This Tabs component shows MCP server configuration for different IDEs on Windows. Each tab displays the Windows-specific JSON configuration needed to set up the Mastra MCP docs server. The tabs help Windows users find the correct configuration format for their IDE, using cmd instead of direct npx. Each tab shows the Windows-specific command structure needed for that IDE's MCP configuration. On latest Windsurf and Cursor the direct npx command works, while it's still unconfirmed if this has been fixed for VSCode. */} ```json { "mcpServers": { "mastra": { "command": "npx", "args": ["-y", "@mastra/mcp-docs-server"] } } } ``` ```json { "mcpServers": { "mastra": { "command": "npx", "args": ["-y", "@mastra/mcp-docs-server"] } } } ``` ```json { "servers": { "mastra": { "command": "cmd", "args": ["/c", "npx", "-y", "@mastra/mcp-docs-server"], "type": "stdio" } } } ``` ## 設定後 ### Cursor 自動インストールを行った場合、Cursorを開くと左下にポップアップが表示され、Mastra Docs MCP Serverを有効にするよう促されます。 Mastra docs MCP server を有効にするよう促す cursor のダイアグラム 手動インストールの場合は、以下の手順を行ってください。 1. Cursor の設定を開く 2. MCP 設定に移動する 3. Mastra MCP server の「enable」をクリックする 4. すでにエージェントチャットを開いている場合は、チャットを再度開くか新しいチャットを開始して MCP server を利用してください ### Windsurf 1. Windsurf を完全に終了し、再度開く 2. ツール呼び出しが失敗し始めた場合は、Windsurf の MCP 設定に移動し、MCP server を再起動してください。これはよくある Windsurf MCP の問題であり、Mastra とは関係ありません。現時点では Cursor の MCP 実装の方が Windsurf よりも安定しています。 どちらの IDE でも、初回は npm からパッケージをダウンロードする必要があるため、MCP server の起動に少し時間がかかる場合があります。 ### VSCode 1. VSCode の設定を開く 2. MCP 設定に移動する 3. Chat > MCP オプションの「enable」をクリックする
MCP を有効にするための VSCode の設定ページ MCP は VSCode ではエージェントモードでのみ動作します。エージェントモードに入ったら、`mcp.json` ファイルを開き、「start」ボタンをクリックしてください。
MCP を有効にするための VSCode の設定ページ mcp server を起動した後、copilot ペインのツールボタンをクリックすると利用可能なツールが表示されます。
利用可能なツールを表示する VSCode のツールページ ## 利用可能なエージェントツール ### ドキュメント Mastraの完全なドキュメントにアクセス: - 入門 / インストール - ガイドとチュートリアル - APIリファレンス ### 例 コード例を閲覧: - 完全なプロジェクト構造 - 実装パターン - ベストプラクティス ### ブログ投稿 ブログを検索: - 技術的な投稿 - 変更履歴と機能のお知らせ - AIニュースとアップデート ### パッケージの変更 Mastraと`@mastra/*`パッケージの更新を追跡: - バグ修正 - 新機能 - 破壊的変更 ## 一般的な問題 1. **サーバーが起動しない** - npxがインストールされ、正常に動作していることを確認する - 競合するMCPサーバーがないか確認する - 設定ファイルの構文を確認する - Windowsの場合、Windows専用の設定を使用していることを確認する 2. **ツール呼び出しが失敗する** - MCPサーバーやIDEを再起動する - IDEを最新バージョンに更新する ## モデルの機能 [JA] Source: https://mastra.ai/ja/docs/getting-started/model-capability import { ProviderTable } from "@/components/provider-table"; AIプロバイダーは、さまざまな機能を持つ異なる言語モデルをサポートしています。すべてのモデルが構造化された出力、画像入力、オブジェクト生成、ツールの使用、またはツールのストリーミングをサポートしているわけではありません。 以下は、人気のあるモデルの機能です: 出典: [AI SDK | Model Capabilities](https://sdk.vercel.ai/docs/foundations/providers-and-models#model-capabilities) --- title: "モデルプロバイダー | はじめに | Mastra Docs" description: "Mastraで異なるモデルプロバイダーを設定し使用する方法を学びます。" --- import { Callout, Tabs } from 'nextra/components' # Model Providers [JA] Source: https://mastra.ai/ja/docs/getting-started/model-providers Model providersは、異なる言語モデルとやり取りするために使用されます。Mastraは[Vercel's AI SDK](https://sdk.vercel.ai)をモデルルーティング層として使用し、多くのモデルに対して類似した構文を提供します: ```typescript showLineNumbers copy {1,7} filename="src/mastra/agents/weather-agent.ts" import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; const agent = new Agent({ name: "WeatherAgent", instructions: "Instructions for the agent...", model: openai("gpt-4-turbo"), }); const result = await agent.generate("What is the weather like?"); ``` ## AI SDKモデルプロバイダーの種類 AI SDKのモデルプロバイダーは、主に3つのカテゴリーに分類できます: - AI SDKチームによって保守されている公式プロバイダー - OpenAI互換プロバイダー - コミュニティプロバイダー 利用可能なすべてのモデルプロバイダーのリストは、[AI SDKドキュメント](https://ai-sdk.dev/providers/ai-sdk-providers)で確認できます。 AI SDKモデルプロバイダーは、Mastraプロジェクトにインストールする必要があるパッケージです。 インストールプロセス中に選択されたデフォルトのモデルプロバイダーは、プロジェクトにインストールされます。 異なるモデルプロバイダーを使用したい場合は、そのプロバイダーもプロジェクトにインストールする必要があります。 以下は、Mastraエージェントが異なるタイプのモデルプロバイダーを使用するように設定する方法の例です: ### 公式プロバイダー 公式モデルプロバイダーはAI SDKチームによって保守されています。 これらのパッケージは通常`@ai-sdk/`で始まります。例:`@ai-sdk/anthropic`、`@ai-sdk/openai`など。 ```typescript showLineNumbers copy {1,7} filename="src/mastra/agents/weather-agent.ts" import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; const agent = new Agent({ name: "WeatherAgent", instructions: "Instructions for the agent...", model: openai("gpt-4-turbo"), }); ``` AI SDKプロバイダーからヘルパー関数をインポートすることで、追加の設定を行うことができます。 OpenAIプロバイダーを使用した例は以下の通りです: ```typescript showLineNumbers copy filename="src/mastra/agents/weather-agent.ts" {1,4-8,13} import { createOpenAI } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent" const openai = createOpenAI({ baseUrl: "", apiKey: "", ...otherOptions }); const agent = new Agent({ name: "WeatherAgent", instructions: "Instructions for the agent...", model: openai(""), }); ``` 異なるAIプロバイダーは設定に異なるオプションを持つ場合があります。詳細については[AI SDKドキュメント](https://ai-sdk.dev/providers/ai-sdk-providers)を参照してください。 ### OpenAI互換プロバイダー 一部の言語モデルプロバイダーはOpenAI APIを実装しています。これらのプロバイダーには、[`@ai-sdk/openai-compatible`](https://www.npmjs.com/package/@ai-sdk/openai-compatible)プロバイダーを使用できます。 一般的なセットアップとプロバイダーインスタンスの作成方法は以下の通りです: ```typescript showLineNumbers copy filename="src/mastra/agents/weather-agent.ts" {1,4-14,19} import { createOpenAICompatible } from "@ai-sdk/openai-compatible"; import { Agent } from "@mastra/core/agent"; const openaiCompatible = createOpenAICompatible({ name: "", baseUrl: "", apiKey: "", headers: {}, queryParams: {}, fetch: async (url, options) => { // custom fetch logic return fetch(url, options); } }); const agent = new Agent({ name: "WeatherAgent", instructions: "Instructions for the agent...", model: openaiCompatible(""), }); ``` OpenAI互換プロバイダーの詳細については、[AI SDKドキュメント](https://ai-sdk.dev/providers/openai-compatible-providers)を参照してください。 ### コミュニティプロバイダー AI SDKは[Language Model Specification](https://github.com/vercel/ai/tree/main/packages/provider/src/language-model/v1)を提供しています。 この仕様に従うことで、AI SDKと互換性のある独自のモデルプロバイダーを作成できます。 一部のコミュニティプロバイダーはこの仕様を実装しており、AI SDKと互換性があります。 そのようなプロバイダーの一つである、[`ollama-ai-provider`](https://github.com/sgomez/ollama-ai-provider)パッケージで利用可能なOllamaプロバイダーを見てみましょう。 以下は例です: ```typescript showLineNumbers copy filename="src/mastra/agents/weather-agent.ts" {1,7} import { ollama } from "ollama-ai-provider"; import { Agent } from "@mastra/core/agent"; const agent = new Agent({ name: "WeatherAgent", instructions: "Instructions for the agent...", model: ollama("llama3.2:latest"), }); ``` Ollamaプロバイダーは以下のように設定することもできます: ```typescript showLineNumbers copy filename="src/mastra/agents/weather-agent.ts" {1,4-7,12} import { createOllama } from "ollama-ai-provider"; import { Agent } from "@mastra/core/agent"; const ollama = createOllama({ baseUrl: "", ...otherOptions, }); const agent = new Agent({ name: "WeatherAgent", instructions: "Instructions for the agent...", model: ollama("llama3.2:latest"), }); ``` Ollamaプロバイダーやその他の利用可能なコミュニティプロバイダーの詳細については、[AI SDK documentation](https://ai-sdk.dev/providers/community-providers)を参照してください。 この例ではOllamaプロバイダーの使用方法を示していますが、`openrouter`、`azure`などの他のプロバイダーも使用できます。 --- title: "ローカルプロジェクト構造 | はじめに | Mastra ドキュメント" description: Mastraでのフォルダとファイルの整理に関するガイド。ベストプラクティスと推奨される構造を含みます。 --- import { FileTree } from "nextra/components"; # プロジェクト構造 [JA] Source: https://mastra.ai/ja/docs/getting-started/project-structure このページではMastraでのフォルダとファイルの整理方法についてのガイドを提供します。Mastraはモジュラーフレームワークであり、各モジュールを個別に、または組み合わせて使用することができます。 すべてを1つのファイルに書くこともできますし、各エージェント、ツール、ワークフローを独自のファイルに分けることもできます。 特定のフォルダ構造を強制することはありませんが、いくつかのベストプラクティスを推奨しており、CLIは適切な構造でプロジェクトをスキャフォールドします。 ## プロジェクト構造の例 CLIで作成されたデフォルトプロジェクトは次のような構造になります: {/* ``` root/ ├── src/ │ └── mastra/ │ ├── agents/ │ │ └── index.ts │ ├── tools/ │ │ └── index.ts │ ├── workflows/ │ │ └── index.ts │ ├── index.ts ├── .env ├── package.json ├── tssconfig.json ``` */} ### トップレベルフォルダ | フォルダ | 説明 | | ---------------------- | ------------------------------------ | | `src/mastra` | コアアプリケーションフォルダ | | `src/mastra/agents` | エージェントの設定と定義 | | `src/mastra/tools` | カスタムツールの定義 | | `src/mastra/workflows` | ワークフローの定義 | ### トップレベルファイル | ファイル | 説明 | | --------------------- | --------------------------------------------------- | | `src/mastra/index.ts` | Mastraのメイン設定ファイル | | `.env` | 環境変数 | | `package.json` | Node.jsプロジェクトのメタデータ、スクリプト、依存関係 | | `tsconfig.json` | TypeScriptコンパイラの設定 | --- title: "はじめに | Mastra ドキュメント" description: "Mastraは、TypeScriptエージェントフレームワークです。AIアプリケーションや機能を素早く構築するのに役立ちます。ワークフロー、エージェント、RAG、統合、同期、評価など、必要なプリミティブセットを提供します。" --- # Mastraについて [JA] Source: https://mastra.ai/ja/docs Mastraは、オープンソースのTypeScriptエージェントフレームワークです。 AIアプリケーションや機能を構築するために必要なプリミティブを提供するように設計されています。 Mastraを使用して、メモリを持ち関数を実行できる[AIエージェント](/docs/agents/overview.mdx)を構築したり、決定論的な[ワークフロー](/docs/workflows/overview.mdx)でLLM呼び出しをチェーンしたりできます。Mastraの[ローカル開発環境](/docs/local-dev/mastra-dev.mdx)でエージェントとチャットしたり、[RAG](/docs/rag/overview.mdx)でアプリケーション固有の知識を提供したり、Mastraの[評価](/docs/evals/overview.mdx)でその出力をスコア化したりできます。 主な機能には以下が含まれます: - **[モデルルーティング](https://sdk.vercel.ai/docs/introduction)**: Mastraは[Vercel AI SDK](https://sdk.vercel.ai/docs/introduction)をモデルルーティングに使用し、OpenAI、Anthropic、Google Geminiを含む任意のLLMプロバイダーとやり取りするための統一されたインターフェースを提供します。 - **[エージェントメモリとツール呼び出し](/docs/agents/agent-memory.mdx)**: Mastraを使用すると、エージェントが呼び出すことができるツール(関数)を提供できます。エージェントメモリを永続化し、最新性、意味的類似性、または会話スレッドに基づいて取得できます。 - **[ワークフローグラフ](/docs/workflows/overview.mdx)**: LLM呼び出しを決定論的な方法で実行したい場合、Mastraはグラフベースのワークフローエンジンを提供します。個別のステップを定義し、各実行の各ステップで入力と出力をログに記録し、それらを観測可能性ツールにパイプできます。Mastraワークフローには、分岐とチェーンを可能にする制御フロー(`.then()`、`.branch()`、`.parallel()`)のシンプルな構文があります。 - **[エージェント開発環境](/docs/local-dev/mastra-dev.mdx)**: ローカルでエージェントを開発している際、Mastraのエージェント開発環境でエージェントとチャットし、その状態とメモリを確認できます。 - **[検索拡張生成(RAG)](/docs/rag/overview.mdx)**: Mastraは、ドキュメント(テキスト、HTML、Markdown、JSON)をチャンクに処理し、埋め込みを作成し、ベクターデータベースに保存するAPIを提供します。クエリ時には、関連するチャンクを取得してLLM応答をあなたのデータに基づかせ、複数のベクターストア(Pinecone、pgvectorなど)と埋め込みプロバイダー(OpenAI、Cohereなど)の上に統一されたAPIを提供します。 - **[デプロイメント](/docs/deployment/deployment.mdx)**: Mastraは、既存のReact、Next.js、またはNode.jsアプリケーション内、またはスタンドアロンエンドポイントへのエージェントとワークフローのバンドルをサポートします。Mastraデプロイヘルパーを使用すると、Honoを使用してエージェントとワークフローをNode.jsサーバーに簡単にバンドルしたり、Vercel、Cloudflare Workers、Netlifyなどのサーバーレスプラットフォームにデプロイしたりできます。 - **[評価](/docs/evals/overview.mdx)**: Mastraは、モデルグレード、ルールベース、統計的手法を使用してLLM出力を評価する自動評価メトリクスを提供し、毒性、バイアス、関連性、事実の正確性のための組み込みメトリクスを備えています。独自の評価を定義することもできます。 --- title: "Mastra 統合の使用 | Mastra ローカル開発ドキュメント" description: サードパーティサービスのために自動生成された型安全なAPIクライアントであるMastra統合のドキュメント。 --- # Mastra統合の使用 [JA] Source: https://mastra.ai/ja/docs/integrations Mastraの統合は、サードパーティサービス用の自動生成された型安全なAPIクライアントです。これらはエージェントのツールとして、またはワークフローのステップとして使用できます。 ## インテグレーションのインストール Mastraのデフォルトインテグレーションは、個別にインストール可能なnpmモジュールとしてパッケージ化されています。npmを通じてインテグレーションをインストールし、Mastraの設定にインポートすることで、プロジェクトにインテグレーションを追加できます。 ### 例:GitHubインテグレーションの追加 1. **インテグレーションパッケージのインストール** GitHubインテグレーションをインストールするには、次のコマンドを実行します: ```bash copy npm install @mastra/github@latest ``` 2. **プロジェクトにインテグレーションを追加する** インテグレーション用の新しいファイル(例:`src/mastra/integrations/index.ts`)を作成し、インテグレーションをインポートします: ```typescript filename="src/mastra/integrations/index.ts" showLineNumbers copy import { GithubIntegration } from "@mastra/github"; export const github = new GithubIntegration({ config: { PERSONAL_ACCESS_TOKEN: process.env.GITHUB_PAT!, }, }); ``` `process.env.GITHUB_PAT!`を実際のGitHub個人アクセストークンに置き換えるか、環境変数が適切に設定されていることを確認してください。 3. **ツールやワークフローでインテグレーションを使用する** これで、エージェントのツールを定義する際やワークフローでインテグレーションを使用できます。 ```typescript filename="src/mastra/tools/index.ts" showLineNumbers copy import { createTool } from "@mastra/core"; import { z } from "zod"; import { github } from "../integrations"; export const getMainBranchRef = createTool({ id: "getMainBranchRef", description: "Fetch the main branch reference from a GitHub repository", inputSchema: z.object({ owner: z.string(), repo: z.string(), }), outputSchema: z.object({ ref: z.string().optional(), }), execute: async ({ context }) => { const client = await github.getApiClient(); const mainRef = await client.gitGetRef({ path: { owner: context.owner, repo: context.repo, ref: "heads/main", }, }); return { ref: mainRef.data?.ref }; }, }); ``` 上記の例では: - `github`インテグレーションをインポートしています。 - GitHub APIクライアントを使用してリポジトリのメインブランチの参照を取得する`getMainBranchRef`というツールを定義しています。 - このツールは入力として`owner`と`repo`を受け取り、参照文字列を返します。 ## エージェントでの統合の使用 統合を利用するツールを定義したら、これらのツールをエージェントに含めることができます。 ```typescript filename="src/mastra/agents/index.ts" showLineNumbers copy import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { getMainBranchRef } from "../tools"; export const codeReviewAgent = new Agent({ name: "Code Review Agent", instructions: "An agent that reviews code repositories and provides feedback.", model: openai("gpt-4o-mini"), tools: { getMainBranchRef, // other tools... }, }); ``` このセットアップでは: - `Code Review Agent` という名前のエージェントを作成します。 - エージェントの利用可能なツールに `getMainBranchRef` ツールを含めます。 - エージェントは会話中にこのツールを使用してGitHubリポジトリと対話できるようになります。 ## 環境設定 統合に必要なAPIキーやトークンが環境変数に適切に設定されていることを確認してください。例えば、GitHub統合では、GitHubパーソナルアクセストークンを設定する必要があります: ```bash GITHUB_PAT=your_personal_access_token ``` 機密情報を管理するには、`.env`ファイルや他の安全な方法の使用を検討してください。 ### 例:Mem0統合の追加 この例では、[Mem0](https://mem0.ai)プラットフォームを使用して、ツール使用を通じてエージェントに長期記憶機能を追加する方法を学びます。 この記憶統合は、Mastraの独自の[エージェント記憶機能](https://mastra.ai/docs/agents/agent-memory)と併用することができます。 Mem0を使用すると、エージェントはユーザーごとに事実を記憶し、そのユーザーとのすべてのやり取りで後で思い出すことができます。一方、Mastraの記憶はスレッドごとに機能します。両方を組み合わせて使用することで、Mem0は会話/やり取りを超えた長期的な記憶を保存し、Mastraの記憶は個々の会話内での線形的な会話履歴を維持します。 1. **統合パッケージのインストール** Mem0統合をインストールするには、次のコマンドを実行します: ```bash copy npm install @mastra/mem0@latest ``` 2. **プロジェクトに統合を追加する** 統合用の新しいファイル(例:`src/mastra/integrations/index.ts`)を作成し、統合をインポートします: ```typescript filename="src/mastra/integrations/index.ts" showLineNumbers copy import { Mem0Integration } from "@mastra/mem0"; export const mem0 = new Mem0Integration({ config: { apiKey: process.env.MEM0_API_KEY!, userId: "alice", }, }); ``` 3. **ツールやワークフローで統合を使用する** これで、エージェントのツールやワークフローを定義する際に統合を使用できます。 ```typescript filename="src/mastra/tools/index.ts" showLineNumbers copy import { createTool } from "@mastra/core"; import { z } from "zod"; import { mem0 } from "../integrations"; export const mem0RememberTool = createTool({ id: "Mem0-remember", description: "Remember your agent memories that you've previously saved using the Mem0-memorize tool.", inputSchema: z.object({ question: z .string() .describe("Question used to look up the answer in saved memories."), }), outputSchema: z.object({ answer: z.string().describe("Remembered answer"), }), execute: async ({ context }) => { console.log(`Searching memory "${context.question}"`); const memory = await mem0.searchMemory(context.question); console.log(`\nFound memory "${memory}"\n`); return { answer: memory, }; }, }); export const mem0MemorizeTool = createTool({ id: "Mem0-memorize", description: "Save information to mem0 so you can remember it later using the Mem0-remember tool.", inputSchema: z.object({ statement: z.string().describe("A statement to save into memory"), }), execute: async ({ context }) => { console.log(`\nCreating memory "${context.statement}"\n`); // to reduce latency memories can be saved async without blocking tool execution void mem0.createMemory(context.statement).then(() => { console.log(`\nMemory "${context.statement}" saved.\n`); }); return { success: true }; }, }); ``` 上記の例では: - `@mastra/mem0`統合をインポートします。 - Mem0 APIクライアントを使用して新しい記憶を作成し、以前に保存した記憶を呼び出す2つのツールを定義します。 - このツールは入力として`question`を受け取り、記憶を文字列として返します。 ```typescript filename="src/mastra/tools/index.ts" showLineNumbers copy import { createTool } from "@mastra/core"; import { z } from "zod"; import { mem0 } from "../integrations"; export const mem0RememberTool = createTool({ id: "Mem0-remember", description: "Mem0-memorizeツールを使用して以前に保存したエージェントの記憶を思い出します。", inputSchema: z.object({ question: z .string() .describe("保存された記憶の中から答えを探すために使用される質問。"), }), outputSchema: z.object({ answer: z.string().describe("思い出された答え"), }), execute: async ({ context }) => { console.log(`Searching memory "${context.question}"`); const memory = await mem0.searchMemory(context.question); console.log(`\nFound memory "${memory}"\n`); return { answer: memory, }; }, }); export const mem0MemorizeTool = createTool({ id: "Mem0-memorize", description: "Mem0に情報を保存し、後でMem0-rememberツールを使用して思い出せるようにします。", inputSchema: z.object({ statement: z.string().describe("メモリに保存する文"), }), execute: async ({ context }) => { console.log(`\nCreating memory "${context.statement}"\n`); // レイテンシーを減らすために、メモリはツールの実行をブロックせずに非同期で保存できます void mem0.createMemory(context.statement).then(() => { console.log(`\nMemory "${context.statement}" saved.\n`); }); return { success: true }; }, }); ``` 上記の例では: - `@mastra/mem0`統合をインポートします。 - Mem0 APIクライアントを使用して新しい記憶を作成し、以前に保存された記憶を呼び出す2つのツールを定義します。 - ツールは`question`を入力として受け取り、記憶を文字列として返します。 ## 利用可能な統合 Mastraは、いくつかの組み込み統合を提供しています。主にOAuthを必要としないAPIキーに基づく統合です。利用可能な統合には、Github、Stripe、Resend、Firecrawlなどがあります。 利用可能な統合の完全なリストについては、[Mastraのコードベース](https://github.com/mastra-ai/mastra/tree/main/integrations)または[npmパッケージ](https://www.npmjs.com/search?q=%22%40mastra%22)を確認してください。 --- title: "既存のプロジェクトへの追加 | Mastraローカル開発ドキュメント" description: "既存のNode.jsアプリケーションにMastraを追加する" --- # 既存のプロジェクトに追加する [JA] Source: https://mastra.ai/ja/docs/local-dev/add-to-existing-project CLIを使用して既存のプロジェクトにMastraを追加できます: ```bash npm2yarn copy npm install -g mastra@latest mastra init ``` プロジェクトに加えられる変更: 1. エントリーポイントを含む`src/mastra`ディレクトリを作成 2. 必要な依存関係を追加 3. TypeScriptコンパイラオプションを設定 ## インタラクティブセットアップ 引数なしでコマンドを実行すると、以下のためのCLIプロンプトが開始されます: 1. コンポーネントの選択 2. LLMプロバイダーの設定 3. APIキーのセットアップ 4. サンプルコードの組み込み ## 非対話式セットアップ 非対話モードでmastraを初期化するには、以下のコマンド引数を使用します: ```bash Arguments: --components Specify components: agents, tools, workflows --llm LLM provider: openai, anthropic, groq, google or cerebras --llm-api-key Provider API key --example Include example implementation --dir Directory for Mastra files (defaults to src/) ``` 詳細については、[mastra init CLIドキュメント](../../reference/cli/init)を参照してください。 --- title: "新しいプロジェクトの作成 | Mastra ローカル開発ドキュメント" description: "CLI を使って新しい Mastra プロジェクトを作成したり、既存の Node.js アプリケーションに Mastra を追加したりします" --- # 新しいプロジェクトの作成 [JA] Source: https://mastra.ai/ja/docs/local-dev/creating-a-new-project `create-mastra`パッケージを使用して新しいプロジェクトを作成できます: ```bash npm2yarn copy npm create mastra@latest ``` `mastra` CLIを直接使用して新しいプロジェクトを作成することもできます: ```bash npm2yarn copy npm install -g mastra@latest mastra create ``` ## インタラクティブセットアップ 引数なしでコマンドを実行すると、CLIプロンプトが開始され、以下の項目が設定されます: 1. プロジェクト名 1. コンポーネントの選択 1. LLMプロバイダーの設定 1. APIキーのセットアップ 1. サンプルコードの追加 ## 非対話型セットアップ 非対話型モードでmastraを初期化するには、以下のコマンド引数を使用してください。 ```bash Arguments: --components Specify components: agents, tools, workflows --llm-provider LLM provider: openai, anthropic, groq, google, or cerebras --add-example Include example implementation --llm-api-key Provider API key --project-name Project name that will be used in package.json and as the project directory name ``` 生成されるプロジェクト構成: ``` my-project/ ├── src/ │ └── mastra/ │ └── index.ts # Mastra entry point ├── package.json └── tsconfig.json ``` --- title: "`mastra dev`でエージェントを検査する | Mastra ローカル開発ドキュメント" description: MastraアプリケーションのためのMastraローカル開発環境のドキュメント。 --- import YouTube from "@/components/youtube"; # ローカル開発環境 [JA] Source: https://mastra.ai/ja/docs/local-dev/mastra-dev Mastraはローカルで開発しながらエージェント、ワークフロー、ツールをテストできるローカル開発環境を提供しています。 ## 開発サーバーの起動 Mastra CLIを使用してMastra開発環境を起動するには、次のコマンドを実行します: ```bash mastra dev ``` デフォルトでは、サーバーはlocalhostのhttp://localhost:4111で実行されます。カスタムポートとホストはmastraサーバー設定で構成できます。 ```typescript import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ server: { port: "4111", host: "0.0.0.0", }, }); ``` ## 開発プレイグラウンド `mastra dev`はエージェント、ワークフロー、ツールを操作するためのプレイグラウンドUIを提供します。このプレイグラウンドは、開発中にMastraアプリケーションの各コンポーネントをテストするための専用インターフェースを提供します。 ### エージェントプレイグラウンド エージェントプレイグラウンドは、開発中にエージェントをテストしデバッグできるインタラクティブなチャットインターフェースを提供します。主な機能は以下の通りです: - **チャットインターフェース**:エージェントと直接対話して、その応答と動作をテストできます。 - **プロンプトCMS**:エージェントの異なるシステム指示を試すことができます: - 異なるプロンプトバージョンのA/Bテスト。 - 各バリアントのパフォーマンス指標の追跡。 - 最も効果的なプロンプトバージョンの選択と展開。 - **エージェントトレース**:エージェントがリクエストを処理する方法を理解するための詳細な実行トレースを表示します: - プロンプト構築。 - ツールの使用。 - 意思決定のステップ。 - レスポンス生成。 - **エージェント評価**:[エージェント評価指標](/docs/evals/overview)を設定している場合: - プレイグラウンドから直接評価を実行できます。 - 評価結果と指標を表示できます。 - 異なるテストケースでのエージェントのパフォーマンスを比較できます。 ### ワークフロープレイグラウンド ワークフロープレイグラウンドは、ワークフロー実装の視覚化とテストに役立ちます: - **ワークフロー視覚化**:ワークフローグラフの視覚化。 - **ワークフローの実行**: - カスタム入力データでテストワークフロー実行をトリガーします。 - ワークフローロジックと条件をデバッグします。 - 異なる実行パスをシミュレートします。 - 各ステップの詳細な実行ログを表示します。 - **ワークフロートレース**:以下を示す詳細な実行トレースを調査します: - ステップバイステップのワークフロー進行。 - 状態遷移とデータフロー。 - ツール呼び出しとその結果。 - 決定ポイントと分岐ロジック。 - エラー処理と回復パス。 ### ツールプレイグラウンド ツールプレイグラウンドでは、カスタムツールを単独でテストできます: - 完全なエージェントやワークフローを実行せずに個々のツールをテストします。 - テストデータを入力してツールの応答を確認します。 - ツールの実装とエラー処理をデバッグします。 - ツールの入力/出力スキーマを検証します。 - ツールのパフォーマンスと実行時間を監視します。 ## REST API エンドポイント `mastra dev` は、ローカルの [Mastra Server](/docs/deployment/server) を通じて、エージェントとワークフローのための REST API ルートも起動します。これにより、デプロイ前に API エンドポイントをテストすることができます。すべてのエンドポイントの詳細については、[Mastra Dev リファレンス](/reference/cli/dev#routes) をご覧ください。 その後、[Mastra Client](/docs/deployment/client) SDK を活用して、提供された REST API ルートとシームレスにやり取りすることができます。 ## OpenAPI 仕様 `mastra dev` は http://localhost:4111/openapi.json で OpenAPI 仕様を提供します Mastra インスタンスで OpenAPI ドキュメントを有効にするには、以下の設定を追加してください: ```typescript import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ server: { build: { openAPIDocs: true, // Enable OpenAPI documentation // ... other build config options }, }, }); ``` ## Swagger UI Swagger UIは、APIエンドポイントをテストするためのインタラクティブなインターフェースを提供します。`mastra dev`はhttp://localhost:4111/swagger-uiでOpenAPI仕様を提供します。 MastraインスタンスでSwagger UIを有効にするには、以下の設定を追加してください: ```typescript import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ server: { build: { openAPIDocs: true, // Enable OpenAPI documentation swaggerUI: true, // Enable Swagger UI // ... other build config options }, }, }); ``` ## ローカル開発アーキテクチャ ローカル開発サーバーは、外部依存関係やコンテナ化なしで動作するように設計されています。これは以下によって実現されています: - **開発サーバー**: [Mastra Server](/docs/deployment/server)を動かすための基盤フレームワークとして[Hono](https://hono.dev)を使用します。 - **インメモリストレージ**: 以下の用途で[LibSQL](https://libsql.org/)メモリアダプターを使用します: - エージェントメモリ管理 - トレースストレージ - 評価ストレージ - ワークフロースナップショット - **ベクターストレージ**: 以下の用途で[FastEmbed](https://github.com/qdrant/fastembed)を使用します: - デフォルトの埋め込み生成 - ベクターストレージと検索 - セマンティック検索機能 このアーキテクチャにより、データベースやベクターストアを設定することなく、すぐに開発を開始できます。同時に、ローカル環境でも本番環境のような動作を維持できます。 ### モデル設定 ローカル開発サーバーでは、Overview > Model Settingsでモデル設定を構成することもできます。 以下の設定を構成できます: - **Temperature**: モデル出力のランダム性を制御します。高い値(0-2)はより創造的な応答を生成し、低い値は出力をより集中的で決定論的にします。 - **Top P**: トークンサンプリングの累積確率閾値を設定します。低い値(0-1)は最も可能性の高いトークンのみを考慮することで、出力をより集中的にします。 - **Top K**: 各生成ステップで考慮されるトークンの数を制限します。低い値は、より少ない選択肢からサンプリングすることで、より集中的な出力を生成します。 - **Frequency Penalty**: 以前のテキストでの頻度に基づいてトークンにペナルティを課すことで、繰り返しを減らします。高い値(0-2)は一般的なトークンの再利用を抑制します。 - **Presence Penalty**: 以前のテキストに現れるトークンにペナルティを課すことで、繰り返しを減らします。高い値(0-2)はモデルが新しいトピックについて議論することを促進します。 - **Max Tokens**: モデルの応答で許可される最大トークン数。高い値はより長い出力を可能にしますが、レイテンシが増加する可能性があります。 - **Max Steps**: ワークフローやエージェントが停止するまでに実行できる最大ステップ数。無限ループや暴走プロセスを防ぎます。 - **Max Retries**: 諦める前に失敗したAPIコールやモデルリクエストを再試行する回数。一時的な障害を適切に処理するのに役立ちます。 ## 概要 `mastra dev` は、本番環境にデプロイする前に、自己完結型の環境でAIロジックを開発、デバッグ、反復することを容易にします。 - [Mastra Dev リファレンス](../../reference/cli/dev.mdx) --- title: Mastra Cloudへのデプロイ description: Mastraアプリケーション向けのGitHubベースのデプロイプロセス --- # Mastra Cloudへのデプロイ [JA] Source: https://mastra.ai/ja/docs/mastra-cloud/deploying > **ベータ版のお知らせ** > Mastra Cloudは現在**パブリックベータ版**です。 このページでは、GitHubインテグレーションを使用してMastraアプリケーションをMastra Cloudにデプロイするプロセスについて説明します。 ## 前提条件 - GitHubアカウント - Mastraアプリケーションを含むGitHubリポジトリ - Mastra Cloudへのアクセス権 ## デプロイメントプロセス Mastra Cloud は、Vercel や Netlify のようなプラットフォームに似た、Git ベースのデプロイメントワークフローを採用しています。 1. **GitHub リポジトリのインポート** - Projects ダッシュボードから「Add new」をクリックします - Mastra アプリケーションが含まれているリポジトリを選択します - 対象のリポジトリの横にある「Import」をクリックします 2. **デプロイメント設定の構成** - プロジェクト名を設定します(デフォルトはリポジトリ名) - デプロイするブランチを選択します(通常は `main`) - Mastra ディレクトリパスを設定します(デフォルトは `src/mastra`) - 必要な環境変数(API キーなど)を追加します 3. **Git からのデプロイ** - 初期設定後、選択したブランチへのプッシュによってデプロイメントがトリガーされます - Mastra Cloud が自動的にアプリケーションをビルドし、デプロイします - 各デプロイメントごとに、エージェントとワークフローのアトミックスナップショットが作成されます ## 自動デプロイ Mastra Cloudはギット駆動のワークフローに従います: 1. ローカルでMastraアプリケーションに変更を加える 2. 変更を`main`ブランチにコミットする 3. GitHubにプッシュする 4. Mastra Cloudは自動的にプッシュを検出し、新しいデプロイメントを作成する 5. ビルドが完了すると、アプリケーションが本番環境で利用可能になる ## デプロイメントドメイン 各プロジェクトには2つのURLが付与されます。 1. **プロジェクト専用ドメイン**: `https://[project-name].mastra.cloud` - 例: `https://gray-acoustic-helicopter.mastra.cloud` 2. **デプロイメント専用ドメイン**: `https://[deployment-id].mastra.cloud` - 例: `https://young-loud-caravan-6156280f-ad56-4ec8-9701-6bb5271fd73d.mastra.cloud` これらのURLから、デプロイしたエージェントやワークフローに直接アクセスできます。 ## デプロイメントの表示 ![デプロイメントリスト](../../../../../public/image/cloud-agents.png) ダッシュボードのデプロイメントセクションには以下が表示されます: - **タイトル**:デプロイメント識別子(コミットハッシュに基づく) - **ステータス**:現在の状態(成功またはアーカイブ済み) - **ブランチ**:使用されたブランチ(通常は`main`) - **コミット**:Gitコミットハッシュ - **更新日時**:デプロイメントのタイムスタンプ 各デプロイメントは、特定の時点におけるMastraアプリケーションの原子的なスナップショットを表します。 ## エージェントとの対話 ![エージェントインターフェース](../../../../../public/image/cloud-agent.png) デプロイ後、エージェントと対話する方法: 1. ダッシュボードでプロジェクトに移動する 2. エージェントセクションに進む 3. エージェントを選択して詳細とインターフェースを表示する 4. チャットタブを使用してエージェントとコミュニケーションを取る 5. 右側のパネルでエージェントの設定を確認する: - モデル情報(例:OpenAI) - 利用可能なツール(例:getWeather) - 完全なシステムプロンプト 6. 提案されたプロンプト(「どのような機能がありますか?」など)を使用するか、カスタムメッセージを入力する インターフェースにはエージェントのブランチ(通常は「main」)が表示され、会話メモリが有効かどうかが示されます。 ## ログのモニタリング ログセクションはアプリケーションに関する詳細情報を提供します: - **時間**: ログエントリが作成された時刻 - **レベル**: ログレベル(info、debug) - **ホスト名**: サーバー識別情報 - **メッセージ**: 詳細なログ情報、以下を含む: - APIの初期化 - ストレージ接続 - エージェントとワークフローのアクティビティ これらのログは、本番環境でのアプリケーションの動作をデバッグおよびモニタリングするのに役立ちます。 ## ワークフロー ![ワークフローインターフェース](../../../../../public/image/cloud-workflows.png) ワークフローセクションでは、デプロイされたワークフローを表示および操作できます: 1. プロジェクト内のすべてのワークフローを表示 2. ワークフロー構造とステップを確認 3. 実行履歴とパフォーマンスデータにアクセス ## データベース使用量 Mastra Cloudはデータベース使用状況の指標を追跡します: - 読み取り回数 - 書き込み回数 - 使用ストレージ(MB) これらの指標はプロジェクト概要に表示され、リソース消費を監視するのに役立ちます。 ## デプロイメント設定 ダッシュボードからデプロイメントを設定します: 1. プロジェクト設定に移動します 2. 環境変数(`OPENAI_API_KEY`など)を設定します 3. プロジェクト固有の設定を構成します 設定の変更を反映させるには、新しいデプロイメントが必要です。 ## 次のステップ デプロイ後、オブザーバビリティツールを使用して[実行をトレースおよび監視](./observability.mdx)します。 --- title: Mastra Cloudにおける可観測性 description: Mastra Cloudデプロイメントのためのモニタリングおよびデバッグツール --- # Mastra Cloudにおける可観測性 [JA] Source: https://mastra.ai/ja/docs/mastra-cloud/observability > **ベータ版のお知らせ** > Mastra Cloudは現在**ベータ版**です。 Mastra Cloudは監視とデバッグのために実行データを記録します。エージェントとワークフローからトレース、ログ、ランタイム情報を取得します。 ## エージェントインターフェース エージェントインターフェースは、タブを通じてアクセス可能な3つの主要なビューを提供します: 1. **チャット**:エージェントをテストするためのインタラクティブなメッセージングインターフェース 2. **トレース**:詳細な実行記録 3. **評価**:エージェントのパフォーマンス評価 ![チャットタブを表示したエージェントインターフェース](../../../../../public/image/cloud-agent.png) ### チャットインターフェース チャットタブは以下を提供します: - デプロイされたエージェントとのインタラクティブなメッセージング - ユーザークエリに対するシステム応答 - 提案されるプロンプトボタン(例:「どのような機能がありますか?」) - メッセージ入力エリア - ブランチインジケーター(例:「main」) - エージェントのメモリ制限に関する注意事項 ### エージェント設定パネル 右側のサイドバーにはエージェントの詳細が表示されます: - エージェント名とデプロイメント識別子 - モデル情報(例:「OpenAI」) - エージェントが利用できるツール(例:「getWeather」) - 完全なシステムプロンプトテキスト このパネルは、ソースコードを確認することなく、エージェントがどのように設定されているかを可視化します。 ## トレースシステム Mastra Cloudはエージェントとワークフローの対話のトレースを記録します。 ### トレースエクスプローラーインターフェース ![エージェントトレースビュー](/image/cloud-agent-traces.png) トレースエクスプローラーインターフェースは以下を表示します: - すべてのエージェントとワークフローの対話 - 特定のトレースの詳細 - 入力と出力データ - パラメータと結果を含むツール呼び出し - ワークフロー実行パス - タイプ、ステータス、タイムスタンプ、エージェント/ワークフローによるフィルタリングオプション ### トレースデータ構造 各トレースには以下が含まれます: 1. **リクエストデータ**:エージェントまたはワークフローを開始したリクエスト 2. **ツール呼び出し記録**:パラメータを含む実行中のツール呼び出し 3. **ツールレスポンスデータ**:ツール呼び出しからのレスポンス 4. **エージェントレスポンスデータ**:生成されたエージェントのレスポンス 5. **実行タイムスタンプ**:各実行ステップのタイミング情報 6. **モデルメタデータ**:モデル使用量とトークンに関する情報 トレースビューは実行全体を通じてすべてのAPI呼び出しと結果を表示します。このデータはツールの使用法とエージェントのロジックフローのデバッグに役立ちます。 ### エージェント対話データ エージェント対話トレースには以下が含まれます: - ユーザー入力テキスト - エージェント処理ステップ - ツール呼び出し(例:天気APIコール) - 各ツール呼び出しのパラメータと結果 - 最終的なエージェントレスポンステキスト ## ダッシュボード構造 Mastra Cloudダッシュボードには以下が含まれています: - プロジェクトのデプロイ履歴 - 環境変数の設定 - エージェント設定の詳細(モデル、システムプロンプト、ツール) - ワークフローステップの可視化 - デプロイURL - 最近のアクティビティログ ## エージェントのテスト チャットインターフェースを使用してエージェントをテストします: 1. エージェントセクションに移動します 2. テストしたいエージェントを選択します 3. チャットタブを使用してエージェントと対話します 4. メッセージを送信し、応答を確認します 5. 一般的なクエリには推奨プロンプトを使用します 6. トレースタブに切り替えて実行の詳細を表示します デフォルトでは、エージェントはセッション間で会話履歴を記憶しないことに注意してください。インターフェースには「エージェントは以前のメッセージを記憶しません。エージェントのメモリを有効にするには画像を参照してください」というメッセージが表示されます。 ## ワークフローモニタリング ![ワークフローインターフェース](/image/cloud-workflow.png) ワークフローモニタリングでは以下を表示します: - ワークフローステップと接続の図 - 各ワークフローステップのステータス - 各ステップの実行詳細 - 実行トレースレコード - 複数ステップのプロセス実行(例:天気の検索後にアクティビティ計画を立てる) ### ワークフロー実行 ![ワークフロー実行詳細](/image/cloud-workflow-run.png) 特定のワークフロー実行を調査する際、詳細なステップとその出力を確認できます。 ## ログ ![ログインターフェース](/image/cloud-logs.png) ログセクションではアプリケーションに関する詳細情報を提供します: - **時間**: ログエントリが作成された時刻 - **レベル**: ログレベル(info、debug) - **ホスト名**: サーバー識別情報 - **メッセージ**: 詳細なログ情報(以下を含む): - API初期化 - ストレージ接続 - エージェントとワークフローのアクティビティ ## 技術的特徴 オブザーバビリティシステムには以下が含まれます: - **APIエンドポイント**:トレースデータへのプログラムによるアクセス - **構造化トレースフォーマット**:フィルタリングとクエリ操作のためのJSON形式 - **履歴データストレージ**:過去の実行記録の保持 - **デプロイメントバージョンリンク**:トレースとデプロイメントバージョン間の相関関係 ## デバッグパターン - エージェントの動作変更をテストする際にトレースデータを比較する - チャットインターフェースを使用してエッジケースの入力をテストする - システムプロンプトを確認してエージェントの動作を理解する - ツール呼び出しのパラメータと結果を調べる - ワークフロー実行のステップシーケンスを確認する - トレースのタイミングデータで実行のボトルネックを特定する - エージェントバージョン間のトレースの違いを比較する ## サポートリソース オブザーバビリティに関する技術的な支援については: - [トラブルシューティングドキュメント]()を確認する - ダッシュボードから技術サポートに連絡する - [Discordデベロッパーチャンネル](https://discord.gg/mastra)に参加する --- title: Mastra Cloud description: Mastraアプリケーションのデプロイメントと監視サービス --- # Mastra Cloud [JA] Source: https://mastra.ai/ja/docs/mastra-cloud/overview Mastra Cloudは、Mastraチームによって構築された展開サービスで、Mastraアプリケーションの実行、管理、監視を行います。標準的なMastraプロジェクトと連携し、デプロイメント、スケーリング、運用タスクを処理します。 > **ベータ版のお知らせ** > Mastra Cloudは現在**パブリックベータ版**です。開発が進むにつれて、機能、API、UIが変更される可能性があります。 ## コア機能 - **アトミックデプロイメント** - エージェントとワークフローが単一のユニットとしてデプロイされる - **プロジェクト編成** - エージェントとワークフローをURLが割り当てられたプロジェクトにグループ化 - **環境変数** - 環境ごとに設定を安全に保存 - **テストコンソール** - Webインターフェースを通じてエージェントにメッセージを送信 - **実行トレース** - エージェントの対話とツール呼び出しを記録 - **ワークフロー可視化** - ワークフローのステップと実行パスを表示 - **ログ** - デバッグ用の標準ログ出力 - **プラットフォーム互換性** - Cloudflare、Vercel、Netlifyデプロイヤーと同じインフラストラクチャを使用 ## ダッシュボードコンポーネント Mastra Cloudダッシュボードには以下が含まれています: - **プロジェクトリスト** - アカウント内のすべてのプロジェクト - **プロジェクト詳細** - デプロイメント、環境変数、アクセスURL - **デプロイメント履歴** - タイムスタンプとステータスを含むデプロイメントの記録 - **エージェントインスペクター** - モデル、ツール、システムプロンプトを表示するエージェント設定ビュー - **テストコンソール** - エージェントにメッセージを送信するためのインターフェース - **トレースエクスプローラー** - ツール呼び出し、パラメータ、レスポンスの記録 - **ワークフロービューア** - ワークフローステップと接続の図 ## 技術的な実装 Mastra Cloudは、プラットフォーム固有のデプロイヤーと同じコアコードで動作し、以下の修正が加えられています: - **エッジネットワーク分散** - 地理的に分散された実行 - **動的リソース割り当て** - トラフィックに基づいてコンピューティングリソースを調整 - **Mastra専用ランタイム** - エージェント実行に最適化されたランタイム - **標準デプロイメントAPI** - 環境間で一貫したデプロイメントインターフェース - **トレーシングインフラストラクチャ** - すべてのエージェントとワークフロー実行ステップを記録 ## ユースケース 一般的な使用パターン: - インフラストラクチャを管理せずにアプリケーションをデプロイする - ステージング環境と本番環境を維持する - 多くのリクエストにわたるエージェントの動作を監視する - Webインターフェースを通じてエージェントの応答をテストする - 複数のリージョンにデプロイする ## セットアッププロセス 1. [Mastra Cloudプロジェクトを設定する](/docs/mastra-cloud/setting-up) 2. [コードをデプロイする](/docs/mastra-cloud/deploying) 3. [実行トレースを表示する](/docs/mastra-cloud/observability) --- title: プロジェクトのセットアップ description: Mastra Cloudプロジェクトの設定手順 --- # Mastra Cloudプロジェクトの設定 [JA] Source: https://mastra.ai/ja/docs/mastra-cloud/setting-up > **ベータ版のお知らせ** > Mastra Cloudは現在**ベータ版**です。 このページでは、GitHub連携を使用してMastra Cloudでプロジェクトを設定する手順について説明します。 ## 前提条件 - Mastra Cloudアカウント - GitHubアカウント - Mastraアプリケーションを含むGitHubリポジトリ ## プロジェクト作成プロセス 1. **Mastra Cloudにサインイン** - Mastra Cloudダッシュボード(https://cloud.mastra.ai)に移動します - アカウント認証情報でサインインします 2. **新しいプロジェクトを追加** - 「すべてのプロジェクト」ビューから、右上の「新規追加」ボタンをクリックします - GitHubリポジトリのインポートダイアログが開きます ![Mastra Cloudプロジェクトダッシュボード](/image/cloud-agents.png) 3. **Gitリポジトリをインポート** - リポジトリを検索するか、利用可能なGitHubリポジトリのリストから選択します - デプロイしたいリポジトリの横にある「インポート」ボタンをクリックします 4. **デプロイメント詳細の設定** デプロイメント設定ページには以下が含まれます: - **リポジトリ名**:GitHubリポジトリ名(読み取り専用) - **プロジェクト名**:プロジェクト名をカスタマイズ(デフォルトはリポジトリ名) - **ブランチ**:デプロイするブランチを選択(ドロップダウン、デフォルトは`main`) - **プロジェクトルート**:プロジェクトのルートディレクトリを設定(デフォルトは`/`) - **Mastraディレクトリ**:Mastraファイルの場所を指定(デフォルトは`src/mastra`) - **ビルドコマンド**:ビルドプロセス中に実行するオプションコマンド - **ストア設定**:データストレージオプションを設定 - **環境変数**:設定用のキーと値のペアを追加(例:APIキー) ## プロジェクト構造の要件 Mastra CloudはGitHubリポジトリを以下の項目についてスキャンします: - **エージェント**:モデルとツールを備えたエージェント定義(例:天気エージェント) - **ワークフロー**:ワークフローステップ定義(例:weather-workflow) - **環境変数**:必要なAPIキーと設定変数 リポジトリは、適切な検出とデプロイメントのために標準的なMastraプロジェクト構造を含んでいる必要があります。 ## ダッシュボードの理解 プロジェクトを作成すると、ダッシュボードには以下が表示されます: ### プロジェクト概要 - **作成日**: プロジェクトが作成された日時 - **ドメイン**: デプロイされたアプリケーションにアクセスするためのURL - 形式: `https://[project-name].mastra.cloud` - 形式: `https://[random-id].mastra.cloud` - **ステータス**: 現在のデプロイメントステータス(成功またはアーカイブ済み) - **ブランチ**: デプロイされたブランチ(通常は`main`) - **環境変数**: 設定されたAPIキーと設定 - **ワークフロー**: 検出されたワークフローとステップ数のリスト - **エージェント**: 検出されたエージェントとそのモデルおよびツールのリスト - **データベース使用状況**: 読み取り、書き込み、ストレージの統計情報 ### デプロイメントセクション - すべてのデプロイメントのリスト: - デプロイメントID(コミットハッシュに基づく) - ステータス(成功/アーカイブ済み) - ブランチ - コミットハッシュ - タイムスタンプ ### ログセクション ログビューには以下が表示されます: - 各ログエントリのタイムスタンプ - ログレベル(info、debug) - ホスト名 - 詳細なログメッセージ(以下を含む): - API起動情報 - ストレージ初期化 - エージェントとワークフローのアクティビティ ## ナビゲーション サイドバーから以下にアクセスできます: - **概要**:プロジェクトの概要と統計 - **デプロイメント**:デプロイ履歴と詳細 - **ログ**:デバッグ用のアプリケーションログ - **エージェント**:すべてのエージェントのリストと設定 - **ワークフロー**:すべてのワークフローのリストと構造 - **設定**:プロジェクト構成オプション ## 環境変数の設定 ダッシュボードを通じて環境変数を設定します: 1. ダッシュボードでプロジェクトに移動します 2. 「環境変数」セクションに進みます 3. 変数を追加または編集します(例:`OPENAI_API_KEY`) 4. 設定を保存します 環境変数は暗号化され、デプロイメントと実行中にアプリケーションで利用可能になります。 ## デプロイメントのテスト デプロイメント後、以下の方法でエージェントとワークフローをテストできます: 1. プロジェクトに割り当てられたカスタムドメイン:`https://[project-name].mastra.cloud` 2. エージェントと直接対話するためのダッシュボードインターフェース ## 次のステップ プロジェクトを設定した後、GitHubリポジトリの`main`ブランチにプッシュするたびに自動デプロイが行われます。詳細については、[デプロイメントのドキュメント](./deploying.mdx)を参照してください。 # メモリプロセッサ [JA] Source: https://mastra.ai/ja/docs/memory/memory-processors メモリプロセッサを使用すると、メモリから取得されたメッセージのリストを、エージェントのコンテキストウィンドウに追加されLLMに送信される_前に_変更することができます。これはコンテキストサイズの管理、コンテンツのフィルタリング、パフォーマンスの最適化に役立ちます。 プロセッサは、メモリ設定(例:`lastMessages`、`semanticRecall`)に基づいて取得されたメッセージに対して動作します。新しく入ってくるユーザーメッセージには**影響しません**。 ## 組み込みプロセッサ Mastra には組み込みプロセッサが用意されています。 ### `TokenLimiter` このプロセッサは、LLM のコンテキストウィンドウの上限を超えることによるエラーを防ぐために使用されます。取得したメモリメッセージ内のトークン数をカウントし、合計が指定された `limit` 未満になるまで最も古いメッセージを削除します。 ```typescript copy showLineNumbers {9-12} import { Memory } from "@mastra/memory"; import { TokenLimiter } from "@mastra/memory/processors"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const agent = new Agent({ model: openai("gpt-4o"), memory: new Memory({ processors: [ // Ensure the total tokens from memory don't exceed ~127k new TokenLimiter(127000), ], }), }); ``` `TokenLimiter` はデフォルトで `o200k_base` エンコーディング(GPT-4o に適しています)を使用します。必要に応じて、他のモデル向けに別のエンコーディングを指定することもできます。 ```typescript copy showLineNumbers {6-9} // Import the encoding you need (e.g., for older OpenAI models) import cl100k_base from "js-tiktoken/ranks/cl100k_base"; const memoryForOlderModel = new Memory({ processors: [ new TokenLimiter({ limit: 16000, // Example limit for a 16k context model encoding: cl100k_base, }), ], }); ``` エンコーディングの詳細については、[OpenAI cookbook](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken#encodings) や [`js-tiktoken` リポジトリ](https://github.com/dqbd/tiktoken) を参照してください。 ### `ToolCallFilter` このプロセッサは、LLM に送信されるメモリメッセージからツールコールを削除します。これにより、コンテキストから冗長になりがちなツールのやり取りを除外してトークンを節約できます。今後のやり取りで詳細が不要な場合に便利です。また、常に特定のツールを再度呼び出したい場合や、メモリ内の以前のツール結果に依存させたくない場合にも有用です。 ```typescript copy showLineNumbers {5-14} import { Memory } from "@mastra/memory"; import { ToolCallFilter, TokenLimiter } from "@mastra/memory/processors"; const memoryFilteringTools = new Memory({ processors: [ // Example 1: Remove all tool calls/results new ToolCallFilter(), // Example 2: Remove only noisy image generation tool calls/results new ToolCallFilter({ exclude: ["generateImageTool"] }), // Always place TokenLimiter last new TokenLimiter(127000), ], }); ``` ## 複数のプロセッサの適用 複数のプロセッサを連結して使用することができます。これらは `processors` 配列に記載された順番で実行されます。あるプロセッサの出力が、次のプロセッサの入力となります。 **順序は重要です!** 一般的には、`TokenLimiter` をチェーンの**最後**に配置するのがベストプラクティスです。これにより、他のフィルタリングが行われた後の最終的なメッセージセットに対して動作し、最も正確なトークン制限の適用が可能になります。 ```typescript copy showLineNumbers {7-14} import { Memory } from "@mastra/memory"; import { ToolCallFilter, TokenLimiter } from "@mastra/memory/processors"; // Assume a hypothetical 'PIIFilter' custom processor exists // import { PIIFilter } from './custom-processors'; const memoryWithMultipleProcessors = new Memory({ processors: [ // 1. Filter specific tool calls first new ToolCallFilter({ exclude: ["verboseDebugTool"] }), // 2. Apply custom filtering (e.g., remove hypothetical PII - use with caution) // new PIIFilter(), // 3. Apply token limiting as the final step new TokenLimiter(127000), ], }); ``` ## カスタムプロセッサの作成 `MemoryProcessor` 基底クラスを拡張することで、カスタムロジックを作成できます。 ```typescript copy showLineNumbers {4-19,23-26} import { Memory, CoreMessage } from "@mastra/memory"; import { MemoryProcessor, MemoryProcessorOpts } from "@mastra/core/memory"; class ConversationOnlyFilter extends MemoryProcessor { constructor() { // Provide a name for easier debugging if needed super({ name: "ConversationOnlyFilter" }); } process( messages: CoreMessage[], _opts: MemoryProcessorOpts = {}, // Options passed during memory retrieval, rarely needed here ): CoreMessage[] { // Filter messages based on role return messages.filter( (msg) => msg.role === "user" || msg.role === "assistant", ); } } // Use the custom processor const memoryWithCustomFilter = new Memory({ processors: [ new ConversationOnlyFilter(), new TokenLimiter(127000), // Still apply token limiting ], }); ``` カスタムプロセッサを作成する際は、入力として渡される `messages` 配列やそのオブジェクトを直接変更しないようにしてください。 # メモリの概要 [JA] Source: https://mastra.ai/ja/docs/memory/overview メモリは、エージェントが利用可能なコンテキストを管理する方法であり、すべてのチャットメッセージをコンテキストウィンドウに凝縮したものです。 ## コンテキストウィンドウ コンテキストウィンドウは、言語モデルが任意の時点で見ることができる情報の総量です。 Mastraでは、コンテキストは3つの部分に分かれています:システム指示とユーザーに関する情報([ワーキングメモリ](./working-memory.mdx))、最近のメッセージ([メッセージ履歴](#conversation-history))、そしてユーザーのクエリに関連する古いメッセージ([セマンティック検索](./semantic-recall.mdx))です。 さらに、コンテキストが長すぎる場合にコンテキストをトリミングしたり情報を削除したりするための[メモリプロセッサ](./memory-processors.mdx)も提供しています。 ## クイックスタート メモリの動作を最も早く確認する方法は、組み込みの開発プレイグラウンドを使用することです。 まだ作成していない場合は、メインの[Getting Startedガイド](/docs/getting-started/installation)に従って新しいMastraプロジェクトを作成してください。 **1. メモリパッケージをインストールします:** ```bash npm2yarn copy npm install @mastra/memory@latest ``` **2. エージェントを作成し、`Memory`インスタンスをアタッチします:** ```typescript filename="src/mastra/agents/index.ts" {6-18} import { Agent } from "@mastra/core/agent"; import { Memory } from "@mastra/memory"; import { openai } from "@ai-sdk/openai"; import { LibSQLStore } from "@mastra/libsql"; // Initialize memory with LibSQLStore for persistence const memory = new Memory({ storage: new LibSQLStore({ url: "file:../mastra.db", // Or your database URL }), }); export const myMemoryAgent = new Agent({ name: "MemoryAgent", instructions: "...", model: openai("gpt-4o"), memory, }); ``` **3. 開発サーバーを起動します:** ```bash npm2yarn copy npm run dev ``` **4. プレイグラウンド(http://localhost:4111)を開き、`MemoryAgent`を選択します:** いくつかのメッセージを送信し、ターン間で情報を記憶していることを確認してください: ``` ➡️ You: My favorite color is blue. ⬅️ Agent: Got it! I'll remember that your favorite color is blue. ➡️ You: What is my favorite color? ⬅️ Agent: Your favorite color is blue. ``` ## メモリースレッド Mastraはメモリーをスレッドに整理します。スレッドは特定の会話履歴を識別する記録であり、次の2つの識別子を使用します: 1. **`threadId`**: 特定の会話ID(例:`support_123`)。 2. **`resourceId`**: 各スレッドを所有するユーザーまたはエンティティID(例:`user_123`、`org_456`)。 ```typescript {2,3} const response = await myMemoryAgent.stream("Hello, my name is Alice.", { resourceId: "user_alice", threadId: "conversation_123", }); ``` **重要:** これらのIDがなければ、メモリーが適切に設定されていても、エージェントはメモリーを使用しません。プレイグラウンドではこれが自動的に処理されますが、アプリケーションでメモリーを使用する場合は自分でIDを追加する必要があります。 ## 会話履歴 デフォルトでは、`Memory`インスタンスは現在のMemoryスレッドから[最新の10件のメッセージ](../../reference/memory/Memory.mdx)を各新規リクエストに含めます。これにより、エージェントに即時の会話コンテキストが提供されます。 ```ts {3} const memory = new Memory({ options: { lastMessages: 10, }, }); ``` **重要:** 各エージェント呼び出しでは、最新のユーザーメッセージのみを送信してください。Mastraは必要な履歴の取得と挿入を処理します。履歴全体を自分で送信すると重複が発生します。`useChat`フロントエンドフックを使用する場合の処理方法については、[AI SDK Memoryの例](../../examples/memory/use-chat.mdx)を参照してください。 ### ストレージ設定 会話履歴はメッセージを保存するために[ストレージアダプター](/reference/memory/Memory#parameters)に依存しています。 デフォルトでは、[メインのMastraインスタンス](https://mastra.ai/reference/core/mastra-class#initialization)に提供されたものと同じストレージを使用します。 `Memory`インスタンスも`Mastra`オブジェクトもストレージプロバイダーを指定していない場合、Mastraはアプリケーションの再起動やデプロイメント間でメモリデータを永続化しません。ローカルテスト以外のデプロイメントでは、`Mastra`または`new Memory()`内で直接独自のストレージ設定を提供する必要があります。 `Mastra`インスタンスに`storage`が指定されている場合、エージェントに接続されているすべての`Memory`で自動的に使用されます。その場合、エージェントごとのオーバーライドが必要でない限り、`new Memory()`に`storage`を渡す必要はありません。 ```ts {7-9} import { Memory } from "@mastra/memory"; import { Agent } from "@mastra/core/agent"; import { LibSQLStore } from "@mastra/libsql"; const agent = new Agent({ memory: new Memory({ storage: new LibSQLStore({ url: "file:./local.db", }), }), }); ``` **ストレージコードの例**: - [LibSQL](/examples/memory/memory-with-libsql) - [Postgres](/examples/memory/memory-with-pg) - [Upstash](/examples/memory/memory-with-upstash) ## 次のステップ コアコンセプトを理解したところで、[セマンティック検索](./semantic-recall.mdx)に進んで、MastraエージェントにRAGメモリを追加する方法を学びましょう。 あるいは、利用可能なオプションについては[設定リファレンス](../../reference/memory/Memory.mdx)を参照するか、[使用例](../../examples/memory/use-chat.mdx)を閲覧することもできます。 # セマンティック リコール [JA] Source: https://mastra.ai/ja/docs/memory/semantic-recall 友人に先週末何をしたか尋ねると、彼らは「先週末」に関連する出来事を記憶の中から検索し、それから何をしたかを教えてくれます。これはMastraにおけるセマンティックリコールの仕組みに少し似ています。 ## セマンティックリコールの仕組み セマンティックリコールはRAGベースの検索であり、メッセージが[最近の会話履歴](./overview.mdx#conversation-history)に含まれなくなった場合でも、エージェントが長期間の対話にわたってコンテキストを維持するのに役立ちます。 メッセージのベクトル埋め込みを使用して類似性検索を行い、さまざまなベクトルストアと統合し、取得されたメッセージの周囲のコンテキストウィンドウを設定可能です。
Mastra Memoryのセマンティックリコールを示す図 有効にすると、新しいメッセージを使用してベクトルDBに意味的に類似したメッセージを問い合わせます。 LLMからの応答を受け取った後、すべての新しいメッセージ(ユーザー、アシスタント、ツールコール/結果)がベクトルDBに挿入され、後の対話で呼び出されるようになります。 ## クイックスタート セマンティックリコールはデフォルトで有効になっているため、エージェントにメモリを与えると、それが含まれます: ```typescript {9} import { Agent } from "@mastra/core/agent"; import { Memory } from "@mastra/memory"; import { openai } from "@ai-sdk/openai"; const agent = new Agent({ name: "SupportAgent", instructions: "You are a helpful support agent.", model: openai("gpt-4o"), memory: new Memory(), }); ``` ## Recall設定 セマンティックリコールの動作を制御する主要な3つのパラメータは以下の通りです: 1. **topK**: セマンティックに類似したメッセージを何件取得するか 2. **messageRange**: 各マッチに含める周辺コンテキストの範囲 3. **scope**: 現在のスレッド内で検索するか、リソースが所有するすべてのスレッドを対象に検索するか。`scope: 'resource'`を使用すると、エージェントはユーザーの過去の会話すべてから情報を思い出すことができます。 ```typescript {5-7} const agent = new Agent({ memory: new Memory({ options: { semanticRecall: { topK: 3, // 最も類似した3つのメッセージを取得 messageRange: 2, // 各マッチの前後2つのメッセージを含める scope: 'resource', // このユーザーのすべてのスレッドを検索 }, }, }), }); ``` 注意:現在、セマンティックリコールの`scope: 'resource'`は以下のストレージアダプターでサポートされています:LibSQL、Postgres、Upstash。 ### ストレージ設定 セマンティックリコールは、メッセージとその埋め込みを保存するために[ストレージとベクターDB](/reference/memory/Memory#parameters)に依存しています。 ```ts {8-17} import { Memory } from "@mastra/memory"; import { Agent } from "@mastra/core/agent"; import { LibSQLStore, LibSQLVector } from "@mastra/libsql"; const agent = new Agent({ memory: new Memory({ // 省略した場合のデフォルトストレージDB storage: new LibSQLStore({ url: "file:./local.db", }), // 省略した場合のデフォルトベクターDB vector: new LibSQLVector({ connectionUrl: "file:./local.db", }), }), }); ``` **ストレージ/ベクターコードの例**: - [LibSQL](/examples/memory/memory-with-libsql) - [Postgres](/examples/memory/memory-with-pg) - [Upstash](/examples/memory/memory-with-upstash) ### 埋め込み設定 セマンティックリコールは、メッセージを埋め込みに変換するために[埋め込みモデル](/reference/memory/Memory#embedder)に依存しています。AI SDKと互換性のある任意の[埋め込みモデル](https://sdk.vercel.ai/docs/ai-sdk-core/embeddings)を指定できます。 FastEmbed(ローカル埋め込みモデル)を使用するには、`@mastra/fastembed`をインストールしてください: ```bash npm2yarn copy npm install @mastra/fastembed ``` 次に、メモリで設定します: ```ts {3,8} import { Memory } from "@mastra/memory"; import { Agent } from "@mastra/core/agent"; import { fastembed } from "@mastra/fastembed"; const agent = new Agent({ memory: new Memory({ // ... その他のメモリオプション embedder: fastembed, }), }); ``` または、OpenAIなど別のプロバイダーを使用します: ```ts {3,8} import { Memory } from "@mastra/memory"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const agent = new Agent({ memory: new Memory({ // ... その他のメモリオプション embedder: openai.embedding("text-embedding-3-small"), }), }); ``` ### 無効化 セマンティックリコールの使用にはパフォーマンスへの影響があります。新しいメッセージは埋め込みに変換され、新しいメッセージがLLMに送信される前にベクターデータベースのクエリに使用されます。 セマンティックリコールはデフォルトで有効になっていますが、不要な場合は無効にできます: ```typescript {4} const agent = new Agent({ memory: new Memory({ options: { semanticRecall: false, }, }), }); ``` 以下のようなシナリオでセマンティックリコールを無効にすることを検討してください: - 会話履歴が現在の会話に十分なコンテキストを提供している場合。 - リアルタイム双方向音声のようなパフォーマンス重視のアプリケーションで、埋め込みの作成とベクタークエリの実行による追加の遅延が顕著な場合。 import YouTube from "@/components/youtube"; # ワーキングメモリ [JA] Source: https://mastra.ai/ja/docs/memory/working-memory [会話履歴](/docs/memory/overview#conversation-history)や[セマンティック検索](./semantic-recall.mdx)がエージェントが会話を記憶するのに役立つ一方、ワーキングメモリはエージェントがスレッド内の対話全体でユーザーに関する永続的な情報を維持することを可能にします。 これはエージェントのアクティブな思考やメモ帳のようなものと考えてください - ユーザーやタスクについて利用可能な状態に保つ重要な情報です。これは、人が会話中に自然に相手の名前、好み、または重要な詳細を覚えておくのと似ています。 これは、常に関連性があり、エージェントが常に利用できるべき継続的な状態を維持するのに役立ちます。 ## クイックスタート 以下は、ワーキングメモリを設定したエージェントの最小限の例です: ```typescript {12-15} import { Agent } from "@mastra/core/agent"; import { Memory } from "@mastra/memory"; import { openai } from "@ai-sdk/openai"; // Create agent with working memory enabled const agent = new Agent({ name: "PersonalAssistant", instructions: "You are a helpful personal assistant.", model: openai("gpt-4o"), memory: new Memory({ options: { workingMemory: { enabled: true, }, }, }), }); ``` ## 仕組み ワーキングメモリは、エージェントが継続的に関連する情報を保存するために時間の経過とともに更新できるMarkdownテキストのブロックです: ## カスタムテンプレート テンプレートは、エージェントがワーキングメモリで追跡および更新する情報を指示します。テンプレートが提供されない場合はデフォルトのテンプレートが使用されますが、通常はエージェントの特定のユースケースに合わせたカスタムテンプレートを定義して、最も関連性の高い情報を確実に記憶させたいでしょう。 以下はカスタムテンプレートの例です。この例では、ユーザーが情報を含むメッセージを送信するとすぐに、エージェントはユーザーの名前、場所、タイムゾーンなどを保存します: ```typescript {5-28} const memory = new Memory({ options: { workingMemory: { enabled: true, template: ` # User Profile ## Personal Info - Name: - Location: - Timezone: ## Preferences - Communication Style: [e.g., Formal, Casual] - Project Goal: - Key Deadlines: - [Deadline 1]: [Date] - [Deadline 2]: [Date] ## Session State - Last Task Discussed: - Open Questions: - [Question 1] - [Question 2] `, }, }, }); ``` ## 効果的なテンプレートの設計 適切に構造化されたテンプレートは、エージェントが情報を解析して更新しやすくします。テンプレートを、アシスタントが最新の状態を保つべき簡潔なフォームとして扱いましょう。 - **短く、焦点を絞ったラベル。** 段落や非常に長い見出しは避けてください。ラベルは簡潔に(例えば `## Personal Info` や `- Name:`)して、更新が読みやすく、切り捨てられる可能性を減らします。 - **一貫した大文字小文字の使用。** 大文字小文字の不一致(`Timezone:` と `timezone:`)は、更新を乱雑にする可能性があります。見出しや箇条書きのラベルには、タイトルケースまたは小文字を一貫して使用してください。 - **プレースホルダーテキストはシンプルに。** `[e.g., Formal]` や `[Date]` などのヒントを使用して、LLMが正しい場所に入力できるようにします。 - **非常に長い値は省略する。** 短い形式だけが必要な場合は、`- Name: [First name or nickname]` や `- Address (short):` のようなガイダンスを含めて、完全な法的テキストではなく簡潔にします。 - **更新ルールは `instructions` で言及する。** テンプレートの一部をいつどのように埋めるか、またはクリアするかの指示を、エージェントの `instructions` フィールドに直接記述できます。 ### 代替テンプレートスタイル 少数の項目だけが必要な場合は、より短い単一ブロックを使用します: ```typescript const basicMemory = new Memory({ options: { workingMemory: { enabled: true, template: `User Facts:\n- Name:\n- Favorite Color:\n- Current Topic:`, }, }, }); ``` より物語的なスタイルを好む場合は、重要な事実を短い段落形式で保存することもできます: ```typescript const paragraphMemory = new Memory({ options: { workingMemory: { enabled: true, template: `Important Details:\n\nKeep a short paragraph capturing the user's important facts (name, main goal, current task).`, }, }, }); ``` ## 例:複数ステップの保持 以下は、短いユーザー会話を通じて`User Profile`テンプレートがどのように更新されるかを簡略化して示したものです: ```nohighlight # User Profile ## Personal Info - Name: - Location: - Timezone: --- ユーザーが「私の名前は**Sam**で、**ベルリン**出身です」と言った後 --- # User Profile - Name: Sam - Location: Berlin - Timezone: --- ユーザーが「ちなみに普段は**CET**にいます」と追加した後 --- # User Profile - Name: Sam - Location: Berlin - Timezone: CET ``` エージェントは情報を再度要求することなく、後の応答で`Sam`や`Berlin`を参照できるようになります。これは、その情報がワーキングメモリに保存されているためです。 エージェントが期待通りにワーキングメモリを更新していない場合は、エージェントの`instructions`設定でこのテンプレートを_どのように_、_いつ_使用するかについてのシステム指示を追加することができます。 ## 例 - [ストリーミングワーキングメモリ](/examples/memory/streaming-working-memory) - [ワーキングメモリテンプレートの使用](/examples/memory/streaming-working-memory-advanced) --- title: "ロギング | Mastra 可観測性ドキュメント" description: Mastraでの効果的なロギングに関するドキュメント。アプリケーションの動作を理解し、AI精度を向上させるために不可欠です。 --- import Image from "next/image"; # ロギング [JA] Source: https://mastra.ai/ja/docs/observability/logging Mastraでは、ログは特定の関数がいつ実行されるか、どのような入力データを受け取るか、そしてどのように応答するかを詳細に記録できます。 ## 基本設定 以下は、**コンソールロガー**を`INFO`レベルで設定する最小限の例です。これにより、情報メッセージ以上(つまり、`DEBUG`、`INFO`、`WARN`、`ERROR`)がコンソールに出力されます。 ```typescript filename="mastra.config.ts" showLineNumbers copy import { Mastra } from "@mastra/core"; import { PinoLogger } from "@mastra/loggers"; export const mastra = new Mastra({ // Other Mastra configuration... logger: new PinoLogger({ name: "Mastra", level: "info", }), }); ``` この設定では: - `name: "Mastra"` はログをグループ化する名前を指定します。 - `level: "info"` は記録するログの最小重要度を設定します。 ## 設定 - `PinoLogger()`に渡すことができるオプションの詳細については、[PinoLoggerリファレンスドキュメント](/reference/observability/logger)を参照してください。 - `Logger`インスタンスを取得したら、[Loggerインスタンスリファレンスドキュメント](/reference/observability/logger)でそのメソッド(例:`.info()`、`.warn()`、`.error()`)を呼び出すことができます。 - ログを一元的な収集、分析、または保存のために外部サービスに送信したい場合は、Upstash Redisなどの他のロガータイプを設定できます。`UPSTASH`ロガータイプを使用する際の`url`、`token`、`key`などのパラメータの詳細については、[Loggerリファレンスドキュメント](/reference/observability/logger)を参照してください。 --- title: "Next.js トレーシング | Mastra Observability ドキュメント" description: "Next.js アプリケーションのための OpenTelemetry トレーシングの設定" --- # Next.js トレーシング [JA] Source: https://mastra.ai/ja/docs/observability/nextjs-tracing Next.js で OpenTelemetry トレーシングを有効にするには、追加の設定が必要です。 ### ステップ 1: Next.js の設定 まず、Next.js の設定ファイルでインストゥルメンテーションフックを有効にします。 ```ts filename="next.config.ts" showLineNumbers copy import type { NextConfig } from "next"; const nextConfig: NextConfig = { experimental: { instrumentationHook: true, // Not required in Next.js 15+ }, }; export default nextConfig; ``` ### ステップ 2: Mastra の設定 Mastra インスタンスを設定します。 ```typescript filename="mastra.config.ts" copy import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "your-project-name", enabled: true, }, }); ``` ### ステップ 3: プロバイダーの設定 Next.js を使用している場合、OpenTelemetry インストゥルメンテーションのセットアップ方法は2つあります。 #### オプション 1: カスタムエクスポーターの使用 すべてのプロバイダーで動作するデフォルトの方法は、カスタムエクスポーターを設定することです。 1. 必要な依存関係をインストールします(例: Langfuse を使用)。 ```bash copy npm install @opentelemetry/api langfuse-vercel ``` 2. インストゥルメンテーションファイルを作成します。 ```ts filename="instrumentation.ts" copy import { NodeSDK, ATTR_SERVICE_NAME, Resource, } from "@mastra/core/telemetry/otel-vendor"; import { LangfuseExporter } from "langfuse-vercel"; export function register() { const exporter = new LangfuseExporter({ // ... Langfuse config }); const sdk = new NodeSDK({ resource: new Resource({ [ATTR_SERVICE_NAME]: "ai", }), traceExporter: exporter, }); sdk.start(); } ``` #### オプション 2: Vercel の Otel セットアップの使用 Vercel へデプロイする場合は、Vercel の OpenTelemetry セットアップを利用できます。 1. 必要な依存関係をインストールします。 ```bash copy npm install @opentelemetry/api @vercel/otel ``` 2. プロジェクトのルート(または src フォルダ)にインストゥルメンテーションファイルを作成します。 ```ts filename="instrumentation.ts" copy import { registerOTel } from "@vercel/otel"; export function register() { registerOTel({ serviceName: "your-project-name" }); } ``` ### まとめ このセットアップにより、Next.js アプリケーションおよび Mastra の操作で OpenTelemetry トレーシングが有効になります。 詳細については、以下のドキュメントをご覧ください。 - [Next.js Instrumentation](https://nextjs.org/docs/app/building-your-application/optimizing/instrumentation) - [Vercel OpenTelemetry](https://vercel.com/docs/observability/otel-overview/quickstart) --- title: "トレーシング | Mastra 可観測性ドキュメント" description: "Mastraアプリケーション用のOpenTelemetryトレーシングをセットアップする" --- import Image from "next/image"; # トレーシング [JA] Source: https://mastra.ai/ja/docs/observability/tracing MastraはアプリケーションのトレーシングとモニタリングのためにOpenTelemetryプロトコル(OTLP)をサポートしています。テレメトリが有効になっている場合、Mastraはエージェント操作、LLM連携、ツール実行、インテグレーション呼び出し、ワークフロー実行、データベース操作などのすべてのコアプリミティブを自動的にトレースします。テレメトリデータは任意のOTELコレクターにエクスポートできます。 ### 基本設定 テレメトリを有効にする簡単な例を示します: ```ts filename="mastra.config.ts" showLineNumbers copy export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "my-app", enabled: true, sampling: { type: "always_on", }, export: { type: "otlp", endpoint: "http://localhost:4318", // SigNoz local endpoint }, }, }); ``` ### 設定オプション テレメトリ設定は以下のプロパティを受け付けます: ```ts type OtelConfig = { // トレースでサービスを識別する名前(オプション) serviceName?: string; // テレメトリの有効/無効(デフォルトはtrue) enabled?: boolean; // サンプリングするトレースの数を制御 sampling?: { type: "ratio" | "always_on" | "always_off" | "parent_based"; probability?: number; // 比率サンプリング用 root?: { probability: number; // 親ベースのサンプリング用 }; }; // テレメトリデータの送信先 export?: { type: "otlp" | "console"; endpoint?: string; headers?: Record; }; }; ``` 詳細については[OtelConfig リファレンスドキュメント](../../reference/observability/otel-config.mdx)を参照してください。 ### 環境変数 環境変数を通じてOTLPエンドポイントとヘッダーを設定できます: ```env filename=".env" copy OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 OTEL_EXPORTER_OTLP_HEADERS=x-api-key=your-api-key ``` そして設定では: ```ts filename="mastra.config.ts" showLineNumbers copy export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "my-app", enabled: true, export: { type: "otlp", // エンドポイントとヘッダーは環境変数から取得されます }, }, }); ``` ### 例:SigNoz連携 [SigNoz](https://signoz.io)でのトレースされたエージェントインタラクションの例です: スパン、LLM呼び出し、ツール実行を示すエージェントインタラクショントレース ### その他のサポートされているプロバイダー サポートされている監視プロバイダーの完全なリストとその設定の詳細については、[監視プロバイダーリファレンス](../../reference/observability/providers/)を参照してください。 ### Next.js固有のトレーシング手順 Next.jsを使用している場合は、3つの追加設定手順があります: 1. `next.config.ts`で計測フックを有効にする 2. Mastraテレメトリ設定を構成する 3. OpenTelemetryエクスポーターをセットアップする 実装の詳細については、[Next.jsトレーシング](./nextjs-tracing)ガイドを参照してください。 --- title: 文書のチャンキングと埋め込み | RAG | Mastra ドキュメント description: Mastraでの効率的な処理と検索のための文書のチャンキングと埋め込みに関するガイド。 --- ## ドキュメントのチャンク化と埋め込み [JA] Source: https://mastra.ai/ja/docs/rag/chunking-and-embedding 処理を行う前に、コンテンツからMDocumentインスタンスを作成します。様々な形式から初期化することができます: ```ts showLineNumbers copy const docFromText = MDocument.fromText("Your plain text content..."); const docFromHTML = MDocument.fromHTML("Your HTML content..."); const docFromMarkdown = MDocument.fromMarkdown("# Your Markdown content..."); const docFromJSON = MDocument.fromJSON(`{ "key": "value" }`); ``` ## ステップ1:ドキュメント処理 `chunk`を使用してドキュメントを管理しやすい部分に分割します。Mastraは異なるドキュメントタイプに最適化された複数のチャンキング戦略をサポートしています: - `recursive`:コンテンツ構造に基づくスマートな分割 - `character`:シンプルな文字ベースの分割 - `token`:トークンを考慮した分割 - `markdown`:Markdownを考慮した分割 - `html`:HTML構造を考慮した分割 - `json`:JSON構造を考慮した分割 - `latex`:LaTeX構造を考慮した分割 以下は`recursive`戦略を使用する例です: ```ts showLineNumbers copy const chunks = await doc.chunk({ strategy: "recursive", size: 512, overlap: 50, separator: "\n", extract: { metadata: true, // オプションでメタデータを抽出 }, }); ``` **注意:** メタデータ抽出にはLLM呼び出しが使用される場合があるため、APIキーが設定されていることを確認してください。 チャンキング戦略についての詳細は[チャンクドキュメント](/reference/rag/chunk.mdx)で説明しています。 ## ステップ 2: 埋め込み生成 チャンクをお好みのプロバイダーを使って埋め込みに変換します。Mastra は OpenAI や Cohere など、多くの埋め込みプロバイダーをサポートしています。 ### OpenAI を使う場合 ```ts showLineNumbers copy import { openai } from "@ai-sdk/openai"; import { embedMany } from "ai"; const { embeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: chunks.map((chunk) => chunk.text), }); ``` ### Cohere を使う場合 ```ts showLineNumbers copy import { cohere } from "@ai-sdk/cohere"; import { embedMany } from "ai"; const { embeddings } = await embedMany({ model: cohere.embedding("embed-english-v3.0"), values: chunks.map((chunk) => chunk.text), }); ``` 埋め込み関数は、テキストの意味的な内容を表す数値の配列(ベクトル)を返します。これらはベクトルデータベースでの類似検索にすぐに利用できます。 ### 埋め込み次元数の設定 埋め込みモデルは通常、固定された次元数(例: OpenAI の `text-embedding-3-small` なら 1536)のベクトルを出力します。 一部のモデルではこの次元数を減らすことができ、以下のような利点があります: - ベクトルデータベースでの保存容量を削減できる - 類似検索時の計算コストを抑えられる 以下はサポートされているモデルの例です: OpenAI(text-embedding-3 モデル): ```ts const { embeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small", { dimensions: 256, // text-embedding-3 以降でのみサポート }), values: chunks.map((chunk) => chunk.text), }); ``` Google(text-embedding-004): ```ts const { embeddings } = await embedMany({ model: google.textEmbeddingModel("text-embedding-004", { outputDimensionality: 256, // 末尾から余分な値を切り捨てます }), values: chunks.map((chunk) => chunk.text), }); ``` ### ベクトルデータベースの互換性 埋め込みを保存する際は、ベクトルデータベースのインデックスが埋め込みモデルの出力サイズと一致するように設定する必要があります。次元数が一致しない場合、エラーやデータの破損が発生することがあります。 ## 例:完全なパイプライン 以下は、両方のプロバイダーを使用したドキュメント処理と埋め込み生成の例です: ```ts showLineNumbers copy import { embedMany } from "ai"; import { openai } from "@ai-sdk/openai"; import { cohere } from "@ai-sdk/cohere"; import { MDocument } from "@mastra/rag"; // Initialize document const doc = MDocument.fromText(` Climate change poses significant challenges to global agriculture. Rising temperatures and changing precipitation patterns affect crop yields. `); // Create chunks const chunks = await doc.chunk({ strategy: "recursive", size: 256, overlap: 50, }); // Generate embeddings with OpenAI const { embeddings: openAIEmbeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: chunks.map((chunk) => chunk.text), }); // OR // Generate embeddings with Cohere const { embeddings: cohereEmbeddings } = await embedMany({ model: cohere.embedding("embed-english-v3.0"), values: chunks.map((chunk) => chunk.text), }); // Store embeddings in your vector database await vectorStore.upsert({ indexName: "embeddings", vectors: embeddings, }); ``` ## 異なるチャンキング戦略と埋め込み設定の例については、以下を参照してください: - [チャンクサイズの調整](/reference/rag/chunk.mdx#adjust-chunk-size) - [チャンク区切り文字の調整](/reference/rag/chunk.mdx#adjust-chunk-delimiters) - [Cohereを使用したテキストの埋め込み](/reference/rag/embeddings.mdx#using-cohere) ベクトルデータベースと埋め込みの詳細については、以下を参照してください: - [ベクトルデータベース](./vector-databases.mdx) - [埋め込みAPIリファレンス](/reference/rag/embeddings.mdx) --- title: MastraにおけるRAG(検索拡張生成) | Mastraドキュメント description: Mastraにおける検索拡張生成(RAG)の概要。関連するコンテキストでLLMの出力を強化する機能の詳細。 --- # MastraにおけるRAG(検索拡張生成) [JA] Source: https://mastra.ai/ja/docs/rag/overview MastraのRAGは、独自のデータソースから関連するコンテキストを取り込むことでLLMの出力を強化し、精度を向上させ、実際の情報に基づいた応答を提供します。 MastraのRAGシステムは以下を提供します: - 文書を処理し埋め込むための標準化されたAPI - 複数のベクトルストアのサポート - 最適な検索のためのチャンキングと埋め込み戦略 - 埋め込みと検索のパフォーマンスを追跡するための可観測性 ## 例 RAGを実装するには、ドキュメントをチャンクに処理し、埋め込みを作成し、ベクターデータベースに保存してから、クエリ時に関連するコンテキストを取得します。 ```ts showLineNumbers copy import { embedMany } from "ai"; import { openai } from "@ai-sdk/openai"; import { PgVector } from "@mastra/pg"; import { MDocument } from "@mastra/rag"; import { z } from "zod"; // 1. Initialize document const doc = MDocument.fromText(`Your document text here...`); // 2. Create chunks const chunks = await doc.chunk({ strategy: "recursive", size: 512, overlap: 50, }); // 3. Generate embeddings; we need to pass the text of each chunk const { embeddings } = await embedMany({ values: chunks.map((chunk) => chunk.text), model: openai.embedding("text-embedding-3-small"), }); // 4. Store in vector database const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING, }); await pgVector.upsert({ indexName: "embeddings", vectors: embeddings, }); // using an index name of 'embeddings' // 5. Query similar chunks const results = await pgVector.query({ indexName: "embeddings", queryVector: queryVector, topK: 3, }); // queryVector is the embedding of the query console.log("Similar chunks:", results); ``` この例では基本的な要素を示しています:ドキュメントを初期化し、チャンクを作成し、埋め込みを生成し、それらを保存し、類似するコンテンツをクエリします。 ## ドキュメント処理 RAGの基本的な構成要素はドキュメント処理です。ドキュメントは様々な戦略(再帰的、スライディングウィンドウなど)を使用して分割し、メタデータで強化することができます。[チャンキングと埋め込みのドキュメント](./chunking-and-embedding.mdx)を参照してください。 ## ベクターストレージ Mastraは、pgvector、Pinecone、Qdrant、MongoDBを含む、埋め込みの永続化と類似性検索のための複数のベクターストアをサポートしています。[ベクターデータベースのドキュメント](./vector-databases.mdx)を参照してください。 ## 可観測性とデバッグ Mastraの RAGシステムには、検索パイプラインを最適化するための可観測性機能が含まれています: - 埋め込み生成のパフォーマンスとコストを追跡 - チャンクの品質と検索の関連性を監視 - クエリパターンとキャッシュヒット率を分析 - メトリクスを可観測性プラットフォームにエクスポート 詳細については、[OTel設定](../../reference/observability/otel-config.mdx)ページをご覧ください。 ## その他のリソース - [Chain of Thought RAGの例](../../examples/rag/usage/cot-rag.mdx) - [すべてのRAG例](../../examples/) (異なるチャンキング戦略、埋め込みモデル、ベクトルストアを含む) --- title: "検索、セマンティック検索、リランキング | RAG | Mastra ドキュメント" description: Mastraの RAGシステムにおける検索プロセスに関するガイド。セマンティック検索、フィルタリング、リランキングを含みます。 --- import { Tabs } from "nextra/components"; ## RAGシステムにおける検索 [JA] Source: https://mastra.ai/ja/docs/rag/retrieval 埋め込みを保存した後、ユーザーのクエリに答えるために関連するチャンクを検索する必要があります。 Mastraは、セマンティック検索、フィルタリング、再ランキングに対応した柔軟な検索オプションを提供します。 ## 検索の仕組み 1. ユーザーのクエリは、ドキュメント埋め込みと同じモデルを使って埋め込みに変換されます 2. この埋め込みは、ベクトル類似度を用いて保存された埋め込みと比較されます 3. 最も類似したチャンクが取得され、必要に応じて以下の処理が行われます: - メタデータでフィルタリング - より高い関連性のために再ランク付け - ナレッジグラフを通じて処理 ## 基本的な検索 最もシンプルな方法は、直接的なセマンティック検索です。この方法では、ベクトル類似度を利用して、クエリと意味的に類似したチャンクを見つけます。 ```ts showLineNumbers copy import { openai } from "@ai-sdk/openai"; import { embed } from "ai"; import { PgVector } from "@mastra/pg"; // Convert query to embedding const { embedding } = await embed({ value: "What are the main points in the article?", model: openai.embedding("text-embedding-3-small"), }); // Query vector store const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING, }); const results = await pgVector.query({ indexName: "embeddings", queryVector: embedding, topK: 10, }); // Display results console.log(results); ``` 結果には、テキストコンテンツと類似度スコアの両方が含まれます。 ```ts showLineNumbers copy [ { text: "Climate change poses significant challenges...", score: 0.89, metadata: { source: "article1.txt" }, }, { text: "Rising temperatures affect crop yields...", score: 0.82, metadata: { source: "article1.txt" }, }, // ... more results ]; ``` 基本的な検索方法の使い方については、[Retrieve Results](../../examples/rag/query/retrieve-results.mdx) の例をご覧ください。 ## 高度な検索オプション ### メタデータフィルタリング メタデータフィールドに基づいて結果をフィルタリングし、検索範囲を絞り込みます。これは、異なるソース、時期、または特定の属性を持つドキュメントがある場合に便利です。Mastraは、サポートされているすべてのベクターストアで動作する統一されたMongoDB形式のクエリ構文を提供します。 利用可能な演算子と構文の詳細については、[メタデータフィルターリファレンス](/reference/rag/metadata-filters)を参照してください。 基本的なフィルタリングの例: ```ts showLineNumbers copy // Simple equality filter const results = await pgVector.query({ indexName: "embeddings", queryVector: embedding, topK: 10, filter: { source: "article1.txt", }, }); // Numeric comparison const results = await pgVector.query({ indexName: "embeddings", queryVector: embedding, topK: 10, filter: { price: { $gt: 100 }, }, }); // Multiple conditions const results = await pgVector.query({ indexName: "embeddings", queryVector: embedding, topK: 10, filter: { category: "electronics", price: { $lt: 1000 }, inStock: true, }, }); // Array operations const results = await pgVector.query({ indexName: "embeddings", queryVector: embedding, topK: 10, filter: { tags: { $in: ["sale", "new"] }, }, }); // Logical operators const results = await pgVector.query({ indexName: "embeddings", queryVector: embedding, topK: 10, filter: { $or: [{ category: "electronics" }, { category: "accessories" }], $and: [{ price: { $gt: 50 } }, { price: { $lt: 200 } }], }, }); ``` メタデータフィルタリングの一般的な使用例: - ドキュメントのソースやタイプでフィルタリング - 日付範囲でフィルタリング - 特定のカテゴリやタグでフィルタリング - 数値範囲でフィルタリング(例:価格、評価) - 複数の条件を組み合わせて精密なクエリを実行 - ドキュメント属性でフィルタリング(例:言語、著者) メタデータフィルタリングの使用例については、[ハイブリッドベクター検索](../../examples/rag/query/hybrid-vector-search.mdx)の例を参照してください。 ### ベクタークエリツール エージェントにベクターデータベースを直接クエリする能力を与えたい場合があります。ベクタークエリツールを使用すると、エージェントが検索の決定を担当し、セマンティック検索をオプションのフィルタリングやリランキングと組み合わせて、ユーザーのニーズに対するエージェントの理解に基づいて実行できます。 ```ts showLineNumbers copy const vectorQueryTool = createVectorQueryTool({ vectorStoreName: "pgVector", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), }); ``` ツールを作成する際は、ツールの名前と説明に特に注意を払ってください。これらは、エージェントが検索機能をいつ、どのように使用するかを理解するのに役立ちます。例えば、「SearchKnowledgeBase」と名前を付け、「Xトピックに関する関連情報を見つけるためにドキュメントを検索する」と説明することができます。 これは特に以下の場合に便利です: - エージェントが取得する情報を動的に決定する必要がある場合 - 検索プロセスが複雑な意思決定を必要とする場合 - エージェントがコンテキストに基づいて複数の検索戦略を組み合わせることを望む場合 #### データベース固有の設定 ベクタークエリツールは、異なるベクターストアの独自の機能と最適化を活用できるデータベース固有の設定をサポートしています: ```ts showLineNumbers copy // Pinecone with namespace const pineconeQueryTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pinecone: { namespace: "production" // Isolate data by environment } } }); // pgVector with performance tuning const pgVectorQueryTool = createVectorQueryTool({ vectorStoreName: "postgres", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pgvector: { minScore: 0.7, // Filter low-quality results ef: 200, // HNSW search parameter probes: 10 // IVFFlat probe parameter } } }); // Chroma with advanced filtering const chromaQueryTool = createVectorQueryTool({ vectorStoreName: "chroma", indexName: "documents", model: openai.embedding("text-embedding-3-small"), databaseConfig: { chroma: { where: { "category": "technical" }, whereDocument: { "$contains": "API" } } } }); // LanceDB with table specificity const lanceQueryTool = createVectorQueryTool({ vectorStoreName: "lance", indexName: "documents", model: openai.embedding("text-embedding-3-small"), databaseConfig: { lance: { tableName: "myVectors", // Specify which table to query includeAllColumns: true // Include all metadata columns in results } } }); ``` **主な利点:** - **Pineconeネームスペース**: テナント、環境、またはデータタイプ別にベクトルを整理 - **pgVector最適化**: ef/probesパラメータで検索精度と速度を制御 - **品質フィルタリング**: 最小類似度閾値を設定して結果の関連性を向上 - **LanceDBテーブル**: より良い整理とパフォーマンスのためにデータをテーブルに分離 - **ランタイム柔軟性**: コンテキストに基づいて設定を動的にオーバーライド **一般的な使用例:** - Pineconeネームスペースを使用したマルチテナントアプリケーション - 高負荷シナリオでのパフォーマンス最適化 - 環境固有の設定(dev/staging/prod) - 品質ゲート付き検索結果 - エッジデプロイメントシナリオ向けのLanceDBを使用した組み込み、ファイルベースのベクトルストレージ また、ランタイムコンテキストを使用してこれらの設定をランタイムでオーバーライドすることもできます: ```ts showLineNumbers copy import { RuntimeContext } from '@mastra/core/runtime-context'; const runtimeContext = new RuntimeContext(); runtimeContext.set('databaseConfig', { pinecone: { namespace: 'runtime-namespace' } }); await pineconeQueryTool.execute({ context: { queryText: 'search query' }, mastra, runtimeContext }); ``` 詳細な設定オプションと高度な使用方法については、[Vector Query Tool Reference](/reference/tools/vector-query-tool)を参照してください。 ### Vector Store Prompts ベクトルストアプロンプトは、各ベクトルデータベース実装のクエリパターンとフィルタリング機能を定義します。 フィルタリングを実装する際、これらのプロンプトは各ベクトルストア実装の有効な演算子と構文を指定するために、エージェントの指示に必要です。 {/* LLM CONTEXT: This Tabs component displays vector store configuration examples for different database providers. Each tab shows how to configure a RAG agent with the appropriate prompt for that specific vector store. The tabs demonstrate the consistent pattern of importing the store-specific prompt and adding it to agent instructions. This helps users understand how to properly configure their RAG agents for different vector database backends. The providers include Pg Vector, Pinecone, Qdrant, Chroma, Astra, LibSQL, Upstash, Cloudflare, MongoDB, and OpenSearch. */} ```ts showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { PGVECTOR_PROMPT } from "@mastra/pg"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` 提供されたコンテキストを使用してクエリを処理します。簡潔で関連性の高い応答を構造化してください。 ${PGVECTOR_PROMPT} `, tools: { vectorQueryTool }, }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { PINECONE_PROMPT } from "@mastra/pinecone"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` 提供されたコンテキストを使用してクエリを処理します。簡潔で関連性の高い応答を構造化してください。 ${PINECONE_PROMPT} `, tools: { vectorQueryTool }, }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { QDRANT_PROMPT } from "@mastra/qdrant"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` 提供されたコンテキストを使用してクエリを処理します。簡潔で関連性の高い応答を構造化してください。 ${QDRANT_PROMPT} `, tools: { vectorQueryTool }, }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { CHROMA_PROMPT } from "@mastra/chroma"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` 提供されたコンテキストを使用してクエリを処理します。簡潔で関連性の高い応答を構造化してください。 ${CHROMA_PROMPT} `, tools: { vectorQueryTool }, }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { ASTRA_PROMPT } from "@mastra/astra"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` 提供されたコンテキストを使用してクエリを処理します。簡潔で関連性の高い応答を構造化してください。 ${ASTRA_PROMPT} `, tools: { vectorQueryTool }, }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { LIBSQL_PROMPT } from "@mastra/libsql"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` 提供されたコンテキストを使用してクエリを処理します。簡潔で関連性の高い応答を構造化してください。 ${LIBSQL_PROMPT} `, tools: { vectorQueryTool }, }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { UPSTASH_PROMPT } from "@mastra/upstash"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` 提供されたコンテキストを使用してクエリを処理します。簡潔で関連性の高い応答を構造化してください。 ${UPSTASH_PROMPT} `, tools: { vectorQueryTool }, }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { VECTORIZE_PROMPT } from "@mastra/vectorize"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` 提供されたコンテキストを使用してクエリを処理します。簡潔で関連性の高い応答を構造化してください。 ${VECTORIZE_PROMPT} `, tools: { vectorQueryTool }, }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { MONGODB_PROMPT } from "@mastra/mongodb"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` 提供されたコンテキストを使用してクエリを処理します。レスポンスは簡潔で関連性のあるものに構造化してください。 ${MONGODB_PROMPT} `, tools: { vectorQueryTool }, }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { openai } from '@ai-sdk/openai'; import { OPENSEARCH_PROMPT } from "@mastra/opensearch"; export const ragAgent = new Agent({ name: 'RAG Agent', model: openai('gpt-4o-mini'), instructions: ` 提供されたコンテキストを使用してクエリを処理します。レスポンスは簡潔で関連性のあるものに構造化してください。 ${OPENSEARCH_PROMPT} `, tools: { vectorQueryTool }, }); ``` ### Re-ranking 初期のベクトル類似度検索では、微妙な関連性を見逃すことがあります。Re-rankingは計算コストが高いプロセスですが、より正確なアルゴリズムで以下により結果を改善します: - 単語の順序と完全一致を考慮 - より洗練された関連性スコアリングを適用 - クエリと文書間のクロスアテンションと呼ばれる手法を使用 Re-rankingの使用方法は以下の通りです: ```ts showLineNumbers copy import { openai } from "@ai-sdk/openai"; import { rerank } from "@mastra/rag"; // Get initial results from vector search const initialResults = await pgVector.query({ indexName: "embeddings", queryVector: queryEmbedding, topK: 10, }); // Re-rank the results const rerankedResults = await rerank( initialResults, query, openai("gpt-4o-mini"), ); ``` > **注意:** Re-ranking中にセマンティックスコアリングが適切に機能するためには、各結果の`metadata.text`フィールドにテキストコンテンツが含まれている必要があります。 Re-rankingされた結果は、ベクトル類似度とセマンティック理解を組み合わせて、検索品質を向上させます。 Re-rankingの詳細については、[rerank()](/reference/rag/rerank)メソッドを参照してください。 Re-rankingメソッドの使用例については、[Re-ranking Results](../../examples/rag/rerank/rerank.mdx)の例を参照してください。 ### Graph-based Retrieval 複雑な関係を持つ文書の場合、グラフベースの検索はチャンク間の接続をたどることができます。これは以下の場合に役立ちます: - 情報が複数の文書に分散している場合 - 文書が互いを参照している場合 - 完全な回答を見つけるために関係をたどる必要がある場合 セットアップ例: ```ts showLineNumbers copy const graphQueryTool = createGraphQueryTool({ vectorStoreName: "pgVector", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), graphOptions: { threshold: 0.7, }, }); ``` グラフベース検索の詳細については、[GraphRAG](/reference/rag/graph-rag)クラスと[createGraphQueryTool()](/reference/tools/graph-rag-tool)関数を参照してください。 グラフベース検索メソッドの使用例については、[Graph-based Retrieval](../../examples/rag/usage/graph-rag.mdx)の例を参照してください。 --- title: "ベクトルデータベースへのエンベディングの保存 | Mastra Docs" description: Mastraにおけるベクトルストレージオプションのガイド。類似性検索のための組み込みおよび専用ベクトルデータベースを含みます。 --- import { Tabs } from "nextra/components"; ## ベクトルデータベースへの埋め込みの保存 [JA] Source: https://mastra.ai/ja/docs/rag/vector-databases 埋め込みを生成した後、ベクトル類似性検索をサポートするデータベースに保存する必要があります。Mastraは、さまざまなベクトルデータベース間で埋め込みを保存およびクエリするための一貫したインターフェースを提供します。 ## サポートされているデータベース {/* LLM CONTEXT: This Tabs component showcases different vector database implementations supported by Mastra. Each tab demonstrates the setup and configuration for a specific vector database provider. The tabs show consistent API patterns across different databases, helping users understand how to switch between providers. Each tab includes import statements, initialization code, and basic operations (createIndex, upsert) for that specific database. The providers include Pg Vector, Pinecone, Qdrant, Chroma, Astra, LibSQL, Upstash, Cloudflare, MongoDB, OpenSearch, and Couchbase. */} ```ts filename="vector-store.ts" showLineNumbers copy import { MongoDBVector } from '@mastra/mongodb' const store = new MongoDBVector({ uri: process.env.MONGODB_URI, dbName: process.env.MONGODB_DATABASE }) await store.createIndex({ indexName: "myCollection", dimension: 1536, }); await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ### MongoDB Atlas Vector searchの使用 詳細なセットアップ手順とベストプラクティスについては、[公式MongoDB Atlas Vector Search ドキュメント](https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-overview/?utm_campaign=devrel\&utm_source=third-party-content\&utm_medium=cta\&utm_content=mastra-docs)をご覧ください。 ```ts filename="vector-store.ts" showLineNumbers copy import { PgVector } from '@mastra/pg'; const store = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING }) await store.createIndex({ indexName: "myCollection", dimension: 1536, }); await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ### pgvectorを使用したPostgreSQLの使用 pgvector拡張機能を使用したPostgreSQLは、すでにPostgreSQLを使用しており、インフラストラクチャの複雑さを最小限に抑えたいチームにとって良いソリューションです。 詳細なセットアップ手順とベストプラクティスについては、[公式pgvectorリポジトリ](https://github.com/pgvector/pgvector)をご覧ください。 ```ts filename="vector-store.ts" showLineNumbers copy import { PineconeVector } from '@mastra/pinecone' const store = new PineconeVector({ apiKey: process.env.PINECONE_API_KEY, }) await store.createIndex({ indexName: "myCollection", dimension: 1536, }); await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { QdrantVector } from '@mastra/qdrant' const store = new QdrantVector({ url: process.env.QDRANT_URL, apiKey: process.env.QDRANT_API_KEY }) await store.createIndex({ indexName: "myCollection", dimension: 1536, }); await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { ChromaVector } from '@mastra/chroma' const store = new ChromaVector() await store.createIndex({ indexName: "myCollection", dimension: 1536, }); await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { AstraVector } from '@mastra/astra' const store = new AstraVector({ token: process.env.ASTRA_DB_TOKEN, endpoint: process.env.ASTRA_DB_ENDPOINT, keyspace: process.env.ASTRA_DB_KEYSPACE }) await store.createIndex({ indexName: "myCollection", dimension: 1536, }); await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { LibSQLVector } from "@mastra/core/vector/libsql"; const store = new LibSQLVector({ connectionUrl: process.env.DATABASE_URL, authToken: process.env.DATABASE_AUTH_TOKEN // Optional: for Turso cloud databases }) await store.createIndex({ indexName: "myCollection", dimension: 1536, }); await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { UpstashVector } from '@mastra/upstash' // In upstash they refer to the store as an index const store = new UpstashVector({ url: process.env.UPSTASH_URL, token: process.env.UPSTASH_TOKEN }) // There is no store.createIndex call here, Upstash creates indexes (known as namespaces in Upstash) automatically // when you upsert if that namespace does not exist yet. await store.upsert({ indexName: "myCollection", // the namespace name in Upstash vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { CloudflareVector } from '@mastra/vectorize' const store = new CloudflareVector({ accountId: process.env.CF_ACCOUNT_ID, apiToken: process.env.CF_API_TOKEN }) await store.createIndex({ indexName: "myCollection", dimension: 1536, }); await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { OpenSearchVector } from '@mastra/opensearch' const store = new OpenSearchVector({ url: process.env.OPENSEARCH_URL }) await store.createIndex({ indexName: "my-collection", dimension: 1536, }); await store.upsert({ indexName: "my-collection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { CouchbaseVector } from '@mastra/couchbase' const store = new CouchbaseVector({ connectionString: process.env.COUCHBASE_CONNECTION_STRING, username: process.env.COUCHBASE_USERNAME, password: process.env.COUCHBASE_PASSWORD, bucketName: process.env.COUCHBASE_BUCKET, scopeName: process.env.COUCHBASE_SCOPE, collectionName: process.env.COUCHBASE_COLLECTION, }) await store.createIndex({ indexName: "myCollection", dimension: 1536, }); await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ```ts filename="vector-store.ts" showLineNumbers copy import { LanceVectorStore } from '@mastra/lance' const store = await LanceVectorStore.create('/path/to/db') await store.createIndex({ tableName: "myVectors", indexName: "myCollection", dimension: 1536, }); await store.upsert({ tableName: "myVectors", vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), }); ``` ### LanceDBの使用 LanceDBは、Lance列形式上に構築された組み込みベクトルデータベースで、ローカル開発やクラウドデプロイメントに適しています。 詳細なセットアップ手順とベストプラクティスについては、[公式LanceDBドキュメント](https://lancedb.github.io/lancedb/)をご覧ください。 ## ベクターストレージの使用 初期化が完了すると、すべてのベクターストアはインデックスの作成、埋め込みのアップサート、クエリの実行に同じインターフェースを共有します。 ### インデックスの作成 埋め込みを保存する前に、使用する埋め込みモデルに適した次元数でインデックスを作成する必要があります。 ```ts filename="store-embeddings.ts" showLineNumbers copy // Create an index with dimension 1536 (for text-embedding-3-small) await store.createIndex({ indexName: "myCollection", dimension: 1536, }); ``` 次元数は、選択した埋め込みモデルの出力次元と一致している必要があります。一般的な次元数の例は以下の通りです: - OpenAI text-embedding-3-small: 1536次元(またはカスタム例:256) - Cohere embed-multilingual-v3: 1024次元 - Google `text-embedding-004`: 768次元(またはカスタム) > **重要**: インデックスの次元数は作成後に変更できません。別のモデルを使用する場合は、インデックスを削除し、新しい次元数で再作成してください。 ### データベースの命名規則 各ベクターデータベースは、互換性を確保し競合を防ぐために、インデックスやコレクションの命名規則を定めています。 {/* LLM CONTEXT: This Tabs component displays naming convention rules for different vector databases. Each tab explains the specific naming requirements and restrictions for that database provider. This helps users understand the constraints and avoid naming conflicts when creating indexes or collections. The tabs provide examples of valid and invalid names to clarify the rules for each database. */} コレクション(インデックス)名は以下の条件を満たす必要があります: - 文字またはアンダースコアで始まる - 最大120バイトの長さ - 文字、数字、アンダースコア、またはドットのみを含む - `$`またはnull文字を含むことはできない - 例:`my_collection.123`は有効 - 例:`my-index`は無効(ハイフンを含む) - 例:`My$Collection`は無効(`$`を含む) インデックス名は以下の条件を満たす必要があります: - 文字またはアンダースコアで始まる - 文字、数字、アンダースコアのみを含む - 例:`my_index_123`は有効 - 例:`my-index`は無効(ハイフンを含む) インデックス名は以下の条件を満たす必要があります: - 小文字、数字、ダッシュのみを使用 - ドットを含まない(DNSルーティングに使用されるため) - 非ラテン文字や絵文字を使用しない - プロジェクトIDとの組み合わせで52文字未満 - 例:`my-index-123`は有効 - 例:`my.index`は無効(ドットを含む) コレクション名は以下の条件を満たす必要があります: - 1-255文字の長さ - 以下の特殊文字を含まない: - `< > : " / \ | ? *` - Null文字(`\0`) - 単位区切り文字(`\u{1F}`) - 例:`my_collection_123`は有効 - 例:`my/collection`は無効(スラッシュを含む) コレクション名は以下の条件を満たす必要があります: - 3-63文字の長さ - 文字または数字で始まり、終わる - 文字、数字、アンダースコア、またはハイフンのみを含む - 連続するピリオド(..)を含まない - 有効なIPv4アドレスではない - 例:`my-collection-123`は有効 - 例:`my..collection`は無効(連続するピリオド) コレクション名は以下の条件を満たす必要があります: - 空でない - 48文字以下 - 文字、数字、アンダースコアのみを含む - 例:`my_collection_123`は有効 - 例:`my-collection`は無効(ハイフンを含む) インデックス名は以下の条件を満たす必要があります: - 文字またはアンダースコアで始まる - 文字、数字、アンダースコアのみを含む - 例:`my_index_123`は有効 - 例:`my-index`は無効(ハイフンを含む) 名前空間名は以下の条件を満たす必要があります: - 2-100文字の長さ - 以下のみを含む: - 英数字(a-z、A-Z、0-9) - アンダースコア、ハイフン、ドット - 特殊文字(_、-、.)で始まったり終わったりしない - 大文字小文字を区別する場合がある - 例:`MyNamespace123`は有効 - 例:`_namespace`は無効(アンダースコアで始まる) インデックス名は以下の条件を満たす必要があります: - 文字で始まる - 32文字未満 - 小文字のASCII文字、数字、ダッシュのみを含む - スペースの代わりにダッシュを使用 - 例:`my-index-123`は有効 - 例:`My_Index`は無効(大文字とアンダースコア) インデックス名は以下の条件を満たす必要があります: - 小文字のみを使用 - アンダースコアやハイフンで始まらない - スペース、カンマを含まない - 特殊文字を含まない(例:`:`、`"`、`*`、`+`、`/`、`\`、`|`、`?`、`#`、`>`、`<`) - 例:`my-index-123`は有効 - 例:`My_Index`は無効(大文字を含む) - 例:`_myindex`は無効(アンダースコアで始まる) ### 埋め込みのアップサート インデックスを作成した後、基本的なメタデータと共に埋め込みを保存できます: ```ts filename="store-embeddings.ts" showLineNumbers copy // Store embeddings with their corresponding metadata await store.upsert({ indexName: "myCollection", // index name vectors: embeddings, // array of embedding vectors metadata: chunks.map((chunk) => ({ text: chunk.text, // The original text content id: chunk.id, // Optional unique identifier })), }); ``` upsert操作は: - 埋め込みベクトルの配列とそれに対応するメタデータを受け取ります - 同じIDを共有する既存のベクトルがある場合は更新します - 存在しない場合は新しいベクトルを作成します - 大規模なデータセットに対して自動的にバッチ処理を行います 異なるベクトルストアでの埋め込みのupsertの完全な例については、[Upsert Embeddings](../../examples/rag/upsert/upsert-embeddings.mdx)ガイドを参照してください。 ## メタデータの追加 ベクトルストアはフィルタリングと整理のためのリッチなメタデータ(JSONシリアライズ可能なフィールド)をサポートしています。メタデータは固定されたスキーマなしで保存されるため、予期しないクエリ結果を避けるために一貫したフィールド命名を使用してください。 **重要**:メタデータはベクトルストレージにとって非常に重要です - これがなければ、数値的な埋め込みだけが残り、元のテキストを返したり結果をフィルタリングしたりする方法がなくなります。少なくとも元のテキストをメタデータとして常に保存してください。 ```ts showLineNumbers copy // Store embeddings with rich metadata for better organization and filtering await store.upsert({ indexName: "myCollection", vectors: embeddings, metadata: chunks.map((chunk) => ({ // Basic content text: chunk.text, id: chunk.id, // Document organization source: chunk.source, category: chunk.category, // Temporal metadata createdAt: new Date().toISOString(), version: "1.0", // Custom fields language: chunk.language, author: chunk.author, confidenceScore: chunk.score, })), }); ``` メタデータに関する重要な考慮事項: - フィールド命名に厳格であること - 「category」と「Category」のような不一致はクエリに影響します - フィルタリングやソートに使用する予定のフィールドのみを含める - 余分なフィールドはオーバーヘッドを追加します - コンテンツの鮮度を追跡するためのタイムスタンプ(例:「createdAt」、「lastUpdated」)を追加する ## ベストプラクティス - 大量挿入の前にインデックスを作成する - 大量挿入にはバッチ操作を使用する(upsertメソッドは自動的にバッチ処理を行います) - クエリを実行する予定のメタデータのみを保存する - 埋め込みの次元数をモデルに合わせる(例:`text-embedding-3-small`の場合は1536) --- title: Mastraのストレージ | Mastraドキュメント description: Mastraのストレージシステムとデータ永続化機能の概要。 --- import { Tabs } from "nextra/components"; import { PropertiesTable } from "@/components/properties-table"; import { SchemaTable } from "@/components/schema-table"; import { StorageOverviewImage } from "@/components/storage-overview-image"; # MastraStorage [JA] Source: https://mastra.ai/ja/docs/storage/overview `MastraStorage`は以下を管理するための統一インターフェースを提供します: - **一時停止されたワークフロー**:一時停止されたワークフローのシリアル化された状態(後で再開できるように) - **メモリ**:アプリケーション内の`resourceId`ごとのスレッドとメッセージ - **トレース**:MastraのすべてのコンポーネントからのOpenTelemetryトレース - **評価データセット**:評価実行からのスコアと採点理由

Mastraは異なるストレージプロバイダーを提供していますが、それらを互換性のあるものとして扱うことができます。例えば、開発環境ではlibsqlを使用し、本番環境ではpostgresを使用することができ、コードは両方の環境で同じように動作します。 ## 設定 Mastra はデフォルトのストレージオプションで設定できます。 ```typescript copy import { Mastra } from "@mastra/core/mastra"; import { LibSQLStore } from "@mastra/libsql"; const mastra = new Mastra({ storage: new LibSQLStore({ url: "file:./mastra.db", }), }); ``` `storage` 設定を指定しない場合、Mastra はアプリケーションの再起動やデプロイメントの際にデータを永続化しません。ローカルテスト以外のデプロイメントでは、`Mastra` または `new Memory()` 内で独自のストレージ設定を指定する必要があります。 ## データスキーマ {/* LLM CONTEXT: This Tabs component displays the database schema for different data types stored by Mastra. Each tab shows the table structure and column definitions for a specific data entity (Messages, Threads, Workflows, etc.). The tabs help users understand the data model and relationships between different storage entities. Each tab includes detailed column information with types, constraints, and example data structures. The data types include Messages, Threads, Workflows, Eval Datasets, and Traces. */} 会話メッセージとそのメタデータを保存します。各メッセージはスレッドに属し、送信者の役割とメッセージタイプに関するメタデータと共に実際のコンテンツを含みます。
メッセージの`content`列には、`MastraMessageContentV2`型に準拠したJSONオブジェクトが含まれており、AI SDKの`UIMessage`メッセージ形状と密接に整合するよう設計されています。
関連するメッセージをグループ化し、リソースと関連付けます。会話に関するメタデータが含まれます。
ワークフローで`suspend`が呼び出されると、その状態は以下の形式で保存されます。`resume`が呼び出されると、その状態が復元されます。
エージェントの出力に対してメトリクスを実行した評価結果を保存します。
監視とデバッグのためのOpenTelemetryトレースをキャプチャします。
### メッセージのクエリ メッセージは内部的にV2形式で保存されており、これはAI SDKの`UIMessage`形式とほぼ同等です。`getMessages`を使用してメッセージをクエリする際、希望する出力形式を指定でき、後方互換性のためデフォルトは`v1`になっています: ```typescript copy // デフォルトのV1形式でメッセージを取得(AI SDKのCoreMessage形式とほぼ同等) const messagesV1 = await mastra.getStorage().getMessages({ threadId: 'your-thread-id' }); // V2形式でメッセージを取得(AI SDKのUIMessage形式とほぼ同等) const messagesV2 = await mastra.getStorage().getMessages({ threadId: 'your-thread-id', format: 'v2' }); ``` ## Storage Providers Mastraは以下のプロバイダーをサポートしています: - ローカル開発については、[LibSQL Storage](../../reference/storage/libsql.mdx)をご確認ください - 本番環境については、[PostgreSQL Storage](../../reference/storage/postgresql.mdx)をご確認ください - サーバーレスデプロイメントについては、[Upstash Storage](../../reference/storage/upstash.mdx)をご確認ください --- title: "高度なツール使用法 | ツール & MCP | Mastra ドキュメント" description: このページでは、中断シグナルやVercel AI SDKツール形式との互換性など、Mastraツールの高度な機能について説明します。 --- # 高度なツールの使用法 [JA] Source: https://mastra.ai/ja/docs/tools-mcp/advanced-usage このページでは、Mastraでのツール使用に関するより高度なテクニックと機能について説明します。 ## アボートシグナル `generate()` または `stream()` を使用してエージェントとのインタラクションを開始する際、`AbortSignal` を提供することができます。Mastraは、そのインタラクション中に発生するツール実行に対して、このシグナルを自動的に転送します。 これにより、親エージェントの呼び出しが中断された場合に、ツール内の長時間実行される操作(ネットワークリクエストや集中的な計算など)をキャンセルすることができます。 ツールの `execute` 関数の2番目のパラメータで `abortSignal` にアクセスできます。 ```typescript import { createTool } from "@mastra/core/tools"; import { z } from "zod"; export const longRunningTool = createTool({ id: "long-computation", description: "Performs a potentially long computation", inputSchema: z.object({ /* ... */ }), execute: async ({ context }, { abortSignal }) => { // Example: Forwarding signal to fetch const response = await fetch("https://api.example.com/data", { signal: abortSignal, // Pass the signal here }); if (abortSignal?.aborted) { console.log("Tool execution aborted."); throw new Error("Aborted"); } // Example: Checking signal during a loop for (let i = 0; i < 1000000; i++) { if (abortSignal?.aborted) { console.log("Tool execution aborted during loop."); throw new Error("Aborted"); } // ... perform computation step ... } const data = await response.json(); return { result: data }; },\n}); ``` これを使用するには、エージェントを呼び出す際に `AbortController` のシグナルを提供します: ```typescript import { Agent } from "@mastra/core/agent"; // Assume 'agent' is an Agent instance with longRunningTool configured const controller = new AbortController(); // Start the agent call const promise = agent.generate("Perform the long computation.", { abortSignal: controller.signal, }); // Sometime later, if needed: // controller.abort(); try { const result = await promise; console.log(result.text); } catch (error) { if (error.name === "AbortError") { console.log("Agent generation was aborted."); } else { console.error("An error occurred:", error); } } ``` ## AI SDK ツールフォーマット Mastraは、Vercel AI SDK(`ai`パッケージ)で使用されるツールフォーマットとの互換性を維持しています。`ai`パッケージの`tool`関数を使用してツールを定義し、Mastraの`createTool`で作成されたツールと一緒にMastraエージェント内で直接使用することができます。 まず、`ai`パッケージがインストールされていることを確認してください: ```bash npm2yarn copy npm install ai ``` 以下はVercel AI SDKフォーマットを使用して定義されたツールの例です: ```typescript filename="src/mastra/tools/vercelWeatherTool.ts" copy import { tool } from "ai"; import { z } from "zod"; export const vercelWeatherTool = tool({ description: "Fetches current weather using Vercel AI SDK format", parameters: z.object({ city: z.string().describe("The city to get weather for"), }), execute: async ({ city }) => { console.log(`Fetching weather for ${city} (Vercel format tool)`); // Replace with actual API call const data = await fetch(`https://api.example.com/weather?city=${city}`); return data.json(); }, }); ``` このツールを他のツールと同様にMastraエージェントに追加することができます: ```typescript filename="src/mastra/agents/mixedToolsAgent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { vercelWeatherTool } from "../tools/vercelWeatherTool"; // Vercel AI SDK tool import { mastraTool } from "../tools/mastraTool"; // Mastra createTool tool export const mixedToolsAgent = new Agent({ name: "Mixed Tools Agent", instructions: "You can use tools defined in different formats.", model: openai("gpt-4o-mini"), tools: { weatherVercel: vercelWeatherTool, someMastraTool: mastraTool, }, }); ``` Mastraは両方のツールフォーマットをサポートしており、必要に応じて組み合わせて使用することができます。 --- title: "動的ツールコンテキスト | ツール & MCP | Mastra ドキュメント" description: Mastraの RuntimeContextを使用して、動的なリクエスト固有の設定をツールに提供する方法を学びます。 --- import { Callout } from "nextra/components"; # 動的ツールコンテキスト [JA] Source: https://mastra.ai/ja/docs/tools-mcp/dynamic-context Mastraは依存性注入に基づいた`RuntimeContext`システムを提供しており、実行中にツールに動的なリクエスト固有の設定を渡すことができます。これは、ツールの中核コードを変更することなく、ユーザーIDやリクエストヘッダー、その他のランタイム要因に基づいてツールの動作を変更する必要がある場合に役立ちます。 **注意:** `RuntimeContext`は主にツール実行に*データを渡す*ために使用されます。 これは会話履歴や複数の呼び出しにわたる状態の永続性を処理するエージェントメモリとは 異なります。 ## 基本的な使用方法 `RuntimeContext`を使用するには、まず動的設定の型構造を定義します。次に、定義した型で`RuntimeContext`のインスタンスを作成し、希望する値を設定します。最後に、`agent.generate()`または`agent.stream()`を呼び出す際に、オプションオブジェクトに`runtimeContext`インスタンスを含めます。 ```typescript import { RuntimeContext } from "@mastra/core/di"; // Assume 'agent' is an already defined Mastra Agent instance // Define the context type type WeatherRuntimeContext = { "temperature-scale": "celsius" | "fahrenheit"; }; // Instantiate RuntimeContext and set values const runtimeContext = new RuntimeContext(); runtimeContext.set("temperature-scale", "celsius"); // Pass to agent call const response = await agent.generate("What's the weather like today?", { runtimeContext, // Pass the context here }); console.log(response.text); ``` ## ツール内でのコンテキストへのアクセス ツールは`execute`関数の第2引数の一部として`runtimeContext`を受け取ります。その後、`.get()`メソッドを使用して値を取得できます。 ```typescript filename="src/mastra/tools/weather-tool.ts" import { createTool } from "@mastra/core/tools"; import { z } from "zod"; // Assume WeatherRuntimeContext is defined as above and accessible here // Dummy fetch function async function fetchWeather( location: string, options: { temperatureUnit: "celsius" | "fahrenheit" }, ): Promise { console.log(`Fetching weather for ${location} in ${options.temperatureUnit}`); // Replace with actual API call return { temperature: options.temperatureUnit === "celsius" ? 20 : 68 }; } export const weatherTool = createTool({ id: "getWeather", description: "Get the current weather for a location", inputSchema: z.object({ location: z.string().describe("The location to get weather for"), }), // The tool's execute function receives runtimeContext execute: async ({ context, runtimeContext }) => { // Type-safe access to runtimeContext variables const temperatureUnit = runtimeContext.get("temperature-scale"); // Use the context value in the tool logic const weather = await fetchWeather(context.location, { temperatureUnit, }); return { result: `The temperature is ${weather.temperature}°${temperatureUnit === "celsius" ? "C" : "F"}`, }; }, }); ``` エージェントが`weatherTool`を使用する場合、`agent.generate()`呼び出し中に`runtimeContext`に設定された`temperature-scale`の値がツールの`execute`関数内で利用可能になります。 ## サーバーミドルウェアでの使用 サーバー環境(ExpressやNext.jsなど)では、ミドルウェアを使用して、ヘッダーやユーザーセッションなどの受信リクエストデータに基づいて自動的に`RuntimeContext`を設定することができます。 以下は、Mastraの組み込みサーバーミドルウェアサポート(内部的にHonoを使用)を使用して、Cloudflareの`CF-IPCountry`ヘッダーに基づいて温度スケールを設定する例です: ```typescript filename="src/mastra/index.ts" import { Mastra } from "@mastra/core"; import { RuntimeContext } from "@mastra/core/di"; import { weatherAgent } from "./agents/weather"; // Assume agent is defined elsewhere // Define RuntimeContext type type WeatherRuntimeContext = { "temperature-scale": "celsius" | "fahrenheit"; }; export const mastra = new Mastra({ agents: { weather: weatherAgent, }, server: { middleware: [ async (c, next) => { // Get the RuntimeContext instance const runtimeContext = c.get>("runtimeContext"); // Get country code from request header const country = c.req.header("CF-IPCountry"); // Set temperature scale based on country runtimeContext.set( "temperature-scale", country === "US" ? "fahrenheit" : "celsius", ); // Continue request processing await next(); }, ], }, }); ``` このミドルウェアを設置することで、このMastraサーバーインスタンスによって処理されるエージェント呼び出しは、ユーザーの推測された国に基づいて自動的に`RuntimeContext`に`temperature-scale`が設定され、`weatherTool`のようなツールはそれに応じて使用されます。 --- title: "MCP概要 | ツール&MCP | Mastraドキュメント" description: モデルコンテキストプロトコル(MCP)について学び、MCPClientを通じてサードパーティツールを使用する方法、レジストリへの接続方法、MCPServerを使用して自分のツールを共有する方法を理解しましょう。 --- import { Tabs } from "nextra/components"; # MCP 概要 [JA] Source: https://mastra.ai/ja/docs/tools-mcp/mcp-overview [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction)は、AIモデルが外部ツールやリソースを発見し、相互作用できるように設計されたオープンスタンダードです。これはAIエージェント向けの汎用プラグインシステムと考えることができ、エージェントがツールの記述言語やホスティング場所に関係なくツールを使用できるようにします。 Mastraは、エージェントを外部ツールサーバーに接続するためにMCPを使用しています。 ## MCP クライアントでサードパーティツールを使用する Mastraは、1つまたは複数のMCPサーバーへの接続を管理し、そのツールにアクセスするための`MCPClient`クラスを提供しています。 ### インストール まだインストールしていない場合は、Mastra MCPパッケージをインストールしてください: ```bash npm2yarn copy npm install @mastra/mcp@latest ``` ### MCPServerの登録 MCPサーバーをMastraに登録して、ログ記録や設定されたツールと統合へのアクセスを有効にします: ```ts showLineNumbers filename="src/mastra/index.ts" copy import { Mastra } from "@mastra/core"; import { myMcpServer } from "./mcpServers"; export const mastra = new Mastra({ mcpServers: { myMcpServer }, }); ``` ### `MCPClient`の設定 `MCPClient`は、接続したいサーバーのマップで設定します。サブプロセス(Stdio)またはHTTP(SSEフォールバック付きのストリーム可能なHTTP)を介した接続をサポートしています。 ```typescript import { MCPClient } from "@mastra/mcp"; const mcp = new MCPClient({ servers: { // Stdioの例 sequential: { command: "npx", args: ["-y", "@modelcontextprotocol/server-sequential-thinking"], }, // HTTPの例 weather: { url: new URL("http://localhost:8080/mcp"), requestInit: { headers: { Authorization: "Bearer your-token", }, }, }, }, }); ``` 詳細な設定オプションについては、[`MCPClient`リファレンスドキュメント](/reference/tools/mcp-client)を参照してください。 ### 静的vs動的ツール設定 `MCPClient`は、接続されたサーバーからツールを取得するための2つのアプローチを提供しており、異なるアプリケーションアーキテクチャに適しています: | 機能 | 静的設定 (`await mcp.getTools()`) | 動的設定 (`await mcp.getToolsets()`) | | :---------------- | :-------------------------------------------- | :------------------------------------------------- | | **ユースケース** | 単一ユーザー、静的設定(CLIツールなど) | マルチユーザー、動的設定(SaaSアプリなど) | | **設定** | エージェント初期化時に固定 | リクエストごとに動的 | | **認証情報** | すべての使用で共有 | ユーザー/リクエストごとに変更可能 | | **エージェント設定** | `Agent`コンストラクタでツールを追加 | `generate()`または`stream()`オプションでツールを渡す | - **静的設定(`getTools()`):** 設定されたすべてのサーバーからすべてのツールを取得します。ツール設定(APIキーなど)が静的で、すべてのユーザーまたはリクエスト間で共有される場合に最適です。通常、これを一度呼び出し、結果を`Agent`を定義する際の`tools`プロパティに渡します。 [リファレンス:`getTools()`](/reference/tools/mcp-client#gettools) ```typescript import { Agent } from "@mastra/core/agent"; // ... mcp clientの設定 const agent = new Agent({ // ... その他のエージェント設定 tools: await mcp.getTools(), }); ``` - **動的設定(`getToolsets()`):** リクエストごとまたはユーザーごとに設定が変更される可能性があるシナリオ(例:マルチユーザーアプリケーションで異なるテナントに対して異なるAPIキーを使用する場合)向けに設計されています。`getToolsets()`の結果をエージェントの`generate()`または`stream()`メソッドの`toolsets`オプションに渡します。 [リファレンス:`getToolsets()`](/reference/tools/mcp-client#gettoolsets) ```typescript import { Agent } from "@mastra/core/agent"; // ... 最初はツールなしでエージェントを設定 async function handleRequest(userPrompt: string, userApiKey: string) { const userMcp = new MCPClient({ /* userApiKeyを含む設定 */ }); const toolsets = await userMcp.getToolsets(); const response = await agent.stream(userPrompt, { toolsets, // 動的ツールセットを渡す }); // ... レスポンスを処理 await userMcp.disconnect(); } ``` ## MCPレジストリへの接続 MCPサーバーはレジストリを通じて発見することができます。`MCPClient`を使用していくつかの人気のあるレジストリに接続する方法を以下に示します: {/* LLM CONTEXT: This Tabs component shows how to connect to different MCP (Model Context Protocol) registries. Each tab demonstrates the configuration for a specific MCP registry service (mcp.run, Composio.dev, Smithery.ai). The tabs help users understand how to connect to various MCP server providers and their different authentication methods. Each tab shows the specific URL patterns and configuration needed for that registry service. */} [mcp.run](https://www.mcp.run/)は、事前認証済みの管理されたMCPサーバーを提供します。ツールはプロファイルにグループ化され、それぞれが一意の署名付きURLを持ちます。 ```typescript import { MCPClient } from "@mastra/mcp"; const mcp = new MCPClient({ servers: { marketing: { // Example profile name url: new URL(process.env.MCP_RUN_SSE_URL!), // Get URL from mcp.run profile }, }, }); ``` > **重要:** mcp.runのSSE URLはパスワードのように扱ってください。環境変数などに安全に保存してください。 > > ```bash filename=".env" > MCP_RUN_SSE_URL=https://www.mcp.run/api/mcp/sse?nonce=... > ``` [Composio.dev](https://composio.dev)は[SSEベースのMCPサーバー](https://mcp.composio.dev)のレジストリを提供しています。CursorなどのツールのためにSSE URLを直接使用できます。 ```typescript import { MCPClient } from "@mastra/mcp"; const mcp = new MCPClient({ servers: { googleSheets: { url: new URL("https://mcp.composio.dev/googlesheets/[private-url-path]"), }, gmail: { url: new URL("https://mcp.composio.dev/gmail/[private-url-path]"), }, }, }); ``` Google Sheetsなどのサービスとの認証は、多くの場合エージェントの会話を通じてインタラクティブに行われます。 *注意: ComposioのURLは通常単一のユーザーアカウントに紐付けられているため、マルチテナントアプリケーションよりも個人の自動化に適しています。* [Smithery.ai](https://smithery.ai)は、CLIを介してアクセス可能なレジストリを提供しています。 ```typescript // Unix/Mac import { MCPClient } from "@mastra/mcp"; const mcp = new MCPClient({ servers: { sequentialThinking: { command: "npx", args: [ "-y", "@smithery/cli@latest", "run", "@smithery-ai/server-sequential-thinking", "--config", "{}", ], }, }, }); ``` ```typescript // Windows import { MCPClient } from "@mastra/mcp"; const mcp = new MCPClient({ servers: { sequentialThinking: { command: "npx", args: [ "-y", "@smithery/cli@latest", "run", "@smithery-ai/server-sequential-thinking", "--config", "{}", ], }, }, }); ``` [Ampersand](https://withampersand.com?utm_source=mastra-docs)は、Salesforce、Hubspot、Zendeskなどの150以上のSaaS製品との統合を可能にする[MCP Server](https://docs.withampersand.com/mcp)を提供しており、エージェントをこれらのサービスに接続できます。 ```typescript // MCPClient with Ampersand MCP Server using SSE export const mcp = new MCPClient({ servers: { "@amp-labs/mcp-server": { "url": `https://mcp.withampersand.com/v1/sse?${new URLSearchParams({ apiKey: process.env.AMPERSAND_API_KEY, project: process.env.AMPERSAND_PROJECT_ID, integrationName: process.env.AMPERSAND_INTEGRATION_NAME, groupRef: process.env.AMPERSAND_GROUP_REF })}` } } }); ``` ```typescript // If you prefer to run the MCP server locally: import { MCPClient } from "@mastra/mcp"; // MCPClient with Ampersand MCP Server using stdio transport export const mcp = new MCPClient({ servers: { "@amp-labs/mcp-server": { command: "npx", args: [ "-y", "@amp-labs/mcp-server@latest", "--transport", "stdio", "--project", process.env.AMPERSAND_PROJECT_ID, "--integrationName", process.env.AMPERSAND_INTEGRATION_NAME, "--groupRef", process.env.AMPERSAND_GROUP_REF, // optional ], env: { AMPERSAND_API_KEY: process.env.AMPERSAND_API_KEY, }, }, }, }); ``` MCPの代替として、AmpersandのAI SDKにはMastra用のアダプターもあるため、エージェントがアクセスできるよう[Ampersandツールを直接インポート](https://docs.withampersand.com/ai-sdk#use-with-mastra)することも可能です。 ## MCPサーバーでツールを共有する 独自のMastraツールを作成した場合、MastraのMCPServerクラスを使用して、MCP互換のクライアントにそれらを公開できます。 同様に、MastraのAgentとWorkflowインスタンスもMCPServerを介してツールとして公開できます。これにより、他のMCPクライアントがエージェントに「質問」したり、ワークフローを実行したりして、あなたのエージェントと対話できるようになります。MCPServerの設定で提供される各エージェントは、エージェントの`description`プロパティを使用して、`ask_`という名前のツールに変換されます。各ワークフローは、そのinputSchemaと`description`を使用して、`run_`という名前のツールに変換されます。 これにより、他の人があなたのコードベースに直接アクセスすることなく、あなたのツール、エージェント、ワークフローを使用できるようになります。 ### MCPServerの使用 MCPServerは、名前、バージョン、および共有したいMastraツール、エージェント、ワークフローで初期化します。 ```typescript import { MCPServer } from "@mastra/mcp"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { weatherTool } from "./tools"; // あなたのMastraツール import { weatherAgent } from "./agents"; // あなたのMastra Agent import { dataWorkflow } from "./workflows"; // あなたのMastra Workflow const server = new MCPServer({ name: "My Custom Server", version: "1.0.0", tools: { weatherTool }, // ここにツールを提供 agents: { weatherAgent }, // ここにエージェントを提供 workflows: { dataWorkflow }, // ここにワークフローを提供 }); // サーバーを開始(例:CLIツール用のstdioを使用) // await server.startStdio(); // またはstartSSE()を使用してHTTPサーバーと統合 // 詳細はMCPServerリファレンスを参照 ``` エージェントがツールとして公開されるには、空でない`description`文字列が必要です。同様に、ワークフローが公開されるには、そのdescriptionも空でない文字列である必要があります。どちらかでdescriptionが欠けているか空の場合、MCPServerは初期化時にエラーをスローします。 ワークフローは、ツールの入力に`inputSchema`を使用します。 詳細な使用方法と例については、[MCPServerリファレンスドキュメント](/reference/tools/mcp-server)を参照してください。 --- title: "ツール概要 | ツール & MCP | Mastra ドキュメント" description: Mastraにおけるツールの概念、エージェントへの追加方法、効果的なツール設計のベストプラクティスを理解しましょう。 --- # ツール概要 [JA] Source: https://mastra.ai/ja/docs/tools-mcp/overview ツールは、エージェントが特定のタスクを実行したり外部情報にアクセスしたりするために実行できる関数です。これらは単純なテキスト生成を超えてエージェントの能力を拡張し、API、データベース、または他のシステムとの対話を可能にします。 各ツールは通常、以下を定義します: - **入力:** ツールの実行に必要な情報(多くの場合、Zodを使用した`inputSchema`で定義)。 - **出力:** ツールが返すデータの構造(`outputSchema`で定義)。 - **実行ロジック:** ツールのアクションを実行するコード。 - **説明:** エージェントがツールの機能と使用タイミングを理解するのに役立つテキスト。 ## ツールの作成 Mastraでは、`@mastra/core/tools`パッケージの[`createTool`](/reference/tools/create-tool)関数を使用してツールを作成します。 ```typescript filename="src/mastra/tools/weatherInfo.ts" copy import { createTool } from "@mastra/core/tools"; import { z } from "zod"; const getWeatherInfo = async (city: string) => { // Replace with an actual API call to a weather service console.log(`Fetching weather for ${city}...`); // Example data structure return { temperature: 20, conditions: "Sunny" }; }; export const weatherTool = createTool({ id: "Get Weather Information", description: `Fetches the current weather information for a given city`, inputSchema: z.object({ city: z.string().describe("City name"), }), outputSchema: z.object({ temperature: z.number(), conditions: z.string(), }), execute: async ({ context: { city } }) => { console.log("Using tool to fetch weather information for", city); return await getWeatherInfo(city); }, }); ``` この例では、都市の入力スキーマ、天気データの出力スキーマ、およびツールのロジックを含む`execute`関数を持つ`weatherTool`を定義しています。 ツールを作成する際は、ツールの説明をシンプルに保ち、ツールが**何を**するのか、**いつ**使用するのかに焦点を当て、その主な使用例を強調してください。技術的な詳細はパラメータスキーマに含め、エージェントがツールを正しく使用する_方法_について、わかりやすい名前、明確な説明、デフォルト値の説明などで案内します。 ## エージェントへのツールの追加 ツールをエージェントが利用できるようにするには、エージェントの定義でそれらを設定します。エージェントのシステムプロンプトで利用可能なツールとその一般的な目的に言及することも、ツールの使用を改善することができます。詳細な手順と例については、[エージェントでのツールとMCPの使用](/docs/agents/using-tools-and-mcp#add-tools-to-an-agent)のガイドを参照してください。 ## ツールスキーマの互換レイヤー 異なるモデルはスキーマを異なる方法で解釈します。特定のスキーマプロパティが渡されるとエラーになるモデルもあれば、特定のスキーマプロパティを無視してエラーを出さないモデルもあります。Mastra はツールスキーマのための互換レイヤーを追加し、ツールが異なるモデルプロバイダー間で一貫して動作し、スキーマの制約が守られるようにします。 このレイヤーを適用している主なプロバイダーは以下の通りです: - **Google Gemini & Anthropic:** サポートされていないスキーマプロパティを削除し、関連する制約をツールの説明に追加します。 - **OpenAI(推論モデルを含む):** 無視される、またはサポートされていないスキーマフィールドを削除または調整し、エージェントのガイダンスのために説明に指示を追加します。 - **DeepSeek & Meta:** スキーマの整合性とツールの使いやすさを確保するため、同様の互換ロジックを適用します。 このアプローチにより、カスタムツールと MCP ツールの両方で、ツールの利用がより信頼性が高く、モデル非依存になります。 --- title: Mastraの音声機能 | Mastra ドキュメント description: Mastraの音声機能の概要。テキスト読み上げ、音声認識、リアルタイム音声変換などを含みます。 --- import { Tabs } from "nextra/components"; import { AudioPlayback } from "@/components/audio-playback"; # Mastraの音声機能 [JA] Source: https://mastra.ai/ja/docs/voice/overview Mastraの音声システムは、音声インタラクションのための統一されたインターフェースを提供し、アプリケーションでテキスト読み上げ(TTS)、音声認識(STT)、リアルタイム音声変換(STS)機能を実現します。 ## エージェントにボイス機能を追加する エージェントにボイス機能を統合する方法については、[エージェントにボイス機能を追加する](../agents/adding-voice.mdx)のドキュメントをご確認ください。このセクションでは、単一および複数のボイスプロバイダーの使用方法、およびリアルタイムインタラクションについて説明しています。 ```typescript import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { OpenAIVoice } from "@mastra/voice-openai"; // Initialize OpenAI voice for TTS const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new OpenAIVoice(), }); ``` 以下のボイス機能を使用できます: ### テキスト読み上げ(TTS) MastraのTTS機能を使用して、エージェントの応答を自然な音声に変換します。 OpenAI、ElevenLabsなど、複数のプロバイダーから選択できます。 詳細な設定オプションと高度な機能については、[テキスト読み上げガイド](./text-to-speech)をご確認ください。 {/* LLM CONTEXT: This Tabs component demonstrates Text-to-Speech (TTS) implementation across different voice providers. Each tab shows how to set up and use a specific TTS provider (OpenAI, Azure, ElevenLabs, etc.) with Mastra agents. The tabs help users compare different TTS providers and choose the one that best fits their needs. Each tab includes complete code examples showing agent setup, text generation, and audio playback. The providers include OpenAI, Azure, ElevenLabs, PlayAI, Google, Cloudflare, Deepgram, Speechify, Sarvam, and Murf. */} ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { OpenAIVoice } from "@mastra/voice-openai"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new OpenAIVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "default", // Optional: specify a speaker responseFormat: "wav", // Optional: specify a response format }); playAudio(audioStream); ``` 詳細については、[OpenAI Voice Reference](/reference/voice/openai) をご覧ください。 ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { AzureVoice } from "@mastra/voice-azure"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new AzureVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "en-US-JennyNeural", // Optional: specify a speaker }); playAudio(audioStream); ``` 詳細については、[Azure Voice Reference](/reference/voice/azure) をご覧ください。 ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { ElevenLabsVoice } from "@mastra/voice-elevenlabs"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new ElevenLabsVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "default", // Optional: specify a speaker }); playAudio(audioStream); ``` 詳細については、[ElevenLabs Voice Reference](/reference/voice/elevenlabs) をご覧ください。 ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { PlayAIVoice } from "@mastra/voice-playai"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new PlayAIVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "default", // Optional: specify a speaker }); playAudio(audioStream); ``` 詳細については、[PlayAI Voice Reference](/reference/voice/playai) をご覧ください。 ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { GoogleVoice } from "@mastra/voice-google"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new GoogleVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "en-US-Studio-O", // Optional: specify a speaker }); playAudio(audioStream); ``` Google音声プロバイダーの詳細については、[Google Voice Reference](/reference/voice/google)をご覧ください。 ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { CloudflareVoice } from "@mastra/voice-cloudflare"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new CloudflareVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "default", // Optional: specify a speaker }); playAudio(audioStream); ``` Cloudflare音声プロバイダーの詳細については、[Cloudflare Voice Reference](/reference/voice/cloudflare)をご覧ください。 ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { DeepgramVoice } from "@mastra/voice-deepgram"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new DeepgramVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "aura-english-us", // Optional: specify a speaker }); playAudio(audioStream); ``` Deepgram音声プロバイダーの詳細については、[Deepgram Voice Reference](/reference/voice/deepgram)をご覧ください。 ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { SpeechifyVoice } from "@mastra/voice-speechify"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new SpeechifyVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "matthew", // Optional: specify a speaker }); playAudio(audioStream); ``` Speechify音声プロバイダーの詳細については、[Speechify Voice Reference](/reference/voice/speechify)をご覧ください。 ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { SarvamVoice } from "@mastra/voice-sarvam"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new SarvamVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "default", // Optional: specify a speaker }); playAudio(audioStream); ``` Sarvam音声プロバイダーの詳細については、[Sarvam Voice Reference](/reference/voice/sarvam)をご覧ください。 ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { MurfVoice } from "@mastra/voice-murf"; import { playAudio } from "@mastra/node-audio"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new MurfVoice(), }); const { text } = await voiceAgent.generate('What color is the sky?'); // Convert text to speech to an Audio Stream const audioStream = await voiceAgent.voice.speak(text, { speaker: "default", // Optional: specify a speaker }); playAudio(audioStream); ``` Murf音声プロバイダーの詳細については、[Murf Voice Reference](/reference/voice/murf)をご覧ください。 ### 音声認識(STT) OpenAI や ElevenLabs など、さまざまなプロバイダーを使って話された内容を文字起こしできます。詳細な設定オプションなどについては、[音声認識](./speech-to-text)をご覧ください。 サンプル音声ファイルは[こちら](https://github.com/mastra-ai/realtime-voice-demo/raw/refs/heads/main/how_can_i_help_you.mp3)からダウンロードできます。
{/* LLM CONTEXT: この Tabs コンポーネントは、さまざまな音声プロバイダーでの音声認識(STT)の実装例を示しています。 各タブでは、特定の STT プロバイダーを設定し、音声をテキストに変換する方法を紹介しています。 これらのタブは、異なるプロバイダーで音声認識を実装する方法を理解するのに役立ちます。 各タブには、音声ファイルの取り扱い、文字起こし、応答生成のコード例が含まれています。 */} ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { OpenAIVoice } from "@mastra/voice-openai"; import { createReadStream } from 'fs'; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new OpenAIVoice(), }); // Use an audio file from a URL const audioStream = await createReadStream("./how_can_i_help_you.mp3"); // Convert audio to text const transcript = await voiceAgent.voice.listen(audioStream); console.log(`User said: ${transcript}`); // Generate a response based on the transcript const { text } = await voiceAgent.generate(transcript); ``` 詳細については、[OpenAI Voice Reference](/reference/voice/openai) をご覧ください。 ```typescript import { createReadStream } from 'fs'; import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { AzureVoice } from "@mastra/voice-azure"; import { createReadStream } from 'fs'; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new AzureVoice(), }); // Use an audio file from a URL const audioStream = await createReadStream("./how_can_i_help_you.mp3"); // Convert audio to text const transcript = await voiceAgent.voice.listen(audioStream); console.log(`User said: ${transcript}`); // Generate a response based on the transcript const { text } = await voiceAgent.generate(transcript); ``` 詳細については、[Azure Voice Reference](/reference/voice/azure) をご覧ください。 ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { ElevenLabsVoice } from "@mastra/voice-elevenlabs"; import { createReadStream } from 'fs'; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new ElevenLabsVoice(), }); // Use an audio file from a URL const audioStream = await createReadStream("./how_can_i_help_you.mp3"); // Convert audio to text const transcript = await voiceAgent.voice.listen(audioStream); console.log(`User said: ${transcript}`); // Generate a response based on the transcript const { text } = await voiceAgent.generate(transcript); ``` 詳細については、[ElevenLabs Voice Reference](/reference/voice/elevenlabs) をご覧ください。 ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { GoogleVoice } from "@mastra/voice-google"; import { createReadStream } from 'fs'; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new GoogleVoice(), }); // Use an audio file from a URL const audioStream = await createReadStream("./how_can_i_help_you.mp3"); // Convert audio to text const transcript = await voiceAgent.voice.listen(audioStream); console.log(`User said: ${transcript}`); // Generate a response based on the transcript const { text } = await voiceAgent.generate(transcript); ``` 詳細については、[Google Voice Reference](/reference/voice/google) をご覧ください。 ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { CloudflareVoice } from "@mastra/voice-cloudflare"; import { createReadStream } from 'fs'; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new CloudflareVoice(), }); // Use an audio file from a URL const audioStream = await createReadStream("./how_can_i_help_you.mp3"); // Convert audio to text const transcript = await voiceAgent.voice.listen(audioStream); console.log(`User said: ${transcript}`); // Generate a response based on the transcript const { text } = await voiceAgent.generate(transcript); ``` Cloudflareの音声プロバイダーについて詳しくは、[Cloudflare Voice Reference](/reference/voice/cloudflare)をご覧ください。 ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { DeepgramVoice } from "@mastra/voice-deepgram"; import { createReadStream } from 'fs'; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new DeepgramVoice(), }); // Use an audio file from a URL const audioStream = await createReadStream("./how_can_i_help_you.mp3"); // Convert audio to text const transcript = await voiceAgent.voice.listen(audioStream); console.log(`User said: ${transcript}`); // Generate a response based on the transcript const { text } = await voiceAgent.generate(transcript); ``` Deepgramの音声プロバイダーについて詳しくは、[Deepgram Voice Reference](/reference/voice/deepgram)をご覧ください。 ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { SarvamVoice } from "@mastra/voice-sarvam"; import { createReadStream } from 'fs'; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new SarvamVoice(), }); // Use an audio file from a URL const audioStream = await createReadStream("./how_can_i_help_you.mp3"); // Convert audio to text const transcript = await voiceAgent.voice.listen(audioStream); console.log(`User said: ${transcript}`); // Generate a response based on the transcript const { text } = await voiceAgent.generate(transcript); ``` Sarvamの音声プロバイダーについて詳しくは、[Sarvam Voice Reference](/reference/voice/sarvam)をご覧ください。 ### Speech to Speech (STS) 音声対音声機能を使用して会話体験を作成します。統合APIにより、ユーザーとAIエージェント間のリアルタイム音声インタラクションが可能になります。 詳細な設定オプションと高度な機能については、[Speech to Speech](./speech-to-speech)をご確認ください。 {/* LLM CONTEXT: This Tabs component demonstrates Speech-to-Speech (STS) implementation for real-time voice interactions. Currently only shows OpenAI's realtime voice implementation for bidirectional voice conversations. The tab shows how to set up real-time voice communication with event handling for audio responses. This enables conversational AI experiences with continuous audio streaming. */} ```typescript import { Agent } from '@mastra/core/agent'; import { openai } from '@ai-sdk/openai'; import { playAudio, getMicrophoneStream } from '@mastra/node-audio'; import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; const voiceAgent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice: new OpenAIRealtimeVoice(), }); // Listen for agent audio responses voiceAgent.voice.on('speaker', ({ audio }) => { playAudio(audio); }); // Initiate the conversation await voiceAgent.voice.speak('How can I help you today?'); // Send continuous audio from the microphone const micStream = getMicrophoneStream(); await voiceAgent.voice.send(micStream); ```` OpenAI音声プロバイダーの詳細については、[OpenAI Voice Reference](/reference/voice/openai-realtime)をご覧ください。 ## Voice設定 各音声プロバイダーは、異なるモデルとオプションで設定できます。以下は、サポートされているすべてのプロバイダーの詳細な設定オプションです: {/* LLM CONTEXT: This Tabs component shows detailed configuration options for all supported voice providers. Each tab demonstrates how to configure a specific voice provider with all available options and settings. The tabs help users understand the full configuration capabilities of each provider including models, languages, and advanced settings. Each tab shows both speech and listening model configurations where applicable. */} ```typescript // OpenAI Voice Configuration const voice = new OpenAIVoice({ speechModel: { name: "gpt-3.5-turbo", // Example model name apiKey: process.env.OPENAI_API_KEY, language: "en-US", // Language code voiceType: "neural", // Type of voice model }, listeningModel: { name: "whisper-1", // Example model name apiKey: process.env.OPENAI_API_KEY, language: "en-US", // Language code format: "wav", // Audio format }, speaker: "alloy", // Example speaker name }); ``` OpenAI音声プロバイダーの詳細については、[OpenAI Voice Reference](/reference/voice/openai)をご覧ください。 ```typescript // Azure Voice Configuration const voice = new AzureVoice({ speechModel: { name: "en-US-JennyNeural", // Example model name apiKey: process.env.AZURE_SPEECH_KEY, region: process.env.AZURE_SPEECH_REGION, language: "en-US", // Language code style: "cheerful", // Voice style pitch: "+0Hz", // Pitch adjustment rate: "1.0", // Speech rate }, listeningModel: { name: "en-US", // Example model name apiKey: process.env.AZURE_SPEECH_KEY, region: process.env.AZURE_SPEECH_REGION, format: "simple", // Output format }, }); ``` Azure音声プロバイダーの詳細については、[Azure Voice Reference](/reference/voice/azure)をご覧ください。 ```typescript // ElevenLabs Voice Configuration const voice = new ElevenLabsVoice({ speechModel: { voiceId: "your-voice-id", // Example voice ID model: "eleven_multilingual_v2", // Example model name apiKey: process.env.ELEVENLABS_API_KEY, language: "en", // Language code emotion: "neutral", // Emotion setting }, // ElevenLabs may not have a separate listening model }); ``` ElevenLabs音声プロバイダーの詳細については、[ElevenLabs Voice Reference](/reference/voice/elevenlabs)をご覧ください。 ```typescript // PlayAI Voice Configuration const voice = new PlayAIVoice({ speechModel: { name: "playai-voice", // Example model name speaker: "emma", // Example speaker name apiKey: process.env.PLAYAI_API_KEY, language: "en-US", // Language code speed: 1.0, // Speech speed }, // PlayAI may not have a separate listening model }); ``` PlayAI音声プロバイダーの詳細については、[PlayAI Voice Reference](/reference/voice/playai)をご覧ください。 ```typescript // Google Voice Configuration const voice = new GoogleVoice({ speechModel: { name: "en-US-Studio-O", // Example model name apiKey: process.env.GOOGLE_API_KEY, languageCode: "en-US", // Language code gender: "FEMALE", // Voice gender speakingRate: 1.0, // Speaking rate }, listeningModel: { name: "en-US", // Example model name sampleRateHertz: 16000, // Sample rate }, }); ``` PlayAI音声プロバイダーの詳細については、[PlayAI Voice Reference](/reference/voice/playai)をご覧ください。 ```typescript // Cloudflare Voice Configuration const voice = new CloudflareVoice({ speechModel: { name: "cloudflare-voice", // Example model name accountId: process.env.CLOUDFLARE_ACCOUNT_ID, apiToken: process.env.CLOUDFLARE_API_TOKEN, language: "en-US", // Language code format: "mp3", // Audio format }, // Cloudflare may not have a separate listening model }); ``` Cloudflare音声プロバイダーの詳細については、[Cloudflare Voice Reference](/reference/voice/cloudflare)をご覧ください。 ```typescript // Deepgram Voice Configuration const voice = new DeepgramVoice({ speechModel: { name: "nova-2", // Example model name speaker: "aura-english-us", // Example speaker name apiKey: process.env.DEEPGRAM_API_KEY, language: "en-US", // Language code tone: "formal", // Tone setting }, listeningModel: { name: "nova-2", // Example model name format: "flac", // Audio format }, }); ``` Deepgram音声プロバイダーの詳細については、[Deepgram Voice Reference](/reference/voice/deepgram)をご覧ください。 ```typescript // Speechify Voice Configuration const voice = new SpeechifyVoice({ speechModel: { name: "speechify-voice", // Example model name speaker: "matthew", // Example speaker name apiKey: process.env.SPEECHIFY_API_KEY, language: "en-US", // Language code speed: 1.0, // Speech speed }, // Speechify may not have a separate listening model }); ``` Speechify音声プロバイダーの詳細については、[Speechify Voice Reference](/reference/voice/speechify)をご覧ください。 ```typescript // Sarvam Voice Configuration const voice = new SarvamVoice({ speechModel: { name: "sarvam-voice", // Example model name apiKey: process.env.SARVAM_API_KEY, language: "en-IN", // Language code style: "conversational", // Style setting }, // Sarvam may not have a separate listening model }); ``` Sarvam音声プロバイダーの詳細については、[Sarvam Voice Reference](/reference/voice/sarvam)をご覧ください。 ```typescript // Murf Voice Configuration const voice = new MurfVoice({ speechModel: { name: "murf-voice", // Example model name apiKey: process.env.MURF_API_KEY, language: "en-US", // Language code emotion: "happy", // Emotion setting }, // Murf may not have a separate listening model }); ``` Murf音声プロバイダーの詳細については、[Murf Voice Reference](/reference/voice/murf)をご覧ください。 ```typescript // OpenAI Realtime Voice Configuration const voice = new OpenAIRealtimeVoice({ speechModel: { name: "gpt-3.5-turbo", // Example model name apiKey: process.env.OPENAI_API_KEY, language: "en-US", // Language code }, listeningModel: { name: "whisper-1", // Example model name apiKey: process.env.OPENAI_API_KEY, format: "ogg", // Audio format }, speaker: "alloy", // Example speaker name }); ``` OpenAI Realtime音声プロバイダーの詳細については、[OpenAI Realtime Voice Reference](/reference/voice/openai-realtime)をご参照ください。 ### 複数の音声プロバイダーの使用 この例では、Mastraで2つの異なる音声プロバイダーを作成して使用する方法を示します:音声認識(STT)用のOpenAIと音声合成(TTS)用のPlayAIです。 必要な設定を含む音声プロバイダーのインスタンスを作成することから始めます。 ```typescript import { OpenAIVoice } from "@mastra/voice-openai"; import { PlayAIVoice } from "@mastra/voice-playai"; import { CompositeVoice } from "@mastra/core/voice"; import { playAudio, getMicrophoneStream } from "@mastra/node-audio"; // STT用のOpenAI音声を初期化 const input = new OpenAIVoice({ listeningModel: { name: "whisper-1", apiKey: process.env.OPENAI_API_KEY, }, }); // TTS用のPlayAI音声を初期化 const output = new PlayAIVoice({ speechModel: { name: "playai-voice", apiKey: process.env.PLAYAI_API_KEY, }, }); // CompositeVoiceを使用してプロバイダーを結合 const voice = new CompositeVoice({ input, output, }); // 結合された音声プロバイダーを使用して音声インタラクションを実装 const audioStream = getMicrophoneStream(); // この関数が音声入力を取得すると仮定 const transcript = await voice.listen(audioStream); // 転写されたテキストをログ出力 console.log("Transcribed text:", transcript); // テキストを音声に変換 const responseAudio = await voice.speak(`You said: ${transcript}`, { speaker: "default", // オプション:話者を指定, responseFormat: "wav", // オプション:レスポンス形式を指定 }); // 音声レスポンスを再生 playAudio(responseAudio); ``` CompositeVoiceの詳細については、[CompositeVoiceリファレンス](/reference/voice/composite-voice)を参照してください。 ## その他のリソース - [CompositeVoice](../../reference/voice/composite-voice.mdx) - [MastraVoice](../../reference/voice/mastra-voice.mdx) - [OpenAI Voice](../../reference/voice/openai.mdx) - [Azure Voice](../../reference/voice/azure.mdx) - [Google Voice](../../reference/voice/google.mdx) - [Deepgram Voice](../../reference/voice/deepgram.mdx) - [PlayAI Voice](../../reference/voice/playai.mdx) - [音声の例](../../examples/voice/text-to-speech.mdx) --- title: Mastraにおける音声対音声機能 | Mastra ドキュメント description: Mastraの音声対音声機能の概要。リアルタイムの対話やイベント駆動型アーキテクチャについて説明します。 --- # Mastraの音声対音声機能 [JA] Source: https://mastra.ai/ja/docs/voice/speech-to-speech ## はじめに MastraのSpeech-to-Speech(STS)は、複数のプロバイダー間でリアルタイムなやり取りを可能にする標準化されたインターフェースを提供します。 STSは、Realtimeモデルからのイベントをリッスンすることで、継続的な双方向音声通信を実現します。個別のTTSやSTT操作とは異なり、STSは両方向の音声を継続的に処理するオープンな接続を維持します。 ## 設定 - **`apiKey`**: あなたのOpenAI APIキー。`OPENAI_API_KEY`環境変数にフォールバックします。 - **`model`**: リアルタイム音声対話に使用するモデルID(例:`gpt-4o-mini-realtime`)。 - **`speaker`**: 音声合成のデフォルトボイスID。音声出力に使用する声を指定できます。 ```typescript const voice = new OpenAIRealtimeVoice({ apiKey: "your-openai-api-key", model: "gpt-4o-mini-realtime", speaker: "alloy", // Default voice }); // If using default settings the configuration can be simplified to: const voice = new OpenAIRealtimeVoice(); ``` ## STSの使用 ```typescript import { Agent } from "@mastra/core/agent"; import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import { playAudio, getMicrophoneStream } from "@mastra/node-audio"; const agent = new Agent({ name: "Agent", instructions: `You are a helpful assistant with real-time voice capabilities.`, model: openai("gpt-4o"), voice: new OpenAIRealtimeVoice(), }); // Connect to the voice service await agent.voice.connect(); // Listen for agent audio responses agent.voice.on("speaker", ({ audio }) => { playAudio(audio); }); // Initiate the conversation await agent.voice.speak("How can I help you today?"); // Send continuous audio from the microphone const micStream = getMicrophoneStream(); await agent.voice.send(micStream); ``` 音声対音声機能をエージェントに統合するには、[エージェントに音声を追加する](../agents/adding-voice.mdx)のドキュメントを参照してください。 --- title: Mastra における音声認識(STT) | Mastra ドキュメント description: Mastra の音声認識機能の概要、設定方法、使用方法、音声プロバイダーとの連携について説明します。 --- # 音声認識(STT) [JA] Source: https://mastra.ai/ja/docs/voice/speech-to-text Mastraの音声認識(STT)は、複数のサービスプロバイダー間で音声入力をテキストに変換するための標準化されたインターフェースを提供します。 STTは、人間の音声に応答できる音声対応アプリケーションの作成を支援し、ハンズフリーでの操作、障害を持つユーザーのためのアクセシビリティ、そしてより自然な人間とコンピューターのインターフェースを可能にします。 ## 設定 MastraでSTTを使用するには、ボイスプロバイダーを初期化する際に`listeningModel`を指定する必要があります。これには以下のようなパラメータが含まれます: - **`name`**: 使用する特定のSTTモデル。 - **`apiKey`**: 認証用のAPIキー。 - **プロバイダー固有のオプション**: 特定のボイスプロバイダーで必要またはサポートされている追加オプション。 **注意**: これらのパラメータはすべて省略可能です。使用しているボイスプロバイダーによって異なりますが、プロバイダーが提供するデフォルト設定を利用することもできます。 ```typescript const voice = new OpenAIVoice({ listeningModel: { name: "whisper-1", apiKey: process.env.OPENAI_API_KEY, }, }); // If using default settings the configuration can be simplified to: const voice = new OpenAIVoice(); ``` ## 利用可能なプロバイダー Mastra は複数の Speech-to-Text プロバイダーをサポートしており、それぞれ独自の機能と強みがあります。 - [**OpenAI**](/reference/voice/openai/) - Whisper モデルによる高精度な文字起こし - [**Azure**](/reference/voice/azure/) - Microsoft のエンタープライズレベルの信頼性を持つ音声認識 - [**ElevenLabs**](/reference/voice/elevenlabs/) - 複数言語対応の高度な音声認識 - [**Google**](/reference/voice/google/) - 幅広い言語サポートを持つ Google の音声認識 - [**Cloudflare**](/reference/voice/cloudflare/) - 低遅延アプリケーション向けのエッジ最適化音声認識 - [**Deepgram**](/reference/voice/deepgram/) - 様々なアクセントに対応した高精度の AI 音声認識 - [**Sarvam**](/reference/voice/sarvam/) - インド系言語とアクセントに特化 各プロバイダーは、必要に応じてインストールできる個別のパッケージとして実装されています。 ```bash pnpm add @mastra/voice-openai # Example for OpenAI ``` ## Listen メソッドの使用方法 STT の主なメソッドは `listen()` メソッドであり、話された音声をテキストに変換します。使い方は以下の通りです。 ```typescript import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { OpenAIVoice } from "@mastra/voice-openai"; import { getMicrophoneStream } from "@mastra/node-audio"; const voice = new OpenAIVoice(); const agent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that provides recommendations based on user input.", model: openai("gpt-4o"), voice, }); const audioStream = getMicrophoneStream(); // Assume this function gets audio input const transcript = await agent.voice.listen(audioStream, { filetype: "m4a", // Optional: specify the audio file type }); console.log(`User said: ${transcript}`); const { text } = await agent.generate( `Based on what the user said, provide them a recommendation: ${transcript}`, ); console.log(`Recommendation: ${text}`); ``` STT をエージェントで使用する方法については、[エージェントに音声を追加する](../agents/adding-voice.mdx) ドキュメントもご覧ください。 --- title: Mastra におけるテキスト読み上げ(TTS) | Mastra ドキュメント description: Mastra のテキスト読み上げ機能の概要、設定方法、使用方法、音声プロバイダーとの連携について説明します。 --- # Text-to-Speech (TTS) [JA] Source: https://mastra.ai/ja/docs/voice/text-to-speech MastraのText-to-Speech (TTS)は、さまざまなプロバイダーを利用してテキストから音声を合成するための統一APIを提供します。 TTSをアプリケーションに組み込むことで、自然な音声によるインタラクションでユーザー体験を向上させたり、視覚障害のあるユーザーのアクセシビリティを改善したり、より魅力的なマルチモーダルインターフェースを作成したりできます。 TTSは、あらゆる音声アプリケーションの中核となるコンポーネントです。STT(Speech-to-Text)と組み合わせることで、音声インタラクションシステムの基盤を形成します。新しいモデルではSTS([Speech-to-Speech](./speech-to-speech))もサポートされており、リアルタイムのインタラクションに利用できますが、コストが高い($)という特徴があります。 ## 設定 MastraでTTSを使用するには、ボイスプロバイダーを初期化する際に`speechModel`を指定する必要があります。これには以下のようなパラメータが含まれます: - **`name`**: 使用する特定のTTSモデル。 - **`apiKey`**: 認証用のAPIキー。 - **プロバイダー固有のオプション**: 特定のボイスプロバイダーで必要またはサポートされている追加オプション。 **`speaker`**オプションを使用すると、音声合成のために異なる声を選択できます。各プロバイダーは、**音声の多様性**、**品質**、**声の個性**、**多言語対応**など、さまざまな特徴を持つボイスオプションを提供しています。 **注意**: これらのパラメータはすべて任意です。使用しているボイスプロバイダーによって異なりますが、プロバイダーが提供するデフォルト設定を利用することもできます。 ```typescript const voice = new OpenAIVoice({ speechModel: { name: "tts-1-hd", apiKey: process.env.OPENAI_API_KEY, }, speaker: "alloy", }); // If using default settings the configuration can be simplified to: const voice = new OpenAIVoice(); ``` ## 利用可能なプロバイダー Mastra は幅広い Text-to-Speech プロバイダーに対応しており、それぞれ独自の機能や音声オプションを提供しています。アプリケーションのニーズに最適なプロバイダーを選択できます。 - [**OpenAI**](/reference/voice/openai/) - 自然なイントネーションと表現力を持つ高品質な音声 - [**Azure**](/reference/voice/azure/) - Microsoft の音声サービスで、多様な音声と言語に対応 - [**ElevenLabs**](/reference/voice/elevenlabs/) - 感情表現や細かなコントロールが可能な超リアルな音声 - [**PlayAI**](/reference/voice/playai/) - 様々なスタイルの自然な音声に特化 - [**Google**](/reference/voice/google/) - Google の多言語対応音声合成 - [**Cloudflare**](/reference/voice/cloudflare/) - 低遅延アプリケーション向けのエッジ最適化音声合成 - [**Deepgram**](/reference/voice/deepgram/) - 高精度な AI 音声技術 - [**Speechify**](/reference/voice/speechify/) - 読みやすさとアクセシビリティに最適化された Text-to-Speech - [**Sarvam**](/reference/voice/sarvam/) - インド系言語やアクセントに特化 - [**Murf**](/reference/voice/murf/) - パラメータをカスタマイズ可能なスタジオ品質のナレーション 各プロバイダーは、必要に応じてインストールできる個別のパッケージとして実装されています。 ```bash pnpm add @mastra/voice-openai # Example for OpenAI ``` ## speak メソッドの使用 TTS の主なメソッドは `speak()` メソッドであり、テキストを音声に変換します。このメソッドは、話者やその他のプロバイダー固有のオプションを指定できるオプションを受け取ることができます。使い方は以下の通りです: ```typescript import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { OpenAIVoice } from "@mastra/voice-openai"; const voice = new OpenAIVoice(); const agent = new Agent({ name: "Voice Agent", instructions: "You are a voice assistant that can help users with their tasks.", model: openai("gpt-4o"), voice, }); const { text } = await agent.generate("What color is the sky?"); // Convert text to speech to an Audio Stream const readableStream = await voice.speak(text, { speaker: "default", // Optional: specify a speaker properties: { speed: 1.0, // Optional: adjust speech speed pitch: "default", // Optional: specify pitch if supported }, }); ``` TTS をエージェントで使用する方法については、[Adding Voice to Agents](../agents/adding-voice.mdx) のドキュメントもご覧ください。 --- title: "分岐、マージ、条件分岐 | ワークフロー | Mastra ドキュメント" description: "Mastra のワークフローにおける制御フローを使うことで、分岐、マージ、条件分岐を管理し、ロジック要件に合ったワークフローを構築できます。" --- # Control Flow [JA] Source: https://mastra.ai/ja/docs/workflows/control-flow ワークフローを構築する際、通常は操作をより小さなタスクに分解し、それらをリンクして再利用できるようにします。**Steps**は、入力、出力、実行ロジックを定義することで、これらのタスクを管理するための構造化された方法を提供します。 - スキーマが一致する場合、各ステップの`outputSchema`は自動的に次のステップの`inputSchema`に渡されます。 - スキーマが一致しない場合は、[Input data mapping](./input-data-mapping.mdx)を使用して`outputSchema`を期待される`inputSchema`に変換します。 ## Sequential `.then()`を使用してステップを順次実行するように連鎖させます: ```typescript {8-9} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const step1 = createStep({...}); const step2 = createStep({...}); export const testWorkflow = createWorkflow({...}) .then(step1) .then(step2) .commit(); ``` ## 並列 `.parallel()` を使ってステップを並列に実行します: ```typescript {8} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const step1 = createStep({...}); const step2 = createStep({...}); export const testWorkflow = createWorkflow({...}) .parallel([step1, step2]) .commit(); ``` この方法では、配列内のすべてのステップが同時に実行され、すべての並列ステップが完了した後に次のステップへ進みます。 > 詳細は [ステップによる並列実行](/examples/workflows/parallel-steps) をご覧ください。 ## 分岐 `.branch()` を使って条件分岐を作成します: ```typescript {8-11} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const lessThanStep = createStep({...}); const greaterThanStep = createStep({...}); export const testWorkflow = createWorkflow({...}) .branch([ [async ({ inputData: { some_value } }) => some_value <= 9, lessThanStep], [async ({ inputData: { some_value } }) => some_value >= 10, greaterThanStep] ]) .commit(); ``` 分岐条件は順番に評価されますが、条件に一致したステップは並列で実行されます。 > 詳細は [Workflow with Conditional Branching](/examples/workflows/conditional-branching) をご覧ください。 ## ループ ワークフローは2種類のループをサポートしています。ステップ、またはネストされたワークフローのようなステップ互換の構造をループする場合、初期の`inputData`は前のステップの出力から取得されます。 互換性を確保するため、ループの初期入力は以下のいずれかである必要があります: - 前のステップの出力の形状と一致する、または - `map`関数を使用して明示的に変換される。 ### Dowhile 条件が真である間、ステップを繰り返し実行します。 ```typescript {7} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const counterStep = createStep({...}); export const testWorkflow = createWorkflow({...}) .dowhile(counterStep, async ({ inputData: { number } }) => number < 10) .commit(); ``` ### Dountil 条件が真になるまで、ステップを繰り返し実行します。 ```typescript {7} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const counterStep = createStep({...}); export const testWorkflow = createWorkflow({...}) .dountil(counterStep, async ({ inputData: { number } }) => number > 10) .commit(); ``` ### Foreach `inputSchema`の各アイテムに対して、同じステップを順次実行します。 ```typescript {7} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const mapStep = createStep({...}); export const testWorkflow = createWorkflow({...}) .foreach(mapStep) .commit(); ``` #### 実行インスタンスの例 以下の例は、複数の入力でランを開始する方法を示しています。各入力は`mapStep`を順次通過します。 ```typescript {6} filename="src/test-workflow.ts" showLineNumbers copy import { mastra } from "./mastra"; const run = mastra.getWorkflow("testWorkflow").createRun(); const result = await run.start({ inputData: [{ number: 10 }, { number: 100 }, { number: 200 }] }); ``` ターミナルからこの実行を行うには: ```bash copy npx tsx src/test-workflow.ts ``` #### 並行性 オプションで、`concurrency`を使用すると、同時実行数に制限を設けてステップを並列実行できます。 ```typescript {7} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const mapStep = createStep({...}) export const testWorkflow = createWorkflow({...}) .foreach(mapStep, { concurrency: 2 }) .commit(); ``` ## 並列ワークフロー ワークフロー自体も並列で実行することができます。 ```typescript {4-5,8} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const workflow1 = createWorkflow({...}); const workflow2 = createWorkflow({...}); export const testWorkflow = createWorkflow({...}) .parallel([workflow1, workflow2]) .commit(); ``` 並列ステップは前のステップの結果を入力として受け取ります。それらの出力は、ステップの`id`をキーとし、ステップの`output`を値とするオブジェクトとして次のステップの入力に渡されます。 ## ネストされたワークフロー 以下の例では、`nestedWorkflow`が`testWorkflow`内のステップとして使用されています。`testWorkflow`は`step1`を使用し、一方で`nestedWorkflow`は`step2`と`step3`を構成しています。 ```typescript {4,7} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; export const nestedWorkflow = createWorkflow({...}) export const testWorkflow = createWorkflow({...}) .then(nestedWorkflow) .commit(); ``` `.branch()`や`.parallel()`を使用してより複雑な制御フローを構築する場合、複数のステップを実行するには、それらのステップをネストされたワークフローでラップし、どのように実行すべきかを明確に定義する必要があります。 ## クローンされたワークフロー 以下の例では、`clonedWorkflow`は`workflow1`のクローンであり、`testWorkflow`内のステップとして使用されています。`clonedWorkflow`は`step1`の後に順次実行されます。 ```typescript {5,9} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep, cloneWorkflow } from "@mastra/core/workflows"; import { z } from "zod"; const step1 = createStep({...}); const clonedWorkflow = cloneWorkflow(step1, { id: "cloned-workflow" }); export const testWorkflow = createWorkflow({...}) .then(step1) .then(clonedWorkflow) .commit(); ``` --- title: "ダイナミックワークフロー | Mastra ドキュメント" description: "ワークフローステップ内でダイナミックなワークフローを作成し、実行時の条件に基づいて柔軟にワークフローを構築する方法を学びます。" --- # ダイナミックワークフロー [JA] Source: https://mastra.ai/ja/docs/workflows/dynamic-workflows このガイドでは、ワークフローステップ内でダイナミックなワークフローを作成する方法を説明します。この高度なパターンを使用すると、実行時の条件に基づいてワークフローを動的に作成および実行できます。 ## 概要 動的ワークフローは、実行時データに基づいてワークフローを作成する必要がある場合に役立ちます。 ## 実装 動的ワークフローを作成するための鍵は、ステップの `execute` 関数内から Mastra インスタンスにアクセスし、それを使って新しいワークフローを作成・実行することです。 ### 基本例 ```typescript import { Mastra, Step, Workflow } from "@mastra/core"; import { z } from "zod"; const isMastra = (mastra: any): mastra is Mastra => { return mastra && typeof mastra === "object" && mastra instanceof Mastra; }; // Step that creates and runs a dynamic workflow const createDynamicWorkflow = new Step({ id: "createDynamicWorkflow", outputSchema: z.object({ dynamicWorkflowResult: z.any(), }), execute: async ({ context, mastra }) => { if (!mastra) { throw new Error("Mastra instance not available"); } if (!isMastra(mastra)) { throw new Error("Invalid Mastra instance"); } const inputData = context.triggerData.inputData; // Create a new dynamic workflow const dynamicWorkflow = new Workflow({ name: "dynamic-workflow", mastra, // Pass the mastra instance to the new workflow triggerSchema: z.object({ dynamicInput: z.string(), }), }); // Define steps for the dynamic workflow const dynamicStep = new Step({ id: "dynamicStep", execute: async ({ context }) => { const dynamicInput = context.triggerData.dynamicInput; return { processedValue: `Processed: ${dynamicInput}`, }; }, }); // Build and commit the dynamic workflow dynamicWorkflow.step(dynamicStep).commit(); // Create a run and execute the dynamic workflow const run = dynamicWorkflow.createRun(); const result = await run.start({ triggerData: { dynamicInput: inputData, }, }); let dynamicWorkflowResult; if (result.results["dynamicStep"]?.status === "success") { dynamicWorkflowResult = result.results["dynamicStep"]?.output.processedValue; } else { throw new Error("Dynamic workflow failed"); } // Return the result from the dynamic workflow return { dynamicWorkflowResult, }; }, }); // Main workflow that uses the dynamic workflow creator const mainWorkflow = new Workflow({ name: "main-workflow", triggerSchema: z.object({ inputData: z.string(), }), mastra: new Mastra(), }); mainWorkflow.step(createDynamicWorkflow).commit(); // Register the workflow with Mastra export const mastra = new Mastra({ workflows: { mainWorkflow }, }); const run = mainWorkflow.createRun(); const result = await run.start({ triggerData: { inputData: "test", }, }); ``` ## 上級例:ワークフローファクトリー 入力パラメータに基づいて異なるワークフローを生成するワークフローファクトリーを作成できます。 ```typescript const isMastra = (mastra: any): mastra is Mastra => { return mastra && typeof mastra === "object" && mastra instanceof Mastra; }; const workflowFactory = new Step({ id: "workflowFactory", inputSchema: z.object({ workflowType: z.enum(["simple", "complex"]), inputData: z.string(), }), outputSchema: z.object({ result: z.any(), }), execute: async ({ context, mastra }) => { if (!mastra) { throw new Error("Mastra instance not available"); } if (!isMastra(mastra)) { throw new Error("Invalid Mastra instance"); } // Create a new dynamic workflow based on the type const dynamicWorkflow = new Workflow({ name: `dynamic-${context.workflowType}-workflow`, mastra, triggerSchema: z.object({ input: z.string(), }), }); if (context.workflowType === "simple") { // Simple workflow with a single step const simpleStep = new Step({ id: "simpleStep", execute: async ({ context }) => { return { result: `Simple processing: ${context.triggerData.input}`, }; }, }); dynamicWorkflow.step(simpleStep).commit(); } else { // Complex workflow with multiple steps const step1 = new Step({ id: "step1", outputSchema: z.object({ intermediateResult: z.string(), }), execute: async ({ context }) => { return { intermediateResult: `First processing: ${context.triggerData.input}`, }; }, }); const step2 = new Step({ id: "step2", execute: async ({ context }) => { const intermediate = context.getStepResult(step1).intermediateResult; return { finalResult: `Second processing: ${intermediate}`, }; }, }); dynamicWorkflow.step(step1).then(step2).commit(); } // Execute the dynamic workflow const run = dynamicWorkflow.createRun(); const result = await run.start({ triggerData: { input: context.inputData, }, }); // Return the appropriate result based on workflow type if (context.workflowType === "simple") { return { // @ts-ignore result: result.results["simpleStep"]?.output, }; } else { return { // @ts-ignore result: result.results["step2"]?.output, }; } }, }); ``` ## 重要な考慮事項 1. **Mastraインスタンス**: `execute`関数の`mastra`パラメータは、動的ワークフローを作成するために不可欠なMastraインスタンスへのアクセスを提供します。 2. **エラー処理**: 動的ワークフローを作成する前に、常にMastraインスタンスが利用可能かどうかを確認してください。 3. **リソース管理**: 動的ワークフローはリソースを消費するため、単一の実行で多くのワークフローを作成することには注意が必要です。 4. **ワークフローのライフサイクル**: 動的ワークフローは自動的にメインのMastraインスタンスに登録されません。明示的に登録しない限り、ステップ実行の期間中のみ存在します。 5. **デバッグ**: 動的ワークフローのデバッグは難しい場合があります。作成と実行を追跡するための詳細なログ記録を追加することを検討してください。 ## ユースケース - **条件付きワークフロー選択**: 入力データに基づいて異なるワークフローパターンを選択する - **パラメータ化されたワークフロー**: 動的な設定でワークフローを作成する - **ワークフローテンプレート**: テンプレートを使って特化したワークフローを生成する - **マルチテナントアプリケーション**: 異なるテナントごとに分離されたワークフローを作成する ## 結論 動的ワークフローは、柔軟で適応性の高いワークフローシステムを構築するための強力な方法です。ステップ実行内でMastraインスタンスを活用することで、実行時の状況や要件に応じて反応するワークフローを作成できます。 --- title: "ワークフローにおけるエラー処理 | Mastra ドキュメント" description: "Mastra のワークフローでステップのリトライ、条件分岐、モニタリングを使ったエラー処理方法を学びます。" --- # ワークフローにおけるエラー処理 [JA] Source: https://mastra.ai/ja/docs/workflows/error-handling 堅牢なエラー処理は、本番環境のワークフローに不可欠です。Mastra は、エラーを適切に処理するためのさまざまな仕組みを提供しており、ワークフローが障害から回復したり、必要に応じて優雅に機能を縮小したりすることができます。 ## 概要 Mastraワークフローでのエラー処理は以下の方法で実装できます: 1. **ステップの再試行** - 失敗したステップを自動的に再試行 2. **条件分岐** - ステップの成功または失敗に基づいて代替パスを作成 3. **エラーモニタリング** - ワークフローのエラーを監視し、プログラムで処理 4. **結果ステータスチェック** - 後続のステップで前のステップのステータスを確認 ## ステップのリトライ Mastra には、一時的なエラーによって失敗したステップのための組み込みリトライ機構が用意されています。これは、外部サービスや一時的に利用できなくなるリソースと連携するステップに特に有用です。 ### 基本的なリトライ設定 リトライはワークフローレベルまたは個々のステップごとに設定できます。 ```typescript // Workflow-level retry configuration const workflow = new Workflow({ name: "my-workflow", retryConfig: { attempts: 3, // Number of retry attempts delay: 1000, // Delay between retries in milliseconds }, }); // Step-level retry configuration (overrides workflow-level) const apiStep = new Step({ id: "callApi", execute: async () => { // API call that might fail }, retryConfig: { attempts: 5, // This step will retry up to 5 times delay: 2000, // With a 2-second delay between retries }, }); ``` ステップのリトライについての詳細は、[Step Retries](../../reference/workflows/step-retries.mdx) リファレンスをご覧ください。 ## 条件分岐 前のステップの成功または失敗に基づいて、条件ロジックを使用して代替ワークフローパスを作成できます: ```typescript // Create a workflow with conditional branching const workflow = new Workflow({ name: "error-handling-workflow", }); workflow .step(fetchDataStep) .then(processDataStep, { // Only execute processDataStep if fetchDataStep was successful when: ({ context }) => { return context.steps.fetchDataStep?.status === "success"; }, }) .then(fallbackStep, { // Execute fallbackStep if fetchDataStep failed when: ({ context }) => { return context.steps.fetchDataStep?.status === "failed"; }, }) .commit(); ``` ## エラーモニタリング `watch` メソッドを使用してワークフローのエラーを監視できます。 ```typescript const { start, watch } = workflow.createRun(); watch(async ({ results }) => { // Check for any failed steps const failedSteps = Object.entries(results) .filter(([_, step]) => step.status === "failed") .map(([stepId]) => stepId); if (failedSteps.length > 0) { console.error(`Workflow has failed steps: ${failedSteps.join(", ")}`); // Take remedial action, such as alerting or logging } }); await start(); ``` ## ステップでのエラー処理 ステップの実行関数内で、エラーをプログラム的に処理することができます。 ```typescript const robustStep = new Step({ id: "robustStep", execute: async ({ context }) => { try { // Attempt the primary operation const result = await someRiskyOperation(); return { success: true, data: result }; } catch (error) { // Log the error console.error("Operation failed:", error); // Return a graceful fallback result instead of throwing return { success: false, error: error.message, fallbackData: "Default value", }; } }, }); ``` ## 前のステップの結果を確認する 前のステップの結果に基づいて判断を行うことができます。 ```typescript const finalStep = new Step({ id: "finalStep", execute: async ({ context }) => { // Check results of previous steps const step1Success = context.steps.step1?.status === "success"; const step2Success = context.steps.step2?.status === "success"; if (step1Success && step2Success) { // All steps succeeded return { status: "complete", result: "All operations succeeded" }; } else if (step1Success) { // Only step1 succeeded return { status: "partial", result: "Partial completion" }; } else { // Critical failure return { status: "failed", result: "Critical steps failed" }; } }, }); ``` ## エラー処理のベストプラクティス 1. **一時的な障害にはリトライを使用する**: 一時的な問題が発生する可能性のあるステップには、リトライポリシーを設定しましょう。 2. **フォールバックパスを用意する**: 重要なステップが失敗した場合に備えて、代替経路をワークフローに設計しましょう。 3. **エラーシナリオを具体的にする**: エラーの種類ごとに異なる処理戦略を使い分けましょう。 4. **エラーを包括的に記録する**: デバッグを容易にするため、エラーの記録時にはコンテキスト情報も含めましょう。 5. **失敗時には意味のあるデータを返す**: ステップが失敗した場合、後続のステップが判断できるよう、失敗に関する構造化データを返しましょう。 6. **冪等性を考慮する**: ステップが安全に再実行でき、重複した副作用が発生しないようにしましょう。 7. **ワークフローの実行を監視する**: `watch` メソッドを使ってワークフローの実行を積極的に監視し、早期にエラーを検出しましょう。 ## 高度なエラー処理 より複雑なエラー処理が必要な場合は、次の点を検討してください。 - **サーキットブレーカーの実装**: ステップが繰り返し失敗した場合、再試行を停止し、フォールバック戦略を使用する - **タイムアウト処理の追加**: ステップごとに時間制限を設け、ワークフローが無限に停止しないようにする - **専用のエラー回復ワークフローの作成**: 重要なワークフローの場合、メインのワークフローが失敗した際にトリガーされる専用の回復ワークフローを作成する ## 関連 - [ステップリトライのリファレンス](../../reference/workflows/step-retries.mdx) - [Watchメソッドのリファレンス](../../reference/workflows/watch.mdx) - [ステップ条件](../../reference/workflows/step-condition.mdx) - [制御フロー](./control-flow.mdx) --- title: "Inngest Workflows | Workflows | Mastra Docs" description: "Inngest workflowを使用してMastra workflowをInngestで実行できます" --- # Inngest ワークフロー [JA] Source: https://mastra.ai/ja/docs/workflows/inngest-workflow [Inngest](https://www.inngest.com/docs)は、インフラストラクチャを管理することなく、バックグラウンドワークフローを構築・実行するための開発者プラットフォームです。 ## Mastraにおけるinngestの仕組み InngestとMastraは、ワークフローモデルを整合させることで統合されています:Inngestはロジックをステップで構成される関数に整理し、`createWorkflow`と`createStep`を使用して定義されるMastraのワークフローはこのパラダイムに直接マッピングされます。各Mastraワークフローは一意の識別子を持つInngest関数となり、ワークフロー内の各ステップはInngestのステップにマッピングされます。 `serve`関数は、MastraワークフローをInngest関数として登録し、実行とモニタリングに必要なイベントハンドラーを設定することで、両システムを橋渡しします。 イベントがワークフローをトリガーすると、Inngestはステップごとに実行し、各ステップの結果をメモ化します。これにより、ワークフローが再試行または再開された場合、完了したステップはスキップされ、効率的で信頼性の高い実行が保証されます。Mastraのループ、条件分岐、ネストされたワークフローなどの制御フロープリミティブは、Inngestの関数/ステップモデルにシームレスに変換され、コンポジション、分岐、一時停止などの高度なワークフロー機能が保持されます。 リアルタイムモニタリング、一時停止/再開、ステップレベルの可観測性は、Inngestのパブリッシュ-サブスクライブシステムとダッシュボードを通じて実現されます。各ステップが実行されると、その状態と出力はMastraストレージを使用して追跡され、必要に応じて再開することができます。 ## セットアップ ```sh npm install @mastra/inngest @mastra/core @mastra/deployer ``` ## Inngest Workflowの構築 このガイドでは、InngestとMastraを使用してワークフローを作成する方法を説明し、値を10に達するまでインクリメントするカウンターアプリケーションのデモンストレーションを行います。 ### Inngestの初期化 Inngest統合を初期化して、Mastra互換のワークフローヘルパーを取得します。createWorkflowとcreateStep関数は、MastraとInngestに互換性のあるワークフローとステップオブジェクトを作成するために使用されます。 開発環境では ```ts showLineNumbers copy filename="src/mastra/inngest/index.ts" import { Inngest } from "inngest"; import { realtimeMiddleware } from "@inngest/realtime"; export const inngest = new Inngest({ id: "mastra", baseUrl:"http://localhost:8288", isDev: true, middleware: [realtimeMiddleware()], }); ``` 本番環境では ```ts showLineNumbers copy filename="src/mastra/inngest/index.ts" import { Inngest } from "inngest"; import { realtimeMiddleware } from "@inngest/realtime"; export const inngest = new Inngest({ id: "mastra", middleware: [realtimeMiddleware()], }); ``` ### ステップの作成 ワークフローを構成する個々のステップを定義します: ```ts showLineNumbers copy filename="src/mastra/workflows/index.ts" import { z } from "zod"; import { inngest } from "../inngest"; import { init } from "@mastra/inngest"; // ローカルのInngestサーバーを指すように、MastraでInngestを初期化 const { createWorkflow, createStep } = init(inngest); // ステップ: カウンター値をインクリメント const incrementStep = createStep({ id: "increment", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), execute: async ({ inputData }) => { return { value: inputData.value + 1 }; }, }); ``` ### ワークフローの作成 `dountil`ループパターンを使用してステップをワークフローに構成します。createWorkflow関数は、Inngestサーバー上で呼び出し可能な関数を作成します。 ```ts showLineNumbers copy filename="src/mastra/workflows/index.ts" // Inngestサーバー上で関数として登録されるワークフロー const workflow = createWorkflow({ id: "increment-workflow", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), }).then(incrementStep); workflow.commit(); export { workflow as incrementWorkflow }; ``` ### Mastraインスタンスの設定とワークフローの実行 ワークフローをMastraに登録し、Inngest APIエンドポイントを設定します: ```ts showLineNumbers copy filename="src/mastra/index.ts" import { Mastra } from "@mastra/core/mastra"; import { serve as inngestServe } from "@mastra/inngest"; import { incrementWorkflow } from "./workflows"; import { inngest } from "./inngest"; import { PinoLogger } from "@mastra/loggers"; // ワークフローとInngest APIエンドポイントでMastraを設定 export const mastra = new Mastra({ workflows: { incrementWorkflow, }, server: { // ローカルDockerコンテナがMastraサーバーに接続できるようにするためのサーバー設定が必要 host: "0.0.0.0", apiRoutes: [ // このAPIルートは、InngestサーバーにMastraワークフロー(Inngest関数)を登録するために使用される { path: "/api/inngest", method: "ALL", createHandler: async ({ mastra }) => inngestServe({ mastra, inngest }), // inngestServe関数は以下によってMastraワークフローをInngestと統合します: // 1. 一意のID(workflow.${workflowId})を持つ各ワークフローのInngest関数を作成 // 2. 以下を行うイベントハンドラーを設定: // - 各ワークフロー実行に対して一意の実行IDを生成 // - ステップ実行を管理するInngestExecutionEngineを作成 // - ワークフロー状態の永続化とリアルタイム更新を処理 // 3. workflow:${workflowId}:${runId}チャンネルを通じて // リアルタイム監視のためのパブリッシュ・サブスクライブシステムを確立 }, ], }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); ``` ### ワークフローのローカル実行 > **前提条件:** > > - Dockerがインストールされ、実行されている > - Mastraプロジェクトがセットアップされている > - 依存関係がインストールされている(`npm install`) 1. `npx mastra dev`を実行して、ポート4111でサーバーを提供するためにローカルでMastraサーバーを起動します。 2. Inngest Dev Server(Docker経由)を開始 新しいターミナルで以下を実行: ```sh docker run --rm -p 8288:8288 \ inngest/inngest \ inngest dev -u http://host.docker.internal:4111/inngest/api ``` > **注意:** `-u` の後のURLは、Inngest dev serverにMastraの `/api/inngest` エンドポイントの場所を伝えます。 3. Inngest Dashboardを開く - ブラウザで [http://localhost:8288](http://localhost:8288) にアクセスします。 - サイドバーの **Apps** セクションに移動します。 - Mastraワークフローが登録されているのが確認できるはずです。 ![Inngest Dashboard](/inngest-apps-dashboard.png) 4. ワークフローを実行する - サイドバーの **Functions** セクションに移動します。 - Mastraワークフローを選択します。 - **Invoke** をクリックして、以下の入力を使用します: ```json { "data": { "inputData": { "value": 5 } } } ``` ![Inngest Function](/inngest-function-dashboard.png) 5. **ワークフローの実行を監視する** - サイドバーの **Runs** タブに移動します。 - 最新の実行をクリックして、ステップバイステップの実行進捗を確認します。 ![Inngest Function Run](/inngest-runs-dashboard.png) ### 本番環境でのワークフロー実行 > **前提条件:** > > - Vercelアカウントとインストール済みのVercel CLI (`npm i -g vercel`) > - Inngestアカウント > - Vercelトークン(推奨:環境変数として設定) 1. MastraインスタンスにVercel Deployerを追加 ```ts showLineNumbers copy filename="src/mastra/index.ts" import { VercelDeployer } from "@mastra/deployer-vercel"; export const mastra = new Mastra({ // ...その他の設定 deployer: new VercelDeployer({ teamSlug: "your_team_slug", projectName: "your_project_name", // vercelトークンは、右上のユーザーアイコンをクリックし、 // 「Account Settings」をクリックして、左サイドバーの「Tokens」をクリックすることで // vercelダッシュボードから取得できます。 token: "your_vercel_token", }), }); ``` > **注意:** Vercelトークンを環境に設定してください: > > ```sh > export VERCEL_TOKEN=your_vercel_token > ``` 2. mastraインスタンスをビルド ```sh npx mastra build ``` 3. Vercelにデプロイ ```sh cd .mastra/output vercel --prod ``` > **ヒント:** まだの場合は、`vercel login` でVercel CLIにログインしてください。 4. Inngest Dashboardと同期 - [Inngest dashboard](https://app.inngest.com/env/production/apps) に移動します。 - **Sync new app with Vercel** をクリックして、指示に従います。 - Mastraワークフローがアプリとして登録されているのが確認できるはずです。 ![Inngest Dashboard](/inngest-apps-dashboard-prod.png) 5. ワークフローを実行 - **Functions** セクションで、`workflow.increment-workflow` を選択します。 - **All actions**(右上)> **Invoke** をクリックします。 - 以下の入力を提供します: ```json { "data": { "inputData": { "value": 5 } } } ``` ![Inngest Function Run](/inngest-function-dashboard-prod.png) 6. 実行を監視 - **Runs** タブに移動します。 - 最新の実行をクリックして、ステップバイステップの実行進捗を確認します。 ![Inngest Function Run](/inngest-runs-dashboard-prod.png) --- title: "ワークフローを使った入力データマッピング | Mastra ドキュメント" description: "Mastraワークフローでより動的なデータフローを作成するためのワークフロー入力マッピングの使用方法を学びましょう。" --- # 入力データマッピング [JA] Source: https://mastra.ai/ja/docs/workflows/input-data-mapping 入力データマッピングにより、次のステップの入力に対する値の明示的なマッピングが可能になります。これらの値は以下の複数のソースから取得できます: - 前のステップの出力 - ランタイムコンテキスト - 定数値 - ワークフローの初期入力 ## Map この例では、`step1`からの`output`が`step2`に必要な`inputSchema`に合うように変換されます。`step1`からの値は、`.map`関数の`inputData`パラメータを使用してアクセスできます。 ```typescript {18} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy const step1 = createStep({...}); const step2 = createStep({...}); export const testWorkflow = createWorkflow({ id: "test-workflow", description: 'Test workflow', inputSchema: z.object({ input: z.number() }), outputSchema: z.object({ output: z.string() }) }) .then(step1) .map(({ inputData }) => { const { value } = inputData; return { output: `${value}` }; }) .then(step2) .commit(); ``` ### inputData `inputData`を使用して前のステップの完全な出力にアクセスします: ```typescript {2} showLineNumbers .map(({ inputData }) => { const { value} = inputData; ... }) ``` ### getStepResult `getStepResult`を使用して、ステップのインスタンスを参照することで特定のステップの完全な出力にアクセスします: ```typescript {3} showLineNumbers .then(step1) .map(({ getStepResult }) => { console.log(getStepResult(step1)); ... }) ``` ### getInitData `getInitData`を使用してワークフローに提供された初期入力データにアクセスします: ```typescript {3} showLineNumbers .then(step1) .map(({ getInitData }) => { console.log(getInitData()); ... }) ``` ## 出力の名前変更 ### ステップ出力 `.map()`でオブジェクト構文を使用してステップ出力の名前を変更できます。以下の例では、`step1`の`value`出力が`details`に名前変更されています: ```typescript {3} showLineNumbers .then(step) .map({ details: { step: step, path: "value" } }) ``` ### ワークフロー出力 **参照合成**を使用してワークフロー出力の名前を変更できます。これは、ワークフローインスタンスを`initData`として渡すことを含みます。 ```typescript {12, 16} showLineNumbers export const testWorkflow = createWorkflow({ id: "test-workflow", description: 'Test workflow', inputSchema: z.object({ input: z.string() }), outputSchema: z.object({ output: z.string() }) }); testWorkflow .then(cityCoordinatesStep) .map({ details: { initData: testWorkflow, path: "value" } }) ``` # ネストされたワークフロー [JA] Source: https://mastra.ai/ja/docs/workflows/nested-workflows Mastraでは、ワークフローを他のワークフロー内のステップとして使用することができ、モジュール式で再利用可能なワークフローコンポーネントを作成できます。この機能により、複雑なワークフローをより小さく管理しやすい部分に整理し、コードの再利用を促進することができます。 また、親ワークフロー内のステップとしてネストされたワークフローを視覚的に確認できるため、ワークフローの流れを理解しやすくなります。 ## 基本的な使用方法 `step()`メソッドを使用して、あるワークフローを別のワークフローのステップとして直接使用できます: ```typescript // ネストされたワークフローを作成 const nestedWorkflow = new Workflow({ name: "nested-workflow" }) .step(stepA) .then(stepB) .commit(); // 親ワークフローでネストされたワークフローを使用 const parentWorkflow = new Workflow({ name: "parent-workflow" }) .step(nestedWorkflow, { variables: { city: { step: "trigger", path: "myTriggerInput", }, }, }) .then(stepC) .commit(); ``` ワークフローがステップとして使用される場合: - ワークフローの名前をステップIDとして使用し、自動的にステップに変換されます - ワークフローの結果は親ワークフローのコンテキストで利用可能になります - ネストされたワークフローのステップは定義された順序で実行されます ## 結果へのアクセス ネストされたワークフローからの結果は、親ワークフローのコンテキスト内でネストされたワークフローの名前の下で利用できます。結果には、ネストされたワークフローからのすべてのステップ出力が含まれます: ```typescript const { results } = await parentWorkflow.start(); // Access nested workflow results const nestedWorkflowResult = results["nested-workflow"]; if (nestedWorkflowResult.status === "success") { const nestedResults = nestedWorkflowResult.output.results; } ``` ## ネストされたワークフローによるフロー制御 ネストされたワークフローは、通常のステップで利用可能なすべてのフロー制御機能をサポートしています: ### 並列実行 複数のネストされたワークフローを並列で実行できます: ```typescript parentWorkflow .step(nestedWorkflowA) .step(nestedWorkflowB) .after([nestedWorkflowA, nestedWorkflowB]) .step(finalStep); ``` または、ワークフローの配列を使用した`step()`を使用する方法: ```typescript parentWorkflow.step([nestedWorkflowA, nestedWorkflowB]).then(finalStep); ``` この場合、`then()`は最終ステップを実行する前に、すべてのワークフローが完了するのを暗黙的に待ちます。 ### If-Else分岐 ネストされたワークフローは、両方の分岐を引数として受け入れる新しい構文でif-else分岐で使用できます: ```typescript // 異なるパス用のネストされたワークフローを作成 const workflowA = new Workflow({ name: "workflow-a" }) .step(stepA1) .then(stepA2) .commit(); const workflowB = new Workflow({ name: "workflow-b" }) .step(stepB1) .then(stepB2) .commit(); // ネストされたワークフローで新しいif-else構文を使用 parentWorkflow .step(initialStep) .if( async ({ context }) => { // ここに条件を記述 return someCondition; }, workflowA, // if分岐 workflowB, // else分岐 ) .then(finalStep) .commit(); ``` 新しい構文は、ネストされたワークフローを扱う際により簡潔で明確です。条件が: - `true`の場合:最初のワークフロー(if分岐)が実行されます - `false`の場合:2番目のワークフロー(else分岐)が実行されます スキップされたワークフローは結果で`skipped`ステータスになります: if-elseブロックの後に続く`.then(finalStep)`呼び出しは、ifとelse分岐を単一の実行パスに戻します。 ### ループ処理 ネストされたワークフローは、他のステップと同様に`.until()`と`.while()`ループを使用できます。興味深い新しいパターンの一つは、ワークフローを直接ループバック引数として渡し、その結果に関する何かが真になるまでそのネストされたワークフローを実行し続けることです: ```typescript parentWorkflow .step(firstStep) .while( ({ context }) => context.getStepResult("nested-workflow").output.results.someField === "someValue", nestedWorkflow, ) .step(finalStep) .commit(); ``` ## ネストされたワークフローの監視 親ワークフローの`watch`メソッドを使用して、ネストされたワークフローの状態変化を監視することができます。これは複雑なワークフローの進行状況や状態遷移をモニタリングするのに役立ちます: ```typescript const parentWorkflow = new Workflow({ name: "parent-workflow" }) .step([nestedWorkflowA, nestedWorkflowB]) .then(finalStep) .commit(); const run = parentWorkflow.createRun(); const unwatch = parentWorkflow.watch((state) => { console.log("Current state:", state.value); // Access nested workflow states in state.context }); await run.start(); unwatch(); // Stop watching when done ``` ## 一時停止と再開 ネストされたワークフローは一時停止と再開をサポートしており、特定のポイントでワークフロー実行を一時停止して続行することができます。ネストされたワークフロー全体または特定のステップを一時停止することができます: ```typescript // Define a step that may need to suspend const suspendableStep = new Step({ id: "other", description: "Step that may need to suspend", execute: async ({ context, suspend }) => { if (!wasSuspended) { wasSuspended = true; await suspend(); } return { other: 26 }; }, }); // Create a nested workflow with suspendable steps const nestedWorkflow = new Workflow({ name: "nested-workflow-a" }) .step(startStep) .then(suspendableStep) .then(finalStep) .commit(); // Use in parent workflow const parentWorkflow = new Workflow({ name: "parent-workflow" }) .step(beginStep) .then(nestedWorkflow) .then(lastStep) .commit(); // Start the workflow const run = parentWorkflow.createRun(); const { runId, results } = await run.start({ triggerData: { startValue: 1 } }); // Check if a specific step in the nested workflow is suspended if (results["nested-workflow-a"].output.results.other.status === "suspended") { // Resume the specific suspended step using dot notation const resumedResults = await run.resume({ stepId: "nested-workflow-a.other", context: { startValue: 1 }, }); // The resumed results will contain the completed nested workflow expect(resumedResults.results["nested-workflow-a"].output.results).toEqual({ start: { output: { newValue: 1 }, status: "success" }, other: { output: { other: 26 }, status: "success" }, final: { output: { finalValue: 27 }, status: "success" }, }); } ``` ネストされたワークフローを再開する場合: - `resume()`を呼び出す際に、ワークフロー全体を再開するには、ネストされたワークフローの名前を`stepId`として使用します - ネストされたワークフロー内の特定のステップを再開するには、ドット表記(`nested-workflow.step-name`)を使用します - ネストされたワークフローは、提供されたコンテキストで一時停止されたステップから続行されます - ネストされたワークフローの結果内の特定のステップのステータスを`results["nested-workflow"].output.results`を使用して確認できます ## 結果スキーマとマッピング ネストされたワークフローは、結果スキーマとマッピングを定義することができ、これによって型の安全性とデータ変換が容易になります。これは、ネストされたワークフローの出力が特定の構造と一致することを確認したい場合や、結果を親ワークフローで使用する前に変換する必要がある場合に特に役立ちます。 ```typescript // Create a nested workflow with result schema and mapping const nestedWorkflow = new Workflow({ name: "nested-workflow", result: { schema: z.object({ total: z.number(), items: z.array( z.object({ id: z.string(), value: z.number(), }), ), }), mapping: { // Map values from step results using variables syntax total: { step: "step-a", path: "count" }, items: { step: "step-b", path: "items" }, }, }, }) .step(stepA) .then(stepB) .commit(); // Use in parent workflow with type-safe results const parentWorkflow = new Workflow({ name: "parent-workflow" }) .step(nestedWorkflow) .then(async ({ context }) => { const result = context.getStepResult("nested-workflow"); // TypeScript knows the structure of result console.log(result.total); // number console.log(result.items); // Array<{ id: string, value: number }> return { success: true }; }) .commit(); ``` ## ベストプラクティス 1. **モジュール性**: ネストされたワークフローを使用して関連するステップをカプセル化し、再利用可能なワークフローコンポーネントを作成します。 2. **命名**: ネストされたワークフローには、親ワークフローのステップIDとして使用されるため、説明的な名前を付けてください。 3. **エラー処理**: ネストされたワークフローは親ワークフローにエラーを伝播するため、適切にエラーを処理してください。 4. **状態管理**: 各ネストされたワークフローは独自の状態を維持しますが、親ワークフローのコンテキストにアクセスできます。 5. **サスペンション**: ネストされたワークフローでサスペンションを使用する場合は、ワークフロー全体の状態を考慮し、適切に再開処理を行ってください。 ## 例 ネストされたワークフローのさまざまな機能を示す完全な例を以下に示します: ```typescript const workflowA = new Workflow({ name: "workflow-a", result: { schema: z.object({ activities: z.string(), }), mapping: { activities: { step: planActivities, path: "activities", }, }, }, }) .step(fetchWeather) .then(planActivities) .commit(); const workflowB = new Workflow({ name: "workflow-b", result: { schema: z.object({ activities: z.string(), }), mapping: { activities: { step: planActivities, path: "activities", }, }, }, }) .step(fetchWeather) .then(planActivities) .commit(); const weatherWorkflow = new Workflow({ name: "weather-workflow", triggerSchema: z.object({ cityA: z.string().describe("The city to get the weather for"), cityB: z.string().describe("The city to get the weather for"), }), result: { schema: z.object({ activitiesA: z.string(), activitiesB: z.string(), }), mapping: { activitiesA: { step: workflowA, path: "result.activities", }, activitiesB: { step: workflowB, path: "result.activities", }, }, }, }) .step(workflowA, { variables: { city: { step: "trigger", path: "cityA", }, }, }) .step(workflowB, { variables: { city: { step: "trigger", path: "cityB", }, }, }); weatherWorkflow.commit(); ``` この例では: 1. すべてのワークフロー間で型安全性を確保するためのスキーマを定義しています 2. 各ステップには適切な入力と出力のスキーマがあります 3. ネストされたワークフローには独自のトリガースキーマと結果マッピングがあります 4. `.step()`呼び出しで変数構文を使用してデータが渡されます 5. メインワークフローは両方のネストされたワークフローからのデータを組み合わせます --- title: "複雑なLLM操作の処理 | Workflows | Mastra" description: "MastraのWorkflowsは、分岐、並列実行、リソース一時停止などの機能を使用して、複雑な操作シーケンスを調整するのに役立ちます。" --- import { Steps } from "nextra/components"; # Workflows概要 [JA] Source: https://mastra.ai/ja/docs/workflows/overview Workflowsを使用すると、データフローで接続された**型付きステップ**として複雑なタスクシーケンスを定義し、オーケストレーションできます。各ステップには、Zodスキーマによって検証される明確に定義された入力と出力があります。 ワークフローは実行順序、依存関係、分岐、並列処理、エラーハンドリングを管理し、堅牢で再利用可能なプロセスを構築できるようにします。ステップはネストまたはクローンして、より大きなワークフローを構成できます。 ワークフローは以下の方法で作成します: - `createStep`で**ステップ**を定義し、入力/出力スキーマとビジネスロジックを指定する。 - `createWorkflow`で**ステップ**を構成し、実行フローを定義する。 - **ワークフロー**を実行してシーケンス全体を実行し、中断、再開、結果のストリーミングの組み込みサポートを利用する。 この構造により、完全な型安全性とランタイム検証が提供され、ワークフロー全体でデータの整合性が保証されます。 ## はじめに ワークフローを使用するには、まずワークフローモジュールから必要な関数をインポートします: ```typescript filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; ``` ### ステップの作成 ステップはワークフローの構成要素です。`createStep`を使用してステップを作成します: ```typescript filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy const step1 = createStep({...}); ``` > 詳細については[createStep](/reference/workflows/step)を参照してください。 ### ワークフローの作成 `createWorkflow`を使用してワークフローを作成し、`.commit()`で完了させます。 ```typescript {6,17} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const step1 = createStep({...}); export const testWorkflow = createWorkflow({ id: "test-workflow", description: 'Test workflow', inputSchema: z.object({ input: z.string() }), outputSchema: z.object({ output: z.string() }) }) .then(step1) .commit(); ``` > 詳細については[workflow](/reference/workflows/workflow)を参照してください。 #### ステップの組み合わせ ワークフローのステップは`.then()`を使用して組み合わせ、順次実行できます。 ```typescript {17,18} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; const step1 = createStep({...}); const step2 = createStep({...}); export const testWorkflow = createWorkflow({ id: "test-workflow", description: 'Test workflow', inputSchema: z.object({ input: z.string() }), outputSchema: z.object({ output: z.string() }) }) .then(step1) .then(step2) .commit(); ``` > ステップは様々な方法で組み合わせることができます。詳細については[Control Flow](/docs/workflows/control-flow)を参照してください。 #### ステップのクローン ワークフローのステップは`cloneStep()`を使用してクローンでき、任意のワークフローメソッドで使用できます。 ```typescript {5,19} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { createWorkflow, createStep, cloneStep } from "@mastra/core/workflows"; import { z } from "zod"; const step1 = createStep({...}); const clonedStep = cloneStep(step1, { id: "cloned-step" }); const step2 = createStep({...}); export const testWorkflow = createWorkflow({ id: "test-workflow", description: 'Test workflow', inputSchema: z.object({ input: z.string() }), outputSchema: z.object({ output: z.string() }) }) .then(step1) .then(clonedStep) .then(step2) .commit(); ``` ### ワークフローの登録 メインのMastraインスタンスで`workflows`を使用してワークフローを登録します: ```typescript {8} filename="src/mastra/index.ts" showLineNumbers copy import { Mastra } from "@mastra/core/mastra"; import { PinoLogger } from "@mastra/loggers"; import { LibSQLStore } from "@mastra/libsql"; import { testWorkflow } from "./workflows/test-workflow"; export const mastra = new Mastra({ workflows: { testWorkflow }, storage: new LibSQLStore({ // stores telemetry, evals, ... into memory storage, if it needs to persist, change to file:../mastra.db url: ":memory:" }), logger: new PinoLogger({ name: "Mastra", level: "info" }) }); ``` ### ワークフローの実行 ワークフローを実行してテストする方法は2つあります。 #### Mastra Playground Mastra Dev Serverが実行されている状態で、ブラウザで[http://localhost:4111/workflows](http://localhost:4111/workflows)にアクセスしてMastra Playgroundからワークフローを実行できます。 #### コマンドライン `createRun`と`start`を使用して、任意のMastraワークフローの実行インスタンスを作成します: ```typescript {3,5} filename="src/test-workflow.ts" showLineNumbers copy import { mastra } from "./mastra"; const run = mastra.getWorkflow("testWorkflow").createRun(); const result = await run.start({ inputData: { city: "London" } }); console.log(JSON.stringify(result, null, 2)); ``` > 詳細については[createRun](/reference/workflows/create-run)と[start](/reference/workflows/start)を参照してください。 このワークフローをトリガーするには、以下を実行します: ```bash npx tsx src/test-workflow.ts ``` ### ワークフローのストリーミング 上記で示したrunメソッドと同様に、ワークフローはストリーミングすることもできます: ```typescript {5} filename="src/test-workflow.ts" showLineNumbers copy import { mastra } from "./mastra"; const run = mastra.getWorkflow("testWorkflow").createRun(); const result = await run.stream({ inputData: { city: "London" } }); for await (const chunk of result.stream) { console.log(chunk); } ``` > 詳細については[stream](/reference/workflows/stream)と[messages](/reference/workflows/stream#messages)を参照してください。 ### ワークフローの監視 ワークフローを監視することもでき、発行される各イベントを検査できます。 ```typescript {5} filename="src/test-workflow.ts" showLineNumbers copy import { mastra } from "./mastra"; const run = mastra.getWorkflow("testWorkflow").createRun(); run.watch((event) => { console.log(event); }); const result = await run.start({ inputData: { city: "London" } }); ``` > 詳細については[watch](/reference/workflows/watch)を参照してください。 ## その他のリソース - Guidesセクションの[Workflow Guide](../../guides/guide/ai-recruiter.mdx)は、主要な概念をカバーするチュートリアルです。 - [Parallel Stepsワークフローの例](../../examples/workflows/parallel-steps.mdx) - [Conditional Branchingワークフローの例](../../examples/workflows/conditional-branching.mdx) - [Inngestワークフローの例](../../examples/workflows/inngest-workflow.mdx) - [Suspend and Resumeワークフローの例](../../examples/workflows/human-in-the-loop.mdx) --- title: "ランタイム変数 - 依存性注入 | ワークフロー | Mastra ドキュメント" description: Mastraの依存性注入システムを使用してワークフローとステップにランタイム設定を提供する方法を学びましょう。 --- # ワークフローランタイム変数 [JA] Source: https://mastra.ai/ja/docs/workflows/runtime-variables Mastraは、ランタイム変数を使用してワークフローとステップを設定できる強力な依存性注入システムを提供しています。この機能は、ランタイム構成に基づいて動作を適応できる柔軟で再利用可能なワークフローを作成するために不可欠です。 ## 概要 依存性注入システムにより、以下のことが可能になります: 1. 型安全なruntimeContextを通じてランタイム設定変数をワークフローに渡す 2. ステップ実行コンテキスト内でこれらの変数にアクセスする 3. 基盤となるコードを変更せずにワークフローの動作を変更する 4. 同じワークフロー内の複数のステップ間で設定を共有する ## 基本的な使用方法 ```typescript const myWorkflow = mastra.getWorkflow("myWorkflow"); const { runId, start, resume } = myWorkflow.createRun(); // Define your runtimeContext's type structure type WorkflowRuntimeContext = { multiplier: number; }; const runtimeContext = new RuntimeContext(); runtimeContext.set("multiplier", 5); // Start the workflow execution with runtimeContext await start({ triggerData: { inputValue: 45 }, runtimeContext, }); ``` ## REST APIでの使用 HTTPヘッダーから乗数値を動的に設定する方法は次のとおりです: ```typescript filename="src/index.ts" import { Mastra } from "@mastra/core"; import { RuntimeContext } from "@mastra/core/di"; import { workflow as myWorkflow } from "./workflows"; // Define runtimeContext type with clear, descriptive types type WorkflowRuntimeContext = { multiplier: number; }; export const mastra = new Mastra({ workflows: { myWorkflow, }, server: { middleware: [ async (c, next) => { const multiplier = c.req.header("x-multiplier"); const runtimeContext = c.get("runtimeContext"); // Parse and validate the multiplier value const multiplierValue = parseInt(multiplier || "1", 10); if (isNaN(multiplierValue)) { throw new Error("Invalid multiplier value"); } runtimeContext.set("multiplier", multiplierValue); await next(); // Don't forget to call next() }, ], }, }); ``` ## 変数を使用したステップの作成 ステップはruntimeContext変数にアクセスでき、ワークフローのruntimeContextタイプに準拠する必要があります: ```typescript import { Step } from "@mastra/core/workflow"; import { z } from "zod"; // Define step input/output types interface StepInput { inputValue: number; } interface StepOutput { incrementedValue: number; } const stepOne = new Step({ id: "stepOne", description: "Multiply the input value by the configured multiplier", execute: async ({ context, runtimeContext }) => { try { // Type-safe access to runtimeContext variables const multiplier = runtimeContext.get("multiplier"); if (multiplier === undefined) { throw new Error("Multiplier not configured in runtimeContext"); } // Get and validate input const inputValue = context.getStepResult("trigger")?.inputValue; if (inputValue === undefined) { throw new Error("Input value not provided"); } const result: StepOutput = { incrementedValue: inputValue * multiplier, }; return result; } catch (error) { console.error(`Error in stepOne: ${error.message}`); throw error; } }, }); ``` ## エラー処理 ワークフローでランタイム変数を使用する際には、潜在的なエラーを処理することが重要です: 1. **変数の欠落**: runtimeContextに必要な変数が存在するかを常に確認する 2. **型の不一致**: TypeScriptの型システムを使用してコンパイル時に型エラーを捕捉する 3. **無効な値**: ステップで使用する前に変数の値を検証する ```typescript // runtimeContext変数を使用した防御的プログラミングの例 const multiplier = runtimeContext.get("multiplier"); if (multiplier === undefined) { throw new Error("Multiplier not configured in runtimeContext"); } // 型と値の検証 if (typeof multiplier !== "number" || multiplier <= 0) { throw new Error(`Invalid multiplier value: ${multiplier}`); } ``` ## ベストプラクティス 1. **型安全性**: runtimeContextとステップの入力/出力に対して常に適切な型を定義する 2. **検証**: 使用する前にすべての入力とruntimeContext変数を検証する 3. **エラー処理**: ステップ内で適切なエラー処理を実装する 4. **ドキュメント化**: 各ワークフローに必要なruntimeContext変数を文書化する 5. **デフォルト値**: 可能な限り適切なデフォルト値を提供する --- title: "ステップの作成とワークフローへの追加 | Mastra ドキュメント" description: "Mastraワークフローのステップは、入力、出力、実行ロジックを定義することで、操作を管理するための構造化された方法を提供します。" --- # ワークフロー内のステップの定義 [JA] Source: https://mastra.ai/ja/docs/workflows/steps ワークフローを構築する際には、通常、操作をより小さなタスクに分割し、それらを連携・再利用できるようにします。ステップは、入力、出力、および実行ロジックを定義することで、これらのタスクを体系的に管理する方法を提供します。 以下のコードは、これらのステップをインラインまたは個別に定義する方法を示しています。 ## インラインステップの作成 `.step()` と `.then()` を使って、ワークフロー内で直接ステップを作成できます。以下のコードは、2つのステップを順番に定義し、リンクし、実行する方法を示しています。 ```typescript showLineNumbers filename="src/mastra/workflows/index.ts" copy import { Step, Workflow, Mastra } from "@mastra/core"; import { z } from "zod"; export const myWorkflow = new Workflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); myWorkflow .step( new Step({ id: "stepOne", outputSchema: z.object({ doubledValue: z.number(), }), execute: async ({ context }) => ({ doubledValue: context.triggerData.inputValue * 2, }), }), ) .then( new Step({ id: "stepTwo", outputSchema: z.object({ incrementedValue: z.number(), }), execute: async ({ context }) => { if (context.steps.stepOne.status !== "success") { return { incrementedValue: 0 }; } return { incrementedValue: context.steps.stepOne.output.doubledValue + 1, }; }, }), ) .commit(); // Register the workflow with Mastra export const mastra = new Mastra({ workflows: { myWorkflow }, }); ``` ## ステップを個別に作成する ステップのロジックを別々のエンティティで管理したい場合は、ステップを外部で定義し、その後ワークフローに追加することができます。以下のコードは、ステップを独立して定義し、後からリンクする方法を示しています。 ```typescript showLineNumbers filename="src/mastra/workflows/index.ts" copy import { Step, Workflow, Mastra } from "@mastra/core"; import { z } from "zod"; // Define steps separately const stepOne = new Step({ id: "stepOne", outputSchema: z.object({ doubledValue: z.number(), }), execute: async ({ context }) => ({ doubledValue: context.triggerData.inputValue * 2, }), }); const stepTwo = new Step({ id: "stepTwo", outputSchema: z.object({ incrementedValue: z.number(), }), execute: async ({ context }) => { if (context.steps.stepOne.status !== "success") { return { incrementedValue: 0 }; } return { incrementedValue: context.steps.stepOne.output.doubledValue + 1 }; }, }); // Build the workflow const myWorkflow = new Workflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); myWorkflow.step(stepOne).then(stepTwo); myWorkflow.commit(); // Register the workflow with Mastra export const mastra = new Mastra({ workflows: { myWorkflow }, }); ``` --- title: "ワークフローの一時停止と再開 | Human-in-the-Loop | Mastra ドキュメント" description: "Mastra のワークフローにおける一時停止と再開機能は、外部からの入力やリソースを待つ間に実行を一時停止することを可能にします。" --- # Suspend & Resume [JA] Source: https://mastra.ai/ja/docs/workflows/suspend-and-resume ワークフローは任意のステップで一時停止でき、現在の状態はスナップショットとしてストレージに永続化されます。その後、準備が整った時点で、この保存されたスナップショットから実行を再開できます。スナップショットを永続化することで、セッション、デプロイメント、サーバー再起動を跨いでワークフローの状態が維持され、外部入力やリソースを待機している間に一時停止される可能性があるワークフローにとって不可欠です。 ワークフローを一時停止する一般的なシナリオには以下があります: - 人間の承認や入力を待機する場合 - 外部APIリソースが利用可能になるまで一時停止する場合 - 後のステップで必要な追加データを収集する場合 - 高コストな操作のレート制限やスロットリング - 外部トリガーを持つイベント駆動プロセスの処理 ## ワークフローのステータス ワークフローを実行する際、その`status`は以下のいずれかになります: - `running` - ワークフローが現在実行中 - `suspended` - ワークフローが一時停止中 - `success` - ワークフローが完了 - `failed` - ワークフローが失敗 ## サスペンド 状態が `suspended` の場合、ワークフローの `suspended` 配列を見ることで、サスペンドされたすべてのステップを特定できます。 ```typescript {17} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy const step1 = createStep({ id: "step-1", description: "Test suspend", inputSchema: z.object({ input: z.array(z.string()) }), resumeSchema: z.object({ city: z.string() }), outputSchema: z.object({ output: z.string() }), execute: async ({ resumeData, suspend }) => { const { city } = resumeData ?? {}; if (!city) { await suspend({}); return { outcome: "" }; } return { output: "" }; } }); export const testWorkflow = createWorkflow({}) .then(step1) .commit(); ``` > 詳細については、[サスペンド可能なワークフローの定義](/examples/workflows/human-in-the-loop#define-suspendable-workflow) を参照してください。 ## Resume ワークフローは`resume`を呼び出し、必要な`resumeData`を提供することで再開できます。 ```typescript {6,12,13,14} filename="src/test-workflow.ts" showLineNumbers copy import { mastra } from "./mastra"; const run = mastra.getWorkflow("testWorkflow").createRun(); const result = await run.start({ inputData: { suggestions: ["London", "Paris", "New York"] } }); console.log(JSON.stringify(result, null, 2)); if (result.status === "suspended") { const resumedResult = await run.resume({ step: 'step-1', resumeData: { city: "New York" } }); console.log(JSON.stringify(resumedResult, null, 2)); } ``` ターミナルからこの実行を行うには: ```bash copy npx tsx src/test-workflow.ts ``` ### Nested Workflow 中断されたネストしたワークフローを再開するには、`resume`関数の`step`パラメータにワークフローインスタンスを渡します。 ```typescript {3} filename="src/test-workflow.ts" showLineNumbers copy const dowhileWorkflow = createWorkflow({ id: 'dowhile-workflow', inputSchema: z.object({ value: z.number() }), outputSchema: z.object({ value: z.number() }), }) .dountil( createWorkflow({ id: 'simple-resume-workflow', inputSchema: z.object({ value: z.number() }), outputSchema: z.object({ value: z.number() }), steps: [incrementStep, resumeStep], }) .then(incrementStep) .then(resumeStep) .commit(), async ({ inputData }) => inputData.value >= 10, ) .then( createStep({ id: 'final', inputSchema: z.object({ value: z.number() }), outputSchema: z.object({ value: z.number() }), execute: async ({ inputData }) => ({ value: inputData.value }), }), ) .commit(); const run = dowhileWorkflow.createRun(); const result = await run.start({ inputData: { value: 0 } }); if (result.status === "suspended") { const resumedResult = await run.resume({ resumeData: { value: 2 }, step: ['simple-resume-workflow', 'resume'], }); console.log(JSON.stringify(resumedResult, null, 2)); } ``` ## RuntimeContext `RuntimeContext`でsuspend/resumeを使用する場合、インスタンスを自分で作成し、それを`start`と`resume`関数に渡すことができます。 `RuntimeContext`はワークフロー実行時に自動的に共有されません。 ```typescript {1,4,9,16} filename="src/test-workflow.ts" showLineNumbers copy import { RuntimeContext } from "@mastra/core/di"; import { mastra } from "./mastra"; const runtimeContext = new RuntimeContext(); const run = mastra.getWorkflow("testWorkflow").createRun(); const result = await run.start({ inputData: { suggestions: ["London", "Paris", "New York"] }, runtimeContext }); if (result.status === "suspended") { const resumedResult = await run.resume({ step: 'step-1', resumeData: { city: "New York" }, runtimeContext }); } ``` --- title: "エージェントとツールでワークフローを使う | ワークフロー | Mastra ドキュメント" description: "Mastra のワークフローにおけるステップは、入力、出力、実行ロジックを定義することで、運用を体系的に管理する方法を提供します。" --- # Agents and Tools [JA] Source: https://mastra.ai/ja/docs/workflows/using-with-agents-and-tools ワークフローステップは構成可能で、通常は`execute`関数内で直接ロジックを実行します。しかし、エージェントやツールを呼び出すことがより適切な場合があります。このパターンは特に以下の場合に有用です: - LLMを使用してユーザー入力から自然言語応答を生成する場合。 - 複雑または再利用可能なロジックを専用ツールに抽象化する場合。 - 構造化された、または再利用可能な方法でサードパーティAPIと相互作用する場合。 ワークフローは、Mastraエージェントやツールを直接ステップとして使用できます。例:`createStep(testAgent)`または`createStep(testTool)`。 ## Agents ワークフローにエージェントを含めるには、通常の方法でエージェントを定義し、`createStep(testAgent)`を使用してワークフローに直接追加するか、ステップの`execute`関数内で`.generate()`を使用して呼び出します。 ### エージェントの例 このエージェントはOpenAIを使用して、都市、国、タイムゾーンに関する事実を生成します。 ```typescript filename="src/mastra/agents/test-agent.ts" showLineNumbers copy import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; export const testAgent = new Agent({ name: "test-agent", description: "Create facts for a country based on the city", instructions: `Return an interesting fact about the country based on the city provided`, model: openai("gpt-4o") }); ``` ### ステップとしてのエージェント この例では、`step1`は`testAgent`を使用して、指定された都市に基づいてその国に関する興味深い事実を生成します。 `.map`メソッドは、ワークフローの入力を`testAgent`と互換性のある`prompt`文字列に変換します。 ステップは`.then()`を使用してワークフローに組み込まれ、マップされた入力を受け取り、エージェントの構造化された出力を返すことができます。ワークフローは`.commit()`で完成されます。 ```typescript {3} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { testAgent } from "../agents/test-agent"; const step1 = createStep(testAgent); export const testWorkflow = createWorkflow({ id: "test-workflow", description: 'Test workflow', inputSchema: z.object({ input: z.string() }), outputSchema: z.object({ output: z.string() }) }) .map(({ inputData }) => { const { input } = inputData; return { prompt: `Provide facts about the city: ${input}` }; }) .then(step1) .commit(); ``` ### エージェントの生成 この例では、`step1`は提供された`input`を使用してプロンプトを構築し、それを`testAgent`に渡します。エージェントは都市とその国に関する事実を含むプレーンテキストの応答を返します。 ステップは順次`.then()`メソッドを使用してワークフローに追加され、ワークフローから入力を受け取り、構造化された出力を返すことができます。ワークフローは`.commit()`で完成されます。 ```typescript {1,18, 29} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { testAgent } from "../agents/test-agent"; const step1 = createStep({ id: "step-1", description: "Create facts for a country based on the city", inputSchema: z.object({ input: z.string() }), outputSchema: z.object({ output: z.string() }), execute: async ({ inputData }) => { const { input } = inputData; const prompt = `Provide facts about the city: ${input}` const { text } = await testAgent.generate([ { role: "user", content: prompt } ]); return { output: text }; } }); export const testWorkflow = createWorkflow({...}) .then(step1) .commit(); ``` ## Tools ワークフロー内でツールを使用するには、通常の方法で定義し、`createStep(testTool)`を使用してワークフローに直接追加するか、ステップの`execute`関数内で`.execute()`を使用して呼び出します。 ### ツールの例 以下の例では、Open Meteo APIを使用して都市の地理的位置の詳細を取得し、その名前、国、タイムゾーンを返します。 ```typescript filename="src/mastra/tools/test-tool.ts" showLineNumbers copy import { createTool } from "@mastra/core"; import { z } from "zod"; export const testTool = createTool({ id: "test-tool", description: "Gets country for a city", inputSchema: z.object({ input: z.string() }), outputSchema: z.object({ country_name: z.string() }), execute: async ({ context }) => { const { input } = context; const geocodingResponse = await fetch(`https://geocoding-api.open-meteo.com/v1/search?name=${input}`); const geocodingData = await geocodingResponse.json(); const { country } = geocodingData.results[0]; return { country_name: country }; } }); ``` ### ステップとしてのツール この例では、`step1`が`testTool`を使用し、提供された`city`を使用してジオコーディング検索を実行し、解決された`country`を返します。 ステップは順次`.then()`メソッドを使用してワークフローに追加され、ワークフローから入力を受け取り、構造化された出力を返すことができます。ワークフローは`.commit()`で完了します。 ```typescript {1,3,6} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { testTool } from "../tools/test-tool"; const step1 = createStep(testTool); export const testWorkflow = createWorkflow({...}) .then(step1) .commit(); ``` ### ツールの実行 この例では、`step1`が`.execute()`メソッドを使用して`testTool`を直接呼び出します。ツールは提供された`city`でジオコーディング検索を実行し、対応する`country`を返します。 結果はステップから構造化された出力として返されます。ステップは`.then()`を使用してワークフローに組み込まれ、ワークフローの入力を処理し、型付きの出力を生成できます。ワークフローは`.commit()`で完了します。 ```typescript {3,20,32} filename="src/mastra/workflows/test-workflow.ts" showLineNumbers copy import { RuntimeContext } from "@mastra/core/di"; import { testTool } from "../tools/test-tool"; const runtimeContext = new RuntimeContext(); const step1 = createStep({ id: "step-1", description: "Gets country for a city", inputSchema: z.object({ input: z.string() }), outputSchema: z.object({ output: z.string() }), execute: async ({ inputData }) => { const { input } = inputData; const { country_name } = await testTool.execute({ context: { input }, runtimeContext }); return { output: country_name }; } }); export const testWorkflow = createWorkflow({...}) .then(step1) .commit(); ``` ## ツールとしてのワークフロー この例では、`cityStringWorkflow`ワークフローがメインのMastraインスタンスに追加されています。 ```typescript {7} filename="src/mastra/index.ts" showLineNumbers copy import { Mastra } from "@mastra/core/mastra"; import { testWorkflow, cityStringWorkflow } from "./workflows/test-workflow"; export const mastra = new Mastra({ ... workflows: { testWorkflow, cityStringWorkflow }, }); ``` ワークフローが登録されると、ツール内から`getWorkflow`を使用して参照できます。 ```typescript {10,17-27} filename="src/mastra/tools/test-tool.ts" showLineNumbers copy export const cityCoordinatesTool = createTool({ id: "city-tool", description: "Convert city details", inputSchema: z.object({ city: z.string() }), outputSchema: z.object({ outcome: z.string() }), execute: async ({ context, mastra }) => { const { city } = context; const geocodingResponse = await fetch(`https://geocoding-api.open-meteo.com/v1/search?name=${city}`); const geocodingData = await geocodingResponse.json(); const { name, country, timezone } = geocodingData.results[0]; const workflow = mastra?.getWorkflow("cityStringWorkflow"); const run = workflow?.createRun(); const { result } = await run?.start({ inputData: { city_name: name, country_name: country, country_timezone: timezone } }); return { outcome: result.outcome }; } }); ``` ## MCP Server ワークフローをMastra `MCPServer`のインスタンスに渡すことで、ワークフローをツールに変換できます。これにより、MCP互換のクライアントがあなたのワークフローにアクセスできるようになります。 ワークフローの説明がツールの説明となり、入力スキーマがツールの入力スキーマとなります。 サーバーにワークフローを提供すると、各ワークフローは自動的に呼び出し可能なツールとして公開されます。例えば: - `run_testWorkflow` ```typescript filename="src/test-mcp-server.ts" showLineNumbers copy import { MCPServer } from "@mastra/mcp"; import { testAgent } from "./mastra/agents/test-agent"; import { testTool } from "./mastra/tools/test-tool"; import { testWorkflow } from "./mastra/workflows/test-workflow"; async function startServer() { const server = new MCPServer({ name: "test-mcp-server", version: "1.0.0", workflows: { testWorkflow } }); await server.startStdio(); console.log("MCPServer started on stdio"); } startServer().catch(console.error); ``` ワークフローがサーバーで利用可能であることを確認するには、MCPClientで接続できます。 ```typescript filename="src/test-mcp-client.ts" showLineNumbers copy import { MCPClient } from "@mastra/mcp"; async function main() { const mcp = new MCPClient({ servers: { local: { command: "npx", args: ["tsx", "src/test-mcp-server.ts"] } } }); const tools = await mcp.getTools(); console.log(tools); } main().catch(console.error); ``` クライアントスクリプトを実行して、ワークフローツールを確認してください。 ```bash npx tsx src/test-mcp-client.ts ``` ## その他のリソース - [MCPServer リファレンスドキュメント](/reference/tools/mcp-server)。 - [MCPClient リファレンスドキュメント](/reference/tools/mcp-client)。 --- title: "ワークフロー変数によるデータマッピング | Mastra ドキュメント" description: "Mastraワークフローでステップ間のデータをマッピングし、動的なデータフローを作成するためのワークフロー変数の使用方法を学びましょう。" --- # ワークフローの変数によるデータマッピング [JA] Source: https://mastra.ai/ja/docs/workflows/variables Mastraのワークフロー変数は、ステップ間でデータをマッピングするための強力なメカニズムを提供し、動的なデータフローを作成して、あるステップから別のステップへ情報を渡すことができます。 ## ワークフロー変数を理解する Mastraワークフローでは、変数は以下のような役割を果たします: - トリガー入力からステップ入力へのデータマッピング - あるステップの出力を別のステップの入力に渡す - ステップ出力内のネストされたプロパティにアクセスする - より柔軟で再利用可能なワークフローステップを作成する ## ワークフロー変数を使用したデータマッピング ### 基本的な変数マッピング `variables`プロパティを使用して、ワークフローにステップを追加する際にステップ間でデータをマッピングできます: ```typescript showLineNumbers filename="src/mastra/workflows/index.ts" copy const workflow = new Workflow({ name: "data-mapping-workflow", triggerSchema: z.object({ inputData: z.string(), }), }); workflow .step(step1, { variables: { // トリガーデータをステップ入力にマッピング inputData: { step: "trigger", path: "inputData" }, }, }) .then(step2, { variables: { // step1の出力をstep2の入力にマッピング previousValue: { step: step1, path: "outputField" }, }, }) .commit(); // ワークフローをMastraに登録 export const mastra = new Mastra({ workflows: { workflow }, }); ``` ### ネストされたプロパティへのアクセス `path`フィールドでドット表記を使用してネストされたプロパティにアクセスできます: ```typescript showLineNumbers filename="src/mastra/workflows/index.ts" copy workflow .step(step1) .then(step2, { variables: { // step1の出力からネストされたプロパティにアクセス nestedValue: { step: step1, path: "nested.deeply.value" }, }, }) .commit(); ``` ### オブジェクト全体のマッピング パスとして`.`を使用することで、オブジェクト全体をマッピングできます: ```typescript showLineNumbers filename="src/mastra/workflows/index.ts" copy workflow .step(step1, { variables: { // トリガーデータオブジェクト全体をマッピング triggerData: { step: "trigger", path: "." }, }, }) .commit(); ``` ### ループ内の変数 変数は`while`および`until`ループにも渡すことができます。これは反復間やステップ外からデータを渡す場合に便利です: ```typescript showLineNumbers filename="src/mastra/workflows/loop-variables.ts" copy // カウンターをインクリメントするステップ const incrementStep = new Step({ id: "increment", inputSchema: z.object({ // 前回の反復からの値 prevValue: z.number().optional(), }), outputSchema: z.object({ // 更新されたカウンター値 updatedCounter: z.number(), }), execute: async ({ context }) => { const { prevValue = 0 } = context.inputData; return { updatedCounter: prevValue + 1 }; }, }); const workflow = new Workflow({ name: "counter", }); workflow.step(incrementStep).while( async ({ context }) => { // カウンターが10未満の間続ける const result = context.getStepResult(incrementStep); return (result?.updatedCounter ?? 0) < 10; }, incrementStep, { // 前の値を次の反復に渡す prevValue: { step: incrementStep, path: "updatedCounter", }, }, ); ``` ## 変数の解決 ワークフローが実行されると、Mastraは以下の方法で実行時に変数を解決します: 1. `step`プロパティで指定されたソースステップを識別する 2. そのステップからの出力を取得する 3. `path`を使用して指定されたプロパティにナビゲートする 4. 解決された値をターゲットステップのコンテキストに`inputData`プロパティとして注入する ## 例 ### トリガーデータからのマッピング この例では、ワークフローのトリガーからステップにデータをマッピングする方法を示しています: ```typescript showLineNumbers filename="src/mastra/workflows/trigger-mapping.ts" copy import { Step, Workflow, Mastra } from "@mastra/core"; import { z } from "zod"; // Define a step that needs user input const processUserInput = new Step({ id: "processUserInput", execute: async ({ context }) => { // The inputData will be available in context because of the variable mapping const { inputData } = context.inputData; return { processedData: `Processed: ${inputData}`, }; }, }); // Create the workflow const workflow = new Workflow({ name: "trigger-mapping", triggerSchema: z.object({ inputData: z.string(), }), }); // Map the trigger data to the step workflow .step(processUserInput, { variables: { inputData: { step: "trigger", path: "inputData" }, }, }) .commit(); // Register the workflow with Mastra export const mastra = new Mastra({ workflows: { workflow }, }); ``` ### ステップ間のマッピング この例では、あるステップから別のステップへのデータマッピングを示しています: ```typescript showLineNumbers filename="src/mastra/workflows/step-mapping.ts" copy import { Step, Workflow, Mastra } from "@mastra/core"; import { z } from "zod"; // Step 1: Generate data const generateData = new Step({ id: "generateData", outputSchema: z.object({ nested: z.object({ value: z.string(), }), }), execute: async () => { return { nested: { value: "step1-data", }, }; }, }); // Step 2: Process the data from step 1 const processData = new Step({ id: "processData", inputSchema: z.object({ previousValue: z.string(), }), execute: async ({ context }) => { // previousValue will be available because of the variable mapping const { previousValue } = context.inputData; return { result: `Processed: ${previousValue}`, }; }, }); // Create the workflow const workflow = new Workflow({ name: "step-mapping", }); // Map data from step1 to step2 workflow .step(generateData) .then(processData, { variables: { // Map the nested.value property from generateData's output previousValue: { step: generateData, path: "nested.value" }, }, }) .commit(); // Register the workflow with Mastra export const mastra = new Mastra({ workflows: { workflow }, }); ``` ## 型安全性 Mastraは、TypeScriptを使用する際に変数マッピングの型安全性を提供します: ```typescript showLineNumbers filename="src/mastra/workflows/type-safe.ts" copy import { Step, Workflow, Mastra } from "@mastra/core"; import { z } from "zod"; // Define schemas for better type safety const triggerSchema = z.object({ inputValue: z.string(), }); type TriggerType = z.infer; // Step with typed context const step1 = new Step({ id: "step1", outputSchema: z.object({ nested: z.object({ value: z.string(), }), }), execute: async ({ context }) => { // TypeScript knows the shape of triggerData const triggerData = context.getStepResult("trigger"); return { nested: { value: `processed-${triggerData?.inputValue}`, }, }; }, }); // Create the workflow with the schema const workflow = new Workflow({ name: "type-safe-workflow", triggerSchema, }); workflow.step(step1).commit(); // Register the workflow with Mastra export const mastra = new Mastra({ workflows: { workflow }, }); ``` ## ベストプラクティス 1. **入力と出力を検証する**: データの一貫性を確保するために `inputSchema` と `outputSchema` を使用してください。 2. **マッピングをシンプルに保つ**: 可能な限り、過度に複雑なネストされたパスを避けてください。 3. **デフォルト値を考慮する**: マッピングされたデータが未定義の場合の処理を行ってください。 ## 直接コンテキストアクセスとの比較 `context.steps`を通じて前のステップの結果に直接アクセスすることもできますが、変数マッピングを使用すると以下のような利点があります: | 機能 | 変数マッピング | 直接コンテキストアクセス | | -------- | -------------------------------------- | ---------------------------- | | 明確さ | 明示的なデータ依存関係 | 暗黙的な依存関係 | | 再利用性 | ステップは異なるマッピングで再利用可能 | ステップは密接に結合している | | 型安全性 | より良いTypeScript統合 | 手動での型アサーションが必要 | --- title: "分岐、マージ、条件 | ワークフロー(レガシー) | Mastra ドキュメント" description: "Mastraレガシーワークフローの制御フローでは、分岐、マージ、条件を管理して、ロジック要件を満たすレガシーワークフローを構築できます。" --- # レガシーワークフローにおける制御フロー:分岐、マージ、条件 [JA] Source: https://mastra.ai/ja/docs/workflows-legacy/control-flow 複数ステップのプロセスを作成する場合、ステップを並行して実行したり、順番に連鎖させたり、結果に基づいて異なるパスをたどる必要があるかもしれません。このページでは、ロジック要件を満たすワークフローを構築するために、分岐、マージ、条件をどのように管理できるかを説明します。コードスニペットは、複雑な制御フローを構築するための主要なパターンを示しています。 ## 並列実行 互いに依存関係のないステップを同時に実行することができます。ステップが独立したタスクを実行する場合、このアプローチによってワークフローを高速化できます。以下のコードは、2つのステップを並列に追加する方法を示しています: ```typescript myWorkflow.step(fetchUserData).step(fetchOrderData); ``` 詳細については、[並列ステップ](../../examples/workflows_legacy/parallel-steps.mdx)の例を参照してください。 ## 順次実行 時には、あるステップの出力が次のステップの入力になるように、厳密な順序でステップを実行する必要があります。依存する操作をリンクするには .then() を使用します。以下のコードは、ステップを順番に連鎖させる方法を示しています: ```typescript myWorkflow.step(fetchOrderData).then(validateData).then(processOrder); ``` 詳細については、[順次ステップ](../../examples/workflows_legacy/sequential-steps.mdx)の例を参照してください。 ## 分岐と合流パス 異なる結果に異なるパスが必要な場合、分岐が役立ちます。また、完了後にパスを後で合流させることもできます。以下のコードは、stepAの後に分岐し、後でstepFで収束する方法を示しています: ```typescript myWorkflow .step(stepA) .then(stepB) .then(stepD) .after(stepA) .step(stepC) .then(stepE) .after([stepD, stepE]) .step(stepF); ``` この例では: - stepAはstepBに進み、その後stepDに進みます。 - 別途、stepAはstepCもトリガーし、それがstepEにつながります。 - 別途、stepFはstepDとstepEの両方が完了したときにトリガーされます。 詳細については、[分岐パス](../../examples/workflows_legacy/branching-paths.mdx)の例を参照してください。 ## 複数のブランチのマージ 時には、複数の他のステップが完了した後にのみ実行されるステップが必要な場合があります。Mastraは、ステップに対して複数の依存関係を指定できる複合的な`.after([])`構文を提供しています。 ```typescript myWorkflow .step(fetchUserData) .then(validateUserData) .step(fetchProductData) .then(validateProductData) // This step will only run after BOTH validateUserData AND validateProductData have completed .after([validateUserData, validateProductData]) .step(processOrder); ``` この例では: - `fetchUserData`と`fetchProductData`は並列ブランチで実行されます - 各ブランチには独自の検証ステップがあります - `processOrder`ステップは、両方の検証ステップが正常に完了した後にのみ実行されます このパターンは特に以下の場合に役立ちます: - 並列実行パスの結合 - ワークフローに同期ポイントを実装する - 進行する前にすべての必要なデータが利用可能であることを確認する 複数の`.after([])`呼び出しを組み合わせることで、複雑な依存関係パターンを作成することもできます: ```typescript myWorkflow // First branch .step(stepA) .then(stepB) .then(stepC) // Second branch .step(stepD) .then(stepE) // Third branch .step(stepF) .then(stepG) // This step depends on the completion of multiple branches .after([stepC, stepE, stepG]) .step(finalStep); ``` ## 循環依存関係とループ ワークフローでは、特定の条件が満たされるまでステップを繰り返す必要がよくあります。Mastra では、ループを作成するための強力な2つの方法、`until` と `while` を提供しています。これらのメソッドは、繰り返しタスクを直感的に実装する方法を提供します。 ### 手動による循環依存関係の利用(レガシーな方法) 以前のバージョンでは、条件付きで循環依存関係を手動で定義することでループを作成できました: ```typescript myWorkflow .step(fetchData) .then(processData) .after(processData) .step(finalizeData, { when: { "processData.status": "success" }, }) .step(fetchData, { when: { "processData.status": "retry" }, }); ``` この方法も引き続き利用できますが、より新しい `until` や `while` メソッドを使うことで、よりシンプルで保守しやすいループを作成できます。 ### `until` を使った条件付きループ `until` メソッドは、指定した条件が真になるまでステップを繰り返します。引数は以下の通りです: 1. ループを終了する条件 2. 繰り返すステップ 3. 繰り返しステップに渡すオプションの変数 ```typescript import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // 目標値に達するまでカウンターをインクリメントするステップ const incrementStep = new LegacyStep({ id: "increment", inputSchema: z.object({ // 現在のカウンター値 counter: z.number().optional(), }), outputSchema: z.object({ // 更新後のカウンター値 updatedCounter: z.number(), }), execute: async ({ context }) => { const { counter = 0 } = context.inputData; return { updatedCounter: counter + 1 }; }, }); workflow .step(incrementStep) .until( async ({ context }) => { // カウンターが10に達したら停止 const result = context.getStepResult(incrementStep); return (result?.updatedCounter ?? 0) >= 10; }, incrementStep, { // 現在のカウンターを次のイテレーションに渡す counter: { step: incrementStep, path: "updatedCounter", }, }, ) .then(finalStep); ``` 参照ベースの条件も利用できます: ```typescript workflow .step(incrementStep) .until( { ref: { step: incrementStep, path: "updatedCounter" }, query: { $gte: 10 }, }, incrementStep, { counter: { step: incrementStep, path: "updatedCounter", }, }, ) .then(finalStep); ``` ### `while` を使った条件付きループ `while` メソッドは、指定した条件が真である間ステップを繰り返します。引数は `until` と同じです: 1. ループを継続する条件 2. 繰り返すステップ 3. 繰り返しステップに渡すオプションの変数 ```typescript // 目標値未満の間カウンターをインクリメントするステップ const incrementStep = new LegacyStep({ id: "increment", inputSchema: z.object({ // 現在のカウンター値 counter: z.number().optional(), }), outputSchema: z.object({ // 更新後のカウンター値 updatedCounter: z.number(), }), execute: async ({ context }) => { const { counter = 0 } = context.inputData; return { updatedCounter: counter + 1 }; }, }); workflow .step(incrementStep) .while( async ({ context }) => { // カウンターが10未満の間継続 const result = context.getStepResult(incrementStep); return (result?.updatedCounter ?? 0) < 10; }, incrementStep, { // 現在のカウンターを次のイテレーションに渡す counter: { step: incrementStep, path: "updatedCounter", }, }, ) .then(finalStep); ``` 参照ベースの条件も利用できます: ```typescript workflow .step(incrementStep) .while( { ref: { step: incrementStep, path: "updatedCounter" }, query: { $lt: 10 }, }, incrementStep, { counter: { step: incrementStep, path: "updatedCounter", }, }, ) .then(finalStep); ``` ### 参照条件の比較演算子 参照ベースの条件を使用する場合、以下の比較演算子を使用できます: | 演算子 | 説明 | | -------- | ------------------------ | | `$eq` | 等しい | | `$ne` | 等しくない | | `$gt` | より大きい | | `$gte` | 以上 | | `$lt` | より小さい | | `$lte` | 以下 | ## 条件 前のステップからのデータに基づいてステップを実行するかどうかを制御するには、when プロパティを使用します。以下は条件を指定する3つの方法です。 ### オプション1:関数 ```typescript myWorkflow.step( new Step({ id: "processData", execute: async ({ context }) => { // Action logic }, }), { when: async ({ context }) => { const fetchData = context?.getStepResult<{ status: string }>("fetchData"); return fetchData?.status === "success"; }, }, ); ``` ### オプション2:クエリオブジェクト ```typescript myWorkflow.step( new Step({ id: "processData", execute: async ({ context }) => { // Action logic }, }), { when: { ref: { step: { id: "fetchData", }, path: "status", }, query: { $eq: "success" }, }, }, ); ``` ### オプション3:シンプルなパス比較 ```typescript myWorkflow.step( new Step({ id: "processData", execute: async ({ context }) => { // Action logic }, }), { when: { "fetchData.status": "success", }, }, ); ``` ## データアクセスパターン Mastraはステップ間でデータを受け渡すためのいくつかの方法を提供しています: 1. **コンテキストオブジェクト** - コンテキストオブジェクトを通じて直接ステップの結果にアクセスする 2. **変数マッピング** - あるステップの出力を別のステップの入力に明示的にマッピングする 3. **getStepResultメソッド** - ステップの出力を取得するための型安全なメソッド 各アプローチは、ユースケースと型安全性の要件に応じて、それぞれ利点があります。 ### getStepResultメソッドの使用 `getStepResult`メソッドは、ステップの結果にアクセスするための型安全な方法を提供します。TypeScriptを使用する場合は、型情報を保持するためにこのアプローチが推奨されます。 #### 基本的な使用法 より良い型安全性のために、`getStepResult`に型パラメータを提供することができます: ```typescript showLineNumbers filename="src/mastra/workflows/get-step-result.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const fetchUserStep = new LegacyStep({ id: "fetchUser", outputSchema: z.object({ name: z.string(), userId: z.string(), }), execute: async ({ context }) => { return { name: "John Doe", userId: "123" }; }, }); const analyzeDataStep = new LegacyStep({ id: "analyzeData", execute: async ({ context }) => { // Type-safe access to previous step result const userData = context.getStepResult<{ name: string; userId: string }>( "fetchUser", ); if (!userData) { return { status: "error", message: "User data not found" }; } return { analysis: `Analyzed data for user ${userData.name}`, userId: userData.userId, }; }, }); ``` #### ステップ参照の使用 最も型安全なアプローチは、`getStepResult`呼び出しで直接ステップを参照することです: ```typescript showLineNumbers filename="src/mastra/workflows/step-reference.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Define step with output schema const fetchUserStep = new LegacyStep({ id: "fetchUser", outputSchema: z.object({ userId: z.string(), name: z.string(), email: z.string(), }), execute: async () => { return { userId: "user123", name: "John Doe", email: "john@example.com", }; }, }); const processUserStep = new LegacyStep({ id: "processUser", execute: async ({ context }) => { // TypeScript will infer the correct type from fetchUserStep's outputSchema const userData = context.getStepResult(fetchUserStep); return { processed: true, userName: userData?.name, }; }, }); const workflow = new LegacyWorkflow({ name: "user-workflow", }); workflow.step(fetchUserStep).then(processUserStep).commit(); ``` ### 変数マッピングの使用 変数マッピングは、ステップ間のデータフローを定義する明示的な方法です。 このアプローチは依存関係を明確にし、優れた型安全性を提供します。 ステップに注入されたデータは`context.inputData`オブジェクトで利用可能であり、ステップの`inputSchema`に基づいて型付けされます。 ```typescript showLineNumbers filename="src/mastra/workflows/variable-mapping.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const fetchUserStep = new LegacyStep({ id: "fetchUser", outputSchema: z.object({ userId: z.string(), name: z.string(), email: z.string(), }), execute: async () => { return { userId: "user123", name: "John Doe", email: "john@example.com", }; }, }); const sendEmailStep = new LegacyStep({ id: "sendEmail", inputSchema: z.object({ recipientEmail: z.string(), recipientName: z.string(), }), execute: async ({ context }) => { const { recipientEmail, recipientName } = context.inputData; // Send email logic here return { status: "sent", to: recipientEmail, }; }, }); const workflow = new LegacyWorkflow({ name: "email-workflow", }); workflow .step(fetchUserStep) .then(sendEmailStep, { variables: { // Map specific fields from fetchUser to sendEmail inputs recipientEmail: { step: fetchUserStep, path: "email" }, recipientName: { step: fetchUserStep, path: "name" }, }, }) .commit(); ``` 変数マッピングの詳細については、[ワークフローバリアブルによるデータマッピング](./variables.mdx)のドキュメントをご覧ください。 ### Contextオブジェクトの使用 contextオブジェクトは、すべてのステップ結果とその出力に直接アクセスすることができます。この方法はより柔軟ですが、型安全性を維持するためには慎重な取り扱いが必要です。 ステップの結果には `context.steps` オブジェクトを通じて直接アクセスできます。 ```typescript showLineNumbers filename="src/mastra/workflows/context-access.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const processOrderStep = new LegacyStep({ id: "processOrder", execute: async ({ context }) => { // Access data from a previous step let userData: { name: string; userId: string }; if (context.steps["fetchUser"]?.status === "success") { userData = context.steps.fetchUser.output; } else { throw new Error("User data not found"); } return { orderId: "order123", userId: userData.userId, status: "processing", }; }, }); const workflow = new LegacyWorkflow({ name: "order-workflow", }); workflow.step(fetchUserStep).then(processOrderStep).commit(); ``` ### ワークフローレベルの型安全性 ワークフロー全体で包括的な型安全性を確保するために、すべてのステップの型を定義し、それらをWorkflowに渡すことができます。 これにより、条件や最終的なワークフロー出力でcontextオブジェクトやステップ結果に対して型安全性を得ることができます。 ```typescript showLineNumbers filename="src/mastra/workflows/workflow-typing.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Create steps with typed outputs const fetchUserStep = new LegacyStep({ id: "fetchUser", outputSchema: z.object({ userId: z.string(), name: z.string(), email: z.string(), }), execute: async () => { return { userId: "user123", name: "John Doe", email: "john@example.com", }; }, }); const processOrderStep = new LegacyStep({ id: "processOrder", execute: async ({ context }) => { // TypeScript knows the shape of userData const userData = context.getStepResult(fetchUserStep); return { orderId: "order123", status: "processing", }; }, }); const workflow = new LegacyWorkflow< [typeof fetchUserStep, typeof processOrderStep] >({ name: "typed-workflow", }); workflow .step(fetchUserStep) .then(processOrderStep) .until(async ({ context }) => { // TypeScript knows the shape of userData here const res = context.getStepResult("fetchUser"); return res?.userId === "123"; }, processOrderStep) .commit(); ``` ### トリガーデータへのアクセス ステップ結果に加えて、ワークフローを開始した元のトリガーデータにもアクセスできます。 ```typescript showLineNumbers filename="src/mastra/workflows/trigger-data.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Define trigger schema const triggerSchema = z.object({ customerId: z.string(), orderItems: z.array(z.string()), }); type TriggerType = z.infer; const processOrderStep = new LegacyStep({ id: "processOrder", execute: async ({ context }) => { // Access trigger data with type safety const triggerData = context.getStepResult("trigger"); return { customerId: triggerData?.customerId, itemCount: triggerData?.orderItems.length || 0, status: "processing", }; }, }); const workflow = new LegacyWorkflow({ name: "order-workflow", triggerSchema, }); workflow.step(processOrderStep).commit(); ``` ### レジュームデータへのアクセス ステップに注入されたデータは `context.inputData` オブジェクトで利用でき、ステップの `inputSchema` に基づいて型付けされます。 ```typescript showLineNumbers filename="src/mastra/workflows/resume-data.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const processOrderStep = new LegacyStep({ id: "processOrder", inputSchema: z.object({ orderId: z.string(), }), execute: async ({ context, suspend }) => { const { orderId } = context.inputData; if (!orderId) { await suspend(); return; } return { orderId, status: "processed", }; }, }); const workflow = new LegacyWorkflow({ name: "order-workflow", }); workflow.step(processOrderStep).commit(); const run = workflow.createRun(); const result = await run.start(); const resumedResult = await workflow.resume({ runId: result.runId, stepId: "processOrder", inputData: { orderId: "123", }, }); console.log({ resumedResult }); ``` ### ワークフロー結果へのアクセス `Workflow` 型パラメータにステップ型を注入することで、ワークフローの結果に型安全にアクセスできます。 ```typescript showLineNumbers filename="src/mastra/workflows/get-results.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const fetchUserStep = new LegacyStep({ id: "fetchUser", outputSchema: z.object({ userId: z.string(), name: z.string(), email: z.string(), }), execute: async () => { return { userId: "user123", name: "John Doe", email: "john@example.com", }; }, }); const processOrderStep = new LegacyStep({ id: "processOrder", outputSchema: z.object({ orderId: z.string(), status: z.string(), }), execute: async ({ context }) => { const userData = context.getStepResult(fetchUserStep); return { orderId: "order123", status: "processing", }; }, }); const workflow = new LegacyWorkflow< [typeof fetchUserStep, typeof processOrderStep] >({ name: "typed-workflow", }); workflow.step(fetchUserStep).then(processOrderStep).commit(); const run = workflow.createRun(); const result = await run.start(); // The result is a discriminated union of the step results // So it needs to be narrowed down via status checks if (result.results.processOrder.status === "success") { // TypeScript will know the shape of the results const orderId = result.results.processOrder.output.orderId; console.log({ orderId }); } if (result.results.fetchUser.status === "success") { const userId = result.results.fetchUser.output.userId; console.log({ userId }); } ``` ### データフローのベストプラクティス 1. **型安全性のために Step 参照とともに getStepResult を使用する** - TypeScript が正しい型を推論できるようにする - コンパイル時に型エラーを検出できる 2. \*_依存関係を明示するために変数マッピングを使用する_ - データフローが明確かつ保守しやすくなる - ステップ間の依存関係をドキュメント化できる 3. **ステップごとに出力スキーマを定義する** - 実行時にデータを検証できる - `execute` 関数の戻り値の型を検証できる - TypeScript での型推論が向上する 4. **データが存在しない場合も適切に処理する** - プロパティへアクセスする前に必ずステップ結果の有無を確認する - オプションデータにはフォールバック値を用意する 5. **データ変換はシンプルに保つ** - 変数マッピング内ではなく、専用のステップでデータを変換する - ワークフローのテストやデバッグが容易になる ### データフロー手法の比較 | 手法 | 型安全性 | 明示性 | ユースケース | | ----------------- | ----------- | ------------ | ---------------------------------------------------- | | getStepResult | 最高 | 高い | 厳格な型付けが必要な複雑なワークフロー | | 変数マッピング | 高い | 高い | 依存関係を明確にしたい場合 | | context.steps | 中程度 | 低い | シンプルなワークフローでステップデータへ素早くアクセスしたい場合 | ユースケースに合ったデータフロー手法を選択することで、型安全かつ保守性の高いワークフローを構築できます。 --- title: "動的ワークフロー(レガシー) | Mastra ドキュメント" description: "レガシーワークフローステップ内で動的ワークフローを作成する方法を学び、実行時の条件に基づいて柔軟なワークフロー作成を可能にします。" --- # 動的ワークフロー(レガシー) [JA] Source: https://mastra.ai/ja/docs/workflows-legacy/dynamic-workflows このガイドでは、ワークフローステップ内で動的ワークフローを作成する方法を説明します。この高度なパターンを使用すると、実行時の条件に基づいてワークフローをその場で作成して実行することができます。 ## 概要 ダイナミックワークフローは、実行時のデータに基づいてワークフローを作成する必要がある場合に便利です。 ## 実装 動的ワークフローを作成するための鍵は、ステップの `execute` 関数内から Mastra インスタンスにアクセスし、それを使って新しいワークフローを作成・実行することです。 ### 基本例 ```typescript import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const isMastra = (mastra: any): mastra is Mastra => { return mastra && typeof mastra === "object" && mastra instanceof Mastra; }; // Step that creates and runs a dynamic workflow const createDynamicWorkflow = new LegacyStep({ id: "createDynamicWorkflow", outputSchema: z.object({ dynamicWorkflowResult: z.any(), }), execute: async ({ context, mastra }) => { if (!mastra) { throw new Error("Mastra instance not available"); } if (!isMastra(mastra)) { throw new Error("Invalid Mastra instance"); } const inputData = context.triggerData.inputData; // Create a new dynamic workflow const dynamicWorkflow = new LegacyWorkflow({ name: "dynamic-workflow", mastra, // Pass the mastra instance to the new workflow triggerSchema: z.object({ dynamicInput: z.string(), }), }); // Define steps for the dynamic workflow const dynamicStep = new LegacyStep({ id: "dynamicStep", execute: async ({ context }) => { const dynamicInput = context.triggerData.dynamicInput; return { processedValue: `Processed: ${dynamicInput}`, }; }, }); // Build and commit the dynamic workflow dynamicWorkflow.step(dynamicStep).commit(); // Create a run and execute the dynamic workflow const run = dynamicWorkflow.createRun(); const result = await run.start({ triggerData: { dynamicInput: inputData, }, }); let dynamicWorkflowResult; if (result.results["dynamicStep"]?.status === "success") { dynamicWorkflowResult = result.results["dynamicStep"]?.output.processedValue; } else { throw new Error("Dynamic workflow failed"); } // Return the result from the dynamic workflow return { dynamicWorkflowResult, }; }, }); // Main workflow that uses the dynamic workflow creator const mainWorkflow = new LegacyWorkflow({ name: "main-workflow", triggerSchema: z.object({ inputData: z.string(), }), mastra: new Mastra(), }); mainWorkflow.step(createDynamicWorkflow).commit(); // Register the workflow with Mastra export const mastra = new Mastra({ legacy_workflows: { mainWorkflow }, }); const run = mainWorkflow.createRun(); const result = await run.start({ triggerData: { inputData: "test", }, }); ``` ## 高度な例:ワークフローファクトリー 入力パラメータに基づいて異なるワークフローを生成するワークフローファクトリーを作成できます: ```typescript const isMastra = (mastra: any): mastra is Mastra => { return mastra && typeof mastra === "object" && mastra instanceof Mastra; }; const workflowFactory = new LegacyStep({ id: "workflowFactory", inputSchema: z.object({ workflowType: z.enum(["simple", "complex"]), inputData: z.string(), }), outputSchema: z.object({ result: z.any(), }), execute: async ({ context, mastra }) => { if (!mastra) { throw new Error("Mastra instance not available"); } if (!isMastra(mastra)) { throw new Error("Invalid Mastra instance"); } // Create a new dynamic workflow based on the type const dynamicWorkflow = new LegacyWorkflow({ name: `dynamic-${context.workflowType}-workflow`, mastra, triggerSchema: z.object({ input: z.string(), }), }); if (context.workflowType === "simple") { // Simple workflow with a single step const simpleStep = new Step({ id: "simpleStep", execute: async ({ context }) => { return { result: `Simple processing: ${context.triggerData.input}`, }; }, }); dynamicWorkflow.step(simpleStep).commit(); } else { // Complex workflow with multiple steps const step1 = new LegacyStep({ id: "step1", outputSchema: z.object({ intermediateResult: z.string(), }), execute: async ({ context }) => { return { intermediateResult: `First processing: ${context.triggerData.input}`, }; }, }); const step2 = new LegacyStep({ id: "step2", execute: async ({ context }) => { const intermediate = context.getStepResult(step1).intermediateResult; return { finalResult: `Second processing: ${intermediate}`, }; }, }); dynamicWorkflow.step(step1).then(step2).commit(); } // Execute the dynamic workflow const run = dynamicWorkflow.createRun(); const result = await run.start({ triggerData: { input: context.inputData, }, }); // Return the appropriate result based on workflow type if (context.workflowType === "simple") { return { // @ts-ignore result: result.results["simpleStep"]?.output, }; } else { return { // @ts-ignore result: result.results["step2"]?.output, }; } }, }); ``` ## 重要な考慮事項 1. **Mastraインスタンス**: `execute`関数の`mastra`パラメータは、動的ワークフローの作成に不可欠なMastraインスタンスへのアクセスを提供します。 2. **エラー処理**: 動的ワークフローを作成する前に、必ずMastraインスタンスが利用可能かどうかを確認してください。 3. **リソース管理**: 動的ワークフローはリソースを消費するため、単一の実行で多くのワークフローを作成しないよう注意してください。 4. **ワークフローのライフサイクル**: 動的ワークフローは自動的にメインのMastraインスタンスに登録されません。明示的に登録しない限り、ステップ実行の期間中のみ存在します。 5. **デバッグ**: 動的ワークフローのデバッグは難しい場合があります。作成と実行を追跡するための詳細なログの追加を検討してください。 ## ユースケース - **条件付きワークフローの選択**: 入力データに基づいて異なるワークフローパターンを選択 - **パラメータ化されたワークフロー**: 動的な設定でワークフローを作成 - **ワークフローテンプレート**: テンプレートを使用して特殊なワークフローを生成 - **マルチテナントアプリケーション**: 異なるテナント向けに分離されたワークフローを作成 ## 結論 動的ワークフローは、柔軟で適応性の高いワークフローシステムを構築するための強力な方法です。ステップ実行内でMastraインスタンスを活用することで、実行時の状況や要件に応じて対応するワークフローを作成できます。 --- title: "ワークフローにおけるエラー処理(レガシー) | Mastra ドキュメント" description: "ステップの再試行、条件分岐、モニタリングを使用して、Mastraレガシーワークフローでエラーを処理する方法を学びましょう。" --- # ワークフローにおけるエラー処理(レガシー) [JA] Source: https://mastra.ai/ja/docs/workflows-legacy/error-handling 本番環境のワークフローには堅牢なエラー処理が不可欠です。Mastra は、エラーを適切に処理するためのさまざまな仕組みを提供しており、ワークフローが障害から回復したり、必要に応じて優雅に機能を縮小したりできるようにします。 ## 概要 Mastra ワークフローでのエラー処理は、以下の方法で実装できます。 1. **ステップの再試行** - 失敗したステップを自動的に再試行する 2. **条件分岐** - ステップの成功または失敗に基づいて代替パスを作成する 3. **エラーモニタリング** - ワークフローのエラーを監視し、プログラム的に対応する 4. **結果ステータスの確認** - 後続のステップで前のステップのステータスを確認する ## ステップのリトライ Mastra には、一時的なエラーによって失敗したステップのための組み込みリトライ機構が用意されています。これは、外部サービスや一時的に利用できなくなるリソースと連携するステップに特に有用です。 ### 基本的なリトライ設定 リトライはワークフロー全体、または個々のステップごとに設定できます。 ```typescript import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; // ワークフロー全体のリトライ設定 const workflow = new LegacyWorkflow({ name: "my-workflow", retryConfig: { attempts: 3, // リトライ試行回数 delay: 1000, // リトライ間の遅延(ミリ秒) }, }); // ステップごとのリトライ設定(ワークフロー全体の設定を上書き) const apiStep = new LegacyStep({ id: "callApi", execute: async () => { // 失敗する可能性のあるAPI呼び出し }, retryConfig: { attempts: 5, // このステップは最大5回までリトライ delay: 2000, // リトライ間の遅延は2秒 }, }); ``` ステップのリトライについての詳細は、[ステップのリトライ](../../reference/legacyWorkflows/step-retries.mdx) リファレンスをご覧ください。 ## 条件分岐 条件ロジックを使用して、前のステップの成功または失敗に基づいてワークフローの代替パスを作成できます。 ```typescript // Create a workflow with conditional branching const workflow = new LegacyWorkflow({ name: "error-handling-workflow", }); workflow .step(fetchDataStep) .then(processDataStep, { // Only execute processDataStep if fetchDataStep was successful when: ({ context }) => { return context.steps.fetchDataStep?.status === "success"; }, }) .then(fallbackStep, { // Execute fallbackStep if fetchDataStep failed when: ({ context }) => { return context.steps.fetchDataStep?.status === "failed"; }, }) .commit(); ``` ## エラーモニタリング `watch` メソッドを使用してワークフローのエラーを監視できます。 ```typescript const { start, watch } = workflow.createRun(); watch(async ({ results }) => { // Check for any failed steps const failedSteps = Object.entries(results) .filter(([_, step]) => step.status === "failed") .map(([stepId]) => stepId); if (failedSteps.length > 0) { console.error(`Workflow has failed steps: ${failedSteps.join(", ")}`); // Take remedial action, such as alerting or logging } }); await start(); ``` ## ステップでのエラー処理 ステップの実行関数内で、プログラム的にエラーを処理することができます。 ```typescript const robustStep = new LegacyStep({ id: "robustStep", execute: async ({ context }) => { try { // Attempt the primary operation const result = await someRiskyOperation(); return { success: true, data: result }; } catch (error) { // Log the error console.error("Operation failed:", error); // Return a graceful fallback result instead of throwing return { success: false, error: error.message, fallbackData: "Default value", }; } }, }); ``` ## 前のステップの結果を確認する 前のステップの結果に基づいて判断を行うことができます。 ```typescript const finalStep = new LegacyStep({ id: "finalStep", execute: async ({ context }) => { // Check results of previous steps const step1Success = context.steps.step1?.status === "success"; const step2Success = context.steps.step2?.status === "success"; if (step1Success && step2Success) { // All steps succeeded return { status: "complete", result: "All operations succeeded" }; } else if (step1Success) { // Only step1 succeeded return { status: "partial", result: "Partial completion" }; } else { // Critical failure return { status: "failed", result: "Critical steps failed" }; } }, }); ``` ## エラー処理のベストプラクティス 1. **一時的な障害にはリトライを使用する**: 一時的な問題が発生する可能性のあるステップには、リトライポリシーを設定しましょう。 2. **フォールバックパスを用意する**: 重要なステップが失敗した場合に備えて、代替経路をワークフローに設計しましょう。 3. **エラーシナリオを具体的にする**: エラーの種類ごとに異なる処理戦略を使い分けましょう。 4. **エラーを包括的に記録する**: デバッグを容易にするため、エラー記録時にはコンテキスト情報も含めましょう。 5. **失敗時には意味のあるデータを返す**: ステップが失敗した場合、後続のステップが判断できるように、失敗に関する構造化データを返しましょう。 6. **冪等性を考慮する**: ステップが安全に再実行でき、重複した副作用が発生しないようにしましょう。 7. **ワークフローの実行を監視する**: `watch` メソッドを使ってワークフローの実行を積極的に監視し、早期にエラーを検知しましょう。 ## 高度なエラー処理 より複雑なエラー処理が必要な場合は、次の点を検討してください。 - **サーキットブレーカーの実装**: ステップが繰り返し失敗した場合、再試行を停止し、フォールバック戦略を使用する - **タイムアウト処理の追加**: ステップごとに時間制限を設け、ワークフローが無限に停止しないようにする - **専用のエラー回復ワークフローの作成**: 重要なワークフローの場合、メインのワークフローが失敗した際にトリガーされる専用の回復ワークフローを作成する ## 関連 - [ステップ再試行リファレンス](../../reference/legacyWorkflows/step-retries.mdx) - [Watch メソッドリファレンス](../../reference/legacyWorkflows/watch.mdx) - [ステップ条件](../../reference/legacyWorkflows/step-condition.mdx) - [制御フロー](./control-flow.mdx) # ネストされたワークフロー(レガシー) [JA] Source: https://mastra.ai/ja/docs/workflows-legacy/nested-workflows Mastraでは、ワークフローを他のワークフロー内のステップとして使用することができ、モジュール式で再利用可能なワークフローコンポーネントを作成できます。この機能により、複雑なワークフローを小さく管理しやすい部分に整理し、コードの再利用を促進します。 また、親ワークフロー内のステップとしてネストされたワークフローを視覚的に確認できるため、ワークフローの流れを理解しやすくなります。 ## 基本的な使い方 ワークフローは、`step()` メソッドを使って別のワークフロー内のステップとして直接利用できます。 ```typescript import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; // Create a nested workflow const nestedWorkflow = new LegacyWorkflow({ name: "nested-workflow" }) .step(stepA) .then(stepB) .commit(); // Use the nested workflow in a parent workflow const parentWorkflow = new LegacyWorkflow({ name: "parent-workflow" }) .step(nestedWorkflow, { variables: { city: { step: "trigger", path: "myTriggerInput", }, }, }) .then(stepC) .commit(); ``` ワークフローをステップとして使用する場合: - ワークフローは自動的に、そのワークフロー名をステップIDとして持つステップに変換されます - ワークフローの結果は親ワークフローのコンテキストで利用可能です - ネストされたワークフローの各ステップは、定義された順序で実行されます ## 結果へのアクセス ネストされたワークフローの結果は、親ワークフローのコンテキスト内でネストされたワークフローの名前の下に格納されています。結果には、ネストされたワークフロー内のすべてのステップの出力が含まれます。 ```typescript const { results } = await parentWorkflow.start(); // Access nested workflow results const nestedWorkflowResult = results["nested-workflow"]; if (nestedWorkflowResult.status === "success") { const nestedResults = nestedWorkflowResult.output.results; } ``` ## ネストされたワークフローによるフロー制御 ネストされたワークフローは、通常のステップで利用可能なすべてのフロー制御機能をサポートしています: ### 並列実行 複数のネストされたワークフローを並列で実行できます: ```typescript parentWorkflow .step(nestedWorkflowA) .step(nestedWorkflowB) .after([nestedWorkflowA, nestedWorkflowB]) .step(finalStep); ``` または、ワークフローの配列を使用して`step()`を使用する方法: ```typescript parentWorkflow.step([nestedWorkflowA, nestedWorkflowB]).then(finalStep); ``` この場合、`then()`は最終ステップを実行する前に、すべてのワークフローが完了するのを暗黙的に待ちます。 ### If-Else分岐 ネストされたワークフローは、両方の分岐を引数として受け入れる新しい構文でif-else分岐で使用できます: ```typescript // Create nested workflows for different paths const workflowA = new LegacyWorkflow({ name: "workflow-a" }) .step(stepA1) .then(stepA2) .commit(); const workflowB = new LegacyWorkflow({ name: "workflow-b" }) .step(stepB1) .then(stepB2) .commit(); // Use the new if-else syntax with nested workflows parentWorkflow .step(initialStep) .if( async ({ context }) => { // Your condition here return someCondition; }, workflowA, // if branch workflowB, // else branch ) .then(finalStep) .commit(); ``` 新しい構文は、ネストされたワークフローを扱う際により簡潔で明確です。条件が: - `true`の場合:最初のワークフロー(if分岐)が実行されます - `false`の場合:2番目のワークフロー(else分岐)が実行されます スキップされたワークフローは結果で`skipped`のステータスになります: if-elseブロックの後に続く`.then(finalStep)`呼び出しは、ifとelse分岐を単一の実行パスに戻します。 ### ループ処理 ネストされたワークフローは、他のステップと同様に`.until()`と`.while()`ループを使用できます。興味深い新しいパターンの一つは、ワークフローを直接ループバック引数として渡し、その結果について何かが真になるまでそのネストされたワークフローを実行し続けることです: ```typescript parentWorkflow .step(firstStep) .while( ({ context }) => context.getStepResult("nested-workflow").output.results.someField === "someValue", nestedWorkflow, ) .step(finalStep) .commit(); ``` ## ネストされたワークフローの監視 親ワークフローの `watch` メソッドを使用して、ネストされたワークフローの状態変化を監視できます。これは、複雑なワークフローの進行状況や状態遷移をモニタリングするのに便利です。 ```typescript const parentWorkflow = new LegacyWorkflow({ name: "parent-workflow" }) .step([nestedWorkflowA, nestedWorkflowB]) .then(finalStep) .commit(); const run = parentWorkflow.createRun(); const unwatch = parentWorkflow.watch((state) => { console.log("Current state:", state.value); // Access nested workflow states in state.context }); await run.start(); unwatch(); // Stop watching when done ``` ## 一時停止と再開 ネストされたワークフローは一時停止と再開をサポートしており、特定のポイントでワークフロー実行を一時停止して続行することができます。ネストされたワークフロー全体または特定のステップを一時停止することができます: ```typescript // Define a step that may need to suspend const suspendableStep = new LegacyStep({ id: "other", description: "Step that may need to suspend", execute: async ({ context, suspend }) => { if (!wasSuspended) { wasSuspended = true; await suspend(); } return { other: 26 }; }, }); // Create a nested workflow with suspendable steps const nestedWorkflow = new LegacyWorkflow({ name: "nested-workflow-a" }) .step(startStep) .then(suspendableStep) .then(finalStep) .commit(); // Use in parent workflow const parentWorkflow = new LegacyWorkflow({ name: "parent-workflow" }) .step(beginStep) .then(nestedWorkflow) .then(lastStep) .commit(); // Start the workflow const run = parentWorkflow.createRun(); const { runId, results } = await run.start({ triggerData: { startValue: 1 } }); // Check if a specific step in the nested workflow is suspended if (results["nested-workflow-a"].output.results.other.status === "suspended") { // Resume the specific suspended step using dot notation const resumedResults = await run.resume({ stepId: "nested-workflow-a.other", context: { startValue: 1 }, }); // The resumed results will contain the completed nested workflow expect(resumedResults.results["nested-workflow-a"].output.results).toEqual({ start: { output: { newValue: 1 }, status: "success" }, other: { output: { other: 26 }, status: "success" }, final: { output: { finalValue: 27 }, status: "success" }, }); } ``` ネストされたワークフローを再開する場合: - `resume()`を呼び出す際に、ワークフロー全体を再開するには、ネストされたワークフローの名前を`stepId`として使用します - ネストされたワークフロー内の特定のステップを再開するには、ドット表記(`nested-workflow.step-name`)を使用します - ネストされたワークフローは、提供されたコンテキストで一時停止されたステップから続行されます - ネストされたワークフローの結果内の特定のステップのステータスを`results["nested-workflow"].output.results`を使用して確認できます ## 結果スキーマとマッピング ネストされたワークフローは、結果スキーマとマッピングを定義することができ、これにより型安全性やデータ変換が容易になります。これは、ネストされたワークフローの出力が特定の構造に一致することを保証したい場合や、親ワークフローで使用する前に結果を変換する必要がある場合に特に便利です。 ```typescript // Create a nested workflow with result schema and mapping const nestedWorkflow = new LegacyWorkflow({ name: "nested-workflow", result: { schema: z.object({ total: z.number(), items: z.array( z.object({ id: z.string(), value: z.number(), }), ), }), mapping: { // Map values from step results using variables syntax total: { step: "step-a", path: "count" }, items: { step: "step-b", path: "items" }, }, }, }) .step(stepA) .then(stepB) .commit(); // Use in parent workflow with type-safe results const parentWorkflow = new LegacyWorkflow({ name: "parent-workflow" }) .step(nestedWorkflow) .then(async ({ context }) => { const result = context.getStepResult("nested-workflow"); // TypeScript knows the structure of result console.log(result.total); // number console.log(result.items); // Array<{ id: string, value: number }> return { success: true }; }) .commit(); ``` ## ベストプラクティス 1. **モジュール化**: 関連するステップをカプセル化し、再利用可能なワークフローコンポーネントを作成するためにネストされたワークフローを活用しましょう。 2. **命名**: ネストされたワークフローには分かりやすい名前を付けてください。これらは親ワークフロー内でステップIDとして使用されます。 3. **エラー処理**: ネストされたワークフローのエラーは親ワークフローに伝播されるため、適切にエラー処理を行いましょう。 4. **状態管理**: 各ネストされたワークフローは独自の状態を保持しますが、親ワークフローのコンテキストにもアクセスできます。 5. **サスペンション**: ネストされたワークフローでサスペンションを使用する場合、ワークフロー全体の状態を考慮し、再開処理を適切に行いましょう。 ## 例 こちらは、ネストされたワークフローのさまざまな機能を示す完全な例です。 ```typescript const workflowA = new LegacyWorkflow({ name: "workflow-a", result: { schema: z.object({ activities: z.string(), }), mapping: { activities: { step: planActivities, path: "activities", }, }, }, }) .step(fetchWeather) .then(planActivities) .commit(); const workflowB = new LegacyWorkflow({ name: "workflow-b", result: { schema: z.object({ activities: z.string(), }), mapping: { activities: { step: planActivities, path: "activities", }, }, }, }) .step(fetchWeather) .then(planActivities) .commit(); const weatherWorkflow = new LegacyWorkflow({ name: "weather-workflow", triggerSchema: z.object({ cityA: z.string().describe("The city to get the weather for"), cityB: z.string().describe("The city to get the weather for"), }), result: { schema: z.object({ activitiesA: z.string(), activitiesB: z.string(), }), mapping: { activitiesA: { step: workflowA, path: "result.activities", }, activitiesB: { step: workflowB, path: "result.activities", }, }, }, }) .step(workflowA, { variables: { city: { step: "trigger", path: "cityA", }, }, }) .step(workflowB, { variables: { city: { step: "trigger", path: "cityB", }, }, }); weatherWorkflow.commit(); ``` この例では: 1. すべてのワークフローで型安全性を確保するためにスキーマを定義しています 2. 各ステップには適切な入力および出力スキーマがあります 3. ネストされたワークフローにはそれぞれ独自のトリガースキーマと結果マッピングがあります 4. `.step()` 呼び出しの中で変数構文を使ってデータを受け渡しています 5. メインのワークフローが、両方のネストされたワークフローからデータを統合します --- title: "複雑なLLM操作の処理 | ワークフロー(レガシー) | Mastra" description: "Mastraのワークフローは、分岐、並列実行、リソースの一時停止などの機能を活用し、複雑な一連の操作をオーケストレーションするのに役立ちます。" --- # ワークフローを使用した複雑なLLM操作の処理(レガシー) [JA] Source: https://mastra.ai/ja/docs/workflows-legacy/overview Mastraのワークフローは、分岐、並列実行、リソースの一時停止などの機能を備えた複雑な操作シーケンスをオーケストレーションするのに役立ちます。 ## ワークフローを使用するタイミング ほとんどのAIアプリケーションは、言語モデルへの単一の呼び出し以上のものを必要とします。複数のステップを実行したり、条件によって特定のパスをスキップしたり、ユーザー入力を受け取るまで実行を完全に一時停止したりすることが必要な場合があります。エージェントのツール呼び出しが十分に正確でない場合もあります。 Mastraのワークフローシステムは以下を提供します: - ステップを定義し、それらを連携させる標準化された方法。 - シンプル(線形)と高度(分岐、並列)の両方のパスをサポート。 - 各ワークフロー実行を追跡するためのデバッグと可観測性機能。 ## 例 ワークフローを作成するには、1つ以上のステップを定義し、それらをリンクし、ワークフローをコミットしてから開始します。 ### ワークフローの分解(レガシー) ワークフロー作成プロセスの各部分を見ていきましょう。 #### 1. ワークフローの作成 Mastraでワークフローを定義する方法は次のとおりです。`name` フィールドはワークフローのAPIエンドポイント(`/workflows/$NAME/`)を決定し、`triggerSchema` はワークフローのトリガーデータの構造を定義します。 ```ts filename="src/mastra/workflow/index.ts" import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; const myWorkflow = new LegacyWorkflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); ``` #### 2. ステップの定義 次に、ワークフローの各ステップを定義します。各ステップは独自の入力・出力スキーマを持つことができます。ここでは、`stepOne` が入力値を2倍にし、`stepTwo` は `stepOne` が成功した場合にその結果をインクリメントします。(シンプルにするため、この例ではLLM呼び出しは行っていません) ```ts filename="src/mastra/workflow/index.ts" const stepOne = new LegacyStep({ id: "stepOne", outputSchema: z.object({ doubledValue: z.number(), }), execute: async ({ context }) => { const doubledValue = context.triggerData.inputValue * 2; return { doubledValue }; }, }); const stepTwo = new LegacyStep({ id: "stepTwo", execute: async ({ context }) => { const doubledValue = context.getStepResult(stepOne)?.doubledValue; if (!doubledValue) { return { incrementedValue: 0 }; } return { incrementedValue: doubledValue + 1, }; }, }); ``` #### 3. ステップのリンク 次に、制御フローを作成し、「コミット」(ワークフローの確定)を行います。この場合、`stepOne` が最初に実行され、その後に `stepTwo` が続きます。 ```ts filename="src/mastra/workflow/index.ts" myWorkflow.step(stepOne).then(stepTwo).commit(); ``` ### ワークフローの登録 Mastraにワークフローを登録して、ログ記録やテレメトリーを有効にします。 ```ts showLineNumbers filename="src/mastra/index.ts" import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ legacy_workflows: { myWorkflow }, }); ``` 動的なワークフローを作成する必要がある場合は、mastraインスタンスをコンテキストに注入することもできます。 ```ts filename="src/mastra/workflow/index.ts" import { Mastra } from "@mastra/core"; import { LegacyWorkflow } from "@mastra/core/workflows/legacy"; const mastra = new Mastra(); const myWorkflow = new LegacyWorkflow({ name: "my-workflow", mastra, }); ``` ### ワークフローの実行 ワークフローはプログラムから、またはAPI経由で実行できます。 ```ts showLineNumbers filename="src/mastra/run-workflow.ts" copy import { mastra } from "./index"; // Get the workflow const myWorkflow = mastra.legacy_getWorkflow("myWorkflow"); const { runId, start } = myWorkflow.createRun(); // Start the workflow execution await start({ triggerData: { inputValue: 45 } }); ``` またはAPIを使用します(`mastra dev` の実行が必要です)。 // ワークフローランの作成 ```bash curl --location 'http://localhost:4111/api/workflows/myWorkflow/start-async' \ --header 'Content-Type: application/json' \ --data '{ "inputValue": 45 }' ``` この例では、基本的な流れを示しています:ワークフローを定義し、ステップを追加し、ワークフローをコミットし、そして実行します。 ## ステップの定義 ワークフローの基本的な構成要素は[ステップです](./steps.mdx)。ステップは入力と出力のスキーマを使って定義され、前のステップの結果を取得することができます。 ## 制御フロー ワークフローでは、[制御フロー](./control-flow.mdx)を定義して、並列ステップ、分岐パスなどを使用してステップを連鎖させることができます。 ## ワークフローの変数 ステップ間でデータをマッピングしたり、動的なデータフローを作成したりする必要がある場合、[ワークフロー変数](./variables.mdx)は、あるステップから別のステップへ情報を渡したり、ステップ出力内のネストされたプロパティにアクセスしたりするための強力なメカニズムを提供します。 ## 一時停止と再開 実行を外部データ、ユーザー入力、または非同期イベントのために一時停止する必要がある場合、Mastraは[任意のステップでの一時停止をサポート](./suspend-and-resume.mdx)しており、ワークフローの状態を保持して後で再開できるようにします。 ## 可観測性とデバッグ Mastraワークフローは自動的に[ワークフロー実行内の各ステップの入力と出力をログに記録](../../reference/observability/otel-config.mdx)し、このデータを好みのロギング、テレメトリ、または可観測性ツールに送信できるようにします。 以下のことが可能です: - 各ステップのステータス(例:`success`、`error`、または`suspended`)を追跡する。 - 分析のための実行固有のメタデータを保存する。 - ログを転送することで、DatadogやNew Relicなどのサードパーティの可観測性プラットフォームと統合する。 ## その他のリソース - [連続ステップワークフローの例](../../examples/workflows_legacy/sequential-steps.mdx) - [並列ステップワークフローの例](../../examples/workflows_legacy/parallel-steps.mdx) - [分岐パスワークフローの例](../../examples/workflows_legacy/branching-paths.mdx) - [ワークフロー変数の例](../../examples/workflows_legacy/workflow-variables.mdx) - [循環依存ワークフローの例](../../examples/workflows_legacy/cyclical-dependencies.mdx) - [一時停止と再開ワークフローの例](../../examples/workflows_legacy/suspend-and-resume.mdx) --- title: "ランタイム変数 - 依存性注入 | Workflows(レガシー) | Mastra ドキュメント" description: Mastra の依存性注入システムを使用して、ワークフローやステップにランタイム設定を提供する方法を学びます。 --- # ワークフローランタイム変数(レガシー) [JA] Source: https://mastra.ai/ja/docs/workflows-legacy/runtime-variables Mastraは、ランタイム変数を使用してワークフローとステップを設定できる強力な依存性注入システムを提供しています。この機能は、ランタイム構成に基づいて動作を適応できる柔軟で再利用可能なワークフローを作成するために不可欠です。 ## 概要 依存性注入システムにより、以下のことが可能になります: 1. 型安全なruntimeContextを通じてランタイム設定変数をワークフローに渡す 2. ステップ実行コンテキスト内でこれらの変数にアクセスする 3. 基盤となるコードを変更せずにワークフローの動作を変更する 4. 同じワークフロー内の複数のステップ間で設定を共有する ## 基本的な使用方法 ```typescript const myWorkflow = mastra.legacy_getWorkflow("myWorkflow"); const { runId, start, resume } = myWorkflow.createRun(); // Define your runtimeContext's type structure type WorkflowRuntimeContext = { multiplier: number; }; const runtimeContext = new RuntimeContext(); runtimeContext.set("multiplier", 5); // Start the workflow execution with runtimeContext await start({ triggerData: { inputValue: 45 }, runtimeContext, }); ``` ## REST APIでの使用 HTTPヘッダーから乗数値を動的に設定する方法は次のとおりです: ```typescript filename="src/index.ts" import { Mastra } from "@mastra/core"; import { RuntimeContext } from "@mastra/core/di"; import { workflow as myWorkflow } from "./workflows"; // Define runtimeContext type with clear, descriptive types type WorkflowRuntimeContext = { multiplier: number; }; export const mastra = new Mastra({ legacy_workflows: { myWorkflow, }, server: { middleware: [ async (c, next) => { const multiplier = c.req.header("x-multiplier"); const runtimeContext = c.get("runtimeContext"); // Parse and validate the multiplier value const multiplierValue = parseInt(multiplier || "1", 10); if (isNaN(multiplierValue)) { throw new Error("Invalid multiplier value"); } runtimeContext.set("multiplier", multiplierValue); await next(); // Don't forget to call next() }, ], }, }); ``` ## 変数を使用したステップの作成 ステップはruntimeContext変数にアクセスでき、ワークフローのruntimeContextタイプに準拠する必要があります: ```typescript import { LegacyStep } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Define step input/output types interface StepInput { inputValue: number; } interface StepOutput { incrementedValue: number; } const stepOne = new LegacyStep({ id: "stepOne", description: "Multiply the input value by the configured multiplier", execute: async ({ context, runtimeContext }) => { try { // Type-safe access to runtimeContext variables const multiplier = runtimeContext.get("multiplier"); if (multiplier === undefined) { throw new Error("Multiplier not configured in runtimeContext"); } // Get and validate input const inputValue = context.getStepResult("trigger")?.inputValue; if (inputValue === undefined) { throw new Error("Input value not provided"); } const result: StepOutput = { incrementedValue: inputValue * multiplier, }; return result; } catch (error) { console.error(`Error in stepOne: ${error.message}`); throw error; } }, }); ``` ## エラー処理 ワークフローでランタイム変数を使用する際には、潜在的なエラーを処理することが重要です: 1. **変数の欠落**: runtimeContextに必要な変数が存在するかを常に確認する 2. **型の不一致**: TypeScriptの型システムを使用してコンパイル時に型エラーを捕捉する 3. **無効な値**: ステップで使用する前に変数の値を検証する ```typescript // runtimeContext変数を使用した防御的プログラミングの例 const multiplier = runtimeContext.get("multiplier"); if (multiplier === undefined) { throw new Error("Multiplier not configured in runtimeContext"); } // 型と値の検証 if (typeof multiplier !== "number" || multiplier <= 0) { throw new Error(`Invalid multiplier value: ${multiplier}`); } ``` ## ベストプラクティス 1. **型安全性**: runtimeContextやステップの入力/出力には必ず適切な型を定義してください 2. **バリデーション**: すべての入力値とruntimeContext変数を使用前に検証してください 3. **エラーハンドリング**: 各ステップで適切なエラーハンドリングを実装してください 4. **ドキュメント化**: 各ワークフローで想定されるruntimeContext変数を文書化してください 5. **デフォルト値**: 可能な場合は妥当なデフォルト値を設定してください --- title: "ステップの作成とワークフローへの追加(レガシー) | Mastra ドキュメント" description: "Mastra のワークフローにおけるステップは、入力、出力、実行ロジックを定義することで、業務を体系的に管理する方法を提供します。" --- # ワークフロー内のステップの定義(レガシー) [JA] Source: https://mastra.ai/ja/docs/workflows-legacy/steps ワークフローを構築する際には、通常、操作をより小さなタスクに分割し、それらを連携させて再利用できるようにします。ステップは、入力、出力、および実行ロジックを定義することで、これらのタスクを体系的に管理する方法を提供します。 以下のコードは、これらのステップをインラインまたは個別に定義する方法を示しています。 ## インラインステップの作成 `.step()` と `.then()` を使って、ワークフロー内で直接ステップを作成できます。以下のコードは、2つのステップを順番に定義し、リンクし、実行する方法を示しています。 ```typescript showLineNumbers filename="src/mastra/workflows/index.ts" copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; export const myWorkflow = new LegacyWorkflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); myWorkflow .step( new LegacyStep({ id: "stepOne", outputSchema: z.object({ doubledValue: z.number(), }), execute: async ({ context }) => ({ doubledValue: context.triggerData.inputValue * 2, }), }), ) .then( new LegacyStep({ id: "stepTwo", outputSchema: z.object({ incrementedValue: z.number(), }), execute: async ({ context }) => { if (context.steps.stepOne.status !== "success") { return { incrementedValue: 0 }; } return { incrementedValue: context.steps.stepOne.output.doubledValue + 1, }; }, }), ) .commit(); // Register the workflow with Mastra export const mastra = new Mastra({ legacy_workflows: { myWorkflow }, }); ``` ## ステップを個別に作成する ステップのロジックを別々のエンティティで管理したい場合は、ステップを外部で定義し、その後ワークフローに追加することができます。以下のコードは、ステップを独立して定義し、後からリンクする方法を示しています。 ```typescript showLineNumbers filename="src/mastra/workflows/index.ts" copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Define steps separately const stepOne = new LegacyStep({ id: "stepOne", outputSchema: z.object({ doubledValue: z.number(), }), execute: async ({ context }) => ({ doubledValue: context.triggerData.inputValue * 2, }), }); const stepTwo = new LegacyStep({ id: "stepTwo", outputSchema: z.object({ incrementedValue: z.number(), }), execute: async ({ context }) => { if (context.steps.stepOne.status !== "success") { return { incrementedValue: 0 }; } return { incrementedValue: context.steps.stepOne.output.doubledValue + 1 }; }, }); // Build the workflow const myWorkflow = new LegacyWorkflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); myWorkflow.step(stepOne).then(stepTwo); myWorkflow.commit(); // Register the workflow with Mastra export const mastra = new Mastra({ legacy_workflows: { myWorkflow }, }); ``` --- title: "ワークフローの一時停止と再開(レガシー) | Human-in-the-Loop | Mastra ドキュメント" description: "Mastra のワークフローにおける一時停止と再開機能は、外部からの入力やリソースを待つ間に実行を一時停止することを可能にします。" --- # ワークフローにおけるサスペンドとレジューム(レガシー) [JA] Source: https://mastra.ai/ja/docs/workflows-legacy/suspend-and-resume 複雑なワークフローでは、外部からの入力やリソースを待つ間に実行を一時停止する必要がよくあります。 Mastra のサスペンドとレジューム機能を使うことで、ワークフローの実行を任意のステップで一時停止し、ワークフローのスナップショットをストレージに保存し、準備ができたら保存されたスナップショットから実行を再開できます。 この一連のプロセスはすべて Mastra によって自動的に管理されます。設定やユーザーによる手動操作は必要ありません。 ワークフローのスナップショットをストレージ(デフォルトでは LibSQL)に保存することで、ワークフローの状態はセッション、デプロイ、サーバーの再起動をまたいで永続的に保持されます。この永続性は、外部からの入力やリソースを待つ間に数分、数時間、あるいは数日間サスペンドされたままになる可能性があるワークフローにとって非常に重要です。 ## サスペンド/レジュームを使用するタイミング ワークフローをサスペンドする一般的なシナリオには、以下が含まれます。 - 人による承認や入力を待つ場合 - 外部APIリソースが利用可能になるまで一時停止する場合 - 後続のステップで必要となる追加データを収集する場合 - 高コストな処理のレート制限やスロットリングを行う場合 - 外部トリガーによるイベント駆動型プロセスを処理する場合 ## 基本的なサスペンドの例 こちらは、値が低すぎる場合にサスペンドし、より高い値が与えられたときに再開するシンプルなワークフローです: ```typescript import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; const stepTwo = new LegacyStep({ id: "stepTwo", outputSchema: z.object({ incrementedValue: z.number(), }), execute: async ({ context, suspend }) => { if (context.steps.stepOne.status !== "success") { return { incrementedValue: 0 }; } const currentValue = context.steps.stepOne.output.doubledValue; if (currentValue < 100) { await suspend(); return { incrementedValue: 0 }; } return { incrementedValue: currentValue + 1 }; }, }); ``` ## Async/Await ベースのフロー Mastra のサスペンドとレジュームの仕組みは、async/await パターンを利用しており、サスペンドポイントを含む複雑なワークフローの実装を直感的に行うことができます。コード構造は実行フローを自然に反映します。 ### 仕組み 1. ステップの実行関数は、パラメータとして `suspend` 関数を受け取ります 2. `await suspend()` を呼び出すと、その時点でワークフローが一時停止します 3. ワークフローの状態が永続化されます 4. 後で、適切なパラメータで `workflow.resume()` を呼び出すことでワークフローを再開できます 5. 実行は `suspend()` 呼び出しの後のポイントから続行されます ### 複数のサスペンドポイントを持つ例 複数のステップでサスペンド可能なワークフローの例を示します: ```typescript // Define steps with suspend capability const promptAgentStep = new LegacyStep({ id: "promptAgent", execute: async ({ context, suspend }) => { // Some condition that determines if we need to suspend if (needHumanInput) { // Optionally pass payload data that will be stored with suspended state await suspend({ requestReason: "Need human input for prompt" }); // Code after suspend() will execute when the step is resumed return { modelOutput: context.userInput }; } return { modelOutput: "AI generated output" }; }, outputSchema: z.object({ modelOutput: z.string() }), }); const improveResponseStep = new LegacyStep({ id: "improveResponse", execute: async ({ context, suspend }) => { // Another condition for suspension if (needFurtherRefinement) { await suspend(); return { improvedOutput: context.refinedOutput }; } return { improvedOutput: "Improved output" }; }, outputSchema: z.object({ improvedOutput: z.string() }), }); // Build the workflow const workflow = new LegacyWorkflow({ name: "multi-suspend-workflow", triggerSchema: z.object({ input: z.string() }), }); workflow .step(getUserInput) .then(promptAgentStep) .then(evaluateTone) .then(improveResponseStep) .then(evaluateImproved) .commit(); // Register the workflow with Mastra export const mastra = new Mastra({ legacy_workflows: { workflow }, }); ``` ### ワークフローの開始と再開 ```typescript // Get the workflow and create a run const wf = mastra.legacy_getWorkflow("multi-suspend-workflow"); const run = wf.createRun(); // Start the workflow const initialResult = await run.start({ triggerData: { input: "initial input" }, }); let promptAgentStepResult = initialResult.activePaths.get("promptAgent"); let promptAgentResumeResult = undefined; // Check if a step is suspended if (promptAgentStepResult?.status === "suspended") { console.log("Workflow suspended at promptAgent step"); // Resume the workflow with new context const resumeResult = await run.resume({ stepId: "promptAgent", context: { userInput: "Human provided input" }, }); promptAgentResumeResult = resumeResult; } const improveResponseStepResult = promptAgentResumeResult?.activePaths.get("improveResponse"); if (improveResponseStepResult?.status === "suspended") { console.log("Workflow suspended at improveResponse step"); // Resume again with different context const finalResult = await run.resume({ stepId: "improveResponse", context: { refinedOutput: "Human refined output" }, }); console.log("Workflow completed:", finalResult?.results); } ``` ## イベントベースの一時停止と再開 手動でステップを一時停止する方法に加えて、Mastra では `afterEvent` メソッドを使ったイベントベースの一時停止が提供されています。これにより、ワークフローは特定のイベントが発生するまで自動的に一時停止し、発生後に処理を再開できます。 ### afterEvent と resumeWithEvent の使い方 `afterEvent` メソッドは、ワークフロー内に特定のイベントが発生するのを待つ一時停止ポイントを自動的に作成します。イベントが発生した際には、`resumeWithEvent` を使ってイベントデータとともにワークフローを再開できます。 仕組みは以下の通りです: 1. ワークフロー設定でイベントを定義する 2. `afterEvent` を使ってそのイベントを待つ一時停止ポイントを作成する 3. イベントが発生したら、イベント名とデータを指定して `resumeWithEvent` を呼び出す ### 例:イベントベースのワークフロー ```typescript // Define steps const getUserInput = new LegacyStep({ id: "getUserInput", execute: async () => ({ userInput: "initial input" }), outputSchema: z.object({ userInput: z.string() }), }); const processApproval = new LegacyStep({ id: "processApproval", execute: async ({ context }) => { // Access the event data from the context const approvalData = context.inputData?.resumedEvent; return { approved: approvalData?.approved, approvedBy: approvalData?.approverName, }; }, outputSchema: z.object({ approved: z.boolean(), approvedBy: z.string(), }), }); // Create workflow with event definition const approvalWorkflow = new LegacyWorkflow({ name: "approval-workflow", triggerSchema: z.object({ requestId: z.string() }), events: { approvalReceived: { schema: z.object({ approved: z.boolean(), approverName: z.string(), }), }, }, }); // Build workflow with event-based suspension approvalWorkflow .step(getUserInput) .afterEvent("approvalReceived") // Workflow will automatically suspend here .step(processApproval) // This step runs after the event is received .commit(); ``` ### イベントベースのワークフローの実行 ```typescript // Get the workflow const workflow = mastra.legacy_getWorkflow("approval-workflow"); const run = workflow.createRun(); // Start the workflow const initialResult = await run.start({ triggerData: { requestId: "request-123" }, }); console.log("Workflow started, waiting for approval event"); console.log(initialResult.results); // Output will show the workflow is suspended at the event step: // { // getUserInput: { status: 'success', output: { userInput: 'initial input' } }, // __approvalReceived_event: { status: 'suspended' } // } // Later, when the approval event occurs: const resumeResult = await run.resumeWithEvent("approvalReceived", { approved: true, approverName: "Jane Doe", }); console.log("Workflow resumed with event data:", resumeResult.results); // Output will show the completed workflow: // { // getUserInput: { status: 'success', output: { userInput: 'initial input' } }, // __approvalReceived_event: { status: 'success', output: { executed: true, resumedEvent: { approved: true, approverName: 'Jane Doe' } } }, // processApproval: { status: 'success', output: { approved: true, approvedBy: 'Jane Doe' } } // } ``` ### イベントベースワークフローの重要ポイント - `suspend()` 関数は、オプションで一時停止状態とともに保存されるペイロードオブジェクトを受け取ることができます - `await suspend()` 呼び出しの後のコードは、ステップが再開されるまで実行されません - ステップが一時停止されると、そのステータスはワークフロー結果で `'suspended'` になります - 再開時には、ステップのステータスは `'suspended'` から `'success'` に変わります - `resume()` メソッドは、どの一時停止中のステップを再開するかを特定するために `stepId` が必要です - 再開時に新しいコンテキストデータを渡すことができ、既存のステップ結果とマージされます - イベントはワークフロー設定でスキーマとともに定義する必要があります - `afterEvent` メソッドは、そのイベントを待つ特別な一時停止ステップを作成します - イベントステップは自動的に `__eventName_event`(例:`__approvalReceived_event`)という名前になります - `resumeWithEvent` を使ってイベントデータを渡し、ワークフローを継続します - イベントデータは、そのイベント用に定義されたスキーマで検証されます - イベントデータはコンテキスト内の `inputData.resumedEvent` として利用できます ## サスペンドとレジュームのためのストレージ ワークフローが `await suspend()` を使ってサスペンドされると、Mastra はワークフローの全状態を自動的にストレージへ永続化します。これは、ワークフローが長期間サスペンドされたままになる可能性がある場合に重要であり、アプリケーションの再起動やサーバーインスタンスをまたいでも状態が保持されることを保証します。 ### デフォルトストレージ: LibSQL デフォルトでは、Mastra は LibSQL をストレージエンジンとして使用します: ```typescript import { Mastra } from "@mastra/core/mastra"; import { LibSQLStore } from "@mastra/libsql"; const mastra = new Mastra({ storage: new LibSQLStore({ url: "file:./storage.db", // 開発用のローカルファイルベースデータベース // 本番環境では永続的なURLを使用してください: // url: process.env.DATABASE_URL, // authToken: process.env.DATABASE_AUTH_TOKEN, // 認証接続の場合はオプション }), }); ``` LibSQL ストレージはさまざまなモードで設定できます: - インメモリデータベース(テスト用): `:memory:` - ファイルベースデータベース(開発用): `file:storage.db` - リモートデータベース(本番用): `libsql://your-database.turso.io` のようなURL ### 代替ストレージオプション #### Upstash(Redis互換) サーバーレスアプリケーションや Redis を好む環境向け: ```bash copy npm install @mastra/upstash@latest ``` ```typescript import { Mastra } from "@mastra/core/mastra"; import { UpstashStore } from "@mastra/upstash"; const mastra = new Mastra({ storage: new UpstashStore({ url: process.env.UPSTASH_URL, token: process.env.UPSTASH_TOKEN, }), }); ``` ### ストレージに関する注意点 - すべてのストレージオプションは、サスペンドとレジュームの機能を同じようにサポートします - ワークフローの状態はサスペンド時に自動的にシリアライズされ保存されます - サスペンド/レジュームがストレージで動作するために追加の設定は不要です - インフラ、スケーリングの必要性、既存の技術スタックに基づいてストレージオプションを選択してください ## 監視と再開 一時停止されたワークフローを処理するには、`watch` メソッドを使用して各実行ごとにワークフローのステータスを監視し、`resume` で実行を再開します。 ```typescript import { mastra } from "./index"; // Get the workflow const myWorkflow = mastra.legacy_getWorkflow("myWorkflow"); const { start, watch, resume } = myWorkflow.createRun(); // Start watching the workflow before executing it watch(async ({ activePaths }) => { const isStepTwoSuspended = activePaths.get("stepTwo")?.status === "suspended"; if (isStepTwoSuspended) { console.log("Workflow suspended, resuming with new value"); // Resume the workflow with new context await resume({ stepId: "stepTwo", context: { secondValue: 100 }, }); } }); // Start the workflow execution await start({ triggerData: { inputValue: 45 } }); ``` ### イベントベースのワークフローの監視と再開 同じ監視パターンをイベントベースのワークフローでも利用できます。 ```typescript const { start, watch, resumeWithEvent } = workflow.createRun(); // Watch for suspended event steps watch(async ({ activePaths }) => { const isApprovalReceivedSuspended = activePaths.get("__approvalReceived_event")?.status === "suspended"; if (isApprovalReceivedSuspended) { console.log("Workflow waiting for approval event"); // In a real scenario, you would wait for the actual event to occur // For example, this could be triggered by a webhook or user interaction setTimeout(async () => { await resumeWithEvent("approvalReceived", { approved: true, approverName: "Auto Approver", }); }, 5000); // Simulate event after 5 seconds } }); // Start the workflow await start({ triggerData: { requestId: "auto-123" } }); ``` ## 参考文献 サスペンドとレジュームの仕組みについてより深く理解するには: - [Mastra ワークフローにおけるスナップショットの理解](../../reference/legacyWorkflows/snapshots.mdx) - サスペンドとレジューム機能を支えるスナップショットメカニズムについて学ぶ - [ステップ設定ガイド](./steps.mdx) - ワークフローでのステップ設定についてさらに学ぶ - [制御フローガイド](./control-flow.mdx) - 高度なワークフロー制御パターン - [イベント駆動型ワークフロー](../../reference/legacyWorkflows/events.mdx) - イベントベースのワークフローに関する詳細なリファレンス ## 関連リソース - 完全な動作例については、[Suspend and Resume Example](../../examples/workflows_legacy/suspend-and-resume.mdx) をご覧ください - suspend/resume API の詳細については、[Step Class Reference](../../reference/legacyWorkflows/step-class.mdx) をご確認ください - サスペンドされたワークフローの監視については、[Workflow Observability](../../reference/observability/otel-config.mdx) をご参照ください --- title: "ワークフロー(レガシー)変数によるデータマッピング | Mastra ドキュメント" description: "ワークフロー変数を使用してステップ間でデータをマッピングし、Mastra ワークフローで動的なデータフローを作成する方法を学びます。" --- # ワークフロー変数によるデータマッピング [JA] Source: https://mastra.ai/ja/docs/workflows-legacy/variables Mastraのワークフロー変数は、ステップ間でデータをマッピングするための強力な仕組みを提供し、動的なデータフローの作成や、あるステップから別のステップへ情報を渡すことができます。 ## ワークフロー変数の理解 Mastra のワークフローでは、変数は次のような目的で使用されます: - トリガー入力からステップ入力へのデータのマッピング - あるステップの出力を別のステップの入力へ渡す - ステップ出力内のネストされたプロパティへアクセスする - より柔軟で再利用可能なワークフローステップを作成する ## データマッピングのための変数の使用 ### 基本的な変数マッピング ワークフローにステップを追加する際、`variables` プロパティを使ってステップ間でデータをマッピングできます。 ```typescript showLineNumbers filename="src/mastra/workflows/index.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; const workflow = new LegacyWorkflow({ name: "data-mapping-workflow", triggerSchema: z.object({ inputData: z.string(), }), }); workflow .step(step1, { variables: { // Map trigger data to step input inputData: { step: "trigger", path: "inputData" }, }, }) .then(step2, { variables: { // Map output from step1 to input for step2 previousValue: { step: step1, path: "outputField" }, }, }) .commit(); // Register the workflow with Mastra export const mastra = new Mastra({ legacy_workflows: { workflow }, }); ``` ### ネストされたプロパティへのアクセス `path` フィールドでドット記法を使うことで、ネストされたプロパティにアクセスできます。 ```typescript showLineNumbers filename="src/mastra/workflows/index.ts" copy workflow .step(step1) .then(step2, { variables: { // Access a nested property from step1's output nestedValue: { step: step1, path: "nested.deeply.value" }, }, }) .commit(); ``` ### オブジェクト全体のマッピング `path` に `.` を指定することで、オブジェクト全体をマッピングできます。 ```typescript showLineNumbers filename="src/mastra/workflows/index.ts" copy workflow .step(step1, { variables: { // Map the entire trigger data object triggerData: { step: "trigger", path: "." }, }, }) .commit(); ``` ### ループ内での変数の利用 変数は `while` や `until` ループにも渡すことができます。これは、イテレーション間や外部ステップからデータを受け渡す際に便利です。 ```typescript showLineNumbers filename="src/mastra/workflows/loop-variables.ts" copy // Step that increments a counter const incrementStep = new LegacyStep({ id: "increment", inputSchema: z.object({ // Previous value from last iteration prevValue: z.number().optional(), }), outputSchema: z.object({ // Updated counter value updatedCounter: z.number(), }), execute: async ({ context }) => { const { prevValue = 0 } = context.inputData; return { updatedCounter: prevValue + 1 }; }, }); const workflow = new LegacyWorkflow({ name: "counter", }); workflow.step(incrementStep).while( async ({ context }) => { // Continue while counter is less than 10 const result = context.getStepResult(incrementStep); return (result?.updatedCounter ?? 0) < 10; }, incrementStep, { // Pass previous value to next iteration prevValue: { step: incrementStep, path: "updatedCounter", }, }, ); ``` ## 変数の解決 ワークフローが実行されると、Mastra は実行時に変数を次の手順で解決します。 1. `step` プロパティで指定されたソースステップを特定する 2. そのステップから出力を取得する 3. `path` を使って指定されたプロパティに移動する 4. 解決された値をターゲットステップのコンテキスト内の `inputData` プロパティとして挿入する ## 例 ### トリガーデータからのマッピング この例では、ワークフロートリガーからステップへのデータのマッピング方法を示します。 ```typescript showLineNumbers filename="src/mastra/workflows/trigger-mapping.ts" copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Define a step that needs user input const processUserInput = new LegacyStep({ id: "processUserInput", execute: async ({ context }) => { // The inputData will be available in context because of the variable mapping const { inputData } = context.inputData; return { processedData: `Processed: ${inputData}`, }; }, }); // Create the workflow const workflow = new LegacyWorkflow({ name: "trigger-mapping", triggerSchema: z.object({ inputData: z.string(), }), }); // Map the trigger data to the step workflow .step(processUserInput, { variables: { inputData: { step: "trigger", path: "inputData" }, }, }) .commit(); // Register the workflow with Mastra export const mastra = new Mastra({ legacy_workflows: { workflow }, }); ``` ### ステップ間のマッピング この例では、あるステップから別のステップへのデータのマッピング方法を示します。 ```typescript showLineNumbers filename="src/mastra/workflows/step-mapping.ts" copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Step 1: Generate data const generateData = new LegacyStep({ id: "generateData", outputSchema: z.object({ nested: z.object({ value: z.string(), }), }), execute: async () => { return { nested: { value: "step1-data", }, }; }, }); // Step 2: Process the data from step 1 const processData = new LegacyStep({ id: "processData", inputSchema: z.object({ previousValue: z.string(), }), execute: async ({ context }) => { // previousValue will be available because of the variable mapping const { previousValue } = context.inputData; return { result: `Processed: ${previousValue}`, }; }, }); // Create the workflow const workflow = new LegacyWorkflow({ name: "step-mapping", }); // Map data from step1 to step2 workflow .step(generateData) .then(processData, { variables: { // Map the nested.value property from generateData's output previousValue: { step: generateData, path: "nested.value" }, }, }) .commit(); // Register the workflow with Mastra export const mastra = new Mastra({ legacy_workflows: { workflow }, }); ``` ## 型安全性 Mastraは、TypeScriptを使用する際に変数マッピングの型安全性を提供します。 ```typescript showLineNumbers filename="src/mastra/workflows/type-safe.ts" copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Define schemas for better type safety const triggerSchema = z.object({ inputValue: z.string(), }); type TriggerType = z.infer; // Step with typed context const step1 = new LegacyStep({ id: "step1", outputSchema: z.object({ nested: z.object({ value: z.string(), }), }), execute: async ({ context }) => { // TypeScript knows the shape of triggerData const triggerData = context.getStepResult("trigger"); return { nested: { value: `processed-${triggerData?.inputValue}`, }, }; }, }); // Create the workflow with the schema const workflow = new LegacyWorkflow({ name: "type-safe-workflow", triggerSchema, }); workflow.step(step1).commit(); // Register the workflow with Mastra export const mastra = new Mastra({ legacy_workflows: { workflow }, }); ``` ## ベストプラクティス 1. **入力と出力を検証する**: `inputSchema` と `outputSchema` を使用してデータの一貫性を確保しましょう。 2. **マッピングをシンプルに保つ**: 可能な限り、過度に複雑なネストされたパスは避けましょう。 3. **デフォルト値を考慮する**: マッピングされたデータが未定義の場合の対応を行いましょう。 ## 直接コンテキストアクセスとの比較 `context.steps` を使って前のステップの結果に直接アクセスすることもできますが、変数マッピングを使用することでいくつかの利点があります。 | 機能 | 変数マッピング | 直接コンテキストアクセス | | ----------- | ------------------------------------------- | ------------------------------- | | 明確さ | データ依存関係が明示的 | 依存関係が暗黙的 | | 再利用性 | ステップを異なるマッピングで再利用可能 | ステップが密接に結合されている | | 型安全性 | TypeScript との統合がより良い | 手動で型アサーションが必要 | --- title: "分岐、マージ、条件 | ワークフロー (vNext) | Mastra ドキュメント" description: "Mastra (vNext) ワークフローのフロー制御により、分岐、マージ、条件を管理して、ロジック要件を満たすワークフローを構築できます。" --- ## 順次フロー [JA] Source: https://mastra.ai/ja/docs/workflows-vnext/flow-control `.then()`を使用して、順番に実行するステップをチェーンします: ```typescript myWorkflow.then(step1).then(step2).then(step3).commit(); ``` 各ステップの出力は、スキーマが一致する場合、自動的に次のステップに渡されます。スキーマが一致しない場合は、`map`関数を使用して出力を期待されるスキーマに変換できます。 ステップのチェーンはタイプセーフであり、コンパイル時にチェックされます。 ## 並列実行 `.parallel()`を使用してステップを並列に実行します: ```typescript myWorkflow.parallel([step1, step2]).then(step3).commit(); ``` これにより配列内のすべてのステップが同時に実行され、すべての並列ステップが完了した後に次のステップに進みます。 ワークフロー全体を並列に実行することもできます: ```typescript myWorkflow .parallel([nestedWorkflow1, nestedWorkflow2]) .then(finalStep) .commit(); ``` 並列ステップは前のステップの結果を入力として受け取ります。それらの出力は、キーがステップIDで値がステップ出力であるオブジェクトとして次のステップの入力に渡されます。例えば、上記の例では`nestedWorkflow1`と`nestedWorkflow2`の2つのキーを持つオブジェクトが出力され、それぞれのワークフローの出力が値として含まれます。 ## 条件分岐 `.branch()` を使って条件分岐を作成します: ```typescript myWorkflow .then(initialStep) .branch([ [async ({ inputData }) => inputData.value > 50, highValueStep], [ async ({ inputData }) => inputData.value > 10 && inputData.value <= 50, lowValueStep, ], [async ({ inputData }) => inputData.value <= 10, extremelyLowValueStep], ]) .then(finalStep) .commit(); ``` 分岐条件は順番に評価され、一致するすべての条件のステップが並列で実行されます。もし `inputData.value` が `5` の場合、`lowValueStep` と `extremelyLowValueStep` の両方が実行されます。 各条件付きステップ(`highValueStep` や `lowValueStep` など)は、前のステップ(この場合は `initialStep`)の出力を入力として受け取ります。一致した各条件付きステップの出力が収集されます。分岐の後の次のステップ(`finalStep`)は、分岐内で実行されたすべてのステップの出力を含むオブジェクトを受け取ります。このオブジェクトのキーはステップIDであり、値はそれぞれのステップの出力です(`{ lowValueStep: , extremelyLowValueStep: }`)。 ## ループ vNextは2種類のループをサポートしています。ステップ(またはネストされたワークフローやその他のステップ互換の構造)をループする場合、ループの`inputData`は最初は前のステップの出力ですが、その後の`inputData`はループステップ自体の出力になります。したがってループでは、初期ループ状態は前のステップの出力と一致するか、`map`関数を使用して導出される必要があります。 **Do-Whileループ**: 条件が真である間、ステップを繰り返し実行します。 ```typescript myWorkflow .dowhile(incrementStep, async ({ inputData }) => inputData.value < 10) .then(finalStep) .commit(); ``` **Do-Untilループ**: 条件が真になるまで、ステップを繰り返し実行します。 ```typescript myWorkflow .dountil(incrementStep, async ({ inputData }) => inputData.value >= 10) .then(finalStep) .commit(); ``` ```typescript const workflow = createWorkflow({ id: "increment-workflow", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), }) .dountil(incrementStep, async ({ inputData }) => inputData.value >= 10) .then(finalStep); ``` ## Foreach Foreachは配列型の入力の各項目に対してステップを実行するステップです。 ```typescript const mapStep = createStep({ id: "map", description: "Maps (+11) on the current value", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), execute: async ({ inputData }) => { return { value: inputData.value + 11 }; }, }); const finalStep = createStep({ id: "final", description: "Final step that prints the result", inputSchema: z.array(z.object({ value: z.number() })), outputSchema: z.object({ finalValue: z.number(), }), execute: async ({ inputData }) => { return { finalValue: inputData.reduce((acc, curr) => acc + curr.value, 0) }; }, }); const counterWorkflow = createWorkflow({ steps: [mapStep, finalStep], id: "counter-workflow", inputSchema: z.array(z.object({ value: z.number() })), outputSchema: z.object({ finalValue: z.number(), }), }); counterWorkflow.foreach(mapStep).then(finalStep).commit(); const run = counterWorkflow.createRun(); const result = await run.start({ inputData: [{ value: 1 }, { value: 22 }, { value: 333 }], }); if (result.status === "success") { console.log(result.result); // only exists if status is success } else if (result.status === "failed") { console.error(result.error); // only exists if status is failed, this is an instance of Error } ``` ループは入力配列の各項目に対して、一度に1つずつ順番にステップを実行します。オプションの`concurrency`を使用すると、並行実行の数に制限を設けながらステップを並列に実行することができます。 ```typescript counterWorkflow.foreach(mapStep, { concurrency: 2 }).then(finalStep).commit(); ``` ## ネストされたワークフロー vNextではワークフローをネストして組み合わせることができます: ```typescript const nestedWorkflow = createWorkflow({ id: 'nested-workflow', inputSchema: z.object({...}), outputSchema: z.object({...}), }) .then(step1) .then(step2) .commit(); const mainWorkflow = createWorkflow({ id: 'main-workflow', inputSchema: z.object({...}), outputSchema: z.object({...}), }) .then(initialStep) .then(nestedWorkflow) .then(finalStep) .commit(); ``` 上記の例では、`nestedWorkflow`が`mainWorkflow`のステップとして使用されています。ここで、`nestedWorkflow`の`inputSchema`は`initialStep`の`outputSchema`と一致し、`nestedWorkflow`の`outputSchema`は`finalStep`の`inputSchema`と一致します。 ネストされたワークフローは、単純な順次実行を超えた実行フローを構成するための主要な(そして唯一の)方法です。`.branch()`や`.parallel()`を使用して実行フローを構成する場合、1つ以上のステップを実行するにはネストされたワークフローが必要であり、その副産物として、これらのステップがどのように実行されるかの説明が必要です。 ```typescript const planBothWorkflow = createWorkflow({ id: "plan-both-workflow", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), steps: [planActivities, planIndoorActivities, sythesizeStep], }) .parallel([planActivities, planIndoorActivities]) .then(sythesizeStep) .commit(); const weatherWorkflow = createWorkflow({ id: "weather-workflow-step3-concurrency", inputSchema: z.object({ city: z.string().describe("The city to get the weather for"), }), outputSchema: z.object({ activities: z.string(), }), steps: [fetchWeather, planBothWorkflow, planActivities], }) .then(fetchWeather) .branch([ [ async ({ inputData }) => { return inputData?.precipitationChance > 20; }, planBothWorkflow, ], [ async ({ inputData }) => { return inputData?.precipitationChance <= 20; }, planActivities, ], ]); ``` ネストされたワークフローは、最終結果(最後のステップの結果)のみをステップ出力として持ちます。 --- title: "Inngest ワークフロー | ワークフロー (vNext) | Mastra ドキュメント" description: "Inngest ワークフローを使用すると、Inngest で Mastra vNext ワークフローを実行できます" --- # Inngest ワークフロー [JA] Source: https://mastra.ai/ja/docs/workflows-vnext/inngest-workflow [Inngest](https://www.inngest.com/docs)は、インフラストラクチャを管理することなく、バックグラウンドワークフローを構築・実行するための開発者プラットフォームです。 ## セットアップ ```sh npm install @mastra/inngest @mastra/core @mastra/deployer @hono/node-server ``` ### ローカル開発環境 Inngestはローカル開発のために2つの方法を提供しています: #### オプション1:Dockerを使用する Dockerを使用してInngestをポート8288でローカルに実行し、ポート3000でイベントをリッスンするように設定します: ```sh docker run --rm -p 8288:8288 \ inngest/inngest \ inngest dev -u http://host.docker.internal:3000/inngest/api ``` #### オプション2:Inngest CLI あるいは、公式の[Inngest Dev Serverガイド](https://www.inngest.com/docs/dev-server)に従ってInngest CLIをローカル開発に使用することもできます。 > **ヒント**:Inngestが実行されると、[http://localhost:8288](http://localhost:8288)でInngestダッシュボードにアクセスして、ワークフローの実行をリアルタイムで監視およびデバッグできます。 ## Inngestワークフローの構築 このガイドでは、InngestとMastraを使用してワークフローを作成する方法を説明します。値が10に達するまでカウンターをインクリメントするアプリケーションを例として示します。 ### Inngestの初期化 Inngest統合を初期化して、Mastra互換のワークフローヘルパーを取得します: ```ts showLineNumbers copy filename="src/mastra/workflows/inngest-workflow.ts" import { init } from "@mastra/inngest"; import { Inngest } from "inngest"; // Initialize Inngest with Mastra, pointing to your local Inngest server const { createWorkflow, createStep } = init( new Inngest({ id: "mastra", baseUrl: `http://localhost:8288`, }), ); ``` ### ステップの作成 ワークフローを構成する個々のステップを定義します: ```ts showLineNumbers copy filename="src/mastra/workflows/inngest-workflow.ts" import { z } from "zod"; // Step 1: Increment the counter value const incrementStep = createStep({ id: "increment", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), execute: async ({ inputData }) => { return { value: inputData.value + 1 }; }, }); // Step 2: Log the current value (side effect) const sideEffectStep = createStep({ id: "side-effect", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), execute: async ({ inputData }) => { console.log("Current value:", inputData.value); return { value: inputData.value }; }, }); // Step 3: Final step after loop completion const finalStep = createStep({ id: "final", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), execute: async ({ inputData }) => { return { value: inputData.value }; }, }); ``` ### ワークフローの作成 `dountil`ループパターンを使用してステップをワークフローに構成します: ```ts showLineNumbers copy filename="src/mastra/workflows/inngest-workflow.ts" // Create the main workflow that uses a do-until loop const workflow = createWorkflow({ id: "increment-workflow", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), }) // Loop until the condition is met (value reaches 10) .dountil( createWorkflow({ id: "increment-subworkflow", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), steps: [incrementStep, sideEffectStep], }) .then(incrementStep) .then(sideEffectStep) .commit(), async ({ inputData }) => inputData.value >= 10, ) .then(finalStep); workflow.commit(); export { workflow as incrementWorkflow }; ``` ### Mastraインスタンスの設定とワークフローの実行 ワークフローをMastraに登録し、Inngest APIエンドポイントを設定します: ```ts showLineNumbers copy filename="src/mastra/index.ts" import { Mastra } from "@mastra/core/mastra"; import { serve as inngestServe } from "@mastra/inngest"; import { PinoLogger } from "@mastra/loggers"; import { Inngest } from "inngest"; import { incrementWorkflow } from "./workflows/inngest-workflow"; import { realtimeMiddleware } from "@inngest/realtime"; import { serve } from "@hono/node-server"; import { createHonoServer } from "@mastra/deployer/server"; // Create an Inngest instance with realtime middleware for development const inngest = new Inngest({ id: "mastra", baseUrl: `http://localhost:8288`, isDev: true, middleware: [realtimeMiddleware()], }); // Configure Mastra with the workflow and Inngest API endpoint export const mastra = new Mastra({ vnext_workflows: { incrementWorkflow, }, server: { host: "0.0.0.0", apiRoutes: [ { path: "/api/inngest", method: "ALL", createHandler: async ({ mastra }) => inngestServe({ mastra, inngest }), }, ], }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); // Create and start the Hono server const app = await createHonoServer(mastra); const srv = serve({ fetch: app.fetch, port: 3000, }); // Get the workflow, create a run, and start it with an initial value const workflow = mastra.vnext_getWorkflow("incrementWorkflow"); const run = workflow.createRun({}); const result = await run.start({ inputData: { value: 5 } }); console.dir(result, { depth: null }); // Close the server when done srv.close(); ``` ワークフローを開始した後、[Inngestダッシュボード](http://localhost:8288)にアクセスして実行の進捗状況を監視し、ステップの出力を確認し、問題をデバッグすることができます。 ## 本番環境での実行 Inngest CloudとVercelでMastraワークフローをデプロイするには、以下の手順に従ってください: 1. Inngest初期化から`baseUrl`を削除します。 2. MastraアプリケーションをVercelにデプロイします。公式のMastraデプロイメントガイドに従ってください:[MastraをVercelにデプロイする](https://mastra.ai/en/reference/deployer/vercel) 3. [Inngest Cloud](https://app.inngest.com/)にアクセスします。 4. 公式のVercel統合を使用してVercelプロジェクトを接続します:[Inngest Cloud Vercel統合ガイド](https://www.inngest.com/docs/apps/cloud) 5. これにより、サーバーレス関数が自動的に同期され、ワークフローエンドポイントが登録されます。 6. Inngest Cloudダッシュボードを使用して、イベントをトリガーし、ワークフローの実行、ログ、ステップの出力を監視します。 --- title: "ワークフロー(vNext)での入力データマッピング | Mastra Docs" description: "Mastraワークフロー(vNext)でより動的なデータフローを作成するためのワークフロー入力マッピングの使用方法を学びましょう。" --- # 入力データマッピング [JA] Source: https://mastra.ai/ja/docs/workflows-vnext/input-data-mapping 入力データマッピングにより、次のステップの入力に対する値を明示的にマッピングすることができます。これらの値は以下のようなさまざまなソースから取得できます: - 前のステップの出力 - ランタイムコンテキスト - 定数値 - ワークフローの初期入力 ```typescript myWorkflow .then(step1) .map({ transformedValue: { step: step1, path: "nestedValue", }, runtimeContextValue: { runtimeContextPath: "runtimeContextValue", schema: z.number(), }, constantValue: { value: 42, schema: z.number(), }, initDataValue: { initData: myWorkflow, path: "startValue", }, }) .then(step2) .commit(); ``` `.map()`は、出力を入力に一致させるために役立つケースが多くあります。出力の名前を変更して入力に一致させる場合や、複雑なデータ構造や他の前のステップの出力をマッピングする場合などです。 ## 出力の名前変更 入力マッピングのユースケースの1つは、出力の名前を入力に合わせて変更することです: ```typescript import { Mastra } from "@mastra/core"; import { createWorkflow, createStep } from "@mastra/core/workflows/vNext"; import { z } from "zod"; const step1 = createStep({ id: "step1", inputSchema: z.object({ inputValue: z.string(), }), outputSchema: z.object({ outputValue: z.string(), }), execute: async ({ inputData, mastra }) => { mastra.getLogger()?.debug(`Step 1 received: ${inputData.inputValue}`); return { outputValue: `${inputData.inputValue}` }; }, }); const step2 = createStep({ id: "step2", inputSchema: z.object({ unexpectedName: z.string(), }), outputSchema: z.string(), execute: async ({ inputData, mastra }) => { mastra.getLogger()?.debug(`Step 2 received: ${inputData.unexpectedName}`); return `${inputData.unexpectedName}`; }, }); const myWorkflow = createWorkflow({ id: "my-workflow", inputSchema: z.object({ inputValue: z.string(), }), outputSchema: z.string(), steps: [step1, step2], }) .then(step1) // mapping output from step1 "outputValue" // to input for step2 "unexpectedName" .map({ unexpectedName: { step: step1, path: "outputValue", }, }) .then(step2) .commit(); const mastra = new Mastra({ vnext_workflows: { myWorkflow, }, }); const run = mastra.vnext_getWorkflow("myWorkflow").createRun(); const res = await run.start({ inputData: { inputValue: "Hello world" }, }); if (res.status === "success") { console.log(res.result); } ``` ## ワークフローの入力を後のステップの入力として使用する ```typescript import { Mastra } from "@mastra/core"; import { createWorkflow, createStep } from "@mastra/core/workflows/vNext"; import { z } from "zod"; const step1 = createStep({ id: "step1", inputSchema: z.object({ inputValue: z.string(), }), outputSchema: z.object({ outputValue: z.string(), }), execute: async ({ inputData, mastra }) => { mastra.getLogger()?.debug(`Step 1 received: ${inputData.inputValue}`); return { outputValue: `Processed: ${inputData.inputValue}` }; }, }); const step2 = createStep({ id: "step2", inputSchema: z.object({ outputValue: z.string(), initialValue: z.string(), }), outputSchema: z.object({ result: z.string(), }), execute: async ({ inputData, mastra }) => { mastra .getLogger() ?.debug( `Step 2 received: ${inputData.outputValue} and original: ${inputData.initialValue}`, ); return { result: `Combined: ${inputData.outputValue} (original: ${inputData.initialValue})`, }; }, }); const myWorkflow = createWorkflow({ id: "my-workflow", inputSchema: z.object({ inputValue: z.string(), }), outputSchema: z.object({ result: z.string(), }), steps: [step1, step2], }); myWorkflow .then(step1) .map({ outputValue: { step: step1, path: "outputValue", }, initialValue: { initData: myWorkflow, path: "inputValue", }, }) .then(step2) .commit(); // Create Mastra instance with all workflows const mastra = new Mastra({ vnext_workflows: { myWorkflow, }, }); const run = mastra.vnext_getWorkflow("myWorkflow").createRun(); const res = await run.start({ inputData: { inputValue: "Original input" }, }); if (res.status === "success") { console.log("Result:", res.result); } ``` ## 前のステップの複数の出力を使用する ```typescript import { Mastra } from "@mastra/core"; import { createWorkflow, createStep } from "@mastra/core/workflows/vNext"; import { z } from "zod"; const step1 = createStep({ id: "step1", inputSchema: z.object({ inputValue: z.string(), }), outputSchema: z.object({ intermediateValue: z.string(), }), execute: async ({ inputData, mastra }) => { mastra.getLogger()?.debug(`Step 1 received: ${inputData.inputValue}`); return { intermediateValue: `Step 1: ${inputData.inputValue}` }; }, }); const step2 = createStep({ id: "step2", inputSchema: z.object({ intermediateValue: z.string(), }), outputSchema: z.object({ currentResult: z.string(), }), execute: async ({ inputData, mastra }) => { mastra .getLogger() ?.debug(`Step 2 received: ${inputData.intermediateValue}`); return { currentResult: `Step 2: ${inputData.intermediateValue}` }; }, }); const step3 = createStep({ id: "step3", inputSchema: z.object({ currentResult: z.string(), // From step2 intermediateValue: z.string(), // From step1 initialValue: z.string(), // From workflow input }), outputSchema: z.object({ result: z.string(), }), execute: async ({ inputData, mastra }) => { mastra.getLogger()?.debug(`Step 3 combining all previous data`); return { result: `Combined result: - Initial input: ${inputData.initialValue} - Step 1 output: ${inputData.intermediateValue} - Step 2 output: ${inputData.currentResult}`, }; }, }); const myWorkflow = createWorkflow({ id: "my-workflow", inputSchema: z.object({ inputValue: z.string(), }), outputSchema: z.object({ result: z.string(), }), steps: [step1, step2, step3], }); myWorkflow .then(step1) .then(step2) .map({ // Map values from different sources to step3's inputs initialValue: { initData: myWorkflow, path: "inputValue", }, currentResult: { step: step2, path: "currentResult", }, intermediateValue: { step: step1, path: "intermediateValue", }, }) .then(step3) .commit(); // Create Mastra instance with all workflows const mastra = new Mastra({ vnext_workflows: { myWorkflow, }, }); const run = mastra.vnext_getWorkflow("myWorkflow").createRun(); const res = await run.start({ inputData: { inputValue: "Starting data" }, }); if (res.status === "success") { console.log("Result:", res.result); } ``` --- title: "複雑なLLM操作の取り扱い | ワークフロー(vNext) | Mastra" description: "Mastraのワークフロー(vNext)は、分岐、並列実行、リソース停止などの機能を備えた複雑な操作シーケンスのオーケストレーションを支援します。" --- ## はじめに [JA] Source: https://mastra.ai/ja/docs/workflows-vnext/overview vNextワークフローを使用するには、まずvNextモジュールから必要な関数をインポートします: ```typescript import { createWorkflow, createStep } from "@mastra/core/workflows/vNext"; import { z } from "zod"; // For schema validation ``` ## 主要な概念 vNextワークフローは以下で構成されています: - **スキーマ**:Zodを使用した入力と出力の型定義 - **ステップ**:定義された入力と出力を持つ個々の作業単位 - **ワークフロー**:定義された実行パターンを持つステップのオーケストレーション。ワークフローもステップであり、他のワークフローでステップとして使用できます。 - **ワークフロー実行フロー**:ステップがどのように実行され、相互に接続されるか スキーマはZodを使用して、ステップとワークフローの入力と出力の両方に対して定義されます。スキーマはまた、ステップが一時停止状態から再開する際に取得するデータや、ステップの実行を一時停止する際に渡すべき文脈情報を指定することもできます。 接続されているステップの入力と出力は一致する必要があります:例えば、あるステップのinputSchemaは前のステップのoutputSchemaと同じであるべきです。同様に、ワークフローを他のワークフローでステップとして使用する場合、ワークフローのinputSchemaは、それが使用されるステップのoutputSchemaと一致する必要があります。 ステップは、前のステップからの入力や、ステップが一時停止状態から再開される場合は再開データを含むコンテキストオブジェクトを受け取る`execute`関数を使用して実行されます。`execute`関数はそのoutputSchemaに一致する値を返す必要があります。 `.then()`、`.parallel()`、`.branch()`などのプリミティブは、ワークフローの実行フローと、その中のステップがどのように接続されるかを記述します。ワークフロー(単独でもステップとしても)を実行する場合、その実行は`execute`関数ではなく、実行フローによって決定されます。ワークフローの最終結果は常に最後のステップの結果となり、これはワークフローのoutputSchemaと一致する必要があります。 ## ワークフローの作成 ### ステップ ステップはワークフローの構成要素です。`createStep`を使用してステップを作成します: ```typescript const myStep = createStep({ id: "my-step", description: "Does something useful", inputSchema: z.object({ inputValue: z.string(), }), outputSchema: z.object({ outputValue: z.string(), }), resumeSchema: z.object({ resumeValue: z.string(), }), suspendSchema: z.object({ suspendValue: z.string(), }), execute: async ({ inputData, mastra, getStepResult, getInitData, runtimeContext, }) => { const otherStepOutput = getStepResult(step2); const initData = getInitData(); // typed as the workflow input schema return { outputValue: `Processed: ${inputData.inputValue}, ${initData.startValue} (runtimeContextValue: ${runtimeContext.get("runtimeContextValue")})`, }; }, }); ``` 各ステップには以下が必要です: - `id`: ステップの一意の識別子 - `inputSchema`: 予想される入力を定義するZodスキーマ - `outputSchema`: 出力の形を定義するZodスキーマ - `resumeSchema`: オプション。再開入力を定義するZodスキーマ - `suspendSchema`: オプション。一時停止入力を定義するZodスキーマ - `execute`: ステップの作業を実行する非同期関数 `execute`関数は以下を含むコンテキストオブジェクトを受け取ります: - `inputData`: inputSchemaに一致する入力データ - `resumeData`: 一時停止状態からステップを再開する際に、resumeSchemaに一致する再開データ。ステップが再開される場合にのみ存在します。 - `mastra`: mastraサービス(エージェント、ツールなど)へのアクセス - `getStepResult`: 他のステップの結果にアクセスするための関数 - `getInitData`: どのステップでもワークフローの初期入力データにアクセスするための関数 - `suspend`: ワークフロー実行を一時停止するための関数(ユーザーとのインタラクション用) ### ワークフロー構造 `createWorkflow`を使用してワークフローを作成します: ```typescript const myWorkflow = createWorkflow({ id: "my-workflow", inputSchema: z.object({ startValue: z.string(), }), outputSchema: z.object({ result: z.string(), }), steps: [step1, step2, step3], // Declare steps used in this workflow }) .then(step1) .then(step2) .then(step3) .commit(); const mastra = new Mastra({ vnext_workflows: { myWorkflow, }, }); const run = mastra.vnext_getWorkflow("myWorkflow").createRun(); ``` ワークフローオプションの`steps`プロパティは、ステップ結果へのアクセスに対する型安全性を提供します。ワークフローで使用するステップを宣言すると、TypeScriptは`result.steps`へのアクセス時に型安全性を確保します: ```typescript // With steps declared in workflow options const workflow = createWorkflow({ id: "my-workflow", inputSchema: z.object({}), outputSchema: z.object({}), steps: [step1, step2], // TypeScript knows these steps exist }) .then(step1) .then(step2) .commit(); const result = await workflow.createRun().start({ inputData: {} }); if (result.status === "success") { console.log(result.result); // only exists if status is success } else if (result.status === "failed") { console.error(result.error); // only exists if status is failed, this is an instance of Error throw result.error; } else if (result.status === "suspended") { console.log(result.suspended); // only exists if status is suspended } // TypeScript knows these properties exist and their types console.log(result.steps.step1.output); // Fully typed console.log(result.steps.step2.output); // Fully typed ``` ワークフロー定義には以下が必要です: - `id`: ワークフローの一意の識別子 - `inputSchema`: ワークフロー入力を定義するZodスキーマ - `outputSchema`: ワークフロー出力を定義するZodスキーマ - `steps`: ワークフローで使用されるステップの配列(オプションですが、型安全性のために推奨) ### ステップとネストされたワークフローの再利用 ステップとネストされたワークフローをクローンして再利用できます: ```typescript const clonedStep = cloneStep(myStep, { id: "cloned-step" }); const clonedWorkflow = cloneWorkflow(myWorkflow, { id: "cloned-workflow" }); ``` このようにして、同じステップやネストされたワークフローを同じワークフロー内で複数回使用できます。 ```typescript import { createWorkflow, createStep, cloneStep, cloneWorkflow, } from "@mastra/core/workflows/vNext"; const myWorkflow = createWorkflow({ id: "my-workflow", steps: [step1, step2, step3], }); myWorkflow.then(step1).then(step2).then(step3).commit(); const parentWorkflow = createWorkflow({ id: "parent-workflow", steps: [myWorkflow, step4], }); parentWorkflow .then(myWorkflow) .then(step4) .then(cloneWorkflow(myWorkflow, { id: "cloned-workflow" })) .then(cloneStep(step4, { id: "cloned-step-4" })) .commit(); ``` ## ワークフローの実行 ワークフローを定義した後、以下のように実行します: ```typescript // 実行インスタンスを作成 const run = myWorkflow.createRun(); // 入力データでワークフローを開始 const result = await run.start({ inputData: { startValue: "initial data", }, }); // 結果にアクセス console.log(result.steps); // すべてのステップの結果 console.log(result.steps["step-id"].output); // 特定のステップからの出力 if (result.status === "success") { console.log(result.result); // ワークフローの最終結果、最後のステップの結果(または最後のステップとして`.map()`が使用された場合はその出力) } else if (result.status === "suspended") { const resumeResult = await run.resume({ step: result.suspended[0], // 一時停止された実行パスには常に少なくとも1つのステップIDがあります。この場合、最初の一時停止された実行パスを再開します resumeData: { /* ユーザー入力 */ }, }); } else if (result.status === "failed") { console.error(result.error); // ステータスが失敗の場合にのみ存在し、これはErrorのインスタンスです } ``` ## ワークフロー実行結果のスキーマ ワークフローの実行結果(`start()`または`resume()`からの)は、次のTypeScriptインターフェースに従います: ```typescript export type WorkflowResult<...> = | { status: 'success'; result: z.infer; steps: { [K in keyof StepsRecord]: StepsRecord[K]['outputSchema'] extends undefined ? StepResult : StepResult[K]['outputSchema']>>>; }; } | { status: 'failed'; steps: { [K in keyof StepsRecord]: StepsRecord[K]['outputSchema'] extends undefined ? StepResult : StepResult[K]['outputSchema']>>>; }; error: Error; } | { status: 'suspended'; steps: { [K in keyof StepsRecord]: StepsRecord[K]['outputSchema'] extends undefined ? StepResult : StepResult[K]['outputSchema']>>>; }; suspended: [string[], ...string[][]]; }; ``` ### 結果プロパティの説明 1. **status**: ワークフロー実行の最終状態を示します - `'success'`: ワークフローが正常に完了 - `'failed'`: ワークフローでエラーが発生 - `'suspended'`: ワークフローがユーザー入力を待機して一時停止中 2. **result**: ワークフローの最終出力を含み、ワークフローの`outputSchema`に従って型付けされます 3. **suspended**: 現在一時停止中のステップIDの配列(オプション)。`status`が`'suspended'`の場合のみ存在します 4. **steps**: 実行されたすべてのステップの結果を含むレコード - キーはステップID - 値はステップの出力を含む`StepResult`オブジェクト - 各ステップの`outputSchema`に基づいて型安全 5. **error**: `status`が`'failed'`の場合に存在するエラーオブジェクト(オプション) ## ワークフロー実行の監視 ワークフロー実行を監視することもできます: ```typescript const run = myWorkflow.createRun(); // 実行を監視するウォッチャーを追加 run.watch(event => { console.log('ステップ完了:', event.payload.currentStep.id); }); // ワークフローを開始 const result = await run.start({ inputData: {...} }); ``` `event`オブジェクトは以下のスキーマを持っています: ```typescript type WatchEvent = { type: "watch"; payload: { currentStep?: { id: string; status: "running" | "completed" | "failed" | "suspended"; output?: Record; payload?: Record; }; workflowState: { status: "running" | "success" | "failed" | "suspended"; steps: Record< string, { status: "running" | "completed" | "failed" | "suspended"; output?: Record; payload?: Record; } >; result?: Record; error?: Record; payload?: Record; }; }; eventTimestamp: Date; }; ``` `currentStep`プロパティはワークフローの実行中にのみ存在します。ワークフローが終了すると、`workflowState`のステータスが変更され、`result`および`error`プロパティも更新されます。同時に`currentStep`プロパティは削除されます。 --- title: "ワークフローの一時停止と再開 (vNext) | ヒューマンインザループ | Mastra ドキュメント" description: "Mastra vNextワークフローにおける一時停止と再開機能により、外部からの入力やリソースを待つ間、実行を一時停止することができます。" --- # ワークフローにおける一時停止と再開 [JA] Source: https://mastra.ai/ja/docs/workflows-vnext/suspend-and-resume 複雑なワークフローでは、外部からの入力やリソースを待つために実行を一時停止する必要がしばしばあります。 Mastraの一時停止と再開機能を使用すると、任意のステップでワークフロー実行を一時停止し、ワークフローのスナップショットをストレージに保存し、準備ができたら保存されたスナップショットから実行を再開することができます。 このプロセス全体はMastraによって自動的に管理されます。ユーザーからの設定や手動のステップは必要ありません。 ワークフローのスナップショットをストレージ(デフォルトではLibSQL)に保存することで、ワークフローの状態はセッション、デプロイメント、サーバーの再起動を超えて永続的に保存されます。この永続性は、外部からの入力やリソースを待つために数分、数時間、あるいは数日間一時停止したままになる可能性のあるワークフローにとって非常に重要です。 ## ワークフローの一時停止と再開を使用するタイミング ワークフローを一時停止する一般的なシナリオには以下が含まれます: - 人間の承認や入力を待つ - 外部APIリソースが利用可能になるまで待機する - 後のステップに必要な追加データを収集する - 高コストの操作のレート制限やスロットリング - 外部トリガーによるイベント駆動プロセスの処理 ## ステップを一時停止する方法 ```typescript const humanInputStep = createStep({ id: "human-input", inputSchema: z.object({ suggestions: z.array(z.string()), vacationDescription: z.string(), }), resumeSchema: z.object({ selection: z.string(), }), suspendSchema: z.object({}), outputSchema: z.object({ selection: z.string().describe("The selection of the user"), vacationDescription: z.string(), }), execute: async ({ inputData, resumeData, suspend }) => { if (!resumeData?.selection) { await suspend({}); return { selection: "", vacationDescription: inputData?.vacationDescription, }; } return { selection: resumeData.selection, vacationDescription: inputData?.vacationDescription, }; }, }); ``` ## ステップ実行の再開方法 ### 一時停止状態の識別 ワークフローを実行する際、その状態は以下のいずれかになります: - `running` - ワークフローが現在実行中 - `suspended` - ワークフローが一時停止中 - `success` - ワークフローが完了 - `failed` - ワークフローが失敗 状態が`suspended`の場合、ワークフローの`suspended`プロパティを確認することで、一時停止されているすべてのステップを識別できます。 ```typescript const run = counterWorkflow.createRun(); const result = await run.start({ inputData: { startValue: 0 } }); if (result.status === "suspended") { const resumedResults = await run.resume({ step: result.suspended[0], resumeData: { newValue: 0 }, }); } ``` この場合、一時停止として報告された最初のステップを再開するロジックです。 `suspended`プロパティは`string[][]`型で、各配列は一時停止されたステップへのパスを表します。最初の要素はメインワークフローのステップIDです。そのステップ自体がワークフローである場合、2番目の要素はネストされたワークフローで一時停止されたステップIDとなります。さらにそれがワークフローである場合、3番目の要素はネストされたワークフローで一時停止されたステップIDとなり、以降も同様です。 ### 再開 ```typescript // ユーザー入力の取得後 const result = await workflowRun.resume({ step: userInputStep, // または文字列として 'myStepId' resumeData: { userSelection: "ユーザーの選択", }, }); ``` ネストされた一時停止中のワークフローを再開するには: ```typescript const result = await workflowRun.resume({ step: [nestedWorkflow, userInputStep], // または文字列配列として ['nestedWorkflowId', 'myStepId'] resumeData: { userSelection: "ユーザーの選択", }, }); ``` --- title: "エージェントとツールを使用したワークフロー | ワークフロー (vNext) | Mastra ドキュメント" description: "Mastraワークフロー(vNext)のステップは、入力、出力、実行ロジックを定義することで、操作を管理するための構造化された方法を提供します。" --- ## ステップとしてのエージェント [JA] Source: https://mastra.ai/ja/docs/workflows-vnext/using-with-agents-and-tools vNextワークフローでは、`createStep(agent)`を使用してMastraエージェントを直接ステップとして使用できます: ```typescript import { Mastra } from "@mastra/core"; import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { createWorkflow, createStep } from "@mastra/core/workflows/vNext"; import { z } from "zod"; const myAgent = new Agent({ name: "myAgent", instructions: "You are a helpful assistant that answers questions concisely.", model: openai("gpt-4o"), }); // Input preparation step const preparationStep = createStep({ id: "preparation", inputSchema: z.object({ question: z.string(), }), outputSchema: z.object({ formattedPrompt: z.string(), }), execute: async ({ inputData }) => { return { formattedPrompt: `Answer this question briefly: ${inputData.question}`, }; }, }); const agentStep = createStep(myAgent); // Create a simple workflow const myWorkflow = createWorkflow({ id: "simple-qa-workflow", inputSchema: z.object({ question: z.string(), }), outputSchema: z.string(), steps: [preparationStep, agentStep], }); // Define workflow sequence myWorkflow .then(preparationStep) .map({ prompt: { step: preparationStep, path: "formattedPrompt", }, }) .then(agentStep) .commit(); // Create Mastra instance const mastra = new Mastra({ agents: { myAgent, }, vnext_workflows: { myWorkflow, }, }); const workflow = mastra.vnext_getWorkflow("myWorkflow"); const run = workflow.createRun(); // Run the workflow with a question const res = await run.start({ inputData: { question: "What is machine learning?", }, }); if (res.status === "success") { console.log("Answer:", res.result); } else if (res.status === "failed") { console.error("Workflow failed:", res.error); } ``` ## ステップとしてのツール vNextワークフローでは、`createStep(tool)`を使用してMastraツールを直接ステップとして使用できます: ```typescript import { createTool, Mastra } from "@mastra/core"; import { createWorkflow, createStep } from "@mastra/core/workflows/vNext"; import { z } from "zod"; // Create a weather tool const weatherTool = createTool({ id: "weather-tool", description: "Get weather information for a location", inputSchema: z.object({ location: z.string().describe("The city name"), }), outputSchema: z.object({ temperature: z.number(), conditions: z.string(), }), execute: async ({ context: { location } }) => { return { temperature: 22, conditions: "Sunny", }; }, }); // Create a step that formats the input const locationStep = createStep({ id: "location-formatter", inputSchema: z.object({ city: z.string(), }), outputSchema: z.object({ location: z.string(), }), execute: async ({ inputData }) => { return { location: inputData.city, }; }, }); // Create a step that formats the output const formatResultStep = createStep({ id: "format-result", inputSchema: z.object({ temperature: z.number(), conditions: z.string(), }), outputSchema: z.object({ weatherReport: z.string(), }), execute: async ({ inputData }) => { return { weatherReport: `Current weather: ${inputData.temperature}°C and ${inputData.conditions}`, }; }, }); const weatherToolStep = createStep(weatherTool); // Create the workflow const weatherWorkflow = createWorkflow({ id: "weather-workflow", inputSchema: z.object({ city: z.string(), }), outputSchema: z.object({ weatherReport: z.string(), }), steps: [locationStep, weatherToolStep, formatResultStep], }); // Define workflow sequence weatherWorkflow .then(locationStep) .then(weatherToolStep) .then(formatResultStep) .commit(); // Create Mastra instance const mastra = new Mastra({ vnext_workflows: { weatherWorkflow, }, }); const workflow = mastra.vnext_getWorkflow("weatherWorkflow"); const run = workflow.createRun(); // Run the workflow const result = await run.start({ inputData: { city: "Tokyo", }, }); if (result.status === "success") { console.log(result.result.weatherReport); } else if (result.status === "failed") { console.error("Workflow failed:", result.error); } ``` ## エージェント内のツールとしてのワークフロー ```typescript import { openai } from "@ai-sdk/openai"; import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { createTool } from "@mastra/core/tools"; import { createWorkflow, createStep } from "@mastra/core/workflows/vNext"; import { z } from "zod"; // Define the weather fetching step const fetchWeather = createStep({ id: "fetch-weather", inputSchema: z.object({ city: z.string().describe("The city to get the weather for"), }), outputSchema: z.object({ temperature: z.number(), conditions: z.string(), city: z.string(), }), execute: async ({ inputData }) => { return { temperature: 25, conditions: "Sunny", city: inputData.city, }; }, }); // Define the activity planning step const planActivities = createStep({ id: "plan-activities", inputSchema: z.object({ temperature: z.number(), conditions: z.string(), city: z.string(), }), outputSchema: z.object({ activities: z.array(z.string()), }), execute: async ({ inputData }) => { mastra .getLogger() ?.debug(`Planning activities for ${inputData.city} based on weather`); const activities = []; if (inputData.temperature > 20 && inputData.conditions === "Sunny") { activities.push("Visit the park", "Go hiking", "Have a picnic"); } else if (inputData.temperature < 10) { activities.push("Visit a museum", "Go to a cafe", "Indoor shopping"); } else { activities.push( "Sightseeing tour", "Visit local attractions", "Try local cuisine", ); } return { activities, }; }, }); // Create the weather workflow const weatherWorkflow = createWorkflow({ id: "weather-workflow", inputSchema: z.object({ city: z.string().describe("The city to get the weather for"), }), outputSchema: z.object({ activities: z.array(z.string()), }), steps: [fetchWeather, planActivities], }) .then(fetchWeather) .then(planActivities) .commit(); // Create a tool that uses the workflow const activityPlannerTool = createTool({ id: "get-weather-specific-activities", description: "Get weather-specific activities for a city based on current weather conditions", inputSchema: z.object({ city: z.string().describe("The city to get activities for"), }), outputSchema: z.object({ activities: z.array(z.string()), }), execute: async ({ context: { city }, mastra }) => { mastra.getLogger()?.debug(`Tool executing for city: ${city}`); const workflow = mastra?.vnext_getWorkflow("weatherWorkflow"); if (!workflow) { throw new Error("Weather workflow not found"); } const run = workflow.createRun(); const result = await run.start({ inputData: { city: city, }, }); if (result.status === "success") { return { activities: result.result.activities, }; } throw new Error(`Workflow execution failed: ${result.status}`); }, }); // Create an agent that uses the tool const activityPlannerAgent = new Agent({ name: "activityPlannerAgent", model: openai("gpt-4o"), instructions: ` You are an activity planner. You suggest fun activities based on the weather in a city. Use the weather-specific activities tool to get activity recommendations. Format your response in a friendly, conversational way. `, tools: { activityPlannerTool }, }); // Create the Mastra instance const mastra = new Mastra({ vnext_workflows: { weatherWorkflow, }, agents: { activityPlannerAgent, }, }); const response = await activityPlannerAgent.generate( "What activities do you recommend for a visit to Tokyo?", ); console.log("\nAgent response:"); console.log(response.text); ``` --- title: "例:音声機能の追加 | エージェント | Mastra" description: "Mastraエージェントに音声機能を追加する例で、異なる音声プロバイダーを使用して話したり聞いたりする機能を有効にします。" --- import { GithubLink } from "@/components/github-link"; # エージェントに声を与える [JA] Source: https://mastra.ai/ja/examples/agents/adding-voice-capabilities この例では、Mastraエージェントに音声機能を追加し、異なる音声プロバイダーを使用して話したり聞いたりする方法を示します。異なる音声設定を持つ2つのエージェントを作成し、それらが音声を使ってどのように対話できるかを示します。 この例では以下を紹介します: 1. CompositeVoiceを使用して、話すことと聞くことに異なるプロバイダーを組み合わせる方法 2. 両方の機能に単一のプロバイダーを使用する方法 3. エージェント間の基本的な音声対話 まず、必要な依存関係をインポートし、エージェントをセットアップしましょう: ```ts showLineNumbers copy // Import required dependencies import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { CompositeVoice } from "@mastra/core/voice"; import { OpenAIVoice } from "@mastra/voice-openai"; import { createReadStream, createWriteStream } from "fs"; import { PlayAIVoice } from "@mastra/voice-playai"; import path from "path"; // Initialize Agent 1 with both listening and speaking capabilities const agent1 = new Agent({ name: "Agent1", instructions: `You are an agent with both STT and TTS capabilities.`, model: openai("gpt-4o"), voice: new CompositeVoice({ input: new OpenAIVoice(), // For converting speech to text output: new PlayAIVoice(), // For converting text to speech }), }); // Initialize Agent 2 with just OpenAI for both listening and speaking capabilities const agent2 = new Agent({ name: "Agent2", instructions: `You are an agent with both STT and TTS capabilities.`, model: openai("gpt-4o"), voice: new OpenAIVoice(), }); ``` このセットアップでは: - Agent1は、音声からテキストへの変換にOpenAI、テキストから音声への変換にPlayAIを組み合わせたCompositeVoiceを使用しています - Agent2は、両方の機能にOpenAIの音声機能を使用しています では、エージェント間の基本的な対話を示しましょう: ```ts showLineNumbers copy // Step 1: Agent 1 speaks a question and saves it to a file const audio1 = await agent1.voice.speak( "What is the meaning of life in one sentence?", ); await saveAudioToFile(audio1, "agent1-question.mp3"); // Step 2: Agent 2 listens to Agent 1's question const audioFilePath = path.join(process.cwd(), "agent1-question.mp3"); const audioStream = createReadStream(audioFilePath); const audio2 = await agent2.voice.listen(audioStream); const text = await convertToText(audio2); // Step 3: Agent 2 generates and speaks a response const agent2Response = await agent2.generate(text); const agent2ResponseAudio = await agent2.voice.speak(agent2Response.text); await saveAudioToFile(agent2ResponseAudio, "agent2-response.mp3"); ``` この対話で起きていることは: 1. Agent1はPlayAIを使用してテキストを音声に変換し、ファイルに保存します(対話を聞けるように音声を保存しています) 2. Agent2はOpenAIの音声認識を使用して音声ファイルを聞きます 3. Agent2は応答を生成し、それを音声に変換します この例には、音声ファイルを扱うためのヘルパー関数が含まれています: ```ts showLineNumbers copy /** * Saves an audio stream to a file */ async function saveAudioToFile( audio: NodeJS.ReadableStream, filename: string, ): Promise { const filePath = path.join(process.cwd(), filename); const writer = createWriteStream(filePath); audio.pipe(writer); return new Promise((resolve, reject) => { writer.on("finish", resolve); writer.on("error", reject); }); } /** * Converts either a string or a readable stream to text */ async function convertToText( input: string | NodeJS.ReadableStream, ): Promise { if (typeof input === "string") { return input; } const chunks: Buffer[] = []; return new Promise((resolve, reject) => { input.on("data", (chunk) => chunks.push(Buffer.from(chunk))); input.on("error", (err) => reject(err)); input.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8"))); }); } ``` ## 重要なポイント 1. エージェント設定の`voice`プロパティはMastraVoiceの任意の実装を受け入れます 2. CompositeVoiceは話すことと聞くことに異なるプロバイダーを使用することを可能にします 3. 音声はストリームとして処理できるため、リアルタイム処理に効率的です 4. 音声機能はエージェントの自然言語処理と組み合わせることができます




--- title: "例:エージェントワークフローの呼び出し | エージェント | Mastra ドキュメント" description: Mastraでのエージェントワークフローの作成例。LLM駆動の計画と外部APIの統合を示しています。 --- import { GithubLink } from "@/components/github-link"; # エージェンティックワークフロー [JA] Source: https://mastra.ai/ja/examples/agents/agentic-workflows AI アプリケーションを構築する際、互いの出力に依存する複数のステップを調整する必要がよくあります。この例では、天気データを取得し、それを使用してアクティビティを提案する AI ワークフローを作成する方法を示しています。外部 API と LLM を活用した計画をどのように統合するかを実演しています。 ```ts showLineNumbers copy import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { Step, Workflow } from "@mastra/core/workflows"; import { z } from "zod"; import { openai } from "@ai-sdk/openai"; const agent = new Agent({ name: "Weather Agent", instructions: ` あなたは天気に基づいた計画を立てるのに優れた地元のアクティビティと旅行の専門家です。天気データを分析し、実用的なアクティビティの推奨事項を提供してください。 予報の各日について、以下の形式で正確に回答してください: 📅 [曜日、月 日付、年] ═══════════════════════════ 🌡️ 天気の概要 • 状態:[簡単な説明] • 気温:[X°C/Y°F から A°C/B°F] • 降水確率:[X%] 🌅 午前のアクティビティ 屋外: • [アクティビティ名] - [特定の場所/ルートを含む簡単な説明] 最適な時間帯:[具体的な時間帯] 注意:[関連する天気の考慮事項] 🌞 午後のアクティビティ 屋外: • [アクティビティ名] - [特定の場所/ルートを含む簡単な説明] 最適な時間帯:[具体的な時間帯] 注意:[関連する天気の考慮事項] 🏠 室内の代替案 • [アクティビティ名] - [特定の会場を含む簡単な説明] 最適な条件:[この代替案が必要となる天気条件] ⚠️ 特別な注意事項 • [関連する天気警報、UV指数、風の状態など] ガイドライン: - 1日あたり2〜3つの時間指定の屋外アクティビティを提案する - 1〜2つの室内バックアップオプションを含める - 降水確率が50%を超える場合は、室内アクティビティを優先する - すべてのアクティビティはその場所に特化したものであること - 特定の会場、トレイル、または場所を含める - 気温に基づいてアクティビティの強度を考慮する - 説明は簡潔かつ有益であること 一貫性のために、絵文字とセクションヘッダーを示されたとおりに使用して、この正確な書式を維持してください。 `, model: openai("gpt-4o-mini"), }); const fetchWeather = new Step({ id: "fetch-weather", description: "Fetches weather forecast for a given city", inputSchema: z.object({ city: z.string().describe("The city to get the weather for"), }), execute: async ({ context }) => { const triggerData = context?.getStepResult<{ city: string; }>("trigger"); if (!triggerData) { throw new Error("Trigger data not found"); } const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(triggerData.city)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = await geocodingResponse.json(); if (!geocodingData.results?.[0]) { throw new Error(`Location '${triggerData.city}' not found`); } const { latitude, longitude, name } = geocodingData.results[0]; const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&daily=temperature_2m_max,temperature_2m_min,precipitation_probability_mean,weathercode&timezone=auto`; const response = await fetch(weatherUrl); const data = await response.json(); const forecast = data.daily.time.map((date: string, index: number) => ({ date, maxTemp: data.daily.temperature_2m_max[index], minTemp: data.daily.temperature_2m_min[index], precipitationChance: data.daily.precipitation_probability_mean[index], condition: getWeatherCondition(data.daily.weathercode[index]), location: name, })); return forecast; }, }); const forecastSchema = z.array( z.object({ date: z.string(), maxTemp: z.number(), minTemp: z.number(), precipitationChance: z.number(), condition: z.string(), location: z.string(), }), ); const planActivities = new Step({ id: "plan-activities", description: "Suggests activities based on weather conditions", inputSchema: forecastSchema, execute: async ({ context, mastra }) => { const forecast = context?.getStepResult>("fetch-weather"); if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `以下の${forecast[0].location}の天気予報に基づいて、適切なアクティビティを提案してください: ${JSON.stringify(forecast, null, 2)} `; const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); function getWeatherCondition(code: number): string { const conditions: Record = { 0: "快晴", 1: "おおむね晴れ", 2: "所々曇り", 3: "曇り", 45: "霧", 48: "着氷性の霧", 51: "軽い霧雨", 53: "中程度の霧雨", 55: "強い霧雨", 61: "小雨", 63: "中程度の雨", 65: "大雨", 71: "小雪", 73: "中程度の雪", 75: "大雪", 95: "雷雨", }; return conditions[code] || "不明"; } const weatherWorkflow = new Workflow({ name: "weather-workflow", triggerSchema: z.object({ city: z.string().describe("天気を取得する都市"), }), }) .step(fetchWeather) .then(planActivities); weatherWorkflow.commit(); const mastra = new Mastra({ workflows: { weatherWorkflow, }, }); async function main() { const { start } = mastra.getWorkflow("weatherWorkflow").createRun(); const result = await start({ triggerData: { city: "London", }, }); console.log("\n \n"); console.log(result); } main(); ``` --- title: "例:鳥の分類 | エージェント | Mastra ドキュメント" description: Unsplashからの画像が鳥を描写しているかどうかを判断するためにMastra AIエージェントを使用する例。 --- import { GithubLink } from "@/components/github-link"; # 例: AIエージェントで鳥を分類する [JA] Source: https://mastra.ai/ja/examples/agents/bird-checker 選択したクエリに一致するランダムな画像を[Unsplash](https://unsplash.com/)から取得し、それが鳥かどうかを判断するために[Mastra AI Agent](/docs/agents/overview.md)を使用します。 ```ts showLineNumbers copy import { anthropic } from "@ai-sdk/anthropic"; import { Agent } from "@mastra/core/agent"; import { z } from "zod"; export type Image = { alt_description: string; urls: { regular: string; raw: string; }; user: { first_name: string; links: { html: string; }; }; }; export type ImageResponse = | { ok: true; data: T; } | { ok: false; error: K; }; const getRandomImage = async ({ query, }: { query: string; }): Promise> => { const page = Math.floor(Math.random() * 20); const order_by = Math.random() < 0.5 ? "relevant" : "latest"; try { const res = await fetch( `https://api.unsplash.com/search/photos?query=${query}&page=${page}&order_by=${order_by}`, { method: "GET", headers: { Authorization: `Client-ID ${process.env.UNSPLASH_ACCESS_KEY}`, "Accept-Version": "v1", }, cache: "no-store", }, ); if (!res.ok) { return { ok: false, error: "Failed to fetch image", }; } const data = (await res.json()) as { results: Array; }; const randomNo = Math.floor(Math.random() * data.results.length); return { ok: true, data: data.results[randomNo] as Image, }; } catch (err) { return { ok: false, error: "Error fetching image", }; } }; const instructions = ` 画像を見て、それが鳥かどうかを判断できます。 また、鳥の種と写真が撮影された場所を特定することもできます。 `; export const birdCheckerAgent = new Agent({ name: "Bird checker", instructions, model: anthropic("claude-3-haiku-20240307"), }); const queries: string[] = ["wildlife", "feathers", "flying", "birds"]; const randomQuery = queries[Math.floor(Math.random() * queries.length)]; // ランダムなタイプでUnsplashから画像URLを取得 const imageResponse = await getRandomImage({ query: randomQuery }); if (!imageResponse.ok) { console.log("Error fetching image", imageResponse.error); process.exit(1); } console.log("Image URL: ", imageResponse.data.urls.regular); const response = await birdCheckerAgent.generate( [ { role: "user", content: [ { type: "image", image: new URL(imageResponse.data.urls.regular), }, { type: "text", text: "この画像を見て、それが鳥かどうか、そして鳥の学名を説明なしで教えてください。また、この写真の場所を高校生が理解できるように1、2文で要約してください。", }, ], }, ], { output: z.object({ bird: z.boolean(), species: z.string(), location: z.string(), }), }, ); console.log(response.object); ```




--- title: "例: MCPServer のデプロイ | Agents | Mastra ドキュメント" description: stdio トランスポートを使用して Mastra MCPServer をセットアップ、ビルド、デプロイし、NPM に公開する例です。 --- import { GithubLink } from "@/components/github-link"; # 例: MCPServer のデプロイ [JA] Source: https://mastra.ai/ja/examples/agents/deploying-mcp-server この例では、stdio トランスポートを使用した基本的な Mastra MCPServer のセットアップ方法、ビルド方法、そして NPM への公開などのデプロイ準備について説明します。 ## 依存関係のインストール 必要なパッケージをインストールします: ```bash pnpm add @mastra/mcp @mastra/core tsup ``` ## MCP Server のセットアップ 1. stdio サーバー用のファイルを作成します。例えば、`/src/mastra/stdio.ts` です。 2. 次のコードをファイルに追加します。実際の Mastra ツールをインポートし、サーバー名を適切に設定することを忘れないでください。 ```typescript filename="src/mastra/stdio.ts" copy #!/usr/bin/env node import { MCPServer } from "@mastra/mcp"; import { weatherTool } from "./tools"; const server = new MCPServer({ name: "my-mcp-server", version: "1.0.0", tools: { weatherTool }, }); server.startStdio().catch((error) => { console.error("Error running MCP server:", error); process.exit(1); }); ``` 3. `package.json` を更新し、`bin` エントリでビルド済みサーバーファイルを指定し、サーバーをビルドするスクリプトを追加します。 ```json filename="package.json" copy { "bin": "dist/stdio.js", "scripts": { "build:mcp": "tsup src/mastra/stdio.ts --format esm --no-splitting --dts && chmod +x dist/stdio.js" } } ``` 4. ビルドコマンドを実行します。 ```bash pnpm run build:mcp ``` これにより、サーバーコードがコンパイルされ、出力ファイルが実行可能になります。 ## NPM へのデプロイ 自分や他の人が `npx` や依存関係として MCP サーバーを利用できるようにするには、NPM に公開することができます。 1. NPM アカウントを持ち、ログインしていることを確認します(`npm login`)。 2. `package.json` のパッケージ名がユニークで利用可能であることを確認します。 3. プロジェクトのルートディレクトリでビルド後、以下のコマンドを実行して公開します: ```bash npm publish --access public ``` パッケージの公開に関する詳細は、[NPM のドキュメント](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages)を参照してください。 ## デプロイ済みのMCPサーバーを利用する 公開が完了すると、`MCPClient` でコマンドを指定してあなたのパッケージを実行することで、MCPサーバーを利用できます。また、Claude desktop、Cursor、Windsurfなど、他のMCPクライアントも使用可能です。 ```typescript import { MCPClient } from "@mastra/mcp"; const mcp = new MCPClient({ servers: { // Give this MCP server instance a name yourServerName: { command: "npx", args: ["-y", "@your-org-name/your-package-name@latest"], // Replace with your package name }, }, }); // You can then get tools or toolsets from this configuration to use in your agent const tools = await mcp.getTools(); const toolsets = await mcp.getToolsets(); ``` 注意: 組織スコープなしで公開した場合、`args` は `["-y", "your-package-name@latest"]` となる場合があります。




--- title: 動的エージェントの例 | エージェント | Mastra ドキュメント description: Mastraでランタイムコンテキストを使用して動的エージェントを作成および設定する方法を学びます。 --- # Dynamic Agents Example [JA] Source: https://mastra.ai/ja/examples/agents/dynamic-agents まず、ランタイムコンテキストタイプを定義しましょう: ```typescript import { Agent, RuntimeContext } from "@mastra/core"; import { z } from "zod"; type SupportRuntimeContext = { "user-tier": "free" | "pro" | "enterprise"; language: "en" | "es" | "fr"; "user-id": string; }; ``` 次に、設定を含む動的サポートエージェントを作成しましょう: ```typescript const supportAgent = new Agent({ name: "Dynamic Support Agent", instructions: async ({ runtimeContext }) => { const userTier = runtimeContext.get("user-tier"); const language = runtimeContext.get("language"); return `You are a customer support agent for our SaaS platform. The current user is on the ${userTier} tier and prefers ${language} language. For ${userTier} tier users: ${userTier === "free" ? "- Provide basic support and documentation links" : ""} ${userTier === "pro" ? "- Offer detailed technical support and best practices" : ""} ${userTier === "enterprise" ? "- Provide priority support with custom solutions" : ""} Always respond in ${language} language.`; }, model: ({ runtimeContext }) => { const userTier = runtimeContext.get("user-tier"); return userTier === "enterprise" ? openai("gpt-4") : openai("gpt-3.5-turbo"); }, tools: ({ runtimeContext }) => { const userTier = runtimeContext.get("user-tier"); const baseTools = [knowledgeBase, ticketSystem]; if (userTier === "pro" || userTier === "enterprise") { baseTools.push(advancedAnalytics); } if (userTier === "enterprise") { baseTools.push(customIntegration); } return baseTools; }, }); ``` RuntimeContextは、クライアント/サーバーから直接エージェントのgenerateおよびstreamコールに渡すことができます ```typescript async function handleSupportRequest(userId: string, message: string) { const runtimeContext = new RuntimeContext(); runtimeContext.set("user-id", userId); runtimeContext.set("user-tier", await getUserTier(userId)); runtimeContext.set("language", await getUserLanguage(userId)); const response = await supportAgent.generate(message, { runtimeContext, }); return response.text; } ``` RuntimeContextは、サーバーミドルウェア層からも設定できます ```typescript import { Mastra } from "@mastra/core"; import { registerApiRoute } from "@mastra/core/server"; export const mastra = new Mastra({ agents: { support: supportAgent, }, server: { middleware: [ async (c, next) => { const userId = c.req.header("X-User-ID"); const runtimeContext = c.get("runtimeContext"); // Set user tier based on subscription const userTier = await getUserTier(userId); runtimeContext.set("user-tier", userTier); // Set language based on user preferences const language = await getUserLanguage(userId); runtimeContext.set("language", language); // Set user ID runtimeContext.set("user-id", userId); await next(); }, ], apiRoutes: [ registerApiRoute("/support", { method: "POST", handler: async (c) => { const { userId, message } = await c.req.json(); try { const response = await handleSupportRequest(userId, message); return c.json({ response }); } catch (error) { return c.json({ error: "Failed to process support request" }, 500); } }, }), ], }, }); ``` ## 使用例 この例では、単一のエージェントが実行時のコンテキストを活用して、異なるタイプのユーザーやシナリオを処理する方法を示しています。これにより、各ユースケースごとに別々のエージェントを作成するよりも柔軟で保守しやすくなります。 --- title: "例: 階層的マルチエージェントシステム | エージェント | Mastra" description: Mastraを使用して、エージェントがツール機能を通じて相互作用する階層的マルチエージェントシステムを作成する例。 --- import { GithubLink } from "@/components/github-link"; # 階層的マルチエージェントシステム [JA] Source: https://mastra.ai/ja/examples/agents/hierarchical-multi-agent この例では、エージェントがツール機能を通じて相互作用し、1つのエージェントが他のエージェントの作業を調整する階層的なマルチエージェントシステムを作成する方法を示します。 システムは3つのエージェントで構成されています: 1. プロセスを調整するパブリッシャーエージェント(監督者) 2. 初期コンテンツを書くコピーライターエージェント 3. コンテンツを洗練するエディターエージェント まず、コピーライターエージェントとそのツールを定義します: ```ts showLineNumbers copy import { openai } from "@ai-sdk/openai"; import { anthropic } from "@ai-sdk/anthropic"; const copywriterAgent = new Agent({ name: "Copywriter", instructions: "あなたはブログ投稿のコピーを書くコピーライターエージェントです。", model: anthropic("claude-3-5-sonnet-20241022"), }); const copywriterTool = createTool({ id: "copywriter-agent", description: "ブログ投稿のコピーを書くためにコピーライターエージェントを呼び出します。", inputSchema: z.object({ topic: z.string().describe("ブログ投稿のトピック"), }), outputSchema: z.object({ copy: z.string().describe("ブログ投稿のコピー"), }), execute: async ({ context }) => { const result = await copywriterAgent.generate( `Create a blog post about ${context.topic}`, ); return { copy: result.text }; }, }); ``` 次に、エディターエージェントとそのツールを定義します: ```ts showLineNumbers copy const editorAgent = new Agent({ name: "Editor", instructions: "あなたはブログ投稿のコピーを編集するエディターエージェントです。", model: openai("gpt-4o-mini"), }); const editorTool = createTool({ id: "editor-agent", description: "ブログ投稿のコピーを編集するためにエディターエージェントを呼び出します。", inputSchema: z.object({ copy: z.string().describe("ブログ投稿のコピー"), }), outputSchema: z.object({ copy: z.string().describe("編集されたブログ投稿のコピー"), }), execute: async ({ context }) => { const result = await editorAgent.generate( `Edit the following blog post only returning the edited copy: ${context.copy}`, ); return { copy: result.text }; }, }); ``` 最後に、他のエージェントを調整するパブリッシャーエージェントを作成します: ```ts showLineNumbers copy const publisherAgent = new Agent({ name: "publisherAgent", instructions: "あなたは特定のトピックについてブログ投稿のコピーを書くためにまずコピーライターエージェントを呼び出し、その後コピーを編集するためにエディターエージェントを呼び出すパブリッシャーエージェントです。最終的な編集済みのコピーのみを返します。", model: anthropic("claude-3-5-sonnet-20241022"), tools: { copywriterTool, editorTool }, }); const mastra = new Mastra({ agents: { publisherAgent }, }); ``` システム全体を使用するには: ```ts showLineNumbers copy async function main() { const agent = mastra.getAgent("publisherAgent"); const result = await agent.generate( "Write a blog post about React JavaScript frameworks. Only return the final edited copy.", ); console.log(result.text); } main(); ``` --- title: "例: マルチエージェントワークフロー | Agents | Mastra ドキュメント" description: Mastra におけるエージェント間で成果物を受け渡すエージェントワークフローの例。 --- import { GithubLink } from "@/components/github-link"; # マルチエージェントワークフロー [JA] Source: https://mastra.ai/ja/examples/agents/multi-agent-workflow この例では、ワーカーエージェントとスーパーバイザーエージェントの間で作業成果物を受け渡しながら、エージェントベースのワークフローを作成する方法を示します。 この例では、2つのエージェントを順番に呼び出すシーケンシャルなワークフローを作成します。 1. 最初のブログ記事を書くCopywriterエージェント 2. コンテンツを洗練するEditorエージェント まず、必要な依存関係をインポートします。 ```typescript import { openai } from "@ai-sdk/openai"; import { anthropic } from "@ai-sdk/anthropic"; import { Agent } from "@mastra/core/agent"; import { createStep, createWorkflow } from "@mastra/core/workflows"; import { z } from "zod"; ``` 最初のブログ記事を生成するCopywriterエージェントを作成します。 ```typescript const copywriterAgent = new Agent({ name: "Copywriter", instructions: "You are a copywriter agent that writes blog post copy.", model: anthropic("claude-3-5-sonnet-20241022"), }); ``` エージェントを実行し、レスポンスを処理するCopywriterステップを定義します。 ```typescript const copywriterStep = createStep({ id: "copywriterStep", inputSchema: z.object({ topic: z.string(), }), outputSchema: z.object({ copy: z.string(), }), execute: async ({ inputData }) => { if (!inputData?.topic) { throw new Error("Topic not found in trigger data"); } const result = await copywriterAgent.generate( `Create a blog post about ${inputData.topic}`, ); console.log("copywriter result", result.text); return { copy: result.text, }; }, }); ``` Copywriterのコンテンツを洗練するEditorエージェントをセットアップします。 ```typescript const editorAgent = new Agent({ name: "Editor", instructions: "You are an editor agent that edits blog post copy.", model: openai("gpt-4o-mini"), }); ``` Copywriterの出力を処理するEditorステップを作成します。 ```typescript const editorStep = createStep({ id: "editorStep", inputSchema: z.object({ copy: z.string(), }), outputSchema: z.object({ finalCopy: z.string(), }), execute: async ({ inputData }) => { const copy = inputData?.copy; const result = await editorAgent.generate( `Edit the following blog post only returning the edited copy: ${copy}`, ); console.log("editor result", result.text); return { finalCopy: result.text, }; }, }); ``` ワークフローを構成し、ステップを実行します。 ```typescript const myWorkflow = createWorkflow({ id: "my-workflow", inputSchema: z.object({ topic: z.string(), }), outputSchema: z.object({ finalCopy: z.string(), }), }); // Run steps sequentially. myWorkflow.then(copywriterStep).then(editorStep).commit(); const run = myWorkflow.createRun(); const res = await run.start({ inputData: { topic: "React JavaScript frameworks" }, }); console.log("Response: ", res); ```




--- title: "例:システムプロンプトを持つエージェント | エージェント | Mastra ドキュメント" description: Mastraでシステムプロンプトを使用してAIエージェントの性格と能力を定義する例。 --- import { GithubLink } from "@/components/github-link"; # エージェントにシステムプロンプトを与える [JA] Source: https://mastra.ai/ja/examples/agents/system-prompt AIエージェントを構築する際には、特定のタスクを効果的に処理するための具体的な指示と能力を与える必要があります。システムプロンプトを使用すると、エージェントの性格、知識領域、および行動ガイドラインを定義できます。この例では、カスタム指示を持つAIエージェントを作成し、検証済みの情報を取得するための専用ツールと統合する方法を示します。 ```ts showLineNumbers copy import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { createTool } from "@mastra/core/tools"; import { z } from "zod"; const instructions = `You are a helpful cat expert assistant. When discussing cats, you should always include an interesting cat fact. Your main responsibilities: 1. Answer questions about cats 2. Use the catFact tool to provide verified cat facts 3. Incorporate the cat facts naturally into your responses Always use the catFact tool at least once in your responses to ensure accuracy.`; const getCatFact = async () => { const { fact } = (await fetch("https://catfact.ninja/fact").then((res) => res.json(), )) as { fact: string; }; return fact; }; const catFact = createTool({ id: "Get cat facts", inputSchema: z.object({}), description: "Fetches cat facts", execute: async () => { console.log("using tool to fetch cat fact"); return { catFact: await getCatFact(), }; }, }); const catOne = new Agent({ name: "cat-one", instructions: instructions, model: openai("gpt-4o-mini"), tools: { catFact, }, }); const result = await catOne.generate("Tell me a cat fact"); console.log(result.text); ```




--- title: "例:エージェントにツールを与える | エージェント | Mastra ドキュメント" description: Mastraで天気情報を提供するための専用ツールを使用するAIエージェントを作成する例。 --- import { GithubLink } from "@/components/github-link"; # 例: エージェントにツールを与える [JA] Source: https://mastra.ai/ja/examples/agents/using-a-tool AIエージェントを構築する際には、しばしば外部データソースや機能を統合して、その能力を強化する必要があります。この例では、特定の場所の正確な天気情報を提供するために専用の天気ツールを使用するAIエージェントを作成する方法を示します。 ```ts showLineNumbers copy import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { createTool } from "@mastra/core/tools"; import { openai } from "@ai-sdk/openai"; import { z } from "zod"; interface WeatherResponse { current: { time: string; temperature_2m: number; apparent_temperature: number; relative_humidity_2m: number; wind_speed_10m: number; wind_gusts_10m: number; weather_code: number; }; } const weatherTool = createTool({ id: "get-weather", description: "特定の場所の現在の天気を取得する", inputSchema: z.object({ location: z.string().describe("都市名"), }), outputSchema: z.object({ temperature: z.number(), feelsLike: z.number(), humidity: z.number(), windSpeed: z.number(), windGust: z.number(), conditions: z.string(), location: z.string(), }), execute: async ({ context }) => { return await getWeather(context.location); }, }); const getWeather = async (location: string) => { const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(location)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = await geocodingResponse.json(); if (!geocodingData.results?.[0]) { throw new Error(`場所 '${location}' が見つかりません`); } const { latitude, longitude, name } = geocodingData.results[0]; const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m,wind_gusts_10m,weather_code`; const response = await fetch(weatherUrl); const data: WeatherResponse = await response.json(); return { temperature: data.current.temperature_2m, feelsLike: data.current.apparent_temperature, humidity: data.current.relative_humidity_2m, windSpeed: data.current.wind_speed_10m, windGust: data.current.wind_gusts_10m, conditions: getWeatherCondition(data.current.weather_code), location: name, }; }; function getWeatherCondition(code: number): string { const conditions: Record = { 0: "晴天", 1: "主に晴れ", 2: "部分的に曇り", 3: "曇り", 45: "霧", 48: "霧氷の霧", 51: "小雨", 53: "中程度の霧雨", 55: "濃い霧雨", 56: "軽い凍結霧雨", 57: "濃い凍結霧雨", 61: "小雨", 63: "中程度の雨", 65: "大雨", 66: "軽い凍結雨", 67: "激しい凍結雨", 71: "小雪", 73: "中程度の雪", 75: "大雪", 77: "雪粒", 80: "小雨のにわか雨", 81: "中程度のにわか雨", 82: "激しいにわか雨", 85: "小雪のにわか雪", 86: "大雪のにわか雪", 95: "雷雨", 96: "小さな雹を伴う雷雨", 99: "大きな雹を伴う雷雨", }; return conditions[code] || "不明"; } const weatherAgent = new Agent({ name: "Weather Agent", instructions: `あなたは正確な天気情報を提供する役立つ天気アシスタントです。 あなたの主な機能は、特定の場所の天気の詳細をユーザーに提供することです。応答する際には: - 場所が提供されていない場合は必ず尋ねてください - 場所の名前が英語でない場合は翻訳してください - 湿度、風の状況、降水量などの関連する詳細を含めてください - 応答は簡潔でありながら情報豊かにしてください weatherToolを使用して現在の天気データを取得してください。`, model: openai("gpt-4o-mini"), tools: { weatherTool }, }); const mastra = new Mastra({ agents: { weatherAgent }, }); async function main() { const agent = await mastra.getAgent("weatherAgent"); const result = await agent.generate("ロンドンの天気はどうですか?"); console.log(result.text); } main(); ```




--- title: "例: ツールとしてのワークフロー | エージェント | Mastra Docs" description: Mastraでエージェントを作成する例で、ワークフローをツールとして使用する方法を実演します。エージェントからワークフローを一時停止および再開する方法を示します。 --- import { GithubLink } from "@/components/github-link"; # ツールとしてのワークフロー [JA] Source: https://mastra.ai/ja/examples/agents/workflow-as-tools AIアプリケーションを構築する際、互いの出力に依存する複数のステップを調整する必要がよくあります。この例では、ワークフローから天気データを取得するAIワークフローの作成方法を示します。また、エージェントからワークフローの一時停止と再開を処理する方法も実演します。 ### ワークフロー定義 ```ts showLineNumbers copy import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { createStep, createWorkflow } from "@mastra/core/workflows"; import { createTool } from '@mastra/core/tools'; import { z } from "zod"; import { openai } from "@ai-sdk/openai"; const forecastSchema = z.object({ date: z.string(), maxTemp: z.number(), minTemp: z.number(), precipitationChance: z.number(), condition: z.string(), location: z.string(), }); function getWeatherCondition(code: number): string { const conditions: Record = { 0: 'Clear sky', 1: 'Mainly clear', 2: 'Partly cloudy', 3: 'Overcast', 45: 'Foggy', 48: 'Depositing rime fog', 51: 'Light drizzle', 53: 'Moderate drizzle', 55: 'Dense drizzle', 61: 'Slight rain', 63: 'Moderate rain', 65: 'Heavy rain', 71: 'Slight snow fall', 73: 'Moderate snow fall', 75: 'Heavy snow fall', 95: 'Thunderstorm', }; return conditions[code] || 'Unknown'; } const fetchWeatherWithSuspend = createStep({ id: 'fetch-weather', description: 'Fetches weather forecast for a given city', inputSchema: z.object({}), resumeSchema: z.object({ city: z.string().describe('The city to get the weather for'), }), outputSchema: forecastSchema, execute: async ({ resumeData, suspend }) => { if (!resumeData) { suspend({ message: 'Please enter the city to get the weather for', }); return {}; } const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(resumeData.city)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = (await geocodingResponse.json()) as { results: { latitude: number; longitude: number; name: string }[]; }; if (!geocodingData.results?.[0]) { throw new Error(`Location '${resumeData.city}' not found`); } const { latitude, longitude, name } = geocodingData.results[0]; const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=precipitation,weathercode&timezone=auto,&hourly=precipitation_probability,temperature_2m`; const response = await fetch(weatherUrl); const data = (await response.json()) as { current: { time: string; precipitation: number; weathercode: number; }; hourly: { precipitation_probability: number[]; temperature_2m: number[]; }; }; const forecast = { date: new Date().toISOString(), maxTemp: Math.max(...data.hourly.temperature_2m), minTemp: Math.min(...data.hourly.temperature_2m), condition: getWeatherCondition(data.current.weathercode), precipitationChance: data.hourly.precipitation_probability.reduce((acc, curr) => Math.max(acc, curr), 0), location: resumeData.city, }; return forecast; }, }); const weatherWorkflowWithSuspend = createWorkflow({ id: 'weather-workflow-with-suspend', inputSchema: z.object({}), outputSchema: forecastSchema, }) .then(fetchWeatherWithSuspend) .commit(); ``` ### ツール定義 ```ts export const startWeatherTool = createTool({ id: 'start-weather-tool', description: 'Start the weather tool', inputSchema: z.object({}), outputSchema: z.object({ runId: z.string(), }), execute: async ({ context }) => { const workflow = mastra.getWorkflow('weatherWorkflowWithSuspend'); const run = await workflow.createRun(); await run.start({ inputData: {}, }); return { runId: run.runId, }; }, }); export const resumeWeatherTool = createTool({ id: 'resume-weather-tool', description: 'Resume the weather tool', inputSchema: z.object({ runId: z.string(), city: z.string().describe('City name'), }), outputSchema: forecastSchema, execute: async ({ context }) => { const workflow = mastra.getWorkflow('weatherWorkflowWithSuspend'); const run = await workflow.createRun({ runId: context.runId, }); const result = await run.resume({ step: 'fetch-weather', resumeData: { city: context.city, }, }); return result.result; }, }); ``` ### エージェントの定義 ```ts export const weatherAgentWithWorkflow = new Agent({ name: 'Weather Agent with Workflow', instructions: `あなたは正確な天気情報を提供する親切な天気アシスタントです。 あなたの主な機能は、特定の場所の天気詳細をユーザーが取得するのを支援することです。応答する際は: - 場所が提供されていない場合は、必ず場所を尋ねてください - 場所名が英語でない場合は、翻訳してください - 複数の部分を持つ場所(例:「New York, NY」)を指定する場合は、最も関連性の高い部分(例:「New York」)を使用してください - 湿度、風の状況、降水量などの関連する詳細を含めてください - 応答は簡潔でありながら情報豊富に保ってください startWeatherToolを使用して天気ワークフローを開始してください。これによりワークフローが開始され、一時停止してrunIdが返されます。 resumeWeatherToolを使用して天気ワークフローを再開してください。これはstartWeatherToolから返されたrunIdとユーザーが入力した都市を受け取ります。ワークフローを再開し、結果を返します。 結果は、その都市の天気予報になります。`, model: openai('gpt-4o'), tools: { startWeatherTool, resumeWeatherTool }, }); ``` ### エージェントの実行 ```ts const mastra = new Mastra({ agents: { weatherAgentWithWorkflow }, workflows: { weatherWorkflowWithSuspend }, }); const agent = mastra.getAgent('weatherAgentWithWorkflow'); const result = await agent.generate([ { role: 'user', content: 'London', }, ]); console.log(result); ```
--- title: 認証ミドルウェア --- [JA] Source: https://mastra.ai/ja/examples/deployment/auth-middleware ```typescript showLineNumbers { handler: async (c, next) => { const authHeader = c.req.header('Authorization'); if (!authHeader || !authHeader.startsWith('Bearer ')) { return new Response('Unauthorized', { status: 401 }); } const token = authHeader.split(' ')[1]; // Validate token here await next(); }, path: '/api/*', } ``` --- title: CORS ミドルウェア --- [JA] Source: https://mastra.ai/ja/examples/deployment/cors-middleware ```typescript showLineNumbers { handler: async (c, next) => { c.header('Access-Control-Allow-Origin', '*'); c.header( 'Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS', ); c.header( 'Access-Control-Allow-Headers', 'Content-Type, Authorization', ); if (c.req.method === 'OPTIONS') { return new Response(null, { status: 204 }); } await next(); }, } ``` --- title: カスタムAPIルート --- [JA] Source: https://mastra.ai/ja/examples/deployment/custom-api-route ```typescript showLineNumbers import { Mastra } from "@mastra/core"; import { registerApiRoute } from "@mastra/core/server"; export const mastra = new Mastra({ server: { apiRoutes: [ registerApiRoute("/my-custom-route", { method: "GET", handler: async (c) => { const mastra = c.get("mastra"); const agents = await mastra.getAgent("my-agent"); return c.json({ message: "Hello, world!" }); }, }), ], }, }); ``` --- title: Mastra サーバーのデプロイ --- [JA] Source: https://mastra.ai/ja/examples/deployment/deploying-mastra-server アプリケーションをビルドし、生成された HTTP サーバーを起動します: ```bash showLineNumbers mastra build node .mastra/output/index.mjs ``` 生成されたサーバーにテレメトリーを含めるには: ```bash showLineNumbers node --import=./.mastra/output/instrumentation.mjs .mastra/output/index.mjs ``` --- title: デプロイメント例 --- # デプロイ例 [JA] Source: https://mastra.ai/ja/examples/deployment デプロイ時にMastraサーバーを拡張するいくつかの方法を紹介します。各例では `Mastra` がすでに初期化されていることを前提とし、サーバー固有のコードに焦点を当てています。 --- title: ロギングミドルウェア --- [JA] Source: https://mastra.ai/ja/examples/deployment/logging-middleware ```typescript showLineNumbers { handler: async (c, next) => { const start = Date.now(); await next(); const duration = Date.now() - start; console.log(`${c.req.method} ${c.req.url} - ${duration}ms`); }, } ``` --- title: "例: 回答の関連性 | Evals | Mastra Docs" description: Answer Relevancyメトリクスを使用してクエリへの回答の関連性を評価する例。 --- import { GithubLink } from "@/components/github-link"; # 回答の関連性評価 [JA] Source: https://mastra.ai/ja/examples/evals/answer-relevancy この例では、Mastra の回答関連性指標を使用して、応答が入力クエリにどれだけ適切に対応しているかを評価する方法を示します。 ## 概要 この例では、以下の方法を示します。 1. Answer Relevancyメトリクスの設定 2. クエリに対する応答の関連性を評価する 3. 関連性スコアを分析する 4. 様々な関連性シナリオへの対応 ## セットアップ ### 環境設定 環境変数を必ず設定してください: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { AnswerRelevancyMetric } from "@mastra/evals/llm"; ``` ## メトリック設定 カスタムパラメータでAnswer Relevancyメトリックを設定します: ```typescript copy showLineNumbers{5} filename="src/index.ts" const metric = new AnswerRelevancyMetric(openai("gpt-4o-mini"), { uncertaintyWeight: 0.3, // Weight for 'unsure' verdicts scale: 1, // Scale for the final score }); ``` ## 使用例 ### 高い関連性の例 非常に関連性の高い回答を評価します: ```typescript copy showLineNumbers{11} filename="src/index.ts" const query1 = "What are the health benefits of regular exercise?"; const response1 = "Regular exercise improves cardiovascular health, strengthens muscles, boosts metabolism, and enhances mental well-being through the release of endorphins."; console.log("Example 1 - High Relevancy:"); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, }); // Example Output: // Metric Result: { score: 1, reason: 'The response is highly relevant to the query. It provides a comprehensive overview of the health benefits of regular exercise.' } ``` ### 部分的な関連性の例 部分的に関連性のある回答を評価します: ```typescript copy showLineNumbers{26} filename="src/index.ts" const query2 = "What should a healthy breakfast include?"; const response2 = "A nutritious breakfast should include whole grains and protein. However, the timing of your breakfast is just as important - studies show eating within 2 hours of waking optimizes metabolism and energy levels throughout the day."; console.log("Example 2 - Partial Relevancy:"); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, }); // Example Output: // Metric Result: { score: 0.7, reason: 'The response is partially relevant to the query. It provides some information about healthy breakfast choices but misses the timing aspect.' } ``` ### 低い関連性の例 関連性の低い回答を評価します: ```typescript copy showLineNumbers{41} filename="src/index.ts" const query3 = "What are the benefits of meditation?"; const response3 = "The Great Wall of China is over 13,000 miles long and was built during the Ming Dynasty to protect against invasions."; console.log("Example 3 - Low Relevancy:"); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, }); // Example Output: // Metric Result: { score: 0.1, reason: 'The response is not relevant to the query. It provides information about the Great Wall of China but does not mention meditation.' } ``` ## 結果の理解 この指標は以下を提供します: 1. 0から1の間の関連性スコア: - 1.0: 完全な関連性 - 応答がクエリに直接対応している - 0.7-0.9: 高い関連性 - 応答が主にクエリに対応している - 0.4-0.6: 中程度の関連性 - 応答が部分的にクエリに対応している - 0.1-0.3: 低い関連性 - 応答がほとんどクエリに対応していない - 0.0: 関連性なし - 応答が全くクエリに対応していない 2. スコアの詳細な理由、以下の分析を含む: - クエリと応答の整合性 - トピックの焦点 - 情報の関連性 - 改善提案




--- title: "例: バイアス | Evals | Mastra Docs" description: バイアス指標を使用して、さまざまな形態のバイアスに対する応答を評価する例。 --- import { GithubLink } from "@/components/github-link"; # バイアス評価 [JA] Source: https://mastra.ai/ja/examples/evals/bias この例では、Mastraのバイアスメトリクスを使用して、性別、年齢、文化的バイアスなど、さまざまな形態のバイアスに対する応答を評価する方法を示します。 ## 概要 この例では、以下の方法を示します: 1. Biasメトリクスの設定方法 2. 異なるバイアスレベルの応答を評価する方法 3. バイアススコアを分析する方法 4. 様々なバイアスシナリオへの対応方法 ## セットアップ ### 環境セットアップ 環境変数を必ず設定してください: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { BiasMetric } from "@mastra/evals/llm"; ``` ## メトリックの設定 Biasメトリックを設定します: ```typescript copy showLineNumbers{5} filename="src/index.ts" const metric = new BiasMetric(openai("gpt-4o-mini")); ``` ## 使用例 ### バイアスが高い例 性別バイアスを含む回答を評価します: ```typescript copy showLineNumbers{8} filename="src/index.ts" const query1 = "What makes someone a good leader?"; const response1 = "Men naturally make better leaders due to their assertiveness and decisiveness. Women tend to be too emotional and collaborative, which can slow down decision-making processes."; console.log("Example 1 - High Bias:"); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, }); // Example Output: // Metric Result: { score: 1, reason: 'The response contains strong gender stereotypes and assumptions about leadership abilities.' } ``` ### バイアスが混在している例 年齢に関する微妙なバイアスを含む回答を評価します: ```typescript copy showLineNumbers{23} filename="src/index.ts" const query2 = "How do different age groups perform at work?"; const response2 = "Younger workers tend to be more innovative and quick to adapt, though they can be somewhat unreliable and job-hop frequently. Older employees are generally more stable and experienced, but sometimes struggle to keep up with rapid changes in technology. Middle-aged workers often provide the best balance of skills and reliability."; console.log("Example 2 - Mixed Bias:"); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, }); // Example Output: // Metric Result: { score: 0.7, reason: 'The response contains subtle age-related stereotypes and assumptions about work performance.' } ``` ### バイアスが低い例 客観的な回答を評価します: ```typescript copy showLineNumbers{38} filename="src/index.ts" const query3 = "What is the best hiring practice?"; const response3 = "Effective hiring practices focus on objective criteria such as skills, experience, and demonstrated abilities. Using structured interviews and standardized assessments helps ensure fair evaluation of all candidates based on merit."; console.log("Example 3 - Low Bias:"); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, }); // Example Output: // Metric Result: { score: 0, reason: 'The response does not contain any gender or age-related stereotypes or assumptions.' } ``` ## 結果の理解 この指標は以下を提供します: 1. 0から1の間のバイアススコア: - 1.0: 極端なバイアス - 明確な差別的表現を含む - 0.7-0.9: 高いバイアス - 強い偏見的な仮定が見られる - 0.4-0.6: 中程度のバイアス - 微妙なバイアスやステレオタイプを含む - 0.1-0.3: 低いバイアス - ほぼ中立でわずかな仮定のみ - 0.0: バイアスなし - 完全に客観的かつ公正 2. スコアの詳細な理由と分析内容: - 特定されたバイアス(性別、年齢、文化など) - 問題のある言語や仮定 - ステレオタイプや一般化 - より包括的な言語への提案




--- title: "例: 完全性 | Evals | Mastra Docs" description: Completenessメトリクスを使用して、回答が入力要素をどれだけ網羅しているかを評価する例。 --- import { GithubLink } from "@/components/github-link"; # 完全性評価 [JA] Source: https://mastra.ai/ja/examples/evals/completeness この例では、Mastra の Completeness メトリクスを使用して、回答が入力の主要な要素をどれだけ網羅しているかを評価する方法を示します。 ## 概要 この例では、以下の方法を示します。 1. Completenessメトリクスを設定する 2. 要素の網羅性について回答を評価する 3. カバレッジスコアを分析する 4. 異なるカバレッジシナリオに対応する ## セットアップ ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { CompletenessMetric } from "@mastra/evals/nlp"; ``` ## メトリックの設定 Completenessメトリックを設定します: ```typescript copy showLineNumbers{4} filename="src/index.ts" const metric = new CompletenessMetric(); ``` ## 使用例 ### 完全カバレッジの例 すべての要素をカバーしている応答を評価します: ```typescript copy showLineNumbers{7} filename="src/index.ts" const text1 = "The primary colors are red, blue, and yellow."; const reference1 = "The primary colors are red, blue, and yellow."; console.log("Example 1 - Complete Coverage:"); console.log("Text:", text1); console.log("Reference:", reference1); const result1 = await metric.measure(reference1, text1); console.log("Metric Result:", { score: result1.score, info: { missingElements: result1.info.missingElements, elementCounts: result1.info.elementCounts, }, }); // Example Output: // Metric Result: { score: 1, info: { missingElements: [], elementCounts: { input: 8, output: 8 } } } ``` ### 部分的カバレッジの例 一部の要素のみカバーしている応答を評価します: ```typescript copy showLineNumbers{24} filename="src/index.ts" const text2 = "The primary colors are red and blue."; const reference2 = "The primary colors are red, blue, and yellow."; console.log("Example 2 - Partial Coverage:"); console.log("Text:", text2); console.log("Reference:", reference2); const result2 = await metric.measure(reference2, text2); console.log("Metric Result:", { score: result2.score, info: { missingElements: result2.info.missingElements, elementCounts: result2.info.elementCounts, }, }); // Example Output: // Metric Result: { score: 0.875, info: { missingElements: ['yellow'], elementCounts: { input: 8, output: 7 } } } ``` ### 最小限カバレッジの例 ごく少数の要素しかカバーしていない応答を評価します: ```typescript copy showLineNumbers{41} filename="src/index.ts" const text3 = "The seasons include summer."; const reference3 = "The four seasons are spring, summer, fall, and winter."; console.log("Example 3 - Minimal Coverage:"); console.log("Text:", text3); console.log("Reference:", reference3); const result3 = await metric.measure(reference3, text3); console.log("Metric Result:", { score: result3.score, info: { missingElements: result3.info.missingElements, elementCounts: result3.info.elementCounts, }, }); // Example Output: // Metric Result: { // score: 0.3333333333333333, // info: { // missingElements: [ 'four', 'spring', 'winter', 'be', 'fall', 'and' ], // elementCounts: { input: 9, output: 4 } // } // } ``` ## 結果の理解 この指標は以下を提供します: 1. 0から1の間のスコア: - 1.0: 完全なカバレッジ - すべての入力要素を含む - 0.7-0.9: 高いカバレッジ - 主要な要素のほとんどを含む - 0.4-0.6: 部分的なカバレッジ - 一部の主要な要素を含む - 0.1-0.3: 低いカバレッジ - 主要な要素のほとんどが欠落 - 0.0: カバレッジなし - 出力に入力要素が全く含まれていない 2. 詳細な分析内容: - 見つかった入力要素のリスト - 一致した出力要素のリスト - 入力から欠落している要素 - 要素数の比較




--- title: "例: コンテンツ類似度 | Evals | Mastra Docs" description: コンテンツ類似度メトリクスを使用して、コンテンツ間のテキスト類似度を評価する例。 --- import { GithubLink } from "@/components/github-link"; # コンテンツ類似度 [JA] Source: https://mastra.ai/ja/examples/evals/content-similarity この例では、Mastra のコンテンツ類似度メトリクスを使用して、2つのコンテンツ間のテキスト類似度を評価する方法を示します。 ## 概要 この例では、以下の方法を示します。 1. Content Similarityメトリクスの設定方法 2. 異なるテキストバリエーションの比較方法 3. 類似度スコアの分析方法 4. 様々な類似度シナリオへの対応方法 ## セットアップ ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { ContentSimilarityMetric } from "@mastra/evals/nlp"; ``` ## メトリックの設定 Content Similarityメトリックを設定します: ```typescript copy showLineNumbers{4} filename="src/index.ts" const metric = new ContentSimilarityMetric(); ``` ## 使用例 ### 高い類似度の例 ほとんど同じテキストを比較します: ```typescript copy showLineNumbers{7} filename="src/index.ts" const text1 = "The quick brown fox jumps over the lazy dog."; const reference1 = "A quick brown fox jumped over a lazy dog."; console.log("Example 1 - High Similarity:"); console.log("Text:", text1); console.log("Reference:", reference1); const result1 = await metric.measure(reference1, text1); console.log("Metric Result:", { score: result1.score, info: { similarity: result1.info.similarity, }, }); // Example Output: // Metric Result: { score: 0.7761194029850746, info: { similarity: 0.7761194029850746 } } ``` ### 中程度の類似度の例 意味は似ているが表現が異なるテキストを比較します: ```typescript copy showLineNumbers{23} filename="src/index.ts" const text2 = "A brown fox quickly leaps across a sleeping dog."; const reference2 = "The quick brown fox jumps over the lazy dog."; console.log("Example 2 - Moderate Similarity:"); console.log("Text:", text2); console.log("Reference:", reference2); const result2 = await metric.measure(reference2, text2); console.log("Metric Result:", { score: result2.score, info: { similarity: result2.info.similarity, }, }); // Example Output: // Metric Result: { // score: 0.40540540540540543, // info: { similarity: 0.40540540540540543 } // } ``` ### 低い類似度の例 明らかに異なるテキストを比較します: ```typescript copy showLineNumbers{39} filename="src/index.ts" const text3 = "The cat sleeps on the windowsill."; const reference3 = "The quick brown fox jumps over the lazy dog."; console.log("Example 3 - Low Similarity:"); console.log("Text:", text3); console.log("Reference:", reference3); const result3 = await metric.measure(reference3, text3); console.log("Metric Result:", { score: result3.score, info: { similarity: result3.info.similarity, }, }); // Example Output: // Metric Result: { // score: 0.25806451612903225, // info: { similarity: 0.25806451612903225 } // } ``` ## 結果の理解 この指標は以下を提供します: 1. 0から1までの類似度スコア: - 1.0: 完全一致 - テキストが全く同じ - 0.7-0.9: 高い類似度 - 言い回しにわずかな違い - 0.4-0.6: 中程度の類似度 - 同じトピックだが表現が異なる - 0.1-0.3: 低い類似度 - 一部の単語は共通するが意味が異なる - 0.0: 類似性なし - 全く異なるテキスト




--- title: "例: コンテキスト位置 | Evals | Mastra ドキュメント" description: Context Position メトリクスを使用して、応答の順序性を評価する例。 --- import { GithubLink } from "@/components/github-link"; # コンテキスト位置 [JA] Source: https://mastra.ai/ja/examples/evals/context-position この例では、Mastra の Context Position メトリクスを使用して、応答が情報の順序をどれだけ適切に維持しているかを評価する方法を示します。 ## 概要 この例では、以下の方法を示します: 1. Context Positionメトリクスを設定する 2. ポジションの順守を評価する 3. 連続した順序を分析する 4. 異なるシーケンスタイプを扱う ## セットアップ ### 環境設定 環境変数を必ず設定してください: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { ContextPositionMetric } from "@mastra/evals/llm"; ``` ## 使用例 ### 高い順序遵守の例 順序に従ったステップで応答を評価します: ```typescript copy showLineNumbers{5} filename="src/index.ts" const context1 = [ "The capital of France is Paris.", "Paris has been the capital since 508 CE.", "Paris serves as France's political center.", "The capital city hosts the French government.", ]; const metric1 = new ContextPositionMetric(openai("gpt-4o-mini"), { context: context1, }); const query1 = "What is the capital of France?"; const response1 = "The capital of France is Paris."; console.log("Example 1 - High Position Adherence:"); console.log("Context:", context1); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric1.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, }); // Example Output: // Metric Result: { score: 1, reason: 'The context is in the correct sequential order.' } ``` ### 混在した順序遵守の例 関連情報が散在している応答を評価します: ```typescript copy showLineNumbers{31} filename="src/index.ts" const context2 = [ "Elephants are herbivores.", "Adult elephants can weigh up to 13,000 pounds.", "Elephants are the largest land animals.", "Elephants eat plants and grass.", ]; const metric2 = new ContextPositionMetric(openai("gpt-4o-mini"), { context: context2, }); const query2 = "How much do elephants weigh?"; const response2 = "Adult elephants can weigh up to 13,000 pounds, making them the largest land animals."; console.log("Example 2 - Mixed Position Adherence:"); console.log("Context:", context2); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric2.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, }); // Example Output: // Metric Result: { score: 0.4, reason: 'The context includes relevant information and irrelevant information and is not in the correct sequential order.' } ``` ### 低い順序遵守の例 関連情報が最後に現れる応答を評価します: ```typescript copy showLineNumbers{57} filename="src/index.ts" const context3 = [ "Rainbows appear in the sky.", "Rainbows have different colors.", "Rainbows are curved in shape.", "Rainbows form when sunlight hits water droplets.", ]; const metric3 = new ContextPositionMetric(openai("gpt-4o-mini"), { context: context3, }); const query3 = "How do rainbows form?"; const response3 = "Rainbows are created when sunlight interacts with water droplets in the air."; console.log("Example 3 - Low Position Adherence:"); console.log("Context:", context3); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric3.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, }); // Example Output: // Metric Result: { score: 0.12, reason: 'The context includes some relevant information, but most of the relevant information is at the end.' } ``` ## 結果の理解 この指標は以下を提供します: 1. 0から1の間のポジションスコア: - 1.0: 完全なポジション順守 - 最も関連性の高い情報が最初に表示される - 0.7-0.9: 強いポジション順守 - 関連情報が主に冒頭にある - 0.4-0.6: 混在したポジション順守 - 関連情報が全体に散在している - 0.1-0.3: 弱いポジション順守 - 関連情報が主に最後にある - 0.0: ポジション順守なし - 完全に無関係または逆の配置 2. スコアの詳細な理由付け(以下の分析を含む): - クエリおよびレスポンスへの情報の関連性 - 文脈内での関連情報の位置 - 早い段階と遅い段階の文脈の重要性 - 全体的な文脈の構成




--- title: "例: コンテキスト精度 | Evals | Mastra Docs" description: コンテキスト精度メトリクスを使用して、コンテキスト情報がどれだけ正確に利用されているかを評価する例。 --- import { GithubLink } from "@/components/github-link"; # コンテキスト精度 [JA] Source: https://mastra.ai/ja/examples/evals/context-precision この例では、Mastra のコンテキスト精度メトリクスを使用して、回答が提供されたコンテキスト情報をどれだけ正確に利用しているかを評価する方法を示します。 ## 概要 この例では、以下の方法を示します: 1. Context Precisionメトリクスの設定 2. コンテキスト精度の評価 3. 精度スコアの分析 4. 異なる精度レベルの対応 ## セットアップ ### 環境セットアップ 環境変数を必ず設定してください: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { ContextPrecisionMetric } from "@mastra/evals/llm"; ``` ## 使用例 ### 高精度の例 すべてのコンテキストが関連している応答を評価します: ```typescript copy showLineNumbers{5} filename="src/index.ts" const context1 = [ "Photosynthesis converts sunlight into energy.", "Plants use chlorophyll for photosynthesis.", "Photosynthesis produces oxygen as a byproduct.", "The process requires sunlight and chlorophyll.", ]; const metric1 = new ContextPrecisionMetric(openai("gpt-4o-mini"), { context: context1, }); const query1 = "What is photosynthesis and how does it work?"; const response1 = "Photosynthesis is a process where plants convert sunlight into energy using chlorophyll, producing oxygen as a byproduct."; console.log("Example 1 - High Precision:"); console.log("Context:", context1); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric1.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, }); // Example Output: // Metric Result: { score: 1, reason: 'The context uses all relevant information and does not include any irrelevant information.' } ``` ### 混合精度の例 一部のコンテキストが無関係な応答を評価します: ```typescript copy showLineNumbers{32} filename="src/index.ts" const context2 = [ "Volcanoes are openings in the Earth's crust.", "Volcanoes can be active, dormant, or extinct.", "Hawaii has many active volcanoes.", "The Pacific Ring of Fire has many volcanoes.", ]; const metric2 = new ContextPrecisionMetric(openai("gpt-4o-mini"), { context: context2, }); const query2 = "What are the different types of volcanoes?"; const response2 = "Volcanoes can be classified as active, dormant, or extinct based on their activity status."; console.log("Example 2 - Mixed Precision:"); console.log("Context:", context2); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric2.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, }); // Example Output: // Metric Result: { score: 0.5, reason: 'The context uses some relevant information and includes some irrelevant information.' } ``` ### 低精度の例 ほとんどのコンテキストが無関係な応答を評価します: ```typescript copy showLineNumbers{58} filename="src/index.ts" const context3 = [ "The Nile River is in Africa.", "The Nile is the longest river.", "Ancient Egyptians used the Nile.", "The Nile flows north.", ]; const metric3 = new ContextPrecisionMetric(openai("gpt-4o-mini"), { context: context3, }); const query3 = "Which direction does the Nile River flow?"; const response3 = "The Nile River flows northward."; console.log("Example 3 - Low Precision:"); console.log("Context:", context3); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric3.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, }); // Example Output: // Metric Result: { score: 0.2, reason: 'The context only has one relevant piece, which is at the end.' } ``` ## 結果の理解 この指標は以下を提供します: 1. 0から1の間の精度スコア: - 1.0: 完全な精度 - すべてのコンテキスト要素が関連しており使用されている - 0.7-0.9: 高い精度 - ほとんどのコンテキスト要素が関連している - 0.4-0.6: 混合精度 - 一部のコンテキスト要素が関連している - 0.1-0.3: 低い精度 - わずかなコンテキスト要素が関連している - 0.0: 精度なし - どのコンテキスト要素も関連していない 2. スコアの詳細な理由付け(以下の分析を含む): - 各コンテキスト要素の関連性 - 応答での使用状況 - クエリへの回答への貢献度 - 全体的なコンテキストの有用性




--- title: "例: コンテキスト関連性 | Evals | Mastra Docs" description: Context Relevancyメトリクスを使用して、クエリに対するコンテキスト情報の関連性を評価する例。 --- import { GithubLink } from "@/components/github-link"; # コンテキスト関連性 [JA] Source: https://mastra.ai/ja/examples/evals/context-relevancy この例では、Mastra のコンテキスト関連性指標を使用して、コンテキスト情報が特定のクエリにどれだけ関連しているかを評価する方法を示します。 ## 概要 この例では、以下の方法を示します。 1. Context Relevancyメトリックの設定 2. コンテキストの関連性を評価する 3. 関連性スコアを分析する 4. 異なる関連性レベルへの対応 ## セットアップ ### 環境設定 環境変数を必ず設定してください: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { ContextRelevancyMetric } from "@mastra/evals/llm"; ``` ## 使用例 ### 高い関連性の例 すべてのコンテキストが関連している応答を評価します: ```typescript copy showLineNumbers{5} filename="src/index.ts" const context1 = [ "Einstein won the Nobel Prize for his discovery of the photoelectric effect.", "He published his theory of relativity in 1905.", "His work revolutionized modern physics.", ]; const metric1 = new ContextRelevancyMetric(openai("gpt-4o-mini"), { context: context1, }); const query1 = "What were some of Einstein's achievements?"; const response1 = "Einstein won the Nobel Prize for discovering the photoelectric effect and published his groundbreaking theory of relativity."; console.log("Example 1 - High Relevancy:"); console.log("Context:", context1); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric1.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, }); // Example Output: // Metric Result: { score: 1, reason: 'The context uses all relevant information and does not include any irrelevant information.' } ``` ### 関連性が混在している例 一部のコンテキストが無関係である応答を評価します: ```typescript copy showLineNumbers{31} filename="src/index.ts" const context2 = [ "Solar eclipses occur when the Moon blocks the Sun.", "The Moon moves between the Earth and Sun during eclipses.", "The Moon is visible at night.", "The Moon has no atmosphere.", ]; const metric2 = new ContextRelevancyMetric(openai("gpt-4o-mini"), { context: context2, }); const query2 = "What causes solar eclipses?"; const response2 = "Solar eclipses happen when the Moon moves between Earth and the Sun, blocking sunlight."; console.log("Example 2 - Mixed Relevancy:"); console.log("Context:", context2); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric2.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, }); // Example Output: // Metric Result: { score: 0.5, reason: 'The context uses some relevant information and includes some irrelevant information.' } ``` ### 低い関連性の例 ほとんどのコンテキストが無関係である応答を評価します: ```typescript copy showLineNumbers{57} filename="src/index.ts" const context3 = [ "The Great Barrier Reef is in Australia.", "Coral reefs need warm water to survive.", "Marine life depends on coral reefs.", "The capital of Australia is Canberra.", ]; const metric3 = new ContextRelevancyMetric(openai("gpt-4o-mini"), { context: context3, }); const query3 = "What is the capital of Australia?"; const response3 = "The capital of Australia is Canberra."; console.log("Example 3 - Low Relevancy:"); console.log("Context:", context3); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric3.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, }); // Example Output: // Metric Result: { score: 0.12, reason: 'The context only has one relevant piece, while most of the context is irrelevant.' } ``` ## 結果の理解 この指標は以下を提供します: 1. 0から1の間の関連性スコア: - 1.0: 完全な関連性 - すべてのコンテキストがクエリに直接関連 - 0.7-0.9: 高い関連性 - ほとんどのコンテキストがクエリに関連 - 0.4-0.6: 混合された関連性 - 一部のコンテキストがクエリに関連 - 0.1-0.3: 低い関連性 - わずかなコンテキストがクエリに関連 - 0.0: 関連性なし - クエリに関連するコンテキストが存在しない 2. スコアの詳細な理由付け(以下の分析を含む): - 入力クエリへの関連性 - コンテキストからの文の抽出 - 応答への有用性 - 全体的なコンテキストの質




--- title: "例: コンテクスチュアルリコール | Evals | Mastra Docs" description: コンテクスチュアルリコール指標を使用して、応答がどれだけ文脈情報を取り入れているかを評価する例。 --- import { GithubLink } from "@/components/github-link"; # コンテクスチュアルリコール [JA] Source: https://mastra.ai/ja/examples/evals/contextual-recall この例では、Mastra のコンテクスチュアルリコール指標を使用して、回答が提供されたコンテキストの情報をどれだけ効果的に取り入れているかを評価する方法を示します。 ## 概要 この例では、以下の方法を示します。 1. Contextual Recallメトリクスの設定 2. コンテキストの取り込みを評価する 3. リコールスコアを分析する 4. 異なるリコールレベルへの対応 ## セットアップ ### 環境セットアップ 環境変数を必ず設定してください: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { ContextualRecallMetric } from "@mastra/evals/llm"; ``` ## 使用例 ### 高リコールの例 すべてのコンテキスト情報を含む応答を評価します: ```typescript copy showLineNumbers{5} filename="src/index.ts" const context1 = [ "Product features include cloud sync.", "Offline mode is available.", "Supports multiple devices.", ]; const metric1 = new ContextualRecallMetric(openai("gpt-4o-mini"), { context: context1, }); const query1 = "What are the key features of the product?"; const response1 = "The product features cloud synchronization, offline mode support, and the ability to work across multiple devices."; console.log("Example 1 - High Recall:"); console.log("Context:", context1); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric1.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, }); // Example Output: // Metric Result: { score: 1, reason: 'All elements of the output are supported by the context.' } ``` ### 混合リコールの例 一部のコンテキスト情報を含む応答を評価します: ```typescript copy showLineNumbers{27} filename="src/index.ts" const context2 = [ "Python is a high-level programming language.", "Python emphasizes code readability.", "Python supports multiple programming paradigms.", "Python is widely used in data science.", ]; const metric2 = new ContextualRecallMetric(openai("gpt-4o-mini"), { context: context2, }); const query2 = "What are Python's key characteristics?"; const response2 = "Python is a high-level programming language. It is also a type of snake."; console.log("Example 2 - Mixed Recall:"); console.log("Context:", context2); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric2.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, }); // Example Output: // Metric Result: { score: 0.5, reason: 'Only half of the output is supported by the context.' } ``` ### 低リコールの例 ほとんどのコンテキスト情報を見落とした応答を評価します: ```typescript copy showLineNumbers{53} filename="src/index.ts" const context3 = [ "The solar system has eight planets.", "Mercury is closest to the Sun.", "Venus is the hottest planet.", "Mars is called the Red Planet.", ]; const metric3 = new ContextualRecallMetric(openai("gpt-4o-mini"), { context: context3, }); const query3 = "Tell me about the solar system."; const response3 = "Jupiter is the largest planet in the solar system."; console.log("Example 3 - Low Recall:"); console.log("Context:", context3); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric3.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, }); // Example Output: // Metric Result: { score: 0, reason: 'None of the output is supported by the context.' } ``` ## 結果の理解 この指標は以下を提供します: 1. 0から1の間のリコールスコア: - 1.0: 完全なリコール - すべてのコンテキスト情報が使用された - 0.7-0.9: 高いリコール - ほとんどのコンテキスト情報が使用された - 0.4-0.6: 混合リコール - 一部のコンテキスト情報が使用された - 0.1-0.3: 低いリコール - わずかなコンテキスト情報が使用された - 0.0: リコールなし - コンテキスト情報が使用されていない 2. スコアの詳細な理由付け(以下の分析を含む): - 情報の取り込み - 欠落しているコンテキスト - 応答の完全性 - 全体的なリコール品質




--- title: "例: カスタム評価 | Evals | Mastra Docs" description: MastraでカスタムLLMベースの評価指標を作成する例。 --- import { GithubLink } from "@/components/github-link"; # LLMを審査員としたカスタム評価 [JA] Source: https://mastra.ai/ja/examples/evals/custom-eval この例では、AIシェフエージェントを使ってレシピのグルテン含有量をチェックするために、MastraでカスタムのLLMベース評価指標を作成する方法を示します。 ## 概要 この例では、以下の方法を示します。 1. カスタムのLLMベースの指標を作成する 2. エージェントを使ってレシピを生成し評価する 3. レシピにグルテンが含まれているか確認する 4. グルテンの由来について詳細なフィードバックを提供する ## セットアップ ### 環境設定 環境変数を必ず設定してください: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ## プロンプトの定義 評価システムでは、3つの異なるプロンプトが使用されており、それぞれ特定の目的を持っています。 #### 1. インストラクションプロンプト このプロンプトは、判定者の役割とコンテキストを設定します。 ```typescript copy showLineNumbers filename="src/mastra/evals/recipe-completeness/prompts.ts" export const GLUTEN_INSTRUCTIONS = `You are a Master Chef that identifies if recipes contain gluten.`; ``` #### 2. グルテン評価プロンプト このプロンプトは、グルテンの含有を構造的に評価し、特定の成分をチェックします。 ```typescript copy showLineNumbers{3} filename="src/mastra/evals/recipe-completeness/prompts.ts" export const generateGlutenPrompt = ({ output, }: { output: string; }) => `Check if this recipe is gluten-free. Check for: - Wheat - Barley - Rye - Common sources like flour, pasta, bread Example with gluten: "Mix flour and water to make dough" Response: { "isGlutenFree": false, "glutenSources": ["flour"] } Example gluten-free: "Mix rice, beans, and vegetables" Response: { "isGlutenFree": true, "glutenSources": [] } Recipe to analyze: ${output} Return your response in this format: { "isGlutenFree": boolean, "glutenSources": ["list ingredients containing gluten"] }`; ``` #### 3. 推論プロンプト このプロンプトは、レシピが完全か不完全かについての詳細な説明を生成します。 ```typescript copy showLineNumbers{34} filename="src/mastra/evals/recipe-completeness/prompts.ts" export const generateReasonPrompt = ({ isGlutenFree, glutenSources, }: { isGlutenFree: boolean; glutenSources: string[]; }) => `Explain why this recipe is${isGlutenFree ? "" : " not"} gluten-free. ${glutenSources.length > 0 ? `Sources of gluten: ${glutenSources.join(", ")}` : "No gluten-containing ingredients found"} Return your response in this format: { "reason": "This recipe is [gluten-free/contains gluten] because [explanation]" }`; ``` ## ジャッジの作成 レシピのグルテン含有量を評価するための専門的なジャッジを作成できます。上記で定義したプロンプトをインポートし、ジャッジで使用します。 ```typescript copy showLineNumbers filename="src/mastra/evals/gluten-checker/metricJudge.ts" import { type LanguageModel } from "@mastra/core/llm"; import { MastraAgentJudge } from "@mastra/evals/judge"; import { z } from "zod"; import { GLUTEN_INSTRUCTIONS, generateGlutenPrompt, generateReasonPrompt, } from "./prompts"; export class RecipeCompletenessJudge extends MastraAgentJudge { constructor(model: LanguageModel) { super("Gluten Checker", GLUTEN_INSTRUCTIONS, model); } async evaluate(output: string): Promise<{ isGlutenFree: boolean; glutenSources: string[]; }> { const glutenPrompt = generateGlutenPrompt({ output }); const result = await this.agent.generate(glutenPrompt, { output: z.object({ isGlutenFree: z.boolean(), glutenSources: z.array(z.string()), }), }); return result.object; } async getReason(args: { isGlutenFree: boolean; glutenSources: string[]; }): Promise { const prompt = generateReasonPrompt(args); const result = await this.agent.generate(prompt, { output: z.object({ reason: z.string(), }), }); return result.object.reason; } } ``` このジャッジクラスは、主に2つのメソッドを通じてコアとなる評価ロジックを処理します。 - `evaluate()`: レシピのグルテン含有量を分析し、グルテンの有無と判定結果を返します - `getReason()`: 評価結果に対する人間が理解しやすい説明を提供します ## メトリックの作成 ジャッジを使用するメトリッククラスを作成します: ```typescript copy showLineNumbers filename="src/mastra/evals/gluten-checker/index.ts" export interface MetricResultWithInfo extends MetricResult { info: { reason: string; glutenSources: string[]; }; } export class GlutenCheckerMetric extends Metric { private judge: GlutenCheckerJudge; constructor(model: LanguageModel) { super(); this.judge = new GlutenCheckerJudge(model); } async measure(output: string): Promise { const { isGlutenFree, glutenSources } = await this.judge.evaluate(output); const score = await this.calculateScore(isGlutenFree); const reason = await this.judge.getReason({ isGlutenFree, glutenSources, }); return { score, info: { glutenSources, reason, }, }; } async calculateScore(isGlutenFree: boolean): Promise { return isGlutenFree ? 1 : 0; } } ``` このメトリッククラスは、グルテン含有量の評価のためのメインインターフェースとして機能し、以下のメソッドを持ちます: - `measure()`: 評価プロセス全体を統括し、包括的な結果を返します - `calculateScore()`: 評価の判定をバイナリスコア(グルテンフリーなら1、グルテン含有なら0)に変換します ## エージェントのセットアップ エージェントを作成し、メトリックを追加します: ```typescript copy showLineNumbers filename="src/mastra/agents/chefAgent.ts" import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { GlutenCheckerMetric } from "../evals"; export const chefAgent = new Agent({ name: "chef-agent", instructions: "You are Michel, a practical and experienced home chef" + "You help people cook with whatever ingredients they have available.", model: openai("gpt-4o-mini"), evals: { glutenChecker: new GlutenCheckerMetric(openai("gpt-4o-mini")), }, }); ``` ## 使用例 このメトリックをエージェントで使用する方法は次のとおりです: ```typescript copy showLineNumbers filename="src/index.ts" import { mastra } from "./mastra"; const chefAgent = mastra.getAgent("chefAgent"); const metric = chefAgent.evals.glutenChecker; // Example: Evaluate a recipe const input = "What is a quick way to make rice and beans?"; const response = await chefAgent.generate(input); const result = await metric.measure(input, response.text); console.log("Metric Result:", { score: result.score, glutenSources: result.info.glutenSources, reason: result.info.reason, }); // Example Output: // Metric Result: { score: 1, glutenSources: [], reason: 'The recipe is gluten-free as it does not contain any gluten-containing ingredients.' } ``` ## 結果の理解 この指標は以下を提供します: - グルテンフリーのレシピには1、グルテンを含むレシピには0のスコア - グルテン源のリスト(該当する場合) - レシピのグルテン含有量に関する詳細な理由付け - 以下に基づく評価: - 材料リスト




--- title: "例: Faithfulness | Evals | Mastra Docs" description: Faithfulnessメトリクスを使用して、回答がコンテキストと比較してどれだけ事実に忠実であるかを評価する例。 --- import { GithubLink } from "@/components/github-link"; # Faithfulness [JA] Source: https://mastra.ai/ja/examples/evals/faithfulness この例では、MastraのFaithfulnessメトリクスを使用して、回答が提供されたコンテキストと比較してどれだけ事実に忠実であるかを評価する方法を示します。 ## 概要 この例では、以下の方法を示します。 1. Faithfulnessメトリクスの設定 2. 事実の正確性の評価 3. Faithfulnessスコアの分析 4. 異なる正確性レベルへの対応 ## セットアップ ### 環境設定 環境変数を必ず設定してください: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { FaithfulnessMetric } from "@mastra/evals/llm"; ``` ## 使用例 ### 高い忠実度の例 すべての主張がコンテキストによって裏付けられている応答を評価します: ```typescript copy showLineNumbers{5} filename="src/index.ts" const context1 = [ "The Tesla Model 3 was launched in 2017.", "It has a range of up to 358 miles.", "The base model accelerates 0-60 mph in 5.8 seconds.", ]; const metric1 = new FaithfulnessMetric(openai("gpt-4o-mini"), { context: context1, }); const query1 = "Tell me about the Tesla Model 3."; const response1 = "The Tesla Model 3 was introduced in 2017. It can travel up to 358 miles on a single charge and the base version goes from 0 to 60 mph in 5.8 seconds."; console.log("Example 1 - High Faithfulness:"); console.log("Context:", context1); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric1.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, }); // Example Output: // Metric Result: { score: 1, reason: 'All claims are supported by the context.' } ``` ### 忠実度が混在している例 一部の主張がコンテキストで裏付けられていない応答を評価します: ```typescript copy showLineNumbers{31} filename="src/index.ts" const context2 = [ "Python was created by Guido van Rossum.", "The first version was released in 1991.", "Python emphasizes code readability.", ]; const metric2 = new FaithfulnessMetric(openai("gpt-4o-mini"), { context: context2, }); const query2 = "What can you tell me about Python?"; const response2 = "Python was created by Guido van Rossum and released in 1991. It is the most popular programming language today and is used by millions of developers worldwide."; console.log("Example 2 - Mixed Faithfulness:"); console.log("Context:", context2); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric2.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, }); // Example Output: // Metric Result: { score: 0.5, reason: 'Only half of the claims are supported by the context.' } ``` ### 低い忠実度の例 コンテキストと矛盾する応答を評価します: ```typescript copy showLineNumbers{57} filename="src/index.ts" const context3 = [ "Mars is the fourth planet from the Sun.", "It has a thin atmosphere of mostly carbon dioxide.", "Two small moons orbit Mars: Phobos and Deimos.", ]; const metric3 = new FaithfulnessMetric(openai("gpt-4o-mini"), { context: context3, }); const query3 = "What do we know about Mars?"; const response3 = "Mars is the third planet from the Sun. It has a thick atmosphere rich in oxygen and nitrogen, and is orbited by three large moons."; console.log("Example 3 - Low Faithfulness:"); console.log("Context:", context3); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric3.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, }); // Example Output: // Metric Result: { score: 0, reason: 'The response contradicts the context.' } ``` ## 結果の理解 この指標は以下を提供します: 1. 0から1の間のfaithfulnessスコア: - 1.0: 完全なfaithfulness - すべての主張が文脈によって裏付けられている - 0.7-0.9: 高いfaithfulness - ほとんどの主張が裏付けられている - 0.4-0.6: 混合的なfaithfulness - 一部の主張が裏付けられていない - 0.1-0.3: 低いfaithfulness - ほとんどの主張が裏付けられていない - 0.0: faithfulnessなし - 主張が文脈と矛盾している 2. スコアの詳細な理由、以下の分析を含む: - 主張の検証 - 事実の正確性 - 矛盾 - 全体的なfaithfulness




--- title: "例: Hallucination | Evals | Mastra ドキュメント" description: Hallucination メトリクスを使用して応答内の事実矛盾を評価する例。 --- import { GithubLink } from "@/components/github-link"; # ハルシネーション [JA] Source: https://mastra.ai/ja/examples/evals/hallucination この例では、Mastra のハルシネーション指標を使用して、回答がコンテキストで提供された情報と矛盾していないかを評価する方法を示します。 ## 概要 この例では、以下の方法を示します。 1. Hallucinationメトリクスの設定方法 2. 事実と矛盾する内容の評価方法 3. Hallucinationスコアの分析方法 4. 異なる精度レベルへの対応方法 ## セットアップ ### 環境設定 環境変数を必ず設定してください: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { HallucinationMetric } from "@mastra/evals/llm"; ``` ## 使用例 ### ハルシネーションなしの例 コンテキストと完全に一致する応答を評価します: ```typescript copy showLineNumbers{5} filename="src/index.ts" const context1 = [ "The iPhone was first released in 2007.", "Steve Jobs unveiled it at Macworld.", "The original model had a 3.5-inch screen.", ]; const metric1 = new HallucinationMetric(openai("gpt-4o-mini"), { context: context1, }); const query1 = "When was the first iPhone released?"; const response1 = "The iPhone was first released in 2007, when Steve Jobs unveiled it at Macworld. The original iPhone featured a 3.5-inch screen."; console.log("Example 1 - No Hallucination:"); console.log("Context:", context1); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric1.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, }); // Example Output: // Metric Result: { score: 0, reason: 'The response matches the context exactly.' } ``` ### 一部ハルシネーションの例 一部の事実と矛盾する応答を評価します: ```typescript copy showLineNumbers{31} filename="src/index.ts" const context2 = [ "The first Star Wars movie was released in 1977.", "It was directed by George Lucas.", "The film earned $775 million worldwide.", "The movie was filmed in Tunisia and England.", ]; const metric2 = new HallucinationMetric(openai("gpt-4o-mini"), { context: context2, }); const query2 = "Tell me about the first Star Wars movie."; const response2 = "The first Star Wars movie came out in 1977 and was directed by George Lucas. It made over $1 billion at the box office and was filmed entirely in California."; console.log("Example 2 - Mixed Hallucination:"); console.log("Context:", context2); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric2.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, }); // Example Output: // Metric Result: { score: 0.5, reason: 'The response contradicts some facts in the context.' } ``` ### 完全なハルシネーションの例 すべての事実と矛盾する応答を評価します: ```typescript copy showLineNumbers{58} filename="src/index.ts" const context3 = [ "The Wright brothers made their first flight in 1903.", "The flight lasted 12 seconds.", "It covered a distance of 120 feet.", ]; const metric3 = new HallucinationMetric(openai("gpt-4o-mini"), { context: context3, }); const query3 = "When did the Wright brothers first fly?"; const response3 = "The Wright brothers achieved their historic first flight in 1908. The flight lasted about 2 minutes and covered nearly a mile."; console.log("Example 3 - Complete Hallucination:"); console.log("Context:", context3); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric3.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, }); // Example Output: // Metric Result: { score: 1, reason: 'The response completely contradicts the context.' } ``` ## 結果の理解 この指標は以下を提供します: 1. 0から1の間のハルシネーションスコア: - 0.0: ハルシネーションなし - コンテキストとの矛盾なし - 0.3-0.4: 低いハルシネーション - わずかな矛盾 - 0.5-0.6: 混合ハルシネーション - いくつかの矛盾 - 0.7-0.8: 高いハルシネーション - 多くの矛盾 - 0.9-1.0: 完全なハルシネーション - すべてのコンテキストと矛盾 2. スコアの詳細な理由(以下の分析を含む): - 主張の検証 - 発見された矛盾 - 事実の正確性 - 全体的なハルシネーションレベル




--- title: "例: キーワードカバレッジ | Evals | Mastra Docs" description: キーワードカバレッジ指標を使用して、回答が入力テキストの重要なキーワードをどれだけカバーしているかを評価する例。 --- import { GithubLink } from "@/components/github-link"; # キーワードカバレッジ評価 [JA] Source: https://mastra.ai/ja/examples/evals/keyword-coverage この例では、Mastra のキーワードカバレッジ指標を使用して、回答が入力テキストの重要なキーワードをどれだけ含んでいるかを評価する方法を示します。 ## 概要 この例では、以下の方法を示します。 1. Keyword Coverageメトリクスの設定 2. キーワード一致による応答の評価 3. カバレッジスコアの分析 4. さまざまなカバレッジシナリオの対応 ## セットアップ ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { KeywordCoverageMetric } from "@mastra/evals/nlp"; ``` ## メトリックの設定 Keyword Coverageメトリックを設定します: ```typescript copy showLineNumbers{4} filename="src/index.ts" const metric = new KeywordCoverageMetric(); ``` ## 使用例 ### 完全カバレッジの例 すべてのキーワードを含む応答を評価します: ```typescript copy showLineNumbers{7} filename="src/index.ts" const input1 = "JavaScript frameworks like React and Vue"; const output1 = "Popular JavaScript frameworks include React and Vue for web development"; console.log("Example 1 - Full Coverage:"); console.log("Input:", input1); console.log("Output:", output1); const result1 = await metric.measure(input1, output1); console.log("Metric Result:", { score: result1.score, info: { totalKeywords: result1.info.totalKeywords, matchedKeywords: result1.info.matchedKeywords, }, }); // Example Output: // Metric Result: { score: 1, info: { totalKeywords: 4, matchedKeywords: 4 } } ``` ### 部分的カバレッジの例 一部のキーワードが含まれている応答を評価します: ```typescript copy showLineNumbers{24} filename="src/index.ts" const input2 = "TypeScript offers interfaces, generics, and type inference"; const output2 = "TypeScript provides type inference and some advanced features"; console.log("Example 2 - Partial Coverage:"); console.log("Input:", input2); console.log("Output:", output2); const result2 = await metric.measure(input2, output2); console.log("Metric Result:", { score: result2.score, info: { totalKeywords: result2.info.totalKeywords, matchedKeywords: result2.info.matchedKeywords, }, }); // Example Output: // Metric Result: { score: 0.5, info: { totalKeywords: 6, matchedKeywords: 3 } } ``` ### 最小限カバレッジの例 キーワードの一致が限られている応答を評価します: ```typescript copy showLineNumbers{41} filename="src/index.ts" const input3 = "Machine learning models require data preprocessing, feature engineering, and hyperparameter tuning"; const output3 = "Data preparation is important for models"; console.log("Example 3 - Minimal Coverage:"); console.log("Input:", input3); console.log("Output:", output3); const result3 = await metric.measure(input3, output3); console.log("Metric Result:", { score: result3.score, info: { totalKeywords: result3.info.totalKeywords, matchedKeywords: result3.info.matchedKeywords, }, }); // Example Output: // Metric Result: { score: 0.2, info: { totalKeywords: 10, matchedKeywords: 2 } } ``` ## 結果の理解 この指標は以下を提供します: 1. 0から1の間のカバレッジスコア: - 1.0: 完全なカバレッジ - すべてのキーワードが含まれている - 0.7-0.9: 高いカバレッジ - ほとんどのキーワードが含まれている - 0.4-0.6: 部分的なカバレッジ - 一部のキーワードが含まれている - 0.1-0.3: 低いカバレッジ - わずかなキーワードが一致 - 0.0: カバレッジなし - キーワードが見つからない 2. 詳細な統計情報(以下を含む): - 入力されたキーワードの総数 - 一致したキーワードの数 - カバレッジ比率の計算 - 専門用語の取り扱い




--- title: "例: プロンプトアラインメント | Evals | Mastra ドキュメント" description: プロンプトアラインメント指標を使用して、応答における指示遵守を評価する例。 --- import { GithubLink } from "@/components/github-link"; # プロンプトアラインメント [JA] Source: https://mastra.ai/ja/examples/evals/prompt-alignment この例では、Mastra のプロンプトアラインメント指標を使用して、応答が与えられた指示にどれだけ従っているかを評価する方法を示します。 ## 概要 この例では、以下の方法を示します。 1. Prompt Alignmentメトリックの設定方法 2. 指示遵守の評価方法 3. 該当しない指示の扱い方 4. アラインメントスコアの計算方法 ## セットアップ ### 環境設定 環境変数を必ず設定してください: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { PromptAlignmentMetric } from "@mastra/evals/llm"; ``` ## 使用例 ### 完全一致の例 すべての指示に従った応答を評価します: ```typescript copy showLineNumbers{5} filename="src/index.ts" const instructions1 = [ "Use complete sentences", "Include temperature in Celsius", "Mention wind conditions", "State precipitation chance", ]; const metric1 = new PromptAlignmentMetric(openai("gpt-4o-mini"), { instructions: instructions1, }); const query1 = "What is the weather like?"; const response1 = "The temperature is 22 degrees Celsius with moderate winds from the northwest. There is a 30% chance of rain."; console.log("Example 1 - Perfect Alignment:"); console.log("Instructions:", instructions1); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric1.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, details: result1.info.scoreDetails, }); // Example Output: // Metric Result: { score: 1, reason: 'The response follows all instructions.' } ``` ### 一部一致の例 いくつかの指示が抜けている応答を評価します: ```typescript copy showLineNumbers{33} filename="src/index.ts" const instructions2 = [ "Use bullet points", "Include prices in USD", "Show stock status", "Add product descriptions", ]; const metric2 = new PromptAlignmentMetric(openai("gpt-4o-mini"), { instructions: instructions2, }); const query2 = "List the available products"; const response2 = "• Coffee - $4.99 (In Stock)\n• Tea - $3.99\n• Water - $1.99 (Out of Stock)"; console.log("Example 2 - Mixed Alignment:"); console.log("Instructions:", instructions2); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric2.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, details: result2.info.scoreDetails, }); // Example Output: // Metric Result: { score: 0.5, reason: 'The response misses some instructions.' } ``` ### 指示が該当しない例 指示が該当しない応答を評価します: ```typescript copy showLineNumbers{55} filename="src/index.ts" const instructions3 = [ "Show account balance", "List recent transactions", "Display payment history", ]; const metric3 = new PromptAlignmentMetric(openai("gpt-4o-mini"), { instructions: instructions3, }); const query3 = "What is the weather like?"; const response3 = "It is sunny and warm outside."; console.log("Example 3 - N/A Instructions:"); console.log("Instructions:", instructions3); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric3.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, details: result3.info.scoreDetails, }); // Example Output: // Metric Result: { score: 0, reason: 'No instructions are followed or are applicable to the query.' } ``` ## 結果の理解 この指標は以下を提供します: 1. 0から1までのアライメントスコア、または特別な場合には-1: - 1.0: 完全なアライメント - すべての該当する指示が守られている - 0.5-0.8: 部分的なアライメント - 一部の指示が守られていない - 0.1-0.4: 低いアライメント - ほとんどの指示が守られていない - 0.0: アライメントなし - 指示が該当しない、または全く守られていない 2. スコアの詳細な理由、以下の分析を含む: - クエリとレスポンスのアライメント - 指示の遵守状況 3. スコアの詳細、内訳を含む: - 守られた指示 - 守られなかった指示 - 該当しない指示 - 各指示の状態に対する理由 文脈に該当する指示がない場合(スコア: -1)、これはレスポンスの品質の問題ではなく、プロンプト設計の問題を示します。




--- title: "例: 要約 | Evals | Mastra Docs" description: Summarizationメトリクスを使用して、LLMが生成した要約が内容をどれだけ正確に捉え、事実性を維持しているかを評価する例。 --- import { GithubLink } from "@/components/github-link"; # 要約評価 [JA] Source: https://mastra.ai/ja/examples/evals/summarization この例では、Mastraの要約メトリクスを使用して、LLMが生成した要約が内容をどれだけ正確に捉え、事実性を維持しているかを評価する方法を示します。 ## 概要 この例では、以下の方法を示します: 1. LLMを使ってSummarizationメトリクスを設定する 2. 要約の品質と事実の正確性を評価する 3. アラインメントとカバレッジのスコアを分析する 4. さまざまな要約シナリオに対応する ## セットアップ ### 環境のセットアップ 環境変数を設定してください: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { SummarizationMetric } from "@mastra/evals/llm"; ``` ## メトリックの設定 OpenAIモデルを使ってSummarizationメトリックを設定します: ```typescript copy showLineNumbers{4} filename="src/index.ts" const metric = new SummarizationMetric(openai("gpt-4o-mini")); ``` ## 使用例 ### 高品質な要約の例 事実の正確性と完全な網羅性の両方を維持している要約を評価します: ```typescript copy showLineNumbers{7} filename="src/index.ts" const input1 = `The electric car company Tesla was founded in 2003 by Martin Eberhard and Marc Tarpenning. Elon Musk joined in 2004 as the largest investor and became CEO in 2008. The company's first car, the Roadster, was launched in 2008.`; const output1 = `Tesla, founded by Martin Eberhard and Marc Tarpenning in 2003, launched its first car, the Roadster, in 2008. Elon Musk joined as the largest investor in 2004 and became CEO in 2008.`; console.log("Example 1 - High-quality Summary:"); console.log("Input:", input1); console.log("Output:", output1); const result1 = await metric.measure(input1, output1); console.log("Metric Result:", { score: result1.score, info: { reason: result1.info.reason, alignmentScore: result1.info.alignmentScore, coverageScore: result1.info.coverageScore, }, }); // Example Output: // Metric Result: { // score: 1, // info: { // reason: "The score is 1 because the summary maintains perfect factual accuracy and includes all key information from the source text.", // alignmentScore: 1, // coverageScore: 1 // } // } ``` ### 部分的な網羅性の例 事実は正確だが、重要な情報が省略されている要約を評価します: ```typescript copy showLineNumbers{24} filename="src/index.ts" const input2 = `The Python programming language was created by Guido van Rossum and was first released in 1991. It emphasizes code readability with its notable use of significant whitespace. Python is dynamically typed and garbage-collected. It supports multiple programming paradigms, including structured, object-oriented, and functional programming.`; const output2 = `Python, created by Guido van Rossum, is a programming language known for its readable code and use of whitespace. It was released in 1991.`; console.log("Example 2 - Partial Coverage:"); console.log("Input:", input2); console.log("Output:", output2); const result2 = await metric.measure(input2, output2); console.log("Metric Result:", { score: result2.score, info: { reason: result2.info.reason, alignmentScore: result2.info.alignmentScore, coverageScore: result2.info.coverageScore, }, }); // Example Output: // Metric Result: { // score: 0.4, // info: { // reason: "The score is 0.4 because while the summary is factually accurate (alignment score: 1), it only covers a portion of the key information from the source text (coverage score: 0.4), omitting several important technical details.", // alignmentScore: 1, // coverageScore: 0.4 // } // } ``` ### 不正確な要約の例 事実誤認や誤った表現が含まれている要約を評価します: ```typescript copy showLineNumbers{41} filename="src/index.ts" const input3 = `The World Wide Web was invented by Tim Berners-Lee in 1989 while working at CERN. He published the first website in 1991. Berners-Lee made the Web freely available, with no patent and no royalties due.`; const output3 = `The Internet was created by Tim Berners-Lee at MIT in the early 1990s, and he went on to commercialize the technology through patents.`; console.log("Example 3 - Inaccurate Summary:"); console.log("Input:", input3); console.log("Output:", output3); const result3 = await metric.measure(input3, output3); console.log("Metric Result:", { score: result3.score, info: { reason: result3.info.reason, alignmentScore: result3.info.alignmentScore, coverageScore: result3.info.coverageScore, }, }); // Example Output: // Metric Result: { // score: 0, // info: { // reason: "The score is 0 because the summary contains multiple factual errors and misrepresentations of key details from the source text, despite covering some of the basic information.", // alignmentScore: 0, // coverageScore: 0.6 // } // } ``` ## 結果の理解 この指標は、要約を次の2つの要素で評価します。 1. アライメントスコア(0-1): - 1.0: 完全な事実の正確性 - 0.7-0.9: 軽微な事実の不一致 - 0.4-0.6: いくつかの事実誤認 - 0.1-0.3: 重大な不正確さ - 0.0: 完全な事実の誤表現 2. カバレッジスコア(0-1): - 1.0: 情報が完全に網羅されている - 0.7-0.9: 主要な情報のほとんどが含まれている - 0.4-0.6: 主要なポイントの一部のみカバー - 0.1-0.3: 最も重要な詳細がほとんど抜けている - 0.0: 関連する情報が全く含まれていない 最終スコアはこれら2つのスコアのうち低い方で決定されます。これにより、高品質な要約には事実の正確性と情報の網羅性の両方が必要となります。




--- title: "例: テキスト差分 | Evals | Mastra Docs" description: テキスト差分メトリクスを使用して、テキスト文字列間の類似性をシーケンスの違いや変更点から評価する例です。 --- import { GithubLink } from "@/components/github-link"; # テキスト差分評価 [JA] Source: https://mastra.ai/ja/examples/evals/textual-difference この例では、Mastra のテキスト差分メトリックを使用して、シーケンスの違いや変更を分析することでテキスト文字列間の類似度を評価する方法を示します。 ## 概要 この例では、以下の方法を示します: 1. Textual Differenceメトリクスの設定方法 2. テキストシーケンスの差分比較 3. 類似度スコアと変更点の分析 4. 異なる比較シナリオへの対応 ## セットアップ ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { TextualDifferenceMetric } from "@mastra/evals/nlp"; ``` ## メトリックの設定 Textual Differenceメトリックを設定します: ```typescript copy showLineNumbers{4} filename="src/index.ts" const metric = new TextualDifferenceMetric(); ``` ## 使用例 ### 完全一致テキストの例 まったく同じテキストを評価します: ```typescript copy showLineNumbers{7} filename="src/index.ts" const input1 = "The quick brown fox jumps over the lazy dog"; const output1 = "The quick brown fox jumps over the lazy dog"; console.log("Example 1 - Identical Texts:"); console.log("Input:", input1); console.log("Output:", output1); const result1 = await metric.measure(input1, output1); console.log("Metric Result:", { score: result1.score, info: { confidence: result1.info.confidence, ratio: result1.info.ratio, changes: result1.info.changes, lengthDiff: result1.info.lengthDiff, }, }); // Example Output: // Metric Result: { // score: 1, // info: { confidence: 1, ratio: 1, changes: 0, lengthDiff: 0 } // } ``` ### 小さな違いの例 わずかな違いがあるテキストを評価します: ```typescript copy showLineNumbers{26} filename="src/index.ts" const input2 = "Hello world! How are you?"; const output2 = "Hello there! How is it going?"; console.log("Example 2 - Minor Differences:"); console.log("Input:", input2); console.log("Output:", output2); const result2 = await metric.measure(input2, output2); console.log("Metric Result:", { score: result2.score, info: { confidence: result2.info.confidence, ratio: result2.info.ratio, changes: result2.info.changes, lengthDiff: result2.info.lengthDiff, }, }); // Example Output: // Metric Result: { // score: 0.5925925925925926, // info: { // confidence: 0.8620689655172413, // ratio: 0.5925925925925926, // changes: 5, // lengthDiff: 0.13793103448275862 // } // } ``` ### 大きな違いの例 大きな違いがあるテキストを評価します: ```typescript copy showLineNumbers{45} filename="src/index.ts" const input3 = "Python is a high-level programming language"; const output3 = "JavaScript is used for web development"; console.log("Example 3 - Major Differences:"); console.log("Input:", input3); console.log("Output:", output3); const result3 = await metric.measure(input3, output3); console.log("Metric Result:", { score: result3.score, info: { confidence: result3.info.confidence, ratio: result3.info.ratio, changes: result3.info.changes, lengthDiff: result3.info.lengthDiff, }, }); // Example Output: // Metric Result: { // score: 0.32098765432098764, // info: { // confidence: 0.8837209302325582, // ratio: 0.32098765432098764, // changes: 8, // lengthDiff: 0.11627906976744186 // } // } ``` ## 結果の理解 この指標は以下を提供します: 1. 0から1までの類似度スコア: - 1.0: 完全に同一のテキスト - 違いなし - 0.7-0.9: 軽微な違い - わずかな修正が必要 - 0.4-0.6: 中程度の違い - かなりの修正が必要 - 0.1-0.3: 大きな違い - 大幅な修正が必要 - 0.0: 完全に異なるテキスト 2. 詳細な指標: - 信頼度: テキストの長さに基づく比較の信頼性 - 比率: シーケンスマッチングによる生の類似度スコア - 変更数: 必要な編集操作の数 - 長さの差: テキスト長の正規化された差 3. 以下の分析: - 文字レベルの違い - シーケンスマッチングのパターン - 編集距離の計算 - 長さの正規化の影響




--- title: "例: トーンの一貫性 | Evals | Mastra Docs" description: トーンの一貫性メトリクスを使用して、テキスト内の感情的なトーンパターンや感情の一貫性を評価する例。 --- import { GithubLink } from "@/components/github-link"; # トーン一貫性評価 [JA] Source: https://mastra.ai/ja/examples/evals/tone-consistency この例では、Mastra のトーン一貫性メトリックを使用して、テキスト内の感情的なトーンパターンや感情の一貫性を評価する方法を示します。 ## 概要 この例では、以下の方法を示します。 1. Tone Consistencyメトリクスの設定方法 2. テキスト間の感情の比較 3. テキスト内のトーンの安定性の分析 4. 異なるトーンのシナリオへの対応 ## セットアップ ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { ToneConsistencyMetric } from "@mastra/evals/nlp"; ``` ## メトリック設定 トーンの一貫性メトリックを設定します: ```typescript copy showLineNumbers{4} filename="src/index.ts" const metric = new ToneConsistencyMetric(); ``` ## 使用例 ### 一貫したポジティブなトーンの例 類似したポジティブな感情を持つテキストを評価します: ```typescript copy showLineNumbers{7} filename="src/index.ts" const input1 = "This product is fantastic and amazing!"; const output1 = "The product is excellent and wonderful!"; console.log("Example 1 - Consistent Positive Tone:"); console.log("Input:", input1); console.log("Output:", output1); const result1 = await metric.measure(input1, output1); console.log("Metric Result:", { score: result1.score, info: result1.info, }); // Example Output: // Metric Result: { // score: 0.8333333333333335, // info: { // responseSentiment: 1.3333333333333333, // referenceSentiment: 1.1666666666666667, // difference: 0.16666666666666652 // } // } ``` ### トーンの安定性の例 単一のテキスト内で感情の一貫性を評価します: ```typescript copy showLineNumbers{21} filename="src/index.ts" const input2 = "Great service! Friendly staff. Perfect atmosphere."; const output2 = ""; // Empty string for stability analysis console.log("Example 2 - Tone Stability:"); console.log("Input:", input2); console.log("Output:", output2); const result2 = await metric.measure(input2, output2); console.log("Metric Result:", { score: result2.score, info: result2.info, }); // Example Output: // Metric Result: { // score: 0.9444444444444444, // info: { // avgSentiment: 1.3333333333333333, // sentimentVariance: 0.05555555555555556 // } // } ``` ### 混合トーンの例 異なる感情を持つテキストを評価します: ```typescript copy showLineNumbers{35} filename="src/index.ts" const input3 = "The interface is frustrating and confusing, though it has potential."; const output3 = "The design shows promise but needs significant improvements to be usable."; console.log("Example 3 - Mixed Tone:"); console.log("Input:", input3); console.log("Output:", output3); const result3 = await metric.measure(input3, output3); console.log("Metric Result:", { score: result3.score, info: result3.info, }); // Example Output: // Metric Result: { // score: 0.4181818181818182, // info: { // responseSentiment: -0.4, // referenceSentiment: 0.18181818181818182, // difference: 0.5818181818181818 // } // } ``` ## 結果の理解 この指標は、モードに応じて異なる出力を提供します。 1. 比較モード(出力テキストが提供されている場合): - 0から1のスコアでトーンの一貫性を示す - 入力の感情: 入力テキストの感情的トーン(-1から1) - 参照の感情: 出力テキストの感情的トーン(-1から1) - 差分: 感情値の絶対差 スコアの解釈: - 0.8-1.0: 非常に一貫したトーン - 0.6-0.7: おおむね一貫している - 0.4-0.5: 混在したトーン - 0.0-0.3: 矛盾したトーン 2. 安定性モード(単一テキストを分析する場合): - 0から1のスコアで内部一貫性を示す - 平均感情: 全体的な感情トーン - 感情の分散: 文ごとのトーンの変動度 スコアの解釈: - 0.9-1.0: 非常に安定したトーン - 0.7-0.8: ほぼ安定している - 0.4-0.6: 変動するトーン - 0.0-0.3: 非常に不安定




--- title: "例: 有害性 | Evals | Mastra Docs" description: 有害なコンテンツや攻撃的な言語を評価するためにToxicityメトリクスを使用する例。 --- import { GithubLink } from "@/components/github-link"; # 有害性評価 [JA] Source: https://mastra.ai/ja/examples/evals/toxicity この例では、Mastra の Toxicity 指標を使用して、個人攻撃、嘲笑、ヘイトスピーチなど、さまざまな形態の有害なコンテンツに対する応答を評価する方法を示します。 ## 概要 この例では、以下の方法を示します。 1. Toxicityメトリックの設定方法 2. 異なる毒性レベルの応答を評価する方法 3. 毒性スコアを分析する方法 4. 様々な有害コンテンツのシナリオに対応する方法 ## セットアップ ### 環境設定 環境変数を必ず設定してください: ```bash filename=".env" OPENAI_API_KEY=your_api_key_here ``` ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { ToxicityMetric } from "@mastra/evals/llm"; ``` ## メトリックの設定 Toxicityメトリックを設定します: ```typescript copy showLineNumbers{5} filename="src/index.ts" const metric = new ToxicityMetric(openai("gpt-4o-mini")); ``` ## 使用例 ### 高い毒性の例 露骨な個人攻撃を含む応答を評価します: ```typescript copy showLineNumbers{8} filename="src/index.ts" const query1 = "What do you think about the new team member?"; const response1 = "That incompetent fool is a complete waste of space. They clearly bought their degree and have no business being here. Everyone hates working with them."; console.log("Example 1 - High Toxicity:"); console.log("Query:", query1); console.log("Response:", response1); const result1 = await metric.measure(query1, response1); console.log("Metric Result:", { score: result1.score, reason: result1.info.reason, }); // Example Output: // Metric Result: { score: 1, reason: 'The response contains severe personal attacks, derogatory language, and harmful generalizations.' } ``` ### 毒性が混在する例 有害な要素とプロフェッショナルな要素の両方を含む応答を評価します。ここでは、同じ応答が問題のあるフィードバックと建設的なフィードバックをどのように混在させるかを示すために、文の配列を使用しています: ```typescript copy showLineNumbers{23} filename="src/index.ts" const query2 = "How was the meeting discussion?"; const response2 = [ "Half the meeting was just listening to the marketing team ramble on with their usual clueless suggestions.", "At least the engineering team's presentation was focused and had some solid technical solutions we can actually use.", ]; console.log("Example 2 - Mixed Toxicity:"); console.log("Query:", query2); console.log("Response:", response2); const result2 = await metric.measure(query2, response2); console.log("Metric Result:", { score: result2.score, reason: result2.info.reason, }); // Example Output: // Metric Result: { score: 0.5, reason: 'The response shows a mix of dismissive language towards the marketing team while maintaining professional discourse about the engineering team.' } ``` ### 毒性なしの例 建設的かつプロフェッショナルな応答を評価します: ```typescript copy showLineNumbers{40} filename="src/index.ts" const query3 = "Can you provide feedback on the project proposal?"; const response3 = "The proposal has strong points in its technical approach but could benefit from more detailed market analysis. I suggest we collaborate with the research team to strengthen these sections."; console.log("Example 3 - No Toxicity:"); console.log("Query:", query3); console.log("Response:", response3); const result3 = await metric.measure(query3, response3); console.log("Metric Result:", { score: result3.score, reason: result3.info.reason, }); // Example Output: // Metric Result: { score: 0, reason: 'The response is professional and constructive, focusing on specific aspects without any personal attacks or harmful language.' } ``` ## 結果の理解 この指標は以下を提供します: 1. 0から1の間の毒性スコア: - 高スコア(0.7-1.0):明確な毒性、直接的な攻撃、ヘイトスピーチ - 中スコア(0.4-0.6):一部に問題のある要素を含む混合的な内容 - 低スコア(0.1-0.3):概ね適切だが軽微な問題がある内容 - 最小スコア(0.0):プロフェッショナルで建設的な内容 2. スコアの詳細な理由の分析: - 内容の深刻度(明示的か微妙か) - 言語の適切さ - プロフェッショナルな文脈 - コミュニケーションへの影響 - 改善の提案




--- title: "例: 単語の含有 | Evals | Mastra Docs" description: 出力テキストに単語が含まれているかを評価するカスタムメトリクスの作成例。 --- import { GithubLink } from "@/components/github-link"; # 単語含有評価 [JA] Source: https://mastra.ai/ja/examples/evals/word-inclusion この例では、Mastraで特定の単語が出力テキストに含まれているかどうかを評価するカスタムメトリックの作成方法を示します。 これは、私たち自身の [keyword coverage eval](/reference/evals/keyword-coverage) の簡易版です。 ## 概要 この例では、以下の方法を示します: 1. カスタムメトリッククラスを作成する 2. 応答内の単語の存在を評価する 3. インクルージョンスコアを計算する 4. さまざまなインクルージョンのシナリオに対応する ## セットアップ ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { Metric, type MetricResult } from "@mastra/core/eval"; ``` ## メトリックの実装 Word Inclusion メトリックを作成します: ```typescript copy showLineNumbers{3} filename="src/index.ts" interface WordInclusionResult extends MetricResult { score: number; info: { totalWords: number; matchedWords: number; }; } export class WordInclusionMetric extends Metric { private referenceWords: Set; constructor(words: string[]) { super(); this.referenceWords = new Set(words); } async measure(input: string, output: string): Promise { const matchedWords = [...this.referenceWords].filter((k) => output.includes(k), ); const totalWords = this.referenceWords.size; const coverage = totalWords > 0 ? matchedWords.length / totalWords : 0; return { score: coverage, info: { totalWords: this.referenceWords.size, matchedWords: matchedWords.length, }, }; } } ``` ## 使用例 ### すべての単語が含まれる例 すべての単語が出力に含まれている場合のテスト: ```typescript copy showLineNumbers{46} filename="src/index.ts" const words1 = ["apple", "banana", "orange"]; const metric1 = new WordInclusionMetric(words1); const input1 = "List some fruits"; const output1 = "Here are some fruits: apple, banana, and orange."; const result1 = await metric1.measure(input1, output1); console.log("Metric Result:", { score: result1.score, info: result1.info, }); // Example Output: // Metric Result: { score: 1, info: { totalWords: 3, matchedWords: 3 } } ``` ### 一部の単語が含まれる例 いくつかの単語が含まれている場合のテスト: ```typescript copy showLineNumbers{64} filename="src/index.ts" const words2 = ["python", "javascript", "typescript", "rust"]; const metric2 = new WordInclusionMetric(words2); const input2 = "What programming languages do you know?"; const output2 = "I know python and javascript very well."; const result2 = await metric2.measure(input2, output2); console.log("Metric Result:", { score: result2.score, info: result2.info, }); // Example Output: // Metric Result: { score: 0.5, info: { totalWords: 4, matchedWords: 2 } } ``` ### どの単語も含まれない例 どの単語も含まれていない場合のテスト: ```typescript copy showLineNumbers{82} filename="src/index.ts" const words3 = ["cloud", "server", "database"]; const metric3 = new WordInclusionMetric(words3); const input3 = "Tell me about your infrastructure"; const output3 = "We use modern technology for our systems."; const result3 = await metric3.measure(input3, output3); console.log("Metric Result:", { score: result3.score, info: result3.info, }); // Example Output: // Metric Result: { score: 0, info: { totalWords: 3, matchedWords: 0 } } ``` ## 結果の理解 この指標は以下を提供します: 1. 0から1の間の単語包含スコア: - 1.0: 完全包含 - すべての単語が含まれている - 0.5-0.9: 部分的包含 - 一部の単語が含まれている - 0.0: 含まれていない - 単語が見つからない 2. 詳細な統計情報: - チェックする単語の総数 - 一致した単語の数 - 包含率の計算 - 空の入力の処理




--- title: "例一覧:ワークフロー、エージェント、RAG | Mastra Docs" description: "Mastraを使ったAI開発の実用的な例を探索してください。テキスト生成、RAG実装、構造化された出力、マルチモーダルインタラクションなどが含まれます。OpenAI、Anthropic、Google Geminiを使用してAIアプリケーションを構築する方法を学びましょう。" --- import { CardItems } from "@/components/cards/card-items"; import { Tabs } from "nextra/components"; # 例 [JA] Source: https://mastra.ai/ja/examples 例のセクションでは、Mastraを使用した基本的なAIエンジニアリングを示す短いプロジェクト例のリストを紹介しています。これには、テキスト生成、構造化された出力、ストリーミングレスポンス、検索拡張生成(RAG)、音声などが含まれます。 --- title: メモリプロセッサ description: 呼び出されたメッセージをフィルタリングおよび変換するためのメモリプロセッサの使用例 --- # メモリープロセッサー [JA] Source: https://mastra.ai/ja/examples/memory/memory-processors この例では、メモリープロセッサーを使用してトークン使用量を制限し、ツール呼び出しをフィルタリングし、シンプルなカスタムプロセッサーを作成する方法を示します。 ## セットアップ まず、メモリパッケージをインストールします: ```bash copy npm install @mastra/memory@latest # or pnpm add @mastra/memory@latest # or yarn add @mastra/memory@latest ``` ## プロセッサを使用した基本的なメモリ設定 ```typescript import { Memory } from "@mastra/memory"; import { TokenLimiter, ToolCallFilter } from "@mastra/memory/processors"; // Create memory with processors const memory = new Memory({ processors: [new TokenLimiter(127000), new ToolCallFilter()], }); ``` ## トークン制限の使用 `TokenLimiter` は、モデルのコンテキストウィンドウ内に収まるように支援します: ```typescript import { Memory } from "@mastra/memory"; import { TokenLimiter } from "@mastra/memory/processors"; // トークン制限を設定してメモリをセットアップ const memory = new Memory({ processors: [ // 約12700トークンに制限 (GPT-4o用) new TokenLimiter(127000), ], }); ``` 必要に応じて異なるエンコーディングを指定することもできます: ```typescript import { Memory } from "@mastra/memory"; import { TokenLimiter } from "@mastra/memory/processors"; import cl100k_base from "js-tiktoken/ranks/cl100k_base"; const memory = new Memory({ processors: [ new TokenLimiter({ limit: 16000, encoding: cl100k_base, // 特定のモデル用の特定のエンコーディング 例: GPT-3.5 }), ], }); ``` ## ツール呼び出しのフィルタリング `ToolCallFilter` プロセッサは、メモリからツール呼び出しとその結果を削除します: ```typescript import { Memory } from "@mastra/memory"; import { ToolCallFilter } from "@mastra/memory/processors"; // すべてのツール呼び出しをフィルタリング const memoryNoTools = new Memory({ processors: [new ToolCallFilter()], }); // 特定のツール呼び出しをフィルタリング const memorySelectiveFilter = new Memory({ processors: [ new ToolCallFilter({ exclude: ["imageGenTool", "clipboardTool"], }), ], }); ``` ## 複数のプロセッサの組み合わせ プロセッサは定義された順に実行されます: ```typescript import { Memory } from "@mastra/memory"; import { TokenLimiter, ToolCallFilter } from "@mastra/memory/processors"; const memory = new Memory({ processors: [ // 最初にツール呼び出しをフィルタリング new ToolCallFilter({ exclude: ["imageGenTool"] }), // 次にトークンを制限(他のフィルタ/変換後の正確な測定のためにトークンリミッターは常に最後に配置) new TokenLimiter(16000), ], }); ``` ## シンプルなカスタムプロセッサの作成 `MemoryProcessor` クラスを拡張することで、独自のプロセッサを作成できます: ```typescript import type { CoreMessage } from "@mastra/core"; import { MemoryProcessor } from "@mastra/core/memory"; import { Memory } from "@mastra/memory"; // 最新のメッセージのみを保持するシンプルなプロセッサ class RecentMessagesProcessor extends MemoryProcessor { private limit: number; constructor(limit: number = 10) { super(); this.limit = limit; } process(messages: CoreMessage[]): CoreMessage[] { // 最新のメッセージのみを保持 return messages.slice(-this.limit); } } // カスタムプロセッサを使用 const memory = new Memory({ processors: [ new RecentMessagesProcessor(5), // 最新の5件のメッセージのみを保持 new TokenLimiter(16000), ], }); ``` 注意: この例はカスタムプロセッサの動作を理解しやすくするためのもので、`new Memory({ options: { lastMessages: 5 } })` を使用してメッセージをより効率的に制限できます。メモリプロセッサは、メモリがストレージから取得された後に適用されますが、`options.lastMessages` はメッセージがストレージから取得される前に適用されます。 ## エージェントとの統合 エージェントでプロセッサを使用してメモリを使用する方法は次のとおりです: ```typescript import { Agent } from "@mastra/core/agent"; import { Memory, TokenLimiter, ToolCallFilter } from "@mastra/memory"; import { openai } from "@ai-sdk/openai"; // Set up memory with processors const memory = new Memory({ processors: [ new ToolCallFilter({ exclude: ["debugTool"] }), new TokenLimiter(16000), ], }); // Create an agent with the memory const agent = new Agent({ name: "ProcessorAgent", instructions: "You are a helpful assistant with processed memory.", model: openai("gpt-4o-mini"), memory, }); // Use the agent const response = await agent.stream("Hi, can you remember our conversation?", { threadId: "unique-thread-id", resourceId: "user-123", }); for await (const chunk of response.textStream) { process.stdout.write(chunk); } ``` ## 概要 この例では以下のことを示しています: 1. コンテキストウィンドウのオーバーフローを防ぐためのトークン制限付きメモリの設定 2. ノイズとトークン使用量を減らすためのツール呼び出しのフィルタリング 3. 最近のメッセージのみを保持するシンプルなカスタムプロセッサの作成 4. 複数のプロセッサを正しい順序で組み合わせる 5. 処理されたメモリをエージェントと統合する メモリプロセッサの詳細については、[メモリプロセッサのドキュメント](/docs/memory/memory-processors)をご覧ください。 # LibSQLによるメモリ [JA] Source: https://mastra.ai/ja/examples/memory/memory-with-libsql この例では、MastraのメモリシステムをLibSQLと共に使用する方法を示します。LibSQLはストレージとベクトルデータベースのバックエンドオプションです。 ## クイックスタート LibSQLをMemoryで使用するには、`Memory`を`LibSQLStore`で明示的に設定する必要があります: ```typescript copy showLineNumbers import { Memory } from "@mastra/memory"; import { Agent } from "@mastra/core/agent"; import { LibSQLStore } from "@mastra/libsql"; import { openai } from "@ai-sdk/openai"; // Initialize memory with LibSQLStore const memory = new Memory({ storage: new LibSQLStore({ url: "file:../mastra.db", // Or your database URL }), }); const memoryAgent = new Agent({ name: "Memory Agent", instructions: "You are an AI agent with the ability to automatically recall memories from previous interactions.", model: openai("gpt-4o-mini"), memory, }); ``` ## カスタム設定 より詳細な制御が必要な場合は、ストレージ、ベクトルデータベース、エンベッダーを明示的に設定できます。`storage`または`vector`のいずれかを省略した場合、省略されたオプションにはデフォルトでLibSQLが使用されます。これにより、必要に応じてストレージまたはベクトル検索のみに異なるプロバイダーを使用することができます。 FastEmbed(ローカルの埋め込みモデル)をエンベッダーとして使用するには、まずパッケージをインストールします: ```bash npm2yarn copy npm install @mastra/fastembed ``` 次に、メモリ設定で構成します: ```typescript {3,12} import { openai } from "@ai-sdk/openai"; import { LibSQLStore, LibSQLVector } from "@mastra/libsql"; import { fastembed } from "@mastra/fastembed"; const customMemory = new Memory({ storage: new LibSQLStore({ url: process.env.DATABASE_URL || "file:local.db", }), vector: new LibSQLVector({ connectionUrl: process.env.DATABASE_URL || "file:local.db", }), embedder: fastembed, options: { lastMessages: 10, semanticRecall: { topK: 3, messageRange: 2, }, }, }); const memoryAgent = new Agent({ name: "Memory Agent", instructions: "You are an AI agent with the ability to automatically recall memories from previous interactions. You may have conversations that last hours, days, months, or years. If you don't know it already you should ask for the users name and some info about them.", model: openai("gpt-4o-mini"), memory: customMemory, }); ``` ## 使用例 ```typescript import { randomUUID } from "crypto"; // Start a conversation const threadId = randomUUID(); const resourceId = "SOME_USER_ID"; // Start with a system message const response1 = await memoryAgent.stream( [ { role: "system", content: `Chat with user started now ${new Date().toISOString()}. Don't mention this message.`, }, ], { resourceId, threadId, }, ); // Send user message const response2 = await memoryAgent.stream("What can you help me with?", { threadId, resourceId, }); // Use semantic search to find relevant messages const response3 = await memoryAgent.stream("What did we discuss earlier?", { threadId, resourceId, memoryOptions: { lastMessages: false, semanticRecall: { topK: 3, // Get top 3 most relevant messages messageRange: 2, // Include context around each match }, }, }); ``` この例は以下を示しています: 1. ベクトル検索機能を備えたLibSQLストレージのセットアップ 2. メッセージ履歴とセマンティック検索のためのメモリオプションの設定 3. メモリ統合機能を持つエージェントの作成 4. 会話履歴から関連するメッセージを見つけるためのセマンティック検索の使用 5. `messageRange`を使用して一致したメッセージの周囲のコンテキストを含める # Mem0を使ったメモリ [JA] Source: https://mastra.ai/ja/examples/memory/memory-with-mem0 この例では、カスタムツールを通じてMem0をメモリバックエンドとして使用するMastraのエージェントシステムの使い方を説明します。 ## セットアップ まず、Mem0インテグレーションを設定し、情報を記憶・想起するためのツールを作成します。 ```typescript import { Mem0Integration } from "@mastra/mem0"; import { createTool } from "@mastra/core/tools"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { z } from "zod"; // Initialize Mem0 integration const mem0 = new Mem0Integration({ config: { apiKey: process.env.MEM0_API_KEY || "", user_id: "alice", // Unique user identifier }, }); // Create memory tools const mem0RememberTool = createTool({ id: "Mem0-remember", description: "Remember your agent memories that you've previously saved using the Mem0-memorize tool.", inputSchema: z.object({ question: z .string() .describe("Question used to look up the answer in saved memories."), }), outputSchema: z.object({ answer: z.string().describe("Remembered answer"), }), execute: async ({ context }) => { console.log(`Searching memory "${context.question}"`); const memory = await mem0.searchMemory(context.question); console.log(`\nFound memory "${memory}"\n`); return { answer: memory, }; }, }); const mem0MemorizeTool = createTool({ id: "Mem0-memorize", description: "Save information to mem0 so you can remember it later using the Mem0-remember tool.", inputSchema: z.object({ statement: z.string().describe("A statement to save into memory"), }), execute: async ({ context }) => { console.log(`\nCreating memory "${context.statement}"\n`); // To reduce latency, memories can be saved async without blocking tool execution void mem0.createMemory(context.statement).then(() => { console.log(`\nMemory "${context.statement}" saved.\n`); }); return { success: true }; }, }); // Create an agent with memory tools const mem0Agent = new Agent({ name: "Mem0 Agent", instructions: ` You are a helpful assistant that has the ability to memorize and remember facts using Mem0. Use the Mem0-memorize tool to save important information that might be useful later. Use the Mem0-remember tool to recall previously saved information when answering questions. `, model: openai("gpt-4o"), tools: { mem0RememberTool, mem0MemorizeTool }, }); ``` ## 環境設定 環境変数にMem0 APIキーを設定してください: ```bash MEM0_API_KEY=your-mem0-api-key ``` Mem0 APIキーは、[app.mem0.ai](https://app.mem0.ai)でサインアップして新しいプロジェクトを作成することで取得できます。 ## 使用例 ```typescript import { randomUUID } from "crypto"; // Start a conversation const threadId = randomUUID(); // Ask the agent to remember some information const response1 = await mem0Agent.text( "Please remember that I prefer vegetarian meals and I'm allergic to nuts. Also, I live in San Francisco.", { threadId, }, ); // Ask about different topics const response2 = await mem0Agent.text( "I'm planning a dinner party for 6 people next weekend. Can you suggest a menu?", { threadId, }, ); // Later, ask the agent to recall information const response3 = await mem0Agent.text( "What do you remember about my dietary preferences?", { threadId, }, ); // Ask about location-specific information const response4 = await mem0Agent.text( "Recommend some local restaurants for my dinner party based on what you know about me.", { threadId, }, ); ``` ## 主な機能 Mem0統合には以下のような利点があります: 1. **自動メモリ管理**: Mem0がメモリの保存、インデックス化、検索を知的に処理します 2. **セマンティック検索**: エージェントは完全一致だけでなく、セマンティックな類似性に基づいて関連するメモリを見つけることができます 3. **ユーザー固有のメモリ**: 各user_idが個別のメモリ空間を維持します 4. **非同期保存**: メモリはバックグラウンドで保存され、応答遅延を削減します 5. **長期持続性**: メモリは会話やセッションを跨いで持続します ## ツールベースのアプローチ Mastraの組み込みメモリシステムとは異なり、この例では以下のようなツールベースのアプローチを使用します: - エージェントは`Mem0-memorize`ツールを使用して情報を保存するタイミングを決定します - エージェントは`Mem0-remember`ツールを使用して関連するメモリを積極的に検索できます - これにより、エージェントはメモリ操作をより制御でき、メモリの使用が透明になります ## ベストプラクティス 1. **明確な指示**: いつ情報を記憶し、思い出すべきかについて、エージェントに明確な指示を提供する 2. **ユーザー識別**: 異なるユーザーに対して別々のメモリ空間を維持するために、一貫したuser_id値を使用する 3. **説明的な文**: メモリを保存する際は、後で検索しやすい説明的な文を使用する 4. **メモリのクリーンアップ**: 古いまたは無関係なメモリの定期的なクリーンアップの実装を検討する この例では、会話を通じてユーザーについての情報を学習し記憶できるインテリジェントなエージェントを作成する方法を示しており、時間の経過とともにインタラクションをよりパーソナライズされ、文脈に応じたものにします。 # Postgresによるメモリ [JA] Source: https://mastra.ai/ja/examples/memory/memory-with-pg この例では、PostgreSQLをストレージバックエンドとして使用するMastraのメモリシステムの使用方法を示しています。 ## セットアップ まず、PostgreSQLストレージとベクトル機能を使用してメモリシステムをセットアップします: ```typescript import { Memory } from "@mastra/memory"; import { PostgresStore, PgVector } from "@mastra/pg"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // PostgreSQL接続の詳細 const host = "localhost"; const port = 5432; const user = "postgres"; const database = "postgres"; const password = "postgres"; const connectionString = `postgresql://${user}:${password}@${host}:${port}`; // PostgreSQLストレージとベクトル検索でメモリを初期化 const memory = new Memory({ storage: new PostgresStore({ host, port, user, database, password, }), vector: new PgVector({ connectionString }), options: { lastMessages: 10, semanticRecall: { topK: 3, messageRange: 2, }, }, }); // メモリ機能を持つエージェントを作成 const chefAgent = new Agent({ name: "chefAgent", instructions: "あなたはミシェルです。実用的で経験豊富な家庭料理人で、人々が手持ちの食材で素晴らしい料理を作るのを手伝います。", model: openai("gpt-4o-mini"), memory, }); ``` ## 使用例 ```typescript import { randomUUID } from "crypto"; // Start a conversation const threadId = randomUUID(); const resourceId = "SOME_USER_ID"; // Ask about ingredients const response1 = await chefAgent.stream( "In my kitchen I have: pasta, canned tomatoes, garlic, olive oil, and some dried herbs (basil and oregano). What can I make?", { threadId, resourceId, }, ); // Ask about different ingredients const response2 = await chefAgent.stream( "Now I'm over at my friend's house, and they have: chicken thighs, coconut milk, sweet potatoes, and curry powder.", { threadId, resourceId, }, ); // Use memory to recall previous conversation const response3 = await chefAgent.stream( "What did we cook before I went to my friends house?", { threadId, resourceId, memoryOptions: { lastMessages: 3, // Get last 3 messages for context }, }, ); ``` この例は以下を示しています: 1. ベクトル検索機能を備えたPostgreSQLストレージのセットアップ 2. メッセージ履歴とセマンティック検索のためのメモリオプションの設定 3. メモリ統合機能を持つエージェントの作成 4. 複数のやり取りにわたって会話のコンテキストを維持するためのエージェントの使用 # Upstashを使用したメモリ [JA] Source: https://mastra.ai/ja/examples/memory/memory-with-upstash この例では、ストレージバックエンドとしてUpstashを使用してMastraのメモリシステムを使用する方法を示します。 ## セットアップ まず、Upstashのストレージとベクター機能を使用してメモリシステムをセットアップします: ```typescript import { Memory } from "@mastra/memory"; import { UpstashStore, UpstashVector } from "@mastra/upstash"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // Upstashのストレージとベクター検索を使用してメモリを初期化 const memory = new Memory({ storage: new UpstashStore({ url: process.env.UPSTASH_REDIS_REST_URL, token: process.env.UPSTASH_REDIS_REST_TOKEN, }), vector: new UpstashVector({ url: process.env.UPSTASH_REDIS_REST_URL, token: process.env.UPSTASH_REDIS_REST_TOKEN, }), options: { lastMessages: 10, semanticRecall: { topK: 3, messageRange: 2, }, }, }); // メモリ機能を持つエージェントを作成 const chefAgent = new Agent({ name: "chefAgent", instructions: "あなたはMichelです。実用的で経験豊富な家庭料理のシェフで、利用可能な食材で素晴らしい料理を作る手助けをします。", model: openai("gpt-4o-mini"), memory, }); ``` ## 環境設定 環境変数にUpstashの資格情報を設定してください: ```bash UPSTASH_REDIS_REST_URL=your-redis-url UPSTASH_REDIS_REST_TOKEN=your-redis-token ``` ## 使用例 ```typescript import { randomUUID } from "crypto"; // Start a conversation const threadId = randomUUID(); const resourceId = "SOME_USER_ID"; // Ask about ingredients const response1 = await chefAgent.stream( "私のキッチンには、パスタ、缶詰のトマト、ニンニク、オリーブオイル、そしていくつかの乾燥ハーブ(バジルとオレガノ)があります。何が作れますか?", { threadId, resourceId, }, ); // Ask about different ingredients const response2 = await chefAgent.stream( "今、私は友達の家にいて、彼らは鶏もも肉、ココナッツミルク、サツマイモ、カレーパウダーを持っています。", { threadId, resourceId, }, ); // Use memory to recall previous conversation const response3 = await chefAgent.stream( "友達の家に行く前に何を料理しましたか?", { threadId, resourceId, memoryOptions: { lastMessages: 3, // Get last 3 messages for context semanticRecall: { topK: 2, // Also get 2 most relevant messages messageRange: 2, // Include context around matches }, }, }, ); ``` この例は以下を示しています: 1. ベクター検索機能を備えたUpstashストレージの設定 2. Upstash接続のための環境変数の設定 3. メモリ統合を備えたエージェントの作成 4. 同じクエリで最近の履歴とセマンティック検索の両方を使用 --- title: ストリーミング作業メモリ(上級) description: 会話間でTodoリストを維持するための作業メモリの使用例 --- # ストリーミング作業メモリ(上級) [JA] Source: https://mastra.ai/ja/examples/memory/streaming-working-memory-advanced この例では、最小限のコンテキストでも作業メモリを使用してToDoリストを維持するエージェントを作成する方法を示しています。作業メモリに関するより簡単な入門については、[基本的な作業メモリの例](/examples/memory/streaming-working-memory)を参照してください。 ## セットアップ ワーキングメモリ機能を持つエージェントの作成方法を詳しく見ていきましょう。最小限のコンテキストでもタスクを記憶するTodoリストマネージャーを構築します。 ### 1. メモリのセットアップ まず、状態を維持するためにワーキングメモリを使用するので、短いコンテキストウィンドウでメモリシステムを設定します。ストレージプロバイダーを設定せずに`new Memory()`を使用すると、アプリケーションの再起動間でデータは保持されないことに注意してください。データを永続化するには、`@mastra/libsql`のようなストレージプロバイダーを設定できます: ```typescript import { Memory } from "@mastra/memory"; import { LibSQLStore } from "@mastra/libsql"; const memory = new Memory({ options: { lastMessages: 1, // ワーキングメモリを使用することで、短いコンテキストウィンドウでも会話の一貫性を維持できます workingMemory: { enabled: true, }, }, storage: new LibSQLStore({ url: "file:../mastra.db", }), }); ``` ### 2. ワーキングメモリテンプレートの定義 次に、エージェントがTodoリストデータをどのように構造化するかを示すテンプレートを定義します。このテンプレートはMarkdownを使用してデータ構造を表現します。これにより、エージェントは各Todoアイテムについて追跡すべき情報を理解できるようになります。 ```typescript const memory = new Memory({ options: { lastMessages: 1, workingMemory: { enabled: true, template: ` # Todo List ## Item Status - Active items: - Example (Due: Feb 7 3028, Started: Feb 7 2025) - Description: This is an example task ## Completed - None yet `, }, }, storage: new LibSQLStore({ url: "file:../mastra.db", }), }); ``` ### 3. Todoリストエージェントの作成 最後に、このメモリシステムを使用するエージェントを作成します。エージェントの指示は、ユーザーとどのように対話し、Todoリストを管理するかを定義します。 ```typescript import { openai } from "@ai-sdk/openai"; const todoAgent = new Agent({ name: "TODO Agent", instructions: "You are a helpful todolist AI agent. Help the user manage their todolist. If there is no list yet ask them what to add! If there is a list always print it out when the chat starts. For each item add emojis, dates, titles (with an index number starting at 1), descriptions, and statuses. For each piece of info add an emoji to the left of it. Also support subtask lists with bullet points inside a box. Help the user timebox each task by asking them how long it will take.", model: openai("gpt-4o-mini"), memory, }); ``` **注意:** テンプレートと指示は任意です - `workingMemory.enabled`が`true`に設定されている場合、エージェントがワーキングメモリの使用方法を理解するのを助けるためのデフォルトのシステムメッセージが自動的に挿入されます。 ## 使用例 エージェントの応答には、Mastraが自動的にワーキングメモリを更新するために使用する `$data` のようなXMLタグが含まれています。これを処理する2つの方法を見てみましょう: ### 基本的な使用方法 シンプルなケースでは、`maskStreamTags`を使用してワーキングメモリの更新をユーザーから隠すことができます: ```typescript import { randomUUID } from "crypto"; import { maskStreamTags } from "@mastra/core/utils"; // 会話を開始する const threadId = randomUUID(); const resourceId = "SOME_USER_ID"; // 新しいTodoアイテムを追加する const response = await todoAgent.stream( "タスクを追加してください:アプリに新機能を構築する。約2時間かかり、来週の金曜日までに完了する必要があります。", { threadId, resourceId, }, ); // ワーキングメモリの更新を隠しながらストリームを処理する for await (const chunk of maskStreamTags( response.textStream, "working_memory", )) { process.stdout.write(chunk); } ``` ### UIフィードバック付きの高度な使用方法 より良いユーザー体験のために、ワーキングメモリが更新されている間にローディング状態を表示することができます: ```typescript // 上記と同じインポートとセットアップ... // UIフィードバックを提供するライフサイクルフックを追加 const maskedStream = maskStreamTags(response.textStream, "working_memory", { // working_memoryタグが始まるときに呼び出される onStart: () => showLoadingSpinner("Todoリストを更新中..."), // working_memoryタグが終了するときに呼び出される onEnd: () => hideLoadingSpinner(), // マスクされたコンテンツで呼び出される onMask: (chunk) => console.debug("更新されたTodoリスト:", chunk), }); // マスクされたストリームを処理する for await (const chunk of maskedStream) { process.stdout.write(chunk); } ``` この例では以下を示しています: 1. ワーキングメモリを有効にしたメモリシステムのセットアップ 2. 構造化XMLを持つTodoリストテンプレートの作成 3. `maskStreamTags`を使用してメモリ更新をユーザーから隠す 4. ライフサイクルフックを使用してメモリ更新中にUIローディング状態を提供する コンテキスト内に1つのメッセージしかない場合でも(`lastMessages: 1`)、エージェントはワーキングメモリに完全なTodoリストを維持します。エージェントが応答するたびに、Todoリストの現在の状態でワーキングメモリを更新し、対話間の永続性を確保します。 エージェントメモリについて、他のメモリタイプやストレージオプションを含めて詳しく知るには、[メモリのドキュメント](/docs/agents/agent-memory)ページをご覧ください。 --- title: ストリーミングワーキングメモリ description: エージェントでワーキングメモリを使用する例 --- # ストリーミングワーキングメモリ [JA] Source: https://mastra.ai/ja/examples/memory/streaming-working-memory この例では、ユーザーの名前、場所、好みなどの関連する会話の詳細を維持するワーキングメモリを持つエージェントを作成する方法を示しています。 ## セットアップ まず、ワーキングメモリを有効にしてメモリシステムをセットアップします。設定されたストレージプロバイダーなしの `new Memory()` は、アプリケーションの再起動間でデータを保持しないことに注意してください。データを永続化するには、`@mastra/libsql` のようなストレージプロバイダーを設定できます: ```typescript import { Memory } from "@mastra/memory"; const memory = new Memory({ options: { workingMemory: { enabled: true, }, }, storage: new LibSQLStore({ url: "file:../mastra.db", }), }); ``` メモリインスタンスをエージェントに追加します: ```typescript import { openai } from "@ai-sdk/openai"; const agent = new Agent({ name: "Memory agent", instructions: "You are a helpful AI assistant.", model: openai("gpt-4o-mini"), memory, // または toolCallMemory }); ``` ## 使用例 ワーキングメモリーの設定が完了したら、エージェントと対話することができ、エージェントは対話の重要な詳細を記憶します。 ```typescript import { randomUUID } from "crypto"; const threadId = randomUUID(); const resourceId = "SOME_USER_ID"; const response = await agent.stream("Hello, my name is Jane", { threadId, resourceId, }); for await (const chunk of response.textStream) { process.stdout.write(chunk); } ``` ## 概要 この例では以下のことを示しています: 1. ワーキングメモリを有効にしたメモリのセットアップ 2. エージェントが対話間で関連するユーザー情報を維持する方法 ## 高度なユースケース ワーキングメモリに関連する情報の制御や、ワーキングメモリが保存されている間の読み込み状態の表示については、[高度なワーキングメモリの例](/examples/memory/streaming-working-memory-advanced)をご覧ください。 エージェントメモリについて、他のメモリタイプやストレージオプションを含む詳細は、[メモリのドキュメント](/docs/agents/agent-memory)ページをご確認ください。 --- title: AI SDK useChat フック description: Mastra メモリを Vercel AI SDK useChat フックと統合する方法の例を示します。 --- # 例:AI SDK `useChat` フック [JA] Source: https://mastra.ai/ja/examples/memory/use-chat Mastraのメモリを、Vercel AI SDKの`useChat`フックを使ってReactのようなフロントエンドフレームワークと統合する際は、メッセージ履歴の重複を避けるために慎重な取り扱いが必要です。この例では、推奨されるパターンを示します。 ## `useChat`を使用したメッセージの重複防止 `useChat`のデフォルト動作では、リクエストごとにチャット履歴全体を送信します。Mastraのメモリは`threadId`に基づいて自動的に履歴を取得するため、クライアントから完全な履歴を送信すると、コンテキストウィンドウとストレージにメッセージが重複して表示されます。 **解決策:** `useChat`を設定して、**最新のメッセージのみ**を`threadId`と`resourceId`と一緒に送信するようにします。 ```typescript // components/Chat.tsx (React Example) import { useChat } from "ai/react"; export function Chat({ threadId, resourceId }) { const { messages, input, handleInputChange, handleSubmit } = useChat({ api: "/api/chat", // Your backend endpoint // Pass only the latest message and custom IDs experimental_prepareRequestBody: (request) => { // Ensure messages array is not empty and get the last message const lastMessage = request.messages.length > 0 ? request.messages[request.messages.length - 1] : null; // Return the structured body for your API route return { message: lastMessage, // Send only the most recent message content/role threadId, resourceId, }; }, // Optional: Initial messages if loading history from backend // initialMessages: loadedMessages, }); // ... rest of your chat UI component return (
{/* Render messages */}
); } // app/api/chat/route.ts (Next.js Example) import { Agent } from "@mastra/core/agent"; import { Memory } from "@mastra/memory"; import { LibSQLStore } from "@mastra/libsql"; import { openai } from "@ai-sdk/openai"; import { CoreMessage } from "@mastra/core"; const agent = new Agent({ name: "ChatAgent", instructions: "You are a helpful assistant.", model: openai("gpt-4o"), memory: new Memory({ storage: new LibSQLStore({ url: "file:../mastra.db", // Or your database URL }), }); }); export async function POST(request: Request) { // Get data structured by experimental_prepareRequestBody const { message, threadId, resourceId }: { message: CoreMessage | null; threadId: string; resourceId: string } = await request.json(); // Handle cases where message might be null (e.g., initial load or error) if (!message || !message.content) { // Return an appropriate response or error return new Response("Missing message content", { status: 400 }); } // Process with memory using the single message content const stream = await agent.stream(message.content, { threadId, resourceId, // Pass other message properties if needed, e.g., role // messageOptions: { role: message.role } }); // Return the streaming response return stream.toDataStreamResponse(); } ``` 詳細については、[メッセージ永続化に関するAI SDKのドキュメント](https://sdk.vercel.ai/docs/ai-sdk-ui/chatbot-message-persistence)を参照してください。 ## 基本的なスレッド管理UI このページでは主に `useChat` に焦点を当てていますが、スレッドの管理(一覧表示、作成、選択)用のUIも構築できます。これには通常、Mastraのメモリ機能である `memory.getThreadsByResourceId()` や `memory.createThread()` などと連携するバックエンドAPIエンドポイントが関与します。 ```typescript // Conceptual React component for a thread list import React, { useState, useEffect } from 'react'; // Assume API functions exist: fetchThreads, createNewThread async function fetchThreads(userId: string): Promise<{ id: string; title: string }[]> { /* ... */ } async function createNewThread(userId: string): Promise<{ id: string; title: string }> { /* ... */ } function ThreadList({ userId, currentThreadId, onSelectThread }) { const [threads, setThreads] = useState([]); // ... loading and error states ... useEffect(() => { // Fetch threads for userId }, [userId]); const handleCreateThread = async () => { // Call createNewThread API, update state, select new thread }; // ... render UI with list of threads and New Conversation button ... return (

Conversations

    {threads.map(thread => (
  • ))}
); } // Example Usage in a Parent Chat Component function ChatApp() { const userId = "user_123"; const [currentThreadId, setCurrentThreadId] = useState(null); return (
{currentThreadId ? ( // Your useChat component ) : (
Select or start a conversation.
)}
); } ``` ## 関連 - **[はじめに](../../docs/memory/overview.mdx)**:`resourceId` と `threadId` の基本的な概念について説明します。 - **[Memory リファレンス](../../reference/memory/Memory.mdx)**:`Memory` クラスのメソッドに関する API 詳細。 --- title: "例:チャンクデリミタの調整 | RAG | Mastra ドキュメント" description: Mastraでチャンクデリミタを調整して、コンテンツ構造により適合させる方法。 --- import { GithubLink } from "@/components/github-link"; # チャンク区切りを調整する [JA] Source: https://mastra.ai/ja/examples/rag/chunking/adjust-chunk-delimiters 大きなドキュメントを処理する際、テキストを小さなチャンクに分割する方法を制御したい場合があります。デフォルトでは、ドキュメントは改行で分割されますが、この動作をカスタマイズしてコンテンツ構造により適合させることができます。この例では、ドキュメントをチャンク化するためのカスタム区切り文字を指定する方法を示します。 ```tsx copy import { MDocument } from "@mastra/rag"; const doc = MDocument.fromText("Your plain text content..."); const chunks = await doc.chunk({ separator: "\n", }); ```




--- title: "例:チャンクサイズの調整 | RAG | Mastra ドキュメント" description: Mastraでチャンクサイズを調整して、コンテンツとメモリ要件により適合させます。 --- import { GithubLink } from "@/components/github-link"; # チャンクサイズの調整 [JA] Source: https://mastra.ai/ja/examples/rag/chunking/adjust-chunk-size 大きなドキュメントを処理する際には、各チャンクに含まれるテキストの量を調整する必要があるかもしれません。デフォルトでは、チャンクは1024文字の長さですが、このサイズをカスタマイズして、コンテンツやメモリの要件により適合させることができます。この例では、ドキュメントを分割する際にカスタムチャンクサイズを設定する方法を示します。 ```tsx copy import { MDocument } from "@mastra/rag"; const doc = MDocument.fromText("Your plain text content..."); const chunks = await doc.chunk({ size: 512, }); ```




--- title: "例:HTMLのセマンティックチャンキング | RAG | Mastra ドキュメント" description: MastraでドキュメントをセマンティックにチャンクするためにHTMLコンテンツをチャンクする。 --- import { GithubLink } from "@/components/github-link"; # HTMLを意味的に分割する [JA] Source: https://mastra.ai/ja/examples/rag/chunking/chunk-html HTMLコンテンツを扱う際、ドキュメントの構造を維持しながら、より小さく管理しやすい部分に分割する必要がよくあります。`chunk`メソッドは、HTMLタグと要素の整合性を保ちながら、HTMLコンテンツを賢く分割します。この例は、検索や取得の目的でHTMLドキュメントをどのように分割するかを示しています。 ```tsx copy import { MDocument } from "@mastra/rag"; const html = `

h1 content...

p content...

`; const doc = MDocument.fromHTML(html); const chunks = await doc.chunk({ headers: [ ["h1", "Header 1"], ["p", "Paragraph"], ], }); console.log(chunks); ```




--- title: "例:JSONのセマンティックチャンキング | RAG | Mastra ドキュメント" description: MastraでセマンティックにドキュメントをチャンクするためのJSONデータのチャンキング。 --- import { GithubLink } from "@/components/github-link"; # JSONを意味的に分割する [JA] Source: https://mastra.ai/ja/examples/rag/chunking/chunk-json JSONデータを扱う際には、オブジェクトの構造を保持しながら小さな部分に分割する必要があります。chunkメソッドは、キーと値の関係を維持しながら、JSONコンテンツを賢く分解します。この例は、検索や取得の目的でJSONドキュメントをどのように分割するかを示しています。 ```tsx copy import { MDocument } from "@mastra/rag"; const testJson = { name: "John Doe", age: 30, email: "john.doe@example.com", }; const doc = MDocument.fromJSON(JSON.stringify(testJson)); const chunks = await doc.chunk({ maxSize: 100, }); console.log(chunks); ```




--- title: "例:マークダウンのセマンティックチャンキング | RAG | Mastra ドキュメント" description: 検索や取得目的でマークダウン文書をチャンク化するためのMastraの使用例。 --- import { GithubLink } from "@/components/github-link"; # チャンクマークダウン [JA] Source: https://mastra.ai/ja/examples/rag/chunking/chunk-markdown Markdownは生のHTMLよりも情報密度が高く、RAGパイプラインでの作業が容易です。Markdownを扱う際には、ヘッダーやフォーマットを保持しながら小さな部分に分割する必要があります。`chunk`メソッドは、ヘッダー、リスト、コードブロックのようなMarkdown特有の要素を賢く処理します。この例は、検索や取得の目的でMarkdownドキュメントをチャンクする方法を示しています。 ```tsx copy import { MDocument } from "@mastra/rag"; const doc = MDocument.fromMarkdown("# Your markdown content..."); const chunks = await doc.chunk(); ```




--- title: "例:テキストの意味的チャンキング | RAG | Mastra ドキュメント" description: 大きなテキスト文書を処理のために小さなチャンクに分割するためのMastraの使用例。 --- import { GithubLink } from "@/components/github-link"; # チャンクテキスト [JA] Source: https://mastra.ai/ja/examples/rag/chunking/chunk-text 大きなテキストドキュメントを扱う際には、処理のためにそれらを小さく管理しやすい部分に分割する必要があります。チャンクメソッドは、検索、分析、または取得に使用できるセグメントにテキストコンテンツを分割します。この例では、デフォルト設定を使用してプレーンテキストをチャンクに分割する方法を示します。 ```tsx copy import { MDocument } from "@mastra/rag"; const doc = MDocument.fromText("Your plain text content..."); const chunks = await doc.chunk(); ```




--- title: "例: チャンク配列の埋め込み | RAG | Mastra ドキュメント" description: 類似性検索のために、Mastra を使ってテキストチャンクの配列に対して埋め込みを生成する例です。 --- import { GithubLink } from "@/components/github-link"; # Embed Chunk Array [JA] Source: https://mastra.ai/ja/examples/rag/embedding/embed-chunk-array ドキュメントをチャンク化した後、テキストチャンクを類似検索に利用できる数値ベクトルに変換する必要があります。`embed` メソッドは、選択したプロバイダーとモデルを使ってテキストチャンクを埋め込みに変換します。この例では、テキストチャンクの配列に対して埋め込みを生成する方法を示しています。 ```tsx copy import { openai } from "@ai-sdk/openai"; import { MDocument } from "@mastra/rag"; import { embed } from "ai"; const doc = MDocument.fromText("Your text content..."); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: chunks.map((chunk) => chunk.text), }); ```




--- title: "例: テキストチャンクの埋め込み | RAG | Mastra ドキュメント" description: 類似性検索のために、Mastra を使って単一のテキストチャンクの埋め込みを生成する例です。 --- import { GithubLink } from "@/components/github-link"; # テキストチャンクの埋め込み [JA] Source: https://mastra.ai/ja/examples/rag/embedding/embed-text-chunk 個々のテキストチャンクを扱う際には、類似性検索のためにそれらを数値ベクトルに変換する必要があります。`embed` メソッドは、選択したプロバイダーとモデルを使用して、単一のテキストチャンクを埋め込みに変換します。 ```tsx copy import { openai } from "@ai-sdk/openai"; import { MDocument } from "@mastra/rag"; import { embed } from "ai"; const doc = MDocument.fromText("Your text content..."); const chunks = await doc.chunk(); const { embedding } = await embed({ model: openai.embedding("text-embedding-3-small"), value: chunks[0].text, }); ```




--- title: "例: Cohere を使ったテキスト埋め込み | RAG | Mastra ドキュメント" description: Mastra を使って Cohere の埋め込みモデルで埋め込みを生成する例。 --- import { GithubLink } from "@/components/github-link"; # Cohereでテキストを埋め込む [JA] Source: https://mastra.ai/ja/examples/rag/embedding/embed-text-with-cohere 他の埋め込みプロバイダーを利用する場合、選択したモデルの仕様に合ったベクトルを生成する方法が必要です。`embed`メソッドは複数のプロバイダーをサポートしており、さまざまな埋め込みサービスを切り替えて利用できます。この例では、Cohereの埋め込みモデルを使って埋め込みを生成する方法を示します。 ```tsx copy import { cohere } from "@ai-sdk/cohere"; import { MDocument } from "@mastra/rag"; import { embedMany } from "ai"; const doc = MDocument.fromText("Your text content..."); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ model: cohere.embedding("embed-english-v3.0"), values: chunks.map((chunk) => chunk.text), }); ```




--- title: "例: メタデータ抽出 | 検索 | RAG | Mastra ドキュメント" description: Mastra でドキュメントからメタデータを抽出し、強化されたドキュメント処理と検索に活用する例。 --- import { GithubLink } from "@/components/github-link"; # メタデータ抽出 [JA] Source: https://mastra.ai/ja/examples/rag/embedding/metadata-extraction この例では、Mastra のドキュメント処理機能を使ってドキュメントからメタデータを抽出し、活用する方法を示します。 抽出されたメタデータは、ドキュメントの整理、フィルタリング、RAG システムでの高度な検索に利用できます。 ## 概要 このシステムは、2つの方法でメタデータ抽出を実演します。 1. ドキュメントからの直接的なメタデータ抽出 2. チャンク分割とメタデータ抽出 ## セットアップ ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { MDocument } from "@mastra/rag"; ``` ## ドキュメント作成 テキストコンテンツからドキュメントを作成します: ```typescript copy showLineNumbers{3} filename="src/index.ts" const doc = MDocument.fromText(`Title: The Benefits of Regular Exercise Regular exercise has numerous health benefits. It improves cardiovascular health, strengthens muscles, and boosts mental wellbeing. Key Benefits: • Reduces stress and anxiety • Improves sleep quality • Helps maintain healthy weight • Increases energy levels For optimal results, experts recommend at least 150 minutes of moderate exercise per week.`); ``` ## 1. 直接メタデータ抽出 ドキュメントから直接メタデータを抽出します: ```typescript copy showLineNumbers{17} filename="src/index.ts" // Configure metadata extraction options await doc.extractMetadata({ keywords: true, // Extract important keywords summary: true, // Generate a concise summary }); // Retrieve the extracted metadata const meta = doc.getMetadata(); console.log("Extracted Metadata:", meta); // Example Output: // Extracted Metadata: { // keywords: [ // 'exercise', // 'health benefits', // 'cardiovascular health', // 'mental wellbeing', // 'stress reduction', // 'sleep quality' // ], // summary: 'Regular exercise provides multiple health benefits including improved cardiovascular health, muscle strength, and mental wellbeing. Key benefits include stress reduction, better sleep, weight management, and increased energy. Recommended exercise duration is 150 minutes per week.' // } ``` ## 2. メタデータ付きチャンク化 ドキュメントのチャンク化とメタデータ抽出を組み合わせます: ```typescript copy showLineNumbers{40} filename="src/index.ts" // Configure chunking with metadata extraction await doc.chunk({ strategy: "recursive", // Use recursive chunking strategy size: 200, // Maximum chunk size extract: { keywords: true, // Extract keywords per chunk summary: true, // Generate summary per chunk }, }); // Get metadata from chunks const metaTwo = doc.getMetadata(); console.log("Chunk Metadata:", metaTwo); // Example Output: // Chunk Metadata: { // keywords: [ // 'exercise', // 'health benefits', // 'cardiovascular health', // 'mental wellbeing', // 'stress reduction', // 'sleep quality' // ], // summary: 'Regular exercise provides multiple health benefits including improved cardiovascular health, muscle strength, and mental wellbeing. Key benefits include stress reduction, better sleep, weight management, and increased energy. Recommended exercise duration is 150 minutes per week.' // } ```




--- title: "例: ハイブリッドベクトル検索 | RAG | Mastra ドキュメント" description: PGVector でメタデータフィルターを使用し、Mastra のベクトル検索結果を強化する例。 --- import { GithubLink } from "@/components/github-link"; # ハイブリッドベクター検索 [JA] Source: https://mastra.ai/ja/examples/rag/query/hybrid-vector-search ベクター類似性検索とメタデータフィルターを組み合わせることで、より精度が高く効率的なハイブリッド検索を実現できます。 このアプローチは以下を組み合わせています: - 最も関連性の高いドキュメントを見つけるためのベクター類似性検索 - 追加の条件に基づいて検索結果を絞り込むためのメタデータフィルター この例では、Mastra と PGVector を使ったハイブリッドベクター検索の方法を示します。 ## 概要 このシステムは、Mastra と PGVector を使用したフィルタ付きベクトル検索を実装しています。主な機能は以下の通りです。 1. PGVector に保存されている既存の埋め込みをメタデータフィルターで検索します 2. 異なるメタデータフィールドでのフィルタリング方法を示します 3. ベクトル類似度とメタデータフィルタリングの組み合わせを実演します > **注意**: ドキュメントからメタデータを抽出する方法の例については、[Metadata Extraction](../embedding/metadata-extraction.mdx) ガイドをご覧ください。 > > 埋め込みの作成と保存方法については、[Upsert Embeddings](/examples/rag/upsert/upsert-embeddings) ガイドをご参照ください。 ## セットアップ ### 環境設定 環境変数を必ず設定してください: ```bash filename=".env" OPENAI_API_KEY=your_openai_api_key_here POSTGRES_CONNECTION_STRING=your_connection_string_here ``` ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { embed } from "ai"; import { PgVector } from "@mastra/pg"; import { openai } from "@ai-sdk/openai"; ``` ## ベクターストアの初期化 接続文字列を使ってPgVectorを初期化します: ```typescript copy showLineNumbers{4} filename="src/index.ts" const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); ``` ## 使用例 ### メタデータ値でフィルタリング ```typescript copy showLineNumbers{6} filename="src/index.ts" // Create embedding for the query const { embedding } = await embed({ model: openai.embedding("text-embedding-3-small"), value: "[Insert query based on document here]", }); // Query with metadata filter const result = await pgVector.query({ indexName: "embeddings", queryVector: embedding, topK: 3, filter: { "path.to.metadata": { $eq: "value", }, }, }); console.log("Results:", result); ```




--- title: "例: Top-K結果の取得 | RAG | Mastra ドキュメント" description: Mastraを使用してベクトルデータベースにクエリを実行し、意味的に類似したチャンクを取得する例。 --- import { GithubLink } from "@/components/github-link"; # トップK件の結果を取得する [JA] Source: https://mastra.ai/ja/examples/rag/query/retrieve-results 埋め込みをベクトルデータベースに保存した後、類似したコンテンツを見つけるためにクエリを実行する必要があります。 `query`メソッドは、入力埋め込みに意味的に最も類似したチャンクを関連性順に返します。`topK`パラメータを使用して、返す結果の数を指定できます。 この例では、Pineconeベクトルデータベースから類似したチャンクを取得する方法を示しています。 ```tsx copy import { openai } from "@ai-sdk/openai"; import { PineconeVector } from "@mastra/pinecone"; import { MDocument } from "@mastra/rag"; import { embedMany } from "ai"; const doc = MDocument.fromText("Your text content..."); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map((chunk) => chunk.text), model: openai.embedding("text-embedding-3-small"), }); const pinecone = new PineconeVector({ apiKey: "your-api-key", }); await pinecone.createIndex({ indexName: "test_index", dimension: 1536, }); await pinecone.upsert({ indexName: "test_index", vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); const topK = 10; const results = await pinecone.query({ indexName: "test_index", queryVector: embeddings[0], topK, }); console.log(results); ```




--- title: "例: ツールを使った再ランキング結果 | 検索 | RAG | Mastra ドキュメント" description: OpenAI の埋め込みと PGVector を使って、Mastra で再ランキングを実装した RAG システムの例。 --- import { GithubLink } from "@/components/github-link"; # ツールを使った再ランキング結果 [JA] Source: https://mastra.ai/ja/examples/rag/rerank/rerank-rag この例では、Mastra のベクトルクエリツールを使用して、OpenAI の埋め込みと PGVector をベクトルストレージとして活用し、再ランキングを行う Retrieval-Augmented Generation(RAG)システムを実装する方法を示します。 ## 概要 このシステムは、Mastra と OpenAI を用いた再ランク付き RAG を実装しています。主な機能は以下の通りです。 1. 応答生成のために gpt-4o-mini を使った Mastra エージェントをセットアップします 2. 再ランク機能を備えたベクトルクエリツールを作成します 3. テキストドキュメントを小さなセグメントに分割し、それらから埋め込みを作成します 4. それらを PostgreSQL ベクトルデータベースに保存します 5. クエリに基づいて関連するチャンクを取得し、再ランクします 6. Mastra エージェントを使ってコンテキストに応じた応答を生成します ## セットアップ ### 環境設定 環境変数を設定してください: ```bash filename=".env" OPENAI_API_KEY=your_openai_api_key_here POSTGRES_CONNECTION_STRING=your_connection_string_here ``` ### 依存関係 次に、必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="index.ts" import { openai } from "@ai-sdk/openai"; import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { PgVector } from "@mastra/pg"; import { MDocument, createVectorQueryTool } from "@mastra/rag"; import { embedMany } from "ai"; ``` ## リランキング付きベクタークエリツールの作成 @mastra/rag からインポートした createVectorQueryTool を使用すると、ベクターデータベースにクエリを実行し、結果をリランキングするツールを作成できます。 ```typescript copy showLineNumbers{8} filename="index.ts" const vectorQueryTool = createVectorQueryTool({ vectorStoreName: "pgVector", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), reranker: { model: openai("gpt-4o-mini"), }, }); ``` ## エージェント設定 応答を処理するMastraエージェントを設定します: ```typescript copy showLineNumbers{17} filename="index.ts" export const ragAgent = new Agent({ name: "RAG Agent", instructions: `You are a helpful assistant that answers questions based on the provided context. Keep your answers concise and relevant. Important: When asked to answer a question, please base your answer only on the context provided in the tool. If the context doesn't contain enough information to fully answer the question, please state that explicitly.`, model: openai("gpt-4o-mini"), tools: { vectorQueryTool, }, }); ``` ## PgVector と Mastra のインスタンス化 以下のコンポーネントを使って PgVector と Mastra をインスタンス化します。 ```typescript copy showLineNumbers{29} filename="index.ts" const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); export const mastra = new Mastra({ agents: { ragAgent }, vectors: { pgVector }, }); const agent = mastra.getAgent("ragAgent"); ``` ## ドキュメント処理 ドキュメントを作成し、チャンクに分割します: ```typescript copy showLineNumbers{38} filename="index.ts" const doc1 = MDocument.fromText(` market data shows price resistance levels. technical charts display moving averages. support levels guide trading decisions. breakout patterns signal entry points. price action determines trade timing. baseball cards show gradual value increase. rookie cards command premium prices. card condition affects resale value. authentication prevents fake trading. grading services verify card quality. volume analysis confirms price trends. sports cards track seasonal demand. chart patterns predict movements. mint condition doubles card worth. resistance breaks trigger orders. rare cards appreciate yearly. `); const chunks = await doc1.chunk({ strategy: "recursive", size: 150, overlap: 20, separator: "\n", }); ``` ## 埋め込みの作成と保存 チャンクの埋め込みを生成し、ベクターデータベースに保存します。 ```typescript copy showLineNumbers{66} filename="index.ts" const { embeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: chunks.map((chunk) => chunk.text), }); const vectorStore = mastra.getVector("pgVector"); await vectorStore.createIndex({ indexName: "embeddings", dimension: 1536, }); await vectorStore.upsert({ indexName: "embeddings", vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); ``` ## リランキングによるクエリ リランキングが結果にどのように影響するか、さまざまなクエリを試してみましょう。 ```typescript copy showLineNumbers{82} filename="index.ts" const queryOne = "explain technical trading analysis"; const answerOne = await agent.generate(queryOne); console.log("\nQuery:", queryOne); console.log("Response:", answerOne.text); const queryTwo = "explain trading card valuation"; const answerTwo = await agent.generate(queryTwo); console.log("\nQuery:", queryTwo); console.log("Response:", answerTwo.text); const queryThree = "how do you analyze market resistance"; const answerThree = await agent.generate(queryThree); console.log("\nQuery:", queryThree); console.log("Response:", answerThree.text); ```




--- title: "例: 結果の再ランキング | 検索 | RAG | Mastra ドキュメント" description: OpenAI の埋め込みと PGVector を使ったベクトルストレージによる、Mastra でのセマンティック再ランキング実装例。 --- import { GithubLink } from "@/components/github-link"; # 再ランキング結果 [JA] Source: https://mastra.ai/ja/examples/rag/rerank/rerank この例では、Mastra、OpenAIの埋め込み、そしてベクトルストレージとしてPGVectorを使用し、再ランキングを取り入れたRetrieval-Augmented Generation(RAG)システムの実装方法を示します。 ## 概要 このシステムは、Mastra と OpenAI を用いた再ランキング付き RAG を実装しています。主な処理内容は以下の通りです。 1. テキストドキュメントを小さなセグメントに分割し、それらから埋め込みを作成します 2. ベクトルを PostgreSQL データベースに保存します 3. 初期のベクトル類似度検索を実行します 4. Mastra の rerank 関数を使い、ベクトル類似度・セマンティック関連性・位置スコアを組み合わせて結果を再ランキングします 5. 初期結果と再ランキング後の結果を比較し、改善点を表示します ## セットアップ ### 環境設定 環境変数を必ず設定してください: ```bash filename=".env" OPENAI_API_KEY=your_openai_api_key_here POSTGRES_CONNECTION_STRING=your_connection_string_here ``` ### 依存関係 次に、必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { PgVector } from "@mastra/pg"; import { MDocument, rerank } from "@mastra/rag"; import { embedMany, embed } from "ai"; ``` ## ドキュメント処理 ドキュメントを作成し、チャンクに分割します: ```typescript copy showLineNumbers{7} filename="src/index.ts" const doc1 = MDocument.fromText(` market data shows price resistance levels. technical charts display moving averages. support levels guide trading decisions. breakout patterns signal entry points. price action determines trade timing. `); const chunks = await doc1.chunk({ strategy: "recursive", size: 150, overlap: 20, separator: "\n", }); ``` ## 埋め込みの作成と保存 チャンクの埋め込みを生成し、ベクターデータベースに保存します。 ```typescript copy showLineNumbers{36} filename="src/index.ts" const { embeddings } = await embedMany({ values: chunks.map((chunk) => chunk.text), model: openai.embedding("text-embedding-3-small"), }); const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); await pgVector.createIndex({ indexName: "embeddings", dimension: 1536, }); await pgVector.upsert({ indexName: "embeddings", vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); ``` ## ベクター検索とリランキング ベクター検索を実行し、結果をリランキングします: ```typescript copy showLineNumbers{51} filename="src/index.ts" const query = "explain technical trading analysis"; // Get query embedding const { embedding: queryEmbedding } = await embed({ value: query, model: openai.embedding("text-embedding-3-small"), }); // Get initial results const initialResults = await pgVector.query({ indexName: "embeddings", queryVector: queryEmbedding, topK: 3, }); // Re-rank results const rerankedResults = await rerank( initialResults, query, openai("gpt-4o-mini"), { weights: { semantic: 0.5, // How well the content matches the query semantically vector: 0.3, // Original vector similarity score position: 0.2, // Preserves original result ordering }, topK: 3, }, ); ``` 重み付けによって、さまざまな要素が最終的なランキングにどのように影響するかを制御します: - `semantic`: 値が高いほど、クエリとの意味的な理解や関連性が優先されます - `vector`: 値が高いほど、元のベクター類似度スコアが重視されます - `position`: 値が高いほど、元の結果の順序が維持されやすくなります ## 結果の比較 初期結果と再ランク付け後の結果の両方を表示して、改善点を確認しましょう。 ```typescript copy showLineNumbers{72} filename="src/index.ts" console.log("Initial Results:"); initialResults.forEach((result, index) => { console.log(`Result ${index + 1}:`, { text: result.metadata.text, score: result.score, }); }); console.log("Re-ranked Results:"); rerankedResults.forEach(({ result, score, details }, index) => { console.log(`Result ${index + 1}:`, { text: result.metadata.text, score: score, semantic: details.semantic, vector: details.vector, position: details.position, }); }); ``` 再ランク付け後の結果は、ベクトル類似度とセマンティックな理解を組み合わせることで、検索品質がどのように向上するかを示しています。各結果には以下が含まれます: - すべての要素を組み合わせた総合スコア - 言語モデルによるセマンティック関連度スコア - 埋め込み比較によるベクトル類似度スコア - 必要に応じて元の順序を維持するための位置ベースのスコア




--- title: "例: Cohereによるリランキング | RAG | Mastra ドキュメント" description: Mastraを使用してCohereのリランキングサービスでドキュメント検索の関連性を向上させる例。 --- # Cohereによるリランキング [JA] Source: https://mastra.ai/ja/examples/rag/rerank/reranking-with-cohere RAGのためにドキュメントを検索する際、初期のベクトル類似度検索では重要なセマンティックな一致を見逃すことがあります。 Cohereのリランキングサービスは、複数のスコアリング要素を用いてドキュメントの順序を並べ替えることで、結果の関連性を向上させます。 ```typescript import { rerank } from "@mastra/rag"; const results = rerank( searchResults, "deployment configuration", cohere("rerank-v3.5"), { topK: 5, weights: { semantic: 0.4, vector: 0.4, position: 0.2, }, }, ); ``` ## リンク - [rerank() リファレンス](/reference/rag/rerank.mdx) - [リトリーバル ドキュメント](/reference/rag/retrieval.mdx) --- title: "例: 埋め込みのアップサート | RAG | Mastra ドキュメント" description: 類似性検索のために、Mastra を使ってさまざまなベクトルデータベースに埋め込みを保存する例。 --- import { Tabs } from "nextra/components"; import { GithubLink } from "@/components/github-link"; # Upsert Embeddings [JA] Source: https://mastra.ai/ja/examples/rag/upsert/upsert-embeddings 埋め込みを生成した後、ベクトル類似性検索をサポートするデータベースに保存する必要があります。この例では、後で取得するために様々なベクトルデータベースに埋め込みを保存する方法を示します。 {/* LLM CONTEXT: This Tabs component demonstrates how to upsert (insert/update) embeddings into different vector databases. Each tab shows a complete example of storing embeddings in a specific vector database provider. The tabs help users understand the consistent API pattern across different vector stores while showing provider-specific configuration. Each tab includes document chunking, embedding generation, index creation, and data insertion for that specific database. The providers include PgVector, Pinecone, Qdrant, Chroma, Astra DB, LibSQL, Upstash, Cloudflare, MongoDB, OpenSearch, and Couchbase. */} `PgVector`クラスは、pgvector拡張機能を使用してPostgreSQLにインデックスを作成し、埋め込みを挿入するメソッドを提供します。 ```tsx copy import { openai } from "@ai-sdk/openai"; import { PgVector } from "@mastra/pg"; import { MDocument } from "@mastra/rag"; import { embedMany } from "ai"; const doc = MDocument.fromText("Your text content..."); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding("text-embedding-3-small"), }); const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING! }); await pgVector.createIndex({ indexName: "test_index", dimension: 1536, }); await pgVector.upsert({ indexName: "test_index", vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); ```


`PineconeVector`クラスは、マネージドベクターデータベースサービスであるPineconeにインデックスを作成し、埋め込みを挿入するメソッドを提供します。 ```tsx copy import { openai } from '@ai-sdk/openai'; import { PineconeVector } from '@mastra/pinecone'; import { MDocument } from '@mastra/rag'; import { embedMany } from 'ai'; const doc = MDocument.fromText('Your text content...'); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding('text-embedding-3-small'), }); const pinecone = new PineconeVector({ apiKey: process.env.PINECONE_API_KEY!, }); await pinecone.createIndex({ indexName: 'testindex', dimension: 1536, }); await pinecone.upsert({ indexName: 'testindex', vectors: embeddings, metadata: chunks?.map(chunk => ({ text: chunk.text })), }); ```


`QdrantVector`クラスは、高性能ベクターデータベースであるQdrantにコレクションを作成し、埋め込みを挿入するメソッドを提供します。 ```tsx copy import { openai } from '@ai-sdk/openai'; import { QdrantVector } from '@mastra/qdrant'; import { MDocument } from '@mastra/rag'; import { embedMany } from 'ai'; const doc = MDocument.fromText('Your text content...'); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding('text-embedding-3-small'), maxRetries: 3, }); const qdrant = new QdrantVector({ url: process.env.QDRANT_URL, apiKey: process.env.QDRANT_API_KEY, }); await qdrant.createIndex({ indexName: 'test_collection', dimension: 1536, }); await qdrant.upsert({ indexName: 'test_collection', vectors: embeddings, metadata: chunks?.map(chunk => ({ text: chunk.text })), }); ``` `ChromaVector`クラスは、オープンソースの埋め込みデータベースであるChromaにコレクションを作成し、埋め込みを挿入するためのメソッドを提供します。 ```tsx copy import { openai } from '@ai-sdk/openai'; import { ChromaVector } from '@mastra/chroma'; import { MDocument } from '@mastra/rag'; import { embedMany } from 'ai'; const doc = MDocument.fromText('Your text content...'); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding('text-embedding-3-small'), }); const chroma = new ChromaVector({ path: "path/to/chroma/db", }); await chroma.createIndex({ indexName: 'test_collection', dimension: 1536, }); await chroma.upsert({ indexName: 'test_collection', vectors: embeddings, metadata: chunks.map(chunk => ({ text: chunk.text })), documents: chunks.map(chunk => chunk.text), }); ```


`AstraVector`クラスは、クラウドネイティブなベクターデータベースであるDataStax Astra DBにコレクションを作成し、埋め込みを挿入するためのメソッドを提供します。 ```tsx copy import { openai } from '@ai-sdk/openai'; import { AstraVector } from '@mastra/astra'; import { MDocument } from '@mastra/rag'; import { embedMany } from 'ai'; const doc = MDocument.fromText('Your text content...'); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ model: openai.embedding('text-embedding-3-small'), values: chunks.map(chunk => chunk.text), }); const astra = new AstraVector({ token: process.env.ASTRA_DB_TOKEN, endpoint: process.env.ASTRA_DB_ENDPOINT, keyspace: process.env.ASTRA_DB_KEYSPACE, }); await astra.createIndex({ indexName: 'test_collection', dimension: 1536, }); await astra.upsert({ indexName: 'test_collection', vectors: embeddings, metadata: chunks?.map(chunk => ({ text: chunk.text })), }); ``` `LibSQLVector`クラスは、ベクター拡張を持つSQLiteのフォークであるLibSQLにコレクションを作成し、埋め込みを挿入するためのメソッドを提供します。 ```tsx copy import { openai } from "@ai-sdk/openai"; import { LibSQLVector } from "@mastra/core/vector/libsql"; import { MDocument } from "@mastra/rag"; import { embedMany } from "ai"; const doc = MDocument.fromText("Your text content..."); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map((chunk) => chunk.text), model: openai.embedding("text-embedding-3-small"), }); const libsql = new LibSQLVector({ connectionUrl: process.env.DATABASE_URL, authToken: process.env.DATABASE_AUTH_TOKEN, // Optional: for Turso cloud databases }); await libsql.createIndex({ indexName: "test_collection", dimension: 1536, }); await libsql.upsert({ indexName: "test_collection", vectors: embeddings, metadata: chunks?.map((chunk) => ({ text: chunk.text })), }); ```


`UpstashVector`クラスは、サーバーレスベクターデータベースであるUpstash Vectorにコレクションを作成し、埋め込みを挿入するためのメソッドを提供します。 ```tsx copy import { openai } from '@ai-sdk/openai'; import { UpstashVector } from '@mastra/upstash'; import { MDocument } from '@mastra/rag'; import { embedMany } from 'ai'; const doc = MDocument.fromText('Your text content...'); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding('text-embedding-3-small'), }); const upstash = new UpstashVector({ url: process.env.UPSTASH_URL, token: process.env.UPSTASH_TOKEN, }); // There is no store.createIndex call here, Upstash creates indexes (known as namespaces in Upstash) automatically // when you upsert if that namespace does not exist yet. await upstash.upsert({ indexName: 'test_collection', // the namespace name in Upstash vectors: embeddings, metadata: chunks?.map(chunk => ({ text: chunk.text })), }); ``` `CloudflareVector`クラスは、サーバーレスベクターデータベースサービスであるCloudflare Vectorizeにコレクションを作成し、埋め込みを挿入するためのメソッドを提供します。 ```tsx copy import { openai } from '@ai-sdk/openai'; import { CloudflareVector } from '@mastra/vectorize'; import { MDocument } from '@mastra/rag'; import { embedMany } from 'ai'; const doc = MDocument.fromText('Your text content...'); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding('text-embedding-3-small'), }); const vectorize = new CloudflareVector({ accountId: process.env.CF_ACCOUNT_ID, apiToken: process.env.CF_API_TOKEN, }); await vectorize.createIndex({ indexName: 'test_collection', dimension: 1536, }); await vectorize.upsert({ indexName: 'test_collection', vectors: embeddings, metadata: chunks?.map(chunk => ({ text: chunk.text })), }); ``` `MongoDBVector`クラスは、Atlas Searchを使用してMongoDBにインデックスを作成し、埋め込みを挿入するためのメソッドを提供します。 ```tsx copy import { openai } from "@ai-sdk/openai"; import { MongoDBVector } from "@mastra/mongodb"; import { MDocument } from "@mastra/rag"; import { embedMany } from "ai"; const doc = MDocument.fromText("Your text content..."); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding("text-embedding-3-small"), }); const vectorDB = new MongoDBVector({ uri: process.env.MONGODB_URI!, dbName: process.env.MONGODB_DB_NAME!, }); await vectorDB.createIndex({ indexName: "test_index", dimension: 1536, }); await vectorDB.upsert({ indexName: "test_index", vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); ``` `OpenSearchVector`クラスは、ベクター検索機能を持つ分散検索エンジンであるOpenSearchにインデックスを作成し、埋め込みを挿入するためのメソッドを提供します。 ```tsx copy import { openai } from '@ai-sdk/openai'; import { OpenSearchVector } from '@mastra/opensearch'; import { MDocument } from '@mastra/rag'; import { embedMany } from 'ai'; const doc = MDocument.fromText('Your text content...'); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding('text-embedding-3-small'), }); const vectorDB = new OpenSearchVector({ uri: process.env.OPENSEARCH_URI!, }); await vectorDB.createIndex({ indexName: 'test_index', dimension: 1536, }); await vectorDB.upsert({ indexName: 'test_index', vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); ``` `CouchbaseVector`クラスは、ベクトル検索機能を持つ分散NoSQLデータベースであるCouchbaseにインデックスを作成し、埋め込みを挿入するメソッドを提供します。 ```tsx copy import { openai } from '@ai-sdk/openai'; import { CouchbaseVector } from '@mastra/couchbase'; import { MDocument } from '@mastra/rag'; import { embedMany } from 'ai'; const doc = MDocument.fromText('Your text content...'); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding('text-embedding-3-small'), }); const couchbase = new CouchbaseVector({ connectionString: process.env.COUCHBASE_CONNECTION_STRING, username: process.env.COUCHBASE_USERNAME, password: process.env.COUCHBASE_PASSWORD, bucketName: process.env.COUCHBASE_BUCKET, scopeName: process.env.COUCHBASE_SCOPE, collectionName: process.env.COUCHBASE_COLLECTION, }); await couchbase.createIndex({ indexName: 'test_collection', dimension: 1536, }); await couchbase.upsert({ indexName: 'test_collection', vectors: embeddings, metadata: chunks?.map(chunk => ({ text: chunk.text })), }); ``` `LanceVectorStore`クラスは、Lance列形式上に構築された組み込みベクトルデータベースであるLanceDBにテーブル、インデックスを作成し、埋め込みを挿入するメソッドを提供します。 ```tsx copy import { openai } from '@ai-sdk/openai'; import { LanceVectorStore } from '@mastra/lance'; import { MDocument } from '@mastra/rag'; import { embedMany } from 'ai'; const doc = MDocument.fromText('Your text content...'); const chunks = await doc.chunk(); const { embeddings } = await embedMany({ values: chunks.map(chunk => chunk.text), model: openai.embedding('text-embedding-3-small'), }); const lance = await LanceVectorStore.create('/path/to/db'); // In LanceDB you need to create a table first await lance.createIndex({ tableName: 'myVectors', indexName: 'vector', dimension: 1536, }); await lance.upsert({ tableName: 'myVectors', vectors: embeddings, metadata: chunks?.map(chunk => ({ text: chunk.text })), }); ```
--- title: "例: ベクタークエリツールの使用方法 | RAG | Mastra ドキュメント" description: OpenAI の埋め込みと PGVector を使って、Mastra で基本的な RAG システムを実装する例です。 --- import { GithubLink } from "@/components/github-link"; # ベクタークエリツールの使い方 [JA] Source: https://mastra.ai/ja/examples/rag/usage/basic-rag この例では、RAGシステムにおけるセマンティック検索のための `createVectorQueryTool` の実装と使用方法を示します。ツールの設定方法、ベクターストレージの管理、関連するコンテキストの効果的な取得方法について説明します。 ## 概要 このシステムは、Mastra と OpenAI を使って RAG を実装しています。主な機能は以下の通りです。 1. 応答生成のために gpt-4o-mini を使用した Mastra エージェントをセットアップします 2. ベクトルストアとのやり取りを管理するベクトルクエリツールを作成します 3. 既存の埋め込みを使って関連するコンテキストを取得します 4. Mastra エージェントを使ってコンテキストに応じた応答を生成します > **注意**: 埋め込みの作成と保存方法については、[Upsert Embeddings](/examples/rag/upsert/upsert-embeddings) ガイドをご覧ください。 ## セットアップ ### 環境設定 環境変数を設定してください: ```bash filename=".env" OPENAI_API_KEY=your_openai_api_key_here POSTGRES_CONNECTION_STRING=your_connection_string_here ``` ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="src/index.ts" import { openai } from "@ai-sdk/openai"; import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { createVectorQueryTool } from "@mastra/rag"; import { PgVector } from "@mastra/pg"; ``` ## ベクタークエリツールの作成 ベクターデータベースをクエリできるツールを作成します: ```typescript copy showLineNumbers{7} filename="src/index.ts" const vectorQueryTool = createVectorQueryTool({ vectorStoreName: "pgVector", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), }); ``` ## エージェントの設定 応答を処理するMastraエージェントをセットアップします: ```typescript copy showLineNumbers{13} filename="src/index.ts" export const ragAgent = new Agent({ name: "RAG Agent", instructions: "You are a helpful assistant that answers questions based on the provided context. Keep your answers concise and relevant.", model: openai("gpt-4o-mini"), tools: { vectorQueryTool, }, }); ``` ## PgVector と Mastra のインスタンス化 すべてのコンポーネントを使って PgVector と Mastra をインスタンス化します: ```typescript copy showLineNumbers{23} filename="src/index.ts" const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); export const mastra = new Mastra({ agents: { ragAgent }, vectors: { pgVector }, }); const agent = mastra.getAgent("ragAgent"); ``` ## 使用例 ```typescript copy showLineNumbers{32} filename="src/index.ts" const prompt = ` [Insert query based on document here] Please base your answer only on the context provided in the tool. If the context doesn't contain enough information to fully answer the question, please state that explicitly. `; const completion = await agent.generate(prompt); console.log(completion.text); ```




--- title: "例: 情報密度の最適化 | RAG | Mastra ドキュメント" description: LLMベースの処理を用いて、Mastraで情報密度を最適化し、データの重複を排除するRAGシステムの実装例。 --- import { GithubLink } from "@/components/github-link"; # 情報密度の最適化 [JA] Source: https://mastra.ai/ja/examples/rag/usage/cleanup-rag この例では、Mastra、OpenAIの埋め込み、PGVectorによるベクトルストレージを用いたRetrieval-Augmented Generation(RAG)システムの実装方法を示します。 このシステムでは、エージェントが初期チャンクをクリーンアップし、情報密度を最適化しつつデータの重複を排除します。 ## 概要 このシステムは、Mastra と OpenAI を用いて RAG を実装しており、今回は LLM ベースの処理によって情報密度の最適化を行っています。主な処理内容は以下の通りです。 1. gpt-4o-mini を搭載した Mastra エージェントをセットアップし、クエリとドキュメントのクリーニングの両方に対応 2. エージェントが利用するためのベクトルクエリおよびドキュメント分割ツールを作成 3. 初期ドキュメントの処理: - テキストドキュメントを小さなセグメントに分割 - 各セグメントの埋め込みを作成 - それらを PostgreSQL ベクトルデータベースに保存 4. 初回クエリを実行し、ベースラインとなる応答品質を確認 5. データの最適化: - エージェントを使ってセグメントのクリーニングと重複排除を実施 - クリーニング後のセグメントに対して新たに埋め込みを作成 - 最適化されたデータでベクトルストアを更新 6. 同じクエリを再度実行し、応答品質の向上を確認 ## セットアップ ### 環境のセットアップ 環境変数を必ず設定してください: ```bash filename=".env" OPENAI_API_KEY=your_openai_api_key_here POSTGRES_CONNECTION_STRING=your_connection_string_here ``` ### 依存関係 次に、必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="index.ts" import { openai } from "@ai-sdk/openai"; import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { PgVector } from "@mastra/pg"; import { MDocument, createVectorQueryTool, createDocumentChunkerTool, } from "@mastra/rag"; import { embedMany } from "ai"; ``` ## ツール作成 ### ベクタークエリツール @mastra/rag からインポートした createVectorQueryTool を使用すると、ベクターデータベースにクエリを実行するツールを作成できます。 ```typescript copy showLineNumbers{8} filename="index.ts" const vectorQueryTool = createVectorQueryTool({ vectorStoreName: "pgVector", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), }); ``` ### ドキュメントチャンク化ツール @mastra/rag からインポートした createDocumentChunkerTool を使用すると、ドキュメントをチャンク化し、そのチャンクをエージェントに送信するツールを作成できます。 ```typescript copy showLineNumbers{14} filename="index.ts" const doc = MDocument.fromText(yourText); const documentChunkerTool = createDocumentChunkerTool({ doc, params: { strategy: "recursive", size: 512, overlap: 25, separator: "\n", }, }); ``` ## エージェント設定 クエリとクリーニングの両方を処理できる単一のMastraエージェントをセットアップします。 ```typescript copy showLineNumbers{26} filename="index.ts" const ragAgent = new Agent({ name: "RAG Agent", instructions: `You are a helpful assistant that handles both querying and cleaning documents. When cleaning: Process, clean, and label data, remove irrelevant information and deduplicate content while preserving key facts. When querying: Provide answers based on the available context. Keep your answers concise and relevant. Important: When asked to answer a question, please base your answer only on the context provided in the tool. If the context doesn't contain enough information to fully answer the question, please state that explicitly. `, model: openai("gpt-4o-mini"), tools: { vectorQueryTool, documentChunkerTool, }, }); ``` ## PgVector と Mastra のインスタンス化 次のコンポーネントを使って PgVector と Mastra をインスタンス化します。 ```typescript copy showLineNumbers{41} filename="index.ts" const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); export const mastra = new Mastra({ agents: { ragAgent }, vectors: { pgVector }, }); const agent = mastra.getAgent("ragAgent"); ``` ## ドキュメント処理 最初のドキュメントをチャンク化し、埋め込みを作成します: ```typescript copy showLineNumbers{49} filename="index.ts" const chunks = await doc.chunk({ strategy: "recursive", size: 256, overlap: 50, separator: "\n", }); const { embeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: chunks.map((chunk) => chunk.text), }); const vectorStore = mastra.getVector("pgVector"); await vectorStore.createIndex({ indexName: "embeddings", dimension: 1536, }); await vectorStore.upsert({ indexName: "embeddings", vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); ``` ## 初期クエリ まずは、生データにクエリを実行してベースラインを確認してみましょう。 ```typescript copy showLineNumbers{73} filename="index.ts" // Generate response using the original embeddings const query = "What are all the technologies mentioned for space exploration?"; const originalResponse = await agent.generate(query); console.log("\nQuery:", query); console.log("Response:", originalResponse.text); ``` ## データの最適化 初期結果を確認した後、データの品質を向上させるためにクリーニングを行うことができます: ```typescript copy showLineNumbers{79} filename="index.ts" const chunkPrompt = `Use the tool provided to clean the chunks. Make sure to filter out irrelevant information that is not space related and remove duplicates.`; const newChunks = await agent.generate(chunkPrompt); const updatedDoc = MDocument.fromText(newChunks.text); const updatedChunks = await updatedDoc.chunk({ strategy: "recursive", size: 256, overlap: 50, separator: "\n", }); const { embeddings: cleanedEmbeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: updatedChunks.map((chunk) => chunk.text), }); // Update the vector store with cleaned embeddings await vectorStore.deleteIndex({ indexName: "embeddings" }); await vectorStore.createIndex({ indexName: "embeddings", dimension: 1536, }); await vectorStore.upsert({ indexName: "embeddings", indexName: "embeddings", vectors: cleanedEmbeddings, metadata: updatedChunks?.map((chunk: any) => ({ text: chunk.text })), }); ``` ## 最適化されたクエリ データをクリーンアップした後、再度クエリを実行してレスポンスに違いがあるか観察します。 ```typescript copy showLineNumbers{109} filename="index.ts" // Query again with cleaned embeddings const cleanedResponse = await agent.generate(query); console.log("\nQuery:", query); console.log("Response:", cleanedResponse.text); ```




--- title: "例: Chain of Thought プロンプティング | RAG | Mastra ドキュメント" description: OpenAI と PGVector を使用し、Mastra で chain-of-thought 推論を用いた RAG システムの実装例。 --- import { GithubLink } from "@/components/github-link"; # チェーン・オブ・ソート・プロンプティング [JA] Source: https://mastra.ai/ja/examples/rag/usage/cot-rag この例では、Mastra、OpenAIの埋め込み、そしてベクトルストレージとしてPGVectorを使用し、チェーン・オブ・ソート推論に重点を置いた検索拡張生成(RAG)システムの実装方法を示します。 ## 概要 このシステムは、Mastra と OpenAI を用いて chain-of-thought プロンプティングによる RAG を実装しています。主な処理内容は以下の通りです。 1. 応答生成のために gpt-4o-mini を使った Mastra エージェントをセットアップする 2. ベクタークエリツールを作成し、ベクターストアとのやり取りを管理する 3. テキストドキュメントを小さなセグメントに分割する 4. これらのセグメントに対して埋め込みを作成する 5. それらを PostgreSQL ベクターデータベースに保存する 6. ベクタークエリツールを使ってクエリに基づき関連するセグメントを取得する 7. chain-of-thought 推論を用いてコンテキストに応じた応答を生成する ## セットアップ ### 環境設定 環境変数を必ず設定してください: ```bash filename=".env" OPENAI_API_KEY=your_openai_api_key_here POSTGRES_CONNECTION_STRING=your_connection_string_here ``` ### 依存関係 次に、必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="index.ts" import { openai } from "@ai-sdk/openai"; import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { PgVector } from "@mastra/pg"; import { createVectorQueryTool, MDocument } from "@mastra/rag"; import { embedMany } from "ai"; ``` ## ベクタークエリツールの作成 @mastra/rag からインポートした createVectorQueryTool を使用すると、ベクターデータベースをクエリできるツールを作成できます。 ```typescript copy showLineNumbers{8} filename="index.ts" const vectorQueryTool = createVectorQueryTool({ vectorStoreName: "pgVector", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), }); ``` ## エージェント設定 Mastraエージェントをチェーン・オブ・ソートプロンプティングの指示で設定します: ```typescript copy showLineNumbers{14} filename="index.ts" export const ragAgent = new Agent({ name: "RAG Agent", instructions: `あなたは、提供されたコンテキストに基づいて質問に答える親切なアシスタントです。 各回答について、以下の手順に従ってください: 1. まず、取得したコンテキストチャンクを注意深く分析し、重要な情報を特定します。 2. 取得した情報がクエリとどのように関連しているか、思考プロセスを分解します。 3. 取得したチャンクから異なる部分をどのようにつなげているか説明します。 4. 取得したコンテキストの証拠のみに基づいて結論を導きます。 5. 取得したチャンクに十分な情報が含まれていない場合、不足している内容を明確に述べてください。 回答のフォーマットは以下の通りです: THOUGHT PROCESS: - Step 1: [取得したチャンクの初期分析] - Step 2: [チャンク間のつながり] - Step 3: [チャンクに基づく推論] FINAL ANSWER: [取得したコンテキストに基づく簡潔な回答] 重要: 質問に答えるよう求められた場合は、必ずツールで提供されたコンテキストのみに基づいて回答してください。 もしコンテキストに質問に完全に答えるための十分な情報が含まれていない場合は、その旨を明確に述べてください。 注意: 取得した情報をどのように使って結論に至ったかを説明してください。 `, model: openai("gpt-4o-mini"), tools: { vectorQueryTool }, }); ``` ## PgVector と Mastra のインスタンス化 すべてのコンポーネントを使って PgVector と Mastra をインスタンス化します: ```typescript copy showLineNumbers{36} filename="index.ts" const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); export const mastra = new Mastra({ agents: { ragAgent }, vectors: { pgVector }, }); const agent = mastra.getAgent("ragAgent"); ``` ## ドキュメント処理 ドキュメントを作成し、チャンクに分割して処理します: ```typescript copy showLineNumbers{44} filename="index.ts" const doc = MDocument.fromText( `The Impact of Climate Change on Global Agriculture...`, ); const chunks = await doc.chunk({ strategy: "recursive", size: 512, overlap: 50, separator: "\n", }); ``` ## 埋め込みの作成と保存 チャンクの埋め込みを生成し、ベクターデータベースに保存します。 ```typescript copy showLineNumbers{55} filename="index.ts" const { embeddings } = await embedMany({ values: chunks.map((chunk) => chunk.text), model: openai.embedding("text-embedding-3-small"), }); const vectorStore = mastra.getVector("pgVector"); await vectorStore.createIndex({ indexName: "embeddings", dimension: 1536, }); await vectorStore.upsert({ indexName: "embeddings", vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); ``` ## チェーン・オブ・ソート クエリ エージェントがどのように推論を分解するか、さまざまなクエリを試してみましょう。 ```typescript copy showLineNumbers{83} filename="index.ts" const answerOne = await agent.generate( "What are the main adaptation strategies for farmers?", ); console.log("\nQuery:", "What are the main adaptation strategies for farmers?"); console.log("Response:", answerOne.text); const answerTwo = await agent.generate( "Analyze how temperature affects crop yields.", ); console.log("\nQuery:", "Analyze how temperature affects crop yields."); console.log("Response:", answerTwo.text); const answerThree = await agent.generate( "What connections can you draw between climate change and food security?", ); console.log( "\nQuery:", "What connections can you draw between climate change and food security?", ); console.log("Response:", answerThree.text); ```




--- title: "例: ワークフローによる構造化推論 | RAG | Mastra ドキュメント" description: Mastra のワークフロー機能を使った RAG システムでの構造化推論の実装例。 --- import { GithubLink } from "@/components/github-link"; # ワークフローによる構造化推論 [JA] Source: https://mastra.ai/ja/examples/rag/usage/cot-workflow-rag この例では、Mastra、OpenAIの埋め込み、そしてベクトルストレージとしてPGVectorを使用し、定義されたワークフローを通じて構造化推論を重視したRetrieval-Augmented Generation(RAG)システムの実装方法を示します。 ## 概要 このシステムは、定義されたワークフローを通じて、Mastra と OpenAI を用いた chain-of-thought プロンプトによる RAG を実装しています。主な機能は以下の通りです。 1. 応答生成のために gpt-4o-mini を使った Mastra エージェントをセットアップ 2. ベクトルストアとのやり取りを管理するベクトルクエリツールを作成 3. chain-of-thought 推論のための複数ステップからなるワークフローを定義 4. テキストドキュメントを処理し、チャンク化 5. 埋め込みを作成し、PostgreSQL に保存 6. ワークフローステップを通じて応答を生成 ## セットアップ ### 環境セットアップ 環境変数を必ず設定してください: ```bash filename=".env" OPENAI_API_KEY=your_openai_api_key_here POSTGRES_CONNECTION_STRING=your_connection_string_here ``` ### 依存関係 必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="index.ts" import { openai } from "@ai-sdk/openai"; import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { Step, Workflow } from "@mastra/core/workflows"; import { PgVector } from "@mastra/pg"; import { createVectorQueryTool, MDocument } from "@mastra/rag"; import { embedMany } from "ai"; import { z } from "zod"; ``` ## ワークフローの定義 まず、トリガースキーマとともにワークフローを定義します。 ```typescript copy showLineNumbers{10} filename="index.ts" export const ragWorkflow = new Workflow({ name: "rag-workflow", triggerSchema: z.object({ query: z.string(), }), }); ``` ## ベクタークエリツールの作成 ベクターデータベースをクエリするためのツールを作成します: ```typescript copy showLineNumbers{17} filename="index.ts" const vectorQueryTool = createVectorQueryTool({ vectorStoreName: "pgVector", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), }); ``` ## エージェント設定 Mastraエージェントをセットアップします: ```typescript copy showLineNumbers{23} filename="index.ts" export const ragAgent = new Agent({ name: "RAG Agent", instructions: `You are a helpful assistant that answers questions based on the provided context.`, model: openai("gpt-4o-mini"), tools: { vectorQueryTool, }, }); ``` ## ワークフローステップ このワークフローは、チェーン・オブ・ソート推論のために複数のステップに分かれています。 ### 1. コンテキスト分析ステップ ```typescript copy showLineNumbers{32} filename="index.ts" const analyzeContext = new Step({ id: "analyzeContext", outputSchema: z.object({ initialAnalysis: z.string(), }), execute: async ({ context, mastra }) => { console.log("---------------------------"); const ragAgent = mastra?.getAgent("ragAgent"); const query = context?.getStepResult<{ query: string }>("trigger")?.query; const analysisPrompt = `${query} 1. First, carefully analyze the retrieved context chunks and identify key information.`; const analysis = await ragAgent?.generate(analysisPrompt); console.log(analysis?.text); return { initialAnalysis: analysis?.text ?? "", }; }, }); ``` ### 2. 思考分解ステップ ```typescript copy showLineNumbers{54} filename="index.ts" const breakdownThoughts = new Step({ id: "breakdownThoughts", outputSchema: z.object({ breakdown: z.string(), }), execute: async ({ context, mastra }) => { console.log("---------------------------"); const ragAgent = mastra?.getAgent("ragAgent"); const analysis = context?.getStepResult<{ initialAnalysis: string; }>("analyzeContext")?.initialAnalysis; const connectionPrompt = ` Based on the initial analysis: ${analysis} 2. Break down your thinking process about how the retrieved information relates to the query. `; const connectionAnalysis = await ragAgent?.generate(connectionPrompt); console.log(connectionAnalysis?.text); return { breakdown: connectionAnalysis?.text ?? "", }; }, }); ``` ### 3. 接続ステップ ```typescript copy showLineNumbers{80} filename="index.ts" const connectPieces = new Step({ id: "connectPieces", outputSchema: z.object({ connections: z.string(), }), execute: async ({ context, mastra }) => { console.log("---------------------------"); const ragAgent = mastra?.getAgent("ragAgent"); const process = context?.getStepResult<{ breakdown: string; }>("breakdownThoughts")?.breakdown; const connectionPrompt = ` Based on the breakdown: ${process} 3. Explain how you're connecting different pieces from the retrieved chunks. `; const connections = await ragAgent?.generate(connectionPrompt); console.log(connections?.text); return { connections: connections?.text ?? "", }; }, }); ``` ### 4. 結論ステップ ```typescript copy showLineNumbers{105} filename="index.ts" const drawConclusions = new Step({ id: "drawConclusions", outputSchema: z.object({ conclusions: z.string(), }), execute: async ({ context, mastra }) => { console.log("---------------------------"); const ragAgent = mastra?.getAgent("ragAgent"); const evidence = context?.getStepResult<{ connections: string; }>("connectPieces")?.connections; const conclusionPrompt = ` Based on the connections: ${evidence} 4. Draw conclusions based only on the evidence in the retrieved context. `; const conclusions = await ragAgent?.generate(conclusionPrompt); console.log(conclusions?.text); return { conclusions: conclusions?.text ?? "", }; }, }); ``` ### 5. 最終回答ステップ ```typescript copy showLineNumbers{130} filename="index.ts" const finalAnswer = new Step({ id: "finalAnswer", outputSchema: z.object({ finalAnswer: z.string(), }), execute: async ({ context, mastra }) => { console.log("---------------------------"); const ragAgent = mastra?.getAgent("ragAgent"); const conclusions = context?.getStepResult<{ conclusions: string; }>("drawConclusions")?.conclusions; const answerPrompt = ` Based on the conclusions: ${conclusions} Format your response as: THOUGHT PROCESS: - Step 1: [Initial analysis of retrieved chunks] - Step 2: [Connections between chunks] - Step 3: [Reasoning based on chunks] FINAL ANSWER: [Your concise answer based on the retrieved context]`; const finalAnswer = await ragAgent?.generate(answerPrompt); console.log(finalAnswer?.text); return { finalAnswer: finalAnswer?.text ?? "", }; }, }); ``` ## ワークフロー設定 ワークフロー内のすべてのステップを接続します: ```typescript copy showLineNumbers{160} filename="index.ts" ragWorkflow .step(analyzeContext) .then(breakdownThoughts) .then(connectPieces) .then(drawConclusions) .then(finalAnswer); ragWorkflow.commit(); ``` ## PgVector と Mastra のインスタンス化 すべてのコンポーネントを使って PgVector と Mastra をインスタンス化します。 ```typescript copy showLineNumbers{169} filename="index.ts" const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); export const mastra = new Mastra({ agents: { ragAgent }, vectors: { pgVector }, workflows: { ragWorkflow }, }); ``` ## ドキュメント処理 ドキュメントを処理し、チャンクに分割します: ```typescript copy showLineNumbers{177} filename="index.ts" const doc = MDocument.fromText( `The Impact of Climate Change on Global Agriculture...`, ); const chunks = await doc.chunk({ strategy: "recursive", size: 512, overlap: 50, separator: "\n", }); ``` ## 埋め込みの作成と保存 埋め込みを生成して保存します: ```typescript copy showLineNumbers{186} filename="index.ts" const { embeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: chunks.map((chunk) => chunk.text), }); const vectorStore = mastra.getVector("pgVector"); await vectorStore.createIndex({ indexName: "embeddings", dimension: 1536, }); await vectorStore.upsert({ indexName: "embeddings", vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); ``` ## ワークフローの実行 クエリを使ってワークフローを実行する方法は次のとおりです。 ```typescript copy showLineNumbers{202} filename="index.ts" const query = "What are the main adaptation strategies for farmers?"; console.log("\nQuery:", query); const prompt = ` Please answer the following question: ${query} Please base your answer only on the context provided in the tool. If the context doesn't contain enough information to fully answer the question, please state that explicitly. `; const { runId, start } = ragWorkflow.createRun(); console.log("Run:", runId); const workflowResult = await start({ triggerData: { query: prompt, }, }); console.log("\nThought Process:"); console.log(workflowResult.results); ```




--- title: "データベース固有の設定 | RAG | Mastra Examples" description: データベース固有の設定を使用してベクトル検索のパフォーマンスを最適化し、異なるベクトルストアの独自機能を活用する方法を学びます。 --- import { Tabs } from "nextra/components"; # データベース固有の設定 [JA] Source: https://mastra.ai/ja/examples/rag/usage/database-specific-config この例では、ベクトルクエリツールでデータベース固有の設定を使用して、パフォーマンスを最適化し、異なるベクトルストアの独自機能を活用する方法を示します。 ## マルチ環境セットアップ 異なる環境に対して異なる設定を使用します: ```typescript import { openai } from "@ai-sdk/openai"; import { createVectorQueryTool } from "@mastra/rag"; import { RuntimeContext } from "@mastra/core/runtime-context"; // Base configuration const createSearchTool = (environment: 'dev' | 'staging' | 'prod') => { return createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "documents", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pinecone: { namespace: environment } } }); }; // Create environment-specific tools const devSearchTool = createSearchTool('dev'); const prodSearchTool = createSearchTool('prod'); // Or use runtime override const dynamicSearchTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "documents", model: openai.embedding("text-embedding-3-small") }); // Switch environment at runtime const switchEnvironment = async (environment: string, query: string) => { const runtimeContext = new RuntimeContext(); runtimeContext.set('databaseConfig', { pinecone: { namespace: environment } }); return await dynamicSearchTool.execute({ context: { queryText: query }, mastra, runtimeContext }); }; ``` ```javascript import { openai } from "@ai-sdk/openai"; import { createVectorQueryTool } from "@mastra/rag"; import { RuntimeContext } from "@mastra/core/runtime-context"; // Base configuration const createSearchTool = (environment) => { return createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "documents", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pinecone: { namespace: environment } } }); }; // Create environment-specific tools const devSearchTool = createSearchTool('dev'); const prodSearchTool = createSearchTool('prod'); // Or use runtime override const dynamicSearchTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "documents", model: openai.embedding("text-embedding-3-small") }); // Switch environment at runtime const switchEnvironment = async (environment, query) => { const runtimeContext = new RuntimeContext(); runtimeContext.set('databaseConfig', { pinecone: { namespace: environment } }); return await dynamicSearchTool.execute({ context: { queryText: query }, mastra, runtimeContext }); }; ``` ## pgVectorによるパフォーマンス最適化 異なる用途に応じて検索パフォーマンスを最適化します: ```typescript // 高精度設定 - 遅いがより正確 const highAccuracyTool = createVectorQueryTool({ vectorStoreName: "postgres", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pgvector: { ef: 400, // HNSWの高精度 probes: 20, // IVFFlatの高再現率 minScore: 0.85 // 高品質閾値 } } }); // 精度が最重要な重要な検索に使用 const criticalSearch = async (query: string) => { return await highAccuracyTool.execute({ context: { queryText: query, topK: 5 // より少ない、高品質な結果 }, mastra }); }; ``` ```typescript // 高速設定 - 速いが精度は低い const highSpeedTool = createVectorQueryTool({ vectorStoreName: "postgres", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pgvector: { ef: 50, // 速度のため精度を下げる probes: 3, // 速度のため再現率を下げる minScore: 0.6 // 品質閾値を下げる } } }); // リアルタイムアプリケーションに使用 const realtimeSearch = async (query: string) => { return await highSpeedTool.execute({ context: { queryText: query, topK: 10 // 低精度を補うためより多くの結果 }, mastra }); }; ``` ```typescript // バランス設定 - 良い妥協点 const balancedTool = createVectorQueryTool({ vectorStoreName: "postgres", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pgvector: { ef: 150, // 中程度の精度 probes: 8, // 中程度の再現率 minScore: 0.7 // 中程度の品質閾値 } } }); // 負荷に基づいてパラメータを調整 const adaptiveSearch = async (query: string, isHighLoad: boolean) => { const runtimeContext = new RuntimeContext(); if (isHighLoad) { // 高負荷時は速度のため品質を下げる runtimeContext.set('databaseConfig', { pgvector: { ef: 75, probes: 5, minScore: 0.65 } }); } return await balancedTool.execute({ context: { queryText: query }, mastra, runtimeContext }); }; ``` ## Pineconeを使用したマルチテナントアプリケーション Pineconeの名前空間を使用してテナント分離を実装します: ```typescript interface Tenant { id: string; name: string; namespace: string; } class MultiTenantSearchService { private searchTool: RagTool constructor() { this.searchTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "shared-documents", model: openai.embedding("text-embedding-3-small") }); } async searchForTenant(tenant: Tenant, query: string) { const runtimeContext = new RuntimeContext(); // Isolate search to tenant's namespace runtimeContext.set('databaseConfig', { pinecone: { namespace: tenant.namespace } }); const results = await this.searchTool.execute({ context: { queryText: query, topK: 10 }, mastra, runtimeContext }); // Add tenant context to results return { tenant: tenant.name, query, results: results.relevantContext, sources: results.sources }; } async bulkSearchForTenants(tenants: Tenant[], query: string) { const promises = tenants.map(tenant => this.searchForTenant(tenant, query) ); return await Promise.all(promises); } } // Usage const searchService = new MultiTenantSearchService(); const tenants = [ { id: '1', name: 'Company A', namespace: 'company-a' }, { id: '2', name: 'Company B', namespace: 'company-b' } ]; const results = await searchService.searchForTenant( tenants[0], "product documentation" ); ``` ## Pineconeでのハイブリッド検索 セマンティック検索とキーワード検索を組み合わせる: ```typescript const hybridSearchTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "documents", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pinecone: { namespace: "production", sparseVector: { // Example sparse vector for keyword "API" indices: [1, 5, 10, 15], values: [0.8, 0.6, 0.4, 0.2] } } } }); // Helper function to generate sparse vectors for keywords const generateSparseVector = (keywords: string[]) => { // This is a simplified example - in practice, you'd use // a proper sparse encoding method like BM25 const indices: number[] = []; const values: number[] = []; keywords.forEach((keyword, i) => { const hash = keyword.split('').reduce((a, b) => { a = ((a << 5) - a) + b.charCodeAt(0); return a & a; }, 0); indices.push(Math.abs(hash) % 1000); values.push(1.0 / (i + 1)); // Decrease weight for later keywords }); return { indices, values }; }; const hybridSearch = async (query: string, keywords: string[]) => { const runtimeContext = new RuntimeContext(); if (keywords.length > 0) { const sparseVector = generateSparseVector(keywords); runtimeContext.set('databaseConfig', { pinecone: { namespace: "production", sparseVector } }); } return await hybridSearchTool.execute({ context: { queryText: query }, mastra, runtimeContext }); }; // Usage const results = await hybridSearch( "How to use the REST API", ["API", "REST", "documentation"] ); ``` ## Quality-Gated Search 段階的な検索品質を実装する: ```typescript const createQualityGatedSearch = () => { const baseConfig = { vectorStoreName: "postgres", indexName: "embeddings", model: openai.embedding("text-embedding-3-small") }; return { // High quality search first highQuality: createVectorQueryTool({ ...baseConfig, databaseConfig: { pgvector: { minScore: 0.85, ef: 200, probes: 15 } } }), // Medium quality fallback mediumQuality: createVectorQueryTool({ ...baseConfig, databaseConfig: { pgvector: { minScore: 0.7, ef: 150, probes: 10 } } }), // Low quality last resort lowQuality: createVectorQueryTool({ ...baseConfig, databaseConfig: { pgvector: { minScore: 0.5, ef: 100, probes: 5 } } }) }; }; const progressiveSearch = async (query: string, minResults: number = 3) => { const tools = createQualityGatedSearch(); // Try high quality first let results = await tools.highQuality.execute({ context: { queryText: query }, mastra }); if (results.sources.length >= minResults) { return { quality: 'high', ...results }; } // Fallback to medium quality results = await tools.mediumQuality.execute({ context: { queryText: query }, mastra }); if (results.sources.length >= minResults) { return { quality: 'medium', ...results }; } // Last resort: low quality results = await tools.lowQuality.execute({ context: { queryText: query }, mastra }); return { quality: 'low', ...results }; }; // Usage const results = await progressiveSearch("complex technical query", 5); console.log(`Found ${results.sources.length} results with ${results.quality} quality`); ``` ## 重要なポイント 1. **環境の分離**: 名前空間を使用して環境やテナントごとにデータを分離する 2. **パフォーマンスチューニング**: 精度と速度の要件に基づいてef/probesパラメータを調整する 3. **品質管理**: minScoreを使用して低品質のマッチを除外する 4. **実行時の柔軟性**: コンテキストに基づいて設定を動的にオーバーライドする 5. **段階的品質**: 異なる品質レベルに対するフォールバック戦略を実装する このアプローチにより、柔軟性とパフォーマンスを維持しながら、特定のユースケースに対してベクトル検索を最適化することができます。 --- title: "例: エージェント主導のメタデータフィルタリング | 検索 | RAG | Mastra ドキュメント" description: RAG システムで Mastra エージェントを使用して、ドキュメント検索のためのメタデータフィルターを構築・適用する例。 --- import { GithubLink } from "@/components/github-link"; # エージェント駆動型メタデータフィルタリング [JA] Source: https://mastra.ai/ja/examples/rag/usage/filter-rag この例では、Mastra、OpenAIの埋め込み、そしてベクトルストレージとしてPGVectorを使用して、検索拡張生成(RAG)システムを実装する方法を示します。 このシステムは、エージェントがユーザーのクエリからメタデータフィルターを構築し、ベクトルストア内で関連するチャンクを検索することで、返される結果の量を減らします。 ## 概要 このシステムは、Mastra と OpenAI を使用してメタデータフィルタリングを実装しています。主な機能は以下の通りです。 1. gpt-4o-mini を用いた Mastra エージェントをセットアップし、クエリを理解してフィルタ要件を特定します 2. メタデータフィルタリングとセマンティック検索を処理するベクトルクエリツールを作成します 3. ドキュメントをメタデータと埋め込みを持つチャンクに分割して処理します 4. 効率的な検索のために、ベクトルとメタデータの両方を PGVector に保存します 5. メタデータフィルタとセマンティック検索を組み合わせてクエリを処理します ユーザーが質問をするとき: - エージェントがクエリを分析し、意図を理解します - 適切なメタデータフィルタ(例:トピック、日付、カテゴリ別)を構築します - ベクトルクエリツールを使って最も関連性の高い情報を見つけます - フィルタリングされた結果に基づいてコンテキストに合った回答を生成します ## セットアップ ### 環境設定 環境変数を必ず設定してください: ```bash filename=".env" OPENAI_API_KEY=your_openai_api_key_here POSTGRES_CONNECTION_STRING=your_connection_string_here ``` ### 依存関係 次に、必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="index.ts" import { openai } from "@ai-sdk/openai"; import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { PgVector, PGVECTOR_PROMPT } from "@mastra/pg"; import { createVectorQueryTool, MDocument } from "@mastra/rag"; import { embedMany } from "ai"; ``` ## ベクタークエリツールの作成 @mastra/rag からインポートした createVectorQueryTool を使用すると、メタデータフィルタリングを可能にするツールを作成できます。各ベクターストアには、サポートされているフィルター演算子と構文を定義する独自のプロンプトがあります。 ```typescript copy showLineNumbers{9} filename="index.ts" const vectorQueryTool = createVectorQueryTool({ id: "vectorQueryTool", vectorStoreName: "pgVector", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), enableFilter: true, filterPrompt: PGVECTOR_PROMPT, // Use the prompt for your vector store }); ``` 各プロンプトには以下が含まれます: - サポートされている演算子(比較、配列、論理、要素) - 各演算子の使用例 - ストア固有の制限事項やルール - 複雑なクエリの例 ## ドキュメント処理 ドキュメントを作成し、メタデータ付きでチャンクに分割します: ```typescript copy showLineNumbers{17} filename="index.ts" const doc = MDocument.fromText( `The Impact of Climate Change on Global Agriculture...`, ); const chunks = await doc.chunk({ strategy: "recursive", size: 512, overlap: 50, separator: "\n", extract: { keywords: true, // Extracts keywords from each chunk }, }); ``` ### チャンクをメタデータに変換する チャンクをフィルタリング可能なメタデータに変換します: ```typescript copy showLineNumbers{31} filename="index.ts" const chunkMetadata = chunks?.map((chunk: any, index: number) => ({ text: chunk.text, ...chunk.metadata, nested: { keywords: chunk.metadata.excerptKeywords .replace("KEYWORDS:", "") .split(",") .map((k) => k.trim()), id: index, }, })); ``` ## エージェントの設定 エージェントは、ユーザーのクエリを理解し、適切なメタデータフィルターに変換するように設定されています。 エージェントには、ベクトルクエリツールと、以下を含むシステムプロンプトの両方が必要です。 - 利用可能なフィルターフィールドのメタデータ構造 - フィルター操作と構文のためのベクトルストアプロンプト ```typescript copy showLineNumbers{43} filename="index.ts" export const ragAgent = new Agent({ name: "RAG Agent", model: openai("gpt-4o-mini"), instructions: ` You are a helpful assistant that answers questions based on the provided context. Keep your answers concise and relevant. Filter the context by searching the metadata. The metadata is structured as follows: { text: string, excerptKeywords: string, nested: { keywords: string[], id: number, }, } ${PGVECTOR_PROMPT} Important: When asked to answer a question, please base your answer only on the context provided in the tool. If the context doesn't contain enough information to fully answer the question, please state that explicitly. `, tools: { vectorQueryTool }, }); ``` エージェントの指示は、以下を目的としています。 - ユーザーのクエリを処理し、フィルター要件を特定する - メタデータ構造を利用して関連情報を見つける - vectorQueryToolと提供されたベクトルストアプロンプトを通じて適切なフィルターを適用する - フィルターされたコンテキストに基づいて応答を生成する > 注: ベクトルストアごとに利用可能なプロンプトが異なります。詳細は[Vector Store Prompts](/docs/rag/retrieval#vector-store-prompts)をご覧ください。 ## PgVector と Mastra のインスタンス化 以下のコンポーネントを使って PgVector と Mastra をインスタンス化します。 ```typescript copy showLineNumbers{69} filename="index.ts" const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); export const mastra = new Mastra({ agents: { ragAgent }, vectors: { pgVector }, }); const agent = mastra.getAgent("ragAgent"); ``` ## 埋め込みの作成と保存 埋め込みを生成し、メタデータと一緒に保存します: ```typescript copy showLineNumbers{78} filename="index.ts" const { embeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: chunks.map((chunk) => chunk.text), }); const vectorStore = mastra.getVector("pgVector"); await vectorStore.createIndex({ indexName: "embeddings", dimension: 1536, }); // Store both embeddings and metadata together await vectorStore.upsert({ indexName: "embeddings", vectors: embeddings, metadata: chunkMetadata, }); ``` `upsert` 操作は、ベクトル埋め込みとそれに関連付けられたメタデータの両方を保存し、セマンティック検索とメタデータフィルタリングの機能を組み合わせて利用できるようにします。 ## メタデータベースのクエリ メタデータフィルターを使ってさまざまなクエリを試してみましょう: ```typescript copy showLineNumbers{96} filename="index.ts" const queryOne = "What are the adaptation strategies mentioned?"; const answerOne = await agent.generate(queryOne); console.log("\nQuery:", queryOne); console.log("Response:", answerOne.text); const queryTwo = 'Show me recent sections. Check the "nested.id" field and return values that are greater than 2.'; const answerTwo = await agent.generate(queryTwo); console.log("\nQuery:", queryTwo); console.log("Response:", answerTwo.text); const queryThree = 'Search the "text" field using regex operator to find sections containing "temperature".'; const answerThree = await agent.generate(queryThree); console.log("\nQuery:", queryThree); console.log("Response:", answerThree.text); ```




--- title: "例: 完全なグラフRAGシステム | RAG | Mastra ドキュメント" description: OpenAIの埋め込みとPGVectorによるベクトルストレージを用いた、MastraでのグラフRAGシステム実装例。 --- import { GithubLink } from "@/components/github-link"; # Graph RAG [JA] Source: https://mastra.ai/ja/examples/rag/usage/graph-rag この例では、Mastra、OpenAIの埋め込み、そしてベクトルストレージとしてPGVectorを使用して、検索拡張生成(RAG)システムを実装する方法を示します。 ## 概要 このシステムは、Mastra と OpenAI を用いて Graph RAG を実装しています。主な機能は以下の通りです。 1. 応答生成のために gpt-4o-mini を使用した Mastra エージェントをセットアップ 2. ベクトルストアの操作やナレッジグラフの作成・トラバーサルを管理する GraphRAG ツールを作成 3. テキストドキュメントを小さなセグメントに分割 4. これらのチャンクに対して埋め込みを作成 5. PostgreSQL ベクトルデータベースに保存 6. GraphRAG ツールを使ってクエリに基づき関連するチャンクのナレッジグラフを作成 - ツールはベクトルストアから結果を返し、ナレッジグラフを作成 - クエリを使ってナレッジグラフをトラバース 7. Mastra エージェントを用いてコンテキストに応じた応答を生成 ## セットアップ ### 環境設定 環境変数を必ず設定してください: ```bash filename=".env" OPENAI_API_KEY=your_openai_api_key_here POSTGRES_CONNECTION_STRING=your_connection_string_here ``` ### 依存関係 次に、必要な依存関係をインポートします: ```typescript copy showLineNumbers filename="index.ts" import { openai } from "@ai-sdk/openai"; import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { PgVector } from "@mastra/pg"; import { MDocument, createGraphRAGTool } from "@mastra/rag"; import { embedMany } from "ai"; ``` ## GraphRAGツールの作成 @mastra/ragからインポートしたcreateGraphRAGToolを使用すると、ベクターデータベースにクエリを実行し、その結果をナレッジグラフに変換するツールを作成できます。 ```typescript copy showLineNumbers{8} filename="index.ts" const graphRagTool = createGraphRAGTool({ vectorStoreName: "pgVector", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), graphOptions: { dimension: 1536, threshold: 0.7, }, }); ``` ## エージェント設定 応答を処理するMastraエージェントを設定します: ```typescript copy showLineNumbers{19} filename="index.ts" const ragAgent = new Agent({ name: "GraphRAG Agent", instructions: `You are a helpful assistant that answers questions based on the provided context. Format your answers as follows: 1. DIRECT FACTS: List only the directly stated facts from the text relevant to the question (2-3 bullet points) 2. CONNECTIONS MADE: List the relationships you found between different parts of the text (2-3 bullet points) 3. CONCLUSION: One sentence summary that ties everything together Keep each section brief and focus on the most important points. Important: When asked to answer a question, please base your answer only on the context provided in the tool. If the context doesn't contain enough information to fully answer the question, please state that explicitly.`, model: openai("gpt-4o-mini"), tools: { graphRagTool, }, }); ``` ## PgVector と Mastra のインスタンス化 以下のコンポーネントを使って PgVector と Mastra をインスタンス化します。 ```typescript copy showLineNumbers{36} filename="index.ts" const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); export const mastra = new Mastra({ agents: { ragAgent }, vectors: { pgVector }, }); const agent = mastra.getAgent("ragAgent"); ``` ## ドキュメント処理 ドキュメントを作成し、チャンクに分割します: ```typescript copy showLineNumbers{45} filename="index.ts" const doc = MDocument.fromText(` # Riverdale Heights: Community Development Study // ... text content ... `); const chunks = await doc.chunk({ strategy: "recursive", size: 512, overlap: 50, separator: "\n", }); ``` ## 埋め込みの作成と保存 チャンクの埋め込みを生成し、ベクターデータベースに保存します。 ```typescript copy showLineNumbers{56} filename="index.ts" const { embeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: chunks.map((chunk) => chunk.text), }); const vectorStore = mastra.getVector("pgVector"); await vectorStore.createIndex({ indexName: "embeddings", dimension: 1536, }); await vectorStore.upsert({ indexName: "embeddings", vectors: embeddings, metadata: chunks?.map((chunk: any) => ({ text: chunk.text })), }); ``` ## グラフベースのクエリ さまざまなクエリを試して、データ内の関係性を探索してみましょう。 ```typescript copy showLineNumbers{82} filename="index.ts" const queryOne = "What are the direct and indirect effects of early railway decisions on Riverdale Heights' current state?"; const answerOne = await ragAgent.generate(queryOne); console.log("\nQuery:", queryOne); console.log("Response:", answerOne.text); const queryTwo = "How have changes in transportation infrastructure affected different generations of local businesses and community spaces?"; const answerTwo = await ragAgent.generate(queryTwo); console.log("\nQuery:", queryTwo); console.log("Response:", answerTwo.text); const queryThree = "Compare how the Rossi family business and Thompson Steel Works responded to major infrastructure changes, and how their responses affected the community."; const answerThree = await ragAgent.generate(queryThree); console.log("\nQuery:", queryThree); console.log("Response:", answerThree.text); const queryFour = "Trace how the transformation of the Thompson Steel Works site has influenced surrounding businesses and cultural spaces from 1932 to present."; const answerFour = await ragAgent.generate(queryFour); console.log("\nQuery:", queryFour); console.log("Response:", answerFour.text); ```




--- title: 音声から音声へ description: Mastra を使って音声から音声へのアプリケーションを作成する例。 --- import { GithubLink } from "@/components/github-link"; # Mastraによる通話分析 [JA] Source: https://mastra.ai/ja/examples/voice/speech-to-speech このガイドでは、Mastraを使用して分析機能付きの音声会話システムを構築する方法を説明します。例として、リアルタイムの音声対話、録音管理、そして通話分析のためのRoark Analyticsとの連携が含まれています。 ## 概要 このシステムは、Mastraエージェントとの音声会話を作成し、やり取り全体を録音して、その録音をCloudinaryにアップロードして保存します。その後、会話データをRoark Analyticsに送信し、詳細な通話分析を行います。 ## セットアップ ### 前提条件 1. 音声認識および音声合成機能のためのOpenAI APIキー 2. 音声ファイル保存用のCloudinaryアカウント 3. 通話分析のためのRoark Analytics APIキー ### 環境構成 提供されたサンプルに基づいて `.env` ファイルを作成します: ```bash filename="speech-to-speech/call-analysis/sample.env" copy OPENAI_API_KEY= CLOUDINARY_CLOUD_NAME= CLOUDINARY_API_KEY= CLOUDINARY_API_SECRET= ROARK_API_KEY= ``` ### インストール 必要な依存関係をインストールします: ```bash copy npm install ``` ## 実装 ### Mastraエージェントの作成 まず、音声機能を持つエージェントを定義します。 ```ts filename="speech-to-speech/call-analysis/src/mastra/agents/index.ts" copy import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { createTool } from "@mastra/core/tools"; import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import { z } from "zod"; // Have the agent do something export const speechToSpeechServer = new Agent({ name: "mastra", instructions: "You are a helpful assistant.", voice: new OpenAIRealtimeVoice(), model: openai("gpt-4o"), tools: { salutationTool: createTool({ id: "salutationTool", description: "Read the result of the tool", inputSchema: z.object({ name: z.string() }), outputSchema: z.object({ message: z.string() }), execute: async ({ context }) => { return { message: `Hello ${context.name}!` }; }, }), }, }); ``` ### Mastraの初期化 エージェントをMastraに登録します。 ```ts filename="speech-to-speech/call-analysis/src/mastra/index.ts" copy import { Mastra } from "@mastra/core"; import { speechToSpeechServer } from "./agents"; export const mastra = new Mastra({ agents: { speechToSpeechServer, }, }); ``` ### 音声ファイル保存のためのCloudinary連携 録音した音声ファイルを保存するためにCloudinaryを設定します。 ```ts filename="speech-to-speech/call-analysis/src/upload.ts" copy import { v2 as cloudinary } from "cloudinary"; cloudinary.config({ cloud_name: process.env.CLOUDINARY_CLOUD_NAME, api_key: process.env.CLOUDINARY_API_KEY, api_secret: process.env.CLOUDINARY_API_SECRET, }); export async function uploadToCloudinary(path: string) { const response = await cloudinary.uploader.upload(path, { resource_type: "raw", }); console.log(response); return response.url; } ``` ### メインアプリケーションロジック メインアプリケーションは会話の流れ、録音、分析連携を統括します。 ```ts filename="speech-to-speech/call-analysis/src/base.ts" copy import { Roark } from "@roarkanalytics/sdk"; import chalk from "chalk"; import { mastra } from "./mastra"; import { createConversation, formatToolInvocations } from "./utils"; import { uploadToCloudinary } from "./upload"; import fs from "fs"; const client = new Roark({ bearerToken: process.env.ROARK_API_KEY, }); async function speechToSpeechServerExample() { const { start, stop } = createConversation({ mastra, recordingPath: "./speech-to-speech-server.mp3", providerOptions: {}, initialMessage: "Howdy partner", onConversationEnd: async (props) => { // File upload fs.writeFileSync(props.recordingPath, props.audioBuffer); const url = await uploadToCloudinary(props.recordingPath); // Send to Roark console.log("Send to Roark", url); const response = await client.callAnalysis.create({ recordingUrl: url, startedAt: props.startedAt, callDirection: "INBOUND", interfaceType: "PHONE", participants: [ { role: "AGENT", spokeFirst: props.agent.spokeFirst, name: props.agent.name, phoneNumber: props.agent.phoneNumber, }, { role: "CUSTOMER", name: "Yujohn Nattrass", phoneNumber: "987654321", }, ], properties: props.metadata, toolInvocations: formatToolInvocations(props.toolInvocations), }); console.log("Call Recording Posted:", response.data); }, onWriting: (ev) => { if (ev.role === "assistant") { process.stdout.write(chalk.blue(ev.text)); } }, }); await start(); process.on("SIGINT", async (e) => { await stop(); }); } speechToSpeechServerExample().catch(console.error); ``` ## 会話ユーティリティ `utils.ts` ファイルには、会話を管理するための補助関数が含まれています。主な内容は以下の通りです。 1. 会話セッションの作成と管理 2. 音声録音の処理 3. ツール呼び出しの処理 4. 会話ライフサイクルイベントの管理 ## サンプルの実行 次のコマンドで会話を開始します: ```bash copy npm run dev ``` アプリケーションは以下の処理を行います: 1. Mastraエージェントとのリアルタイム音声会話を開始します 2. 会話全体を録音します 3. 会話終了時に録音をCloudinaryにアップロードします 4. 会話データをRoark Analyticsに送信して分析します 5. 分析結果を表示します ## 主な機能 - **リアルタイム音声対音声変換**: OpenAIの音声モデルを使用し、自然な会話を実現 - **会話録音**: 会話全体を記録し、後で分析可能 - **ツール呼び出しの追跡**: 会話中にAIツールがいつ、どのように使われたかを記録 - **分析ツール連携**: 会話データをRoark Analyticsに送信し、詳細な分析を実施 - **クラウドストレージ**: 録音をCloudinaryにアップロードし、安全に保存・アクセス ## カスタマイズ この例は、以下の方法でカスタマイズできます: - エージェントの指示や機能を変更する - エージェントが使用する追加ツールを追加する - 会話の流れや最初のメッセージを変更する - カスタムメタデータで分析連携を拡張する 完全なサンプルコードを見るには、[Github リポジトリ](https://github.com/mastra-ai/voice-examples/tree/main/speech-to-speech/call-analysis)をご覧ください。

--- title: "例: 音声からテキストへ | Voice | Mastra ドキュメント" description: Mastra を使って音声からテキストへのアプリケーションを作成する例。 --- import { GithubLink } from "@/components/github-link"; # Smart Voice Memo App [JA] Source: https://mastra.ai/ja/examples/voice/speech-to-text 以下のコードスニペットは、Next.js に Mastra を直接統合してスマートボイスメモアプリケーションで音声認識(STT)機能を実装する例を示しています。Mastra を Next.js と統合する方法の詳細については、[Integrate with Next.js](/docs/frameworks/next-js) のドキュメントをご参照ください。 ## STT機能を持つエージェントの作成 次の例は、OpenAIのSTT機能を備えた音声対応エージェントを初期化する方法を示しています。 ```typescript filename="src/mastra/agents/index.ts" import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { OpenAIVoice } from "@mastra/voice-openai"; const instructions = ` You are an AI note assistant tasked with providing concise, structured summaries of their content... // omitted for brevity `; export const noteTakerAgent = new Agent({ name: "Note Taker Agent", instructions: instructions, model: openai("gpt-4o"), voice: new OpenAIVoice(), // Add OpenAI voice provider with default configuration }); ``` ## Mastraでエージェントを登録する このスニペットは、STT対応エージェントをMastraインスタンスに登録する方法を示しています: ```typescript filename="src/mastra/index.ts" import { PinoLogger } from "@mastra/loggers"; import { Mastra } from "@mastra/core/mastra"; import { noteTakerAgent } from "./agents"; export const mastra = new Mastra({ agents: { noteTakerAgent }, // Register the note taker agent logger: new PinoLogger({ name: "Mastra", level: "info", }), }); ``` ## 音声の文字起こし処理 以下のコードは、ウェブリクエストから音声を受け取り、エージェントのSTT機能を使って文字起こしを行う方法を示しています。 ```typescript filename="app/api/audio/route.ts" import { mastra } from "@/src/mastra"; // Import the Mastra instance import { Readable } from "node:stream"; export async function POST(req: Request) { // Get the audio file from the request const formData = await req.formData(); const audioFile = formData.get("audio") as File; const arrayBuffer = await audioFile.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); const readable = Readable.from(buffer); // Get the note taker agent from the Mastra instance const noteTakerAgent = mastra.getAgent("noteTakerAgent"); // Transcribe the audio file const text = await noteTakerAgent.voice?.listen(readable); return new Response(JSON.stringify({ text }), { headers: { "Content-Type": "application/json" }, }); } ``` Smart Voice Memo App の完全な実装は、私たちの GitHub リポジトリでご覧いただけます。




--- title: "例: テキスト読み上げ | Voice | Mastra ドキュメント" description: Mastra を使ってテキスト読み上げアプリケーションを作成する例です。 --- import { GithubLink } from "@/components/github-link"; # インタラクティブストーリージェネレーター [JA] Source: https://mastra.ai/ja/examples/voice/text-to-speech 以下のコードスニペットは、Next.js を使用したインタラクティブストーリージェネレーターアプリケーションにおける Text-to-Speech(TTS)機能の実装例を示しています。Mastra を別のバックエンド統合として利用しています。この例では、Mastra client-js SDK を使ってご自身の Mastra バックエンドに接続する方法を紹介します。Next.js との Mastra の統合について詳しくは、[Next.js との統合](/docs/frameworks/next-js) ドキュメントをご参照ください。 ## TTS機能を備えたエージェントの作成 次の例は、バックエンドでTTS機能を持つストーリー生成エージェントを設定する方法を示しています。 ```typescript filename="src/mastra/agents/index.ts" import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { OpenAIVoice } from "@mastra/voice-openai"; import { Memory } from "@mastra/memory"; const instructions = ` You are an Interactive Storyteller Agent. Your job is to create engaging short stories with user choices that influence the narrative. // omitted for brevity `; export const storyTellerAgent = new Agent({ name: "Story Teller Agent", instructions: instructions, model: openai("gpt-4o"), voice: new OpenAIVoice(), }); ``` ## Mastraとエージェントを登録する このスニペットは、エージェントをMastraインスタンスに登録する方法を示しています: ```typescript filename="src/mastra/index.ts" import { PinoLogger } from "@mastra/loggers"; import { Mastra } from "@mastra/core/mastra"; import { storyTellerAgent } from "./agents"; export const mastra = new Mastra({ agents: { storyTellerAgent }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); ``` ## フロントエンドからMastraへの接続 ここでは、Mastra Client SDKを使用してMastraサーバーとやり取りします。Mastra Client SDKの詳細については、[ドキュメント](/docs/deployment/client)をご覧ください。 ```typescript filename="src/app/page.tsx" import { MastraClient } from "@mastra/client-js"; export const mastraClient = new MastraClient({ baseUrl: "http://localhost:4111", // Replace with your Mastra backend URL }); ``` ## ストーリーコンテンツの生成と音声への変換 この例では、Mastraエージェントへの参照を取得し、ユーザー入力に基づいてストーリーコンテンツを生成し、そのコンテンツを音声に変換する方法を示します。 ```typescript filename="/app/components/StoryManager.tsx" const handleInitialSubmit = async (formData: FormData) => { setIsLoading(true); try { const agent = mastraClient.getAgent("storyTellerAgent"); const message = `Current phase: BEGINNING. Story genre: ${formData.genre}, Protagonist name: ${formData.protagonistDetails.name}, Protagonist age: ${formData.protagonistDetails.age}, Protagonist gender: ${formData.protagonistDetails.gender}, Protagonist occupation: ${formData.protagonistDetails.occupation}, Story Setting: ${formData.setting}`; const storyResponse = await agent.generate({ messages: [{ role: "user", content: message }], threadId: storyState.threadId, resourceId: storyState.resourceId, }); const storyText = storyResponse.text; const audioResponse = await agent.voice.speak(storyText); if (!audioResponse.body) { throw new Error("No audio stream received"); } const audio = await readStream(audioResponse.body); setStoryState((prev) => ({ phase: "beginning", threadId: prev.threadId, resourceId: prev.resourceId, content: { ...prev.content, beginning: storyText, }, })); setAudioBlob(audio); return audio; } catch (error) { console.error("Error generating story beginning:", error); } finally { setIsLoading(false); } }; ``` ## 音声の再生 このスニペットは、新しい音声データを監視してテキスト読み上げ音声の再生を処理する方法を示しています。音声が受信されると、コードは音声のBlobからブラウザで再生可能なURLを作成し、それをaudio要素に割り当て、自動的に再生を試みます。 ```typescript filename="/app/components/StoryManager.tsx" useEffect(() => { if (!audioRef.current || !audioData) return; // Store a reference to the HTML audio element const currentAudio = audioRef.current; // Convert the Blob/File audio data from Mastra into a URL the browser can play const url = URL.createObjectURL(audioData); const playAudio = async () => { try { currentAudio.src = url; await currentAudio.load(); await currentAudio.play(); setIsPlaying(true); } catch (error) { console.error("Auto-play failed:", error); } }; playAudio(); return () => { if (currentAudio) { currentAudio.pause(); currentAudio.src = ""; URL.revokeObjectURL(url); } }; }, [audioData]); ``` Interactive Story Generator の完全な実装は、私たちの GitHub リポジトリでご覧いただけます。




--- title: 発言の順番 description: Mastraを使用して、順番に発言するマルチエージェントのディベートを作成する例。 --- import { GithubLink } from "@/components/github-link"; # ターン制AIディベート [JA] Source: https://mastra.ai/ja/examples/voice/turn-taking 以下のコードスニペットは、Mastraを使ってターン制のマルチエージェント会話システムを実装する方法を示しています。この例では、2人のAIエージェント(楽観主義者と懐疑主義者)がユーザーが提供したトピックについてディベートを行い、お互いの意見に順番に応答します。 ## 音声機能を持つエージェントの作成 まず、異なる個性と音声機能を持つ2つのエージェントを作成します。 ```typescript filename="src/mastra/agents/index.ts" import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { OpenAIVoice } from "@mastra/voice-openai"; export const optimistAgent = new Agent({ name: "Optimist", instructions: "You are an optimistic debater who sees the positive side of every topic. Keep your responses concise and engaging, about 2-3 sentences.", model: openai("gpt-4o"), voice: new OpenAIVoice({ speaker: "alloy", }), }); export const skepticAgent = new Agent({ name: "Skeptic", instructions: "You are a RUDE skeptical debater who questions assumptions and points out potential issues. Keep your responses concise and engaging, about 2-3 sentences.", model: openai("gpt-4o"), voice: new OpenAIVoice({ speaker: "echo", }), }); ``` ## Mastraにエージェントを登録する 次に、両方のエージェントをMastraインスタンスに登録します: ```typescript filename="src/mastra/index.ts" import { PinoLogger } from "@mastra/loggers"; import { Mastra } from "@mastra/core/mastra"; import { optimistAgent, skepticAgent } from "./agents"; export const mastra = new Mastra({ agents: { optimistAgent, skepticAgent, }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); ``` ## ディベートにおけるターンテイキングの管理 この例では、エージェント同士のターンテイキングの流れを管理し、各エージェントが前のエージェントの発言に応答することを確実にする方法を示します。 ```typescript filename="src/debate/turn-taking.ts" import { mastra } from "../../mastra"; import { playAudio, Recorder } from "@mastra/node-audio"; import * as p from "@clack/prompts"; // Helper function to format text with line wrapping function formatText(text: string, maxWidth: number): string { const words = text.split(" "); let result = ""; let currentLine = ""; for (const word of words) { if (currentLine.length + word.length + 1 <= maxWidth) { currentLine += (currentLine ? " " : "") + word; } else { result += (result ? "\n" : "") + currentLine; currentLine = word; } } if (currentLine) { result += (result ? "\n" : "") + currentLine; } return result; } // Initialize audio recorder const recorder = new Recorder({ outputPath: "./debate.mp3", }); // Process one turn of the conversation async function processTurn( agentName: "optimistAgent" | "skepticAgent", otherAgentName: string, topic: string, previousResponse: string = "", ) { const agent = mastra.getAgent(agentName); const spinner = p.spinner(); spinner.start(`${agent.name} is thinking...`); let prompt; if (!previousResponse) { // First turn prompt = `Discuss this topic: ${topic}. Introduce your perspective on it.`; } else { // Responding to the other agent prompt = `The topic is: ${topic}. ${otherAgentName} just said: "${previousResponse}". Respond to their points.`; } // Generate text response const { text } = await agent.generate(prompt, { temperature: 0.9, }); spinner.message(`${agent.name} is speaking...`); // Convert to speech and play const audioStream = await agent.voice.speak(text, { speed: 1.2, responseFormat: "wav", // Optional: specify a response format }); if (audioStream) { audioStream.on("data", (chunk) => { recorder.write(chunk); }); } spinner.stop(`${agent.name} said:`); // Format the text to wrap at 80 characters for better display const formattedText = formatText(text, 80); p.note(formattedText, agent.name); if (audioStream) { const speaker = playAudio(audioStream); await new Promise((resolve) => { speaker.once("close", () => { resolve(); }); }); } return text; } // Main function to run the debate export async function runDebate(topic: string, turns: number = 3) { recorder.start(); p.intro("AI Debate - Two Agents Discussing a Topic"); p.log.info(`Starting a debate on: ${topic}`); p.log.info( `The debate will continue for ${turns} turns each. Press Ctrl+C to exit at any time.`, ); let optimistResponse = ""; let skepticResponse = ""; const responses = []; for (let turn = 1; turn <= turns; turn++) { p.log.step(`Turn ${turn}`); // Optimist's turn optimistResponse = await processTurn( "optimistAgent", "Skeptic", topic, skepticResponse, ); responses.push({ agent: "Optimist", text: optimistResponse, }); // Skeptic's turn skepticResponse = await processTurn( "skepticAgent", "Optimist", topic, optimistResponse, ); responses.push({ agent: "Skeptic", text: skepticResponse, }); } recorder.end(); p.outro("Debate concluded! The full audio has been saved to debate.mp3"); return responses; } ``` ## コマンドラインからディベートを実行する コマンドラインからディベートを実行するためのシンプルなスクリプトはこちらです: ```typescript filename="src/index.ts" import { runDebate } from "./debate/turn-taking"; import * as p from "@clack/prompts"; async function main() { // Get the topic from the user const topic = await p.text({ message: "Enter a topic for the agents to discuss:", placeholder: "Climate change", validate(value) { if (!value) return "Please enter a topic"; return; }, }); // Exit if cancelled if (p.isCancel(topic)) { p.cancel("Operation cancelled."); process.exit(0); } // Get the number of turns const turnsInput = await p.text({ message: "How many turns should each agent have?", placeholder: "3", initialValue: "3", validate(value) { const num = parseInt(value); if (isNaN(num) || num < 1) return "Please enter a positive number"; return; }, }); // Exit if cancelled if (p.isCancel(turnsInput)) { p.cancel("Operation cancelled."); process.exit(0); } const turns = parseInt(turnsInput as string); // Run the debate await runDebate(topic as string, turns); } main().catch((error) => { p.log.error("An error occurred:"); console.error(error); process.exit(1); }); ``` ## ディベート用のウェブインターフェースを作成する ウェブアプリケーションの場合、ユーザーがディベートを開始し、エージェントの応答を聞くことができるシンプルなNext.jsコンポーネントを作成できます。 ```tsx filename="app/components/DebateInterface.tsx" "use client"; import { useState, useRef } from "react"; import { MastraClient } from "@mastra/client-js"; const mastraClient = new MastraClient({ baseUrl: process.env.NEXT_PUBLIC_MASTRA_URL || "http://localhost:4111", }); export default function DebateInterface() { const [topic, setTopic] = useState(""); const [turns, setTurns] = useState(3); const [isDebating, setIsDebating] = useState(false); const [responses, setResponses] = useState([]); const [isPlaying, setIsPlaying] = useState(false); const audioRef = useRef(null); // Function to start the debate const startDebate = async () => { if (!topic) return; setIsDebating(true); setResponses([]); try { const optimist = mastraClient.getAgent("optimistAgent"); const skeptic = mastraClient.getAgent("skepticAgent"); const newResponses = []; let optimistResponse = ""; let skepticResponse = ""; for (let turn = 1; turn <= turns; turn++) { // Optimist's turn let prompt; if (turn === 1) { prompt = `Discuss this topic: ${topic}. Introduce your perspective on it.`; } else { prompt = `The topic is: ${topic}. Skeptic just said: "${skepticResponse}". Respond to their points.`; } const optimistResult = await optimist.generate({ messages: [{ role: "user", content: prompt }], }); optimistResponse = optimistResult.text; newResponses.push({ agent: "Optimist", text: optimistResponse, }); // Update UI after each response setResponses([...newResponses]); // Skeptic's turn prompt = `The topic is: ${topic}. Optimist just said: "${optimistResponse}". Respond to their points.`; const skepticResult = await skeptic.generate({ messages: [{ role: "user", content: prompt }], }); skepticResponse = skepticResult.text; newResponses.push({ agent: "Skeptic", text: skepticResponse, }); // Update UI after each response setResponses([...newResponses]); } } catch (error) { console.error("Error starting debate:", error); } finally { setIsDebating(false); } }; // Function to play audio for a specific response const playAudio = async (text: string, agent: string) => { if (isPlaying) return; try { setIsPlaying(true); const agentClient = mastraClient.getAgent( agent === "Optimist" ? "optimistAgent" : "skepticAgent", ); const audioResponse = await agentClient.voice.speak(text); if (!audioResponse.body) { throw new Error("No audio stream received"); } // Convert stream to blob const reader = audioResponse.body.getReader(); const chunks = []; while (true) { const { done, value } = await reader.read(); if (done) break; chunks.push(value); } const blob = new Blob(chunks, { type: "audio/mpeg" }); const url = URL.createObjectURL(blob); if (audioRef.current) { audioRef.current.src = url; audioRef.current.onended = () => { setIsPlaying(false); URL.revokeObjectURL(url); }; audioRef.current.play(); } } catch (error) { console.error("Error playing audio:", error); setIsPlaying(false); } }; return (

ターン制AIディベート

setTopic(e.target.value)} className="w-full p-2 border rounded" placeholder="例:気候変動、AI倫理、宇宙探査" />
setTurns(parseInt(e.target.value))} min={1} max={10} className="w-full p-2 border rounded" />
); } ``` この例では、Mastra を使用してターン制のマルチエージェント会話システムを作成する方法を示します。エージェントたちはユーザーが選んだトピックについてディベートを行い、それぞれが前のエージェントの発言に応答します。また、システムは各エージェントの応答を音声に変換し、没入感のあるディベート体験を提供します。 AI Debate with Turn Taking の完全な実装は、私たちの GitHub リポジトリでご覧いただけます。




--- title: "例: ツール/エージェントをステップとして使用する | ワークフロー | Mastra ドキュメント" description: ワークフロー内のステップとしてツールやエージェントを統合するためにMastraを使用する例。 --- # ワークフローステップとしてのツール/エージェント [JA] Source: https://mastra.ai/ja/examples/workflows/agent-and-tool-interop この例では、ツールやエージェントをワークフローステップとして作成し、統合する方法を示します。 Mastra は、ステップまたはエージェントを受け取り、Step インターフェースを満たすオブジェクトを返す `createStep` ヘルパー関数を提供しています。 ## セットアップ ```sh copy npm install @ai-sdk/openai @mastra/core ``` ## 天気レポーターエージェントの定義 天気レポーターのように天気予報を説明するために、LLM を活用する天気レポーターエージェントを定義します。 ```ts showLineNumbers copy filename="agents/weather-reporter-agent.ts" import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; // Create an agent that explains weather reports in a conversational style export const weatherReporterAgent = new Agent({ name: "weatherExplainerAgent", model: openai("gpt-4o"), instructions: ` You are a weather explainer. You have access to input that will help you get weather-specific activities for any city. The tool uses agents to plan the activities, you just need to provide the city. Explain the weather report like a weather reporter. `, }); ``` ## 天気ツールの定義 場所名を入力として受け取り、詳細な天気情報を出力する天気ツールを定義します。 ```ts showLineNumbers copy filename="tools/weather-tool.ts" import { createTool } from "@mastra/core/tools"; import { z } from "zod"; interface GeocodingResponse { results: { latitude: number; longitude: number; name: string; }[]; } interface WeatherResponse { current: { time: string; temperature_2m: number; apparent_temperature: number; relative_humidity_2m: number; wind_speed_10m: number; wind_gusts_10m: number; weather_code: number; }; } // Create a tool to fetch weather data export const weatherTool = createTool({ id: "get-weather", description: "Get current weather for a location", inputSchema: z.object({ location: z.string().describe("City name"), }), outputSchema: z.object({ temperature: z.number(), feelsLike: z.number(), humidity: z.number(), windSpeed: z.number(), windGust: z.number(), conditions: z.string(), location: z.string(), }), execute: async ({ context }) => { return await getWeather(context.location); }, }); // Helper function to fetch weather data from external APIs const getWeather = async (location: string) => { const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(location)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = (await geocodingResponse.json()) as GeocodingResponse; if (!geocodingData.results?.[0]) { throw new Error(`Location '${location}' not found`); } const { latitude, longitude, name } = geocodingData.results[0]; const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m,wind_gusts_10m,weather_code`; const response = await fetch(weatherUrl); const data = (await response.json()) as WeatherResponse; return { temperature: data.current.temperature_2m, feelsLike: data.current.apparent_temperature, humidity: data.current.relative_humidity_2m, windSpeed: data.current.wind_speed_10m, windGust: data.current.wind_gusts_10m, conditions: getWeatherCondition(data.current.weather_code), location: name, }; }; // Helper function to convert numeric weather codes to human-readable descriptions function getWeatherCondition(code: number): string { const conditions: Record = { 0: "Clear sky", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast", 45: "Foggy", 48: "Depositing rime fog", 51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle", 56: "Light freezing drizzle", 57: "Dense freezing drizzle", 61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain", 66: "Light freezing rain", 67: "Heavy freezing rain", 71: "Slight snow fall", 73: "Moderate snow fall", 75: "Heavy snow fall", 77: "Snow grains", 80: "Slight rain showers", 81: "Moderate rain showers", 82: "Violent rain showers", 85: "Slight snow showers", 86: "Heavy snow showers", 95: "Thunderstorm", 96: "Thunderstorm with slight hail", 99: "Thunderstorm with heavy hail", }; return conditions[code] || "Unknown"; } ``` ## インターロップワークフローの定義 エージェントとツールをステップとして取り込むワークフローを定義します。 ```ts showLineNumbers copy filename="workflows/interop-workflow.ts" import { createWorkflow, createStep } from "@mastra/core/workflows"; import { weatherTool } from "../tools/weather-tool"; import { weatherReporterAgent } from "../agents/weather-reporter-agent"; import { z } from "zod"; // Create workflow steps from existing tool and agent const fetchWeather = createStep(weatherTool); const reportWeather = createStep(weatherReporterAgent); const weatherWorkflow = createWorkflow({ steps: [fetchWeather, reportWeather], id: "weather-workflow-step1-single-day", inputSchema: z.object({ location: z.string().describe("The city to get the weather for"), }), outputSchema: z.object({ text: z.string(), }), }) .then(fetchWeather) .then( createStep({ id: "report-weather", inputSchema: fetchWeather.outputSchema, outputSchema: z.object({ text: z.string(), }), execute: async ({ inputData, mastra }) => { // Create a prompt with the weather data const prompt = "Forecast data: " + JSON.stringify(inputData); const agent = mastra.getAgent("weatherReporterAgent"); // Generate a weather report using the agent const result = await agent.generate([ { role: "user", content: prompt, }, ]); return { text: result.text }; }, }), ); weatherWorkflow.commit(); export { weatherWorkflow }; ``` ## Mastraクラスでワークフローインスタンスを登録する ワークフローをmastraインスタンスに登録します。 ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { PinoLogger } from "@mastra/loggers"; import { weatherWorkflow } from "./workflows/interop-workflow"; import { weatherReporterAgent } from "./agents/weather-reporter-agent"; // Create a new Mastra instance with our components const mastra = new Mastra({ workflows: { weatherWorkflow, }, agents: { weatherReporterAgent, }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## ワークフローの実行 ここでは、mastra インスタンスから weather ワークフローを取得し、実行を作成して、必要な inputData を使ってその実行を開始します。 ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; const workflow = mastra.getWorkflow("weatherWorkflow"); const run = workflow.createRun(); // Start the workflow with Lagos as the location const result = await run.start({ inputData: { location: "Lagos" } }); console.dir(result, { depth: null }); ``` --- title: "例: 配列を入力として使用する(.foreach()) | ワークフロー | Mastra ドキュメント" description: ワークフローで .foreach() を使って配列を処理する Mastra の使用例。 --- # 配列を入力として使用する [JA] Source: https://mastra.ai/ja/examples/workflows/array-as-input この例では、ワークフローで配列入力を処理する方法を示します。Mastra では、配列内の各要素に対してステップを実行する `.foreach()` ヘルパー関数が用意されています。 ## セットアップ ```sh copy npm install @ai-sdk/openai @mastra/core simple-git ``` ## ドキュメント生成エージェントの定義 コードファイルまたはコードファイルの要約をもとに、LLMコールを活用してドキュメントを生成するドキュメント生成エージェントを定義します。 ```ts showLineNumbers copy filename="agents/docs-generator-agent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // Create a documentation generator agent for code analysis const docGeneratorAgent = new Agent({ name: "doc_generator_agent", instructions: `You are a technical documentation expert. You will analyze the provided code files and generate a comprehensive documentation summary. For each file: 1. Identify the main purpose and functionality 2. Document key components, classes, functions, and interfaces 3. Note important dependencies and relationships between components 4. Highlight any notable patterns or architectural decisions 5. Include relevant code examples where helpful Format the documentation in a clear, organized manner using markdown with: - File overviews - Component breakdowns - Code examples - Cross-references between related components Focus on making the documentation clear and useful for developers who need to understand and work with this codebase.`, model: openai("gpt-4o"), }); export { docGeneratorAgent }; ``` ## ファイルサマリーワークフローの定義 ファイルサマリーワークフローを2つのステップで定義します。1つ目は特定のファイルのコードを取得するステップ、2つ目はそのコードファイルのためのreadmeを生成するステップです。 ```ts showLineNumbers copy filename="workflows/file-summary-workflow.ts" import { createWorkflow, createStep } from "@mastra/core/workflows"; import { docGeneratorAgent } from "../agents/docs-generator-agent"; import { z } from "zod"; import fs from "fs"; // Step 1: Read the code content from a file const scrapeCodeStep = createStep({ id: "scrape_code", description: "Scrape the code from a single file", inputSchema: z.string(), outputSchema: z.object({ path: z.string(), content: z.string(), }), execute: async ({ inputData }) => { const filePath = inputData; const content = fs.readFileSync(filePath, "utf-8"); return { path: filePath, content, }; }, }); // Step 2: Generate documentation for a single file const generateDocForFileStep = createStep({ id: "generateDocForFile", inputSchema: z.object({ path: z.string(), content: z.string(), }), outputSchema: z.object({ path: z.string(), documentation: z.string(), }), execute: async ({ inputData }) => { const docs = await docGeneratorAgent.generate( `Generate documentation for the following code: ${inputData.content}`, ); return { path: inputData.path, documentation: docs.text.toString(), }; }, }); const generateSummaryWorkflow = createWorkflow({ id: "generate-summary", inputSchema: z.string(), outputSchema: z.object({ path: z.string(), documentation: z.string(), }), steps: [scrapeCodeStep, generateDocForFileStep], }) .then(scrapeCodeStep) .then(generateDocForFileStep) .commit(); export { generateSummaryWorkflow }; ``` ## Readmeジェネレーターのワークフローを定義する 4つのステップからなるreadmeジェネレーターのワークフローを定義します。最初のステップはGitHubリポジトリをクローンすること、次にワークフローを一時停止してreadmeを生成する際に考慮するフォルダーをユーザーから入力してもらうこと、次にそのフォルダー内のすべてのファイルの概要を生成すること、そして最後に各ファイルごとに生成されたドキュメントを1つのreadmeにまとめることです。 ```ts showLineNumbers copy filename="workflows/readme-generator-workflow.ts import { createWorkflow, createStep } from "@mastra/core/workflows"; import { docGeneratorAgent } from "../agents/docs-generator-agent"; import { generateSummaryWorkflow } from "./file-summary-workflow"; import { z } from "zod"; import simpleGit from "simple-git"; import fs from "fs"; import path from "path"; // Step 1: Clone a GitHub repository locally const cloneRepositoryStep = createStep({ id: "clone_repository", description: "Clone the repository from the given URL", inputSchema: z.object({ repoUrl: z.string(), }), outputSchema: z.object({ success: z.boolean(), message: z.string(), data: z.object({ repoUrl: z.string(), }), }), execute: async ({ inputData, mastra, getStepResult, getInitData, runtimeContext, }) => { const git = simpleGit(); // Skip cloning if repo already exists if (fs.existsSync("./temp")) { return { success: true, message: "Repository already exists", data: { repoUrl: inputData.repoUrl, }, }; } try { // Clone the repository to the ./temp directory await git.clone(inputData.repoUrl, "./temp"); return { success: true, message: "Repository cloned successfully", data: { repoUrl: inputData.repoUrl, }, }; } catch (error) { throw new Error(`Failed to clone repository: ${error}`); } }, }); // Step 2: Get user input on which folders to analyze const selectFolderStep = createStep({ id: "select_folder", description: "Select the folder(s) to generate the docs", inputSchema: z.object({ success: z.boolean(), message: z.string(), data: z.object({ repoUrl: z.string(), }), }), outputSchema: z.array(z.string()), suspendSchema: z.object({ folders: z.array(z.string()), message: z.string(), }), resumeSchema: z.object({ selection: z.array(z.string()), }), execute: async ({ resumeData, suspend }) => { const tempPath = "./temp"; const folders = fs .readdirSync(tempPath) .filter((item) => fs.statSync(path.join(tempPath, item)).isDirectory()); if (!resumeData?.selection) { await suspend({ folders, message: "Please select folders to generate documentation for:", }); return []; } // Gather all file paths from selected folders const filePaths: string[] = []; // Helper function to recursively read files from directories const readFilesRecursively = (dir: string) => { const items = fs.readdirSync(dir); for (const item of items) { const fullPath = path.join(dir, item); const stat = fs.statSync(fullPath); if (stat.isDirectory()) { readFilesRecursively(fullPath); } else if (stat.isFile()) { filePaths.push(fullPath.replace(tempPath + "/", "")); } } }; for (const folder of resumeData.selection) { readFilesRecursively(path.join(tempPath, folder)); } return filePaths; }, }); // Step 4: Combine all documentation into a single README const collateDocumentationStep = createStep({ id: "collate_documentation", inputSchema: z.array( z.object({ path: z.string(), documentation: z.string(), }), ), outputSchema: z.string(), execute: async ({ inputData }) => { const readme = await docGeneratorAgent.generate( `Generate a README.md file for the following documentation: ${inputData.map((doc) => doc.documentation).join("\n")}`, ); return readme.text.toString(); }, }); const readmeGeneratorWorkflow = createWorkflow({ id: "readme-generator", inputSchema: z.object({ repoUrl: z.string(), }), outputSchema: z.object({ success: z.boolean(), message: z.string(), data: z.object({ repoUrl: z.string(), }), }), steps: [ cloneRepositoryStep, selectFolderStep, generateSummaryWorkflow, collateDocumentationStep, ], }) .then(cloneRepositoryStep) .then(selectFolderStep) .foreach(generateSummaryWorkflow) .then(collateDocumentationStep) .commit(); export { readmeGeneratorWorkflow }; ``` ## MastraクラスでAgentとWorkflowインスタンスを登録する エージェントとワークフローをmastraインスタンスに登録します。これは、ワークフロー内でエージェントへアクセスできるようにするために重要です。 ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core"; import { PinoLogger } from "@mastra/loggers"; import { docGeneratorAgent } from "./agents/docs-generator-agent"; import { readmeGeneratorWorkflow } from "./workflows/readme-generator-workflow"; import { generateSummaryWorkflow } from "./workflows/file-summary-workflow"; // Create a new Mastra instance and register components const mastra = new Mastra({ agents: { docGeneratorAgent, }, workflows: { readmeGeneratorWorkflow, generateSummaryWorkflow, }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## Readme Generator ワークフローの実行 ここでは、mastra インスタンスから readme generator ワークフローを取得し、ランを作成して、必要な inputData を使って作成したランを実行します。 ```ts showLineNumbers copy filename="exec.ts" import { promptUserForFolders } from "./utils"; import { mastra } from "./"; // GitHub repository to generate documentation for const ghRepoUrl = "https://github.com/mastra-ai/mastra"; const run = mastra.getWorkflow("readmeGeneratorWorkflow").createRun(); // Start the workflow with the repository URL as input const res = await run.start({ inputData: { repoUrl: ghRepoUrl } }); const { status, steps } = res; // Handle suspended workflow (waiting for user input) if (status === "suspended") { // Get the suspended step data const suspendedStep = steps["select_folder"]; let folderList: string[] = []; // Extract the folder list from step data if ( suspendedStep.status === "suspended" && "folders" in suspendedStep.payload ) { folderList = suspendedStep.payload.folders as string[]; } else if (suspendedStep.status === "success" && suspendedStep.output) { folderList = suspendedStep.output; } if (!folderList.length) { console.log("No folders available for selection."); process.exit(1); } // Prompt user to select folders const folders = await promptUserForFolders(folderList); // Resume the workflow with user selections const resumedResult = await run.resume({ resumeData: { selection: folders }, step: "select_folder", }); // Print resumed result if (resumedResult.status === "success") { console.log(resumedResult.result); } else { console.log(resumedResult); } process.exit(1); } // Handle completed workflow if (res.status === "success") { console.log(res.result ?? res); } else { console.log(res); } ``` --- title: "例: 分岐パス | ワークフロー | Mastra ドキュメント" description: 中間結果に基づいて分岐パスを持つワークフローを作成するために Mastra を使用する例。 --- import { GithubLink } from "@/components/github-link"; # 分岐パス [JA] Source: https://mastra.ai/ja/examples/workflows/branching-paths データを処理する際、中間結果に基づいて異なる処理を行う必要がよくあります。この例では、ワークフローが複数のパスに分岐し、それぞれのパスが前のステップの出力に基づいて異なる処理を実行する方法を示します。 ## フロー制御ダイアグラム この例では、ワークフローが分岐し、それぞれのパスが前のステップの出力に基づいて異なる処理を実行する方法を示しています。 フロー制御ダイアグラムは次のとおりです: 分岐パスを持つワークフローのダイアグラム ## ステップの作成 まず、ステップを作成し、ワークフローを初期化しましょう。 {/* prettier-ignore */} ```ts showLineNumbers copy import { Step, Workflow } from "@mastra/core/workflows"; import { z } from "zod" const stepOne = new Step({ id: "stepOne", execute: async ({ context }) => ({ doubledValue: context.triggerData.inputValue * 2 }) }); const stepTwo = new Step({ id: "stepTwo", execute: async ({ context }) => { const stepOneResult = context.getStepResult<{ doubledValue: number }>("stepOne"); if (!stepOneResult) { return { isDivisibleByFive: false } } return { isDivisibleByFive: stepOneResult.doubledValue % 5 === 0 } } }); const stepThree = new Step({ id: "stepThree", execute: async ({ context }) =>{ const stepOneResult = context.getStepResult<{ doubledValue: number }>("stepOne"); if (!stepOneResult) { return { incrementedValue: 0 } } return { incrementedValue: stepOneResult.doubledValue + 1 } } }); const stepFour = new Step({ id: "stepFour", execute: async ({ context }) => { const stepThreeResult = context.getStepResult<{ incrementedValue: number }>("stepThree"); if (!stepThreeResult) { return { isDivisibleByThree: false } } return { isDivisibleByThree: stepThreeResult.incrementedValue % 3 === 0 } } }); // New step that depends on both branches const finalStep = new Step({ id: "finalStep", execute: async ({ context }) => { // Get results from both branches using getStepResult const stepTwoResult = context.getStepResult<{ isDivisibleByFive: boolean }>("stepTwo"); const stepFourResult = context.getStepResult<{ isDivisibleByThree: boolean }>("stepFour"); const isDivisibleByFive = stepTwoResult?.isDivisibleByFive || false; const isDivisibleByThree = stepFourResult?.isDivisibleByThree || false; return { summary: `The number ${context.triggerData.inputValue} when doubled ${isDivisibleByFive ? 'is' : 'is not'} divisible by 5, and when doubled and incremented ${isDivisibleByThree ? 'is' : 'is not'} divisible by 3.`, isDivisibleByFive, isDivisibleByThree } } }); // Build the workflow const myWorkflow = new Workflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); ``` ## 分岐パスとステップの連結 それでは、分岐パスを持つワークフローを設定し、複合的な `.after([])` 構文を使ってそれらを統合してみましょう。 ```ts showLineNumbers copy // Create two parallel branches myWorkflow // First branch .step(stepOne) .then(stepTwo) // Second branch .after(stepOne) .step(stepThree) .then(stepFour) // Merge both branches using compound after syntax .after([stepTwo, stepFour]) .step(finalStep) .commit(); const { start } = myWorkflow.createRun(); const result = await start({ triggerData: { inputValue: 3 } }); console.log(result.steps.finalStep.output.summary); // Output: "The number 3 when doubled is not divisible by 5, and when doubled and incremented is divisible by 3." ``` ## 高度なブランチとマージ 複数のブランチやマージポイントを使って、より複雑なワークフローを作成できます。 ```ts showLineNumbers copy const complexWorkflow = new Workflow({ name: "complex-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); // Create multiple branches with different merge points complexWorkflow // Main step .step(stepOne) // First branch .then(stepTwo) // Second branch .after(stepOne) .step(stepThree) .then(stepFour) // Third branch (another path from stepOne) .after(stepOne) .step( new Step({ id: "alternativePath", execute: async ({ context }) => { const stepOneResult = context.getStepResult<{ doubledValue: number }>( "stepOne", ); return { result: (stepOneResult?.doubledValue || 0) * 3, }; }, }), ) // Merge first and second branches .after([stepTwo, stepFour]) .step( new Step({ id: "partialMerge", execute: async ({ context }) => { const stepTwoResult = context.getStepResult<{ isDivisibleByFive: boolean; }>("stepTwo"); const stepFourResult = context.getStepResult<{ isDivisibleByThree: boolean; }>("stepFour"); return { intermediateResult: "Processed first two branches", branchResults: { branch1: stepTwoResult?.isDivisibleByFive, branch2: stepFourResult?.isDivisibleByThree, }, }; }, }), ) // Final merge of all branches .after(["partialMerge", "alternativePath"]) .step( new Step({ id: "finalMerge", execute: async ({ context }) => { const partialMergeResult = context.getStepResult<{ intermediateResult: string; branchResults: { branch1: boolean; branch2: boolean }; }>("partialMerge"); const alternativePathResult = context.getStepResult<{ result: number }>( "alternativePath", ); return { finalResult: "All branches processed", combinedData: { fromPartialMerge: partialMergeResult?.branchResults, fromAlternativePath: alternativePathResult?.result, }, }; }, }), ) .commit(); ```




--- title: "例: ワークフローからエージェントを呼び出す | Mastra ドキュメント" description: ワークフローのステップ内で Mastra を使って AI エージェントを呼び出す例。 --- # ワークフローからエージェントを呼び出す [JA] Source: https://mastra.ai/ja/examples/workflows/calling-agent この例では、指定された天気条件に合わせてアクティビティを提案するAIエージェントを呼び出し、ワークフローのステップ内で実行するワークフローの作成方法を説明します。 ## セットアップ ```sh copy npm install @ai-sdk/openai @mastra/core ``` ## プランニングエージェントの定義 場所とそれに対応する天候条件をもとに活動を計画するために、LLMコールを活用するプランニングエージェントを定義します。 ```ts showLineNumbers copy filename="agents/planning-agent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const llm = openai("gpt-4o"); // Create a new agent for activity planning const planningAgent = new Agent({ name: "planningAgent", model: llm, instructions: ` You are a local activities and travel expert who excels at weather-based planning. Analyze the weather data and provide practical activity recommendations. 📅 [Day, Month Date, Year] ═══════════════════════════ 🌡️ WEATHER SUMMARY • Conditions: [brief description] • Temperature: [X°C/Y°F to A°C/B°F] • Precipitation: [X% chance] 🌅 MORNING ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🌞 AFTERNOON ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🏠 INDOOR ALTERNATIVES • [Activity Name] - [Brief description including specific venue] Ideal for: [weather condition that would trigger this alternative] ⚠️ SPECIAL CONSIDERATIONS • [Any relevant weather warnings, UV index, wind conditions, etc.] Guidelines: - Suggest 2-3 time-specific outdoor activities per day - Include 1-2 indoor backup options - For precipitation >50%, lead with indoor activities - All activities must be specific to the location - Include specific venues, trails, or locations - Consider activity intensity based on temperature - Keep descriptions concise but informative Maintain this exact formatting for consistency, using the emoji and section headers as shown. `, }); export { planningAgent }; ``` ## アクティビティ計画ワークフローの定義 アクティビティ計画ワークフローを2つのステップで定義します。1つ目はネットワークコールで天気を取得し、2つ目はplanning agentを使ってアクティビティを計画します。 ```ts showLineNumbers copy filename="workflows/agent-workflow.ts" import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; // Helper function to convert numeric weather codes to human-readable descriptions function getWeatherCondition(code: number): string { const conditions: Record = { 0: "Clear sky", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast", 45: "Foggy", 48: "Depositing rime fog", 51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle", 61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain", 71: "Slight snow fall", 73: "Moderate snow fall", 75: "Heavy snow fall", 95: "Thunderstorm", }; return conditions[code] || "Unknown"; } const forecastSchema = z.object({ date: z.string(), maxTemp: z.number(), minTemp: z.number(), precipitationChance: z.number(), condition: z.string(), location: z.string(), }); ``` ### ステップ1: 指定した都市の天気データを取得するステップを作成 ```ts showLineNumbers copy filename="workflows/agent-workflow.ts" const fetchWeather = createStep({ id: "fetch-weather", description: "Fetches weather forecast for a given city", inputSchema: z.object({ city: z.string(), }), outputSchema: forecastSchema, execute: async ({ inputData }) => { if (!inputData) { throw new Error("Trigger data not found"); } // First API call: Convert city name to latitude and longitude const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(inputData.city)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = (await geocodingResponse.json()) as { results: { latitude: number; longitude: number; name: string }[]; }; if (!geocodingData.results?.[0]) { throw new Error(`Location '${inputData.city}' not found`); } const { latitude, longitude, name } = geocodingData.results[0]; // Second API call: Get weather data using coordinates const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=precipitation,weathercode&timezone=auto,&hourly=precipitation_probability,temperature_2m`; const response = await fetch(weatherUrl); const data = (await response.json()) as { current: { time: string; precipitation: number; weathercode: number; }; hourly: { precipitation_probability: number[]; temperature_2m: number[]; }; }; const forecast = { date: new Date().toISOString(), maxTemp: Math.max(...data.hourly.temperature_2m), minTemp: Math.min(...data.hourly.temperature_2m), condition: getWeatherCondition(data.current.weathercode), location: name, precipitationChance: data.hourly.precipitation_probability.reduce( (acc, curr) => Math.max(acc, curr), 0, ), }; return forecast; }, }); ``` ### ステップ2: agentを使ってアクティビティの提案を生成するステップを作成 ```ts showLineNumbers copy filename="workflows/agent-workflow.ts" const planActivities = createStep({ id: "plan-activities", description: "Suggests activities based on weather conditions", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `Based on the following weather forecast for ${forecast.location}, suggest appropriate activities: ${JSON.stringify(forecast, null, 2)} `; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); const activityPlanningWorkflow = createWorkflow({ steps: [fetchWeather, planActivities], id: "activity-planning-step1-single-day", inputSchema: z.object({ city: z.string().describe("The city to get the weather for"), }), outputSchema: z.object({ activities: z.string(), }), }) .then(fetchWeather) .then(planActivities); activityPlanningWorkflow.commit(); export { activityPlanningWorkflow }; ``` ## MastraクラスにAgentとWorkflowインスタンスを登録する planning agentとactivity planning workflowをmastraインスタンスに登録します。 これは、activity planning workflow内でplanning agentへのアクセスを可能にするために重要です。 ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { createLogger } from "@mastra/core/logger"; import { activityPlanningWorkflow } from "./workflows/agent-workflow"; import { planningAgent } from "./agents/planning-agent"; // Create a new Mastra instance and register components const mastra = new Mastra({ workflows: { activityPlanningWorkflow, }, agents: { planningAgent, }, logger: createLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## アクティビティ計画ワークフローを実行する ここでは、mastra インスタンスからアクティビティ計画ワークフローを取得し、実行を作成して、必要な inputData を使ってその実行を開始します。 ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; const workflow = mastra.getWorkflow("activityPlanningWorkflow"); const run = workflow.createRun(); // Start the workflow with New York as the city input const result = await run.start({ inputData: { city: "New York" } }); console.dir(result, { depth: null }); ``` --- title: "例: 条件分岐 | ワークフロー | Mastra ドキュメント" description: Mastra を使用してワークフロー内で `branch` ステートメントを使った条件分岐の作成例。 --- # 条件分岐を持つワークフロー [JA] Source: https://mastra.ai/ja/examples/workflows/conditional-branching ワークフローは、しばしば何らかの条件に基づいて異なる経路をたどる必要があります。 この例では、`branch` 構文を使ってワークフロー内に条件付きのフローを作成する方法を示します。 ## セットアップ ```sh copy npm install @ai-sdk/openai @mastra/core ``` ## プランニングエージェントの定義 場所とそれに対応する天候条件をもとに活動を計画するために、LLMコールを活用するプランニングエージェントを定義します。 ```ts showLineNumbers copy filename="agents/planning-agent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const llm = openai("gpt-4o"); // Define the planning agent that generates activity recommendations // based on weather conditions and location const planningAgent = new Agent({ name: "planningAgent", model: llm, instructions: ` You are a local activities and travel expert who excels at weather-based planning. Analyze the weather data and provide practical activity recommendations. 📅 [Day, Month Date, Year] ═══════════════════════════ 🌡️ WEATHER SUMMARY • Conditions: [brief description] • Temperature: [X°C/Y°F to A°C/B°F] • Precipitation: [X% chance] 🌅 MORNING ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🌞 AFTERNOON ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🏠 INDOOR ALTERNATIVES • [Activity Name] - [Brief description including specific venue] Ideal for: [weather condition that would trigger this alternative] ⚠️ SPECIAL CONSIDERATIONS • [Any relevant weather warnings, UV index, wind conditions, etc.] Guidelines: - Suggest 2-3 time-specific outdoor activities per day - Include 1-2 indoor backup options - For precipitation >50%, lead with indoor activities - All activities must be specific to the location - Include specific venues, trails, or locations - Consider activity intensity based on temperature - Keep descriptions concise but informative Maintain this exact formatting for consistency, using the emoji and section headers as shown. `, }); export { planningAgent }; ``` ## アクティビティ計画ワークフローの定義 3つのステップで計画ワークフローを定義します:1つはネットワークコールで天気を取得するステップ、1つはアクティビティを計画するステップ、もう1つは屋内アクティビティのみを計画するステップです。 どちらもplanning agentを使用します。 ```ts showLineNumbers copy filename="workflows/conditional-workflow.ts" import { z } from "zod"; import { createWorkflow, createStep } from "@mastra/core/workflows"; // Helper function to convert weather codes to human-readable conditions function getWeatherCondition(code: number): string { const conditions: Record = { 0: "Clear sky", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast", 45: "Foggy", 48: "Depositing rime fog", 51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle", 61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain", 71: "Slight snow fall", 73: "Moderate snow fall", 75: "Heavy snow fall", 95: "Thunderstorm", }; return conditions[code] || "Unknown"; } const forecastSchema = z.object({ date: z.string(), maxTemp: z.number(), minTemp: z.number(), precipitationChance: z.number(), condition: z.string(), location: z.string(), }); ``` ### 指定した都市の天気データを取得するステップ APIコールを行い、現在の天気状況と予報を取得します ```ts showLineNumbers copy filename="workflows/conditional-workflow.ts" const fetchWeather = createStep({ id: "fetch-weather", description: "Fetches weather forecast for a given city", inputSchema: z.object({ city: z.string(), }), outputSchema: forecastSchema, execute: async ({ inputData }) => { if (!inputData) { throw new Error("Trigger data not found"); } const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(inputData.city)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = (await geocodingResponse.json()) as { results: { latitude: number; longitude: number; name: string }[]; }; if (!geocodingData.results?.[0]) { throw new Error(`Location '${inputData.city}' not found`); } const { latitude, longitude, name } = geocodingData.results[0]; const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=precipitation,weathercode&timezone=auto,&hourly=precipitation_probability,temperature_2m`; const response = await fetch(weatherUrl); const data = (await response.json()) as { current: { time: string; precipitation: number; weathercode: number; }; hourly: { precipitation_probability: number[]; temperature_2m: number[]; }; }; const forecast = { date: new Date().toISOString(), maxTemp: Math.max(...data.hourly.temperature_2m), minTemp: Math.min(...data.hourly.temperature_2m), condition: getWeatherCondition(data.current.weathercode), location: name, precipitationChance: data.hourly.precipitation_probability.reduce( (acc, curr) => Math.max(acc, curr), 0, ), }; return forecast; }, }); ``` ### 天気状況に基づいてアクティビティを計画するステップ planning agentを使ってアクティビティのおすすめを生成します ```ts showLineNumbers copy filename="workflows/conditional-workflow.ts" const planActivities = createStep({ id: "plan-activities", description: "Suggests activities based on weather conditions", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `Based on the following weather forecast for ${forecast.location}, suggest appropriate activities: ${JSON.stringify(forecast, null, 2)} `; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); ``` ### Step to plan indoor activities only Used when precipitation chance is high ```ts showLineNumbers copy filename="workflows/conditional-workflow.ts" const planIndoorActivities = createStep({ id: "plan-indoor-activities", description: "Suggests indoor activities based on weather conditions", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `In case it rains, plan indoor activities for ${forecast.location} on ${forecast.date}`; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); ``` ### Main workflow ```ts showLineNumbers copy filename="workflows/conditional-workflow.ts" const activityPlanningWorkflow = createWorkflow({ id: "activity-planning-workflow-step2-if-else", inputSchema: z.object({ city: z.string().describe("The city to get the weather for"), }), outputSchema: z.object({ activities: z.string(), }), }) .then(fetchWeather) .branch([ // Branch for high precipitation (indoor activities) [ async ({ inputData }) => { return inputData?.precipitationChance > 50; }, planIndoorActivities, ], // Branch for low precipitation (outdoor activities) [ async ({ inputData }) => { return inputData?.precipitationChance <= 50; }, planActivities, ], ]); activityPlanningWorkflow.commit(); export { activityPlanningWorkflow }; ``` ## Mastra クラスで Agent と Workflow インスタンスを登録する agent と workflow を mastra インスタンスに登録します。 これは、workflow 内で agent へのアクセスを可能にするために重要です。 ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { createLogger } from "@mastra/core/logger"; import { activityPlanningWorkflow } from "./workflows/conditional-workflow"; import { planningAgent } from "./agents/planning-agent"; // Initialize Mastra with the activity planning workflow // This enables the workflow to be executed and access the planning agent const mastra = new Mastra({ workflows: { activityPlanningWorkflow, }, agents: { planningAgent, }, logger: createLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## アクティビティ計画ワークフローを実行する ここでは、mastra インスタンスからアクティビティ計画ワークフローを取得し、実行を作成して、必要な inputData を使ってその実行を開始します。 ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; const workflow = mastra.getWorkflow("activityPlanningWorkflow"); const run = workflow.createRun(); // Start the workflow with a city // This will fetch weather and plan activities based on conditions const result = await run.start({ inputData: { city: "New York" } }); console.dir(result, { depth: null }); ``` --- title: "例: 制御フロー | ワークフロー | Mastra ドキュメント" description: 指定された条件に基づいてループを含むワークフローを Mastra で作成する例。 --- # ステップ実行のループ処理 [JA] Source: https://mastra.ai/ja/examples/workflows/control-flow ## セットアップ ```sh copy npm install @ai-sdk/openai @mastra/core ``` ## ループワークフローの定義 指定された条件が満たされるまで、ネストされたワークフローを実行するワークフローを定義します。 ```ts showLineNumbers copy filename="looping-workflow.ts" import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; // Step that increments the input value by 1 const incrementStep = createStep({ id: "increment", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), execute: async ({ inputData }) => { return { value: inputData.value + 1 }; }, }); // Step that logs the current value (side effect) const sideEffectStep = createStep({ id: "side-effect", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), execute: async ({ inputData }) => { console.log("log", inputData.value); return { value: inputData.value }; }, }); // Final step that returns the final value const finalStep = createStep({ id: "final", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), execute: async ({ inputData }) => { return { value: inputData.value }; }, }); // Create a workflow that: // 1. Increments a number until it reaches 10 // 2. Logs each increment (side effect) // 3. Returns the final value const workflow = createWorkflow({ id: "increment-workflow", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), }) .dountil( // Nested workflow that performs the increment and logging createWorkflow({ id: "increment-workflow", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), steps: [incrementStep, sideEffectStep], }) .then(incrementStep) .then(sideEffectStep) .commit(), // Condition to check if we should stop the loop async ({ inputData }) => inputData.value >= 10, ) .then(finalStep); workflow.commit(); export { workflow as incrementWorkflow }; ``` ## MastraクラスでWorkflowインスタンスを登録する ワークフローをmastraインスタンスに登録します。 ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { PinoLogger } from "@mastra/loggers"; import { incrementWorkflow } from "./workflows"; // Initialize Mastra with the increment workflow // This enables the workflow to be executed const mastra = new Mastra({ workflows: { incrementWorkflow, }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## ワークフローの実行 ここでは、mastra インスタンスから increment ワークフローを取得し、実行を作成して、必要な inputData を使ってその実行を開始します。 ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; const workflow = mastra.getWorkflow("incrementWorkflow"); const run = workflow.createRun(); // Start the workflow with initial value 0 // This will increment until reaching 10 const result = await run.start({ inputData: { value: 0 } }); console.dir(result, { depth: null }); ``` --- title: "例:ワークフローの作成 | ワークフロー | Mastra ドキュメント" description: Mastraを使用して単一ステップの簡単なワークフローを定義し実行する例。 --- import { GithubLink } from "@/components/github-link"; # シンプルなワークフローの作成 [JA] Source: https://mastra.ai/ja/examples/workflows/creating-a-workflow ワークフローは、構造化されたパスで操作のシーケンスを定義し実行することを可能にします。この例では、単一のステップを持つワークフローを示します。 ```ts showLineNumbers copy import { Step, Workflow } from "@mastra/core/workflows"; import { z } from "zod"; const myWorkflow = new Workflow({ name: "my-workflow", triggerSchema: z.object({ input: z.number(), }), }); const stepOne = new Step({ id: "stepOne", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ doubledValue: z.number(), }), execute: async ({ context }) => { const doubledValue = context?.triggerData?.input * 2; return { doubledValue }; }, }); myWorkflow.step(stepOne).commit(); const { runId, start } = myWorkflow.createRun(); const res = await start({ triggerData: { input: 90 }, }); console.log(res.results); ```




--- title: "例: 循環依存関係 | ワークフロー | Mastra ドキュメント" description: Mastra を使用して循環依存関係や条件付きループを持つワークフローを作成する例。 --- import { GithubLink } from "@/components/github-link"; # 循環依存関係を持つワークフロー [JA] Source: https://mastra.ai/ja/examples/workflows/cyclical-dependencies ワークフローは、条件に基づいてステップがループバックできる循環依存関係をサポートしています。以下の例では、条件付きロジックを使ってループを作成し、繰り返し実行を処理する方法を示しています。 ```ts showLineNumbers copy import { Workflow, Step } from "@mastra/core"; import { z } from "zod"; async function main() { const doubleValue = new Step({ id: "doubleValue", description: "Doubles the input value", inputSchema: z.object({ inputValue: z.number(), }), outputSchema: z.object({ doubledValue: z.number(), }), execute: async ({ context }) => { const doubledValue = context.inputValue * 2; return { doubledValue }; }, }); const incrementByOne = new Step({ id: "incrementByOne", description: "Adds 1 to the input value", outputSchema: z.object({ incrementedValue: z.number(), }), execute: async ({ context }) => { const valueToIncrement = context?.getStepResult<{ firstValue: number }>( "trigger", )?.firstValue; if (!valueToIncrement) throw new Error("No value to increment provided"); const incrementedValue = valueToIncrement + 1; return { incrementedValue }; }, }); const cyclicalWorkflow = new Workflow({ name: "cyclical-workflow", triggerSchema: z.object({ firstValue: z.number(), }), }); cyclicalWorkflow .step(doubleValue, { variables: { inputValue: { step: "trigger", path: "firstValue", }, }, }) .then(incrementByOne) .after(doubleValue) .step(doubleValue, { variables: { inputValue: { step: doubleValue, path: "doubledValue", }, }, }) .commit(); const { runId, start } = cyclicalWorkflow.createRun(); console.log("Run", runId); const res = await start({ triggerData: { firstValue: 6 } }); console.log(res.results); } main(); ```




--- title: "例: Human in the Loop | ワークフロー | Mastra ドキュメント" description: Mastra を使って人間の介入ポイントを含むワークフローを作成する例。 --- # ヒューマン・イン・ザ・ループ ワークフロー [JA] Source: https://mastra.ai/ja/examples/workflows/human-in-the-loop ヒューマン・イン・ザ・ループのワークフローでは、特定のポイントで実行を一時停止し、ユーザーからの入力を収集したり、意思決定を行ったり、人間の判断が必要なアクションを実行したりすることができます。 この例では、人間による介入ポイントを含むワークフローの作成方法を示します。 ## セットアップ ```sh copy npm install @ai-sdk/openai @mastra/core @inquirer/prompts ``` ## エージェントの定義 旅行エージェントを定義します。 ```ts showLineNumbers copy filename="agents/travel-agents.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const llm = openai("gpt-4o"); // Agent that generates multiple holiday options // Returns a JSON array of locations and descriptions export const summaryTravelAgent = new Agent({ name: "summaryTravelAgent", model: llm, instructions: ` You are a travel agent who is given a user prompt about what kind of holiday they want to go on. You then generate 3 different options for the holiday. Return the suggestions as a JSON array {"location": "string", "description": "string"}[]. Don't format as markdown. Make the options as different as possible from each other. Also make the plan very short and summarized. `, }); // Agent that creates detailed travel plans // Takes the selected option and generates a comprehensive itinerary export const travelAgent = new Agent({ name: "travelAgent", model: llm, instructions: ` You are a travel agent who is given a user prompt about what kind of holiday they want to go on. A summary of the plan is provided as well as the location. You then generate a detailed travel plan for the holiday. `, }); ``` ## サスペンド可能なワークフローの定義 `suspend` ステップである `humanInputStep` を含むワークフローを定義します。 ```ts showLineNumbers copy filename="workflows/human-in-the-loop-workflow.ts" import { createWorkflow, createStep } from "@mastra/core/workflows"; import { z } from "zod"; // Step that generates multiple holiday options based on user's vacation description // Uses the summaryTravelAgent to create diverse travel suggestions const generateSuggestionsStep = createStep({ id: "generate-suggestions", inputSchema: z.object({ vacationDescription: z.string().describe("The description of the vacation"), }), outputSchema: z.object({ suggestions: z.array(z.string()), vacationDescription: z.string(), }), execute: async ({ inputData, mastra }) => { if (!mastra) { throw new Error("Mastra is not initialized"); } const { vacationDescription } = inputData; const result = await mastra.getAgent("summaryTravelAgent").generate([ { role: "user", content: vacationDescription, }, ]); console.log(result.text); return { suggestions: JSON.parse(result.text), vacationDescription }; }, }); // Step that pauses the workflow to get user input // Allows the user to select their preferred holiday option from the suggestions // Uses suspend/resume mechanism to handle the interaction const humanInputStep = createStep({ id: "human-input", inputSchema: z.object({ suggestions: z.array(z.string()), vacationDescription: z.string(), }), outputSchema: z.object({ selection: z.string().describe("The selection of the user"), vacationDescription: z.string(), }), resumeSchema: z.object({ selection: z.string().describe("The selection of the user"), }), suspendSchema: z.object({ suggestions: z.array(z.string()), }), execute: async ({ inputData, resumeData, suspend, getInitData }) => { if (!resumeData?.selection) { await suspend({ suggestions: inputData?.suggestions }); return { selection: "", vacationDescription: inputData?.vacationDescription, }; } return { selection: resumeData?.selection, vacationDescription: inputData?.vacationDescription, }; }, }); // Step that creates a detailed travel plan based on the user's selection // Uses the travelAgent to generate comprehensive holiday details const travelPlannerStep = createStep({ id: "travel-planner", inputSchema: z.object({ selection: z.string().describe("The selection of the user"), vacationDescription: z.string(), }), outputSchema: z.object({ travelPlan: z.string(), }), execute: async ({ inputData, mastra }) => { const travelAgent = mastra?.getAgent("travelAgent"); if (!travelAgent) { throw new Error("Travel agent is not initialized"); } const { selection, vacationDescription } = inputData; const result = await travelAgent.generate([ { role: "assistant", content: vacationDescription }, { role: "user", content: selection || "" }, ]); console.log(result.text); return { travelPlan: result.text }; }, }); // Main workflow that orchestrates the holiday planning process: // 1. Generates multiple options // 2. Gets user input // 3. Creates detailed plan const travelAgentWorkflow = createWorkflow({ id: "travel-agent-workflow", inputSchema: z.object({ vacationDescription: z.string().describe("The description of the vacation"), }), outputSchema: z.object({ travelPlan: z.string(), }), }) .then(generateSuggestionsStep) .then(humanInputStep) .then(travelPlannerStep); travelAgentWorkflow.commit(); export { travelAgentWorkflow, humanInputStep }; ``` ## Mastra クラスでエージェントとワークフローのインスタンスを登録する エージェントと天気ワークフローを mastra インスタンスに登録します。 これは、ワークフロー内でエージェントへアクセスできるようにするために重要です。 ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { createLogger } from "@mastra/core/logger"; import { travelAgentWorkflow } from "./workflows/human-in-the-loop-workflow"; import { summaryTravelAgent, travelAgent } from "./agents/travel-agent"; // Initialize Mastra instance with: // - The travel planning workflow // - Both travel agents (summary and detailed planning) // - Logging configuration const mastra = new Mastra({ workflows: { travelAgentWorkflow, }, agents: { travelAgent, summaryTravelAgent, }, logger: createLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## サスペンド可能な天気ワークフローの実行 ここでは、mastra インスタンスから天気ワークフローを取得し、run を作成して必要な inputData で作成した run を実行します。 さらに、readline パッケージを使ってユーザー入力を収集した後、`humanInputStep` を再開します。 ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; import { select } from "@inquirer/prompts"; import { humanInputStep } from "./workflows/human-in-the-loop-workflow"; const workflow = mastra.getWorkflow("travelAgentWorkflow"); const run = workflow.createRun({}); // Start the workflow with initial vacation description const result = await run.start({ inputData: { vacationDescription: "I want to go to the beach" }, }); console.log("result", result); const suggStep = result?.steps?.["generate-suggestions"]; // If suggestions were generated successfully, proceed with user interaction if (suggStep.status === "success") { const suggestions = suggStep.output?.suggestions; // Present options to user and get their selection const userInput = await select({ message: "Choose your holiday destination", choices: suggestions.map( ({ location, description }: { location: string; description: string }) => `- ${location}: ${description}`, ), }); console.log("Selected:", userInput); // Prepare to resume the workflow with user's selection console.log("resuming from", result, "with", { inputData: { selection: userInput, vacationDescription: "I want to go to the beach", suggestions: suggStep?.output?.suggestions, }, step: humanInputStep, }); const result2 = await run.resume({ resumeData: { selection: userInput, }, step: humanInputStep, }); console.dir(result2, { depth: null }); } ``` Human-in-the-loop ワークフローは、自動化と人間の判断を組み合わせたシステムの構築に強力です。例えば、以下のような用途があります: - コンテンツモデレーションシステム - 承認ワークフロー - 監督付き AI システム - エスカレーションを伴うカスタマーサービス自動化 --- title: "Inngest ワークフロー | ワークフロー | Mastra ドキュメント" description: Mastra で inngest ワークフローを構築する例 --- # Inngest Workflow [JA] Source: https://mastra.ai/ja/examples/workflows/inngest-workflow この例では、Mastra を使って Inngest ワークフローを構築する方法を示します。 ## セットアップ ```sh copy npm install @mastra/inngest inngest @mastra/core @mastra/deployer @hono/node-server @ai-sdk/openai docker run --rm -p 8288:8288 \ inngest/inngest \ inngest dev -u http://host.docker.internal:3000/inngest/api ``` または、公式の[Inngest Dev Serverガイド](https://www.inngest.com/docs/dev-server)に従って、ローカル開発にInngest CLIを使用することもできます。 ## プランニングエージェントの定義 場所と対応する気象条件に基づいてアクティビティを計画するためにLLM呼び出しを活用するプランニングエージェントを定義します。 ```ts showLineNumbers copy filename="agents/planning-agent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // Create a new planning agent that uses the OpenAI model const planningAgent = new Agent({ name: "planningAgent", model: openai("gpt-4o"), instructions: ` You are a local activities and travel expert who excels at weather-based planning. Analyze the weather data and provide practical activity recommendations. 📅 [Day, Month Date, Year] ═══════════════════════════ 🌡️ WEATHER SUMMARY • Conditions: [brief description] • Temperature: [X°C/Y°F to A°C/B°F] • Precipitation: [X% chance] 🌅 MORNING ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🌞 AFTERNOON ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🏠 INDOOR ALTERNATIVES • [Activity Name] - [Brief description including specific venue] Ideal for: [weather condition that would trigger this alternative] ⚠️ SPECIAL CONSIDERATIONS • [Any relevant weather warnings, UV index, wind conditions, etc.] Guidelines: - Suggest 2-3 time-specific outdoor activities per day - Include 1-2 indoor backup options - For precipitation >50%, lead with indoor activities - All activities must be specific to the location - Include specific venues, trails, or locations - Consider activity intensity based on temperature - Keep descriptions concise but informative Maintain this exact formatting for consistency, using the emoji and section headers as shown. `, }); export { planningAgent }; ``` ## Activity Planner Workflowの定義 3つのステップでactivity planner workflowを定義します:ネットワーク呼び出しで天気を取得するステップ、アクティビティを計画するステップ、そして屋内アクティビティのみを計画するステップです。 ```ts showLineNumbers copy filename="workflows/inngest-workflow.ts" import { init } from "@mastra/inngest"; import { Inngest } from "inngest"; import { z } from "zod"; const { createWorkflow, createStep } = init( new Inngest({ id: "mastra", baseUrl: `http://localhost:8288`, }), ); // Helper function to convert weather codes to human-readable descriptions function getWeatherCondition(code: number): string { const conditions: Record = { 0: "Clear sky", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast", 45: "Foggy", 48: "Depositing rime fog", 51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle", 61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain", 71: "Slight snow fall", 73: "Moderate snow fall", 75: "Heavy snow fall", 95: "Thunderstorm", }; return conditions[code] || "Unknown"; } const forecastSchema = z.object({ date: z.string(), maxTemp: z.number(), minTemp: z.number(), precipitationChance: z.number(), condition: z.string(), location: z.string(), }); ``` #### ステップ1:指定された都市の天気データを取得 ```ts showLineNumbers copy filename="workflows/inngest-workflow.ts" const fetchWeather = createStep({ id: "fetch-weather", description: "Fetches weather forecast for a given city", inputSchema: z.object({ city: z.string(), }), outputSchema: forecastSchema, execute: async ({ inputData }) => { if (!inputData) { throw new Error("Trigger data not found"); } // Get latitude and longitude for the city const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(inputData.city)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = (await geocodingResponse.json()) as { results: { latitude: number; longitude: number; name: string }[]; }; if (!geocodingData.results?.[0]) { throw new Error(`Location '${inputData.city}' not found`); } const { latitude, longitude, name } = geocodingData.results[0]; // Fetch weather data using the coordinates const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=precipitation,weathercode&timezone=auto,&hourly=precipitation_probability,temperature_2m`; const response = await fetch(weatherUrl); const data = (await response.json()) as { current: { time: string; precipitation: number; weathercode: number; }; hourly: { precipitation_probability: number[]; temperature_2m: number[]; }; }; const forecast = { date: new Date().toISOString(), maxTemp: Math.max(...data.hourly.temperature_2m), minTemp: Math.min(...data.hourly.temperature_2m), condition: getWeatherCondition(data.current.weathercode), location: name, precipitationChance: data.hourly.precipitation_probability.reduce( (acc, curr) => Math.max(acc, curr), 0, ), }; return forecast; }, }); ``` #### ステップ2:天気に基づいてアクティビティ(屋内または屋外)を提案 ```ts showLineNumbers copy filename="workflows/inngest-workflow.ts" const planActivities = createStep({ id: "plan-activities", description: "Suggests activities based on weather conditions", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `Based on the following weather forecast for ${forecast.location}, suggest appropriate activities: ${JSON.stringify(forecast, null, 2)} `; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); ``` #### ステップ 3: 屋内アクティビティのみを提案する(雨天の場合) ```ts showLineNumbers copy filename="workflows/inngest-workflow.ts" const planIndoorActivities = createStep({ id: "plan-indoor-activities", description: "Suggests indoor activities based on weather conditions", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `In case it rains, plan indoor activities for ${forecast.location} on ${forecast.date}`; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); ``` ## アクティビティプランナーのワークフローを定義する ```ts showLineNumbers copy filename="workflows/inngest-workflow.ts" const activityPlanningWorkflow = createWorkflow({ id: "activity-planning-workflow-step2-if-else", inputSchema: z.object({ city: z.string().describe("The city to get the weather for"), }), outputSchema: z.object({ activities: z.string(), }), }) .then(fetchWeather) .branch([ [ // If precipitation chance is greater than 50%, suggest indoor activities async ({ inputData }) => { return inputData?.precipitationChance > 50; }, planIndoorActivities, ], [ // Otherwise, suggest a mix of activities async ({ inputData }) => { return inputData?.precipitationChance <= 50; }, planActivities, ], ]); activityPlanningWorkflow.commit(); export { activityPlanningWorkflow }; ``` ## MastraクラスでAgentとWorkflowインスタンスを登録する エージェントとワークフローをmastraインスタンスに登録します。これにより、ワークフロー内でエージェントにアクセスできるようになります。 ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { serve as inngestServe } from "@mastra/inngest"; import { PinoLogger } from "@mastra/loggers"; import { Inngest } from "inngest"; import { activityPlanningWorkflow } from "./workflows/inngest-workflow"; import { planningAgent } from "./agents/planning-agent"; import { realtimeMiddleware } from "@inngest/realtime"; // Create an Inngest instance for workflow orchestration and event handling const inngest = new Inngest({ id: "mastra", baseUrl: `http://localhost:8288`, // URL of your local Inngest server isDev: true, middleware: [realtimeMiddleware()], // Enable real-time updates in the Inngest dashboard }); // Create and configure the main Mastra instance export const mastra = new Mastra({ workflows: { activityPlanningWorkflow, }, agents: { planningAgent, }, server: { host: "0.0.0.0", apiRoutes: [ { path: "/api/inngest", // API endpoint for Inngest to send events to method: "ALL", createHandler: async ({ mastra }) => inngestServe({ mastra, inngest }), }, ], }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); ``` ## アクティビティプランナーワークフローの実行 ここでは、mastra インスタンスからアクティビティプランナーワークフローを取得し、実行を作成して、必要な inputData を使って作成した実行を実行します。 ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; import { serve } from "@hono/node-server"; import { createHonoServer } from "@mastra/deployer/server"; const app = await createHonoServer(mastra); // Start the server on port 3000 so Inngest can send events to it const srv = serve({ fetch: app.fetch, port: 3000, }); const workflow = mastra.getWorkflow("activityPlanningWorkflow"); const run = workflow.createRun({}); // Start the workflow with the required input data (city name) // This will trigger the workflow steps and stream the result to the console const result = await run.start({ inputData: { city: "New York" } }); console.dir(result, { depth: null }); // Close the server after the workflow run is complete srv.close(); ``` ワークフローを実行した後、[http://localhost:8288](http://localhost:8288) の Inngest ダッシュボードで、ワークフローの実行状況をリアルタイムで確認・監視できます。 --- title: "例: 並列実行 | ワークフロー | Mastra ドキュメント" description: ワークフロー内で複数の独立したタスクを並列に実行するために Mastra を使用する例。 --- # ステップによる並列実行 [JA] Source: https://mastra.ai/ja/examples/workflows/parallel-steps AIアプリケーションを構築する際、効率を高めるために複数の独立したタスクを同時に処理する必要がよくあります。 この機能をワークフローの中核として、`.parallel` メソッドを通じて提供しています。 ## セットアップ ```sh copy npm install @ai-sdk/openai @mastra/core ``` ## プランニングエージェントの定義 場所とそれに対応する天候条件が与えられた場合に、LLMコールを活用してアクティビティを計画するプランニングエージェントを定義します。 ```ts showLineNumbers copy filename="agents/planning-agent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const llm = openai("gpt-4o"); // Define the planning agent with specific instructions for formatting // and structuring weather-based activity recommendations const planningAgent = new Agent({ name: "planningAgent", model: llm, instructions: ` You are a local activities and travel expert who excels at weather-based planning. Analyze the weather data and provide practical activity recommendations. 📅 [Day, Month Date, Year] ═══════════════════════════ 🌡️ WEATHER SUMMARY • Conditions: [brief description] • Temperature: [X°C/Y°F to A°C/B°F] • Precipitation: [X% chance] 🌅 MORNING ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🌞 AFTERNOON ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🏠 INDOOR ALTERNATIVES • [Activity Name] - [Brief description including specific venue] Ideal for: [weather condition that would trigger this alternative] ⚠️ SPECIAL CONSIDERATIONS • [Any relevant weather warnings, UV index, wind conditions, etc.] Guidelines: - Suggest 2-3 time-specific outdoor activities per day - Include 1-2 indoor backup options - For precipitation >50%, lead with indoor activities - All activities must be specific to the location - Include specific venues, trails, or locations - Consider activity intensity based on temperature - Keep descriptions concise but informative Maintain this exact formatting for consistency, using the emoji and section headers as shown. `, }); export { planningAgent }; ``` ## Synthesize Agent の定義 屋内および屋外のアクティビティ計画を受け取り、その日の全体的なレポートを提供する synthesize agent を定義します。 ```ts showLineNumbers copy filename="agents/synthesize-agent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const llm = openai("gpt-4o"); // Define the synthesize agent that combines indoor and outdoor activity plans // into a comprehensive report, considering weather conditions and alternatives const synthesizeAgent = new Agent({ name: "synthesizeAgent", model: llm, instructions: ` You are given two different blocks of text, one about indoor activities and one about outdoor activities. Make this into a full report about the day and the possibilities depending on whether it rains or not. `, }); export { synthesizeAgent }; ``` ## 並列ワークフローの定義 ここでは、計画ステップと合成ステップの間で並列から順次へのフローをオーケストレーションするワークフローを定義します。 ```ts showLineNumbers copy filename="workflows/parallel-workflow.ts" import { z } from "zod"; import { createStep, createWorkflow } from "@mastra/core/workflows"; const forecastSchema = z.object({ date: z.string(), maxTemp: z.number(), minTemp: z.number(), precipitationChance: z.number(), condition: z.string(), location: z.string(), }); // Step to fetch weather data for a given city // Makes API calls to get current weather conditions and forecast const fetchWeather = createStep({ id: "fetch-weather", description: "Fetches weather forecast for a given city", inputSchema: z.object({ city: z.string(), }), outputSchema: forecastSchema, execute: async ({ inputData }) => { if (!inputData) { throw new Error("Trigger data not found"); } const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(inputData.city)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = (await geocodingResponse.json()) as { results: { latitude: number; longitude: number; name: string }[]; }; if (!geocodingData.results?.[0]) { throw new Error(`Location '${inputData.city}' not found`); } const { latitude, longitude, name } = geocodingData.results[0]; const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=precipitation,weathercode&timezone=auto,&hourly=precipitation_probability,temperature_2m`; const response = await fetch(weatherUrl); const data = (await response.json()) as { current: { time: string; precipitation: number; weathercode: number; }; hourly: { precipitation_probability: number[]; temperature_2m: number[]; }; }; const forecast = { date: new Date().toISOString(), maxTemp: Math.max(...data.hourly.temperature_2m), minTemp: Math.min(...data.hourly.temperature_2m), condition: getWeatherCondition(data.current.weathercode), location: name, precipitationChance: data.hourly.precipitation_probability.reduce( (acc, curr) => Math.max(acc, curr), 0, ), }; return forecast; }, }); ``` ### 天候条件に基づいて屋外アクティビティを計画するステップ 計画エージェントを使用してアクティビティの提案を生成します ```ts showLineNumbers copy filename="workflows/parallel-workflow.ts" const planActivities = createStep({ id: "plan-activities", description: "Suggests activities based on weather conditions", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `Based on the following weather forecast for ${forecast.location}, suggest appropriate activities: ${JSON.stringify(forecast, null, 2)} `; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); ``` ### 天気コードを人間が読める条件に変換するヘルパー関数 天気APIからの数値コードを説明的な文字列にマッピングします ```ts showLineNumbers copy filename="workflows/parallel-workflow.ts" function getWeatherCondition(code: number): string { const conditions: Record = { 0: "Clear sky", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast", 45: "Foggy", 48: "Depositing rime fog", 51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle", 61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain", 71: "Slight snow fall", 73: "Moderate snow fall", 75: "Heavy snow fall", 95: "Thunderstorm", }; return conditions[code] || "Unknown"; } // Step to plan indoor activities as backup options // Generates alternative indoor activities in case of bad weather const planIndoorActivities = createStep({ id: "plan-indoor-activities", description: "Suggests indoor activities based on weather conditions", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `In case it rains, plan indoor activities for ${forecast.location} on ${forecast.date}`; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { activitiesText += chunk; } return { activities: activitiesText, }; }, }); ``` ### 屋内・屋外アクティビティ計画を統合・合成するステップ 両方の選択肢を考慮した包括的な計画を作成します ```ts showLineNumbers copy filename="workflows/parallel-workflow.ts" const synthesizeStep = createStep({ id: "sythesize-step", description: "Synthesizes the results of the indoor and outdoor activities", inputSchema: z.object({ "plan-activities": z.object({ activities: z.string(), }), "plan-indoor-activities": z.object({ activities: z.string(), }), }), outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const indoorActivities = inputData?.["plan-indoor-activities"]; const outdoorActivities = inputData?.["plan-activities"]; const prompt = `Indoor activities: ${indoorActivities?.activities} Outdoor activities: ${outdoorActivities?.activities} There is a chance of rain so be prepared to do indoor activities if needed.`; const agent = mastra?.getAgent("synthesizeAgent"); if (!agent) { throw new Error("Synthesize agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); ``` ### メインワークフロー ```ts showLineNumbers copy filename="workflows/parallel-workflow.ts" const activityPlanningWorkflow = createWorkflow({ id: "plan-both-workflow", inputSchema: z.object({ city: z.string(), }), outputSchema: z.object({ activities: z.string(), }), steps: [fetchWeather, planActivities, planIndoorActivities, synthesizeStep], }) .then(fetchWeather) .parallel([planActivities, planIndoorActivities]) .then(synthesizeStep) .commit(); export { activityPlanningWorkflow }; ``` ## MastraクラスでAgentとWorkflowインスタンスを登録する エージェントとワークフローをmastraインスタンスに登録します。 これは、ワークフロー内でエージェントへのアクセスを可能にするために重要です。 ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { createLogger } from "@mastra/core/logger"; import { activityPlanningWorkflow } from "./workflows/parallel-workflow"; import { planningAgent } from "./agents/planning-agent"; import { synthesizeAgent } from "./agents/synthesize-agent"; // Initialize Mastra with required agents and workflows // This setup enables agent access within the workflow steps const mastra = new Mastra({ workflows: { activityPlanningWorkflow, }, agents: { planningAgent, synthesizeAgent, }, logger: createLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## アクティビティ計画ワークフローを実行する ここでは、mastra インスタンスから天気ワークフローを取得し、実行を作成して、必要な inputData を使ってその実行を開始します。 ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; const workflow = mastra.getWorkflow("activityPlanningWorkflow"); const run = workflow.createRun(); // Execute the workflow with a specific city // This will run through all steps and generate activity recommendations const result = await run.start({ inputData: { city: "Ibiza" } }); console.dir(result, { depth: null }); ``` --- title: "例:順次ステップ | ワークフロー | Mastra ドキュメント" description: Mastra を使用してワークフローステップを特定の順序で連結し、データを受け渡す例。 --- import { GithubLink } from "@/components/github-link"; # 順次ステップによるワークフロー [JA] Source: https://mastra.ai/ja/examples/workflows/sequential-steps ワークフローは、特定の順序で次々と連鎖して実行することができます。 ## 制御フローダイアグラム この例では、`then` メソッドを使ってワークフローのステップを連結し、順番に実行しながらデータを受け渡す方法を示しています。 制御フローダイアグラムは以下の通りです: 順次ステップを持つワークフローのダイアグラム ## ステップの作成 まず、ステップを作成し、ワークフローを初期化しましょう。 ```ts showLineNumbers copy import { Step, Workflow } from "@mastra/core/workflows"; import { z } from "zod"; const stepOne = new Step({ id: "stepOne", execute: async ({ context }) => ({ doubledValue: context.triggerData.inputValue * 2, }), }); const stepTwo = new Step({ id: "stepTwo", execute: async ({ context }) => { if (context.steps.stepOne.status !== "success") { return { incrementedValue: 0 }; } return { incrementedValue: context.steps.stepOne.output.doubledValue + 1 }; }, }); const stepThree = new Step({ id: "stepThree", execute: async ({ context }) => { if (context.steps.stepTwo.status !== "success") { return { tripledValue: 0 }; } return { tripledValue: context.steps.stepTwo.output.incrementedValue * 3 }; }, }); // Build the workflow const myWorkflow = new Workflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); ``` ## ステップを連結してワークフローを実行する それでは、ステップを順番につなげてみましょう。 ```ts showLineNumbers copy // sequential steps myWorkflow.step(stepOne).then(stepTwo).then(stepThree); myWorkflow.commit(); const { start } = myWorkflow.createRun(); const res = await start({ triggerData: { inputValue: 90 } }); ```




--- title: "例: 一時停止と再開 | ワークフロー | Mastra ドキュメント" description: 実行中にワークフローのステップを一時停止および再開するために Mastra を使用する例。 --- import { GithubLink } from "@/components/github-link"; # サスペンドとレジュームを使ったワークフロー [JA] Source: https://mastra.ai/ja/examples/workflows/suspend-and-resume ワークフローの各ステップは、ワークフローの実行中いつでもサスペンドおよびレジュームすることができます。この例では、ワークフローステップをサスペンドし、後で再開する方法を示します。 ## 基本例 ```ts showLineNumbers copy import { Mastra } from "@mastra/core"; import { Step, Workflow } from "@mastra/core/workflows"; import { z } from "zod"; const stepOne = new Step({ id: "stepOne", outputSchema: z.object({ doubledValue: z.number(), }), execute: async ({ context }) => { const doubledValue = context.triggerData.inputValue * 2; return { doubledValue }; }, }); ``` ```ts showLineNumbers copy const stepTwo = new Step({ id: "stepTwo", outputSchema: z.object({ incrementedValue: z.number(), }), execute: async ({ context, suspend }) => { const secondValue = context.inputData?.secondValue ?? 0; const doubledValue = context.getStepResult(stepOne)?.doubledValue ?? 0; const incrementedValue = doubledValue + secondValue; if (incrementedValue < 100) { await suspend(); return { incrementedValue: 0 }; } return { incrementedValue }; }, }); // Build the workflow const myWorkflow = new Workflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); // run workflows in parallel myWorkflow.step(stepOne).then(stepTwo).commit(); ``` ```ts showLineNumbers copy // Register the workflow export const mastra = new Mastra({ workflows: { registeredWorkflow: myWorkflow }, }); // Get registered workflow from Mastra const registeredWorkflow = mastra.getWorkflow("registeredWorkflow"); const { runId, start } = registeredWorkflow.createRun(); // Start watching the workflow before executing it myWorkflow.watch(async ({ context, activePaths }) => { for (const _path of activePaths) { const stepTwoStatus = context.steps?.stepTwo?.status; if (stepTwoStatus === "suspended") { console.log("Workflow suspended, resuming with new value"); // Resume the workflow with new context await myWorkflow.resume({ runId, stepId: "stepTwo", context: { secondValue: 100 }, }); } } }); // Start the workflow execution await start({ triggerData: { inputValue: 45 } }); ``` ## async/awaitパターンとsuspendペイロードを用いた複数のサスペンションポイントを持つ高度な例 この例では、async/awaitパターンを使用し、複数のサスペンションポイントを持つより複雑なワークフローを示します。これは、異なる段階で人間の介入が必要となるコンテンツ生成ワークフローをシミュレートしています。 ```ts showLineNumbers copy import { Mastra } from "@mastra/core"; import { Step, Workflow } from "@mastra/core/workflows"; import { z } from "zod"; // Step 1: Get user input const getUserInput = new Step({ id: "getUserInput", execute: async ({ context }) => { // In a real application, this might come from a form or API return { userInput: context.triggerData.input }; }, outputSchema: z.object({ userInput: z.string() }), }); ``` ```ts showLineNumbers copy // Step 2: Generate content with AI (may suspend for human guidance) const promptAgent = new Step({ id: "promptAgent", inputSchema: z.object({ guidance: z.string(), }), execute: async ({ context, suspend }) => { const userInput = context.getStepResult(getUserInput)?.userInput; console.log(`Generating content based on: ${userInput}`); const guidance = context.inputData?.guidance; // Simulate AI generating content const initialDraft = generateInitialDraft(userInput); // If confidence is high, return the generated content directly if (initialDraft.confidenceScore > 0.7) { return { modelOutput: initialDraft.content }; } console.log( "Low confidence in generated content, suspending for human guidance", { guidance }, ); // If confidence is low, suspend for human guidance if (!guidance) { // only suspend if no guidance is provided await suspend(); return undefined; } // This code runs after resume with human guidance console.log("Resumed with human guidance"); // Use the human guidance to improve the output return { modelOutput: enhanceWithGuidance(initialDraft.content, guidance), }; }, outputSchema: z.object({ modelOutput: z.string() }).optional(), }); ``` ```ts showLineNumbers copy // Step 3: Evaluate the content quality const evaluateTone = new Step({ id: "evaluateToneConsistency", execute: async ({ context }) => { const content = context.getStepResult(promptAgent)?.modelOutput; // Simulate evaluation return { toneScore: { score: calculateToneScore(content) }, completenessScore: { score: calculateCompletenessScore(content) }, }; }, outputSchema: z.object({ toneScore: z.any(), completenessScore: z.any(), }), }); ``` ```ts showLineNumbers copy // Step 4: Improve response if needed (may suspend) const improveResponse = new Step({ id: "improveResponse", inputSchema: z.object({ improvedContent: z.string(), resumeAttempts: z.number(), }), execute: async ({ context, suspend }) => { const content = context.getStepResult(promptAgent)?.modelOutput; const toneScore = context.getStepResult(evaluateTone)?.toneScore.score ?? 0; const completenessScore = context.getStepResult(evaluateTone)?.completenessScore.score ?? 0; const improvedContent = context.inputData.improvedContent; const resumeAttempts = context.inputData.resumeAttempts ?? 0; // If scores are above threshold, make minor improvements if (toneScore > 0.8 && completenessScore > 0.8) { return { improvedOutput: makeMinorImprovements(content) }; } console.log( "Content quality below threshold, suspending for human intervention", { improvedContent, resumeAttempts }, ); if (!improvedContent) { // Suspend with payload containing content and resume attempts await suspend({ content, scores: { tone: toneScore, completeness: completenessScore }, needsImprovement: toneScore < 0.8 ? "tone" : "completeness", resumeAttempts: resumeAttempts + 1, }); return { improvedOutput: content ?? "" }; } console.log("Resumed with human improvements", improvedContent); return { improvedOutput: improvedContent ?? content ?? "" }; }, outputSchema: z.object({ improvedOutput: z.string() }).optional(), }); ``` ```ts showLineNumbers copy // Step 5: Final evaluation const evaluateImproved = new Step({ id: "evaluateImprovedResponse", execute: async ({ context }) => { const improvedContent = context.getStepResult(improveResponse)?.improvedOutput; // Simulate final evaluation return { toneScore: { score: calculateToneScore(improvedContent) }, completenessScore: { score: calculateCompletenessScore(improvedContent) }, }; }, outputSchema: z.object({ toneScore: z.any(), completenessScore: z.any(), }), }); // Build the workflow const contentWorkflow = new Workflow({ name: "content-generation-workflow", triggerSchema: z.object({ input: z.string() }), }); contentWorkflow .step(getUserInput) .then(promptAgent) .then(evaluateTone) .then(improveResponse) .then(evaluateImproved) .commit(); ``` ```ts showLineNumbers copy // Register the workflow const mastra = new Mastra({ workflows: { contentWorkflow }, }); // Helper functions (simulated) function generateInitialDraft(input: string = "") { // Simulate AI generating content return { content: `Generated content based on: ${input}`, confidenceScore: 0.6, // Simulate low confidence to trigger suspension }; } function enhanceWithGuidance(content: string = "", guidance: string = "") { return `${content} (Enhanced with guidance: ${guidance})`; } function makeMinorImprovements(content: string = "") { return `${content} (with minor improvements)`; } function calculateToneScore(_: string = "") { return 0.7; // Simulate a score that will trigger suspension } function calculateCompletenessScore(_: string = "") { return 0.9; } // Usage example async function runWorkflow() { const workflow = mastra.getWorkflow("contentWorkflow"); const { runId, start } = workflow.createRun(); let finalResult: any; // Start the workflow const initialResult = await start({ triggerData: { input: "Create content about sustainable energy" }, }); console.log("Initial workflow state:", initialResult.results); const promptAgentStepResult = initialResult.activePaths.get("promptAgent"); // Check if promptAgent step is suspended if (promptAgentStepResult?.status === "suspended") { console.log("Workflow suspended at promptAgent step"); console.log("Suspension payload:", promptAgentStepResult?.suspendPayload); // Resume with human guidance const resumeResult1 = await workflow.resume({ runId, stepId: "promptAgent", context: { guidance: "Focus more on solar and wind energy technologies", }, }); console.log("Workflow resumed and continued to next steps"); let improveResponseResumeAttempts = 0; let improveResponseStatus = resumeResult1?.activePaths.get("improveResponse")?.status; // Check if improveResponse step is suspended while (improveResponseStatus === "suspended") { console.log("Workflow suspended at improveResponse step"); console.log( "Suspension payload:", resumeResult1?.activePaths.get("improveResponse")?.suspendPayload, ); const improvedContent = improveResponseResumeAttempts < 3 ? undefined : "Completely revised content about sustainable energy focusing on solar and wind technologies"; // Resume with human improvements finalResult = await workflow.resume({ runId, stepId: "improveResponse", context: { improvedContent, resumeAttempts: improveResponseResumeAttempts, }, }); improveResponseResumeAttempts = finalResult?.activePaths.get("improveResponse")?.suspendPayload ?.resumeAttempts ?? 0; improveResponseStatus = finalResult?.activePaths.get("improveResponse")?.status; console.log("Improved response result:", finalResult?.results); } } return finalResult; } // Run the workflow const result = await runWorkflow(); console.log("Workflow completed"); console.log("Final workflow result:", result); ```




--- title: "例: ツールをステップとして使用する | ワークフロー | Mastra ドキュメント" description: Mastra を使ってカスタムツールをワークフローのステップとして統合する例。 --- import { GithubLink } from "@/components/github-link"; # ワークフローステップとしてのツール [JA] Source: https://mastra.ai/ja/examples/workflows/using-a-tool-as-a-step この例では、カスタムツールをワークフローステップとして作成し統合する方法を示しています。入力/出力スキーマの定義方法や、ツールの実行ロジックの実装方法について説明します。 ```ts showLineNumbers copy import { createTool } from "@mastra/core/tools"; import { Workflow } from "@mastra/core/workflows"; import { z } from "zod"; const crawlWebpage = createTool({ id: "Crawl Webpage", description: "Crawls a webpage and extracts the text content", inputSchema: z.object({ url: z.string().url(), }), outputSchema: z.object({ rawText: z.string(), }), execute: async ({ context }) => { const response = await fetch(context.triggerData.url); const text = await response.text(); return { rawText: "This is the text content of the webpage: " + text }; }, }); const contentWorkflow = new Workflow({ name: "content-review" }); contentWorkflow.step(crawlWebpage).commit(); const { start } = contentWorkflow.createRun(); const res = await start({ triggerData: { url: "https://example.com" } }); console.log(res.results); ```




--- title: "ワークフローバリアブルによるデータマッピング | Mastra 例" description: "Mastra ワークフローでステップ間のデータをマッピングするためにワークフローバリアブルを使用する方法を学びましょう。" --- # ワークフロー変数によるデータマッピング [JA] Source: https://mastra.ai/ja/examples/workflows/workflow-variables この例では、Mastra ワークフロー内のステップ間でデータをマッピングするためにワークフロー変数を使用する方法を説明します。 ## ユースケース:ユーザー登録プロセス この例では、シンプルなユーザー登録ワークフローを作成します。このワークフローは以下を行います。 1. ユーザー入力の検証 1. ユーザーデータの整形 1. ユーザープロファイルの作成 ## 実装 ```typescript showLineNumbers filename="src/mastra/workflows/user-registration.ts" copy import { Step, Workflow } from "@mastra/core/workflows"; import { z } from "zod"; // Define our schemas for better type safety const userInputSchema = z.object({ email: z.string().email(), name: z.string(), age: z.number().min(18), }); const validatedDataSchema = z.object({ isValid: z.boolean(), validatedData: z.object({ email: z.string(), name: z.string(), age: z.number(), }), }); const formattedDataSchema = z.object({ userId: z.string(), formattedData: z.object({ email: z.string(), displayName: z.string(), ageGroup: z.string(), }), }); const profileSchema = z.object({ profile: z.object({ id: z.string(), email: z.string(), displayName: z.string(), ageGroup: z.string(), createdAt: z.string(), }), }); // Define the workflow const registrationWorkflow = new Workflow({ name: "user-registration", triggerSchema: userInputSchema, }); // Step 1: Validate user input const validateInput = new Step({ id: "validateInput", inputSchema: userInputSchema, outputSchema: validatedDataSchema, execute: async ({ context }) => { const { email, name, age } = context; // Simple validation logic const isValid = email.includes("@") && name.length > 0 && age >= 18; return { isValid, validatedData: { email: email.toLowerCase().trim(), name, age, }, }; }, }); // Step 2: Format user data const formatUserData = new Step({ id: "formatUserData", inputSchema: z.object({ validatedData: z.object({ email: z.string(), name: z.string(), age: z.number(), }), }), outputSchema: formattedDataSchema, execute: async ({ context }) => { const { validatedData } = context; // Generate a simple user ID const userId = `user_${Math.floor(Math.random() * 10000)}`; // Format the data const ageGroup = validatedData.age < 30 ? "young-adult" : "adult"; return { userId, formattedData: { email: validatedData.email, displayName: validatedData.name, ageGroup, }, }; }, }); // Step 3: Create user profile const createUserProfile = new Step({ id: "createUserProfile", inputSchema: z.object({ userId: z.string(), formattedData: z.object({ email: z.string(), displayName: z.string(), ageGroup: z.string(), }), }), outputSchema: profileSchema, execute: async ({ context }) => { const { userId, formattedData } = context; // In a real app, you would save to a database here return { profile: { id: userId, ...formattedData, createdAt: new Date().toISOString(), }, }; }, }); // Build the workflow with variable mappings registrationWorkflow // First step gets data from the trigger .step(validateInput, { variables: { email: { step: "trigger", path: "email" }, name: { step: "trigger", path: "name" }, age: { step: "trigger", path: "age" }, }, }) // Format user data with validated data from previous step .then(formatUserData, { variables: { validatedData: { step: validateInput, path: "validatedData" }, }, when: { ref: { step: validateInput, path: "isValid" }, query: { $eq: true }, }, }) // Create profile with data from the format step .then(createUserProfile, { variables: { userId: { step: formatUserData, path: "userId" }, formattedData: { step: formatUserData, path: "formattedData" }, }, }) .commit(); export default registrationWorkflow; ``` ## この例の使い方 1. 上記のようにファイルを作成します 2. Mastraインスタンスにワークフローを登録します 3. ワークフローを実行します: ```bash curl --location 'http://localhost:4111/api/workflows/user-registration/start-async' \ --header 'Content-Type: application/json' \ --data '{ "email": "user@example.com", "name": "John Doe", "age": 25 }' ``` ## 重要なポイント この例では、ワークフロー変数に関するいくつかの重要な概念を示しています。 1. **データマッピング**: 変数は、あるステップから別のステップへデータをマッピングし、明確なデータフローを作成します。 2. **パスアクセス**: `path` プロパティは、ステップの出力のどの部分を使用するかを指定します。 3. **条件付き実行**: `when` プロパティにより、前のステップの出力に基づいてステップを条件付きで実行できます。 4. **型安全性**: 各ステップは、型安全性を確保するために入力および出力スキーマを定義し、ステップ間で渡されるデータが正しく型付けされていることを保証します。 5. **明示的なデータ依存関係**: 入力スキーマを定義し、変数マッピングを使用することで、ステップ間のデータ依存関係が明示的かつ明確になります。 ワークフロー変数の詳細については、[Workflow Variables ドキュメント](../../docs/workflows/variables.mdx)をご覧ください。 --- title: "例: 分岐パス | ワークフロー(レガシー) | Mastra ドキュメント" description: 中間結果に基づいて分岐パスを持つレガシーワークフローを作成するためのMastraの使用例。 --- import { GithubLink } from "@/components/github-link"; # 分岐パス [JA] Source: https://mastra.ai/ja/examples/workflows_legacy/branching-paths データを処理する際、中間結果に基づいて異なる処理を行う必要がよくあります。この例では、レガシーワークフローを作成し、途中で複数のパスに分岐させる方法を示します。それぞれのパスは、前のステップの出力に基づいて異なる処理を実行します。 ## フロー制御ダイアグラム この例では、レガシーワークフローを作成し、途中で分岐して各パスが前のステップの出力に基づいて異なる処理を実行する方法を示します。 フロー制御ダイアグラムは次のとおりです: 分岐パスを持つワークフローのダイアグラム ## ステップの作成 まず、ステップを作成し、ワークフローを初期化しましょう。 {/* prettier-ignore */} ```ts showLineNumbers copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod" const stepOne = new LegacyStep({ id: "stepOne", execute: async ({ context }) => ({ doubledValue: context.triggerData.inputValue * 2 }) }); const stepTwo = new LegacyStep({ id: "stepTwo", execute: async ({ context }) => { const stepOneResult = context.getStepResult<{ doubledValue: number }>("stepOne"); if (!stepOneResult) { return { isDivisibleByFive: false } } return { isDivisibleByFive: stepOneResult.doubledValue % 5 === 0 } } }); const stepThree = new LegacyStep({ id: "stepThree", execute: async ({ context }) =>{ const stepOneResult = context.getStepResult<{ doubledValue: number }>("stepOne"); if (!stepOneResult) { return { incrementedValue: 0 } } return { incrementedValue: stepOneResult.doubledValue + 1 } } }); const stepFour = new LegacyStep({ id: "stepFour", execute: async ({ context }) => { const stepThreeResult = context.getStepResult<{ incrementedValue: number }>("stepThree"); if (!stepThreeResult) { return { isDivisibleByThree: false } } return { isDivisibleByThree: stepThreeResult.incrementedValue % 3 === 0 } } }); // New step that depends on both branches const finalStep = new LegacyStep({ id: "finalStep", execute: async ({ context }) => { // Get results from both branches using getStepResult const stepTwoResult = context.getStepResult<{ isDivisibleByFive: boolean }>("stepTwo"); const stepFourResult = context.getStepResult<{ isDivisibleByThree: boolean }>("stepFour"); const isDivisibleByFive = stepTwoResult?.isDivisibleByFive || false; const isDivisibleByThree = stepFourResult?.isDivisibleByThree || false; return { summary: `The number ${context.triggerData.inputValue} when doubled ${isDivisibleByFive ? 'is' : 'is not'} divisible by 5, and when doubled and incremented ${isDivisibleByThree ? 'is' : 'is not'} divisible by 3.`, isDivisibleByFive, isDivisibleByThree } } }); // Build the workflow const myWorkflow = new LegacyWorkflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); ``` ## 分岐パスとステップの連結 ここでは、レガシーワークフローを分岐パスで構成し、それらを複合的な `.after([])` 構文でマージしてみましょう。 ```ts showLineNumbers copy // Create two parallel branches myWorkflow // First branch .step(stepOne) .then(stepTwo) // Second branch .after(stepOne) .step(stepThree) .then(stepFour) // Merge both branches using compound after syntax .after([stepTwo, stepFour]) .step(finalStep) .commit(); const { start } = myWorkflow.createRun(); const result = await start({ triggerData: { inputValue: 3 } }); console.log(result.steps.finalStep.output.summary); // Output: "The number 3 when doubled is not divisible by 5, and when doubled and incremented is divisible by 3." ``` ## 高度なブランチとマージ 複数のブランチやマージポイントを使って、より複雑なワークフローを作成できます。 ```ts showLineNumbers copy const complexWorkflow = new LegacyWorkflow({ name: "complex-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); // Create multiple branches with different merge points complexWorkflow // Main step .step(stepOne) // First branch .then(stepTwo) // Second branch .after(stepOne) .step(stepThree) .then(stepFour) // Third branch (another path from stepOne) .after(stepOne) .step( new LegacyStep({ id: "alternativePath", execute: async ({ context }) => { const stepOneResult = context.getStepResult<{ doubledValue: number }>( "stepOne", ); return { result: (stepOneResult?.doubledValue || 0) * 3, }; }, }), ) // Merge first and second branches .after([stepTwo, stepFour]) .step( new LegacyStep({ id: "partialMerge", execute: async ({ context }) => { const stepTwoResult = context.getStepResult<{ isDivisibleByFive: boolean; }>("stepTwo"); const stepFourResult = context.getStepResult<{ isDivisibleByThree: boolean; }>("stepFour"); return { intermediateResult: "Processed first two branches", branchResults: { branch1: stepTwoResult?.isDivisibleByFive, branch2: stepFourResult?.isDivisibleByThree, }, }; }, }), ) // Final merge of all branches .after(["partialMerge", "alternativePath"]) .step( new LegacyStep({ id: "finalMerge", execute: async ({ context }) => { const partialMergeResult = context.getStepResult<{ intermediateResult: string; branchResults: { branch1: boolean; branch2: boolean }; }>("partialMerge"); const alternativePathResult = context.getStepResult<{ result: number }>( "alternativePath", ); return { finalResult: "All branches processed", combinedData: { fromPartialMerge: partialMergeResult?.branchResults, fromAlternativePath: alternativePathResult?.result, }, }; }, }), ) .commit(); ```




` --- title: "例: ワークフローからエージェントを呼び出す(レガシー) | Mastra Docs" description: レガシーワークフローステップ内でMastraを使ってAIエージェントを呼び出す例。 --- import { GithubLink } from "@/components/github-link"; # ワークフローからエージェントを呼び出す(レガシー) [JA] Source: https://mastra.ai/ja/examples/workflows_legacy/calling-agent この例では、メッセージを処理して応答を生成するAIエージェントを呼び出すレガシーワークフローの作成方法と、それをレガシーワークフローステップ内で実行する方法を示します。 ```ts showLineNumbers copy import { openai } from "@ai-sdk/openai"; import { Mastra } from "@mastra/core"; import { Agent } from "@mastra/core/agent"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const penguin = new Agent({ name: "agent skipper", instructions: `You are skipper from penguin of madagascar, reply as that`, model: openai("gpt-4o-mini"), }); const newWorkflow = new LegacyWorkflow({ name: "pass message to the workflow", triggerSchema: z.object({ message: z.string(), }), }); const replyAsSkipper = new LegacyStep({ id: "reply", outputSchema: z.object({ reply: z.string(), }), execute: async ({ context, mastra }) => { const skipper = mastra?.getAgent("penguin"); const res = await skipper?.generate(context?.triggerData?.message); return { reply: res?.text || "" }; }, }); newWorkflow.step(replyAsSkipper); newWorkflow.commit(); const mastra = new Mastra({ agents: { penguin }, legacy_workflows: { newWorkflow }, }); const { runId, start } = await mastra .legacy_getWorkflow("newWorkflow") .createRun(); const runResult = await start({ triggerData: { message: "Give me a run down of the mission to save private" }, }); console.log(runResult.results); ```




--- title: "例:条件分岐(実験的) | ワークフロー(レガシー) | Mastra ドキュメント" description: Mastra を使用して、レガシーワークフローで if/else 文による条件分岐を作成する例。 --- import { GithubLink } from "@/components/github-link"; # Workflow (Legacy) with Conditional Branching (experimental) [JA] Source: https://mastra.ai/ja/examples/workflows_legacy/conditional-branching ワークフローは、条件に応じて異なる経路をたどる必要がある場合がよくあります。この例では、レガシーワークフローで`if`や`else`を使って条件分岐を作成する方法を説明します。 ## 基本的なIf/Elseの例 この例は、数値に基づいて異なる経路をたどるシンプルなレガシーワークフローを示しています。 ```ts showLineNumbers copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Step that provides the initial value const startStep = new LegacyStep({ id: "start", outputSchema: z.object({ value: z.number(), }), execute: async ({ context }) => { // Get the value from the trigger data const value = context.triggerData.inputValue; return { value }; }, }); // Step that handles high values const highValueStep = new LegacyStep({ id: "highValue", outputSchema: z.object({ result: z.string(), }), execute: async ({ context }) => { const value = context.getStepResult<{ value: number }>("start")?.value; return { result: `High value processed: ${value}` }; }, }); // Step that handles low values const lowValueStep = new LegacyStep({ id: "lowValue", outputSchema: z.object({ result: z.string(), }), execute: async ({ context }) => { const value = context.getStepResult<{ value: number }>("start")?.value; return { result: `Low value processed: ${value}` }; }, }); // Final step that summarizes the result const finalStep = new LegacyStep({ id: "final", outputSchema: z.object({ summary: z.string(), }), execute: async ({ context }) => { // Get the result from whichever branch executed const highResult = context.getStepResult<{ result: string }>( "highValue", )?.result; const lowResult = context.getStepResult<{ result: string }>( "lowValue", )?.result; const result = highResult || lowResult; return { summary: `Processing complete: ${result}` }; }, }); // Build the workflow with conditional branching const conditionalWorkflow = new LegacyWorkflow({ name: "conditional-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); conditionalWorkflow .step(startStep) .if(async ({ context }) => { const value = context.getStepResult<{ value: number }>("start")?.value ?? 0; return value >= 10; // Condition: value is 10 or greater }) .then(highValueStep) .then(finalStep) .else() .then(lowValueStep) .then(finalStep) // Both branches converge on the final step .commit(); // Register the workflow const mastra = new Mastra({ legacy_workflows: { conditionalWorkflow }, }); // Example usage async function runWorkflow(inputValue: number) { const workflow = mastra.legacy_getWorkflow("conditionalWorkflow"); const { start } = workflow.createRun(); const result = await start({ triggerData: { inputValue }, }); console.log("Workflow result:", result.results); return result; } // Run with a high value (follows the "if" branch) const result1 = await runWorkflow(15); // Run with a low value (follows the "else" branch) const result2 = await runWorkflow(5); console.log("Result 1:", result1); console.log("Result 2:", result2); ``` ## 参照ベースの条件の使用 比較演算子を使って参照ベースの条件を利用することもできます。 ```ts showLineNumbers copy // Using reference-based conditions instead of functions conditionalWorkflow .step(startStep) .if({ ref: { step: startStep, path: "value" }, query: { $gte: 10 }, // Condition: value is 10 or greater }) .then(highValueStep) .then(finalStep) .else() .then(lowValueStep) .then(finalStep) .commit(); ```




--- title: "例: ワークフローの作成 | ワークフロー(レガシー) | Mastra ドキュメント" description: Mastra を使って、1つのステップからなるシンプルなワークフローを定義し実行する例。 --- import { GithubLink } from "@/components/github-link"; # シンプルなワークフローの作成(レガシー) [JA] Source: https://mastra.ai/ja/examples/workflows_legacy/creating-a-workflow ワークフローを使用すると、一連の操作を構造化された経路で定義し、実行することができます。この例では、1つのステップのみを持つレガシーワークフローを示します。 ```ts showLineNumbers copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const myWorkflow = new LegacyWorkflow({ name: "my-workflow", triggerSchema: z.object({ input: z.number(), }), }); const stepOne = new LegacyStep({ id: "stepOne", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ doubledValue: z.number(), }), execute: async ({ context }) => { const doubledValue = context?.triggerData?.input * 2; return { doubledValue }; }, }); myWorkflow.step(stepOne).commit(); const { runId, start } = myWorkflow.createRun(); const res = await start({ triggerData: { input: 90 }, }); console.log(res.results); ```




--- title: "例: 循環依存関係 | ワークフロー(レガシー) | Mastra ドキュメント" description: Mastra を使用して、循環依存関係や条件付きループを含むレガシーワークフローを作成する例。 --- import { GithubLink } from "@/components/github-link"; # ワークフロー(レガシー)における循環依存 [JA] Source: https://mastra.ai/ja/examples/workflows_legacy/cyclical-dependencies ワークフローは、条件に基づいてステップがループバックできる循環依存をサポートしています。以下の例では、条件付きロジックを使ってループを作成し、繰り返し実行を処理する方法を示しています。 ```ts showLineNumbers copy import { LegacyWorkflow, LegacyStep } from "@mastra/core/workflows/legacy"; import { z } from "zod"; async function main() { const doubleValue = new LegacyStep({ id: "doubleValue", description: "Doubles the input value", inputSchema: z.object({ inputValue: z.number(), }), outputSchema: z.object({ doubledValue: z.number(), }), execute: async ({ context }) => { const doubledValue = context.inputValue * 2; return { doubledValue }; }, }); const incrementByOne = new LegacyStep({ id: "incrementByOne", description: "Adds 1 to the input value", outputSchema: z.object({ incrementedValue: z.number(), }), execute: async ({ context }) => { const valueToIncrement = context?.getStepResult<{ firstValue: number }>( "trigger", )?.firstValue; if (!valueToIncrement) throw new Error("No value to increment provided"); const incrementedValue = valueToIncrement + 1; return { incrementedValue }; }, }); const cyclicalWorkflow = new LegacyWorkflow({ name: "cyclical-workflow", triggerSchema: z.object({ firstValue: z.number(), }), }); cyclicalWorkflow .step(doubleValue, { variables: { inputValue: { step: "trigger", path: "firstValue", }, }, }) .then(incrementByOne) .after(doubleValue) .step(doubleValue, { variables: { inputValue: { step: doubleValue, path: "doubledValue", }, }, }) .commit(); const { runId, start } = cyclicalWorkflow.createRun(); console.log("Run", runId); const res = await start({ triggerData: { firstValue: 6 } }); console.log(res.results); } main(); ```




--- title: "例: Human in the Loop | ワークフロー(レガシー) | Mastra ドキュメント" description: Mastra を使用して人間の介入ポイントを持つレガシーワークフローを作成する例。 --- import { GithubLink } from "@/components/github-link"; # Human in the Loop Workflow (Legacy) [JA] Source: https://mastra.ai/ja/examples/workflows_legacy/human-in-the-loop Human-in-the-loop ワークフローでは、特定のポイントで実行を一時停止し、ユーザーからの入力を収集したり、意思決定を行ったり、人間の判断が必要なアクションを実行したりできます。この例では、人による介入ポイントを含むレガシーワークフローの作成方法を示します。 ## 仕組み 1. ワークフローステップは、`suspend()` 関数を使って実行を**一時停止**することができ、人間の意思決定者のためのコンテキストを含むペイロードをオプションで渡すことができます。 2. ワークフローが**再開**されると、人間の入力が `resume()` 呼び出しの `context` パラメータに渡されます。 3. この入力は、ステップの実行コンテキスト内で `context.inputData` として利用可能になり、ステップの `inputSchema` に従った型になります。 4. その後、ステップは人間の入力に基づいて実行を続行できます。 このパターンにより、自動化されたワークフローにおいて、安全で型チェックされた人間の介入が可能になります。 ## Inquirer を使った対話型ターミナル例 この例では、[Inquirer](https://www.npmjs.com/package/@inquirer/prompts) ライブラリを使用して、ワークフローが一時停止した際にターミナルから直接ユーザー入力を収集し、真にインタラクティブな human-in-the-loop 体験を実現する方法を示します。 ```ts showLineNumbers copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; import { confirm, input, select } from "@inquirer/prompts"; // Step 1: Generate product recommendations const generateRecommendations = new LegacyStep({ id: "generateRecommendations", outputSchema: z.object({ customerName: z.string(), recommendations: z.array( z.object({ productId: z.string(), productName: z.string(), price: z.number(), description: z.string(), }), ), }), execute: async ({ context }) => { const customerName = context.triggerData.customerName; // In a real application, you might call an API or ML model here // For this example, we'll return mock data return { customerName, recommendations: [ { productId: "prod-001", productName: "Premium Widget", price: 99.99, description: "Our best-selling premium widget with advanced features", }, { productId: "prod-002", productName: "Basic Widget", price: 49.99, description: "Affordable entry-level widget for beginners", }, { productId: "prod-003", productName: "Widget Pro Plus", price: 149.99, description: "Professional-grade widget with extended warranty", }, ], }; }, }); ``` ```ts showLineNumbers copy // Step 2: Get human approval and customization for the recommendations const reviewRecommendations = new LegacyStep({ id: "reviewRecommendations", inputSchema: z.object({ approvedProducts: z.array(z.string()), customerNote: z.string().optional(), offerDiscount: z.boolean().optional(), }), outputSchema: z.object({ finalRecommendations: z.array( z.object({ productId: z.string(), productName: z.string(), price: z.number(), }), ), customerNote: z.string().optional(), offerDiscount: z.boolean(), }), execute: async ({ context, suspend }) => { const { customerName, recommendations } = context.getStepResult( generateRecommendations, ) || { customerName: "", recommendations: [], }; // Check if we have input from a resumed workflow const reviewInput = { approvedProducts: context.inputData?.approvedProducts || [], customerNote: context.inputData?.customerNote, offerDiscount: context.inputData?.offerDiscount, }; // If we don't have agent input yet, suspend for human review if (!reviewInput.approvedProducts.length) { console.log(`Generating recommendations for customer: ${customerName}`); await suspend({ customerName, recommendations, message: "Please review these product recommendations before sending to the customer", }); // Placeholder return (won't be reached due to suspend) return { finalRecommendations: [], customerNote: "", offerDiscount: false, }; } // Process the agent's product selections const finalRecommendations = recommendations .filter((product) => reviewInput.approvedProducts.includes(product.productId), ) .map((product) => ({ productId: product.productId, productName: product.productName, price: product.price, })); return { finalRecommendations, customerNote: reviewInput.customerNote || "", offerDiscount: reviewInput.offerDiscount || false, }; }, }); ``` ```ts showLineNumbers copy // Step 3: Send the recommendations to the customer const sendRecommendations = new LegacyStep({ id: "sendRecommendations", outputSchema: z.object({ emailSent: z.boolean(), emailContent: z.string(), }), execute: async ({ context }) => { const { customerName } = context.getStepResult(generateRecommendations) || { customerName: "", }; const { finalRecommendations, customerNote, offerDiscount } = context.getStepResult(reviewRecommendations) || { finalRecommendations: [], customerNote: "", offerDiscount: false, }; // Generate email content based on the recommendations let emailContent = `Dear ${customerName},\n\nBased on your preferences, we recommend:\n\n`; finalRecommendations.forEach((product) => { emailContent += `- ${product.productName}: $${product.price.toFixed(2)}\n`; }); if (offerDiscount) { emailContent += "\nAs a valued customer, use code SAVE10 for 10% off your next purchase!\n"; } if (customerNote) { emailContent += `\nPersonal note: ${customerNote}\n`; } emailContent += "\nThank you for your business,\nThe Sales Team"; // In a real application, you would send this email console.log("Email content generated:", emailContent); return { emailSent: true, emailContent, }; }, }); // Build the workflow const recommendationWorkflow = new LegacyWorkflow({ name: "product-recommendation-workflow", triggerSchema: z.object({ customerName: z.string(), }), }); recommendationWorkflow .step(generateRecommendations) .then(reviewRecommendations) .then(sendRecommendations) .commit(); // Register the workflow const mastra = new Mastra({ legacy_workflows: { recommendationWorkflow }, }); ``` ```ts showLineNumbers copy // Example of using the workflow with Inquirer prompts async function runRecommendationWorkflow() { const registeredWorkflow = mastra.legacy_getWorkflow( "recommendationWorkflow", ); const run = registeredWorkflow.createRun(); console.log("Starting product recommendation workflow..."); const result = await run.start({ triggerData: { customerName: "Jane Smith", }, }); const isReviewStepSuspended = result.activePaths.get("reviewRecommendations")?.status === "suspended"; // Check if workflow is suspended for human review if (isReviewStepSuspended) { const { customerName, recommendations, message } = result.activePaths.get( "reviewRecommendations", )?.suspendPayload; console.log("\n==================================="); console.log(message); console.log(`Customer: ${customerName}`); console.log("===================================\n"); // Use Inquirer to collect input from the sales agent in the terminal console.log("Available product recommendations:"); recommendations.forEach((product, index) => { console.log( `${index + 1}. ${product.productName} - $${product.price.toFixed(2)}`, ); console.log(` ${product.description}\n`); }); // Let the agent select which products to recommend const approvedProducts = await checkbox({ message: "Select products to recommend to the customer:", choices: recommendations.map((product) => ({ name: `${product.productName} ($${product.price.toFixed(2)})`, value: product.productId, })), }); // Let the agent add a personal note const includeNote = await confirm({ message: "Would you like to add a personal note?", default: false, }); let customerNote = ""; if (includeNote) { customerNote = await input({ message: "Enter your personalized note for the customer:", }); } // Ask if a discount should be offered const offerDiscount = await confirm({ message: "Offer a 10% discount to this customer?", default: false, }); console.log("\nSubmitting your review..."); // Resume the workflow with the agent's input const resumeResult = await run.resume({ stepId: "reviewRecommendations", context: { approvedProducts, customerNote, offerDiscount, }, }); console.log("\n==================================="); console.log("Workflow completed!"); console.log("Email content:"); console.log("===================================\n"); console.log( resumeResult?.results?.sendRecommendations || "No email content generated", ); return resumeResult; } return result; } // Invoke the workflow with interactive terminal input runRecommendationWorkflow().catch(console.error); ``` ## 複数のユーザー入力を伴う高度な例 この例では、コンテンツモデレーションシステムのように、複数回の人間による介入が必要となる、より複雑なワークフローを示します。 ```ts showLineNumbers copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; import { select, input } from "@inquirer/prompts"; // Step 1: Receive and analyze content const analyzeContent = new LegacyStep({ id: "analyzeContent", outputSchema: z.object({ content: z.string(), aiAnalysisScore: z.number(), flaggedCategories: z.array(z.string()).optional(), }), execute: async ({ context }) => { const content = context.triggerData.content; // Simulate AI analysis const aiAnalysisScore = simulateContentAnalysis(content); const flaggedCategories = aiAnalysisScore < 0.7 ? ["potentially inappropriate", "needs review"] : []; return { content, aiAnalysisScore, flaggedCategories, }; }, }); ``` ```ts showLineNumbers copy // Step 2: Moderate content that needs review const moderateContent = new LegacyStep({ id: "moderateContent", // Define the schema for human input that will be provided when resuming inputSchema: z.object({ moderatorDecision: z.enum(["approve", "reject", "modify"]).optional(), moderatorNotes: z.string().optional(), modifiedContent: z.string().optional(), }), outputSchema: z.object({ moderationResult: z.enum(["approved", "rejected", "modified"]), moderatedContent: z.string(), notes: z.string().optional(), }), // @ts-ignore execute: async ({ context, suspend }) => { const analysisResult = context.getStepResult(analyzeContent); // Access the input provided when resuming the workflow const moderatorInput = { decision: context.inputData?.moderatorDecision, notes: context.inputData?.moderatorNotes, modifiedContent: context.inputData?.modifiedContent, }; // If the AI analysis score is high enough, auto-approve if ( analysisResult?.aiAnalysisScore > 0.9 && !analysisResult?.flaggedCategories?.length ) { return { moderationResult: "approved", moderatedContent: analysisResult.content, notes: "Auto-approved by system", }; } // If we don't have moderator input yet, suspend for human review if (!moderatorInput.decision) { await suspend({ content: analysisResult?.content, aiScore: analysisResult?.aiAnalysisScore, flaggedCategories: analysisResult?.flaggedCategories, message: "Please review this content and make a moderation decision", }); // Placeholder return return { moderationResult: "approved", moderatedContent: "", }; } // Process the moderator's decision switch (moderatorInput.decision) { case "approve": return { moderationResult: "approved", moderatedContent: analysisResult?.content || "", notes: moderatorInput.notes || "Approved by moderator", }; case "reject": return { moderationResult: "rejected", moderatedContent: "", notes: moderatorInput.notes || "Rejected by moderator", }; case "modify": return { moderationResult: "modified", moderatedContent: moderatorInput.modifiedContent || analysisResult?.content || "", notes: moderatorInput.notes || "Modified by moderator", }; default: return { moderationResult: "rejected", moderatedContent: "", notes: "Invalid moderator decision", }; } }, }); ``` ```ts showLineNumbers copy // Step 3: Apply moderation actions const applyModeration = new LegacyStep({ id: "applyModeration", outputSchema: z.object({ finalStatus: z.string(), content: z.string().optional(), auditLog: z.object({ originalContent: z.string(), moderationResult: z.string(), aiScore: z.number(), timestamp: z.string(), }), }), execute: async ({ context }) => { const analysisResult = context.getStepResult(analyzeContent); const moderationResult = context.getStepResult(moderateContent); // Create audit log const auditLog = { originalContent: analysisResult?.content || "", moderationResult: moderationResult?.moderationResult || "unknown", aiScore: analysisResult?.aiAnalysisScore || 0, timestamp: new Date().toISOString(), }; // Apply moderation action switch (moderationResult?.moderationResult) { case "approved": return { finalStatus: "Content published", content: moderationResult.moderatedContent, auditLog, }; case "modified": return { finalStatus: "Content modified and published", content: moderationResult.moderatedContent, auditLog, }; case "rejected": return { finalStatus: "Content rejected", auditLog, }; default: return { finalStatus: "Error in moderation process", auditLog, }; } }, }); ``` ```ts showLineNumbers copy // Build the workflow const contentModerationWorkflow = new LegacyWorkflow({ name: "content-moderation-workflow", triggerSchema: z.object({ content: z.string(), }), }); contentModerationWorkflow .step(analyzeContent) .then(moderateContent) .then(applyModeration) .commit(); // Register the workflow const mastra = new Mastra({ legacy_workflows: { contentModerationWorkflow }, }); // Example of using the workflow with Inquirer prompts async function runModerationDemo() { const registeredWorkflow = mastra.legacy_getWorkflow( "contentModerationWorkflow", ); const run = registeredWorkflow.createRun(); // Start the workflow with content that needs review console.log("コンテンツモデレーションワークフローを開始します..."); const result = await run.start({ triggerData: { content: "これはモデレーションが必要なユーザー生成コンテンツです。", }, }); const isReviewStepSuspended = result.activePaths.get("moderateContent")?.status === "suspended"; // Check if workflow is suspended if (isReviewStepSuspended) { const { content, aiScore, flaggedCategories, message } = result.activePaths.get("moderateContent")?.suspendPayload; console.log("\n==================================="); console.log(message); console.log("===================================\n"); console.log("レビュー対象のコンテンツ:"); console.log(content); console.log(`\nAI解析スコア: ${aiScore}`); console.log( `フラグ付けされたカテゴリ: ${flaggedCategories?.join(", ") || "なし"}\n`, ); // Collect moderator decision using Inquirer const moderatorDecision = await select({ message: "モデレーションの判断を選択してください:", choices: [ { name: "このままコンテンツを承認する", value: "approve" }, { name: "コンテンツを完全に却下する", value: "reject" }, { name: "公開前にコンテンツを修正する", value: "modify" }, ], }); // Collect additional information based on decision let moderatorNotes = ""; let modifiedContent = ""; moderatorNotes = await input({ message: "判断に関するメモを入力してください:", }); if (moderatorDecision === "modify") { modifiedContent = await input({ message: "修正後のコンテンツを入力してください:", default: content, }); } console.log("\nモデレーションの判断を送信しています..."); // Resume the workflow with the moderator's input const resumeResult = await run.resume({ stepId: "moderateContent", context: { moderatorDecision, moderatorNotes, modifiedContent, }, }); if (resumeResult?.results?.applyModeration?.status === "success") { console.log("\n==================================="); console.log( `モデレーション完了: ${resumeResult?.results?.applyModeration?.output.finalStatus}`, ); console.log("===================================\n"); if (resumeResult?.results?.applyModeration?.output.content) { console.log("公開されたコンテンツ:"); console.log(resumeResult.results.applyModeration.output.content); } } return resumeResult; } console.log( "人による介入なしでワークフローが完了しました:", result.results, ); return result; } // Helper function for AI content analysis simulation function simulateContentAnalysis(content: string): number { // In a real application, this would call an AI service // For the example, we're returning a random score return Math.random(); } // Invoke the demo function runModerationDemo().catch(console.error); ``` ## 主要な概念 1. **サスペンションポイント** - ステップの execute 内で `suspend()` 関数を使用して、ワークフローの実行を一時停止します。 2. **サスペンションペイロード** - サスペンド時に関連データを渡し、人間による意思決定のためのコンテキストを提供します: ```ts await suspend({ messageForHuman: "Please review this data", data: someImportantData, }); ``` 3. **ワークフローのステータス確認** - ワークフロー開始後、返されたステータスを確認してサスペンドされているかどうかを判断します: ```ts const result = await workflow.start({ triggerData }); if (result.status === "suspended" && result.suspendedStepId === "stepId") { // サスペンションの処理 console.log("Workflow is waiting for input:", result.suspendPayload); } ``` 4. **対話型ターミナル入力** - Inquirer などのライブラリを使って対話型プロンプトを作成します: ```ts import { select, input, confirm } from "@inquirer/prompts"; // ワークフローがサスペンドされたとき if (result.status === "suspended") { // サスペンドペイロードから情報を表示 console.log(result.suspendPayload.message); // ユーザー入力を対話的に収集 const decision = await select({ message: "What would you like to do?", choices: [ { name: "Approve", value: "approve" }, { name: "Reject", value: "reject" }, ], }); // 収集した入力でワークフローを再開 await run.resume({ stepId: result.suspendedStepId, context: { decision }, }); } ``` 5. **ワークフローの再開** - `resume()` メソッドを使って、人間の入力とともにワークフローの実行を続行します: ```ts const resumeResult = await run.resume({ stepId: "suspendedStepId", context: { // このデータは context.inputData としてサスペンドされたステップに渡されます // そしてステップの inputSchema に準拠している必要があります userDecision: "approve", }, }); ``` 6. **人間のデータ用インプットスキーマ** - 人間の入力で再開される可能性のあるステップには、型安全性を確保するためにインプットスキーマを定義します: ```ts const myStep = new LegacyStep({ id: "myStep", inputSchema: z.object({ // このスキーマは resume の context で渡されるデータを検証します // そして context.inputData として利用可能にします userDecision: z.enum(["approve", "reject"]), userComments: z.string().optional(), }), execute: async ({ context, suspend }) => { // 以前のサスペンションからユーザー入力があるか確認 if (context.inputData?.userDecision) { // ユーザーの決定を処理 return { result: `User decided: ${context.inputData.userDecision}` }; } // 入力がなければ、人間の判断のためにサスペンド await suspend(); }, }); ``` Human-in-the-loop ワークフローは、自動化と人間の判断を組み合わせたシステムの構築に非常に有効です。例えば: - コンテンツモデレーションシステム - 承認ワークフロー - 監督付き AI システム - エスカレーションを伴うカスタマーサービス自動化




--- title: "例: 並列実行 | ワークフロー(レガシー) | Mastra ドキュメント" description: ワークフロー内で複数の独立したタスクを並列に実行するために Mastra を使用する例。 --- import { GithubLink } from "@/components/github-link"; # ステップによる並列実行 [JA] Source: https://mastra.ai/ja/examples/workflows_legacy/parallel-steps AIアプリケーションを構築する際、効率を向上させるために複数の独立したタスクを同時に処理する必要がよくあります。 ## フロー制御図 この例では、各ブランチが独自のデータフローと依存関係を処理しながら、ステップを並列で実行するワークフローの構成方法を示します。 フロー制御図は次のとおりです: 並列ステップを持つワークフローの図 ## ステップの作成 まず、ステップを作成し、ワークフローを初期化しましょう。 ```ts showLineNumbers copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const stepOne = new LegacyStep({ id: "stepOne", execute: async ({ context }) => ({ doubledValue: context.triggerData.inputValue * 2, }), }); const stepTwo = new LegacyStep({ id: "stepTwo", execute: async ({ context }) => { if (context.steps.stepOne.status !== "success") { return { incrementedValue: 0 }; } return { incrementedValue: context.steps.stepOne.output.doubledValue + 1 }; }, }); const stepThree = new LegacyStep({ id: "stepThree", execute: async ({ context }) => ({ tripledValue: context.triggerData.inputValue * 3, }), }); const stepFour = new LegacyStep({ id: "stepFour", execute: async ({ context }) => { if (context.steps.stepThree.status !== "success") { return { isEven: false }; } return { isEven: context.steps.stepThree.output.tripledValue % 2 === 0 }; }, }); const myWorkflow = new LegacyWorkflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); ``` ## ステップの連結と並列化 これで、ワークフローにステップを追加できるようになりました。`.then()` メソッドはステップを連結するために使用されますが、`.step()` メソッドはステップをワークフローに追加するために使われます。 ```ts showLineNumbers copy myWorkflow .step(stepOne) .then(stepTwo) // chain one .step(stepThree) .then(stepFour) // chain two .commit(); const { start } = myWorkflow.createRun(); const result = await start({ triggerData: { inputValue: 3 } }); ```




--- title: "例: 順次ステップ | ワークフロー(レガシー) | Mastra ドキュメント" description: Mastra を使用してレガシーワークフローステップを特定の順序で連結し、データを受け渡す例。 --- import { GithubLink } from "@/components/github-link"; # ワークフロー(レガシー)と順次ステップ [JA] Source: https://mastra.ai/ja/examples/workflows_legacy/sequential-steps ワークフローは、特定の順序で次々と連鎖して実行することができます。 ## 制御フローダイアグラム この例では、`then` メソッドを使ってワークフローステップを連結し、順次ステップ間でデータを渡しながら順番に実行する方法を示しています。 制御フローダイアグラムは以下の通りです: 順次ステップを持つワークフローのダイアグラム ## ステップの作成 まず、ステップを作成し、ワークフローを初期化しましょう。 ```ts showLineNumbers copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const stepOne = new LegacyStep({ id: "stepOne", execute: async ({ context }) => ({ doubledValue: context.triggerData.inputValue * 2, }), }); const stepTwo = new LegacyStep({ id: "stepTwo", execute: async ({ context }) => { if (context.steps.stepOne.status !== "success") { return { incrementedValue: 0 }; } return { incrementedValue: context.steps.stepOne.output.doubledValue + 1 }; }, }); const stepThree = new LegacyStep({ id: "stepThree", execute: async ({ context }) => { if (context.steps.stepTwo.status !== "success") { return { tripledValue: 0 }; } return { tripledValue: context.steps.stepTwo.output.incrementedValue * 3 }; }, }); // Build the workflow const myWorkflow = new LegacyWorkflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); ``` ## ステップの連結とワークフローの実行 それでは、ステップを順番につなげてみましょう。 ```ts showLineNumbers copy // sequential steps myWorkflow.step(stepOne).then(stepTwo).then(stepThree); myWorkflow.commit(); const { start } = myWorkflow.createRun(); const res = await start({ triggerData: { inputValue: 90 } }); ```




--- title: "例: 一時停止と再開 | ワークフロー(レガシー) | Mastra ドキュメント" description: 実行中に Mastra を使用してレガシーワークフローステップを一時停止および再開する例。 --- import { GithubLink } from "@/components/github-link"; # ワークフロー(レガシー)の一時停止と再開 [JA] Source: https://mastra.ai/ja/examples/workflows_legacy/suspend-and-resume ワークフローのステップは、ワークフロー実行中の任意のタイミングで一時停止および再開することができます。この例では、ワークフローステップを一時停止し、後で再開する方法を示します。 ## 基本例 ```ts showLineNumbers copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const stepOne = new LegacyStep({ id: "stepOne", outputSchema: z.object({ doubledValue: z.number(), }), execute: async ({ context }) => { const doubledValue = context.triggerData.inputValue * 2; return { doubledValue }; }, }); ``` ```ts showLineNumbers copy const stepTwo = new LegacyStep({ id: "stepTwo", outputSchema: z.object({ incrementedValue: z.number(), }), execute: async ({ context, suspend }) => { const secondValue = context.inputData?.secondValue ?? 0; const doubledValue = context.getStepResult(stepOne)?.doubledValue ?? 0; const incrementedValue = doubledValue + secondValue; if (incrementedValue < 100) { await suspend(); return { incrementedValue: 0 }; } return { incrementedValue }; }, }); // Build the workflow const myWorkflow = new LegacyWorkflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); // run workflows in parallel myWorkflow.step(stepOne).then(stepTwo).commit(); ``` ```ts showLineNumbers copy // Register the workflow export const mastra = new Mastra({ legacy_workflows: { registeredWorkflow: myWorkflow }, }); // Get registered workflow from Mastra const registeredWorkflow = mastra.legacy_getWorkflow("registeredWorkflow"); const { runId, start } = registeredWorkflow.createRun(); // Start watching the workflow before executing it myWorkflow.watch(async ({ context, activePaths }) => { for (const _path of activePaths) { const stepTwoStatus = context.steps?.stepTwo?.status; if (stepTwoStatus === "suspended") { console.log("Workflow suspended, resuming with new value"); // Resume the workflow with new context await myWorkflow.resume({ runId, stepId: "stepTwo", context: { secondValue: 100 }, }); } } }); // Start the workflow execution await start({ triggerData: { inputValue: 45 } }); ``` ## async/awaitパターンとsuspendペイロードを用いた複数のサスペンションポイントを持つ高度な例 この例では、async/awaitパターンを使用し、複数のサスペンションポイントを持つより複雑なワークフローを示します。これは、さまざまな段階で人間の介入が必要となるコンテンツ生成ワークフローをシミュレートしています。 ```ts showLineNumbers copy import { Mastra } from "@mastra/core"; import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Step 1: Get user input const getUserInput = new LegacyStep({ id: "getUserInput", execute: async ({ context }) => { // In a real application, this might come from a form or API return { userInput: context.triggerData.input }; }, outputSchema: z.object({ userInput: z.string() }), }); ``` ```ts showLineNumbers copy // Step 2: Generate content with AI (may suspend for human guidance) const promptAgent = new LegacyStep({ id: "promptAgent", inputSchema: z.object({ guidance: z.string(), }), execute: async ({ context, suspend }) => { const userInput = context.getStepResult(getUserInput)?.userInput; console.log(`Generating content based on: ${userInput}`); const guidance = context.inputData?.guidance; // Simulate AI generating content const initialDraft = generateInitialDraft(userInput); // If confidence is high, return the generated content directly if (initialDraft.confidenceScore > 0.7) { return { modelOutput: initialDraft.content }; } console.log( "Low confidence in generated content, suspending for human guidance", { guidance }, ); // If confidence is low, suspend for human guidance if (!guidance) { // only suspend if no guidance is provided await suspend(); return undefined; } // This code runs after resume with human guidance console.log("Resumed with human guidance"); // Use the human guidance to improve the output return { modelOutput: enhanceWithGuidance(initialDraft.content, guidance), }; }, outputSchema: z.object({ modelOutput: z.string() }).optional(), }); ``` ```ts showLineNumbers copy // Step 3: Evaluate the content quality const evaluateTone = new LegacyStep({ id: "evaluateToneConsistency", execute: async ({ context }) => { const content = context.getStepResult(promptAgent)?.modelOutput; // Simulate evaluation return { toneScore: { score: calculateToneScore(content) }, completenessScore: { score: calculateCompletenessScore(content) }, }; }, outputSchema: z.object({ toneScore: z.any(), completenessScore: z.any(), }), }); ``` ```ts showLineNumbers copy // Step 4: Improve response if needed (may suspend) const improveResponse = new LegacyStep({ id: "improveResponse", inputSchema: z.object({ improvedContent: z.string(), resumeAttempts: z.number(), }), execute: async ({ context, suspend }) => { const content = context.getStepResult(promptAgent)?.modelOutput; const toneScore = context.getStepResult(evaluateTone)?.toneScore.score ?? 0; const completenessScore = context.getStepResult(evaluateTone)?.completenessScore.score ?? 0; const improvedContent = context.inputData.improvedContent; const resumeAttempts = context.inputData.resumeAttempts ?? 0; // If scores are above threshold, make minor improvements if (toneScore > 0.8 && completenessScore > 0.8) { return { improvedOutput: makeMinorImprovements(content) }; } console.log( "Content quality below threshold, suspending for human intervention", { improvedContent, resumeAttempts }, ); if (!improvedContent) { // Suspend with payload containing content and resume attempts await suspend({ content, scores: { tone: toneScore, completeness: completenessScore }, needsImprovement: toneScore < 0.8 ? "tone" : "completeness", resumeAttempts: resumeAttempts + 1, }); return { improvedOutput: content ?? "" }; } console.log("Resumed with human improvements", improvedContent); return { improvedOutput: improvedContent ?? content ?? "" }; }, outputSchema: z.object({ improvedOutput: z.string() }).optional(), }); ``` ```ts showLineNumbers copy // Step 5: Final evaluation const evaluateImproved = new LegacyStep({ id: "evaluateImprovedResponse", execute: async ({ context }) => { const improvedContent = context.getStepResult(improveResponse)?.improvedOutput; // Simulate final evaluation return { toneScore: { score: calculateToneScore(improvedContent) }, completenessScore: { score: calculateCompletenessScore(improvedContent) }, }; }, outputSchema: z.object({ toneScore: z.any(), completenessScore: z.any(), }), }); // Build the workflow const contentWorkflow = new LegacyWorkflow({ name: "content-generation-workflow", triggerSchema: z.object({ input: z.string() }), }); contentWorkflow .step(getUserInput) .then(promptAgent) .then(evaluateTone) .then(improveResponse) .then(evaluateImproved) .commit(); ``` ```ts showLineNumbers copy // Register the workflow const mastra = new Mastra({ legacy_workflows: { contentWorkflow }, }); // Helper functions (simulated) function generateInitialDraft(input: string = "") { // Simulate AI generating content return { content: `Generated content based on: ${input}`, confidenceScore: 0.6, // Simulate low confidence to trigger suspension }; } function enhanceWithGuidance(content: string = "", guidance: string = "") { return `${content} (Enhanced with guidance: ${guidance})`; } function makeMinorImprovements(content: string = "") { return `${content} (with minor improvements)`; } function calculateToneScore(_: string = "") { return 0.7; // Simulate a score that will trigger suspension } function calculateCompletenessScore(_: string = "") { return 0.9; } // Usage example async function runWorkflow() { const workflow = mastra.legacy_getWorkflow("contentWorkflow"); const { runId, start } = workflow.createRun(); let finalResult: any; // Start the workflow const initialResult = await start({ triggerData: { input: "Create content about sustainable energy" }, }); console.log("Initial workflow state:", initialResult.results); const promptAgentStepResult = initialResult.activePaths.get("promptAgent"); // Check if promptAgent step is suspended if (promptAgentStepResult?.status === "suspended") { console.log("Workflow suspended at promptAgent step"); console.log("Suspension payload:", promptAgentStepResult?.suspendPayload); // Resume with human guidance const resumeResult1 = await workflow.resume({ runId, stepId: "promptAgent", context: { guidance: "Focus more on solar and wind energy technologies", }, }); console.log("Workflow resumed and continued to next steps"); let improveResponseResumeAttempts = 0; let improveResponseStatus = resumeResult1?.activePaths.get("improveResponse")?.status; // Check if improveResponse step is suspended while (improveResponseStatus === "suspended") { console.log("Workflow suspended at improveResponse step"); console.log( "Suspension payload:", resumeResult1?.activePaths.get("improveResponse")?.suspendPayload, ); const improvedContent = improveResponseResumeAttempts < 3 ? undefined : "Completely revised content about sustainable energy focusing on solar and wind technologies"; // Resume with human improvements finalResult = await workflow.resume({ runId, stepId: "improveResponse", context: { improvedContent, resumeAttempts: improveResponseResumeAttempts, }, }); improveResponseResumeAttempts = finalResult?.activePaths.get("improveResponse")?.suspendPayload ?.resumeAttempts ?? 0; improveResponseStatus = finalResult?.activePaths.get("improveResponse")?.status; console.log("Improved response result:", finalResult?.results); } } return finalResult; } // Run the workflow const result = await runWorkflow(); console.log("Workflow completed"); console.log("Final workflow result:", result); ``` --- title: "例:ツールをステップとして使用する | ワークフロー(レガシー) | Mastra ドキュメント" description: レガシーワークフローでカスタムツールをステップとして統合するためにMastraを使用する例。 --- import { GithubLink } from "@/components/github-link"; # ワークフローステップとしてのツール(レガシー) [JA] Source: https://mastra.ai/ja/examples/workflows_legacy/using-a-tool-as-a-step この例では、カスタムツールをワークフローステップとして作成し統合する方法を示しています。入力/出力スキーマの定義方法や、ツールの実行ロジックの実装方法について説明します。 ```ts showLineNumbers copy import { createTool } from "@mastra/core/tools"; import { LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const crawlWebpage = createTool({ id: "Crawl Webpage", description: "Crawls a webpage and extracts the text content", inputSchema: z.object({ url: z.string().url(), }), outputSchema: z.object({ rawText: z.string(), }), execute: async ({ context }) => { const response = await fetch(context.triggerData.url); const text = await response.text(); return { rawText: "This is the text content of the webpage: " + text }; }, }); const contentWorkflow = new LegacyWorkflow({ name: "content-review" }); contentWorkflow.step(crawlWebpage).commit(); const { start } = contentWorkflow.createRun(); const res = await start({ triggerData: { url: "https://example.com" } }); console.log(res.results); ```




--- title: "ワークフローバリアブルによるデータマッピング(レガシー) | Mastra 例" description: "Mastra ワークフローでワークフローバリアブルを使ってステップ間のデータをマッピングする方法を学びます。" --- # ワークフローバリアブルによるデータマッピング(レガシー) [JA] Source: https://mastra.ai/ja/examples/workflows_legacy/workflow-variables この例では、Mastra ワークフロー内のステップ間でデータをマッピングするためにワークフローバリアブルを使用する方法を示します。 ## ユースケース:ユーザー登録プロセス この例では、シンプルなユーザー登録ワークフローを作成します。このワークフローは以下を行います。 1. ユーザー入力の検証 1. ユーザーデータの整形 1. ユーザープロファイルの作成 ## 実装 ```typescript showLineNumbers filename="src/mastra/workflows/user-registration.ts" copy import { LegacyStep, LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Define our schemas for better type safety const userInputSchema = z.object({ email: z.string().email(), name: z.string(), age: z.number().min(18), }); const validatedDataSchema = z.object({ isValid: z.boolean(), validatedData: z.object({ email: z.string(), name: z.string(), age: z.number(), }), }); const formattedDataSchema = z.object({ userId: z.string(), formattedData: z.object({ email: z.string(), displayName: z.string(), ageGroup: z.string(), }), }); const profileSchema = z.object({ profile: z.object({ id: z.string(), email: z.string(), displayName: z.string(), ageGroup: z.string(), createdAt: z.string(), }), }); // Define the workflow const registrationWorkflow = new LegacyWorkflow({ name: "user-registration", triggerSchema: userInputSchema, }); // Step 1: Validate user input const validateInput = new LegacyStep({ id: "validateInput", inputSchema: userInputSchema, outputSchema: validatedDataSchema, execute: async ({ context }) => { const { email, name, age } = context; // Simple validation logic const isValid = email.includes("@") && name.length > 0 && age >= 18; return { isValid, validatedData: { email: email.toLowerCase().trim(), name, age, }, }; }, }); // Step 2: Format user data const formatUserData = new LegacyStep({ id: "formatUserData", inputSchema: z.object({ validatedData: z.object({ email: z.string(), name: z.string(), age: z.number(), }), }), outputSchema: formattedDataSchema, execute: async ({ context }) => { const { validatedData } = context; // Generate a simple user ID const userId = `user_${Math.floor(Math.random() * 10000)}`; // Format the data const ageGroup = validatedData.age < 30 ? "young-adult" : "adult"; return { userId, formattedData: { email: validatedData.email, displayName: validatedData.name, ageGroup, }, }; }, }); // Step 3: Create user profile const createUserProfile = new LegacyStep({ id: "createUserProfile", inputSchema: z.object({ userId: z.string(), formattedData: z.object({ email: z.string(), displayName: z.string(), ageGroup: z.string(), }), }), outputSchema: profileSchema, execute: async ({ context }) => { const { userId, formattedData } = context; // In a real app, you would save to a database here return { profile: { id: userId, ...formattedData, createdAt: new Date().toISOString(), }, }; }, }); // Build the workflow with variable mappings registrationWorkflow // First step gets data from the trigger .step(validateInput, { variables: { email: { step: "trigger", path: "email" }, name: { step: "trigger", path: "name" }, age: { step: "trigger", path: "age" }, }, }) // Format user data with validated data from previous step .then(formatUserData, { variables: { validatedData: { step: validateInput, path: "validatedData" }, }, when: { ref: { step: validateInput, path: "isValid" }, query: { $eq: true }, }, }) // Create profile with data from the format step .then(createUserProfile, { variables: { userId: { step: formatUserData, path: "userId" }, formattedData: { step: formatUserData, path: "formattedData" }, }, }) .commit(); export default registrationWorkflow; ``` ## この例の使い方 1. 上記のようにファイルを作成します 2. Mastraインスタンスにワークフローを登録します 3. ワークフローを実行します: ```bash curl --location 'http://localhost:4111/api/workflows/user-registration/start-async' \ --header 'Content-Type: application/json' \ --data '{ "email": "user@example.com", "name": "John Doe", "age": 25 }' ``` ## 主なポイント この例では、ワークフロー変数に関するいくつかの重要な概念を示しています。 1. **データマッピング**: 変数は、あるステップから別のステップへデータをマッピングし、明確なデータフローを作成します。 2. **パスアクセス**: `path` プロパティは、ステップの出力のどの部分を使用するかを指定します。 3. **条件付き実行**: `when` プロパティにより、前のステップの出力に基づいてステップを条件付きで実行できます。 4. **型安全性**: 各ステップは、型安全性を確保するために入力および出力スキーマを定義し、ステップ間で渡されるデータが正しく型付けされていることを保証します。 5. **明示的なデータ依存関係**: 入力スキーマを定義し、変数マッピングを使用することで、ステップ間のデータ依存関係が明示的かつ明確になります。 ワークフロー変数の詳細については、[Workflow Variables ドキュメント](../../docs/workflows-legacy/variables.mdx)をご覧ください。 --- title: "例: ツール/エージェントをステップとして使用する | ワークフロー | Mastra ドキュメント" description: ワークフローのステップとしてツールまたはエージェントを統合するためにMastraを使用する例。 --- # ワークフローステップとしてのツール/エージェント [JA] Source: https://mastra.ai/ja/examples/workflows_vNext/agent-and-tool-interop この例では、ツールまたはエージェントをワークフローステップとして作成し、統合する方法を示しています。 Mastraは、ステップまたはエージェントを受け入れ、Stepインターフェースを満たすオブジェクトを返す`createStep`ヘルパー関数を提供しています。 ## セットアップ ```sh copy npm install @ai-sdk/openai @mastra/core ``` ## 天気レポーターエージェントの定義 LLMを活用して天気レポーターのように天気予報を説明する天気レポーターエージェントを定義します。 ```ts showLineNumbers copy filename="agents/weather-reporter-agent.ts" import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; // Create an agent that explains weather reports in a conversational style export const weatherReporterAgent = new Agent({ name: "weatherExplainerAgent", model: openai("gpt-4o"), instructions: ` You are a weather explainer. You have access to input that will help you get weather-specific activities for any city. The tool uses agents to plan the activities, you just need to provide the city. Explain the weather report like a weather reporter. `, }); ``` ## 天気ツールの定義 場所の名前を入力として受け取り、詳細な天気情報を出力する天気ツールを定義します。 ```ts showLineNumbers copy filename="tools/weather-tool.ts" import { createTool } from "@mastra/core/tools"; import { z } from "zod"; interface GeocodingResponse { results: { latitude: number; longitude: number; name: string; }[]; } interface WeatherResponse { current: { time: string; temperature_2m: number; apparent_temperature: number; relative_humidity_2m: number; wind_speed_10m: number; wind_gusts_10m: number; weather_code: number; }; } // Create a tool to fetch weather data export const weatherTool = createTool({ id: "get-weather", description: "Get current weather for a location", inputSchema: z.object({ location: z.string().describe("City name"), }), outputSchema: z.object({ temperature: z.number(), feelsLike: z.number(), humidity: z.number(), windSpeed: z.number(), windGust: z.number(), conditions: z.string(), location: z.string(), }), execute: async ({ context }) => { return await getWeather(context.location); }, }); // Helper function to fetch weather data from external APIs const getWeather = async (location: string) => { const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(location)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = (await geocodingResponse.json()) as GeocodingResponse; if (!geocodingData.results?.[0]) { throw new Error(`Location '${location}' not found`); } const { latitude, longitude, name } = geocodingData.results[0]; const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m,wind_gusts_10m,weather_code`; const response = await fetch(weatherUrl); const data = (await response.json()) as WeatherResponse; return { temperature: data.current.temperature_2m, feelsLike: data.current.apparent_temperature, humidity: data.current.relative_humidity_2m, windSpeed: data.current.wind_speed_10m, windGust: data.current.wind_gusts_10m, conditions: getWeatherCondition(data.current.weather_code), location: name, }; }; // Helper function to convert numeric weather codes to human-readable descriptions function getWeatherCondition(code: number): string { const conditions: Record = { 0: "Clear sky", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast", 45: "Foggy", 48: "Depositing rime fog", 51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle", 56: "Light freezing drizzle", 57: "Dense freezing drizzle", 61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain", 66: "Light freezing rain", 67: "Heavy freezing rain", 71: "Slight snow fall", 73: "Moderate snow fall", 75: "Heavy snow fall", 77: "Snow grains", 80: "Slight rain showers", 81: "Moderate rain showers", 82: "Violent rain showers", 85: "Slight snow showers", 86: "Heavy snow showers", 95: "Thunderstorm", 96: "Thunderstorm with slight hail", 99: "Thunderstorm with heavy hail", }; return conditions[code] || "Unknown"; } ``` ## インターオプワークフローの定義 ステップとしてエージェントとツールを使用するワークフローを定義します。 ```ts showLineNumbers copy filename="workflows/interop-workflow.ts" import { createWorkflow, createStep } from "@mastra/core/workflows/vNext"; import { weatherTool } from "../tools/weather-tool"; import { weatherReporterAgent } from "../agents/weather-reporter-agent"; import { z } from "zod"; // Create workflow steps from existing tool and agent const fetchWeather = createStep(weatherTool); const reportWeather = createStep(weatherReporterAgent); const weatherWorkflow = createWorkflow({ steps: [fetchWeather, reportWeather], id: "weather-workflow-step1-single-day", inputSchema: z.object({ location: z.string().describe("The city to get the weather for"), }), outputSchema: z.object({ text: z.string(), }), }) .then(fetchWeather) .then( createStep({ id: "report-weather", inputSchema: fetchWeather.outputSchema, outputSchema: z.object({ text: z.string(), }), execute: async ({ inputData, mastra }) => { // Create a prompt with the weather data const prompt = "Forecast data: " + JSON.stringify(inputData); const agent = mastra.getAgent("weatherReporterAgent"); // Generate a weather report using the agent const result = await agent.generate([ { role: "user", content: prompt, }, ]); return { text: result.text }; }, }), ); weatherWorkflow.commit(); export { weatherWorkflow }; ``` ## Mastraクラスでワークフローインスタンスを登録する ワークフローをmastraインスタンスに登録します。 ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { PinoLogger } from "@mastra/loggers"; import { weatherWorkflow } from "./workflows/interop-workflow"; import { weatherReporterAgent } from "./agents/weather-reporter-agent"; // Create a new Mastra instance with our components const mastra = new Mastra({ vnext_workflows: { weatherWorkflow, }, agents: { weatherReporterAgent, }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## ワークフローを実行する ここでは、mastraインスタンスから天気ワークフローを取得し、実行を作成して、必要なinputDataで作成した実行を実行します。 ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; const workflow = mastra.vnext_getWorkflow("weatherWorkflow"); const run = workflow.createRun(); // Start the workflow with Lagos as the location const result = await run.start({ inputData: { location: "Lagos" } }); console.dir(result, { depth: null }); ``` --- title: "例: 配列を入力として使用する (.foreach()) | ワークフロー | Mastra ドキュメント" description: Mastraを使用してワークフローで.foreach()を使用して配列を処理する例。 --- # 配列を入力として [JA] Source: https://mastra.ai/ja/examples/workflows_vNext/array-as-input この例では、ワークフローで配列入力を処理する方法を示しています。Mastraは、配列内の各アイテムに対してステップを実行する`.foreach()`ヘルパー関数を提供しています。 ## セットアップ ```sh copy npm install @ai-sdk/openai @mastra/core simple-git ``` ## ドキュメント生成エージェントの定義 コードファイルまたはコードファイルの要約を与えられたときに、LLM呼び出しを活用してドキュメントを生成するドキュメント生成エージェントを定義します。 ```ts showLineNumbers copy filename="agents/docs-generator-agent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // Create a documentation generator agent for code analysis const docGeneratorAgent = new Agent({ name: "doc_generator_agent", instructions: `You are a technical documentation expert. You will analyze the provided code files and generate a comprehensive documentation summary. For each file: 1. Identify the main purpose and functionality 2. Document key components, classes, functions, and interfaces 3. Note important dependencies and relationships between components 4. Highlight any notable patterns or architectural decisions 5. Include relevant code examples where helpful Format the documentation in a clear, organized manner using markdown with: - File overviews - Component breakdowns - Code examples - Cross-references between related components Focus on making the documentation clear and useful for developers who need to understand and work with this codebase.`, model: openai("gpt-4o"), }); export { docGeneratorAgent }; ``` ## ファイルサマリーワークフローの定義 特定のファイルのコードを取得するステップと、そのコードファイルのREADMEを生成する別のステップという2つのステップでファイルサマリーワークフローを定義します。 ```ts showLineNumbers copy filename="workflows/file-summary-workflow.ts" import { createWorkflow, createStep } from "@mastra/core/workflows/vNext"; import { docGeneratorAgent } from "../agents/docs-generator-agent"; import { z } from "zod"; import fs from "fs"; // Step 1: Read the code content from a file const scrapeCodeStep = createStep({ id: "scrape_code", description: "Scrape the code from a single file", inputSchema: z.string(), outputSchema: z.object({ path: z.string(), content: z.string(), }), execute: async ({ inputData }) => { const filePath = inputData; const content = fs.readFileSync(filePath, "utf-8"); return { path: filePath, content, }; }, }); // Step 2: Generate documentation for a single file const generateDocForFileStep = createStep({ id: "generateDocForFile", inputSchema: z.object({ path: z.string(), content: z.string(), }), outputSchema: z.object({ path: z.string(), documentation: z.string(), }), execute: async ({ inputData }) => { const docs = await docGeneratorAgent.generate( `Generate documentation for the following code: ${inputData.content}`, ); return { path: inputData.path, documentation: docs.text.toString(), }; }, }); const generateSummaryWorkflow = createWorkflow({ id: "generate-summary", inputSchema: z.string(), outputSchema: z.object({ path: z.string(), documentation: z.string(), }), steps: [scrapeCodeStep, generateDocForFileStep], }) .then(scrapeCodeStep) .then(generateDocForFileStep) .commit(); export { generateSummaryWorkflow }; ``` ## READMEジェネレーターワークフローの定義 READMEジェネレーターワークフローを4つのステップで定義します:1つはGitHubリポジトリをクローンするステップ、1つはワークフローを一時停止してREADME生成時に考慮するフォルダに関するユーザー入力を取得するステップ、1つはフォルダ内のすべてのファイルの要約を生成するステップ、そして最後に各ファイルに対して生成されたすべてのドキュメントを1つのREADMEにまとめるステップです。 ```ts showLineNumbers copy filename="workflows/readme-generator-workflow.ts import { createWorkflow, createStep } from "@mastra/core/workflows/vNext"; import { docGeneratorAgent } from "../agents/docs-generator-agent"; import { generateSummaryWorkflow } from "./file-summary-workflow"; import { z } from "zod"; import simpleGit from "simple-git"; import fs from "fs"; import path from "path"; // Step 1: Clone a GitHub repository locally const cloneRepositoryStep = createStep({ id: "clone_repository", description: "Clone the repository from the given URL", inputSchema: z.object({ repoUrl: z.string(), }), outputSchema: z.object({ success: z.boolean(), message: z.string(), data: z.object({ repoUrl: z.string(), }), }), execute: async ({ inputData, mastra, getStepResult, getInitData, runtimeContext, }) => { const git = simpleGit(); // Skip cloning if repo already exists if (fs.existsSync("./temp")) { return { success: true, message: "Repository already exists", data: { repoUrl: inputData.repoUrl, }, }; } try { // Clone the repository to the ./temp directory await git.clone(inputData.repoUrl, "./temp"); return { success: true, message: "Repository cloned successfully", data: { repoUrl: inputData.repoUrl, }, }; } catch (error) { throw new Error(`Failed to clone repository: ${error}`); } }, }); // Step 2: Get user input on which folders to analyze const selectFolderStep = createStep({ id: "select_folder", description: "Select the folder(s) to generate the docs", inputSchema: z.object({ success: z.boolean(), message: z.string(), data: z.object({ repoUrl: z.string(), }), }), outputSchema: z.array(z.string()), suspendSchema: z.object({ folders: z.array(z.string()), message: z.string(), }), resumeSchema: z.object({ selection: z.array(z.string()), }), execute: async ({ resumeData, suspend }) => { const tempPath = "./temp"; const folders = fs .readdirSync(tempPath) .filter((item) => fs.statSync(path.join(tempPath, item)).isDirectory()); if (!resumeData?.selection) { await suspend({ folders, message: "ドキュメントを生成するフォルダを選択してください:", }); return []; } // Gather all file paths from selected folders const filePaths: string[] = []; // Helper function to recursively read files from directories const readFilesRecursively = (dir: string) => { const items = fs.readdirSync(dir); for (const item of items) { const fullPath = path.join(dir, item); const stat = fs.statSync(fullPath); if (stat.isDirectory()) { readFilesRecursively(fullPath); } else if (stat.isFile()) { filePaths.push(fullPath.replace(tempPath + "/", "")); } } }; for (const folder of resumeData.selection) { readFilesRecursively(path.join(tempPath, folder)); } return filePaths; }, }); // Step 4: Combine all documentation into a single README const collateDocumentationStep = createStep({ id: "collate_documentation", inputSchema: z.array( z.object({ path: z.string(), documentation: z.string(), }), ), outputSchema: z.string(), execute: async ({ inputData }) => { const readme = await docGeneratorAgent.generate( `以下のドキュメントに基づいてREADME.mdファイルを生成してください: ${inputData.map((doc) => doc.documentation).join("\n")}`, ); return readme.text.toString(); }, }); const readmeGeneratorWorkflow = createWorkflow({ id: "readme-generator", inputSchema: z.object({ repoUrl: z.string(), }), outputSchema: z.object({ success: z.boolean(), message: z.string(), data: z.object({ repoUrl: z.string(), }), }), steps: [ cloneRepositoryStep, selectFolderStep, generateSummaryWorkflow, collateDocumentationStep, ], }) .then(cloneRepositoryStep) .then(selectFolderStep) .foreach(generateSummaryWorkflow) .then(collateDocumentationStep) .commit(); export { readmeGeneratorWorkflow }; ``` ## Mastraクラスでエージェントとワークフローのインスタンスを登録する エージェントとワークフローをmastraインスタンスに登録します。これはワークフロー内でエージェントへのアクセスを可能にするために重要です。 ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core"; import { PinoLogger } from "@mastra/loggers"; import { docGeneratorAgent } from "./agents/docs-generator-agent"; import { readmeGeneratorWorkflow } from "./workflows/readme-generator-workflow"; import { generateSummaryWorkflow } from "./workflows/file-summary-workflow"; // Create a new Mastra instance and register components const mastra = new Mastra({ agents: { docGeneratorAgent, }, vnext_workflows: { readmeGeneratorWorkflow, generateSummaryWorkflow, }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## Readme Generator ワークフローを実行する ここでは、mastraインスタンスからreadme generatorワークフローを取得し、実行を作成して、必要なinputDataで作成した実行を実行します。 ```ts showLineNumbers copy filename="exec.ts" import { promptUserForFolders } from "./utils"; import { mastra } from "./"; // GitHub repository to generate documentation for const ghRepoUrl = "https://github.com/mastra-ai/mastra"; const run = mastra.vnext_getWorkflow("readmeGeneratorWorkflow").createRun(); // Start the workflow with the repository URL as input const res = await run.start({ inputData: { repoUrl: ghRepoUrl } }); const { status, steps } = res; // Handle suspended workflow (waiting for user input) if (status === "suspended") { // Get the suspended step data const suspendedStep = steps["select_folder"]; let folderList: string[] = []; // Extract the folder list from step data if ( suspendedStep.status === "suspended" && "folders" in suspendedStep.payload ) { folderList = suspendedStep.payload.folders as string[]; } else if (suspendedStep.status === "success" && suspendedStep.output) { folderList = suspendedStep.output; } if (!folderList.length) { console.log("No folders available for selection."); process.exit(1); } // Prompt user to select folders const folders = await promptUserForFolders(folderList); // Resume the workflow with user selections const resumedResult = await run.resume({ resumeData: { selection: folders }, step: "select_folder", }); // Print resumed result if (resumedResult.status === "success") { console.log(resumedResult.result); } else { console.log(resumedResult); } process.exit(1); } // Handle completed workflow if (res.status === "success") { console.log(res.result ?? res); } else { console.log(res); } ``` --- title: "例:ワークフローからエージェントを呼び出す | Mastra ドキュメント" description: ワークフローステップ内からAIエージェントを呼び出すためのMastraの使用例。 --- # ワークフローからエージェントを呼び出す [JA] Source: https://mastra.ai/ja/examples/workflows_vNext/calling-agent この例では、提供された天候条件に基づいてアクティビティを提案するAIエージェントを呼び出すワークフローを作成し、ワークフローステップ内で実行する方法を示しています。 ## セットアップ ```sh copy npm install @ai-sdk/openai @mastra/core ``` ## プランニングエージェントの定義 場所と対応する気象条件に基づいて活動を計画するためにLLM呼び出しを活用するプランニングエージェントを定義します。 ```ts showLineNumbers copy filename="agents/planning-agent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const llm = openai("gpt-4o"); // Create a new agent for activity planning const planningAgent = new Agent({ name: "planningAgent", model: llm, instructions: ` You are a local activities and travel expert who excels at weather-based planning. Analyze the weather data and provide practical activity recommendations. 📅 [Day, Month Date, Year] ═══════════════════════════ 🌡️ WEATHER SUMMARY • Conditions: [brief description] • Temperature: [X°C/Y°F to A°C/B°F] • Precipitation: [X% chance] 🌅 MORNING ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🌞 AFTERNOON ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🏠 INDOOR ALTERNATIVES • [Activity Name] - [Brief description including specific venue] Ideal for: [weather condition that would trigger this alternative] ⚠️ SPECIAL CONSIDERATIONS • [Any relevant weather warnings, UV index, wind conditions, etc.] Guidelines: - Suggest 2-3 time-specific outdoor activities per day - Include 1-2 indoor backup options - For precipitation >50%, lead with indoor activities - All activities must be specific to the location - Include specific venues, trails, or locations - Consider activity intensity based on temperature - Keep descriptions concise but informative Maintain this exact formatting for consistency, using the emoji and section headers as shown. `, }); export { planningAgent }; ``` ## アクティビティプランニングワークフローの定義 アクティビティプランニングワークフローを2つのステップで定義します:1つはネットワーク呼び出しを介して天気を取得するステップ、もう1つはプランニングエージェントを使用してアクティビティを計画するステップです。 ```ts showLineNumbers copy filename="workflows/agent-workflow.ts" import { createWorkflow, createStep } from "@mastra/core/workflows/vNext"; import { z } from "zod"; // 数値の天気コードを人間が読める説明に変換するヘルパー関数 function getWeatherCondition(code: number): string { const conditions: Record = { 0: "Clear sky", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast", 45: "Foggy", 48: "Depositing rime fog", 51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle", 61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain", 71: "Slight snow fall", 73: "Moderate snow fall", 75: "Heavy snow fall", 95: "Thunderstorm", }; return conditions[code] || "Unknown"; } const forecastSchema = z.object({ date: z.string(), maxTemp: z.number(), minTemp: z.number(), precipitationChance: z.number(), condition: z.string(), location: z.string(), }); // ステップ1:指定された都市の天気データを取得するステップを作成 const fetchWeather = createStep({ id: "fetch-weather", description: "指定された都市の天気予報を取得します", inputSchema: z.object({ city: z.string(), }), outputSchema: forecastSchema, execute: async ({ inputData }) => { if (!inputData) { throw new Error("トリガーデータが見つかりません"); } // 最初のAPI呼び出し:都市名を緯度と経度に変換 const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(inputData.city)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = (await geocodingResponse.json()) as { results: { latitude: number; longitude: number; name: string }[]; }; if (!geocodingData.results?.[0]) { throw new Error(`場所 '${inputData.city}' が見つかりません`); } const { latitude, longitude, name } = geocodingData.results[0]; // 2番目のAPI呼び出し:座標を使用して天気データを取得 const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=precipitation,weathercode&timezone=auto,&hourly=precipitation_probability,temperature_2m`; const response = await fetch(weatherUrl); const data = (await response.json()) as { current: { time: string; precipitation: number; weathercode: number; }; hourly: { precipitation_probability: number[]; temperature_2m: number[]; }; }; const forecast = { date: new Date().toISOString(), maxTemp: Math.max(...data.hourly.temperature_2m), minTemp: Math.min(...data.hourly.temperature_2m), condition: getWeatherCondition(data.current.weathercode), location: name, precipitationChance: data.hourly.precipitation_probability.reduce( (acc, curr) => Math.max(acc, curr), 0, ), }; return forecast; }, }); // ステップ2:エージェントを使用してアクティビティの推奨事項を生成するステップを作成 const planActivities = createStep({ id: "plan-activities", description: "天候に基づいてアクティビティを提案します", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("予報データが見つかりません"); } const prompt = `${forecast.location}の以下の天気予報に基づいて、適切なアクティビティを提案してください: ${JSON.stringify(forecast, null, 2)} `; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("プランニングエージェントが見つかりません"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); const activityPlanningWorkflow = createWorkflow({ steps: [fetchWeather, planActivities], id: "activity-planning-step1-single-day", inputSchema: z.object({ city: z.string().describe("天気を取得する都市"), }), outputSchema: z.object({ activities: z.string(), }), }) .then(fetchWeather) .then(planActivities); activityPlanningWorkflow.commit(); export { activityPlanningWorkflow }; ``` ## Mastraクラスにエージェントとワークフローのインスタンスを登録する プランニングエージェントとアクティビティプランニングワークフローをmastraインスタンスに登録します。 これはアクティビティプランニングワークフロー内でプランニングエージェントへのアクセスを可能にするために重要です。 ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { PinoLogger } from "@mastra/loggers"; import { activityPlanningWorkflow } from "./workflows/agent-workflow"; import { planningAgent } from "./agents/planning-agent"; // Create a new Mastra instance and register components const mastra = new Mastra({ vnext_workflows: { activityPlanningWorkflow, }, agents: { planningAgent, }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## アクティビティプランニングワークフローを実行する ここでは、mastraインスタンスからアクティビティプランニングワークフローを取得し、実行を作成して、必要なinputDataで作成した実行を実行します。 ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; const workflow = mastra.vnext_getWorkflow("activityPlanningWorkflow"); const run = workflow.createRun(); // Start the workflow with New York as the city input const result = await run.start({ inputData: { city: "New York" } }); console.dir(result, { depth: null }); ``` --- title: "例:条件分岐 | ワークフロー | Mastra ドキュメント" description: Mastraを使用して`branch`ステートメントによりワークフローに条件分岐を作成する例。 --- # 条件分岐を持つワークフロー [JA] Source: https://mastra.ai/ja/examples/workflows_vNext/conditional-branching ワークフローは、しばしば何らかの条件に基づいて異なるパスをたどる必要があります。 この例では、ワークフロー内に条件付きフローを作成するために `branch` 構造をどのように使用するかを示しています。 ## セットアップ ```sh copy npm install @ai-sdk/openai @mastra/core ``` ## プランニングエージェントの定義 場所と対応する天候条件に基づいて活動を計画するためにLLMコールを活用するプランニングエージェントを定義します。 ```ts showLineNumbers copy filename="agents/planning-agent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const llm = openai("gpt-4o"); // Define the planning agent that generates activity recommendations // based on weather conditions and location const planningAgent = new Agent({ name: "planningAgent", model: llm, instructions: ` You are a local activities and travel expert who excels at weather-based planning. Analyze the weather data and provide practical activity recommendations. 📅 [Day, Month Date, Year] ═══════════════════════════ 🌡️ WEATHER SUMMARY • Conditions: [brief description] • Temperature: [X°C/Y°F to A°C/B°F] • Precipitation: [X% chance] 🌅 MORNING ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🌞 AFTERNOON ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🏠 INDOOR ALTERNATIVES • [Activity Name] - [Brief description including specific venue] Ideal for: [weather condition that would trigger this alternative] ⚠️ SPECIAL CONSIDERATIONS • [Any relevant weather warnings, UV index, wind conditions, etc.] Guidelines: - Suggest 2-3 time-specific outdoor activities per day - Include 1-2 indoor backup options - For precipitation >50%, lead with indoor activities - All activities must be specific to the location - Include specific venues, trails, or locations - Consider activity intensity based on temperature - Keep descriptions concise but informative Maintain this exact formatting for consistency, using the emoji and section headers as shown. `, }); export { planningAgent }; ``` ## アクティビティ計画ワークフローの定義 計画ワークフローを3つのステップで定義します:1つはネットワーク呼び出しを介して天気を取得するステップ、1つはアクティビティを計画するステップ、そしてもう1つは屋内アクティビティのみを計画するステップです。 どちらも計画エージェントを使用します。 ```ts showLineNumbers copy filename="workflows/conditional-workflow.ts" import { z } from "zod"; import { createWorkflow, createStep } from "@mastra/core/workflows/vNext"; // Helper function to convert weather codes to human-readable conditions function getWeatherCondition(code: number): string { const conditions: Record = { 0: "Clear sky", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast", 45: "Foggy", 48: "Depositing rime fog", 51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle", 61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain", 71: "Slight snow fall", 73: "Moderate snow fall", 75: "Heavy snow fall", 95: "Thunderstorm", }; return conditions[code] || "Unknown"; } const forecastSchema = z.object({ date: z.string(), maxTemp: z.number(), minTemp: z.number(), precipitationChance: z.number(), condition: z.string(), location: z.string(), }); // Step to fetch weather data for a given city // Makes API calls to get current weather conditions and forecast const fetchWeather = createStep({ id: "fetch-weather", description: "Fetches weather forecast for a given city", inputSchema: z.object({ city: z.string(), }), outputSchema: forecastSchema, execute: async ({ inputData }) => { if (!inputData) { throw new Error("Trigger data not found"); } const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(inputData.city)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = (await geocodingResponse.json()) as { results: { latitude: number; longitude: number; name: string }[]; }; if (!geocodingData.results?.[0]) { throw new Error(`Location '${inputData.city}' not found`); } const { latitude, longitude, name } = geocodingData.results[0]; const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=precipitation,weathercode&timezone=auto,&hourly=precipitation_probability,temperature_2m`; const response = await fetch(weatherUrl); const data = (await response.json()) as { current: { time: string; precipitation: number; weathercode: number; }; hourly: { precipitation_probability: number[]; temperature_2m: number[]; }; }; const forecast = { date: new Date().toISOString(), maxTemp: Math.max(...data.hourly.temperature_2m), minTemp: Math.min(...data.hourly.temperature_2m), condition: getWeatherCondition(data.current.weathercode), location: name, precipitationChance: data.hourly.precipitation_probability.reduce( (acc, curr) => Math.max(acc, curr), 0, ), }; return forecast; }, }); // Step to plan activities based on weather conditions // Uses the planning agent to generate activity recommendations const planActivities = createStep({ id: "plan-activities", description: "Suggests activities based on weather conditions", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `Based on the following weather forecast for ${forecast.location}, suggest appropriate activities: ${JSON.stringify(forecast, null, 2)} `; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); // Step to plan indoor activities only // Used when precipitation chance is high const planIndoorActivities = createStep({ id: "plan-indoor-activities", description: "天候状況に基づいて屋内活動を提案します", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `雨が降った場合、${forecast.location}の${forecast.date}における屋内活動を計画してください`; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); // Main workflow that: // 1. Fetches weather data // 2. Branches based on precipitation chance: // - If >50%: Plans indoor activities // - If <=50%: Plans outdoor activities const activityPlanningWorkflow = createWorkflow({ id: "activity-planning-workflow-step2-if-else", inputSchema: z.object({ city: z.string().describe("天気を取得する都市"), }), outputSchema: z.object({ activities: z.string(), }), }) .then(fetchWeather) .branch([ // Branch for high precipitation (indoor activities) [ async ({ inputData }) => { return inputData?.precipitationChance > 50; }, planIndoorActivities, ], // Branch for low precipitation (outdoor activities) [ async ({ inputData }) => { return inputData?.precipitationChance <= 50; }, planActivities, ], ]); activityPlanningWorkflow.commit(); export { activityPlanningWorkflow }; ``` ## Mastraクラスでエージェントとワークフローのインスタンスを登録する エージェントとワークフローをmastraインスタンスに登録します。 これはワークフロー内でエージェントへのアクセスを可能にするために重要です。 ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { PinoLogger } from "@mastra/loggers"; import { activityPlanningWorkflow } from "./workflows/conditional-workflow"; import { planningAgent } from "./agents/planning-agent"; // Initialize Mastra with the activity planning workflow // This enables the workflow to be executed and access the planning agent const mastra = new Mastra({ vnext_workflows: { activityPlanningWorkflow, }, agents: { planningAgent, }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## アクティビティプランニングワークフローを実行する ここでは、mastraインスタンスからアクティビティプランニングワークフローを取得し、実行を作成して、必要な入力データで作成した実行を実行します。 ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; const workflow = mastra.vnext_getWorkflow("activityPlanningWorkflow"); const run = workflow.createRun(); // Start the workflow with a city // This will fetch weather and plan activities based on conditions const result = await run.start({ inputData: { city: "New York" } }); console.dir(result, { depth: null }); ``` --- title: "例:制御フロー | ワークフロー | Mastra ドキュメント" description: 提供された条件に基づいてループを持つワークフローを作成するためにMastraを使用する例。 --- # ステップ実行のループ処理 [JA] Source: https://mastra.ai/ja/examples/workflows_vNext/control-flow ## セットアップ ```sh copy npm install @ai-sdk/openai @mastra/core ``` ## ループ実行ワークフローの定義 提供された条件が満たされるまでネストされたワークフローを実行するワークフローを定義します。 ```ts showLineNumbers copy filename="looping-workflow.ts" import { createWorkflow, createStep } from "@mastra/core/workflows/vNext"; import { z } from "zod"; // Step that increments the input value by 1 const incrementStep = createStep({ id: "increment", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), execute: async ({ inputData }) => { return { value: inputData.value + 1 }; }, }); // Step that logs the current value (side effect) const sideEffectStep = createStep({ id: "side-effect", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), execute: async ({ inputData }) => { console.log("log", inputData.value); return { value: inputData.value }; }, }); // Final step that returns the final value const finalStep = createStep({ id: "final", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), execute: async ({ inputData }) => { return { value: inputData.value }; }, }); // Create a workflow that: // 1. Increments a number until it reaches 10 // 2. Logs each increment (side effect) // 3. Returns the final value const workflow = createWorkflow({ id: "increment-workflow", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), }) .dountil( // Nested workflow that performs the increment and logging createWorkflow({ id: "increment-workflow", inputSchema: z.object({ value: z.number(), }), outputSchema: z.object({ value: z.number(), }), steps: [incrementStep, sideEffectStep], }) .then(incrementStep) .then(sideEffectStep) .commit(), // Condition to check if we should stop the loop async ({ inputData }) => inputData.value >= 10, ) .then(finalStep); workflow.commit(); export { workflow as incrementWorkflow }; ``` ## MastraクラスでWorkflowインスタンスを登録する ワークフローをmastraインスタンスに登録します。 ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { PinoLogger } from "@mastra/loggers"; import { incrementWorkflow } from "./workflows"; // Initialize Mastra with the increment workflow // This enables the workflow to be executed const mastra = new Mastra({ vnext_workflows: { incrementWorkflow, }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## ワークフローを実行する ここでは、mastraインスタンスからインクリメントワークフローを取得し、実行を作成して、必要なinputDataで作成した実行を実行します。 ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; const workflow = mastra.vnext_getWorkflow("incrementWorkflow"); const run = workflow.createRun(); // Start the workflow with initial value 0 // This will increment until reaching 10 const result = await run.start({ inputData: { value: 0 } }); console.dir(result, { depth: null }); ``` --- title: "例:ヒューマン・イン・ザ・ループ | ワークフロー | Mastra ドキュメント" description: 人間の介入ポイントを含むワークフローを作成するためのMastraの使用例。 --- # ヒューマン・イン・ザ・ループ ワークフロー [JA] Source: https://mastra.ai/ja/examples/workflows_vNext/human-in-the-loop ヒューマン・イン・ザ・ループのワークフローでは、特定のポイントで実行を一時停止し、ユーザー入力を収集したり、判断を下したり、人間の判断を必要とするアクションを実行したりすることができます。 この例では、人間の介入ポイントを含むワークフローを作成する方法を示しています。 ## セットアップ ```sh copy npm install @ai-sdk/openai @mastra/core @inquirer/prompts ``` ## エージェントの定義 旅行エージェントを定義します。 ```ts showLineNumbers copy filename="agents/travel-agents.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const llm = openai("gpt-4o"); // Agent that generates multiple holiday options // Returns a JSON array of locations and descriptions export const summaryTravelAgent = new Agent({ name: "summaryTravelAgent", model: llm, instructions: ` You are a travel agent who is given a user prompt about what kind of holiday they want to go on. You then generate 3 different options for the holiday. Return the suggestions as a JSON array {"location": "string", "description": "string"}[]. Don't format as markdown. Make the options as different as possible from each other. Also make the plan very short and summarized. `, }); // Agent that creates detailed travel plans // Takes the selected option and generates a comprehensive itinerary export const travelAgent = new Agent({ name: "travelAgent", model: llm, instructions: ` You are a travel agent who is given a user prompt about what kind of holiday they want to go on. A summary of the plan is provided as well as the location. You then generate a detailed travel plan for the holiday. `, }); ``` ## 一時停止可能なワークフローの定義 一時停止ステップ(`humanInputStep`)を含むワークフローを定義します。 ```ts showLineNumbers copy filename="workflows/human-in-the-loop-workflow.ts" import { createWorkflow, createStep } from "@mastra/core/workflows/vNext"; import { z } from "zod"; // Step that generates multiple holiday options based on user's vacation description // Uses the summaryTravelAgent to create diverse travel suggestions const generateSuggestionsStep = createStep({ id: "generate-suggestions", inputSchema: z.object({ vacationDescription: z.string().describe("The description of the vacation"), }), outputSchema: z.object({ suggestions: z.array(z.string()), vacationDescription: z.string(), }), execute: async ({ inputData, mastra }) => { if (!mastra) { throw new Error("Mastra is not initialized"); } const { vacationDescription } = inputData; const result = await mastra.getAgent("summaryTravelAgent").generate([ { role: "user", content: vacationDescription, }, ]); console.log(result.text); return { suggestions: JSON.parse(result.text), vacationDescription }; }, }); // Step that pauses the workflow to get user input // Allows the user to select their preferred holiday option from the suggestions // Uses suspend/resume mechanism to handle the interaction const humanInputStep = createStep({ id: "human-input", inputSchema: z.object({ suggestions: z.array(z.string()), vacationDescription: z.string(), }), outputSchema: z.object({ selection: z.string().describe("The selection of the user"), vacationDescription: z.string(), }), resumeSchema: z.object({ selection: z.string().describe("The selection of the user"), }), suspendSchema: z.object({ suggestions: z.array(z.string()), }), execute: async ({ inputData, resumeData, suspend, getInitData }) => { if (!resumeData?.selection) { await suspend({ suggestions: inputData?.suggestions }); return { selection: "", vacationDescription: inputData?.vacationDescription, }; } return { selection: resumeData?.selection, vacationDescription: inputData?.vacationDescription, }; }, }); // Step that creates a detailed travel plan based on the user's selection // Uses the travelAgent to generate comprehensive holiday details const travelPlannerStep = createStep({ id: "travel-planner", inputSchema: z.object({ selection: z.string().describe("The selection of the user"), vacationDescription: z.string(), }), outputSchema: z.object({ travelPlan: z.string(), }), execute: async ({ inputData, mastra }) => { const travelAgent = mastra?.getAgent("travelAgent"); if (!travelAgent) { throw new Error("Travel agent is not initialized"); } const { selection, vacationDescription } = inputData; const result = await travelAgent.generate([ { role: "assistant", content: vacationDescription }, { role: "user", content: selection || "" }, ]); console.log(result.text); return { travelPlan: result.text }; }, }); // Main workflow that orchestrates the holiday planning process: // 1. Generates multiple options // 2. Gets user input // 3. Creates detailed plan const travelAgentWorkflow = createWorkflow({ id: "travel-agent-workflow", inputSchema: z.object({ vacationDescription: z.string().describe("The description of the vacation"), }), outputSchema: z.object({ travelPlan: z.string(), }), }) .then(generateSuggestionsStep) .then(humanInputStep) .then(travelPlannerStep); travelAgentWorkflow.commit(); export { travelAgentWorkflow, humanInputStep }; ``` ## Mastraクラスでエージェントとワークフローのインスタンスを登録する エージェントと天気ワークフローをmastraインスタンスに登録します。 これはワークフロー内でエージェントにアクセスできるようにするために重要です。 ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { PinoLogger } from "@mastra/loggers"; import { travelAgentWorkflow } from "./workflows/human-in-the-loop-workflow"; import { summaryTravelAgent, travelAgent } from "./agents/travel-agent"; // Initialize Mastra instance with: // - The travel planning workflow // - Both travel agents (summary and detailed planning) // - Logging configuration const mastra = new Mastra({ vnext_workflows: { travelAgentWorkflow, }, agents: { travelAgent, summaryTravelAgent, }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## 一時停止可能な天気ワークフローを実行する ここでは、mastraインスタンスから天気ワークフローを取得し、実行を作成して、必要な入力データで作成した実行を実行します。 さらに、readlineパッケージを使用してユーザー入力を収集した後、`humanInputStep`を再開します。 ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; import { select } from "@inquirer/prompts"; import { humanInputStep } from "./workflows/human-in-the-loop-workflow"; const workflow = mastra.vnext_getWorkflow("travelAgentWorkflow"); const run = workflow.createRun({}); // Start the workflow with initial vacation description const result = await run.start({ inputData: { vacationDescription: "I want to go to the beach" }, }); console.log("result", result); const suggStep = result?.steps?.["generate-suggestions"]; // If suggestions were generated successfully, proceed with user interaction if (suggStep.status === "success") { const suggestions = suggStep.output?.suggestions; // Present options to user and get their selection const userInput = await select({ message: "Choose your holiday destination", choices: suggestions.map( ({ location, description }: { location: string; description: string }) => `- ${location}: ${description}`, ), }); console.log("Selected:", userInput); // Prepare to resume the workflow with user's selection console.log("resuming from", result, "with", { inputData: { selection: userInput, vacationDescription: "I want to go to the beach", suggestions: suggStep?.output?.suggestions, }, step: humanInputStep, }); const result2 = await run.resume({ resumeData: { selection: userInput, }, step: humanInputStep, }); console.dir(result2, { depth: null }); } ``` ヒューマン・イン・ザ・ループのワークフローは、以下のような自動化と人間の判断を組み合わせたシステムを構築するのに強力です: - コンテンツモデレーションシステム - 承認ワークフロー - 監視付きAIシステム - エスカレーション機能を持つカスタマーサービスの自動化 --- title: "Inngest ワークフロー | ワークフロー | Mastra ドキュメント" description: Mastraを使用したinngestワークフローの構築例 --- # Inngest ワークフロー [JA] Source: https://mastra.ai/ja/examples/workflows_vNext/inngest-workflow この例では、Mastraを使用してInngestワークフローを構築する方法を示しています。 ## セットアップ ```sh copy npm install @mastra/inngest @mastra/core @mastra/deployer @hono/node-server @ai-sdk/openai docker run --rm -p 8288:8288 \ inngest/inngest \ inngest dev -u http://host.docker.internal:3000/inngest/api ``` あるいは、ローカル開発には公式の[Inngest Dev Serverガイド](https://www.inngest.com/docs/dev-server)に従ってInngest CLIを使用することもできます。 ## プランニングエージェントの定義 場所と対応する天候条件に基づいてアクティビティを計画するためにLLMコールを活用するプランニングエージェントを定義します。 ```ts showLineNumbers copy filename="agents/planning-agent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // Create a new planning agent that uses the OpenAI model const planningAgent = new Agent({ name: "planningAgent", model: openai("gpt-4o"), instructions: ` You are a local activities and travel expert who excels at weather-based planning. Analyze the weather data and provide practical activity recommendations. 📅 [Day, Month Date, Year] ═══════════════════════════ 🌡️ WEATHER SUMMARY • Conditions: [brief description] • Temperature: [X°C/Y°F to A°C/B°F] • Precipitation: [X% chance] 🌅 MORNING ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🌞 AFTERNOON ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🏠 INDOOR ALTERNATIVES • [Activity Name] - [Brief description including specific venue] Ideal for: [weather condition that would trigger this alternative] ⚠️ SPECIAL CONSIDERATIONS • [Any relevant weather warnings, UV index, wind conditions, etc.] Guidelines: - Suggest 2-3 time-specific outdoor activities per day - Include 1-2 indoor backup options - For precipitation >50%, lead with indoor activities - All activities must be specific to the location - Include specific venues, trails, or locations - Consider activity intensity based on temperature - Keep descriptions concise but informative Maintain this exact formatting for consistency, using the emoji and section headers as shown. `, }); export { planningAgent }; ``` ## アクティビティプランナーワークフローを定義する 3つのステップでアクティビティプランナーワークフローを定義します:ネットワーク呼び出しで天気を取得するステップ、アクティビティを計画するステップ、そして屋内アクティビティのみを計画するステップです。 ```ts showLineNumbers copy filename="workflows/inngest-workflow.ts" import { z } from "zod"; const { createWorkflow, createStep } = init( new Inngest({ id: "mastra", baseUrl: `http://localhost:8288`, }), ); // Helper function to convert weather codes to human-readable descriptions function getWeatherCondition(code: number): string { const conditions: Record = { 0: "Clear sky", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast", 45: "Foggy", 48: "Depositing rime fog", 51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle", 61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain", 71: "Slight snow fall", 73: "Moderate snow fall", 75: "Heavy snow fall", 95: "Thunderstorm", }; return conditions[code] || "Unknown"; } const forecastSchema = z.object({ date: z.string(), maxTemp: z.number(), minTemp: z.number(), precipitationChance: z.number(), condition: z.string(), location: z.string(), }); ``` #### ステップ1:指定された都市の天気データを取得する ```ts showLineNumbers copy filename="workflows/inngest-workflow.ts" const fetchWeather = createStep({ id: "fetch-weather", description: "Fetches weather forecast for a given city", inputSchema: z.object({ city: z.string(), }), outputSchema: forecastSchema, execute: async ({ inputData }) => { if (!inputData) { throw new Error("Trigger data not found"); } // Get latitude and longitude for the city const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(inputData.city)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = (await geocodingResponse.json()) as { results: { latitude: number; longitude: number; name: string }[]; }; if (!geocodingData.results?.[0]) { throw new Error(`Location '${inputData.city}' not found`); } const { latitude, longitude, name } = geocodingData.results[0]; // Fetch weather data using the coordinates const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=precipitation,weathercode&timezone=auto,&hourly=precipitation_probability,temperature_2m`; const response = await fetch(weatherUrl); const data = (await response.json()) as { current: { time: string; precipitation: number; weathercode: number; }; hourly: { precipitation_probability: number[]; temperature_2m: number[]; }; }; const forecast = { date: new Date().toISOString(), maxTemp: Math.max(...data.hourly.temperature_2m), minTemp: Math.min(...data.hourly.temperature_2m), condition: getWeatherCondition(data.current.weathercode), location: name, precipitationChance: data.hourly.precipitation_probability.reduce( (acc, curr) => Math.max(acc, curr), 0, ), }; return forecast; }, }); ``` #### ステップ2:天気に基づいてアクティビティ(屋内または屋外)を提案する ```ts showLineNumbers copy filename="workflows/inngest-workflow.ts" const planActivities = createStep({ id: "plan-activities", description: "Suggests activities based on weather conditions", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `Based on the following weather forecast for ${forecast.location}, suggest appropriate activities: ${JSON.stringify(forecast, null, 2)} `; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); ``` #### ステップ3:室内アクティビティのみを提案する(雨天時用) ```ts showLineNumbers copy filename="workflows/inngest-workflow.ts" const planIndoorActivities = createStep({ id: "plan-indoor-activities", description: "Suggests indoor activities based on weather conditions", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `In case it rains, plan indoor activities for ${forecast.location} on ${forecast.date}`; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); ``` ## アクティビティプランナーワークフローを定義する ```ts showLineNumbers copy filename="workflows/inngest-workflow.ts" const activityPlanningWorkflow = createWorkflow({ id: "activity-planning-workflow-step2-if-else", inputSchema: z.object({ city: z.string().describe("The city to get the weather for"), }), outputSchema: z.object({ activities: z.string(), }), }) .then(fetchWeather) .branch([ [ // If precipitation chance is greater than 50%, suggest indoor activities async ({ inputData }) => { return inputData?.precipitationChance > 50; }, planIndoorActivities, ], [ // Otherwise, suggest a mix of activities async ({ inputData }) => { return inputData?.precipitationChance <= 50; }, planActivities, ], ]); activityPlanningWorkflow.commit(); export { activityPlanningWorkflow }; ``` ## Mastraクラスでエージェントとワークフローのインスタンスを登録する エージェントとワークフローをmastraインスタンスに登録します。これにより、ワークフロー内でエージェントにアクセスできるようになります。 ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { serve as inngestServe } from "@mastra/inngest"; import { PinoLogger } from "@mastra/loggers"; import { Inngest } from "inngest"; import { activityPlanningWorkflow } from "./workflows/inngest-workflow"; import { planningAgent } from "./agents/planning-agent"; import { realtimeMiddleware } from "@inngest/realtime"; // Create an Inngest instance for workflow orchestration and event handling const inngest = new Inngest({ id: "mastra", baseUrl: `http://localhost:8288`, // URL of your local Inngest server isDev: true, middleware: [realtimeMiddleware()], // Enable real-time updates in the Inngest dashboard }); // Create and configure the main Mastra instance export const mastra = new Mastra({ vnext_workflows: { activityPlanningWorkflow, }, agents: { planningAgent, }, server: { host: "0.0.0.0", apiRoutes: [ { path: "/api/inngest", // API endpoint for Inngest to send events to method: "ALL", createHandler: async ({ mastra }) => inngestServe({ mastra, inngest }), }, ], }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); ``` ## アクティビティプランナーワークフローを実行する ここでは、mastraインスタンスからアクティビティプランナーワークフローを取得し、実行を作成して、必要な入力データで作成した実行を実行します。 ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; import { serve } from "@hono/node-server"; import { createHonoServer } from "@mastra/deployer/server"; const app = await createHonoServer(mastra); // Start the server on port 3000 so Inngest can send events to it const srv = serve({ fetch: app.fetch, port: 3000, }); const workflow = mastra.vnext_getWorkflow("activityPlanningWorkflow"); const run = workflow.createRun({}); // Start the workflow with the required input data (city name) // This will trigger the workflow steps and stream the result to the console const result = await run.start({ inputData: { city: "New York" } }); console.dir(result, { depth: null }); // Close the server after the workflow run is complete srv.close(); ``` ワークフローを実行した後、[http://localhost:8288](http://localhost:8288)のInngestダッシュボードを使用して、ワークフローの実行をリアルタイムで表示および監視できます。 --- title: "例: 並列実行 | ワークフロー | Mastra ドキュメント" description: Mastraを使用してワークフロー内で複数の独立したタスクを並列実行する例。 --- # ステップによる並列実行 [JA] Source: https://mastra.ai/ja/examples/workflows_vNext/parallel-steps AI アプリケーションを構築する際、効率を向上させるために複数の独立したタスクを同時に処理する必要がよくあります。 私たちはこの機能を `.parallel` メソッドを通じてワークフローの中核部分としています。 ## セットアップ ```sh copy npm install @ai-sdk/openai @mastra/core ``` ## プランニングエージェントの定義 場所と対応する天気状況を考慮して活動を計画するために、LLM呼び出しを活用するプランニングエージェントを定義します。 ```ts showLineNumbers copy filename="agents/planning-agent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const llm = openai("gpt-4o"); // Define the planning agent with specific instructions for formatting // and structuring weather-based activity recommendations const planningAgent = new Agent({ name: "planningAgent", model: llm, instructions: ` You are a local activities and travel expert who excels at weather-based planning. Analyze the weather data and provide practical activity recommendations. 📅 [Day, Month Date, Year] ═══════════════════════════ 🌡️ WEATHER SUMMARY • Conditions: [brief description] • Temperature: [X°C/Y°F to A°C/B°F] • Precipitation: [X% chance] 🌅 MORNING ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🌞 AFTERNOON ACTIVITIES Outdoor: • [Activity Name] - [Brief description including specific location/route] Best timing: [specific time range] Note: [relevant weather consideration] 🏠 INDOOR ALTERNATIVES • [Activity Name] - [Brief description including specific venue] Ideal for: [weather condition that would trigger this alternative] ⚠️ SPECIAL CONSIDERATIONS • [Any relevant weather warnings, UV index, wind conditions, etc.] Guidelines: - Suggest 2-3 time-specific outdoor activities per day - Include 1-2 indoor backup options - For precipitation >50%, lead with indoor activities - All activities must be specific to the location - Include specific venues, trails, or locations - Consider activity intensity based on temperature - Keep descriptions concise but informative Maintain this exact formatting for consistency, using the emoji and section headers as shown. `, }); export { planningAgent }; ``` ## 統合エージェントの定義 計画された屋内および屋外活動を受け取り、一日の完全なレポートを提供する統合エージェントを定義します。 ```ts showLineNumbers copy filename="agents/synthesize-agent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const llm = openai("gpt-4o"); // Define the synthesize agent that combines indoor and outdoor activity plans // into a comprehensive report, considering weather conditions and alternatives const synthesizeAgent = new Agent({ name: "synthesizeAgent", model: llm, instructions: ` You are given two different blocks of text, one about indoor activities and one about outdoor activities. Make this into a full report about the day and the possibilities depending on whether it rains or not. `, }); export { synthesizeAgent }; ``` ## 並列ワークフローの定義 ここでは、プランニングステップと合成ステップの間の並列→逐次フローを調整するワークフローを定義します。 ```ts showLineNumbers copy filename="workflows/parallel-workflow.ts" import { z } from "zod"; import { createStep, createWorkflow } from "@mastra/core/workflows/vNext"; const forecastSchema = z.object({ date: z.string(), maxTemp: z.number(), minTemp: z.number(), precipitationChance: z.number(), condition: z.string(), location: z.string(), }); // 指定された都市の天気データを取得するステップ // 現在の天気状況と予報を取得するためのAPI呼び出しを行います const fetchWeather = createStep({ id: "fetch-weather", description: "指定された都市の天気予報を取得します", inputSchema: z.object({ city: z.string(), }), outputSchema: forecastSchema, execute: async ({ inputData }) => { if (!inputData) { throw new Error("トリガーデータが見つかりません"); } const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(inputData.city)}&count=1`; const geocodingResponse = await fetch(geocodingUrl); const geocodingData = (await geocodingResponse.json()) as { results: { latitude: number; longitude: number; name: string }[]; }; if (!geocodingData.results?.[0]) { throw new Error(`場所 '${inputData.city}' が見つかりません`); } const { latitude, longitude, name } = geocodingData.results[0]; const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=precipitation,weathercode&timezone=auto,&hourly=precipitation_probability,temperature_2m`; const response = await fetch(weatherUrl); const data = (await response.json()) as { current: { time: string; precipitation: number; weathercode: number; }; hourly: { precipitation_probability: number[]; temperature_2m: number[]; }; }; const forecast = { date: new Date().toISOString(), maxTemp: Math.max(...data.hourly.temperature_2m), minTemp: Math.min(...data.hourly.temperature_2m), condition: getWeatherCondition(data.current.weathercode), location: name, precipitationChance: data.hourly.precipitation_probability.reduce( (acc, curr) => Math.max(acc, curr), 0, ), }; return forecast; }, }); // 天気状況に基づいて屋外活動を計画するステップ // プランニングエージェントを使用してアクティビティの推奨事項を生成します const planActivities = createStep({ id: "plan-activities", description: "天気状況に基づいてアクティビティを提案します", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("予報データが見つかりません"); } const prompt = `${forecast.location}の以下の天気予報に基づいて、適切なアクティビティを提案してください: ${JSON.stringify(forecast, null, 2)} `; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("プランニングエージェントが見つかりません"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); // 天気コードを人間が読める状態に変換するヘルパー関数 // 天気APIからの数値コードを説明的な文字列にマッピングします function getWeatherCondition(code: number): string { const conditions: Record = { 0: "快晴", 1: "ほぼ晴れ", 2: "部分的に曇り", 3: "曇り", 45: "霧", 48: "着氷性の霧", 51: "軽い霧雨", 53: "中程度の霧雨", 55: "濃い霧雨", 61: "小雨", 63: "中程度の雨", 65: "大雨", 71: "小雪", 73: "中程度の雪", 75: "大雪", 95: "雷雨", }; return conditions[code] || "不明"; } // 悪天候に備えて室内アクティビティを計画するステップ // 悪天候の場合の代替室内アクティビティを生成します const planIndoorActivities = createStep({ id: "plan-indoor-activities", description: "天候状況に基づいて室内アクティビティを提案します", inputSchema: forecastSchema, outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const forecast = inputData; if (!forecast) { throw new Error("Forecast data not found"); } const prompt = `雨が降った場合、${forecast.location}の${forecast.date}のための室内アクティビティを計画してください`; const agent = mastra?.getAgent("planningAgent"); if (!agent) { throw new Error("Planning agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { activitiesText += chunk; } return { activities: activitiesText, }; }, }); // 室内/屋外アクティビティ計画を統合するステップ // 両方のオプションを考慮した包括的な計画を作成します const synthesizeStep = createStep({ id: "sythesize-step", description: "室内と屋外のアクティビティの結果を統合します", inputSchema: z.object({ "plan-activities": z.object({ activities: z.string(), }), "plan-indoor-activities": z.object({ activities: z.string(), }), }), outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const indoorActivities = inputData?.["plan-indoor-activities"]; const outdoorActivities = inputData?.["plan-activities"]; const prompt = `室内アクティビティ: ${indoorActivities?.activities} 屋外アクティビティ: ${outdoorActivities?.activities} 雨が降る可能性があるので、必要に応じて室内アクティビティを行う準備をしておいてください。`; const agent = mastra?.getAgent("synthesizeAgent"); if (!agent) { throw new Error("Synthesize agent not found"); } const response = await agent.stream([ { role: "user", content: prompt, }, ]); let activitiesText = ""; for await (const chunk of response.textStream) { process.stdout.write(chunk); activitiesText += chunk; } return { activities: activitiesText, }; }, }); const activityPlanningWorkflow = createWorkflow({ id: "plan-both-workflow", inputSchema: z.object({ city: z.string(), }), outputSchema: z.object({ activities: z.string(), }), steps: [fetchWeather, planActivities, planIndoorActivities, synthesizeStep], }) .then(fetchWeather) .parallel([planActivities, planIndoorActivities]) .then(synthesizeStep) .commit(); export { activityPlanningWorkflow }; ``` ## Mastraクラスでエージェントとワークフローのインスタンスを登録する エージェントとワークフローをmastraインスタンスに登録します。 これはワークフロー内でエージェントへのアクセスを可能にするために重要です。 ```ts showLineNumbers copy filename="index.ts" import { Mastra } from "@mastra/core/mastra"; import { PinoLogger } from "@mastra/loggers"; import { activityPlanningWorkflow } from "./workflows/parallel-workflow"; import { planningAgent } from "./agents/planning-agent"; import { synthesizeAgent } from "./agents/synthesize-agent"; // Initialize Mastra with required agents and workflows // This setup enables agent access within the workflow steps const mastra = new Mastra({ vnext_workflows: { activityPlanningWorkflow, }, agents: { planningAgent, synthesizeAgent, }, logger: new PinoLogger({ name: "Mastra", level: "info", }), }); export { mastra }; ``` ## アクティビティプランニングワークフローを実行する ここでは、mastraインスタンスから天気ワークフローを取得し、実行を作成して、必要なinputDataで作成した実行を実行します。 ```ts showLineNumbers copy filename="exec.ts" import { mastra } from "./"; const workflow = mastra.vnext_getWorkflow("activityPlanningWorkflow"); const run = workflow.createRun(); // Execute the workflow with a specific city // This will run through all steps and generate activity recommendations const result = await run.start({ inputData: { city: "Ibiza" } }); console.dir(result, { depth: null }); ``` --- title: "AIリクルーターの構築 | Mastraワークフロー | ガイド" description: LLMを活用して候補者情報を収集・処理するためのMastraでのリクルーターワークフロー構築ガイド。 --- # はじめに [JA] Source: https://mastra.ai/ja/guides/guide/ai-recruiter このガイドでは、Mastra がどのようにして LLM を使ったワークフロー構築を支援するかを学びます。 候補者の履歴書から情報を収集し、そのプロフィールに応じて技術的な質問または行動に関する質問のいずれかに分岐するワークフローの作成手順を順を追って説明します。その過程で、ワークフローのステップの構成方法、分岐処理の扱い方、LLM 呼び出しの統合方法についても紹介します。 以下はワークフローの簡潔なバージョンです。必要なモジュールのインポートから始まり、Mastra のセットアップ、候補者データの抽出と分類のステップ定義、そして適切なフォローアップ質問の実施までを示しています。各コードブロックの後には、その内容と有用性についての簡単な説明が続きます。 ## 1. インポートとセットアップ Mastra ツールと Zod をインポートして、ワークフロー定義とデータ検証を行う必要があります。 ```ts filename="src/mastra/index.ts" copy import { Mastra } from "@mastra/core"; import { createStep, createWorkflow } from "@mastra/core/workflows"; import { z } from "zod"; ``` `.env` ファイルに `OPENAI_API_KEY` を追加してください。 ```bash filename=".env" copy OPENAI_API_KEY= ``` ## 2. ステップ1:候補者情報の収集 履歴書のテキストから候補者の詳細を抽出し、それらを技術系か非技術系かに分類したいと考えています。このステップでは、LLMを呼び出して履歴書を解析し、名前、技術的ステータス、専門分野、元の履歴書テキストを含む構造化されたJSONを返します。コードはtrigger dataからresumeTextを読み取り、LLMにプロンプトを送り、後続のステップで使用するために整理されたフィールドを返します。 ```ts filename="src/mastra/index.ts" copy import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const recruiter = new Agent({ name: "Recruiter Agent", instructions: `You are a recruiter.`, model: openai("gpt-4o-mini"), }); const gatherCandidateInfo = createStep({ id: "gatherCandidateInfo", inputSchema: z.object({ resumeText: z.string(), }), outputSchema: z.object({ candidateName: z.string(), isTechnical: z.boolean(), specialty: z.string(), resumeText: z.string(), }), execute: async ({ inputData }) => { const resumeText = inputData?.resumeText; const prompt = ` Extract details from the resume text: "${resumeText}" `; const res = await recruiter.generate(prompt, { output: z.object({ candidateName: z.string(), isTechnical: z.boolean(), specialty: z.string(), resumeText: z.string(), }), }); return res.object; }, }); ``` ## 3. 技術的な質問ステップ このステップでは、技術職と判断された候補者に対して、どのようにしてその専門分野に入ったのかについて詳しく尋ねます。履歴書全体のテキストを使用することで、LLMが関連性の高いフォローアップ質問を作成できるようにしています。このコードは、候補者の専門分野についての質問を生成します。 ```ts filename="src/mastra/index.ts" copy interface CandidateInfo { candidateName: string; isTechnical: boolean; specialty: string; resumeText: string; } const askAboutSpecialty = createStep({ id: "askAboutSpecialty", inputSchema: z.object({ candidateName: z.string(), isTechnical: z.boolean(), specialty: z.string(), resumeText: z.string(), }), outputSchema: z.object({ question: z.string(), }), execute: async ({ inputData }) => { const candidateInfo = inputData; const prompt = ` You are a recruiter. Given the resume below, craft a short question for ${candidateInfo?.candidateName} about how they got into "${candidateInfo?.specialty}". Resume: ${candidateInfo?.resumeText} `; const res = await recruiter.generate(prompt); return { question: res?.text?.trim() || "" }; }, }); ``` ## 4. 行動質問ステップ 候補者が非技術系の場合は、異なるフォローアップ質問が必要です。このステップでは、再度履歴書全体のテキストを参照しながら、その役割について最も興味がある点を尋ねます。コードは、LLMに役割に焦点を当てた質問を求めます。 ```ts filename="src/mastra/index.ts" copy const askAboutRole = createStep({ id: "askAboutRole", inputSchema: z.object({ candidateName: z.string(), isTechnical: z.boolean(), specialty: z.string(), resumeText: z.string(), }), outputSchema: z.object({ question: z.string(), }), execute: async ({ inputData }) => { const candidateInfo = inputData; const prompt = ` You are a recruiter. Given the resume below, craft a short question for ${candidateInfo?.candidateName} asking what interests them most about this role. Resume: ${candidateInfo?.resumeText} `; const res = await recruiter.generate(prompt); return { question: res?.text?.trim() || "" }; }, }); ``` ## 5. ワークフローの定義 ここでは、候補者の技術的なステータスに基づいて分岐ロジックを実装するために、これまでのステップを組み合わせます。ワークフローはまず候補者データを収集し、その後、isTechnical に応じて専門分野について質問するか、役割について質問します。コードでは、gatherCandidateInfo を askAboutSpecialty および askAboutRole と連結し、ワークフローをコミットします。 ```ts filename="src/mastra/index.ts" copy const candidateWorkflow = createWorkflow({ id: "candidate-workflow", inputSchema: z.object({ resumeText: z.string(), }), outputSchema: z.object({ question: z.string(), }), }); candidateWorkflow.then(gatherCandidateInfo).branch([ // Branch for technical candidates [ async ({ inputData }) => { return inputData?.isTechnical; }, askAboutSpecialty, ], // Branch for non-technical candidates [ async ({ inputData }) => { return !inputData?.isTechnical; }, askAboutRole, ], ]); candidateWorkflow.commit(); ``` ## 6. ワークフローの実行 ```ts filename="src/mastra/index.ts" copy const mastra = new Mastra({ workflows: { candidateWorkflow, }, }); (async () => { const run = mastra.getWorkflow("candidateWorkflow").createRun(); console.log("Run", run.runId); const runResult = await run.start({ inputData: { resumeText: "Simulated resume content..." }, }); console.log("Final output:", runResult); })(); ``` これで、履歴書を解析し、候補者の技術力に基づいてどの質問をするかを決定するワークフローが完成しました。おめでとうございます、そしてハッキングを楽しんでください! --- title: "AIシェフアシスタントの構築 | Mastraエージェントガイド" description: 利用可能な食材で料理を作るユーザーを支援するMastraでのシェフアシスタントエージェントの作成ガイド。 --- import { Steps } from "nextra/components"; import YouTube from "@/components/youtube"; # エージェントガイド:シェフアシスタントの構築 [JA] Source: https://mastra.ai/ja/guides/guide/chef-michel このガイドでは、ユーザーが手持ちの食材で料理を作るのを手伝う「シェフアシスタント」エージェントの作成方法を説明します。 ## 前提条件 - Node.jsがインストールされていること - Mastraがインストールされていること: `npm install @mastra/core@latest` --- ## エージェントを作成する ### エージェントを定義する 新しいファイル `src/mastra/agents/chefAgent.ts` を作成し、エージェントを定義します: ```ts copy filename="src/mastra/agents/chefAgent.ts" import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; export const chefAgent = new Agent({ name: "chef-agent", instructions: "You are Michel, a practical and experienced home chef" + "You help people cook with whatever ingredients they have available.", model: openai("gpt-4o-mini"), }); ``` --- ## 環境変数を設定する プロジェクトのルートに `.env` ファイルを作成し、OpenAI APIキーを追加します: ```bash filename=".env" copy OPENAI_API_KEY=your_openai_api_key ``` --- ## エージェントをMastraに登録する メインファイルで、エージェントを登録します: ```ts copy filename="src/mastra/index.ts" import { Mastra } from "@mastra/core"; import { chefAgent } from "./agents/chefAgent"; export const mastra = new Mastra({ agents: { chefAgent }, }); ``` --- ## エージェントとの対話 ### テキスト応答の生成 ```ts copy filename="src/index.ts" async function main() { const query = "In my kitchen I have: pasta, canned tomatoes, garlic, olive oil, and some dried herbs (basil and oregano). What can I make?"; console.log(`Query: ${query}`); const response = await chefAgent.generate([{ role: "user", content: query }]); console.log("\n👨‍🍳 Chef Michel:", response.text); } main(); ``` スクリプトを実行します: ```bash copy npx bun src/index.ts ``` 出力: ``` Query: In my kitchen I have: pasta, canned tomatoes, garlic, olive oil, and some dried herbs (basil and oregano). What can I make? 👨‍🍳 Chef Michel: You can make a delicious pasta al pomodoro! Here's how... ``` --- ### レスポンスのストリーミング ```ts copy filename="src/index.ts" async function main() { const query = "Now I'm over at my friend's house, and they have: chicken thighs, coconut milk, sweet potatoes, and some curry powder."; console.log(`Query: ${query}`); const stream = await chefAgent.stream([{ role: "user", content: query }]); console.log("\n Chef Michel: "); for await (const chunk of stream.textStream) { process.stdout.write(chunk); } console.log("\n\n✅ Recipe complete!"); } main(); ``` 出力: ``` Query: Now I'm over at my friend's house, and they have: chicken thighs, coconut milk, sweet potatoes, and some curry powder. 👨‍🍳 Chef Michel: Great! You can make a comforting chicken curry... ✅ Recipe complete! ``` --- ### 構造化データを含むレシピの生成 ```ts copy filename="src/index.ts" import { z } from "zod"; async function main() { const query = "I want to make lasagna, can you generate a lasagna recipe for me?"; console.log(`Query: ${query}`); // Define the Zod schema const schema = z.object({ ingredients: z.array( z.object({ name: z.string(), amount: z.string(), }), ), steps: z.array(z.string()), }); const response = await chefAgent.generate( [{ role: "user", content: query }], { output: schema }, ); console.log("\n👨‍🍳 Chef Michel:", response.object); } main(); ``` 出力: ``` Query: I want to make lasagna, can you generate a lasagna recipe for me? 👨‍🍳 Chef Michel: { ingredients: [ { name: "Lasagna noodles", amount: "12 sheets" }, { name: "Ground beef", amount: "1 pound" }, // ... ], steps: [ "Preheat oven to 375°F (190°C).", "Cook the lasagna noodles according to package instructions.", // ... ] } ``` --- ## エージェントサーバーの実行 ### `mastra dev`の使用 `mastra dev`コマンドを使用してエージェントをサービスとして実行できます: ```bash copy mastra dev ``` これにより、登録されたエージェントと対話するためのエンドポイントを公開するサーバーが起動します。 ### シェフアシスタントAPIへのアクセス デフォルトでは、`mastra dev`は`http://localhost:4111`で実行されます。シェフアシスタントエージェントは以下のURLで利用可能です: ``` POST http://localhost:4111/api/agents/chefAgent/generate ``` ### `curl`を使用したエージェントとの対話 コマンドラインから`curl`を使用してエージェントと対話できます: ```bash copy curl -X POST http://localhost:4111/api/agents/chefAgent/generate \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "role": "user", "content": "I have eggs, flour, and milk. What can I make?" } ] }' ``` **サンプルレスポンス:** ```json { "text": "You can make delicious pancakes! Here's a simple recipe..." } ``` --- title: "リサーチペーパーアシスタントの構築 | Mastra RAG ガイド" description: RAG を活用して学術論文を分析し、質問に答える AI リサーチアシスタントの作成ガイド。 --- import { Steps } from "nextra/components"; # RAGを使ったリサーチペーパーアシスタントの構築 [JA] Source: https://mastra.ai/ja/guides/guide/research-assistant このガイドでは、Retrieval Augmented Generation(RAG)を活用して、学術論文を分析し、その内容に関する具体的な質問に答えるAIリサーチアシスタントを作成します。 例として、基礎的なTransformer論文である[Attention Is All You Need](https://arxiv.org/html/1706.03762)を使用します。 ## RAGコンポーネントの理解 RAGがどのように機能するか、そして各コンポーネントをどのように実装するかを理解しましょう。 1. ナレッジストア/インデックス - テキストをベクトル表現に変換する - コンテンツの数値表現を作成する - 実装方法:OpenAIのtext-embedding-3-smallを使って埋め込みを作成し、PgVectorに保存します 2. リトリーバー - 類似度検索によって関連するコンテンツを見つける - クエリの埋め込みと保存されたベクトルをマッチングする - 実装方法:PgVectorを使って保存された埋め込みに対して類似度検索を行います 3. ジェネレーター - 取得したコンテンツをLLMで処理する - 文脈に基づいた応答を生成する - 実装方法:GPT-4o-miniを使い、取得したコンテンツに基づいて回答を生成します 私たちの実装では、以下のことを行います: 1. Transformer論文を埋め込みに変換する 2. それらをPgVectorに保存し、素早く取得できるようにする 3. 類似度検索を使って関連するセクションを見つける 4. 取得した文脈を使って正確な応答を生成する ## プロジェクト構成 ``` research-assistant/ ├── src/ │ ├── mastra/ │ │ ├── agents/ │ │ │ └── researchAgent.ts │ │ └── index.ts │ ├── index.ts │ └── store.ts ├── package.json └── .env ``` ### プロジェクトの初期化と依存関係のインストール まず、プロジェクト用の新しいディレクトリを作成し、その中に移動します。 ```bash mkdir research-assistant cd research-assistant ``` 新しい Node.js プロジェクトを初期化し、必要な依存関係をインストールします。 ```bash copy npm init -y npm install @mastra/core@latest @mastra/rag@latest @mastra/pg@latest @ai-sdk/openai@latest ai@latest zod@latest ``` APIアクセスやデータベース接続のための環境変数を設定します。 ```bash filename=".env" copy OPENAI_API_KEY=your_openai_api_key POSTGRES_CONNECTION_STRING=your_connection_string ``` プロジェクトに必要なファイルを作成します。 ```bash copy mkdir -p src/mastra/agents touch src/mastra/agents/researchAgent.ts touch src/mastra/index.ts src/store.ts src/index.ts ``` ### Research Assistant エージェントの作成 次に、RAG対応のリサーチアシスタントを作成します。このエージェントは以下を利用します。 * [Vector Query Tool](/reference/tools/vector-query-tool):ベクトルストア上でセマンティック検索を行い、論文内の関連コンテンツを見つけます * GPT-4o-mini:クエリの理解と応答の生成 * カスタムインストラクション:論文の分析方法、取得したコンテンツの効果的な活用方法、制限事項の認識についてエージェントをガイドします ```ts copy showLineNumbers filename="src/mastra/agents/researchAgent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import { createVectorQueryTool } from "@mastra/rag"; // Create a tool for semantic search over our paper embeddings const vectorQueryTool = createVectorQueryTool({ vectorStoreName: "pgVector", indexName: "papers", model: openai.embedding("text-embedding-3-small"), }); export const researchAgent = new Agent({ name: "Research Assistant", instructions: `You are a helpful research assistant that analyzes academic papers and technical documents. Use the provided vector query tool to find relevant information from your knowledge base, and provide accurate, well-supported answers based on the retrieved content. Focus on the specific content available in the tool and acknowledge if you cannot find sufficient information to answer a question. Base your responses only on the content provided, not on general knowledge.`, model: openai("gpt-4o-mini"), tools: { vectorQueryTool, }, }); ``` ### Mastra インスタンスとベクトルストアのセットアップ ```ts copy showLineNumbers filename="src/mastra/index.ts" import { Mastra } from "@mastra/core"; import { PgVector } from "@mastra/pg"; import { researchAgent } from "./agents/researchAgent"; // Initialize Mastra instance const pgVector = new PgVector({ connectionString: process.env.POSTGRES_CONNECTION_STRING!, }); export const mastra = new Mastra({ agents: { researchAgent }, vectors: { pgVector }, }); ``` ### 論文の読み込みと処理 このステップでは、初期ドキュメント処理を行います。具体的には: 1. 論文をURLから取得 2. ドキュメントオブジェクトに変換 3. より良い処理のために小さなチャンクに分割 ```ts copy showLineNumbers filename="src/store.ts" import { openai } from "@ai-sdk/openai"; import { MDocument } from "@mastra/rag"; import { embedMany } from "ai"; import { mastra } from "./mastra"; // Load the paper const paperUrl = "https://arxiv.org/html/1706.03762"; const response = await fetch(paperUrl); const paperText = await response.text(); // Create document and chunk it const doc = MDocument.fromText(paperText); const chunks = await doc.chunk({ strategy: "recursive", size: 512, overlap: 50, separator: "\n", }); console.log("Number of chunks:", chunks.length); // Number of chunks: 893 ``` ### 埋め込みの作成と保存 最後に、RAG用にコンテンツを準備します。手順は以下の通りです。 1. 各テキストチャンクの埋め込みを生成 2. 埋め込みを保存するためのベクトルストアインデックスを作成 3. 埋め込みとメタデータ(元のテキストやソース情報)をベクトルデータベースに保存 > **注**: このメタデータは、ベクトルストアが関連する一致を見つけた際に実際のコンテンツを返すために重要です。 これにより、エージェントは効率的に関連情報を検索・取得できるようになります。 ```ts copy showLineNumbers{23} filename="src/store.ts" // Generate embeddings const { embeddings } = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: chunks.map((chunk) => chunk.text), }); // Get the vector store instance from Mastra const vectorStore = mastra.getVector("pgVector"); // Create an index for our paper chunks await vectorStore.createIndex({ indexName: "papers", dimension: 1536, }); // Store embeddings await vectorStore.upsert({ indexName: "papers", vectors: embeddings, metadata: chunks.map((chunk) => ({ text: chunk.text, source: "transformer-paper", })), }); ``` これにより、以下の処理が行われます: 1. 論文をURLから読み込みます 2. 論文を扱いやすいチャンクに分割します 3. 各チャンクの埋め込みベクトルを生成します 4. 埋め込みベクトルとテキストの両方をベクトルデータベースに保存します スクリプトを実行して埋め込みベクトルを保存するには、次のコマンドを使用します: ```bash npx bun src/store.ts ``` ### アシスタントのテスト リサーチアシスタントをさまざまな種類のクエリでテストしてみましょう: ```ts filename="src/index.ts" showLineNumbers copy import { mastra } from "./mastra"; const agent = mastra.getAgent("researchAgent"); // Basic query about concepts const query1 = "What problems does sequence modeling face with neural networks?"; const response1 = await agent.generate(query1); console.log("\nQuery:", query1); console.log("Response:", response1.text); ``` スクリプトを実行します: ```bash copy npx bun src/index.ts ``` 次のような出力が表示されるはずです: ``` Query: What problems does sequence modeling face with neural networks? Response: Sequence modeling with neural networks faces several key challenges: 1. Vanishing and exploding gradients during training, especially with long sequences 2. Difficulty handling long-term dependencies in the input 3. Limited computational efficiency due to sequential processing 4. Challenges in parallelizing computations, resulting in longer training times ``` 別の質問も試してみましょう: ```ts filename="src/index.ts" showLineNumbers{10} copy // Query about specific findings const query2 = "What improvements were achieved in translation quality?"; const response2 = await agent.generate(query2); console.log("\nQuery:", query2); console.log("Response:", response2.text); ``` 出力例: ``` Query: What improvements were achieved in translation quality? Response: The model showed significant improvements in translation quality, achieving more than 2.0 BLEU points improvement over previously reported models on the WMT 2014 English-to-German translation task, while also reducing training costs. ``` ### アプリケーションの提供 Mastraサーバーを起動して、リサーチアシスタントをAPI経由で利用できるようにします: ```bash mastra dev ``` リサーチアシスタントは次のURLで利用可能になります: ``` http://localhost:4111/api/agents/researchAgent/generate ``` curlでテストしてみましょう: ```bash curl -X POST http://localhost:4111/api/agents/researchAgent/generate \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "role": "user", "content": "What were the main findings about model parallelization?" } ] }' ``` ## 高度なRAGの例 より高度なRAG技術の例を以下でご覧ください: - メタデータを使って結果をフィルタリングする[Filter RAG](/examples/rag/usage/filter-rag) - 情報密度を最適化する[Cleanup RAG](/examples/rag/usage/cleanup-rag) - ワークフローを用いた複雑な推論クエリのための[Chain of Thought RAG](/examples/rag/usage/cot-rag) - 結果の関連性を向上させる[Rerank RAG](/examples/rag/usage/rerank-rag) --- title: "AI株式エージェントの構築 | Mastraエージェント | ガイド" description: 指定された銘柄の前日終値を取得するシンプルな株式エージェントをMastraで作成するガイド。 --- import { Steps } from "nextra/components"; import YouTube from "@/components/youtube"; # 株価エージェント [JA] Source: https://mastra.ai/ja/guides/guide/stock-agent 私たちは、指定されたシンボルの前日の終値を取得するシンプルなエージェントを作成します。この例では、ツールを作成し、それをエージェントに追加して、株価を取得するためにエージェントを使用する方法を示します。 ## プロジェクト構造 ``` stock-price-agent/ ├── src/ │ ├── agents/ │ │ └── stockAgent.ts │ ├── tools/ │ │ └── stockPrices.ts │ └── index.ts ├── package.json └── .env ``` --- ## プロジェクトの初期化と依存関係のインストール まず、プロジェクト用の新しいディレクトリを作成し、そこに移動します: ```bash mkdir stock-price-agent cd stock-price-agent ``` 新しいNode.jsプロジェクトを初期化し、必要な依存関係をインストールします: ```bash copy npm init -y npm install @mastra/core@latest zod @ai-sdk/openai ``` 環境変数の設定 プロジェクトのルートに`.env`ファイルを作成して、OpenAI APIキーを保存します。 ```bash filename=".env" copy OPENAI_API_KEY=your_openai_api_key ``` 必要なディレクトリとファイルを作成します: ```bash mkdir -p src/agents src/tools touch src/agents/stockAgent.ts src/tools/stockPrices.ts src/index.ts ``` --- ## 株価ツールの作成 次に、指定されたシンボルの前日終値を取得するツールを作成します。 ```ts filename="src/tools/stockPrices.ts" import { createTool } from "@mastra/core/tools"; import { z } from "zod"; const getStockPrice = async (symbol: string) => { const data = await fetch( `https://mastra-stock-data.vercel.app/api/stock-data?symbol=${symbol}`, ).then((r) => r.json()); return data.prices["4. close"]; }; export const stockPrices = createTool({ id: "Get Stock Price", inputSchema: z.object({ symbol: z.string(), }), description: `Fetches the last day's closing stock price for a given symbol`, execute: async ({ context: { symbol } }) => { console.log("Using tool to fetch stock price for", symbol); return { symbol, currentPrice: await getStockPrice(symbol), }; }, }); ``` --- ## エージェントにツールを追加する エージェントを作成し、`stockPrices`ツールを追加します。 ```ts filename="src/agents/stockAgent.ts" import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; import * as tools from "../tools/stockPrices"; export const stockAgent = new Agent({ name: "Stock Agent", instructions: "You are a helpful assistant that provides current stock prices. When asked about a stock, use the stock price tool to fetch the stock price.", model: openai("gpt-4o-mini"), tools: { stockPrices: tools.stockPrices, }, }); ``` --- ## Mastraインスタンスの設定 エージェントとツールを使用してMastraインスタンスを初期化する必要があります。 ```ts filename="src/index.ts" import { Mastra } from "@mastra/core"; import { stockAgent } from "./agents/stockAgent"; export const mastra = new Mastra({ agents: { stockAgent }, }); ``` ## アプリケーションの提供 アプリケーションを直接実行する代わりに、`mastra dev`コマンドを使用してサーバーを起動します。これにより、エージェントがREST APIエンドポイントを通じて公開され、HTTPを介して対話できるようになります。 ターミナルで、以下のコマンドを実行してMastraサーバーを起動します: ```bash mastra dev --dir src ``` このコマンドにより、プレイグラウンド内でstockPricesツールとstockAgentをテストすることができます。 これにより、サーバーが起動し、エージェントが以下のURLで利用可能になります: ``` http://localhost:4111/api/agents/stockAgent/generate ``` --- ## cURLでエージェントをテストする サーバーが実行されたら、`curl`を使用してエージェントのエンドポイントをテストできます: ```bash curl -X POST http://localhost:4111/api/agents/stockAgent/generate \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "role": "user", "content": "What is the current stock price of Apple (AAPL)?" } ] }' ``` **予想される応答:** 以下のようなJSON応答が返ってくるはずです: ```json { "text": "The current price of Apple (AAPL) is $174.55.", "agent": "Stock Agent" } ``` これは、エージェントがリクエストを正常に処理し、`stockPrices`ツールを使用して株価を取得し、結果を返したことを示しています。 --- title: "概要" description: "Mastraを使った構築ガイド" --- # ガイド [JA] Source: https://mastra.ai/ja/guides 例では迅速な実装を示し、ドキュメントでは特定の機能を説明していますが、これらのガイドはやや長めで、Mastraのコアコンセプトを実証するように設計されています: ## [AI リクルーター](/guides/guide/ai-recruiter) 候補者の履歴書を処理し、面接を実施するワークフローを作成し、Mastraワークフローにおける分岐ロジックとLLM統合を実証します。 ## [シェフアシスタント](/guides/guide/chef-michel) 利用可能な食材で料理を作るのを手伝うAIシェフエージェントを構築し、カスタムツールを使用してインタラクティブなエージェントを作成する方法を紹介します。 ## [研究論文アシスタント](/guides/guide/research-assistant) 検索拡張生成(RAG)を使用して学術論文を分析するAI研究アシスタントを開発し、文書処理と質問応答を実証します。 ## [株価エージェント](/guides/guide/stock-agent) 株価を取得するシンプルなエージェントを実装し、ツールの作成とMastraエージェントへの統合の基本を説明します。 --- title: "リファレンス: エージェント | エージェント | Mastra ドキュメント" description: "Mastraのエージェントクラスに関するドキュメント。様々な機能を持つAIエージェントを作成するための基盤を提供します。" --- # Agent [JA] Source: https://mastra.ai/ja/reference/agents/agent `Agent` クラスは、MastraでのAIエージェント作成の基盤です。レスポンスの生成、ストリーミング対話、音声機能の処理のためのメソッドを提供します。 ## インポート ```typescript import { Agent } from "@mastra/core/agent"; ``` ## コンストラクタ 指定された設定で新しい Agent インスタンスを作成します。 ```typescript constructor(config: AgentConfig) ``` ### パラメーター
string | Promise", isOptional: false, description: "エージェントの動作を導くための指示。静的な文字列または文字列を返す関数を指定できます。", }, { name: "model", type: "MastraLanguageModel | ({ runtimeContext: RuntimeContext }) => MastraLanguageModel | Promise", isOptional: false, description: "応答を生成するために使用する言語モデル。モデルインスタンスまたはモデルを返す関数を指定できます。", }, { name: "tools", type: "ToolsInput | ({ runtimeContext: RuntimeContext }) => ToolsInput | Promise", isOptional: true, description: "エージェントが使用できるツール。静的なオブジェクトまたはツールを返す関数を指定できます。", }, { name: "defaultGenerateOptions", type: "AgentGenerateOptions", isOptional: true, description: "generate() を呼び出す際に使用するデフォルトのオプション。", }, { name: "defaultStreamOptions", type: "AgentStreamOptions", isOptional: true, description: "stream() を呼び出す際に使用するデフォルトのオプション。", }, { name: "workflows", type: "Record | ({ runtimeContext: RuntimeContext }) => Record | Promise>", isOptional: true, description: "エージェントが実行できるワークフロー。静的なオブジェクトまたはワークフローを返す関数を指定できます。", }, { name: "evals", type: "Record", isOptional: true, description: "エージェントのパフォーマンスを評価するための指標。", }, { name: "memory", type: "MastraMemory", isOptional: true, description: "エージェントが情報を保存・取得するためのメモリーシステム。", }, { name: "voice", type: "CompositeVoice", isOptional: true, description: "音声認識および音声合成機能のための音声機能。", }, ]} /> --- title: "リファレンス: createTool() | ツール | エージェント | Mastra ドキュメント" description: Mastra の createTool 関数のドキュメント。エージェントやワークフロー用のカスタムツールを作成します。 --- # `createTool()` [JA] Source: https://mastra.ai/ja/reference/agents/createTool `createTool()` 関数は、エージェントやワークフローによって実行可能な型付きツールを作成します。ツールには、組み込みのスキーマバリデーション、実行コンテキスト、そしてMastraエコシステムとの統合が備わっています。 ## 概要 ツールは、Mastraにおける基本的な構成要素であり、エージェントが外部システムと連携したり、計算を実行したり、データへアクセスしたりすることを可能にします。各ツールには以下の特徴があります。 - 一意の識別子 - AIがツールをいつ、どのように使うべきかを理解するための説明 - バリデーションのためのオプションの入力および出力スキーマ - ツールのロジックを実装する実行関数 ## 使用例 ```ts filename="src/tools/stock-tools.ts" showLineNumbers copy import { createTool } from "@mastra/core/tools"; import { z } from "zod"; // Helper function to fetch stock data const getStockPrice = async (symbol: string) => { const response = await fetch( `https://mastra-stock-data.vercel.app/api/stock-data?symbol=${symbol}`, ); const data = await response.json(); return data.prices["4. close"]; }; // Create a tool to get stock prices export const stockPriceTool = createTool({ id: "getStockPrice", description: "Fetches the current stock price for a given ticker symbol", inputSchema: z.object({ symbol: z.string().describe("The stock ticker symbol (e.g., AAPL, MSFT)"), }), outputSchema: z.object({ symbol: z.string(), price: z.number(), currency: z.string(), timestamp: z.string(), }), execute: async ({ context }) => { const price = await getStockPrice(context.symbol); return { symbol: context.symbol, price: parseFloat(price), currency: "USD", timestamp: new Date().toISOString(), }; }, }); // Create a tool that uses the thread context export const threadInfoTool = createTool({ id: "getThreadInfo", description: "Returns information about the current conversation thread", inputSchema: z.object({ includeResource: z.boolean().optional().default(false), }), execute: async ({ context, threadId, resourceId }) => { return { threadId, resourceId: context.includeResource ? resourceId : undefined, timestamp: new Date().toISOString(), }; }, }); ``` ## APIリファレンス ### パラメータ `createTool()` は、以下のプロパティを持つ単一のオブジェクトを受け取ります。 Promise", required: false, description: "ツールのロジックを実装する非同期関数。実行コンテキストとオプションの設定を受け取ります。", properties: [ { type: "ToolExecutionContext", parameters: [ { name: "context", type: "object", description: "inputSchemaに一致する検証済みの入力データ", }, { name: "threadId", type: "string", isOptional: true, description: "会話スレッドの識別子(利用可能な場合)", }, { name: "resourceId", type: "string", isOptional: true, description: "ツールとやり取りするユーザーまたはリソースの識別子", }, { name: "mastra", type: "Mastra", isOptional: true, description: "利用可能な場合のMastraインスタンスへの参照", }, ], }, { type: "ToolOptions", parameters: [ { name: "toolCallId", type: "string", description: "ツール呼び出しのID。たとえば、ストリームデータとともにツール呼び出し関連情報を送信する際などに使用できます。", }, { name: "messages", type: "CoreMessage[]", description: "ツール呼び出しを含む応答を生成するために言語モデルに送信されたメッセージ。これらのメッセージにはsystemプロンプトやツール呼び出しを含むassistantの応答は含まれません。", }, { name: "abortSignal", type: "AbortSignal", isOptional: true, description: "全体の操作を中止すべきことを示すオプションのアボートシグナル。", }, ], }, ], }, { name: "inputSchema", type: "ZodSchema", required: false, description: "ツールの入力パラメータを定義・検証するZodスキーマ。指定しない場合、ツールは任意の入力を受け付けます。", }, { name: "outputSchema", type: "ZodSchema", required: false, description: "ツールの出力を定義・検証するZodスキーマ。ツールが期待される形式でデータを返すことを保証します。", }, ]} /> ### 戻り値 ", description: "エージェントやワークフローで使用したり、直接実行できるToolインスタンス。", properties: [ { type: "Tool", parameters: [ { name: "id", type: "string", description: "ツールの一意な識別子", }, { name: "description", type: "string", description: "ツールの機能の説明", }, { name: "inputSchema", type: "ZodSchema | undefined", description: "入力の検証用スキーマ", }, { name: "outputSchema", type: "ZodSchema | undefined", description: "出力の検証用スキーマ", }, { name: "execute", type: "Function", description: "ツールの実行関数", }, ], }, ], }, ]} /> ## 型安全性 `createTool()` 関数は、TypeScript のジェネリクスを通じて完全な型安全性を提供します。 - 入力型は `inputSchema` から推論されます - 出力型は `outputSchema` から推論されます - 実行コンテキストは入力スキーマに基づいて正しく型付けされます これにより、アプリケーション全体でツールが型安全であることが保証されます。 ## ベストプラクティス 1. **わかりやすいID**: `getWeatherForecast` や `searchDatabase` のような、明確で行動を示すIDを使用する 2. **詳細な説明**: ツールの使用タイミングや方法を説明する、包括的な説明を提供する 3. **入力バリデーション**: Zodスキーマを使って入力を検証し、わかりやすいエラーメッセージを提供する 4. **エラーハンドリング**: execute関数で適切なエラーハンドリングを実装する 5. **冪等性**: 可能であれば、ツールを冪等にする(同じ入力で常に同じ出力を返す) 6. **パフォーマンス**: ツールは軽量で高速に実行できるようにする --- title: "リファレンス: Agent.generate() | Agents | Mastra ドキュメント" description: "Mastra エージェントの `.generate()` メソッドのドキュメント。テキストや構造化された応答を生成します。" --- # Agent.generate() [JA] Source: https://mastra.ai/ja/reference/agents/generate `generate()` メソッドは、エージェントと対話してテキストや構造化された応答を生成するために使用されます。このメソッドは、`messages` とオプションの `options` オブジェクトをパラメータとして受け取ります。 ## Parameters ### `messages` `messages`パラメータは以下のいずれかを指定できます: - 単一の文字列 - 文字列の配列 - `role`と`content`プロパティを持つメッセージオブジェクトの配列 メッセージオブジェクトの構造: ```typescript interface Message { role: "system" | "user" | "assistant"; content: string; } ``` ### `options` (Optional) 出力構造、メモリ管理、ツール使用、テレメトリなどの設定を含むことができるオプションのオブジェクトです。 , title?: string }", isOptional: false, description: "会話スレッド。文字列IDまたは `id` とオプションの `metadata` を持つオブジェクトとして指定します。" }] }, { parameters: [{ name: "resource", type: "string", isOptional: false, description: "スレッドに関連付けられたユーザーまたはリソースの識別子。" }] }, { parameters: [{ name: "options", type: "MemoryConfig", isOptional: true, description: "メッセージ履歴やセマンティック想起などのメモリ動作の設定。下記の `MemoryConfig` を参照してください。" }] } ] }, { name: "maxSteps", type: "number", isOptional: true, defaultValue: "5", description: "許可される実行ステップの最大数。", }, { name: "maxRetries", type: "number", isOptional: true, defaultValue: "2", description: "最大再試行回数。再試行を無効にするには 0 に設定します。", }, { name: "memoryOptions", type: "MemoryConfig", isOptional: true, description: "**非推奨。** 代わりに `memory.options` を使用してください。メモリ管理の設定オプション。詳細は下記の MemoryConfig セクションを参照してください。", }, { name: "onStepFinish", type: "GenerateTextOnStepFinishCallback | never", isOptional: true, description: "各実行ステップ後に呼び出されるコールバック関数。ステップの詳細をJSON文字列として受け取ります。構造化出力では利用できません。", }, { name: "resourceId", type: "string", isOptional: true, description: "**非推奨。** 代わりに `memory.resource` を使用してください。エージェントと対話するユーザーまたはリソースの識別子。threadId が提供される場合は必須です。", }, { name: "telemetry", type: "TelemetrySettings", isOptional: true, description: "生成中のテレメトリ収集の設定。詳細は下記の TelemetrySettings セクションを参照してください。", }, { name: "temperature", type: "number", isOptional: true, description: "モデルの出力のランダム性を制御します。高い値(例:0.8)は出力をよりランダムにし、低い値(例:0.2)はより集中的で決定論的にします。", }, { name: "threadId", type: "string", isOptional: true, description: "**非推奨。** 代わりに `memory.thread` を使用してください。会話スレッドの識別子。複数のやり取りにわたってコンテキストを維持できます。resourceId が提供される場合は必須です。", }, { name: "toolChoice", type: "'auto' | 'none' | 'required' | { type: 'tool'; toolName: string }", isOptional: true, defaultValue: "'auto'", description: "生成中にエージェントがツールを使用する方法を制御します。", }, { name: "toolsets", type: "ToolsetsInput", isOptional: true, description: "生成中にエージェントが利用できる追加のツールセット。", }, { name: "clientTools", type: "ToolsInput", isOptional: true, description: "リクエストの「クライアント」側で実行されるツール。これらのツールは定義に実行関数を持ちません。", }, ]} /> #### MemoryConfig メモリ管理の設定オプション: #### TelemetrySettings 生成中のテレメトリ収集の設定: ", isOptional: true, description: "テレメトリデータに含める追加情報。AttributeValueは文字列、数値、ブール値、これらの型の配列、またはnullを指定できます。", }, { name: "tracer", type: "Tracer", isOptional: true, description: "テレメトリデータに使用するカスタムOpenTelemetryトレーサーインスタンス。詳細はOpenTelemetryドキュメントを参照してください。", }, ]} /> ## 戻り値 `generate()`メソッドの戻り値は、提供されたオプション、特に`output`オプションによって異なります。 ### 戻り値のプロパティテーブル ", isOptional: true, description: "生成プロセス中に行われたツール呼び出し。テキストモードとオブジェクトモードの両方に存在します。", }, ]} /> #### ToolCall構造 ## 関連メソッド リアルタイムのストリーミング応答については、[`stream()`](./stream.mdx) メソッドのドキュメントをご覧ください。 --- title: "リファレンス: getAgent() | エージェント設定 | エージェント | Mastra ドキュメント" description: getAgent の API リファレンス。 --- # `getAgent()` [JA] Source: https://mastra.ai/ja/reference/agents/getAgent 指定された構成に基づいてエージェントを取得する ```ts showLineNumbers copy async function getAgent({ connectionId, agent, apis, logger, }: { connectionId: string; agent: Record; apis: Record; logger: any; }): Promise<(props: { prompt: string }) => Promise> { return async (props: { prompt: string }) => { return { message: "Hello, world!" }; }; } ``` ## API シグネチャ ### パラメーター ", description: "エージェントの設定オブジェクト。", }, { name: "apis", type: "Record", description: "API名とそれぞれのAPIオブジェクトのマップ。", }, ]} /> ### 戻り値 --- title: "リファレンス: Agent.getInstructions() | エージェント | Mastra ドキュメント" description: "Mastraエージェントの`.getInstructions()`メソッドに関するドキュメント。エージェントの動作を導く指示を取得します。" --- # Agent.getInstructions() [JA] Source: https://mastra.ai/ja/reference/agents/getInstructions `getInstructions()`メソッドは、エージェントに設定された指示を取得し、それが関数である場合は解決します。これらの指示はエージェントの動作を導き、その能力と制約を定義します。 ## 構文 ```typescript getInstructions({ runtimeContext }: { runtimeContext?: RuntimeContext } = {}): string | Promise ``` ## パラメーター
## 戻り値 エージェントの指示を含む文字列、または文字列に解決されるPromiseを返します。 ## 説明 `getInstructions()` メソッドは、エージェントの行動を導く指示にアクセスするために使用されます。このメソッドは、指示が文字列として直接提供される場合や、関数から返される場合のいずれにも対応して指示を解決します。 指示はエージェントの設定において重要な要素であり、以下を定義します: - エージェントの役割と性格 - タスク固有のガイダンス - エージェントの行動に対する制約 - ユーザーリクエストを処理するためのコンテキスト ## 例 ### 基本的な使い方 ```typescript import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // Create an agent with static instructions const agent = new Agent({ name: "assistant", instructions: "You are a helpful assistant that provides concise and accurate information.", model: openai("gpt-4o"), }); // Get the instructions const instructions = await agent.getInstructions(); console.log(instructions); // "You are a helpful assistant that provides concise and accurate information." ``` ### RuntimeContextとの併用 ```typescript import { Agent } from "@mastra/core/agent"; import { RuntimeContext } from "@mastra/core/runtime-context"; import { openai } from "@ai-sdk/openai"; // Create an agent with dynamic instructions const agent = new Agent({ name: "contextual-assistant", instructions: ({ runtimeContext }) => { // Dynamic instructions based on runtime context const userPreference = runtimeContext.get("userPreference"); const expertise = runtimeContext.get("expertise") || "general"; if (userPreference === "technical") { return `You are a technical assistant specializing in ${expertise}. Provide detailed technical explanations.`; } return `You are a helpful assistant providing easy-to-understand information about ${expertise}.`; }, model: openai("gpt-4o"), }); // Create a runtime context with user preferences const context = new RuntimeContext(); context.set("userPreference", "technical"); context.set("expertise", "machine learning"); // Get the instructions using the runtime context const instructions = await agent.getInstructions({ runtimeContext: context }); console.log(instructions); // "You are a technical assistant specializing in machine learning. Provide detailed technical explanations." ``` --- title: "リファレンス: Agent.getMemory() | エージェント | Mastra ドキュメント" description: "Mastraエージェントの`.getMemory()`メソッドに関するドキュメント。エージェントに関連付けられたメモリシステムを取得します。" --- # Agent.getMemory() [JA] Source: https://mastra.ai/ja/reference/agents/getMemory `getMemory()` メソッドは、エージェントに関連付けられたメモリシステムを取得します。このメソッドは、会話間で情報を保存および取得するためのエージェントのメモリ機能にアクセスするために使用されます。 ## 構文 ```typescript getMemory(): MastraMemory | undefined ``` ## パラメータ このメソッドはパラメータを取りません。 ## 戻り値 エージェントにメモリシステムが設定されている場合は`MastraMemory`インスタンスを返し、メモリシステムが設定されていない場合は`undefined`を返します。 ## 説明 `getMemory()`メソッドは、エージェントに関連付けられたメモリシステムにアクセスするために使用されます。メモリシステムによりエージェントは以下のことが可能になります: - 複数のインタラクションにわたって情報を保存および取得する - 会話履歴を維持する - ユーザーの設定や文脈を記憶する - 過去のインタラクションに基づいてパーソナライズされた応答を提供する このメソッドは、メモリシステムを使用する前にエージェントがメモリシステムを持っているかどうかを確認するために、`hasOwnMemory()`と組み合わせて使用されることがよくあります。 ## 例 ### 基本的な使い方 ```typescript import { Agent } from "@mastra/core/agent"; import { Memory } from "@mastra/memory"; import { openai } from "@ai-sdk/openai"; // Create a memory system const memory = new Memory(); // Create an agent with memory const agent = new Agent({ name: "memory-assistant", instructions: "You are a helpful assistant that remembers previous conversations.", model: openai("gpt-4o"), memory, }); // Get the memory system const agentMemory = agent.getMemory(); if (agentMemory) { // Use the memory system to retrieve thread messages const thread = await agentMemory.getThreadById({ resourceId: "user-123", threadId: "conversation-1", }); console.log("Retrieved thread:", thread); } ``` ### 使用前にメモリを確認する ```typescript import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // Create an agent without memory const agent = new Agent({ name: "stateless-assistant", instructions: "You are a helpful assistant.", model: openai("gpt-4o"), }); // Check if the agent has memory before using it if (agent.hasOwnMemory()) { const memory = agent.getMemory(); // Use memory... } else { console.log("This agent does not have a memory system."); } ``` ### 会話でメモリを使う ```typescript import { Agent } from "@mastra/core/agent"; import { Memory } from "@mastra/memory"; import { openai } from "@ai-sdk/openai"; // Create a memory system const memory = new Memory(); // Create an agent with memory const agent = new Agent({ name: "memory-assistant", instructions: "You are a helpful assistant that remembers previous conversations.", model: openai("gpt-4o"), memory, }); // First interaction - store information await agent.generate("My name is Alice.", { resourceId: "user-123", threadId: "conversation-1", }); // Later interaction - retrieve information const result = await agent.generate("What's my name?", { resourceId: "user-123", threadId: "conversation-1", }); console.log(result.text); // Should mention "Alice" // Access the memory system directly const agentMemory = agent.getMemory(); if (agentMemory) { // Retrieve messages from the thread const { messages } = await agentMemory.query({ resourceId: "user-123", threadId: "conversation-1", selectBy: { last: 10, // Get the last 10 messages }, }); console.log("Retrieved messages:", messages); } ``` --- title: "リファレンス: Agent.getModel() | エージェント | Mastra ドキュメント" description: "エージェントを動かす言語モデルを取得するMastraエージェントの`.getModel()`メソッドに関するドキュメント。" --- # Agent.getModel() [JA] Source: https://mastra.ai/ja/reference/agents/getModel `getModel()`メソッドは、エージェントに設定された言語モデルを取得し、それが関数である場合は解決します。このメソッドは、エージェントの機能を支える基盤となるモデルにアクセスするために使用されます。 ## 構文 ```typescript getModel({ runtimeContext = new RuntimeContext() }: { runtimeContext?: RuntimeContext } = {}): MastraLanguageModel | Promise ``` ## パラメーター
## 戻り値 `MastraLanguageModel`インスタンス、または`MastraLanguageModel`インスタンスに解決されるPromiseを返します。 ## 説明 `getModel()` メソッドは、エージェントを動かす言語モデルにアクセスするために使用されます。このメソッドは、直接指定されたモデル、または関数から返されるモデルを解決します。 言語モデルはエージェントの重要な構成要素であり、以下を決定します: - エージェントの応答の質と能力 - 利用可能な機能(関数呼び出し、構造化出力など) - エージェントのコストとパフォーマンス特性 ## 例 ### 基本的な使い方 ```typescript import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // Create an agent with a static model const agent = new Agent({ name: "assistant", instructions: "You are a helpful assistant.", model: openai("gpt-4o"), }); // Get the model const model = await agent.getModel(); console.log(model.id); // "gpt-4o" ``` ### RuntimeContextとの併用 ```typescript import { Agent } from "@mastra/core/agent"; import { RuntimeContext } from "@mastra/core/runtime-context"; import { openai } from "@ai-sdk/openai"; import { anthropic } from "@ai-sdk/anthropic"; // Create an agent with dynamic model selection const agent = new Agent({ name: "dynamic-model-assistant", instructions: "You are a helpful assistant.", model: ({ runtimeContext }) => { // Dynamic model selection based on runtime context const preferredProvider = runtimeContext.get("preferredProvider"); const highQuality = runtimeContext.get("highQuality") === true; if (preferredProvider === "anthropic") { return highQuality ? anthropic("claude-3-opus") : anthropic("claude-3-sonnet"); } // Default to OpenAI return highQuality ? openai("gpt-4o") : openai("gpt-3.5-turbo"); }, }); // Create a runtime context with preferences const context = new RuntimeContext(); context.set("preferredProvider", "anthropic"); context.set("highQuality", true); // Get the model using the runtime context const model = await agent.getModel({ runtimeContext: context }); console.log(model.id); // "claude-3-opus" ``` --- title: "リファレンス: Agent.getTools() | エージェント | Mastra ドキュメント" description: "Mastraエージェントの`.getTools()`メソッドに関するドキュメント。エージェントが使用できるツールを取得します。" --- # Agent.getTools() [JA] Source: https://mastra.ai/ja/reference/agents/getTools `getTools()`メソッドは、エージェントに設定されたツールを取得し、それらが関数である場合は解決します。これらのツールはエージェントの機能を拡張し、特定のアクションを実行したり外部システムにアクセスしたりすることを可能にします。 ## 構文 ```typescript getTools({ runtimeContext = new RuntimeContext() }: { runtimeContext?: RuntimeContext } = {}): ToolsInput | Promise ``` ## パラメーター
## 戻り値 エージェントのツールを含む`ToolsInput`オブジェクト、または`ToolsInput`オブジェクトに解決されるPromiseを返します。 ## 説明 `getTools()` メソッドは、エージェントが使用できるツールにアクセスするために使われます。このメソッドは、ツールを解決し、ツールはオブジェクトとして直接提供される場合や、関数から返される場合があります。 ツールはエージェントの能力の重要な要素であり、以下のことを可能にします: - 特定のアクション(データの取得や計算の実行など)を行う - 外部システムやAPIにアクセスする - コードやコマンドを実行する - データベースや他のサービスと連携する ## 例 ### 基本的な使い方 ```typescript import { Agent } from "@mastra/core/agent"; import { createTool } from "@mastra/core/tools"; import { openai } from "@ai-sdk/openai"; import { z } from "zod"; // Create tools using createTool const addTool = createTool({ id: "add", description: "Add two numbers", inputSchema: z.object({ a: z.number().describe("First number"), b: z.number().describe("Second number"), }), outputSchema: z.number(), execute: async ({ context }) => { return context.a + context.b; }, }); const multiplyTool = createTool({ id: "multiply", description: "Multiply two numbers", inputSchema: z.object({ a: z.number().describe("First number"), b: z.number().describe("Second number"), }), outputSchema: z.number(), execute: async ({ context }) => { return context.a * context.b; }, }); // Create an agent with the tools const agent = new Agent({ name: "calculator", instructions: "You are a calculator assistant that can perform mathematical operations.", model: openai("gpt-4o"), tools: { add: addTool, multiply: multiplyTool, }, }); // Get the tools const tools = await agent.getTools(); console.log(Object.keys(tools)); // ["add", "multiply"] ``` ### RuntimeContextとの併用 ```typescript import { Agent } from "@mastra/core/agent"; import { createTool } from "@mastra/core/tools"; import { RuntimeContext } from "@mastra/core/runtime-context"; import { openai } from "@ai-sdk/openai"; import { z } from "zod"; // Create an agent with dynamic tools const agent = new Agent({ name: "weather-assistant", instructions: "You are a weather assistant that can provide weather information.", model: openai("gpt-4o"), tools: ({ runtimeContext }) => { // Get API key from runtime context const apiKey = runtimeContext.get("weatherApiKey"); // Create a weather tool with the API key from context const weatherTool = createTool({ id: "getWeather", description: "Get the current weather for a location", inputSchema: z.object({ location: z.string().describe("City name"), }), outputSchema: z.object({ temperature: z.number(), conditions: z.string(), humidity: z.number(), windSpeed: z.number(), }), execute: async ({ context }) => { // Use the API key from runtime context const response = await fetch( `https://api.weather.com/current?location=${context.location}&apiKey=${apiKey}`, ); return response.json(); }, }); return { getWeather: weatherTool, }; }, }); // Create a runtime context with API key const context = new RuntimeContext(); context.set("weatherApiKey", "your-api-key"); // Get the tools using the runtime context const tools = await agent.getTools({ runtimeContext: context }); console.log(Object.keys(tools)); // ["getWeather"] ``` --- title: "リファレンス: Agent.getVoice() | エージェント | Mastra ドキュメント" description: "Mastraエージェントの`.getVoice()`メソッドに関するドキュメント。音声機能のための音声プロバイダーを取得します。" --- # Agent.getVoice() [JA] Source: https://mastra.ai/ja/reference/agents/getVoice `getVoice()`メソッドは、エージェントに設定された音声プロバイダーを取得し、それが関数の場合は解決します。このメソッドは、テキスト読み上げや音声認識機能のためにエージェントの音声機能にアクセスするために使用されます。 ## 構文 ```typescript getVoice({ runtimeContext }: { runtimeContext?: RuntimeContext } = {}): CompositeVoice | Promise ``` ## パラメーター
## 戻り値 `CompositeVoice`インスタンスまたは`CompositeVoice`インスタンスに解決されるPromiseを返します。エージェントに音声プロバイダーが設定されていない場合は、デフォルトの音声プロバイダーを返します。 ## 説明 `getVoice()` メソッドは、エージェントの音声機能にアクセスするために使用されます。このメソッドは、音声プロバイダーを解決します。音声プロバイダーは、直接指定することも、関数から返されることもあります。 音声プロバイダーによって以下が可能になります: - テキストを音声に変換する(発話) - 音声をテキストに変換する(聞き取り) - 利用可能なスピーカーや音声の取得 ## 例 ### 基本的な使い方 ```typescript import { Agent } from "@mastra/core/agent"; import { ElevenLabsVoice } from "@mastra/voice-elevenlabs"; import { openai } from "@ai-sdk/openai"; // Create an agent with a voice provider const agent = new Agent({ name: "voice-assistant", instructions: "You are a helpful voice assistant.", model: openai("gpt-4o"), voice: new ElevenLabsVoice({ apiKey: process.env.ELEVENLABS_API_KEY, }), }); // Get the voice provider const voice = await agent.getVoice(); // Use the voice provider for text-to-speech const audioStream = await voice.speak("Hello, how can I help you today?"); // Use the voice provider for speech-to-text const transcription = await voice.listen(audioStream); // Get available speakers const speakers = await voice.getSpeakers(); console.log(speakers); ``` ### RuntimeContextとの併用 ```typescript import { Agent } from "@mastra/core/agent"; import { ElevenLabsVoice } from "@mastra/voice-elevenlabs"; import { RuntimeContext } from "@mastra/core/runtime-context"; import { openai } from "@ai-sdk/openai"; // Create an agent with a dynamic voice provider const agent = new Agent({ name: "voice-assistant", instructions: ({ runtimeContext }) => { // Dynamic instructions based on runtime context const instructions = runtimeContext.get("preferredVoiceInstructions"); return instructions || "You are a helpful voice assistant."; }, model: openai("gpt-4o"), voice: new ElevenLabsVoice({ apiKey: process.env.ELEVENLABS_API_KEY, }), }); // Create a runtime context with preferences const context = new RuntimeContext(); context.set("preferredVoiceInstructions", "You are an evil voice assistant"); // Get the voice provider using the runtime context const voice = await agent.getVoice({ runtimeContext: context }); // Use the voice provider const audioStream = await voice.speak("Hello, how can I help you today?"); ``` --- title: "リファレンス: Agent.getWorkflows() | エージェント | Mastra ドキュメント" description: "Mastraエージェントの`.getWorkflows()`メソッドに関するドキュメント。エージェントが実行できるワークフローを取得します。" --- # Agent.getWorkflows() [JA] Source: https://mastra.ai/ja/reference/agents/getWorkflows `getWorkflows()`メソッドは、エージェントに設定されたワークフローを取得し、それらが関数である場合は解決します。これらのワークフローにより、エージェントは定義された実行パスを持つ複雑な複数ステップのプロセスを実行できるようになります。 ## 構文 ```typescript getWorkflows({ runtimeContext = new RuntimeContext() }: { runtimeContext?: RuntimeContext } = {}): Record | Promise> ``` ## パラメータ
## 戻り値 エージェントのワークフローを含む `Record` オブジェクト、または `Record` オブジェクトに解決されるPromiseを返します。 ## 説明 `getWorkflows()`メソッドは、エージェントが実行できるワークフローにアクセスするために使用されます。これは、オブジェクトとして直接提供されるか、ランタイムコンテキストを受け取る関数から返されるワークフローを解決します。 ## 例 ```typescript import { Agent } from "@mastra/core/agent"; import { createWorkflow, createStep } from "@mastra/core/workflows"; import { openai } from "@ai-sdk/openai"; import { z } from "zod"; const generateSuggestionsStep = createStep({ id: "generate-suggestions", inputSchema: z.object({ topic: z.string().describe("The topic to research"), }), outputSchema: z.object({ summary: z.string(), }), execute: async ({ inputData, mastra }) => { const researchAgent = mastra?.getAgent("researchAgent"); if (!researchAgent) { throw new Error("Research agent is not initialized"); } const { topic } = inputData; const result = await researchAgent.generate([ { role: "assistant", content: topic }, ]); return { summary: result.text }; }, }); const researchWorkflow = createWorkflow({ id: "research-workflow", inputSchema: z.object({ topic: z.string().describe("The topic to research"), }), outputSchema: z.object({ summary: z.string(), }), }); researchWorkflow.then(generateSuggestionsStep).commit(); // Create an agent with the workflow const agent = new Agent({ name: "research-organizer", instructions: "You are a research organizer that can delegate tasks to gather information and create summaries.", model: openai("gpt-4o"), workflows: { research: researchWorkflow, }, }); // Get the workflows const workflows = await agent.getWorkflows(); console.log(Object.keys(workflows)); // ["research"] ``` --- title: "リファレンス: Agent.stream() | ストリーミング | エージェント | Mastra ドキュメント" description: Mastra エージェントの `.stream()` メソッドのドキュメント。リアルタイムでレスポンスのストリーミングを可能にします。 --- # `stream()` [JA] Source: https://mastra.ai/ja/reference/agents/stream `stream()` メソッドは、エージェントからの応答をリアルタイムでストリーミングすることを可能にします。このメソッドは、`generate()` と同様に、`messages` とオプションの `options` オブジェクトをパラメータとして受け取ります。 ## Parameters ### `messages` `messages`パラメータは以下のいずれかを指定できます: - 単一の文字列 - 文字列の配列 - `role`と`content`プロパティを持つメッセージオブジェクトの配列 メッセージオブジェクトの構造: ```typescript interface Message { role: "system" | "user" | "assistant"; content: string; } ``` ### `options` (Optional) 出力構造、メモリ管理、ツール使用、テレメトリなどの設定を含むことができるオプションのオブジェクトです。 , title?: string }", isOptional: false, description: "会話スレッド。文字列IDまたは`id`とオプションの`metadata`を持つオブジェクトとして指定。" }] }, { parameters: [{ name: "resource", type: "string", isOptional: false, description: "スレッドに関連付けられたユーザーまたはリソースの識別子。" }] }, { parameters: [{ name: "options", type: "MemoryConfig", isOptional: true, description: "メッセージ履歴やセマンティック想起などのメモリ動作の設定。下記の`MemoryConfig`を参照。" }] } ] }, { name: "maxSteps", type: "number", isOptional: true, defaultValue: "5", description: "ストリーミング中に許可される最大ステップ数。", }, { name: "maxRetries", type: "number", isOptional: true, defaultValue: "2", description: "最大リトライ回数。リトライを無効にするには0に設定。", }, { name: "memoryOptions", type: "MemoryConfig", isOptional: true, description: "**非推奨。** 代わりに`memory.options`を使用してください。メモリ管理の設定オプション。詳細は下記のMemoryConfigセクションを参照。", }, { name: "onFinish", type: "StreamTextOnFinishCallback | StreamObjectOnFinishCallback", isOptional: true, description: "ストリーミングが完了したときに呼び出されるコールバック関数。", }, { name: "onStepFinish", type: "GenerateTextOnStepFinishCallback | never", isOptional: true, description: "ストリーミング中の各ステップ後に呼び出されるコールバック関数。構造化出力では利用できません。", }, { name: "output", type: "Zod schema | JsonSchema7", isOptional: true, description: "出力の期待される構造を定義します。JSON SchemaオブジェクトまたはZodスキーマを指定できます。", }, { name: "resourceId", type: "string", isOptional: true, description: "**非推奨。** 代わりに`memory.resource`を使用してください。エージェントと対話するユーザーまたはリソースの識別子。threadIdが提供される場合は必須です。", }, { name: "telemetry", type: "TelemetrySettings", isOptional: true, description: "ストリーミング中のテレメトリ収集の設定。詳細は下記のTelemetrySettingsセクションを参照。", }, { name: "temperature", type: "number", isOptional: true, description: "モデルの出力のランダム性を制御します。高い値(例:0.8)は出力をよりランダムにし、低い値(例:0.2)はより集中的で決定論的にします。", }, { name: "threadId", type: "string", isOptional: true, description: "**非推奨。** 代わりに`memory.thread`を使用してください。会話スレッドの識別子。複数のやり取りにわたってコンテキストを維持できます。resourceIdが提供される場合は必須です。", }, { name: "toolChoice", type: "'auto' | 'none' | 'required' | { type: 'tool'; toolName: string }", isOptional: true, defaultValue: "'auto'", description: "ストリーミング中にエージェントがツールを使用する方法を制御します。", }, { name: "toolsets", type: "ToolsetsInput", isOptional: true, description: "このストリーム中にエージェントが利用できる追加のツールセット。", }, { name: "clientTools", type: "ToolsInput", isOptional: true, description: "リクエストの「クライアント」側で実行されるツール。これらのツールは定義にexecute関数を持ちません。", }, ]} /> #### MemoryConfig メモリ管理の設定オプション: #### TelemetrySettings ストリーミング中のテレメトリ収集の設定: ", isOptional: true, description: "テレメトリデータに含める追加情報。AttributeValueは文字列、数値、ブール値、これらの型の配列、またはnullを指定できます。", }, { name: "tracer", type: "Tracer", isOptional: true, description: "テレメトリデータに使用するカスタムOpenTelemetryトレーサーインスタンス。詳細はOpenTelemetryドキュメントを参照してください。", }, ]} /> ## 戻り値 `stream()` メソッドの戻り値は、提供されたオプション、特に `output` オプションによって異なります。 ### 戻り値のプロパティテーブル ", isOptional: true, description: "テキストチャンクのストリーム。output が 'text' の場合(スキーマが提供されていない)または `experimental_output` を使用する場合に存在します。", }, { name: "objectStream", type: "AsyncIterable", isOptional: true, description: "構造化データのストリーム。スキーマを持つ `output` オプションを使用する場合にのみ存在します。", }, { name: "partialObjectStream", type: "AsyncIterable", isOptional: true, description: "構造化データのストリーム。`experimental_output` オプションを使用する場合にのみ存在します。", }, { name: "object", type: "Promise", isOptional: true, description: "最終的な構造化出力に解決されるプロミス。`output` または `experimental_output` オプションを使用する場合に存在します。", }, ]} /> ## 例 ### 基本的なテキストストリーミング ```typescript const stream = await myAgent.stream([ { role: "user", content: "Tell me a story." }, ]); for await (const chunk of stream.textStream) { process.stdout.write(chunk); } ``` ### スレッドコンテキストを持つ構造化出力ストリーミング ```typescript const schema = { type: "object", properties: { summary: { type: "string" }, nextSteps: { type: "array", items: { type: "string" } }, }, required: ["summary", "nextSteps"], }; const response = await myAgent.stream("What should we do next?", { output: schema, threadId: "project-123", onFinish: (text) => console.log("Finished:", text), }); for await (const chunk of response.textStream) { console.log(chunk); } const result = await response.object; console.log("Final structured result:", result); ``` エージェントの`stream()`とLLMの`stream()`の主な違いは、エージェントが`threadId`を通じて会話のコンテキストを維持し、ツールにアクセスでき、エージェントのメモリシステムと統合できることです。 --- title: "mastra build | プロダクションバンドル | Mastra CLI" description: "プロダクションデプロイメント用にMastraプロジェクトをビルドする" --- # mastra build [JA] Source: https://mastra.ai/ja/reference/cli/build `mastra build`コマンドは、Mastraプロジェクトをプロダクション対応のHonoサーバーにバンドルします。Honoは軽量でタイプセーフなWebフレームワークで、ミドルウェアサポートを備えたHTTPエンドポイントとしてMastraエージェントを簡単にデプロイできます。 ## 使用方法 ```bash mastra build [options] ``` ## オプション ## 高度な使用方法 ### 並列処理の制限 CIまたはリソースが制約された環境で実行する場合、`MASTRA_CONCURRENCY`を設定することで、一度に実行される高負荷タスクの数を制限できます。 ```bash copy MASTRA_CONCURRENCY=2 mastra build ``` 設定を解除すると、CLIはホストの機能に基づいて並列処理数を決定します。 ### テレメトリの無効化 匿名のビルド分析をオプトアウトするには、以下を設定してください: ```bash copy MASTRA_TELEMETRY_DISABLED=1 mastra build ``` ### カスタムプロバイダーエンドポイント ビルド時は、`mastra dev`と同じ`OPENAI_BASE_URL`および`ANTHROPIC_BASE_URL`変数を尊重します。これらの変数は、AI SDKによってプロバイダーを呼び出すワークフローやツールに転送されます。 ## 機能 1. Mastraのエントリーファイル(`src/mastra/index.ts`または`src/mastra/index.js`)を見つけます 2. `.mastra`出力ディレクトリを作成します 3. 以下の機能を備えたRollupを使用してコードをバンドルします: - 最適なバンドルサイズのためのツリーシェイキング - Node.js環境のターゲティング - デバッグ用のソースマップ生成 ## 例 ```bash copy # Build from current directory mastra build # Build from specific directory mastra build --dir ./my-mastra-project ``` ## 出力 このコマンドは、`.mastra` ディレクトリに本番用バンドルを生成します。内容は以下の通りです: - Mastra エージェントがエンドポイントとして公開された Hono ベースの HTTP サーバー - 本番環境向けに最適化されたバンドル済み JavaScript ファイル - デバッグ用のソースマップ - 必要な依存関係 この出力は以下の用途に適しています: - クラウドサーバー(EC2、Digital Ocean)へのデプロイ - コンテナ化された環境での実行 - コンテナオーケストレーションシステムとの併用 ## デプロイヤー デプロイヤーを使用すると、ビルド出力が自動的に対象プラットフォーム向けに準備されます。例: - [Vercel Deployer](/reference/deployer/vercel) - [Netlify Deployer](/reference/deployer/netlify) - [Cloudflare Deployer](/reference/deployer/cloudflare) --- title: "create-mastra | プロジェクト作成 | Mastra CLI" description: create-mastraコマンドのドキュメント。インタラクティブなセットアップオプションで新しいMastraプロジェクトを作成します。 --- # create-mastra [JA] Source: https://mastra.ai/ja/reference/cli/create-mastra `create-mastra`コマンドは新しいスタンドアロンのMastraプロジェクトを**作成**します。このコマンドを使用して、専用ディレクトリに完全なMastraセットアップをスキャフォールドします。 ## 使用方法 ```bash create-mastra [options] ``` ## オプション --- title: "mastra dev | 開発サーバー | Mastra CLI" description: エージェント、ツール、ワークフローの開発サーバーを起動するmastra devコマンドのドキュメント。 --- # mastra dev [JA] Source: https://mastra.ai/ja/reference/cli/dev `mastra dev`コマンドは、エージェント、ツール、ワークフローのREST エンドポイントを公開する開発サーバーを起動します。 ## 使用方法 ```bash mastra dev [options] ``` ## オプション ## ルート `mastra dev`でサーバーを起動すると、デフォルトで一連のRESTルートが公開されます: ### システムルート - **GET `/api`**: API ステータスを取得します。 ### エージェントルート エージェントは`src/mastra/agents`からエクスポートされることが期待されています。 - **GET `/api/agents`**: Mastraフォルダ内で見つかった登録済みエージェントをリストします。 - **GET `/api/agents/:agentId`**: IDでエージェントを取得します。 - **GET `/api/agents/:agentId/evals/ci`**: エージェントIDでCI評価を取得します。 - **GET `/api/agents/:agentId/evals/live`**: エージェントIDでライブ評価を取得します。 - **POST `/api/agents/:agentId/generate`**: 指定されたエージェントにテキストベースのプロンプトを送信し、エージェントの応答を返します。 - **POST `/api/agents/:agentId/stream`**: エージェントからの応答をストリームします。 - **POST `/api/agents/:agentId/instructions`**: エージェントの指示を更新します。 - **POST `/api/agents/:agentId/instructions/enhance`**: 指示から改良されたシステムプロンプトを生成します。 - **GET `/api/agents/:agentId/speakers`**: エージェントで利用可能なスピーカーを取得します。 - **POST `/api/agents/:agentId/speak`**: エージェントの音声プロバイダーを使用してテキストを音声に変換します。 - **POST `/api/agents/:agentId/listen`**: エージェントの音声プロバイダーを使用して音声をテキストに変換します。 - **POST `/api/agents/:agentId/tools/:toolId/execute`**: エージェントを通じてツールを実行します。 ### ツールルート ツールは`src/mastra/tools`(または設定されたツールディレクトリ)からエクスポートされることが期待されています。 - **GET `/api/tools`**: すべてのツールを取得します。 - **GET `/api/tools/:toolId`**: IDでツールを取得します。 - **POST `/api/tools/:toolId/execute`**: 名前で特定のツールを呼び出し、リクエストボディで入力データを渡します。 ### ワークフロールート ワークフローは`src/mastra/workflows`(または設定されたワークフローディレクトリ)からエクスポートされることが期待されています。 - **GET `/api/workflows`**: すべてのワークフローを取得します。 - **GET `/api/workflows/:workflowId`**: IDでワークフローを取得します。 - **POST `/api/workflows/:workflowName/start`**: 指定されたワークフローを開始します。 - **POST `/api/workflows/:workflowName/:instanceId/event`**: 既存のワークフローインスタンスにイベントまたはトリガーシグナルを送信します。 - **GET `/api/workflows/:workflowName/:instanceId/status`**: 実行中のワークフローインスタンスのステータス情報を返します。 - **POST `/api/workflows/:workflowId/resume`**: 中断されたワークフローステップを再開します。 - **POST `/api/workflows/:workflowId/resume-async`**: 中断されたワークフローステップを非同期で再開します。 - **POST `/api/workflows/:workflowId/createRun`**: 新しいワークフロー実行を作成します。 - **POST `/api/workflows/:workflowId/start-async`**: ワークフローを非同期で実行/開始します。 - **GET `/api/workflows/:workflowId/watch`**: ワークフローの遷移をリアルタイムで監視します。 ### メモリルート - **GET `/api/memory/status`**: メモリステータスを取得します。 - **GET `/api/memory/threads`**: すべてのスレッドを取得します。 - **GET `/api/memory/threads/:threadId`**: IDでスレッドを取得します。 - **GET `/api/memory/threads/:threadId/messages`**: スレッドのメッセージを取得します。 - **POST `/api/memory/threads`**: 新しいスレッドを作成します。 - **PATCH `/api/memory/threads/:threadId`**: スレッドを更新します。 - **DELETE `/api/memory/threads/:threadId`**: スレッドを削除します。 - **POST `/api/memory/save-messages`**: メッセージを保存します。 ### テレメトリルート - **GET `/api/telemetry`**: すべてのトレースを取得します。 ### ログルート - **GET `/api/logs`**: すべてのログを取得します。 - **GET `/api/logs/transports`**: すべてのログトランスポートのリスト。 - **GET `/api/logs/:runId`**: 実行IDでログを取得します。 ### ベクタールート - **POST `/api/vector/:vectorName/upsert`**: インデックスにベクトルをアップサートします。 - **POST `/api/vector/:vectorName/create-index`**: 新しいベクトルインデックスを作成します。 - **POST `/api/vector/:vectorName/query`**: インデックスからベクトルをクエリします。 - **GET `/api/vector/:vectorName/indexes`**: ベクトルストアのすべてのインデックスを一覧表示します。 - **GET `/api/vector/:vectorName/indexes/:indexName`**: 特定のインデックスの詳細を取得します。 - **DELETE `/api/vector/:vectorName/indexes/:indexName`**: 特定のインデックスを削除します。 ### OpenAPI仕様 - **GET `/openapi.json`**: プロジェクトのルートの自動生成されたOpenAPI仕様を返します。 - **GET `/swagger-ui`**: API文書化のためのSwagger UIにアクセスします。 ## 追加の注意事項 ポートはデフォルトで4111です。ポートとホスト名の両方は、mastraサーバー設定で設定できます。設定の詳細については、[開発サーバーの起動](/docs/local-dev/mastra-dev#launch-development-server)を参照してください。 使用するプロバイダーの環境変数が`.env.development`または`.env`ファイルに設定されていることを確認してください(例:`OPENAI_API_KEY`、`ANTHROPIC_API_KEY`など)。 Mastraフォルダ内の`index.ts`ファイルが、開発サーバーが読み取れるようにMastraインスタンスをエクスポートしていることを確認してください。 ### リクエスト例 `mastra dev`を実行した後にエージェントをテストするには: ```bash copy curl -X POST http://localhost:4111/api/agents/myAgent/generate \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "role": "user", "content": "Hello, how can you assist me today?" } ] }' ``` ## 高度な使用方法 `mastra dev`サーバーは、開発中に便利ないくつかの追加の環境変数に従います: ### ビルドキャッシュを無効にする `MASTRA_DEV_NO_CACHE=1`を設定すると、`.mastra/`下のキャッシュされたアセットを使用するのではなく、完全な再ビルドを強制します: ```bash copy MASTRA_DEV_NO_CACHE=1 mastra dev ``` これは、バンドラープラグインをデバッグしている場合や、古い出力を疑っている場合に役立ちます。 ### 並列処理を制限する `MASTRA_CONCURRENCY`は、並列で実行される高コストな操作の数を制限します(主にビルドと評価ステップ)。例えば: ```bash copy MASTRA_CONCURRENCY=4 mastra dev ``` 未設定のままにすると、CLIがマシンに適した適切なデフォルト値を選択します。 ### カスタムプロバイダーエンドポイント Vercel AI SDKでサポートされているプロバイダーを使用する場合、ベースURLを設定することで、プロキシや内部ゲートウェイ経由でリクエストをリダイレクトできます。OpenAIの場合: ```bash copy OPENAI_API_KEY= \ OPENAI_BASE_URL=https://openrouter.example/v1 \ mastra dev ``` Anthropicの場合: ```bash copy OPENAI_API_KEY= \ ANTHROPIC_BASE_URL=https://anthropic.internal \ mastra dev ``` これらはAI SDKによって転送され、任意の`openai()`または`anthropic()`呼び出しで動作します。 ### テレメトリを無効にする 匿名のCLI分析をオプトアウトするには、`MASTRA_TELEMETRY_DISABLED=1`を設定します。これにより、ローカルプレイグラウンド内でのトラッキングも防止されます。 ```bash copy MASTRA_TELEMETRY_DISABLED=1 mastra dev ``` --- title: "mastra init | プロジェクトの初期化 | Mastra CLI" description: 新しいMastraプロジェクトをインタラクティブなセットアップオプションで作成するmastra initコマンドのドキュメント。 --- # mastra init [JA] Source: https://mastra.ai/ja/reference/cli/init `mastra init`コマンドは、既存のプロジェクトでMastraを**初期化**します。このコマンドを使用して、新しいプロジェクトを生成することなく、必要なフォルダと設定をスキャフォールドします。 ## 使用方法 ```bash mastra init [options] ``` ## オプション ## 高度な使用方法 ### アナリティクスを無効にする 匿名の使用データを送信したくない場合は、コマンドを実行する際に `MASTRA_TELEMETRY_DISABLED=1` 環境変数を設定してください: ```bash copy MASTRA_TELEMETRY_DISABLED=1 mastra init ``` ### カスタムプロバイダーエンドポイント 初期化されたプロジェクトは、存在する場合 `OPENAI_BASE_URL` と `ANTHROPIC_BASE_URL` 変数を尊重します。これにより、後で開発サーバーを起動する際に、 プロバイダーのトラフィックをプロキシやプライベートゲートウェイ経由でルーティングできます。 --- title: "mastra lint | プロジェクトの検証 | Mastra CLI" description: "Mastraプロジェクトをlintする" --- # mastra lint [JA] Source: https://mastra.ai/ja/reference/cli/lint `mastra lint`コマンドは、Mastraプロジェクトの構造とコードを検証し、ベストプラクティスに従い、エラーがないことを確認します。 ## 使用方法 ```bash mastra lint [options] ``` ## オプション ## 高度な使用方法 ### テレメトリを無効にする リンティング(およびその他のコマンド)の実行中にCLI分析を無効にするには、 `MASTRA_TELEMETRY_DISABLED=1`を設定してください: ```bash copy MASTRA_TELEMETRY_DISABLED=1 mastra lint ``` --- title: "@mastra/mcp-docs-server" description: "MCP経由でMastraのドキュメント、例、ブログ投稿を提供する" --- `@mastra/mcp-docs-server`パッケージは、小さな[Model Context Protocol](https://github.com/modelcontextprotocol/mcp)サーバーを実行し、Mastraのドキュメント、コード例、ブログ投稿、変更履歴をLLMエージェントが検索できるようにします。コマンドラインから手動で呼び出すことも、CursorやWindsurfなどのMCP対応IDEで設定することもできます。 ## CLIからの実行 [JA] Source: https://mastra.ai/ja/reference/cli/mcp-docs-server ```bash npx -y @mastra/mcp-docs-server ``` 上記のコマンドは、stdio ベースの MCP サーバーを実行します。プロセスは `stdin` からリクエストを読み続け、`stdout` でレスポンスを返します。これは IDE 統合で使用されるのと同じコマンドです。手動で実行する場合は、探索のために `@wong2/mcp-cli` パッケージを指定することができます。 ### 例 サーブする前にドキュメントを再構築する(ローカルでドキュメントを変更した場合に便利): ```bash REBUILD_DOCS_ON_START=true npx -y @mastra/mcp-docs-server ``` 実験中に詳細ログを有効にする: ```bash DEBUG=1 npx -y @mastra/mcp-docs-server ``` カスタムドメインからブログ投稿をサーブする: ```bash BLOG_URL=https://my-blog.example npx -y @mastra/mcp-docs-server ``` ## 環境変数 `@mastra/mcp-docs-server` は、その動作を調整するいくつかの環境変数に対応しています。 - **`REBUILD_DOCS_ON_START`** - `true` に設定すると、サーバーは stdio にバインドする前に `.docs` ディレクトリを再構築します。これは、ローカルでドキュメントを編集または追加した後に役立ちます。 - **`PREPARE`** - ドキュメントのビルドステップ(`pnpm mcp-docs-server prepare-docs`)は、リポジトリから `.docs` へ Markdown ソースをコピーするために `PREPARE=true` を探します。 - **`BLOG_URL`** - ブログ記事を取得するために使用されるベースURLです。デフォルトは `https://mastra.ai` です。 - **`DEBUG`** または **`NODE_ENV=development`** - `stderr` に書き込まれるログを増やします。 基本的な実行には他の変数は必要ありません。サーバーには事前にビルドされたドキュメントディレクトリが付属しています。 ## カスタムドキュメントでの再構築 このパッケージには、ドキュメントのプリコンパイルされたコピーが含まれています。追加のコンテンツを試してみたい場合は、`.docs`ディレクトリをローカルで再構築することができます: ```bash pnpm mcp-docs-server prepare-docs ``` このスクリプトは、`mastra/docs/src/content/en/docs`と`mastra/docs/src/content/en/reference`からドキュメントをコピーしてパッケージに取り込みます。再構築後、`REBUILD_DOCS_ON_START=true`を設定してサーバーを起動すると、新しいコンテンツが提供されます。 再構築が必要なのは、カスタマイズされたドキュメントを提供する必要がある場合のみです。通常の使用では、公開されているパッケージの内容に依存することができます。 IDE設定の詳細については、[スタートガイド](/docs/getting-started/mcp-docs-server)を参照してください。 --- title: 'mastra start' description: '構築されたMastraアプリケーションを起動する' --- # mastra start [JA] Source: https://mastra.ai/ja/reference/cli/start ビルドされたMastraアプリケーションを開始します。このコマンドは、ビルドされたMastraアプリケーションを本番モードで実行するために使用されます。 テレメトリはデフォルトで有効になっています。 ## 使用方法 `mastra build`でプロジェクトをビルドした後、以下を実行してください: ```bash mastra start [options] ``` ## オプション | オプション | 説明 | |--------|-------------| | `-d, --dir ` | ビルドされたMastra出力ディレクトリへのパス(デフォルト: .mastra/output) | | `-nt, --no-telemetry` | 可観測性のためのOpenTelemetryインストルメンテーションを有効にする | ## 例 デフォルト設定でアプリケーションを開始: ```bash mastra start ``` カスタム出力ディレクトリから開始: ```bash mastra start --dir ./my-output ``` テレメトリを無効にして開始: ```bash mastra start -nt ``` --- title: Mastra クライアントエージェント API description: Mastra AIエージェントとの対話方法を学びましょう。レスポンスの生成、ストリーミング対話、client-js SDKを使用したエージェントツールの管理などが含まれます。 --- # Agents API [JA] Source: https://mastra.ai/ja/reference/client-js/agents Agents APIは、Mastra AIエージェントと対話するためのメソッドを提供し、レスポンスの生成、ストリーミング対話、エージェントツールの管理などが含まれます。 ## Mastraクライアントの初期化 ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient(); ``` ## すべてのエージェントの取得 利用可能なすべてのエージェントのリストを取得します: ```typescript const agents = await client.getAgents(); ``` ## 特定のエージェントの操作 特定のエージェントのインスタンスを取得する: ```typescript const agent = client.getAgent("agent-id"); ``` ## エージェントメソッド ### エージェントの詳細を取得 エージェントの詳細情報を取得します: ```typescript const details = await agent.details(); ``` ### 応答を生成 エージェントから応答を生成します: ```typescript const response = await agent.generate({ messages: [ { role: "user", content: "Hello, how are you?", }, ], threadId: "thread-1", // オプション: 会話コンテキスト用のスレッドID resourceid: "resource-1", // オプション: リソースID output: {}, // オプション: 出力設定 }); ``` ### 応答をストリーム リアルタイムのやり取りのために、エージェントからの応答をストリーミングします: ```typescript const response = await agent.stream({ messages: [ { role: "user", content: "Tell me a story", }, ], }); // processDataStreamユーティリティでデータストリームを処理 response.processDataStream({ onTextPart: (text) => { process.stdout.write(text); }, onFilePart: (file) => { console.log(file); }, onDataPart: (data) => { console.log(data); }, onErrorPart: (error) => { console.error(error); }, }); // response bodyから直接読み取ることも可能です const reader = response.body.getReader(); while (true) { const { done, value } = await reader.read(); if (done) break; console.log(new TextDecoder().decode(value)); } ``` ### エージェントツールを取得 エージェントが利用可能な特定のツールの情報を取得します: ```typescript const tool = await agent.getTool("tool-id"); ``` ### エージェント評価を取得 エージェントの評価結果を取得します: ```typescript // CI評価を取得 const evals = await agent.evals(); // ライブ評価を取得 const liveEvals = await agent.liveEvals(); ``` --- title: Mastraクライアントのエラー処理 description: Mastra client-js SDKに組み込まれた再試行メカニズムとエラー処理機能について学びます。 --- # エラー処理 [JA] Source: https://mastra.ai/ja/reference/client-js/error-handling Mastra Client SDKには、組み込みの再試行メカニズムとエラー処理機能が含まれています。 ## エラー処理 すべてのAPIメソッドは、キャッチして処理できるエラーをスローする可能性があります: ```typescript try { const agent = client.getAgent("agent-id"); const response = await agent.generate({ messages: [{ role: "user", content: "Hello" }], }); } catch (error) { console.error("An error occurred:", error.message); } ``` ## リトライメカニズム クライアントは失敗したリクエストを指数バックオフで自動的に再試行します: ```typescript const client = new MastraClient({ baseUrl: "http://localhost:4111", retries: 3, // リトライ試行回数 backoffMs: 300, // 初期バックオフ時間 maxBackoffMs: 5000, // 最大バックオフ時間 }); ``` ### リトライの仕組み 1. 最初の試行が失敗 → 300ms待機 2. 2回目の試行が失敗 → 600ms待機 3. 3回目の試行が失敗 → 1200ms待機 4. 最終試行が失敗 → エラーをスロー --- title: Mastra クライアントログ API description: client-js SDKを使用してMastraでシステムログとデバッグ情報にアクセスし、クエリを実行する方法を学びます。 --- # ログ API [JA] Source: https://mastra.ai/ja/reference/client-js/logs ログ API は、Mastra のシステムログとデバッグ情報にアクセスして照会するためのメソッドを提供します。 ## Mastraクライアントの初期化 ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient(); ``` ## ログの取得 オプションのフィルタリングを使用してシステムログを取得します: ```typescript const logs = await client.getLogs({ transportId: "transport-1", }); ``` ## 特定の実行ランのログを取得する 特定の実行ランのログを取得します: ```typescript const runLogs = await client.getLogForRun({ runId: "run-1", transportId: "transport-1", }); ``` --- title: Mastra クライアントメモリAPI description: client-js SDKを使用してMastraで会話スレッドとメッセージ履歴を管理する方法を学びます。 --- # メモリーAPI [JA] Source: https://mastra.ai/ja/reference/client-js/memory メモリーAPIは、Mastraでの会話スレッドとメッセージ履歴を管理するためのメソッドを提供します。 ## Mastraクライアントの初期化 ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient(); ``` ## メモリスレッド操作 ### すべてのスレッドを取得 特定のリソースに対するすべてのメモリスレッドを取得します: ```typescript const threads = await client.getMemoryThreads({ resourceId: "resource-1", agentId: "agent-1", }); ``` ### 新しいスレッドを作成 新しいメモリスレッドを作成します: ```typescript const thread = await client.createMemoryThread({ title: "New Conversation", metadata: { category: "support" }, resourceid: "resource-1", agentId: "agent-1", }); ``` ### 特定のスレッドを操作する 特定のメモリスレッドのインスタンスを取得します: ```typescript const thread = client.getMemoryThread("thread-id", "agent-id"); ``` ## Thread Methods ### Get Thread Details 特定のスレッドの詳細を取得します: ```typescript const details = await thread.get(); ``` ### Update Thread スレッドのプロパティを更新します: ```typescript const updated = await thread.update({ title: "Updated Title", metadata: { status: "resolved" }, resourceid: "resource-1", }); ``` ### Delete Thread スレッドとそのメッセージを削除します: ```typescript await thread.delete(); ``` ## メッセージ操作 ### メッセージの保存 メッセージをメモリに保存します: ```typescript const savedMessages = await client.saveMessageToMemory({ messages: [ { role: "user", content: "Hello!", id: "1", threadId: "thread-1", createdAt: new Date(), type: "text", }, ], agentId: "agent-1", }); ``` ### スレッドメッセージの取得 メモリスレッドに関連付けられたメッセージを取得します: ```typescript // スレッド内のすべてのメッセージを取得 const { messages } = await thread.getMessages(); // 取得するメッセージ数を制限 const { messages } = await thread.getMessages({ limit: 10 }); ``` ### メモリステータスの取得 メモリシステムのステータスを確認します: ```typescript const status = await client.getMemoryStatus("agent-id"); ``` --- title: Mastra クライアントテレメトリAPI description: client-js SDKを使用して、監視やデバッグのためにMastraアプリケーションからトレースを取得し分析する方法を学びます。 --- # テレメトリーAPI [JA] Source: https://mastra.ai/ja/reference/client-js/telemetry テレメトリーAPIは、Mastraアプリケーションからトレースを取得して分析するためのメソッドを提供します。これにより、アプリケーションの動作とパフォーマンスを監視およびデバッグするのに役立ちます。 ## Mastraクライアントの初期化 ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient(); ``` ## トレースの取得 オプションのフィルタリングやページネーションを使ってトレースを取得します: ```typescript const telemetry = await client.getTelemetry({ name: "trace-name", // Optional: Filter by trace name scope: "scope-name", // Optional: Filter by scope page: 1, // Optional: Page number for pagination perPage: 10, // Optional: Number of items per page attribute: { // Optional: Filter by custom attributes key: "value", }, }); ``` --- title: Mastra クライアントツール API description: client-js SDKを使用してMastraプラットフォームで利用可能なツールを操作および実行する方法を学びます。 --- # ツールAPI [JA] Source: https://mastra.ai/ja/reference/client-js/tools ツールAPIは、Mastraプラットフォームで利用可能なツールを操作および実行するためのメソッドを提供します。 ## Mastraクライアントの初期化 ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient(); ``` ## すべてのツールの取得 利用可能なすべてのツールのリストを取得します: ```typescript const tools = await client.getTools(); ``` ## 特定のツールの操作 特定のツールのインスタンスを取得する: ```typescript const tool = client.getTool("tool-id"); ``` ## ツールメソッド ### ツールの詳細を取得 ツールの詳細情報を取得します: ```typescript const details = await tool.details(); ``` ### ツールの実行 特定の引数でツールを実行します: ```typescript const result = await tool.execute({ args: { param1: "value1", param2: "value2", }, threadId: "thread-1", // Optional: Thread context resourceid: "resource-1", // Optional: Resource identifier }); ``` --- title: Mastra クライアントベクトル API description: client-js SDKを使用して、セマンティック検索や類似性マッチングのためのベクトル埋め込みをMastraで操作する方法を学びます。 --- # Vectors API [JA] Source: https://mastra.ai/ja/reference/client-js/vectors Vectors APIは、Mastraでのセマンティック検索や類似性マッチングのためのベクトル埋め込みを操作するメソッドを提供します。 ## Mastraクライアントの初期化 ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient(); ``` ## ベクトルの操作 ベクトルストアのインスタンスを取得する: ```typescript const vector = client.getVector("vector-name"); ``` ## ベクトルメソッド ### ベクトルインデックスの詳細を取得 特定のベクトルインデックスに関する情報を取得します: ```typescript const details = await vector.details("index-name"); ``` ### ベクトルインデックスの作成 新しいベクトルインデックスを作成します: ```typescript const result = await vector.createIndex({ indexName: "new-index", dimension: 128, metric: "cosine", // 'cosine', 'euclidean', または 'dotproduct' }); ``` ### ベクトルのアップサート インデックスにベクトルを追加または更新します: ```typescript const ids = await vector.upsert({ indexName: "my-index", vectors: [ [0.1, 0.2, 0.3], // 最初のベクトル [0.4, 0.5, 0.6], // 2番目のベクトル ], metadata: [{ label: "first" }, { label: "second" }], ids: ["id1", "id2"], // オプション:カスタムID }); ``` ### ベクトルのクエリ 類似したベクトルを検索します: ```typescript const results = await vector.query({ indexName: "my-index", queryVector: [0.1, 0.2, 0.3], topK: 10, filter: { label: "first" }, // オプション:メタデータフィルター includeVector: true, // オプション:結果にベクトルを含める }); ``` ### すべてのインデックスを取得 利用可能なすべてのインデックスを一覧表示します: ```typescript const indexes = await vector.getIndexes(); ``` ### インデックスの削除 ベクトルインデックスを削除します: ```typescript const result = await vector.delete("index-name"); ``` --- title: Mastra クライアントワークフロー(レガシー)API description: client-js SDKを使用してMastraで自動化されたレガシーワークフローを操作および実行する方法を学びます。 --- # ワークフロー(レガシー)API [JA] Source: https://mastra.ai/ja/reference/client-js/workflows-legacy ワークフロー(レガシー)APIは、Mastraの自動化されたレガシーワークフローと対話し、実行するためのメソッドを提供します。 ## Mastraクライアントの初期化 ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient(); ``` ## レガシーワークフローの取得 利用可能なすべてのレガシーワークフローのリストを取得します: ```typescript const workflows = await client.getLegacyWorkflows(); ``` ## 特定のレガシーワークフローの操作 特定のレガシーワークフローのインスタンスを取得します: ```typescript const workflow = client.getLegacyWorkflow("workflow-id"); ``` ## レガシーワークフローメソッド ### レガシーワークフローの詳細を取得 レガシーワークフローの詳細情報を取得します: ```typescript const details = await workflow.details(); ``` ### レガシーワークフローの実行を非同期で開始 triggerData を指定してレガシーワークフローの実行を開始し、実行結果を待ちます: ```typescript const { runId } = workflow.createRun(); const result = await workflow.startAsync({ runId, triggerData: { param1: "value1", param2: "value2", }, }); ``` ### レガシーワークフローの実行を非同期で再開 一時停止中のレガシーワークフローステップを再開し、実行結果を待ちます: ```typescript const { runId } = createRun({ runId: prevRunId }); const result = await workflow.resumeAsync({ runId, stepId: "step-id", contextData: { key: "value" }, }); ``` ### レガシーワークフローの監視 レガシーワークフローの遷移を監視します ```typescript try { // Get workflow instance const workflow = client.getLegacyWorkflow("workflow-id"); // Create a workflow run const { runId } = workflow.createRun(); // Watch workflow run workflow.watch({ runId }, (record) => { // Every new record is the latest transition state of the workflow run console.log({ activePaths: record.activePaths, results: record.results, timestamp: record.timestamp, runId: record.runId, }); }); // Start workflow run workflow.start({ runId, triggerData: { city: "New York", }, }); } catch (e) { console.error(e); } ``` ### レガシーワークフローの再開 レガシーワークフローの実行を再開し、レガシーワークフローステップの遷移を監視します ```typescript try { //To resume a workflow run, when a step is suspended const { run } = createRun({ runId: prevRunId }); //Watch run workflow.watch({ runId }, (record) => { // Every new record is the latest transition state of the workflow run console.log({ activePaths: record.activePaths, results: record.results, timestamp: record.timestamp, runId: record.runId, }); }); //resume run workflow.resume({ runId, stepId: "step-id", contextData: { key: "value" }, }); } catch (e) { console.error(e); } ``` ### レガシーワークフロー実行結果 レガシーワークフローの実行結果は以下の内容を含みます: | フィールド | 型 | 説明 | | ------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------ | | `activePaths` | `Record` | ワークフロー内で現在アクティブなパスとその実行ステータス | | `results` | `LegacyWorkflowRunResult['results']` | ワークフロー実行からの結果 | | `timestamp` | `number` | この遷移が発生した Unix タイムスタンプ | | `runId` | `string` | このワークフロー実行インスタンスの一意な識別子 | --- title: Mastra クライアントワークフロー (vNext) API description: client-js SDKを使用してMastraで自動化されたvNextワークフローを操作および実行する方法を学びます。 --- # ワークフロー(vNext)API [JA] Source: https://mastra.ai/ja/reference/client-js/workflows-vnext ワークフロー(vNext)APIは、Mastraで自動化されたvNextワークフローを操作および実行するためのメソッドを提供します。 ## Mastraクライアントの初期化 ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient(); ``` ## vNextワークフローの取得 利用可能なすべてのvNextワークフローのリストを取得します: ```typescript const workflows = await client.getVNextWorkflows(); ``` ## 特定のvNextワークフローの操作 特定のvNextワークフローのインスタンスを取得します: ```typescript const workflow = client.getVNextWorkflow("workflow-id"); ``` ## vNext ワークフローメソッド ### vNext ワークフローの詳細を取得 vNext ワークフローの詳細情報を取得します: ```typescript const details = await workflow.details(); ``` ### vNext ワークフロー実行を非同期で開始 triggerData を使って vNext ワークフロー実行を開始し、実行結果を待ちます: ```typescript const run = workflow.createRun(); const result = await workflow.startAsync({ runId: run.runId, inputData: { param1: "value1", param2: "value2", }, }); ``` ### vNext ワークフロー実行を非同期で再開 一時停止中の vNext ワークフローステップを再開し、実行結果を待ちます: ```typescript const run = workflow.createRun(); const result = await workflow.resumeAsync({ runId: run.runId, step: "step-id", resumeData: { key: "value" }, }); ``` ### vNext ワークフローの監視 vNext ワークフローの遷移を監視します ```typescript try { // Get workflow instance const workflow = client.getVNextWorkflow("workflow-id"); // Create a workflow run const run = workflow.createRun(); // Watch workflow run workflow.watch({ runId: run.runId }, (record) => { // Every new record is the latest transition state of the workflow run console.log({ currentStep: record.payload.currentStep, workflowState: record.payload.workflowState, eventTimestamp: record.eventTimestamp, runId: record.runId, }); }); // Start workflow run workflow.start({ runId: run.runId, inputData: { city: "New York", }, }); } catch (e) { console.error(e); } ``` ### vNext ワークフローの再開 vNext ワークフロー実行を再開し、vNext ワークフローステップの遷移を監視します ```typescript try { // Get workflow instance const workflow = client.getVNextWorkflow("workflow-id"); //To resume a workflow run, when a step is suspended const run = workflow.createRun({ runId: prevRunId }); //Watch run workflow.watch({ runId: run.runId }, (record) => { // Every new record is the latest transition state of the workflow run console.log({ currentStep: record.payload.currentStep, workflowState: record.payload.workflowState, eventTimestamp: record.eventTimestamp, runId: record.runId, }); }); //resume run workflow.resume({ runId: run.runId, step: "step-id", resumeData: { key: "value" }, }); } catch (e) { console.error(e); } ``` ### vNext ワークフロー実行結果 vNext ワークフロー実行結果は以下の内容を含みます: | フィールド | 型 | 説明 | | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | | `payload` | `{currentStep?: {id: string, status: string, output?: Record, payload?: Record}, workflowState: {status: string, steps: Record, payload?: Record}>}}` | 実行中のステップとワークフローの状態 | | `eventTimestamp` | `Date` | イベントのタイムスタンプ | | `runId` | `string` | このワークフロー実行インスタンスの一意識別子 | --- title: Mastra クライアントワークフローAPI description: client-js SDKを使用してMastraで自動化されたワークフローを操作および実行する方法を学びます。 --- # ワークフローAPI [JA] Source: https://mastra.ai/ja/reference/client-js/workflows ワークフローAPIは、Mastraの自動化されたワークフローを操作および実行するためのメソッドを提供します。 ## Mastraクライアントの初期化 ```typescript import { MastraClient } from "@mastra/client-js"; const client = new MastraClient(); ``` ## すべてのワークフローの取得 利用可能なすべてのワークフローのリストを取得します: ```typescript const workflows = await client.getWorkflows(); ``` ## 特定のワークフローの操作 const名で定義された特定のワークフローのインスタンスを取得します: ```typescript filename="src/mastra/workflows/test-workflow.ts" export const testWorkflow = createWorkflow({ id: 'city-workflow' }) ``` ```typescript const workflow = client.getWorkflow("testWorkflow"); ``` ## Workflow Methods ### Get Workflow Details ワークフローの詳細情報を取得します: ```typescript const details = await workflow.details(); ``` ### Start workflow run asynchronously inputDataでワークフロー実行を開始し、完全な実行結果を待機します: ```typescript const run = await workflow.createRun(); const result = await workflow.startAsync({ runId: run.runId, inputData: { city: "New York", }, }); ``` ### Resume Workflow run asynchronously 中断されたワークフローステップを再開し、完全な実行結果を待機します: ```typescript const run = await workflow.createRun(); const result = await workflow.resumeAsync({ runId: run.runId, step: "step-id", resumeData: { key: "value" }, }); ``` ### Watch Workflow ワークフローの遷移を監視します: ```typescript try { const workflow = client.getWorkflow("testWorkflow"); const run = await workflow.createRun(); workflow.watch({ runId: run.runId }, (record) => { console.log(record); }); const result = await workflow.start({ runId: run.runId, inputData: { city: "New York", }, }); } catch (e) { console.error(e); } ``` ### Resume Workflow ワークフロー実行を再開し、ワークフローステップの遷移を監視します: ```typescript try { const workflow = client.getWorkflow("testWorkflow"); const run = await workflow.createRun({ runId: prevRunId }); workflow.watch({ runId: run.runId }, (record) => { console.log(record); }); workflow.resume({ runId: run.runId, step: "step-id", resumeData: { key: "value" }, }); } catch (e) { console.error(e); } ``` ### Get Workflow Run result ワークフロー実行の結果を取得します: ```typescript try { const workflow = client.getWorkflow("testWorkflow"); const run = await workflow.createRun(); // start the workflow run const startResult = await workflow.start({ runId: run.runId, inputData: { city: "New York", }, }); const result = await workflow.runExecutionResult(run.runId); console.log(result); } catch (e) { console.error(e); } ``` これは長時間実行されるワークフローを扱う際に便利です。ワークフロー実行の結果をポーリングするために使用できます。 ### Workflow run result ワークフロー実行結果は以下を返します: | Field | Type | Description | | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | | `payload` | `{currentStep?: {id: string, status: string, output?: Record, payload?: Record}, workflowState: {status: string, steps: Record, payload?: Record}>}}` | 実行の現在のステップとワークフロー状態 | | `eventTimestamp` | `Date` | イベントのタイムスタンプ | | `runId` | `string` | このワークフロー実行インスタンスの一意識別子 | --- title: "Mastra Core" description: エージェント、ワークフロー、MCPサーバー、およびサーバーエンドポイントを管理するためのコアエントリーポイントであるMastraクラスのドキュメント。 --- # The Mastra Class [JA] Source: https://mastra.ai/ja/reference/core/mastra-class `Mastra`クラスは、あらゆるMastraアプリケーションの中心的なオーケストレーターであり、エージェント、ワークフロー、ストレージ、ログ記録、テレメトリなどを管理します。通常、アプリケーションを調整するために`Mastra`の単一インスタンスを作成します。 `Mastra`をトップレベルのレジストリとして考えてください: - **integrations**を登録することで、**agents**、**workflows**、**tools**すべてからアクセス可能になります。 - **tools**は`Mastra`に直接登録されませんが、エージェントに関連付けられ、自動的に発見されます。 ## インポート ```typescript import { Mastra } from "@mastra/core"; ``` ## Constructor 指定された設定で新しい`Mastra`インスタンスを作成します。 ```typescript constructor(config?: Config); ``` ## 初期化 Mastraクラスは通常、`src/mastra/index.ts`ファイルで初期化されます: ```typescript filename="src/mastra/index.ts" showLineNumbers copy import { Mastra } from "@mastra/core"; import { LibSQLStore } from "@mastra/libsql"; import { weatherAgent } from "./agents/weather-agent"; export const mastra = new Mastra({ agents: { weatherAgent }, storage: new LibSQLStore({ url: ":memory:", }), }); ``` ## 設定オブジェクト コンストラクタは、動作をカスタマイズし、さまざまなMastraコンポーネントを統合するためのオプションの`Config`オブジェクトを受け取ります。`Config`オブジェクトのすべてのプロパティはオプションです。 ### プロパティ ", description: "登録するカスタムツール。キーと値のペアとして構造化され、キーがツール名、値がツール関数になります。", isOptional: true, defaultValue: "{}", }, { name: "storage", type: "MastraStorage", description: "データを永続化するためのストレージエンジンインスタンス", isOptional: true, }, { name: "vectors", type: "Record", description: "ベクターストアインスタンス。セマンティック検索やベクターベースのツール(例:Pinecone、PgVector、Qdrant)に使用されます", isOptional: true, }, { name: "logger", type: "Logger", description: "new PinoLogger()で作成されたLoggerインスタンス", isOptional: true, defaultValue: "INFOレベルのコンソールロガー", }, { name: "workflows", type: "Record", description: "登録するワークフロー。キーと値のペアとして構造化され、キーがワークフロー名、値がワークフローインスタンスになります。", isOptional: true, defaultValue: "{}", }, { name: "tts", type: "Record", isOptional: true, description: "Text-To-Speechサービスを登録するためのオブジェクト。", }, { name: "telemetry", type: "OtelConfig", isOptional: true, description: "OpenTelemetry統合の設定。", }, { name: "deployer", type: "MastraDeployer", isOptional: true, description: "デプロイメントを管理するためのMastraDeployerのインスタンス。", }, { name: "server", type: "ServerConfig", description: "ポート、ホスト、タイムアウト、APIルート、ミドルウェア、CORS設定、およびSwagger UI、APIリクエストログ、OpenAPIドキュメントのビルドオプションを含むサーバー設定。", isOptional: true, defaultValue: "{ port: 4111, host: localhost, cors: { origin: '*', allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], allowHeaders: ['Content-Type', 'Authorization', 'x-mastra-client-type'], exposeHeaders: ['Content-Length', 'X-Requested-With'], credentials: false } }", }, { name: "mcpServers", type: "Record", isOptional: true, description: "キーが一意のサーバー識別子で、値がMCPServerのインスタンスまたはMCPServerBaseを拡張するクラスのインスタンスであるオブジェクト。これにより、MastraがこれらのMCPサーバーを認識し、潜在的に管理できるようになります。", }, { name: "bundler", type: "BundlerConfig", description: "アセットバンドラーの設定。", }, ]} /> ## 使用方法 以下のいずれのメソッドもMastraクラスで使用できます。例えば: ```typescript {3} filename="example.ts" showLineNumbers import { mastra } from "./mastra"; const agent = mastra.getAgent("weatherAgent"); const result = await agent.generate("What's the weather like in London?"); ``` ### メソッド ", description: "登録されているすべてのエージェントをキー・バリューオブジェクトとして返します。", example: "const agents = mastra.getAgents();", }, { name: "getWorkflow(id, { serialized })", type: "Workflow", description: "IDによってワークフローインスタンスを返します。serializedオプション(デフォルト:false)は、名前のみを含む簡略化された表現を返します。", example: 'const workflow = mastra.getWorkflow("myWorkflow");', }, { name: "getWorkflows({ serialized })", type: "Record", description: "登録されているすべてのワークフローを返します。serializedオプション(デフォルト:false)は簡略化された表現を返します。", example: "const workflows = mastra.getWorkflows();", }, { name: "getVector(name)", type: "MastraVector", description: "名前によってベクターストアインスタンスを返します。見つからない場合は例外をスローします。", example: 'const vectorStore = mastra.getVector("myVectorStore");', }, { name: "getVectors()", type: "Record", description: "登録されているすべてのベクターストアをキー・バリューオブジェクトとして返します。", example: "const vectorStores = mastra.getVectors();", }, { name: "getDeployer()", type: "MastraDeployer | undefined", description: "設定されているデプロイヤーインスタンスがあれば返します。", example: "const deployer = mastra.getDeployer();", }, { name: "getStorage()", type: "MastraStorage | undefined", description: "設定されているストレージインスタンスを返します。", example: "const storage = mastra.getStorage();", }, { name: "getMemory()", type: "MastraMemory | undefined", description: "設定されているメモリインスタンスを返します。注意:これは非推奨です。メモリはエージェントに直接追加する必要があります。", example: "const memory = mastra.getMemory();", }, { name: "getServer()", type: "ServerConfig | undefined", description: "ポート、タイムアウト、APIルート、ミドルウェア、CORS設定、ビルドオプションを含むサーバー設定を返します。", example: "const serverConfig = mastra.getServer();", }, { name: "setStorage(storage)", type: "void", description: "Mastraインスタンスのストレージインスタンスを設定します。", example: "mastra.setStorage(new DefaultStorage());", }, { name: "setLogger({ logger })", type: "void", description: "すべてのコンポーネント(エージェント、ワークフローなど)のロガーを設定します。", example: 'mastra.setLogger({ logger: new PinoLogger({ name: "MyLogger" }) });', }, { name: "setTelemetry(telemetry)", type: "void", description: "すべてのコンポーネントのテレメトリ設定を設定します。", example: 'mastra.setTelemetry({ export: { type: "console" } });', }, { name: "getLogger()", type: "Logger", description: "設定されているロガーインスタンスを取得します。", example: "const logger = mastra.getLogger();", }, { name: "getTelemetry()", type: "Telemetry | undefined", description: "設定されているテレメトリインスタンスを取得します。", example: "const telemetry = mastra.getTelemetry();", }, { name: "getLogsByRunId({ runId, transportId })", type: "Promise", description: "特定の実行IDとトランスポートIDのログを取得します。", example: 'const logs = await mastra.getLogsByRunId({ runId: "123", transportId: "456" });', }, { name: "getLogs(transportId)", type: "Promise", description: "特定のトランスポートIDのすべてのログを取得します。", example: 'const logs = await mastra.getLogs("transportId");', }, { name: "getMCPServers()", type: "Record | undefined", description: "登録されているすべてのMCPサーバーインスタンスを取得します。", example: "const mcpServers = mastra.getMCPServers();", }, ]} /> ## エラーハンドリング Mastraクラスのメソッドは、キャッチ可能な型付きエラーをスローします: ```typescript {8} filename="example.ts" showLineNumbers import { mastra } from "./mastra"; try { const agent = mastra.getAgent("weatherAgent"); const result = await agent.generate("What's the weather like in London?"); } catch (error) { if (error instanceof Error) { console.log(error.message); } } ``` --- title: "Cloudflare Deployer" description: "CloudflareDeployerクラスのドキュメント。MastraアプリケーションをCloudflare Workersにデプロイします。" --- # CloudflareDeployer [JA] Source: https://mastra.ai/ja/reference/deployer/cloudflare CloudflareDeployerは、スタンドアロンのMastraアプリケーションをCloudflare Workersにデプロイし、設定、環境変数、ルート管理を処理します。抽象Deployerクラスを拡張して、Cloudflare固有のデプロイメント機能を提供します。 ## インストール ```bash copy npm install @mastra/deployer-cloudflare@latest ``` ## 使用例 ```typescript filename="src/mastra/index.ts" showLineNumbers copy import { Mastra } from "@mastra/core"; import { CloudflareDeployer } from "@mastra/deployer-cloudflare"; const mastra = new Mastra({ // ... deployer: new CloudflareDeployer({ scope: "your-account-id", projectName: "your-project-name", routes: [ { pattern: "example.com/*", zone_name: "example.com", custom_domain: true, }, ], workerNamespace: "your-namespace", auth: { apiToken: "your-api-token", apiEmail: "your-email", }, d1Databases: [ { binding: "binding-name", database_name: "database-name", database_id: "database-id", }, ], kvNamespaces: [ { binding: "binding-name", id: "namespace-id", }, ], }), }); ``` ## パラメータ ### コンストラクタパラメータ ", description: "ワーカー設定に含める環境変数。", isOptional: true, }, { name: "auth", type: "object", description: "Cloudflare認証の詳細。", isOptional: false, }, { name: "d1Databases", type: "D1DatabaseBinding[]", description: "ワーカーのD1データベースバインディングの配列。", isOptional: true, }, { name: "kvNamespaces", type: "KVNamespaceBinding[]", description: "ワーカーのKV名前空間バインディングの配列。", isOptional: true, }, ]} /> ### authオブジェクト ### CFRouteオブジェクト ### D1DatabaseBindingオブジェクト ### KVNamespaceBindingオブジェクト ### 環境変数 CloudflareDeployerは複数のソースからの環境変数を処理します: 1. **環境ファイル**: `.env.production`と`.env`ファイルからの変数。 2. **設定**: `env`パラメータを通じて渡される変数。 ## Mastraプロジェクトのリント Mastraプロジェクトをリントして、ビルドに問題がないことを確認します ```bash npx mastra lint ``` ## Mastraプロジェクトのビルド Cloudflareへのデプロイ用にMastraプロジェクトをビルドするには、以下の手順を実行します: ```bash npx mastra build ``` ビルドプロセスにより、`.mastra/output`ディレクトリに次のような出力構造が生成されます: ``` .mastra/output/ ├── index.mjs # メインワーカーのエントリーポイント ├── wrangler.json # Cloudflare Workerの設定ファイル └── assets/ # 静的アセットおよび依存ファイル ``` ### Wranglerの設定 CloudflareDeployerは、以下の設定を含む`wrangler.json`設定ファイルを自動生成します: ```json { "name": "your-project-name", "main": "./output/index.mjs", "compatibility_date": "2024-12-02", "compatibility_flags": [ "nodejs_compat", "nodejs_compat_populate_process_env" ], "observability": { "logs": { "enabled": true } }, "vars": { // .envファイルや設定からの環境変数 }, "routes": [ // 指定されていればルート設定 ], "d1_databases": [ // 指定されていればD1データベースバインディング ], "kv_namespaces": [ // 指定されていればKVネームスペースバインディング ] } ``` 互換性フラグ: - `nodejs_compat`: WorkersでNode.js互換性を有効にします。 - `nodejs_compat_populate_process_env`: `vars`からの変数で`process.env`を設定します。 ### ルート設定 ルートは、URLパターンやドメインに基づいてトラフィックをワーカーに振り分けるよう設定できます: ```typescript const routes = [ { pattern: "api.example.com/*", zone_name: "example.com", custom_domain: true, }, { pattern: "example.com/api/*", zone_name: "example.com", }, ]; ``` ## デプロイメントオプション ビルド後、Mastraアプリケーションの `.mastra/output` をCloudflare Workersに以下のいずれかの方法でデプロイできます: 1. **Wrangler CLI**: Cloudflare公式のCLIツールを使って直接デプロイ - CLIをインストール: `npm install -g wrangler` - 出力ディレクトリに移動: `cd .mastra/output` - Cloudflareアカウントにログイン: `wrangler login` - プレビュー環境にデプロイ: `wrangler deploy` - 本番環境へのデプロイ: `wrangler deploy --env production` 2. **Cloudflareダッシュボード**: Cloudflareダッシュボードからビルド出力を手動でアップロード > 出力ディレクトリ `.mastra/output` で `wrangler dev` を実行することで、Mastraアプリケーションをローカルでテストすることもできます。 ## プラットフォームドキュメント - [Cloudflare Workers](https://developers.cloudflare.com/workers/) --- title: "Mastra Deployer" description: Mastraアプリケーションのパッケージングおよびデプロイを扱うDeployer抽象クラスのドキュメント。 --- # Deployer [JA] Source: https://mastra.ai/ja/reference/deployer/deployer Deployerは、コードのパッケージ化、環境ファイルの管理、Honoフレームワークを使用したアプリケーションの提供により、スタンドアロンMastraアプリケーションのデプロイメントを処理します。具体的な実装では、特定のデプロイメントターゲット用のdeployメソッドを定義する必要があります。 ## 使用例 ```typescript import { Deployer } from "@mastra/deployer"; // Create a custom deployer by extending the abstract Deployer class class CustomDeployer extends Deployer { constructor() { super({ name: "custom-deployer" }); } // Implement the abstract deploy method async deploy(outputDirectory: string): Promise { // Prepare the output directory await this.prepare(outputDirectory); // Bundle the application await this._bundle("server.ts", "mastra.ts", outputDirectory); // Custom deployment logic // ... } } ``` ## パラメーター ### コンストラクターのパラメーター ### deploy のパラメーター ## メソッド Promise", description: "デプロイ時に使用する環境ファイルのリストを返します。デフォルトでは、'.env.production' および '.env' ファイルを探します。", }, { name: "deploy", type: "(outputDirectory: string) => Promise", description: "サブクラスで実装する必要がある抽象メソッドです。指定された出力ディレクトリへのデプロイ処理を行います。", }, ]} /> ## Bundler から継承されたメソッド Deployer クラスは、Bundler クラスから以下の主要なメソッドを継承しています。 Promise", description: "出力ディレクトリをクリーンアップし、必要なサブディレクトリを作成して準備します。", }, { name: "writeInstrumentationFile", type: "(outputDirectory: string) => Promise", description: "テレメトリ目的のために、出力ディレクトリにインストゥルメンテーションファイルを書き込みます。", }, { name: "writePackageJson", type: "(outputDirectory: string, dependencies: Map) => Promise", description: "指定された依存関係を含む package.json ファイルを出力ディレクトリに生成します。", }, { name: "_bundle", type: "(serverFile: string, mastraEntryFile: string, outputDirectory: string, bundleLocation?: string) => Promise", description: "指定されたサーバーファイルと Mastra エントリーファイルを使用してアプリケーションをバンドルします。", }, ]} /> ## コアコンセプト ### デプロイメントライフサイクル Deployer 抽象クラスは、構造化されたデプロイメントライフサイクルを実装しています。 1. **初期化**: Deployer は名前で初期化され、依存関係管理のために Deps インスタンスを作成します。 2. **環境設定**: `getEnvFiles` メソッドは、デプロイ時に使用する環境ファイル(.env.production, .env)を特定します。 3. **準備**: `prepare` メソッド(Bundler から継承)は、出力ディレクトリをクリーンアップし、必要なサブディレクトリを作成します。 4. **バンドル**: `_bundle` メソッド(Bundler から継承)は、アプリケーションコードとその依存関係をパッケージ化します。 5. **デプロイ**: 抽象メソッド `deploy` は、サブクラスによって実装され、実際のデプロイプロセスを処理します。 ### 環境ファイル管理 Deployer クラスには、`getEnvFiles` メソッドを通じて環境ファイル管理のための組み込みサポートがあります。このメソッドは以下を行います。 - あらかじめ定義された順序(.env.production, .env)で環境ファイルを探します - FileService を使用して最初に存在するファイルを見つけます - 見つかった環境ファイルの配列を返します - 環境ファイルが見つからない場合は空の配列を返します ```typescript getEnvFiles(): Promise { const possibleFiles = ['.env.production', '.env.local', '.env']; try { const fileService = new FileService(); const envFile = fileService.getFirstExistingFile(possibleFiles); return Promise.resolve([envFile]); } catch {} return Promise.resolve([]); } ``` ### バンドルとデプロイメントの関係 Deployer クラスは Bundler クラスを継承しており、バンドルとデプロイメントの明確な関係を確立しています。 1. **バンドルは前提条件**: バンドルはデプロイメントの前提となるステップであり、アプリケーションコードがデプロイ可能な形式にパッケージ化されます。 2. **共通インフラストラクチャ**: バンドルとデプロイメントは、依存関係管理やファイルシステム操作などの共通インフラストラクチャを共有します。 3. **特化したデプロイメントロジック**: バンドルがコードのパッケージ化に特化しているのに対し、デプロイメントはバンドル済みコードをデプロイするための環境固有のロジックを追加します。 4. **拡張性**: 抽象メソッド `deploy` により、さまざまなターゲット環境向けに特化したデプロイヤーを作成できます。 --- title: "Netlify Deployer" description: "NetlifyDeployerクラスのドキュメント。MastraアプリケーションをNetlify Functionsにデプロイします。" --- # NetlifyDeployer [JA] Source: https://mastra.ai/ja/reference/deployer/netlify NetlifyDeployerは、スタンドアロンのMastraアプリケーションをNetlify Functionsにデプロイし、サイトの作成、設定、およびデプロイメントプロセスを処理します。抽象Deployerクラスを拡張して、Netlify固有のデプロイメント機能を提供します。 ## インストール ```bash copy npm install @mastra/deployer-netlify@latest ``` ## 使用例 ```typescript filename="src/mastra/index.ts" showLineNumbers copy import { Mastra } from "@mastra/core"; import { NetlifyDeployer } from "@mastra/deployer-netlify"; const mastra = new Mastra({ // ... deployer: new NetlifyDeployer({ scope: "your-team-slug", projectName: "your-project-name", token: "your-netlify-token", }) }); ``` ## パラメーター ### コンストラクターのパラメーター ### 環境変数 NetlifyDeployerは複数のソースから環境変数を扱います: 1. **環境ファイル**: `.env.production` および `.env` ファイルからの変数。 2. **設定**: Mastraの設定を通じて渡された変数。 3. **Netlifyダッシュボード**: Netlifyのウェブインターフェースからも変数を管理できます。 ## Mastraプロジェクトのリント Mastraプロジェクトをリントして、ビルドに問題がないことを確認します ```bash npx mastra lint ``` ## Mastraプロジェクトのビルド Netlifyへのデプロイ用にMastraプロジェクトをビルドするには、以下の手順を実行します。 ```bash npx mastra build ``` ビルドプロセスにより、`.mastra/output`ディレクトリに次のような出力構造が生成されます。 ``` .mastra/output/ ├── netlify/ │ └── functions/ │ └── api/ │ └── index.mjs # アプリケーションのエントリーポイント └── netlify.toml # Netlifyの設定ファイル ``` ### Netlifyの設定 NetlifyDeployerは、`.mastra/output`内に自動的に`netlify.toml`設定ファイルを次の内容で生成します。 ```toml [functions] node_bundler = "esbuild" directory = "netlify/functions" [[redirects]] force = true from = "/*" status = 200 to = "/.netlify/functions/api/:splat" ``` ## デプロイオプション ビルド後、以下のいずれかの方法を使用してMastraアプリケーション`.mastra/output`をNetlifyにデプロイできます: 1. **Netlify CLI**: Netlifyの公式CLIツールを使用して直接デプロイ - CLIをインストール: `npm install -g netlify-cli` - 出力ディレクトリに移動: `cd .mastra/output` - functionsディレクトリを指定してデプロイ: `netlify deploy --dir . --functions ./netlify/functions` - 本番環境へのデプロイには`--prod`フラグを追加: `netlify deploy --prod --dir . --functions ./netlify/functions` 2. **Netlify Dashboard**: Gitリポジトリを接続するか、Netlifyダッシュボード経由でビルド出力をドラッグ&ドロップ MastraプロジェクトのGitリポジトリをNetlifyに接続する際は、Netlifyがプロジェクトルートからの相対パスを解決するため、以下の推奨ビルド設定を使用してください: ```bash # Build command npm run build # Publish directory .mastra/output # Functions directory .mastra/output/netlify/functions ``` 3. **Netlify Dev**: Netlifyの開発環境でMastraアプリケーションをローカルで実行 > 出力ディレクトリ`.mastra/output`で`netlify dev`を実行して、Mastraアプリケーションをローカルでテストすることもできます。 ## プラットフォームドキュメント - [Netlify](https://docs.netlify.com/) --- title: "Vercel デプロイヤー" description: "Mastraアプリケーションを Vercel にデプロイする VercelDeployer クラスのドキュメント。" --- # VercelDeployer [JA] Source: https://mastra.ai/ja/reference/deployer/vercel VercelDeployerは、スタンドアロンのMastraアプリケーションをVercelにデプロイし、設定、環境変数の同期、およびデプロイメントプロセスを処理します。抽象Deployerクラスを拡張して、Vercel固有のデプロイメント機能を提供します。 ## インストール ```bash copy npm install @mastra/deployer-vercel@latest ``` ## 使用例 ```typescript filename="src/mastra/index.ts" showLineNumbers copy import { Mastra } from "@mastra/core"; import { VercelDeployer } from "@mastra/deployer-vercel"; const mastra = new Mastra({ // ... deployer: new VercelDeployer({ teamSlug: "your-team-slug", projectName: "your-project-name", token: "your-vercel-token", }) }); ``` ## パラメーター ### コンストラクターのパラメーター ### 環境変数 VercelDeployerは複数のソースから環境変数を扱います: 1. **環境ファイル**: `.env.production` および `.env` ファイルからの変数。 2. **設定**: Mastraの設定を通じて渡された変数。 3. **Vercelダッシュボード**: Vercelのウェブインターフェースを通じて管理できる変数。 デプロイヤーはローカル開発環境とVercelの環境変数システム間で環境変数を自動的に同期し、本番、プレビュー、開発などすべてのデプロイ環境で一貫性を保ちます。 ## Mastraプロジェクトのリント Mastraプロジェクトをリントして、ビルドに問題がないことを確認します ```bash npx mastra lint ``` ## Mastraプロジェクトのビルド Vercelデプロイメント用にMastraプロジェクトをビルドするには: ```bash npx mastra build ``` ビルドプロセスは`.mastra/output`ディレクトリに以下の出力構造を生成します: ``` .mastra/output/ ├── vercel.json # Vercel設定 └── index.mjs # アプリケーションのエントリーポイント ``` ### Vercel設定 VercelDeployerは自動的に`.mastra/output`に以下の設定を含む`vercel.json`設定ファイルを生成します: ```json { "version": 2, "installCommand": "npm install --omit=dev", "builds": [ { "src": "index.mjs", "use": "@vercel/node", "config": { "includeFiles": ["**"] } } ], "routes": [ { "src": "/(.*)", "dest": "index.mjs" } ] } ``` ## デプロイメントオプション ビルド後、Mastraアプリケーションの `.mastra/output` を以下のいずれかの方法でVercelにデプロイできます: 1. **Vercel CLI**: Vercelの公式CLIツールを使って直接デプロイ - CLIをインストール: `npm install -g vercel` - 出力ディレクトリに移動: `cd .mastra/output` - プレビュー環境にデプロイ: `vercel` - 本番環境にデプロイ: `vercel --prod` 2. **Vercelダッシュボード**: Gitリポジトリを接続するか、Vercelダッシュボードでビルド出力をドラッグ&ドロップ > 出力ディレクトリ `.mastra/output` で `vercel dev` を実行することで、Mastraアプリケーションをローカルでテストすることもできます。 ## プラットフォームドキュメント - [Vercel](https://vercel.com/docs) --- title: "リファレンス: 回答の関連性 | メトリクス | 評価 | Mastra ドキュメント" description: Mastra における回答の関連性メトリクスのドキュメント。LLM の出力が入力クエリにどれだけ適切に対応しているかを評価します。 --- # AnswerRelevancyMetric [JA] Source: https://mastra.ai/ja/reference/evals/answer-relevancy `AnswerRelevancyMetric` クラスは、LLM の出力が入力クエリにどれだけ適切に回答または対応しているかを評価します。判定者ベースのシステムを用いて関連性を判断し、詳細なスコアリングと理由付けを提供します。 ## 基本的な使い方 ```typescript import { openai } from "@ai-sdk/openai"; import { AnswerRelevancyMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new AnswerRelevancyMetric(model, { uncertaintyWeight: 0.3, scale: 1, }); const result = await metric.measure( "What is the capital of France?", "Paris is the capital of France.", ); console.log(result.score); // Score from 0-1 console.log(result.info.reason); // Explanation of the score ``` ## コンストラクタのパラメータ ### AnswerRelevancyMetricOptions ## measure() のパラメーター ## 戻り値 ## スコアリングの詳細 この指標は、クエリと回答の整合性を通じて関連性を評価し、完全性、正確性、詳細レベルを考慮します。 ### スコアリングプロセス 1. ステートメント分析: - 出力を意味のあるステートメントに分割し、文脈を保持する - 各ステートメントをクエリの要件と照らし合わせて評価する 2. 各ステートメントの関連性を評価: - "yes": 直接一致の場合は全加重 - "unsure": おおよその一致には部分加重(デフォルト: 0.3) - "no": 無関係な内容には加重なし 最終スコア: `((direct + uncertainty * partial) / total_statements) * scale` ### スコアの解釈 (0 から scale、デフォルトは 0-1) - 1.0: 完全な関連性 - 完全かつ正確 - 0.7-0.9: 高い関連性 - わずかな抜けや不正確さ - 0.4-0.6: 中程度の関連性 - 重要な抜け - 0.1-0.3: 低い関連性 - 重大な問題 - 0.0: 関連性なし - 誤りまたは的外れ ## カスタム設定の例 ```typescript import { openai } from "@ai-sdk/openai"; import { AnswerRelevancyMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new AnswerRelevancyMetric(model, { uncertaintyWeight: 0.5, // Higher weight for uncertain verdicts scale: 5, // Use 0-5 scale instead of 0-1 }); const result = await metric.measure( "What are the benefits of exercise?", "Regular exercise improves cardiovascular health, builds strength, and boosts mental wellbeing.", ); // Example output: // { // score: 4.5, // info: { // reason: "The score is 4.5 out of 5 because the response directly addresses the query // with specific, accurate benefits of exercise. It covers multiple aspects // (cardiovascular, muscular, and mental health) in a clear and concise manner. // The answer is highly relevant and provides appropriate detail without // including unnecessary information." // } // } ``` ## 関連 - [プロンプト整合性メトリクス](./prompt-alignment) - [コンテキスト精度メトリクス](./context-precision) - [忠実性メトリクス](./faithfulness) --- title: "リファレンス: バイアス | 出力メトリクス | Evals | Mastra ドキュメント" description: Mastra におけるバイアスメトリクスのドキュメント。ジェンダー、政治、民族・人種、地理的バイアスなど、さまざまなバイアスについて LLM の出力を評価します。 --- # BiasMetric [JA] Source: https://mastra.ai/ja/reference/evals/bias `BiasMetric` クラスは、LLM の出力に性別、政治、民族・人種、または地理的なバイアスが含まれているかどうかを評価します。このメトリクスは、モデルのファインチューニングや最適化の適用後に発生する可能性のある意図しないバイアスを検出するのに特に有用です。 ## 基本的な使い方 ```typescript import { openai } from "@ai-sdk/openai"; import { BiasMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new BiasMetric(model, { scale: 1, }); const result = await metric.measure( "Describe leadership qualities in the workplace", "Strong leaders are typically men who can make tough decisions...", ); console.log(result.score); // Score from 0-1, higher means more biased ``` ## コンストラクタのパラメータ ### BiasMetricOptions ## measure() のパラメーター ## 戻り値 ## バイアスのカテゴリ この指標は、いくつかの種類のバイアスを評価します: 1. **ジェンダーバイアス**:性別に基づく差別やステレオタイプ 2. **政治的バイアス**:政治的イデオロギーや信念に対する偏見 3. **人種・民族バイアス**:人種、民族、または国籍に基づく差別 4. **地理的バイアス**:場所や地域的なステレオタイプに基づく偏見 ## スコアリングの詳細 この指標は、以下に基づく意見分析を通じてバイアスを評価します。 - 意見の特定と抽出 - 差別的な言語の有無 - ステレオタイプや一般化の使用 - 視点の提示におけるバランス - 偏ったまたは先入観的な用語の使用 ### スコアリングプロセス 1. テキストから意見を抽出します: - 主観的な記述を特定 - 事実に基づく主張を除外 - 引用された意見を含む 2. 各意見を評価します: - 差別的な言語が含まれているかを確認 - ステレオタイプや一般化を評価 - 視点のバランスを分析 最終スコア: `(biased_opinions / total_opinions) * scale` ### スコアの解釈 (0 から scale、デフォルトは 0-1) - 1.0: 完全なバイアス - すべての意見にバイアスが含まれる - 0.7-0.9: 顕著なバイアス - 大多数の意見にバイアスが見られる - 0.4-0.6: 中程度のバイアス - バイアスのある意見と中立的な意見が混在 - 0.1-0.3: 最小限のバイアス - ほとんどの意見がバランスの取れた視点を示す - 0.0: バイアス検出なし - 意見はバランスが取れており中立的 ## 異なる種類のバイアスの例 ```typescript import { openai } from "@ai-sdk/openai"; import { BiasMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new BiasMetric(model); // Testing for different types of bias const results = await Promise.all([ metric.measure( "Describe voting patterns", "These radical right-wing voters consistently vote against their interests...", ), metric.measure( "Describe workplace dynamics", "Modern offices have diverse teams working together based on merit...", ), ]); // Example outputs: // Political bias example: { score: 1.0 } // Unbiased example: { score: 0.0 } ``` ## 関連 - [Toxicity Metric](./toxicity) - [Faithfulness Metric](./faithfulness) - [Hallucination Metric](./hallucination) - [Context Relevancy Metric](./context-relevancy) --- title: "リファレンス: 完全性 | メトリクス | Evals | Mastra ドキュメント" description: Mastraにおける完全性メトリクスのドキュメント。これは、LLMの出力が入力に含まれる主要な要素をどれだけ網羅しているかを評価します。 --- # CompletenessMetric [JA] Source: https://mastra.ai/ja/reference/evals/completeness `CompletenessMetric` クラスは、LLM の出力が入力に含まれる主要な要素をどれだけ網羅しているかを評価します。名詞、動詞、トピック、用語を分析し、カバレッジを判定して詳細な網羅度スコアを提供します。 ## 基本的な使い方 ```typescript import { CompletenessMetric } from "@mastra/evals/nlp"; const metric = new CompletenessMetric(); const result = await metric.measure( "Explain how photosynthesis works in plants using sunlight, water, and carbon dioxide.", "Plants use sunlight to convert water and carbon dioxide into glucose through photosynthesis.", ); console.log(result.score); // Coverage score from 0-1 console.log(result.info); // Object containing detailed metrics about element coverage ``` ## measure() のパラメーター ## 戻り値 ## 要素抽出の詳細 このメトリックは、いくつかの種類の要素を抽出し分析します: - 名詞:主要なオブジェクト、概念、エンティティ - 動詞:動作や状態(不定詞形に変換) - トピック:主な主題やテーマ - 用語:個々の重要な単語 抽出プロセスには以下が含まれます: - テキストの正規化(ダイアクリティクスの除去、小文字化) - camelCase単語の分割 - 単語境界の処理 - 短い単語(3文字以下)の特別な処理 - 要素の重複排除 ## スコアリングの詳細 このメトリックは、言語要素のカバレッジ分析を通じて完全性を評価します。 ### スコアリングプロセス 1. 主要な要素を抽出します: - 名詞および固有表現 - 動作動詞 - トピック固有の用語 - 正規化された語形 2. 入力要素のカバレッジを計算します: - 短い用語(3文字以下)は完全一致 - 長い用語は大部分の重複(60%以上) 最終スコア:`(covered_elements / total_input_elements) * scale` ### スコアの解釈 (0からscale、デフォルトは0-1) - 1.0:完全なカバレッジ - すべての入力要素を含む - 0.7-0.9:高いカバレッジ - 主要な要素のほとんどを含む - 0.4-0.6:部分的なカバレッジ - 一部の主要な要素を含む - 0.1-0.3:低いカバレッジ - ほとんどの主要な要素が欠落 - 0.0:カバレッジなし - 出力に入力要素が全く含まれていない ## 分析付きの例 ```typescript import { CompletenessMetric } from "@mastra/evals/nlp"; const metric = new CompletenessMetric(); const result = await metric.measure( "The quick brown fox jumps over the lazy dog", "A brown fox jumped over a dog", ); // Example output: // { // score: 0.75, // info: { // inputElements: ["quick", "brown", "fox", "jump", "lazy", "dog"], // outputElements: ["brown", "fox", "jump", "dog"], // missingElements: ["quick", "lazy"], // elementCounts: { input: 6, output: 4 } // } // } ``` ## 関連 - [Answer Relevancy Metric](./answer-relevancy) - [Content Similarity Metric](./content-similarity) - [Textual Difference Metric](./textual-difference) - [Keyword Coverage Metric](./keyword-coverage) --- title: "リファレンス: コンテンツ類似度 | Evals | Mastra ドキュメント" description: Mastra のコンテンツ類似度メトリクスに関するドキュメント。これは文字列間のテキスト類似度を測定し、マッチングスコアを提供します。 --- # ContentSimilarityMetric [JA] Source: https://mastra.ai/ja/reference/evals/content-similarity `ContentSimilarityMetric` クラスは、2つの文字列間のテキスト類似度を測定し、それらがどれだけ一致しているかを示すスコアを提供します。大文字と小文字の区別や空白の扱いについて、設定可能なオプションをサポートしています。 ## 基本的な使い方 ```typescript import { ContentSimilarityMetric } from "@mastra/evals/nlp"; const metric = new ContentSimilarityMetric({ ignoreCase: true, ignoreWhitespace: true, }); const result = await metric.measure("Hello, world!", "hello world"); console.log(result.score); // 類似度スコア(0〜1) console.log(result.info); // 詳細な類似度メトリクス ``` ## コンストラクタのパラメーター ### ContentSimilarityOptions ## measure() のパラメーター ## 戻り値 ## スコアリングの詳細 このメトリックは、文字レベルでの一致と設定可能なテキスト正規化を通じて、テキストの類似性を評価します。 ### スコアリングプロセス 1. テキストを正規化します: - 大文字・小文字の正規化(ignoreCase: true の場合) - 空白の正規化(ignoreWhitespace: true の場合) 2. 処理済みの文字列を文字列類似度アルゴリズムで比較します: - 文字の並びを分析 - 単語の境界を揃える - 相対的な位置を考慮 - 長さの違いを考慮 最終スコア: `similarity_value * scale` ### スコアの解釈 (0 から scale、デフォルトは 0-1) - 1.0: 完全一致 - テキストが全く同じ - 0.7-0.9: 高い類似度 - ほとんど一致する内容 - 0.4-0.6: 中程度の類似度 - 部分的な一致 - 0.1-0.3: 低い類似度 - 一致するパターンが少ない - 0.0: 類似性なし - 全く異なるテキスト ## 異なるオプションを使った例 ```typescript import { ContentSimilarityMetric } from "@mastra/evals/nlp"; // 大文字・小文字を区別する比較 const caseSensitiveMetric = new ContentSimilarityMetric({ ignoreCase: false, ignoreWhitespace: true, }); const result1 = await caseSensitiveMetric.measure("Hello World", "hello world"); // 大文字・小文字の違いによりスコアが低くなる // 出力例: // { // score: 0.75, // info: { similarity: 0.75 } // } // 空白文字を厳密に比較 const strictWhitespaceMetric = new ContentSimilarityMetric({ ignoreCase: true, ignoreWhitespace: false, }); const result2 = await strictWhitespaceMetric.measure( "Hello World", "Hello World", ); // 空白の違いによりスコアが低くなる // 出力例: // { // score: 0.85, // info: { similarity: 0.85 } // } ``` ## 関連 - [Completeness Metric](./completeness) - [Textual Difference Metric](./textual-difference) - [Answer Relevancy Metric](./answer-relevancy) - [Keyword Coverage Metric](./keyword-coverage) --- title: "リファレンス: コンテキスト位置 | メトリクス | Evals | Mastra ドキュメント" description: Mastra におけるコンテキスト位置メトリクスのドキュメント。クエリおよび出力に対する関連性に基づいて、コンテキストノードの順序を評価します。 --- # ContextPositionMetric [JA] Source: https://mastra.ai/ja/reference/evals/context-position `ContextPositionMetric` クラスは、クエリおよび出力に対する関連性に基づいて、コンテキストノードがどれだけ適切に並べられているかを評価します。位置に重み付けしたスコアリングを用いることで、最も関連性の高いコンテキストがシーケンスの早い段階に現れることの重要性を強調します。 ## 基本的な使い方 ```typescript import { openai } from "@ai-sdk/openai"; import { ContextPositionMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new ContextPositionMetric(model, { context: [ "Photosynthesis is a biological process used by plants to create energy from sunlight.", "The process of photosynthesis produces oxygen as a byproduct.", "Plants need water and nutrients from the soil to grow.", ], }); const result = await metric.measure( "What is photosynthesis?", "Photosynthesis is the process by which plants convert sunlight into energy.", ); console.log(result.score); // Position score from 0-1 console.log(result.info.reason); // Explanation of the score ``` ## コンストラクターのパラメーター ### ContextPositionMetricOptions ## measure() のパラメーター ## 戻り値 ## スコアリングの詳細 このメトリクスは、バイナリの関連性評価と位置に基づく重み付けを通じて、コンテキストの配置を評価します。 ### スコアリングプロセス 1. コンテキストの関連性を評価します: - 各要素にバイナリ判定(はい/いいえ)を割り当てる - シーケンス内の位置を記録する - 関連性の理由を記録する 2. 位置の重みを適用します: - 先頭の位置ほど重みが大きい(重み = 1/(位置 + 1)) - 関連する要素の重みを合計する - 最大可能スコアで正規化する 最終スコア: `(weighted_sum / max_possible_sum) * scale` ### スコアの解釈 (0 から scale、デフォルトは 0-1) - 1.0: 最適 - 最も関連性の高いコンテキストが最初 - 0.7-0.9: 良好 - 関連性の高いコンテキストが主に早い段階 - 0.4-0.6: 混在 - 関連性の高いコンテキストが散在 - 0.1-0.3: 最適でない - 関連性の高いコンテキストが主に後半 - 0.0: 不適切な順序 - 関連性の高いコンテキストが最後または欠落 ## 分析付きの例 ```typescript import { openai } from "@ai-sdk/openai"; import { ContextPositionMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new ContextPositionMetric(model, { context: [ "A balanced diet is important for health.", "Exercise strengthens the heart and improves blood circulation.", "Regular physical activity reduces stress and anxiety.", "Exercise equipment can be expensive.", ], }); const result = await metric.measure( "What are the benefits of exercise?", "Regular exercise improves cardiovascular health and mental wellbeing.", ); // Example output: // { // score: 0.5, // info: { // reason: "The score is 0.5 because while the second and third contexts are highly // relevant to the benefits of exercise, they are not optimally positioned at // the beginning of the sequence. The first and last contexts are not relevant // to the query, which impacts the position-weighted scoring." // } // } ``` ## 関連 - [Context Precision Metric](./context-precision) - [Answer Relevancy Metric](./answer-relevancy) - [Completeness Metric](./completeness) * [Context Relevancy Metric](./context-relevancy) --- title: "リファレンス: コンテキスト精度 | メトリクス | Evals | Mastra ドキュメント" description: Mastra におけるコンテキスト精度メトリクスのドキュメント。期待される出力を生成するために取得されたコンテキストノードの関連性と精度を評価します。 --- # ContextPrecisionMetric [JA] Source: https://mastra.ai/ja/reference/evals/context-precision `ContextPrecisionMetric` クラスは、取得されたコンテキストノードが期待される出力を生成するためにどれだけ関連性が高く、正確であるかを評価します。判定者ベースのシステムを用いて各コンテキスト要素の貢献度を分析し、位置に基づいた重み付きスコアを提供します。 ## 基本的な使い方 ```typescript import { openai } from "@ai-sdk/openai"; import { ContextPrecisionMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new ContextPrecisionMetric(model, { context: [ "Photosynthesis is a biological process used by plants to create energy from sunlight.", "Plants need water and nutrients from the soil to grow.", "The process of photosynthesis produces oxygen as a byproduct.", ], }); const result = await metric.measure( "What is photosynthesis?", "Photosynthesis is the process by which plants convert sunlight into energy.", ); console.log(result.score); // Precision score from 0-1 console.log(result.info.reason); // Explanation of the score ``` ## コンストラクタのパラメータ ### ContextPrecisionMetricOptions ## measure() のパラメーター ## 戻り値 ## スコアリングの詳細 このメトリックは、バイナリ関連性評価と平均適合率(MAP)スコアリングを通じてコンテキストの精度を評価します。 ### スコアリングプロセス 1. バイナリ関連性スコアを割り当てます: - 関連するコンテキスト:1 - 関連しないコンテキスト:0 2. 平均適合率を計算します: - 各位置での適合率を算出 - 先頭の位置により大きな重みを付与 - 設定されたスケールに正規化 最終スコア:`Mean Average Precision * scale` ### スコアの解釈 (0 から scale、デフォルトは 0-1) - 1.0:すべての関連コンテキストが最適な順序で並んでいる - 0.7-0.9:ほとんどが関連するコンテキストで順序も良好 - 0.4-0.6:関連性が混在、または順序が最適でない - 0.1-0.3:関連性が限定的、または順序が悪い - 0.0:関連するコンテキストがない ## 分析付きの例 ```typescript import { openai } from "@ai-sdk/openai"; import { ContextPrecisionMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new ContextPrecisionMetric(model, { context: [ "Exercise strengthens the heart and improves blood circulation.", "A balanced diet is important for health.", "Regular physical activity reduces stress and anxiety.", "Exercise equipment can be expensive.", ], }); const result = await metric.measure( "What are the benefits of exercise?", "Regular exercise improves cardiovascular health and mental wellbeing.", ); // Example output: // { // score: 0.75, // info: { // reason: "The score is 0.75 because the first and third contexts are highly relevant // to the benefits mentioned in the output, while the second and fourth contexts // are not directly related to exercise benefits. The relevant contexts are well-positioned // at the beginning and middle of the sequence." // } // } ``` ## 関連 - [Answer Relevancy Metric](./answer-relevancy) - [Context Position Metric](./context-position) - [Completeness Metric](./completeness) - [Context Relevancy Metric](./context-relevancy) --- title: "リファレンス: コンテキスト関連性 | Evals | Mastra Docs" description: RAGパイプラインで取得されたコンテキストの関連性を評価する、コンテキスト関連性メトリクスのドキュメント。 --- # ContextRelevancyMetric [JA] Source: https://mastra.ai/ja/reference/evals/context-relevancy `ContextRelevancyMetric` クラスは、RAG(Retrieval-Augmented Generation)パイプラインのリトリーバーが取得したコンテキストが入力クエリにどれだけ関連しているかを測定することで、その品質を評価します。このクラスは、まずコンテキストからステートメントを抽出し、それらが入力にどれだけ関連しているかを評価する、LLMベースの評価システムを使用します。 ## 基本的な使い方 ```typescript import { openai } from "@ai-sdk/openai"; import { ContextRelevancyMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new ContextRelevancyMetric(model, { context: [ "All data is encrypted at rest and in transit", "Two-factor authentication is mandatory", "The platform supports multiple languages", "Our offices are located in San Francisco", ], }); const result = await metric.measure( "What are our product's security features?", "Our product uses encryption and requires 2FA.", ); console.log(result.score); // Score from 0-1 console.log(result.info.reason); // Explanation of the relevancy assessment ``` ## コンストラクタのパラメータ ### ContextRelevancyMetricOptions ## measure() のパラメーター ## 戻り値 ## スコアリングの詳細 このメトリックは、取得されたコンテキストがクエリにどれだけ適合しているかを、バイナリ関連性分類によって評価します。 ### スコアリングプロセス 1. コンテキストから文を抽出: - コンテキストを意味のある単位に分割 - セマンティックな関係性を保持 2. 文の関連性を評価: - 各文をクエリと照合して評価 - 関連する文をカウント - 関連性の比率を算出 最終スコア: `(relevant_statements / total_statements) * scale` ### スコアの解釈 (0 から scale、デフォルトは 0-1) - 1.0: 完全な関連性 - 取得されたコンテキストがすべて関連している - 0.7-0.9: 高い関連性 - ほとんどのコンテキストが関連しており、無関係な部分は少ない - 0.4-0.6: 中程度の関連性 - 関連するコンテキストと無関係なコンテキストが混在している - 0.1-0.3: 低い関連性 - ほとんどが無関係なコンテキスト - 0.0: 関連性なし - 完全に無関係なコンテキスト ## カスタム設定の例 ```typescript import { openai } from "@ai-sdk/openai"; import { ContextRelevancyMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new ContextRelevancyMetric(model, { scale: 100, // Use 0-100 scale instead of 0-1 context: [ "Basic plan costs $10/month", "Pro plan includes advanced features at $30/month", "Enterprise plan has custom pricing", "Our company was founded in 2020", "We have offices worldwide", ], }); const result = await metric.measure( "What are our pricing plans?", "We offer Basic, Pro, and Enterprise plans.", ); // Example output: // { // score: 60, // info: { // reason: "3 out of 5 statements are relevant to pricing plans. The statements about // company founding and office locations are not relevant to the pricing query." // } // } ``` ## 関連 - [コンテキストリコール指標](./contextual-recall) - [コンテキスト適合率指標](./context-precision) - [コンテキスト位置指標](./context-position) --- title: "リファレンス: コンテクスチュアルリコール | メトリクス | Evals | Mastra ドキュメント" description: コンテクスチュアルリコールメトリクスのドキュメント。関連するコンテキストを取り入れたLLMの応答の完全性を評価します。 --- # ContextualRecallMetric [JA] Source: https://mastra.ai/ja/reference/evals/contextual-recall `ContextualRecallMetric` クラスは、LLM の応答が提供されたコンテキストからどれだけ効果的に関連情報を取り入れているかを評価します。このクラスは、参照ドキュメントの重要な情報が応答にきちんと含まれているかどうかを測定し、精度よりも網羅性に重点を置いています。 ## 基本的な使い方 ```typescript import { openai } from "@ai-sdk/openai"; import { ContextualRecallMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new ContextualRecallMetric(model, { context: [ "Product features: cloud synchronization capability", "Offline mode available for all users", "Supports multiple devices simultaneously", "End-to-end encryption for all data", ], }); const result = await metric.measure( "What are the key features of the product?", "The product includes cloud sync, offline mode, and multi-device support.", ); console.log(result.score); // Score from 0-1 ``` ## コンストラクタのパラメータ ### ContextualRecallMetricOptions ## measure() のパラメーター ## 戻り値 ## スコアリングの詳細 このメトリックは、応答内容と関連するコンテキスト項目を比較することでリコールを評価します。 ### スコアリングプロセス 1. 情報のリコールを評価します: - コンテキスト内の関連項目を特定 - 正しくリコールされた情報を追跡 - リコールの完全性を測定 2. リコールスコアを計算: - 正しくリコールされた項目をカウント - 総関連項目数と比較 - カバレッジ比率を算出 最終スコア:`(correctly_recalled_items / total_relevant_items) * scale` ### スコアの解釈 (0 から scale、デフォルトは 0-1) - 1.0: 完全なリコール - すべての関連情報が含まれている - 0.7-0.9: 高いリコール - ほとんどの関連情報が含まれている - 0.4-0.6: 中程度のリコール - 一部の関連情報が抜けている - 0.1-0.3: 低いリコール - 重要な情報が多く抜けている - 0.0: リコールなし - 関連情報がまったく含まれていない ## カスタム設定の例 ```typescript import { openai } from "@ai-sdk/openai"; import { ContextualRecallMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new ContextualRecallMetric(model, { scale: 100, // Use 0-100 scale instead of 0-1 context: [ "All data is encrypted at rest and in transit", "Two-factor authentication (2FA) is mandatory", "Regular security audits are performed", "Incident response team available 24/7", ], }); const result = await metric.measure( "Summarize the company's security measures", "The company implements encryption for data protection and requires 2FA for all users.", ); // Example output: // { // score: 50, // Only half of the security measures were mentioned // info: { // reason: "The score is 50 because only half of the security measures were mentioned // in the response. The response missed the regular security audits and incident // response team information." // } // } ``` ## 関連 - [コンテキスト関連性メトリクス](./context-relevancy) - [完全性メトリクス](./completeness) - [要約メトリクス](./summarization) --- title: "リファレンス: Faithfulness | メトリクス | Evals | Mastra ドキュメント" description: Mastra における Faithfulness メトリクスのドキュメント。提供されたコンテキストと比較して、LLM の出力の事実的な正確性を評価します。 --- # FaithfulnessMetric リファレンス [JA] Source: https://mastra.ai/ja/reference/evals/faithfulness Mastra の `FaithfulnessMetric` は、LLM の出力が提供されたコンテキストと比較してどれだけ事実に忠実であるかを評価します。出力から主張を抽出し、それらをコンテキストと照合することで、RAG パイプラインの応答の信頼性を測定する上で重要な役割を果たします。 ## 基本的な使い方 ```typescript import { openai } from "@ai-sdk/openai"; import { FaithfulnessMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new FaithfulnessMetric(model, { context: [ "The company was established in 1995.", "Currently employs around 450-550 people.", ], }); const result = await metric.measure( "Tell me about the company.", "The company was founded in 1995 and has 500 employees.", ); console.log(result.score); // 1.0 console.log(result.info.reason); // "All claims are supported by the context." ``` ## コンストラクタのパラメータ ### FaithfulnessMetricOptions ## measure() のパラメーター ## 戻り値 ## スコアリングの詳細 このメトリックは、提供されたコンテキストに対するクレーム検証を通じて忠実性を評価します。 ### スコアリングプロセス 1. クレームとコンテキストを分析します: - すべてのクレーム(事実および推測)を抽出 - 各クレームをコンテキストと照合して検証 - 3つの判定のいずれかを割り当てる: - "yes" - クレームがコンテキストによって支持されている - "no" - クレームがコンテキストと矛盾している - "unsure" - クレームが検証できない 2. 忠実性スコアを計算: - 支持されたクレームの数をカウント - 総クレーム数で割る - 設定された範囲にスケーリング 最終スコア: `(supported_claims / total_claims) * scale` ### スコアの解釈 (0 から scale、デフォルトは 0-1) - 1.0: すべてのクレームがコンテキストによって支持されている - 0.7-0.9: ほとんどのクレームが支持されており、検証できないものは少数 - 0.4-0.6: 支持と矛盾が混在 - 0.1-0.3: 支持は限定的で、多くが矛盾 - 0.0: 支持されたクレームがない ## 応用例 ```typescript import { openai } from "@ai-sdk/openai"; import { FaithfulnessMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new FaithfulnessMetric(model, { context: [ "The company had 100 employees in 2020.", "Current employee count is approximately 500.", ], }); // Example with mixed claim types const result = await metric.measure( "What's the company's growth like?", "The company has grown from 100 employees in 2020 to 500 now, and might expand to 1000 by next year.", ); // Example output: // { // score: 0.67, // info: { // reason: "The score is 0.67 because two claims are supported by the context // (initial employee count of 100 in 2020 and current count of 500), // while the future expansion claim is marked as unsure as it cannot // be verified against the context." // } // } ``` ### 関連項目 - [Answer Relevancy Metric](./answer-relevancy) - [Hallucination Metric](./hallucination) - [Context Relevancy Metric](./context-relevancy) --- title: "リファレンス: ハルシネーション | メトリクス | Evals | Mastra ドキュメント" description: Mastra におけるハルシネーションメトリクスのドキュメント。提供されたコンテキストと矛盾する箇所を特定することで、LLM出力の事実的正確性を評価します。 --- # HallucinationMetric [JA] Source: https://mastra.ai/ja/reference/evals/hallucination `HallucinationMetric`は、LLMが生成した情報が事実に基づいているかどうかを、与えられたコンテキストと出力を比較することで評価します。このメトリクスは、コンテキストと出力の間に直接的な矛盾があるかどうかを特定することで、ハルシネーションを測定します。 ## 基本的な使い方 ```typescript import { openai } from "@ai-sdk/openai"; import { HallucinationMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new HallucinationMetric(model, { context: [ "Tesla was founded in 2003 by Martin Eberhard and Marc Tarpenning in San Carlos, California.", ], }); const result = await metric.measure( "Tell me about Tesla's founding.", "Tesla was founded in 2004 by Elon Musk in California.", ); console.log(result.score); // Score from 0-1 console.log(result.info.reason); // Explanation of the score // Example output: // { // score: 0.67, // info: { // reason: "The score is 0.67 because two out of three statements from the context // (founding year and founders) were contradicted by the output, while the // location statement was not contradicted." // } // } ``` ## コンストラクタのパラメータ ### HallucinationMetricOptions ## measure() のパラメータ ## 戻り値 ## スコアリングの詳細 このメトリックは、矛盾検出と根拠のない主張の分析を通じてハルシネーションを評価します。 ### スコアリングプロセス 1. 事実内容の分析: - コンテキストから文を抽出 - 数値や日付を特定 - 文同士の関係をマッピング 2. 出力のハルシネーション分析: - コンテキストの文と比較 - 直接的な矛盾をハルシネーションとしてマーク - 根拠のない主張をハルシネーションとして特定 - 数値の正確性を評価 - 概算のコンテキストを考慮 3. ハルシネーションスコアの計算: - ハルシネーションと判定された文(矛盾および根拠のない主張)の数をカウント - 総文数で割る - 設定された範囲にスケーリング 最終スコア: `(hallucinated_statements / total_statements) * scale` ### 重要な考慮事項 - コンテキストに存在しない主張はハルシネーションとして扱われます - 主観的な主張は、明確な根拠がない限りハルシネーションとみなされます - コンテキスト内の事実についての推測的な言い回し(「かもしれない」「おそらく」など)は許容されます - コンテキスト外の事実についての推測的な言い回しはハルシネーションとみなされます - 出力が空の場合、ハルシネーションはゼロとなります - 数値の評価では以下を考慮します: - スケールに応じた精度 - コンテキスト上の概算 - 明示的な精度の指標 ### スコアの解釈 (0 から scale、デフォルトは 0-1) - 1.0: 完全なハルシネーション - すべてのコンテキスト文と矛盾 - 0.75: 高度なハルシネーション - 75%のコンテキスト文と矛盾 - 0.5: 中程度のハルシネーション - 半数のコンテキスト文と矛盾 - 0.25: 低度のハルシネーション - 25%のコンテキスト文と矛盾 - 0.0: ハルシネーションなし - すべてのコンテキスト文と整合 **注:** このスコアはハルシネーションの度合いを示します。スコアが低いほど、提供されたコンテキストとの事実整合性が高いことを意味します。 ## 分析付きの例 ```typescript import { openai } from "@ai-sdk/openai"; import { HallucinationMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new HallucinationMetric(model, { context: [ "OpenAI was founded in December 2015 by Sam Altman, Greg Brockman, and others.", "The company launched with a $1 billion investment commitment.", "Elon Musk was an early supporter but left the board in 2018.", ], }); const result = await metric.measure({ input: "What are the key details about OpenAI?", output: "OpenAI was founded in 2015 by Elon Musk and Sam Altman with a $2 billion investment.", }); // Example output: // { // score: 0.33, // info: { // reason: "The score is 0.33 because one out of three statements from the context // was contradicted (the investment amount was stated as $2 billion instead // of $1 billion). The founding date was correct, and while the output's // description of founders was incomplete, it wasn't strictly contradictory." // } // } ``` ## 関連 - [Faithfulness Metric](./faithfulness) - [Answer Relevancy Metric](./answer-relevancy) - [Context Precision Metric](./context-precision) - [Context Relevancy Metric](./context-relevancy) --- title: "リファレンス: キーワードカバレッジ | メトリクス | Evals | Mastra ドキュメント" description: Mastra におけるキーワードカバレッジメトリクスのドキュメント。入力から重要なキーワードが LLM の出力でどれだけカバーされているかを評価します。 --- # KeywordCoverageMetric [JA] Source: https://mastra.ai/ja/reference/evals/keyword-coverage `KeywordCoverageMetric` クラスは、LLM の出力が入力の重要なキーワードをどれだけ網羅しているかを評価します。一般的な単語やストップワードを無視しながら、キーワードの存在と一致を分析します。 ## 基本的な使い方 ```typescript import { KeywordCoverageMetric } from "@mastra/evals/nlp"; const metric = new KeywordCoverageMetric(); const result = await metric.measure( "What are the key features of Python programming language?", "Python is a high-level programming language known for its simple syntax and extensive libraries.", ); console.log(result.score); // Coverage score from 0-1 console.log(result.info); // Object containing detailed metrics about keyword coverage ``` ## measure() のパラメーター ## 戻り値 ## スコアリングの詳細 この指標は、以下の特徴を持つキーワードとのマッチングによってキーワードカバレッジを評価します。 - 一般的な単語やストップワードのフィルタリング(例:「the」「a」「and」など) - 大文字・小文字を区別しないマッチング - 単語形のバリエーションへの対応 - 技術用語や複合語の特別な処理 ### スコアリングプロセス 1. 入力と出力からキーワードを処理します: - 一般的な単語やストップワードを除外 - 大文字・小文字や単語形を正規化 - 特別な用語や複合語を処理 2. キーワードカバレッジを計算します: - テキスト間でキーワードをマッチング - 成功したマッチ数をカウント - カバレッジ比率を算出 最終スコア:`(matched_keywords / total_keywords) * scale` ### スコアの解釈 (0 から scale、デフォルトは 0-1) - 1.0: 完全なキーワードカバレッジ - 0.7-0.9: ほとんどのキーワードが含まれている良好なカバレッジ - 0.4-0.6: 一部のキーワードが欠落している中程度のカバレッジ - 0.1-0.3: 多くのキーワードが欠落している低いカバレッジ - 0.0: キーワードの一致なし ## 例と分析 ```typescript import { KeywordCoverageMetric } from "@mastra/evals/nlp"; const metric = new KeywordCoverageMetric(); // Perfect coverage example const result1 = await metric.measure( "The quick brown fox jumps over the lazy dog", "A quick brown fox jumped over a lazy dog", ); // { // score: 1.0, // info: { // matchedKeywords: 6, // totalKeywords: 6 // } // } // Partial coverage example const result2 = await metric.measure( "Python features include easy syntax, dynamic typing, and extensive libraries", "Python has simple syntax and many libraries", ); // { // score: 0.67, // info: { // matchedKeywords: 4, // totalKeywords: 6 // } // } // Technical terms example const result3 = await metric.measure( "Discuss React.js component lifecycle and state management", "React components have lifecycle methods and manage state", ); // { // score: 1.0, // info: { // matchedKeywords: 4, // totalKeywords: 4 // } // } ``` ## 特殊なケース このメトリクスはいくつかの特殊なケースに対応しています: - 入力/出力が空の場合:両方が空ならスコアは1.0、どちらか一方のみ空なら0.0を返します - 単語が1つの場合:1つのキーワードとして扱います - 技術用語:複合的な技術用語(例: "React.js", "machine learning")を保持します - 大文字・小文字の違い:"JavaScript"は"javascript"と一致します - 一般的な単語:意味のあるキーワードに集中するため、スコア計算時に無視されます ## 関連 - [Completeness Metric](./completeness) - [Content Similarity Metric](./content-similarity) - [Answer Relevancy Metric](./answer-relevancy) - [Textual Difference Metric](./textual-difference) - [Context Relevancy Metric](./context-relevancy) --- title: "リファレンス: プロンプトアラインメント | メトリクス | Evals | Mastra ドキュメント" description: Mastra におけるプロンプトアラインメントメトリクスのドキュメント。LLM の出力が与えられたプロンプト指示にどれだけ従っているかを評価します。 --- # PromptAlignmentMetric [JA] Source: https://mastra.ai/ja/reference/evals/prompt-alignment `PromptAlignmentMetric` クラスは、LLM の出力が与えられたプロンプト指示にどれだけ厳密に従っているかを評価します。各指示が正確に守られているかを判定するジャッジベースのシステムを使用し、逸脱があった場合には詳細な理由を提供します。 ## 基本的な使い方 ```typescript import { openai } from "@ai-sdk/openai"; import { PromptAlignmentMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const instructions = [ "Start sentences with capital letters", "End each sentence with a period", "Use present tense", ]; const metric = new PromptAlignmentMetric(model, { instructions, scale: 1, }); const result = await metric.measure( "describe the weather", "The sun is shining. Clouds float in the sky. A gentle breeze blows.", ); console.log(result.score); // Alignment score from 0-1 console.log(result.info.reason); // Explanation of the score ``` ## コンストラクタのパラメータ ### PromptAlignmentOptions ## measure() のパラメーター ## 戻り値 ## スコアリングの詳細 この指標は、以下の観点からインストラクションの整合性を評価します。 - 各インストラクションの適用可能性の評価 - 適用可能なインストラクションに対する厳格な遵守評価 - すべての判定に対する詳細な理由付け - 適用可能なインストラクションに基づく比例配点 ### インストラクションの判定 各インストラクションには、次のいずれかの判定が与えられます。 - "yes":インストラクションが適用可能で、完全に遵守されている - "no":インストラクションが適用可能だが、遵守されていない、または部分的にしか遵守されていない - "n/a":インストラクションが該当する状況に適用できない ### スコアリングプロセス 1. インストラクションの適用可能性を評価: - 各インストラクションが状況に適用できるかを判断 - 関連性のないインストラクションは "n/a" としてマーク - ドメイン固有の要件を考慮 2. 適用可能なインストラクションの遵守状況を評価: - 各適用可能なインストラクションを個別に評価 - "yes" の判定には完全な遵守が必要 - すべての判定に対して具体的な理由を記録 3. 整合性スコアを算出: - 遵守されたインストラクション("yes" 判定)の数をカウント - 適用可能なインストラクションの総数("n/a" を除く)で割る - 設定された範囲にスケーリング 最終スコア:`(followed_instructions / applicable_instructions) * scale` ### 重要な考慮事項 - 出力が空の場合: - すべての書式指示は適用可能と見なされる - 要件を満たせないため "no" としてマーク - ドメイン固有のインストラクション: - 問い合わせたドメインに関する場合は常に適用可能 - 遵守されていない場合は "no"、"n/a" にはしない - "n/a" の判定: - 完全に異なるドメインの場合のみ使用 - 最終スコアの計算には影響しない ### スコアの解釈 (0 から scale、デフォルトは 0-1) - 1.0:すべての適用可能なインストラクションが完全に遵守されている - 0.7-0.9:ほとんどの適用可能なインストラクションが遵守されている - 0.4-0.6:適用可能なインストラクションの遵守状況が混在している - 0.1-0.3:適用可能なインストラクションの遵守が限定的 - 0.0:適用可能なインストラクションがまったく遵守されていない ## 例と分析 ```typescript import { openai } from "@ai-sdk/openai"; import { PromptAlignmentMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new PromptAlignmentMetric(model, { instructions: [ "Use bullet points for each item", "Include exactly three examples", "End each point with a semicolon" ], scale: 1 }); const result = await metric.measure( "List three fruits", "• Apple is red and sweet; • Banana is yellow and curved; • Orange is citrus and round." ); // Example output: // { // score: 1.0, // info: { // reason: "The score is 1.0 because all instructions were followed exactly: // bullet points were used, exactly three examples were provided, and // each point ends with a semicolon." // } // } const result2 = await metric.measure( "List three fruits", "1. Apple 2. Banana 3. Orange and Grape" ); // Example output: // { // score: 0.33, // info: { // reason: "The score is 0.33 because: numbered lists were used instead of bullet points, // no semicolons were used, and four fruits were listed instead of exactly three." // } // } ``` ## 関連 - [Answer Relevancy Metric](./answer-relevancy) - [Keyword Coverage Metric](./keyword-coverage) --- title: "リファレンス: 要約 | メトリクス | Evals | Mastra ドキュメント" description: Mastra における要約メトリクスのドキュメント。コンテンツと事実の正確性に関して、LLM が生成した要約の品質を評価します。 --- # SummarizationMetric [JA] Source: https://mastra.ai/ja/reference/evals/summarization , `SummarizationMetric`は、LLMによる要約が元のテキストの内容をどれだけ正確に捉え、事実に基づいているかを評価します。この指標は、アライメント(事実の正確性)とカバレッジ(重要な情報の網羅)の2つの側面を組み合わせており、どちらの品質も優れた要約に不可欠であることを保証するために最小スコアを使用します。 ## 基本的な使い方 ```typescript import { openai } from "@ai-sdk/openai"; import { SummarizationMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new SummarizationMetric(model); const result = await metric.measure( "The company was founded in 1995 by John Smith. It started with 10 employees and grew to 500 by 2020. The company is based in Seattle.", "Founded in 1995 by John Smith, the company grew from 10 to 500 employees by 2020.", ); console.log(result.score); // Score from 0-1 console.log(result.info); // Object containing detailed metrics about the summary ``` ## コンストラクタのパラメータ ### SummarizationMetricOptions ## measure() のパラメーター ## 戻り値 ## スコアリングの詳細 このメトリックは、要約を2つの重要な要素で評価します。 1. **アライメントスコア**:事実の正確性を測定 - 要約から主張を抽出 - 各主張を元のテキストと照合 - 「yes」「no」「unsure」の判定を付与 2. **カバレッジスコア**:重要情報の網羅性を測定 - 元のテキストから重要な質問を生成 - 要約がこれらの質問に答えているか確認 - 情報の包含と網羅性を評価 ### スコアリングプロセス 1. アライメントスコアを計算: - 要約から主張を抽出 - 元テキストと照合 - 計算式:`supported_claims / total_claims` 2. カバレッジスコアを決定: - 元テキストから質問を生成 - 要約が回答しているか確認 - 完全性を評価 - 計算式:`answerable_questions / total_questions` 最終スコア:`min(alignment_score, coverage_score) * scale` ### スコアの解釈 (0からscale、デフォルトは0-1) - 1.0:完璧な要約 - 完全に事実に基づき、すべての重要情報を網羅 - 0.7-0.9:強力な要約だが、わずかな抜けや軽微な不正確さあり - 0.4-0.6:中程度の品質で、重要な抜けや不正確さが目立つ - 0.1-0.3:大きな抜けや事実誤認がある低品質な要約 - 0.0:無効な要約 - 完全に不正確、または重要な情報が欠落 ## 分析付きの例 ```typescript import { openai } from "@ai-sdk/openai"; import { SummarizationMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new SummarizationMetric(model); const result = await metric.measure( "The electric car company Tesla was founded in 2003 by Martin Eberhard and Marc Tarpenning. Elon Musk joined in 2004 as the largest investor and became CEO in 2008. The company's first car, the Roadster, was launched in 2008.", "Tesla, founded by Elon Musk in 2003, revolutionized the electric car industry starting with the Roadster in 2008.", ); // Example output: // { // score: 0.5, // info: { // reason: "The score is 0.5 because while the coverage is good (0.75) - mentioning the founding year, // first car model, and launch date - the alignment score is lower (0.5) due to incorrectly // attributing the company's founding to Elon Musk instead of Martin Eberhard and Marc Tarpenning. // The final score takes the minimum of these two scores to ensure both factual accuracy and // coverage are necessary for a good summary." // alignmentScore: 0.5, // coverageScore: 0.75, // } // } ``` ## 関連 - [Faithfulness Metric](./faithfulness) - [Completeness Metric](./completeness) - [Contextual Recall Metric](./contextual-recall) - [Hallucination Metric](./hallucination) --- title: "リファレンス: テキスト差分 | Evals | Mastra ドキュメント" description: Mastra におけるテキスト差分メトリクスのドキュメント。これはシーケンスマッチングを用いて文字列間のテキスト差分を測定します。 --- # TextualDifferenceMetric [JA] Source: https://mastra.ai/ja/reference/evals/textual-difference `TextualDifferenceMetric` クラスは、シーケンスマッチングを使用して2つの文字列間のテキスト差分を測定します。このクラスは、一方のテキストをもう一方に変換するために必要な操作数を含む、変更に関する詳細な情報を提供します。 ## 基本的な使い方 ```typescript import { TextualDifferenceMetric } from "@mastra/evals/nlp"; const metric = new TextualDifferenceMetric(); const result = await metric.measure( "The quick brown fox", "The fast brown fox", ); console.log(result.score); // 0〜1の類似度比率 console.log(result.info); // 詳細な変更メトリクス ``` ## measure() のパラメーター ## 戻り値 ## スコアリングの詳細 このメトリックは、いくつかの指標を計算します: - **類似度比**:テキスト間のシーケンスマッチングに基づく(0-1) - **変更数**:一致しない操作の回数 - **長さの差**:テキスト長の正規化された差 - **信頼度**:長さの差に反比例 ### スコアリングプロセス 1. テキストの違いを分析します: - 入力と出力の間でシーケンスマッチングを実行 - 必要な変更操作の数をカウント - 長さの違いを測定 2. 指標を計算します: - 類似度比を算出 - 信頼度スコアを決定 - 重み付けされたスコアに統合 最終スコア:`(similarity_ratio * confidence) * scale` ### スコアの解釈 (0 から scale、デフォルトは 0-1) - 1.0:完全に同一のテキスト - 違いなし - 0.7-0.9:わずかな違い - 少しの変更のみ必要 - 0.4-0.6:中程度の違い - かなりの変更が必要 - 0.1-0.3:大きな違い - 大幅な変更が必要 - 0.0:全く異なるテキスト ## 分析付きの例 ```typescript import { TextualDifferenceMetric } from "@mastra/evals/nlp"; const metric = new TextualDifferenceMetric(); const result = await metric.measure( "Hello world! How are you?", "Hello there! How is it going?", ); // Example output: // { // score: 0.65, // info: { // confidence: 0.95, // ratio: 0.65, // changes: 2, // lengthDiff: 0.05 // } // } ``` ## 関連 - [コンテンツ類似度メトリック](./content-similarity) - [完全性メトリック](./completeness) - [キーワードカバレッジメトリック](./keyword-coverage) --- title: "リファレンス: トーンの一貫性 | メトリクス | 評価 | Mastra ドキュメント" description: Mastra におけるトーンの一貫性メトリクスのドキュメント。テキスト内の感情的なトーンや感情の一貫性を評価します。 --- # ToneConsistencyMetric [JA] Source: https://mastra.ai/ja/reference/evals/tone-consistency `ToneConsistencyMetric` クラスは、テキストの感情的なトーンと感情の一貫性を評価します。このクラスは、入力と出力のペア間でトーンを比較するモードと、単一のテキスト内でトーンの安定性を分析するモードの2つのモードで動作します。 ## 基本的な使い方 ```typescript import { ToneConsistencyMetric } from "@mastra/evals/nlp"; const metric = new ToneConsistencyMetric(); // Compare tone between input and output const result1 = await metric.measure( "I love this amazing product!", "This product is wonderful and fantastic!", ); // Analyze tone stability in a single text const result2 = await metric.measure( "The service is excellent. The staff is friendly. The atmosphere is perfect.", "", // Empty string for single-text analysis ); console.log(result1.score); // Tone consistency score from 0-1 console.log(result2.score); // Tone stability score from 0-1 ``` ## measure() のパラメーター ## 戻り値 ### info オブジェクト(トーン比較) ### info オブジェクト(トーン安定性) ## スコアリングの詳細 このメトリックは、トーンパターンの分析とモード別スコアリングを通じて感情の一貫性を評価します。 ### スコアリングプロセス 1. トーンパターンを分析: - 感情の特徴を抽出 - 感情スコアを算出 - トーンの変動を測定 2. モード別スコアを計算: **トーンの一貫性**(入力と出力): - テキスト間の感情を比較 - 感情の差分を計算 - スコア = 1 - (感情の差分 / 最大差分) **トーンの安定性**(単一入力): - 文ごとの感情を分析 - 感情の分散を計算 - スコア = 1 - (感情の分散 / 最大分散) 最終スコア:`mode_specific_score * scale` ### スコアの解釈 (0 から scale、デフォルトは 0-1) - 1.0: 完全なトーンの一貫性/安定性 - 0.7-0.9: 軽微な変動を伴う強い一貫性 - 0.4-0.6: 目立つ変化を伴う中程度の一貫性 - 0.1-0.3: 大きなトーン変化を伴う低い一貫性 - 0.0: 一貫性なし ― 完全に異なるトーン ## 両方のモードの例 ```typescript import { ToneConsistencyMetric } from "@mastra/evals/nlp"; const metric = new ToneConsistencyMetric(); // Tone Consistency Mode const consistencyResult = await metric.measure( "This product is fantastic and amazing!", "The product is excellent and wonderful!", ); // Example output: // { // score: 0.95, // info: { // responseSentiment: 0.8, // referenceSentiment: 0.75, // difference: 0.05 // } // } // Tone Stability Mode const stabilityResult = await metric.measure( "Great service! Friendly staff. Perfect atmosphere.", "", ); // Example output: // { // score: 0.9, // info: { // avgSentiment: 0.6, // sentimentVariance: 0.1 // } // } ``` ## 関連 - [コンテンツ類似度メトリック](./content-similarity) - [有害性メトリック](./toxicity) --- title: "リファレンス: 有害性 | メトリクス | Evals | Mastra ドキュメント" description: Mastra における有害性メトリクスのドキュメント。LLM の出力における人種差別的、偏見的、または有害な要素を評価します。 --- # ToxicityMetric [JA] Source: https://mastra.ai/ja/reference/evals/toxicity `ToxicityMetric` クラスは、LLM の出力に人種差別的、偏見的、または有害な要素が含まれているかどうかを評価します。これは、判定者ベースのシステムを使用して、個人攻撃、嘲笑、ヘイトスピーチ、軽視的な発言、脅迫など、さまざまな形態の有害性について応答を分析します。 ## 基本的な使い方 ```typescript import { openai } from "@ai-sdk/openai"; import { ToxicityMetric } from "@mastra/evals/llm"; // Configure the model for evaluation const model = openai("gpt-4o-mini"); const metric = new ToxicityMetric(model, { scale: 1, // Default scale is 0-1 }); const result = await metric.measure( "How is Sarah as a person?", "Sarah is a dedicated team member who always delivers quality work.", ); console.log(result.score); // Score from 0-1 (0 = not toxic, 1 = toxic) console.log(result.info.reason); // Explanation of the toxicity assessment ``` ## コンストラクタのパラメータ ### ToxicityMetricOptions ## measure() のパラメーター ## 戻り値 ## スコアリングの詳細 この指標は、複数の側面から有害性を評価します: - 個人攻撃 - 嘲笑や皮肉 - ヘイトスピーチ - 軽視的な発言 - 脅迫や威圧 ### スコアリングプロセス 1. 有害な要素を分析: - 個人攻撃や嘲笑を特定 - ヘイトスピーチや脅迫を検出 - 軽視的な発言を評価 - 深刻度レベルを査定 2. 有害性スコアを算出: - 検出された要素を重み付け - 深刻度評価を組み合わせ - スケールに正規化 最終スコア:`(toxicity_weighted_sum / max_toxicity) * scale` ### スコアの解釈 (0 から scale、デフォルトは 0-1) - 0.8-1.0:深刻な有害性 - 0.4-0.7:中程度の有害性 - 0.1-0.3:軽度の有害性 - 0.0:有害な要素は検出されませんでした ## カスタム設定の例 ```typescript import { openai } from "@ai-sdk/openai"; const model = openai("gpt-4o-mini"); const metric = new ToxicityMetric(model, { scale: 10, // 0-1 の代わりに 0-10 のスケールを使用 }); const result = await metric.measure( "What do you think about the new team member?", "The new team member shows promise but needs significant improvement in basic skills.", ); ``` ## 関連項目 - [トーン一貫性メトリック](./tone-consistency) - [バイアスメトリック](./bias) --- title: "API リファレンス" description: "Mastra API リファレンス" --- import { ReferenceCards } from "@/components/reference-cards"; # リファレンス [JA] Source: https://mastra.ai/ja/reference リファレンスセクションでは、パラメータ、タイプ、使用例を含むMastraのAPIのドキュメントを提供しています。 --- title: "リファレンス: .after() | ワークフローの構築(レガシー) | Mastra ドキュメント" description: ワークフロー(レガシー)における `after()` メソッドのドキュメント。分岐や統合パスを可能にします。 --- # .after() [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/after `.after()` メソッドは、ワークフローの各ステップ間に明示的な依存関係を定義し、ワークフロー実行における分岐や統合パスを可能にします。 ## 使い方 ### 基本的な分岐 ```typescript workflow .step(stepA) .then(stepB) .after(stepA) // stepAが完了した後に新しい分岐を作成 .step(stepC); ``` ### 複数の分岐のマージ ```typescript workflow .step(stepA) .then(stepB) .step(stepC) .then(stepD) .after([stepB, stepD]) // 複数のステップに依存するステップを作成 .step(stepE); ``` ## パラメーター ## 戻り値 ## 例 ### 単一の依存関係 ```typescript workflow .step(fetchData) .then(processData) .after(fetchData) // Branch after fetchData .step(logData); ``` ### 複数の依存関係(ブランチの統合) ```typescript workflow .step(fetchUserData) .then(validateUserData) .step(fetchProductData) .then(validateProductData) .after([validateUserData, validateProductData]) // Wait for both validations to complete .step(processOrder); ``` ## 関連 - [Branching Paths の例](../../examples/workflows_legacy/branching-paths.mdx) - [Workflow クラスリファレンス](./workflow.mdx) - [Step リファレンス](./step-class.mdx) - [制御フローガイド](../../docs/workflows-legacy/control-flow.mdx) --- title: ".afterEvent() メソッド | Mastra ドキュメント" description: "Mastra ワークフローにおける afterEvent メソッドのリファレンス。イベントベースのサスペンションポイントを作成します。" --- # afterEvent() [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/afterEvent `afterEvent()` メソッドは、ワークフロー内で特定のイベントが発生するまで実行を一時停止し、その後に処理を続行するサスペンションポイントを作成します。 ## 構文 ```typescript workflow.afterEvent(eventName: string): Workflow ``` ## パラメーター | パラメーター | 型 | 説明 | | ----------- | ------ | ------------------------------------------------------------------------------------------------------ | | eventName | string | 待機するイベントの名前。ワークフローの `events` 設定で定義されたイベントと一致する必要があります。 | ## 戻り値 メソッドチェーンのためにワークフローインスタンスを返します。 ## 説明 `afterEvent()` メソッドは、ワークフロー内で特定の名前付きイベントを待機する自動的なサスペンションポイントを作成するために使用されます。これは、ワークフローが一時停止し、外部イベントが発生するのを待つポイントを宣言的に定義する方法です。 `afterEvent()` を呼び出すと、Mastra は以下の処理を行います: 1. ID が `__eventName_event` の特別なステップを作成します 2. このステップは自動的にワークフローの実行を一時停止します 3. 指定されたイベントが `resumeWithEvent()` を通じてトリガーされるまで、ワークフローは一時停止したままになります 4. イベントが発生すると、`afterEvent()` 呼び出しの次のステップから実行が再開されます このメソッドは Mastra のイベント駆動型ワークフロー機能の一部であり、サスペンションロジックを手動で実装することなく、外部システムやユーザー操作と連携するワークフローを作成できます。 ## 使用上の注意 - `afterEvent()` で指定されたイベントは、ワークフローの `events` 設定でスキーマとともに定義されている必要があります - 作成される特別なステップには予測可能なID形式が使われます:`__eventName_event`(例:`__approvalReceived_event`) - `afterEvent()` の後に続く任意のステップは、`context.inputData.resumedEvent` を通じてイベントデータにアクセスできます - `resumeWithEvent()` が呼び出された際、イベントデータはそのイベント用に定義されたスキーマに対して検証されます ## 例 ### 基本的な使い方 ```typescript import { LegacyWorkflow } from "@mastra/core/workflows/legacy"; // Define workflow with events const workflow = new LegacyWorkflow({ name: "approval-workflow", events: { approval: { schema: z.object({ approved: z.boolean(), approverName: z.string(), }), }, }, }); // Build workflow with event suspension point workflow .step(submitRequest) .afterEvent("approval") // Workflow suspends here .step(processApproval) // This step runs after the event occurs .commit(); ``` ## 関連 - [イベント駆動型ワークフロー](./events.mdx) - [resumeWithEvent()](./resumeWithEvent.mdx) - [サスペンドと再開](../../docs/workflows-legacy/suspend-and-resume.mdx) - [Workflow クラス](./workflow.mdx) --- title: "リファレンス: Workflow.commit() | ワークフローの実行(レガシー) | Mastra ドキュメント" description: ワークフロー内の `.commit()` メソッドのドキュメント。現在のステップ構成でワークフローマシンを再初期化します。 --- # Workflow.commit() [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/commit `.commit()` メソッドは、現在のステップ構成でワークフローのステートマシンを再初期化します。 ## 使い方 ```typescript workflow.step(stepA).then(stepB).commit(); ``` ## 戻り値 ## 関連 - [Branching Paths の例](../../examples/workflows_legacy/branching-paths.mdx) - [Workflow クラスリファレンス](./workflow.mdx) - [Step リファレンス](./step-class.mdx) - [制御フローガイド](../../docs/workflows-legacy/control-flow.mdx) --- title: "リファレンス: Workflow.createRun() | ワークフローの実行(レガシー) | Mastra ドキュメント" description: "ワークフロー(レガシー)における `.createRun()` メソッドのドキュメント。新しいワークフロー実行インスタンスを初期化します。" --- # Workflow.createRun() [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/createRun `.createRun()` メソッドは、新しいワークフロー実行インスタンスを初期化します。トラッキング用のユニークな実行IDを生成し、呼び出されたときにワークフローの実行を開始する start 関数を返します。 `.createRun()` を `.execute()` の代わりに使用する理由の一つは、トラッキングやログ記録、`.watch()` を使った購読のためにユニークな実行IDを取得できることです。 ## 使い方 ```typescript const { runId, start, watch } = workflow.createRun(); const result = await start(); ``` ## 戻り値 Promise", description: "呼び出すことでワークフローの実行を開始する関数", }, { name: "watch", type: "(callback: (record: LegacyWorkflowResult) => void) => () => void", description: "ワークフロー実行の各遷移ごとにコールバック関数が呼び出される関数", }, { name: "resume", type: "({stepId: string, context: Record}) => Promise", description: "指定したステップIDとコンテキストからワークフロー実行を再開する関数", }, { name: "resumeWithEvent", type: "(eventName: string, data: any) => Promise", description: "指定したイベント名とデータからワークフロー実行を再開する関数", }, ]} /> ## エラー処理 start 関数は、ワークフローの設定が無効な場合にバリデーションエラーをスローすることがあります。 ```typescript try { const { runId, start, watch, resume, resumeWithEvent } = workflow.createRun(); await start({ triggerData: data }); } catch (error) { if (error instanceof ValidationError) { // Handle validation errors console.log(error.type); // 'circular_dependency' | 'no_terminal_path' | 'unreachable_step' console.log(error.details); } } ``` ## 関連 - [Workflow クラスリファレンス](./workflow.mdx) - [Step クラスリファレンス](./step-class.mdx) - 完全な使用例については、[ワークフローの作成](../../examples/workflows_legacy/creating-a-workflow.mdx)の例をご覧ください ``` ``` --- title: "リファレンス: Workflow.else() | 条件分岐 | Mastra ドキュメント" description: "Mastra ワークフローにおける `.else()` メソッドのドキュメント。if 条件が偽の場合に代替の分岐を作成します。" --- # Workflow.else() [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/else > 実験的 `.else()` メソッドは、直前の `if` 条件が false と評価された場合に実行される、ワークフロー内の代替分岐を作成します。これにより、条件に応じてワークフローが異なる経路をたどることができます。 ## 使用方法 ```typescript copy showLineNumbers workflow .step(startStep) .if(async ({ context }) => { const value = context.getStepResult<{ value: number }>("start")?.value; return value < 10; }) .then(ifBranchStep) .else() // Alternative branch when the condition is false .then(elseBranchStep) .commit(); ``` ## パラメーター `else()` メソッドはパラメーターを受け取りません。 ## 戻り値 ## 挙動 - `else()` メソッドは、ワークフロー定義内で `if()` ブランチの後に続けて使用する必要があります - これは、直前の `if` 条件が false と評価された場合にのみ実行されるブランチを作成します - `.then()` を使って、`else()` の後に複数のステップをチェーンできます - `else` ブランチ内で追加の `if`/`else` 条件をネストすることができます ## エラー処理 `else()` メソッドは、直前に `if()` ステートメントが必要です。もし先行する `if` なしで使用しようとすると、エラーが発生します。 ```typescript try { // これはエラーを投げます workflow.step(someStep).else().then(anotherStep).commit(); } catch (error) { console.error(error); // "No active condition found" } ``` ## 関連 - [if リファレンス](./if.mdx) - [then リファレンス](./then.mdx) - [制御フローガイド](../../docs/workflows-legacy/control-flow.mdx) - [ステップ条件リファレンス](./step-condition.mdx) --- title: "イベント駆動型ワークフロー(レガシー) | Mastra ドキュメント" description: "MastraでafterEventおよびresumeWithEventメソッドを使用してイベント駆動型ワークフローを作成する方法を学びます。" --- # イベント駆動型ワークフロー [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/events Mastra は、`afterEvent` と `resumeWithEvent` メソッドを通じて、イベント駆動型ワークフローを標準でサポートしています。これらのメソッドを使用することで、特定のイベントが発生するのを待ってワークフローの実行を一時停止し、イベントデータが利用可能になった時点で再開するワークフローを作成できます。 ## 概要 イベント駆動型ワークフローは、次のようなシナリオで役立ちます。 - 外部システムの処理完了を待つ必要がある場合 - 特定のタイミングでユーザーの承認や入力が必要な場合 - 非同期処理を調整する必要がある場合 - 長時間実行されるプロセスを複数のサービスに分割して実行する必要がある場合 ## イベントの定義 イベント駆動型の手法を使用する前に、ワークフロー構成でワークフローがリッスンするイベントを定義する必要があります。 ```typescript import { LegacyWorkflow } from "@mastra/core/workflows/legacy"; import { z } from "zod"; const workflow = new LegacyWorkflow({ name: "approval-workflow", triggerSchema: z.object({ requestId: z.string() }), events: { // Define events with their validation schemas approvalReceived: { schema: z.object({ approved: z.boolean(), approverName: z.string(), comment: z.string().optional(), }), }, documentUploaded: { schema: z.object({ documentId: z.string(), documentType: z.enum(["invoice", "receipt", "contract"]), metadata: z.record(z.string()).optional(), }), }, }, }); ``` 各イベントには名前と、そのイベントが発生した際に期待されるデータの構造を定義するスキーマが必要です。 ## afterEvent() `afterEvent` メソッドは、ワークフロー内に特定のイベントを自動的に待機するサスペンションポイントを作成します。 ### 構文 ```typescript workflow.afterEvent(eventName: string): LegacyWorkflow ``` ### パラメーター - `eventName`: 待機するイベントの名前(ワークフローの `events` 設定で定義されている必要があります) ### 戻り値 メソッドチェーンのためのワークフローインスタンスを返します。 ### 動作概要 `afterEvent` が呼び出されると、Mastra は以下を行います: 1. ID が `__eventName_event` の特別なステップを作成します 2. このステップをワークフロー実行を自動的にサスペンドするように設定します 3. イベント受信後の継続ポイントを設定します ### 使用例 ```typescript workflow .step(initialProcessStep) .afterEvent("approvalReceived") // ここでワークフローがサスペンドされます .step(postApprovalStep) // この処理はイベント受信後に実行されます .then(finalStep) .commit(); ``` ## resumeWithEvent() `resumeWithEvent` メソッドは、特定のイベントに対するデータを提供することで、一時停止中のワークフローを再開します。 ### 構文 ```typescript run.resumeWithEvent(eventName: string, data: any): Promise ``` ### パラメーター - `eventName`: トリガーされるイベントの名前 - `data`: イベントデータ(このイベントのために定義されたスキーマに準拠している必要があります) ### 戻り値 再開後のワークフロー実行結果を解決する Promise を返します。 ### 動作の仕組み `resumeWithEvent` が呼び出されると、Mastra は以下を行います: 1. イベントデータがそのイベントのために定義されたスキーマに合致しているか検証します 2. ワークフローのスナップショットを読み込みます 3. イベントデータでコンテキストを更新します 4. イベントステップから実行を再開します 5. その後のステップでワークフローの実行を継続します ### 使用例 ```typescript // ワークフローランを作成 const run = workflow.createRun(); // ワークフローを開始 await run.start({ triggerData: { requestId: "req-123" } }); // 後で、イベントが発生したとき: const result = await run.resumeWithEvent("approvalReceived", { approved: true, approverName: "John Doe", comment: "Looks good to me!", }); console.log(result.results); ``` ## イベントデータへのアクセス ワークフローがイベントデータで再開されると、そのデータはステップコンテキスト内の `context.inputData.resumedEvent` で利用できます。 ```typescript const processApprovalStep = new LegacyStep({ id: "processApproval", execute: async ({ context }) => { // Access the event data const eventData = context.inputData.resumedEvent; return { processingResult: `Processed approval from ${eventData.approverName}`, wasApproved: eventData.approved, }; }, }); ``` ## 複数のイベント さまざまなタイミングで複数の異なるイベントを待機するワークフローを作成できます。 ```typescript workflow .step(createRequest) .afterEvent("approvalReceived") .step(processApproval) .afterEvent("documentUploaded") .step(processDocument) .commit(); ``` 複数のイベント停止ポイントがあるワークフローを再開する場合、現在の停止ポイントに対応する正しいイベント名とデータを指定する必要があります。 ## 実践例 この例では、承認とドキュメントのアップロードの両方が必要な完全なワークフローを示します。 ```typescript import { LegacyWorkflow, LegacyStep } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Define steps const createRequest = new LegacyStep({ id: "createRequest", execute: async () => ({ requestId: `req-${Date.now()}` }), }); const processApproval = new LegacyStep({ id: "processApproval", execute: async ({ context }) => { const approvalData = context.inputData.resumedEvent; return { approved: approvalData.approved, approver: approvalData.approverName, }; }, }); const processDocument = new LegacyStep({ id: "processDocument", execute: async ({ context }) => { const documentData = context.inputData.resumedEvent; return { documentId: documentData.documentId, processed: true, type: documentData.documentType, }; }, }); const finalizeRequest = new LegacyStep({ id: "finalizeRequest", execute: async ({ context }) => { const requestId = context.steps.createRequest.output.requestId; const approved = context.steps.processApproval.output.approved; const documentId = context.steps.processDocument.output.documentId; return { finalized: true, summary: `Request ${requestId} was ${approved ? "approved" : "rejected"} with document ${documentId}`, }; }, }); // Create workflow const requestWorkflow = new LegacyWorkflow({ name: "document-request-workflow", events: { approvalReceived: { schema: z.object({ approved: z.boolean(), approverName: z.string(), }), }, documentUploaded: { schema: z.object({ documentId: z.string(), documentType: z.enum(["invoice", "receipt", "contract"]), }), }, }, }); // Build workflow requestWorkflow .step(createRequest) .afterEvent("approvalReceived") .step(processApproval) .afterEvent("documentUploaded") .step(processDocument) .then(finalizeRequest) .commit(); // Export workflow export { requestWorkflow }; ``` ### サンプルワークフローの実行 ```typescript import { requestWorkflow } from "./workflows"; import { mastra } from "./mastra"; async function runWorkflow() { // Get the workflow const workflow = mastra.legacy_getWorkflow("document-request-workflow"); const run = workflow.createRun(); // Start the workflow const initialResult = await run.start(); console.log("Workflow started:", initialResult.results); // Simulate receiving approval const afterApprovalResult = await run.resumeWithEvent("approvalReceived", { approved: true, approverName: "Jane Smith", }); console.log("After approval:", afterApprovalResult.results); // Simulate document upload const finalResult = await run.resumeWithEvent("documentUploaded", { documentId: "doc-456", documentType: "invoice", }); console.log("Final result:", finalResult.results); } runWorkflow().catch(console.error); ``` ## ベストプラクティス 1. **明確なイベントスキーマを定義する**: Zod を使ってイベントデータのバリデーション用に正確なスキーマを作成しましょう 2. **分かりやすいイベント名を使う**: イベントの目的が明確に伝わる名前を選びましょう 3. **イベントの未発生を処理する**: イベントが発生しない場合やタイムアウトする場合にもワークフローが対応できるようにしましょう 4. **モニタリングを含める**: `watch` メソッドを使って、イベント待ちでサスペンドされているワークフローを監視しましょう 5. **タイムアウトを考慮する**: 発生しない可能性のあるイベントに対してタイムアウト機構を実装しましょう 6. **イベントをドキュメント化する**: 他の開発者のために、ワークフローが依存するイベントを明確にドキュメント化しましょう ## 関連 - [ワークフローにおける一時停止と再開](../../docs/workflows-legacy/suspend-and-resume.mdx) - [Workflow クラスリファレンス](./workflow.mdx) - [Resume メソッドリファレンス](./resume.mdx) - [Watch メソッドリファレンス](./watch.mdx) - [After Event リファレンス](./afterEvent.mdx) - [Resume With Event リファレンス](./resumeWithEvent.mdx) --- title: "リファレンス: Workflow.execute() | ワークフロー(レガシー) | Mastra ドキュメント" description: "Mastra ワークフローにおける `.execute()` メソッドのドキュメント。このメソッドはワークフローステップを実行し、結果を返します。" --- # Workflow.execute() [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/execute 指定されたトリガーデータでワークフローを実行し、結果を返します。ワークフローは実行前にコミットされている必要があります。 ## 使用例 ```typescript const workflow = new LegacyWorkflow({ name: "my-workflow", triggerSchema: z.object({ inputValue: z.number(), }), }); workflow.step(stepOne).then(stepTwo).commit(); const result = await workflow.execute({ triggerData: { inputValue: 42 }, }); ``` ## パラメーター ## 戻り値 ", description: "完了した各ステップの結果", }, { name: "status", type: "WorkflowStatus", description: "ワークフロー実行の最終ステータス", }, ], }, ]} /> ## 追加の例 run ID を指定して実行: ```typescript const result = await workflow.execute({ runId: "custom-run-id", triggerData: { inputValue: 42 }, }); ``` 実行結果を処理する: ```typescript const { runId, results, status } = await workflow.execute({ triggerData: { inputValue: 42 }, }); if (status === "COMPLETED") { console.log("Step results:", results); } ``` ### 関連 - [Workflow.createRun()](./createRun.mdx) - [Workflow.commit()](./commit.mdx) - [Workflow.start()](./start.mdx) --- title: "リファレンス: Workflow.if() | 条件分岐 | Mastra ドキュメント" description: "Mastra ワークフローにおける `.if()` メソッドのドキュメント。指定した条件に基づいて条件分岐を作成します。" --- # Workflow.if() [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/if > 実験的 `.if()` メソッドはワークフロー内で条件分岐を作成し、指定した条件が真の場合にのみステップを実行できるようにします。これにより、前のステップの結果に基づいて動的なワークフローパスを実現できます。 ## 使用方法 ```typescript copy showLineNumbers workflow .step(startStep) .if(async ({ context }) => { const value = context.getStepResult<{ value: number }>("start")?.value; return value < 10; // If true, execute the "if" branch }) .then(ifBranchStep) .else() .then(elseBranchStep) .commit(); ``` ## パラメーター ## 条件タイプ ### 関数条件 真偽値を返す関数を使用できます: ```typescript workflow .step(startStep) .if(async ({ context }) => { const result = context.getStepResult<{ status: string }>("start"); return result?.status === "success"; // statusが"success"のときに"if"ブランチを実行 }) .then(successStep) .else() .then(failureStep); ``` ### 参照条件 比較演算子を使った参照ベースの条件を使用できます: ```typescript workflow .step(startStep) .if({ ref: { step: startStep, path: "value" }, query: { $lt: 10 }, // valueが10未満のときに"if"ブランチを実行 }) .then(ifBranchStep) .else() .then(elseBranchStep); ``` ## 戻り値 ## エラー処理 `if` メソッドは、前のステップが定義されている必要があります。前のステップなしで使用しようとすると、エラーが発生します。 ```typescript try { // This will throw an error workflow .if(async ({ context }) => true) .then(someStep) .commit(); } catch (error) { console.error(error); // "Condition requires a step to be executed after" } ``` ## 関連 - [else リファレンス](./else.mdx) - [then リファレンス](./then.mdx) - [制御フローガイド](../../docs/workflows-legacy/control-flow.mdx) - [ステップ条件リファレンス](./step-condition.mdx) --- title: "リファレンス: run.resume() | ワークフローの実行(レガシー) | Mastra ドキュメント" description: ワークフロー内の `.resume()` メソッドのドキュメント。中断されたワークフローステップの実行を再開します。 --- # run.resume() [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/resume `.resume()` メソッドは、一時停止されたワークフローステップの実行を再開し、オプションで新しいコンテキストデータを提供できます。このデータは、そのステップの inputData プロパティからアクセス可能です。 ## 使用方法 ```typescript copy showLineNumbers await run.resume({ runId: "abc-123", stepId: "stepTwo", context: { secondValue: 100, }, }); ``` ## パラメーター ### config ", description: "ステップのinputDataプロパティに注入する新しいコンテキストデータ", isOptional: true, }, ]} /> ## 戻り値 ", type: "object", description: "再開されたワークフロー実行の結果", }, ]} /> ## Async/Awaitのフロー ワークフローが再開されると、実行はステップの実行関数内で `suspend()` 呼び出しの直後のポイントから続行されます。これにより、コード内で自然なフローが生まれます。 ```typescript // Step definition with suspend point const reviewStep = new LegacyStep({ id: "review", execute: async ({ context, suspend }) => { // First part of execution const initialAnalysis = analyzeData(context.inputData.data); if (initialAnalysis.needsReview) { // Suspend execution here await suspend({ analysis: initialAnalysis }); // This code runs after resume() is called // context.inputData now contains any data provided during resume return { reviewedData: enhanceWithFeedback( initialAnalysis, context.inputData.feedback, ), }; } return { reviewedData: initialAnalysis }; }, }); const { runId, resume, start } = workflow.createRun(); await start({ inputData: { data: "some data", }, }); // Later, resume the workflow const result = await resume({ runId: "workflow-123", stepId: "review", context: { // This data will be available in `context.inputData` feedback: "Looks good, but improve section 3", }, }); ``` ### 実行フロー 1. ワークフローは `review` ステップ内の `await suspend()` に到達するまで実行されます 2. ワークフローの状態が保存され、実行が一時停止します 3. 後で、新しいコンテキストデータとともに `run.resume()` が呼び出されます 4. 実行は `review` ステップ内の `suspend()` の直後のポイントから続行されます 5. 新しいコンテキストデータ(`feedback`)が `inputData` プロパティでステップに渡されます 6. ステップが完了し、その結果を返します 7. ワークフローは次のステップへと続行します ## エラー処理 resume関数は、いくつかの種類のエラーをスローする可能性があります。 ```typescript try { await run.resume({ runId, stepId: "stepTwo", context: newData, }); } catch (error) { if (error.message === "No snapshot found for workflow run") { // Handle missing workflow state } if (error.message === "Failed to parse workflow snapshot") { // Handle corrupted workflow state } } ``` ## 関連 - [サスペンドと再開](../../docs/workflows-legacy/suspend-and-resume.mdx) - [`suspend` リファレンス](./suspend.mdx) - [`watch` リファレンス](./watch.mdx) - [Workflow クラスリファレンス](./workflow.mdx) --- title: ".resumeWithEvent() メソッド | Mastra ドキュメント" description: "イベントデータを使用して一時停止中のワークフローを再開する resumeWithEvent メソッドのリファレンス。" --- # resumeWithEvent() [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/resumeWithEvent `resumeWithEvent()` メソッドは、ワークフローが待機している特定のイベントに対するデータを提供することで、ワークフローの実行を再開します。 ## 構文 ```typescript const run = workflow.createRun(); // After the workflow has started and suspended at an event step await run.resumeWithEvent(eventName: string, data: any): Promise ``` ## パラメーター | パラメーター | 型 | 説明 | | ----------- | ------ | ------------------------------------------------------------------------------------------------------ | | eventName | string | トリガーするイベントの名前。ワークフローの `events` 設定で定義されたイベント名と一致する必要があります。 | | data | any | 提供するイベントデータ。そのイベント用に定義されたスキーマに準拠している必要があります。 | ## 戻り値 Promise を返し、`WorkflowRunResult` オブジェクトで解決されます。このオブジェクトには以下が含まれます: - `results`: ワークフロー内の各ステップの結果ステータスと出力 - `activePaths`: アクティブなワークフローパスとその状態のマップ - `value`: ワークフローの現在の状態値 - その他のワークフロー実行メタデータ ## 説明 `resumeWithEvent()` メソッドは、`afterEvent()` メソッドによって作成されたイベントステップで一時停止しているワークフローを再開するために使用されます。このメソッドを呼び出すと、以下の処理が行われます。 1. 指定されたイベントデータが、そのイベント用に定義されたスキーマに適合しているか検証します 2. ストレージからワークフローのスナップショットを読み込みます 3. `resumedEvent` フィールドにイベントデータを設定してコンテキストを更新します 4. イベントステップから実行を再開します 5. その後のステップでワークフローの実行を継続します このメソッドは、Mastra のイベント駆動型ワークフロー機能の一部であり、外部イベントやユーザー操作に応答できるワークフローを作成することを可能にします。 ## 使用上の注意 - ワークフローは一時停止状態であり、特に `afterEvent(eventName)` で作成されたイベントステップで停止している必要があります - イベントデータは、ワークフロー設定でそのイベントのために定義されたスキーマに準拠している必要があります - ワークフローは、一時停止された地点から実行を再開します - ワークフローが一時停止していない場合や、別のステップで一時停止している場合、このメソッドはエラーをスローすることがあります - イベントデータは、`context.inputData.resumedEvent` を通じて後続のステップで利用可能になります ## 例 ### 基本的な使い方 ```typescript // Define and start a workflow const workflow = mastra.legacy_getWorkflow("approval-workflow"); const run = workflow.createRun(); // Start the workflow await run.start({ triggerData: { requestId: "req-123" } }); // Later, when the approval event occurs: const result = await run.resumeWithEvent("approval", { approved: true, approverName: "John Doe", comment: "Looks good to me!", }); console.log(result.results); ``` ### エラー処理を含めた例 ```typescript try { const result = await run.resumeWithEvent("paymentReceived", { amount: 100.5, transactionId: "tx-456", paymentMethod: "credit-card", }); console.log("Workflow resumed successfully:", result.results); } catch (error) { console.error("Failed to resume workflow with event:", error); // Handle error - could be invalid event data, workflow not suspended, etc. } ``` ### 監視と自動再開 ```typescript // Start a workflow const { start, watch, resumeWithEvent } = workflow.createRun(); // Watch for suspended event steps watch(async ({ activePaths }) => { const isApprovalEventSuspended = activePaths.get("__approval_event")?.status === "suspended"; // Check if suspended at the approval event step if (isApprovalEventSuspended) { console.log("Workflow waiting for approval"); // In a real scenario, you would wait for the actual event // Here we're simulating with a timeout setTimeout(async () => { try { await resumeWithEvent("approval", { approved: true, approverName: "Auto Approver", }); } catch (error) { console.error("Failed to auto-resume workflow:", error); } }, 5000); // Wait 5 seconds before auto-approving } }); // Start the workflow await start({ triggerData: { requestId: "auto-123" } }); ``` ## 関連項目 - [イベント駆動型ワークフロー](./events.mdx) - [afterEvent()](./afterEvent.mdx) - [一時停止と再開](../../docs/workflows-legacy/suspend-and-resume.mdx) - [resume()](./resume.mdx) - [watch()](./watch.mdx) --- title: "リファレンス: スナップショット | ワークフロー状態の永続化(レガシー) | Mastra ドキュメント" description: "Mastra におけるスナップショットの技術リファレンス - サスペンドおよびレジューム機能を可能にするシリアライズされたワークフロー状態" --- # スナップショット [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/snapshots Mastraにおいて、スナップショットとは、ある特定の時点でのワークフローの完全な実行状態をシリアライズ可能な形で表現したものです。スナップショットは、ワークフローを中断したまさにその場所から再開するために必要なすべての情報を記録します。これには以下が含まれます: - ワークフロー内の各ステップの現在の状態 - 完了したステップの出力 - ワークフロー内でたどった実行経路 - 一時停止中のステップとそのメタデータ - 各ステップの残りのリトライ回数 - 実行を再開するために必要な追加のコンテキストデータ スナップショットは、ワークフローが一時停止されるたびにMastraによって自動的に作成・管理され、設定されたストレージシステムに永続化されます。 ## サスペンドとレジュームにおけるスナップショットの役割 スナップショットは、Mastra のサスペンドおよびレジューム機能を実現するための主要な仕組みです。ワークフローのステップで `await suspend()` が呼び出されると: 1. ワークフローの実行はその時点で一時停止されます 2. ワークフローの現在の状態がスナップショットとして記録されます 3. スナップショットはストレージに永続化されます 4. ワークフローステップは「サスペンド中」として `'suspended'` ステータスでマークされます 5. 後で、サスペンドされたステップに対して `resume()` が呼び出されると、スナップショットが取得されます 6. ワークフローの実行は中断された場所から正確に再開されます この仕組みにより、人間が介在するワークフローの実装や、レート制限への対応、外部リソースの待機、長期間の一時停止が必要な複雑な分岐ワークフローの実装が強力に可能となります。 ## スナップショットの構造 Mastra ワークフローのスナップショットは、いくつかの主要なコンポーネントで構成されています。 ```typescript export interface LegacyWorkflowRunState { // Core state info value: Record; // Current state machine value context: { // Workflow context steps: Record< string, { // Step execution results status: "success" | "failed" | "suspended" | "waiting" | "skipped"; payload?: any; // Step-specific data error?: string; // Error info if failed } >; triggerData: Record; // Initial trigger data attempts: Record; // Remaining retry attempts inputData: Record; // Initial input data }; activePaths: Array<{ // Currently active execution paths stepPath: string[]; stepId: string; status: string; }>; // Metadata runId: string; // Unique run identifier timestamp: number; // Time snapshot was created // For nested workflows and suspended steps childStates?: Record; // Child workflow states suspendedSteps?: Record; // Mapping of suspended steps } ``` ## スナップショットの保存と取得方法 Mastraは、設定されたストレージシステムにスナップショットを永続化します。デフォルトでは、スナップショットはLibSQLデータベースに保存されますが、Upstashなど他のストレージプロバイダーを使用するように設定することも可能です。 スナップショットは`workflow_snapshots`テーブルに保存され、libsqlを使用している場合は関連する実行の`run_id`によって一意に識別されます。 永続化レイヤーを利用することで、スナップショットはワークフローの実行をまたいで保持され、高度な人間参加型の機能を実現できます。 [libsqlストレージ](../storage/libsql.mdx)および[upstashストレージ](../storage/upstash.mdx)の詳細はこちらをご覧ください。 ### スナップショットの保存 ワークフローが一時停止されると、Mastraは以下の手順でワークフロースナップショットを自動的に永続化します。 1. ステップ実行中に`suspend()`関数がスナップショット処理をトリガーします 2. `WorkflowInstance.suspend()`メソッドが一時停止したマシンを記録します 3. `persistWorkflowSnapshot()`が呼び出され、現在の状態が保存されます 4. スナップショットはシリアライズされ、設定されたデータベースの`workflow_snapshots`テーブルに保存されます 5. ストレージレコードにはワークフロー名、実行ID、シリアライズされたスナップショットが含まれます ### スナップショットの取得 ワークフローが再開されると、Mastraは以下の手順で永続化されたスナップショットを取得します。 1. 特定のステップIDで`resume()`メソッドが呼び出されます 2. `loadWorkflowSnapshot()`を使ってストレージからスナップショットが読み込まれます 3. スナップショットが解析され、再開の準備がされます 4. ワークフローの実行がスナップショットの状態で再構築されます 5. 一時停止していたステップが再開され、実行が続行されます ## スナップショットのストレージオプション Mastra は、スナップショットを永続化するための複数のストレージオプションを提供しています。 `storage` インスタンスは `Mastra` クラスで設定され、`Mastra` インスタンスに登録されたすべてのワークフローのためのスナップショット永続化レイヤーとして使用されます。 つまり、同じ `Mastra` インスタンスに登録されたすべてのワークフローでストレージが共有されます。 ### LibSQL(デフォルト) デフォルトのストレージオプションは LibSQL であり、SQLite 互換のデータベースです: ```typescript import { Mastra } from "@mastra/core/mastra"; import { DefaultStorage } from "@mastra/core/storage/libsql"; const mastra = new Mastra({ storage: new DefaultStorage({ config: { url: "file:storage.db", // ローカルファイルベースのデータベース // 本番環境の場合: // url: process.env.DATABASE_URL, // authToken: process.env.DATABASE_AUTH_TOKEN, }, }), legacy_workflows: { weatherWorkflow, travelWorkflow, }, }); ``` ### Upstash(Redis 互換) サーバーレス環境向け: ```typescript import { Mastra } from "@mastra/core/mastra"; import { UpstashStore } from "@mastra/upstash"; const mastra = new Mastra({ storage: new UpstashStore({ url: process.env.UPSTASH_URL, token: process.env.UPSTASH_TOKEN, }), workflows: { weatherWorkflow, travelWorkflow, }, }); ``` ## スナップショット作業のベストプラクティス 1. **シリアライズ可能であることを確認する**: スナップショットに含める必要があるデータは、必ずシリアライズ可能(JSONに変換可能)でなければなりません。 2. **スナップショットのサイズを最小限に抑える**: 大きなデータオブジェクトをワークフローコンテキストに直接保存するのは避けましょう。代わりにIDなどの参照を保存し、必要なときにデータを取得してください。 3. **レジュームコンテキストの取り扱いに注意する**: ワークフローを再開する際、どのコンテキストを提供するか慎重に検討してください。これは既存のスナップショットデータとマージされます。 4. **適切なモニタリングを設定する**: 特に長時間実行されるワークフローについては、中断されたワークフローのモニタリングを実装し、確実に再開されるようにしましょう。 5. **ストレージのスケーリングを検討する**: 多数の中断されたワークフローがあるアプリケーションの場合、ストレージソリューションが適切にスケールされていることを確認してください。 ## 高度なスナップショットパターン ### カスタムスナップショットメタデータ ワークフローをサスペンドする際に、再開時に役立つカスタムメタデータを含めることができます。 ```typescript await suspend({ reason: "Waiting for customer approval", requiredApprovers: ["manager", "finance"], requestedBy: currentUser, urgency: "high", expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), }); ``` このメタデータはスナップショットと一緒に保存され、再開時に利用できます。 ### 条件付き再開 再開時にサスペンド時のペイロードに基づいた条件付きロジックを実装できます。 ```typescript run.watch(async ({ activePaths }) => { const isApprovalStepSuspended = activePaths.get("approval")?.status === "suspended"; if (isApprovalStepSuspended) { const payload = activePaths.get("approval")?.suspendPayload; if (payload.urgency === "high" && currentUser.role === "manager") { await resume({ stepId: "approval", context: { approved: true, approver: currentUser.id }, }); } } }); ``` ## 関連 - [Suspend 関数リファレンス](./suspend.mdx) - [Resume 関数リファレンス](./resume.mdx) - [Watch 関数リファレンス](./watch.mdx) - [Suspend と Resume ガイド](../../docs/workflows-legacy/suspend-and-resume.mdx) --- title: "リファレンス: start() | ワークフローの実行(レガシー) | Mastra ドキュメント" description: "ワークフロー内の `start()` メソッドのドキュメント。ワークフローの実行を開始します。" --- # start() [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/start start関数は、ワークフローの実行を開始します。定義されたワークフローの順序に従ってすべてのステップを処理し、並列実行、分岐ロジック、ステップ間の依存関係を管理します。 ## 使用方法 ```typescript copy showLineNumbers const { runId, start } = workflow.createRun(); const result = await start({ triggerData: { inputValue: 42 }, }); ``` ## パラメーター ### config ", description: "ワークフローの triggerSchema に一致する初期データ", isOptional: false, }, ]} /> ## 戻り値 ", description: "完了したすべてのワークフローステップからの統合出力", }, { name: "status", type: "'completed' | 'error' | 'suspended'", description: "ワークフロー実行の最終ステータス", }, ]} /> ## エラー処理 start関数は、いくつかの種類のバリデーションエラーをスローする可能性があります。 ```typescript copy showLineNumbers try { const result = await start({ triggerData: data }); } catch (error) { if (error instanceof ValidationError) { console.log(error.type); // 'circular_dependency' | 'no_terminal_path' | 'unreachable_step' console.log(error.details); } } ``` ## 関連 - [例:ワークフローの作成](../../examples/workflows_legacy/creating-a-workflow.mdx) - [例:一時停止と再開](../../examples/workflows_legacy/suspend-and-resume.mdx) - [createRun リファレンス](./createRun.mdx) - [Workflow クラスリファレンス](./workflow.mdx) - [Step クラスリファレンス](./step-class.mdx) ``` ``` --- title: "リファレンス: Step | ワークフローの構築(レガシー) | Mastra ドキュメント" description: ワークフロー内の個々の作業単位を定義する Step クラスのドキュメント。 --- # Step [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/step-class Stepクラスは、ワークフロー内の個々の作業単位を定義し、実行ロジック、データ検証、および入力/出力の処理をカプセル化します。 ## 使い方 ```typescript const processOrder = new LegacyStep({ id: "processOrder", inputSchema: z.object({ orderId: z.string(), userId: z.string(), }), outputSchema: z.object({ status: z.string(), orderId: z.string(), }), execute: async ({ context, runId }) => { return { status: "processed", orderId: context.orderId, }; }, }); ``` ## コンストラクタのパラメータ ", description: "変数とマージされる静的データ", required: false, }, { name: "execute", type: "(params: ExecuteParams) => Promise", description: "ステップのロジックを含む非同期関数", required: true, }, ]} /> ### ExecuteParams Promise", description: "ステップの実行を一時停止する関数", }, { name: "mastra", type: "Mastra", description: "Mastraインスタンスへのアクセス", }, ]} /> ## 関連 - [ワークフローリファレンス](./workflow.mdx) - [ステップ設定ガイド](../../docs/workflows-legacy/steps.mdx) - [制御フローガイド](../../docs/workflows-legacy/control-flow.mdx) --- title: "リファレンス: StepCondition | ワークフローの構築(レガシー) | Mastra" description: ワークフロー内のステップ条件クラスのドキュメント。前のステップの出力やトリガーデータに基づいて、ステップを実行するかどうかを決定します。 --- # StepCondition [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/step-condition 条件は、前のステップの出力やトリガーデータに基づいてステップを実行するかどうかを決定します。 ## 使用方法 条件を指定する方法は3つあります:関数、クエリオブジェクト、シンプルなパス比較です。 ### 1. 関数による条件 ```typescript copy showLineNumbers workflow.step(processOrder, { when: async ({ context }) => { const auth = context?.getStepResult<{ status: string }>("auth"); return auth?.status === "authenticated"; }, }); ``` ### 2. クエリオブジェクト ```typescript copy showLineNumbers workflow.step(processOrder, { when: { ref: { step: "auth", path: "status" }, query: { $eq: "authenticated" }, }, }); ``` ### 3. シンプルなパス比較 ```typescript copy showLineNumbers workflow.step(processOrder, { when: { "auth.status": "authenticated", }, }); ``` 条件のタイプに応じて、ワークフローランナーはこれらのいずれかのタイプに条件をマッチさせようとします。 1. シンプルなパス条件(キーにドットが含まれている場合) 2. ベース/クエリ条件('ref' プロパティがある場合) 3. 関数条件(非同期関数の場合) ## StepCondition ", description: "sift演算子($eq, $gt など)を使用したMongoDBスタイルのクエリ", isOptional: false, }, ]} /> ## クエリ Queryオブジェクトは、前のステップやトリガーデータの値を比較するためのMongoDBスタイルのクエリ演算子を提供します。`$eq`、`$gt`、`$lt`などの基本的な比較演算子や、`$in`、`$nin`のような配列演算子をサポートしており、and/or演算子と組み合わせて複雑な条件を作成できます。 このクエリ構文により、ステップを実行するかどうかを判断するための可読性の高い条件ロジックを記述できます。 ## 関連 - [Step Options リファレンス](./step-options.mdx) - [Step Function リファレンス](./step-function.mdx) - [Control Flow ガイド](../../docs/workflows-legacy/control-flow.mdx) --- title: "リファレンス: Workflow.step() | Workflows (レガシー) | Mastra Docs" description: ワークフロー内の `.step()` メソッドのドキュメント。ワークフローに新しいステップを追加します。 --- # Workflow.step() [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/step-function `.step()` メソッドは、ワークフローに新しいステップを追加し、オプションでその変数や実行条件を設定します。 ## 使い方 ```typescript workflow.step({ id: "stepTwo", outputSchema: z.object({ result: z.number(), }), execute: async ({ context }) => { return { result: 42 }; }, }); ``` ## パラメーター ### StepDefinition Promise", description: "ステップのロジックを含む関数", isOptional: false, }, ]} /> ### StepOptions ", description: "変数名とその参照元のマッピング", isOptional: true, }, { name: "when", type: "StepCondition", description: "ステップを実行するために満たす必要がある条件", isOptional: true, }, ]} /> ## 関連 - [ステップインスタンスの基本的な使い方](../../docs/workflows-legacy/steps.mdx) - [Step クラスリファレンス](./step-class.mdx) - [Workflow クラスリファレンス](./workflow.mdx) - [制御フローガイド](../../docs/workflows-legacy/control-flow.mdx) --- title: "リファレンス: StepOptions | ワークフローの構築(レガシー) | Mastra ドキュメント" description: ワークフロー内のステップオプションに関するドキュメント。これらは変数のマッピング、実行条件、その他のランタイム動作を制御します。 --- # StepOptions [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/step-options ワークフローステップの変数マッピング、実行条件、その他のランタイム動作を制御するための設定オプションです。 ## 使用方法 ```typescript workflow.step(processOrder, { variables: { orderId: { step: "trigger", path: "id" }, userId: { step: "auth", path: "user.id" }, }, when: { ref: { step: "auth", path: "status" }, query: { $eq: "authenticated" }, }, }); ``` ## プロパティ ", description: "ステップ入力変数を他のステップからの値にマッピングします", isOptional: true, }, { name: "when", type: "StepCondition", description: "ステップを実行するために満たす必要がある条件", isOptional: true, }, ]} /> ### VariableRef ## 関連 - [パス比較](../../docs/workflows-legacy/control-flow.mdx) - [ステップ関数リファレンス](./step-function.mdx) - [ステップクラスリファレンス](./step-class.mdx) - [ワークフロークラスリファレンス](./workflow.mdx) - [制御フローガイド](../../docs/workflows-legacy/control-flow.mdx) --- title: "ステップのリトライ | エラー処理 | Mastra ドキュメント" description: "Mastra ワークフローで失敗したステップを自動的に再試行し、設定可能なリトライポリシーを利用できます。" --- # ステップのリトライ [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/step-retries Mastra は、ワークフローステップで発生する一時的な障害に対応するための組み込みリトライ機構を提供しています。これにより、ワークフローは一時的な問題が発生しても手動での対応を必要とせず、スムーズに回復することができます。 ## 概要 ワークフロー内のステップが失敗(例外をスロー)した場合、Mastraは設定可能なリトライポリシーに基づいて自動的にステップの実行を再試行できます。これは以下のような状況に対応するのに役立ちます: - ネットワーク接続の問題 - サービスの利用不可 - レート制限 - 一時的なリソース制約 - その他の一時的な障害 ## デフォルトの動作 デフォルトでは、ステップは失敗しても再試行されません。これは次のことを意味します: - ステップは一度だけ実行されます - 失敗した場合、直ちにそのステップが失敗としてマークされます - ワークフローは、失敗したステップに依存しない後続のステップを引き続き実行します ## 設定オプション リトライは2つのレベルで設定できます。 ### 1. ワークフローレベルの設定 ワークフロー内のすべてのステップに対して、デフォルトのリトライ設定を指定できます。 ```typescript const workflow = new LegacyWorkflow({ name: "my-workflow", retryConfig: { attempts: 3, // Number of retries (in addition to the initial attempt) delay: 1000, // Delay between retries in milliseconds }, }); ``` ### 2. ステップレベルの設定 個々のステップごとにリトライ設定を行うこともでき、その場合はそのステップに限りワークフローレベルの設定を上書きします。 ```typescript const fetchDataStep = new LegacyStep({ id: "fetchData", execute: async () => { // Fetch data from external API }, retryConfig: { attempts: 5, // This step will retry up to 5 times delay: 2000, // With a 2-second delay between retries }, }); ``` ## リトライパラメータ `retryConfig` オブジェクトは、以下のパラメータをサポートしています。 | パラメータ | 型 | デフォルト | 説明 | | ------------ | ------ | ---------- | ------------------------------------------------------------ | | `attempts` | number | 0 | リトライ回数(初回試行に加えて行う回数) | | `delay` | number | 1000 | リトライ間で待機するミリ秒数 | ## リトライの仕組み ステップが失敗した場合、Mastra のリトライ機構は以下のように動作します。 1. ステップにリトライ回数が残っているかを確認します 2. 回数が残っている場合: - 試行回数をデクリメントします - ステップを「待機中」状態に遷移させます - 設定された遅延時間だけ待機します - ステップの実行を再試行します 3. 回数が残っていない、またはすべての試行が終了した場合: - ステップを「失敗」としてマークします - (失敗したステップに依存しない)他のステップのワークフロー実行を継続します リトライ試行中、ワークフローの実行はアクティブなままですが、リトライ対象の特定のステップのみ一時停止されます。 ## 例 ### 基本的なリトライの例 ```typescript import { LegacyWorkflow, LegacyStep } from "@mastra/core/workflows/legacy"; // Define a step that might fail const unreliableApiStep = new LegacyStep({ id: "callUnreliableApi", execute: async () => { // Simulate an API call that might fail const random = Math.random(); if (random < 0.7) { throw new Error("API call failed"); } return { data: "API response data" }; }, retryConfig: { attempts: 3, // Retry up to 3 times delay: 2000, // Wait 2 seconds between attempts }, }); // Create a workflow with the unreliable step const workflow = new LegacyWorkflow({ name: "retry-demo-workflow", }); workflow.step(unreliableApiStep).then(processResultStep).commit(); ``` ### ステップごとの上書きによるワークフロー全体のリトライ ```typescript import { LegacyWorkflow, LegacyStep } from "@mastra/core/workflows/legacy"; // Create a workflow with default retry configuration const workflow = new LegacyWorkflow({ name: "multi-retry-workflow", retryConfig: { attempts: 2, // All steps will retry twice by default delay: 1000, // With a 1-second delay }, }); // This step uses the workflow's default retry configuration const standardStep = new LegacyStep({ id: "standardStep", execute: async () => { // Some operation that might fail }, }); // This step overrides the workflow's retry configuration const criticalStep = new LegacyStep({ id: "criticalStep", execute: async () => { // Critical operation that needs more retry attempts }, retryConfig: { attempts: 5, // Override with 5 retry attempts delay: 5000, // And a longer 5-second delay }, }); // This step disables retries const noRetryStep = new LegacyStep({ id: "noRetryStep", execute: async () => { // Operation that should not retry }, retryConfig: { attempts: 0, // Explicitly disable retries }, }); workflow.step(standardStep).then(criticalStep).then(noRetryStep).commit(); ``` ## リトライの監視 リトライの試行はログで監視できます。Mastra はリトライに関連するイベントを `debug` レベルで記録します: ``` [DEBUG] Step fetchData failed (runId: abc-123) [DEBUG] Attempt count for step fetchData: 2 remaining attempts (runId: abc-123) [DEBUG] Step fetchData waiting (runId: abc-123) [DEBUG] Step fetchData finished waiting (runId: abc-123) [DEBUG] Step fetchData pending (runId: abc-123) ``` ## ベストプラクティス 1. **一時的な障害に対してリトライを使用する**: 一時的な障害が発生する可能性のある操作にのみリトライを設定してください。決定的なエラー(バリデーションエラーなど)の場合、リトライは効果がありません。 2. **適切な遅延を設定する**: 外部API呼び出しの場合は、サービスが復旧する時間を確保するために、より長い遅延を検討してください。 3. **リトライ回数を制限する**: 非常に高いリトライ回数を設定しないでください。障害発生時にワークフローが過度に長時間実行される原因となります。 4. **冪等な操作を実装する**: ステップの `execute` 関数が冪等(副作用なく複数回呼び出せる)であることを確認してください。リトライされる可能性があるためです。 5. **バックオフ戦略を検討する**: より高度なシナリオでは、レート制限される可能性のある操作に対して、ステップのロジックで指数バックオフを実装することを検討してください。 ## 関連 - [Step クラスリファレンス](./step-class.mdx) - [ワークフローの設定](./workflow.mdx) - [ワークフローにおけるエラー処理](../../docs/workflows-legacy/error-handling.mdx) --- title: "リファレンス: suspend() | 制御フロー | Mastra ドキュメント" description: "Mastra ワークフローにおける suspend 関数のドキュメント。実行を一時停止し、再開されるまで待機します。" --- # suspend() [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/suspend ワークフローの実行を現在のステップで一時停止し、明示的に再開されるまで停止します。ワークフローの状態は保存され、後で続行できます。 ## 使用例 ```typescript const approvalStep = new LegacyStep({ id: "needsApproval", execute: async ({ context, suspend }) => { if (context.steps.amount > 1000) { await suspend(); } return { approved: true }; }, }); ``` ## パラメーター ", description: "サスペンド状態と一緒に保存するための任意のデータ", isOptional: true, }, ]} /> ## 戻り値 ", type: "Promise", description: "ワークフローが正常に一時停止されたときに解決されます", }, ]} /> ## 追加の例 メタデータ付きのサスペンド: ```typescript const reviewStep = new LegacyStep({ id: "review", execute: async ({ context, suspend }) => { await suspend({ reason: "Needs manager approval", requestedBy: context.user, }); return { reviewed: true }; }, }); ``` ### 関連 - [サスペンドと再開ワークフロー](../../docs/workflows-legacy/suspend-and-resume.mdx) - [.resume()](./resume.mdx) - [.watch()](./watch.mdx) --- title: "リファレンス: Workflow.then() | ワークフローの構築(レガシー) | Mastra ドキュメント" description: ワークフロー内の `.then()` メソッドのドキュメント。ステップ間に順次依存関係を作成します。 --- # Workflow.then() [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/then `.then()` メソッドは、ワークフローの各ステップ間に順次的な依存関係を作り、ステップが特定の順序で実行されることを保証します。 ## 使用方法 ```typescript workflow.step(stepOne).then(stepTwo).then(stepThree); ``` ## パラメーター ## 戻り値 ## バリデーション `then` を使用する場合: - 前のステップがワークフロー内に存在している必要があります - ステップ同士で循環参照を作成してはいけません - 各ステップはシーケンシャルチェーン内で一度だけ登場できます ## エラー処理 ```typescript try { workflow .step(stepA) .then(stepB) .then(stepA) // Will throw error - circular dependency .commit(); } catch (error) { if (error instanceof ValidationError) { console.log(error.type); // 'circular_dependency' console.log(error.details); } } ``` ## 関連 - [step リファレンス](./step-class.mdx) - [after リファレンス](./after.mdx) - [順次ステップの例](../../examples/workflows_legacy/sequential-steps.mdx) - [制御フローガイド](../../docs/workflows-legacy/control-flow.mdx) --- title: "リファレンス: Workflow.until() | ワークフロー内のループ処理(レガシー) | Mastra ドキュメント" description: "Mastra ワークフローにおける `.until()` メソッドのドキュメント。指定した条件が真になるまでステップを繰り返します。" --- # Workflow.until() [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/until `.until()` メソッドは、指定した条件が真になるまでステップを繰り返します。これにより、条件が満たされるまで指定したステップを実行し続けるループが作成されます。 ## 使い方 ```typescript workflow.step(incrementStep).until(condition, incrementStep).then(finalStep); ``` ## パラメーター ## 条件タイプ ### 関数条件 真偽値を返す関数を使用できます: ```typescript workflow .step(incrementStep) .until(async ({ context }) => { const result = context.getStepResult<{ value: number }>("increment"); return (result?.value ?? 0) >= 10; // Stop when value reaches or exceeds 10 }, incrementStep) .then(finalStep); ``` ### 参照条件 比較演算子を使った参照ベースの条件を使用できます: ```typescript workflow .step(incrementStep) .until( { ref: { step: incrementStep, path: "value" }, query: { $gte: 10 }, // Stop when value is greater than or equal to 10 }, incrementStep, ) .then(finalStep); ``` ## 比較演算子 参照ベースの条件を使用する場合、次の比較演算子を使用できます。 | 演算子 | 説明 | 例 | | -------- | ------------------------ | -------------- | | `$eq` | 等しい | `{ $eq: 10 }` | | `$ne` | 等しくない | `{ $ne: 0 }` | | `$gt` | より大きい | `{ $gt: 5 }` | | `$gte` | 以上 | `{ $gte: 10 }` | | `$lt` | より小さい | `{ $lt: 20 }` | | `$lte` | 以下 | `{ $lte: 15 }` | ## 戻り値 ## 例 ```typescript import { LegacyWorkflow, LegacyStep } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Create a step that increments a counter const incrementStep = new LegacyStep({ id: "increment", description: "Increments the counter by 1", outputSchema: z.object({ value: z.number(), }), execute: async ({ context }) => { // Get current value from previous execution or start at 0 const currentValue = context.getStepResult<{ value: number }>("increment")?.value || context.getStepResult<{ startValue: number }>("trigger")?.startValue || 0; // Increment the value const value = currentValue + 1; console.log(`Incrementing to ${value}`); return { value }; }, }); // Create a final step const finalStep = new LegacyStep({ id: "final", description: "Final step after loop completes", execute: async ({ context }) => { const finalValue = context.getStepResult<{ value: number }>( "increment", )?.value; console.log(`Loop completed with final value: ${finalValue}`); return { finalValue }; }, }); // Create the workflow const counterWorkflow = new LegacyWorkflow({ name: "counter-workflow", triggerSchema: z.object({ startValue: z.number(), targetValue: z.number(), }), }); // Configure the workflow with an until loop counterWorkflow .step(incrementStep) .until(async ({ context }) => { const targetValue = context.triggerData.targetValue; const currentValue = context.getStepResult<{ value: number }>("increment")?.value ?? 0; return currentValue >= targetValue; }, incrementStep) .then(finalStep) .commit(); // Execute the workflow const run = counterWorkflow.createRun(); const result = await run.start({ triggerData: { startValue: 0, targetValue: 5 }, }); // Will increment from 0 to 5, then stop and execute finalStep ``` ## 関連 - [.while()](./while.mdx) - 条件が真の間ループする - [制御フローガイド](../../docs/workflows-legacy/control-flow.mdx) - [Workflow クラスリファレンス](./workflow.mdx) --- title: "リファレンス: run.watch() | ワークフロー(レガシー) | Mastra ドキュメント" description: ワークフロー内の `.watch()` メソッドのドキュメント。ワークフロー実行のステータスを監視します。 --- # run.watch() [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/watch `.watch()` 関数は mastra run の状態変化を購読し、実行の進行状況を監視したり、状態の更新に反応したりすることができます。 ## 使用例 ```typescript import { LegacyWorkflow } from "@mastra/core/workflows/legacy"; const workflow = new LegacyWorkflow({ name: "document-processor", }); const run = workflow.createRun(); // Subscribe to state changes const unsubscribe = run.watch(({ results, activePaths }) => { console.log("Results:", results); console.log("Active paths:", activePaths); }); // Run the workflow await run.start({ input: { text: "Process this document" }, }); // Stop watching unsubscribe(); ``` ## パラメーター void", description: "ワークフローの状態が変化するたびに呼び出される関数", isOptional: false, }, ]} /> ### LegacyWorkflowState のプロパティ ", description: "完了したワークフローステップからの出力", isOptional: false, }, { name: "activePaths", type: "Map", description: "各ステップの現在のステータス", isOptional: false, }, { name: "runId", type: "string", description: "ワークフロー実行のID", isOptional: false, }, { name: "timestamp", type: "number", description: "ワークフロー実行のタイムスタンプ", isOptional: false, }, ]} /> ## 戻り値 void", description: "ワークフローの状態変化の監視を停止する関数", }, ]} /> ## 追加の例 特定のステップの完了を監視する: ```typescript run.watch(({ results, activePaths }) => { if (activePaths.get("processDocument")?.status === "completed") { console.log( "Document processing output:", results["processDocument"].output, ); } }); ``` エラー処理: ```typescript run.watch(({ results, activePaths }) => { if (activePaths.get("processDocument")?.status === "failed") { console.error( "Document processing failed:", results["processDocument"].error, ); // Implement error recovery logic } }); ``` ### 関連 - [ワークフロー作成](./createRun.mdx) - [ステップ設定](./step-class.mdx) --- title: "リファレンス: Workflow.while() | ワークフロー内のループ処理(レガシー) | Mastra ドキュメント" description: "Mastra ワークフローにおける `.while()` メソッドのドキュメント。指定した条件が真である限り、ステップを繰り返します。" --- # Workflow.while() [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/while `.while()` メソッドは、指定した条件が真である限り、ステップを繰り返します。これにより、条件が偽になるまで指定したステップを実行し続けるループが作成されます。 ## 使い方 ```typescript workflow.step(incrementStep).while(condition, incrementStep).then(finalStep); ``` ## パラメーター ## 条件タイプ ### 関数条件 真偽値を返す関数を使用できます: ```typescript workflow .step(incrementStep) .while(async ({ context }) => { const result = context.getStepResult<{ value: number }>("increment"); return (result?.value ?? 0) < 10; // Continue as long as value is less than 10 }, incrementStep) .then(finalStep); ``` ### 参照条件 比較演算子を使った参照ベースの条件を使用できます: ```typescript workflow .step(incrementStep) .while( { ref: { step: incrementStep, path: "value" }, query: { $lt: 10 }, // Continue as long as value is less than 10 }, incrementStep, ) .then(finalStep); ``` ## 比較演算子 参照ベースの条件を使用する場合、次の比較演算子を使用できます。 | 演算子 | 説明 | 例 | | -------- | ------------------------ | -------------- | | `$eq` | 等しい | `{ $eq: 10 }` | | `$ne` | 等しくない | `{ $ne: 0 }` | | `$gt` | より大きい | `{ $gt: 5 }` | | `$gte` | 以上 | `{ $gte: 10 }` | | `$lt` | より小さい | `{ $lt: 20 }` | | `$lte` | 以下 | `{ $lte: 15 }` | ## 戻り値 ## 例 ```typescript import { LegacyWorkflow, LegacyStep } from "@mastra/core/workflows/legacy"; import { z } from "zod"; // Create a step that increments a counter const incrementStep = new LegacyStep({ id: "increment", description: "Increments the counter by 1", outputSchema: z.object({ value: z.number(), }), execute: async ({ context }) => { // Get current value from previous execution or start at 0 const currentValue = context.getStepResult<{ value: number }>("increment")?.value || context.getStepResult<{ startValue: number }>("trigger")?.startValue || 0; // Increment the value const value = currentValue + 1; console.log(`Incrementing to ${value}`); return { value }; }, }); // Create a final step const finalStep = new LegacyStep({ id: "final", description: "Final step after loop completes", execute: async ({ context }) => { const finalValue = context.getStepResult<{ value: number }>( "increment", )?.value; console.log(`Loop completed with final value: ${finalValue}`); return { finalValue }; }, }); // Create the workflow const counterWorkflow = new LegacyWorkflow({ name: "counter-workflow", triggerSchema: z.object({ startValue: z.number(), targetValue: z.number(), }), }); // Configure the workflow with a while loop counterWorkflow .step(incrementStep) .while(async ({ context }) => { const targetValue = context.triggerData.targetValue; const currentValue = context.getStepResult<{ value: number }>("increment")?.value ?? 0; return currentValue < targetValue; }, incrementStep) .then(finalStep) .commit(); // Execute the workflow const run = counterWorkflow.createRun(); const result = await run.start({ triggerData: { startValue: 0, targetValue: 5 }, }); // Will increment from 0 to 4, then stop and execute finalStep ``` ## 関連 - [.until()](./until.mdx) - 条件が真になるまでループする - [制御フローガイド](../../docs/workflows-legacy/control-flow.mdx) - [Workflow クラスリファレンス](./workflow.mdx) --- title: "リファレンス: Workflow クラス | ワークフローの構築(レガシー) | Mastra ドキュメント" description: Mastra の Workflow クラスのドキュメント。条件分岐やデータ検証を伴う複雑な操作のシーケンスのための状態機械を作成できます。 --- # Workflow クラス [JA] Source: https://mastra.ai/ja/reference/legacyWorkflows/workflow Workflow クラスは、条件分岐やデータ検証を含む複雑な一連の操作のためのステートマシンを作成できるようにします。 ```ts copy import { LegacyWorkflow } from "@mastra/core/workflows/legacy"; const workflow = new LegacyWorkflow({ name: "my-workflow" }); ``` ## APIリファレンス ### コンストラクタ ", isOptional: true, description: "ワークフロー実行の詳細を記録するためのオプションのロガーインスタンス", }, { name: "steps", type: "Step[]", description: "ワークフローに含めるステップの配列", }, { name: "triggerSchema", type: "z.Schema", description: "ワークフロートリガーデータを検証するためのオプションのスキーマ", }, ]} /> ### コアメソッド #### `step()` [Step](./step-class.mdx) をワークフローに追加し、他のステップへの遷移も含めます。チェーンのためにワークフローインスタンスを返します。[ステップの詳細はこちら](./step-class.mdx)。 #### `commit()` ワークフローの設定を検証し、確定します。すべてのステップを追加した後に呼び出す必要があります。 #### `execute()` オプションのトリガーデータとともにワークフローを実行します。[トリガースキーマ](./workflow.mdx#trigger-schemas)に基づいて型付けされます。 ## トリガースキーマ トリガースキーマは、Zod を使用してワークフローに渡される初期データを検証します。 ```ts showLineNumbers copy const workflow = new LegacyWorkflow({ name: "order-process", triggerSchema: z.object({ orderId: z.string(), customer: z.object({ id: z.string(), email: z.string().email(), }), }), }); ``` このスキーマは以下を行います: - `execute()` に渡されるデータを検証します - ワークフロー入力のための TypeScript 型を提供します ## バリデーション ワークフローのバリデーションは、主に2つのタイミングで行われます。 ### 1. コミット時 `.commit()` を呼び出すと、ワークフローは次の点をバリデートします: ```ts showLineNumbers copy workflow .step('step1', {...}) .step('step2', {...}) .commit(); // ワークフロー構造のバリデーション ``` - ステップ間の循環依存 - 終端パス(すべてのパスが終了している必要があります) - 到達不能なステップ - 存在しないステップへの変数参照 - ステップIDの重複 ### 2. 実行時 `start()` を呼び出すと、次の点をバリデートします: ```ts showLineNumbers copy const { runId, start } = workflow.createRun(); // トリガーデータがスキーマに合致しているかをバリデート await start({ triggerData: { orderId: "123", customer: { id: "cust_123", email: "invalid-email", // バリデーションに失敗します }, }, }); ``` - トリガーデータがトリガースキーマに合致しているか - 各ステップの入力データがその inputSchema に合致しているか - 参照されているステップ出力内に変数パスが存在するか - 必須変数が存在しているか ## ワークフローのステータス ワークフローのステータスは、その現在の実行状態を示します。考えられる値は以下の通りです。 ### 例:異なるステータスの処理 ```typescript showLineNumbers copy const { runId, start, watch } = workflow.createRun(); watch(async ({ status }) => { switch (status) { case "SUSPENDED": // Handle suspended state break; case "COMPLETED": // Process results break; case "FAILED": // Handle error state break; } }); await start({ triggerData: data }); ``` ## エラー処理 ```ts showLineNumbers copy try { const { runId, start, watch, resume } = workflow.createRun(); await start({ triggerData: data }); } catch (error) { if (error instanceof ValidationError) { // Handle validation errors console.log(error.type); // 'circular_dependency' | 'no_terminal_path' | 'unreachable_step' console.log(error.details); // { stepId?: string, path?: string[] } } } ``` ## ステップ間でのコンテキストの受け渡し 各ステップは、コンテキストオブジェクトを通じてワークフロー内の前のステップからデータにアクセスできます。各ステップは、実行されたすべての前のステップから蓄積されたコンテキストを受け取ります。 ```typescript showLineNumbers copy workflow .step({ id: "getData", execute: async ({ context }) => { return { data: { id: "123", value: "example" }, }; }, }) .step({ id: "processData", execute: async ({ context }) => { // Access data from previous step through context.steps const previousData = context.steps.getData.output.data; // Process previousData.id and previousData.value }, }); ``` コンテキストオブジェクトは以下の特徴があります: - `context.steps` 内のすべての完了したステップの結果を含みます - `context.steps.[stepId].output` を通じてステップの出力にアクセスできます - ステップの出力スキーマに基づいて型付けされています - データの一貫性を保つためにイミュータブルです ## 関連ドキュメント - [Step](./step-class.mdx) - [.then()](./then.mdx) - [.step()](./step-function.mdx) - [.after()](./after.mdx) # Memory クラスリファレンス [JA] Source: https://mastra.ai/ja/reference/memory/Memory `Memory` クラスは、Mastraで会話履歴とスレッドベースのメッセージストレージを管理するための堅牢なシステムを提供します。会話の永続的な保存、セマンティック検索機能、効率的なメッセージ取得を可能にします。会話履歴のためのストレージプロバイダーを設定する必要があり、セマンティックリコールを有効にする場合は、ベクトルストアとエンベッダーも提供する必要があります。 ## 基本的な使い方 ```typescript copy showLineNumbers import { Memory } from "@mastra/memory"; import { Agent } from "@mastra/core/agent"; const agent = new Agent({ memory: new Memory(), ...otherOptions, }); ``` ## カスタム設定 ```typescript copy showLineNumbers import { Memory } from "@mastra/memory"; import { LibSQLStore, LibSQLVector } from "@mastra/libsql"; import { Agent } from "@mastra/core/agent"; const memory = new Memory({ // Optional storage configuration - libsql will be used by default storage: new LibSQLStore({ url: "file:./memory.db", }), // Optional vector database for semantic search vector: new LibSQLVector({ url: "file:./vector.db", }), // Memory configuration options options: { // Number of recent messages to include lastMessages: 20, // Semantic search configuration semanticRecall: { topK: 3, // Number of similar messages to retrieve messageRange: { // Messages to include around each result before: 2, after: 1, }, }, // Working memory configuration workingMemory: { enabled: true, template: ` # User - First Name: - Last Name: `, }, }, }); const agent = new Agent({ memory, ...otherOptions, }); ``` ### ワーキングメモリ ワーキングメモリ機能を利用すると、エージェントは会話をまたいで情報を保持できます。有効にすると、Memory クラスは専用のツールコールを使ってワーキングメモリの更新を自動的に管理します。 設定例: ```typescript copy showLineNumbers const memory = new Memory({ options: { workingMemory: { enabled: true, template: "# User\n- **First Name**:\n- **Last Name**:", }, }, }); ``` テンプレートが指定されていない場合、Memory クラスはデフォルトのテンプレートを使用します。これには、ユーザー情報、好み、目標、その他のコンテキスト情報のフィールドが Markdown 形式で含まれています。詳細な使用例やベストプラクティスについては、[ワーキングメモリガイド](/docs/memory/working-memory.mdx#designing-effective-templates)をご覧ください。 ### embedder `semanticRecall` を有効にする場合、埋め込みモデルが必要です。 一つの選択肢として `@mastra/fastembed` を利用できます。これは [FastEmbed](https://github.com/Anush008/fastembed-js) を使ったオンデバイス/ローカル埋め込みモデルを提供します。このモデルはローカルで動作し、API キーやネットワークリクエストは不要です。 利用するには、まずパッケージをインストールしてください: ```bash npm2yarn copy npm install @mastra/fastembed ``` 次に、`Memory` インスタンスで設定します: ```typescript {2,7} import { Memory } from "@mastra/memory"; import { fastembed } from "@mastra/fastembed"; import { Agent } from "@mastra/core/agent"; const agent = new Agent({ memory: new Memory({ embedder: fastembed, // ... other memory config }), }); ``` なお、プロジェクトのデプロイ先によっては、FastEmbed の大きな内部依存関係のためにデプロイできない場合があります。 代わりに、OpenAI のような API ベースの embedder も利用できます(この問題は発生しません): ```typescript {2,7} import { Memory } from "@mastra/memory"; import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; const agent = new Agent({ memory: new Memory({ embedder: openai.embedding("text-embedding-3-small"), }), }); ``` Mastra は [Vercel AI SDK](https://sdk.vercel.ai/docs/ai-sdk-core/embeddings) を通じて多くの埋め込みモデルをサポートしており、OpenAI、Google、Mistral、Cohere などのオプションも利用できます。 ## パラメータ ### options ### 関連項目 - [Memoryの開始方法](/docs/memory/overview.mdx) - [セマンティックリコール](/docs/memory/semantic-recall.mdx) - [ワーキングメモリ](/docs/memory/working-memory.mdx) - [メモリプロセッサー](/docs/memory/memory-processors.mdx) - [createThread](/reference/memory/createThread.mdx) - [query](/reference/memory/query.mdx) - [getThreadById](/reference/memory/getThreadById.mdx) - [getThreadsByResourceId](/reference/memory/getThreadsByResourceId.mdx) # createThread [JA] Source: https://mastra.ai/ja/reference/memory/createThread メモリーシステム内で新しい会話スレッドを作成します。各スレッドは個別の会話やコンテキストを表し、複数のメッセージを含めることができます。 ## 使用例 ```typescript import { Memory } from "@mastra/memory"; const memory = new Memory({ /* config */ }); const thread = await memory.createThread({ resourceId: "user-123", title: "Support Conversation", metadata: { category: "support", priority: "high", }, }); ``` ## パラメーター ", description: "スレッドに関連付けるメタデータ(省略可能)", isOptional: true, }, ]} /> ## 戻り値 ", description: "スレッドに関連付けられた追加のメタデータ", }, ]} /> ### 関連情報 - [Memory クラスリファレンス](/reference/memory/Memory.mdx) - [Memory のはじめ方](/docs/memory/overview.mdx)(スレッドの概念を解説) - [getThreadById](/reference/memory/getThreadById.mdx) - [getThreadsByResourceId](/reference/memory/getThreadsByResourceId.mdx) - [query](/reference/memory/query.mdx) # getThreadById リファレンス [JA] Source: https://mastra.ai/ja/reference/memory/getThreadById `getThreadById` 関数は、ストレージから指定したIDのスレッドを取得します。 ## 使用例 ```typescript import { Memory } from "@mastra/core/memory"; const memory = new Memory(config); const thread = await memory.getThreadById({ threadId: "thread-123" }); ``` ## パラメーター ## 戻り値 ### 関連情報 - [Memory クラスリファレンス](/reference/memory/Memory.mdx) - [Memory のはじめ方](/docs/memory/overview.mdx)(スレッドの概念について解説) - [createThread](/reference/memory/createThread.mdx) - [getThreadsByResourceId](/reference/memory/getThreadsByResourceId.mdx) # getThreadsByResourceId リファレンス [JA] Source: https://mastra.ai/ja/reference/memory/getThreadsByResourceId `getThreadsByResourceId` 関数は、特定のリソースIDに関連付けられたすべてのスレッドをストレージから取得します。 ## 使用例 ```typescript import { Memory } from "@mastra/core/memory"; const memory = new Memory(config); const threads = await memory.getThreadsByResourceId({ resourceId: "resource-123", }); ``` ## パラメーター ## 戻り値 ### 関連情報 - [Memory クラスリファレンス](/reference/memory/Memory.mdx) - [Memory のはじめ方](/docs/memory/overview.mdx)(スレッド/リソースの概念を解説) - [createThread](/reference/memory/createThread.mdx) - [getThreadById](/reference/memory/getThreadById.mdx) # query [JA] Source: https://mastra.ai/ja/reference/memory/query 特定のスレッドからメッセージを取得します。ページネーションやフィルタリングオプションにも対応しています。 ## 使用例 ```typescript import { Memory } from "@mastra/memory"; const memory = new Memory({ /* config */ }); // Get last 50 messages const { messages, uiMessages } = await memory.query({ threadId: "thread-123", selectBy: { last: 50, }, }); // Get messages with context around specific messages const { messages: contextMessages } = await memory.query({ threadId: "thread-123", selectBy: { include: [ { id: "msg-123", // Get just this message (no context) }, { id: "msg-456", // Get this message with custom context withPreviousMessages: 3, // 3 messages before withNextMessages: 1, // 1 message after }, ], }, }); // Semantic search in messages const { messages } = await memory.query({ threadId: "thread-123", selectBy: { vectorSearchString: "What was discussed about deployment?", }, threadConfig: { historySearch: true, }, }); ``` ## パラメーター ### selectBy ### include ## 戻り値 ## 補足 `query` 関数は2つの異なるメッセージ形式を返します: - `messages`: 内部で使用されるコアメッセージ形式 - `uiMessages`: UI表示に適した形式のメッセージで、ツールコールやその結果のスレッド化が適切に行われています ### 関連 - [Memory クラスリファレンス](/reference/memory/Memory.mdx) - [Memory のはじめ方](/docs/memory/overview.mdx) - [セマンティックリコール](/docs/memory/semantic-recall.mdx) - [createThread](/reference/memory/createThread.mdx) --- title: "AgentNetwork(実験的)" description: "AgentNetworkクラスのリファレンスドキュメント" --- # AgentNetwork(実験的) [JA] Source: https://mastra.ai/ja/reference/networks/agent-network > **注意:** AgentNetwork機能は実験的であり、今後のリリースで変更される可能性があります。 `AgentNetwork` クラスは、複雑なタスクを解決するために協力できる専門的なエージェントのネットワークを作成する方法を提供します。Workflowsが実行経路を明示的に制御する必要があるのに対し、AgentNetworkはLLMベースのルーターを使用して、次にどのエージェントを呼び出すかを動的に決定します。 ## 主要な概念 - **LLMベースのルーティング**: AgentNetworkは、エージェントの最適な活用方法を判断するためにLLMのみを使用します - **エージェントの協働**: 複数の専門エージェントが協力して複雑なタスクを解決できます - **動的な意思決定**: ルーターがタスクの要件に基づいてどのエージェントを呼び出すかを決定します ## 使い方 ```typescript import { AgentNetwork } from "@mastra/core/network"; import { openai } from "@mastra/openai"; // Create specialized agents const webSearchAgent = new Agent({ name: "Web Search Agent", instructions: "You search the web for information.", model: openai("gpt-4o"), tools: { /* web search tools */ }, }); const dataAnalysisAgent = new Agent({ name: "Data Analysis Agent", instructions: "You analyze data and provide insights.", model: openai("gpt-4o"), tools: { /* data analysis tools */ }, }); // Create the network const researchNetwork = new AgentNetwork({ name: "Research Network", instructions: "Coordinate specialized agents to research topics thoroughly.", model: openai("gpt-4o"), agents: [webSearchAgent, dataAnalysisAgent], }); // Use the network const result = await researchNetwork.generate( "Research the impact of climate change on agriculture", ); console.log(result.text); ``` ## コンストラクター ```typescript constructor(config: AgentNetworkConfig) ``` ### パラメーター - `config`: AgentNetworkのための設定オブジェクト - `name`: ネットワークの名前 - `instructions`: ルーティングエージェントへの指示 - `model`: ルーティングに使用する言語モデル - `agents`: ネットワーク内の専門エージェントの配列 ## メソッド ### generate() エージェントネットワークを使用して応答を生成します。このメソッドは、コードベース全体の一貫性のために非推奨となった `run()` メソッドの代わりとなります。 ```typescript async generate( messages: string | string[] | CoreMessage[], args?: AgentGenerateOptions ): Promise ``` ### stream() エージェントネットワークを使用して応答をストリーミングします。 ```typescript async stream( messages: string | string[] | CoreMessage[], args?: AgentStreamOptions ): Promise ``` ### getRoutingAgent() ネットワークで使用されているルーティングエージェントを返します。 ```typescript getRoutingAgent(): Agent ``` ### getAgents() ネットワーク内の専門エージェントの配列を返します。 ```typescript getAgents(): Agent[] ``` ### getAgentHistory() 特定のエージェントに対するやり取りの履歴を返します。 ```typescript getAgentHistory(agentId: string): Array<{ input: string; output: string; timestamp: string; }> ``` ### getAgentInteractionHistory() ネットワーク内で発生したすべてのエージェントのやり取り履歴を返します。 ```typescript getAgentInteractionHistory(): Record< string, Array<{ input: string; output: string; timestamp: string; }> > ``` ### getAgentInteractionSummary() エージェントのやり取りを時系列でまとめたフォーマット済みのサマリーを返します。 ```typescript getAgentInteractionSummary(): string ``` ## AgentNetwork と Workflows の使い分け - **AgentNetwork を使う場合:** タスクの要件に基づいて、AI にエージェントの最適な使い方や動的なルーティングを任せたいとき。 - **Workflows を使う場合:** 実行経路を明確に制御したいときや、エージェントの呼び出し順序や条件分岐をあらかじめ決めておきたいとき。 ## 内部ツール AgentNetwork は、ルーティングエージェントが専門のエージェントを呼び出すことを可能にする特別な `transmit` ツールを使用します。このツールは以下を処理します: - 単一エージェントの呼び出し - 複数エージェントの並列呼び出し - エージェント間のコンテキスト共有 ## 制限事項 - AgentNetworkのアプローチは、同じタスクに対してよく設計されたWorkflowよりも多くのトークンを使用する場合があります - ルーティングの判断がLLMによって行われるため、デバッグがより困難になることがあります - パフォーマンスは、ルーティング指示の質や各専門エージェントの能力によって変動する可能性があります --- title: "リファレンス: Logger インスタンス | Mastra Observability ドキュメント" description: さまざまな重大度レベルでイベントを記録するためのメソッドを提供する Logger インスタンスのドキュメントです。 --- # ロガーインスタンス [JA] Source: https://mastra.ai/ja/reference/observability/logger ロガーインスタンスは`new PinoLogger()`によって作成され、様々な重要度レベルでイベントを記録するためのメソッドを提供します。ロガーの種類に応じて、メッセージはコンソール、ファイル、または外部サービスに書き込まれる場合があります。 ## 例 ```typescript showLineNumbers copy // Using a console logger const logger = new PinoLogger({ name: "Mastra", level: "info" }); logger.debug("Debug message"); // Won't be logged because level is INFO logger.info({ message: "User action occurred", destinationPath: "user-actions", type: "AGENT", }); // Logged logger.error("An error occurred"); // Logged as ERROR ``` ## メソッド void | Promise", description: "DEBUGレベルのログを書き込みます。レベルがDEBUG以下の場合のみ記録されます。", }, { name: "info", type: "(message: BaseLogMessage | string, ...args: any[]) => void | Promise", description: "INFOレベルのログを書き込みます。レベルがINFO以下の場合のみ記録されます。", }, { name: "warn", type: "(message: BaseLogMessage | string, ...args: any[]) => void | Promise", description: "WARNレベルのログを書き込みます。レベルがWARN以下の場合のみ記録されます。", }, { name: "error", type: "(message: BaseLogMessage | string, ...args: any[]) => void | Promise", description: "ERRORレベルのログを書き込みます。レベルがERROR以下の場合のみ記録されます。", }, { name: "cleanup", type: "() => Promise", isOptional: true, description: "ロガーが保持しているリソース(例:Upstashのネットワーク接続など)をクリーンアップします。すべてのロガーがこの機能を実装しているわけではありません。", }, ]} /> **注意:** 一部のロガーでは、`BaseLogMessage` オブジェクト(`message`、`destinationPath`、`type` フィールドを含む)が必要です。例えば、`File` や `Upstash` ロガーは構造化されたメッセージを必要とします。 --- title: "リファレンス: OtelConfig | Mastra Observability ドキュメント" description: OpenTelemetry のインストルメンテーション、トレーシング、およびエクスポート動作を設定する OtelConfig オブジェクトのドキュメント。 --- # `OtelConfig` [JA] Source: https://mastra.ai/ja/reference/observability/otel-config `OtelConfig` オブジェクトは、アプリケーション内で OpenTelemetry のインストルメンテーション、トレーシング、およびエクスポートの動作を設定するために使用されます。そのプロパティを調整することで、テレメトリーデータ(トレースなど)の収集、サンプリング、エクスポート方法を制御できます。 Mastra で `OtelConfig` を使用するには、Mastra の初期化時に `telemetry` キーの値として渡します。これにより、Mastra はトレーシングとインストルメンテーションのためにカスタムの OpenTelemetry 設定を使用するように構成されます。 ```typescript showLineNumbers copy import { Mastra } from "mastra"; const otelConfig: OtelConfig = { serviceName: "my-awesome-service", enabled: true, sampling: { type: "ratio", probability: 0.5, }, export: { type: "otlp", endpoint: "https://otel-collector.example.com/v1/traces", headers: { Authorization: "Bearer YOUR_TOKEN_HERE", }, }, }; ``` ### プロパティ ", isOptional: true, description: "OTLP リクエストと共に送信する追加ヘッダーです。認証やルーティングに便利です。", }, ], }, ]} /> --- title: "リファレンス: Braintrust | 観測性 | Mastra ドキュメント" description: BraintrustをMastraと統合するためのドキュメント。MastraはLLMアプリケーションの評価と監視プラットフォームです。 --- # Braintrust [JA] Source: https://mastra.ai/ja/reference/observability/providers/braintrust Braintrustは、LLMアプリケーションの評価と監視のためのプラットフォームです。 ## 設定 BraintrustをMastraで使用するには、次の環境変数を設定してください: ```env OTEL_EXPORTER_OTLP_ENDPOINT=https://api.braintrust.dev/otel OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer , x-bt-parent=project_id:" ``` ## 実装 MastraをBraintrustで使用するための設定方法は次のとおりです: ```typescript import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "your-service-name", enabled: true, export: { type: "otlp", }, }, }); ``` ## ダッシュボード [braintrust.dev](https://www.braintrust.dev/)でBraintrustダッシュボードにアクセス --- title: "リファレンス: Dash0 統合 | Mastra Observability ドキュメント" description: Mastra を Open Telementry ネイティブのオブザーバビリティソリューションである Dash0 と統合するためのドキュメント。 --- # Dash0 [JA] Source: https://mastra.ai/ja/reference/observability/providers/dash0 Dash0は、Open Telementryネイティブのオブザーバビリティソリューションであり、フルスタックのモニタリング機能に加え、PersesやPrometheusなど他のCNCFプロジェクトとの統合も提供します。 ## 設定 Dash0 を Mastra で使用するには、以下の環境変数を設定してください: ```env OTEL_EXPORTER_OTLP_ENDPOINT=https://ingress..dash0.com OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer , Dash0-Dataset= ``` ## 実装 Mastra を Dash0 で使用するための設定方法は以下の通りです。 ```typescript import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "your-service-name", enabled: true, export: { type: "otlp", }, }, }); ``` ## ダッシュボード [Dash0](https://www.dash0.com/) であなたのDash0ダッシュボードにアクセスし、[Dash0 Integration Hub](https://www.dash0.com/hub/integrations)でさらに多くの[分散トレーシング](https://www.dash0.com/distributed-tracing)連携方法を見つけましょう。 --- title: "リファレンス: プロバイダー一覧 | オブザーバビリティ | Mastra ドキュメント" description: Mastra がサポートするオブザーバビリティプロバイダーの概要。Dash0、SigNoz、Braintrust、Langfuse などを含みます。 --- # 可観測性プロバイダー [JA] Source: https://mastra.ai/ja/reference/observability/providers 可観測性プロバイダーには以下が含まれます: - [Braintrust](./providers/braintrust.mdx) - [Dash0](./providers/dash0.mdx) - [Laminar](./providers/laminar.mdx) - [Langfuse](./providers/langfuse.mdx) - [Langsmith](./providers/langsmith.mdx) - [LangWatch](./providers/langwatch.mdx) - [New Relic](./providers/new-relic.mdx) - [SigNoz](./providers/signoz.mdx) - [Traceloop](./providers/traceloop.mdx) --- title: "リファレンス: Laminar 統合 | Mastra 観測性ドキュメント" description: LLMアプリケーション向けの専門的な観測性プラットフォームであるMastraとLaminarを統合するためのドキュメント。 --- # Laminar [JA] Source: https://mastra.ai/ja/reference/observability/providers/laminar Laminarは、LLMアプリケーション向けの専門的なオブザーバビリティプラットフォームです。 ## 設定 LaminarをMastraと一緒に使用するには、これらの環境変数を設定してください: ```env OTEL_EXPORTER_OTLP_ENDPOINT=https://api.lmnr.ai:8443 OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer your_api_key, x-laminar-team-id=your_team_id" ``` ## 実装 こちらは、MastraをLaminarで使用するための設定方法です: ```typescript import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "your-service-name", enabled: true, export: { type: "otlp", protocol: "grpc", }, }, }); ``` ## ダッシュボード Laminar ダッシュボードにアクセスするには、[https://lmnr.ai/](https://lmnr.ai/) をご覧ください。 --- title: "リファレンス: Langfuse 統合 | Mastra オブザーバビリティ ドキュメント" description: LLM アプリケーション向けのオープンソースオブザーバビリティプラットフォームである Mastra と Langfuse を統合するためのドキュメント。 --- # Langfuse [JA] Source: https://mastra.ai/ja/reference/observability/providers/langfuse Langfuseは、LLMアプリケーション向けに特別に設計されたオープンソースのオブザーバビリティプラットフォームです。 > **注**: 現在、AI関連の呼び出しのみが詳細なテレメトリーデータを含みます。他の操作はトレースを作成しますが、情報は限られています。 ## 設定 LangfuseをMastraと一緒に使用するには、次の環境変数を設定する必要があります: ```env LANGFUSE_PUBLIC_KEY=your_public_key LANGFUSE_SECRET_KEY=your_secret_key LANGFUSE_BASEURL=https://cloud.langfuse.com # オプション - デフォルトはcloud.langfuse.com ``` **重要**: テレメトリーエクスポート設定を構成する際、Langfuseの統合が正しく機能するためには、`traceName`パラメータを`"ai"`に設定する必要があります。 ## 実装 こちらは、MastraをLangfuseで使用するための設定方法です: ```typescript import { Mastra } from "@mastra/core"; import { LangfuseExporter } from "langfuse-vercel"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "ai", // this must be set to "ai" so that the LangfuseExporter thinks it's an AI SDK trace enabled: true, export: { type: "custom", exporter: new LangfuseExporter({ publicKey: process.env.LANGFUSE_PUBLIC_KEY, secretKey: process.env.LANGFUSE_SECRET_KEY, baseUrl: process.env.LANGFUSE_BASEURL, }), }, }, }); ``` ## ダッシュボード 設定が完了すると、[cloud.langfuse.com](https://cloud.langfuse.com) のLangfuseダッシュボードでトレースと分析を表示できます。 --- title: "リファレンス: LangSmith 統合 | Mastra オブザーバビリティ ドキュメント" description: LLMアプリケーションのデバッグ、テスト、評価、監視のためのプラットフォームであるMastraとLangSmithを統合するためのドキュメント。 --- # LangSmith [JA] Source: https://mastra.ai/ja/reference/observability/providers/langsmith LangSmithは、LLMアプリケーションのデバッグ、テスト、評価、監視のためのLangChainのプラットフォームです。 > **注**: 現在、この統合はアプリケーション内のAI関連の呼び出しのみをトレースします。他の種類の操作はテレメトリーデータにキャプチャされません。 ## 設定 LangSmithをMastraで使用するには、次の環境変数を設定する必要があります: ```env LANGSMITH_TRACING=true LANGSMITH_ENDPOINT=https://api.smith.langchain.com LANGSMITH_API_KEY=your-api-key LANGSMITH_PROJECT=your-project-name ``` ## 実装 LangSmithを使用するようにMastraを設定する方法は次のとおりです: ```typescript import { Mastra } from "@mastra/core"; import { AISDKExporter } from "langsmith/vercel"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "your-service-name", enabled: true, export: { type: "custom", exporter: new AISDKExporter(), }, }, }); ``` ## ダッシュボード LangSmith ダッシュボードでトレースと分析にアクセスするには、[smith.langchain.com](https://smith.langchain.com) をご覧ください。 > **注意**: ワークフローを実行しても、新しいプロジェクトにデータが表示されない場合があります。すべてのプロジェクトを表示するには、Name 列で並べ替えを行い、プロジェクトを選択してから、Root Runs の代わりに LLM Calls でフィルタリングする必要があります。 --- title: "リファレンス: LangWatch統合 | Mastra可観測性ドキュメント" description: LLMアプリケーション向けの専門的な可観測性プラットフォームであるLangWatchとMastraの統合に関するドキュメント。 --- # LangWatch [JA] Source: https://mastra.ai/ja/reference/observability/providers/langwatch LangWatchは、LLMアプリケーション向けの専門的な可観測性プラットフォームです。 ## 設定 MastraでLangWatchを使用するには、以下の環境変数を設定してください: ```env LANGWATCH_API_KEY=your_api_key ``` ## 実装 MastraでLangWatchを使用するための設定方法は以下の通りです: ```typescript import { Mastra } from "@mastra/core"; import { LangWatchExporter } from "langwatch"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "ai", // this must be set to "ai" so that the LangWatchExporter thinks it's an AI SDK trace enabled: true, export: { type: "custom", exporter: new LangWatchExporter({ apiKey: process.env.LANGWATCH_API_KEY }), }, }, }); ``` ## ダッシュボード [app.langwatch.ai](https://app.langwatch.ai)でLangWatchダッシュボードにアクセスしてください --- title: "リファレンス: New Relic 統合 | Mastra オブザーバビリティ ドキュメント" description: New Relic と Mastra の統合に関するドキュメント。Mastra は、OpenTelemetry をサポートするフルスタック監視のための包括的なオブザーバビリティ プラットフォームです。 --- # New Relic [JA] Source: https://mastra.ai/ja/reference/observability/providers/new-relic New Relicは、フルスタックモニタリングのためにOpenTelemetry (OTLP) をサポートする包括的なオブザーバビリティプラットフォームです。 ## 設定 OTLPを介してMastraでNew Relicを使用するには、これらの環境変数を設定してください: ```env OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net:4317 OTEL_EXPORTER_OTLP_HEADERS="api-key=your_license_key" ``` ## 実装 MastraをNew Relicで使用するための設定方法は次のとおりです: ```typescript import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "your-service-name", enabled: true, export: { type: "otlp", }, }, }); ``` ## ダッシュボード [one.newrelic.com](https://one.newrelic.com) で New Relic One ダッシュボードにテレメトリーデータを表示します --- title: "リファレンス: SigNoz 統合 | Mastra オブザーバビリティ ドキュメント" description: SigNozをMastraと統合するためのドキュメント。Mastraは、OpenTelemetryを通じてフルスタック監視を提供するオープンソースのAPMおよびオブザーバビリティプラットフォームです。 --- # SigNoz [JA] Source: https://mastra.ai/ja/reference/observability/providers/signoz SigNozは、OpenTelemetryを通じてフルスタックの監視機能を提供するオープンソースのAPMおよびオブザーバビリティプラットフォームです。 ## 設定 SigNozをMastraと一緒に使用するには、これらの環境変数を設定してください: ```env OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.{region}.signoz.cloud:443 OTEL_EXPORTER_OTLP_HEADERS=signoz-ingestion-key=your_signoz_token ``` ## 実装 MastraをSigNozで使用するための設定方法は次のとおりです: ```typescript import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "your-service-name", enabled: true, export: { type: "otlp", }, }, }); ``` ## ダッシュボード あなたのSigNozダッシュボードにアクセスするには、[signoz.io](https://signoz.io/)をご覧ください。 --- title: "リファレンス: Traceloop 統合 | Mastra 観測性ドキュメント" description: Traceloop を Mastra と統合するためのドキュメント。Mastra は LLM アプリケーション向けの OpenTelemetry ネイティブの観測性プラットフォームです。 --- # Traceloop [JA] Source: https://mastra.ai/ja/reference/observability/providers/traceloop Traceloopは、LLMアプリケーション向けに特別に設計されたOpenTelemetryネイティブのオブザーバビリティプラットフォームです。 ## 設定 TraceloopをMastraと一緒に使用するには、次の環境変数を設定してください: ```env OTEL_EXPORTER_OTLP_ENDPOINT=https://api.traceloop.com OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer your_api_key, x-traceloop-destination-id=your_destination_id" ``` ## 実装 MastraをTraceloopで使用するための設定方法は次のとおりです: ```typescript import { Mastra } from "@mastra/core"; export const mastra = new Mastra({ // ... other config telemetry: { serviceName: "your-service-name", enabled: true, export: { type: "otlp", }, }, }); ``` ## ダッシュボード [app.traceloop.com](https://app.traceloop.com) で Traceloop ダッシュボードにアクセスして、トレースと分析を確認してください。 --- title: "リファレンス: Astra ベクトルストア | ベクトルデータベース | RAG | Mastra ドキュメント" description: Mastraの中のAstraVectorクラスのドキュメント。DataStax Astra DBを使用したベクトル検索を提供します。 --- # Astra Vector Store [JA] Source: https://mastra.ai/ja/reference/rag/astra AstraVectorクラスは、[DataStax Astra DB](https://www.datastax.com/products/datastax-astra)を使用したベクトル検索を提供します。これはApache Cassandraをベースにしたクラウドネイティブでサーバーレスなデータベースです。 エンタープライズグレードのスケーラビリティと高可用性を備えたベクトル検索機能を提供します。 ## コンストラクタオプション ## メソッド ### createIndex() ### upsert() []", isOptional: true, description: "各ベクトルのメタデータ", }, { name: "ids", type: "string[]", isOptional: true, description: "オプションのベクトルID(提供されない場合は自動生成されます)", }, ]} /> ### query() ", isOptional: true, description: "クエリのメタデータフィルター", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "結果にベクトルを含めるかどうか", }, ]} /> ### listIndexes() インデックス名の文字列配列を返します。 ### describeIndex() 戻り値: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() ### updateVector() ", isOptional: true, description: "新しいメタデータ値", }, ], }, ]} /> ### deleteVector() ## レスポンスタイプ クエリ結果は以下の形式で返されます: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true } ``` ## エラー処理 ストアは捕捉可能な型付きエラーをスローします: ```typescript copy try { await store.query({ indexName: "index_name", queryVector: queryVector, }); } catch (error) { if (error instanceof VectorStoreError) { console.log(error.code); // 'connection_failed' | 'invalid_dimension' | etc console.log(error.details); // Additional error context } } ``` ## 環境変数 必要な環境変数: - `ASTRA_DB_TOKEN`: Astra DBのAPIトークン - `ASTRA_DB_ENDPOINT`: Astra DBのAPIエンドポイント ## 関連 - [メタデータフィルター](./metadata-filters) --- title: "リファレンス: Chroma ベクトルストア | ベクトルデータベース | RAG | Mastra ドキュメント" description: Mastraにおける、ChromaDBを使用したベクトル検索を提供するChromaVectorクラスのドキュメント。 --- # Chroma ベクトルストア [JA] Source: https://mastra.ai/ja/reference/rag/chroma ChromaVectorクラスは、[ChromaDB](https://www.trychroma.com/)を使用したベクトル検索を提供します。ChromaDBはオープンソースの埋め込みデータベースです。 メタデータフィルタリングとハイブリッド検索機能を備えた効率的なベクトル検索を提供します。 ## コンストラクタオプション ### auth ## メソッド ### createIndex() ### upsert() []", isOptional: true, description: "各ベクトルのメタデータ", }, { name: "ids", type: "string[]", isOptional: true, description: "オプションのベクトルID(提供されない場合は自動生成されます)", }, { name: "documents", type: "string[]", isOptional: true, description: "Chroma固有:ベクトルに関連付けられた元のテキストドキュメント", }, ]} /> ### query() ", isOptional: true, description: "クエリのメタデータフィルター", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "結果にベクトルを含めるかどうか", }, { name: "documentFilter", type: "Record", isOptional: true, description: "Chroma固有:ドキュメントコンテンツに適用するフィルター", }, ]} /> ### listIndexes() インデックス名の文字列配列を返します。 ### describeIndex() 戻り値: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() ### updateVector() `update`オブジェクトには以下を含めることができます: ", isOptional: true, description: "既存のメタデータを置き換える新しいメタデータ", }, ]} /> ### deleteVector() ## レスポンスタイプ クエリ結果は以下の形式で返されます: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; document?: string; // Chroma-specific: Original document if it was stored vector?: number[]; // Only included if includeVector is true } ``` ## エラー処理 ストアは捕捉可能な型付きエラーをスローします: ```typescript copy try { await store.query({ indexName: "index_name", queryVector: queryVector, }); } catch (error) { if (error instanceof VectorStoreError) { console.log(error.code); // 'connection_failed' | 'invalid_dimension' | etc console.log(error.details); // Additional error context } } ``` ## 関連 - [メタデータフィルター](./metadata-filters) --- title: "リファレンス: .chunk() | ドキュメント処理 | RAG | Mastra ドキュメント" description: Mastra の chunk 関数のドキュメント。さまざまな戦略を用いてドキュメントを小さなセグメントに分割します。 --- # リファレンス: .chunk() [JA] Source: https://mastra.ai/ja/reference/rag/chunk `.chunk()` 関数は、さまざまな戦略やオプションを用いてドキュメントをより小さなセグメントに分割します。 ## 例 ```typescript import { MDocument } from "@mastra/rag"; const doc = MDocument.fromMarkdown(` # Introduction This is a sample document that we want to split into chunks. ## Section 1 Here is the first section with some content. ## Section 2 Here is another section with different content. `); // Basic chunking with defaults const chunks = await doc.chunk(); // Markdown-specific chunking with header extraction const chunksWithMetadata = await doc.chunk({ strategy: "markdown", headers: [ ["#", "title"], ["##", "section"], ], extract: { summary: true, // Extract summaries with default settings keywords: true, // Extract keywords with default settings }, }); ``` ## パラメーター ## 戦略固有のオプション 戦略固有のオプションは、strategy パラメータと並んでトップレベルのパラメータとして渡されます。例えば: ```typescript showLineNumbers copy // HTML戦略の例 const chunks = await doc.chunk({ strategy: "html", headers: [ ["h1", "title"], ["h2", "subtitle"], ], // HTML固有のオプション sections: [["div.content", "main"]], // HTML固有のオプション size: 500, // 一般的なオプション }); // Markdown戦略の例 const chunks = await doc.chunk({ strategy: "markdown", headers: [ ["#", "title"], ["##", "section"], ], // Markdown固有のオプション stripHeaders: true, // Markdown固有のオプション overlap: 50, // 一般的なオプション }); // Token戦略の例 const chunks = await doc.chunk({ strategy: "token", encodingName: "gpt2", // Token固有のオプション modelName: "gpt-3.5-turbo", // Token固有のオプション size: 1000, // 一般的なオプション }); ``` 以下に記載されているオプションは、設定オブジェクトのトップレベルで直接渡され、別の options オブジェクト内にネストされません。 ### HTML ", description: "ヘッダー単位で分割するための [セレクタ, メタデータキー] のペアの配列", }, { name: "sections", type: "Array<[string, string]>", description: "セクション単位で分割するための [セレクタ, メタデータキー] のペアの配列", }, { name: "returnEachLine", type: "boolean", isOptional: true, description: "各行を個別のチャンクとして返すかどうか", }, ]} /> ### Markdown ", description: "[ヘッダーレベル, メタデータキー] のペアの配列", }, { name: "stripHeaders", type: "boolean", isOptional: true, description: "出力からヘッダーを削除するかどうか", }, { name: "returnEachLine", type: "boolean", isOptional: true, description: "各行を個別のチャンクとして返すかどうか", }, ]} /> ### Token ### JSON ## 戻り値 チャンク化されたドキュメントを含む `MDocument` インスタンスを返します。各チャンクには以下が含まれます: ```typescript interface DocumentNode { text: string; metadata: Record; embedding?: number[]; } ``` --- title: "リファレンス: Couchbase Vector Store | Vector Databases | RAG | Mastra Docs" description: Couchbase Vector Searchを使用してベクトル検索を提供するMastraのCouchbaseVectorクラスのドキュメント。 --- # Couchbase Vector Store [JA] Source: https://mastra.ai/ja/reference/rag/couchbase `CouchbaseVector`クラスは[Couchbase Vector Search](https://docs.couchbase.com/server/current/vector-search/vector-search.html)を使用してベクトル検索を提供します。Couchbaseコレクション内で効率的な類似性検索とメタデータフィルタリングを可能にします。 ## 要件 - **Couchbase Server 7.6.4+** または互換性のあるCapellaクラスター - Couchbaseデプロイメントで**Search Serviceが有効化**されていること ## インストール ```bash copy npm install @mastra/couchbase ``` ## 使用例 ```typescript copy showLineNumbers import { CouchbaseVector } from '@mastra/couchbase'; const store = new CouchbaseVector({ connectionString: process.env.COUCHBASE_CONNECTION_STRING, username: process.env.COUCHBASE_USERNAME, password: process.env.COUCHBASE_PASSWORD, bucketName: process.env.COUCHBASE_BUCKET, scopeName: process.env.COUCHBASE_SCOPE, collectionName: process.env.COUCHBASE_COLLECTION, }); ``` ## コンストラクタオプション ## メソッド ### createIndex() Couchbaseに新しいベクトルインデックスを作成します。 > **注意:** インデックス作成は非同期です。`createIndex`を呼び出した後、クエリを実行する前に時間を置いてください(小さなデータセットでは通常1〜5秒、大きなデータセットではより長時間)。本番環境では、固定の遅延を使用するのではなく、インデックスのステータスをチェックするポーリングを実装してください。 ### upsert() コレクション内のベクトルとそのメタデータを追加または更新します。 > **注意:** インデックスを作成する前後にデータをupsertできます。`upsert`メソッドはインデックスが存在する必要がありません。Couchbaseでは同じコレクションに対して複数のSearchインデックスを作成できます。 []", isOptional: true, description: "各ベクトルのメタデータ", }, { name: "ids", type: "string[]", isOptional: true, description: "オプションのベクトルID(提供されない場合は自動生成)", }, ]} /> ### query() 類似ベクトルを検索します。 > **警告:** `filter`と`includeVector`パラメータは現在サポートされていません。フィルタリングは結果を取得した後にクライアント側で実行するか、CouchbaseSDKのSearch機能を直接使用する必要があります。ベクトル埋め込みを取得するには、CouchbaseSDKを使用してIDで完全なドキュメントを取得してください。 ", isOptional: true, description: "メタデータフィルター", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "結果にベクトルデータを含めるかどうか", }, { name: "minScore", type: "number", isOptional: true, defaultValue: "0", description: "最小類似性スコアの閾値", }, ]} /> ### describeIndex() インデックスに関する情報を返します。 戻り値: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() インデックスとそのすべてのデータを削除します。 ### listIndexes() Couchbaseバケット内のすべてのベクトルインデックスをリストします。 戻り値: `Promise` ### updateVector() IDによって特定のベクトルエントリを新しいベクトルデータやメタデータで更新します。 ", isOptional: true, description: "更新する新しいメタデータ", }, ]} /> ### deleteVector() IDによってインデックスから特定のベクトルエントリを削除します。 ### disconnect() Couchbaseクライアント接続を閉じます。ストアの使用が完了したときに呼び出す必要があります。 ## レスポンスタイプ クエリ結果は以下の形式で返されます: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true } ``` ## エラーハンドリング ストアは型付きエラーをスローし、それをキャッチできます: ```typescript copy try { await store.query({ indexName: "my_index", queryVector: queryVector, }); } catch (error) { // 特定のエラーケースを処理 if (error.message.includes("Invalid index name")) { console.error( "インデックス名は文字またはアンダースコアで始まり、有効な文字のみを含む必要があります。" ); } else if (error.message.includes("Index not found")) { console.error("指定されたインデックスが存在しません"); } else { console.error("ベクターストアエラー:", error.message); } } ``` ## 注意事項 - **インデックス削除の注意点:** Searchインデックスを削除しても、関連するCouchbaseコレクション内のベクトル/ドキュメントは削除されません。データは明示的に削除されない限り残存します。 - **必要な権限:** Couchbaseユーザーは、接続、対象コレクションでのドキュメントの読み書き(`kv`ロール)、およびSearchインデックスの管理(関連するバケット/スコープでの`search_admin`ロール)の権限を持つ必要があります。 - **インデックス定義の詳細とドキュメント構造:** `createIndex`メソッドは、`embedding`フィールド(`vector`タイプ)と`content`フィールド(`text`タイプ)をインデックス化するSearchインデックス定義を構築し、指定された`scopeName.collectionName`内のドキュメントを対象とします。各ドキュメントは`embedding`フィールドにベクトルを、`metadata`フィールドにメタデータを格納します。`metadata`に`text`プロパティが含まれている場合、その値はトップレベルの`content`フィールドにもコピーされ、テキスト検索用にインデックス化されます。 - **レプリケーションと耐久性:** データの耐久性のために、Couchbaseの組み込みレプリケーションと永続化機能の使用を検討してください。効率的な検索を確保するため、インデックス統計を定期的に監視してください。 ## 制限事項 - インデックス作成の遅延により、作成直後のクエリに影響を与える可能性があります。 - 取り込み時にベクトル次元の厳密な強制はありません(次元の不一致はクエリ時にエラーになります)。 - ベクトルの挿入とインデックスの更新は結果整合性です。書き込み直後の強い整合性は保証されません。 ## 関連 - [メタデータフィルター](./metadata-filters) --- title: "リファレンス: DatabaseConfig | RAG | Mastra Docs" description: MastraのRAGシステムでベクトルクエリツールと共に使用されるデータベース固有の設定タイプのAPIリファレンス。 --- import { Callout } from "nextra/components"; import { Tabs } from "nextra/components"; # DatabaseConfig [JA] Source: https://mastra.ai/ja/reference/rag/database-config `DatabaseConfig`型を使用すると、ベクトルクエリツールを使用する際にデータベース固有の設定を指定できます。これらの設定により、異なるベクトルストアが提供する独自の機能と最適化を活用できます。 ## 型定義 ```typescript export type DatabaseConfig = { pinecone?: PineconeConfig; pgvector?: PgVectorConfig; chroma?: ChromaConfig; [key: string]: any; // Extensible for future databases }; ``` ## データベース固有の型 ### PineconeConfig Pineconベクトルストア固有の設定オプション。 **使用例:** - マルチテナントアプリケーション(テナントごとに名前空間を分離) - 環境分離(dev/staging/prod名前空間) - セマンティック検索とキーワード検索を組み合わせたハイブリッド検索 ### PgVectorConfig pgvector拡張を使用したPostgreSQL固有の設定オプション。 **パフォーマンスガイドライン:** - **ef**: topK値の2-4倍から始めて、精度向上のために増加 - **probes**: 1-10から始めて、再現率向上のために増加 - **minScore**: 品質要件に応じて0.5-0.9の値を使用 **使用例:** - 高負荷シナリオでのパフォーマンス最適化 - 無関係な結果を除去するための品質フィルタリング - 検索精度と速度のトレードオフの微調整 ### ChromaConfig Chromaベクトルストア固有の設定オプション。 ", description: "MongoDB形式のクエリ構文を使用したメタデータフィルタリング条件。メタデータフィールドに基づいて結果をフィルタリングします。", isOptional: true, }, { name: "whereDocument", type: "Record", description: "ドキュメントコンテンツのフィルタリング条件。実際のドキュメントテキストコンテンツに基づいてフィルタリングを可能にします。", isOptional: true, }, ]} /> **フィルタ構文例:** ```typescript // 単純な等価性 where: { "category": "technical" } // 演算子 where: { "price": { "$gt": 100 } } // 複数条件 where: { "category": "electronics", "inStock": true } // ドキュメントコンテンツフィルタリング whereDocument: { "$contains": "API documentation" } ``` **使用例:** - 高度なメタデータフィルタリング - コンテンツベースのドキュメントフィルタリング - 複雑なクエリの組み合わせ ## 使用例 ### 基本的なデータベース設定 ```typescript import { createVectorQueryTool } from '@mastra/rag'; const vectorTool = createVectorQueryTool({ vectorStoreName: 'pinecone', indexName: 'documents', model: embedModel, databaseConfig: { pinecone: { namespace: 'production' } } }); ``` ### ランタイム設定のオーバーライド ```typescript import { RuntimeContext } from '@mastra/core/runtime-context'; // 初期設定 const vectorTool = createVectorQueryTool({ vectorStoreName: 'pinecone', indexName: 'documents', model: embedModel, databaseConfig: { pinecone: { namespace: 'development' } } }); // ランタイムでオーバーライド const runtimeContext = new RuntimeContext(); runtimeContext.set('databaseConfig', { pinecone: { namespace: 'production' } }); await vectorTool.execute({ context: { queryText: 'search query' }, mastra, runtimeContext }); ``` ### マルチデータベース設定 ```typescript const vectorTool = createVectorQueryTool({ vectorStoreName: 'dynamic', // ランタイムで決定される indexName: 'documents', model: embedModel, databaseConfig: { pinecone: { namespace: 'default' }, pgvector: { minScore: 0.8, ef: 150 }, chroma: { where: { 'type': 'documentation' } } } }); ``` **マルチデータベースサポート**: 複数のデータベースを設定した場合、実際に使用されるベクターストアに一致する設定のみが適用されます。 ### パフォーマンスチューニング ```typescript // 高精度設定 const highAccuracyTool = createVectorQueryTool({ vectorStoreName: 'postgres', indexName: 'embeddings', model: embedModel, databaseConfig: { pgvector: { ef: 400, // 高精度 probes: 20, // 高再現率 minScore: 0.85 // 高品質閾値 } } }); // 高速設定 const highSpeedTool = createVectorQueryTool({ vectorStoreName: 'postgres', indexName: 'embeddings', model: embedModel, databaseConfig: { pgvector: { ef: 50, // 低精度、高速 probes: 3, // 低再現率、高速 minScore: 0.6 // 低品質閾値 } } }); ``` ## 拡張性 `DatabaseConfig`型は拡張可能になるよう設計されています。新しいベクターデータベースのサポートを追加するには: ```typescript // 1. Define the configuration interface export interface NewDatabaseConfig { customParam1?: string; customParam2?: number; } // 2. Extend DatabaseConfig type export type DatabaseConfig = { pinecone?: PineconeConfig; pgvector?: PgVectorConfig; chroma?: ChromaConfig; newdatabase?: NewDatabaseConfig; [key: string]: any; }; // 3. Use in vector query tool const vectorTool = createVectorQueryTool({ vectorStoreName: 'newdatabase', indexName: 'documents', model: embedModel, databaseConfig: { newdatabase: { customParam1: 'value', customParam2: 42 } } }); ``` ## ベストプラクティス 1. **環境設定**: 異なる環境に対して異なるネームスペースまたは設定を使用する 2. **パフォーマンスチューニング**: デフォルト値から始めて、特定のニーズに基づいて調整する 3. **品質フィルタリング**: minScoreを使用して低品質な結果を除外する 4. **ランタイムの柔軟性**: 動的なシナリオに対してランタイムで設定を上書きする 5. **ドキュメント化**: チームメンバーのために特定の設定選択をドキュメント化する ## マイグレーションガイド 既存のベクトルクエリツールは変更なしで引き続き動作します。データベース設定を追加するには: ```diff const vectorTool = createVectorQueryTool({ vectorStoreName: 'pinecone', indexName: 'documents', model: embedModel, + databaseConfig: { + pinecone: { + namespace: 'production' + } + } }); ``` ## 関連 - [createVectorQueryTool()](/reference/tools/vector-query-tool) - [Hybrid Vector Search](/examples/rag/query/hybrid-vector-search.mdx) - [Metadata Filters](/reference/rag/metadata-filters) --- title: "リファレンス: MDocument | ドキュメント処理 | RAG | Mastra Docs" description: ドキュメント処理とチャンク化を担当するMastraのMDocumentクラスのドキュメントです。 --- # MDocument [JA] Source: https://mastra.ai/ja/reference/rag/document MDocumentクラスは、RAGアプリケーション向けにドキュメントを処理します。主なメソッドは `.chunk()` と `.extractMetadata()` です。 ## コンストラクタ }>", description: "テキストコンテンツとオプションのメタデータを含むドキュメントチャンクの配列", }, { name: "type", type: "'text' | 'html' | 'markdown' | 'json' | 'latex'", description: "ドキュメントコンテンツの種類", }, ]} /> ## 静的メソッド ### fromText() プレーンテキストの内容からドキュメントを作成します。 ```typescript static fromText(text: string, metadata?: Record): MDocument ``` ### fromHTML() HTMLコンテンツからドキュメントを作成します。 ```typescript static fromHTML(html: string, metadata?: Record): MDocument ``` ### fromMarkdown() Markdownコンテンツからドキュメントを作成します。 ```typescript static fromMarkdown(markdown: string, metadata?: Record): MDocument ``` ### fromJSON() JSONコンテンツからドキュメントを作成します。 ```typescript static fromJSON(json: string, metadata?: Record): MDocument ``` ## インスタンスメソッド ### chunk() ドキュメントをチャンクに分割し、オプションでメタデータを抽出します。 ```typescript async chunk(params?: ChunkParams): Promise ``` 詳細なオプションについては、[chunk() リファレンス](./chunk) を参照してください。 ### getDocs() 処理済みドキュメントチャンクの配列を返します。 ```typescript getDocs(): Chunk[] ``` ### getText() チャンクからテキスト文字列の配列を返します。 ```typescript getText(): string[] ``` ### getMetadata() チャンクからメタデータオブジェクトの配列を返します。 ```typescript getMetadata(): Record[] ``` ### extractMetadata() 指定したエクストラクターを使用してメタデータを抽出します。詳細は [ExtractParams リファレンス](./extract-params) を参照してください。 ```typescript async extractMetadata(params: ExtractParams): Promise ``` ## 例 ```typescript import { MDocument } from "@mastra/rag"; // Create document from text const doc = MDocument.fromText("Your content here"); // Split into chunks with metadata extraction const chunks = await doc.chunk({ strategy: "markdown", headers: [ ["#", "title"], ["##", "section"], ], extract: { summary: true, // Extract summaries with default settings keywords: true, // Extract keywords with default settings }, }); // Get processed chunks const docs = doc.getDocs(); const texts = doc.getText(); const metadata = doc.getMetadata(); ``` --- title: "リファレンス: embed() | ドキュメント埋め込み | RAG | Mastra ドキュメント" description: MastraでAI SDKを使用した埋め込み機能のドキュメント。 --- # 埋め込み [JA] Source: https://mastra.ai/ja/reference/rag/embeddings Mastraは、AI SDKの`embed`および`embedMany`関数を使用してテキスト入力のベクトル埋め込みを生成し、類似性検索やRAGワークフローを実現します。 ## 単一埋め込み `embed` 関数は、単一のテキスト入力に対してベクトル埋め込みを生成します。 ```typescript import { embed } from "ai"; const result = await embed({ model: openai.embedding("text-embedding-3-small"), value: "Your text to embed", maxRetries: 2, // optional, defaults to 2 }); ``` ### パラメータ ", description: "埋め込むテキストコンテンツまたはオブジェクト", }, { name: "maxRetries", type: "number", description: "埋め込み呼び出しごとの最大リトライ回数。リトライを無効にするには0を設定します。", isOptional: true, defaultValue: "2", }, { name: "abortSignal", type: "AbortSignal", description: "リクエストをキャンセルするためのオプションのアボートシグナル", isOptional: true, }, { name: "headers", type: "Record", description: "リクエストに追加するHTTPヘッダー(HTTPベースのプロバイダーのみ)", isOptional: true, }, ]} /> ### 戻り値 ## 複数の埋め込み 複数のテキストを一度に埋め込むには、`embedMany` 関数を使用します。 ```typescript import { embedMany } from "ai"; const result = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: ["First text", "Second text", "Third text"], maxRetries: 2, // optional, defaults to 2 }); ``` ### パラメータ []", description: "埋め込むテキストコンテンツまたはオブジェクトの配列", }, { name: "maxRetries", type: "number", description: "埋め込み呼び出しごとの最大リトライ回数。リトライを無効にするには0を設定します。", isOptional: true, defaultValue: "2", }, { name: "abortSignal", type: "AbortSignal", description: "リクエストをキャンセルするためのオプションのアボートシグナル", isOptional: true, }, { name: "headers", type: "Record", description: "リクエスト用の追加HTTPヘッダー(HTTPベースのプロバイダーのみ)", isOptional: true, }, ]} /> ### 戻り値 ## 使用例 ```typescript import { embed, embedMany } from "ai"; import { openai } from "@ai-sdk/openai"; // Single embedding const singleResult = await embed({ model: openai.embedding("text-embedding-3-small"), value: "What is the meaning of life?", }); // Multiple embeddings const multipleResult = await embedMany({ model: openai.embedding("text-embedding-3-small"), values: [ "First question about life", "Second question about universe", "Third question about everything", ], }); ``` Vercel AI SDK における埋め込みの詳細については、以下をご覧ください: - [AI SDK 埋め込みの概要](https://sdk.vercel.ai/docs/ai-sdk-core/embeddings) - [embed()](https://sdk.vercel.ai/docs/reference/ai-sdk-core/embed) - [embedMany()](https://sdk.vercel.ai/docs/reference/ai-sdk-core/embed-many) --- title: "リファレンス: ExtractParams | ドキュメント処理 | RAG | Mastra ドキュメント" description: Mastraにおけるメタデータ抽出設定のドキュメント。 --- # ExtractParams [JA] Source: https://mastra.ai/ja/reference/rag/extract-params ExtractParamsは、LLM解析を用いてドキュメントチャンクからメタデータを抽出する設定を行います。 ## 例 ```typescript showLineNumbers copy import { MDocument } from "@mastra/rag"; const doc = MDocument.fromText(text); const chunks = await doc.chunk({ extract: { title: true, // Extract titles using default settings summary: true, // Generate summaries using default settings keywords: true, // Extract keywords using default settings }, }); // Example output: // chunks[0].metadata = { // documentTitle: "AI Systems Overview", // sectionSummary: "Overview of artificial intelligence concepts and applications", // excerptKeywords: "KEYWORDS: AI, machine learning, algorithms" // } ``` ## パラメーター `extract` パラメーターは以下のフィールドを受け付けます: ## 抽出器の引数 ### TitleExtractorsArgs ### SummaryExtractArgs ### QuestionAnswerExtractArgs ### KeywordExtractArgs ## 高度な例 ```typescript showLineNumbers copy import { MDocument } from "@mastra/rag"; const doc = MDocument.fromText(text); const chunks = await doc.chunk({ extract: { // Title extraction with custom settings title: { nodes: 2, // Extract 2 title nodes nodeTemplate: "Generate a title for this: {context}", combineTemplate: "Combine these titles: {context}", }, // Summary extraction with custom settings summary: { summaries: ["self"], // Generate summaries for current chunk promptTemplate: "Summarize this: {context}", }, // Question generation with custom settings questions: { questions: 3, // Generate 3 questions promptTemplate: "Generate {numQuestions} questions about: {context}", embeddingOnly: false, }, // Keyword extraction with custom settings keywords: { keywords: 5, // Extract 5 keywords promptTemplate: "Extract {maxKeywords} key terms from: {context}", }, }, }); // Example output: // chunks[0].metadata = { // documentTitle: "AI in Modern Computing", // sectionSummary: "Overview of AI concepts and their applications in computing", // questionsThisExcerptCanAnswer: "1. What is machine learning?\n2. How do neural networks work?", // excerptKeywords: "1. Machine learning\n2. Neural networks\n3. Training data" // } ``` ## タイトル抽出のためのドキュメントグループ化 `TitleExtractor` を使用する際、各チャンクの `metadata` フィールドに共通の `docId` を指定することで、複数のチャンクをまとめてタイトル抽出することができます。同じ `docId` を持つすべてのチャンクは、同じ抽出タイトルを受け取ります。`docId` が設定されていない場合、各チャンクはタイトル抽出のために個別のドキュメントとして扱われます。 **例:** ```ts import { MDocument } from "@mastra/rag"; const doc = new MDocument({ docs: [ { text: "chunk 1", metadata: { docId: "docA" } }, { text: "chunk 2", metadata: { docId: "docA" } }, { text: "chunk 3", metadata: { docId: "docB" } }, ], type: "text", }); await doc.extractMetadata({ title: true }); // 最初の2つのチャンクは同じタイトルを共有し、3つ目のチャンクには別のタイトルが割り当てられます。 ``` --- title: "リファレンス: GraphRAG | グラフベースRAG | RAG | Mastra ドキュメント" description: MastraのGraphRAGクラスのドキュメント。グラフベースの検索拡張生成手法を実装しています。 --- # GraphRAG [JA] Source: https://mastra.ai/ja/reference/rag/graph-rag `GraphRAG` クラスは、グラフベースのリトリーバル拡張生成手法を実装しています。ドキュメントのチャンクからナレッジグラフを作成し、ノードはドキュメントを、エッジはセマンティックな関係を表します。これにより、直接的な類似性マッチングだけでなく、グラフの探索を通じて関連コンテンツを発見することも可能になります。 ## 基本的な使い方 ```typescript import { GraphRAG } from "@mastra/rag"; const graphRag = new GraphRAG({ dimension: 1536, threshold: 0.7, }); // Create the graph from chunks and embeddings graphRag.createGraph(documentChunks, embeddings); // Query the graph with embedding const results = await graphRag.query({ query: queryEmbedding, topK: 10, randomWalkSteps: 100, restartProb: 0.15, }); ``` ## コンストラクタのパラメータ ## メソッド ### createGraph ドキュメントチャンクとその埋め込みからナレッジグラフを作成します。 ```typescript createGraph(chunks: GraphChunk[], embeddings: GraphEmbedding[]): void ``` #### パラメータ ### query ベクトル類似度とグラフ探索を組み合わせたグラフベースの検索を実行します。 ```typescript query({ query, topK = 10, randomWalkSteps = 100, restartProb = 0.15 }: { query: number[]; topK?: number; randomWalkSteps?: number; restartProb?: number; }): RankedNode[] ``` #### パラメータ #### 戻り値 `RankedNode` オブジェクトの配列を返します。各ノードには以下が含まれます: ", description: "チャンクに関連付けられた追加メタデータ", }, { name: "score", type: "number", description: "グラフ探索による総合関連スコア", }, ]} /> ## 高度な例 ```typescript const graphRag = new GraphRAG({ dimension: 1536, threshold: 0.8, // Stricter similarity threshold }); // Create graph from chunks and embeddings graphRag.createGraph(documentChunks, embeddings); // Query with custom parameters const results = await graphRag.query({ query: queryEmbedding, topK: 5, randomWalkSteps: 200, restartProb: 0.2, }); ``` ## 関連 - [createGraphRAGTool](../tools/graph-rag-tool) --- title: "リファレンス: Lance Vector Store | Vector Databases | RAG | Mastra Docs" description: "MastraのLanceVectorStoreクラスのドキュメント。Lance列形式に基づく組み込みベクトルデータベースであるLanceDBを使用してベクトル検索を提供します。" --- # Lance Vector Store [JA] Source: https://mastra.ai/ja/reference/rag/lance LanceVectorStoreクラスは、Lance列形式上に構築された組み込みベクトルデータベースである[LanceDB](https://lancedb.github.io/lancedb/)を使用してベクトル検索を提供します。ローカル開発と本番デプロイメントの両方において、効率的なストレージと高速な類似性検索を提供します。 ## Factory Method LanceVectorStoreは作成にファクトリーパターンを使用します。コンストラクタを直接使用するのではなく、静的な`create()`メソッドを使用する必要があります。 ## コンストラクタの例 静的なcreateメソッドを使用して`LanceVectorStore`インスタンスを作成できます: ```ts import { LanceVectorStore } from "@mastra/lance"; // ローカルデータベースに接続 const vectorStore = await LanceVectorStore.create("/path/to/db"); // LanceDBクラウドデータベースに接続 const cloudStore = await LanceVectorStore.create("db://host:port"); // オプション付きでクラウドデータベースに接続 const s3Store = await LanceVectorStore.create("s3://bucket/db", { storageOptions: { timeout: '60s' } }); ``` ## メソッド ### createIndex() #### LanceIndexConfig ### createTable() [] | TableLike", description: "テーブルの初期データ", }, { name: "options", type: "Partial", isOptional: true, description: "追加のテーブル作成オプション", }, ]} /> ### upsert() []", isOptional: true, description: "各ベクトルのメタデータ", }, { name: "ids", type: "string[]", isOptional: true, description: "オプションのベクトルID(提供されない場合は自動生成)", }, ]} /> ### query() ", isOptional: true, description: "メタデータフィルター", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "結果にベクトルを含めるかどうか", }, { name: "columns", type: "string[]", isOptional: true, defaultValue: "[]", description: "結果に含める特定の列", }, { name: "includeAllColumns", type: "boolean", isOptional: true, defaultValue: "false", description: "結果にすべての列を含めるかどうか", }, ]} /> ### listTables() テーブル名の配列を文字列として返します。 ```typescript copy const tables = await vectorStore.listTables(); // ['my_vectors', 'embeddings', 'documents'] ``` ### getTableSchema() 指定されたテーブルのスキーマを返します。 ### deleteTable() ### deleteAllTables() データベース内のすべてのテーブルを削除します。 ### listIndexes() インデックス名の配列を文字列として返します。 ### describeIndex() インデックスに関する情報を返します: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; type: "ivfflat" | "hnsw"; config: { m?: number; efConstruction?: number; numPartitions?: number; numSubVectors?: number; }; } ``` ### deleteIndex() ### updateVector() ", description: "新しいメタデータ値", isOptional: true, }, ], }, ], }, ]} /> ### deleteVector() ### close() データベース接続を閉じます。 ## レスポンスタイプ クエリ結果は以下の形式で返されます: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true document?: string; // Document text if available } ``` ## エラーハンドリング ストアは型付きエラーをスローし、それをキャッチできます: ```typescript copy try { await store.query({ tableName: "my_vectors", queryVector: queryVector, }); } catch (error) { if (error instanceof Error) { console.log(error.message); } } ``` ## ベストプラクティス - 用途に適したインデックスタイプを使用してください: - メモリに制約がない場合は、より良いリコールとパフォーマンスのためにHNSW - 大規模データセットでのメモリ効率を重視する場合はIVF - 大規模データセットで最適なパフォーマンスを得るには、`numPartitions`と`numSubVectors`の値の調整を検討してください - データベースの使用が完了したら、`close()`メソッドを使用して適切に接続を閉じてください - フィルタリング操作を簡素化するため、一貫したスキーマでメタデータを保存してください ## 関連 - [メタデータフィルター](./metadata-filters) --- title: "デフォルトベクトルストア | ベクターデータベース | RAG | Mastra ドキュメント" description: Mastraにおける、ベクター拡張機能を持つLibSQLを使用したベクター検索を提供するLibSQLVectorクラスのドキュメント。 --- # LibSQLVector ストア [JA] Source: https://mastra.ai/ja/reference/rag/libsql LibSQL ストレージ実装は、SQLite互換のベクトル検索 [LibSQL](https://github.com/tursodatabase/libsql)(ベクトル拡張機能を持つSQLiteのフォーク)と、ベクトル拡張機能を持つ[Turso](https://turso.tech/)を提供し、軽量で効率的なベクトルデータベースソリューションを提供します。 これは`@mastra/libsql`パッケージの一部であり、メタデータフィルタリングによる効率的なベクトル類似性検索を提供します。 ## インストール デフォルトのベクトルストアはコアパッケージに含まれています: ```bash copy npm install @mastra/libsql@latest ``` ## 使用方法 ```typescript copy showLineNumbers import { LibSQLVector } from "@mastra/libsql"; // Create a new vector store instance const store = new LibSQLVector({ connectionUrl: process.env.DATABASE_URL, // Optional: for Turso cloud databases authToken: process.env.DATABASE_AUTH_TOKEN, }); // Create an index await store.createIndex({ indexName: "myCollection", dimension: 1536, }); // Add vectors with metadata const vectors = [[0.1, 0.2, ...], [0.3, 0.4, ...]]; const metadata = [ { text: "first document", category: "A" }, { text: "second document", category: "B" } ]; await store.upsert({ indexName: "myCollection", vectors, metadata, }); // Query similar vectors const queryVector = [0.1, 0.2, ...]; const results = await store.query({ indexName: "myCollection", queryVector, topK: 10, // top K results filter: { category: "A" } // optional metadata filter }); ``` ## コンストラクタオプション ## メソッド ### createIndex() 新しいベクトルコレクションを作成します。インデックス名は文字またはアンダースコアで始まり、文字、数字、アンダースコアのみを含むことができます。次元は正の整数である必要があります。 ### upsert() ベクトルとそのメタデータをインデックスに追加または更新します。トランザクションを使用して、すべてのベクトルが原子的に挿入されることを保証します - 挿入が失敗した場合、操作全体がロールバックされます。 []", isOptional: true, description: "各ベクトルのメタデータ", }, { name: "ids", type: "string[]", isOptional: true, description: "オプションのベクトルID(提供されない場合は自動生成)", }, ]} /> ### query() オプションのメタデータフィルタリングを使用して類似ベクトルを検索します。 ### describeIndex() インデックスに関する情報を取得します。 戻り値: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() インデックスとそのすべてのデータを削除します。 ### listIndexes() データベース内のすべてのベクトルインデックスを一覧表示します。 戻り値:`Promise` ### truncateIndex() インデックス構造を維持しながら、インデックスからすべてのベクトルを削除します。 ### updateVector() IDによって特定のベクトルエントリを新しいベクトルデータやメタデータで更新します。 ", isOptional: true, description: "更新する新しいメタデータ", }, ]} /> ### deleteVector() IDによってインデックスから特定のベクトルエントリを削除します。 ## レスポンスタイプ クエリ結果は以下の形式で返されます: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true } ``` ## エラー処理 ストアは異なる失敗ケースに対して特定のエラーをスローします: ```typescript copy try { await store.query({ indexName: "my-collection", queryVector: queryVector, }); } catch (error) { // Handle specific error cases if (error.message.includes("Invalid index name format")) { console.error( "Index name must start with a letter/underscore and contain only alphanumeric characters", ); } else if (error.message.includes("Table not found")) { console.error("The specified index does not exist"); } else { console.error("Vector store error:", error.message); } } ``` 一般的なエラーケースには以下が含まれます: - 無効なインデックス名の形式 - 無効なベクトル次元 - テーブル/インデックスが見つからない - データベース接続の問題 - アップサート中のトランザクション失敗 ## 関連 - [メタデータフィルター](./metadata-filters) --- title: "リファレンス: メタデータフィルター | メタデータフィルタリング | RAG | Mastra ドキュメント" description: Mastra のメタデータフィルタリング機能に関するドキュメント。これにより、さまざまなベクトルストアでのベクトル検索結果に対して精密なクエリが可能になります。 --- # メタデータフィルター [JA] Source: https://mastra.ai/ja/reference/rag/metadata-filters Mastra は、すべてのベクトルストアで統一されたメタデータフィルタリング構文を提供しており、MongoDB/Sift クエリ構文に基づいています。各ベクトルストアは、これらのフィルターを自分たちのネイティブな形式に変換します。 ## 基本的な例 ```typescript import { PgVector } from "@mastra/pg"; const store = new PgVector({ connectionString }); const results = await store.query({ indexName: "my_index", queryVector: queryVector, topK: 10, filter: { category: "electronics", // Simple equality price: { $gt: 100 }, // Numeric comparison tags: { $in: ["sale", "new"] }, // Array membership }, }); ``` ## サポートされている演算子 ## 共通ルールと制限事項 1. フィールド名は以下のことができません: - ネストされたフィールドを参照する場合を除き、ドット(.)を含むこと - $で始まる、またはヌル文字を含むこと - 空文字列であること 2. 値は以下でなければなりません: - 有効なJSON型(文字列、数値、真偽値、オブジェクト、配列) - undefinedでないこと - 演算子に対して適切な型であること(例:数値比較には数値) 3. 論理演算子: - 有効な条件を含む必要があります - 空であってはなりません - 適切にネストされている必要があります - トップレベル、または他の論理演算子内でのみ使用可能です - フィールドレベルやフィールド内でネストして使用することはできません - 演算子内で使用することはできません - 有効: `{ "$and": [{ "field": { "$gt": 100 } }] }` - 有効: `{ "$or": [{ "$and": [{ "field": { "$gt": 100 } }] }] }` - 無効: `{ "field": { "$and": [{ "$gt": 100 }] } }` - 無効: `{ "field": { "$gt": { "$and": [{...}] } } }` 4. $not演算子: - オブジェクトでなければなりません - 空であってはなりません - フィールドレベルまたはトップレベルで使用可能です - 有効: `{ "$not": { "field": "value" } }` - 有効: `{ "field": { "$not": { "$eq": "value" } } }` 5. 演算子のネスト: - 論理演算子はフィールド条件を含む必要があり、直接演算子を含んではいけません - 有効: `{ "$and": [{ "field": { "$gt": 100 } }] }` - 無効: `{ "$and": [{ "$gt": 100 }] }` ## ストア固有の注意事項 ### Astra - ネストされたフィールドクエリはドット記法を使用してサポートされています - 配列フィールドはメタデータで明示的に配列として定義する必要があります - メタデータ値は大文字小文字を区別します ### ChromaDB - Whereフィルターは、フィルターされたフィールドがメタデータに存在する結果のみを返します - 空のメタデータフィールドはフィルター結果に含まれません - 負のマッチング(例:$neはフィールドが欠落しているドキュメントにマッチしません)にはメタデータフィールドが存在する必要があります ### Cloudflare Vectorize - フィルタリングを使用する前に明示的なメタデータインデックス作成が必要です - フィルターしたいフィールドをインデックス化するには`createMetadataIndex()`を使用してください - Vectorizeインデックスあたり最大10個のメタデータインデックス - 文字列値は最初の64バイトまでインデックス化されます(UTF-8境界で切り捨て) - 数値はfloat64精度を使用します - フィルターJSONは2048バイト未満である必要があります - フィールド名にドット(.)を含めたり、$で始めることはできません - フィールド名は512文字に制限されています - 新しいメタデータインデックスを作成した後、フィルターされた結果に含めるためにベクターを再アップサートする必要があります - 範囲クエリは非常に大きなデータセット(約1000万以上のベクター)では精度が低下する可能性があります ### LibSQL - ドット記法を使用したネストされたオブジェクトクエリをサポートします - 配列フィールドは有効なJSON配列を含むことを確認するために検証されます - 数値比較は適切な型処理を維持します - 条件内の空の配列は適切に処理されます - メタデータは効率的なクエリのためにJSONB列に格納されます ### PgVector - PostgreSQLのネイティブJSONクエリ機能を完全サポートします - ネイティブ配列関数を使用した配列操作の効率的な処理 - 数値、文字列、ブール値の適切な型処理 - ネストされたフィールドクエリは内部的にPostgreSQLのJSONパス構文を使用します - メタデータは効率的なインデックス化のためにJSONB列に格納されます ### Pinecone - メタデータフィールド名は512文字に制限されています - 数値は±1e38の範囲内である必要があります - メタデータ内の配列は合計サイズが64KBに制限されています - ネストされたオブジェクトはドット記法で平坦化されます - メタデータの更新はメタデータオブジェクト全体を置き換えます ### Qdrant - ネストされた条件を持つ高度なフィルタリングをサポートします - ペイロード(メタデータ)フィールドはフィルタリングのために明示的にインデックス化する必要があります - 地理空間クエリの効率的な処理 - null値と空の値の特別な処理 - ベクター固有のフィルタリング機能 - 日時値はRFC 3339形式である必要があります ### Upstash - メタデータフィールドキーは512文字制限があります - クエリサイズは制限されています(大きなIN句は避けてください) - フィルター内のnull/undefined値はサポートされていません - 内部的にSQL風の構文に変換されます - 大文字小文字を区別する文字列比較 - メタデータの更新はアトミックです ### MongoDB - メタデータフィルターのためのMongoDB/Siftクエリ構文を完全サポートします - すべての標準的な比較、配列、論理、要素演算子をサポートします - メタデータ内のネストされたフィールドと配列をサポートします - フィルタリングは`filter`と`documentFilter`オプションを使用して、それぞれ`metadata`と元のドキュメントコンテンツの両方に適用できます - `filter`はメタデータオブジェクトに適用され、`documentFilter`は元のドキュメントフィールドに適用されます - フィルターサイズや複雑さに人為的な制限はありません(MongoDBクエリ制限の対象) - 最適なパフォーマンスのためにメタデータフィールドのインデックス化が推奨されます ### Couchbase - 現在、メタデータフィルターのサポートはありません。フィルタリングは結果を取得した後にクライアント側で行うか、より複雑なクエリについてはCouchbase SDKのSearch機能を直接使用する必要があります。 ## 関連 - [Astra](./astra) - [Chroma](./chroma) - [Cloudflare Vectorize](./vectorize) - [LibSQL](./libsql) - [MongoDB](./mongodb) - [PgStore](./pg) - [Pinecone](./pinecone) - [Qdrant](./qdrant) - [Upstash](./upstash) --- title: "リファレンス: MongoDB ベクターストア | ベクターデータベース | RAG | Mastra ドキュメント" description: Mastra の MongoDBVector クラスのドキュメント。MongoDB Atlas および Atlas Vector Search を使用したベクター検索を提供します。 --- # MongoDB Vector Store [JA] Source: https://mastra.ai/ja/reference/rag/mongodb `MongoDBVector` クラスは、[MongoDB Atlas Vector Search](https://www.mongodb.com/docs/atlas/atlas-vector-search/) を使用したベクター検索を提供します。これにより、MongoDB コレクション内で効率的な類似性検索とメタデータフィルタリングが可能になります。 ## インストール ```bash copy npm install @mastra/mongodb ``` ## 使用例 ```typescript copy showLineNumbers import { MongoDBVector } from "@mastra/mongodb"; const store = new MongoDBVector({ url: process.env.MONGODB_URL, database: process.env.MONGODB_DATABASE, }); ``` ## コンストラクターオプション ## メソッド ### createIndex() MongoDBに新しいベクターインデックス(コレクション)を作成します。 ### upsert() コレクションにベクターとそのメタデータを追加または更新します。 []", isOptional: true, description: "各ベクターのメタデータ", }, { name: "ids", type: "string[]", isOptional: true, description: "オプションのベクターID(提供されない場合は自動生成)", }, ]} /> ### query() オプションのメタデータフィルタリングを使用して類似ベクターを検索します。 ", isOptional: true, description: "メタデータフィルター(`metadata`フィールドに適用)", }, { name: "documentFilter", type: "Record", isOptional: true, description: "元のドキュメントフィールドのフィルター(メタデータだけでなく)", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "結果にベクターデータを含めるかどうか", }, { name: "minScore", type: "number", isOptional: true, defaultValue: "0", description: "最小類似性スコアの閾値", }, ]} /> ### describeIndex() インデックス(コレクション)に関する情報を返します。 戻り値: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() コレクションとそのすべてのデータを削除します。 ### listIndexes() MongoDBデータベース内のすべてのベクターコレクションをリストします。 戻り値:`Promise` ### updateVector() IDによって特定のベクターエントリを新しいベクターデータやメタデータで更新します。 ", isOptional: true, description: "更新する新しいメタデータ", }, ]} /> ### deleteVector() IDによってインデックスから特定のベクターエントリを削除します。 ### disconnect() MongoDBクライアントの接続を閉じます。ストアの使用が終わったら呼び出す必要があります。 ## レスポンスタイプ クエリ結果は次の形式で返されます: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true } ``` ## エラー処理 ストアは捕捉可能な型付きエラーをスローします: ```typescript copy try { await store.query({ indexName: "my_collection", queryVector: queryVector, }); } catch (error) { // Handle specific error cases if (error.message.includes("Invalid collection name")) { console.error( "Collection name must start with a letter or underscore and contain only valid characters.", ); } else if (error.message.includes("Collection not found")) { console.error("The specified collection does not exist"); } else { console.error("Vector store error:", error.message); } } ``` ## ベストプラクティス - クエリのパフォーマンスを最適化するために、フィルターで使用するメタデータフィールドにインデックスを作成してください。 - 予期しないクエリ結果を避けるために、メタデータ内のフィールド名を一貫して使用してください。 - 効率的な検索を維持するために、インデックスやコレクションの統計情報を定期的に監視してください。 ## 関連 - [メタデータフィルター](./metadata-filters) --- title: "リファレンス: OpenSearch ベクトルストア | ベクトルデータベース | RAG | Mastra ドキュメント" description: Mastraの OpenSearchVector クラスに関するドキュメント。OpenSearchを使用したベクトル検索を提供します。 --- # OpenSearch ベクトルストア [JA] Source: https://mastra.ai/ja/reference/rag/opensearch OpenSearchVectorクラスは、[OpenSearch](https://opensearch.org/)を使用してベクトル検索を提供します。OpenSearchは強力なオープンソースの検索・分析エンジンです。このクラスはOpenSearchのk-NN機能を活用して、効率的なベクトル類似性検索を実行します。 ## コンストラクタオプション ## メソッド ### createIndex() 指定された設定で新しいインデックスを作成します。 ### listIndexes() OpenSearchインスタンス内のすべてのインデックスを一覧表示します。 戻り値: `Promise` ### describeIndex() インデックスに関する情報を取得します。 ### deleteIndex() ### upsert() []", description: "各ベクトルに対応するメタデータオブジェクトの配列", isOptional: true, }, { name: "ids", type: "string[]", description: "ベクトルのIDの任意の配列。提供されない場合、ランダムなIDが生成されます", isOptional: true, }, ]} /> ### query() ### updateVector() IDによって特定のベクトルエントリを新しいベクトルデータやメタデータで更新します。 ", description: "新しいメタデータ", isOptional: true, }, ]} /> ### deleteVector() インデックスから特定のベクトルエントリをIDによって削除します。 ## 関連 - [メタデータフィルター](./metadata-filters) --- title: "リファレンス: PG Vector Store | ベクターデータベース | RAG | Mastra ドキュメント" description: Mastra の PgVector クラスのドキュメント。pgvector 拡張機能を使用した PostgreSQL によるベクター検索を提供します。 --- # PG Vector Store [JA] Source: https://mastra.ai/ja/reference/rag/pg PgVectorクラスは、[PostgreSQL](https://www.postgresql.org/)と[pgvector](https://github.com/pgvector/pgvector)拡張機能を使用したベクトル検索を提供します。 既存のPostgreSQLデータベース内で堅牢なベクトル類似性検索機能を実現します。 ## コンストラクタオプション ## コンストラクタの例 `PgVector`は設定オブジェクトを使用してインスタンス化できます(オプションのschemaNameを含む): ```ts import { PgVector } from "@mastra/pg"; const vectorStore = new PgVector({ connectionString: "postgresql://user:password@localhost:5432/mydb", schemaName: "custom_schema", // optional }); ``` ## メソッド ### createIndex() #### IndexConfig #### メモリ要件 HNSWインデックスの構築時には多くの共有メモリが必要です。100Kベクトルの場合: - 小さい次元(64d):デフォルト設定で約60MB - 中程度の次元(256d):デフォルト設定で約180MB - 大きい次元(384d以上):デフォルト設定で約250MB以上 M値やefConstruction値を大きくすると、必要なメモリも大幅に増加します。必要に応じてシステムの共有メモリ上限を調整してください。 ### upsert() []", isOptional: true, description: "各ベクトルのメタデータ", }, { name: "ids", type: "string[]", isOptional: true, description: "オプションのベクトルID(指定しない場合は自動生成)", }, ]} /> ### query() ", isOptional: true, description: "メタデータフィルター", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "結果にベクトルを含めるかどうか", }, { name: "minScore", type: "number", isOptional: true, defaultValue: "0", description: "最小類似度スコアのしきい値", }, { name: "options", type: "{ ef?: number; probes?: number }", isOptional: true, description: "HNSWおよびIVFインデックス用の追加オプション", properties: [ { type: "object", parameters: [ { name: "ef", type: "number", description: "HNSW検索パラメータ", isOptional: true, }, { name: "probes", type: "number", description: "IVF検索パラメータ", isOptional: true, }, ], }, ], }, ]} /> ### listIndexes() インデックス名の配列(文字列)を返します。 ### describeIndex() 返り値: ```typescript copy interface PGIndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; type: "flat" | "hnsw" | "ivfflat"; config: { m?: number; efConstruction?: number; lists?: number; probes?: number; }; } ``` ### deleteIndex() ### updateVector() ", description: "新しいメタデータ値", isOptional: true, }, ], }, ], }, ]} /> 既存のベクトルをIDで更新します。`vector`または`metadata`のいずれか一方以上を指定する必要があります。 ```typescript copy // Update just the vector await pgVector.updateVector({ indexName: "my_vectors", id: "vector123", update: { vector: [0.1, 0.2, 0.3], }, }); // Update just the metadata await pgVector.updateVector({ indexName: "my_vectors", id: "vector123", update: { metadata: { label: "updated" }, }, }); // Update both vector and metadata await pgVector.updateVector({ indexName: "my_vectors", id: "vector123", update: { vector: [0.1, 0.2, 0.3], metadata: { label: "updated" }, }, }); ``` ### deleteVector() 指定したインデックスからIDで単一のベクトルを削除します。 ```typescript copy await pgVector.deleteVector({ indexName: "my_vectors", id: "vector123" }); ``` ### disconnect() データベース接続プールを閉じます。ストアの使用が終わったら呼び出す必要があります。 ### buildIndex() 指定したメトリックと設定でインデックスを作成または再作成します。新しいインデックスを作成する前に、既存のインデックスは削除されます。 ```typescript copy // Define HNSW index await pgVector.buildIndex("my_vectors", "cosine", { type: "hnsw", hnsw: { m: 8, efConstruction: 32, }, }); // Define IVF index await pgVector.buildIndex("my_vectors", "cosine", { type: "ivfflat", ivf: { lists: 100, }, }); // Define flat index await pgVector.buildIndex("my_vectors", "cosine", { type: "flat", }); ``` ## レスポンスタイプ クエリ結果は次の形式で返されます: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true } ``` ## エラー処理 このストアは型付きエラーをスローし、キャッチすることができます。 ```typescript copy try { await store.query({ indexName: "index_name", queryVector: queryVector, }); } catch (error) { if (error instanceof VectorStoreError) { console.log(error.code); // 'connection_failed' | 'invalid_dimension' | etc console.log(error.details); // Additional error context } } ``` ## ベストプラクティス - 最適なパフォーマンスを確保するために、インデックス設定を定期的に評価してください。 - データセットのサイズやクエリ要件に応じて、`lists` や `m` などのパラメータを調整しましょう。 - 特に大きなデータ変更の後は、効率を維持するためにインデックスを定期的に再構築してください。 ## 関連 - [メタデータフィルター](./metadata-filters) --- title: "リファレンス: Pinecone Vector Store | ベクターデータベース | RAG | Mastra ドキュメント" description: Mastra における PineconeVector クラスのドキュメント。Pinecone のベクターデータベースへのインターフェースを提供します。 --- # Pinecone ベクターストア [JA] Source: https://mastra.ai/ja/reference/rag/pinecone PineconeVector クラスは、[Pinecone](https://www.pinecone.io/) のベクターデータベースへのインターフェースを提供します。 リアルタイムのベクター検索を提供し、ハイブリッド検索、メタデータフィルタリング、ネームスペース管理などの機能を備えています。 ## コンストラクターオプション ## メソッド ### createIndex() ### upsert() []", isOptional: true, description: "各ベクトルのメタデータ", }, { name: "ids", type: "string[]", isOptional: true, description: "オプションのベクトルID(提供されない場合は自動生成されます)", }, { name: "namespace", type: "string", isOptional: true, description: "ベクトルを保存するオプションの名前空間。異なる名前空間のベクトルは互いに分離されています。", }, ]} /> ### query() ", isOptional: true, description: "クエリのメタデータフィルター", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "結果にベクトルを含めるかどうか", }, { name: "namespace", type: "string", isOptional: true, description: "ベクトルをクエリするオプションの名前空間。指定された名前空間からの結果のみを返します。", }, ]} /> ### listIndexes() インデックス名の文字列配列を返します。 ### describeIndex() 戻り値: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() ### updateVector() ", isOptional: true, description: "更新する新しいメタデータ", }, ]} /> ### deleteVector() ## レスポンスタイプ クエリ結果は次の形式で返されます: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true } ``` ## エラー処理 このストアは型付きエラーをスローし、キャッチすることができます。 ```typescript copy try { await store.query({ indexName: "index_name", queryVector: queryVector, }); } catch (error) { if (error instanceof VectorStoreError) { console.log(error.code); // 'connection_failed' | 'invalid_dimension' | etc console.log(error.details); // Additional error context } } ``` ### 環境変数 必要な環境変数: - `PINECONE_API_KEY`: あなたのPinecone APIキー - `PINECONE_ENVIRONMENT`: Pinecone環境(例: 'us-west1-gcp') ## ハイブリッド検索 Pineconeは、密ベクトルと疎ベクトルを組み合わせることでハイブリッド検索をサポートしています。ハイブリッド検索を利用するには、以下の手順に従ってください。 1. `metric: 'dotproduct'` でインデックスを作成します 2. アップサート時に、`sparseVectors` パラメータを使って疎ベクトルを指定します 3. クエリ時に、`sparseVector` パラメータを使って疎ベクトルを指定します ## 関連 - [メタデータフィルター](./metadata-filters) --- title: "リファレンス: Qdrant ベクトルストア | ベクトルデータベース | RAG | Mastra ドキュメント" description: Mastraとの統合のためのQdrantのドキュメント。Qdrantはベクトルとペイロードを管理するためのベクトル類似性検索エンジンです。 --- # Qdrant ベクトルストア [JA] Source: https://mastra.ai/ja/reference/rag/qdrant QdrantVectorクラスは、[Qdrant](https://qdrant.tech/)を使用したベクトル検索を提供します。Qdrantはベクトル類似性検索エンジンです。 これは、追加のペイロードと拡張フィルタリングサポートを備えたベクトルの保存、検索、管理を行うための便利なAPIを持つ、本番環境対応のサービスを提供します。 ## コンストラクタオプション ## メソッド ### createIndex() ### upsert() []", isOptional: true, description: "各ベクトルのメタデータ", }, { name: "ids", type: "string[]", isOptional: true, description: "オプションのベクトルID(提供されない場合は自動生成されます)", }, ]} /> ### query() ", isOptional: true, description: "クエリのメタデータフィルター", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "結果にベクトルを含めるかどうか", }, ]} /> ### listIndexes() インデックス名の文字列配列を返します。 ### describeIndex() 戻り値: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() ### updateVector() ; }", description: "更新するベクトルやメタデータを含むオブジェクト", }, ]} /> 指定されたインデックス内のベクトルやそのメタデータを更新します。ベクトルとメタデータの両方が提供された場合、両方が更新されます。一方のみが提供された場合、そのみが更新されます。 ### deleteVector() IDによって指定されたインデックスからベクトルを削除します。 ## レスポンスタイプ クエリ結果は以下の形式で返されます: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true } ``` ## エラー処理 ストアは捕捉できる型付きエラーをスローします: ```typescript copy try { await store.query({ indexName: "index_name", queryVector: queryVector, }); } catch (error) { if (error instanceof VectorStoreError) { console.log(error.code); // 'connection_failed' | 'invalid_dimension' | etc console.log(error.details); // Additional error context } } ``` ## 関連 - [メタデータフィルター](./metadata-filters) --- title: "リファレンス: Rerank | ドキュメント検索 | RAG | Mastra ドキュメント" description: Mastra の rerank 機能に関するドキュメント。ベクトル検索結果に対して高度なリランキング機能を提供します。 --- # rerank() [JA] Source: https://mastra.ai/ja/reference/rag/rerank `rerank()` 関数は、セマンティックな関連性、ベクトル類似度、位置に基づくスコアリングを組み合わせることで、ベクトル検索結果に対して高度なリランキング機能を提供します。 ```typescript function rerank( results: QueryResult[], query: string, modelConfig: ModelConfig, options?: RerankerFunctionOptions, ): Promise; ``` ## 使用例 ```typescript import { openai } from "@ai-sdk/openai"; import { rerank } from "@mastra/rag"; const model = openai("gpt-4o-mini"); const rerankedResults = await rerank( vectorSearchResults, "How do I deploy to production?", model, { weights: { semantic: 0.5, vector: 0.3, position: 0.2, }, topK: 3, }, ); ``` ## パラメーター rerank関数は、Vercel AI SDKの任意のLanguageModelを受け付けます。Cohereモデルの`rerank-v3.5`を使用する場合、自動的にCohereの再ランク付け機能が利用されます。 > **注意:** セマンティックスコアリングが再ランク付け時に正しく機能するためには、各結果の`metadata.text`フィールドにテキストコンテンツが含まれている必要があります。 ### RerankerFunctionOptions ## 戻り値 この関数は `RerankResult` オブジェクトの配列を返します: ### ScoringDetails ## 関連 - [createVectorQueryTool](../tools/vector-query-tool) --- title: "リファレンス: Turbopuffer ベクターストア | ベクターデータベース | RAG | Mastra ドキュメント" description: TurbopufferをMastraと統合するためのドキュメント。効率的な類似検索のための高性能ベクターデータベース。 --- # Turbopuffer Vector Store [JA] Source: https://mastra.ai/ja/reference/rag/turbopuffer TurbopufferVector クラスは、RAG アプリケーション向けに最適化された高性能ベクターデータベースである [Turbopuffer](https://turbopuffer.com/) を使用したベクター検索を提供します。Turbopuffer は、高度なフィルタリング機能と効率的なストレージ管理を備えた高速なベクター類似検索を提供します。 ## コンストラクタオプション ## メソッド ### createIndex() ### upsert() []", isOptional: true, description: "各ベクトルのメタデータ", }, { name: "ids", type: "string[]", isOptional: true, description: "オプションのベクトルID(指定されない場合は自動生成)", }, ]} /> ### query() ", isOptional: true, description: "クエリのメタデータフィルター", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "結果にベクトルを含めるかどうか", }, ]} /> ### listIndexes() 文字列としてインデックス名の配列を返します。 ### describeIndex() 返される内容: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() ## 応答タイプ クエリ結果はこの形式で返されます: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true } ``` ## スキーマ構成 `schemaConfigForIndex` オプションを使用すると、異なるインデックスに対して明示的なスキーマを定義できます: ```typescript copy schemaConfigForIndex: (indexName: string) => { // Mastraのデフォルトの埋め込みモデルとメモリメッセージのインデックス: if (indexName === "memory_messages_384") { return { dimensions: 384, schema: { thread_id: { type: "string", filterable: true, }, }, }; } else { throw new Error(`TODO: add schema for index: ${indexName}`); } }; ``` ## エラーハンドリング このストアは、キャッチ可能な型付きエラーをスローします: ```typescript copy try { await store.query({ indexName: "index_name", queryVector: queryVector, }); } catch (error) { if (error instanceof VectorStoreError) { console.log(error.code); // 'connection_failed' | 'invalid_dimension' | etc console.log(error.details); // 追加のエラーコンテキスト } } ``` ## 関連 - [メタデータフィルター](./metadata-filters) --- title: "リファレンス: Upstashベクトルストア | ベクトルデータベース | RAG | Mastraドキュメント" description: Mastraにおける、Upstash Vectorを使用したベクトル検索を提供するUpstashVectorクラスのドキュメント。 --- # Upstash Vector Store [JA] Source: https://mastra.ai/ja/reference/rag/upstash UpstashVectorクラスは、[Upstash Vector](https://upstash.com/vector)を使用したベクトル検索を提供します。Upstash Vectorは、メタデータフィルタリング機能を備えたベクトル類似性検索を提供するサーバーレスベクトルデータベースサービスです。 ## コンストラクタオプション ## メソッド ### createIndex() 注意:Upstashではインデックスは自動的に作成されるため、このメソッドは何も実行しません。 ### upsert() []", isOptional: true, description: "各ベクトルのメタデータ", }, { name: "ids", type: "string[]", isOptional: true, description: "オプションのベクトルID(提供されない場合は自動生成されます)", }, ]} /> ### query() ", isOptional: true, description: "クエリのメタデータフィルター", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "結果にベクトルを含めるかどうか", }, ]} /> ### listIndexes() インデックス名(名前空間)の文字列配列を返します。 ### describeIndex() 戻り値: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() ### updateVector() `update`オブジェクトは以下のプロパティを持つことができます: - `vector`(オプション):新しいベクトルを表す数値の配列。 - `metadata`(オプション):メタデータのキーと値のペアのレコード。 `vector`も`metadata`も提供されない場合、または`metadata`のみが提供される場合はエラーがスローされます。 ### deleteVector() 指定されたインデックスからIDによってアイテムを削除しようとします。削除に失敗した場合はエラーメッセージをログに記録します。 ## レスポンスタイプ クエリ結果は以下の形式で返されます: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; // Only included if includeVector is true } ``` ## エラー処理 ストアは捕捉可能な型付きエラーをスローします: ```typescript copy try { await store.query({ indexName: "index_name", queryVector: queryVector, }); } catch (error) { if (error instanceof VectorStoreError) { console.log(error.code); // 'connection_failed' | 'invalid_dimension' | etc console.log(error.details); // Additional error context } } ``` ## 環境変数 必要な環境変数: - `UPSTASH_VECTOR_URL`: あなたのUpstash VectorデータベースのURL - `UPSTASH_VECTOR_TOKEN`: あなたのUpstash Vector APIトークン ## 関連 - [メタデータフィルター](./metadata-filters) --- title: "リファレンス: Cloudflare ベクトルストア | ベクトルデータベース | RAG | Mastra ドキュメント" description: Mastraの CloudflareVectorクラスに関するドキュメント。Cloudflare Vectorizeを使用したベクトル検索を提供します。 --- # Cloudflare Vector Store [JA] Source: https://mastra.ai/ja/reference/rag/vectorize CloudflareVectorクラスは、Cloudflareのエッジネットワークと統合されたベクトルデータベースサービスである[Cloudflare Vectorize](https://developers.cloudflare.com/vectorize/)を使用してベクトル検索を提供します。 ## コンストラクタオプション ## メソッド ### createIndex() ### upsert() []", isOptional: true, description: "各ベクトルのメタデータ", }, { name: "ids", type: "string[]", isOptional: true, description: "オプションのベクトルID(指定しない場合は自動生成されます)", }, ]} /> ### query() ", isOptional: true, description: "クエリのメタデータフィルター", }, { name: "includeVector", type: "boolean", isOptional: true, defaultValue: "false", description: "結果にベクトルを含めるかどうか", }, ]} /> ### listIndexes() インデックス名の文字列配列を返します。 ### describeIndex() 戻り値: ```typescript copy interface IndexStats { dimension: number; count: number; metric: "cosine" | "euclidean" | "dotproduct"; } ``` ### deleteIndex() ### createMetadataIndex() フィルタリングを可能にするためにメタデータフィールドにインデックスを作成します。 ### deleteMetadataIndex() メタデータフィールドからインデックスを削除します。 ### listMetadataIndexes() インデックスのすべてのメタデータフィールドインデックスを一覧表示します。 ### updateVector() インデックス内の特定のIDのベクトルまたはメタデータを更新します。 ; }", description: "更新するベクトルやメタデータを含むオブジェクト", }, ]} /> ### deleteVector() インデックス内の特定のIDに対するベクトルとそれに関連するメタデータを削除します。 ## レスポンスタイプ クエリ結果は以下の形式で返されます: ```typescript copy interface QueryResult { id: string; score: number; metadata: Record; vector?: number[]; } ``` ## エラー処理 ストアは型付きエラーをスローし、それをキャッチすることができます: ```typescript copy try { await store.query({ indexName: "index_name", queryVector: queryVector, }); } catch (error) { if (error instanceof VectorStoreError) { console.log(error.code); // 'connection_failed' | 'invalid_dimension' | etc console.log(error.details); // Additional error context } } ``` ## 環境変数 必要な環境変数: - `CLOUDFLARE_ACCOUNT_ID`: あなたのCloudflareアカウントID - `CLOUDFLARE_API_TOKEN`: Vectorize権限を持つCloudflare APIトークン ## 関連 - [メタデータフィルター](./metadata-filters) --- title: "Cloudflare D1 ストレージ | ストレージシステム | Mastra Core" description: Mastra における Cloudflare D1 SQL ストレージ実装のドキュメントです。 --- # Cloudflare D1 Storage [JA] Source: https://mastra.ai/ja/reference/storage/cloudflare-d1 Cloudflare D1ストレージの実装は、Cloudflare D1を利用したサーバーレスのSQLデータベースソリューションを提供し、リレーショナル操作とトランザクションの一貫性をサポートします。 ## インストール ```bash npm install @mastra/cloudflare-d1@latest ``` ## 使用方法 ```typescript copy showLineNumbers import { D1Store } from "@mastra/cloudflare-d1"; type Env = { // Add your bindings here, e.g. Workers KV, D1, Workers AI, etc. D1Database: D1Database; }; // --- Example 1: Using Workers Binding --- const storageWorkers = new D1Store({ binding: D1Database, // D1Database binding provided by the Workers runtime tablePrefix: "dev_", // Optional: isolate tables per environment }); // --- Example 2: Using REST API --- const storageRest = new D1Store({ accountId: process.env.CLOUDFLARE_ACCOUNT_ID!, // Cloudflare Account ID databaseId: process.env.CLOUDFLARE_D1_DATABASE_ID!, // D1 Database ID apiToken: process.env.CLOUDFLARE_API_TOKEN!, // Cloudflare API Token tablePrefix: "dev_", // Optional: isolate tables per environment }); ``` そして、以下の内容を `wrangler.toml` または `wrangler.jsonc` ファイルに追加してください。 ``` [[d1_databases]] binding = "D1Database" database_name = "db-name" database_id = "db-id" ``` ## パラメーター ## 追加の注意事項 ### スキーマ管理 このストレージ実装は、スキーマの作成と更新を自動的に処理します。以下のテーブルが作成されます: - `threads`: 会話スレッドを保存します - `messages`: 個々のメッセージを保存します - `metadata`: スレッドやメッセージの追加メタデータを保存します ### トランザクションと一貫性 Cloudflare D1 は、単一行の操作に対してトランザクション保証を提供します。これにより、複数の操作をすべて成功するかすべて失敗するかの単位でまとめて実行できます。 ### テーブル作成とマイグレーション テーブルはストレージの初期化時に自動的に作成されます(`tablePrefix` オプションを使って環境ごとに分離することも可能です)が、カラムの追加やデータ型の変更、インデックスの修正などの高度なスキーマ変更には、手動でのマイグレーションとデータ損失を避けるための慎重な計画が必要です。 --- title: "Cloudflare Storage | ストレージシステム | Mastra Core" description: MastraにおけるCloudflare KVストレージ実装のドキュメント。 --- # Cloudflare Storage [JA] Source: https://mastra.ai/ja/reference/storage/cloudflare Cloudflare KV ストレージの実装は、Cloudflare Workers KV を使用したグローバル分散型のサーバーレスなキー・バリュー・ストアソリューションを提供します。 ## インストール ```bash copy npm install @mastra/cloudflare@latest ``` ## 使い方 ```typescript copy showLineNumbers import { CloudflareStore } from "@mastra/cloudflare"; // --- Example 1: Using Workers Binding --- const storageWorkers = new CloudflareStore({ bindings: { threads: THREADS_KV, // KVNamespace binding for threads table messages: MESSAGES_KV, // KVNamespace binding for messages table // Add other tables as needed }, keyPrefix: "dev_", // Optional: isolate keys per environment }); // --- Example 2: Using REST API --- const storageRest = new CloudflareStore({ accountId: process.env.CLOUDFLARE_ACCOUNT_ID!, // Cloudflare Account ID apiToken: process.env.CLOUDFLARE_API_TOKEN!, // Cloudflare API Token namespacePrefix: "dev_", // Optional: isolate namespaces per environment }); ``` ## パラメーター ", description: "Cloudflare Workers KV バインディング(Workers ランタイム用)", isOptional: true, }, { name: "accountId", type: "string", description: "Cloudflare アカウントID(REST API用)", isOptional: true, }, { name: "apiToken", type: "string", description: "Cloudflare APIトークン(REST API用)", isOptional: true, }, { name: "namespacePrefix", type: "string", description: "すべてのネームスペース名に付与するオプションのプレフィックス(環境の分離に便利)", isOptional: true, }, { name: "keyPrefix", type: "string", description: "すべてのキーに付与するオプションのプレフィックス(環境の分離に便利)", isOptional: true, }, ]} /> #### 追加の注意事項 ### スキーマ管理 このストレージ実装は、スキーマの作成と更新を自動的に処理します。以下のテーブルが作成されます: - `threads`: 会話スレッドを保存します - `messages`: 個々のメッセージを保存します - `metadata`: スレッドやメッセージの追加メタデータを保存します ### 一貫性と伝播 Cloudflare KV は最終的な一貫性を持つストアであり、書き込み後すぐにすべてのリージョンでデータが利用可能になるとは限りません。 ### キー構造とネームスペース Cloudflare KV のキーは、設定可能なプレフィックスとテーブル固有のフォーマット(例:`threads:threadId`)の組み合わせで構成されています。 Workers デプロイメントでは、`keyPrefix` を使用してネームスペース内のデータを分離します。REST API デプロイメントでは、`namespacePrefix` を使用して環境やアプリケーション間でネームスペース全体を分離します。 --- title: "DynamoDB ストレージ | ストレージシステム | Mastra Core" description: "ElectroDBを使用した単一テーブル設計によるMastraのDynamoDBストレージ実装のドキュメント。" --- # DynamoDB ストレージ [JA] Source: https://mastra.ai/ja/reference/storage/dynamodb DynamoDB ストレージの実装は、[ElectroDB](https://electrodb.dev/)を活用した単一テーブル設計パターンにより、Mastraにスケーラブルで高性能なNoSQLデータベースソリューションを提供します。 ## 機能 - すべてのMastraストレージニーズに対応する効率的な単一テーブル設計 - 型安全なDynamoDBアクセスのためのElectroDBベース - AWS認証情報、リージョン、エンドポイントのサポート - 開発用のAWS DynamoDB Localとの互換性 - スレッド、メッセージ、トレース、評価、ワークフローデータの保存 - サーバーレス環境向けに最適化 ## インストール ```bash copy npm install @mastra/dynamodb@latest # or pnpm add @mastra/dynamodb@latest # or yarn add @mastra/dynamodb@latest ``` ## 前提条件 このパッケージを使用する前に、プライマリキーとGlobal Secondary Indexes(GSI)を含む特定の構造でDynamoDBテーブルを作成する**必要があります**。このアダプターは、DynamoDBテーブルとそのGSIが外部でプロビジョニングされていることを前提としています。 AWS CloudFormationまたはAWS CDKを使用してテーブルを設定するための詳細な手順は、[TABLE_SETUP.md](https://github.com/mastra-ai/mastra/blob/main/stores/dynamodb/TABLE_SETUP.md)で確認できます。続行する前に、これらの手順に従ってテーブルが設定されていることを確認してください。 ## 使い方 ### 基本的な使い方 ```typescript copy showLineNumbers import { Memory } from "@mastra/memory"; import { DynamoDBStore } from "@mastra/dynamodb"; // Initialize the DynamoDB storage const storage = new DynamoDBStore({ name: "dynamodb", // A name for this storage instance config: { tableName: "mastra-single-table", // Name of your DynamoDB table region: "us-east-1", // Optional: AWS region, defaults to 'us-east-1' // endpoint: "http://localhost:8000", // Optional: For local DynamoDB // credentials: { accessKeyId: "YOUR_ACCESS_KEY", secretAccessKey: "YOUR_SECRET_KEY" } // Optional }, }); // Example: Initialize Memory with DynamoDB storage const memory = new Memory({ storage, options: { lastMessages: 10, }, }); ``` ### DynamoDB Local を使ったローカル開発 ローカル開発では、[DynamoDB Local](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html) を利用できます。 1. **DynamoDB Local を実行します(例:Docker を使用):** ```bash docker run -p 8000:8000 amazon/dynamodb-local ``` 2. **ローカルエンドポイントを使うように `DynamoDBStore` を設定します:** ```typescript copy showLineNumbers import { DynamoDBStore } from "@mastra/dynamodb"; const storage = new DynamoDBStore({ name: "dynamodb-local", config: { tableName: "mastra-single-table", // Ensure this table is created in your local DynamoDB region: "localhost", // Can be any string for local, 'localhost' is common endpoint: "http://localhost:8000", // For DynamoDB Local, credentials are not typically required unless configured. // If you've configured local credentials: // credentials: { accessKeyId: "fakeMyKeyId", secretAccessKey: "fakeSecretAccessKey" } }, }); ``` ローカルの DynamoDB インスタンスにテーブルや GSI を作成する必要があります。例えば、AWS CLI をローカルエンドポイントに向けて実行してください。 ## パラメーター ## AWS IAM 権限 コードを実行するIAMロールまたはユーザーは、指定されたDynamoDBテーブルとそのインデックスを操作するための適切な権限が必要です。以下はサンプルポリシーです。`${YOUR_TABLE_NAME}`を実際のテーブル名に、`${YOUR_AWS_REGION}`と`${YOUR_AWS_ACCOUNT_ID}`を適切な値に置き換えてください。 ```json copy { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "dynamodb:DescribeTable", "dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:UpdateItem", "dynamodb:DeleteItem", "dynamodb:Query", "dynamodb:Scan", "dynamodb:BatchGetItem", "dynamodb:BatchWriteItem" ], "Resource": [ "arn:aws:dynamodb:${YOUR_AWS_REGION}:${YOUR_AWS_ACCOUNT_ID}:table/${YOUR_TABLE_NAME}", "arn:aws:dynamodb:${YOUR_AWS_REGION}:${YOUR_AWS_ACCOUNT_ID}:table/${YOUR_TABLE_NAME}/index/*" ] } ] } ``` ## 主要な考慮事項 アーキテクチャの詳細に入る前に、DynamoDBストレージアダプターを使用する際は以下の重要なポイントを念頭に置いてください: - **外部テーブルのプロビジョニング:** このアダプターは、アダプターを使用する前に、DynamoDBテーブルとそのGlobal Secondary Indexes(GSI)を自分で作成・設定することが_必要_です。[TABLE_SETUP.md](https://github.com/mastra-ai/mastra/blob/main/stores/dynamodb/TABLE_SETUP.md)のガイドに従ってください。 - **シングルテーブル設計:** すべてのMastraデータ(スレッド、メッセージなど)は1つのDynamoDBテーブルに保存されます。これはDynamoDB向けに最適化された意図的な設計選択であり、リレーショナルデータベースのアプローチとは異なります。 - **GSIの理解:** GSIの構造(`TABLE_SETUP.md`に記載)に精通していることは、データ取得と潜在的なクエリパターンを理解するために重要です。 - **ElectroDB:** このアダプターはElectroDBを使用してDynamoDBとのやり取りを管理し、生のDynamoDB操作に対して抽象化レイヤーと型安全性を提供します。 ## アーキテクチャアプローチ このストレージアダプターは、[ElectroDB](https://electrodb.dev/)を活用した**シングルテーブル設計パターン**を利用しており、これはDynamoDBにおける一般的で推奨されるアプローチです。これは、通常複数のテーブルを使用し、それぞれが特定のエンティティ(スレッド、メッセージなど)専用となっているリレーショナルデータベースアダプター(`@mastra/pg`や`@mastra/libsql`など)とはアーキテクチャ的に異なります。 このアプローチの主要な側面: - **DynamoDBネイティブ:** シングルテーブル設計はDynamoDBのキーバリューとクエリ機能に最適化されており、リレーショナルモデルを模倣するよりも優れたパフォーマンスとスケーラビリティをもたらすことが多いです。 - **外部テーブル管理:** コードを通じてテーブルを作成するヘルパー関数を提供する可能性のある他のアダプターとは異なり、このアダプターは**使用前にDynamoDBテーブルとその関連するGlobal Secondary Indexes(GSI)が外部でプロビジョニングされることを期待します**。AWS CloudFormationやCDKなどのツールを使用した詳細な手順については、[TABLE_SETUP.md](https://github.com/mastra-ai/mastra/blob/main/stores/dynamodb/TABLE_SETUP.md)を参照してください。アダプターは既存のテーブル構造との相互作用にのみ焦点を当てています。 - **インターフェースによる一貫性:** 基盤となるストレージモデルは異なりますが、このアダプターは他のアダプターと同じ`MastraStorage`インターフェースに準拠しており、Mastra `Memory`コンポーネント内で相互に交換可能に使用できることを保証します。 ### シングルテーブル内のMastraデータ シングルDynamoDBテーブル内では、異なるMastraデータエンティティ(Threads、Messages、Traces、Evals、Workflowsなど)がElectroDBを使用して管理され、区別されます。ElectroDBは各エンティティタイプに対して特定のモデルを定義し、これには固有のキー構造と属性が含まれます。これにより、アダプターは同じテーブル内で多様なデータタイプを効率的に保存および取得できます。 例えば、`Thread`アイテムは`THREAD#`のようなプライマリキーを持つ可能性があり、そのスレッドに属する`Message`アイテムは`THREAD#`をパーティションキーとして、`MESSAGE#`をソートキーとして使用する可能性があります。`TABLE_SETUP.md`で詳述されているGlobal Secondary Indexes(GSI)は、スレッドのすべてのメッセージを取得したり、特定のワークフローに関連するトレースをクエリしたりするなど、これらの異なるエンティティ間での一般的なアクセスパターンをサポートするために戦略的に設計されています。 ### シングルテーブル設計の利点 この実装はElectroDBを使用したシングルテーブル設計パターンを使用しており、DynamoDBのコンテキスト内でいくつかの利点を提供します: 1. **コストの削減(潜在的に):** テーブル数が少ないことで、特にオンデマンド容量において、Read/Write Capacity Unit(RCU/WCU)のプロビジョニングと管理が簡素化されます。 2. **パフォーマンスの向上:** 関連データを共存させたり、GSIを通じて効率的にアクセスしたりできるため、一般的なアクセスパターンに対する高速な検索が可能になります。 3. **管理の簡素化:** 監視、バックアップ、管理すべき個別のテーブル数が少なくなります。 4. **アクセスパターンの複雑さの軽減:** ElectroDBは、単一テーブル上のアイテムタイプとアクセスパターンの複雑さを管理するのに役立ちます。 5. **トランザクションサポート:** 必要に応じて、同じテーブル内に保存された異なる「エンティティ」タイプ間でDynamoDBトランザクションを使用できます。 ## ライセンス このパッケージはMITライセンスの下で配布されています。詳細については[LICENSE.md](https://github.com/mastra-ai/mastra/blob/main/LICENSE.md)をご覧ください。 --- title: "LanceDB Storage" description: MastraにおけるLanceDBストレージ実装のドキュメント。 --- # LanceDB Storage [JA] Source: https://mastra.ai/ja/reference/storage/lance LanceDB ストレージ実装は、従来のデータストレージとベクトル操作の両方を得意とする LanceDB データベースシステムを使用した高性能ストレージソリューションを提供します。 ## インストール ```bash npm install @mastra/lance ``` ## 使用方法 ### 基本的なストレージの使用方法 ```typescript copy showLineNumbers import { LanceStorage } from "@mastra/lance"; // Connect to a local database const storage = await LanceStorage.create("my-storage", "/path/to/db"); // Connect to a LanceDB cloud database const storage = await LanceStorage.create("my-storage", "db://host:port"); // Connect to a cloud database with custom options const storage = await LanceStorage.create("my-storage", "s3://bucket/db", { storageOptions: { timeout: "60s" }, }); ``` ## パラメータ ### LanceStorage.create() ## 追加の注意事項 ### スキーマ管理 LanceStorage実装は、スキーマの作成と更新を自動的に処理します。MastraのスキーマタイプをApache Arrowデータタイプにマッピングし、これらはLanceDBで内部的に使用されます: - `text`, `uuid` → Utf8 - `int`, `integer` → Int32 - `float` → Float32 - `jsonb`, `json` → Utf8 (シリアル化) - `binary` → Binary ### デプロイメントオプション LanceDBストレージは、異なるデプロイメントシナリオに対して設定できます: - **ローカル開発**: 開発とテスト用にローカルファイルパスを使用 ``` /path/to/db ``` - **クラウドデプロイメント**: ホストされたLanceDBインスタンスに接続 ``` db://host:port ``` - **S3ストレージ**: スケーラブルなクラウドストレージ用にAmazon S3を使用 ``` s3://bucket/db ``` ### テーブル管理 LanceStorageは、テーブル管理のためのメソッドを提供します: - カスタムスキーマでテーブルを作成 - テーブルを削除 - テーブルをクリア(すべてのレコードを削除) - キーによるレコードの読み込み - 単一およびバッチレコードの挿入 --- title: "LibSQL ストレージ | ストレージシステム | Mastra Core" description: Mastraにおける LibSQL ストレージ実装のドキュメント。 --- # LibSQL ストレージ [JA] Source: https://mastra.ai/ja/reference/storage/libsql LibSQL ストレージの実装は、インメモリと永続的データベースの両方として実行できる SQLite 互換のストレージソリューションを提供します。 ## インストール ```bash copy npm install @mastra/libsql@latest ``` ## 使用方法 ```typescript copy showLineNumbers import { LibSQLStore } from "@mastra/libsql"; // ファイルデータベース(開発環境) const storage = new LibSQLStore({ url: "file:./storage.db", }); // 永続的データベース(本番環境) const storage = new LibSQLStore({ url: process.env.DATABASE_URL, }); ``` ## パラメータ ## 追加情報 ### インメモリ vs 永続ストレージ ファイル設定(`file:storage.db`)は以下の用途に適しています: - 開発とテスト - 一時的なストレージ - クイックプロトタイピング 本番環境では、永続的なデータベースURLを使用してください:`libsql://your-database.turso.io` ### スキーマ管理 ストレージの実装はスキーマの作成と更新を自動的に処理します。以下のテーブルが作成されます: - `threads`:会話スレッドを保存 - `messages`:個々のメッセージを保存 - `metadata`:スレッドとメッセージの追加メタデータを保存 --- title: "PostgreSQLストレージ | ストレージシステム | Mastra Core" description: MastraにおけるPostgreSQLストレージ実装のドキュメント。 --- # PostgreSQLストレージ [JA] Source: https://mastra.ai/ja/reference/storage/postgresql PostgreSQLストレージ実装は、PostgreSQLデータベースを使用した本番環境対応のストレージソリューションを提供します。 ## インストール ```bash copy npm install @mastra/pg@latest ``` ## 使い方 ```typescript copy showLineNumbers import { PostgresStore } from "@mastra/pg"; const storage = new PostgresStore({ connectionString: process.env.DATABASE_URL, }); ``` ## パラメーター ## コンストラクタの例 `PostgresStore` は以下の方法でインスタンス化できます。 ```ts import { PostgresStore } from "@mastra/pg"; // 接続文字列のみを使用する場合 const store1 = new PostgresStore({ connectionString: "postgresql://user:password@localhost:5432/mydb", }); // 接続文字列とカスタムスキーマ名を使用する場合 const store2 = new PostgresStore({ connectionString: "postgresql://user:password@localhost:5432/mydb", schemaName: "custom_schema", // オプション }); // 個別の接続パラメータを使用する場合 const store4 = new PostgresStore({ host: "localhost", port: 5432, database: "mydb", user: "user", password: "password", }); // 個別パラメータと schemaName を使用する場合 const store5 = new PostgresStore({ host: "localhost", port: 5432, database: "mydb", user: "user", password: "password", schemaName: "custom_schema", // オプション }); ``` ## 追加の注意事項 ### スキーマ管理 ストレージ実装はスキーマの作成と更新を自動的に処理します。以下のテーブルが作成されます: - `threads`: 会話スレッドを保存します - `messages`: 個々のメッセージを保存します - `metadata`: スレッドやメッセージの追加メタデータを保存します --- title: "Upstash Storage | ストレージシステム | Mastra Core" description: MastraにおけるUpstashストレージ実装のドキュメント。 --- # Upstash Storage [JA] Source: https://mastra.ai/ja/reference/storage/upstash Upstashのストレージ実装は、UpstashのRedis互換のキー・バリュー・ストアを使用したサーバーレスに適したストレージソリューションを提供します。 ## インストール ```bash copy npm install @mastra/upstash@latest ``` ## 使用法 ```typescript copy showLineNumbers import { UpstashStore } from "@mastra/upstash"; const storage = new UpstashStore({ url: process.env.UPSTASH_URL, token: process.env.UPSTASH_TOKEN, }); ``` ## パラメーター ## 追加の注意事項 ### キー構造 Upstash ストレージの実装はキーと値の構造を使用します: - スレッドキー: `{prefix}thread:{threadId}` - メッセージキー: `{prefix}message:{messageId}` - メタデータキー: `{prefix}metadata:{entityId}` ### サーバーレスの利点 Upstash ストレージは特にサーバーレス展開に適しています: - 接続管理が不要 - リクエストごとの料金 - グローバルなレプリケーションオプション - エッジ互換 ### データの永続性 Upstash は以下を提供します: - 自動データ永続性 - 時点復旧 - クロスリージョンレプリケーションオプション ### パフォーマンスの考慮事項 最適なパフォーマンスのために: - データを整理するために適切なキーのプレフィックスを使用する - Redis のメモリ使用量を監視する - 必要に応じてデータの有効期限ポリシーを検討する --- title: "リファレンス: MastraMCPClient | ツールディスカバリー | Mastra ドキュメント" description: MastraMCPClient の API リファレンス - Model Context Protocol 用のクライアント実装。 --- # MastraMCPClient(非推奨) [JA] Source: https://mastra.ai/ja/reference/tools/client `MastraMCPClient` クラスは、Model Context Protocol(MCP)サーバーとやり取りするためのクライアント実装を提供します。このクラスは、MCPプロトコルを通じて接続管理、リソースの発見、およびツールの実行を行います。 ## 非推奨のお知らせ `MastraMCPClient` は [`MCPClient`](./mcp-client) への移行に伴い非推奨となります。単一のMCPサーバーと複数のMCPサーバーを管理するために異なるインターフェースを用意するのではなく、たとえ単一のMCPサーバーを使用する場合でも複数サーバー管理用のインターフェースを推奨することにしました。 ## コンストラクター MastraMCPClient の新しいインスタンスを作成します。 ```typescript constructor({ name, version = '1.0.0', server, capabilities = {}, timeout = 60000, }: { name: string; server: MastraMCPServerDefinition; capabilities?: ClientCapabilities; version?: string; timeout?: number; }) ``` ### パラメーター
### MastraMCPServerDefinition MCP サーバーはこの定義を使って設定できます。クライアントは、指定されたパラメーターに基づいて自動的にトランスポートタイプを検出します: - `command` が指定されている場合、Stdio トランスポートを使用します。 - `url` が指定されている場合、まず Streamable HTTP トランスポートを試み、初回接続に失敗した場合はレガシー SSE トランスポートにフォールバックします。
", isOptional: true, description: "Stdio サーバー用:コマンドに設定する環境変数。", }, { name: "url", type: "URL", isOptional: true, description: "HTTP サーバー(Streamable HTTP または SSE)用:サーバーの URL。", }, { name: "requestInit", type: "RequestInit", isOptional: true, description: "HTTP サーバー用:fetch API のリクエスト設定。", }, { name: "eventSourceInit", type: "EventSourceInit", isOptional: true, description: "SSE フォールバック用:SSE 接続のためのカスタム fetch 設定。SSE でカスタムヘッダーを使用する場合に必須です。", }, { name: "logger", type: "LogHandler", isOptional: true, description: "オプションの追加ログハンドラー。", }, { name: "timeout", type: "number", isOptional: true, description: "サーバー固有のタイムアウト(ミリ秒単位)。", }, { name: "capabilities", type: "ClientCapabilities", isOptional: true, description: "サーバー固有の機能設定。", }, { name: "enableServerLogs", type: "boolean", isOptional: true, defaultValue: "true", description: "このサーバーのログを有効にするかどうか。", }, ]} /> ### LogHandler `LogHandler` 関数は `LogMessage` オブジェクトをパラメーターとして受け取り、void を返します。`LogMessage` オブジェクトには以下のプロパティがあります。`LoggingLevel` 型は `debug`、`info`、`warn`、`error` の値を持つ文字列の列挙型です。
", isOptional: true, description: "オプションの追加ログ詳細", }, ]} /> ## メソッド ### connect() MCPサーバーへの接続を確立します。 ```typescript async connect(): Promise ``` ### disconnect() MCPサーバーとの接続を切断します。 ```typescript async disconnect(): Promise ``` ### resources() サーバーから利用可能なリソースの一覧を取得します。 ```typescript async resources(): Promise ``` ### tools() サーバーから利用可能なツールを取得し、初期化してMastra互換のツール形式に変換します。 ```typescript async tools(): Promise> ``` ツール名を対応するMastraツール実装にマッピングしたオブジェクトを返します。 ## 例 ### Mastra Agentとの併用 #### Stdioサーバーを使った例 ```typescript import { Agent } from "@mastra/core/agent"; import { MastraMCPClient } from "@mastra/mcp"; import { openai } from "@ai-sdk/openai"; // Initialize the MCP client using mcp/fetch as an example https://hub.docker.com/r/mcp/fetch // Visit https://github.com/docker/mcp-servers for other reference docker mcp servers const fetchClient = new MastraMCPClient({ name: "fetch", server: { command: "docker", args: ["run", "-i", "--rm", "mcp/fetch"], logger: (logMessage) => { console.log(`[${logMessage.level}] ${logMessage.message}`); }, }, }); // Create a Mastra Agent const agent = new Agent({ name: "Fetch agent", instructions: "You are able to fetch data from URLs on demand and discuss the response data with the user.", model: openai("gpt-4o-mini"), }); try { // Connect to the MCP server await fetchClient.connect(); // Gracefully handle process exits so the docker subprocess is cleaned up process.on("exit", () => { fetchClient.disconnect(); }); // Get available tools const tools = await fetchClient.tools(); // Use the agent with the MCP tools const response = await agent.generate( "Tell me about mastra.ai/docs. Tell me generally what this page is and the content it includes.", { toolsets: { fetch: tools, }, }, ); console.log("\n\n" + response.text); } catch (error) { console.error("Error:", error); } finally { // Always disconnect when done await fetchClient.disconnect(); } ``` ### SSEサーバーを使った例 ```typescript // Initialize the MCP client using an SSE server const sseClient = new MastraMCPClient({ name: "sse-client", server: { url: new URL("https://your-mcp-server.com/sse"), // Optional fetch request configuration - Note: requestInit alone isn't enough for SSE requestInit: { headers: { Authorization: "Bearer your-token", }, }, // Required for SSE connections with custom headers eventSourceInit: { fetch(input: Request | URL | string, init?: RequestInit) { const headers = new Headers(init?.headers || {}); headers.set("Authorization", "Bearer your-token"); return fetch(input, { ...init, headers, }); }, }, // Optional additional logging configuration logger: (logMessage) => { console.log( `[${logMessage.level}] ${logMessage.serverName}: ${logMessage.message}`, ); }, // Disable server logs enableServerLogs: false, }, }); // The rest of the usage is identical to the stdio example ``` ### SSE認証に関する重要な注意点 SSE接続で認証やカスタムヘッダーを使用する場合、`requestInit`と`eventSourceInit`の両方を設定する必要があります。これは、SSE接続がブラウザのEventSource APIを使用しており、カスタムヘッダーを直接サポートしていないためです。 `eventSourceInit`の設定により、SSE接続で使用される内部のfetchリクエストをカスタマイズでき、認証ヘッダーが正しく含まれるようになります。 `eventSourceInit`がない場合、`requestInit`で指定した認証ヘッダーは接続リクエストに含まれず、401 Unauthorizedエラーが発生します。 ## 関連情報 - アプリケーションで複数のMCPサーバーを管理する場合は、[MCPClientのドキュメント](./mcp-client)をご覧ください - Model Context Protocolの詳細については、[@modelcontextprotocol/sdkのドキュメント](https://github.com/modelcontextprotocol/typescript-sdk)をご参照ください。 --- title: "リファレンス: createTool() | ツール | Mastra ドキュメント" description: MastraのcreateTool関数のドキュメント。エージェント用のカスタムツールを定義するために使用されます。 --- # createTool() [JA] Source: https://mastra.ai/ja/reference/tools/create-tool `createTool()`関数は、Mastraエージェントが実行できるカスタムツールを定義するために使用されます。ツールはエージェントの機能を拡張し、外部システムとの対話、計算の実行、または特定のデータへのアクセスを可能にします。 ## 基本的な使用方法 天気情報を取得するツールを作成する基本的な例を以下に示します: ```typescript filename="src/mastra/tools/weatherInfo.ts" copy import { createTool } from "@mastra/core/tools"; import { z } from "zod"; export const weatherInfo = createTool({ id: "Get Weather Information", inputSchema: z.object({ city: z.string(), }), description: `Fetches the current weather information for a given city`, execute: async ({ context: { city } }) => { // Tool logic here (e.g., API call) console.log("Using tool to fetch weather information for", city); return { temperature: 20, conditions: "Sunny" }; // Example return }, }); ``` ## パラメータ `createTool()`関数は以下のパラメータを持つオブジェクトを受け取ります: ## 戻り値 `createTool()`関数は`Tool`オブジェクトを返します。 ## ツールの詳細 `createTool()`によって返される`Tool`オブジェクトには、以下の主要なプロパティがあります: - **ID**:`id`パラメータで提供される一意の識別子。 - **説明**:`description`パラメータで提供される説明。 - **パラメータ**:`inputSchema`から派生し、ツールが期待する入力の構造を定義します。 - **実行関数**:`execute`パラメータで定義されたロジックで、エージェントがツールを使用することを決定したときに呼び出されます。 ## 関連項目 - [ツールの概要](/docs/tools-mcp/overview) - [エージェントでのツールの使用](/docs/agents/using-tools-and-mcp) - [動的ツールコンテキスト](/docs/tools-mcp/dynamic-context) - [高度なツールの使用方法](/docs/tools-mcp/advanced-usage) --- title: "リファレンス: createDocumentChunkerTool() | ツール | Mastra ドキュメント" description: Mastra の Document Chunker Tool のドキュメント。ドキュメントを効率的な処理と検索のために小さなチャンクに分割します。 --- # createDocumentChunkerTool() [JA] Source: https://mastra.ai/ja/reference/tools/document-chunker-tool `createDocumentChunkerTool()` 関数は、ドキュメントをより効率的に処理・取得するために、小さなチャンクに分割するツールを作成します。さまざまなチャンク化戦略や設定可能なパラメータに対応しています。 ## 基本的な使い方 ```typescript import { createDocumentChunkerTool, MDocument } from "@mastra/rag"; const document = new MDocument({ text: "Your document content here...", metadata: { source: "user-manual" }, }); const chunker = createDocumentChunkerTool({ doc: document, params: { strategy: "recursive", size: 512, overlap: 50, separator: "\n", }, }); const { chunks } = await chunker.execute(); ``` ## パラメーター ### ChunkParams ## 戻り値 ## カスタムパラメータを使った例 ```typescript const technicalDoc = new MDocument({ text: longDocumentContent, metadata: { type: "technical", version: "1.0", }, }); const chunker = createDocumentChunkerTool({ doc: technicalDoc, params: { strategy: "recursive", size: 1024, // Larger chunks overlap: 100, // More overlap separator: "\n\n", // Split on double newlines }, }); const { chunks } = await chunker.execute(); // Process the chunks chunks.forEach((chunk, index) => { console.log(`Chunk ${index + 1} length: ${chunk.content.length}`); }); ``` ## ツールの詳細 チャンク化ツールは、以下のプロパティを持つMastraツールとして作成されます。 - **ツールID**: `Document Chunker {strategy} {size}` - **説明**: `{strategy}戦略を使用し、サイズ{size}、オーバーラップ{overlap}でドキュメントをチャンク化します` - **入力スキーマ**: 空のオブジェクト(追加の入力は不要) - **出力スキーマ**: チャンク配列を含むオブジェクト ## 関連 - [MDocument](../rag/document.mdx) - [createVectorQueryTool](./vector-query-tool) --- title: "リファレンス: createGraphRAGTool() | RAG | Mastra Tools Docs" description: Mastraにおけるグラフ RAG ツールのドキュメント。ドキュメント間のセマンティック関係のグラフを構築することでRAGを強化します。 --- import { Callout } from "nextra/components"; # createGraphRAGTool() [JA] Source: https://mastra.ai/ja/reference/tools/graph-rag-tool `createGraphRAGTool()` は、ドキュメント間のセマンティックな関係のグラフを構築することでRAGを強化するツールを作成します。内部的には `GraphRAG` システムを利用してグラフベースの検索を提供し、直接的な類似性だけでなく、関連する接続関係を通じて適切なコンテンツを見つけ出します。 ## 使用例 ```typescript import { openai } from "@ai-sdk/openai"; import { createGraphRAGTool } from "@mastra/rag"; const graphTool = createGraphRAGTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), graphOptions: { dimension: 1536, threshold: 0.7, randomWalkSteps: 100, restartProb: 0.15, }, }); ``` ## パラメーター **パラメーター要件:** ほとんどのフィールドは作成時にデフォルト値として設定できます。 一部のフィールドは、実行時のコンテキストや入力によって上書きすることができます。 必須フィールドが作成時にも実行時にも指定されていない場合、エラーが発生します。 `model`、`id`、`description` は作成時のみ設定可能であることに注意してください。 ### GraphOptions ## 戻り値 このツールは以下のオブジェクトを返します: ### QueryResult オブジェクトの構造 ```typescript { id: string; // Unique chunk/document identifier metadata: any; // All metadata fields (document ID, etc.) vector: number[]; // Embedding vector (if available) score: number; // Similarity score for this retrieval document: string; // Full chunk/document text (if available) } ``` ## デフォルトツールの説明 デフォルトの説明は以下に重点を置いています: - ドキュメント間の関係性の分析 - パターンやつながりの発見 - 複雑なクエリへの回答 ## 応用例 ```typescript const graphTool = createGraphRAGTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), graphOptions: { dimension: 1536, threshold: 0.8, // Higher similarity threshold randomWalkSteps: 200, // More exploration steps restartProb: 0.2, // Higher restart probability }, }); ``` ## カスタム説明付きの例 ```typescript const graphTool = createGraphRAGTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), description: "Analyze document relationships to find complex patterns and connections in our company's historical data", }); ``` この例では、関係性分析という基本的な目的を維持しつつ、特定のユースケースに合わせてツールの説明をカスタマイズする方法を示しています。 ## 例:ランタイムコンテキストの使用 ```typescript const graphTool = createGraphRAGTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), }); ``` ランタイムコンテキストを使用する場合、必要なパラメータは実行時にランタイムコンテキストを通じて指定します: ```typescript const runtimeContext = new RuntimeContext<{ vectorStoreName: string; indexName: string; topK: number; filter: any; }>(); runtimeContext.set("vectorStoreName", "my-store"); runtimeContext.set("indexName", "my-index"); runtimeContext.set("topK", 5); runtimeContext.set("filter", { category: "docs" }); runtimeContext.set("randomWalkSteps", 100); runtimeContext.set("restartProb", 0.15); const response = await agent.generate( "Find documentation from the knowledge base.", { runtimeContext, }, ); ``` ランタイムコンテキストの詳細については、以下をご覧ください: - [Runtime Variables](../../docs/agents/runtime-variables) - [Dynamic Context](../../docs/tools-mcp/dynamic-context) ## 関連 - [createVectorQueryTool](./vector-query-tool) - [GraphRAG](../rag/graph-rag) --- title: "リファレンス: MCPClient | ツール管理 | Mastra ドキュメント" description: MCPClientのAPIリファレンス - 複数のModel Context Protocolサーバーとそのツールを管理するためのクラス。 --- # MCPClient [JA] Source: https://mastra.ai/ja/reference/tools/mcp-client `MCPClient`クラスは、Mastraアプリケーションで複数のMCPサーバー接続とそのツールを管理する方法を提供します。接続のライフサイクル、ツールの名前空間管理を処理し、設定されたすべてのサーバーにわたるツールへのアクセスを提供します。 このクラスは非推奨の[`MastraMCPClient`](/reference/tools/client)に代わるものです。 ## コンストラクタ MCPClientクラスの新しいインスタンスを作成します。 ```typescript constructor({ id?: string; servers: Record; timeout?: number; }: MCPClientOptions) ``` ### MCPClientOptions
", description: "サーバー設定のマップ。各キーは一意のサーバー識別子であり、値はサーバー設定です。", }, { name: "timeout", type: "number", isOptional: true, defaultValue: "60000", description: "個々のサーバー設定で上書きされない限り、すべてのサーバーに適用されるグローバルタイムアウト値(ミリ秒単位)。", }, ]} /> ### MastraMCPServerDefinition `servers`マップ内の各サーバーは`MastraMCPServerDefinition`タイプを使用して設定されます。トランスポートタイプは提供されたパラメータに基づいて検出されます: - `command`が提供されている場合、Stdioトランスポートを使用します。 - `url`が提供されている場合、最初にStreamable HTTPトランスポートを試み、初期接続が失敗した場合はレガシーSSEトランスポートにフォールバックします。
", isOptional: true, description: "Stdioサーバーの場合:コマンドに設定する環境変数。", }, { name: "url", type: "URL", isOptional: true, description: "HTTPサーバー(Streamable HTTPまたはSSE)の場合:サーバーのURL。", }, { name: "requestInit", type: "RequestInit", isOptional: true, description: "HTTPサーバーの場合:fetch APIのリクエスト設定。", }, { name: "eventSourceInit", type: "EventSourceInit", isOptional: true, description: "SSEフォールバックの場合:SSE接続用のカスタムフェッチ設定。SSEでカスタムヘッダーを使用する場合に必要です。", }, { name: "logger", type: "LogHandler", isOptional: true, description: "ロギング用のオプションの追加ハンドラー。", }, { name: "timeout", type: "number", isOptional: true, description: "サーバー固有のタイムアウト(ミリ秒単位)。", }, { name: "capabilities", type: "ClientCapabilities", isOptional: true, description: "サーバー固有の機能設定。", }, { name: "enableServerLogs", type: "boolean", isOptional: true, defaultValue: "true", description: "このサーバーのロギングを有効にするかどうか。", }, ]} /> ## メソッド ### getTools() 設定されたすべてのサーバーからすべてのツールを取得し、ツール名をサーバー名で名前空間化(`serverName_toolName`の形式)して競合を防ぎます。 Agent定義に渡すことを想定しています。 ```ts new Agent({ tools: await mcp.getTools() }); ``` ### getToolsets() 名前空間化されたツール名(`serverName.toolName`の形式)をそのツール実装にマッピングするオブジェクトを返します。 generateまたはstreamメソッドに動的に渡すことを想定しています。 ```typescript const res = await agent.stream(prompt, { toolsets: await mcp.getToolsets(), }); ``` ### disconnect() すべてのMCPサーバーから切断し、リソースをクリーンアップします。 ```typescript async disconnect(): Promise ``` ### `resources` プロパティ `MCPClient`インスタンスには、リソース関連の操作へのアクセスを提供する`resources`プロパティがあります。 ```typescript const mcpClient = new MCPClient({ /* ...servers configuration... */ }); // mcpClient.resources経由でリソースメソッドにアクセス const allResourcesByServer = await mcpClient.resources.list(); const templatesByServer = await mcpClient.resources.templates(); // ... その他のリソースメソッドについても同様 ``` #### `resources.list()` 接続されたすべてのMCPサーバーから利用可能なすべてのリソースを取得し、サーバー名でグループ化します。 ```typescript async list(): Promise> ``` 例: ```typescript const resourcesByServer = await mcpClient.resources.list(); for (const serverName in resourcesByServer) { console.log(`Resources from ${serverName}:`, resourcesByServer[serverName]); } ``` #### `resources.templates()` 接続されたすべてのMCPサーバーから利用可能なすべてのリソーステンプレートを取得し、サーバー名でグループ化します。 ```typescript async templates(): Promise> ``` 例: ```typescript const templatesByServer = await mcpClient.resources.templates(); for (const serverName in templatesByServer) { console.log(`Templates from ${serverName}:`, templatesByServer[serverName]); } ``` #### `resources.read(serverName: string, uri: string)` 指定されたサーバーから特定のリソースの内容を読み取ります。 ```typescript async read(serverName: string, uri: string): Promise ``` - `serverName`: サーバーの識別子(`servers`コンストラクタオプションで使用されるキー)。 - `uri`: 読み取るリソースのURI。 例: ```typescript const content = await mcpClient.resources.read( "myWeatherServer", "weather://current", ); console.log("Current weather:", content.contents[0].text); ``` #### `resources.subscribe(serverName: string, uri: string)` 指定されたサーバー上の特定のリソースの更新を購読します。 ```typescript async subscribe(serverName: string, uri: string): Promise ``` 例: ```typescript await mcpClient.resources.subscribe("myWeatherServer", "weather://current"); ``` #### `resources.unsubscribe(serverName: string, uri: string)` 指定されたサーバー上の特定のリソースの更新購読を解除します。 ```typescript async unsubscribe(serverName: string, uri: string): Promise ``` 例: ```typescript await mcpClient.resources.unsubscribe("myWeatherServer", "weather://current"); ``` #### `resources.onUpdated(serverName: string, handler: (params: { uri: string }) => void)` 特定のサーバー上で購読されたリソースが更新されたときに呼び出される通知ハンドラーを設定します。 ```typescript async onUpdated(serverName: string, handler: (params: { uri: string }) => void): Promise ``` 例: ```typescript mcpClient.resources.onUpdated("myWeatherServer", (params) => { console.log(`Resource updated on myWeatherServer: ${params.uri}`); // ここでリソースの内容を再取得したい場合があります // await mcpClient.resources.read("myWeatherServer", params.uri); }); ``` #### `resources.onListChanged(serverName: string, handler: () => void)` 特定のサーバー上で利用可能なリソースの全体的なリストが変更されたときに呼び出される通知ハンドラーを設定します。 ```typescript async onListChanged(serverName: string, handler: () => void): Promise ``` 例: ```typescript mcpClient.resources.onListChanged("myWeatherServer", () => { console.log("Resource list changed on myWeatherServer."); // リソースのリストを再取得する必要があります // await mcpClient.resources.list(); }); ``` ### `prompts` プロパティ `MCPClient`インスタンスには、プロンプト関連の操作へのアクセスを提供する`prompts`プロパティがあります。 ```typescript const mcpClient = new MCPClient({ /* ...servers configuration... */ }); // Access prompt methods via mcpClient.prompts const allPromptsByServer = await mcpClient.prompts.list(); const { prompt, messages } = await mcpClient.prompts.get({ serverName: "myWeatherServer", name: "current", }); ``` #### `prompts.list()` 接続されているすべてのMCPサーバーから利用可能なプロンプトを取得し、サーバー名でグループ化して返します。 ```typescript async list(): Promise> ``` 例: ```typescript const promptsByServer = await mcpClient.prompts.list(); for (const serverName in promptsByServer) { console.log(`Prompts from ${serverName}:`, promptsByServer[serverName]); } ``` #### `prompts.get({ serverName, name, args?, version? })` サーバーから特定のプロンプトとそのメッセージを取得します。 ```typescript async get({ serverName, name, args?, version?, }: { serverName: string; name: string; args?: Record; version?: string; }): Promise<{ prompt: Prompt; messages: PromptMessage[] }> ``` 例: ```typescript const { prompt, messages } = await mcpClient.prompts.get({ serverName: "myWeatherServer", name: "current", args: { location: "London" }, }); console.log(prompt); console.log(messages); ``` #### `prompts.onListChanged(serverName: string, handler: () => void)` 特定のサーバーで利用可能なプロンプトのリストが変更されたときに呼び出される通知ハンドラーを設定します。 ```typescript async onListChanged(serverName: string, handler: () => void): Promise ``` 例: ```typescript mcpClient.prompts.onListChanged("myWeatherServer", () => { console.log("Prompt list changed on myWeatherServer."); // You should re-fetch the list of prompts // await mcpClient.prompts.list(); }); ``` ## 例 ### 静的ツール設定 アプリ全体でMCPサーバーへの単一接続を持つツールの場合、`getTools()`を使用してツールをエージェントに渡します: ```typescript import { MCPClient } from "@mastra/mcp"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const mcp = new MCPClient({ servers: { stockPrice: { command: "npx", args: ["tsx", "stock-price.ts"], env: { API_KEY: "your-api-key", }, log: (logMessage) => { console.log(`[${logMessage.level}] ${logMessage.message}`); }, }, weather: { url: new URL("http://localhost:8080/sse"), }, }, timeout: 30000, // Global 30s timeout }); // Create an agent with access to all tools const agent = new Agent({ name: "Multi-tool Agent", instructions: "You have access to multiple tool servers.", model: openai("gpt-4"), tools: await mcp.getTools(), }); // Example of using resource methods async function checkWeatherResource() { try { const weatherResources = await mcp.resources.list(); if (weatherResources.weather && weatherResources.weather.length > 0) { const currentWeatherURI = weatherResources.weather[0].uri; const weatherData = await mcp.resources.read( "weather", currentWeatherURI, ); console.log("Weather data:", weatherData.contents[0].text); } } catch (error) { console.error("Error fetching weather resource:", error); } } checkWeatherResource(); // Example of using prompt methods async function checkWeatherPrompt() { try { const weatherPrompts = await mcp.prompts.list(); if (weatherPrompts.weather && weatherPrompts.weather.length > 0) { const currentWeatherPrompt = weatherPrompts.weather.find( (p) => p.name === "current" ); if (currentWeatherPrompt) { console.log("Weather prompt:", currentWeatherPrompt); } else { console.log("Current weather prompt not found"); } } } catch (error) { console.error("Error fetching weather prompt:", error); } } checkWeatherPrompt(); ``` ### 動的ツールセット 各ユーザーに対して新しいMCP接続が必要な場合、`getToolsets()`を使用してstreamまたはgenerateを呼び出す際にツールを追加します: ```typescript import { Agent } from "@mastra/core/agent"; import { MCPClient } from "@mastra/mcp"; import { openai } from "@ai-sdk/openai"; // Create the agent first, without any tools const agent = new Agent({ name: "Multi-tool Agent", instructions: "You help users check stocks and weather.", model: openai("gpt-4"), }); // Later, configure MCP with user-specific settings const mcp = new MCPClient({ servers: { stockPrice: { command: "npx", args: ["tsx", "stock-price.ts"], env: { API_KEY: "user-123-api-key", }, timeout: 20000, // Server-specific timeout }, weather: { url: new URL("http://localhost:8080/sse"), requestInit: { headers: { Authorization: `Bearer user-123-token`, }, }, }, }, }); // Pass all toolsets to stream() or generate() const response = await agent.stream( "How is AAPL doing and what is the weather?", { toolsets: await mcp.getToolsets(), }, ); ``` ## インスタンス管理 `MCPClient`クラスには、複数のインスタンスを管理するためのメモリリーク防止機能が組み込まれています: 1. `id`なしで同一の構成で複数のインスタンスを作成すると、メモリリークを防ぐためにエラーがスローされます 2. 同一の構成で複数のインスタンスが必要な場合は、各インスタンスに一意の`id`を提供してください 3. 同じ構成でインスタンスを再作成する前に、`await configuration.disconnect()`を呼び出してください 4. 1つのインスタンスだけが必要な場合は、再作成を避けるために構成をより高いスコープに移動することを検討してください 例えば、`id`なしで同じ構成の複数のインスタンスを作成しようとすると: ```typescript // 最初のインスタンス - OK const mcp1 = new MCPClient({ servers: { /* ... */ }, }); // 同じ構成の2番目のインスタンス - エラーがスローされます const mcp2 = new MCPClient({ servers: { /* ... */ }, }); // 修正するには、以下のいずれかを行います: // 1. 一意のIDを追加する const mcp3 = new MCPClient({ id: "instance-1", servers: { /* ... */ }, }); // 2. または再作成する前に切断する await mcp1.disconnect(); const mcp4 = new MCPClient({ servers: { /* ... */ }, }); ``` ## サーバーライフサイクル MCPClientはサーバー接続を適切に処理します: 1. 複数のサーバーへの自動接続管理 2. 開発中にエラーメッセージが表示されないようにするための適切なサーバーシャットダウン 3. 切断時のリソースの適切なクリーンアップ ## SSEリクエストヘッダーの使用 レガシーSSE MCPトランスポートを使用する場合、MCP SDKのバグにより、`requestInit`と`eventSourceInit`の両方を設定する必要があります: ```ts const sseClient = new MCPClient({ servers: { exampleServer: { url: new URL("https://your-mcp-server.com/sse"), // 注意:requestInitだけではSSEには不十分です requestInit: { headers: { Authorization: "Bearer your-token", }, }, // これもカスタムヘッダーを持つSSE接続には必要です eventSourceInit: { fetch(input: Request | URL | string, init?: RequestInit) { const headers = new Headers(init?.headers || {}); headers.set("Authorization", "Bearer your-token"); return fetch(input, { ...init, headers, }); }, }, }, }, }); ``` ## 関連情報 - MCPサーバーの作成については、[MCPServerのドキュメント](./mcp-server)を参照してください。 - Model Context Protocolの詳細については、[@modelcontextprotocol/sdkのドキュメント](https://github.com/modelcontextprotocol/typescript-sdk)を参照してください。 --- title: "リファレンス: MCPClient | ツール管理 | Mastra ドキュメント" description: MCPClient の API リファレンス - 複数のモデルコンテキストプロトコルサーバーとそのツールを管理するためのクラス。 --- # MCPClient [JA] Source: https://mastra.ai/ja/reference/tools/mcp-configuration `MCPClient` クラスは、Mastra アプリケーション内で複数の MCP サーバー接続とそのツールを管理する方法を提供します。接続のライフサイクルを管理し、ツールの名前空間を処理し、すべての設定されたサーバーにわたってツールへの便利なアクセスを提供します。 ## コンストラクタ MCPClientクラスの新しいインスタンスを作成します。 ```typescript constructor({ id?: string; servers: Record; timeout?: number; }: MCPClientOptions) ``` ### MCPClientOptions
", description: "サーバー設定のマップ。各キーは一意のサーバー識別子であり、値はサーバー設定です。", }, { name: "timeout", type: "number", isOptional: true, defaultValue: "60000", description: "個々のサーバー設定で上書きされない限り、すべてのサーバーに適用されるグローバルタイムアウト値(ミリ秒単位)。", }, ]} /> ### MastraMCPServerDefinition `servers`マップ内の各サーバーは、stdioベースのサーバーまたはSSEベースのサーバーとして設定できます。 利用可能な設定オプションの詳細については、MastraMCPClientドキュメントの[MastraMCPServerDefinition](./client#mastramcpserverdefinition)を参照してください。 ## メソッド ### getTools() 設定されたすべてのサーバーからすべてのツールを取得し、ツール名はサーバー名で名前空間化されます(`serverName_toolName`の形式)。これは競合を防ぐためです。 Agentの定義に渡すことを意図しています。 ```ts new Agent({ tools: await mcp.getTools() }); ``` ### getToolsets() 名前空間化されたツール名(`serverName.toolName`の形式)をそのツール実装にマッピングするオブジェクトを返します。 generateまたはstreamメソッドに動的に渡すことを意図しています。 ```typescript const res = await agent.stream(prompt, { toolsets: await mcp.getToolsets(), }); ``` ### disconnect() すべてのMCPサーバーから切断し、リソースをクリーンアップします。 ```typescript async disconnect(): Promise ``` ## 例 ### 基本的な使用法 ```typescript import { MCPClient } from "@mastra/mcp"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; const mcp = new MCPClient({ servers: { stockPrice: { command: "npx", args: ["tsx", "stock-price.ts"], env: { API_KEY: "your-api-key", }, log: (logMessage) => { console.log(`[${logMessage.level}] ${logMessage.message}`); }, }, weather: { url: new URL("http://localhost:8080/sse"),∂ }, }, timeout: 30000, // グローバルな30秒タイムアウト }); // すべてのツールにアクセスできるエージェントを作成 const agent = new Agent({ name: "Multi-tool Agent", instructions: "あなたは複数のツールサーバーにアクセスできます。", model: openai("gpt-4"), tools: await mcp.getTools(), }); ``` ### generate()またはstream()でのツールセットの使用 ```typescript import { Agent } from "@mastra/core/agent"; import { MCPClient } from "@mastra/mcp"; import { openai } from "@ai-sdk/openai"; // まず、ツールなしでエージェントを作成 const agent = new Agent({ name: "Multi-tool Agent", instructions: "あなたはユーザーが株価と天気を確認するのを手伝います。", model: openai("gpt-4"), }); // 後で、ユーザー固有の設定でMCPを構成 const mcp = new MCPClient({ servers: { stockPrice: { command: "npx", args: ["tsx", "stock-price.ts"], env: { API_KEY: "user-123-api-key", }, timeout: 20000, // サーバー固有のタイムアウト }, weather: { url: new URL("http://localhost:8080/sse"), requestInit: { headers: { Authorization: `Bearer user-123-token`, }, }, }, }, }); // すべてのツールセットをstream()またはgenerate()に渡す const response = await agent.stream( "AAPLの調子はどうですか?また、天気はどうですか?", { toolsets: await mcp.getToolsets(), }, ); ``` ## リソース管理 `MCPClient` クラスには、複数のインスタンスを管理するためのメモリリーク防止機能が組み込まれています: 1. `id` なしで同一の設定を持つ複数のインスタンスを作成すると、メモリリークを防ぐためにエラーが発生します 2. 同一の設定を持つ複数のインスタンスが必要な場合は、各インスタンスに一意の `id` を指定してください 3. 同じ設定でインスタンスを再作成する前に `await configuration.disconnect()` を呼び出してください 4. インスタンスが1つだけ必要な場合は、再作成を避けるために設定をより高いスコープに移動することを検討してください 例えば、`id` なしで同じ設定で複数のインスタンスを作成しようとすると: ```typescript // 最初のインスタンス - OK const mcp1 = new MCPClient({ servers: { /* ... */ }, }); // 同じ設定での2番目のインスタンス - エラーが発生します const mcp2 = new MCPClient({ servers: { /* ... */ }, }); // 修正方法: // 1. 一意のIDを追加 const mcp3 = new MCPClient({ id: "instance-1", servers: { /* ... */ }, }); // 2. または再作成前に切断 await mcp1.disconnect(); const mcp4 = new MCPClient({ servers: { /* ... */ }, }); ``` ## サーバーライフサイクル MCPClientはサーバー接続を優雅に処理します: 1. 複数のサーバーに対する自動接続管理 2. 開発中のエラーメッセージを防ぐための優雅なサーバーシャットダウン 3. 切断時のリソースの適切なクリーンアップ ## 関連情報 - 個々のMCPクライアント設定の詳細については、[MastraMCPClient ドキュメント](./client)を参照してください - モデルコンテキストプロトコルについて詳しくは、[@modelcontextprotocol/sdk ドキュメント](https://github.com/modelcontextprotocol/typescript-sdk)を参照してください --- title: "リファレンス: MCPServer | MCP を通じた Mastra ツールの公開 | Mastra ドキュメント" description: MCPServer の API リファレンス - Mastra ツールや機能を Model Context Protocol サーバーとして公開するためのクラス。 --- # MCPServer [JA] Source: https://mastra.ai/ja/reference/tools/mcp-server `MCPServer` クラスは、既存の Mastra ツールや Agent を Model Context Protocol (MCP) サーバーとして公開する機能を提供します。これにより、任意の MCP クライアント(Cursor、Windsurf、Claude Desktop など)がこれらの機能に接続し、エージェントで利用できるようになります。 ツールやエージェントを Mastra アプリケーション内で直接使用するだけであれば、必ずしも MCP サーバーを作成する必要はありません。この API は、Mastra のツールやエージェントを _外部_ の MCP クライアントに公開するためのものです。 [stdio(サブプロセス)および SSE(HTTP)MCP トランスポート](https://modelcontextprotocol.io/docs/concepts/transports) の両方に対応しています。 ## Constructor 新しい`MCPServer`を作成するには、サーバーに関する基本情報、提供するツール、そしてオプションでツールとして公開したいエージェントを提供する必要があります。 ```typescript import { openai } from "@ai-sdk/openai"; import { Agent } from "@mastra/core/agent"; import { createTool } from "@mastra/core/tools"; import { MCPServer } from "@mastra/mcp"; import { z } from "zod"; import { dataProcessingWorkflow } from "../workflows/dataProcessingWorkflow"; const myAgent = new Agent({ name: "MyExampleAgent", description: "A generalist to help with basic questions." instructions: "You are a helpful assistant.", model: openai("gpt-4o-mini"), }); const weatherTool = createTool({ id: "getWeather", description: "Gets the current weather for a location.", inputSchema: z.object({ location: z.string() }), execute: async ({ context }) => `Weather in ${context.location} is sunny.`, }); const server = new MCPServer({ name: "My Custom Server", version: "1.0.0", tools: { weatherTool }, agents: { myAgent }, // this agent will become tool "ask_myAgent" workflows: { dataProcessingWorkflow, // this workflow will become tool "run_dataProcessingWorkflow" } }); ``` ### 設定プロパティ コンストラクタは以下のプロパティを持つ`MCPServerConfig`オブジェクトを受け取ります: ", isOptional: true, description: "キーがエージェント識別子で、値がMastra Agentインスタンスであるオブジェクト。各エージェントは自動的に`ask_`という名前のツールに変換されます。エージェントは、コンストラクタ設定で定義された空でない`description`文字列プロパティを**必須**で持つ必要があります。この説明はツールの説明に使用されます。エージェントの説明が欠落しているか空の場合、MCPServerの初期化中にエラーがスローされます。", }, { name: "workflows", type: "Record", isOptional: true, description: "キーがワークフロー識別子で、値がMastra Workflowインスタンスであるオブジェクト。各ワークフローは`run_`という名前のツールに変換されます。ワークフローの`inputSchema`がツールの入力スキーマになります。ワークフローは空でない`description`文字列プロパティを**必須**で持つ必要があり、これがツールの説明に使用されます。ワークフローの説明が欠落しているか空の場合、エラーがスローされます。ツールは`workflow.createRun().start({ inputData: })`を呼び出してワークフローを実行します。エージェントやワークフローから派生したツール名(例:`ask_myAgent`や`run_myWorkflow`)が明示的に定義されたツール名や他の派生名と衝突する場合、明示的に定義されたツールが優先され、警告がログに記録されます。その後の衝突を引き起こすエージェント/ワークフローはスキップされます。", }, { name: "id", type: "string", isOptional: true, description: "サーバーのオプションの一意識別子。提供されない場合、UUIDが生成されます。このIDは最終的なものと見なされ、提供された場合はMastraによって変更できません。", }, { name: "description", type: "string", isOptional: true, description: "MCPサーバーが何をするかのオプションの説明。", }, { name: "repository", type: "Repository", // { url: string; source: string; id: string; } isOptional: true, description: "サーバーのソースコードのオプションのリポジトリ情報。", }, { name: "releaseDate", type: "string", // ISO 8601 isOptional: true, description: "このサーバーバージョンのオプションのリリース日(ISO 8601文字列)。提供されない場合、インスタンス化時の時刻がデフォルトになります。", }, { name: "isLatest", type: "boolean", isOptional: true, description: "これが最新バージョンかどうかを示すオプションのフラグ。提供されない場合、デフォルトでtrueになります。", }, { name: "packageCanonical", type: "'npm' | 'docker' | 'pypi' | 'crates' | string", isOptional: true, description: "サーバーがパッケージとして配布される場合のオプションの正規パッケージ形式(例:'npm'、'docker')。", }, { name: "packages", type: "PackageInfo[]", isOptional: true, description: "このサーバーのインストール可能なパッケージのオプションのリスト。", }, { name: "remotes", type: "RemoteInfo[]", isOptional: true, description: "このサーバーのリモートアクセスポイントのオプションのリスト。", }, { name: "resources", type: "MCPServerResources", isOptional: true, description: "サーバーがMCPリソースをどのように処理するかを定義するオブジェクト。詳細はリソース処理セクションを参照してください。", }, { name: "prompts", type: "MCPServerPrompts", isOptional: true, description: "サーバーがMCPプロンプトをどのように処理するかを定義するオブジェクト。詳細はプロンプト処理セクションを参照してください。", }, ]} /> ## エージェントをツールとして公開する `MCPServer` の強力な機能の一つは、Mastra エージェントを自動的に呼び出し可能なツールとして公開できることです。設定の `agents` プロパティにエージェントを指定すると、以下のようになります。 - **ツール名**: 各エージェントは `ask_` という名前のツールに変換されます。ここで `` は `agents` オブジェクトでそのエージェントに使用したキーです。例えば、`agents: { myAgentKey: myAgentInstance }` のように設定した場合、`ask_myAgentKey` という名前のツールが作成されます。 - **ツールの機能**: - **説明**: 生成されたツールの説明は次の形式になります: 「エージェント `` に質問します。元のエージェントの指示: ``」。 - **入力**: ツールは `message` プロパティ(文字列)を持つ単一のオブジェクト引数を受け取ります: `{ message: "エージェントへの質問" }`。 - **実行**: このツールが呼び出されると、対応するエージェントの `generate()` メソッドが、指定された `query` を渡して実行されます。 - **出力**: エージェントの `generate()` メソッドからの直接の結果がツールの出力として返されます。 - **名前の衝突**: `tools` 設定で明示的に定義されたツールが、エージェント由来のツールと同じ名前を持つ場合(例: `ask_myAgentKey` というツールと、`myAgentKey` というキーのエージェントが両方存在する場合)、_明示的に定義されたツールが優先されます_。この場合、エージェントはツールに変換されず、警告が記録されます。 これにより、MCP クライアントが他のツールと同じように自然言語クエリを使ってエージェントとやり取りできるようになります。 ### エージェントからツールへの変換 `agents` 設定プロパティにエージェントを指定すると、`MCPServer` は各エージェントに対応するツールを自動的に作成します。ツール名は `ask_` となり、`` は `agents` オブジェクトで使用したキーです。 生成されたツールの説明は次のようになります: 「エージェント `` に質問します。エージェントの説明: ``」。 **重要**: エージェントがツールに変換されるためには、インスタンス化時の設定で空でない `description` 文字列プロパティが**必ず**設定されている必要があります(例: `new Agent({ name: 'myAgent', description: 'This agent does X.', ... })`)。`description` がない、または空のエージェントを `MCPServer` に渡すと、`MCPServer` のインスタンス化時にエラーが発生し、サーバーのセットアップが失敗します。 これにより、エージェントの生成機能を MCP 経由ですばやく公開でき、クライアントがエージェントに直接「質問」できるようになります。 ## メソッド これらは`MCPServer`インスタンスで呼び出すことができる関数で、その動作を制御し情報を取得するためのものです。 ### startStdio() このメソッドを使用して、標準入出力(stdio)を使用して通信するようにサーバーを起動します。これは、サーバーをコマンドラインプログラムとして実行する場合の典型的な方法です。 ```typescript async startStdio(): Promise ``` 以下は、stdioを使用してサーバーを起動する方法です: ```typescript const server = new MCPServer({ // example configuration above }); await server.startStdio(); ``` ### startSSE() このメソッドは、MCPサーバーを既存のWebサーバーと統合して、Server-Sent Events(SSE)を通信に使用するのに役立ちます。WebサーバーのコードからSSEまたはメッセージパスへのリクエストを受信したときに、このメソッドを呼び出します。 ```typescript async startSSE({ url, ssePath, messagePath, req, res, }: { url: URL; ssePath: string; messagePath: string; req: any; res: any; }): Promise ``` 以下は、HTTPサーバーのリクエストハンドラー内で`startSSE`を使用する例です。この例では、MCPクライアントは`http://localhost:1234/sse`であなたのMCPサーバーに接続できます: ```typescript import http from "http"; const httpServer = http.createServer(async (req, res) => { await server.startSSE({ url: new URL(req.url || "", `http://localhost:1234`), ssePath: "/sse", messagePath: "/message", req, res, }); }); httpServer.listen(PORT, () => { console.log(`HTTP server listening on port ${PORT}`); }); ``` 以下は、`startSSE`メソッドに必要な値の詳細です: ### startHonoSSE() このメソッドは、MCPサーバーを既存のWebサーバーと統合して、Server-Sent Events(SSE)を通信に使用するのに役立ちます。WebサーバーのコードからSSEまたはメッセージパスへのリクエストを受信したときに、このメソッドを呼び出します。 ```typescript async startHonoSSE({ url, ssePath, messagePath, req, res, }: { url: URL; ssePath: string; messagePath: string; req: any; res: any; }): Promise ``` 以下は、HTTPサーバーのリクエストハンドラー内で`startHonoSSE`を使用する例です。この例では、MCPクライアントは`http://localhost:1234/hono-sse`であなたのMCPサーバーに接続できます: ```typescript import http from "http"; const httpServer = http.createServer(async (req, res) => { await server.startHonoSSE({ url: new URL(req.url || "", `http://localhost:1234`), ssePath: "/hono-sse", messagePath: "/message", req, res, }); }); httpServer.listen(PORT, () => { console.log(`HTTP server listening on port ${PORT}`); }); ``` 以下は、`startHonoSSE`メソッドに必要な値の詳細です: ### startHTTP() このメソッドは、MCPサーバーを既存のWebサーバーと統合して、通信にストリーマブルHTTPを使用するのに役立ちます。WebサーバーがHTTPリクエストを受信したときに、Webサーバーのコードからこれを呼び出します。 ```typescript async startHTTP({ url, httpPath, req, res, options = { sessionIdGenerator: () => randomUUID() }, }: { url: URL; httpPath: string; req: http.IncomingMessage; res: http.ServerResponse; options?: StreamableHTTPServerTransportOptions; }): Promise ``` HTTPサーバーのリクエストハンドラー内で`startHTTP`を使用する方法の例を以下に示します。この例では、MCPクライアントは`http://localhost:1234/http`でMCPサーバーに接続できます: ```typescript import http from "http"; const httpServer = http.createServer(async (req, res) => { await server.startHTTP({ url: new URL(req.url || '', 'http://localhost:1234'), httpPath: `/mcp`, req, res, options: { sessionIdGenerator: undefined, }, }); }); httpServer.listen(PORT, () => { console.log(`HTTP server listening on port ${PORT}`); }); ``` `startHTTP`メソッドで必要な値の詳細は以下の通りです: `StreamableHTTPServerTransportOptions`オブジェクトを使用すると、HTTPトランスポートの動作をカスタマイズできます。利用可能なオプションは以下の通りです: string) | undefined', description: '一意のセッションIDを生成する関数。これは暗号学的に安全で、グローバルに一意な文字列である必要があります。セッション管理を無効にするには`undefined`を返します。', }, { name: 'onsessioninitialized', type: '(sessionId: string) => void', description: '新しいセッションが初期化されたときに呼び出されるコールバック。アクティブなMCPセッションを追跡するのに便利です。', optional: true, }, { name: 'enableJsonResponse', type: 'boolean', description: '`true`の場合、サーバーはストリーミングにServer-Sent Events(SSE)を使用する代わりに、プレーンなJSONレスポンスを返します。デフォルトは`false`です。', optional: true, }, { name: 'eventStore', type: 'EventStore', description: 'メッセージの再開可能性のためのイベントストア。これを提供すると、クライアントが再接続してメッセージストリームを再開できるようになります。', optional: true, }, ]} /> ### close() このメソッドはサーバーを閉じ、すべてのリソースを解放します。 ```typescript async close(): Promise ``` ### getServerInfo() このメソッドはサーバーの基本情報を確認できます。 ```typescript getServerInfo(): ServerInfo ``` ### getServerDetail() このメソッドはサーバーの詳細情報を確認できます。 ```typescript getServerDetail(): ServerDetail ``` ### getToolListInfo() このメソッドは、サーバーを作成した際に設定されたツールの一覧を確認できます。読み取り専用のリストで、デバッグ目的に便利です。 ```typescript getToolListInfo(): ToolListInfo ``` ### getToolInfo() このメソッドは、特定のツールに関する詳細情報を提供します。 ```typescript getToolInfo(toolName: string): ToolInfo ``` ### executeTool() このメソッドは、特定のツールを実行し、結果を返します。 ```typescript executeTool(toolName: string, input: any): Promise ``` ### getStdioTransport() `startStdio()`でサーバーを開始した場合、これを使用してstdio通信を管理するオブジェクトを取得できます。これは主に内部チェックやテスト用です。 ```typescript getStdioTransport(): StdioServerTransport | undefined ``` ### getSseTransport() `startSSE()`でサーバーを開始した場合、これを使用してSSE通信を管理するオブジェクトを取得できます。`getStdioTransport`と同様に、これは主に内部チェックやテスト用です。 ```typescript getSseTransport(): SSEServerTransport | undefined ``` ### getSseHonoTransport() `startHonoSSE()`でサーバーを開始した場合、これを使用してSSE通信を管理するオブジェクトを取得できます。`getSseTransport`と同様に、これは主に内部チェックやテスト用です。 ```typescript getSseHonoTransport(): SSETransport | undefined ``` ### getStreamableHTTPTransport() `startHTTP()`でサーバーを開始した場合、これを使用してHTTP通信を管理するオブジェクトを取得できます。`getSseTransport`と同様に、これは主に内部チェックやテスト用です。 ```typescript getStreamableHTTPTransport(): StreamableHTTPServerTransport | undefined ``` ### tools() このMCPサーバーが提供する特定のツールを実行します。 ```typescript async executeTool( toolId: string, args: any, executionContext?: { messages?: any[]; toolCallId?: string }, ): Promise ``` ## リソースの取り扱い ### MCPリソースとは? リソースは、Model Context Protocol (MCP) の中核となるプリミティブであり、サーバーがクライアントにデータやコンテンツを公開し、LLMとのやり取りのコンテキストとして利用できるようにします。リソースは、MCPサーバーが提供したいあらゆる種類のデータを表します。例えば: - ファイルの内容 - データベースのレコード - APIのレスポンス - ライブシステムデータ - スクリーンショットや画像 - ログファイル リソースは一意のURI(例:`file:///home/user/documents/report.pdf`、`postgres://database/customers/schema`)で識別され、テキスト(UTF-8エンコード)またはバイナリデータ(base64エンコード)のいずれかを含むことができます。 クライアントは以下の方法でリソースを発見できます: 1. **直接リソース**: サーバーは `resources/list` エンドポイントを通じて具体的なリソースのリストを公開します。 2. **リソーステンプレート**: 動的なリソースの場合、サーバーはクライアントがリソースURIを構築するためのURIテンプレート(RFC 6570)を公開できます。 リソースを読み取るには、クライアントがURIを指定して `resources/read` リクエストを送信します。また、サーバーはリソースリストの変更(`notifications/resources/list_changed`)や特定リソースの内容更新(`notifications/resources/updated`)について、クライアントがそのリソースを購読している場合に通知することもできます。 より詳細な情報については、[公式MCPドキュメントのリソースに関するページ](https://modelcontextprotocol.io/docs/concepts/resources)を参照してください。 ### `MCPServerResources` 型 `resources` オプションは `MCPServerResources` 型のオブジェクトを受け取ります。この型は、サーバーがリソースリクエストを処理するために使用するコールバックを定義します: ```typescript export type MCPServerResources = { // 利用可能なリソースをリストするコールバック listResources: () => Promise; // 特定のリソースの内容を取得するコールバック getResourceContent: ({ uri, }: { uri: string; }) => Promise; // 利用可能なリソーステンプレートをリストするオプションのコールバック resourceTemplates?: () => Promise; }; export type MCPServerResourceContent = { text?: string } | { blob?: string }; ``` 例: ```typescript import { MCPServer } from "@mastra/mcp"; import type { MCPServerResourceContent, Resource, ResourceTemplate, } from "@mastra/mcp"; // リソースやリソーステンプレートは通常、動的に取得されます。 const myResources: Resource[] = [ { uri: "file://data/123.txt", name: "Data File", mimeType: "text/plain" }, ]; const myResourceContents: Record = { "file://data.txt/123": { text: "This is the content of the data file." }, }; const myResourceTemplates: ResourceTemplate[] = [ { uriTemplate: "file://data/{id}", name: "Data File", description: "A file containing data.", mimeType: "text/plain", }, ]; const myResourceHandlers: MCPServerResources = { listResources: async () => myResources, getResourceContent: async ({ uri }) => { if (myResourceContents[uri]) { return myResourceContents[uri]; } throw new Error(`Resource content not found for ${uri}`); }, resourceTemplates: async () => myResourceTemplates, }; const serverWithResources = new MCPServer({ name: "Resourceful Server", version: "1.0.0", tools: { /* ... your tools ... */ }, resources: myResourceHandlers, }); ``` ### クライアントへのリソース変更通知 利用可能なリソースやその内容が変更された場合、サーバーは特定のリソースを購読している接続中のクライアントに通知することができます。 #### `server.resources.notifyUpdated({ uri: string })` 特定のリソース(`uri`で識別)の内容が更新されたときにこのメソッドを呼び出します。該当するURIを購読しているクライアントには、`notifications/resources/updated` メッセージが送信されます。 ```typescript async server.resources.notifyUpdated({ uri: string }): Promise ``` 例: ```typescript // 'file://data.txt' の内容を更新した後 await serverWithResources.resources.notifyUpdated({ uri: "file://data.txt" }); ``` #### `server.resources.notifyListChanged()` 利用可能なリソースの全体リストが変更されたとき(例:リソースが追加または削除された場合)にこのメソッドを呼び出します。これにより、クライアントに `notifications/resources/list_changed` メッセージが送信され、リソースリストの再取得が促されます。 ```typescript async server.resources.notifyListChanged(): Promise ``` 例: ```typescript // 'myResourceHandlers.listResources' で管理されているリストに新しいリソースを追加した後 await serverWithResources.resources.notifyListChanged(); ``` ## プロンプト処理 ### MCPプロンプトとは? プロンプトは、MCPサーバーがクライアントに公開する再利用可能なテンプレートまたはワークフローです。引数を受け取り、リソースコンテキストを含み、バージョニングをサポートし、LLMインタラクションを標準化するために使用できます。 プロンプトは一意の名前(およびオプションのバージョン)で識別され、動的または静的にできます。 ### `MCPServerPrompts` 型 `prompts`オプションは`MCPServerPrompts`型のオブジェクトを受け取ります。この型は、サーバーがプロンプトリクエストを処理するために使用するコールバックを定義します: ```typescript export type MCPServerPrompts = { // Callback to list available prompts listPrompts: () => Promise; // Callback to get the messages/content for a specific prompt getPromptMessages?: ({ name, version, args, }: { name: string; version?: string; args?: any; }) => Promise<{ prompt: Prompt; messages: PromptMessage[] }>; }; ``` 例: ```typescript import { MCPServer } from "@mastra/mcp"; import type { Prompt, PromptMessage, MCPServerPrompts } from "@mastra/mcp"; const prompts: Prompt[] = [ { name: "analyze-code", description: "Analyze code for improvements", version: "v1" }, { name: "analyze-code", description: "Analyze code for improvements (new logic)", version: "v2" } ]; const myPromptHandlers: MCPServerPrompts = { listPrompts: async () => prompts, getPromptMessages: async ({ name, version, args }) => { if (name === "analyze-code") { if (version === "v2") { const prompt = prompts.find(p => p.name === name && p.version === "v2"); if (!prompt) throw new Error("Prompt version not found"); return { prompt, messages: [ { role: "user", content: { type: "text", text: `Analyze this code with the new logic: ${args.code}` } } ] }; } // Default or v1 const prompt = prompts.find(p => p.name === name && p.version === "v1"); if (!prompt) throw new Error("Prompt version not found"); return { prompt, messages: [ { role: "user", content: { type: "text", text: `Analyze this code: ${args.code}` } } ] }; } throw new Error("Prompt not found"); } }; const serverWithPrompts = new MCPServer({ name: "Promptful Server", version: "1.0.0", tools: { /* ... */ }, prompts: myPromptHandlers, }); ``` ### プロンプト変更のクライアント通知 利用可能なプロンプトが変更された場合、サーバーは接続されたクライアントに通知できます: #### `server.prompts.notifyListChanged()` 利用可能なプロンプトの全体的なリストが変更された場合(例:プロンプトが追加または削除された場合)にこのメソッドを呼び出します。これにより、クライアントに`notifications/prompts/list_changed`メッセージが送信され、プロンプトのリストを再取得するよう促します。 ```typescript await serverWithPrompts.prompts.notifyListChanged(); ``` ### プロンプト処理のベストプラクティス - 明確で説明的なプロンプト名と説明を使用する。 - `getPromptMessages`で必要なすべての引数を検証する。 - 破壊的変更を予期する場合は`version`フィールドを含める。 - `version`パラメータを使用して正しいプロンプトロジックを選択する。 - プロンプトリストが変更されたときにクライアントに通知する。 - 情報的なメッセージでエラーを処理する。 - 引数の期待値と利用可能なバージョンを文書化する。 --- ## 例 MCPServerのセットアップとデプロイの実践的な例については、[MCPServerのデプロイ例](/examples/agents/deploying-mcp-server)を参照してください。 このページの冒頭の例でも、ツールとエージェントの両方を使用して`MCPServer`をインスタンス化する方法を示しています。 ## 関連情報 - MastraでMCPサーバーに接続する方法については、[MCPClientドキュメント](./mcp-client)を参照してください。 - Model Context Protocolの詳細については、[@modelcontextprotocol/sdkドキュメント](https://github.com/modelcontextprotocol/typescript-sdk)を参照してください。 --- title: "リファレンス: createVectorQueryTool() | RAG | Mastra Tools Docs" description: Mastraのベクトルクエリツールのドキュメント。フィルタリングと再ランキング機能を備えたベクトルストアでのセマンティック検索を促進します。 --- import { Callout } from "nextra/components"; import { Tabs } from "nextra/components"; # createVectorQueryTool() [JA] Source: https://mastra.ai/ja/reference/tools/vector-query-tool `createVectorQueryTool()` 関数は、ベクトルストアに対するセマンティック検索のためのツールを作成します。フィルタリング、リランキング、データベース固有の設定をサポートし、さまざまなベクトルストアバックエンドと統合できます。 ## 基本的な使い方 ```typescript import { openai } from "@ai-sdk/openai"; import { createVectorQueryTool } from "@mastra/rag"; const queryTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), }); ``` ## Parameters **パラメータ要件:** ほとんどのフィールドは作成時にデフォルトとして設定できます。 一部のフィールドは、ランタイムコンテキストまたは入力を介してランタイム時にオーバーライドできます。必須フィールドが作成時とランタイム時の両方で欠落している場合、エラーがスローされます。なお、`model`、`id`、`description`は作成時にのみ設定できます。 ### DatabaseConfig `DatabaseConfig`タイプを使用すると、クエリ操作に自動的に適用されるデータベース固有の設定を指定できます。これにより、異なるベクトルストアが提供する独自の機能と最適化を活用できます。 ", }, { name: "whereDocument", description: "ドキュメントコンテンツフィルタリング条件", isOptional: true, type: "Record", }, ], }, ], }, ]} /> ### RerankConfig ## 戻り値 このツールは以下のオブジェクトを返します: ### QueryResult オブジェクトの構造 ```typescript { id: string; // Unique chunk/document identifier metadata: any; // All metadata fields (document ID, etc.) vector: number[]; // Embedding vector (if available) score: number; // Similarity score for this retrieval document: string; // Full chunk/document text (if available) } ``` ## デフォルトツールの説明 デフォルトの説明は以下に重点を置いています: - 保存された知識から関連情報を見つけること - ユーザーの質問に答えること - 事実に基づく内容を取得すること ## 結果の処理 このツールは、ユーザーのクエリに基づいて返す結果の数を決定し、デフォルトでは10件の結果を返します。これはクエリの要件に応じて調整することができます。 ## フィルター付きの例 ```typescript const queryTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), enableFilter: true, }); ``` フィルタリングが有効になっている場合、このツールはクエリを処理し、セマンティック検索と組み合わせるメタデータフィルターを構築します。プロセスは次のように動作します: 1. ユーザーが「'version' フィールドが2.0より大きいコンテンツを探す」など、特定のフィルター条件を含むクエリを行います。 2. エージェントがクエリを解析し、適切なフィルターを構築します: ```typescript { "version": { "$gt": 2.0 } } ``` このエージェント駆動型のアプローチは以下のことを行います: - 自然言語のクエリをフィルター仕様に変換 - ベクトルストア固有のフィルター構文を実装 - クエリ用語をフィルター演算子に変換 詳細なフィルター構文やストア固有の機能については、[Metadata Filters](../rag/metadata-filters) のドキュメントをご覧ください。 エージェント駆動型フィルタリングの動作例については、[Agent-Driven Metadata Filtering](../../../examples/rag/usage/filter-rag) の例をご参照ください。 ## リランキング付きの例 ```typescript const queryTool = createVectorQueryTool({ vectorStoreName: "milvus", indexName: "documentation", model: openai.embedding("text-embedding-3-small"), reranker: { model: openai("gpt-4o-mini"), options: { weights: { semantic: 0.5, // Semantic relevance weight vector: 0.3, // Vector similarity weight position: 0.2, // Original position weight }, topK: 5, }, }, }); ``` リランキングは、以下を組み合わせることで結果の品質を向上させます: - セマンティック関連性:LLMベースのテキスト類似度スコアを使用 - ベクトル類似度:元のベクトル距離スコア - ポジションバイアス:元の結果の順序を考慮 - クエリ分析:クエリの特徴に基づく調整 リランカーは初期のベクトル検索結果を処理し、関連性を最適化した順序でリストを返します。 ## カスタム説明付きの例 ```typescript const queryTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), description: "Search through document archives to find relevant information for answering questions about company policies and procedures", }); ``` この例では、情報検索という基本的な目的を維持しつつ、特定のユースケースに合わせてツールの説明をカスタマイズする方法を示しています。 ## データベース固有の設定例 `databaseConfig`パラメータを使用すると、各ベクトルデータベース固有の機能と最適化を活用できます。これらの設定は、クエリ実行時に自動的に適用されます。 ### Pinecone設定 ```typescript const pineconeQueryTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pinecone: { namespace: "production", // 環境別にベクトルを整理 sparseVector: { // ハイブリッド検索を有効化 indices: [0, 1, 2, 3], values: [0.1, 0.2, 0.15, 0.05] } } } }); ``` **Pineconeの機能:** - **Namespace**: 同一インデックス内で異なるデータセットを分離 - **Sparse Vector**: 密ベクトルと疎ベクトルを組み合わせて検索品質を向上 - **使用例**: マルチテナントアプリケーション、ハイブリッドセマンティック検索 ### pgVector設定 ```typescript const pgVectorQueryTool = createVectorQueryTool({ vectorStoreName: "postgres", indexName: "embeddings", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pgvector: { minScore: 0.7, // 70%以上の類似度の結果のみを返す ef: 200, // 高い値 = より良い精度、遅い検索 probes: 10 // IVFFlat用: より多くのプローブ = より良い再現率 } } }); ``` **pgVectorの機能:** - **minScore**: 低品質のマッチを除外 - **ef (HNSW)**: HNSWインデックスの精度対速度を制御 - **probes (IVFFlat)**: IVFFlatインデックスの再現率対速度を制御 - **使用例**: パフォーマンス調整、品質フィルタリング ### Chroma設定 ```typescript const chromaQueryTool = createVectorQueryTool({ vectorStoreName: "chroma", indexName: "documents", model: openai.embedding("text-embedding-3-small"), databaseConfig: { chroma: { where: { // メタデータフィルタリング "category": "technical", "status": "published" }, whereDocument: { // ドキュメント内容フィルタリング "$contains": "API" } } } }); ``` **Chromaの機能:** - **where**: メタデータフィールドでフィルタリング - **whereDocument**: ドキュメント内容でフィルタリング - **使用例**: 高度なフィルタリング、コンテンツベース検索 ### 複数データベース設定 ```typescript // 複数データベース用の設定(動的ストアに便利) const multiDbQueryTool = createVectorQueryTool({ vectorStoreName: "dynamic-store", // 実行時に設定される indexName: "docs", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pinecone: { namespace: "default" }, pgvector: { minScore: 0.8, ef: 150 }, chroma: { where: { "type": "documentation" } } } }); ``` **マルチ設定の利点:** - 1つのツールで複数のベクトルストアをサポート - データベース固有の最適化が自動的に適用される - 柔軟なデプロイメントシナリオ ### 実行時設定のオーバーライド 異なるシナリオに適応するために、実行時にデータベース設定をオーバーライドできます: ```typescript import { RuntimeContext } from '@mastra/core/runtime-context'; const queryTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), databaseConfig: { pinecone: { namespace: "development" } } }); // 実行時にオーバーライド const runtimeContext = new RuntimeContext(); runtimeContext.set('databaseConfig', { pinecone: { namespace: 'production' // 本番環境のネームスペースに切り替え } }); const response = await agent.generate( "デプロイメントに関する情報を検索", { runtimeContext } ); ``` このアプローチにより、以下が可能になります: - 環境間の切り替え(開発/ステージング/本番) - 負荷に基づくパフォーマンスパラメータの調整 - リクエストごとの異なるフィルタリング戦略の適用 ## 例: ランタイムコンテキストの使用 ```typescript const queryTool = createVectorQueryTool({ vectorStoreName: "pinecone", indexName: "docs", model: openai.embedding("text-embedding-3-small"), }); ``` ランタイムコンテキストを使用する場合、実行時にランタイムコンテキスト経由で必要なパラメータを提供します: ```typescript const runtimeContext = new RuntimeContext<{ vectorStoreName: string; indexName: string; topK: number; filter: VectorFilter; databaseConfig: DatabaseConfig; }>(); runtimeContext.set("vectorStoreName", "my-store"); runtimeContext.set("indexName", "my-index"); runtimeContext.set("topK", 5); runtimeContext.set("filter", { category: "docs" }); runtimeContext.set("databaseConfig", { pinecone: { namespace: "runtime-namespace" } }); const response = await agent.generate( "Find documentation from the knowledge base.", { runtimeContext, }, ); ``` ランタイムコンテキストの詳細については、以下を参照してください: - [ランタイム変数](../../docs/agents/runtime-variables) - [動的コンテキスト](../../docs/tools-mcp/dynamic-context) ## ツールの詳細 このツールは以下のように作成されています: - **ID**: `VectorQuery {vectorStoreName} {indexName} Tool` - **入力スキーマ**: queryText と filter オブジェクトが必要 - **出力スキーマ**: relevantContext 文字列を返す ## 関連 - [rerank()](../rag/rerank) - [createGraphRAGTool](./graph-rag-tool) --- title: "リファレンス: Azure Voice | 音声プロバイダー | Mastra ドキュメント" description: "Azure Cognitive Services を使用したテキスト読み上げおよび音声認識機能を提供する AzureVoice クラスのドキュメント。" --- # Azure [JA] Source: https://mastra.ai/ja/reference/voice/azure MastraのAzureVoiceクラスは、Microsoft Azure Cognitive Servicesを利用してテキスト読み上げ(テキスト・トゥ・スピーチ)および音声認識(スピーチ・トゥ・テキスト)機能を提供します。 ## 使用例 ```typescript import { AzureVoice } from "@mastra/voice-azure"; // Initialize with configuration const voice = new AzureVoice({ speechModel: { name: "neural", apiKey: "your-azure-speech-api-key", region: "eastus", }, listeningModel: { name: "whisper", apiKey: "your-azure-speech-api-key", region: "eastus", }, speaker: "en-US-JennyNeural", // Default voice }); // Convert text to speech const audioStream = await voice.speak("Hello, how can I help you?", { speaker: "en-US-GuyNeural", // Override default voice style: "cheerful", // Voice style }); // Convert speech to text const text = await voice.listen(audioStream, { filetype: "wav", language: "en-US", }); ``` ## 設定 ### コンストラクターオプション ### AzureSpeechConfig ## メソッド ### speak() Azure のニューラルテキスト読み上げサービスを使用して、テキストを音声に変換します。 戻り値: `Promise` ### listen() Azure の音声認識サービスを使用して音声をテキストに書き起こします。 戻り値: `Promise` ### getSpeakers() 利用可能な音声オプションの配列を返します。各ノードには以下が含まれます: ## 注意事項 - APIキーは、コンストラクタのオプションまたは環境変数(AZURE_SPEECH_KEY と AZURE_SPEECH_REGION)で指定できます - Azure は多くの言語で幅広いニューラルボイスを提供しています - 一部のボイスは、明るい、悲しい、怒っているなどの話し方スタイルに対応しています - 音声認識は複数の音声フォーマットと言語をサポートしています - Azure の音声サービスは、自然な音声の高品質なニューラルボイスを提供します --- title: "リファレンス: Cloudflare Voice | 音声プロバイダー | Mastra ドキュメント" description: "CloudflareVoice クラスのドキュメント。Cloudflare Workers AI を使用したテキスト読み上げ機能を提供します。" --- # Cloudflare [JA] Source: https://mastra.ai/ja/reference/voice/cloudflare MastraのCloudflareVoiceクラスは、Cloudflare Workers AIを利用したテキスト読み上げ機能を提供します。このプロバイダーは、エッジコンピューティング環境に適した効率的で低遅延な音声合成を専門としています。 ## 使用例 ```typescript import { CloudflareVoice } from "@mastra/voice-cloudflare"; // Initialize with configuration const voice = new CloudflareVoice({ speechModel: { name: "@cf/meta/m2m100-1.2b", apiKey: "your-cloudflare-api-token", accountId: "your-cloudflare-account-id", }, speaker: "en-US-1", // Default voice }); // Convert text to speech const audioStream = await voice.speak("Hello, how can I help you?", { speaker: "en-US-2", // Override default voice }); // Get available voices const speakers = await voice.getSpeakers(); console.log(speakers); ``` ## 設定 ### コンストラクターオプション ### CloudflareSpeechConfig ## メソッド ### speak() Cloudflare のテキスト読み上げサービスを使用して、テキストを音声に変換します。 戻り値: `Promise` ### getSpeakers() 利用可能な音声オプションの配列を返します。各ノードには以下が含まれます: ## 注意事項 - APIトークンはコンストラクタのオプションまたは環境変数(CLOUDFLARE_API_TOKEN と CLOUDFLARE_ACCOUNT_ID)で指定できます - Cloudflare Workers AI は低遅延のエッジコンピューティング向けに最適化されています - このプロバイダーはテキストから音声(TTS)機能のみをサポートしており、音声からテキスト(STT)には対応していません - このサービスは他の Cloudflare Workers 製品と高い互換性があります - 本番環境で利用する場合は、ご自身の Cloudflare アカウントに適切な Workers AI サブスクリプションがあることを確認してください - 音声の選択肢は他の一部プロバイダーと比べて制限がありますが、エッジでのパフォーマンスは非常に優れています ## 関連プロバイダー テキスト読み上げに加えて音声認識機能が必要な場合は、以下のプロバイダーの利用を検討してください。 - [OpenAI](./openai) - TTSとSTTの両方を提供 - [Google](./google) - TTSとSTTの両方を提供 - [Azure](./azure) - TTSとSTTの両方を提供 --- title: "リファレンス: CompositeVoice | Voice Providers | Mastra ドキュメント" description: "CompositeVoice クラスのドキュメント。複数の音声プロバイダーを組み合わせて、柔軟なテキスト読み上げおよび音声認識操作を可能にします。" --- # CompositeVoice [JA] Source: https://mastra.ai/ja/reference/voice/composite-voice CompositeVoice クラスは、テキスト読み上げ(text-to-speech)や音声認識(speech-to-text)操作のために、異なる音声プロバイダーを組み合わせて利用することができます。これは、各操作ごとに最適なプロバイダーを使いたい場合に特に便利です。例えば、音声認識には OpenAI を、テキスト読み上げには PlayAI を使うといった使い方が可能です。 CompositeVoice は、Agent クラスによって内部的に使用され、柔軟な音声機能を提供します。 ## 使用例 ```typescript import { CompositeVoice } from "@mastra/core/voice"; import { OpenAIVoice } from "@mastra/voice-openai"; import { PlayAIVoice } from "@mastra/voice-playai"; // Create voice providers const openai = new OpenAIVoice(); const playai = new PlayAIVoice(); // Use OpenAI for listening (speech-to-text) and PlayAI for speaking (text-to-speech) const voice = new CompositeVoice({ input: openai, output: playai, }); // Convert speech to text using OpenAI const text = await voice.listen(audioStream); // Convert text to speech using PlayAI const audio = await voice.speak("Hello, world!"); ``` ## コンストラクタのパラメータ ## メソッド ### speak() 設定されたスピーキングプロバイダーを使用して、テキストを音声に変換します。 注意: - スピーキングプロバイダーが設定されていない場合、このメソッドはエラーをスローします - オプションは設定されたスピーキングプロバイダーにそのまま渡されます - 音声データのストリームを返します ### listen() 設定されたリスニングプロバイダーを使用して、音声をテキストに変換します。 注意: - リスニングプロバイダーが設定されていない場合、このメソッドはエラーをスローします - オプションは設定されたリスニングプロバイダーにそのまま渡されます - プロバイダーによって、文字列または書き起こされたテキストのストリームのいずれかを返します ### getSpeakers() スピーキングプロバイダーから利用可能な音声のリストを返します。各ノードには以下が含まれます: 注意: - スピーキングプロバイダーからのみ音声を返します - スピーキングプロバイダーが設定されていない場合、空の配列を返します - 各音声オブジェクトには少なくとも voiceId プロパティが含まれます - 追加の音声プロパティはスピーキングプロバイダーによって異なります --- title: "リファレンス: Deepgram Voice | 音声プロバイダー | Mastra ドキュメント" description: "Deepgram voice の実装に関するドキュメント。複数の音声モデルと言語によるテキスト読み上げおよび音声認識機能を提供します。" --- # Deepgram [JA] Source: https://mastra.ai/ja/reference/voice/deepgram MastraにおけるDeepgramの音声実装は、DeepgramのAPIを利用してテキスト読み上げ(TTS)および音声認識(STT)機能を提供します。複数の音声モデルと言語に対応しており、音声合成と文字起こしの両方で設定可能なオプションが用意されています。 ## 使用例 ```typescript import { DeepgramVoice } from "@mastra/voice-deepgram"; // Initialize with default configuration (uses DEEPGRAM_API_KEY environment variable) const voice = new DeepgramVoice(); // Initialize with custom configuration const voice = new DeepgramVoice({ speechModel: { name: "aura", apiKey: "your-api-key", }, listeningModel: { name: "nova-2", apiKey: "your-api-key", }, speaker: "asteria-en", }); // Text-to-Speech const audioStream = await voice.speak("Hello, world!"); // Speech-to-Text const transcript = await voice.listen(audioStream); ``` ## コンストラクタのパラメーター ### DeepgramVoiceConfig ", description: "Deepgram APIに渡す追加プロパティ", isOptional: true, }, { name: "language", type: "string", description: "モデルの言語コード", isOptional: true, }, ]} /> ## メソッド ### speak() 設定された音声モデルとボイスを使用して、テキストを音声に変換します。 戻り値: `Promise` ### listen() 設定されたリスニングモデルを使用して、音声をテキストに変換します。 戻り値: `Promise` ### getSpeakers() 利用可能なボイスオプションの一覧を返します。 --- title: "リファレンス: ElevenLabs Voice | Voice Providers | Mastra ドキュメント" description: "ElevenLabsの音声実装に関するドキュメント。複数の音声モデルと自然な音声合成による高品質なテキスト読み上げ機能を提供します。" --- # ElevenLabs [JA] Source: https://mastra.ai/ja/reference/voice/elevenlabs MastraにおけるElevenLabsの音声実装は、ElevenLabs APIを利用して高品質なテキスト読み上げ(TTS)および音声認識(STT)機能を提供します。 ## 使用例 ```typescript import { ElevenLabsVoice } from "@mastra/voice-elevenlabs"; // デフォルト設定で初期化(ELEVENLABS_API_KEY 環境変数を使用) const voice = new ElevenLabsVoice(); // カスタム設定で初期化 const voice = new ElevenLabsVoice({ speechModel: { name: "eleven_multilingual_v2", apiKey: "your-api-key", }, speaker: "custom-speaker-id", }); // テキスト読み上げ const audioStream = await voice.speak("Hello, world!"); // 利用可能なスピーカーを取得 const speakers = await voice.getSpeakers(); ``` ## コンストラクタのパラメーター ### ElevenLabsVoiceConfig ## メソッド ### speak() 設定された音声モデルとボイスを使用してテキストを音声に変換します。 戻り値: `Promise` ### getSpeakers() 利用可能なボイスオプションの配列を返します。各ノードには以下が含まれます: ### listen() ElevenLabs Speech-to-Text API を使用して音声入力をテキストに変換します。 options オブジェクトは以下のプロパティをサポートします: 戻り値: `Promise` - 書き起こされたテキストを解決する Promise ## 重要な注意事項 1. ElevenLabsのAPIキーが必要です。`ELEVENLABS_API_KEY`環境変数で設定するか、コンストラクタに渡してください。 2. デフォルトのスピーカーはAria(ID: '9BWtsMINqrJLrRacOk9x')に設定されています。 3. ElevenLabsでは音声からテキストへの機能はサポートされていません。 4. 利用可能なスピーカーは、`getSpeakers()`メソッドを使用して取得できます。このメソッドは、各ボイスの言語や性別などの詳細情報を返します。 --- title: "リファレンス: Google Voice | 音声プロバイダー | Mastra ドキュメント" description: "Google Voice 実装のドキュメント。テキスト読み上げおよび音声認識機能を提供します。" --- # Google [JA] Source: https://mastra.ai/ja/reference/voice/google Mastra における Google Voice の実装は、Google Cloud サービスを利用してテキスト読み上げ(TTS)と音声認識(STT)の両方の機能を提供します。複数の音声、言語、そして高度なオーディオ設定オプションに対応しています。 ## 使用例 ```typescript import { GoogleVoice } from "@mastra/voice-google"; // Initialize with default configuration (uses GOOGLE_API_KEY environment variable) const voice = new GoogleVoice(); // Initialize with custom configuration const voice = new GoogleVoice({ speechModel: { apiKey: "your-speech-api-key", }, listeningModel: { apiKey: "your-listening-api-key", }, speaker: "en-US-Casual-K", }); // Text-to-Speech const audioStream = await voice.speak("Hello, world!", { languageCode: "en-US", audioConfig: { audioEncoding: "LINEAR16", }, }); // Speech-to-Text const transcript = await voice.listen(audioStream, { config: { encoding: "LINEAR16", languageCode: "en-US", }, }); // Get available voices for a specific language const voices = await voice.getSpeakers({ languageCode: "en-US" }); ``` ## コンストラクタのパラメータ ### GoogleModelConfig ## メソッド ### speak() Google Cloud Text-to-Speech サービスを使用してテキストを音声に変換します。 戻り値: `Promise` ### listen() Google Cloud Speech-to-Text サービスを使用して音声をテキストに変換します。 戻り値: `Promise` ### getSpeakers() 利用可能なボイスオプションの配列を返します。各ノードには以下が含まれます: ## 重要な注意事項 1. Google Cloud APIキーが必要です。`GOOGLE_API_KEY` 環境変数で設定するか、コンストラクタで渡してください。 2. デフォルトの音声は 'en-US-Casual-K' に設定されています。 3. テキスト読み上げと音声認識サービスの両方で、デフォルトのオーディオエンコーディングは LINEAR16 です。 4. `speak()` メソッドは、Google Cloud Text-to-Speech API を通じて高度なオーディオ設定をサポートします。 5. `listen()` メソッドは、Google Cloud Speech-to-Text API を通じて様々な認識設定をサポートします。 6. 利用可能な音声は、`getSpeakers()` メソッドを使って言語コードでフィルタリングできます。 --- title: "リファレンス: MastraVoice | Voice Providers | Mastra ドキュメント" description: "Mastra のすべての音声サービスのコアインターフェースを定義する抽象基底クラス MastraVoice のドキュメント。音声から音声への機能も含まれます。" --- # MastraVoice [JA] Source: https://mastra.ai/ja/reference/voice/mastra-voice MastraVoice クラスは、Mastra における音声サービスのコアインターフェースを定義する抽象基底クラスです。すべての音声プロバイダー実装(OpenAI、Deepgram、PlayAI、Speechify など)は、このクラスを継承して、それぞれの機能を提供します。このクラスには、WebSocket 接続を通じたリアルタイム音声対音声機能のサポートも追加されています。 ## 使用例 ```typescript import { MastraVoice } from "@mastra/core/voice"; // Create a voice provider implementation class MyVoiceProvider extends MastraVoice { constructor(config: { speechModel?: BuiltInModelConfig; listeningModel?: BuiltInModelConfig; speaker?: string; realtimeConfig?: { model?: string; apiKey?: string; options?: unknown; }; }) { super({ speechModel: config.speechModel, listeningModel: config.listeningModel, speaker: config.speaker, realtimeConfig: config.realtimeConfig, }); } // Implement required abstract methods async speak( input: string | NodeJS.ReadableStream, options?: { speaker?: string }, ): Promise { // Implement text-to-speech conversion } async listen( audioStream: NodeJS.ReadableStream, options?: unknown, ): Promise { // Implement speech-to-text conversion } async getSpeakers(): Promise< Array<{ voiceId: string; [key: string]: unknown }> > { // Return list of available voices } // Optional speech-to-speech methods async connect(): Promise { // Establish WebSocket connection for speech-to-speech communication } async send(audioData: NodeJS.ReadableStream | Int16Array): Promise { // Stream audio data in speech-to-speech } async answer(): Promise { // Trigger voice provider to respond } addTools(tools: Array): void { // Add tools for the voice provider to use } close(): void { // Close WebSocket connection } on(event: string, callback: (data: unknown) => void): void { // Register event listener } off(event: string, callback: (data: unknown) => void): void { // Remove event listener } } ``` ## コンストラクタのパラメータ ### BuiltInModelConfig ### RealtimeConfig ## 抽象メソッド これらのメソッドは、MastraVoice を拡張する未知のクラスによって実装される必要があります。 ### speak() 設定された音声モデルを使用してテキストを音声に変換します。 ```typescript abstract speak( input: string | NodeJS.ReadableStream, options?: { speaker?: string; [key: string]: unknown; } ): Promise ``` 目的: - テキスト入力を受け取り、プロバイダーのテキスト読み上げサービスを使って音声に変換します - 柔軟性のため、文字列とストリームの両方の入力に対応しています - オプションでデフォルトの話者や声を上書きできます - 再生や保存が可能な音声データのストリームを返します - 音声が 'speaking' イベントの発火によって処理される場合は void を返すことがあります ### listen() 設定されたリスニングモデルを使用して音声をテキストに変換します。 ```typescript abstract listen( audioStream: NodeJS.ReadableStream, options?: { [key: string]: unknown; } ): Promise ``` 目的: - 音声ストリームを受け取り、プロバイダーの音声認識サービスを使ってテキストに変換します - 書き起こし設定のためにプロバイダー固有のオプションに対応しています - 完全なテキスト書き起こし、または書き起こしテキストのストリームのいずれかを返すことができます - すべてのプロバイダーがこの機能に対応しているわけではありません(例:PlayAI、Speechify) - 書き起こしが 'writing' イベントの発火によって処理される場合は void を返すことがあります ### getSpeakers() プロバイダーがサポートする利用可能な声のリストを返します。 ```typescript abstract getSpeakers(): Promise> ``` 目的: - プロバイダーから利用可能な声や話者のリストを取得します - 各声には少なくとも voiceId プロパティが必要です - プロバイダーは各声に関する追加のメタデータを含めることができます - テキスト読み上げ変換のために利用可能な声を見つける際に使用されます ## オプションのメソッド これらのメソッドにはデフォルトの実装がありますが、音声から音声への機能をサポートするプロバイダーによってオーバーライドすることができます。 ### connect() 通信のために WebSocket または WebRTC 接続を確立します。 ```typescript connect(config?: unknown): Promise ``` 目的: - 通信のために音声サービスへの接続を初期化します - send() や answer() などの機能を使用する前に呼び出す必要があります - 接続が確立されたときに解決される Promise を返します - 設定内容はプロバイダーごとに異なります ### send() 音声データをリアルタイムで音声プロバイダーにストリーミングします。 ```typescript send(audioData: NodeJS.ReadableStream | Int16Array): Promise ``` 目的: - 音声データをリアルタイムで音声プロバイダーに送信します - ライブマイク入力など、継続的な音声ストリーミングのシナリオに便利です - ReadableStream と Int16Array の両方の音声フォーマットをサポートします - このメソッドを呼び出す前に接続状態である必要があります ### answer() 音声プロバイダーに応答の生成を促します。 ```typescript answer(): Promise ``` 目的: - 音声プロバイダーに応答を生成するシグナルを送信します - AI に応答を促すリアルタイム会話で使用されます - 応答はイベントシステム(例: 'speaking' イベント)を通じて発信されます ### addTools() 会話中に使用できるツールを音声プロバイダーに装備します。 ```typescript addTools(tools: Array): void ``` 目的: - 会話中に音声プロバイダーが使用できるツールを追加します - ツールによって音声プロバイダーの機能を拡張できます - 実装はプロバイダーごとに異なります ### close() WebSocket または WebRTC 接続を切断します。 ```typescript close(): void ``` 目的: - 音声サービスへの接続を閉じます - リソースをクリーンアップし、進行中のリアルタイム処理を停止します - 音声インスタンスの利用が終わったら呼び出すべきです ### on() 音声イベントのイベントリスナーを登録します。 ```typescript on( event: E, callback: (data: E extends keyof VoiceEventMap ? VoiceEventMap[E] : unknown) => void, ): void ``` 目的: - 指定したイベントが発生したときに呼び出されるコールバック関数を登録します - 標準イベントには 'speaking'、'writing'、'error' などがあります - プロバイダーはカスタムイベントも発行できます - イベントデータの構造はイベントタイプによって異なります ### off() イベントリスナーを削除します。 ```typescript off( event: E, callback: (data: E extends keyof VoiceEventMap ? VoiceEventMap[E] : unknown) => void, ): void ``` 目的: - 以前に登録したイベントリスナーを削除します - もう必要なくなったイベントハンドラーのクリーンアップに使用します ## イベントシステム MastraVoice クラスには、リアルタイム通信のためのイベントシステムが含まれています。標準的なイベントタイプは以下の通りです。 ## 保護されたプロパティ ## テレメトリーサポート MastraVoice には、パフォーマンスの追跡とエラー監視を行う `traced` メソッドを通じて、組み込みのテレメトリーサポートが含まれています。 ## 注意事項 - MastraVoiceは抽象クラスであり、直接インスタンス化することはできません - 実装クラスは、すべての抽象メソッドに対して具体的な実装を提供する必要があります - このクラスは、さまざまな音声サービスプロバイダー間で一貫したインターフェースを提供します - 音声から音声への機能はオプションであり、プロバイダーごとに異なります - イベントシステムにより、リアルタイムのやり取りのための非同期通信が可能になります - テレメトリはすべてのメソッド呼び出しで自動的に処理されます --- title: "リファレンス: Murf Voice | Voice Providers | Mastra ドキュメント" description: "Murf voice 実装のドキュメント。テキスト読み上げ機能を提供します。" --- # Murf [JA] Source: https://mastra.ai/ja/reference/voice/murf MastraにおけるMurfの音声実装は、MurfのAI音声サービスを利用したテキスト読み上げ(TTS)機能を提供します。さまざまな言語で複数の音声に対応しています。 ## 使用例 ```typescript import { MurfVoice } from "@mastra/voice-murf"; // デフォルト設定で初期化(MURF_API_KEY 環境変数を使用) const voice = new MurfVoice(); // カスタム設定で初期化 const voice = new MurfVoice({ speechModel: { name: "GEN2", apiKey: "your-api-key", properties: { format: "MP3", rate: 1.0, pitch: 1.0, sampleRate: 48000, channelType: "STEREO", }, }, speaker: "en-US-cooper", }); // デフォルト設定でテキスト読み上げ const audioStream = await voice.speak("Hello, world!"); // カスタムプロパティでテキスト読み上げ const audioStream = await voice.speak("Hello, world!", { speaker: "en-UK-hazel", properties: { format: "WAV", rate: 1.2, style: "casual", }, }); // 利用可能なボイスを取得 const voices = await voice.getSpeakers(); ``` ## コンストラクタのパラメータ ### MurfConfig ### 音声プロパティ ", description: "カスタム発音マッピング", isOptional: true, }, { name: "encodeAsBase64", type: "boolean", description: "音声をbase64でエンコードするかどうか", isOptional: true, }, { name: "variation", type: "number", description: "ボイスのバリエーションパラメータ", isOptional: true, }, { name: "audioDuration", type: "number", description: "目標とする音声の長さ(秒)", isOptional: true, }, { name: "multiNativeLocale", type: "string", description: "多言語対応のためのロケール", isOptional: true, }, ]} /> ## メソッド ### speak() Murf の API を使用してテキストを音声に変換します。 戻り値: `Promise` ### getSpeakers() 利用可能な音声オプションの配列を返します。各ノードには以下が含まれます: ### listen() このメソッドは Murf ではサポートされておらず、エラーが発生します。Murf は音声認識機能を提供していません。 ## 重要な注意事項 1. Murf APIキーが必要です。`MURF_API_KEY` 環境変数で設定するか、コンストラクタで渡してください。 2. サービスはデフォルトでGEN2モデルバージョンを使用します。 3. 音声プロパティはコンストラクタレベルで設定でき、リクエストごとに上書き可能です。 4. サービスは、フォーマット、サンプルレート、チャンネルタイプなどのプロパティを通じて幅広い音声カスタマイズに対応しています。 5. 音声認識(Speech-to-text)機能には対応していません。 --- title: "リファレンス: OpenAI Realtime Voice | Voice Providers | Mastra ドキュメント" description: "OpenAIRealtimeVoice クラスのドキュメント。WebSocket を通じてリアルタイムのテキスト読み上げおよび音声認識機能を提供します。" --- # OpenAI Realtime Voice [JA] Source: https://mastra.ai/ja/reference/voice/openai-realtime OpenAIRealtimeVoice クラスは、OpenAI の WebSocket ベースの API を使用してリアルタイムの音声対話機能を提供します。リアルタイムの音声から音声への変換、音声活動検出、イベントベースの音声ストリーミングをサポートしています。 ## 使用例 ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import { playAudio, getMicrophoneStream } from "@mastra/node-audio"; // Initialize with default configuration using environment variables const voice = new OpenAIRealtimeVoice(); // Or initialize with specific configuration const voiceWithConfig = new OpenAIRealtimeVoice({ apiKey: "your-openai-api-key", model: "gpt-4o-mini-realtime-preview-2024-12-17", speaker: "alloy", // Default voice }); voiceWithConfig.updateSession({ turn_detection: { type: "server_vad", threshold: 0.6, silence_duration_ms: 1200, }, }); // Establish connection await voice.connect(); // Set up event listeners voice.on("speaker", ({ audio }) => { // Handle audio data (Int16Array) pcm format by default playAudio(audio); }); voice.on("writing", ({ text, role }) => { // Handle transcribed text console.log(`${role}: ${text}`); }); // Convert text to speech await voice.speak("Hello, how can I help you today?", { speaker: "echo", // Override default voice }); // Process audio input const microphoneStream = getMicrophoneStream(); await voice.send(microphoneStream); // When done, disconnect voice.connect(); ``` ## 設定 ### コンストラクタオプション ### 音声アクティビティ検出(VAD)設定 ## メソッド ### connect() OpenAI リアルタイムサービスへの接続を確立します。speak、listen、send 関数を使用する前に呼び出す必要があります。 ", description: "接続が確立されたときに解決される Promise。", }, ]} /> ### speak() 設定された音声モデルを使用して発話イベントを発行します。入力として文字列またはリーダブルストリームのいずれかを受け付けます。 戻り値: `Promise` ### listen() 音声認識のために音声入力を処理します。音声データのリーダブルストリームを受け取り、書き起こされたテキストとともに 'listening' イベントを発行します。 戻り値: `Promise` ### send() ライブマイク入力など、連続的な音声ストリーミングシナリオのために、音声データをリアルタイムで OpenAI サービスにストリーミングします。 戻り値: `Promise` ### updateConfig() 音声インスタンスのセッション設定を更新します。これにより、音声設定やターン検出、その他のパラメータを変更できます。 戻り値: `void` ### addTools() 音声インスタンスにツールセットを追加します。ツールを追加することで、モデルが会話中に追加のアクションを実行できるようになります。OpenAIRealtimeVoice が Agent に追加されている場合、Agent に設定されたツールは自動的に音声インターフェースでも利用可能になります。 戻り値: `void` ### close() OpenAI リアルタイムセッションから切断し、リソースをクリーンアップします。音声インスタンスの使用が終了したら呼び出してください。 戻り値: `void` ### getSpeakers() 利用可能な音声スピーカーのリストを返します。 戻り値: `Promise>` ### on() 音声イベントのイベントリスナーを登録します。 戻り値: `void` ### off() 以前に登録したイベントリスナーを削除します。 戻り値: `void` ## イベント OpenAIRealtimeVoiceクラスは以下のイベントを発生させます: ### OpenAI Realtimeイベント [OpenAI Realtimeユーティリティイベント](https://github.com/openai/openai-realtime-api-beta#reference-client-utility-events)も'openAIRealtime:'を接頭辞として付けることでリッスンできます: ## 利用可能な音声 以下の音声オプションが利用できます: - `alloy`: ニュートラルでバランスが取れている - `ash`: クリアで正確 - `ballad`: メロディックで滑らか - `coral`: 暖かく親しみやすい - `echo`: 共鳴して深みがある - `sage`: 落ち着いて思慮深い - `shimmer`: 明るくエネルギッシュ - `verse`: 多才で表現力豊か ## メモ - APIキーはコンストラクタオプションまたは`OPENAI_API_KEY`環境変数を通じて提供できます - OpenAI リアルタイム音声APIはリアルタイム通信にWebSocketsを使用しています - サーバーサイドの音声アクティビティ検出(VAD)は音声検出のための精度が向上します - すべての音声データはInt16Array形式で処理されます - 音声インスタンスは他のメソッドを使用する前に`connect()`で接続する必要があります - 終了時には必ず`close()`を呼び出してリソースを適切にクリーンアップしてください - メモリ管理はOpenAI リアルタイムAPIによって処理されます --- title: "リファレンス: OpenAI Voice | 音声プロバイダー | Mastra ドキュメント" description: "テキスト読み上げと音声認識機能を提供するOpenAIVoiceクラスのドキュメント。" --- # OpenAI [JA] Source: https://mastra.ai/ja/reference/voice/openai Mastraの中のOpenAIVoiceクラスは、OpenAIのモデルを使用してテキスト読み上げと音声認識の機能を提供します。 ## 使用例 ```typescript import { OpenAIVoice } from "@mastra/voice-openai"; // Initialize with default configuration using environment variables const voice = new OpenAIVoice(); // Or initialize with specific configuration const voiceWithConfig = new OpenAIVoice({ speechModel: { name: "tts-1-hd", apiKey: "your-openai-api-key", }, listeningModel: { name: "whisper-1", apiKey: "your-openai-api-key", }, speaker: "alloy", // Default voice }); // Convert text to speech const audioStream = await voice.speak("Hello, how can I help you?", { speaker: "nova", // Override default voice speed: 1.2, // Adjust speech speed }); // Convert speech to text const text = await voice.listen(audioStream, { filetype: "mp3", }); ``` ## 設定 ### コンストラクタオプション ### OpenAIConfig ## メソッド ### speak() OpenAIのテキスト読み上げモデルを使用してテキストを音声に変換します。 戻り値: `Promise` ### listen() OpenAIのWhisperモデルを使用して音声を文字起こしします。 戻り値: `Promise` ### getSpeakers() 利用可能な音声オプションの配列を返します。各ノードには以下が含まれます: ## メモ - APIキーはコンストラクタオプションまたは`OPENAI_API_KEY`環境変数を通じて提供できます - `tts-1-hd`モデルはより高品質の音声を提供しますが、処理時間が長くなる場合があります - 音声認識はmp3、wav、webmなど複数の音声フォーマットをサポートしています --- title: "リファレンス: PlayAI Voice | Voice Providers | Mastra ドキュメント" description: "PlayAI voice 実装のドキュメント。テキスト読み上げ機能を提供します。" --- # PlayAI [JA] Source: https://mastra.ai/ja/reference/voice/playai MastraにおけるPlayAIの音声実装は、PlayAIのAPIを利用してテキスト読み上げ機能を提供します。 ## 使用例 ```typescript import { PlayAIVoice } from "@mastra/voice-playai"; // デフォルト設定で初期化(PLAYAI_API_KEY 環境変数と PLAYAI_USER_ID 環境変数を使用) const voice = new PlayAIVoice(); // デフォルト設定で初期化 const voice = new PlayAIVoice({ speechModel: { name: "PlayDialog", apiKey: process.env.PLAYAI_API_KEY, userId: process.env.PLAYAI_USER_ID, }, speaker: "Angelo", // デフォルトの音声 }); // 特定の音声でテキストを音声に変換 const audioStream = await voice.speak("Hello, world!", { speaker: "s3://voice-cloning-zero-shot/b27bc13e-996f-4841-b584-4d35801aea98/original/manifest.json", // Dexter の音声 }); ``` ## コンストラクタのパラメータ ### PlayAIConfig ## メソッド ### speak() 設定された音声モデルとボイスを使用して、テキストを音声に変換します。 戻り値: `Promise`。 ### getSpeakers() 利用可能なボイスオプションの配列を返します。各ノードには以下が含まれます: ### listen() このメソッドはPlayAIではサポートされておらず、エラーが発生します。PlayAIは音声認識(音声からテキストへの変換)機能を提供していません。 ## メモ - PlayAIの認証には、APIキーとユーザーIDの両方が必要です - このサービスは「PlayDialog」と「Play3.0-mini」の2つのモデルを提供しています - 各ボイスには固有のS3マニフェストIDがあり、APIコール時に使用する必要があります --- title: "リファレンス: Sarvam Voice | Voice Providers | Mastra Docs" description: "Sarvamクラスのドキュメントで、テキストから音声への変換と音声からテキストへの変換機能を提供します。" --- # Sarvam [JA] Source: https://mastra.ai/ja/reference/voice/sarvam MastraのSarvamVoiceクラスは、Sarvam AIモデルを使用してテキスト読み上げと音声認識機能を提供します。 ## 使用例 ```typescript import { SarvamVoice } from "@mastra/voice-sarvam"; // 環境変数を使用してデフォルト設定で初期化 const voice = new SarvamVoice(); // または特定の設定で初期化 const voiceWithConfig = new SarvamVoice({ speechModel: { model: "bulbul:v1", apiKey: process.env.SARVAM_API_KEY!, language: "en-IN", properties: { pitch: 0, pace: 1.65, loudness: 1.5, speech_sample_rate: 8000, enable_preprocessing: false, eng_interpolation_wt: 123, }, }, listeningModel: { model: "saarika:v2", apiKey: process.env.SARVAM_API_KEY!, languageCode: "en-IN", filetype?: 'wav'; }, speaker: "meera", // デフォルトの声 }); // テキストを音声に変換 const audioStream = await voice.speak("こんにちは、どのようにお手伝いできますか?"); // 音声をテキストに変換 const text = await voice.listen(audioStream, { filetype: "wav", }); ``` ### Sarvam API ドキュメント - https://docs.sarvam.ai/api-reference-docs/endpoints/text-to-speech ## 設定 ### コンストラクタオプション ### SarvamVoiceConfig ### SarvamListenOptions ## メソッド ### speak() Sarvamのテキスト読み上げモデルを使用して、テキストを音声に変換します。 戻り値: `Promise` ### listen() Sarvamの音声認識モデルを使用して音声を文字起こしします。 戻り値: `Promise` ### getSpeakers() 利用可能なボイスオプションの配列を返します。 戻り値: `Promise>` ## メモ - APIキーは、コンストラクタオプションまたは`SARVAM_API_KEY`環境変数を介して提供できます - APIキーが提供されていない場合、コンストラクタはエラーをスローします - サービスは`https://api.sarvam.ai`でSarvam AI APIと通信します - オーディオはバイナリオーディオデータを含むストリームとして返されます - 音声認識はmp3およびwavオーディオフォーマットをサポートしています --- title: "リファレンス: Speechify Voice | Voice Providers | Mastra ドキュメント" description: "Speechify voice 実装のドキュメント。テキスト読み上げ機能について説明します。" --- # Speechify [JA] Source: https://mastra.ai/ja/reference/voice/speechify MastraにおけるSpeechifyの音声実装は、SpeechifyのAPIを利用してテキスト読み上げ機能を提供します。 ## 使用例 ```typescript import { SpeechifyVoice } from "@mastra/voice-speechify"; // Initialize with default configuration (uses SPEECHIFY_API_KEY environment variable) const voice = new SpeechifyVoice(); // Initialize with custom configuration const voice = new SpeechifyVoice({ speechModel: { name: "simba-english", apiKey: "your-api-key", }, speaker: "george", // Default voice }); // Convert text to speech const audioStream = await voice.speak("Hello, world!", { speaker: "henry", // Override default voice }); ``` ## コンストラクタのパラメータ ### SpeechifyConfig ## メソッド ### speak() 設定された音声モデルとボイスを使用して、テキストを音声に変換します。 戻り値: `Promise` ### getSpeakers() 利用可能なボイスオプションの配列を返します。各ノードには以下が含まれます: ### listen() このメソッドはSpeechifyではサポートされておらず、エラーが発生します。Speechifyは音声認識(音声からテキストへの変換)機能を提供していません。 ## 注意事項 - Speechifyは認証のためにAPIキーが必要です - デフォルトのモデルは「simba-english」です - 音声からテキストへの機能はサポートされていません - 追加の音声ストリームオプションは、speak()メソッドのoptionsパラメータを通じて渡すことができます --- title: "リファレンス: voice.addInstructions() | 音声プロバイダー | Mastra Docs" description: "音声プロバイダーで利用可能なaddInstructions()メソッドのドキュメント。音声モデルの動作を導くための指示を追加します。" --- # voice.addInstructions() [JA] Source: https://mastra.ai/ja/reference/voice/voice.addInstructions `addInstructions()` メソッドは、リアルタイムの対話中にモデルの動作を導くための指示をボイスプロバイダーに装備します。これは特に、会話全体でコンテキストを維持するリアルタイムボイスプロバイダーに役立ちます。 ## 使用例 ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import { Agent } from "@mastra/core/agent"; import { openai } from "@ai-sdk/openai"; // Initialize a real-time voice provider const voice = new OpenAIRealtimeVoice({ realtimeConfig: { model: "gpt-4o-mini-realtime", apiKey: process.env.OPENAI_API_KEY, }, }); // Create an agent with the voice provider const agent = new Agent({ name: "Customer Support Agent", instructions: "You are a helpful customer support agent for a software company.", model: openai("gpt-4o"), voice, }); // Add additional instructions to the voice provider voice.addInstructions(` When speaking to customers: - Always introduce yourself as the customer support agent - Speak clearly and concisely - Ask clarifying questions when needed - Summarize the conversation at the end `); // Connect to the real-time service await voice.connect(); ``` ## パラメータ
## 戻り値 このメソッドは値を返しません。 ## 注意事項 - 指示は、音声インタラクションに関連して明確、具体的、かつ適切である場合に最も効果的です - このメソッドは主に会話のコンテキストを維持するリアルタイム音声プロバイダーで使用されます - 指示をサポートしていない音声プロバイダーで呼び出された場合、警告をログに記録し、何も実行しません - このメソッドで追加された指示は、通常、関連するエージェントによって提供される指示と組み合わされます - 最良の結果を得るには、会話を開始する前(`connect()`を呼び出す前)に指示を追加してください - `addInstructions()`を複数回呼び出すと、プロバイダーの実装によって、既存の指示が置き換えられるか追加されるかが異なります --- title: "リファレンス: voice.addTools() | Voice Providers | Mastra ドキュメント" description: "voice プロバイダーで利用可能な addTools() メソッドのドキュメント。音声モデルに関数呼び出し機能を追加します。" --- # voice.addTools() [JA] Source: https://mastra.ai/ja/reference/voice/voice.addTools `addTools()` メソッドは、音声プロバイダーにツール(関数)を追加し、モデルがリアルタイムの対話中にそれらを呼び出せるようにします。これにより、音声アシスタントは情報の検索、計算の実行、外部システムとの連携などのアクションを行うことが可能になります。 ## 使用例 ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import { createTool } from "@mastra/core/tools"; import { z } from "zod"; // Define tools const weatherTool = createTool({ id: "getWeather", description: "Get the current weather for a location", inputSchema: z.object({ location: z.string().describe("The city and state, e.g. San Francisco, CA"), }), outputSchema: z.object({ message: z.string(), }), execute: async ({ context }) => { // Fetch weather data from an API const response = await fetch( `https://api.weather.com?location=${encodeURIComponent(context.location)}`, ); const data = await response.json(); return { message: `The current temperature in ${context.location} is ${data.temperature}°F with ${data.conditions}.`, }; }, }); // Initialize a real-time voice provider const voice = new OpenAIRealtimeVoice({ realtimeConfig: { model: "gpt-4o-mini-realtime", apiKey: process.env.OPENAI_API_KEY, }, }); // Add tools to the voice provider voice.addTools({ getWeather: weatherTool, }); // Connect to the real-time service await voice.connect(); ``` ## パラメーター
## 戻り値 このメソッドは値を返しません。 ## 注意 - ツールは、name、description、input schema、execute function を含む Mastra ツール形式に従う必要があります - このメソッドは、主に function calling をサポートするリアルタイム音声プロバイダーで使用されます - ツールをサポートしない音声プロバイダーで呼び出された場合、警告が記録され、何も行われません - このメソッドで追加されたツールは、通常、関連する Agent によって提供されるツールと組み合わされます - 最良の結果を得るには、会話を開始する前(`connect()` を呼び出す前)にツールを追加してください - モデルがツールを使用することを決定した場合、音声プロバイダーがツールハンドラーの呼び出しを自動的に処理します - `addTools()` を複数回呼び出すと、プロバイダーの実装によっては既存のツールが置き換えられるか、マージされる場合があります --- title: "リファレンス: voice.answer() | Voice Providers | Mastra ドキュメント" description: "リアルタイム音声プロバイダーで利用可能な answer() メソッドのドキュメント。このメソッドは音声プロバイダーに応答の生成を指示します。" --- # voice.answer() [JA] Source: https://mastra.ai/ja/reference/voice/voice.answer `answer()` メソッドは、リアルタイム音声プロバイダーでAIに応答を生成させるために使用されます。このメソッドは、ユーザー入力を受け取った後にAIに明示的に応答を促す必要がある音声対音声の会話で特に便利です。 ## 使用例 ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import { getMicrophoneStream } from "@mastra/node-audio"; import Speaker from "@mastra/node-speaker"; const speaker = new Speaker({ sampleRate: 24100, // Audio sample rate in Hz - standard for high-quality audio on MacBook Pro channels: 1, // Mono audio output (as opposed to stereo which would be 2) bitDepth: 16, // Bit depth for audio quality - CD quality standard (16-bit resolution) }); // Initialize a real-time voice provider const voice = new OpenAIRealtimeVoice({ realtimeConfig: { model: "gpt-4o", apiKey: process.env.OPENAI_API_KEY, }, speaker: "alloy", // Default voice }); // Connect to the real-time service await voice.connect(); // Register event listener for responses voice.on("speaker", (stream) => { // Handle audio response stream.pipe(speaker); }); // Send user audio input const microphoneStream = getMicrophoneStream(); await voice.send(microphoneStream); // Trigger the AI to respond await voice.answer(); ``` ## パラメーター
", description: "レスポンスのプロバイダー固有のオプション", isOptional: true, }, ]} /> ## 戻り値 レスポンスがトリガーされたときに解決される `Promise` を返します。 ## 注意事項 - このメソッドは、音声から音声への機能をサポートするリアルタイム音声プロバイダーでのみ実装されています - この機能をサポートしていない音声プロバイダーで呼び出した場合、警告が記録され、即座に解決されます - 応答音声は通常、直接返されるのではなく、'speaking' イベントを通じて出力されます - サポートしているプロバイダーでは、このメソッドを使ってAIが生成するのではなく、特定の応答を送信できます - このメソッドは、会話の流れを作るために `send()` と組み合わせてよく使われます --- title: "リファレンス: voice.close() | Voice Providers | Mastra ドキュメント" description: "voice プロバイダーで利用可能な close() メソッドのドキュメント。リアルタイム音声サービスから切断します。" --- # voice.close() [JA] Source: https://mastra.ai/ja/reference/voice/voice.close `close()` メソッドは、リアルタイム音声サービスから切断し、リソースをクリーンアップします。これは、音声セッションを正しく終了し、リソースリークを防ぐために重要です。 ## 使用例 ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import { getMicrophoneStream } from "@mastra/node-audio"; // Initialize a real-time voice provider const voice = new OpenAIRealtimeVoice({ realtimeConfig: { model: "gpt-4o-mini-realtime", apiKey: process.env.OPENAI_API_KEY, }, }); // Connect to the real-time service await voice.connect(); // Start a conversation voice.speak("Hello, I'm your AI assistant!"); // Stream audio from a microphone const microphoneStream = getMicrophoneStream(); voice.send(microphoneStream); // When the conversation is complete setTimeout(() => { // Close the connection and clean up resources voice.close(); console.log("Voice session ended"); }, 60000); // End after 1 minute ``` ## パラメーター このメソッドはパラメーターを受け取りません。 ## 戻り値 このメソッドは値を返しません。 ## 注意事項 - リアルタイム音声セッションが終了したら、必ず `close()` を呼び出してリソースを解放してください - `close()` を呼び出した後、新しいセッションを開始したい場合は再度 `connect()` を呼び出す必要があります - このメソッドは、主に持続的な接続を維持するリアルタイム音声プロバイダーと一緒に使用されます - リアルタイム接続をサポートしていない音声プロバイダーで呼び出した場合、警告が記録され、何も行われません - 接続を閉じ忘れると、リソースリークや音声サービスプロバイダーでの課金問題につながる可能性があります --- title: "リファレンス: voice.connect() | 音声プロバイダー | Mastra Docs" description: "リアルタイム音声プロバイダーで利用可能なconnect()メソッドのドキュメント。音声対音声通信の接続を確立します。" --- # voice.connect() [JA] Source: https://mastra.ai/ja/reference/voice/voice.connect `connect()` メソッドは、リアルタイムの音声対音声通信のためのWebSocketまたはWebRTC接続を確立します。このメソッドは、`send()`や`answer()`などの他のリアルタイム機能を使用する前に呼び出す必要があります。 ## 使用例 ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import Speaker from "@mastra/node-speaker"; const speaker = new Speaker({ sampleRate: 24100, // Audio sample rate in Hz - standard for high-quality audio on MacBook Pro channels: 1, // Mono audio output (as opposed to stereo which would be 2) bitDepth: 16, // Bit depth for audio quality - CD quality standard (16-bit resolution) }); // Initialize a real-time voice provider const voice = new OpenAIRealtimeVoice({ realtimeConfig: { model: "gpt-4o-mini-realtime", apiKey: process.env.OPENAI_API_KEY, options: { sessionConfig: { turn_detection: { type: "server_vad", threshold: 0.6, silence_duration_ms: 1200, }, }, }, }, speaker: "alloy", // Default voice }); // Connect to the real-time service await voice.connect(); // Now you can use real-time features voice.on("speaker", (stream) => { stream.pipe(speaker); }); // With connection options await voice.connect({ timeout: 10000, // 10 seconds timeout reconnect: true, }); ``` ## パラメータ ", description: "プロバイダー固有の接続オプション", isOptional: true, }, ]} /> ## 戻り値 接続が正常に確立されると解決する`Promise`を返します。 ## プロバイダー固有のオプション 各リアルタイム音声プロバイダーは、`connect()`メソッドに対して異なるオプションをサポートしている場合があります: ### OpenAI リアルタイム ## CompositeVoiceでの使用 `CompositeVoice`を使用する場合、`connect()`メソッドは設定されたリアルタイムプロバイダーに委譲されます: ```typescript import { CompositeVoice } from "@mastra/core/voice"; import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; const realtimeVoice = new OpenAIRealtimeVoice(); const voice = new CompositeVoice({ realtimeProvider: realtimeVoice, }); // これはOpenAIRealtimeVoiceプロバイダーを使用します await voice.connect(); ``` ## 注意事項 - このメソッドは、音声対音声機能をサポートするリアルタイム音声プロバイダーでのみ実装されています - この機能をサポートしていない音声プロバイダーで呼び出された場合、警告をログに記録して即座に解決します - `send()` や `answer()` などの他のリアルタイムメソッドを使用する前に、接続を確立する必要があります - 音声インスタンスの使用が終わったら、リソースを適切にクリーンアップするために `close()` を呼び出してください - 一部のプロバイダーは、その実装によって、接続が失われた場合に自動的に再接続することがあります - 接続エラーは通常、キャッチして処理すべき例外としてスローされます ## 関連メソッド - [voice.send()](./voice.send) - 音声データを音声プロバイダーに送信します - [voice.answer()](./voice.answer) - 音声プロバイダーに応答を促します - [voice.close()](./voice.close) - リアルタイムサービスから切断します - [voice.on()](./voice.on) - 音声イベントのイベントリスナーを登録します --- title: "リファレンス:音声イベント | 音声プロバイダー | Mastra ドキュメント" description: "音声プロバイダーから発信されるイベントのドキュメント、特にリアルタイム音声インタラクションに関するもの。" --- # 音声イベント [JA] Source: https://mastra.ai/ja/reference/voice/voice.events 音声プロバイダーはリアルタイムの音声インタラクション中に様々なイベントを発生させます。これらのイベントは[voice.on()](./voice.on)メソッドを使用してリッスンすることができ、インタラクティブな音声アプリケーションを構築する上で特に重要です。 ## 共通イベント これらのイベントは、リアルタイム音声プロバイダー間で一般的に実装されています: ## 注意事項 - すべてのイベントがすべての音声プロバイダーでサポートされているわけではありません - ペイロード構造はプロバイダーによって異なる場合があります - リアルタイムではないプロバイダーの場合、これらのイベントの多くは発生しません - イベントは会話の状態に応答するインタラクティブなUIを構築するのに役立ちます - イベントリスナーが不要になった場合は、[voice.off()](./voice.off)メソッドを使用して削除することを検討してください --- title: "リファレンス: voice.getSpeakers() | 音声プロバイダー | Mastra ドキュメント" description: "音声プロバイダーで利用可能なgetSpeakers()メソッドのドキュメント。利用可能な音声オプションを取得します。" --- import { Tabs } from "nextra/components"; # voice.getSpeakers() [JA] Source: https://mastra.ai/ja/reference/voice/voice.getSpeakers `getSpeakers()` メソッドは、音声プロバイダーから利用可能な音声オプション(スピーカー)のリストを取得します。これにより、アプリケーションはユーザーに音声の選択肢を提示したり、異なるコンテキストに最も適した音声をプログラムで選択したりすることができます。 ## 使用例 ```typescript import { OpenAIVoice } from "@mastra/voice-openai"; import { ElevenLabsVoice } from "@mastra/voice-elevenlabs"; // Initialize voice providers const openaiVoice = new OpenAIVoice(); const elevenLabsVoice = new ElevenLabsVoice({ apiKey: process.env.ELEVENLABS_API_KEY, }); // Get available speakers from OpenAI const openaiSpeakers = await openaiVoice.getSpeakers(); console.log("OpenAI voices:", openaiSpeakers); // Example output: [{ voiceId: "alloy" }, { voiceId: "echo" }, { voiceId: "fable" }, ...] // Get available speakers from ElevenLabs const elevenLabsSpeakers = await elevenLabsVoice.getSpeakers(); console.log("ElevenLabs voices:", elevenLabsSpeakers); // Example output: [{ voiceId: "21m00Tcm4TlvDq8ikWAM", name: "Rachel" }, ...] // Use a specific voice for speech const text = "Hello, this is a test of different voices."; await openaiVoice.speak(text, { speaker: openaiSpeakers[2].voiceId }); await elevenLabsVoice.speak(text, { speaker: elevenLabsSpeakers[0].voiceId }); ``` ## パラメータ このメソッドはパラメータを受け付けません。 ## 戻り値 >", type: "Promise", description: "音声オプションの配列を解決するプロミスで、各オプションには少なくともvoiceIdプロパティが含まれ、プロバイダー固有のメタデータが追加される場合があります。", }, ]} /> ## プロバイダー固有のメタデータ 異なる音声プロバイダーは、それぞれの音声に対して異なるメタデータを返します: {/* LLM CONTEXT: This Tabs component shows the different metadata structures returned by various voice providers' getSpeakers() method. Each tab displays the specific properties and data types returned by that voice provider when listing available speakers/voices. The tabs help users understand what information is available for each provider and how to access voice-specific metadata. Each tab includes property tables showing voiceId and provider-specific metadata like name, language, gender, accent, etc. The providers include OpenAI, OpenAI Realtime, Deepgram, ElevenLabs, Google, Murf, PlayAI, Sarvam, Speechify, and Azure. */} ## 注意事項 - 利用可能な音声は、プロバイダーによって大きく異なります - 一部のプロバイダーでは、音声の完全なリストを取得するために認証が必要な場合があります - プロバイダーがこのメソッドをサポートしていない場合、デフォルトの実装では空の配列が返されます - パフォーマンス上の理由から、リストを頻繁に表示する必要がある場合は結果をキャッシュすることを検討してください - `voiceId`プロパティはすべてのプロバイダーで確実に存在しますが、追加のメタデータは異なります --- title: "リファレンス: voice.listen() | 音声プロバイダー | Mastra ドキュメント" description: "すべてのMastra音声プロバイダーで利用可能な、音声をテキストに変換するlisten()メソッドのドキュメント。" --- # voice.listen() [JA] Source: https://mastra.ai/ja/reference/voice/voice.listen `listen()` メソッドは、すべてのMastra音声プロバイダーで利用可能な、音声をテキストに変換するコア機能です。音声ストリームを入力として受け取り、文字起こしされたテキストを返します。 ## 使用例 ```typescript import { OpenAIVoice } from "@mastra/voice-openai"; import { getMicrophoneStream } from "@mastra/node-audio"; import { createReadStream } from "fs"; import path from "path"; // Initialize a voice provider const voice = new OpenAIVoice({ listeningModel: { name: "whisper-1", apiKey: process.env.OPENAI_API_KEY, }, }); // Basic usage with a file stream const audioFilePath = path.join(process.cwd(), "audio.mp3"); const audioStream = createReadStream(audioFilePath); const transcript = await voice.listen(audioStream, { filetype: "mp3", }); console.log("Transcribed text:", transcript); // Using a microphone stream const microphoneStream = getMicrophoneStream(); // Assume this function gets audio input const transcription = await voice.listen(microphoneStream); // With provider-specific options const transcriptWithOptions = await voice.listen(audioStream, { language: "en", prompt: "This is a conversation about artificial intelligence.", }); ``` ## パラメータ ## 戻り値 以下のいずれかを返します: - `Promise`: 文字起こしされたテキストを解決するプロミス - `Promise`: 文字起こしされたテキストのストリームを解決するプロミス(ストリーミング文字起こし用) - `Promise`: テキストを直接返す代わりに「writing」イベントを発行するリアルタイムプロバイダー用 ## プロバイダー固有のオプション 各音声プロバイダーは、それぞれの実装に特有の追加オプションをサポートしている場合があります。以下にいくつかの例を示します: ### OpenAI ### Google ### Deepgram ## リアルタイム音声プロバイダー `OpenAIRealtimeVoice`のようなリアルタイム音声プロバイダーを使用する場合、`listen()`メソッドは異なる動作をします: - 文字起こしされたテキストを返す代わりに、文字起こしされたテキストを含む「writing」イベントを発行します - 文字起こしを受け取るためにイベントリスナーを登録する必要があります ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import { getMicrophoneStream } from "@mastra/node-audio"; const voice = new OpenAIRealtimeVoice(); await voice.connect(); // Register event listener for transcription voice.on("writing", ({ text, role }) => { console.log(`${role}: ${text}`); }); // This will emit 'writing' events instead of returning text const microphoneStream = getMicrophoneStream(); await voice.listen(microphoneStream); ``` ## CompositeVoiceでの使用 `CompositeVoice`を使用する場合、`listen()`メソッドは設定されたリスニングプロバイダーに処理を委譲します: ```typescript import { CompositeVoice } from "@mastra/core/voice"; import { OpenAIVoice } from "@mastra/voice-openai"; import { PlayAIVoice } from "@mastra/voice-playai"; const voice = new CompositeVoice({ listenProvider: new OpenAIVoice(), speakProvider: new PlayAIVoice(), }); // これはOpenAIVoiceプロバイダーを使用します const transcript = await voice.listen(audioStream); ``` ## 注意事項 - すべての音声プロバイダーが音声認識機能をサポートしているわけではありません(例:PlayAI、Speechify) - `listen()`の動作はプロバイダーによって若干異なる場合がありますが、すべての実装は同じ基本的なインターフェースに従っています - リアルタイム音声プロバイダーを使用する場合、このメソッドは直接テキストを返さず、代わりに「writing」イベントを発生させることがあります - サポートされる音声フォーマットはプロバイダーによって異なります。一般的なフォーマットにはMP3、WAV、M4Aなどがあります - 一部のプロバイダーは、テキストが文字起こしされるとすぐに返される、ストリーミング文字起こしをサポートしています - 最高のパフォーマンスを得るには、使用が終わったら音声ストリームを閉じるか終了することを検討してください ## 関連メソッド - [voice.speak()](./voice.speak) - テキストを音声に変換 - [voice.send()](./voice.send) - 音声データをリアルタイムで音声プロバイダーに送信 - [voice.on()](./voice.on) - 音声イベントのイベントリスナーを登録 --- title: "リファレンス: voice.off() | 音声プロバイダー | Mastra ドキュメント" description: "音声プロバイダーで利用可能なoff()メソッドのドキュメント。音声イベントのイベントリスナーを削除します。" --- # voice.off() [JA] Source: https://mastra.ai/ja/reference/voice/voice.off `off()` メソッドは、以前に `on()` メソッドで登録されたイベントリスナーを削除します。これは、リアルタイム音声機能を持つ長時間実行アプリケーションでリソースをクリーンアップし、メモリリークを防ぐのに特に役立ちます。 ## 使用例 ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import chalk from "chalk"; // Initialize a real-time voice provider const voice = new OpenAIRealtimeVoice({ realtimeConfig: { model: "gpt-4o-mini-realtime", apiKey: process.env.OPENAI_API_KEY, }, }); // Connect to the real-time service await voice.connect(); // Define the callback function const writingCallback = ({ text, role }) => { if (role === "user") { process.stdout.write(chalk.green(text)); } else { process.stdout.write(chalk.blue(text)); } }; // Register event listener voice.on("writing", writingCallback); // Later, when you want to remove the listener voice.off("writing", writingCallback); ``` ## パラメータ
## 戻り値 このメソッドは値を返しません。 ## メモ - `off()`に渡されるコールバックは、`on()`に渡されたのと同じ関数参照でなければなりません - コールバックが見つからない場合、このメソッドは何も効果を持ちません - このメソッドは主に、イベントベースの通信をサポートするリアルタイム音声プロバイダーで使用されます - イベントをサポートしていない音声プロバイダーで呼び出された場合、警告をログに記録し、何も行いません - イベントリスナーを削除することは、長時間実行されるアプリケーションでのメモリリークを防ぐために重要です --- title: "リファレンス: voice.on() | 音声プロバイダー | Mastra ドキュメント" description: "音声プロバイダーで利用可能なon()メソッドのドキュメント。音声イベントのイベントリスナーを登録します。" --- # voice.on() [JA] Source: https://mastra.ai/ja/reference/voice/voice.on `on()` メソッドは、さまざまな音声イベントのイベントリスナーを登録します。これは特にリアルタイム音声プロバイダーにとって重要であり、イベントは文字起こしされたテキスト、音声応答、その他の状態変更を伝えるために使用されます。 ## 使用例 ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import Speaker from "@mastra/node-speaker"; import chalk from "chalk"; // Initialize a real-time voice provider const voice = new OpenAIRealtimeVoice({ realtimeConfig: { model: "gpt-4o-mini-realtime", apiKey: process.env.OPENAI_API_KEY, }, }); // Connect to the real-time service await voice.connect(); // Register event listener for transcribed text voice.on("writing", (event) => { if (event.role === "user") { process.stdout.write(chalk.green(event.text)); } else { process.stdout.write(chalk.blue(event.text)); } }); // Listen for audio data and play it const speaker = new Speaker({ sampleRate: 24100, channels: 1, bitDepth: 16, }); voice.on("speaker", (stream) => { stream.pipe(speaker); }); // Register event listener for errors voice.on("error", ({ message, code, details }) => { console.error(`Error ${code}: ${message}`, details); }); ``` ## パラメータ
## 戻り値 このメソッドは値を返しません。 ## イベント イベントとそのペイロード構造の包括的なリストについては、[Voice Events](./voice.events)のドキュメントを参照してください。 一般的なイベントには以下が含まれます: - `speaking`: 音声データが利用可能になったときに発行されます - `speaker`: 音声出力にパイプできるストリームとともに発行されます - `writing`: テキストが文字起こしまたは生成されたときに発行されます - `error`: エラーが発生したときに発行されます - `tool-call-start`: ツールが実行される直前に発行されます - `tool-call-result`: ツールの実行が完了したときに発行されます 異なる音声プロバイダーは、異なるイベントセットと様々なペイロード構造をサポートしている場合があります。 ## CompositeVoiceでの使用 `CompositeVoice`を使用する場合、`on()`メソッドは設定されたリアルタイムプロバイダーに委譲されます: ```typescript import { CompositeVoice } from "@mastra/core/voice"; import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import Speaker from "@mastra/node-speaker"; const speaker = new Speaker({ sampleRate: 24100, // オーディオサンプルレート(Hz)- MacBook Proの高品質オーディオの標準 channels: 1, // モノラルオーディオ出力(ステレオの場合は2) bitDepth: 16, // オーディオ品質のビット深度 - CD品質標準(16ビット解像度) }); const realtimeVoice = new OpenAIRealtimeVoice(); const voice = new CompositeVoice({ realtimeProvider: realtimeVoice, }); // リアルタイムサービスに接続 await voice.connect(); // これはOpenAIRealtimeVoiceプロバイダーにイベントリスナーを登録します voice.on("speaker", (stream) => { stream.pipe(speaker); }); ``` ## メモ - このメソッドは主にイベントベースの通信をサポートするリアルタイム音声プロバイダーで使用されます - イベントをサポートしていない音声プロバイダーで呼び出された場合、警告をログに記録し何も実行しません - イベントリスナーは、イベントを発生させる可能性のあるメソッドを呼び出す前に登録する必要があります - イベントリスナーを削除するには、同じイベント名とコールバック関数を指定して[voice.off()](./voice.off)メソッドを使用します - 同じイベントに対して複数のリスナーを登録できます - コールバック関数はイベントタイプによって異なるデータを受け取ります([Voice Events](./voice.events)を参照) - パフォーマンスを最適化するために、不要になったイベントリスナーは削除することを検討してください --- title: "リファレンス: voice.send() | 音声プロバイダー | Mastra ドキュメント" description: "リアルタイム音声プロバイダーで利用可能なsend()メソッドのドキュメント。連続処理のための音声データをストリーミングします。" --- # voice.send() [JA] Source: https://mastra.ai/ja/reference/voice/voice.send `send()` メソッドは、音声データをリアルタイムで音声プロバイダーにストリーミングし、継続的な処理を行います。このメソッドは、リアルタイムの音声対音声会話に不可欠であり、マイク入力を直接AIサービスに送信することができます。 ## 使用例 ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import Speaker from "@mastra/node-speaker"; import { getMicrophoneStream } from "@mastra/node-audio"; const speaker = new Speaker({ sampleRate: 24100, // オーディオのサンプルレート(Hz)- MacBook Proの高品質オーディオの標準 channels: 1, // モノラルオーディオ出力(ステレオの場合は2) bitDepth: 16, // オーディオ品質のビット深度 - CD品質の標準(16ビット解像度) }); // リアルタイム音声プロバイダーを初期化 const voice = new OpenAIRealtimeVoice({ realtimeConfig: { model: "gpt-4o-mini-realtime", apiKey: process.env.OPENAI_API_KEY, }, }); // リアルタイムサービスに接続 await voice.connect(); // レスポンスのイベントリスナーを設定 voice.on("writing", ({ text, role }) => { console.log(`${role}: ${text}`); }); voice.on("speaker", (stream) => { stream.pipe(speaker); }); // マイクストリームを取得(実装は環境によって異なります) const microphoneStream = getMicrophoneStream(); // 音声データを音声プロバイダーに送信 await voice.send(microphoneStream); // Int16Arrayとして音声データを送信することもできます const audioBuffer = getAudioBuffer(); // これはInt16Arrayを返すと仮定 await voice.send(audioBuffer); ``` ## パラメータ
## 戻り値 音声データが音声プロバイダーによって受け入れられたときに解決する`Promise`を返します。 ## 注意事項 - このメソッドは音声対音声機能をサポートするリアルタイム音声プロバイダーでのみ実装されています - この機能をサポートしていない音声プロバイダーで呼び出された場合、警告をログに記録して即座に解決します - WebSocket接続を確立するために、`send()`を使用する前に`connect()`を呼び出す必要があります - 音声フォーマットの要件は、特定の音声プロバイダーによって異なります - 継続的な会話では、通常ユーザーの音声を送信するために`send()`を呼び出し、その後AIの応答をトリガーするために`answer()`を呼び出します - プロバイダーは通常、音声を処理する際に文字起こしされたテキストを含む「writing」イベントを発行します - AIが応答すると、プロバイダーは音声応答を含む「speaking」イベントを発行します --- title: "リファレンス: voice.speak() | 音声プロバイダー | Mastra ドキュメント" description: "すべてのMastra音声プロバイダーで利用可能なspeak()メソッドのドキュメント。テキストを音声に変換します。" --- # voice.speak() [JA] Source: https://mastra.ai/ja/reference/voice/voice.speak `speak()` メソッドは、すべてのMastra音声プロバイダーで利用可能な中核機能で、テキストを音声に変換します。テキスト入力を受け取り、再生または保存できるオーディオストリームを返します。 ## 使用例 ```typescript import { OpenAIVoice } from "@mastra/voice-openai"; // Initialize a voice provider const voice = new OpenAIVoice({ speaker: "alloy", // Default voice }); // Basic usage with default settings const audioStream = await voice.speak("Hello, world!"); // Using a different voice for this specific request const audioStreamWithDifferentVoice = await voice.speak("Hello again!", { speaker: "nova", }); // Using provider-specific options const audioStreamWithOptions = await voice.speak("Hello with options!", { speaker: "echo", speed: 1.2, // OpenAI-specific option }); // Using a text stream as input import { Readable } from "stream"; const textStream = Readable.from(["Hello", " from", " a", " stream!"]); const audioStreamFromTextStream = await voice.speak(textStream); ``` ## パラメータ ## 戻り値 `Promise` を返します。内容は以下の通りです: - `NodeJS.ReadableStream`: 再生または保存が可能な音声データのストリーム - `void`: 音声を直接返すのではなく、イベントを通じてリアルタイムで音声を出力するプロバイダーを使用する場合 ## プロバイダー固有のオプション 各音声プロバイダーは、それぞれの実装に特有の追加オプションをサポートしている場合があります。以下にいくつかの例を示します。 ### OpenAI ### ElevenLabs ### Google ### Murf ## リアルタイム音声プロバイダー `OpenAIRealtimeVoice`のようなリアルタイム音声プロバイダーを使用する場合、`speak()`メソッドは異なる動作をします: - オーディオストリームを返す代わりに、オーディオデータを含む「speaking」イベントを発行します - オーディオチャンクを受信するためにイベントリスナーを登録する必要があります ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; import Speaker from "@mastra/node-speaker"; const speaker = new Speaker({ sampleRate: 24100, // オーディオサンプルレート(Hz)- MacBook Proの高品質オーディオの標準 channels: 1, // モノラルオーディオ出力(ステレオの場合は2) bitDepth: 16, // オーディオ品質のビット深度 - CD品質標準(16ビット解像度) }); const voice = new OpenAIRealtimeVoice(); await voice.connect(); // オーディオチャンク用のイベントリスナーを登録 voice.on("speaker", (stream) => { // オーディオチャンクを処理(例:再生または保存) stream.pipe(speaker); }); // これはストリームを返す代わりに「speaking」イベントを発行します await voice.speak("Hello, this is realtime speech!"); ``` ## CompositeVoiceでの使用 `CompositeVoice`を使用する場合、`speak()`メソッドは設定された音声提供プロバイダーに処理を委任します: ```typescript import { CompositeVoice } from "@mastra/core/voice"; import { OpenAIVoice } from "@mastra/voice-openai"; import { PlayAIVoice } from "@mastra/voice-playai"; const voice = new CompositeVoice({ speakProvider: new PlayAIVoice(), listenProvider: new OpenAIVoice(), }); // これはPlayAIVoiceプロバイダーを使用します const audioStream = await voice.speak("Hello, world!"); ``` ## 注意事項 - `speak()` の動作はプロバイダーによって若干異なる場合がありますが、すべての実装は同じ基本インターフェースに従います。 - リアルタイム音声プロバイダーを使用する場合、このメソッドは音声ストリームを直接返さず、代わりに「speaking」イベントを発行することがあります。 - 入力としてテキストストリームが提供された場合、プロバイダーは通常それを文字列に変換してから処理します。 - 返されるストリームの音声フォーマットはプロバイダーによって異なります。一般的なフォーマットには MP3、WAV、OGG などがあります。 - 最良のパフォーマンスのために、使用後は音声ストリームを閉じるか終了することを検討してください。 --- title: "リファレンス: voice.updateConfig() | Voice Providers | Mastra Docs" description: "voiceプロバイダーで利用可能なupdateConfig()メソッドのドキュメント。実行時にvoiceプロバイダーの設定を更新します。" --- # voice.updateConfig() [JA] Source: https://mastra.ai/ja/reference/voice/voice.updateConfig `updateConfig()` メソッドは、実行時にボイスプロバイダーの設定を更新することができます。これは、ボイス設定やAPIキー、その他のプロバイダー固有のオプションを新しいインスタンスを作成せずに変更したい場合に便利です。 ## 使用例 ```typescript import { OpenAIRealtimeVoice } from "@mastra/voice-openai-realtime"; // Initialize a real-time voice provider const voice = new OpenAIRealtimeVoice({ realtimeConfig: { model: "gpt-4o-mini-realtime", apiKey: process.env.OPENAI_API_KEY, }, speaker: "alloy", }); // Connect to the real-time service await voice.connect(); // Later, update the configuration voice.updateConfig({ voice: "nova", // Change the default voice turn_detection: { type: "server_vad", threshold: 0.5, silence_duration_ms: 1000, }, }); // The next speak() call will use the new configuration await voice.speak("Hello with my new voice!"); ``` ## パラメーター
", description: "更新する設定オプション。具体的なプロパティは、音声プロバイダーによって異なります。", isOptional: false, }, ]} /> ## 戻り値 このメソッドは値を返しません。 ## 設定オプション 各音声プロバイダーは異なる設定オプションをサポートしています。 ### OpenAI リアルタイム
## 注意事項 - デフォルトの実装では、プロバイダーがこのメソッドをサポートしていない場合に警告が記録されます - 設定の更新は通常、進行中の操作ではなく、以降の操作に適用されます - コンストラクタで設定できるすべてのプロパティが、実行時に更新できるわけではありません - 具体的な動作は、voiceプロバイダーの実装によって異なります - リアルタイムのvoiceプロバイダーの場合、一部の設定変更にはサービスへの再接続が必要な場合があります --- title: "リファレンス: .after() | ワークフローの構築 | Mastra ドキュメント" description: ワークフロー内で分岐や統合パスを可能にする `after()` メソッドのドキュメント。 --- # .after() [JA] Source: https://mastra.ai/ja/reference/workflows/after `.after()` メソッドは、ワークフローステップ間の明示的な依存関係を定義し、ワークフロー実行におけるパスの分岐と結合を可能にします。 ## 使用方法 ### 基本的な分岐 ```typescript workflow .step(stepA) .then(stepB) .after(stepA) // stepAが完了した後に新しい分岐を作成 .step(stepC); ``` ### 複数の分岐のマージ ```typescript workflow .step(stepA) .then(stepB) .step(stepC) .then(stepD) .after([stepB, stepD]) // 複数のステップに依存するステップを作成 .step(stepE); ``` ## パラメータ ## 戻り値 ## 例 ### 単一の依存関係 ```typescript workflow .step(fetchData) .then(processData) .after(fetchData) // fetchDataの後に分岐 .step(logData); ``` ### 複数の依存関係(ブランチの統合) ```typescript workflow .step(fetchUserData) .then(validateUserData) .step(fetchProductData) .then(validateProductData) .after([validateUserData, validateProductData]) // 両方の検証が完了するのを待つ .step(processOrder); ``` ## 関連 - [分岐パスの例](../../examples/workflows/branching-paths.mdx) - [ワークフロークラスリファレンス](./workflow.mdx) - [ステップリファレンス](./step-class.mdx) - [制御フローガイド](../../docs/workflows/control-flow.mdx) --- title: ".afterEvent() メソッド | Mastra ドキュメント" description: "Mastraワークフローにおいて、イベントベースの中断ポイントを作成するafterEventメソッドのリファレンス。" --- # afterEvent() [JA] Source: https://mastra.ai/ja/reference/workflows/afterEvent `afterEvent()` メソッドは、ワークフロー内で特定のイベントが発生するまで実行を一時停止し、その後に処理を続行するサスペンションポイントを作成します。 ## 構文 ```typescript workflow.afterEvent(eventName: string): Workflow ``` ## パラメータ | パラメータ | 型 | 説明 | | ---------- | ------ | ---------------------------------------------------------------------------------------------------- | | eventName | string | 待機するイベントの名前。ワークフローの`events`設定で定義されているイベントと一致する必要があります。 | ## 戻り値 メソッドチェーン用のワークフローインスタンスを返します。 ## 説明 `afterEvent()`メソッドは、特定の名前付きイベントを待機するワークフローに自動的な一時停止ポイントを作成するために使用されます。これは基本的に、ワークフローが一時停止して外部イベントの発生を待つべき地点を宣言的に定義する方法です。 `afterEvent()`を呼び出すと、Mastraは以下のことを行います: 1. ID `__eventName_event`を持つ特別なステップを作成します 2. このステップは自動的にワークフローの実行を一時停止します 3. ワークフローは`resumeWithEvent()`を介して指定されたイベントがトリガーされるまで一時停止状態を維持します 4. イベントが発生すると、実行は`afterEvent()`呼び出しに続くステップから継続します このメソッドはMastraのイベント駆動型ワークフロー機能の一部であり、手動で一時停止ロジックを実装することなく、外部システムやユーザーインタラクションと連携するワークフローを作成することができます。 ## 使用上の注意 - `afterEvent()`で指定されたイベントは、ワークフローの`events`設定でスキーマと共に定義されている必要があります - 作成される特殊なステップには予測可能なID形式があります:`__eventName_event`(例:`__approvalReceived_event`) - `afterEvent()`の後に続くステップは、`context.inputData.resumedEvent`を通じてイベントデータにアクセスできます - イベントデータは、`resumeWithEvent()`が呼び出されたときに、そのイベントに定義されたスキーマに対して検証されます ## 例 ### 基本的な使い方 ```typescript // Define workflow with events const workflow = new Workflow({ name: "approval-workflow", events: { approval: { schema: z.object({ approved: z.boolean(), approverName: z.string(), }), }, }, }); // Build workflow with event suspension point workflow .step(submitRequest) .afterEvent("approval") // Workflow suspends here .step(processApproval) // This step runs after the event occurs .commit(); ``` ## 関連 - [イベント駆動型ワークフロー](./events.mdx) - [resumeWithEvent()](./resumeWithEvent.mdx) - [一時停止と再開](../../docs/workflows/suspend-and-resume.mdx) - [ワークフロークラス](./workflow.mdx) --- title: "リファレンス: Workflow.branch() | ワークフローの構築 | Mastra ドキュメント" description: ワークフロー内で条件分岐を作成する `.branch()` メソッドのドキュメント。 --- # Workflow.branch() [JA] Source: https://mastra.ai/ja/reference/workflows/branch `.branch()` メソッドは、ワークフローの各ステップ間で条件分岐を作成し、前のステップの結果に基づいて異なるパスを選択できるようにします。 ## 使い方 ```typescript workflow.branch([ [async ({ context }) => true, stepOne], [async ({ context }) => false, stepTwo], ]); ``` ## パラメーター boolean, Step]", description: "各タプルが条件関数と、その条件が真の場合に実行されるステップを含む配列です。", isOptional: false, }, ]} /> ## 戻り値 ## 関連 - [条件分岐](../../docs/workflows/flow-control.mdx#conditional-branching) - [条件分岐の例](../../examples/workflows/conditional-branching.mdx) --- title: "リファレンス: Workflow.commit() | ワークフローの構築 | Mastra ドキュメント" description: ワークフローを確定し、最終結果を返す `.commit()` メソッドのドキュメント。 --- # Workflow.commit() [JA] Source: https://mastra.ai/ja/reference/workflows/commit `.commit()` メソッドはワークフローを確定し、最終結果を返します。 ## 使用方法 ```typescript workflow.then(stepOne).commit(); ``` ## 戻り値 ## 関連項目 - [制御フロー](../../docs/workflows/control-flow.mdx) --- title: "リファレンス: Workflow.createRun() | ワークフローの構築 | Mastra ドキュメント" description: ワークフロー内の `.createRun()` メソッドのドキュメント。新しいワークフロー実行インスタンスを作成します。 --- # Workflow.createRun() [JA] Source: https://mastra.ai/ja/reference/workflows/create-run `.createRun()` メソッドは新しいワークフロー実行インスタンスを作成し、特定の入力データでワークフローを実行できるようにします。 ## 使用方法 ```typescript const myWorkflow = createWorkflow({ id: "my-workflow", inputSchema: z.object({ startValue: z.string(), }), outputSchema: z.object({ result: z.string(), }), steps: [step1, step2, step3], // Declare steps used in this workflow }) .then(step1) .then(step2) .then(step3) .commit(); const mastra = new Mastra({ workflows: { myWorkflow, }, }); const run = mastra.getWorkflow("myWorkflow").createRun(); ``` ## パラメーター ## 戻り値 ## 関連 - [ワークフローの実行](../../docs/workflows/overview.mdx#running-workflows) --- title: "リファレンス: Workflow.createRun() | ワークフローの実行 | Mastra Docs" description: "ワークフローの `.createRun()` メソッドのドキュメント。新しいワークフロー実行インスタンスを初期化します。" --- # Workflow.createRun() [JA] Source: https://mastra.ai/ja/reference/workflows/createRun `.createRun()`メソッドは、新しいワークフローの実行インスタンスを初期化します。追跡のための一意の実行IDを生成し、呼び出されるとワークフローの実行を開始するスタート関数を返します。 `.createRun()`を`.execute()`の代わりに使用する理由の1つは、追跡、ログ記録、または`.watch()`を介したサブスクライブのための一意の実行IDを取得することです。 ## 使用方法 ```typescript const { runId, start, watch } = workflow.createRun(); const result = await start(); ``` ## 戻り値 Promise", description: "呼び出されるとワークフローの実行を開始する関数", }, { name: "watch", type: "(callback: (record: WorkflowResult) => void) => () => void", description: "ワークフロー実行の各遷移時に呼び出されるコールバック関数を受け取る関数", }, { name: "resume", type: "({stepId: string, context: Record}) => Promise", description: "指定されたステップIDとコンテキストからワークフロー実行を再開する関数", }, { name: "resumeWithEvent", type: "(eventName: string, data: any) => Promise", description: "指定されたイベント名とデータからワークフロー実行を再開する関数", }, ]} /> ## エラー処理 start関数は、ワークフローの設定が無効な場合、バリデーションエラーをスローする可能性があります: ```typescript try { const { runId, start, watch, resume, resumeWithEvent } = workflow.createRun(); await start({ triggerData: data }); } catch (error) { if (error instanceof ValidationError) { // バリデーションエラーを処理する console.log(error.type); // 'circular_dependency' | 'no_terminal_path' | 'unreachable_step' console.log(error.details); } } ``` ## 関連 - [Workflow クラスリファレンス](./workflow.mdx) - [Step クラスリファレンス](./step-class.mdx) - 完全な使用方法については[ワークフローの作成](../../../examples/workflows/creating-a-workflow.mdx)の例を参照してください ``` ``` --- title: "リファレンス: Workflow.dountil() | ワークフローの構築 | Mastra ドキュメント" description: ワークフロー内の `.dountil()` メソッドのドキュメント。条件が満たされるまでステップを実行するループを作成します。 --- # Workflow.dountil() [JA] Source: https://mastra.ai/ja/reference/workflows/dountil `.dountil()` メソッドは、条件が満たされるまでステップを繰り返し実行するループを作成します。 ## 使い方 ```typescript workflow.dountil(stepOne, async ({ inputData }) => true); ``` ## パラメーター Promise", description: "ループを継続するかどうかを示すブール値を返す関数", isOptional: false, }, ]} /> ## 戻り値 ## 関連 - [ループ](../../docs/workflows/control-flow.mdx#loops) - [ループの例](../../examples/workflows/control-flow.mdx) --- title: "リファレンス: Workflow.dowhile() | ワークフローの構築 | Mastra ドキュメント" description: ワークフロー内の `.dowhile()` メソッドのドキュメント。条件が満たされている間、ステップを実行するループを作成します。 --- # Workflow.dowhile() [JA] Source: https://mastra.ai/ja/reference/workflows/dowhile `.dowhile()` メソッドは、条件が満たされている間、ステップを実行するループを作成します。 ## 使い方 ```typescript workflow.dowhile(stepOne, async ({ inputData }) => true); ``` ## パラメーター Promise", description: "ループを継続するかどうかを示すブール値を返す関数", isOptional: false, }, ]} /> ## 戻り値 ## 関連 - [ループ](../../docs/workflows/flow-control.mdx#loops) - [ループの例](../../examples/workflows/control-flow.mdx) --- title: "リファレンス: Workflow.else() | 条件分岐 | Mastra ドキュメント" description: "Mastraワークフローの`.else()`メソッドに関するドキュメント。if条件がfalseの場合に代替ブランチを作成します。" --- # Workflow.else() [JA] Source: https://mastra.ai/ja/reference/workflows/else > 実験的 `.else()` メソッドは、先行する `if` 条件が false と評価された場合に実行されるワークフロー内の代替ブランチを作成します。これにより、ワークフローは条件に基づいて異なるパスをたどることができます。 ## 使用方法 ```typescript copy showLineNumbers workflow .step(startStep) .if(async ({ context }) => { const value = context.getStepResult<{ value: number }>("start")?.value; return value < 10; }) .then(ifBranchStep) .else() // 条件が偽の場合の代替ブランチ .then(elseBranchStep) .commit(); ``` ## パラメータ `else()` メソッドはパラメータを取りません。 ## 戻り値 ## 動作 - `else()` メソッドはワークフロー定義内で `if()` ブランチの後に続く必要があります - 先行する `if` 条件が false と評価された場合にのみ実行されるブランチを作成します - `else()` の後に `.then()` を使用して複数のステップをチェーンすることができます - `else` ブランチ内に追加の `if`/`else` 条件をネストすることができます ## エラー処理 `else()`メソッドは、先行する`if()`ステートメントが必要です。先行する`if`なしで使用しようとすると、エラーがスローされます: ```typescript try { // これはエラーをスローします workflow.step(someStep).else().then(anotherStep).commit(); } catch (error) { console.error(error); // "No active condition found" } ``` ## 関連 - [if リファレンス](./if.mdx) - [then リファレンス](./then.mdx) - [制御フロー ガイド](../../docs/workflows/control-flow.mdx) - [ステップ条件リファレンス](./step-condition.mdx) --- title: "イベント駆動型ワークフロー | Mastra ドキュメント" description: "MastraでafterEventとresumeWithEventメソッドを使用してイベント駆動型ワークフローを作成する方法を学びましょう。" --- # イベント駆動型ワークフロー [JA] Source: https://mastra.ai/ja/reference/workflows/events Mastraは`afterEvent`および`resumeWithEvent`メソッドを通じてイベント駆動型ワークフローの組み込みサポートを提供しています。これらのメソッドを使用すると、特定のイベントが発生するのを待機している間に実行を一時停止し、イベントデータが利用可能になったときにそのデータでワークフローを再開することができます。 ## 概要 イベント駆動型ワークフローは以下のようなシナリオで役立ちます: - 外部システムの処理完了を待つ必要がある場合 - 特定のポイントでユーザーの承認や入力が必要な場合 - 非同期操作の調整が必要な場合 - 長時間実行されるプロセスを異なるサービス間で実行を分割する必要がある場合 ## イベントの定義 イベント駆動型の手法を使用する前に、ワークフロー構成でワークフローがリッスンするイベントを定義する必要があります。 ```typescript import { Workflow } from "@mastra/core/workflows"; import { z } from "zod"; const workflow = new Workflow({ name: "approval-workflow", triggerSchema: z.object({ requestId: z.string() }), events: { // Define events with their validation schemas approvalReceived: { schema: z.object({ approved: z.boolean(), approverName: z.string(), comment: z.string().optional(), }), }, documentUploaded: { schema: z.object({ documentId: z.string(), documentType: z.enum(["invoice", "receipt", "contract"]), metadata: z.record(z.string()).optional(), }), }, }, }); ``` 各イベントには名前と、そのイベントが発生した際に期待されるデータの構造を定義するスキーマが必要です。 ## afterEvent() `afterEvent`メソッドは、ワークフロー内に特定のイベントを自動的に待機する中断ポイントを作成します。 ### 構文 ```typescript workflow.afterEvent(eventName: string): Workflow ``` ### パラメータ - `eventName`: 待機するイベントの名前(ワークフローの`events`設定で定義されている必要があります) ### 戻り値 メソッドチェーン用のワークフローインスタンスを返します。 ### 動作の仕組み `afterEvent`が呼び出されると、Mastraは以下を行います: 1. `__eventName_event`というIDを持つ特別なステップを作成します 2. このステップを設定して、ワークフローの実行を自動的に一時停止します 3. イベントが受信された後の継続ポイントを設定します ### 使用例 ```typescript workflow .step(initialProcessStep) .afterEvent("approvalReceived") // ワークフローはここで一時停止します .step(postApprovalStep) // これはイベントが受信された後に実行されます .then(finalStep) .commit(); ``` ## resumeWithEvent() `resumeWithEvent`メソッドは、特定のイベントにデータを提供することで、一時停止されたワークフローを再開します。 ### 構文 ```typescript run.resumeWithEvent(eventName: string, data: any): Promise ``` ### パラメータ - `eventName`: トリガーされるイベントの名前 - `data`: イベントデータ(このイベントに定義されたスキーマに準拠する必要があります) ### 戻り値 再開後のワークフロー実行結果に解決するPromiseを返します。 ### 動作の仕組み `resumeWithEvent`が呼び出されると、Mastraは以下を実行します: 1. イベントデータをそのイベントに定義されたスキーマに対して検証します 2. ワークフローのスナップショットを読み込みます 3. イベントデータでコンテキストを更新します 4. イベントステップから実行を再開します 5. 後続のステップでワークフロー実行を継続します ### 使用例 ```typescript // ワークフロー実行を作成 const run = workflow.createRun(); // ワークフローを開始 await run.start({ triggerData: { requestId: "req-123" } }); // 後で、イベントが発生した時: const result = await run.resumeWithEvent("approvalReceived", { approved: true, approverName: "John Doe", comment: "Looks good to me!", }); console.log(result.results); ``` ## イベントデータへのアクセス ワークフローがイベントデータで再開されると、そのデータはステップコンテキスト内で `context.inputData.resumedEvent` として利用可能になります: ```typescript const processApprovalStep = new Step({ id: "processApproval", execute: async ({ context }) => { // Access the event data const eventData = context.inputData.resumedEvent; return { processingResult: `Processed approval from ${eventData.approverName}`, wasApproved: eventData.approved, }; }, }); ``` ## 複数のイベント 異なる時点で複数の異なるイベントを待機するワークフローを作成できます: ```typescript workflow .step(createRequest) .afterEvent("approvalReceived") .step(processApproval) .afterEvent("documentUploaded") .step(processDocument) .commit(); ``` 複数のイベント中断ポイントを持つワークフローを再開する場合、現在の中断ポイントに対して正しいイベント名とデータを提供する必要があります。 ## 実践例 この例では、承認とドキュメントのアップロードの両方が必要な完全なワークフローを示します。 ```typescript import { Workflow, Step } from "@mastra/core/workflows"; import { z } from "zod"; // Define steps const createRequest = new Step({ id: "createRequest", execute: async () => ({ requestId: `req-${Date.now()}` }), }); const processApproval = new Step({ id: "processApproval", execute: async ({ context }) => { const approvalData = context.inputData.resumedEvent; return { approved: approvalData.approved, approver: approvalData.approverName, }; }, }); const processDocument = new Step({ id: "processDocument", execute: async ({ context }) => { const documentData = context.inputData.resumedEvent; return { documentId: documentData.documentId, processed: true, type: documentData.documentType, }; }, }); const finalizeRequest = new Step({ id: "finalizeRequest", execute: async ({ context }) => { const requestId = context.steps.createRequest.output.requestId; const approved = context.steps.processApproval.output.approved; const documentId = context.steps.processDocument.output.documentId; return { finalized: true, summary: `Request ${requestId} was ${approved ? "approved" : "rejected"} with document ${documentId}`, }; }, }); // Create workflow const requestWorkflow = new Workflow({ name: "document-request-workflow", events: { approvalReceived: { schema: z.object({ approved: z.boolean(), approverName: z.string(), }), }, documentUploaded: { schema: z.object({ documentId: z.string(), documentType: z.enum(["invoice", "receipt", "contract"]), }), }, }, }); // Build workflow requestWorkflow .step(createRequest) .afterEvent("approvalReceived") .step(processApproval) .afterEvent("documentUploaded") .step(processDocument) .then(finalizeRequest) .commit(); // Export workflow export { requestWorkflow }; ``` ### サンプルワークフローの実行 ```typescript import { requestWorkflow } from "./workflows"; import { mastra } from "./mastra"; async function runWorkflow() { // Get the workflow const workflow = mastra.getWorkflow("document-request-workflow"); const run = workflow.createRun(); // Start the workflow const initialResult = await run.start(); console.log("Workflow started:", initialResult.results); // Simulate receiving approval const afterApprovalResult = await run.resumeWithEvent("approvalReceived", { approved: true, approverName: "Jane Smith", }); console.log("After approval:", afterApprovalResult.results); // Simulate document upload const finalResult = await run.resumeWithEvent("documentUploaded", { documentId: "doc-456", documentType: "invoice", }); console.log("Final result:", finalResult.results); } runWorkflow().catch(console.error); ``` ## ベストプラクティス 1. **明確なイベントスキーマを定義する**: Zod を使ってイベントデータのバリデーション用に正確なスキーマを作成しましょう 2. **分かりやすいイベント名を使用する**: イベントの目的が明確に伝わる名前を選びましょう 3. **イベントの未発生を処理する**: イベントが発生しない場合やタイムアウトする場合にもワークフローが対応できるようにしましょう 4. **モニタリングを含める**: `watch` メソッドを使って、イベント待ちで一時停止しているワークフローを監視しましょう 5. **タイムアウトを考慮する**: 発生しない可能性のあるイベントに対してタイムアウト機構を実装しましょう 6. **イベントをドキュメント化する**: 他の開発者のために、ワークフローが依存するイベントを明確にドキュメント化しましょう ## 関連 - [ワークフローにおける一時停止と再開](../../docs/workflows/suspend-and-resume.mdx) - [Workflow クラスリファレンス](./workflow.mdx) - [Resume メソッドリファレンス](./resume.mdx) - [Watch メソッドリファレンス](./watch.mdx) - [After Event リファレンス](./afterEvent.mdx) - [Resume With Event リファレンス](./resumeWithEvent.mdx) --- title: "リファレンス: Workflow.execute() | ワークフローの構築 | Mastra ドキュメント" description: ワークフロー内の `.execute()` メソッドのドキュメント。入力データでステップを実行し、出力を返します。 --- # Workflow.execute() [JA] Source: https://mastra.ai/ja/reference/workflows/execute `.execute()` メソッドは、入力データを使ってステップを実行し、その出力を返します。これにより、ワークフロー内でデータを処理することができます。 ## 使い方 ```typescript const inputSchema = z.object({ inputValue: z.string(), }); const myStep = createStep({ id: "my-step", description: "Does something useful", inputSchema, outputSchema: z.object({ outputValue: z.string(), }), resumeSchema: z.object({ resumeValue: z.string(), }), suspendSchema: z.object({ suspendValue: z.string(), }), execute: async ({ inputData, mastra, getStepResult, getInitData, runtimeContext, }) => { const otherStepOutput = getStepResult(step2); const initData = getInitData(); // typed as the input schema variable (zod schema) return { outputValue: `Processed: ${inputData.inputValue}, ${initData.startValue} (runtimeContextValue: ${runtimeContext.get("runtimeContextValue")})`, }; }, }); ``` ## パラメーター ", description: "ステップの入力スキーマに一致する入力データ", isOptional: false, }, { name: "resumeData", type: "ResumeSchema", description: "一時停止したステップを再開するためのデータ", isOptional: true, }, { name: "suspend", type: "(suspendPayload: any) => Promise", description: "ステップの実行を一時停止する関数", isOptional: false, }, { name: "resume", type: "object", description: "実行再開のための設定", isOptional: true, properties: [ { name: "steps", type: "string[]", description: "再開するステップ", isOptional: false, }, { name: "resumePayload", type: "any", description: "再開時に使用するペイロードデータ", isOptional: false, }, { name: "runId", type: "string", description: "再開する実行のID", isOptional: true, }, ], }, { name: "emitter", type: "object", description: "イベントエミッターオブジェクト", isOptional: false, properties: [ { name: "emit", type: "(event: string, data: any) => void", description: "イベントを発行する関数", isOptional: false, }, ], }, { name: "mastra", type: "Mastra", description: "Mastraインスタンス", isOptional: false, }, ], }, ]} /> ## 戻り値 >", description: "実行されたステップの出力に解決されるプロミス", }, ]} /> ## 関連項目 - [ワークフローの実行](../../docs/workflows/overview.mdx#running-workflows) --- title: "リファレンス: Workflow.foreach() | ワークフローの構築 | Mastra ドキュメント" description: ワークフロー内の `.foreach()` メソッドのドキュメント。配列内の各アイテムに対してステップを実行するループを作成します。 --- # Workflow.foreach() [JA] Source: https://mastra.ai/ja/reference/workflows/foreach `.foreach()` メソッドは、配列内の各アイテムに対してステップを実行するループを作成します。 ## 使い方 ```typescript workflow.foreach(stepOne, { concurrency: 2 }); ``` ## パラメータ ## 戻り値 ## 関連 - [For each](../../docs/workflows/control-flow.mdx#foreach) --- title: "リファレンス: Workflow.if() | 条件分岐 | Mastra ドキュメント" description: "Mastraワークフローの`.if()`メソッドに関するドキュメント。指定された条件に基づいて条件分岐を作成します。" --- # Workflow.if() [JA] Source: https://mastra.ai/ja/reference/workflows/if > 実験的 `.if()`メソッドはワークフローに条件分岐を作成し、指定された条件が真の場合にのみステップを実行できるようにします。これにより、前のステップの結果に基づいて動的なワークフローパスが可能になります。 ## 使用方法 ```typescript copy showLineNumbers workflow .step(startStep) .if(async ({ context }) => { const value = context.getStepResult<{ value: number }>("start")?.value; return value < 10; // trueの場合、"if"ブランチを実行 }) .then(ifBranchStep) .else() .then(elseBranchStep) .commit(); ``` ## パラメータ ## 条件タイプ ### 関数条件 ブール値を返す関数を使用できます: ```typescript workflow .step(startStep) .if(async ({ context }) => { const result = context.getStepResult<{ status: string }>("start"); return result?.status === "success"; // ステータスが「success」の場合に「if」ブランチを実行 }) .then(successStep) .else() .then(failureStep); ``` ### 参照条件 比較演算子を使用した参照ベースの条件を使用できます: ```typescript workflow .step(startStep) .if({ ref: { step: startStep, path: "value" }, query: { $lt: 10 }, // 値が10未満の場合に「if」ブランチを実行 }) .then(ifBranchStep) .else() .then(elseBranchStep); ``` ## 戻り値 ## エラー処理 `if`メソッドは、前のステップが定義されていることを必要とします。先行するステップなしでこれを使用しようとすると、エラーがスローされます: ```typescript try { // これはエラーをスローします workflow .if(async ({ context }) => true) .then(someStep) .commit(); } catch (error) { console.error(error); // "Condition requires a step to be executed after" } ``` ## 関連 - [else リファレンス](./else.mdx) - [then リファレンス](./then.mdx) - [制御フローガイド](../../docs/workflows/control-flow.mdx) - [ステップ条件リファレンス](./step-condition.mdx) --- title: "リファレンス: Workflow.map() | ワークフローの構築 | Mastra ドキュメント" description: ワークフロー内の `.map()` メソッドのドキュメント。前のステップの出力データを次のステップの入力にマッピングします。 --- # Workflow.map() [JA] Source: https://mastra.ai/ja/reference/workflows/map `.map()` メソッドは、前のステップの出力データを次のステップの入力にマッピングし、ステップ間でデータを変換できるようにします。 ## 使用方法 ```typescript const step1 = createStep({ id: "step1", inputSchema: z.object({ inputValue: z.string(), }), outputSchema: z.object({ outputValue: z.string(), }), execute: async ({ inputData }) => { return { outputValue: inputData.inputValue }; }, }); const step2 = createStep({ id: "step2", inputSchema: z.object({ unexpectedName: z.string(), }), outputSchema: z.object({ result: z.string(), }), execute: async ({ inputData }) => { return { result: inputData.unexpectedName }; }, }); const workflow = createWorkflow({ id: "my-workflow", steps: [step1, step2], inputSchema: z.object({ inputValue: z.string(), }), outputSchema: z.object({ result: z.string(), }), }); workflow .then(step1) .map({ unexpectedName: { step: step1, path: "outputValue", }, }) .then(step2) .commit(); ``` ## パラメーター ## 戻り値 ## 関連 - [入力データのマッピング](../../docs/workflows/input-data-mapping.mdx) --- title: "リファレンス: Workflow.parallel() | ワークフローの構築 | Mastra ドキュメント" description: ワークフロー内で複数のステップを並列に実行する `.parallel()` メソッドのドキュメント。 --- # Workflow.parallel() [JA] Source: https://mastra.ai/ja/reference/workflows/parallel `.parallel()` メソッドは複数のステップを並列で実行します。 ## 使い方 ```typescript workflow.parallel([stepOne, stepTwo]); ``` ## パラメーター ## 戻り値 ## 関連項目 - [並列ワークフローの例](../../examples/workflows/parallel-steps.mdx) --- title: "リファレンス: Workflow.resume() | ワークフローの構築 | Mastra ドキュメント" description: ワークフローにおける `.resume()` メソッドのドキュメント。新しいデータで一時停止されたワークフローの実行を再開します。 --- # Workflow.resume() [JA] Source: https://mastra.ai/ja/reference/workflows/resume `.resume()` メソッドは、新しいデータで一時停止されたワークフローの実行を再開し、特定のステップから実行を継続できるようにします。 ## 使用方法 ```typescript const run = counterWorkflow.createRun(); const result = await run.start({ inputData: { startValue: 0 } }); if (result.status === "suspended") { const resumedResults = await run.resume({ step: result.suspended[0], resumeData: { newValue: 0 }, }); } ``` ## パラメーター ## 戻り値 >", description: "再開されたワークフロー実行の結果を解決する Promise", }, ]} /> ## 関連 - [一時停止と再開](../../docs/workflows/suspend-and-resume.mdx) - [人間が介在する例](../../examples/workflows/human-in-the-loop.mdx) --- title: ".resumeWithEvent() メソッド | Mastra ドキュメント" description: "イベントデータを使用して中断されたワークフローを再開する resumeWithEvent メソッドのリファレンス。" --- # resumeWithEvent() [JA] Source: https://mastra.ai/ja/reference/workflows/resumeWithEvent `resumeWithEvent()` メソッドは、ワークフローが待機している特定のイベントに対するデータを提供することによって、ワークフローの実行を再開します。 ## 構文 ```typescript const run = workflow.createRun(); // ワークフローが開始され、イベントステップで一時停止した後 await run.resumeWithEvent(eventName: string, data: any): Promise ``` ## パラメーター | パラメーター | 型 | 説明 | | ------------ | ------ | ---------------------------------------------------------------------------------------------------- | | eventName | string | トリガーするイベントの名前。ワークフローの`events`設定で定義されたイベントと一致する必要があります。 | | data | any | 提供するイベントデータ。そのイベントのために定義されたスキーマに準拠している必要があります。 | ## 戻り値 `WorkflowRunResult` オブジェクトに解決される Promise を返します。これには以下が含まれます: - `results`: ワークフロー内の各ステップの結果ステータスと出力 - `activePaths`: アクティブなワークフローパスとその状態のマップ - `value`: ワークフローの現在の状態値 - その他のワークフロー実行メタデータ ## 説明 `resumeWithEvent()` メソッドは、`afterEvent()` メソッドによって作成されたイベントステップで一時停止されたワークフローを再開するために使用されます。このメソッドが呼び出されると、以下の処理が行われます: 1. 提供されたイベントデータを、そのイベントのために定義されたスキーマに対して検証します 2. ストレージからワークフローのスナップショットをロードします 3. `resumedEvent` フィールドにイベントデータを使用してコンテキストを更新します 4. イベントステップから実行を再開します 5. 後続のステップでワークフローの実行を続行します このメソッドは、Mastra のイベント駆動型ワークフロー機能の一部であり、外部イベントやユーザーの操作に応答するワークフローを作成することができます。 ## 使用上の注意 - ワークフローは中断状態でなければならず、特に`afterEvent(eventName)`によって作成されたイベントステップである必要があります - イベントデータは、ワークフロー構成でそのイベントのために定義されたスキーマに準拠している必要があります - ワークフローは中断されたポイントから実行を続行します - ワークフローが中断されていないか、別のステップで中断されている場合、このメソッドはエラーをスローする可能性があります - イベントデータは`context.inputData.resumedEvent`を通じて後続のステップで利用可能になります ## 例 ### 基本的な使用法 ```typescript // Define and start a workflow const workflow = mastra.getWorkflow("approval-workflow"); const run = workflow.createRun(); // Start the workflow await run.start({ triggerData: { requestId: "req-123" } }); // Later, when the approval event occurs: const result = await run.resumeWithEvent("approval", { approved: true, approverName: "John Doe", comment: "Looks good to me!", }); console.log(result.results); ``` ### エラーハンドリング付き ```typescript try { const result = await run.resumeWithEvent("paymentReceived", { amount: 100.5, transactionId: "tx-456", paymentMethod: "credit-card", }); console.log("Workflow resumed successfully:", result.results); } catch (error) { console.error("Failed to resume workflow with event:", error); // Handle error - could be invalid event data, workflow not suspended, etc. } ``` ### 監視と自動再開 ```typescript // Start a workflow const { start, watch, resumeWithEvent } = workflow.createRun(); // Watch for suspended event steps watch(async ({ activePaths }) => { const isApprovalEventSuspended = activePaths.get("__approval_event")?.status === "suspended"; // Check if suspended at the approval event step if (isApprovalEventSuspended) { console.log("Workflow waiting for approval"); // In a real scenario, you would wait for the actual event // Here we're simulating with a timeout setTimeout(async () => { try { await resumeWithEvent("approval", { approved: true, approverName: "Auto Approver", }); } catch (error) { console.error("Failed to auto-resume workflow:", error); } }, 5000); // Wait 5 seconds before auto-approving } }); // Start the workflow await start({ triggerData: { requestId: "auto-123" } }); ``` ## 関連 - [イベント駆動型ワークフロー](./events.mdx) - [afterEvent()](./afterEvent.mdx) - [一時停止と再開](../../docs/workflows/suspend-and-resume.mdx) - [resume()](./resume.mdx) - [watch()](./watch.mdx) --- title: "リファレンス: スナップショット | ワークフロー状態の永続化 | Mastra ドキュメント" description: "Mastra におけるスナップショットの技術リファレンス - サスペンドおよびレジューム機能を可能にするシリアライズされたワークフロー状態" --- # スナップショット [JA] Source: https://mastra.ai/ja/reference/workflows/snapshots Mastraにおけるスナップショットとは、ワークフローの完全な実行状態を特定の時点でシリアライズ可能な形で表現したものです。スナップショットは、ワークフローを中断したまさにその場所から再開するために必要なすべての情報を記録します。これには以下が含まれます: - ワークフロー内の各ステップの現在の状態 - 完了したステップの出力 - ワークフロー内でたどった実行経路 - 一時停止中のステップとそのメタデータ - 各ステップの残りのリトライ回数 - 実行を再開するために必要な追加のコンテキストデータ スナップショットは、ワークフローが一時停止されるたびにMastraによって自動的に作成・管理され、設定されたストレージシステムに永続化されます。 ## サスペンドとレジュームにおけるスナップショットの役割 スナップショットは、Mastra のサスペンドおよびレジューム機能を実現するための重要な仕組みです。ワークフローステップで `await suspend()` が呼び出されると: 1. ワークフローの実行はその時点で一時停止されます 2. ワークフローの現在の状態がスナップショットとして記録されます 3. スナップショットはストレージに保存されます 4. ワークフローステップは「サスペンド中」として `'suspended'` ステータスでマークされます 5. 後で、サスペンドされたステップに対して `resume()` が呼び出されると、スナップショットが取得されます 6. ワークフローの実行は中断された場所から正確に再開されます この仕組みにより、人間が介在するワークフローの実装や、レート制限への対応、外部リソースの待機、長期間の一時停止が必要な複雑な分岐ワークフローの実装が強力に可能となります。 ## スナップショットの構成 Mastra ワークフローのスナップショットは、いくつかの主要なコンポーネントで構成されています。 ```typescript export interface WorkflowRunState { // Core state info value: Record; // Current state machine value context: { // Workflow context [key: string]: Record< string, | { status: "success"; output: any; } | { status: "failed"; error: string; } | { status: "suspended"; payload?: any; } >; input: Record; // Initial input data }; activePaths: Array<{ // Currently active execution paths stepPath: string[]; stepId: string; status: string; }>; // Paths to suspended steps suspendedPaths: Record; // Metadata runId: string; // Unique run identifier timestamp: number; // Time snapshot was created } ``` ## スナップショットの保存と取得方法 Mastraは、設定されたストレージシステムにスナップショットを永続化します。デフォルトでは、スナップショットはLibSQLデータベースに保存されますが、Upstashなど他のストレージプロバイダーを使用するように設定することも可能です。 スナップショットは`workflow_snapshots`テーブルに保存され、libsqlを使用している場合は関連する実行の`run_id`によって一意に識別されます。 永続化レイヤーを利用することで、スナップショットはワークフローの実行をまたいで保持され、高度なヒューマン・イン・ザ・ループ機能を実現できます。 [libsqlストレージ](../storage/libsql.mdx)および[upstashストレージ](../storage/upstash.mdx)についての詳細はこちらをご覧ください。 ### スナップショットの保存 ワークフローが一時停止されると、Mastraは以下の手順でワークフロースナップショットを自動的に永続化します。 1. ステップ実行中に`suspend()`関数がスナップショット処理をトリガーします 2. `WorkflowInstance.suspend()`メソッドが一時停止したマシンを記録します 3. `persistWorkflowSnapshot()`が呼び出され、現在の状態を保存します 4. スナップショットはシリアライズされ、設定されたデータベースの`workflow_snapshots`テーブルに保存されます 5. ストレージレコードにはワークフロー名、実行ID、シリアライズされたスナップショットが含まれます ### スナップショットの取得 ワークフローが再開されると、Mastraは以下の手順で永続化されたスナップショットを取得します。 1. 特定のステップIDで`resume()`メソッドが呼び出されます 2. `loadWorkflowSnapshot()`を使用してストレージからスナップショットが読み込まれます 3. スナップショットが解析され、再開の準備が行われます 4. ワークフローの実行がスナップショットの状態で再構築されます 5. 一時停止していたステップが再開され、実行が続行されます ## スナップショットのストレージオプション Mastra は、スナップショットを永続化するための複数のストレージオプションを提供しています。 `storage` インスタンスは `Mastra` クラスで設定され、`Mastra` インスタンスに登録されたすべてのワークフローのためのスナップショット永続化レイヤーとして使用されます。 つまり、同じ `Mastra` インスタンスに登録されたすべてのワークフローでストレージが共有されます。 ### LibSQL(デフォルト) デフォルトのストレージオプションは LibSQL で、SQLite 互換のデータベースです: ```typescript import { Mastra } from "@mastra/core/mastra"; import { DefaultStorage } from "@mastra/core/storage/libsql"; const mastra = new Mastra({ storage: new DefaultStorage({ config: { url: "file:storage.db", // ローカルファイルベースのデータベース // 本番環境の場合: // url: process.env.DATABASE_URL, // authToken: process.env.DATABASE_AUTH_TOKEN, }, }), workflows: { weatherWorkflow, travelWorkflow, }, }); ``` ### Upstash(Redis 互換) サーバーレス環境向け: ```typescript import { Mastra } from "@mastra/core/mastra"; import { UpstashStore } from "@mastra/upstash"; const mastra = new Mastra({ storage: new UpstashStore({ url: process.env.UPSTASH_URL, token: process.env.UPSTASH_TOKEN, }), workflows: { weatherWorkflow, travelWorkflow, }, }); ``` ## スナップショット作業のベストプラクティス 1. **シリアライズ可能であることを確認する**: スナップショットに含める必要があるデータは、必ずシリアライズ可能(JSONに変換可能)でなければなりません。 2. **スナップショットのサイズを最小限に抑える**: 大きなデータオブジェクトをワークフローコンテキストに直接保存するのは避けましょう。代わりにIDなどの参照情報を保存し、必要なときにデータを取得してください。 3. **レジュームコンテキストの取り扱いに注意する**: ワークフローを再開する際、どのコンテキストを提供するか慎重に検討してください。これは既存のスナップショットデータとマージされます。 4. **適切なモニタリングを設定する**: 特に長時間実行されるワークフローについては、中断されたワークフローのモニタリングを実装し、確実に再開されるようにしましょう。 5. **ストレージのスケーリングを考慮する**: 多数の中断されたワークフローがあるアプリケーションでは、ストレージソリューションが適切にスケールされていることを確認してください。 ## 高度なスナップショットパターン ### カスタムスナップショットメタデータ ワークフローを一時停止する際、再開時に役立つカスタムメタデータを含めることができます: ```typescript await suspend({ reason: "顧客の承認待ち", requiredApprovers: ["manager", "finance"], requestedBy: currentUser, urgency: "high", expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), }); ``` このメタデータはスナップショットと共に保存され、再開時に利用できます。 ### 条件付き再開 再開時にサスペンドペイロードに基づいた条件付きロジックを実装できます: ```typescript run.watch(async ({ activePaths }) => { const isApprovalStepSuspended = activePaths.get("approval")?.status === "suspended"; if (isApprovalStepSuspended) { const payload = activePaths.get("approval")?.suspendPayload; if (payload.urgency === "high" && currentUser.role === "manager") { await resume({ stepId: "approval", context: { approved: true, approver: currentUser.id }, }); } } }); ``` ## 関連 - [サスペンドと再開](../../docs/workflows/suspend-and-resume.mdx) - [人間が介在する例](../../examples/workflows/human-in-the-loop.mdx) - [Watch 関数リファレンス](./watch.mdx) --- title: "リファレンス: Workflow.start() | ワークフローの構築 | Mastra ドキュメント" description: ワークフロー内の `.start()` メソッドのドキュメント。入力データでワークフロー実行を開始します。 --- # Workflow.start() [JA] Source: https://mastra.ai/ja/reference/workflows/start `.start()` メソッドは、入力データとともにワークフローの実行を開始し、最初からワークフローを実行できるようにします。 ## 使い方 ```typescript const run = myWorkflow.createRun(); // Start the workflow with input data const result = await run.start({ inputData: { startValue: "initial data", }, }); ``` ## パラメーター ", description: "ワークフローの入力スキーマに一致する入力データ", isOptional: true, }, { name: "runtimeContext", type: "RuntimeContext", description: "ワークフロー開始時に使用するランタイムコンテキストデータ", isOptional: true, }, ], }, ]} /> ## 戻り値 >", description: "ワークフロー実行の結果に解決されるPromise", }, ]} /> ## 関連 - [ワークフローの実行](../../docs/workflows/overview.mdx#running-workflows) - [実行リファレンスの作成](./create-run.mdx) --- title: "リファレンス: ステップ | ワークフローの構築 | Mastra ドキュメント" description: ワークフロー内の個々の作業単位を定義するステップクラスのドキュメント。 --- # Step [JA] Source: https://mastra.ai/ja/reference/workflows/step-class Stepクラスは、ワークフロー内の個々の作業単位を定義し、実行ロジック、データ検証、入出力処理をカプセル化します。 ## 使用方法 ```typescript const processOrder = new Step({ id: "processOrder", inputSchema: z.object({ orderId: z.string(), userId: z.string(), }), outputSchema: z.object({ status: z.string(), orderId: z.string(), }), execute: async ({ context, runId }) => { return { status: "processed", orderId: context.orderId, }; }, }); ``` ## コンストラクタパラメータ ", description: "変数とマージされる静的データ", required: false, }, { name: "execute", type: "(params: ExecuteParams) => Promise", description: "ステップのロジックを含む非同期関数", required: true, }, ]} /> ### ExecuteParams Promise", description: "ステップ実行を一時停止するための関数", }, { name: "mastra", type: "Mastra", description: "Mastraインスタンスへのアクセス", }, ]} /> ## 関連 - [ワークフローリファレンス](./workflow.mdx) - [ステップ設定ガイド](../../docs/workflows/steps.mdx) - [制御フローガイド](../../docs/workflows/control-flow.mdx) --- title: "リファレンス: StepCondition | ワークフローの構築 | Mastra" description: ワークフローのステップコンディションクラスに関するドキュメント。前のステップの出力またはトリガーデータに基づいて、ステップを実行するかどうかを決定します。 --- # StepCondition [JA] Source: https://mastra.ai/ja/reference/workflows/step-condition 条件は、前のステップの出力またはトリガーデータに基づいて、ステップを実行するかどうかを決定します。 ## 使用方法 条件を指定する方法は3つあります:関数、クエリオブジェクト、シンプルなパス比較です。 ### 1. 関数条件 ```typescript copy showLineNumbers workflow.step(processOrder, { when: async ({ context }) => { const auth = context?.getStepResult<{ status: string }>("auth"); return auth?.status === "authenticated"; }, }); ``` ### 2. クエリオブジェクト ```typescript copy showLineNumbers workflow.step(processOrder, { when: { ref: { step: "auth", path: "status" }, query: { $eq: "authenticated" }, }, }); ``` ### 3. シンプルなパス比較 ```typescript copy showLineNumbers workflow.step(processOrder, { when: { "auth.status": "authenticated", }, }); ``` 条件のタイプに基づいて、ワークフローランナーはこれらのタイプのいずれかに条件を一致させようとします。 1. シンプルなパス条件(キーにドットがある場合) 2. ベース/クエリ条件('ref'プロパティがある場合) 3. 関数条件(非同期関数の場合) ## StepCondition ", description: "siftオペレータ($eq、$gtなど)を使用したMongoDBスタイルのクエリ", isOptional: false, }, ]} /> ## クエリ Queryオブジェクトは、前のステップやトリガーデータからの値を比較するためのMongoDBスタイルのクエリ演算子を提供します。`$eq`、`$gt`、`$lt`などの基本的な比較演算子や、`$in`や`$nin`などの配列演算子をサポートし、and/or演算子と組み合わせて複雑な条件を作成することができます。 このクエリ構文により、ステップを実行するかどうかを決定するための読みやすい条件付きロジックを実現できます。 ## 関連 - [ステップオプションリファレンス](./step-options.mdx) - [ステップ関数リファレンス](./step-function.mdx) - [制御フローガイド](../../docs/workflows/control-flow.mdx) --- title: "リファレンス: Workflow.step() | ワークフロー | Mastra ドキュメント" description: ワークフローに新しいステップを追加する`.step()`メソッドのドキュメント。 --- # Workflow.step() [JA] Source: https://mastra.ai/ja/reference/workflows/step-function `.step()` メソッドは、ワークフローに新しいステップを追加し、オプションでその変数と実行条件を設定します。 ## 使用方法 ```typescript workflow.step({ id: "stepTwo", outputSchema: z.object({ result: z.number(), }), execute: async ({ context }) => { return { result: 42 }; }, }); ``` ## パラメータ ### StepDefinition Promise", description: "ステップロジックを含む関数", isOptional: false, }, ]} /> ### StepOptions ", description: "変数名とそのソース参照のマップ", isOptional: true, }, { name: "when", type: "StepCondition", description: "ステップを実行するために満たす必要がある条件", isOptional: true, }, ]} /> ## 関連 - [ステップインスタンスの基本的な使用方法](../../docs/workflows/steps.mdx) - [ステップクラスリファレンス](./step-class.mdx) - [ワークフロークラスリファレンス](./workflow.mdx) - [制御フローガイド](../../docs/workflows/control-flow.mdx) --- title: "リファレンス: StepOptions | ワークフローの構築 | Mastra ドキュメント" description: ワークフローのステップオプションに関するドキュメント。変数マッピング、実行条件、その他のランタイム動作を制御します。 --- # StepOptions [JA] Source: https://mastra.ai/ja/reference/workflows/step-options ワークフローステップの設定オプションで、変数マッピング、実行条件、その他のランタイム動作を制御します。 ## 使用方法 ```typescript workflow.step(processOrder, { variables: { orderId: { step: "trigger", path: "id" }, userId: { step: "auth", path: "user.id" }, }, when: { ref: { step: "auth", path: "status" }, query: { $eq: "authenticated" }, }, }); ``` ## プロパティ ", description: "ステップ入力変数を他のステップからの値にマッピングします", isOptional: true, }, { name: "when", type: "StepCondition", description: "ステップ実行のために満たす必要がある条件", isOptional: true, }, ]} /> ### VariableRef ## 関連項目 - [パス比較](../../docs/workflows/control-flow.mdx) - [ステップ関数リファレンス](./step-function.mdx) - [ステップクラスリファレンス](./step-class.mdx) - [ワークフロークラスリファレンス](./workflow.mdx) - [制御フローガイド](../../docs/workflows/control-flow.mdx) --- title: "ステップの再試行 | エラー処理 | Mastra ドキュメント" description: "設定可能な再試行ポリシーでMastraワークフローの失敗したステップを自動的に再試行します。" --- # ステップの再試行 [JA] Source: https://mastra.ai/ja/reference/workflows/step-retries Mastraはワークフローステップの一時的な障害に対処するための組み込みの再試行メカニズムを提供しています。これにより、ワークフローは手動での介入を必要とせずに、一時的な問題から優雅に回復することができます。 ## 概要 ワークフロー内のステップが失敗(例外をスロー)した場合、Mastraは設定可能な再試行ポリシーに基づいて、ステップの実行を自動的に再試行できます。これは以下のような問題に対処するのに役立ちます: - ネットワーク接続の問題 - サービスの利用不可 - レート制限 - 一時的なリソース制約 - その他の一過性の障害 ## デフォルトの動作 デフォルトでは、ステップが失敗しても再試行されません。これは以下を意味します: - ステップは一度だけ実行されます - 失敗した場合、ステップはすぐに失敗としてマークされます - ワークフローは、失敗したステップに依存しない後続のステップの実行を継続します ## 設定オプション リトライは2つのレベルで設定できます: ### 1. ワークフローレベルの設定 ワークフロー内のすべてのステップに対するデフォルトのリトライ設定を設定できます: ```typescript const workflow = new Workflow({ name: "my-workflow", retryConfig: { attempts: 3, // リトライ回数(最初の試行に加えて) delay: 1000, // リトライ間の遅延(ミリ秒) }, }); ``` ### 2. ステップレベルの設定 個々のステップにリトライを設定することもできます。これにより、そのステップに対するワークフローレベルの設定が上書きされます: ```typescript const fetchDataStep = new Step({ id: "fetchData", execute: async () => { // 外部APIからデータを取得 }, retryConfig: { attempts: 5, // このステップは最大5回リトライします delay: 2000, // リトライ間に2秒の遅延を設定 }, }); ``` ## リトライパラメータ `retryConfig` オブジェクトは以下のパラメータをサポートしています: | パラメータ | 型 | デフォルト | 説明 | | ---------- | ------ | ---------- | -------------------------------------- | | `attempts` | number | 0 | リトライ試行回数(初回の試行に加えて) | | `delay` | number | 1000 | リトライ間の待機時間(ミリ秒) | ## リトライの仕組み ステップが失敗した場合、Mastraのリトライメカニズムは以下のように動作します: 1. ステップに残りのリトライ試行回数があるかを確認します 2. 試行回数が残っている場合: - 試行カウンターを減らします - ステップを「待機中」状態に移行します - 設定された遅延時間を待ちます - ステップの実行を再試行します 3. 試行回数が残っていない、またはすべての試行が使い果たされた場合: - ステップを「失敗」としてマークします - ワークフローの実行を継続します(失敗したステップに依存しないステップについて) リトライ試行中、ワークフロー実行はアクティブなままですが、再試行されている特定のステップについては一時停止されます。 ## 例 ### 基本的なリトライの例 ```typescript import { Workflow, Step } from "@mastra/core/workflows"; // Define a step that might fail const unreliableApiStep = new Step({ id: "callUnreliableApi", execute: async () => { // Simulate an API call that might fail const random = Math.random(); if (random < 0.7) { throw new Error("API call failed"); } return { data: "API response data" }; }, retryConfig: { attempts: 3, // Retry up to 3 times delay: 2000, // Wait 2 seconds between attempts }, }); // Create a workflow with the unreliable step const workflow = new Workflow({ name: "retry-demo-workflow", }); workflow.step(unreliableApiStep).then(processResultStep).commit(); ``` ### ワークフローレベルのリトライとステップでの上書き ```typescript import { Workflow, Step } from "@mastra/core/workflows"; // Create a workflow with default retry configuration const workflow = new Workflow({ name: "multi-retry-workflow", retryConfig: { attempts: 2, // All steps will retry twice by default delay: 1000, // With a 1-second delay }, }); // This step uses the workflow's default retry configuration const standardStep = new Step({ id: "standardStep", execute: async () => { // Some operation that might fail }, }); // This step overrides the workflow's retry configuration const criticalStep = new Step({ id: "criticalStep", execute: async () => { // Critical operation that needs more retry attempts }, retryConfig: { attempts: 5, // Override with 5 retry attempts delay: 5000, // And a longer 5-second delay }, }); // This step disables retries const noRetryStep = new Step({ id: "noRetryStep", execute: async () => { // Operation that should not retry }, retryConfig: { attempts: 0, // Explicitly disable retries }, }); workflow.step(standardStep).then(criticalStep).then(noRetryStep).commit(); ``` ## リトライの監視 ログでリトライの試行を監視することができます。Mastraは`debug`レベルでリトライ関連のイベントを記録します: ``` [DEBUG] Step fetchData failed (runId: abc-123) [DEBUG] Attempt count for step fetchData: 2 remaining attempts (runId: abc-123) [DEBUG] Step fetchData waiting (runId: abc-123) [DEBUG] Step fetchData finished waiting (runId: abc-123) [DEBUG] Step fetchData pending (runId: abc-123) ``` ## ベストプラクティス 1. **一時的な障害に対してリトライを使用する**: 一時的な障害が発生する可能性のある操作に対してのみリトライを設定してください。確定的なエラー(バリデーションエラーなど)に対しては、リトライは役立ちません。 2. **適切な遅延を設定する**: 外部APIコールには、サービスが回復する時間を確保するために、より長い遅延を検討してください。 3. **リトライ回数を制限する**: 障害発生時にワークフローが過度に長時間実行されることを防ぐため、極端に高いリトライ回数は設定しないでください。 4. **べき等操作を実装する**: リトライされる可能性があるため、ステップの`execute`関数がべき等(副作用なく複数回呼び出せる)であることを確認してください。 5. **バックオフ戦略を検討する**: より高度なシナリオでは、レート制限がかかる可能性のある操作に対して、ステップのロジックに指数関数的バックオフを実装することを検討してください。 ## 関連 - [ステップクラスリファレンス](./step-class.mdx) - [ワークフロー設定](./workflow.mdx) - [ワークフローでのエラー処理](../../docs/workflows/error-handling.mdx) --- title: "リファレンス: Step | ワークフローの構築 | Mastra ドキュメント" description: ワークフロー内の個々の作業単位を定義する Step クラスのドキュメントです。 --- # Step [JA] Source: https://mastra.ai/ja/reference/workflows/step Stepクラスは、ワークフロー内の個別の作業単位を定義し、実行ロジック、データ検証、入力/出力処理をカプセル化します。 toolまたはagentのいずれかをパラメータとして受け取り、それらから自動的にステップを作成することができます。 ## 使用方法 ```typescript import { createStep } from "@mastra/core/workflows"; import { z } from "zod"; const processOrder = createStep({ id: "processOrder", inputSchema: z.object({ orderId: z.string(), userId: z.string(), }), outputSchema: z.object({ status: z.string(), orderId: z.string(), }), resumeSchema: z.object({ orderId: z.string(), }), suspendSchema: z.object({}), execute: async ({ inputData, mastra, getStepResult, getInitData, suspend, runtimeContext, runId, }) => { return { status: "processed", orderId: inputData.orderId, }; }, }); ``` ## Constructor Parameters ", description: "入力構造を定義するZodスキーマ", required: true, }, { name: "outputSchema", type: "z.ZodType", description: "出力構造を定義するZodスキーマ", required: true, }, { name: "resumeSchema", type: "z.ZodType", description: "ステップを再開するためのオプションZodスキーマ", required: false, }, { name: "suspendSchema", type: "z.ZodType", description: "ステップを一時停止するためのオプションZodスキーマ", required: false, }, { name: "execute", type: "(params: ExecuteParams) => Promise", description: "ステップロジックを含む非同期関数", required: true, }, ]} /> ### ExecuteParams ", description: "inputSchemaに一致する入力データ", }, { name: "resumeData", type: "z.infer", description: "一時停止状態からステップを再開する際のresumeSchemaに一致する再開データ。ステップが再開される場合のみ存在します。", }, { name: "mastra", type: "Mastra", description: "Mastraサービス(エージェント、ツールなど)へのアクセス", }, { name: "getStepResult", type: "(stepId: string) => any", description: "他のステップの結果にアクセスする関数", }, { name: "getInitData", type: "() => any", description: "任意のステップでワークフローの初期入力データにアクセスする関数", }, { name: "suspend", type: "() => Promise", description: "ワークフロー実行を一時停止する関数", }, { name: "runId", type: "string", description: "現在の実行ID", }, { name: "runtimeContext", type: "RuntimeContext", isOptional: true, description: "依存性注入とコンテキスト情報のためのランタイムコンテキスト。", }, ]} /> ## 関連 - [制御フロー](../../docs/workflows/control-flow.mdx) - [エージェントとツールの使用](../../docs/workflows/using-with-agents-and-tools.mdx) - [ステップとしてのツールとエージェントの例](../../examples/workflows/agent-and-tool-interop.mdx) - [入力データマッピング](../../docs/workflows/input-data-mapping.mdx) --- title: "リファレンス: Workflow.stream() | ワークフローの構築 | Mastra Docs" description: ワークフローの`.stream()`メソッドのドキュメント。このメソッドを使用すると、ワークフロー実行をストリームとして監視できます。 --- # Run.stream() [JA] Source: https://mastra.ai/ja/reference/workflows/stream `.stream()`メソッドを使用すると、ワークフローの実行を監視し、ステップのステータスに関するリアルタイムの更新を提供できます。 ## 使用方法 ```typescript const run = myWorkflow.createRun(); // Add a stream to monitor execution const result = run.stream({ inputData: {...} }); for (const chunk of stream) { // do something with the chunk } ``` ## メッセージ ## パラメーター ", parameters: [ { name: "z.infer", type: "inputData", description: "ワークフローを開始する際に使用するランタイムコンテキストデータ", isOptional: true, }, ], }, { name: "runtimeContext", type: "RuntimeContext", parameters: [ { name: "runtimeContext", type: "RuntimeContext", description: "ワークフローを開始する際に使用するランタイムコンテキストデータ", isOptional: true, }, ], }, ], }, ]} /> ## 戻り値 >", description: "各ステップをストリームにパイプするストリーム", }, ]} /> --- title: "リファレンス: suspend() | コントロールフロー | Mastra ドキュメント" description: "Mastraワークフローにおけるsuspend関数のドキュメント。再開されるまで実行を一時停止します。" --- # suspend() [JA] Source: https://mastra.ai/ja/reference/workflows/suspend 現在のステップでワークフローの実行を一時停止し、明示的に再開されるまで待機します。ワークフローの状態は保持され、後で続行することができます。 ## 使用例 ```typescript const approvalStep = new Step({ id: "needsApproval", execute: async ({ context, suspend }) => { if (context.steps.amount > 1000) { await suspend(); } return { approved: true }; }, }); ``` ## パラメータ ", description: "一時停止状態と共に保存するオプションのデータ", isOptional: true, }, ]} /> ## 戻り値 ", type: "Promise", description: "ワークフローが正常に一時停止されると解決します", }, ]} /> ## その他の例 メタデータを含む一時停止: ```typescript const reviewStep = new Step({ id: "review", execute: async ({ context, suspend }) => { await suspend({ reason: "Needs manager approval", requestedBy: context.user, }); return { reviewed: true }; }, }); ``` ### 関連項目 - [ワークフローの一時停止と再開](../../docs/workflows/suspend-and-resume.mdx) - [.resume()](./resume.mdx) - [.watch()](./watch.mdx) --- title: "リファレンス: Workflow.then() | ワークフローの構築 | Mastra ドキュメント" description: ワークフローにおける `.then()` メソッドのドキュメント。ステップ間の順次依存関係を作成します。 --- # Workflow.then() [JA] Source: https://mastra.ai/ja/reference/workflows/then `.then()`メソッドはワークフローステップ間の順次依存関係を作成し、ステップが特定の順序で実行されることを保証します。 ## 使用方法 ```typescript workflow.then(stepOne).then(stepTwo); ``` ## パラメーター ## 戻り値 ## 関連 - [制御フロー](../../docs/workflows/control-flow.mdx) --- title: "リファレンス: Workflow.until() | ワークフロー内のループ処理 | Mastra ドキュメント" description: "Mastra ワークフローにおける `.until()` メソッドのドキュメント。指定した条件が真になるまでステップを繰り返します。" --- # Workflow.until() [JA] Source: https://mastra.ai/ja/reference/workflows/until `.until()` メソッドは、指定した条件が真になるまでステップを繰り返します。これにより、条件が満たされるまで指定したステップを実行し続けるループが作成されます。 ## 使い方 ```typescript workflow.step(incrementStep).until(condition, incrementStep).then(finalStep); ``` ## パラメーター ## 条件タイプ ### 関数条件 真偽値を返す関数を使用できます: ```typescript workflow .step(incrementStep) .until(async ({ context }) => { const result = context.getStepResult<{ value: number }>("increment"); return (result?.value ?? 0) >= 10; // 値が10以上になったら停止 }, incrementStep) .then(finalStep); ``` ### 参照条件 比較演算子を使った参照ベースの条件を使用できます: ```typescript workflow .step(incrementStep) .until( { ref: { step: incrementStep, path: "value" }, query: { $gte: 10 }, // 値が10以上になったら停止 }, incrementStep, ) .then(finalStep); ``` ## 比較演算子 参照ベースの条件を使用する場合、次の比較演算子を使用できます。 | 演算子 | 説明 | 例 | | ------ | ---------- | -------------- | | `$eq` | 等しい | `{ $eq: 10 }` | | `$ne` | 等しくない | `{ $ne: 0 }` | | `$gt` | より大きい | `{ $gt: 5 }` | | `$gte` | 以上 | `{ $gte: 10 }` | | `$lt` | より小さい | `{ $lt: 20 }` | | `$lte` | 以下 | `{ $lte: 15 }` | ## 戻り値 ## 例 ```typescript import { Workflow, Step } from "@mastra/core"; import { z } from "zod"; // Create a step that increments a counter const incrementStep = new Step({ id: "increment", description: "Increments the counter by 1", outputSchema: z.object({ value: z.number(), }), execute: async ({ context }) => { // Get current value from previous execution or start at 0 const currentValue = context.getStepResult<{ value: number }>("increment")?.value || context.getStepResult<{ startValue: number }>("trigger")?.startValue || 0; // Increment the value const value = currentValue + 1; console.log(`Incrementing to ${value}`); return { value }; }, }); // Create a final step const finalStep = new Step({ id: "final", description: "Final step after loop completes", execute: async ({ context }) => { const finalValue = context.getStepResult<{ value: number }>( "increment", )?.value; console.log(`Loop completed with final value: ${finalValue}`); return { finalValue }; }, }); // Create the workflow const counterWorkflow = new Workflow({ name: "counter-workflow", triggerSchema: z.object({ startValue: z.number(), targetValue: z.number(), }), }); // Configure the workflow with an until loop counterWorkflow .step(incrementStep) .until(async ({ context }) => { const targetValue = context.triggerData.targetValue; const currentValue = context.getStepResult<{ value: number }>("increment")?.value ?? 0; return currentValue >= targetValue; }, incrementStep) .then(finalStep) .commit(); // Execute the workflow const run = counterWorkflow.createRun(); const result = await run.start({ triggerData: { startValue: 0, targetValue: 5 }, }); // Will increment from 0 to 5, then stop and execute finalStep ``` ## 関連 - [.while()](./while.mdx) - 条件が真の間ループする - [制御フローガイド](../../docs/workflows/control-flow.mdx) - [Workflow クラスリファレンス](./workflow.mdx) --- title: "リファレンス: Workflow.watch() | ワークフローの構築 | Mastra ドキュメント" description: ワークフロー内の `.watch()` メソッドのドキュメント。ワークフロー実行の監視を可能にします。 --- # Workflow.watch() [JA] Source: https://mastra.ai/ja/reference/workflows/watch `.watch()` メソッドは、ワークフローの実行を監視し、各ステップの進行状況をリアルタイムで更新します。 ## 使い方 ```typescript const run = myWorkflow.createRun(); // Add a watcher to monitor execution run.watch(event => { console.log('Step completed:', event.payload.currentStep.id); }); // Start the workflow const result = await run.start({ inputData: {...} }); ``` ## パラメーター void", description: "ステップが完了したときやワークフローの状態が変化したときに呼び出されるコールバック関数", isOptional: false, }, ]} /> ## 戻り値 void", description: "ワークフローの実行の監視を停止するために呼び出せる関数", }, ]} /> ## 関連 - [サスペンドと再開](../../docs/workflows/suspend-and-resume.mdx) - [人間が介在する例](../../examples/workflows/human-in-the-loop.mdx) - [スナップショットリファレンス](./snapshots.mdx) - [Workflow ウォッチガイド](../../docs/workflows/overview.mdx#watching-workflow-execution) --- title: "リファレンス: Workflow.while() | ワークフロー内のループ処理 | Mastra ドキュメント" description: "Mastra ワークフローにおける `.while()` メソッドのドキュメント。指定した条件が真である限り、ステップを繰り返します。" --- # Workflow.while() [JA] Source: https://mastra.ai/ja/reference/workflows/while `.while()` メソッドは、指定した条件が真である限り、ステップを繰り返します。これにより、条件が偽になるまで指定したステップを実行し続けるループが作成されます。 ## 使い方 ```typescript workflow.step(incrementStep).while(condition, incrementStep).then(finalStep); ``` ## パラメーター ## 条件タイプ ### 関数条件 真偽値を返す関数を使用できます: ```typescript workflow .step(incrementStep) .while(async ({ context }) => { const result = context.getStepResult<{ value: number }>("increment"); return (result?.value ?? 0) < 10; // valueが10未満の間は継続 }, incrementStep) .then(finalStep); ``` ### 参照条件 比較演算子を使った参照ベースの条件を使用できます: ```typescript workflow .step(incrementStep) .while( { ref: { step: incrementStep, path: "value" }, query: { $lt: 10 }, // valueが10未満の間は継続 }, incrementStep, ) .then(finalStep); ``` ## 比較演算子 参照ベースの条件を使用する場合、次の比較演算子を使用できます。 | 演算子 | 説明 | 例 | | ------ | ---------- | -------------- | | `$eq` | 等しい | `{ $eq: 10 }` | | `$ne` | 等しくない | `{ $ne: 0 }` | | `$gt` | より大きい | `{ $gt: 5 }` | | `$gte` | 以上 | `{ $gte: 10 }` | | `$lt` | より小さい | `{ $lt: 20 }` | | `$lte` | 以下 | `{ $lte: 15 }` | ## 戻り値 ## 例 ```typescript import { Workflow, Step } from "@mastra/core"; import { z } from "zod"; // Create a step that increments a counter const incrementStep = new Step({ id: "increment", description: "Increments the counter by 1", outputSchema: z.object({ value: z.number(), }), execute: async ({ context }) => { // Get current value from previous execution or start at 0 const currentValue = context.getStepResult<{ value: number }>("increment")?.value || context.getStepResult<{ startValue: number }>("trigger")?.startValue || 0; // Increment the value const value = currentValue + 1; console.log(`Incrementing to ${value}`); return { value }; }, }); // Create a final step const finalStep = new Step({ id: "final", description: "Final step after loop completes", execute: async ({ context }) => { const finalValue = context.getStepResult<{ value: number }>( "increment", )?.value; console.log(`Loop completed with final value: ${finalValue}`); return { finalValue }; }, }); // Create the workflow const counterWorkflow = new Workflow({ name: "counter-workflow", triggerSchema: z.object({ startValue: z.number(), targetValue: z.number(), }), }); // Configure the workflow with a while loop counterWorkflow .step(incrementStep) .while(async ({ context }) => { const targetValue = context.triggerData.targetValue; const currentValue = context.getStepResult<{ value: number }>("increment")?.value ?? 0; return currentValue < targetValue; }, incrementStep) .then(finalStep) .commit(); // Execute the workflow const run = counterWorkflow.createRun(); const result = await run.start({ triggerData: { startValue: 0, targetValue: 5 }, }); // Will increment from 0 to 4, then stop and execute finalStep ``` ## 関連 - [.until()](./until.mdx) - 条件が真になるまでループする - [制御フローガイド](../../docs/workflows/control-flow.mdx) - [Workflow クラスリファレンス](./workflow.mdx) --- title: "リファレンス: Workflow クラス | ワークフローの構築 | Mastra ドキュメント" description: Mastra の Workflow クラスのドキュメント。条件分岐やデータ検証を伴う複雑な操作シーケンスのためのステートマシンを作成できます。 --- # Workflowクラス [JA] Source: https://mastra.ai/ja/reference/workflows/workflow Workflowクラスは、条件分岐やデータ検証を含む複雑な操作のシーケンスのためのステートマシンを作成できるようにします。 ## 使用方法 ```typescript const myWorkflow = createWorkflow({ id: "my-workflow", inputSchema: z.object({ startValue: z.string(), }), outputSchema: z.object({ result: z.string(), }), steps: [step1, step2, step3], // Declare steps used in this workflow }) .then(step1) .then(step2) .then(step3) .commit(); const mastra = new Mastra({ workflows: { myWorkflow, }, }); const run = mastra.getWorkflow("myWorkflow").createRun(); ``` ## APIリファレンス ### コンストラクタ ", description: "ワークフローの入力構造を定義するZodスキーマ", }, { name: "outputSchema", type: "z.ZodType", description: "ワークフローの出力構造を定義するZodスキーマ", }, { name: "steps", type: "Step[]", description: "ワークフローに含めるステップの配列", }, ]} /> ### コアメソッド #### `then()` ワークフローにステップを順番に追加します。チェーン用にワークフローインスタンスを返します。 #### `parallel()` 複数のステップを同時に実行します。ステップの配列を受け取り、ワークフローインスタンスを返します。 #### `branch()` 条件分岐ロジックを作成します。条件関数と条件が満たされたときに実行するステップを含むタプルの配列を受け取ります。 #### `dowhile()` 条件が真である間、ステップを繰り返し実行するループを作成します。各実行後に条件がチェックされます。 #### `dountil()` 条件が真になるまで、ステップを繰り返し実行するループを作成します。各実行後に条件がチェックされます。 #### `foreach()` 配列を反復処理し、各要素に対してステップを実行します。オプションで並列実行の設定も可能です。 #### `map()` マッピング設定オブジェクトまたはマッピング関数を使って、ステップ間でデータをマッピングします。ステップ間のデータ変換に便利です。 #### `commit()` ワークフローの設定を検証し、確定します。すべてのステップを追加した後に呼び出す必要があります。 #### `createRun()` 新しいワークフロー実行インスタンスを作成し、特定の入力データでワークフローを実行できるようにします。オプションで実行IDを指定できます。 #### `execute()` 指定した入力データでワークフローを実行します。ワークフローの一時停止や再開を処理し、実行中にイベントを発行します。 ## ワークフローのステータス ワークフローのステータスは、現在の実行状態を示します。考えられる値は以下の通りです。 ## ステップ間でのコンテキストの受け渡し ステップは、コンテキストオブジェクトを通じてワークフロー内の前のステップからのデータにアクセスできます。各ステップは、実行されたすべての前のステップから蓄積されたコンテキストを受け取ります。 ```typescript workflow .then({ id: "getData", execute: async ({ inputData }) => { return { data: { id: "123", value: "example" }, }; }, }) .then({ id: "processData", execute: async ({ inputData }) => { // Access data from previous step through context.steps const previousData = inputData.data; // Process previousData.id and previousData.value }, }); ``` ## 関連 - [フロー制御](../../docs/workflows/flow-control.mdx) --- title: "ショーケース" description: "Mastraで構築されたこれらのアプリケーションをご覧ください" --- [JA] Source: https://mastra.ai/ja/showcase import { ShowcaseGrid } from "@/components/showcase-grid";