mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 09:20:22 +08:00
Merge origin/main into codex/gemini-embedding-batch
# Conflicts: # apps/aether-gateway/src/ai_serving/api.rs # apps/aether-gateway/src/ai_serving/planner/passthrough/provider/family/request.rs # apps/aether-gateway/src/ai_serving/planner/standard/family/request.rs # apps/aether-gateway/src/ai_serving/transport.rs # apps/aether-gateway/src/handlers/admin/provider/query/models/model_test/summary.rs # apps/aether-gateway/src/handlers/admin/provider/query/models/model_test/tests.rs # crates/aether-data/src/repository/candidate_selection/postgres.rs # crates/aether-model-fetch/src/strategy.rs
This commit is contained in:
@@ -229,7 +229,7 @@ pub fn endpoint_supports_rust_models_fetch(api_format: &str) -> bool {
|
||||
pub fn provider_type_uses_preset_models(provider_type: &str) -> bool {
|
||||
matches!(
|
||||
provider_type.trim().to_ascii_lowercase().as_str(),
|
||||
"claude_code" | "gemini_cli"
|
||||
"claude_code" | "gemini_cli" | "grok"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -272,6 +272,27 @@ pub fn preset_models_for_provider(provider_type: &str) -> Option<Vec<Value>> {
|
||||
preset_model("gpt-5.3-codex", "openai", "GPT-5.3 Codex", "openai:responses"),
|
||||
preset_model("gpt-5.3-codex-spark", "openai", "GPT-5.3 Codex Spark", "openai:responses"),
|
||||
],
|
||||
"grok" => vec![
|
||||
preset_model("grok-4.20-0309-non-reasoning", "xai", "Grok 4.20 0309 Non-Reasoning", "openai:chat"),
|
||||
preset_model("grok-4.20-0309", "xai", "Grok 4.20 0309", "openai:chat"),
|
||||
preset_model("grok-4.20-0309-reasoning", "xai", "Grok 4.20 0309 Reasoning", "openai:chat"),
|
||||
preset_model("grok-4.20-0309-non-reasoning-super", "xai", "Grok 4.20 0309 Non-Reasoning Super", "openai:chat"),
|
||||
preset_model("grok-4.20-0309-super", "xai", "Grok 4.20 0309 Super", "openai:chat"),
|
||||
preset_model("grok-4.20-0309-reasoning-super", "xai", "Grok 4.20 0309 Reasoning Super", "openai:chat"),
|
||||
preset_model("grok-4.20-0309-non-reasoning-heavy", "xai", "Grok 4.20 0309 Non-Reasoning Heavy", "openai:chat"),
|
||||
preset_model("grok-4.20-0309-heavy", "xai", "Grok 4.20 0309 Heavy", "openai:chat"),
|
||||
preset_model("grok-4.20-0309-reasoning-heavy", "xai", "Grok 4.20 0309 Reasoning Heavy", "openai:chat"),
|
||||
preset_model("grok-4.20-multi-agent-0309", "xai", "Grok 4.20 Multi-Agent 0309", "openai:chat"),
|
||||
preset_model("grok-4.20-auto", "xai", "Grok 4.20 Auto", "openai:chat"),
|
||||
preset_model("grok-4.20-fast", "xai", "Grok 4.20 Fast", "openai:chat"),
|
||||
preset_model("grok-4.20-expert", "xai", "Grok 4.20 Expert", "openai:chat"),
|
||||
preset_model("grok-4.20-heavy", "xai", "Grok 4.20 Heavy", "openai:chat"),
|
||||
preset_model("grok-4.3-beta", "xai", "Grok 4.3 Beta", "openai:chat"),
|
||||
preset_model("grok-imagine-image-lite", "xai", "Grok Imagine Image Lite", "openai:image"),
|
||||
preset_model("grok-imagine-image", "xai", "Grok Imagine Image", "openai:image"),
|
||||
preset_model("grok-imagine-image-pro", "xai", "Grok Imagine Image Pro", "openai:image"),
|
||||
preset_model("grok-imagine-image-edit", "xai", "Grok Imagine Image Edit", "openai:image"),
|
||||
],
|
||||
_ => return None,
|
||||
};
|
||||
Some(models)
|
||||
@@ -934,4 +955,42 @@ mod tests {
|
||||
.iter()
|
||||
.all(|model| model["api_formats"] == json!(["claude:messages"])));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preset_models_cover_grok_non_video_catalog() {
|
||||
let models = preset_models_for_provider("grok").expect("preset models should exist");
|
||||
let model_ids = models
|
||||
.iter()
|
||||
.map(|model| model["id"].as_str().expect("model id"))
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(
|
||||
model_ids,
|
||||
vec![
|
||||
"grok-4.20-0309-non-reasoning",
|
||||
"grok-4.20-0309",
|
||||
"grok-4.20-0309-reasoning",
|
||||
"grok-4.20-0309-non-reasoning-super",
|
||||
"grok-4.20-0309-super",
|
||||
"grok-4.20-0309-reasoning-super",
|
||||
"grok-4.20-0309-non-reasoning-heavy",
|
||||
"grok-4.20-0309-heavy",
|
||||
"grok-4.20-0309-reasoning-heavy",
|
||||
"grok-4.20-multi-agent-0309",
|
||||
"grok-4.20-auto",
|
||||
"grok-4.20-fast",
|
||||
"grok-4.20-expert",
|
||||
"grok-4.20-heavy",
|
||||
"grok-4.3-beta",
|
||||
"grok-imagine-image-lite",
|
||||
"grok-imagine-image",
|
||||
"grok-imagine-image-pro",
|
||||
"grok-imagine-image-edit",
|
||||
]
|
||||
);
|
||||
assert!(!model_ids.contains(&"grok-imagine-video"));
|
||||
assert_eq!(models[0]["api_formats"], json!(["openai:chat"]));
|
||||
assert_eq!(models[10]["api_formats"], json!(["openai:chat"]));
|
||||
assert_eq!(models[15]["api_formats"], json!(["openai:image"]));
|
||||
assert_eq!(models[18]["api_formats"], json!(["openai:image"]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ const ANTIGRAVITY_DAILY_BASE_URL: &str = "https://daily-cloudcode-pa.googleapis.
|
||||
const ANTIGRAVITY_PROD_BASE_URL: &str = "https://cloudcode-pa.googleapis.com";
|
||||
const ANTIGRAVITY_BLOCKED_MODELS: &[&str] = &["chat_23310", "chat_20706"];
|
||||
const VERTEX_API_BASE_URL: &str = "https://aiplatform.googleapis.com";
|
||||
const VERTEX_MODEL_GARDEN_LIST_API_VERSION: &str = "v1beta1";
|
||||
const VERTEX_PAGE_SIZE: &str = "100";
|
||||
const VERTEX_MAX_PAGES: usize = 20;
|
||||
const GOOGLE_OAUTH_TOKEN_URL: &str = "https://oauth2.googleapis.com/token";
|
||||
@@ -479,7 +480,10 @@ async fn fetch_vertex_service_account_models(
|
||||
("google", gemini_transport, "gemini:generate_content"),
|
||||
("anthropic", claude_transport, "claude:messages"),
|
||||
] {
|
||||
let url = build_vertex_service_account_list_url(&base, publisher, None);
|
||||
let project_id = json_string(auth_config.get("project_id")).unwrap_or_default();
|
||||
let region = json_string(auth_config.get("region")).unwrap_or_default();
|
||||
let url =
|
||||
build_vertex_service_account_list_url(&base, &project_id, ®ion, publisher, None);
|
||||
let outcome = fetch_vertex_models_from_url(
|
||||
runtime,
|
||||
transport,
|
||||
@@ -921,7 +925,7 @@ fn iter_vertex_base_urls(transports: &[GatewayProviderTransportSnapshot]) -> Vec
|
||||
}
|
||||
|
||||
fn build_vertex_google_list_url(base_url: &str, api_key: &str, page_token: Option<&str>) -> String {
|
||||
let url = build_vertex_publisher_models_list_base_url(base_url, "google");
|
||||
let url = build_vertex_model_garden_list_url(base_url, "google");
|
||||
let mut url = append_query_param(url, "key", api_key);
|
||||
url = append_query_param(url, "pageSize", VERTEX_PAGE_SIZE);
|
||||
if let Some(page_token) = page_token {
|
||||
@@ -932,10 +936,12 @@ fn build_vertex_google_list_url(base_url: &str, api_key: &str, page_token: Optio
|
||||
|
||||
fn build_vertex_service_account_list_url(
|
||||
base_url: &str,
|
||||
_project_id: &str,
|
||||
_region: &str,
|
||||
publisher: &str,
|
||||
page_token: Option<&str>,
|
||||
) -> String {
|
||||
let mut url = build_vertex_publisher_models_list_base_url(base_url, publisher);
|
||||
let mut url = build_vertex_model_garden_list_url(base_url, publisher);
|
||||
url = append_query_param(url, "pageSize", VERTEX_PAGE_SIZE);
|
||||
if let Some(page_token) = page_token {
|
||||
url = append_query_param(url, "pageToken", page_token);
|
||||
@@ -943,14 +949,14 @@ fn build_vertex_service_account_list_url(
|
||||
url
|
||||
}
|
||||
|
||||
fn build_vertex_publisher_models_list_base_url(base_url: &str, publisher: &str) -> String {
|
||||
fn build_vertex_model_garden_list_url(base_url: &str, publisher: &str) -> String {
|
||||
let trimmed_base = base_url.trim().trim_end_matches('/');
|
||||
let path = if trimmed_base.ends_with("/v1") || trimmed_base.ends_with("/v1beta1") {
|
||||
format!("/publishers/{publisher}/models")
|
||||
} else {
|
||||
format!("/v1beta1/publishers/{publisher}/models")
|
||||
};
|
||||
build_simple_path_url(trimmed_base, &path)
|
||||
let unversioned_base = trimmed_base
|
||||
.strip_suffix("/v1beta1")
|
||||
.or_else(|| trimmed_base.strip_suffix("/v1"))
|
||||
.unwrap_or(trimmed_base);
|
||||
let path = format!("/{VERTEX_MODEL_GARDEN_LIST_API_VERSION}/publishers/{publisher}/models");
|
||||
build_simple_path_url(unversioned_base, &path)
|
||||
}
|
||||
|
||||
fn build_simple_path_url(base_url: &str, path: &str) -> String {
|
||||
@@ -1263,7 +1269,10 @@ mod tests {
|
||||
use async_trait::async_trait;
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use super::{select_model_fetch_strategy, ModelFetchStrategy, ModelFetchStrategyKind};
|
||||
use super::{
|
||||
build_vertex_google_list_url, build_vertex_service_account_list_url,
|
||||
select_model_fetch_strategy, ModelFetchStrategy, ModelFetchStrategyKind,
|
||||
};
|
||||
use crate::fetch_models_from_transports;
|
||||
use crate::transport::ModelFetchTransportRuntime;
|
||||
|
||||
@@ -1471,6 +1480,8 @@ mod tests {
|
||||
fn vertex_publisher_models_list_url_uses_model_garden_resource_not_runtime_resource() {
|
||||
let url = super::build_vertex_service_account_list_url(
|
||||
"https://aiplatform.googleapis.com",
|
||||
"project-1",
|
||||
"global",
|
||||
"google",
|
||||
None,
|
||||
);
|
||||
@@ -1485,6 +1496,28 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vertex_model_fetch_uses_model_garden_list_endpoint() {
|
||||
assert_eq!(
|
||||
build_vertex_google_list_url(
|
||||
"https://aiplatform.googleapis.com/v1",
|
||||
"vertex-secret",
|
||||
None,
|
||||
),
|
||||
"https://aiplatform.googleapis.com/v1beta1/publishers/google/models?key=vertex-secret&pageSize=100"
|
||||
);
|
||||
assert_eq!(
|
||||
build_vertex_service_account_list_url(
|
||||
"https://aiplatform.googleapis.com",
|
||||
"project-1",
|
||||
"global",
|
||||
"google",
|
||||
Some("page-2"),
|
||||
),
|
||||
"https://aiplatform.googleapis.com/v1beta1/publishers/google/models?pageSize=100&pageToken=page-2"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn codex_transport_fetches_upstream_models_instead_of_preset_catalog() {
|
||||
let executed_urls = Arc::new(Mutex::new(Vec::new()));
|
||||
|
||||
Reference in New Issue
Block a user