sql-ai-harness 0.0.0-stage → 0.1.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/.env.example +31 -0
- package/LICENSE +15 -0
- package/README.md +201 -2
- package/dist/ai/factory.d.ts +4 -0
- package/dist/ai/factory.d.ts.map +1 -0
- package/dist/ai/factory.js +48 -0
- package/dist/ai/factory.js.map +1 -0
- package/dist/ai/provider.d.ts +13 -0
- package/dist/ai/provider.d.ts.map +1 -0
- package/dist/ai/provider.js +2 -0
- package/dist/ai/provider.js.map +1 -0
- package/dist/ai/sdk-provider.d.ts +13 -0
- package/dist/ai/sdk-provider.d.ts.map +1 -0
- package/dist/ai/sdk-provider.js +29 -0
- package/dist/ai/sdk-provider.js.map +1 -0
- package/dist/cli-observer.d.ts +5 -0
- package/dist/cli-observer.d.ts.map +1 -0
- package/dist/cli-observer.js +79 -0
- package/dist/cli-observer.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +101 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +232 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/config/config.d.ts +39 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +84 -0
- package/dist/config/config.js.map +1 -0
- package/dist/context/db-context.d.ts +12 -0
- package/dist/context/db-context.d.ts.map +1 -0
- package/dist/context/db-context.js +29 -0
- package/dist/context/db-context.js.map +1 -0
- package/dist/core/agent/agent.d.ts +32 -0
- package/dist/core/agent/agent.d.ts.map +1 -0
- package/dist/core/agent/agent.js +323 -0
- package/dist/core/agent/agent.js.map +1 -0
- package/dist/core/agent/index.d.ts +4 -0
- package/dist/core/agent/index.d.ts.map +1 -0
- package/dist/core/agent/index.js +2 -0
- package/dist/core/agent/index.js.map +1 -0
- package/dist/core/agent/observability.d.ts +19 -0
- package/dist/core/agent/observability.d.ts.map +1 -0
- package/dist/core/agent/observability.js +4 -0
- package/dist/core/agent/observability.js.map +1 -0
- package/dist/core/tools/describe-table.d.ts +6 -0
- package/dist/core/tools/describe-table.d.ts.map +1 -0
- package/dist/core/tools/describe-table.js +25 -0
- package/dist/core/tools/describe-table.js.map +1 -0
- package/dist/core/tools/describe-tables.d.ts +6 -0
- package/dist/core/tools/describe-tables.d.ts.map +1 -0
- package/dist/core/tools/describe-tables.js +22 -0
- package/dist/core/tools/describe-tables.js.map +1 -0
- package/dist/core/tools/execute-query.d.ts +6 -0
- package/dist/core/tools/execute-query.d.ts.map +1 -0
- package/dist/core/tools/execute-query.js +31 -0
- package/dist/core/tools/execute-query.js.map +1 -0
- package/dist/core/tools/explain-query.d.ts +10 -0
- package/dist/core/tools/explain-query.d.ts.map +1 -0
- package/dist/core/tools/explain-query.js +34 -0
- package/dist/core/tools/explain-query.js.map +1 -0
- package/dist/core/tools/get-relationships.d.ts +6 -0
- package/dist/core/tools/get-relationships.d.ts.map +1 -0
- package/dist/core/tools/get-relationships.js +23 -0
- package/dist/core/tools/get-relationships.js.map +1 -0
- package/dist/core/tools/index.d.ts +9 -0
- package/dist/core/tools/index.d.ts.map +1 -0
- package/dist/core/tools/index.js +8 -0
- package/dist/core/tools/index.js.map +1 -0
- package/dist/core/tools/list-tables.d.ts +3 -0
- package/dist/core/tools/list-tables.d.ts.map +1 -0
- package/dist/core/tools/list-tables.js +18 -0
- package/dist/core/tools/list-tables.js.map +1 -0
- package/dist/core/tools/registry.d.ts +11 -0
- package/dist/core/tools/registry.d.ts.map +1 -0
- package/dist/core/tools/registry.js +48 -0
- package/dist/core/tools/registry.js.map +1 -0
- package/dist/core/types/index.d.ts +94 -0
- package/dist/core/types/index.d.ts.map +1 -0
- package/dist/core/types/index.js +6 -0
- package/dist/core/types/index.js.map +1 -0
- package/dist/database/adapter.d.ts +3 -0
- package/dist/database/adapter.d.ts.map +1 -0
- package/dist/database/adapter.js +2 -0
- package/dist/database/adapter.js.map +1 -0
- package/dist/database/index.d.ts +4 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +2 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/mysql/adapter.d.ts +21 -0
- package/dist/database/mysql/adapter.d.ts.map +1 -0
- package/dist/database/mysql/adapter.js +140 -0
- package/dist/database/mysql/adapter.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/safety/limits.d.ts +7 -0
- package/dist/safety/limits.d.ts.map +1 -0
- package/dist/safety/limits.js +15 -0
- package/dist/safety/limits.js.map +1 -0
- package/dist/safety/policy.d.ts +8 -0
- package/dist/safety/policy.d.ts.map +1 -0
- package/dist/safety/policy.js +11 -0
- package/dist/safety/policy.js.map +1 -0
- package/dist/safety/sql-validator.d.ts +15 -0
- package/dist/safety/sql-validator.d.ts.map +1 -0
- package/dist/safety/sql-validator.js +31 -0
- package/dist/safety/sql-validator.js.map +1 -0
- package/dist/schema/cache.d.ts +24 -0
- package/dist/schema/cache.d.ts.map +1 -0
- package/dist/schema/cache.js +56 -0
- package/dist/schema/cache.js.map +1 -0
- package/package.json +75 -3
- package/sql-ai.example.md +32 -0
package/.env.example
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# AI provider: openrouter | groq | google | cerebras | ollama
|
|
2
|
+
AI_PROVIDER=openrouter
|
|
3
|
+
AI_MODEL=your-model-id
|
|
4
|
+
|
|
5
|
+
# Set the key for the selected provider only.
|
|
6
|
+
OPENROUTER_API_KEY=
|
|
7
|
+
GROQ_API_KEY=
|
|
8
|
+
GOOGLE_GENERATIVE_AI_API_KEY=
|
|
9
|
+
CEREBRAS_API_KEY=
|
|
10
|
+
|
|
11
|
+
# Ollama-compatible OpenAI API endpoint (used when AI_PROVIDER=ollama)
|
|
12
|
+
OLLAMA_BASE_URL=http://localhost:11434/v1
|
|
13
|
+
|
|
14
|
+
# Optional OpenRouter application metadata
|
|
15
|
+
AI_SITE_URL=
|
|
16
|
+
AI_SITE_NAME=SQL AI Harness
|
|
17
|
+
|
|
18
|
+
# MySQL connection (the current CLI adapter supports MySQL)
|
|
19
|
+
DB_DRIVER=mysql
|
|
20
|
+
DB_HOST=127.0.0.1
|
|
21
|
+
DB_PORT=3306
|
|
22
|
+
DB_NAME=your_database
|
|
23
|
+
DB_USER=your_read_only_user
|
|
24
|
+
DB_PASSWORD=
|
|
25
|
+
|
|
26
|
+
# Safety and runtime limits
|
|
27
|
+
SQL_MAX_ROWS=500
|
|
28
|
+
SQL_QUERY_TIMEOUT_MS=10000
|
|
29
|
+
SQL_MAX_RESULT_BYTES=1048576
|
|
30
|
+
AGENT_MAX_STEPS=8
|
|
31
|
+
SCHEMA_CACHE_TTL_MS=300000
|
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, NegusDev
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
14
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
+
PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,202 @@
|
|
|
1
|
-
#
|
|
1
|
+
# SQL AI Harness
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Open-source, privacy-first AI integration layer for existing relational databases.
|
|
4
|
+
|
|
5
|
+
## CLI and TypeScript SDK
|
|
6
|
+
|
|
7
|
+
The package provides a CLI and a supported TypeScript SDK entry point. The CLI currently connects to MySQL; the SDK accepts a `DatabaseAdapter` implementation so applications can supply their own database integration.
|
|
8
|
+
|
|
9
|
+
### Run from a checkout
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm install
|
|
13
|
+
cp .env.example .env
|
|
14
|
+
pnpm dev ask "List active users"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Configure the AI provider and database values in `.env`. Use a database account with read-only permissions. Schema information and query results may be sent to the selected AI provider as part of inference; configure the provider according to your data-handling requirements.
|
|
18
|
+
|
|
19
|
+
### Build and run the packaged CLI
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm build
|
|
23
|
+
node dist/cli.js ask "List active users"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
After the package is published, install it globally with:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install --global sql-ai-harness
|
|
30
|
+
sql-ai-harness ask "List active users"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The CLI reads configuration from environment variables and a `.env` file in the current working directory. See `.env.example` for the supported options.
|
|
34
|
+
|
|
35
|
+
### Use the TypeScript SDK
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import {
|
|
39
|
+
Agent,
|
|
40
|
+
MySqlAdapter,
|
|
41
|
+
createAiProvider,
|
|
42
|
+
loadConfig,
|
|
43
|
+
} from "sql-ai-harness";
|
|
44
|
+
|
|
45
|
+
const config = loadConfig();
|
|
46
|
+
const database = new MySqlAdapter({
|
|
47
|
+
host: config.database.host,
|
|
48
|
+
port: config.database.port,
|
|
49
|
+
database: config.database.name,
|
|
50
|
+
user: config.database.user,
|
|
51
|
+
password: config.database.password,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const provider = createAiProvider(config.ai);
|
|
55
|
+
const agent = new Agent(
|
|
56
|
+
provider,
|
|
57
|
+
{ database, safety: config.safety },
|
|
58
|
+
{ maxSteps: config.agent.maxSteps, responseMode: "natural" },
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const result = await agent.ask("List active users");
|
|
63
|
+
console.log(result.text);
|
|
64
|
+
} finally {
|
|
65
|
+
await database.close();
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The SDK also exports `DatabaseAdapter`, `ToolContext`, agent result/options types, provider interfaces, observer types, and `SchemaCache`. Consumers should import from `sql-ai-harness`, not internal `src/` paths. `createAiProvider` supports the providers configured by the current project; the available database adapter in this release is MySQL.
|
|
70
|
+
|
|
71
|
+
### Package development checks
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pnpm typecheck
|
|
75
|
+
pnpm test
|
|
76
|
+
pnpm build
|
|
77
|
+
npm pack --dry-run
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## CLI behavior
|
|
81
|
+
|
|
82
|
+
The current milestone wires the CLI, OpenRouter, the database adapter, safety layer,
|
|
83
|
+
and database tools into a multi-step agent loop.
|
|
84
|
+
|
|
85
|
+
### Setup
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pnpm install
|
|
89
|
+
cp .env.example .env
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Configure at minimum:
|
|
93
|
+
|
|
94
|
+
```env
|
|
95
|
+
OPENROUTER_API_KEY=your-key
|
|
96
|
+
AI_MODEL=your-openrouter-model
|
|
97
|
+
DB_NAME=your_database
|
|
98
|
+
DB_USER=read_only_user
|
|
99
|
+
DB_PASSWORD=your_password
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The database connection currently supports MySQL.
|
|
103
|
+
|
|
104
|
+
### Ask a question
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
pnpm dev ask "How many students are enrolled?"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The agent can use:
|
|
111
|
+
|
|
112
|
+
- `list_tables`
|
|
113
|
+
- `describe_table`
|
|
114
|
+
- `get_relationships`
|
|
115
|
+
- `execute_query`
|
|
116
|
+
- `explain_query`
|
|
117
|
+
|
|
118
|
+
Only read-only SQL is allowed by the safety layer.
|
|
119
|
+
|
|
120
|
+
### Validation
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
pnpm typecheck
|
|
124
|
+
pnpm test
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Optional database context
|
|
128
|
+
|
|
129
|
+
The harness works without any database context file. If you want to give the
|
|
130
|
+
agent additional knowledge about the business/domain represented by your
|
|
131
|
+
existing database, create a `sql-ai.md` file in the project directory.
|
|
132
|
+
|
|
133
|
+
For example:
|
|
134
|
+
|
|
135
|
+
```md
|
|
136
|
+
# Database Context
|
|
137
|
+
|
|
138
|
+
## Overview
|
|
139
|
+
|
|
140
|
+
This database belongs to a school management system. It stores information
|
|
141
|
+
about students, parents, teachers, classes, enrollments and payments.
|
|
142
|
+
|
|
143
|
+
## Business Rules
|
|
144
|
+
|
|
145
|
+
- Only active enrollments represent currently enrolled students.
|
|
146
|
+
- Completed payments are considered successful payments.
|
|
147
|
+
- Cancelled payments should not be included in revenue.
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
The file is optional. Without it, the harness relies on the database schema,
|
|
151
|
+
relationships, query results and other available tools exactly as before.
|
|
152
|
+
With it, the agent has additional user-defined business/domain knowledge.
|
|
153
|
+
|
|
154
|
+
A template is included as `sql-ai.example.md`.
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
## Query correctness safeguards
|
|
158
|
+
|
|
159
|
+
The agent now requires a successful global foreign-key discovery call before it can execute SQL. This ensures the model has access to the database relationship map during query planning. The system instructions also require it to plan relevant tables, use explicit FK-backed joins when related entities are needed, select meaningful descriptive columns for entity-list requests, and compare query results with the original question before answering.
|
|
160
|
+
|
|
161
|
+
SQL execution is capped at three attempts per question so the agent can correct an invalid or inadequate query without retrying indefinitely. These controls improve the agent's behavior, but the FK map is not yet a full SQL AST-level proof that every generated JOIN follows a declared foreign key; databases with undeclared relationships or complex SQL still need live testing.
|
|
162
|
+
|
|
163
|
+
## Response modes
|
|
164
|
+
|
|
165
|
+
The CLI supports three response modes:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
pnpm dev ask "How much revenue did we make last month?"
|
|
169
|
+
pnpm dev ask --mode technical "How much revenue did we make last month?"
|
|
170
|
+
pnpm dev ask --mode debug "How much revenue did we make last month?"
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
- `natural` (default): concise, business-friendly answers without unnecessary SQL details.
|
|
174
|
+
- `technical`: includes useful SQL and technical details when relevant.
|
|
175
|
+
- `debug`: technical answer plus tool execution diagnostics and timings.
|
|
176
|
+
|
|
177
|
+
The shorthand flags `--technical` and `--debug` are also supported.
|
|
178
|
+
|
|
179
|
+
## Schema discovery and caching
|
|
180
|
+
|
|
181
|
+
The agent can describe several relevant tables in one tool call using `describe_tables`,
|
|
182
|
+
which avoids unnecessary sequential schema calls when a question involves multiple tables.
|
|
183
|
+
|
|
184
|
+
Schema metadata is also cached in memory for five minutes by default. The cache covers
|
|
185
|
+
table listings, table descriptions, and global foreign-key relationships. Query results are
|
|
186
|
+
never cached. Configure the TTL with `SCHEMA_CACHE_TTL_MS`.
|
|
187
|
+
|
|
188
|
+
The cache is process-local and is cleared when the CLI process exits. This keeps the
|
|
189
|
+
current CLI simple while reducing repeated metadata queries during an agent run or future
|
|
190
|
+
long-lived interfaces.
|
|
191
|
+
|
|
192
|
+
## Evaluation and benchmarking
|
|
193
|
+
|
|
194
|
+
The `evals/` directory contains the fixed benchmark dataset, runner, and saved reports used to evaluate the harness. The runner records structured tool events, database execution attempts, latency, result equivalence, and configured answer checks. See [`evals/README.md`](evals/README.md) for dataset setup and scoring details.
|
|
195
|
+
|
|
196
|
+
Run the benchmark against a disposable evaluation database, using the same provider/model, configuration, database snapshot, and dataset when comparing versions:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
pnpm eval -- --tag local-check
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
A passing benchmark is evidence for the tested cases, not a guarantee of correctness for every schema or question. Review the generated JSON and Markdown reports when changing query-planning, tool, or safety behavior.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/ai/factory.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,GAAG,UAAU,CAwDpE"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createOpenRouter } from '@openrouter/ai-sdk-provider';
|
|
2
|
+
import { createGroq } from '@ai-sdk/groq';
|
|
3
|
+
import { createGoogleGenerativeAI } from '@ai-sdk/google';
|
|
4
|
+
import { createCerebras } from '@ai-sdk/cerebras';
|
|
5
|
+
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
|
|
6
|
+
import { SdkAiProvider } from './sdk-provider.js';
|
|
7
|
+
export function createAiProvider(config) {
|
|
8
|
+
switch (config.provider) {
|
|
9
|
+
case 'openrouter': {
|
|
10
|
+
const provider = createOpenRouter({
|
|
11
|
+
apiKey: config.apiKey,
|
|
12
|
+
...(config.siteUrl ? { appUrl: config.siteUrl } : {}),
|
|
13
|
+
...(config.siteName ? { appName: config.siteName } : {}),
|
|
14
|
+
});
|
|
15
|
+
return new SdkAiProvider('openrouter', provider.chat(config.model));
|
|
16
|
+
}
|
|
17
|
+
case 'groq': {
|
|
18
|
+
const provider = createGroq({
|
|
19
|
+
apiKey: config.apiKey,
|
|
20
|
+
});
|
|
21
|
+
return new SdkAiProvider('groq', provider(config.model));
|
|
22
|
+
}
|
|
23
|
+
case 'google': {
|
|
24
|
+
const provider = createGoogleGenerativeAI({
|
|
25
|
+
apiKey: config.apiKey,
|
|
26
|
+
});
|
|
27
|
+
return new SdkAiProvider('google', provider(config.model));
|
|
28
|
+
}
|
|
29
|
+
case 'cerebras': {
|
|
30
|
+
const provider = createCerebras({
|
|
31
|
+
apiKey: config.apiKey,
|
|
32
|
+
});
|
|
33
|
+
return new SdkAiProvider('cerebras', provider(config.model));
|
|
34
|
+
}
|
|
35
|
+
case 'ollama': {
|
|
36
|
+
const provider = createOpenAICompatible({
|
|
37
|
+
name: 'ollama',
|
|
38
|
+
baseURL: config.baseUrl ?? 'http://localhost:11434/v1',
|
|
39
|
+
});
|
|
40
|
+
return new SdkAiProvider('ollama', provider.chatModel(config.model));
|
|
41
|
+
}
|
|
42
|
+
default: {
|
|
43
|
+
const exhaustiveCheck = config.provider;
|
|
44
|
+
throw new Error(`Unsupported AI provider: ${exhaustiveCheck}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/ai/factory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAInE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,MAAM,UAAU,gBAAgB,CAAC,MAAuB;IACtD,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,KAAK,YAAY,EAAE,CAAC;YAClB,MAAM,QAAQ,GAAG,gBAAgB,CAAC;gBAChC,MAAM,EAAE,MAAM,CAAC,MAAO;gBACtB,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACrD,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACzD,CAAC,CAAC;YAEH,OAAO,IAAI,aAAa,CACtB,YAAY,EACZ,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAC5B,CAAC;QACJ,CAAC;QAED,KAAK,MAAM,EAAE,CAAC;YACZ,MAAM,QAAQ,GAAG,UAAU,CAAC;gBAC1B,MAAM,EAAE,MAAM,CAAC,MAAO;aACvB,CAAC,CAAC;YAEH,OAAO,IAAI,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3D,CAAC;QAED,KAAK,QAAQ,EAAE,CAAC;YACd,MAAM,QAAQ,GAAG,wBAAwB,CAAC;gBACxC,MAAM,EAAE,MAAM,CAAC,MAAO;aACvB,CAAC,CAAC;YAEH,OAAO,IAAI,aAAa,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7D,CAAC;QAED,KAAK,UAAU,EAAE,CAAC;YAChB,MAAM,QAAQ,GAAG,cAAc,CAAC;gBAC9B,MAAM,EAAE,MAAM,CAAC,MAAO;aACvB,CAAC,CAAC;YAEH,OAAO,IAAI,aAAa,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/D,CAAC;QAED,KAAK,QAAQ,EAAE,CAAC;YACd,MAAM,QAAQ,GAAG,sBAAsB,CAAC;gBACtC,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,2BAA2B;aACvD,CAAC,CAAC;YAEH,OAAO,IAAI,aAAa,CACtB,QAAQ,EACR,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CACjC,CAAC;QACJ,CAAC;QAED,SAAS,CAAC;YACR,MAAM,eAAe,GAAU,MAAM,CAAC,QAAQ,CAAC;YAC/C,MAAM,IAAI,KAAK,CAAC,4BAA4B,eAAe,EAAE,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ToolSet } from 'ai';
|
|
2
|
+
import type { ModelProvider, ModelRequest, ModelResponse } from '../core/types/index.js';
|
|
3
|
+
export type { ModelProvider, ModelRequest, ModelResponse };
|
|
4
|
+
export interface AiProvider extends ModelProvider {
|
|
5
|
+
generate(request: ModelRequest & {
|
|
6
|
+
tools?: ToolSet;
|
|
7
|
+
maxSteps?: number;
|
|
8
|
+
}): Promise<ModelResponse & {
|
|
9
|
+
steps?: number;
|
|
10
|
+
toolCalls?: number;
|
|
11
|
+
}>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/ai/provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEzF,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC;AAE3D,MAAM,WAAW,UAAW,SAAQ,aAAa;IAC/C,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,aAAa,GAAG;QAChG,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/ai/provider.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type LanguageModel, type ToolSet } from 'ai';
|
|
2
|
+
import type { ModelRequest, ModelResponse } from '../core/types/index.js';
|
|
3
|
+
import type { AiProvider } from './provider.js';
|
|
4
|
+
export declare class SdkAiProvider implements AiProvider {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
private readonly model;
|
|
7
|
+
constructor(name: string, model: LanguageModel);
|
|
8
|
+
generate(request: ModelRequest & {
|
|
9
|
+
tools?: ToolSet;
|
|
10
|
+
maxSteps?: number;
|
|
11
|
+
}): Promise<ModelResponse>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=sdk-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk-provider.d.ts","sourceRoot":"","sources":["../../src/ai/sdk-provider.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,OAAO,EACb,MAAM,IAAI,CAAC;AAEZ,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,qBAAa,aAAc,YAAW,UAAU;IAE5C,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAFxB,YACW,IAAI,EAAE,MAAM,EACJ,KAAK,EAAE,aAAa,EACnC;IAEE,QAAQ,CACZ,OAAO,EAAE,YAAY,GAAG;QACtB,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GACA,OAAO,CAAC,aAAa,CAAC,CAuBxB;CACF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { generateText, isStepCount, } from 'ai';
|
|
2
|
+
export class SdkAiProvider {
|
|
3
|
+
name;
|
|
4
|
+
model;
|
|
5
|
+
constructor(name, model) {
|
|
6
|
+
this.name = name;
|
|
7
|
+
this.model = model;
|
|
8
|
+
}
|
|
9
|
+
async generate(request) {
|
|
10
|
+
const result = await generateText({
|
|
11
|
+
model: this.model,
|
|
12
|
+
system: request.system,
|
|
13
|
+
prompt: request.prompt,
|
|
14
|
+
tools: request.tools,
|
|
15
|
+
stopWhen: request.maxSteps
|
|
16
|
+
? isStepCount(request.maxSteps)
|
|
17
|
+
: undefined,
|
|
18
|
+
temperature: request.temperature,
|
|
19
|
+
});
|
|
20
|
+
const toolCalls = result.steps.reduce((count, step) => count + (step.toolCalls?.length ?? 0), 0);
|
|
21
|
+
return {
|
|
22
|
+
text: result.text,
|
|
23
|
+
raw: result,
|
|
24
|
+
steps: result.steps.length,
|
|
25
|
+
toolCalls,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=sdk-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk-provider.js","sourceRoot":"","sources":["../../src/ai/sdk-provider.ts"],"names":[],"mappings":"AACA,OAAO,EACL,YAAY,EACZ,WAAW,GAGZ,MAAM,IAAI,CAAC;AAKZ,MAAM,OAAO,aAAa;IAEb,IAAI;IACI,KAAK;IAFxB,YACW,IAAY,EACJ,KAAoB;oBAD5B,IAAI;qBACI,KAAK;IACrB,CAAC;IAEJ,KAAK,CAAC,QAAQ,CACZ,OAGC;QAED,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC;YAChC,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBACxB,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC;gBAC/B,CAAC,CAAC,SAAS;YACb,WAAW,EAAE,OAAO,CAAC,WAAW;SACjC,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CACnC,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,IAAI,CAAC,CAAC,EACtD,CAAC,CACF,CAAC;QAEF,OAAO;YACL,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,GAAG,EAAE,MAAM;YACX,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM;YAC1B,SAAS;SACV,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-observer.d.ts","sourceRoot":"","sources":["../src/cli-observer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,cAAc,EACf,MAAM,+BAA+B,CAAC;AA8DvC,qBAAa,gBAAiB,YAAW,aAAa;IACpD,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAyCvC;CACF"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
function formatInput(input) {
|
|
3
|
+
if (!input || typeof input !== 'object') {
|
|
4
|
+
return String(input ?? '');
|
|
5
|
+
}
|
|
6
|
+
const value = input;
|
|
7
|
+
if (typeof value.sql === 'string') {
|
|
8
|
+
return value.sql;
|
|
9
|
+
}
|
|
10
|
+
return JSON.stringify(value);
|
|
11
|
+
}
|
|
12
|
+
function getRowCount(data) {
|
|
13
|
+
if (!data || typeof data !== 'object')
|
|
14
|
+
return undefined;
|
|
15
|
+
const value = data;
|
|
16
|
+
if (typeof value.rowCount === 'number') {
|
|
17
|
+
return value.rowCount;
|
|
18
|
+
}
|
|
19
|
+
if (Array.isArray(value.rows)) {
|
|
20
|
+
return value.rows.length;
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
function emitStructuredEvent(event) {
|
|
25
|
+
if (process.env.SQL_AI_TRACE_JSON !== '1')
|
|
26
|
+
return;
|
|
27
|
+
if (event.type !== 'tool-end')
|
|
28
|
+
return;
|
|
29
|
+
try {
|
|
30
|
+
const json = JSON.stringify({
|
|
31
|
+
source: 'sql-ai-harness',
|
|
32
|
+
...event,
|
|
33
|
+
}, (_key, value) => typeof value === 'bigint' ? value.toString() : value);
|
|
34
|
+
if (json) {
|
|
35
|
+
// One complete JSON object per line, on stderr.
|
|
36
|
+
console.error(json);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.error(JSON.stringify({
|
|
41
|
+
source: 'sql-ai-harness',
|
|
42
|
+
type: 'trace-serialization-error',
|
|
43
|
+
message: error instanceof Error ? error.message : String(error),
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export class CliAgentObserver {
|
|
48
|
+
onToolEvent(event) {
|
|
49
|
+
// Emit the structured event before the human-readable diagnostic.
|
|
50
|
+
emitStructuredEvent(event);
|
|
51
|
+
if (event.type === 'tool-start') {
|
|
52
|
+
console.error(`\n[tool] ${event.name}`);
|
|
53
|
+
const input = formatInput(event.input);
|
|
54
|
+
if (!input)
|
|
55
|
+
return;
|
|
56
|
+
if (typeof event.input === 'object' &&
|
|
57
|
+
event.input !== null &&
|
|
58
|
+
'sql' in event.input) {
|
|
59
|
+
console.error('[sql]');
|
|
60
|
+
console.error(input);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
console.error(`[input] ${input}`);
|
|
64
|
+
}
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (event.success) {
|
|
68
|
+
const rowCount = getRowCount(event.data);
|
|
69
|
+
const rows = rowCount === undefined
|
|
70
|
+
? ''
|
|
71
|
+
: `, ${rowCount} row${rowCount === 1 ? '' : 's'}`;
|
|
72
|
+
console.error(`[done] ${event.name} (${event.durationMs}ms${rows})`);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
console.error(`[error] ${event.name} (${event.durationMs}ms): ${event.error ?? 'Unknown error'}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=cli-observer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-observer.js","sourceRoot":"","sources":["../src/cli-observer.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Agent } from './core/agent/index.js';
|
|
3
|
+
import { loadConfig } from './config/config.js';
|
|
4
|
+
import { MySqlAdapter } from './database/index.js';
|
|
5
|
+
import { createAiProvider } from './ai/factory.js';
|
|
6
|
+
import { CliAgentObserver } from './cli-observer.js';
|
|
7
|
+
import { SchemaCache } from './schema/cache.js';
|
|
8
|
+
import { loadDatabaseContext } from './context/db-context.js';
|
|
9
|
+
import { runInit } from './commands/init.js';
|
|
10
|
+
function printUsage() {
|
|
11
|
+
console.log(`Usage:
|
|
12
|
+
sql-ai-harness init [--force]
|
|
13
|
+
sql-ai-harness ask [--mode natural|technical|debug] "your question"
|
|
14
|
+
|
|
15
|
+
Modes:
|
|
16
|
+
natural Business-friendly answer (default)
|
|
17
|
+
technical Include useful SQL and technical details
|
|
18
|
+
debug Technical answer plus tool execution diagnostics`);
|
|
19
|
+
}
|
|
20
|
+
function parseAskArgs(args) {
|
|
21
|
+
let mode = 'natural';
|
|
22
|
+
const questionParts = [];
|
|
23
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
24
|
+
const arg = args[i];
|
|
25
|
+
if (arg === '--mode') {
|
|
26
|
+
const value = args[++i];
|
|
27
|
+
if (value !== 'natural' && value !== 'technical' && value !== 'debug') {
|
|
28
|
+
throw new Error('Invalid response mode. Use natural, technical, or debug.');
|
|
29
|
+
}
|
|
30
|
+
mode = value;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (arg === '--technical') {
|
|
34
|
+
mode = 'technical';
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (arg === '--debug') {
|
|
38
|
+
mode = 'debug';
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
questionParts.push(arg);
|
|
42
|
+
}
|
|
43
|
+
return { mode, question: questionParts.join(' ').trim() };
|
|
44
|
+
}
|
|
45
|
+
async function main() {
|
|
46
|
+
const [command, ...args] = process.argv.slice(2);
|
|
47
|
+
if (command === 'init') {
|
|
48
|
+
await runInit(args);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (command !== 'ask') {
|
|
52
|
+
printUsage();
|
|
53
|
+
process.exitCode = command ? 1 : 0;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const { mode, question } = parseAskArgs(args);
|
|
57
|
+
if (!question) {
|
|
58
|
+
console.error('Error: a question is required.');
|
|
59
|
+
process.exitCode = 1;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const config = loadConfig();
|
|
63
|
+
if (config.database.driver !== 'mysql') {
|
|
64
|
+
throw new Error(`Database driver "${config.database.driver}" is not implemented yet. M4 currently supports MySQL.`);
|
|
65
|
+
}
|
|
66
|
+
const database = new MySqlAdapter({
|
|
67
|
+
host: config.database.host,
|
|
68
|
+
port: config.database.port,
|
|
69
|
+
database: config.database.name,
|
|
70
|
+
user: config.database.user,
|
|
71
|
+
password: config.database.password,
|
|
72
|
+
});
|
|
73
|
+
const provider = createAiProvider(config.ai);
|
|
74
|
+
const databaseContext = await loadDatabaseContext();
|
|
75
|
+
const schemaCache = new SchemaCache({ ttlMs: config.schema.cacheTtlMs });
|
|
76
|
+
const agent = new Agent(provider, {
|
|
77
|
+
database,
|
|
78
|
+
safety: config.safety,
|
|
79
|
+
schemaCache,
|
|
80
|
+
}, {
|
|
81
|
+
maxSteps: config.agent.maxSteps,
|
|
82
|
+
observer: mode === 'debug' ? new CliAgentObserver() : undefined,
|
|
83
|
+
databaseContext,
|
|
84
|
+
responseMode: mode,
|
|
85
|
+
});
|
|
86
|
+
try {
|
|
87
|
+
const result = await agent.ask(question);
|
|
88
|
+
console.log('\n' + result.text);
|
|
89
|
+
if (mode === 'debug') {
|
|
90
|
+
console.error(`\n[agent] ${result.steps} step${result.steps === 1 ? '' : 's'}, ${result.toolCalls} tool call${result.toolCalls === 1 ? '' : 's'}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
await database.close();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
main().catch((error) => {
|
|
98
|
+
console.error(`\nError: ${error instanceof Error ? error.message : String(error)}`);
|
|
99
|
+
process.exitCode = 1;
|
|
100
|
+
});
|
|
101
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AA+GA,wBAAsB,OAAO,CAAC,IAAI,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAiHhE"}
|