Skip to main content

rig_memory/
saved.rs

1//! A saved agent's values read without the host that saved them: the keys
2//! rig saves an agent's model and title under, typed reads of any saved
3//! value, and which agent of a session is its main one.
4
5use std::collections::BTreeMap;
6
7use serde::de::DeserializeOwned;
8use serde_json::Value;
9
10use crate::session::skipped;
11use crate::{SavedAgent, Session};
12
13/// The key an agent's model is saved under: a string, `vendor/model`.
14pub const MODEL: &str = "rig::model";
15
16/// The key an agent's title is saved under, such as a subagent's task: a
17/// string.
18pub const TITLE: &str = "rig::title";
19
20impl SavedAgent {
21    /// Its saved value under `key`, such as a plugin's `goals.goal`, read
22    /// as a `T`: `None` when it has none, an error when the value is not a
23    /// `T`.
24    pub fn value<T: DeserializeOwned>(&self, key: &str) -> Option<Result<T, serde_json::Error>> {
25        value(&self.saved, key)
26    }
27
28    /// Its model, `vendor/model`, when one was saved ([`MODEL`]).
29    pub fn model(&self) -> Option<String> {
30        self.value(MODEL)?.ok()
31    }
32
33    /// Its title, when one was saved ([`TITLE`]).
34    pub fn title(&self) -> Option<String> {
35        self.value(TITLE)?.ok()
36    }
37}
38
39/// The value of `key` in `state`, parsed.
40fn value<T: DeserializeOwned>(
41    state: &BTreeMap<String, Value>,
42    key: &str,
43) -> Option<Result<T, serde_json::Error>> {
44    state.get(key).map(T::deserialize)
45}
46
47/// Where an agent sorts among the agents of a session: those nothing
48/// spawned first, each group by id. The first is the main agent, the one
49/// the user talks to when none is named.
50pub fn main_order(spawned: bool, id: &str) -> (bool, &str) {
51    (spawned, id)
52}
53
54impl Session {
55    /// The session's own saved value under `key` (the [`SESSION`](crate::SESSION)
56    /// log's), read as a `T`: `None` when it has none, an error when the
57    /// value is not a `T`.
58    pub fn value<T: DeserializeOwned>(&self, key: &str) -> Option<Result<T, serde_json::Error>> {
59        value(&self.saved, key)
60    }
61
62    /// The main agent: the first by [`main_order`] of the agents a restore
63    /// brings back (not retired, nor spawned by one retired).
64    pub fn main_agent(&self) -> Option<&SavedAgent> {
65        let logs = self.agents.iter().map(|agent| {
66            let parent = agent.parent.as_deref();
67            (agent.id.as_str(), parent, agent.retired)
68        });
69        let skipped = skipped(logs);
70        self.agents
71            .iter()
72            .filter(|agent| !skipped.contains(agent.id.as_str()))
73            .min_by_key(|agent| main_order(agent.parent.is_some(), &agent.id))
74    }
75}
76
77#[cfg(test)]
78mod tests;