@celestia-island/plana-types 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.toml +38 -0
- package/bindings/FileAnchor.ts +3 -0
- package/bindings/engine.ts +277 -0
- package/bindings/enums.ts +31 -0
- package/bindings/httpTypes.ts +197 -0
- package/bindings/index.ts +47 -0
- package/bindings/mcp/aporia.ts +61 -0
- package/bindings/mcp/eleos.ts +18 -0
- package/bindings/mcp/epieikeia.ts +48 -0
- package/bindings/mcp/haplotes.ts +47 -0
- package/bindings/mcp/hubris.ts +41 -0
- package/bindings/mcp/index.ts +13 -0
- package/bindings/mcp/kalos.ts +47 -0
- package/bindings/mcp/neikos.ts +76 -0
- package/bindings/mcp/orexis.ts +64 -0
- package/bindings/mcp/philia.ts +57 -0
- package/bindings/mcp/polemos.ts +55 -0
- package/bindings/mcp/skemma.ts +58 -0
- package/bindings/mcp/skopeo.ts +56 -0
- package/bindings/mcp/webAutomation.ts +31 -0
- package/bindings/model.ts +240 -0
- package/bindings/package.json +16 -0
- package/bindings/region.ts +3 -0
- package/bindings/serde_json/JsonValue.ts +3 -0
- package/bindings/ws/agentLifecycle.ts +41 -0
- package/bindings/ws/auth.ts +15 -0
- package/bindings/ws/baseMessages.ts +7 -0
- package/bindings/ws/bridgeNetwork.ts +71 -0
- package/bindings/ws/core.ts +51 -0
- package/bindings/ws/fileBrowsing.ts +57 -0
- package/bindings/ws/handshake.ts +23 -0
- package/bindings/ws/industrial.ts +72 -0
- package/bindings/ws/knowledgeBase.ts +10 -0
- package/bindings/ws/layer2.ts +25 -0
- package/bindings/ws/llmProvider.ts +74 -0
- package/bindings/ws/logs.ts +11 -0
- package/bindings/ws/malkuth.ts +62 -0
- package/bindings/ws/noa.ts +17 -0
- package/bindings/ws/stateSync.ts +19 -0
- package/bindings/ws/systemUi.ts +5 -0
- package/bindings/ws/tasks.ts +6 -0
- package/bindings/ws/views.ts +163 -0
- package/bindings/ws/workspace.ts +11 -0
- package/bindings/ws/yolo.ts +32 -0
- package/examples/schema_dump.rs +51 -0
- package/package.json +6 -0
- package/pnpm-workspace.yaml +2 -0
- package/src/engine.rs +602 -0
- package/src/enums.rs +334 -0
- package/src/external_mcp.rs +132 -0
- package/src/http.rs +1077 -0
- package/src/identity.rs +160 -0
- package/src/lib.rs +1215 -0
- package/src/malkuth.rs +145 -0
- package/src/mcp/aporia.rs +272 -0
- package/src/mcp/eleos.rs +210 -0
- package/src/mcp/epieikeia.rs +194 -0
- package/src/mcp/haplotes.rs +310 -0
- package/src/mcp/hubris.rs +377 -0
- package/src/mcp/kalos.rs +251 -0
- package/src/mcp/mod.rs +23 -0
- package/src/mcp/neikos.rs +533 -0
- package/src/mcp/orexis.rs +493 -0
- package/src/mcp/philia.rs +267 -0
- package/src/mcp/polemos.rs +241 -0
- package/src/mcp/skemma.rs +442 -0
- package/src/mcp/skopeo.rs +282 -0
- package/src/mcp/web_automation.rs +122 -0
- package/src/model.rs +421 -0
- package/src/protocol/base_messages.rs +125 -0
- package/src/protocol/handshake.rs +364 -0
- package/src/protocol/jsonrpc.rs +888 -0
- package/src/protocol/mod.rs +10 -0
- package/src/rbac.rs +786 -0
- package/src/region.rs +362 -0
- package/src/tracing_helpers.rs +9 -0
- package/src/ws/agent/agent_lifecycle.rs +221 -0
- package/src/ws/agent/layer2.rs +126 -0
- package/src/ws/agent/mod.rs +9 -0
- package/src/ws/agent/state_sync.rs +111 -0
- package/src/ws/agent/tasks.rs +43 -0
- package/src/ws/agent/yolo.rs +161 -0
- package/src/ws/mod.rs +10 -0
- package/src/ws/services/auth.rs +99 -0
- package/src/ws/services/industrial.rs +647 -0
- package/src/ws/services/knowledge_base.rs +59 -0
- package/src/ws/services/llm_provider.rs +371 -0
- package/src/ws/services/mod.rs +7 -0
- package/src/ws/ui/bridge_network.rs +96 -0
- package/src/ws/ui/file_browsing.rs +88 -0
- package/src/ws/ui/logs.rs +55 -0
- package/src/ws/ui/mod.rs +11 -0
- package/src/ws/ui/noa.rs +105 -0
- package/src/ws/ui/system_ui.rs +27 -0
- package/src/ws/ui/views.rs +159 -0
- package/src/ws/ui/workspace.rs +73 -0
package/src/model.rs
ADDED
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
//! Unified model management — shared types for the entelecheia + shittim-chest
|
|
2
|
+
//! model lifecycle.
|
|
3
|
+
//!
|
|
4
|
+
//! ## Architecture
|
|
5
|
+
//!
|
|
6
|
+
//! **evernight owns all model deployment.** Neither the upstream engine
|
|
7
|
+
//! (scepter) nor the web UI (shittim-chest) loads, starts, or stops models
|
|
8
|
+
//! directly. They send requests; evernight handles the lifecycle:
|
|
9
|
+
//!
|
|
10
|
+
//! ```text
|
|
11
|
+
//! WebUI (chest) ──WS──▶ Scepter ──▶ evernight
|
|
12
|
+
//! Scepter (RAG) ──────────────────▶ evernight
|
|
13
|
+
//! │
|
|
14
|
+
//! ┌────────────────────┴────────────────────┐
|
|
15
|
+
//! │ GPU-first: detect GPU nodes → deploy │
|
|
16
|
+
//! │ vLLM / faster GPU backends │
|
|
17
|
+
//! │ GPU unavailable? → degrade to CPU: │
|
|
18
|
+
//! │ ollama / whisper.cpp / onnxruntime │
|
|
19
|
+
//! └─────────────────────────────────────────┘
|
|
20
|
+
//! ```
|
|
21
|
+
//!
|
|
22
|
+
//! **GPU-first, CPU-fallback.** evernight always attempts GPU first. Only
|
|
23
|
+
//! when no GPU is detected (or no GPU node is reachable) does it fall back
|
|
24
|
+
//! to CPU-only small models. CPU is a degraded mode, never the default.
|
|
25
|
+
//!
|
|
26
|
+
//! Arona provides the shared vocabulary so both sides describe models in the
|
|
27
|
+
//! same terms.
|
|
28
|
+
//!
|
|
29
|
+
//! ## Model categories
|
|
30
|
+
//!
|
|
31
|
+
//! | Category | Example | Primary consumer |
|
|
32
|
+
//! |---|---|---|
|
|
33
|
+
//! | LLM | gpt-5.5, claude-opus-4.8 | scepter (agent skill execution) |
|
|
34
|
+
//! | Embedding | bge-m3, nomic-embed-text | scepter (RAG / vector store) |
|
|
35
|
+
//! | Speech → Text | whisper tiny/base/small | chest (voice input → text) |
|
|
36
|
+
//! | Text → Speech | tts-1, elevenlabs | scepter (generation) |
|
|
37
|
+
|
|
38
|
+
use schemars::JsonSchema;
|
|
39
|
+
use serde::{Deserialize, Serialize};
|
|
40
|
+
use ts_rs::TS;
|
|
41
|
+
|
|
42
|
+
// ═══════════════════════════════════════════════════════════════
|
|
43
|
+
// Model category — what KIND of model is this?
|
|
44
|
+
// ═══════════════════════════════════════════════════════════════
|
|
45
|
+
|
|
46
|
+
/// Top-level model category. Determines which subsystem consumes the model.
|
|
47
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, TS, JsonSchema)]
|
|
48
|
+
#[ts(export, export_to = "model.ts")]
|
|
49
|
+
#[serde(rename_all = "snake_case")]
|
|
50
|
+
pub enum ModelCategory {
|
|
51
|
+
/// Large language model — chat, reasoning, tool use.
|
|
52
|
+
Llm,
|
|
53
|
+
/// Text embedding model — vector representation for RAG / similarity.
|
|
54
|
+
Embedding,
|
|
55
|
+
/// Speech-to-text — transcribe audio input to text.
|
|
56
|
+
SpeechToText,
|
|
57
|
+
/// Text-to-speech — synthesise audio from text.
|
|
58
|
+
TextToSpeech,
|
|
59
|
+
/// Image generation — DALL-E, Stable Diffusion, ComfyUI pipelines.
|
|
60
|
+
/// Consumed by the MediaFlow node graph (image_to_image, text_to_image nodes).
|
|
61
|
+
ImageGeneration,
|
|
62
|
+
/// 3D model generation — TRELLIS, Meshy, Rodin. Produces GLB / mesh output.
|
|
63
|
+
/// Consumed by the MediaFlow node graph (image_to_3d, text_to_3d nodes).
|
|
64
|
+
ThreeDGeneration,
|
|
65
|
+
/// Multimodal — models that accept text + image input in the same message
|
|
66
|
+
/// (glm-4.6v, glm-5v-turbo, GPT-4V). Used for vision critique nodes.
|
|
67
|
+
MultiModal,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/// Fine-grained model capability flags.
|
|
71
|
+
///
|
|
72
|
+
/// Whereas [`ModelCategory`] answers "what kind of model is this?",
|
|
73
|
+
/// `ModelCapability` answers "what specific things can this model do?".
|
|
74
|
+
/// Skills declare their `required_capabilities`; the scepter router filters
|
|
75
|
+
/// available models by capability intersection.
|
|
76
|
+
///
|
|
77
|
+
/// This replaces the scattered boolean flags (`supports_vision`,
|
|
78
|
+
/// `supports_function_calling` …) with a single extensible enum. The booleans
|
|
79
|
+
/// remain for backward compatibility but are superseded by this enum when
|
|
80
|
+
/// present.
|
|
81
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, TS, JsonSchema)]
|
|
82
|
+
#[ts(export, export_to = "model.ts")]
|
|
83
|
+
#[serde(rename_all = "snake_case")]
|
|
84
|
+
pub enum ModelCapability {
|
|
85
|
+
// ── Text / LLM ──
|
|
86
|
+
/// Standard chat / completion.
|
|
87
|
+
TextChat,
|
|
88
|
+
/// SSE streaming output.
|
|
89
|
+
TextStreaming,
|
|
90
|
+
/// Tool / function calling.
|
|
91
|
+
FunctionCalling,
|
|
92
|
+
/// Chain-of-thought / deep reasoning.
|
|
93
|
+
Reasoning,
|
|
94
|
+
/// Code generation (JavaScript, Python, OpenSCAD, CSG …).
|
|
95
|
+
CodeGeneration,
|
|
96
|
+
|
|
97
|
+
// ── Embedding ──
|
|
98
|
+
/// Text → vector embedding.
|
|
99
|
+
TextEmbedding,
|
|
100
|
+
|
|
101
|
+
// ── Audio ──
|
|
102
|
+
/// Audio → text (speech-to-text).
|
|
103
|
+
SpeechToText,
|
|
104
|
+
/// Text → audio (text-to-speech).
|
|
105
|
+
TextToSpeech,
|
|
106
|
+
|
|
107
|
+
// ── Vision / multimodal input ──
|
|
108
|
+
/// Accept image in chat messages (multimodal input).
|
|
109
|
+
ImageInput,
|
|
110
|
+
/// Accept video in chat messages.
|
|
111
|
+
VideoInput,
|
|
112
|
+
/// Analyse an image and produce a structured critique + improvement plan.
|
|
113
|
+
/// This is the key capability for the MediaFlow vision_critique node.
|
|
114
|
+
VisualCritique,
|
|
115
|
+
|
|
116
|
+
// ── Image generation ──
|
|
117
|
+
/// Text prompt → image.
|
|
118
|
+
TextToImage,
|
|
119
|
+
/// Image + text → modified image.
|
|
120
|
+
ImageToImage,
|
|
121
|
+
/// Inpainting / outpainting / selective editing.
|
|
122
|
+
ImageEdit,
|
|
123
|
+
/// Increase resolution with detail preservation.
|
|
124
|
+
ImageUpscale,
|
|
125
|
+
|
|
126
|
+
// ── 3D generation ──
|
|
127
|
+
/// Text prompt → 3D mesh (GLB).
|
|
128
|
+
#[serde(rename = "text_to_3d")]
|
|
129
|
+
TextTo3D,
|
|
130
|
+
/// Single / multi image → 3D mesh.
|
|
131
|
+
#[serde(rename = "image_to_3d")]
|
|
132
|
+
ImageTo3D,
|
|
133
|
+
/// Modify an existing 3D model programmatically (CSG, parametric).
|
|
134
|
+
#[serde(rename = "three_d_edit")]
|
|
135
|
+
ThreeDEdit,
|
|
136
|
+
/// Export to GLB / FBX / OBJ.
|
|
137
|
+
#[serde(rename = "three_d_export")]
|
|
138
|
+
ThreeDExport,
|
|
139
|
+
/// Generate PBR texture sets (albedo / normal / roughness / metalness).
|
|
140
|
+
#[serde(rename = "pbr_texturing")]
|
|
141
|
+
PBRTexturing,
|
|
142
|
+
/// Decimation, vertex merging, remeshing.
|
|
143
|
+
#[serde(rename = "mesh_optimization")]
|
|
144
|
+
MeshOptimization,
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/// Generation quality tier — applies to image / 3D generation models.
|
|
148
|
+
///
|
|
149
|
+
/// Distinct from [`super::ModelTier`] (which ranks LLM reasoning depth),
|
|
150
|
+
/// `GenerationTier` ranks output fidelity vs. speed for generative models.
|
|
151
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, TS, JsonSchema)]
|
|
152
|
+
#[ts(export, export_to = "model.ts")]
|
|
153
|
+
#[serde(rename_all = "snake_case")]
|
|
154
|
+
pub enum GenerationTier {
|
|
155
|
+
/// Low resolution, fast (≤30s). For iteration previews inside MediaFlow loops.
|
|
156
|
+
FastPreview,
|
|
157
|
+
/// Medium resolution (1–2 min). Default for most generation nodes.
|
|
158
|
+
Standard,
|
|
159
|
+
/// High resolution (5 min+). Final export quality.
|
|
160
|
+
Production,
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/// Minimum hardware requirements for a local generative model.
|
|
164
|
+
///
|
|
165
|
+
/// Populated for GPU-deployed models (TRELLIS, SDXL …). Remote-API models
|
|
166
|
+
/// leave this as `None`.
|
|
167
|
+
#[derive(Debug, Clone, Serialize, Deserialize, TS, JsonSchema)]
|
|
168
|
+
#[ts(export, export_to = "model.ts")]
|
|
169
|
+
pub struct HardwareRequirements {
|
|
170
|
+
/// Minimum VRAM in GB.
|
|
171
|
+
#[serde(default)]
|
|
172
|
+
#[ts(optional)]
|
|
173
|
+
pub min_vram_gb: Option<u32>,
|
|
174
|
+
/// Minimum system RAM in GB.
|
|
175
|
+
#[serde(default)]
|
|
176
|
+
#[ts(optional)]
|
|
177
|
+
pub min_ram_gb: Option<u32>,
|
|
178
|
+
/// Recommended GPU (e.g. `"NVIDIA RTX 4090"`).
|
|
179
|
+
#[serde(default)]
|
|
180
|
+
#[ts(optional)]
|
|
181
|
+
pub recommended_gpu: Option<String>,
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ═══════════════════════════════════════════════════════════════
|
|
185
|
+
// Execution backend — WHERE does the model run?
|
|
186
|
+
// ═══════════════════════════════════════════════════════════════
|
|
187
|
+
|
|
188
|
+
/// Where a model physically executes. evernight chooses the backend based on
|
|
189
|
+
/// GPU availability — GPU-first, CPU-fallback.
|
|
190
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, TS, JsonSchema)]
|
|
191
|
+
#[ts(export, export_to = "model.ts")]
|
|
192
|
+
#[serde(rename_all = "snake_case")]
|
|
193
|
+
pub enum ModelBackend {
|
|
194
|
+
/// Remote API (OpenAI, Anthropic, ZhiPu …). No local resources.
|
|
195
|
+
RemoteApi,
|
|
196
|
+
/// GPU node — either local (PCI passthrough) or remote (forwarded by
|
|
197
|
+
/// evernight to a GPU-equipped host). This is the **preferred** backend;
|
|
198
|
+
/// evernight always tries this first.
|
|
199
|
+
Gpu,
|
|
200
|
+
/// CPU fallback — used only when no GPU is detected or reachable.
|
|
201
|
+
/// Degraded mode: slower, smaller models.
|
|
202
|
+
Cpu,
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// ═══════════════════════════════════════════════════════════════
|
|
206
|
+
// Model descriptor — unified description of any model
|
|
207
|
+
// ═══════════════════════════════════════════════════════════════
|
|
208
|
+
|
|
209
|
+
/// A unified description of an AI model, shared between scepter and chest.
|
|
210
|
+
///
|
|
211
|
+
/// Both sides can enumerate available models, check their status, and request
|
|
212
|
+
/// inference using this common vocabulary.
|
|
213
|
+
#[derive(Debug, Clone, Serialize, Deserialize, TS, JsonSchema)]
|
|
214
|
+
#[ts(export, export_to = "model.ts")]
|
|
215
|
+
pub struct ModelDescriptor {
|
|
216
|
+
/// Unique id, e.g. `"bge-m3"`, `"whisper-tiny"`, `"claude-opus-4.8"`.
|
|
217
|
+
pub id: String,
|
|
218
|
+
/// Human-readable display name.
|
|
219
|
+
pub display_name: String,
|
|
220
|
+
/// What kind of model this is.
|
|
221
|
+
pub category: ModelCategory,
|
|
222
|
+
/// Where it runs.
|
|
223
|
+
pub backend: ModelBackend,
|
|
224
|
+
/// Size tier (LLM coding-plan concept; `None` for non-LLM models).
|
|
225
|
+
#[serde(default)]
|
|
226
|
+
#[ts(optional)]
|
|
227
|
+
pub tier: Option<ModelTier>,
|
|
228
|
+
/// Output dimension (embedding models only).
|
|
229
|
+
#[serde(default)]
|
|
230
|
+
#[ts(optional)]
|
|
231
|
+
pub dimension: Option<u32>,
|
|
232
|
+
/// Approximate model size in bytes (local models).
|
|
233
|
+
#[serde(default)]
|
|
234
|
+
#[ts(optional)]
|
|
235
|
+
pub size_bytes: Option<u64>,
|
|
236
|
+
/// Provider index (`#N` convention; LLM models only).
|
|
237
|
+
#[serde(default)]
|
|
238
|
+
#[ts(optional)]
|
|
239
|
+
pub provider_index: Option<u8>,
|
|
240
|
+
/// Fine-grained capability flags. When non-empty, the scepter router uses
|
|
241
|
+
/// these to match skills that declare `required_capabilities`. When empty,
|
|
242
|
+
/// falls back to the legacy boolean flags on `ModelFsInfo`.
|
|
243
|
+
#[serde(default)]
|
|
244
|
+
pub capabilities: Vec<ModelCapability>,
|
|
245
|
+
/// Generation quality tier (image / 3D generation models only).
|
|
246
|
+
#[serde(default)]
|
|
247
|
+
#[ts(optional)]
|
|
248
|
+
pub generation_tier: Option<GenerationTier>,
|
|
249
|
+
/// Hardware requirements (local generative models only).
|
|
250
|
+
#[serde(default)]
|
|
251
|
+
#[ts(optional)]
|
|
252
|
+
pub hardware_requirements: Option<HardwareRequirements>,
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/// Re-export so consumers don't need a separate import.
|
|
256
|
+
pub use super::ModelTier;
|
|
257
|
+
|
|
258
|
+
// ═══════════════════════════════════════════════════════════════
|
|
259
|
+
// Model server lifecycle — managed local model process
|
|
260
|
+
// ═══════════════════════════════════════════════════════════════
|
|
261
|
+
|
|
262
|
+
/// Status of a local model server (ollama, whisper.cpp, …).
|
|
263
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, TS, JsonSchema)]
|
|
264
|
+
#[ts(export, export_to = "model.ts")]
|
|
265
|
+
#[serde(rename_all = "snake_case")]
|
|
266
|
+
pub enum ModelServerStatus {
|
|
267
|
+
/// Server is running and accepting requests.
|
|
268
|
+
Running,
|
|
269
|
+
/// Server is starting up (model loading).
|
|
270
|
+
Starting,
|
|
271
|
+
/// Server is stopped.
|
|
272
|
+
Stopped,
|
|
273
|
+
/// Server failed to start.
|
|
274
|
+
Failed,
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/// A managed model server instance, deployed and owned by **evernight**.
|
|
278
|
+
/// Neither scepter nor chest starts/stops these directly — they issue
|
|
279
|
+
/// `RequestModelServerAction` and evernight performs the lifecycle.
|
|
280
|
+
#[derive(Debug, Clone, Serialize, Deserialize, TS, JsonSchema)]
|
|
281
|
+
#[ts(export, export_to = "model.ts")]
|
|
282
|
+
pub struct ModelServerInfo {
|
|
283
|
+
/// Server kind (determines the Docker image / launch command).
|
|
284
|
+
pub kind: ModelServerKind,
|
|
285
|
+
/// HTTP endpoint (e.g. `http://localhost:8178`).
|
|
286
|
+
pub endpoint: String,
|
|
287
|
+
/// Current lifecycle status.
|
|
288
|
+
pub status: ModelServerStatus,
|
|
289
|
+
/// Which backend this server is running on (GPU or CPU).
|
|
290
|
+
pub backend: ModelBackend,
|
|
291
|
+
/// Docker container id (managed by evernight's container runtime).
|
|
292
|
+
#[serde(default)]
|
|
293
|
+
#[ts(optional)]
|
|
294
|
+
pub container_id: Option<String>,
|
|
295
|
+
/// Which models are loaded in this server.
|
|
296
|
+
#[serde(default)]
|
|
297
|
+
pub loaded_models: Vec<String>,
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/// The type of model server. evernight deploys and manages these; the choice
|
|
301
|
+
/// of GPU vs CPU variant is made by evernight at deploy time (GPU-first).
|
|
302
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, TS, JsonSchema)]
|
|
303
|
+
#[ts(export, export_to = "model.ts")]
|
|
304
|
+
#[serde(rename_all = "snake_case")]
|
|
305
|
+
pub enum ModelServerKind {
|
|
306
|
+
/// Ollama — LLM + embedding models (GPU via candle/CUDA; CPU via GGUF fallback).
|
|
307
|
+
Ollama,
|
|
308
|
+
/// whisper.cpp — speech-to-text (GPU build when available; CPU otherwise).
|
|
309
|
+
WhisperCpp,
|
|
310
|
+
/// vLLM — high-throughput LLM serving. GPU-only (no CPU build).
|
|
311
|
+
Vllm,
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// ═══════════════════════════════════════════════════════════════
|
|
315
|
+
// Model request — how the web UI asks for inference
|
|
316
|
+
// ═══════════════════════════════════════════════════════════════
|
|
317
|
+
|
|
318
|
+
/// A model inference request, sent from the web UI to the upstream engine
|
|
319
|
+
/// over the WS JSON-RPC channel. The engine routes it to the appropriate
|
|
320
|
+
/// backend (local CPU / local GPU / remote GPU / remote API).
|
|
321
|
+
#[derive(Debug, Clone, Serialize, Deserialize, TS, JsonSchema)]
|
|
322
|
+
#[ts(export, export_to = "model.ts")]
|
|
323
|
+
pub struct ModelInferenceRequest {
|
|
324
|
+
/// Which model to use (by id).
|
|
325
|
+
pub model_id: String,
|
|
326
|
+
/// Input data (format depends on category: text for LLM/embedding,
|
|
327
|
+
/// base64 audio for STT, base64 image for vision).
|
|
328
|
+
pub input: String,
|
|
329
|
+
/// Optional parameters (temperature, max_tokens, language hint …).
|
|
330
|
+
#[serde(default)]
|
|
331
|
+
#[ts(optional, type = "Record<string, unknown>")]
|
|
332
|
+
pub parameters: Option<serde_json::Value>,
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/// Inference result returned to the web UI.
|
|
336
|
+
#[derive(Debug, Clone, Serialize, Deserialize, TS, JsonSchema)]
|
|
337
|
+
#[ts(export, export_to = "model.ts")]
|
|
338
|
+
pub struct ModelInferenceResult {
|
|
339
|
+
/// Model that produced the output.
|
|
340
|
+
pub model_id: String,
|
|
341
|
+
/// Output data (text for LLM/embedding/TTS, text for STT, JSON for vision).
|
|
342
|
+
pub output: String,
|
|
343
|
+
/// Time spent (milliseconds).
|
|
344
|
+
#[serde(default)]
|
|
345
|
+
#[ts(optional)]
|
|
346
|
+
pub elapsed_ms: Option<u64>,
|
|
347
|
+
/// Token/processing usage (if applicable).
|
|
348
|
+
#[serde(default)]
|
|
349
|
+
#[ts(optional, type = "Record<string, unknown>")]
|
|
350
|
+
pub usage: Option<serde_json::Value>,
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// ═══════════════════════════════════════════════════════════════
|
|
354
|
+
// WS protocol — SyncMessage variants for model management
|
|
355
|
+
// ═══════════════════════════════════════════════════════════════
|
|
356
|
+
|
|
357
|
+
/// `Sync.RequestModelList` — enumerate available models.
|
|
358
|
+
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
|
359
|
+
#[ts(export, export_to = "model.ts")]
|
|
360
|
+
pub struct RequestModelListParams {
|
|
361
|
+
/// Filter by category (omit for all).
|
|
362
|
+
#[serde(default)]
|
|
363
|
+
#[ts(optional)]
|
|
364
|
+
pub category: Option<ModelCategory>,
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/// `Sync.ModelList` — model catalogue response.
|
|
368
|
+
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
|
369
|
+
#[ts(export, export_to = "model.ts")]
|
|
370
|
+
pub struct ModelListParams {
|
|
371
|
+
pub models: Vec<ModelDescriptor>,
|
|
372
|
+
pub servers: Vec<ModelServerInfo>,
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/// `Sync.RequestModelInference` — ask the engine to run a model.
|
|
376
|
+
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
|
377
|
+
#[ts(export, export_to = "model.ts")]
|
|
378
|
+
pub struct RequestModelInferenceParams {
|
|
379
|
+
pub request: ModelInferenceRequest,
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/// `Sync.ModelInferenceResult` — inference result push.
|
|
383
|
+
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
|
384
|
+
#[ts(export, export_to = "model.ts")]
|
|
385
|
+
pub struct ModelInferenceResultParams {
|
|
386
|
+
pub result: ModelInferenceResult,
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/// `Sync.RequestModelServerAction` — ask evernight (via scepter) to start /
|
|
390
|
+
/// stop / restart a model server. Neither chest nor scepter performs the
|
|
391
|
+
/// deployment directly; the action is forwarded to evernight's model lifecycle
|
|
392
|
+
/// manager.
|
|
393
|
+
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
|
394
|
+
#[ts(export, export_to = "model.ts")]
|
|
395
|
+
pub struct RequestModelServerActionParams {
|
|
396
|
+
pub kind: ModelServerKind,
|
|
397
|
+
pub action: ModelServerAction,
|
|
398
|
+
/// Preferred backend. evernight will honour this if possible; falls back
|
|
399
|
+
/// to CPU if the requested GPU is unavailable.
|
|
400
|
+
#[serde(default)]
|
|
401
|
+
#[ts(optional)]
|
|
402
|
+
pub preferred_backend: Option<ModelBackend>,
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/// `Sync.ModelServerActionResult` — action result.
|
|
406
|
+
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
|
407
|
+
#[ts(export, export_to = "model.ts")]
|
|
408
|
+
pub struct ModelServerActionResultParams {
|
|
409
|
+
pub kind: ModelServerKind,
|
|
410
|
+
pub status: ModelServerStatus,
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/// What to do with a model server.
|
|
414
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, TS, JsonSchema)]
|
|
415
|
+
#[ts(export, export_to = "model.ts")]
|
|
416
|
+
#[serde(rename_all = "snake_case")]
|
|
417
|
+
pub enum ModelServerAction {
|
|
418
|
+
Start,
|
|
419
|
+
Stop,
|
|
420
|
+
Restart,
|
|
421
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
//! Base protocol messages — heartbeat, error, ack.
|
|
2
|
+
|
|
3
|
+
use serde::{Deserialize, Serialize};
|
|
4
|
+
use ts_rs::TS;
|
|
5
|
+
|
|
6
|
+
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
|
7
|
+
#[ts(export, export_to = "ws/baseMessages.ts")]
|
|
8
|
+
pub struct BaseHeartbeatParams {
|
|
9
|
+
pub timestamp: i64,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
|
13
|
+
#[ts(export, export_to = "ws/baseMessages.ts")]
|
|
14
|
+
pub struct BaseErrorParams {
|
|
15
|
+
pub code: String,
|
|
16
|
+
pub message: String,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
|
20
|
+
#[ts(export, export_to = "ws/baseMessages.ts")]
|
|
21
|
+
pub struct BaseAckParams {
|
|
22
|
+
pub message_id: String,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#[cfg(test)]
|
|
26
|
+
mod tests {
|
|
27
|
+
use super::*;
|
|
28
|
+
|
|
29
|
+
// ── BaseHeartbeatParams ─────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
#[test]
|
|
32
|
+
fn heartbeat_round_trip() {
|
|
33
|
+
let h = BaseHeartbeatParams {
|
|
34
|
+
timestamp: 1700000000,
|
|
35
|
+
};
|
|
36
|
+
let s = serde_json::to_string(&h).unwrap();
|
|
37
|
+
assert_eq!(s, r#"{"timestamp":1700000000}"#);
|
|
38
|
+
let back: BaseHeartbeatParams = serde_json::from_str(&s).unwrap();
|
|
39
|
+
assert_eq!(back.timestamp, 1700000000);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#[test]
|
|
43
|
+
fn heartbeat_negative_timestamp() {
|
|
44
|
+
// Pre-epoch timestamps should round-trip without error.
|
|
45
|
+
let h = BaseHeartbeatParams { timestamp: -1 };
|
|
46
|
+
let v = serde_json::to_value(&h).unwrap();
|
|
47
|
+
assert_eq!(v["timestamp"], -1);
|
|
48
|
+
let back: BaseHeartbeatParams = serde_json::from_value(v).unwrap();
|
|
49
|
+
assert_eq!(back.timestamp, -1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
#[test]
|
|
53
|
+
fn heartbeat_no_extra_fields() {
|
|
54
|
+
let h = BaseHeartbeatParams { timestamp: 0 };
|
|
55
|
+
let v = serde_json::to_value(&h).unwrap();
|
|
56
|
+
assert_eq!(
|
|
57
|
+
v.as_object().unwrap().len(),
|
|
58
|
+
1,
|
|
59
|
+
"heartbeat must have exactly 1 field"
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ── BaseErrorParams ─────────────────────────────────────────────
|
|
64
|
+
|
|
65
|
+
#[test]
|
|
66
|
+
fn error_params_round_trip() {
|
|
67
|
+
let e = BaseErrorParams {
|
|
68
|
+
code: "E_TIMEOUT".into(),
|
|
69
|
+
message: "request timed out".into(),
|
|
70
|
+
};
|
|
71
|
+
let v = serde_json::to_value(&e).unwrap();
|
|
72
|
+
assert_eq!(v["code"], "E_TIMEOUT");
|
|
73
|
+
assert_eq!(v["message"], "request timed out");
|
|
74
|
+
let back: BaseErrorParams = serde_json::from_value(v).unwrap();
|
|
75
|
+
assert_eq!(back.code, "E_TIMEOUT");
|
|
76
|
+
assert_eq!(back.message, "request timed out");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
#[test]
|
|
80
|
+
fn error_params_no_extra_fields() {
|
|
81
|
+
let e = BaseErrorParams {
|
|
82
|
+
code: "X".into(),
|
|
83
|
+
message: "y".into(),
|
|
84
|
+
};
|
|
85
|
+
let v = serde_json::to_value(&e).unwrap();
|
|
86
|
+
assert_eq!(v.as_object().unwrap().len(), 2);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
#[test]
|
|
90
|
+
fn error_params_missing_field_rejected() {
|
|
91
|
+
let raw = serde_json::json!({"code": "X"});
|
|
92
|
+
assert!(serde_json::from_value::<BaseErrorParams>(raw).is_err());
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ── BaseAckParams ───────────────────────────────────────────────
|
|
96
|
+
|
|
97
|
+
#[test]
|
|
98
|
+
fn ack_params_round_trip() {
|
|
99
|
+
let a = BaseAckParams {
|
|
100
|
+
message_id: "msg-001".into(),
|
|
101
|
+
};
|
|
102
|
+
let s = serde_json::to_string(&a).unwrap();
|
|
103
|
+
assert_eq!(s, r#"{"message_id":"msg-001"}"#);
|
|
104
|
+
let back: BaseAckParams = serde_json::from_str(&s).unwrap();
|
|
105
|
+
assert_eq!(back.message_id, "msg-001");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
#[test]
|
|
109
|
+
fn ack_params_empty_message_id() {
|
|
110
|
+
let a = BaseAckParams {
|
|
111
|
+
message_id: String::new(),
|
|
112
|
+
};
|
|
113
|
+
let v = serde_json::to_value(&a).unwrap();
|
|
114
|
+
assert_eq!(v["message_id"], "");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
#[test]
|
|
118
|
+
fn ack_params_no_extra_fields() {
|
|
119
|
+
let a = BaseAckParams {
|
|
120
|
+
message_id: "m".into(),
|
|
121
|
+
};
|
|
122
|
+
let v = serde_json::to_value(&a).unwrap();
|
|
123
|
+
assert_eq!(v.as_object().unwrap().len(), 1);
|
|
124
|
+
}
|
|
125
|
+
}
|