fix(ui): gate New Session catalogs on agent roster (#125339)

This commit is contained in:
Peter Steinberger
2026-08-17 09:34:40 -07:00
committed by GitHub
parent 1298adfca7
commit 25e54ef255
5 changed files with 67 additions and 12 deletions
@@ -62,6 +62,61 @@ function cliAgentCatalog(startTerminal: boolean) {
}
suite.define(() => {
it("waits for the current roster before loading the CLI catalog", async () => {
const context = await suite.browser.newContext({
locale: "en-US",
serviceWorkers: "block",
});
const page = await context.newPage();
const gateway = await installMockGateway(page, {
assistantAgentId: "roboclaw",
assistantName: "Roboclaw",
cliAgentsEnabled: true,
defaultAgentId: "roboclaw",
deferredMethods: ["agents.list"],
featureMethods: [...TERMINAL_START_FEATURE_METHODS],
methodResponses: {
"sessions.catalog.list": { catalogs: [cliAgentCatalog(false)] },
},
});
try {
await page.goto(`${suite.server.baseUrl}new`);
await gateway.waitForRequest("agents.list");
await page.locator(".new-session-page__message").waitFor({ state: "visible" });
expect(
(await gateway.getRequests("sessions.catalog.list"))
.filter((request) => requestHasParam(request, "limitPerHost", 1))
.map((request) => request.params),
).toEqual([]);
await gateway.resolveDeferred("agents.list");
await page.getByRole("heading", { name: "Roboclaw" }).waitFor();
await expect
.poll(async () =>
(await gateway.getRequests("sessions.catalog.list")).filter((request) =>
requestHasParam(request, "limitPerHost", 1),
),
)
.toHaveLength(1);
const catalogRequest = (await gateway.getRequests("sessions.catalog.list")).find((request) =>
requestHasParam(request, "limitPerHost", 1),
);
expect(catalogRequest?.params).toEqual({
agentId: "roboclaw",
limitPerHost: 1,
});
await page.locator('[data-chat-model-select="true"]').click();
const cliGroup = page.locator('[data-chat-model-target-group="cliAgents"]');
await expect.poll(() => cliGroup.isVisible()).toBe(true);
await pollLocatorText(cliGroup).toContain("Claude Code");
} finally {
await context.close();
}
});
it("routes a Labs-enabled CLI agent picker row through catalog-target mode", async () => {
if (captureCliAgentsProof) {
await mkdir(cliAgentsProofDir, { recursive: true });
+2 -2
View File
@@ -155,12 +155,12 @@ export function resolveAgentId(
): string {
const rawRequested = data?.agentId?.trim();
if (!rawRequested) {
return normalizeAgentId(fallback);
return fallback && normalizeAgentId(fallback);
}
const requested = normalizeAgentId(rawRequested);
return availableAgents.some((candidate) => normalizeAgentId(candidate.id) === requested)
? requested
: normalizeAgentId(fallback);
: fallback && normalizeAgentId(fallback);
}
export function allowsSelectedAgent(
@@ -245,15 +245,15 @@ export class DraftPlaceState {
const agents = this.agents();
const configuredDefault = snapshot.context?.agents.state.agentsList?.defaultId;
const fallback = agents.some((agent) => agent.id === configuredDefault)
? (configuredDefault ?? "main")
: (agents[0]?.id ?? "main");
? (configuredDefault ?? "")
: (agents[0]?.id ?? "");
const keepSelectedAgent =
options.preserveSelectedAgent && this.agentSelectedByUser && Boolean(this.selectedAgent());
if (!keepSelectedAgent) {
this.agentIdValue = catalog.resolveAgentId(snapshot.data, agents, fallback);
this.agentSelectedByUser = false;
}
const preference = this.gateway.readPreference(this.agentIdValue);
const preference = this.agentIdValue ? this.gateway.readPreference(this.agentIdValue) : null;
const keepSelectedFolder = options.preserveSelectedFolder && this.folderSelectedByUser;
if (!this.execNodeValue && !keepSelectedFolder && !snapshot.pendingCloudSessionKey) {
const workspace = this.workspacePath();
+2 -2
View File
@@ -164,7 +164,7 @@ export class NewSessionModelControl {
loadCatalogTargets(context: ApplicationContext | undefined, agentId: string, enabled: boolean) {
const snapshot = context?.gateway.snapshot;
const client = snapshot?.client;
const normalizedAgentId = normalizeAgentId(agentId);
const normalizedAgentId = agentId.trim() ? normalizeAgentId(agentId) : "";
if (
!enabled ||
snapshot?.phase !== "connected" ||
@@ -339,7 +339,7 @@ export class NewSessionModelControl {
) {
const snapshot = context?.gateway.snapshot;
const client = snapshot?.client;
const normalizedAgentId = normalizeAgentId(agentId);
const normalizedAgentId = agentId.trim() ? normalizeAgentId(agentId) : "";
if (this.agentId !== normalizedAgentId) {
// Catalog availability belongs to an agent. A real owner change clears
// the snapshot; same-agent refreshes retain it until replacement.
+5 -5
View File
@@ -245,11 +245,6 @@ class NewSessionPage extends OpenClawLightDomElement {
}
this.gateway.retryPendingCatalogTarget();
void this.context?.agentIdentity.ensure(this.place.agents().map((agent) => agent.id));
this.place.modelControl.loadCatalogTargets(
this.context,
this.place.agentId,
this.context?.config.current.cliAgentsEnabled === true && !catalog.isTarget(this.data),
);
const agentState = this.context?.agents.state;
const agentsReady = Boolean(
this.gateway.connected &&
@@ -258,6 +253,11 @@ class NewSessionPage extends OpenClawLightDomElement {
agentState.client === this.gateway.client &&
this.place.agents().length > 0,
);
this.place.modelControl.loadCatalogTargets(
this.context,
agentsReady && this.place.agentId ? (this.place.selectedAgent()?.id ?? "") : "",
this.context?.config.current.cliAgentsEnabled === true && !catalog.isTarget(this.data),
);
const openKey = this.data
? catalog.routeKey(this.data)
: catalog.routeKeyFromSearch(window.location.search);