use crate::{ModelOutput, Signal};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub enum Block {
Text(String),
FileRef { path: String, hash: Option<String>, excerpt: Option<String> },
Skill { name: String, body: String },
ToolCall { call_id: String, name: String, args: serde_json::Value },
ToolResult { call_id: String, content: serde_json::Value },
Feedback(Vec<Signal>),
Reasoning(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Turn {
pub role: TurnRole,
pub blocks: Vec<Block>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[non_exhaustive]
pub enum TurnRole {
User,
Assistant,
System,
Tool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Task {
pub description: String,
pub source: Option<String>, pub deadline: Option<i64>,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct Policy {
pub max_iters: u32,
pub max_input_tokens: u32,
pub max_output_tokens: u32,
pub self_correct_rounds: u32,
}
impl Default for Policy {
fn default() -> Self {
Self {
max_iters: 50,
max_input_tokens: 150_000,
max_output_tokens: 8_000,
self_correct_rounds: 3,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Context {
pub system: Vec<Block>,
pub guides: Vec<Block>,
pub history: Vec<Turn>,
pub task: Task,
pub policy: Policy,
pub metadata: BTreeMap<String, serde_json::Value>,
pub tools: Vec<crate::ToolSchema>,
}
impl Context {
pub fn new(task: Task) -> Self {
Self {
system: Vec::new(),
guides: Vec::new(),
history: Vec::new(),
task,
policy: Policy::default(),
metadata: BTreeMap::new(),
tools: Vec::new(),
}
}
pub fn push_model_output(&mut self, out: &ModelOutput) {
let mut blocks = Vec::new();
if let Some(r) = &out.reasoning
&& !r.is_empty()
{
blocks.push(Block::Reasoning(r.clone()));
}
if let Some(t) = &out.text
&& !t.is_empty()
{
blocks.push(Block::Text(t.clone()));
}
for c in &out.tool_calls {
blocks.push(Block::ToolCall {
call_id: c.id.clone(),
name: c.name.clone(),
args: c.args.clone(),
});
}
self.history.push(Turn { role: TurnRole::Assistant, blocks });
}
pub fn push_feedback(&mut self, signals: Vec<Signal>) {
self.history.push(Turn {
role: TurnRole::Tool,
blocks: vec![Block::Feedback(signals)],
});
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Action {
pub tool: String,
pub call_id: String,
pub args: serde_json::Value,
}