///|
pub impl @json.FromJson for Model with fn from_json(
json : Json,
json_path : @json.JsonPath,
) -> Model {
guard json is Object(json) else {
raise JsonDecodeError(
(json_path, "@vectie/moonclaw/model.Model::from_json: expected object"),
)
}
let name : String = {
guard json.get("name") is Some(name) else {
raise JsonDecodeError(
(
json_path, "@vectie/moonclaw/model.Model::from_json: missing 'name' field",
),
)
}
@json.from_json(name, path=json_path.add_key("name"))
}
let model_name : String = {
guard json.get("model_name") is Some(model_name) else {
raise JsonDecodeError(
(
json_path, "@vectie/moonclaw/model.Model::from_json: missing 'model_name' field",
),
)
}
@json.from_json(model_name, path=json_path.add_key("model_name"))
}
let model_type : Type = {
guard json.get("model_type") is Some(model_type) else {
raise JsonDecodeError(
(
json_path, "@vectie/moonclaw/model.Model::from_json: missing 'model_type' field",
),
)
}
@json.from_json(model_type, path=json_path.add_key("model_type"))
}
let api_key : String = {
guard json.get("api_key") is Some(api_key) else { "" }
@json.from_json(api_key, path=json_path.add_key("api_key"))
}
let base_url : String = {
guard json.get("base_url") is Some(base_url) else {
match model_type {
SaaS(OpenAI) => "https://api.openai.com/v1"
SaaS(Anthropic) => "https://api.anthropic.com"
SaaS(CodexOAuth) => "https://chatgpt.com/backend-api"
SaaS(Copilot) => "https://api.githubcopilot.com"
SaaS(Qwen) => "https://dashscope.aliyuncs.com/compatible-mode/v1"
SaaS(Kimi) => "https://api.moonshot.cn/v1"
SaaS(KimiCoding) => "https://api.moonshot.cn/v1"
}
}
@json.from_json(base_url, path=json_path.add_key("base_url"))
}
let description : String? = {
guard json.get("description") is Some(description) else { None }
Some(@json.from_json(description, path=json_path.add_key("description")))
}
let safe_zone_tokens : Int = {
guard json.get("safe_zone_tokens") is Some(safe_zone_tokens) else {
// raise @json.JsonDecodeError(
// (
// json_path, "@vectie/moonclaw/model.Model::from_json: missing 'safe_zone_tokens' field",
// ),
// )
128_000
}
@json.from_json(
safe_zone_tokens,
path=json_path.add_key("safe_zone_tokens"),
)
}
let supports_anthropic_prompt_caching : Bool = {
guard json.get("supports_anthropic_prompt_caching")
is Some(supports_anthropic_prompt_caching) else {
false
}
@json.from_json(
supports_anthropic_prompt_caching,
path=json_path.add_key("supports_anthropic_prompt_caching"),
)
}
let supports_apply_patch : Bool = {
guard json.get("supports_apply_patch") is Some(supports_apply_patch) else {
// Auto-detect based on model name for GPT 5.1+
let name_lower = model_name.to_lower()
name_lower.contains("gpt-5.1") ||
name_lower.contains("gpt-5.2") ||
name_lower.contains("gpt-5.3") ||
name_lower.contains("gpt-5.4") ||
name_lower.contains("gpt-5.5") ||
name_lower.contains("gpt-5.6")
}
@json.from_json(
supports_apply_patch,
path=json_path.add_key("supports_apply_patch"),
)
}
let access_token : String? = {
guard json.get("access_token") is Some(access_token) else { None }
Some(@json.from_json(access_token, path=json_path.add_key("access_token")))
}
let account_id : String? = {
guard json.get("account_id") is Some(account_id) else { None }
Some(@json.from_json(account_id, path=json_path.add_key("account_id")))
}
let refresh_token : String? = {
guard json.get("refresh_token") is Some(refresh_token) else { None }
Some(
@json.from_json(refresh_token, path=json_path.add_key("refresh_token")),
)
}
let id_token : String? = {
guard json.get("id_token") is Some(id_token) else { None }
Some(@json.from_json(id_token, path=json_path.add_key("id_token")))
}
{
name,
description,
model_name,
model_type,
api_key,
base_url,
safe_zone_tokens,
supports_anthropic_prompt_caching,
supports_apply_patch,
access_token,
account_id,
refresh_token,
id_token,
}
}
///|
pub impl @json.FromJson for Type with fn from_json(
json : Json,
json_path : @json.JsonPath,
) -> Type {
guard json is String(json) else {
raise JsonDecodeError(
(json_path, "@vectie/moonclaw/model.Type::from_json: expected string"),
)
}
match json {
"saas/openai" => SaaS(OpenAI)
"saas/anthropic" => SaaS(Anthropic)
"saas/codex_oauth" => SaaS(CodexOAuth)
"saas/copilot" => SaaS(Copilot)
"saas/qwen" => SaaS(Qwen)
"saas/kimi" => SaaS(Kimi)
"saas/kimi_coding" => SaaS(KimiCoding)
[.. "saas/", .. provider] =>
raise JsonDecodeError(
(
json_path,
"@vectie/moonclaw/model.Type::from_json: unsupported SaaS provider '\{provider}'",
),
)
_ =>
raise JsonDecodeError(
(
json_path,
"@vectie/moonclaw/model.Type::from_json: unknown model type '\{json}'",
),
)
}
}
///|
pub impl ToJson for Type with fn to_json(self) {
match self {
SaaS(OpenAI) => "saas/openai"
SaaS(Anthropic) => "saas/anthropic"
SaaS(CodexOAuth) => "saas/codex_oauth"
SaaS(Copilot) => "saas/copilot"
SaaS(Qwen) => "saas/qwen"
SaaS(Kimi) => "saas/kimi"
SaaS(KimiCoding) => "saas/kimi_coding"
}
}