@senad-d/observme 0.1.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 (111) hide show
  1. package/.env.example +57 -0
  2. package/CHANGELOG.md +52 -0
  3. package/LICENSE +21 -0
  4. package/ObservMe-Production-Docs/00-README.md +79 -0
  5. package/ObservMe-Production-Docs/01-requirements-and-scope.md +207 -0
  6. package/ObservMe-Production-Docs/02-reference-architecture.md +306 -0
  7. package/ObservMe-Production-Docs/03-pi-event-and-session-model.md +266 -0
  8. package/ObservMe-Production-Docs/04-telemetry-semantic-conventions.md +722 -0
  9. package/ObservMe-Production-Docs/05-otel-pipeline-and-collector.md +355 -0
  10. package/ObservMe-Production-Docs/06-security-privacy-redaction.md +294 -0
  11. package/ObservMe-Production-Docs/07-extension-implementation-blueprint.md +447 -0
  12. package/ObservMe-Production-Docs/08-query-grafana-integration.md +276 -0
  13. package/ObservMe-Production-Docs/09-dashboards-alerts-slos.md +640 -0
  14. package/ObservMe-Production-Docs/10-testing-release-operations.md +319 -0
  15. package/ObservMe-Production-Docs/11-deployment-runbooks.md +203 -0
  16. package/ObservMe-Production-Docs/12-configuration-reference.md +337 -0
  17. package/ObservMe-Production-Docs/13-source-notes.md +33 -0
  18. package/ObservMe-Production-Docs/pi-session-format.md +427 -0
  19. package/README.md +356 -0
  20. package/SECURITY.md +45 -0
  21. package/dashboards/observme-agent-node-graphs.json +250 -0
  22. package/dashboards/observme-agents.json +1880 -0
  23. package/dashboards/observme-alerts.yaml +113 -0
  24. package/dashboards/observme-branches-compactions.json +1042 -0
  25. package/dashboards/observme-cost.json +1254 -0
  26. package/dashboards/observme-errors.json +1659 -0
  27. package/dashboards/observme-export-health.json +1802 -0
  28. package/dashboards/observme-latency.json +1494 -0
  29. package/dashboards/observme-llm-conversations.json +730 -0
  30. package/dashboards/observme-logs-llm.json +644 -0
  31. package/dashboards/observme-models.json +933 -0
  32. package/dashboards/observme-overview.json +2129 -0
  33. package/dashboards/observme-slo-health.json +737 -0
  34. package/dashboards/observme-slos.yaml +56 -0
  35. package/dashboards/observme-tools.json +902 -0
  36. package/dashboards/observme-trace-journey.json +1793 -0
  37. package/docs/STRUCTURE.md +49 -0
  38. package/docs/agent-subagent-observability-requirements.md +997 -0
  39. package/docs/compatibility-matrix.md +39 -0
  40. package/docs/configuration-tui-design-standard.md +767 -0
  41. package/docs/configuration.md +38 -0
  42. package/docs/review-validation.md +115 -0
  43. package/docs/validation-flow.md +117 -0
  44. package/examples/collector.yaml +123 -0
  45. package/examples/observme.yaml +131 -0
  46. package/img/demo.gif +0 -0
  47. package/img/icon.svg +47 -0
  48. package/package.json +103 -0
  49. package/src/commands/obs-agents-runtime.ts +150 -0
  50. package/src/commands/obs-agents.ts +491 -0
  51. package/src/commands/obs-args.ts +63 -0
  52. package/src/commands/obs-backfill.ts +1334 -0
  53. package/src/commands/obs-command-support.ts +43 -0
  54. package/src/commands/obs-cost.ts +228 -0
  55. package/src/commands/obs-diagnostics.ts +22 -0
  56. package/src/commands/obs-errors.ts +156 -0
  57. package/src/commands/obs-health.ts +301 -0
  58. package/src/commands/obs-link.ts +90 -0
  59. package/src/commands/obs-logs.ts +194 -0
  60. package/src/commands/obs-loki-summary.ts +184 -0
  61. package/src/commands/obs-session.ts +259 -0
  62. package/src/commands/obs-status.ts +359 -0
  63. package/src/commands/obs-tools.ts +274 -0
  64. package/src/commands/obs-trace.ts +411 -0
  65. package/src/commands/obs.ts +211 -0
  66. package/src/config/bootstrap-project-config.ts +300 -0
  67. package/src/config/defaults.ts +143 -0
  68. package/src/config/load-config.ts +631 -0
  69. package/src/config/project-paths.ts +61 -0
  70. package/src/config/schema.ts +405 -0
  71. package/src/config/validate.ts +456 -0
  72. package/src/constants.ts +4 -0
  73. package/src/diagnostics/sanitize.ts +6 -0
  74. package/src/extension.ts +38 -0
  75. package/src/otel/logs.ts +160 -0
  76. package/src/otel/metrics.ts +165 -0
  77. package/src/otel/otlp-endpoint.ts +10 -0
  78. package/src/otel/sdk.ts +114 -0
  79. package/src/otel/shutdown.ts +102 -0
  80. package/src/otel/traces.ts +166 -0
  81. package/src/pi/agent-lineage.ts +378 -0
  82. package/src/pi/agent-tree-tracker.ts +258 -0
  83. package/src/pi/event-handlers/agent-turn.ts +155 -0
  84. package/src/pi/event-handlers/lifecycle.ts +642 -0
  85. package/src/pi/event-handlers/llm.ts +115 -0
  86. package/src/pi/event-handlers/session-events.ts +159 -0
  87. package/src/pi/event-handlers/tool-bash.ts +275 -0
  88. package/src/pi/handler-internals.ts +2154 -0
  89. package/src/pi/handler-runtime.ts +633 -0
  90. package/src/pi/handler-types.ts +261 -0
  91. package/src/pi/handlers.ts +75 -0
  92. package/src/pi/subagent-spawn.ts +975 -0
  93. package/src/pi/subagent-types.ts +29 -0
  94. package/src/privacy/content-capture.ts +104 -0
  95. package/src/privacy/hash.ts +93 -0
  96. package/src/privacy/redact.ts +619 -0
  97. package/src/privacy/secret-patterns.ts +185 -0
  98. package/src/privacy/truncate.ts +69 -0
  99. package/src/query/grafana-readiness.ts +164 -0
  100. package/src/query/grafana-transport.ts +481 -0
  101. package/src/query/grafana.ts +371 -0
  102. package/src/query/loki.ts +332 -0
  103. package/src/query/prometheus.ts +388 -0
  104. package/src/query/tempo.ts +332 -0
  105. package/src/safety/sensitive-input.ts +208 -0
  106. package/src/semconv/attributes.ts +279 -0
  107. package/src/semconv/metrics.ts +146 -0
  108. package/src/semconv/spans.ts +19 -0
  109. package/src/semconv/values.ts +13 -0
  110. package/src/util/bounded-map.ts +97 -0
  111. package/tsconfig.json +15 -0
