feat: rescope to AI-first DB harness with multi-DB chat agent
Removes enterprise/DBA features and replaces the marginal AI bar with a central chat agent that has progressive-discovery tools, cross-session memory, saved-query reuse, and inline result actions. Adds ClickHouse support alongside PostgreSQL/Greenplum. Cleanup - Drop ~10k LOC of advanced features: Docker, Snapshots, Validation, Index Advisor, Role/User Management, Data Generator, ERD, Lookup. - Trim deps: drop @xyflow/react, dagre, @types/dagre; cut tokio features to rt-multi-thread/sync/time/net/macros. - Remove unused TuskError variants and dead helpers (topological_sort, invalidate_schema_cache). Multi-DB (PostgreSQL + ClickHouse) - New src-tauri/src/db/ module: ChClient (HTTP-based, reuses reqwest), sql_guard (cross-flavor read-only whitelist with 8 tests). - ConnectionConfig gains db_flavor and secure fields with serde defaults for backwards-compatible connections.json. - All connection/query/schema/data commands dispatch by flavor; CH covers connect, execute_query, list_databases/schemas/tables/views/ columns/completion_schema, paginated table fetch. - Frontend: dbCapabilities matrix, ConnectionDialog engine selector with port auto-swap and HTTPS toggle, SqlEditor switches to StandardSQL dialect for CH, TableDataView surfaces CH connections as read-only. AI-first chat agent - New src/components/chat/ panel with composer, message rendering, collapsible tool-call/result blocks, top-level ErrorBoundary. - Backend agent loop in commands/chat.rs with strict-JSON tool protocol. Nine tools: list_databases, list_tables, get_columns, switch_database, run_query, remember, save_query, find_queries, final. Forgiving parser accepts both flat and nested-input shapes. - Compressed history: only the last 4 run_query results carry sample rows (≤10, cells truncated to 200 chars) into LLM context; older results marked omitted. - System prompt uses lite OVERVIEW (DB list + active-DB tables only) instead of full DDL — schema details are loaded on demand via get_columns. CH OVERVIEW shows cross-DB tables since CH allows db.table queries. Cross-session memory (F1) - Per-connection markdown file at app_data_dir/memory/<connection_id>.md, 16KB cap with oldest-block eviction. Agent appends via remember() tool; the file is injected into LEARNED NOTES section of every system prompt. - New Memory sidebar tab with editable textarea, badge for note count, empty-state with template. Edits picked up on the next agent turn. Saved-query reuse (F2) - Tools save_query and find_queries scoped to current connection. save_query attaches a UUID + timestamp; find_queries returns top 10 matches with SQL preview ≤500 chars. - Storage shared with the sidebar Saved panel. Inline result actions (F3) - run_query result block in chat gets Open-full (90vw × 80vh modal with full ResultsTable, no row cap) and Export (reuses ExportDialog for CSV/JSON via existing exportCsv/exportJson commands). Verification - cargo check clean, zero warnings. - cargo test --lib: 50 pass (20 chat parser + 4 memory + 8 sql_guard + 6 clean_sql + 12 escape_ident). - npx tsc --noEmit clean. - npx vitest run: 20 pass.
This commit is contained in:
@@ -41,6 +41,8 @@ pub struct OllamaChatRequest {
|
||||
pub model: String,
|
||||
pub messages: Vec<OllamaChatMessage>,
|
||||
pub stream: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub format: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
@@ -57,130 +59,3 @@ pub struct OllamaTagsResponse {
|
||||
pub struct OllamaModel {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
// --- Wave 1: Validation ---
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ValidationStatus {
|
||||
Pending,
|
||||
Generating,
|
||||
Running,
|
||||
Passed,
|
||||
Failed,
|
||||
Error,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ValidationRule {
|
||||
pub id: String,
|
||||
pub description: String,
|
||||
pub generated_sql: String,
|
||||
pub status: ValidationStatus,
|
||||
pub violation_count: u64,
|
||||
pub sample_violations: Vec<Vec<serde_json::Value>>,
|
||||
pub violation_columns: Vec<String>,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
// --- Wave 2: Data Generator ---
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GenerateDataParams {
|
||||
pub connection_id: String,
|
||||
pub schema: String,
|
||||
pub table: String,
|
||||
pub row_count: u32,
|
||||
pub include_related: bool,
|
||||
pub custom_instructions: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GeneratedDataPreview {
|
||||
pub tables: Vec<GeneratedTableData>,
|
||||
pub insert_order: Vec<String>,
|
||||
pub total_rows: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GeneratedTableData {
|
||||
pub schema: String,
|
||||
pub table: String,
|
||||
pub columns: Vec<String>,
|
||||
pub rows: Vec<Vec<serde_json::Value>>,
|
||||
pub row_count: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DataGenProgress {
|
||||
pub gen_id: String,
|
||||
pub stage: String,
|
||||
pub percent: u8,
|
||||
pub message: String,
|
||||
pub detail: Option<String>,
|
||||
}
|
||||
|
||||
// --- Wave 3A: Index Advisor ---
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct TableStats {
|
||||
pub schema: String,
|
||||
pub table: String,
|
||||
pub seq_scan: i64,
|
||||
pub idx_scan: i64,
|
||||
pub n_live_tup: i64,
|
||||
pub table_size: String,
|
||||
pub index_size: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct IndexStats {
|
||||
pub schema: String,
|
||||
pub table: String,
|
||||
pub index_name: String,
|
||||
pub idx_scan: i64,
|
||||
pub index_size: String,
|
||||
pub definition: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SlowQuery {
|
||||
pub query: String,
|
||||
pub calls: i64,
|
||||
pub total_time_ms: f64,
|
||||
pub mean_time_ms: f64,
|
||||
pub rows: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum IndexRecommendationType {
|
||||
#[serde(rename = "create_index")]
|
||||
Create,
|
||||
#[serde(rename = "drop_index")]
|
||||
Drop,
|
||||
#[serde(rename = "replace_index")]
|
||||
Replace,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct IndexRecommendation {
|
||||
pub id: String,
|
||||
pub recommendation_type: IndexRecommendationType,
|
||||
pub table_schema: String,
|
||||
pub table_name: String,
|
||||
pub index_name: Option<String>,
|
||||
pub ddl: String,
|
||||
pub rationale: String,
|
||||
pub estimated_impact: String,
|
||||
pub priority: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct IndexAdvisorReport {
|
||||
pub table_stats: Vec<TableStats>,
|
||||
pub index_stats: Vec<IndexStats>,
|
||||
pub slow_queries: Vec<SlowQuery>,
|
||||
pub recommendations: Vec<IndexRecommendation>,
|
||||
pub has_pg_stat_statements: bool,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user