sqlsaber 0.24.0__tar.gz → 0.25.0__tar.gz
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.
Potentially problematic release.
This version of sqlsaber might be problematic. Click here for more details.
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/PKG-INFO +4 -3
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/README.md +2 -1
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/changelog.md +8 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/guides/database-setup.mdx +15 -2
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/guides/getting-started.mdx +2 -1
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/guides/queries.mdx +4 -1
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/index.mdx +1 -1
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/reference/commands.md +48 -7
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/pyproject.toml +2 -2
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/agents/base.py +4 -1
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/agents/pydantic_ai_agent.py +4 -1
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/commands.py +19 -11
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/database.py +17 -6
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/interactive.py +6 -1
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/config/database.py +3 -1
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/database/connection.py +123 -99
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/database/resolver.py +7 -3
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/database/schema.py +225 -1
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_config/test_database.py +26 -1
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_database/test_connection.py +9 -0
- sqlsaber-0.25.0/tests/test_database/test_csv_connection.py +42 -0
- sqlsaber-0.25.0/tests/test_database/test_schema.py +47 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_database_resolver.py +24 -2
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/uv.lock +865 -938
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/.github/workflows/claude-code-review.yml +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/.github/workflows/claude.yml +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/.github/workflows/deploy-docs.yml +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/.github/workflows/publish.yml +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/.github/workflows/test.yml +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/.gitignore +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/.python-version +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/AGENT.md +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/CLAUDE.md +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/LICENSE +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/.gitignore +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/.vscode/extensions.json +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/.vscode/launch.json +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/CLAUDE.md +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/astro.config.mjs +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/package-lock.json +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/package.json +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/public/CNAME +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/public/favicon.svg +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/assets/sqlsaber-hero.svg +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/guides/authentication.mdx +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/guides/memory.mdx +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/guides/models.mdx +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/guides/threads.md +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/installation.mdx +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content.config.ts +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/styles/global.css +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/tsconfig.json +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/legislators.db +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/pytest.ini +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/sqlsaber.gif +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/sqlsaber.svg +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/__init__.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/__main__.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/agents/__init__.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/agents/mcp.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/__init__.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/auth.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/completers.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/display.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/memory.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/models.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/streaming.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/threads.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/config/__init__.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/config/api_keys.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/config/auth.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/config/oauth_flow.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/config/oauth_tokens.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/config/providers.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/config/settings.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/database/__init__.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/mcp/__init__.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/mcp/mcp.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/memory/__init__.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/memory/manager.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/memory/storage.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/threads/__init__.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/threads/storage.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/tools/__init__.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/tools/base.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/tools/enums.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/tools/instructions.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/tools/registry.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/tools/sql_tools.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/__init__.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/conftest.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_cli/__init__.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_cli/test_auth_reset.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_cli/test_commands.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_cli/test_threads.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_config/__init__.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_config/test_oauth.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_config/test_providers.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_config/test_settings.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_database/__init__.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_database/test_timeout.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_threads_storage.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_tools/__init__.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_tools/test_base.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_tools/test_instructions.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_tools/test_registry.py +0 -0
- {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_tools/test_sql_tools.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlsaber
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.25.0
|
|
4
4
|
Summary: SQLsaber - Open-source agentic SQL assistant
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Requires-Python: >=3.12
|
|
@@ -8,10 +8,10 @@ Requires-Dist: aiomysql>=0.2.0
|
|
|
8
8
|
Requires-Dist: aiosqlite>=0.21.0
|
|
9
9
|
Requires-Dist: asyncpg>=0.30.0
|
|
10
10
|
Requires-Dist: cyclopts>=3.22.1
|
|
11
|
+
Requires-Dist: duckdb>=0.9.2
|
|
11
12
|
Requires-Dist: fastmcp>=2.9.0
|
|
12
13
|
Requires-Dist: httpx>=0.28.1
|
|
13
14
|
Requires-Dist: keyring>=25.6.0
|
|
14
|
-
Requires-Dist: pandas>=2.0.0
|
|
15
15
|
Requires-Dist: platformdirs>=4.0.0
|
|
16
16
|
Requires-Dist: prompt-toolkit>3.0.51
|
|
17
17
|
Requires-Dist: pydantic-ai
|
|
@@ -58,7 +58,7 @@ Ask your questions in natural language and `sqlsaber` will gather the right cont
|
|
|
58
58
|
- 🧠 Memory management
|
|
59
59
|
- 💬 Interactive REPL mode
|
|
60
60
|
- 🧵 Conversation threads (store, display, and resume conversations)
|
|
61
|
-
- 🗄️ Support for PostgreSQL, SQLite, and
|
|
61
|
+
- 🗄️ Support for PostgreSQL, MySQL, SQLite, and DuckDB
|
|
62
62
|
- 🔌 MCP (Model Context Protocol) server support
|
|
63
63
|
- 🎨 Beautiful formatted output
|
|
64
64
|
|
|
@@ -170,6 +170,7 @@ saber -d mydb "count all orders"
|
|
|
170
170
|
|
|
171
171
|
# You can also pass a connection string
|
|
172
172
|
saber -d "postgresql://user:password@localhost:5432/mydb" "count all orders"
|
|
173
|
+
saber -d "duckdb:///path/to/data.duckdb" "top customers"
|
|
173
174
|
```
|
|
174
175
|
|
|
175
176
|
## Examples
|
|
@@ -37,7 +37,7 @@ Ask your questions in natural language and `sqlsaber` will gather the right cont
|
|
|
37
37
|
- 🧠 Memory management
|
|
38
38
|
- 💬 Interactive REPL mode
|
|
39
39
|
- 🧵 Conversation threads (store, display, and resume conversations)
|
|
40
|
-
- 🗄️ Support for PostgreSQL, SQLite, and
|
|
40
|
+
- 🗄️ Support for PostgreSQL, MySQL, SQLite, and DuckDB
|
|
41
41
|
- 🔌 MCP (Model Context Protocol) server support
|
|
42
42
|
- 🎨 Beautiful formatted output
|
|
43
43
|
|
|
@@ -149,6 +149,7 @@ saber -d mydb "count all orders"
|
|
|
149
149
|
|
|
150
150
|
# You can also pass a connection string
|
|
151
151
|
saber -d "postgresql://user:password@localhost:5432/mydb" "count all orders"
|
|
152
|
+
saber -d "duckdb:///path/to/data.duckdb" "top customers"
|
|
152
153
|
```
|
|
153
154
|
|
|
154
155
|
## Examples
|
|
@@ -7,6 +7,14 @@ All notable changes to SQLsaber will be documented here.
|
|
|
7
7
|
|
|
8
8
|
### Unreleased
|
|
9
9
|
|
|
10
|
+
### v0.25.0 - 2025-09-26
|
|
11
|
+
|
|
12
|
+
#### Added
|
|
13
|
+
|
|
14
|
+
- DuckDB support for efficient CSV and data file analysis
|
|
15
|
+
- Added `duckdb` provider to database options
|
|
16
|
+
- Enhanced CSV processing capabilities using DuckDB's optimized engine
|
|
17
|
+
|
|
10
18
|
### v0.24.0 - 2025-09-24
|
|
11
19
|
|
|
12
20
|
#### Added
|
|
@@ -5,13 +5,14 @@ description: Configure database connections in SQLsaber
|
|
|
5
5
|
|
|
6
6
|
import { Aside } from '@astrojs/starlight/components';
|
|
7
7
|
|
|
8
|
-
SQLsaber supports PostgreSQL, MySQL,
|
|
8
|
+
SQLsaber supports PostgreSQL, MySQL, SQLite, DuckDB, and CSV data sources. This guide covers all the ways to configure database connections.
|
|
9
9
|
|
|
10
10
|
### Supported Database Types
|
|
11
11
|
|
|
12
12
|
- **PostgreSQL** - Full support with SSL
|
|
13
13
|
- **MySQL** - Full support with SSL
|
|
14
14
|
- **SQLite** - Local database files
|
|
15
|
+
- **DuckDB** - Local DuckDB files or in-memory analytics
|
|
15
16
|
- **CSV** - Local CSV files
|
|
16
17
|
|
|
17
18
|
### Adding Database
|
|
@@ -24,12 +25,14 @@ This will prompt you for all necessary connection details.
|
|
|
24
25
|
|
|
25
26
|
### Connection Strings
|
|
26
27
|
|
|
27
|
-
SQLsaber supports direct connection strings for PostgreSQL and MySQL.
|
|
28
|
+
SQLsaber supports direct connection strings for PostgreSQL and MySQL, plus file URIs for SQLite and DuckDB.
|
|
28
29
|
|
|
29
30
|
```bash
|
|
30
31
|
saber -d "postgresql://user:password@localhost:5432/database"
|
|
31
32
|
|
|
32
33
|
saber -d "mysql://user:password@localhost:3306/database"
|
|
34
|
+
|
|
35
|
+
saber -d "duckdb:///path/to/data.duckdb"
|
|
33
36
|
```
|
|
34
37
|
|
|
35
38
|
### Files
|
|
@@ -44,6 +47,16 @@ saber -d "./data/sales.db" "Show me total sales by month"
|
|
|
44
47
|
saber -d "~/Documents/mydata.db" "Count all records"
|
|
45
48
|
```
|
|
46
49
|
|
|
50
|
+
#### DuckDB
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Query a DuckDB file
|
|
54
|
+
saber -d "./warehouse/data.duckdb" "Show the latest partition"
|
|
55
|
+
|
|
56
|
+
# Use an absolute path
|
|
57
|
+
saber -d "duckdb:///Users/me/analytics.duckdb" "Describe orders"
|
|
58
|
+
```
|
|
59
|
+
|
|
47
60
|
#### CSV
|
|
48
61
|
|
|
49
62
|
SQLsaber can also analyze CSV files directly.
|
|
@@ -10,7 +10,7 @@ Welcome to SQLsaber! This guide will walk you through setting up SQLsaber and ru
|
|
|
10
10
|
Before you begin, make sure you have:
|
|
11
11
|
|
|
12
12
|
1. [Installed SQLsaber](/installation)
|
|
13
|
-
2. Access to a database (PostgreSQL, MySQL, or
|
|
13
|
+
2. Access to a database (PostgreSQL, MySQL, SQLite, or DuckDB)
|
|
14
14
|
3. An API key from a supported AI provider (Anthropic, OpenAI, Google, etc.)
|
|
15
15
|
|
|
16
16
|
### Quick Setup
|
|
@@ -54,6 +54,7 @@ This interactive command will ask you for:
|
|
|
54
54
|
- PostgreSQL
|
|
55
55
|
- MySQL
|
|
56
56
|
- SQLite
|
|
57
|
+
- DuckDB
|
|
57
58
|
- Connection details (host, port, database name, username)
|
|
58
59
|
- SSL configuration (if needed)
|
|
59
60
|
|
|
@@ -109,12 +109,15 @@ saber -d prod-db "What's our revenue this month?"
|
|
|
109
109
|
|
|
110
110
|
#### Using Files Directly
|
|
111
111
|
|
|
112
|
-
Work with SQLite or CSV files directly:
|
|
112
|
+
Work with SQLite, DuckDB, or CSV files directly:
|
|
113
113
|
|
|
114
114
|
```bash
|
|
115
115
|
# SQLite file
|
|
116
116
|
saber -d "./data/sales.db" "Top selling products"
|
|
117
117
|
|
|
118
|
+
# DuckDB file
|
|
119
|
+
saber -d "./data/warehouse.duckdb" "Latest partitions"
|
|
120
|
+
|
|
118
121
|
# CSV file
|
|
119
122
|
saber -d "./customers.csv" "How many customers per state?"
|
|
120
123
|
```
|
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
</p>
|
|
58
58
|
<li class="flex items-center gap-3">
|
|
59
59
|
<Icon name="seti:db" />
|
|
60
|
-
<span>PostgreSQL, MySQL, SQLite, CSV support</span>
|
|
60
|
+
<span>PostgreSQL, MySQL, SQLite, DuckDB, CSV support</span>
|
|
61
61
|
</li>
|
|
62
62
|
<li class="flex items-center gap-3">
|
|
63
63
|
<Icon name="forward-slash" />
|
|
@@ -10,6 +10,7 @@ This is a comprehensive reference for all SQLsaber commands and their options.
|
|
|
10
10
|
The main SQLsaber command for running queries.
|
|
11
11
|
|
|
12
12
|
**Usage:**
|
|
13
|
+
|
|
13
14
|
```bash
|
|
14
15
|
# Interactive mode (default)
|
|
15
16
|
saber
|
|
@@ -25,10 +26,12 @@ saber -d "postgresql://user:pass@host:5432/db" "User statistics for 2024"
|
|
|
25
26
|
```
|
|
26
27
|
|
|
27
28
|
**Parameters:**
|
|
29
|
+
|
|
28
30
|
- `QUERY-TEXT` - SQL query in natural language (optional, starts interactive mode if not provided)
|
|
29
|
-
- `-d, --database` - Database connection name, file path (CSV/SQLite), or connection string
|
|
31
|
+
- `-d, --database` - Database connection name, file path (CSV/SQLite/DuckDB), or connection string (postgresql://, mysql://, duckdb://)
|
|
30
32
|
|
|
31
33
|
**Global Options:**
|
|
34
|
+
|
|
32
35
|
- `--help, -h` - Display help message
|
|
33
36
|
- `--version` - Show version information
|
|
34
37
|
|
|
@@ -43,6 +46,7 @@ Manage authentication configuration for AI providers.
|
|
|
43
46
|
Configure authentication for SQLsaber (API keys and OAuth).
|
|
44
47
|
|
|
45
48
|
**Usage:**
|
|
49
|
+
|
|
46
50
|
```bash
|
|
47
51
|
saber auth setup
|
|
48
52
|
```
|
|
@@ -52,11 +56,13 @@ saber auth setup
|
|
|
52
56
|
Check current authentication configuration.
|
|
53
57
|
|
|
54
58
|
**Usage:**
|
|
59
|
+
|
|
55
60
|
```bash
|
|
56
61
|
saber auth status
|
|
57
62
|
```
|
|
58
63
|
|
|
59
64
|
**Output shows:**
|
|
65
|
+
|
|
60
66
|
- Configured providers
|
|
61
67
|
- Authentication methods (API key vs OAuth)
|
|
62
68
|
|
|
@@ -65,6 +71,7 @@ saber auth status
|
|
|
65
71
|
Remove stored credentials for a provider.
|
|
66
72
|
|
|
67
73
|
**Usage:**
|
|
74
|
+
|
|
68
75
|
```bash
|
|
69
76
|
saber auth reset
|
|
70
77
|
```
|
|
@@ -80,15 +87,18 @@ Manage database connections.
|
|
|
80
87
|
Add a new database connection.
|
|
81
88
|
|
|
82
89
|
**Usage:**
|
|
90
|
+
|
|
83
91
|
```bash
|
|
84
92
|
saber db add my-database [OPTIONS]
|
|
85
93
|
```
|
|
86
94
|
|
|
87
95
|
**Parameters:**
|
|
96
|
+
|
|
88
97
|
- `NAME` - Name for the database connection (required)
|
|
89
98
|
|
|
90
99
|
**Options:**
|
|
91
|
-
|
|
100
|
+
|
|
101
|
+
- `-t, --type` - Database type: `postgresql`, `mysql`, `sqlite`, `duckdb` (default: postgresql)
|
|
92
102
|
- `-h, --host` - Database host
|
|
93
103
|
- `-p, --port` - Database port
|
|
94
104
|
- `--database, --db` - Database name
|
|
@@ -101,7 +111,8 @@ saber db add my-database [OPTIONS]
|
|
|
101
111
|
|
|
102
112
|
**SSL Modes:**
|
|
103
113
|
|
|
104
|
-
|
|
114
|
+
_PostgreSQL:_
|
|
115
|
+
|
|
105
116
|
- `disable` - No SSL
|
|
106
117
|
- `allow` - Try SSL, fallback to non-SSL
|
|
107
118
|
- `prefer` - Try SSL first (default)
|
|
@@ -109,24 +120,26 @@ saber db add my-database [OPTIONS]
|
|
|
109
120
|
- `verify-ca` - Require SSL and verify certificate
|
|
110
121
|
- `verify-full` - Require SSL, verify certificate and hostname
|
|
111
122
|
|
|
112
|
-
|
|
123
|
+
_MySQL:_
|
|
124
|
+
|
|
113
125
|
- `DISABLED` - No SSL
|
|
114
126
|
- `PREFERRED` - Try SSL first (default)
|
|
115
127
|
- `REQUIRED` - Require SSL
|
|
116
128
|
- `VERIFY_CA` - Require SSL and verify certificate
|
|
117
129
|
- `VERIFY_IDENTITY` - Require SSL, verify certificate and hostname
|
|
118
130
|
|
|
119
|
-
|
|
120
131
|
#### `saber db list`
|
|
121
132
|
|
|
122
133
|
List all configured database connections.
|
|
123
134
|
|
|
124
135
|
**Usage:**
|
|
136
|
+
|
|
125
137
|
```bash
|
|
126
138
|
saber db list
|
|
127
139
|
```
|
|
128
140
|
|
|
129
141
|
**Output shows:**
|
|
142
|
+
|
|
130
143
|
- Database names
|
|
131
144
|
- Connection details (host, port, database)
|
|
132
145
|
- Default database indicator
|
|
@@ -136,6 +149,7 @@ saber db list
|
|
|
136
149
|
Set a database as the default connection.
|
|
137
150
|
|
|
138
151
|
**Usage:**
|
|
152
|
+
|
|
139
153
|
```bash
|
|
140
154
|
saber db set-default my-database
|
|
141
155
|
```
|
|
@@ -145,11 +159,13 @@ saber db set-default my-database
|
|
|
145
159
|
Test a database connection.
|
|
146
160
|
|
|
147
161
|
**Usage:**
|
|
162
|
+
|
|
148
163
|
```bash
|
|
149
164
|
saber db test my-database
|
|
150
165
|
```
|
|
151
166
|
|
|
152
167
|
**Output:**
|
|
168
|
+
|
|
153
169
|
- Connection success/failure
|
|
154
170
|
- Error details if connection fails
|
|
155
171
|
|
|
@@ -158,6 +174,7 @@ saber db test my-database
|
|
|
158
174
|
Remove a database connection.
|
|
159
175
|
|
|
160
176
|
**Usage:**
|
|
177
|
+
|
|
161
178
|
```bash
|
|
162
179
|
saber db remove my-database
|
|
163
180
|
```
|
|
@@ -175,17 +192,21 @@ Manage database-specific memories and context.
|
|
|
175
192
|
Add a new memory entry.
|
|
176
193
|
|
|
177
194
|
**Usage:**
|
|
195
|
+
|
|
178
196
|
```bash
|
|
179
197
|
saber memory add "Memory content here" [OPTIONS]
|
|
180
198
|
```
|
|
181
199
|
|
|
182
200
|
**Parameters:**
|
|
201
|
+
|
|
183
202
|
- `CONTENT` - Memory content to add (required)
|
|
184
203
|
|
|
185
204
|
**Options:**
|
|
205
|
+
|
|
186
206
|
- `-d, --database` - Database connection name (uses default if not specified)
|
|
187
207
|
|
|
188
208
|
**Examples:**
|
|
209
|
+
|
|
189
210
|
```bash
|
|
190
211
|
# Add memory to default database
|
|
191
212
|
saber memory add "Active customers are those who made a purchase in the last 90 days"
|
|
@@ -205,14 +226,17 @@ saber memory add "Always format dates as YYYY-MM-DD for reports"
|
|
|
205
226
|
List all memory entries for a database.
|
|
206
227
|
|
|
207
228
|
**Usage:**
|
|
229
|
+
|
|
208
230
|
```bash
|
|
209
231
|
saber memory list [OPTIONS]
|
|
210
232
|
```
|
|
211
233
|
|
|
212
234
|
**Options:**
|
|
235
|
+
|
|
213
236
|
- `-d, --database` - Database connection name (uses default if not specified)
|
|
214
237
|
|
|
215
238
|
**Output shows:**
|
|
239
|
+
|
|
216
240
|
- Memory ID
|
|
217
241
|
- Memory content
|
|
218
242
|
- Creation timestamp
|
|
@@ -222,11 +246,13 @@ saber memory list [OPTIONS]
|
|
|
222
246
|
Remove a specific memory entry.
|
|
223
247
|
|
|
224
248
|
**Usage:**
|
|
249
|
+
|
|
225
250
|
```bash
|
|
226
251
|
saber memory remove a1b2c3d4
|
|
227
252
|
```
|
|
228
253
|
|
|
229
254
|
**Parameters:**
|
|
255
|
+
|
|
230
256
|
- `ID` - Memory ID from `saber memory list` output
|
|
231
257
|
|
|
232
258
|
#### `saber memory clear`
|
|
@@ -234,11 +260,13 @@ saber memory remove a1b2c3d4
|
|
|
234
260
|
Remove all memory entries for a database.
|
|
235
261
|
|
|
236
262
|
**Usage:**
|
|
263
|
+
|
|
237
264
|
```bash
|
|
238
265
|
saber memory clear [OPTIONS]
|
|
239
266
|
```
|
|
240
267
|
|
|
241
268
|
**Options:**
|
|
269
|
+
|
|
242
270
|
- `-d, --database` - Database connection name (uses default if not specified)
|
|
243
271
|
|
|
244
272
|
**Confirmation required** - Will prompt before deletion.
|
|
@@ -254,6 +282,7 @@ Manage LLM models from different providers.
|
|
|
254
282
|
List all available models for configured providers.
|
|
255
283
|
|
|
256
284
|
**Usage:**
|
|
285
|
+
|
|
257
286
|
```bash
|
|
258
287
|
saber models list
|
|
259
288
|
```
|
|
@@ -263,6 +292,7 @@ saber models list
|
|
|
263
292
|
Set the default model.
|
|
264
293
|
|
|
265
294
|
**Usage:**
|
|
295
|
+
|
|
266
296
|
```bash
|
|
267
297
|
saber models set
|
|
268
298
|
```
|
|
@@ -272,6 +302,7 @@ saber models set
|
|
|
272
302
|
Reset to the default model (Claude Sonnet 4).
|
|
273
303
|
|
|
274
304
|
**Usage:**
|
|
305
|
+
|
|
275
306
|
```bash
|
|
276
307
|
saber models reset
|
|
277
308
|
```
|
|
@@ -287,28 +318,32 @@ Manage conversation threads.
|
|
|
287
318
|
List conversation threads.
|
|
288
319
|
|
|
289
320
|
**Usage:**
|
|
321
|
+
|
|
290
322
|
```bash
|
|
291
323
|
saber threads list [OPTIONS]
|
|
292
324
|
```
|
|
293
325
|
|
|
294
326
|
**Options:**
|
|
327
|
+
|
|
295
328
|
- `-d, --database` - Filter by database name
|
|
296
329
|
- `-n, --limit` - Maximum threads to return (default: 50)
|
|
297
330
|
|
|
298
|
-
|
|
299
331
|
#### `saber threads show`
|
|
300
332
|
|
|
301
333
|
Show complete thread transcript.
|
|
302
334
|
|
|
303
335
|
**Usage:**
|
|
336
|
+
|
|
304
337
|
```bash
|
|
305
338
|
saber threads show a1b2c3d4
|
|
306
339
|
```
|
|
307
340
|
|
|
308
341
|
**Parameters:**
|
|
342
|
+
|
|
309
343
|
- `THREAD_ID` - Thread ID from `saber threads list`
|
|
310
344
|
|
|
311
345
|
**Output shows:**
|
|
346
|
+
|
|
312
347
|
- Thread metadata (database, model, timestamps)
|
|
313
348
|
- Complete conversation history
|
|
314
349
|
- SQL queries and results
|
|
@@ -319,17 +354,21 @@ saber threads show a1b2c3d4
|
|
|
319
354
|
Resume an existing conversation thread.
|
|
320
355
|
|
|
321
356
|
**Usage:**
|
|
357
|
+
|
|
322
358
|
```bash
|
|
323
359
|
saber threads resume a1b2c3d4 [OPTIONS]
|
|
324
360
|
```
|
|
325
361
|
|
|
326
362
|
**Parameters:**
|
|
363
|
+
|
|
327
364
|
- `THREAD_ID` - Thread ID to resume
|
|
328
365
|
|
|
329
366
|
**Options:**
|
|
367
|
+
|
|
330
368
|
- `-d, --database` - Use different database than original thread
|
|
331
369
|
|
|
332
370
|
**Features:**
|
|
371
|
+
|
|
333
372
|
- Loads full conversation context
|
|
334
373
|
- Uses same model as original thread
|
|
335
374
|
- Connects to original database
|
|
@@ -340,21 +379,23 @@ saber threads resume a1b2c3d4 [OPTIONS]
|
|
|
340
379
|
Clean up old conversation threads.
|
|
341
380
|
|
|
342
381
|
**Usage:**
|
|
382
|
+
|
|
343
383
|
```bash
|
|
344
384
|
saber threads prune
|
|
345
385
|
```
|
|
346
386
|
|
|
347
387
|
---
|
|
348
388
|
|
|
349
|
-
|
|
350
389
|
### Interactive Mode
|
|
351
390
|
|
|
352
391
|
When in interactive mode (`saber` with no arguments), you have access to a few additional features:
|
|
353
392
|
|
|
354
393
|
#### Slash Commands
|
|
394
|
+
|
|
355
395
|
- `/clear` - Clear conversation history
|
|
356
396
|
- `/exit` - Exit SQLsaber
|
|
357
397
|
- `/quit` - Exit SQLsaber (alias for `/exit`)
|
|
358
398
|
|
|
359
399
|
#### Autocomplete
|
|
400
|
+
|
|
360
401
|
- **Table names** - Type `@table_name[TAB]` for completions
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sqlsaber"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.25.0"
|
|
4
4
|
description = "SQLsaber - Open-source agentic SQL assistant"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -14,7 +14,7 @@ dependencies = [
|
|
|
14
14
|
"httpx>=0.28.1",
|
|
15
15
|
"aiomysql>=0.2.0",
|
|
16
16
|
"aiosqlite>=0.21.0",
|
|
17
|
-
"
|
|
17
|
+
"duckdb>=0.9.2",
|
|
18
18
|
"fastmcp>=2.9.0",
|
|
19
19
|
"cyclopts>=3.22.1",
|
|
20
20
|
"prompt-toolkit>3.0.51",
|
|
@@ -8,6 +8,7 @@ from typing import Any, AsyncIterator
|
|
|
8
8
|
from sqlsaber.database.connection import (
|
|
9
9
|
BaseDatabaseConnection,
|
|
10
10
|
CSVConnection,
|
|
11
|
+
DuckDBConnection,
|
|
11
12
|
MySQLConnection,
|
|
12
13
|
PostgreSQLConnection,
|
|
13
14
|
SQLiteConnection,
|
|
@@ -51,7 +52,9 @@ class BaseSQLAgent(ABC):
|
|
|
51
52
|
elif isinstance(self.db, SQLiteConnection):
|
|
52
53
|
return "SQLite"
|
|
53
54
|
elif isinstance(self.db, CSVConnection):
|
|
54
|
-
return "
|
|
55
|
+
return "DuckDB"
|
|
56
|
+
elif isinstance(self.db, DuckDBConnection):
|
|
57
|
+
return "DuckDB"
|
|
55
58
|
else:
|
|
56
59
|
return "database" # Fallback
|
|
57
60
|
|
|
@@ -17,6 +17,7 @@ from sqlsaber.config.settings import Config
|
|
|
17
17
|
from sqlsaber.database.connection import (
|
|
18
18
|
BaseDatabaseConnection,
|
|
19
19
|
CSVConnection,
|
|
20
|
+
DuckDBConnection,
|
|
20
21
|
MySQLConnection,
|
|
21
22
|
PostgreSQLConnection,
|
|
22
23
|
SQLiteConnection,
|
|
@@ -169,7 +170,9 @@ def _get_database_type_name(db: BaseDatabaseConnection) -> str:
|
|
|
169
170
|
return "MySQL"
|
|
170
171
|
elif isinstance(db, SQLiteConnection):
|
|
171
172
|
return "SQLite"
|
|
173
|
+
elif isinstance(db, DuckDBConnection):
|
|
174
|
+
return "DuckDB"
|
|
172
175
|
elif isinstance(db, CSVConnection):
|
|
173
|
-
return "
|
|
176
|
+
return "DuckDB"
|
|
174
177
|
else:
|
|
175
178
|
return "database"
|
|
@@ -46,7 +46,7 @@ def meta_handler(
|
|
|
46
46
|
str | None,
|
|
47
47
|
cyclopts.Parameter(
|
|
48
48
|
["--database", "-d"],
|
|
49
|
-
help="Database connection name, file path (CSV/SQLite), or connection string (postgresql://, mysql://) (uses default if not specified)",
|
|
49
|
+
help="Database connection name, file path (CSV/SQLite/DuckDB), or connection string (postgresql://, mysql://, duckdb://) (uses default if not specified)",
|
|
50
50
|
),
|
|
51
51
|
] = None,
|
|
52
52
|
):
|
|
@@ -59,8 +59,10 @@ def meta_handler(
|
|
|
59
59
|
saber -d mydb "show me users" # Run a query with specific database
|
|
60
60
|
saber -d data.csv "show me users" # Run a query with ad-hoc CSV file
|
|
61
61
|
saber -d data.db "show me users" # Run a query with ad-hoc SQLite file
|
|
62
|
+
saber -d data.duckdb "show me users" # Run a query with ad-hoc DuckDB file
|
|
62
63
|
saber -d "postgresql://user:pass@host:5432/db" "show users" # PostgreSQL connection string
|
|
63
64
|
saber -d "mysql://user:pass@host:3306/db" "show users" # MySQL connection string
|
|
65
|
+
saber -d "duckdb:///data.duckdb" "show users" # DuckDB connection string
|
|
64
66
|
echo "show me all users" | saber # Read query from stdin
|
|
65
67
|
cat query.txt | saber # Read query from file via stdin
|
|
66
68
|
"""
|
|
@@ -80,7 +82,7 @@ def query(
|
|
|
80
82
|
str | None,
|
|
81
83
|
cyclopts.Parameter(
|
|
82
84
|
["--database", "-d"],
|
|
83
|
-
help="Database connection name, file path (CSV/SQLite), or connection string (postgresql://, mysql://) (uses default if not specified)",
|
|
85
|
+
help="Database connection name, file path (CSV/SQLite/DuckDB), or connection string (postgresql://, mysql://, duckdb://) (uses default if not specified)",
|
|
84
86
|
),
|
|
85
87
|
] = None,
|
|
86
88
|
):
|
|
@@ -97,8 +99,10 @@ def query(
|
|
|
97
99
|
saber "show me all users" # Run a single query
|
|
98
100
|
saber -d data.csv "show users" # Run a query with ad-hoc CSV file
|
|
99
101
|
saber -d data.db "show users" # Run a query with ad-hoc SQLite file
|
|
102
|
+
saber -d data.duckdb "show users" # Run a query with ad-hoc DuckDB file
|
|
100
103
|
saber -d "postgresql://user:pass@host:5432/db" "show users" # PostgreSQL connection string
|
|
101
104
|
saber -d "mysql://user:pass@host:3306/db" "show users" # MySQL connection string
|
|
105
|
+
saber -d "duckdb:///data.duckdb" "show users" # DuckDB connection string
|
|
102
106
|
echo "show me all users" | saber # Read query from stdin
|
|
103
107
|
"""
|
|
104
108
|
|
|
@@ -111,6 +115,7 @@ def query(
|
|
|
111
115
|
from sqlsaber.database.connection import (
|
|
112
116
|
CSVConnection,
|
|
113
117
|
DatabaseConnection,
|
|
118
|
+
DuckDBConnection,
|
|
114
119
|
MySQLConnection,
|
|
115
120
|
PostgreSQLConnection,
|
|
116
121
|
SQLiteConnection,
|
|
@@ -149,15 +154,18 @@ def query(
|
|
|
149
154
|
# Single query mode with streaming
|
|
150
155
|
streaming_handler = StreamingQueryHandler(console)
|
|
151
156
|
# Compute DB type for the greeting line
|
|
152
|
-
|
|
153
|
-
"PostgreSQL"
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
)
|
|
157
|
+
if isinstance(db_conn, PostgreSQLConnection):
|
|
158
|
+
db_type = "PostgreSQL"
|
|
159
|
+
elif isinstance(db_conn, MySQLConnection):
|
|
160
|
+
db_type = "MySQL"
|
|
161
|
+
elif isinstance(db_conn, DuckDBConnection):
|
|
162
|
+
db_type = "DuckDB"
|
|
163
|
+
elif isinstance(db_conn, SQLiteConnection):
|
|
164
|
+
db_type = "SQLite"
|
|
165
|
+
elif isinstance(db_conn, CSVConnection):
|
|
166
|
+
db_type = "DuckDB"
|
|
167
|
+
else:
|
|
168
|
+
db_type = "database"
|
|
161
169
|
console.print(
|
|
162
170
|
f"[bold blue]Connected to:[/bold blue] {db_name} ({db_type})\n"
|
|
163
171
|
)
|
|
@@ -31,7 +31,7 @@ def add(
|
|
|
31
31
|
str,
|
|
32
32
|
cyclopts.Parameter(
|
|
33
33
|
["--type", "-t"],
|
|
34
|
-
help="Database type (postgresql, mysql, sqlite)",
|
|
34
|
+
help="Database type (postgresql, mysql, sqlite, duckdb)",
|
|
35
35
|
),
|
|
36
36
|
] = "postgresql",
|
|
37
37
|
host: Annotated[
|
|
@@ -87,17 +87,17 @@ def add(
|
|
|
87
87
|
if not type or type == "postgresql":
|
|
88
88
|
type = questionary.select(
|
|
89
89
|
"Database type:",
|
|
90
|
-
choices=["postgresql", "mysql", "sqlite"],
|
|
90
|
+
choices=["postgresql", "mysql", "sqlite", "duckdb"],
|
|
91
91
|
default="postgresql",
|
|
92
92
|
).ask()
|
|
93
93
|
|
|
94
|
-
if type
|
|
95
|
-
# SQLite only
|
|
94
|
+
if type in {"sqlite", "duckdb"}:
|
|
95
|
+
# SQLite/DuckDB only need database file path
|
|
96
96
|
database = database or questionary.path("Database file path:").ask()
|
|
97
97
|
database = str(Path(database).expanduser().resolve())
|
|
98
98
|
host = "localhost"
|
|
99
99
|
port = 0
|
|
100
|
-
username =
|
|
100
|
+
username = type
|
|
101
101
|
password = ""
|
|
102
102
|
else:
|
|
103
103
|
# PostgreSQL/MySQL need connection details
|
|
@@ -182,6 +182,17 @@ def add(
|
|
|
182
182
|
port = 0
|
|
183
183
|
username = "sqlite"
|
|
184
184
|
password = ""
|
|
185
|
+
elif type == "duckdb":
|
|
186
|
+
if not database:
|
|
187
|
+
console.print(
|
|
188
|
+
"[bold red]Error:[/bold red] Database file path is required for DuckDB"
|
|
189
|
+
)
|
|
190
|
+
sys.exit(1)
|
|
191
|
+
database = str(Path(database).expanduser().resolve())
|
|
192
|
+
host = "localhost"
|
|
193
|
+
port = 0
|
|
194
|
+
username = "duckdb"
|
|
195
|
+
password = ""
|
|
185
196
|
else:
|
|
186
197
|
if not all([host, database, username]):
|
|
187
198
|
console.print(
|
|
@@ -264,7 +275,7 @@ def list():
|
|
|
264
275
|
if db.ssl_ca or db.ssl_cert:
|
|
265
276
|
ssl_status += " (certs)"
|
|
266
277
|
else:
|
|
267
|
-
ssl_status = "disabled" if db.type
|
|
278
|
+
ssl_status = "disabled" if db.type not in {"sqlite", "duckdb"} else "N/A"
|
|
268
279
|
|
|
269
280
|
table.add_row(
|
|
270
281
|
db.name,
|
|
@@ -23,6 +23,7 @@ from sqlsaber.cli.display import DisplayManager
|
|
|
23
23
|
from sqlsaber.cli.streaming import StreamingQueryHandler
|
|
24
24
|
from sqlsaber.database.connection import (
|
|
25
25
|
CSVConnection,
|
|
26
|
+
DuckDBConnection,
|
|
26
27
|
MySQLConnection,
|
|
27
28
|
PostgreSQLConnection,
|
|
28
29
|
SQLiteConnection,
|
|
@@ -85,8 +86,12 @@ class InteractiveSession:
|
|
|
85
86
|
if isinstance(self.db_conn, PostgreSQLConnection)
|
|
86
87
|
else "MySQL"
|
|
87
88
|
if isinstance(self.db_conn, MySQLConnection)
|
|
89
|
+
else "DuckDB"
|
|
90
|
+
if isinstance(self.db_conn, DuckDBConnection)
|
|
91
|
+
else "DuckDB"
|
|
92
|
+
if isinstance(self.db_conn, CSVConnection)
|
|
88
93
|
else "SQLite"
|
|
89
|
-
if isinstance(self.db_conn,
|
|
94
|
+
if isinstance(self.db_conn, SQLiteConnection)
|
|
90
95
|
else "database"
|
|
91
96
|
)
|
|
92
97
|
|