pretensor 0.1.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.
- pretensor/__init__.py +50 -0
- pretensor/benchmark/__init__.py +54 -0
- pretensor/benchmark/cli.py +294 -0
- pretensor/benchmark/fixtures.py +84 -0
- pretensor/benchmark/l1/__init__.py +23 -0
- pretensor/benchmark/l1/metrics.py +141 -0
- pretensor/benchmark/l1/pipeline.py +188 -0
- pretensor/benchmark/l1/runner.py +245 -0
- pretensor/benchmark/l2/__init__.py +27 -0
- pretensor/benchmark/l2/gold.py +236 -0
- pretensor/benchmark/l2/metrics.py +146 -0
- pretensor/benchmark/l2/pipeline.py +124 -0
- pretensor/benchmark/l2/runner.py +530 -0
- pretensor/benchmark/l3/__init__.py +73 -0
- pretensor/benchmark/l3/agent.py +316 -0
- pretensor/benchmark/l3/db.py +188 -0
- pretensor/benchmark/l3/gold.py +85 -0
- pretensor/benchmark/l3/llm_client.py +395 -0
- pretensor/benchmark/l3/mcp_client.py +357 -0
- pretensor/benchmark/l3/pretensor_runner.py +456 -0
- pretensor/benchmark/l3/prompt.py +132 -0
- pretensor/benchmark/l3/runner.py +358 -0
- pretensor/benchmark/l3/sql_equivalence.py +176 -0
- pretensor/benchmark/release_gate.py +448 -0
- pretensor/benchmark/results.py +298 -0
- pretensor/benchmark/runner.py +109 -0
- pretensor/cli/__init__.py +1 -0
- pretensor/cli/commands/_source_runner.py +147 -0
- pretensor/cli/commands/analyze.py +201 -0
- pretensor/cli/commands/connections/__init__.py +7 -0
- pretensor/cli/commands/connections/add_remove.py +126 -0
- pretensor/cli/commands/connections/register.py +12 -0
- pretensor/cli/commands/export.py +131 -0
- pretensor/cli/commands/index.py +559 -0
- pretensor/cli/commands/list.py +76 -0
- pretensor/cli/commands/quickstart.py +207 -0
- pretensor/cli/commands/reindex.py +646 -0
- pretensor/cli/commands/semantic.py +190 -0
- pretensor/cli/commands/serve.py +144 -0
- pretensor/cli/commands/sync_grants.py +149 -0
- pretensor/cli/commands/validate.py +176 -0
- pretensor/cli/config_file.py +442 -0
- pretensor/cli/constants.py +10 -0
- pretensor/cli/dbt_enrichment.py +96 -0
- pretensor/cli/main.py +109 -0
- pretensor/cli/paths.py +43 -0
- pretensor/cli/plugin.py +52 -0
- pretensor/config.py +226 -0
- pretensor/connectors/__init__.py +29 -0
- pretensor/connectors/base.py +165 -0
- pretensor/connectors/bigquery.py +468 -0
- pretensor/connectors/inspect.py +321 -0
- pretensor/connectors/lineage_sqlglot.py +97 -0
- pretensor/connectors/models.py +130 -0
- pretensor/connectors/mysql.py +402 -0
- pretensor/connectors/pg_array_parse.py +53 -0
- pretensor/connectors/postgres.py +938 -0
- pretensor/connectors/registry.py +93 -0
- pretensor/connectors/snapshot.py +244 -0
- pretensor/connectors/snowflake.py +908 -0
- pretensor/core/__init__.py +1 -0
- pretensor/core/builder.py +307 -0
- pretensor/core/dsn_crypto.py +51 -0
- pretensor/core/graph_schema_manager.py +246 -0
- pretensor/core/graph_store.py +1226 -0
- pretensor/core/ids.py +101 -0
- pretensor/core/portable_export.py +276 -0
- pretensor/core/query_runner.py +67 -0
- pretensor/core/registry.py +209 -0
- pretensor/core/schema.py +473 -0
- pretensor/core/secure_io.py +93 -0
- pretensor/core/store.py +469 -0
- pretensor/enrichment/__init__.py +1 -0
- pretensor/enrichment/analyze/__init__.py +0 -0
- pretensor/enrichment/analyze/classify.py +49 -0
- pretensor/enrichment/analyze/extract_python.py +196 -0
- pretensor/enrichment/analyze/parse.py +141 -0
- pretensor/enrichment/analyze/pipeline.py +195 -0
- pretensor/enrichment/analyze/summary.py +38 -0
- pretensor/enrichment/analyze/walker.py +98 -0
- pretensor/enrichment/analyze/writers.py +214 -0
- pretensor/enrichment/dbt/__init__.py +30 -0
- pretensor/enrichment/dbt/lineage.py +100 -0
- pretensor/enrichment/dbt/manifest.py +300 -0
- pretensor/enrichment/dbt/metadata.py +263 -0
- pretensor/enrichment/dbt/pipeline.py +77 -0
- pretensor/enrichment/dbt/resolution.py +101 -0
- pretensor/enrichment/dbt/signals.py +305 -0
- pretensor/entities/__init__.py +27 -0
- pretensor/entities/builder.py +63 -0
- pretensor/entities/classifier.py +383 -0
- pretensor/entities/llm_extract.py +66 -0
- pretensor/errors.py +35 -0
- pretensor/graph_models/__init__.py +17 -0
- pretensor/graph_models/base.py +11 -0
- pretensor/graph_models/consumer.py +71 -0
- pretensor/graph_models/edge.py +35 -0
- pretensor/graph_models/entity.py +21 -0
- pretensor/graph_models/node.py +79 -0
- pretensor/graph_models/relationship.py +33 -0
- pretensor/integrations/__init__.py +42 -0
- pretensor/integrations/_base.py +138 -0
- pretensor/integrations/google_adk.py +49 -0
- pretensor/integrations/langchain.py +55 -0
- pretensor/integrations/llamaindex.py +53 -0
- pretensor/intelligence/__init__.py +33 -0
- pretensor/intelligence/cluster_labeler.py +425 -0
- pretensor/intelligence/clustering.py +168 -0
- pretensor/intelligence/combining.py +32 -0
- pretensor/intelligence/discovery.py +114 -0
- pretensor/intelligence/embeddings.py +317 -0
- pretensor/intelligence/graph_export.py +200 -0
- pretensor/intelligence/heuristic.py +544 -0
- pretensor/intelligence/join_paths/__init__.py +130 -0
- pretensor/intelligence/join_paths/on_demand.py +516 -0
- pretensor/intelligence/join_paths/storage.py +70 -0
- pretensor/intelligence/llm_infer.py +78 -0
- pretensor/intelligence/llm_runtime.py +62 -0
- pretensor/intelligence/metric_templates.py +193 -0
- pretensor/intelligence/pipeline.py +364 -0
- pretensor/intelligence/role_exemplars.py +263 -0
- pretensor/intelligence/schema_classification.py +360 -0
- pretensor/intelligence/scoring.py +76 -0
- pretensor/intelligence/semantic.py +240 -0
- pretensor/intelligence/shadow_alias.py +101 -0
- pretensor/intelligence/statistical.py +50 -0
- pretensor/intelligence/steps.py +191 -0
- pretensor/intelligence/steps_embedding.py +168 -0
- pretensor/introspection/__init__.py +6 -0
- pretensor/introspection/inspector.py +5 -0
- pretensor/introspection/models/__init__.py +0 -0
- pretensor/introspection/models/base.py +5 -0
- pretensor/introspection/models/config.py +237 -0
- pretensor/introspection/models/dsn.py +550 -0
- pretensor/introspection/models/plan.py +116 -0
- pretensor/introspection/models/schema.py +10 -0
- pretensor/introspection/models/semantic.py +121 -0
- pretensor/introspection/models/validation.py +116 -0
- pretensor/introspection/snapshot.py +46 -0
- pretensor/mcp/__init__.py +16 -0
- pretensor/mcp/config_json.py +24 -0
- pretensor/mcp/payload_types.py +274 -0
- pretensor/mcp/resources/__init__.py +17 -0
- pretensor/mcp/resources/markdown.py +314 -0
- pretensor/mcp/server.py +285 -0
- pretensor/mcp/service.py +49 -0
- pretensor/mcp/service_context.py +142 -0
- pretensor/mcp/service_registry.py +294 -0
- pretensor/mcp/store_cache.py +43 -0
- pretensor/mcp/tool_registry.py +136 -0
- pretensor/mcp/tools/__init__.py +1 -0
- pretensor/mcp/tools/_rank.py +244 -0
- pretensor/mcp/tools/_timed.py +26 -0
- pretensor/mcp/tools/compile_metric.py +144 -0
- pretensor/mcp/tools/consumers.py +161 -0
- pretensor/mcp/tools/context.py +1121 -0
- pretensor/mcp/tools/cypher.py +509 -0
- pretensor/mcp/tools/detect_changes.py +254 -0
- pretensor/mcp/tools/impact.py +271 -0
- pretensor/mcp/tools/list.py +131 -0
- pretensor/mcp/tools/schema.py +170 -0
- pretensor/mcp/tools/search.py +316 -0
- pretensor/mcp/tools/semantic_search.py +282 -0
- pretensor/mcp/tools/traverse.py +1027 -0
- pretensor/mcp/tools/validate_sql.py +150 -0
- pretensor/observability.py +203 -0
- pretensor/py.typed +0 -0
- pretensor/quickstart/README.md +29 -0
- pretensor/quickstart/__init__.py +6 -0
- pretensor/quickstart/docker-compose.yml +18 -0
- pretensor/quickstart/pagila_data.sql +63 -0
- pretensor/quickstart/pagila_ddl.sql +92 -0
- pretensor/search/__init__.py +6 -0
- pretensor/search/base.py +80 -0
- pretensor/search/index.py +435 -0
- pretensor/semantic/__init__.py +24 -0
- pretensor/semantic/base.py +123 -0
- pretensor/semantic/compiler.py +487 -0
- pretensor/semantic/yaml_layer.py +180 -0
- pretensor/skills/__init__.py +5 -0
- pretensor/skills/generator.py +235 -0
- pretensor/staleness/__init__.py +15 -0
- pretensor/staleness/graph_patcher.py +355 -0
- pretensor/staleness/impact_analyzer.py +162 -0
- pretensor/staleness/snapshot_store.py +38 -0
- pretensor/validation/__init__.py +9 -0
- pretensor/validation/query_validator.py +436 -0
- pretensor/visibility/__init__.py +23 -0
- pretensor/visibility/config.py +126 -0
- pretensor/visibility/filter.py +143 -0
- pretensor/visibility/kuzu_helpers.py +32 -0
- pretensor/visibility/runtime.py +36 -0
- pretensor/visibility/sync_grants.py +188 -0
- pretensor-0.1.0.dist-info/METADATA +251 -0
- pretensor-0.1.0.dist-info/RECORD +198 -0
- pretensor-0.1.0.dist-info/WHEEL +4 -0
- pretensor-0.1.0.dist-info/entry_points.txt +2 -0
- pretensor-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
"""MCP ``semantic_search`` tool — cosine ranking over ``SchemaTable.embedding``.
|
|
2
|
+
|
|
3
|
+
Read-only. Additive signal. Returns a structured ``fallback_bm25`` envelope
|
|
4
|
+
when the ``[embeddings]`` extra is absent or no candidate table carries a
|
|
5
|
+
vector — per the determinism contract, the tool must never raise
|
|
6
|
+
from its happy path and must never create graph edges.
|
|
7
|
+
|
|
8
|
+
At index time, each table is embedded as ``"{schema}.{table}: cols..."``.
|
|
9
|
+
At query time, the natural-language ``query`` string is embedded **raw**
|
|
10
|
+
(asymmetric retrieval); callers who want lexical search should use the
|
|
11
|
+
BM25 ``query`` tool.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import logging
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
from pretensor.core.registry import RegistryEntry
|
|
21
|
+
from pretensor.intelligence.embeddings import (
|
|
22
|
+
EmbeddingClient,
|
|
23
|
+
embeddings_disabled_via_env,
|
|
24
|
+
get_default_embedding_client,
|
|
25
|
+
)
|
|
26
|
+
from pretensor.mcp.tool_registry import McpTool
|
|
27
|
+
from pretensor.observability import log_timed_operation
|
|
28
|
+
from pretensor.visibility.filter import VisibilityFilter
|
|
29
|
+
|
|
30
|
+
from ..payload_types import SemanticHit, snippet
|
|
31
|
+
from ..service_context import get_effective_visibility_filter
|
|
32
|
+
from ..service_registry import (
|
|
33
|
+
load_registry,
|
|
34
|
+
resolve_registry_entry,
|
|
35
|
+
)
|
|
36
|
+
from ._rank import CosineHit, any_entry_has_vectors, cosine_rank_tables
|
|
37
|
+
|
|
38
|
+
logger = logging.getLogger(__name__)
|
|
39
|
+
|
|
40
|
+
_K_MIN = 1
|
|
41
|
+
_K_MAX = 50
|
|
42
|
+
_FALLBACK_HINT = "Install `pretensor[embeddings]` and reindex, or use the `query` tool."
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _fallback(
|
|
46
|
+
*,
|
|
47
|
+
query: str,
|
|
48
|
+
database: str | None,
|
|
49
|
+
cluster: str | None,
|
|
50
|
+
hint: str | None = None,
|
|
51
|
+
) -> dict[str, Any]:
|
|
52
|
+
"""Return the documented ``fallback_bm25`` envelope.
|
|
53
|
+
|
|
54
|
+
Extended with ``query`` / ``database`` / ``cluster`` echo so callers can
|
|
55
|
+
log and correlate without branching on envelope shape. Reserved for
|
|
56
|
+
"embeddings unavailable" (extra absent, disabled, or no vectors) —
|
|
57
|
+
caller mistakes such as an unresolved ``database`` get a plain error
|
|
58
|
+
envelope instead, matching sibling tools.
|
|
59
|
+
"""
|
|
60
|
+
return {
|
|
61
|
+
"mode": "fallback_bm25",
|
|
62
|
+
"hint": hint or _FALLBACK_HINT,
|
|
63
|
+
"results": [],
|
|
64
|
+
"query": query,
|
|
65
|
+
"database": database,
|
|
66
|
+
"cluster": cluster,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _select_entries(
|
|
71
|
+
graph_dir: Path, database: str | None
|
|
72
|
+
) -> tuple[list[RegistryEntry], str | None]:
|
|
73
|
+
"""Resolve candidate registry entries; return ``(entries, error)``."""
|
|
74
|
+
reg = load_registry(graph_dir)
|
|
75
|
+
entries = reg.list_entries()
|
|
76
|
+
if not entries:
|
|
77
|
+
return [], None # empty registry → normal fallback, not an error
|
|
78
|
+
if database is None:
|
|
79
|
+
return entries, None
|
|
80
|
+
resolved = resolve_registry_entry(reg, database)
|
|
81
|
+
if resolved is None:
|
|
82
|
+
return [], f"Unknown database: {database!r}"
|
|
83
|
+
return [resolved], None
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _hit_from_cosine(hit: CosineHit) -> SemanticHit:
|
|
87
|
+
result: SemanticHit = {
|
|
88
|
+
"node_type": "SchemaTable",
|
|
89
|
+
"name": (
|
|
90
|
+
f"{hit.schema_name}.{hit.table_name}" if hit.schema_name else hit.table_name
|
|
91
|
+
),
|
|
92
|
+
"database_name": hit.database,
|
|
93
|
+
"connection_name": hit.connection_name,
|
|
94
|
+
"description": hit.description,
|
|
95
|
+
"snippet": snippet(hit.description),
|
|
96
|
+
"score": hit.score,
|
|
97
|
+
"cluster_id": hit.cluster_id,
|
|
98
|
+
}
|
|
99
|
+
return result
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def semantic_search_payload(
|
|
103
|
+
graph_dir: Path,
|
|
104
|
+
*,
|
|
105
|
+
query: str,
|
|
106
|
+
k: int = 10,
|
|
107
|
+
database: str | None = None,
|
|
108
|
+
cluster: str | None = None,
|
|
109
|
+
visibility_filter: VisibilityFilter | None = None,
|
|
110
|
+
embedding_client: EmbeddingClient | None = None,
|
|
111
|
+
) -> dict[str, Any]:
|
|
112
|
+
"""Top-K ``SchemaTable`` ids by cosine similarity against ``SchemaTable.embedding``.
|
|
113
|
+
|
|
114
|
+
Returns the happy-path envelope ``{mode: "semantic", query, database,
|
|
115
|
+
cluster, results: [...]}`` when embeddings are available, otherwise the
|
|
116
|
+
documented ``fallback_bm25`` envelope. The response never raises; any
|
|
117
|
+
``ImportError`` from the embedding client (missing ``[embeddings]``
|
|
118
|
+
extra) or unexpected runtime failure funnels to the fallback envelope
|
|
119
|
+
with a single ``WARNING`` logged.
|
|
120
|
+
"""
|
|
121
|
+
k_clamped = max(_K_MIN, min(_K_MAX, int(k)))
|
|
122
|
+
with log_timed_operation(
|
|
123
|
+
logger,
|
|
124
|
+
event="mcp.semantic_search_payload",
|
|
125
|
+
query=query,
|
|
126
|
+
database=database,
|
|
127
|
+
cluster=cluster,
|
|
128
|
+
k=k_clamped,
|
|
129
|
+
graph_dir=str(graph_dir),
|
|
130
|
+
):
|
|
131
|
+
# Kill switch wins over everything, including an injected client,
|
|
132
|
+
# so PRETENSOR_EMBEDDINGS_DISABLED=1 yields the same fallback
|
|
133
|
+
# envelope as a missing extra.
|
|
134
|
+
if embeddings_disabled_via_env():
|
|
135
|
+
return _fallback(
|
|
136
|
+
query=query,
|
|
137
|
+
database=database,
|
|
138
|
+
cluster=cluster,
|
|
139
|
+
hint=(
|
|
140
|
+
"Embeddings are disabled via PRETENSOR_EMBEDDINGS_DISABLED; "
|
|
141
|
+
"unset it to enable semantic ranking, or use the `query` tool."
|
|
142
|
+
),
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
vf = visibility_filter or get_effective_visibility_filter()
|
|
146
|
+
|
|
147
|
+
entries, error = _select_entries(graph_dir, database)
|
|
148
|
+
if error is not None:
|
|
149
|
+
# Invalid required argument: surface a plain error envelope so
|
|
150
|
+
# callers can correct the database name, matching the contract
|
|
151
|
+
# of sibling tools (`context`, `traverse`). The fallback_bm25
|
|
152
|
+
# envelope is reserved for "embeddings unavailable", not for
|
|
153
|
+
# caller mistakes.
|
|
154
|
+
return {
|
|
155
|
+
"error": error,
|
|
156
|
+
"query": query,
|
|
157
|
+
"database": database,
|
|
158
|
+
"cluster": cluster,
|
|
159
|
+
"hint": (
|
|
160
|
+
"Resolve the database name with the `list_databases` "
|
|
161
|
+
"tool, then retry."
|
|
162
|
+
),
|
|
163
|
+
}
|
|
164
|
+
if not entries:
|
|
165
|
+
return _fallback(query=query, database=database, cluster=cluster)
|
|
166
|
+
|
|
167
|
+
# Probe for stored vectors BEFORE embedding the query: with none
|
|
168
|
+
# present the response is the fallback envelope regardless, and on
|
|
169
|
+
# a cold process the first embed() call would trigger the ONNX
|
|
170
|
+
# model download + session init for nothing.
|
|
171
|
+
if not any_entry_has_vectors(entries):
|
|
172
|
+
return _fallback(query=query, database=database, cluster=cluster)
|
|
173
|
+
|
|
174
|
+
# Embed the natural-language query as-is. The indexed documents use
|
|
175
|
+
# ``"{schema}.{table}: cols..."``; asymmetric CLS-pooled retrieval.
|
|
176
|
+
# Construction is I/O-free (the ONNX session loads lazily inside
|
|
177
|
+
# ``embed()``); only the embed() call can raise, and it's caught
|
|
178
|
+
# below to route to the never-raises fallback envelope.
|
|
179
|
+
client: EmbeddingClient = embedding_client or get_default_embedding_client()
|
|
180
|
+
try:
|
|
181
|
+
vectors = client.embed([query])
|
|
182
|
+
except ImportError as exc:
|
|
183
|
+
logger.warning("semantic_search: [embeddings] extra not installed: %s", exc)
|
|
184
|
+
return _fallback(query=query, database=database, cluster=cluster)
|
|
185
|
+
except Exception as exc: # noqa: BLE001 — tool must never raise
|
|
186
|
+
logger.warning(
|
|
187
|
+
"semantic_search: embedding client failed (%s); returning fallback",
|
|
188
|
+
exc,
|
|
189
|
+
)
|
|
190
|
+
return _fallback(query=query, database=database, cluster=cluster)
|
|
191
|
+
|
|
192
|
+
if not vectors:
|
|
193
|
+
# NullEmbeddingClient path.
|
|
194
|
+
return _fallback(query=query, database=database, cluster=cluster)
|
|
195
|
+
|
|
196
|
+
qvec = vectors[0]
|
|
197
|
+
|
|
198
|
+
cosine_hits, any_candidate_had_vector = cosine_rank_tables(
|
|
199
|
+
entries,
|
|
200
|
+
qvec,
|
|
201
|
+
database=database,
|
|
202
|
+
cluster=cluster,
|
|
203
|
+
visibility_filter=vf,
|
|
204
|
+
k=k_clamped,
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
if not any_candidate_had_vector:
|
|
208
|
+
return _fallback(query=query, database=database, cluster=cluster)
|
|
209
|
+
|
|
210
|
+
results = [_hit_from_cosine(h) for h in cosine_hits]
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
"mode": "semantic",
|
|
214
|
+
"query": query,
|
|
215
|
+
"database": database,
|
|
216
|
+
"cluster": cluster,
|
|
217
|
+
"results": results,
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
__all__ = ["create_tool", "semantic_search_payload"]
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def create_tool(graph_dir: Path) -> McpTool:
|
|
225
|
+
from ._timed import timed_tool
|
|
226
|
+
|
|
227
|
+
async def _handle(args: dict) -> dict:
|
|
228
|
+
q = str(args.get("query", "")).strip()
|
|
229
|
+
if not q:
|
|
230
|
+
return {"error": "Missing or empty `query`"}
|
|
231
|
+
k = int(args.get("k", 10))
|
|
232
|
+
database = args.get("database")
|
|
233
|
+
database_s = str(database) if database is not None else None
|
|
234
|
+
cluster = args.get("cluster")
|
|
235
|
+
cluster_s = str(cluster) if cluster is not None else None
|
|
236
|
+
with timed_tool(
|
|
237
|
+
"semantic_search", graph_dir, database=database_s, cluster=cluster_s, k=k
|
|
238
|
+
):
|
|
239
|
+
return semantic_search_payload(
|
|
240
|
+
graph_dir,
|
|
241
|
+
query=q,
|
|
242
|
+
k=k,
|
|
243
|
+
database=database_s,
|
|
244
|
+
cluster=cluster_s,
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
return McpTool(
|
|
248
|
+
name="semantic_search",
|
|
249
|
+
description=(
|
|
250
|
+
"Natural-language semantic search over SchemaTable nodes by cosine similarity "
|
|
251
|
+
"against the persisted embedding column. Requires the `[embeddings]` extra — "
|
|
252
|
+
"falls back to a structured hint pointing at the `query` (BM25) tool when the "
|
|
253
|
+
"extra is absent or no tables carry vectors."
|
|
254
|
+
),
|
|
255
|
+
input_schema={
|
|
256
|
+
"type": "object",
|
|
257
|
+
"properties": {
|
|
258
|
+
"query": {
|
|
259
|
+
"type": "string",
|
|
260
|
+
"description": "Natural-language query to embed and match against table vectors",
|
|
261
|
+
},
|
|
262
|
+
"k": {
|
|
263
|
+
"type": "integer",
|
|
264
|
+
"default": 10,
|
|
265
|
+
"minimum": 1,
|
|
266
|
+
"maximum": 50,
|
|
267
|
+
"description": "Maximum number of hits to return (clamped to 1..50)",
|
|
268
|
+
},
|
|
269
|
+
"database": {
|
|
270
|
+
"type": ["string", "null"],
|
|
271
|
+
"description": "Restrict scan to one connection_name or logical database",
|
|
272
|
+
},
|
|
273
|
+
"cluster": {
|
|
274
|
+
"type": ["string", "null"],
|
|
275
|
+
"description": "Restrict scan to one Cluster id (node_id)",
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
"required": ["query"],
|
|
279
|
+
"additionalProperties": False,
|
|
280
|
+
},
|
|
281
|
+
handler=_handle,
|
|
282
|
+
)
|