@@ -22,6 +22,7 @@ import PlanView from "./plan";
2222import { IPlanStep , convertToIPlanSteps } from "../../types/plan" ;
2323import RenderFile from "../../common/filerenderer" ;
2424import LearnPlanButton from "../../features/Plans/LearnPlanButton" ;
25+ import RenderSentinelStep from "./rendersentinelstep" ;
2526
2627// Types
2728interface MessageProps {
@@ -40,6 +41,8 @@ interface MessageProps {
4041 onRegeneratePlan ?: ( ) => void ;
4142 runStatus ?: string ;
4243 forceCollapsed ?: boolean ;
44+ allMessages ?: any [ ] ; // All messages for sentinel step tracking
45+ skipSentinelHiding ?: boolean ; // Skip hiding sentinel messages (used inside RenderSentinelStep)
4346}
4447
4548interface RenderPlanProps {
@@ -540,6 +543,18 @@ export const messageUtils = {
540543 return metadata ?. type === "step_execution" ;
541544 } ,
542545
546+ isSentinelStart ( metadata ?: Record < string , any > ) : boolean {
547+ return metadata ?. type === "sentinel_start" ;
548+ } ,
549+
550+ isSentinelCheck ( metadata ?: Record < string , any > ) : boolean {
551+ return metadata ?. type === "sentinel_check" ;
552+ } ,
553+
554+ isSentinelComplete ( metadata ?: Record < string , any > ) : boolean {
555+ return metadata ?. type === "sentinel_complete" ;
556+ } ,
557+
543558 findUserPlan ( content : unknown ) : IPlanStep [ ] {
544559 if ( typeof content !== "string" ) return [ ] ;
545560 try {
@@ -670,10 +685,61 @@ export const RenderMessage: React.FC<MessageProps> = memo(
670685 onToggleHide,
671686 onRegeneratePlan,
672687 forceCollapsed = false ,
688+ allMessages = [ ] ,
689+ skipSentinelHiding = false ,
673690 } ) => {
674691 if ( ! message ) return null ;
675692 if ( message . metadata ?. type === "browser_address" ) return null ;
676693
694+ // Hide sentinel check and complete messages - they're shown in RenderSentinelStep
695+ // Unless we're inside RenderSentinelStep (skipSentinelHiding = true)
696+ if ( ! skipSentinelHiding ) {
697+ if (
698+ messageUtils . isSentinelCheck ( message . metadata ) ||
699+ messageUtils . isSentinelComplete ( message . metadata )
700+ ) {
701+ return null ;
702+ }
703+
704+ // Hide agent messages that are part of a sentinel step check (they're shown in RenderSentinelStep)
705+ if ( message . metadata ?. sentinel_id && message . metadata ?. check_number ) {
706+ return null ;
707+ }
708+ }
709+
710+ // Handle sentinel start message
711+ if ( messageUtils . isSentinelStart ( message . metadata ) ) {
712+ try {
713+ const sentinelData = JSON . parse ( message . content as string ) ;
714+ return (
715+ < div className = "mb-3 w-full" >
716+ < RenderSentinelStep
717+ sentinelId = { message . metadata ?. sentinel_id || "" }
718+ title = { sentinelData . title || message . metadata ?. step_title || "" }
719+ condition = {
720+ sentinelData . condition || message . metadata ?. condition || ""
721+ }
722+ sleepDuration = {
723+ sentinelData . sleep_duration ||
724+ parseInt ( message . metadata ?. sleep_duration || "30" )
725+ }
726+ allMessages = { allMessages }
727+ currentMessageIndex = { messageIdx }
728+ sessionId = { sessionId }
729+ runStatus = { runStatus }
730+ />
731+ </ div >
732+ ) ;
733+ } catch ( e ) {
734+ // Fallback if JSON parsing fails
735+ return (
736+ < div className = "mb-3 w-full text-sm text-gray-600" >
737+ Executing sentinel step: { message . metadata ?. step_title || "" }
738+ </ div >
739+ ) ;
740+ }
741+ }
742+
677743 const isUser = messageUtils . isUser ( message . source ) ;
678744 const isUserProxy = message . source === "user_proxy" ;
679745 const isOrchestrator = [ "Orchestrator" ] . includes ( message . source ) ;
0 commit comments