Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
e5af62e
feat: plan agent refinement, feature discovery, and telemetry instrum…
anandgupta42 Mar 29, 2026
57a2e78
fix: address CodeRabbit review comments
anandgupta42 Mar 29, 2026
7384fe2
feat: e2e tests, performance benchmarks, and UX gap fixes
anandgupta42 Mar 29, 2026
1fc5c05
test: plan layer safety e2e tests (68 tests)
anandgupta42 Mar 29, 2026
a5b4e44
merge: resolve conflicts with main (skill followups + sql findings)
anandgupta42 Mar 29, 2026
bc4287b
fix: add mongodb to devDependencies for typecheck resolution
anandgupta42 Mar 29, 2026
77dae71
Merge branch 'main' into feat/plan-agent-and-feature-discovery
anandgupta42 Mar 29, 2026
b24d84e
Merge branch 'main' into feat/plan-agent-and-feature-discovery
anandgupta42 Mar 29, 2026
17f4a19
fix: track suggestion failures in warehouse-add telemetry
anandgupta42 Mar 29, 2026
3b78d42
test: 125 simulated user scenarios for plan + suggestions
anandgupta42 Mar 29, 2026
adb6c7e
test: 40 real tool execution simulations with mocked Dispatcher
anandgupta42 Mar 29, 2026
3f5fcb3
docs: document plan refinement, feature discovery, and new telemetry …
anandgupta42 Mar 29, 2026
24234ff
fix: replace mock.module() with spyOn to prevent cross-file test poll…
anandgupta42 Mar 29, 2026
734d173
fix: reset dedup state in tests + replace passwords with fake values
anandgupta42 Mar 29, 2026
63b1dbd
Merge branch 'main' into feat/plan-agent-and-feature-discovery
anandgupta42 Mar 29, 2026
11bb99d
fix: replace all credential-like test values for GitGuardian
anandgupta42 Mar 29, 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
32 changes: 32 additions & 0 deletions packages/opencode/src/altimate/telemetry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,9 @@ export namespace Telemetry {
skill_name: string
skill_source: "builtin" | "global" | "project"
duration_ms: number
// altimate_change start — skill trigger classification for discovery analytics
trigger: "user_command" | "llm_selected" | "auto_suggested" | "unknown"
// altimate_change end
has_followups: boolean
followup_count: number
}
Expand Down Expand Up @@ -387,6 +390,15 @@ export namespace Telemetry {
source: "cli" | "tui"
}
// altimate_change end
// altimate_change start — plan refinement telemetry event
| {
type: "plan_revision"
timestamp: number
session_id: string
revision_number: number
action: "refine" | "approve" | "reject" | "cap_reached"
}
// altimate_change end
| {
type: "sql_execute_failure"
timestamp: number
Expand All @@ -397,6 +409,16 @@ export namespace Telemetry {
masked_sql: string
duration_ms: number
}
// altimate_change start — feature_suggestion event for post-connect and progressive disclosure tracking
| {
type: "feature_suggestion"
timestamp: number
session_id: string
suggestion_type: "post_warehouse_connect" | "dbt_detected" | "schema_not_indexed" | "progressive_disclosure"
suggestions_shown: string[]
warehouse_type?: string
}
// altimate_change end
| {
type: "core_failure"
timestamp: number
Expand Down Expand Up @@ -591,6 +613,16 @@ export namespace Telemetry {
return "standard"
}

// altimate_change start — classify how a skill was triggered for discovery analytics
export function classifySkillTrigger(extra?: { [key: string]: any }): "user_command" | "llm_selected" | "auto_suggested" | "unknown" {
if (!extra) return "llm_selected"
if (extra.trigger === "user_command") return "user_command"
if (extra.trigger === "auto_suggested") return "auto_suggested"
if (extra.trigger === "llm_selected") return "llm_selected"
return "llm_selected"
}
// altimate_change end

export function bucketCount(n: number): string {
if (n <= 0) return "0"
if (n <= 10) return "1-10"
Expand Down
132 changes: 132 additions & 0 deletions packages/opencode/src/altimate/tools/post-connect-suggestions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/**
* Post-connect feature suggestions and progressive disclosure.
*
* After warehouse connect, users often don't know what to do next.
* This module provides contextual suggestions based on the user's
* environment and progressive next-step hints after tool usage.
*
* Deduplication: progressive suggestions are shown at most once per
* session per tool to avoid repetitive hints.
*/

import { Telemetry } from "../../telemetry"

export namespace PostConnectSuggestions {
export interface SuggestionContext {
warehouseType: string
schemaIndexed: boolean
dbtDetected: boolean
connectionCount: number
toolsUsedInSession: string[]
}

/**
* Set of progressive suggestion keys already shown in this process.
* Reset when the process restarts (per-session lifetime).
*/
const shownProgressiveSuggestions = new Set<string>()

/** Reset shown suggestions (useful for testing). */
export function resetShownSuggestions(): void {
shownProgressiveSuggestions.clear()
}

export function getPostConnectSuggestions(ctx: SuggestionContext): string {
const suggestions: string[] = []

if (!ctx.schemaIndexed) {
suggestions.push(
"Index your schema — enables SQL analysis, column-level lineage, and data quality checks. Use the schema_index tool.",
)
}

suggestions.push(
"Run SQL queries against your " +
ctx.warehouseType +
" warehouse using sql_execute",
)
suggestions.push(
"Analyze SQL quality and find potential issues with sql_analyze",
)

if (ctx.dbtDetected) {
suggestions.push(
"dbt project detected — try /dbt-develop to help build models or /dbt-troubleshoot to debug issues",
)
}

suggestions.push(
"Trace data lineage across your models with lineage_check",
)
suggestions.push("Audit for PII exposure with schema_detect_pii")

if (ctx.connectionCount > 1) {
suggestions.push("Compare data across warehouses with data_diff")
}

return (
"\n\n---\nAvailable capabilities for your " +
ctx.warehouseType +
" warehouse:\n" +
suggestions.map((s, i) => `${i + 1}. ${s}`).join("\n")
)
}

/**
* Progressive disclosure: suggest next tool based on what was just used.
* Returns null if no suggestion applies, tool is unknown, or the
* suggestion was already shown in this session (deduplication).
*/
export function getProgressiveSuggestion(
lastToolUsed: string,
): string | null {
const progression: Record<string, string | null> = {
sql_execute:
"Tip: Use sql_analyze to check this query for potential issues, performance optimizations, and best practices.",
sql_analyze:
"Tip: Use schema_inspect to explore the tables and columns referenced in your query.",
schema_inspect:
"Tip: Use lineage_check to see how this data flows through your models.",
schema_index:
"Schema indexed! You can now use sql_analyze for quality checks, schema_inspect for exploration, and lineage_check for data flow analysis.",
warehouse_add: null, // Handled by post-connect suggestions
}

const suggestion = progression[lastToolUsed] ?? null
if (!suggestion) return null

// Deduplicate: only show each progressive suggestion once per session
if (shownProgressiveSuggestions.has(lastToolUsed)) {
return null
}
shownProgressiveSuggestions.add(lastToolUsed)

return suggestion
}

/**
* Track that feature suggestions were shown, for measuring discovery rates.
*/
export function trackSuggestions(opts: {
suggestionType:
| "post_warehouse_connect"
| "dbt_detected"
| "progressive_disclosure"
suggestionsShown: string[]
warehouseType?: string
}): void {
try {
const sessionId = Telemetry.getContext().sessionId || "unknown-session"
Telemetry.track({
type: "feature_suggestion",
timestamp: Date.now(),
session_id: sessionId,
suggestion_type: opts.suggestionType,
suggestions_shown: opts.suggestionsShown,
warehouse_type: opts.warehouseType ?? "unknown",
})
} catch {
// Telemetry must never break tool execution
}
}
}
17 changes: 17 additions & 0 deletions packages/opencode/src/altimate/tools/project-scan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,23 @@ export const ProjectScanTool = Tool.define("project_scan", {
if (dbtProject.hasPackages) {
lines.push(` ✓ packages.yml or dependencies.yml found`)
}
// altimate_change start — dbt auto-detection skill suggestions
lines.push("")
lines.push(` Recommended skills:`)
lines.push(` - /dbt-develop — Build and modify dbt models with AI assistance`)
lines.push(` - /dbt-troubleshoot — Debug failing dbt models and tests`)
lines.push(` - /dbt-analyze — Analyze dbt project structure and dependencies`)

try {
const { PostConnectSuggestions } = await import("./post-connect-suggestions")
PostConnectSuggestions.trackSuggestions({
suggestionType: "dbt_detected",
suggestionsShown: ["dbt-develop", "dbt-troubleshoot", "dbt-analyze"],
})
} catch {
// Telemetry must never break scan output
}
// altimate_change end
} else {
lines.push("✗ No dbt_project.yml found")
}
Expand Down
17 changes: 16 additions & 1 deletion packages/opencode/src/altimate/tools/schema-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import z from "zod"
import { Tool } from "../../tool/tool"
import { Dispatcher } from "../native"
import type { SchemaIndexResult } from "../native/types"
// altimate_change start — progressive disclosure suggestions
import { PostConnectSuggestions } from "./post-connect-suggestions"
// altimate_change end

export const SchemaIndexTool = Tool.define("schema_index", {
description:
Expand All @@ -15,14 +18,26 @@ export const SchemaIndexTool = Tool.define("schema_index", {
warehouse: args.warehouse,
})

// altimate_change start — progressive disclosure suggestions
let output = formatIndexResult(result)
const suggestion = PostConnectSuggestions.getProgressiveSuggestion("schema_index")
if (suggestion) {
output += "\n\n" + suggestion
PostConnectSuggestions.trackSuggestions({
suggestionType: "progressive_disclosure",
suggestionsShown: ["sql_analyze", "schema_inspect", "lineage_check"],
warehouseType: result.type,
})
}
// altimate_change end
return {
title: `Schema Indexed: ${result.warehouse}`,
metadata: {
schemas: result.schemas_indexed,
tables: result.tables_indexed,
columns: result.columns_indexed,
},
output: formatIndexResult(result),
output,
}
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
Expand Down
17 changes: 16 additions & 1 deletion packages/opencode/src/altimate/tools/schema-inspect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import z from "zod"
import { Tool } from "../../tool/tool"
import { Dispatcher } from "../native"
import type { SchemaInspectResult } from "../native/types"
// altimate_change start — progressive disclosure suggestions
import { PostConnectSuggestions } from "./post-connect-suggestions"
// altimate_change end

export const SchemaInspectTool = Tool.define("schema_inspect", {
description: "Inspect database schema — list columns, types, and constraints for a table.",
Expand All @@ -18,10 +21,22 @@ export const SchemaInspectTool = Tool.define("schema_inspect", {
warehouse: args.warehouse,
})

// altimate_change start — progressive disclosure suggestions
let output = formatSchema(result)
const suggestion = PostConnectSuggestions.getProgressiveSuggestion("schema_inspect")
if (suggestion) {
output += "\n\n" + suggestion
PostConnectSuggestions.trackSuggestions({
suggestionType: "progressive_disclosure",
suggestionsShown: ["lineage_check"],
warehouseType: args.warehouse ?? "unknown",
})
}
// altimate_change end
return {
title: `Schema: ${result.table}`,
metadata: { columnCount: result.columns.length, rowCount: result.row_count },
output: formatSchema(result),
output,
}
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
Expand Down
18 changes: 17 additions & 1 deletion packages/opencode/src/altimate/tools/sql-analyze.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { Tool } from "../../tool/tool"
import { Dispatcher } from "../native"
import type { Telemetry } from "../telemetry"
import type { SqlAnalyzeResult } from "../native/types"
// altimate_change start — progressive disclosure suggestions
import { PostConnectSuggestions } from "./post-connect-suggestions"
// altimate_change end

export const SqlAnalyzeTool = Tool.define("sql_analyze", {
description:
Expand Down Expand Up @@ -39,6 +42,19 @@ export const SqlAnalyzeTool = Tool.define("sql_analyze", {
category: issue.rule ?? issue.type,
}))
// altimate_change end

// altimate_change start — progressive disclosure suggestions
let output = formatAnalysis(result)
const suggestion = PostConnectSuggestions.getProgressiveSuggestion("sql_analyze")
if (suggestion) {
output += "\n\n" + suggestion
PostConnectSuggestions.trackSuggestions({
suggestionType: "progressive_disclosure",
suggestionsShown: ["schema_inspect"],
warehouseType: "unknown",
})
}
// altimate_change end
return {
title: `Analyze: ${result.error ? "ERROR" : `${result.issue_count} issue${result.issue_count !== 1 ? "s" : ""}`} [${result.confidence}]`,
metadata: {
Expand All @@ -50,7 +66,7 @@ export const SqlAnalyzeTool = Tool.define("sql_analyze", {
...(result.error && { error: result.error }),
...(findings.length > 0 && { findings }),
},
output: formatAnalysis(result),
output,
}
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
Expand Down
16 changes: 15 additions & 1 deletion packages/opencode/src/altimate/tools/sql-execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import type { SqlExecuteResult } from "../native/types"
// altimate_change start - SQL write access control
import { classifyAndCheck } from "./sql-classify"
// altimate_change end
// altimate_change start — progressive disclosure suggestions
import { PostConnectSuggestions } from "./post-connect-suggestions"
// altimate_change end

export const SqlExecuteTool = Tool.define("sql_execute", {
description: "Execute SQL against a connected data warehouse. Returns results as a formatted table.",
Expand Down Expand Up @@ -37,7 +40,18 @@ export const SqlExecuteTool = Tool.define("sql_execute", {
limit: args.limit,
})

const output = formatResult(result)
let output = formatResult(result)
// altimate_change start — progressive disclosure suggestions
const suggestion = PostConnectSuggestions.getProgressiveSuggestion("sql_execute")
if (suggestion) {
output += "\n\n" + suggestion
PostConnectSuggestions.trackSuggestions({
suggestionType: "progressive_disclosure",
suggestionsShown: ["sql_analyze"],
warehouseType: args.warehouse ?? "default",
})
}
// altimate_change end
return {
title: `SQL: ${args.query.slice(0, 60)}${args.query.length > 60 ? "..." : ""}`,
metadata: { rowCount: result.row_count, truncated: result.truncated },
Expand Down
Loading
Loading