diff --git a/app/en/get-started/agent-frameworks/langchain/use-arcade-with-langchain-ts/page.mdx b/app/en/get-started/agent-frameworks/langchain/use-arcade-with-langchain-ts/page.mdx index 7f7c0944f..778ce8b36 100644 --- a/app/en/get-started/agent-frameworks/langchain/use-arcade-with-langchain-ts/page.mdx +++ b/app/en/get-started/agent-frameworks/langchain/use-arcade-with-langchain-ts/page.mdx @@ -7,7 +7,9 @@ import { Steps, Tabs, Callout } from "nextra/components"; # Setup Arcade with LangChain -Learn how to integrate Arcade tools using LangChain primitives to build AI agents. +Integrate Arcade tools using LangChain primitives to build AI agents. + +This page explains how to use Arcade tools within the LangChain agentic framework. You'll learn to transform Arcade tool definitions into LangChain-compatible tools, manage authorization flows, and create agents that can execute external APIs through Arcade's MCP servers. This integration is useful when you want to leverage LangChain's abstractions while accessing Arcade's extensive tool ecosystem. LangChain is a popular agentic framework that abstracts a lot of the complexity of building AI agents. LangGraph, a lower level orchestration framework, builds it and offers more control over the inner flow of the agent. @@ -41,7 +43,7 @@ LangChain provides multiple abstractions for building AI agents, and it's useful - [_Agents_](https://docs.langchain.com/oss/javascript/langchain/agents): Most agentic frameworks, including LangChain, provide an abstraction for a ReAct agent. - [_Interrupts_](https://docs.langchain.com/oss/javascript/langgraph/interrupts): Interrupts in LangChain are a way to control the flow of the agentic loop when something needs to occur outside of the normal ReAct flow. For example, if a tool requires authorization, you can interrupt the agent and ask the user to authorize the tool before continuing. -- [_Checkpointers_](https://docs.langchain.com/oss/javascript/langgraph/persistence): Checkpointers are how LangChain implements persistence. A checkpointer stores the agent's state in a "checkpoint" that you can resume later. Those checkpoints are saved to a _thread_, which you can access after the agent's execution, making it simple for long-running agents and for handling interruptions and more sophisticated flows such as branching, time travel, and more. +- [_Checkpointers_](https://docs.langchain.com/oss/javascript/langgraph/persistence): Checkpointers are how LangChain implements persistence. A checkpointer stores the agent's state in a "checkpoint" that you can resume later. The system saves those checkpoints to a _thread_, which you can access after the agent's execution, making it straightforward for long-running agents and for handling interruptions and more sophisticated flows such as branching, time travel, and more. ## Integrate Arcade tools into a LangChain agent @@ -87,7 +89,7 @@ import chalk from "chalk"; import readline from "node:readline/promises"; ``` -This is a number of imports, examine them: +This represents several imports, examine them: - Arcade imports: - `Arcade`: This is the Arcade client, used to interact with the Arcade API. @@ -100,14 +102,14 @@ This is a number of imports, examine them: - `tool`: Turns an Arcade tool definition into a LangChain tool. - `interrupt`: Interrupts the ReAct flow and asks the user for input. - `Command`: Communicates the user's decisions to the agent's interrupts. - - `MemorySaver`: Stores the agent's state, and is required for checkpointing and interrupts. + - `MemorySaver`: Stores the agent's state, and you need it for checkpointing and interrupts. - Other imports: - `chalk`: This is a library to colorize the console output. - `readline`: This is a library to read input from the console. ### Configure the agent -These variables are used in the rest of the code to customize the agent and manage the tools. Feel free to configure them to your liking. +These variables serve to customize the agent and manage the tools throughout the rest of the code. Feel free to configure them to your liking. ```ts filename="main.ts" // configure your own values to customize your agent @@ -456,7 +458,7 @@ You should see the agent responding to your prompts like any model, as well as h - Context isolation: By handling the authorization flow outside of the agent's context, you remove the risk of the LLM replacing the authorization URL or leaking it, and you keep the context free from any authorization-related traces, which reduces the risk of hallucinations. - You can leverage the interrupts mechanism to handle human intervention in the agent's flow, useful for authorization flows, policy enforcement, or anything else that requires input from the user. -## Next Steps +## Next steps 1. Try adding additional tools to the agent or modifying the tools in the catalog for a different use case by modifying the `MCPServers` and `individualTools` variables. 2. Try refactoring the `handleAuthInterrupt` function to handle more complex flows, such as human-in-the-loop. @@ -715,7 +717,7 @@ rl.pause(); const interrupts = await streamAgent(agent, agentInput, config); if (interrupts.length === 0) { - break; // No more interrupts, we're done + break; // No more interrupts, you're done } // Handle all interrupts diff --git a/app/en/get-started/agent-frameworks/mastra/page.mdx b/app/en/get-started/agent-frameworks/mastra/page.mdx index f094e32d0..6d71b7d74 100644 --- a/app/en/get-started/agent-frameworks/mastra/page.mdx +++ b/app/en/get-started/agent-frameworks/mastra/page.mdx @@ -5,9 +5,11 @@ description: "Create a TypeScript agent that uses Arcade tools to access Gmail a import { Steps, Tabs, Callout } from "nextra/components"; +This guide walks you through building an AI agent and workflow that integrates Gmail and Slack using Arcade's MCP tools in a conversational interface. + [Mastra](https://mastra.ai/docs) is an open-source, TypeScript agent framework for building AI applications. It provides agents with memory, tool calling, workflows, and RAG capabilities. This guide uses **Mastra v1.x**. -In this guide, you'll build an agent lets you read emails, send messages, and interact with Gmail and Slack using Arcade's MCP tools in a conversational interface with built-in authentication. You will also build a workflow that summarizes emails and sends them to Slack. +You'll build an agent that lets you read emails, send messages, and interact with Gmail and Slack using Arcade's MCP tools in a conversational interface with built-in authentication. You will also build a workflow that summarizes emails and sends them to Slack. @@ -29,7 +31,7 @@ A Mastra agent and workflow that integrates Arcade tools for Gmail and Slack. - How to retrieve Arcade tools and convert them to Mastra format - How to create an agent with tool calling capabilities - How to create a workflow with multiple steps -- How to handle Arcade's authorization flow in your application +- How to handle Arcade's user authorization flow in your application - How to test your agent and workflow with Mastra Studio @@ -56,7 +58,7 @@ Before diving into the code, here are the key Mastra concepts you'll use: npx create-mastra@latest arcade-agent ``` -Select your preferred model provider when prompted (we recommend OpenAI). Enter your API key when asked. +Select your preferred model provider when prompted (recommend OpenAI). Enter your API key when asked. Then navigate to the project directory and install the Arcade client: @@ -230,7 +232,7 @@ You might select your tools individually for a few reasons: * **Cost** Each tool's schema consumes tokens. Loading all Gmail tools (~20 tools) uses more tokens than loading just the 3 you need. This matters for rate limits and cost. - Browse the [complete MCP server catalog](/resources/integrations) to see available servers and their tools. + Browse the [complete MCP server catalog](/resources/integrations) to see available MCP servers and their tools. ##### Arcade SDK functions @@ -238,11 +240,11 @@ You might select your tools individually for a few reasons: - `arcade.tools.list({ toolkit })`: Fetches all tools from an MCP server - `arcade.tools.get(toolName)`: Fetches a single tool by its full name - `toZodToolSet`: Converts Arcade tools to [Zod](https://zod.dev) schemas that Mastra requires -- `executeOrAuthorizeZodTool`: Handles tool execution and returns authorization URLs when needed +- `executeOrAuthorizeZodTool`: Handles tool execution and returns user authorization URLs when required ### Output handling -- `truncateDeep`: Recursively limits all strings to 300 characters to prevent token overflow when tool results are passed back to the LLM +- `truncateDeep`: Recursively limits all strings to 300 characters to prevent token overflow when tool results pass back to the LLM ### Create the agent @@ -292,7 +294,7 @@ For Slack: After completing any action, always confirm what you did with specific details. -IMPORTANT: When a tool returns an authorization response with a URL, tell the user to visit that URL to grant access. After they authorize, they can retry their request.`, +IMPORTANT: When a tool returns a user authorization response with a URL, tell the user to visit that URL to grant access. After they authorize, they can retry their request.`, model: openai("gpt-4o"), tools: arcadeTools, memory, @@ -362,7 +364,7 @@ Open [http://localhost:4111](http://localhost:4111) to access Mastra Studio. Sel - "Send a Slack DM to myself saying hello" - "What's my Gmail address?" -On first use, the agent will return an authorization URL. Visit the URL to connect your Gmail or Slack account, then retry your request. Arcade remembers this authorization for future requests. +On first use, the agent will return a user authorization URL. Visit the URL to connect your Gmail or Slack account, then retry your request. Arcade remembers this user authorization for future requests. @@ -379,7 +381,7 @@ This workflow does the following: This also demonstrates how workflows: * handle **large data** the full email content stays internal to the workflow, and only the compact summary gets sent to Slack. -* handle **authorization errors** +* handle **user authorization errors** * **pass auth URLs** through multiple workflow steps @@ -432,7 +434,7 @@ const fetchEmails = createStep({ return { emails, userId }; } catch (error: any) { - // Handle authorization required error + // Handle user authorization requirement if (error.status === 403 || error.message?.includes("authorization")) { const authResponse = await arcade.auth.start({ user_id: userId, @@ -512,11 +514,11 @@ const sendToSlack = createStep({ execute: async ({ inputData }) => { const { summary, userId, authRequired, authUrl } = inputData!; - // Return auth URL if authorization is needed + // Return auth URL if user authorization takes place if (authRequired) { return { success: false, - message: `Authorization required. Please visit this URL to grant access: ${authUrl}`, + message: `User authorization required. Please visit this URL to grant access: ${authUrl}`, authUrl, }; } @@ -545,7 +547,7 @@ const sendToSlack = createStep({ return { success: true, message: "Digest sent as DM" }; } catch (error: any) { - // Handle Slack authorization required + // Handle Slack user authorization requirement if (error.status === 403 || error.message?.includes("authorization")) { const slackAuth = await arcade.auth.start({ user_id: userId, @@ -554,7 +556,7 @@ const sendToSlack = createStep({ }); return { success: false, - message: `Slack authorization required. Please visit: ${slackAuth.url}`, + message: `Slack user authorization required. Please visit: ${slackAuth.url}`, authUrl: slackAuth.url, }; } @@ -608,7 +610,7 @@ export const mastra = new Mastra({ 1. Restart the dev server and open Mastra Studio. In the sidebar, open **Workflows**. Select **email-digest**. 2. In the right sidebar, select "run" to run the workflow. -3. If authorization is required, the workflow returns an auth URL. Visit the URL, complete authorization, then run the workflow again. +3. If user authorization takes place, the workflow returns an auth URL. Visit the URL, complete user authorization, then run the workflow again. 4. Check your Slack DMs for the digest. @@ -620,7 +622,7 @@ export const mastra = new Mastra({ - **Arcade tools work seamlessly with Mastra**: Use `toZodToolSet` to convert Arcade tools to the Zod schema format Mastra expects. - **Agent vs Workflow**: The agent handles open-ended requests ("help me with my emails"). The workflow handles repeatable processes ("every morning, summarize and send to Slack"). Use both together for powerful automation. - **Truncate large outputs**: Tools like Gmail can return 200KB+ of data. Wrap tool execution with truncation to prevent token overflow in the agentic loop. -- **Authorization is automatic**: The `executeOrAuthorizeZodTool` factory handles auth flows. When a tool needs authorization, it returns a URL for the user to visit. +- **User authorization is automatic**: The `executeOrAuthorizeZodTool` factory handles auth flows. When a tool needs user authorization, it returns a URL for the user to visit. - **Workflows need explicit auth handling**: Unlike agents, workflows don't have built-in auth handling. Catch 403 errors, call `arcade.auth.start()`, and pass the auth URL through your workflow steps. ## Next steps @@ -630,7 +632,7 @@ export const mastra = new Mastra({ - **Deploy to production**: Follow Mastra's [deployment guides](https://mastra.ai/docs/deployment/overview) to deploy your agent and workflows. - **Building a multi-user app?** This tutorial uses a single `ARCADE_USER_ID` for simplicity. For production apps where each user needs their own OAuth tokens, see [Secure auth for production](/guides/user-facing-agents/secure-auth-production) to learn how to dynamically pass user IDs and handle per-user authorization. + **Building a multi-user app?** This tutorial uses a single `ARCADE_USER_ID` for simplicity. For production apps where each user needs their own OAuth tokens, see [Secure auth for production](/guides/user-facing-agents/secure-auth-production) to learn how to dynamically pass user IDs and handle per-user user authorization. ## Complete code @@ -765,7 +767,7 @@ For Slack: After completing any action, always confirm what you did with specific details. -IMPORTANT: When a tool returns an authorization response with a URL, tell the user to visit that URL to grant access. After they authorize, they can retry their request.`, +IMPORTANT: When a tool returns a user authorization response with a URL, tell the user to visit that URL to grant access. After they authorize, they can retry their request.`, model: openai("gpt-4o"), tools: arcadeTools, memory, @@ -895,95 +897,4 @@ const summarizeEmails = createStep({ ).join("\n\n"); const response = await agent!.generate( - `Summarize these emails in 2-3 bullet points:\n\n${emailList}` - ); - - return { summary: response.text, userId }; - }, -}); - -const sendToSlack = createStep({ - id: "send-to-slack", - inputSchema: z.object({ - summary: z.string(), - userId: z.string(), - authRequired: z.boolean().optional(), - authUrl: z.string().optional(), - }), - outputSchema: z.object({ - success: z.boolean(), - message: z.string(), - authUrl: z.string().optional(), - }), - execute: async ({ inputData }) => { - const { summary, userId, authRequired, authUrl } = inputData!; - - if (authRequired) { - return { - success: false, - message: `Authorization required. Please visit this URL to grant access: ${authUrl}`, - authUrl, - }; - } - - const arcade = new Arcade(); - - try { - const whoAmI = await arcade.tools.execute({ - tool_name: "Slack_WhoAmI", - user_id: userId, - input: {}, - }); - - const slackUserId = (whoAmI as any)?.output?.value?.user_id; - - await arcade.tools.execute({ - tool_name: "Slack_SendMessage", - user_id: userId, - input: { - message: `📬 *Email Digest*\n\n${summary}`, - user_ids: [slackUserId], - }, - }); - - return { success: true, message: "Digest sent as DM" }; - } catch (error: any) { - if (error.status === 403 || error.message?.includes("authorization")) { - const slackAuth = await arcade.auth.start({ - user_id: userId, - provider: "slack", - scopes: ["chat:write", "users:read"], - }); - return { - success: false, - message: `Slack authorization required. Please visit: ${slackAuth.url}`, - authUrl: slackAuth.url, - }; - } - throw error; - } - }, -}); - -const emailDigestWorkflow = createWorkflow({ - id: "email-digest", - inputSchema: z.object({ - userId: z.string().default(defaultUserId), - maxEmails: z.number().default(5), - }), - outputSchema: z.object({ - success: z.boolean(), - message: z.string(), - authUrl: z.string().optional(), - }), -}) - .then(fetchEmails) - .then(summarizeEmails) - .then(sendToSlack); - -emailDigestWorkflow.commit(); - -export { emailDigestWorkflow }; -``` - - + `Summarize these emails in 2-3 \ No newline at end of file diff --git a/app/en/get-started/agent-frameworks/vercelai/page.mdx b/app/en/get-started/agent-frameworks/vercelai/page.mdx index e09c61307..aeeac993a 100644 --- a/app/en/get-started/agent-frameworks/vercelai/page.mdx +++ b/app/en/get-started/agent-frameworks/vercelai/page.mdx @@ -5,13 +5,11 @@ description: "Create a browser-based chatbot that uses Arcade tools to access Gm import { Steps, Tabs, Callout } from "nextra/components"; -{/* Editorial: Structure - Removed marketing language "straightforward" in opening paragraph; Voice and tone - Changed "Let's get started!" to more direct language; Structure - Modified intro to better follow 10/20/70 format */} - # Build an AI Chatbot with Arcade and Vercel AI SDK -The [Vercel AI SDK](https://sdk.vercel.ai/) is a TypeScript toolkit for building AI-powered applications. It provides streaming responses, framework-agnostic support for React, Next.js, Vue, and more, plus AI provider switching. This guide uses **Vercel AI SDK v6**. +This guide shows you how to build a browser-based chatbot that uses Arcade's Gmail and Slack tools. -In this guide, you'll build a browser-based chatbot that uses Arcade's Gmail and Slack tools. Your users can read emails, send messages, and interact with Slack through a conversational interface with built-in authentication. +The [Vercel AI SDK](https://sdk.vercel.ai/) is a TypeScript toolkit for building AI-powered applications. It provides streaming responses, framework-agnostic support for React, Next.js, Vue, and more, plus AI provider switching. This guide uses **Vercel AI SDK v6**. You'll create a conversational interface where users can read emails, send messages, and interact with Slack through built-in authentication. This is useful when you want to give users natural language access to their productivity tools without requiring them to learn specific commands or interfaces. @@ -888,77 +886,4 @@ export default function Chat() { const result = toolPart.output as Record; return result?.authorization_required; } - } - return false; - }); - - // Get text content from message parts - const textContent = message.parts - ?.filter((part) => part.type === "text") - .map((part) => part.text) - .join(""); - - // Skip empty messages without auth prompts - if (!textContent && !authPart && !(message.role === "assistant" && isLoading)) { - return null; - } - - return ( - - - {/* Show loader while assistant is thinking */} - {message.role === "assistant" && !textContent && !authPart && isLoading ? ( - - ) : authPart ? ( - // Show auth UI when Arcade needs authorization - (() => { - const toolPart = authPart as { toolName?: string; output?: unknown }; - const result = toolPart.output as Record; - const authResponse = result?.authorization_response as { url?: string }; - // In Vercel AI SDK v6, toolName is a property on the part, not derived from type - const toolName = toolPart.toolName || ""; - return ( - regenerate()} - /> - ); - })() - ) : ( - {textContent} - )} - - - ); - })} - - - - {/* PromptInput handles the form with auto-resize textarea */} -
- { - if (text.trim()) { - sendMessage({ text }); - } - }} - > - - -
{/* Spacer */} - - - -
-
- ); -} -``` - - - + } \ No newline at end of file diff --git a/app/en/guides/tool-calling/custom-apps/get-tool-definitions/page.mdx b/app/en/guides/tool-calling/custom-apps/get-tool-definitions/page.mdx index 27bb7cdfd..20f8ad763 100644 --- a/app/en/guides/tool-calling/custom-apps/get-tool-definitions/page.mdx +++ b/app/en/guides/tool-calling/custom-apps/get-tool-definitions/page.mdx @@ -8,13 +8,15 @@ import ToggleContent from "@/app/_components/toggle-content"; # Get Formatted Tool Definitions -When calling tools directly, it can be useful to get tool definitions in a specific model provider's format. The Arcade Client provides methods for getting a tool's definition and also for listing the definitions of multiple tools in a specific model provider's format. +Learn how to get tool definitions formatted for specific model providers using the Arcade Client. + +When calling tools directly, you can get tool definitions in a specific model provider's format. The Arcade Client provides methods for getting a tool's definition and also for listing the definitions of multiple tools in a specific model provider's format. This is useful when you need to integrate with different AI frameworks or when building custom applications that consume tool definitions in standardized formats. You'll use these methods when working with model providers like OpenAI or when you need type-safe tool definitions with Zod schemas. ## Get a single tool definition formatted for a model -It can be useful to get a tool's definition in a specific model provider's format. For example, you may want to get the `Github.SetStarred` tool's definition in OpenAI's format. +You can get a tool's definition in a specific model provider's format. For example, you may want to get the `Github.SetStarred` tool's definition in OpenAI's format. -To do this, you can use the `client.tools.formatted.get` method and specify the tool name and format. +Use the `client.tools.formatted.get` method and specify the tool name and format. @@ -78,11 +80,11 @@ console.log(githubStarRepo); -## Get all tool definitions in a MCP Server formatted for a model +## Get all tool definitions in an MCP server formatted for a model -It can be useful to list tool definitions for a MCP Server in a specific model provider's format. For example, you may want to get the definitions of tools in the `Github` MCP Server in OpenAI's format. +You can list tool definitions for an MCP server in a specific model provider's format. For example, you may want to get the definitions of tools in the `Github` MCP server in OpenAI's format. -To do this, you can use the `client.tools.formatted.list` method and specify the MCP Server and format. Since this method returns an iterator of pages, you can cast to a list to get all the tools. +Use the `client.tools.formatted.list` method and specify the MCP server and format. Since this method returns an iterator of pages, you can cast to a list to get all the tools. @@ -91,10 +93,10 @@ from arcadepy import Arcade client = Arcade() -# Get all tools in the Github MCP Server formatted for OpenAI +# Get all tools in the Github MCP server formatted for OpenAI github_tools = list(client.tools.formatted.list(format="openai", toolkit="github")) -# Print the number of tools in the Github MCP Server +# Print the number of tools in the Github MCP server print(len(github_tools)) ``` @@ -104,13 +106,13 @@ import Arcade from "@arcadeai/arcadejs"; const client = new Arcade(); -// Get all tools in the Github MCP Server formatted for OpenAI +// Get all tools in the Github MCP server formatted for OpenAI const githubTools = await client.tools.formatted.list({ format: "openai", toolkit: "github", }); -// Print the number of tools in the Github MCP Server +// Print the number of tools in the Github MCP server console.log(githubTools.total_count); ``` @@ -119,7 +121,7 @@ console.log(githubTools.total_count); ## Get all tool definitions formatted for a model -To get all tools formatted for OpenAI, you can use the `client.tools.formatted.list` method without specifying a MCP Server. +To get all tools formatted for OpenAI, use the `client.tools.formatted.list` method without specifying an MCP server. @@ -150,15 +152,15 @@ console.log(allTools.total_count); -## Get Zod Tool Definitions +## Get Zod tool definitions -[Zod](https://zod.dev) is a TypeScript-first schema validation library that helps you define and validate data structures. The [Arcade JS](https://github.com/ArcadeAI/arcade-js) client offers methods to convert Arcade tool definitions into Zod schemas, providing type safety and validation while enabling seamless integration with AI frameworks like LangChain, Vercel AI SDK, and Mastra AI. Using Zod with Arcade provides: +[Zod](https://zod.dev) is a TypeScript-first schema validation library that helps you define and validate data structures. The [Arcade JS](https://github.com/ArcadeAI/arcade-js) client offers methods to convert Arcade tool definitions into Zod schemas, providing type safety and validation while enabling integration with AI frameworks like LangChain, Vercel AI SDK, and Mastra AI. Using Zod with Arcade provides: 1. **Type Safety**: Runtime validation of tool inputs and outputs against their defined types -2. **TypeScript Integration**: Provides excellent TypeScript support with automatic type inference +2. **TypeScript Integration**: Provides outstanding TypeScript support with automatic type inference 3. **Framework Compatibility**: Direct integration with LangChain, Vercel AI SDK, and Mastra AI -### Convert to Zod Format +### Convert to Zod format Arcade offers three ways to convert your tools into Zod schemas, each for different use cases: @@ -224,7 +226,7 @@ const emails = await listEmailsTool.execute({ }); ``` -### Handle Authorization +### Handle authorization When working with tools that require user authorization (like Gmail, GitHub, Slack, etc.), Arcade provides two approaches to handle the authorization flow when using Zod-converted tools: #### Option 1: Manual handling @@ -265,7 +267,7 @@ try { Arcade offers a more convenient way to handle tool execution and initial authorization steps. When converting tools to Zod, you can add the `executeOrAuthorizeZodTool` helper to the `executeFactory`. With this helper, your code no longer needs to catch a `PermissionDeniedError` for tools requiring permissions (as shown in Option 1). Instead, if the user hasn't yet granted access, the `execute` method will return an `ToolAuthorizationResponse` object that contains the authorization URL. -This approach simplifies your code by: +This approach improves your code by: 1. Attempting to execute the tool. 2. If permissions are missing, it returns an object containing the authorization URL. This eliminates the need for both a `try...catch` block for `PermissionDeniedError` and a separate call (like `arcade.tools.authorize`) just to retrieve this URL. @@ -293,5 +295,4 @@ if ("authorization_required" in result && result.authorization_required) { ); } else { console.log(result); -} -``` +} \ No newline at end of file