@@ -50,7 +50,9 @@ const mock = createServer(async (request, response) => {
5050 const data = JSON . parse ( body ) ;
5151 requests . push ( data ) ;
5252 const lastUser = data . messages . findLastIndex ( message => message . role === "user" ) ;
53- const spawnChild = JSON . stringify ( data . messages [ lastUser ] ) . includes ( "SPAWN_SMOKE_CHILD" )
53+ const userText = JSON . stringify ( data . messages [ lastUser ] ) ;
54+ const switchSmoke = userText . includes ( "SWITCH_SMOKE" ) ;
55+ const spawnChild = userText . includes ( "SPAWN_SMOKE_CHILD" )
5456 && ! data . messages . slice ( lastUser + 1 ) . some ( message => message . role === "tool" ) ;
5557 const tool = data . tools ?. find ( tool => tool . function . name === "subagent" ) ;
5658 const toolCalls = spawnChild && tool ? [ { index : 0 , id : "usage-smoke-child" , type : "function" , function : {
@@ -71,7 +73,7 @@ const mock = createServer(async (request, response) => {
7173 chunk ( { role : "assistant" } ) ;
7274 await new Promise ( resolve => setTimeout ( resolve , 300 ) ) ;
7375 chunk ( toolCalls ? { tool_calls : toolCalls } : { content : content . slice ( 0 , 4 ) } ) ;
74- await new Promise ( resolve => setTimeout ( resolve , 700 ) ) ;
76+ await new Promise ( resolve => setTimeout ( resolve , switchSmoke ? 2_500 : 700 ) ) ;
7577 if ( content ) chunk ( { content : content . slice ( 4 ) } ) ;
7678 await new Promise ( resolve => setTimeout ( resolve , 100 ) ) ;
7779 chunk ( { } , toolCalls ? "tool_calls" : "stop" , usage ) ;
@@ -131,7 +133,8 @@ const openTui = sessionID => {
131133 await writeFile ( path . join ( work , `${ name } .txt` ) , screen ( ) ) ;
132134 await writeFile ( path . join ( work , `${ name } .ansi` ) , raw ) ;
133135 } ;
134- const entry = { process, screen, save, terminal } ;
136+ const send = data => process . stdin . write ( data ) ;
137+ const entry = { process, screen, save, send, terminal } ;
135138 terminals . push ( entry ) ;
136139 return entry ;
137140} ;
@@ -164,9 +167,43 @@ try {
164167 assert . doesNotMatch ( tui . screen ( ) , / \b (?: T P S | T T F T ) \b / , "empty session hides unavailable performance rows" ) ;
165168 await tui . save ( "01-empty" ) ;
166169 console . log ( "PASS: packed plugin loads; empty sidebar hides zero-value and context rows" ) ;
170+
171+ const switchTarget = await client . session . create ( { location : { directory : project } , title : "Live Switch Target" , permissions : [ { action : "*" , resource : "*" , effect : "allow" } ] } ) ;
172+ const switchPrompt = client . session . prompt ( { sessionID : switchTarget . id , text : "SWITCH_SMOKE" } ) ;
173+ await new Promise ( resolve => setTimeout ( resolve , 650 ) ) ;
174+ tui . send ( "\x18" ) ;
175+ await new Promise ( resolve => setTimeout ( resolve , 50 ) ) ;
176+ tui . send ( "l" ) ;
177+ await wait ( ( ) => / S e s s i o n s f o r p r o j e c t / . test ( tui . screen ( ) ) && / L i v e S w i t c h T a r g e t / . test ( tui . screen ( ) ) , "session switch dialog" ) ;
178+ tui . send ( "Live Switch Target" ) ;
179+ await new Promise ( resolve => setTimeout ( resolve , 100 ) ) ;
180+ tui . send ( "\r" ) ;
181+ await wait ( ( ) => ! / S e s s i o n s f o r p r o j e c t / . test ( tui . screen ( ) ) && / T P S \s + ~ [ \d . ] + t o k \/ s / . test ( tui . screen ( ) )
182+ && / T T F T \s + [ \d . ] + s / . test ( tui . screen ( ) ) , "live performance restored after session switch" ) ;
183+ await tui . save ( "02-switched-streaming" ) ;
184+ await switchPrompt ;
185+ await wait ( async ( ) => ( await client . message . list ( { sessionID : switchTarget . id } ) ) . data . some ( m => m . type === "assistant" && m . tokens ) , "switched session usage" ) ;
186+ const switchSnapshot = await loadSnapshot ( source , switchTarget . id , new AbortController ( ) . signal ) ;
187+ const switchPerformance = historicalPerformance ( uniqueMessages ( switchSnapshot ) ) ;
188+ assert . ok ( switchPerformance . tps && switchPerformance . tps > 0 ) ;
189+ await wait ( ( ) => new RegExp ( `TPS\\s+${ switchPerformance . tps . toFixed ( 1 ) . replace ( "." , "\\." ) } tok/s` ) . test ( tui . screen ( ) ) , "switched stream exact TPS" ) ;
190+ assert . doesNotMatch ( tui . screen ( ) , / T P S \s + ~ / , "switched stream converges to exact TPS" ) ;
191+ await tui . save ( "03-switched-complete" ) ;
192+ console . log ( "PASS: switching to an in-flight session restores live TPS/TTFT and converges to exact TPS" ) ;
193+
194+ tui . send ( "\x18" ) ;
195+ await new Promise ( resolve => setTimeout ( resolve , 50 ) ) ;
196+ tui . send ( "l" ) ;
197+ await wait ( ( ) => / S e s s i o n s f o r p r o j e c t / . test ( tui . screen ( ) ) && / T o k e n U s a g e S m o k e / . test ( tui . screen ( ) ) , "return session dialog" ) ;
198+ tui . send ( "\x1b[B" ) ;
199+ await new Promise ( resolve => setTimeout ( resolve , 100 ) ) ;
200+ tui . send ( "\r" ) ;
201+ await wait ( ( ) => ! / S e s s i o n s f o r p r o j e c t / . test ( tui . screen ( ) ) && / T o k e n U s a g e / . test ( tui . screen ( ) )
202+ && / C a c h e R a t e \s + 0 \. 0 % / . test ( tui . screen ( ) ) && ! / \b T P S \b / . test ( tui . screen ( ) ) , "return to empty root session" ) ;
203+
167204 const firstPrompt = client . session . prompt ( { sessionID : root . id , text : "Return SMOKE_OK." } ) ;
168205 await wait ( ( ) => / T P S \s + ~ [ \d . ] + t o k \/ s / . test ( tui . screen ( ) ) && / T T F T \s + [ \d . ] + s / . test ( tui . screen ( ) ) , "live TPS and TTFT" ) ;
169- await tui . save ( "02 -streaming" ) ;
206+ await tui . save ( "04 -streaming" ) ;
170207 await firstPrompt ;
171208 await wait ( async ( ) => ( await client . message . list ( { sessionID : root . id } ) ) . data . some ( m => m . type === "assistant" && m . tokens ) , "first usage" ) ;
172209 let snapshot = await loadSnapshot ( source , root . id , new AbortController ( ) . signal ) ;
@@ -186,19 +223,19 @@ try {
186223 assert . equal ( lineNumber ( tui . screen ( ) , / \b T P S \s + / ) , lineNumber ( tui . screen ( ) , / \b C o s t \s + / ) + 2 , "one blank line separates usage and performance" ) ;
187224 assert . ok ( lineNumber ( tui . screen ( ) , / \b T P S \s + / ) < lineNumber ( tui . screen ( ) , / \b T T F T \s + / ) ) ;
188225 assert . ok ( lineNumber ( tui . screen ( ) , / \b C o s t \s + / ) < lineNumber ( tui . screen ( ) , / \b T P S \s + / ) ) ;
189- await tui . save ( "03 -message" ) ;
226+ await tui . save ( "05 -message" ) ;
190227 console . log ( "PASS: live estimates converge to exact TPS; TTFT and token/context rows update" ) ;
191228 await client . session . wait ( { sessionID : root . id } ) ;
192229 await client . session . prompt ( { sessionID : root . id , text : "SPAWN_SMOKE_CHILD" } ) ;
193230 await wait ( async ( ) => ( await client . session . list ( { parentID : root . id } ) ) . data . length > 0 , "real subagent creation" ) ;
194231 const child = ( await client . session . list ( { parentID : root . id } ) ) . data [ 0 ] ;
195232 await client . session . wait ( { sessionID : root . id } ) ;
196233 await wait ( ( ) => / I n p u t \s + 4 0 0 / . test ( tui . screen ( ) ) && / C a c h e R e a d \s + 4 , 0 0 0 / . test ( tui . screen ( ) ) , "child usage in root sidebar" ) ;
197- await tui . save ( "04 -subagent" ) ;
234+ await tui . save ( "06 -subagent" ) ;
198235 const childTui = openTui ( child . id ) ;
199236 await wait ( ( ) => / I n p u t \s + 4 0 0 / . test ( childTui . screen ( ) ) && / C a c h e R e a d \s + 4 , 0 0 0 / . test ( childTui . screen ( ) ) , "same tree in child sidebar" ) ;
200237 assert . match ( childTui . screen ( ) , / C o n t e x t \s + 1 , 2 7 0 \/ 1 2 8 , 0 0 0 \( 1 \. 0 % \) / ) ;
201- await childTui . save ( "05 -child-view" ) ;
238+ await childTui . save ( "07 -child-view" ) ;
202239 snapshot = await loadSnapshot ( source , child . id , new AbortController ( ) . signal ) ;
203240 assert . equal ( snapshot . rootID , root . id ) ;
204241 assert . equal ( snapshot . viewedID , child . id ) ;
@@ -208,9 +245,9 @@ try {
208245 await client . session . switchModel ( { sessionID : root . id , model : { providerID : "usage-test" , id : "large" } } ) ;
209246 await wait ( async ( ) => ( await loadSnapshot ( source , root . id , new AbortController ( ) . signal ) ) . model . label === "usage-test/large" , "active model switch" ) ;
210247 await wait ( ( ) => / C o n t e x t \s + 1 , 2 7 0 \/ 3 2 , 0 0 0 \( 4 \. 0 % \) / . test ( tui . screen ( ) ) , "context window follows model switch" ) ;
211- await tui . save ( "06 -model-switch" ) ;
248+ await tui . save ( "08 -model-switch" ) ;
212249 console . log ( "PASS: active model switch refreshes price selection and context window" ) ;
213- await writeFile ( path . join ( work , "result.json" ) , JSON . stringify ( { version : opencodeVersion . replace ( / ^ o p e n c o d e v / , "" ) , root : root . id , child : child . id , total : 5080 , performance, context : { used : 1270 , limitBefore : 128000 , limitAfter : 32000 , percentAfter : "4.0" } , package : packed [ 0 ] . filename , files } , null , 2 ) ) ;
250+ await writeFile ( path . join ( work , "result.json" ) , JSON . stringify ( { version : opencodeVersion . replace ( / ^ o p e n c o d e v / , "" ) , root : root . id , child : child . id , switchTarget : switchTarget . id , total : 5080 , performance, switchPerformance , context : { used : 1270 , limitBefore : 128000 , limitAfter : 32000 , percentAfter : "4.0" } , package : packed [ 0 ] . filename , files } , null , 2 ) ) ;
214251} finally {
215252 for ( const [ index , terminal ] of terminals . entries ( ) ) {
216253 await terminal . save ( `final-${ index } ` ) ;
0 commit comments