llmtap 0.1.6 → 0.1.8

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 (50) hide show
  1. package/README.md +29 -0
  2. package/dist/dashboard/assets/CommandBar-CBRbPbgc.js +1 -0
  3. package/dist/dashboard/assets/Costs-B-TMvDlI.js +1 -0
  4. package/dist/dashboard/assets/Dashboard-CFNAMjdc.js +1 -0
  5. package/dist/dashboard/assets/DataTable-p1PD-dJj.js +1 -0
  6. package/dist/dashboard/assets/EmptyState-xDl-M9Rz.js +1 -0
  7. package/dist/dashboard/assets/GettingStartedPanel-Cn46fQ1w.js +18 -0
  8. package/dist/dashboard/assets/Models-BpMhGVp5.js +1 -0
  9. package/dist/dashboard/assets/ProviderBadge-Cs31007s.js +1 -0
  10. package/dist/dashboard/assets/Sessions-CiKyTRlP.js +3 -0
  11. package/dist/dashboard/assets/Settings-7wRfCPnB.js +6 -0
  12. package/dist/dashboard/assets/TraceDetail-CKDDbbEV.js +17 -0
  13. package/dist/dashboard/assets/Traces-BYWwPP14.js +1 -0
  14. package/dist/dashboard/assets/accordion-CC_sxDZ8.js +1 -0
  15. package/dist/dashboard/assets/content-DZmxO8bn.js +2 -0
  16. package/dist/dashboard/assets/format-zoXqpaOb.js +1 -0
  17. package/dist/dashboard/assets/icons-BOLUIAKd.js +1 -0
  18. package/dist/dashboard/assets/index-CtlcBMi-.css +1 -0
  19. package/dist/dashboard/assets/index-DG2eF3M2.js +14 -0
  20. package/dist/dashboard/assets/motion-CSeNjKbZ.js +17 -0
  21. package/dist/dashboard/assets/{number-ticker-C1hiu1bi.js → number-ticker-CjofSQ3s.js} +1 -1
  22. package/dist/dashboard/assets/provider-colors-CTiHNYHs.js +1 -0
  23. package/dist/dashboard/assets/query-DVWnIZNd.js +4 -0
  24. package/dist/dashboard/assets/select-BJEJvQo4.js +1 -0
  25. package/dist/dashboard/assets/statistics-with-status-grid-tcb9SpIY.js +1 -0
  26. package/dist/dashboard/assets/ui-BFiKdTjl.js +51 -0
  27. package/dist/dashboard/index.html +6 -6
  28. package/dist/index.js +332 -107
  29. package/dist/index.js.map +1 -1
  30. package/package.json +6 -4
  31. package/dist/dashboard/assets/Costs-DcNWZXjX.js +0 -1
  32. package/dist/dashboard/assets/Dashboard-Dkx38fyX.js +0 -9
  33. package/dist/dashboard/assets/DataTable-CBsuKoTx.js +0 -1
  34. package/dist/dashboard/assets/Models-CESHenJX.js +0 -1
  35. package/dist/dashboard/assets/Sessions-BcRE0OFh.js +0 -3
  36. package/dist/dashboard/assets/Settings-BUDP0ZDT.js +0 -12
  37. package/dist/dashboard/assets/StatusDot-BAf4TSfE.js +0 -1
  38. package/dist/dashboard/assets/TraceDetail-ByibqI-g.js +0 -17
  39. package/dist/dashboard/assets/Traces-D9kJG7O9.js +0 -1
  40. package/dist/dashboard/assets/charts-BXAtT8sy.js +0 -89
  41. package/dist/dashboard/assets/constants-OlSc-7iA.js +0 -1
  42. package/dist/dashboard/assets/content-BRoZVvRJ.js +0 -2
  43. package/dist/dashboard/assets/format-CgXokIEM.js +0 -1
  44. package/dist/dashboard/assets/icons-DhpK1vUv.js +0 -1
  45. package/dist/dashboard/assets/index-C7GMIuGj.css +0 -1
  46. package/dist/dashboard/assets/index-jVcSWGwX.js +0 -58
  47. package/dist/dashboard/assets/motion-Bw6xJyTE.js +0 -9
  48. package/dist/dashboard/assets/provider-colors-DcHYMgVv.js +0 -1
  49. package/dist/dashboard/assets/query-BSZkMKN4.js +0 -4
  50. package/dist/dashboard/assets/select-CbYE6Q0M.js +0 -1
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/start.ts","../src/commands/reset.ts","../src/commands/export.ts","../src/commands/status.ts","../src/commands/tail.ts","../src/commands/doctor.ts","../src/commands/stats.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { startCommand } from \"./commands/start.js\";\nimport { resetCommand } from \"./commands/reset.js\";\nimport { exportCommand } from \"./commands/export.js\";\nimport { statusCommand } from \"./commands/status.js\";\nimport { tailCommand } from \"./commands/tail.js\";\nimport { doctorCommand } from \"./commands/doctor.js\";\nimport { statsCommand } from \"./commands/stats.js\";\nimport { VERSION } from \"@llmtap/shared\";\n\nconst program = new Command();\n\nprogram\n .name(\"llmtap\")\n .description(\"DevTools for AI Agents - See every LLM call, trace agent workflows, track costs\")\n .version(VERSION);\n\nprogram\n .command(\"start\", { isDefault: true })\n .description(\"Start the LLMTap collector and dashboard\")\n .option(\"-p, --port <port>\", \"Port number\", \"4781\")\n .option(\"-H, --host <host>\", \"Host to bind to (use 0.0.0.0 to expose to network)\", \"127.0.0.1\")\n .option(\"-q, --quiet\", \"Suppress server logs\")\n .option(\"--demo\", \"Seed demo data on startup\")\n .option(\"--no-open\", \"Don't open browser automatically\")\n .option(\"-r, --retention <days>\", \"Auto-delete data older than N days (0 = keep forever)\")\n .action(startCommand);\n\nprogram\n .command(\"status\")\n .description(\"Show collector status, database info, and span count\")\n .action(statusCommand);\n\nprogram\n .command(\"reset\")\n .description(\"Clear all stored data\")\n .action(resetCommand);\n\nprogram\n .command(\"export\")\n .description(\"Export traces as JSON, CSV, or OTLP\")\n .option(\"-o, --output <path>\", \"Output file path\", \"llmtap-export.json\")\n .option(\"-f, --format <format>\", \"Output format (json, csv, or otlp)\", \"json\")\n .option(\"-l, --limit <count>\", \"Number of traces/spans to export\", \"100\")\n .option(\"-e, --endpoint <url>\", \"OTLP endpoint to forward spans to (e.g. http://localhost:4318/v1/traces)\")\n .option(\"-s, --service <name>\", \"service.name for OTLP export\", \"llmtap\")\n .action(exportCommand);\n\nprogram\n .command(\"tail\")\n .description(\"Stream traces to terminal in real-time\")\n .option(\"-f, --format <format>\", \"Output format (pretty or json)\", \"pretty\")\n .action(tailCommand);\n\nprogram\n .command(\"doctor\")\n .description(\"Diagnose common setup issues\")\n .action(doctorCommand);\n\nprogram\n .command(\"stats\")\n .description(\"Show quick terminal stats (cost, models, errors)\")\n .option(\"-p, --period <hours>\", \"Time period in hours\", \"24\")\n .option(\"--host <url>\", \"Collector URL\", \"http://localhost:4781\")\n .action(statsCommand);\n\nprogram.parse();\n","import path from \"node:path\";\nimport fs from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport chalk from \"chalk\";\nimport open from \"open\";\nimport { startServer, getOtlpEndpoint } from \"@llmtap/collector\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\ninterface StartOptions {\n port: string;\n host: string;\n quiet?: boolean;\n open?: boolean;\n demo?: boolean;\n retention?: string;\n}\n\nexport async function startCommand(options: StartOptions): Promise<void> {\n const port = parseInt(options.port, 10);\n const retentionDays = options.retention\n ? parseInt(options.retention, 10)\n : undefined;\n\n // Resolve dashboard dist path\n // 1. Bundled inside CLI dist (for npm publish): dist/dashboard/\n // 2. Monorepo sibling (for local dev): ../../dashboard/dist/\n const bundledPath = path.resolve(__dirname, \"dashboard\");\n const monorepoPath = path.resolve(__dirname, \"..\", \"..\", \"dashboard\", \"dist\");\n const dashboardPath = fs.existsSync(bundledPath) ? bundledPath : monorepoPath;\n\n console.log(\"\");\n console.log(chalk.bold.hex(\"#6366f1\")(\" LLMTap\") + chalk.gray(\" - DevTools for AI Agents\"));\n console.log(\"\");\n\n try {\n const host = options.host;\n\n if (host === \"0.0.0.0\") {\n console.log(chalk.yellow(\" ⚠ Binding to 0.0.0.0 — the collector will be accessible from your network\"));\n console.log(\"\");\n }\n\n const address = await startServer({\n port,\n host,\n dashboardPath,\n quiet: options.quiet,\n demo: options.demo,\n retentionDays,\n });\n\n const url = `http://${host === \"0.0.0.0\" ? \"localhost\" : host}:${port}`;\n\n console.log(chalk.green(\" Ready!\"));\n console.log(\"\");\n console.log(` ${chalk.gray(\"Dashboard:\")} ${chalk.cyan(url)}`);\n console.log(` ${chalk.gray(\"API:\")} ${chalk.cyan(`${url}/v1`)}`);\n console.log(` ${chalk.gray(\"Health:\")} ${chalk.cyan(`${url}/health`)}`);\n if (retentionDays && retentionDays > 0) {\n console.log(` ${chalk.gray(\"Retention:\")} ${chalk.yellow(`${retentionDays} days`)}`);\n }\n const otlpTarget = getOtlpEndpoint();\n if (otlpTarget) {\n console.log(` ${chalk.gray(\"OTLP:\")} ${chalk.cyan(otlpTarget)} ${chalk.green(\"(auto-forwarding)\")}`);\n }\n console.log(\"\");\n console.log(chalk.gray(\" Press Ctrl+C to stop\"));\n console.log(\"\");\n\n // Open browser\n if (options.open !== false) {\n try {\n await open(url);\n } catch {\n // Ignore if browser can't be opened\n }\n }\n } catch (err: unknown) {\n const error = err as Error;\n if (error.message?.includes(\"EADDRINUSE\")) {\n console.error(chalk.red(` Port ${port} is already in use.`));\n console.error(chalk.gray(` Try: npx llmtap --port ${port + 1}`));\n } else if (\n error.message?.includes(\"better-sqlite3\") ||\n error.message?.includes(\"MODULE_NOT_FOUND\") ||\n error.message?.includes(\"node-gyp\") ||\n error.message?.includes(\"prebuild-install\") ||\n error.message?.includes(\"Cannot find module\")\n ) {\n console.error(chalk.red(\" Failed to load native SQLite module (better-sqlite3).\"));\n console.error(\"\");\n console.error(chalk.yellow(\" This usually means your Node.js version doesn't have prebuilt binaries.\"));\n console.error(\"\");\n console.error(chalk.white(\" How to fix:\"));\n console.error(chalk.gray(\" 1. Use Node.js LTS (v18, v20, or v22) — prebuilt binaries are available\"));\n console.error(chalk.gray(\" → nvm install --lts && nvm use --lts\"));\n console.error(chalk.gray(\" 2. Or install C++ build tools for your platform:\"));\n console.error(chalk.gray(\" → Windows: npm install -g windows-build-tools\"));\n console.error(chalk.gray(\" → macOS: xcode-select --install\"));\n console.error(chalk.gray(\" → Linux: sudo apt install build-essential python3\"));\n console.error(\"\");\n console.error(chalk.gray(` Your Node.js version: ${process.version}`));\n } else {\n console.error(chalk.red(` Failed to start: ${error.message}`));\n }\n process.exit(1);\n }\n}\n","import chalk from \"chalk\";\nimport { resetDb } from \"@llmtap/collector\";\n\nexport async function resetCommand(): Promise<void> {\n try {\n resetDb();\n console.log(chalk.green(\" Data cleared successfully.\"));\n } catch (err: unknown) {\n const error = err as Error;\n console.error(chalk.red(` Failed to reset: ${error.message}`));\n process.exit(1);\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport { getDb } from \"@llmtap/collector\";\nimport { spansToOtlp } from \"@llmtap/shared\";\nimport type { Span } from \"@llmtap/shared\";\n\ninterface ExportOptions {\n output: string;\n limit: string;\n format: string;\n endpoint?: string;\n service?: string;\n}\n\nfunction safeParse(v: unknown): unknown {\n if (!v || typeof v !== \"string\") return undefined;\n try { return JSON.parse(v); } catch { return undefined; }\n}\n\nfunction rowToSpan(row: Record<string, unknown>): Span {\n return {\n ...row,\n parentSpanId: (row.parentSpanId as string) ?? undefined,\n endTime: (row.endTime as number) ?? undefined,\n duration: (row.duration as number) ?? undefined,\n responseModel: (row.responseModel as string) ?? undefined,\n temperature: (row.temperature as number) ?? undefined,\n maxTokens: (row.maxTokens as number) ?? undefined,\n topP: (row.topP as number) ?? undefined,\n inputMessages: safeParse(row.inputMessages) as Span[\"inputMessages\"],\n outputMessages: safeParse(row.outputMessages) as Span[\"outputMessages\"],\n toolCalls: safeParse(row.toolCalls) as Span[\"toolCalls\"],\n tags: safeParse(row.tags) as Record<string, string> | undefined,\n errorType: (row.errorType as string) ?? undefined,\n errorMessage: (row.errorMessage as string) ?? undefined,\n sessionId: (row.sessionId as string) ?? undefined,\n userId: (row.userId as string) ?? undefined,\n } as Span;\n}\n\nexport async function exportCommand(options: ExportOptions): Promise<void> {\n try {\n const db = getDb();\n const limit = parseInt(options.limit, 10);\n const format = options.format ?? \"json\";\n\n if (format === \"otlp\") {\n return await exportOtlp(db, limit, options);\n }\n\n // Get traces\n const traces = db\n .prepare(\n `\n SELECT\n traceId,\n MIN(name) as name,\n MIN(startTime) as startTime,\n MAX(endTime) as endTime,\n CASE WHEN SUM(CASE WHEN status = 'error' THEN 1 ELSE 0 END) > 0\n THEN 'error' ELSE 'ok' END as status,\n COUNT(*) as spanCount,\n COALESCE(SUM(totalTokens), 0) as totalTokens,\n COALESCE(SUM(totalCost), 0) as totalCost\n FROM spans\n GROUP BY traceId\n ORDER BY startTime DESC\n LIMIT ?\n `\n )\n .all(limit) as Array<Record<string, unknown>>;\n\n // Get spans for each trace\n const getSpans = db.prepare(\"SELECT * FROM spans WHERE traceId = ? ORDER BY startTime ASC\");\n const exportData = traces.map((trace) => ({\n ...trace,\n spans: (getSpans.all(trace.traceId) as Array<Record<string, unknown>>).map((span) => ({\n ...span,\n inputMessages: safeParse(span.inputMessages),\n outputMessages: safeParse(span.outputMessages),\n toolCalls: safeParse(span.toolCalls),\n tags: safeParse(span.tags),\n })),\n }));\n\n let output: string;\n let ext: string;\n\n if (format === \"csv\") {\n ext = \"csv\";\n const headers = [\n \"traceId\", \"name\", \"status\", \"spanCount\", \"totalTokens\", \"totalCost\",\n \"startTime\", \"endTime\",\n ];\n const rows = traces.map((t) =>\n headers.map((h) => {\n const val = t[h];\n const s = String(val ?? \"\");\n return s.includes(\",\") || s.includes('\"') || s.includes(\"\\n\") ? `\"${s.replace(/\"/g, '\"\"')}\"` : s;\n }).join(\",\")\n );\n output = [headers.join(\",\"), ...rows].join(\"\\n\");\n } else {\n ext = \"json\";\n output = JSON.stringify(exportData, null, 2);\n }\n\n const defaultOutput = options.output === \"llmtap-export.json\" && format === \"csv\"\n ? \"llmtap-export.csv\"\n : options.output;\n const outputPath = path.resolve(defaultOutput);\n fs.writeFileSync(outputPath, output);\n\n console.log(chalk.green(` Exported ${traces.length} traces as ${ext.toUpperCase()} to ${outputPath}`));\n } catch (err: unknown) {\n const error = err as Error;\n console.error(chalk.red(` Export failed: ${error.message}`));\n process.exit(1);\n }\n}\n\nasync function exportOtlp(\n db: ReturnType<typeof getDb>,\n limit: number,\n options: ExportOptions\n): Promise<void> {\n const rows = db\n .prepare(\"SELECT * FROM spans ORDER BY startTime DESC LIMIT ?\")\n .all(limit) as Array<Record<string, unknown>>;\n\n const spans = rows.map(rowToSpan);\n const otlp = spansToOtlp(spans, options.service ?? \"llmtap\");\n\n // If --endpoint is provided, forward to OTLP collector\n if (options.endpoint) {\n console.log(chalk.blue(` Forwarding ${spans.length} spans to ${options.endpoint}...`));\n try {\n const res = await fetch(options.endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(otlp),\n signal: AbortSignal.timeout(30000),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n console.error(chalk.red(` OTLP endpoint returned ${res.status}: ${body.slice(0, 200)}`));\n process.exit(1);\n }\n console.log(chalk.green(` Successfully forwarded ${spans.length} spans to OTLP endpoint`));\n } catch (err) {\n console.error(chalk.red(` Failed to reach OTLP endpoint: ${err instanceof Error ? err.message : String(err)}`));\n process.exit(1);\n }\n return;\n }\n\n // Otherwise write to file\n const outputPath = path.resolve(\n options.output === \"llmtap-export.json\" ? \"llmtap-export.otlp.json\" : options.output\n );\n fs.writeFileSync(outputPath, JSON.stringify(otlp, null, 2));\n console.log(chalk.green(` Exported ${spans.length} spans as OTLP JSON to ${outputPath}`));\n console.log(chalk.dim(` Import into Jaeger, Grafana Tempo, Datadog, or any OTLP-compatible backend`));\n}\n","import chalk from \"chalk\";\r\n\r\nexport async function statusCommand(): Promise<void> {\r\n try {\r\n const res = await fetch(\"http://localhost:4781/v1/db-info\", {\r\n signal: AbortSignal.timeout(3000),\r\n });\r\n\r\n if (!res.ok) {\r\n console.error(chalk.red(\" Collector responded with an error.\"));\r\n process.exit(1);\r\n }\r\n\r\n const info = (await res.json()) as {\r\n path: string;\r\n sizeBytes: number;\r\n spanCount: number;\r\n traceCount: number;\r\n oldestSpan: number | null;\r\n newestSpan: number | null;\r\n walMode: string;\r\n };\r\n\r\n const formatBytes = (bytes: number) => {\r\n if (bytes === 0) return \"0 B\";\r\n const units = [\"B\", \"KB\", \"MB\", \"GB\"];\r\n const i = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);\r\n return `${(bytes / Math.pow(1024, i)).toFixed(i === 0 ? 0 : 1)} ${units[i]}`;\r\n };\r\n\r\n console.log(\"\");\r\n console.log(chalk.bold.hex(\"#6366f1\")(\" LLMTap\") + chalk.green(\" — Running\"));\r\n console.log(\"\");\r\n console.log(` ${chalk.gray(\"Spans:\")} ${chalk.white(info.spanCount.toLocaleString())}`);\r\n console.log(` ${chalk.gray(\"Traces:\")} ${chalk.white(info.traceCount.toLocaleString())}`);\r\n console.log(` ${chalk.gray(\"DB size:\")} ${chalk.white(formatBytes(info.sizeBytes))}`);\r\n console.log(` ${chalk.gray(\"WAL mode:\")} ${chalk.white(info.walMode.toUpperCase())}`);\r\n console.log(` ${chalk.gray(\"DB path:\")} ${chalk.white(info.path)}`);\r\n\r\n if (info.oldestSpan && info.newestSpan) {\r\n const oldest = new Date(info.oldestSpan).toLocaleString();\r\n const newest = new Date(info.newestSpan).toLocaleString();\r\n console.log(` ${chalk.gray(\"Data range:\")} ${chalk.white(`${oldest} — ${newest}`)}`);\r\n }\r\n console.log(\"\");\r\n } catch {\r\n console.log(\"\");\r\n console.log(chalk.bold.hex(\"#6366f1\")(\" LLMTap\") + chalk.red(\" — Not running\"));\r\n console.log(\"\");\r\n console.log(chalk.gray(\" Start the collector with: \") + chalk.cyan(\"npx llmtap\"));\r\n console.log(\"\");\r\n }\r\n}\r\n","import chalk from \"chalk\";\r\n\r\ninterface TailOptions {\r\n format: string;\r\n}\r\n\r\nexport async function tailCommand(options: TailOptions): Promise<void> {\r\n const format = options.format ?? \"pretty\";\r\n const url = \"http://localhost:4781/v1/stream\";\r\n\r\n console.log(\"\");\r\n console.log(\r\n chalk.bold.hex(\"#6366f1\")(\" LLMTap\") +\r\n chalk.gray(\" — Streaming traces in real-time\")\r\n );\r\n console.log(chalk.gray(\" Press Ctrl+C to stop\"));\r\n console.log(\"\");\r\n\r\n try {\r\n const res = await fetch(url, {\r\n headers: { Accept: \"text/event-stream\" },\r\n });\r\n\r\n if (!res.ok || !res.body) {\r\n console.error(chalk.red(\" Could not connect to collector.\"));\r\n console.error(chalk.gray(\" Make sure the collector is running: npx llmtap\"));\r\n process.exit(1);\r\n }\r\n\r\n const decoder = new TextDecoder();\r\n const reader = res.body.getReader();\r\n let buffer = \"\";\r\n\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n buffer += decoder.decode(value, { stream: true });\r\n const lines = buffer.split(\"\\n\");\r\n buffer = lines.pop() ?? \"\";\r\n\r\n for (const line of lines) {\r\n if (!line.startsWith(\"data: \")) continue;\r\n const json = line.slice(6).trim();\r\n if (!json) continue;\r\n\r\n try {\r\n const span = JSON.parse(json) as {\r\n spanId: string;\r\n traceId: string;\r\n name: string;\r\n providerName: string;\r\n requestModel: string;\r\n duration?: number;\r\n totalTokens: number;\r\n totalCost: number;\r\n status: string;\r\n errorMessage?: string;\r\n };\r\n\r\n if (format === \"json\") {\r\n console.log(json);\r\n } else {\r\n const dur = span.duration ? `${span.duration}ms` : \"...\";\r\n const cost =\r\n span.totalCost > 0 ? `$${span.totalCost.toFixed(4)}` : \"$0\";\r\n const statusIcon =\r\n span.status === \"error\" ? chalk.red(\"ERR\") : chalk.green(\"OK \");\r\n\r\n console.log(\r\n ` ${statusIcon} ${chalk.gray(dur.padStart(7))} ${chalk.cyan(span.providerName.padEnd(10))} ${chalk.white(span.requestModel.padEnd(24))} ${chalk.yellow(String(span.totalTokens).padStart(6) + \" tok\")} ${chalk.green(cost.padStart(8))} ${chalk.gray(span.name)}`\r\n );\r\n if (span.errorMessage) {\r\n console.log(\r\n ` ${chalk.red(\"→ \" + span.errorMessage.slice(0, 120))}`\r\n );\r\n }\r\n }\r\n } catch {\r\n // Skip malformed events\r\n }\r\n }\r\n }\r\n } catch {\r\n console.error(chalk.red(\" Could not connect to collector.\"));\r\n console.error(chalk.gray(\" Make sure the collector is running: npx llmtap\"));\r\n process.exit(1);\r\n }\r\n}\r\n","import chalk from \"chalk\";\r\n\r\nexport async function doctorCommand(): Promise<void> {\r\n console.log(\"\");\r\n console.log(chalk.bold.hex(\"#6366f1\")(\" LLMTap Doctor\"));\r\n console.log(chalk.gray(\" Checking your setup...\"));\r\n console.log(\"\");\r\n\r\n const checks: { label: string; status: \"ok\" | \"warn\" | \"fail\"; detail: string }[] = [];\r\n\r\n // Check 1: Node.js version\r\n const nodeVersion = process.version;\r\n const major = parseInt(nodeVersion.slice(1), 10);\r\n if (major >= 18) {\r\n checks.push({ label: \"Node.js version\", status: \"ok\", detail: nodeVersion });\r\n } else {\r\n checks.push({ label: \"Node.js version\", status: \"fail\", detail: `${nodeVersion} (requires >= 18)` });\r\n }\r\n\r\n // Check 2: Collector running\r\n try {\r\n const res = await fetch(\"http://localhost:4781/health\", {\r\n signal: AbortSignal.timeout(3000),\r\n });\r\n if (res.ok) {\r\n checks.push({ label: \"Collector\", status: \"ok\", detail: \"Running on port 4781\" });\r\n } else {\r\n checks.push({ label: \"Collector\", status: \"fail\", detail: `Responded with HTTP ${res.status}` });\r\n }\r\n } catch {\r\n checks.push({ label: \"Collector\", status: \"warn\", detail: \"Not running (start with: npx llmtap)\" });\r\n }\r\n\r\n // Check 3: Database accessible\r\n try {\r\n const res = await fetch(\"http://localhost:4781/v1/db-info\", {\r\n signal: AbortSignal.timeout(3000),\r\n });\r\n if (res.ok) {\r\n const info = (await res.json()) as { sizeBytes: number; spanCount: number; walMode: string };\r\n checks.push({\r\n label: \"Database\",\r\n status: info.walMode === \"wal\" ? \"ok\" : \"warn\",\r\n detail: `${info.spanCount} spans, WAL=${info.walMode.toUpperCase()}`,\r\n });\r\n }\r\n } catch {\r\n checks.push({ label: \"Database\", status: \"warn\", detail: \"Cannot check (collector not running)\" });\r\n }\r\n\r\n // Check 4: SDK installed\r\n try {\r\n await import(\"@llmtap/sdk\");\r\n checks.push({ label: \"@llmtap/sdk\", status: \"ok\", detail: \"Installed\" });\r\n } catch {\r\n checks.push({ label: \"@llmtap/sdk\", status: \"warn\", detail: \"Not found in current project (install with: npm i @llmtap/sdk)\" });\r\n }\r\n\r\n // Check 5: Port available\r\n if (checks.find((c) => c.label === \"Collector\")?.status !== \"ok\") {\r\n try {\r\n // Try connecting to port 4781 to see if something else is using it\r\n const res = await fetch(\"http://localhost:4781\", {\r\n signal: AbortSignal.timeout(1000),\r\n });\r\n if (!res.ok) {\r\n checks.push({ label: \"Port 4781\", status: \"warn\", detail: \"Something is running but not LLMTap\" });\r\n }\r\n } catch {\r\n checks.push({ label: \"Port 4781\", status: \"ok\", detail: \"Available\" });\r\n }\r\n }\r\n\r\n // Display results\r\n for (const check of checks) {\r\n const icon =\r\n check.status === \"ok\"\r\n ? chalk.green(\" ✓\")\r\n : check.status === \"warn\"\r\n ? chalk.yellow(\" !\")\r\n : chalk.red(\" ✗\");\r\n const label = chalk.white(check.label.padEnd(20));\r\n const detail =\r\n check.status === \"ok\"\r\n ? chalk.gray(check.detail)\r\n : check.status === \"warn\"\r\n ? chalk.yellow(check.detail)\r\n : chalk.red(check.detail);\r\n console.log(`${icon} ${label} ${detail}`);\r\n }\r\n\r\n const failCount = checks.filter((c) => c.status === \"fail\").length;\r\n const warnCount = checks.filter((c) => c.status === \"warn\").length;\r\n console.log(\"\");\r\n if (failCount > 0) {\r\n console.log(chalk.red(` ${failCount} issue(s) found. Fix them to use LLMTap.`));\r\n } else if (warnCount > 0) {\r\n console.log(chalk.yellow(` ${warnCount} warning(s). Everything should still work.`));\r\n } else {\r\n console.log(chalk.green(\" All checks passed!\"));\r\n }\r\n console.log(\"\");\r\n}\r\n","import chalk from \"chalk\";\r\n\r\ninterface StatsResponse {\r\n totalTraces: number;\r\n totalSpans: number;\r\n totalTokens: number;\r\n totalCost: number;\r\n avgDuration: number;\r\n errorCount: number;\r\n errorRate: number;\r\n byProvider: { provider: string; spanCount: number; totalTokens: number; totalCost: number; avgDuration: number }[];\r\n byModel: { model: string; provider: string; spanCount: number; totalTokens: number; totalCost: number; avgDuration: number }[];\r\n}\r\n\r\nexport async function statsCommand(options: { period?: string; host?: string }): Promise<void> {\r\n const period = Number(options.period ?? \"24\");\r\n const host = options.host ?? \"http://localhost:4781\";\r\n\r\n try {\r\n const res = await fetch(`${host}/v1/stats?period=${period}`);\r\n if (!res.ok) {\r\n console.error(chalk.red(`Error: Collector returned HTTP ${res.status}`));\r\n console.error(chalk.dim(\"Is the collector running? Try: npx llmtap start\"));\r\n process.exit(1);\r\n }\r\n\r\n const stats = (await res.json()) as StatsResponse;\r\n\r\n console.log(\"\");\r\n console.log(chalk.bold.white(` LLMTap Stats — Last ${period}h`));\r\n console.log(chalk.dim(\" ─────────────────────────────────\"));\r\n console.log(\"\");\r\n\r\n // Summary\r\n const errorPct = (stats.errorRate * 100).toFixed(1);\r\n console.log(` ${chalk.dim(\"Traces\")} ${chalk.bold.white(String(stats.totalTraces))}`);\r\n console.log(` ${chalk.dim(\"Spans\")} ${chalk.bold.white(String(stats.totalSpans))}`);\r\n console.log(` ${chalk.dim(\"Tokens\")} ${chalk.bold.white(stats.totalTokens.toLocaleString())}`);\r\n console.log(` ${chalk.dim(\"Total Cost\")} ${chalk.bold.green(\"$\" + stats.totalCost.toFixed(4))}`);\r\n console.log(` ${chalk.dim(\"Avg Latency\")} ${chalk.white(formatMs(stats.avgDuration))}`);\r\n console.log(\r\n ` ${chalk.dim(\"Error Rate\")} ${\r\n stats.errorRate > 0.05\r\n ? chalk.bold.red(errorPct + \"%\")\r\n : chalk.green(errorPct + \"%\")\r\n } ${chalk.dim(`(${stats.errorCount} errors)`)}`\r\n );\r\n\r\n // Top providers\r\n if (stats.byProvider.length > 0) {\r\n console.log(\"\");\r\n console.log(chalk.bold.white(\" Top Providers\"));\r\n console.log(chalk.dim(\" ─────────────────────────────────\"));\r\n for (const p of stats.byProvider.slice(0, 5)) {\r\n const bar = makeBar(p.totalCost, stats.totalCost, 20);\r\n console.log(\r\n ` ${chalk.cyan(p.provider.padEnd(12))} ${chalk.dim(String(p.spanCount).padStart(5) + \" calls\")} ${chalk.green(\"$\" + p.totalCost.toFixed(4).padStart(8))} ${chalk.dim(bar)}`\r\n );\r\n }\r\n }\r\n\r\n // Top models\r\n if (stats.byModel.length > 0) {\r\n console.log(\"\");\r\n console.log(chalk.bold.white(\" Top Models\"));\r\n console.log(chalk.dim(\" ─────────────────────────────────\"));\r\n for (const m of stats.byModel.slice(0, 8)) {\r\n const bar = makeBar(m.totalCost, stats.totalCost, 20);\r\n console.log(\r\n ` ${chalk.white(m.model.padEnd(28).slice(0, 28))} ${chalk.dim(String(m.spanCount).padStart(5) + \" calls\")} ${chalk.green(\"$\" + m.totalCost.toFixed(4).padStart(8))} ${chalk.dim(bar)}`\r\n );\r\n }\r\n }\r\n\r\n console.log(\"\");\r\n } catch (err) {\r\n if (err instanceof TypeError && (err as NodeJS.ErrnoException).cause) {\r\n console.error(chalk.red(\"Error: Cannot connect to collector\"));\r\n console.error(chalk.dim(\"Is the collector running? Try: npx llmtap start\"));\r\n } else {\r\n console.error(chalk.red(\"Error:\"), err instanceof Error ? err.message : err);\r\n }\r\n process.exit(1);\r\n }\r\n}\r\n\r\nfunction formatMs(ms: number): string {\r\n if (ms < 1000) return `${Math.round(ms)}ms`;\r\n return `${(ms / 1000).toFixed(2)}s`;\r\n}\r\n\r\nfunction makeBar(value: number, total: number, width: number): string {\r\n if (total <= 0) return \"\";\r\n const filled = Math.max(Math.round((value / total) * width), 1);\r\n return \"█\".repeat(filled) + \"░\".repeat(width - filled);\r\n}\r\n"],"mappings":"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","names":["chalk","fs","path","chalk","chalk","chalk","chalk","chalk"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/start.ts","../src/commands/reset.ts","../src/commands/export.ts","../src/commands/backup.ts","../src/lib/collector.ts","../src/commands/restore.ts","../src/commands/import.ts","../src/lib/data.ts","../src/commands/status.ts","../src/commands/tail.ts","../src/commands/doctor.ts","../src/commands/stats.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { startCommand } from \"./commands/start.js\";\nimport { resetCommand } from \"./commands/reset.js\";\nimport { exportCommand } from \"./commands/export.js\";\nimport { backupCommand } from \"./commands/backup.js\";\nimport { restoreCommand } from \"./commands/restore.js\";\nimport { importCommand } from \"./commands/import.js\";\nimport { statusCommand } from \"./commands/status.js\";\nimport { tailCommand } from \"./commands/tail.js\";\nimport { doctorCommand } from \"./commands/doctor.js\";\nimport { statsCommand } from \"./commands/stats.js\";\nimport { VERSION } from \"@llmtap/shared\";\n\nconst program = new Command();\n\nprogram\n .name(\"llmtap\")\n .description(\"DevTools for AI Agents - See every LLM call, trace agent workflows, track costs\")\n .version(VERSION);\n\nprogram\n .command(\"start\", { isDefault: true })\n .description(\"Start the LLMTap collector and dashboard\")\n .option(\"-p, --port <port>\", \"Port number\", \"4781\")\n .option(\"-H, --host <host>\", \"Host to bind to (use 0.0.0.0 to expose to network)\", \"127.0.0.1\")\n .option(\"-q, --quiet\", \"Suppress server logs\")\n .option(\"--demo\", \"Seed demo data on startup\")\n .option(\"--no-open\", \"Don't open browser automatically\")\n .option(\"-r, --retention <days>\", \"Auto-delete data older than N days (0 = keep forever)\")\n .action(startCommand);\n\nprogram\n .command(\"status\")\n .description(\"Show collector status, database info, and span count\")\n .option(\"--host <url>\", \"Collector URL\", \"http://localhost:4781\")\n .action(statusCommand);\n\nprogram\n .command(\"reset\")\n .description(\"Clear all stored data\")\n .action(resetCommand);\n\nprogram\n .command(\"export\")\n .description(\"Export traces as JSON, CSV, or OTLP\")\n .option(\"-o, --output <path>\", \"Output file path\", \"llmtap-export.json\")\n .option(\"-f, --format <format>\", \"Output format (json, csv, or otlp)\", \"json\")\n .option(\"-l, --limit <count>\", \"Number of traces/spans to export\", \"100\")\n .option(\"-e, --endpoint <url>\", \"OTLP endpoint to forward spans to (e.g. http://localhost:4318/v1/traces)\")\n .option(\"-s, --service <name>\", \"service.name for OTLP export\", \"llmtap\")\n .action(exportCommand);\n\nprogram\n .command(\"backup\")\n .description(\"Create a portable SQLite backup of your local LLMTap data\")\n .option(\"-o, --output <path>\", \"Backup output path\")\n .action(backupCommand);\n\nprogram\n .command(\"restore <input>\")\n .description(\"Restore the local LLMTap database from a backup file\")\n .option(\"--host <url>\", \"Collector URL to check before restoring\", \"http://localhost:4781\")\n .action(restoreCommand);\n\nprogram\n .command(\"import <input>\")\n .description(\"Import LLMTap JSON exports back into local storage\")\n .option(\"--replace\", \"Replace the existing local database contents before importing\")\n .option(\"--host <url>\", \"Collector URL for live ingest when running\", \"http://localhost:4781\")\n .action(importCommand);\n\nprogram\n .command(\"tail\")\n .description(\"Stream traces to terminal in real-time\")\n .option(\"-f, --format <format>\", \"Output format (pretty or json)\", \"pretty\")\n .action(tailCommand);\n\nprogram\n .command(\"doctor\")\n .description(\"Diagnose common setup issues\")\n .option(\"--host <url>\", \"Collector URL\", \"http://localhost:4781\")\n .action(doctorCommand);\n\nprogram\n .command(\"stats\")\n .description(\"Show quick terminal stats (cost, models, errors)\")\n .option(\"-p, --period <hours>\", \"Time period in hours\", \"24\")\n .option(\"--host <url>\", \"Collector URL\", \"http://localhost:4781\")\n .action(statsCommand);\n\nprogram.parse();\n","import path from \"node:path\";\nimport fs from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport chalk from \"chalk\";\nimport open from \"open\";\nimport { startServer, getOtlpEndpoint } from \"@llmtap/collector\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\ninterface StartOptions {\n port: string;\n host: string;\n quiet?: boolean;\n open?: boolean;\n demo?: boolean;\n retention?: string;\n}\n\nexport async function startCommand(options: StartOptions): Promise<void> {\n const port = parseInt(options.port, 10);\n const retentionDays = options.retention\n ? parseInt(options.retention, 10)\n : undefined;\n\n // Resolve dashboard dist path\n // 1. Bundled inside CLI dist (for npm publish): dist/dashboard/\n // 2. Monorepo sibling (for local dev): ../../dashboard/dist/\n const bundledPath = path.resolve(__dirname, \"dashboard\");\n const monorepoPath = path.resolve(__dirname, \"..\", \"..\", \"dashboard\", \"dist\");\n const dashboardPath = fs.existsSync(bundledPath) ? bundledPath : monorepoPath;\n\n console.log(\"\");\n console.log(chalk.bold.hex(\"#6366f1\")(\" LLMTap\") + chalk.gray(\" - DevTools for AI Agents\"));\n console.log(\"\");\n\n try {\n const host = options.host;\n\n if (host === \"0.0.0.0\") {\n console.log(chalk.yellow(\" ⚠ Binding to 0.0.0.0 — the collector will be accessible from your network\"));\n console.log(\"\");\n }\n\n const address = await startServer({\n port,\n host,\n dashboardPath,\n quiet: options.quiet,\n demo: options.demo,\n retentionDays,\n });\n\n const url = `http://${host === \"0.0.0.0\" ? \"localhost\" : host}:${port}`;\n\n console.log(chalk.green(\" Ready!\"));\n console.log(\"\");\n console.log(` ${chalk.gray(\"Dashboard:\")} ${chalk.cyan(url)}`);\n console.log(` ${chalk.gray(\"API:\")} ${chalk.cyan(`${url}/v1`)}`);\n console.log(` ${chalk.gray(\"Health:\")} ${chalk.cyan(`${url}/health`)}`);\n if (retentionDays && retentionDays > 0) {\n console.log(` ${chalk.gray(\"Retention:\")} ${chalk.yellow(`${retentionDays} days`)}`);\n }\n const otlpTarget = getOtlpEndpoint();\n if (otlpTarget) {\n console.log(` ${chalk.gray(\"OTLP:\")} ${chalk.cyan(otlpTarget)} ${chalk.green(\"(auto-forwarding)\")}`);\n }\n console.log(\"\");\n console.log(chalk.gray(\" Press Ctrl+C to stop\"));\n console.log(\"\");\n\n // Open browser\n if (options.open !== false) {\n try {\n await open(url);\n } catch {\n // Ignore if browser can't be opened\n }\n }\n } catch (err: unknown) {\n const error = err as Error;\n if (error.message?.includes(\"EADDRINUSE\")) {\n console.error(chalk.red(` Port ${port} is already in use.`));\n console.error(chalk.gray(` Try: npx llmtap --port ${port + 1}`));\n } else if (\n error.message?.includes(\"better-sqlite3\") ||\n error.message?.includes(\"MODULE_NOT_FOUND\") ||\n error.message?.includes(\"node-gyp\") ||\n error.message?.includes(\"prebuild-install\") ||\n error.message?.includes(\"Cannot find module\")\n ) {\n console.error(chalk.red(\" Failed to load native SQLite module (better-sqlite3).\"));\n console.error(\"\");\n console.error(chalk.yellow(\" This usually means your Node.js version doesn't have prebuilt binaries.\"));\n console.error(\"\");\n console.error(chalk.white(\" How to fix:\"));\n console.error(chalk.gray(\" 1. Use Node.js LTS (v18, v20, or v22) — prebuilt binaries are available\"));\n console.error(chalk.gray(\" → nvm install --lts && nvm use --lts\"));\n console.error(chalk.gray(\" 2. Or install C++ build tools for your platform:\"));\n console.error(chalk.gray(\" → Windows: npm install -g windows-build-tools\"));\n console.error(chalk.gray(\" → macOS: xcode-select --install\"));\n console.error(chalk.gray(\" → Linux: sudo apt install build-essential python3\"));\n console.error(\"\");\n console.error(chalk.gray(` Your Node.js version: ${process.version}`));\n } else {\n console.error(chalk.red(` Failed to start: ${error.message}`));\n }\n process.exit(1);\n }\n}\n","import chalk from \"chalk\";\nimport { resetDb } from \"@llmtap/collector\";\n\nexport async function resetCommand(): Promise<void> {\n try {\n resetDb();\n console.log(chalk.green(\" Data cleared successfully.\"));\n } catch (err: unknown) {\n const error = err as Error;\n console.error(chalk.red(` Failed to reset: ${error.message}`));\n process.exit(1);\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport { getDb } from \"@llmtap/collector\";\nimport { spansToOtlp } from \"@llmtap/shared\";\nimport type { Span } from \"@llmtap/shared\";\n\ninterface ExportOptions {\n output: string;\n limit: string;\n format: string;\n endpoint?: string;\n service?: string;\n}\n\nfunction safeParse(v: unknown): unknown {\n if (!v || typeof v !== \"string\") return undefined;\n try { return JSON.parse(v); } catch { return undefined; }\n}\n\nfunction rowToSpan(row: Record<string, unknown>): Span {\n return {\n ...row,\n parentSpanId: (row.parentSpanId as string) ?? undefined,\n endTime: (row.endTime as number) ?? undefined,\n duration: (row.duration as number) ?? undefined,\n responseModel: (row.responseModel as string) ?? undefined,\n temperature: (row.temperature as number) ?? undefined,\n maxTokens: (row.maxTokens as number) ?? undefined,\n topP: (row.topP as number) ?? undefined,\n inputMessages: safeParse(row.inputMessages) as Span[\"inputMessages\"],\n outputMessages: safeParse(row.outputMessages) as Span[\"outputMessages\"],\n toolCalls: safeParse(row.toolCalls) as Span[\"toolCalls\"],\n tags: safeParse(row.tags) as Record<string, string> | undefined,\n errorType: (row.errorType as string) ?? undefined,\n errorMessage: (row.errorMessage as string) ?? undefined,\n sessionId: (row.sessionId as string) ?? undefined,\n userId: (row.userId as string) ?? undefined,\n } as Span;\n}\n\nexport async function exportCommand(options: ExportOptions): Promise<void> {\n try {\n const db = getDb();\n const limit = parseInt(options.limit, 10);\n const format = options.format ?? \"json\";\n\n if (format === \"otlp\") {\n return await exportOtlp(db, limit, options);\n }\n\n // Get traces\n const traces = db\n .prepare(\n `\n SELECT\n traceId,\n MIN(name) as name,\n MIN(startTime) as startTime,\n MAX(endTime) as endTime,\n CASE WHEN SUM(CASE WHEN status = 'error' THEN 1 ELSE 0 END) > 0\n THEN 'error' ELSE 'ok' END as status,\n COUNT(*) as spanCount,\n COALESCE(SUM(totalTokens), 0) as totalTokens,\n COALESCE(SUM(totalCost), 0) as totalCost\n FROM spans\n GROUP BY traceId\n ORDER BY startTime DESC\n LIMIT ?\n `\n )\n .all(limit) as Array<Record<string, unknown>>;\n\n // Get spans for each trace\n const getSpans = db.prepare(\"SELECT * FROM spans WHERE traceId = ? ORDER BY startTime ASC\");\n const exportData = traces.map((trace) => ({\n ...trace,\n spans: (getSpans.all(trace.traceId) as Array<Record<string, unknown>>).map((span) => ({\n ...span,\n inputMessages: safeParse(span.inputMessages),\n outputMessages: safeParse(span.outputMessages),\n toolCalls: safeParse(span.toolCalls),\n tags: safeParse(span.tags),\n })),\n }));\n\n let output: string;\n let ext: string;\n\n if (format === \"csv\") {\n ext = \"csv\";\n const headers = [\n \"traceId\", \"name\", \"status\", \"spanCount\", \"totalTokens\", \"totalCost\",\n \"startTime\", \"endTime\",\n ];\n const rows = traces.map((t) =>\n headers.map((h) => {\n const val = t[h];\n const s = String(val ?? \"\");\n return s.includes(\",\") || s.includes('\"') || s.includes(\"\\n\") ? `\"${s.replace(/\"/g, '\"\"')}\"` : s;\n }).join(\",\")\n );\n output = [headers.join(\",\"), ...rows].join(\"\\n\");\n } else {\n ext = \"json\";\n output = JSON.stringify(exportData, null, 2);\n }\n\n const defaultOutput = options.output === \"llmtap-export.json\" && format === \"csv\"\n ? \"llmtap-export.csv\"\n : options.output;\n const outputPath = path.resolve(defaultOutput);\n fs.writeFileSync(outputPath, output);\n\n console.log(chalk.green(` Exported ${traces.length} traces as ${ext.toUpperCase()} to ${outputPath}`));\n } catch (err: unknown) {\n const error = err as Error;\n console.error(chalk.red(` Export failed: ${error.message}`));\n process.exit(1);\n }\n}\n\nasync function exportOtlp(\n db: ReturnType<typeof getDb>,\n limit: number,\n options: ExportOptions\n): Promise<void> {\n const rows = db\n .prepare(\"SELECT * FROM spans ORDER BY startTime DESC LIMIT ?\")\n .all(limit) as Array<Record<string, unknown>>;\n\n const spans = rows.map(rowToSpan);\n const otlp = spansToOtlp(spans, options.service ?? \"llmtap\");\n\n // If --endpoint is provided, forward to OTLP collector\n if (options.endpoint) {\n console.log(chalk.blue(` Forwarding ${spans.length} spans to ${options.endpoint}...`));\n try {\n const res = await fetch(options.endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(otlp),\n signal: AbortSignal.timeout(30000),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n console.error(chalk.red(` OTLP endpoint returned ${res.status}: ${body.slice(0, 200)}`));\n process.exit(1);\n }\n console.log(chalk.green(` Successfully forwarded ${spans.length} spans to OTLP endpoint`));\n } catch (err) {\n console.error(chalk.red(` Failed to reach OTLP endpoint: ${err instanceof Error ? err.message : String(err)}`));\n process.exit(1);\n }\n return;\n }\n\n // Otherwise write to file\n const outputPath = path.resolve(\n options.output === \"llmtap-export.json\" ? \"llmtap-export.otlp.json\" : options.output\n );\n fs.writeFileSync(outputPath, JSON.stringify(otlp, null, 2));\n console.log(chalk.green(` Exported ${spans.length} spans as OTLP JSON to ${outputPath}`));\n console.log(chalk.dim(` Import into Jaeger, Grafana Tempo, Datadog, or any OTLP-compatible backend`));\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport { backupDb, getDbPath } from \"@llmtap/collector\";\nimport { formatBytes } from \"../lib/collector.js\";\n\ninterface BackupOptions {\n output?: string;\n}\n\nexport async function backupCommand(options: BackupOptions): Promise<void> {\n try {\n const sourcePath = getDbPath();\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const output = options.output?.trim() || `llmtap-backup-${stamp}.db`;\n const backupPath = backupDb(output);\n const sizeBytes = fs.statSync(backupPath).size;\n\n console.log(\"\");\n console.log(chalk.bold.hex(\"#6366f1\")(\" LLMTap Backup\"));\n console.log(\"\");\n console.log(` ${chalk.gray(\"Source:\")} ${chalk.white(sourcePath)}`);\n console.log(` ${chalk.gray(\"Backup file:\")} ${chalk.white(path.resolve(backupPath))}`);\n console.log(` ${chalk.gray(\"Size:\")} ${chalk.white(formatBytes(sizeBytes))}`);\n console.log(\"\");\n console.log(chalk.green(\" Backup completed.\"));\n console.log(\"\");\n } catch (err) {\n const error = err as Error;\n console.error(chalk.red(` Backup failed: ${error.message}`));\n process.exit(1);\n }\n}\n","export interface CollectorDbInfo {\n path: string;\n sizeBytes: number;\n spanCount: number;\n traceCount: number;\n oldestSpan: number | null;\n newestSpan: number | null;\n walMode: string;\n}\n\nexport async function isCollectorRunning(baseUrl = \"http://localhost:4781\"): Promise<boolean> {\n try {\n const res = await fetch(`${baseUrl}/health`, {\n signal: AbortSignal.timeout(1500),\n });\n return res.ok;\n } catch {\n return false;\n }\n}\n\nexport async function fetchCollectorDbInfo(\n baseUrl = \"http://localhost:4781\"\n): Promise<CollectorDbInfo | null> {\n try {\n const res = await fetch(`${baseUrl}/v1/db-info`, {\n signal: AbortSignal.timeout(3000),\n });\n if (!res.ok) return null;\n return (await res.json()) as CollectorDbInfo;\n } catch {\n return null;\n }\n}\n\nexport async function ingestSpans(\n spans: unknown[],\n baseUrl = \"http://localhost:4781\",\n batchSize = 250\n): Promise<number> {\n let accepted = 0;\n\n for (let index = 0; index < spans.length; index += batchSize) {\n const batch = spans.slice(index, index + batchSize);\n const res = await fetch(`${baseUrl}/v1/spans`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ spans: batch }),\n signal: AbortSignal.timeout(10000),\n });\n\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`Collector import failed with HTTP ${res.status}${body ? `: ${body.slice(0, 200)}` : \"\"}`);\n }\n\n const payload = (await res.json()) as { accepted?: number };\n accepted += payload.accepted ?? batch.length;\n }\n\n return accepted;\n}\n\nexport function formatBytes(bytes: number): string {\n if (bytes === 0) return \"0 B\";\n const units = [\"B\", \"KB\", \"MB\", \"GB\"];\n const index = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);\n return `${(bytes / Math.pow(1024, index)).toFixed(index === 0 ? 0 : 1)} ${units[index]}`;\n}\n","import chalk from \"chalk\";\nimport { restoreDb } from \"@llmtap/collector\";\nimport { isCollectorRunning } from \"../lib/collector.js\";\n\ninterface RestoreOptions {\n host?: string;\n}\n\nexport async function restoreCommand(inputPath: string, options: RestoreOptions): Promise<void> {\n const host = options.host ?? \"http://localhost:4781\";\n\n try {\n if (await isCollectorRunning(host)) {\n console.error(chalk.red(\" Restore blocked: the collector is currently running.\"));\n console.error(chalk.yellow(\" Stop LLMTap first, then run restore again.\"));\n process.exit(1);\n }\n\n const restoredPath = restoreDb(inputPath);\n\n console.log(\"\");\n console.log(chalk.bold.hex(\"#6366f1\")(\" LLMTap Restore\"));\n console.log(\"\");\n console.log(` ${chalk.gray(\"Backup:\")} ${chalk.white(inputPath)}`);\n console.log(` ${chalk.gray(\"Restored to:\")} ${chalk.white(restoredPath)}`);\n console.log(\"\");\n console.log(chalk.green(\" Restore completed. Start LLMTap to inspect the restored data.\"));\n console.log(\"\");\n } catch (err) {\n const error = err as Error;\n console.error(chalk.red(` Restore failed: ${error.message}`));\n process.exit(1);\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport { insertSpans, resetDb } from \"@llmtap/collector\";\nimport { ingestSpans, isCollectorRunning } from \"../lib/collector.js\";\nimport { normalizeImportPayload, summarizeImportedSpans } from \"../lib/data.js\";\n\ninterface ImportOptions {\n replace?: boolean;\n host?: string;\n}\n\nexport async function importCommand(inputPath: string, options: ImportOptions): Promise<void> {\n try {\n const resolvedPath = path.resolve(inputPath);\n const file = fs.readFileSync(resolvedPath, \"utf8\");\n const payload = JSON.parse(file) as unknown;\n const spans = normalizeImportPayload(payload);\n const summary = summarizeImportedSpans(spans);\n const host = options.host ?? \"http://localhost:4781\";\n const collectorRunning = await isCollectorRunning(host);\n\n if (options.replace) {\n if (collectorRunning) {\n console.error(chalk.red(\" Replace import blocked: the collector is currently running.\"));\n console.error(chalk.yellow(\" Stop LLMTap first, then rerun with --replace.\"));\n process.exit(1);\n }\n resetDb();\n }\n\n const accepted = collectorRunning\n ? await ingestSpans(spans, host)\n : insertSpans(spans);\n\n console.log(\"\");\n console.log(chalk.bold.hex(\"#6366f1\")(\" LLMTap Import\"));\n console.log(\"\");\n console.log(` ${chalk.gray(\"File:\")} ${chalk.white(resolvedPath)}`);\n console.log(` ${chalk.gray(\"Trace count:\")} ${chalk.white(summary.traceCount.toLocaleString())}`);\n console.log(` ${chalk.gray(\"Span count:\")} ${chalk.white(summary.spanCount.toLocaleString())}`);\n console.log(` ${chalk.gray(\"Mode:\")} ${chalk.white(collectorRunning ? \"Live ingest via collector\" : \"Direct local database import\")}`);\n if (options.replace) {\n console.log(` ${chalk.gray(\"Replace:\")} ${chalk.white(\"Yes\")}`);\n }\n console.log(\"\");\n console.log(chalk.green(` Imported ${accepted.toLocaleString()} spans.`));\n console.log(\"\");\n } catch (err) {\n const error = err as Error;\n console.error(chalk.red(` Import failed: ${error.message}`));\n process.exit(1);\n }\n}\n","import type { SpanInput } from \"@llmtap/shared\";\n\ninterface TraceExportShape {\n traceId?: unknown;\n spans?: unknown;\n}\n\nfunction isSpanCandidate(value: unknown): value is SpanInput {\n if (!value || typeof value !== \"object\") return false;\n const span = value as Record<string, unknown>;\n return (\n typeof span.spanId === \"string\" &&\n typeof span.traceId === \"string\" &&\n typeof span.name === \"string\" &&\n typeof span.operationName === \"string\" &&\n typeof span.providerName === \"string\" &&\n typeof span.requestModel === \"string\" &&\n typeof span.startTime === \"number\" &&\n typeof span.status === \"string\"\n );\n}\n\nfunction collectFromArray(items: unknown[]): SpanInput[] {\n if (items.every(isSpanCandidate)) {\n return items;\n }\n\n const spans = items.flatMap((item) => {\n if (!item || typeof item !== \"object\") return [];\n const trace = item as TraceExportShape;\n return Array.isArray(trace.spans) ? trace.spans.filter(isSpanCandidate) : [];\n });\n\n return spans;\n}\n\nexport function normalizeImportPayload(payload: unknown): SpanInput[] {\n if (Array.isArray(payload)) {\n const spans = collectFromArray(payload);\n if (spans.length > 0) return spans;\n }\n\n if (payload && typeof payload === \"object\") {\n const record = payload as Record<string, unknown>;\n if (Array.isArray(record.spans)) {\n const spans = record.spans.filter(isSpanCandidate);\n if (spans.length > 0) return spans;\n }\n if (Array.isArray(record.traces)) {\n const spans = collectFromArray(record.traces);\n if (spans.length > 0) return spans;\n }\n }\n\n throw new Error(\n \"Unsupported import file. Expected LLMTap JSON export with traces[].spans or a raw spans array.\"\n );\n}\n\nexport function summarizeImportedSpans(spans: SpanInput[]): {\n spanCount: number;\n traceCount: number;\n} {\n return {\n spanCount: spans.length,\n traceCount: new Set(spans.map((span) => span.traceId)).size,\n };\n}\n","import chalk from \"chalk\";\nimport { fetchCollectorDbInfo, formatBytes } from \"../lib/collector.js\";\n\ninterface StatusOptions {\n host?: string;\n}\n\nexport async function statusCommand(options: StatusOptions = {}): Promise<void> {\n try {\n const info = await fetchCollectorDbInfo(options.host ?? \"http://localhost:4781\");\n\n if (!info) {\n console.error(chalk.red(\" Collector responded with an error.\"));\n process.exit(1);\n }\n\n console.log(\"\");\n console.log(chalk.bold.hex(\"#6366f1\")(\" LLMTap\") + chalk.green(\" - Running\"));\n console.log(\"\");\n console.log(` ${chalk.gray(\"Spans:\")} ${chalk.white(info.spanCount.toLocaleString())}`);\n console.log(` ${chalk.gray(\"Traces:\")} ${chalk.white(info.traceCount.toLocaleString())}`);\n console.log(` ${chalk.gray(\"DB size:\")} ${chalk.white(formatBytes(info.sizeBytes))}`);\n console.log(` ${chalk.gray(\"WAL mode:\")} ${chalk.white(info.walMode.toUpperCase())}`);\n console.log(` ${chalk.gray(\"DB path:\")} ${chalk.white(info.path)}`);\n\n if (info.oldestSpan && info.newestSpan) {\n const oldest = new Date(info.oldestSpan).toLocaleString();\n const newest = new Date(info.newestSpan).toLocaleString();\n console.log(` ${chalk.gray(\"Data range:\")} ${chalk.white(`${oldest} - ${newest}`)}`);\n }\n console.log(\"\");\n } catch {\n console.log(\"\");\n console.log(chalk.bold.hex(\"#6366f1\")(\" LLMTap\") + chalk.red(\" - Not running\"));\n console.log(\"\");\n console.log(chalk.gray(\" Start the collector with: \") + chalk.cyan(\"npx llmtap\"));\n console.log(\"\");\n }\n}\n","import chalk from \"chalk\";\r\n\r\ninterface TailOptions {\r\n format: string;\r\n}\r\n\r\nexport async function tailCommand(options: TailOptions): Promise<void> {\r\n const format = options.format ?? \"pretty\";\r\n const url = \"http://localhost:4781/v1/stream\";\r\n\r\n console.log(\"\");\r\n console.log(\r\n chalk.bold.hex(\"#6366f1\")(\" LLMTap\") +\r\n chalk.gray(\" — Streaming traces in real-time\")\r\n );\r\n console.log(chalk.gray(\" Press Ctrl+C to stop\"));\r\n console.log(\"\");\r\n\r\n try {\r\n const res = await fetch(url, {\r\n headers: { Accept: \"text/event-stream\" },\r\n });\r\n\r\n if (!res.ok || !res.body) {\r\n console.error(chalk.red(\" Could not connect to collector.\"));\r\n console.error(chalk.gray(\" Make sure the collector is running: npx llmtap\"));\r\n process.exit(1);\r\n }\r\n\r\n const decoder = new TextDecoder();\r\n const reader = res.body.getReader();\r\n let buffer = \"\";\r\n\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n buffer += decoder.decode(value, { stream: true });\r\n const lines = buffer.split(\"\\n\");\r\n buffer = lines.pop() ?? \"\";\r\n\r\n for (const line of lines) {\r\n if (!line.startsWith(\"data: \")) continue;\r\n const json = line.slice(6).trim();\r\n if (!json) continue;\r\n\r\n try {\r\n const span = JSON.parse(json) as {\r\n spanId: string;\r\n traceId: string;\r\n name: string;\r\n providerName: string;\r\n requestModel: string;\r\n duration?: number;\r\n totalTokens: number;\r\n totalCost: number;\r\n status: string;\r\n errorMessage?: string;\r\n };\r\n\r\n if (format === \"json\") {\r\n console.log(json);\r\n } else {\r\n const dur = span.duration ? `${span.duration}ms` : \"...\";\r\n const cost =\r\n span.totalCost > 0 ? `$${span.totalCost.toFixed(4)}` : \"$0\";\r\n const statusIcon =\r\n span.status === \"error\" ? chalk.red(\"ERR\") : chalk.green(\"OK \");\r\n\r\n console.log(\r\n ` ${statusIcon} ${chalk.gray(dur.padStart(7))} ${chalk.cyan(span.providerName.padEnd(10))} ${chalk.white(span.requestModel.padEnd(24))} ${chalk.yellow(String(span.totalTokens).padStart(6) + \" tok\")} ${chalk.green(cost.padStart(8))} ${chalk.gray(span.name)}`\r\n );\r\n if (span.errorMessage) {\r\n console.log(\r\n ` ${chalk.red(\"→ \" + span.errorMessage.slice(0, 120))}`\r\n );\r\n }\r\n }\r\n } catch {\r\n // Skip malformed events\r\n }\r\n }\r\n }\r\n } catch {\r\n console.error(chalk.red(\" Could not connect to collector.\"));\r\n console.error(chalk.gray(\" Make sure the collector is running: npx llmtap\"));\r\n process.exit(1);\r\n }\r\n}\r\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport chalk from \"chalk\";\nimport { getDbDirPath, getDbPath } from \"@llmtap/collector\";\nimport { fetchCollectorDbInfo, formatBytes, isCollectorRunning } from \"../lib/collector.js\";\n\ntype CheckStatus = \"ok\" | \"warn\" | \"fail\";\n\ninterface Check {\n label: string;\n status: CheckStatus;\n detail: string;\n}\n\ninterface DoctorOptions {\n host?: string;\n}\n\nfunction formatCheck(check: Check): string {\n const icon =\n check.status === \"ok\"\n ? chalk.green(\" OK \")\n : check.status === \"warn\"\n ? chalk.yellow(\" ! \")\n : chalk.red(\" X \");\n\n const label = chalk.white(check.label.padEnd(20));\n const detail =\n check.status === \"ok\"\n ? chalk.gray(check.detail)\n : check.status === \"warn\"\n ? chalk.yellow(check.detail)\n : chalk.red(check.detail);\n\n return `${icon}${label} ${detail}`;\n}\n\nfunction hasLocalSdkInstall(): boolean {\n try {\n const requireFromCwd = createRequire(path.join(process.cwd(), \"__llmtap__.js\"));\n requireFromCwd.resolve(\"@llmtap/sdk\");\n return true;\n } catch {\n return false;\n }\n}\n\nfunction findPackageJson(): { hasPackageJson: boolean; path?: string } {\n const packageJsonPath = path.join(process.cwd(), \"package.json\");\n return fs.existsSync(packageJsonPath)\n ? { hasPackageJson: true, path: packageJsonPath }\n : { hasPackageJson: false };\n}\n\nexport async function doctorCommand(options: DoctorOptions = {}): Promise<void> {\n const host = options.host ?? \"http://localhost:4781\";\n const checks: Check[] = [];\n const nextSteps: string[] = [];\n\n console.log(\"\");\n console.log(chalk.bold.hex(\"#6366f1\")(\" LLMTap Doctor\"));\n console.log(chalk.gray(` Checking runtime, storage, and onboarding state at ${host}`));\n console.log(\"\");\n\n const nodeVersion = process.version;\n const major = parseInt(nodeVersion.slice(1), 10);\n checks.push(\n major >= 18\n ? { label: \"Node.js version\", status: \"ok\", detail: nodeVersion }\n : { label: \"Node.js version\", status: \"fail\", detail: `${nodeVersion} (requires Node 18 or newer)` }\n );\n\n const collectorRunning = await isCollectorRunning(host);\n if (collectorRunning) {\n checks.push({ label: \"Collector\", status: \"ok\", detail: `Running at ${host}` });\n } else {\n checks.push({ label: \"Collector\", status: \"warn\", detail: \"Not running right now\" });\n nextSteps.push(\"Start LLMTap with `npx llmtap` to open the dashboard and collector.\");\n }\n\n const dbDir = getDbDirPath();\n const dbPath = getDbPath();\n const dbDirExists = fs.existsSync(dbDir);\n const dbFileExists = fs.existsSync(dbPath);\n\n checks.push(\n dbDirExists\n ? { label: \"DB directory\", status: \"ok\", detail: dbDir }\n : { label: \"DB directory\", status: \"warn\", detail: `Not created yet (${dbDir})` }\n );\n\n if (dbDirExists) {\n try {\n fs.accessSync(dbDir, fs.constants.R_OK | fs.constants.W_OK);\n checks.push({ label: \"DB permissions\", status: \"ok\", detail: \"Readable and writable\" });\n } catch {\n checks.push({ label: \"DB permissions\", status: \"fail\", detail: \"Current user cannot read/write the data directory\" });\n }\n }\n\n if (dbFileExists) {\n const stat = fs.statSync(dbPath);\n checks.push({ label: \"DB file\", status: \"ok\", detail: `${dbPath} (${formatBytes(stat.size)})` });\n } else {\n checks.push({ label: \"DB file\", status: \"warn\", detail: `No local database yet (${dbPath})` });\n }\n\n const dbInfo = collectorRunning ? await fetchCollectorDbInfo(host) : null;\n if (collectorRunning && dbInfo) {\n const spanSummary =\n dbInfo.spanCount > 0\n ? `${dbInfo.spanCount.toLocaleString()} spans across ${dbInfo.traceCount.toLocaleString()} traces`\n : \"Collector is healthy, but no spans have been captured yet\";\n checks.push({\n label: \"Collector data\",\n status: dbInfo.spanCount > 0 ? \"ok\" : \"warn\",\n detail: `${spanSummary}; WAL=${dbInfo.walMode.toUpperCase()}`,\n });\n if (dbInfo.spanCount === 0) {\n nextSteps.push(\"Wrap your LLM client with `@llmtap/sdk`, make one model call, then refresh the dashboard.\");\n }\n } else if (collectorRunning) {\n checks.push({ label: \"Collector data\", status: \"warn\", detail: \"Collector is up, but /v1/db-info did not respond cleanly\" });\n }\n\n const packageJson = findPackageJson();\n if (packageJson.hasPackageJson) {\n checks.push({ label: \"Project root\", status: \"ok\", detail: packageJson.path! });\n } else {\n checks.push({ label: \"Project root\", status: \"warn\", detail: \"No package.json in the current directory\" });\n nextSteps.push(\"Run `doctor` from the app you want to instrument so LLMTap can verify local dependencies.\");\n }\n\n if (hasLocalSdkInstall()) {\n checks.push({ label: \"@llmtap/sdk\", status: \"ok\", detail: \"Installed in the current project\" });\n } else {\n checks.push({ label: \"@llmtap/sdk\", status: \"warn\", detail: \"Not installed in the current project\" });\n nextSteps.push(\"Install the SDK in your app with `npm i @llmtap/sdk` or `pnpm add @llmtap/sdk`.\");\n }\n\n for (const check of checks) {\n console.log(formatCheck(check));\n }\n\n const failCount = checks.filter((check) => check.status === \"fail\").length;\n const warnCount = checks.filter((check) => check.status === \"warn\").length;\n\n console.log(\"\");\n if (nextSteps.length > 0) {\n console.log(chalk.bold.white(\" Next steps\"));\n for (const step of nextSteps) {\n console.log(chalk.gray(` - ${step}`));\n }\n console.log(\"\");\n }\n\n if (failCount > 0) {\n console.log(chalk.red(` ${failCount} blocking issue(s) found.`));\n } else if (warnCount > 0) {\n console.log(chalk.yellow(` ${warnCount} warning(s) found.`));\n } else {\n console.log(chalk.green(\" All checks passed.\"));\n }\n console.log(\"\");\n}\n","import chalk from \"chalk\";\r\n\r\ninterface StatsResponse {\r\n totalTraces: number;\r\n totalSpans: number;\r\n totalTokens: number;\r\n totalCost: number;\r\n avgDuration: number;\r\n errorCount: number;\r\n errorRate: number;\r\n byProvider: { provider: string; spanCount: number; totalTokens: number; totalCost: number; avgDuration: number }[];\r\n byModel: { model: string; provider: string; spanCount: number; totalTokens: number; totalCost: number; avgDuration: number }[];\r\n}\r\n\r\nexport async function statsCommand(options: { period?: string; host?: string }): Promise<void> {\r\n const period = Number(options.period ?? \"24\");\r\n const host = options.host ?? \"http://localhost:4781\";\r\n\r\n try {\r\n const res = await fetch(`${host}/v1/stats?period=${period}`);\r\n if (!res.ok) {\r\n console.error(chalk.red(`Error: Collector returned HTTP ${res.status}`));\r\n console.error(chalk.dim(\"Is the collector running? Try: npx llmtap start\"));\r\n process.exit(1);\r\n }\r\n\r\n const stats = (await res.json()) as StatsResponse;\r\n\r\n console.log(\"\");\r\n console.log(chalk.bold.white(` LLMTap Stats — Last ${period}h`));\r\n console.log(chalk.dim(\" ─────────────────────────────────\"));\r\n console.log(\"\");\r\n\r\n // Summary\r\n const errorPct = (stats.errorRate * 100).toFixed(1);\r\n console.log(` ${chalk.dim(\"Traces\")} ${chalk.bold.white(String(stats.totalTraces))}`);\r\n console.log(` ${chalk.dim(\"Spans\")} ${chalk.bold.white(String(stats.totalSpans))}`);\r\n console.log(` ${chalk.dim(\"Tokens\")} ${chalk.bold.white(stats.totalTokens.toLocaleString())}`);\r\n console.log(` ${chalk.dim(\"Total Cost\")} ${chalk.bold.green(\"$\" + stats.totalCost.toFixed(4))}`);\r\n console.log(` ${chalk.dim(\"Avg Latency\")} ${chalk.white(formatMs(stats.avgDuration))}`);\r\n console.log(\r\n ` ${chalk.dim(\"Error Rate\")} ${\r\n stats.errorRate > 0.05\r\n ? chalk.bold.red(errorPct + \"%\")\r\n : chalk.green(errorPct + \"%\")\r\n } ${chalk.dim(`(${stats.errorCount} errors)`)}`\r\n );\r\n\r\n // Top providers\r\n if (stats.byProvider.length > 0) {\r\n console.log(\"\");\r\n console.log(chalk.bold.white(\" Top Providers\"));\r\n console.log(chalk.dim(\" ─────────────────────────────────\"));\r\n for (const p of stats.byProvider.slice(0, 5)) {\r\n const bar = makeBar(p.totalCost, stats.totalCost, 20);\r\n console.log(\r\n ` ${chalk.cyan(p.provider.padEnd(12))} ${chalk.dim(String(p.spanCount).padStart(5) + \" calls\")} ${chalk.green(\"$\" + p.totalCost.toFixed(4).padStart(8))} ${chalk.dim(bar)}`\r\n );\r\n }\r\n }\r\n\r\n // Top models\r\n if (stats.byModel.length > 0) {\r\n console.log(\"\");\r\n console.log(chalk.bold.white(\" Top Models\"));\r\n console.log(chalk.dim(\" ─────────────────────────────────\"));\r\n for (const m of stats.byModel.slice(0, 8)) {\r\n const bar = makeBar(m.totalCost, stats.totalCost, 20);\r\n console.log(\r\n ` ${chalk.white(m.model.padEnd(28).slice(0, 28))} ${chalk.dim(String(m.spanCount).padStart(5) + \" calls\")} ${chalk.green(\"$\" + m.totalCost.toFixed(4).padStart(8))} ${chalk.dim(bar)}`\r\n );\r\n }\r\n }\r\n\r\n console.log(\"\");\r\n } catch (err) {\r\n if (err instanceof TypeError && (err as NodeJS.ErrnoException).cause) {\r\n console.error(chalk.red(\"Error: Cannot connect to collector\"));\r\n console.error(chalk.dim(\"Is the collector running? Try: npx llmtap start\"));\r\n } else {\r\n console.error(chalk.red(\"Error:\"), err instanceof Error ? err.message : err);\r\n }\r\n process.exit(1);\r\n }\r\n}\r\n\r\nfunction formatMs(ms: number): string {\r\n if (ms < 1000) return `${Math.round(ms)}ms`;\r\n return `${(ms / 1000).toFixed(2)}s`;\r\n}\r\n\r\nfunction makeBar(value: number, total: number, width: number): string {\r\n if (total <= 0) return \"\";\r\n const filled = Math.max(Math.round((value / total) * width), 1);\r\n return \"█\".repeat(filled) + \"░\".repeat(width - filled);\r\n}\r\n"],"mappings":"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","names":["chalk","fs","path","chalk","fs","path","chalk","fs","chalk","path","chalk","chalk","fs","path","chalk","resetDb","path","fs","chalk","resetDb","chalk","chalk","chalk","fs","path","chalk","getDbPath","chalk","path","fs","getDbPath","chalk"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "llmtap",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "DevTools for AI Agents - See every LLM call, trace agent workflows, track costs",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,8 +10,8 @@
10
10
  "dist"
11
11
  ],
