use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
pub const AGENT_LABORATORY_ID_PREFIX: &str = "oai-agent-";
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
JsonSchema,
arbitrary::Arbitrary,
)]
#[schemars(rename = "agent.Laboratory")]
pub struct Laboratory {
pub image: crate::laboratories::LaboratoryImage,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[schemars(extend("omitempty" = true))]
pub env: Option<Vec<[String; 2]>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[schemars(extend("omitempty" = true))]
pub cwd: Option<String>,
}
pub type Laboratories = Vec<Laboratory>;
pub mod laboratories {
use twox_hash::XxHash3_128;
pub fn prepare(
mut this: super::Laboratories,
) -> Option<super::Laboratories> {
if this.is_empty() {
return None;
}
for laboratory in &mut this {
laboratory.env = match laboratory.env.take() {
Some(mut env) if !env.is_empty() => {
env.sort();
Some(env)
}
_ => None,
};
if laboratory.cwd.as_deref() == Some("/") {
laboratory.cwd = None;
}
}
this.sort();
Some(this)
}
pub fn validate(this: &super::Laboratories) -> Result<(), String> {
for laboratory in this {
laboratory
.image
.validate()
.map_err(|message| format!("`laboratories` image: {message}"))?;
}
for (i, a) in this.iter().enumerate() {
for b in &this[i + 1..] {
if a == b {
return Err(
"`laboratories` contains duplicate entries".to_string()
);
}
}
}
Ok(())
}
pub fn derived_id(
agent_full_id: &str,
laboratory: &super::Laboratory,
) -> String {
let mut hasher = XxHash3_128::with_seed(0);
hasher.write(agent_full_id.as_bytes());
hasher.write(&[0u8]);
hasher.write(serde_json::to_string(laboratory).unwrap().as_bytes());
format!(
"{}{:0>22}",
super::AGENT_LABORATORY_ID_PREFIX,
base62::encode(hasher.finish_128())
)
}
}