Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 2 additions & 15 deletions pkg/workflow/claude_logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package workflow
import (
"encoding/json"
"fmt"
"sort"
"strings"
"time"

Expand Down Expand Up @@ -337,10 +336,8 @@ func (e *ClaudeEngine) parseClaudeJSONLog(logContent string, verbose bool) LogMe
}
}

// Add the complete sequence if we found any tool calls
if len(currentSequence) > 0 {
metrics.ToolSequences = append(metrics.ToolSequences, currentSequence)
}
// Finalize tool calls and sequences using shared helper
FinalizeToolCallsAndSequence(&metrics, toolCallMap, currentSequence)

if verbose && len(metrics.ToolSequences) > 0 {
totalTools := 0
Expand All @@ -351,16 +348,6 @@ func (e *ClaudeEngine) parseClaudeJSONLog(logContent string, verbose bool) LogMe
len(metrics.ToolSequences), totalTools)
}

// Convert tool call map to slice
for _, toolInfo := range toolCallMap {
metrics.ToolCalls = append(metrics.ToolCalls, *toolInfo)
}

// Sort tool calls by name for consistent output
sort.Slice(metrics.ToolCalls, func(i, j int) bool {
return metrics.ToolCalls[i].Name < metrics.ToolCalls[j].Name
})

return metrics
}

Expand Down
25 changes: 2 additions & 23 deletions pkg/workflow/codex_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,29 +404,8 @@ func (e *CodexEngine) ParseLogMetrics(logContent string, verbose bool) LogMetric
// Basic processing - error/warning counting moved to end of function
}

// Add final sequence if any
if len(currentSequence) > 0 {
metrics.ToolSequences = append(metrics.ToolSequences, currentSequence)
}

metrics.TokenUsage = totalTokenUsage
metrics.Turns = turns

// Convert tool call map to slice
for _, toolInfo := range toolCallMap {
metrics.ToolCalls = append(metrics.ToolCalls, *toolInfo)
}

// Sort tool calls by name for consistent output
sort.Slice(metrics.ToolCalls, func(i, j int) bool {
return metrics.ToolCalls[i].Name < metrics.ToolCalls[j].Name
})

// Count errors and warnings using pattern matching for better accuracy
errorPatterns := e.GetErrorPatterns()
if len(errorPatterns) > 0 {
metrics.Errors = CountErrorsAndWarningsWithPatterns(logContent, errorPatterns)
}
// Finalize metrics using shared helper
FinalizeToolMetrics(&metrics, toolCallMap, currentSequence, turns, totalTokenUsage, logContent, e.GetErrorPatterns())

codexEngineLog.Printf("Parsed Codex metrics: turns=%d, token_usage=%d, tool_calls=%d, errors=%d",
metrics.Turns, metrics.TokenUsage, len(metrics.ToolCalls), len(metrics.Errors))
Expand Down
25 changes: 2 additions & 23 deletions pkg/workflow/copilot_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -489,29 +489,8 @@ func (e *CopilotEngine) ParseLogMetrics(logContent string, verbose bool) LogMetr
// Basic processing - error/warning counting moved to end of function
}

// Add final sequence if any
if len(currentSequence) > 0 {
metrics.ToolSequences = append(metrics.ToolSequences, currentSequence)
}

metrics.TokenUsage = maxTokenUsage
metrics.Turns = turns

// Convert tool call map to slice
for _, toolInfo := range toolCallMap {
metrics.ToolCalls = append(metrics.ToolCalls, *toolInfo)
}

// Sort tool calls by name for consistent output
sort.Slice(metrics.ToolCalls, func(i, j int) bool {
return metrics.ToolCalls[i].Name < metrics.ToolCalls[j].Name
})

// Count errors and warnings using pattern matching for better accuracy
errorPatterns := e.GetErrorPatterns()
if len(errorPatterns) > 0 {
metrics.Errors = CountErrorsAndWarningsWithPatterns(logContent, errorPatterns)
}
// Finalize metrics using shared helper
FinalizeToolMetrics(&metrics, toolCallMap, currentSequence, turns, maxTokenUsage, logContent, e.GetErrorPatterns())

return metrics
}
Expand Down
62 changes: 62 additions & 0 deletions pkg/workflow/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"regexp"
"sort"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -464,3 +465,64 @@ func extractErrorMessage(line string) string {

return cleanedLine
}

// FinalizeToolMetrics completes the metric collection process by finalizing sequences,
// converting tool call maps to sorted slices, and optionally counting errors using patterns.
// This function is called by engine-specific ParseLogMetrics implementations to avoid code duplication.
func FinalizeToolMetrics(
metrics *LogMetrics,
toolCallMap map[string]*ToolCallInfo,
currentSequence []string,
turns int,
tokenUsage int,
logContent string,
errorPatterns []ErrorPattern,
) {
// Add final sequence if any
if len(currentSequence) > 0 {
metrics.ToolSequences = append(metrics.ToolSequences, currentSequence)
}

metrics.TokenUsage = tokenUsage
metrics.Turns = turns

// Convert tool call map to slice
for _, toolInfo := range toolCallMap {
metrics.ToolCalls = append(metrics.ToolCalls, *toolInfo)
}
Comment thread
pelikhan marked this conversation as resolved.

// Sort tool calls by name for consistent output
sort.Slice(metrics.ToolCalls, func(i, j int) bool {
return metrics.ToolCalls[i].Name < metrics.ToolCalls[j].Name
})

// Count errors and warnings using pattern matching for better accuracy
if len(errorPatterns) > 0 {
metrics.Errors = CountErrorsAndWarningsWithPatterns(logContent, errorPatterns)
}
}

// FinalizeToolCallsAndSequence completes the tool call and sequence finalization.
// Use this function when the engine extracts token usage and turns from structured result entries,
// rather than accumulating them during line-by-line log parsing. This is a lighter version of
// FinalizeToolMetrics for engines that do not need to finalize token usage and turns here.
func FinalizeToolCallsAndSequence(
metrics *LogMetrics,
toolCallMap map[string]*ToolCallInfo,
currentSequence []string,
) {
// Add final sequence if any
if len(currentSequence) > 0 {
metrics.ToolSequences = append(metrics.ToolSequences, currentSequence)
}

// Convert tool call map to slice
for _, toolInfo := range toolCallMap {
metrics.ToolCalls = append(metrics.ToolCalls, *toolInfo)
}
Comment thread
pelikhan marked this conversation as resolved.

// Sort tool calls by name for consistent output
sort.Slice(metrics.ToolCalls, func(i, j int) bool {
return metrics.ToolCalls[i].Name < metrics.ToolCalls[j].Name
})
}
Loading
Loading