Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T02:55:53.154Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

render.rs

264 lines · 9.2 KB · rust
1//! Render public-safe inspector and room-header field rows.
2//!
3//! Output is structured label/value pairs for GPUI or tests. Values never
4//! include raw tokens, private paths, or unbounded tool content.
5
6use crate::public_ref::PublicRef;
7use crate::receipt::AuthorityReceiptDetail;
8use crate::room_header::RoomAuthorityHeader;
9
10/// Conversation header title per spec §9.6 — name only, no authority details.
11pub const CONVERSATION_HEADER_TITLE: &str = "Sarah";
12
13/// One label/value row in the inspector or room header strip.
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct InspectorField {
16    pub label: &'static str,
17    pub value: String,
18}
19
20impl InspectorField {
21    pub fn new(label: &'static str, value: impl Into<String>) -> Self {
22        Self {
23            label,
24            value: value.into(),
25        }
26    }
27
28    pub fn line(&self) -> String {
29        format!("{}: {}", self.label, self.value)
30    }
31}
32
33/// Details view for one activity/receipt row.
34#[derive(Clone, Debug, PartialEq, Eq)]
35pub struct ReceiptInspectorView {
36    pub fields: Vec<InspectorField>,
37    pub allowed: bool,
38}
39
40impl ReceiptInspectorView {
41    pub fn lines(&self) -> Vec<String> {
42        self.fields.iter().map(InspectorField::line).collect()
43    }
44
45    pub fn joined_text(&self) -> String {
46        self.lines().join("\n")
47    }
48
49    pub fn field_value(&self, label: &str) -> Option<&str> {
50        self.fields
51            .iter()
52            .find(|f| f.label == label)
53            .map(|f| f.value.as_str())
54    }
55}
56
57/// Room header area authority strip (separate from conversation header).
58#[derive(Clone, Debug, PartialEq, Eq)]
59pub struct RoomHeaderAuthorityView {
60    /// Always `Sarah` — must not include profile or revision.
61    pub conversation_header: &'static str,
62    pub fields: Vec<InspectorField>,
63}
64
65impl RoomHeaderAuthorityView {
66    pub fn lines(&self) -> Vec<String> {
67        self.fields.iter().map(InspectorField::line).collect()
68    }
69
70    pub fn joined_text(&self) -> String {
71        self.lines().join("\n")
72    }
73}
74
75/// Render the details view for one receipt row.
76pub fn render_receipt_detail(detail: &AuthorityReceiptDetail) -> ReceiptInspectorView {
77    let mut fields = vec![
78        InspectorField::new("tool_ref", detail.tool_ref.as_str()),
79        InspectorField::new("allowed", if detail.allowed { "true" } else { "false" }),
80        InspectorField::new(
81            "authority_receipt_ref",
82            detail.authority_receipt_ref.as_str(),
83        ),
84        InspectorField::new("decision_ref", detail.decision_ref.as_str()),
85        InspectorField::new(
86            "bounded_result_ref",
87            detail
88                .bounded_result_ref
89                .as_ref()
90                .map(PublicRef::as_str)
91                .unwrap_or("—"),
92        ),
93    ];
94
95    if let Some(refusal) = &detail.refusal {
96        fields.push(InspectorField::new(
97            "reason_class",
98            refusal.reason_class.as_label(),
99        ));
100        if let Some(category) = &refusal.reserved_category {
101            fields.push(InspectorField::new(
102                "reserved_category",
103                category.as_str(),
104            ));
105        }
106    }
107
108    ReceiptInspectorView {
109        fields,
110        allowed: detail.allowed,
111    }
112}
113
114/// Render the room header authority strip.
115///
116/// Conversation header stays `Sarah`. Profile ref and revision live here only.
117pub fn render_room_header_authority(header: &RoomAuthorityHeader) -> RoomHeaderAuthorityView {
118    RoomHeaderAuthorityView {
119        conversation_header: CONVERSATION_HEADER_TITLE,
120        fields: vec![
121            InspectorField::new(
122                "authority_profile_ref",
123                header.authority_profile_ref.as_str(),
124            ),
125            InspectorField::new(
126                "authority_revision",
127                header.authority_revision.to_string(),
128            ),
129        ],
130    }
131}
132
133#[cfg(test)]
134mod tests {
135    use super::*;
136    use crate::public_ref::PublicRef;
137    use crate::receipt::{
138        AuthorityReceiptDetail, RefusalDetail, RefusalReasonClass, RawAuthorityBlock,
139    };
140    use crate::room_header::RoomAuthorityHeader;
141
142    fn allowed_detail() -> AuthorityReceiptDetail {
143        AuthorityReceiptDetail::from_raw(RawAuthorityBlock {
144            tool_ref: "tool.sarah.list_full_auto_runs",
145            allowed: true,
146            authority_receipt_ref: "receipt.authority.sarah.tool.ok.1",
147            decision_ref: "decision.sarah.tool.call-ok",
148            result_refs: &["result.full_auto.list.page1"],
149            bounded_result_ref: None,
150            refusal_reason: None,
151            reserved_category: None,
152        })
153        .expect("allowed")
154    }
155
156    fn refused_detail() -> AuthorityReceiptDetail {
157        AuthorityReceiptDetail::from_raw(RawAuthorityBlock {
158            tool_ref: "tool.sarah.export_secret",
159            allowed: false,
160            authority_receipt_ref: "receipt.authority.sarah.tool.refuse.1",
161            decision_ref: "decision.sarah.tool.call-refuse",
162            result_refs: &["blocker.sarah.authority_refused"],
163            bounded_result_ref: None,
164            refusal_reason: Some("reserved_action"),
165            reserved_category: Some("reserved.secret_export"),
166        })
167        .expect("refused")
168    }
169
170    #[test]
171    fn renders_allowed_receipt_fields() {
172        let view = render_receipt_detail(&allowed_detail());
173        assert!(view.allowed);
174        assert_eq!(
175            view.field_value("tool_ref"),
176            Some("tool.sarah.list_full_auto_runs")
177        );
178        assert_eq!(view.field_value("allowed"), Some("true"));
179        assert_eq!(
180            view.field_value("authority_receipt_ref"),
181            Some("receipt.authority.sarah.tool.ok.1")
182        );
183        assert_eq!(
184            view.field_value("decision_ref"),
185            Some("decision.sarah.tool.call-ok")
186        );
187        assert_eq!(
188            view.field_value("bounded_result_ref"),
189            Some("result.full_auto.list.page1")
190        );
191        assert!(view.field_value("reason_class").is_none());
192        assert!(view.field_value("reserved_category").is_none());
193        let text = view.joined_text();
194        assert!(!text.contains("sk-"));
195        assert!(!text.contains("/Users/"));
196    }
197
198    #[test]
199    fn renders_refused_receipt_with_reason_class_and_reserved_category() {
200        let view = render_receipt_detail(&refused_detail());
201        assert!(!view.allowed);
202        assert_eq!(view.field_value("allowed"), Some("false"));
203        assert_eq!(view.field_value("reason_class"), Some("reserved_action"));
204        assert_eq!(
205            view.field_value("reserved_category"),
206            Some("reserved.secret_export")
207        );
208        // Refusals are not errors in the label set — reason_class is explicit.
209        let labels: Vec<_> = view.fields.iter().map(|f| f.label).collect();
210        assert!(!labels.contains(&"error"));
211        assert!(labels.contains(&"reason_class"));
212    }
213
214    #[test]
215    fn room_header_holds_profile_conversation_header_is_sarah_only() {
216        let header = RoomAuthorityHeader::from_raw("openagents.sarah-owner-orchestrator", 6)
217            .expect("header");
218        let view = render_room_header_authority(&header);
219        assert_eq!(view.conversation_header, "Sarah");
220        assert_eq!(view.conversation_header, CONVERSATION_HEADER_TITLE);
221        assert_eq!(
222            view.fields
223                .iter()
224                .find(|f| f.label == "authority_profile_ref")
225                .map(|f| f.value.as_str()),
226            Some("openagents.sarah-owner-orchestrator")
227        );
228        assert_eq!(
229            view.fields
230                .iter()
231                .find(|f| f.label == "authority_revision")
232                .map(|f| f.value.as_str()),
233            Some("6")
234        );
235        // Conversation header must not carry authority text.
236        assert!(!view.conversation_header.contains("openagents"));
237        assert!(!view.conversation_header.contains("revision"));
238        assert!(!view.conversation_header.contains("6"));
239    }
240
241    #[test]
242    fn rendering_never_includes_dropped_unsafe_material() {
243        let detail = AuthorityReceiptDetail {
244            tool_ref: PublicRef::new("tool.sarah.safe").unwrap(),
245            allowed: false,
246            authority_receipt_ref: PublicRef::new("receipt.authority.sarah.tool.x").unwrap(),
247            decision_ref: PublicRef::new("decision.sarah.tool.x").unwrap(),
248            bounded_result_ref: Some(PublicRef::new("blocker.sarah.authority_refused").unwrap()),
249            bounded_result_refs: vec![PublicRef::new("blocker.sarah.authority_refused").unwrap()],
250            refusal: Some(RefusalDetail::new(
251                RefusalReasonClass::ReservedAction,
252                Some(PublicRef::new("reserved.secret_export").unwrap()),
253            )),
254        };
255        let text = render_receipt_detail(&detail).joined_text();
256        assert!(!text.contains("Bearer"));
257        assert!(!text.contains("sk-"));
258        assert!(!text.contains("/Users/"));
259        assert!(!text.contains("OPENAGENTS_AGENT_TOKEN"));
260        assert!(text.contains("reserved_action"));
261        assert!(text.contains("reserved.secret_export"));
262    }
263}
264
Served at tenant.openagents/omega Member data and write actions are omitted.