UNPKG

@agentdb/sdk

Version:

JavaScript SDK for AgentDB database service

882 lines (672 loc) 27.3 kB
# AgentDB JavaScript/TypeScript SDK A lightweight JavaScript/TypeScript SDK for the AgentDB database service. This SDK provides a simple interface for listing databases and executing SQL statements against SQLite and DuckDB databases. ## Features - **Fetch-only**: Uses only the native fetch API, no external dependencies - **Async/Await**: Modern promise-based API - **Error Handling**: Comprehensive error handling with custom exception types - **Full TypeScript Support**: Written in TypeScript with complete type definitions - **Dual Module Support**: Supports both ES modules and CommonJS - **Multi-Database**: Supports both SQLite and DuckDB databases - **Vector Support**: Built-in utilities for vector operations and embeddings - **Template Management**: Create, manage, and apply database templates - **Natural Language to SQL**: Convert natural language queries to SQL - **MCP Integration**: Create and manage MCP server URL slugs - **Debug Mode**: Built-in debug logging with server-side debug information ## Installation ```bash npm install @agentdb/sdk ``` ## Quick Start ### JavaScript (ES Modules) ```javascript import { DatabaseService } from '@agentdb/sdk'; // Create a service instance const service = new DatabaseService('https://api.agentdb.dev', 'your-api-key'); // List databases for a token const databases = await service.listDatabases('your-uuid-token'); console.log('Available databases:', databases); // Create a connection const connection = service.connect('your-uuid-token', 'my-database', 'sqlite'); // Execute SQL statements const result = await connection.execute([ { sql: 'CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)', params: [] }, { sql: 'INSERT INTO users (name) VALUES (?)', params: ['John Doe'] } ]); console.log('Execution result:', result); ``` ### TypeScript ```typescript import { DatabaseService, DatabaseInfo, ExecuteResult } from '@agentdb/sdk'; // Create a service instance with full type safety const service = new DatabaseService('https://api.agentdb.dev', 'your-api-key'); // List databases with typed response const databases: DatabaseInfo[] = await service.listDatabases('your-uuid-token'); console.log('Available databases:', databases); // Create a connection const connection = service.connect('your-uuid-token', 'my-database', 'sqlite'); // Execute SQL statements with typed results const result: ExecuteResult = await connection.execute([ { sql: 'CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)', params: [] }, { sql: 'INSERT INTO users (name) VALUES (?)', params: ['John Doe'] } ]); console.log('Execution result:', result); ``` ### CommonJS ```javascript const { DatabaseService } = require('@agentdb/sdk'); // Create a service instance const service = new DatabaseService('https://api.agentdb.dev', 'your-api-key'); // Use the same API as ES modules const databases = await service.listDatabases('your-uuid-token'); console.log('Available databases:', databases); ``` ## API Reference ### DatabaseService The main service class for listing databases and creating connections. #### Constructor ```javascript new DatabaseService(baseUrl, apiKey, debug = false) ``` - `baseUrl` (string): The base URL of the AgentDB service - `apiKey` (string): Your API key for authentication - `debug` (boolean, optional): Enable debug logging (default: false) #### Methods ##### `listDatabases(token)` Lists all databases for a given token. - `token` (string): The UUID token for database access - Returns: `Promise<DatabaseInfo[]>` - Array of database objects ```javascript const databases = await service.listDatabases('uuid-token'); // Returns: [{ name: 'db1', type: 'sqlite', fileName: 'db1.sqlite', size: 8192, modified: '2024-01-01T00:00:00.000Z' }] ``` ##### `connect(token, dbName, dbType)` Creates a new database connection. - `token` (string): The UUID token for database access - `dbName` (string): The name of the database - `dbType` (string): The type of database ('sqlite' or 'duckdb', defaults to 'sqlite') - Returns: `DatabaseConnection` - A new connection instance ```javascript const connection = service.connect('uuid-token', 'my-database', 'sqlite'); ``` ##### `deleteDatabase(token, dbName, dbType)` Deletes a database permanently. - `token` (string): The UUID token for database access - `dbName` (string): The name of the database to delete - `dbType` (string): The type of database ('sqlite' or 'duckdb', defaults to 'sqlite') - Returns: `Promise<DeleteDatabaseResponse>` - Deletion result with success message ```javascript await service.deleteDatabase('uuid-token', 'old-database', 'sqlite'); ``` ##### `renameDatabase(token, oldDbName, newDbName, dbType)` Renames a database. - `token` (string): The UUID token for database access - `oldDbName` (string): The current name of the database - `newDbName` (string): The new name for the database - `dbType` (string): The type of database ('sqlite' or 'duckdb', defaults to 'sqlite') - Returns: `Promise<RenameDatabaseResponse>` - Rename result with success message ```javascript await service.renameDatabase('uuid-token', 'old-name', 'new-name', 'sqlite'); ``` ##### `copyDatabase(sourceToken, sourceDbName, sourceDbType, destToken, destDbName)` Copies a database from one location to another. - `sourceToken` (string): The UUID token for the source database - `sourceDbName` (string): The name of the source database - `sourceDbType` (string): The type of the source database ('sqlite' or 'duckdb') - `destToken` (string): The UUID token for the destination - `destDbName` (string): The name for the destination database - Returns: `Promise<CopyDatabaseResponse>` - Copy result with success message ```javascript await service.copyDatabase('source-token', 'source-db', 'sqlite', 'dest-token', 'dest-db'); ``` ##### `getUploadUrl(token, dbName, dbType)` Gets a presigned URL for uploading a database file. - `token` (string): The UUID token for database access - `dbName` (string): The name for the database - `dbType` (string): The type of file ('sqlite', 'duckdb', or 'csv' - CSV files are converted to SQLite, defaults to 'sqlite') - Returns: `Promise<UploadUrlResponse>` - Upload URL information with uploadUrl, fileName, and expiresIn ```javascript const { uploadUrl, fileName } = await service.getUploadUrl('uuid-token', 'my-db', 'sqlite'); ``` ##### `getDownloadUrl(token, dbName, dbType)` Gets a presigned URL for downloading a database file. - `token` (string): The UUID token for database access - `dbName` (string): The name of the database - `dbType` (string): The type of database ('sqlite' or 'duckdb', defaults to 'sqlite') - Returns: `Promise<DownloadUrlResponse>` - Download URL information with downloadUrl, fileName, and expiresIn ```javascript const { downloadUrl, fileName } = await service.getDownloadUrl('uuid-token', 'my-db', 'sqlite'); ``` ##### `createTemplate(templateName, initializationSql, description)` Creates a new database template. - `templateName` (string): The name for the template - `initializationSql` (Array<string>): Array of SQL statements to initialize the template - `description` (string): Description of the template - Returns: `Promise<CreateTemplateResponse>` - Created template information ```javascript const template = await service.createTemplate( 'my-template', ['CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)'], 'A simple user table template' ); ``` ##### `listTemplates()` Lists all available templates. - Returns: `Promise<TemplateInfo[]>` - Array of template objects ```javascript const templates = await service.listTemplates(); ``` ##### `getTemplate(templateName)` Gets a specific template by name. - `templateName` (string): The name of the template to retrieve - Returns: `Promise<GetTemplateResponse>` - Template information ```javascript const template = await service.getTemplate('my-template'); ``` ##### `updateTemplate(templateName, initializationSql, description)` Updates an existing template. - `templateName` (string): The name of the template to update - `initializationSql` (Array<string>): Array of SQL statements to initialize the template - `description` (string): Description of the template - Returns: `Promise<UpdateTemplateResponse>` - Update result with success message and old template info ```javascript const result = await service.updateTemplate( 'my-template', ['CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)'], 'Updated user table template with email' ); ``` ##### `deleteTemplate(templateName)` Deletes a template. - `templateName` (string): The name of the template to delete - Returns: `Promise<DeleteTemplateResponse>` - Deletion result with success message ```javascript await service.deleteTemplate('my-template'); ``` ##### `getTemplateInfo(templateName, token, dbName, dbType)` Gets template information for a specific database. - `templateName` (string): The name of the template - `token` (string): The UUID token for database access - `dbName` (string): The name of the database - `dbType` (string): The type of database ('sqlite' or 'duckdb', defaults to 'sqlite') - Returns: `Promise<TemplateInfoResponse>` - Template info including schema and application status ```javascript const info = await service.getTemplateInfo('my-template', 'uuid-token', 'my-db', 'sqlite'); ``` ##### `getAppliedTemplates(token, dbName, dbType)` Gets applied templates for a database. - `token` (string): The UUID token for database access - `dbName` (string): The name of the database - `dbType` (string): The type of database ('sqlite' or 'duckdb', defaults to 'sqlite') - Returns: `Promise<AppliedTemplatesResponse>` - Applied templates information ```javascript const applied = await service.getAppliedTemplates('uuid-token', 'my-db', 'sqlite'); ``` ##### `uploadAndCreateTemplate(token, filePath, options)` Uploads a file (or multiple files) and automatically creates a database with an AI-generated template. This is a complete workflow that handles file upload, database analysis, AI description generation, template creation, and application. **Parameters:** - `token` (string): The UUID token for database access - `filePath` (string|string[]|File|File[]): Path to the file(s) to upload (Node.js) or File object (browser) - `options` (Object): Optional configuration - `options.dbName` (string): Custom database name (must be unique - will fail if already exists) - `options.templateName` (string): Custom template name (must be unique - will fail if already exists) - `options.onProgress` (Function): Progress callback function(step, message) **Returns:** `Promise<UploadResult>` with the following properties: - `success` (boolean): Whether the operation completed successfully - `dbName` (string): Name of the created database - `templateName` (string): Name of the created template - `description` (string): AI-generated description of the database - `tableCount` (number): Number of tables in the database - `message` (string): Success message **Supported file types:** CSV (converted to SQLite), SQLite **Naming Behavior:** - **Auto-generated names**: When no custom names are provided, the SDK automatically generates unique names: - Database names use the filename (sanitized): `customers.csv` -> `customers`, `customers1`, `customers2`, etc. - Template names append `_template` with uniqueness validation: `customers_template`, `customers_template1`, etc. - **Custom names**: When you specify custom `dbName` or `templateName`, they must be unique: - If a database/template with that name already exists, the operation will **fail** - No automatic conflict resolution is performed for custom names ```javascript // Upload from file path (Node.js) with auto-generated names const result = await service.uploadAndCreateTemplate( 'uuid-token', './data/customers.csv', { onProgress: (step, message) => console.log(`Step ${step}/6: ${message}`) } ); // Upload from File object (browser) const fileInput = document.querySelector('input[type="file"]'); const result = await service.uploadAndCreateTemplate( 'uuid-token', fileInput.files[0], { onProgress: (step, message) => console.log(`Step ${step}/6: ${message}`) } ); // Upload with custom names (must be unique) const result2 = await service.uploadAndCreateTemplate( 'uuid-token', './data/sales.sqlite', { dbName: 'sales_data', // Will fail if 'sales_data' already exists templateName: 'sales_template', // Will fail if 'sales_template' already exists onProgress: (step, message) => console.log(`Step ${step}: ${message}`) } ); console.log('Database created:', result.dbName); console.log('Template created:', result.templateName); console.log('Description:', result.description); ``` ##### `createMcpSlug(queryParams)` Creates a permanent URL slug for MCP server endpoints. - `queryParams` (Object): Query parameters for the MCP endpoint - Returns: `Promise<McpSlugResponse>` - Created slug information with slug and full URL ```javascript const slug = await service.createMcpSlug({ key: 'your-api-key', token: 'uuid-token', dbName: 'my-db', template: 'my-template' // optional }); ``` ##### `getMcpSlug(slug)` Gets MCP slug information. - `slug` (string): The slug identifier - Returns: `Promise<GetMcpSlugResponse>` - Slug information and query parameters ```javascript const slugInfo = await service.getMcpSlug('abc123'); ``` ### DatabaseConnection A connection to a specific database for executing SQL statements. #### Constructor ```javascript new DatabaseConnection(baseUrl, apiKey, token, dbName, dbType) ``` Typically created via `DatabaseService.connect()` rather than directly. #### Methods ##### `execute(statements)` Executes one or more SQL statements. - `statements` (Array|Object): Array of statement objects or single statement object - Returns: `Promise<ExecuteResult>` - Execution results Each statement object should have: - `sql` (string): The SQL statement to execute - `params` (Array, optional): Parameters for the SQL statement ```javascript // Single statement const result = await connection.execute({ sql: 'SELECT * FROM users WHERE id = ?', params: [1] }); // Multiple statements const result = await connection.execute([ { sql: 'INSERT INTO users (name) VALUES (?)', params: ['Alice'] }, { sql: 'INSERT INTO users (name) VALUES (?)', params: ['Bob'] } ]); ``` ##### `executeFailFast(statements, options)` Executes a batch of SQL statements but stops at the first failure. The response mirrors `execute` but also returns metadata describing what succeeded and where execution stopped. - `statements` (Array|Object): Array of statement objects or single statement object - `options` (Object, optional): Additional parameters such as `{ templateName: 'crm' }` - Returns: `Promise<FailFastExecuteResult>` - Execution results with fail-fast metadata Each statement object should have: - `sql` (string): The SQL statement to execute - `params` (Array, optional): Parameters for the SQL statement ```javascript const result = await connection.executeFailFast([ { sql: 'INSERT INTO tasks (title) VALUES (?)', params: ['First task'] }, { sql: 'INSERT INTO tasks (title) VALUES (?)', params: ['Second task'] }, { sql: 'INSERT INTO tasks (title, status) VALUES (?, ?)', params: ['Third task', 'done'] } ]); if (result.metadata.status === 'partial') { console.log('Failed at statement', result.metadata.failedStatementIndex); console.log('Error message:', result.metadata.failedStatement?.error); console.log('Completed statements:', result.metadata.successfulStatements); } ``` ##### `naturalLanguageToSql(query, conversationHistory, templateName)` Converts natural language to SQL and optionally executes it. - `query` (string): The natural language query - `conversationHistory` (Array, optional): Optional conversation history for context - `templateName` (string, optional): Optional template name for schema context - Returns: `Promise<NaturalLanguageResponse>` - Natural language conversion results with generated SQL and optional execution results ```javascript // Simple natural language query const result = await connection.naturalLanguageToSql('show me all users'); console.log('Generated SQL:', result.sql); console.log('Results:', result.results); // With conversation history for context const conversationHistory = [ { query: 'show me all users', sql: 'SELECT * FROM users', results: [{ rows: [{ id: 1, name: 'John' }] }] } ]; const result2 = await connection.naturalLanguageToSql( 'how many are there?', conversationHistory ); // With template for schema context const result3 = await connection.naturalLanguageToSql( 'show me customer orders', null, 'crm-template' ); ``` ## Error Handling The SDK provides specific error types for different scenarios: ```javascript import { AgentDBError, AuthenticationError, ValidationError, DatabaseError, createVectorBuffer } from '@agentdb/sdk'; try { const result = await connection.execute({ sql: 'SELECT * FROM users', params: [] }); } catch (error) { if (error instanceof AuthenticationError) { console.error('Authentication failed:', error.message); } else if (error instanceof ValidationError) { console.error('Invalid request:', error.message); } else if (error instanceof DatabaseError) { console.error('Database error:', error.message); } else if (error instanceof AgentDBError) { console.error('AgentDB error:', error.message); } else { console.error('Unexpected error:', error.message); } } ``` ## Examples ### Basic CRUD Operations ```javascript import { DatabaseService } from '@agentdb/sdk'; const service = new DatabaseService('https://api.agentdb.dev', 'your-api-key'); const connection = service.connect('your-token', 'users-db', 'sqlite'); // Create table await connection.execute({ sql: `CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT UNIQUE, created_at DATETIME DEFAULT CURRENT_TIMESTAMP )`, params: [] }); // Insert data await connection.execute({ sql: 'INSERT INTO users (name, email) VALUES (?, ?)', params: ['John Doe', 'john@example.com'] }); // Query data const result = await connection.execute({ sql: 'SELECT * FROM users WHERE email = ?', params: ['john@example.com'] }); console.log('User data:', result.results[0].rows); ``` ### Batch Operations ```javascript // Insert multiple records in a single request const users = [ ['Alice Smith', 'alice@example.com'], ['Bob Johnson', 'bob@example.com'], ['Carol Williams', 'carol@example.com'] ]; const statements = users.map(([name, email]) => ({ sql: 'INSERT INTO users (name, email) VALUES (?, ?)', params: [name, email] })); await connection.execute(statements); ``` ### Using DuckDB for Analytics ```javascript const analyticsConnection = service.connect('your-token', 'analytics', 'duckdb'); // Create analytics table await analyticsConnection.execute({ sql: `CREATE TABLE IF NOT EXISTS events ( id UUID DEFAULT gen_random_uuid(), timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, event_type VARCHAR(50), user_id VARCHAR(50), properties JSON )`, params: [] }); // Aggregate query const result = await analyticsConnection.execute({ sql: `SELECT event_type, COUNT(*) as total_events, COUNT(DISTINCT user_id) as unique_users FROM events WHERE timestamp >= CURRENT_DATE - INTERVAL '7 days' GROUP BY event_type ORDER BY total_events DESC`, params: [] }); console.log('Weekly analytics:', result.results[0].rows); ``` ### Database Management Operations ```javascript import { DatabaseService } from '@agentdb/sdk'; const service = new DatabaseService('https://api.agentdb.dev', 'your-api-key'); const token = 'your-uuid-token'; // Delete a database await service.deleteDatabase(token, 'old-database', 'sqlite'); // Rename a database await service.renameDatabase(token, 'current-name', 'new-name', 'sqlite'); // Copy a database between tokens await service.copyDatabase( 'source-token', 'source-db', 'sqlite', 'dest-token', 'backup-db' ); ``` ### Vector Operations The SDK provides utilities for working with vector embeddings and similarity search: ```javascript import { DatabaseService, createVectorBuffer } from '@agentdb/sdk'; const service = new DatabaseService('https://api.agentdb.dev', 'your-api-key'); const connection = service.connect('your-token', 'documents-db', 'sqlite'); // Create a table with vector embeddings await connection.execute({ sql: `CREATE TABLE IF NOT EXISTS documents ( id INTEGER PRIMARY KEY, content TEXT, embedding BLOB )`, params: [] }); // Insert documents with vector embeddings const documents = [ { content: 'Machine learning basics', embedding: [0.1, 0.2, 0.3, 0.4] }, { content: 'Database fundamentals', embedding: [0.5, 0.6, 0.7, 0.8] }, { content: 'Vector search techniques', embedding: [0.2, 0.3, 0.4, 0.5] } ]; for (const doc of documents) { await connection.execute({ sql: 'INSERT INTO documents (content, embedding) VALUES (?, ?)', params: [doc.content, createVectorBuffer(doc.embedding)] }); } // Perform vector similarity search const queryEmbedding = createVectorBuffer([0.1, 0.2, 0.3, 0.4]); const searchResult = await connection.execute({ sql: `SELECT id, content, vec_distance_cosine(embedding, ?) as similarity FROM documents ORDER BY similarity LIMIT 5`, params: [queryEmbedding] }); console.log('Similar documents:', searchResult.results[0].rows); // You can also use arrays directly (they will be automatically converted) const directArrayResult = await connection.execute({ sql: `SELECT id, content, vec_distance_cosine(embedding, ?) as similarity FROM documents ORDER BY similarity LIMIT 5`, params: [[0.1, 0.2, 0.3, 0.4]] // Array will be processed server-side }); ``` For a complete vector operations example, see [`examples/vector-operations.js`](./examples/vector-operations.js). ### File Upload/Download ```javascript // Get upload URL and upload a file const { uploadUrl } = await service.getUploadUrl(token, 'imported-db', 'sqlite'); // Upload file using the presigned URL const file = new File([fileData], 'database.sqlite'); await fetch(uploadUrl, { method: 'PUT', body: file, headers: { 'Content-Type': 'application/octet-stream' } }); // Get download URL and download a file const { downloadUrl, fileName } = await service.getDownloadUrl(token, 'my-db', 'sqlite'); // Download the file const response = await fetch(downloadUrl); const blob = await response.blob(); // Create download link const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = fileName; a.click(); URL.revokeObjectURL(url); ``` ### Upload a File and Create a Template The SDK provides a streamlined method to upload files and automatically create AI-powered templates: ```javascript import { DatabaseService } from '@agentdb/sdk'; const service = new DatabaseService('https://api.agentdb.dev', 'your-api-key'); const token = 'your-uuid-token'; // Upload a CSV file with progress tracking const result = await service.uploadAndCreateTemplate( token, './data/sales-data.csv', { onProgress: (step, message) => { console.log(`Step ${step}/6: ${message}`); } } ); console.log('✅ Upload completed!'); console.log(`Database: ${result.dbName}`); console.log(`Template: ${result.templateName}`); console.log(`Description: ${result.description}`); // Now you can use the database with the template const connection = service.connect(token, result.dbName, 'sqlite'); // Execute queries with template context for better AI understanding const nlResult = await connection.naturalLanguageToSql( 'show me the top 10 sales by amount', null, result.templateName ); console.log('Generated SQL:', nlResult.sql); console.log('Results:', nlResult.results); ``` **Workflow Steps:** 1. **File upload** - Uploads file to cloud storage 2. **Database analysis** - Waits for file processing and database creation 3. **AI description** - Generates intelligent description and schema analysis 4. **Template creation** - Creates reusable template with the AI-generated content 5. **Template application** - Applies template to database for enhanced querying 6. **Verification** - Ensures everything is set up correctly **Error Handling:** - Automatic cleanup of partially created resources on failure - Detailed error messages for troubleshooting - Retry logic for transient failures during database processing **Naming Conflicts:** ```javascript // This will fail if 'my_database' already exists try { const result = await service.uploadAndCreateTemplate( token, './data.csv', { dbName: 'my_database' } ); } catch (error) { if (error.message.includes('already exists')) { console.log('Database name conflict - choose a different name'); } } // This will automatically find a unique name (data, data1, data2, etc.) const result = await service.uploadAndCreateTemplate( token, './data.csv' // No custom dbName - automatic conflict resolution ); ``` ## Debug Mode The SDK supports debug mode for troubleshooting and development. When enabled, it provides detailed logging of requests, responses, and server-side debug information. ```javascript // Enable debug mode const service = new DatabaseService('https://api.agentdb.dev', 'your-api-key', true); // Debug logs will be shown in console const databases = await service.listDatabases('your-token'); // Connections inherit debug mode from service const connection = service.connect('your-token', 'my-db', 'sqlite'); // Execute with debug information const result = await connection.execute({ sql: 'SELECT * FROM users', params: [] }); // Access server-side debug logs from response if (result.debugLogs) { console.log('Server debug logs:', result.debugLogs); } ``` For detailed debug mode documentation, see [DEBUG_USAGE.md](./DEBUG_USAGE.md). ## API Reference ### createVectorBuffer(values) Creates a Float32 buffer from an array of numbers for use as vector parameters in SQL queries. **Parameters:** - `values` (number[]): Array of numeric values to convert to a vector buffer **Returns:** - `Buffer|Uint8Array`: Buffer containing the vector data as Float32 values **Throws:** - `ValidationError`: If values is not an array, is empty, or contains non-numeric values **Example:** ```javascript import { createVectorBuffer } from '@agentdb/sdk'; // Create a vector buffer const embedding = createVectorBuffer([0.1, 0.2, 0.3, 0.4]); // Use in a query const result = await connection.execute({ sql: 'SELECT * FROM documents WHERE vec_distance_cosine(embedding, ?) < 0.5', params: [embedding] }); ``` **Notes:** - Each number is stored as a 32-bit float (4 bytes) - The resulting buffer length will be `values.length × 4` bytes - Works in both Node.js and browser environments - For simple use cases, you can pass arrays directly to `params` and they will be processed server-side ## Requirements - Node.js 18.0.0 or higher - Modern browser with fetch API support ## License MIT