From 04ad786998e9ec2683ba8c387aaf311adc6f1233 Mon Sep 17 00:00:00 2001 From: Won Park Date: Fri, 9 Oct 2026 18:16:14 +0000 Subject: [PATCH] Add retention annotations to submitted tool outputs (#52671) ## What changed Add `TurnInput::AnnotatedResponseItem` with a caller-supplied `retain` annotation. For function-call outputs, `retain: true` sets `client_authored` history metadata while keeping annotations out of model requests. Accept annotated items through the existing turn submission paths, including continuation. ## Testing Add an integration test covering retention metadata during turn start, steering, idle submission, and rollout storage. Verify that ordinary outputs remain unmarked and model requests contain neither `retain` nor `client_authored`. GitOrigin-RevId: 7285dde31149b17b0dcf31d4ea1c7cba66d9efe6 --- .../app-server-exports-stable.json.zst | Bin 159214 -> 159235 bytes codex-rs/core/src/session/turn_input.rs | 39 +++++- .../core/tests/suite/turn_input_submission.rs | 120 ++++++++++++++++++ codex-rs/history/src/lib.rs | 2 +- codex-rs/protocol/src/turn_input.rs | 17 +++ 5 files changed, 171 insertions(+), 7 deletions(-) diff --git a/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-stable.json.zst b/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-stable.json.zst index 96be2b38651649623a7bf1300907a8cc62436ed6..bf9172bec20a6692102d6fbbe7f0453335f2c1d1 100644 GIT binary patch delta 21834 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%0D+PT*E4{IQoZ)@n3OmV^ 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 Jxfj!|{|`ru%sBu6 delta 21813 zcmV(wKn^URpvT_{B(EAw|&fMnageU z*qT>jD%g_J3d9Uu=4xkiz|E#?DrrDWuo|%lMgd$QMX{;S7wbYxy@;aNf3v26$GXer z_|)>iYJMQ*@&qLgv#Tx?en0n`r36{xmOpEGPj{|kkN&*>Pyg?p&vwx=(60x)5=1nv z#7;}}dcC8c*`z4unX31c&HG$FYV+xp>l9Cxf?9hf)<8mPTh>jd)mtg+pbmRK4CNMF zHi$bXE$!26+H88|YKb!-e~Arogsn#C<$f($%&y|YC22I6PD5z8EN|(K5{J=(IO(ib z6}#rrV`&0#(NEtuZ+4egyPvDJ+##2by_I>at{!%UU#Pyma|#*fX}FFwx7Rw#g|lHc`XeV)e-G!&dBd zzo!}Og1`0;w@>|yf9vB=gVD|8T+PxW@KOk4pm(OMHK4F(`S;KnvCaKJ0G>r%U`B#+ z`}ZJHdJJ)8rL({)#Vfc_2?tI<6m4C-H`GyC6fNS-*tUGYGCe%nv5w_H^eX^bhD9$` z&hBm$nn$(lSp1xz8=gpes6&cL?-0S5e*e4)`-)gH5BXt zj_m63#C8*Ye>$eAh#Eb}0@)vFP{GY+FGUgIRf}hc6Il~M**;~!<^Qmlq|~)or`*Wq1*CNC@YC*kQy=t6d>iCfO8_IkEp2=4AKr4B{&T5Ry4Qv=+uPLIm9Ahcwo zoA)lE)R3dZzURq~BxUEohU8V!%!O${VN6?dexT0`AFIWR< zw1$iP6dx{lrc!eai7*B7xF8(QtG|nuW0~u+l>N1hMdJnB@JFWP z1=UA~g(>jy)r1A%poYVTyl<1WWTe4NT^I#mTQL4^4It@Mf-U9$f3X6_l$a?Mpnp=c zf4W;P)P3j*xLv`>WF|m)btSZw%(#q`)tu8ZYPgX`;?6t!&WC*GZwOKsv0)UK%hj=* z;#jFG3mIe$uqB1-k@7)l`1D)GV3ZCcnyS27fTeyhix`e^PZc zMD3Sh!*7do9>AWQ!y#8rzFQxHB!SQcoCl0?JLsdoT3}?1sqjOM&jl9VT$LS?eM@@7 zu%H>if()K--_C|mP^}>eS>19-j3Y=+t9ovhiG+4lM@qiodB?vFb=vO80#{rLhZuEN zs5ErY4uh@Q8=k?Rm*5nARl8ene-G705AXi7kzyK1v5kl&jJ;TchFjI2Q7xHnO_w~) zU*V?!z`aLSILQ4u4)Nj8Z>74yrPh`)fHaT##5LxbvB;1 z;1`8=`6BplDnSvVYdn1x7E3AHsat%$Q~Qg|b{e8e7_C@?3>(KLkX_9S;)bQ4gC;Z> zV1=l58htH=VB4ffv!-_%drljTmJ9X0RtkE|2r=3_Fd&x>g#(wKf3#ra{Cc4D#*b$# zXn|7$g{V#Z#5g!@WoVXM(RyQ#!pP{)P64mbK7G9^sm{`E8x-Ad-n z_jx$_`d2f2hd}T2f7OiPXRya0cZb%yWukaYAgkHn0Bl$HNwk1ygY3TU#zUKVTXvv$ zpH9s`1IftAMV^zaDY!at?a^`zdJ0-RjEaBWC!O$%wh>!3M_7KC+{C3dQXDGrtBmN!C&rOR7rTkO-KJ9 zno%v#7t+0Oe=5#{ZX1y)6_A4@P)fWM}8(xQe4xxF~d1dLk&JJVDIHp8GDfA^F#V1U`JVbk%uPNM3xSP`y< zq>~W*)w{N1DYt+UOSz?eU$}RrpijK%?6CUkS?(O-1W=IBs)v>*FRGbgZkeuhiSR(i zQ(YusPK%W~wd}Op_O-M&q?idleLh$857?@wFFWhGDeL?1&Sg=bmWGnPviyRF67!uw zUAnn|mCm6BKSpZ`Ol3b4>?lA$yw{4Z0^1BfC)uimv zt5#}qOXZZc{5+-&6Dz3Jq9&A4$x>9{tp)KaXJZV`a`$_w)Tu z3fn1Vwrhe1QkvD_T|~R3$2N~bub5wjraB*mLA}Z?8s^73myM9rQ(JVe%OX@x89gwX zX>wA0K@*(~+6uj$f{(v9jzdV@Lem2ZLo{?8mDhi!0(xsV7fn&9;LnDH|AaMkau#iX ze^uhe!a07_j(HfNj9mE2e%$egw^iqDm=O1MU_pjHs~{Be^i--~S(eHYWLmbi((Hr) zBw9H8x+DNwSF*2gxNLYY?2IZj_21Jb@gNyI|6i)>u;#iQ|L}Cr!wUNvkWLd3v?mm1Y~FK<_B4qP1)9Ae~iBc*A#GGYyc3*)DbnX*+XsQ{qfI`JR{Td zA;wgb$t4v-L#c1pdQY~u@+og!J#KxfWn*4Yjo4AOMxZDYaSV;~!7 zGDz2!w6OS1XYaCkrT?*@)htBq1OvWA#`&pL$I)#X=`tH5UXz&8;hEe zl3Zi|AVsHDq4}dZrG^0EKgaB$%8ph0p2JB7m;rHhX>;mrZF%x}3rZtGn+_`zpXIJB z_pQBktm&|^PBk4CA>oBIct)VDe>5GIB64b>Q5g#z-G%I7#pdG6gG`4$mT$i0?86CpPk-VBm#-2x(9k!s3&A+0y4{xQqL3K3_H2!SU_x2F`rEpS5GPVT89( zO8`o(*okL7nY~=k--BA_69qFEx*a;r>MRRU(?nhp?KaDye>(;^vk`=@==_wC+-L;R zy`ky8-xb7UQt2V%rGk5TCh>8qTMR2{BtPgdWw3c*ZbDIr*lBJOVVw=c<3;5!T34i& zx_3+ShRc5SqW}aE;uWe=QI}6$Z=|9FP`&iB{KMH9rnXDfhI#pjc2PJiJA$MQaJ?|! z*m%|E3bJO$e>92pK~sV~Bhq%VQA;pr)UxcpzQRDxcNm&)$x;be`&Wz} zX^1g|D*Ar6$H~uTUPPe_&bNBO(vfEViH!bSQbLbiL|#nICYpqxNag3cx+Yk_tYgcnB(0ZwvCMAmFR zD1l-N04+au$wCX7YZr%>u!xX653K*6U&%ZAqwV1S$#ccPwtqgS`sk!a58HRLt%Tau z+{Xilf4BF24hASa%rd~b&Rs<~I-~qlAA!s*eP$)~9wAy4X*J~HsIe+&V%b)5D1$=y zw)kV-C92NslXeiE12vX7MR{*Xm*j1<4nI+A<}sVzS?bub@M1CZ zKq%3VerD}PQu%rmVCi~3B~XW<!a=&5P0BeaB4i${ZbQuHqG^DPD5p?}MLDrbm>d!qYDqqRwojPAPC0V& zxv`&9AK3+i($T5qYEu?|N&$%z9Gii$Q>)kSr^IqG5mJ1{PiQG|=H+|K(VRID>5)idRlpsHg<+AgS|P^2nt7-7 zUU|u8gUaS|=T2+Wv2t9OIV%DZfBGav&rbN3gY`+rRvV~Pvl^{6uKwCyvR0d)=hHuo z@jGoiHhQ%2nF_@0z+npJVQcZ3QRp`FdBU1O%zASE%KQQsl@}HnzueGbU#&4u^#s_JQ;P5kdHNJnWD^eI&Q(+KfG)k!D2FhqCwNSAl~a-j5-{DURIs5 zue@fWY6S*=MYX+Z*nJ6t(p3^9KaN&`f?9uJ$a#W^Vz*O^V6__I3|;(eDqq=uoKEz4 zcLTFMKf1*Sl9)?m;YhAm1_jF>GPRYCkw1}EV$;NcM*Lx&KcbJ>oZ+&WA#efB<^Mba1?3VKq=-F2(HyT*Af&EtGf0B<$ zFZUp~Vv==ZRl^t=XAbm#X-e?rFUeG1I7ml-;zLxg@gOjpUAKh&lP0xbR!CS)dI|do z*|t0-^0RP6;81+xLmO#|kvq|DC0=(?IOs8?#uzH8dz~%|Qmj7ciA{+D>}{T$%?yKb zQed`rzqfa%bIofo0tyy2T!_tPUHYqLvwBil9(qWH&#=bu_{x8wo<^%^|;2 z#&LZ3lL0DRE5-CRkdpD6svJ)gw37$&of#F3dx>{iPsfT>qfO;eY{e=;?U3G@ z$5sh$kA$}&F3b8;Wq)~IsAc|a`I`|9--0nMVx9Z?@#w^Vab<%-#0W$+j27MUydMkB zo~8H)lC}=Yj|P$gHuO>oNE#@E>)^|iKEOd7QX@l%d{_k^61Y6jTxszqLKs;vG9C%LeQ8WjCVhuM548k`QIaf-ObVd&?VyE}S zmWQa(l|-rZCw;l^ZMN^jx>#mQ@aZ7`3smTwm`M$hA~h)AfiFKGkU>UV_9%?uK;y)4 znqft@$#Z!%|Fw990{4Md0YuBU7L$BqmwajFhRTV+_wH5iClH*LYo5#7QIh*o7{^sf zYY-fNlu{sc=zJok)cq&M=Ws*`gmC6Xb$&t}cSE&6tFiuIEYN$u#+*yv9yq?2qCBe+ zSxr~Y1I;4BAkjgCoENF*OFxwC!wup;0FZ7KgV_Y154LytCoC;dDkG3-JAU$Xl1;Qe#0j)3Q;BV({T zBg92ga}=R3{V2*GQK^W6=fW^?qsYaY;8MG9D2<0f_x|G+!_`1&7E znBG2F8TSGD*o8Y^kZV29+pDL*nn&55+SR8R*c&Zt#J}kiV8*u&r)LDH5;Ki|8%aCE z%x30IIYXA-2QdHy?`<*v0cg|~Sx%@6zz99(5bAwWjF5+7KvW@=2>^O>T>w20wjRRN- zftmU=@V@9(mAN1N7(XZ|lK6l#`WvW>ivwO)nEY={aHDg&)gI`XwXevZ>a}G~_2|S} z#LqZo$!y_kfGVwi6-9 zLkHUq3*nyxbhO_tqXK&SWq-&arH!YIrqir`wi#Jy!;!+2GKxhg#Z(Voq~ohn>4F48 zm4&BSHe0RlX!-;E2F>v9H*Hi6QFt@(geM885yV?l8W4jdp5AJIN9m>6q>m|V4*r9| z?L%%rs}$vPuaq$+3KPKPcW90c?KBh)f*q8mP4Q>PFBd5e8yp;lfDGK)@T`9RBxeos z&!2AeoC3uCXKRXVU<46R4D9?k!)rUYP?kRaiXGxYjW{1;vz4baD7j?;kGT8)Bi%dc zm|`u^;aket6;-l-RgsoI_4MZqV&!6sp|Y+>2&7mA(#+lz*^^wTjJLz6E2FtKTX%#I z{J(^3J@R!xWpULwP1!V-J>!^9+iy`u#<8r8`VN>Jw-3hzxO)*!xrSB0Qj0b5#PQ-N zxBgOMQ16>*$qQ(>ZLEdqBf7ofoxlst`kX!u92;^)OpxV&*9?B79_r(=mZB3)A>L_4 z^YY8l-RHr*V-ZlUQtdt<<>$yl2M-*N5DkN~HS1Tjns>1oo4nfu9}JgL!-G5ff%L3? z8qV|n`*L(_RzJzBDqDl7>smIbcPF<@(pa#h0d)!TndGyhdYe#n`k~+r@@O?J@;%kv+%y4k3zEkh8?=RAr5XG6x{%($8ns$MXO=xP;hkq9@wE-YoLm?0v zk8SjWuf{EZSW_$hq;6$8lhJneq$Z%&bp?6cC-^RZ8zNY?m;6C5=nUlzz$n>B2)SHN zc~S#uDh=S#$Dsd~B!shk5C2xdoEDDIyw*xBj1U*FQ8MIjGT=&LH94vgZSH{}`C5g^ z{=pd`xb7naWB8{z{WtP#nG@HEutM?04E17xSl1A~MgCCrjiw=9Gt#Y!sU8(9IU&*@ z;(`u;G`6OR)ZQT6D2SSXQJw@9Y_>-#Q=x%5%97NUq?{_i!z$mpH_iN{YR4Ehjew`M z0Uy>{cgUQ5kD_gPWTpx*_+8hTzQPPK5`Xe|NOnF_twRGd>C zHu6er9!VgC>{g*rZU@^T8ezW<{CXm9<1eLu1htTN31R!ilMH6milrA=Bh(&Or~H*Msb3ugR_M2; zS0SRmvxNteWY`RG3-YrVc@pI(fj(BZ3*&Ceubm)58DQXp$0@**S)_nu2+%N(43ces zF8C{1a{K~2nLt+kiwxT53IhnI1Dkp^!r@QPruA`%64?=G$e$QvfGPY3Y`=aTuhh+w zl=335y38>vH*7fPdJ!czXGD5*GY7T229LSzZ&w`zFFU;!`GhgoCkgvGf`lK(LnjI6 z2wh$QqZv`+V^}oN-FVfr{M#`t|C647;MT{H6f#`Puofibi~AQ>OW;UhEas%vSH%Qp zLnevbOK{pyPgiNlcjj3X+AVZZR@5<+W)X&Zan0yAA_?(16Utkio~+ z*V0zf+iP~`%)&_?JK=n){k$Q6mlaO;f+x8q2_0jq2-9=xY;NmyZHgcd`_Qg8OxIbb z-A5|#oh;{Zt%*Qcz5wuNk%7_*F`#UcTOsWtl>xbK)5-y7H|K&jZ1O^XEjAi%_~jLq_ke~7 zY$P0LUnguYh}oq^(RRmaDnk3RRHmMf=|Q%wu)$CG$UPvW&snrffg@+olJ?bYO4uU# zx0zlbwZ`uh-2N`MO4;(j$O{PwB!!7{nqa;ay2oZYOXL2vLBnawHgJ9LEEulS!7S%y zEa@P@m<)$Pk4j&EKyc42C|A)2$#SzKT%KG=9s9cODZ@jU5jTWTxE=mX-pU8}idjVP ziX4<)S2gcaih8cPeM4)!;ZN7m(>mQW({w?LUKmMms6`Yq0v%`uDubKGhc*{KGg4gt zU*ppGR%yIAirr!)^}S~qs+AU+Nesh_ZP%%LQTS<0-cB5U^s7P&^G&Y$LT6agy9jB@ zV`?h7?x8BaCxl?(%wAM4Fjt>*HI|FCwD=IZY0eOM`11vVBOg*duA{X zZ_r)wlXl7x$sV@S*3*WW=vXLwCZX*}B~tw9meHnIJ`d-d)Q#P(Ym<%1ww#j$*4ZG_ z4Gtai48L!G=M$YEA^-I4o4?;?y!5srAEA_wF=LQJF!ClVZpH-nbijezjvL}0d8m8^ z9Se16sXbVxtp2mS{(zhNnA4NG0V-9-aI&CKF=vOIok66yV>Dd8LH*VQ0ur8lN@$)u zH0TQcGO7k98uSP@Ih`_c1}-yaMRyz9Byx8=3hust_@sg_6l%*XBxdp?MVe|7(>3Og z-}Z!+N7^=av{=m^Zv@jU&PuMl)o{3%WVau<{0m4dmsUb0WEyuDlLY+};dxhjiyugX@&Krpu_9tpU8Y$O_f$ z242Ykq6T!dZ-#ZSlkbM;|Hs4lr8N6qA!8wk+ruRq8AC7iW_oqYy{ zyfY<3Bp%sGh8wtzhMqja*8Zs;!j^u@wiu!0Rg8oGxPW=lO`Rd=20={*p(e>iF z-Q*NJgB_%rqrwcPT(kBsgW59xxic0kCGK+b}LW?u1rA} z27tfROZX`oVPDiv*2>7_;=}(eO5CLSjN~HH?9eGi-T=Fx%HY5sVb=u>nC195y*-5; zvq&PYiCbTy2AjlCuH*Umru-ZUweh8YW9w0oP)%l+`bR*9K)9Jw*}l6#*#PkFASZ4G zMk>1LIRxTHw#Gfco4idyz-36|^Wm*4nkIqVy#B#{Cn{g1sD8{R2Z&wTZ&w*&c0jRV zGKC9y`S=2NCA*)CZoyx8gifo3t$I+~G>rnW|MrRGr=)+KB63m2Fg6NdmI6J0&h>?m z;*f=VI%B1V(4x>WgX#TJ^yAcYpI#jwKJ*?5tn}hj{TWnJ!7cQdYY6R&&Vy zMNZmeyiNo#X$_s`<4R-1&nj<(f_L`@)0`8bm#Vb59im@Oqig4PD6UbDi5bA*2_%dX z_(|mB8_mc@We!1{s{QiBLr;l+f(3X&1IzMgy?(%G9Q)K4)s!g6lkN^=C_)j~Fl>Ud z0WP&5aWX7NF06^J>D4-p!io<#VM@CFRdQ1iKxJ9Xz{ZXKVwrg$hs}`3&L6ZGV+yo# zZEdWuIth=7+aQqMFK?_g0{36fUG_H}kE`qyP*F&wUsL^9Rq_&WD99Rr3Z+NMNDG_D z+an5Y=zcV~lYTnbehnDR*?FhW}rWea@zl)%(_Rv$@^>gcya(Ux$Cfpg;m z2}b{pz~H#=Tdw{W7=(_V{ky{vNjm(C_z#k(Lot3cY8#9V0R60|tN*_`B0pKb03b2M zE6Es9xO%Jxu=}TO=HI%1VK9wMKefxOt14*4qf1)9QzKV8=J8CFwGheFBbI}?>+}oUeV)VO}6PZGPj*J^}E_KT)fBKY3 z9)hgi?UU$S_w41WV2B-OVG|OZcEyv3xoG1@m$9{vAVP*Hf$t2c;}-l0a80%rc47Dc zZKK7V@Gmsh1w-di+;oNvX%tiMfz}Z23+8ozj+y+cBer6sd5-er*e>l8pn9Z0>c6&A zFq{rn-+j#DRSjZ)cmw=-{uiH10NB(Rbwmr(sauU)q*~u`jMT;k_9cC}4yOyX@n2-a zr%U2N3n2#JmXEF<@L7 zHUQoObTgd$Gyg($rL?Fitjtj}n(Vv4bXq7tFT|f?wvuUoX2fff%@n3$e&o!|8IwqW z>y?WyJ;}miE=ns4W-x(qS0shlnN{@Gh1PnS*`x2QP0@(VQvhuu;lUhNUk5JmBJl_6 zoG%BO{G+mwI<|oJNT4cXG7=Crz$p&8!A+h}UCXF{ox^(Pe_`x1)fdl&$zmpAXD`z06gbKO@Y=-X~Jwicrp^FS{f( zgB+$CeSI-s8c{iZ=Y9aJew27bQ}=cv`vK%)`~LRVgk@_u_Hzpz5v{D4yV5fk(6T3M?>om;oUT~ zFc-=me|W`hT&lrYE7!vpzT5xNW=R0F!A5vB7r%uSTi%X_3jvi8=@CKdrEnARkN=D+;waSR(r=>AEC&NMX1o;>yp*ih#&0#sU1;3@oEtr|@eTU~i_wV1pi6dKh&1cj>AuS@p zSfocODM*K_#p;&|=$zCTncCY6Z*vNN$6NFtS9uPE8tVBE2K}bRZ<$o9C@z|$fmzzgm+8mvu!3CeVnP*%nbS@Kc$Y5h z`3ffJr->(T0sa)eQ7fTUXd*0CtvM?ms4B z28$LR@SFD15Y`o**I8Hj8fn&#P_8Mf0|rAZGldyR%?`z7S8mtGl0mk( zaB0TJ)!vFeUFdnPuQ|Tw@Y?-l)! zn^@Pkdb0Y^>eFx%Ffce^434t6C0^gUzxQ=6m&2|LE|27zSf)nKMl#EP5qD5PZT&Sj zhnH~Y5My@woG?YoFOg$%^a>FV6pHC=7LZ5SD3z8r4fZdOw93qa ztFw~q9C6R>tRUN5b)wftcA9G>?z+gZ>TsEoC1Yohw%V<8vf40g@qtf;IS|Wi&z+sq zN;*;=4$q1@$pa7ZRZ!f2bA8;duN_{y31V9hW0;Kzz+KZh{GC(FY;ZJhr1nIT*GYCF zP|BAhNs+l;-Zv!!0|X6GWCcBG@GA8H>&dK90~rF>=HF~yo;sbGfR;dtG*)8EQAz@m zD+x%4xTv%JlueSP10x_1fPjF(!b1XiBpQqbW7A0th(9BMu)xrNFcJsOpdd&H2!et@ zAjk-UAP9mWG=d-qLLv;yfJSpQtpU=_uG00_O#09O({Ir$4!r-1IbnS;fB`AakLKaO z6iM?%D7{S>v%UsCmEI7w35oCr4G9d@_hPF4 zDV6Gp;P`u=pC!$I37|i|p4=f9Ye4fGOlR+fs z?X!`6Z9%iiyvYnI-)_{DQ?cGy)qp$d=7MaBII*oCLkN%T3%SL;&{j$(s}7QA#u48~ zy?2w)e$nXc2)G?lk3@K;VqrzG%2aa+*%1D;glw^(MtvK9(t0Ii-$d~?tVDYGJ$XH% z!wybP5a>d^%0aSGM(`X&Mc&-4ffZLJz%UAQbWgkn52~VD(w!Sy(p@eap7a7ZDfZh_ zW8>|R#O-&c0%POpSJ*1>w_+3qt)TC_`CWNK$W5Fm0XN7fw%bsm%7Y9#0xTV7fT{gH zO`R$VoPY{{rh}xclmaL1zq3=ylHHgk9ez5s%%gOuX zZSZ0P<-3O=j3unjDb(6{Rw0;+4}r=8ec4L>JF~VERotwJ0BG(@EC6${{+x-+8wohkom%_Ly$&Ydz#ZZs3QJK2I2W`qyb-Gg(uusD%sgFw?mxCDV!ET)Q2E2>q;^&dGra8)D zQ@^@@YI*j4F?vn4wf5yEh5X+>iYv=p@Cq800>pj(aWjH_|E4;+g2xB*DH!npEyt$V zH*@%^{WkAnw9hc;R(N-BP|PA)2Xs^Lv&MTIWnvKnB+XIJq?4W;h_`qu`2+x%!>2O! zG!tF+{+DBw+c6@O-0qqFY}qnny+I$>ihV49V|bsof=)6OW~ER(Dm8U2PDJ6>rqap_ zU$_~2g>`hi{PdF;D9`^AiBpoanDtpLm-^T|E!TUc@KPD4b0P3x zAi>8DD!^>Ss=#K@3M^PEjNSa=)D$R2Tos*U{*fDy?rmRXw~csOgHEZsoF#*5=+zk! zJrA{rGB+ODr1@W(&qPc$3cN+uY+F5lT0!I%E`xZhuOFIPTK^86Hk^PhAv9>{33I;) zZR*q=%VJPkv-`(KiCYB7h>##o9dr9u;>WV{y!#}D1VeQ}6ZmxDjFhz$M`)hn(5Bf(-j$b+iIF*J zF(4yIiHAT7WnVQpa?5>SKYU~gEW`v!7|#~E9C%0Vz~Kp{bo4ZSS37$^M}qWWu~|fW z*RZz-gq09*KqzQ7N4OUaR}lJtNGCk(`XCk>AWlx#+_>?`iyuO=)dps%A}Nam(pP7_ zf!^(X*heiC=6V{du}BDp!w;;Z_tidr-%)OXofVC~qdnbORKYqtpLB5L- z>%px#G=LW#C5SRcM&f|yu7e)$cL+!}Gux}8tDv=GW_Hw?*H2<}m5nTack8bm$qxXG z_a2%|SiUBeReIJ4$l+l!mVJD&n=BG@g!=-NZTWIvlKNecMOxI?wY&9k*M2cs%IpB$ zncMot%Mi|~DD{qDWpYKwxk(j}esAJx8tvFjqQ+T$x)4^pWcd|+C^rbIxCL|D`xZ4K zj&<|l!x`D|K>+{JZz3swo!t&)=o(Fzh^R@XQl+8FGXqtkyi$bFAg9r~8+G?$Hlr%mJNuEpC=5 z`ZJlO#YO8E7qxD^n>7X(kNvE734Npn7Y6#*w#oD7Nv#^iK2{;h0oUJQWeg`g_>~uZ z`hV*1n&>_zR0~=QDt0Uho7RnK5#I@xbgXWwD=tu2Z4&F{0jMxgt z=$$_iapnhN%Bv*3?65O31fyNinUY#C4_t%g{bMTcfee(qj|uLzb#Ay`?o!|buM;}? z(&;9NJ7xC9c-EM0)+Zch2@OhTRUB_n_!8hDCI!&sgU~>KqI+|lC|@gXqXx)jd7$dl z)ZY)7DC_>>;cBm3s(wYf&tDJa=k_C0xu7}E8T!(}?yb)Y=UqaHV$SE3oclviEhP3L z`A|JU=^%XAr0n7nnJ9bt|M#!VpIjm1*@rW61@4l(7}6K2ztp_PDG?#+bz*;OSHf|5 zpuPR1$>>gh3$7s0xJjkAq=fSlrd}ytvSKzjRY(!dACNRCszTiparrBKbRf_qLr11c zwlN45(2GG#O;uQ`nP7wf$mDGu5cO~}Q0iM``6;?uZ|xpw(d_dJFGgwKT}=GYSIveriB$z35c&p;UZPCGmC4#1~`_fAX`= zEuLDPdns;g)c(sjQFtv8XDe6XPJb0HN3g<;W|>d~#9vYC*(&ip;yfxDZ7If#8*_-K zF#RHb*H^2|JmyT=VS8K4LUsG3r4>XJ^Vld$l!$#9ps$wbK|2SRsiVCA5z*yVo8?<* z53hL^ZhS;AY`pBQq^EcYES-ix!34?+p%e@!!*BTL#%!TjBxvoBCyJ=MR5@4_rR(iM zW?KONwILd9+Q!F!abWD64aCphBP?tZtA+i4Lk0o_PJLZJ|4Jg%Rm9?id%cuc!#vWf zMa*8nz1-a~^U65Q_`C9aZR&5cW}31QgLaS5W?PtZy*BJC`e_F&YUE(qnyvn3y%!ww zv<0Lq0TY5E5pgw!RwTR0ocMMbP^F}tpy4?5EbulQrkP>h9zpHheOq7~@4$|9q$;3) zi&*CU>oKuODG&;@t_GV@t_&`X+IbTbIq*m=K^^Og4kYW(6`tfh0Rnk4lmQ(PI#>6o zoc{;}=q|n%MBQUS&lPNwjQyJ`gAtbV+(toqgU5vRCT>8*WI(6n!qrlj(+0w3VgZF6 zDslF|O<@BeRA+R(hS`wZO%nWqX}A}EooIrjYY-PCp(K^&Iath&{AcjVBs6zA)PhwC zIGjO%#$E6!mrq(~UHM7C2T&KXK2xP6SD3v*`cSD<#O?i-*9rrjU3JRcU~Kqu;tB zNQUg3!UIwnS~!YZ^?^l5f`H|OZc2)A`5gc)_?(EqC&nfKsjUeCMBtQIPMx~NE!uHw z1emF<7USKavb42@puYoIjm?OH`n~vz8Xx0%e(vls~1jN`8%^}^6Xw$EE zL{lh-N3?g?!2OBcFVw*%(tlcgF>P`JZ8rg-0bS=24Hvn4`_4yJj{xEDdv8Fq_DjHa zux+fqj;}8E3f@SnFKA>Qm**rdILF)u>0FT14=0LRQs_o$GRP}AXs_{q$4o}ZTbCID zy2l5JT|rSG;mj3bl*bzmgATx#tGEGb93tlu8Qy_d<$fv~od{(+92L_ke5dgk;7b;3 zPJMp`4s{_lDH@%ir1ZmaSLOHOk%eRVLm7h>aHAx)Q}TgOYb*SJigpb3Rn)6B@N%E{ zMZ9(&6+Dt{*SZJuGUM`pr^{38QBxU#GHX|gQI24@gTt|GEqnU zIQK|? zVfpW%ehE9-z!@p<7|!xMyVp=ilqT1j3`l zp>Wpl;TK`n@WJg_swX<76S9V%gov5-{df-jxsHK;sRX;j1|?ofEwRH)bHJMJ^{F!4Hbm-Dr5qwvGHFxl(2#&#@iq%_xz5+e(LpDB2A5LV|}kx-Y6M*~=Z zyaIo*vSm{$(Bw4e4&-PUDmaLFpSnvla$%n2O{PEt zVkp1J=y_RK{mk_t2VJ7we(^&Os&QF%Sg*Aq-hVz3+j~ytmz^QIykaEEqa_f(Skw_&m=h+1)Z#*Sg_ zQST5jx+1lfCo=rL zEh^7d>!&1Mf8Kvae__oyAhQbD;ky3u(4HLtLq~nHzk~W_S-!7Z2WxPR0XO*($ezWr zbNx}?7ZH7e@?h6+#;?V;#8?=SJY=XKq~1n!B0s{HFh6m zHLeH+MJchg2M@5i&z6fIqB#>K-Mxb=mIT~SbF4X;dmV|Jw0b0D-q zVb$sXdz(k;XmE>aL z`NkwH;pyZs=jS1P@rP66&mu{^2k0yke`+RLK62t?8PHOqzz+GA#V4j9=NO5%GHpbJ ze++6wpTbrTH!GccQZpHt=_@O;pYx8;x2?MvTX=9yKi0N)aE+wHF>%%%T$j)K+&Q(% zMq>o4q*J>3pc(q#h}l4h+{+tZDQ0B^7iW3OMmK*xJcR;{zNchry?Dp9**k7~V&yj4 z>vMhFT5D%>Tgf@Vs~9#!?KZ`5c$udbe?hWPZ&TEicvakrh)K0#IlBX2DuE%fMu?$3iDm#Wui;3bb@|icOSJ;(crX%ulYIEx(X#SXXtY7C{>`G%H#SmE95m6EReaM7TcgnZB9pMS zzo#YHj84M1tY*tq(rv*xY|GLYvQES+a`qJnn*;(`Tv}gB36tVTe;xRgvy{Bc=GaXr%2h$3`-NV_RGOI8TYuqu`r|vA zTsrv9v)RQ-?!+Sj+T&)V`q;{OG^v}ytw`)PNfLJqe(O1hy0A{c8@%R1tRrux_REYI3VUe>>pp0Dp?2 z4mUE2!%b?&5BBpYZwv+ZPfzX$>NM{qgNoaXRG-~xig1oOelgQnU$481nalK)>4*8w zP%{5JKi>qD39;tfb0#62$ESVq^hO?BTT(r+0h&QV7?O$D`Pl&`OZ7V4^Ukne3>$)T zV=S|1Gbtf)v(l*VceemWf0*lOEdoxQ_p0)*KM+qe!6D>aAZ;-TTl@`Nn~D)Fr9-Mr z7E50^-tv@@FTWh}H3FOp4sX7UEZA21VQhCrcISj{)(0vuV=q-lf_?`0WixS>{VdGY z2W@7&pPO0iq|6u?JYe}uzE;sBDYBInz7rnz@ci*!;^~d6_m1^de~ysCQ{O7_+s~3e z&dpA08y<{7Zqf0RW@K`5_EZ6}5&60ai~c9X`IX;s%x?&yx3ijFZt@DQfJUTaoZtw@!8W6)?f{abg9^Ykx2c!W5uI`wv?{M6Wq*L zX?t>0V+t0l<;F#8Y={&PM0fxMu9cN~jPqJw3yYrbzjvQ(e<9%zK!6Y&gbf5z_w6np zD5P!9b)ia?<1U|8g$0wHO2JC0{h{f2teo9Z%Wl%tPap9YqH+;sQB?_aUrm@M1cT;~ zwI^Q`JCMUq^_@8_zJXfz0KIdT1Z^-ll;wTksocu5U$VjzsbAH~Gq8DS<=Hx?<7%zw zC6a1_Ew0wJf8AvY3F0&IYT;_VBbwl9Z6-Y6YJCgY-)b$2wE9+Sx=8m{Yba!StFjjXt7DIPyEmPP3XxWJ;CXe-%kaO?Tm_h|k`_>D&gOD9fOJ z#}Sw0;aV-W7~3T-jaF=>_>Dm0tML*Kq*TjY3il_0TZI9nnGRO%I z&!g{B31@hwGq%E2r+c!g8hMUQ?6w7a<)}0hGjk}u*XQ-;vx*GA@hkyd7X~dUQ?SIO zYS_e>q04Ytu?m;*f@D$DdgVSGZ}h@>;7i}26ydrN^+h$t-8aX< zMCVk|Ptwmp6Kf~=+}TXhU2#-eDke~#7Zv=H@ufdc0+lGc28eMiCVe&1T~PGkeF6s~ zg648S32G4b-CVijvna@GaBS4Aih7#xTwkgeS(60{B= z0oW1yfI9dD&6h-C0>giLyzcci2ir})n5M?G zMCk(=VlA7oUuT5I>?;dw#AqG^Ri)Va07D3s%<({g!4x_ZAWnkrFHq#a&lEGi%4RN& zt5I|AyiWNN^tpeheld1h?1tFp0b3_%O>zc3ZYEVli}7mS&be`LE{i zfa3Q0_vC(h?d_OqX{`aKCgw+BO!il}aK^mz5lDvUzH03y961%=f}fo36;c|6W+~zn z>&Fq2j~7s_0!f!{U!+bCo&{i(nxNnVR*qKN7y5yE3l1=91%Wp}LeZk|VjXJ)`lJQI zxqsEZSrWiJhz@6*D$!{MhR<3>JgyT)A6KgKJ}oQE zYSY*-Hy#73tk9j1vWyj)Ox&OgJIh_^<=|N=$SKsbR~||$Ga${ypfyPdjx6p`=+K~+ z2aX64gLVnV*01p4f z0uqwf)5_Hb%L*Na)P`Ceiw2mPSC&Zi7+d+lX0q7`0x3cIVw2x8poA$lmMXs6OT@aM zB!GVm-xZfE8QAaDq%Zm4E?J(X4CGlj8-k5E!#y&Mi-73E(OFv=DQT~a!n98vL%nTR zzJ?w|L{12h=#|YP&_1DN6|~FWb%4wecs&mXkyBM3ENvcrNPuZajG5A=42hm_m7H3U zb^$$)^IY-@8ixZi16*+_0vB>1GX$ET0h)iJ88WBSf)%A+#6(W^V`5HXH*8?FvW2zTN z*W#4N;Z>C?^LqvAwQcHOpOn6E78Jx}`t*f|Q(M4QRbM!Yy$u*H3!tCiRMH8ijse4a z&pJNNIQX(reBte~*$easxavvfhLnF^^4S;F99%_>KyW4B?e|Dd25u=auE4|#XV{+m zbvSOhP<*C`_m|9ru-r20p_)@Iyb0vfJUkk)z9a?MISqk&(ak1qP5P;YVMo85w8LpL7so!-C%?9 z!#};CH#HojI>Z^biFHuEY5s{cgIlC%U>OR5eBw!;%e^&Y zZdJ|gX5K)y>V)fg5lO6{2sR0MdV1W{g%_=e((STy=uu+PzX0TYABx$Vd!O(}?+WxNj9%6Sg4BWl zaR`21R=cRG0DScqJs^pP?Hgb85~D^ie=*jtH1UXm1k>m(l>hl;2qk~Cabv_2A_bV^ zwWae`F)znUKj#fS!@mKMD?#+chTSQiEpFZn?|Xr4OT0g3i3#wST#?i-Wtd$!m$j1r z5#PAgU3ONcf@3}~N~|95uMv*4u1Pga1uRy(gt<*F z2Z`5| z3{W;+U?5Q&zOR3X_s+U}P~C>_h~VMPRVS1Oi#}!03ExGLobV0wbkSu_>U`X0QedoP zMv8xJ+6*y~*#5qAf_E0diL-5jSP8D^Ik(H+3ca0{!2JmSQp$a_&))r_+5n&*;ze?@ zKbs;|T@#4ejGXx`rL9A2p}Xm@rS0MV7qzfAzqe5-?b3fRiI`RkpWo(EKP%Xjd?)4n z7VZhBmh&4i>EWwn4%*G;zsa*VnCusvbK2Qe`vnfkCSkSfOIhL6GAa}Pup6?34PGTe zp-K0tfBfRm-Ns;VLFTxA>9xIA2H_noG48lAFiHxbx9gXjW4skZ~Bt!E%B0uTS)Z>`vhYfE{k+7 zc4~j6u~k-MG6O|t<=GM1mxL%GDb}%4#ECWFaEOsIPv}Dq0q!E_1hLz<5ObnA zSos_P^5B_z3GeXApO7AD4zzP<9M#NajN3gk{;RO7y_0>~Apj7_WWNACPb%|)Mtfn< zey(Ih@@lM^-oO@N3u(VVKTP=4(Jr?FSss6pyNVULQ_zDUFu5(qOVaND|5oiFWEmXU zt@AcGop%3x3gYL_WgzK*Tu=y1rR$Vao`JvpOyfC6JyEd^>}7oXJ5?L(q^R|ggR&0d z?0dyf`J=J98JI3j@;y=ncLIw{daXi2HiD7VjIqgR3(F!fFnfR|my5%)U|_kH+arIY zmt0;jLto+K*V(=(N}_sg;9S!z3(NFf+CQVAx)XCC+7mTcV9%WZK=g<2`Jo4v79mEj zy3CJnw?$LZv1_dWh|WJV?*sJ`Rq3h8yXmCY&S2n+6zUt1P#~Q0*u!5s@0e1II9+dr ou#7RqL|bnWJv5P(^b diff --git a/codex-rs/core/src/session/turn_input.rs b/codex-rs/core/src/session/turn_input.rs index 3a95e42a12..74a7592de8 100644 --- a/codex-rs/core/src/session/turn_input.rs +++ b/codex-rs/core/src/session/turn_input.rs @@ -42,6 +42,7 @@ use codex_protocol::protocol::NonSteerableTurnKind; use codex_protocol::protocol::SessionSource; use codex_protocol::protocol::SubAgentSource; use codex_protocol::protocol::ThreadSettingsOverrides; +use codex_protocol::turn_input::AnnotatedResponseItem; use codex_protocol::turn_input::NotSubmittedReason; use codex_protocol::turn_input::TurnInput as SubmittedTurnInput; use codex_protocol::turn_input::TurnInputMode; @@ -242,6 +243,7 @@ pub(super) async fn handle( } SubmittedTurnInput::UserInput { .. } | SubmittedTurnInput::ResponseItem(_) + | SubmittedTurnInput::AnnotatedResponseItem(_) | SubmittedTurnInput::InterAgentCommunication(_) => TurnStartKind::Automatic, }; start_if_idle( @@ -256,7 +258,10 @@ pub(super) async fn handle( TurnInputMode::ContinueIfIdle { expected_previous_turn_id, } => { - if !matches!(&request.request.input, SubmittedTurnInput::ResponseItem(_)) { + if !matches!( + &request.request.input, + SubmittedTurnInput::ResponseItem(_) | SubmittedTurnInput::AnnotatedResponseItem(_) + ) { return Err(CodexErr::InvalidRequest( "continuation requires internal response input".to_string(), )); @@ -343,6 +348,10 @@ async fn start_or_steer( SubmittedTurnInput::ResponseItem(ResponseItem::FunctionCallOutput { call_id: None, .. + }) + | SubmittedTurnInput::AnnotatedResponseItem(AnnotatedResponseItem { + item: ResponseItem::FunctionCallOutput { call_id: None, .. }, + .. }) => true, _ => { return Err(CodexErr::InvalidRequest( @@ -907,12 +916,14 @@ async fn capture_sender_user_messages( session: &Session, input: &mut SubmittedTurnInput, ) -> Option { - let SubmittedTurnInput::ResponseItem( - item @ ResponseItem::FunctionCallOutput { call_id: None, .. }, - ) = input + let (SubmittedTurnInput::ResponseItem(item) + | SubmittedTurnInput::AnnotatedResponseItem(AnnotatedResponseItem { item, .. })) = input else { return None; }; + if !matches!(item, ResponseItem::FunctionCallOutput { call_id: None, .. }) { + return None; + } Session::assign_missing_response_item_id(item); session .services @@ -928,7 +939,11 @@ async fn pending_turn_input( turn_id: &str, origin: UserInputOrigin, ) -> TurnInput { - match input { + let retain = match &input { + SubmittedTurnInput::AnnotatedResponseItem(input) => input.annotations.retain, + _ => false, + }; + let mut input = match input { SubmittedTurnInput::UserInput { content, client_id } => TurnInput::UserInput { content, client_id, @@ -938,6 +953,7 @@ async fn pending_turn_input( }, }, SubmittedTurnInput::ResponseItem(item) + | SubmittedTurnInput::AnnotatedResponseItem(AnnotatedResponseItem { item, .. }) if matches!( &item, ResponseItem::FunctionCallOutput { call_id: None, .. } @@ -960,9 +976,20 @@ async fn pending_turn_input( }; TurnInput::FunctionCallOutput(ResponseItemEnvelope { item, metadata }) } - SubmittedTurnInput::ResponseItem(item) => TurnInput::ResponseItem(item.into()), + SubmittedTurnInput::ResponseItem(item) + | SubmittedTurnInput::AnnotatedResponseItem(AnnotatedResponseItem { item, .. }) => { + TurnInput::ResponseItem(item.into()) + } SubmittedTurnInput::InterAgentCommunication(communication) => { TurnInput::InterAgentCommunication(communication) } + }; + if retain + && let TurnInput::ResponseItem(envelope) | TurnInput::FunctionCallOutput(envelope) = + &mut input + && matches!(envelope.item, ResponseItem::FunctionCallOutput { .. }) + { + envelope.metadata.get_or_insert_default().client_authored = true; } + input } diff --git a/codex-rs/core/tests/suite/turn_input_submission.rs b/codex-rs/core/tests/suite/turn_input_submission.rs index af7fab2fa8..920d864531 100644 --- a/codex-rs/core/tests/suite/turn_input_submission.rs +++ b/codex-rs/core/tests/suite/turn_input_submission.rs @@ -29,8 +29,11 @@ use codex_protocol::protocol::SubAgentSource; use codex_protocol::protocol::ThreadSettingsOverrides; use codex_protocol::protocol::TurnEnvironmentRequests; use codex_protocol::protocol::TurnEnvironmentSelections; +use codex_protocol::turn_input::AnnotatedResponseItem; +use codex_protocol::turn_input::ResponseItemAnnotations; use codex_protocol::turn_input::TurnAttribution; use codex_protocol::user_input::UserInput; +use core_test_support::ThreadIdle; use core_test_support::responses; use core_test_support::responses::ev_completed; use core_test_support::responses::ev_response_created; @@ -1578,3 +1581,120 @@ async fn daemon_recovery_includes_local_environment_that_finished_starting() -> .await; Ok(()) } + +/// Retention follows accepted outputs through idle submission, steering, and rollout storage. +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn tool_output_retention_is_submission_metadata() -> anyhow::Result<()> { + let (release, gate) = oneshot::channel(); + let (server, _completions) = start_streaming_sse_server(vec![ + vec![StreamingSseChunk { + gate: Some(gate), + body: responses::sse_completed("started"), + }], + vec![StreamingSseChunk { + gate: None, + body: responses::sse_completed("steered"), + }], + vec![StreamingSseChunk { + gate: None, + body: responses::sse_completed("idle"), + }], + ]) + .await; + let mut extensions = ExtensionRegistryBuilder::new(); + extensions.thread_lifecycle_contributor(Arc::new(ThreadIdle)); + let test = test_codex() + .with_extensions(Arc::new(extensions.build())) + .build_with_streaming_server(&server) + .await?; + for (name, retain) in [("started", true), ("steered", true), ("ordinary", false)] { + let item = serde_json::from_value(serde_json::json!({ + "type": "function_call_output", "name": name, + "namespace": "example", "output": "Inspect the failing tests.", + }))?; + let input = if retain { + TurnInput::AnnotatedResponseItem(AnnotatedResponseItem { + item, + annotations: ResponseItemAnnotations { retain }, + }) + } else { + TurnInput::ResponseItem(item) + }; + let request = TurnInputRequest::new(input); + let submission = test.codex.start_or_steer_turn(request).await?; + if name == "started" { + assert!(matches!(submission, TurnInputSubmission::Started { .. })); + server.wait_for_request_count(/*count*/ 1).await; + } else { + assert!(matches!(submission, TurnInputSubmission::Steered { .. })); + } + } + release.send(()).expect("release active response"); + wait_for_event(&test.codex, |event| { + matches!(event, EventMsg::TurnComplete(_)) + }) + .await; + + ThreadIdle::wait(&test.codex).await; + + let request = TurnInputRequest::new(TurnInput::AnnotatedResponseItem(AnnotatedResponseItem { + item: serde_json::from_value(serde_json::json!({ + "type": "function_call_output", "name": "idle", + "namespace": "example", "output": "Report your findings.", + }))?, + annotations: ResponseItemAnnotations { retain: true }, + })); + assert!(matches!( + test.codex.start_turn_if_idle(request).await?, + StartIfIdleSubmission::Started { .. } + )); + wait_for_event(&test.codex, |event| { + matches!(event, EventMsg::TurnComplete(_)) + }) + .await; + test.codex.shutdown_and_wait().await?; + + let history = codex_rollout::RolloutRecorder::get_rollout_history( + &test.codex.rollout_path().expect("durable rollout"), + ) + .await?; + let retained = history + .get_rollout_items() + .iter() + .filter_map(|item| { + let codex_history::RolloutItem::ResponseItem(envelope) = item else { + return None; + }; + let codex_protocol::models::ResponseItem::FunctionCallOutput { name, .. } = + &envelope.item + else { + return None; + }; + Some(( + name.as_deref().unwrap(), + envelope + .metadata + .as_ref() + .is_some_and(|metadata| metadata.client_authored), + )) + }) + .collect::>(); + assert_eq!( + retained, + vec![ + ("started", true), + ("steered", true), + ("ordinary", false), + ("idle", true) + ] + ); + for request in server.requests().await { + let body: Value = serde_json::from_slice(&request)?; + for item in body["input"].as_array().unwrap() { + assert!(item.get("retain").is_none()); + assert!(item.get("client_authored").is_none()); + } + } + server.shutdown().await; + Ok(()) +} diff --git a/codex-rs/history/src/lib.rs b/codex-rs/history/src/lib.rs index 5ce19f056a..e639c12831 100644 --- a/codex-rs/history/src/lib.rs +++ b/codex-rs/history/src/lib.rs @@ -85,7 +85,7 @@ pub struct CodexHarnessMetadata { #[serde(default, skip_serializing_if = "Option::is_none")] pub retained_source: Option, - /// Whether a developer message was supplied by an app-server client. + /// Whether a developer message was supplied by a client or a client requested tool-output retention. #[serde(default)] pub client_authored: bool, diff --git a/codex-rs/protocol/src/turn_input.rs b/codex-rs/protocol/src/turn_input.rs index 3069a5f6ff..7e9977959c 100644 --- a/codex-rs/protocol/src/turn_input.rs +++ b/codex-rs/protocol/src/turn_input.rs @@ -36,9 +36,26 @@ pub enum TurnInput { client_id: Option, }, ResponseItem(ResponseItem), + AnnotatedResponseItem(AnnotatedResponseItem), InterAgentCommunication(InterAgentCommunication), } +/// A Responses API item with caller-supplied, harness-only annotations. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct AnnotatedResponseItem { + pub item: ResponseItem, + #[serde(default)] + pub annotations: ResponseItemAnnotations, +} + +/// Public annotations accepted by Core; internal history metadata stays private. +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct ResponseItemAnnotations { + /// Request compaction retention for a function-call output. + #[serde(default, skip_serializing_if = "std::ops::Not::not")] + pub retain: bool, +} + /// One turn input and the context that follows it through submission. /// /// Callers choose start-or-steer, idle-start, or steer-only behavior through