| 527 | } |
| 528 | |
| 529 | func parseContainerEvents(events []map[string]any) (response string, cost float64, outputTokens int64, toolCalls []string) { |
| 530 | var responseBuf strings.Builder |
| 531 | for _, event := range events { |
| 532 | eventType, _ := event["type"].(string) |
| 533 | |
| 534 | switch eventType { |
| 535 | case "agent_choice": |
| 536 | if content, ok := event["content"].(string); ok { |
| 537 | responseBuf.WriteString(content) |
| 538 | } |
| 539 | case "tool_call": |
| 540 | if tc, ok := event["tool_call"].(map[string]any); ok { |
| 541 | if fn, ok := tc["function"].(map[string]any); ok { |
| 542 | if name, ok := fn["name"].(string); ok { |
| 543 | toolCalls = append(toolCalls, name) |
| 544 | } |
| 545 | } |
| 546 | } |
| 547 | case "token_usage": |
| 548 | if usage, ok := event["usage"].(map[string]any); ok { |
| 549 | if c, ok := usage["cost"].(float64); ok { |
| 550 | cost = c |
| 551 | } |
| 552 | if tokens, ok := usage["output_tokens"].(float64); ok { |
| 553 | outputTokens += int64(tokens) |
| 554 | } |
| 555 | } |
| 556 | } |
| 557 | } |
| 558 | |
| 559 | return responseBuf.String(), cost, outputTokens, toolCalls |
| 560 | } |
| 561 | |
| 562 | // buildTranscript creates a chronological transcript of agent interactions. |
| 563 | // Unlike parseContainerEvents which only extracts text, this preserves the |