agentlytics 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/cache.js +413 -9
- package/editors/cursor.js +28 -6
- package/editors/vscode.js +6 -0
- package/package.json +1 -1
- package/server.js +27 -0
- package/ui/package-lock.json +60 -375
- package/ui/package.json +1 -1
- package/ui/src/App.jsx +4 -1
- package/ui/src/lib/api.js +20 -0
- package/ui/src/lib/constants.js +8 -0
- package/ui/src/pages/ChatDetail.jsx +5 -2
- package/ui/src/pages/CostAnalysis.jsx +356 -0
- package/ui/src/pages/Dashboard.jsx +25 -7
- package/ui/src/pages/DeepAnalysis.jsx +11 -4
- package/ui/src/pages/ProjectDetail.jsx +12 -4
- package/ui/src/pages/Projects.jsx +9 -3
- package/ui/src/pages/Sessions.jsx +5 -1
|
@@ -3,8 +3,8 @@ import { useSearchParams, useNavigate } from 'react-router-dom'
|
|
|
3
3
|
import { ArrowLeft, Search, FolderOpen, Calendar, MessageSquare, Wrench, Cpu, Zap, AlertTriangle } from 'lucide-react'
|
|
4
4
|
import { Chart as ChartJS, ArcElement, Tooltip, Legend, CategoryScale, LinearScale, BarElement } from 'chart.js'
|
|
5
5
|
import { Doughnut, Bar } from 'react-chartjs-2'
|
|
6
|
-
import { fetchProjects, fetchChats } from '../lib/api'
|
|
7
|
-
import { editorColor, editorLabel, formatNumber, formatDate } from '../lib/constants'
|
|
6
|
+
import { fetchProjects, fetchChats, fetchCosts } from '../lib/api'
|
|
7
|
+
import { editorColor, editorLabel, formatNumber, formatDate, formatCost } from '../lib/constants'
|
|
8
8
|
import { useTheme } from '../lib/theme'
|
|
9
9
|
import KpiCard from '../components/KpiCard'
|
|
10
10
|
import EditorIcon from '../components/EditorIcon'
|
|
@@ -31,6 +31,7 @@ export default function ProjectDetail() {
|
|
|
31
31
|
const [loading, setLoading] = useState(true)
|
|
32
32
|
const [chatSearch, setChatSearch] = useState('')
|
|
33
33
|
const [selectedChatId, setSelectedChatId] = useState(null)
|
|
34
|
+
const [costs, setCosts] = useState(null)
|
|
34
35
|
const [enabledEditors, setEnabledEditors] = useState(null)
|
|
35
36
|
|
|
36
37
|
useEffect(() => {
|
|
@@ -39,10 +40,12 @@ export default function ProjectDetail() {
|
|
|
39
40
|
Promise.all([
|
|
40
41
|
fetchProjects(),
|
|
41
42
|
fetchChats({ folder, limit: 1000 }),
|
|
42
|
-
|
|
43
|
+
fetchCosts({ folder }),
|
|
44
|
+
]).then(([projects, chatData, costData]) => {
|
|
43
45
|
const match = projects.find(p => p.folder === folder)
|
|
44
46
|
setProject(match || null)
|
|
45
47
|
setChats(chatData.chats || [])
|
|
48
|
+
setCosts(costData)
|
|
46
49
|
if (match) setEnabledEditors(new Set(Object.keys(match.editors)))
|
|
47
50
|
setLoading(false)
|
|
48
51
|
})
|
|
@@ -144,11 +147,12 @@ export default function ProjectDetail() {
|
|
|
144
147
|
<KpiCard label="sessions" value={displaySessions} sub={!allEnabled ? 'filtered' : ''} />
|
|
145
148
|
<KpiCard label="messages" value={formatNumber(project.totalMessages)} sub={`${avgMsgs} avg/session`} />
|
|
146
149
|
<KpiCard label="tool calls" value={formatNumber(project.totalToolCalls)} sub={<span className="flex items-center gap-0.5"><Wrench size={8} /> invocations</span>} />
|
|
147
|
-
<KpiCard label="tokens" value={formatNumber(totalTok)} sub={`${outputRatio}
|
|
150
|
+
<KpiCard label="tokens" value={formatNumber(totalTok)} sub={`${outputRatio}\u00d7 out/in`} />
|
|
148
151
|
{project.totalCacheRead > 0 && (
|
|
149
152
|
<KpiCard label="cache read" value={formatNumber(project.totalCacheRead)} sub={`write: ${formatNumber(project.totalCacheWrite)}`} />
|
|
150
153
|
)}
|
|
151
154
|
<KpiCard label="you wrote" value={formatNumber(project.totalUserChars)} sub={`AI: ${formatNumber(project.totalAssistantChars)}`} />
|
|
155
|
+
<KpiCard label="est. cost" value={costs && costs.totalCost > 0 ? formatCost(costs.totalCost) : '\u2014'} sub={costs && costs.byModel.length > 0 ? `${costs.byModel.length} model${costs.byModel.length !== 1 ? 's' : ''}` : undefined} />
|
|
152
156
|
</div>
|
|
153
157
|
|
|
154
158
|
{/* Charts row */}
|
|
@@ -256,6 +260,7 @@ export default function ProjectDetail() {
|
|
|
256
260
|
<th className="text-left py-2 px-3 font-medium">mode</th>
|
|
257
261
|
<th className="text-left py-2 px-3 font-medium">model</th>
|
|
258
262
|
<th className="text-left py-2 px-3 font-medium">context</th>
|
|
263
|
+
<th className="text-right py-2 px-3 font-medium">est. cost</th>
|
|
259
264
|
<th className="text-left py-2 px-3 font-medium">updated</th>
|
|
260
265
|
</tr>
|
|
261
266
|
</thead>
|
|
@@ -294,6 +299,9 @@ export default function ProjectDetail() {
|
|
|
294
299
|
<span style={{ color: 'var(--c-text3)' }}>{c.bubbleCount || 0} msgs</span>
|
|
295
300
|
)}
|
|
296
301
|
</td>
|
|
302
|
+
<td className="py-2 px-3 font-mono text-right" style={{ color: c.cost > 0 ? 'var(--c-text2)' : 'var(--c-text3)' }}>
|
|
303
|
+
{c.cost > 0 ? formatCost(c.cost) : ''}
|
|
304
|
+
</td>
|
|
297
305
|
<td className="py-2 px-3 whitespace-nowrap" style={{ color: 'var(--c-text3)' }}>{formatDate(c.lastUpdatedAt || c.createdAt)}</td>
|
|
298
306
|
</tr>
|
|
299
307
|
))}
|
|
@@ -3,8 +3,8 @@ import { Chart as ChartJS, ArcElement, Tooltip, Legend, CategoryScale, LinearSca
|
|
|
3
3
|
import { Doughnut, Bar } from 'react-chartjs-2'
|
|
4
4
|
import { Search, MessageSquare, Wrench, Cpu, FolderOpen, Calendar, ArrowRight } from 'lucide-react'
|
|
5
5
|
import { useNavigate } from 'react-router-dom'
|
|
6
|
-
import { fetchProjects } from '../lib/api'
|
|
7
|
-
import { editorColor, editorLabel, formatNumber, formatDate, dateRangeToApiParams } from '../lib/constants'
|
|
6
|
+
import { fetchProjects, fetchCosts } from '../lib/api'
|
|
7
|
+
import { editorColor, editorLabel, formatNumber, formatCost, formatDate, dateRangeToApiParams } from '../lib/constants'
|
|
8
8
|
import { useTheme } from '../lib/theme'
|
|
9
9
|
import KpiCard from '../components/KpiCard'
|
|
10
10
|
import EditorIcon from '../components/EditorIcon'
|
|
@@ -25,11 +25,16 @@ export default function Projects({ overview }) {
|
|
|
25
25
|
const [search, setSearch] = useState('')
|
|
26
26
|
const [editorFilter, setEditorFilter] = useState('')
|
|
27
27
|
const [dateRange, setDateRange] = useState(null)
|
|
28
|
+
const [costs, setCosts] = useState(null)
|
|
28
29
|
const navigate = useNavigate()
|
|
29
30
|
const editors = overview?.editors || []
|
|
30
31
|
|
|
31
32
|
useEffect(() => {
|
|
32
|
-
|
|
33
|
+
const dateParams = dateRangeToApiParams(dateRange)
|
|
34
|
+
Promise.all([
|
|
35
|
+
fetchProjects(dateParams),
|
|
36
|
+
fetchCosts(dateParams),
|
|
37
|
+
]).then(([p, c]) => { setProjects(p); setCosts(c) })
|
|
33
38
|
}, [dateRange])
|
|
34
39
|
|
|
35
40
|
if (!projects) return <div className="text-sm py-12 text-center" style={{ color: 'var(--c-text2)' }}>loading projects...</div>
|
|
@@ -64,6 +69,7 @@ export default function Projects({ overview }) {
|
|
|
64
69
|
<KpiCard label="sessions" value={formatNumber(totalSessions)} onClick={() => navigate('/sessions')} />
|
|
65
70
|
<KpiCard label="messages" value={formatNumber(totalMessages)} />
|
|
66
71
|
<KpiCard label="tokens" value={formatNumber(totalTokens)} />
|
|
72
|
+
<KpiCard label="est. cost" value={costs && costs.totalCost > 0 ? formatCost(costs.totalCost) : '\u2014'} />
|
|
67
73
|
</div>
|
|
68
74
|
|
|
69
75
|
{/* Charts row */}
|
|
@@ -4,7 +4,7 @@ import { Search, Filter, List, FolderOpen, ChevronDown, ChevronRight, X, AlertTr
|
|
|
4
4
|
import { Chart as ChartJS, ArcElement, CategoryScale, LinearScale, PointElement, LineElement, BarElement, Tooltip, Legend, Filler } from 'chart.js'
|
|
5
5
|
import { Line, Doughnut, Bar } from 'react-chartjs-2'
|
|
6
6
|
import { fetchChats } from '../lib/api'
|
|
7
|
-
import { editorColor, editorLabel, formatNumber, formatDate, dateRangeToApiParams } from '../lib/constants'
|
|
7
|
+
import { editorColor, editorLabel, formatNumber, formatCost, formatDate, dateRangeToApiParams } from '../lib/constants'
|
|
8
8
|
import { useTheme } from '../lib/theme'
|
|
9
9
|
import KpiCard from '../components/KpiCard'
|
|
10
10
|
import EditorIcon from '../components/EditorIcon'
|
|
@@ -285,6 +285,9 @@ export default function Sessions({ overview }) {
|
|
|
285
285
|
<span style={{ color: 'var(--c-text3)' }}>{c.bubbleCount || 0}</span>
|
|
286
286
|
)}
|
|
287
287
|
</td>
|
|
288
|
+
<td className="py-2 px-3 text-[12px] font-mono text-right" style={{ color: c.cost > 0 ? 'var(--c-text2)' : 'var(--c-text3)' }}>
|
|
289
|
+
{c.cost > 0 ? formatCost(c.cost) : ''}
|
|
290
|
+
</td>
|
|
288
291
|
<td className="py-2 px-3 text-[12px] whitespace-nowrap" style={{ color: 'var(--c-text3)' }}>
|
|
289
292
|
{formatDate(c.lastUpdatedAt || c.createdAt)}
|
|
290
293
|
</td>
|
|
@@ -475,6 +478,7 @@ export default function Sessions({ overview }) {
|
|
|
475
478
|
<th className="text-left py-2 px-3 font-medium">mode</th>
|
|
476
479
|
<th className="text-left py-2 px-3 font-medium">model</th>
|
|
477
480
|
<th className="text-left py-2 px-3 font-medium">context</th>
|
|
481
|
+
<th className="text-right py-2 px-3 font-medium">est. cost</th>
|
|
478
482
|
<th className="text-left py-2 px-3 font-medium">updated</th>
|
|
479
483
|
</tr>
|
|
480
484
|
</thead>
|