@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.
- package/.claude/settings.local.json +8 -0
- package/.env.example +6 -0
- package/.github/workflows/peakinfer.yml +64 -0
- package/CHANGELOG.md +31 -0
- package/LICENSE +190 -0
- package/README.md +335 -0
- package/data/inferencemax.json +274 -0
- package/dist/agent-analyzer.d.ts +45 -0
- package/dist/agent-analyzer.d.ts.map +1 -0
- package/dist/agent-analyzer.js +374 -0
- package/dist/agent-analyzer.js.map +1 -0
- package/dist/agent.d.ts +76 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +965 -0
- package/dist/agent.js.map +1 -0
- package/dist/agents/correlation-analyzer.d.ts +34 -0
- package/dist/agents/correlation-analyzer.d.ts.map +1 -0
- package/dist/agents/correlation-analyzer.js +261 -0
- package/dist/agents/correlation-analyzer.js.map +1 -0
- package/dist/agents/index.d.ts +91 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +111 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/runtime-analyzer.d.ts +38 -0
- package/dist/agents/runtime-analyzer.d.ts.map +1 -0
- package/dist/agents/runtime-analyzer.js +244 -0
- package/dist/agents/runtime-analyzer.js.map +1 -0
- package/dist/analysis-types.d.ts +500 -0
- package/dist/analysis-types.d.ts.map +1 -0
- package/dist/analysis-types.js +11 -0
- package/dist/analysis-types.js.map +1 -0
- package/dist/analytics.d.ts +25 -0
- package/dist/analytics.d.ts.map +1 -0
- package/dist/analytics.js +94 -0
- package/dist/analytics.js.map +1 -0
- package/dist/analyzer.d.ts +48 -0
- package/dist/analyzer.d.ts.map +1 -0
- package/dist/analyzer.js +547 -0
- package/dist/analyzer.js.map +1 -0
- package/dist/artifacts.d.ts +44 -0
- package/dist/artifacts.d.ts.map +1 -0
- package/dist/artifacts.js +165 -0
- package/dist/artifacts.js.map +1 -0
- package/dist/benchmarks/index.d.ts +88 -0
- package/dist/benchmarks/index.d.ts.map +1 -0
- package/dist/benchmarks/index.js +205 -0
- package/dist/benchmarks/index.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +427 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/ci.d.ts +19 -0
- package/dist/commands/ci.d.ts.map +1 -0
- package/dist/commands/ci.js +253 -0
- package/dist/commands/ci.js.map +1 -0
- package/dist/commands/config.d.ts +16 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +249 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/demo.d.ts +15 -0
- package/dist/commands/demo.d.ts.map +1 -0
- package/dist/commands/demo.js +106 -0
- package/dist/commands/demo.js.map +1 -0
- package/dist/commands/export.d.ts +14 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +209 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/history.d.ts +15 -0
- package/dist/commands/history.d.ts.map +1 -0
- package/dist/commands/history.js +389 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/template.d.ts +14 -0
- package/dist/commands/template.d.ts.map +1 -0
- package/dist/commands/template.js +341 -0
- package/dist/commands/template.js.map +1 -0
- package/dist/commands/validate-map.d.ts +12 -0
- package/dist/commands/validate-map.d.ts.map +1 -0
- package/dist/commands/validate-map.js +274 -0
- package/dist/commands/validate-map.js.map +1 -0
- package/dist/commands/whatif.d.ts +17 -0
- package/dist/commands/whatif.d.ts.map +1 -0
- package/dist/commands/whatif.js +206 -0
- package/dist/commands/whatif.js.map +1 -0
- package/dist/comparison.d.ts +38 -0
- package/dist/comparison.d.ts.map +1 -0
- package/dist/comparison.js +223 -0
- package/dist/comparison.js.map +1 -0
- package/dist/config.d.ts +42 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +158 -0
- package/dist/config.js.map +1 -0
- package/dist/connectors/helicone.d.ts +9 -0
- package/dist/connectors/helicone.d.ts.map +1 -0
- package/dist/connectors/helicone.js +106 -0
- package/dist/connectors/helicone.js.map +1 -0
- package/dist/connectors/index.d.ts +37 -0
- package/dist/connectors/index.d.ts.map +1 -0
- package/dist/connectors/index.js +65 -0
- package/dist/connectors/index.js.map +1 -0
- package/dist/connectors/langsmith.d.ts +9 -0
- package/dist/connectors/langsmith.d.ts.map +1 -0
- package/dist/connectors/langsmith.js +122 -0
- package/dist/connectors/langsmith.js.map +1 -0
- package/dist/connectors/types.d.ts +83 -0
- package/dist/connectors/types.d.ts.map +1 -0
- package/dist/connectors/types.js +98 -0
- package/dist/connectors/types.js.map +1 -0
- package/dist/cost-estimator.d.ts +46 -0
- package/dist/cost-estimator.d.ts.map +1 -0
- package/dist/cost-estimator.js +104 -0
- package/dist/cost-estimator.js.map +1 -0
- package/dist/costs.d.ts +57 -0
- package/dist/costs.d.ts.map +1 -0
- package/dist/costs.js +251 -0
- package/dist/costs.js.map +1 -0
- package/dist/counterfactuals.d.ts +29 -0
- package/dist/counterfactuals.d.ts.map +1 -0
- package/dist/counterfactuals.js +448 -0
- package/dist/counterfactuals.js.map +1 -0
- package/dist/enhancement-prompts.d.ts +41 -0
- package/dist/enhancement-prompts.d.ts.map +1 -0
- package/dist/enhancement-prompts.js +88 -0
- package/dist/enhancement-prompts.js.map +1 -0
- package/dist/envelopes.d.ts +20 -0
- package/dist/envelopes.d.ts.map +1 -0
- package/dist/envelopes.js +790 -0
- package/dist/envelopes.js.map +1 -0
- package/dist/format-normalizer.d.ts +71 -0
- package/dist/format-normalizer.d.ts.map +1 -0
- package/dist/format-normalizer.js +1331 -0
- package/dist/format-normalizer.js.map +1 -0
- package/dist/history.d.ts +79 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +313 -0
- package/dist/history.js.map +1 -0
- package/dist/html.d.ts +11 -0
- package/dist/html.d.ts.map +1 -0
- package/dist/html.js +463 -0
- package/dist/html.js.map +1 -0
- package/dist/impact.d.ts +42 -0
- package/dist/impact.d.ts.map +1 -0
- package/dist/impact.js +443 -0
- package/dist/impact.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/insights.d.ts +5 -0
- package/dist/insights.d.ts.map +1 -0
- package/dist/insights.js +271 -0
- package/dist/insights.js.map +1 -0
- package/dist/joiner.d.ts +9 -0
- package/dist/joiner.d.ts.map +1 -0
- package/dist/joiner.js +247 -0
- package/dist/joiner.js.map +1 -0
- package/dist/orchestrator.d.ts +34 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +827 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/pdf.d.ts +26 -0
- package/dist/pdf.d.ts.map +1 -0
- package/dist/pdf.js +84 -0
- package/dist/pdf.js.map +1 -0
- package/dist/prediction.d.ts +33 -0
- package/dist/prediction.d.ts.map +1 -0
- package/dist/prediction.js +316 -0
- package/dist/prediction.js.map +1 -0
- package/dist/prompts/loader.d.ts +38 -0
- package/dist/prompts/loader.d.ts.map +1 -0
- package/dist/prompts/loader.js +60 -0
- package/dist/prompts/loader.js.map +1 -0
- package/dist/renderer.d.ts +64 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/renderer.js +923 -0
- package/dist/renderer.js.map +1 -0
- package/dist/runid.d.ts +57 -0
- package/dist/runid.d.ts.map +1 -0
- package/dist/runid.js +199 -0
- package/dist/runid.js.map +1 -0
- package/dist/runtime.d.ts +29 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +366 -0
- package/dist/runtime.js.map +1 -0
- package/dist/scanner.d.ts +11 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +426 -0
- package/dist/scanner.js.map +1 -0
- package/dist/templates.d.ts +120 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +429 -0
- package/dist/templates.js.map +1 -0
- package/dist/tools/index.d.ts +153 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +177 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/types.d.ts +3647 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +703 -0
- package/dist/types.js.map +1 -0
- package/dist/version.d.ts +7 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +23 -0
- package/dist/version.js.map +1 -0
- package/docs/demo-guide.md +423 -0
- package/docs/events-format.md +295 -0
- package/docs/inferencemap-spec.md +344 -0
- package/docs/migration-v2.md +293 -0
- package/fixtures/demo/precomputed.json +142 -0
- package/fixtures/demo-project/README.md +52 -0
- package/fixtures/demo-project/ai-service.ts +65 -0
- package/fixtures/demo-project/sample-events.jsonl +15 -0
- package/fixtures/demo-project/src/ai-service.ts +128 -0
- package/fixtures/demo-project/src/llm-client.ts +155 -0
- package/package.json +65 -0
- package/prompts/agent-analyzer.yaml +47 -0
- package/prompts/ci-gate.yaml +98 -0
- package/prompts/correlation-analyzer.yaml +178 -0
- package/prompts/format-normalizer.yaml +46 -0
- package/prompts/peak-performance.yaml +180 -0
- package/prompts/pr-comment.yaml +111 -0
- package/prompts/runtime-analyzer.yaml +189 -0
- package/prompts/unified-analyzer.yaml +241 -0
- package/schemas/inference-map.v0.1.json +215 -0
- package/scripts/benchmark.ts +394 -0
- package/scripts/demo-v1.5.sh +158 -0
- package/scripts/sync-from-site.sh +197 -0
- package/scripts/validate-sync.sh +178 -0
- package/src/agent-analyzer.ts +481 -0
- package/src/agent.ts +1232 -0
- package/src/agents/correlation-analyzer.ts +353 -0
- package/src/agents/index.ts +235 -0
- package/src/agents/runtime-analyzer.ts +343 -0
- package/src/analysis-types.ts +558 -0
- package/src/analytics.ts +100 -0
- package/src/analyzer.ts +692 -0
- package/src/artifacts.ts +218 -0
- package/src/benchmarks/index.ts +309 -0
- package/src/cli.ts +503 -0
- package/src/commands/ci.ts +336 -0
- package/src/commands/config.ts +288 -0
- package/src/commands/demo.ts +175 -0
- package/src/commands/export.ts +297 -0
- package/src/commands/history.ts +425 -0
- package/src/commands/template.ts +385 -0
- package/src/commands/validate-map.ts +324 -0
- package/src/commands/whatif.ts +272 -0
- package/src/comparison.ts +283 -0
- package/src/config.ts +188 -0
- package/src/connectors/helicone.ts +164 -0
- package/src/connectors/index.ts +93 -0
- package/src/connectors/langsmith.ts +179 -0
- package/src/connectors/types.ts +180 -0
- package/src/cost-estimator.ts +146 -0
- package/src/costs.ts +347 -0
- package/src/counterfactuals.ts +516 -0
- package/src/enhancement-prompts.ts +118 -0
- package/src/envelopes.ts +814 -0
- package/src/format-normalizer.ts +1486 -0
- package/src/history.ts +400 -0
- package/src/html.ts +512 -0
- package/src/impact.ts +522 -0
- package/src/index.ts +83 -0
- package/src/insights.ts +341 -0
- package/src/joiner.ts +289 -0
- package/src/orchestrator.ts +1015 -0
- package/src/pdf.ts +110 -0
- package/src/prediction.ts +392 -0
- package/src/prompts/loader.ts +88 -0
- package/src/renderer.ts +1045 -0
- package/src/runid.ts +261 -0
- package/src/runtime.ts +450 -0
- package/src/scanner.ts +508 -0
- package/src/templates.ts +561 -0
- package/src/tools/index.ts +214 -0
- package/src/types.ts +873 -0
- package/src/version.ts +24 -0
- package/templates/context-accumulation.yaml +23 -0
- package/templates/cost-concentration.yaml +20 -0
- package/templates/dead-code.yaml +20 -0
- package/templates/latency-explainer.yaml +23 -0
- package/templates/optimizations/ab-testing-framework.yaml +74 -0
- package/templates/optimizations/api-gateway-optimization.yaml +81 -0
- package/templates/optimizations/api-model-routing-strategy.yaml +126 -0
- package/templates/optimizations/auto-scaling-optimization.yaml +85 -0
- package/templates/optimizations/batch-utilization-diagnostic.yaml +142 -0
- package/templates/optimizations/comprehensive-apm.yaml +76 -0
- package/templates/optimizations/context-window-optimization.yaml +91 -0
- package/templates/optimizations/cost-sensitive-batch-processing.yaml +77 -0
- package/templates/optimizations/distributed-training-optimization.yaml +77 -0
- package/templates/optimizations/document-analysis-edge.yaml +77 -0
- package/templates/optimizations/document-pipeline-optimization.yaml +78 -0
- package/templates/optimizations/domain-specific-distillation.yaml +78 -0
- package/templates/optimizations/error-handling-optimization.yaml +76 -0
- package/templates/optimizations/gptq-4bit-quantization.yaml +96 -0
- package/templates/optimizations/long-context-memory-management.yaml +78 -0
- package/templates/optimizations/max-tokens-optimization.yaml +76 -0
- package/templates/optimizations/memory-bandwidth-optimization.yaml +73 -0
- package/templates/optimizations/multi-framework-resilience.yaml +75 -0
- package/templates/optimizations/multi-tenant-optimization.yaml +75 -0
- package/templates/optimizations/prompt-caching-optimization.yaml +143 -0
- package/templates/optimizations/pytorch-to-onnx-migration.yaml +109 -0
- package/templates/optimizations/quality-monitoring.yaml +74 -0
- package/templates/optimizations/realtime-budget-controls.yaml +74 -0
- package/templates/optimizations/realtime-latency-optimization.yaml +74 -0
- package/templates/optimizations/sglang-concurrency-optimization.yaml +78 -0
- package/templates/optimizations/smart-model-routing.yaml +96 -0
- package/templates/optimizations/streaming-batch-selection.yaml +167 -0
- package/templates/optimizations/system-prompt-optimization.yaml +75 -0
- package/templates/optimizations/tensorrt-llm-performance.yaml +77 -0
- package/templates/optimizations/vllm-high-throughput-optimization.yaml +93 -0
- package/templates/optimizations/vllm-migration-memory-bound.yaml +78 -0
- package/templates/overpowered-extraction.yaml +32 -0
- package/templates/overpowered-model.yaml +31 -0
- package/templates/prompt-bloat.yaml +24 -0
- package/templates/retry-explosion.yaml +28 -0
- package/templates/schema/insight.schema.json +113 -0
- package/templates/schema/optimization.schema.json +180 -0
- package/templates/streaming-drift.yaml +30 -0
- package/templates/throughput-gap.yaml +21 -0
- package/templates/token-underutilization.yaml +28 -0
- package/templates/untested-fallback.yaml +21 -0
- package/tests/accuracy/drift-detection.test.ts +184 -0
- package/tests/accuracy/false-positives.test.ts +166 -0
- package/tests/accuracy/templates.test.ts +205 -0
- package/tests/action/commands.test.ts +125 -0
- package/tests/action/comments.test.ts +347 -0
- package/tests/cli.test.ts +203 -0
- package/tests/comparison.test.ts +309 -0
- package/tests/correlation-analyzer.test.ts +534 -0
- package/tests/counterfactuals.test.ts +347 -0
- package/tests/fixtures/events/missing-id.jsonl +1 -0
- package/tests/fixtures/events/missing-input.jsonl +1 -0
- package/tests/fixtures/events/missing-latency.jsonl +1 -0
- package/tests/fixtures/events/missing-model.jsonl +1 -0
- package/tests/fixtures/events/missing-output.jsonl +1 -0
- package/tests/fixtures/events/missing-provider.jsonl +1 -0
- package/tests/fixtures/events/missing-ts.jsonl +1 -0
- package/tests/fixtures/events/valid.csv +3 -0
- package/tests/fixtures/events/valid.json +1 -0
- package/tests/fixtures/events/valid.jsonl +2 -0
- package/tests/fixtures/events/with-callsite.jsonl +1 -0
- package/tests/fixtures/events/with-intent.jsonl +1 -0
- package/tests/fixtures/events/wrong-type.jsonl +1 -0
- package/tests/fixtures/repos/empty/.gitkeep +0 -0
- package/tests/fixtures/repos/hybrid-router/router.py +35 -0
- package/tests/fixtures/repos/saas-anthropic/agent.ts +27 -0
- package/tests/fixtures/repos/saas-openai/assistant.js +33 -0
- package/tests/fixtures/repos/saas-openai/client.py +26 -0
- package/tests/fixtures/repos/self-hosted-vllm/inference.py +22 -0
- package/tests/github-action.test.ts +292 -0
- package/tests/insights.test.ts +878 -0
- package/tests/joiner.test.ts +168 -0
- package/tests/performance/action-latency.test.ts +132 -0
- package/tests/performance/benchmark.test.ts +189 -0
- package/tests/performance/cli-latency.test.ts +102 -0
- package/tests/pr-comment.test.ts +313 -0
- package/tests/prediction.test.ts +296 -0
- package/tests/runtime-analyzer.test.ts +375 -0
- package/tests/runtime.test.ts +205 -0
- package/tests/scanner.test.ts +122 -0
- package/tests/template-conformance.test.ts +526 -0
- package/tests/unit/cost-calculator.test.ts +303 -0
- package/tests/unit/credits.test.ts +180 -0
- package/tests/unit/inference-map.test.ts +276 -0
- package/tests/unit/schema.test.ts +300 -0
- package/tsconfig.json +20 -0
- 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
|
+
}
|