Skip to content

Conversation

@changhoi
Copy link
Contributor

Resolves TA-232

Summary

Session 상세 페이지에 Graph View를 추가합니다. React Flow를 사용하여 Main Session과 SubAgent들의 호출 관계를 좌우 흐름도(Left to Right) 형태로 시각화합니다.

Features

  • Chat View와 Graph View 간 전환 토글
  • Main Session 노드와 SubAgent 노드들을 좌에서 우로 시간 순서대로 배치
  • Main에서 SubAgent로의 호출 관계를 연결선으로 표시
  • 노드 클릭 시 해당 SubAgent의 메시지 목록을 Popover로 표시
  • 각 노드에 토큰 사용량 표시 (input/output/cache)
  • React Flow Controls (zoom/pan) 및 MiniMap 지원

Issue

https://linear.app/team-attention/issue/TA-232/session-graph-view-component

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@gemini-code-assist
Copy link

Summary of Changes

Hello @changhoi, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 풀 리퀘스트는 세션 상세 페이지에 혁신적인 그래프 뷰를 도입하여 사용자가 복잡한 에이전트 상호작용을 더 쉽게 이해할 수 있도록 합니다. 메인 세션과 서브 에이전트 간의 호출 관계를 시각적으로 표현하고, 각 단계에서 사용된 토큰 정보를 제공함으로써, 시스템의 동작 방식과 리소스 흐름에 대한 깊이 있는 통찰력을 제공합니다. 이는 디버깅 및 성능 분석에 큰 도움이 될 것입니다.

Highlights

  • 세션 그래프 뷰 도입: 메인 세션과 서브 에이전트 간의 호출 관계를 시각화하는 새로운 그래프 뷰가 세션 상세 페이지에 추가되었습니다.
  • React Flow 통합: 대화 흐름을 인터랙티브하게 표시하기 위해 @xyflow/react 라이브러리가 도입되었습니다.
  • 노드별 메시지 팝오버: 그래프 노드를 클릭하면 해당 세션의 메시지 목록을 보여주는 팝오버가 표시됩니다.
  • 토큰 사용량 시각화: 각 세션 노드에 입력/출력/캐시 토큰 사용량이 표시되어 리소스 소비를 한눈에 파악할 수 있습니다.
  • 뷰 전환 기능: 기존 채팅 뷰와 새로운 그래프 뷰 간을 전환할 수 있는 토글 버튼이 추가되었습니다.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

이 PR은 세션 그래프 뷰를 성공적으로 추가하여 메인 세션과 서브 에이전트 간의 상호작용을 훌륭하게 시각화합니다. React Flow를 사용한 구현은 관심사를 여러 컴포넌트와 유틸리티 파일로 명확하게 분리하여 잘 구조화되어 있습니다. 성능과 견고성을 개선하기 위한 몇 가지 제안을 포함했습니다. 전반적으로 훌륭한 추가 기능입니다.

Comment on lines 77 to 90
const selectedNodeSessions = useMemo(() => {
if (!selectedNodeId) return []
const node = nodes.find((n) => n.id === selectedNodeId)
if (!node || !isSessionNode(node)) return []
return node.data.sessions
}, [nodes, selectedNodeId])

// Get selected node's label for popover
const selectedNodeLabel = useMemo(() => {
if (!selectedNodeId) return ''
const node = nodes.find((n) => n.id === selectedNodeId)
if (!node || !isSessionNode(node)) return ''
return node.data.label
}, [nodes, selectedNodeId])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

두 개의 useMemo 훅에서 selectedNodeSessionsselectedNodeLabel을 계산하기 위해 각각 nodes 배열을 순회하고 있습니다. 이로 인해 불필요한 중복 계산이 발생할 수 있습니다.

하나의 useMemo 훅을 사용하여 selectedNode를 찾은 다음, 그 결과를 바탕으로 selectedNodeSessionsselectedNodeLabel을 파생시키는 것이 더 효율적이고 가독성이 좋습니다.

  // Get selected node and its data for popover
  const selectedNode = useMemo(() => {
    if (!selectedNodeId) {
      return null
    }
    const node = nodes.find((n) => n.id === selectedNodeId)
    return node && isSessionNode(node) ? node : null
  }, [nodes, selectedNodeId])

  const selectedNodeSessions = selectedNode?.data.sessions ?? []
  const selectedNodeLabel = selectedNode?.data.label ?? ''

} satisfies SessionNode)

// Group SubAgents by timestamp to identify parallel spawns
// Use toolExecutionId for grouping since parallel calls happen in same batch

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

이 주석은 구현 내용과 일치하지 않는 것 같습니다. 코드는 toolExecutionId가 아닌 타임스탬프를 기준으로 서브 에이전트를 그룹화하여 병렬 실행 여부를 판단하고 있습니다.

타임스탬프를 기준으로 그룹화하는 방식은 대부분의 경우에 잘 동작하겠지만, 완전히 견고하지는 않습니다. 순차적으로 실행된 별개의 에이전트 호출이 같은 초(second) 내에 발생할 경우 동일한 타임스탬프 키를 갖게 되어, 병렬로 잘못 렌더링될 수 있습니다.

더 신뢰성 있는 방법은 서브 에이전트를 생성한 부모 에이전트 메시지의 ID를 기준으로 그룹화하는 것입니다. 이를 위해서는 PROGRESS_TYPE_AGENT 이벤트에서부터 원본 에이전트 메시지까지 거슬러 올라가는 추가적인 로직이 필요할 수 있습니다.

우선은 현재 로직을 정확하게 설명하도록 주석을 수정하는 것이 좋겠습니다.

Suggested change
// Use toolExecutionId for grouping since parallel calls happen in same batch
// Use timestamp for grouping to identify parallel calls

changhoi and others added 4 commits January 30, 2026 16:20
- Add buildToolExecutionMetadata helper function
- Populate ToolExecution.Metadata with IsSubagent and SubagentID
- Add unit tests for SubAgent metadata conversion

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ents

- Add maxRetries parameter to FindByBatchID in EventQueryPort
- Update MongoDB adapter to filter by retryCount < maxRetries
- Pass config maxRetries value in processBatch

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ProgressTypeSkill constant to v2 domain
- Re-add PROGRESS_TYPE_SKILL = 2 to proto definition
- Update API gRPC converter to handle ProgressTypeSkill
- Update frontend types and components for skill progress

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add GraphPopupState interface for external popup state management
- Modify SessionGraphView to accept onNodeSelect callback
- Move MessagePopover rendering to parent component

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@changhoi
Copy link
Contributor Author

TA-233: Fix SubAgent-Tool relationship in claudecodeadapter conversion

Problem

SubAgent logs were not displaying correctly in the dashboard because ToolExecutionMetadata (containing IsSubagent and SubagentID fields) was not being populated during the Claude Code adapter conversion process.

Changes

  • Added buildToolExecutionMetadata helper function in converter.go
  • Updated adaptAssistant to populate ToolExecution.Metadata for SubAgent tool executions
  • Updated splitUserContent to populate ToolExecution.Metadata for SubAgent tool results
  • Added 5 unit tests for SubAgent metadata conversion

Files Modified

  • shared/domain/v2/claudecodeadapter/converter.go
  • shared/domain/v2/claudecodeadapter/converter_test.go (new)

@changhoi
Copy link
Contributor Author

TA-234: Fix event retry infinite increase by excluding max-retried events

Problem

Event retry count was increasing infinitely because events that exceeded the maximum retry count were still being fetched for processing.

Solution

Simple fix: Add retryCount < maxRetries filter to the FindByBatchID query so events that have exceeded max retries are never fetched for processing.

Changes

  • Added maxRetries parameter to FindByBatchID in EventQueryPort interface
  • Updated MongoDB adapter to filter by retryCount < maxRetries
  • Updated processBatch to pass s.cfg.Retry.MaxRetries to the query

Files Modified

  • api/internal/service/session/outbound/repository/event_query_port.go
  • api/internal/service/session/outbound/repository/mongodb/event_query.go
  • api/internal/service/session/session_service.go

@changhoi
Copy link
Contributor Author

TA-235: Fix Skill Progress type display in Session Detail UI

Problem

Session Detail UI was displaying "Unknown" for Skill Progress type messages because the skill_progress type mapping was missing throughout the data flow.

Changes

Go Backend:

  • Added ProgressTypeSkill constant to v2 domain (session_progress.go)
  • Re-added PROGRESS_TYPE_SKILL = 2 to proto definition
  • Updated API gRPC converter to handle ProgressTypeSkill

Frontend:

  • Updated content-block.ts to include 'skill' in progressType union
  • Updated parse-content.ts to handle ProgressType.SKILL
  • Updated message-bubble.tsx to display "Skill" label
  • Updated message-detail-sheet.tsx to display "Skill" label

Files Modified

  • shared/domain/v2/session_progress.go
  • idl/protobuf/session/v1/session.proto
  • shared/gen/grpcstub/session/v1/session.pb.go (regenerated)
  • web/src/gen/grpcstub/session/v1/session_pb.ts (regenerated)
  • api/internal/service/dashboard/inbound/grpc/connectrpc/converter.go
  • web/src/feature/session/type/content-block.ts
  • web/src/feature/session/util/parse-content.ts
  • web/src/feature/session/component/message-bubble.tsx
  • web/src/feature/session/component/message-detail-sheet.tsx

@changhoi
Copy link
Contributor Author

TA-236: Fix Graph View popup position by moving popup outside container

Problem

The MessagePopover in Graph View was rendered inside a Card container with overflow-hidden, causing the popup to be clipped at container boundaries.

Solution

Move popup state management to the parent component and render MessagePopover outside the SessionGraphView component, ensuring it displays without container clipping.

Changes

  • Added GraphPopupState interface for external popup state management
  • Modified SessionGraphView to accept onNodeSelect callback instead of internal popup state
  • Updated $sessionId.tsx to manage popup state externally and render MessagePopover at page level
  • Added type guard functions in parse-content.ts for type-safe node data access

Files Modified

  • web/src/feature/session/type/graph.ts
  • web/src/feature/session/component/session-graph-view.tsx
  • web/src/route/sessions/$sessionId.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants