@@ -1387,7 +1387,7 @@ func (b *Builder) wireDependencies() error {
13871387 OnText : func (text string ) {
13881388 app .touchStepHeartbeat ()
13891389 if app .program != nil {
1390- app .program . Send (ui .StreamTextMsg (text ))
1390+ app .safeSendToProgram (ui .StreamTextMsg (text ))
13911391 }
13921392
13931393 // Track streamed text for token estimation
@@ -1401,7 +1401,7 @@ func (b *Builder) wireDependencies() error {
14011401 // Estimate: 1 token ~= 4 chars
14021402 estimatedTokens := chars / 4
14031403 if app .program != nil {
1404- app .program . Send (ui.StreamTokenUpdateMsg {
1404+ app .safeSendToProgram (ui.StreamTokenUpdateMsg {
14051405 EstimatedOutputTokens : estimatedTokens ,
14061406 })
14071407 }
@@ -1411,7 +1411,7 @@ func (b *Builder) wireDependencies() error {
14111411 app .touchStepHeartbeat ()
14121412 logging .Debug ("OnThinking callback fired" , "text_length" , len (text ), "text_preview" , text [:min (len (text ), 80 )])
14131413 if app .program != nil {
1414- app .program . Send (ui .StreamThinkingMsg (text ))
1414+ app .safeSendToProgram (ui .StreamThinkingMsg (text ))
14151415 }
14161416 },
14171417 OnToolStart : func (name string , args map [string ]any ) {
@@ -1431,7 +1431,7 @@ func (b *Builder) wireDependencies() error {
14311431 }
14321432
14331433 if app .program != nil {
1434- app .program . Send (ui.ToolCallMsg {Name : name , Args : args })
1434+ app .safeSendToProgram (ui.ToolCallMsg {Name : name , Args : args })
14351435 }
14361436 app .journalEvent ("tool_start" , map [string ]any {
14371437 "tool" : name ,
@@ -1458,7 +1458,7 @@ func (b *Builder) wireDependencies() error {
14581458 app .mu .Unlock ()
14591459
14601460 if app .program != nil {
1461- app .program . Send (ui.ToolResultMsg {Name : name , Content : result .Content })
1461+ app .safeSendToProgram (ui.ToolResultMsg {Name : name , Content : result .Content })
14621462 }
14631463 app .journalEvent ("tool_end" , map [string ]any {
14641464 "tool" : name ,
@@ -1475,7 +1475,7 @@ func (b *Builder) wireDependencies() error {
14751475 app .mu .Lock ()
14761476 ctx := app .currentToolContext
14771477 app .mu .Unlock ()
1478- app .program . Send (ui.ToolProgressMsg {Name : name , Elapsed : elapsed , CurrentStep : ctx })
1478+ app .safeSendToProgram (ui.ToolProgressMsg {Name : name , Elapsed : elapsed , CurrentStep : ctx })
14791479 }
14801480 },
14811481 OnToolDetailedProgress : func (name string , progress float64 , currentStep string ) {
@@ -1487,7 +1487,7 @@ func (b *Builder) wireDependencies() error {
14871487 app .mu .Unlock ()
14881488 }
14891489 if app .program != nil {
1490- app .program . Send (ui.ToolProgressMsg {
1490+ app .safeSendToProgram (ui.ToolProgressMsg {
14911491 Name : name ,
14921492 Progress : progress ,
14931493 CurrentStep : currentStep ,
@@ -1499,12 +1499,12 @@ func (b *Builder) wireDependencies() error {
14991499 "error" : err .Error (),
15001500 })
15011501 if app .program != nil {
1502- app .program . Send (ui .ErrorMsg (err ))
1502+ app .safeSendToProgram (ui .ErrorMsg (err ))
15031503 }
15041504 },
15051505 OnInlineDiff : func (filePath , oldText , newText string ) {
15061506 if app .program != nil {
1507- app .program . Send (ui.InlineDiffMsg {
1507+ app .safeSendToProgram (ui.InlineDiffMsg {
15081508 FilePath : filePath ,
15091509 OldText : oldText ,
15101510 NewText : newText ,
@@ -1513,7 +1513,7 @@ func (b *Builder) wireDependencies() error {
15131513 },
15141514 OnLoopIteration : func (iteration int , toolsUsed int ) {
15151515 if app .program != nil {
1516- app .program . Send (ui.LoopIterationMsg {
1516+ app .safeSendToProgram (ui.LoopIterationMsg {
15171517 Iteration : iteration ,
15181518 ToolsUsed : toolsUsed ,
15191519 })
@@ -1536,7 +1536,7 @@ func (b *Builder) wireDependencies() error {
15361536 if maxTokens > 0 {
15371537 pct = float64 (inputTokens ) / float64 (maxTokens )
15381538 }
1539- app .program . Send (ui.TokenUsageMsg {
1539+ app .safeSendToProgram (ui.TokenUsageMsg {
15401540 Tokens : inputTokens ,
15411541 MaxTokens : maxTokens ,
15421542 PercentUsed : pct ,
@@ -1546,7 +1546,7 @@ func (b *Builder) wireDependencies() error {
15461546 },
15471547 OnFilePeek : func (filePath , title , content , action string ) {
15481548 if app .program != nil {
1549- app .program . Send (ui.FilePeekMsg {
1549+ app .safeSendToProgram (ui.FilePeekMsg {
15501550 FilePath : filePath ,
15511551 Title : title ,
15521552 Content : content ,
@@ -1563,7 +1563,7 @@ func (b *Builder) wireDependencies() error {
15631563 }
15641564 msg += ": " + summary
15651565 }
1566- app .program . Send (ui.LearningInsightMsg {Message : msg })
1566+ app .safeSendToProgram (ui.LearningInsightMsg {Message : msg })
15671567 }
15681568 },
15691569 })
@@ -1647,7 +1647,7 @@ func (b *Builder) wireDependencies() error {
16471647 if len (desc ) > 50 {
16481648 desc = desc [:47 ] + "..."
16491649 }
1650- app .program . Send (ui.BackgroundTaskMsg {
1650+ app .safeSendToProgram (ui.BackgroundTaskMsg {
16511651 ID : id ,
16521652 Type : "agent" ,
16531653 Description : desc ,
@@ -1666,7 +1666,7 @@ func (b *Builder) wireDependencies() error {
16661666 status = "cancelled"
16671667 }
16681668 }
1669- app .program . Send (ui.BackgroundTaskMsg {
1669+ app .safeSendToProgram (ui.BackgroundTaskMsg {
16701670 ID : id ,
16711671 Type : "agent" ,
16721672 Status : status ,
@@ -1710,7 +1710,7 @@ func (b *Builder) wireDependencies() error {
17101710 if total < 1 {
17111711 total = 1
17121712 }
1713- app .program . Send (ui.BackgroundTaskProgressMsg {
1713+ app .safeSendToProgram (ui.BackgroundTaskProgressMsg {
17141714 ID : id ,
17151715 Progress : float64 (progress .CurrentStep ) / float64 (total ),
17161716 CurrentStep : progress .CurrentStep ,
@@ -1732,21 +1732,21 @@ func (b *Builder) wireDependencies() error {
17321732 }
17331733
17341734 if app .program != nil {
1735- app .program . Send (ui .ScratchpadMsg (content ))
1735+ app .safeSendToProgram (ui .ScratchpadMsg (content ))
17361736 }
17371737 })
17381738
17391739 // Wire thinking callback for sub-agents
17401740 b .agentRunner .SetOnThinking (func (text string ) {
17411741 if app .program != nil {
1742- app .program . Send (ui .StreamThinkingMsg (text ))
1742+ app .safeSendToProgram (ui .StreamThinkingMsg (text ))
17431743 }
17441744 })
17451745
17461746 // Wire sub-agent activity to UI
17471747 b .agentRunner .SetOnSubAgentActivity (func (agentID , agentType , toolName string , args map [string ]any , status string ) {
17481748 if app .program != nil {
1749- app .program . Send (ui.SubAgentActivityMsg {
1749+ app .safeSendToProgram (ui.SubAgentActivityMsg {
17501750 AgentID : agentID ,
17511751 AgentType : agentType ,
17521752 ToolName : toolName ,
@@ -1846,7 +1846,7 @@ func (b *Builder) wireDependencies() error {
18461846 b .metaAgent .SetInterventionCallback (func (agentID string , reason string , action string ) {
18471847 if app .program != nil {
18481848 msg := fmt .Sprintf ("⚡ Meta-Agent: %s → %s" , action , reason )
1849- app .program . Send (ui.LearningInsightMsg {Message : msg })
1849+ app .safeSendToProgram (ui.LearningInsightMsg {Message : msg })
18501850 }
18511851 })
18521852 }
@@ -1855,7 +1855,7 @@ func (b *Builder) wireDependencies() error {
18551855 if b .agentRunner != nil {
18561856 b .agentRunner .SetOnThinking (func (text string ) {
18571857 if app .program != nil {
1858- app .program . Send (ui .StreamThinkingMsg (text ))
1858+ app .safeSendToProgram (ui .StreamThinkingMsg (text ))
18591859 }
18601860 })
18611861 }
@@ -1982,7 +1982,7 @@ type uiBroadcasterAdapter struct {
19821982// BroadcastTaskStarted sends a task started event to the UI.
19831983func (a * uiBroadcasterAdapter ) BroadcastTaskStarted (taskID , message , planType string ) {
19841984 if a .app != nil && a .app .program != nil {
1985- a .app .program . Send (ui.TaskStartedEvent {
1985+ a .app .safeSendToProgram (ui.TaskStartedEvent {
19861986 TaskID : taskID ,
19871987 Message : message ,
19881988 PlanType : planType ,
@@ -1993,7 +1993,7 @@ func (a *uiBroadcasterAdapter) BroadcastTaskStarted(taskID, message, planType st
19931993// BroadcastTaskCompleted sends a task completed event to the UI.
19941994func (a * uiBroadcasterAdapter ) BroadcastTaskCompleted (taskID string , success bool , duration time.Duration , err error , planType string ) {
19951995 if a .app != nil && a .app .program != nil {
1996- a .app .program . Send (ui.TaskCompletedEvent {
1996+ a .app .safeSendToProgram (ui.TaskCompletedEvent {
19971997 TaskID : taskID ,
19981998 Success : success ,
19991999 Duration : duration ,
@@ -2006,7 +2006,7 @@ func (a *uiBroadcasterAdapter) BroadcastTaskCompleted(taskID string, success boo
20062006// BroadcastTaskProgress sends a task progress event to the UI.
20072007func (a * uiBroadcasterAdapter ) BroadcastTaskProgress (taskID string , progress float64 , message string ) {
20082008 if a .app != nil && a .app .program != nil {
2009- a .app .program . Send (ui.TaskProgressEvent {
2009+ a .app .safeSendToProgram (ui.TaskProgressEvent {
20102010 TaskID : taskID ,
20112011 Progress : progress ,
20122012 Message : message ,
0 commit comments