@tokcalc/mcp-server 0.1.3 → 0.2.0-alpha.1

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.
Files changed (193) hide show
  1. package/README.md +86 -406
  2. package/dist/http.js +23504 -0
  3. package/dist/index.js +21290 -0
  4. package/package.json +36 -92
  5. package/.zscripts/build.sh +0 -175
  6. package/.zscripts/database-runtime-build.sh +0 -33
  7. package/.zscripts/dev.pid +0 -1
  8. package/.zscripts/dev.sh +0 -154
  9. package/.zscripts/mini-services-build.sh +0 -78
  10. package/.zscripts/mini-services-install.sh +0 -65
  11. package/.zscripts/mini-services-start.sh +0 -123
  12. package/.zscripts/python-runtime-build.sh +0 -120
  13. package/.zscripts/start.sh +0 -145
  14. package/CAPACITY_STUDY.md +0 -283
  15. package/CODE_OF_CONDUCT.md +0 -55
  16. package/CONTRIBUTING.md +0 -177
  17. package/Caddyfile +0 -23
  18. package/LICENSE +0 -204
  19. package/bun.lock +0 -1965
  20. package/components.json +0 -21
  21. package/db/custom.db +0 -0
  22. package/download/README.md +0 -1
  23. package/download/tokcalc-dark-calculator.png +0 -0
  24. package/download/tokcalc-dark-default.png +0 -0
  25. package/download/tokcalc-demo.webm +0 -0
  26. package/download/tokcalc-github-link.png +0 -0
  27. package/download/tokcalc-hydration-fixed.png +0 -0
  28. package/download/tokcalc-issue-resolved.png +0 -0
  29. package/download/tokcalc-light-mode.png +0 -0
  30. package/download/tokcalc-light-reference.png +0 -0
  31. package/download/tokcalc-long-context-qwen.png +0 -0
  32. package/download/tokcalc-long-context.png +0 -0
  33. package/download/tokcalc-og-image-preview.png +0 -0
  34. package/download/tokcalc-phase2-3.png +0 -0
  35. package/download/tokcalc-plain-english.png +0 -0
  36. package/download/tokcalc-preview.png +0 -0
  37. package/download/tokcalc-share-bvb.png +0 -0
  38. package/download/tokcalc-share-feature.png +0 -0
  39. package/download/tokcalc-tab-build-vs-buy.png +0 -0
  40. package/download/tokcalc-tab-calculator.png +0 -0
  41. package/download/tokcalc-tab-reference.png +0 -0
  42. package/eslint.config.mjs +0 -50
  43. package/examples/websocket/frontend.tsx +0 -196
  44. package/examples/websocket/server.ts +0 -138
  45. package/mini-services/.gitkeep +0 -0
  46. package/mini-services/mcp-server/README.md +0 -86
  47. package/mini-services/mcp-server/bun.lock +0 -202
  48. package/mini-services/mcp-server/index.ts +0 -504
  49. package/mini-services/mcp-server/package.json +0 -40
  50. package/next.config.ts +0 -12
  51. package/postcss.config.mjs +0 -5
  52. package/prisma/schema.prisma +0 -32
  53. package/public/google6f58ca6be85fa903.html +0 -1
  54. package/public/logo.svg +0 -29
  55. package/public/manifest.json +0 -51
  56. package/public/og-icon-256.png +0 -0
  57. package/public/og.png +0 -0
  58. package/public/robots.txt +0 -25
  59. package/public/sitemap.xml +0 -23
  60. package/public/tokcalc-demo.gif +0 -0
  61. package/scripts/og-template.html +0 -120
  62. package/scripts/render-og.mjs +0 -43
  63. package/server.json +0 -21
  64. package/src/app/api/pricing/aws/route.ts +0 -186
  65. package/src/app/api/pricing/azure/route.ts +0 -168
  66. package/src/app/api/pricing/gcp/route.ts +0 -230
  67. package/src/app/api/pricing/vast-ai/route.ts +0 -164
  68. package/src/app/api/route.ts +0 -5
  69. package/src/app/compare/h100-vs-h200/layout.tsx +0 -30
  70. package/src/app/compare/h100-vs-h200/page.tsx +0 -328
  71. package/src/app/globals.css +0 -122
  72. package/src/app/layout.tsx +0 -276
  73. package/src/app/page.tsx +0 -2670
  74. package/src/components/azure-live-pricing.tsx +0 -185
  75. package/src/components/benchmark-import.tsx +0 -340
  76. package/src/components/confidence-badge.tsx +0 -116
  77. package/src/components/live-pricing-comparison.tsx +0 -241
  78. package/src/components/theme-provider.tsx +0 -11
  79. package/src/components/theme-toggle.tsx +0 -55
  80. package/src/components/ui/accordion.tsx +0 -66
  81. package/src/components/ui/alert-dialog.tsx +0 -157
  82. package/src/components/ui/alert.tsx +0 -66
  83. package/src/components/ui/aspect-ratio.tsx +0 -11
  84. package/src/components/ui/avatar.tsx +0 -53
  85. package/src/components/ui/badge.tsx +0 -46
  86. package/src/components/ui/breadcrumb.tsx +0 -109
  87. package/src/components/ui/button.tsx +0 -59
  88. package/src/components/ui/calendar.tsx +0 -213
  89. package/src/components/ui/card.tsx +0 -92
  90. package/src/components/ui/carousel.tsx +0 -241
  91. package/src/components/ui/chart.tsx +0 -353
  92. package/src/components/ui/checkbox.tsx +0 -32
  93. package/src/components/ui/collapsible.tsx +0 -33
  94. package/src/components/ui/command.tsx +0 -184
  95. package/src/components/ui/context-menu.tsx +0 -252
  96. package/src/components/ui/dialog.tsx +0 -143
  97. package/src/components/ui/drawer.tsx +0 -135
  98. package/src/components/ui/dropdown-menu.tsx +0 -257
  99. package/src/components/ui/form.tsx +0 -167
  100. package/src/components/ui/hover-card.tsx +0 -44
  101. package/src/components/ui/input-otp.tsx +0 -77
  102. package/src/components/ui/input.tsx +0 -21
  103. package/src/components/ui/label.tsx +0 -24
  104. package/src/components/ui/menubar.tsx +0 -276
  105. package/src/components/ui/navigation-menu.tsx +0 -168
  106. package/src/components/ui/pagination.tsx +0 -127
  107. package/src/components/ui/popover.tsx +0 -48
  108. package/src/components/ui/progress.tsx +0 -31
  109. package/src/components/ui/radio-group.tsx +0 -45
  110. package/src/components/ui/resizable.tsx +0 -56
  111. package/src/components/ui/scroll-area.tsx +0 -58
  112. package/src/components/ui/select.tsx +0 -185
  113. package/src/components/ui/separator.tsx +0 -28
  114. package/src/components/ui/sheet.tsx +0 -139
  115. package/src/components/ui/sidebar.tsx +0 -726
  116. package/src/components/ui/skeleton.tsx +0 -13
  117. package/src/components/ui/slider.tsx +0 -63
  118. package/src/components/ui/sonner.tsx +0 -25
  119. package/src/components/ui/switch.tsx +0 -31
  120. package/src/components/ui/table.tsx +0 -116
  121. package/src/components/ui/tabs.tsx +0 -66
  122. package/src/components/ui/textarea.tsx +0 -18
  123. package/src/components/ui/toast.tsx +0 -129
  124. package/src/components/ui/toaster.tsx +0 -35
  125. package/src/components/ui/toggle-group.tsx +0 -73
  126. package/src/components/ui/toggle.tsx +0 -47
  127. package/src/components/ui/tooltip.tsx +0 -61
  128. package/src/components/vast-ai-live-pricing.tsx +0 -176
  129. package/src/hooks/use-mobile.ts +0 -19
  130. package/src/hooks/use-toast.ts +0 -194
  131. package/src/lib/benchmark-parser-sglang.ts +0 -150
  132. package/src/lib/benchmark-parser-tokcalc.ts +0 -247
  133. package/src/lib/benchmark-parser-trtllm.ts +0 -152
  134. package/src/lib/benchmark-parser-vllm.ts +0 -198
  135. package/src/lib/benchmark-schema.ts +0 -263
  136. package/src/lib/db.ts +0 -13
  137. package/src/lib/engine-presets.ts +0 -183
  138. package/src/lib/price-schema.ts +0 -141
  139. package/src/lib/token-calc.ts +0 -808
  140. package/src/lib/track.ts +0 -31
  141. package/src/lib/url-state.ts +0 -256
  142. package/src/lib/utils.ts +0 -6
  143. package/tailwind.config.ts +0 -64
  144. package/tests/database-runtime-build.sh +0 -75
  145. package/tests/python-runtime-build.sh +0 -64
  146. package/tests/python-runtime-container.sh +0 -31
  147. package/tool-results/bash_1789888171144_2c5381860539.txt +0 -161
  148. package/tool-results/bash_1789888175925_49c53ba3c61b.txt +0 -191
  149. package/tool-results/bash_1789888181202_49c53ba3c61b.txt +0 -191
  150. package/tool-results/bash_1789888195219_4a86a5c91411.txt +0 -200
  151. package/tool-results/bash_1789888203128_6cca13c71b47.txt +0 -199
  152. package/tool-results/bash_1789929256963_2a52aff0d0a8.txt +0 -160
  153. package/tool-results/read_1789888151021_69f58eec6a5b.txt +0 -653
  154. package/tool-results/read_1789888153837_1d3a8bfc2a94.txt +0 -653
  155. package/tool-results/read_1789888163087_ccc406d47505.txt +0 -122
  156. package/tool-results/read_1789888167347_67d1d7c9830a.txt +0 -122
  157. package/tool-results/read_1789929252529_d90e8f383a25.txt +0 -285
  158. package/tsconfig.json +0 -42
  159. package/upload/Pasted Content_1789887800864.txt +0 -652
  160. package/upload/Pasted Content_1789887909561.txt +0 -652
  161. package/upload/Pasted Content_1789887918428.txt +0 -652
  162. package/upload/Pasted Content_1789887959420.txt +0 -652
  163. package/upload/Pasted Content_1789888020485.txt +0 -652
  164. package/upload/Pasted Content_1789888058079.txt +0 -652
  165. package/upload/Pasted Content_1789888885033.txt +0 -686
  166. package/upload/Pasted Content_1789928912741.txt +0 -285
  167. package/upload/Pasted Content_1789928938402.txt +0 -285
  168. package/upload/Pasted Content_1789929160389.txt +0 -285
  169. package/upload/Pasted Content_1789929176660.txt +0 -285
  170. package/upload/issue_vision.json +0 -28
  171. package/upload/pasted_image_1789883175209.png +0 -0
  172. package/upload/pasted_image_1789899056690.png +0 -0
  173. package/upload/pasted_image_1789900371483.png +0 -0
  174. package/upload/pasted_image_1789900472823.png +0 -0
  175. package/upload/pasted_image_1789900490374.png +0 -0
  176. package/upload/pasted_image_1789900585552.png +0 -0
  177. package/upload/pasted_image_1789900606519.png +0 -0
  178. package/upload/pasted_image_1789901598705.png +0 -0
  179. package/upload/pasted_image_1789901613545.png +0 -0
  180. package/upload/pasted_image_1789978382674.png +0 -0
  181. package/upload/pasted_image_1789978392749.png +0 -0
  182. package/upload/pasted_image_1789978474879.png +0 -0
  183. package/upload/pasted_image_1789978523652.png +0 -0
  184. package/upload/pasted_image_1789984219089.png +0 -0
  185. package/upload/pasted_image_1789984491896.png +0 -0
  186. package/upload/pasted_image_1789985017950.png +0 -0
  187. package/upload/pasted_image_1789985036765.png +0 -0
  188. package/upload/pasted_image_1789985049848.png +0 -0
  189. package/upload/pasted_image_1790002427833.png +0 -0
  190. package/upload/pasted_image_1790002659944.png +0 -0
  191. package/upload/pasted_image_1790037038476.png +0 -0
  192. package/upload/screenshot_analysis.json +0 -28
  193. package/upload/vision_output.json +0 -28
