Skip to main content

openkind_core/
models.rs

1//! `ModelInfo` and `ModelsResponse` — match the wire shape on
2//! docs.typesafe.ai/models#listing-models.
3//!
4//! > `GET /v1/models` returns the names your account can send in the
5//! > `model` field, with a description and release date for each. It
6//! > currently lists the aliases.
7//!
8//! Response shape: `{ "models": [ { "name", "description", "release_date" } ] }`
9
10use serde::{Deserialize, Serialize};
11
12/// One entry in the `models` array. Fields are required and order-stable.
13#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
14pub struct ModelInfo {
15    /// The model ID or alias, as accepted by the `model` field.
16    pub name: String,
17    /// What the model is for.
18    pub description: String,
19    /// ISO-8601 release date (e.g. `"2024-09-17"`).
20    pub release_date: String,
21}
22
23/// Top-level `GET /v1/models` response.
24#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
25pub struct ModelsResponse {
26    /// List of available model descriptors and aliases.
27    pub models: Vec<ModelInfo>,
28}
29
30impl ModelsResponse {
31    /// Construct a new `ModelsResponse` from a list of model infos.
32    pub fn new(models: Vec<ModelInfo>) -> Self {
33        Self { models }
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    #[test]
42    fn serializes_to_jev_shape() {
43        let resp = ModelsResponse::new(vec![ModelInfo {
44            name: "mock".into(),
45            description: "A mock engine for testing".into(),
46            release_date: "2026-01-01".into(),
47        }]);
48        let v: serde_json::Value = serde_json::to_value(&resp).unwrap();
49        assert_eq!(v["models"][0]["name"], "mock");
50        assert_eq!(v["models"][0]["description"], "A mock engine for testing");
51        assert_eq!(v["models"][0]["release_date"], "2026-01-01");
52        assert!(v.get("data").is_none());
53        assert!(v.get("object").is_none());
54    }
55}