nttp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +245 -0
- package/dist/NTTP.d.ts +121 -0
- package/dist/NTTP.d.ts.map +1 -0
- package/dist/NTTP.js +229 -0
- package/dist/NTTP.js.map +1 -0
- package/dist/cache/exact-cache.d.ts +46 -0
- package/dist/cache/exact-cache.d.ts.map +1 -0
- package/dist/cache/exact-cache.js +104 -0
- package/dist/cache/exact-cache.js.map +1 -0
- package/dist/cache/index.d.ts +8 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +7 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/semantic-cache.d.ts +82 -0
- package/dist/cache/semantic-cache.d.ts.map +1 -0
- package/dist/cache/semantic-cache.js +243 -0
- package/dist/cache/semantic-cache.js.map +1 -0
- package/dist/cache/types.d.ts +135 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache/types.js +5 -0
- package/dist/cache/types.js.map +1 -0
- package/dist/cache.d.ts +71 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +129 -0
- package/dist/cache.js.map +1 -0
- package/dist/errors.d.ts +35 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +55 -0
- package/dist/errors.js.map +1 -0
- package/dist/executor.d.ts +82 -0
- package/dist/executor.d.ts.map +1 -0
- package/dist/executor.js +395 -0
- package/dist/executor.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/intent.d.ts +55 -0
- package/dist/intent.d.ts.map +1 -0
- package/dist/intent.js +183 -0
- package/dist/intent.js.map +1 -0
- package/dist/llm.d.ts +60 -0
- package/dist/llm.d.ts.map +1 -0
- package/dist/llm.js +171 -0
- package/dist/llm.js.map +1 -0
- package/dist/types.d.ts +280 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +61 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +19 -0
- package/dist/utils.js.map +1 -0
- package/package.json +94 -0
package/README.md
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# NTTP - Natural Text Transfer Protocol
|
|
2
|
+
|
|
3
|
+
Query databases with natural language using Claude AI.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install nttp
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
You'll also need a database driver:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# SQLite
|
|
15
|
+
npm install better-sqlite3
|
|
16
|
+
|
|
17
|
+
# PostgreSQL
|
|
18
|
+
npm install pg
|
|
19
|
+
|
|
20
|
+
# MySQL
|
|
21
|
+
npm install mysql2
|
|
22
|
+
|
|
23
|
+
# SQL Server
|
|
24
|
+
npm install mssql
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { NTTP } from 'nttp';
|
|
31
|
+
|
|
32
|
+
const nttp = new NTTP({
|
|
33
|
+
database: {
|
|
34
|
+
client: 'pg',
|
|
35
|
+
connection: process.env.DATABASE_URL
|
|
36
|
+
},
|
|
37
|
+
anthropic: {
|
|
38
|
+
apiKey: process.env.ANTHROPIC_API_KEY
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Initialize (connects to database, builds schema cache)
|
|
43
|
+
await nttp.init();
|
|
44
|
+
|
|
45
|
+
// Query naturally!
|
|
46
|
+
const users = await nttp.query("get all active users");
|
|
47
|
+
console.log(users.data); // Array of users
|
|
48
|
+
|
|
49
|
+
// Close when done
|
|
50
|
+
await nttp.close();
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## API Reference
|
|
54
|
+
|
|
55
|
+
### `new NTTP(config)`
|
|
56
|
+
|
|
57
|
+
Create a new NTTP instance.
|
|
58
|
+
|
|
59
|
+
**Config:**
|
|
60
|
+
```typescript
|
|
61
|
+
{
|
|
62
|
+
database: {
|
|
63
|
+
client: 'pg' | 'mysql2' | 'better-sqlite3' | 'mssql',
|
|
64
|
+
connection: string | object // Knex connection config
|
|
65
|
+
},
|
|
66
|
+
anthropic: {
|
|
67
|
+
apiKey: string,
|
|
68
|
+
model?: string, // Default: 'claude-sonnet-4-5-20250929'
|
|
69
|
+
maxTokens?: number // Default: 2048
|
|
70
|
+
},
|
|
71
|
+
limits?: {
|
|
72
|
+
maxQueryLength?: number, // Default: 500
|
|
73
|
+
defaultLimit?: number, // Default: 100
|
|
74
|
+
maxLimit?: number // Default: 1000
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### `nttp.init()`
|
|
80
|
+
|
|
81
|
+
Initialize NTTP. Must be called before querying.
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
await nttp.init();
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### `nttp.query(query, options?)`
|
|
88
|
+
|
|
89
|
+
Execute a natural language query.
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
const result = await nttp.query("show pending orders over $500");
|
|
93
|
+
|
|
94
|
+
// Result structure:
|
|
95
|
+
{
|
|
96
|
+
query: string, // Original query
|
|
97
|
+
data: any[], // Query results
|
|
98
|
+
schemaId: string, // Cache key
|
|
99
|
+
cacheHit: boolean, // Was cached?
|
|
100
|
+
executionTimeMs: number, // Execution time
|
|
101
|
+
intent: {...}, // Parsed intent
|
|
102
|
+
sql?: string, // Generated SQL (debug)
|
|
103
|
+
params?: any[] // SQL parameters (debug)
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Options:**
|
|
108
|
+
```typescript
|
|
109
|
+
{
|
|
110
|
+
useCache?: boolean, // Use cache (default: true)
|
|
111
|
+
forceNewSchema?: boolean // Force new schema (default: false)
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### `nttp.explain(query)`
|
|
116
|
+
|
|
117
|
+
Explain what SQL would be generated without executing.
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
const explanation = await nttp.explain("top 10 customers by revenue");
|
|
121
|
+
|
|
122
|
+
// Returns:
|
|
123
|
+
{
|
|
124
|
+
query: string,
|
|
125
|
+
intent: {...},
|
|
126
|
+
sql: string,
|
|
127
|
+
params: any[],
|
|
128
|
+
schemaId: string,
|
|
129
|
+
cachedSchema: SchemaDefinition | null
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Schema Management
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
// List all cached schemas
|
|
137
|
+
const schemas = await nttp.listSchemas();
|
|
138
|
+
|
|
139
|
+
// Get specific schema
|
|
140
|
+
const schema = await nttp.getSchema(schemaId);
|
|
141
|
+
|
|
142
|
+
// Delete schema
|
|
143
|
+
await nttp.deleteSchema(schemaId);
|
|
144
|
+
|
|
145
|
+
// Pin schema (prevent eviction)
|
|
146
|
+
await nttp.pinSchema(schemaId);
|
|
147
|
+
|
|
148
|
+
// Unpin schema
|
|
149
|
+
await nttp.unpinSchema(schemaId);
|
|
150
|
+
|
|
151
|
+
// Get cache statistics
|
|
152
|
+
const stats = await nttp.getCacheStats();
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Database Inspection
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
// Get all tables
|
|
159
|
+
const tables = await nttp.getTables();
|
|
160
|
+
|
|
161
|
+
// Get table schema
|
|
162
|
+
const schema = await nttp.getTableSchema('users');
|
|
163
|
+
|
|
164
|
+
// Get schema description (for LLM)
|
|
165
|
+
const description = nttp.getSchemaDescription();
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Example Queries
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
// Simple queries
|
|
172
|
+
await nttp.query("get all users");
|
|
173
|
+
await nttp.query("show products");
|
|
174
|
+
await nttp.query("list orders");
|
|
175
|
+
|
|
176
|
+
// Filtered queries
|
|
177
|
+
await nttp.query("active users only");
|
|
178
|
+
await nttp.query("products in Electronics category");
|
|
179
|
+
await nttp.query("pending orders");
|
|
180
|
+
|
|
181
|
+
// With limits
|
|
182
|
+
await nttp.query("top 10 products by price");
|
|
183
|
+
await nttp.query("show me 5 recent orders");
|
|
184
|
+
|
|
185
|
+
// Aggregations
|
|
186
|
+
await nttp.query("count all users");
|
|
187
|
+
await nttp.query("total revenue by category");
|
|
188
|
+
await nttp.query("average order value");
|
|
189
|
+
|
|
190
|
+
// Complex conditions
|
|
191
|
+
await nttp.query("products with 4+ star rating under $100");
|
|
192
|
+
await nttp.query("orders from California in the last 30 days");
|
|
193
|
+
await nttp.query("users who joined this year");
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Database Support
|
|
197
|
+
|
|
198
|
+
NTTP works with any SQL database supported by Knex.js:
|
|
199
|
+
|
|
200
|
+
- **PostgreSQL** - Recommended for production
|
|
201
|
+
- **MySQL** - Widely supported
|
|
202
|
+
- **SQLite** - Perfect for development
|
|
203
|
+
- **SQL Server** - Enterprise-ready
|
|
204
|
+
|
|
205
|
+
## Performance
|
|
206
|
+
|
|
207
|
+
- **Cache Hit**: <50ms average
|
|
208
|
+
- **Cache Miss**: ~2-3s (LLM call)
|
|
209
|
+
- **Throughput**: >10,000 req/s (cached)
|
|
210
|
+
|
|
211
|
+
## Error Handling
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
import { IntentParseError, SQLGenerationError, SQLExecutionError } from 'nttp';
|
|
215
|
+
|
|
216
|
+
try {
|
|
217
|
+
const result = await nttp.query("ambiguous query");
|
|
218
|
+
} catch (error) {
|
|
219
|
+
if (error instanceof IntentParseError) {
|
|
220
|
+
console.error('Could not understand query');
|
|
221
|
+
} else if (error instanceof SQLGenerationError) {
|
|
222
|
+
console.error('Could not generate SQL');
|
|
223
|
+
} else if (error instanceof SQLExecutionError) {
|
|
224
|
+
console.error('SQL execution failed');
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## TypeScript
|
|
230
|
+
|
|
231
|
+
Full TypeScript support with exported types:
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
import type {
|
|
235
|
+
NTTPConfig,
|
|
236
|
+
QueryResult,
|
|
237
|
+
Intent,
|
|
238
|
+
SchemaDefinition,
|
|
239
|
+
CacheStats
|
|
240
|
+
} from 'nttp';
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## License
|
|
244
|
+
|
|
245
|
+
MIT
|
package/dist/NTTP.d.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main nttp class - provides programmatic API for natural language database queries.
|
|
3
|
+
*/
|
|
4
|
+
import type { NTTPConfig, QueryOptions, QueryResult, Intent, SchemaDefinition, CacheStats } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* nttp - natural text to query
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const nttp = new NTTP({
|
|
11
|
+
* database: {
|
|
12
|
+
* client: 'pg',
|
|
13
|
+
* connection: process.env.DATABASE_URL
|
|
14
|
+
* },
|
|
15
|
+
* llm: {
|
|
16
|
+
* provider: 'anthropic',
|
|
17
|
+
* model: 'claude-sonnet-4-5-20250929',
|
|
18
|
+
* apiKey: process.env.ANTHROPIC_API_KEY
|
|
19
|
+
* },
|
|
20
|
+
* cache: {
|
|
21
|
+
* l2: {
|
|
22
|
+
* provider: 'openai',
|
|
23
|
+
* model: 'text-embedding-3-small',
|
|
24
|
+
* apiKey: process.env.OPENAI_API_KEY
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* const users = await nttp.query("get all active users");
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare class NTTP {
|
|
33
|
+
private config;
|
|
34
|
+
private db;
|
|
35
|
+
private inspector;
|
|
36
|
+
private cache;
|
|
37
|
+
private llm;
|
|
38
|
+
private intentParser;
|
|
39
|
+
private executor;
|
|
40
|
+
private schemaInfo;
|
|
41
|
+
private l1Cache?;
|
|
42
|
+
private l2Cache?;
|
|
43
|
+
constructor(config: NTTPConfig);
|
|
44
|
+
/**
|
|
45
|
+
* Initialize NTTP - must be called before using.
|
|
46
|
+
*/
|
|
47
|
+
init(): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Execute a natural language query.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const result = await nttp.query("get top 10 products by price");
|
|
54
|
+
* console.log(result.data); // Array of products
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
query(query: string, options?: QueryOptions): Promise<QueryResult>;
|
|
58
|
+
/**
|
|
59
|
+
* Explain what SQL would be generated without executing.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* const explanation = await nttp.explain("show pending orders");
|
|
64
|
+
* console.log(explanation.sql); // Generated SQL
|
|
65
|
+
* console.log(explanation.intent); // Parsed intent
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
explain(query: string): Promise<{
|
|
69
|
+
query: string;
|
|
70
|
+
intent: Intent;
|
|
71
|
+
sql: string;
|
|
72
|
+
params: any[];
|
|
73
|
+
schemaId: string;
|
|
74
|
+
cachedSchema: SchemaDefinition | null;
|
|
75
|
+
}>;
|
|
76
|
+
/**
|
|
77
|
+
* Get all cached schemas.
|
|
78
|
+
*/
|
|
79
|
+
listSchemas(): Promise<SchemaDefinition[]>;
|
|
80
|
+
/**
|
|
81
|
+
* Get a specific cached schema.
|
|
82
|
+
*/
|
|
83
|
+
getSchema(schemaId: string): Promise<SchemaDefinition | undefined>;
|
|
84
|
+
/**
|
|
85
|
+
* Delete a cached schema.
|
|
86
|
+
*/
|
|
87
|
+
deleteSchema(schemaId: string): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* Pin a schema to prevent eviction.
|
|
90
|
+
*/
|
|
91
|
+
pinSchema(schemaId: string): Promise<void>;
|
|
92
|
+
/**
|
|
93
|
+
* Unpin a schema.
|
|
94
|
+
*/
|
|
95
|
+
unpinSchema(schemaId: string): Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* Get cache statistics.
|
|
98
|
+
*/
|
|
99
|
+
getCacheStats(): Promise<CacheStats>;
|
|
100
|
+
/**
|
|
101
|
+
* Get list of all database tables.
|
|
102
|
+
*/
|
|
103
|
+
getTables(): Promise<string[]>;
|
|
104
|
+
/**
|
|
105
|
+
* Get schema for a specific table.
|
|
106
|
+
*/
|
|
107
|
+
getTableSchema(tableName: string): Promise<any[]>;
|
|
108
|
+
/**
|
|
109
|
+
* Get formatted schema description for LLM prompts.
|
|
110
|
+
*/
|
|
111
|
+
getSchemaDescription(): string;
|
|
112
|
+
/**
|
|
113
|
+
* Close database connection and cleanup.
|
|
114
|
+
*/
|
|
115
|
+
close(): Promise<void>;
|
|
116
|
+
/**
|
|
117
|
+
* Build schema information cache.
|
|
118
|
+
*/
|
|
119
|
+
private buildSchemaInfo;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=NTTP.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NTTP.d.ts","sourceRoot":"","sources":["../src/NTTP.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EACV,UAAU,EACV,YAAY,EACZ,WAAW,EACX,MAAM,EACN,gBAAgB,EAChB,UAAU,EACX,MAAM,YAAY,CAAC;AAOpB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,IAAI;IAaH,OAAO,CAAC,MAAM;IAZ1B,OAAO,CAAC,EAAE,CAAO;IACjB,OAAO,CAAC,SAAS,CAAqC;IACtD,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,GAAG,CAAa;IACxB,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,UAAU,CAAkE;IAGpF,OAAO,CAAC,OAAO,CAAC,CAAa;IAC7B,OAAO,CAAC,OAAO,CAAC,CAAgB;gBAEZ,MAAM,EAAE,UAAU;IA8BtC;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ3B;;;;;;;;OAQG;IACG,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,CAAC;IAoB5E;;;;;;;;;OASG;IACG,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QACpC,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,GAAG,EAAE,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,gBAAgB,GAAG,IAAI,CAAC;KACvC,CAAC;IAkBF;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAIhD;;OAEG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC;IAIxE;;OAEG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInD;;OAEG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhD;;OAEG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC;IA4B1C;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIpC;;OAEG;IACG,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAIvD;;OAEG;IACH,oBAAoB,IAAI,MAAM;IAW9B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;OAEG;YACW,eAAe;CAW9B"}
|
package/dist/NTTP.js
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main nttp class - provides programmatic API for natural language database queries.
|
|
3
|
+
*/
|
|
4
|
+
import { knex } from 'knex';
|
|
5
|
+
import { SchemaInspector } from 'knex-schema-inspector';
|
|
6
|
+
import { SchemaCache } from './cache.js';
|
|
7
|
+
import { LLMService } from './llm.js';
|
|
8
|
+
import { IntentParser } from './intent.js';
|
|
9
|
+
import { QueryExecutor } from './executor.js';
|
|
10
|
+
import { ExactCache, SemanticCache } from './cache/index.js';
|
|
11
|
+
/**
|
|
12
|
+
* nttp - natural text to query
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const nttp = new NTTP({
|
|
17
|
+
* database: {
|
|
18
|
+
* client: 'pg',
|
|
19
|
+
* connection: process.env.DATABASE_URL
|
|
20
|
+
* },
|
|
21
|
+
* llm: {
|
|
22
|
+
* provider: 'anthropic',
|
|
23
|
+
* model: 'claude-sonnet-4-5-20250929',
|
|
24
|
+
* apiKey: process.env.ANTHROPIC_API_KEY
|
|
25
|
+
* },
|
|
26
|
+
* cache: {
|
|
27
|
+
* l2: {
|
|
28
|
+
* provider: 'openai',
|
|
29
|
+
* model: 'text-embedding-3-small',
|
|
30
|
+
* apiKey: process.env.OPENAI_API_KEY
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* const users = await nttp.query("get all active users");
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export class NTTP {
|
|
39
|
+
config;
|
|
40
|
+
db;
|
|
41
|
+
inspector;
|
|
42
|
+
cache;
|
|
43
|
+
llm;
|
|
44
|
+
intentParser;
|
|
45
|
+
executor;
|
|
46
|
+
schemaInfo = {};
|
|
47
|
+
// 3-layer caches
|
|
48
|
+
l1Cache;
|
|
49
|
+
l2Cache;
|
|
50
|
+
constructor(config) {
|
|
51
|
+
this.config = config;
|
|
52
|
+
// Initialize Knex
|
|
53
|
+
this.db = knex(config.database);
|
|
54
|
+
// Initialize schema inspector
|
|
55
|
+
this.inspector = SchemaInspector(this.db);
|
|
56
|
+
// Initialize services
|
|
57
|
+
this.cache = new SchemaCache();
|
|
58
|
+
this.llm = new LLMService(config.llm);
|
|
59
|
+
this.intentParser = new IntentParser(this.llm);
|
|
60
|
+
// Initialize 3-layer caches
|
|
61
|
+
if (config.cache?.l1?.enabled !== false) {
|
|
62
|
+
this.l1Cache = new ExactCache(config.cache?.l1?.maxSize);
|
|
63
|
+
}
|
|
64
|
+
if (config.cache?.l2?.enabled !== false && config.cache?.l2) {
|
|
65
|
+
this.l2Cache = new SemanticCache(config.cache.l2);
|
|
66
|
+
}
|
|
67
|
+
// Initialize executor with caches
|
|
68
|
+
this.executor = new QueryExecutor(this.db, this.llm, this.cache, this.l1Cache, this.l2Cache);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Initialize NTTP - must be called before using.
|
|
72
|
+
*/
|
|
73
|
+
async init() {
|
|
74
|
+
// Test database connection
|
|
75
|
+
await this.db.raw('SELECT 1');
|
|
76
|
+
// Build schema cache
|
|
77
|
+
await this.buildSchemaInfo();
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Execute a natural language query.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* const result = await nttp.query("get top 10 products by price");
|
|
85
|
+
* console.log(result.data); // Array of products
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
async query(query, options = {}) {
|
|
89
|
+
const startTime = Date.now();
|
|
90
|
+
// Parse intent from natural language
|
|
91
|
+
const intent = await this.intentParser.parse(query, this.getSchemaDescription());
|
|
92
|
+
// Execute query with caching
|
|
93
|
+
const result = await this.executor.execute({
|
|
94
|
+
query,
|
|
95
|
+
intent,
|
|
96
|
+
useCache: options.useCache ?? true,
|
|
97
|
+
forceNewSchema: options.forceNewSchema ?? false,
|
|
98
|
+
});
|
|
99
|
+
return {
|
|
100
|
+
...result,
|
|
101
|
+
executionTimeMs: Date.now() - startTime,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Explain what SQL would be generated without executing.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* const explanation = await nttp.explain("show pending orders");
|
|
110
|
+
* console.log(explanation.sql); // Generated SQL
|
|
111
|
+
* console.log(explanation.intent); // Parsed intent
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
async explain(query) {
|
|
115
|
+
const intent = await this.intentParser.parse(query, this.getSchemaDescription());
|
|
116
|
+
const schemaId = this.intentParser.generateSchemaId(intent);
|
|
117
|
+
const cached = await this.cache.get(schemaId);
|
|
118
|
+
// Generate SQL without executing
|
|
119
|
+
const { sql, params } = await this.executor.generateSql(intent);
|
|
120
|
+
return {
|
|
121
|
+
query,
|
|
122
|
+
intent,
|
|
123
|
+
sql,
|
|
124
|
+
params,
|
|
125
|
+
schemaId,
|
|
126
|
+
cachedSchema: cached || null,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Get all cached schemas.
|
|
131
|
+
*/
|
|
132
|
+
async listSchemas() {
|
|
133
|
+
return this.cache.listAll();
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Get a specific cached schema.
|
|
137
|
+
*/
|
|
138
|
+
async getSchema(schemaId) {
|
|
139
|
+
return this.cache.get(schemaId);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Delete a cached schema.
|
|
143
|
+
*/
|
|
144
|
+
async deleteSchema(schemaId) {
|
|
145
|
+
await this.cache.delete(schemaId);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Pin a schema to prevent eviction.
|
|
149
|
+
*/
|
|
150
|
+
async pinSchema(schemaId) {
|
|
151
|
+
await this.cache.pin(schemaId);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Unpin a schema.
|
|
155
|
+
*/
|
|
156
|
+
async unpinSchema(schemaId) {
|
|
157
|
+
await this.cache.unpin(schemaId);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Get cache statistics.
|
|
161
|
+
*/
|
|
162
|
+
async getCacheStats() {
|
|
163
|
+
const l1Stats = this.l1Cache?.getStats() ?? { size: 0, hits: 0, misses: 0 };
|
|
164
|
+
const l2Stats = this.l2Cache?.getStats() ?? { size: 0, hits: 0, misses: 0 };
|
|
165
|
+
const totalQueries = l1Stats.hits + l1Stats.misses;
|
|
166
|
+
const l1Hits = l1Stats.hits;
|
|
167
|
+
const l2Hits = l2Stats.hits;
|
|
168
|
+
const l3Calls = l2Stats.misses;
|
|
169
|
+
// Calculate cost savings
|
|
170
|
+
// L1 saves $0.01 per hit
|
|
171
|
+
// L2 saves $0.01 - $0.0001 = $0.0099 per hit
|
|
172
|
+
const estimatedCostSaved = l1Hits * 0.01 + l2Hits * 0.0099;
|
|
173
|
+
return {
|
|
174
|
+
l1: l1Stats,
|
|
175
|
+
l2: l2Stats,
|
|
176
|
+
l3: { calls: l3Calls },
|
|
177
|
+
totalQueries,
|
|
178
|
+
hitRates: {
|
|
179
|
+
l1: totalQueries > 0 ? l1Hits / totalQueries : 0,
|
|
180
|
+
l2: totalQueries > 0 ? l2Hits / totalQueries : 0,
|
|
181
|
+
l3: totalQueries > 0 ? l3Calls / totalQueries : 0,
|
|
182
|
+
},
|
|
183
|
+
estimatedCostSaved,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Get list of all database tables.
|
|
188
|
+
*/
|
|
189
|
+
async getTables() {
|
|
190
|
+
return this.inspector.tables();
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Get schema for a specific table.
|
|
194
|
+
*/
|
|
195
|
+
async getTableSchema(tableName) {
|
|
196
|
+
return this.inspector.columnInfo(tableName);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Get formatted schema description for LLM prompts.
|
|
200
|
+
*/
|
|
201
|
+
getSchemaDescription() {
|
|
202
|
+
const lines = [`Database schema (${this.config.database.client}):`];
|
|
203
|
+
for (const [table, info] of Object.entries(this.schemaInfo)) {
|
|
204
|
+
const columns = info.columns.join(', ');
|
|
205
|
+
lines.push(`- ${table} (${columns})`);
|
|
206
|
+
}
|
|
207
|
+
return lines.join('\n');
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Close database connection and cleanup.
|
|
211
|
+
*/
|
|
212
|
+
async close() {
|
|
213
|
+
await this.db.destroy();
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Build schema information cache.
|
|
217
|
+
*/
|
|
218
|
+
async buildSchemaInfo() {
|
|
219
|
+
const tables = await this.getTables();
|
|
220
|
+
for (const table of tables) {
|
|
221
|
+
const columns = await this.inspector.columnInfo(table);
|
|
222
|
+
this.schemaInfo[table] = {
|
|
223
|
+
columns: columns.map((col) => col.name),
|
|
224
|
+
description: `Table: ${table}`,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=NTTP.js.map
|
package/dist/NTTP.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NTTP.js","sourceRoot":"","sources":["../src/NTTP.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* L1 Exact Match Cache
|
|
3
|
+
* Fast hash-based cache for identical queries
|
|
4
|
+
*/
|
|
5
|
+
import type { CachedResult, LayerStats } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* L1 exact match cache using Map with LRU eviction
|
|
8
|
+
*/
|
|
9
|
+
export declare class ExactCache {
|
|
10
|
+
private cache;
|
|
11
|
+
private accessOrder;
|
|
12
|
+
private accessCounter;
|
|
13
|
+
private maxSize;
|
|
14
|
+
private hits;
|
|
15
|
+
private misses;
|
|
16
|
+
constructor(maxSize?: number);
|
|
17
|
+
/**
|
|
18
|
+
* Get cached result for a query
|
|
19
|
+
*/
|
|
20
|
+
get(query: string): CachedResult | null;
|
|
21
|
+
/**
|
|
22
|
+
* Set cached result for a query
|
|
23
|
+
*/
|
|
24
|
+
set(query: string, result: CachedResult): void;
|
|
25
|
+
/**
|
|
26
|
+
* Clear all cached results
|
|
27
|
+
*/
|
|
28
|
+
clear(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Get cache statistics
|
|
31
|
+
*/
|
|
32
|
+
getStats(): LayerStats;
|
|
33
|
+
/**
|
|
34
|
+
* Normalize query string for consistent cache keys
|
|
35
|
+
* - Convert to lowercase
|
|
36
|
+
* - Trim whitespace
|
|
37
|
+
* - Collapse multiple spaces
|
|
38
|
+
* - Hash to fixed-length key
|
|
39
|
+
*/
|
|
40
|
+
private normalizeQuery;
|
|
41
|
+
/**
|
|
42
|
+
* Evict least recently used entry
|
|
43
|
+
*/
|
|
44
|
+
private evictLRU;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=exact-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exact-cache.d.ts","sourceRoot":"","sources":["../../src/cache/exact-cache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE3D;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,MAAM,CAAK;gBAEP,OAAO,GAAE,MAAa;IAIlC;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAiBvC;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI;IAY9C;;OAEG;IACH,KAAK,IAAI,IAAI;IAQb;;OAEG;IACH,QAAQ,IAAI,UAAU;IAQtB;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAatB;;OAEG;IACH,OAAO,CAAC,QAAQ;CAgBjB"}
|