Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
56194d7
fix: [AI-5975] propagate actual error messages to telemetry instead o…
suryaiyer95 Mar 24, 2026
1dfb107
fix: [AI-5975] early-return "No schema provided" error for `validate`…
suryaiyer95 Mar 24, 2026
f5f5382
fix: [AI-5975] add `.filter(Boolean)` to all error extractors to prev…
suryaiyer95 Mar 24, 2026
244df89
merge: resolve conflict in `sql-analyze.ts` — take main's spread patt…
suryaiyer95 Mar 24, 2026
1e4c4e4
fix: [AI-5975] treat "not equivalent" as valid result in `altimate_co…
suryaiyer95 Mar 24, 2026
fde7db3
fix: [AI-5975] address PR review feedback
suryaiyer95 Mar 24, 2026
c14852a
fix: [AI-5975] use error-driven title in semantics, generic error lab…
suryaiyer95 Mar 24, 2026
40f8e92
fix: [AI-5975] ensure `metadata.error` is never `undefined` on succes…
suryaiyer95 Mar 24, 2026
f123470
fix: [AI-5975] dispatcher wrappers: `success` means "handler complete…
suryaiyer95 Mar 24, 2026
efef758
fix: [AI-5975] address code review findings for tool wrappers
suryaiyer95 Mar 24, 2026
03b4dd9
fix: [AI-5975] revert validate tool to use dispatcher's `result.succe…
suryaiyer95 Mar 24, 2026
f0be8f2
fix: [AI-5975] make error propagation tests self-contained with mocks
suryaiyer95 Mar 24, 2026
ddf53be
fix: [AI-5975] propagate tool error messages to telemetry across all …
suryaiyer95 Mar 24, 2026
9d08243
fix: [AI-5975] add missing `dialect` fields to test args for type-check
suryaiyer95 Mar 24, 2026
3623461
fix: [AI-5975] remove spurious `dialect` from grade test (no such param)
suryaiyer95 Mar 24, 2026
8f05cf8
Merge remote-tracking branch 'origin/main' into fix/ai-5975-tool-erro…
suryaiyer95 Mar 24, 2026
7a85ad8
fix: [AI-5975] update test expectation to match error title format af…
suryaiyer95 Mar 24, 2026
fe1d8a1
feat: [AI-5975] add sql_quality telemetry for issue prevention metric…
suryaiyer95 Mar 24, 2026
e2d07c7
Merge branch 'main' into fix/ai-5975-tool-error-propagation
anandgupta42 Mar 24, 2026
3aa877a
Merge branch 'main' into fix/ai-5975-tool-error-propagation
suryaiyer95 Mar 25, 2026
353fde3
Merge branch 'main' into fix/ai-5975-tool-error-propagation
suryaiyer95 Mar 25, 2026
a692b74
fix: add missing `altimate_change` markers and prettier formatting in…
anandgupta42 Mar 25, 2026
a6d1609
style: prettier formatting on all changed tool files
anandgupta42 Mar 25, 2026
5ee2ce5
fix: preserve original formatting of `errorMsg` ternary to avoid mark…
anandgupta42 Mar 25, 2026
314a805
fix: restore original `errorMsg` indentation to match `main`
anandgupta42 Mar 25, 2026
f713632
fix: correct indentation of `altimate_change end` marker in `tool.ts`
anandgupta42 Mar 25, 2026
a22c03a
fix: propagate `metadata.error` in `sql-optimize` and `sql-translate`…
anandgupta42 Mar 25, 2026
307613e
fix: remove unused `@ts-expect-error` directives now that `define()` …
anandgupta42 Mar 25, 2026
e79eb66
Merge remote-tracking branch 'origin/main' into fix/ai-5975-tool-erro…
anandgupta42 Mar 25, 2026
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
10 changes: 10 additions & 0 deletions packages/opencode/src/altimate/native/sql/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,13 +215,23 @@ register("sql.fix", async (params) => {
fixed_sql: f.fixed_sql ?? f.rewritten_sql,
}))

const unfixableMessages = Array.isArray(result.unfixable_errors)
? result.unfixable_errors
.map((e: any) => e.error?.message ?? e.message ?? e.reason ?? String(e))
.filter((msg: any) => typeof msg === "string" ? msg.trim().length > 0 : Boolean(msg))
: []
const unfixableError = !result.fixed && unfixableMessages.length > 0
? unfixableMessages.join("; ")
: undefined

