Skip to main content

agentmux_mcp/tools/
global_memory.rs

1// Copyright 2026, AgentMux Corp.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Global Memory.
5
6use super::*;
7
8pub(super) async fn call(name: &str, arguments: &Value, cx: &ToolCtx<'_>) -> Result<String> {
9    let ToolCtx { local_url, auth_key, block_id, client, .. } = *cx;
10    match name {
11        "GlobalMemoryList" => {
12            require_agent_env(local_url, auth_key, block_id)?;
13            let url = format!("{}/api/v1/agent/globalmemory/list", local_url.trim_end_matches('/'));
14            let resp = client
15                .get(&url)
16                .header(AUTH_KEY_HEADER, auth_key)
17                .send()
18                .await
19                .map_err(|e| anyhow::anyhow!("request failed: {e}"))?;
20            if !resp.status().is_success() {
21                let status = resp.status();
22                let text = resp.text().await.unwrap_or_default();
23                anyhow::bail!("globalmemory/list failed: HTTP {status} — {text}");
24            }
25            let result: Value = resp
26                .json()
27                .await
28                .map_err(|e| anyhow::anyhow!("response parse failed: {e}"))?;
29            Ok(serde_json::to_string_pretty(&result).unwrap_or_else(|_| result.to_string()))
30        }
31        "GlobalMemoryRead" => {
32            let id = arguments
33                .get("id")
34                .and_then(|v| v.as_str())
35                .filter(|s| !s.is_empty())
36                .ok_or_else(|| anyhow::anyhow!("missing required parameter: id"))?;
37            require_agent_env(local_url, auth_key, block_id)?;
38            let url = format!("{}/api/v1/agent/globalmemory/read", local_url.trim_end_matches('/'));
39            let resp = client
40                .get(&url)
41                .header(AUTH_KEY_HEADER, auth_key)
42                .query(&[("id", id)])
43                .send()
44                .await
45                .map_err(|e| anyhow::anyhow!("request failed: {e}"))?;
46            if !resp.status().is_success() {
47                let status = resp.status();
48                let text = resp.text().await.unwrap_or_default();
49                anyhow::bail!("globalmemory/read failed: HTTP {status} — {text}");
50            }
51            let result: Value = resp
52                .json()
53                .await
54                .map_err(|e| anyhow::anyhow!("response parse failed: {e}"))?;
55            Ok(result
56                .get("content")
57                .and_then(|v| v.as_str())
58                .map(str::to_string)
59                .unwrap_or_else(|| {
60                    serde_json::to_string_pretty(&result).unwrap_or_else(|_| result.to_string())
61                }))
62        }
63        "GlobalMemoryWrite" => {
64            let name = arguments
65                .get("name")
66                .and_then(|v| v.as_str())
67                .filter(|s| !s.is_empty())
68                .ok_or_else(|| anyhow::anyhow!("missing required parameter: name"))?;
69            let content = arguments
70                .get("content")
71                .and_then(|v| v.as_str())
72                .ok_or_else(|| anyhow::anyhow!("missing required parameter: content"))?;
73            require_agent_env(local_url, auth_key, block_id)?;
74            let agent_id = agent_slug()?;
75            let url = format!("{}/api/v1/agent/globalmemory/write", local_url.trim_end_matches('/'));
76            let mut body = json!({
77                "agent_id": agent_id,
78                "name": name,
79                "content": content,
80            });
81            if let Some(id) = arguments.get("id").and_then(|v| v.as_str()).filter(|s| !s.is_empty()) {
82                body["id"] = json!(id);
83            }
84            // Pass provenance through verbatim when the caller supplied it —
85            // same advisory-metadata pattern as MemoryWrite above.
86            if let Some(provenance) = arguments.get("provenance") {
87                body["provenance"] = provenance.clone();
88            }
89            let resp = client
90                .post(&url)
91                .header(AUTH_KEY_HEADER, auth_key)
92                .json(&body)
93                .send()
94                .await
95                .map_err(|e| anyhow::anyhow!("request failed: {e}"))?;
96            if !resp.status().is_success() {
97                let status = resp.status();
98                let text = resp.text().await.unwrap_or_default();
99                anyhow::bail!("globalmemory/write failed: HTTP {status} — {text}");
100            }
101            let result: Value = resp
102                .json()
103                .await
104                .map_err(|e| anyhow::anyhow!("response parse failed: {e}"))?;
105            let id = result.get("id").and_then(|v| v.as_str()).unwrap_or("?");
106            Ok(format!("Wrote Global Memory entry \"{name}\" (id: {id})"))
107        }
108        "GlobalMemoryRemove" => {
109            let id = arguments
110                .get("id")
111                .and_then(|v| v.as_str())
112                .filter(|s| !s.is_empty())
113                .ok_or_else(|| anyhow::anyhow!("missing required parameter: id"))?;
114            require_agent_env(local_url, auth_key, block_id)?;
115            let url = format!("{}/api/v1/agent/globalmemory/remove", local_url.trim_end_matches('/'));
116            let body = json!({ "id": id });
117            let resp = client
118                .post(&url)
119                .header(AUTH_KEY_HEADER, auth_key)
120                .json(&body)
121                .send()
122                .await
123                .map_err(|e| anyhow::anyhow!("request failed: {e}"))?;
124            if !resp.status().is_success() {
125                let status = resp.status();
126                let text = resp.text().await.unwrap_or_default();
127                anyhow::bail!("globalmemory/remove failed: HTTP {status} — {text}");
128            }
129            Ok(format!("Removed Global Memory entry {id}"))
130        }
131        "GlobalMemoryHistory" => {
132            let id = arguments
133                .get("id")
134                .and_then(|v| v.as_str())
135                .filter(|s| !s.is_empty())
136                .ok_or_else(|| anyhow::anyhow!("missing required parameter: id"))?;
137            require_agent_env(local_url, auth_key, block_id)?;
138            let url = format!("{}/api/v1/agent/globalmemory/history", local_url.trim_end_matches('/'));
139            let resp = client
140                .get(&url)
141                .header(AUTH_KEY_HEADER, auth_key)
142                .query(&[("id", id)])
143                .send()
144                .await
145                .map_err(|e| anyhow::anyhow!("request failed: {e}"))?;
146            if !resp.status().is_success() {
147                let status = resp.status();
148                let text = resp.text().await.unwrap_or_default();
149                anyhow::bail!("globalmemory/history failed: HTTP {status} — {text}");
150            }
151            let result: Value = resp
152                .json()
153                .await
154                .map_err(|e| anyhow::anyhow!("response parse failed: {e}"))?;
155            Ok(serde_json::to_string_pretty(&result).unwrap_or_else(|_| result.to_string()))
156        }
157        "GlobalMemoryDiff" => {
158            let id = arguments
159                .get("id")
160                .and_then(|v| v.as_str())
161                .filter(|s| !s.is_empty())
162                .ok_or_else(|| anyhow::anyhow!("missing required parameter: id"))?;
163            let from_version_id = arguments
164                .get("from_version_id")
165                .and_then(|v| v.as_str())
166                .filter(|s| !s.is_empty())
167                .ok_or_else(|| anyhow::anyhow!("missing required parameter: from_version_id"))?;
168            let to_version_id = arguments
169                .get("to_version_id")
170                .and_then(|v| v.as_str())
171                .filter(|s| !s.is_empty())
172                .ok_or_else(|| anyhow::anyhow!("missing required parameter: to_version_id"))?;
173            require_agent_env(local_url, auth_key, block_id)?;
174            let url = format!("{}/api/v1/agent/globalmemory/diff", local_url.trim_end_matches('/'));
175            let resp = client
176                .get(&url)
177                .header(AUTH_KEY_HEADER, auth_key)
178                .query(&[("id", id), ("from_version_id", from_version_id), ("to_version_id", to_version_id)])
179                .send()
180                .await
181                .map_err(|e| anyhow::anyhow!("request failed: {e}"))?;
182            if !resp.status().is_success() {
183                let status = resp.status();
184                let text = resp.text().await.unwrap_or_default();
185                anyhow::bail!("globalmemory/diff failed: HTTP {status} — {text}");
186            }
187            let result: Value = resp
188                .json()
189                .await
190                .map_err(|e| anyhow::anyhow!("response parse failed: {e}"))?;
191            Ok(result
192                .get("diff")
193                .and_then(|v| v.as_str())
194                .map(str::to_string)
195                .unwrap_or_else(|| {
196                    serde_json::to_string_pretty(&result).unwrap_or_else(|_| result.to_string())
197                }))
198        }
199        "GlobalMemoryRevert" => {
200            let id = arguments
201                .get("id")
202                .and_then(|v| v.as_str())
203                .filter(|s| !s.is_empty())
204                .ok_or_else(|| anyhow::anyhow!("missing required parameter: id"))?;
205            let version_id = arguments
206                .get("version_id")
207                .and_then(|v| v.as_str())
208                .filter(|s| !s.is_empty())
209                .ok_or_else(|| anyhow::anyhow!("missing required parameter: version_id"))?;
210            require_agent_env(local_url, auth_key, block_id)?;
211            let agent_id = agent_slug()?;
212            let url = format!("{}/api/v1/agent/globalmemory/revert", local_url.trim_end_matches('/'));
213            let body = json!({
214                "agent_id": agent_id,
215                "id": id,
216                "version_id": version_id,
217            });
218            let resp = client
219                .post(&url)
220                .header(AUTH_KEY_HEADER, auth_key)
221                .json(&body)
222                .send()
223                .await
224                .map_err(|e| anyhow::anyhow!("request failed: {e}"))?;
225            if !resp.status().is_success() {
226                let status = resp.status();
227                let text = resp.text().await.unwrap_or_default();
228                anyhow::bail!("globalmemory/revert failed: HTTP {status} — {text}");
229            }
230            Ok(format!("Reverted Global Memory entry {id} to version {version_id}"))
231        }
232        _ => Err(not_in_family()),
233    }
234}