buildTranscript creates a chronological transcript of agent interactions. Unlike parseContainerEvents which only extracts text, this preserves the temporal sequence of events, enabling evaluation of criteria like "explains before executing" or "announces tool usage beforehand".
(events []map[string]any)
| 564 | // temporal sequence of events, enabling evaluation of criteria like |
| 565 | // "explains before executing" or "announces tool usage beforehand". |
| 566 | func buildTranscript(events []map[string]any) string { |
| 567 | var transcript strings.Builder |
| 568 | var pendingText strings.Builder |
| 569 | var currentAgent string |
| 570 | |
| 571 | flushText := func() { |
| 572 | if pendingText.Len() == 0 { |
| 573 | return |
| 574 | } |
| 575 | fmt.Fprintf(&transcript, "[Agent %s says]:\n%s\n\n", cmp.Or(currentAgent, "unknown"), pendingText.String()) |
| 576 | pendingText.Reset() |
| 577 | } |
| 578 | |
| 579 | for _, event := range events { |
| 580 | switch event["type"] { |
| 581 | case "agent_choice": |
| 582 | if agentName, _ := event["agent_name"].(string); agentName != "" { |
| 583 | currentAgent = agentName |
| 584 | } |
| 585 | if content, _ := event["content"].(string); content != "" { |
| 586 | pendingText.WriteString(content) |
| 587 | } |
| 588 | |
| 589 | case "tool_call": |
| 590 | flushText() |
| 591 | name, args := getToolCallInfo(event) |
| 592 | if agentName, _ := event["agent_name"].(string); agentName != "" { |
| 593 | currentAgent = agentName |
| 594 | } |
| 595 | fmt.Fprintf(&transcript, "[Agent %s calls tool %q with arguments: %s]\n\n", cmp.Or(currentAgent, "unknown"), name, args) |
| 596 | |
| 597 | case "tool_call_response": |
| 598 | // The ToolCallResponseEvent has tool_definition at the top level, not |
| 599 | // nested under "tool_call". |
| 600 | var name string |
| 601 | if td, ok := event["tool_definition"].(map[string]any); ok { |
| 602 | name, _ = td["name"].(string) |
| 603 | } |
| 604 | response, _ := event["response"].(string) |
| 605 | if len(response) > 500 { |
| 606 | response = response[:500] + "...(truncated)" |
| 607 | } |
| 608 | fmt.Fprintf(&transcript, "[Tool %q returns: %s]\n\n", name, response) |
| 609 | } |
| 610 | } |
| 611 | |
| 612 | flushText() |
| 613 | return transcript.String() |
| 614 | } |
| 615 | |
| 616 | // getToolCallInfo extracts the tool name and arguments from an event. |
| 617 | func getToolCallInfo(event map[string]any) (name, args string) { |