@@ -1261,6 +1261,73 @@ function providerLabel(provider?: string) {
12611261 return 'MISCONDUCT' ;
12621262}
12631263
1264+ function phaseAgentLabel ( stage ?: string ) {
1265+ const value = String ( stage || '' ) . toLowerCase ( ) ;
1266+ if ( value === 'conductor' ) return 'Conductor' ;
1267+ if ( value === 'build' || value === 'builder' ) return 'Builder' ;
1268+ if ( value === 'judge' || value === 'review' ) return 'Judge' ;
1269+ if ( value === 'refiner' || value === 'refine' ) return 'Refiner' ;
1270+ if ( value === 'retry' ) return 'Stage Manager' ;
1271+ return 'MISCONDUCT' ;
1272+ }
1273+
1274+ function eventAgentName ( event : OrchestrationEvent ) {
1275+ const data = event . data ;
1276+ if ( ! data || typeof data !== 'object' || Array . isArray ( data ) ) return '' ;
1277+ const profile = data . agent_profile ;
1278+ if ( ! profile || typeof profile !== 'object' || Array . isArray ( profile ) ) return '' ;
1279+ return stringField ( profile as Record < string , unknown > , 'name' ) ;
1280+ }
1281+
1282+ function eventSpeaker ( event : OrchestrationEvent ) {
1283+ const type = String ( event . type || '' ) . toLowerCase ( ) ;
1284+ const action = String ( event . action || '' ) . toLowerCase ( ) ;
1285+ const agentName = eventAgentName ( event ) ;
1286+
1287+ if ( type . includes ( 'operator' ) ) return 'Operator' ;
1288+ if ( type . includes ( 'retry' ) ) return 'Stage Manager' ;
1289+ if ( type === 'agent.event' && ( action === 'stdout' || action === 'turn_completed' ) ) {
1290+ return agentName || phaseAgentLabel ( event . stage ) ;
1291+ }
1292+ if ( type === 'agent.event' && ( action === 'stderr' || action === 'turn_failed' || action === 'session_started' ) ) {
1293+ return 'Codex Runner' ;
1294+ }
1295+ if ( agentName ) return agentName ;
1296+ if ( event . stage ) return phaseAgentLabel ( event . stage ) ;
1297+ return providerLabel ( event . provider ) ;
1298+ }
1299+
1300+ function eventReadableType ( event : OrchestrationEvent ) {
1301+ const type = String ( event . type || '' ) . toLowerCase ( ) ;
1302+ const action = String ( event . action || '' ) . toLowerCase ( ) ;
1303+
1304+ if ( type === 'operator.issue.action.accepted' ) return 'Operator accepted action' ;
1305+ if ( type === 'issue.stage.started' ) return `${ phaseAgentLabel ( event . stage ) } started` ;
1306+ if ( type === 'issue.stage.completed' ) return `${ phaseAgentLabel ( event . stage ) } completed` ;
1307+ if ( type === 'issue.stage.blocked' ) return `${ phaseAgentLabel ( event . stage ) } blocked` ;
1308+ if ( type === 'issue.score.ready' ) return 'Conductor score ready' ;
1309+ if ( type === 'issue.judge.verdict' ) return 'Judge verdict' ;
1310+ if ( type === 'issue.execution.completed' ) return 'Movement completed' ;
1311+ if ( type === 'issue.execution.failed' ) return 'Movement failed' ;
1312+ if ( type === 'issue.retry.scheduled' ) return 'Retry scheduled' ;
1313+ if ( type === 'agent.event' && action === 'session_started' ) return 'Subprocess started' ;
1314+ if ( type === 'agent.event' && action === 'stdout' ) return 'Agent output' ;
1315+ if ( type === 'agent.event' && action === 'stderr' ) return 'Runner output' ;
1316+ if ( type === 'agent.event' && action === 'turn_completed' ) return 'Turn completed' ;
1317+ if ( type === 'agent.event' && action === 'turn_failed' ) return 'Turn failed' ;
1318+ return event . type || 'Event' ;
1319+ }
1320+
1321+ function eventTone ( event : OrchestrationEvent ) {
1322+ const combined = `${ event . status || '' } ${ event . type || '' } ${ event . action || '' } ` . toLowerCase ( ) ;
1323+ if ( combined . match ( / f a i l | e r r o r | s t d e r r | b l o c k | r e j e c t / ) ) return 'danger' ;
1324+ if ( combined . match ( / r e t r y | r e f i n | a t t e n t i o n / ) ) return 'warning' ;
1325+ if ( combined . match ( / j u d g e | r e v i e w | v e r d i c t / ) ) return 'review' ;
1326+ if ( combined . match ( / c o m p l e t e | p a s s | a p p r o v e d | r e a d y / ) ) return 'success' ;
1327+ if ( combined . match ( / s t a r t | r u n n i n g | a c c e p t e d / ) ) return 'active' ;
1328+ return 'neutral' ;
1329+ }
1330+
12641331function authPhaseLabel ( phase ?: string ) {
12651332 const normalized = String ( phase || '' ) . replace ( / _ / g, ' ' ) ;
12661333 if ( ! normalized ) return 'auth phase unknown' ;
@@ -2383,8 +2450,7 @@ function MovementEvents({ card, debugPayload, liveEvents }: { card: Card; debugP
23832450 const ids = [ event . issue_id , event . issue_identifier ] . filter ( Boolean ) ;
23842451 return ids . includes ( card . backendId ) || ids . includes ( card . identifier ) ;
23852452 } )
2386- . slice ( - 18 )
2387- . reverse ( ) ;
2453+ . slice ( - 24 ) ;
23882454 const events = [
23892455 [ 'Movement' , card . movement ] ,
23902456 [ 'Status' , card . status ] ,
@@ -2400,14 +2466,42 @@ function MovementEvents({ card, debugPayload, liveEvents }: { card: Card; debugP
24002466 < div className = "movementTimeline" >
24012467 { events . map ( ( [ label , value ] ) => < div className = "timelineRow" key = { label } > < b > { label } </ b > < span > { value } </ span > </ div > ) }
24022468 < div className = "liveMovementLedger" >
2403- < h3 > Live pit ledger </ h3 >
2404- { movementEvents . length ? movementEvents . map ( event => < EventRow event = { event } key = { event . id } /> ) : < p className = "subtle" > No live events for this movement yet.</ p > }
2469+ < h3 > Agent conversation </ h3 >
2470+ { movementEvents . length ? < EventConversation events = { movementEvents } /> : < p className = "subtle" > No live events for this movement yet.</ p > }
24052471 </ div >
24062472 { debugPayload && < pre className = "debugPanel inline" > { debugPayload } </ pre > }
24072473 </ div >
24082474 ) ;
24092475}
24102476
2477+ function EventConversation ( { events } : { events : OrchestrationEvent [ ] } ) {
2478+ return (
2479+ < div className = "eventConversation" aria-label = "Movement agent conversation" >
2480+ { events . map ( event => < EventBubble event = { event } key = { event . id } /> ) }
2481+ </ div >
2482+ ) ;
2483+ }
2484+
2485+ function EventBubble ( { event } : { event : OrchestrationEvent } ) {
2486+ const speaker = eventSpeaker ( event ) ;
2487+ const own = speaker === 'Operator' || speaker === 'Conductor' || speaker === 'Workflow Conductor' ;
2488+ const tone = eventTone ( event ) ;
2489+ const message = event . message || event . action || 'Event received' ;
2490+
2491+ return (
2492+ < div className = { `eventBubbleRow ${ own ? 'own' : '' } ` } >
2493+ < div className = { `agentBubble ${ tone } ` } >
2494+ < div className = "speechMeta" >
2495+ < b > { speaker } </ b >
2496+ < span > { formatEventTime ( event . occurred_at ) } </ span >
2497+ </ div >
2498+ < p > { message } </ p >
2499+ < small > { eventReadableType ( event ) } · { providerLabel ( event . provider ) } </ small >
2500+ </ div >
2501+ </ div >
2502+ ) ;
2503+ }
2504+
24112505function MovementTools ( { card, busy, onDebug, onMove, onAction } : { card : Card ; busy : boolean ; onDebug : ( id : string ) => void ; onMove : ( id : string , target : string ) => void ; onAction : ( id : string , action : string ) => void } ) {
24122506 return (
24132507 < div className = "movementTools" >
@@ -3080,9 +3174,9 @@ function EventRow({ event }: { event: OrchestrationEvent }) {
30803174 return (
30813175 < div className = "eventRow" >
30823176 < div className = "eventMain" >
3083- < span className = { `eventDot ${ statusClass ( event . status || event . type ) } ` } />
3177+ < span className = { `eventDot ${ eventTone ( event ) } ` } />
30843178 < div >
3085- < b > { event . type } </ b >
3179+ < b > { eventReadableType ( event ) } </ b >
30863180 < small > { providerLabel ( event . provider ) } · { event . stage || 'system' } · { formatEventTime ( event . occurred_at ) } </ small >
30873181 </ div >
30883182 </ div >
0 commit comments