Skip to main content

opi_agent/
message.rs

1//! Agent-level message types (S7.2).
2
3use serde::{Deserialize, Serialize};
4
5/// Messages within the agent loop.
6///
7/// Wraps provider-facing `Message` types and adds session-level variants
8/// that never reach the provider.
9#[non_exhaustive]
10#[derive(Debug, Clone, Serialize, Deserialize)]
11#[serde(tag = "type")]
12pub enum AgentMessage {
13    /// A provider-facing message (user, assistant, or tool result).
14    Llm(#[serde(with = "llm_message_serde")] opi_ai::message::Message),
15    /// Summary produced after context compaction.
16    CompactionSummary(CompactionSummaryMessage),
17    /// Summary of a parent session branch.
18    BranchSummary(BranchSummaryMessage),
19    /// Extension-provided agent message.
20    Custom(CustomAgentMessage),
21}
22
23/// Summary produced after context compaction (S9.5).
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct CompactionSummaryMessage {
26    pub summary: String,
27    pub first_kept_entry_id: String,
28    pub tokens_before: u64,
29    pub tokens_after: u64,
30}
31
32/// Summary of a parent session branch (S9.3).
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct BranchSummaryMessage {
35    pub parent_session_id: String,
36    pub summary: String,
37    pub entry_count: u64,
38}
39
40/// Extension-provided agent message (S7.2).
41///
42/// Unknown custom messages MUST NOT panic the runtime.
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct CustomAgentMessage {
45    pub kind: String,
46    pub data: serde_json::Value,
47    pub include_in_llm_context: bool,
48}
49
50/// Custom serde module for `opi_ai::Message` that preserves the internal
51/// tagged representation used by `Message`'s own `#[serde(tag = "role")]`.
52mod llm_message_serde {
53    use opi_ai::message::Message;
54    use serde::{Deserialize, Deserializer, Serializer};
55
56    pub fn serialize<S>(msg: &Message, serializer: S) -> Result<S::Ok, S::Error>
57    where
58        S: Serializer,
59    {
60        use serde::Serialize as _;
61        serde_json::to_value(msg)
62            .map_err(serde::ser::Error::custom)
63            .and_then(|v| v.serialize(serializer))
64    }
65
66    pub fn deserialize<'de, D>(deserializer: D) -> Result<Message, D::Error>
67    where
68        D: Deserializer<'de>,
69    {
70        let v = serde_json::Value::deserialize(deserializer)?;
71        serde_json::from_value(v).map_err(serde::de::Error::custom)
72    }
73}