diff --git a/app/en/get-started/agent-frameworks/openai-agents/setup-typescript/page.mdx b/app/en/get-started/agent-frameworks/openai-agents/setup-typescript/page.mdx index 03e4d2978..18bd99df4 100644 --- a/app/en/get-started/agent-frameworks/openai-agents/setup-typescript/page.mdx +++ b/app/en/get-started/agent-frameworks/openai-agents/setup-typescript/page.mdx @@ -7,6 +7,8 @@ import { Steps, Tabs, Callout } from "nextra/components"; # Setup Arcade with OpenAI Agents (TypeScript) +Learn to build an agent with Arcade tools using the OpenAI Agents SDK for JavaScript/TypeScript. + The [OpenAI Agents SDK for JavaScript](https://openai.github.io/openai-agents-js/) provides a framework for building AI agents in TypeScript and JavaScript. Arcade's `@arcadeai/arcadejs` library converts Arcade tools to the format OpenAI Agents expects. @@ -174,7 +176,7 @@ async function main() { output: process.stdout, }); - console.log("Hello! I'm your helpful OpenAI Agent! I use Arcade Tools to access your Gmail and Slack. Try asking me to summarize your recent emails or DM you on Slack!\n\nType 'exit' to quit.\n"); + console.log("Hello I'm your helpful OpenAI Agent I use Arcade tools to access your Gmail and Slack. Try asking me to summarize your recent emails or DM you on Slack!\n\nType 'exit' to quit.\n"); // Track conversation history for multi-turn context let conversationHistory: any[] = []; @@ -215,7 +217,7 @@ The `executeOrAuthorizeZodTool` factory automatically handles authorization. Whe Please authorize access: https://accounts.google.com/... ``` -After the user visits the URL and authorizes, running the same request again will succeed. +After you visit the URL and authorize, running the same request again will succeed. For more control over authorization flow, you can create a custom execute factory: @@ -360,7 +362,7 @@ async function main() { output: process.stdout, }); - console.log("Hello! I'm your helpful OpenAI Agent! I use Arcade Tools to access your Gmail and Slack. Try asking me to summarize your recent emails or DM you on Slack!\n\nType 'exit' to quit.\n"); + console.log("Hello I'm your helpful OpenAI Agent I use Arcade tools to access your Gmail and Slack. Try asking me to summarize your recent emails or DM you on Slack!\n\nType 'exit' to quit.\n"); // Track conversation history for multi-turn context let conversationHistory: any[] = []; @@ -396,4 +398,4 @@ main().catch(console.error); - Add more tools by modifying `MCP_SERVERS` and `INDIVIDUAL_TOOLS` - Build a web interface using frameworks like Next.js or Express - See the [Vercel AI SDK tutorial](/get-started/agent-frameworks/vercelai) or [TanStack AI tutorial](/get-started/agent-frameworks/tanstack-ai) for complete web chatbot examples -- Explore [creating custom tools](/guides/create-tools/tool-basics/build-mcp-server) with the Arcade Tool SDK +- Explore [creating custom tools](/guides/create-tools/tool-basics/build-mcp-server) with the Arcade Tool SDK \ No newline at end of file diff --git a/app/en/get-started/agent-frameworks/tanstack-ai/page.mdx b/app/en/get-started/agent-frameworks/tanstack-ai/page.mdx index d21776db2..dce3d0f0f 100644 --- a/app/en/get-started/agent-frameworks/tanstack-ai/page.mdx +++ b/app/en/get-started/agent-frameworks/tanstack-ai/page.mdx @@ -7,9 +7,11 @@ import { Steps, Tabs, Callout } from "nextra/components"; # Build an AI Chatbot with Arcade and TanStack AI +You'll build a browser-based chatbot using [TanStack Start](https://tanstack.com/start) that uses Arcade's Gmail and Slack tools. + [TanStack AI](https://tanstack.com/ai/latest/docs) is a type-safe, provider-agnostic SDK for building AI applications in JavaScript and TypeScript. It provides streaming responses, tool calling, and framework-agnostic primitives for React, Solid, and vanilla JavaScript. Provider adapters let you switch between OpenAI, Anthropic, Google Gemini, and Ollama without rewriting your code. -In this guide, you'll build a browser-based chatbot using [TanStack Start](https://tanstack.com/start) 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. +Your users can read emails, send messages, and interact with Slack through a conversational interface with built-in authentication. @@ -360,7 +362,7 @@ export const Route = createFileRoute("/api/chat")({ - **Handling large tool outputs:** Tools like `Gmail.ListEmails` can return 200KB+ of email content. When the agent passes this data back to the LLM in the agentic loop, it may exceed token limits. The code above includes `truncateDeep` to limit all strings to 300 characters and `prepareMessages` to keep only the last 10 messages. + **Handling large tool outputs:** tools like `Gmail.ListEmails` can return 200KB+ of email content. When the agent passes this data back to the LLM in the agentic loop, it may exceed token limits. The code above includes `truncateDeep` to limit all strings to 300 characters and `prepareMessages` to keep only the last 10 messages. ### Create the auth status server function @@ -390,7 +392,7 @@ export const checkAuthStatus = createServerFn({ method: "POST" }) }); ``` -This server function allows the frontend to poll for authorization completion, creating a seamless experience where the chatbot automatically retries after the user authorizes. +This server function allows the frontend to poll for authorization completion, creating a seamless experience where the chatbot automatically retries after you authorize. ### Build the chat route @@ -635,7 +637,7 @@ export const Route = createFileRoute("/")({ }); ``` -The `AuthPendingUI` component polls for OAuth completion using the `checkAuthStatus` server function and calls `onAuthComplete` when the user finishes authorizing, triggering a reload to retry the tool call. +The `AuthPendingUI` component polls for OAuth completion using the `checkAuthStatus` server function and calls `onAuthComplete` when you finish authorizing, triggering a reload to retry the tool call. ### Run the chatbot @@ -690,7 +692,7 @@ On first use, you'll see an authorization button. Click it to connect your Gmail - **Full TanStack stack**: TanStack Start + TanStack Router + TanStack AI work together seamlessly with server routes and file-based routing. - **Server routes keep secrets safe**: The `server.handlers` property ensures your API keys never reach the client while handling streaming responses. - **Authorization is automatic**: Check `authorization_required` in tool results and display the authorization UI. Poll for completion to retry automatically. -- **Truncate large outputs**: Tools like Gmail can return 200KB+ of data. Wrap tool execution with truncation to prevent token overflow in the agentic loop. +- **Truncate large outputs**: tools like Gmail can return 200KB+ of data. Wrap tool execution with truncation to prevent token overflow in the agentic loop. - **Provider flexibility**: Switch between OpenAI, Anthropic, Gemini, or Ollama by changing the adapter. No code rewrites needed. ## Next steps @@ -911,200 +913,4 @@ export const checkAuthStatus = createServerFn({ method: "POST" }) **src/routes/index.tsx** (full file) ```tsx filename="src/routes/index.tsx" -import { createFileRoute } from "@tanstack/react-router"; -import { useChat, fetchServerSentEvents } from "@tanstack/ai-react"; -import { useState, useRef, useEffect } from "react"; -import ReactMarkdown from "react-markdown"; -import { checkAuthStatus } from "../functions/auth"; - -function AuthPendingUI({ - authUrl, - toolName, - onAuthComplete, -}: { - authUrl: string; - toolName: string; - onAuthComplete: () => void; -}) { - const [status, setStatus] = useState<"initial" | "waiting" | "completed">( - "initial" - ); - const pollingRef = useRef(null); - const hasCompletedRef = useRef(false); - const onAuthCompleteRef = useRef(onAuthComplete); - - useEffect(() => { - onAuthCompleteRef.current = onAuthComplete; - }, [onAuthComplete]); - - useEffect(() => { - if (status !== "waiting" || !toolName || hasCompletedRef.current) return; - - const pollStatus = async () => { - try { - const result = await checkAuthStatus({ data: { toolName } }); - - if (result.status === "completed" && !hasCompletedRef.current) { - hasCompletedRef.current = true; - if (pollingRef.current) clearInterval(pollingRef.current); - setStatus("completed"); - setTimeout(() => onAuthCompleteRef.current(), 1500); - } - } catch (error) { - console.error("Polling error:", error); - } - }; - - pollingRef.current = setInterval(pollStatus, 2000); - return () => { - if (pollingRef.current) clearInterval(pollingRef.current); - }; - }, [status, toolName]); - - const displayName = toolName.split("_")[0] || toolName; - - const handleAuthClick = () => { - if (!authUrl) return; - window.open(authUrl, "_blank"); - setStatus("waiting"); - }; - - return ( -
- {status === "completed" ? ( -

- {displayName} authorized successfully -

- ) : !authUrl ? ( -

Authorization URL not available

- ) : ( -
- Authorize access to {displayName}? - -
- )} -
- ); -} - -function Chat() { - const [input, setInput] = useState(""); - const inputRef = useRef(null); - - const { messages, sendMessage, reload, isLoading } = useChat({ - connection: fetchServerSentEvents("/api/chat"), - }); - - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); - if (input.trim() && !isLoading) { - sendMessage(input); - setInput(""); - } - }; - - useEffect(() => { - if (!isLoading && inputRef.current) { - inputRef.current.focus(); - } - }, [isLoading]); - - return ( -
-

Arcade + TanStack AI Chat

- -
- {messages.map((message) => { - // Extract text content and tool results from parts - const textParts = (message.parts || []).filter( - (p: { type: string }) => p.type === "text" - ); - const toolResultParts = (message.parts || []).filter( - (p: { type: string }) => p.type === "tool-result" - ); - const textContent = textParts - .map((p: { content?: string }) => p.content || "") - .join(""); - const authRequired = toolResultParts.find( - (result: { output?: { authorization_required?: boolean } }) => - result.output?.authorization_required - ); - - return ( -
-
- {message.role === "assistant" ? "Assistant" : "You"} -
- - {authRequired ? ( - reload()} - /> - ) : ( -
{textContent}
- )} -
- ); - })} - - {isLoading && ( -
-
- Assistant -
-
Thinking...
-
- )} -
- -
- setInput(e.target.value)} - placeholder="Ask about your emails or Slack..." - disabled={isLoading} - className="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" - /> - -
-
- ); -} - -export const Route = createFileRoute("/")({ - component: Chat, -}); -``` - - +import { createFileRoute } from "@tanstack \ 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 9a231fb6b..eecb5998f 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 retrieve tool definitions in a specific model provider's format. The Arcade Client provides methods for getting a single tool's definition and for listing definitions of multiple tools formatted for your chosen model provider. This is useful when you need to integrate tools with different AI frameworks or when you want to examine how tools appear to specific model providers. ## 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. +To do this, 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. +To do this, 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, Mastra AI, and TanStack 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, Mastra AI, and TanStack AI. Using Zod with Arcade provides: 1. **Type Safety**: Runtime validation of tool inputs and outputs against their defined types 2. **TypeScript Integration**: Provides TypeScript support with automatic type inference 3. **Framework Compatibility**: Direct integration with LangChain, Vercel AI SDK, Mastra AI, and TanStack 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 streamlines 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. @@ -294,4 +296,4 @@ if ("authorization_required" in result && result.authorization_required) { } else { console.log(result); } -``` +``` \ No newline at end of file