@smithers-orchestrator/observability 0.16.0

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 (202) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +44 -0
  3. package/src/MetricName.ts +1 -0
  4. package/src/MetricsServiceLive.js +9 -0
  5. package/src/ResolvedSmithersObservabilityOptions.ts +10 -0
  6. package/src/SmithersEvent.ts +603 -0
  7. package/src/SmithersLogFormat.ts +1 -0
  8. package/src/SmithersMetricDefinition.ts +15 -0
  9. package/src/SmithersMetricType.ts +1 -0
  10. package/src/SmithersMetricUnit.ts +8 -0
  11. package/src/SmithersObservability.js +6 -0
  12. package/src/SmithersObservabilityOptions.ts +10 -0
  13. package/src/SmithersObservabilityService.ts +15 -0
  14. package/src/_coreCorrelation/CorrelationContext.ts +10 -0
  15. package/src/_coreCorrelation/CorrelationContextLive.js +11 -0
  16. package/src/_coreCorrelation/CorrelationContextService.js +6 -0
  17. package/src/_coreCorrelation/CorrelationContextServiceShape.ts +14 -0
  18. package/src/_coreCorrelation/CorrelationPatch.ts +3 -0
  19. package/src/_coreCorrelation/_correlationStorage.js +4 -0
  20. package/src/_coreCorrelation/correlationContextFiberRef.js +2 -0
  21. package/src/_coreCorrelation/correlationContextToLogAnnotations.js +28 -0
  22. package/src/_coreCorrelation/getCurrentCorrelationContext.js +9 -0
  23. package/src/_coreCorrelation/getCurrentCorrelationContextEffect.js +11 -0
  24. package/src/_coreCorrelation/index.js +14 -0
  25. package/src/_coreCorrelation/mergeCorrelationContext.js +61 -0
  26. package/src/_coreCorrelation/runWithCorrelationContext.js +14 -0
  27. package/src/_coreCorrelation/updateCurrentCorrelationContext.js +19 -0
  28. package/src/_coreCorrelation/withCorrelationContext.js +15 -0
  29. package/src/_coreCorrelation/withCurrentCorrelationContext.js +13 -0
  30. package/src/_coreMetrics.js +510 -0
  31. package/src/_coreMetricsShape.ts +55 -0
  32. package/src/_corePrometheus.js +93 -0
  33. package/src/_corePrometheusShape.ts +11 -0
  34. package/src/_coreTracing.js +142 -0
  35. package/src/_coreTracingShape.ts +17 -0
  36. package/src/_smithersSpanAttributeAliases.js +19 -0
  37. package/src/_smithersTraceSpanStorage.js +3 -0
  38. package/src/annotateSmithersTrace.js +11 -0
  39. package/src/correlation.js +20 -0
  40. package/src/createSmithersObservabilityLayer.js +49 -0
  41. package/src/createSmithersOtelLayer.js +21 -0
  42. package/src/createSmithersRuntimeLayer.js +2 -0
  43. package/src/getCurrentSmithersTraceAnnotations.js +14 -0
  44. package/src/getCurrentSmithersTraceSpan.js +7 -0
  45. package/src/index.d.ts +1032 -0
  46. package/src/index.js +35 -0
  47. package/src/logging.js +91 -0
  48. package/src/makeSmithersSpanAttributes.js +20 -0
  49. package/src/metrics/SmithersMetricDefinition.ts +17 -0
  50. package/src/metrics/SmithersMetricType.ts +1 -0
  51. package/src/metrics/SmithersMetricUnit.ts +8 -0
  52. package/src/metrics/_asyncExternalWaitCounts.js +4 -0
  53. package/src/metrics/_buckets.js +43 -0
  54. package/src/metrics/_processStartMs.js +1 -0
  55. package/src/metrics/activeNodes.js +2 -0
  56. package/src/metrics/activeRuns.js +2 -0
  57. package/src/metrics/agentActionsTotal.js +2 -0
  58. package/src/metrics/agentDurationMs.js +3 -0
  59. package/src/metrics/agentErrorsTotal.js +2 -0
  60. package/src/metrics/agentEventsTotal.js +2 -0
  61. package/src/metrics/agentInvocationsTotal.js +2 -0
  62. package/src/metrics/agentRetriesTotal.js +2 -0
  63. package/src/metrics/agentSessionsTotal.js +2 -0
  64. package/src/metrics/agentTokensTotal.js +2 -0
  65. package/src/metrics/alertDeliveriesAttempted.js +2 -0
  66. package/src/metrics/alertDeliveriesSuppressed.js +2 -0
  67. package/src/metrics/alertsAcknowledgedTotal.js +2 -0
  68. package/src/metrics/alertsActive.js +2 -0
  69. package/src/metrics/alertsEscalatedTotal.js +2 -0
  70. package/src/metrics/alertsFiredTotal.js +2 -0
  71. package/src/metrics/alertsReopenedTotal.js +2 -0
  72. package/src/metrics/alertsResolvedTotal.js +2 -0
  73. package/src/metrics/alertsSilencedTotal.js +2 -0
  74. package/src/metrics/approvalPending.js +2 -0
  75. package/src/metrics/approvalWaitDuration.js +3 -0
  76. package/src/metrics/approvalsDenied.js +2 -0
  77. package/src/metrics/approvalsGranted.js +2 -0
  78. package/src/metrics/approvalsRequested.js +2 -0
  79. package/src/metrics/attemptDuration.js +3 -0
  80. package/src/metrics/attentionBacklog.js +2 -0
  81. package/src/metrics/cacheHits.js +2 -0
  82. package/src/metrics/cacheMisses.js +2 -0
  83. package/src/metrics/dbQueryDuration.js +3 -0
  84. package/src/metrics/dbRetries.js +2 -0
  85. package/src/metrics/dbTransactionDuration.js +3 -0
  86. package/src/metrics/dbTransactionRetries.js +2 -0
  87. package/src/metrics/dbTransactionRollbacks.js +2 -0
  88. package/src/metrics/devtoolsActiveSubscribers.js +2 -0
  89. package/src/metrics/devtoolsBackpressureDisconnectTotal.js +2 -0
  90. package/src/metrics/devtoolsDeltaBuildMs.js +3 -0
  91. package/src/metrics/devtoolsEventBytes.js +3 -0
  92. package/src/metrics/devtoolsEventTotal.js +2 -0
  93. package/src/metrics/devtoolsSnapshotBuildMs.js +3 -0
  94. package/src/metrics/devtoolsSubscribeTotal.js +2 -0
  95. package/src/metrics/errorsTotal.js +2 -0
  96. package/src/metrics/eventsEmittedTotal.js +2 -0
  97. package/src/metrics/externalWaitAsyncPending.js +2 -0
  98. package/src/metrics/gatewayApprovalDecisionsTotal.js +2 -0
  99. package/src/metrics/gatewayAuthEventsTotal.js +2 -0
  100. package/src/metrics/gatewayConnectionsActive.js +2 -0
  101. package/src/metrics/gatewayConnectionsClosedTotal.js +2 -0
  102. package/src/metrics/gatewayConnectionsTotal.js +2 -0
  103. package/src/metrics/gatewayCronTriggersTotal.js +2 -0
  104. package/src/metrics/gatewayErrorsTotal.js +2 -0
  105. package/src/metrics/gatewayHeartbeatTicksTotal.js +2 -0
  106. package/src/metrics/gatewayMessagesReceivedTotal.js +2 -0
  107. package/src/metrics/gatewayMessagesSentTotal.js +2 -0
  108. package/src/metrics/gatewayRpcCallsTotal.js +2 -0
  109. package/src/metrics/gatewayRpcDuration.js +3 -0
  110. package/src/metrics/gatewayRunsCompletedTotal.js +2 -0
  111. package/src/metrics/gatewayRunsStartedTotal.js +2 -0
  112. package/src/metrics/gatewaySignalsTotal.js +2 -0
  113. package/src/metrics/gatewayWebhooksReceivedTotal.js +2 -0
  114. package/src/metrics/gatewayWebhooksRejectedTotal.js +2 -0
  115. package/src/metrics/gatewayWebhooksVerifiedTotal.js +2 -0
  116. package/src/metrics/heartbeatDataSizeBytes.js +3 -0
  117. package/src/metrics/heartbeatIntervalMs.js +3 -0
  118. package/src/metrics/hotReloadDuration.js +3 -0
  119. package/src/metrics/hotReloadFailures.js +2 -0
  120. package/src/metrics/hotReloads.js +2 -0
  121. package/src/metrics/httpRequestDuration.js +3 -0
  122. package/src/metrics/httpRequests.js +2 -0
  123. package/src/metrics/index.js +151 -0
  124. package/src/metrics/metricsServiceAdapter.js +188 -0
  125. package/src/metrics/nodeDuration.js +3 -0
  126. package/src/metrics/nodeRetriesTotal.js +2 -0
  127. package/src/metrics/nodesFailed.js +2 -0
  128. package/src/metrics/nodesFinished.js +2 -0
  129. package/src/metrics/nodesStarted.js +2 -0
  130. package/src/metrics/processHeapUsedBytes.js +2 -0
  131. package/src/metrics/processMemoryRssBytes.js +2 -0
  132. package/src/metrics/processUptimeSeconds.js +2 -0
  133. package/src/metrics/promptSizeBytes.js +3 -0
  134. package/src/metrics/responseSizeBytes.js +3 -0
  135. package/src/metrics/rewindDurationMs.js +3 -0
  136. package/src/metrics/rewindFramesDeleted.js +3 -0
  137. package/src/metrics/rewindRollbackTotal.js +2 -0
  138. package/src/metrics/rewindSandboxesReverted.js +3 -0
  139. package/src/metrics/rewindTotal.js +2 -0
  140. package/src/metrics/runDuration.js +3 -0
  141. package/src/metrics/runsAncestryDepth.js +3 -0
  142. package/src/metrics/runsCancelledTotal.js +2 -0
  143. package/src/metrics/runsCarriedStateBytes.js +3 -0
  144. package/src/metrics/runsContinuedTotal.js +2 -0
  145. package/src/metrics/runsFailedTotal.js +2 -0
  146. package/src/metrics/runsFinishedTotal.js +2 -0
  147. package/src/metrics/runsResumedTotal.js +2 -0
  148. package/src/metrics/runsTotal.js +2 -0
  149. package/src/metrics/sandboxActive.js +2 -0
  150. package/src/metrics/sandboxBundleSizeBytes.js +3 -0
  151. package/src/metrics/sandboxCompletedTotal.js +2 -0
  152. package/src/metrics/sandboxCreatedTotal.js +2 -0
  153. package/src/metrics/sandboxDurationMs.js +3 -0
  154. package/src/metrics/sandboxPatchCount.js +3 -0
  155. package/src/metrics/sandboxTransportDurationMs.js +3 -0
  156. package/src/metrics/schedulerConcurrencyUtilization.js +2 -0
  157. package/src/metrics/schedulerQueueDepth.js +2 -0
  158. package/src/metrics/schedulerWaitDuration.js +3 -0
  159. package/src/metrics/scorerEventsFailed.js +2 -0
  160. package/src/metrics/scorerEventsFinished.js +2 -0
  161. package/src/metrics/scorerEventsStarted.js +2 -0
  162. package/src/metrics/smithersMetricCatalog.js +484 -0
  163. package/src/metrics/smithersMetricCatalogByKey.js +2 -0
  164. package/src/metrics/smithersMetricCatalogByName.js +2 -0
  165. package/src/metrics/smithersMetricCatalogByPrometheusName.js +2 -0
  166. package/src/metrics/supervisorPollDuration.js +3 -0
  167. package/src/metrics/supervisorPollsTotal.js +2 -0
  168. package/src/metrics/supervisorResumeLag.js +3 -0
  169. package/src/metrics/supervisorResumedTotal.js +2 -0
  170. package/src/metrics/supervisorSkippedTotal.js +2 -0
  171. package/src/metrics/supervisorStaleDetected.js +2 -0
  172. package/src/metrics/taskHeartbeatTimeoutTotal.js +2 -0
  173. package/src/metrics/taskHeartbeatsTotal.js +2 -0
  174. package/src/metrics/timerDelayDuration.js +3 -0
  175. package/src/metrics/timersCancelled.js +2 -0
  176. package/src/metrics/timersCreated.js +2 -0
  177. package/src/metrics/timersFired.js +2 -0
  178. package/src/metrics/timersPending.js +2 -0
  179. package/src/metrics/toPrometheusMetricName.js +8 -0
  180. package/src/metrics/tokensCacheReadTotal.js +2 -0
  181. package/src/metrics/tokensCacheWriteTotal.js +2 -0
  182. package/src/metrics/tokensContextWindowBucketTotal.js +2 -0
  183. package/src/metrics/tokensContextWindowPerCall.js +3 -0
  184. package/src/metrics/tokensInputPerCall.js +3 -0
  185. package/src/metrics/tokensInputTotal.js +2 -0
  186. package/src/metrics/tokensOutputPerCall.js +3 -0
  187. package/src/metrics/tokensOutputTotal.js +2 -0
  188. package/src/metrics/tokensReasoningTotal.js +2 -0
  189. package/src/metrics/toolCallErrorsTotal.js +2 -0
  190. package/src/metrics/toolCallsTotal.js +2 -0
  191. package/src/metrics/toolDuration.js +3 -0
  192. package/src/metrics/toolOutputTruncatedTotal.js +2 -0
  193. package/src/metrics/trackEvent.js +604 -0
  194. package/src/metrics/updateAsyncExternalWaitPending.js +14 -0
  195. package/src/metrics/updateProcessMetrics.js +17 -0
  196. package/src/metrics/vcsDuration.js +3 -0
  197. package/src/prometheusContentType.js +1 -0
  198. package/src/renderPrometheusMetrics.js +205 -0
  199. package/src/resolveSmithersObservabilityOptions.js +79 -0
  200. package/src/smithersMetrics.js +2 -0
  201. package/src/smithersSpanNames.js +6 -0
  202. package/src/withSmithersSpan.js +15 -0
