use llmsdk_provider::ProviderError;
use llmsdk_provider::error::Result;
use llmsdk_provider::shared::ProviderOptions;
use serde::Deserialize;
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(rename_all = "camelCase", default)]
pub(crate) struct XaiFilesOptions {
pub team_id: Option<String>,
#[allow(dead_code, reason = "captured for parity with upstream schema")]
pub file_path: Option<String>,
}
pub(crate) fn parse_xai_files_options(po: Option<&ProviderOptions>) -> Result<XaiFilesOptions> {
let Some(map) = po else {
return Ok(XaiFilesOptions::default());
};
let Some(slot) = map.get("xai") else {
return Ok(XaiFilesOptions::default());
};
serde_json::from_value::<XaiFilesOptions>(serde_json::Value::Object(slot.clone())).map_err(
|err| {
ProviderError::invalid_argument(
"provider_options.xai",
format!("invalid xAI files options: {err}"),
)
},
)
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
fn po(v: &serde_json::Value) -> ProviderOptions {
let mut m = ProviderOptions::default();
m.insert("xai".into(), v.as_object().expect("object").clone());
m
}
#[test]
fn missing_options_yields_default() {
let r = parse_xai_files_options(None).expect("ok");
assert!(r.team_id.is_none());
assert!(r.file_path.is_none());
}
#[test]
fn missing_xai_slot_yields_default() {
let mut m = ProviderOptions::default();
m.insert(
"openai".into(),
json!({ "reasoningEffort": "high" })
.as_object()
.unwrap()
.clone(),
);
let r = parse_xai_files_options(Some(&m)).expect("ok");
assert!(r.team_id.is_none());
}
#[test]
fn parses_team_id() {
let m = po(&json!({ "teamId": "team-123" }));
let r = parse_xai_files_options(Some(&m)).expect("ok");
assert_eq!(r.team_id.as_deref(), Some("team-123"));
}
#[test]
fn parses_file_path_passthrough() {
let m = po(&json!({ "filePath": "/tmp/x.bin" }));
let r = parse_xai_files_options(Some(&m)).expect("ok");
assert_eq!(r.file_path.as_deref(), Some("/tmp/x.bin"));
}
#[test]
fn unknown_keys_are_ignored_for_passthrough_parity() {
let m = po(&json!({ "teamId": "t1", "futureKnob": 42 }));
let r = parse_xai_files_options(Some(&m)).expect("ok");
assert_eq!(r.team_id.as_deref(), Some("t1"));
}
#[test]
fn wrong_type_for_team_id_errors() {
let m = po(&json!({ "teamId": 42 }));
let err = parse_xai_files_options(Some(&m)).unwrap_err();
assert!(format!("{err}").contains("invalid xAI files options"));
}
}