return {
success: result.fixed ?? true,
original_sql: result.original_sql ?? params.sql,
fixed_sql: result.fixed_sql ?? params.sql,
error_message: params.error_message ?? "",
suggestions,
suggestion_count: suggestions.length,
...(unfixableError && { error: unfixableError }),
}
} catch (e) {
return {
Expand Down
2 changes: 2 additions & 0 deletions packages/opencode/src/altimate/native/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface SqlExecuteResult {
export interface SqlAnalyzeParams {
sql: string
dialect?: string
schema_path?: string
schema_context?: Record<string, any>
}

Expand Down Expand Up @@ -385,6 +386,7 @@ export interface SqlFixResult {
error_message: string
suggestions: SqlFixSuggestion[]
suggestion_count: number
error?: string
}

// --- SQL Autocomplete ---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Dispatcher } from "../native"

export const AltimateCoreCheckTool = Tool.define("altimate_core_check", {
description:
"Run full analysis pipeline: validate + lint + safety scan + PII check using the Rust-based altimate-core engine. Single call for comprehensive SQL analysis.",
"Run full analysis pipeline: validate + lint + safety scan + PII check. Single call for comprehensive SQL analysis. Provide schema_context or schema_path for accurate table/column resolution.",
parameters: z.object({
sql: z.string().describe("SQL query to analyze"),
schema_path: z.string().optional().describe("Path to YAML/JSON schema file"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Dispatcher } from "../native"

export const AltimateCoreClassifyPiiTool = Tool.define("altimate_core_classify_pii", {
description:
"Classify PII columns in a schema using the Rust-based altimate-core engine. Identifies columns likely containing personal identifiable information by name patterns and data types.",
"Classify PII columns in a schema. Identifies columns likely containing personal identifiable information by name patterns and data types. Provide schema_context or schema_path for accurate table/column resolution.",
parameters: z.object({
schema_path: z.string().optional().describe("Path to YAML/JSON schema file"),
schema_context: z.record(z.string(), z.any()).optional().describe("Inline schema definition"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Dispatcher } from "../native"

export const AltimateCoreColumnLineageTool = Tool.define("altimate_core_column_lineage", {
description:
"Trace schema-aware column lineage using the Rust-based altimate-core engine. Maps how columns flow through a query from source tables to output. Requires altimate_core.init() with API key.",
"Trace schema-aware column lineage. Maps how columns flow through a query from source tables to output. Requires altimate_core.init() with API key. Provide schema_context or schema_path for accurate table/column resolution.",
parameters: z.object({
sql: z.string().describe("SQL query to trace lineage for"),
dialect: z.string().optional().describe("SQL dialect (e.g. snowflake, bigquery)"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Dispatcher } from "../native"

export const AltimateCoreCompareTool = Tool.define("altimate_core_compare", {
description:
"Structurally compare two SQL queries using the Rust-based altimate-core engine. Identifies differences in table references, join conditions, filters, projections, and aggregations.",
"Structurally compare two SQL queries. Identifies differences in table references, join conditions, filters, projections, and aggregations.",
parameters: z.object({
left_sql: z.string().describe("First SQL query"),
right_sql: z.string().describe("Second SQL query"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Dispatcher } from "../native"

export const AltimateCoreCompleteTool = Tool.define("altimate_core_complete", {
description:
"Get cursor-aware SQL completion suggestions using the Rust-based altimate-core engine. Returns table names, column names, functions, and keywords relevant to the cursor position.",
"Get cursor-aware SQL completion suggestions. Returns table names, column names, functions, and keywords relevant to the cursor position. Provide schema_context or schema_path for accurate table/column resolution.",
parameters: z.object({
sql: z.string().describe("Partial SQL query"),
cursor_pos: z.number().describe("Cursor position (0-indexed character offset)"),
Expand All @@ -21,14 +21,15 @@ export const AltimateCoreCompleteTool = Tool.define("altimate_core_complete", {
})
const data = result.data as Record<string, any>
const count = data.items?.length ?? data.suggestions?.length ?? 0
const error = result.error ?? (data as any).error
return {
title: `Complete: ${count} suggestion(s)`,
metadata: { success: result.success, suggestion_count: count },
metadata: { success: result.success, suggestion_count: count, ...(error && { error }) },
output: formatComplete(data),
}
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
return { title: "Complete: ERROR", metadata: { success: false, suggestion_count: 0 }, output: `Failed: ${msg}` }
return { title: "Complete: ERROR", metadata: { success: false, suggestion_count: 0, error: msg }, output: `Failed: ${msg}` }
}
},
})
Expand Down
21 changes: 17 additions & 4 deletions packages/opencode/src/altimate/tools/altimate-core-correct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Dispatcher } from "../native"

export const AltimateCoreCorrectTool = Tool.define("altimate_core_correct", {
description:
"Iteratively correct SQL using a propose-verify-refine loop via the Rust-based altimate-core engine. More thorough than fix — applies multiple correction rounds to produce valid SQL.",
"Iteratively correct SQL using a propose-verify-refine loop. More thorough than fix — applies multiple correction rounds to produce valid SQL. Provide schema_context or schema_path for accurate table/column resolution.",
parameters: z.object({
sql: z.string().describe("SQL query to correct"),
schema_path: z.string().optional().describe("Path to YAML/JSON schema file"),
Expand All @@ -17,19 +17,32 @@ export const AltimateCoreCorrectTool = Tool.define("altimate_core_correct", {
schema_path: args.schema_path ?? "",
schema_context: args.schema_context,
})
const data = result.data as Record<string, any>
const data = (result.data ?? {}) as Record<string, any>
const error = result.error ?? data.error ?? extractCorrectErrors(data)
return {
title: `Correct: ${data.success ? "CORRECTED" : "COULD NOT CORRECT"}`,
metadata: { success: result.success, iterations: data.iterations },
metadata: { success: result.success, iterations: data.iterations, ...(error && { error }) },
output: formatCorrect(data),
}
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
return { title: "Correct: ERROR", metadata: { success: false, iterations: 0 }, output: `Failed: ${msg}` }
return { title: "Correct: ERROR", metadata: { success: false, iterations: 0, error: msg }, output: `Failed: ${msg}` }
}
},
})

function extractCorrectErrors(data: Record<string, any>): string | undefined {
if (data.final_validation?.errors?.length > 0) {
const msgs = data.final_validation.errors.map((e: any) => e.message ?? String(e)).filter(Boolean)
if (msgs.length > 0) return msgs.join("; ")
}
if (Array.isArray(data.errors) && data.errors.length > 0) {
const msgs = data.errors.map((e: any) => e.message ?? String(e)).filter(Boolean)
if (msgs.length > 0) return msgs.join("; ")
}
return undefined
}

function formatCorrect(data: Record<string, any>): string {
if (data.error) return `Error: ${data.error}`
const lines: string[] = []
Expand Down
26 changes: 21 additions & 5 deletions packages/opencode/src/altimate/tools/altimate-core-equivalence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,50 @@ import { Dispatcher } from "../native"

export const AltimateCoreEquivalenceTool = Tool.define("altimate_core_equivalence", {
description:
"Check semantic equivalence of two SQL queries using the Rust-based altimate-core engine. Determines if two queries produce the same result set regardless of syntactic differences.",
"Check semantic equivalence of two SQL queries. Determines if two queries produce the same result set regardless of syntactic differences. Provide schema_context or schema_path for accurate table/column resolution.",
parameters: z.object({
sql1: z.string().describe("First SQL query"),
sql2: z.string().describe("Second SQL query"),
schema_path: z.string().optional().describe("Path to YAML/JSON schema file"),
schema_context: z.record(z.string(), z.any()).optional().describe("Inline schema definition"),
}),
async execute(args, ctx) {
if (!args.schema_path && (!args.schema_context || Object.keys(args.schema_context).length === 0)) {
const error = "No schema provided. Provide schema_context or schema_path so table/column references can be resolved."
return { title: "Equivalence: NO SCHEMA", metadata: { success: false, equivalent: false, error }, output: `Error: ${error}` }
}
try {
const result = await Dispatcher.call("altimate_core.equivalence", {
sql1: args.sql1,
sql2: args.sql2,
schema_path: args.schema_path ?? "",
schema_context: args.schema_context,
})
const data = result.data as Record<string, any>
const data = (result.data ?? {}) as Record<string, any>
const error = result.error ?? data.error ?? extractEquivalenceErrors(data)
// "Not equivalent" is a valid analysis result, not a failure.
// Only treat it as failure when there's an actual error.
const isRealFailure = !!error
return {
title: `Equivalence: ${data.equivalent ? "EQUIVALENT" : "DIFFERENT"}`,
metadata: { success: result.success, equivalent: data.equivalent },
title: isRealFailure ? "Equivalence: ERROR" : `Equivalence: ${data.equivalent ? "EQUIVALENT" : "DIFFERENT"}`,
metadata: { success: !isRealFailure, equivalent: data.equivalent, ...(error && { error }) },
output: formatEquivalence(data),
}
Comment thread
suryaiyer95 marked this conversation as resolved.
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
return { title: "Equivalence: ERROR", metadata: { success: false, equivalent: false }, output: `Failed: ${msg}` }
return { title: "Equivalence: ERROR", metadata: { success: false, equivalent: false, error: msg }, output: `Failed: ${msg}` }
}
},
})

function extractEquivalenceErrors(data: Record<string, any>): string | undefined {
if (Array.isArray(data.validation_errors) && data.validation_errors.length > 0) {
const msgs = data.validation_errors.filter(Boolean)
return msgs.length > 0 ? msgs.join("; ") : undefined
}
return undefined
}

function formatEquivalence(data: Record<string, any>): string {
if (data.error) return `Error: ${data.error}`
const lines: string[] = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Dispatcher } from "../native"

export const AltimateCoreExportDdlTool = Tool.define("altimate_core_export_ddl", {
description:
"Export a YAML/JSON schema as CREATE TABLE DDL statements using the Rust-based altimate-core engine.",
"Export a YAML/JSON schema as CREATE TABLE DDL statements. Provide schema_context or schema_path for accurate table/column resolution.",
parameters: z.object({
schema_path: z.string().optional().describe("Path to YAML/JSON schema file"),
schema_context: z.record(z.string(), z.any()).optional().describe("Inline schema definition"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Dispatcher } from "../native"

export const AltimateCoreExtractMetadataTool = Tool.define("altimate_core_extract_metadata", {
description:
"Extract metadata from SQL using the Rust-based altimate-core engine. Identifies tables, columns, functions, CTEs, and other structural elements referenced in a query.",
"Extract metadata from SQL. Identifies tables, columns, functions, CTEs, and other structural elements referenced in a query.",
parameters: z.object({
sql: z.string().describe("SQL query to extract metadata from"),
dialect: z.string().optional().describe("SQL dialect (e.g. snowflake, bigquery, postgres)"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Dispatcher } from "../native"

export const AltimateCoreFingerprintTool = Tool.define("altimate_core_fingerprint", {
description:
"Compute a SHA-256 fingerprint of a schema using the Rust-based altimate-core engine. Useful for cache invalidation and change detection.",
"Compute a SHA-256 fingerprint of a schema. Useful for cache invalidation and change detection. Provide schema_context or schema_path for accurate table/column resolution.",
parameters: z.object({
schema_path: z.string().optional().describe("Path to YAML/JSON schema file"),
schema_context: z.record(z.string(), z.any()).optional().describe("Inline schema definition"),
Expand Down
28 changes: 23 additions & 5 deletions packages/opencode/src/altimate/tools/altimate-core-fix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Dispatcher } from "../native"

export const AltimateCoreFixTool = Tool.define("altimate_core_fix", {
description:
"Auto-fix SQL errors using the Rust-based altimate-core engine. Uses fuzzy matching and iterative re-validation to correct syntax errors, typos, and schema reference issues.",
"Auto-fix SQL errors using fuzzy matching and iterative re-validation. Corrects syntax errors, typos, and schema reference issues. IMPORTANT: Provide schema_context or schema_path — without schema, table/column references cannot be resolved or fixed.",
parameters: z.object({
sql: z.string().describe("SQL query to fix"),
schema_path: z.string().optional().describe("Path to YAML/JSON schema file"),
Expand All @@ -19,19 +19,37 @@ export const AltimateCoreFixTool = Tool.define("altimate_core_fix", {
schema_context: args.schema_context,
max_iterations: args.max_iterations ?? 5,
})
const data = result.data as Record<string, any>
const data = (result.data ?? {}) as Record<string, any>
const error = result.error ?? data.error ?? extractFixErrors(data)
// post_fix_valid=true with no errors means SQL was already valid (nothing to fix)
const alreadyValid = data.post_fix_valid && !error
const success = result.success || alreadyValid
return {
title: `Fix: ${data.success ? "FIXED" : "COULD NOT FIX"}`,
metadata: { success: result.success, fixed: !!data.fixed_sql },
title: `Fix: ${alreadyValid ? "ALREADY VALID" : data.fixed ? "FIXED" : "COULD NOT FIX"}`,
metadata: { success, fixed: !!data.fixed_sql, ...(error && { error }) },
output: formatFix(data),
}
Comment thread
suryaiyer95 marked this conversation as resolved.
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
return { title: "Fix: ERROR", metadata: { success: false, fixed: false }, output: `Failed: ${msg}` }
return { title: "Fix: ERROR", metadata: { success: false, fixed: false, error: msg }, output: `Failed: ${msg}` }
}
},
})

// Safety net: the native handler (register.ts) also extracts unfixable_errors into
// result.error, but we extract here too in case the handler is updated without setting it.
function extractFixErrors(data: Record<string, any>): string | undefined {
if (Array.isArray(data.unfixable_errors) && data.unfixable_errors.length > 0) {
const msgs = data.unfixable_errors.map((e: any) => e.error?.message ?? e.reason ?? String(e)).filter(Boolean)
if (msgs.length > 0) return msgs.join("; ")
}
if (Array.isArray(data.errors) && data.errors.length > 0) {
const msgs = data.errors.map((e: any) => e.message ?? String(e)).filter(Boolean)
if (msgs.length > 0) return msgs.join("; ")
}
return undefined
}

function formatFix(data: Record<string, any>): string {
if (data.error) return `Error: ${data.error}`
const lines: string[] = []
Expand Down
7 changes: 4 additions & 3 deletions packages/opencode/src/altimate/tools/altimate-core-grade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Dispatcher } from "../native"

export const AltimateCoreGradeTool = Tool.define("altimate_core_grade", {
description:
"Grade SQL quality on an A-F scale using the Rust-based altimate-core engine. Evaluates readability, performance, correctness, and best practices to produce an overall quality grade.",
"Grade SQL quality on an A-F scale. Evaluates readability, performance, correctness, and best practices to produce an overall quality grade. Provide schema_context or schema_path for accurate table/column resolution.",
parameters: z.object({
sql: z.string().describe("SQL query to grade"),
schema_path: z.string().optional().describe("Path to YAML/JSON schema file"),
Expand All @@ -20,14 +20,15 @@ export const AltimateCoreGradeTool = Tool.define("altimate_core_grade", {
const data = result.data as Record<string, any>
const grade = data.overall_grade ?? data.grade
const score = data.scores?.overall != null ? Math.round(data.scores.overall * 100) : data.score
const error = result.error ?? data.error
return {
title: `Grade: ${grade ?? "?"}`,
metadata: { success: result.success, grade, score },
metadata: { success: result.success, grade, score, ...(error && { error }) },
output: formatGrade(data),
}
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
return { title: "Grade: ERROR", metadata: { success: false, grade: null, score: null }, output: `Failed: ${msg}` }
return { title: "Grade: ERROR", metadata: { success: false, grade: null, score: null, error: msg }, output: `Failed: ${msg}` }
}
},
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Dispatcher } from "../native"

export const AltimateCoreImportDdlTool = Tool.define("altimate_core_import_ddl", {
description:
"Convert CREATE TABLE DDL into YAML schema definition using the Rust-based altimate-core engine. Parses DDL statements and produces a structured schema that other altimate-core tools can consume.",
"Convert CREATE TABLE DDL into YAML schema definition. Parses DDL statements and produces a structured schema that other altimate-core tools can consume.",
parameters: z.object({
ddl: z.string().describe("CREATE TABLE DDL statements to parse"),
dialect: z.string().optional().describe("SQL dialect of the DDL"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Dispatcher } from "../native"

export const AltimateCoreMigrationTool = Tool.define("altimate_core_migration", {
description:
"Analyze DDL migration safety using the Rust-based altimate-core engine. Detects potential data loss, type narrowing, missing defaults, and other risks in schema migration statements.",
"Analyze DDL migration safety. Detects potential data loss, type narrowing, missing defaults, and other risks in schema migration statements.",
parameters: z.object({
old_ddl: z.string().describe("Original DDL (before migration)"),
new_ddl: z.string().describe("New DDL (after migration)"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Dispatcher } from "../native"

export const AltimateCoreOptimizeContextTool = Tool.define("altimate_core_optimize_context", {
description:
"Optimize schema for LLM context window using the Rust-based altimate-core engine. Applies 5-level progressive disclosure to reduce schema size while preserving essential information.",
"Optimize schema for LLM context window. Applies 5-level progressive disclosure to reduce schema size while preserving essential information. Provide schema_context or schema_path for accurate table/column resolution.",
parameters: z.object({
schema_path: z.string().optional().describe("Path to YAML/JSON schema file"),
schema_context: z.record(z.string(), z.any()).optional().describe("Inline schema definition"),
Expand Down
Loading
Loading