@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.
Files changed (254) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +60 -0
  3. package/dist/auth.d.ts +2 -0
  4. package/dist/auth.js +9 -0
  5. package/dist/auth.js.map +1 -0
  6. package/dist/chunk-UGWDOGGH.js +319 -0
  7. package/dist/chunk-UGWDOGGH.js.map +1 -0
  8. package/dist/chunk-XKQTVIRE.js +671 -0
  9. package/dist/chunk-XKQTVIRE.js.map +1 -0
  10. package/dist/index.d.ts +1197 -0
  11. package/dist/index.js +17707 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/ingest-auth-HFVO1zIp.d.ts +165 -0
  14. package/dist/openai-FJYOQ7WO.js +384 -0
  15. package/dist/openai-FJYOQ7WO.js.map +1 -0
  16. package/package.json +73 -0
  17. package/src/ai-parity/ai-parity.acceptance.test.ts +449 -0
  18. package/src/analyses/derive.ts +642 -0
  19. package/src/analyses/index.ts +50 -0
  20. package/src/analyses/investigations.ts +277 -0
  21. package/src/analyses/tier0.ts +568 -0
  22. package/src/auth/dashboard-auth.ts +269 -0
  23. package/src/auth/ingest-auth.ts +147 -0
  24. package/src/durable-objects/tail-hub.test.ts +32 -0
  25. package/src/durable-objects/tail-hub.ts +158 -0
  26. package/src/framework/collector.ts +467 -0
  27. package/src/framework/env.ts +90 -0
  28. package/src/framework/logger.ts +81 -0
  29. package/src/index.ts +211 -0
  30. package/src/lib/action-aggregates.ts +1031 -0
  31. package/src/lib/action-identity.ts +106 -0
  32. package/src/lib/actions-store.ts +397 -0
  33. package/src/lib/ai-pricing.ts +80 -0
  34. package/src/lib/ai-store/calls.ts +148 -0
  35. package/src/lib/ai-store/evaluations.test.ts +47 -0
  36. package/src/lib/ai-store/evaluations.ts +125 -0
  37. package/src/lib/ai-store/helpers.ts +37 -0
  38. package/src/lib/ai-store/retention.ts +17 -0
  39. package/src/lib/ai-store/sessions.ts +277 -0
  40. package/src/lib/ai-store/spans.ts +109 -0
  41. package/src/lib/ai-store/types.ts +112 -0
  42. package/src/lib/ai-store.ts +76 -0
  43. package/src/lib/alerts-store.ts +458 -0
  44. package/src/lib/analyses-runner.ts +439 -0
  45. package/src/lib/analyses-store.test.ts +243 -0
  46. package/src/lib/analyses-store.ts +454 -0
  47. package/src/lib/ask.test.ts +302 -0
  48. package/src/lib/ask.ts +390 -0
  49. package/src/lib/blob-store-s3.ts +213 -0
  50. package/src/lib/blob-store.ts +366 -0
  51. package/src/lib/eval-cases-store.test.ts +171 -0
  52. package/src/lib/eval-cases-store.ts +1033 -0
  53. package/src/lib/evidence-references.test.ts +10 -0
  54. package/src/lib/evidence-references.ts +684 -0
  55. package/src/lib/hash.ts +26 -0
  56. package/src/lib/identity-index/action-lookups.ts +805 -0
  57. package/src/lib/identity-index/constants.ts +1 -0
  58. package/src/lib/identity-index/key-lookups.ts +199 -0
  59. package/src/lib/identity-index/mappers.ts +349 -0
  60. package/src/lib/identity-index/types.ts +196 -0
  61. package/src/lib/identity-index/user-lookup.ts +137 -0
  62. package/src/lib/identity-index.test.ts +624 -0
  63. package/src/lib/identity-index.ts +85 -0
  64. package/src/lib/json.ts +39 -0
  65. package/src/lib/llm.ts +263 -0
  66. package/src/lib/logs-store.ts +188 -0
  67. package/src/lib/metrics-store.test.ts +189 -0
  68. package/src/lib/metrics-store.ts +312 -0
  69. package/src/lib/narrate-gate.test.ts +260 -0
  70. package/src/lib/narrate-gate.ts +253 -0
  71. package/src/lib/openai.test.ts +300 -0
  72. package/src/lib/openai.ts +512 -0
  73. package/src/lib/otlp.ts +212 -0
  74. package/src/lib/parse-pprof.test.ts +64 -0
  75. package/src/lib/parse-pprof.ts +184 -0
  76. package/src/lib/payload-capture.ts +22 -0
  77. package/src/lib/projects-store.ts +207 -0
  78. package/src/lib/propagation-metric.test.ts +196 -0
  79. package/src/lib/propagation-metric.ts +175 -0
  80. package/src/lib/sql-db-dialect.test.ts +22 -0
  81. package/src/lib/sql-db-postgres.ts +229 -0
  82. package/src/lib/sql-db.ts +166 -0
  83. package/src/lib/stage6.test.ts +216 -0
  84. package/src/lib/store/export.ts +65 -0
  85. package/src/lib/store/helpers.ts +367 -0
  86. package/src/lib/store/ingest.ts +68 -0
  87. package/src/lib/store/issues.ts +158 -0
  88. package/src/lib/store/overview.ts +127 -0
  89. package/src/lib/store/retention.ts +10 -0
  90. package/src/lib/store/service-map.ts +384 -0
  91. package/src/lib/store/trace-detail.bench.ts +76 -0
  92. package/src/lib/store/trace-detail.test.ts +410 -0
  93. package/src/lib/store/trace-detail.ts +427 -0
  94. package/src/lib/store/trace-queries.test.ts +29 -0
  95. package/src/lib/store/trace-queries.ts +89 -0
  96. package/src/lib/store-overview.test.ts +77 -0
  97. package/src/lib/store.ts +96 -0
  98. package/src/lib/tail-publisher.ts +64 -0
  99. package/src/lib/test-utils/mem-sql-db.test.ts +93 -0
  100. package/src/lib/test-utils/mem-sql-db.ts +86 -0
  101. package/src/lib/ua-parser.ts +61 -0
  102. package/src/lib/usage-store.ts +567 -0
  103. package/src/migrations/001_telemetry_spans.sql +28 -0
  104. package/src/migrations/002_usage_events.sql +24 -0
  105. package/src/migrations/003_usage_analytics_columns.sql +13 -0
  106. package/src/migrations/004_logs.sql +19 -0
  107. package/src/migrations/005_ai_calls.sql +25 -0
  108. package/src/migrations/006_user_profiles.sql +11 -0
  109. package/src/migrations/007_session_replay_metadata.sql +10 -0
  110. package/src/migrations/008_session_replay_storage_bytes.sql +1 -0
  111. package/src/migrations/009_projects_and_keys.sql +22 -0
  112. package/src/migrations/010_signal_project_id.sql +15 -0
  113. package/src/migrations/011_default_project_seed.sql +3 -0
  114. package/src/migrations/012_alert_rules.sql +17 -0
  115. package/src/migrations/013_alert_evaluations.sql +13 -0
  116. package/src/migrations/014_alert_state.sql +9 -0
  117. package/src/migrations/015_metrics.sql +58 -0
  118. package/src/migrations/016_metrics_exp_histogram_summary.sql +5 -0
  119. package/src/migrations/017_span_dropped_counts.sql +11 -0
  120. package/src/migrations/018_log_flags.sql +8 -0
  121. package/src/migrations/019_ai_span_payloads.sql +30 -0
  122. package/src/migrations/020_ai_span_evaluations.sql +33 -0
  123. package/src/migrations/021_ai_span_session.sql +13 -0
  124. package/src/migrations/022_span_log_session_id.sql +13 -0
  125. package/src/migrations/023_service_map_indexes.sql +32 -0
  126. package/src/migrations/024_analysis_results.sql +49 -0
  127. package/src/migrations/025_stage6_autopinning_alerts.sql +38 -0
  128. package/src/migrations/026_obs_dashboard_project_seed.sql +18 -0
  129. package/src/migrations/027_identity_propagation.sql +50 -0
  130. package/src/migrations/028_profile_blobs.sql +57 -0
  131. package/src/migrations/029_telemetry_sdk_name.sql +20 -0
  132. package/src/migrations/030_analysis_claim.sql +18 -0
  133. package/src/migrations/031_agent_action_graph.sql +154 -0
  134. package/src/migrations/032_payload_capture_flags.sql +8 -0
  135. package/src/migrations/033_eval_cases.sql +52 -0
  136. package/src/migrations/034_eval_case_results.sql +23 -0
  137. package/src/migrations/035_metric_exemplars.sql +33 -0
  138. package/src/migrations/036_trace_instrumentation_gaps.sql +19 -0
  139. package/src/migrations/037_eval_runs.sql +37 -0
  140. package/src/migrations/038_tool_call_evidence.sql +11 -0
  141. package/src/migrations/039_drop_trace_instrumentation_gaps.sql +11 -0
  142. package/src/migrations/040_evidence_retrieval_refs.sql +50 -0
  143. package/src/migrations-postgres/001_telemetry_spans.sql +33 -0
  144. package/src/migrations-postgres/002_usage_events.sql +24 -0
  145. package/src/migrations-postgres/003_usage_analytics_columns.sql +13 -0
  146. package/src/migrations-postgres/004_logs.sql +19 -0
  147. package/src/migrations-postgres/005_ai_calls.sql +25 -0
  148. package/src/migrations-postgres/006_user_profiles.sql +11 -0
  149. package/src/migrations-postgres/007_session_replay_metadata.sql +10 -0
  150. package/src/migrations-postgres/008_session_replay_storage_bytes.sql +2 -0
  151. package/src/migrations-postgres/009_projects_and_keys.sql +25 -0
  152. package/src/migrations-postgres/010_signal_project_id.sql +18 -0
  153. package/src/migrations-postgres/011_default_project_seed.sql +5 -0
  154. package/src/migrations-postgres/012_alert_rules.sql +17 -0
  155. package/src/migrations-postgres/013_alert_evaluations.sql +13 -0
  156. package/src/migrations-postgres/014_alert_state.sql +9 -0
  157. package/src/migrations-postgres/015_metrics.sql +47 -0
  158. package/src/migrations-postgres/016_metrics_exp_histogram_summary.sql +1 -0
  159. package/src/migrations-postgres/017_span_dropped_counts.sql +4 -0
  160. package/src/migrations-postgres/018_log_flags.sql +2 -0
  161. package/src/migrations-postgres/019_ai_span_payloads.sql +18 -0
  162. package/src/migrations-postgres/020_ai_span_evaluations.sql +21 -0
  163. package/src/migrations-postgres/021_ai_span_session.sql +7 -0
  164. package/src/migrations-postgres/022_span_log_session_id.sql +7 -0
  165. package/src/migrations-postgres/023_service_map_indexes.sql +9 -0
  166. package/src/migrations-postgres/024_analysis_results.sql +41 -0
  167. package/src/migrations-postgres/025_stage6_autopinning_alerts.sql +17 -0
  168. package/src/migrations-postgres/026_obs_dashboard_project_seed.sql +14 -0
  169. package/src/migrations-postgres/027_identity_propagation.sql +27 -0
  170. package/src/migrations-postgres/028_profile_blobs.sql +48 -0
  171. package/src/migrations-postgres/029_telemetry_sdk_name.sql +5 -0
  172. package/src/migrations-postgres/030_analysis_claim.sql +5 -0
  173. package/src/migrations-postgres/031_agent_action_graph.sql +190 -0
  174. package/src/migrations-postgres/032_payload_capture_flags.sql +8 -0
  175. package/src/migrations-postgres/033_eval_cases.sql +55 -0
  176. package/src/migrations-postgres/034_eval_case_results.sql +26 -0
  177. package/src/migrations-postgres/035_metric_exemplars.sql +31 -0
  178. package/src/migrations-postgres/036_trace_instrumentation_gaps.sql +19 -0
  179. package/src/migrations-postgres/037_eval_runs.sql +40 -0
  180. package/src/migrations-postgres/038_tool_call_evidence.sql +11 -0
  181. package/src/migrations-postgres/039_drop_trace_instrumentation_gaps.sql +11 -0
  182. package/src/migrations-postgres/040_evidence_retrieval_refs.sql +47 -0
  183. package/src/migrations-postgres/README.md +40 -0
  184. package/src/otlp/acceptance.test.ts +373 -0
  185. package/src/otlp/decode/body.ts +127 -0
  186. package/src/otlp/decode/logs.ts +96 -0
  187. package/src/otlp/decode/metrics.ts +402 -0
  188. package/src/otlp/decode/traces.ts +92 -0
  189. package/src/otlp/decode/values.ts +150 -0
  190. package/src/otlp/decode.test.ts +800 -0
  191. package/src/otlp/decode.ts +11 -0
  192. package/src/otlp/gen/opentelemetry/proto/collector/logs/v1/logs_service_pb.ts +132 -0
  193. package/src/otlp/gen/opentelemetry/proto/collector/metrics/v1/metrics_service_pb.ts +158 -0
  194. package/src/otlp/gen/opentelemetry/proto/collector/trace/v1/trace_service_pb.ts +158 -0
  195. package/src/otlp/gen/opentelemetry/proto/common/v1/common_pb.ts +289 -0
  196. package/src/otlp/gen/opentelemetry/proto/logs/v1/logs_pb.ts +397 -0
  197. package/src/otlp/gen/opentelemetry/proto/metrics/v1/metrics_pb.ts +1329 -0
  198. package/src/otlp/gen/opentelemetry/proto/resource/v1/resource_pb.ts +86 -0
  199. package/src/otlp/gen/opentelemetry/proto/trace/v1/trace_pb.ts +710 -0
  200. package/src/otlp/response.test.ts +158 -0
  201. package/src/otlp/response.ts +129 -0
  202. package/src/plugins/_context.ts +15 -0
  203. package/src/plugins/action-graph-processor/enrichers.ts +45 -0
  204. package/src/plugins/action-graph-processor/redaction.ts +84 -0
  205. package/src/plugins/action-graph-processor.test.ts +1023 -0
  206. package/src/plugins/action-graph-processor.ts +1172 -0
  207. package/src/plugins/action-routes.test.ts +716 -0
  208. package/src/plugins/action-routes.ts +343 -0
  209. package/src/plugins/ai-receiver.ts +254 -0
  210. package/src/plugins/ai-span-payloads-processor.test.ts +90 -0
  211. package/src/plugins/ai-span-payloads-processor.ts +180 -0
  212. package/src/plugins/alerts-evaluator.test.ts +91 -0
  213. package/src/plugins/alerts-evaluator.ts +328 -0
  214. package/src/plugins/alerts-routes.ts +101 -0
  215. package/src/plugins/analyses-routes.ts +138 -0
  216. package/src/plugins/ask-routes.ts +182 -0
  217. package/src/plugins/bot-filter.ts +19 -0
  218. package/src/plugins/connected-routes/manifest.ts +531 -0
  219. package/src/plugins/connected-routes.test.ts +1791 -0
  220. package/src/plugins/connected-routes.ts +1103 -0
  221. package/src/plugins/dashboard-routes.ts +41 -0
  222. package/src/plugins/default-span-enrichment.ts +92 -0
  223. package/src/plugins/eval-cases-routes.test.ts +391 -0
  224. package/src/plugins/eval-cases-routes.ts +529 -0
  225. package/src/plugins/evidence-retrieval-routes.benchmark.test.ts +245 -0
  226. package/src/plugins/evidence-retrieval-routes.test.ts +932 -0
  227. package/src/plugins/evidence-retrieval-routes.ts +2179 -0
  228. package/src/plugins/gen-ai-normalizer.test.ts +680 -0
  229. package/src/plugins/gen-ai-normalizer.ts +302 -0
  230. package/src/plugins/identity-receiver.ts +96 -0
  231. package/src/plugins/issue-enrichment.ts +132 -0
  232. package/src/plugins/issue-insights.ts +81 -0
  233. package/src/plugins/logs-receiver.ts +160 -0
  234. package/src/plugins/metrics-receiver.ts +91 -0
  235. package/src/plugins/onboarding-routes.ts +54 -0
  236. package/src/plugins/otlp-receiver.ts +124 -0
  237. package/src/plugins/platform-routes.ts +165 -0
  238. package/src/plugins/profile-routes.ts +468 -0
  239. package/src/plugins/projects-routes.ts +92 -0
  240. package/src/plugins/query-routes.ts +220 -0
  241. package/src/plugins/redaction-processor.ts +132 -0
  242. package/src/plugins/replay-query-routes.test.ts +38 -0
  243. package/src/plugins/replay-query-routes.ts +199 -0
  244. package/src/plugins/replay-receiver.ts +81 -0
  245. package/src/plugins/tail-routes.test.ts +47 -0
  246. package/src/plugins/tail-routes.ts +42 -0
  247. package/src/plugins/timeline-routes.ts +244 -0
  248. package/src/plugins/ua-enrichment.ts +27 -0
  249. package/src/plugins/usage-normalization.ts +46 -0
  250. package/src/plugins/usage-privacy.ts +55 -0
  251. package/src/plugins/usage-query-routes.ts +102 -0
  252. package/src/plugins/usage-receiver.ts +129 -0
  253. package/src/plugins/users-query-routes.ts +78 -0
  254. package/src/plugins/utm-enrichment.ts +36 -0
