import { type ClientTool } from "@outspeed/client";// params & context can be skipped here since this tool doesn't use themconst getTime: ClientTool<{}> = (params, context) => { return new Date().toLocaleTimeString();};
The return value from your function is sent directly to the AI model, which uses it to generate its response to the user.
Always return a value - even for action-based tools:
Data tools (weather, calculations): Return the actual data
Action tools (generate image, open browser): Return acknowledgment like “Image generated successfully” or “Browser tab opened”
On failure: Return error description like “Failed to generate image: rate limit error”
This tells the AI whether your tool succeeded or failed. See the implementation section for more details.
Here’s a more complex tool with typed parameters and context usage:
Copy
Ask AI
import { type ClientTool } from "@outspeed/client";const setTimer: ClientTool<{ time: number; prompt: string }> = ({ time, prompt }, context) => { setTimeout(() => { // show a toast if you want to // toast.info("Timer completed!"); // we let the model know that the timer is done so that it can respond to the user context.sendText( `🔔 TIMER ALERT: The timer you set ${time} seconds ago has finished.Timer prompt: "${prompt}"Completed at: ${new Date().toLocaleString()}This is an automated system notification. Please proceed with any actions related to this timer.`, ); }, time * 1000); // we set the timer and let the model know that the timer is set return "Timer set";};
The context parameter provides access to conversation methods like sendText() for sending messages back to the AI after your tool completes.
Always return meaningful values - the AI uses your return value to respond to the user:
Copy
Ask AI
import { type ClientTool } from "@outspeed/client";// ✅ Good: Return actual dataconst getWeather: ClientTool<{ city: string }> = ({ city }, context) => { return "72°F and sunny in San Francisco";};// ✅ Good: Return success confirmationconst sendEmail: ClientTool<{ to: string; subject: string }> = ({ to, subject }, context) => { // ... send email logic return `Email sent to ${to}`;};// ✅ Good: Return error detailsconst uploadFile: ClientTool<{ filename: string }> = ({ filename }, context) => { try { // ... upload logic return "File uploaded successfully"; } catch (error) { return `Upload failed: ${error.message}`; }};// ❌ Bad: Don't return undefined/nullconst badTool: ClientTool<{}> = (params, context) => { // The AI gets nothing to work with return null;};
Handle errors gracefully:
Copy
Ask AI
const robustTool: ClientTool<{ param: string }> = ({ param }, context) => { try { if (!param?.trim()) { return "Parameter is required"; } const result = performOperation(param); // notice that we're returning something that model can use to respond to the user return result || "Operation completed but no data returned"; } catch (error) { return `Error: ${error.message}`; // for the model to understand the error }};
Use async/await for API calls:
Copy
Ask AI
const fetchData: ClientTool<{ query: string }> = async ({ query }, context) => { try { const response = await fetch(`/api/search?q=${query}`); const data = await response.json(); return `Found ${data.results.length} results for "${query}"`; } catch (error) { return "Search service unavailable"; // again, for the model to understand what went wrong }};