diff --git a/packages/opencode/src/altimate/fingerprint/index.ts b/packages/opencode/src/altimate/fingerprint/index.ts index fcbb9911fc..8241a96af2 100644 --- a/packages/opencode/src/altimate/fingerprint/index.ts +++ b/packages/opencode/src/altimate/fingerprint/index.ts @@ -6,6 +6,12 @@ import path from "path" const log = Log.create({ service: "fingerprint" }) +/** Canonical list of warehouse adapter identifiers, shared with system prompt builder. */ +export const ADAPTER_TAGS = [ + "snowflake", "bigquery", "redshift", "databricks", "postgres", + "mysql", "sqlite", "duckdb", "trino", "spark", "clickhouse", +] as const + export namespace Fingerprint { export interface Result { tags: string[] @@ -102,7 +108,7 @@ export namespace Fingerprint { try { const content = await Filesystem.readText(path.join(dir, "profiles.yml")) const adapterMatch = content.match( - /type:\s*(snowflake|bigquery|redshift|databricks|postgres|mysql|sqlite|duckdb|trino|spark|clickhouse)/i, + new RegExp(`type:\\s*(${ADAPTER_TAGS.join("|")})`, "i"), ) if (adapterMatch) { tags.push(adapterMatch[1]!.toLowerCase()) diff --git a/packages/opencode/src/session/system.ts b/packages/opencode/src/session/system.ts index 6e1e4c45e3..120e3ea29b 100644 --- a/packages/opencode/src/session/system.ts +++ b/packages/opencode/src/session/system.ts @@ -14,7 +14,7 @@ import type { Agent } from "@/agent/agent" import { PermissionNext } from "@/permission/next" import { Skill } from "@/skill" // altimate_change start - import for env-based skill selection -import { Fingerprint } from "../altimate/fingerprint" +import { Fingerprint, ADAPTER_TAGS } from "../altimate/fingerprint" import { Config } from "../config/config" import { selectSkillsWithLLM } from "../altimate/skill-selector" // altimate_change end @@ -36,7 +36,7 @@ export namespace SystemPrompt { export async function environment(model: Provider.Model) { const project = Instance.project - return [ + const parts: string[] = [ [ `You are powered by the model named ${model.api.id}. The exact model ID is ${model.providerID}/${model.api.id}`, `Here is some useful information about the environment you are running in:`, @@ -59,6 +59,42 @@ export namespace SystemPrompt { ``, ].join("\n"), ] + + // altimate_change start - inject project context to guide connection discovery + try { + // detect() caches per-cwd, so calling it directly is both correct and cheap + const fingerprint = await Fingerprint.detect(Instance.directory, Instance.worktree) + if (fingerprint.tags.length > 0) { + const isDbt = fingerprint.tags.includes("dbt") + const detectedAdapter = fingerprint.tags.find(t => (ADAPTER_TAGS as readonly string[]).includes(t)) + + parts.push( + [ + ``, + ` Detected project tags: ${fingerprint.tags.join(", ")}`, + ...(isDbt ? [ + ``, + ` This workspace contains a dbt project. When executing SQL queries:`, + ` 1. Attempt to use the dbt connection first (configured via profiles.yml${detectedAdapter ? `, adapter: ${detectedAdapter}` : ""}).`, + ` 2. If the dbt connection is unavailable or fails, fall back to a configured warehouse connection.`, + ` 3. If neither works, ask the user for the credentials needed to connect${detectedAdapter ? ` to ${detectedAdapter}` : ""}.`, + ` Do not assume the dbt connection will always succeed — be prepared to ask for credentials.`, + ] : [ + ``, + ` No dbt project detected. When SQL execution is needed:`, + ` 1. Check if a warehouse connection is already configured.`, + ` 2. If not, ask the user for the connection credentials appropriate to this project${detectedAdapter ? ` (detected: ${detectedAdapter})` : ""}.`, + ]), + ``, + ].join("\n"), + ) + } + } catch { + // fingerprint detection is best-effort — never block session startup + } + // altimate_change end + + return parts } export async function skills(agent: Agent.Info) {