okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
e9df547
main
1// Signed replay and provider schema policy are tested offline because Antigravity 2// uses an authenticated fixed endpoint that the loopback E2E provider cannot reach. 3import albedo/harness/extensions/antigravity/catalog 4import albedo/harness/extensions/antigravity/stream 5import albedo/harness/extensions/antigravity/wire 6import albedo/openai_api 7import albedo/openai_api/stream as provider_stream 8import albedo/openai_api/types 9import gleam/dynamic 10import gleam/dynamic/decode 11import gleam/int 12import gleam/json 13import gleam/list 14import gleam/option .{ type Option , None , Some } 15import gleam/string 16import gleam/string_tree 17 18const gemini = "gemini-3.1-pro-low" 19 20const claude = "claude-sonnet-4-6" 21 22/// Test fixture models for wire encoding and streaming tests. 23fn model ( id : String ) -> catalog . Model { 24case id { 25"gemini-3.1-pro-low" -> 26catalog . Model ( 27id , 28"Gemini 3.1 Pro (Low)" , 291_048_576 , 3065_535 , 31True , 32catalog . Budget ( 1001 , 8192 , 10_001 ), 33Some ( "MODEL_PLACEHOLDER_M36" ), 34True , 35) 36"claude-sonnet-4-6" -> 37catalog . Model ( 38id , 39"Claude Sonnet 4.6" , 40250_000 , 4164_000 , 42True , 43catalog . Budget ( 4096 , 8192 , 16_384 ), 44None , 45True , 46) 47_ -> catalog . model ( "/nonexistent/albedo-home" , id , None ) 48} 49} 50 51fn context ( id : String ) -> wire . Context { 52wire . Context ( 53"token-1" , 54"project-1" , 55"session-1" , 56model ( id ), 57"antigravity/hub/test" , 58) 59} 60 61fn body ( model : String , request : types . Request ) -> dynamic . Dynamic { 62let assert Ok ( openai_api . Exchange ( body : body , ..)) = 63wire . encode ( context ( model ), request ) 64let assert Ok ( value ) = json . parse ( string_tree . to_string ( body ), decode . dynamic ) 65value 66} 67 68fn at ( 69value : dynamic . Dynamic , 70path : List ( String ), 71decoder : decode . Decoder ( a), 72) -> a{ 73let assert Ok ( found ) = decode . run ( value , decode . at ( path , decoder )) 74found 75} 76 77fn schema_json ( source : String ) -> json . Json { 78let assert Ok ( value ) = json . parse ( source , decode . dynamic ) 79types . encode_value ( value ) 80} 81 82fn schema_request ( id : String , schema : json . Json ) -> types . Request { 83types . Request ( 84.. openai_api . request ( id , [ types . User ( "hi" )]), 85tools : [ types . Tool ( "inputs" , "Choose inputs" , schema , False )], 86options : types . Options ( 87.. types . defaults , 88format : Some ( types . JsonSchema ( "answer" , schema , True )), 89), 90) 91} 92 93fn tool_schema ( value : dynamic . Dynamic ) -> dynamic . Dynamic { 94let assert [ tool ] = 95at ( value , [ "request" , "tools" ], decode . list ( decode . dynamic )) 96let assert [ declaration ] = 97at ( tool , [ "functionDeclarations" ], decode . list ( decode . dynamic )) 98at ( declaration , [ "parameters" ], decode . dynamic ) 99} 100 101pub fn schema_resolves_references_and_merges_object_requirements_test () -> Result ( 102dynamic . Dynamic , 103List ( decode . DecodeError ), 104) { 105let schema = 106schema_json ( 107"{ 108\"definitions\": {\"child\": {\"type\": \"boolean\"}}, 109\"$defs\": {\"child\": {\"type\": \"object\", \"properties\": { 110\"value\": {\"type\": \"integer\"} 111}, \"required\": [\"value\", \"missing\", 12]}}, 112\"properties\": {\"shared\": {\"type\": \"string\"}}, 113\"required\": [\"shared\", \"absent\", false], 114\"allOf\": [ 115{\"title\": \"earlier\", \"properties\": { 116\"shared\": {\"type\": \"number\"}, 117\"branch\": {\"type\": \"boolean\"}, 118\"children\": {\"type\": \"array\", \"items\": {\"$ref\": \"#/arbitrary/path/child\"}} 119}, \"required\": [\"children\", \"branch\"]}, 120{\"title\": \"later\", \"properties\": {\"branch\": {\"type\": \"string\"}}, 121\"required\": [\"shared\", \"branch\", null]} 122] 123}" , 124) 125let actual = tool_schema ( body ( gemini , schema_request ( gemini , schema ))) 126assert at ( actual , [ "type" ], decode . string ) == "object" 127assert at ( actual , [ "title" ], decode . string ) == "later" 128assert at ( actual , [ "properties" , "shared" , "type" ], decode . string ) == "string" 129assert at ( actual , [ "properties" , "branch" , "type" ], decode . string ) 130== "boolean" 131assert at ( actual , [ "required" ], decode . list ( decode . string )) 132== [ "branch" , "children" , "shared" ] 133let child = at ( actual , [ "properties" , "children" , "items" ], decode . dynamic ) 134assert at ( child , [ "type" ], decode . string ) == "object" 135assert at ( child , [ "properties" , "value" , "type" ], decode . string ) == "integer" 136assert at ( child , [ "required" ], decode . list ( decode . string )) == [ "value" ] 137let assert Error ( _ ) = decode . run ( actual , decode . at ([ "allOf" ], decode . dynamic )) 138} 139 140pub fn schema_reduces_unions_and_keeps_constraint_guidance_test () -> Result ( 141dynamic . Dynamic , 142List ( decode . DecodeError ), 143) { 144let schema = 145schema_json ( 146"{\"type\": \"object\", \"properties\": { 147\"nullable\": {\"anyOf\": [{\"type\": \"null\"}, {\"type\": \"integer\"}]}, 148\"typed\": {\"type\": [null, \"null\", \"boolean\", \"string\"]}, 149\"choice\": {\"oneOf\": [{\"const\": 7}, {\"enum\": [true, \"seven\", null, 7]}]}, 150\"constant\": {\"const\": false}, 151\"mixed\": {\"description\": \"Pick\", \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"number\"}]}, 152\"limited\": {\"type\": \"string\", \"description\": \"Name\", \"pattern\": \"^[a-z]+$\", \"minLength\": 2} 153}}" , 154) 155let actual = tool_schema ( body ( gemini , schema_request ( gemini , schema ))) 156let properties = at ( actual , [ "properties" ], decode . dynamic ) 157assert at ( properties , [ "nullable" , "type" ], decode . string ) == "integer" 158assert at ( properties , [ "typed" , "type" ], decode . string ) == "boolean" 159assert at ( properties , [ "choice" , "type" ], decode . string ) == "string" 160assert at ( properties , [ "choice" , "enum" ], decode . list ( decode . string )) 161== [ "7" , "seven" , "true" ] 162assert at ( properties , [ "constant" , "enum" ], decode . list ( decode . string )) 163== [ "false" ] 164assert at ( properties , [ "mixed" , "type" ], decode . string ) == "string" 165assert at ( properties , [ "mixed" , "description" ], decode . string ) 166== "Pick (one of: string, number)" 167let limited = at ( properties , [ "limited" ], decode . dynamic ) 168let guidance = at ( limited , [ "description" ], decode . string ) 169assert string . contains ( guidance , "Name" ) 170assert string . contains ( guidance , "pattern: \"^[a-z]+$\"" ) 171assert string . contains ( guidance , "minLength: 2" ) 172let assert Error ( _ ) = 173decode . run ( limited , decode . at ([ "pattern" ], decode . dynamic )) 174} 175 176fn item_depth ( schema : dynamic . Dynamic ) -> Int { 177case decode . run ( schema , decode . at ([ "items" ], decode . dynamic )) { 178Ok ( items ) -> 1 + item_depth ( items ) 179Error ( _ ) -> 0 180} 181} 182 183pub fn schema_bounds_recursion_and_handles_malformed_keywords_test () -> Nil { 184let malformed = 185schema_json ( 186"{ 187\"type\": \"object\", \"description\": false, \"title\": [], \"required\": true, 188\"definitions\": [], \"$defs\": {\"loop\": {\"$ref\": \"#/$defs/loop\"}}, 189\"allOf\": [null, false, {\"properties\": [], \"required\": false}], 190\"properties\": { 191\"cycle\": {\"$ref\": \"#/$defs/loop\"}, 192\"object\": {\"type\": \"object\", \"properties\": [], \"required\": true}, 193\"array\": {\"type\": \"array\", \"items\": [false, {\"type\": \"string\"}]}, 194\"union\": {\"oneOf\": [3, {\"title\": false}, {\"title\": []}]}, 195\"enum\": {\"type\": \"string\", \"enum\": false}, 196\"combiner\": {\"anyOf\": false, \"allOf\": {}, \"oneOf\": 2} 197} 198}" , 199) 200let actual = tool_schema ( body ( gemini , schema_request ( gemini , malformed ))) 201let assert Ok ( empty ) = json . parse ( "{}" , decode . dynamic ) 202assert at ( actual , [ "properties" , "cycle" ], decode . dynamic ) == empty 203assert at ( actual , [ "properties" , "object" , "properties" ], decode . dynamic ) 204== empty 205let assert Error ( _ ) = 206decode . run ( actual , decode . at ([ "required" ], decode . dynamic )) 207assert at ( actual , [ "title" ], decode . string ) == "" 208assert at ( actual , [ "description" ], decode . string ) == "" 209let assert Error ( _ ) = 210decode . run ( 211actual , 212decode . at ([ "properties" , "enum" , "enum" ], decode . dynamic ), 213) 214assert at ( actual , [ "properties" , "combiner" ], decode . dynamic ) == empty 215assert at ( actual , [ "properties" , "union" , "description" ], decode . string ) 216== "one of: schema, schema" 217assert at ( actual , [ "properties" , "array" , "items" , "type" ], decode . string ) 218== "string" 219let deep = 220list . fold ( list . repeat ( Nil , 40 ), json . object ([]), fn ( items , _ ) { 221json . object ([#( "type" , json . string ( "array" )), #( "items" , items )]) 222}) 223let schema = 224json . object ([ 225#( "type" , json . string ( "object" )), 226#( "properties" , json . object ([#( "deep" , deep )])), 227]) 228let actual = tool_schema ( body ( gemini , schema_request ( gemini , schema ))) 229let depth = item_depth ( at ( actual , [ "properties" , "deep" ], decode . dynamic )) 230assert depth > 0 231assert depth <= 32 232let definitions = 233int . range ( 0 , 41 , [], fn ( definitions , index ) { 234let target = case index { 23540 -> 236json . object ([ 237#( "type" , json . string ( "object" )), 238#( 239"properties" , 240json . object ([ 241#( 242"unreachable" , 243json . object ([#( "type" , json . string ( "string" ))]), 244), 245]), 246), 247]) 248_ -> 249json . object ([ 250#( "$ref" , json . string ( "#/$defs/" <> int . to_string ( index + 1 ))), 251]) 252} 253[#( int . to_string ( index ), target ), .. definitions ] 254}) 255let schema = 256json . object ([ 257#( "$ref" , json . string ( "#/$defs/0" )), 258#( "$defs" , json . object ( definitions )), 259]) 260let actual = tool_schema ( body ( gemini , schema_request ( gemini , schema ))) 261assert at ( actual , [ "type" ], decode . string ) == "object" 262assert at ( actual , [ "properties" ], decode . dynamic ) == empty 263} 264 265pub fn both_model_families_normalize_tools_and_structured_responses_test () -> Nil { 266let schemas = [ 267#( 268schema_json ( 269"{\"properties\": {\"answer\": {\"const\": 42}}, \"required\": [\"answer\", \"missing\"]}" , 270), 271True , 272), 273#( json . bool ( True ), False ), 274#( 275schema_json ( "{\"type\": \"array\", \"items\": {\"type\": \"string\"}}" ), 276False , 277), 278] 279list . each ([ gemini , claude ], fn ( id ) { 280list . each ( schemas , fn ( entry ) { 281let #( schema , has_answer ) = entry 282let value = body ( id , schema_request ( id , schema )) 283let parameters = tool_schema ( value ) 284let response = 285at ( 286value , 287[ "request" , "generationConfig" , "responseSchema" ], 288decode . dynamic , 289) 290assert parameters == response 291assert at ( response , [ "type" ], decode . string ) == "object" 292assert at ( 293value , 294[ "request" , "generationConfig" , "responseMimeType" ], 295decode . string , 296) 297== "application/json" 298case has_answer { 299True -> { 300assert at ( 301response , 302[ "properties" , "answer" , "enum" ], 303decode . list ( decode . string ), 304) 305== [ "42" ] 306assert at ( response , [ "required" ], decode . list ( decode . string )) 307== [ "answer" ] 308} 309False -> { 310let assert Ok ( empty ) = json . parse ( "{}" , decode . dynamic ) 311assert at ( response , [ "properties" ], decode . dynamic ) == empty 312} 313} 314}) 315}) 316} 317 318fn chunk ( json : String ) -> String { 319"{\"response\":" <> json <> ",\"traceId\":\"t\"}" 320} 321 322/// Feeds each payload, then ends the body. 323fn reduce ( 324id : String , 325payloads : List ( String ), 326) -> #( Result ( types . Turn , types . Error ), List ( types . Event )) { 327let #( reducer , events ) = 328list . fold ( payloads , #( stream . reducer ( model ( id )), []), fn ( acc , data ) { 329let #( reducer , events ) = acc 330let assert Ok (#( next , new , None )) = reducer . feed ( data ) 331#( next , list . append ( events , new )) 332}) 333#( reducer . finish (), events ) 334} 335 336const signed_turn = [ 337"{\"responseId\":\"r1\",\"candidates\":[{\"content\":{\"role\":\"model\",\"parts\":[{\"text\":\"weigh\",\"thought\":true},{\"text\":\"ing\",\"thought\":true,\"thoughtSignature\":\"c2ln\"}]}}]}" , 338"{\"candidates\":[{\"content\":{\"parts\":[{\"text\":\"looking\"},{\"functionCall\":{\"name\":\"bash\",\"args\":{\"command\":\"ls\"}},\"thoughtSignature\":\"Y2FsbA==\"}]},\"finishReason\":\"STOP\"}],\"usageMetadata\":{\"promptTokenCount\":10,\"candidatesTokenCount\":3,\"thoughtsTokenCount\":2,\"cachedContentTokenCount\":4}}" , 339] 340 341fn signed_turn_payloads () -> List ( String ) { 342list . map ( signed_turn , chunk ) 343} 344 345pub fn stream_reduces_thoughts_text_and_calls_test () -> Nil { 346let #( outcome , events ) = reduce ( gemini , signed_turn_payloads ()) 347let assert Ok ( turn ) = outcome 348let assert [ 349types . Started ( "r1" ), 350types . ThinkingDelta ( "weigh" ), 351types . ThinkingDelta ( "ing" ), 352types . TextDelta ( 0 , 0 , "looking" ), 353types . ArgumentsDelta ( 0 , "bash" , arguments ), 354] = events 355assert arguments == "{\"command\":\"ls\"}" 356assert turn . finish == types . ToolCalls 357// Output folds the 2 thought tokens in; reasoning carries the thought count. 358assert turn . usage 359== Some ( types . Usage ( 10 , 5 , Some ( 4 ), None , None , None , Some ( 2 ))) 360let assert [ types . ToolCall ( id , "bash" , "{\"command\":\"ls\"}" )] = 361turn . tool_calls 362assert string . starts_with ( id , "call_" ) 363assert turn . call_indices == [#( id , 0 )] 364let assert [ item ] = turn . output 365assert types . inspect_item ( item , decode . at ([ "content" ], decode . string )) 366== Ok ( "looking" ) 367assert types . inspect_item ( 368item , 369decode . at ([ "reasoning_content" ], decode . string ), 370) 371== Ok ( "weighing" ) 372} 373 374pub fn stream_maps_multiple_calls_to_their_emitted_output_indices_test () -> Nil { 375let payload = 376chunk ( 377"{\"candidates\":[{\"content\":{\"parts\":[{\"functionCall\":{\"name\":\"bash\",\"args\":{\"command\":\"ls\"}}},{\"functionCall\":{\"name\":\"bash\",\"args\":{\"command\":\"pwd\"}}}]},\"finishReason\":\"STOP\"}],\"usageMetadata\":{\"promptTokenCount\":10,\"candidatesTokenCount\":3}}" , 378) 379let #( outcome , events ) = reduce ( gemini , [ payload ]) 380let assert Ok ( turn ) = outcome 381let assert [ first , second ] = turn . tool_calls 382assert turn . call_indices == [#( first . id , 0 ), #( second . id , 1 )] 383assert events 384== [ 385types . ArgumentsDelta ( 0 , "bash" , "{\"command\":\"ls\"}" ), 386types . ArgumentsDelta ( 1 , "bash" , "{\"command\":\"pwd\"}" ), 387] 388} 389 390pub fn same_model_replay_keeps_signed_parts_test () -> Nil { 391let #( outcome , _ ) = reduce ( gemini , signed_turn_payloads ()) 392let assert Ok ( turn ) = outcome 393let assert [ item ] = turn . output 394let assert [ call ] = turn . tool_calls 395let request = 396openai_api . request ( gemini , [ 397types . User ( "hi" ), 398types . Replay ( item ), 399types . ToolOutput ( call . id , "a b" , []), 400]) 401let contents = 402at ( 403body ( gemini , request ), 404[ "request" , "contents" ], 405decode . list ( decode . dynamic ), 406) 407let assert [ _ , model , result ] = contents 408let parts = at ( model , [ "parts" ], decode . list ( decode . dynamic )) 409let assert [ thought , text , function ] = parts 410assert at ( thought , [ "thought" ], decode . bool ) 411assert at ( thought , [ "text" ], decode . string ) == "weighing" 412assert at ( thought , [ "thoughtSignature" ], decode . string ) == "c2ln" 413assert at ( text , [ "text" ], decode . string ) == "looking" 414assert at ( function , [ "thoughtSignature" ], decode . string ) == "Y2FsbA==" 415assert at ( function , [ "functionCall" , "args" , "command" ], decode . string ) 416== "ls" 417// Gemini correlates by name; ids are only for Claude routes. 418let assert Error ( _ ) = 419decode . run ( function , decode . at ([ "functionCall" , "id" ], decode . string )) 420assert at ( result , [ "role" ], decode . string ) == "user" 421assert at ( 422result , 423[ "parts" ], 424decode . list ( decode . at ([ "functionResponse" , "name" ], decode . string )), 425) 426== [ "bash" ] 427} 428 429pub fn another_models_output_replays_portably_test () -> Nil { 430let #( outcome , _ ) = reduce ( gemini , signed_turn_payloads ()) 431let assert Ok ( turn ) = outcome 432let assert [ item ] = turn . output 433let assert [ call ] = turn . tool_calls 434let request = 435openai_api . request ( claude , [ 436types . User ( "hi" ), 437types . Replay ( item ), 438types . ToolOutput ( call . id , "" , []), 439]) 440let request_body = body ( claude , request ) 441let assert [ _ , model , result ] = 442at ( request_body , [ "request" , "contents" ], decode . list ( decode . dynamic )) 443let assert [ text , function ] = 444at ( model , [ "parts" ], decode . list ( decode . dynamic )) 445assert at ( text , [ "text" ], decode . string ) == "looking" 446assert at ( function , [ "functionCall" , "id" ], decode . string ) == call . id 447let assert Error ( _ ) = 448decode . run ( function , decode . at ([ "thoughtSignature" ], decode . string )) 449assert at ( 450result , 451[ "parts" ], 452decode . list ( decode . at ([ "functionResponse" , "id" ], decode . string )), 453) 454== [ call . id ] 455assert at ( 456request_body , 457[ "request" , "toolConfig" , "functionCallingConfig" , "mode" ], 458decode . string , 459) 460== "VALIDATED" 461} 462 463pub fn foreign_calls_carry_the_skip_signature_on_gemini_test () -> Nil { 464let assert Ok ( item ) = 465json . parse ( 466"{\"role\":\"assistant\",\"content\":null,\"tool_calls\":[{\"id\":\"c1\",\"type\":\"function\",\"function\":{\"name\":\"bash\",\"arguments\":\"{}\"}}]}" , 467types . replay_decoder ( types . ChatCompletions ), 468) 469let request = 470openai_api . request ( gemini , [ 471types . User ( "hi" ), 472types . Replay ( item ), 473types . ToolOutput ( "c1" , "ok" , []), 474]) 475let assert [ _ , model , _ ] = 476at ( 477body ( gemini , request ), 478[ "request" , "contents" ], 479decode . list ( decode . dynamic ), 480) 481assert at ( 482model , 483[ "parts" ], 484decode . list ( decode . at ([ "thoughtSignature" ], decode . string )), 485) 486== [ "skip_thought_signature_validator" ] 487} 488 489pub fn frame_archive_images_carry_no_empty_text_part_test () -> Nil { 490// Snapcompact's frame archive attaches images with no text after the 491// archive prompt; Cloud Code Assist's Claude translation rejected the 492// empty text part with "messages.0.content.2.text.text: Field required". 493let assert Ok ( first ) = types . image ( "image/png" , "aGk=" , 2 , 3 , 2 ) 494let assert Ok ( second ) = types . image ( "image/png" , "aGk=" , 2 , 3 , 2 ) 495let request = 496openai_api . request ( claude , [ 497types . UserImage ( "the archive prompt" , [ first ]), 498types . UserImage ( "" , [ second ]), 499]) 500let assert [ user ] = 501at ( 502body ( claude , request ), 503[ "request" , "contents" ], 504decode . list ( decode . dynamic ), 505) 506assert at ( user , [ "role" ], decode . string ) == "user" 507let assert [ text , first_part , second_part ] = 508at ( user , [ "parts" ], decode . list ( decode . dynamic )) 509assert at ( text , [ "text" ], decode . string ) == "the archive prompt" 510assert at ( first_part , [ "inlineData" , "mimeType" ], decode . string ) 511== "image/png" 512assert at ( second_part , [ "inlineData" , "mimeType" ], decode . string ) 513== "image/png" 514let assert Error ( _ ) = 515decode . run ( second_part , decode . at ([ "text" ], decode . string )) 516Nil 517} 518 519pub fn empty_body_is_a_retryable_failure_test () -> Nil { 520let #( outcome , _ ) = reduce ( gemini , []) 521assert outcome == Error ( types . UnexpectedEnd ) 522} 523 524pub fn stream_errors_surface_the_provider_message_test () -> Result ( 525#( provider_stream . Reducer , List ( types . Event ), option . Option ( types . Turn )), 526types . Error , 527) { 528let reducer = stream . reducer ( model ( gemini )) 529let assert Error ( types . ProviderError ( "quota" )) = 530reducer . feed ( "{\"error\":{\"code\":429,\"message\":\"quota\"}}" ) 531} 532 533pub type LimitResult { 534LimitResult ( until : Int , lasting : Bool , meter : Option ( String )) 535} 536 537@external ( erlang , "albedo_antigravity" , "limit" ) 538fn native_limit ( body : String ) -> Result ( LimitResult , Nil ) 539 540@external ( erlang , "albedo_antigravity" , "limit" ) 541fn native_limit_fallback ( 542body : String , 543fallback : Option ( String ), 544) -> Result ( LimitResult , Nil ) 545 546pub fn limit_extracts_claude_meter_from_metadata_model_test () -> Nil { 547let body = 548"{\"error\":{\"code\":429,\"status\":\"RESOURCE_EXHAUSTED\",\"details\":[{\"@type\":\"type.googleapis.com/google.rpc.ErrorInfo\",\"reason\":\"QUOTA_EXHAUSTED\",\"metadata\":{\"model\":\"claude-sonnet-5-5-high\",\"quotaResetDelay\":\"60s\"}}]}}" 549let assert Ok ( result ) = native_limit ( body ) 550assert result . meter == Some ( "claude" ) 551assert result . lasting == True 552} 553 554pub fn limit_extracts_gpt_oss_meter_from_metadata_model_test () -> Nil { 555let body = 556"{\"error\":{\"code\":429,\"status\":\"RESOURCE_EXHAUSTED\",\"details\":[{\"@type\":\"type.googleapis.com/google.rpc.ErrorInfo\",\"reason\":\"QUOTA_EXHAUSTED\",\"metadata\":{\"model\":\"gpt-oss-120b-medium\",\"quotaResetDelay\":\"60s\"}}]}}" 557let assert Ok ( result ) = native_limit ( body ) 558assert result . meter == Some ( "gpt-oss" ) 559assert result . lasting == True 560} 561 562pub fn limit_extracts_gemini_meter_from_metadata_model_test () -> Nil { 563let body = 564"{\"error\":{\"code\":429,\"status\":\"RESOURCE_EXHAUSTED\",\"details\":[{\"@type\":\"type.googleapis.com/google.rpc.ErrorInfo\",\"reason\":\"QUOTA_EXHAUSTED\",\"metadata\":{\"model\":\"gemini-3.8-flash-medium\",\"quotaResetDelay\":\"60s\"}}]}}" 565let assert Ok ( result ) = native_limit ( body ) 566assert result . meter == Some ( "gemini" ) 567assert result . lasting == True 568} 569 570pub fn limit_falls_back_to_request_family_when_metadata_model_missing_test () -> Nil { 571let body = 572"{\"error\":{\"code\":429,\"status\":\"RESOURCE_EXHAUSTED\",\"details\":[{\"@type\":\"type.googleapis.com/google.rpc.ErrorInfo\",\"reason\":\"QUOTA_EXHAUSTED\",\"metadata\":{\"quotaResetDelay\":\"60s\"}}]}}" 573let assert Ok ( claude_result ) = native_limit_fallback ( body , Some ( "claude" )) 574assert claude_result . meter == Some ( "claude" ) 575 576let assert Ok ( gemini_result ) = native_limit_fallback ( body , Some ( "gemini" )) 577assert gemini_result . meter == Some ( "gemini" ) 578 579let assert Ok ( gpt_result ) = native_limit_fallback ( body , Some ( "gpt-oss" )) 580assert gpt_result . meter == Some ( "gpt-oss" ) 581 582let assert Ok ( no_fallback ) = native_limit ( body ) 583assert no_fallback . meter == None 584} 585 586pub fn model_capacity_exhausted_marks_nobody_test () -> Nil { 587let body = 588"{\"error\":{\"code\":429,\"status\":\"RESOURCE_EXHAUSTED\",\"details\":[{\"@type\":\"type.googleapis.com/google.rpc.ErrorInfo\",\"reason\":\"MODEL_CAPACITY_EXHAUSTED\",\"metadata\":{\"model\":\"claude-sonnet-5-5-high\"}}]}}" 589assert native_limit ( body ) == Error ( Nil ) 590}