Skip to main content

forge_agent/translate/
agents.rs

1//! Available-agents catalogue parser. Used by the session task's fold
2//! to turn a `system/init.agents` payload into the `AvailableAgent` list
3//! the server carries.
4
5use serde_json::Value;
6
7use forge_primitives::AvailableAgent;
8
9/// Mirrors `mapAvailableAgentsFromNames(value)` - agents listed as
10/// plain strings (no descriptions). Used when the CLI emits a names-
11/// only list.
12pub fn map_available_agents_from_names(value: Option<&Value>) -> Vec<AvailableAgent> {
13    let Some(arr) = value.and_then(Value::as_array) else {
14        return Vec::new();
15    };
16    let mut by_name: std::collections::BTreeMap<String, AvailableAgent> =
17        std::collections::BTreeMap::new();
18    for entry in arr {
19        let Some(name) = entry.as_str() else { continue };
20        let name = name.trim().to_owned();
21        if name.is_empty() {
22            continue;
23        }
24        by_name.entry(name.clone()).or_insert_with(|| AvailableAgent {
25            name,
26            description: String::new(),
27            model: None,
28        });
29    }
30    by_name.into_values().collect()
31}
32
33#[cfg(test)]
34mod tests {
35    use super::*;
36    use serde_json::json;
37
38    #[test]
39    fn map_agents_from_names_dedupes_and_sorts() {
40        let v = json!(["b", "a", "a", " ", "c"]);
41        let agents = map_available_agents_from_names(Some(&v));
42        assert_eq!(agents.iter().map(|a| a.name.as_str()).collect::<Vec<_>>(), vec!["a", "b", "c"]);
43    }
44}