@teaql/ai-sdk

Generated, typed, auditable business tools for Vercel AI SDK agents


Keywords
teaql, vercel-ai-sdk, ai-sdk, agent, tools, typed-tools, database, audit, ai-agents, tool-calling, typescript
License
Apache-2.0
Install
npm install @teaql/ai-sdk@0.1.2

Documentation

TeaQL Agent Data Tools for Vercel AI SDK

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.

Published package: @teaql/ai-sdk on npm

Why

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.

Install

npm install @teaql/ai-sdk @teaql/teaql ai zod

Node.js 22 or newer and AI SDK 7 are required by the initial release.

Define business capabilities

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.

Create native AI SDK tools

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.

Govern writes

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.

Observe execution without leaking internals

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.

Run the local demonstration

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 example

The 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.

See examples/school-agent.

Security model

  • Capabilities are deny-by-absence: only definitions passed to createTeaQLTools exist.
  • allow can narrow the registered capabilities for a particular user or agent.
  • context is captured by the server-side execute closure and is not part of inputSchema.
  • 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.

Current scope

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.

Related projects

License

Apache-2.0