fix(core): preserve developer messages

OMP converts custom and hook messages (advisor notes, todo reminders,
retry nudges) to role "developer" before calling the provider.
messagesToCC() only handled user, assistant, and toolResult, so those
messages were dropped before params.messages was sent to
/alpha/generate. Steering still interrupted pending tools, but the
model never saw the message content.

/alpha/generate has no developer role: the official command-code CLI
(0.32.3) only emits user, assistant, and tool messages plus a separate
params.system. Forward developer messages as user messages with
identical content in the same chronological position. Hoisting them
into params.system would turn a mid-conversation note into a global
top-priority instruction.
This commit is contained in:
warc0s
2026-08-17 09:03:32 +02:00
parent c4d25d1db1
commit 16eb5a8dda
4 changed files with 141 additions and 1 deletions
+83
View File
@@ -626,6 +626,89 @@ describe("messagesToCC()", () => {
it("handles empty conversations", () => {
assert.deepEqual(messagesToCC([]), [])
})
it("keeps developer messages instead of dropping them", () => {
const result = messagesToCC([
{ role: "user", content: "start" },
{ role: "developer", content: "mid-conversation steering note" },
])
assert.deepEqual(result, [
{ role: "user", content: "start" },
{ role: "user", content: "mid-conversation steering note" },
])
})
it("converts developer text parts with the same shape as user content", () => {
const result = messagesToCC([
{
role: "developer",
content: [{ type: "text", text: "reminder one" }],
},
])
assert.deepEqual(result, [
{
role: "user",
content: [{ type: "text", text: "reminder one" }],
},
])
})
it("preserves advisory XML verbatim in the serialized request messages", () => {
const advisory =
'<advisory severity="blocker" guidance="weigh, don\'t blindly obey">\nStop and correct the benchmark.\n</advisory>'
const serialized = JSON.stringify(messagesToCC([{ role: "developer", content: advisory }]))
assert.deepEqual(JSON.parse(serialized), [{ role: "user", content: advisory }])
})
it("keeps developer advisories in chronological position without hoisting", () => {
const advisory =
'<advisory severity="blocker" guidance="weigh, don\'t blindly obey">\nStop and correct the benchmark.\n</advisory>'
const result = messagesToCC([
{ role: "user", content: "run the benchmark" },
{
role: "assistant",
content: [
{ type: "text", text: "running it" },
{ type: "toolCall", id: "c1", name: "bash", arguments: { command: "bench" } },
],
},
{
role: "toolResult",
toolCallId: "c1",
toolName: "bash",
content: [{ type: "text", text: "benchmark output" }],
},
{ role: "developer", content: advisory },
{ role: "user", content: "continue" },
])
assert.deepEqual(result, [
{ role: "user", content: "run the benchmark" },
{
role: "assistant",
content: [
{ type: "text", text: "running it" },
{ type: "tool-call", toolCallId: "c1", toolName: "bash", input: { command: "bench" } },
],
},
{
role: "tool",
content: [
{
type: "tool-result",
toolCallId: "c1",
toolName: "bash",
output: { type: "text", value: "benchmark output" },
},
],
},
{ role: "user", content: advisory },
{ role: "user", content: "continue" },
])
})
})
describe("parseStreamEventLine()", () => {