@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,279 @@
1
+ export type AttributeKey = (typeof ALL_ATTRIBUTE_KEYS)[number];
2
+
3
+ export const RESOURCE_ATTRIBUTES = {
4
+ SERVICE_NAME: "service.name",
5
+ SERVICE_NAMESPACE: "service.namespace",
6
+ SERVICE_VERSION: "service.version",
7
+ SERVICE_INSTANCE_ID: "service.instance.id",
8
+ TELEMETRY_SDK_NAME: "telemetry.sdk.name",
9
+ OBSERVME_VERSION: "observme.version",
10
+ OBSERVME_INSTANCE_ID: "observme.instance.id",
11
+ PI_AGENT_ID: "pi.agent.id",
12
+ PI_AGENT_PARENT_ID: "pi.agent.parent_id",
13
+ PI_AGENT_ROOT_ID: "pi.agent.root_id",
14
+ PI_AGENT_ROLE: "pi.agent.role",
15
+ PI_AGENT_DEPTH: "pi.agent.depth",
16
+ PI_CWD_HASH: "pi.cwd.hash",
17
+ PI_CWD_BASENAME: "pi.cwd.basename",
18
+ DEPLOYMENT_ENVIRONMENT_NAME: "deployment.environment.name",
19
+ OBSERVME_ENVIRONMENT: "observme.environment",
20
+ OBSERVME_TENANT_ID: "observme.tenant.id",
21
+ PI_WORKFLOW_ID: "pi.workflow.id",
22
+ PI_WORKFLOW_ROOT_AGENT_ID: "pi.workflow.root_agent_id",
23
+ PI_USER_HASH: "pi.user.hash",
24
+ PI_PROJECT_NAME: "pi.project.name",
25
+ } as const;
26
+
27
+ export const SESSION_ATTRIBUTES = {
28
+ PI_SESSION_ID: "pi.session.id",
29
+ PI_SESSION_NAME: "pi.session.name",
30
+ PI_SESSION_CWD_HASH: "pi.session.cwd_hash",
31
+ PI_SESSION_PARENT_SESSION_HASH: "pi.session.parent_session_hash",
32
+ PI_SESSION_PERSISTED: "pi.session.persisted",
33
+ PI_SESSION_FILE_HASH: "pi.session.file_hash",
34
+ PI_SESSION_VERSION: "pi.session.version",
35
+ PI_MODEL_PROVIDER_CURRENT: "pi.model.provider.current",
36
+ PI_MODEL_ID_CURRENT: "pi.model.id.current",
37
+ PI_THINKING_LEVEL_CURRENT: "pi.thinking.level.current",
38
+ } as const;
39
+
40
+ export const WORKFLOW_ATTRIBUTES = {
41
+ PI_WORKFLOW_DURATION_MS: "pi.workflow.duration_ms",
42
+ PI_WORKFLOW_STATUS: "pi.workflow.status",
43
+ } as const;
44
+
45
+ export const COMMON_SPAN_ATTRIBUTES = {
46
+ PI_SESSION_ID: "pi.session.id",
47
+ PI_WORKFLOW_ID: "pi.workflow.id",
48
+ PI_WORKFLOW_ROOT_AGENT_ID: "pi.workflow.root_agent_id",
49
+ PI_AGENT_ID: "pi.agent.id",
50
+ PI_AGENT_PARENT_ID: "pi.agent.parent_id",
51
+ PI_AGENT_ROOT_ID: "pi.agent.root_id",
52
+ PI_AGENT_RUN_ID: "pi.agent.run.id",
53
+ PI_ENTRY_ID: "pi.entry.id",
54
+ PI_ENTRY_PARENT_ID: "pi.entry.parent_id",
55
+ PI_ENTRY_TYPE: "pi.entry.type",
56
+ OBSERVME_CAPTURE_PROMPTS: "observme.capture.prompts",
57
+ OBSERVME_CAPTURE_RESPONSES: "observme.capture.responses",
58
+ OBSERVME_CAPTURE_TOOL_ARGUMENTS: "observme.capture.tool_arguments",
59
+ OBSERVME_REDACTION_ENABLED: "observme.redaction.enabled",
60
+ OBSERVME_SEMCONV_VERSION: "observme.semconv.version",
61
+ OBSERVME_REPLAYED: "observme.replayed",
62
+ OBSERVME_EVICTED: "observme.evicted",
63
+ OBSERVME_TRUNCATED: "observme.truncated",
64
+ OBSERVME_ORIGINAL_LENGTH: "observme.original_length",
65
+ } as const;
66
+
67
+ export const AGENT_LINEAGE_ATTRIBUTES = {
68
+ PI_AGENT_CAPABILITY: "pi.agent.capability",
69
+ PI_AGENT_ORPHANED: "pi.agent.orphaned",
70
+ } as const;
71
+
72
+ export const AGENT_RUN_ATTRIBUTES = {
73
+ PI_AGENT_ID: "pi.agent.id",
74
+ PI_AGENT_PARENT_ID: "pi.agent.parent_id",
75
+ PI_AGENT_ROOT_ID: "pi.agent.root_id",
76
+ PI_AGENT_ROLE: "pi.agent.role",
77
+ PI_AGENT_DEPTH: "pi.agent.depth",
78
+ PI_AGENT_RUN_ID: "pi.agent.run.id",
79
+ PI_AGENT_RUN_INDEX: "pi.agent.run.index",
80
+ PI_AGENT_RUN_SOURCE: "pi.agent.run.source",
81
+ PI_AGENT_RUN_PROMPT_HASH: "pi.agent.run.prompt.hash",
82
+ PI_AGENT_RUN_PROMPT_LENGTH: "pi.agent.run.prompt.length",
83
+ GEN_AI_AGENT_ID: "gen_ai.agent.id",
84
+ GEN_AI_AGENT_NAME: "gen_ai.agent.name",
85
+ GEN_AI_AGENT_VERSION: "gen_ai.agent.version",
86
+ } as const;
87
+
88
+ export const AGENT_SPAWN_ATTRIBUTES = {
89
+ PI_AGENT_SPAWN_ID: "pi.agent.spawn.id",
90
+ PI_AGENT_SPAWN_TYPE: "pi.agent.spawn.type",
91
+ PI_AGENT_SPAWN_REASON: "pi.agent.spawn.reason",
92
+ PI_AGENT_SPAWN_OUTCOME: "pi.agent.spawn.outcome",
93
+ PI_AGENT_SPAWN_TOOL_CALL_ID: "pi.agent.spawn.tool_call_id",
94
+ PI_AGENT_SPAWN_COMMAND_HASH: "pi.agent.spawn.command.hash",
95
+ PI_AGENT_CHILD_ID: "pi.agent.child.id",
96
+ PI_AGENT_CHILD_COUNT: "pi.agent.child.count",
97
+ PI_AGENT_CHILDREN_ACTIVE: "pi.agent.children.active",
98
+ PI_AGENT_PARENT_ID: "pi.agent.parent_id",
99
+ PI_AGENT_ROOT_ID: "pi.agent.root_id",
100
+ PI_WORKFLOW_ID: "pi.workflow.id",
101
+ PI_WORKFLOW_ROOT_AGENT_ID: "pi.workflow.root_agent_id",
102
+ PI_AGENT_DEPTH: "pi.agent.depth",
103
+ PI_SESSION_ID: "pi.session.id",
104
+ PI_AGENT_SPAWN_TRACE_CONTEXT_PROPAGATED: "pi.agent.spawn.trace_context_propagated",
105
+ } as const;
106
+
107
+ export const AGENT_WAIT_JOIN_ATTRIBUTES = {
108
+ PI_WORKFLOW_ID: "pi.workflow.id",
109
+ PI_AGENT_ID: "pi.agent.id",
110
+ PI_AGENT_CHILD_ID: "pi.agent.child.id",
111
+ PI_AGENT_SPAWN_ID: "pi.agent.spawn.id",
112
+ PI_AGENT_WAIT_REASON: "pi.agent.wait.reason",
113
+ PI_AGENT_JOIN_STATUS: "pi.agent.join.status",
114
+ PI_AGENT_CHILD_STATUS: "pi.agent.child.status",
115
+ PI_AGENT_FAILURE_PROPAGATED: "pi.agent.failure.propagated",
116
+ PI_AGENT_CHILDREN_ACTIVE: "pi.agent.children.active",
117
+ PI_AGENT_CHILD_COUNT: "pi.agent.child.count",
118
+ } as const;
119
+
120
+ export const TURN_ATTRIBUTES = {
121
+ PI_TURN_ID: "pi.turn.id",
122
+ PI_TURN_INDEX: "pi.turn.index",
123
+ PI_TURN_BRANCH_PATH_HASH: "pi.turn.branch_path_hash",
124
+ PI_TURN_USER_MESSAGE_HASH: "pi.turn.user_message.hash",
125
+ PI_TURN_USER_MESSAGE_LENGTH: "pi.turn.user_message.length",
126
+ PI_TURN_USER_MESSAGE_IMAGE_COUNT: "pi.turn.user_message.image_count",
127
+ PI_MODEL_PROVIDER_CURRENT: "pi.model.provider.current",
128
+ PI_MODEL_ID_CURRENT: "pi.model.id.current",
129
+ } as const;
130
+
131
+ export const LLM_ATTRIBUTES = {
132
+ GEN_AI_OPERATION_NAME: "gen_ai.operation.name",
133
+ GEN_AI_PROVIDER_NAME: "gen_ai.provider.name",
134
+ GEN_AI_REQUEST_MODEL: "gen_ai.request.model",
135
+ GEN_AI_RESPONSE_MODEL: "gen_ai.response.model",
136
+ GEN_AI_RESPONSE_ID: "gen_ai.response.id",
137
+ GEN_AI_RESPONSE_FINISH_REASONS: "gen_ai.response.finish_reasons",
138
+ GEN_AI_REQUEST_TEMPERATURE: "gen_ai.request.temperature",
139
+ GEN_AI_REQUEST_MAX_TOKENS: "gen_ai.request.max_tokens",
140
+ GEN_AI_USAGE_INPUT_TOKENS: "gen_ai.usage.input_tokens",
141
+ GEN_AI_USAGE_OUTPUT_TOKENS: "gen_ai.usage.output_tokens",
142
+ GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS: "gen_ai.usage.cache_read.input_tokens",
143
+ GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS: "gen_ai.usage.cache_creation.input_tokens",
144
+ GEN_AI_USAGE_REASONING_OUTPUT_TOKENS: "gen_ai.usage.reasoning.output_tokens",
145
+ GEN_AI_CONVERSATION_ID: "gen_ai.conversation.id",
146
+ ERROR_TYPE: "error.type",
147
+ PI_LLM_API: "pi.llm.api",
148
+ PI_LLM_REQUEST_THINKING_LEVEL: "pi.llm.request.thinking_level",
149
+ PI_LLM_REQUEST_MESSAGE_COUNT: "pi.llm.request.message_count",
150
+ PI_LLM_REQUEST_TOOL_SCHEMA_COUNT: "pi.llm.request.tool_schema_count",
151
+ PI_LLM_REQUEST_INPUT_CHARS: "pi.llm.request.input_chars",
152
+ PI_LLM_REQUEST_ID: "pi.llm.request.id",
153
+ PI_LLM_STOP_REASON: "pi.llm.stop_reason",
154
+ PI_LLM_ERROR_MESSAGE_HASH: "pi.llm.error_message_hash",
155
+ PI_LLM_USAGE_TOTAL_TOKENS: "pi.llm.usage.total_tokens",
156
+ PI_LLM_USAGE_CACHE_WRITE_1H_TOKENS: "pi.llm.usage.cache_write_1h_tokens",
157
+ PI_LLM_COST_INPUT_USD: "pi.llm.cost.input_usd",
158
+ PI_LLM_COST_OUTPUT_USD: "pi.llm.cost.output_usd",
159
+ PI_LLM_COST_CACHE_READ_USD: "pi.llm.cost.cache_read_usd",
160
+ PI_LLM_COST_CACHE_WRITE_USD: "pi.llm.cost.cache_write_usd",
161
+ PI_LLM_COST_TOTAL_USD: "pi.llm.cost.total_usd",
162
+ PI_LLM_TOOL_CALL_COUNT: "pi.llm.tool_call_count",
163
+ GEN_AI_INPUT_MESSAGES: "gen_ai.input.messages",
164
+ GEN_AI_OUTPUT_MESSAGES: "gen_ai.output.messages",
165
+ PI_LLM_PROMPT_REDACTED: "pi.llm.prompt.redacted",
166
+ PI_LLM_RESPONSE_REDACTED: "pi.llm.response.redacted",
167
+ PI_LLM_THINKING_REDACTED: "pi.llm.thinking.redacted",
168
+ PI_LLM_CONTENT_KIND: "pi.llm.content.kind",
169
+ } as const;
170
+
171
+ export const MESSAGE_ATTRIBUTES = {
172
+ PI_MESSAGE_ROLE: "pi.message.role",
173
+ PI_MESSAGE_CONTENT_LENGTH: "pi.message.content_length",
174
+ } as const;
175
+
176
+ export const TOOL_ATTRIBUTES = {
177
+ PI_TOOL_CALL_ID: "pi.tool.call.id",
178
+ PI_TOOL_NAME: "pi.tool.name",
179
+ PI_TOOL_CATEGORY: "pi.tool.category",
180
+ PI_TOOL_ARGUMENTS_HASH: "pi.tool.arguments.hash",
181
+ PI_TOOL_ARGUMENTS_SIZE: "pi.tool.arguments.size",
182
+ PI_TOOL_RESULT_SIZE: "pi.tool.result.size",
183
+ PI_TOOL_RESULT_HASH: "pi.tool.result.hash",
184
+ PI_TOOL_SUCCESS: "pi.tool.success",
185
+ PI_TOOL_ERROR: "pi.tool.error",
186
+ PI_TOOL_ERROR_CLASS: "pi.tool.error_class",
187
+ GEN_AI_TOOL_CALL_ID: "gen_ai.tool.call.id",
188
+ GEN_AI_TOOL_NAME: "gen_ai.tool.name",
189
+ GEN_AI_TOOL_TYPE: "gen_ai.tool.type",
190
+ PI_TOOL_ARGUMENTS_REDACTED: "pi.tool.arguments.redacted",
191
+ PI_TOOL_RESULT_REDACTED: "pi.tool.result.redacted",
192
+ GEN_AI_TOOL_CALL_ARGUMENTS: "gen_ai.tool.call.arguments",
193
+ GEN_AI_TOOL_CALL_RESULT: "gen_ai.tool.call.result",
194
+ } as const;
195
+
196
+ export const BASH_ATTRIBUTES = {
197
+ PI_BASH_COMMAND_HASH: "pi.bash.command.hash",
198
+ PI_BASH_COMMAND_REDACTED: "pi.bash.command.redacted",
199
+ PI_BASH_EXIT_CODE: "pi.bash.exit_code",
200
+ PI_BASH_CANCELLED: "pi.bash.cancelled",
201
+ PI_BASH_TRUNCATED: "pi.bash.truncated",
202
+ PI_BASH_OUTPUT_SIZE: "pi.bash.output.size",
203
+ PI_BASH_OUTPUT_HASH: "pi.bash.output.hash",
204
+ PI_BASH_OUTPUT_REDACTED: "pi.bash.output.redacted",
205
+ PI_BASH_FULL_OUTPUT_PATH_PRESENT: "pi.bash.full_output_path_present",
206
+ PI_BASH_EXCLUDE_FROM_CONTEXT: "pi.bash.exclude_from_context",
207
+ } as const;
208
+
209
+ export const BRANCH_ATTRIBUTES = {
210
+ PI_BRANCH_FROM_ID: "pi.branch.from_id",
211
+ PI_BRANCH_TO_ID: "pi.branch.to_id",
212
+ PI_BRANCH_COMMON_ANCESTOR_ID: "pi.branch.common_ancestor_id",
213
+ PI_BRANCH_PATH_HASH: "pi.branch.path_hash",
214
+ PI_LEAF_ID: "pi.leaf.id",
215
+ PI_BRANCH_SUMMARY_HASH: "pi.branch.summary.hash",
216
+ PI_BRANCH_SUMMARY_LENGTH: "pi.branch.summary.length",
217
+ PI_BRANCH_FROM_HOOK: "pi.branch.from_hook",
218
+ PI_BRANCH_READ_FILES_COUNT: "pi.branch.read_files_count",
219
+ PI_BRANCH_MODIFIED_FILES_COUNT: "pi.branch.modified_files_count",
220
+ } as const;
221
+
222
+ export const COMPACTION_ATTRIBUTES = {
223
+ PI_COMPACTION_FIRST_KEPT_ENTRY_ID: "pi.compaction.first_kept_entry_id",
224
+ PI_COMPACTION_TOKENS_BEFORE: "pi.compaction.tokens_before",
225
+ PI_COMPACTION_SUMMARY_HASH: "pi.compaction.summary.hash",
226
+ PI_COMPACTION_SUMMARY_LENGTH: "pi.compaction.summary.length",
227
+ PI_COMPACTION_FROM_HOOK: "pi.compaction.from_hook",
228
+ PI_COMPACTION_REASON: "pi.compaction.reason",
229
+ PI_COMPACTION_WILL_RETRY: "pi.compaction.will_retry",
230
+ PI_COMPACTION_READ_FILES_COUNT: "pi.compaction.read_files_count",
231
+ PI_COMPACTION_MODIFIED_FILES_COUNT: "pi.compaction.modified_files_count",
232
+ } as const;
233
+
234
+ export const CONFIG_ATTRIBUTES = {
235
+ OBSERVME_CONFIG_SOURCE: "observme.config.source",
236
+ OBSERVME_CONFIG_REJECTION_ISSUE_CODES: "observme.config.rejection.issue_codes",
237
+ OBSERVME_CONFIG_REJECTION_ISSUE_COUNT: "observme.config.rejection.issue_count",
238
+ } as const;
239
+
240
+ export const LOG_ATTRIBUTES = {
241
+ EVENT_NAME: "event.name",
242
+ EVENT_CATEGORY: "event.category",
243
+ PI_SESSION_ID: "pi.session.id",
244
+ PI_WORKFLOW_ID: "pi.workflow.id",
245
+ PI_WORKFLOW_ROOT_AGENT_ID: "pi.workflow.root_agent_id",
246
+ PI_AGENT_ID: "pi.agent.id",
247
+ PI_AGENT_PARENT_ID: "pi.agent.parent_id",
248
+ PI_AGENT_ROOT_ID: "pi.agent.root_id",
249
+ PI_AGENT_RUN_ID: "pi.agent.run.id",
250
+ PI_TURN_ID: "pi.turn.id",
251
+ TRACE_ID: "trace_id",
252
+ SPAN_ID: "span_id",
253
+ SEVERITY: "severity",
254
+ ERROR_TYPE: "error.type",
255
+ } as const;
256
+
257
+ export const ATTRIBUTE_GROUPS = {
258
+ RESOURCE_ATTRIBUTES,
259
+ SESSION_ATTRIBUTES,
260
+ WORKFLOW_ATTRIBUTES,
261
+ COMMON_SPAN_ATTRIBUTES,
262
+ AGENT_LINEAGE_ATTRIBUTES,
263
+ AGENT_RUN_ATTRIBUTES,
264
+ AGENT_SPAWN_ATTRIBUTES,
265
+ AGENT_WAIT_JOIN_ATTRIBUTES,
266
+ TURN_ATTRIBUTES,
267
+ LLM_ATTRIBUTES,
268
+ MESSAGE_ATTRIBUTES,
269
+ TOOL_ATTRIBUTES,
270
+ BASH_ATTRIBUTES,
271
+ BRANCH_ATTRIBUTES,
272
+ COMPACTION_ATTRIBUTES,
273
+ CONFIG_ATTRIBUTES,
274
+ LOG_ATTRIBUTES,
275
+ } as const;
276
+
277
+ export const ALL_ATTRIBUTE_KEYS = [
278
+ ...new Set(Object.values(ATTRIBUTE_GROUPS).flatMap(group => Object.values(group))),
279
+ ].sort((left, right) => left.localeCompare(right));
@@ -0,0 +1,146 @@
1
+ export const OBSERVME_COUNTER_METRIC_NAMES = {
2
+ SESSIONS_STARTED_TOTAL: "observme_sessions_started_total",
3
+ SESSIONS_SHUTDOWN_TOTAL: "observme_sessions_shutdown_total",
4
+ WORKFLOWS_STARTED_TOTAL: "observme_workflows_started_total",
5
+ WORKFLOWS_COMPLETED_TOTAL: "observme_workflows_completed_total",
6
+ WORKFLOW_ERRORS_TOTAL: "observme_workflow_errors_total",
7
+ AGENT_RUNS_TOTAL: "observme_agent_runs_total",
8
+ AGENT_RUN_ERRORS_TOTAL: "observme_agent_run_errors_total",
9
+ SUBAGENTS_SPAWNED_TOTAL: "observme_subagents_spawned_total",
10
+ SUBAGENT_SPAWN_FAILURES_TOTAL: "observme_subagent_spawn_failures_total",
11
+ ORPHAN_AGENTS_TOTAL: "observme_orphan_agents_total",
12
+ TRACE_CONTEXT_PROPAGATION_FAILURES_TOTAL: "observme_trace_context_propagation_failures_total",
13
+ CHILD_AGENT_FAILURES_TOTAL: "observme_child_agent_failures_total",
14
+ PARENT_RECOVERED_FROM_CHILD_FAILURE_TOTAL: "observme_parent_recovered_from_child_failure_total",
15
+ TURNS_STARTED_TOTAL: "observme_turns_started_total",
16
+ TURNS_COMPLETED_TOTAL: "observme_turns_completed_total",
17
+ LLM_REQUESTS_TOTAL: "observme_llm_requests_total",
18
+ LLM_ERRORS_TOTAL: "observme_llm_errors_total",
19
+ TOOL_CALLS_TOTAL: "observme_tool_calls_total",
20
+ TOOL_FAILURES_TOTAL: "observme_tool_failures_total",
21
+ BASH_EXECUTIONS_TOTAL: "observme_bash_executions_total",
22
+ BASH_FAILURES_TOTAL: "observme_bash_failures_total",
23
+ MODEL_CHANGES_TOTAL: "observme_model_changes_total",
24
+ THINKING_LEVEL_CHANGES_TOTAL: "observme_thinking_level_changes_total",
25
+ COMPACTIONS_TOTAL: "observme_compactions_total",
26
+ BRANCHES_TOTAL: "observme_branches_total",
27
+ TELEMETRY_DROPPED_TOTAL: "observme_telemetry_dropped_total",
28
+ EXPORT_ERRORS_TOTAL: "observme_export_errors_total",
29
+ REDACTION_FAILURES_TOTAL: "observme_redaction_failures_total",
30
+ EVENTS_OBSERVED_TOTAL: "observme_events_observed_total",
31
+ HANDLER_ERRORS_TOTAL: "observme_handler_errors_total",
32
+ } as const;
33
+
34
+ export const OBSERVME_TOKEN_COST_COUNTER_METRIC_NAMES = {
35
+ LLM_INPUT_TOKENS_TOTAL: "observme_llm_input_tokens_total",
36
+ LLM_OUTPUT_TOKENS_TOTAL: "observme_llm_output_tokens_total",
37
+ LLM_CACHE_READ_TOKENS_TOTAL: "observme_llm_cache_read_tokens_total",
38
+ LLM_CACHE_WRITE_TOKENS_TOTAL: "observme_llm_cache_write_tokens_total",
39
+ LLM_CACHE_WRITE_1H_TOKENS_TOTAL: "observme_llm_cache_write_1h_tokens_total",
40
+ LLM_REASONING_TOKENS_TOTAL: "observme_llm_reasoning_tokens_total",
41
+ LLM_TOTAL_TOKENS_TOTAL: "observme_llm_total_tokens_total",
42
+ LLM_COST_USD_TOTAL: "observme_llm_cost_usd_total",
43
+ } as const;
44
+
45
+ export const OBSERVME_HISTOGRAM_METRIC_NAMES = {
46
+ WORKFLOW_DURATION_MS: "observme_workflow_duration_ms",
47
+ AGENT_RUN_DURATION_MS: "observme_agent_run_duration_ms",
48
+ AGENT_LIFETIME_DURATION_MS: "observme_agent_lifetime_duration_ms",
49
+ SUBAGENT_SPAWN_DURATION_MS: "observme_subagent_spawn_duration_ms",
50
+ AGENT_WAIT_DURATION_MS: "observme_agent_wait_duration_ms",
51
+ AGENT_JOIN_DURATION_MS: "observme_agent_join_duration_ms",
52
+ AGENT_TREE_DEPTH: "observme_agent_tree_depth",
53
+ AGENT_TREE_WIDTH: "observme_agent_tree_width",
54
+ AGENT_FANOUT_COUNT: "observme_agent_fanout_count",
55
+ TURN_DURATION_MS: "observme_turn_duration_ms",
56
+ LLM_REQUEST_DURATION_MS: "observme_llm_request_duration_ms",
57
+ TOOL_DURATION_MS: "observme_tool_duration_ms",
58
+ BASH_DURATION_MS: "observme_bash_duration_ms",
59
+ COMPACTION_TOKENS_BEFORE: "observme_compaction_tokens_before",
60
+ PROMPT_SIZE_CHARS: "observme_prompt_size_chars",
61
+ RESPONSE_SIZE_CHARS: "observme_response_size_chars",
62
+ TOOL_RESULT_SIZE_CHARS: "observme_tool_result_size_chars",
63
+ HANDLER_DURATION_MS: "observme_handler_duration_ms",
64
+ } as const;
65
+
66
+ export const OBSERVME_GAUGE_METRIC_NAMES = {
67
+ ACTIVE_SPANS: "observme_active_spans",
68
+ ACTIVE_AGENTS: "observme_active_agents",
69
+ } as const;
70
+
71
+ export const OFFICIAL_GENAI_METRIC_NAMES = {
72
+ CLIENT_TOKEN_USAGE: "gen_ai.client.token.usage",
73
+ CLIENT_OPERATION_DURATION: "gen_ai.client.operation.duration",
74
+ } as const;
75
+
76
+ export const LOG_EVENT_NAMES = {
77
+ CONFIG_REJECTED: "config.rejected",
78
+ SESSION_STARTED: "session.started",
79
+ SESSION_NAMED: "session.named",
80
+ SESSION_SHUTDOWN: "session.shutdown",
81
+ SESSION_ERROR: "session.error",
82
+ SESSION_DUPLICATE_START: "session.duplicate_start",
83
+ WORKFLOW_STARTED: "workflow.started",
84
+ WORKFLOW_COMPLETED: "workflow.completed",
85
+ WORKFLOW_FAILED: "workflow.failed",
86
+ AGENT_RUN_STARTED: "agent.run.started",
87
+ AGENT_RUN_COMPLETED: "agent.run.completed",
88
+ AGENT_RUN_FAILED: "agent.run.failed",
89
+ AGENT_SPAWN_STARTED: "agent.spawn.started",
90
+ AGENT_SPAWN_COMPLETED: "agent.spawn.completed",
91
+ AGENT_SPAWN_FAILED: "agent.spawn.failed",
92
+ AGENT_WAIT_STARTED: "agent.wait.started",
93
+ AGENT_WAIT_COMPLETED: "agent.wait.completed",
94
+ AGENT_JOIN_STARTED: "agent.join.started",
95
+ AGENT_JOIN_COMPLETED: "agent.join.completed",
96
+ AGENT_ORPHANED: "agent.orphaned",
97
+ TRACE_CONTEXT_PROPAGATION_FAILED: "trace_context.propagation_failed",
98
+ TURN_STARTED: "turn.started",
99
+ TURN_COMPLETED: "turn.completed",
100
+ LLM_REQUEST_STARTED: "llm.request.started",
101
+ LLM_REQUEST_COMPLETED: "llm.request.completed",
102
+ LLM_REQUEST_FAILED: "llm.request.failed",
103
+ LLM_PROMPT_CAPTURED: "llm.prompt.captured",
104
+ LLM_RESPONSE_CAPTURED: "llm.response.captured",
105
+ LLM_THINKING_CAPTURED: "llm.thinking.captured",
106
+ MESSAGE_REPLAYED: "message.replayed",
107
+ TOOL_CALL_STARTED: "tool.call.started",
108
+ TOOL_CALL_COMPLETED: "tool.call.completed",
109
+ TOOL_CALL_FAILED: "tool.call.failed",
110
+ TOOL_ERROR_CAPTURED: "tool.error.captured",
111
+ BASH_COMPLETED: "bash.completed",
112
+ MODEL_CHANGED: "model.changed",
113
+ THINKING_CHANGED: "thinking.changed",
114
+ BRANCH_CREATED: "branch.created",
115
+ COMPACTION_CREATED: "compaction.created",
116
+ REDACTION_FAILED: "redaction.failed",
117
+ EXPORT_FAILED: "export.failed",
118
+ HANDLER_FAILED: "handler.failed",
119
+ TELEMETRY_DROPPED: "telemetry.dropped",
120
+ } as const;
121
+
122
+ export const OBSERVME_METRIC_NAME_GROUPS = {
123
+ COUNTERS: OBSERVME_COUNTER_METRIC_NAMES,
124
+ TOKEN_COST_COUNTERS: OBSERVME_TOKEN_COST_COUNTER_METRIC_NAMES,
125
+ HISTOGRAMS: OBSERVME_HISTOGRAM_METRIC_NAMES,
126
+ GAUGES: OBSERVME_GAUGE_METRIC_NAMES,
127
+ } as const;
128
+
129
+ export const ALL_OBSERVME_METRIC_NAMES = [
130
+ ...new Set(Object.values(OBSERVME_METRIC_NAME_GROUPS).flatMap(group => Object.values(group))),
131
+ ].sort((left, right) => left.localeCompare(right));
132
+
133
+ export const ALL_OFFICIAL_GENAI_METRIC_NAMES = Object.values(OFFICIAL_GENAI_METRIC_NAMES).sort((left, right) =>
134
+ left.localeCompare(right),
135
+ );
136
+
137
+ export const ALL_METRIC_NAMES = [...ALL_OBSERVME_METRIC_NAMES, ...ALL_OFFICIAL_GENAI_METRIC_NAMES].sort((left, right) =>
138
+ left.localeCompare(right),
139
+ );
140
+
141
+ export const ALL_LOG_EVENT_NAMES = Object.values(LOG_EVENT_NAMES).sort((left, right) => left.localeCompare(right));
142
+
143
+ export type ObservMeMetricName = (typeof ALL_OBSERVME_METRIC_NAMES)[number];
144
+ export type OfficialGenAiMetricName = (typeof ALL_OFFICIAL_GENAI_METRIC_NAMES)[number];
145
+ export type MetricName = (typeof ALL_METRIC_NAMES)[number];
146
+ export type LogEventName = (typeof ALL_LOG_EVENT_NAMES)[number];
@@ -0,0 +1,19 @@
1
+ export const SPAN_NAMES = {
2
+ PI_SESSION: "pi.session",
3
+ PI_AGENT_RUN: "pi.agent.run",
4
+ PI_AGENT_SPAWN: "pi.agent.spawn",
5
+ PI_AGENT_WAIT: "pi.agent.wait",
6
+ PI_AGENT_JOIN: "pi.agent.join",
7
+ PI_TURN: "pi.turn",
8
+ PI_LLM_REQUEST: "pi.llm.request",
9
+ PI_TOOL_CALL: "pi.tool.call",
10
+ PI_BASH_EXECUTION: "pi.bash.execution",
11
+ PI_COMPACTION: "pi.compaction",
12
+ PI_BRANCH: "pi.branch",
13
+ PI_MODEL_CHANGE: "pi.model.change",
14
+ PI_THINKING_CHANGE: "pi.thinking.change",
15
+ } as const;
16
+
17
+ export const ALL_SPAN_NAMES = Object.values(SPAN_NAMES).sort((left, right) => left.localeCompare(right));
18
+
19
+ export type SpanName = (typeof ALL_SPAN_NAMES)[number];
@@ -0,0 +1,13 @@
1
+ export const SUBAGENT_SPAWN_REASON_VALUES = [
2
+ "delegated_task",
3
+ "parallel_search",
4
+ "review",
5
+ "tool_wrapper",
6
+ "unknown",
7
+ ] as const;
8
+
9
+ export type SubagentSpawnReason = (typeof SUBAGENT_SPAWN_REASON_VALUES)[number];
10
+
11
+ export const AGENT_WAIT_REASON_VALUES = ["dependency", "rate_limit", "child_running", "unknown"] as const;
12
+
13
+ export type AgentWaitReason = (typeof AGENT_WAIT_REASON_VALUES)[number];
@@ -0,0 +1,97 @@
1
+ export interface BoundedMapEviction<K, V> {
2
+ readonly key: K;
3
+ readonly value: V;
4
+ readonly reason: "max_size_exceeded";
5
+ }
6
+
7
+ export interface BoundedMapOptions<K, V> {
8
+ readonly maxSize: number;
9
+ readonly onEvict?: (eviction: BoundedMapEviction<K, V>) => void;
10
+ readonly entries?: Iterable<readonly [K, V]>;
11
+ }
12
+
13
+ export class BoundedMap<K, V> implements Iterable<[K, V]> {
14
+ readonly #maxSize: number;
15
+ readonly #entries = new Map<K, V>();
16
+ readonly #onEvict?: (eviction: BoundedMapEviction<K, V>) => void;
17
+
18
+ constructor(options: BoundedMapOptions<K, V>) {
19
+ assertValidMaxSize(options.maxSize);
20
+ this.#maxSize = options.maxSize;
21
+ this.#onEvict = options.onEvict;
22
+
23
+ if (options.entries) this.setMany(options.entries);
24
+ }
25
+
26
+ get maxSize(): number {
27
+ return this.#maxSize;
28
+ }
29
+
30
+ get size(): number {
31
+ return this.#entries.size;
32
+ }
33
+
34
+ get(key: K): V | undefined {
35
+ return this.#entries.get(key);
36
+ }
37
+
38
+ has(key: K): boolean {
39
+ return this.#entries.has(key);
40
+ }
41
+
42
+ set(key: K, value: V): this {
43
+ this.#entries.set(key, value);
44
+ this.evictOldestEntriesOverLimit();
45
+ return this;
46
+ }
47
+
48
+ setMany(entries: Iterable<readonly [K, V]>): this {
49
+ for (const [key, value] of entries) this.set(key, value);
50
+ return this;
51
+ }
52
+
53
+ delete(key: K): boolean {
54
+ return this.#entries.delete(key);
55
+ }
56
+
57
+ clear(): void {
58
+ this.#entries.clear();
59
+ }
60
+
61
+ keys(): MapIterator<K> {
62
+ return this.#entries.keys();
63
+ }
64
+
65
+ values(): MapIterator<V> {
66
+ return this.#entries.values();
67
+ }
68
+
69
+ entries(): MapIterator<[K, V]> {
70
+ return this.#entries.entries();
71
+ }
72
+
73
+ toMap(): Map<K, V> {
74
+ return new Map(this.#entries);
75
+ }
76
+
77
+ [Symbol.iterator](): MapIterator<[K, V]> {
78
+ return this.entries();
79
+ }
80
+
81
+ private evictOldestEntriesOverLimit(): void {
82
+ while (this.#entries.size > this.#maxSize) this.evictOldestEntry();
83
+ }
84
+
85
+ private evictOldestEntry(): void {
86
+ const oldestEntry = this.#entries.entries().next().value;
87
+ if (!oldestEntry) return;
88
+
89
+ const [key, value] = oldestEntry;
90
+ this.#entries.delete(key);
91
+ this.#onEvict?.({ key, value, reason: "max_size_exceeded" });
92
+ }
93
+ }
94
+
95
+ export function assertValidMaxSize(maxSize: number): void {
96
+ if (!Number.isInteger(maxSize) || maxSize < 1) throw new Error("BoundedMap maxSize must be a positive integer");
97
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2023",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "noEmit": true,
11
+ "allowImportingTsExtensions": true,
12
+ "types": ["node"]
13
+ },
14
+ "include": ["src/**/*.ts"]
15
+ }