Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
855 changes: 417 additions & 438 deletions packages/opencode/src/altimate/native/altimate-core.ts

Large diffs are not rendered by default.

819 changes: 428 additions & 391 deletions packages/opencode/src/altimate/native/sql/register.ts

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions packages/opencode/src/altimate/native/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ export interface SqlExecuteResult {
export interface SqlAnalyzeParams {
sql: string
dialect?: string
schema_path?: string
schema_context?: Record<string, any>
}

export interface SqlAnalyzeIssue {
type: string
rule?: string
severity: string
message: string
recommendation: string
Expand Down Expand Up @@ -385,6 +387,7 @@ export interface SqlFixResult {
error_message: string
suggestions: SqlFixSuggestion[]
suggestion_count: number
error?: string
}

// --- SQL Autocomplete ---
Expand Down
84 changes: 64 additions & 20 deletions packages/opencode/src/altimate/telemetry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ export namespace Telemetry {
// No nested objects: Azure App Insights custom measures must be top-level numbers.
tokens_input: number
tokens_output: number
tokens_reasoning?: number // only for reasoning models
tokens_cache_read?: number // only when a cached prompt was reused
tokens_reasoning?: number // only for reasoning models
tokens_cache_read?: number // only when a cached prompt was reused
tokens_cache_write?: number // only when a new cache entry was written
}
| {
Expand Down Expand Up @@ -401,19 +401,27 @@ export namespace Telemetry {
session_id: string
tool_name: string
tool_category: string
error_class:
| "parse_error"
| "connection"
| "timeout"
| "validation"
| "internal"
| "permission"
| "unknown"
error_class: "parse_error" | "connection" | "timeout" | "validation" | "internal" | "permission" | "unknown"
error_message: string
input_signature: string
masked_args?: string
duration_ms: number
}
// altimate_change start — sql quality telemetry for issue prevention metrics
| {
type: "sql_quality"
timestamp: number
session_id: string
tool_name: string
tool_category: string
finding_count: number
/** JSON-encoded Record<string, number> — count per issue category */
by_category: string
has_schema: boolean
dialect?: string
duration_ms: number
}
// altimate_change end

const ERROR_PATTERNS: Array<{
class: Telemetry.Event & { type: "core_failure" } extends { error_class: infer C } ? C : never
Expand Down Expand Up @@ -476,20 +484,40 @@ export namespace Telemetry {

// Mirrors altimate-sdk (Rust) SENSITIVE_KEYS — keep in sync.
const SENSITIVE_KEYS: string[] = [
"key", "api_key", "apikey", "apiKey", "token", "access_token", "refresh_token",
"secret", "secret_key", "password", "passwd", "pwd",
"credential", "credentials", "authorization", "auth",
"signature", "sig", "private_key", "connection_string",
"key",
"api_key",
"apikey",
"apiKey",
"token",
"access_token",
"refresh_token",
"secret",
"secret_key",
"password",
"passwd",
"pwd",
"credential",
"credentials",
"authorization",
"auth",
"signature",
"sig",
"private_key",
"connection_string",
// camelCase variants not caught by prefix/suffix matching
"authtoken", "accesstoken", "refreshtoken", "bearertoken", "jwttoken",
"jwtsecret", "clientsecret", "appsecret",
"authtoken",
"accesstoken",
"refreshtoken",
"bearertoken",
"jwttoken",
"jwtsecret",
"clientsecret",
"appsecret",
]

function isSensitiveKey(key: string): boolean {
const lower = key.toLowerCase()
return SENSITIVE_KEYS.some(
(k) => lower === k || lower.endsWith(`_${k}`) || lower.startsWith(`${k}_`),
)
return SENSITIVE_KEYS.some((k) => lower === k || lower.endsWith(`_${k}`) || lower.startsWith(`${k}_`))
}

export function maskString(s: string): string {
Expand Down Expand Up @@ -674,7 +702,7 @@ export namespace Telemetry {
// before Instance.provide()). Treat config failures as "not disabled" —
// the env var check above is the early-init escape hatch.
try {
const userConfig = await Config.get() as any
const userConfig = (await Config.get()) as any
if (userConfig.telemetry?.disabled) {
buffer = []
return
Expand Down Expand Up @@ -789,6 +817,22 @@ export namespace Telemetry {
}
}

// altimate_change start — sql quality telemetry types
/** Lightweight finding record for quality telemetry. Only category — never SQL content. */
export interface Finding {
category: string
}

/** Aggregate an array of findings into category counts suitable for the sql_quality event. */
export function aggregateFindings(findings: Finding[]): Record<string, number> {
const by_category: Record<string, number> = {}
for (const f of findings) {
by_category[f.category] = (by_category[f.category] ?? 0) + 1
}
return by_category
}
// altimate_change end

export async function shutdown() {
// Wait for init to complete so we know whether telemetry is enabled
// and have a valid endpoint to flush to. init() is fire-and-forget
Expand Down
35 changes: 31 additions & 4 deletions packages/opencode/src/altimate/tools/altimate-core-check.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,58 @@
import z from "zod"
import { Tool } from "../../tool/tool"
import { Dispatcher } from "../native"
import type { Telemetry } from "../telemetry"

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"),
schema_context: z.record(z.string(), z.any()).optional().describe("Inline schema definition"),
}),
async execute(args, ctx) {
const hasSchema = !!(args.schema_path || (args.schema_context && Object.keys(args.schema_context).length > 0))
try {
const result = await Dispatcher.call("altimate_core.check", {
sql: args.sql,
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
// altimate_change start — sql quality findings for telemetry
const findings: Telemetry.Finding[] = []
for (const err of data.validation?.errors ?? []) {
findings.push({ category: "validation_error" })
}
for (const f of data.lint?.findings ?? []) {
findings.push({ category: f.rule ?? "lint" })
}
for (const t of data.safety?.threats ?? []) {
findings.push({ category: t.type ?? "safety_threat" })
}
for (const p of data.pii?.findings ?? []) {
findings.push({ category: "pii_detected" })
}
// altimate_change end
return {
title: `Check: ${formatCheckTitle(data)}`,
metadata: { success: result.success },
metadata: {
success: result.success,
has_schema: hasSchema,
...(error && { error }),
...(findings.length > 0 && { findings }),
},
output: formatCheck(data),
}
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
return { title: "Check: ERROR", metadata: { success: false }, output: `Failed: ${msg}` }
return {
title: "Check: ERROR",
metadata: { success: false, has_schema: hasSchema, 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 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 All @@ -15,17 +15,22 @@ export const AltimateCoreClassifyPiiTool = Tool.define("altimate_core_classify_p
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 piiColumns = data.columns ?? data.findings ?? []
const findingCount = piiColumns.length
const error = result.error ?? data.error
return {
title: `PII Classification: ${findingCount} finding(s)`,
metadata: { success: result.success, finding_count: findingCount },
metadata: { success: result.success, finding_count: findingCount, ...(error && { error }) },
output: formatClassifyPii(data),
}
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
return { title: "PII Classification: ERROR", metadata: { success: false, finding_count: 0 }, output: `Failed: ${msg}` }
return {
title: "PII Classification: ERROR",
metadata: { success: false, finding_count: 0, 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 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 All @@ -19,16 +19,21 @@ export const AltimateCoreColumnLineageTool = Tool.define("altimate_core_column_l
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 edgeCount = data.column_lineage?.length ?? 0
const error = result.error ?? data.error
return {
title: `Column Lineage: ${edgeCount} edge(s)`,
metadata: { success: result.success, edge_count: edgeCount },
metadata: { success: result.success, edge_count: edgeCount, ...(error && { error }) },
output: formatColumnLineage(data),
}
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
return { title: "Column Lineage: ERROR", metadata: { success: false, edge_count: 0 }, output: `Failed: ${msg}` }
return {
title: "Column Lineage: ERROR",
metadata: { success: false, edge_count: 0, error: msg },
output: `Failed: ${msg}`,
}
}
},
})
Expand Down
13 changes: 9 additions & 4 deletions packages/opencode/src/altimate/tools/altimate-core-compare.ts
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 All @@ -17,16 +17,21 @@ export const AltimateCoreCompareTool = Tool.define("altimate_core_compare", {
right_sql: args.right_sql,
dialect: args.dialect ?? "",
})
const data = result.data as Record<string, any>
const data = (result.data ?? {}) as Record<string, any>
const diffCount = data.differences?.length ?? 0
const error = result.error ?? data.error
return {
title: `Compare: ${diffCount === 0 ? "IDENTICAL" : `${diffCount} difference(s)`}`,
metadata: { success: result.success, difference_count: diffCount },
metadata: { success: result.success, difference_count: diffCount, ...(error && { error }) },
output: formatCompare(data),
}
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
return { title: "Compare: ERROR", metadata: { success: false, difference_count: 0 }, output: `Failed: ${msg}` }
return {
title: "Compare: ERROR",
metadata: { success: false, difference_count: 0, error: msg },
output: `Failed: ${msg}`,
}
}
},
})
Expand Down
13 changes: 9 additions & 4 deletions packages/opencode/src/altimate/tools/altimate-core-complete.ts
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 @@ -19,16 +19,21 @@ export const AltimateCoreCompleteTool = Tool.define("altimate_core_complete", {
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 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
Loading
Loading