Something went wrong. Try again.
My version of https://github.com/vercel-labs/fx
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014const std = @import("std");const builtin = @import("builtin");const build_options = @import("build_options");const secret = @import("../core/auth/secret.zig");const agent_stream_provider = @import("../core/agent/stream_provider.zig");const debug_trace = @import("../core/shared/debug_trace.zig");const http_pool = @import("../core/shared/http_pool.zig");const io_mod = @import("../core/shared/io.zig");const mem_utils = @import("../core/shared/mem_utils.zig");const types = @import("../core/shared/types.zig");const atomic_value = @import("../core/mcp/atomic_value.zig");const json_comparison = @import("../core/shared/json_comparison.zig");const sse = @import("sse.zig");
pub fn isRetryableGatewayError(err: anyerror) bool { return err == error.HttpConnectionClosing or err == error.ConnectionResetByPeer or err == error.ConnectionTimedOut;}
pub fn networkFailureEvidence( err: anyerror, delivery: DeliveryCertainty.State,) ?agent_stream_provider.NetworkFailureEvidence { const cause: agent_stream_provider.NetworkFailureCause = if (err == error.SystemResumed) .system_resumed else if (err == error.StreamStalled) .stream_stalled else if (isConnectivityFailure(err)) .connectivity_lost else if (isRetryableAgentNetworkError(err)) .transport_interrupted else return null; return .{ .cause = cause, .delivery = delivery };}
/// Errors that prove the network path itself is down: nothing reached a/// server, so no request was sent and no generation exists. Distinct from/// connected-but-failed errors (reset mid-stream, closed connection), which/// carry delivery ambiguity and belong to the retry class.pub fn isConnectivityFailure(err: anyerror) bool { return err == error.UnknownHostName or err == error.NameServerFailure or err == error.NoAddressReturned or err == error.DetectingNetworkConfigurationFailed or err == error.AddressUnavailable or err == error.ConnectionRefused or err == error.ConnectionTimedOut or err == error.HostUnreachable or err == error.NetworkUnreachable or err == error.NetworkDown;}
fn isRetryableAgentNetworkError(err: anyerror) bool { return err == error.TlsInitializationFailed or err == error.ConnectionSetupTimedOut or err == error.UnknownHostName or err == error.NameServerFailure or err == error.NoAddressReturned or err == error.DetectingNetworkConfigurationFailed or err == error.AddressUnavailable or err == error.ConnectionPending or err == error.ConnectionRefused or err == error.HostUnreachable or err == error.NetworkUnreachable or err == error.NetworkDown or err == error.Timeout or err == error.WouldBlock or err == error.WriteFailed or err == error.ReadFailed or isRetryableGatewayError(err);}
fn connectedIoFailure( cancelled: bool, system_resumed: bool, transport_error: anyerror,) anyerror { if (cancelled) return error.Cancelled; if (system_resumed) return error.SystemResumed; return transport_error;}
fn connectedIoFailureWithWatch( watch: ?*ConnectedRequestWatch, cancelled: bool, system_resumed: bool, transport_error: anyerror,) anyerror { const mapped = connectedIoFailure(cancelled, system_resumed, transport_error); return if (watch) |state| state.finish_error(mapped) else mapped;}
test "connected request failures prefer cancellation then wake evidence" { try std.testing.expectEqual( error.Cancelled, connectedIoFailure(true, true, error.WriteFailed), ); try std.testing.expectEqual( error.SystemResumed, connectedIoFailure(false, true, error.WriteFailed), ); try std.testing.expectEqual( error.WriteFailed, connectedIoFailure(false, false, error.WriteFailed), );}
test "isRetryableGatewayError matches active retryable transport errors" { try std.testing.expect(isRetryableGatewayError(error.HttpConnectionClosing)); try std.testing.expect(isRetryableGatewayError(error.ConnectionResetByPeer)); try std.testing.expect(isRetryableGatewayError(error.ConnectionTimedOut)); try std.testing.expect(!isRetryableGatewayError(error.AccessDenied));}
test "native network failure evidence covers setup send read and resume failures" { const Cases = struct { err: anyerror, cause: agent_stream_provider.NetworkFailureCause = .transport_interrupted, }; const cases = [_]Cases{ .{ .err = error.TlsInitializationFailed }, .{ .err = error.ConnectionSetupTimedOut }, .{ .err = error.UnknownHostName, .cause = .connectivity_lost }, .{ .err = error.NameServerFailure, .cause = .connectivity_lost }, .{ .err = error.NoAddressReturned, .cause = .connectivity_lost }, .{ .err = error.DetectingNetworkConfigurationFailed, .cause = .connectivity_lost }, .{ .err = error.AddressUnavailable, .cause = .connectivity_lost }, .{ .err = error.ConnectionPending }, .{ .err = error.ConnectionRefused, .cause = .connectivity_lost }, .{ .err = error.ConnectionResetByPeer }, .{ .err = error.ConnectionTimedOut, .cause = .connectivity_lost }, .{ .err = error.HostUnreachable, .cause = .connectivity_lost }, .{ .err = error.NetworkUnreachable, .cause = .connectivity_lost }, .{ .err = error.NetworkDown, .cause = .connectivity_lost }, .{ .err = error.Timeout }, .{ .err = error.WouldBlock }, .{ .err = error.HttpConnectionClosing }, .{ .err = error.WriteFailed }, .{ .err = error.ReadFailed }, .{ .err = error.StreamStalled, .cause = .stream_stalled }, .{ .err = error.SystemResumed, .cause = .system_resumed }, };
for (cases) |case| { const evidence = networkFailureEvidence( case.err, .possibly_sent, ) orelse return error.TestExpectedNetworkFailureEvidence; try std.testing.expectEqual(case.cause, evidence.cause); try std.testing.expectEqual( DeliveryCertainty.State.possibly_sent, evidence.delivery, ); }
const pre_send = networkFailureEvidence( error.ConnectionRefused, .definitely_unsent, ).?; try std.testing.expectEqual( DeliveryCertainty.State.definitely_unsent, pre_send.delivery, );}
test "native network failure evidence excludes opaque and configuration failures" { const excluded = [_]anyerror{ error.JsHostStreamFailed, error.OutOfMemory, error.AccessDenied, error.UnsupportedUriScheme, error.ProtocolUnsupportedBySystem, error.ResolvConfParseFailed, error.InvalidDnsARecord, };
for (excluded) |err| { try std.testing.expectEqual( @as(?agent_stream_provider.NetworkFailureEvidence, null), networkFailureEvidence(err, .definitely_unsent), ); }}
const HttpResult = struct { status: std.http.Status, body: []u8,
pub fn deinit(self: *HttpResult, alloc: std.mem.Allocator) void { alloc.free(self.body); self.* = undefined; }};
pub const PostResult = HttpResult;pub const GetResult = HttpResult;
pub const GatewayJsonResult = union(enum) { /// Owned response body; the caller frees it with the request allocator. success: []u8, http_status: std.http.Status,
fn deinit(self: *@This(), alloc: std.mem.Allocator) void { switch (self.*) { .success => |body| alloc.free(body), .http_status => {}, } self.* = undefined; }};
pub const StreamCallback = agent_stream_provider.StreamCallback;pub const ToolStartCallback = agent_stream_provider.ToolStartCallback;
const gateway_retry_base_delay_ns: u64 = 150 * std.time.ns_per_ms;/// Max time the post-stream body drain may take before the pooled connection/// is abandoned instead of reused. The response is already complete at this/// point; only connection reuse is at stake.const pool_drain_budget_ms: i64 = 2_000;const gateway_connection_setup_timeout_ms: i64 = 30_000;const gateway_retry_after_max_ns: u64 = 5 * std.time.ns_per_s;const gateway_transfer_buffer_bytes: usize = 256 * 1024;const provider_failure_detail_max_bytes: usize = 600;const generation_response_max_bytes: usize = 128 * 1024;const generation_lookup_timeout_ms: i64 = 30_000;// Covers a 4 MiB string at worst-case JSON escaping plus SSE framing.const max_sse_event_line_bytes: usize = 32 * 1024 * 1024;const e2e_gateway_chat_url_env = "FX_E2E_GATEWAY_CHAT_URL";const e2e_gateway_models_url_env = "FX_E2E_GATEWAY_MODELS_URL";const e2e_gateway_credits_url_env = "FX_E2E_GATEWAY_CREDITS_URL";const default_gateway_base_url = "https://ai-gateway.vercel.sh";pub const vercel_ai_gateway_team_header = "x-vercel-ai-gateway-team";pub const vercel_gateway_extended_time_header = "x-vercel-gateway-extended-time";pub const vercel_gateway_extended_time_value = "true";/// Identifies fx on every AI Gateway request; the zig std.http default/// (`zig/<version> (std.http)`) is never sent to the gateway.pub const user_agent = "fx/" ++ build_options.app_version;var resolved_model_trace_emitted = std.atomic.Value(bool).init(false);var test_cancel_watcher_spawn_error: ?anyerror = null;
pub const StreamResult = struct { status: std.http.Status, completion: types.ModelCompletion = .{}, err_body: ?[]u8 = null, retry_after_seconds: ?u64 = null,
/// Frees all owned response buffers allocated for this stream result. pub fn deinit(self: *StreamResult, alloc: std.mem.Allocator) void { if (self.err_body) |body| alloc.free(body); deinitGatewayCompletion(alloc, &self.completion); const status = self.status; self.* = .{ .status = status }; }};
/// Possibly-sent model requests are retried by the agent so transport retries/// cannot multiply the logical response budget. Other gateway consumers keep/// their existing bounded transport retry behavior.pub const ProviderAttemptOwner = enum { transport, agent,};
pub fn fetchGatewayJson( alloc: std.mem.Allocator, api_key: ?[]const u8, gateway_team: ?[]const u8, url: []const u8,) !GatewayJsonResult { var result = try fetchGatewayGetAtUrl(alloc, api_key, gateway_team, url, e2e_gateway_models_url_env); if (failedGatewayJsonStatus(result.status)) |status| { result.deinit(alloc); return .{ .http_status = status }; }
return .{ .success = result.body };}
pub fn fetchGatewayGetResult(alloc: std.mem.Allocator, api_key: ?[]const u8, path: []const u8) !GetResult { return fetchGatewayGet(alloc, api_key, null, path, e2e_gateway_credits_url_env);}
pub fn fetchGatewayGenerationResult( alloc: std.mem.Allocator, api_key: ?[]const u8, gateway_team: ?[]const u8, gateway_origin: []const u8, generation_id: []const u8, cancel_flag: *std.atomic.Value(bool),) !GetResult { if (!types.validGatewayGenerationId(generation_id)) return error.InvalidGenerationId; var operation = GenerationLookupOperation{ .alloc = alloc, .api_key = api_key, .gateway_team = gateway_team, .gateway_origin = gateway_origin, .generation_id = generation_id, }; return runBoundedHttpOperation( GetResult, alloc, cancel_flag, std.Io.Clock.Timestamp.fromNow(io_mod.getIo(), .{ .clock = .awake, .raw = .fromMilliseconds(generation_lookup_timeout_ms), }), &operation, );}
const GenerationLookupOperation = struct { alloc: std.mem.Allocator, api_key: ?[]const u8, gateway_team: ?[]const u8, gateway_origin: []const u8, generation_id: []const u8,
fn run(self: *@This()) !GetResult { const path = try std.fmt.allocPrint( self.alloc, "/v1/generation?id={s}", .{self.generation_id}, ); defer self.alloc.free(path); const url = try std.fmt.allocPrint( self.alloc, "{s}{s}", .{ self.gateway_origin, path }, ); defer self.alloc.free(url); const uri = try std.Uri.parse(url);
var client: std.http.Client = .{ .allocator = self.alloc, .io = io_mod.getIo(), }; defer client.deinit(); var auth_header: ?[]u8 = null; defer if (auth_header) |value| secret.zeroAndFree(self.alloc, value); var headers: std.http.Client.Request.Headers = .{ .accept_encoding = .omit, .user_agent = .{ .override = user_agent }, }; if (self.api_key) |api_key| { auth_header = try std.fmt.allocPrint(self.alloc, "Bearer {s}", .{api_key}); headers.authorization = .{ .override = auth_header.? }; } var extra_headers_buf: [1]std.http.Header = undefined; const extra_headers = gatewayModelCatalogExtraHeaders( &extra_headers_buf, self.gateway_team, ); var req = try client.request(.GET, uri, .{ .headers = headers, .extra_headers = extra_headers, .redirect_behavior = .unhandled, }); defer req.deinit(); try req.sendBodiless(); if (req.connection) |conn| try conn.flush();
var response = try req.receiveHead(&.{}); var transfer_buffer: [16 * 1024]u8 = undefined; const reader = response.reader(&transfer_buffer); const body = reader.allocRemaining( self.alloc, .limited(generation_response_max_bytes), ) catch |err| switch (err) { error.StreamTooLong => return error.GatewayGenerationResponseTooLarge, else => return err, }; return .{ .status = response.head.status, .body = body }; }};
fn fetchGatewayGet(alloc: std.mem.Allocator, api_key: ?[]const u8, gateway_team: ?[]const u8, path: []const u8, e2e_url_env: []const u8) !GetResult { const default_url = try std.fmt.allocPrint(alloc, "{s}{s}", .{ gatewayBaseUrl(), path }); defer alloc.free(default_url);
return fetchGatewayGetAtUrl(alloc, api_key, gateway_team, default_url, e2e_url_env);}
fn fetchGatewayGetAtUrl(alloc: std.mem.Allocator, api_key: ?[]const u8, gateway_team: ?[]const u8, default_url: []const u8, e2e_url_env: []const u8) !GetResult { var client: std.http.Client = .{ .allocator = alloc, .io = io_mod.getIo() }; defer client.deinit();
const url = try resolveE2eGatewayUrl(e2e_url_env, default_url);
var auth_header: ?[]u8 = null; defer if (auth_header) |value| secret.zeroAndFree(alloc, value);
var headers: std.http.Client.Request.Headers = .{}; headers.user_agent = .{ .override = user_agent }; if (api_key) |key| { auth_header = try std.fmt.allocPrint(alloc, "Bearer {s}", .{key}); headers.authorization = .{ .override = auth_header.? }; } var extra_headers_buf: [1]std.http.Header = undefined; const extra_headers = gatewayModelCatalogExtraHeaders(&extra_headers_buf, gateway_team);
var out: std.Io.Writer.Allocating = .init(alloc); defer out.deinit();
const result = try client.fetch(.{ .location = .{ .url = url }, .method = .GET, .headers = headers, .extra_headers = extra_headers, .response_writer = &out.writer, .redirect_behavior = .unhandled, });
return .{ .status = result.status, .body = try out.toOwnedSlice(), };}
pub fn fetchGatewayJsonCancellable( alloc: std.mem.Allocator, api_key: ?[]const u8, gateway_team: ?[]const u8, url: []const u8, cancel_flag: *std.atomic.Value(bool),) !GatewayJsonResult { if (cancel_flag.load(.seq_cst)) return error.Cancelled;
const request_url = try resolveE2eGatewayUrl(e2e_gateway_models_url_env, url); return fetchGatewayJsonAtUrlCancellable(alloc, api_key, gateway_team, request_url, cancel_flag);}
fn fetchGatewayJsonAtUrlCancellable( alloc: std.mem.Allocator, api_key: ?[]const u8, gateway_team: ?[]const u8, url: []const u8, cancel_flag: *std.atomic.Value(bool),) !GatewayJsonResult { var operation = GatewayJsonFetchOperation{ .alloc = alloc, .api_key = api_key, .gateway_team = gateway_team, .url = url, .cancel_flag = cancel_flag, }; return runCancellableGatewayJsonFetch(alloc, cancel_flag, &operation);}
const GatewayJsonFetchOperation = struct { alloc: std.mem.Allocator, api_key: ?[]const u8, gateway_team: ?[]const u8, url: []const u8, cancel_flag: *std.atomic.Value(bool),
fn run(self: *@This()) !GatewayJsonResult { return fetchGatewayJsonAtUrlCore( self.alloc, self.api_key, self.gateway_team, self.url, self.cancel_flag, ); }};
fn runCancellableGatewayJsonFetch( alloc: std.mem.Allocator, cancel_flag: *std.atomic.Value(bool), operation: *GatewayJsonFetchOperation,) !GatewayJsonResult { if (cancel_flag.load(.seq_cst)) return error.Cancelled;
const Event = union(enum) { request: anyerror!GatewayJsonResult, cancelled: anyerror!void, }; const Runner = struct { fn run(value: *GatewayJsonFetchOperation) anyerror!GatewayJsonResult { return value.run(); } }; const Cleanup = struct { fn drain(result_alloc: std.mem.Allocator, select: *std.Io.Select(Event)) void { while (select.cancel()) |item| switch (item) { .request => |request_result| { var late_result = request_result catch continue; late_result.deinit(result_alloc); }, .cancelled => {}, }; } };
var select_buffer: [2]Event = undefined; var select: std.Io.Select(Event) = .init(io_mod.getIo(), &select_buffer); select.concurrent(.cancelled, waitForBoundedCancellation, .{cancel_flag}) catch |err| return err; select.concurrent(.request, Runner.run, .{operation}) catch |err| { select.cancelDiscard(); return err; };
const event = select.await() catch |err| { Cleanup.drain(alloc, &select); return err; }; switch (event) { .request => |request_result| { Cleanup.drain(alloc, &select); if (cancel_flag.load(.seq_cst)) { var result = request_result catch return error.Cancelled; result.deinit(alloc); return error.Cancelled; } return request_result; }, .cancelled => |cancel_result| { cancel_result catch |err| { Cleanup.drain(alloc, &select); return err; }; Cleanup.drain(alloc, &select); return error.Cancelled; }, }}
fn fetchGatewayJsonAtUrlCore( alloc: std.mem.Allocator, api_key: ?[]const u8, gateway_team: ?[]const u8, url: []const u8, cancel_flag: *std.atomic.Value(bool),) !GatewayJsonResult { if (cancel_flag.load(.seq_cst)) return error.Cancelled;
var client: std.http.Client = .{ .allocator = alloc, .io = io_mod.getIo() }; defer client.deinit();
const uri = try std.Uri.parse(url);
var auth_header: ?[]u8 = null; defer if (auth_header) |value| secret.zeroAndFree(alloc, value);
var headers: std.http.Client.Request.Headers = .{}; headers.accept_encoding = .omit; headers.user_agent = .{ .override = user_agent }; if (api_key) |key| { auth_header = try std.fmt.allocPrint(alloc, "Bearer {s}", .{key}); headers.authorization = .{ .override = auth_header.? }; } var extra_headers_buf: [1]std.http.Header = undefined; const extra_headers = gatewayModelCatalogExtraHeaders(&extra_headers_buf, gateway_team);
var req = client.request(.GET, uri, .{ .headers = headers, .extra_headers = extra_headers, .redirect_behavior = .unhandled, }) catch |err| { if (cancel_flag.load(.seq_cst)) return error.Cancelled; return err; }; defer req.deinit(); if (cancel_flag.load(.seq_cst)) return error.Cancelled;
var cancel_watch_done = std.atomic.Value(bool).init(false); const cancel_watcher = if (req.connection) |conn| try spawn_gateway_cancel_watcher(&cancel_watch_done, cancel_flag, null, null, null, conn.stream_writer.stream) else null; defer { cancel_watch_done.store(true, .seq_cst); if (cancel_watcher) |thread| thread.join(); } if (cancel_flag.load(.seq_cst)) return error.Cancelled;
req.sendBodiless() catch |err| { if (cancel_flag.load(.seq_cst)) return error.Cancelled; return err; }; if (cancel_flag.load(.seq_cst)) return error.Cancelled; if (req.connection) |conn| { conn.flush() catch |err| { if (cancel_flag.load(.seq_cst)) return error.Cancelled; return err; }; } if (cancel_flag.load(.seq_cst)) return error.Cancelled;
var response = req.receiveHead(&.{}) catch |err| { if (cancel_flag.load(.seq_cst)) return error.Cancelled; return err; }; if (cancel_flag.load(.seq_cst)) return error.Cancelled; if (failedGatewayJsonStatus(response.head.status)) |status| return .{ .http_status = status };
var out: std.Io.Writer.Allocating = .init(alloc); defer out.deinit(); var transfer_buffer: [64 * 1024]u8 = undefined; const reader = response.reader(&transfer_buffer); _ = reader.streamRemaining(&out.writer) catch |err| { if (cancel_flag.load(.seq_cst)) return error.Cancelled; return err; }; if (cancel_flag.load(.seq_cst)) return error.Cancelled; return .{ .success = try out.toOwnedSlice() };}
fn failedGatewayJsonStatus(status: std.http.Status) ?std.http.Status { return if (status == .ok) null else status;}
test "gateway JSON transport preserves non-success HTTP status" { try std.testing.expect(failedGatewayJsonStatus(.ok) == null); try std.testing.expectEqual(std.http.Status.unauthorized, failedGatewayJsonStatus(.unauthorized).?); try std.testing.expectEqual(std.http.Status.too_many_requests, failedGatewayJsonStatus(.too_many_requests).?); try std.testing.expectEqual(std.http.Status.service_unavailable, failedGatewayJsonStatus(.service_unavailable).?);}
fn gatewayBaseUrl() []const u8 { const override = io_mod.getenv("FX_GATEWAY_BASE_URL") orelse return default_gateway_base_url; // The base URL carries the bearer token; only a loopback HTTP override is // trusted for local testing. if (!isLoopbackHttpUrl(override)) { debug_trace.logf("stream", "ignoring FX_GATEWAY_BASE_URL: not loopback http", .{}); return default_gateway_base_url; } return override;}
pub fn generationBaseUrl() []const u8 { return std.mem.trimEnd(u8, gatewayBaseUrl(), "/");}
pub fn isTrustedGenerationOrigin(origin: []const u8) bool { return std.mem.eql(u8, origin, default_gateway_base_url) or isLoopbackHttpUrl(origin);}
pub fn postGatewayCompletion( alloc: std.mem.Allocator, api_key: []const u8, model: []const u8, retry_count: usize, chat_url: []const u8, payload: []const u8,) !PostResult { const request_url = try resolveE2eGatewayUrl(e2e_gateway_chat_url_env, chat_url); var attempt: usize = 0; while (attempt < retry_count) : (attempt += 1) { debug_trace.logf("stream", "open attempt={d}/{d} url={s} payload_bytes={d}", .{ attempt + 1, retry_count, request_url, payload.len }); var client: std.http.Client = .{ .allocator = alloc, .io = io_mod.getIo() }; defer client.deinit();
const auth_header = try std.fmt.allocPrint(alloc, "Bearer {s}", .{api_key}); defer secret.zeroAndFree(alloc, auth_header);
const extra_headers = [_]std.http.Header{ .{ .name = "HTTP-Referer", .value = "https://github.com/vercel-labs/fx" }, .{ .name = "X-Title", .value = "fx" }, .{ .name = "Accept", .value = "application/json" }, .{ .name = vercel_gateway_extended_time_header, .value = vercel_gateway_extended_time_value }, .{ .name = "ai-gateway-protocol-version", .value = "0.0.1" }, .{ .name = "ai-language-model-specification-version", .value = "4" }, .{ .name = "ai-language-model-id", .value = model }, .{ .name = "ai-language-model-streaming", .value = "false" }, };
var out: std.Io.Writer.Allocating = .init(alloc); defer out.deinit();
const result = client.fetch(.{ .location = .{ .url = request_url }, .method = .POST, .payload = payload, .headers = .{ .content_type = .{ .override = "application/json" }, .authorization = .{ .override = auth_header }, .accept_encoding = .omit, .user_agent = .{ .override = user_agent }, }, .extra_headers = &extra_headers, .response_writer = &out.writer, }) catch |err| { if (isRetryableGatewayError(err) and attempt + 1 < retry_count) { io_mod.sleep((attempt + 1) * 150 * std.time.ns_per_ms); continue; } return err; };
if (isRetryableGatewayStatus(result.status) and attempt + 1 < retry_count) { const delay_ns = retryBackoffDelayNs(attempt); debug_trace.logf("stream", "retrying status={d} attempt={d} delay_ms={d}", .{ @intFromEnum(result.status), attempt + 1, delay_ns / std.time.ns_per_ms }); io_mod.sleep(delay_ns); continue; }
return .{ .status = result.status, .body = try out.toOwnedSlice(), }; }
return error.HttpConnectionClosing;}
/// Monotonic request-delivery evidence. It becomes possibly sent before the/// first body write so any later transport failure is treated as potentially billed.pub const DeliveryCertainty = agent_stream_provider.DeliveryCertainty;
const ConnectionSetupOutcome = union(enum) { request_succeeded, request_failed: anyerror,};
const ConnectionSetupAction = union(enum) { succeed, retry, fail: anyerror, cancelled,};
const ConnectionSetupSnapshot = struct { attempt: usize, attempt_limit: usize, now: std.Io.Clock.Timestamp, deadline: std.Io.Clock.Timestamp, cancelled: bool, delivery: DeliveryCertainty.State, outcome: ConnectionSetupOutcome,};
const ConnectionSetupDecision = struct { action: ConnectionSetupAction,};
fn decideConnectionSetup(snapshot: ConnectionSetupSnapshot) ConnectionSetupDecision { if (snapshot.cancelled) return .{ .action = .cancelled }; if (!std.Io.Clock.Timestamp.compare(snapshot.now, .lt, snapshot.deadline)) { return .{ .action = .{ .fail = error.ConnectionSetupTimedOut } }; }
return switch (snapshot.outcome) { .request_succeeded => .{ .action = .succeed }, .request_failed => |err| if (isRetryableConnectionSetupError(err) and snapshot.delivery == .definitely_unsent and snapshot.attempt < snapshot.attempt_limit) .{ .action = .retry } else .{ .action = .{ .fail = err } }, };}
fn isRetryableConnectionSetupError(err: anyerror) bool { return err == error.TlsInitializationFailed or isRetryableGatewayError(err);}
/// std.http.Client does not mark a connection closing when the body write or/// flush fails, so deinit would release a poisoned connection (with possibly/// buffered unsent bytes) back to the pool. Mark it ourselves so a send/// failure can never hand a dirty connection to the next borrower.fn markPooledConnectionClosing(req: *std.http.Client.Request, request: StreamRequest) void { if (request.shared_pool == null) return; if (req.connection) |conn| conn.closing = true;}
const ConnectionSetupTiming = struct { timeout_ms: i64 = gateway_connection_setup_timeout_ms,};
const ResponseHeadTiming = struct { timeout_ms: i64 = 120_000, /// Patient head-wait (agent streaming path): a long-thinking model and a /// hung gateway are byte-identical on the wire, and the gateway sends no /// heartbeat. Never abort a sent request on head silence alone; only a dead /// socket, cancellation, or a system resume ends the wait. patient: bool = false, /// Mid-stream stall watchdog: once the head has arrived, a stream that /// produces no bytes for this long is treated as dead (positive evidence, /// unlike silence before the head). stall_timeout_ms: i64 = 60_000,};
test "connection setup keeps the production timeout" { const timing = ConnectionSetupTiming{};
try std.testing.expectEqual(@as(i64, 30_000), timing.timeout_ms);}
test "response head wait keeps the production timeout" { const timing = ResponseHeadTiming{};
try std.testing.expectEqual(@as(i64, 120_000), timing.timeout_ms); try std.testing.expect(!timing.patient);}
const ConnectionSetupEpoch = struct { deadline: std.Io.Clock.Timestamp,
fn init(timing: ConnectionSetupTiming) ConnectionSetupEpoch { const started = std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake); return .{ .deadline = .{ .clock = .awake, .raw = started.raw.addDuration(.fromMilliseconds(timing.timeout_ms)), }, }; }};
const RequestOpenOverride = struct { ctx: *anyopaque, run: *const fn ( ctx: *anyopaque, client: *std.http.Client, method: std.http.Method, uri: std.Uri, options: std.http.Client.RequestOptions, ) anyerror!std.http.Client.Request,};
const StreamCoreOptions = struct { setup_timing: ConnectionSetupTiming = .{}, response_head_timing: ResponseHeadTiming = .{}, request_open_override: ?RequestOpenOverride = null,};
const ConnectedRequestWatch = struct { const Phase = enum(u8) { sending, awaiting_head, streaming, completed, timed_out, cancelled, system_resumed, stalled, };
phase: std.atomic.Value(Phase) = .init(.sending), response_head_deadline: std.Io.Clock.Timestamp = undefined, /// Last byte progress in the streaming phase (awake clock, ms). Written by /// the consume loop, read by the watcher thread. wasm32-safe via the /// project's portable atomic wrapper (wide atomics do not exist there); /// millisecond precision is ample for second-scale stall thresholds. last_progress_ms: atomic_value.Value(i64) = .init(0), timing: ResponseHeadTiming,
fn init(timing: ResponseHeadTiming) ConnectedRequestWatch { return .{ .timing = timing }; }
fn arm_response_head(self: *ConnectedRequestWatch) ?anyerror { self.response_head_deadline = std.Io.Clock.Timestamp.fromNow( io_mod.getIo(), .{ .clock = .awake, .raw = .fromMilliseconds(self.timing.timeout_ms), }, ); if (self.phase.cmpxchgStrong( .sending, .awaiting_head, .seq_cst, .seq_cst, )) |winner| return phase_error(winner); return null; }
fn commit_response_head(self: *ConnectedRequestWatch) ?anyerror { if (self.phase.cmpxchgStrong( .awaiting_head, .streaming, .seq_cst, .seq_cst, )) |winner| return phase_error(winner); self.markStreamProgress(); return null; }
fn finish(self: *ConnectedRequestWatch) ?anyerror { var current = self.phase.load(.seq_cst); while (is_active(current)) { if (self.phase.cmpxchgWeak( current, .completed, .seq_cst, .seq_cst, )) |observed| { current = observed; continue; } return null; } return phase_error(current); }
fn finish_error( self: *ConnectedRequestWatch, transport_error: anyerror, ) anyerror { return self.finish() orelse transport_error; }
fn win(self: *ConnectedRequestWatch, winner: Phase) bool { std.debug.assert(!is_active(winner)); std.debug.assert(winner != .completed); var current = self.phase.load(.seq_cst); while (is_active(current)) { if (self.phase.cmpxchgWeak( current, winner, .seq_cst, .seq_cst, )) |observed| { current = observed; continue; } return true; } return false; }
fn win_response_head_timeout(self: *ConnectedRequestWatch) bool { return self.phase.cmpxchgStrong( .awaiting_head, .timed_out, .seq_cst, .seq_cst, ) == null; }
fn markStreamProgress(self: *ConnectedRequestWatch) void { // Both writer and reader use the monotonic awake clock; mixing in the // wall clock would make the elapsed subtraction permanently negative. const now_ns = std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake).raw.toNanoseconds(); self.last_progress_ms.store(@intCast(@divFloor(now_ns, std.time.ns_per_ms)), .seq_cst); }
/// Positive-evidence stall: the head arrived, then the stream went silent /// past the stall threshold. Wins `.stalled` so the caller can distinguish /// it from a pre-head timeout (which stays patient). fn stream_stall_expired( self: *const ConnectedRequestWatch, now: std.Io.Clock.Timestamp, ) bool { if (self.phase.load(.seq_cst) != .streaming) return false; const last = self.last_progress_ms.load(.seq_cst); if (last == 0) return false; const now_ms: i64 = @intCast(@divFloor(now.raw.toNanoseconds(), std.time.ns_per_ms)); const elapsed = now_ms - last; return elapsed >= self.timing.stall_timeout_ms; }
fn win_stall_timeout(self: *ConnectedRequestWatch) bool { return self.phase.cmpxchgStrong( .streaming, .stalled, .seq_cst, .seq_cst, ) == null; }
fn response_head_expired( self: *ConnectedRequestWatch, now: std.Io.Clock.Timestamp, ) bool { if (self.timing.patient) { // Patient head-wait never aborts. The wait ends only with data, // a dead socket, cancel, or system resume. if (self.phase.load(.seq_cst) != .awaiting_head) return false; if (std.Io.Clock.Timestamp.compare(now, .lt, self.response_head_deadline)) return false; return false; } if (self.phase.load(.seq_cst) != .awaiting_head) return false; return !std.Io.Clock.Timestamp.compare( now, .lt, self.response_head_deadline, ); }
fn is_active(phase: Phase) bool { return switch (phase) { .sending, .awaiting_head, .streaming => true, .completed, .timed_out, .cancelled, .system_resumed, .stalled => false, }; }
fn phase_error(phase: Phase) ?anyerror { return switch (phase) { .timed_out => error.Timeout, .cancelled => error.Cancelled, .system_resumed => error.SystemResumed, .stalled => error.StreamStalled, .sending, .awaiting_head, .streaming, .completed => null, }; }};
const RequestOpenOperation = struct { client: *std.http.Client, uri: std.Uri, options: std.http.Client.RequestOptions, request_open_override: ?RequestOpenOverride,
fn run(self: *@This()) anyerror!std.http.Client.Request { if (self.request_open_override) |request_open| { return request_open.run( request_open.ctx, self.client, .POST, self.uri, self.options, ); } return self.client.request(.POST, self.uri, self.options); }};
fn openGatewayRequestBounded( client: *std.http.Client, uri: std.Uri, options: std.http.Client.RequestOptions, request_open_override: ?RequestOpenOverride, epoch: *ConnectionSetupEpoch, cancel_flag: *std.atomic.Value(bool),) anyerror!std.http.Client.Request { if (cancel_flag.load(.seq_cst)) return error.Cancelled;
const now = std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake); if (!std.Io.Clock.Timestamp.compare(now, .lt, epoch.deadline)) { return error.ConnectionSetupTimedOut; }
const Event = union(enum) { request: anyerror!std.http.Client.Request, cancelled: anyerror!void, deadline: anyerror!void, }; const Cleanup = struct { fn drain(select: *std.Io.Select(Event)) void { while (select.cancel()) |item| switch (item) { .request => |request_result| { var late_request = request_result catch continue; late_request.deinit(); }, .cancelled, .deadline => {}, }; } };
var operation = RequestOpenOperation{ .client = client, .uri = uri, .options = options, .request_open_override = request_open_override, }; var select_buffer: [3]Event = undefined; var select: std.Io.Select(Event) = .init(io_mod.getIo(), &select_buffer); select.concurrent(.cancelled, waitForBoundedCancellation, .{cancel_flag}) catch |err| return err; select.concurrent(.deadline, waitForBoundedDeadline, .{epoch.deadline}) catch |err| { select.cancelDiscard(); return err; }; select.concurrent(.request, RequestOpenOperation.run, .{&operation}) catch |err| { select.cancelDiscard(); return err; };
while (true) { const event = select.await() catch |err| { Cleanup.drain(&select); return err; }; switch (event) { .request => |request_result| { Cleanup.drain(&select); if (cancel_flag.load(.seq_cst)) { var cancelled_request = request_result catch return error.Cancelled; cancelled_request.deinit(); return error.Cancelled; }
var owned_request = request_result catch |request_err| return request_err; const result_now = std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake); if (!std.Io.Clock.Timestamp.compare(result_now, .lt, epoch.deadline)) { owned_request.deinit(); return error.ConnectionSetupTimedOut; } return owned_request; }, .cancelled => |cancelled_result| { cancelled_result catch |err| { Cleanup.drain(&select); return err; }; Cleanup.drain(&select); return error.Cancelled; }, .deadline => |deadline_result| { deadline_result catch |err| { Cleanup.drain(&select); return err; }; Cleanup.drain(&select); if (cancel_flag.load(.seq_cst)) return error.Cancelled; return error.ConnectionSetupTimedOut; }, } }}
fn sleepGatewaySetupRetry( delay_ns: u64, epoch: *ConnectionSetupEpoch, cancel_flag: *std.atomic.Value(bool),) anyerror!void { const retry_deadline = std.Io.Clock.Timestamp.fromNow(io_mod.getIo(), .{ .clock = .awake, .raw = .fromNanoseconds(@intCast(delay_ns)), });
while (true) { if (cancel_flag.load(.seq_cst)) return error.Cancelled;
const now = std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake); if (!std.Io.Clock.Timestamp.compare(now, .lt, epoch.deadline)) { return error.ConnectionSetupTimedOut; } if (!std.Io.Clock.Timestamp.compare(now, .lt, retry_deadline)) return;
var sleep_ns: i96 = 10 * std.time.ns_per_ms; sleep_ns = @min(sleep_ns, now.raw.durationTo(retry_deadline.raw).toNanoseconds()); sleep_ns = @min(sleep_ns, now.raw.durationTo(epoch.deadline.raw).toNanoseconds()); if (sleep_ns <= 0) continue; try io_mod.getIo().sleep(.fromNanoseconds(sleep_ns), .awake); }}
fn testAwakeTimestamp(milliseconds: i64) std.Io.Clock.Timestamp { return .{ .clock = .awake, .raw = .fromNanoseconds(@as(i96, milliseconds) * std.time.ns_per_ms), };}
fn expectConnectionSetupActionTag( expected: std.meta.Tag(ConnectionSetupAction), action: ConnectionSetupAction,) !void { try std.testing.expectEqual(expected, std.meta.activeTag(action));}
test "connection setup policy makes cancellation absorbing" { const outcomes = [_]ConnectionSetupOutcome{ .request_succeeded, .{ .request_failed = error.TlsInitializationFailed }, }; for (outcomes) |outcome| { const decision = decideConnectionSetup(.{ .attempt = 1, .attempt_limit = 3, .now = testAwakeTimestamp(10), .deadline = testAwakeTimestamp(30_000), .cancelled = true, .delivery = .definitely_unsent, .outcome = outcome, }); try expectConnectionSetupActionTag(.cancelled, decision.action); }}
test "connection setup policy bounds retry by deadline attempts and delivery" { const retry = decideConnectionSetup(.{ .attempt = 1, .attempt_limit = 3, .now = testAwakeTimestamp(10), .deadline = testAwakeTimestamp(30_000), .cancelled = false, .delivery = .definitely_unsent, .outcome = .{ .request_failed = error.TlsInitializationFailed }, }); try expectConnectionSetupActionTag(.retry, retry.action);
const exhausted = decideConnectionSetup(.{ .attempt = 3, .attempt_limit = 3, .now = testAwakeTimestamp(10), .deadline = testAwakeTimestamp(30_000), .cancelled = false, .delivery = .definitely_unsent, .outcome = .{ .request_failed = error.TlsInitializationFailed }, }); try expectConnectionSetupActionTag(.fail, exhausted.action);
const possibly_sent = decideConnectionSetup(.{ .attempt = 1, .attempt_limit = 3, .now = testAwakeTimestamp(10), .deadline = testAwakeTimestamp(30_000), .cancelled = false, .delivery = .possibly_sent, .outcome = .{ .request_failed = error.TlsInitializationFailed }, }); try expectConnectionSetupActionTag(.fail, possibly_sent.action);
const timed_out = decideConnectionSetup(.{ .attempt = 1, .attempt_limit = 3, .now = testAwakeTimestamp(30_000), .deadline = testAwakeTimestamp(30_000), .cancelled = false, .delivery = .definitely_unsent, .outcome = .{ .request_failed = error.TlsInitializationFailed }, }); try expectConnectionSetupActionTag(.fail, timed_out.action); switch (timed_out.action) { .fail => |err| try std.testing.expectEqual(error.ConnectionSetupTimedOut, err), else => return error.TestExpectedConnectionTimeout, }}
pub const StreamRequest = struct { api_key: ?[]const u8, model: []const u8, retry_count: usize, chat_url: []const u8, payload: []const u8, team: ?[]const u8 = null, /// Borrowed until `streamGatewayCompletion` returns. session_id: ?[]const u8 = null, trace_ctx: debug_trace.TraceContext = .{}, content_capture_limit: ?usize = null, delivery: ?*DeliveryCertainty = null, admission: ?agent_stream_provider.Admission = null, on_reasoning_chunk: ?StreamCallback = null, on_tool_input_chunk: ?StreamCallback = null, provider_attempt_owner: ProviderAttemptOwner = .transport, /// Long-lived pooled HTTP client owned by the provider runtime. When set, /// requests reuse pooled keep-alive connections instead of dialing per /// attempt. Borrowed; must outlive every in-flight stream. shared_pool: ?*http_pool.HttpPool = null,};
pub fn streamGatewayCompletion( alloc: std.mem.Allocator, request: StreamRequest, callback_ctx: *anyopaque, on_content_chunk: StreamCallback, on_tool_start: ?ToolStartCallback, cancel_flag: *std.atomic.Value(bool),) !StreamResult { if (cancel_flag.load(.seq_cst)) return error.Cancelled; const expected_provider_tool_name = try expectedProviderToolName(alloc, request.payload); return streamGatewayCompletionCore( alloc, request, callback_ctx, on_content_chunk, on_tool_start, cancel_flag, expected_provider_tool_name, true, );}
pub fn streamGatewayCompletionBounded( alloc: std.mem.Allocator, request: StreamRequest, callback_ctx: *anyopaque, on_content_chunk: StreamCallback, on_tool_start: ?ToolStartCallback, deadline: std.Io.Clock.Timestamp, cancel_flag: *std.atomic.Value(bool),) !StreamResult { if (cancel_flag.load(.seq_cst)) return error.Cancelled; const expected_provider_tool_name = try expectedProviderToolName(alloc, request.payload); var operation = BoundedStreamingGatewayOperation{ .alloc = alloc, .request = request, .callback_ctx = callback_ctx, .on_content_chunk = on_content_chunk, .on_tool_start = on_tool_start, .expected_provider_tool_name = expected_provider_tool_name, .cancel_flag = cancel_flag, }; return runBoundedStreamOperation(alloc, cancel_flag, deadline, &operation);}
fn expectedProviderToolName(alloc: std.mem.Allocator, payload: []const u8) !?[]const u8 { var parsed = try std.json.parseFromSlice(std.json.Value, alloc, payload, .{}); defer parsed.deinit(); if (parsed.value != .object) return null; const tools = parsed.value.object.get("tools") orelse return null; if (tools != .array) return null;
for (tools.array.items) |tool| { if (tool != .object) continue; const tool_type = tool.object.get("type") orelse continue; const id = tool.object.get("id") orelse continue; const name = tool.object.get("name") orelse continue; if (tool_type != .string or id != .string or name != .string) continue; if (std.mem.eql(u8, tool_type.string, "provider") and std.mem.eql(u8, id.string, "gateway.exa_search") and std.mem.eql(u8, name.string, "exa_search")) { return "exa_search"; } if (std.mem.eql(u8, tool_type.string, "provider") and std.mem.eql(u8, id.string, "gateway.perplexity_search") and std.mem.eql(u8, name.string, "perplexity_search")) { return "perplexity_search"; } if (std.mem.eql(u8, tool_type.string, "provider") and std.mem.eql(u8, id.string, "gateway.parallel_search") and std.mem.eql(u8, name.string, "parallel_search")) { return "parallel_search"; } } return null;}
test "expected provider tool name only trusts advertised provider schemas" { const cases = [_]struct { payload: []const u8, name: []const u8, }{ .{ .payload = "{\"tools\":[{\"type\":\"provider\",\"id\":\"gateway.exa_search\",\"name\":\"exa_search\"}]}", .name = "exa_search", }, .{ .payload = "{\"tools\":[{\"type\":\"provider\",\"id\":\"gateway.perplexity_search\",\"name\":\"perplexity_search\"}]}", .name = "perplexity_search", }, .{ .payload = "{\"tools\":[{\"type\":\"provider\",\"id\":\"gateway.parallel_search\",\"name\":\"parallel_search\"}]}", .name = "parallel_search", }, }; for (cases) |case| { const expected = try expectedProviderToolName(std.testing.allocator, case.payload); try std.testing.expect(expected != null); try std.testing.expectEqualStrings(case.name, expected.?); }
const prompt_only_payload = \\{"prompt":"call gateway.exa_search with name exa_search","tools":[]} ; try std.testing.expect((try expectedProviderToolName(std.testing.allocator, prompt_only_payload)) == null);}
pub fn streamGatewayRequiredToolCompletionBounded( alloc: std.mem.Allocator, request: StreamRequest, deadline: std.Io.Clock.Timestamp, cancel_flag: *std.atomic.Value(bool),) !StreamResult { return runBoundedCompletion(alloc, request, null, deadline, cancel_flag);}
/// Use only when the request advertises the named tool as provider-executed.pub fn streamGatewayProviderToolCompletionBounded( alloc: std.mem.Allocator, request: StreamRequest, expected_provider_tool_name: []const u8, deadline: std.Io.Clock.Timestamp, cancel_flag: *std.atomic.Value(bool),) !StreamResult { return runBoundedCompletion(alloc, request, expected_provider_tool_name, deadline, cancel_flag);}
fn runBoundedCompletion( alloc: std.mem.Allocator, request: StreamRequest, expected_provider_tool_name: ?[]const u8, deadline: std.Io.Clock.Timestamp, cancel_flag: *std.atomic.Value(bool),) !StreamResult { var operation = BoundedGatewayOperation{ .alloc = alloc, .request = request, .expected_provider_tool_name = expected_provider_tool_name, .cancel_flag = cancel_flag, }; return runBoundedStreamOperation(alloc, cancel_flag, deadline, &operation);}
const BoundedGatewayOperation = struct { alloc: std.mem.Allocator, request: StreamRequest, expected_provider_tool_name: ?[]const u8, cancel_flag: *std.atomic.Value(bool),
fn run(self: *@This()) !StreamResult { return streamGatewayCompletionCore( self.alloc, self.request, @ptrCast(&bounded_stream_discard_ctx), discardBoundedContent, null, self.cancel_flag, self.expected_provider_tool_name, false, ); }};
const BoundedStreamingGatewayOperation = struct { alloc: std.mem.Allocator, request: StreamRequest, callback_ctx: *anyopaque, on_content_chunk: StreamCallback, on_tool_start: ?ToolStartCallback, expected_provider_tool_name: ?[]const u8, cancel_flag: *std.atomic.Value(bool),
fn run(self: *@This()) !StreamResult { return streamGatewayCompletionCore( self.alloc, self.request, self.callback_ctx, self.on_content_chunk, self.on_tool_start, self.cancel_flag, self.expected_provider_tool_name, true, ); }};
var bounded_stream_discard_ctx: u8 = 0;
fn discardBoundedContent(_: *anyopaque, _: []const u8) void {}
fn streamGatewayCompletionCore( alloc: std.mem.Allocator, request: StreamRequest, callback_ctx: *anyopaque, on_content_chunk: StreamCallback, on_tool_start: ?ToolStartCallback, cancel_flag: *std.atomic.Value(bool), expected_provider_tool_name: ?[]const u8, watch_connected_socket: bool,) !StreamResult { return streamGatewayCompletionCoreWithOptions( alloc, request, callback_ctx, on_content_chunk, on_tool_start, cancel_flag, expected_provider_tool_name, watch_connected_socket, .{ .response_head_timing = .{ // The agent path waits patiently for long-thinking models: head // silence alone never aborts a sent request. Mid-stream stalls // still get positive-evidence detection via the stall watchdog. .patient = true, .stall_timeout_ms = agent_stream_stall_timeout_ms, }, }, );}
/// Mid-stream stall patience on the agent streaming path. The gateway sends no/// heartbeat while a model thinks, so silence is ambiguous for every model,/// not just known long-thinking classes: any model can go quiet for minutes on/// a hard prompt. Treat all models with the same ten-minute window instead of/// classifying by name.const agent_stream_stall_timeout_ms: i64 = 600_000;
test "agent stream stall window gives every model ten minutes of silence" { try std.testing.expectEqual(@as(i64, 600_000), agent_stream_stall_timeout_ms);}
fn streamGatewayCompletionCoreWithOptions( alloc: std.mem.Allocator, request: StreamRequest, callback_ctx: *anyopaque, on_content_chunk: StreamCallback, on_tool_start: ?ToolStartCallback, cancel_flag: *std.atomic.Value(bool), expected_provider_tool_name: ?[]const u8, watch_connected_socket: bool, core_options: StreamCoreOptions,) !StreamResult { const model = request.model; const payload = request.payload; const retry_count = switch (request.provider_attempt_owner) { .agent => 1, .transport => request.retry_count, }; const trace_ctx = request.trace_ctx; const request_url = try resolveE2eGatewayUrl(e2e_gateway_chat_url_env, request.chat_url); const uri = try std.Uri.parse(request_url);
var auth_header: ?[]u8 = null; defer if (auth_header) |value| secret.zeroAndFree(alloc, value); var request_headers: std.http.Client.Request.Headers = .{ .content_type = .{ .override = "application/json" }, .accept_encoding = .omit, .user_agent = .{ .override = user_agent }, }; if (request.api_key) |api_key| { auth_header = try std.fmt.allocPrint(alloc, "Bearer {s}", .{api_key}); request_headers.authorization = .{ .override = auth_header.? }; }
var extra_headers_buf: [10]std.http.Header = undefined; const extra_headers = gatewayExtraHeaders( &extra_headers_buf, model, request.team, request.session_id, );
if (request.admission) |admission| try admission.admit(); var attempt: usize = 0; var delivery_ambiguous = false; var request_body_possibly_sent = false; var setup_epoch: ?ConnectionSetupEpoch = null; while (attempt < retry_count) : (attempt += 1) { if (cancel_flag.load(.seq_cst)) return error.Cancelled; var local_client: std.http.Client = undefined; const client: *std.http.Client = if (request.shared_pool) |pool| pool.clientFor(request_url) else blk: { local_client = .{ .allocator = alloc, .io = io_mod.getIo() }; break :blk &local_client; }; defer if (request.shared_pool == null) local_client.deinit(); if (request.shared_pool) |pool| { debug_trace.eventf("gateway", "pool_borrow", trace_ctx, "attempt={d} free_connections={d}", .{ attempt + 1, pool.freeConnectionCount() }); }
if (setup_epoch == null) { setup_epoch = ConnectionSetupEpoch.init(core_options.setup_timing); } const epoch = &setup_epoch.?; const setup_delivery: DeliveryCertainty.State = if (request_body_possibly_sent) .possibly_sent else if (request.delivery) |delivery| delivery.load() else .definitely_unsent;
debug_trace.eventf("gateway", "before_http_open_connect", trace_ctx, "attempt={d} attempt_limit={d} retries_used={d}", .{ attempt + 1, retry_count, attempt }); debug_trace.eventf("gateway", "before_request_open", trace_ctx, "attempt={d} attempt_limit={d} retries_used={d} payload_bytes={d}", .{ attempt + 1, retry_count, attempt, payload.len }); var req = openGatewayRequestBounded(client, uri, .{ .headers = request_headers, .extra_headers = extra_headers, .keep_alive = request.shared_pool != null, .redirect_behavior = .unhandled, }, core_options.request_open_override, epoch, cancel_flag) catch |err| { debug_trace.eventf("gateway", "http_open_connect_error", trace_ctx, "attempt={d} err={s}", .{ attempt + 1, @errorName(err) }); const decision = decideConnectionSetup(.{ .attempt = attempt + 1, .attempt_limit = retry_count, .now = std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake), .deadline = epoch.deadline, .cancelled = cancel_flag.load(.seq_cst), .delivery = setup_delivery, .outcome = .{ .request_failed = err }, }); switch (decision.action) { .retry => { sleepGatewaySetupRetry( (attempt + 1) * gateway_retry_base_delay_ns, epoch, cancel_flag, ) catch |sleep_err| return @as(anyerror!StreamResult, sleep_err); continue; }, .fail => |terminal_err| return @as(anyerror!StreamResult, terminal_err), .cancelled => return error.Cancelled, .succeed => unreachable, } }; const setup_success = decideConnectionSetup(.{ .attempt = attempt + 1, .attempt_limit = retry_count, .now = std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake), .deadline = epoch.deadline, .cancelled = cancel_flag.load(.seq_cst), .delivery = setup_delivery, .outcome = .request_succeeded, }); switch (setup_success.action) { .succeed => {}, .fail => |terminal_err| { req.deinit(); return @as(anyerror!StreamResult, terminal_err); }, .cancelled => { req.deinit(); return error.Cancelled; }, .retry => unreachable, } setup_epoch = null; defer req.deinit(); debug_trace.eventf("gateway", "after_http_open_connect", trace_ctx, "attempt={d}", .{attempt + 1}); debug_trace.eventf("gateway", "after_request_open", trace_ctx, "attempt={d}", .{attempt + 1});
var cancel_watch_done = std.atomic.Value(bool).init(false); var system_resumed = std.atomic.Value(bool).init(false); var connected_watch = ConnectedRequestWatch.init(core_options.response_head_timing); const cancel_watcher = if (watch_connected_socket) if (req.connection) |conn| spawn_gateway_cancel_watcher(&cancel_watch_done, cancel_flag, &system_resumed, null, &connected_watch, conn.stream_writer.stream) catch |err| { debug_trace.eventf("gateway", "cancel_watcher_spawn_error", trace_ctx, "attempt={d} err={s}", .{ attempt + 1, @errorName(err) }); return @as(anyerror!StreamResult, err); } else null else null; const active_connected_watch: ?*ConnectedRequestWatch = if (cancel_watcher != null) &connected_watch else null; defer { cancel_watch_done.store(true, .seq_cst); if (cancel_watcher) |thread| thread.join(); } if (cancel_flag.load(.seq_cst)) return error.Cancelled;
req.transfer_encoding = .{ .content_length = payload.len }; var send_buf: [8192]u8 = undefined; debug_trace.eventf("gateway", "before_request_send", trace_ctx, "attempt={d} payload_bytes={d}", .{ attempt + 1, payload.len }); request_body_possibly_sent = true; if (request.delivery) |delivery| delivery.markPossiblySent(); var body_writer = req.sendBodyUnflushed(&send_buf) catch |err| { debug_trace.eventf("gateway", "request_send_error", trace_ctx, "attempt={d} err={s}", .{ attempt + 1, @errorName(err) }); markPooledConnectionClosing(&req, request); return @as(anyerror!StreamResult, connectedIoFailureWithWatch( active_connected_watch, cancel_flag.load(.seq_cst), system_resumed.load(.seq_cst), err, )); }; body_writer.writer.writeAll(payload) catch |err| { debug_trace.eventf("gateway", "request_send_error", trace_ctx, "attempt={d} err={s}", .{ attempt + 1, @errorName(err) }); markPooledConnectionClosing(&req, request); return @as(anyerror!StreamResult, connectedIoFailureWithWatch( active_connected_watch, cancel_flag.load(.seq_cst), system_resumed.load(.seq_cst), err, )); }; body_writer.end() catch |err| { debug_trace.eventf("gateway", "request_send_error", trace_ctx, "attempt={d} err={s}", .{ attempt + 1, @errorName(err) }); markPooledConnectionClosing(&req, request); return @as(anyerror!StreamResult, connectedIoFailureWithWatch( active_connected_watch, cancel_flag.load(.seq_cst), system_resumed.load(.seq_cst), err, )); }; req.connection.?.flush() catch |err| { debug_trace.eventf("gateway", "request_send_error", trace_ctx, "attempt={d} err={s}", .{ attempt + 1, @errorName(err) }); markPooledConnectionClosing(&req, request); return @as(anyerror!StreamResult, connectedIoFailureWithWatch( active_connected_watch, cancel_flag.load(.seq_cst), system_resumed.load(.seq_cst), err, )); }; debug_trace.eventf("gateway", "after_request_send", trace_ctx, "attempt={d} payload_bytes={d}", .{ attempt + 1, payload.len }); debug_trace.eventf("gateway", "after_send", trace_ctx, "attempt={d} payload_bytes={d}", .{ attempt + 1, payload.len });
if (active_connected_watch) |watch| { if (watch.arm_response_head()) |err| { markPooledConnectionClosing(&req, request); return @as(anyerror!StreamResult, err); } } debug_trace.eventf("gateway", "before_receive_head", trace_ctx, "attempt={d}", .{attempt + 1}); var response = req.receiveHead(&.{}) catch |err| { debug_trace.eventf("gateway", "receive_head_error", trace_ctx, "attempt={d} err={s}", .{ attempt + 1, @errorName(err) }); const mapped = connectedIoFailureWithWatch( active_connected_watch, cancel_flag.load(.seq_cst), system_resumed.load(.seq_cst), err, ); if (mapped == error.Cancelled or mapped == error.SystemResumed) { return @as(anyerror!StreamResult, mapped); } if (request.provider_attempt_owner == .transport and isRetryableGatewayError(mapped) and attempt + 1 < retry_count) { delivery_ambiguous = true; try sleepGatewayRetry((attempt + 1) * 150 * std.time.ns_per_ms, cancel_flag); continue; } return @as(anyerror!StreamResult, mapped); }; if (active_connected_watch) |watch| { if (watch.commit_response_head()) |err| return @as(anyerror!StreamResult, err); } debug_trace.eventf("gateway", "after_receive_head", trace_ctx, "attempt={d} status={d}", .{ attempt + 1, @intFromEnum(response.head.status) }); const resolved_model_seen_in_head = traceResolvedModelHeader(response.head, model, trace_ctx);
if (response.head.status != .ok) { const status = response.head.status; if (@intFromEnum(status) >= 500) delivery_ambiguous = true; const retry_after_seconds = retryAfterSeconds(response.head); const retry_delay_ns = if (request.provider_attempt_owner == .transport and isRetryableGatewayStatus(status) and attempt + 1 < retry_count) retryDelayNsForResponse(response.head, attempt) else null; debug_trace.logf("stream", "http status={d} attempt={d}", .{ @intFromEnum(status), attempt + 1 }); var err_out: std.Io.Writer.Allocating = .init(alloc); defer err_out.deinit(); var err_buf: [4096]u8 = undefined; const err_reader = response.reader(&err_buf); _ = err_reader.streamRemaining(&err_out.writer) catch {}; if (cancel_flag.load(.seq_cst)) return error.Cancelled; if (retry_delay_ns) |delay_ns| { debug_trace.eventf("gateway", "http_status_retry", trace_ctx, "attempt={d} status={d} delay_ms={d}", .{ attempt + 1, @intFromEnum(status), delay_ns / std.time.ns_per_ms, }); try sleepGatewayRetry(delay_ns, cancel_flag); continue; } return .{ .status = status, .err_body = err_out.toOwnedSlice() catch null, .retry_after_seconds = retry_after_seconds, .completion = .{ .delivery_ambiguous = delivery_ambiguous, }, }; }
var transfer_buf: [gateway_transfer_buffer_bytes]u8 = undefined; const body_reader = response.reader(&transfer_buf); debug_trace.eventf("gateway", "before_sse_consume", trace_ctx, "attempt={d}", .{attempt + 1}); var completion = consumeSseStreamTraced( alloc, body_reader, callback_ctx, on_content_chunk, on_tool_start, request.on_reasoning_chunk, request.on_tool_input_chunk, cancel_flag, .{ .requested_model = model, .ctx = trace_ctx }, expected_provider_tool_name, request.content_capture_limit, active_connected_watch, ) catch |err| { debug_trace.eventf("gateway", "sse_consume_error", trace_ctx, "attempt={d} err={s}", .{ attempt + 1, @errorName(err) }); return @as(anyerror!StreamResult, connectedIoFailureWithWatch( active_connected_watch, cancel_flag.load(.seq_cst), system_resumed.load(.seq_cst), err, )); }; if (request.shared_pool != null) { // SSE consumption stops at the terminal event, which can leave // the HTTP body unread; std's Request.deinit marks body-ful // requests closing unless the body drains to the end. Drain so a // cleanly finished stream returns its connection to the pool. // The drain is bounded: a server that never terminates the body // must not hang an already-completed request. The watcher's // deadline shuts the socket, turning the hang into a drain error; // only reuse is lost, never the response. const drain_started = io_mod.milliTimestamp(); var drain_watch_done = std.atomic.Value(bool).init(false); const drain_deadline = std.Io.Clock.Timestamp{ .clock = .awake, .raw = std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake).raw.addDuration(.fromMilliseconds(pool_drain_budget_ms)), }; const drain_thread = if (req.connection) |conn| spawn_gateway_cancel_watcher(&drain_watch_done, cancel_flag, null, drain_deadline, null, conn.stream_writer.stream) catch null else null; const drain_ok = if (body_reader.discardRemaining()) |drained_bytes| blk: { debug_trace.eventf("gateway", "pool_body_drain", trace_ctx, "attempt={d} result=ok bytes={d} elapsed_ms={d}", .{ attempt + 1, drained_bytes, io_mod.milliTimestamp() - drain_started }); break :blk true; } else |err| blk: { debug_trace.eventf("gateway", "pool_body_drain", trace_ctx, "attempt={d} result=error err={s}", .{ attempt + 1, @errorName(err) }); break :blk false; }; drain_watch_done.store(true, .seq_cst); if (drain_thread) |thread| thread.join(); // The connection returns to the pool NOW, at stream end — the // TTL invariant requires last_activity to track the freshest // return, so stamp only on a clean return. if (drain_ok) request.shared_pool.?.noteActivity(); } if (active_connected_watch) |watch| { if (watch.finish()) |err| { deinitGatewayCompletion(alloc, &completion); return @as(anyerror!StreamResult, err); } } if (cancel_flag.load(.seq_cst)) { deinitGatewayCompletion(alloc, &completion); return error.Cancelled; } if (system_resumed.load(.seq_cst)) { deinitGatewayCompletion(alloc, &completion); return error.SystemResumed; } completion.delivery_ambiguous = delivery_ambiguous; if (!resolved_model_seen_in_head) traceResolvedModelMissingOnce(model, trace_ctx); debug_trace.eventf("gateway", "after_sse_consume", trace_ctx, "attempt={d} finish_reason={s} content_bytes={d} tool_call_count={d}", .{ attempt + 1, finish_reason_label(completion.finish_reason), if (completion.content) |content| content.len else 0, completion.tool_calls.len, }); debug_trace.logf( "stream", "completed attempt={d} finish_reason={s} content_bytes={d} tool_calls={d}", .{ attempt + 1, finish_reason_label(completion.finish_reason), if (completion.content) |content| content.len else 0, completion.tool_calls.len, }, ); debug_trace.eventf( "gateway", "stream_complete", trace_ctx, "attempt={d} finish_reason={s} content_bytes={d} tool_call_count={d} tool_calls={d}", .{ attempt + 1, finish_reason_label(completion.finish_reason), if (completion.content) |content| content.len else 0, completion.tool_calls.len, completion.tool_calls.len, }, );
return .{ .status = .ok, .completion = completion, }; }
return error.HttpConnectionClosing;}
fn gatewayExtraHeaders( buf: []std.http.Header, model: []const u8, team: ?[]const u8, session_id: ?[]const u8,) []const std.http.Header { std.debug.assert(buf.len >= 10); var len: usize = 0; buf[len] = .{ .name = "HTTP-Referer", .value = "https://github.com/vercel-labs/fx" }; len += 1; buf[len] = .{ .name = "X-Title", .value = "fx" }; len += 1; buf[len] = .{ .name = vercel_gateway_extended_time_header, .value = vercel_gateway_extended_time_value }; len += 1; buf[len] = .{ .name = "ai-gateway-protocol-version", .value = "0.0.1" }; len += 1; buf[len] = .{ .name = "ai-language-model-specification-version", .value = "4" }; len += 1; buf[len] = .{ .name = "ai-language-model-id", .value = model }; len += 1; buf[len] = .{ .name = "ai-language-model-streaming", .value = "true" }; len += 1; if (team) |gateway_team| { if (gateway_team.len > 0) { buf[len] = .{ .name = vercel_ai_gateway_team_header, .value = gateway_team }; len += 1; } } if (session_id) |id| { if (id.len > 0) { buf[len] = .{ .name = "x-session-id", .value = id }; len += 1; buf[len] = .{ .name = "x-session-affinity", .value = id }; len += 1; } } return buf[0..len];}
fn gatewayModelCatalogExtraHeaders(buf: []std.http.Header, team: ?[]const u8) []const std.http.Header { std.debug.assert(buf.len >= 1); var len: usize = 0; if (team) |gateway_team| { if (gateway_team.len > 0) { buf[len] = .{ .name = vercel_ai_gateway_team_header, .value = gateway_team }; len += 1; } } return buf[0..len];}
test "gateway extra headers request extended execution time" { var buf: [10]std.http.Header = undefined; const headers = gatewayExtraHeaders(&buf, "test/model", null, null); try std.testing.expectEqualStrings( vercel_gateway_extended_time_value, headerValue(headers, vercel_gateway_extended_time_header).?, );}
test "gateway extra headers include selected team" { var buf: [10]std.http.Header = undefined; const headers = gatewayExtraHeaders(&buf, "test/model", "team_123", null); try std.testing.expectEqualStrings("team_123", headerValue(headers, vercel_ai_gateway_team_header).?); try std.testing.expectEqualStrings("test/model", headerValue(headers, "ai-language-model-id").?);
const headers_without_team = gatewayExtraHeaders(&buf, "test/model", "", null); try std.testing.expect(headerValue(headers_without_team, vercel_ai_gateway_team_header) == null);}
test "gateway extra headers derive session identity and affinity together" { var buf: [10]std.http.Header = undefined; const cases = [_]struct { session_id: ?[]const u8, expected: ?[]const u8, }{ .{ .session_id = null, .expected = null }, .{ .session_id = "", .expected = null }, .{ .session_id = "session_123", .expected = "session_123" }, };
for (cases) |case| { const headers = gatewayExtraHeaders( &buf, "test/model", "team_123", case.session_id, ); try std.testing.expectEqualStrings( "team_123", headerValue(headers, vercel_ai_gateway_team_header).?, ); if (case.expected) |expected| { try std.testing.expectEqualStrings(expected, headerValue(headers, "x-session-id").?); try std.testing.expectEqualStrings(expected, headerValue(headers, "x-session-affinity").?); } else { try std.testing.expect(headerValue(headers, "x-session-id") == null); try std.testing.expect(headerValue(headers, "x-session-affinity") == null); } }}
fn headerValue(headers: []const std.http.Header, name: []const u8) ?[]const u8 { for (headers) |header| { if (std.ascii.eqlIgnoreCase(header.name, name)) return header.value; } return null;}
fn sleepGatewayRetry(delay_ns: u64, cancel_flag: *std.atomic.Value(bool)) (std.Io.Cancelable || error{Cancelled})!void { var remaining_ns = delay_ns; while (remaining_ns > 0) { if (cancel_flag.load(.seq_cst)) return error.Cancelled; const sleep_ns = @min(remaining_ns, 10 * std.time.ns_per_ms); try io_mod.getIo().sleep(.fromNanoseconds(@intCast(sleep_ns)), .awake); remaining_ns -= sleep_ns; } if (cancel_flag.load(.seq_cst)) return error.Cancelled;}
fn runBoundedStreamOperation( alloc: std.mem.Allocator, cancel_flag: *std.atomic.Value(bool), deadline: std.Io.Clock.Timestamp, operation: anytype,) !StreamResult { return runBoundedHttpOperation( StreamResult, alloc, cancel_flag, deadline, operation, );}
pub fn runBoundedHttpOperation( comptime Result: type, alloc: std.mem.Allocator, cancel_flag: *std.atomic.Value(bool), deadline: std.Io.Clock.Timestamp, operation: anytype,) !Result { if (cancel_flag.load(.seq_cst)) { debug_trace.logf("stream", "bounded termination cause=cancellation phase=admission", .{}); return error.Cancelled; } std.debug.assert(deadline.clock == .awake);
const zio = io_mod.getIo(); const now = std.Io.Clock.Timestamp.now(zio, .awake); if (!std.Io.Clock.Timestamp.compare(now, .lt, deadline)) { debug_trace.logf("stream", "bounded termination cause=deadline phase=admission", .{}); return error.Timeout; }
const Event = union(enum) { request: anyerror!Result, cancelled: anyerror!void, deadline: anyerror!void, }; const Operation = @TypeOf(operation); const Runner = struct { fn run(value: Operation) anyerror!Result { return value.run(); } }; const Cleanup = struct { fn drain(result_alloc: std.mem.Allocator, select: *std.Io.Select(Event)) void { while (select.cancel()) |item| switch (item) { .request => |request_result| { var late_result = request_result catch continue; late_result.deinit(result_alloc); }, .cancelled, .deadline => {}, }; } };
var select_buffer: [3]Event = undefined; var select: std.Io.Select(Event) = .init(zio, &select_buffer); select.concurrent(.cancelled, waitForBoundedCancellation, .{cancel_flag}) catch |err| { return err; }; select.concurrent(.deadline, waitForBoundedDeadline, .{deadline}) catch |err| { select.cancelDiscard(); return err; }; select.concurrent(.request, Runner.run, .{operation}) catch |err| { select.cancelDiscard(); return err; };
const event = select.await() catch |err| { Cleanup.drain(alloc, &select); return err; }; switch (event) { .request => |request_result| { Cleanup.drain(alloc, &select); if (cancel_flag.load(.seq_cst)) { debug_trace.logf("stream", "bounded termination cause=cancellation phase=request_result", .{}); var owned_result = request_result catch return error.Cancelled; owned_result.deinit(alloc); return error.Cancelled; } return request_result; }, .cancelled => |cancel_result| { cancel_result catch |err| { Cleanup.drain(alloc, &select); return err; }; Cleanup.drain(alloc, &select); debug_trace.logf("stream", "bounded termination cause=cancellation phase=control", .{}); return error.Cancelled; }, .deadline => |deadline_result| { deadline_result catch |err| { Cleanup.drain(alloc, &select); return err; }; Cleanup.drain(alloc, &select); if (cancel_flag.load(.seq_cst)) { debug_trace.logf("stream", "bounded termination cause=cancellation phase=deadline_cleanup", .{}); return error.Cancelled; } debug_trace.logf("stream", "bounded termination cause=deadline phase=control", .{}); return error.Timeout; }, }}
fn waitForBoundedCancellation(cancel_flag: *std.atomic.Value(bool)) anyerror!void { while (!cancel_flag.load(.seq_cst)) { try io_mod.getIo().sleep(.fromMilliseconds(5), .awake); }}
fn waitForBoundedDeadline(deadline: std.Io.Clock.Timestamp) anyerror!void { try deadline.wait(io_mod.getIo());}
const GatewayCancelWatcher = struct { fn run( done: *std.atomic.Value(bool), cancel_flag: *std.atomic.Value(bool), system_resumed: ?*std.atomic.Value(bool), deadline: ?std.Io.Clock.Timestamp, connected_watch: ?*ConnectedRequestWatch, stream: std.Io.net.Stream, ) void { var previous = SuspendClockSample.now(); while (!done.load(.seq_cst)) { if (cancel_flag.load(.seq_cst)) { if (connected_watch == null or connected_watch.?.win(.cancelled)) { stream.shutdown(io_mod.getIo(), .both) catch {}; } return; } const current = SuspendClockSample.now(); if (system_resumed != null and suspendGapDetected(previous, current)) { if (cancel_flag.load(.seq_cst)) { if (connected_watch == null or connected_watch.?.win(.cancelled)) { stream.shutdown(io_mod.getIo(), .both) catch {}; } return; } if (connected_watch == null or connected_watch.?.win(.system_resumed)) { system_resumed.?.store(true, .seq_cst); stream.shutdown(io_mod.getIo(), .both) catch {}; } return; } if (deadline) |limit| { const now = std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake); if (!std.Io.Clock.Timestamp.compare(now, .lt, limit)) { stream.shutdown(io_mod.getIo(), .both) catch {}; return; } } if (connected_watch) |watch| { const now = std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake); if (watch.response_head_expired(now) and watch.win_response_head_timeout()) { stream.shutdown(io_mod.getIo(), .both) catch {}; return; } if (watch.stream_stall_expired(now) and watch.win_stall_timeout()) { stream.shutdown(io_mod.getIo(), .both) catch {}; return; } if (watch.phase.load(.seq_cst) == .completed) return; } previous = current; io_mod.sleep(10 * std.time.ns_per_ms); } }};
const suspend_gap_tolerance_ns: i128 = 100 * std.time.ns_per_ms;
const SuspendClockSample = struct { awake_ns: i128, boot_ns: i128,
fn now() SuspendClockSample { const io = io_mod.getIo(); return .{ .awake_ns = @intCast(std.Io.Clock.Timestamp.now(io, .awake).raw.toNanoseconds()), .boot_ns = @intCast(std.Io.Clock.Timestamp.now(io, .boot).raw.toNanoseconds()), }; }};
fn suspendGapDetected(previous: SuspendClockSample, current: SuspendClockSample) bool { const awake_elapsed = current.awake_ns - previous.awake_ns; const boot_elapsed = current.boot_ns - previous.boot_ns; if (awake_elapsed < 0 or boot_elapsed < 0) return false; return boot_elapsed - awake_elapsed > suspend_gap_tolerance_ns;}
pub fn spawnHttpCancelWatcher( done: *std.atomic.Value(bool), cancel_flag: *std.atomic.Value(bool), stream: std.Io.net.Stream,) !std.Thread { return spawn_gateway_cancel_watcher(done, cancel_flag, null, null, null, stream);}
pub fn spawnHttpCancelWatcherBounded( done: *std.atomic.Value(bool), cancel_flag: *std.atomic.Value(bool), deadline: std.Io.Clock.Timestamp, stream: std.Io.net.Stream,) !std.Thread { return spawn_gateway_cancel_watcher(done, cancel_flag, null, deadline, null, stream);}
/// One shared concrete opener result so every backend reuses the same/// bounded-operation instantiation instead of specializing per file.pub const OpenedPost = struct { request: ?std.http.Client.Request,
pub fn deinit(self: *OpenedPost, _: std.mem.Allocator) void { if (self.request) |*request| request.deinit(); self.request = null; }
pub fn take(self: *OpenedPost) std.http.Client.Request { const request = self.request.?; self.request = null; return request; }};
pub const PostOperation = struct { client: *std.http.Client, uri: std.Uri, authorization: ?[]const u8, extra_headers: []const std.http.Header = &.{},
pub fn run(self: *PostOperation) !OpenedPost { var headers: std.http.Client.Request.Headers = .{ .content_type = .{ .override = "application/json" }, .accept_encoding = .omit, .user_agent = .{ .override = user_agent }, }; if (self.authorization) |value| headers.authorization = .{ .override = value }; return .{ .request = try self.client.request(.POST, self.uri, .{ .headers = headers, .extra_headers = self.extra_headers, .keep_alive = false, .redirect_behavior = .unhandled, }) }; }};
pub fn openBoundedPost( alloc: std.mem.Allocator, cancel_flag: *std.atomic.Value(bool), deadline: std.Io.Clock.Timestamp, operation: *PostOperation,) !OpenedPost { return runBoundedHttpOperation(OpenedPost, alloc, cancel_flag, deadline, operation);}
pub const CancelWatch = struct { done: std.atomic.Value(bool) = .init(false), thread: ?std.Thread = null,
pub fn start(self: *CancelWatch, cancel: *std.atomic.Value(bool), deadline: ?std.Io.Clock.Timestamp, connection: std.Io.net.Stream) !void { self.done.store(false, .seq_cst); self.thread = if (deadline) |limit| try spawnHttpCancelWatcherBounded(&self.done, cancel, limit, connection) else try spawnHttpCancelWatcher(&self.done, cancel, connection); }
pub fn stop(self: *CancelWatch) void { self.done.store(true, .seq_cst); if (self.thread) |thread| thread.join(); self.thread = null; }};
fn spawn_gateway_cancel_watcher( done: *std.atomic.Value(bool), cancel_flag: *std.atomic.Value(bool), system_resumed: ?*std.atomic.Value(bool), deadline: ?std.Io.Clock.Timestamp, connected_watch: ?*ConnectedRequestWatch, stream: std.Io.net.Stream,) !std.Thread { if (builtin.is_test) { if (test_cancel_watcher_spawn_error) |err| return err; } return std.Thread.spawn(.{}, GatewayCancelWatcher.run, .{ done, cancel_flag, system_resumed, deadline, connected_watch, stream, });}
test "suspend gap classification compares boot and awake clocks" { const before = SuspendClockSample{ .awake_ns = 1_000, .boot_ns = 10_000 }; try std.testing.expect(!suspendGapDetected(before, .{ .awake_ns = before.awake_ns + 10 * std.time.ns_per_ms, .boot_ns = before.boot_ns + 10 * std.time.ns_per_ms, })); try std.testing.expect(!suspendGapDetected(before, .{ .awake_ns = before.awake_ns + 10 * std.time.ns_per_ms, .boot_ns = before.boot_ns + 10 * std.time.ns_per_ms + suspend_gap_tolerance_ns, })); try std.testing.expect(suspendGapDetected(before, .{ .awake_ns = before.awake_ns + 10 * std.time.ns_per_ms, .boot_ns = before.boot_ns + 10 * std.time.ns_per_ms + suspend_gap_tolerance_ns + 1, }));}
test "connected request watch keeps the first terminal winner" { var cancelled = ConnectedRequestWatch.init(.{}); try std.testing.expect(cancelled.win(.cancelled)); try std.testing.expect(!cancelled.win_response_head_timeout()); try std.testing.expectEqual(error.Cancelled, cancelled.finish().?);
var resumed = ConnectedRequestWatch.init(.{}); try std.testing.expect(resumed.win(.system_resumed)); try std.testing.expect(!resumed.win(.cancelled)); try std.testing.expectEqual(error.SystemResumed, resumed.finish().?);
var ordinary = ConnectedRequestWatch.init(.{}); try std.testing.expect(ordinary.finish() == null); try std.testing.expect(!ordinary.win(.cancelled));}
test "connected request watch disarms timeout at response head" { var watch = ConnectedRequestWatch.init(.{ .timeout_ms = 1 }); try std.testing.expect(watch.arm_response_head() == null); try std.testing.expect(watch.commit_response_head() == null); try std.testing.expect(!watch.win_response_head_timeout()); try std.testing.expect(watch.finish() == null);}
test "stream stall watchdog fires with production clocks" { var watch = ConnectedRequestWatch.init(.{ .stall_timeout_ms = 50 }); // t0 precedes the progress mark, so elapsed never exceeds the synthetic // gap regardless of millisecond-boundary rounding. const t0 = std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake); try std.testing.expect(watch.arm_response_head() == null); try std.testing.expect(watch.commit_response_head() == null); const before_expiry = std.Io.Clock.Timestamp{ .clock = .awake, .raw = t0.raw.addDuration(.fromMilliseconds(1)), }; try std.testing.expect(!watch.stream_stall_expired(before_expiry)); const past_expiry = std.Io.Clock.Timestamp{ .clock = .awake, .raw = t0.raw.addDuration(.fromMilliseconds(100)), }; try std.testing.expect(watch.stream_stall_expired(past_expiry)); try std.testing.expect(watch.win_stall_timeout()); try std.testing.expectEqual(error.StreamStalled, watch.finish().?);}
test "production response head wait accepts slow headers and still expires" { var watch = ConnectedRequestWatch.init(.{}); try std.testing.expect(watch.arm_response_head() == null); const now = std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake); const slow_headers = std.Io.Clock.Timestamp{ .clock = .awake, .raw = now.raw.addDuration(.fromSeconds(36)), }; try std.testing.expect(!watch.response_head_expired(slow_headers)); try std.testing.expect(watch.response_head_expired(watch.response_head_deadline)); try std.testing.expect(watch.commit_response_head() == null); try std.testing.expect(!watch.response_head_expired(watch.response_head_deadline)); try std.testing.expect(watch.finish() == null);}
fn resolveE2eGatewayUrl(env_name: []const u8, default_url: []const u8) ![]const u8 { return selectE2eGatewayUrl(io_mod.getenv(env_name), default_url);}
/// Chat URL exactly as the request path resolves it, including the E2E/// loopback override. Invalid overrides fall back to the default so launch/// warming never fails on configuration.pub fn resolveChatUrlForWarmup(default_url: []const u8) []const u8 { return resolveE2eGatewayUrl(e2e_gateway_chat_url_env, default_url) catch default_url;}
fn selectE2eGatewayUrl(override_url: ?[]const u8, default_url: []const u8) ![]const u8 { const override = override_url orelse return default_url; if (!isLoopbackHttpUrl(override)) return error.InvalidE2EGatewayUrl; return override;}
pub fn isLoopbackHttpUrl(url: []const u8) bool { const uri = std.Uri.parse(url) catch return false; if (!std.ascii.eqlIgnoreCase(uri.scheme, "http") or uri.user != null or uri.password != null or uri.port == null) { return false; }
const host_component = uri.host orelse return false; var host_buf: [std.Io.net.HostName.max_len]u8 = undefined; const host = host_component.toRaw(&host_buf) catch return false; return std.mem.eql(u8, host, "127.0.0.1") or std.ascii.eqlIgnoreCase(host, "localhost") or std.mem.eql(u8, host, "[::1]");}
const HeaderMatch = struct { name: []const u8, value: []const u8,};
fn isRetryableGatewayStatus(status: std.http.Status) bool { return switch (status) { .too_many_requests, .internal_server_error, .bad_gateway, .service_unavailable, .gateway_timeout, => true, else => false, };}
fn retryDelayNsForResponse(head: std.http.Client.Response.Head, attempt: usize) u64 { if (retryAfterDelayNs(head)) |delay_ns| return delay_ns; return retryBackoffDelayNs(attempt);}
fn retryBackoffDelayNs(attempt: usize) u64 { const multiplier: u64 = @intCast(attempt + 1); return multiplier * gateway_retry_base_delay_ns;}
fn retryAfterDelayNs(head: std.http.Client.Response.Head) ?u64 { const seconds = retryAfterSeconds(head) orelse return null; const delay = std.math.mul(u64, seconds, std.time.ns_per_s) catch gateway_retry_after_max_ns; return @min(delay, gateway_retry_after_max_ns);}
fn retryAfterSeconds(head: std.http.Client.Response.Head) ?u64 { const raw = findHeaderValue(head, "retry-after") orelse return null; const trimmed = std.mem.trim(u8, raw, " \t\r\n"); if (trimmed.len == 0) return null; return std.fmt.parseInt(u64, trimmed, 10) catch |err| switch (err) { error.Overflow => std.math.maxInt(u64), error.InvalidCharacter => null, };}
fn findHeaderValue(head: std.http.Client.Response.Head, name: []const u8) ?[]const u8 { var it = head.iterateHeaders(); while (it.next()) |header| { if (std.ascii.eqlIgnoreCase(header.name, name)) return header.value; } return null;}
fn traceResolvedModelHeader(head: std.http.Client.Response.Head, requested_model: []const u8, trace_ctx: debug_trace.TraceContext) bool { if (findResolvedModelHeader(head)) |header| { traceResolvedModelOnce(requested_model, header.name, header.value, trace_ctx); return true; } return false;}
fn traceResolvedModelOnce(requested_model: []const u8, source: []const u8, resolved_model: []const u8, trace_ctx: debug_trace.TraceContext) void { if (resolved_model_trace_emitted.swap(true, .acq_rel)) return;
debug_trace.eventf( "gateway", "resolved_model", trace_ctx, "requested_model={s} source={s} resolved_model={s}", .{ requested_model, source, resolved_model }, );}
fn traceResolvedModelMissingOnce(requested_model: []const u8, trace_ctx: debug_trace.TraceContext) void { if (resolved_model_trace_emitted.swap(true, .acq_rel)) return;
debug_trace.eventf( "gateway", "resolved_model_missing", trace_ctx, "requested_model={s}", .{requested_model}, );}
fn findResolvedModelHeader(head: std.http.Client.Response.Head) ?HeaderMatch { var it = head.iterateHeaders(); while (it.next()) |header| { if (isResolvedModelHeaderName(header.name)) { return .{ .name = header.name, .value = std.mem.trim(u8, header.value, " \t\r\n"), }; } } return null;}
fn isResolvedModelHeaderName(name: []const u8) bool { return std.ascii.eqlIgnoreCase(name, "x-vercel-ai-gateway-model") or std.ascii.eqlIgnoreCase(name, "x-vercel-ai-gateway-model-id") or std.ascii.eqlIgnoreCase(name, "x-ai-gateway-model") or std.ascii.eqlIgnoreCase(name, "ai-gateway-model") or std.ascii.eqlIgnoreCase(name, "ai-language-model-id");}
const StreamedToolInputState = enum { open, ended, finalized,};
const GatewayReplayBuilder = struct { const max_bytes = types.ProviderReplay.max_bytes; const Kind = enum { text, reasoning, tool_call }; const Part = struct { kind: Kind, id: []u8, text: std.ArrayList(u8) = .empty, offset: usize = 0, length: usize = 0, metadata: ?[]u8 = null, has_provider_metadata: bool = false, ended: bool = false,
fn deinit(self: *Part, alloc: std.mem.Allocator) void { alloc.free(self.id); self.text.deinit(alloc); if (self.metadata) |value| alloc.free(value); } };
alloc: std.mem.Allocator, parts: std.ArrayList(Part) = .empty, retained_bytes: usize = 0, needed: bool = false,
fn deinit(self: *GatewayReplayBuilder) void { for (self.parts.items) |*part| part.deinit(self.alloc); self.parts.deinit(self.alloc); }
fn reserve(self: *GatewayReplayBuilder, bytes: usize) !void { if (bytes > max_bytes - self.retained_bytes) return error.ProviderStateTooLarge; self.retained_bytes += bytes; }
fn findPart(parts: []const Part, kind: Kind, id: []const u8, starts_segment: bool) ?usize { for (0..parts.len) |offset| { const index = if (kind == .tool_call) offset else parts.len - 1 - offset; const part = parts[index]; if (part.kind != kind or !std.mem.eql(u8, part.id, id)) continue; // Provider continuations can restart a text or reasoning ID within one response. if (kind != .tool_call and starts_segment and part.ended) return null; return index; } return null; }
fn observe(self: *GatewayReplayBuilder, root: std.json.Value, content_offset: usize) !void { const event = root.object.get("type").?.string; const kind: Kind = if (std.mem.startsWith(u8, event, "reasoning-")) .reasoning else if (std.mem.startsWith(u8, event, "text-")) .text else if (std.mem.startsWith(u8, event, "tool-input-") or std.mem.eql(u8, event, "tool-call")) .tool_call else return; if (kind == .reasoning and !std.mem.eql(u8, event, "reasoning-start") and !std.mem.eql(u8, event, "reasoning-delta") and !std.mem.eql(u8, event, "reasoning-end")) return; const id_value = root.object.get(if (std.mem.eql(u8, event, "tool-call")) "toolCallId" else "id"); const id: []const u8 = if (id_value) |value| if (value == .string) value.string else "" else ""; // Canonical admission owns rejection of malformed tool identities. if (kind == .tool_call and types.ConversationIdentity.invalidReason(id) != null) return; if (id.len > types.ConversationIdentity.max_bytes) return error.ProviderStateTooLarge; var index = findPart(self.parts.items, kind, id, std.mem.eql(u8, event, "text-start") or std.mem.eql(u8, event, "reasoning-start")); if (index == null) { try self.reserve(@sizeOf(Part) + id.len); const owned_id = try self.alloc.dupe(u8, id); errdefer self.alloc.free(owned_id); try self.parts.append(self.alloc, .{ .kind = kind, .id = owned_id, .offset = content_offset }); index = self.parts.items.len - 1; } const part = &self.parts.items[index.?]; if (kind == .reasoning) self.needed = true; if (std.mem.endsWith(u8, event, "-delta") and kind != .tool_call) { const delta = root.object.get("delta") orelse return; if (delta != .string) return error.InvalidProviderState; if (part.ended) return error.InvalidProviderState; if (kind == .reasoning) { try self.reserve(delta.string.len); try part.text.appendSlice(self.alloc, delta.string); } else { const end = std.math.add(usize, part.offset, part.length) catch return error.ProviderStateTooLarge; if (content_offset != end) return error.InvalidProviderState; part.length = std.math.add(usize, part.length, delta.string.len) catch return error.ProviderStateTooLarge; } } if (std.mem.endsWith(u8, event, "-end") or std.mem.eql(u8, event, "tool-call")) part.ended = true; if (root.object.get("providerMetadata")) |metadata| { if (metadata != .object) return error.InvalidProviderState; for (metadata.object.values()) |options| if (options != .object) return error.InvalidProviderState; for (metadata.object.keys()) |key| { if (!std.mem.eql(u8, key, "gateway")) { self.needed = true; part.has_provider_metadata = true; } } if (part.has_provider_metadata and id.len == 0) return error.InvalidProviderState; const merged = try mergeReplayMetadata(self.alloc, part.metadata, metadata); errdefer self.alloc.free(merged); const previous_len = if (part.metadata) |previous| previous.len else 0; if (merged.len > previous_len) try self.reserve(merged.len - previous_len); if (merged.len < previous_len) self.retained_bytes -= previous_len - merged.len; if (part.metadata) |previous| self.alloc.free(previous); part.metadata = merged; } }
fn finish(self: *GatewayReplayBuilder, content: []const u8, calls: []const types.ToolCall) !?[]u8 { if (!self.needed) return null; var out: std.Io.Writer.Allocating = .init(self.alloc); errdefer out.deinit(); try out.writer.writeByte('['); var emitted = false; parts: for (self.parts.items, 0..) |part, index| { var metadata: ?[]const u8 = part.metadata; var merged_metadata: ?[]u8 = null; defer if (merged_metadata) |owned| self.alloc.free(owned); var canonical_call: ?types.ToolCall = null; if (part.kind == .tool_call) { for (calls) |call| { if (partMatchesCall(part, call)) { canonical_call = call; break; } } const call = canonical_call orelse { if (part.has_provider_metadata) return error.InvalidProviderState; continue; }; for (self.parts.items[0..index]) |prior| { if (partMatchesCall(prior, call)) continue :parts; } for (self.parts.items[index + 1 ..]) |later| { if (!partMatchesCall(later, call)) continue; const next = later.metadata orelse continue; const parsed = try std.json.parseFromSlice(std.json.Value, self.alloc, next, .{}); defer parsed.deinit(); const merged = try mergeReplayMetadata(self.alloc, metadata, parsed.value); if (merged_metadata) |owned| self.alloc.free(owned); merged_metadata = merged; metadata = merged; } } if (emitted) try out.writer.writeByte(','); switch (part.kind) { .reasoning => { if (!part.ended and part.metadata != null) return error.InvalidProviderState; try out.writer.writeAll("{\"type\":\"reasoning\",\"text\":"); try std.json.Stringify.value(part.text.items, .{}, &out.writer); }, .text => { if (part.offset > content.len or part.length > content.len - part.offset) return error.InvalidProviderState; try out.writer.print("{{\"type\":\"text\",\"offset\":{d},\"length\":{d}", .{ part.offset, part.length }); }, .tool_call => { try out.writer.writeAll("{\"type\":\"tool-call\",\"toolCallId\":"); try std.json.Stringify.value(canonical_call.?.id, .{}, &out.writer); }, } if (metadata) |value| { try out.writer.writeAll(",\"providerOptions\":"); try out.writer.writeAll(value); } try out.writer.writeByte('}'); emitted = true; if (out.written().len > max_bytes) return error.ProviderStateTooLarge; } try out.writer.writeByte(']'); if (out.written().len > max_bytes) return error.ProviderStateTooLarge; return try out.toOwnedSlice(); }
fn partMatchesCall(part: Part, call: types.ToolCall) bool { return part.kind == .tool_call and (std.mem.eql(u8, part.id, call.id) or if (call.provisional_id) |id| std.mem.eql(u8, part.id, id) else false); }};
fn mergeReplayMetadata(alloc: std.mem.Allocator, previous: ?[]const u8, next: std.json.Value) ![]u8 { var scratch = std.heap.ArenaAllocator.init(alloc); defer scratch.deinit(); const arena = scratch.allocator(); var merged = if (previous) |bytes| try std.json.parseFromSliceLeaky(std.json.Value, arena, bytes, .{}) else std.json.Value{ .object = .empty }; try mergeReplayObject(arena, &merged, next); return stringifyJsonValueOwned(alloc, merged);}
fn mergeReplayObject(alloc: std.mem.Allocator, target: *std.json.Value, next: std.json.Value) !void { const Merge = struct { target: *std.json.Value, source: std.json.Value }; var pending: std.ArrayList(Merge) = .empty; defer pending.deinit(alloc); try pending.append(alloc, .{ .target = target, .source = next }); while (pending.pop()) |entry| { if (entry.target.* != .object or entry.source != .object) { entry.target.* = entry.source; continue; } const capacity = std.math.add(usize, entry.target.object.count(), entry.source.object.count()) catch return error.ProviderStateTooLarge; try entry.target.object.ensureTotalCapacity(alloc, capacity); var fields = entry.source.object.iterator(); while (fields.next()) |field| { const slot = entry.target.object.getOrPutAssumeCapacity(field.key_ptr.*); if (slot.found_existing) { try pending.append(alloc, .{ .target = slot.value_ptr, .source = field.value_ptr.* }); } else { slot.value_ptr.* = field.value_ptr.*; } } }}
const SseStreamedToolInput = struct { id: std.ArrayList(u8), name: std.ArrayList(u8), arguments: std.ArrayList(u8), state: StreamedToolInputState = .open, label_sent: bool = false,
fn deinit(self: *SseStreamedToolInput, alloc: std.mem.Allocator) void { self.id.deinit(alloc); self.name.deinit(alloc); self.arguments.deinit(alloc); self.* = undefined; }};
const ProviderResultState = enum { none, preliminary, final,};
const SseToolCallAccumulator = struct { id: std.ArrayList(u8), name: std.ArrayList(u8), arguments: std.ArrayList(u8), provisional_id: std.ArrayList(u8) = .empty, argument_integrity: types.ToolArgumentIntegrity = .valid, provider_result: ?[]u8 = null, provider_result_state: ProviderResultState = .none, final_identity: types.FinalToolIdentity = .valid, provenance: types.ToolExecutionProvenance = .fx_local,
fn deinit(self: *SseToolCallAccumulator, alloc: std.mem.Allocator) void { self.id.deinit(alloc); self.name.deinit(alloc); self.arguments.deinit(alloc); self.provisional_id.deinit(alloc); if (self.provider_result) |result| alloc.free(result); self.* = undefined; }};
const ResolvedModelTrace = struct { requested_model: []const u8, ctx: debug_trace.TraceContext,};
const StreamStateAnomaly = enum { invalid_start, conflicting_start, late_start, unmatched_or_late_delta, unmatched_or_duplicate_end,};
var test_force_sse_preview_failure = false;
fn traceStreamStateAnomaly(reason: StreamStateAnomaly) void { debug_trace.logf("sse", "event=stream_state_anomaly reason={s}", .{@tagName(reason)});}
fn canonicalSseEventType(event_type: []const u8) []const u8 { inline for (.{ "response-metadata", "text-start", "text-delta", "text-end", "reasoning-start", "reasoning-delta", "reasoning-end", "tool-input-start", "tool-input-delta", "tool-input-end", "tool-call", "tool-result", "source", "file", "raw", "error", "start", "start-step", "finish-step", "finish", }) |known| { if (std.mem.eql(u8, event_type, known)) return known; } return "unknown";}
fn traceParsedSseEvent(alloc: std.mem.Allocator, root: std.json.Value, json_bytes: usize) void { if (!debug_trace.isScopeEnabled("sse")) return;
const event_type = if (root == .object) if (root.object.get("type")) |type_value| if (type_value == .string) canonicalSseEventType(type_value.string) else "invalid" else "invalid" else "invalid";
if (builtin.is_test and test_force_sse_preview_failure) { debug_trace.logf("sse", "event type={s} bytes={d} preview=<preview-error>", .{ event_type, json_bytes, }); return; }
const preview_text = debug_trace.keylessJsonValuePreview(alloc, root) catch { debug_trace.logf("sse", "event type={s} bytes={d} preview=<preview-error>", .{ event_type, json_bytes, }); return; }; defer alloc.free(preview_text); debug_trace.logf("sse", "event type={s} bytes={d} preview={s}", .{ event_type, json_bytes, preview_text, });}
fn traceMalformedSseEvent(json_bytes: usize) void { debug_trace.logf("sse", "event type=invalid bytes={d} preview=<invalid-json>", .{json_bytes});}
fn setProviderResultFailure( failure: *?types.ProviderResultIdentityFailure, value: types.ProviderResultIdentityFailure,) void { if (failure.* == null) failure.* = value;}
fn findStreamedToolInput(records: []const SseStreamedToolInput, id: []const u8) ?usize { for (records, 0..) |record, i| { if (std.mem.eql(u8, record.id.items, id)) return i; } return null;}
fn findEquivalentEndedStreamedToolInput( alloc: std.mem.Allocator, records: []const SseStreamedToolInput, final_name: []const u8, final_arguments: []const u8,) std.mem.Allocator.Error!?usize { if (final_name.len == 0) return null;
for (records, 0..) |record, i| { if (record.state != .ended) continue; if (!std.mem.eql(u8, record.name.items, final_name)) continue; if (try json_comparison.serializedEqual(alloc, record.arguments.items, final_arguments)) return i; } return null;}
fn initStreamedToolInput( alloc: std.mem.Allocator, id: []const u8, name: []const u8,) !SseStreamedToolInput { var record: SseStreamedToolInput = .{ .id = .empty, .name = .empty, .arguments = .empty, }; errdefer record.deinit(alloc); try record.id.appendSlice(alloc, id); try record.name.appendSlice(alloc, name); return record;}
fn streamedToolInputId( root: std.json.Value, anomaly: StreamStateAnomaly,) ?[]const u8 { const id_value = root.object.get("id") orelse { traceStreamStateAnomaly(anomaly); return null; }; if (id_value != .string or id_value.string.len == 0) { traceStreamStateAnomaly(anomaly); return null; } return id_value.string;}
const ToolArgumentSource = enum { final_string, streamed_fallback,};
const FinalToolInputState = enum { absent, valid, malformed,};
fn appendSerializedToolArguments( alloc: std.mem.Allocator, destination: *std.ArrayList(u8), serialized: []const u8, call_id: []const u8, tool_name: []const u8, source: ToolArgumentSource,) !types.ToolArgumentIntegrity { const integrity = try types.ToolArgumentIntegrity.classifySerialized(alloc, serialized); if (integrity == .valid) { try destination.appendSlice(alloc, serialized); return .valid; }
try destination.appendSlice(alloc, "{}"); debug_trace.logf( "sse", "event=tool_argument_integrity call_id={s} tool_name={s} source={s} bytes={d} failure=malformed_json", .{ call_id, tool_name, @tagName(source), serialized.len }, ); return .malformed_json;}
fn appendSupportedFinalInput( alloc: std.mem.Allocator, destination: *std.ArrayList(u8), input: std.json.Value, call_id: []const u8, tool_name: []const u8,) !types.ToolArgumentIntegrity { switch (input) { .string => |value| { return try appendSerializedToolArguments( alloc, destination, value, call_id, tool_name, .final_string, ); }, .object, .array => { var out: std.Io.Writer.Allocating = .init(alloc); defer out.deinit(); std.json.Stringify.value(input, .{}, &out.writer) catch return error.OutOfMemory; try destination.appendSlice(alloc, out.written()); return .valid; }, else => { try destination.appendSlice(alloc, "{}"); debug_trace.logf( "sse", "event=tool_argument_integrity call_id={s} tool_name={s} source=final_value input_kind={s} failure=malformed_json", .{ call_id, tool_name, @tagName(input) }, ); return .malformed_json; }, }}
fn stringifyJsonValueOwned(alloc: std.mem.Allocator, value: std.json.Value) ![]u8 { var out: std.Io.Writer.Allocating = .init(alloc); errdefer out.deinit(); std.json.Stringify.value(value, .{}, &out.writer) catch return error.OutOfMemory; return out.toOwnedSlice();}
fn deinitGatewayCompletion(alloc: std.mem.Allocator, completion: *types.ModelCompletion) void { if (completion.content) |content| alloc.free(content); if (completion.generation_id) |id| alloc.free(id); if (completion.billing) |billing| alloc.free(@constCast(billing.model)); for (completion.tool_calls) |call| { alloc.free(call.id); alloc.free(call.name); alloc.free(call.arguments_json); if (call.provisional_id) |provisional_id| alloc.free(provisional_id); if (call.provider_result) |provider_result| alloc.free(provider_result); } if (completion.tool_calls.len > 0) alloc.free(completion.tool_calls); if (completion.provider_failure_detail) |detail| alloc.free(@constCast(detail)); if (completion.provider_state_json) |state| alloc.free(state); completion.* = .{};}
fn clippedDupe(alloc: std.mem.Allocator, text: []const u8, max_bytes: usize) ![]u8 { const trimmed = std.mem.trim(u8, text, " \r\n\t"); const clipped = trimmed[0..@min(trimmed.len, max_bytes)]; return try alloc.dupe(u8, clipped);}
fn replaceProviderFailureDetail(alloc: std.mem.Allocator, current: *?[]u8, text: []const u8) !void { if (text.len == 0) return; const owned = try clippedDupe(alloc, text, provider_failure_detail_max_bytes); if (owned.len == 0) { alloc.free(owned); return; } if (current.*) |old| alloc.free(old); current.* = owned;}
fn replaceProviderFailureMessage( alloc: std.mem.Allocator, current: *?[]u8, text: []const u8,) !void { const combined = try std.fmt.allocPrint(alloc, "provider_error: {s}", .{text}); defer alloc.free(combined); try replaceProviderFailureDetail(alloc, current, combined);}
fn jsonValueString(value: std.json.Value) ?[]const u8 { return if (value == .string and value.string.len > 0) value.string else null;}
fn isGatewayStreamTimeoutCode(value: std.json.Value) bool { const text = jsonValueString(value) orelse return false; return std.mem.eql(u8, text, "gateway_stream_timeout");}
fn objectHasGatewayStreamTimeout(object: std.json.ObjectMap) bool { if (object.get("code")) |value| { if (isGatewayStreamTimeoutCode(value)) return true; } if (object.get("type")) |value| { if (isGatewayStreamTimeoutCode(value)) return true; } return false;}
fn providerFailureCause(root: std.json.Value) ?types.ProviderFailureCause { if (root != .object) return null; const object = root.object; if (objectHasGatewayStreamTimeout(object)) return .gateway_stream_timeout;
inline for (.{ "error", "providerError" }) |key| { if (object.get(key)) |value| { if (value == .object and objectHasGatewayStreamTimeout(value.object)) { return .gateway_stream_timeout; } } } if (object.get("finishReason")) |value| { if (value == .object) { if (value.object.get("raw")) |raw| { if (isGatewayStreamTimeoutCode(raw)) return .gateway_stream_timeout; } } } return null;}
fn captureProviderFailureObject( alloc: std.mem.Allocator, current: *?[]u8, object: std.json.ObjectMap, include_type: bool,) !bool { const code = if (object.get("code")) |value| jsonValueString(value) else if (include_type) if (object.get("type")) |value| jsonValueString(value) else null else null; const message = if (object.get("message")) |value| jsonValueString(value) else null; if (code) |code_text| { if (message) |message_text| { const combined = try std.fmt.allocPrint(alloc, "{s}: {s}", .{ code_text, message_text }); defer alloc.free(combined); try replaceProviderFailureDetail(alloc, current, combined); return true; } }
const message_keys = [_][]const u8{ "message", "detail", "details", "reason" }; for (&message_keys) |key| { if (object.get(key)) |value| { if (jsonValueString(value)) |text| { try replaceProviderFailureMessage(alloc, current, text); return true; } } } if (code) |code_text| { try replaceProviderFailureDetail(alloc, current, code_text); return true; } return false;}
fn captureProviderFailureDetail(alloc: std.mem.Allocator, current: *?[]u8, root: std.json.Value) !void { if (root != .object or current.* != null) return; if (try captureProviderFailureObject(alloc, current, root.object, false)) return; if (root.object.get("error")) |value| { if (jsonValueString(value)) |text| { try replaceProviderFailureMessage(alloc, current, text); return; } if (value == .object) { if (try captureProviderFailureObject(alloc, current, value.object, true)) return; const rendered = try stringifyJsonValueOwned(alloc, value); defer alloc.free(rendered); try replaceProviderFailureDetail(alloc, current, rendered); return; } } if (root.object.get("providerError")) |value| { if (jsonValueString(value)) |text| { try replaceProviderFailureMessage(alloc, current, text); return; } if (value == .object) { if (try captureProviderFailureObject(alloc, current, value.object, true)) return; } const rendered = try stringifyJsonValueOwned(alloc, value); defer alloc.free(rendered); try replaceProviderFailureDetail(alloc, current, rendered); }}
fn materializeToolCalls( alloc: std.mem.Allocator, accumulators: []const SseToolCallAccumulator,) ![]const types.ToolCall { if (accumulators.len == 0) return &.{};
const calls = try alloc.alloc(types.ToolCall, accumulators.len); var initialized: usize = 0; errdefer { for (calls[0..initialized]) |call| { alloc.free(call.id); alloc.free(call.name); alloc.free(call.arguments_json); if (call.provisional_id) |provisional_id| alloc.free(provisional_id); if (call.provider_result) |provider_result| alloc.free(provider_result); } alloc.free(calls); }
for (accumulators, 0..) |acc, i| { const id = try alloc.dupe(u8, acc.id.items); errdefer alloc.free(id); const name = try alloc.dupe(u8, acc.name.items); errdefer alloc.free(name); const arguments = try alloc.dupe(u8, acc.arguments.items); errdefer alloc.free(arguments); const provisional_id = if (acc.provisional_id.items.len > 0) try alloc.dupe(u8, acc.provisional_id.items) else null; errdefer if (provisional_id) |value| alloc.free(value); const provider_result = if (acc.provider_result_state == .final) if (acc.provider_result) |result| try alloc.dupe(u8, result) else null else null; errdefer if (provider_result) |result| alloc.free(result);
calls[i] = .{ .id = id, .name = name, .arguments_json = arguments, .argument_integrity = acc.argument_integrity, .provisional_id = provisional_id, .provider_result = provider_result, .final_identity = acc.final_identity, .provenance = acc.provenance, }; initialized += 1; }
return calls;}
fn extractFirstJsonStringValue(args: []const u8) ?[]const u8 { const colon = std.mem.findScalar(u8, args, ':') orelse return null; var i = colon + 1; while (i < args.len and args[i] == ' ') : (i += 1) {} if (i >= args.len or args[i] != '"') return null; i += 1; const start = i; while (i < args.len) : (i += 1) { if (args[i] == '\\') { i += 1; continue; } if (args[i] == '"') return args[start..i]; } return null;}
fn finish_reason_label(finish_reason: ?types.ProviderFinishReason) []const u8 { return if (finish_reason) |reason| reason.label() else "(none)";}
fn traceSseTermination(trace: ?ResolvedModelTrace, cause: []const u8, finish_reason: ?types.ProviderFinishReason) void { debug_trace.logf("stream", "termination cause={s} finish_reason={s}", .{ cause, finish_reason_label(finish_reason), }); if (trace) |resolved| { debug_trace.eventf("gateway", "sse_termination", resolved.ctx, "cause={s} finish_reason={s}", .{ cause, finish_reason_label(finish_reason), }); }}
const SseFinishEvent = struct { finish_reason: types.ProviderFinishReason, usage: types.Usage = .{},};
const SseFinishParseError = error{ InvalidProviderFinishReason, UnknownProviderFinishReason,};
fn parseSseFinishEvent( alloc: std.mem.Allocator, root: std.json.Value, provider_failure_detail: *?[]u8,) !SseFinishEvent { const finish_reason = try parseSseFinishReason(root); if (finish_reason == .provider_error) { try captureProviderFailureDetail(alloc, provider_failure_detail, root); } return .{ .finish_reason = finish_reason, .usage = parseSseUsage(root), };}
fn parseSseFinishReason(root: std.json.Value) SseFinishParseError!types.ProviderFinishReason { if (root != .object) return error.InvalidProviderFinishReason; const finish_reason_value = root.object.get("finishReason") orelse return error.InvalidProviderFinishReason; if (finish_reason_value != .object) return error.InvalidProviderFinishReason; const unified_value = finish_reason_value.object.get("unified") orelse return error.InvalidProviderFinishReason; if (unified_value != .string) return error.InvalidProviderFinishReason; return types.ProviderFinishReason.parse_unified(unified_value.string) orelse error.UnknownProviderFinishReason;}
fn parseSseUsage(root: std.json.Value) types.Usage { if (root != .object) return .{}; const usage_value = root.object.get("usage") orelse return .{}; if (usage_value != .object) return .{}; return .{ .input_tokens = parseSseTokenTotal(usage_value, "inputTokens"), .output_tokens = parseSseTokenTotal(usage_value, "outputTokens"), };}
fn parseSseTokenTotal(usage_value: std.json.Value, key: []const u8) ?u64 { if (usage_value != .object) return null; const token_value = usage_value.object.get(key) orelse return null; if (token_value != .object) return null; const total_value = token_value.object.get("total") orelse return null; if (total_value != .integer or total_value.integer < 0) return null; return @intCast(total_value.integer);}
const SseBillingParseError = std.mem.Allocator.Error || error{InvalidSseBilling};
fn parseSseBilling( alloc: std.mem.Allocator, root: std.json.Value, created_at_ms: ?i64, tools: []const SseToolCallAccumulator,) SseBillingParseError!types.ProviderBilling { const timestamp = created_at_ms orelse return error.InvalidSseBilling; const usage = if (root == .object) root.object.get("usage") orelse return error.InvalidSseBilling else return error.InvalidSseBilling; if (usage != .object) return error.InvalidSseBilling; const input = usage.object.get("inputTokens") orelse return error.InvalidSseBilling; const output = usage.object.get("outputTokens") orelse return error.InvalidSseBilling; if (input != .object or output != .object) return error.InvalidSseBilling;
const provider_metadata = root.object.get("providerMetadata") orelse return error.InvalidSseBilling; if (provider_metadata != .object) return error.InvalidSseBilling; const gateway = provider_metadata.object.get("gateway") orelse return error.InvalidSseBilling; if (gateway != .object) return error.InvalidSseBilling; const routing = gateway.object.get("routing") orelse return error.InvalidSseBilling; if (routing != .object) return error.InvalidSseBilling; const model_value = routing.object.get("canonicalSlug") orelse return error.InvalidSseBilling; if (model_value != .string or model_value.string.len == 0 or model_value.string.len > 1024) { return error.InvalidSseBilling; } for (model_value.string) |byte| { if (byte < 0x21 or byte > 0x7e) return error.InvalidSseBilling; }
const cost_value = gateway.object.get("cost") orelse return error.InvalidSseBilling; if (cost_value != .string) return error.InvalidSseBilling; const total_cost = std.fmt.parseFloat(f64, cost_value.string) catch return error.InvalidSseBilling; if (!std.math.isFinite(total_cost) or total_cost < 0) { return error.InvalidSseBilling; }
var billable_web_search_calls: u64 = 0; for (tools) |tool| { if (tool.provenance != .provider_executed) continue; if (!std.mem.eql(u8, tool.name.items, "web_search") and !std.mem.endsWith(u8, tool.name.items, "_search")) { continue; } billable_web_search_calls = std.math.add( u64, billable_web_search_calls, 1, ) catch return error.InvalidSseBilling; }
const input_tokens = try parseBillingInteger(input.object.get("total")); const output_tokens = try parseBillingInteger(output.object.get("total")); const cache_read_tokens = try parseOptionalBillingInteger( input.object.get("cacheRead"), ); const cache_write_tokens = try parseOptionalBillingInteger( input.object.get("cacheWrite"), ); const reasoning_tokens = try parseOptionalNullableBillingInteger( output.object.get("reasoning"), ); if (cache_read_tokens > input_tokens or cache_write_tokens > input_tokens or (reasoning_tokens != null and reasoning_tokens.? > output_tokens)) { return error.InvalidSseBilling; }
return .{ .created_at_ms = timestamp, .model = try alloc.dupe(u8, model_value.string), .total_cost = total_cost, .input_tokens = input_tokens, .output_tokens = output_tokens, .cache_read_tokens = cache_read_tokens, .cache_write_tokens = cache_write_tokens, .reasoning_tokens = reasoning_tokens, .billable_web_search_calls = billable_web_search_calls, };}
fn parseBillingInteger(value: ?std.json.Value) error{InvalidSseBilling}!u64 { const actual = value orelse return error.InvalidSseBilling; if (actual != .integer or actual.integer < 0) { return error.InvalidSseBilling; } return @intCast(actual.integer);}
fn parseOptionalBillingInteger( value: ?std.json.Value,) error{InvalidSseBilling}!u64 { return if (value) |actual| try parseBillingInteger(actual) else 0;}
fn parseOptionalNullableBillingInteger( value: ?std.json.Value,) error{InvalidSseBilling}!?u64 { return if (value) |actual| if (actual == .null) null else try parseBillingInteger(actual) else null;}
fn captureGenerationMetadata( alloc: std.mem.Allocator, root: std.json.Value, generation_id: *?[]u8, invalid: *bool,) !void { if (root != .object) return; const provider_metadata = root.object.get("providerMetadata") orelse return; if (provider_metadata != .object) { invalid.* = true; return; } const gateway = provider_metadata.object.get("gateway") orelse return; if (gateway != .object) { invalid.* = true; return; } const generation_value = gateway.object.get("generationId") orelse return; if (generation_value != .string or !types.validGatewayGenerationId(generation_value.string)) { invalid.* = true; return; } if (generation_id.*) |existing| { if (!std.mem.eql(u8, existing, generation_value.string)) invalid.* = true; return; } generation_id.* = try alloc.dupe(u8, generation_value.string);}
fn consumeSseStream( alloc: std.mem.Allocator, reader: *std.Io.Reader, callback_ctx: *anyopaque, on_content_chunk: StreamCallback, on_tool_start: ?ToolStartCallback, cancel_flag: *std.atomic.Value(bool),) !types.ModelCompletion { return consumeSseStreamTraced(alloc, reader, callback_ctx, on_content_chunk, on_tool_start, null, null, cancel_flag, null, null, null, null);}
/// Decodes an AI Gateway SSE response from a transport-owned reader.////// The returned completion and every populated child buffer are owned by/// `alloc`. This is the shared protocol boundary used by native HTTP and web/// host transports; transports remain responsible for status and headers.pub fn consumeGatewaySseStream( alloc: std.mem.Allocator, reader: *std.Io.Reader, callback_ctx: *anyopaque, on_content_chunk: StreamCallback, on_tool_start: ?ToolStartCallback, on_reasoning_chunk: ?StreamCallback, cancel_flag: *std.atomic.Value(bool), content_capture_limit: ?usize,) !types.ModelCompletion { return consumeSseStreamTraced( alloc, reader, callback_ctx, on_content_chunk, on_tool_start, on_reasoning_chunk, null, cancel_flag, null, null, content_capture_limit, null, );}
fn consumeSseStreamTraced( alloc: std.mem.Allocator, reader: *std.Io.Reader, callback_ctx: *anyopaque, on_content_chunk: StreamCallback, on_tool_start: ?ToolStartCallback, on_reasoning_chunk: ?StreamCallback, on_tool_input_chunk: ?StreamCallback, cancel_flag: *std.atomic.Value(bool), resolved_model_trace: ?ResolvedModelTrace, expected_provider_tool_name: ?[]const u8, content_capture_limit: ?usize, progress_watch: ?*ConnectedRequestWatch,) !types.ModelCompletion { var content_buf: std.ArrayList(u8) = .empty; defer content_buf.deinit(alloc); var replay = GatewayReplayBuilder{ .alloc = alloc }; defer replay.deinit(); // Reuse event storage instead of pinning old response buffers in the caller's arena. var event_arena = std.heap.ArenaAllocator.init(alloc); defer mem_utils.deinit_arena(event_arena);
var streamed_tool_inputs: std.ArrayList(SseStreamedToolInput) = .empty; defer { for (streamed_tool_inputs.items) |*record| record.deinit(alloc); streamed_tool_inputs.deinit(alloc); }
var tool_accumulators: std.ArrayList(SseToolCallAccumulator) = .empty; defer { for (tool_accumulators.items) |*acc| acc.deinit(alloc); tool_accumulators.deinit(alloc); }
var finish_reason_holder: ?types.ProviderFinishReason = null; var finish_usage: types.Usage = .{}; var finish_billing: ?types.ProviderBilling = null; defer if (finish_billing) |billing| alloc.free(@constCast(billing.model)); var generation_id: ?[]u8 = null; defer if (generation_id) |id| alloc.free(id); var resolved_model: ?[]u8 = null; defer if (resolved_model) |model| alloc.free(model); var response_timestamp_ms: ?i64 = null; var response_timestamp_invalid = false; var generation_metadata_invalid = false; var provider_result_identity_failure: ?types.ProviderResultIdentityFailure = null; var provider_failure_cause: ?types.ProviderFailureCause = null; var provider_failure_detail: ?[]u8 = null; defer if (provider_failure_detail) |detail| alloc.free(detail); var data_event_count: usize = 0;
var event_reader = sse.Reader{ .max_event_bytes = max_sse_event_line_bytes }; defer event_reader.deinit(alloc);
while (true) { if (cancel_flag.load(.seq_cst)) { traceSseTermination(resolved_model_trace, "cancellation", finish_reason_holder); break; }
const payload = event_reader.next(alloc, reader, cancel_flag) catch |err| switch (err) { error.EventTooLarge => return error.GatewaySseEventTooLarge, error.Cancelled => { traceSseTermination(resolved_model_trace, "cancellation", finish_reason_holder); break; }, error.ReadFailed => { if (cancel_flag.load(.seq_cst)) { traceSseTermination(resolved_model_trace, "cancellation", finish_reason_holder); break; } traceSseTermination(resolved_model_trace, "read_failure", finish_reason_holder); return error.ReadFailed; }, else => return err, }; const json_text = payload orelse { traceSseTermination(resolved_model_trace, "eof_without_finish", finish_reason_holder); break; }; if (progress_watch) |watch| watch.markStreamProgress(); if (std.mem.eql(u8, json_text, "[DONE]")) { traceSseTermination(resolved_model_trace, "done_without_finish", finish_reason_holder); break; } data_event_count += 1;
defer _ = event_arena.reset(.retain_capacity); const root = std.json.parseFromSliceLeaky(std.json.Value, event_arena.allocator(), json_text, .{}) catch |err| { if (err == error.OutOfMemory) return err; traceMalformedSseEvent(json_text.len); return error.InvalidGatewaySseEvent; }; traceParsedSseEvent(alloc, root, json_text.len); if (root != .object) continue; try captureGenerationMetadata( alloc, root, &generation_id, &generation_metadata_invalid, );
const type_val = root.object.get("type") orelse continue; if (type_val != .string) continue; const event_type = type_val.string;
if (content_capture_limit == null) try replay.observe(root, content_buf.items.len);
if (std.mem.eql(u8, event_type, "response-metadata")) { if (root.object.get("timestamp")) |timestamp_value| { if (timestamp_value == .string) { const timestamp = types.parseGatewayTimestamp( timestamp_value.string, ) catch null; if (timestamp) |valid_timestamp| { if (response_timestamp_ms) |existing| { if (existing != valid_timestamp) { response_timestamp_invalid = true; response_timestamp_ms = null; } } else if (!response_timestamp_invalid) { response_timestamp_ms = valid_timestamp; } } else { response_timestamp_invalid = true; response_timestamp_ms = null; } } else { response_timestamp_invalid = true; response_timestamp_ms = null; } } if (root.object.get("modelId")) |model_val| { if (model_val == .string and model_val.string.len > 0 and model_val.string.len <= 128) { if (resolved_model) |existing| { if (!std.mem.eql(u8, existing, model_val.string)) { generation_metadata_invalid = true; } } else { resolved_model = try alloc.dupe(u8, model_val.string); } } else { generation_metadata_invalid = true; } } if (resolved_model_trace) |trace| { if (root.object.get("modelId")) |model_val| { if (model_val == .string and model_val.string.len > 0) { traceResolvedModelOnce(trace.requested_model, "sse.response-metadata.modelId", model_val.string, trace.ctx); } } } } else if (std.mem.eql(u8, event_type, "error")) { provider_failure_cause = provider_failure_cause orelse providerFailureCause(root); try captureProviderFailureDetail(alloc, &provider_failure_detail, root); } else if (std.mem.eql(u8, event_type, "text-delta")) { if (root.object.get("delta")) |delta_val| { if (delta_val == .string and delta_val.string.len > 0) { const retained = if (content_capture_limit) |limit| delta_val.string[0..@min(delta_val.string.len, limit -| content_buf.items.len)] else delta_val.string; try content_buf.appendSlice(alloc, retained); on_content_chunk(callback_ctx, delta_val.string); } } } else if (std.mem.eql(u8, event_type, "reasoning-delta")) { if (on_reasoning_chunk) |callback| { if (root.object.get("delta")) |delta_val| { if (delta_val == .string and delta_val.string.len > 0) { callback(callback_ctx, delta_val.string); } } } } else if (std.mem.eql(u8, event_type, "tool-input-start")) { const id = streamedToolInputId(root, .invalid_start) orelse continue; const name = if (root.object.get("toolName")) |name_value| if (name_value == .string) name_value.string else "" else "";
if (findStreamedToolInput(streamed_tool_inputs.items, id)) |index| { const existing = &streamed_tool_inputs.items[index]; if (existing.state != .open) { traceStreamStateAnomaly(.late_start); } else if (!std.mem.eql(u8, existing.name.items, name)) { traceStreamStateAnomaly(.conflicting_start); } continue; }
var record = try initStreamedToolInput(alloc, id, name); streamed_tool_inputs.append(alloc, record) catch |err| { record.deinit(alloc); return err; }; if (name.len > 0) { if (on_tool_start) |cb| cb(callback_ctx, id, name, null, null); } } else if (std.mem.eql(u8, event_type, "tool-input-delta") or std.mem.eql(u8, event_type, "tool-input-end")) { const is_delta = std.mem.eql(u8, event_type, "tool-input-delta"); const anomaly: StreamStateAnomaly = if (is_delta) .unmatched_or_late_delta else .unmatched_or_duplicate_end; const id = streamedToolInputId(root, anomaly) orelse continue; const index = findStreamedToolInput(streamed_tool_inputs.items, id) orelse { traceStreamStateAnomaly(anomaly); continue; }; const record = &streamed_tool_inputs.items[index]; if (record.state != .open) { traceStreamStateAnomaly(anomaly); continue; } if (is_delta) { const delta_value = root.object.get("delta") orelse continue; if (delta_value != .string) continue; try record.arguments.appendSlice(alloc, delta_value.string); if (on_tool_input_chunk) |callback| callback(callback_ctx, delta_value.string); } else { record.state = .ended; } } else if (std.mem.eql(u8, event_type, "tool-call")) { var acc: SseToolCallAccumulator = .{ .id = .empty, .name = .empty, .arguments = .empty, }; var acc_owned = true; defer if (acc_owned) acc.deinit(alloc);
acc.final_identity = finalToolIdentity(root.object.get("toolCallId")); if (acc.final_identity == .valid) { try acc.id.appendSlice(alloc, root.object.get("toolCallId").?.string); }
var duplicate_final_id = false; if (acc.final_identity == .valid) { for (tool_accumulators.items) |prior| { if (prior.final_identity == .valid and std.mem.eql(u8, prior.id.items, acc.id.items)) { duplicate_final_id = true; break; } } }
var stream_index = if (acc.final_identity == .valid) findStreamedToolInput(streamed_tool_inputs.items, acc.id.items) else null;
const final_name_value = root.object.get("toolName"); if (final_name_value) |name_val| { if (name_val == .string) try acc.name.appendSlice(alloc, name_val.string); } if (acc.name.items.len == 0 and final_name_value == null) { if (stream_index) |index| { try acc.name.appendSlice(alloc, streamed_tool_inputs.items[index].name.items); } }
var final_name_compatible = true; if (stream_index) |index| { if (final_name_value) |name_value| { const record = &streamed_tool_inputs.items[index]; if (name_value != .string or !std.mem.eql(u8, name_value.string, record.name.items)) { final_name_compatible = false; setProviderResultFailure( &provider_result_identity_failure, .conflicting_tool_name, ); } } }
const final_input_state = if (root.object.get("input")) |input_value| blk: { const integrity = try appendSupportedFinalInput( alloc, &acc.arguments, input_value, acc.id.items, acc.name.items, ); acc.argument_integrity = integrity; break :blk if (integrity == .valid) FinalToolInputState.valid else FinalToolInputState.malformed; } else FinalToolInputState.absent; if (stream_index == null and final_input_state == .valid and final_name_compatible and acc.final_identity == .valid and !duplicate_final_id) { stream_index = try findEquivalentEndedStreamedToolInput( alloc, streamed_tool_inputs.items, acc.name.items, acc.arguments.items, ); } if (final_input_state == .absent and final_name_compatible and acc.final_identity == .valid and !duplicate_final_id) { if (stream_index) |index| { const record = &streamed_tool_inputs.items[index]; switch (record.state) { .ended => acc.argument_integrity = try appendSerializedToolArguments( alloc, &acc.arguments, record.arguments.items, acc.id.items, acc.name.items, .streamed_fallback, ), .open => setProviderResultFailure( &provider_result_identity_failure, .incomplete_streamed_input, ), .finalized => setProviderResultFailure( &provider_result_identity_failure, .invalid_tool_input, ), } } else { setProviderResultFailure( &provider_result_identity_failure, .invalid_tool_input, ); } }
if (root.object.get("providerExecuted")) |provider_value| { if (provider_value == .bool) { if (provider_value.bool) acc.provenance = .provider_executed; } else { setProviderResultFailure( &provider_result_identity_failure, .malformed_provider_executed, ); } } else if (expected_provider_tool_name) |expected_name| { if (final_name_compatible and std.mem.eql(u8, acc.name.items, expected_name)) { acc.provenance = .provider_executed; } }
if (stream_index) |index| { const record = &streamed_tool_inputs.items[index]; if (!std.mem.eql(u8, record.id.items, acc.id.items)) { try acc.provisional_id.appendSlice(alloc, record.id.items); } if (final_name_compatible and !record.label_sent and acc.argument_integrity == .valid) { if (on_tool_start) |cb| { record.label_sent = true; cb(callback_ctx, record.id.items, record.name.items, extractFirstJsonStringValue(acc.arguments.items), acc.arguments.items); } } }
try tool_accumulators.append(alloc, acc); acc_owned = false; if (stream_index) |index| { streamed_tool_inputs.items[index].state = .finalized; } } else if (std.mem.eql(u8, event_type, "tool-result")) { const result_identity = finalToolIdentity(root.object.get("toolCallId")); if (result_identity != .valid) { setProviderResultFailure( &provider_result_identity_failure, switch (result_identity) { .absent => .absent, .empty => .empty, .wrong_type => .wrong_type, .valid => unreachable, }, ); continue; }
const result_id = root.object.get("toolCallId").?.string; var matched_index: ?usize = null; var match_count: usize = 0; for (tool_accumulators.items, 0..) |candidate, i| { if (candidate.final_identity == .valid and std.mem.eql(u8, candidate.id.items, result_id)) { match_count += 1; matched_index = i; } } if (match_count != 1) { setProviderResultFailure( &provider_result_identity_failure, if (match_count == 0) .unmatched else .ambiguous, ); continue; }
const acc = &tool_accumulators.items[matched_index.?]; if (acc.provenance != .provider_executed) { setProviderResultFailure( &provider_result_identity_failure, .provenance_contradiction, ); continue; } if (acc.provider_result_state == .final) { setProviderResultFailure( &provider_result_identity_failure, .duplicate_result, ); continue; }
const preliminary = if (root.object.get("preliminary")) |preliminary_value| blk: { if (preliminary_value != .bool) { setProviderResultFailure( &provider_result_identity_failure, .malformed_preliminary, ); continue; } break :blk preliminary_value.bool; } else false;
const result_value = root.object.get("result") orelse { setProviderResultFailure( &provider_result_identity_failure, .missing_result, ); continue; }; if (result_value == .null) { setProviderResultFailure( &provider_result_identity_failure, .missing_result, ); continue; }
const owned_result = try stringifyJsonValueOwned(alloc, result_value); if (acc.provider_result) |old_result| alloc.free(old_result); acc.provider_result = owned_result; acc.provider_result_state = if (preliminary) .preliminary else .final; } else if (std.mem.eql(u8, event_type, "finish")) { provider_failure_cause = provider_failure_cause orelse providerFailureCause(root); const finish_event = parseSseFinishEvent(alloc, root, &provider_failure_detail) catch |err| { switch (err) { error.UnknownProviderFinishReason => { traceSseTermination(resolved_model_trace, "invalid_finish", null); return error.InvalidProviderFinishReason; }, else => return err, } }; finish_reason_holder = finish_event.finish_reason; finish_usage = finish_event.usage; finish_billing = parseSseBilling( alloc, root, if (response_timestamp_invalid) null else response_timestamp_ms, tool_accumulators.items, ) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.InvalidSseBilling => invalid: { debug_trace.logf( "sse", "stream billing ignored reason=invalid_terminal_metadata", .{}, ); break :invalid null; }, }; traceSseTermination(resolved_model_trace, "valid_finish", finish_reason_holder); break; } }
var completion: types.ModelCompletion = .{}; errdefer deinitGatewayCompletion(alloc, &completion);
if (content_buf.items.len > 0) { completion.content = try content_buf.toOwnedSlice(alloc); }
completion.tool_calls = try materializeToolCalls(alloc, tool_accumulators.items); if (finish_reason_holder == .stop or finish_reason_holder == .tool_calls) { completion.provider_state_json = try replay.finish(completion.content orelse "", completion.tool_calls); }
completion.provider_result_identity_failure = provider_result_identity_failure; completion.provider_failure_cause = provider_failure_cause; completion.provider_failure_detail = provider_failure_detail; provider_failure_detail = null; completion.generation_id = generation_id; generation_id = null; completion.billing = finish_billing; finish_billing = null; completion.generation_metadata_invalid = generation_metadata_invalid; completion.finish_reason = finish_reason_holder; completion.usage = finish_usage;
debug_trace.logf( "stream", "sse summary events={d} finish_reason={s}", .{ data_event_count, finish_reason_label(completion.finish_reason), }, );
return completion;}
fn finalToolIdentity(value: ?std.json.Value) types.FinalToolIdentity { const actual = value orelse return .absent; if (actual != .string) return .wrong_type; return if (actual.string.len == 0) .empty else .valid;}
fn readTraceFileForTest(alloc: std.mem.Allocator, path: []const u8) ![]u8 { var file = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), path, .{}); defer file.close(io_mod.getIo()); return io_mod.readFileToEnd(alloc, &file, 65536);}
test "SSE text capture keeps arena capacity proportional to the retained response" { const alloc = std.testing.allocator; const chunk = "x" ** 256; const chunk_count = 2048; const output_bytes = chunk.len * chunk_count; var wire: std.Io.Writer.Allocating = .init(alloc); defer wire.deinit(); for (0..chunk_count) |_| { try wire.writer.writeAll("data: {\"type\":\"text-delta\",\"delta\":\"" ++ chunk ++ "\"}\n\n"); } try wire.writer.writeAll("data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\"}}\n\n"); var arena = std.heap.ArenaAllocator.init(alloc); defer arena.deinit(); var reader = std.Io.Reader.fixed(wire.written()); var cancelled = std.atomic.Value(bool).init(false); const Noop = struct { fn discard(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(arena.allocator(), &reader, undefined, Noop.discard, null, &cancelled); defer deinitGatewayCompletion(arena.allocator(), &completion); try std.testing.expectEqual(output_bytes, completion.content.?.len); try std.testing.expect(std.mem.allEqual(u8, completion.content.?, 'x')); try std.testing.expect(arena.queryCapacity() <= output_bytes * 4);}
test "provider framing assembles Gateway data fields" { for ([_][]const u8{ "data:{\"type\":\"text-delta\",\"delta\":\"EXPECTED_FINAL\"}\n\n", "data: {\"type\":\"text-delta\",\ndata: \"delta\":\"EXPECTED_FINAL\"}\n\n", }) |answer| { const payload = try std.mem.concat(std.testing.allocator, u8, &.{ "data: {\"type\":\"text-delta\",\"delta\":\"CONTROL_PREFIX\\n\"}\n\n", answer, "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\"}}\n\n", }); defer std.testing.allocator.free(payload); var reader = std.Io.Reader.fixed(payload); var cancelled = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancelled); defer deinitGatewayCompletion(std.testing.allocator, &completion); try std.testing.expectEqualStrings("CONTROL_PREFIX\nEXPECTED_FINAL", completion.content.?); }}
test "provider framing rejects malformed Gateway JSON" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const root = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "."); defer alloc.free(root); const path = try std.fs.path.join(alloc, &.{ root, "malformed-sse.log" }); defer alloc.free(path); debug_trace.resetForTest(); defer debug_trace.resetForTest(); try debug_trace.configureForTestWithScopes(alloc, path, "sse"); var reader = std.Io.Reader.fixed("data: {not-json}\n\ndata: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\"}}\n\n"); var cancelled = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; try std.testing.expectError(error.InvalidGatewaySseEvent, consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancelled)); debug_trace.shutdown(); const trace = try readTraceFileForTest(alloc, path); defer alloc.free(trace); try std.testing.expect(std.mem.find(u8, trace, "event type=invalid") != null); try std.testing.expect(std.mem.find(u8, trace, "not-json") == null);}
test "consumeSseStream preserves provider finish_reason" { const payload = "data: {\"type\":\"text-delta\",\"id\":\"t1\",\"delta\":\"Hola\"}\n" ++ "\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"length\",\"raw\":\"length\"},\"usage\":{\"inputTokens\":{\"total\":10},\"outputTokens\":{\"total\":5}}}\n" ++ "\n" ++ "data: [DONE]\n" ++ "\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false);
const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
const completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer if (completion.content) |content| std.testing.allocator.free(content);
try std.testing.expectEqualStrings("Hola", completion.content.?); try std.testing.expectEqual(types.ProviderFinishReason.length, completion.finish_reason.?);}
test "consumeSseStream captures generation identity metadata" { const payload = "data: {\"type\":\"response-metadata\",\"modelId\":\"provider/resolved\"}\n\n" ++ "data: {\"type\":\"text-start\",\"id\":\"t1\",\"providerMetadata\":{\"gateway\":{\"generationId\":\"gen_01ARZ3NDEKTSV4RRFFQ69G5FAV\"}}}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\"},\"usage\":{\"inputTokens\":{\"total\":1},\"outputTokens\":{\"total\":2}}}\n\n"; var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
var completion = try consumeSseStream( std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag, ); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqualStrings( "gen_01ARZ3NDEKTSV4RRFFQ69G5FAV", completion.generation_id.?, ); try std.testing.expect(!completion.generation_metadata_invalid); try std.testing.expect(completion.billing == null);}
test "consumeSseStream traces rejected terminal billing before fallback" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const root = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "."); defer alloc.free(root); const trace_path = try std.fs.path.join( alloc, &.{ root, "invalid-terminal-billing.log" }, ); defer alloc.free(trace_path); debug_trace.resetForTest(); defer debug_trace.resetForTest(); try debug_trace.configureForTestWithScopes(alloc, trace_path, "sse");
const payload = "data: {\"type\":\"response-metadata\",\"modelId\":\"provider/resolved\",\"timestamp\":\"2026-07-29T03:31:07.000Z\"}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\"},\"usage\":{\"inputTokens\":{\"total\":1},\"outputTokens\":{\"total\":2}},\"providerMetadata\":{\"gateway\":{\"cost\":\"invalid\",\"routing\":{\"canonicalSlug\":\"provider/resolved\"}}}}\n\n"; var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream( alloc, &reader, undefined, Noop.chunk, null, &cancel_flag, ); defer deinitGatewayCompletion(alloc, &completion); try std.testing.expect(completion.billing == null);
debug_trace.shutdown(); const trace = try readTraceFileForTest(alloc, trace_path); defer alloc.free(trace); try std.testing.expect(std.mem.find( u8, trace, "stream billing ignored reason=invalid_terminal_metadata", ) != null);}
test "consumeSseStream captures exact terminal billing" { const payload = "data: {\"type\":\"response-metadata\",\"modelId\":\"provider/resolved\",\"timestamp\":\"2026-07-29T03:31:07.000Z\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"call_1\",\"toolName\":\"web_search\",\"input\":{},\"providerExecuted\":true,\"providerMetadata\":{\"gateway\":{\"generationId\":\"gen_01ARZ3NDEKTSV4RRFFQ69G5FAV\"}}}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"call_2\",\"toolName\":\"image_search\",\"input\":{},\"providerExecuted\":true}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"call_3\",\"toolName\":\"read_file\",\"input\":{},\"providerExecuted\":true}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"call_4\",\"toolName\":\"web_search\",\"input\":{}}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\"},\"usage\":{\"inputTokens\":{\"total\":130,\"cacheRead\":20,\"cacheWrite\":10},\"outputTokens\":{\"total\":25,\"reasoning\":5}},\"providerMetadata\":{\"gateway\":{\"generationId\":\"gen_01ARZ3NDEKTSV4RRFFQ69G5FAV\",\"cost\":\"0.0123\",\"routing\":{\"canonicalSlug\":\"provider/canonical\"}}}}\n\n"; var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
var completion = try consumeSseStream( std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag, ); defer deinitGatewayCompletion(std.testing.allocator, &completion);
const billing = completion.billing.?; try std.testing.expectEqualStrings("provider/canonical", billing.model); try std.testing.expectApproxEqAbs(@as(f64, 0.0123), billing.total_cost, 1e-12); try std.testing.expectEqual(@as(u64, 130), billing.input_tokens); try std.testing.expectEqual(@as(u64, 25), billing.output_tokens); try std.testing.expectEqual(@as(u64, 20), billing.cache_read_tokens); try std.testing.expectEqual(@as(u64, 10), billing.cache_write_tokens); try std.testing.expectEqual(@as(u64, 5), billing.reasoning_tokens.?); try std.testing.expectEqual(@as(u64, 2), billing.billable_web_search_calls);}
test "consumeSseStream ignores malformed finish usage totals" { const payload = "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\"},\"usage\":{\"inputTokens\":{\"total\":-1},\"outputTokens\":{\"total\":\"5\"}}}\n" ++ "\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false);
const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(types.ProviderFinishReason.stop, completion.finish_reason.?); try std.testing.expect(completion.usage.input_tokens == null); try std.testing.expect(completion.usage.output_tokens == null);}
test "consumeSseStream preserves provider error detail" { const payload = "data: {\"type\":\"error\",\"error\":{\"code\":\"provider_down\",\"message\":\"wafer route unavailable\"}}\n" ++ "\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"error\",\"raw\":\"provider_error\"},\"usage\":{\"inputTokens\":{\"total\":1},\"outputTokens\":{\"total\":1}}}\n" ++ "\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false);
const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(types.ProviderFinishReason.provider_error, completion.finish_reason.?); try std.testing.expectEqualStrings("provider_down: wafer route unavailable", completion.provider_failure_detail.?); try std.testing.expectEqual(@as(u64, 1), completion.usage.input_tokens.?); try std.testing.expectEqual(@as(u64, 1), completion.usage.output_tokens.?);}
test "consumeSseStream classifies gateway stream timeout by structured code" { const payload = "data: {\"type\":\"error\",\"error\":{\"code\":\"gateway_stream_timeout\",\"message\":\"stream exceeded maximum duration\"}}\n" ++ "\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false);
const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(types.ProviderFailureCause.gateway_stream_timeout, completion.provider_failure_cause.?); try std.testing.expectEqualStrings( "gateway_stream_timeout: stream exceeded maximum duration", completion.provider_failure_detail.?, );}
test "consumeSseStream classifies finish-only gateway stream timeout" { const payload = "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"error\",\"raw\":\"gateway_stream_timeout\"}}\n" ++ "\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false);
const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(types.ProviderFinishReason.provider_error, completion.finish_reason.?); try std.testing.expectEqual(types.ProviderFailureCause.gateway_stream_timeout, completion.provider_failure_cause.?);}
test "providerFailureCause ignores matching prose without the structured code" { const alloc = std.testing.allocator; var parsed = try std.json.parseFromSlice( std.json.Value, alloc, "{\"type\":\"error\",\"error\":{\"code\":\"provider_error\",\"message\":\"gateway_stream_timeout\"}}", .{}, ); defer parsed.deinit();
try std.testing.expectEqual(@as(?types.ProviderFailureCause, null), providerFailureCause(parsed.value));}
test "consumeSseStream assigns a fallback identity to message-only provider errors" { const payload = "data: {\"type\":\"error\",\"message\":\"wafer route unavailable\"}\n" ++ "\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"error\",\"raw\":\"provider_error\"}}\n" ++ "\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false);
const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqualStrings( "provider_error: wafer route unavailable", completion.provider_failure_detail.?, );}
test "captureProviderFailureDetail preserves top-level provider code and message" { const alloc = std.testing.allocator; var parsed = try std.json.parseFromSlice( std.json.Value, alloc, "{\"code\":\"provider_down\",\"message\":\"wafer route unavailable\"}", .{}, ); defer parsed.deinit(); var detail: ?[]u8 = null; defer if (detail) |owned| alloc.free(owned);
try captureProviderFailureDetail(alloc, &detail, parsed.value);
try std.testing.expectEqualStrings("provider_down: wafer route unavailable", detail.?);}
test "captureProviderFailureDetail preserves nested provider type and message" { const alloc = std.testing.allocator; var parsed = try std.json.parseFromSlice( std.json.Value, alloc, "{\"type\":\"error\",\"error\":{\"type\":\"no_available_providers\",\"message\":\"No providers are currently available\"}}", .{}, ); defer parsed.deinit(); var detail: ?[]u8 = null; defer if (detail) |owned| alloc.free(owned);
try captureProviderFailureDetail(alloc, &detail, parsed.value);
try std.testing.expectEqualStrings( "no_available_providers: No providers are currently available", detail.?, );}
test "consumeSseStream returns immediately after valid finish without waiting for done" { const payload = "data: {\"type\":\"text-delta\",\"id\":\"t1\",\"delta\":\"answer\"}\n" ++ "\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\"}}\n" ++ "\n" ++ "data: {\"type\":\"text-delta\",\"id\":\"t2\",\"delta\":\"late\"}\n" ++ "\n" ++ "data: [DONE]\n" ++ "\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false);
const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
const completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer if (completion.content) |content| std.testing.allocator.free(content);
try std.testing.expectEqualStrings("answer", completion.content.?); try std.testing.expectEqual(types.ProviderFinishReason.stop, completion.finish_reason.?);}
test "consumeSseStream rejects malformed provider finish reasons" { const cases = [_][]const u8{ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"\"}}\n\n", "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"future-reason\"}}\n\n", };
const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
for (cases) |payload| { var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); try std.testing.expectError( error.InvalidProviderFinishReason, consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag), ); }}
test "consumeSseStream treats done before finish as framing only" { const payload = "data: {\"type\":\"text-delta\",\"id\":\"t1\",\"delta\":\"partial\"}\n" ++ "\n" ++ "data: [DONE]\n" ++ "\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\"}}\n" ++ "\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false);
const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
const completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer if (completion.content) |content| std.testing.allocator.free(content);
try std.testing.expectEqualStrings("partial", completion.content.?); try std.testing.expect(completion.finish_reason == null);}
test "consumeSseStream propagates read failure before finish" { const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
var reader = std.Io.Reader.failing; var failure_buffer: [1]u8 = undefined; reader.buffer = &failure_buffer; var cancel_flag = std.atomic.Value(bool).init(false);
try std.testing.expectError( error.ReadFailed, consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag), );}
test "consumeSseStream traces every terminal cause" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const root = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "."); defer alloc.free(root); const trace_path = try std.fs.path.join(alloc, &.{ root, "sse-terminal-causes.log" }); defer alloc.free(trace_path);
debug_trace.resetForTest(); defer debug_trace.resetForTest(); try debug_trace.configureForTestWithScopes(alloc, trace_path, "stream");
const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
const valid_finish = "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\"}}\n\n"; var finish_reader = std.Io.Reader.fixed(valid_finish); var active_flag = std.atomic.Value(bool).init(false); const finished = try consumeSseStream(alloc, &finish_reader, undefined, Noop.chunk, null, &active_flag); _ = finished;
const done_without_finish = "data: [DONE]\n\n"; var done_reader = std.Io.Reader.fixed(done_without_finish); _ = try consumeSseStream(alloc, &done_reader, undefined, Noop.chunk, null, &active_flag);
var eof_reader = std.Io.Reader.fixed(""); _ = try consumeSseStream(alloc, &eof_reader, undefined, Noop.chunk, null, &active_flag);
var failing_reader = std.Io.Reader.failing; var failure_buffer: [1]u8 = undefined; failing_reader.buffer = &failure_buffer; try std.testing.expectError( error.ReadFailed, consumeSseStream(alloc, &failing_reader, undefined, Noop.chunk, null, &active_flag), );
var cancelled_flag = std.atomic.Value(bool).init(true); var cancelled_reader = std.Io.Reader.fixed(""); _ = try consumeSseStream(alloc, &cancelled_reader, undefined, Noop.chunk, null, &cancelled_flag);
debug_trace.shutdown(); const trace = try readTraceFileForTest(alloc, trace_path); defer alloc.free(trace);
try std.testing.expect(std.mem.find(u8, trace, "termination cause=valid_finish") != null); try std.testing.expect(std.mem.find(u8, trace, "termination cause=done_without_finish") != null); try std.testing.expect(std.mem.find(u8, trace, "termination cause=eof_without_finish") != null); try std.testing.expect(std.mem.find(u8, trace, "termination cause=read_failure") != null); try std.testing.expect(std.mem.find(u8, trace, "termination cause=cancellation") != null);}
test "Gateway completion retains ordered continuation parts and final metadata" { const alloc = std.testing.allocator; const payload = "data: {\"type\":\"reasoning-start\",\"id\":\"r1\",\"providerMetadata\":{\"openai\":{\"itemId\":\"reason-1\",\"reasoningEncryptedContent\":\"partial\"}}}\n\n" ++ "data: {\"type\":\"reasoning-delta\",\"id\":\"r1\",\"delta\":\"reasoning\"}\n\n" ++ "data: {\"type\":\"reasoning-end\",\"id\":\"r1\",\"providerMetadata\":{\"openai\":{\"reasoningEncryptedContent\":\"complete\"}}}\n\n" ++ "data: {\"type\":\"text-start\",\"id\":\"t1\"}\n\n" ++ "data: {\"type\":\"text-delta\",\"id\":\"t1\",\"delta\":\"visible\"}\n\n" ++ "data: {\"type\":\"text-end\",\"id\":\"t1\"}\n\n" ++ "data: {\"type\":\"tool-input-start\",\"id\":\"call-1\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"call-1\",\"toolName\":\"read_file\",\"input\":{\"path\":\"file\"},\"providerMetadata\":{\"vertex\":{\"thoughtSignature\":\"signature\"}}}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"tool-calls\"}}\n\n"; const Noop = struct { fn discard(_: *anyopaque, _: []const u8) void {} }; var reader = std.Io.Reader.fixed(payload); var cancelled = std.atomic.Value(bool).init(false); var completion = try consumeSseStream(alloc, &reader, undefined, Noop.discard, null, &cancelled); defer deinitGatewayCompletion(alloc, &completion); try std.testing.expectEqualStrings("visible", completion.content.?); const state = completion.provider_state_json orelse return error.TestExpectedProviderReplay; const parsed = try std.json.parseFromSlice(std.json.Value, alloc, state, .{}); defer parsed.deinit(); const parts = parsed.value.array.items; try std.testing.expectEqual(@as(usize, 3), parts.len); try std.testing.expectEqualStrings("reasoning", parts[0].object.get("type").?.string); const metadata = parts[0].object.get("providerOptions").?.object.get("openai").?.object; try std.testing.expectEqualStrings("reason-1", metadata.get("itemId").?.string); try std.testing.expectEqualStrings("complete", metadata.get("reasoningEncryptedContent").?.string); try std.testing.expectEqualStrings("text", parts[1].object.get("type").?.string); try std.testing.expectEqualStrings("tool-call", parts[2].object.get("type").?.string); try std.testing.expectEqualStrings("signature", parts[2].object.get("providerOptions").?.object.get("vertex").?.object.get("thoughtSignature").?.string);}
test "Gateway replay preserves restarted reasoning and text segments" { const alloc = std.testing.allocator; const Fixture = struct { fn event(writer: *std.Io.Writer, value: anytype) !void { try writer.writeAll("data: "); try std.json.Stringify.value(value, .{}, writer); try writer.writeAll("\n\n"); }
fn discard(_: *anyopaque, _: []const u8) void {} }; var distinct_id_replay: ?[]u8 = null; defer if (distinct_id_replay) |replay| alloc.free(replay);
for ([_]bool{ false, true }) |reuse_ids| { var payload: std.Io.Writer.Allocating = .init(alloc); defer payload.deinit(); const labels = [_][]const u8{ "A", "B", "C" }; for (labels) |label| { const id = if (reuse_ids) "0" else label; try Fixture.event(&payload.writer, .{ .type = "reasoning-start", .id = id }); try Fixture.event(&payload.writer, .{ .type = "reasoning-delta", .id = id, .delta = "" }); try Fixture.event(&payload.writer, .{ .type = "reasoning-delta", .id = id, .delta = label }); try Fixture.event(&payload.writer, .{ .type = "reasoning-end", .id = id, .providerMetadata = .{ .anthropic = .{ .signature = label } } }); try Fixture.event(&payload.writer, .{ .type = "text-start", .id = id }); try Fixture.event(&payload.writer, .{ .type = "text-delta", .id = id, .delta = label }); try Fixture.event(&payload.writer, .{ .type = "text-end", .id = id }); try Fixture.event(&payload.writer, .{ .type = "tool-call", .toolCallId = label, .toolName = "exa_search", .input = .{ .query = label }, .providerExecuted = true }); try Fixture.event(&payload.writer, .{ .type = "tool-result", .toolCallId = label, .result = .{ .results = .{} } }); } try Fixture.event(&payload.writer, .{ .type = "finish", .finishReason = .{ .unified = "stop" } }); var reader = std.Io.Reader.fixed(payload.written()); var cancelled = std.atomic.Value(bool).init(false); var completion = try consumeSseStream(alloc, &reader, undefined, Fixture.discard, null, &cancelled); defer deinitGatewayCompletion(alloc, &completion); try std.testing.expectEqualStrings("ABC", completion.content.?); try std.testing.expectEqual(@as(usize, 3), completion.tool_calls.len); const replay = completion.provider_state_json orelse return error.TestExpectedProviderReplay; const parsed = try std.json.parseFromSlice(std.json.Value, alloc, replay, .{}); defer parsed.deinit(); const parts = parsed.value.array.items; try std.testing.expectEqual(@as(usize, 9), parts.len); for (labels, 0..) |label, i| { const reasoning = parts[i * 3].object; try std.testing.expectEqualStrings("reasoning", reasoning.get("type").?.string); try std.testing.expectEqualStrings(label, reasoning.get("text").?.string); try std.testing.expectEqualStrings(label, reasoning.get("providerOptions").?.object.get("anthropic").?.object.get("signature").?.string); const text = parts[i * 3 + 1].object; try std.testing.expectEqualStrings("text", text.get("type").?.string); try std.testing.expectEqual(@as(i64, @intCast(i)), text.get("offset").?.integer); try std.testing.expectEqual(@as(i64, 1), text.get("length").?.integer); try std.testing.expectEqualStrings(label, parts[i * 3 + 2].object.get("toolCallId").?.string); try std.testing.expectEqualStrings(label, completion.tool_calls[i].id); try std.testing.expectEqual(types.ToolExecutionProvenance.provider_executed, completion.tool_calls[i].provenance); } if (distinct_id_replay) |expected| { try std.testing.expectEqualStrings(expected, replay); } else { distinct_id_replay = try alloc.dupe(u8, replay); } }}
test "Gateway replay rejects late deltas without a segment restart" { const alloc = std.testing.allocator; for ([_][]const u8{ "reasoning", "text" }) |kind| { const payload = try std.fmt.allocPrint( alloc, "data: {{\"type\":\"{s}-start\",\"id\":\"0\"}}\n\n" ++ "data: {{\"type\":\"{s}-end\",\"id\":\"0\"}}\n\n" ++ "data: {{\"type\":\"{s}-delta\",\"id\":\"0\",\"delta\":\"\"}}\n\n", .{ kind, kind, kind }, ); defer alloc.free(payload); var reader = std.Io.Reader.fixed(payload); var cancelled = std.atomic.Value(bool).init(false); const Noop = struct { fn discard(_: *anyopaque, _: []const u8) void {} }; try std.testing.expectError(error.InvalidProviderState, consumeSseStream(alloc, &reader, undefined, Noop.discard, null, &cancelled)); }}
test "Gateway replay assembly is allocation-safe and rejects incomplete metadata" { const Check = struct { fn run(alloc: std.mem.Allocator) !void { var replay = GatewayReplayBuilder{ .alloc = alloc }; defer replay.deinit(); for ([_][]const u8{ "{\"type\":\"reasoning-start\",\"id\":\"r\",\"providerMetadata\":{\"anthropic\":{\"redactedData\":\"opaque\"}}}", "{\"type\":\"reasoning-delta\",\"id\":\"r\",\"delta\":\"\",\"providerMetadata\":{\"anthropic\":{\"signature\":\"signed\"}}}", "{\"type\":\"reasoning-end\",\"id\":\"r\"}", "{\"type\":\"reasoning-start\",\"id\":\"r\"}", "{\"type\":\"reasoning-delta\",\"id\":\"r\",\"delta\":\"\",\"providerMetadata\":{\"anthropic\":{\"signature\":\"second\"}}}", "{\"type\":\"reasoning-end\",\"id\":\"r\"}", }) |event| { const parsed = try std.json.parseFromSlice(std.json.Value, alloc, event, .{}); defer parsed.deinit(); try replay.observe(parsed.value, 0); } const output = (replay.finish("", &.{}) catch |err| switch (err) { error.WriteFailed => return error.OutOfMemory, else => return err, }).?; defer alloc.free(output); try std.testing.expect(std.mem.find(u8, output, "opaque") != null); try std.testing.expect(std.mem.find(u8, output, "signed") != null); try std.testing.expect(std.mem.find(u8, output, "second") != null); } }; try std.testing.checkAllAllocationFailures(std.testing.allocator, Check.run, .{}); var replay = GatewayReplayBuilder{ .alloc = std.testing.allocator }; defer replay.deinit(); const incomplete = try std.json.parseFromSlice(std.json.Value, std.testing.allocator, "{\"type\":\"reasoning-start\",\"id\":\"r\",\"providerMetadata\":{\"anthropic\":{\"signature\":\"partial\"}}}", .{}); defer incomplete.deinit(); try replay.observe(incomplete.value, 0); try std.testing.expectError(error.InvalidProviderState, replay.finish("", &.{})); try std.testing.expectError(error.ProviderStateTooLarge, replay.reserve(types.ProviderReplay.max_bytes));}
test "consumeSseStream traces every SSE event with keyless metadata" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const root = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "."); defer alloc.free(root); const trace_path = try std.fs.path.join(alloc, &.{ root, "reasoning-sse.log" }); defer alloc.free(trace_path);
debug_trace.resetForTest(); defer debug_trace.resetForTest(); try debug_trace.configureForTestWithScopes(alloc, trace_path, "sse");
const payload = "data: {\"type\":\"reasoning-start\",\"id\":\"r1\"}\n" ++ "\n" ++ "data: {\"type\":\"reasoning-delta\",\"id\":\"r1\",\"delta\":\"FX_REASONING_SENTINEL\",\"providerMetadata\":{\"anthropic\":{\"signature\":\"FX_PROVIDER_SIGNATURE\"}}}\n" ++ "\n" ++ "data: {\"type\":\"reasoning-end\",\"id\":\"r1\"}\n" ++ "\n" ++ "data: {\"type\":\"reasoning-future\",\"FX_DYNAMIC_KEY_SENTINEL\":\"FX_UNKNOWN_REASONING_SENTINEL\"}\n" ++ "\n" ++ "data: {\"type\":\"text-start\",\"id\":\"t1\"}\n" ++ "\n" ++ "data: {\"type\":\"text-delta\",\"id\":\"t1\",\"delta\":\"answer\"}\n" ++ "\n" ++ "data: {\"type\":\"text-end\",\"id\":\"t1\"}\n" ++ "\n" ++ "data: {\"type\":\"tool-input-start\",\"id\":\"c1\",\"toolName\":\"read_file\"}\n" ++ "\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"c1\",\"delta\":\"{\\\"path\\\":\\\"/tmp/input\\\"}\"}\n" ++ "\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"c1\",\"toolName\":\"read_file\",\"input\":{\"path\":\"/tmp/input\"}}\n" ++ "\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\",\"raw\":\"end_turn\"},\"usage\":{\"inputTokens\":{\"total\":21},\"outputTokens\":{\"total\":8}}}\n" ++ "\n" ++ "data: [DONE]\n" ++ "\n";
const Capture = struct { content_chunks: usize = 0, tool_starts: usize = 0,
fn onContent(ctx: *anyopaque, chunk: []const u8) void { const self: *@This() = @ptrCast(@alignCast(ctx)); if (std.mem.eql(u8, chunk, "answer")) self.content_chunks += 1; }
fn onToolStart(ctx: *anyopaque, _: []const u8, _: []const u8, _: ?[]const u8, _: ?[]const u8) void { const self: *@This() = @ptrCast(@alignCast(ctx)); self.tool_starts += 1; } };
var capture = Capture{}; var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); var completion = try consumeSseStream(alloc, &reader, &capture, Capture.onContent, Capture.onToolStart, &cancel_flag); defer deinitGatewayCompletion(alloc, &completion); debug_trace.shutdown();
try std.testing.expectEqualStrings("answer", completion.content.?); try std.testing.expectEqual(types.ProviderFinishReason.stop, completion.finish_reason.?); try std.testing.expectEqual(@as(?u64, 21), completion.usage.input_tokens); try std.testing.expectEqual(@as(?u64, 8), completion.usage.output_tokens); try std.testing.expectEqual(@as(usize, 1), capture.content_chunks); try std.testing.expect(capture.tool_starts >= 1); try std.testing.expectEqual(@as(usize, 1), completion.tool_calls.len); try std.testing.expectEqualStrings("read_file", completion.tool_calls[0].name);
const trace = try readTraceFileForTest(alloc, trace_path); defer alloc.free(trace);
try std.testing.expectEqual(@as(usize, 11), std.mem.count(u8, trace, "event type=")); try std.testing.expect(std.mem.find(u8, trace, "event type=reasoning-start bytes=") != null); try std.testing.expect(std.mem.find(u8, trace, "event type=reasoning-delta bytes=") != null); try std.testing.expect(std.mem.find(u8, trace, "event type=reasoning-end bytes=") != null); try std.testing.expect(std.mem.find(u8, trace, "event type=unknown bytes=") != null); try std.testing.expect(std.mem.find(u8, trace, "event type=text-delta bytes=") != null); try std.testing.expect(std.mem.find(u8, trace, "preview=<object_fields=") != null); try std.testing.expect(std.mem.find(u8, trace, "reasoning-future") == null); try std.testing.expect(std.mem.find(u8, trace, "FX_DYNAMIC_KEY_SENTINEL") == null); try std.testing.expect(std.mem.find(u8, trace, "FX_REASONING_SENTINEL") == null); try std.testing.expect(std.mem.find(u8, trace, "FX_UNKNOWN_REASONING_SENTINEL") == null); try std.testing.expect(std.mem.find(u8, trace, "FX_PROVIDER_SIGNATURE") == null); try std.testing.expect(std.mem.find(u8, trace, "/tmp/input") == null); try std.testing.expect(std.mem.find(u8, trace, "answer") == null);}
test "consumeSseStream keyless tracing handles oversized CRLF payloads" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const root = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "."); defer alloc.free(root); const trace_path = try std.fs.path.join(alloc, &.{ root, "oversized-reasoning-sse.log" }); defer alloc.free(trace_path);
debug_trace.resetForTest(); defer debug_trace.resetForTest(); try debug_trace.configureForTestWithScopes(alloc, trace_path, "sse");
var payload: std.ArrayList(u8) = .empty; defer payload.deinit(alloc); try payload.appendSlice(alloc, "data: {\"type\":\"reasoning-start\",\"id\":\"r1\"}\r\n\r\ndata: {\"type\":\"reasoning-delta\",\"id\":\"r1\",\"delta\":\"FX_OVERSIZED_REASONING_HEAD_"); const reasoning_bytes = try alloc.alloc(u8, 256 * 1024); defer alloc.free(reasoning_bytes); @memset(reasoning_bytes, 'r'); try payload.appendSlice(alloc, reasoning_bytes); try payload.appendSlice( alloc, "FX_OVERSIZED_REASONING_TAIL\",\"providerMetadata\":{\"anthropic\":{\"signature\":\"FX_OVERSIZED_SIGNATURE\"}}}\r\n\r\n" ++ "data: {\"type\":\"reasoning-end\",\"id\":\"r1\"}\r\n\r\n" ++ "data: {\"type\":\"text-delta\",\"id\":\"t1\",\"delta\":\"answer\"}\r\n\r\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\"},\"usage\":{\"inputTokens\":{\"total\":1},\"outputTokens\":{\"total\":2}}}\r\n\r\n" ++ "data: [DONE]\r\n\r\n", );
const Capture = struct { fn onContent(_: *anyopaque, _: []const u8) void {} }; var capture: u8 = 0; var reader = std.Io.Reader.fixed(payload.items); var cancel_flag = std.atomic.Value(bool).init(false); var completion = try consumeSseStream(alloc, &reader, &capture, Capture.onContent, null, &cancel_flag); defer deinitGatewayCompletion(alloc, &completion); debug_trace.shutdown();
try std.testing.expectEqualStrings("answer", completion.content.?); try std.testing.expectEqual(types.ProviderFinishReason.stop, completion.finish_reason.?); try std.testing.expectEqual(@as(?u64, 1), completion.usage.input_tokens); try std.testing.expectEqual(@as(?u64, 2), completion.usage.output_tokens);
const trace = try readTraceFileForTest(alloc, trace_path); defer alloc.free(trace); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, trace, "event type=reasoning-delta")); try std.testing.expect(std.mem.find(u8, trace, "preview=<object_fields=") != null); try std.testing.expect(std.mem.find(u8, trace, "FX_OVERSIZED_REASONING_HEAD") == null); try std.testing.expect(std.mem.find(u8, trace, "FX_OVERSIZED_REASONING_TAIL") == null); try std.testing.expect(std.mem.find(u8, trace, "FX_OVERSIZED_SIGNATURE") == null); try std.testing.expect(std.mem.find(u8, trace, "answer") == null);}
test "E2E gateway URL override accepts loopback HTTP only" { try std.testing.expectEqualStrings( "https://ai-gateway.vercel.sh/v4/ai/language-model", try selectE2eGatewayUrl(null, "https://ai-gateway.vercel.sh/v4/ai/language-model"), ); try std.testing.expectEqualStrings( "http://127.0.0.1:43123/v4/ai/language-model", try selectE2eGatewayUrl("http://127.0.0.1:43123/v4/ai/language-model", "https://ai-gateway.vercel.sh/v4/ai/language-model"), ); try std.testing.expectEqualStrings( "http://[::1]:43123/v1/models", try selectE2eGatewayUrl("http://[::1]:43123/v1/models", "https://ai-gateway.vercel.sh/v1/models"), ); try std.testing.expectError( error.InvalidE2EGatewayUrl, selectE2eGatewayUrl("https://ai-gateway.vercel.sh/v4/ai/language-model", "https://ai-gateway.vercel.sh/v4/ai/language-model"), ); try std.testing.expectError( error.InvalidE2EGatewayUrl, selectE2eGatewayUrl("http://127.0.0.1:43123@ai-gateway.vercel.sh/v4/ai/language-model", "https://ai-gateway.vercel.sh/v4/ai/language-model"), );}
test "StreamResult.deinit frees owned completion fields" { const alloc = std.testing.allocator; var calls = try alloc.alloc(types.ToolCall, 1); calls[0] = .{ .id = try alloc.dupe(u8, "call_1"), .name = try alloc.dupe(u8, "read_file"), .arguments_json = try alloc.dupe(u8, "{}"), .provider_result = try alloc.dupe(u8, "{\"ok\":true}"), }; var result = StreamResult{ .status = .ok, .completion = .{ .content = try alloc.dupe(u8, "hello"), .finish_reason = .stop, .tool_calls = calls, .provider_failure_detail = try alloc.dupe(u8, "provider detail"), .provider_state_json = try alloc.dupe(u8, "[]"), }, .err_body = try alloc.dupe(u8, "err"), };
result.deinit(alloc); result.deinit(alloc);
try std.testing.expectEqual(std.http.Status.ok, result.status); try std.testing.expect(result.completion.content == null); try std.testing.expect(result.completion.tool_calls.len == 0); try std.testing.expect(result.completion.provider_state_json == null); try std.testing.expect(result.err_body == null);}
test "StreamResult.deinit releases parsed provider replay" { const alloc = std.testing.allocator; const payload = "data: {\"type\":\"reasoning-start\",\"id\":\"r\"}\n\n" ++ "data: {\"type\":\"reasoning-delta\",\"id\":\"r\",\"delta\":\"reasoning\"}\n\n" ++ "data: {\"type\":\"reasoning-end\",\"id\":\"r\"}\n\n" ++ "data: {\"type\":\"text-delta\",\"id\":\"t\",\"delta\":\"answer\"}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\"}}\n\n"; const Noop = struct { fn discard(_: *anyopaque, _: []const u8) void {} }; var reader = std.Io.Reader.fixed(payload); var cancelled = std.atomic.Value(bool).init(false); var result = StreamResult{ .status = .ok, .completion = try consumeSseStream(alloc, &reader, undefined, Noop.discard, null, &cancelled), }; defer result.deinit(alloc); try std.testing.expect(result.completion.provider_state_json != null); try std.testing.expectEqualStrings("answer", result.completion.content.?);}
test "findResolvedModelHeader reads gateway model response header" { const response_bytes = "HTTP/1.1 200 OK\r\n" ++ "content-type: text/event-stream\r\n" ++ "x-vercel-ai-gateway-model: anthropic/claude-opus-4.7 \r\n" ++ "\r\n"; const head = try std.http.Client.Response.Head.parse(response_bytes);
const header = findResolvedModelHeader(head) orelse return error.ExpectedResolvedModelHeader; try std.testing.expectEqualStrings("x-vercel-ai-gateway-model", header.name); try std.testing.expectEqualStrings("anthropic/claude-opus-4.7", header.value);}
test "findResolvedModelHeader ignores unrelated headers" { const response_bytes = "HTTP/1.1 200 OK\r\n" ++ "content-type: text/event-stream\r\n" ++ "x-vercel-id: sfo1::abc\r\n" ++ "\r\n"; const head = try std.http.Client.Response.Head.parse(response_bytes);
try std.testing.expect(findResolvedModelHeader(head) == null);}
test "gateway retry policy covers rate limits and transient server errors" { try std.testing.expect(isRetryableGatewayStatus(.too_many_requests)); try std.testing.expect(isRetryableGatewayStatus(.internal_server_error)); try std.testing.expect(isRetryableGatewayStatus(.bad_gateway)); try std.testing.expect(isRetryableGatewayStatus(.service_unavailable)); try std.testing.expect(isRetryableGatewayStatus(.gateway_timeout)); try std.testing.expect(!isRetryableGatewayStatus(.bad_request)); try std.testing.expect(!isRetryableGatewayStatus(.unauthorized)); try std.testing.expect(!isRetryableGatewayStatus(.forbidden));}
test "gateway retry delay respects bounded retry-after seconds" { const response_bytes = "HTTP/1.1 429 Too Many Requests\r\n" ++ "Retry-After: 2\r\n" ++ "\r\n"; const head = try std.http.Client.Response.Head.parse(response_bytes); try std.testing.expectEqual(@as(u64, 2 * std.time.ns_per_s), retryDelayNsForResponse(head, 0));
const clamped_bytes = "HTTP/1.1 429 Too Many Requests\r\n" ++ "retry-after: 999\r\n" ++ "\r\n"; const clamped = try std.http.Client.Response.Head.parse(clamped_bytes); try std.testing.expectEqual(gateway_retry_after_max_ns, retryDelayNsForResponse(clamped, 0)); try std.testing.expectEqual(@as(?u64, 999), retryAfterSeconds(clamped));
const invalid_bytes = "HTTP/1.1 503 Service Unavailable\r\n" ++ "retry-after: later\r\n" ++ "\r\n"; const invalid = try std.http.Client.Response.Head.parse(invalid_bytes); try std.testing.expectEqual(@as(u64, 2 * gateway_retry_base_delay_ns), retryDelayNsForResponse(invalid, 1));}
// Gateway `tool-call` events may send `input` as parsed JSON instead of a// serialized string. Normalize it so downstream tool dispatch always receives// a JSON argument buffer.test "consumeSseStream serializes tool-call input that arrives as an object" { const payload = "data: {\"type\":\"tool-call\",\"toolCallId\":\"c1\",\"toolName\":\"ask_user_question\",\"input\":{\"questions\":[{\"question\":\"ok?\",\"options\":[{\"label\":\"yes\"},{\"label\":\"no\"}]}]}}\n" ++ "\n" ++ "data: [DONE]\n" ++ "\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false);
const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
const completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer { if (completion.content) |c| std.testing.allocator.free(c); for (completion.tool_calls) |tc| { std.testing.allocator.free(tc.id); std.testing.allocator.free(tc.name); std.testing.allocator.free(tc.arguments_json); if (tc.provisional_id) |id| std.testing.allocator.free(id); if (tc.provider_result) |pr| std.testing.allocator.free(pr); } std.testing.allocator.free(completion.tool_calls); }
try std.testing.expectEqual(@as(usize, 1), completion.tool_calls.len); try std.testing.expect(completion.tool_calls[0].arguments_json.len > 0); // The normalized argument buffer remains parseable JSON. var parsed = try std.json.parseFromSlice(std.json.Value, std.testing.allocator, completion.tool_calls[0].arguments_json, .{}); defer parsed.deinit(); try std.testing.expect(parsed.value == .object); try std.testing.expect(parsed.value.object.get("questions") != null);}
test "consumeSseStream serializes tool-call input that arrives as an array" { const payload = "data: {\"type\":\"tool-call\",\"toolCallId\":\"c1\",\"toolName\":\"dynamic_tool\",\"input\":[1,{\"nested\":true}]}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"tool-calls\"}}\n\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqualStrings("[1,{\"nested\":true}]", completion.tool_calls[0].arguments_json); try std.testing.expectEqual(types.ToolArgumentIntegrity.valid, completion.tool_calls[0].argument_integrity);}
test "consumeSseStream preserves valid serialized final input bytes exactly" { const expected = " {\"first\":1,\"second\":2,\"number\":1e+02} \n"; const payload = "data: {\"type\":\"tool-call\",\"toolCallId\":\"c1\",\"toolName\":\"read_file\",\"input\":\" {\\\"first\\\":1,\\\"second\\\":2,\\\"number\\\":1e+02} \\n\"}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"tool-calls\"}}\n\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqualStrings(expected, completion.tool_calls[0].arguments_json); try std.testing.expectEqual(types.ToolArgumentIntegrity.valid, completion.tool_calls[0].argument_integrity);}
test "consumeSseStream preserves valid serialized scalar roots" { const cases = [_][]const u8{ "null", "true", "42", "\"text\"", };
for (cases) |input| { var event: std.Io.Writer.Allocating = .init(std.testing.allocator); defer event.deinit(); try event.writer.writeAll("{\"type\":\"tool-call\",\"toolCallId\":\"c1\",\"toolName\":\"dynamic_tool\",\"input\":"); try std.json.Stringify.value(input, .{}, &event.writer); try event.writer.writeAll("}"); const payload = try std.fmt.allocPrint( std.testing.allocator, "data: {s}\n\ndata: {{\"type\":\"finish\",\"finishReason\":{{\"unified\":\"tool-calls\"}}}}\n\n", .{event.written()}, ); defer std.testing.allocator.free(payload);
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqualStrings(input, completion.tool_calls[0].arguments_json); try std.testing.expectEqual(types.ToolArgumentIntegrity.valid, completion.tool_calls[0].argument_integrity); }}
test "consumeSseStream replaces malformed trailing or duplicate-key serialized final input with safe JSON" { const Case = struct { input: []const u8, }; const cases = [_]Case{ .{ .input = "{]FX_FINAL_MALFORMED_SENTINEL" }, .{ .input = "{} FX_FINAL_TRAILING_SENTINEL" }, .{ .input = "{\"depth\":1,\"depth\":2}" }, };
for (cases) |case| { var event: std.Io.Writer.Allocating = .init(std.testing.allocator); defer event.deinit(); try event.writer.writeAll("{\"type\":\"tool-call\",\"toolCallId\":\"c1\",\"toolName\":\"ask_user_question\",\"input\":"); try std.json.Stringify.value(case.input, .{}, &event.writer); try event.writer.writeAll("}");
const payload = try std.fmt.allocPrint( std.testing.allocator, "data: {s}\n\ndata: {{\"type\":\"finish\",\"finishReason\":{{\"unified\":\"tool-calls\"}}}}\n\n", .{event.written()}, ); defer std.testing.allocator.free(payload);
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqualStrings("{}", completion.tool_calls[0].arguments_json); try std.testing.expectEqual(types.ToolArgumentIntegrity.malformed_json, completion.tool_calls[0].argument_integrity); }}
test "consumeSseStream replaces duplicate-key exact-id ended fallback with safe JSON" { const payload = "data: {\"type\":\"tool-input-start\",\"id\":\"c1\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"c1\",\"delta\":\" \\n{\\\"number\\\":1e+02,\\\"duplicate\\\":1,\\\"duplicate\\\":2}\\t\"}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"c1\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"c1\"}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"tool-calls\"}}\n\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqualStrings("{}", completion.tool_calls[0].arguments_json); try std.testing.expectEqual(types.ToolArgumentIntegrity.malformed_json, completion.tool_calls[0].argument_integrity);}
test "consumeSseStream absent outer input uses exact-id ended fallback for compatible names" { const final_names = [_][]const u8{ "", ",\"toolName\":\"read_file\"", };
for (final_names) |final_name| { const payload = try std.fmt.allocPrint( std.testing.allocator, "data: {{\"type\":\"tool-input-start\",\"id\":\"c1\",\"toolName\":\"read_file\"}}\n\n" ++ "data: {{\"type\":\"tool-input-delta\",\"id\":\"c1\",\"delta\":\"{{\\\"path\\\":\\\"README.md\\\"}}\"}}\n\n" ++ "data: {{\"type\":\"tool-input-end\",\"id\":\"c1\"}}\n\n" ++ "data: {{\"type\":\"tool-call\",\"toolCallId\":\"c1\"{s}}}\n\n" ++ "data: {{\"type\":\"finish\",\"finishReason\":{{\"unified\":\"tool-calls\"}}}}\n\n", .{final_name}, ); defer std.testing.allocator.free(payload);
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqualStrings("{\"path\":\"README.md\"}", completion.tool_calls[0].arguments_json); try std.testing.expectEqual(types.ToolArgumentIntegrity.valid, completion.tool_calls[0].argument_integrity); try std.testing.expectEqual( types.AuthoritativeToolAdmission.admitted, types.authoritativeToolAdmission(completion), ); }}
test "consumeSseStream present unsupported final input does not use streamed fallback" { const final_inputs = [_][]const u8{ "null", "false", "7", };
for (final_inputs) |final_input| { const payload = try std.fmt.allocPrint( std.testing.allocator, "data: {{\"type\":\"tool-input-start\",\"id\":\"c1\",\"toolName\":\"read_file\"}}\n\n" ++ "data: {{\"type\":\"tool-input-delta\",\"id\":\"c1\",\"delta\":\"{{\\\"path\\\":\\\"SHOULD_NOT_SURVIVE\\\"}}\"}}\n\n" ++ "data: {{\"type\":\"tool-input-end\",\"id\":\"c1\"}}\n\n" ++ "data: {{\"type\":\"tool-call\",\"toolCallId\":\"c1\",\"input\":{s}}}\n\n" ++ "data: {{\"type\":\"finish\",\"finishReason\":{{\"unified\":\"tool-calls\"}}}}\n\n", .{final_input}, ); defer std.testing.allocator.free(payload);
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqualStrings("{}", completion.tool_calls[0].arguments_json); try std.testing.expectEqual(types.ToolArgumentIntegrity.malformed_json, completion.tool_calls[0].argument_integrity); }}
test "consumeSseStream rejects absent outer input without exact ended fallback" { const Case = struct { streamed_events: []const u8, call_id: []const u8, expected: types.ProviderResultIdentityFailure, }; const cases = [_]Case{ .{ .streamed_events = "", .call_id = "c1", .expected = .invalid_tool_input, }, .{ .streamed_events = "data: {\"type\":\"tool-input-start\",\"id\":\"c1\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"c1\",\"delta\":\"{\\\"path\\\":\\\"partial\"}\n\n", .call_id = "c1", .expected = .incomplete_streamed_input, }, .{ .streamed_events = "data: {\"type\":\"tool-input-start\",\"id\":\"other\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"other\",\"delta\":\"{\\\"path\\\":\\\"README.md\\\"}\"}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"other\"}\n\n", .call_id = "c1", .expected = .invalid_tool_input, }, };
for (cases) |case| { const payload = try std.fmt.allocPrint( std.testing.allocator, "{s}data: {{\"type\":\"tool-call\",\"toolCallId\":\"{s}\"}}\n\n" ++ "data: {{\"type\":\"finish\",\"finishReason\":{{\"unified\":\"tool-calls\"}}}}\n\n", .{ case.streamed_events, case.call_id }, ); defer std.testing.allocator.free(payload);
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual( types.AuthoritativeToolAdmission{ .reject_malformed_provider_result = case.expected }, types.authoritativeToolAdmission(completion), ); }}
test "consumeSseStream replaces malformed exact-id ended fallback with safe JSON" { const payload = "data: {\"type\":\"tool-input-start\",\"id\":\"c1\",\"toolName\":\"ask_user_question\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"c1\",\"delta\":\"{]FX_FALLBACK_MALFORMED_SENTINEL\"}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"c1\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"c1\"}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"tool-calls\"}}\n\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqualStrings("{}", completion.tool_calls[0].arguments_json); try std.testing.expectEqual(types.ToolArgumentIntegrity.malformed_json, completion.tool_calls[0].argument_integrity);}
test "consumeSseStream does not publish labels from malformed streamed arguments" { const sentinel = "FX_MALFORMED_LABEL_SENTINEL"; const payload = "data: {\"type\":\"tool-input-start\",\"id\":\"c1\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"c1\",\"delta\":\"{\\\"path\\\":\\\"FX_MALFORMED_LABEL_SENTINEL\\\",\"}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"c1\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"c1\"}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"tool-calls\"}}\n\n";
const Capture = struct { labels: usize = 0, leaked_sentinel: bool = false,
fn onContent(_: *anyopaque, _: []const u8) void {}
fn onToolStart(ctx: *anyopaque, _: []const u8, _: []const u8, label: ?[]const u8, _: ?[]const u8) void { const self: *@This() = @ptrCast(@alignCast(ctx)); const value = label orelse return; self.labels += 1; if (std.mem.find(u8, value, sentinel) != null) self.leaked_sentinel = true; } };
var capture = Capture{}; var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); var completion = try consumeSseStream( std.testing.allocator, &reader, &capture, Capture.onContent, Capture.onToolStart, &cancel_flag, ); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(@as(usize, 0), capture.labels); try std.testing.expect(!capture.leaked_sentinel); try std.testing.expectEqualStrings("{}", completion.tool_calls[0].arguments_json); try std.testing.expectEqual(types.ToolArgumentIntegrity.malformed_json, completion.tool_calls[0].argument_integrity);}
test "consumeSseStream traces malformed argument metadata without source bytes" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const root = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "."); defer alloc.free(root); const trace_path = try std.fs.path.join(alloc, &.{ root, "argument-integrity.log" }); defer alloc.free(trace_path);
debug_trace.resetForTest(); defer debug_trace.resetForTest(); try debug_trace.configureForTestWithScopes(alloc, trace_path, "sse");
const sentinel = "{]FX_ARGUMENT_PRIVACY_SENTINEL"; var event: std.Io.Writer.Allocating = .init(alloc); defer event.deinit(); try event.writer.writeAll("{\"type\":\"tool-call\",\"toolCallId\":\"c1\",\"toolName\":\"ask_user_question\",\"input\":"); try std.json.Stringify.value(sentinel, .{}, &event.writer); try event.writer.writeAll("}"); const payload = try std.fmt.allocPrint( alloc, "data: {s}\n\ndata: {{\"type\":\"finish\",\"finishReason\":{{\"unified\":\"tool-calls\"}}}}\n\n", .{event.written()}, ); defer alloc.free(payload);
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(alloc, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(alloc, &completion); debug_trace.shutdown();
const trace = try readTraceFileForTest(alloc, trace_path); defer alloc.free(trace); try std.testing.expect(std.mem.find(u8, trace, "event=tool_argument_integrity") != null); try std.testing.expect(std.mem.find(u8, trace, "source=final_string") != null); try std.testing.expect(std.mem.find(u8, trace, "failure=malformed_json") != null); try std.testing.expect(std.mem.find(u8, trace, sentinel) == null);}
test "consumeSseStream malformed final identity borrows no streamed state" { const payload = "data: {\"type\":\"tool-input-start\",\"id\":\"provisional_1\",\"toolName\":\"read_file\"}\n" ++ "\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"provisional_1\",\"delta\":\"{\\\"path\\\":\\\"STREAMED_SENTINEL\\\"}\"}\n" ++ "\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"provisional_1\"}\n" ++ "\n" ++ "data: {\"type\":\"tool-call\"}\n" ++ "\n" ++ "data: [DONE]\n" ++ "\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false);
const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(@as(usize, 1), completion.tool_calls.len); try std.testing.expectEqual(.absent, completion.tool_calls[0].final_identity); try std.testing.expectEqualStrings("", completion.tool_calls[0].id); try std.testing.expectEqualStrings("", completion.tool_calls[0].name); try std.testing.expectEqualStrings("", completion.tool_calls[0].arguments_json); try std.testing.expect(completion.tool_calls[0].provisional_id == null);}
test "consumeSseStream preserves final identity states without recency aliases" { const Case = struct { final_field: []const u8, expected: types.FinalToolIdentity, expected_id: []const u8, }; const cases = [_]Case{ .{ .final_field = "", .expected = .absent, .expected_id = "" }, .{ .final_field = ",\"toolCallId\":\"\"", .expected = .empty, .expected_id = "" }, .{ .final_field = ",\"toolCallId\":7", .expected = .wrong_type, .expected_id = "" }, .{ .final_field = ",\"toolCallId\":\"final_1\"", .expected = .valid, .expected_id = "final_1" }, };
for (cases) |case| { const payload = try std.fmt.allocPrint( std.testing.allocator, "data: {{\"type\":\"tool-input-start\",\"id\":\"provisional_1\",\"toolName\":\"read_file\"}}\n\n" ++ "data: {{\"type\":\"tool-call\",\"toolName\":\"read_file\",\"input\":{{\"path\":\"README.md\"}}{s}}}\n\n" ++ "data: [DONE]\n\n", .{case.final_field}, ); defer std.testing.allocator.free(payload);
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(case.expected, completion.tool_calls[0].final_identity); try std.testing.expectEqualStrings(case.expected_id, completion.tool_calls[0].id); try std.testing.expect(completion.tool_calls[0].provisional_id == null); }}
test "consumeSseStream reconciles a changed final id with equivalent streamed input" { const payload = "data: {\"type\":\"reasoning-start\",\"id\":\"r\"}\n\n" ++ "data: {\"type\":\"reasoning-end\",\"id\":\"r\"}\n\n" ++ "data: {\"type\":\"tool-input-start\",\"id\":\"provisional_read\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"provisional_read\",\"delta\":\"{\\\"path\\\":\\\"README.md\\\"}\"}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"provisional_read\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"final_read\",\"toolName\":\"read_file\",\"input\":{\"path\":\"README.md\"}}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"tool-calls\"}}\n\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream( std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag, ); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(@as(usize, 1), completion.tool_calls.len); try std.testing.expectEqualStrings("final_read", completion.tool_calls[0].id); try std.testing.expectEqualStrings( "provisional_read", completion.tool_calls[0].provisional_id orelse return error.TestUnexpectedResult, ); try std.testing.expectEqualStrings("read_file", completion.tool_calls[0].name); try std.testing.expectEqualStrings("{\"path\":\"README.md\"}", completion.tool_calls[0].arguments_json); try std.testing.expect(completion.provider_result_identity_failure == null); try std.testing.expect(std.mem.find(u8, completion.provider_state_json.?, "\"toolCallId\":\"final_read\"") != null); try std.testing.expect(std.mem.find(u8, completion.provider_state_json.?, "provisional_read") == null);}
test "consumeSseStream reconciles interleaved changed ids by structural input" { const payload = "data: {\"type\":\"tool-input-start\",\"id\":\"provisional_a\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"provisional_a\",\"delta\":\"{\\\"path\\\":\\\"a.txt\\\",\\\"line_end\\\":2}\"}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"provisional_a\"}\n\n" ++ "data: {\"type\":\"tool-input-start\",\"id\":\"provisional_b\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"provisional_b\",\"delta\":\"{\\\"path\\\":\\\"b.txt\\\",\\\"line_end\\\":4}\"}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"provisional_b\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"final_b\",\"toolName\":\"read_file\",\"input\":{\"line_end\":4,\"path\":\"b.txt\"}}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"final_a\",\"toolName\":\"read_file\",\"input\":{\"line_end\":2,\"path\":\"a.txt\"}}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"tool-calls\"}}\n\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream( std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag, ); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(@as(usize, 2), completion.tool_calls.len); try std.testing.expectEqualStrings("final_b", completion.tool_calls[0].id); try std.testing.expectEqualStrings( "provisional_b", completion.tool_calls[0].provisional_id orelse return error.TestUnexpectedResult, ); try std.testing.expectEqualStrings("final_a", completion.tool_calls[1].id); try std.testing.expectEqualStrings( "provisional_a", completion.tool_calls[1].provisional_id orelse return error.TestUnexpectedResult, ); try std.testing.expect(completion.provider_result_identity_failure == null);}
test "consumeSseStream does not alias changed ids with different input" { const payload = "data: {\"type\":\"tool-input-start\",\"id\":\"provisional_read\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"provisional_read\",\"delta\":\"{\\\"path\\\":\\\"a.txt\\\"}\"}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"provisional_read\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"final_read\",\"toolName\":\"read_file\",\"input\":{\"path\":\"b.txt\"}}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"tool-calls\"}}\n\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream( std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag, ); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(@as(usize, 1), completion.tool_calls.len); try std.testing.expectEqualStrings("final_read", completion.tool_calls[0].id); try std.testing.expect(completion.tool_calls[0].provisional_id == null); try std.testing.expectEqualStrings("{\"path\":\"b.txt\"}", completion.tool_calls[0].arguments_json); try std.testing.expect(completion.provider_result_identity_failure == null);}
test "consumeSseStream isolates interleaved streamed inputs by exact event id" { const payload = "data: {\"type\":\"tool-input-start\",\"id\":\"A\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"A\",\"delta\":\"{\\\"path\\\":\"}\n\n" ++ "data: {\"type\":\"tool-input-start\",\"id\":\"B\",\"toolName\":\"grep_files\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"B\",\"delta\":\"{\\\"pattern\\\":\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"A\",\"delta\":\"\\\"alpha-A.txt\\\"}\"}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"A\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"A\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"B\",\"delta\":\"\\\"needle-B\\\"}\"}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"B\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"B\"}\n\n" ++ "data: [DONE]\n\n";
const Capture = struct { starts: usize = 0, labels: usize = 0,
fn onContent(_: *anyopaque, _: []const u8) void {}
fn onToolStart(ctx: *anyopaque, _: []const u8, _: []const u8, label: ?[]const u8, _: ?[]const u8) void { const self: *@This() = @ptrCast(@alignCast(ctx)); if (label == null) { self.starts += 1; } else { self.labels += 1; } } };
var capture = Capture{}; var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); var completion = try consumeSseStream( std.testing.allocator, &reader, &capture, Capture.onContent, Capture.onToolStart, &cancel_flag, ); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(@as(usize, 2), capture.starts); try std.testing.expectEqual(@as(usize, 2), capture.labels); try std.testing.expectEqual(@as(usize, 2), completion.tool_calls.len); try std.testing.expectEqualStrings("A", completion.tool_calls[0].id); try std.testing.expectEqualStrings("read_file", completion.tool_calls[0].name); try std.testing.expectEqualStrings("{\"path\":\"alpha-A.txt\"}", completion.tool_calls[0].arguments_json); try std.testing.expect(completion.tool_calls[0].provisional_id == null); try std.testing.expectEqualStrings("B", completion.tool_calls[1].id); try std.testing.expectEqualStrings("grep_files", completion.tool_calls[1].name); try std.testing.expectEqualStrings("{\"pattern\":\"needle-B\"}", completion.tool_calls[1].arguments_json); try std.testing.expect(completion.tool_calls[1].provisional_id == null); try std.testing.expect(completion.provider_result_identity_failure == null);}
test "consumeSseStream observes complete skill arguments before finish even without a label hint" { const Capture = struct { expected_json: []const u8, expected_hint: ?[]const u8, starts: usize = 0, updates: usize = 0, matched: bool = true,
fn content(_: *anyopaque, _: []const u8) void {} fn toolStart(raw: *anyopaque, id: []const u8, name: []const u8, hint: ?[]const u8, arguments_json: ?[]const u8) void { const self: *@This() = @ptrCast(@alignCast(raw)); self.matched = self.matched and std.mem.eql(u8, id, "skill_1") and std.mem.eql(u8, name, "skill"); if (arguments_json) |json| { self.updates += 1; self.matched = self.matched and std.mem.eql(u8, self.expected_json, json); self.matched = self.matched and if (self.expected_hint) |expected| if (hint) |actual| std.mem.eql(u8, expected, actual) else false else hint == null; } else { self.starts += 1; self.matched = self.matched and hint == null; } } }; const cases = [_]struct { json: []const u8, hint: ?[]const u8 }{ .{ .json = "{\"location\":\"skill:opaque/location\",\"resource\":\"references/types.md\"}", .hint = "skill:opaque/location" }, .{ .json = "{\"resource\":\"references/types.md\",\"location\":\"skill:opaque/location\"}", .hint = "references/types.md" }, .{ .json = "{\"offset\":0,\"location\":\"skill:opaque/location\",\"resource\":\"references/types.md\"}", .hint = null }, }; const alloc = std.testing.allocator; for (cases) |case| { const payload = try std.fmt.allocPrint( alloc, "data: {{\"type\":\"tool-input-start\",\"id\":\"skill_1\",\"toolName\":\"skill\"}}\n\n" ++ "data: {{\"type\":\"tool-input-end\",\"id\":\"skill_1\"}}\n\n" ++ "data: {{\"type\":\"tool-call\",\"toolCallId\":\"skill_1\",\"toolName\":\"skill\",\"input\":{s}}}\n\n", .{case.json}, ); defer alloc.free(payload); var reader = std.Io.Reader.fixed(payload); var cancelled = std.atomic.Value(bool).init(false); var capture = Capture{ .expected_json = case.json, .expected_hint = case.hint }; var completion = try consumeSseStream(alloc, &reader, &capture, Capture.content, Capture.toolStart, &cancelled); defer deinitGatewayCompletion(alloc, &completion); try std.testing.expect(capture.matched); try std.testing.expectEqual(@as(usize, 1), capture.starts); try std.testing.expectEqual(@as(usize, 1), capture.updates); try std.testing.expect(completion.finish_reason == null); try std.testing.expectEqualStrings(case.json, completion.tool_calls[0].arguments_json); }}
test "consumeSseStream ignores conflicting and late stream events without mutation" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const root = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "."); defer alloc.free(root); const trace_path = try std.fs.path.join(alloc, &.{ root, "stream-state-anomalies.log" }); defer alloc.free(trace_path);
debug_trace.resetForTest(); defer debug_trace.resetForTest(); try debug_trace.configureForTestWithScopes(alloc, trace_path, "sse");
const payload = "data: {\"type\":\"tool-input-start\",\"id\":\"X\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-start\",\"id\":\"X\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-start\",\"id\":\"X\",\"toolName\":\"grep_files\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"X\",\"delta\":\"{\\\"path\\\":\\\"stable.txt\\\"}\"}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"X\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"X\",\"delta\":\"LATE_PREFIX_SENTINEL\"}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"X\"}\n\n" ++ "data: {\"type\":\"tool-input-start\",\"id\":\"X\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"missing\",\"delta\":\"UNMATCHED_SENTINEL\"}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"missing\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"X\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"X\",\"delta\":\"FINALIZED_SENTINEL\"}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"X\"}\n\n" ++ "data: {\"type\":\"tool-input-start\",\"id\":\"X\",\"toolName\":\"read_file\"}\n\n" ++ "data: [DONE]\n\n";
const Capture = struct { starts: usize = 0, labels: usize = 0,
fn onContent(_: *anyopaque, _: []const u8) void {}
fn onToolStart(ctx: *anyopaque, _: []const u8, _: []const u8, label: ?[]const u8, _: ?[]const u8) void { const self: *@This() = @ptrCast(@alignCast(ctx)); if (label == null) { self.starts += 1; } else { self.labels += 1; } } };
var capture = Capture{}; var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); var completion = try consumeSseStream( alloc, &reader, &capture, Capture.onContent, Capture.onToolStart, &cancel_flag, ); defer deinitGatewayCompletion(alloc, &completion); debug_trace.shutdown();
try std.testing.expectEqual(@as(usize, 1), capture.starts); try std.testing.expectEqual(@as(usize, 1), capture.labels); try std.testing.expectEqual(@as(usize, 1), completion.tool_calls.len); try std.testing.expectEqualStrings("{\"path\":\"stable.txt\"}", completion.tool_calls[0].arguments_json);
const trace = try readTraceFileForTest(alloc, trace_path); defer alloc.free(trace); inline for (.{ "reason=conflicting_start", "reason=late_start", "reason=unmatched_or_late_delta", "reason=unmatched_or_duplicate_end", }) |reason| { try std.testing.expect(std.mem.find(u8, trace, reason) != null); } try std.testing.expect(std.mem.find(u8, trace, "LATE_PREFIX_SENTINEL") == null); try std.testing.expect(std.mem.find(u8, trace, "UNMATCHED_SENTINEL") == null); try std.testing.expect(std.mem.find(u8, trace, "FINALIZED_SENTINEL") == null);}
test "consumeSseStream accepts authoritative final input before end" { const payload = "data: {\"type\":\"tool-input-start\",\"id\":\"A\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"A\",\"delta\":\"PARTIAL_SENTINEL\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"A\",\"input\":{\"path\":\"authoritative.txt\"}}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"A\",\"delta\":\"LATE_SENTINEL\"}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"A\"}\n\n" ++ "data: [DONE]\n\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(@as(usize, 1), completion.tool_calls.len); try std.testing.expectEqualStrings("read_file", completion.tool_calls[0].name); try std.testing.expectEqualStrings("{\"path\":\"authoritative.txt\"}", completion.tool_calls[0].arguments_json); try std.testing.expect(completion.provider_result_identity_failure == null);}
test "consumeSseStream rejects a final tool name that conflicts with streamed identity" { const final_inputs = [_][]const u8{ "", ",\"input\":{\"path\":\"authoritative.txt\"}", };
for (final_inputs) |final_input| { const payload = try std.fmt.allocPrint( std.testing.allocator, "data: {{\"type\":\"tool-input-start\",\"id\":\"A\",\"toolName\":\"read_file\"}}\n\n" ++ "data: {{\"type\":\"tool-input-delta\",\"id\":\"A\",\"delta\":\"{{\\\"path\\\":\\\"victim.txt\\\"}}\"}}\n\n" ++ "data: {{\"type\":\"tool-input-end\",\"id\":\"A\"}}\n\n" ++ "data: {{\"type\":\"tool-call\",\"toolCallId\":\"A\",\"toolName\":\"edit_file\"{s}}}\n\n" ++ "data: [DONE]\n\n", .{final_input}, ); defer std.testing.allocator.free(payload);
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
switch (types.authoritativeToolAdmission(completion)) { .admitted => return error.TestUnexpectedResult, else => {}, } try std.testing.expect(std.mem.find(u8, completion.tool_calls[0].arguments_json, "victim.txt") == null); }}
test "consumeSseStream rejects fallback from an open stream" { const payload = "data: {\"type\":\"tool-input-start\",\"id\":\"A\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"A\",\"delta\":\"{\\\"path\\\":\\\"partial\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"A\"}\n\n" ++ "data: [DONE]\n\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqualStrings("", completion.tool_calls[0].arguments_json); try std.testing.expectEqual( types.AuthoritativeToolAdmission{ .reject_malformed_provider_result = .incomplete_streamed_input }, types.authoritativeToolAdmission(completion), );}
test "consumeSseStream keeps unmatched valid finals independent and alias-free" { const payload = "data: {\"type\":\"tool-input-start\",\"id\":\"streamed\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"final\",\"toolName\":\"grep_files\",\"input\":{\"pattern\":\"needle\"}}\n\n" ++ "data: [DONE]\n\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqualStrings("final", completion.tool_calls[0].id); try std.testing.expectEqualStrings("grep_files", completion.tool_calls[0].name); try std.testing.expectEqualStrings("{\"pattern\":\"needle\"}", completion.tool_calls[0].arguments_json); try std.testing.expect(completion.tool_calls[0].provisional_id == null); try std.testing.expect(completion.provider_result_identity_failure == null);}
test "consumeSseStream preserves duplicate final ids for duplicate admission" { const payload = "data: {\"type\":\"tool-call\",\"toolCallId\":\"duplicate\",\"toolName\":\"read_file\",\"input\":{\"path\":\"a\"}}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"duplicate\",\"toolName\":\"read_file\",\"input\":{\"path\":\"b\"}}\n\n" ++ "data: [DONE]\n\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(@as(usize, 2), completion.tool_calls.len); try std.testing.expect(completion.provider_result_identity_failure == null); try std.testing.expectEqual( types.AuthoritativeToolAdmission.reject_duplicate_identity, types.authoritativeToolAdmission(completion), );}
test "consumeSseStream duplicate final ids do not reuse finalized stream fallback" { const payload = "data: {\"type\":\"tool-input-start\",\"id\":\"duplicate\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"duplicate\",\"delta\":\"{\\\"path\\\":\\\"a\\\"}\"}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"duplicate\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"duplicate\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"duplicate\"}\n\n" ++ "data: [DONE]\n\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(@as(usize, 2), completion.tool_calls.len); try std.testing.expectEqualStrings("{\"path\":\"a\"}", completion.tool_calls[0].arguments_json); try std.testing.expectEqualStrings("", completion.tool_calls[1].arguments_json); try std.testing.expect(completion.provider_result_identity_failure == null); try std.testing.expectEqual( types.AuthoritativeToolAdmission.reject_duplicate_identity, types.authoritativeToolAdmission(completion), );}
test "consumeSseStream records malformed provider result correlation identity" { const Case = struct { result_field: []const u8, expected: types.ProviderResultIdentityFailure, }; const cases = [_]Case{ .{ .result_field = "", .expected = .absent }, .{ .result_field = ",\"toolCallId\":\"\"", .expected = .empty }, .{ .result_field = ",\"toolCallId\":7", .expected = .wrong_type }, .{ .result_field = ",\"toolCallId\":\"other\"", .expected = .unmatched }, };
for (cases) |case| { const payload = try std.fmt.allocPrint( std.testing.allocator, "data: {{\"type\":\"tool-call\",\"toolCallId\":\"call_1\",\"toolName\":\"parallel_search\",\"input\":{{}},\"providerExecuted\":true}}\n\n" ++ "data: {{\"type\":\"tool-result\",\"result\":{{\"results\":[]}}{s}}}\n\n" ++ "data: [DONE]\n\n", .{case.result_field}, ); defer std.testing.allocator.free(payload);
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(case.expected, completion.provider_result_identity_failure.?); }}
test "consumeSseStream rejects ambiguous provider result correlation" { const payload = "data: {\"type\":\"tool-call\",\"toolCallId\":\"duplicate_1\",\"toolName\":\"parallel_search\",\"input\":{},\"providerExecuted\":true}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"duplicate_1\",\"toolName\":\"parallel_search\",\"input\":{},\"providerExecuted\":true}\n\n" ++ "data: {\"type\":\"tool-result\",\"toolCallId\":\"duplicate_1\",\"result\":{\"results\":[]}}\n\n" ++ "data: [DONE]\n\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(@as(usize, 2), completion.tool_calls.len); try std.testing.expectEqual( types.ProviderResultIdentityFailure.ambiguous, completion.provider_result_identity_failure.?, ); switch (types.authoritativeToolAdmission(completion)) { .reject_malformed_provider_result => |failure| { try std.testing.expectEqual(types.ProviderResultIdentityFailure.ambiguous, failure); }, else => return error.TestUnexpectedResult, }}
test "consumeSseStream preserves missing provider result for admission" { const payload = "data: {\"type\":\"tool-call\",\"toolCallId\":\"call_1\",\"toolName\":\"parallel_search\",\"input\":{},\"providerExecuted\":true}\n" ++ "\n" ++ "data: {\"type\":\"tool-result\",\"toolCallId\":\"call_1\"}\n" ++ "\n" ++ "data: [DONE]\n" ++ "\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(@as(usize, 1), completion.tool_calls.len); try std.testing.expectEqual(.provider_executed, completion.tool_calls[0].provenance); try std.testing.expectEqual(@as(?[]const u8, null), completion.tool_calls[0].provider_result); try std.testing.expectEqual( types.AuthoritativeToolAdmission{ .reject_malformed_provider_result = .missing_result }, types.authoritativeToolAdmission(completion), );}
test "consumeSseStream takes provider execution provenance from the final call" { const payload = "data: {\"type\":\"tool-call\",\"toolCallId\":\"call_1\",\"toolName\":\"parallel_search\",\"input\":{},\"providerExecuted\":true}\n\n" ++ "data: {\"type\":\"tool-result\",\"toolCallId\":\"call_1\",\"result\":{\"results\":[{\"title\":\"ok\"}]}}\n\n" ++ "data: [DONE]\n\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(.provider_executed, completion.tool_calls[0].provenance); try std.testing.expectEqualStrings( "{\"results\":[{\"title\":\"ok\"}]}", completion.tool_calls[0].provider_result.?, ); try std.testing.expectEqual( types.AuthoritativeToolAdmission.admitted, types.authoritativeToolAdmission(completion), );}
test "consumeSseStream rejects malformed final-call provider execution flags" { const payload = "data: {\"type\":\"tool-call\",\"toolCallId\":\"call_1\",\"toolName\":\"parallel_search\",\"input\":{},\"providerExecuted\":\"yes\"}\n\n" ++ "data: [DONE]\n\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(.fx_local, completion.tool_calls[0].provenance); try std.testing.expectEqual( types.AuthoritativeToolAdmission{ .reject_malformed_provider_result = .malformed_provider_executed }, types.authoritativeToolAdmission(completion), );}
test "consumeSseStream rejects provider results for local calls" { const payload = "data: {\"type\":\"tool-call\",\"toolCallId\":\"call_1\",\"toolName\":\"read_file\",\"input\":{\"path\":\"README.md\"}}\n\n" ++ "data: {\"type\":\"tool-result\",\"toolCallId\":\"call_1\",\"providerExecuted\":true,\"result\":{\"ignored\":true}}\n\n" ++ "data: [DONE]\n\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expect(completion.tool_calls[0].provider_result == null); try std.testing.expectEqual( types.AuthoritativeToolAdmission{ .reject_malformed_provider_result = .provenance_contradiction }, types.authoritativeToolAdmission(completion), );}
test "consumeSseStream preliminary-only results do not satisfy admission" { const payload = "data: {\"type\":\"tool-call\",\"toolCallId\":\"call_1\",\"toolName\":\"parallel_search\",\"input\":{},\"providerExecuted\":true}\n\n" ++ "data: {\"type\":\"tool-result\",\"toolCallId\":\"call_1\",\"preliminary\":true,\"result\":{\"partial\":true}}\n\n" ++ "data: [DONE]\n\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expect(completion.provider_result_identity_failure == null); try std.testing.expect(completion.tool_calls[0].provider_result == null); try std.testing.expectEqual( types.AuthoritativeToolAdmission{ .reject_malformed_provider_result = .missing_result }, types.authoritativeToolAdmission(completion), );}
test "consumeSseStream rejects malformed and late provider result events" { const Case = struct { result_events: []const u8, expected: types.ProviderResultIdentityFailure, }; const cases = [_]Case{ .{ .result_events = "data: {\"type\":\"tool-result\",\"toolCallId\":\"call_1\",\"preliminary\":\"yes\",\"result\":{\"bad\":true}}\n\n", .expected = .malformed_preliminary, }, .{ .result_events = "data: {\"type\":\"tool-result\",\"toolCallId\":\"call_1\",\"result\":null}\n\n", .expected = .missing_result, }, .{ .result_events = "data: {\"type\":\"tool-result\",\"toolCallId\":\"call_1\",\"result\":{\"final\":1}}\n\n" ++ "data: {\"type\":\"tool-result\",\"toolCallId\":\"call_1\",\"preliminary\":true,\"result\":{\"late\":2}}\n\n", .expected = .duplicate_result, }, .{ .result_events = "data: {\"type\":\"tool-result\",\"toolCallId\":\"call_1\",\"result\":{\"final\":1}}\n\n" ++ "data: {\"type\":\"tool-result\",\"toolCallId\":\"call_1\",\"result\":{\"late\":2}}\n\n", .expected = .duplicate_result, }, };
for (cases) |case| { const payload = try std.fmt.allocPrint( std.testing.allocator, "data: {{\"type\":\"tool-call\",\"toolCallId\":\"call_1\",\"toolName\":\"parallel_search\",\"input\":{{}},\"providerExecuted\":true}}\n\n" ++ "{s}" ++ "data: [DONE]\n\n", .{case.result_events}, ); defer std.testing.allocator.free(payload);
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(case.expected, completion.provider_result_identity_failure.?); switch (types.authoritativeToolAdmission(completion)) { .reject_malformed_provider_result => |failure| try std.testing.expectEqual(case.expected, failure), else => return error.TestUnexpectedResult, } }}
fn consolidatedToolCallSseForTest( alloc: std.mem.Allocator, content_len: usize,) ![]u8 { var out: std.Io.Writer.Allocating = .init(alloc); defer out.deinit(); try out.writer.writeAll( "data: {\"type\":\"tool-call\",\"toolCallId\":\"large\",\"toolName\":\"write_file\",\"input\":{\"path\":\"large.txt\",\"content\":\"", ); try out.writer.splatByteAll('x', content_len); try out.writer.writeAll("\"}}\n\ndata: [DONE]\n\n"); return out.toOwnedSlice();}
test "consumeSseStream preserves consolidated tool calls across the transport buffer boundary" { const alloc = std.testing.allocator; const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
for ([_]usize{ 192 * 1024, 300 * 1024, 4 * 1024 * 1024 }) |content_len| { const payload = try consolidatedToolCallSseForTest(alloc, content_len); defer alloc.free(payload);
var source = std.Io.Reader.fixed(payload); var transfer_buffer: [gateway_transfer_buffer_bytes]u8 = undefined; var buffered = source.limited(.unlimited, &transfer_buffer); var cancel_flag = std.atomic.Value(bool).init(false); const completion = try consumeSseStream( alloc, &buffered.interface, undefined, Noop.chunk, null, &cancel_flag, ); var result = StreamResult{ .status = .ok, .completion = completion, }; defer result.deinit(alloc);
try std.testing.expectEqual(@as(usize, 1), completion.tool_calls.len); try std.testing.expectEqualStrings( "write_file", completion.tool_calls[0].name, ); var parsed = try std.json.parseFromSlice( std.json.Value, alloc, completion.tool_calls[0].arguments_json, .{}, ); defer parsed.deinit(); try std.testing.expectEqual( content_len, parsed.value.object.get("content").?.string.len, ); }}
test "provider framing rejects an over-limit event explicitly" { const alloc = std.testing.allocator; const payload = try consolidatedToolCallSseForTest(alloc, 1024); defer alloc.free(payload);
var source = std.Io.Reader.fixed(payload); var transfer_buffer: [64]u8 = undefined; var buffered = source.limited(.unlimited, &transfer_buffer); var event_reader = sse.Reader{ .max_event_bytes = 512 }; defer event_reader.deinit(alloc); const cancelled = std.atomic.Value(bool).init(false);
try std.testing.expectError( error.EventTooLarge, event_reader.next(alloc, &buffered.interface, &cancelled), );}
test "consumeSseStream replaces preliminary results and preserves the first final result" { const payload = "data: {\"type\":\"tool-call\",\"toolCallId\":\"c1\",\"toolName\":\"parallel_search\",\"input\":{},\"providerExecuted\":true}\n" ++ "\n" ++ "data: {\"type\":\"tool-result\",\"toolCallId\":\"c1\",\"preliminary\":true,\"result\":{\"first\":true}}\n" ++ "\n" ++ "data: {\"type\":\"tool-result\",\"toolCallId\":\"c1\",\"preliminary\":true,\"result\":{\"second\":true}}\n" ++ "\n" ++ "data: {\"type\":\"tool-result\",\"toolCallId\":\"c1\",\"result\":{\"final\":true}}\n" ++ "\n" ++ "data: [DONE]\n" ++ "\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false);
const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(@as(usize, 1), completion.tool_calls.len); try std.testing.expectEqualStrings("{\"final\":true}", completion.tool_calls[0].provider_result.?); try std.testing.expectEqual(.provider_executed, completion.tool_calls[0].provenance); try std.testing.expect(completion.provider_result_identity_failure == null); try std.testing.expectEqual( types.AuthoritativeToolAdmission.admitted, types.authoritativeToolAdmission(completion), );}
fn checkConsumeSseAllocationFailures(alloc: std.mem.Allocator) !void { const payload = "data: {\"type\":\"text-delta\",\"id\":\"text\",\"delta\":\"hello\"}\n\n" ++ "data: {\"type\":\"tool-input-start\",\"id\":\"A\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"A\",\"delta\":\"{\\\"path\\\":\\\"alpha.txt\\\",\\\"line_end\\\":2}\"}\n\n" ++ "data: {\"type\":\"tool-input-start\",\"id\":\"B\",\"toolName\":\"parallel_search\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"B\",\"delta\":\"{\\\"query\\\":\\\"zig\\\"}\"}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"A\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"final_A\",\"toolName\":\"read_file\",\"input\":{\"line_end\":2,\"path\":\"alpha.txt\"}}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"B\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"B\",\"input\":{\"query\":\"zig\"},\"providerExecuted\":true}\n\n" ++ "data: {\"type\":\"tool-result\",\"toolCallId\":\"B\",\"preliminary\":true,\"result\":{\"phase\":1}}\n\n" ++ "data: {\"type\":\"tool-result\",\"toolCallId\":\"B\",\"result\":{\"results\":[{\"title\":\"final\"}]}}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"C\",\"toolName\":\"dynamic_tool\",\"input\":[1,{\"nested\":true}]}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"tool-calls\"}}\n\n";
const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} fn toolStart(_: *anyopaque, _: []const u8, _: []const u8, _: ?[]const u8, _: ?[]const u8) void {} };
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); var completion = try consumeSseStream( alloc, &reader, undefined, Noop.chunk, Noop.toolStart, &cancel_flag, ); defer deinitGatewayCompletion(alloc, &completion);
try std.testing.expectEqualStrings("hello", completion.content.?); try std.testing.expectEqual(@as(usize, 3), completion.tool_calls.len); try std.testing.expectEqualStrings( "{\"line_end\":2,\"path\":\"alpha.txt\"}", completion.tool_calls[0].arguments_json, ); try std.testing.expectEqualStrings("A", completion.tool_calls[0].provisional_id.?); try std.testing.expectEqualStrings("{\"results\":[{\"title\":\"final\"}]}", completion.tool_calls[1].provider_result.?); try std.testing.expectEqualStrings("[1,{\"nested\":true}]", completion.tool_calls[2].arguments_json); try std.testing.expectEqual( types.AuthoritativeToolAdmission.admitted, types.authoritativeToolAdmission(completion), );}
test "consumeSseStream frees all response state across allocation failures" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkConsumeSseAllocationFailures, .{}, );}
test "consumeSseStream frees streamed state on cancellation after a start" { const payload = "data: {\"type\":\"tool-input-start\",\"id\":\"cancelled\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"cancelled\",\"delta\":\"{\\\"path\\\":\\\"never-read\\\"}\"}\n\n";
const Capture = struct { cancel_flag: *std.atomic.Value(bool),
fn chunk(_: *anyopaque, _: []const u8) void {}
fn toolStart(ctx: *anyopaque, _: []const u8, _: []const u8, _: ?[]const u8, _: ?[]const u8) void { const self: *@This() = @ptrCast(@alignCast(ctx)); self.cancel_flag.store(true, .seq_cst); } };
var cancel_flag = std.atomic.Value(bool).init(false); var capture = Capture{ .cancel_flag = &cancel_flag }; var reader = std.Io.Reader.fixed(payload); var completion = try consumeSseStream( std.testing.allocator, &reader, &capture, Capture.chunk, Capture.toolStart, &cancel_flag, ); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(@as(usize, 0), completion.tool_calls.len); try std.testing.expect(completion.finish_reason == null);}
test "consumeSseStream frees streamed state on read failure" { const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
const payload = "data: {\"type\":\"tool-input-start\",\"id\":\"failed\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"failed\",\"delta\":\"{\\\"path\\\":\\\"partial\\\"}\"}\n\n"; var reader = std.Io.Reader.failing; reader.buffer = @constCast(payload); reader.end = payload.len; var cancel_flag = std.atomic.Value(bool).init(false); try std.testing.expectError( error.ReadFailed, consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag), );}
test "consumeSseStream frees unfinished streamed state at EOF" { const payload = "data: {\"type\":\"tool-input-start\",\"id\":\"unfinished\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"unfinished\",\"delta\":\"{\\\"path\\\":\\\"partial\\\"}\"}\n\n"; const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); var completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(std.testing.allocator, &completion);
try std.testing.expectEqual(@as(usize, 0), completion.tool_calls.len); try std.testing.expect(completion.finish_reason == null);}
test "consumeSseStream preview failure is metadata-only and non-fatal" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const root = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "."); defer alloc.free(root); const trace_path = try std.fs.path.join(alloc, &.{ root, "preview-failure.log" }); defer alloc.free(trace_path);
debug_trace.resetForTest(); defer debug_trace.resetForTest(); try debug_trace.configureForTestWithScopes(alloc, trace_path, "sse"); test_force_sse_preview_failure = true; defer test_force_sse_preview_failure = false;
const payload = "data: {\"type\":\"text-delta\",\"id\":\"text\",\"delta\":\"FX_PREVIEW_VALUE_SENTINEL\"}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\"}}\n\n"; const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); var completion = try consumeSseStream(alloc, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(alloc, &completion); debug_trace.shutdown();
try std.testing.expectEqualStrings("FX_PREVIEW_VALUE_SENTINEL", completion.content.?); const trace = try readTraceFileForTest(alloc, trace_path); defer alloc.free(trace); try std.testing.expectEqual(@as(usize, 2), std.mem.count(u8, trace, "preview=<preview-error>")); try std.testing.expect(std.mem.find(u8, trace, "FX_PREVIEW_VALUE_SENTINEL") == null);}
test "consumeSseStream unfiltered trace excludes all payload keys and values" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const root = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "."); defer alloc.free(root); const trace_path = try std.fs.path.join(alloc, &.{ root, "unfiltered-sse-privacy.log" }); defer alloc.free(trace_path);
debug_trace.resetForTest(); defer debug_trace.resetForTest(); try debug_trace.configureForTest(alloc, trace_path);
const payload = "data: {\"type\":\"FX_UNKNOWN_TYPE_SENTINEL\",\"FX_DYNAMIC_KEY_SENTINEL\":\"FX_UNKNOWN_VALUE_SENTINEL\"}\n\n" ++ "data: {\"type\":\"text-delta\",\"id\":\"text\",\"delta\":\"FX_MODEL_TEXT_SENTINEL\"}\n\n" ++ "data: {\"type\":\"tool-input-start\",\"id\":\"safe_call\",\"toolName\":\"read_file\"}\n\n" ++ "data: {\"type\":\"tool-input-start\",\"id\":\"safe_call\",\"toolName\":\"grep_files\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"safe_call\",\"delta\":\"{\\\"FX_ARGUMENT_KEY_SENTINEL\\\":\\\"FX_PATH_VALUE_SENTINEL\\\"}\"}\n\n" ++ "data: {\"type\":\"tool-input-end\",\"id\":\"safe_call\"}\n\n" ++ "data: {\"type\":\"tool-input-delta\",\"id\":\"safe_call\",\"delta\":\"FX_LATE_PREFIX_SENTINEL\"}\n\n" ++ "data: {\"type\":\"tool-call\",\"toolCallId\":\"safe_call\",\"toolName\":\"read_file\",\"input\":{\"FX_FINAL_KEY_SENTINEL\":\"FX_FINAL_VALUE_SENTINEL\"},\"providerExecuted\":true}\n\n" ++ "data: {\"type\":\"tool-result\",\"toolCallId\":\"safe_call\",\"result\":{\"FX_RESULT_KEY_SENTINEL\":\"FX_RESULT_VALUE_SENTINEL\"}}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"tool-calls\"}}\n\n";
const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} }; var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false); var completion = try consumeSseStream(alloc, &reader, undefined, Noop.chunk, null, &cancel_flag); defer deinitGatewayCompletion(alloc, &completion); debug_trace.shutdown();
try std.testing.expectEqualStrings("FX_MODEL_TEXT_SENTINEL", completion.content.?); try std.testing.expectEqual( types.AuthoritativeToolAdmission.admitted, types.authoritativeToolAdmission(completion), );
const trace = try readTraceFileForTest(alloc, trace_path); defer alloc.free(trace); inline for (.{ "event type=unknown", "event type=text-delta", "event type=tool-input-start", "event type=tool-input-delta", "event type=tool-input-end", "event type=tool-call", "event type=tool-result", "event type=finish", "reason=conflicting_start", "reason=unmatched_or_late_delta", }) |metadata| { try std.testing.expect(std.mem.find(u8, trace, metadata) != null); } inline for (.{ "FX_UNKNOWN_TYPE_SENTINEL", "FX_DYNAMIC_KEY_SENTINEL", "FX_UNKNOWN_VALUE_SENTINEL", "FX_MODEL_TEXT_SENTINEL", "FX_ARGUMENT_KEY_SENTINEL", "FX_PATH_VALUE_SENTINEL", "FX_LATE_PREFIX_SENTINEL", "FX_FINAL_KEY_SENTINEL", "FX_FINAL_VALUE_SENTINEL", "FX_RESULT_KEY_SENTINEL", "FX_RESULT_VALUE_SENTINEL", }) |sentinel| { try std.testing.expect(std.mem.find(u8, trace, sentinel) == null); }}
test "consumeSseStream preserves partial content without finish proof at EOF" { const payload = "data: {\"type\":\"text-delta\",\"id\":\"t1\",\"delta\":\"Hola\"}\n" ++ "\n";
var reader = std.Io.Reader.fixed(payload); var cancel_flag = std.atomic.Value(bool).init(false);
const Noop = struct { fn chunk(_: *anyopaque, _: []const u8) void {} };
const completion = try consumeSseStream(std.testing.allocator, &reader, undefined, Noop.chunk, null, &cancel_flag); defer if (completion.content) |content| std.testing.allocator.free(content);
try std.testing.expectEqualStrings("Hola", completion.content.?); try std.testing.expect(completion.finish_reason == null);}
const BoundedProbeStage = enum { request_open, dns, connect, tls, send, response_head, response_body, retry_sleep,};
const BoundedProbeMode = enum { success, wait, success_and_cancel, wait_and_mark_cancel_when_task_is_cancelled,};
const BoundedProbe = struct { alloc: std.mem.Allocator, cancel_flag: *std.atomic.Value(bool), mode: BoundedProbeMode, stage: BoundedProbeStage = .request_open, request_starts: usize = 0, active_tasks: usize = 0, network_opens: usize = 0, reached_stage: ?BoundedProbeStage = null,
fn run(self: *@This()) anyerror!StreamResult { self.request_starts += 1; self.active_tasks += 1; defer self.active_tasks -= 1; self.network_opens += 1; self.reached_stage = self.stage;
switch (self.mode) { .success => return self.successResult(), .wait => { try io_mod.getIo().sleep(.fromSeconds(5), .awake); return error.TestRequestDidNotBlock; }, .success_and_cancel => { self.cancel_flag.store(true, .seq_cst); return self.successResult(); }, .wait_and_mark_cancel_when_task_is_cancelled => { io_mod.getIo().sleep(.fromSeconds(5), .awake) catch |err| { if (err == error.Canceled) self.cancel_flag.store(true, .seq_cst); return err; }; return error.TestRequestDidNotBlock; }, } }
fn successResult(self: *@This()) !StreamResult { const content = try self.alloc.dupe(u8, "ok"); errdefer self.alloc.free(content); return .{ .status = .ok, .completion = .{ .content = content, .provider_state_json = try self.alloc.dupe(u8, "[]"), .finish_reason = .stop, }, }; }};
fn testAwakeDeadlineAfter(milliseconds: i64) std.Io.Clock.Timestamp { return std.Io.Clock.Timestamp.fromNow(io_mod.getIo(), .{ .clock = .awake, .raw = .fromMilliseconds(milliseconds), });}
const LoopbackGatewayMode = enum { reset_on_accept, tls_handshake_stall, request_send_stall, response_head_stall, response_body_stall, response_body_delayed_success, response_body_progress, retry_once, retry_once_then_success, success, success_capture, model_catalog_success, private_model_catalog_success, keep_alive_reuse, keep_alive_close_after_response, reset_mid_request, reset_after_head_read, slow_terminal_chunk, never_terminating_body,};
const LoopbackGatewayFixture = struct { io_backend: std.Io.Threaded = .init_single_threaded, server: std.Io.net.Server, mode: LoopbackGatewayMode, hold_ms: u64, thread: ?std.Thread = null, server_open: bool = true, accept_started: std.atomic.Value(bool) = .init(false), stopping: std.atomic.Value(bool) = .init(false), accepted: std.atomic.Value(bool) = .init(false), accepted_count: std.atomic.Value(usize) = .init(0), requests_served: std.atomic.Value(usize) = .init(0), reached_stage: std.atomic.Value(bool) = .init(false), request_headers: [16 * 1024]u8 = undefined, request_headers_len: std.atomic.Value(usize) = .init(0), failure: ?anyerror = null,
fn init(mode: LoopbackGatewayMode, hold_ms: u64) !@This() { var fixture: @This() = .{ .server = undefined, .mode = mode, .hold_ms = hold_ms, }; var address = try std.Io.net.IpAddress.parse("127.0.0.1", 0); fixture.server = try address.listen(fixture.io(), .{ .reuse_address = true }); return fixture; }
fn start(self: *@This()) !void { std.debug.assert(self.thread == null); self.thread = try std.Thread.spawn(.{}, run, .{self}); }
fn deinit(self: *@This()) void { if (!self.server_open) return;
const zio = self.io(); self.stopping.store(true, .seq_cst); if (self.thread) |thread| { const listener = std.Io.net.Stream{ .socket = self.server.socket }; listener.shutdown(zio, .both) catch {}; self.wakeAccept(); thread.join(); self.thread = null; } self.server.deinit(zio); self.server_open = false; }
fn port(self: *@This()) u16 { return self.server.socket.address.getPort(); }
fn io(self: *@This()) std.Io { return self.io_backend.io(); }
fn waitForAcceptStart(self: *@This(), timeout_ms: u64) bool { return self.waitForSignal(&self.accept_started, timeout_ms); }
fn waitForStageOrDone(self: *@This(), request_done: *std.atomic.Value(bool)) bool { while (!self.reached_stage.load(.seq_cst)) { if (request_done.load(.seq_cst) or self.stopping.load(.seq_cst)) return false; sleepBlocking(1); } return true; }
fn waitForSignal(self: *@This(), signal: *std.atomic.Value(bool), timeout_ms: u64) bool { var remaining_ms = timeout_ms; while (remaining_ms > 0) : (remaining_ms -= 1) { if (signal.load(.seq_cst)) return true; if (self.stopping.load(.seq_cst)) return false; sleepBlocking(1); } return signal.load(.seq_cst); }
fn wakeAccept(self: *@This()) void { var wake_io_backend: std.Io.Threaded = .init_single_threaded; const zio = wake_io_backend.io(); const address = std.Io.net.IpAddress{ .ip4 = .loopback(self.port()) }; var stream = address.connect(zio, .{ .mode = .stream, }) catch return; stream.close(zio); }
fn sleepBlocking(milliseconds: u64) void { var sleep_io_backend: std.Io.Threaded = .init_single_threaded; sleep_io_backend.io().sleep(.fromMilliseconds(@intCast(milliseconds)), .real) catch {}; }
fn hold(self: *@This()) void { var remaining_ms = self.hold_ms; while (remaining_ms > 0 and !self.stopping.load(.seq_cst)) { const sleep_ms: u64 = @min(remaining_ms, 10); sleepBlocking(sleep_ms); remaining_ms -= sleep_ms; } }
fn markStage(self: *@This()) void { self.reached_stage.store(true, .seq_cst); }
fn captureRequestHeaders(self: *@This(), headers: []const u8) void { const len = @min(headers.len, self.request_headers.len); @memcpy(self.request_headers[0..len], headers[0..len]); self.request_headers_len.store(len, .seq_cst); }
fn capturedHeaderValue(self: *@This(), name: []const u8) ?[]const u8 { const len = self.request_headers_len.load(.seq_cst); if (len == 0) return null; return rawHeaderValue(self.request_headers[0..len], name); }
fn run(self: *@This()) void { self.runFallible() catch |err| { if (self.stopping.load(.seq_cst) and err == error.SocketNotListening) return; self.failure = err; }; }
fn runFallible(self: *@This()) !void { const zio = self.io(); self.accept_started.store(true, .seq_cst); var stream = try self.server.accept(zio); defer stream.close(zio); if (self.stopping.load(.seq_cst)) return; self.accepted.store(true, .seq_cst); _ = self.accepted_count.fetchAdd(1, .seq_cst);
switch (self.mode) { .reset_on_accept => { const reset_on_close: std.posix.linger = .{ .onoff = 1, .linger = 0, }; try std.posix.setsockopt( stream.socket.handle, std.posix.SOL.SOCKET, std.posix.SO.LINGER, std.mem.asBytes(&reset_on_close), ); self.markStage(); }, .tls_handshake_stall => { self.markStage(); self.hold(); }, .request_send_stall => { const receive_buffer: c_int = 1024; std.posix.setsockopt( stream.socket.handle, std.posix.SOL.SOCKET, std.posix.SO.RCVBUF, std.mem.asBytes(&receive_buffer), ) catch {}; self.markStage(); self.hold(); }, .response_head_stall => { try readLoopbackGatewayRequest(zio, stream, self); self.markStage(); self.hold(); }, .response_body_stall => { try readLoopbackGatewayRequest(zio, stream, self); try writeLoopbackGatewayBytes( zio, stream, "HTTP/1.1 200 OK\r\n" ++ "Content-Type: text/event-stream\r\n" ++ "Connection: close\r\n\r\n" ++ "data: {\"type\":\"text-delta\",\"id\":\"partial\",\"delta\":\"partial\"}\n\n", ); self.markStage(); self.hold(); }, .response_body_delayed_success => { try readLoopbackGatewayRequest(zio, stream, self); try writeLoopbackGatewayBytes( zio, stream, "HTTP/1.1 200 OK\r\n" ++ "Content-Type: text/event-stream\r\n" ++ "Connection: close\r\n\r\n", ); self.markStage(); self.hold(); try writeLoopbackGatewayBytes( zio, stream, "data: {\"type\":\"text-delta\",\"id\":\"answer\",\"delta\":\"ok\"}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\"}}\n\n", ); }, .response_body_progress => { try readLoopbackGatewayRequest(zio, stream, self); try writeLoopbackGatewayBytes( zio, stream, "HTTP/1.1 200 OK\r\n" ++ "Content-Type: text/event-stream\r\n" ++ "Connection: close\r\n\r\n", ); self.markStage(); for (0..30) |_| { if (self.stopping.load(.seq_cst)) return; writeLoopbackGatewayBytes(zio, stream, ": progress\n\n") catch return; sleepBlocking(20); } self.hold(); }, .retry_once => { try readLoopbackGatewayRequest(zio, stream, self); self.markStage(); try writeLoopbackGatewayBytes( zio, stream, "HTTP/1.1 503 Service Unavailable\r\n" ++ "Content-Length: 0\r\n" ++ "Connection: close\r\n\r\n", ); }, .retry_once_then_success => { try readLoopbackGatewayRequest(zio, stream, self); self.markStage(); try writeLoopbackGatewayBytes( zio, stream, "HTTP/1.1 503 Service Unavailable\r\n" ++ "Content-Length: 0\r\n" ++ "Connection: close\r\n\r\n", );
var recovered_stream = try self.server.accept(zio); defer recovered_stream.close(zio); _ = self.accepted_count.fetchAdd(1, .seq_cst); try readLoopbackGatewayRequest(zio, recovered_stream, self); try writeLoopbackGatewayBytes( zio, recovered_stream, "HTTP/1.1 200 OK\r\n" ++ "Content-Type: text/event-stream\r\n" ++ "Connection: close\r\n\r\n" ++ "data: {\"type\":\"text-delta\",\"id\":\"answer\",\"delta\":\"ok\"}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\"}}\n\n", ); }, .success => { self.markStage(); try writeLoopbackGatewayBytes( zio, stream, "HTTP/1.1 200 OK\r\n" ++ "Content-Type: text/event-stream\r\n" ++ "Connection: close\r\n\r\n" ++ "data: {\"type\":\"text-delta\",\"id\":\"answer\",\"delta\":\"ok\"}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\"}}\n\n", ); self.hold(); }, .success_capture => { try readLoopbackGatewayRequest(zio, stream, self); self.markStage(); try writeLoopbackGatewayBytes( zio, stream, "HTTP/1.1 200 OK\r\n" ++ "Content-Type: text/event-stream\r\n" ++ "Connection: close\r\n\r\n" ++ "data: {\"type\":\"text-delta\",\"id\":\"answer\",\"delta\":\"ok\"}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\"}}\n\n", ); }, .model_catalog_success => { try readLoopbackGatewayRequest(zio, stream, self); self.markStage(); try writeLoopbackGatewayBytes( zio, stream, "HTTP/1.1 200 OK\r\n" ++ "Content-Type: application/json\r\n" ++ "Connection: close\r\n\r\n" ++ loopback_model_catalog_json, ); }, .private_model_catalog_success => { try readLoopbackGatewayRequest(zio, stream, self); self.markStage(); try writeLoopbackGatewayBytes( zio, stream, "HTTP/1.1 200 OK\r\n" ++ "Content-Type: application/json\r\n" ++ "Connection: close\r\n\r\n" ++ loopback_private_model_catalog_json, ); }, .keep_alive_reuse => { self.markStage(); self.serveKeepAliveLoop(zio, stream); }, .keep_alive_close_after_response => { self.markStage(); // Serve once, then drop the connection without a // Connection: close header, simulating an edge idle timeout: // the client pools the dead connection and discovers it on // the next borrow. self.serveKeepAliveOnce(zio, stream); stream.shutdown(zio, .both) catch {}; var recovered = try self.server.accept(zio); defer recovered.close(zio); _ = self.accepted_count.fetchAdd(1, .seq_cst); self.serveKeepAliveOnce(zio, recovered); }, .reset_mid_request => { // Read one byte, then RST: the client fails mid-send or at // head read; either way the connection must not be pooled. var one: [1]u8 = undefined; var reader = stream.reader(zio, &one); _ = reader.interface.takeByte() catch {}; const rst: std.posix.linger = .{ .onoff = 1, .linger = 0 }; try std.posix.setsockopt( stream.socket.handle, std.posix.SOL.SOCKET, std.posix.SO.LINGER, std.mem.asBytes(&rst), ); self.markStage(); }, .reset_after_head_read => { // Read only the request head, wait for the client to block // mid-body against full kernel buffers, then RST: the client // fails inside the send path, and the connection must never // reach the pool. var socket_buffer: [4096]u8 = undefined; var reader = stream.reader(zio, &socket_buffer); var header_buf: [512]u8 = undefined; var header_len: usize = 0; while (header_len < header_buf.len) { header_buf[header_len] = reader.interface.takeByte() catch break; header_len += 1; if (std.mem.endsWith(u8, header_buf[0..header_len], "\r\n\r\n")) break; } sleepBlocking(200); const rst: std.posix.linger = .{ .onoff = 1, .linger = 0 }; try std.posix.setsockopt( stream.socket.handle, std.posix.SOL.SOCKET, std.posix.SO.LINGER, std.mem.asBytes(&rst), ); self.markStage(); }, .slow_terminal_chunk => { try readLoopbackGatewayRequest(zio, stream, self); self.markStage(); var frame_buf: [512]u8 = undefined; const partial = try std.fmt.bufPrint( &frame_buf, "HTTP/1.1 200 OK\r\nContent-Type: text/event-stream\r\nTransfer-Encoding: chunked\r\n\r\n{x}\r\n{s}\r\n", .{ keep_alive_sse_payload.len, keep_alive_sse_payload }, ); try writeLoopbackGatewayBytes(zio, stream, partial); self.hold(); try writeLoopbackGatewayBytes(zio, stream, "0\r\n\r\n"); }, .never_terminating_body => { try readLoopbackGatewayRequest(zio, stream, self); self.markStage(); var frame_buf: [512]u8 = undefined; const partial = try std.fmt.bufPrint( &frame_buf, "HTTP/1.1 200 OK\r\nContent-Type: text/event-stream\r\nTransfer-Encoding: chunked\r\n\r\n{x}\r\n{s}\r\n", .{ keep_alive_sse_payload.len, keep_alive_sse_payload }, ); try writeLoopbackGatewayBytes(zio, stream, partial); // The terminal chunk never comes; keep the body open with // one-byte chunks until teardown. while (!self.stopping.load(.seq_cst)) { writeLoopbackGatewayBytes(zio, stream, "1\r\n:\r\n") catch return; sleepBlocking(50); } }, } }
fn serveKeepAliveLoop(self: *@This(), zio: std.Io, stream: std.Io.net.Stream) void { var socket_buffer: [4096]u8 = undefined; var reader = stream.reader(zio, &socket_buffer); while (!self.stopping.load(.seq_cst)) { readKeepAliveRequest(&reader.interface) catch return; _ = self.requests_served.fetchAdd(1, .seq_cst); writeKeepAliveResponse(zio, stream) catch return; } }
fn serveKeepAliveOnce(self: *@This(), zio: std.Io, stream: std.Io.net.Stream) void { var socket_buffer: [4096]u8 = undefined; var reader = stream.reader(zio, &socket_buffer); readKeepAliveRequest(&reader.interface) catch return; _ = self.requests_served.fetchAdd(1, .seq_cst); writeKeepAliveResponse(zio, stream) catch return; }};
const loopback_model_catalog_json = "{\"data\":[{\"id\":\"openai/gpt-5\",\"type\":\"language\",\"tags\":[\"reasoning\",\"tool-use\",\"vision\",\"file-input\",\"web-search\",\"explicit-caching\",\"implicit-caching\"],\"context_window\":256000,\"max_tokens\":32000},{\"id\":\"anthropic/claude-opus-4\",\"type\":\"language\",\"tags\":[\"tool-use\"],\"context_window\":200000},{\"id\":\"anthropic/claude-sonnet-4\",\"type\":\"language\",\"tags\":[\"tool-use\"],\"context_window\":200000}]}";
const loopback_private_model_catalog_json = "{\"data\":[{\"id\":\"openai/gpt-5\",\"type\":\"language\",\"tags\":[\"reasoning\",\"tool-use\",\"vision\",\"file-input\",\"web-search\",\"explicit-caching\",\"implicit-caching\"],\"context_window\":256000,\"max_tokens\":32000},{\"id\":\"anthropic/claude-opus-4\",\"type\":\"language\",\"tags\":[\"tool-use\"],\"context_window\":200000},{\"id\":\"anthropic/claude-sonnet-4\",\"type\":\"language\",\"tags\":[\"tool-use\"],\"context_window\":200000},{\"id\":\"private/blue-hornbill\",\"type\":\"language\",\"tags\":[\"tool-use\"],\"context_window\":200000}]}";
pub const TestModelCatalogFixture = struct { fixture: LoopbackGatewayFixture,
pub fn init() !@This() { return .{ .fixture = try LoopbackGatewayFixture.init(.model_catalog_success, 0) }; }
pub fn initPrivate() !@This() { return .{ .fixture = try LoopbackGatewayFixture.init(.private_model_catalog_success, 0) }; }
pub fn start(self: *@This()) !void { try self.fixture.start(); }
pub fn deinit(self: *@This()) void { self.fixture.deinit(); }
pub fn port(self: *@This()) u16 { return self.fixture.port(); }
pub fn waitForAcceptStart(self: *@This(), timeout_ms: u64) bool { return self.fixture.waitForAcceptStart(timeout_ms); }
pub fn failure(self: *@This()) ?anyerror { return self.fixture.failure; }
pub fn capturedHeaderValue(self: *@This(), name: []const u8) ?[]const u8 { return self.fixture.capturedHeaderValue(name); }};
const RequestOpenProbe = struct { attempts: usize = 0, tls_failure_attempt: ?usize = null, delays_ms: [3]i64 = .{ 0, 0, 0 }, keep_alive_seen: ?bool = null,
fn requestOpenOverride(self: *@This()) RequestOpenOverride { return .{ .ctx = @ptrCast(self), .run = open }; }
fn open( raw_ctx: *anyopaque, client: *std.http.Client, method: std.http.Method, uri: std.Uri, options: std.http.Client.RequestOptions, ) anyerror!std.http.Client.Request { const self: *@This() = @ptrCast(@alignCast(raw_ctx)); const attempt_index = self.attempts; self.attempts += 1; self.keep_alive_seen = options.keep_alive; if (attempt_index < self.delays_ms.len) { const delay_ms = self.delays_ms[attempt_index]; if (delay_ms > 0) { try io_mod.getIo().sleep(.fromMilliseconds(delay_ms), .awake); } } if (self.tls_failure_attempt == attempt_index) { return error.TlsInitializationFailed; } return client.request(method, uri, options); }};
const ConnectionSetupHarness = struct { fixture: LoopbackGatewayFixture, url: []u8,
fn init(mode: LoopbackGatewayMode, use_tls: bool) !ConnectionSetupHarness { var fixture = try LoopbackGatewayFixture.init(mode, 500); errdefer fixture.deinit(); const url = try std.fmt.allocPrint( std.testing.allocator, "{s}://127.0.0.1:{d}/chat", .{ if (use_tls) "https" else "http", fixture.port() }, ); return .{ .fixture = fixture, .url = url }; }
fn start(self: *@This()) !void { try self.fixture.start(); if (!self.fixture.waitForAcceptStart(5000)) return error.TestFixtureDidNotStart; }
fn deinit(self: *@This()) void { self.fixture.deinit(); std.testing.allocator.free(self.url); }};
fn discardConnectionSetupTestChunk(_: *anyopaque, _: []const u8) void {}
test "direct gateway request-open cancellation interrupts real TLS setup" { var harness = try ConnectionSetupHarness.init(.tls_handshake_stall, true); defer harness.deinit(); try harness.start();
var cancel_flag = std.atomic.Value(bool).init(false); var request_done = std.atomic.Value(bool).init(false); const Cancel = struct { fn run( fixture: *LoopbackGatewayFixture, flag: *std.atomic.Value(bool), done: *std.atomic.Value(bool), ) void { if (!fixture.waitForStageOrDone(done)) return; LoopbackGatewayFixture.sleepBlocking(30); if (!done.load(.seq_cst)) flag.store(true, .seq_cst); } }; const cancel_thread = try std.Thread.spawn(.{}, Cancel.run, .{ &harness.fixture, &cancel_flag, &request_done, }); defer { request_done.store(true, .seq_cst); cancel_thread.join(); }
var callback_ctx: u8 = 0; const started = std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake); const result = streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 1, .chat_url = harness.url, .payload = "{}", }, @ptrCast(&callback_ctx), discardConnectionSetupTestChunk, null, &cancel_flag, null, false, .{ .setup_timing = .{ .timeout_ms = 1000 } }, ); const elapsed_ms = started.durationTo( std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake), ).raw.toMilliseconds();
try std.testing.expectError(error.Cancelled, result); try std.testing.expect(elapsed_ms < 500); harness.fixture.deinit(); if (harness.fixture.failure) |err| return err;}
test "direct gateway request-open deadline interrupts real TLS setup" { var harness = try ConnectionSetupHarness.init(.tls_handshake_stall, true); defer harness.deinit(); try harness.start();
var delivery = DeliveryCertainty.init(); var cancel_flag = std.atomic.Value(bool).init(false); var callback_ctx: u8 = 0; const started = std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake); const result = streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 1, .chat_url = harness.url, .payload = "{}", .delivery = &delivery, }, @ptrCast(&callback_ctx), discardConnectionSetupTestChunk, null, &cancel_flag, null, false, .{ .setup_timing = .{ .timeout_ms = 80 } }, ); const elapsed_ms = started.durationTo( std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake), ).raw.toMilliseconds();
try std.testing.expectError(error.ConnectionSetupTimedOut, result); try std.testing.expect(elapsed_ms < 400); try std.testing.expectEqual(DeliveryCertainty.State.definitely_unsent, delivery.load()); harness.fixture.deinit(); if (harness.fixture.failure) |err| return err;}
test "TLS retry sleep consumes the original connection setup deadline" { var probe = RequestOpenProbe{ .tls_failure_attempt = 0 }; var cancel_flag = std.atomic.Value(bool).init(false); var callback_ctx: u8 = 0; const result = streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 3, .chat_url = "http://127.0.0.1:1/chat", .payload = "{}", }, @ptrCast(&callback_ctx), discardConnectionSetupTestChunk, null, &cancel_flag, null, false, .{ .setup_timing = .{ .timeout_ms = 80 }, .request_open_override = probe.requestOpenOverride(), }, );
try std.testing.expectError(error.ConnectionSetupTimedOut, result); try std.testing.expectEqual(@as(usize, 1), probe.attempts);}
test "transport-owned TLS setup retries before send" { var harness = try ConnectionSetupHarness.init(.success, false); defer harness.deinit(); try harness.start();
var probe = RequestOpenProbe{ .tls_failure_attempt = 0 }; var cancel_flag = std.atomic.Value(bool).init(false); var callback_ctx: u8 = 0; var result = try streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 2, .chat_url = harness.url, .payload = "{}", }, @ptrCast(&callback_ctx), discardConnectionSetupTestChunk, null, &cancel_flag, null, false, .{ .setup_timing = .{ .timeout_ms = 1000 }, .request_open_override = probe.requestOpenOverride(), }, ); defer result.deinit(std.testing.allocator);
try std.testing.expectEqual(@as(usize, 2), probe.attempts); try std.testing.expectEqualStrings("ok", result.completion.content.?); harness.fixture.deinit(); if (harness.fixture.failure) |err| return err;}
test "shared pool requests keep-alive and never pools server-closed connections" { var harness = try ConnectionSetupHarness.init(.success, false); defer harness.deinit(); try harness.start();
var pool = http_pool.HttpPool.init(std.testing.allocator); defer _ = pool.deinit();
var probe = RequestOpenProbe{}; var cancel_flag = std.atomic.Value(bool).init(false); var callback_ctx: u8 = 0; var result = try streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 1, .chat_url = harness.url, .payload = "{}", .shared_pool = &pool, }, @ptrCast(&callback_ctx), discardConnectionSetupTestChunk, null, &cancel_flag, null, false, .{ .request_open_override = probe.requestOpenOverride() }, ); defer result.deinit(std.testing.allocator);
try std.testing.expectEqual(@as(usize, 1), probe.attempts); try std.testing.expectEqual(true, probe.keep_alive_seen orelse false); try std.testing.expectEqualStrings("ok", result.completion.content.?); // The fixture answers with Connection: close; the pool must not retain it. try std.testing.expectEqual(@as(usize, 0), pool.freeConnectionCount()); harness.fixture.deinit(); if (harness.fixture.failure) |err| return err;}
test "unpooled requests keep close semantics" { var harness = try ConnectionSetupHarness.init(.success, false); defer harness.deinit(); try harness.start();
var probe = RequestOpenProbe{}; var cancel_flag = std.atomic.Value(bool).init(false); var callback_ctx: u8 = 0; var result = try streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 1, .chat_url = harness.url, .payload = "{}", }, @ptrCast(&callback_ctx), discardConnectionSetupTestChunk, null, &cancel_flag, null, false, .{ .request_open_override = probe.requestOpenOverride() }, ); defer result.deinit(std.testing.allocator);
try std.testing.expectEqual(@as(usize, 1), probe.attempts); try std.testing.expectEqual(false, probe.keep_alive_seen orelse true); try std.testing.expectEqualStrings("ok", result.completion.content.?); harness.fixture.deinit(); if (harness.fixture.failure) |err| return err;}
fn pooledLoopbackCall(pool: *http_pool.HttpPool, url: []const u8) anyerror!StreamResult { var cancel_flag = std.atomic.Value(bool).init(false); var callback_ctx: u8 = 0; return streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 1, .chat_url = url, .payload = "{}", .shared_pool = pool, }, @ptrCast(&callback_ctx), discardConnectionSetupTestChunk, null, &cancel_flag, null, false, .{}, );}
test "shared pool reuses one keep-alive connection across sequential requests" { var harness = try ConnectionSetupHarness.init(.keep_alive_reuse, false); defer harness.deinit(); try harness.start();
var pool = http_pool.HttpPool.init(std.testing.allocator); defer _ = pool.deinit();
var first = try pooledLoopbackCall(&pool, harness.url); defer first.deinit(std.testing.allocator); try std.testing.expectEqualStrings("ok", first.completion.content.?); try std.testing.expectEqual(@as(usize, 1), pool.freeConnectionCount());
var second = try pooledLoopbackCall(&pool, harness.url); defer second.deinit(std.testing.allocator); try std.testing.expectEqualStrings("ok", second.completion.content.?);
// One accepted connection served both requests. try std.testing.expectEqual(@as(usize, 1), harness.fixture.accepted_count.load(.seq_cst)); try std.testing.expectEqual(@as(usize, 2), harness.fixture.requests_served.load(.seq_cst)); // Close the pooled connection before the fixture teardown so the serve // loop observes EOF and the fixture thread can join. _ = pool.deinit(); harness.fixture.deinit(); if (harness.fixture.failure) |err| return err;}
test "stale pooled connection fails once, never re-pools, and the next request redials" { var harness = try ConnectionSetupHarness.init(.keep_alive_close_after_response, false); defer harness.deinit(); try harness.start();
var pool = http_pool.HttpPool.init(std.testing.allocator); defer _ = pool.deinit();
var first = try pooledLoopbackCall(&pool, harness.url); defer first.deinit(std.testing.allocator); try std.testing.expectEqualStrings("ok", first.completion.content.?); try std.testing.expectEqual(@as(usize, 1), pool.freeConnectionCount());
// The server silently dropped the pooled connection after responding // (idle-close). The next borrow writes into the dead socket and fails. const stale = pooledLoopbackCall(&pool, harness.url); if (stale) |ok_result| { var r = ok_result; r.deinit(std.testing.allocator); return error.TestExpectedStaleFailure; } else |_| {} // The dead connection was destroyed, not returned to the free list. try std.testing.expectEqual(@as(usize, 0), pool.freeConnectionCount());
var third = try pooledLoopbackCall(&pool, harness.url); defer third.deinit(std.testing.allocator); try std.testing.expectEqualStrings("ok", third.completion.content.?); try std.testing.expectEqual(@as(usize, 2), harness.fixture.accepted_count.load(.seq_cst));}
test "mid-request reset never returns the connection to the pool" { var harness = try ConnectionSetupHarness.init(.reset_mid_request, false); defer harness.deinit(); try harness.start();
var pool = http_pool.HttpPool.init(std.testing.allocator); defer _ = pool.deinit();
const result = pooledLoopbackCall(&pool, harness.url); if (result) |ok_result| { var r = ok_result; r.deinit(std.testing.allocator); return error.TestExpectedResetFailure; } else |_| {} try std.testing.expectEqual(@as(usize, 0), pool.freeConnectionCount());}
test "drain waits for a delayed terminal chunk without failing the request" { var harness = try ConnectionSetupHarness.init(.slow_terminal_chunk, false); defer harness.deinit(); try harness.start();
var pool = http_pool.HttpPool.init(std.testing.allocator); defer _ = pool.deinit();
const started = io_mod.milliTimestamp(); var result = try pooledLoopbackCall(&pool, harness.url); defer result.deinit(std.testing.allocator); const elapsed = io_mod.milliTimestamp() - started; try std.testing.expectEqualStrings("ok", result.completion.content.?); try std.testing.expect(elapsed >= 450); // fixture holds the terminal chunk for 500 ms try std.testing.expect(elapsed < 15_000); // No pool assertion here: under extreme CI runner load the fixture's // sliced hold can stretch past the drain budget, which by design forfeits // reuse of that connection. Pooling after a normal drain is covered // deterministically by the keep-alive reuse test. harness.fixture.deinit(); if (harness.fixture.failure) |err| return err;}
test "never-terminating body completes within the drain budget instead of hanging" { var harness = try ConnectionSetupHarness.init(.never_terminating_body, false); defer harness.deinit(); try harness.start();
var pool = http_pool.HttpPool.init(std.testing.allocator); defer _ = pool.deinit();
const started = io_mod.milliTimestamp(); var result = try pooledLoopbackCall(&pool, harness.url); defer result.deinit(std.testing.allocator); const elapsed = io_mod.milliTimestamp() - started; try std.testing.expectEqualStrings("ok", result.completion.content.?); // The drain budget rescues the completed request; it must not hang. try std.testing.expect(elapsed >= pool_drain_budget_ms - 500); try std.testing.expect(elapsed < 15_000); // The connection that never finished its body is destroyed, not pooled. try std.testing.expectEqual(@as(usize, 0), pool.freeConnectionCount());}
test "mid-send failure never returns the connection to the pool" { var harness = try ConnectionSetupHarness.init(.reset_after_head_read, false); defer harness.deinit(); try harness.start();
var pool = http_pool.HttpPool.init(std.testing.allocator); defer _ = pool.deinit();
const payload = try std.testing.allocator.alloc(u8, 16 * 1024 * 1024); defer std.testing.allocator.free(payload); @memset(payload, 'x');
var cancel_flag = std.atomic.Value(bool).init(false); var callback_ctx: u8 = 0; const result = streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 1, .chat_url = harness.url, .payload = payload, .shared_pool = &pool, }, @ptrCast(&callback_ctx), discardConnectionSetupTestChunk, null, &cancel_flag, null, false, .{}, ); if (result) |ok_result| { var r = ok_result; r.deinit(std.testing.allocator); return error.TestExpectedSendFailure; } else |_| {} try std.testing.expectEqual(@as(usize, 0), pool.freeConnectionCount());}
test "gateway setup trace distinguishes attempt limits from retries used" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const root = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "."); defer alloc.free(root); const trace_path = try std.fs.path.join(alloc, &.{ root, "gateway-attempts.log" }); defer alloc.free(trace_path);
debug_trace.resetForTest(); defer debug_trace.resetForTest(); try debug_trace.configureForTestWithScopes(alloc, trace_path, "gateway");
var harness = try ConnectionSetupHarness.init(.success, false); defer harness.deinit(); try harness.start();
var probe = RequestOpenProbe{ .tls_failure_attempt = 0 }; var cancel_flag = std.atomic.Value(bool).init(false); var callback_ctx: u8 = 0; var result = try streamGatewayCompletionCoreWithOptions( alloc, .{ .api_key = "test-key", .model = "test/model", .retry_count = 2, .chat_url = harness.url, .payload = "{}", }, @ptrCast(&callback_ctx), discardConnectionSetupTestChunk, null, &cancel_flag, null, false, .{ .setup_timing = .{ .timeout_ms = 1000 }, .request_open_override = probe.requestOpenOverride(), }, ); defer result.deinit(alloc); debug_trace.shutdown();
const trace = try readTraceFileForTest(alloc, trace_path); defer alloc.free(trace); try std.testing.expect(std.mem.find( u8, trace, "attempt=1 attempt_limit=2 retries_used=0", ) != null); try std.testing.expect(std.mem.find( u8, trace, "attempt=2 attempt_limit=2 retries_used=1", ) != null); try std.testing.expect(std.mem.find(u8, trace, "retry_count=") == null);
harness.fixture.deinit(); if (harness.fixture.failure) |err| return err;}
test "a fresh setup epoch succeeds normally" { var harness = try ConnectionSetupHarness.init(.success, false); defer harness.deinit(); try harness.start();
var cancel_flag = std.atomic.Value(bool).init(false); var callback_ctx: u8 = 0; var result = try streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 1, .chat_url = harness.url, .payload = "{}", }, @ptrCast(&callback_ctx), discardConnectionSetupTestChunk, null, &cancel_flag, null, false, .{ .setup_timing = .{ .timeout_ms = 1000 } }, ); defer result.deinit(std.testing.allocator);
try std.testing.expectEqualStrings("ok", result.completion.content.?); harness.fixture.deinit(); if (harness.fixture.failure) |err| return err;}
test "transport-owned TLS retry succeeds after delayed open" { var harness = try ConnectionSetupHarness.init(.success, false); defer harness.deinit(); try harness.start();
var probe = RequestOpenProbe{ .tls_failure_attempt = 0, .delays_ms = .{ 0, 100, 0 }, }; var cancel_flag = std.atomic.Value(bool).init(false); var callback_ctx: u8 = 0; var result = try streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 3, .chat_url = harness.url, .payload = "{}", }, @ptrCast(&callback_ctx), discardConnectionSetupTestChunk, null, &cancel_flag, null, false, .{ .setup_timing = .{ .timeout_ms = 1000 }, .request_open_override = probe.requestOpenOverride(), }, ); defer result.deinit(std.testing.allocator);
try std.testing.expectEqual(@as(usize, 2), probe.attempts); harness.fixture.deinit(); if (harness.fixture.failure) |err| return err;}
test "transport-owned TLS retry succeeds after delayed failure" { var harness = try ConnectionSetupHarness.init(.success, false); defer harness.deinit(); try harness.start();
var probe = RequestOpenProbe{ .tls_failure_attempt = 0, .delays_ms = .{ 50, 0, 0 }, }; var cancel_flag = std.atomic.Value(bool).init(false); var callback_ctx: u8 = 0; var result = try streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 3, .chat_url = harness.url, .payload = "{}", }, @ptrCast(&callback_ctx), discardConnectionSetupTestChunk, null, &cancel_flag, null, false, .{ .setup_timing = .{ .timeout_ms = 1000 }, .request_open_override = probe.requestOpenOverride(), }, ); defer result.deinit(std.testing.allocator);
try std.testing.expectEqual(@as(usize, 2), probe.attempts); harness.fixture.deinit(); if (harness.fixture.failure) |err| return err;}
test "response retry starts a fresh setup epoch without resetting delivery" { var harness = try ConnectionSetupHarness.init(.retry_once_then_success, false); defer harness.deinit(); try harness.start();
var probe = RequestOpenProbe{ .delays_ms = .{ 500, 500, 0 } }; var delivery = DeliveryCertainty.init(); var cancel_flag = std.atomic.Value(bool).init(false); var callback_ctx: u8 = 0; var result = try streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 2, .chat_url = harness.url, .payload = "{}", .delivery = &delivery, }, @ptrCast(&callback_ctx), discardConnectionSetupTestChunk, null, &cancel_flag, null, false, .{ .setup_timing = .{ .timeout_ms = 800 }, .request_open_override = probe.requestOpenOverride(), }, ); defer result.deinit(std.testing.allocator);
try std.testing.expectEqual(@as(usize, 2), probe.attempts); try std.testing.expectEqual(DeliveryCertainty.State.possibly_sent, delivery.load()); try std.testing.expectEqualStrings("ok", result.completion.content.?); harness.fixture.deinit(); if (harness.fixture.failure) |err| return err;}
test "agent-owned provider attempts return the first retryable response" { var harness = try ConnectionSetupHarness.init(.retry_once, false); defer harness.deinit(); try harness.start();
var probe = RequestOpenProbe{}; var delivery = DeliveryCertainty.init(); var cancel_flag = std.atomic.Value(bool).init(false); var callback_ctx: u8 = 0; var result = try streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 3, .chat_url = harness.url, .payload = "{}", .delivery = &delivery, .provider_attempt_owner = .agent, }, @ptrCast(&callback_ctx), discardConnectionSetupTestChunk, null, &cancel_flag, null, false, .{ .setup_timing = .{ .timeout_ms = 1000 }, .request_open_override = probe.requestOpenOverride(), }, ); defer result.deinit(std.testing.allocator);
try std.testing.expectEqual(std.http.Status.service_unavailable, result.status); try std.testing.expectEqual(@as(usize, 1), probe.attempts); try std.testing.expectEqual(DeliveryCertainty.State.possibly_sent, delivery.load()); harness.fixture.deinit(); if (harness.fixture.failure) |err| return err;}
test "agent-owned provider attempts return the first TLS setup failure" { var harness = try ConnectionSetupHarness.init(.success, false); defer harness.deinit(); try harness.start();
var probe = RequestOpenProbe{ .tls_failure_attempt = 0 }; var delivery = DeliveryCertainty.init(); var cancel_flag = std.atomic.Value(bool).init(false); var callback_ctx: u8 = 0; const result = streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 3, .chat_url = harness.url, .payload = "{}", .delivery = &delivery, .provider_attempt_owner = .agent, }, @ptrCast(&callback_ctx), discardConnectionSetupTestChunk, null, &cancel_flag, null, false, .{ .setup_timing = .{ .timeout_ms = 1000 }, .request_open_override = probe.requestOpenOverride(), }, ); if (result) |success_value| { var success = success_value; success.deinit(std.testing.allocator); return error.TestExpectedTlsInitializationFailure; } else |err| { try std.testing.expectEqual(error.TlsInitializationFailed, err); }
try std.testing.expectEqual(@as(usize, 1), probe.attempts); try std.testing.expectEqual(DeliveryCertainty.State.definitely_unsent, delivery.load()); harness.fixture.deinit(); if (harness.fixture.failure) |err| return err;}
test "agent-owned provider attempts return immediate peer resets without transport retry" { var harness = try ConnectionSetupHarness.init(.reset_on_accept, false); defer harness.deinit(); try harness.start();
var probe = RequestOpenProbe{}; var delivery = DeliveryCertainty.init(); var cancel_flag = std.atomic.Value(bool).init(false); var callback_ctx: u8 = 0; const result = streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 3, .chat_url = harness.url, .payload = "{}", .delivery = &delivery, .provider_attempt_owner = .agent, }, @ptrCast(&callback_ctx), discardConnectionSetupTestChunk, null, &cancel_flag, null, false, .{ .setup_timing = .{ .timeout_ms = 1000 }, .request_open_override = probe.requestOpenOverride(), }, ); if (result) |success_value| { var success = success_value; success.deinit(std.testing.allocator); return error.TestExpectedPeerReset; } else |err| { const evidence = networkFailureEvidence( err, delivery.load(), ) orelse return error.TestExpectedNetworkFailureEvidence; try std.testing.expectEqual( agent_stream_provider.NetworkFailureCause.transport_interrupted, evidence.cause, ); try std.testing.expectEqual(delivery.load(), evidence.delivery); }
try std.testing.expectEqual(@as(usize, 1), probe.attempts); harness.fixture.deinit(); if (harness.fixture.failure) |err| return err;}
test "TLS setup does not retry after a response made delivery possible" { var harness = try ConnectionSetupHarness.init(.retry_once, false); defer harness.deinit(); try harness.start();
var probe = RequestOpenProbe{ .tls_failure_attempt = 1 }; var delivery = DeliveryCertainty.init(); var cancel_flag = std.atomic.Value(bool).init(false); var callback_ctx: u8 = 0; const result = streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 3, .chat_url = harness.url, .payload = "{}", .delivery = &delivery, }, @ptrCast(&callback_ctx), discardConnectionSetupTestChunk, null, &cancel_flag, null, false, .{ .setup_timing = .{ .timeout_ms = 1000 }, .request_open_override = probe.requestOpenOverride(), }, );
try std.testing.expectError(error.TlsInitializationFailed, result); try std.testing.expectEqual(@as(usize, 2), probe.attempts); try std.testing.expectEqual(DeliveryCertainty.State.possibly_sent, delivery.load()); harness.fixture.deinit(); if (harness.fixture.failure) |err| return err;}
test "TLS setup does not retry after delivery when no certainty sink is provided" { var harness = try ConnectionSetupHarness.init(.retry_once, false); defer harness.deinit(); try harness.start();
var probe = RequestOpenProbe{ .tls_failure_attempt = 1 }; var cancel_flag = std.atomic.Value(bool).init(false); var callback_ctx: u8 = 0; const result = streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 3, .chat_url = harness.url, .payload = "{}", }, @ptrCast(&callback_ctx), discardConnectionSetupTestChunk, null, &cancel_flag, null, false, .{ .setup_timing = .{ .timeout_ms = 1000 }, .request_open_override = probe.requestOpenOverride(), }, );
try std.testing.expectError(error.TlsInitializationFailed, result); try std.testing.expectEqual(@as(usize, 2), probe.attempts); harness.fixture.deinit(); if (harness.fixture.failure) |err| return err;}
test "direct gateway cancellation before admission opens no connection" { var fixture = try LoopbackGatewayFixture.init(.success, 0); defer fixture.deinit(); try fixture.start(); try std.testing.expect(fixture.waitForAcceptStart(5000));
const chat_url = try std.fmt.allocPrint( std.testing.allocator, "http://127.0.0.1:{d}/v1/chat/completions", .{fixture.port()}, ); defer std.testing.allocator.free(chat_url);
var cancel_flag = std.atomic.Value(bool).init(true); try std.testing.expectError( error.Cancelled, streamGatewayCompletion( std.testing.allocator, .{ .api_key = "test-key", .model = "provider/test-model", .retry_count = 1, .chat_url = chat_url, .payload = "{}", }, @ptrCast(&bounded_stream_discard_ctx), discardBoundedContent, null, &cancel_flag, ), ); try std.testing.expect(!fixture.accepted.load(.seq_cst)); if (fixture.failure) |err| return err;}
var stable_models_test_environ: ?*std.process.Environ.Map = null;
fn stableModelsTestEnviron() !*const std.process.Environ.Map { if (stable_models_test_environ) |map| return map;
const alloc = std.heap.page_allocator; const map = try alloc.create(std.process.Environ.Map); map.* = std.process.Environ.Map.init(alloc); stable_models_test_environ = map; return map;}
const ModelsUrlTestEnv = struct { alloc: std.mem.Allocator, map: std.process.Environ.Map,
fn install(alloc: std.mem.Allocator, models_url: []const u8) !*ModelsUrlTestEnv { _ = try stableModelsTestEnviron();
const self = try alloc.create(ModelsUrlTestEnv); errdefer alloc.destroy(self); self.* = .{ .alloc = alloc, .map = std.process.Environ.Map.init(alloc), }; errdefer self.map.deinit(); try self.map.put(e2e_gateway_models_url_env, models_url); io_mod.setEnvironMap(&self.map); return self; }
fn deinit(self: *ModelsUrlTestEnv) void { if (stable_models_test_environ) |map| io_mod.setEnvironMap(map); self.map.deinit(); const alloc = self.alloc; alloc.destroy(self); }};
fn expectCancellableGatewayJsonCancellation( mode: LoopbackGatewayMode, api_key: []const u8, use_tls: bool, cancel_after_stage_ms: u64, hold_ms: u64, max_elapsed_ms: i64,) !void { const zio = io_mod.getIo(); var fixture = try LoopbackGatewayFixture.init(mode, hold_ms); defer fixture.deinit(); try fixture.start(); try std.testing.expect(fixture.waitForAcceptStart(5000));
const models_url = try std.fmt.allocPrint( std.testing.allocator, "{s}://127.0.0.1:{d}/v1/models", .{ if (use_tls) "https" else "http", fixture.port() }, ); defer std.testing.allocator.free(models_url); const env = if (use_tls) null else try ModelsUrlTestEnv.install(std.testing.allocator, models_url); defer if (env) |value| value.deinit();
var cancel_flag = std.atomic.Value(bool).init(false); var request_done = std.atomic.Value(bool).init(false); const Cancel = struct { fn run( server_fixture: *LoopbackGatewayFixture, flag: *std.atomic.Value(bool), done: *std.atomic.Value(bool), delay_ms: u64, ) void { if (!server_fixture.waitForStageOrDone(done)) return; LoopbackGatewayFixture.sleepBlocking(delay_ms); if (!done.load(.seq_cst)) flag.store(true, .seq_cst); } }; const cancel_thread = try std.Thread.spawn(.{}, Cancel.run, .{ &fixture, &cancel_flag, &request_done, cancel_after_stage_ms, }); defer { request_done.store(true, .seq_cst); cancel_thread.join(); }
const started = std.Io.Clock.Timestamp.now(zio, .awake); const result = if (use_tls) fetchGatewayJsonAtUrlCancellable(std.testing.allocator, api_key, null, models_url, &cancel_flag) else fetchGatewayJsonCancellable(std.testing.allocator, api_key, null, "https://ai-gateway.vercel.sh/v1/models", &cancel_flag); const elapsed_ms = started.durationTo(std.Io.Clock.Timestamp.now(zio, .awake)).raw.toMilliseconds();
try std.testing.expectError(error.Cancelled, result); if (fixture.failure) |err| return err; try std.testing.expect(fixture.reached_stage.load(.seq_cst)); try std.testing.expect(elapsed_ms < max_elapsed_ms);}
test "cancellable gateway JSON request closes a held response head" { try expectCancellableGatewayJsonCancellation(.response_head_stall, "test-key", false, 20, 800, 500);}
test "cancellable gateway JSON request closes a stalled request send" { const api_key = try std.testing.allocator.alloc(u8, 32 * 1024 * 1024); defer std.testing.allocator.free(api_key); @memset(api_key, 'x');
try expectCancellableGatewayJsonCancellation(.request_send_stall, api_key, false, 100, 5000, 2000);}
test "cancellable gateway JSON request interrupts a stalled TLS handshake" { try expectCancellableGatewayJsonCancellation(.tls_handshake_stall, "test-key", true, 20, 1200, 500);}
fn readLoopbackGatewayRequest(zio: std.Io, stream: std.Io.net.Stream, fixture: *LoopbackGatewayFixture) !void { var socket_buffer: [4096]u8 = undefined; var reader = stream.reader(zio, &socket_buffer); var request: [16 * 1024]u8 = undefined; var header_len: usize = 0;
while (header_len < request.len) { request[header_len] = reader.interface.takeByte() catch |err| switch (err) { error.EndOfStream => return error.TestRequestClosedEarly, else => return err, }; header_len += 1; if (!std.mem.endsWith(u8, request[0..header_len], "\r\n\r\n")) continue;
const headers = request[0 .. header_len - 4]; fixture.captureRequestHeaders(headers); if (loopbackContentLength(headers)) |content_length| { reader.interface.discardAll(content_length) catch |err| switch (err) { error.EndOfStream => return error.TestRequestClosedEarly, else => return err, }; } return; }
return error.TestRequestTooLarge;}
fn rawHeaderValue(headers: []const u8, name: []const u8) ?[]const u8 { var lines = std.mem.splitSequence(u8, headers, "\r\n"); _ = lines.next(); while (lines.next()) |line| { const colon_index = std.mem.findScalar(u8, line, ':') orelse continue; const header_name = std.mem.trim(u8, line[0..colon_index], " \t"); if (!std.ascii.eqlIgnoreCase(header_name, name)) continue; return std.mem.trim(u8, line[colon_index + 1 ..], " \t"); } return null;}
const keep_alive_sse_payload = "data: {\"type\":\"text-delta\",\"id\":\"answer\",\"delta\":\"ok\"}\n\n" ++ "data: {\"type\":\"finish\",\"finishReason\":{\"unified\":\"stop\"}}\n\n";
/// Larger than the client's transfer buffer, so it cannot all be read ahead/// while the terminal SSE event is parsed.const keep_alive_padding = ":" ** (66 * 1024);
fn readKeepAliveRequest(reader: *std.Io.Reader) !void { var header_buf: [16 * 1024]u8 = undefined; var header_len: usize = 0; while (header_len < header_buf.len) { header_buf[header_len] = try reader.takeByte(); header_len += 1; if (std.mem.endsWith(u8, header_buf[0..header_len], "\r\n\r\n")) break; } else { return error.TestRequestTooLarge; } if (loopbackContentLength(header_buf[0 .. header_len - 4])) |content_length| { try reader.discardAll(content_length); }}
fn writeKeepAliveResponse(zio: std.Io, stream: std.Io.net.Stream) !void { var head_buf: [512]u8 = undefined; const head_events = try std.fmt.bufPrint( &head_buf, "HTTP/1.1 200 OK\r\nContent-Type: text/event-stream\r\nTransfer-Encoding: chunked\r\n\r\n{x}\r\n{s}\r\n", .{ keep_alive_sse_payload.len, keep_alive_sse_payload }, ); try writeLoopbackGatewayBytes(zio, stream, head_events); // Trailing padding arrives late and exceeds the client's transfer // buffer, so the body is provably unread when SSE consumption finishes: // only the client-side drain can return this connection to the pool. io_mod.sleep(150 * std.time.ns_per_ms); var tail_head_buf: [64]u8 = undefined; const tail_head = try std.fmt.bufPrint(&tail_head_buf, "{x}\r\n", .{keep_alive_padding.len}); try writeLoopbackGatewayBytes(zio, stream, tail_head); try writeLoopbackGatewayBytes(zio, stream, keep_alive_padding); try writeLoopbackGatewayBytes(zio, stream, "\r\n0\r\n\r\n");}
fn loopbackContentLength(headers: []const u8) ?usize { var lines = std.mem.splitSequence(u8, headers, "\r\n"); while (lines.next()) |line| { const name = "content-length:"; if (line.len < name.len or !std.ascii.eqlIgnoreCase(line[0..name.len], name)) continue; return std.fmt.parseInt(usize, std.mem.trim(u8, line[name.len..], " \t"), 10) catch null; } return null;}
fn writeLoopbackGatewayBytes(zio: std.Io, stream: std.Io.net.Stream, bytes: []const u8) !void { var buffer: [4096]u8 = undefined; var writer = stream.writer(zio, &buffer); try writer.interface.writeAll(bytes); try writer.interface.flush();}
test "loopback gateway fixture cleanup joins without a client" { var fixture = try LoopbackGatewayFixture.init(.success, 0); defer fixture.deinit(); try fixture.start(); try std.testing.expect(fixture.waitForAcceptStart(1000));
fixture.deinit();
try std.testing.expect(fixture.failure == null); try std.testing.expect(fixture.thread == null); try std.testing.expect(!fixture.server_open);}
fn expectBoundedLoopbackTimeout( mode: LoopbackGatewayMode, payload: []const u8, retry_count: usize, deadline_ms: i64, hold_ms: u64, max_elapsed_ms: i64,) !void { const zio = io_mod.getIo(); var fixture = try LoopbackGatewayFixture.init(mode, hold_ms); defer fixture.deinit(); try fixture.start(); try std.testing.expect(fixture.waitForAcceptStart(5000));
const url = try std.fmt.allocPrint(std.testing.allocator, "http://127.0.0.1:{d}/chat", .{fixture.port()}); defer std.testing.allocator.free(url);
var cancel_flag = std.atomic.Value(bool).init(false); const started = std.Io.Clock.Timestamp.now(zio, .awake); const request_result = streamGatewayRequiredToolCompletionBounded( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = retry_count, .chat_url = url, .payload = payload, }, testAwakeDeadlineAfter(deadline_ms), &cancel_flag, ); const elapsed_ms = started.durationTo(std.Io.Clock.Timestamp.now(zio, .awake)).raw.toMilliseconds();
fixture.deinit();
try std.testing.expectError(error.Timeout, request_result); if (fixture.failure) |err| return err; try std.testing.expect(fixture.accepted.load(.seq_cst)); try std.testing.expect(fixture.reached_stage.load(.seq_cst)); try std.testing.expect(elapsed_ms < max_elapsed_ms);}
fn expectBoundedLoopbackCancellation( mode: LoopbackGatewayMode, payload: []const u8, use_tls: bool, cancel_after_stage_ms: u64, hold_ms: u64,) !void { var fixture = try LoopbackGatewayFixture.init(mode, hold_ms); defer fixture.deinit(); try fixture.start(); try std.testing.expect(fixture.waitForAcceptStart(5000));
const scheme = if (use_tls) "https" else "http"; const url = try std.fmt.allocPrint(std.testing.allocator, "{s}://127.0.0.1:{d}/chat", .{ scheme, fixture.port() }); defer std.testing.allocator.free(url);
var cancel_flag = std.atomic.Value(bool).init(false); var request_done = std.atomic.Value(bool).init(false); const Cancel = struct { fn run( server_fixture: *LoopbackGatewayFixture, flag: *std.atomic.Value(bool), done: *std.atomic.Value(bool), delay_ms: u64, ) void { if (!server_fixture.waitForStageOrDone(done)) return; LoopbackGatewayFixture.sleepBlocking(delay_ms); if (done.load(.seq_cst)) return; flag.store(true, .seq_cst); } }; const cancel_thread = try std.Thread.spawn( .{}, Cancel.run, .{ &fixture, &cancel_flag, &request_done, cancel_after_stage_ms }, );
const request_result = streamGatewayRequiredToolCompletionBounded( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 1, .chat_url = url, .payload = payload, }, testAwakeDeadlineAfter(5000), &cancel_flag, );
request_done.store(true, .seq_cst); cancel_thread.join(); fixture.deinit();
try std.testing.expectError(error.Cancelled, request_result); if (fixture.failure) |err| return err; try std.testing.expect(fixture.accepted.load(.seq_cst)); try std.testing.expect(fixture.reached_stage.load(.seq_cst));}
test "bounded stream admission rejects cancellation before expiry without starting work" { var cancel_flag = std.atomic.Value(bool).init(true); var probe = BoundedProbe{ .alloc = std.testing.allocator, .cancel_flag = &cancel_flag, .mode = .success, };
try std.testing.expectError( error.Cancelled, runBoundedStreamOperation(std.testing.allocator, &cancel_flag, testAwakeDeadlineAfter(-1), &probe), ); try std.testing.expectEqual(@as(usize, 0), probe.request_starts); try std.testing.expectEqual(@as(usize, 0), probe.active_tasks); try std.testing.expectEqual(@as(usize, 0), probe.network_opens);}
test "bounded stream admission rejects expiry without starting work" { var cancel_flag = std.atomic.Value(bool).init(false); var probe = BoundedProbe{ .alloc = std.testing.allocator, .cancel_flag = &cancel_flag, .mode = .success, };
try std.testing.expectError( error.Timeout, runBoundedStreamOperation(std.testing.allocator, &cancel_flag, testAwakeDeadlineAfter(-1), &probe), ); try std.testing.expectEqual(@as(usize, 0), probe.request_starts); try std.testing.expectEqual(@as(usize, 0), probe.active_tasks); try std.testing.expectEqual(@as(usize, 0), probe.network_opens);}
test "bounded stream returns a request result and joins control branches" { var cancel_flag = std.atomic.Value(bool).init(false); var probe = BoundedProbe{ .alloc = std.testing.allocator, .cancel_flag = &cancel_flag, .mode = .success, };
var result = try runBoundedStreamOperation(std.testing.allocator, &cancel_flag, testAwakeDeadlineAfter(1000), &probe); defer result.deinit(std.testing.allocator);
try std.testing.expectEqualStrings("ok", result.completion.content.?); try std.testing.expectEqual(types.ProviderFinishReason.stop, result.completion.finish_reason.?); try std.testing.expectEqual(@as(usize, 1), probe.request_starts); try std.testing.expectEqual(@as(usize, 0), probe.active_tasks);}
test "bounded stream deadline cancels and joins every blocked request stage" { inline for (std.meta.tags(BoundedProbeStage)) |stage| { var cancel_flag = std.atomic.Value(bool).init(false); var probe = BoundedProbe{ .alloc = std.testing.allocator, .cancel_flag = &cancel_flag, .mode = .wait, .stage = stage, };
try std.testing.expectError( error.Timeout, runBoundedStreamOperation(std.testing.allocator, &cancel_flag, testAwakeDeadlineAfter(1), &probe), ); try std.testing.expectEqual(stage, probe.reached_stage.?); try std.testing.expectEqual(@as(usize, 0), probe.active_tasks); }}
test "bounded stream deadline does not depend on async capacity" { const previous_async_limit = std.testing.io_instance.async_limit; std.testing.io_instance.setAsyncLimit(.nothing); defer std.testing.io_instance.setAsyncLimit(previous_async_limit);
var cancel_flag = std.atomic.Value(bool).init(false); var done = std.atomic.Value(bool).init(false); const Watchdog = struct { fn run(flag: *std.atomic.Value(bool), operation_done: *std.atomic.Value(bool)) void { var remaining_ms: u64 = 250; while (remaining_ms > 0) : (remaining_ms -= 1) { if (operation_done.load(.seq_cst)) return; LoopbackGatewayFixture.sleepBlocking(1); } flag.store(true, .seq_cst); } }; const watchdog = try std.Thread.spawn(.{}, Watchdog.run, .{ &cancel_flag, &done }); defer { done.store(true, .seq_cst); watchdog.join(); }
var probe = BoundedProbe{ .alloc = std.testing.allocator, .cancel_flag = &cancel_flag, .mode = .wait, }; try std.testing.expectError( error.Timeout, runBoundedStreamOperation(std.testing.allocator, &cancel_flag, testAwakeDeadlineAfter(1), &probe), ); done.store(true, .seq_cst); try std.testing.expectEqual(@as(usize, 0), probe.active_tasks);}
test "bounded stream traces deadline termination" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const root = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "."); defer alloc.free(root); const trace_path = try std.fs.path.join(alloc, &.{ root, "bounded-deadline.log" }); defer alloc.free(trace_path);
debug_trace.resetForTest(); defer debug_trace.resetForTest(); try debug_trace.configureForTestWithScopes(alloc, trace_path, "stream");
var cancel_flag = std.atomic.Value(bool).init(false); var probe = BoundedProbe{ .alloc = alloc, .cancel_flag = &cancel_flag, .mode = .wait, }; try std.testing.expectError( error.Timeout, runBoundedStreamOperation(alloc, &cancel_flag, testAwakeDeadlineAfter(1), &probe), );
debug_trace.shutdown(); const trace = try readTraceFileForTest(alloc, trace_path); defer alloc.free(trace); try std.testing.expect(std.mem.find(u8, trace, "bounded termination cause=deadline") != null);}
test "bounded stream cancellation cancels and joins every blocked request stage" { const Flip = struct { fn run(flag: *std.atomic.Value(bool)) void { io_mod.sleep(20 * std.time.ns_per_ms); flag.store(true, .seq_cst); } };
inline for (std.meta.tags(BoundedProbeStage)) |stage| { var cancel_flag = std.atomic.Value(bool).init(false); const thread = try std.Thread.spawn(.{}, Flip.run, .{&cancel_flag});
var probe = BoundedProbe{ .alloc = std.testing.allocator, .cancel_flag = &cancel_flag, .mode = .wait, .stage = stage, }; const result = runBoundedStreamOperation(std.testing.allocator, &cancel_flag, testAwakeDeadlineAfter(1000), &probe); thread.join();
try std.testing.expectError(error.Cancelled, result); try std.testing.expectEqual(stage, probe.reached_stage.?); try std.testing.expectEqual(@as(usize, 0), probe.active_tasks); }}
test "bounded stream cancellation wins when observable while deadline cleanup completes" { var cancel_flag = std.atomic.Value(bool).init(false); var probe = BoundedProbe{ .alloc = std.testing.allocator, .cancel_flag = &cancel_flag, .mode = .wait_and_mark_cancel_when_task_is_cancelled, };
try std.testing.expectError( error.Cancelled, runBoundedStreamOperation(std.testing.allocator, &cancel_flag, testAwakeDeadlineAfter(1), &probe), ); try std.testing.expect(cancel_flag.load(.seq_cst)); try std.testing.expectEqual(@as(usize, 0), probe.active_tasks);}
test "bounded stream discards a successful result when cancellation wins before return" { var cancel_flag = std.atomic.Value(bool).init(false); var probe = BoundedProbe{ .alloc = std.testing.allocator, .cancel_flag = &cancel_flag, .mode = .success_and_cancel, };
try std.testing.expectError( error.Cancelled, runBoundedStreamOperation(std.testing.allocator, &cancel_flag, testAwakeDeadlineAfter(1000), &probe), ); try std.testing.expectEqual(@as(usize, 0), probe.active_tasks);}
test "bounded gateway cancellation joins a real TLS handshake stall" { try expectBoundedLoopbackCancellation(.tls_handshake_stall, "{}", true, 20, 1200);}
test "bounded gateway cancellation joins a blocked real request send" { const payload = try std.testing.allocator.alloc(u8, 32 * 1024 * 1024); defer std.testing.allocator.free(payload); @memset(payload, 'x');
try expectBoundedLoopbackCancellation(.request_send_stall, payload, false, 100, 500);}
test "bounded gateway cancellation joins a real response head stall" { try expectBoundedLoopbackCancellation(.response_head_stall, "{}", false, 20, 500);}
test "bounded gateway cancellation joins a real response body stall" { try expectBoundedLoopbackCancellation(.response_body_stall, "{}", false, 20, 500);}
test "bounded gateway progress does not extend the absolute deadline" { try expectBoundedLoopbackTimeout(.response_body_progress, "{}", 1, 250, 300, 1500);}
test "delivery certainty stays definitely unsent when request setup fails" { var delivery = DeliveryCertainty.init(); var cancel_flag = std.atomic.Value(bool).init(false); const result = streamGatewayCompletion( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 1, .chat_url = "not a valid URL", .payload = "{}", .delivery = &delivery, }, @ptrCast(&bounded_stream_discard_ctx), discardBoundedContent, null, &cancel_flag, ); if (result) |value| { var owned = value; owned.deinit(std.testing.allocator); return error.TestExpectedGatewayFailure; } else |_| {} try std.testing.expectEqual( DeliveryCertainty.State.definitely_unsent, delivery.load(), );}
test "delivery certainty becomes possibly sent before response head" { var fixture = try LoopbackGatewayFixture.init(.response_head_stall, 500); defer fixture.deinit(); try fixture.start(); try std.testing.expect(fixture.waitForAcceptStart(5000)); const url = try std.fmt.allocPrint( std.testing.allocator, "http://127.0.0.1:{d}/chat", .{fixture.port()}, ); defer std.testing.allocator.free(url);
var delivery = DeliveryCertainty.init(); var cancel_flag = std.atomic.Value(bool).init(false); try std.testing.expectError( error.Timeout, streamGatewayRequiredToolCompletionBounded( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 1, .chat_url = url, .payload = "{}", .delivery = &delivery, }, testAwakeDeadlineAfter(20), &cancel_flag, ), ); try std.testing.expectEqual( DeliveryCertainty.State.possibly_sent, delivery.load(), );}
test "server error response preserves billing ambiguity" { var fixture = try LoopbackGatewayFixture.init(.retry_once, 0); defer fixture.deinit(); try fixture.start(); try std.testing.expect(fixture.waitForAcceptStart(5000)); const url = try std.fmt.allocPrint( std.testing.allocator, "http://127.0.0.1:{d}/chat", .{fixture.port()}, ); defer std.testing.allocator.free(url);
var delivery = DeliveryCertainty.init(); var cancel_flag = std.atomic.Value(bool).init(false); var result = try streamGatewayRequiredToolCompletionBounded( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 1, .chat_url = url, .payload = "{}", .delivery = &delivery, }, testAwakeDeadlineAfter(1000), &cancel_flag, ); defer result.deinit(std.testing.allocator);
try std.testing.expectEqual(std.http.Status.service_unavailable, result.status); try std.testing.expect(result.completion.delivery_ambiguous); try std.testing.expectEqual( DeliveryCertainty.State.possibly_sent, delivery.load(), );}
test "bounded gateway retry sleep uses the original absolute deadline" { try expectBoundedLoopbackTimeout(.retry_once, "{}", 2, 250, 0, 1500);}
test "generation lookup cancellation interrupts TLS setup" { var fixture = try LoopbackGatewayFixture.init(.tls_handshake_stall, 1500); defer fixture.deinit(); try fixture.start(); try std.testing.expect(fixture.waitForAcceptStart(5000)); const origin = try std.fmt.allocPrint( std.testing.allocator, "https://127.0.0.1:{d}", .{fixture.port()}, ); defer std.testing.allocator.free(origin);
var cancel_flag = std.atomic.Value(bool).init(false); var request_done = std.atomic.Value(bool).init(false); const Cancel = struct { fn run( server_fixture: *LoopbackGatewayFixture, flag: *std.atomic.Value(bool), done: *std.atomic.Value(bool), ) void { if (!server_fixture.waitForStageOrDone(done)) return; LoopbackGatewayFixture.sleepBlocking(20); if (!done.load(.seq_cst)) flag.store(true, .seq_cst); } }; const cancel_thread = try std.Thread.spawn( .{}, Cancel.run, .{ &fixture, &cancel_flag, &request_done }, ); const started = std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake); const result = fetchGatewayGenerationResult( std.testing.allocator, "test-key", null, origin, "gen_01ARZ3NDEKTSV4RRFFQ69G5FAV", &cancel_flag, ); const elapsed_ms = started.durationTo( std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake), ).raw.toMilliseconds(); request_done.store(true, .seq_cst); cancel_thread.join(); fixture.deinit();
try std.testing.expectError(error.Cancelled, result); try std.testing.expect(elapsed_ms < 1000);}
test "gateway retry sleep rejects cancellation before waiting" { var cancel_flag = std.atomic.Value(bool).init(true); try std.testing.expectError( error.Cancelled, sleepGatewayRetry(std.time.ns_per_s, &cancel_flag), );}
fn expectDirectLoopbackCancellation( mode: LoopbackGatewayMode, payload: []const u8, cancel_after_stage_ms: u64, hold_ms: u64, max_elapsed_ms: i64,) !void { const zio = io_mod.getIo(); var fixture = try LoopbackGatewayFixture.init(mode, hold_ms); defer fixture.deinit(); try fixture.start(); try std.testing.expect(fixture.waitForAcceptStart(5000));
const url = try std.fmt.allocPrint(std.testing.allocator, "http://127.0.0.1:{d}/chat", .{fixture.port()}); defer std.testing.allocator.free(url);
var cancel_flag = std.atomic.Value(bool).init(false); var request_done = std.atomic.Value(bool).init(false); const Cancel = struct { fn run( server_fixture: *LoopbackGatewayFixture, flag: *std.atomic.Value(bool), done: *std.atomic.Value(bool), delay_ms: u64, ) void { if (!server_fixture.waitForStageOrDone(done)) return; LoopbackGatewayFixture.sleepBlocking(delay_ms); if (!done.load(.seq_cst)) flag.store(true, .seq_cst); } }; const cancel_thread = try std.Thread.spawn(.{}, Cancel.run, .{ &fixture, &cancel_flag, &request_done, cancel_after_stage_ms, });
const Noop = struct { fn onChunk(_: *anyopaque, _: []const u8) void {} }; var callback_ctx: u8 = 0; const started = std.Io.Clock.Timestamp.now(zio, .awake); const result = streamGatewayCompletionCore( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 1, .chat_url = url, .payload = payload, }, @ptrCast(&callback_ctx), Noop.onChunk, null, &cancel_flag, null, true, ); const elapsed_ms = started.durationTo(std.Io.Clock.Timestamp.now(zio, .awake)).raw.toMilliseconds();
request_done.store(true, .seq_cst); cancel_thread.join(); fixture.deinit();
if (result) |value| { var owned = value; owned.deinit(std.testing.allocator); return error.TestExpectedCancellation; } else |err| { try std.testing.expectEqual(error.Cancelled, err); } if (fixture.failure) |err| return err; try std.testing.expect(cancel_flag.load(.seq_cst)); try std.testing.expect(elapsed_ms < max_elapsed_ms);}
test "direct gateway cancellation closes a stalled response body promptly" { try expectDirectLoopbackCancellation(.response_body_stall, "{}", 20, 800, 500);}
test "direct gateway times out only while awaiting the response head" { const zio = io_mod.getIo(); var fixture = try LoopbackGatewayFixture.init(.response_head_stall, 500); defer fixture.deinit(); try fixture.start(); try std.testing.expect(fixture.waitForAcceptStart(5000));
const url = try std.fmt.allocPrint(std.testing.allocator, "http://127.0.0.1:{d}/chat", .{fixture.port()}); defer std.testing.allocator.free(url); const Noop = struct { fn onChunk(_: *anyopaque, _: []const u8) void {} }; var callback_ctx: u8 = 0; var cancel_flag = std.atomic.Value(bool).init(false); var delivery = DeliveryCertainty.init(); const started = std.Io.Clock.Timestamp.now(zio, .awake); const result = streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 1, .chat_url = url, .payload = "{}", .delivery = &delivery, }, @ptrCast(&callback_ctx), Noop.onChunk, null, &cancel_flag, null, true, .{ .response_head_timing = .{ .timeout_ms = 80 } }, ); const elapsed_ms = started.durationTo(std.Io.Clock.Timestamp.now(zio, .awake)).raw.toMilliseconds();
fixture.deinit(); try std.testing.expectError(error.Timeout, result); if (fixture.failure) |err| return err; try std.testing.expectEqual(DeliveryCertainty.State.possibly_sent, delivery.load()); try std.testing.expect(elapsed_ms < 500);}
test "direct gateway response head timeout does not limit a delayed SSE body" { const zio = io_mod.getIo(); var fixture = try LoopbackGatewayFixture.init(.response_body_delayed_success, 150); defer fixture.deinit(); try fixture.start(); try std.testing.expect(fixture.waitForAcceptStart(5000));
const url = try std.fmt.allocPrint(std.testing.allocator, "http://127.0.0.1:{d}/chat", .{fixture.port()}); defer std.testing.allocator.free(url); const Noop = struct { fn onChunk(_: *anyopaque, _: []const u8) void {} }; var callback_ctx: u8 = 0; var cancel_flag = std.atomic.Value(bool).init(false); const started = std.Io.Clock.Timestamp.now(zio, .awake); var result = try streamGatewayCompletionCoreWithOptions( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 1, .chat_url = url, .payload = "{}", }, @ptrCast(&callback_ctx), Noop.onChunk, null, &cancel_flag, null, true, .{ .response_head_timing = .{ .timeout_ms = 40 } }, ); defer result.deinit(std.testing.allocator); const elapsed_ms = started.durationTo(std.Io.Clock.Timestamp.now(zio, .awake)).raw.toMilliseconds();
fixture.deinit(); if (fixture.failure) |err| return err; try std.testing.expectEqual(std.http.Status.ok, result.status); try std.testing.expectEqualStrings("ok", result.completion.content.?); try std.testing.expect(elapsed_ms >= 100);}
test "direct gateway cancellation closes a stalled request send promptly" { const payload = try std.testing.allocator.alloc(u8, 32 * 1024 * 1024); defer std.testing.allocator.free(payload); @memset(payload, 'x');
try expectDirectLoopbackCancellation(.request_send_stall, payload, 100, 5000, 2000);}
test "direct gateway fails fast when cancellation watcher cannot start" { var fixture = try LoopbackGatewayFixture.init(.request_send_stall, 1000); defer fixture.deinit(); try fixture.start(); try std.testing.expect(fixture.waitForAcceptStart(5000));
const url = try std.fmt.allocPrint(std.testing.allocator, "http://127.0.0.1:{d}/chat", .{fixture.port()}); defer std.testing.allocator.free(url);
test_cancel_watcher_spawn_error = error.TestCancelWatcherSpawnFailed; defer test_cancel_watcher_spawn_error = null;
const Noop = struct { fn onChunk(_: *anyopaque, _: []const u8) void {} }; var callback_ctx: u8 = 0; var cancel_flag = std.atomic.Value(bool).init(false); const started = std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake); const result = streamGatewayCompletionCore( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 1, .chat_url = url, .payload = "{}", }, @ptrCast(&callback_ctx), Noop.onChunk, null, &cancel_flag, null, true, ); const elapsed_ms = started.durationTo(std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake)).raw.toMilliseconds();
fixture.deinit();
try std.testing.expectError(error.TestCancelWatcherSpawnFailed, result); if (fixture.failure) |err| return err; try std.testing.expect(elapsed_ms < 500);}
test "direct gateway core callbacks stay on the invoking thread" { var fixture = try LoopbackGatewayFixture.init(.success, 100); defer fixture.deinit(); try fixture.start(); try std.testing.expect(fixture.waitForAcceptStart(5000));
const url = try std.fmt.allocPrint(std.testing.allocator, "http://127.0.0.1:{d}/chat", .{fixture.port()}); defer std.testing.allocator.free(url);
const CallbackCapture = struct { expected_thread: std.Thread.Id, observed_thread: ?std.Thread.Id = null, chunk_count: usize = 0,
fn onChunk(raw: *anyopaque, _: []const u8) void { const self: *@This() = @ptrCast(@alignCast(raw)); self.observed_thread = std.Thread.getCurrentId(); self.chunk_count += 1; } }; var capture = CallbackCapture{ .expected_thread = std.Thread.getCurrentId() }; var cancel_flag = std.atomic.Value(bool).init(false); var result = try streamGatewayCompletionCore( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 1, .chat_url = url, .payload = "{}", }, @ptrCast(&capture), CallbackCapture.onChunk, null, &cancel_flag, null, false, ); defer result.deinit(std.testing.allocator); fixture.deinit();
if (fixture.failure) |err| return err; try std.testing.expectEqualStrings("ok", result.completion.content.?); try std.testing.expectEqual(types.ProviderFinishReason.stop, result.completion.finish_reason.?); try std.testing.expectEqual(@as(usize, 1), capture.chunk_count); try std.testing.expectEqual(capture.expected_thread, capture.observed_thread.?);}
test "non-streaming gateway request sends extended time header" { var fixture = try LoopbackGatewayFixture.init(.success_capture, 0); defer fixture.deinit(); try fixture.start(); try std.testing.expect(fixture.waitForAcceptStart(5000));
const url = try std.fmt.allocPrint(std.testing.allocator, "http://127.0.0.1:{d}/chat", .{fixture.port()}); defer std.testing.allocator.free(url);
var result = try postGatewayCompletion( std.testing.allocator, "test-key", "test/model", 1, url, "{}", ); defer result.deinit(std.testing.allocator); fixture.deinit();
if (fixture.failure) |err| return err; try std.testing.expectEqualStrings( vercel_gateway_extended_time_value, fixture.capturedHeaderValue(vercel_gateway_extended_time_header).?, );}
test "gateway chat request sends extended time and attribution headers" { var fixture = try LoopbackGatewayFixture.init(.success_capture, 0); defer fixture.deinit(); try fixture.start(); try std.testing.expect(fixture.waitForAcceptStart(5000));
const url = try std.fmt.allocPrint(std.testing.allocator, "http://127.0.0.1:{d}/chat", .{fixture.port()}); defer std.testing.allocator.free(url);
const Noop = struct { fn onChunk(_: *anyopaque, _: []const u8) void {} }; var callback_ctx: u8 = 0; var cancel_flag = std.atomic.Value(bool).init(false); var result = try streamGatewayCompletionCore( std.testing.allocator, .{ .api_key = "test-key", .model = "test/model", .retry_count = 1, .chat_url = url, .payload = "{}", .session_id = "session_wire_123", }, @ptrCast(&callback_ctx), Noop.onChunk, null, &cancel_flag, null, false, ); defer result.deinit(std.testing.allocator); fixture.deinit();
if (fixture.failure) |err| return err; try std.testing.expectEqualStrings(user_agent, fixture.capturedHeaderValue("user-agent").?); try std.testing.expectEqualStrings("https://github.com/vercel-labs/fx", fixture.capturedHeaderValue("http-referer").?); try std.testing.expectEqualStrings("fx", fixture.capturedHeaderValue("x-title").?); try std.testing.expectEqualStrings( vercel_gateway_extended_time_value, fixture.capturedHeaderValue(vercel_gateway_extended_time_header).?, ); try std.testing.expectEqualStrings("session_wire_123", fixture.capturedHeaderValue("x-session-id").?); try std.testing.expectEqualStrings("session_wire_123", fixture.capturedHeaderValue("x-session-affinity").?); try std.testing.expect(std.mem.find(u8, fixture.capturedHeaderValue("user-agent").?, "zig") == null);}
test "host-managed Gateway chat omits authentication-owned headers" { var fixture = try LoopbackGatewayFixture.init(.success_capture, 0); defer fixture.deinit(); try fixture.start(); try std.testing.expect(fixture.waitForAcceptStart(5000));
const url = try std.fmt.allocPrint(std.testing.allocator, "http://127.0.0.1:{d}/chat", .{fixture.port()}); defer std.testing.allocator.free(url);
const Noop = struct { fn onChunk(_: *anyopaque, _: []const u8) void {} }; var callback_ctx: u8 = 0; var cancel_flag = std.atomic.Value(bool).init(false); var result = try streamGatewayCompletionCore( std.testing.allocator, .{ .api_key = null, .model = "test/model", .retry_count = 1, .chat_url = url, .payload = "{}", .team = null, }, @ptrCast(&callback_ctx), Noop.onChunk, null, &cancel_flag, null, false, ); defer result.deinit(std.testing.allocator); fixture.deinit();
if (fixture.failure) |err| return err; try std.testing.expect(fixture.capturedHeaderValue("authorization") == null); try std.testing.expect(fixture.capturedHeaderValue(vercel_ai_gateway_team_header) == null); try std.testing.expectEqualStrings(user_agent, fixture.capturedHeaderValue("user-agent").?);}