sqlsaber 0.19.0__tar.gz → 0.20.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.19.0 → sqlsaber-0.20.0}/PKG-INFO +1 -1
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/src/content/docs/changelog.md +8 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/pyproject.toml +1 -1
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/cli/commands.py +11 -41
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/cli/database.py +3 -1
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/cli/interactive.py +24 -19
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/cli/threads.py +14 -7
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/test_cli/test_threads.py +12 -8
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/uv.lock +1 -1
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/.github/workflows/claude-code-review.yml +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/.github/workflows/claude.yml +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/.github/workflows/deploy-docs.yml +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/.github/workflows/publish.yml +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/.github/workflows/test.yml +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/.gitignore +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/.python-version +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/AGENT.md +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/CLAUDE.md +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/LICENSE +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/README.md +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/.gitignore +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/.vscode/extensions.json +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/.vscode/launch.json +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/CLAUDE.md +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/astro.config.mjs +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/package-lock.json +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/package.json +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/public/CNAME +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/public/favicon.svg +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/src/assets/sqlsaber-hero.svg +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/src/content/docs/guides/authentication.mdx +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/src/content/docs/guides/database-setup.mdx +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/src/content/docs/guides/getting-started.mdx +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/src/content/docs/guides/memory.mdx +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/src/content/docs/guides/models.mdx +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/src/content/docs/guides/queries.mdx +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/src/content/docs/guides/threads.md +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/src/content/docs/index.mdx +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/src/content/docs/installation.mdx +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/src/content/docs/reference/commands.md +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/src/content.config.ts +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/src/styles/global.css +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/docs/tsconfig.json +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/legislators.db +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/pytest.ini +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/sqlsaber.gif +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/sqlsaber.svg +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/__init__.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/__main__.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/agents/__init__.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/agents/base.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/agents/mcp.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/agents/pydantic_ai_agent.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/cli/__init__.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/cli/auth.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/cli/completers.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/cli/display.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/cli/memory.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/cli/models.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/cli/streaming.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/config/__init__.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/config/api_keys.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/config/auth.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/config/database.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/config/oauth_flow.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/config/oauth_tokens.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/config/providers.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/config/settings.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/database/__init__.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/database/connection.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/database/resolver.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/database/schema.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/mcp/__init__.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/mcp/mcp.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/memory/__init__.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/memory/manager.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/memory/storage.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/threads/__init__.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/threads/storage.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/tools/__init__.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/tools/base.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/tools/enums.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/tools/instructions.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/tools/registry.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/src/sqlsaber/tools/sql_tools.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/__init__.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/conftest.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/test_cli/__init__.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/test_cli/test_auth_reset.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/test_cli/test_commands.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/test_config/__init__.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/test_config/test_database.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/test_config/test_oauth.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/test_config/test_providers.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/test_config/test_settings.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/test_database/__init__.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/test_database/test_connection.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/test_database_resolver.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/test_threads_storage.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/test_tools/__init__.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/test_tools/test_base.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/test_tools/test_instructions.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/test_tools/test_registry.py +0 -0
- {sqlsaber-0.19.0 → sqlsaber-0.20.0}/tests/test_tools/test_sql_tools.py +0 -0
|
@@ -9,6 +9,14 @@ All notable changes to SQLsaber will be documented here.
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
+
### v0.20.0 - 2025-09-10
|
|
13
|
+
|
|
14
|
+
#### Fixed
|
|
15
|
+
|
|
16
|
+
- Subcommand help visibility for nested apps
|
|
17
|
+
- Removed mouse support for user prompt
|
|
18
|
+
- Enabling mouse support disables terminal scrolling when user prompt is focused
|
|
19
|
+
|
|
12
20
|
### v0.19.0 - 2025-09-09
|
|
13
21
|
|
|
14
22
|
#### Added
|
|
@@ -7,6 +7,12 @@ from typing import Annotated
|
|
|
7
7
|
import cyclopts
|
|
8
8
|
from rich.console import Console
|
|
9
9
|
|
|
10
|
+
from sqlsaber.cli.auth import create_auth_app
|
|
11
|
+
from sqlsaber.cli.database import create_db_app
|
|
12
|
+
from sqlsaber.cli.memory import create_memory_app
|
|
13
|
+
from sqlsaber.cli.models import create_models_app
|
|
14
|
+
from sqlsaber.cli.threads import create_threads_app
|
|
15
|
+
|
|
10
16
|
# Lazy imports - only import what's needed for CLI parsing
|
|
11
17
|
from sqlsaber.config.database import DatabaseConfigManager
|
|
12
18
|
|
|
@@ -24,6 +30,11 @@ app = cyclopts.App(
|
|
|
24
30
|
help="SQLsaber - Open-source agentic SQL assistant for your database",
|
|
25
31
|
)
|
|
26
32
|
|
|
33
|
+
app.command(create_auth_app(), name="auth")
|
|
34
|
+
app.command(create_db_app(), name="db")
|
|
35
|
+
app.command(create_memory_app(), name="memory")
|
|
36
|
+
app.command(create_models_app(), name="models")
|
|
37
|
+
app.command(create_threads_app(), name="threads")
|
|
27
38
|
|
|
28
39
|
console = Console()
|
|
29
40
|
config_manager = DatabaseConfigManager()
|
|
@@ -195,47 +206,6 @@ def query(
|
|
|
195
206
|
sys.exit(e.exit_code)
|
|
196
207
|
|
|
197
208
|
|
|
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
|
|
227
|
-
|
|
228
|
-
return create_models_app()(*args, **kwargs)
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
@app.command(name="threads")
|
|
232
|
-
def threads(*args, **kwargs):
|
|
233
|
-
"""Manage SQLsaber threads."""
|
|
234
|
-
from sqlsaber.cli.threads import create_threads_app
|
|
235
|
-
|
|
236
|
-
return create_threads_app()(*args, **kwargs)
|
|
237
|
-
|
|
238
|
-
|
|
239
209
|
def main():
|
|
240
210
|
"""Entry point for the CLI application."""
|
|
241
211
|
app()
|
|
@@ -12,7 +12,6 @@ from rich.console import Console
|
|
|
12
12
|
from rich.table import Table
|
|
13
13
|
|
|
14
14
|
from sqlsaber.config.database import DatabaseConfig, DatabaseConfigManager
|
|
15
|
-
from sqlsaber.database.connection import DatabaseConnection
|
|
16
15
|
|
|
17
16
|
# Global instances for CLI commands
|
|
18
17
|
console = Console()
|
|
@@ -343,6 +342,9 @@ def test(
|
|
|
343
342
|
"""Test a database connection."""
|
|
344
343
|
|
|
345
344
|
async def test_connection():
|
|
345
|
+
# Lazy import to keep CLI startup fast
|
|
346
|
+
from sqlsaber.database.connection import DatabaseConnection
|
|
347
|
+
|
|
346
348
|
if name:
|
|
347
349
|
db_config = config_manager.get_database(name)
|
|
348
350
|
if not db_config:
|
|
@@ -6,6 +6,7 @@ from pathlib import Path
|
|
|
6
6
|
import platformdirs
|
|
7
7
|
from prompt_toolkit import PromptSession
|
|
8
8
|
from prompt_toolkit.history import FileHistory
|
|
9
|
+
from prompt_toolkit.patch_stdout import patch_stdout
|
|
9
10
|
from prompt_toolkit.styles import Style
|
|
10
11
|
from pydantic_ai import Agent
|
|
11
12
|
from rich.console import Console
|
|
@@ -118,6 +119,15 @@ class InteractiveSession:
|
|
|
118
119
|
if self._thread_id:
|
|
119
120
|
self.console.print(f"[dim]Resuming thread:[/dim] {self._thread_id}\n")
|
|
120
121
|
|
|
122
|
+
async def _end_thread_and_display_resume_hint(self):
|
|
123
|
+
"""End thread and display command to resume thread"""
|
|
124
|
+
# Print resume hint if there is an active thread
|
|
125
|
+
if self._thread_id:
|
|
126
|
+
await self._threads.end_thread(self._thread_id)
|
|
127
|
+
self.console.print(
|
|
128
|
+
f"[dim]You can continue this thread using:[/dim] saber threads resume {self._thread_id}"
|
|
129
|
+
)
|
|
130
|
+
|
|
121
131
|
async def _update_table_cache(self):
|
|
122
132
|
"""Update the table completer cache with fresh data."""
|
|
123
133
|
try:
|
|
@@ -215,33 +225,27 @@ class InteractiveSession:
|
|
|
215
225
|
|
|
216
226
|
while True:
|
|
217
227
|
try:
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
)
|
|
228
|
+
with patch_stdout():
|
|
229
|
+
user_query = await session.prompt_async(
|
|
230
|
+
"",
|
|
231
|
+
multiline=True,
|
|
232
|
+
completer=CompositeCompleter(
|
|
233
|
+
SlashCommandCompleter(), self.table_completer
|
|
234
|
+
),
|
|
235
|
+
show_frame=True,
|
|
236
|
+
bottom_toolbar=bottom_toolbar,
|
|
237
|
+
style=style,
|
|
238
|
+
)
|
|
230
239
|
|
|
231
240
|
if not user_query:
|
|
232
241
|
continue
|
|
233
242
|
|
|
234
243
|
if (
|
|
235
|
-
user_query in ["/exit", "/quit"]
|
|
244
|
+
user_query in ["/exit", "/quit", "exit", "quit"]
|
|
236
245
|
or user_query.startswith("/exit")
|
|
237
246
|
or user_query.startswith("/quit")
|
|
238
247
|
):
|
|
239
|
-
|
|
240
|
-
if self._thread_id:
|
|
241
|
-
await self._threads.end_thread(self._thread_id)
|
|
242
|
-
self.console.print(
|
|
243
|
-
f"[dim]You can continue this thread using:[/dim] saber threads resume {self._thread_id}"
|
|
244
|
-
)
|
|
248
|
+
await self._end_thread_and_display_resume_hint()
|
|
245
249
|
break
|
|
246
250
|
|
|
247
251
|
if user_query == "/clear":
|
|
@@ -313,6 +317,7 @@ class InteractiveSession:
|
|
|
313
317
|
)
|
|
314
318
|
except EOFError:
|
|
315
319
|
# Exit when Ctrl+D is pressed
|
|
320
|
+
await self._end_thread_and_display_resume_hint()
|
|
316
321
|
break
|
|
317
322
|
except Exception as e:
|
|
318
323
|
self.console.print(f"[bold red]Error:[/bold red] {str(e)}")
|
|
@@ -12,17 +12,10 @@ from rich.markdown import Markdown
|
|
|
12
12
|
from rich.panel import Panel
|
|
13
13
|
from rich.table import Table
|
|
14
14
|
|
|
15
|
-
from sqlsaber.agents import build_sqlsaber_agent
|
|
16
|
-
from sqlsaber.cli.display import DisplayManager
|
|
17
|
-
from sqlsaber.cli.interactive import InteractiveSession
|
|
18
|
-
from sqlsaber.config.database import DatabaseConfigManager
|
|
19
|
-
from sqlsaber.database.connection import DatabaseConnection
|
|
20
|
-
from sqlsaber.database.resolver import DatabaseResolutionError, resolve_database
|
|
21
15
|
from sqlsaber.threads import ThreadStorage
|
|
22
16
|
|
|
23
17
|
# Globals consistent with other CLI modules
|
|
24
18
|
console = Console()
|
|
25
|
-
config_manager = DatabaseConfigManager()
|
|
26
19
|
|
|
27
20
|
|
|
28
21
|
threads_app = cyclopts.App(
|
|
@@ -41,6 +34,9 @@ def _render_transcript(
|
|
|
41
34
|
console: Console, all_msgs: list[ModelMessage], last_n: int | None = None
|
|
42
35
|
) -> None:
|
|
43
36
|
"""Render conversation turns from ModelMessage[] using DisplayManager."""
|
|
37
|
+
# Lazy import to avoid pulling UI helpers at startup
|
|
38
|
+
from sqlsaber.cli.display import DisplayManager
|
|
39
|
+
|
|
44
40
|
dm = DisplayManager(console)
|
|
45
41
|
|
|
46
42
|
# Locate indices of user prompts
|
|
@@ -237,6 +233,16 @@ def resume(
|
|
|
237
233
|
store = ThreadStorage()
|
|
238
234
|
|
|
239
235
|
async def _run() -> None:
|
|
236
|
+
# Lazy imports to avoid heavy modules at CLI startup
|
|
237
|
+
from sqlsaber.agents import build_sqlsaber_agent
|
|
238
|
+
from sqlsaber.cli.interactive import InteractiveSession
|
|
239
|
+
from sqlsaber.config.database import DatabaseConfigManager
|
|
240
|
+
from sqlsaber.database.connection import DatabaseConnection
|
|
241
|
+
from sqlsaber.database.resolver import (
|
|
242
|
+
DatabaseResolutionError,
|
|
243
|
+
resolve_database,
|
|
244
|
+
)
|
|
245
|
+
|
|
240
246
|
thread = await store.get_thread(thread_id)
|
|
241
247
|
if not thread:
|
|
242
248
|
console.print(f"[red]Thread not found:[/red] {thread_id}")
|
|
@@ -248,6 +254,7 @@ def resume(
|
|
|
248
254
|
)
|
|
249
255
|
return
|
|
250
256
|
try:
|
|
257
|
+
config_manager = DatabaseConfigManager()
|
|
251
258
|
resolved = resolve_database(db_selector, config_manager)
|
|
252
259
|
connection_string = resolved.connection_string
|
|
253
260
|
db_name = resolved.name
|
|
@@ -17,9 +17,9 @@ from rich.console import Console
|
|
|
17
17
|
from sqlsaber.cli.threads import (
|
|
18
18
|
_human_readable,
|
|
19
19
|
_render_transcript,
|
|
20
|
-
config_manager,
|
|
21
20
|
create_threads_app,
|
|
22
21
|
)
|
|
22
|
+
from sqlsaber.config.database import DatabaseConfigManager
|
|
23
23
|
from sqlsaber.threads.storage import Thread, ThreadStorage
|
|
24
24
|
|
|
25
25
|
|
|
@@ -220,7 +220,7 @@ class TestThreadsCLI:
|
|
|
220
220
|
),
|
|
221
221
|
]
|
|
222
222
|
|
|
223
|
-
with patch("sqlsaber.cli.
|
|
223
|
+
with patch("sqlsaber.cli.display.DisplayManager") as mock_dm_class:
|
|
224
224
|
mock_dm = MagicMock()
|
|
225
225
|
mock_dm_class.return_value = mock_dm
|
|
226
226
|
|
|
@@ -253,7 +253,7 @@ class TestThreadsCLI:
|
|
|
253
253
|
),
|
|
254
254
|
]
|
|
255
255
|
|
|
256
|
-
with patch("sqlsaber.cli.
|
|
256
|
+
with patch("sqlsaber.cli.display.DisplayManager") as mock_dm_class:
|
|
257
257
|
mock_dm = MagicMock()
|
|
258
258
|
mock_dm_class.return_value = mock_dm
|
|
259
259
|
|
|
@@ -307,10 +307,14 @@ class TestThreadsCLI:
|
|
|
307
307
|
|
|
308
308
|
with (
|
|
309
309
|
patch("sqlsaber.cli.threads.ThreadStorage", return_value=store),
|
|
310
|
-
patch("sqlsaber.
|
|
311
|
-
patch("sqlsaber.
|
|
312
|
-
patch(
|
|
313
|
-
|
|
310
|
+
patch("sqlsaber.database.resolver") as mock_resolve,
|
|
311
|
+
patch("sqlsaber.database.DatabaseConnection") as mock_db_conn_class,
|
|
312
|
+
patch(
|
|
313
|
+
"sqlsaber.agents.pydantic_ai_agent.build_sqlsaber_agent"
|
|
314
|
+
) as mock_build_agent,
|
|
315
|
+
patch(
|
|
316
|
+
"sqlsaber.cli.interactive.InteractiveSession"
|
|
317
|
+
) as mock_session_class,
|
|
314
318
|
):
|
|
315
319
|
# Mock database resolution
|
|
316
320
|
mock_resolved = MagicMock()
|
|
@@ -333,7 +337,7 @@ class TestThreadsCLI:
|
|
|
333
337
|
assert resolved_thread == thread
|
|
334
338
|
|
|
335
339
|
db_selector = resolved_thread.database_name
|
|
336
|
-
resolved = mock_resolve(db_selector,
|
|
340
|
+
resolved = mock_resolve(db_selector, DatabaseConfigManager())
|
|
337
341
|
assert resolved.name == "prod_db"
|
|
338
342
|
|
|
339
343
|
await mock_resume_run()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|