mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
fix(kiro): merge adjacent user history turns after role normalization (#2105)
Merged automatically
This commit is contained in:
@@ -288,7 +288,50 @@ function convertMessages(messages, tools, model) {
|
||||
}
|
||||
});
|
||||
|
||||
return { history, currentMessage };
|
||||
// Kiro expects history to alternate between user and assistant turns. After
|
||||
// normalizing `system`/`tool` roles into `userInputMessage`, the history can
|
||||
// contain adjacent user turns, which Kiro can reject. Merge consecutive
|
||||
// `userInputMessage` entries by concatenating their content and preserving
|
||||
// any attached `userInputMessageContext` (e.g. accumulated toolResults).
|
||||
//
|
||||
// Why this is not redundant with the `flushPending` grouping in the main
|
||||
// loop: the assistant branch resets `currentRole = null` after emitting
|
||||
// `toolUses`. Any following `tool` role (normalized to user) and a
|
||||
// subsequent `user` role therefore each open their own flush, producing
|
||||
// two adjacent `userInputMessage` entries in history. This pass collapses
|
||||
// those.
|
||||
const mergedHistory: typeof history = [];
|
||||
for (const item of history) {
|
||||
const previous = mergedHistory[mergedHistory.length - 1];
|
||||
if (item.userInputMessage && previous?.userInputMessage) {
|
||||
const previousContent = previous.userInputMessage.content || "";
|
||||
const currentContent = item.userInputMessage.content || "";
|
||||
previous.userInputMessage.content = previousContent
|
||||
? `${previousContent}\n\n${currentContent}`
|
||||
: currentContent;
|
||||
|
||||
if (item.userInputMessage.userInputMessageContext) {
|
||||
const previousContext = previous.userInputMessage.userInputMessageContext || {};
|
||||
const nextContext = item.userInputMessage.userInputMessageContext;
|
||||
const mergedContext: Record<string, unknown> = { ...previousContext };
|
||||
|
||||
for (const [key, value] of Object.entries(nextContext)) {
|
||||
const existing = (previousContext as Record<string, unknown>)[key];
|
||||
if (Array.isArray(existing) && Array.isArray(value)) {
|
||||
mergedContext[key] = [...existing, ...value];
|
||||
} else {
|
||||
mergedContext[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
previous.userInputMessage.userInputMessageContext = mergedContext;
|
||||
}
|
||||
} else {
|
||||
mergedHistory.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
return { history: mergedHistory, currentMessage };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -254,3 +254,38 @@ test("OpenAI -> Kiro still returns a valid payload for minimal requests", () =>
|
||||
);
|
||||
assert.equal(result.conversationState.currentMessage.userInputMessage.modelId, "claude-sonnet-4");
|
||||
});
|
||||
|
||||
test("OpenAI -> Kiro merges adjacent user history turns after role normalization", () => {
|
||||
const result = buildKiroPayload(
|
||||
"claude-sonnet-4",
|
||||
{
|
||||
messages: [
|
||||
{ role: "system", content: "System rules" },
|
||||
{ role: "user", content: "First question" },
|
||||
{ role: "assistant", content: "Answer 1" },
|
||||
{ role: "tool", tool_call_id: "call_orphan", content: "tool log" },
|
||||
{ role: "user", content: "Follow-up" },
|
||||
],
|
||||
},
|
||||
false,
|
||||
null
|
||||
);
|
||||
|
||||
const history = result.conversationState.history as Array<{
|
||||
userInputMessage?: { content: string };
|
||||
assistantResponseMessage?: { content: string };
|
||||
}>;
|
||||
|
||||
for (let i = 1; i < history.length; i++) {
|
||||
assert.equal(
|
||||
Boolean(history[i - 1].userInputMessage) && Boolean(history[i].userInputMessage),
|
||||
false,
|
||||
"history should not contain adjacent userInputMessage turns"
|
||||
);
|
||||
}
|
||||
|
||||
const firstUser = history[0].userInputMessage;
|
||||
assert.ok(firstUser, "first history turn should be a user turn");
|
||||
assert.equal(firstUser.content, "System rules\n\nFirst question");
|
||||
assert.equal(history[1].assistantResponseMessage?.content, "Answer 1");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user