1 use serde::Serialize;
2
3 /// What gets sent to GresIQ when a model finishes loading.
4 #[derive(Debug, Clone, Serialize)]
5 pub struct ModelLoadedEvent {
6 /// Which machine this is. Keep it stable across restarts — change it
7 /// and you'll get a duplicate edge row in the dashboard.
8 pub edge_id: String,
9 /// The HuggingFace repo ID, e.g. `bartowski/Qwen2.5-3B-Instruct-GGUF`.
10 pub model_id: String,
11 /// What shows up in the UI, e.g. `Qwen 2.5 3B`.
12 pub model_name: String,
13 /// How long the load took. This is `elapsed.as_millis() as u64`,
14 /// where `elapsed` is what `load_gguf_model` returns.
15 pub load_duration_ms: u64,
16 /// The Onde app that loaded this model (UUID string from the
17 /// ondeinference.com dashboard). `None` for SDK builds without app
18 /// credentials or for direct Rust consumers. In the document store this
19 /// is a plain field on the `pulse_models` doc, not a foreign key.
20 #[serde(skip_serializing_if = "Option::is_none")]
21 pub onde_app_id: Option<String>,
22 }
23
24 /// What gets sent to GresIQ after each `send_message` or `generate`.
25 #[derive(Debug, Clone, Serialize)]
26 pub struct InferenceEvent {
27 /// Same edge as in `ModelLoadedEvent`.
28 pub edge_id: String,
29 /// Same model as in `ModelLoadedEvent`.
30 pub model_id: String,
31 /// Auto-generated per request. Looks like `onde-1720000000000-42`.
32 pub request_id: String,
33 /// Wall-clock time for the whole response, in milliseconds.
34 pub duration_ms: u64,
35 /// `"success"`, `"cancelled"`, or `"error"`. Currently always
36 /// `"success"` here — inference errors throw before we reach this point.
37 pub status: String,
38 /// Same Onde app as the corresponding `ModelLoadedEvent`. `None` for SDK
39 /// builds without app credentials or direct Rust consumers.
40 #[serde(skip_serializing_if = "Option::is_none")]
41 pub onde_app_id: Option<String>,
42 }
43
44 #[cfg(test)]
45 mod tests {
46 use super::*;
47
48 #[test]
49 fn model_loaded_serializes_onde_app_id_when_present() {
50 let event = ModelLoadedEvent {
51 edge_id: "edge-1".into(),
52 model_id: "org/repo".into(),
53 model_name: "Repo 3B".into(),
54 load_duration_ms: 1234,
55 onde_app_id: Some("app-uuid".into()),
56 };
57 let value = serde_json::to_value(&event).expect("serialize");
58 assert_eq!(value["onde_app_id"], "app-uuid");
59 assert_eq!(value["load_duration_ms"], 1234);
60 }
61
62 #[test]
63 fn onde_app_id_is_omitted_when_absent() {
64 let event = InferenceEvent {
65 edge_id: "edge-1".into(),
66 model_id: "org/repo".into(),
67 request_id: "onde-1-0".into(),
68 duration_ms: 42,
69 status: "success".into(),
70 onde_app_id: None,
71 };
72 let value = serde_json::to_value(&event).expect("serialize");
73 assert!(value.get("onde_app_id").is_none());
74 }
75 }