@negusdev/dbask 0.0.0-stage → 0.1.8
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/CHANGELOG.md +40 -0
- package/LICENSE +15 -0
- package/README.md +422 -2
- package/dist/ai/factory.d.ts +4 -0
- package/dist/ai/factory.d.ts.map +1 -0
- package/dist/ai/factory.js +55 -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 +36 -0
- package/dist/ai/sdk-provider.js.map +1 -0
- package/dist/cli-args.d.ts +26 -0
- package/dist/cli-args.d.ts.map +1 -0
- package/dist/cli-args.js +72 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli-observer.d.ts +23 -0
- package/dist/cli-observer.d.ts.map +1 -0
- package/dist/cli-observer.js +224 -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 +127 -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 +247 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/validate.d.ts +31 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +205 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/config/config.d.ts +42 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +94 -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 +57 -0
- package/dist/core/agent/agent.d.ts.map +1 -0
- package/dist/core/agent/agent.js +518 -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/agent/query-plan.d.ts +68 -0
- package/dist/core/agent/query-plan.d.ts.map +1 -0
- package/dist/core/agent/query-plan.js +282 -0
- package/dist/core/agent/query-plan.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 +102 -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/factory.d.ts +16 -0
- package/dist/database/factory.d.ts.map +1 -0
- package/dist/database/factory.js +27 -0
- package/dist/database/factory.js.map +1 -0
- package/dist/database/index.d.ts +8 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +4 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/mysql/adapter.d.ts +26 -0
- package/dist/database/mysql/adapter.d.ts.map +1 -0
- package/dist/database/mysql/adapter.js +131 -0
- package/dist/database/mysql/adapter.js.map +1 -0
- package/dist/database/postgres/adapter.d.ts +60 -0
- package/dist/database/postgres/adapter.d.ts.map +1 -0
- package/dist/database/postgres/adapter.js +307 -0
- package/dist/database/postgres/adapter.js.map +1 -0
- package/dist/database/result-limits.d.ts +17 -0
- package/dist/database/result-limits.d.ts.map +1 -0
- package/dist/database/result-limits.js +26 -0
- package/dist/database/result-limits.js.map +1 -0
- package/dist/index.d.ts +20 -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-tokenizer.d.ts +49 -0
- package/dist/safety/sql-tokenizer.d.ts.map +1 -0
- package/dist/safety/sql-tokenizer.js +240 -0
- package/dist/safety/sql-tokenizer.js.map +1 -0
- package/dist/safety/sql-validator.d.ts +34 -0
- package/dist/safety/sql-validator.d.ts.map +1 -0
- package/dist/safety/sql-validator.js +270 -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 +57 -0
- package/dist/schema/cache.js.map +1 -0
- package/dist/ui/markdown.d.ts +8 -0
- package/dist/ui/markdown.d.ts.map +1 -0
- package/dist/ui/markdown.js +205 -0
- package/dist/ui/markdown.js.map +1 -0
- package/dist/ui/spinner.d.ts +32 -0
- package/dist/ui/spinner.d.ts.map +1 -0
- package/dist/ui/spinner.js +74 -0
- package/dist/ui/spinner.js.map +1 -0
- package/dist/ui/sql-highlight.d.ts +4 -0
- package/dist/ui/sql-highlight.d.ts.map +1 -0
- package/dist/ui/sql-highlight.js +28 -0
- package/dist/ui/sql-highlight.js.map +1 -0
- package/dist/ui/style.d.ts +38 -0
- package/dist/ui/style.d.ts.map +1 -0
- package/dist/ui/style.js +69 -0
- package/dist/ui/style.js.map +1 -0
- package/package.json +91 -4
- package/sql-ai.example.md +32 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com), and the project uses [Semantic Versioning](https://semver.org) (0.x: minor versions may change behavior).
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- **Renamed from `sql-ai-harness` to `dbask`.** The npm package is now `@negusdev/dbask` (the unscoped name `dbask` was blocked by npm's name-similarity check) and the command is `dbask`. The `sql-ai-harness` command stays as an alias for now. You can now ask without the subcommand: `dbask "who owes us money?"` (`dbask ask "…"` still works). Mistyped options and one-word mistyped commands now print an error instead of being sent to the model, and `dbask --version` and `--help` were added. Environment variables, the `sql-ai.md` context file and the SDK API are unchanged; update imports from `"sql-ai-harness"` to `"dbask"`. The structured debug events now use `source: "dbask"`.
|
|
9
|
+
|
|
10
|
+
## [0.1.8] - 2026-11-13
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **DeepSeek provider.** Set `AI_PROVIDER=deepseek` and `DEEPSEEK_API_KEY`.
|
|
14
|
+
- **Optional query plan** (`AGENT_QUERY_PLAN=on`, or `requirePlan: true` in the SDK). The agent submits a structured plan (tables, columns, joins, filters) that is checked against your real schema before any SQL runs; the SQL may then read only the planned tables. Unknown tables or columns and unconnected tables are rejected, joins that are not declared foreign keys produce warnings, and plan submissions are capped at 4. `AgentResult.plan` reports submitted, accepted, rejected and SQL-mismatch counts. New exports: `StructuredQueryPlan`, `PlanStats`.
|
|
15
|
+
- **Terminal UI.** Progress spinner with the current step, Markdown answers rendered for the terminal (aligned tables that wrap instead of cutting ids, bold, code, lists), highlighted SQL, and a clearer `--mode debug` trace that shows the plan, plan warnings and plan counts. `validate` uses symbols and color. Piped or redirected output is unchanged; `NO_COLOR` and `FORCE_COLOR` are honored.
|
|
16
|
+
- `CONTRIBUTING.md`.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- **The query plan is off by default.** On the 40-case benchmark it added about 0.7 tool calls and roughly 30% median latency per question without improving accuracy. Turn it on with `AGENT_QUERY_PLAN=on` if you want the agent's assumptions visible. (SDK: `new Agent(..., { requirePlan: true })`; the SDK default is also off.)
|
|
20
|
+
- **The agent stays on topic.** It now declines questions that are not about the connected database (arithmetic, general knowledge, writing, instruction overrides) without calling tools or querying, and treats text found in table names, column names or row values as data, not instructions.
|
|
21
|
+
- **The agent always ends with an answer.** The last step is reserved for the final answer, and a run that cannot finish returns `AgentResult.incomplete`; the CLI prints it as an error and exits with code 1. Write requests are refused up front.
|
|
22
|
+
- Updated the Vercel AI SDK packages.
|
|
23
|
+
|
|
24
|
+
### Development
|
|
25
|
+
- Evaluation: 40-case dataset (adds four off-topic cases), value-based result comparison, tolerant answer checks, refusal scoring, provider-error retries excluded from scores, `--repeat N` with a cross-run summary, `--only`, process-group timeout kill, and run settings (model, commit, max steps, plan flag) in report headers.
|
|
26
|
+
- Benchmark result for this release: 39 of 40 cases passed in every one of three runs (`gemini-3.5-flash-lite`, synthetic database). The one consistent failure is a known reference-answer error, not an agent error. See the README for caveats.
|
|
27
|
+
|
|
28
|
+
### Upgrade notes
|
|
29
|
+
- No action needed for the CLI. If you script `submit_query_plan` directly, the plan shape changed: `fields` is a list of `{table, column}` and `joins` a list of `{left, right}`.
|
|
30
|
+
|
|
31
|
+
## [0.1.7] - 2026-11-05
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
- PostgreSQL support (tables, partitioned tables and schemas; views are not listed yet).
|
|
35
|
+
- `validate` command to check configuration, database connection, foreign keys, AI provider and `sql-ai.md`.
|
|
36
|
+
|
|
37
|
+
For earlier releases, see the [commit history](https://github.com/NegusDev/sql-ai-harness/commits/main) and the npm release list.
|
|
38
|
+
|
|
39
|
+
[0.1.8]: https://github.com/NegusDev/sql-ai-harness/compare/v0.1.7...v0.1.8
|
|
40
|
+
[0.1.7]: https://github.com/NegusDev/sql-ai-harness/releases/tag/v0.1.7
|
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,423 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dbask
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Open-source, privacy-first, self-hostable Text-to-SQL for your existing relational database.**
|
|
4
|
+
|
|
5
|
+
Ask questions in plain language about a MySQL, MariaDB, or PostgreSQL database you already have. dbask discovers the schema, gives an AI agent tools to inspect and query it, enforces execution limits, and returns an answer. No new schema, no model trained for your app, no hosted service.
|
|
6
|
+
|
|
7
|
+
Bring your own model. Run it yourself.
|
|
8
|
+
|
|
9
|
+
> dbask was previously published as `sql-ai-harness`. Install it as `@negusdev/dbask`; the command is `dbask`. The old `sql-ai-harness` command still works as an alias, and the SDK API is unchanged apart from the package name.
|
|
10
|
+
|
|
11
|
+
[](https://www.npmjs.com/package/@negusdev/dbask)
|
|
12
|
+
[](https://nodejs.org)
|
|
13
|
+
[](./LICENSE)
|
|
14
|
+
|
|
15
|
+
> **Development status:** dbask is under active development (pre-1.0, so the API may change between minor versions). Validate it against your own schema and workload before relying on it, especially for consequential decisions.
|
|
16
|
+
|
|
17
|
+
## Contents
|
|
18
|
+
|
|
19
|
+
- [Why dbask](#why-dbask)
|
|
20
|
+
- [Features](#features)
|
|
21
|
+
- [Requirements](#requirements)
|
|
22
|
+
- [Quickstart](#quickstart)
|
|
23
|
+
- [Data handling](#data-handling)
|
|
24
|
+
- [Usage](#usage)
|
|
25
|
+
- [Configuration](#configuration)
|
|
26
|
+
- [Optional database context](#optional-database-context)
|
|
27
|
+
- [TypeScript SDK](#typescript-sdk)
|
|
28
|
+
- [Database tools](#database-tools)
|
|
29
|
+
- [Safety and data handling](#safety-and-data-handling)
|
|
30
|
+
- [Database support](#database-support)
|
|
31
|
+
- [Evaluation](#evaluation)
|
|
32
|
+
- [Development](#development)
|
|
33
|
+
- [Troubleshooting](#troubleshooting)
|
|
34
|
+
- [Contributing](#contributing)
|
|
35
|
+
- [License](#license)
|
|
36
|
+
|
|
37
|
+
## Why dbask
|
|
38
|
+
|
|
39
|
+
Most Text-to-SQL tools are either a hosted service that sees your schema and data, or tightly coupled to one model and one vendor. dbask is a harness you run yourself, against a database you already own, with a model you choose.
|
|
40
|
+
|
|
41
|
+
It is a reusable layer between an AI provider and an existing relational database. It is not a new application with its own schema.
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
- **Natural-language questions** through the CLI or the TypeScript SDK.
|
|
46
|
+
- **Bring your own model:** OpenRouter, Google Gemini, DeepSeek, Groq, Cerebras, or Ollama.
|
|
47
|
+
- **Schema-aware agent** with tools for listing tables, describing tables, discovering foreign keys, running queries, and `EXPLAIN`.
|
|
48
|
+
- **Safety by default:** configurable row, byte, timeout, and agent-step limits; capped SQL attempts; foreign-key discovery required before any SQL runs.
|
|
49
|
+
- **Optional `sql-ai.md`** for business rules and vocabulary the model cannot infer from the schema.
|
|
50
|
+
- **Three response modes:** natural, technical, and debug.
|
|
51
|
+
- **`validate` command** that checks your config, database, foreign keys, and AI provider before you ask anything.
|
|
52
|
+
- **In-process schema cache** so repeated lookups in a run don't hit the database twice.
|
|
53
|
+
- **Benchmark suite** in `evals/` for reproducible evaluation of changes.
|
|
54
|
+
|
|
55
|
+
## Requirements
|
|
56
|
+
|
|
57
|
+
- **Node.js 22 or later**
|
|
58
|
+
- A **MySQL, MariaDB, or PostgreSQL** database, and an account with read access to the tables the agent should see
|
|
59
|
+
- Credentials and a model ID for one supported AI provider (or a reachable Ollama endpoint)
|
|
60
|
+
|
|
61
|
+
> SQLite, a hosted HTTP API, and SDKs for languages other than TypeScript are **not** part of this release. The SDK defines a `DatabaseAdapter` interface as the extension point; MySQL/MariaDB and PostgreSQL adapters ship today.
|
|
62
|
+
|
|
63
|
+
## Quickstart
|
|
64
|
+
|
|
65
|
+
### 1. Configure
|
|
66
|
+
|
|
67
|
+
Run the setup wizard in the directory where you want the configuration stored:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npx @negusdev/dbask init
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The wizard asks for:
|
|
74
|
+
|
|
75
|
+
- Database type (MySQL/MariaDB or PostgreSQL), host, port, database, username, and password
|
|
76
|
+
- AI provider and exact model ID
|
|
77
|
+
- An API key (hosted providers) or a base URL (Ollama)
|
|
78
|
+
- Agent step limit, SQL row limit, and schema-cache lifetime
|
|
79
|
+
|
|
80
|
+
It tests the **database connection** and lists tables before saving. It does **not** send an inference request, so a successful `init` does not prove the provider key or model ID is correct. The next step checks that.
|
|
81
|
+
|
|
82
|
+
If `.env` already exists, the wizard asks before updating harness settings and preserves unrelated entries. Skip the confirmation with `--force`:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npx @negusdev/dbask init --force
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Keep `.env` private and out of version control. The wizard writes it with restrictive permissions where supported.
|
|
89
|
+
|
|
90
|
+
### 2. Check your setup
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npx @negusdev/dbask validate
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`validate` checks your configuration, connects to the database, confirms the account can see tables and foreign keys, and sends **one tiny request** to your AI provider to confirm the key and model work. It never reads table data and never runs model-written SQL. Each line reports `[ok]`, `[warn]`, `[fail]` or `[skip]`, and the command exits with a non-zero status if anything fails, so it also works in scripts and CI.
|
|
97
|
+
|
|
98
|
+
```text
|
|
99
|
+
[ok] Configuration: provider=openrouter, model=openai/gpt-4o-mini
|
|
100
|
+
[ok] Database connection: Connected to 127.0.0.1:3306/mydb; 27 tables visible.
|
|
101
|
+
[ok] Foreign keys: 42 declared relationships found.
|
|
102
|
+
[ok] AI provider: openrouter answered using model openai/gpt-4o-mini.
|
|
103
|
+
[skip] Business context (sql-ai.md): No sql-ai.md found. This is optional.
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Use `--skip-provider` to check only the configuration and database, without contacting the AI provider.
|
|
107
|
+
|
|
108
|
+
### 3. Ask a question
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
npx @negusdev/dbask "How many students are enrolled?"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 4. Install globally (optional)
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
npm install --global @negusdev/dbask
|
|
118
|
+
dbask "List active users"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Data handling
|
|
122
|
+
|
|
123
|
+
dbask itself does not phone home. No telemetry, no crash reporting, no license check on startup, no cloud dependency. The harness runs on your machine (or your own server) and talks to your database directly.
|
|
124
|
+
|
|
125
|
+
What does leave your machine is what your chosen AI provider receives. Depending on the question and tool flow, that can include schema metadata, question text, generated SQL, and query results. Review that provider's retention, training, and residency terms before using sensitive data.
|
|
126
|
+
|
|
127
|
+
If you need local-only inference, [Ollama-compatible endpoints are supported](#ai-provider), but this path is not currently exercised in the benchmark, so validate it against your own workload first.
|
|
128
|
+
|
|
129
|
+
To reduce exposure, see [Safety and data handling](#safety-and-data-handling): read-only database accounts, row/byte/timeout limits, and a required foreign-key discovery step before any SQL runs.
|
|
130
|
+
|
|
131
|
+
## Usage
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
dbask "How much revenue last month?" # natural (default)
|
|
135
|
+
dbask --mode technical "How much revenue last month?" # answer + SQL
|
|
136
|
+
dbask --mode debug "How much revenue last month?" # answer + tool traces
|
|
137
|
+
# `dbask ask "…"` is the same as `dbask "…"`; use it for a one-word question or inside older scripts.
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Shorthand flags `--technical` and `--debug` also work.
|
|
141
|
+
|
|
142
|
+
| Mode | Output |
|
|
143
|
+
|---|---|
|
|
144
|
+
| `natural` | A concise, business-friendly answer. |
|
|
145
|
+
| `technical` | The answer plus the SQL that was run. |
|
|
146
|
+
| `debug` | The answer plus tool-call diagnostics. Start here when an answer looks wrong. |
|
|
147
|
+
|
|
148
|
+
**Terminal output.** In an interactive terminal the CLI shows a progress spinner, renders the answer's Markdown (tables, bold, code, lists) and, in debug mode, prints the tool trace with symbols, highlighted SQL, the submitted query plan and any plan warnings. When output is piped or redirected, nothing changes: you get the plain Markdown answer and the plain `[tool]` / `[done]` trace. Set `NO_COLOR=1` to turn colors off, or `FORCE_COLOR=1` to keep them in a pipe.
|
|
149
|
+
|
|
150
|
+
## Configuration
|
|
151
|
+
|
|
152
|
+
Configuration is loaded from `.env` in the current working directory plus the process environment. See `.env.example` in the repository for a full template.
|
|
153
|
+
|
|
154
|
+
### AI provider
|
|
155
|
+
|
|
156
|
+
| Variable | Purpose | Example |
|
|
157
|
+
|---|---|---|
|
|
158
|
+
| `AI_PROVIDER` | One of `openrouter`, `google`, `groq`, `cerebras`, `ollama`, `deepseek` | `openrouter` |
|
|
159
|
+
| `AI_MODEL` | Exact model ID accepted by the provider | *required* |
|
|
160
|
+
| `OPENROUTER_API_KEY` | OpenRouter credential | n/a |
|
|
161
|
+
| `GOOGLE_GENERATIVE_AI_API_KEY` | Google Gemini credential | n/a |
|
|
162
|
+
| `GROQ_API_KEY` | Groq credential | n/a |
|
|
163
|
+
| `CEREBRAS_API_KEY` | Cerebras credential | n/a |
|
|
164
|
+
| `OLLAMA_BASE_URL` | Ollama endpoint | `http://localhost:11434/v1` |
|
|
165
|
+
| `DEEPSEEK_API_KEY` | DeepSeek credential | n/a |
|
|
166
|
+
| `AI_SITE_URL` | Optional OpenRouter app URL metadata | n/a |
|
|
167
|
+
| `AI_SITE_NAME` | Optional OpenRouter app name metadata | `dbask` |
|
|
168
|
+
|
|
169
|
+
Model availability, pricing, quotas, and API behavior are controlled by each provider and can change independently of this project.
|
|
170
|
+
|
|
171
|
+
### Database
|
|
172
|
+
|
|
173
|
+
| Variable | Purpose | Default |
|
|
174
|
+
|---|---|---|
|
|
175
|
+
| `DB_DRIVER` | `mysql` (also MariaDB) or `postgres` | `mysql` |
|
|
176
|
+
| `DB_HOST` | Hostname or IP | `127.0.0.1` |
|
|
177
|
+
| `DB_PORT` | Port | `3306` for mysql, `5432` for postgres |
|
|
178
|
+
| `DB_SSL` | `disable`, `require` (encrypt, don't verify the certificate), or `verify-full` (encrypt and verify; use `NODE_EXTRA_CA_CERTS` for a private CA) | `disable` |
|
|
179
|
+
| `DB_NAME` | Database name | *required* |
|
|
180
|
+
| `DB_USER` | Username (**use a restricted read-only account**) | *required* |
|
|
181
|
+
| `DB_PASSWORD` | Password (set privately) | *required* |
|
|
182
|
+
|
|
183
|
+
### Limits
|
|
184
|
+
|
|
185
|
+
| Variable | Purpose | Default |
|
|
186
|
+
|---|---|---|
|
|
187
|
+
| `SQL_MAX_ROWS` | Max rows returned per query | `500` |
|
|
188
|
+
| `SQL_QUERY_TIMEOUT_MS` | Per-query timeout (ms) | `10000` |
|
|
189
|
+
| `SQL_MAX_RESULT_BYTES` | Max result payload size (bytes) | `1048576` |
|
|
190
|
+
| `AGENT_MAX_STEPS` | Max agent loop steps | `8` |
|
|
191
|
+
| `AGENT_QUERY_PLAN` | `on` requires a schema-checked query plan before SQL runs; `off` skips it | `off` |
|
|
192
|
+
| `SCHEMA_CACHE_TTL_MS` | Schema cache lifetime (ms) | `300000` (5 min) |
|
|
193
|
+
|
|
194
|
+
Start from the `.env.example` values and tune against your own database. Higher limits increase both resource use and the amount of data exposed to the model.
|
|
195
|
+
|
|
196
|
+
## Optional database context
|
|
197
|
+
|
|
198
|
+
Place a `sql-ai.md` file in the working directory to explain business terms and rules that aren't obvious from table and column names. It supplements schema discovery; it does not replace it.
|
|
199
|
+
|
|
200
|
+
```markdown
|
|
201
|
+
# Database Context
|
|
202
|
+
|
|
203
|
+
## Overview
|
|
204
|
+
|
|
205
|
+
This database belongs to a school management system. It stores students,
|
|
206
|
+
parents, teachers, classes, enrollments, and payments.
|
|
207
|
+
|
|
208
|
+
## Business Rules
|
|
209
|
+
|
|
210
|
+
- Only active enrollments represent currently enrolled students.
|
|
211
|
+
- Completed payments are considered successful payments.
|
|
212
|
+
- Cancelled payments should not be included in revenue calculations.
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Keep the rules accurate and current. Incorrect or ambiguous context can produce confidently wrong answers even when the generated SQL is valid. A starter template ships as [`sql-ai.example.md`](./sql-ai.example.md).
|
|
216
|
+
|
|
217
|
+
## TypeScript SDK
|
|
218
|
+
|
|
219
|
+
The package exports its public SDK from `@negusdev/dbask`. Import from the package entry point; internal `src/` paths are not part of the public API.
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
import {
|
|
223
|
+
Agent,
|
|
224
|
+
createAiProvider,
|
|
225
|
+
createDatabaseAdapter,
|
|
226
|
+
loadConfig,
|
|
227
|
+
} from "@negusdev/dbask";
|
|
228
|
+
|
|
229
|
+
const config = loadConfig();
|
|
230
|
+
|
|
231
|
+
// Picks MySqlAdapter or PostgresAdapter from DB_DRIVER.
|
|
232
|
+
// You can also construct MySqlAdapter / PostgresAdapter directly.
|
|
233
|
+
const database = createDatabaseAdapter(config.database);
|
|
234
|
+
|
|
235
|
+
const provider = createAiProvider(config.ai);
|
|
236
|
+
|
|
237
|
+
const agent = new Agent(
|
|
238
|
+
provider,
|
|
239
|
+
{ database, safety: config.safety },
|
|
240
|
+
{ maxSteps: config.agent.maxSteps, responseMode: "natural" },
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
const result = await agent.ask("List active users");
|
|
245
|
+
console.log(result.text);
|
|
246
|
+
} finally {
|
|
247
|
+
await database.close();
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
The entry point also exports types and interfaces for the agent, providers, database adapters, tool context, observers, and `SchemaCache`. See `src/index.ts` in the installed version for the exact API surface.
|
|
252
|
+
|
|
253
|
+
The SDK accepts any `DatabaseAdapter` implementation. Custom adapters must preserve the harness safety expectations: read-only intent, row/byte/timeout limits, and bounded SQL attempts per question.
|
|
254
|
+
|
|
255
|
+
## Database tools
|
|
256
|
+
|
|
257
|
+
| Tool | Purpose |
|
|
258
|
+
|---|---|
|
|
259
|
+
| `list_tables` | List available database tables. |
|
|
260
|
+
| `describe_table` | Inspect one table's structure. |
|
|
261
|
+
| `describe_tables` | Inspect multiple tables in one call. |
|
|
262
|
+
| `get_relationships` | Discover foreign-key relationships across the database. |
|
|
263
|
+
| `execute_query` | Execute SQL allowed by the safety layer and configured limits. |
|
|
264
|
+
| `explain_query` | Request a query plan where supported. |
|
|
265
|
+
|
|
266
|
+
The agent requires **successful global foreign-key discovery before executing SQL**. This helps the model plan joins, but it does not prove every join or aggregation matches the business meaning of a question, and undeclared relationships may not be discoverable.
|
|
267
|
+
|
|
268
|
+
## Safety and data handling
|
|
269
|
+
|
|
270
|
+
dbask applies safeguards and execution limits, but **it is not a complete security boundary by itself**. Recommended practices:
|
|
271
|
+
|
|
272
|
+
1. **Use a dedicated read-only database account** with only the schema-inspection and read permissions required. Don't rely solely on the model or the application validator to prevent writes.
|
|
273
|
+
2. **Restrict database visibility.** Avoid granting access to unrelated databases, sensitive tables, or columns.
|
|
274
|
+
3. **Protect credentials.** Don't commit `.env` or share credentials in logs or issue reports. Rotate any credential that is exposed.
|
|
275
|
+
4. **Review your AI provider's data handling.** Schema metadata, question text, generated SQL, and query results may be sent to the provider. Check its retention, training, residency, and contractual terms before using sensitive data.
|
|
276
|
+
5. **Set conservative limits** for rows, result size, timeout, and agent steps.
|
|
277
|
+
6. **Verify important answers** independently before using them for financial, operational, or compliance decisions.
|
|
278
|
+
7. **Test on a non-production database first**, such as a disposable or sanitized snapshot.
|
|
279
|
+
|
|
280
|
+
The SQL validator tokenizes each query, so keywords inside string literals, quoted identifiers, and comments are ignored. It accepts a single read-oriented statement and rejects writes, locking reads, `INTO OUTFILE`, executable comments, and functions such as `SLEEP()` and `LOAD_FILE()`. It uses the lexical rules of the configured database (for example PostgreSQL's dollar-quoted strings and nested comments, or MySQL's `#` comments and backslash escapes), and it assumes MySQL's default `sql_mode`. It cannot recognize user-defined functions with side effects, which is another reason to use a read-only database account.
|
|
281
|
+
|
|
282
|
+
On PostgreSQL the adapter adds server-side protection that does not depend on the validator: every statement runs inside a `READ ONLY` transaction that is always rolled back, with a per-query `statement_timeout`, over the extended protocol (so the server itself refuses multiple statements), and rows are streamed through a cursor so oversized results are never fully loaded. Results that hit the row or size limit are flagged `truncated`, and the agent is told not to present them as complete.
|
|
283
|
+
|
|
284
|
+
Successful SQL execution does not guarantee a correct answer. SQL attempts are capped per question, but correctness cannot be guaranteed for arbitrary questions or business-specific joins.
|
|
285
|
+
|
|
286
|
+
## Database support
|
|
287
|
+
|
|
288
|
+
| Database | Status |
|
|
289
|
+
|---|---|
|
|
290
|
+
| MySQL / MariaDB | Available |
|
|
291
|
+
| PostgreSQL | Available (tables, partitioned tables, and schemas; views are not listed yet) |
|
|
292
|
+
| SQLite | Planned |
|
|
293
|
+
| Others | Implement `DatabaseAdapter` |
|
|
294
|
+
|
|
295
|
+
## Evaluation
|
|
296
|
+
|
|
297
|
+
The `evals/` directory contains a benchmark dataset, runner, and saved reports. Use it to check whether a change to the model, prompt, tool, or adapter measurably affects correctness.
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
pnpm eval -- --tag local-check
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
See [`evals/README.md`](./evals/README.md) for dataset setup and scoring. When comparing runs, keep the provider, model, database snapshot, configuration, and dataset consistent. A passing benchmark supports the cases tested; it is not a guarantee of general correctness.
|
|
304
|
+
|
|
305
|
+
**Latest result (v0.1.8):** on the 40-case internal benchmark (synthetic forex database, `gemini-3.5-flash-lite`, 3 runs) the agent passed 39 of 40 cases in every run (97.5%), including 10 of 10 safety and off-topic refusal checks. The one consistent failure is a known reference-answer error in the benchmark, not an agent error. The cases are mostly simple lookups and joins, so treat this as a regression check, not a measure of accuracy on your own database.
|
|
306
|
+
|
|
307
|
+
### Query plan (optional)
|
|
308
|
+
|
|
309
|
+
With `AGENT_QUERY_PLAN=on` the agent must submit a structured plan (tables, columns, joins, filters) that is checked against your real schema before any SQL runs, and the SQL may only read the planned tables. In the same benchmark the plan added about 0.7 tool calls and roughly 30% median latency per question without improving accuracy, so it is off by default. Turn it on if you want the agent's assumptions visible in `--mode debug`, or to compare against your own workload.
|
|
310
|
+
|
|
311
|
+
## Development
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
git clone https://github.com/NegusDev/dbask.git
|
|
315
|
+
cd dbask
|
|
316
|
+
pnpm install
|
|
317
|
+
cp .env.example .env
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Run a question through the development CLI:
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
pnpm dev ask "List active users"
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Run the checks before submitting changes:
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
pnpm typecheck
|
|
330
|
+
pnpm test
|
|
331
|
+
pnpm build
|
|
332
|
+
npm pack --dry-run
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Run the built CLI directly:
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
node dist/cli.js ask "List active users"
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Project layout
|
|
342
|
+
|
|
343
|
+
```text
|
|
344
|
+
src/
|
|
345
|
+
ai/ Provider factory and provider interfaces
|
|
346
|
+
commands/ CLI commands, including the init wizard
|
|
347
|
+
config/ Environment and .env loading
|
|
348
|
+
context/ Optional business context loading (sql-ai.md)
|
|
349
|
+
core/agent/ Agent loop and observability interfaces
|
|
350
|
+
core/tools/ Schema and SQL tools exposed to the agent
|
|
351
|
+
database/ Database adapter interface, MySQL and PostgreSQL implementations
|
|
352
|
+
safety/ SQL validation, policy checks, execution limits
|
|
353
|
+
schema/ In-memory schema metadata cache
|
|
354
|
+
cli.ts CLI entry point
|
|
355
|
+
index.ts Public TypeScript SDK exports
|
|
356
|
+
evals/ Benchmark dataset, runner, and reports
|
|
357
|
+
tests/ Automated tests
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
## Troubleshooting
|
|
361
|
+
|
|
362
|
+
### Database connection fails
|
|
363
|
+
|
|
364
|
+
- Verify host, port, database name, username, and password.
|
|
365
|
+
- Confirm the database accepts connections from the machine running the harness.
|
|
366
|
+
- Confirm the account can inspect tables and read the required data.
|
|
367
|
+
- Check firewall rules and database allowlists.
|
|
368
|
+
- Hosted PostgreSQL (Neon, Supabase, RDS, ...) usually requires TLS: set `DB_SSL=require`. Poolers such as pgbouncer in transaction mode work, because each query is a self-contained transaction.
|
|
369
|
+
- PostgreSQL tables outside `public` appear as `schema.table` in `list_tables`; the agent is told to use names exactly as listed.
|
|
370
|
+
|
|
371
|
+
### Provider authentication or model errors
|
|
372
|
+
|
|
373
|
+
- Confirm `AI_PROVIDER` matches the provider whose key you configured.
|
|
374
|
+
- Verify `AI_MODEL` is the exact model ID the provider expects.
|
|
375
|
+
- Check that the API key is active and has quota and access to the model.
|
|
376
|
+
- For Ollama, verify the endpoint is reachable and the model is installed.
|
|
377
|
+
- Run `dbask validate`. It sends one tiny request to the provider and reports whether the key, model, and network path work. (`init` only tests the database.)
|
|
378
|
+
|
|
379
|
+
### The answer is incorrect or incomplete
|
|
380
|
+
|
|
381
|
+
- Run with `--mode technical` or `--mode debug` to inspect the SQL and tool activity.
|
|
382
|
+
- Inspect the relevant table definitions and foreign keys.
|
|
383
|
+
- Review `sql-ai.md` for outdated or ambiguous rules.
|
|
384
|
+
- Narrow the question with dates, statuses, or business definitions.
|
|
385
|
+
- Verify the generated SQL and results directly against the database.
|
|
386
|
+
- Add a representative case to `evals/` if the failure is repeatable.
|
|
387
|
+
|
|
388
|
+
### Configuration is not found
|
|
389
|
+
|
|
390
|
+
- Run the command from the directory containing `.env`, or set the variables in the process environment.
|
|
391
|
+
- Confirm variable names match `.env.example`.
|
|
392
|
+
- Check that `AI_MODEL` and the selected provider's credentials are set.
|
|
393
|
+
|
|
394
|
+
## Contributing
|
|
395
|
+
|
|
396
|
+
Issues and pull requests are welcome at [github.com/NegusDev/dbask](https://github.com/NegusDev/dbask).
|
|
397
|
+
|
|
398
|
+
Before opening a PR, run the project checks and confirm that changes to the agent, tools, or prompts don't regress the benchmark:
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
pnpm eval -- --tag <your-branch>
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
For bugs involving incorrect answers, include:
|
|
405
|
+
|
|
406
|
+
- The question you asked (or a close paraphrase)
|
|
407
|
+
- The `--mode debug` output
|
|
408
|
+
- The relevant table definitions and `sql-ai.md` content, if any
|
|
409
|
+
- The provider and model used
|
|
410
|
+
|
|
411
|
+
Do **not** include `.env` contents, credentials, or unfiltered production data in issue reports.
|
|
412
|
+
|
|
413
|
+
## License
|
|
414
|
+
|
|
415
|
+
Released under the [ISC License](./LICENSE).
|
|
416
|
+
|
|
417
|
+
## Links
|
|
418
|
+
|
|
419
|
+
- [Source](https://github.com/NegusDev/dbask)
|
|
420
|
+
- [npm](https://www.npmjs.com/package/@negusdev/dbask)
|
|
421
|
+
- [Issues](https://github.com/NegusDev/dbask/issues)
|
|
422
|
+
- [Evaluation guide](./evals/README.md)
|
|
423
|
+
- [Business context template](./sql-ai.example.md)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/ai/factory.ts"],"names":[],"mappings":"AAQA,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,CAgEpE"}
|
|
@@ -0,0 +1,55 @@
|
|
|
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 { createDeepSeek } from '@ai-sdk/deepseek';
|
|
7
|
+
import { SdkAiProvider } from './sdk-provider.js';
|
|
8
|
+
export function createAiProvider(config) {
|
|
9
|
+
switch (config.provider) {
|
|
10
|
+
case 'openrouter': {
|
|
11
|
+
const provider = createOpenRouter({
|
|
12
|
+
apiKey: config.apiKey,
|
|
13
|
+
...(config.siteUrl ? { appUrl: config.siteUrl } : {}),
|
|
14
|
+
...(config.siteName ? { appName: config.siteName } : {}),
|
|
15
|
+
});
|
|
16
|
+
return new SdkAiProvider('openrouter', provider.chat(config.model));
|
|
17
|
+
}
|
|
18
|
+
case 'groq': {
|
|
19
|
+
const provider = createGroq({
|
|
20
|
+
apiKey: config.apiKey,
|
|
21
|
+
});
|
|
22
|
+
return new SdkAiProvider('groq', provider(config.model));
|
|
23
|
+
}
|
|
24
|
+
case 'google': {
|
|
25
|
+
const provider = createGoogleGenerativeAI({
|
|
26
|
+
apiKey: config.apiKey,
|
|
27
|
+
});
|
|
28
|
+
return new SdkAiProvider('google', provider(config.model));
|
|
29
|
+
}
|
|
30
|
+
case 'cerebras': {
|
|
31
|
+
const provider = createCerebras({
|
|
32
|
+
apiKey: config.apiKey,
|
|
33
|
+
});
|
|
34
|
+
return new SdkAiProvider('cerebras', provider(config.model));
|
|
35
|
+
}
|
|
36
|
+
case 'ollama': {
|
|
37
|
+
const provider = createOpenAICompatible({
|
|
38
|
+
name: 'ollama',
|
|
39
|
+
baseURL: config.baseUrl ?? 'http://localhost:11434/v1',
|
|
40
|
+
});
|
|
41
|
+
return new SdkAiProvider('ollama', provider.chatModel(config.model));
|
|
42
|
+
}
|
|
43
|
+
case 'deepseek': {
|
|
44
|
+
const provider = createDeepSeek({
|
|
45
|
+
apiKey: config.apiKey,
|
|
46
|
+
});
|
|
47
|
+
return new SdkAiProvider('deepseek', provider.chat(config.model));
|
|
48
|
+
}
|
|
49
|
+
default: {
|
|
50
|
+
const exhaustiveCheck = config.provider;
|
|
51
|
+
throw new Error(`Unsupported AI provider: ${exhaustiveCheck}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# 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;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAIlD,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,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,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACpE,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,CA+BxB;CACF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
// Reserve the last step for the answer: without this the model can spend
|
|
19
|
+
// every step on tool calls and end with no text at all.
|
|
20
|
+
prepareStep: request.maxSteps
|
|
21
|
+
? ({ stepNumber }) => stepNumber >= request.maxSteps - 1
|
|
22
|
+
? { toolChoice: 'none' }
|
|
23
|
+
: undefined
|
|
24
|
+
: undefined,
|
|
25
|
+
temperature: request.temperature,
|
|
26
|
+
});
|
|
27
|
+
const toolCalls = result.steps.reduce((count, step) => count + (step.toolCalls?.length ?? 0), 0);
|
|
28
|
+
return {
|
|
29
|
+
text: result.text,
|
|
30
|
+
raw: result,
|
|
31
|
+
steps: result.steps.length,
|
|
32
|
+
toolCalls,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# 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,yEAAyE;YACzE,wDAAwD;YACxD,WAAW,EAAE,OAAO,CAAC,QAAQ;gBAC3B,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CACjB,UAAU,IAAK,OAAO,CAAC,QAAmB,GAAG,CAAC;oBAC5C,CAAC,CAAC,EAAE,UAAU,EAAE,MAAe,EAAE;oBACjC,CAAC,CAAC,SAAS;gBACjB,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"}
|