fix(cli): send max-step instruction as user message

Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
This commit is contained in:
chrarnoldus
2026-08-21 07:30:33 +00:00
parent fe760ab024
commit 43c4491560
5 changed files with 44 additions and 3 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@kilocode/cli": patch
---
Prevent provider errors when agents reach their step limit by sending the final summary instruction as user input instead of an assistant prefill.
+1 -1
View File
@@ -209,7 +209,7 @@ const layer = Layer.effect(
system: [agent.info?.system, system.baseline]
.filter((part): part is string => part !== undefined && part.length > 0)
.map(SystemPart.make),
messages: [...toLLMMessages(context, model), ...(isLastStep ? [Message.assistant(MAX_STEPS_PROMPT)] : [])],
messages: [...toLLMMessages(context, model), ...(isLastStep ? [Message.user(MAX_STEPS_PROMPT)] : [])], // kilocode_change - avoid provider-incompatible assistant prefill
tools: toolMaterialization?.definitions ?? [],
toolChoice: isLastStep ? "none" : undefined,
})
+1 -1
View File
@@ -3022,7 +3022,7 @@ describe("SessionRunnerLLM", () => {
expect(requests[1]?.toolChoice).toMatchObject({ type: "none" })
expect(requests[1]?.tools).toEqual([])
expect(requests[1]?.messages.at(-1)).toMatchObject({
role: "assistant",
role: "user", // kilocode_change - max-step instructions must not become assistant prefill
content: [{ type: "text", text: expect.stringContaining("MAXIMUM STEPS REACHED") }],
})
expect(executions).toEqual(["done"])
+1 -1
View File
@@ -1772,7 +1772,7 @@ export const layer = Layer.effect(
system,
messages: [
...modelMsgs,
...(isLastStep ? [{ role: "assistant" as const, content: MAX_STEPS_PROMPT }] : []),
...(isLastStep ? [{ role: "user" as const, content: MAX_STEPS_PROMPT }] : []), // kilocode_change - avoid provider-incompatible assistant prefill
],
tools,
model,
@@ -550,6 +550,42 @@ it.instance("loop calls LLM and returns assistant message", () =>
}),
)
// kilocode_change start - guard provider-compatible max-step request shape
it.instance(
"loop sends max steps instruction as a user message",
() =>
Effect.gen(function* () {
const { llm } = yield* useServerConfig((url) => ({
...providerCfg(url),
agent: { build: { steps: 1 } },
}))
const prompt = yield* SessionPrompt.Service
const sessions = yield* Session.Service
const chat = yield* sessions.create({ title: "Pinned" })
yield* prompt.prompt({
sessionID: chat.id,
agent: "build",
noReply: true,
parts: [{ type: "text", text: "finish at the limit" }],
})
yield* llm.text("summary")
yield* prompt.loop({ sessionID: chat.id })
const inputs = yield* llm.inputs
const messages = inputs.at(-1)?.messages
if (!Array.isArray(messages)) throw new Error("expected LLM messages")
expect(messages.at(-1)).toMatchObject({
role: "user",
content: expect.arrayContaining([
{ type: "text", text: expect.stringContaining("MAXIMUM STEPS REACHED") },
]),
})
}),
30_000,
)
// kilocode_change end
noLLMServer.instance(
"new prompt dismisses a pending question",
() =>