fix(chat): exclude tool-result user messages from run segmentation
Gateway history contains `role: 'user'` messages that are actually tool-result wrappers (Anthropic API format). These were incorrectly treated as run boundaries in nextUserMessageIndexes, causing: - isLatestOpenRun=false during tool execution → graph collapses - Run split into multiple segments → incorrect step attribution Add isRealUserMessage() that detects tool-result wrappers by checking if all content blocks are type 'tool_result', and use it in both nextUserMessageIndexes computation and userRunCards filtering. Also remove debug logging from previous iterations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -187,11 +187,25 @@ export function Chat() {
|
|||||||
|
|
||||||
const isEmpty = messages.length === 0 && !sending;
|
const isEmpty = messages.length === 0 && !sending;
|
||||||
const subagentCompletionInfos = messages.map((message) => parseSubagentCompletionInfo(message));
|
const subagentCompletionInfos = messages.map((message) => parseSubagentCompletionInfo(message));
|
||||||
|
// Build an index of the *next* real user message after each position.
|
||||||
|
// Gateway history may contain `role: 'user'` messages that are actually
|
||||||
|
// tool-result wrappers (Anthropic API format). These must NOT split
|
||||||
|
// the run into multiple segments — only genuine user-authored messages
|
||||||
|
// should act as run boundaries.
|
||||||
|
const isRealUserMessage = (msg: RawMessage): boolean => {
|
||||||
|
if (msg.role !== 'user') return false;
|
||||||
|
const content = msg.content;
|
||||||
|
if (!Array.isArray(content)) return true;
|
||||||
|
// If every block in the content is a tool_result, this is a Gateway
|
||||||
|
// tool-result wrapper, not a real user message.
|
||||||
|
const blocks = content as Array<{ type?: string }>;
|
||||||
|
return blocks.length === 0 || !blocks.every((b) => b.type === 'tool_result');
|
||||||
|
};
|
||||||
const nextUserMessageIndexes = new Array<number>(messages.length).fill(-1);
|
const nextUserMessageIndexes = new Array<number>(messages.length).fill(-1);
|
||||||
let nextUserMessageIndex = -1;
|
let nextUserMessageIndex = -1;
|
||||||
for (let idx = messages.length - 1; idx >= 0; idx -= 1) {
|
for (let idx = messages.length - 1; idx >= 0; idx -= 1) {
|
||||||
nextUserMessageIndexes[idx] = nextUserMessageIndex;
|
nextUserMessageIndexes[idx] = nextUserMessageIndex;
|
||||||
if (messages[idx].role === 'user' && !subagentCompletionInfos[idx]) {
|
if (isRealUserMessage(messages[idx]) && !subagentCompletionInfos[idx]) {
|
||||||
nextUserMessageIndex = idx;
|
nextUserMessageIndex = idx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,7 +216,7 @@ export function Chat() {
|
|||||||
const foldedNarrationIndices = new Set<number>();
|
const foldedNarrationIndices = new Set<number>();
|
||||||
|
|
||||||
const userRunCards: UserRunCard[] = messages.flatMap((message, idx) => {
|
const userRunCards: UserRunCard[] = messages.flatMap((message, idx) => {
|
||||||
if (message.role !== 'user' || subagentCompletionInfos[idx]) return [];
|
if (!isRealUserMessage(message) || subagentCompletionInfos[idx]) return [];
|
||||||
|
|
||||||
const runKey = message.id
|
const runKey = message.id
|
||||||
? `msg-${message.id}`
|
? `msg-${message.id}`
|
||||||
@@ -345,10 +359,12 @@ export function Chat() {
|
|||||||
foldedNarrationIndices.add(idx + 1 + offset);
|
foldedNarrationIndices.add(idx + 1 + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cardActive = isLatestOpenRun && streamingReplyText == null;
|
||||||
|
|
||||||
return [{
|
return [{
|
||||||
triggerIndex: idx,
|
triggerIndex: idx,
|
||||||
replyIndex,
|
replyIndex,
|
||||||
active: isLatestOpenRun && streamingReplyText == null,
|
active: cardActive,
|
||||||
agentLabel: segmentAgentLabel,
|
agentLabel: segmentAgentLabel,
|
||||||
sessionLabel: segmentSessionLabel,
|
sessionLabel: segmentSessionLabel,
|
||||||
segmentEnd: nextUserIndex === -1 ? messages.length - 1 : nextUserIndex - 1,
|
segmentEnd: nextUserIndex === -1 ? messages.length - 1 : nextUserIndex - 1,
|
||||||
|
|||||||
Reference in New Issue
Block a user