mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-11 03:39:49 +08:00
feat(codex): 按操作语义路由 Responses V2 压缩
(cherry picked from commit 2fc604e047)
This commit is contained in:
@@ -25,17 +25,33 @@ pub fn resolve_requested_global_model_name_with_model_directives(
|
||||
requested_model_name: &str,
|
||||
api_format: &str,
|
||||
enable_model_directives: bool,
|
||||
) -> Option<String> {
|
||||
resolve_requested_global_model_name_with_model_directives_and_request_operation(
|
||||
rows,
|
||||
requested_model_name,
|
||||
api_format,
|
||||
enable_model_directives,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn resolve_requested_global_model_name_with_model_directives_and_request_operation(
|
||||
rows: &[StoredMinimalCandidateSelectionRow],
|
||||
requested_model_name: &str,
|
||||
api_format: &str,
|
||||
enable_model_directives: bool,
|
||||
request_operation: Option<&str>,
|
||||
) -> Option<String> {
|
||||
requested_model_name_candidates(requested_model_name, enable_model_directives).find_map(
|
||||
|requested_model_name| {
|
||||
let requested_model_name = requested_model_name.as_ref();
|
||||
resolve_global_model_name_by(rows, |row| {
|
||||
row_has_available_provider_model(row, api_format)
|
||||
row_has_available_provider_model(row, api_format, request_operation)
|
||||
&& row.global_model_name == requested_model_name
|
||||
})
|
||||
.or_else(|| {
|
||||
resolve_global_model_name_by(rows, |row| {
|
||||
row_default_provider_model_name_available(row, api_format)
|
||||
row_default_provider_model_name_available(row, api_format, request_operation)
|
||||
&& row.model_provider_model_name == requested_model_name
|
||||
})
|
||||
})
|
||||
@@ -45,7 +61,7 @@ pub fn resolve_requested_global_model_name_with_model_directives(
|
||||
.as_ref()
|
||||
.is_some_and(|mappings| {
|
||||
mappings.iter().any(|mapping| {
|
||||
mapping_scope_matches(mapping, row, api_format)
|
||||
mapping_scope_matches(mapping, row, api_format, request_operation)
|
||||
&& mapping.name == requested_model_name
|
||||
})
|
||||
})
|
||||
@@ -53,7 +69,7 @@ pub fn resolve_requested_global_model_name_with_model_directives(
|
||||
})
|
||||
.or_else(|| {
|
||||
resolve_global_model_name_by(rows, |row| {
|
||||
row_has_available_provider_model(row, api_format)
|
||||
row_has_available_provider_model(row, api_format, request_operation)
|
||||
&& row.global_model_mappings.as_ref().is_some_and(|patterns| {
|
||||
patterns
|
||||
.iter()
|
||||
@@ -78,10 +94,31 @@ pub fn row_supports_requested_model_with_model_directives(
|
||||
requested_model_name: &str,
|
||||
api_format: &str,
|
||||
enable_model_directives: bool,
|
||||
) -> bool {
|
||||
row_supports_requested_model_with_model_directives_and_request_operation(
|
||||
row,
|
||||
requested_model_name,
|
||||
api_format,
|
||||
enable_model_directives,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn row_supports_requested_model_with_model_directives_and_request_operation(
|
||||
row: &StoredMinimalCandidateSelectionRow,
|
||||
requested_model_name: &str,
|
||||
api_format: &str,
|
||||
enable_model_directives: bool,
|
||||
request_operation: Option<&str>,
|
||||
) -> bool {
|
||||
requested_model_name_candidates(requested_model_name, enable_model_directives).any(
|
||||
|requested_model_name| {
|
||||
row_supports_requested_model_exact(row, requested_model_name.as_ref(), api_format)
|
||||
row_supports_requested_model_exact(
|
||||
row,
|
||||
requested_model_name.as_ref(),
|
||||
api_format,
|
||||
request_operation,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -90,10 +127,11 @@ fn row_supports_requested_model_exact(
|
||||
row: &StoredMinimalCandidateSelectionRow,
|
||||
requested_model_name: &str,
|
||||
api_format: &str,
|
||||
request_operation: Option<&str>,
|
||||
) -> bool {
|
||||
row_has_available_provider_model(row, api_format)
|
||||
row_has_available_provider_model(row, api_format, request_operation)
|
||||
&& (row.global_model_name == requested_model_name
|
||||
|| (row_default_provider_model_name_available(row, api_format)
|
||||
|| (row_default_provider_model_name_available(row, api_format, request_operation)
|
||||
&& row.model_provider_model_name == requested_model_name)
|
||||
|| row.global_model_mappings.as_ref().is_some_and(|patterns| {
|
||||
patterns
|
||||
@@ -105,7 +143,7 @@ fn row_supports_requested_model_exact(
|
||||
.as_ref()
|
||||
.is_some_and(|mappings| {
|
||||
mappings.iter().any(|mapping| {
|
||||
mapping_scope_matches(mapping, row, api_format)
|
||||
mapping_scope_matches(mapping, row, api_format, request_operation)
|
||||
&& mapping.name == requested_model_name
|
||||
})
|
||||
})
|
||||
@@ -145,7 +183,24 @@ pub fn resolve_provider_model_name_with_model_directives(
|
||||
api_format: &str,
|
||||
enable_model_directives: bool,
|
||||
) -> Option<(String, Option<String>)> {
|
||||
let selected_provider_model_name = resolve_selected_provider_model_name(row, api_format)?;
|
||||
resolve_provider_model_name_with_model_directives_and_request_operation(
|
||||
row,
|
||||
requested_model_name,
|
||||
api_format,
|
||||
enable_model_directives,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn resolve_provider_model_name_with_model_directives_and_request_operation(
|
||||
row: &StoredMinimalCandidateSelectionRow,
|
||||
requested_model_name: &str,
|
||||
api_format: &str,
|
||||
enable_model_directives: bool,
|
||||
request_operation: Option<&str>,
|
||||
) -> Option<(String, Option<String>)> {
|
||||
let selected_provider_model_name =
|
||||
resolve_selected_provider_model_name(row, api_format, request_operation)?;
|
||||
let Some(key_allowed_models) = row.key_allowed_models.as_ref() else {
|
||||
return Some((selected_provider_model_name, None));
|
||||
};
|
||||
@@ -175,7 +230,7 @@ pub fn resolve_provider_model_name_with_model_directives(
|
||||
sorted_allowed_models.sort_unstable();
|
||||
|
||||
for &allowed_model in &sorted_allowed_models {
|
||||
if row_has_candidate_model_name(row, api_format, allowed_model) {
|
||||
if row_has_candidate_model_name(row, api_format, request_operation, allowed_model) {
|
||||
let allowed_model = allowed_model.to_owned();
|
||||
return Some((selected_provider_model_name.clone(), Some(allowed_model)));
|
||||
}
|
||||
@@ -198,13 +253,14 @@ pub fn select_provider_model_name(
|
||||
row: &StoredMinimalCandidateSelectionRow,
|
||||
api_format: &str,
|
||||
) -> String {
|
||||
resolve_selected_provider_model_name(row, api_format)
|
||||
resolve_selected_provider_model_name(row, api_format, None)
|
||||
.unwrap_or_else(|| row.model_provider_model_name.clone())
|
||||
}
|
||||
|
||||
fn resolve_selected_provider_model_name(
|
||||
row: &StoredMinimalCandidateSelectionRow,
|
||||
api_format: &str,
|
||||
request_operation: Option<&str>,
|
||||
) -> Option<String> {
|
||||
let Some(mappings) = row.model_provider_model_mappings.as_ref() else {
|
||||
return Some(row.model_provider_model_name.clone());
|
||||
@@ -212,17 +268,20 @@ fn resolve_selected_provider_model_name(
|
||||
|
||||
if let Some(mapping) = mappings
|
||||
.iter()
|
||||
.filter(|mapping| mapping_scope_matches(mapping, row, api_format))
|
||||
.filter(|mapping| mapping_scope_matches(mapping, row, api_format, request_operation))
|
||||
.min_by(|left, right| {
|
||||
left.priority
|
||||
.cmp(&right.priority)
|
||||
.then_with(|| {
|
||||
mapping_operation_scope_rank(right).cmp(&mapping_operation_scope_rank(left))
|
||||
})
|
||||
.then(left.name.cmp(&right.name))
|
||||
})
|
||||
{
|
||||
return Some(mapping.name.clone());
|
||||
}
|
||||
|
||||
row_default_provider_model_name_available(row, api_format)
|
||||
row_default_provider_model_name_available(row, api_format, request_operation)
|
||||
.then(|| row.model_provider_model_name.clone())
|
||||
}
|
||||
|
||||
@@ -231,12 +290,12 @@ pub fn candidate_model_names(
|
||||
api_format: &str,
|
||||
) -> BTreeSet<String> {
|
||||
let mut names = BTreeSet::new();
|
||||
if row_default_provider_model_name_available(row, api_format) {
|
||||
if row_default_provider_model_name_available(row, api_format, None) {
|
||||
names.insert(row.model_provider_model_name.clone());
|
||||
}
|
||||
if let Some(mappings) = row.model_provider_model_mappings.as_ref() {
|
||||
for mapping in mappings {
|
||||
if mapping_scope_matches(mapping, row, api_format) {
|
||||
if mapping_scope_matches(mapping, row, api_format, None) {
|
||||
names.insert(mapping.name.clone());
|
||||
}
|
||||
}
|
||||
@@ -247,13 +306,15 @@ pub fn candidate_model_names(
|
||||
fn row_has_available_provider_model(
|
||||
row: &StoredMinimalCandidateSelectionRow,
|
||||
api_format: &str,
|
||||
request_operation: Option<&str>,
|
||||
) -> bool {
|
||||
resolve_selected_provider_model_name(row, api_format).is_some()
|
||||
resolve_selected_provider_model_name(row, api_format, request_operation).is_some()
|
||||
}
|
||||
|
||||
fn row_default_provider_model_name_available(
|
||||
row: &StoredMinimalCandidateSelectionRow,
|
||||
api_format: &str,
|
||||
request_operation: Option<&str>,
|
||||
) -> bool {
|
||||
let Some(mappings) = row.model_provider_model_mappings.as_ref() else {
|
||||
return true;
|
||||
@@ -264,7 +325,7 @@ fn row_default_provider_model_name_available(
|
||||
continue;
|
||||
}
|
||||
has_explicit_default_mapping = true;
|
||||
if mapping_scope_matches(mapping, row, api_format) {
|
||||
if mapping_scope_matches(mapping, row, api_format, request_operation) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -275,6 +336,7 @@ fn mapping_scope_matches(
|
||||
mapping: &StoredProviderModelMapping,
|
||||
row: &StoredMinimalCandidateSelectionRow,
|
||||
api_format: &str,
|
||||
request_operation: Option<&str>,
|
||||
) -> bool {
|
||||
let api_format_matches_scope = mapping.api_formats.as_ref().is_none_or(|api_formats| {
|
||||
api_formats
|
||||
@@ -285,13 +347,28 @@ fn mapping_scope_matches(
|
||||
return false;
|
||||
}
|
||||
|
||||
mapping.endpoint_ids.as_ref().is_none_or(|endpoint_ids| {
|
||||
let endpoint_matches_scope = mapping.endpoint_ids.as_ref().is_none_or(|endpoint_ids| {
|
||||
endpoint_ids
|
||||
.iter()
|
||||
.any(|endpoint_id| endpoint_id == &row.endpoint_id)
|
||||
});
|
||||
if !endpoint_matches_scope {
|
||||
return false;
|
||||
}
|
||||
|
||||
mapping.operations.as_ref().is_none_or(|operations| {
|
||||
request_operation.is_some_and(|request_operation| {
|
||||
operations
|
||||
.iter()
|
||||
.any(|operation| operation.eq_ignore_ascii_case(request_operation))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn mapping_operation_scope_rank(mapping: &StoredProviderModelMapping) -> u8 {
|
||||
u8::from(mapping.operations.is_some())
|
||||
}
|
||||
|
||||
pub fn row_supports_required_capability(
|
||||
row: &StoredMinimalCandidateSelectionRow,
|
||||
required_capability: &str,
|
||||
@@ -401,16 +478,18 @@ pub fn normalize_api_format(value: &str) -> String {
|
||||
fn row_has_candidate_model_name(
|
||||
row: &StoredMinimalCandidateSelectionRow,
|
||||
api_format: &str,
|
||||
request_operation: Option<&str>,
|
||||
model_name: &str,
|
||||
) -> bool {
|
||||
(row_default_provider_model_name_available(row, api_format)
|
||||
(row_default_provider_model_name_available(row, api_format, request_operation)
|
||||
&& row.model_provider_model_name == model_name)
|
||||
|| row
|
||||
.model_provider_model_mappings
|
||||
.as_ref()
|
||||
.is_some_and(|mappings| {
|
||||
mappings.iter().any(|mapping| {
|
||||
mapping_scope_matches(mapping, row, api_format) && mapping.name == model_name
|
||||
mapping_scope_matches(mapping, row, api_format, request_operation)
|
||||
&& mapping.name == model_name
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -484,6 +563,7 @@ mod tests {
|
||||
use super::{
|
||||
matches_model_mapping, resolve_provider_model_name,
|
||||
resolve_provider_model_name_with_model_directives,
|
||||
resolve_provider_model_name_with_model_directives_and_request_operation,
|
||||
resolve_requested_global_model_name_with_model_directives, row_supports_requested_model,
|
||||
row_supports_requested_model_with_model_directives,
|
||||
};
|
||||
@@ -518,6 +598,7 @@ mod tests {
|
||||
priority: 1,
|
||||
api_formats: Some(vec!["openai:chat".to_string()]),
|
||||
endpoint_ids: None,
|
||||
operations: None,
|
||||
}]);
|
||||
|
||||
let resolved = resolve_provider_model_name(&row, "gpt-5", "openai:chat")
|
||||
@@ -581,6 +662,7 @@ mod tests {
|
||||
priority: 1,
|
||||
api_formats: Some(vec!["openai:responses".to_string()]),
|
||||
endpoint_ids: None,
|
||||
operations: None,
|
||||
}]);
|
||||
|
||||
assert!(row_supports_requested_model(
|
||||
@@ -599,6 +681,7 @@ mod tests {
|
||||
priority: 1,
|
||||
api_formats: Some(vec!["openai:search".to_string()]),
|
||||
endpoint_ids: None,
|
||||
operations: None,
|
||||
}]);
|
||||
assert!(!row_supports_requested_model(
|
||||
&row,
|
||||
@@ -607,6 +690,51 @@ mod tests {
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn operation_scoped_mapping_overrides_generic_mapping_for_compaction() {
|
||||
let mut row = sample_row("gpt-5.6-sol", "gpt-5.6-sol");
|
||||
row.endpoint_api_format = "openai:responses".to_string();
|
||||
row.model_provider_model_mappings = Some(vec![
|
||||
StoredProviderModelMapping {
|
||||
name: "gpt-5.6-sol".to_string(),
|
||||
priority: 1,
|
||||
api_formats: Some(vec!["openai:responses".to_string()]),
|
||||
endpoint_ids: None,
|
||||
operations: None,
|
||||
},
|
||||
StoredProviderModelMapping {
|
||||
name: "gpt-5.6-terra".to_string(),
|
||||
priority: 1,
|
||||
api_formats: Some(vec!["openai:responses".to_string()]),
|
||||
endpoint_ids: None,
|
||||
operations: Some(vec!["compact".to_string()]),
|
||||
},
|
||||
]);
|
||||
|
||||
assert_eq!(
|
||||
resolve_provider_model_name_with_model_directives_and_request_operation(
|
||||
&row,
|
||||
"gpt-5.6-sol",
|
||||
"openai:responses",
|
||||
false,
|
||||
None,
|
||||
)
|
||||
.map(|resolved| resolved.0),
|
||||
Some("gpt-5.6-sol".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
resolve_provider_model_name_with_model_directives_and_request_operation(
|
||||
&row,
|
||||
"gpt-5.6-sol",
|
||||
"openai:responses",
|
||||
false,
|
||||
Some("compact"),
|
||||
)
|
||||
.map(|resolved| resolved.0),
|
||||
Some("gpt-5.6-terra".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn model_directive_suffix_prefers_exact_model_before_base_fallback() {
|
||||
let exact = sample_row("gpt-5.4-high", "gpt-5.4-high-upstream");
|
||||
@@ -685,6 +813,7 @@ mod tests {
|
||||
priority: 1,
|
||||
api_formats: None,
|
||||
endpoint_ids: Some(vec!["endpoint-openai".to_string()]),
|
||||
operations: None,
|
||||
}]);
|
||||
|
||||
assert!(!row_supports_requested_model(
|
||||
|
||||
Reference in New Issue
Block a user