fix: collect tool results from subagent messages with absent isMeta field (#23)
User messages in subagent JSONLs lack the isMeta field, defaulting to false. An unconditional `continue` in the !isMeta branch skipped tool result collection for these messages, causing all subagent tools to show "No result received". Now we check for tool_result blocks before continuing, allowing them to fall through to the result collection logic.
This commit is contained in:
parent
94f722d993
commit
4ec272758c
2 changed files with 106 additions and 3 deletions
|
|
@ -423,16 +423,20 @@ export function buildDisplayItemsFromMessages(
|
|||
}
|
||||
continue;
|
||||
}
|
||||
// Plain-text user message (subagent input prompt)
|
||||
if (rawText.trim()) {
|
||||
// Only treat as subagent input if there are NO tool_result blocks in this message
|
||||
const hasToolResults =
|
||||
Array.isArray(msg.content) &&
|
||||
msg.content.some((b) => b.type === 'tool_result');
|
||||
if (rawText.trim() && !hasToolResults) {
|
||||
displayItems.push({
|
||||
type: 'subagent_input',
|
||||
content: rawText.trim(),
|
||||
timestamp: msgTimestamp,
|
||||
tokenCount: estimateTokens(rawText),
|
||||
});
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
// Fall through to tool result processing below if message has tool_results
|
||||
}
|
||||
|
||||
if (msg.type === 'assistant' && Array.isArray(msg.content)) {
|
||||
|
|
|
|||
99
test/renderer/utils/displayItemBuilder.test.ts
Normal file
99
test/renderer/utils/displayItemBuilder.test.ts
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { buildDisplayItemsFromMessages } from '../../../src/renderer/utils/displayItemBuilder';
|
||||
import type { ParsedMessage } from '../../../src/main/types/messages';
|
||||
|
||||
/**
|
||||
* Helper to create a minimal ParsedMessage for testing.
|
||||
*/
|
||||
function makeMessage(overrides: Partial<ParsedMessage> & Pick<ParsedMessage, 'type' | 'content'>): ParsedMessage {
|
||||
return {
|
||||
uuid: `msg-${Math.random().toString(36).slice(2, 8)}`,
|
||||
parentUuid: null,
|
||||
timestamp: new Date('2025-01-01T00:00:00Z'),
|
||||
isMeta: false,
|
||||
isSidechain: false,
|
||||
toolCalls: [],
|
||||
toolResults: [],
|
||||
...overrides,
|
||||
} as ParsedMessage;
|
||||
}
|
||||
|
||||
describe('buildDisplayItemsFromMessages', () => {
|
||||
describe('subagent tool results with isMeta=false', () => {
|
||||
it('should collect tool results from user messages without isMeta field', () => {
|
||||
// Simulates real subagent JSONL where user messages with tool_result
|
||||
// blocks have isMeta absent (defaults to false after parsing).
|
||||
const toolUseId = 'toolu_test123';
|
||||
|
||||
const assistantMsg = makeMessage({
|
||||
uuid: 'assistant-1',
|
||||
type: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'tool_use',
|
||||
id: toolUseId,
|
||||
name: 'Bash',
|
||||
input: { command: 'echo hello' },
|
||||
},
|
||||
],
|
||||
timestamp: new Date('2025-01-01T00:00:00Z'),
|
||||
});
|
||||
|
||||
// This is the key scenario: user message with tool_result but isMeta: false
|
||||
// (simulating subagent JSONL where isMeta field is absent)
|
||||
const toolResultMsg = makeMessage({
|
||||
uuid: 'user-result-1',
|
||||
type: 'user',
|
||||
isMeta: false,
|
||||
content: [
|
||||
{
|
||||
type: 'tool_result',
|
||||
tool_use_id: toolUseId,
|
||||
content: 'hello\n',
|
||||
is_error: false,
|
||||
},
|
||||
],
|
||||
toolResults: [
|
||||
{
|
||||
toolUseId: toolUseId,
|
||||
content: 'hello\n',
|
||||
isError: false,
|
||||
},
|
||||
],
|
||||
timestamp: new Date('2025-01-01T00:00:01Z'),
|
||||
});
|
||||
|
||||
const items = buildDisplayItemsFromMessages([assistantMsg, toolResultMsg], []);
|
||||
|
||||
const toolItems = items.filter((item) => item.type === 'tool');
|
||||
expect(toolItems).toHaveLength(1);
|
||||
|
||||
const tool = toolItems[0];
|
||||
if (tool.type !== 'tool') throw new Error('Expected tool item');
|
||||
|
||||
// The critical assertion: result must be present, not orphaned
|
||||
expect(tool.tool.isOrphaned).toBe(false);
|
||||
expect(tool.tool.result).toBeDefined();
|
||||
expect(tool.tool.result?.content).toBe('hello\n');
|
||||
expect(tool.tool.name).toBe('Bash');
|
||||
});
|
||||
|
||||
it('should still render subagent_input for plain text user messages without tool results', () => {
|
||||
const userMsg = makeMessage({
|
||||
uuid: 'user-input-1',
|
||||
type: 'user',
|
||||
isMeta: false,
|
||||
content: 'Please run the tests',
|
||||
toolResults: [],
|
||||
timestamp: new Date('2025-01-01T00:00:00Z'),
|
||||
});
|
||||
|
||||
const items = buildDisplayItemsFromMessages([userMsg], []);
|
||||
|
||||
const inputItems = items.filter((item) => item.type === 'subagent_input');
|
||||
expect(inputItems).toHaveLength(1);
|
||||
if (inputItems[0].type !== 'subagent_input') throw new Error('Expected subagent_input');
|
||||
expect(inputItems[0].content).toBe('Please run the tests');
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue