@obsunified/collector 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +60 -0
- package/dist/auth.d.ts +2 -0
- package/dist/auth.js +9 -0
- package/dist/auth.js.map +1 -0
- package/dist/chunk-UGWDOGGH.js +319 -0
- package/dist/chunk-UGWDOGGH.js.map +1 -0
- package/dist/chunk-XKQTVIRE.js +671 -0
- package/dist/chunk-XKQTVIRE.js.map +1 -0
- package/dist/index.d.ts +1197 -0
- package/dist/index.js +17707 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest-auth-HFVO1zIp.d.ts +165 -0
- package/dist/openai-FJYOQ7WO.js +384 -0
- package/dist/openai-FJYOQ7WO.js.map +1 -0
- package/package.json +73 -0
- package/src/ai-parity/ai-parity.acceptance.test.ts +449 -0
- package/src/analyses/derive.ts +642 -0
- package/src/analyses/index.ts +50 -0
- package/src/analyses/investigations.ts +277 -0
- package/src/analyses/tier0.ts +568 -0
- package/src/auth/dashboard-auth.ts +269 -0
- package/src/auth/ingest-auth.ts +147 -0
- package/src/durable-objects/tail-hub.test.ts +32 -0
- package/src/durable-objects/tail-hub.ts +158 -0
- package/src/framework/collector.ts +467 -0
- package/src/framework/env.ts +90 -0
- package/src/framework/logger.ts +81 -0
- package/src/index.ts +211 -0
- package/src/lib/action-aggregates.ts +1031 -0
- package/src/lib/action-identity.ts +106 -0
- package/src/lib/actions-store.ts +397 -0
- package/src/lib/ai-pricing.ts +80 -0
- package/src/lib/ai-store/calls.ts +148 -0
- package/src/lib/ai-store/evaluations.test.ts +47 -0
- package/src/lib/ai-store/evaluations.ts +125 -0
- package/src/lib/ai-store/helpers.ts +37 -0
- package/src/lib/ai-store/retention.ts +17 -0
- package/src/lib/ai-store/sessions.ts +277 -0
- package/src/lib/ai-store/spans.ts +109 -0
- package/src/lib/ai-store/types.ts +112 -0
- package/src/lib/ai-store.ts +76 -0
- package/src/lib/alerts-store.ts +458 -0
- package/src/lib/analyses-runner.ts +439 -0
- package/src/lib/analyses-store.test.ts +243 -0
- package/src/lib/analyses-store.ts +454 -0
- package/src/lib/ask.test.ts +302 -0
- package/src/lib/ask.ts +390 -0
- package/src/lib/blob-store-s3.ts +213 -0
- package/src/lib/blob-store.ts +366 -0
- package/src/lib/eval-cases-store.test.ts +171 -0
- package/src/lib/eval-cases-store.ts +1033 -0
- package/src/lib/evidence-references.test.ts +10 -0
- package/src/lib/evidence-references.ts +684 -0
- package/src/lib/hash.ts +26 -0
- package/src/lib/identity-index/action-lookups.ts +805 -0
- package/src/lib/identity-index/constants.ts +1 -0
- package/src/lib/identity-index/key-lookups.ts +199 -0
- package/src/lib/identity-index/mappers.ts +349 -0
- package/src/lib/identity-index/types.ts +196 -0
- package/src/lib/identity-index/user-lookup.ts +137 -0
- package/src/lib/identity-index.test.ts +624 -0
- package/src/lib/identity-index.ts +85 -0
- package/src/lib/json.ts +39 -0
- package/src/lib/llm.ts +263 -0
- package/src/lib/logs-store.ts +188 -0
- package/src/lib/metrics-store.test.ts +189 -0
- package/src/lib/metrics-store.ts +312 -0
- package/src/lib/narrate-gate.test.ts +260 -0
- package/src/lib/narrate-gate.ts +253 -0
- package/src/lib/openai.test.ts +300 -0
- package/src/lib/openai.ts +512 -0
- package/src/lib/otlp.ts +212 -0
- package/src/lib/parse-pprof.test.ts +64 -0
- package/src/lib/parse-pprof.ts +184 -0
- package/src/lib/payload-capture.ts +22 -0
- package/src/lib/projects-store.ts +207 -0
- package/src/lib/propagation-metric.test.ts +196 -0
- package/src/lib/propagation-metric.ts +175 -0
- package/src/lib/sql-db-dialect.test.ts +22 -0
- package/src/lib/sql-db-postgres.ts +229 -0
- package/src/lib/sql-db.ts +166 -0
- package/src/lib/stage6.test.ts +216 -0
- package/src/lib/store/export.ts +65 -0
- package/src/lib/store/helpers.ts +367 -0
- package/src/lib/store/ingest.ts +68 -0
- package/src/lib/store/issues.ts +158 -0
- package/src/lib/store/overview.ts +127 -0
- package/src/lib/store/retention.ts +10 -0
- package/src/lib/store/service-map.ts +384 -0
- package/src/lib/store/trace-detail.bench.ts +76 -0
- package/src/lib/store/trace-detail.test.ts +410 -0
- package/src/lib/store/trace-detail.ts +427 -0
- package/src/lib/store/trace-queries.test.ts +29 -0
- package/src/lib/store/trace-queries.ts +89 -0
- package/src/lib/store-overview.test.ts +77 -0
- package/src/lib/store.ts +96 -0
- package/src/lib/tail-publisher.ts +64 -0
- package/src/lib/test-utils/mem-sql-db.test.ts +93 -0
- package/src/lib/test-utils/mem-sql-db.ts +86 -0
- package/src/lib/ua-parser.ts +61 -0
- package/src/lib/usage-store.ts +567 -0
- package/src/migrations/001_telemetry_spans.sql +28 -0
- package/src/migrations/002_usage_events.sql +24 -0
- package/src/migrations/003_usage_analytics_columns.sql +13 -0
- package/src/migrations/004_logs.sql +19 -0
- package/src/migrations/005_ai_calls.sql +25 -0
- package/src/migrations/006_user_profiles.sql +11 -0
- package/src/migrations/007_session_replay_metadata.sql +10 -0
- package/src/migrations/008_session_replay_storage_bytes.sql +1 -0
- package/src/migrations/009_projects_and_keys.sql +22 -0
- package/src/migrations/010_signal_project_id.sql +15 -0
- package/src/migrations/011_default_project_seed.sql +3 -0
- package/src/migrations/012_alert_rules.sql +17 -0
- package/src/migrations/013_alert_evaluations.sql +13 -0
- package/src/migrations/014_alert_state.sql +9 -0
- package/src/migrations/015_metrics.sql +58 -0
- package/src/migrations/016_metrics_exp_histogram_summary.sql +5 -0
- package/src/migrations/017_span_dropped_counts.sql +11 -0
- package/src/migrations/018_log_flags.sql +8 -0
- package/src/migrations/019_ai_span_payloads.sql +30 -0
- package/src/migrations/020_ai_span_evaluations.sql +33 -0
- package/src/migrations/021_ai_span_session.sql +13 -0
- package/src/migrations/022_span_log_session_id.sql +13 -0
- package/src/migrations/023_service_map_indexes.sql +32 -0
- package/src/migrations/024_analysis_results.sql +49 -0
- package/src/migrations/025_stage6_autopinning_alerts.sql +38 -0
- package/src/migrations/026_obs_dashboard_project_seed.sql +18 -0
- package/src/migrations/027_identity_propagation.sql +50 -0
- package/src/migrations/028_profile_blobs.sql +57 -0
- package/src/migrations/029_telemetry_sdk_name.sql +20 -0
- package/src/migrations/030_analysis_claim.sql +18 -0
- package/src/migrations/031_agent_action_graph.sql +154 -0
- package/src/migrations/032_payload_capture_flags.sql +8 -0
- package/src/migrations/033_eval_cases.sql +52 -0
- package/src/migrations/034_eval_case_results.sql +23 -0
- package/src/migrations/035_metric_exemplars.sql +33 -0
- package/src/migrations/036_trace_instrumentation_gaps.sql +19 -0
- package/src/migrations/037_eval_runs.sql +37 -0
- package/src/migrations/038_tool_call_evidence.sql +11 -0
- package/src/migrations/039_drop_trace_instrumentation_gaps.sql +11 -0
- package/src/migrations/040_evidence_retrieval_refs.sql +50 -0
- package/src/migrations-postgres/001_telemetry_spans.sql +33 -0
- package/src/migrations-postgres/002_usage_events.sql +24 -0
- package/src/migrations-postgres/003_usage_analytics_columns.sql +13 -0
- package/src/migrations-postgres/004_logs.sql +19 -0
- package/src/migrations-postgres/005_ai_calls.sql +25 -0
- package/src/migrations-postgres/006_user_profiles.sql +11 -0
- package/src/migrations-postgres/007_session_replay_metadata.sql +10 -0
- package/src/migrations-postgres/008_session_replay_storage_bytes.sql +2 -0
- package/src/migrations-postgres/009_projects_and_keys.sql +25 -0
- package/src/migrations-postgres/010_signal_project_id.sql +18 -0
- package/src/migrations-postgres/011_default_project_seed.sql +5 -0
- package/src/migrations-postgres/012_alert_rules.sql +17 -0
- package/src/migrations-postgres/013_alert_evaluations.sql +13 -0
- package/src/migrations-postgres/014_alert_state.sql +9 -0
- package/src/migrations-postgres/015_metrics.sql +47 -0
- package/src/migrations-postgres/016_metrics_exp_histogram_summary.sql +1 -0
- package/src/migrations-postgres/017_span_dropped_counts.sql +4 -0
- package/src/migrations-postgres/018_log_flags.sql +2 -0
- package/src/migrations-postgres/019_ai_span_payloads.sql +18 -0
- package/src/migrations-postgres/020_ai_span_evaluations.sql +21 -0
- package/src/migrations-postgres/021_ai_span_session.sql +7 -0
- package/src/migrations-postgres/022_span_log_session_id.sql +7 -0
- package/src/migrations-postgres/023_service_map_indexes.sql +9 -0
- package/src/migrations-postgres/024_analysis_results.sql +41 -0
- package/src/migrations-postgres/025_stage6_autopinning_alerts.sql +17 -0
- package/src/migrations-postgres/026_obs_dashboard_project_seed.sql +14 -0
- package/src/migrations-postgres/027_identity_propagation.sql +27 -0
- package/src/migrations-postgres/028_profile_blobs.sql +48 -0
- package/src/migrations-postgres/029_telemetry_sdk_name.sql +5 -0
- package/src/migrations-postgres/030_analysis_claim.sql +5 -0
- package/src/migrations-postgres/031_agent_action_graph.sql +190 -0
- package/src/migrations-postgres/032_payload_capture_flags.sql +8 -0
- package/src/migrations-postgres/033_eval_cases.sql +55 -0
- package/src/migrations-postgres/034_eval_case_results.sql +26 -0
- package/src/migrations-postgres/035_metric_exemplars.sql +31 -0
- package/src/migrations-postgres/036_trace_instrumentation_gaps.sql +19 -0
- package/src/migrations-postgres/037_eval_runs.sql +40 -0
- package/src/migrations-postgres/038_tool_call_evidence.sql +11 -0
- package/src/migrations-postgres/039_drop_trace_instrumentation_gaps.sql +11 -0
- package/src/migrations-postgres/040_evidence_retrieval_refs.sql +47 -0
- package/src/migrations-postgres/README.md +40 -0
- package/src/otlp/acceptance.test.ts +373 -0
- package/src/otlp/decode/body.ts +127 -0
- package/src/otlp/decode/logs.ts +96 -0
- package/src/otlp/decode/metrics.ts +402 -0
- package/src/otlp/decode/traces.ts +92 -0
- package/src/otlp/decode/values.ts +150 -0
- package/src/otlp/decode.test.ts +800 -0
- package/src/otlp/decode.ts +11 -0
- package/src/otlp/gen/opentelemetry/proto/collector/logs/v1/logs_service_pb.ts +132 -0
- package/src/otlp/gen/opentelemetry/proto/collector/metrics/v1/metrics_service_pb.ts +158 -0
- package/src/otlp/gen/opentelemetry/proto/collector/trace/v1/trace_service_pb.ts +158 -0
- package/src/otlp/gen/opentelemetry/proto/common/v1/common_pb.ts +289 -0
- package/src/otlp/gen/opentelemetry/proto/logs/v1/logs_pb.ts +397 -0
- package/src/otlp/gen/opentelemetry/proto/metrics/v1/metrics_pb.ts +1329 -0
- package/src/otlp/gen/opentelemetry/proto/resource/v1/resource_pb.ts +86 -0
- package/src/otlp/gen/opentelemetry/proto/trace/v1/trace_pb.ts +710 -0
- package/src/otlp/response.test.ts +158 -0
- package/src/otlp/response.ts +129 -0
- package/src/plugins/_context.ts +15 -0
- package/src/plugins/action-graph-processor/enrichers.ts +45 -0
- package/src/plugins/action-graph-processor/redaction.ts +84 -0
- package/src/plugins/action-graph-processor.test.ts +1023 -0
- package/src/plugins/action-graph-processor.ts +1172 -0
- package/src/plugins/action-routes.test.ts +716 -0
- package/src/plugins/action-routes.ts +343 -0
- package/src/plugins/ai-receiver.ts +254 -0
- package/src/plugins/ai-span-payloads-processor.test.ts +90 -0
- package/src/plugins/ai-span-payloads-processor.ts +180 -0
- package/src/plugins/alerts-evaluator.test.ts +91 -0
- package/src/plugins/alerts-evaluator.ts +328 -0
- package/src/plugins/alerts-routes.ts +101 -0
- package/src/plugins/analyses-routes.ts +138 -0
- package/src/plugins/ask-routes.ts +182 -0
- package/src/plugins/bot-filter.ts +19 -0
- package/src/plugins/connected-routes/manifest.ts +531 -0
- package/src/plugins/connected-routes.test.ts +1791 -0
- package/src/plugins/connected-routes.ts +1103 -0
- package/src/plugins/dashboard-routes.ts +41 -0
- package/src/plugins/default-span-enrichment.ts +92 -0
- package/src/plugins/eval-cases-routes.test.ts +391 -0
- package/src/plugins/eval-cases-routes.ts +529 -0
- package/src/plugins/evidence-retrieval-routes.benchmark.test.ts +245 -0
- package/src/plugins/evidence-retrieval-routes.test.ts +932 -0
- package/src/plugins/evidence-retrieval-routes.ts +2179 -0
- package/src/plugins/gen-ai-normalizer.test.ts +680 -0
- package/src/plugins/gen-ai-normalizer.ts +302 -0
- package/src/plugins/identity-receiver.ts +96 -0
- package/src/plugins/issue-enrichment.ts +132 -0
- package/src/plugins/issue-insights.ts +81 -0
- package/src/plugins/logs-receiver.ts +160 -0
- package/src/plugins/metrics-receiver.ts +91 -0
- package/src/plugins/onboarding-routes.ts +54 -0
- package/src/plugins/otlp-receiver.ts +124 -0
- package/src/plugins/platform-routes.ts +165 -0
- package/src/plugins/profile-routes.ts +468 -0
- package/src/plugins/projects-routes.ts +92 -0
- package/src/plugins/query-routes.ts +220 -0
- package/src/plugins/redaction-processor.ts +132 -0
- package/src/plugins/replay-query-routes.test.ts +38 -0
- package/src/plugins/replay-query-routes.ts +199 -0
- package/src/plugins/replay-receiver.ts +81 -0
- package/src/plugins/tail-routes.test.ts +47 -0
- package/src/plugins/tail-routes.ts +42 -0
- package/src/plugins/timeline-routes.ts +244 -0
- package/src/plugins/ua-enrichment.ts +27 -0
- package/src/plugins/usage-normalization.ts +46 -0
- package/src/plugins/usage-privacy.ts +55 -0
- package/src/plugins/usage-query-routes.ts +102 -0
- package/src/plugins/usage-receiver.ts +129 -0
- package/src/plugins/users-query-routes.ts +78 -0
- package/src/plugins/utm-enrichment.ts +36 -0
|
@@ -0,0 +1,671 @@
|
|
|
1
|
+
// src/lib/evidence-references.ts
|
|
2
|
+
var analysisRoute = (analysisId) => `#/investigate/${encodeURIComponent(analysisId)}`;
|
|
3
|
+
var analysisEvidenceReference = (evidence) => {
|
|
4
|
+
const route = analysisRoute(evidence.analysisId);
|
|
5
|
+
const status = evidence.result?.status ?? "unknown";
|
|
6
|
+
return {
|
|
7
|
+
evidenceId: `ask:analysis:${evidence.analysisId}`,
|
|
8
|
+
entityKind: "analysis",
|
|
9
|
+
entityId: evidence.analysisId,
|
|
10
|
+
route,
|
|
11
|
+
source: "ask.run_analysis",
|
|
12
|
+
confidence: evidence.result ? 1 : 0.55,
|
|
13
|
+
reason: evidence.result ? `Ask consulted analysis "${evidence.definition.title}" with latest status ${status}.` : `Ask consulted analysis "${evidence.definition.title}", but no latest result was available.`,
|
|
14
|
+
citations: [
|
|
15
|
+
{
|
|
16
|
+
label: evidence.definition.title,
|
|
17
|
+
entityKind: "analysis",
|
|
18
|
+
entityId: evidence.analysisId,
|
|
19
|
+
route
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
suggestedNextPivots: [
|
|
23
|
+
{
|
|
24
|
+
label: "Open investigation",
|
|
25
|
+
entityKind: "analysis",
|
|
26
|
+
entityId: evidence.analysisId,
|
|
27
|
+
route,
|
|
28
|
+
reason: "Review the analysis payload, narrative, and connected telemetry rail."
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
var askEvidenceReferences = (evidence) => [...evidence].map((item) => analysisEvidenceReference(item));
|
|
34
|
+
var MAX_ANALYSIS_EVIDENCE_REFERENCES = 50;
|
|
35
|
+
var isRecord = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
36
|
+
var asString = (value) => {
|
|
37
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
38
|
+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
39
|
+
return null;
|
|
40
|
+
};
|
|
41
|
+
var normalizeHeader = (header) => header.trim().toLowerCase().replace(/[\s-]+/g, "_");
|
|
42
|
+
var valueFor = (row, headerIndex, names) => {
|
|
43
|
+
for (const name of names) {
|
|
44
|
+
const index = headerIndex.get(name);
|
|
45
|
+
if (index === void 0) continue;
|
|
46
|
+
const value = asString(row[index]);
|
|
47
|
+
if (value) return value;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
};
|
|
51
|
+
var traceRoute = (traceId) => `#/traces/${encodeURIComponent(traceId)}`;
|
|
52
|
+
var spanRoute = (traceId, spanId) => `${traceRoute(traceId)}#span=${encodeURIComponent(spanId)}`;
|
|
53
|
+
var evidenceRouteFor = (entityKind, entityId, traceId) => {
|
|
54
|
+
switch (entityKind) {
|
|
55
|
+
case "analysis":
|
|
56
|
+
return analysisRoute(entityId);
|
|
57
|
+
case "action":
|
|
58
|
+
return `#/actions/${encodeURIComponent(entityId)}`;
|
|
59
|
+
case "alert":
|
|
60
|
+
return `#/alerts?alert=${encodeURIComponent(entityId)}`;
|
|
61
|
+
case "agent_run":
|
|
62
|
+
return `#/agent-runs/${encodeURIComponent(entityId)}`;
|
|
63
|
+
case "ai_call":
|
|
64
|
+
return `#/ai/calls/${encodeURIComponent(entityId)}`;
|
|
65
|
+
case "eval":
|
|
66
|
+
return `#/evals/${encodeURIComponent(entityId)}`;
|
|
67
|
+
case "log":
|
|
68
|
+
return `#/logs?id=${encodeURIComponent(entityId)}`;
|
|
69
|
+
case "profile":
|
|
70
|
+
return traceId ? `#/profiles/${encodeURIComponent(entityId)}?trace_id=${encodeURIComponent(traceId)}` : `#/profiles/${encodeURIComponent(entityId)}`;
|
|
71
|
+
case "replay":
|
|
72
|
+
return `#/replay?session=${encodeURIComponent(entityId)}`;
|
|
73
|
+
case "service":
|
|
74
|
+
return `#/traces?service=${encodeURIComponent(entityId)}`;
|
|
75
|
+
case "span": {
|
|
76
|
+
const [tracePart, spanPart] = entityId.split(":");
|
|
77
|
+
return spanPart ? spanRoute(tracePart, spanPart) : `#/spans/${entityId}`;
|
|
78
|
+
}
|
|
79
|
+
case "tool_call":
|
|
80
|
+
return `#/tool-calls/${encodeURIComponent(entityId)}`;
|
|
81
|
+
case "trace":
|
|
82
|
+
return traceRoute(entityId);
|
|
83
|
+
case "docs":
|
|
84
|
+
return entityId.startsWith("#/") ? entityId : `#/docs/${entityId}`;
|
|
85
|
+
}
|
|
86
|
+
const exhaustive = entityKind;
|
|
87
|
+
return exhaustive;
|
|
88
|
+
};
|
|
89
|
+
var parseEvidenceTables = (payload) => {
|
|
90
|
+
const evidence = payload.evidence;
|
|
91
|
+
if (!isRecord(evidence)) return [];
|
|
92
|
+
const tables = [];
|
|
93
|
+
for (const [sectionName, section] of Object.entries(evidence)) {
|
|
94
|
+
if (!isRecord(section)) continue;
|
|
95
|
+
const headers = section.headers;
|
|
96
|
+
const rows = section.rows;
|
|
97
|
+
if (!Array.isArray(headers) || !headers.every(
|
|
98
|
+
(header) => typeof header === "string"
|
|
99
|
+
) || !Array.isArray(rows)) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const normalizedRows = rows.filter(
|
|
103
|
+
(row) => Array.isArray(row)
|
|
104
|
+
);
|
|
105
|
+
tables.push({
|
|
106
|
+
sectionName,
|
|
107
|
+
table: {
|
|
108
|
+
title: asString(section.title),
|
|
109
|
+
headers,
|
|
110
|
+
rows: normalizedRows
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return tables;
|
|
115
|
+
};
|
|
116
|
+
var instrumentationGapEvidenceReferences = (result) => {
|
|
117
|
+
const gaps = result.payload.instrumentationGaps;
|
|
118
|
+
if (!isRecord(gaps)) return [];
|
|
119
|
+
const traceId = asString(gaps.traceId);
|
|
120
|
+
const blindspots = gaps.blindspots;
|
|
121
|
+
if (!traceId || !Array.isArray(blindspots)) return [];
|
|
122
|
+
return blindspots.filter(isRecord).map((gap, index) => {
|
|
123
|
+
const spanId = asString(gap.parentSpanId);
|
|
124
|
+
if (!spanId) return null;
|
|
125
|
+
const serviceName = asString(gap.parentServiceName);
|
|
126
|
+
const spanName = asString(gap.parentSpanName);
|
|
127
|
+
const durationMs = typeof gap.durationMs === "number" && Number.isFinite(gap.durationMs) ? gap.durationMs : null;
|
|
128
|
+
const ratio = typeof gap.ratioOfParent === "number" && Number.isFinite(gap.ratioOfParent) ? gap.ratioOfParent : null;
|
|
129
|
+
const recommendation = asString(gap.recommendation);
|
|
130
|
+
const thresholdVersion = asString(gap.thresholdVersion) ?? (isRecord(gaps.thresholds) ? asString(gaps.thresholds.version) : null);
|
|
131
|
+
const entityId = `${traceId}:${spanId}`;
|
|
132
|
+
const route = spanRoute(traceId, spanId);
|
|
133
|
+
const label = spanName ? `${spanName} (${spanId})` : `span ${spanId}`;
|
|
134
|
+
const durationText = durationMs === null ? "unknown duration" : `${durationMs}ms`;
|
|
135
|
+
const ratioText = ratio === null ? "" : `, ${(ratio * 100).toFixed(1)}% of parent`;
|
|
136
|
+
const thresholdText = thresholdVersion ? ` Thresholds: ${thresholdVersion}.` : "";
|
|
137
|
+
const docsRoute = "#/docs/howto/ebpf";
|
|
138
|
+
return {
|
|
139
|
+
evidenceId: `analysis:${result.analysisId}:instrumentation-gap:${index}:span:${entityId}`,
|
|
140
|
+
entityKind: "span",
|
|
141
|
+
entityId,
|
|
142
|
+
route,
|
|
143
|
+
source: "analysis.payload.instrumentationGaps",
|
|
144
|
+
confidence: 0.9,
|
|
145
|
+
reason: `Analysis "${result.analysisId}" found uninstrumented self-time on ${label}: ${durationText}${ratioText}.${thresholdText}${recommendation ? ` ${recommendation}` : ""}`,
|
|
146
|
+
citations: [
|
|
147
|
+
{
|
|
148
|
+
label: `trace ${traceId}`,
|
|
149
|
+
entityKind: "trace",
|
|
150
|
+
entityId: traceId,
|
|
151
|
+
route: traceRoute(traceId)
|
|
152
|
+
}
|
|
153
|
+
],
|
|
154
|
+
suggestedNextPivots: [
|
|
155
|
+
{
|
|
156
|
+
label: "Open uninstrumented span",
|
|
157
|
+
entityKind: "span",
|
|
158
|
+
entityId,
|
|
159
|
+
route,
|
|
160
|
+
reason: "Inspect the parent span whose self-time suggests missing child instrumentation."
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
label: "Open trace gap data",
|
|
164
|
+
entityKind: "trace",
|
|
165
|
+
entityId: traceId,
|
|
166
|
+
route: `${traceRoute(traceId)}/gaps`,
|
|
167
|
+
reason: "Review all structured instrumentation blindspots for this trace."
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
label: "Open profiler setup docs",
|
|
171
|
+
entityKind: "docs",
|
|
172
|
+
entityId: "howto/ebpf",
|
|
173
|
+
route: docsRoute,
|
|
174
|
+
reason: serviceName != null ? `Use profiler or eBPF setup guidance to cover missing spans in ${serviceName}.` : "Use profiler or eBPF setup guidance to cover missing spans."
|
|
175
|
+
}
|
|
176
|
+
]
|
|
177
|
+
};
|
|
178
|
+
}).filter((ref) => ref !== null).slice(0, MAX_ANALYSIS_EVIDENCE_REFERENCES);
|
|
179
|
+
};
|
|
180
|
+
var entityFromRow = (row, headers) => {
|
|
181
|
+
const headerIndex = new Map(headers.map((header, index) => [header, index]));
|
|
182
|
+
const traceId = valueFor(row, headerIndex, ["trace_id", "traceid", "trace"]);
|
|
183
|
+
const spanId = valueFor(row, headerIndex, ["span_id", "spanid"]);
|
|
184
|
+
const logId = valueFor(row, headerIndex, ["log_id", "logid"]);
|
|
185
|
+
const profileId = valueFor(row, headerIndex, ["profile_id", "profileid"]);
|
|
186
|
+
const actionId = valueFor(row, headerIndex, ["action_id", "actionid"]);
|
|
187
|
+
const agentRunId = valueFor(row, headerIndex, [
|
|
188
|
+
"agent_run_id",
|
|
189
|
+
"agentrunid",
|
|
190
|
+
"agent_run"
|
|
191
|
+
]);
|
|
192
|
+
const toolCallId = valueFor(row, headerIndex, [
|
|
193
|
+
"tool_call_id",
|
|
194
|
+
"toolcallid",
|
|
195
|
+
"tool_call"
|
|
196
|
+
]);
|
|
197
|
+
const evalId = valueFor(row, headerIndex, ["eval_id", "evalid"]);
|
|
198
|
+
const service = valueFor(row, headerIndex, ["service", "service_name"]);
|
|
199
|
+
const traceCitation = traceId ? [
|
|
200
|
+
{
|
|
201
|
+
label: `trace ${traceId}`,
|
|
202
|
+
entityKind: "trace",
|
|
203
|
+
entityId: traceId,
|
|
204
|
+
route: traceRoute(traceId)
|
|
205
|
+
}
|
|
206
|
+
] : [];
|
|
207
|
+
if (traceId && spanId) {
|
|
208
|
+
const entityId = `${traceId}:${spanId}`;
|
|
209
|
+
return {
|
|
210
|
+
entityKind: "span",
|
|
211
|
+
entityId,
|
|
212
|
+
route: spanRoute(traceId, spanId),
|
|
213
|
+
label: `span ${spanId}`,
|
|
214
|
+
confidence: 0.95,
|
|
215
|
+
citations: traceCitation,
|
|
216
|
+
suggestedNextPivots: [
|
|
217
|
+
{
|
|
218
|
+
label: "Open span",
|
|
219
|
+
entityKind: "span",
|
|
220
|
+
entityId,
|
|
221
|
+
route: spanRoute(traceId, spanId),
|
|
222
|
+
reason: "Inspect the cited span in its trace context."
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
label: "Open trace",
|
|
226
|
+
entityKind: "trace",
|
|
227
|
+
entityId: traceId,
|
|
228
|
+
route: traceRoute(traceId),
|
|
229
|
+
reason: "Review the surrounding trace context."
|
|
230
|
+
}
|
|
231
|
+
]
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
const candidates = [
|
|
235
|
+
{
|
|
236
|
+
entityKind: "trace",
|
|
237
|
+
entityId: traceId,
|
|
238
|
+
labelPrefix: "trace",
|
|
239
|
+
confidence: 0.95
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
entityKind: "action",
|
|
243
|
+
entityId: actionId,
|
|
244
|
+
labelPrefix: "action",
|
|
245
|
+
confidence: 0.9
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
entityKind: "tool_call",
|
|
249
|
+
entityId: toolCallId,
|
|
250
|
+
labelPrefix: "tool call",
|
|
251
|
+
confidence: 0.9
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
entityKind: "agent_run",
|
|
255
|
+
entityId: agentRunId,
|
|
256
|
+
labelPrefix: "agent run",
|
|
257
|
+
confidence: 0.9
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
entityKind: "profile",
|
|
261
|
+
entityId: profileId,
|
|
262
|
+
labelPrefix: "profile",
|
|
263
|
+
confidence: 0.9
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
entityKind: "log",
|
|
267
|
+
entityId: logId,
|
|
268
|
+
labelPrefix: "log",
|
|
269
|
+
confidence: 0.85
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
entityKind: "eval",
|
|
273
|
+
entityId: evalId,
|
|
274
|
+
labelPrefix: "eval",
|
|
275
|
+
confidence: 0.85
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
entityKind: "service",
|
|
279
|
+
entityId: service,
|
|
280
|
+
labelPrefix: "service",
|
|
281
|
+
confidence: 0.7
|
|
282
|
+
}
|
|
283
|
+
];
|
|
284
|
+
const candidate = candidates.find((item) => item.entityId);
|
|
285
|
+
if (!candidate?.entityId) return null;
|
|
286
|
+
const route = evidenceRouteFor(
|
|
287
|
+
candidate.entityKind,
|
|
288
|
+
candidate.entityId,
|
|
289
|
+
traceId
|
|
290
|
+
);
|
|
291
|
+
return {
|
|
292
|
+
entityKind: candidate.entityKind,
|
|
293
|
+
entityId: candidate.entityId,
|
|
294
|
+
route,
|
|
295
|
+
label: `${candidate.labelPrefix} ${candidate.entityId}`,
|
|
296
|
+
confidence: candidate.confidence,
|
|
297
|
+
citations: traceCitation.filter(
|
|
298
|
+
(citation) => citation.entityKind !== candidate.entityKind || citation.entityId !== candidate.entityId
|
|
299
|
+
),
|
|
300
|
+
suggestedNextPivots: [
|
|
301
|
+
{
|
|
302
|
+
label: `Open ${candidate.labelPrefix}`,
|
|
303
|
+
entityKind: candidate.entityKind,
|
|
304
|
+
entityId: candidate.entityId,
|
|
305
|
+
route,
|
|
306
|
+
reason: "Inspect the cited evidence row."
|
|
307
|
+
}
|
|
308
|
+
]
|
|
309
|
+
};
|
|
310
|
+
};
|
|
311
|
+
var alertEvidenceReferences = (rule, evaluation) => {
|
|
312
|
+
const route = evidenceRouteFor("alert", rule.id);
|
|
313
|
+
const references = [
|
|
314
|
+
{
|
|
315
|
+
evidenceId: evaluation ? `alert:${rule.id}:evaluation:${evaluation.id}` : `alert:${rule.id}:rule`,
|
|
316
|
+
entityKind: "alert",
|
|
317
|
+
entityId: rule.id,
|
|
318
|
+
route,
|
|
319
|
+
source: evaluation ? "alert_evaluations" : "alerts.rule_evaluation_preview",
|
|
320
|
+
confidence: evaluation ? 1 : 0.8,
|
|
321
|
+
reason: evaluation ? `Alert "${rule.name}" evaluated to ${evaluation.value} and state ${evaluation.state}.` : `Alert "${rule.name}" was evaluated against its configured threshold.`,
|
|
322
|
+
citations: [
|
|
323
|
+
{
|
|
324
|
+
label: rule.name,
|
|
325
|
+
entityKind: "alert",
|
|
326
|
+
entityId: rule.id,
|
|
327
|
+
route
|
|
328
|
+
}
|
|
329
|
+
],
|
|
330
|
+
suggestedNextPivots: [
|
|
331
|
+
{
|
|
332
|
+
label: "Open alert",
|
|
333
|
+
entityKind: "alert",
|
|
334
|
+
entityId: rule.id,
|
|
335
|
+
route,
|
|
336
|
+
reason: "Inspect the alert rule, threshold, and recent evaluations."
|
|
337
|
+
}
|
|
338
|
+
]
|
|
339
|
+
}
|
|
340
|
+
];
|
|
341
|
+
if (rule.analysisId) {
|
|
342
|
+
const analysisRouteValue = analysisRoute(rule.analysisId);
|
|
343
|
+
references.push({
|
|
344
|
+
evidenceId: evaluation ? `alert:${rule.id}:evaluation:${evaluation.id}:analysis:${rule.analysisId}` : `alert:${rule.id}:analysis:${rule.analysisId}`,
|
|
345
|
+
entityKind: "analysis",
|
|
346
|
+
entityId: rule.analysisId,
|
|
347
|
+
route: analysisRouteValue,
|
|
348
|
+
source: "alert_rules.analysis_id",
|
|
349
|
+
confidence: 0.9,
|
|
350
|
+
reason: `Alert "${rule.name}" is bound to analysis "${rule.analysisId}".`,
|
|
351
|
+
citations: [
|
|
352
|
+
{
|
|
353
|
+
label: rule.name,
|
|
354
|
+
entityKind: "alert",
|
|
355
|
+
entityId: rule.id,
|
|
356
|
+
route
|
|
357
|
+
}
|
|
358
|
+
],
|
|
359
|
+
suggestedNextPivots: [
|
|
360
|
+
{
|
|
361
|
+
label: "Open investigation",
|
|
362
|
+
entityKind: "analysis",
|
|
363
|
+
entityId: rule.analysisId,
|
|
364
|
+
route: analysisRouteValue,
|
|
365
|
+
reason: "Review the analysis result that drives this alert."
|
|
366
|
+
}
|
|
367
|
+
]
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
return references;
|
|
371
|
+
};
|
|
372
|
+
var aiEvaluationEvidenceReferences = (evaluation) => {
|
|
373
|
+
const spanEntityId = `${evaluation.traceId}:${evaluation.spanId}`;
|
|
374
|
+
const spanRouteValue = evidenceRouteFor(
|
|
375
|
+
"span",
|
|
376
|
+
spanEntityId,
|
|
377
|
+
evaluation.traceId
|
|
378
|
+
);
|
|
379
|
+
return [
|
|
380
|
+
{
|
|
381
|
+
evidenceId: `ai-evaluation:${evaluation.evaluationId}`,
|
|
382
|
+
entityKind: "eval",
|
|
383
|
+
entityId: evaluation.evaluationId,
|
|
384
|
+
route: evidenceRouteFor("eval", evaluation.evaluationId),
|
|
385
|
+
source: `ai_span_evaluations.${evaluation.source}`,
|
|
386
|
+
confidence: 0.95,
|
|
387
|
+
reason: `AI evaluation "${evaluation.name}" graded span "${evaluation.spanId}".`,
|
|
388
|
+
citations: [
|
|
389
|
+
{
|
|
390
|
+
label: `span ${evaluation.spanId}`,
|
|
391
|
+
entityKind: "span",
|
|
392
|
+
entityId: spanEntityId,
|
|
393
|
+
route: spanRouteValue
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
label: `trace ${evaluation.traceId}`,
|
|
397
|
+
entityKind: "trace",
|
|
398
|
+
entityId: evaluation.traceId,
|
|
399
|
+
route: evidenceRouteFor("trace", evaluation.traceId)
|
|
400
|
+
}
|
|
401
|
+
],
|
|
402
|
+
suggestedNextPivots: [
|
|
403
|
+
{
|
|
404
|
+
label: "Open span",
|
|
405
|
+
entityKind: "span",
|
|
406
|
+
entityId: spanEntityId,
|
|
407
|
+
route: spanRouteValue,
|
|
408
|
+
reason: "Inspect the evaluated AI span and its surrounding trace."
|
|
409
|
+
}
|
|
410
|
+
]
|
|
411
|
+
}
|
|
412
|
+
];
|
|
413
|
+
};
|
|
414
|
+
var sourceLinkEvidenceReferences = (source, links) => {
|
|
415
|
+
const citations = [];
|
|
416
|
+
if (source.sourceRoute) {
|
|
417
|
+
citations.push({
|
|
418
|
+
label: source.sourceName ?? source.sourceId,
|
|
419
|
+
entityKind: "eval",
|
|
420
|
+
entityId: source.sourceId,
|
|
421
|
+
route: source.sourceRoute
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
const candidates = [
|
|
425
|
+
{
|
|
426
|
+
kind: "action",
|
|
427
|
+
id: links.sourceActionId,
|
|
428
|
+
label: "source action",
|
|
429
|
+
confidence: 0.92
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
kind: "tool_call",
|
|
433
|
+
id: links.sourceToolCallId,
|
|
434
|
+
label: "source tool call",
|
|
435
|
+
confidence: 0.9
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
kind: "agent_run",
|
|
439
|
+
id: links.sourceAgentRunId,
|
|
440
|
+
label: "source agent run",
|
|
441
|
+
confidence: 0.9
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
kind: "span",
|
|
445
|
+
id: links.sourceTraceId && links.sourceSpanId ? `${links.sourceTraceId}:${links.sourceSpanId}` : null,
|
|
446
|
+
label: "source span",
|
|
447
|
+
confidence: 0.9
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
kind: "trace",
|
|
451
|
+
id: links.sourceTraceId,
|
|
452
|
+
label: "source trace",
|
|
453
|
+
confidence: 0.88
|
|
454
|
+
}
|
|
455
|
+
];
|
|
456
|
+
return candidates.filter(
|
|
457
|
+
(candidate) => Boolean(candidate.id)
|
|
458
|
+
).map((candidate) => {
|
|
459
|
+
const route = evidenceRouteFor(
|
|
460
|
+
candidate.kind,
|
|
461
|
+
candidate.id,
|
|
462
|
+
links.sourceTraceId
|
|
463
|
+
);
|
|
464
|
+
return {
|
|
465
|
+
evidenceId: `${source.sourceKind}:${source.sourceId}:${candidate.kind}:${candidate.id}`,
|
|
466
|
+
entityKind: candidate.kind,
|
|
467
|
+
entityId: candidate.id,
|
|
468
|
+
route,
|
|
469
|
+
source: `${source.sourceKind}.source_links`,
|
|
470
|
+
confidence: candidate.confidence,
|
|
471
|
+
reason: `${source.sourceLabel} links to ${candidate.label} "${candidate.id}".`,
|
|
472
|
+
citations,
|
|
473
|
+
suggestedNextPivots: [
|
|
474
|
+
{
|
|
475
|
+
label: `Open ${candidate.label}`,
|
|
476
|
+
entityKind: candidate.kind,
|
|
477
|
+
entityId: candidate.id,
|
|
478
|
+
route,
|
|
479
|
+
reason: "Inspect the production evidence behind this evaluation item."
|
|
480
|
+
}
|
|
481
|
+
]
|
|
482
|
+
};
|
|
483
|
+
});
|
|
484
|
+
};
|
|
485
|
+
var analysisResultEvidenceReferences = (result) => {
|
|
486
|
+
const references = [
|
|
487
|
+
...instrumentationGapEvidenceReferences(result)
|
|
488
|
+
];
|
|
489
|
+
for (const { sectionName, table } of parseEvidenceTables(result.payload)) {
|
|
490
|
+
const headers = table.headers.map(normalizeHeader);
|
|
491
|
+
for (const [rowIndex, row] of table.rows.entries()) {
|
|
492
|
+
if (references.length >= MAX_ANALYSIS_EVIDENCE_REFERENCES) {
|
|
493
|
+
return references;
|
|
494
|
+
}
|
|
495
|
+
const entity = entityFromRow(row, headers);
|
|
496
|
+
if (!entity) continue;
|
|
497
|
+
const title = table.title ?? sectionName;
|
|
498
|
+
references.push({
|
|
499
|
+
evidenceId: `analysis:${result.analysisId}:${sectionName}:${rowIndex}:${entity.entityKind}:${entity.entityId}`,
|
|
500
|
+
entityKind: entity.entityKind,
|
|
501
|
+
entityId: entity.entityId,
|
|
502
|
+
route: entity.route,
|
|
503
|
+
source: `analysis.payload.evidence.${sectionName}`,
|
|
504
|
+
confidence: entity.confidence,
|
|
505
|
+
reason: `Analysis "${result.analysisId}" cited ${entity.label} in "${title}" row ${rowIndex + 1}.`,
|
|
506
|
+
citations: entity.citations,
|
|
507
|
+
suggestedNextPivots: entity.suggestedNextPivots
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
return references;
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
// src/lib/llm.ts
|
|
515
|
+
var DEFAULT_API_URL = "https://api.anthropic.com/v1/messages";
|
|
516
|
+
var SYSTEM_PROMPT = `You write one-sentence operational narratives for a self-hosted observability dashboard.
|
|
517
|
+
|
|
518
|
+
Hard rules \u2014 violations are unusable:
|
|
519
|
+
1. Never start with "I", "Here's", "We", "It looks", or any first-person/chatbot framing. Write declarative statements about the system.
|
|
520
|
+
2. If you reference a trace, span, log, or service, include the supplied identifier inline (e.g. "trace abc12345").
|
|
521
|
+
3. Include a time anchor: "starting Nm ago", "for the last Nm", "since HH:MM" \u2014 pull from the inputs.
|
|
522
|
+
4. \u2264 2 sentences total, \u2264 220 characters. Numbers belong in the sentence, not in a separate label.
|
|
523
|
+
5. If the inputs are insufficient to write a useful sentence, output exactly the string NO_NARRATIVE (no quotes).
|
|
524
|
+
|
|
525
|
+
Tone: like a senior on-call writing a Slack message. Specific, blunt, no hedging, no advice ("you should..."), no questions.`;
|
|
526
|
+
var renderTemplate = (template, def, r) => {
|
|
527
|
+
const scope = def.scope ?? {};
|
|
528
|
+
const traceIds = Array.isArray(r.payload?.trace_ids) ? r.payload.trace_ids.filter((x) => typeof x === "string").slice(0, 5).join(", ") : "";
|
|
529
|
+
const subs = {
|
|
530
|
+
title: def.title,
|
|
531
|
+
status: r.status,
|
|
532
|
+
primary: r.primaryValue === null ? "n/a" : String(r.primaryValue),
|
|
533
|
+
baseline: r.baselineValue === null ? "n/a" : String(r.baselineValue),
|
|
534
|
+
delta_pct: r.deltaPct === null ? "n/a" : `${r.deltaPct.toFixed(1)}%`,
|
|
535
|
+
service: typeof scope.service === "string" ? scope.service : "",
|
|
536
|
+
trace_ids: traceIds
|
|
537
|
+
};
|
|
538
|
+
return template.replace(/\{\{(\w+)\}\}/g, (_, k) => subs[k] ?? "");
|
|
539
|
+
};
|
|
540
|
+
var buildUserPrompt = ({
|
|
541
|
+
definition,
|
|
542
|
+
current,
|
|
543
|
+
previous
|
|
544
|
+
}) => {
|
|
545
|
+
const lines = [];
|
|
546
|
+
const tmplRendered = renderTemplate(
|
|
547
|
+
definition.narrate?.prompt ?? "",
|
|
548
|
+
definition,
|
|
549
|
+
current
|
|
550
|
+
).trim();
|
|
551
|
+
if (tmplRendered) lines.push(tmplRendered);
|
|
552
|
+
lines.push("");
|
|
553
|
+
lines.push("Current state:");
|
|
554
|
+
lines.push(`- panel: ${definition.title}`);
|
|
555
|
+
lines.push(`- status: ${current.status}`);
|
|
556
|
+
if (current.primaryValue !== null)
|
|
557
|
+
lines.push(`- primary: ${current.primaryValue}`);
|
|
558
|
+
if (current.baselineValue !== null)
|
|
559
|
+
lines.push(`- baseline (1h): ${current.baselineValue}`);
|
|
560
|
+
if (current.deltaPct !== null)
|
|
561
|
+
lines.push(`- delta vs baseline: ${current.deltaPct.toFixed(1)}%`);
|
|
562
|
+
const since = previous ? Math.max(
|
|
563
|
+
1,
|
|
564
|
+
Math.round(
|
|
565
|
+
(new Date(current.generatedAt).getTime() - new Date(previous.generatedAt).getTime()) / 6e4
|
|
566
|
+
)
|
|
567
|
+
) : null;
|
|
568
|
+
if (since !== null) {
|
|
569
|
+
lines.push(
|
|
570
|
+
`- previous run was ${since} minute${since === 1 ? "" : "s"} ago, status=${previous?.status ?? "n/a"}`
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
const payloadKeys = Object.keys(current.payload ?? {}).filter(
|
|
574
|
+
(k) => k !== "sparkline"
|
|
575
|
+
);
|
|
576
|
+
if (payloadKeys.length > 0) {
|
|
577
|
+
lines.push("");
|
|
578
|
+
lines.push("Payload details:");
|
|
579
|
+
for (const k of payloadKeys) {
|
|
580
|
+
const v = current.payload[k];
|
|
581
|
+
const rendered = typeof v === "string" || typeof v === "number" || typeof v === "boolean" ? String(v) : JSON.stringify(v);
|
|
582
|
+
if (rendered.length <= 200) lines.push(`- ${k}: ${rendered}`);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
lines.push("");
|
|
586
|
+
lines.push(
|
|
587
|
+
"Output: a single sentence (max two), no preamble, no quotes, no Markdown."
|
|
588
|
+
);
|
|
589
|
+
return lines.join("\n");
|
|
590
|
+
};
|
|
591
|
+
var LlmCallError = class extends Error {
|
|
592
|
+
status;
|
|
593
|
+
constructor(message, status = null) {
|
|
594
|
+
super(message);
|
|
595
|
+
this.name = "LlmCallError";
|
|
596
|
+
this.status = status;
|
|
597
|
+
}
|
|
598
|
+
};
|
|
599
|
+
async function generateNarrative(req, config) {
|
|
600
|
+
if (config.provider === "openai") {
|
|
601
|
+
const { generateNarrativeOpenAI } = await import("./openai-FJYOQ7WO.js");
|
|
602
|
+
return generateNarrativeOpenAI(req, config);
|
|
603
|
+
}
|
|
604
|
+
return generateNarrativeAnthropic(req, config);
|
|
605
|
+
}
|
|
606
|
+
async function generateNarrativeAnthropic(req, config) {
|
|
607
|
+
const url = config.apiUrl ?? DEFAULT_API_URL;
|
|
608
|
+
const userPrompt = buildUserPrompt(req);
|
|
609
|
+
const tracer = config.tracer;
|
|
610
|
+
const callLLM = async (span) => {
|
|
611
|
+
const response = await fetch(url, {
|
|
612
|
+
method: "POST",
|
|
613
|
+
headers: {
|
|
614
|
+
"x-api-key": config.apiKey,
|
|
615
|
+
"anthropic-version": "2023-06-01",
|
|
616
|
+
"content-type": "application/json"
|
|
617
|
+
},
|
|
618
|
+
body: JSON.stringify({
|
|
619
|
+
model: config.model,
|
|
620
|
+
max_tokens: 200,
|
|
621
|
+
system: SYSTEM_PROMPT,
|
|
622
|
+
messages: [{ role: "user", content: userPrompt }]
|
|
623
|
+
}),
|
|
624
|
+
signal: config.signal
|
|
625
|
+
});
|
|
626
|
+
if (span) {
|
|
627
|
+
span.setAttribute("http.response.status_code", response.status);
|
|
628
|
+
}
|
|
629
|
+
if (!response.ok) {
|
|
630
|
+
const text2 = await response.text().catch(() => "");
|
|
631
|
+
throw new LlmCallError(
|
|
632
|
+
`anthropic ${response.status}: ${text2.slice(0, 200)}`,
|
|
633
|
+
response.status
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
const body = await response.json();
|
|
637
|
+
if (body.stop_reason === "max_tokens") {
|
|
638
|
+
throw new LlmCallError("anthropic response truncated by max_tokens");
|
|
639
|
+
}
|
|
640
|
+
if (span && body.usage) {
|
|
641
|
+
if (typeof body.usage.input_tokens === "number")
|
|
642
|
+
span.setAttribute("gen_ai.usage.input_tokens", body.usage.input_tokens);
|
|
643
|
+
if (typeof body.usage.output_tokens === "number")
|
|
644
|
+
span.setAttribute(
|
|
645
|
+
"gen_ai.usage.output_tokens",
|
|
646
|
+
body.usage.output_tokens
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
const text = (body.content ?? []).filter((block) => block?.type === "text").map((block) => block?.text ?? "").join("").trim();
|
|
650
|
+
if (!text || text === "NO_NARRATIVE") return null;
|
|
651
|
+
return text.replace(/^["']|["']$/g, "").trim();
|
|
652
|
+
};
|
|
653
|
+
if (!tracer) return callLLM(null);
|
|
654
|
+
return tracer("llm.anthropic.messages", async (span) => callLLM(span), {
|
|
655
|
+
"openinference.span.kind": "LLM",
|
|
656
|
+
"gen_ai.system": "anthropic",
|
|
657
|
+
"gen_ai.request.model": config.model,
|
|
658
|
+
"gen_ai.request.max_tokens": 200
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
export {
|
|
663
|
+
askEvidenceReferences,
|
|
664
|
+
alertEvidenceReferences,
|
|
665
|
+
aiEvaluationEvidenceReferences,
|
|
666
|
+
sourceLinkEvidenceReferences,
|
|
667
|
+
analysisResultEvidenceReferences,
|
|
668
|
+
LlmCallError,
|
|
669
|
+
generateNarrative
|
|
670
|
+
};
|
|
671
|
+
//# sourceMappingURL=chunk-XKQTVIRE.js.map
|