diff --git a/desktop/src/features/agents/ui/AgentAiConfigurationMode.tsx b/desktop/src/features/agents/ui/AgentAiConfigurationMode.tsx
index 6750649021..a7ae1876b7 100644
--- a/desktop/src/features/agents/ui/AgentAiConfigurationMode.tsx
+++ b/desktop/src/features/agents/ui/AgentAiConfigurationMode.tsx
@@ -6,6 +6,16 @@ import type { InheritedDefault } from "./bakedEnvHelpers";
export type { AgentAiConfigurationMode } from "./agentAiConfigurationPolicy";
+/**
+ * Motion shared by the sliding pill and the labels it slides under. Both halves
+ * must use it: a bare `transition-colors` falls back to Tailwind's 150ms
+ * default, so the label finishes recoloring ~100ms before the 250ms pill
+ * arrives beneath it, and on a different curve.
+ */
+const TAB_MOTION = "duration-[250ms] ease-out motion-reduce:transition-none";
+
+const TAB_TRIGGER_CLASS = `relative z-10 h-full rounded-md bg-transparent text-xs font-medium shadow-none transition-colors ${TAB_MOTION} data-[state=active]:bg-transparent data-[state=active]:shadow-none`;
+
export function HarnessModelDefaultNotice({
harness,
model,
@@ -86,24 +96,18 @@ export function AgentAiConfigurationModeField({
-
+
{needsProviderSelection
? "Use agent defaults"
: "Use harness defaults"}
-
+
Customize for this agent
diff --git a/desktop/src/features/agents/ui/AgentDefinitionDialog.tsx b/desktop/src/features/agents/ui/AgentDefinitionDialog.tsx
index 29cb48c643..4a094b1d36 100644
--- a/desktop/src/features/agents/ui/AgentDefinitionDialog.tsx
+++ b/desktop/src/features/agents/ui/AgentDefinitionDialog.tsx
@@ -834,7 +834,10 @@ export function AgentDefinitionDialog({
) : null}
{aiConfigurationMode === "custom" ? (
diff --git a/desktop/src/features/huddle/components/HuddleBar.tsx b/desktop/src/features/huddle/components/HuddleBar.tsx
index 35d660e475..321d70610d 100644
--- a/desktop/src/features/huddle/components/HuddleBar.tsx
+++ b/desktop/src/features/huddle/components/HuddleBar.tsx
@@ -493,21 +493,29 @@ export function HuddleBar({
async function handleLeave() {
if (isLeaving) return;
const leavingChannelId = barState?.ephemeral_channel_id ?? null;
+ // Snapshot for rollback: leaving is only optimistic if a failed teardown can
+ // put the bar back exactly as it was.
+ const previousState = state;
stateGenerationRef.current += 1;
locallyLeavingChannelRef.current = leavingChannelId;
setIsLeaving(true);
+ // Close the drawer now rather than after teardown. leaveHuddle() stops the
+ // worklet, stops the mic track, and round-trips Rust `leave_huddle`; waiting
+ // on all three reads as an unresponsive click. `locallyLeavingChannelRef`
+ // already suppresses in-flight "still active" states for this channel, so
+ // nothing reopens the drawer behind us.
+ setState(null);
try {
- const backendClean = await leaveHuddle();
- if (backendClean) {
- setState(null);
- } else {
+ // If cleanup failed, restore the bar so the user can retry.
+ if (!(await leaveHuddle())) {
locallyLeavingChannelRef.current = null;
stateGenerationRef.current += 1;
+ setState(previousState);
}
- // If cleanup failed, keep the bar visible so the user can retry.
} catch (e) {
locallyLeavingChannelRef.current = null;
stateGenerationRef.current += 1;
+ setState(previousState);
console.error("Failed to leave huddle:", e);
} finally {
setIsLeaving(false);