@@ -0,0 +1,93 @@
1
+
2
+ /** @typedef {import("./_corePrometheusShape.ts").MetricLabels} MetricLabels */
3
+ /** @typedef {import("./_corePrometheusShape.ts").PrometheusSample} PrometheusSample */
4
+ export {};
5
+ /**
6
+ * @param {string} name
7
+ * @returns {string}
8
+ */
9
+ export function toPrometheusMetricName(name) {
10
+ const next = name.replace(/[^a-zA-Z0-9_:]/g, "_");
11
+ return /^[a-zA-Z_:]/.test(next) ? next : `_${next}`;
12
+ }
13
+ /**
14
+ * @param {string} text
15
+ * @returns {string}
16
+ */
17
+ function escapeText(text) {
18
+ return text.replace(/\\/g, "\\\\").replace(/\n/g, "\\n");
19
+ }
20
+ /**
21
+ * @param {string} value
22
+ * @returns {string}
23
+ */
24
+ function escapeLabelValue(value) {
25
+ return escapeText(value).replace(/"/g, '\\"');
26
+ }
27
+ /**
28
+ * @param {number} value
29
+ * @returns {string}
30
+ */
31
+ function formatNumber(value) {
32
+ if (Number.isNaN(value))
33
+ return "NaN";
34
+ if (value === Number.POSITIVE_INFINITY)
35
+ return "+Inf";
36
+ if (value === Number.NEGATIVE_INFINITY)
37
+ return "-Inf";
38
+ return String(value);
39
+ }
40
+ /**
41
+ * @param {MetricLabels} labels
42
+ * @returns {string}
43
+ */
44
+ function formatLabels(labels) {
45
+ const entries = Object.entries(labels).sort(([left], [right]) => left.localeCompare(right));
46
+ if (entries.length === 0)
47
+ return "";
48
+ return `{${entries
49
+ .map(([key, value]) => `${toPrometheusMetricName(key)}="${escapeLabelValue(String(value))}"`)
50
+ .join(",")}}`;
51
+ }
52
+ /**
53
+ * @param {MetricLabels} labels
54
+ * @param {MetricLabels} extra
55
+ * @returns {MetricLabels}
56
+ */
57
+ function mergeLabels(labels, extra) {
58
+ return { ...labels, ...extra };
59
+ }
60
+ /**
61
+ * @param {readonly PrometheusSample[]} samples
62
+ * @returns {string}
63
+ */
64
+ export function renderPrometheusSamples(samples) {
65
+ const grouped = new Map();
66
+ for (const sample of samples) {
67
+ const name = toPrometheusMetricName(sample.name);
68
+ const group = grouped.get(name) ??
69
+ (() => {
70
+ const created = { type: sample.type, lines: [] };
71
+ grouped.set(name, created);
72
+ return created;
73
+ })();
74
+ if (sample.type === "histogram") {
75
+ const buckets = [...(sample.buckets ?? new Map()).entries()].sort(([left], [right]) => left - right);
76
+ for (const [boundary, count] of buckets) {
77
+ group.lines.push(`${name}_bucket${formatLabels(mergeLabels(sample.labels, { le: boundary }))} ${formatNumber(count)}`);
78
+ }
79
+ group.lines.push(`${name}_bucket${formatLabels(mergeLabels(sample.labels, { le: "+Inf" }))} ${formatNumber(sample.count ?? 0)}`);
80
+ group.lines.push(`${name}_sum${formatLabels(sample.labels)} ${formatNumber(sample.sum ?? 0)}`);
81
+ group.lines.push(`${name}_count${formatLabels(sample.labels)} ${formatNumber(sample.count ?? 0)}`);
82
+ }
83
+ else {
84
+ group.lines.push(`${name}${formatLabels(sample.labels)} ${formatNumber(sample.value ?? 0)}`);
85
+ }
86
+ }
87
+ const lines = [];
88
+ for (const [name, group] of [...grouped.entries()].sort(([left], [right]) => left.localeCompare(right))) {
89
+ lines.push(`# TYPE ${name} ${group.type}`);
90
+ lines.push(...group.lines.sort());
91
+ }
92
+ return lines.join("\n") + (lines.length > 0 ? "\n" : "");
93
+ }
@@ -0,0 +1,11 @@
1
+ export type MetricLabels = Readonly<Record<string, string | number | boolean>>;
2
+
3
+ export type PrometheusSample = {
4
+ readonly name: string;
5
+ readonly type: "counter" | "gauge" | "histogram";
6
+ readonly labels: MetricLabels;
7
+ readonly value?: number;
8
+ readonly buckets?: ReadonlyMap<number, number>;
9
+ readonly sum?: number;
10
+ readonly count?: number;
11
+ };
@@ -0,0 +1,142 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import { correlationContextToLogAnnotations, getCurrentCorrelationContext, withCorrelationContext, } from "./_coreCorrelation/index.js";
3
+ /** @typedef {import("./SmithersLogFormat.ts").SmithersLogFormat} SmithersLogFormat */
4
+ /** @typedef {import("./_coreTracingShape.ts").SmithersSpanAttributesInput} SmithersSpanAttributesInput */
5
+ /** @typedef {import("./_coreTracingShape.ts").TracingServiceShape} TracingServiceShape */
6
+
7
+ /** @type {"text/plain; version=0.0.4; charset=utf-8"} */
8
+ export const prometheusContentType = "text/plain; version=0.0.4; charset=utf-8";
9
+ /** @type {{ readonly run: "smithers.run"; readonly task: "smithers.task"; readonly agent: "smithers.agent"; readonly tool: "smithers.tool" }} */
10
+ export const smithersSpanNames = {
11
+ run: "smithers.run",
12
+ task: "smithers.task",
13
+ agent: "smithers.agent",
14
+ tool: "smithers.tool",
15
+ };
16
+ const _TracingServiceBase = /** @type {Context.TagClass<TracingService, "TracingService", TracingServiceShape>} */ (/** @type {unknown} */ (Context.Tag("TracingService")()));
17
+ export class TracingService extends _TracingServiceBase {
18
+ }
19
+ /**
20
+ * @returns {| Readonly<Record<string, string>> | undefined}
21
+ */
22
+ export function getCurrentSmithersTraceAnnotations() {
23
+ const context = getCurrentCorrelationContext();
24
+ if (!context?.traceId || !context.spanId)
25
+ return undefined;
26
+ return { traceId: context.traceId, spanId: context.spanId };
27
+ }
28
+ /**
29
+ * @param {SmithersSpanAttributesInput} [attributes]
30
+ * @returns {Record<string, unknown>}
31
+ */
32
+ export function makeSmithersSpanAttributes(attributes = {}) {
33
+ const aliases = {
34
+ runId: "smithers.run_id",
35
+ run_id: "smithers.run_id",
36
+ workflowName: "smithers.workflow_name",
37
+ workflow_name: "smithers.workflow_name",
38
+ nodeId: "smithers.node_id",
39
+ node_id: "smithers.node_id",
40
+ iteration: "smithers.iteration",
41
+ attempt: "smithers.attempt",
42
+ nodeLabel: "smithers.node_label",
43
+ node_label: "smithers.node_label",
44
+ toolName: "smithers.tool_name",
45
+ tool_name: "smithers.tool_name",
46
+ agent: "smithers.agent",
47
+ model: "smithers.model",
48
+ status: "smithers.status",
49
+ waitReason: "smithers.wait_reason",
50
+ wait_reason: "smithers.wait_reason",
51
+ };
52
+ const result = {};
53
+ for (const [key, value] of Object.entries(attributes)) {
54
+ if (value !== undefined) {
55
+ result[key.startsWith("smithers.") ? key : (aliases[key] ?? key)] = value;
56
+ }
57
+ }
58
+ return result;
59
+ }
60
+ /**
61
+ * @param {SmithersSpanAttributesInput} [attributes]
62
+ * @returns {attributes is SmithersSpanAttributesInput}
63
+ */
64
+ function hasAttributes(attributes) {
65
+ return Boolean(attributes && Object.keys(attributes).length > 0);
66
+ }
67
+ /**
68
+ * @param {string} name
69
+ * @param {SmithersSpanAttributesInput} [attributes]
70
+ * @returns {string}
71
+ */
72
+ function inferSmithersSpanName(name, attributes) {
73
+ if (name.startsWith("smithers."))
74
+ return name;
75
+ if (name.startsWith("tool:") ||
76
+ "toolName" in (attributes ?? {}) ||
77
+ "tool_name" in (attributes ?? {})) {
78
+ return smithersSpanNames.tool;
79
+ }
80
+ if (name.startsWith("agent:") ||
81
+ name.startsWith("agent.") ||
82
+ "agent" in (attributes ?? {})) {
83
+ return smithersSpanNames.agent;
84
+ }
85
+ if ("nodeId" in (attributes ?? {}) || "node_id" in (attributes ?? {})) {
86
+ return smithersSpanNames.task;
87
+ }
88
+ if ("runId" in (attributes ?? {}) || "run_id" in (attributes ?? {})) {
89
+ return smithersSpanNames.run;
90
+ }
91
+ return name;
92
+ }
93
+ /**
94
+ * @param {SmithersSpanAttributesInput} [attributes]
95
+ * @returns {Effect.Effect<void>}
96
+ */
97
+ export function annotateSmithersTrace(attributes = {}) {
98
+ const spanAttributes = makeSmithersSpanAttributes(attributes);
99
+ let program = Effect.void;
100
+ if (Object.keys(spanAttributes).length > 0) {
101
+ program = program.pipe(Effect.tap(() => Effect.annotateCurrentSpan(spanAttributes).pipe(Effect.catchAll(() => Effect.void))));
102
+ }
103
+ if (hasAttributes(attributes)) {
104
+ program = program.pipe(Effect.annotateLogs(attributes));
105
+ }
106
+ return program;
107
+ }
108
+ /**
109
+ * @template A, E, R
110
+ * @param {string} name
111
+ * @param {Effect.Effect<A, E, R>} effect
112
+ * @param {SmithersSpanAttributesInput} [attributes]
113
+ * @returns {Effect.Effect<A, E, R>}
114
+ */
115
+ export function withSmithersSpan(name, effect, attributes) {
116
+ const spanAttributes = makeSmithersSpanAttributes(attributes);
117
+ const annotations = correlationContextToLogAnnotations(getCurrentCorrelationContext());
118
+ let program = effect;
119
+ if (Object.keys(spanAttributes).length > 0) {
120
+ program = program.pipe(Effect.annotateSpans(spanAttributes));
121
+ }
122
+ if (hasAttributes(attributes)) {
123
+ program = program.pipe(Effect.annotateLogs(attributes));
124
+ }
125
+ if (annotations) {
126
+ program = program.pipe(Effect.annotateLogs(annotations));
127
+ }
128
+ return program.pipe(Effect.withLogSpan(name), Effect.withSpan(inferSmithersSpanName(name, attributes)));
129
+ }
130
+ /** @type {Layer.Layer<TracingService, never, never>} */
131
+ export const TracingServiceLive = Layer.succeed(TracingService, {
132
+ withSpan: (name, effect, attributes) => {
133
+ return withSmithersSpan(name, effect, attributes);
134
+ },
135
+ annotate: (attributes) => {
136
+ const spanAttributes = makeSmithersSpanAttributes(attributes);
137
+ return Object.keys(spanAttributes).length > 0
138
+ ? Effect.annotateCurrentSpan(spanAttributes).pipe(Effect.catchAll(() => Effect.void))
139
+ : Effect.void;
140
+ },
141
+ withCorrelation: (context, effect) => withCorrelationContext(effect, context),
142
+ });
@@ -0,0 +1,17 @@
1
+ import type { Effect } from "effect";
2
+ import type { CorrelationPatch } from "./_coreCorrelation/CorrelationPatch.ts";
3
+
4
+ export type SmithersSpanAttributesInput = Readonly<Record<string, unknown>>;
5
+
6
+ export type TracingServiceShape = {
7
+ readonly withSpan: <A, E, R>(
8
+ name: string,
9
+ effect: Effect.Effect<A, E, R>,
10
+ attributes?: Record<string, unknown>,
11
+ ) => Effect.Effect<A, E, R>;
12
+ readonly annotate: (attributes: Record<string, unknown>) => Effect.Effect<void>;
13
+ readonly withCorrelation: <A, E, R>(
14
+ context: CorrelationPatch,
15
+ effect: Effect.Effect<A, E, R>,
16
+ ) => Effect.Effect<A, E, R>;
17
+ };
@@ -0,0 +1,19 @@
1
+ export const smithersSpanAttributeAliases = {
2
+ runId: "smithers.run_id",
3
+ run_id: "smithers.run_id",
4
+ workflowName: "smithers.workflow_name",
5
+ workflow_name: "smithers.workflow_name",
6
+ nodeId: "smithers.node_id",
7
+ node_id: "smithers.node_id",
8
+ iteration: "smithers.iteration",
9
+ attempt: "smithers.attempt",
10
+ nodeLabel: "smithers.node_label",
11
+ node_label: "smithers.node_label",
12
+ toolName: "smithers.tool_name",
13
+ tool_name: "smithers.tool_name",
14
+ agent: "smithers.agent",
15
+ model: "smithers.model",
16
+ status: "smithers.status",
17
+ waitReason: "smithers.wait_reason",
18
+ wait_reason: "smithers.wait_reason",
19
+ };
@@ -0,0 +1,3 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ /** @type {AsyncLocalStorage<import("effect/Tracer").AnySpan>} */
3
+ export const smithersTraceSpanStorage = new AsyncLocalStorage();
@@ -0,0 +1,11 @@
1
+ import { TracingService, annotateSmithersTrace as annotateCoreSmithersTrace, } from "./_coreTracing.js";
2
+ import { Effect } from "effect";
3
+ /**
4
+ * @param {Readonly<Record<string, unknown>>} [attributes]
5
+ * @returns {Effect.Effect<void>}
6
+ */
7
+ export function annotateSmithersTrace(attributes = {}) {
8
+ return Effect.flatMap(Effect.serviceOption(TracingService), (service) => service._tag === "Some"
9
+ ? service.value.annotate({ ...attributes })
10
+ : annotateCoreSmithersTrace(attributes));
11
+ }
@@ -0,0 +1,20 @@
1
+ import { getCurrentCorrelationContext as getCoreCurrentCorrelationContext, mergeCorrelationContext as mergeCoreCorrelationContext, } from "./_coreCorrelation/index.js";
2
+ /** @typedef {import("./_coreCorrelation/CorrelationContext.ts").CorrelationContext} CorrelationContext */
3
+ /** @typedef {import("./_coreCorrelation/CorrelationPatch.ts").CorrelationPatch} CorrelationPatch */
4
+ /** @typedef {CorrelationPatch} CorrelationContextPatch */
5
+
6
+ export { correlationContextFiberRef, correlationContextToLogAnnotations, CorrelationContextLive, CorrelationContextService, getCurrentCorrelationContext, getCurrentCorrelationContextEffect, mergeCorrelationContext, runWithCorrelationContext, withCorrelationContext, withCurrentCorrelationContext, } from "./_coreCorrelation/index.js";
7
+ /**
8
+ * @param {CorrelationPatch} patch
9
+ */
10
+ export function updateCurrentCorrelationContext(patch) {
11
+ const current = getCoreCurrentCorrelationContext();
12
+ if (!current)
13
+ return;
14
+ // TODO: replace this compatibility shim once legacy callers adopt the
15
+ // Effect-returning updateCurrentCorrelationContext from @smithers-orchestrator/observability.
16
+ const next = mergeCoreCorrelationContext(current, patch);
17
+ if (!next)
18
+ return;
19
+ Object.assign(current, next);
20
+ }
@@ -0,0 +1,49 @@
1
+ import * as BunContext from "@effect/platform-bun/BunContext";
2
+ import { TracingServiceLive } from "./_coreTracing.js";
3
+ import { Effect, Layer, Logger } from "effect";
4
+ import { SmithersObservability } from "./SmithersObservability.js";
5
+ import { resolveSmithersObservabilityOptions } from "./resolveSmithersObservabilityOptions.js";
6
+ import { createSmithersOtelLayer } from "./createSmithersOtelLayer.js";
7
+ import { MetricsServiceLive } from "./MetricsServiceLive.js";
8
+ import { annotateSmithersTrace } from "./annotateSmithersTrace.js";
9
+ import { withSmithersSpan } from "./withSmithersSpan.js";
10
+ /** @typedef {import("./ResolvedSmithersObservabilityOptions.ts").ResolvedSmithersObservabilityOptions} ResolvedSmithersObservabilityOptions */
11
+ /** @typedef {import("./SmithersLogFormat.ts").SmithersLogFormat} SmithersLogFormat */
12
+ /** @typedef {import("./SmithersObservabilityService.ts").SmithersObservabilityService} SmithersObservabilityService */
13
+
14
+ /** @typedef {import("./SmithersObservabilityOptions.ts").SmithersObservabilityOptions} SmithersObservabilityOptions */
15
+
16
+ /**
17
+ * @param {SmithersLogFormat} format
18
+ */
19
+ function resolveLogger(format) {
20
+ switch (format) {
21
+ case "json":
22
+ return Logger.withLeveledConsole(Logger.jsonLogger);
23
+ case "pretty":
24
+ return Logger.prettyLogger();
25
+ case "string":
26
+ return Logger.withLeveledConsole(Logger.stringLogger);
27
+ case "logfmt":
28
+ default:
29
+ return Logger.withLeveledConsole(Logger.logfmtLogger);
30
+ }
31
+ }
32
+ /**
33
+ * @param {ResolvedSmithersObservabilityOptions} options
34
+ * @returns {SmithersObservabilityService}
35
+ */
36
+ function makeService(options) {
37
+ return {
38
+ options,
39
+ annotate: (attributes) => annotateSmithersTrace(attributes),
40
+ withSpan: (name, effect, attributes) => withSmithersSpan(name, effect, attributes),
41
+ };
42
+ }
43
+ /**
44
+ * @param {SmithersObservabilityOptions} [options]
45
+ */
46
+ export function createSmithersObservabilityLayer(options = {}) {
47
+ const resolved = resolveSmithersObservabilityOptions(options);
48
+ return Layer.mergeAll(BunContext.layer, Logger.replace(Logger.defaultLogger, resolveLogger(resolved.logFormat)), Logger.minimumLogLevel(resolved.logLevel), createSmithersOtelLayer(resolved), MetricsServiceLive, TracingServiceLive, Layer.succeed(SmithersObservability, makeService(resolved)));
49
+ }
@@ -0,0 +1,21 @@
1
+ import * as FetchHttpClient from "@effect/platform/FetchHttpClient";
2
+ import * as Otlp from "@effect/opentelemetry/Otlp";
3
+ import { Layer } from "effect";
4
+ import { smithersTraceSpanStorage } from "./_smithersTraceSpanStorage.js";
5
+ import { resolveSmithersObservabilityOptions } from "./resolveSmithersObservabilityOptions.js";
6
+ /** @typedef {import("./SmithersObservabilityOptions.ts").SmithersObservabilityOptions} SmithersObservabilityOptions */
7
+
8
+ /**
9
+ * @param {SmithersObservabilityOptions} [options]
10
+ */
11
+ export function createSmithersOtelLayer(options = {}) {
12
+ const resolved = resolveSmithersObservabilityOptions(options);
13
+ if (!resolved.enabled) {
14
+ return Layer.empty;
15
+ }
16
+ return Otlp.layerJson({
17
+ baseUrl: resolved.endpoint,
18
+ resource: { serviceName: resolved.serviceName },
19
+ tracerContext: (execute, span) => smithersTraceSpanStorage.run(span, execute),
20
+ }).pipe(Layer.provide(FetchHttpClient.layer));
21
+ }
@@ -0,0 +1,2 @@
1
+ import { createSmithersObservabilityLayer } from "./createSmithersObservabilityLayer.js";
2
+ export const createSmithersRuntimeLayer = createSmithersObservabilityLayer;
@@ -0,0 +1,14 @@
1
+ import { getCurrentSmithersTraceSpan } from "./getCurrentSmithersTraceSpan.js";
2
+ /**
3
+ * @returns {| Readonly<Record<string, string>> | undefined}
4
+ */
5
+ export function getCurrentSmithersTraceAnnotations() {
6
+ const span = getCurrentSmithersTraceSpan();
7
+ if (!span) {
8
+ return undefined;
9
+ }
10
+ return {
11
+ traceId: span.traceId,
12
+ spanId: span.spanId,
13
+ };
14
+ }
@@ -0,0 +1,7 @@
1
+ import { smithersTraceSpanStorage } from "./_smithersTraceSpanStorage.js";
2
+ /**
3
+ * @returns {Tracer.AnySpan | undefined}
4
+ */
5
+ export function getCurrentSmithersTraceSpan() {
6
+ return smithersTraceSpanStorage.getStore();
7
+ }