feat: import Chinese-localized Buzz source snapshot
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled

Signed-off-by: cls_宁波本机 <908705107@qq.com>
This commit is contained in:
2026-08-13 18:34:25 +08:00
parent 61c3fa1df9
commit 9dfa06ffee
3785 changed files with 1085458 additions and 2 deletions
@@ -0,0 +1,255 @@
/**
* Screenshot-regression spec for PR #1764: provider/model dropdown fixes.
*
* Three states that previously regressed on fresh OSS installs:
*
* 01 Global agent config provider select renders both Databricks v1 and v2
* options (they are always shown on OSS builds; the mock bridge returns an
* empty baked env, simulating an OSS install with no BUZZ_AGENT_PROVIDER).
*
* 02 Effort dropdown shows "Default (medium)" instead of bare "Inherit" when
* no effort is baked and the provider uses a known default effort level.
* (provider unset → effortDefault = "medium" → inheritFallbackLabel fires)
*
* 03 Edit dialog for a definition with runtime null auto-seeds the app-default
* runtime (buzz-agent) and model discovery runs → model combobox is non-empty.
* Previously, the seeding effect bailed in edit mode, leaving the runtime
* empty and the model dropdown silently blank.
*/
import { expect, test } from "@playwright/test";
import { installMockBridge } from "../helpers/bridge";
import { waitForAnimations } from "../helpers/animations";
const SHOTS = "test-results/screenshots-dialogs";
/**
* 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 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 during the async load effect; wait for it to clear.
await expect(page.locator(".animate-spin").first()).not.toBeVisible({
timeout: 5_000,
});
}
test.describe("agent provider dropdown screenshots", () => {
test.use({ viewport: { width: 1280, height: 900 } });
test.beforeEach(async ({ page }) => {
page.on("pageerror", (err) => {
console.error(
"PAGE ERROR:",
err.message,
err.stack?.split("\n").slice(0, 5).join("\n"),
);
});
});
// Shot 01: OSS provider dropdown includes both Databricks v1 and v2.
//
// The mock bridge returns get_baked_build_env_keys = [] (OSS), so no
// BUZZ_AGENT_PROVIDER is baked and hideProviderIds is empty → v1 appears.
test("01-provider-dropdown-oss", async ({ page }) => {
await installMockBridge(page);
await openAiDefaultsSettings(page);
const providerSelect = page.getByTestId("global-agent-provider");
await expect(providerSelect).toBeVisible({ timeout: 5_000 });
// Regression: both v1 and v2 must be present on OSS. The defaults editor
// renders the app's styled dropdown, so open it and assert option rows.
await providerSelect.click();
await expect(
page.getByTestId("global-agent-provider-option-databricks"),
).toHaveText("Databricks");
await expect(
page.getByTestId("global-agent-provider-option-databricks_v2"),
).toHaveText("Databricks v2");
await page.keyboard.press("Escape");
await expect(
page.getByTestId("global-agent-provider-option-databricks"),
).toHaveCount(0);
await waitForAnimations(page);
// Screenshot the card — provider select is closed but the assertion above
// proves both Databricks options are present in the option list.
await page
.getByTestId("settings-global-agent-config")
.screenshot({ path: `${SHOTS}/01-provider-dropdown-oss.png` });
});
// Shot 02: Effort dropdown shows "Default (medium)" (no baked effort,
// provider=databricks_v2 with no model → effortDefault = "medium").
//
// getProviderEffortConfig("databricks_v2", "") hits the blank-model branch:
// → { defaultValue: "medium" }
// inheritFallbackLabel = "Default (medium)", bakedEffort = null (OSS)
// → the zero-value option reads "Default (medium)" instead of bare "Inherit".
//
// Using databricks_v2 here (rather than no provider) makes this card
// visually distinct from shot 01 — the provider select shows "Databricks v2"
// as the selected value — so the two PNG hashes differ.
test("02-effort-default-label", async ({ page }) => {
await installMockBridge(page, {
globalAgentConfig: {
provider: "databricks_v2",
model: null,
env_vars: {},
},
});
await openAiDefaultsSettings(page);
const effortSelect = page.getByTestId(
"global-agent-thinking-effort-select",
);
await expect(effortSelect).toBeVisible({ timeout: 5_000 });
// Regression: the zero-value option must show the provider's default
// effort rather than a bare "Inherit". The styled dropdown renders the
// zero value as the closed trigger's label (nothing is persisted) and as
// the "empty" option row when opened.
await expect(effortSelect).toHaveText("Default (medium)");
await effortSelect.click();
await expect(
page.getByTestId("global-agent-thinking-effort-select-option-empty"),
).toHaveText("Default (medium)");
await page.keyboard.press("Escape");
await expect(
page.getByTestId("global-agent-thinking-effort-select-option-empty"),
).toHaveCount(0);
await waitForAnimations(page);
await page
.getByTestId("settings-global-agent-config")
.screenshot({ path: `${SHOTS}/02-effort-default-label.png` });
});
// Shot 03: Edit dialog for a definition with null runtime auto-seeds the
// default runtime (buzz-agent via getDefaultPersonaRuntime) and model
// discovery runs, producing a non-empty model combobox.
//
// Previously the seeding effect bailed in edit mode ("id" in initialValues),
// leaving runtime = "" → modelFieldVisible = false → discovery never ran →
// the model dropdown was silently empty.
test("03-builtin-edit-runtime-seeded", async ({ page }) => {
await installMockBridge(page, {
personas: [
{
displayName: "Null Runtime Agent",
systemPrompt: "An agent with no runtime configured.",
// runtime/provider/model not set → all null in the mock, so the
// edit dialog must auto-seed the app default runtime.
},
],
});
await page.goto("/");
await page.getByTestId("open-agents-view").click();
await expect(page.getByTestId("agents-library-personas")).toBeVisible({
timeout: 10_000,
});
// Open the persona's actions menu (visible for non-builtin personas).
const actionsBtn = page.getByRole("button", {
name: "Open actions for Null Runtime Agent",
});
await expect(actionsBtn).toBeVisible({ timeout: 8_000 });
await actionsBtn.click();
await page.getByRole("menuitem", { name: "Edit" }).click();
const dialog = page.getByTestId("persona-dialog");
await expect(dialog).toBeVisible({ timeout: 10_000 });
await dialog.getByRole("tab", { name: "Customize for this agent" }).click();
// Regression: the runtime trigger must not be empty — the auto-seed effect
// must have run and selected the app default (buzz-agent in the mock catalog).
const runtimeTrigger = dialog.locator("#persona-runtime");
await expect(runtimeTrigger).toBeVisible({ timeout: 8_000 });
await expect(runtimeTrigger).not.toContainText("No preference", {
timeout: 8_000,
});
// Regression: the model combobox must appear (modelFieldVisible = true once
// runtime is non-empty) and model discovery must have run, populating it.
const modelCombobox = dialog.getByRole("combobox", { name: /model/i });
await expect(modelCombobox).toBeVisible({ timeout: 8_000 });
// Open the picker and assert that a known model from the mock discovery
// response is listed. The mock returns "Claude Opus 4.6" for all providers
// (see discover_agent_models in e2eBridge.ts). A zero-model discovery
// regression would leave the list empty and this assertion would fail.
// The picker is a searchable command popover portaled outside the dialog
// whose items render as buttons — query at page level.
await modelCombobox.click();
await expect(
page.getByRole("button", { name: /Claude Opus 4\.6/i }),
).toBeVisible({ timeout: 5_000 });
// Close the popover so the screenshot captures the dialog's resting state.
await page.keyboard.press("Escape");
await expect(
page.getByRole("button", { name: /Claude Opus 4\.6/i }),
).toBeHidden();
await waitForAnimations(page);
await dialog.screenshot({
path: `${SHOTS}/03-builtin-edit-runtime-seeded.png`,
});
});
test("04-codex-definition-exposes-model-without-global-provider-defaults", async ({
page,
}) => {
await installMockBridge(page, {
globalAgentConfig: {
provider: "databricks_v2",
model: "global-databricks-model",
env_vars: {},
},
personas: [
{
displayName: "Codex Definition",
systemPrompt: "A Codex-backed definition.",
runtime: "codex",
},
],
});
await page.goto("/");
await page.getByTestId("open-agents-view").click();
await page
.getByRole("button", { name: "Open actions for Codex Definition" })
.click();
await page.getByRole("menuitem", { name: "Edit" }).click();
const dialog = page.getByTestId("persona-dialog");
await expect(dialog).toBeVisible({ timeout: 10_000 });
await expect(
dialog.getByRole("tab", { name: "Customize for this agent" }),
).toBeVisible();
await expect(
dialog.getByText("Harness default", { exact: true }),
).toBeVisible();
await expect(dialog.getByText(/Databricks/i)).toHaveCount(0);
await dialog.getByRole("tab", { name: "Customize for this agent" }).click();
await expect(
dialog.getByRole("combobox", { name: /model/i }),
).toBeVisible();
await expect(dialog.getByText("Model changes apply only")).toHaveCount(0);
});
});