Skip to content

Commit 832ee88

Browse files
committed
Add a timestamp to runtime events
Signed-off-by: David Gageot <david.gageot@docker.com>
1 parent 4e6da79 commit 832ee88

3 files changed

Lines changed: 125 additions & 46 deletions

File tree

pkg/evaluation/save.go

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ func SessionFromEvents(events []map[string]any, title, question string) *session
7575
var currentModel string
7676
var currentUsage *chat.Usage
7777
var currentCost float64
78+
var currentTimestamp string
7879

7980
// Helper to flush current assistant message
8081
flushAssistantMessage := func() {
@@ -87,7 +88,7 @@ func SessionFromEvents(events []map[string]any, title, question string) *session
8788
ReasoningContent: currentReasoningContent.String(),
8889
ToolCalls: currentToolCalls,
8990
ToolDefinitions: currentToolDefinitions,
90-
CreatedAt: time.Now().Format(time.RFC3339),
91+
CreatedAt: currentTimestamp,
9192
Model: currentModel,
9293
Usage: currentUsage,
9394
Cost: currentCost,
@@ -101,11 +102,13 @@ func SessionFromEvents(events []map[string]any, title, question string) *session
101102
currentModel = ""
102103
currentUsage = nil
103104
currentCost = 0
105+
currentTimestamp = ""
104106
}
105107
}
106108

107109
for _, event := range events {
108110
eventType, _ := event["type"].(string)
111+
eventTimestamp := parseEventTimestamp(event)
109112

110113
switch eventType {
111114
case "agent_choice":
@@ -116,6 +119,9 @@ func SessionFromEvents(events []map[string]any, title, question string) *session
116119
if agentName, ok := event["agent_name"].(string); ok && agentName != "" {
117120
currentAgentName = agentName
118121
}
122+
if eventTimestamp != "" {
123+
currentTimestamp = eventTimestamp
124+
}
119125

120126
case "agent_choice_reasoning":
121127
// Accumulate reasoning content (for models like DeepSeek, Claude with extended thinking)
@@ -125,6 +131,9 @@ func SessionFromEvents(events []map[string]any, title, question string) *session
125131
if agentName, ok := event["agent_name"].(string); ok && agentName != "" {
126132
currentAgentName = agentName
127133
}
134+
if eventTimestamp != "" {
135+
currentTimestamp = eventTimestamp
136+
}
128137

129138
case "tool_call":
130139
// Parse tool call and add to current message
@@ -143,6 +152,9 @@ func SessionFromEvents(events []map[string]any, title, question string) *session
143152
if agentName, ok := event["agent_name"].(string); ok && agentName != "" {
144153
currentAgentName = agentName
145154
}
155+
if eventTimestamp != "" {
156+
currentTimestamp = eventTimestamp
157+
}
146158

147159
case "tool_call_response":
148160
// Flush any pending assistant message before adding tool response
@@ -158,7 +170,7 @@ func SessionFromEvents(events []map[string]any, title, question string) *session
158170
Role: chat.MessageRoleTool,
159171
Content: response,
160172
ToolCallID: toolCallID,
161-
CreatedAt: time.Now().Format(time.RFC3339),
173+
CreatedAt: eventTimestamp,
162174
},
163175
}
164176
sess.AddMessage(msg)
@@ -198,7 +210,7 @@ func SessionFromEvents(events []map[string]any, title, question string) *session
198210
Message: chat.Message{
199211
Role: chat.MessageRoleSystem,
200212
Content: "Error: " + errorMsg,
201-
CreatedAt: time.Now().Format(time.RFC3339),
213+
CreatedAt: eventTimestamp,
202214
},
203215
}
204216
sess.AddMessage(msg)
@@ -301,6 +313,19 @@ func parseMessageUsage(m map[string]any) *chat.Usage {
301313
return usage
302314
}
303315

316+
// parseEventTimestamp extracts the timestamp from an event map.
317+
// Returns the timestamp string, falling back to current time if not present or invalid.
318+
func parseEventTimestamp(event map[string]any) string {
319+
if ts, ok := event["timestamp"].(string); ok && ts != "" {
320+
// Validate RFC3339 format
321+
if _, err := time.Parse(time.RFC3339, ts); err == nil {
322+
return ts
323+
}
324+
// Invalid timestamp format - fall back to current time
325+
}
326+
return time.Now().Format(time.RFC3339)
327+
}
328+
304329
// SaveRunJSON saves the eval run results to a JSON file.
305330
// This is kept for backward compatibility and debugging purposes.
306331
func SaveRunJSON(run *EvalRun, outputDir string) (string, error) {

0 commit comments

Comments
 (0)