toolTimeline.test.ts 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041
  1. import { describe, expect, it } from 'vitest'
  2. import { chatMessagesToUi } from '@/components/workspace/viewModels'
  3. import { normalizeChatMessage } from '@/utils/normalize'
  4. describe('ordinary chat tool timeline', () => {
  5. it('folds persisted function calls and their result rows into one expandable tool', () => {
  6. const user = normalizeChatMessage({ id: 'user-row', role: 'user', content: 'MEDIA:/tmp/keep-raw.png', timestamp: 0 }, 'session-1', 'default')
  7. const call = normalizeChatMessage({
  8. id: 'assistant-call', role: 'assistant', content: '', tool_calls: JSON.stringify([{
  9. id: 'call-1', type: 'function', function: { name: 'terminal', arguments: '{"command":"pwd"}' },
  10. }]), timestamp: 1,
  11. }, 'session-1', 'default')
  12. const result = normalizeChatMessage({
  13. id: 'tool-result', role: 'tool', tool_call_id: 'call-1', tool_name: 'terminal',
  14. content: '{"output":"/tmp/work","exit_code":0,"error":null}', timestamp: 2,
  15. }, 'session-1', 'default')
  16. const system = normalizeChatMessage({ id: 'system-row', role: 'system', content: 'transport detail', timestamp: 3 }, 'session-1', 'default')
  17. const timeline = chatMessagesToUi([user, call, result, system])
  18. expect(timeline).toHaveLength(2)
  19. expect(timeline[0]).toMatchObject({ role: 'user', content: 'MEDIA:/tmp/keep-raw.png' })
  20. expect(timeline[1].role).toBe('assistant')
  21. expect(timeline[1].tools).toEqual([expect.objectContaining({
  22. id: 'call-1', name: 'terminal', status: 'success', input: '{"command":"pwd"}', output: { output: '/tmp/work', exit_code: 0, error: null },
  23. })])
  24. })
  25. it('renders asynchronous delegation completion as a timeline event, not a user message', () => {
  26. const notice = normalizeChatMessage({
  27. id: 'delegation', role: 'user', content: '[ASYNC DELEGATION BATCH COMPLETE]',
  28. display_kind: 'async_delegation_complete',
  29. display_metadata: JSON.stringify({ task_count: 2, completed_count: 2, failed_count: 0, duration_seconds: 71 }),
  30. timestamp: 1,
  31. }, 'session-1', 'default')
  32. const [timeline] = chatMessagesToUi([notice])
  33. expect(timeline).toMatchObject({
  34. role: 'system', timelineKind: 'delegation-complete',
  35. timelineMetadata: { task_count: 2, completed_count: 2 },
  36. })
  37. })
  38. })