@@ -1,176 +0,0 @@
1
- "use client";
2
-
3
- import { useEffect, useState } from "react";
4
- import {
5
- Card,
6
- CardContent,
7
- CardDescription,
8
- CardHeader,
9
- CardTitle,
10
- } from "@/components/ui/card";
11
- import { Button } from "@/components/ui/button";
12
- import { Badge } from "@/components/ui/badge";
13
- import { RefreshCw, Zap, AlertTriangle, TrendingDown } from "lucide-react";
14
- import { track } from "@/lib/track";
15
-
16
- interface VastAiOffer {
17
- gpu: string;
18
- gpuCount: number;
19
- vramGb: number;
20
- pricePerGpuHour: number;
21
- totalPriceHour: number;
22
- reliability: number;
23
- region: string;
24
- bundleId: number;
25
- }
26
-
27
- interface VastAiApiResponse {
28
- source: string;
29
- cached: boolean;
30
- retrievedAt?: string;
31
- count?: number;
32
- offers?: VastAiOffer[];
33
- note?: string;
34
- error?: string;
35
- }
36
-
37
- export function VastAiLivePricing() {
38
- const [data, setData] = useState<VastAiApiResponse | null>(null);
39
- const [loading, setLoading] = useState(false);
40
- const [error, setError] = useState<string | null>(null);
41
-
42
- const fetchPrices = async () => {
43
- setLoading(true);
44
- setError(null);
45
- try {
46
- const res = await fetch("/api/pricing/vast-ai");
47
- if (!res.ok) {
48
- const errData = await res.json().catch(() => ({}));
49
- throw new Error(errData.error || `HTTP ${res.status}`);
50
- }
51
- const json = (await res.json()) as VastAiApiResponse;
52
- setData(json);
53
- track("fetched_live_pricing", { provider: "vast_ai", count: json.count });
54
- } catch (e) {
55
- setError(e instanceof Error ? e.message : "Failed to fetch Vast.ai pricing");
56
- } finally {
57
- setLoading(false);
58
- }
59
- };
60
-
61
- useEffect(() => {
62
- fetchPrices();
63
- }, []);
64
-
65
- const asOfLabel = (() => {
66
- if (!data?.retrievedAt) return null;
67
- const ageMs = Date.now() - new Date(data.retrievedAt).getTime();
68
- if (ageMs < 60000) return "just now";
69
- if (ageMs < 3600000) return `${Math.floor(ageMs / 60000)}m ago`;
70
- return `${Math.floor(ageMs / 3600000)}h ago`;
71
- })();
72
-
73
- const offers = data?.offers || [];
74
-
75
- return (
76
- <Card className="border-amber-500/30 shadow-sm">
77
- <CardHeader className="pb-3">
78
- <div className="flex items-center justify-between">
79
- <div>
80
- <CardTitle className="text-sm flex items-center gap-2">
81
- <TrendingDown className="size-4 text-amber-500" />
82
- Vast.ai marketplace — spot prices
83
- <Badge variant="outline" className="text-[9px] gap-1 ml-1">
84
- <span className="size-1.5 rounded-full bg-amber-500 animate-pulse" />
85
- LIVE
86
- </Badge>
87
- </CardTitle>
88
- <CardDescription className="text-xs mt-1">
89
- Cheapest available GPU offers on Vast.ai marketplace right now.
90
- {asOfLabel && ` Last updated ${asOfLabel}.`}
91
- {" "}Spot prices change rapidly — individual offers may be gone by the time you rent.
92
- </CardDescription>
93
- </div>
94
- <Button
95
- variant="ghost"
96
- size="sm"
97
- onClick={fetchPrices}
98
- disabled={loading}
99
- className="gap-1.5 h-8"
100
- >
101
- <RefreshCw className={`size-3.5 ${loading ? "animate-spin" : ""}`} />
102
- <span className="text-xs">Refresh</span>
103
- </Button>
104
- </div>
105
- </CardHeader>
106
- <CardContent>
107
- {loading && !data && (
108
- <div className="flex items-center justify-center py-8 text-xs text-muted-foreground">
109
- <RefreshCw className="size-4 animate-spin mr-2" />
110
- Fetching Vast.ai marketplace offers...
111
- </div>
112
- )}
113
-
114
- {error && (
115
- <div className="flex items-start gap-2 p-3 rounded-md border border-amber-500/30 bg-amber-500/5 text-xs">
116
- <AlertTriangle className="size-3.5 text-amber-500 shrink-0 mt-0.5" />
117
- <div>
118
- <p className="font-medium text-amber-600 dark:text-amber-400">
119
- Couldn&apos;t fetch marketplace prices
120
- </p>
121
- <p className="text-muted-foreground mt-0.5">{error}</p>
122
- </div>
123
- </div>
124
- )}
125
-
126
- {offers.length > 0 && (
127
- <div className="overflow-x-auto">
128
- <table className="w-full text-xs">
129
- <thead className="bg-muted/40 text-[10px] uppercase">
130
- <tr>
131
- <th className="text-left px-3 py-1.5">GPU</th>
132
- <th className="text-right px-3 py-1.5">$/GPU-hr</th>
133
- <th className="text-right px-3 py-1.5">GPU count</th>
134
- <th className="text-right px-3 py-1.5">Total $/hr</th>
135
- <th className="text-right px-3 py-1.5">VRAM</th>
136
- <th className="text-right px-3 py-1.5">Reliability</th>
137
- <th className="text-left px-3 py-1.5">Region</th>
138
- </tr>
139
- </thead>
140
- <tbody>
141
- {offers.slice(0, 15).map((o, i) => (
142
- <tr key={i} className="border-t border-border/40 hover:bg-muted/20">
143
- <td className="px-3 py-1.5 font-medium">{o.gpu}</td>
144
- <td className="px-3 py-1.5 text-right font-mono text-amber-500 font-semibold">
145
- ${o.pricePerGpuHour}/hr
146
- </td>
147
- <td className="px-3 py-1.5 text-right font-mono">{o.gpuCount}×</td>
148
- <td className="px-3 py-1.5 text-right font-mono text-muted-foreground">${o.totalPriceHour}</td>
149
- <td className="px-3 py-1.5 text-right font-mono text-muted-foreground">{o.vramGb}GB</td>
150
- <td className="px-3 py-1.5 text-right font-mono">
151
- <span className={o.reliability > 0.9 ? "text-emerald-500" : o.reliability > 0.7 ? "text-amber-500" : "text-red-500"}>
152
- {(o.reliability * 100).toFixed(0)}%
153
- </span>
154
- </td>
155
- <td className="px-3 py-1.5 text-muted-foreground text-[10px]">{o.region || "—"}</td>
156
- </tr>
157
- ))}
158
- </tbody>
159
- </table>
160
- <p className="text-[10px] text-muted-foreground mt-2 leading-relaxed">
161
- Spot-market prices from Vast.ai marketplace.
162
- Reliability score (0-100%) indicates host trustworthiness.
163
- Total $/hr is the full bundle price (all GPUs + CPU + RAM).
164
- Source: <a
165
- href="https://vast.ai/pricing"
166
- target="_blank"
167
- rel="noopener noreferrer"
168
- className="text-amber-500 hover:underline"
169
- >Vast.ai marketplace API ↗</a>
170
- </p>
171
- </div>
172
- )}
173
- </CardContent>
174
- </Card>
175
- );
176
- }
@@ -1,19 +0,0 @@
1
- import * as React from "react"
2
-
3
- const MOBILE_BREAKPOINT = 768
4
-
5
- export function useIsMobile() {
6
- const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
7
-
8
- React.useEffect(() => {
9
- const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
10
- const onChange = () => {
11
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
12
- }
13
- mql.addEventListener("change", onChange)
14
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
15
- return () => mql.removeEventListener("change", onChange)
16
- }, [])
17
-
18
- return !!isMobile
19
- }
@@ -1,194 +0,0 @@
1
- "use client"
2
-
3
- // Inspired by react-hot-toast library
4
- import * as React from "react"
5
-
6
- import type {
7
- ToastActionElement,
8
- ToastProps,
9
- } from "@/components/ui/toast"
10
-
11
- const TOAST_LIMIT = 1
12
- const TOAST_REMOVE_DELAY = 1000000
13
-
14
- type ToasterToast = ToastProps & {
15
- id: string
16
- title?: React.ReactNode
17
- description?: React.ReactNode
18
- action?: ToastActionElement
19
- }
20
-
21
- const actionTypes = {
22
- ADD_TOAST: "ADD_TOAST",
23
- UPDATE_TOAST: "UPDATE_TOAST",
24
- DISMISS_TOAST: "DISMISS_TOAST",
25
- REMOVE_TOAST: "REMOVE_TOAST",
26
- } as const
27
-
28
- let count = 0
29
-
30
- function genId() {
31
- count = (count + 1) % Number.MAX_SAFE_INTEGER
32
- return count.toString()
33
- }
34
-
35
- type ActionType = typeof actionTypes
36
-
37
- type Action =
38
- | {
39
- type: ActionType["ADD_TOAST"]
40
- toast: ToasterToast
41
- }
42
- | {
43
- type: ActionType["UPDATE_TOAST"]
44
- toast: Partial<ToasterToast>
45
- }
46
- | {
47
- type: ActionType["DISMISS_TOAST"]
48
- toastId?: ToasterToast["id"]
49
- }
50
- | {
51
- type: ActionType["REMOVE_TOAST"]
52
- toastId?: ToasterToast["id"]
53
- }
54
-
55
- interface State {
56
- toasts: ToasterToast[]
57
- }
58
-
59
- const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>()
60
-
61
- const addToRemoveQueue = (toastId: string) => {
62
- if (toastTimeouts.has(toastId)) {
63
- return
64
- }
65
-
66
- const timeout = setTimeout(() => {
67
- toastTimeouts.delete(toastId)
68
- dispatch({
69
- type: "REMOVE_TOAST",
70
- toastId: toastId,
71
- })
72
- }, TOAST_REMOVE_DELAY)
73
-
74
- toastTimeouts.set(toastId, timeout)
75
- }
76
-
77
- export const reducer = (state: State, action: Action): State => {
78
- switch (action.type) {
79
- case "ADD_TOAST":
80
- return {
81
- ...state,
82
- toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
83
- }
84
-
85
- case "UPDATE_TOAST":
86
- return {
87
- ...state,
88
- toasts: state.toasts.map((t) =>
89
- t.id === action.toast.id ? { ...t, ...action.toast } : t
90
- ),
91
- }
92
-
93
- case "DISMISS_TOAST": {
94
- const { toastId } = action
95
-
96
- // ! Side effects ! - This could be extracted into a dismissToast() action,
97
- // but I'll keep it here for simplicity
98
- if (toastId) {
99
- addToRemoveQueue(toastId)
100
- } else {
101
- state.toasts.forEach((toast) => {
102
- addToRemoveQueue(toast.id)
103
- })
104
- }
105
-
106
- return {
107
- ...state,
108
- toasts: state.toasts.map((t) =>
109
- t.id === toastId || toastId === undefined
110
- ? {
111
- ...t,
112
- open: false,
113
- }
114
- : t
115
- ),
116
- }
117
- }
118
- case "REMOVE_TOAST":
119
- if (action.toastId === undefined) {
120
- return {
121
- ...state,
122
- toasts: [],
123
- }
124
- }
125
- return {
126
- ...state,
127
- toasts: state.toasts.filter((t) => t.id !== action.toastId),
128
- }
129
- }
130
- }
131
-
132
- const listeners: Array<(state: State) => void> = []
133
-
134
- let memoryState: State = { toasts: [] }
135
-
136
- function dispatch(action: Action) {
137
- memoryState = reducer(memoryState, action)
138
- listeners.forEach((listener) => {
139
- listener(memoryState)
140
- })
141
- }
142
-
143
- type Toast = Omit<ToasterToast, "id">
144
-
145
- function toast({ ...props }: Toast) {
146
- const id = genId()
147
-
148
- const update = (props: ToasterToast) =>
149
- dispatch({
150
- type: "UPDATE_TOAST",
151
- toast: { ...props, id },
152
- })
153
- const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })
154
-
155
- dispatch({
156
- type: "ADD_TOAST",
157
- toast: {
158
- ...props,
159
- id,
160
- open: true,
161
- onOpenChange: (open) => {
162
- if (!open) dismiss()
163
- },
164
- },
165
- })
166
-
167
- return {
168
- id: id,
169
- dismiss,
170
- update,
171
- }
172
- }
173
-
174
- function useToast() {
175
- const [state, setState] = React.useState<State>(memoryState)
176
-
177
- React.useEffect(() => {
178
- listeners.push(setState)
179
- return () => {
180
- const index = listeners.indexOf(setState)
181
- if (index > -1) {
182
- listeners.splice(index, 1)
183
- }
184
- }
185
- }, [state])
186
-
187
- return {
188
- ...state,
189
- toast,
190
- dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
191
- }
192
- }
193
-
194
- export { useToast, toast }
@@ -1,150 +0,0 @@
1
- /**
2
- * SGLang benchmark parser.
3
- *
4
- * SGLang's benchmark scripts produce JSON/log output with fields like:
5
- * - total_throughput or output_throughput (tokens/s)
6
- * - mean_ttft or ttft_avg (ms)
7
- * - mean_itl or itl_avg (ms)
8
- * - total_input_tokens, total_output_tokens
9
- * - num_requests
10
- * - concurrency
11
- * - model_id
12
- *
13
- * SGLang output format varies by benchmark script version. This parser
14
- * handles common aliases across SGLang v0.3.x → v0.5.x.
15
- */
16
-
17
- import type {
18
- BenchmarkParser,
19
- BenchmarkRecord,
20
- ConfidenceTier,
21
- } from "./benchmark-schema";
22
- import { generateBenchmarkId } from "./benchmark-schema";
23
-
24
- export const sglangParser: BenchmarkParser = {
25
- name: "sglang-json",
26
- version: "v1",
27
- formatLabel: "SGLang benchmark JSON",
28
-
29
- detect(rawText: string): boolean {
30
- try {
31
- const data = JSON.parse(rawText);
32
- return !!(
33
- data &&
34
- (data.total_throughput ||
35
- data.output_throughput ||
36
- data.mean_ttft ||
37
- data.ttft_avg ||
38
- data.mean_itl ||
39
- data.itl_avg ||
40
- data.num_requests ||
41
- data.total_input_tokens)
42
- );
43
- } catch {
44
- // Also check for SGLang log format (not JSON)
45
- return rawText.includes("sglang") && rawText.includes("throughput");
46
- }
47
- },
48
-
49
- parse(rawText: string): BenchmarkRecord | null {
50
- try {
51
- // Try JSON first
52
- const data = JSON.parse(rawText);
53
- if (!data) return null;
54
-
55
- const modelId = data.model_id || data.model || "unknown";
56
- const modelDisplayName = modelId.split("/").pop() || modelId;
57
-
58
- const outputThroughput =
59
- data.output_throughput ?? data.total_throughput ?? data.throughput ?? 0;
60
- const meanTtft = data.mean_ttft ?? data.ttft_avg ?? data.ttft_mean;
61
- const p99Ttft = data.p99_ttft ?? data.ttft_p99;
62
- const meanItl = data.mean_itl ?? data.itl_avg ?? data.itl_mean;
63
- const p99Itl = data.p99_itl ?? data.itl_p99;
64
-
65
- const numRequests = data.num_requests ?? data.completed ?? 0;
66
- const inputLen = Number(data.input_len ?? data.mean_input_len ?? 0);
67
- const outputLen = Number(data.output_len ?? data.mean_output_len ?? 0);
68
- const concurrency = data.concurrency ?? data.num_procs ?? 1;
69
-
70
- const confidenceTier: ConfidenceTier =
71
- modelId !== "unknown" && outputThroughput > 0 && numRequests > 0
72
- ? "community_reproducible"
73
- : "community_unverified";
74
-
75
- return {
76
- benchmark_id: generateBenchmarkId(),
77
- source_name: "sglang",
78
- source_url: data.source_url || "https://github.com/sgl-project/sglang",
79
- source_license: "Apache-2.0",
80
- ingestion_method: "uploaded_raw_artifact",
81
- retrieved_at: new Date().toISOString(),
82
- parser_name: "sglang-json",
83
- parser_version: "v1",
84
- confidence_tier: confidenceTier,
85
- verification_status: "schema_valid",
86
-
87
- model_id: modelId,
88
- model_display_name: modelDisplayName,
89
- model_revision: data.model_revision || "unspecified",
90
- architecture: data.architecture,
91
- parameter_count_b: data.parameter_count_b,
92
- context_window_tokens: data.max_model_len,
93
- quantization_format: data.quantization || data.dtype || "unspecified",
94
- weight_dtype: data.dtype,
95
- kv_cache_dtype: data.kv_cache_dtype || "float16",
96
-
97
- accelerator_vendor: "NVIDIA",
98
- accelerator_model: data.gpu_model || "unspecified",
99
- gpu_count: data.tensor_parallel_size || data.gpu_count || 1,
100
- memory_per_gpu_gb: data.gpu_memory || 0,
101
- driver_version: data.driver_version,
102
- cuda_rocm_metal_version: data.cuda_version,
103
-
104
- serving_engine: "SGLang",
105
- engine_version: data.sglang_version || "unspecified",
106
- engine_command: data.command,
107
- engine_config: {
108
- tensor_parallel_size: data.tensor_parallel_size,
109
- max_model_len: data.max_model_len,
110
- max_num_seqs: data.max_num_seqs,
111
- prefix_cache_enabled: data.enable_prefix_caching ?? data.radix_cache,
112
- chunked_prefill_enabled: data.enable_chunked_prefill,
113
- attention_backend: data.attention_backend,
114
- },
115
-
116
- workload_type: data.workload_type || "online_poisson",
117
- dataset_name: data.dataset_name || data.dataset,
118
- request_count: numRequests,
119
- concurrency,
120
- input_tokens_mean: inputLen,
121
- output_tokens_mean: outputLen,
122
- streaming_enabled: data.streaming ?? true,
123
-
124
- successful_requests: numRequests,
125
- failed_requests: data.failed ?? 0,
126
- output_token_throughput_tps: outputThroughput,
127
- total_token_throughput_tps: data.total_token_throughput,
128
- request_throughput_rps: data.request_throughput,
129
- ttft_mean_ms: meanTtft,
130
- ttft_p50_ms: data.p50_ttft ?? data.median_ttft,
131
- ttft_p95_ms: data.p95_ttft,
132
- ttft_p99_ms: p99Ttft,
133
- itl_mean_ms: meanItl,
134
- itl_p50_ms: data.p50_itl ?? data.median_itl,
135
- itl_p95_ms: data.p95_itl,
136
- itl_p99_ms: p99Itl,
137
-
138
- gpu_memory_peak_gb: data.peak_gpu_memory,
139
-
140
- metric_definition_version: "sglang-v1",
141
- citation_text: `SGLang benchmark: ${outputThroughput.toFixed(2)} tok/s, TTFT mean ${meanTtft?.toFixed(1) || "?"} ms, ${numRequests} requests`,
142
- attribution_required: true,
143
- commercial_redistribution_allowed: "yes",
144
- };
145
- } catch {
146
- // Not JSON — try log format (future: parse SGLang text logs)
147
- return null;
148
- }
149
- },
150
- };