Skip to main content

artifactize_core/store/definitions/
extensions.rs

1//! Preserve unknown nested saved-profile and selector fields without dynamic core parsing.
2use crate::{config::StoredProfile, project::selection::Selection};
3use serde::{Deserialize, Deserializer, Serialize, Serializer, ser::SerializeMap};
4use serde_json::{Map, Value};
5use std::collections::BTreeMap;
6
7#[derive(Debug, Clone)]
8pub struct Profile {
9    pub known: StoredProfile,
10    pub extra: Map<String, Value>,
11}
12impl<'de> Deserialize<'de> for Profile {
13    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
14        let mut fields = Map::<String, Value>::deserialize(deserializer)?;
15        let names: &[&str] = match fields.get("kind").and_then(Value::as_str) {
16            Some("agent") => &[
17                "kind",
18                "backend",
19                "model",
20                "reasoning",
21                "timeoutMs",
22                "maxToolCalls",
23                "maxTokens",
24            ],
25            Some("runtime") => &["kind", "command", "args", "timeoutMs"],
26            _ => &["kind"],
27        };
28        let known = split(&mut fields, names);
29        let known =
30            serde_json::from_value(Value::Object(known)).map_err(serde::de::Error::custom)?;
31        Ok(Self {
32            known,
33            extra: fields,
34        })
35    }
36}
37impl Serialize for Profile {
38    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
39        serialize(&self.known, &self.extra, serializer)
40    }
41}
42
43#[derive(Debug, Clone)]
44pub struct SavedSelection {
45    pub known: Selection,
46    pub extra: Map<String, Value>,
47}
48impl<'de> Deserialize<'de> for SavedSelection {
49    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
50        let mut fields = Map::<String, Value>::deserialize(deserializer)?;
51        let names: &[&str] = match fields.get("kind").and_then(Value::as_str) {
52            Some("artifact") => &["kind", "artifactId"],
53            Some("eval") => &["kind", "evalId"],
54            Some("artifacts") => &["kind", "artifactIds"],
55            Some("evals") => &["kind", "evalIds"],
56            _ => &["kind"],
57        };
58        let known = serde_json::from_value(Value::Object(split(&mut fields, names)))
59            .map_err(serde::de::Error::custom)?;
60        Ok(Self {
61            known,
62            extra: fields,
63        })
64    }
65}
66impl Serialize for SavedSelection {
67    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
68        serialize(&self.known, &self.extra, serializer)
69    }
70}
71fn split(fields: &mut Map<String, Value>, names: &[&str]) -> Map<String, Value> {
72    names
73        .iter()
74        .filter_map(|name| fields.remove(*name).map(|value| ((*name).into(), value)))
75        .collect()
76}
77fn serialize<T: Serialize, S: Serializer>(
78    known: &T,
79    extra: &Map<String, Value>,
80    serializer: S,
81) -> Result<S::Ok, S::Error> {
82    let known: BTreeMap<String, Value> =
83        serde_json::from_value(serde_json::to_value(known).map_err(serde::ser::Error::custom)?)
84            .map_err(serde::ser::Error::custom)?;
85    let mut object = serializer.serialize_map(Some(known.len() + extra.len()))?;
86    for (name, value) in known {
87        object.serialize_entry(&name, &value)?;
88    }
89    for (name, value) in extra {
90        object.serialize_entry(name, value)?;
91    }
92    object.end()
93}