|
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
|
/// Time to first token, in milliseconds. Only the streaming path can |
|
36
|
/// observe this; a blocking `send_message` gets the whole response at |
|
37
|
/// once and reports `None` rather than a stand-in value. |
|
38
|
#[serde(skip_serializing_if = "Option::is_none")] |
|
39
|
pub ttft_ms: Option<u64>, |
|
40
|
/// `"success"`, `"cancelled"`, or `"error"`. A blocking request only |
|
41
|
/// reports `"success"`, since its errors return before reaching pulse. A |
|
42
|
/// stream can fail after it starts, so a mid-stream model error reports |
|
43
|
/// `"error"`, usually with no `ttft_ms`, and a stream whose receiver was |
|
44
|
/// dropped reports `"cancelled"`. |
|
45
|
pub status: String, |
|
46
|
/// Same Onde app as the corresponding `ModelLoadedEvent`. `None` for SDK |
|
47
|
/// builds without app credentials or direct Rust consumers. |
|
48
|
#[serde(skip_serializing_if = "Option::is_none")] |
|
49
|
pub onde_app_id: Option<String>, |
|
50
|
} |
|
51
|
|
|
52
|
#[cfg(test)] |
|
53
|
mod tests { |
|
54
|
use super::*; |
|
55
|
|
|
56
|
#[test] |
|
57
|
fn model_loaded_serializes_onde_app_id_when_present() { |
|
58
|
let event = ModelLoadedEvent { |
|
59
|
edge_id: "edge-1".into(), |
|
60
|
model_id: "org/repo".into(), |
|
61
|
model_name: "Repo 3B".into(), |
|
62
|
load_duration_ms: 1234, |
|
63
|
onde_app_id: Some("app-uuid".into()), |
|
64
|
}; |
|
65
|
let value = serde_json::to_value(&event).expect("serialize"); |
|
66
|
assert_eq!(value["onde_app_id"], "app-uuid"); |
|
67
|
assert_eq!(value["load_duration_ms"], 1234); |
|
68
|
} |
|
69
|
|
|
70
|
#[test] |
|
71
|
fn onde_app_id_is_omitted_when_absent() { |
|
72
|
let event = InferenceEvent { |
|
73
|
edge_id: "edge-1".into(), |
|
74
|
model_id: "org/repo".into(), |
|
75
|
request_id: "onde-1-0".into(), |
|
76
|
duration_ms: 42, |
|
77
|
ttft_ms: None, |
|
78
|
status: "success".into(), |
|
79
|
onde_app_id: None, |
|
80
|
}; |
|
81
|
let value = serde_json::to_value(&event).expect("serialize"); |
|
82
|
assert!(value.get("onde_app_id").is_none()); |
|
83
|
} |
|
84
|
|
|
85
|
#[test] |
|
86
|
fn ttft_is_omitted_when_the_path_cannot_measure_it() { |
|
87
|
let mut event = InferenceEvent { |
|
88
|
edge_id: "edge-1".into(), |
|
89
|
model_id: "org/repo".into(), |
|
90
|
request_id: "onde-1-0".into(), |
|
91
|
duration_ms: 42, |
|
92
|
ttft_ms: None, |
|
93
|
status: "success".into(), |
|
94
|
onde_app_id: None, |
|
95
|
}; |
|
96
|
assert!(serde_json::to_value(&event) |
|
97
|
.expect("serialize") |
|
98
|
.get("ttft_ms") |
|
99
|
.is_none()); |
|
100
|
|
|
101
|
event.ttft_ms = Some(17); |
|
102
|
assert_eq!( |
|
103
|
serde_json::to_value(&event).expect("serialize")["ttft_ms"], |
|
104
|
17 |
|
105
|
); |
|
106
|
} |
|
107
|
} |