1use crate::{ModelOutput, Signal};
2use serde::{Deserialize, Serialize};
3use std::collections::BTreeMap;
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
10#[non_exhaustive]
11pub enum Block {
12 Text(String),
14 FileRef {
17 path: String,
18 hash: Option<String>,
19 excerpt: Option<String>,
20 },
21 Skill { name: String, body: String },
23 ToolCall {
25 call_id: String,
26 name: String,
27 args: serde_json::Value,
28 },
29 ToolResult {
31 call_id: String,
32 content: serde_json::Value,
33 },
34 Feedback(Vec<Signal>),
36 Reasoning(String),
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct Turn {
45 pub role: TurnRole,
46 pub blocks: Vec<Block>,
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
50#[serde(rename_all = "lowercase")]
51#[non_exhaustive]
52pub enum TurnRole {
53 User,
54 Assistant,
55 System,
56 Tool,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct Task {
61 pub description: String,
62 pub source: Option<String>, pub deadline: Option<i64>,
64}
65
66#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
67pub struct Policy {
68 pub max_iters: u32,
69 pub max_input_tokens: u32,
70 pub max_output_tokens: u32,
71 pub self_correct_rounds: u32,
72}
73
74impl Default for Policy {
75 fn default() -> Self {
76 Self {
77 max_iters: 50,
78 max_input_tokens: 150_000,
79 max_output_tokens: 8_000,
80 self_correct_rounds: 3,
81 }
82 }
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct Context {
88 pub system: Vec<Block>,
89 pub guides: Vec<Block>,
90 pub history: Vec<Turn>,
91 pub task: Task,
92 pub policy: Policy,
93 pub metadata: BTreeMap<String, serde_json::Value>,
94 pub tools: Vec<crate::ToolSchema>,
97}
98
99impl Context {
100 pub fn new(task: Task) -> Self {
101 Self {
102 system: Vec::new(),
103 guides: Vec::new(),
104 history: Vec::new(),
105 task,
106 policy: Policy::default(),
107 metadata: BTreeMap::new(),
108 tools: Vec::new(),
109 }
110 }
111
112 pub fn push_model_output(&mut self, out: &ModelOutput) {
116 let mut blocks = Vec::new();
117 if let Some(r) = &out.reasoning
118 && !r.is_empty()
119 {
120 blocks.push(Block::Reasoning(r.clone()));
121 }
122 if let Some(t) = &out.text
123 && !t.is_empty()
124 {
125 blocks.push(Block::Text(t.clone()));
126 }
127 for c in &out.tool_calls {
128 blocks.push(Block::ToolCall {
129 call_id: c.id.clone(),
130 name: c.name.clone(),
131 args: c.args.clone(),
132 });
133 }
134 self.history.push(Turn {
135 role: TurnRole::Assistant,
136 blocks,
137 });
138 }
139
140 pub fn push_feedback(&mut self, signals: Vec<Signal>) {
142 self.history.push(Turn {
143 role: TurnRole::Tool,
144 blocks: vec![Block::Feedback(signals)],
145 });
146 }
147}
148
149#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct Action {
152 pub tool: String,
153 pub call_id: String,
154 pub args: serde_json::Value,
155}