Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"coverage": "pnpm install --frozen-lockfile && pnpm --filter @argos/web run coverage:erd"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@eslint/eslintrc": "^3.3.5",
"eslint": "^9",
"turbo": "^2.9.16",
"typescript-eslint": "^8"
Expand All @@ -21,7 +21,9 @@
"@babel/core": "7.29.7",
"esbuild": "0.28.1",
"hono": "4.12.25",
"js-yaml": "4.2.0"
"js-yaml": "4.3.0",
"body-parser": "2.3.0",
"brace-expansion": "1.1.16"
Comment on lines +24 to +26
}
}
}
61 changes: 30 additions & 31 deletions packages/web/src/components/dashboard/session-timeline-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,29 +35,12 @@ interface ChartDataItem {
toolSummary: string
}

function getToolSummaryForIndex(
index: number,
usageTimeline: SessionTimelineUsage[],
toolCalls: ToolCallPoint[]
): string {
if (toolCalls.length === 0) return ''

const currentTimestamp = new Date(usageTimeline[index]!.timestamp).getTime()
const prevTimestamp =
index > 0 ? new Date(usageTimeline[index - 1]!.timestamp).getTime() : 0

// 현재 usageTimeline timestamp 이전이면서, 이전 usageTimeline timestamp 이후의 tool events 찾기
// 첫 번째 bar(index=0)는 prevTimestamp가 0이므로 해당 bar 이전의 모든 이벤트를 포함
const relevantTools = toolCalls.filter((e) => {
const toolTimestamp = e.parsedTimestamp
return toolTimestamp <= currentTimestamp && toolTimestamp > prevTimestamp
})

if (relevantTools.length === 0) return ''
function formatToolSummary(tools: ToolCallPoint[]): string {
if (tools.length === 0) return ''

// 이름별로 카운트
const counts = new Map<string, number>()
for (const tool of relevantTools) {
for (const tool of tools) {
const name = tool.toolName || 'unknown'
counts.set(name, (counts.get(name) || 0) + 1)
}
Expand Down Expand Up @@ -138,20 +121,36 @@ export function SessionTimelineChart({
toolName: m.toolName ?? 'unknown',
parsedTimestamp: new Date(m.timestamp).getTime(),
}))
.sort((a, b) => a.parsedTimestamp - b.parsedTimestamp)
}, [messages])

// ⚡ Bolt: usageTimeline 배열을 순회하며 차트 데이터를 생성하는 비용이 높은 작업을
// useMemo로 최적화하여 데이터 변경이 없을 때 캐시된 결과를 재사용함.
// 이로 인해 리렌더링 속도가 향상됨.
// ⚡ Bolt: O(N*M) 복잡도를 O(N+M)으로 최적화하기 위해 두 포인터를 사용함.
// usageTimeline과 toolCalls가 각각 시간순으로 정렬되어 있음을 활용하여 한 번의 순회로 매핑을 완료함.
const chartData: ChartDataItem[] = useMemo(() => {
return usageTimeline.map((u, idx) => ({
relativeTime: formatRelativeTime(u.timestamp, sessionStartedAt),
input: u.inputTokens,
output: u.outputTokens,
cost: u.estimatedCostUsd,
model: u.model,
toolSummary: getToolSummaryForIndex(idx, usageTimeline, toolCalls),
}))
const sortedUsageTimeline = [...usageTimeline].sort(
(a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
)
Comment on lines +130 to +132

let toolIndex = 0

return sortedUsageTimeline.map((u) => {
const currentTimestamp = new Date(u.timestamp).getTime()

const relevantTools: ToolCallPoint[] = []
while (toolIndex < toolCalls.length && toolCalls[toolIndex]!.parsedTimestamp <= currentTimestamp) {
relevantTools.push(toolCalls[toolIndex]!)
toolIndex++
}
Comment on lines +139 to +143

return {
relativeTime: formatRelativeTime(u.timestamp, sessionStartedAt),
input: u.inputTokens,
output: u.outputTokens,
cost: u.estimatedCostUsd,
model: u.model,
toolSummary: formatToolSummary(relevantTools),
}
})
}, [usageTimeline, sessionStartedAt, toolCalls])

if (usageTimeline.length === 0) {
Expand Down
59 changes: 20 additions & 39 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading