mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 06:15:51 +00:00
153 lines
5.1 KiB
TypeScript
153 lines
5.1 KiB
TypeScript
import { describe, expect, test } from 'bun:test'
|
|
import { applyGrouping } from '../groupToolUses'
|
|
|
|
// Helper: build minimal tool-use assistant message
|
|
function makeToolUseMsg(
|
|
uuid: string,
|
|
messageId: string,
|
|
toolUseId: string,
|
|
toolName: string,
|
|
): any {
|
|
return {
|
|
type: 'assistant',
|
|
uuid,
|
|
timestamp: Date.now(),
|
|
message: {
|
|
id: messageId,
|
|
content: [{ type: 'tool_use', id: toolUseId, name: toolName, input: {} }],
|
|
},
|
|
}
|
|
}
|
|
|
|
// Helper: build minimal tool-result user message
|
|
function makeToolResultMsg(uuid: string, toolUseId: string): any {
|
|
return {
|
|
type: 'user',
|
|
uuid,
|
|
timestamp: Date.now(),
|
|
message: {
|
|
content: [{ type: 'tool_result', tool_use_id: toolUseId, content: 'ok' }],
|
|
},
|
|
}
|
|
}
|
|
|
|
// Helper: build minimal text assistant message
|
|
function makeTextMsg(uuid: string, text: string): any {
|
|
return {
|
|
type: 'assistant',
|
|
uuid,
|
|
timestamp: Date.now(),
|
|
message: { id: `msg-${uuid}`, content: [{ type: 'text', text }] },
|
|
}
|
|
}
|
|
|
|
// Minimal tool definitions
|
|
const groupableTool: any = { name: 'Grep', renderGroupedToolUse: true }
|
|
const nonGroupableTool: any = { name: 'Bash', renderGroupedToolUse: undefined }
|
|
|
|
// ─── applyGrouping ────────────────────────────────────────────────────
|
|
|
|
describe('applyGrouping', () => {
|
|
test('returns all messages in verbose mode', () => {
|
|
const msgs = [
|
|
makeToolUseMsg('u1', 'm1', 'tu1', 'Grep'),
|
|
makeToolUseMsg('u2', 'm1', 'tu2', 'Grep'),
|
|
]
|
|
const result = applyGrouping(msgs, [groupableTool], true)
|
|
expect(result.messages).toHaveLength(2)
|
|
expect(result.messages).toBe(msgs) // same reference
|
|
})
|
|
|
|
test('does not group when tool lacks renderGroupedToolUse', () => {
|
|
const msgs = [
|
|
makeToolUseMsg('u1', 'm1', 'tu1', 'Bash'),
|
|
makeToolUseMsg('u2', 'm1', 'tu2', 'Bash'),
|
|
]
|
|
const result = applyGrouping(msgs, [nonGroupableTool])
|
|
expect(result.messages).toHaveLength(2)
|
|
// Both messages should pass through as-is
|
|
expect(result.messages[0]).toBe(msgs[0])
|
|
})
|
|
|
|
test('does not group single tool use', () => {
|
|
const msgs = [makeToolUseMsg('u1', 'm1', 'tu1', 'Grep')]
|
|
const result = applyGrouping(msgs, [groupableTool])
|
|
expect(result.messages).toHaveLength(1)
|
|
expect((result.messages[0] as any).type).toBe('assistant')
|
|
})
|
|
|
|
test('groups 2+ tool uses of same type from same message', () => {
|
|
const msgs = [
|
|
makeToolUseMsg('u1', 'm1', 'tu1', 'Grep'),
|
|
makeToolUseMsg('u2', 'm1', 'tu2', 'Grep'),
|
|
makeToolUseMsg('u3', 'm1', 'tu3', 'Grep'),
|
|
]
|
|
const result = applyGrouping(msgs, [groupableTool])
|
|
expect(result.messages).toHaveLength(1)
|
|
const grouped = result.messages[0] as any
|
|
expect(grouped.type).toBe('grouped_tool_use')
|
|
expect(grouped.toolName).toBe('Grep')
|
|
expect(grouped.messages).toHaveLength(3)
|
|
})
|
|
|
|
test('does not group tool uses from different messages', () => {
|
|
const msgs = [
|
|
makeToolUseMsg('u1', 'm1', 'tu1', 'Grep'),
|
|
makeToolUseMsg('u2', 'm2', 'tu2', 'Grep'),
|
|
]
|
|
const result = applyGrouping(msgs, [groupableTool])
|
|
// Each belongs to a different message.id, so no group (< 2 per group)
|
|
expect(result.messages).toHaveLength(2)
|
|
})
|
|
|
|
test('collects tool results for grouped uses', () => {
|
|
const msgs = [
|
|
makeToolUseMsg('u1', 'm1', 'tu1', 'Grep'),
|
|
makeToolUseMsg('u2', 'm1', 'tu2', 'Grep'),
|
|
makeToolResultMsg('u3', 'tu1'),
|
|
makeToolResultMsg('u4', 'tu2'),
|
|
]
|
|
const result = applyGrouping(msgs, [groupableTool])
|
|
const grouped = result.messages[0] as any
|
|
expect(grouped.type).toBe('grouped_tool_use')
|
|
expect(grouped.results).toHaveLength(2)
|
|
})
|
|
|
|
test('skips user messages whose tool_results are all grouped', () => {
|
|
const msgs = [
|
|
makeToolUseMsg('u1', 'm1', 'tu1', 'Grep'),
|
|
makeToolUseMsg('u2', 'm1', 'tu2', 'Grep'),
|
|
makeToolResultMsg('u3', 'tu1'),
|
|
makeToolResultMsg('u4', 'tu2'),
|
|
]
|
|
const result = applyGrouping(msgs, [groupableTool])
|
|
// Only the grouped message should remain — result messages are consumed
|
|
expect(result.messages).toHaveLength(1)
|
|
})
|
|
|
|
test('preserves non-grouped messages alongside groups', () => {
|
|
const msgs = [
|
|
makeTextMsg('u0', 'thinking...'),
|
|
makeToolUseMsg('u1', 'm1', 'tu1', 'Grep'),
|
|
makeToolUseMsg('u2', 'm1', 'tu2', 'Grep'),
|
|
makeTextMsg('u3', 'done'),
|
|
]
|
|
const result = applyGrouping(msgs, [groupableTool])
|
|
expect(result.messages).toHaveLength(3) // text + grouped + text
|
|
expect((result.messages[0] as any).type).toBe('assistant')
|
|
expect((result.messages[1] as any).type).toBe('grouped_tool_use')
|
|
expect((result.messages[2] as any).type).toBe('assistant')
|
|
})
|
|
|
|
test('handles empty messages array', () => {
|
|
const result = applyGrouping([], [groupableTool])
|
|
expect(result.messages).toHaveLength(0)
|
|
})
|
|
|
|
test('handles empty tools array', () => {
|
|
const msgs = [makeToolUseMsg('u1', 'm1', 'tu1', 'Grep')]
|
|
const result = applyGrouping(msgs, [])
|
|
expect(result.messages).toHaveLength(1)
|
|
})
|
|
})
|