agents_core/
command.rs

1use crate::messaging::AgentMessage;
2use crate::state::{AgentStateSnapshot, TodoItem};
3use serde::{Deserialize, Serialize};
4use std::collections::BTreeMap;
5
6/// Represents a state delta emitted by tools to be applied by the runtime.
7#[derive(Debug, Default, Clone, Serialize, Deserialize)]
8pub struct StateDiff {
9    #[serde(default, skip_serializing_if = "Option::is_none")]
10    pub todos: Option<Vec<TodoItem>>,
11    #[serde(default, skip_serializing_if = "Option::is_none")]
12    pub files: Option<BTreeMap<String, String>>,
13    #[serde(default, skip_serializing_if = "Option::is_none")]
14    pub scratchpad: Option<BTreeMap<String, serde_json::Value>>,
15}
16
17#[derive(Debug, Default, Clone, Serialize, Deserialize)]
18pub struct Command {
19    #[serde(default)]
20    pub state: StateDiff,
21    #[serde(default)]
22    pub messages: Vec<AgentMessage>,
23}
24
25impl Command {
26    pub fn with_state(state: StateDiff) -> Self {
27        Self {
28            state,
29            ..Self::default()
30        }
31    }
32
33    pub fn with_messages(messages: Vec<AgentMessage>) -> Self {
34        Self {
35            messages,
36            ..Self::default()
37        }
38    }
39
40    pub fn apply_to(self, snapshot: &mut AgentStateSnapshot) {
41        if let Some(todos) = self.state.todos {
42            snapshot.todos = todos;
43        }
44        if let Some(files) = self.state.files {
45            for (path, content) in files {
46                snapshot.files.insert(path, content);
47            }
48        }
49        if let Some(scratch) = self.state.scratchpad {
50            for (key, value) in scratch {
51                snapshot.scratchpad.insert(key, value);
52            }
53        }
54    }
55}
56
57impl AgentStateSnapshot {
58    pub fn apply_command(&mut self, command: Command) {
59        command.apply_to(self);
60    }
61}