Deep Agents
AgentOrchestratorRetrievalText2SQLToolbox

SQL Server

Configure Text2SQL with Microsoft SQL Server databases

The SQL Server adapter supports Microsoft SQL Server databases with automatic schema introspection using INFORMATION_SCHEMA and sys catalog views.

Basic Setup

import sql from 'mssql';

import { Text2Sql, InMemoryHistory } from '@deepagents/text2sql';
import { SqlServer } from '@deepagents/text2sql/sqlserver';
import * as sqlserver from '@deepagents/text2sql/sqlserver';

const pool = await sql.connect({
  server: process.env.DB_HOST,
  database: process.env.DB_NAME,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  options: {
    encrypt: true,
    trustServerCertificate: true,
  },
});

const text2sql = new Text2Sql({
  version: 'v1', // Bump this when your schema changes
  adapter: new SqlServer({
    execute: async (query) => {
      const result = await pool.request().query(query);
      return result.recordset;
    },
    grounding: [
      sqlserver.tables(),
      sqlserver.views(),
      sqlserver.info(),
      sqlserver.indexes(),
      sqlserver.constraints(),
      sqlserver.rowCount(),
      sqlserver.columnStats(),
      sqlserver.lowCardinality(),
    ],
  }),
  history: new InMemoryHistory(),
});
import { Connection, Request } from 'tedious';

import { Text2Sql, InMemoryHistory } from '@deepagents/text2sql';
import { SqlServer } from '@deepagents/text2sql/sqlserver';
import * as sqlserver from '@deepagents/text2sql/sqlserver';

const connection = new Connection(config);

const text2sql = new Text2Sql({
  version: 'v1', // Bump this when your schema changes
  adapter: new SqlServer({
    execute: (sql) => new Promise((resolve, reject) => {
      const rows = [];
      const request = new Request(sql, (err) => {
        if (err) reject(err);
        else resolve(rows);
      });
      request.on('row', (columns) => {
        const row = {};
        columns.forEach((col) => {
          row[col.metadata.colName] = col.value;
        });
        rows.push(row);
      });
      connection.execSql(request);
    }),
    grounding: [
      sqlserver.tables(),
      sqlserver.views(),
      sqlserver.info(),
      sqlserver.indexes(),
      sqlserver.constraints(),
      sqlserver.rowCount(),
      sqlserver.columnStats(),
      sqlserver.lowCardinality(),
    ],
  }),
  history: new InMemoryHistory(),
});

Configuration Options

import * as sqlserver from '@deepagents/text2sql/sqlserver';

new SqlServer({
  // Required: Execute SQL queries
  execute: async (sql) => pool.request().query(sql).then(r => r.recordset),

  // Required: Grounding functions for schema introspection
  grounding: [
    sqlserver.tables(),
    sqlserver.info(),
    // Add more grounding functions as needed
  ],

  // Optional: Custom validation function
  validate: async (sql) => {
    // Return void if valid, or error string if invalid
  },

  // Optional: Filter to specific schemas (default excludes sys, INFORMATION_SCHEMA)
  schemas: ['dbo', 'sales'],
});

See Grounding for the full list of available grounding functions and their configuration options.

Schema Filtering

By default, the adapter excludes system schemas (INFORMATION_SCHEMA, sys). To limit introspection to specific schemas:

new SqlServer({
  execute: async (sql) => pool.request().query(sql).then(r => r.recordset),
  schemas: ['dbo', 'sales', 'inventory'],
});

Available Grounding Functions

The following grounding functions are available for SQL Server. Import them from @deepagents/text2sql/sqlserver:

FunctionDescription
tables()Discovers tables and columns using INFORMATION_SCHEMA, identifies primary keys
views()Discovers database views
info()Collects SQL Server version and database info
indexes()Queries sys.indexes for clustered/nonclustered types, detects included columns
constraints()Maps foreign key relationships between tables
rowCount()Counts rows and classifies tables by size
columnStats()Collects min, max, null fraction using CONVERT for type-safe aggregation
lowCardinality()Detects columns with few distinct values using SELECT DISTINCT TOP
report()Uses an LLM to generate a business context report from your database

See Grounding for detailed configuration options.

Error Handling

The adapter maps SQL Server error codes to helpful suggestions:

Error CodeTypeSuggestion
208MISSING_TABLECheck that the table exists and include schema prefix (e.g., dbo.TableName)
207INVALID_COLUMNVerify the column exists and aliases are referenced correctly
156SYNTAX_ERRORReview keywords, punctuation, and clauses like GROUP BY
4104INVALID_COLUMNQualify columns with table aliases when ambiguous
1934CONSTRAINT_ERRORRe-check join logic and filtering

Execute Function Return Types

The execute function can return multiple formats:

// Array of rows directly
execute: async (sql) => {
  const result = await pool.request().query(sql);
  return result.recordset;
}

// Object with recordset property (mssql default)
execute: async (sql) => {
  return await pool.request().query(sql);  // { recordset: [...] }
}

// Object with rows property
execute: async (sql) => {
  return { rows: [...] };
}

// Object with recordsets array (for multi-statement queries)
execute: async (sql) => {
  return { recordsets: [[...]] };  // Uses first recordset
}

Query Validation

By default, validation uses SET PARSEONLY to check syntax without execution:

new SqlServer({
  execute: async (sql) => pool.request().query(sql).then(r => r.recordset),
  // Default validation
  validate: async (sql) => {
    await pool.request().query(`SET PARSEONLY ON; ${sql}; SET PARSEONLY OFF;`);
  },
});

Table Naming Conventions

SQL Server tables are referenced with schema prefix:

dbo.Users
sales.Orders
inventory.Products

The adapter automatically handles bracket quoting: [dbo].[Users]

Size Hints

Tables are classified by row count:

Size HintRow Count
tiny< 100
small100 - 999
medium1,000 - 9,999
large10,000 - 99,999
huge>= 100,000