fix(cli): wait for consistent ACP model choices (#46613)

This commit is contained in:
Kit Langton 2026-09-01 21:35:51 -04:00 committed by GitHub
parent 49f9a60087
commit 95d788f8eb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 41 additions and 1 deletions

View file

@ -412,7 +412,11 @@ async function loadCatalog(client: OpenCodeClient, cwd: string): Promise<Catalog
client.skill.list({ location }),
])
const models = modelResult.data.filter((model) => model.enabled)
const defaultModel = defaultResult.data ?? models[0]
const preferred = defaultResult.data
// Parallel reads can straddle initialization; select only from this model list.
const defaultModel = preferred
? models.find((model) => model.providerID === preferred.providerID && model.id === preferred.id)
: models[0]
const agents = agentResult.data.filter((agent) => agent.mode !== "subagent" && !agent.hidden)
const defaultAgent = agents.find((agent) => agent.mode === "primary") ?? agents[0]
if (defaultModel && defaultAgent) {

View file

@ -1,6 +1,7 @@
import { describe, expect, test } from "bun:test"
import type { McpServer, SessionConfigOption } from "@agentclientprotocol/sdk"
import { makeACPFixture, makeSession, secondModel } from "./service-fixture"
import { flattenSelectOptions, requireSelectOption } from "./subprocess"
describe("acp service directory behavior", () => {
test("creates sessions from a catalog shared by concurrent callers in the same cwd", async () => {
@ -72,6 +73,41 @@ describe("acp service directory behavior", () => {
])
})
test.each(["empty", "missing the default"])(
"retries when the model list is %s but the default is ready",
async (initial) => {
await using fixture = makeACPFixture({
fetch(request, context) {
if (
request.path === "/api/model" &&
context.requests.filter((request) => request.path === "/api/model").length === 1
) {
return Response.json({
location: {
directory: "/workspace",
project: { id: "global", directory: "/workspace", canonical: "/workspace" },
},
data: initial === "empty" ? [] : [secondModel],
})
}
if (request.method === "POST" && request.path === "/api/session") {
return Response.json({ data: makeSession("ses_ready") })
}
return undefined
},
})
const session = await fixture.service.newSession({ cwd: "/workspace", mcpServers: [] })
const model = requireSelectOption(session.configOptions, "model")
const choices = flattenSelectOptions(model).map((option) => option.value)
expect(choices).toContain("test/second-model")
expect(choices).toContain("test/test-model")
expect(model.currentValue).toBe("test/test-model")
expect(fixture.requests.filter((request) => request.path === "/api/model")).toHaveLength(2)
},
)
test("does not cache a failed catalog load", async () => {
let modelCalls = 0
await using fixture = makeACPFixture({