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.

@@ -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)
@@ -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
- # Get authentication credentials based on configured method
89
+ # Authentication method (API key or Anthropic OAuth)
90
90
  self.auth_method = self.auth_config_manager.get_auth_method()
91
- self.api_key = None
92
- self.oauth_token = None
93
-
94
- if self.auth_method == AuthMethod.CLAUDE_PRO:
95
- # Try to get OAuth token and refresh if needed
96
- try:
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
- if model.startswith("anthropic:"):
111
- return self.api_key_manager.get_api_key("anthropic")
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
- # 1. Claude-Pro flow → require OAuth token only
121
- if self.auth_method == AuthMethod.CLAUDE_PRO:
122
- if not self.oauth_token:
123
- raise ValueError(
124
- "OAuth token not available. Run 'saber auth setup' to authenticate with Claude Pro."
125
- )
126
- return # OAuth path satisfied – nothing more to check
127
-
128
- # 2. Default / API-key flow → require API key
129
- if not self.api_key:
130
- raise ValueError("Anthropic API key not found.")
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
@@ -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
@@ -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) -> ToolDefinition:
49
- """Convert this tool to a ToolDefinition."""
50
- return ToolDefinition(
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.15.0
4
- Summary: SQLSaber - Agentic SQL assistant like Claude Code
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
- # SQLSaber
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
- > Use the agent Luke!
26
+ ![demo](./sqlsaber.gif)
34
27
 
35
- SQLSaber is an agentic SQL assistant. Think Claude Code but for SQL.
28
+ Stop fighting your database.
36
29
 
37
- Ask your questions in natural language and it will gather the right context automatically and answer your query by writing SQL and analyzing the results.
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
- # Show database schema
174
- saber "what tables are in my database?"
175
-
176
- # Count records
177
- saber "how many active users do we have?"
168
+ # Start interactive mode
169
+ saber
178
170
 
179
- # Complex queries with joins
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
- SQLSaber uses a multi-step process to gather the right context, provide it to the model, and execute SQL queries to get the right answers:
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
  ![](./sqlsaber.svg)
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
- Contributions are welcome! Please feel free to open an issue to discuss your ideas or report bugs.
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=LWeSeEUE4BhkyAYFF3TE-fx8TtLud3oyEtyB8ojFJgo,167
4
- sqlsaber/agents/anthropic.py,sha256=OSrf_2fancbGH04ckouxChNyKj1H54wt_fWGP0hECII,19564
5
- sqlsaber/agents/base.py,sha256=jOchhaEQWiW__koy2WF4e_YvvsF5l_WYru_q0PkBF7g,6413
6
- sqlsaber/agents/mcp.py,sha256=FKtXgDrPZ2-xqUYCw2baI5JzrWekXaC5fjkYW1_Mg50,827
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=1yvawtS5NGj9dWMRZ8I5T6sqBiRqZpPsjEPrJSQBJAs,4979
10
- sqlsaber/cli/commands.py,sha256=VX7pqQnf-85A9zkjXqzytVNeCG8KO0mB2TyIEzB4sh8,6241
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=tJ8rqGrafZpg3VgDmSiq7eZoPscoGAW3XLTYGoQw8LE,12910
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=7RjUMMPJ49RUuUGn-gP6vgiW6Ccvin9mzmRL-9p6eto,8171
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=HByezaeKqj65GzB_FmWuugjkgTq2Pvab_mzNZnHxya0,7690
17
- sqlsaber/cli/streaming.py,sha256=WfhFd5ntq2HStpJZwWJ0C5uyXKc3aU14eo8HdjzW1o0,3767
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=wnWlYy26AkkevZ1Vln6avYRBDLPRzfrHkj-fPojkxaQ,3624
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/settings.py,sha256=gKhGlErzsBk39RoRSy1b8pb-bN2K7HIaPaBgbJDhY4M,4753
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=sZVGNMzMwiM11GrsLLPwR8A5ugzJ5O0TCdkrt0KVRuI,15123
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=RJ7p3WtuSwwpFQ1Iw4_DHV2zzCtHqIzsjJzxv8kUjUE,287
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=0pCC2OMZc4uyxv-ErRHuXbu_9MeVXPzSyGIyix6Hvw4,2085
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.15.0.dist-info/METADATA,sha256=XEF-xwN39iDs9Gd_uSdeHxyE50i429ol5iU2HSnkdZc,6877
55
- sqlsaber-0.15.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
56
- sqlsaber-0.15.0.dist-info/entry_points.txt,sha256=qEbOB7OffXPFgyJc7qEIJlMEX5RN9xdzLmWZa91zCQQ,162
57
- sqlsaber-0.15.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
58
- sqlsaber-0.15.0.dist-info/RECORD,,
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,,