use tokio_util::sync::CancellationToken;
pub use zeph_context::turn_context::{TurnContext, TurnId};
use zeph_llm::provider::MessagePart;
use crate::metrics::TurnTimings;
pub struct TurnInput {
pub text: String,
pub image_parts: Vec<MessagePart>,
}
impl TurnInput {
#[must_use]
pub fn new(text: String, image_parts: Vec<MessagePart>) -> Self {
Self { text, image_parts }
}
}
#[derive(Debug, Default, Clone)]
pub struct TurnMetrics {
pub timings: TurnTimings,
}
#[allow(dead_code)]
pub(crate) struct ToolOutputRecord {
pub(crate) tool_name: String,
pub(crate) summary: String,
pub(crate) latency_ms: u64,
}
pub struct Turn {
pub context: TurnContext,
pub input: TurnInput,
pub metrics: TurnMetrics,
}
impl Turn {
#[must_use]
pub fn new(context: TurnContext, input: TurnInput) -> Self {
Self {
context,
input,
metrics: TurnMetrics::default(),
}
}
#[must_use]
pub fn id(&self) -> TurnId {
self.context.id
}
#[must_use]
pub fn cancel_token(&self) -> &CancellationToken {
&self.context.cancel_token
}
#[must_use]
pub fn metrics_snapshot(&self) -> &TurnMetrics {
&self.metrics
}
pub fn metrics_mut(&mut self) -> &mut TurnMetrics {
&mut self.metrics
}
}
#[cfg(test)]
mod tests {
use tokio_util::sync::CancellationToken;
use zeph_config::security::TimeoutConfig;
use super::*;
fn make_turn(id: u64, text: &str) -> Turn {
let ctx = TurnContext::new(
TurnId(id),
CancellationToken::new(),
TimeoutConfig::default(),
);
let input = TurnInput::new(text.to_owned(), vec![]);
Turn::new(ctx, input)
}
#[test]
fn turn_new_sets_id() {
let turn = make_turn(7, "hello");
assert_eq!(turn.id(), TurnId(7));
}
#[test]
fn turn_id_display() {
assert_eq!(TurnId(42).to_string(), "42");
}
#[test]
fn turn_id_next() {
assert_eq!(TurnId(3).next(), TurnId(4));
}
#[test]
fn turn_input_fields() {
let input = TurnInput::new("hi".to_owned(), vec![]);
assert_eq!(input.text, "hi");
assert!(input.image_parts.is_empty());
}
#[test]
fn turn_metrics_default_timings_are_zero() {
let m = TurnMetrics::default();
assert_eq!(m.timings.prepare_context_ms, 0);
assert_eq!(m.timings.llm_chat_ms, 0);
}
#[test]
fn turn_cancel_token_not_cancelled_on_new() {
let turn = make_turn(0, "x");
assert!(!turn.cancel_token().is_cancelled());
}
#[test]
fn turn_cancel_token_cancel() {
let turn = make_turn(0, "x");
turn.cancel_token().cancel();
assert!(turn.cancel_token().is_cancelled());
}
#[test]
fn turn_metrics_mut_allows_write() {
let mut turn = make_turn(0, "x");
turn.metrics_mut().timings.prepare_context_ms = 99;
assert_eq!(turn.metrics_snapshot().timings.prepare_context_ms, 99);
}
}