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.

Files changed (107) hide show
  1. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/PKG-INFO +4 -3
  2. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/README.md +2 -1
  3. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/changelog.md +8 -0
  4. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/guides/database-setup.mdx +15 -2
  5. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/guides/getting-started.mdx +2 -1
  6. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/guides/queries.mdx +4 -1
  7. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/index.mdx +1 -1
  8. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/reference/commands.md +48 -7
  9. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/pyproject.toml +2 -2
  10. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/agents/base.py +4 -1
  11. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/agents/pydantic_ai_agent.py +4 -1
  12. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/commands.py +19 -11
  13. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/database.py +17 -6
  14. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/interactive.py +6 -1
  15. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/config/database.py +3 -1
  16. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/database/connection.py +123 -99
  17. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/database/resolver.py +7 -3
  18. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/database/schema.py +225 -1
  19. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_config/test_database.py +26 -1
  20. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_database/test_connection.py +9 -0
  21. sqlsaber-0.25.0/tests/test_database/test_csv_connection.py +42 -0
  22. sqlsaber-0.25.0/tests/test_database/test_schema.py +47 -0
  23. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_database_resolver.py +24 -2
  24. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/uv.lock +865 -938
  25. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/.github/workflows/claude-code-review.yml +0 -0
  26. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/.github/workflows/claude.yml +0 -0
  27. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/.github/workflows/deploy-docs.yml +0 -0
  28. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/.github/workflows/publish.yml +0 -0
  29. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/.github/workflows/test.yml +0 -0
  30. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/.gitignore +0 -0
  31. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/.python-version +0 -0
  32. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/AGENT.md +0 -0
  33. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/CLAUDE.md +0 -0
  34. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/LICENSE +0 -0
  35. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/.gitignore +0 -0
  36. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/.vscode/extensions.json +0 -0
  37. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/.vscode/launch.json +0 -0
  38. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/CLAUDE.md +0 -0
  39. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/astro.config.mjs +0 -0
  40. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/package-lock.json +0 -0
  41. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/package.json +0 -0
  42. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/public/CNAME +0 -0
  43. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/public/favicon.svg +0 -0
  44. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/assets/sqlsaber-hero.svg +0 -0
  45. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/guides/authentication.mdx +0 -0
  46. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/guides/memory.mdx +0 -0
  47. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/guides/models.mdx +0 -0
  48. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/guides/threads.md +0 -0
  49. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content/docs/installation.mdx +0 -0
  50. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/content.config.ts +0 -0
  51. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/src/styles/global.css +0 -0
  52. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/docs/tsconfig.json +0 -0
  53. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/legislators.db +0 -0
  54. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/pytest.ini +0 -0
  55. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/sqlsaber.gif +0 -0
  56. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/sqlsaber.svg +0 -0
  57. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/__init__.py +0 -0
  58. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/__main__.py +0 -0
  59. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/agents/__init__.py +0 -0
  60. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/agents/mcp.py +0 -0
  61. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/__init__.py +0 -0
  62. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/auth.py +0 -0
  63. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/completers.py +0 -0
  64. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/display.py +0 -0
  65. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/memory.py +0 -0
  66. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/models.py +0 -0
  67. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/streaming.py +0 -0
  68. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/cli/threads.py +0 -0
  69. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/config/__init__.py +0 -0
  70. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/config/api_keys.py +0 -0
  71. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/config/auth.py +0 -0
  72. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/config/oauth_flow.py +0 -0
  73. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/config/oauth_tokens.py +0 -0
  74. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/config/providers.py +0 -0
  75. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/config/settings.py +0 -0
  76. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/database/__init__.py +0 -0
  77. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/mcp/__init__.py +0 -0
  78. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/mcp/mcp.py +0 -0
  79. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/memory/__init__.py +0 -0
  80. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/memory/manager.py +0 -0
  81. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/memory/storage.py +0 -0
  82. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/threads/__init__.py +0 -0
  83. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/threads/storage.py +0 -0
  84. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/tools/__init__.py +0 -0
  85. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/tools/base.py +0 -0
  86. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/tools/enums.py +0 -0
  87. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/tools/instructions.py +0 -0
  88. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/tools/registry.py +0 -0
  89. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/src/sqlsaber/tools/sql_tools.py +0 -0
  90. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/__init__.py +0 -0
  91. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/conftest.py +0 -0
  92. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_cli/__init__.py +0 -0
  93. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_cli/test_auth_reset.py +0 -0
  94. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_cli/test_commands.py +0 -0
  95. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_cli/test_threads.py +0 -0
  96. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_config/__init__.py +0 -0
  97. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_config/test_oauth.py +0 -0
  98. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_config/test_providers.py +0 -0
  99. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_config/test_settings.py +0 -0
  100. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_database/__init__.py +0 -0
  101. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_database/test_timeout.py +0 -0
  102. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_threads_storage.py +0 -0
  103. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_tools/__init__.py +0 -0
  104. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_tools/test_base.py +0 -0
  105. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_tools/test_instructions.py +0 -0
  106. {sqlsaber-0.24.0 → sqlsaber-0.25.0}/tests/test_tools/test_registry.py +0 -0
  107. {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.24.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 MySQL
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 MySQL
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, and SQLite databases as well as CSV files. This guide covers all the ways to configure database connections.
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 SQLite)
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
- - `-t, --type` - Database type: `postgresql`, `mysql`, `sqlite` (default: postgresql)
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
- *PostgreSQL:*
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
- *MySQL:*
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.24.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
- "pandas>=2.0.0",
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 "SQLite" # we convert csv to in-memory sqlite
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 "SQLite"
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
- db_type = (
153
- "PostgreSQL"
154
- if isinstance(db_conn, PostgreSQLConnection)
155
- else "MySQL"
156
- if isinstance(db_conn, MySQLConnection)
157
- else "SQLite"
158
- if isinstance(db_conn, (SQLiteConnection, CSVConnection))
159
- else "database"
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 == "sqlite":
95
- # SQLite only needs database path
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 = "sqlite"
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 != "sqlite" else "N/A"
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, (SQLiteConnection, CSVConnection))
94
+ if isinstance(self.db_conn, SQLiteConnection)
90
95
  else "database"
91
96
  )
92
97