dbagent-cli 0.9.7__tar.gz → 0.9.8__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.
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/PKG-INFO +1 -1
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/__init__.py +1 -1
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/agent/generator.py +4 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/agent/pipeline.py +14 -1
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/cli.py +43 -7
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/ui/chat_screen.py +8 -1
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent_cli.egg-info/PKG-INFO +1 -1
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/pyproject.toml +1 -1
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/tests/test_cli.py +19 -2
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/README.md +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/agent/confidence.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/agent/conversation.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/agent/doctor.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/agent/error_classifier.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/agent/recommender.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/agent/validator.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/config.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/connectors/base.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/connectors/factory.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/connectors/mongo.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/connectors/relational.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/execution/__init__.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/execution/cache.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/execution/changeset.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/execution/cost.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/execution/recovery.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/execution/sandbox.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/execution/streaming.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/llm/anthropic_provider.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/llm/auto_setup.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/llm/base.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/llm/deepseek_provider.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/llm/factory.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/llm/gemini_provider.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/llm/groq_provider.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/llm/mistral_provider.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/llm/mock_provider.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/llm/ollama_provider.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/llm/openai_provider.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/llm/openrouter_provider.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/schema/cache.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/schema/formatter.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/schema/graph.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/schema/ground_truth.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/schema/models.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/schema/retriever.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/schema/selector.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/security/__init__.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/security/audit.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/security/environment.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/security/masking.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/security/modes.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/security/rbac.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/semantic/__init__.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/semantic/dictionary.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/semantic/knowledge.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/semantic/templates.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/sql/__init__.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/sql/optimizer.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/sql/validator.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/ui/console.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/ui/grid_window.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/ui/viewer.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent/ui/visualizer.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent_cli.egg-info/SOURCES.txt +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent_cli.egg-info/dependency_links.txt +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent_cli.egg-info/entry_points.txt +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent_cli.egg-info/requires.txt +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/dbagent_cli.egg-info/top_level.txt +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/setup.cfg +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/tests/test_cache.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/tests/test_connectors.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/tests/test_direct_sql.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/tests/test_doctor_and_viz.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/tests/test_generator.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/tests/test_graph.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/tests/test_knowledge.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/tests/test_providers.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/tests/test_recovery.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/tests/test_safety.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/tests/test_sandbox.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/tests/test_schema.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/tests/test_security.py +0 -0
- {dbagent_cli-0.9.7 → dbagent_cli-0.9.8}/tests/test_semantic.py +0 -0
|
@@ -247,6 +247,7 @@ class ScriptGenerator:
|
|
|
247
247
|
user_prompt: str,
|
|
248
248
|
conversation_history: Optional[str] = None,
|
|
249
249
|
model: Optional[str] = None,
|
|
250
|
+
stream_callback: Optional[Callable[[str], None]] = None,
|
|
250
251
|
) -> str:
|
|
251
252
|
"""Generate a natural conversational response to the user's message with full session memory."""
|
|
252
253
|
table_names = [t.name for t in schema.tables]
|
|
@@ -268,6 +269,7 @@ class ScriptGenerator:
|
|
|
268
269
|
prompt=full_prompt,
|
|
269
270
|
system_prompt=system_prompt,
|
|
270
271
|
model=model,
|
|
272
|
+
stream_callback=stream_callback,
|
|
271
273
|
)
|
|
272
274
|
|
|
273
275
|
def generate_analysis_response(
|
|
@@ -276,6 +278,7 @@ class ScriptGenerator:
|
|
|
276
278
|
user_prompt: str,
|
|
277
279
|
conversation_history: Optional[str] = None,
|
|
278
280
|
model: Optional[str] = None,
|
|
281
|
+
stream_callback: Optional[Callable[[str], None]] = None,
|
|
279
282
|
) -> str:
|
|
280
283
|
"""Generate a comprehensive architectural analysis report with ASCII diagrams, theory, and SQL queries."""
|
|
281
284
|
# 1. Filter relevant tables including foreign keys and junction tables
|
|
@@ -301,6 +304,7 @@ class ScriptGenerator:
|
|
|
301
304
|
prompt=full_prompt,
|
|
302
305
|
system_prompt=system_prompt,
|
|
303
306
|
model=model,
|
|
307
|
+
stream_callback=stream_callback,
|
|
304
308
|
)
|
|
305
309
|
|
|
306
310
|
# --- Full generation (for `generate` command) ---
|
|
@@ -56,6 +56,7 @@ class PipelineResult:
|
|
|
56
56
|
# Conversational chat response
|
|
57
57
|
is_chat: bool = False
|
|
58
58
|
is_direct_sql: bool = False
|
|
59
|
+
was_streamed: bool = False
|
|
59
60
|
message: str = ""
|
|
60
61
|
# Query classification
|
|
61
62
|
query_type: str = "unknown" # read, write, ddl, chat, unknown
|
|
@@ -192,7 +193,13 @@ class QueryPipeline:
|
|
|
192
193
|
retriever = ContextRetriever(targeted)
|
|
193
194
|
return retriever.retrieve_context(user_prompt, exact_tables=exact, fuzzy_tables=fuzzy, max_tables=12)
|
|
194
195
|
|
|
195
|
-
def run(
|
|
196
|
+
def run(
|
|
197
|
+
self,
|
|
198
|
+
user_prompt: str,
|
|
199
|
+
force: bool = False,
|
|
200
|
+
bypass_cache: bool = False,
|
|
201
|
+
stream_callback: Optional[Callable[[str], None]] = None,
|
|
202
|
+
) -> PipelineResult:
|
|
196
203
|
"""
|
|
197
204
|
Executes end-to-end pipeline: Prompt -> Security/Semantics -> SQL -> Safe Exec -> Results.
|
|
198
205
|
"""
|
|
@@ -217,7 +224,10 @@ class QueryPipeline:
|
|
|
217
224
|
user_prompt=user_prompt,
|
|
218
225
|
conversation_history=conv_history,
|
|
219
226
|
model=self.model,
|
|
227
|
+
stream_callback=stream_callback,
|
|
220
228
|
)
|
|
229
|
+
if stream_callback:
|
|
230
|
+
result.was_streamed = True
|
|
221
231
|
result.is_chat = True
|
|
222
232
|
result.was_executed = True
|
|
223
233
|
result.query_type = "chat"
|
|
@@ -273,7 +283,10 @@ class QueryPipeline:
|
|
|
273
283
|
user_prompt=analysis_prompt,
|
|
274
284
|
conversation_history=conv_history,
|
|
275
285
|
model=self.model,
|
|
286
|
+
stream_callback=stream_callback,
|
|
276
287
|
)
|
|
288
|
+
if stream_callback:
|
|
289
|
+
result.was_streamed = True
|
|
277
290
|
result.ground_truth = SchemaGroundTruthValidator.validate_response(result.message, sub_schema)
|
|
278
291
|
result.is_chat = True
|
|
279
292
|
result.was_executed = True
|
|
@@ -339,7 +339,10 @@ def _display_pipeline_result(result: PipelineResult, show_sql: bool = True) -> N
|
|
|
339
339
|
|
|
340
340
|
if result.is_chat and result.message:
|
|
341
341
|
console.print("")
|
|
342
|
-
|
|
342
|
+
if not result.was_streamed:
|
|
343
|
+
console.print(Markdown(result.message))
|
|
344
|
+
if result.ground_truth:
|
|
345
|
+
console.print(result.ground_truth.format_summary())
|
|
343
346
|
if result.execution_time_ms > 0:
|
|
344
347
|
print_timing(result.execution_time_ms)
|
|
345
348
|
console.print("")
|
|
@@ -527,8 +530,25 @@ def ask_command(
|
|
|
527
530
|
choice_callback=_choice_callback,
|
|
528
531
|
)
|
|
529
532
|
|
|
530
|
-
|
|
531
|
-
|
|
533
|
+
spinner = DynamicSpinner.for_prompt(prompt, model_name=model or getattr(llm, "default_model", None), connector=connector)
|
|
534
|
+
stream_started = [False]
|
|
535
|
+
|
|
536
|
+
def _query_stream_callback(chunk: str) -> None:
|
|
537
|
+
if not stream_started[0]:
|
|
538
|
+
stream_started[0] = True
|
|
539
|
+
spinner.pause()
|
|
540
|
+
timing_str = f"⚡ {spinner.elapsed_ms / 1000:.2f}s" if spinner.elapsed_ms > 0 else ""
|
|
541
|
+
active_model = model or getattr(llm, "default_model", None)
|
|
542
|
+
model_display = f" ({active_model})" if active_model else ""
|
|
543
|
+
console.print(f"\n[bold cyan]● DB-Agent{model_display}[/bold cyan] [dim]{timing_str}[/dim]")
|
|
544
|
+
try:
|
|
545
|
+
sys.stdout.write(chunk)
|
|
546
|
+
sys.stdout.flush()
|
|
547
|
+
except Exception:
|
|
548
|
+
pass
|
|
549
|
+
|
|
550
|
+
with spinner:
|
|
551
|
+
result = pipeline.run(user_prompt=prompt, force=force, bypass_cache=no_cache, stream_callback=_query_stream_callback)
|
|
532
552
|
|
|
533
553
|
_display_pipeline_result(result, show_sql=True)
|
|
534
554
|
connector.close()
|
|
@@ -1094,14 +1114,30 @@ def chat_command(
|
|
|
1094
1114
|
console.print("[bold cyan]Goodbye![/bold cyan]")
|
|
1095
1115
|
break
|
|
1096
1116
|
|
|
1097
|
-
# --- Natural language query via pipeline ---
|
|
1098
|
-
# Update pipeline settings in-place (pipeline was created once before the loop)
|
|
1117
|
+
# --- Natural language query via pipeline with live streaming ---
|
|
1099
1118
|
pipeline.model = model
|
|
1100
1119
|
pipeline.mode = current_mode
|
|
1101
1120
|
pipeline.auto_execute = auto_execute
|
|
1102
1121
|
|
|
1103
|
-
|
|
1104
|
-
|
|
1122
|
+
spinner = DynamicSpinner.for_prompt(user_input, model_name=model or getattr(llm, "default_model", None), connector=connector)
|
|
1123
|
+
stream_started = [False]
|
|
1124
|
+
|
|
1125
|
+
def _live_stream_callback(chunk: str) -> None:
|
|
1126
|
+
if not stream_started[0]:
|
|
1127
|
+
stream_started[0] = True
|
|
1128
|
+
spinner.pause()
|
|
1129
|
+
timing_str = f"⚡ {spinner.elapsed_ms / 1000:.2f}s" if spinner.elapsed_ms > 0 else ""
|
|
1130
|
+
active_model = model or getattr(llm, "default_model", None)
|
|
1131
|
+
model_display = f" ({active_model})" if active_model else ""
|
|
1132
|
+
console.print(f"\n[bold cyan]● DB-Agent{model_display}[/bold cyan] [dim]{timing_str}[/dim]")
|
|
1133
|
+
try:
|
|
1134
|
+
sys.stdout.write(chunk)
|
|
1135
|
+
sys.stdout.flush()
|
|
1136
|
+
except Exception:
|
|
1137
|
+
pass
|
|
1138
|
+
|
|
1139
|
+
with spinner:
|
|
1140
|
+
result = pipeline.run(user_prompt=user_input, stream_callback=_live_stream_callback)
|
|
1105
1141
|
|
|
1106
1142
|
render_assistant_turn(
|
|
1107
1143
|
result,
|
|
@@ -114,8 +114,15 @@ def render_assistant_turn(
|
|
|
114
114
|
model_display = f" ({ai_model})" if ai_model else ""
|
|
115
115
|
agent_title = f"[bold cyan]● DB-Agent{model_display}[/bold cyan] [dim]{timing_str}[/dim]"
|
|
116
116
|
|
|
117
|
-
# Conversational Chat Response
|
|
117
|
+
# Conversational Chat / Architectural Analysis Response
|
|
118
118
|
if result.is_chat and result.message:
|
|
119
|
+
if result.was_streamed:
|
|
120
|
+
console.print("")
|
|
121
|
+
if result.ground_truth:
|
|
122
|
+
console.print(result.ground_truth.format_summary())
|
|
123
|
+
console.print("")
|
|
124
|
+
return
|
|
125
|
+
|
|
119
126
|
console.print(f"\n{agent_title}")
|
|
120
127
|
console.print(Markdown(result.message))
|
|
121
128
|
if result.ground_truth:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dbagent-cli"
|
|
7
|
-
version = "0.9.
|
|
7
|
+
version = "0.9.8"
|
|
8
8
|
description = "Enterprise AI Database Copilot, Schema Graph Introspector & Autonomous Recovery Agent (CLI)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -481,6 +481,25 @@ def test_cli_changes_and_audit_commands():
|
|
|
481
481
|
assert res_audit.exit_code == 0
|
|
482
482
|
|
|
483
483
|
|
|
484
|
+
def test_pipeline_streaming_callback(sample_db: str):
|
|
485
|
+
from dbagent.connectors.factory import create_connector
|
|
486
|
+
from dbagent.llm.mock_provider import MockProvider
|
|
487
|
+
from dbagent.agent.pipeline import QueryPipeline
|
|
488
|
+
|
|
489
|
+
connector = create_connector(sample_db)
|
|
490
|
+
llm = MockProvider()
|
|
491
|
+
pipeline = QueryPipeline(connector=connector, llm=llm)
|
|
492
|
+
|
|
493
|
+
chunks = []
|
|
494
|
+
def callback(token: str):
|
|
495
|
+
chunks.append(token)
|
|
496
|
+
|
|
497
|
+
result = pipeline.run("hello assistant", stream_callback=callback)
|
|
498
|
+
assert result.was_streamed is True
|
|
499
|
+
assert result.is_chat is True
|
|
500
|
+
connector.close()
|
|
501
|
+
|
|
502
|
+
|
|
484
503
|
def test_cli_recovery_commands():
|
|
485
504
|
res_list = runner.invoke(app, ["recovery", "list"])
|
|
486
505
|
assert res_list.exit_code == 0
|
|
@@ -491,5 +510,3 @@ def test_cli_recovery_commands():
|
|
|
491
510
|
|
|
492
511
|
res_cleanup = runner.invoke(app, ["recovery", "cleanup"])
|
|
493
512
|
assert res_cleanup.exit_code == 0
|
|
494
|
-
|
|
495
|
-
|
|
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
|