Generated, typed, auditable business tools for AI SDK agents—without exposing raw SQL.
Don't give your AI agent unrestricted SQL. Give it a typed business language.
@teaql/ai-sdk converts an explicit allowlist of TeaQL business capabilities into native Vercel AI SDK tools. The model receives business operations and their schemas. A trusted TeaQL UserContext, database resources, authorization state, and internal errors remain on the server.
| Raw SQL agent | TeaQL agent tools |
|---|---|
| Model guesses tables and joins | Model selects named business capabilities |
| Broad database access | Explicit capability allowlist |
| Untyped rows | Schema-validated input and output |
| Authorization depends on prompts | Trusted server-side context |
| Mutations are difficult to govern | AI SDK approval plus TeaQL audit semantics |
| Database errors may leak | Safe public errors and observable internal failures |
| Database-specific behavior | TeaQL domain semantics can span seven runtimes |
This package does not replace the AI SDK agent loop, model providers, UI, or streaming. It supplies the governed business-data layer beneath those features.
npm install @teaql/ai-sdk @teaql/teaql ai zodNode.js 22 or newer and AI SDK 7 are required by the initial release.
Capabilities are an explicit allowlist. The adapter intentionally does not expose every entity and CRUD operation automatically.
import { defineTeaQLCapability } from '@teaql/ai-sdk';
import { z } from 'zod';
const searchSchools = defineTeaQLCapability({
name: 'searchSchools',
description: 'Find schools by governed business criteria.',
inputSchema: z.object({
schoolType: z.enum(['PRIMARY', 'SECONDARY']),
name: z.string().optional(),
}),
risk: 'read',
execute: async ({ context, input }) =>
Q.schools()
.withSchoolType(input.schoolType)
.withNameContaining(input.name)
.comment('AI SDK tool: searchSchools')
.purpose('Search schools requested by the authenticated user')
.executeForList(context),
});The exact generated Q API follows the selected TeaQL model and generator version; capability definitions are ordinary typed application code and compile against it.
import { UserContext } from '@teaql/teaql';
import { ToolLoopAgent } from 'ai';
import { createTeaQLTools } from '@teaql/ai-sdk';
const context = new UserContext()
.insertResource('dataService', dataService)
.insertResource('authorization', authorization);
const agent = new ToolLoopAgent({
model: 'openai/gpt-5.4',
instructions: 'Use only the provided business tools. Never invent SQL.',
tools: createTeaQLTools({
context,
capabilities: [searchSchools, updateSchoolContactPhone],
}),
});Create context on the server for each request or session. Never accept it from model output or a browser payload.
const updateSchoolContactPhone = defineTeaQLCapability({
name: 'updateSchoolContactPhone',
description: 'Update a school phone after explicit user approval.',
inputSchema: z.object({
schoolId: z.number().int().positive(),
contactPhone: z.string(),
auditReason: z.string().min(8),
}),
risk: 'write',
needsApproval: true,
execute: async ({ context, input }) => {
const school = await Q.schools()
.withId(input.schoolId)
.comment('Load school for approved contact update')
.purpose(input.auditReason)
.executeForOne(context);
return school
.updateContactPhone(input.contactPhone)
.auditAs(input.auditReason)
.save(context);
},
});AI SDK approval controls whether the agent may execute the tool. TeaQL audit and runtime authorization still apply when execution begins. Approval is not a replacement for runtime security.
const tools = createTeaQLTools({
context,
capabilities,
onEvent: event => telemetry.record(event),
mapError: (_error, capability) =>
`${capability.name} could not be completed. Review the request or contact support.`,
});Lifecycle events contain capability name, risk, tool-call ID, timing, and the internal error on the server. Inputs are excluded by default because they may contain sensitive business data. The default model-visible error never includes the original database error.
The repository includes a deterministic, no-API-key school-management demonstration. It uses an in-memory SQLite resource inside the trusted UserContext to show the security boundary, approval metadata, optimistic version change, audit record, and model-visible tools.
npm install
npm run exampleThe SQLite repository is deliberately small and handwritten so the example is self-contained. A generated TeaQL project replaces that repository implementation with its generated Q, entity, Save, and Runtime Module APIs; the AI SDK adapter remains unchanged.
- Capabilities are deny-by-absence: only definitions passed to
createTeaQLToolsexist. allowcan narrow the registered capabilities for a particular user or agent.contextis captured by the server-side execute closure and is not part ofinputSchema.- Tool risk is metadata for policy and telemetry; applications must still enforce authorization in the runtime.
- Writes can request AI SDK approval, but must also use TeaQL audit and validation.
- Internal failures are available to server telemetry and hidden from the model by default.
- Capability names and duplicates are validated during startup.
The initial release is a runtime adapter for explicit TypeScript capability definitions. Planned generator work will produce capability definitions, schemas, agent guidance, and conformance fixtures from a TeaQL model. MCP adapters can expose the same capability manifest to Java, Rust, TypeScript, Swift, Python, .NET, and Go runtimes.
Apache-2.0