diff --git a/desktop/src/features/agents/ui/AgentAiDefaults.tsx b/desktop/src/features/agents/ui/AgentAiDefaults.tsx
new file mode 100644
index 0000000000..694841d5ed
--- /dev/null
+++ b/desktop/src/features/agents/ui/AgentAiDefaults.tsx
@@ -0,0 +1,104 @@
+import { useAppNavigation } from "@/app/navigation/useAppNavigation";
+import type { InheritedDefault } from "./bakedEnvHelpers";
+import { getPersonaProviderOptions } from "./personaDialogPickers";
+import { Button } from "@/shared/ui/button";
+
+function providerLabel(providerId: string) {
+ const option = getPersonaProviderOptions("", "buzz-agent").find(
+ (candidate) => candidate.id === providerId,
+ );
+ return option?.label ?? providerId;
+}
+
+export function formatAiDefaultsSummary({
+ provider,
+ model,
+}: {
+ provider: InheritedDefault;
+ model: InheritedDefault;
+}) {
+ const parts = [
+ provider.value ? providerLabel(provider.value) : null,
+ model.value || null,
+ ].filter((value): value is string => Boolean(value));
+
+ return parts.length > 0 ? parts.join(" · ") : "Not configured";
+}
+
+export function AgentAiDefaultsNotice({
+ confirmNavigation = false,
+ explicitModel,
+ explicitProvider,
+ inheritedModel,
+ inheritedProvider,
+}: {
+ confirmNavigation?: boolean;
+ explicitModel: string;
+ explicitProvider: string;
+ inheritedModel: InheritedDefault;
+ inheritedProvider: InheritedDefault;
+}) {
+ const { goSettings } = useAppNavigation();
+ const inheritsProvider = explicitProvider.trim().length === 0;
+ const inheritsModel = explicitModel.trim().length === 0;
+
+ const usesCustomConfig = !inheritsProvider && !inheritsModel;
+ const requiredProviderMissing = inheritsProvider && !inheritedProvider.value;
+
+ const inheritedParts = [
+ inheritsProvider
+ ? inheritedProvider.value
+ ? `Provider ${providerLabel(inheritedProvider.value)}`
+ : "Provider not configured"
+ : null,
+ inheritsModel
+ ? inheritedModel.value
+ ? `Model ${inheritedModel.value}`
+ : "Model not configured"
+ : null,
+ ].filter((value): value is string => Boolean(value));
+
+ return (
+
+
+
+ {usesCustomConfig
+ ? "Custom AI configuration"
+ : requiredProviderMissing
+ ? "AI defaults aren’t configured"
+ : inheritsProvider && inheritsModel
+ ? "Uses AI defaults"
+ : "Partially uses AI defaults"}
+
+
+ {usesCustomConfig
+ ? "This agent won’t follow provider or model default changes."
+ : requiredProviderMissing
+ ? "Choose a provider in AI defaults to use this agent."
+ : `${inheritedParts.join(" · ")}. Inherited fields follow future changes.`}
+
+
+
{
+ if (
+ confirmNavigation &&
+ !window.confirm(
+ "Leave this agent without saving? Your changes will be discarded.",
+ )
+ ) {
+ return;
+ }
+ void goSettings("agents");
+ }}
+ size="xs"
+ type="button"
+ variant="link"
+ >
+ Edit AI defaults
+
+
+ );
+}
diff --git a/desktop/src/features/agents/ui/AgentDefinitionDialog.tsx b/desktop/src/features/agents/ui/AgentDefinitionDialog.tsx
index 526fa19c8d..2e0582e07d 100644
--- a/desktop/src/features/agents/ui/AgentDefinitionDialog.tsx
+++ b/desktop/src/features/agents/ui/AgentDefinitionDialog.tsx
@@ -74,6 +74,7 @@ import {
getBakedProviderInheritLabel,
} from "./bakedEnvHelpers";
import { useAgentDialogDefaults } from "./useAgentDialogDefaults";
+import { AgentAiDefaultsNotice } from "./AgentAiDefaults";
import { useProviderApiKeyFieldState } from "./providerApiKeyFieldState";
import { buildRuntimeModelProviderPayload } from "./agentDefinitionSubmitPayload";
@@ -864,6 +865,14 @@ export function AgentDefinitionDialog({
) : null}
+
+
{isCreateMode ? createRunSection : null}
diff --git a/desktop/src/features/agents/ui/AgentInstanceEditDialog.tsx b/desktop/src/features/agents/ui/AgentInstanceEditDialog.tsx
index 43d58b2131..7100c59b93 100644
--- a/desktop/src/features/agents/ui/AgentInstanceEditDialog.tsx
+++ b/desktop/src/features/agents/ui/AgentInstanceEditDialog.tsx
@@ -78,6 +78,7 @@ import {
} from "./bakedEnvHelpers";
import { getProviderApiKeyEnvVar } from "./personaDialogPickers";
import { useAgentDialogDefaults } from "./useAgentDialogDefaults";
+import { AgentAiDefaultsNotice } from "./AgentAiDefaults";
import { useProviderApiKeyFieldState } from "./providerApiKeyFieldState";
const ADVANCED_FIELDS_MOTION_TRANSITION = {
@@ -1087,6 +1088,14 @@ export function AgentInstanceEditDialog({
+
+
{/* Advanced settings */}
(null);
@@ -95,9 +104,11 @@ export function AgentsView() {
title="Agents"
/>
-
-
{
+ void goSettings("agents");
+ }}
actionErrorMessage={agents.actionErrorMessage}
actionNoticeMessage={agents.actionNoticeMessage}
agents={agents.managedAgents}
diff --git a/desktop/src/features/agents/ui/UnifiedAgentsSection.tsx b/desktop/src/features/agents/ui/UnifiedAgentsSection.tsx
index deadf90661..7d708ee8b9 100644
--- a/desktop/src/features/agents/ui/UnifiedAgentsSection.tsx
+++ b/desktop/src/features/agents/ui/UnifiedAgentsSection.tsx
@@ -32,6 +32,7 @@ import { PersonaActionsMenu } from "./PersonaActionsMenu";
import { buildUnifiedGroups, pickProfileAgent } from "./unifiedAgentGroups";
type UnifiedAgentsSectionProps = {
+ aiDefaultsSummary: string;
actionErrorMessage: string | null;
actionNoticeMessage: string | null;
agents: ManagedAgent[];
@@ -41,6 +42,7 @@ type UnifiedAgentsSectionProps = {
startingAgentPubkey: string | null;
startingPersonaIds: ReadonlySet;
onBulkStopRunning: () => void;
+ onEditAiDefaults: () => void;
onOpenAgentProfile: (
pubkey: string,
options?: ProfilePanelOpenOptions,
@@ -74,6 +76,7 @@ const AGENT_CARD_GRID_CLASS = `${AGENT_CARD_COLUMN_CLASS} grid grid-cols-[repeat
export function UnifiedAgentsSection(props: UnifiedAgentsSectionProps) {
const {
actionErrorMessage,
+ aiDefaultsSummary,
actionNoticeMessage,
agents,
agentsError,
@@ -82,6 +85,7 @@ export function UnifiedAgentsSection(props: UnifiedAgentsSectionProps) {
startingAgentPubkey,
startingPersonaIds,
onBulkStopRunning,
+ onEditAiDefaults,
onOpenAgentProfile,
onOpenPersonaProfile,
onStartAgent,
@@ -160,11 +164,13 @@ export function UnifiedAgentsSection(props: UnifiedAgentsSectionProps) {
{isLoading ? : null}
@@ -437,18 +443,22 @@ function firstAvatarUrl(
function AgentsListHeader({
agentCount,
+ aiDefaultsSummary,
fileInputRef,
handleFileChange,
isActionPending,
runningCount,
onBulkStopRunning,
+ onEditAiDefaults,
}: {
agentCount: number;
+ aiDefaultsSummary: string;
fileInputRef: React.RefObject;
handleFileChange: (e: React.ChangeEvent) => void;
isActionPending: boolean;
runningCount: number;
onBulkStopRunning: () => void;
+ onEditAiDefaults: () => void;
}) {
return (
@@ -461,7 +471,22 @@ function AgentsListHeader({
/>
+ Agents in this community.
+
+ AI defaults: {aiDefaultsSummary}
+
+ Edit defaults
+
+
+ >
+ }
action={
agentCount > 0 ? (
diff --git a/desktop/src/features/agents/ui/bakedEnvHelpers.ts b/desktop/src/features/agents/ui/bakedEnvHelpers.ts
index 23f9dd015f..1463c2aed8 100644
--- a/desktop/src/features/agents/ui/bakedEnvHelpers.ts
+++ b/desktop/src/features/agents/ui/bakedEnvHelpers.ts
@@ -96,7 +96,7 @@ export function getAdvancedInheritedSummary(
...(effort.value ? [`effort ${effort.value}`] : []),
...(globalEnvLabel ? [globalEnvLabel] : []),
];
- return `Using global defaults: ${parts.join(" · ")}`;
+ return `Using AI defaults: ${parts.join(" · ")}`;
}
export function getInheritedAgentDefaults(
diff --git a/desktop/src/features/agents/ui/createAgentLocalModeGate.test.mjs b/desktop/src/features/agents/ui/createAgentLocalModeGate.test.mjs
index e5b6883316..a4f536652e 100644
--- a/desktop/src/features/agents/ui/createAgentLocalModeGate.test.mjs
+++ b/desktop/src/features/agents/ui/createAgentLocalModeGate.test.mjs
@@ -840,8 +840,8 @@ test("providerDefaultLabel_globalSet_returnsInheritLabel", () => {
const label = getDefaultLlmProviderLabel("buzz-agent", "anthropic");
assert.equal(
label,
- "Inherit global default (anthropic)",
- "global provider set must return 'Inherit global default ()'",
+ "Use AI defaults (anthropic)",
+ "global provider set must return 'Use AI defaults ()'",
);
});
@@ -850,7 +850,7 @@ test("providerDefaultLabel_globalSetWithWhitespace_trimsAndReturnsInherit", () =
const label = getDefaultLlmProviderLabel("buzz-agent", " openai ");
assert.equal(
label,
- "Inherit global default (openai)",
+ "Use AI defaults (openai)",
"global provider with surrounding whitespace must be trimmed in label",
);
});
@@ -858,7 +858,7 @@ test("providerDefaultLabel_globalSetWithWhitespace_trimsAndReturnsInherit", () =
test("providerDefaultLabel_sharedCompute_neverLeaksInternalId", () => {
assert.equal(
getDefaultLlmProviderLabel("buzz-agent", "relay-mesh"),
- "Inherit global default (Buzz shared compute)",
+ "Use AI defaults (Buzz shared compute)",
);
});
@@ -972,8 +972,8 @@ test("modelDefaultLabel_globalSet_returnsInheritLabel", () => {
const label = getDefaultLlmModelLabel("claude-opus-4-5");
assert.equal(
label,
- "Inherit global default (claude-opus-4-5)",
- "global model set must return 'Inherit global default ()'",
+ "Use AI defaults (claude-opus-4-5)",
+ "global model set must return 'Use AI defaults ()'",
);
});
@@ -982,7 +982,7 @@ test("modelDefaultLabel_globalSetWithWhitespace_trimsAndReturnsInherit", () => {
const label = getDefaultLlmModelLabel(" gpt-4o ");
assert.equal(
label,
- "Inherit global default (gpt-4o)",
+ "Use AI defaults (gpt-4o)",
"global model with surrounding whitespace must be trimmed in label",
);
});
@@ -1131,11 +1131,11 @@ test("f3_templateDialog_localProviderBlankGlobalAnthropicNoModel_saveBlocked", (
test("f3_templateDialog_globalModelSet_zeroValueLabelIsInherit", () => {
// Case 3: global model set → the zero-value model dropdown option must show
- // "Inherit global default ()" not the generic "Default model".
+ // "Use AI defaults ()" not the generic "Default model".
// getDefaultLlmModelLabel is what AgentDefinitionDialog now uses for that slot.
assert.equal(
getDefaultLlmModelLabel("claude-opus-4-5"),
- "Inherit global default (claude-opus-4-5)",
+ "Use AI defaults (claude-opus-4-5)",
"zero-value model option label must show the global model name when set",
);
assert.equal(
@@ -1175,7 +1175,7 @@ test("f3b_buildTemplateModelDropdownOptions_anthropicGlobalModelSet_containsInhe
);
assert.equal(
inheritEntry.label,
- "Inherit global default (claude-opus-4-5)",
+ "Use AI defaults (claude-opus-4-5)",
"inherit entry must carry the global model name",
);
});
@@ -1215,7 +1215,7 @@ test("f3b_buildTemplateModelDropdownOptions_blankProviderGlobalModelSet_noDouble
);
assert.equal(
autoEntries[0].label,
- "Inherit global default (claude-opus-4-5)",
+ "Use AI defaults (claude-opus-4-5)",
"existing zero-value entry must be relabeled with the global model name",
);
});
diff --git a/desktop/src/features/agents/ui/personaDialogPickers.tsx b/desktop/src/features/agents/ui/personaDialogPickers.tsx
index 1f4447d426..34d5f19598 100644
--- a/desktop/src/features/agents/ui/personaDialogPickers.tsx
+++ b/desktop/src/features/agents/ui/personaDialogPickers.tsx
@@ -271,21 +271,19 @@ export function getDefaultLlmProviderLabel(
) {
const trimmedGlobal = (globalProvider ?? "").trim();
return trimmedGlobal
- ? `Inherit global default (${providerDisplayLabel(trimmedGlobal)})`
+ ? `Use AI defaults (${providerDisplayLabel(trimmedGlobal)})`
: "Select a provider\u2026";
}
/** Returns the zero-value model option label.
*
* When a global model is configured, the empty-model option reads
- * `Inherit global default ()` so users can see which model will run.
+ * `Use AI defaults ()` so users can see which model will run.
* Otherwise falls back to the generic `"Default model"` placeholder.
*/
export function getDefaultLlmModelLabel(globalModel?: string) {
const trimmedGlobal = (globalModel ?? "").trim();
- return trimmedGlobal
- ? `Inherit global default (${trimmedGlobal})`
- : "Default model";
+ return trimmedGlobal ? `Use AI defaults (${trimmedGlobal})` : "Default model";
}
/**
@@ -294,7 +292,7 @@ export function getDefaultLlmModelLabel(globalModel?: string) {
*
* Explicit-model providers (e.g. anthropic) have their zero-value option
* filtered out by `getPersonaModelOptions`, so a relabel-only map would never
- * produce the `Inherit global default ()` entry. This helper prepends
+ * produce the `Use AI defaults ()` entry. This helper prepends
* it when `globalModel` is non-empty AND no zero-value option already exists,
* making the inherited global model visible and selectable in the dropdown.
*
diff --git a/desktop/src/features/agents/ui/personaRuntimeModel.test.mjs b/desktop/src/features/agents/ui/personaRuntimeModel.test.mjs
index e0916020be..a17881cb51 100644
--- a/desktop/src/features/agents/ui/personaRuntimeModel.test.mjs
+++ b/desktop/src/features/agents/ui/personaRuntimeModel.test.mjs
@@ -118,12 +118,12 @@ test("resolveInheritedRuntimeSubmission preserves a user-edited provider + env w
assert.equal(result.model, null);
});
-test("resolveInheritedRuntimeSubmission clears an already-inheriting agent's provider override when the user picks Default", () => {
- // Regression: an already-inheriting agent had a saved provider override
- // (databricks). The user picks the "Default" option → empty local provider.
- // Because the agent was NOT harness-pinned at open, this is a deliberate
- // clear, not the inherit-transition — persist null (runtime default), do NOT
- // resurrect the persona provider.
+test("resolveInheritedRuntimeSubmission clears an already-inheriting agent's persona-backed provider and model to AI defaults", () => {
+ // Regression: an already-inheriting agent is linked to a persona with a
+ // provider and model. The user picks "Use AI defaults" for both fields.
+ // Because the agent was NOT harness-pinned at open, these empty local values
+ // are deliberate clears, not an inherit-transition — persist null for both
+ // rather than resurrecting the persona values.
const result = resolveInheritedRuntimeSubmission({
inheritHarness: true,
agentWasHarnessPinned: false,
@@ -135,6 +135,7 @@ test("resolveInheritedRuntimeSubmission clears an already-inheriting agent's pro
personaEnvVars: { ANTHROPIC_API_KEY: "sk-persona" },
});
assert.equal(result.provider, null);
+ assert.equal(result.model, null);
assert.deepEqual(result.envVars, {});
});
diff --git a/desktop/src/features/settings/ui/GlobalAgentConfigSettingsCard.tsx b/desktop/src/features/settings/ui/GlobalAgentConfigSettingsCard.tsx
index d6285500da..5f1e82db27 100644
--- a/desktop/src/features/settings/ui/GlobalAgentConfigSettingsCard.tsx
+++ b/desktop/src/features/settings/ui/GlobalAgentConfigSettingsCard.tsx
@@ -138,8 +138,8 @@ export function GlobalAgentConfigSettingsCard() {
data-testid="settings-global-agent-config"
>
{isLoading ? (
diff --git a/desktop/src/features/settings/ui/SettingsPanels.tsx b/desktop/src/features/settings/ui/SettingsPanels.tsx
index 3ec811c859..0abd4ddda2 100644
--- a/desktop/src/features/settings/ui/SettingsPanels.tsx
+++ b/desktop/src/features/settings/ui/SettingsPanels.tsx
@@ -63,6 +63,7 @@ import { MobilePairingCard } from "./MobilePairingCard";
import { ModerationQueueCard } from "./ModerationQueueCard";
import { NotificationSettingsCard } from "./NotificationSettingsCard";
import { PreventSleepSettingsCard } from "./PreventSleepSettingsCard";
+import { GlobalAgentConfigSettingsCard } from "./GlobalAgentConfigSettingsCard";
import { ProfileSettingsCard } from "./ProfileSettingsCard";
import { UpdateChecker } from "../UpdateChecker";
import { SettingsSectionHeader } from "./SettingsSectionHeader";
@@ -712,7 +713,12 @@ export function renderSettingsSection(
case "experimental":
return ;
case "agents":
- return ;
+ return (
+
+ );
case "channel-templates":
return ;
case "compute":
diff --git a/desktop/tests/e2e/agent-lifecycle-feedback.spec.ts b/desktop/tests/e2e/agent-lifecycle-feedback.spec.ts
index 0c665619e6..0a3ec16f75 100644
--- a/desktop/tests/e2e/agent-lifecycle-feedback.spec.ts
+++ b/desktop/tests/e2e/agent-lifecycle-feedback.spec.ts
@@ -26,16 +26,25 @@ const CASCADE_AGENT_A_PUBKEY = "aa".repeat(32);
const CASCADE_AGENT_B_PUBKEY = "bb".repeat(32);
/**
- * Navigate to the Agents view and wait for the global agent config card to
- * finish loading (spinner gone). The card lives at the bottom of the view.
+ * Navigate to the Agents view and wait for its unified list to mount.
*/
async function openAgentsView(page: import("@playwright/test").Page) {
await page.goto("/");
await page.getByTestId("open-agents-view").click();
+ await expect(page.getByTestId("unified-agents-groups")).toBeVisible({
+ timeout: 10_000,
+ });
+}
+
+async function openAiDefaultsSettings(page: import("@playwright/test").Page) {
+ await page.goto("/", { waitUntil: "domcontentloaded" });
+ await page.getByTestId("open-settings").click();
+ await page.getByTestId("profile-popover-settings").click();
+ await expect(page.getByTestId("settings-view")).toBeVisible();
+ await page.getByTestId("settings-nav-agents").click();
await expect(page.getByTestId("settings-global-agent-config")).toBeVisible({
timeout: 10_000,
});
- // Spinner disappears once the load effect resolves.
await expect(page.locator(".animate-spin").first()).not.toBeVisible({
timeout: 5_000,
});
@@ -120,7 +129,7 @@ test.describe("agent lifecycle feedback screenshots", () => {
globalConfigRestartedCount: 2,
});
- await openAgentsView(page);
+ await openAiDefaultsSettings(page);
const card = page.getByTestId("settings-global-agent-config");
@@ -150,7 +159,7 @@ test.describe("agent lifecycle feedback screenshots", () => {
test("03-save-plain", async ({ page }) => {
await installMockBridge(page);
- await openAgentsView(page);
+ await openAiDefaultsSettings(page);
const card = page.getByTestId("settings-global-agent-config");
@@ -264,7 +273,7 @@ test.describe("agent lifecycle feedback screenshots", () => {
globalConfigRestartedCount: 1,
});
- await openAgentsView(page);
+ await openAiDefaultsSettings(page);
const card = page.getByTestId("settings-global-agent-config");
@@ -287,7 +296,7 @@ test.describe("agent lifecycle feedback screenshots", () => {
globalConfigFailedRestartCount: 1,
});
- await openAgentsView(page);
+ await openAiDefaultsSettings(page);
const card = page.getByTestId("settings-global-agent-config");
@@ -319,7 +328,7 @@ test.describe("agent lifecycle feedback screenshots", () => {
globalConfigSaveDelayMs: 2_000,
});
- await openAgentsView(page);
+ await openAiDefaultsSettings(page);
const card = page.getByTestId("settings-global-agent-config");
const provider = page.locator("#global-agent-provider");
diff --git a/desktop/tests/e2e/agent-provider-dropdowns.spec.ts b/desktop/tests/e2e/agent-provider-dropdowns.spec.ts
index 68cc6b8d9e..09fde8b8f9 100644
--- a/desktop/tests/e2e/agent-provider-dropdowns.spec.ts
+++ b/desktop/tests/e2e/agent-provider-dropdowns.spec.ts
@@ -24,12 +24,16 @@ import { waitForAnimations } from "../helpers/animations";
const SHOTS = "test-results/screenshots-dialogs";
/**
- * Navigate to the agents view and wait for the global agent config card to
- * finish its async load (spinner gone, card content visible).
+ * Open Settings → Agents through the app UI and wait for the defaults card to
+ * finish loading. The CI static server does not provide SPA fallbacks for a
+ * direct `/settings` request.
*/
-async function openAgentsView(page: import("@playwright/test").Page) {
- await page.goto("/");
- await page.getByTestId("open-agents-view").click();
+async function openAiDefaultsSettings(page: import("@playwright/test").Page) {
+ await page.goto("/", { waitUntil: "domcontentloaded" });
+ await page.getByTestId("open-settings").click();
+ await page.getByTestId("profile-popover-settings").click();
+ await expect(page.getByTestId("settings-view")).toBeVisible();
+ await page.getByTestId("settings-nav-agents").click();
await expect(page.getByTestId("settings-global-agent-config")).toBeVisible({
timeout: 10_000,
});
@@ -58,7 +62,7 @@ test.describe("agent provider dropdown screenshots", () => {
// BUZZ_AGENT_PROVIDER is baked and hideProviderIds is empty → v1 appears.
test("01-provider-dropdown-oss", async ({ page }) => {
await installMockBridge(page);
- await openAgentsView(page);
+ await openAiDefaultsSettings(page);
const providerSelect = page.locator("#global-agent-provider");
await expect(providerSelect).toBeVisible({ timeout: 5_000 });
@@ -98,7 +102,7 @@ test.describe("agent provider dropdown screenshots", () => {
env_vars: {},
},
});
- await openAgentsView(page);
+ await openAiDefaultsSettings(page);
const effortSelect = page.locator("#global-agent-thinking-effort");
await expect(effortSelect).toBeVisible({ timeout: 5_000 });
diff --git a/desktop/tests/e2e/edit-agent.spec.ts b/desktop/tests/e2e/edit-agent.spec.ts
index ee5c99a7d8..216edea7f3 100644
--- a/desktop/tests/e2e/edit-agent.spec.ts
+++ b/desktop/tests/e2e/edit-agent.spec.ts
@@ -202,14 +202,12 @@ test.describe("edit agent dialog", () => {
await openEditDialog(page);
await expect(page.locator("#edit-agent-llm-provider")).toHaveText(
- "Inherit global default (anthropic)",
+ "Use AI defaults (anthropic)",
);
await expect(page.locator("#edit-agent-model")).toHaveText(
- "Inherit global default (claude-opus-4-5)",
+ "Use AI defaults (claude-opus-4-5)",
);
- await expect(
- page.getByText("Using global defaults: effort low"),
- ).toBeVisible();
+ await expect(page.getByText("Using AI defaults: effort low")).toBeVisible();
});
test("profile Edit routes persona-linked agents to the definition editor", async ({
diff --git a/desktop/tests/e2e/global-agent-config-screenshots.spec.ts b/desktop/tests/e2e/global-agent-config-screenshots.spec.ts
index 3d05479a94..85b15aa7a8 100644
--- a/desktop/tests/e2e/global-agent-config-screenshots.spec.ts
+++ b/desktop/tests/e2e/global-agent-config-screenshots.spec.ts
@@ -12,17 +12,19 @@ async function settleAnimations(page: import("@playwright/test").Page) {
}
/**
- * Navigate to the Agents view (where GlobalAgentConfigSettingsCard lives) and
- * wait for the card to finish loading.
+ * Open Settings → Agents through the app UI and wait for the defaults card to
+ * load. CI serves the built SPA with a static file server, so navigating to
+ * `/settings` directly returns a 404 before the client router can start.
*/
-async function openAgentsView(page: import("@playwright/test").Page) {
- await page.goto("/");
- await page.getByTestId("open-agents-view").click();
- // Wait for the global agent config card to mount and finish its load effect.
+async function openAiDefaultsSettings(page: import("@playwright/test").Page) {
+ await page.goto("/", { waitUntil: "domcontentloaded" });
+ await page.getByTestId("open-settings").click();
+ await page.getByTestId("profile-popover-settings").click();
+ await expect(page.getByTestId("settings-view")).toBeVisible();
+ await page.getByTestId("settings-nav-agents").click();
await expect(page.getByTestId("settings-global-agent-config")).toBeVisible({
timeout: 10_000,
});
- // The card shows a spinner while loading; wait for it to disappear.
await expect(page.locator(".animate-spin").first()).not.toBeVisible({
timeout: 5_000,
});
@@ -65,7 +67,7 @@ test.describe("global agent config screenshots", () => {
},
});
- await openAgentsView(page);
+ await openAiDefaultsSettings(page);
const card = page.getByTestId("settings-global-agent-config");
await card.scrollIntoViewIfNeeded();
@@ -187,14 +189,12 @@ test.describe("global agent config screenshots", () => {
await openCreateDialog(page);
await expect(page.locator("#persona-llm-provider")).toHaveText(
- "Inherit global default (anthropic)",
+ "Use AI defaults (anthropic)",
);
await expect(page.locator("#persona-model")).toHaveText(
- "Inherit global default (claude-opus-4-5)",
+ "Use AI defaults (claude-opus-4-5)",
);
- await expect(
- page.getByText("Using global defaults: effort low"),
- ).toBeVisible();
+ await expect(page.getByText("Using AI defaults: effort low")).toBeVisible();
});
// Shot 04: Create gate BLOCKED — no per-agent provider, no global provider