@@ -280,8 +280,9 @@ func TestSimple(t *testing.T) {
280280 AgentChoice ("root" , sess .ID , "Hello" ),
281281 MessageAdded (sess .ID , msgAdded .Message , "root" ),
282282 NewTokenUsageEvent (sess .ID , "root" , & Usage {InputTokens : 3 , OutputTokens : 2 , ContextLength : 5 , LastMessage : & MessageUsage {
283- Usage : chat.Usage {InputTokens : 3 , OutputTokens : 2 },
284- Model : "test/mock-model" ,
283+ Usage : chat.Usage {InputTokens : 3 , OutputTokens : 2 },
284+ Model : "test/mock-model" ,
285+ FinishReason : chat .FinishReasonStop ,
285286 }}),
286287 StreamStopped (sess .ID , "root" ),
287288 }
@@ -323,8 +324,9 @@ func TestMultipleContentChunks(t *testing.T) {
323324 AgentChoice ("root" , sess .ID , "you?" ),
324325 MessageAdded (sess .ID , msgAdded .Message , "root" ),
325326 NewTokenUsageEvent (sess .ID , "root" , & Usage {InputTokens : 8 , OutputTokens : 12 , ContextLength : 20 , LastMessage : & MessageUsage {
326- Usage : chat.Usage {InputTokens : 8 , OutputTokens : 12 },
327- Model : "test/mock-model" ,
327+ Usage : chat.Usage {InputTokens : 8 , OutputTokens : 12 },
328+ Model : "test/mock-model" ,
329+ FinishReason : chat .FinishReasonStop ,
328330 }}),
329331 StreamStopped (sess .ID , "root" ),
330332 }
@@ -362,8 +364,9 @@ func TestWithReasoning(t *testing.T) {
362364 AgentChoice ("root" , sess .ID , "Hello, how can I help you?" ),
363365 MessageAdded (sess .ID , msgAdded .Message , "root" ),
364366 NewTokenUsageEvent (sess .ID , "root" , & Usage {InputTokens : 10 , OutputTokens : 15 , ContextLength : 25 , LastMessage : & MessageUsage {
365- Usage : chat.Usage {InputTokens : 10 , OutputTokens : 15 },
366- Model : "test/mock-model" ,
367+ Usage : chat.Usage {InputTokens : 10 , OutputTokens : 15 },
368+ Model : "test/mock-model" ,
369+ FinishReason : chat .FinishReasonStop ,
367370 }}),
368371 StreamStopped (sess .ID , "root" ),
369372 }
@@ -403,8 +406,9 @@ func TestMixedContentAndReasoning(t *testing.T) {
403406 AgentChoice ("root" , sess .ID , " How can I help you today?" ),
404407 MessageAdded (sess .ID , msgAdded .Message , "root" ),
405408 NewTokenUsageEvent (sess .ID , "root" , & Usage {InputTokens : 15 , OutputTokens : 20 , ContextLength : 35 , LastMessage : & MessageUsage {
406- Usage : chat.Usage {InputTokens : 15 , OutputTokens : 20 },
407- Model : "test/mock-model" ,
409+ Usage : chat.Usage {InputTokens : 15 , OutputTokens : 20 },
410+ Model : "test/mock-model" ,
411+ FinishReason : chat .FinishReasonStop ,
408412 }}),
409413 StreamStopped (sess .ID , "root" ),
410414 }
@@ -963,6 +967,59 @@ func TestEmitStartupInfo_CostIncludesSubSessions(t *testing.T) {
963967 "cost should include sub-session costs (TotalCost, not OwnCost)" )
964968}
965969
970+ func TestEmitStartupInfo_LastMessageFinishReason (t * testing.T ) {
971+ // When restoring a session whose last assistant message has a
972+ // FinishReason, the emitted TokenUsageEvent.LastMessage must carry
973+ // that FinishReason so the UI can identify the final response.
974+ prov := & mockProvider {id : "test/startup-model" , stream : & mockStream {}}
975+ root := agent .New ("root" , "agent" ,
976+ agent .WithModel (prov ),
977+ agent .WithDescription ("Root" ),
978+ )
979+ tm := team .New (team .WithAgents (root ))
980+
981+ rt , err := NewLocalRuntime (tm , WithCurrentAgent ("root" ),
982+ WithModelStore (mockModelStoreWithLimit {limit : 128_000 }))
983+ require .NoError (t , err )
984+
985+ sess := session .New ()
986+ sess .InputTokens = 500
987+ sess .OutputTokens = 200
988+
989+ sess .Messages = append (sess .Messages , session.Item {
990+ Message : & session.Message {
991+ AgentName : "root" ,
992+ Message : chat.Message {
993+ Role : chat .MessageRoleAssistant ,
994+ Content : "final answer" ,
995+ Cost : 0.02 ,
996+ Model : "test/startup-model" ,
997+ FinishReason : chat .FinishReasonStop ,
998+ Usage : & chat.Usage {InputTokens : 500 , OutputTokens : 200 },
999+ },
1000+ },
1001+ })
1002+
1003+ events := make (chan Event , 20 )
1004+ rt .EmitStartupInfo (t .Context (), sess , events )
1005+ close (events )
1006+
1007+ var tokenEvent * TokenUsageEvent
1008+ for event := range events {
1009+ if te , ok := event .(* TokenUsageEvent ); ok {
1010+ tokenEvent = te
1011+ }
1012+ }
1013+
1014+ require .NotNil (t , tokenEvent , "should emit TokenUsageEvent" )
1015+ require .NotNil (t , tokenEvent .Usage .LastMessage , "LastMessage should be populated on session restore" )
1016+ assert .Equal (t , chat .FinishReasonStop , tokenEvent .Usage .LastMessage .FinishReason )
1017+ assert .Equal (t , "test/startup-model" , tokenEvent .Usage .LastMessage .Model )
1018+ assert .InDelta (t , 0.02 , tokenEvent .Usage .LastMessage .Cost , 0.0001 )
1019+ assert .Equal (t , int64 (500 ), tokenEvent .Usage .LastMessage .InputTokens )
1020+ assert .Equal (t , int64 (200 ), tokenEvent .Usage .LastMessage .OutputTokens )
1021+ }
1022+
9661023func TestEmitStartupInfo_NilSessionNoTokenEvent (t * testing.T ) {
9671024 // When sess is nil, no TokenUsageEvent should be emitted.
9681025 prov := & mockProvider {id : "test/startup-model" , stream : & mockStream {}}
0 commit comments