sqlsaber 0.17.0__py3-none-any.whl → 0.19.0__py3-none-any.whl
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/cli/commands.py +51 -32
- sqlsaber/cli/interactive.py +45 -9
- sqlsaber/database/connection.py +4 -1
- {sqlsaber-0.17.0.dist-info → sqlsaber-0.19.0.dist-info}/METADATA +2 -1
- {sqlsaber-0.17.0.dist-info → sqlsaber-0.19.0.dist-info}/RECORD +8 -8
- {sqlsaber-0.17.0.dist-info → sqlsaber-0.19.0.dist-info}/WHEEL +0 -0
- {sqlsaber-0.17.0.dist-info → sqlsaber-0.19.0.dist-info}/entry_points.txt +0 -0
- {sqlsaber-0.17.0.dist-info → sqlsaber-0.19.0.dist-info}/licenses/LICENSE +0 -0
sqlsaber/cli/commands.py
CHANGED
|
@@ -7,24 +7,8 @@ from typing import Annotated
|
|
|
7
7
|
import cyclopts
|
|
8
8
|
from rich.console import Console
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
from sqlsaber.cli.auth import create_auth_app
|
|
12
|
-
from sqlsaber.cli.database import create_db_app
|
|
13
|
-
from sqlsaber.cli.interactive import InteractiveSession
|
|
14
|
-
from sqlsaber.cli.memory import create_memory_app
|
|
15
|
-
from sqlsaber.cli.models import create_models_app
|
|
16
|
-
from sqlsaber.cli.streaming import StreamingQueryHandler
|
|
17
|
-
from sqlsaber.cli.threads import create_threads_app
|
|
10
|
+
# Lazy imports - only import what's needed for CLI parsing
|
|
18
11
|
from sqlsaber.config.database import DatabaseConfigManager
|
|
19
|
-
from sqlsaber.database.connection import (
|
|
20
|
-
CSVConnection,
|
|
21
|
-
DatabaseConnection,
|
|
22
|
-
MySQLConnection,
|
|
23
|
-
PostgreSQLConnection,
|
|
24
|
-
SQLiteConnection,
|
|
25
|
-
)
|
|
26
|
-
from sqlsaber.database.resolver import DatabaseResolutionError, resolve_database
|
|
27
|
-
from sqlsaber.threads import ThreadStorage
|
|
28
12
|
|
|
29
13
|
|
|
30
14
|
class CLIError(Exception):
|
|
@@ -108,6 +92,21 @@ def query(
|
|
|
108
92
|
"""
|
|
109
93
|
|
|
110
94
|
async def run_session():
|
|
95
|
+
# Import heavy dependencies only when actually running a query
|
|
96
|
+
# This is only done to speed up startup time
|
|
97
|
+
from sqlsaber.agents import build_sqlsaber_agent
|
|
98
|
+
from sqlsaber.cli.interactive import InteractiveSession
|
|
99
|
+
from sqlsaber.cli.streaming import StreamingQueryHandler
|
|
100
|
+
from sqlsaber.database.connection import (
|
|
101
|
+
CSVConnection,
|
|
102
|
+
DatabaseConnection,
|
|
103
|
+
MySQLConnection,
|
|
104
|
+
PostgreSQLConnection,
|
|
105
|
+
SQLiteConnection,
|
|
106
|
+
)
|
|
107
|
+
from sqlsaber.database.resolver import DatabaseResolutionError, resolve_database
|
|
108
|
+
from sqlsaber.threads import ThreadStorage
|
|
109
|
+
|
|
111
110
|
# Check if query_text is None and stdin has data
|
|
112
111
|
actual_query = query_text
|
|
113
112
|
if query_text is None and not sys.stdin.isatty():
|
|
@@ -196,25 +195,45 @@ def query(
|
|
|
196
195
|
sys.exit(e.exit_code)
|
|
197
196
|
|
|
198
197
|
|
|
199
|
-
#
|
|
200
|
-
|
|
201
|
-
|
|
198
|
+
# Use lazy imports for fast CLI startup time
|
|
199
|
+
@app.command(name="auth")
|
|
200
|
+
def auth(*args, **kwargs):
|
|
201
|
+
"""Manage authentication configuration."""
|
|
202
|
+
from sqlsaber.cli.auth import create_auth_app
|
|
203
|
+
|
|
204
|
+
return create_auth_app()(*args, **kwargs)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@app.command(name="db")
|
|
208
|
+
def db(*args, **kwargs):
|
|
209
|
+
"""Manage database connections."""
|
|
210
|
+
from sqlsaber.cli.database import create_db_app
|
|
211
|
+
|
|
212
|
+
return create_db_app()(*args, **kwargs)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
@app.command(name="memory")
|
|
216
|
+
def memory(*args, **kwargs):
|
|
217
|
+
"""Manage database-specific memories."""
|
|
218
|
+
from sqlsaber.cli.memory import create_memory_app
|
|
219
|
+
|
|
220
|
+
return create_memory_app()(*args, **kwargs)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
@app.command(name="models")
|
|
224
|
+
def models(*args, **kwargs):
|
|
225
|
+
"""Select and manage models."""
|
|
226
|
+
from sqlsaber.cli.models import create_models_app
|
|
202
227
|
|
|
203
|
-
|
|
204
|
-
db_app = create_db_app()
|
|
205
|
-
app.command(db_app, name="db")
|
|
228
|
+
return create_models_app()(*args, **kwargs)
|
|
206
229
|
|
|
207
|
-
# Add memory management commands
|
|
208
|
-
memory_app = create_memory_app()
|
|
209
|
-
app.command(memory_app, name="memory")
|
|
210
230
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
231
|
+
@app.command(name="threads")
|
|
232
|
+
def threads(*args, **kwargs):
|
|
233
|
+
"""Manage SQLsaber threads."""
|
|
234
|
+
from sqlsaber.cli.threads import create_threads_app
|
|
214
235
|
|
|
215
|
-
|
|
216
|
-
threads_app = create_threads_app()
|
|
217
|
-
app.command(threads_app, name="threads")
|
|
236
|
+
return create_threads_app()(*args, **kwargs)
|
|
218
237
|
|
|
219
238
|
|
|
220
239
|
def main():
|
sqlsaber/cli/interactive.py
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
"""Interactive mode handling for the CLI."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
from pathlib import Path
|
|
4
5
|
|
|
5
|
-
import
|
|
6
|
+
import platformdirs
|
|
7
|
+
from prompt_toolkit import PromptSession
|
|
8
|
+
from prompt_toolkit.history import FileHistory
|
|
9
|
+
from prompt_toolkit.styles import Style
|
|
6
10
|
from pydantic_ai import Agent
|
|
7
11
|
from rich.console import Console
|
|
8
12
|
from rich.panel import Panel
|
|
@@ -24,6 +28,23 @@ from sqlsaber.database.schema import SchemaManager
|
|
|
24
28
|
from sqlsaber.threads import ThreadStorage
|
|
25
29
|
|
|
26
30
|
|
|
31
|
+
def bottom_toolbar():
|
|
32
|
+
return [
|
|
33
|
+
(
|
|
34
|
+
"class:bottom-toolbar",
|
|
35
|
+
" Use 'Esc-Enter' or 'Meta-Enter' to submit.",
|
|
36
|
+
)
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
style = Style.from_dict(
|
|
41
|
+
{
|
|
42
|
+
"frame.border": "#ebbcba",
|
|
43
|
+
"bottom-toolbar": "#ebbcba bg:#21202e",
|
|
44
|
+
}
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
27
48
|
class InteractiveSession:
|
|
28
49
|
"""Manages interactive CLI sessions."""
|
|
29
50
|
|
|
@@ -82,7 +103,7 @@ class InteractiveSession:
|
|
|
82
103
|
self.console.print(
|
|
83
104
|
"\n",
|
|
84
105
|
"[dim] > Use '/clear' to reset conversation",
|
|
85
|
-
"[dim] > Use '/exit' or '/quit' to leave[/dim]",
|
|
106
|
+
"[dim] > Use 'Ctrl+D', '/exit' or '/quit' to leave[/dim]",
|
|
86
107
|
"[dim] > Use 'Ctrl+C' to interrupt and return to prompt\n\n",
|
|
87
108
|
"[dim] > Start message with '#' to add something to agent's memory for this database",
|
|
88
109
|
"[dim] > Type '@' to get table name completions",
|
|
@@ -137,7 +158,10 @@ class InteractiveSession:
|
|
|
137
158
|
# Create the query task
|
|
138
159
|
query_task = asyncio.create_task(
|
|
139
160
|
self.streaming_handler.execute_streaming_query(
|
|
140
|
-
user_query,
|
|
161
|
+
user_query,
|
|
162
|
+
self.agent,
|
|
163
|
+
self.cancellation_token,
|
|
164
|
+
self.message_history,
|
|
141
165
|
)
|
|
142
166
|
)
|
|
143
167
|
self.current_task = query_task
|
|
@@ -183,17 +207,26 @@ class InteractiveSession:
|
|
|
183
207
|
# Initialize table cache
|
|
184
208
|
await self._update_table_cache()
|
|
185
209
|
|
|
210
|
+
session = PromptSession(
|
|
211
|
+
history=FileHistory(
|
|
212
|
+
Path(platformdirs.user_config_dir("sqlsaber")) / "history"
|
|
213
|
+
)
|
|
214
|
+
)
|
|
215
|
+
|
|
186
216
|
while True:
|
|
187
217
|
try:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
218
|
+
# with patch_stdout():
|
|
219
|
+
user_query = await session.prompt_async(
|
|
220
|
+
"",
|
|
191
221
|
multiline=True,
|
|
192
|
-
|
|
222
|
+
mouse_support=True,
|
|
193
223
|
completer=CompositeCompleter(
|
|
194
224
|
SlashCommandCompleter(), self.table_completer
|
|
195
225
|
),
|
|
196
|
-
|
|
226
|
+
show_frame=True,
|
|
227
|
+
bottom_toolbar=bottom_toolbar,
|
|
228
|
+
style=style,
|
|
229
|
+
)
|
|
197
230
|
|
|
198
231
|
if not user_query:
|
|
199
232
|
continue
|
|
@@ -276,7 +309,10 @@ class InteractiveSession:
|
|
|
276
309
|
self.console.print("\n[yellow]Query interrupted[/yellow]")
|
|
277
310
|
else:
|
|
278
311
|
self.console.print(
|
|
279
|
-
"\n[yellow]
|
|
312
|
+
"\n[yellow]Press Ctrl+D to exit. Or use '/exit' or '/quit' slash command.[/yellow]"
|
|
280
313
|
)
|
|
314
|
+
except EOFError:
|
|
315
|
+
# Exit when Ctrl+D is pressed
|
|
316
|
+
break
|
|
281
317
|
except Exception as e:
|
|
282
318
|
self.console.print(f"[bold red]Error:[/bold red] {str(e)}")
|
sqlsaber/database/connection.py
CHANGED
|
@@ -9,7 +9,6 @@ from urllib.parse import parse_qs, urlparse
|
|
|
9
9
|
import aiomysql
|
|
10
10
|
import aiosqlite
|
|
11
11
|
import asyncpg
|
|
12
|
-
import pandas as pd
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
class BaseDatabaseConnection(ABC):
|
|
@@ -324,6 +323,10 @@ class CSVConnection(BaseDatabaseConnection):
|
|
|
324
323
|
return
|
|
325
324
|
|
|
326
325
|
try:
|
|
326
|
+
# Import pandas only when needed for CSV operations
|
|
327
|
+
# This improves CLI load times
|
|
328
|
+
import pandas as pd
|
|
329
|
+
|
|
327
330
|
# Read CSV file using pandas
|
|
328
331
|
df = pd.read_csv(
|
|
329
332
|
self.csv_path,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlsaber
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.19.0
|
|
4
4
|
Summary: SQLsaber - Open-source agentic SQL assistant
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Requires-Python: >=3.12
|
|
@@ -13,6 +13,7 @@ Requires-Dist: httpx>=0.28.1
|
|
|
13
13
|
Requires-Dist: keyring>=25.6.0
|
|
14
14
|
Requires-Dist: pandas>=2.0.0
|
|
15
15
|
Requires-Dist: platformdirs>=4.0.0
|
|
16
|
+
Requires-Dist: prompt-toolkit>3.0.51
|
|
16
17
|
Requires-Dist: pydantic-ai
|
|
17
18
|
Requires-Dist: questionary>=2.1.0
|
|
18
19
|
Requires-Dist: rich>=13.7.0
|
|
@@ -6,11 +6,11 @@ sqlsaber/agents/mcp.py,sha256=GcJTx7YDYH6aaxIADEIxSgcWAdWakUx395JIzVnf17U,768
|
|
|
6
6
|
sqlsaber/agents/pydantic_ai_agent.py,sha256=dGdsgyxCZvfK-v-MH8KimKOr-xb2aSfSWY8CMcOUCT8,6795
|
|
7
7
|
sqlsaber/cli/__init__.py,sha256=qVSLVJLLJYzoC6aj6y9MFrzZvAwc4_OgxU9DlkQnZ4M,86
|
|
8
8
|
sqlsaber/cli/auth.py,sha256=jTsRgbmlGPlASSuIKmdjjwfqtKvjfKd_cTYxX0-QqaQ,7400
|
|
9
|
-
sqlsaber/cli/commands.py,sha256=
|
|
9
|
+
sqlsaber/cli/commands.py,sha256=CmCqDC6KiE8JD6Vkpsry4lBQInCiS8TBeKKx3gdxZcM,8689
|
|
10
10
|
sqlsaber/cli/completers.py,sha256=HsUPjaZweLSeYCWkAcgMl8FylQ1xjWBWYTEL_9F6xfU,6430
|
|
11
11
|
sqlsaber/cli/database.py,sha256=atwg3l8acQ3YTDuhq7vNrBN6tpOv0syz6V62KTF-Bh8,12910
|
|
12
12
|
sqlsaber/cli/display.py,sha256=wa7BjTBwXwqLT145Q1AEL0C28pQJTrvDN10mnFMjqsg,8554
|
|
13
|
-
sqlsaber/cli/interactive.py,sha256=
|
|
13
|
+
sqlsaber/cli/interactive.py,sha256=uoJdLWPoaDBkfdFN-59u6zduU8XGY98L16zpNsGu7nE,12964
|
|
14
14
|
sqlsaber/cli/memory.py,sha256=OufHFJFwV0_GGn7LvKRTJikkWhV1IwNIUDOxFPHXOaQ,7794
|
|
15
15
|
sqlsaber/cli/models.py,sha256=ZewtwGQwhd9b-yxBAPKePolvI1qQG-EkmeWAGMqtWNQ,8986
|
|
16
16
|
sqlsaber/cli/streaming.py,sha256=WNqBYYbWtL5CNQkRg5YWhYpWKI8qz7JmqneB2DXTOHY,5259
|
|
@@ -24,7 +24,7 @@ sqlsaber/config/oauth_tokens.py,sha256=C9z35hyx-PvSAYdC1LNf3rg9_wsEIY56hkEczelba
|
|
|
24
24
|
sqlsaber/config/providers.py,sha256=JFjeJv1K5Q93zWSlWq3hAvgch1TlgoF0qFa0KJROkKY,2957
|
|
25
25
|
sqlsaber/config/settings.py,sha256=vgb_RXaM-7DgbxYDmWNw1cSyMqwys4j3qNCvM4bljwI,5586
|
|
26
26
|
sqlsaber/database/__init__.py,sha256=a_gtKRJnZVO8-fEZI7g3Z8YnGa6Nio-5Y50PgVp07ss,176
|
|
27
|
-
sqlsaber/database/connection.py,sha256=
|
|
27
|
+
sqlsaber/database/connection.py,sha256=kwx18bnwr4kyTUfQT0OW-DXzJUNWIQJP54spJBqU_48,15243
|
|
28
28
|
sqlsaber/database/resolver.py,sha256=RPXF5EoKzvQDDLmPGNHYd2uG_oNICH8qvUjBp6iXmNY,3348
|
|
29
29
|
sqlsaber/database/schema.py,sha256=r12qoN3tdtAXdO22EKlauAe7QwOm8lL2vTMM59XEMMY,26594
|
|
30
30
|
sqlsaber/mcp/__init__.py,sha256=COdWq7wauPBp5Ew8tfZItFzbcLDSEkHBJSMhxzy8C9c,112
|
|
@@ -40,8 +40,8 @@ sqlsaber/tools/enums.py,sha256=CH32mL-0k9ZA18911xLpNtsgpV6tB85TktMj6uqGz54,411
|
|
|
40
40
|
sqlsaber/tools/instructions.py,sha256=X-x8maVkkyi16b6Tl0hcAFgjiYceZaSwyWTfmrvx8U8,9024
|
|
41
41
|
sqlsaber/tools/registry.py,sha256=HWOQMsNIdL4XZS6TeNUyrL-5KoSDH6PHsWd3X66o-18,3211
|
|
42
42
|
sqlsaber/tools/sql_tools.py,sha256=hM6tKqW5MDhFUt6MesoqhTUqIpq_5baIIDoN1MjDCXY,9647
|
|
43
|
-
sqlsaber-0.
|
|
44
|
-
sqlsaber-0.
|
|
45
|
-
sqlsaber-0.
|
|
46
|
-
sqlsaber-0.
|
|
47
|
-
sqlsaber-0.
|
|
43
|
+
sqlsaber-0.19.0.dist-info/METADATA,sha256=oH4qQnKuu5n7ucEEtSccDyvI1obYPPeZV3xNAn-8Mzc,6178
|
|
44
|
+
sqlsaber-0.19.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
45
|
+
sqlsaber-0.19.0.dist-info/entry_points.txt,sha256=qEbOB7OffXPFgyJc7qEIJlMEX5RN9xdzLmWZa91zCQQ,162
|
|
46
|
+
sqlsaber-0.19.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
47
|
+
sqlsaber-0.19.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|