|
1 | 1 | #![allow(dead_code)] |
2 | 2 |
|
| 3 | +use std::collections::HashMap; |
| 4 | + |
3 | 5 | use serde::de::DeserializeOwned; |
4 | 6 | use serde::Deserialize; |
5 | 7 | use serde_json::{json, Map, Value}; |
@@ -432,6 +434,8 @@ pub(crate) struct StatuslineSpecificOptions { |
432 | 434 | pub(crate) timezone: Option<String>, |
433 | 435 | /// Show statusline debug information. |
434 | 436 | pub(crate) debug: Option<bool>, |
| 437 | + /// Map model identifiers to short display labels. |
| 438 | + pub(crate) model_label_aliases: Option<HashMap<String, String>>, |
435 | 439 | } |
436 | 440 |
|
437 | 441 | #[derive(Debug, Default, Deserialize, JsonSchema)] |
@@ -581,6 +585,7 @@ impl StatuslineSpecificOptions { |
581 | 585 | context_medium_threshold: u64_option(map, "contextMediumThreshold"), |
582 | 586 | timezone: string_option(map, "timezone"), |
583 | 587 | debug: bool_option(map, "debug"), |
| 588 | + model_label_aliases: hashmap_option(map, "modelLabelAliases"), |
584 | 589 | } |
585 | 590 | } |
586 | 591 | } |
@@ -720,6 +725,21 @@ where |
720 | 725 | serde_json::from_value(map.get(key)?.clone()).ok() |
721 | 726 | } |
722 | 727 |
|
| 728 | +fn hashmap_option(map: &Map<String, Value>, key: &str) -> Option<HashMap<String, String>> { |
| 729 | + let obj = map.get(key)?.as_object()?; |
| 730 | + let mut result = HashMap::new(); |
| 731 | + for (k, v) in obj { |
| 732 | + if let Some(s) = v.as_str() { |
| 733 | + result.insert(k.clone(), s.to_string()); |
| 734 | + } |
| 735 | + } |
| 736 | + if result.is_empty() { |
| 737 | + None |
| 738 | + } else { |
| 739 | + Some(result) |
| 740 | + } |
| 741 | +} |
| 742 | + |
723 | 743 | fn enrich_schema(value: &mut Value) { |
724 | 744 | match value { |
725 | 745 | Value::Object(map) => { |
@@ -917,6 +937,7 @@ mod tests { |
917 | 937 | use serde_json::{json, Value}; |
918 | 938 |
|
919 | 939 | use super::generate_config_schema_json; |
| 940 | + use super::StatuslineSpecificOptions; |
920 | 941 |
|
921 | 942 | #[test] |
922 | 943 | fn schema_option_sets_expose_expected_keys() { |
@@ -969,6 +990,7 @@ mod tests { |
969 | 990 | "contextMediumThreshold", |
970 | 991 | "costSource", |
971 | 992 | "debug", |
| 993 | + "modelLabelAliases", |
972 | 994 | "noCache", |
973 | 995 | "noOffline", |
974 | 996 | "offline", |
@@ -1248,6 +1270,39 @@ mod tests { |
1248 | 1270 | ); |
1249 | 1271 | } |
1250 | 1272 |
|
| 1273 | + #[test] |
| 1274 | + fn statusline_options_parse_model_label_aliases() { |
| 1275 | + let map = serde_json::json!({ |
| 1276 | + "modelLabelAliases": { |
| 1277 | + "arn:aws:bedrock:ap-northeast-1:012345678910:application-inference-profile/abcde12345": "claude-opus-4-6" |
| 1278 | + } |
| 1279 | + }); |
| 1280 | + let options = StatuslineSpecificOptions::from_map(map.as_object().unwrap()); |
| 1281 | + |
| 1282 | + let aliases = options.model_label_aliases.unwrap(); |
| 1283 | + assert_eq!( |
| 1284 | + aliases.get( |
| 1285 | + "arn:aws:bedrock:ap-northeast-1:012345678910:application-inference-profile/abcde12345" |
| 1286 | + ), |
| 1287 | + Some(&"claude-opus-4-6".to_string()) |
| 1288 | + ); |
| 1289 | + } |
| 1290 | + |
| 1291 | + #[test] |
| 1292 | + fn statusline_options_ignore_non_string_alias_values() { |
| 1293 | + let map = serde_json::json!({ |
| 1294 | + "modelLabelAliases": { |
| 1295 | + "valid": "short", |
| 1296 | + "invalid": 123 |
| 1297 | + } |
| 1298 | + }); |
| 1299 | + let options = StatuslineSpecificOptions::from_map(map.as_object().unwrap()); |
| 1300 | + |
| 1301 | + let aliases = options.model_label_aliases.unwrap(); |
| 1302 | + assert_eq!(aliases.get("valid"), Some(&"short".to_string())); |
| 1303 | + assert!(!aliases.contains_key("invalid")); |
| 1304 | + } |
| 1305 | + |
1251 | 1306 | #[test] |
1252 | 1307 | fn snapshots_schema_agent_specific_option_edges() { |
1253 | 1308 | if running_in_schema_generator_test_binary() { |
|
0 commit comments