Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 66 additions & 20 deletions packages/drivers/src/duckdb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,24 @@ export async function connect(config: ConnectionConfig): Promise<Connector> {
let db: any
let connection: any

// altimate_change start — improve DuckDB error messages
function wrapDuckDBError(err: Error): Error {
const msg = err.message || String(err)
if (msg.toLowerCase().includes("locked") || msg.includes("SQLITE_BUSY") || msg.includes("DUCKDB_LOCKED")) {
return new Error(
`Database "${dbPath}" is locked by another process. ` +
`DuckDB does not support concurrent write access. ` +
`Close other connections to this file and try again.`,
)
}
return err
}
// altimate_change end

function query(sql: string): Promise<any[]> {
return new Promise((resolve, reject) => {
connection.all(sql, (err: Error | null, rows: any[]) => {
if (err) reject(err)
if (err) reject(wrapDuckDBError(err))
else resolve(rows ?? [])
})
})
Expand All @@ -29,33 +43,65 @@ export async function connect(config: ConnectionConfig): Promise<Connector> {
function queryWithParams(sql: string, params: any[]): Promise<any[]> {
return new Promise((resolve, reject) => {
connection.all(sql, ...params, (err: Error | null, rows: any[]) => {
if (err) reject(err)
if (err) reject(wrapDuckDBError(err))
else resolve(rows ?? [])
})
})
}

return {
async connect() {
db = await new Promise<any>((resolve, reject) => {
let resolved = false
const instance = new duckdb.Database(
dbPath,
(err: Error | null) => {
if (resolved) return // Already resolved via timeout
resolved = true
if (err) reject(err)
else resolve(instance)
},
)
// Bun: native callback may not fire; fall back after 2s
setTimeout(() => {
if (!resolved) {
resolved = true
resolve(instance)
// altimate_change start — retry with read-only on lock errors
const tryConnect = (accessMode?: string): Promise<any> =>
new Promise<any>((resolve, reject) => {
let resolved = false
let timeout: ReturnType<typeof setTimeout> | undefined
const opts = accessMode ? { access_mode: accessMode } : undefined
const instance = new duckdb.Database(
dbPath,
opts,
(err: Error | null) => {
if (resolved) { if (instance && typeof instance.close === "function") instance.close(); return }
resolved = true
if (timeout) clearTimeout(timeout)
if (err) {
const msg = err.message || String(err)
if (msg.toLowerCase().includes("locked") || msg.includes("SQLITE_BUSY") || msg.includes("DUCKDB_LOCKED")) {
reject(new Error("DUCKDB_LOCKED"))
} else {
reject(err)
}
} else {
resolve(instance)
}
},
)
// Bun: native callback may not fire; fall back after 2s
timeout = setTimeout(() => {
if (!resolved) {
resolved = true
reject(new Error(`Timed out opening DuckDB database "${dbPath}"`))
}
}, 2000)
})

try {
db = await tryConnect()
} catch (err: any) {
if (err.message === "DUCKDB_LOCKED" && dbPath !== ":memory:") {
// Retry in read-only mode — allows concurrent reads
try {
db = await tryConnect("READ_ONLY")
} catch (retryErr) {
throw wrapDuckDBError(
retryErr instanceof Error ? retryErr : new Error(String(retryErr)),
)
}
}, 2000)
})
} else {
throw err
}
}
// altimate_change end
connection = db.connect()
},

Expand Down
6 changes: 3 additions & 3 deletions packages/opencode/src/altimate/tools/altimate-core-check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export function formatCheck(data: Record<string, any>): string {
lines.push("No lint findings.")
} else {
for (const f of data.lint?.findings ?? []) {
lines.push(` [${f.severity}] ${f.rule}: ${f.message}`)
lines.push(` [${f.severity ?? "warning"}] ${f.rule ?? "lint"}: ${f.message ?? ""}`)
}
}

Expand All @@ -93,7 +93,7 @@ export function formatCheck(data: Record<string, any>): string {
lines.push("Safe — no threats.")
} else {
for (const t of data.safety?.threats ?? []) {
lines.push(` [${t.severity}] ${t.type}: ${t.description}`)
lines.push(` [${t.severity ?? "warning"}] ${t.type ?? "safety"}: ${t.description ?? ""}`)
}
}

Expand All @@ -102,7 +102,7 @@ export function formatCheck(data: Record<string, any>): string {
lines.push("No PII detected.")
} else {
for (const p of data.pii?.findings ?? []) {
lines.push(` ${p.column}: ${p.category} (${p.confidence} confidence)`)
lines.push(` ${p.column ?? "unknown"}: ${p.category ?? "PII"} (${p.confidence ?? "unknown"} confidence)`)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ function formatRewrite(data: Record<string, any>): string {
}
lines.push("Rewrites applied:")
for (const r of suggestions) {
lines.push(` - ${r.rule ?? r.type}: ${r.explanation ?? r.description ?? r.improvement}`)
lines.push(` - ${r.rule ?? r.type ?? "rewrite"}: ${r.explanation ?? r.description ?? r.improvement ?? ""}`)
}
return lines.join("\n")
}
34 changes: 20 additions & 14 deletions packages/opencode/src/altimate/tools/dbt-manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const DbtManifestTool = Tool.define("dbt_manifest", {
const result = await Dispatcher.call("dbt.manifest", { path: args.path })

return {
title: `Manifest: ${result.model_count} models, ${result.source_count} sources`,
title: `Manifest: ${result.model_count ?? 0} models, ${result.source_count ?? 0} sources`,
metadata: {
model_count: result.model_count,
source_count: result.source_count,
Expand All @@ -28,7 +28,7 @@ export const DbtManifestTool = Tool.define("dbt_manifest", {
const msg = e instanceof Error ? e.message : String(e)
return {
title: "Manifest: ERROR",
metadata: { model_count: 0, source_count: 0, test_count: 0, snapshot_count: 0, seed_count: 0 },
metadata: { model_count: 0, source_count: 0, test_count: 0, snapshot_count: 0, seed_count: 0, error: msg },
output: `Failed to parse manifest: ${msg}\n\nEnsure the manifest.json exists and the dispatcher is running.`,
}
}
Expand All @@ -39,31 +39,37 @@ function formatManifest(result: DbtManifestResult): string {
const lines: string[] = []

lines.push("=== Project Summary ===")
lines.push(`Models: ${result.model_count}`)
lines.push(`Sources: ${result.source_count}`)
lines.push(`Tests: ${result.test_count}`)
lines.push(`Snapshots: ${result.snapshot_count}`)
lines.push(`Seeds: ${result.seed_count}`)
lines.push(`Models: ${result.model_count ?? 0}`)
lines.push(`Sources: ${result.source_count ?? 0}`)
lines.push(`Tests: ${result.test_count ?? 0}`)
lines.push(`Snapshots: ${result.snapshot_count ?? 0}`)
lines.push(`Seeds: ${result.seed_count ?? 0}`)

if (result.models.length > 0) {
const models = result.models ?? []
const sources = result.sources ?? []

if (models.length > 0) {
lines.push("")
lines.push("=== Models ===")
lines.push("Name | Schema | Materialized | Dependencies | Columns")
lines.push("-----|--------|-------------|-------------|--------")
for (const model of result.models) {
const deps = model.depends_on.length > 0 ? model.depends_on.map((d) => d.split(".").pop()).join(", ") : "-"
const cols = model.columns.length > 0 ? model.columns.map((c) => c.name).join(", ") : "-"
for (const model of models) {
const depsArr = model.depends_on ?? []
const colsArr = model.columns ?? []
const deps = depsArr.length > 0 ? depsArr.map((d) => d.split(".").pop()).join(", ") : "-"
const cols = colsArr.length > 0 ? colsArr.map((c) => c.name).join(", ") : "-"
lines.push(`${model.name} | ${model.schema_name ?? "-"} | ${model.materialized ?? "-"} | ${deps} | ${cols}`)
}
}

if (result.sources.length > 0) {
if (sources.length > 0) {
lines.push("")
lines.push("=== Sources ===")
lines.push("Source | Table | Schema | Columns")
lines.push("-------|-------|--------|--------")
for (const source of result.sources) {
const cols = source.columns.length > 0 ? source.columns.map((c) => c.name).join(", ") : "-"
for (const source of sources) {
const sourceCols = source.columns ?? []
const cols = sourceCols.length > 0 ? sourceCols.map((c) => c.name).join(", ") : "-"
lines.push(`${source.source_name} | ${source.name} | ${source.schema_name ?? "-"} | ${cols}`)
}
}
Expand Down
14 changes: 8 additions & 6 deletions packages/opencode/src/altimate/tools/finops-analyze-credits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,16 @@ export const FinopsAnalyzeCreditsTool = Tool.define("finops_analyze_credits", {
}
}

const totalCredits = Number(result.total_credits ?? 0)
const daysAnalyzed = result.days_analyzed ?? args.days
return {
title: `Credits: ${result.total_credits.toFixed(2)} over ${result.days_analyzed}d`,
metadata: { success: true, total_credits: result.total_credits },
title: `Credits: ${totalCredits.toFixed(2)} over ${daysAnalyzed}d`,
metadata: { success: true, total_credits: totalCredits },
output: formatCreditsAnalysis(
result.total_credits as number,
result.warehouse_summary as unknown[],
result.recommendations as unknown[],
result.daily_usage as unknown[],
totalCredits,
(result.warehouse_summary ?? []) as unknown[],
(result.recommendations ?? []) as unknown[],
(result.daily_usage ?? []) as unknown[],
),
}
} catch (e) {
Expand Down
13 changes: 7 additions & 6 deletions packages/opencode/src/altimate/tools/schema-inspect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ export const SchemaInspectTool = Tool.define("schema_inspect", {
}
// altimate_change end
return {
title: `Schema: ${result.table}`,
metadata: { columnCount: result.columns.length, rowCount: result.row_count },
title: `Schema: ${result.table ?? args.table}`,
metadata: { columnCount: (result.columns ?? []).length, rowCount: result.row_count },
output,
}
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
return {
title: "Schema: ERROR",
metadata: { columnCount: 0, rowCount: undefined },
metadata: { columnCount: 0, rowCount: undefined, error: msg },
output: `Failed to inspect schema: ${msg}\n\nEnsure the dispatcher is running and a warehouse connection is configured.`,
}
}
Expand All @@ -51,17 +51,18 @@ export const SchemaInspectTool = Tool.define("schema_inspect", {

function formatSchema(result: SchemaInspectResult): string {
const lines: string[] = []
const qualified = result.schema_name ? `${result.schema_name}.${result.table}` : result.table
const table = result.table ?? "unknown"
const qualified = result.schema_name ? `${result.schema_name}.${table}` : table
lines.push(`Table: ${qualified}`)
if (result.row_count !== null && result.row_count !== undefined) {
lines.push(`Rows: ${result.row_count.toLocaleString()}`)
}
lines.push("")
lines.push("Column | Type | Nullable | PK")
lines.push("-------|------|----------|---")
for (const col of result.columns) {
for (const col of result.columns ?? []) {
lines.push(
`${col.name} | ${col.data_type} | ${col.nullable ? "YES" : "NO"} | ${col.primary_key ? "YES" : ""}`,
`${col.name} | ${col.data_type ?? "unknown"} | ${col.nullable ? "YES" : "NO"} | ${col.primary_key ? "YES" : ""}`,
)
}
return lines.join("\n")
Expand Down
27 changes: 15 additions & 12 deletions packages/opencode/src/altimate/tools/sql-analyze.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ export const SqlAnalyzeTool = Tool.define("sql_analyze", {
// there's an actual error (e.g. parse failure).
const isRealFailure = !!result.error
// altimate_change start — sql quality findings for telemetry
const findings: Telemetry.Finding[] = result.issues.map((issue) => ({
category: issue.rule ?? issue.type,
const findings: Telemetry.Finding[] = (result.issues ?? []).map((issue) => ({
category: issue.rule ?? issue.type ?? "analysis_issue",
}))
// altimate_change end

Expand All @@ -56,7 +56,7 @@ export const SqlAnalyzeTool = Tool.define("sql_analyze", {
}
// altimate_change end
return {
title: `Analyze: ${result.error ? "ERROR" : `${result.issue_count} issue${result.issue_count !== 1 ? "s" : ""}`} [${result.confidence}]`,
title: `Analyze: ${result.error ? "ERROR" : `${result.issue_count ?? 0} issue${(result.issue_count ?? 0) !== 1 ? "s" : ""}`} [${result.confidence ?? "unknown"}]`,
metadata: {
success: !isRealFailure,
issueCount: result.issue_count,
Expand Down Expand Up @@ -91,24 +91,27 @@ function formatAnalysis(result: SqlAnalyzeResult): string {
return `Analysis failed: ${result.error}`
}

if (result.issues.length === 0) {
const issues = result.issues ?? []
if (issues.length === 0) {
return "No anti-patterns or issues detected."
}

const issueCount = result.issue_count ?? issues.length
const lines: string[] = [
`Found ${result.issue_count} issue${result.issue_count !== 1 ? "s" : ""} (confidence: ${result.confidence}):`,
`Found ${issueCount} issue${issueCount !== 1 ? "s" : ""} (confidence: ${result.confidence ?? "unknown"}):`,
]
if (result.confidence_factors.length > 0) {
lines.push(` Note: ${result.confidence_factors.join("; ")}`)
const factors = result.confidence_factors ?? []
if (factors.length > 0) {
lines.push(` Note: ${factors.join("; ")}`)
}
lines.push("")

for (const issue of result.issues) {
for (const issue of issues) {
const loc = issue.location ? ` — ${issue.location}` : ""
const conf = issue.confidence !== "high" ? ` [${issue.confidence} confidence]` : ""
lines.push(` [${issue.severity.toUpperCase()}] ${issue.type}${conf}`)
lines.push(` ${issue.message}${loc}`)
lines.push(` → ${issue.recommendation}`)
const conf = issue.confidence !== "high" ? ` [${issue.confidence ?? "unknown"} confidence]` : ""
lines.push(` [${String(issue.severity ?? "unknown").toUpperCase()}] ${issue.type ?? "unknown"}${conf}`)
lines.push(` ${issue.message ?? ""}${loc}`)
lines.push(` → ${issue.recommendation ?? ""}`)
lines.push("")
}

Expand Down
7 changes: 4 additions & 3 deletions packages/opencode/src/altimate/tools/sql-translate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const SqlTranslateTool = Tool.define("sql_translate", {
success: result.success,
source_dialect: result.source_dialect,
target_dialect: result.target_dialect,
warningCount: result.warnings.length,
warningCount: (result.warnings ?? []).length,
...(result.error && { error: result.error }),
},
output: formatTranslation(result, args.sql),
Expand Down Expand Up @@ -70,9 +70,10 @@ function formatTranslation(result: SqlTranslateResult, originalSql: string): str
lines.push(result.translated_sql ?? "")
lines.push("")

if (result.warnings.length > 0) {
const warnings = result.warnings ?? []
if (warnings.length > 0) {
lines.push("--- Warnings ---")
for (const warning of result.warnings) {
for (const warning of warnings) {
lines.push(` ! ${warning}`)
}
lines.push("")
Expand Down
11 changes: 6 additions & 5 deletions packages/opencode/src/altimate/tools/warehouse-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ export const WarehouseListTool = Tool.define("warehouse_list", {
try {
const result = await Dispatcher.call("warehouse.list", {})

if (result.warehouses.length === 0) {
const warehouses = result.warehouses ?? []
if (warehouses.length === 0) {
return {
title: "Warehouses: none configured",
metadata: { count: 0 },
Expand All @@ -18,20 +19,20 @@ export const WarehouseListTool = Tool.define("warehouse_list", {
}

const lines: string[] = ["Name | Type | Database", "-----|------|--------"]
for (const wh of result.warehouses) {
for (const wh of warehouses) {
lines.push(`${wh.name} | ${wh.type} | ${wh.database ?? "-"}`)
}

return {
title: `Warehouses: ${result.warehouses.length} configured`,
metadata: { count: result.warehouses.length },
title: `Warehouses: ${warehouses.length} configured`,
metadata: { count: warehouses.length },
output: lines.join("\n"),
}
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
return {
title: "Warehouses: ERROR",
metadata: { count: 0 },
metadata: { count: 0, error: msg },
output: `Failed to list warehouses: ${msg}\n\nCheck your connection configuration and try again.`,
}
}
Expand Down
Loading
Loading