diff --git a/desktop/src-tauri/src/commands/agent_models_databricks_tests.rs b/desktop/src-tauri/src/commands/agent_models_databricks_tests.rs index d1725df9d3..80657168b1 100644 --- a/desktop/src-tauri/src/commands/agent_models_databricks_tests.rs +++ b/desktop/src-tauri/src/commands/agent_models_databricks_tests.rs @@ -145,7 +145,11 @@ async fn databricks_storage_failure_shows_its_message_without_opening_a_browser( assert_eq!(launched.load(Ordering::SeqCst), sign_ins, "{failure:?}"); assert_eq!( - error.contains("could not securely save the Databricks token cache"), + // The `llm credential storage: ` prefix is what the draft-dialog + // formatter (personaModelDiscoveryStatus.ts) matches on. + error.contains( + "llm credential storage: could not securely save the Databricks token cache" + ), failure == AuthError::CacheUnavailable, "{error}" ); diff --git a/desktop/src/features/agents/ui/personaModelDiscoveryStatus.test.mjs b/desktop/src/features/agents/ui/personaModelDiscoveryStatus.test.mjs index dfa086738f..52bd4d1e2d 100644 --- a/desktop/src/features/agents/ui/personaModelDiscoveryStatus.test.mjs +++ b/desktop/src/features/agents/ui/personaModelDiscoveryStatus.test.mjs @@ -106,6 +106,30 @@ test("Databricks sign-in timeout warns and points at the explicit retry", () => assert.match(status?.message ?? "", /buzz-agent auth databricks/); }); +// Real shapes from agent_models_databricks.rs when a token cannot be saved +// privately: a refresh during discovery, and a completed browser sign-in. +for (const [surface, prefix] of [ + ["discovery refresh", "Databricks model discovery failed"], + ["browser sign-in", "Databricks sign-in failed"], +]) { + test(`Databricks token-storage failure on ${surface} shows the storage remedy, not sign-in advice`, () => { + const status = formatModelDiscoveryErrorStatus( + `${prefix}: llm credential storage: could not securely save the Databricks token cache; use a writable cache location with owner-only file permissions (Windows FAT/exFAT volumes are not supported)`, + "databricks_v2", + ); + + assert.equal(status?.tone, "warning"); + assert.equal( + status?.message, + "Could not securely save the Databricks token cache; use a writable cache location with owner-only file permissions (Windows FAT/exFAT volumes are not supported).", + ); + assert.doesNotMatch( + status?.message ?? "", + /didn't complete|model picker|built-in model options/, + ); + }); +} + test("other Databricks discovery failures fall through to the generic notice", () => { const status = formatModelDiscoveryErrorStatus( new Error("Databricks model discovery failed: relay offline"), diff --git a/desktop/src/features/agents/ui/personaModelDiscoveryStatus.ts b/desktop/src/features/agents/ui/personaModelDiscoveryStatus.ts index 0d89526425..0104edcbb7 100644 --- a/desktop/src/features/agents/ui/personaModelDiscoveryStatus.ts +++ b/desktop/src/features/agents/ui/personaModelDiscoveryStatus.ts @@ -142,6 +142,9 @@ export function formatModelDiscoveryErrorStatus( }; } +/** Display prefix of `AgentError::LlmCredentialStorage` (buzz-agent `types.rs`). */ +const CREDENTIAL_STORAGE_MARKER = "llm credential storage: "; + /** * Maps the terminal Databricks sign-in states to user-facing guidance, or null * when the error is not a Databricks sign-in outcome. "Sign-in required" is a @@ -152,6 +155,20 @@ export function formatModelDiscoveryErrorStatus( function formatDatabricksAuthStatus( message: string, ): PersonaModelDiscoveryStatus | null { + // A token that could not be saved privately (`AgentError::LlmCredentialStorage`). + // Checked first: it also arrives wrapped as "Databricks sign-in failed", and + // another sign-in cannot repair the cache, so show the backend's remedy. + const storageAt = message.indexOf(CREDENTIAL_STORAGE_MARKER); + if (storageAt !== -1) { + const detail = message + .slice(storageAt + CREDENTIAL_STORAGE_MARKER.length) + .trim(); + return { + message: `${detail.charAt(0).toUpperCase()}${detail.slice(1)}.`, + tone: "warning", + }; + } + if (message.includes("Databricks sign-in is required")) { return { message: