@peakinfer/cli 1.0.133

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 (367) hide show
  1. package/.claude/settings.local.json +8 -0
  2. package/.env.example +6 -0
  3. package/.github/workflows/peakinfer.yml +64 -0
  4. package/CHANGELOG.md +31 -0
  5. package/LICENSE +190 -0
  6. package/README.md +335 -0
  7. package/data/inferencemax.json +274 -0
  8. package/dist/agent-analyzer.d.ts +45 -0
  9. package/dist/agent-analyzer.d.ts.map +1 -0
  10. package/dist/agent-analyzer.js +374 -0
  11. package/dist/agent-analyzer.js.map +1 -0
  12. package/dist/agent.d.ts +76 -0
  13. package/dist/agent.d.ts.map +1 -0
  14. package/dist/agent.js +965 -0
  15. package/dist/agent.js.map +1 -0
  16. package/dist/agents/correlation-analyzer.d.ts +34 -0
  17. package/dist/agents/correlation-analyzer.d.ts.map +1 -0
  18. package/dist/agents/correlation-analyzer.js +261 -0
  19. package/dist/agents/correlation-analyzer.js.map +1 -0
  20. package/dist/agents/index.d.ts +91 -0
  21. package/dist/agents/index.d.ts.map +1 -0
  22. package/dist/agents/index.js +111 -0
  23. package/dist/agents/index.js.map +1 -0
  24. package/dist/agents/runtime-analyzer.d.ts +38 -0
  25. package/dist/agents/runtime-analyzer.d.ts.map +1 -0
  26. package/dist/agents/runtime-analyzer.js +244 -0
  27. package/dist/agents/runtime-analyzer.js.map +1 -0
  28. package/dist/analysis-types.d.ts +500 -0
  29. package/dist/analysis-types.d.ts.map +1 -0
  30. package/dist/analysis-types.js +11 -0
  31. package/dist/analysis-types.js.map +1 -0
  32. package/dist/analytics.d.ts +25 -0
  33. package/dist/analytics.d.ts.map +1 -0
  34. package/dist/analytics.js +94 -0
  35. package/dist/analytics.js.map +1 -0
  36. package/dist/analyzer.d.ts +48 -0
  37. package/dist/analyzer.d.ts.map +1 -0
  38. package/dist/analyzer.js +547 -0
  39. package/dist/analyzer.js.map +1 -0
  40. package/dist/artifacts.d.ts +44 -0
  41. package/dist/artifacts.d.ts.map +1 -0
  42. package/dist/artifacts.js +165 -0
  43. package/dist/artifacts.js.map +1 -0
  44. package/dist/benchmarks/index.d.ts +88 -0
  45. package/dist/benchmarks/index.d.ts.map +1 -0
  46. package/dist/benchmarks/index.js +205 -0
  47. package/dist/benchmarks/index.js.map +1 -0
  48. package/dist/cli.d.ts +3 -0
  49. package/dist/cli.d.ts.map +1 -0
  50. package/dist/cli.js +427 -0
  51. package/dist/cli.js.map +1 -0
  52. package/dist/commands/ci.d.ts +19 -0
  53. package/dist/commands/ci.d.ts.map +1 -0
  54. package/dist/commands/ci.js +253 -0
  55. package/dist/commands/ci.js.map +1 -0
  56. package/dist/commands/config.d.ts +16 -0
  57. package/dist/commands/config.d.ts.map +1 -0
  58. package/dist/commands/config.js +249 -0
  59. package/dist/commands/config.js.map +1 -0
  60. package/dist/commands/demo.d.ts +15 -0
  61. package/dist/commands/demo.d.ts.map +1 -0
  62. package/dist/commands/demo.js +106 -0
  63. package/dist/commands/demo.js.map +1 -0
  64. package/dist/commands/export.d.ts +14 -0
  65. package/dist/commands/export.d.ts.map +1 -0
  66. package/dist/commands/export.js +209 -0
  67. package/dist/commands/export.js.map +1 -0
  68. package/dist/commands/history.d.ts +15 -0
  69. package/dist/commands/history.d.ts.map +1 -0
  70. package/dist/commands/history.js +389 -0
  71. package/dist/commands/history.js.map +1 -0
  72. package/dist/commands/template.d.ts +14 -0
  73. package/dist/commands/template.d.ts.map +1 -0
  74. package/dist/commands/template.js +341 -0
  75. package/dist/commands/template.js.map +1 -0
  76. package/dist/commands/validate-map.d.ts +12 -0
  77. package/dist/commands/validate-map.d.ts.map +1 -0
  78. package/dist/commands/validate-map.js +274 -0
  79. package/dist/commands/validate-map.js.map +1 -0
  80. package/dist/commands/whatif.d.ts +17 -0
  81. package/dist/commands/whatif.d.ts.map +1 -0
  82. package/dist/commands/whatif.js +206 -0
  83. package/dist/commands/whatif.js.map +1 -0
  84. package/dist/comparison.d.ts +38 -0
  85. package/dist/comparison.d.ts.map +1 -0
  86. package/dist/comparison.js +223 -0
  87. package/dist/comparison.js.map +1 -0
  88. package/dist/config.d.ts +42 -0
  89. package/dist/config.d.ts.map +1 -0
  90. package/dist/config.js +158 -0
  91. package/dist/config.js.map +1 -0
  92. package/dist/connectors/helicone.d.ts +9 -0
  93. package/dist/connectors/helicone.d.ts.map +1 -0
  94. package/dist/connectors/helicone.js +106 -0
  95. package/dist/connectors/helicone.js.map +1 -0
  96. package/dist/connectors/index.d.ts +37 -0
  97. package/dist/connectors/index.d.ts.map +1 -0
  98. package/dist/connectors/index.js +65 -0
  99. package/dist/connectors/index.js.map +1 -0
  100. package/dist/connectors/langsmith.d.ts +9 -0
  101. package/dist/connectors/langsmith.d.ts.map +1 -0
  102. package/dist/connectors/langsmith.js +122 -0
  103. package/dist/connectors/langsmith.js.map +1 -0
  104. package/dist/connectors/types.d.ts +83 -0
  105. package/dist/connectors/types.d.ts.map +1 -0
  106. package/dist/connectors/types.js +98 -0
  107. package/dist/connectors/types.js.map +1 -0
  108. package/dist/cost-estimator.d.ts +46 -0
  109. package/dist/cost-estimator.d.ts.map +1 -0
  110. package/dist/cost-estimator.js +104 -0
  111. package/dist/cost-estimator.js.map +1 -0
  112. package/dist/costs.d.ts +57 -0
  113. package/dist/costs.d.ts.map +1 -0
  114. package/dist/costs.js +251 -0
  115. package/dist/costs.js.map +1 -0
  116. package/dist/counterfactuals.d.ts +29 -0
  117. package/dist/counterfactuals.d.ts.map +1 -0
  118. package/dist/counterfactuals.js +448 -0
  119. package/dist/counterfactuals.js.map +1 -0
  120. package/dist/enhancement-prompts.d.ts +41 -0
  121. package/dist/enhancement-prompts.d.ts.map +1 -0
  122. package/dist/enhancement-prompts.js +88 -0
  123. package/dist/enhancement-prompts.js.map +1 -0
  124. package/dist/envelopes.d.ts +20 -0
  125. package/dist/envelopes.d.ts.map +1 -0
  126. package/dist/envelopes.js +790 -0
  127. package/dist/envelopes.js.map +1 -0
  128. package/dist/format-normalizer.d.ts +71 -0
  129. package/dist/format-normalizer.d.ts.map +1 -0
  130. package/dist/format-normalizer.js +1331 -0
  131. package/dist/format-normalizer.js.map +1 -0
  132. package/dist/history.d.ts +79 -0
  133. package/dist/history.d.ts.map +1 -0
  134. package/dist/history.js +313 -0
  135. package/dist/history.js.map +1 -0
  136. package/dist/html.d.ts +11 -0
  137. package/dist/html.d.ts.map +1 -0
  138. package/dist/html.js +463 -0
  139. package/dist/html.js.map +1 -0
  140. package/dist/impact.d.ts +42 -0
  141. package/dist/impact.d.ts.map +1 -0
  142. package/dist/impact.js +443 -0
  143. package/dist/impact.js.map +1 -0
  144. package/dist/index.d.ts +26 -0
  145. package/dist/index.d.ts.map +1 -0
  146. package/dist/index.js +34 -0
  147. package/dist/index.js.map +1 -0
  148. package/dist/insights.d.ts +5 -0
  149. package/dist/insights.d.ts.map +1 -0
  150. package/dist/insights.js +271 -0
  151. package/dist/insights.js.map +1 -0
  152. package/dist/joiner.d.ts +9 -0
  153. package/dist/joiner.d.ts.map +1 -0
  154. package/dist/joiner.js +247 -0
  155. package/dist/joiner.js.map +1 -0
  156. package/dist/orchestrator.d.ts +34 -0
  157. package/dist/orchestrator.d.ts.map +1 -0
  158. package/dist/orchestrator.js +827 -0
  159. package/dist/orchestrator.js.map +1 -0
  160. package/dist/pdf.d.ts +26 -0
  161. package/dist/pdf.d.ts.map +1 -0
  162. package/dist/pdf.js +84 -0
  163. package/dist/pdf.js.map +1 -0
  164. package/dist/prediction.d.ts +33 -0
  165. package/dist/prediction.d.ts.map +1 -0
  166. package/dist/prediction.js +316 -0
  167. package/dist/prediction.js.map +1 -0
  168. package/dist/prompts/loader.d.ts +38 -0
  169. package/dist/prompts/loader.d.ts.map +1 -0
  170. package/dist/prompts/loader.js +60 -0
  171. package/dist/prompts/loader.js.map +1 -0
  172. package/dist/renderer.d.ts +64 -0
  173. package/dist/renderer.d.ts.map +1 -0
  174. package/dist/renderer.js +923 -0
  175. package/dist/renderer.js.map +1 -0
  176. package/dist/runid.d.ts +57 -0
  177. package/dist/runid.d.ts.map +1 -0
  178. package/dist/runid.js +199 -0
  179. package/dist/runid.js.map +1 -0
  180. package/dist/runtime.d.ts +29 -0
  181. package/dist/runtime.d.ts.map +1 -0
  182. package/dist/runtime.js +366 -0
  183. package/dist/runtime.js.map +1 -0
  184. package/dist/scanner.d.ts +11 -0
  185. package/dist/scanner.d.ts.map +1 -0
  186. package/dist/scanner.js +426 -0
  187. package/dist/scanner.js.map +1 -0
  188. package/dist/templates.d.ts +120 -0
  189. package/dist/templates.d.ts.map +1 -0
  190. package/dist/templates.js +429 -0
  191. package/dist/templates.js.map +1 -0
  192. package/dist/tools/index.d.ts +153 -0
  193. package/dist/tools/index.d.ts.map +1 -0
  194. package/dist/tools/index.js +177 -0
  195. package/dist/tools/index.js.map +1 -0
  196. package/dist/types.d.ts +3647 -0
  197. package/dist/types.d.ts.map +1 -0
  198. package/dist/types.js +703 -0
  199. package/dist/types.js.map +1 -0
  200. package/dist/version.d.ts +7 -0
  201. package/dist/version.d.ts.map +1 -0
  202. package/dist/version.js +23 -0
  203. package/dist/version.js.map +1 -0
  204. package/docs/demo-guide.md +423 -0
  205. package/docs/events-format.md +295 -0
  206. package/docs/inferencemap-spec.md +344 -0
  207. package/docs/migration-v2.md +293 -0
  208. package/fixtures/demo/precomputed.json +142 -0
  209. package/fixtures/demo-project/README.md +52 -0
  210. package/fixtures/demo-project/ai-service.ts +65 -0
  211. package/fixtures/demo-project/sample-events.jsonl +15 -0
  212. package/fixtures/demo-project/src/ai-service.ts +128 -0
  213. package/fixtures/demo-project/src/llm-client.ts +155 -0
  214. package/package.json +65 -0
  215. package/prompts/agent-analyzer.yaml +47 -0
  216. package/prompts/ci-gate.yaml +98 -0
  217. package/prompts/correlation-analyzer.yaml +178 -0
  218. package/prompts/format-normalizer.yaml +46 -0
  219. package/prompts/peak-performance.yaml +180 -0
  220. package/prompts/pr-comment.yaml +111 -0
  221. package/prompts/runtime-analyzer.yaml +189 -0
  222. package/prompts/unified-analyzer.yaml +241 -0
  223. package/schemas/inference-map.v0.1.json +215 -0
  224. package/scripts/benchmark.ts +394 -0
  225. package/scripts/demo-v1.5.sh +158 -0
  226. package/scripts/sync-from-site.sh +197 -0
  227. package/scripts/validate-sync.sh +178 -0
  228. package/src/agent-analyzer.ts +481 -0
  229. package/src/agent.ts +1232 -0
  230. package/src/agents/correlation-analyzer.ts +353 -0
  231. package/src/agents/index.ts +235 -0
  232. package/src/agents/runtime-analyzer.ts +343 -0
  233. package/src/analysis-types.ts +558 -0
  234. package/src/analytics.ts +100 -0
  235. package/src/analyzer.ts +692 -0
  236. package/src/artifacts.ts +218 -0
  237. package/src/benchmarks/index.ts +309 -0
  238. package/src/cli.ts +503 -0
  239. package/src/commands/ci.ts +336 -0
  240. package/src/commands/config.ts +288 -0
  241. package/src/commands/demo.ts +175 -0
  242. package/src/commands/export.ts +297 -0
  243. package/src/commands/history.ts +425 -0
  244. package/src/commands/template.ts +385 -0
  245. package/src/commands/validate-map.ts +324 -0
  246. package/src/commands/whatif.ts +272 -0
  247. package/src/comparison.ts +283 -0
  248. package/src/config.ts +188 -0
  249. package/src/connectors/helicone.ts +164 -0
  250. package/src/connectors/index.ts +93 -0
  251. package/src/connectors/langsmith.ts +179 -0
  252. package/src/connectors/types.ts +180 -0
  253. package/src/cost-estimator.ts +146 -0
  254. package/src/costs.ts +347 -0
  255. package/src/counterfactuals.ts +516 -0
  256. package/src/enhancement-prompts.ts +118 -0
  257. package/src/envelopes.ts +814 -0
  258. package/src/format-normalizer.ts +1486 -0
  259. package/src/history.ts +400 -0
  260. package/src/html.ts +512 -0
  261. package/src/impact.ts +522 -0
  262. package/src/index.ts +83 -0
  263. package/src/insights.ts +341 -0
  264. package/src/joiner.ts +289 -0
  265. package/src/orchestrator.ts +1015 -0
  266. package/src/pdf.ts +110 -0
  267. package/src/prediction.ts +392 -0
  268. package/src/prompts/loader.ts +88 -0
  269. package/src/renderer.ts +1045 -0
  270. package/src/runid.ts +261 -0
  271. package/src/runtime.ts +450 -0
  272. package/src/scanner.ts +508 -0
  273. package/src/templates.ts +561 -0
  274. package/src/tools/index.ts +214 -0
  275. package/src/types.ts +873 -0
  276. package/src/version.ts +24 -0
  277. package/templates/context-accumulation.yaml +23 -0
  278. package/templates/cost-concentration.yaml +20 -0
  279. package/templates/dead-code.yaml +20 -0
  280. package/templates/latency-explainer.yaml +23 -0
  281. package/templates/optimizations/ab-testing-framework.yaml +74 -0
  282. package/templates/optimizations/api-gateway-optimization.yaml +81 -0
  283. package/templates/optimizations/api-model-routing-strategy.yaml +126 -0
  284. package/templates/optimizations/auto-scaling-optimization.yaml +85 -0
  285. package/templates/optimizations/batch-utilization-diagnostic.yaml +142 -0
  286. package/templates/optimizations/comprehensive-apm.yaml +76 -0
  287. package/templates/optimizations/context-window-optimization.yaml +91 -0
  288. package/templates/optimizations/cost-sensitive-batch-processing.yaml +77 -0
  289. package/templates/optimizations/distributed-training-optimization.yaml +77 -0
  290. package/templates/optimizations/document-analysis-edge.yaml +77 -0
  291. package/templates/optimizations/document-pipeline-optimization.yaml +78 -0
  292. package/templates/optimizations/domain-specific-distillation.yaml +78 -0
  293. package/templates/optimizations/error-handling-optimization.yaml +76 -0
  294. package/templates/optimizations/gptq-4bit-quantization.yaml +96 -0
  295. package/templates/optimizations/long-context-memory-management.yaml +78 -0
  296. package/templates/optimizations/max-tokens-optimization.yaml +76 -0
  297. package/templates/optimizations/memory-bandwidth-optimization.yaml +73 -0
  298. package/templates/optimizations/multi-framework-resilience.yaml +75 -0
  299. package/templates/optimizations/multi-tenant-optimization.yaml +75 -0
  300. package/templates/optimizations/prompt-caching-optimization.yaml +143 -0
  301. package/templates/optimizations/pytorch-to-onnx-migration.yaml +109 -0
  302. package/templates/optimizations/quality-monitoring.yaml +74 -0
  303. package/templates/optimizations/realtime-budget-controls.yaml +74 -0
  304. package/templates/optimizations/realtime-latency-optimization.yaml +74 -0
  305. package/templates/optimizations/sglang-concurrency-optimization.yaml +78 -0
  306. package/templates/optimizations/smart-model-routing.yaml +96 -0
  307. package/templates/optimizations/streaming-batch-selection.yaml +167 -0
  308. package/templates/optimizations/system-prompt-optimization.yaml +75 -0
  309. package/templates/optimizations/tensorrt-llm-performance.yaml +77 -0
  310. package/templates/optimizations/vllm-high-throughput-optimization.yaml +93 -0
  311. package/templates/optimizations/vllm-migration-memory-bound.yaml +78 -0
  312. package/templates/overpowered-extraction.yaml +32 -0
  313. package/templates/overpowered-model.yaml +31 -0
  314. package/templates/prompt-bloat.yaml +24 -0
  315. package/templates/retry-explosion.yaml +28 -0
  316. package/templates/schema/insight.schema.json +113 -0
  317. package/templates/schema/optimization.schema.json +180 -0
  318. package/templates/streaming-drift.yaml +30 -0
  319. package/templates/throughput-gap.yaml +21 -0
  320. package/templates/token-underutilization.yaml +28 -0
  321. package/templates/untested-fallback.yaml +21 -0
  322. package/tests/accuracy/drift-detection.test.ts +184 -0
  323. package/tests/accuracy/false-positives.test.ts +166 -0
  324. package/tests/accuracy/templates.test.ts +205 -0
  325. package/tests/action/commands.test.ts +125 -0
  326. package/tests/action/comments.test.ts +347 -0
  327. package/tests/cli.test.ts +203 -0
  328. package/tests/comparison.test.ts +309 -0
  329. package/tests/correlation-analyzer.test.ts +534 -0
  330. package/tests/counterfactuals.test.ts +347 -0
  331. package/tests/fixtures/events/missing-id.jsonl +1 -0
  332. package/tests/fixtures/events/missing-input.jsonl +1 -0
  333. package/tests/fixtures/events/missing-latency.jsonl +1 -0
  334. package/tests/fixtures/events/missing-model.jsonl +1 -0
  335. package/tests/fixtures/events/missing-output.jsonl +1 -0
  336. package/tests/fixtures/events/missing-provider.jsonl +1 -0
  337. package/tests/fixtures/events/missing-ts.jsonl +1 -0
  338. package/tests/fixtures/events/valid.csv +3 -0
  339. package/tests/fixtures/events/valid.json +1 -0
  340. package/tests/fixtures/events/valid.jsonl +2 -0
  341. package/tests/fixtures/events/with-callsite.jsonl +1 -0
  342. package/tests/fixtures/events/with-intent.jsonl +1 -0
  343. package/tests/fixtures/events/wrong-type.jsonl +1 -0
  344. package/tests/fixtures/repos/empty/.gitkeep +0 -0
  345. package/tests/fixtures/repos/hybrid-router/router.py +35 -0
  346. package/tests/fixtures/repos/saas-anthropic/agent.ts +27 -0
  347. package/tests/fixtures/repos/saas-openai/assistant.js +33 -0
  348. package/tests/fixtures/repos/saas-openai/client.py +26 -0
  349. package/tests/fixtures/repos/self-hosted-vllm/inference.py +22 -0
  350. package/tests/github-action.test.ts +292 -0
  351. package/tests/insights.test.ts +878 -0
  352. package/tests/joiner.test.ts +168 -0
  353. package/tests/performance/action-latency.test.ts +132 -0
  354. package/tests/performance/benchmark.test.ts +189 -0
  355. package/tests/performance/cli-latency.test.ts +102 -0
  356. package/tests/pr-comment.test.ts +313 -0
  357. package/tests/prediction.test.ts +296 -0
  358. package/tests/runtime-analyzer.test.ts +375 -0
  359. package/tests/runtime.test.ts +205 -0
  360. package/tests/scanner.test.ts +122 -0
  361. package/tests/template-conformance.test.ts +526 -0
  362. package/tests/unit/cost-calculator.test.ts +303 -0
  363. package/tests/unit/credits.test.ts +180 -0
  364. package/tests/unit/inference-map.test.ts +276 -0
  365. package/tests/unit/schema.test.ts +300 -0
  366. package/tsconfig.json +20 -0
  367. package/vitest.config.ts +14 -0
package/src/config.ts ADDED
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Config Module (v1.6)
3
+ *
4
+ * Central configuration resolution for PeakInfer.
5
+ * Resolution chain: CLI flags → env vars → global config → local config → defaults
6
+ */
7
+
8
+ import { existsSync, readFileSync } from 'fs';
9
+ import { join } from 'path';
10
+ import { homedir } from 'os';
11
+ import { parse as parseYAML } from 'yaml';
12
+
13
+ // =============================================================================
14
+ // CONSTANTS
15
+ // =============================================================================
16
+
17
+ const GLOBAL_CONFIG_DIR = join(homedir(), '.peakinfer');
18
+ const GLOBAL_CONFIG_FILE = join(GLOBAL_CONFIG_DIR, 'config.yaml');
19
+ const LOCAL_CONFIG_FILE = 'peakinfer.yaml';
20
+
21
+ // =============================================================================
22
+ // TYPES
23
+ // =============================================================================
24
+
25
+ export interface PeakInferConfig {
26
+ apiKey?: string;
27
+ provider: 'anthropic';
28
+ model: string;
29
+ analysisMode: 'agent' | 'llm' | 'regex';
30
+ maxFileSize: number;
31
+ historyRetentionDays: number;
32
+ verbose: boolean;
33
+ }
34
+
35
+ export interface ConfigOverrides {
36
+ apiKey?: string;
37
+ model?: string;
38
+ analysisMode?: string;
39
+ verbose?: boolean;
40
+ }
41
+
42
+ interface ConfigFile {
43
+ apiKey?: string;
44
+ model?: string;
45
+ analysisMode?: string;
46
+ verbose?: boolean;
47
+ maxFileSize?: number;
48
+ historyRetentionDays?: number;
49
+ }
50
+
51
+ // =============================================================================
52
+ // DEFAULTS
53
+ // =============================================================================
54
+
55
+ const DEFAULT_CONFIG: PeakInferConfig = {
56
+ provider: 'anthropic',
57
+ model: 'claude-sonnet-4-20250514',
58
+ analysisMode: 'agent',
59
+ maxFileSize: 1048576, // 1MB
60
+ historyRetentionDays: 90,
61
+ verbose: false,
62
+ };
63
+
64
+ // =============================================================================
65
+ // LOADERS
66
+ // =============================================================================
67
+
68
+ /**
69
+ * Load global config from ~/.peakinfer/config.yaml
70
+ */
71
+ function loadGlobalConfig(): ConfigFile {
72
+ if (!existsSync(GLOBAL_CONFIG_FILE)) {
73
+ return {};
74
+ }
75
+ try {
76
+ const content = readFileSync(GLOBAL_CONFIG_FILE, 'utf-8');
77
+ return parseYAML(content) || {};
78
+ } catch {
79
+ return {};
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Load local config from ./peakinfer.yaml
85
+ */
86
+ function loadLocalConfig(): ConfigFile {
87
+ if (!existsSync(LOCAL_CONFIG_FILE)) {
88
+ return {};
89
+ }
90
+ try {
91
+ const content = readFileSync(LOCAL_CONFIG_FILE, 'utf-8');
92
+ return parseYAML(content) || {};
93
+ } catch {
94
+ return {};
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Get API key from environment variables
100
+ */
101
+ function getEnvApiKey(): string | undefined {
102
+ // Check ANTHROPIC_API_KEY (Claude Agent SDK)
103
+ if (process.env.ANTHROPIC_API_KEY) {
104
+ return process.env.ANTHROPIC_API_KEY;
105
+ }
106
+ // Generic fallback
107
+ return process.env.PEAKINFER_API_KEY;
108
+ }
109
+
110
+ /**
111
+ * Get model from environment
112
+ */
113
+ function getEnvModel(): string | undefined {
114
+ return process.env.PEAKINFER_MODEL;
115
+ }
116
+
117
+ // =============================================================================
118
+ // RESOLUTION
119
+ // =============================================================================
120
+
121
+ /**
122
+ * Resolve configuration from all sources.
123
+ * Priority: CLI overrides → env vars → global config → local config → defaults
124
+ */
125
+ export function resolveConfig(overrides: ConfigOverrides = {}): PeakInferConfig {
126
+ const local = loadLocalConfig();
127
+ const global = loadGlobalConfig();
128
+
129
+ // Start with defaults
130
+ const config: PeakInferConfig = { ...DEFAULT_CONFIG };
131
+
132
+ // Layer 1: Local config file (./peakinfer.yaml)
133
+ if (local.model) config.model = local.model;
134
+ if (local.analysisMode) config.analysisMode = local.analysisMode as PeakInferConfig['analysisMode'];
135
+ if (local.verbose !== undefined) config.verbose = local.verbose;
136
+ if (local.maxFileSize) config.maxFileSize = local.maxFileSize;
137
+ if (local.historyRetentionDays) config.historyRetentionDays = local.historyRetentionDays;
138
+ if (local.apiKey) config.apiKey = local.apiKey;
139
+
140
+ // Layer 2: Global config file (~/.peakinfer/config.yaml)
141
+ if (global.model) config.model = global.model;
142
+ if (global.analysisMode) config.analysisMode = global.analysisMode as PeakInferConfig['analysisMode'];
143
+ if (global.verbose !== undefined) config.verbose = global.verbose;
144
+ if (global.maxFileSize) config.maxFileSize = global.maxFileSize;
145
+ if (global.historyRetentionDays) config.historyRetentionDays = global.historyRetentionDays;
146
+ if (global.apiKey) config.apiKey = global.apiKey;
147
+
148
+ // Layer 3: Environment variables
149
+ const envApiKey = getEnvApiKey();
150
+ const envModel = getEnvModel();
151
+ const envVerbose = process.env.PEAKINFER_VERBOSE;
152
+
153
+ if (envApiKey) config.apiKey = envApiKey;
154
+ if (envModel) config.model = envModel;
155
+ if (envVerbose === '1' || envVerbose === 'true') config.verbose = true;
156
+
157
+ // Layer 4: CLI overrides (highest priority)
158
+ if (overrides.apiKey) config.apiKey = overrides.apiKey;
159
+ if (overrides.model) config.model = overrides.model;
160
+ if (overrides.analysisMode) config.analysisMode = overrides.analysisMode as PeakInferConfig['analysisMode'];
161
+ if (overrides.verbose !== undefined) config.verbose = overrides.verbose;
162
+
163
+ return config;
164
+ }
165
+
166
+ /**
167
+ * Get the resolved API key (convenience function)
168
+ */
169
+ export function getApiKey(): string | undefined {
170
+ return resolveConfig().apiKey;
171
+ }
172
+
173
+ /**
174
+ * Check if API key is configured
175
+ */
176
+ export function hasApiKey(): boolean {
177
+ return !!getApiKey();
178
+ }
179
+
180
+ /**
181
+ * Get config file paths for reference
182
+ */
183
+ export function getConfigPaths(): { global: string; local: string } {
184
+ return {
185
+ global: GLOBAL_CONFIG_FILE,
186
+ local: LOCAL_CONFIG_FILE,
187
+ };
188
+ }
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Helicone API Connector
3
+ *
4
+ * Fetches LLM request logs from Helicone's API.
5
+ * Docs: https://docs.helicone.ai/rest/request/post-v1requestquery
6
+ */
7
+
8
+ import {
9
+ ConnectorConfig,
10
+ ConnectorResult,
11
+ ConnectorError,
12
+ NormalizedEvent,
13
+ calculateSummary,
14
+ } from './types.js';
15
+
16
+ const HELICONE_API_URL = 'https://api.helicone.ai/v1/request/query';
17
+
18
+ interface HeliconeRequest {
19
+ request_id: string;
20
+ created_at: string;
21
+ model: string;
22
+ provider: string;
23
+ request_path: string;
24
+ response_status: number;
25
+ latency_ms: number;
26
+ prompt_tokens?: number;
27
+ completion_tokens?: number;
28
+ total_tokens?: number;
29
+ cost_usd?: number;
30
+ user_id?: string;
31
+ properties?: Record<string, string>;
32
+ request_body?: {
33
+ stream?: boolean;
34
+ model?: string;
35
+ };
36
+ response_body?: {
37
+ error?: { message?: string };
38
+ };
39
+ }
40
+
41
+ interface HeliconeResponse {
42
+ data: HeliconeRequest[];
43
+ error?: string;
44
+ }
45
+
46
+ function normalizeHeliconeEvent(req: HeliconeRequest): NormalizedEvent {
47
+ const isSuccess = req.response_status >= 200 && req.response_status < 400;
48
+ const isStreaming = req.request_body?.stream === true;
49
+
50
+ return {
51
+ id: req.request_id,
52
+ timestamp: req.created_at,
53
+ model: req.model || req.request_body?.model || 'unknown',
54
+ provider: normalizeProvider(req.provider),
55
+ latency_ms: req.latency_ms,
56
+ prompt_tokens: req.prompt_tokens,
57
+ completion_tokens: req.completion_tokens,
58
+ total_tokens: req.total_tokens,
59
+ cost_usd: req.cost_usd,
60
+ success: isSuccess,
61
+ error: !isSuccess ? req.response_body?.error?.message : undefined,
62
+ streaming: isStreaming,
63
+ request_path: req.request_path,
64
+ user_id: req.user_id,
65
+ raw: req as unknown as Record<string, unknown>,
66
+ };
67
+ }
68
+
69
+ function normalizeProvider(provider: string): string {
70
+ const providerMap: Record<string, string> = {
71
+ 'openai': 'openai',
72
+ 'openai-azure': 'azure-openai',
73
+ 'azure': 'azure-openai',
74
+ 'anthropic': 'anthropic',
75
+ 'google': 'google',
76
+ 'vertex': 'google-vertex',
77
+ 'aws': 'aws-bedrock',
78
+ 'bedrock': 'aws-bedrock',
79
+ 'together': 'together',
80
+ 'fireworks': 'fireworks',
81
+ 'groq': 'groq',
82
+ 'deepseek': 'deepseek',
83
+ };
84
+
85
+ return providerMap[provider.toLowerCase()] || provider.toLowerCase();
86
+ }
87
+
88
+ export async function fetchHeliconeEvents(
89
+ config: ConnectorConfig
90
+ ): Promise<ConnectorResult> {
91
+ const limit = config.limit || 1000;
92
+
93
+ // Build filter
94
+ const filter: Record<string, unknown> = {};
95
+
96
+ if (config.startDate) {
97
+ filter.created_at = { gte: config.startDate };
98
+ }
99
+
100
+ if (config.filter?.model) {
101
+ filter.model = { equals: config.filter.model };
102
+ }
103
+
104
+ if (config.filter?.success !== undefined) {
105
+ filter.response_status = config.filter.success
106
+ ? { gte: 200, lt: 400 }
107
+ : { gte: 400 };
108
+ }
109
+
110
+ try {
111
+ const response = await fetch(HELICONE_API_URL, {
112
+ method: 'POST',
113
+ headers: {
114
+ 'Authorization': `Bearer ${config.apiKey}`,
115
+ 'Content-Type': 'application/json',
116
+ },
117
+ body: JSON.stringify({
118
+ filter: Object.keys(filter).length > 0 ? filter : undefined,
119
+ limit,
120
+ sort: {
121
+ created_at: 'desc',
122
+ },
123
+ }),
124
+ });
125
+
126
+ if (!response.ok) {
127
+ const errorText = await response.text();
128
+ throw new ConnectorError(
129
+ `Helicone API error: ${response.status} ${errorText}`,
130
+ 'helicone',
131
+ response.status
132
+ );
133
+ }
134
+
135
+ const data = await response.json() as HeliconeResponse;
136
+
137
+ if (data.error) {
138
+ throw new ConnectorError(data.error, 'helicone');
139
+ }
140
+
141
+ const events = (data.data || []).map(normalizeHeliconeEvent);
142
+ const summary = calculateSummary(events);
143
+
144
+ return {
145
+ events,
146
+ summary,
147
+ metadata: {
148
+ source: 'helicone',
149
+ fetched_at: new Date().toISOString(),
150
+ total_fetched: events.length,
151
+ truncated: events.length >= limit,
152
+ api_version: 'v1',
153
+ },
154
+ };
155
+ } catch (error) {
156
+ if (error instanceof ConnectorError) {
157
+ throw error;
158
+ }
159
+ throw new ConnectorError(
160
+ `Failed to fetch from Helicone: ${error instanceof Error ? error.message : 'Unknown error'}`,
161
+ 'helicone'
162
+ );
163
+ }
164
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Runtime Data Connectors
3
+ *
4
+ * Unified interface for fetching LLM runtime data from various sources.
5
+ * Supports: Helicone, LangSmith
6
+ *
7
+ * Usage:
8
+ * const result = await fetchRuntimeData({
9
+ * source: 'helicone',
10
+ * apiKey: process.env.HELICONE_API_KEY,
11
+ * limit: 1000,
12
+ * });
13
+ */
14
+
15
+ import { fetchHeliconeEvents } from './helicone.js';
16
+ import { fetchLangSmithTraces } from './langsmith.js';
17
+ import {
18
+ ConnectorConfig,
19
+ ConnectorResult,
20
+ ConnectorError,
21
+ NormalizedEvent,
22
+ ConnectorSummary,
23
+ } from './types.js';
24
+
25
+ export type RuntimeSource = 'helicone' | 'langsmith';
26
+
27
+ export interface FetchRuntimeOptions extends Omit<ConnectorConfig, 'apiKey'> {
28
+ source: RuntimeSource;
29
+ apiKey: string;
30
+ }
31
+
32
+ /**
33
+ * Fetch runtime data from the specified source
34
+ */
35
+ export async function fetchRuntimeData(options: FetchRuntimeOptions): Promise<ConnectorResult> {
36
+ const { source, ...config } = options;
37
+
38
+ switch (source) {
39
+ case 'helicone':
40
+ return fetchHeliconeEvents(config);
41
+ case 'langsmith':
42
+ return fetchLangSmithTraces(config);
43
+ default:
44
+ throw new ConnectorError(
45
+ `Unknown runtime source: ${source}. Supported sources: helicone, langsmith`,
46
+ source as RuntimeSource
47
+ );
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Get API key from environment for the given source
53
+ */
54
+ export function getApiKeyFromEnv(source: RuntimeSource): string | undefined {
55
+ const envVarMap: Record<RuntimeSource, string[]> = {
56
+ helicone: ['HELICONE_API_KEY', 'HELICONE_KEY'],
57
+ langsmith: ['LANGSMITH_API_KEY', 'LANGCHAIN_API_KEY'],
58
+ };
59
+
60
+ const envVars = envVarMap[source] || [];
61
+ for (const envVar of envVars) {
62
+ const value = process.env[envVar];
63
+ if (value) return value;
64
+ }
65
+ return undefined;
66
+ }
67
+
68
+ /**
69
+ * Validate that the source is supported
70
+ */
71
+ export function isValidSource(source: string): source is RuntimeSource {
72
+ return source === 'helicone' || source === 'langsmith';
73
+ }
74
+
75
+ /**
76
+ * Get a human-readable description of the source
77
+ */
78
+ export function getSourceDescription(source: RuntimeSource): string {
79
+ const descriptions: Record<RuntimeSource, string> = {
80
+ helicone: 'Helicone LLM Observability',
81
+ langsmith: 'LangSmith Tracing',
82
+ };
83
+ return descriptions[source] || source;
84
+ }
85
+
86
+ // Re-export types
87
+ export {
88
+ ConnectorConfig,
89
+ ConnectorResult,
90
+ ConnectorError,
91
+ NormalizedEvent,
92
+ ConnectorSummary,
93
+ } from './types.js';
@@ -0,0 +1,179 @@
1
+ /**
2
+ * LangSmith API Connector
3
+ *
4
+ * Fetches LLM traces from LangSmith's API.
5
+ * Docs: https://docs.smith.langchain.com/reference/api
6
+ */
7
+
8
+ import {
9
+ ConnectorConfig,
10
+ ConnectorResult,
11
+ ConnectorError,
12
+ NormalizedEvent,
13
+ calculateSummary,
14
+ } from './types.js';
15
+
16
+ const LANGSMITH_API_URL = 'https://api.smith.langchain.com';
17
+
18
+ interface LangSmithRun {
19
+ id: string;
20
+ name: string;
21
+ run_type: string;
22
+ start_time: string;
23
+ end_time?: string;
24
+ status: string;
25
+ error?: string;
26
+ inputs?: Record<string, unknown>;
27
+ outputs?: Record<string, unknown>;
28
+ extra?: {
29
+ invocation_params?: {
30
+ model?: string;
31
+ model_name?: string;
32
+ stream?: boolean;
33
+ };
34
+ metadata?: Record<string, unknown>;
35
+ };
36
+ total_tokens?: number;
37
+ prompt_tokens?: number;
38
+ completion_tokens?: number;
39
+ total_cost?: number;
40
+ trace_id?: string;
41
+ parent_run_id?: string;
42
+ session_id?: string;
43
+ }
44
+
45
+ interface LangSmithResponse {
46
+ runs?: LangSmithRun[];
47
+ cursors?: {
48
+ next?: string;
49
+ };
50
+ }
51
+
52
+ function normalizeProvider(runName: string, invocationParams?: Record<string, unknown>): string {
53
+ const nameLower = runName.toLowerCase();
54
+
55
+ if (nameLower.includes('openai') || nameLower.includes('gpt')) return 'openai';
56
+ if (nameLower.includes('anthropic') || nameLower.includes('claude')) return 'anthropic';
57
+ if (nameLower.includes('azure')) return 'azure-openai';
58
+ if (nameLower.includes('bedrock')) return 'aws-bedrock';
59
+ if (nameLower.includes('vertex') || nameLower.includes('palm') || nameLower.includes('gemini')) return 'google';
60
+ if (nameLower.includes('together')) return 'together';
61
+ if (nameLower.includes('fireworks')) return 'fireworks';
62
+ if (nameLower.includes('groq')) return 'groq';
63
+
64
+ // Check invocation params
65
+ const modelName = invocationParams?.model_name || invocationParams?.model;
66
+ if (typeof modelName === 'string') {
67
+ if (modelName.includes('gpt')) return 'openai';
68
+ if (modelName.includes('claude')) return 'anthropic';
69
+ if (modelName.includes('gemini')) return 'google';
70
+ }
71
+
72
+ return 'unknown';
73
+ }
74
+
75
+ function normalizeLangSmithRun(run: LangSmithRun): NormalizedEvent | null {
76
+ // Only include LLM runs
77
+ if (run.run_type !== 'llm') {
78
+ return null;
79
+ }
80
+
81
+ const startTime = new Date(run.start_time).getTime();
82
+ const endTime = run.end_time ? new Date(run.end_time).getTime() : startTime;
83
+ const latencyMs = endTime - startTime;
84
+
85
+ const invocationParams = run.extra?.invocation_params;
86
+ const model = invocationParams?.model || invocationParams?.model_name || 'unknown';
87
+ const isStreaming = invocationParams?.stream === true;
88
+ const isSuccess = run.status === 'success' || run.status === 'completed';
89
+
90
+ return {
91
+ id: run.id,
92
+ timestamp: run.start_time,
93
+ model: typeof model === 'string' ? model : 'unknown',
94
+ provider: normalizeProvider(run.name, invocationParams),
95
+ latency_ms: Math.max(0, latencyMs),
96
+ prompt_tokens: run.prompt_tokens,
97
+ completion_tokens: run.completion_tokens,
98
+ total_tokens: run.total_tokens,
99
+ cost_usd: run.total_cost,
100
+ success: isSuccess,
101
+ error: run.error,
102
+ streaming: isStreaming,
103
+ trace_id: run.trace_id,
104
+ parent_span_id: run.parent_run_id,
105
+ session_id: run.session_id,
106
+ raw: run as unknown as Record<string, unknown>,
107
+ };
108
+ }
109
+
110
+ export async function fetchLangSmithTraces(
111
+ config: ConnectorConfig
112
+ ): Promise<ConnectorResult> {
113
+ const limit = config.limit || 1000;
114
+
115
+ // Build query params
116
+ const params = new URLSearchParams();
117
+ params.set('limit', limit.toString());
118
+ params.set('run_type', 'llm'); // Only fetch LLM runs
119
+ params.set('is_root', 'false'); // Include nested runs
120
+
121
+ if (config.startDate) {
122
+ params.set('start_time', config.startDate);
123
+ }
124
+
125
+ if (config.endDate) {
126
+ params.set('end_time', config.endDate);
127
+ }
128
+
129
+ if (config.filter?.success !== undefined) {
130
+ params.set('error', config.filter.success ? 'false' : 'true');
131
+ }
132
+
133
+ try {
134
+ const response = await fetch(`${LANGSMITH_API_URL}/runs?${params.toString()}`, {
135
+ method: 'GET',
136
+ headers: {
137
+ 'X-API-Key': config.apiKey,
138
+ 'Content-Type': 'application/json',
139
+ },
140
+ });
141
+
142
+ if (!response.ok) {
143
+ const errorText = await response.text();
144
+ throw new ConnectorError(
145
+ `LangSmith API error: ${response.status} ${errorText}`,
146
+ 'langsmith',
147
+ response.status
148
+ );
149
+ }
150
+
151
+ const data = await response.json() as LangSmithResponse;
152
+
153
+ const events = (data.runs || [])
154
+ .map(normalizeLangSmithRun)
155
+ .filter((e): e is NormalizedEvent => e !== null);
156
+
157
+ const summary = calculateSummary(events);
158
+
159
+ return {
160
+ events,
161
+ summary,
162
+ metadata: {
163
+ source: 'langsmith',
164
+ fetched_at: new Date().toISOString(),
165
+ total_fetched: events.length,
166
+ truncated: data.cursors?.next !== undefined,
167
+ api_version: 'v1',
168
+ },
169
+ };
170
+ } catch (error) {
171
+ if (error instanceof ConnectorError) {
172
+ throw error;
173
+ }
174
+ throw new ConnectorError(
175
+ `Failed to fetch from LangSmith: ${error instanceof Error ? error.message : 'Unknown error'}`,
176
+ 'langsmith'
177
+ );
178
+ }
179
+ }