fix: prevent history truncation from orphaning tool results
This commit is contained in:
parent
14e4b88bf0
commit
bed8b67246
@ -154,7 +154,27 @@ describe("limitHistoryTurns", () => {
|
|||||||
{ role: "assistant", content: [{ type: "text", text: "response" }] },
|
{ role: "assistant", content: [{ type: "text", text: "response" }] },
|
||||||
];
|
];
|
||||||
const limited = limitHistoryTurns(messages, 1);
|
const limited = limitHistoryTurns(messages, 1);
|
||||||
expect(limited[0].content).toEqual([{ type: "text", text: "second" }]);
|
|
||||||
expect(limited[1].content).toEqual([{ type: "text", text: "response" }]);
|
expect(limited[1].content).toEqual([{ type: "text", text: "response" }]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("does not slice between tool use and tool result when limit cuts off tool use", () => {
|
||||||
|
const messages: AgentMessage[] = [
|
||||||
|
{ role: "user", content: [{ type: "text", text: "start" }] },
|
||||||
|
{ role: "assistant", content: [{ type: "text", text: "ack" }] },
|
||||||
|
{ role: "user", content: [{ type: "text", text: "do tool" }] },
|
||||||
|
{ role: "assistant", content: [{ type: "tool_use", id: "call_1", name: "foo", input: {} }] },
|
||||||
|
{ role: "user", content: [{ type: "tool_result", tool_use_id: "call_1", content: "res" }] },
|
||||||
|
];
|
||||||
|
|
||||||
|
// If we limit to 1 turn, we should get the full tool interaction chain (User -> Asst(Call) -> User(Result))
|
||||||
|
const limited = limitHistoryTurns(messages, 1);
|
||||||
|
|
||||||
|
expect(limited.length).toBe(3);
|
||||||
|
expect(limited[0].role).toBe("user");
|
||||||
|
expect((limited[0].content as any)[0].text).toBe("do tool");
|
||||||
|
expect(limited[1].role).toBe("assistant");
|
||||||
|
expect((limited[1].content as any)[0].type).toBe("tool_use");
|
||||||
|
expect(limited[2].role).toBe("user");
|
||||||
|
expect((limited[2].content as any)[0].type).toBe("tool_result");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -9,9 +9,28 @@ function stripThreadSuffix(value: string): string {
|
|||||||
return match?.[1] ?? value;
|
return match?.[1] ?? value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a user message is purely a tool result (not a new user turn).
|
||||||
|
*/
|
||||||
|
function isToolResultMessage(msg: AgentMessage): boolean {
|
||||||
|
if (msg.role !== "user") return false;
|
||||||
|
const content = msg.content;
|
||||||
|
if (!Array.isArray(content)) return false;
|
||||||
|
// A tool result message contains only tool_result blocks
|
||||||
|
return (
|
||||||
|
content.length > 0 &&
|
||||||
|
content.every((block) => {
|
||||||
|
if (!block || typeof block !== "object") return false;
|
||||||
|
const type = (block as { type?: unknown }).type;
|
||||||
|
return type === "tool_result";
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Limits conversation history to the last N user turns (and their associated
|
* Limits conversation history to the last N user turns (and their associated
|
||||||
* assistant responses). This reduces token usage for long-running DM sessions.
|
* assistant responses). This reduces token usage for long-running DM sessions.
|
||||||
|
* Tool result messages are not counted as new user turns.
|
||||||
*/
|
*/
|
||||||
export function limitHistoryTurns(
|
export function limitHistoryTurns(
|
||||||
messages: AgentMessage[],
|
messages: AgentMessage[],
|
||||||
@ -23,7 +42,9 @@ export function limitHistoryTurns(
|
|||||||
let lastUserIndex = messages.length;
|
let lastUserIndex = messages.length;
|
||||||
|
|
||||||
for (let i = messages.length - 1; i >= 0; i--) {
|
for (let i = messages.length - 1; i >= 0; i--) {
|
||||||
if (messages[i].role === "user") {
|
const msg = messages[i];
|
||||||
|
// Only count genuine user messages, not tool results
|
||||||
|
if (msg.role === "user" && !isToolResultMessage(msg)) {
|
||||||
userCount++;
|
userCount++;
|
||||||
if (userCount > limit) {
|
if (userCount > limit) {
|
||||||
return messages.slice(lastUserIndex);
|
return messages.slice(lastUserIndex);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user