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:
MMEXA
2026-05-18 19:02:19 +00:00
446 changed files with 53043 additions and 4780 deletions

View File

@@ -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"]));
}
}

View File

@@ -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, &region, 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()));