@sema-agent/core
Version:
Stateless, task-oriented AI agent core
36 lines (35 loc) • 1.95 kB
TypeScript
import type { ToolSpec } from "../core/types.js";
export interface SqlToolOptions {
/**
* Execute a query that has already passed read-only validation, returning rows.
* IMPORTANT: back this with **read-only database credentials** — the validation here is
* defense-in-depth, not the primary guarantee.
*/
query: (sql: string) => Promise<unknown[]>;
/**
* If set, the query may only reference these tables (case-insensitive). **Best-effort, NOT a hard
* isolation boundary.** Table extraction is regex-based; to stay sound it FAILS CLOSED — comma-joins
* (`FROM a, b`), sub-queries in FROM/JOIN, and set operations (UNION/INTERSECT/EXCEPT) are REJECTED
* (their full table set can't be reliably enumerated). Even so, do **NOT** rely on this alone for
* multi-tenant / cross-tenant isolation: back it with **read-only DB credentials scoped to the tenant +
* DB-level GRANTs**. The allowlist is a usability guardrail and defense-in-depth, not the security
* boundary. (Full AST-parser coverage is deferred to preserve the zero-extra-dependency posture.)
*/
allowTables?: string[];
/** Maximum rows returned to the model. Default 100. */
maxRows?: number;
/** Tool name exposed to the model. Default "query_sql". */
name?: string;
/** Description override. */
description?: string;
}
/** Validate that `sql` is a single, read-only SELECT/CTE query within the allowlist. */
export declare function validateReadOnlySql(sql: string, allowTables?: string[]): void;
/**
* Build a safe, read-only `query_sql` tool.
*
* Layers of defense: (1) read-only DB credentials supplied by the caller's `query`,
* (2) static validation (single SELECT/WITH only, no DML/DDL, no comments/multi-statement),
* (3) optional table allowlist, (4) a row cap on what is returned to the model.
*/
export declare function createSqlTool(opts: SqlToolOptions): ToolSpec;