@@ -0,0 +1 @@
1
+ export const FETCH_LIMIT = 200;
@@ -0,0 +1,199 @@
1
+ import type { SqlDb } from "../sql-db";
2
+ import { FETCH_LIMIT } from "./constants";
3
+ import { mapAi, mapLog, mapMetricExemplar, mapSpan, mapUsage } from "./mappers";
4
+ import type { EntityManifest } from "./types";
5
+
6
+ export async function manifestBySession(
7
+ db: SqlDb,
8
+ projectId: string,
9
+ sessionId: string,
10
+ ): Promise<EntityManifest> {
11
+ const [spans, logs, usage, aiCalls, replay] = await Promise.all([
12
+ db
13
+ .prepare(
14
+ `SELECT trace_id, span_id, parent_span_id, service_name, span_name,
15
+ status_code, status_message, start_time, duration_ms, interaction_id
16
+ FROM telemetry_spans
17
+ WHERE project_id = ? AND session_id = ?
18
+ ORDER BY start_time ASC LIMIT ?`,
19
+ )
20
+ .bind(projectId, sessionId, FETCH_LIMIT)
21
+ .all<Parameters<typeof mapSpan>[0]>(),
22
+ db
23
+ .prepare(
24
+ `SELECT log_id, trace_id, span_id, service_name, logger_name,
25
+ severity, message, occurred_at, interaction_id, session_id
26
+ FROM logs
27
+ WHERE project_id = ? AND session_id = ?
28
+ ORDER BY occurred_at ASC LIMIT ?`,
29
+ )
30
+ .bind(projectId, sessionId, FETCH_LIMIT)
31
+ .all<Parameters<typeof mapLog>[0]>(),
32
+ db
33
+ .prepare(
34
+ `SELECT event_id, event_type, event_name, page_path, severity,
35
+ occurred_at, interaction_id, session_id
36
+ FROM usage_events
37
+ WHERE project_id = ? AND session_id = ?
38
+ ORDER BY occurred_at ASC LIMIT ?`,
39
+ )
40
+ .bind(projectId, sessionId, FETCH_LIMIT)
41
+ .all<Parameters<typeof mapUsage>[0]>(),
42
+ db
43
+ .prepare(
44
+ `SELECT call_id, trace_id, model_name, provider, total_cost_usd,
45
+ occurred_at, interaction_id, session_id
46
+ FROM ai_calls
47
+ WHERE project_id = ? AND session_id = ?
48
+ ORDER BY occurred_at ASC LIMIT ?`,
49
+ )
50
+ .bind(projectId, sessionId, FETCH_LIMIT)
51
+ .all<Parameters<typeof mapAi>[0]>(),
52
+ db
53
+ .prepare(
54
+ `SELECT first_chunk_at, last_chunk_at, chunk_count, events_count
55
+ FROM session_replay_metadata
56
+ WHERE session_id = ?`,
57
+ )
58
+ .bind(sessionId)
59
+ .first<{
60
+ first_chunk_at: string;
61
+ last_chunk_at: string;
62
+ chunk_count: number;
63
+ events_count: number;
64
+ }>(),
65
+ ]);
66
+
67
+ return {
68
+ spans: spans.results.map(mapSpan),
69
+ logs: logs.results.map(mapLog),
70
+ usageEvents: usage.results.map(mapUsage),
71
+ aiCalls: aiCalls.results.map(mapAi),
72
+ metricExemplars: [],
73
+ replay: replay
74
+ ? {
75
+ sessionId,
76
+ firstChunkAt: replay.first_chunk_at,
77
+ lastChunkAt: replay.last_chunk_at,
78
+ chunkCount: replay.chunk_count,
79
+ eventsCount: replay.events_count,
80
+ }
81
+ : null,
82
+ };
83
+ }
84
+
85
+ export async function manifestByTrace(
86
+ db: SqlDb,
87
+ projectId: string,
88
+ traceId: string,
89
+ ): Promise<EntityManifest> {
90
+ const [spans, logs, aiCalls, metricExemplars] = await Promise.all([
91
+ db
92
+ .prepare(
93
+ `SELECT trace_id, span_id, parent_span_id, service_name, span_name,
94
+ status_code, status_message, start_time, duration_ms, interaction_id
95
+ FROM telemetry_spans
96
+ WHERE project_id = ? AND trace_id = ?
97
+ ORDER BY start_time ASC LIMIT ?`,
98
+ )
99
+ .bind(projectId, traceId, FETCH_LIMIT)
100
+ .all<Parameters<typeof mapSpan>[0]>(),
101
+ db
102
+ .prepare(
103
+ `SELECT log_id, trace_id, span_id, service_name, logger_name,
104
+ severity, message, occurred_at, interaction_id, session_id
105
+ FROM logs
106
+ WHERE project_id = ? AND trace_id = ?
107
+ ORDER BY occurred_at ASC LIMIT ?`,
108
+ )
109
+ .bind(projectId, traceId, FETCH_LIMIT)
110
+ .all<Parameters<typeof mapLog>[0]>(),
111
+ db
112
+ .prepare(
113
+ `SELECT call_id, trace_id, model_name, provider, total_cost_usd,
114
+ occurred_at, interaction_id, session_id
115
+ FROM ai_calls
116
+ WHERE project_id = ? AND trace_id = ?
117
+ ORDER BY occurred_at ASC LIMIT ?`,
118
+ )
119
+ .bind(projectId, traceId, FETCH_LIMIT)
120
+ .all<Parameters<typeof mapAi>[0]>(),
121
+ db
122
+ .prepare(
123
+ `SELECT id, point_id, series_id, metric_name, service_name,
124
+ trace_id, span_id, ts_ns, value, received_at
125
+ FROM metric_exemplars
126
+ WHERE project_id = ? AND trace_id = ?
127
+ ORDER BY ts_ns DESC LIMIT ?`,
128
+ )
129
+ .bind(projectId, traceId, FETCH_LIMIT)
130
+ .all<Parameters<typeof mapMetricExemplar>[0]>(),
131
+ ]);
132
+
133
+ return {
134
+ spans: spans.results.map(mapSpan),
135
+ logs: logs.results.map(mapLog),
136
+ usageEvents: [],
137
+ aiCalls: aiCalls.results.map(mapAi),
138
+ metricExemplars: metricExemplars.results.map(mapMetricExemplar),
139
+ replay: null,
140
+ };
141
+ }
142
+
143
+ export async function manifestByInteraction(
144
+ db: SqlDb,
145
+ projectId: string,
146
+ interactionId: string,
147
+ ): Promise<EntityManifest> {
148
+ const [spans, logs, usage, aiCalls] = await Promise.all([
149
+ db
150
+ .prepare(
151
+ `SELECT trace_id, span_id, parent_span_id, service_name, span_name,
152
+ status_code, status_message, start_time, duration_ms, interaction_id
153
+ FROM telemetry_spans
154
+ WHERE project_id = ? AND interaction_id = ?
155
+ ORDER BY start_time ASC LIMIT ?`,
156
+ )
157
+ .bind(projectId, interactionId, FETCH_LIMIT)
158
+ .all<Parameters<typeof mapSpan>[0]>(),
159
+ db
160
+ .prepare(
161
+ `SELECT log_id, trace_id, span_id, service_name, logger_name,
162
+ severity, message, occurred_at, interaction_id, session_id
163
+ FROM logs
164
+ WHERE project_id = ? AND interaction_id = ?
165
+ ORDER BY occurred_at ASC LIMIT ?`,
166
+ )
167
+ .bind(projectId, interactionId, FETCH_LIMIT)
168
+ .all<Parameters<typeof mapLog>[0]>(),
169
+ db
170
+ .prepare(
171
+ `SELECT event_id, event_type, event_name, page_path, severity,
172
+ occurred_at, interaction_id, session_id
173
+ FROM usage_events
174
+ WHERE project_id = ? AND interaction_id = ?
175
+ ORDER BY occurred_at ASC LIMIT ?`,
176
+ )
177
+ .bind(projectId, interactionId, FETCH_LIMIT)
178
+ .all<Parameters<typeof mapUsage>[0]>(),
179
+ db
180
+ .prepare(
181
+ `SELECT call_id, trace_id, model_name, provider, total_cost_usd,
182
+ occurred_at, interaction_id, session_id
183
+ FROM ai_calls
184
+ WHERE project_id = ? AND interaction_id = ?
185
+ ORDER BY occurred_at ASC LIMIT ?`,
186
+ )
187
+ .bind(projectId, interactionId, FETCH_LIMIT)
188
+ .all<Parameters<typeof mapAi>[0]>(),
189
+ ]);
190
+
191
+ return {
192
+ spans: spans.results.map(mapSpan),
193
+ logs: logs.results.map(mapLog),
194
+ usageEvents: usage.results.map(mapUsage),
195
+ aiCalls: aiCalls.results.map(mapAi),
196
+ metricExemplars: [],
197
+ replay: null,
198
+ };
199
+ }
@@ -0,0 +1,349 @@
1
+ import {
2
+ ACTION_CONFIDENCE_KEY,
3
+ ACTION_ID_KEY,
4
+ ACTION_ID_RE,
5
+ ActionConfidence,
6
+ } from "@obsunified/types/constants";
7
+ import type {
8
+ ActionRef,
9
+ AgentRunRef,
10
+ AICallRef,
11
+ ArtifactRef,
12
+ EvalResultRef,
13
+ LogRef,
14
+ MetricExemplarRef,
15
+ RetrievalEventRef,
16
+ SpanRef,
17
+ ToolCallRef,
18
+ UsageEventRef,
19
+ } from "./types";
20
+
21
+ const parseAttrs = (attrsJson: string | null): Record<string, unknown> => {
22
+ if (!attrsJson) return {};
23
+ try {
24
+ const parsed = JSON.parse(attrsJson);
25
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
26
+ ? (parsed as Record<string, unknown>)
27
+ : {};
28
+ } catch {
29
+ return {};
30
+ }
31
+ };
32
+
33
+ const mapCausalConfidence = (action: {
34
+ id: string;
35
+ attrs_json: string | null;
36
+ }): ActionRef["causalConfidence"] => {
37
+ const attrs = parseAttrs(action.attrs_json);
38
+ const attrConfidence = attrs[ACTION_CONFIDENCE_KEY];
39
+ const attrActionId = attrs[ACTION_ID_KEY];
40
+ const hasTrustedExplicitId =
41
+ typeof attrActionId === "string" &&
42
+ attrActionId === action.id &&
43
+ ACTION_ID_RE.test(attrActionId);
44
+
45
+ if (attrConfidence === ActionConfidence.Fallback) {
46
+ return ActionConfidence.Fallback;
47
+ }
48
+ if (attrConfidence === ActionConfidence.Explicit && hasTrustedExplicitId) {
49
+ return ActionConfidence.Explicit;
50
+ }
51
+ return hasTrustedExplicitId
52
+ ? ActionConfidence.Explicit
53
+ : ActionConfidence.Fallback;
54
+ };
55
+
56
+ export const mapSpan = (r: {
57
+ trace_id: string;
58
+ span_id: string;
59
+ parent_span_id: string | null;
60
+ service_name: string | null;
61
+ span_name: string;
62
+ status_code: number;
63
+ status_message: string | null;
64
+ start_time: string;
65
+ duration_ms: number;
66
+ interaction_id: string | null;
67
+ }): SpanRef => ({
68
+ traceId: r.trace_id,
69
+ spanId: r.span_id,
70
+ parentSpanId: r.parent_span_id,
71
+ serviceName: r.service_name,
72
+ spanName: r.span_name,
73
+ statusCode: r.status_code,
74
+ statusMessage: r.status_message,
75
+ startTime: r.start_time,
76
+ durationMs: r.duration_ms,
77
+ interactionId: r.interaction_id,
78
+ });
79
+
80
+ export const mapLog = (r: {
81
+ log_id: string;
82
+ trace_id: string | null;
83
+ span_id: string | null;
84
+ service_name: string | null;
85
+ logger_name: string | null;
86
+ severity: string;
87
+ message: string;
88
+ occurred_at: string;
89
+ interaction_id: string | null;
90
+ }): LogRef => ({
91
+ logId: r.log_id,
92
+ traceId: r.trace_id,
93
+ spanId: r.span_id,
94
+ serviceName: r.service_name,
95
+ loggerName: r.logger_name,
96
+ severity: r.severity,
97
+ message: r.message,
98
+ occurredAt: r.occurred_at,
99
+ interactionId: r.interaction_id,
100
+ });
101
+
102
+ export const mapUsage = (r: {
103
+ event_id: string;
104
+ event_type: string;
105
+ event_name: string;
106
+ page_path: string | null;
107
+ severity: string | null;
108
+ occurred_at: string;
109
+ interaction_id: string | null;
110
+ session_id: string | null;
111
+ }): UsageEventRef => ({
112
+ eventId: r.event_id,
113
+ eventType: r.event_type,
114
+ eventName: r.event_name,
115
+ pagePath: r.page_path,
116
+ severity: r.severity,
117
+ occurredAt: r.occurred_at,
118
+ interactionId: r.interaction_id,
119
+ sessionId: r.session_id,
120
+ });
121
+
122
+ export const mapAi = (r: {
123
+ call_id: string;
124
+ trace_id: string | null;
125
+ model_name: string;
126
+ provider: string;
127
+ total_cost_usd: number | null;
128
+ occurred_at: string;
129
+ interaction_id: string | null;
130
+ }): AICallRef => ({
131
+ callId: r.call_id,
132
+ traceId: r.trace_id,
133
+ modelName: r.model_name,
134
+ provider: r.provider,
135
+ totalCostUsd: r.total_cost_usd,
136
+ occurredAt: r.occurred_at,
137
+ interactionId: r.interaction_id,
138
+ });
139
+
140
+ export const mapMetricExemplar = (r: {
141
+ id: string;
142
+ point_id: string;
143
+ series_id: string;
144
+ metric_name: string;
145
+ service_name: string | null;
146
+ trace_id: string | null;
147
+ span_id: string | null;
148
+ ts_ns: string;
149
+ value: number;
150
+ received_at: string;
151
+ }): MetricExemplarRef => ({
152
+ id: r.id,
153
+ pointId: r.point_id,
154
+ seriesId: r.series_id,
155
+ metricName: r.metric_name,
156
+ serviceName: r.service_name,
157
+ traceId: r.trace_id,
158
+ spanId: r.span_id,
159
+ tsNs: r.ts_ns,
160
+ value: r.value,
161
+ receivedAt: r.received_at,
162
+ });
163
+
164
+ export const mapAction = (r: {
165
+ id: string;
166
+ project_id: string;
167
+ root_action_id: string;
168
+ caused_by_action_id: string | null;
169
+ actor_type: string;
170
+ actor_id: string | null;
171
+ action_kind: string;
172
+ name: string | null;
173
+ status: string;
174
+ started_at: string;
175
+ ended_at: string | null;
176
+ duration_ms: number | null;
177
+ trace_id: string | null;
178
+ span_id: string | null;
179
+ session_id: string | null;
180
+ interaction_id: string | null;
181
+ user_id: string | null;
182
+ agent_run_id: string | null;
183
+ step_id: string | null;
184
+ tool_call_id: string | null;
185
+ prompt_version: string | null;
186
+ model_name: string | null;
187
+ provider: string | null;
188
+ total_cost_usd: number | null;
189
+ attrs_json: string | null;
190
+ }): ActionRef => ({
191
+ id: r.id,
192
+ projectId: r.project_id,
193
+ rootActionId: r.root_action_id,
194
+ causedByActionId: r.caused_by_action_id,
195
+ actorType: r.actor_type,
196
+ actorId: r.actor_id,
197
+ actionKind: r.action_kind,
198
+ name: r.name,
199
+ status: r.status,
200
+ startedAt: r.started_at,
201
+ endedAt: r.ended_at,
202
+ durationMs: r.duration_ms,
203
+ traceId: r.trace_id,
204
+ spanId: r.span_id,
205
+ sessionId: r.session_id,
206
+ interactionId: r.interaction_id,
207
+ userId: r.user_id,
208
+ agentRunId: r.agent_run_id,
209
+ stepId: r.step_id,
210
+ toolCallId: r.tool_call_id,
211
+ promptVersion: r.prompt_version,
212
+ modelName: r.model_name,
213
+ provider: r.provider,
214
+ totalCostUsd: r.total_cost_usd,
215
+ causalConfidence: mapCausalConfidence(r),
216
+ attrsJson: r.attrs_json,
217
+ });
218
+
219
+ export const mapAgentRun = (r: {
220
+ id: string;
221
+ project_id: string;
222
+ agent_id: string;
223
+ agent_name: string;
224
+ agent_version: string;
225
+ goal: string | null;
226
+ outcome: string | null;
227
+ autonomy_level: string;
228
+ status: string;
229
+ error_message: string | null;
230
+ total_cost_usd: number | null;
231
+ total_duration_ms: number | null;
232
+ metadata_json: string | null;
233
+ }): AgentRunRef => ({
234
+ id: r.id,
235
+ projectId: r.project_id,
236
+ agentId: r.agent_id,
237
+ agentName: r.agent_name,
238
+ agentVersion: r.agent_version,
239
+ goal: r.goal,
240
+ outcome: r.outcome,
241
+ autonomyLevel: r.autonomy_level,
242
+ status: r.status,
243
+ errorMessage: r.error_message,
244
+ totalCostUsd: r.total_cost_usd,
245
+ totalDurationMs: r.total_duration_ms,
246
+ metadataJson: r.metadata_json,
247
+ });
248
+
249
+ export const mapToolCall = (r: {
250
+ id: string;
251
+ action_id: string;
252
+ project_id: string;
253
+ tool_name: string;
254
+ args_hash: string;
255
+ result_hash: string;
256
+ error_type: string | null;
257
+ side_effect: number;
258
+ approval_state: string | null;
259
+ args_redacted: string | null;
260
+ result_redacted: string | null;
261
+ mcp_audit_json?: string | null;
262
+ mutation_before_json?: string | null;
263
+ mutation_after_json?: string | null;
264
+ mutation_diff_json?: string | null;
265
+ mutation_artifact_id?: string | null;
266
+ }): ToolCallRef => ({
267
+ id: r.id,
268
+ actionId: r.action_id,
269
+ projectId: r.project_id,
270
+ toolName: r.tool_name,
271
+ argsHash: r.args_hash,
272
+ resultHash: r.result_hash,
273
+ errorType: r.error_type,
274
+ sideEffect: r.side_effect,
275
+ approvalState: r.approval_state,
276
+ argsRedacted: r.args_redacted,
277
+ resultRedacted: r.result_redacted,
278
+ mcpAuditJson: r.mcp_audit_json ?? null,
279
+ mutationBeforeJson: r.mutation_before_json ?? null,
280
+ mutationAfterJson: r.mutation_after_json ?? null,
281
+ mutationDiffJson: r.mutation_diff_json ?? null,
282
+ mutationArtifactId: r.mutation_artifact_id ?? null,
283
+ });
284
+
285
+ export const mapRetrievalEvent = (r: {
286
+ id: string;
287
+ action_id: string;
288
+ project_id: string;
289
+ retriever_name: string;
290
+ query_hash: string;
291
+ documents_json: string | null;
292
+ total_results: number;
293
+ max_relevance_score: number | null;
294
+ duration_ms: number | null;
295
+ }): RetrievalEventRef => ({
296
+ id: r.id,
297
+ actionId: r.action_id,
298
+ projectId: r.project_id,
299
+ retrieverName: r.retriever_name,
300
+ queryHash: r.query_hash,
301
+ documentsJson: r.documents_json,
302
+ totalResults: r.total_results,
303
+ maxRelevanceScore: r.max_relevance_score,
304
+ durationMs: r.duration_ms,
305
+ });
306
+
307
+ export const mapEvalResult = (r: {
308
+ id: string;
309
+ action_id: string;
310
+ project_id: string;
311
+ evaluator_name: string;
312
+ evaluator_version: string;
313
+ score: number | null;
314
+ passed: number;
315
+ reasoning: string | null;
316
+ rubric_json: string | null;
317
+ }): EvalResultRef => ({
318
+ id: r.id,
319
+ actionId: r.action_id,
320
+ projectId: r.project_id,
321
+ evaluatorName: r.evaluator_name,
322
+ evaluatorVersion: r.evaluator_version,
323
+ score: r.score,
324
+ passed: r.passed,
325
+ reasoning: r.reasoning,
326
+ rubricJson: r.rubric_json,
327
+ });
328
+
329
+ export const mapArtifact = (r: {
330
+ id: string;
331
+ action_id: string;
332
+ project_id: string;
333
+ artifact_name: string;
334
+ artifact_type: string;
335
+ storage_ref: string | null;
336
+ size_bytes: number | null;
337
+ sha256_hash: string | null;
338
+ content_preview: string | null;
339
+ }): ArtifactRef => ({
340
+ id: r.id,
341
+ actionId: r.action_id,
342
+ projectId: r.project_id,
343
+ artifactName: r.artifact_name,
344
+ artifactType: r.artifact_type,
345
+ storageRef: r.storage_ref,
346
+ sizeBytes: r.size_bytes,
347
+ sha256Hash: r.sha256_hash,
348
+ contentPreview: r.content_preview,
349
+ });