1use crate::ids::{ModelId, ModelVersion, SessionId};
10use crate::value_objects::{
11 DeviceTarget, ModelFormat, RuntimeKind, SafetyMode, SpeculationMode, StopReason,
12};
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum DegradeReason {
18 Disabled,
19 MemoryPressure,
20 MidRangeProfile,
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum DomainEvent {
27 SessionInitialized {
29 runtime: RuntimeKind,
30 device: DeviceTarget,
31 safety: SafetyMode,
32 speculation: SpeculationMode,
33 },
34 ModelLoaded {
35 model: ModelId,
36 version: ModelVersion,
37 format: ModelFormat,
38 },
39 PrefillCompleted {
40 prompt_tokens: u32,
41 kv_len: u32,
42 prefill_tps: u32,
43 },
44 TokenGenerated {
45 sampled: bool,
46 },
47 TokenCommitted {
48 kv_len: u32,
49 },
50 GenerationCompleted {
51 total_tokens: u32,
52 stop: StopReason,
53 },
54 SessionReset,
55 HybridRelayConsulted,
56
57 PromptCompressed {
59 input_tokens: u32,
60 output_tokens: u32,
61 ratio_milli: u32,
63 },
64 CompressionSkipped {
65 reason: DegradeReason,
66 },
67
68 DraftProposed {
70 draft_len: u8,
71 },
72 DraftVerified {
73 accepted: u8,
74 first_reject: u8,
75 },
76 SpeculationDisabled {
77 reason: DegradeReason,
78 },
79
80 GrammarSwitched {
82 from_state: u32,
83 to_state: u32,
84 },
85 TokenMaskApplied {
86 allowed: u32,
87 },
88 GrammarViolationBlocked,
89
90 SafetyModeSelected {
92 mode: SafetyMode,
93 },
94 LogitsSteered {
95 adjustment_norm_milli: u32,
96 },
97 SafetyViolationDetected {
98 score_milli: u16,
99 threshold_milli: u16,
100 },
101 ClaimBacktracked {
102 claim_index: u32,
103 },
104 SafetyDisabled {
105 reason: DegradeReason,
106 },
107
108 MemoryPlanCreated {
110 total_bytes: u64,
111 sram_bytes: u64,
112 dram_bytes: u64,
113 },
114 KvCacheCompacted {
115 reclaimed: u32,
116 },
117 MemoryBudgetExceeded {
118 requested_bytes: u64,
119 budget_bytes: u64,
120 },
121
122 DeviceProfiled {
124 profile: DeviceTarget,
125 npu_tops: u16,
126 bandwidth_gbs: u16,
127 },
128 DelegateSelected {
129 partitions: u8,
130 },
131 DelegateFellBack,
132
133 ModelSignatureVerified {
135 model: ModelId,
136 version: ModelVersion,
137 },
138 ModelSignatureRejected {
139 model: ModelId,
140 },
141
142 MetricsSampled {
144 decode_tps: u32,
145 ttft_ms: u32,
146 peak_bytes: u64,
147 },
148
149 FrontierLlmConsulted {
154 provider_hash: u32,
155 prompt_tokens: u32,
156 completion_tokens: u32,
157 },
158}
159
160#[derive(Debug, Clone, Copy, PartialEq, Eq)]
163pub struct EventEnvelope {
164 pub session: SessionId,
165 pub step: u32,
166 pub event: DomainEvent,
167}
168
169impl EventEnvelope {
170 pub fn new(session: SessionId, step: u32, event: DomainEvent) -> Self {
171 Self {
172 session,
173 step,
174 event,
175 }
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182
183 fn _assert_copy<T: Copy>() {}
186 #[test]
187 fn events_are_content_free_by_construction() {
188 _assert_copy::<DomainEvent>();
189 _assert_copy::<EventEnvelope>();
190 }
191
192 #[test]
193 fn envelope_carries_step_and_session() {
194 let e = EventEnvelope::new(
195 SessionId(1),
196 4,
197 DomainEvent::TokenGenerated { sampled: true },
198 );
199 assert_eq!(e.step, 4);
200 assert_eq!(e.session, SessionId(1));
201 }
202}