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.
This commit is contained in:
Sergio Serrano 2025-04-03 12:59:05 -03:00 committed by GitHub
parent bc4a1894f3
commit e604e8bde3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,11 +1,11 @@
import { Arcade } from "@arcadeai/arcadejs"; import { Arcade } from "@arcadeai/arcadejs"
import { PermissionDeniedError } from "@arcadeai/arcadejs"; import { PermissionDeniedError } from "@arcadeai/arcadejs"
import { ToolExecutionError } from "ai"; import { ToolExecutionError } from "ai"
import { jsonSchema } from "ai"; import { jsonSchema } from "ai"
const arcadeClient = new Arcade({ const arcadeClient = new Arcade({
baseURL: "http://localhost:9099", baseURL: "http://localhost:9099",
}); })
/** /**
* Retrieves and formats tools from Arcade.dev to the format required by the AI SDK. * Retrieves and formats tools from Arcade.dev to the format required by the AI SDK.
@ -14,35 +14,26 @@ const arcadeClient = new Arcade({
* @param {string} options.user_id - The user ID from your application (e.g. an email, UUID, etc.) * @param {string} options.user_id - The user ID from your application (e.g. an email, UUID, etc.)
*/ */
export const getArcadeTools = async ({ toolkit, user_id }) => { export const getArcadeTools = async ({ toolkit, user_id }) => {
const tools = await arcadeClient.tools.list({ const tools = await arcadeClient.tools.formatted.list({
...(toolkit && { toolkit }), ...(toolkit && { toolkit }),
}); format: "openai",
})
const toolsSet = {}; return tools.items.reduce((acc, item) => {
if (!item.function.name) return acc
for (const item of tools.items) { acc[item.function.name] = {
if (!item.name) continue; parameters: jsonSchema(item.function.parameters),
description: item.description,
const toolName = `${item.toolkit.name}.${item.name}`; execute: async (input) =>
await arcadeClient.tools.execute({
const formattedTool = await arcadeClient.tools.formatted.get(toolName, { tool_name: item.function.name,
format: "openai", input,
}); user_id,
}),
toolsSet[formattedTool.function.name] = { }
parameters: jsonSchema(formattedTool.function.parameters), return acc
description: item.description, }, {})
execute: async (input) => }
await arcadeClient.tools.execute({
tool_name: toolName,
input,
user_id,
}),
};
}
return toolsSet;
};
/** /**
* Determines if the error indicates that user authorization is needed for the tool * Determines if the error indicates that user authorization is needed for the tool
@ -50,11 +41,8 @@ export const getArcadeTools = async ({ toolkit, user_id }) => {
* @returns {boolean} True if the error indicates authorization is required * @returns {boolean} True if the error indicates authorization is required
*/ */
export const isAuthorizationRequiredError = (error) => { export const isAuthorizationRequiredError = (error) => {
return ( return error instanceof ToolExecutionError && error.cause instanceof PermissionDeniedError
error instanceof ToolExecutionError && }
error.cause instanceof PermissionDeniedError
);
};
/** /**
* Gets the authorization response for a tool that requires authentication * Gets the authorization response for a tool that requires authentication
@ -63,11 +51,11 @@ export const isAuthorizationRequiredError = (error) => {
* @returns {Promise<{url: string}>} The authorization response * @returns {Promise<{url: string}>} The authorization response
*/ */
export const getAuthorizationResponse = async (toolName, user_id) => { export const getAuthorizationResponse = async (toolName, user_id) => {
return await arcadeClient.tools.authorize({ return await arcadeClient.tools.authorize({
tool_name: toolName, tool_name: toolName,
user_id, user_id,
}); })
}; }
/** /**
* Handles authorization errors by returning the authorization URL if needed, otherwise rethrows the error * Handles authorization errors by returning the authorization URL if needed, otherwise rethrows the error
@ -76,10 +64,10 @@ export const getAuthorizationResponse = async (toolName, user_id) => {
* @returns {Promise<string>} The authorization URL if needed, otherwise the error is rethrown * @returns {Promise<string>} The authorization URL if needed, otherwise the error is rethrown
*/ */
export const handleAuthorizationError = async (error, user_id) => { export const handleAuthorizationError = async (error, user_id) => {
if (isAuthorizationRequiredError(error)) { if (isAuthorizationRequiredError(error)) {
const response = await getAuthorizationResponse(error.toolName, user_id); const response = await getAuthorizationResponse(error.toolName, user_id)
return response.url; return response.url
} }
throw error; throw error
}; }