@@ -0,0 +1,155 @@
1
+ import { SpanStatusCode } from "@opentelemetry/api";
2
+ import { recordObsSessionTurn } from "../../commands/obs-session.ts";
3
+ import { AGENT_RUN_ATTRIBUTES, TURN_ATTRIBUTES } from "../../semconv/attributes.ts";
4
+ import { LOG_EVENT_NAMES } from "../../semconv/metrics.ts";
5
+ import { SPAN_NAMES } from "../../semconv/spans.ts";
6
+ import {
7
+ buildAgentRunAttributes,
8
+ buildLineageMetricSafeLogAttributes,
9
+ buildTurnAttributes,
10
+ deriveTurnId,
11
+ emitLifecycleLog,
12
+ endActiveSpan,
13
+ metricLabels,
14
+ nextAgentRunId,
15
+ nextTurnIndex,
16
+ readInteger,
17
+ readString,
18
+ recordSpanDurationMs,
19
+ recordTelemetryDrop,
20
+ startActiveChildSpan,
21
+ } from "../handler-internals.ts";
22
+ import { workflowFailed } from "../handler-runtime.ts";
23
+ import type { HandlerRegistrar } from "../handler-runtime.ts";
24
+ import type { Handler, HandlerSessionState, ObservMeHandlerContext } from "../handler-types.ts";
25
+
26
+ export function registerAgentTurnHandlers(registrar: HandlerRegistrar, state: HandlerSessionState): void {
27
+ registrar.add("agent_start", createAgentStartHandler(state));
28
+ registrar.add("turn_start", createTurnStartHandler(state));
29
+ registrar.add("turn_end", createTurnEndHandler(state));
30
+ registrar.add("agent_end", createAgentEndHandler(state));
31
+ }
32
+
33
+ function createAgentStartHandler(state: HandlerSessionState): Handler {
34
+ return handleAgentStart.bind(undefined, state);
35
+ }
36
+
37
+ function handleAgentStart(state: HandlerSessionState, event: unknown, _ctx: ObservMeHandlerContext): void {
38
+ const session = state.session;
39
+ if (!session) return;
40
+
41
+ const runId = nextAgentRunId(session, event);
42
+ const attributes = buildAgentRunAttributes(event, session, runId);
43
+ const span = startActiveChildSpan(session, SPAN_NAMES.PI_AGENT_RUN, session.sessionSpan, attributes, "agent_run");
44
+
45
+ session.currentAgentRunId = runId;
46
+ session.spans.activeAgentRuns.set(runId, span);
47
+ session.metrics.agentRuns.add(1, metricLabels(session.config, session.lineage));
48
+ emitLifecycleLog(session.logger, LOG_EVENT_NAMES.AGENT_RUN_STARTED, attributes);
49
+ }
50
+
51
+ function createAgentEndHandler(state: HandlerSessionState): Handler {
52
+ return handleAgentEnd.bind(undefined, state);
53
+ }
54
+
55
+ function handleAgentEnd(state: HandlerSessionState, event: unknown, _ctx: ObservMeHandlerContext): void {
56
+ const session = state.session;
57
+ if (!session) return;
58
+
59
+ const runId = readString(event, "agentRunId") ?? readString(event, "runId") ?? session.currentAgentRunId;
60
+ if (!runId) return;
61
+
62
+ const span = session.spans.activeAgentRuns.get(runId);
63
+ const failed = workflowFailed(event);
64
+ const labels = metricLabels(session.config, session.lineage);
65
+ if (failed) span?.setStatus({ code: SpanStatusCode.ERROR });
66
+ if (span && failed) session.metrics.agentRunErrors.add(1, labels);
67
+ recordSpanDurationMs(span, session.metrics.agentRunDurationMs, labels);
68
+ endActiveSpan(session, span);
69
+ session.spans.activeAgentRuns.delete(runId);
70
+ session.turnSequences.delete(runId);
71
+ if (session.currentAgentRunId === runId) session.currentAgentRunId = undefined;
72
+ emitLifecycleLog(session.logger, failed ? LOG_EVENT_NAMES.AGENT_RUN_FAILED : LOG_EVENT_NAMES.AGENT_RUN_COMPLETED, {
73
+ [AGENT_RUN_ATTRIBUTES.PI_AGENT_RUN_ID]: runId,
74
+ ...buildLineageMetricSafeLogAttributes(session),
75
+ });
76
+ }
77
+
78
+ function createTurnStartHandler(state: HandlerSessionState): Handler {
79
+ return handleTurnStart.bind(undefined, state);
80
+ }
81
+
82
+ function handleTurnStart(state: HandlerSessionState, event: unknown, _ctx: ObservMeHandlerContext): void {
83
+ const session = state.session;
84
+ if (!session) return;
85
+
86
+ const hadCurrentAgentRun = session.currentAgentRunId !== undefined;
87
+ const runId = session.currentAgentRunId ?? nextAgentRunId(session, event);
88
+ if (!hadCurrentAgentRun) recordTelemetryDrop(session, "agent_run_id_missing_turn_start", { operation: "turn_start" });
89
+ const runSpan = session.spans.activeAgentRuns.get(runId) ?? session.sessionSpan;
90
+ const turnIndex = nextTurnIndex(session, runId, event);
91
+ const turnId = deriveTurnId(runId, turnIndex);
92
+ const attributes = buildTurnAttributes(event, session, runId, turnId, turnIndex);
93
+ const span = startActiveChildSpan(session, SPAN_NAMES.PI_TURN, runSpan, attributes, "turn");
94
+
95
+ session.currentTurnId = turnId;
96
+ session.spans.activeTurns.set(turnId, span);
97
+ session.metrics.turnsStarted.add(1, metricLabels(session.config, session.lineage));
98
+ recordObsSessionTurn();
99
+ emitLifecycleLog(session.logger, LOG_EVENT_NAMES.TURN_STARTED, attributes);
100
+ }
101
+
102
+ function createTurnEndHandler(state: HandlerSessionState): Handler {
103
+ return handleTurnEnd.bind(undefined, state);
104
+ }
105
+
106
+ function handleTurnEnd(state: HandlerSessionState, event: unknown, _ctx: ObservMeHandlerContext): void {
107
+ const session = state.session;
108
+ if (!session) return;
109
+
110
+ const explicitTurnId = readString(event, "turnId") ?? readString(event, "turn_id");
111
+ let turnId = explicitTurnId;
112
+ let runId = readString(event, "agentRunId") ?? readString(event, "runId") ?? session.currentAgentRunId;
113
+ if (!runId && !turnId && session.currentTurnId) {
114
+ turnId = session.currentTurnId;
115
+ runId = readRunIdFromTurnId(turnId);
116
+ }
117
+ if (!runId) {
118
+ recordTelemetryDrop(session, "turn_run_id_missing", { operation: "turn_end" });
119
+ return;
120
+ }
121
+
122
+ const turnIndex = readInteger(event, "turnIndex") ?? readInteger(event, "turn_index") ?? session.turnSequences.get(runId);
123
+ if (!turnId) {
124
+ if (!turnIndex) {
125
+ recordTelemetryDrop(session, "turn_index_missing", { operation: "turn_end" });
126
+ return;
127
+ }
128
+ turnId = deriveTurnId(runId, turnIndex);
129
+ }
130
+
131
+ const span = session.spans.activeTurns.get(turnId);
132
+ if (!span) {
133
+ recordTelemetryDrop(session, "turn_span_missing", { operation: "turn_end" });
134
+ return;
135
+ }
136
+
137
+ if (workflowFailed(event)) span.setStatus({ code: SpanStatusCode.ERROR });
138
+ recordSpanDurationMs(span, session.metrics.turnDurationMs, metricLabels(session.config, session.lineage));
139
+ endActiveSpan(session, span);
140
+ session.spans.activeTurns.delete(turnId);
141
+ if (session.currentTurnId === turnId) session.currentTurnId = undefined;
142
+ session.metrics.turnsCompleted.add(1, metricLabels(session.config, session.lineage));
143
+ emitLifecycleLog(session.logger, LOG_EVENT_NAMES.TURN_COMPLETED, {
144
+ [TURN_ATTRIBUTES.PI_TURN_ID]: turnId,
145
+ [AGENT_RUN_ATTRIBUTES.PI_AGENT_RUN_ID]: runId,
146
+ ...buildLineageMetricSafeLogAttributes(session),
147
+ });
148
+ }
149
+
150
+ function readRunIdFromTurnId(turnId: string): string | undefined {
151
+ const separator = "-turn-";
152
+ const separatorIndex = turnId.lastIndexOf(separator);
153
+ if (separatorIndex <= 0) return undefined;
154
+ return turnId.slice(0, separatorIndex);
155
+ }