12
12
  "dependencies": {
13
- "@llmtap/collector": "^0.1.3",
14
- "@llmtap/shared": "^0.1.3",
13
+ "@llmtap/collector": "^0.1.5",
14
+ "@llmtap/shared": "^0.1.5",
15
15
  "chalk": "^5.4.0",
16
16
  "commander": "^13.0.0",
17
17
  "open": "^10.1.0"
@@ -20,7 +20,8 @@
20
20
  "@types/node": "^25.4.0",
21
21
  "rimraf": "^6.0.0",
22
22
  "tsup": "^8.4.0",
23
- "typescript": "^5.7.0"
23
+ "typescript": "^5.7.0",
24
+ "vitest": "^3.0.0"
24
25
  },
25
26
  "keywords": [
26
27
  "llm",
@@ -47,6 +48,7 @@
47
48
  "scripts": {
48
49
  "prebuild": "node -e \"\"",
49
50
  "build": "tsup",
51
+ "test": "vitest run",
50
52
  "postbuild": "node -e \"const fs=require('fs');const path=require('path');const src=path.resolve(__dirname,'..','dashboard','dist');const dst=path.resolve(__dirname,'dist','dashboard');if(fs.existsSync(src)){fs.cpSync(src,dst,{recursive:true});console.log('Dashboard bundled into CLI dist')}else{console.log('Dashboard dist not found at',src)}\"",
51
53
  "clean": "rimraf dist"
52
54
  }
@@ -1 +0,0 @@
1
- import{r as j,d as y,j as e}from"./query-BSZkMKN4.js";import{a as w,f as C}from"./index-jVcSWGwX.js";import{L as k,y as T}from"./charts-BXAtT8sy.js";import{b as i,c as P,P as D}from"./format-CgXokIEM.js";import{D as S}from"./DataTable-CBsuKoTx.js";import{N as x}from"./number-ticker-C1hiu1bi.js";import{a as v}from"./provider-colors-DcHYMgVv.js";import{m as l}from"./motion-Bw6xJyTE.js";import{I as $,Z as L,$ as K,a0 as M,a1 as N,O as A,y as F,a2 as R}from"./icons-DhpK1vUv.js";const E=["emerald","sky","indigo","amber","orange","pink"],b={container:{transition:{staggerChildren:.08}},item:{hidden:{opacity:0,y:20,scale:.97},show:{opacity:1,y:0,scale:1,transition:{duration:.4,ease:[.22,1,.36,1]}}}};function h({label:r,value:o,sub:t,icon:n,gradient:a}){return e.jsxs(l.div,{variants:b.item,className:"metric-card",children:[e.jsx("div",{className:`metric-orb ${a}`,children:n}),e.jsxs("div",{children:[e.jsx("div",{className:"hud-label",children:r}),e.jsx("div",{className:"mt-1 text-3xl font-semibold tracking-[-0.04em] text-white",children:o}),t&&e.jsx("div",{className:"mt-2 text-sm text-slate-400",children:t})]})]})}function H(){const[r,o]=j.useState([{id:"totalCost",desc:!0}]),{data:t,isLoading:n}=y({queryKey:["stats"],queryFn:()=>C(24)}),a=t?.byModel??[],d=t?.byProvider??[],p=a.map(s=>({name:s.model.length>22?`${s.model.slice(0,20)}...`:s.model,cost:Number(s.totalCost.toFixed(6)),tokens:s.totalTokens,calls:s.spanCount})),c=d.map(s=>({name:s.provider,value:Number(s.totalCost.toFixed(6))})),f=j.useMemo(()=>[{accessorKey:"model",header:"Model",cell:({row:s})=>e.jsx("span",{className:"font-mono text-xs font-semibold text-slate-100",children:s.original.model})},{accessorKey:"provider",header:"Provider",cell:({row:s})=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"h-2.5 w-2.5 rounded-full",style:{backgroundColor:v[s.original.provider]??"#a855f6",boxShadow:`0 0 10px ${v[s.original.provider]??"#a855f6"}`}}),e.jsx("span",{className:"text-xs font-medium capitalize text-slate-200",children:s.original.provider})]})},{accessorKey:"spanCount",header:"Calls",cell:({row:s})=>e.jsx("span",{className:"inline-flex items-center justify-center rounded-md border border-white/8 bg-slate-950/70 px-2 py-0.5 font-mono text-xs text-slate-400",children:s.original.spanCount}),meta:{className:"text-right",cellClassName:"text-right"}},{accessorKey:"totalTokens",header:"Tokens",cell:({row:s})=>e.jsx("span",{className:"font-mono text-xs text-slate-300",children:s.original.totalTokens.toLocaleString()}),meta:{className:"text-right",cellClassName:"text-right"}},{accessorKey:"totalCost",header:"Cost",cell:({row:s})=>e.jsx("span",{className:"font-mono text-xs font-semibold text-white",children:i(s.original.totalCost)}),meta:{className:"text-right",cellClassName:"text-right"}},{accessorKey:"avgDuration",header:"Avg Duration",cell:({row:s})=>e.jsx("span",{className:"font-mono text-xs text-slate-500",children:s.original.avgDuration?P(s.original.avgDuration):"-"}),meta:{className:"text-right",cellClassName:"text-right"}}],[a]);return n?e.jsxs("div",{className:"mx-auto max-w-[1500px] space-y-8",children:[e.jsx("div",{className:"skeleton-panel h-44 rounded-[28px]"}),e.jsx("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-3",children:[...Array(3)].map((s,m)=>e.jsxs("div",{className:"metric-card",children:[e.jsx("div",{className:"skeleton-panel h-12 w-12 rounded-2xl"}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("div",{className:"skeleton-panel h-3 w-20 rounded-full"}),e.jsx("div",{className:"skeleton-panel h-8 w-28 rounded-full"})]})]},m))})]}):e.jsxs(D,{eyebrow:"Economic Layer",title:"Understand where every token is converting into spend.",description:"The economics view is now built like a cost cockpit. It surfaces burn concentration, provider mix, and the models that are consuming budget fastest.",aside:e.jsxs("div",{className:"insight-panel",children:[e.jsx(w,{}),e.jsxs("div",{className:"mt-4 space-y-3",children:[e.jsxs("div",{className:"rounded-2xl border border-white/8 bg-white/4 p-4",children:[e.jsx("div",{className:"hud-label",children:"Highest model spend"}),e.jsx("div",{className:"mt-2 text-base font-medium text-white",children:a[0]?.model??"Awaiting traffic"}),e.jsx("div",{className:"mt-1 text-sm text-slate-400",children:a[0]?`${i(a[0].totalCost)} across ${a[0].spanCount} calls`:"No model cost data yet"})]}),e.jsxs("div",{className:"rounded-2xl border border-white/8 bg-white/4 p-4",children:[e.jsx("div",{className:"hud-label",children:"Provider spread"}),e.jsxs("div",{className:"mt-2 text-base font-medium text-white",children:[d.length," active providers"]}),e.jsx("div",{className:"mt-1 text-sm text-slate-400",children:"Cost dominance becomes obvious here before it becomes expensive."})]})]})]}),children:[e.jsxs(l.div,{className:"grid grid-cols-1 gap-4 md:grid-cols-3",variants:b.container,initial:"hidden",animate:"show",children:[e.jsx(h,{icon:e.jsx($,{className:"h-5 w-5"}),label:"Total Cost",value:e.jsx(x,{value:t?.totalCost??0,decimalPlaces:t&&(t.totalCost??0)<.01?4:2,prefix:"$"}),sub:"Accumulated over the last 24 hours",gradient:"bg-[linear-gradient(135deg,rgba(250,204,21,0.18),rgba(249,115,22,0.18))] text-amber-200"}),e.jsx(h,{icon:e.jsx(L,{className:"h-5 w-5"}),label:"Token Volume",value:e.jsx(x,{value:t?.totalTokens??0}),sub:`${t?.totalSpans??0} model calls observed`,gradient:"bg-[linear-gradient(135deg,rgba(56,189,248,0.18),rgba(168,85,247,0.18))] text-sky-200"}),e.jsx(h,{icon:e.jsx(K,{className:"h-5 w-5"}),label:"Models in Rotation",value:e.jsx(x,{value:a.length}),sub:`${d.length} providers contributing to spend`,gradient:"bg-[linear-gradient(135deg,rgba(52,211,153,0.18),rgba(14,165,233,0.18))] text-emerald-200"})]}),e.jsxs("div",{className:"grid gap-5 xl:grid-cols-[minmax(0,1.1fr)_minmax(360px,0.9fr)]",children:[e.jsxs(l.div,{className:"dashboard-shell rounded-[26px] px-5 py-5",initial:{opacity:0,y:16},animate:{opacity:1,y:0},transition:{delay:.15,duration:.35},children:[e.jsxs("div",{className:"mb-5 flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("div",{className:"hud-label",children:"Model ranking"}),e.jsx("h2",{className:"mt-1 text-xl font-semibold tracking-[-0.04em] text-white",children:"Cost by model"})]}),e.jsxs("span",{className:"status-chip",children:[e.jsx(M,{className:"h-3.5 w-3.5 text-sky-300"}),e.jsx("span",{children:"Spend concentration"})]})]}),p.length>0?e.jsx(k,{data:p,index:"name",categories:["cost"],colors:["emerald"],layout:"vertical",valueFormatter:i,showAnimation:!0,showLegend:!1,showGridLines:!1,className:"min-h-[320px]"}):e.jsxs("div",{className:"empty-state h-[320px]",children:[e.jsx(N,{className:"h-8 w-8 text-slate-500"}),e.jsx("div",{className:"text-base font-medium text-white",children:"No cost data yet"}),e.jsx("div",{className:"text-center text-sm text-slate-400",children:"Model spend will stack up here as soon as traffic hits the collector."})]})]}),e.jsxs(l.div,{className:"dashboard-shell rounded-[26px] px-5 py-5",initial:{opacity:0,y:16},animate:{opacity:1,y:0},transition:{delay:.2,duration:.35},children:[e.jsxs("div",{className:"mb-5 flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("div",{className:"hud-label",children:"Provider mix"}),e.jsx("h2",{className:"mt-1 text-xl font-semibold tracking-[-0.04em] text-white",children:"Who is taking the budget"})]}),e.jsx(A,{className:"h-4 w-4 text-sky-300"})]}),c.length>0?e.jsxs("div",{className:"flex flex-col gap-6 lg:flex-row lg:items-center",children:[e.jsx(T,{data:c,category:"value",index:"name",colors:[...E],valueFormatter:i,showAnimation:!0,showLabel:!1,className:"h-[260px] lg:max-w-[260px]"}),e.jsx("div",{className:"flex-1 space-y-3",children:c.map((s,m)=>{const u=["#34d399","#38bdf8","#818cf8","#f59e0b","#f97316","#f472b6"],g=u[m%u.length];return e.jsx("div",{className:"rounded-2xl border border-white/6 bg-white/4 p-3.5",children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"h-3 w-3 shrink-0 rounded-sm",style:{backgroundColor:g,boxShadow:`0 0 10px ${g}50`}}),e.jsx("span",{className:"flex-1 text-sm font-medium capitalize text-white",children:s.name}),e.jsx("span",{className:"font-mono text-xs text-slate-400",children:i(s.value)})]})},s.name)})})]}):e.jsxs("div",{className:"empty-state h-[260px]",children:[e.jsx(F,{className:"h-8 w-8 text-slate-500"}),e.jsx("div",{className:"text-base font-medium text-white",children:"No providers yet"}),e.jsx("div",{className:"text-center text-sm text-slate-400",children:"Provider allocation appears here as soon as at least one model call is captured."})]})]})]}),a.length>0?e.jsxs(l.div,{className:"dashboard-shell overflow-hidden rounded-[26px] px-4 py-4 sm:px-5",initial:{opacity:0,y:16},animate:{opacity:1,y:0},transition:{delay:.25,duration:.35},children:[e.jsxs("div",{className:"mb-3 flex items-center justify-between gap-3 px-1",children:[e.jsxs("div",{children:[e.jsx("div",{className:"hud-label",children:"Detailed ledger"}),e.jsx("h2",{className:"mt-1 text-xl font-semibold tracking-[-0.04em] text-white",children:"Breakdown by model"})]}),e.jsxs("span",{className:"status-chip",children:[e.jsx(R,{className:"h-3.5 w-3.5 text-sky-300"}),e.jsxs("span",{children:[a.length," models"]})]})]}),e.jsx(S,{columns:f,data:a,sorting:r,onSortingChange:o})]}):e.jsx(l.div,{className:"dashboard-shell rounded-[26px] p-16",initial:{opacity:0},animate:{opacity:1},children:e.jsxs("div",{className:"empty-state",children:[e.jsx(N,{className:"h-8 w-8 text-slate-500"}),e.jsx("div",{className:"text-base font-medium text-white",children:"No cost data yet"}),e.jsx("div",{className:"max-w-sm text-center text-sm text-slate-400",children:"Start making traced model calls and the economic layer will fill in automatically."})]})})]})}export{H as default};
@@ -1,9 +0,0 @@
1
- import{r as o,j as e,d as O}from"./query-BSZkMKN4.js";import{c as ce,u as de,L as oe,a as xe,f as me,b as he,d as pe}from"./index-jVcSWGwX.js";import{N as ue}from"./charts-BXAtT8sy.js";import{f as je,P as ge,a as U,b as S,c as E,d as X}from"./format-CgXokIEM.js";import{S as fe}from"./StatusDot-BAf4TSfE.js";import{S as T,a as P,b as A,c as $,d as p,B}from"./select-CbYE6Q0M.js";import{N as R}from"./number-ticker-C1hiu1bi.js";import{P as Q}from"./constants-OlSc-7iA.js";import{R as ve,C as Ne,k as D,l as W,G as be,X as we,S as ye,A as Y,m as Se,n as ke,o as Ce,p as Z,q as _e,T as J,r as Te,j as Pe,O as Ae}from"./icons-DhpK1vUv.js";import{m as $e}from"./motion-Bw6xJyTE.js";function De({children:a,className:N,spotlightColor:x="rgba(52, 211, 153, 0.15)"}){const n=o.useRef(null),[l,b]=o.useState({x:0,y:0}),[u,j]=o.useState(0);function k(c){if(!n.current)return;const r=n.current.getBoundingClientRect();b({x:c.clientX-r.left,y:c.clientY-r.top})}return e.jsxs("div",{ref:n,onMouseMove:k,onMouseEnter:()=>j(1),onMouseLeave:()=>j(0),className:ce("relative overflow-hidden",N),children:[e.jsx("div",{className:"pointer-events-none absolute -inset-px opacity-0 transition-opacity duration-300",style:{opacity:u,background:`radial-gradient(600px circle at ${l.x}px ${l.y}px, ${x}, transparent 40%)`}}),a]})}const ee=[12,25,50,100];function I({label:a,value:N,detail:x,accent:n,icon:l}){return e.jsxs(De,{className:"metric-card",children:[e.jsx("div",{className:`metric-orb ${n}`,children:l}),e.jsxs("div",{children:[e.jsx("div",{className:"hud-label",children:a}),e.jsx("div",{className:"mt-1 text-3xl font-semibold tracking-[-0.04em] text-white",children:N}),e.jsx("div",{className:"mt-1 text-sm text-slate-400",children:x})]})]})}function ze(){const[a,N]=de(),x=a.get("q")??"",n=o.useDeferredValue(x),l=a.get("provider")??"",b=a.get("status"),u=b==="ok"||b==="error"?b:"",j=Number(a.get("periodHours")??"24"),k=Number(a.get("pageSize")??"12"),c=ee.includes(k)?k:12,r=Math.max(1,Number(a.get("page")??"1")||1),C=(r-1)*c,m=o.useMemo(()=>({limit:c,offset:C,q:n.trim()||void 0,provider:l||void 0,status:u||void 0,periodHours:Q.some(s=>s.value===j)?j:24}),[n,c,C,j,l,u]),{data:t}=O({queryKey:["stats",m.periodHours],queryFn:()=>me(m.periodHours??24)}),{data:H,isLoading:se}=O({queryKey:["traces",m],queryFn:()=>he(m)}),{data:te}=O({queryKey:["insights"],queryFn:pe,refetchInterval:6e4}),F=te?.insights??[],q=H?.traces??[],w=H?.total??0,ae=Math.max(1,Math.ceil(w/c)),[g,le]=o.useState(null),[L,G]=o.useState("desc");function re(s){g===s?G(i=>i==="asc"?"desc":"asc"):(le(s),G("desc"))}const y=o.useMemo(()=>g?[...q].sort((s,i)=>{const _=s[g]??0,h=i[g]??0;return L==="asc"?_-h:h-_}):q,[q,g,L]),f=t?.byProvider[0],v=y[0],ie=[...new Set(t?.byProvider.map(s=>s.provider)??[])],V=t?.costOverTime.map(s=>({time:je(s.timestamp),cost:s.cost}))??[],ne=t&&t.totalSpans>0?t.totalCost/t.totalSpans:0,z=x.length>0||l.length>0||u.length>0||m.periodHours!==24;function d(s,i=!0){N(_=>{const h=new URLSearchParams(_);for(const[K,M]of Object.entries(s))M===void 0||M===""?h.delete(K):h.set(K,String(M));return i&&h.delete("page"),h},{replace:!0})}return e.jsxs(ge,{eyebrow:"Flight Deck",title:"Read the behavior of every model call like a live system.",description:"The dashboard should act like an operator console. This version adds a real trace search surface, URL-synced filters, and paginated queue control.",aside:e.jsxs("div",{className:"insight-panel",children:[e.jsx(xe,{}),e.jsxs("div",{className:"mt-4 grid gap-3",children:[e.jsxs("div",{className:"surface-strong rounded-2xl p-4",children:[e.jsx("div",{className:"hud-label",children:"Dominant provider"}),e.jsxs("div",{className:"mt-2 flex items-center justify-between",children:[e.jsx("div",{className:"text-lg font-medium capitalize text-white",children:f?.provider??"Awaiting traffic"}),e.jsx(Ae,{className:"h-4 w-4 text-sky-300"})]}),e.jsx("div",{className:"mt-1 text-sm text-slate-400",children:f?`${f.spanCount} calls, ${S(f.totalCost)} spend`:"No provider activity yet"})]}),e.jsxs("div",{className:"surface-strong rounded-2xl p-4",children:[e.jsx("div",{className:"hud-label",children:"Latest trace"}),e.jsx("div",{className:"mt-2 text-base font-medium text-white",children:v?.name??"No recent traces"}),e.jsx("div",{className:"mt-1 text-sm text-slate-400",children:v?`${X(v.startTime)} / ${v.spanCount} spans`:"Start sending spans to populate the deck"})]})]})]}),children:[e.jsxs("div",{className:"grid gap-4 md:grid-cols-2 xl:grid-cols-4",children:[e.jsx(I,{label:"Trace Volume",value:e.jsx(R,{value:t?.totalTraces??0,className:"tabular-nums"}),detail:`${t?.totalSpans??0} spans in window`,icon:e.jsx(ve,{className:"h-5 w-5"}),accent:"bg-[linear-gradient(135deg,rgba(52,211,153,0.18),rgba(14,165,233,0.18))] text-emerald-200"}),e.jsx(I,{label:"Token Throughput",value:U(t?.totalTokens??0),detail:"Token load across the active filter window",icon:e.jsx(Ne,{className:"h-5 w-5"}),accent:"bg-[linear-gradient(135deg,rgba(56,189,248,0.18),rgba(168,85,247,0.18))] text-sky-200"}),e.jsx(I,{label:"Spend Velocity",value:e.jsx(R,{value:t?.totalCost??0,decimalPlaces:t&&t.totalCost<.01?4:2,prefix:"$",className:"tabular-nums"}),detail:`${S(ne)} average cost per call`,icon:e.jsx(D,{className:"h-5 w-5"}),accent:"bg-[linear-gradient(135deg,rgba(251,191,36,0.18),rgba(249,115,22,0.18))] text-amber-200"}),e.jsx(I,{label:"Risk Surface",value:e.jsx(R,{value:Math.round((t?.errorRate??0)*100),suffix:"%",className:"tabular-nums"}),detail:`${t?.errorCount??0} failing calls`,icon:e.jsx(W,{className:"h-5 w-5"}),accent:"bg-[linear-gradient(135deg,rgba(244,63,94,0.18),rgba(168,85,247,0.18))] text-rose-200"})]}),e.jsxs("div",{className:"grid gap-5 xl:grid-cols-[minmax(0,1.5fr)_minmax(320px,0.95fr)]",children:[e.jsxs("section",{className:"dashboard-shell rounded-[26px] px-5 py-5 sm:px-6",children:[e.jsxs("div",{className:"mb-5 flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("div",{className:"hud-label",children:"Economic pulse"}),e.jsx("h2",{className:"mt-1 text-xl font-semibold tracking-[-0.04em] text-white",children:"Cost gradient"})]}),e.jsxs("div",{className:"status-chip",children:[e.jsx(be,{className:"h-3.5 w-3.5 text-sky-300"}),e.jsxs("span",{children:[m.periodHours,"h window"]})]})]}),V.length>0?e.jsx(ue,{data:V,index:"time",categories:["cost"],colors:["emerald"],valueFormatter:S,showAnimation:!0,showLegend:!1,showGridLines:!1,className:"h-80",curveType:"monotone"}):e.jsxs("div",{className:"empty-state h-[320px]",children:[e.jsx(D,{className:"h-8 w-8 text-slate-500"}),e.jsx("div",{className:"text-base font-medium text-white",children:"No cost movement yet"})]})]}),e.jsxs("section",{className:"dashboard-shell rounded-[26px] px-5 py-5 sm:px-6",children:[e.jsxs("div",{className:"mb-5",children:[e.jsx("div",{className:"hud-label",children:"Provider pressure"}),e.jsx("h2",{className:"mt-1 text-xl font-semibold tracking-[-0.04em] text-white",children:"Allocation by provider"})]}),e.jsx("div",{className:"space-y-4",children:(t?.byProvider??[]).map(s=>{const i=(t?.totalCost??0)>0?s.totalCost/(t?.totalCost??1)*100:0;return e.jsxs("div",{className:"surface-muted rounded-2xl p-4",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium capitalize text-white",children:s.provider}),e.jsxs("div",{className:"text-xs text-slate-400",children:[s.spanCount," calls / ",U(s.totalTokens)," tokens"]})]}),e.jsxs("div",{className:"text-right",children:[e.jsx("div",{className:"text-sm font-medium text-white",children:S(s.totalCost)}),e.jsx("div",{className:"text-xs text-slate-500",children:E(s.avgDuration)})]})]}),e.jsx("div",{className:"mt-3 h-2 overflow-hidden rounded-full bg-slate-900/80",children:e.jsx($e.div,{className:"h-full w-full origin-left rounded-full bg-[linear-gradient(90deg,#34d399,#38bdf8)]",initial:{scaleX:0},animate:{scaleX:Math.max(i,4)/100},transition:{duration:.5,ease:"easeOut"}})})]},s.provider)})})]})]}),e.jsxs("div",{className:"grid gap-5 xl:grid-cols-[minmax(0,1.45fr)_minmax(320px,0.85fr)]",children:[e.jsxs("section",{className:"dashboard-shell rounded-[26px] px-4 py-4 sm:px-5 sm:py-5",children:[e.jsxs("div",{className:"surface-strong mb-4 rounded-[24px] p-4",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"hud-label",children:"Search console"}),e.jsx("h2",{className:"mt-1 text-xl font-semibold tracking-[-0.04em] text-white",children:"Trace dispatch queue"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("span",{className:"status-chip",children:[w," matches"]}),e.jsxs("button",{type:"button",onClick:()=>d({q:void 0,provider:void 0,status:void 0,periodHours:void 0}),disabled:!z,className:"status-chip transition-colors hover:border-white/16 hover:bg-white/8 disabled:cursor-not-allowed disabled:opacity-50",children:[e.jsx(we,{className:"h-3.5 w-3.5"}),e.jsx("span",{children:"Clear"})]})]})]}),e.jsxs("div",{className:"mt-4 grid gap-3 xl:grid-cols-[minmax(0,1.7fr)_repeat(3,minmax(0,0.7fr))]",children:[e.jsxs("label",{className:"field-surface relative block rounded-2xl",children:[e.jsx(ye,{className:"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-500"}),e.jsx("input",{value:x,onChange:s=>d({q:s.target.value||void 0}),placeholder:"Search traces, models, providers, errors",className:"w-full rounded-2xl bg-transparent py-3 pl-10 pr-4 text-sm text-white placeholder:text-slate-500 focus:outline-none"})]}),e.jsxs(T,{value:l||"__all__",onValueChange:s=>d({provider:s==="__all__"?void 0:s}),children:[e.jsx(P,{className:"w-full rounded-2xl py-3",children:e.jsx(A,{placeholder:"All providers"})}),e.jsxs($,{children:[e.jsx(p,{value:"__all__",children:"All providers"}),ie.map(s=>e.jsx(p,{value:s,children:s},s))]})]}),e.jsxs(T,{value:u||"__all__",onValueChange:s=>d({status:s==="__all__"?void 0:s}),children:[e.jsx(P,{className:"w-full rounded-2xl py-3",children:e.jsx(A,{placeholder:"All states"})}),e.jsxs($,{children:[e.jsx(p,{value:"__all__",children:"All states"}),e.jsx(p,{value:"ok",children:"Healthy only"}),e.jsx(p,{value:"error",children:"Errors only"})]})]}),e.jsxs(T,{value:String(m.periodHours??24),onValueChange:s=>d({periodHours:Number(s)===24?void 0:Number(s)}),children:[e.jsx(P,{className:"w-full rounded-2xl py-3",children:e.jsx(A,{})}),e.jsx($,{children:Q.map(s=>e.jsx(p,{value:String(s.value),children:s.label},s.value))})]})]})]}),se?e.jsx("div",{className:"empty-state h-[280px] text-slate-500",children:"Loading trace queue..."}):y.length===0&&!z?e.jsxs("div",{className:"surface-strong rounded-2xl p-6 sm:p-8",children:[e.jsxs("div",{className:"flex flex-col items-center gap-3 text-center",children:[e.jsx(Y,{className:"h-10 w-10 text-amber-400/60"}),e.jsxs("div",{children:[e.jsx("div",{className:"text-lg font-semibold text-white",children:"No traces recorded yet"}),e.jsx("p",{className:"mt-1 text-sm text-slate-400",children:"Get started in 3 steps — takes under a minute."})]})]}),e.jsxs("div",{className:"mx-auto mt-6 flex max-w-3xl flex-col gap-4",children:[e.jsxs("div",{className:"surface-muted rounded-xl p-4",children:[e.jsxs("div",{className:"mb-2 flex items-center gap-2",children:[e.jsx("span",{className:"flex h-5 w-5 items-center justify-center rounded-full bg-amber-400/20 text-[10px] font-bold text-amber-400",children:"1"}),e.jsx("span",{className:"text-xs font-semibold uppercase tracking-wider text-amber-400",children:"Install the SDK"})]}),e.jsx("pre",{className:"overflow-x-auto rounded-lg bg-black/40 p-3 text-sm leading-relaxed text-green-400 select-all",children:"npm install @llmtap/sdk"})]}),e.jsxs("div",{className:"surface-muted rounded-xl p-4",children:[e.jsxs("div",{className:"mb-2 flex items-center gap-2",children:[e.jsx("span",{className:"flex h-5 w-5 items-center justify-center rounded-full bg-amber-400/20 text-[10px] font-bold text-amber-400",children:"2"}),e.jsx("span",{className:"text-xs font-semibold uppercase tracking-wider text-amber-400",children:"Wrap your client & use normally"})]}),e.jsx("pre",{className:"overflow-x-auto rounded-lg bg-black/40 p-3 text-sm leading-relaxed text-green-400 select-all whitespace-pre",children:`import { wrap } from "@llmtap/sdk";
2
- import OpenAI from "openai";
3
-
4
- const client = wrap(new OpenAI());
5
-
6
- const res = await client.chat.completions.create({
7
- model: "gpt-4o-mini",
8
- messages: [{ role: "user", content: "Hello!" }],
9
- });`})]}),e.jsxs("div",{className:"surface-muted rounded-xl p-4",children:[e.jsxs("div",{className:"mb-2 flex items-center gap-2",children:[e.jsx("span",{className:"flex h-5 w-5 items-center justify-center rounded-full bg-amber-400/20 text-[10px] font-bold text-amber-400",children:"3"}),e.jsx("span",{className:"text-xs font-semibold uppercase tracking-wider text-amber-400",children:"Start the collector"})]}),e.jsx("pre",{className:"overflow-x-auto rounded-lg bg-black/40 p-3 text-sm leading-relaxed text-green-400 select-all",children:"npx llmtap"}),e.jsx("p",{className:"mt-2 text-xs text-slate-500",children:"Run your app and traces will appear here automatically."})]})]}),e.jsx("div",{className:"surface-muted mx-auto mt-4 max-w-3xl rounded-lg px-4 py-2.5",children:e.jsxs("p",{className:"text-center text-xs text-slate-500",children:["Works with ",e.jsx("span",{className:"text-slate-400",children:"OpenAI"}),", ",e.jsx("span",{className:"text-slate-400",children:"Anthropic"}),", ",e.jsx("span",{className:"text-slate-400",children:"Google Gemini"}),", ",e.jsx("span",{className:"text-slate-400",children:"DeepSeek"}),", ",e.jsx("span",{className:"text-slate-400",children:"Groq"}),", ",e.jsx("span",{className:"text-slate-400",children:"Together"}),", ",e.jsx("span",{className:"text-slate-400",children:"Fireworks"}),", ",e.jsx("span",{className:"text-slate-400",children:"OpenRouter"}),", and any OpenAI-compatible provider."]})})]}):y.length===0?e.jsxs("div",{className:"empty-state h-[280px]",children:[e.jsx(Y,{className:"h-8 w-8 text-slate-500"}),e.jsx("div",{className:"text-base font-medium text-white",children:"No traces match these filters"})]}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full border-separate border-spacing-y-2 text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-left text-[11px] uppercase tracking-[0.18em] text-slate-500",children:[e.jsx("th",{className:"px-4 py-2",children:"State"}),e.jsx("th",{className:"px-4 py-2",children:"Trace"}),[["spanCount","Spans"],["totalTokens","Tokens"],["totalCost","Cost"],["startTime","When"]].map(([s,i])=>e.jsx("th",{className:"px-4 py-2 text-right",children:e.jsxs("button",{type:"button",onClick:()=>re(s),className:"inline-flex items-center gap-1 transition-colors hover:text-slate-300",children:[i,g===s?L==="asc"?e.jsx(Se,{className:"h-3 w-3"}):e.jsx(ke,{className:"h-3 w-3"}):e.jsx(Ce,{className:"h-3 w-3 opacity-30"})]})},s))]})}),e.jsx("tbody",{children:y.map(s=>e.jsxs("tr",{className:"table-row-surface rounded-2xl",children:[e.jsx("td",{className:"rounded-l-2xl px-4 py-4",children:e.jsx(fe,{status:s.status})}),e.jsx("td",{className:"px-4 py-4",children:e.jsxs(oe,{to:`/trace/${s.traceId}`,className:"group inline-flex max-w-[380px] flex-col gap-1 text-sm font-medium text-white transition-colors hover:text-emerald-300",children:[e.jsxs("span",{className:"inline-flex items-center gap-2",children:[e.jsx("span",{className:"truncate",children:s.name}),e.jsx(Z,{className:"h-3.5 w-3.5 opacity-0 transition-all group-hover:translate-x-0.5 group-hover:opacity-100"})]}),e.jsxs("span",{className:"font-mono text-[10px] uppercase tracking-[0.16em] text-slate-500",children:[s.traceId.slice(0,12),s.totalDuration?` / ${E(s.totalDuration)}`:""]})]})}),e.jsx("td",{className:"px-4 py-4 text-right font-mono text-xs text-slate-300",children:s.spanCount}),e.jsx("td",{className:"px-4 py-4 text-right font-mono text-xs text-slate-300",children:s.totalTokens.toLocaleString()}),e.jsx("td",{className:"px-4 py-4 text-right font-mono text-xs text-slate-300",children:S(s.totalCost)}),e.jsx("td",{className:"rounded-r-2xl px-4 py-4 text-right text-xs text-slate-500",children:X(s.startTime)})]},s.traceId))})]})}),e.jsxs("div",{className:"mt-4 flex items-center justify-between gap-3 px-1",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"text-xs text-slate-500",children:w>0?`Showing ${C+1}-${Math.min(C+y.length,w)} of ${w}`:"Awaiting traces"}),e.jsxs(T,{value:String(c),onValueChange:s=>d({pageSize:Number(s)===12?void 0:Number(s)}),children:[e.jsx(P,{className:"w-auto rounded-xl px-2 py-1.5 text-xs",children:e.jsx(A,{})}),e.jsx($,{children:ee.map(s=>e.jsxs(p,{value:String(s),children:[s," / page"]},s))})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(B,{variant:"outline",size:"sm",onClick:()=>d({page:r>2?r-1:void 0},!1),disabled:r<=1,children:[e.jsx(_e,{className:"h-3.5 w-3.5"}),e.jsx("span",{children:"Previous"})]}),e.jsxs(B,{variant:"outline",size:"sm",onClick:()=>d({page:r+1},!1),disabled:r>=ae,children:[e.jsx("span",{children:"Next"}),e.jsx(Z,{className:"h-3.5 w-3.5"})]})]})]})]})]}),e.jsxs("section",{className:"dashboard-shell rounded-[26px] px-5 py-5",children:[e.jsxs("div",{className:"mb-5",children:[e.jsx("div",{className:"hud-label",children:"Intelligence layer"}),e.jsx("h2",{className:"mt-1 text-xl font-semibold tracking-[-0.04em] text-white",children:"Insights"})]}),e.jsx("div",{className:"space-y-4",children:F.length>0?F.map(s=>e.jsxs("div",{className:`rounded-2xl border p-4 ${s.severity==="critical"?"border-rose-400/20 bg-rose-500/8":s.severity==="warning"?"border-amber-400/20 bg-amber-500/8":"border-white/6 bg-white/4"}`,children:[e.jsxs("div",{className:"mb-2 flex items-center justify-between gap-2",children:[e.jsxs("div",{className:"flex items-center gap-2 text-sm font-medium text-white",children:[s.type==="cost_anomaly"&&e.jsx(J,{className:"h-4 w-4 text-amber-300"}),s.type==="error_pattern"&&e.jsx(W,{className:"h-4 w-4 text-rose-300"}),s.type==="model_recommendation"&&e.jsx(Te,{className:"h-4 w-4 text-sky-300"}),s.type==="token_waste"&&e.jsx(D,{className:"h-4 w-4 text-purple-300"}),s.title]}),s.metric&&e.jsx("span",{className:"shrink-0 rounded-full border border-white/10 bg-white/6 px-2 py-0.5 text-[10px] font-mono text-slate-400",children:s.metric})]}),e.jsx("p",{className:"text-sm leading-6 text-slate-400",children:s.description})]},s.id)):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"surface-muted rounded-2xl p-4",children:[e.jsxs("div",{className:"mb-2 flex items-center gap-2 text-sm font-medium text-white",children:[e.jsx(Pe,{className:"h-4 w-4 text-sky-300"}),"Health read"]}),e.jsx("p",{className:"text-sm leading-6 text-slate-400",children:(t?.errorRate??0)>.05?"Error rate is elevated. Start with the most recent failed trace and inspect provider or tool payloads.":"Error pressure is currently low. Use this window to compare provider cost drift and latency patterns."})]}),e.jsxs("div",{className:"surface-muted rounded-2xl p-4",children:[e.jsxs("div",{className:"mb-2 flex items-center gap-2 text-sm font-medium text-white",children:[e.jsx(D,{className:"h-4 w-4 text-emerald-300"}),"Spend insight"]}),e.jsx("p",{className:"text-sm leading-6 text-slate-400",children:f?`${f.provider} currently leads cost share. If that is unexpected, inspect the filtered queue for bursty workflows.`:"Provider concentration will appear here once traces land."})]}),e.jsxs("div",{className:"surface-muted rounded-2xl p-4",children:[e.jsxs("div",{className:"mb-2 flex items-center gap-2 text-sm font-medium text-white",children:[e.jsx(J,{className:"h-4 w-4 text-amber-300"}),"Queue focus"]}),e.jsx("p",{className:"text-sm leading-6 text-slate-400",children:v?`Latest traffic is "${v.name}". Open it to inspect hierarchy, timing, and payload shape.`:"No active traces yet. Generate a request through an instrumented client to validate the pipeline."})]})]})})]})]})]})}export{ze as default};
@@ -1 +0,0 @@
1
- import{r as n,j as e,e as y,f as d,h as v,i as T}from"./query-BSZkMKN4.js";import{c as s}from"./index-jVcSWGwX.js";import{a4 as R,a5 as D,o as C}from"./icons-DhpK1vUv.js";const u=n.forwardRef(({className:l,...t},o)=>e.jsx("div",{className:"relative w-full overflow-auto",children:e.jsx("table",{ref:o,className:s("w-full caption-bottom text-sm",l),...t})}));u.displayName="Table";const f=n.forwardRef(({className:l,...t},o)=>e.jsx("thead",{ref:o,className:s("[&_tr]:border-b [&_tr]:border-white/6",l),...t}));f.displayName="TableHeader";const g=n.forwardRef(({className:l,...t},o)=>e.jsx("tbody",{ref:o,className:s("[&_tr:last-child]:border-0",l),...t}));g.displayName="TableBody";const k=n.forwardRef(({className:l,...t},o)=>e.jsx("tfoot",{ref:o,className:s("border-t border-white/6 bg-white/3 font-medium [&>tr]:last:border-b-0",l),...t}));k.displayName="TableFooter";const b=n.forwardRef(({className:l,...t},o)=>e.jsx("tr",{ref:o,className:s("border-b border-white/5 transition-colors hover:bg-white/[0.03] data-[state=selected]:bg-emerald-500/[0.06]",l),...t}));b.displayName="TableRow";const h=n.forwardRef(({className:l,...t},o)=>e.jsx("th",{ref:o,className:s("h-10 px-3 text-left align-middle text-xs font-semibold uppercase tracking-wider text-slate-500 [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",l),...t}));h.displayName="TableHead";const w=n.forwardRef(({className:l,...t},o)=>e.jsx("td",{ref:o,className:s("px-3 py-3 align-middle text-slate-300 [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",l),...t}));w.displayName="TableCell";const S=n.forwardRef(({className:l,...t},o)=>e.jsx("caption",{ref:o,className:s("mt-4 text-sm text-slate-500",l),...t}));S.displayName="TableCaption";function A({columns:l,data:t,sorting:o,onSortingChange:N,emptyState:j,rowClassName:i,onRowClick:m}){const x=y({data:t,columns:l,state:o?{sorting:o}:void 0,onSortingChange:N,getCoreRowModel:T(),getSortedRowModel:v(),manualPagination:!0});return t.length===0?j??e.jsx("div",{className:"empty-state h-[260px] text-slate-500",children:"No rows available."}):e.jsx("div",{className:"overflow-hidden rounded-[24px] border border-white/6 bg-[linear-gradient(180deg,rgba(8,13,24,0.88),rgba(4,8,18,0.96))]",children:e.jsxs(u,{className:"min-w-full",children:[e.jsx(f,{className:"sticky top-0 z-10 bg-[rgba(5,9,18,0.92)] backdrop-blur-xl",children:x.getHeaderGroups().map(r=>e.jsx(b,{className:"hover:bg-transparent",children:r.headers.map(a=>{const c=a.column.getCanSort(),p=a.column.getIsSorted();return e.jsx(h,{className:s("h-12 whitespace-nowrap px-4 text-[10px] tracking-[0.24em] text-slate-500",a.column.columnDef.meta&&typeof a.column.columnDef.meta=="object"&&"className"in a.column.columnDef.meta?String(a.column.columnDef.meta.className):void 0),children:a.isPlaceholder?null:c?e.jsxs("button",{type:"button",onClick:a.column.getToggleSortingHandler(),className:"inline-flex items-center gap-1.5 transition-colors hover:text-slate-200",children:[d(a.column.columnDef.header,a.getContext()),p==="asc"?e.jsx(R,{className:"h-3 w-3"}):p==="desc"?e.jsx(D,{className:"h-3 w-3"}):e.jsx(C,{className:"h-3 w-3 opacity-35"})]}):d(a.column.columnDef.header,a.getContext())},a.id)})},r.id))}),e.jsx(g,{children:x.getRowModel().rows.map(r=>e.jsx(b,{onClick:m?()=>m(r):void 0,className:s("group border-white/0 bg-transparent hover:bg-transparent",m?"cursor-pointer":void 0,typeof i=="function"?i(r):i),children:r.getVisibleCells().map((a,c)=>e.jsx(w,{className:s("table-row-surface px-4 py-4 transition-all duration-200 group-hover:border-white/12 group-hover:shadow-[0_18px_40px_rgba(0,0,0,0.16)]",c===0?"rounded-l-2xl":void 0,c===r.getVisibleCells().length-1?"rounded-r-2xl":void 0,a.column.columnDef.meta&&typeof a.column.columnDef.meta=="object"&&"cellClassName"in a.column.columnDef.meta?String(a.column.columnDef.meta.cellClassName):void 0),children:d(a.column.columnDef.cell,a.getContext())},a.id))},r.id))})]})})}export{A as D};
@@ -1 +0,0 @@
1
- import{r as m,d as v,j as e}from"./query-BSZkMKN4.js";import{a as N,f as j}from"./index-jVcSWGwX.js";import{D as y}from"./DataTable-CBsuKoTx.js";import{a as x,b as o,c as h,P as b}from"./format-CgXokIEM.js";import{N as f}from"./number-ticker-C1hiu1bi.js";import{a as p}from"./provider-colors-DcHYMgVv.js";import{m as l}from"./motion-Bw6xJyTE.js";import{y as C,x as w,C as k,G as M}from"./icons-DhpK1vUv.js";import"./charts-BXAtT8sy.js";function u({rows:t,valueFormatter:i,barClassName:n}){const r=Math.max(...t.map(s=>s.value),1);return e.jsx("div",{className:"space-y-3",children:t.map(s=>e.jsxs("div",{className:"rounded-2xl border border-white/6 bg-[linear-gradient(180deg,rgba(10,16,28,0.9),rgba(5,10,20,0.94))] p-4",children:[e.jsxs("div",{className:"flex items-center justify-between gap-4",children:[e.jsx("span",{className:"truncate text-sm font-medium text-slate-200",children:s.name}),e.jsx("span",{className:"font-mono text-xs text-slate-400",children:i(s.value)})]}),e.jsx("div",{className:"mt-3 h-2.5 overflow-hidden rounded-full bg-slate-950/80",children:e.jsx(l.div,{className:`h-full rounded-full ${n}`,initial:{width:0},animate:{width:`${Math.max(s.value/r*100,6)}%`},transition:{duration:.45,ease:"easeOut"}})})]},s.name))})}function E(){const[t,i]=m.useState([{id:"totalCost",desc:!0}]),{data:n,isLoading:r}=v({queryKey:["stats",168],queryFn:()=>j(168)}),s=n?.byModel??[],d=s.map(a=>({name:a.model.length>20?`${a.model.slice(0,18)}...`:a.model,value:a.avgDuration})).filter(a=>a.value>0).slice(0,8),c=s.map(a=>({name:a.model.length>20?`${a.model.slice(0,18)}...`:a.model,value:a.totalTokens})).filter(a=>a.value>0).slice(0,8),g=m.useMemo(()=>[{accessorKey:"model",header:"Model",cell:({row:a})=>e.jsx("div",{className:"font-mono text-xs font-semibold text-slate-100",children:a.original.model})},{accessorKey:"provider",header:"Provider",cell:({row:a})=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"h-2.5 w-2.5 rounded-full",style:{backgroundColor:p[a.original.provider]??"#a855f6",boxShadow:`0 0 10px ${p[a.original.provider]??"#a855f6"}`}}),e.jsx("span",{className:"text-xs font-medium capitalize text-slate-200",children:a.original.provider})]})},{accessorKey:"spanCount",header:"Calls",cell:({row:a})=>e.jsx("span",{className:"inline-flex items-center justify-center rounded-md border border-white/8 bg-slate-950/70 px-2 py-0.5 font-mono text-xs text-slate-400",children:a.original.spanCount}),meta:{className:"text-right",cellClassName:"text-right"}},{accessorKey:"totalTokens",header:"Tokens",cell:({row:a})=>e.jsx("span",{className:"font-mono text-xs text-slate-300",children:x(a.original.totalTokens)}),meta:{className:"text-right",cellClassName:"text-right"}},{accessorKey:"totalCost",header:"Cost",cell:({row:a})=>e.jsx("span",{className:"font-mono text-xs font-semibold text-white",children:o(a.original.totalCost)}),meta:{className:"text-right",cellClassName:"text-right"}},{accessorKey:"avgDuration",header:"Avg Latency",cell:({row:a})=>e.jsx("span",{className:"font-mono text-xs text-slate-400",children:a.original.avgDuration?h(a.original.avgDuration):"-"}),meta:{className:"text-right",cellClassName:"text-right"}},{id:"costPerCall",header:"Cost/Call",accessorFn:a=>a.spanCount>0?a.totalCost/a.spanCount:0,cell:({row:a})=>e.jsx("span",{className:"font-mono text-xs text-slate-500",children:a.original.spanCount>0?o(a.original.totalCost/a.original.spanCount):"-"}),meta:{className:"text-right",cellClassName:"text-right"}}],[]);return r?e.jsxs("div",{className:"mx-auto max-w-[1500px] space-y-8",children:[e.jsx("div",{className:"skeleton-panel h-44 rounded-[28px]"}),e.jsx("div",{className:"skeleton-panel h-80 rounded-[24px]"})]}):e.jsx(b,{eyebrow:"Model Intelligence",title:"Every model. Every metric. One surface.",description:"Compare cost, token volume, latency, and call frequency across all models in your rotation. Identify the models consuming the most budget and the ones delivering the best performance.",aside:e.jsxs("div",{className:"insight-panel",children:[e.jsx(N,{}),e.jsxs("div",{className:"mt-4 space-y-3",children:[e.jsxs("div",{className:"rounded-2xl border border-white/8 bg-white/4 p-4",children:[e.jsx("div",{className:"hud-label",children:"Models active"}),e.jsx("div",{className:"mt-2 text-lg font-medium text-white",children:e.jsx(f,{value:s.length})}),e.jsxs("div",{className:"mt-1 text-sm text-slate-400",children:["Across ",new Set(s.map(a=>a.provider)).size," providers"]})]}),e.jsxs("div",{className:"rounded-2xl border border-white/8 bg-white/4 p-4",children:[e.jsx("div",{className:"hud-label",children:"Highest cost model"}),e.jsx("div",{className:"mt-2 text-base font-medium text-white",children:s[0]?.model??"No data"}),e.jsx("div",{className:"mt-1 text-sm text-slate-400",children:s[0]?o(s[0].totalCost):"-"})]})]})]}),children:s.length>0?e.jsxs(e.Fragment,{children:[e.jsxs(l.div,{className:"dashboard-shell overflow-hidden rounded-[26px] px-4 py-4 sm:px-5",initial:{opacity:0,y:16},animate:{opacity:1,y:0},transition:{duration:.35},children:[e.jsxs("div",{className:"mb-3 flex items-center justify-between gap-3 px-1",children:[e.jsxs("div",{children:[e.jsx("div",{className:"hud-label",children:"Model roster"}),e.jsx("h2",{className:"mt-1 text-xl font-semibold tracking-[-0.04em] text-white",children:"Performance by model"})]}),e.jsxs("span",{className:"status-chip",children:[e.jsx(C,{className:"h-3.5 w-3.5 text-sky-300"}),e.jsxs("span",{children:[s.length," models"]})]})]}),e.jsx(y,{columns:g,data:s,sorting:t,onSortingChange:i})]}),e.jsxs("div",{className:"grid gap-5 xl:grid-cols-2",children:[e.jsxs(l.div,{className:"dashboard-shell rounded-[26px] px-5 py-5",initial:{opacity:0,y:16},animate:{opacity:1,y:0},transition:{delay:.1,duration:.35},children:[e.jsxs("div",{className:"mb-5 flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("div",{className:"hud-label",children:"Latency profile"}),e.jsx("h2",{className:"mt-1 text-xl font-semibold tracking-[-0.04em] text-white",children:"Average latency by model"})]}),e.jsx(w,{className:"h-4 w-4 text-sky-300"})]}),d.length>0?e.jsx(u,{rows:d,valueFormatter:h,barClassName:"bg-[linear-gradient(90deg,rgba(56,189,248,0.95),rgba(34,211,238,0.78))]"}):e.jsx("div",{className:"empty-state h-[280px] text-slate-500",children:"No latency data available yet."})]}),e.jsxs(l.div,{className:"dashboard-shell rounded-[26px] px-5 py-5",initial:{opacity:0,y:16},animate:{opacity:1,y:0},transition:{delay:.15,duration:.35},children:[e.jsxs("div",{className:"mb-5 flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("div",{className:"hud-label",children:"Token distribution"}),e.jsx("h2",{className:"mt-1 text-xl font-semibold tracking-[-0.04em] text-white",children:"Token volume by model"})]}),e.jsx(k,{className:"h-4 w-4 text-emerald-300"})]}),c.length>0?e.jsx(u,{rows:c,valueFormatter:x,barClassName:"bg-[linear-gradient(90deg,rgba(52,211,153,0.95),rgba(14,165,233,0.78))]"}):e.jsx("div",{className:"empty-state h-[280px] text-slate-500",children:"No token distribution data available yet."})]})]})]}):e.jsx("div",{className:"dashboard-shell rounded-[26px] p-16",children:e.jsxs("div",{className:"empty-state",children:[e.jsx(M,{className:"h-8 w-8 text-slate-500"}),e.jsx("div",{className:"text-base font-medium text-white",children:"No models tracked yet"}),e.jsx("div",{className:"max-w-sm text-center text-sm text-slate-400",children:"Start sending traced API calls and model metrics will populate automatically."})]})})})}export{E as default};
@@ -1,3 +0,0 @@
1
- import{r as i,d as g,j as e}from"./query-BSZkMKN4.js";import{L as N,a as j,o as f}from"./index-jVcSWGwX.js";import{D as b}from"./DataTable-CBsuKoTx.js";import{a as v,b as r,d as n,P as y}from"./format-CgXokIEM.js";import{N as C}from"./number-ticker-C1hiu1bi.js";import{M as c,T as w,a3 as S}from"./icons-DhpK1vUv.js";import{m as k}from"./motion-Bw6xJyTE.js";import"./charts-BXAtT8sy.js";function F(){const[d,m]=i.useState([{id:"lastSeen",desc:!0}]),{data:o,isLoading:x}=g({queryKey:["sessions"],queryFn:()=>f(168)}),t=o?.sessions??[],l=o?.total??0,h=t.reduce((s,a)=>s+a.totalCost,0),p=t.reduce((s,a)=>s+a.traceCount,0),u=i.useMemo(()=>[{accessorKey:"sessionId",header:"Session ID",cell:({row:s})=>e.jsxs(N,{to:`/traces?q=${encodeURIComponent(s.original.sessionId)}`,className:"group inline-flex items-center gap-2",children:[e.jsx(c,{className:"h-4 w-4 text-sky-300"}),e.jsx("span",{className:"font-mono text-xs font-semibold text-slate-100 transition-colors group-hover:text-emerald-300",children:s.original.sessionId.length>28?`${s.original.sessionId.slice(0,26)}...`:s.original.sessionId})]})},{accessorKey:"traceCount",header:"Traces",cell:({row:s})=>e.jsx("span",{className:"font-mono text-xs text-slate-300",children:s.original.traceCount}),meta:{className:"text-right",cellClassName:"text-right"}},{accessorKey:"spanCount",header:"Spans",cell:({row:s})=>e.jsx("span",{className:"font-mono text-xs text-slate-300",children:s.original.spanCount}),meta:{className:"text-right",cellClassName:"text-right"}},{accessorKey:"totalTokens",header:"Tokens",cell:({row:s})=>e.jsx("span",{className:"font-mono text-xs text-slate-300",children:v(s.original.totalTokens)}),meta:{className:"text-right",cellClassName:"text-right"}},{accessorKey:"totalCost",header:"Cost",cell:({row:s})=>e.jsx("span",{className:"font-mono text-xs font-semibold text-white",children:r(s.original.totalCost)}),meta:{className:"text-right",cellClassName:"text-right"}},{accessorKey:"errorCount",header:"Errors",cell:({row:s})=>s.original.errorCount>0?e.jsxs("span",{className:"inline-flex items-center gap-1 rounded-full border border-rose-400/20 bg-rose-400/10 px-2 py-0.5 text-[10px] font-bold text-rose-300",children:[e.jsx(w,{className:"h-3 w-3"}),s.original.errorCount]}):e.jsx("span",{className:"font-mono text-xs text-slate-500",children:"0"}),meta:{className:"text-right",cellClassName:"text-right"}},{accessorKey:"firstSeen",header:"First Seen",cell:({row:s})=>e.jsx("span",{className:"text-xs text-slate-500",children:n(s.original.firstSeen)}),meta:{className:"text-right",cellClassName:"text-right"}},{accessorKey:"lastSeen",header:"Last Active",cell:({row:s})=>e.jsx("span",{className:"text-xs text-slate-500",children:n(s.original.lastSeen)}),meta:{className:"text-right",cellClassName:"text-right"}}],[]);return x?e.jsxs("div",{className:"mx-auto max-w-[1500px] space-y-8",children:[e.jsx("div",{className:"skeleton-panel h-44 rounded-[28px]"}),e.jsx("div",{className:"skeleton-panel h-80 rounded-[24px]"})]}):e.jsx(y,{eyebrow:"Session Fabric",title:"Multi-turn conversations, grouped and measured.",description:"Sessions collect related traces into logical units. Track total cost and token volume across entire user conversations, multi-step agent runs, or workflow pipelines.",aside:e.jsxs("div",{className:"insight-panel",children:[e.jsx(j,{}),e.jsxs("div",{className:"mt-4 space-y-3",children:[e.jsxs("div",{className:"rounded-2xl border border-white/8 bg-white/4 p-4",children:[e.jsx("div",{className:"hud-label",children:"Active sessions"}),e.jsx("div",{className:"mt-2 text-lg font-medium text-white",children:e.jsx(C,{value:l})}),e.jsxs("div",{className:"mt-1 text-sm text-slate-400",children:[p," traces across all sessions"]})]}),e.jsxs("div",{className:"rounded-2xl border border-white/8 bg-white/4 p-4",children:[e.jsx("div",{className:"hud-label",children:"Session spend"}),e.jsx("div",{className:"mt-2 text-base font-medium text-white",children:r(h)}),e.jsx("div",{className:"mt-1 text-sm text-slate-400",children:"Combined cost across visible sessions"})]})]})]}),children:t.length>0?e.jsxs(k.div,{className:"dashboard-shell overflow-hidden rounded-[26px] px-4 py-4 sm:px-5",initial:{opacity:0,y:16},animate:{opacity:1,y:0},transition:{duration:.35},children:[e.jsxs("div",{className:"mb-3 flex items-center justify-between gap-3 px-1",children:[e.jsxs("div",{children:[e.jsx("div",{className:"hud-label",children:"Session registry"}),e.jsx("h2",{className:"mt-1 text-xl font-semibold tracking-[-0.04em] text-white",children:"Tracked sessions"})]}),e.jsxs("span",{className:"status-chip",children:[e.jsx(S,{className:"h-3.5 w-3.5 text-sky-300"}),e.jsxs("span",{children:[l," sessions"]})]})]}),e.jsx(b,{columns:u,data:t,sorting:d,onSortingChange:m})]}):e.jsx("div",{className:"dashboard-shell rounded-[26px] p-16",children:e.jsxs("div",{className:"empty-state",children:[e.jsx(c,{className:"h-8 w-8 text-slate-500"}),e.jsx("div",{className:"text-base font-medium text-white",children:"No sessions tracked yet"}),e.jsxs("div",{className:"max-w-md text-center text-sm text-slate-400",children:["Sessions appear when you pass a ",e.jsx("code",{className:"rounded bg-white/8 px-1.5 py-0.5 font-mono text-emerald-300",children:"sessionId"})," to the SDK. This groups related traces into logical conversations or workflows."]}),e.jsx("pre",{className:"mt-4 max-w-lg rounded-2xl border border-white/8 bg-white/4 p-4 text-left font-mono text-xs text-slate-300",children:`import { init } from "@llmtap/sdk";
2
-
3
- init({ sessionId: "user-session-123" });`})]})})})}export{F as default};
@@ -1,12 +0,0 @@
1
- import{j as e,r as o,u as Le,d as Fe}from"./query-BSZkMKN4.js";import{R as Be,p as le,e as Ue,q as ne,W as ze,C as Je,s as Qe,T as qe,D as Ge,g as ie,O as Ke,v as Ve,w as We,x as He,c as g,t as c,y as Ye,z as Xe,a as Ze,A as et,B as tt,E as st,F as at}from"./index-jVcSWGwX.js";import{P as rt,d as se}from"./format-CgXokIEM.js";import{f as de,S as ot,a as lt,b as nt,c as it,d as w}from"./select-CbYE6Q0M.js";import{m as y}from"./motion-Bw6xJyTE.js";import{a6 as dt,z as P,Q as ct,E as R,a7 as pt,b as xt,D as mt,X as ae,a8 as ht,a9 as ut,aa as gt,ab as bt}from"./icons-DhpK1vUv.js";import"./charts-BXAtT8sy.js";var ce="AlertDialog",[ft]=We(ce,[le]),h=le(),pe=s=>{const{__scopeAlertDialog:a,...r}=s,n=h(a);return e.jsx(Be,{...n,...r,modal:!0})};pe.displayName=ce;var yt="AlertDialogTrigger",jt=o.forwardRef((s,a)=>{const{__scopeAlertDialog:r,...n}=s,i=h(r);return e.jsx(He,{...i,...n,ref:a})});jt.displayName=yt;var vt="AlertDialogPortal",xe=s=>{const{__scopeAlertDialog:a,...r}=s,n=h(a);return e.jsx(Ue,{...n,...r})};xe.displayName=vt;var wt="AlertDialogOverlay",me=o.forwardRef((s,a)=>{const{__scopeAlertDialog:r,...n}=s,i=h(r);return e.jsx(Ke,{...i,...n,ref:a})});me.displayName=wt;var N="AlertDialogContent",[Nt,Ct]=ft(N),Dt=Ve("AlertDialogContent"),he=o.forwardRef((s,a)=>{const{__scopeAlertDialog:r,children:n,...i}=s,u=h(r),b=o.useRef(null),O=ne(a,b),C=o.useRef(null);return e.jsx(ze,{contentName:N,titleName:ue,docsSlug:"alert-dialog",children:e.jsx(Nt,{scope:r,cancelRef:C,children:e.jsxs(Je,{role:"alertdialog",...u,...i,ref:O,onOpenAutoFocus:Qe(i.onOpenAutoFocus,x=>{x.preventDefault(),C.current?.focus({preventScroll:!0})}),onPointerDownOutside:x=>x.preventDefault(),onInteractOutside:x=>x.preventDefault(),children:[e.jsx(Dt,{children:n}),e.jsx(St,{contentRef:b})]})})})});he.displayName=N;var ue="AlertDialogTitle",ge=o.forwardRef((s,a)=>{const{__scopeAlertDialog:r,...n}=s,i=h(r);return e.jsx(qe,{...i,...n,ref:a})});ge.displayName=ue;var be="AlertDialogDescription",fe=o.forwardRef((s,a)=>{const{__scopeAlertDialog:r,...n}=s,i=h(r);return e.jsx(Ge,{...i,...n,ref:a})});fe.displayName=be;var At="AlertDialogAction",ye=o.forwardRef((s,a)=>{const{__scopeAlertDialog:r,...n}=s,i=h(r);return e.jsx(ie,{...i,...n,ref:a})});ye.displayName=At;var je="AlertDialogCancel",ve=o.forwardRef((s,a)=>{const{__scopeAlertDialog:r,...n}=s,{cancelRef:i}=Ct(je,r),u=h(r),b=ne(a,i);return e.jsx(ie,{...u,...n,ref:b})});ve.displayName=je;var St=({contentRef:s})=>{const a=`\`${N}\` requires a description for the component to be accessible for screen reader users.
2
-
3
- You can add a description to the \`${N}\` by passing a \`${be}\` component as a child, which also benefits sighted users by adding visible context to the dialog.
4
-
5
- Alternatively, you can use your own component as a description by assigning it an \`id\` and passing the same value to the \`aria-describedby\` prop in \`${N}\`. If the description is confusing or duplicative for sighted users, you can use the \`@radix-ui/react-visually-hidden\` primitive as a wrapper around your description component.
6
-
7
- For more information, see https://radix-ui.com/primitives/docs/components/alert-dialog`;return o.useEffect(()=>{document.getElementById(s.current?.getAttribute("aria-describedby"))||console.warn(a)},[a,s]),null},Pt=pe,Rt=xe,we=me,Ne=he,Ce=ye,De=ve,Ae=ge,Se=fe;const re=Pt,Ot=Rt,Pe=o.forwardRef(({className:s,...a},r)=>e.jsx(we,{className:g("fixed inset-0 z-50 bg-black/60 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",s),...a,ref:r}));Pe.displayName=we.displayName;const _=o.forwardRef(({className:s,...a},r)=>e.jsxs(Ot,{children:[e.jsx(Pe,{}),e.jsx(Ne,{ref:r,className:g("fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 rounded-[24px] border border-white/10 bg-[linear-gradient(180deg,rgba(12,18,32,0.98),rgba(4,8,18,0.99))] p-6 shadow-[0_40px_100px_rgba(0,0,0,0.5)] backdrop-blur-2xl duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",s),...a})]}));_.displayName=Ne.displayName;const I=({className:s,...a})=>e.jsx("div",{className:g("flex flex-col gap-1.5 text-center sm:text-left",s),...a});I.displayName="AlertDialogHeader";const L=({className:s,...a})=>e.jsx("div",{className:g("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",s),...a});L.displayName="AlertDialogFooter";const F=o.forwardRef(({className:s,...a},r)=>e.jsx(Ae,{ref:r,className:g("text-lg font-semibold text-white",s),...a}));F.displayName=Ae.displayName;const B=o.forwardRef(({className:s,...a},r)=>e.jsx(Se,{ref:r,className:g("text-sm text-slate-400",s),...a}));B.displayName=Se.displayName;const U=o.forwardRef(({className:s,...a},r)=>e.jsx(Ce,{ref:r,className:g(de(),s),...a}));U.displayName=Ce.displayName;const z=o.forwardRef(({className:s,...a},r)=>e.jsx(De,{ref:r,className:g(de({variant:"outline"}),s),...a}));z.displayName=De.displayName;function oe(s){if(s===0)return"0 B";const a=["B","KB","MB","GB"],r=Math.min(Math.floor(Math.log(s)/Math.log(1024)),a.length-1);return`${(s/Math.pow(1024,r)).toFixed(r===0?0:1)} ${a[r]}`}function A({label:s,value:a,mono:r}){return e.jsxs("div",{className:"flex items-center justify-between gap-4 rounded-2xl border border-white/6 bg-white/4 px-4 py-3",children:[e.jsx("span",{className:"text-sm text-slate-400",children:s}),e.jsx("span",{className:`text-sm font-medium text-white ${r?"font-mono":""}`,children:a})]})}function Lt(){const s=Le(),[a,r]=o.useState(!1),[n,i]=o.useState(!1),[u,b]=o.useState(!1),[O,C]=o.useState(null),[x,J]=o.useState([]),[Re,E]=o.useState(!1),[p,j]=o.useState({provider:"",model:"",inputCostPer1M:"",outputCostPer1M:""}),[D,Oe]=o.useState("30"),[Ee,Q]=o.useState(!1),[T,q]=o.useState(null),[G,K]=o.useState(!1),[k,Te]=o.useState(""),[$,ke]=o.useState("llmtap"),[V,W]=o.useState(!1),[M,S]=o.useState(null),[H,Y]=o.useState(!1),[$e,X]=o.useState(!1),[Me,Z]=o.useState(!1),{data:d}=Fe({queryKey:["db-info"],queryFn:at});async function _e(){r(!0);try{await et(),i(!0),s.invalidateQueries(),c.success("Trace data cleared",{description:"The local collector database has been reset."}),setTimeout(()=>i(!1),3e3)}catch(t){c.error("Reset failed",{description:t instanceof Error?t.message:String(t)})}finally{r(!1)}}async function ee(t){K(!0);try{const l=await tt(t);q(l.deletedSpans),Q(!0),s.invalidateQueries(),c.success("Retention applied",{description:l.deletedSpans>0?`Deleted ${l.deletedSpans} old spans.`:"No spans needed cleanup for the selected window."}),setTimeout(()=>{Q(!1),q(null)},4e3)}catch(l){c.error("Retention failed",{description:l instanceof Error?l.message:String(l)})}finally{K(!1)}}async function te(t){b(!0);try{const l=await st(t),v=new Blob([l],{type:t==="json"?"application/json":"text/csv"}),m=URL.createObjectURL(v),f=document.createElement("a");f.href=m,f.download=`llmtap-traces-${new Date().toISOString().slice(0,10)}.${t}`,document.body.appendChild(f),f.click(),document.body.removeChild(f),URL.revokeObjectURL(m),c.success(`Exported ${t.toUpperCase()}`,{description:"Trace data was downloaded successfully."})}catch(l){c.error("Export failed",{description:l instanceof Error?l.message:String(l)})}finally{b(!1)}}function Ie(t,l){navigator.clipboard.writeText(t).catch(()=>{}),C(l),c.success("Copied to clipboard",{description:"Database path copied."}),setTimeout(()=>C(null),2e3)}return e.jsxs(e.Fragment,{children:[e.jsx(rt,{eyebrow:"Control Panel",title:"Configure, export, and manage your local collector.",description:"Database status, data export, and maintenance controls. Everything runs locally on your machine — your data never leaves.",aside:e.jsxs("div",{className:"insight-panel",children:[e.jsx(Ze,{}),e.jsx("div",{className:"mt-4 space-y-3",children:e.jsxs("div",{className:"rounded-2xl border border-white/8 bg-white/4 p-4",children:[e.jsx("div",{className:"hud-label",children:"Database"}),e.jsx("div",{className:"mt-2 text-lg font-medium text-white",children:d?oe(d.sizeBytes):"..."}),e.jsxs("div",{className:"mt-1 text-sm text-slate-400",children:[d?.spanCount??0," spans stored"]})]})})]}),children:e.jsxs("div",{className:"grid gap-5 xl:grid-cols-2",children:[e.jsxs(y.div,{className:"dashboard-shell rounded-[26px] px-5 py-5",initial:{opacity:0,y:16},animate:{opacity:1,y:0},transition:{duration:.35},children:[e.jsxs("div",{className:"mb-5 flex items-center gap-2",children:[e.jsx(dt,{className:"h-4 w-4 text-sky-300"}),e.jsx("h2",{className:"text-xl font-semibold tracking-[-0.04em] text-white",children:"Database status"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(A,{label:"Size on disk",value:d?oe(d.sizeBytes):"-"}),e.jsx(A,{label:"Total spans",value:String(d?.spanCount??0),mono:!0}),e.jsx(A,{label:"Total traces",value:String(d?.traceCount??0),mono:!0}),e.jsx(A,{label:"Journal mode",value:d?.walMode?.toUpperCase()??"-",mono:!0}),e.jsx(A,{label:"Data range",value:d?.oldestSpan&&d?.newestSpan?`${se(d.oldestSpan)} to ${se(d.newestSpan)}`:"No data"}),e.jsxs("div",{className:"flex items-center justify-between gap-4 rounded-2xl border border-white/6 bg-white/4 px-4 py-3",children:[e.jsx("span",{className:"text-sm text-slate-400",children:"Storage path"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"max-w-[220px] truncate font-mono text-xs text-slate-300",children:d?.path??"-"}),d?.path&&e.jsx("button",{type:"button",onClick:()=>Ie(d.path,"path"),className:"rounded-lg border border-white/8 bg-white/4 p-1.5 text-slate-400 transition-colors hover:text-white",children:O==="path"?e.jsx(P,{className:"h-3 w-3 text-emerald-300"}):e.jsx(ct,{className:"h-3 w-3"})})]})]})]})]}),e.jsxs("div",{className:"space-y-5",children:[e.jsxs(y.div,{className:"dashboard-shell rounded-[26px] px-5 py-5",initial:{opacity:0,y:16},animate:{opacity:1,y:0},transition:{delay:.1,duration:.35},children:[e.jsxs("div",{className:"mb-5 flex items-center gap-2",children:[e.jsx(R,{className:"h-4 w-4 text-emerald-300"}),e.jsx("h2",{className:"text-xl font-semibold tracking-[-0.04em] text-white",children:"Export data"})]}),e.jsx("p",{className:"mb-4 text-sm text-slate-400",children:"Download all trace data for offline analysis, backup, or migration."}),e.jsxs("div",{className:"flex gap-3",children:[e.jsxs("button",{type:"button",onClick:()=>te("json"),disabled:u,className:"status-chip transition-colors hover:border-white/16 hover:bg-white/8 disabled:cursor-not-allowed disabled:opacity-50",children:[e.jsx(R,{className:"h-3.5 w-3.5"}),e.jsx("span",{children:u?"Exporting...":"Export JSON"})]}),e.jsxs("button",{type:"button",onClick:()=>te("csv"),disabled:u,className:"status-chip transition-colors hover:border-white/16 hover:bg-white/8 disabled:cursor-not-allowed disabled:opacity-50",children:[e.jsx(R,{className:"h-3.5 w-3.5"}),e.jsx("span",{children:u?"Exporting...":"Export CSV"})]})]})]}),e.jsxs(y.div,{className:"dashboard-shell rounded-[26px] px-5 py-5",initial:{opacity:0,y:16},animate:{opacity:1,y:0},transition:{delay:.15,duration:.35},children:[e.jsxs("div",{className:"mb-5 flex items-center gap-2",children:[e.jsx(pt,{className:"h-4 w-4 text-rose-300"}),e.jsx("h2",{className:"text-xl font-semibold tracking-[-0.04em] text-white",children:"Reset data"})]}),e.jsx("p",{className:"mb-4 text-sm text-slate-400",children:"Permanently delete all stored traces and spans. This action cannot be undone."}),e.jsx("button",{type:"button",onClick:()=>X(!0),disabled:a,className:"inline-flex items-center gap-2 rounded-full border border-rose-400/20 bg-rose-400/8 px-4 py-2.5 text-sm font-medium text-rose-200 transition-colors hover:border-rose-400/30 hover:bg-rose-400/14 disabled:cursor-not-allowed disabled:opacity-50",children:n?e.jsxs(e.Fragment,{children:[e.jsx(P,{className:"h-4 w-4 text-emerald-300"}),e.jsx("span",{children:"Data cleared"})]}):e.jsxs(e.Fragment,{children:[e.jsx(xt,{className:`h-4 w-4 ${a?"animate-spin":""}`}),e.jsx("span",{children:a?"Resetting...":"Reset all data"})]})})]}),e.jsxs(y.div,{className:"dashboard-shell rounded-[26px] px-5 py-5",initial:{opacity:0,y:16},animate:{opacity:1,y:0},transition:{delay:.2,duration:.35},children:[e.jsxs("div",{className:"mb-5 flex items-center gap-2",children:[e.jsx(mt,{className:"h-4 w-4 text-amber-300"}),e.jsx("h2",{className:"text-xl font-semibold tracking-[-0.04em] text-white",children:"Pricing overrides"})]}),e.jsx("p",{className:"mb-4 text-sm text-slate-400",children:"Override built-in per-model pricing. Use this for custom or private models not in the default table."}),x.length>0&&e.jsx("div",{className:"mb-4 space-y-2",children:x.map((t,l)=>e.jsxs("div",{className:"flex items-center justify-between gap-3 rounded-2xl border border-white/6 bg-white/4 px-4 py-3",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"rounded-full border border-white/10 bg-white/6 px-2 py-0.5 text-[10px] font-bold uppercase tracking-[0.16em] text-slate-300",children:t.provider}),e.jsx("span",{className:"font-mono text-sm text-white",children:t.model})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("span",{className:"font-mono text-xs text-slate-400",children:["$",t.inputCostPer1M,"/M in"]}),e.jsxs("span",{className:"font-mono text-xs text-slate-400",children:["$",t.outputCostPer1M,"/M out"]}),e.jsx("button",{type:"button",onClick:()=>J(v=>v.filter((m,f)=>f!==l)),className:"rounded-lg border border-white/8 bg-white/4 p-1.5 text-slate-500 transition-colors hover:text-rose-300",children:e.jsx(ae,{className:"h-3 w-3"})})]})]},`${t.provider}-${t.model}`))}),Re?e.jsxs("div",{className:"rounded-2xl border border-white/8 bg-white/4 p-4",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-3 sm:grid-cols-4",children:[e.jsx("input",{value:p.provider,onChange:t=>j(l=>({...l,provider:t.target.value})),placeholder:"Provider",className:"rounded-xl border border-white/8 bg-white/4 px-3 py-2 text-sm text-white placeholder:text-slate-500 focus:border-emerald-400/30 focus:outline-none"}),e.jsx("input",{value:p.model,onChange:t=>j(l=>({...l,model:t.target.value})),placeholder:"Model name",className:"rounded-xl border border-white/8 bg-white/4 px-3 py-2 text-sm text-white placeholder:text-slate-500 focus:border-emerald-400/30 focus:outline-none"}),e.jsx("input",{value:p.inputCostPer1M,onChange:t=>j(l=>({...l,inputCostPer1M:t.target.value})),placeholder:"Input $/M",type:"number",step:"0.01",className:"rounded-xl border border-white/8 bg-white/4 px-3 py-2 text-sm text-white placeholder:text-slate-500 focus:border-emerald-400/30 focus:outline-none"}),e.jsx("input",{value:p.outputCostPer1M,onChange:t=>j(l=>({...l,outputCostPer1M:t.target.value})),placeholder:"Output $/M",type:"number",step:"0.01",className:"rounded-xl border border-white/8 bg-white/4 px-3 py-2 text-sm text-white placeholder:text-slate-500 focus:border-emerald-400/30 focus:outline-none"})]}),e.jsxs("div",{className:"mt-3 flex items-center gap-2",children:[e.jsxs("button",{type:"button",onClick:()=>{p.provider&&p.model&&p.inputCostPer1M&&p.outputCostPer1M&&(J(t=>[...t,{...p}]),c.success("Pricing override added",{description:`${p.provider}/${p.model} is ready to use.`}),j({provider:"",model:"",inputCostPer1M:"",outputCostPer1M:""}),E(!1))},className:"status-chip transition-colors hover:border-white/16 hover:bg-white/8",children:[e.jsx(P,{className:"h-3.5 w-3.5"}),e.jsx("span",{children:"Add"})]}),e.jsxs("button",{type:"button",onClick:()=>{E(!1),j({provider:"",model:"",inputCostPer1M:"",outputCostPer1M:""})},className:"status-chip transition-colors hover:border-white/16 hover:bg-white/8",children:[e.jsx(ae,{className:"h-3.5 w-3.5"}),e.jsx("span",{children:"Cancel"})]})]})]}):e.jsxs("button",{type:"button",onClick:()=>E(!0),className:"status-chip transition-colors hover:border-white/16 hover:bg-white/8",children:[e.jsx(ht,{className:"h-3.5 w-3.5"}),e.jsx("span",{children:"Add pricing override"})]}),x.length>0&&e.jsxs("div",{className:"mt-4 rounded-2xl border border-white/8 bg-white/4 p-4",children:[e.jsx("div",{className:"mb-2 text-xs font-semibold uppercase tracking-[0.16em] text-slate-500",children:"SDK code to apply these overrides"}),e.jsx("pre",{className:"font-mono text-xs leading-relaxed text-slate-300",children:`import { setPricing } from "@llmtap/sdk";
8
- ${x.map(t=>`setPricing("${t.provider}", "${t.model}", ${t.inputCostPer1M}, ${t.outputCostPer1M});`).join(`
9
- `)}`})]})]}),e.jsxs(y.div,{className:"dashboard-shell rounded-[26px] px-5 py-5",initial:{opacity:0,y:16},animate:{opacity:1,y:0},transition:{delay:.25,duration:.35},children:[e.jsxs("div",{className:"mb-5 flex items-center gap-2",children:[e.jsx(ut,{className:"h-4 w-4 text-purple-300"}),e.jsx("h2",{className:"text-xl font-semibold tracking-[-0.04em] text-white",children:"Data retention"})]}),e.jsx("p",{className:"mb-4 text-sm text-slate-400",children:"Configure how long trace data is kept. Older traces will be automatically cleaned up."}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs(ot,{value:D,onValueChange:t=>Oe(t),children:[e.jsx(lt,{className:"w-[160px] rounded-2xl py-3",children:e.jsx(nt,{})}),e.jsxs(it,{children:[e.jsx(w,{value:"7",children:"7 days"}),e.jsx(w,{value:"14",children:"14 days"}),e.jsx(w,{value:"30",children:"30 days"}),e.jsx(w,{value:"90",children:"90 days"}),e.jsx(w,{value:"365",children:"1 year"}),e.jsx(w,{value:"0",children:"Keep forever"})]})]}),e.jsx("button",{type:"button",onClick:async()=>{const t=parseInt(D,10);if(t>0){Z(!0);return}await ee(t)},disabled:G,className:"status-chip transition-colors hover:border-white/16 hover:bg-white/8 disabled:cursor-not-allowed disabled:opacity-50",children:Ee?e.jsxs(e.Fragment,{children:[e.jsx(P,{className:"h-3.5 w-3.5 text-emerald-300"}),e.jsx("span",{children:T!==null&&T>0?`Cleaned ${T} spans`:"Applied"})]}):e.jsx("span",{children:G?"Applying...":"Apply now"})})]}),e.jsxs("p",{className:"mt-3 text-xs text-slate-500",children:["This immediately deletes spans older than the selected period. For automatic enforcement on every startup, use ",e.jsxs("code",{className:"rounded bg-white/6 px-1.5 py-0.5 font-mono text-slate-400",children:["llmtap start --retention ",D]}),"."]})]}),e.jsxs(y.div,{className:"dashboard-shell rounded-[26px] px-5 py-5",initial:{opacity:0,y:16},animate:{opacity:1,y:0},transition:{delay:.27,duration:.35},children:[e.jsxs("div",{className:"mb-5 flex items-center gap-2",children:[e.jsx(gt,{className:"h-4 w-4 text-cyan-300"}),e.jsx("h2",{className:"text-xl font-semibold tracking-[-0.04em] text-white",children:"OpenTelemetry Export"})]}),e.jsx("p",{className:"mb-4 text-sm text-slate-400",children:"Export spans in OTLP format for Datadog, Grafana Tempo, Jaeger, Honeycomb, or any OTLP-compatible backend."}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("button",{type:"button",disabled:H,onClick:async()=>{Y(!0);try{const t=await Ye(1e3,$),l=new Blob([t],{type:"application/json"}),v=URL.createObjectURL(l),m=document.createElement("a");m.href=v,m.download="llmtap-export.otlp.json",document.body.appendChild(m),m.click(),document.body.removeChild(m),URL.revokeObjectURL(v),c.success("OTLP export downloaded",{description:"The collector export was saved as OTLP JSON."})}catch(t){c.error("Export failed",{description:t instanceof Error?t.message:String(t)})}finally{Y(!1)}},className:"flex items-center gap-2 rounded-2xl border border-cyan-400/20 bg-cyan-400/10 px-4 py-2.5 text-sm font-medium text-cyan-300 transition-colors hover:bg-cyan-400/20",children:[e.jsx(R,{className:"h-3.5 w-3.5"}),H?"Exporting...":"Download OTLP JSON"]}),e.jsxs("div",{className:"rounded-2xl border border-white/8 bg-white/4 p-4",children:[e.jsx("div",{className:"mb-3 text-xs font-semibold uppercase tracking-[0.16em] text-slate-500",children:"Forward to OTLP endpoint"}),e.jsxs("div",{className:"flex flex-col gap-3 sm:flex-row",children:[e.jsx("input",{type:"text",value:k,onChange:t=>{Te(t.target.value),S(null)},placeholder:"http://localhost:4318/v1/traces",className:"flex-1 rounded-xl border border-white/8 bg-white/4 px-3 py-2 text-sm text-white placeholder-slate-500 focus:border-cyan-400/30 focus:outline-none"}),e.jsx("input",{type:"text",value:$,onChange:t=>ke(t.target.value),placeholder:"service name",className:"w-32 rounded-xl border border-white/8 bg-white/4 px-3 py-2 text-sm text-white placeholder-slate-500 focus:border-cyan-400/30 focus:outline-none"}),e.jsx("button",{type:"button",disabled:!k||V,onClick:async()=>{W(!0),S(null);try{const t=await Xe(k,{service:$});S(`Forwarded ${t.spanCount} spans`),c.success("OTLP forward complete",{description:`Forwarded ${t.spanCount} spans to the target endpoint.`})}catch(t){S(`Error: ${t instanceof Error?t.message:String(t)}`),c.error("OTLP forward failed",{description:t instanceof Error?t.message:String(t)})}finally{W(!1)}},className:"rounded-xl border border-cyan-400/20 bg-cyan-400/10 px-4 py-2 text-sm font-medium text-cyan-300 transition-colors hover:bg-cyan-400/20 disabled:opacity-40",children:V?"Sending...":"Send"})]}),M&&e.jsx("p",{className:`mt-2 text-xs ${M.startsWith("Error")?"text-rose-400":"text-emerald-400"}`,children:M})]}),e.jsxs("p",{className:"text-xs text-slate-500",children:["CLI: ",e.jsx("code",{className:"rounded bg-white/6 px-1.5 py-0.5 font-mono text-slate-400",children:"llmtap export --format otlp --endpoint http://localhost:4318/v1/traces"})]})]})]}),e.jsxs(y.div,{className:"dashboard-shell rounded-[26px] px-5 py-5",initial:{opacity:0,y:16},animate:{opacity:1,y:0},transition:{delay:.3,duration:.35},children:[e.jsxs("div",{className:"mb-5 flex items-center gap-2",children:[e.jsx(bt,{className:"h-4 w-4 text-sky-300"}),e.jsx("h2",{className:"text-xl font-semibold tracking-[-0.04em] text-white",children:"Quick start"})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"rounded-2xl border border-white/8 bg-white/4 p-4",children:[e.jsx("div",{className:"mb-2 text-xs font-semibold uppercase tracking-[0.16em] text-slate-500",children:"1. Install the SDK"}),e.jsx("pre",{className:"font-mono text-xs text-slate-300",children:"npm install @llmtap/sdk"})]}),e.jsxs("div",{className:"rounded-2xl border border-white/8 bg-white/4 p-4",children:[e.jsx("div",{className:"mb-2 text-xs font-semibold uppercase tracking-[0.16em] text-slate-500",children:"2. Wrap your client"}),e.jsx("pre",{className:"font-mono text-xs leading-relaxed text-slate-300",children:`import { wrap } from "@llmtap/sdk";
10
- import OpenAI from "openai";
11
-
12
- const openai = wrap(new OpenAI());`})]}),e.jsxs("div",{className:"rounded-2xl border border-white/8 bg-white/4 p-4",children:[e.jsx("div",{className:"mb-2 text-xs font-semibold uppercase tracking-[0.16em] text-slate-500",children:"3. That's it"}),e.jsx("p",{className:"text-xs leading-relaxed text-slate-400",children:"All API calls are now traced automatically. Open this dashboard to see real-time data."})]})]})]})]})]})}),e.jsx(re,{open:$e,onOpenChange:X,children:e.jsxs(_,{children:[e.jsxs(I,{children:[e.jsx(F,{children:"Delete all trace data?"}),e.jsx(B,{children:"This will permanently delete all stored traces and spans. This action cannot be undone."})]}),e.jsxs(L,{children:[e.jsx(z,{children:"Cancel"}),e.jsx(U,{onClick:()=>_e(),className:"border-rose-400/20 bg-rose-500 text-white hover:bg-rose-400",children:"Delete all data"})]})]})}),e.jsx(re,{open:Me,onOpenChange:Z,children:e.jsxs(_,{children:[e.jsxs(I,{children:[e.jsx(F,{children:"Apply data retention?"}),e.jsxs(B,{children:["This will delete all trace data older than ",D," days. This action cannot be undone."]})]}),e.jsxs(L,{children:[e.jsx(z,{children:"Cancel"}),e.jsx(U,{onClick:()=>ee(parseInt(D,10)),className:"border-rose-400/20 bg-rose-500 text-white hover:bg-rose-400",children:"Delete old data"})]})]})})]})}export{Lt as default};
@@ -1 +0,0 @@
1
- import{j as e}from"./query-BSZkMKN4.js";import{c as s}from"./index-jVcSWGwX.js";function l({status:t,className:a}){const r=t==="error";return e.jsxs("span",{className:s("relative flex h-3.5 w-3.5 items-center justify-center",a),children:[e.jsx("span",{className:s("absolute inset-0 rounded-full",r?"bg-rose-400/25":"bg-emerald-400/25")}),e.jsx("span",{className:s("relative h-2 w-2 rounded-full",r?"bg-rose-400":"bg-emerald-300")})]})}export{l as S};