Skip to content

defineTool(options)

Creates a Tool from a plain options object. Use this for inline or one-off tools.

Signature

ts
function defineTool(options: {
  name: string;
  description: string;
  schema: SchemaFn | ZodType;   // fluent builder or a Zod schema
  handle: (input: Record<string, unknown>) => Promise<string> | string;
}): Tool

Parameters

ParameterTypeDescription
namestringUnique identifier for the tool (snake_case recommended)
descriptionstringTells the model when and how to use this tool
schemaSchemaFn | ZodTypeDefines the tool's input parameters
handlefunctionExecutes the tool and returns a string result

Example — fluent builder

ts
import { defineTool } from '@daedalus-ai-dev/ai-sdk';

const getExchangeRate = defineTool({
  name: 'get_exchange_rate',
  description: 'Get the current exchange rate between two currencies. Use for any currency conversion question.',
  schema: (s) => ({
    from: s.string().description('Source currency code, e.g. USD').required(),
    to:   s.string().description('Target currency code, e.g. EUR').required(),
  }),
  handle: async (input) => {
    const rate = await fetchExchangeRate(String(input.from), String(input.to));
    return `1 ${input.from} = ${rate} ${input.to}`;
  },
});

Example — Zod schema

Pass a Zod object schema directly. Fields are automatically required unless marked .optional().

ts
import { defineTool } from '@daedalus-ai-dev/ai-sdk';
import { z } from 'zod';

const InputSchema = z.object({
  from: z.string().describe('Source currency code, e.g. USD'),
  to:   z.string().describe('Target currency code, e.g. EUR'),
});

const getExchangeRate = defineTool({
  name: 'get_exchange_rate',
  description: 'Get the current exchange rate between two currencies.',
  schema: InputSchema,
  handle: async (input) => {
    const rate = await fetchExchangeRate(String(input.from), String(input.to));
    return `1 ${input.from} = ${rate} ${input.to}`;
  },
});

Zod setup

Zod support requires two peer dependencies:

sh
npm install zod zod-to-json-schema

Reuse existing types

When you already have a Zod schema for validation elsewhere, pass it directly to defineTool — no need to duplicate the schema in the fluent builder.

The Tool interface

For class-based tools, implement Tool directly:

ts
import type { Tool } from '@daedalus-ai-dev/ai-sdk';
import type { SchemaBuilder, PropertyBuilder } from '@daedalus-ai-dev/ai-sdk';

class DatabaseSearch implements Tool {
  constructor(private readonly connection: DbConnection) {}

  name() { return 'database_search'; }

  description() {
    return 'Search the database for records matching a query. Returns up to 10 results as JSON.';
  }

  schema(s: SchemaBuilder): Record<string, PropertyBuilder> {
    return {
      table:  s.enum(['users', 'orders', 'products']).required(),
      query:  s.string().description('Search term').required(),
      limit:  s.integer().min(1).max(10),
    };
  }

  async handle(input: Record<string, unknown>): Promise<string> {
    const results = await this.connection.search(
      String(input.table),
      String(input.query),
      Number(input.limit ?? 5),
    );
    return JSON.stringify(results, null, 2);
  }
}

Input types

handle receives Record<string, unknown>. Cast values explicitly:

ts
handle: (input) => {
  const name = String(input.name);       // string cast
  const age  = Number(input.age);        // number cast
  const tags = input.tags as string[];   // array cast

  // ...
}

WARNING

Always validate and cast input — the model may send unexpected values even if the schema constrains them.

Async tools

handle can return a Promise<string>:

ts
handle: async (input) => {
  const result = await fetch(`https://api.example.com/${input.id}`);
  const json = await result.json();
  return JSON.stringify(json);
},

Error handling

Throw an error to signal failure. The SDK catches it and sends it to the model as a tool error:

ts
handle: async (input) => {
  const id = String(input.id);
  const record = await db.find(id);

  if (!record) {
    throw new Error(`No record found with ID: ${id}`);
    // The model receives: "Tool error: No record found with ID: xyz"
    // and can decide how to respond to the user
  }

  return JSON.stringify(record);
},

Released under the MIT License.