diff --git a/.changeset/calm-agents-wait.md b/.changeset/calm-agents-wait.md new file mode 100644 index 00000000000..e745549cb83 --- /dev/null +++ b/.changeset/calm-agents-wait.md @@ -0,0 +1,5 @@ +--- +"@kilocode/cli": patch +--- + +Preserve the selected session agent when sending headless prompts without an explicit agent. diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 0007b11b75d..86660b977e6 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -816,7 +816,7 @@ export const layer = Layer.effect( }) const createUserMessage = Effect.fn("SessionPrompt.createUserMessage")(function* (input: PromptInput) { - const agentName = input.agent + const agentName = input.agent ?? (yield* sessions.get(input.sessionID).pipe(Effect.orDie)).agent // kilocode_change const ag = agentName ? yield* agents.get(agentName) : yield* agents.defaultInfo() if (!ag) { const available = (yield* agents.list()).filter((a) => !a.hidden).map((a) => a.name) diff --git a/packages/opencode/test/kilocode/headless-session-agent.test.ts b/packages/opencode/test/kilocode/headless-session-agent.test.ts new file mode 100644 index 00000000000..f06db730924 --- /dev/null +++ b/packages/opencode/test/kilocode/headless-session-agent.test.ts @@ -0,0 +1,73 @@ +import { afterEach, expect, test } from "bun:test" +import { Server } from "../../src/server/server" +import { disposeAllInstances, provideTestInstance, tmpdir } from "../fixture/fixture" +import { resetDatabase } from "../fixture/db" + +afterEach(async () => { + await disposeAllInstances() + await resetDatabase() +}) + +test("headless prompts preserve the agent selected when the session was created", async () => { + await using tmp = await tmpdir({ + config: { + formatter: false, + lsp: false, + agent: { + "test-engineer": { + mode: "primary", + model: "mock/custom-model", + }, + }, + provider: { + mock: { + npm: "@ai-sdk/openai-compatible", + name: "Mock", + options: { baseURL: "http://127.0.0.1:1/v1", apiKey: "test" }, + models: { + "custom-model": { + name: "Custom Model", + limit: { context: 128000, output: 8192 }, + }, + }, + }, + }, + }, + }) + + await provideTestInstance({ + directory: tmp.path, + fn: async () => { + const app = Server.Default().app + const headers = { "content-type": "application/json", "x-kilo-directory": tmp.path } + const created = await app.request("/session", { + method: "POST", + headers, + body: JSON.stringify({ agent: "test-engineer" }), + }) + expect(created.status).toBe(200) + const session = (await created.json()) as { id: string; agent?: string } + expect(session.agent).toBe("test-engineer") + + const prompted = await app.request(`/session/${session.id}/message`, { + method: "POST", + headers, + body: JSON.stringify({ + noReply: true, + parts: [{ type: "text", text: "hello" }], + }), + }) + expect(prompted.status).toBe(200) + const message = (await prompted.json()) as { + info: { agent: string; model: { providerID: string; modelID: string } } + } + expect(message.info.agent).toBe("test-engineer") + expect(message.info.model).toEqual({ providerID: "mock", modelID: "custom-model" }) + + const loaded = await app.request(`/session/${session.id}`, { headers }) + expect(loaded.status).toBe(200) + const current = (await loaded.json()) as { agent?: string } + expect(current.agent).toBe("test-engineer") + }, + }) +})