diff --git a/hld/session/manager.go b/hld/session/manager.go index 2c43c1c5..39626adf 100644 --- a/hld/session/manager.go +++ b/hld/session/manager.go @@ -1028,6 +1028,7 @@ func (m *Manager) processStreamEvent(ctx context.Context, sessionID string, clau EventType: store.EventTypeSystem, Role: "system", Content: fmt.Sprintf("Session created with ID: %s", event.SessionID), + ParentToolUseID: event.ParentToolUseID, } if err := m.store.AddConversationEvent(ctx, convEvent); err != nil { return err @@ -1038,12 +1039,13 @@ func (m *Manager) processStreamEvent(ctx context.Context, sessionID string, clau m.eventBus.Publish(bus.Event{ Type: bus.EventConversationUpdated, Data: map[string]interface{}{ - "session_id": sessionID, - "claude_session_id": claudeSessionID, - "event_type": "system", - "subtype": event.Subtype, - "content": fmt.Sprintf("Session created with ID: %s", event.SessionID), - "content_type": "system", + "session_id": sessionID, + "claude_session_id": claudeSessionID, + "event_type": "system", + "subtype": event.Subtype, + "content": fmt.Sprintf("Session created with ID: %s", event.SessionID), + "content_type": "system", + "parent_tool_use_id": event.ParentToolUseID, }, }) } @@ -1125,6 +1127,7 @@ func (m *Manager) processStreamEvent(ctx context.Context, sessionID string, clau EventType: store.EventTypeMessage, Role: event.Message.Role, Content: content.Text, + ParentToolUseID: event.ParentToolUseID, } if err := m.store.AddConversationEvent(ctx, convEvent); err != nil { return err @@ -1138,12 +1141,13 @@ func (m *Manager) processStreamEvent(ctx context.Context, sessionID string, clau m.eventBus.Publish(bus.Event{ Type: bus.EventConversationUpdated, Data: map[string]interface{}{ - "session_id": sessionID, - "claude_session_id": claudeSessionID, - "event_type": "message", - "role": event.Message.Role, - "content": content.Text, - "content_type": "text", + "session_id": sessionID, + "claude_session_id": claudeSessionID, + "event_type": "message", + "role": event.Message.Role, + "content": content.Text, + "content_type": "text", + "parent_tool_use_id": event.ParentToolUseID, }, }) } @@ -1204,6 +1208,7 @@ func (m *Manager) processStreamEvent(ctx context.Context, sessionID string, clau Role: "user", ToolResultForID: content.ToolUseID, ToolResultContent: content.Content.Value, + ParentToolUseID: event.ParentToolUseID, } if err := m.store.AddConversationEvent(ctx, convEvent); err != nil { return err @@ -1228,6 +1233,7 @@ func (m *Manager) processStreamEvent(ctx context.Context, sessionID string, clau "tool_result_for_id": content.ToolUseID, "tool_result_content": content.Content.Value, "content_type": "tool_result", + "parent_tool_use_id": event.ParentToolUseID, }, }) } @@ -1249,6 +1255,7 @@ func (m *Manager) processStreamEvent(ctx context.Context, sessionID string, clau EventType: store.EventTypeThinking, Role: event.Message.Role, Content: content.Thinking, + ParentToolUseID: event.ParentToolUseID, } if err := m.store.AddConversationEvent(ctx, convEvent); err != nil { return err @@ -1262,12 +1269,13 @@ func (m *Manager) processStreamEvent(ctx context.Context, sessionID string, clau m.eventBus.Publish(bus.Event{ Type: bus.EventConversationUpdated, Data: map[string]interface{}{ - "session_id": sessionID, - "claude_session_id": claudeSessionID, - "event_type": "thinking", - "role": event.Message.Role, - "content": content.Thinking, - "content_type": "thinking", + "session_id": sessionID, + "claude_session_id": claudeSessionID, + "event_type": "thinking", + "role": event.Message.Role, + "content": content.Thinking, + "content_type": "thinking", + "parent_tool_use_id": event.ParentToolUseID, }, }) } diff --git a/humanlayer-wui/src/components/internal/SessionDetail/components/ActiveSession.tsx b/humanlayer-wui/src/components/internal/SessionDetail/components/ActiveSession.tsx index aa42a178..d5322ea2 100644 --- a/humanlayer-wui/src/components/internal/SessionDetail/components/ActiveSession.tsx +++ b/humanlayer-wui/src/components/internal/SessionDetail/components/ActiveSession.tsx @@ -306,6 +306,7 @@ export function ActiveSession({ session, onClose }: ActiveSessionProps) { // Check if there are pending approvals out of view const [hasPendingApprovalsOutOfView, setHasPendingApprovalsOutOfView] = useState(false) + const [pendingApprovalsCount, setPendingApprovalsCount] = useState(0) const lastTodo = events ?.toReversed() @@ -770,8 +771,12 @@ export function ActiveSession({ session, onClose }: ActiveSessionProps) { useEffect(() => { const checkPendingApprovalVisibility = () => { if (session.status === SessionStatus.WaitingInput) { - const pendingEvent = events.find(e => e.approvalStatus === ApprovalStatus.Pending) - if (pendingEvent) { + const pendingEvents = events.filter(e => e.approvalStatus === ApprovalStatus.Pending) + setPendingApprovalsCount(pendingEvents.length) + + if (pendingEvents.length > 0) { + // Check visibility of the first pending approval + const pendingEvent = pendingEvents[0] const container = document.querySelector('[data-conversation-container]') const element = container?.querySelector(`[data-event-id="${pendingEvent.id}"]`) if (container && element) { @@ -796,6 +801,7 @@ export function ActiveSession({ session, onClose }: ActiveSessionProps) { setHasPendingApprovalsOutOfView(false) } } else { + setPendingApprovalsCount(0) setHasPendingApprovalsOutOfView(false) } } @@ -918,7 +924,11 @@ export function ActiveSession({ session, onClose }: ActiveSessionProps) { }} >
- Pending Approval + + {pendingApprovalsCount === 1 + ? 'Pending Approval' + : `${pendingApprovalsCount} Pending Approvals`} +