agtrace_engine/session/
assembler.rs

1use super::stats::calculate_session_stats;
2use super::turn_builder::TurnBuilder;
3use super::types::*;
4use agtrace_types::{AgentEvent, EventPayload, StreamId};
5
6pub fn assemble_session(events: &[AgentEvent]) -> Option<AgentSession> {
7    if events.is_empty() {
8        return None;
9    }
10
11    // Filter out sidechain/subagent events by default
12    // Only keep main stream events for primary session analysis
13    let main_events: Vec<_> = events
14        .iter()
15        .filter(|e| matches!(e.stream_id, StreamId::Main))
16        .cloned()
17        .collect();
18
19    if main_events.is_empty() {
20        return None;
21    }
22
23    let session_id = main_events.first()?.session_id;
24    let start_time = main_events.first()?.timestamp;
25    let end_time = main_events.last().map(|e| e.timestamp);
26
27    let turns = build_turns(&main_events);
28    let stats = calculate_session_stats(&turns, start_time, end_time);
29
30    Some(AgentSession {
31        session_id,
32        start_time,
33        end_time,
34        turns,
35        stats,
36    })
37}
38
39fn build_turns(events: &[AgentEvent]) -> Vec<AgentTurn> {
40    let mut turns = Vec::new();
41    let mut current_turn: Option<TurnBuilder> = None;
42
43    for event in events {
44        match &event.payload {
45            EventPayload::User(user) => {
46                if let Some(builder) = current_turn.take()
47                    && let Some(turn) = builder.build()
48                {
49                    turns.push(turn);
50                }
51
52                current_turn = Some(TurnBuilder::new(
53                    event.id,
54                    event.timestamp,
55                    UserMessage {
56                        event_id: event.id,
57                        content: user.clone(),
58                    },
59                ));
60            }
61            _ => {
62                if let Some(ref mut builder) = current_turn {
63                    builder.add_event(event);
64                }
65            }
66        }
67    }
68
69    if let Some(builder) = current_turn
70        && let Some(turn) = builder.build()
71    {
72        turns.push(turn);
73    }
74
75    turns
76}