Merge 5db5dc2def into fa9ec6e854
This commit is contained in:
commit
87e61765c5
@ -18,6 +18,7 @@ export function guardSessionManager(
|
|||||||
agentId?: string;
|
agentId?: string;
|
||||||
sessionKey?: string;
|
sessionKey?: string;
|
||||||
allowSyntheticToolResults?: boolean;
|
allowSyntheticToolResults?: boolean;
|
||||||
|
dropOrphanToolResults?: boolean;
|
||||||
},
|
},
|
||||||
): GuardedSessionManager {
|
): GuardedSessionManager {
|
||||||
if (typeof (sessionManager as GuardedSessionManager).flushPendingToolResults === "function") {
|
if (typeof (sessionManager as GuardedSessionManager).flushPendingToolResults === "function") {
|
||||||
@ -48,6 +49,7 @@ export function guardSessionManager(
|
|||||||
const guard = installSessionToolResultGuard(sessionManager, {
|
const guard = installSessionToolResultGuard(sessionManager, {
|
||||||
transformToolResultForPersistence: transform,
|
transformToolResultForPersistence: transform,
|
||||||
allowSyntheticToolResults: opts?.allowSyntheticToolResults,
|
allowSyntheticToolResults: opts?.allowSyntheticToolResults,
|
||||||
|
dropOrphanToolResults: opts?.dropOrphanToolResults,
|
||||||
});
|
});
|
||||||
(sessionManager as GuardedSessionManager).flushPendingToolResults = guard.flushPendingToolResults;
|
(sessionManager as GuardedSessionManager).flushPendingToolResults = guard.flushPendingToolResults;
|
||||||
return sessionManager as GuardedSessionManager;
|
return sessionManager as GuardedSessionManager;
|
||||||
|
|||||||
@ -72,6 +72,25 @@ describe("installSessionToolResultGuard", () => {
|
|||||||
expect(messages.map((m) => m.role)).toEqual(["assistant", "toolResult"]);
|
expect(messages.map((m) => m.role)).toEqual(["assistant", "toolResult"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("drops orphan toolResult messages by default", () => {
|
||||||
|
const sm = SessionManager.inMemory();
|
||||||
|
installSessionToolResultGuard(sm);
|
||||||
|
|
||||||
|
sm.appendMessage({
|
||||||
|
role: "toolResult",
|
||||||
|
toolCallId: "orphan_call",
|
||||||
|
content: [{ type: "text", text: "no matching tool call" }],
|
||||||
|
isError: true,
|
||||||
|
} as AgentMessage);
|
||||||
|
|
||||||
|
const messages = sm
|
||||||
|
.getEntries()
|
||||||
|
.filter((e) => e.type === "message")
|
||||||
|
.map((e) => (e as { message: AgentMessage }).message);
|
||||||
|
|
||||||
|
expect(messages).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
it("preserves ordering with multiple tool calls and partial results", () => {
|
it("preserves ordering with multiple tool calls and partial results", () => {
|
||||||
const sm = SessionManager.inMemory();
|
const sm = SessionManager.inMemory();
|
||||||
const guard = installSessionToolResultGuard(sm);
|
const guard = installSessionToolResultGuard(sm);
|
||||||
|
|||||||
@ -49,6 +49,11 @@ export function installSessionToolResultGuard(
|
|||||||
* Defaults to true.
|
* Defaults to true.
|
||||||
*/
|
*/
|
||||||
allowSyntheticToolResults?: boolean;
|
allowSyntheticToolResults?: boolean;
|
||||||
|
/**
|
||||||
|
* Whether to drop toolResult messages that do not match a pending tool call.
|
||||||
|
* Defaults to true to avoid corrupting transcripts with orphan tool results.
|
||||||
|
*/
|
||||||
|
dropOrphanToolResults?: boolean;
|
||||||
},
|
},
|
||||||
): {
|
): {
|
||||||
flushPendingToolResults: () => void;
|
flushPendingToolResults: () => void;
|
||||||
@ -66,6 +71,7 @@ export function installSessionToolResultGuard(
|
|||||||
};
|
};
|
||||||
|
|
||||||
const allowSyntheticToolResults = opts?.allowSyntheticToolResults ?? true;
|
const allowSyntheticToolResults = opts?.allowSyntheticToolResults ?? true;
|
||||||
|
const dropOrphanToolResults = opts?.dropOrphanToolResults ?? true;
|
||||||
|
|
||||||
const flushPendingToolResults = () => {
|
const flushPendingToolResults = () => {
|
||||||
if (pending.size === 0) return;
|
if (pending.size === 0) return;
|
||||||
@ -90,6 +96,9 @@ export function installSessionToolResultGuard(
|
|||||||
if (role === "toolResult") {
|
if (role === "toolResult") {
|
||||||
const id = extractToolResultId(message as Extract<AgentMessage, { role: "toolResult" }>);
|
const id = extractToolResultId(message as Extract<AgentMessage, { role: "toolResult" }>);
|
||||||
const toolName = id ? pending.get(id) : undefined;
|
const toolName = id ? pending.get(id) : undefined;
|
||||||
|
if (id && !pending.has(id) && dropOrphanToolResults) {
|
||||||
|
return undefined as never;
|
||||||
|
}
|
||||||
if (id) pending.delete(id);
|
if (id) pending.delete(id);
|
||||||
return originalAppend(
|
return originalAppend(
|
||||||
persistToolResult(message, {
|
persistToolResult(message, {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user