arcade-mcp/examples/ai-sdk/arcade.js
Sergio Serrano e604e8bde3
Improve getArcadeTools utility function (#344)
It is unnecessary to call `arcadeClient.tools.list` first and then
`arcadeClient.tools.formatted.get` for each tool. We can simply use the
`arcadeClient.tools.formatted.list` function.
2025-04-03 12:59:05 -03:00

73 lines
2.6 KiB
JavaScript

import { Arcade } from "@arcadeai/arcadejs"
import { PermissionDeniedError } from "@arcadeai/arcadejs"
import { ToolExecutionError } from "ai"
import { jsonSchema } from "ai"
const arcadeClient = new Arcade({
baseURL: "http://localhost:9099",
})
/**
* Retrieves and formats tools from Arcade.dev to the format required by the AI SDK.
* @param {Object} options - The options object
* @param {string} [options.toolkit] - Optional toolkit name to filter tools (e.g. "google", "slack")
* @param {string} options.user_id - The user ID from your application (e.g. an email, UUID, etc.)
*/
export const getArcadeTools = async ({ toolkit, user_id }) => {
const tools = await arcadeClient.tools.formatted.list({
...(toolkit && { toolkit }),
format: "openai",
})
return tools.items.reduce((acc, item) => {
if (!item.function.name) return acc
acc[item.function.name] = {
parameters: jsonSchema(item.function.parameters),
description: item.description,
execute: async (input) =>
await arcadeClient.tools.execute({
tool_name: item.function.name,
input,
user_id,
}),
}
return acc
}, {})
}
/**
* Determines if the error indicates that user authorization is needed for the tool
* @param {Error} error - The error caught during tool execution
* @returns {boolean} True if the error indicates authorization is required
*/
export const isAuthorizationRequiredError = (error) => {
return error instanceof ToolExecutionError && error.cause instanceof PermissionDeniedError
}
/**
* Gets the authorization response for a tool that requires authentication
* @param {string} toolName - The name of the tool that needs authorization
* @param {string} user_id - The user ID from your application
* @returns {Promise<{url: string}>} The authorization response
*/
export const getAuthorizationResponse = async (toolName, user_id) => {
return await arcadeClient.tools.authorize({
tool_name: toolName,
user_id,
})
}
/**
* Handles authorization errors by returning the authorization URL if needed, otherwise rethrows the error
* @param {Error} error - The error to handle
* @param {string} user_id - The user ID from your application
* @returns {Promise<string>} The authorization URL if needed, otherwise the error is rethrown
*/
export const handleAuthorizationError = async (error, user_id) => {
if (isAuthorizationRequiredError(error)) {
const response = await getAuthorizationResponse(error.toolName, user_id)
return response.url
}
throw error
}