use crate::ModelIden;
use crate::adapter::openai::OpenAIAdapter;
use crate::adapter::{Adapter, AdapterKind, ServiceType, WebRequestData};
use crate::chat::{ChatOptionsSet, ChatRequest, ChatResponse, ChatStreamResponse};
use crate::resolver::{AuthData, Endpoint};
use crate::webc::WebResponse;
use crate::{Result, ServiceTarget};
use reqwest::RequestBuilder;
pub const ZAI_CODING_NAMESPACE: &str = "zai-coding";
struct ZaiModelEndpoint {
endpoint: Endpoint,
}
impl ZaiModelEndpoint {
fn from_model(model: &ModelIden) -> Self {
let (namespace, _) = model.model_name.namespace_and_name();
let endpoint = match namespace {
Some(ZAI_CODING_NAMESPACE) => Endpoint::from_static("https://api.z.ai/api/coding/paas/v4/"),
_ => ZaiAdapter::default_endpoint(),
};
Self { endpoint }
}
}
pub struct ZaiAdapter;
pub(in crate::adapter) const MODELS: &[&str] = &[
"glm-4-plus",
"glm-4.6",
"glm-4.5",
"glm-4.5v",
"glm-4.5-x",
"glm-4.5-air",
"glm-4.5-airx",
"glm-4-32b-0414-128k",
"glm-4.5-flash",
"glm-4-air-250414",
"glm-4-flashx-250414",
"glm-4-flash-250414",
"glm-4-air",
"glm-4-airx",
"glm-4-long",
"glm-4-flash",
"glm-4v-plus-0111",
"glm-4v-flash",
"glm-z1-air",
"glm-z1-airx",
"glm-z1-flash",
"glm-z1-flashx",
"glm-4.1v-thinking-flash",
"glm-4.1v-thinking-flashx",
];
impl ZaiAdapter {
pub const API_KEY_DEFAULT_ENV_NAME: &str = "ZAI_API_KEY";
}
impl Adapter for ZaiAdapter {
fn default_endpoint() -> Endpoint {
const BASE_URL: &str = "https://api.z.ai/api/paas/v4/";
Endpoint::from_static(BASE_URL)
}
fn default_auth() -> AuthData {
AuthData::from_env(Self::API_KEY_DEFAULT_ENV_NAME)
}
async fn all_model_names(_kind: AdapterKind) -> Result<Vec<String>> {
Ok(MODELS.iter().map(|s| s.to_string()).collect())
}
fn get_service_url(_model: &ModelIden, service_type: ServiceType, endpoint: Endpoint) -> Result<String> {
let base_url = endpoint.base_url();
let url = match service_type {
ServiceType::Chat | ServiceType::ChatStream => format!("{base_url}chat/completions"),
ServiceType::Embed => format!("{base_url}embeddings"),
};
Ok(url)
}
fn to_web_request_data(
mut target: ServiceTarget,
service_type: ServiceType,
chat_req: ChatRequest,
chat_options: ChatOptionsSet<'_, '_>,
) -> Result<WebRequestData> {
let zai_info = ZaiModelEndpoint::from_model(&target.model);
target.endpoint = zai_info.endpoint;
OpenAIAdapter::util_to_web_request_data(target, service_type, chat_req, chat_options, None)
}
fn to_chat_response(
model_iden: ModelIden,
web_response: WebResponse,
options_set: ChatOptionsSet<'_, '_>,
) -> Result<ChatResponse> {
OpenAIAdapter::to_chat_response(model_iden, web_response, options_set)
}
fn to_chat_stream(
model_iden: ModelIden,
reqwest_builder: RequestBuilder,
options_set: ChatOptionsSet<'_, '_>,
) -> Result<ChatStreamResponse> {
OpenAIAdapter::to_chat_stream(model_iden, reqwest_builder, options_set)
}
fn to_embed_request_data(
mut service_target: crate::ServiceTarget,
embed_req: crate::embed::EmbedRequest,
options_set: crate::embed::EmbedOptionsSet<'_, '_>,
) -> Result<crate::adapter::WebRequestData> {
let zai_info = ZaiModelEndpoint::from_model(&service_target.model);
service_target.endpoint = zai_info.endpoint;
OpenAIAdapter::to_embed_request_data(service_target, embed_req, options_set)
}
fn to_embed_response(
model_iden: crate::ModelIden,
web_response: crate::webc::WebResponse,
options_set: crate::embed::EmbedOptionsSet<'_, '_>,
) -> Result<crate::embed::EmbedResponse> {
OpenAIAdapter::to_embed_response(model_iden, web_response, options_set)
}
}