@@ -406,3 +406,140 @@ func TestPartsToString(t *testing.T) {
406406 ),
407407 )
408408}
409+
410+ func TestInitialPromptReadiness (t * testing.T ) {
411+ now := time .Now ()
412+ changing := st .ConversationStatusChanging
413+ stable := st .ConversationStatusStable
414+
415+ t .Run ("agent not ready - status remains changing" , func (t * testing.T ) {
416+ cfg := st.ConversationConfig {
417+ GetTime : func () time.Time { return now },
418+ SnapshotInterval : 1 * time .Second ,
419+ ScreenStabilityLength : 2 * time .Second ,
420+ AgentIO : & testAgent {screen : "loading..." },
421+ IsAgentReadyForInitialPrompt : func (message string ) bool {
422+ return message == "ready"
423+ },
424+ }
425+ c := st .NewConversation (context .Background (), cfg , "initial prompt here" )
426+
427+ // Fill buffer with stable snapshots, but agent is not ready
428+ c .AddSnapshot ("loading..." )
429+ c .AddSnapshot ("loading..." )
430+ c .AddSnapshot ("loading..." )
431+
432+ // Even though screen is stable, status should be changing because agent is not ready
433+ assert .Equal (t , changing , c .Status ())
434+ assert .False (t , c .AgentReadyForInitialPrompt )
435+ assert .False (t , c .InitialPromptSent )
436+ })
437+
438+ t .Run ("agent becomes ready - status changes to stable" , func (t * testing.T ) {
439+ cfg := st.ConversationConfig {
440+ GetTime : func () time.Time { return now },
441+ SnapshotInterval : 1 * time .Second ,
442+ ScreenStabilityLength : 2 * time .Second ,
443+ AgentIO : & testAgent {screen : "loading..." },
444+ IsAgentReadyForInitialPrompt : func (message string ) bool {
445+ return message == "ready"
446+ },
447+ }
448+ c := st .NewConversation (context .Background (), cfg , "initial prompt here" )
449+
450+ // Agent not ready initially
451+ c .AddSnapshot ("loading..." )
452+ c .AddSnapshot ("loading..." )
453+ c .AddSnapshot ("loading..." )
454+ assert .Equal (t , changing , c .Status ())
455+
456+ // Agent becomes ready
457+ c .AddSnapshot ("ready" )
458+ c .AddSnapshot ("ready" )
459+ c .AddSnapshot ("ready" )
460+ assert .Equal (t , stable , c .Status ())
461+ assert .True (t , c .AgentReadyForInitialPrompt )
462+ assert .False (t , c .InitialPromptSent )
463+ })
464+
465+ t .Run ("no initial prompt - normal status logic applies" , func (t * testing.T ) {
466+ cfg := st.ConversationConfig {
467+ GetTime : func () time.Time { return now },
468+ SnapshotInterval : 1 * time .Second ,
469+ ScreenStabilityLength : 2 * time .Second ,
470+ AgentIO : & testAgent {screen : "loading..." },
471+ IsAgentReadyForInitialPrompt : func (message string ) bool {
472+ return false // Agent never ready
473+ },
474+ }
475+ // Empty initial prompt means no need to wait for readiness
476+ c := st .NewConversation (context .Background (), cfg , "" )
477+
478+ c .AddSnapshot ("loading..." )
479+ c .AddSnapshot ("loading..." )
480+ c .AddSnapshot ("loading..." )
481+
482+ // Status should be stable because no initial prompt to wait for
483+ assert .Equal (t , stable , c .Status ())
484+ assert .False (t , c .AgentReadyForInitialPrompt )
485+ assert .True (t , c .InitialPromptSent ) // Set to true when initial prompt is empty
486+ })
487+
488+ t .Run ("initial prompt sent - normal status logic applies" , func (t * testing.T ) {
489+ cfg := st.ConversationConfig {
490+ GetTime : func () time.Time { return now },
491+ SnapshotInterval : 1 * time .Second ,
492+ ScreenStabilityLength : 2 * time .Second ,
493+ AgentIO : & testAgent {screen : "processing..." },
494+ IsAgentReadyForInitialPrompt : func (message string ) bool {
495+ return false // Agent never ready
496+ },
497+ }
498+ c := st .NewConversation (context .Background (), cfg , "initial prompt here" )
499+ // Manually mark as sent to simulate that initial prompt was already sent
500+ c .InitialPromptSent = true
501+
502+ c .AddSnapshot ("processing..." )
503+ c .AddSnapshot ("processing..." )
504+ c .AddSnapshot ("processing..." )
505+
506+ // Status should be stable because initial prompt was already sent
507+ assert .Equal (t , stable , c .Status ())
508+ assert .False (t , c .AgentReadyForInitialPrompt )
509+ assert .True (t , c .InitialPromptSent )
510+ })
511+
512+ t .Run ("agent readiness detected once - stays ready" , func (t * testing.T ) {
513+ cfg := st.ConversationConfig {
514+ GetTime : func () time.Time { return now },
515+ SnapshotInterval : 1 * time .Second ,
516+ ScreenStabilityLength : 2 * time .Second ,
517+ AgentIO : & testAgent {screen : "ready" },
518+ IsAgentReadyForInitialPrompt : func (message string ) bool {
519+ return message == "ready"
520+ },
521+ }
522+ c := st .NewConversation (context .Background (), cfg , "initial prompt here" )
523+
524+ // Agent becomes ready
525+ c .AddSnapshot ("ready" )
526+ c .AddSnapshot ("ready" )
527+ c .AddSnapshot ("ready" )
528+ assert .Equal (t , stable , c .Status ())
529+ assert .True (t , c .AgentReadyForInitialPrompt )
530+
531+ // After agent is detected as ready, normal status logic applies
532+ // Screen changes should cause changing status
533+ c .AddSnapshot ("changing" )
534+ assert .Equal (t , changing , c .Status ())
535+ assert .True (t , c .AgentReadyForInitialPrompt )
536+
537+ // Once screen stabilizes again, status should be stable
538+ // AgentReadyForInitialPrompt remains true
539+ c .AddSnapshot ("stable now" )
540+ c .AddSnapshot ("stable now" )
541+ c .AddSnapshot ("stable now" )
542+ assert .Equal (t , stable , c .Status ())
543+ assert .True (t , c .AgentReadyForInitialPrompt )
544+ })
545+ }
0 commit comments