@cybernetyx1/atlasflow-observability 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.
package/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ PROPRIETARY SOFTWARE LICENSE
2
+
3
+ Copyright (c) 2026 Cybernetyx. All rights reserved.
4
+
5
+ This software and its source code are the proprietary and confidential property
6
+ of the copyright holder. The software is original work authored independently.
7
+
8
+ No part of this software may be copied, reproduced, modified, published,
9
+ distributed, sublicensed, or sold in any form or by any means without the prior
10
+ written permission of the copyright holder, except as expressly permitted by a
11
+ separate written agreement.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT
16
+ HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION
17
+ OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE
18
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # @cybernetyx1/atlasflow-observability
2
+
3
+ Lightweight JSON logging and in-process metrics observers for the AtlasFlow runtime event stream.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ pnpm add @cybernetyx1/atlasflow-observability
9
+ ```
10
+
11
+ Part of the AtlasFlow monorepo. Proprietary.
12
+
13
+ ## Usage
14
+
15
+ Subscribe an observer to the runtime event bus with `observe()`. `createJsonLogObserver` turns events into JSONL-friendly log records (with filtering and tool-argument redaction); `createMetricsObserver` aggregates run/turn/tool/error counts and token cost, exposing `snapshot()` and `reset()`.
16
+
17
+ ```ts
18
+ import { observe } from "@cybernetyx1/atlasflow-runtime";
19
+ import { createJsonLogObserver, createMetricsObserver } from "@cybernetyx1/atlasflow-observability";
20
+
21
+ observe(createJsonLogObserver());
22
+
23
+ const metrics = createMetricsObserver();
24
+ observe(metrics.observe);
25
+
26
+ // later
27
+ console.log(metrics.snapshot()); // { runsStarted, runsSucceeded, totalTokens, costTotal, byAgent, ... }
28
+ ```
29
+
30
+ In generated servers these are wired automatically: set `ATLASFLOW_OBSERVABILITY=metrics` (or `all`), or `ATLASFLOW_METRICS=true`, to enable the metrics observer and surface it on the authenticated `/admin/metrics` route.
31
+
32
+ Exports: `createJsonLogObserver`, `createMetricsObserver`, and the `LogLevel` / `JsonLogRecord` / `JsonLogObserverOptions` / `AgentMetrics` / `ObservabilityMetrics` / `MetricsObserver` types.
33
+
34
+ ## License
35
+
36
+ Proprietary. © 2026 Cybernetyx. See LICENSE.
@@ -0,0 +1,67 @@
1
+ import { AtlasEvent, EventSubscriber } from '@cybernetyx1/atlasflow-runtime';
2
+
3
+ /**
4
+ * @cybernetyx1/atlasflow-observability — lightweight observers for AtlasFlow's event
5
+ * stream. Use this when you want structured logs and counters without wiring a
6
+ * full OpenTelemetry provider.
7
+ */
8
+
9
+ type LogLevel = "debug" | "info" | "warn" | "error";
10
+ interface JsonLogRecord {
11
+ timestamp: string;
12
+ type: AtlasEvent["type"];
13
+ level: LogLevel;
14
+ runId?: string;
15
+ session?: string;
16
+ event: AtlasEvent;
17
+ }
18
+ interface JsonLogObserverOptions {
19
+ /** Called with one JSON-ready record per event. Defaults to console.log(JSON). */
20
+ sink?: (record: JsonLogRecord) => void | Promise<void>;
21
+ /** Keep only selected event types. */
22
+ include?: AtlasEvent["type"][];
23
+ /** Drop selected event types after include filtering. */
24
+ exclude?: AtlasEvent["type"][];
25
+ /** Include high-volume text/thinking deltas. Defaults to false unless include is set. */
26
+ includeDeltas?: boolean;
27
+ /** Replace tool-call arguments with a marker before logging. Defaults to true. */
28
+ redactToolArguments?: boolean;
29
+ /** Inspect/redact events before logging. Return undefined to drop. */
30
+ sanitize?: (event: AtlasEvent) => AtlasEvent | undefined;
31
+ }
32
+ interface AgentMetrics {
33
+ runsStarted: number;
34
+ runsSucceeded: number;
35
+ runsFailed: number;
36
+ runErrors: number;
37
+ toolCalls: number;
38
+ toolErrors: number;
39
+ totalTokens: number;
40
+ costTotal: number;
41
+ }
42
+ interface ObservabilityMetrics extends AgentMetrics {
43
+ runsEnded: number;
44
+ operationsStarted: number;
45
+ operationsEnded: number;
46
+ operationErrors: number;
47
+ taskCalls: number;
48
+ taskErrors: number;
49
+ ruleBlocks: number;
50
+ ruleWarnings: number;
51
+ compactedTokens: number;
52
+ byAgent: Record<string, AgentMetrics>;
53
+ }
54
+ interface MetricsObserver {
55
+ observe: EventSubscriber;
56
+ snapshot(): ObservabilityMetrics;
57
+ reset(): void;
58
+ }
59
+ /** Create a JSONL-friendly event observer with filtering and redaction hooks. */
60
+ declare function createJsonLogObserver(options?: JsonLogObserverOptions): EventSubscriber;
61
+ /**
62
+ * Create an in-process metrics observer. The returned observer is synchronous
63
+ * and intentionally tiny; export `snapshot()` to your own metrics backend.
64
+ */
65
+ declare function createMetricsObserver(): MetricsObserver;
66
+
67
+ export { type AgentMetrics, type JsonLogObserverOptions, type JsonLogRecord, type LogLevel, type MetricsObserver, type ObservabilityMetrics, createJsonLogObserver, createMetricsObserver };
package/dist/index.js ADDED
@@ -0,0 +1,176 @@
1
+ // src/index.ts
2
+ var ZERO_AGENT = {
3
+ runsStarted: 0,
4
+ runsSucceeded: 0,
5
+ runsFailed: 0,
6
+ runErrors: 0,
7
+ toolCalls: 0,
8
+ toolErrors: 0,
9
+ totalTokens: 0,
10
+ costTotal: 0
11
+ };
12
+ function zeroMetrics() {
13
+ return {
14
+ ...ZERO_AGENT,
15
+ runsEnded: 0,
16
+ operationsStarted: 0,
17
+ operationsEnded: 0,
18
+ operationErrors: 0,
19
+ taskCalls: 0,
20
+ taskErrors: 0,
21
+ ruleBlocks: 0,
22
+ ruleWarnings: 0,
23
+ compactedTokens: 0,
24
+ byAgent: {}
25
+ };
26
+ }
27
+ function redactEvent(event, options) {
28
+ if (options.redactToolArguments === false || event.type !== "tool_call") return event;
29
+ return { ...event, arguments: { redacted: true } };
30
+ }
31
+ function eventLevel(event) {
32
+ switch (event.type) {
33
+ case "log":
34
+ return event.level;
35
+ case "run_error":
36
+ return "error";
37
+ case "run_end":
38
+ case "operation_end":
39
+ case "tool_result":
40
+ case "task_end":
41
+ return event.ok ? "info" : "error";
42
+ case "rule_triggered":
43
+ return "warn";
44
+ case "text_delta":
45
+ case "thinking_delta":
46
+ return "debug";
47
+ default:
48
+ return "info";
49
+ }
50
+ }
51
+ function createJsonLogObserver(options = {}) {
52
+ const include = options.include ? new Set(options.include) : void 0;
53
+ const exclude = new Set(options.exclude ?? []);
54
+ const sink = options.sink ?? ((record) => console.log(JSON.stringify(record)));
55
+ const dropDeltas = !include && options.includeDeltas !== true;
56
+ return (raw) => {
57
+ if (include && !include.has(raw.type)) return;
58
+ if (exclude.has(raw.type)) return;
59
+ if (dropDeltas && (raw.type === "text_delta" || raw.type === "thinking_delta")) return;
60
+ const redacted = redactEvent(raw, options);
61
+ const event = options.sanitize ? options.sanitize(redacted) : redacted;
62
+ if (!event) return;
63
+ const record = {
64
+ timestamp: new Date(event.timestamp).toISOString(),
65
+ type: event.type,
66
+ level: eventLevel(event),
67
+ runId: event.runId,
68
+ session: event.session,
69
+ event
70
+ };
71
+ void Promise.resolve(sink(record)).catch(() => {
72
+ });
73
+ };
74
+ }
75
+ function createMetricsObserver() {
76
+ let metrics = zeroMetrics();
77
+ const runAgents = /* @__PURE__ */ new Map();
78
+ const forAgent = (agent) => {
79
+ if (!agent) return void 0;
80
+ metrics.byAgent[agent] ??= { ...ZERO_AGENT };
81
+ return metrics.byAgent[agent];
82
+ };
83
+ const runAgent = (event) => {
84
+ return event.runId ? forAgent(runAgents.get(event.runId)) : void 0;
85
+ };
86
+ return {
87
+ observe(event) {
88
+ switch (event.type) {
89
+ case "run_start": {
90
+ if (event.runId) runAgents.set(event.runId, event.agent);
91
+ metrics.runsStarted++;
92
+ forAgent(event.agent).runsStarted++;
93
+ break;
94
+ }
95
+ case "run_end": {
96
+ metrics.runsEnded++;
97
+ const agent = runAgent(event);
98
+ if (event.ok) {
99
+ metrics.runsSucceeded++;
100
+ if (agent) agent.runsSucceeded++;
101
+ } else {
102
+ metrics.runsFailed++;
103
+ if (agent) agent.runsFailed++;
104
+ }
105
+ if (event.runId) runAgents.delete(event.runId);
106
+ break;
107
+ }
108
+ case "run_error": {
109
+ metrics.runErrors++;
110
+ const agent = runAgent(event);
111
+ if (agent) agent.runErrors++;
112
+ break;
113
+ }
114
+ case "operation_start": {
115
+ metrics.operationsStarted++;
116
+ break;
117
+ }
118
+ case "operation_end": {
119
+ metrics.operationsEnded++;
120
+ if (!event.ok) metrics.operationErrors++;
121
+ break;
122
+ }
123
+ case "turn_end": {
124
+ metrics.totalTokens += event.usage.totalTokens;
125
+ metrics.costTotal += event.usage.costTotal;
126
+ const agent = runAgent(event);
127
+ if (agent) {
128
+ agent.totalTokens += event.usage.totalTokens;
129
+ agent.costTotal += event.usage.costTotal;
130
+ }
131
+ break;
132
+ }
133
+ case "tool_call": {
134
+ metrics.toolCalls++;
135
+ const agent = runAgent(event);
136
+ if (agent) agent.toolCalls++;
137
+ break;
138
+ }
139
+ case "tool_result": {
140
+ if (!event.ok) {
141
+ metrics.toolErrors++;
142
+ const agent = runAgent(event);
143
+ if (agent) agent.toolErrors++;
144
+ }
145
+ break;
146
+ }
147
+ case "task_start":
148
+ metrics.taskCalls++;
149
+ break;
150
+ case "task_end":
151
+ if (!event.ok) metrics.taskErrors++;
152
+ break;
153
+ case "rule_triggered":
154
+ if (event.action === "block") metrics.ruleBlocks++;
155
+ else metrics.ruleWarnings++;
156
+ break;
157
+ case "compaction":
158
+ metrics.compactedTokens += event.freedTokens;
159
+ break;
160
+ default:
161
+ break;
162
+ }
163
+ },
164
+ snapshot() {
165
+ return JSON.parse(JSON.stringify(metrics));
166
+ },
167
+ reset() {
168
+ metrics = zeroMetrics();
169
+ runAgents.clear();
170
+ }
171
+ };
172
+ }
173
+ export {
174
+ createJsonLogObserver,
175
+ createMetricsObserver
176
+ };
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@cybernetyx1/atlasflow-observability",
3
+ "version": "0.1.0",
4
+ "description": "JSON logging and in-process metrics observers for AtlasFlow event streams.",
5
+ "type": "module",
6
+ "license": "SEE LICENSE IN LICENSE",
7
+ "author": "Cybernetyx",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/Cybernetyx/atlasflow.git",
11
+ "directory": "packages/observability"
12
+ },
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js"
17
+ }
18
+ },
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "dependencies": {
23
+ "@cybernetyx1/atlasflow-runtime": "0.1.0"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^22.10.0",
27
+ "tsup": "^8.3.5",
28
+ "typescript": "^5.7.2",
29
+ "valibot": "^1.0.0"
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "scripts": {
35
+ "build": "tsup",
36
+ "typecheck": "tsc --noEmit",
37
+ "test": "node --import tsx --test test/*.test.ts"
38
+ }
39
+ }