@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 +18 -0
- package/README.md +36 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.js +176 -0
- package/package.json +39 -0
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.
|
package/dist/index.d.ts
ADDED
|
@@ -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
|
+
}
|