Silgi
Integrations

AI SDK

Turn Silgi procedures into AI tools — LLMs call your API through function calling.

The Vercel AI SDK lets you connect LLMs to tools — functions the model can call when it needs data or wants to take actions. Silgi can automatically convert your procedures into AI tools, extracting JSON Schema from your Zod input schemas.

This means your existing API becomes callable by AI models with zero extra code.

Prerequisites

You need a Silgi router and the AI SDK:

npm install ai @ai-sdk/openai

(Or any other AI SDK provider — Anthropic, Google, etc.)

Quick start

Convert your router to tools

import {  } from 'silgi/ai'
import {  } from './router'

const  = ()

This creates one AI tool per procedure. Nested routers are flattened with underscores: users.list becomes users_list, admin.stats becomes admin_stats.

Use with any model

import {  } from 'ai'
import {  } from '@ai-sdk/openai'

const {  } = await ({
  : ('gpt-4o'),
  ,
  : 'List all users with limit 5, then create a user named Bob',
})

The model sees your procedures as callable functions. It reads the descriptions and parameter schemas, decides which tools to call, and Silgi executes them.

How it works

For each procedure, Silgi:

  1. Extracts a description from route.description or route.summary in your procedure definition. Falls back to "Call {name}".
  2. Converts the Zod input schema to JSON Schema, which is the format LLMs use for function calling.
  3. Creates an AI SDK tool that executes the procedure when the model calls it.

This means your existing route metadata doubles as AI tool documentation:

const  = k
  .$input(z.object({ : z.number().optional() }))
  .$route({
    : 'List all registered users',
    : 'Returns a list of users, optionally limited by count.',
  })
  .$resolve(({ ,  }) => .db.users.findMany({ : .limit }))

The AI model sees "List all registered users" as the tool description and knows it can pass { limit: number } as input.

Single procedure

For more control, convert individual procedures instead of the whole router:

import {  } from 'silgi/ai'

const  = ('search', appRouter.search, {
  : 'Search the database for items matching a query',
})

const {  } = await generateText({
  : openai('gpt-4o'),
  : { :  },
  : 'Find all items related to TypeScript',
})

The description option overrides anything from the procedure's route metadata.

Filtering procedures

You probably don't want to expose every procedure to the AI. Use the filter option to control which ones become tools:

const  = routerToTools(appRouter, {
  // Only expose query procedures, not mutations
  : (, ) => .type === 'query',
})

Or filter by path:

const  = routerToTools(appRouter, {
  : () => !.startsWith('admin_'),
})

Custom descriptions

Override descriptions for specific tools:

const  = routerToTools(appRouter, {
  : {
    : 'Get a list of all registered users. Supports a limit parameter.',
    : 'Create a new user account with a name and email.',
  },
})

These take priority over route metadata.

Good descriptions matter. LLMs decide which tool to call based on the description. Be specific about what the tool does and what parameters it accepts.

Supported input types

The Zod-to-JSON-Schema converter handles common types:

Zod typeJSON Schema
z.string(){ "type": "string" }
z.number(){ "type": "number" }
z.boolean(){ "type": "boolean" }
z.object({...}){ "type": "object", "properties": {...} }
z.array(z.string()){ "type": "array", "items": { "type": "string" } }
z.enum(["a", "b"]){ "type": "string", "enum": ["a", "b"] }
z.optional(...)Marked as not required

For procedures without an input schema, the tool accepts an empty object.

What's next?

On this page