sqlsaber 0.15.0__py3-none-any.whl → 0.16.1__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/agents/__init__.py +2 -4
- sqlsaber/agents/base.py +1 -2
- sqlsaber/agents/mcp.py +2 -2
- sqlsaber/agents/pydantic_ai_agent.py +170 -0
- sqlsaber/cli/auth.py +146 -79
- sqlsaber/cli/commands.py +23 -8
- sqlsaber/cli/database.py +1 -1
- sqlsaber/cli/interactive.py +65 -30
- sqlsaber/cli/models.py +58 -29
- sqlsaber/cli/streaming.py +114 -77
- sqlsaber/config/api_keys.py +9 -11
- sqlsaber/config/providers.py +116 -0
- sqlsaber/config/settings.py +50 -30
- sqlsaber/database/connection.py +3 -3
- sqlsaber/models/__init__.py +0 -3
- sqlsaber/tools/base.py +7 -5
- {sqlsaber-0.15.0.dist-info → sqlsaber-0.16.1.dist-info}/METADATA +20 -39
- {sqlsaber-0.15.0.dist-info → sqlsaber-0.16.1.dist-info}/RECORD +21 -28
- sqlsaber/agents/anthropic.py +0 -491
- sqlsaber/agents/streaming.py +0 -16
- sqlsaber/clients/__init__.py +0 -6
- sqlsaber/clients/anthropic.py +0 -285
- sqlsaber/clients/base.py +0 -31
- sqlsaber/clients/exceptions.py +0 -117
- sqlsaber/clients/models.py +0 -282
- sqlsaber/clients/streaming.py +0 -257
- sqlsaber/models/events.py +0 -28
- {sqlsaber-0.15.0.dist-info → sqlsaber-0.16.1.dist-info}/WHEEL +0 -0
- {sqlsaber-0.15.0.dist-info → sqlsaber-0.16.1.dist-info}/entry_points.txt +0 -0
- {sqlsaber-0.15.0.dist-info → sqlsaber-0.16.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Central registry for supported AI providers.
|
|
2
|
+
|
|
3
|
+
This module defines a single source of truth for providers used across the
|
|
4
|
+
codebase (CLI, config, agents). Update this file to add or modify providers.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from typing import Dict, Iterable, List, Optional
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class ProviderSpec:
|
|
15
|
+
"""Specification for a provider."""
|
|
16
|
+
|
|
17
|
+
key: str
|
|
18
|
+
env_var: str
|
|
19
|
+
supports_oauth: bool = False
|
|
20
|
+
aliases: tuple[str, ...] = ()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Ordered definition -> used for CLI display order
|
|
24
|
+
_PROVIDERS: List[ProviderSpec] = [
|
|
25
|
+
ProviderSpec(
|
|
26
|
+
key="anthropic",
|
|
27
|
+
env_var="ANTHROPIC_API_KEY",
|
|
28
|
+
supports_oauth=True,
|
|
29
|
+
aliases=(),
|
|
30
|
+
),
|
|
31
|
+
ProviderSpec(
|
|
32
|
+
key="openai",
|
|
33
|
+
env_var="OPENAI_API_KEY",
|
|
34
|
+
aliases=(),
|
|
35
|
+
),
|
|
36
|
+
ProviderSpec(
|
|
37
|
+
key="google",
|
|
38
|
+
env_var="GOOGLE_API_KEY",
|
|
39
|
+
# Historically some model IDs start with "google-gla"; treat as alias
|
|
40
|
+
aliases=("google-gla",),
|
|
41
|
+
),
|
|
42
|
+
ProviderSpec(
|
|
43
|
+
key="groq",
|
|
44
|
+
env_var="GROQ_API_KEY",
|
|
45
|
+
aliases=(),
|
|
46
|
+
),
|
|
47
|
+
ProviderSpec(
|
|
48
|
+
key="mistral",
|
|
49
|
+
env_var="MISTRAL_API_KEY",
|
|
50
|
+
aliases=(),
|
|
51
|
+
),
|
|
52
|
+
ProviderSpec(
|
|
53
|
+
key="cohere",
|
|
54
|
+
env_var="COHERE_API_KEY",
|
|
55
|
+
aliases=(),
|
|
56
|
+
),
|
|
57
|
+
ProviderSpec(
|
|
58
|
+
key="huggingface",
|
|
59
|
+
env_var="HUGGINGFACE_API_KEY",
|
|
60
|
+
aliases=(),
|
|
61
|
+
),
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# Fast lookup maps
|
|
66
|
+
_BY_KEY: Dict[str, ProviderSpec] = {p.key: p for p in _PROVIDERS}
|
|
67
|
+
_ALIAS_TO_KEY: Dict[str, str] = {
|
|
68
|
+
alias: p.key for p in _PROVIDERS for alias in p.aliases
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def all_keys() -> List[str]:
|
|
73
|
+
"""Return provider keys in display order."""
|
|
74
|
+
return [p.key for p in _PROVIDERS]
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def env_var_name(key: str) -> str:
|
|
78
|
+
"""Return the expected environment variable for a provider.
|
|
79
|
+
|
|
80
|
+
Falls back to a generic name if the provider is unknown.
|
|
81
|
+
"""
|
|
82
|
+
spec = _BY_KEY.get(key)
|
|
83
|
+
return spec.env_var if spec else "AI_API_KEY"
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def supports_oauth(key: str) -> bool:
|
|
87
|
+
"""Return True if the provider supports OAuth in SQLsaber."""
|
|
88
|
+
spec = _BY_KEY.get(key)
|
|
89
|
+
return bool(spec and spec.supports_oauth)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def canonical(key_or_alias: str) -> Optional[str]:
|
|
93
|
+
"""Return the canonical provider key for a provider or alias.
|
|
94
|
+
|
|
95
|
+
Returns None if not recognized.
|
|
96
|
+
"""
|
|
97
|
+
if key_or_alias in _BY_KEY:
|
|
98
|
+
return key_or_alias
|
|
99
|
+
return _ALIAS_TO_KEY.get(key_or_alias)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def provider_from_model(model_name: str) -> Optional[str]:
|
|
103
|
+
"""Infer the canonical provider key from a model identifier.
|
|
104
|
+
|
|
105
|
+
Accepts either "provider:model_id" or a bare provider string. Aliases are
|
|
106
|
+
normalized to their canonical provider key.
|
|
107
|
+
"""
|
|
108
|
+
if not model_name:
|
|
109
|
+
return None
|
|
110
|
+
provider_raw = model_name.split(":", 1)[0]
|
|
111
|
+
return canonical(provider_raw)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def specs() -> Iterable[ProviderSpec]:
|
|
115
|
+
"""Iterate provider specifications (in display order)."""
|
|
116
|
+
return tuple(_PROVIDERS)
|
sqlsaber/config/settings.py
CHANGED
|
@@ -9,6 +9,7 @@ from typing import Any
|
|
|
9
9
|
|
|
10
10
|
import platformdirs
|
|
11
11
|
|
|
12
|
+
from sqlsaber.config import providers
|
|
12
13
|
from sqlsaber.config.api_keys import APIKeyManager
|
|
13
14
|
from sqlsaber.config.auth import AuthConfigManager, AuthMethod
|
|
14
15
|
from sqlsaber.config.oauth_flow import AnthropicOAuthFlow
|
|
@@ -84,47 +85,66 @@ class Config:
|
|
|
84
85
|
self.model_name = self.model_config_manager.get_model()
|
|
85
86
|
self.api_key_manager = APIKeyManager()
|
|
86
87
|
self.auth_config_manager = AuthConfigManager()
|
|
87
|
-
self.oauth_flow = AnthropicOAuthFlow()
|
|
88
88
|
|
|
89
|
-
#
|
|
89
|
+
# Authentication method (API key or Anthropic OAuth)
|
|
90
90
|
self.auth_method = self.auth_config_manager.get_auth_method()
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
token = self.oauth_flow.refresh_token_if_needed()
|
|
98
|
-
if token:
|
|
99
|
-
self.oauth_token = token.access_token
|
|
100
|
-
except Exception:
|
|
101
|
-
# OAuth token unavailable, will need to re-authenticate
|
|
102
|
-
pass
|
|
91
|
+
|
|
92
|
+
# Optional Anthropic OAuth access token (only relevant for provider=='anthropic')
|
|
93
|
+
if self.auth_method == AuthMethod.CLAUDE_PRO and self.model_name.startswith(
|
|
94
|
+
"anthropic"
|
|
95
|
+
):
|
|
96
|
+
self.oauth_token = self.get_oauth_access_token()
|
|
103
97
|
else:
|
|
104
|
-
# Use API key authentication (default or explicitly configured)
|
|
105
98
|
self.api_key = self._get_api_key()
|
|
99
|
+
# self.oauth_token = None
|
|
106
100
|
|
|
107
101
|
def _get_api_key(self) -> str | None:
|
|
108
102
|
"""Get API key for the model provider using cascading logic."""
|
|
109
|
-
model = self.model_name
|
|
110
|
-
|
|
111
|
-
|
|
103
|
+
model = self.model_name or ""
|
|
104
|
+
prov = providers.provider_from_model(model)
|
|
105
|
+
if prov in set(providers.all_keys()):
|
|
106
|
+
return self.api_key_manager.get_api_key(prov) # type: ignore[arg-type]
|
|
107
|
+
return None
|
|
112
108
|
|
|
113
109
|
def set_model(self, model: str) -> None:
|
|
114
110
|
"""Set the model and update configuration."""
|
|
115
111
|
self.model_config_manager.set_model(model)
|
|
116
112
|
self.model_name = model
|
|
117
113
|
|
|
114
|
+
def get_oauth_access_token(self) -> str | None:
|
|
115
|
+
"""Return a valid Anthropic OAuth access token if configured, else None.
|
|
116
|
+
|
|
117
|
+
Uses the stored refresh token (if present) to refresh as needed.
|
|
118
|
+
Only relevant when provider is 'anthropic'.
|
|
119
|
+
"""
|
|
120
|
+
if not self.model_name.startswith("anthropic"):
|
|
121
|
+
return None
|
|
122
|
+
try:
|
|
123
|
+
flow = AnthropicOAuthFlow()
|
|
124
|
+
token = flow.refresh_token_if_needed()
|
|
125
|
+
return token.access_token if token else None
|
|
126
|
+
except Exception:
|
|
127
|
+
return None
|
|
128
|
+
|
|
118
129
|
def validate(self):
|
|
119
|
-
"""Validate that necessary configuration is present.
|
|
120
|
-
|
|
121
|
-
if
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
130
|
+
"""Validate that necessary configuration is present.
|
|
131
|
+
|
|
132
|
+
Also ensure provider env var is set from keyring if needed for API-key flows.
|
|
133
|
+
"""
|
|
134
|
+
model = self.model_name or ""
|
|
135
|
+
provider_key = providers.provider_from_model(model)
|
|
136
|
+
env_var = providers.env_var_name(provider_key or "") if provider_key else None
|
|
137
|
+
if env_var:
|
|
138
|
+
# Anthropic special-case: allow OAuth in lieu of API key only when explicitly configured
|
|
139
|
+
if (
|
|
140
|
+
provider_key == "anthropic"
|
|
141
|
+
and self.auth_method == AuthMethod.CLAUDE_PRO
|
|
142
|
+
and self.oauth_token
|
|
143
|
+
):
|
|
144
|
+
return
|
|
145
|
+
# If we don't have a key resolved from env/keyring, raise
|
|
146
|
+
if not self.api_key:
|
|
147
|
+
raise ValueError(f"{provider_key.capitalize()} API key not found.")
|
|
148
|
+
# Hydrate env var for downstream SDKs if missing
|
|
149
|
+
if not os.getenv(env_var):
|
|
150
|
+
os.environ[env_var] = self.api_key
|
sqlsaber/database/connection.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""Database connection management."""
|
|
2
2
|
|
|
3
|
-
from abc import ABC, abstractmethod
|
|
4
|
-
from typing import Any
|
|
5
|
-
from urllib.parse import urlparse, parse_qs
|
|
6
3
|
import ssl
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
7
5
|
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
from urllib.parse import parse_qs, urlparse
|
|
8
8
|
|
|
9
9
|
import aiomysql
|
|
10
10
|
import aiosqlite
|
sqlsaber/models/__init__.py
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
"""Models module for SQLSaber."""
|
|
2
2
|
|
|
3
|
-
from .events import StreamEvent, SQLResponse
|
|
4
3
|
from .types import ColumnInfo, ForeignKeyInfo, SchemaInfo, ToolDefinition
|
|
5
4
|
|
|
6
5
|
__all__ = [
|
|
7
|
-
"StreamEvent",
|
|
8
|
-
"SQLResponse",
|
|
9
6
|
"ColumnInfo",
|
|
10
7
|
"ForeignKeyInfo",
|
|
11
8
|
"SchemaInfo",
|
sqlsaber/tools/base.py
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
"""Base class for SQLSaber tools."""
|
|
2
2
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
|
+
from types import SimpleNamespace
|
|
4
5
|
from typing import Any
|
|
5
6
|
|
|
6
|
-
from sqlsaber.clients.models import ToolDefinition
|
|
7
|
-
|
|
8
7
|
from .enums import ToolCategory, WorkflowPosition
|
|
9
8
|
|
|
10
9
|
|
|
@@ -45,9 +44,12 @@ class Tool(ABC):
|
|
|
45
44
|
"""
|
|
46
45
|
pass
|
|
47
46
|
|
|
48
|
-
def to_definition(self)
|
|
49
|
-
"""Convert this tool to a ToolDefinition.
|
|
50
|
-
|
|
47
|
+
def to_definition(self):
|
|
48
|
+
"""Convert this tool to a ToolDefinition-like object with attributes.
|
|
49
|
+
|
|
50
|
+
Tests expect attribute access (definition.name), so return a SimpleNamespace.
|
|
51
|
+
"""
|
|
52
|
+
return SimpleNamespace(
|
|
51
53
|
name=self.name,
|
|
52
54
|
description=self.description,
|
|
53
55
|
input_schema=self.input_schema,
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlsaber
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.16.1
|
|
4
|
+
Summary: SQLsaber - Open-source agentic SQL assistant
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Requires-Python: >=3.12
|
|
7
7
|
Requires-Dist: aiomysql>=0.2.0
|
|
8
8
|
Requires-Dist: aiosqlite>=0.21.0
|
|
9
|
-
Requires-Dist: anthropic>=0.54.0
|
|
10
9
|
Requires-Dist: asyncpg>=0.30.0
|
|
11
10
|
Requires-Dist: cyclopts>=3.22.1
|
|
12
11
|
Requires-Dist: fastmcp>=2.9.0
|
|
@@ -14,27 +13,21 @@ Requires-Dist: httpx>=0.28.1
|
|
|
14
13
|
Requires-Dist: keyring>=25.6.0
|
|
15
14
|
Requires-Dist: pandas>=2.0.0
|
|
16
15
|
Requires-Dist: platformdirs>=4.0.0
|
|
16
|
+
Requires-Dist: pydantic-ai
|
|
17
17
|
Requires-Dist: questionary>=2.1.0
|
|
18
18
|
Requires-Dist: rich>=13.7.0
|
|
19
19
|
Requires-Dist: uniplot>=0.21.2
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
|
|
22
|
-
#
|
|
22
|
+
# SQLsaber
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
███████ ██████ ██ ███████ █████ ██████ ███████ ██████
|
|
26
|
-
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
27
|
-
███████ ██ ██ ██ ███████ ███████ ██████ █████ ██████
|
|
28
|
-
██ ██ ▄▄ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
29
|
-
███████ ██████ ███████ ███████ ██ ██ ██████ ███████ ██ ██
|
|
30
|
-
▀▀
|
|
31
|
-
```
|
|
24
|
+
> SQLsaber is an open-source agentic SQL assistant. Think Claude Code but for SQL.
|
|
32
25
|
|
|
33
|
-
|
|
26
|
+

|
|
34
27
|
|
|
35
|
-
|
|
28
|
+
Stop fighting your database.
|
|
36
29
|
|
|
37
|
-
Ask your questions in natural language and
|
|
30
|
+
Ask your questions in natural language and `sqlsaber` will gather the right context automatically and answer your query by writing SQL and analyzing the results.
|
|
38
31
|
|
|
39
32
|
## Table of Contents
|
|
40
33
|
|
|
@@ -59,14 +52,13 @@ Ask your questions in natural language and it will gather the right context auto
|
|
|
59
52
|
|
|
60
53
|
## Features
|
|
61
54
|
|
|
62
|
-
- Natural language to SQL conversion
|
|
63
55
|
- 🔍 Automatic database schema introspection
|
|
64
56
|
- 🛡️ Safe query execution (read-only by default)
|
|
65
57
|
- 🧠 Memory management
|
|
66
58
|
- 💬 Interactive REPL mode
|
|
67
|
-
- 🎨 Beautiful formatted output with syntax highlighting
|
|
68
59
|
- 🗄️ Support for PostgreSQL, SQLite, and MySQL
|
|
69
60
|
- 🔌 MCP (Model Context Protocol) server support
|
|
61
|
+
- 🎨 Beautiful formatted output
|
|
70
62
|
|
|
71
63
|
## Installation
|
|
72
64
|
|
|
@@ -165,34 +157,21 @@ saber -d mydb
|
|
|
165
157
|
|
|
166
158
|
# Single query with specific database
|
|
167
159
|
saber -d mydb "count all orders"
|
|
160
|
+
|
|
161
|
+
# You can also pass a connection string
|
|
162
|
+
saber -d "postgresql://user:password@localhost:5432/mydb" "count all orders"
|
|
168
163
|
```
|
|
169
164
|
|
|
170
165
|
## Examples
|
|
171
166
|
|
|
172
167
|
```bash
|
|
173
|
-
#
|
|
174
|
-
saber
|
|
175
|
-
|
|
176
|
-
# Count records
|
|
177
|
-
saber "how many active users do we have?"
|
|
168
|
+
# Start interactive mode
|
|
169
|
+
saber
|
|
178
170
|
|
|
179
|
-
#
|
|
171
|
+
# Non-interactive mode
|
|
180
172
|
saber "show me orders with customer details for this week"
|
|
181
173
|
|
|
182
|
-
# Aggregations
|
|
183
|
-
saber "what's the total revenue by product category?"
|
|
184
|
-
|
|
185
|
-
# Date filtering
|
|
186
|
-
saber "list users who haven't logged in for 30 days"
|
|
187
|
-
|
|
188
|
-
# Data exploration
|
|
189
|
-
saber "show me the distribution of customer ages"
|
|
190
|
-
|
|
191
|
-
# Business analytics
|
|
192
174
|
saber "which products had the highest sales growth last quarter?"
|
|
193
|
-
|
|
194
|
-
# Start interactive mode
|
|
195
|
-
saber
|
|
196
175
|
```
|
|
197
176
|
|
|
198
177
|
## MCP Server Integration
|
|
@@ -214,7 +193,7 @@ uvx --from sqlsaber saber-mcp
|
|
|
214
193
|
Add SQLSaber as an MCP server in Claude Code:
|
|
215
194
|
|
|
216
195
|
```bash
|
|
217
|
-
claude mcp add -- uvx --from sqlsaber saber-mcp
|
|
196
|
+
claude mcp add sqlsaber -- uvx --from sqlsaber saber-mcp
|
|
218
197
|
```
|
|
219
198
|
|
|
220
199
|
#### Other MCP Clients
|
|
@@ -234,7 +213,7 @@ The MCP server uses your existing SQLSaber database configurations, so make sure
|
|
|
234
213
|
|
|
235
214
|
## How It Works
|
|
236
215
|
|
|
237
|
-
|
|
216
|
+
SQLsaber uses a multi-step agentic process to gather the right context and execute SQL queries to answer your questions:
|
|
238
217
|
|
|
239
218
|

|
|
240
219
|
|
|
@@ -255,7 +234,9 @@ SQLSaber uses a multi-step process to gather the right context, provide it to th
|
|
|
255
234
|
|
|
256
235
|
## Contributing
|
|
257
236
|
|
|
258
|
-
|
|
237
|
+
If you like the project, starring the repo is a great way to show your support!
|
|
238
|
+
|
|
239
|
+
Other contributions are welcome! Please feel free to open an issue to discuss your ideas or report bugs.
|
|
259
240
|
|
|
260
241
|
## License
|
|
261
242
|
|
|
@@ -1,39 +1,33 @@
|
|
|
1
1
|
sqlsaber/__init__.py,sha256=HjS8ULtP4MGpnTL7njVY45NKV9Fi4e_yeYuY-hyXWQc,73
|
|
2
2
|
sqlsaber/__main__.py,sha256=RIHxWeWh2QvLfah-2OkhI5IJxojWfy4fXpMnVEJYvxw,78
|
|
3
|
-
sqlsaber/agents/__init__.py,sha256=
|
|
4
|
-
sqlsaber/agents/
|
|
5
|
-
sqlsaber/agents/
|
|
6
|
-
sqlsaber/agents/
|
|
7
|
-
sqlsaber/agents/streaming.py,sha256=LaSeMTlxuJFRArJVqDly5-_KgcePiCCKPKfMxfB4oGs,521
|
|
3
|
+
sqlsaber/agents/__init__.py,sha256=i_MI2eWMQaVzGikKU71FPCmSQxNDKq36Imq1PrYoIPU,130
|
|
4
|
+
sqlsaber/agents/base.py,sha256=2JX7UKW7tbqxPaK4aQLpXIwT3uszdBQHdSsOyML2U7I,6353
|
|
5
|
+
sqlsaber/agents/mcp.py,sha256=GcJTx7YDYH6aaxIADEIxSgcWAdWakUx395JIzVnf17U,768
|
|
6
|
+
sqlsaber/agents/pydantic_ai_agent.py,sha256=dGdsgyxCZvfK-v-MH8KimKOr-xb2aSfSWY8CMcOUCT8,6795
|
|
8
7
|
sqlsaber/cli/__init__.py,sha256=qVSLVJLLJYzoC6aj6y9MFrzZvAwc4_OgxU9DlkQnZ4M,86
|
|
9
|
-
sqlsaber/cli/auth.py,sha256=
|
|
10
|
-
sqlsaber/cli/commands.py,sha256=
|
|
8
|
+
sqlsaber/cli/auth.py,sha256=jTsRgbmlGPlASSuIKmdjjwfqtKvjfKd_cTYxX0-QqaQ,7400
|
|
9
|
+
sqlsaber/cli/commands.py,sha256=EhQ5KziG2-nh7rNJ7xko8Ks-FfXZ7V21rILKNGjPe08,6715
|
|
11
10
|
sqlsaber/cli/completers.py,sha256=HsUPjaZweLSeYCWkAcgMl8FylQ1xjWBWYTEL_9F6xfU,6430
|
|
12
|
-
sqlsaber/cli/database.py,sha256=
|
|
11
|
+
sqlsaber/cli/database.py,sha256=atwg3l8acQ3YTDuhq7vNrBN6tpOv0syz6V62KTF-Bh8,12910
|
|
13
12
|
sqlsaber/cli/display.py,sha256=HtXwPe3VPUh2EJpyvpJVWyisCanu9O7w-rkqq7Y4UaY,9791
|
|
14
|
-
sqlsaber/cli/interactive.py,sha256=
|
|
13
|
+
sqlsaber/cli/interactive.py,sha256=SNOV_MaqJt2NQr6H8GbbWzMyuGx2NLFEXetjKtFAefw,9635
|
|
15
14
|
sqlsaber/cli/memory.py,sha256=OufHFJFwV0_GGn7LvKRTJikkWhV1IwNIUDOxFPHXOaQ,7794
|
|
16
|
-
sqlsaber/cli/models.py,sha256=
|
|
17
|
-
sqlsaber/cli/streaming.py,sha256=
|
|
18
|
-
sqlsaber/clients/__init__.py,sha256=jcMoVsT92U6nQrfotCp1h0ggskJPAcgeYarqQl1qEBg,171
|
|
19
|
-
sqlsaber/clients/anthropic.py,sha256=umRmuzpmJdYO7hO3biAZXO9T_sb6Vv010o6zqn03is8,9947
|
|
20
|
-
sqlsaber/clients/base.py,sha256=RLFJ3NV75Z6keiu9mnh9zrMZK1HwdeUby0e3oeJMtyw,935
|
|
21
|
-
sqlsaber/clients/exceptions.py,sha256=6OoCSxvuA13I3dML2Zngygl9MdaObISh1UHvBB3yUq0,3408
|
|
22
|
-
sqlsaber/clients/models.py,sha256=fOvnkW8NQSdn8Oqfk3-5dP4TylLh7C9wOvuNQYw184A,7016
|
|
23
|
-
sqlsaber/clients/streaming.py,sha256=CwdoocLAyW_GjZm2XcLb33Sa99w5fyb7dU-27FFpePQ,8319
|
|
15
|
+
sqlsaber/cli/models.py,sha256=ZewtwGQwhd9b-yxBAPKePolvI1qQG-EkmeWAGMqtWNQ,8986
|
|
16
|
+
sqlsaber/cli/streaming.py,sha256=3KXDu8_IJDkt-q6HoO7LYtLXjliNwWy_pOrgV8BQ6Bg,5453
|
|
24
17
|
sqlsaber/config/__init__.py,sha256=olwC45k8Nc61yK0WmPUk7XHdbsZH9HuUAbwnmKe3IgA,100
|
|
25
|
-
sqlsaber/config/api_keys.py,sha256=
|
|
18
|
+
sqlsaber/config/api_keys.py,sha256=RqWQCko1tY7sES7YOlexgBH5Hd5ne_kGXHdBDNqcV2U,3649
|
|
26
19
|
sqlsaber/config/auth.py,sha256=b5qB2h1doXyO9Bn8z0CcL8LAR2jF431gGXBGKLgTmtQ,2756
|
|
27
20
|
sqlsaber/config/database.py,sha256=c6q3l4EvoBch1ckYHA70hf6L7fSOY-sItnLCpvJiPrA,11357
|
|
28
21
|
sqlsaber/config/oauth_flow.py,sha256=A3bSXaBLzuAfXV2ZPA94m9NV33c2MyL6M4ii9oEkswQ,10291
|
|
29
22
|
sqlsaber/config/oauth_tokens.py,sha256=C9z35hyx-PvSAYdC1LNf3rg9_wsEIY56hkEczelbad0,6015
|
|
30
|
-
sqlsaber/config/
|
|
23
|
+
sqlsaber/config/providers.py,sha256=JFjeJv1K5Q93zWSlWq3hAvgch1TlgoF0qFa0KJROkKY,2957
|
|
24
|
+
sqlsaber/config/settings.py,sha256=vgb_RXaM-7DgbxYDmWNw1cSyMqwys4j3qNCvM4bljwI,5586
|
|
31
25
|
sqlsaber/conversation/__init__.py,sha256=xa-1gX6NsZpVGg_LDrsZAtDtsDo5FZc1SO8gwtm_IPk,302
|
|
32
26
|
sqlsaber/conversation/manager.py,sha256=LDfmKGIMvTzsL7S0aXGWw6Ve54CHIeTGLU4qwes2NgU,7046
|
|
33
27
|
sqlsaber/conversation/models.py,sha256=fq4wpIB2yxLCQtsXhdpDji4FpscG2ayrOBACrNvgF14,3510
|
|
34
28
|
sqlsaber/conversation/storage.py,sha256=phpGEnZjXVFTmV5PalCKZpiO9VFHubMMfWA9OJCDbwc,11626
|
|
35
29
|
sqlsaber/database/__init__.py,sha256=a_gtKRJnZVO8-fEZI7g3Z8YnGa6Nio-5Y50PgVp07ss,176
|
|
36
|
-
sqlsaber/database/connection.py,sha256=
|
|
30
|
+
sqlsaber/database/connection.py,sha256=sJtIIe0GVbo-1Py9-j66UxJoY1aKL9gqk68jkDL-Kvk,15123
|
|
37
31
|
sqlsaber/database/resolver.py,sha256=RPXF5EoKzvQDDLmPGNHYd2uG_oNICH8qvUjBp6iXmNY,3348
|
|
38
32
|
sqlsaber/database/schema.py,sha256=OC93dnZkijCoVNqb6itSpQ2XsiZ85PjVUW-VZDwrPrk,25989
|
|
39
33
|
sqlsaber/mcp/__init__.py,sha256=COdWq7wauPBp5Ew8tfZItFzbcLDSEkHBJSMhxzy8C9c,112
|
|
@@ -41,18 +35,17 @@ sqlsaber/mcp/mcp.py,sha256=X12oCMZYAtgJ7MNuh5cqz8y3lALrOzkXWcfpuY0Ijxk,3950
|
|
|
41
35
|
sqlsaber/memory/__init__.py,sha256=GiWkU6f6YYVV0EvvXDmFWe_CxarmDCql05t70MkTEWs,63
|
|
42
36
|
sqlsaber/memory/manager.py,sha256=p3fybMVfH-E4ApT1ZRZUnQIWSk9dkfUPCyfkmA0HALs,2739
|
|
43
37
|
sqlsaber/memory/storage.py,sha256=ne8szLlGj5NELheqLnI7zu21V8YS4rtpYGGC7tOmi-s,5745
|
|
44
|
-
sqlsaber/models/__init__.py,sha256=
|
|
45
|
-
sqlsaber/models/events.py,sha256=89SXKb5GGpH01yTr2kPEBhzp9xv35RFIYuFdAZSIPoE,721
|
|
38
|
+
sqlsaber/models/__init__.py,sha256=b3KVyLN7Y7p2rT1-TlIExpkO26bTG04-VCFwDmBO6i0,204
|
|
46
39
|
sqlsaber/models/types.py,sha256=w-zk81V2dtveuteej36_o1fDK3So428j3P2rAejU62U,862
|
|
47
40
|
sqlsaber/tools/__init__.py,sha256=a-JNOhHsC7WEVhTsQY_IHckaPOmswoM3Q85YOd2iC_E,652
|
|
48
|
-
sqlsaber/tools/base.py,sha256=
|
|
41
|
+
sqlsaber/tools/base.py,sha256=XLaHrAzZc4OUiOsKBvEfZCtWKDBd5WqgNAnmRufnOp4,2174
|
|
49
42
|
sqlsaber/tools/enums.py,sha256=TnlvEOpkGtuzEzg_JBdSb_S38jg4INhtxw4qZ20kU_E,483
|
|
50
43
|
sqlsaber/tools/instructions.py,sha256=nnItVvJBtN-FLB3-PSR6Y23ix6AiOB5hNX3r4TtYFKw,9869
|
|
51
44
|
sqlsaber/tools/registry.py,sha256=decVRNf50JPNT4i-OHZIL2B8cmoOMDaE4y0Av6q6v0I,3619
|
|
52
45
|
sqlsaber/tools/sql_tools.py,sha256=hM6tKqW5MDhFUt6MesoqhTUqIpq_5baIIDoN1MjDCXY,9647
|
|
53
46
|
sqlsaber/tools/visualization_tools.py,sha256=059Pe3aOZvgpqT9487Ydv2PhY7T1pVmfALPTvfqPisI,4973
|
|
54
|
-
sqlsaber-0.
|
|
55
|
-
sqlsaber-0.
|
|
56
|
-
sqlsaber-0.
|
|
57
|
-
sqlsaber-0.
|
|
58
|
-
sqlsaber-0.
|
|
47
|
+
sqlsaber-0.16.1.dist-info/METADATA,sha256=bVuWNDra_PQgj-6WgntIIee-l0RaPNPzOo4-1z7e_k8,5966
|
|
48
|
+
sqlsaber-0.16.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
49
|
+
sqlsaber-0.16.1.dist-info/entry_points.txt,sha256=qEbOB7OffXPFgyJc7qEIJlMEX5RN9xdzLmWZa91zCQQ,162
|
|
50
|
+
sqlsaber-0.16.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
51
|
+
sqlsaber-0.16.1.dist-info/RECORD,,
|