@assemblyline-agents/otlp 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 +21 -0
- package/README.md +19 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +65 -0
- package/dist/index.js.map +1 -0
- package/dist/semconv.d.ts +58 -0
- package/dist/semconv.d.ts.map +1 -0
- package/dist/semconv.js +164 -0
- package/dist/semconv.js.map +1 -0
- package/dist/sink.d.ts +48 -0
- package/dist/sink.d.ts.map +1 -0
- package/dist/sink.js +114 -0
- package/dist/sink.js.map +1 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 OpenEve contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# @assemblyline-agents/otlp
|
|
2
|
+
|
|
3
|
+
Official Assembly Line OTLP/HTTP instrumentation plugin for GenAI telemetry backends.
|
|
4
|
+
|
|
5
|
+
It provides `createOtlpSink` / `createOtlpSinkFromEnv`, which build an OTLP/HTTP `TelemetrySink` (with GenAI semantic conventions) for use inside an agent's `instrumentation.ts` via `defineInstrumentation`. Point it at any OTLP-compatible backend to collect run, turn, and model-usage telemetry from deployed agents.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install @assemblyline-agents/otlp
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Part of Assembly Line
|
|
14
|
+
|
|
15
|
+
This package is part of [Assembly Line](https://github.com/jasonbadeaux/openeve), a vendor-neutral, filesystem-first framework for durable AI agents. See the developer documentation in [docs/developers/](https://github.com/jasonbadeaux/openeve/tree/main/docs/developers) for setup, agent authoring, and deployment guides.
|
|
16
|
+
|
|
17
|
+
## License
|
|
18
|
+
|
|
19
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { TelemetrySink } from "@assemblyline-agents/runtime";
|
|
2
|
+
import { type OtlpSinkOptions } from "./sink.js";
|
|
3
|
+
export * from "./semconv.js";
|
|
4
|
+
export * from "./sink.js";
|
|
5
|
+
/**
|
|
6
|
+
* Build an OTLP/HTTP GenAI {@link TelemetrySink} for use inside
|
|
7
|
+
* `agent/instrumentation.ts`. Wire it in the `setup` callback of
|
|
8
|
+
* `defineInstrumentation`, the single home for telemetry:
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { defineInstrumentation } from "@assemblyline-agents/core";
|
|
12
|
+
* import { createOtlpSinkFromEnv } from "@assemblyline-agents/otlp";
|
|
13
|
+
*
|
|
14
|
+
* export default defineInstrumentation({
|
|
15
|
+
* serviceName: "my-agent",
|
|
16
|
+
* captureContent: "usage",
|
|
17
|
+
* setup: ({ env }) => createOtlpSinkFromEnv(env)
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function createOtlpSink(options: OtlpSinkOptions): TelemetrySink;
|
|
22
|
+
/**
|
|
23
|
+
* Convenience factory that reads OTLP configuration from environment variables
|
|
24
|
+
* (`OTEL_EXPORTER_OTLP_ENDPOINT`, `OTEL_EXPORTER_OTLP_HEADERS`,
|
|
25
|
+
* `OTEL_SERVICE_NAME`, `OTEL_EXPORTER_OTLP_TIMEOUT`, `OPENEVE_OTLP_BATCH_MAX`,
|
|
26
|
+
* `OPENEVE_OTLP_FLUSH_MS`). Pass the `env` handed to the instrumentation
|
|
27
|
+
* `setup` callback so it matches the runtime's environment.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createOtlpSinkFromEnv(env?: Record<string, string | undefined>, overrides?: Partial<OtlpSinkOptions>): TelemetrySink;
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAkC,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjF,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAE1B;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,aAAa,CAEtE;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,EACrD,SAAS,GAAE,OAAO,CAAC,eAAe,CAAM,GACvC,aAAa,CAoBf"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { OtlpHttpSink, parseOtlpHeaders } from "./sink.js";
|
|
2
|
+
export * from "./semconv.js";
|
|
3
|
+
export * from "./sink.js";
|
|
4
|
+
/**
|
|
5
|
+
* Build an OTLP/HTTP GenAI {@link TelemetrySink} for use inside
|
|
6
|
+
* `agent/instrumentation.ts`. Wire it in the `setup` callback of
|
|
7
|
+
* `defineInstrumentation`, the single home for telemetry:
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { defineInstrumentation } from "@assemblyline-agents/core";
|
|
11
|
+
* import { createOtlpSinkFromEnv } from "@assemblyline-agents/otlp";
|
|
12
|
+
*
|
|
13
|
+
* export default defineInstrumentation({
|
|
14
|
+
* serviceName: "my-agent",
|
|
15
|
+
* captureContent: "usage",
|
|
16
|
+
* setup: ({ env }) => createOtlpSinkFromEnv(env)
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function createOtlpSink(options) {
|
|
21
|
+
return new OtlpHttpSink(options);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Convenience factory that reads OTLP configuration from environment variables
|
|
25
|
+
* (`OTEL_EXPORTER_OTLP_ENDPOINT`, `OTEL_EXPORTER_OTLP_HEADERS`,
|
|
26
|
+
* `OTEL_SERVICE_NAME`, `OTEL_EXPORTER_OTLP_TIMEOUT`, `OPENEVE_OTLP_BATCH_MAX`,
|
|
27
|
+
* `OPENEVE_OTLP_FLUSH_MS`). Pass the `env` handed to the instrumentation
|
|
28
|
+
* `setup` callback so it matches the runtime's environment.
|
|
29
|
+
*/
|
|
30
|
+
export function createOtlpSinkFromEnv(env = process.env, overrides = {}) {
|
|
31
|
+
const endpoint = overrides.endpoint ?? env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
32
|
+
if (!endpoint) {
|
|
33
|
+
throw new Error("createOtlpSinkFromEnv requires OTEL_EXPORTER_OTLP_ENDPOINT (or an endpoint override).");
|
|
34
|
+
}
|
|
35
|
+
const headers = { ...parseOtlpHeaders(env.OTEL_EXPORTER_OTLP_HEADERS), ...(overrides.headers ?? {}) };
|
|
36
|
+
const options = { endpoint };
|
|
37
|
+
if (Object.keys(headers).length > 0)
|
|
38
|
+
options.headers = headers;
|
|
39
|
+
const serviceName = overrides.serviceName ?? env.OTEL_SERVICE_NAME;
|
|
40
|
+
if (serviceName)
|
|
41
|
+
options.serviceName = serviceName;
|
|
42
|
+
const batchMax = overrides.batchMax ?? numberFromEnv(env.OPENEVE_OTLP_BATCH_MAX);
|
|
43
|
+
if (batchMax !== undefined)
|
|
44
|
+
options.batchMax = batchMax;
|
|
45
|
+
const flushIntervalMs = overrides.flushIntervalMs ?? numberFromEnv(env.OPENEVE_OTLP_FLUSH_MS);
|
|
46
|
+
if (flushIntervalMs !== undefined)
|
|
47
|
+
options.flushIntervalMs = flushIntervalMs;
|
|
48
|
+
const timeoutMs = overrides.timeoutMs ?? numberFromEnv(env.OTEL_EXPORTER_OTLP_TIMEOUT);
|
|
49
|
+
if (timeoutMs !== undefined)
|
|
50
|
+
options.timeoutMs = timeoutMs;
|
|
51
|
+
if (overrides.fetch)
|
|
52
|
+
options.fetch = overrides.fetch;
|
|
53
|
+
if (overrides.scopeVersion)
|
|
54
|
+
options.scopeVersion = overrides.scopeVersion;
|
|
55
|
+
if (overrides.onError)
|
|
56
|
+
options.onError = overrides.onError;
|
|
57
|
+
return new OtlpHttpSink(options);
|
|
58
|
+
}
|
|
59
|
+
function numberFromEnv(value) {
|
|
60
|
+
if (value === undefined || value.trim() === "")
|
|
61
|
+
return undefined;
|
|
62
|
+
const parsed = Number(value);
|
|
63
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAwB,MAAM,WAAW,CAAC;AAEjF,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAE1B;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,cAAc,CAAC,OAAwB;IACrD,OAAO,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC;AACnC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAA0C,OAAO,CAAC,GAAG,EACrD,YAAsC,EAAE;IAExC,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,IAAI,GAAG,CAAC,2BAA2B,CAAC;IACvE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,uFAAuF,CAAC,CAAC;IAC3G,CAAC;IACD,MAAM,OAAO,GAAG,EAAE,GAAG,gBAAgB,CAAC,GAAG,CAAC,0BAA0B,CAAC,EAAE,GAAG,CAAC,SAAS,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;IACtG,MAAM,OAAO,GAAoB,EAAE,QAAQ,EAAE,CAAC;IAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC;IAC/D,MAAM,WAAW,GAAG,SAAS,CAAC,WAAW,IAAI,GAAG,CAAC,iBAAiB,CAAC;IACnE,IAAI,WAAW;QAAE,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;IACnD,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,IAAI,aAAa,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACjF,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;IACxD,MAAM,eAAe,GAAG,SAAS,CAAC,eAAe,IAAI,aAAa,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IAC9F,IAAI,eAAe,KAAK,SAAS;QAAE,OAAO,CAAC,eAAe,GAAG,eAAe,CAAC;IAC7E,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,IAAI,aAAa,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;IACvF,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAC3D,IAAI,SAAS,CAAC,KAAK;QAAE,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC;IACrD,IAAI,SAAS,CAAC,YAAY;QAAE,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,YAAY,CAAC;IAC1E,IAAI,SAAS,CAAC,OAAO;QAAE,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC;IAC3D,OAAO,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,aAAa,CAAC,KAAyB;IAC9C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IACjE,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { JsonObject, JsonValue } from "@assemblyline-agents/core";
|
|
2
|
+
import type { TelemetrySpan } from "@assemblyline-agents/runtime";
|
|
3
|
+
export interface OtlpAnyValue {
|
|
4
|
+
stringValue?: string;
|
|
5
|
+
boolValue?: boolean;
|
|
6
|
+
intValue?: string;
|
|
7
|
+
doubleValue?: number;
|
|
8
|
+
arrayValue?: {
|
|
9
|
+
values: OtlpAnyValue[];
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export interface OtlpKeyValue {
|
|
13
|
+
key: string;
|
|
14
|
+
value: OtlpAnyValue;
|
|
15
|
+
}
|
|
16
|
+
export interface OtlpSpan {
|
|
17
|
+
traceId: string;
|
|
18
|
+
spanId: string;
|
|
19
|
+
parentSpanId?: string;
|
|
20
|
+
name: string;
|
|
21
|
+
kind: number;
|
|
22
|
+
startTimeUnixNano: string;
|
|
23
|
+
endTimeUnixNano: string;
|
|
24
|
+
attributes: OtlpKeyValue[];
|
|
25
|
+
status: {
|
|
26
|
+
code: number;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export interface OtlpResourceSpans {
|
|
30
|
+
resourceSpans: Array<{
|
|
31
|
+
resource: {
|
|
32
|
+
attributes: OtlpKeyValue[];
|
|
33
|
+
};
|
|
34
|
+
scopeSpans: Array<{
|
|
35
|
+
scope: {
|
|
36
|
+
name: string;
|
|
37
|
+
version?: string;
|
|
38
|
+
};
|
|
39
|
+
spans: OtlpSpan[];
|
|
40
|
+
}>;
|
|
41
|
+
}>;
|
|
42
|
+
}
|
|
43
|
+
export interface SemconvOptions {
|
|
44
|
+
/** service.name for the OTLP resource; falls back to the span's serviceName attribute. */
|
|
45
|
+
serviceName?: string;
|
|
46
|
+
/** Scope name/version reported for the emitting instrumentation. */
|
|
47
|
+
scopeName?: string;
|
|
48
|
+
scopeVersion?: string;
|
|
49
|
+
}
|
|
50
|
+
/** Converts a single JSON value into an OTLP AnyValue (nested objects are JSON-stringified). */
|
|
51
|
+
export declare function toAnyValue(value: JsonValue): OtlpAnyValue | undefined;
|
|
52
|
+
/** Converts a flat attribute object into OTLP KeyValue pairs, dropping null/undefined. */
|
|
53
|
+
export declare function toKeyValues(attributes: JsonObject): OtlpKeyValue[];
|
|
54
|
+
/** Maps one OpenEve span into an OTLP span (raw attributes preserved + semconv aliases added). */
|
|
55
|
+
export declare function toOtlpSpan(span: TelemetrySpan): OtlpSpan;
|
|
56
|
+
/** Bundles a batch of OpenEve spans into a single OTLP/HTTP JSON export payload. */
|
|
57
|
+
export declare function toResourceSpans(spans: TelemetrySpan[], options?: SemconvOptions): OtlpResourceSpans;
|
|
58
|
+
//# sourceMappingURL=semconv.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semconv.d.ts","sourceRoot":"","sources":["../src/semconv.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AA2BlE,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE;QAAE,MAAM,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC;CACzC;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,YAAY,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,YAAY,EAAE,CAAC;IAC3B,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,KAAK,CAAC;QACnB,QAAQ,EAAE;YAAE,UAAU,EAAE,YAAY,EAAE,CAAA;SAAE,CAAC;QACzC,UAAU,EAAE,KAAK,CAAC;YAChB,KAAK,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,OAAO,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC;YAC1C,KAAK,EAAE,QAAQ,EAAE,CAAC;SACnB,CAAC,CAAC;KACJ,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,cAAc;IAC7B,0FAA0F;IAC1F,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,gGAAgG;AAChG,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,YAAY,GAAG,SAAS,CAiBrE;AAED,0FAA0F;AAC1F,wBAAgB,WAAW,CAAC,UAAU,EAAE,UAAU,GAAG,YAAY,EAAE,CAOlE;AAyDD,kGAAkG;AAClG,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,QAAQ,CAexD;AAED,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,OAAO,GAAE,cAAmB,GAAG,iBAAiB,CA0BvG"}
|
package/dist/semconv.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps OpenEve's OTel-shaped `TelemetrySpan` model onto OTLP/HTTP JSON
|
|
3
|
+
* `ResourceSpans`, translating OpenEve's model-loop / tool attributes into
|
|
4
|
+
* OpenTelemetry GenAI semantic-convention attributes so any OTLP backend
|
|
5
|
+
* (Langfuse, Phoenix/Arize, Braintrust, Grafana, Honeycomb, ...) renders
|
|
6
|
+
* token usage, cost, model, and tool calls as first-class fields.
|
|
7
|
+
*
|
|
8
|
+
* Intentionally dependency-free: OpenEve already emits hex trace/span ids and
|
|
9
|
+
* an OTel-compatible span shape, so no OpenTelemetry SDK or protobuf is needed.
|
|
10
|
+
*/
|
|
11
|
+
/** OTLP span kind numeric codes. */
|
|
12
|
+
const SPAN_KIND_INTERNAL = 1;
|
|
13
|
+
const SPAN_KIND_CLIENT = 3;
|
|
14
|
+
/** OTLP status codes. */
|
|
15
|
+
const STATUS_UNSET = 0;
|
|
16
|
+
const STATUS_OK = 1;
|
|
17
|
+
const STATUS_ERROR = 2;
|
|
18
|
+
/** Attributes OpenEve already puts on spans that we alias into semconv; the
|
|
19
|
+
* originals are still emitted verbatim so nothing an operator relies on is lost. */
|
|
20
|
+
const GEN_AI_OPERATION_CHAT = "chat";
|
|
21
|
+
const GEN_AI_OPERATION_EXECUTE_TOOL = "execute_tool";
|
|
22
|
+
/** Converts a single JSON value into an OTLP AnyValue (nested objects are JSON-stringified). */
|
|
23
|
+
export function toAnyValue(value) {
|
|
24
|
+
if (value === null || value === undefined)
|
|
25
|
+
return undefined;
|
|
26
|
+
if (typeof value === "string")
|
|
27
|
+
return { stringValue: value };
|
|
28
|
+
if (typeof value === "boolean")
|
|
29
|
+
return { boolValue: value };
|
|
30
|
+
if (typeof value === "number") {
|
|
31
|
+
if (!Number.isFinite(value))
|
|
32
|
+
return { stringValue: String(value) };
|
|
33
|
+
return Number.isInteger(value) ? { intValue: String(value) } : { doubleValue: value };
|
|
34
|
+
}
|
|
35
|
+
if (Array.isArray(value)) {
|
|
36
|
+
const values = [];
|
|
37
|
+
for (const item of value) {
|
|
38
|
+
const converted = toAnyValue(item);
|
|
39
|
+
if (converted)
|
|
40
|
+
values.push(converted);
|
|
41
|
+
}
|
|
42
|
+
return { arrayValue: { values } };
|
|
43
|
+
}
|
|
44
|
+
return { stringValue: JSON.stringify(value) };
|
|
45
|
+
}
|
|
46
|
+
/** Converts a flat attribute object into OTLP KeyValue pairs, dropping null/undefined. */
|
|
47
|
+
export function toKeyValues(attributes) {
|
|
48
|
+
const out = [];
|
|
49
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
50
|
+
const converted = toAnyValue(value);
|
|
51
|
+
if (converted)
|
|
52
|
+
out.push({ key, value: converted });
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
function isoToUnixNano(iso) {
|
|
57
|
+
const ms = Date.parse(iso);
|
|
58
|
+
if (Number.isNaN(ms))
|
|
59
|
+
return "0";
|
|
60
|
+
// Milliseconds → nanoseconds as an integer string (avoids float precision loss).
|
|
61
|
+
return `${ms}000000`;
|
|
62
|
+
}
|
|
63
|
+
function statusCode(status) {
|
|
64
|
+
if (status === "ok")
|
|
65
|
+
return STATUS_OK;
|
|
66
|
+
if (status === "error")
|
|
67
|
+
return STATUS_ERROR;
|
|
68
|
+
return STATUS_UNSET;
|
|
69
|
+
}
|
|
70
|
+
function num(value) {
|
|
71
|
+
return typeof value === "number" ? value : undefined;
|
|
72
|
+
}
|
|
73
|
+
function str(value) {
|
|
74
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
75
|
+
}
|
|
76
|
+
/** GenAI-semconv aliases derived from OpenEve's span attributes, keyed by span name. */
|
|
77
|
+
function genAiAttributes(span) {
|
|
78
|
+
const a = span.attributes;
|
|
79
|
+
if (span.name === "ai.streamText") {
|
|
80
|
+
const attributes = { "gen_ai.operation.name": GEN_AI_OPERATION_CHAT };
|
|
81
|
+
const system = str(a.provider);
|
|
82
|
+
if (system)
|
|
83
|
+
attributes["gen_ai.system"] = system;
|
|
84
|
+
const requestModel = str(a.model);
|
|
85
|
+
if (requestModel)
|
|
86
|
+
attributes["gen_ai.request.model"] = requestModel;
|
|
87
|
+
const responseModel = str(a.responseModel);
|
|
88
|
+
if (responseModel)
|
|
89
|
+
attributes["gen_ai.response.model"] = responseModel;
|
|
90
|
+
const inputTokens = num(a.inputTokens);
|
|
91
|
+
if (inputTokens !== undefined)
|
|
92
|
+
attributes["gen_ai.usage.input_tokens"] = inputTokens;
|
|
93
|
+
const outputTokens = num(a.outputTokens);
|
|
94
|
+
if (outputTokens !== undefined)
|
|
95
|
+
attributes["gen_ai.usage.output_tokens"] = outputTokens;
|
|
96
|
+
const cachedTokens = num(a.cachedTokens);
|
|
97
|
+
if (cachedTokens !== undefined)
|
|
98
|
+
attributes["gen_ai.usage.cached_input_tokens"] = cachedTokens;
|
|
99
|
+
const costUsd = num(a.costUsd);
|
|
100
|
+
if (costUsd !== undefined)
|
|
101
|
+
attributes["gen_ai.usage.cost"] = costUsd;
|
|
102
|
+
const finishReason = str(a.finishReason);
|
|
103
|
+
if (finishReason)
|
|
104
|
+
attributes["gen_ai.response.finish_reasons"] = [finishReason];
|
|
105
|
+
return { attributes, kind: SPAN_KIND_CLIENT };
|
|
106
|
+
}
|
|
107
|
+
if (span.name === "ai.toolCall") {
|
|
108
|
+
const attributes = { "gen_ai.operation.name": GEN_AI_OPERATION_EXECUTE_TOOL };
|
|
109
|
+
const toolName = str(a.toolName);
|
|
110
|
+
if (toolName)
|
|
111
|
+
attributes["gen_ai.tool.name"] = toolName;
|
|
112
|
+
const toolCallId = str(a.toolCallId);
|
|
113
|
+
if (toolCallId)
|
|
114
|
+
attributes["gen_ai.tool.call.id"] = toolCallId;
|
|
115
|
+
return { attributes, kind: SPAN_KIND_INTERNAL };
|
|
116
|
+
}
|
|
117
|
+
return { attributes: {}, kind: SPAN_KIND_INTERNAL };
|
|
118
|
+
}
|
|
119
|
+
/** Maps one OpenEve span into an OTLP span (raw attributes preserved + semconv aliases added). */
|
|
120
|
+
export function toOtlpSpan(span) {
|
|
121
|
+
const { attributes: semconv, kind } = genAiAttributes(span);
|
|
122
|
+
const merged = { ...span.attributes, ...semconv };
|
|
123
|
+
const otlp = {
|
|
124
|
+
traceId: span.traceId,
|
|
125
|
+
spanId: span.spanId,
|
|
126
|
+
name: span.name,
|
|
127
|
+
kind,
|
|
128
|
+
startTimeUnixNano: isoToUnixNano(span.startedAt),
|
|
129
|
+
endTimeUnixNano: isoToUnixNano(span.endedAt),
|
|
130
|
+
attributes: toKeyValues(merged),
|
|
131
|
+
status: { code: statusCode(span.status) }
|
|
132
|
+
};
|
|
133
|
+
if (span.parentSpanId)
|
|
134
|
+
otlp.parentSpanId = span.parentSpanId;
|
|
135
|
+
return otlp;
|
|
136
|
+
}
|
|
137
|
+
/** Bundles a batch of OpenEve spans into a single OTLP/HTTP JSON export payload. */
|
|
138
|
+
export function toResourceSpans(spans, options = {}) {
|
|
139
|
+
const serviceName = options.serviceName ??
|
|
140
|
+
str(spans.find((span) => str(span.attributes.serviceName))?.attributes.serviceName) ??
|
|
141
|
+
"assembly-line";
|
|
142
|
+
const resourceAttributes = {
|
|
143
|
+
"service.name": serviceName,
|
|
144
|
+
"telemetry.sdk.name": "assembly-line",
|
|
145
|
+
"telemetry.sdk.language": "nodejs"
|
|
146
|
+
};
|
|
147
|
+
return {
|
|
148
|
+
resourceSpans: [
|
|
149
|
+
{
|
|
150
|
+
resource: { attributes: toKeyValues(resourceAttributes) },
|
|
151
|
+
scopeSpans: [
|
|
152
|
+
{
|
|
153
|
+
scope: {
|
|
154
|
+
name: options.scopeName ?? "@assemblyline-agents/otlp",
|
|
155
|
+
...(options.scopeVersion ? { version: options.scopeVersion } : {})
|
|
156
|
+
},
|
|
157
|
+
spans: spans.map(toOtlpSpan)
|
|
158
|
+
}
|
|
159
|
+
]
|
|
160
|
+
}
|
|
161
|
+
]
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=semconv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semconv.js","sourceRoot":"","sources":["../src/semconv.ts"],"names":[],"mappings":"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"}
|
package/dist/sink.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { TelemetrySink, TelemetrySpan } from "@assemblyline-agents/runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Buffered OTLP/HTTP JSON exporter. Batches spans and POSTs them to an OTLP
|
|
4
|
+
* traces endpoint, draining on batch-size, a flush timer, and graceful
|
|
5
|
+
* shutdown (`flush()` is called from the Node host lifecycle). Transport is
|
|
6
|
+
* plain `fetch` + JSON — no OpenTelemetry SDK dependency.
|
|
7
|
+
*/
|
|
8
|
+
export interface OtlpSinkOptions {
|
|
9
|
+
/** Base OTLP endpoint (e.g. https://cloud.langfuse.com/api/public/otel) or a full /v1/traces URL. */
|
|
10
|
+
endpoint: string;
|
|
11
|
+
/** Extra headers (auth). Parsed from OTEL_EXPORTER_OTLP_HEADERS by the factory. */
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
fetch?: typeof fetch;
|
|
14
|
+
/** service.name override; otherwise derived from span attributes. */
|
|
15
|
+
serviceName?: string;
|
|
16
|
+
scopeVersion?: string;
|
|
17
|
+
/** Flush once this many spans are buffered. Default 64. */
|
|
18
|
+
batchMax?: number;
|
|
19
|
+
/** Flush at most this often (ms) when spans trickle in. Default 2000. */
|
|
20
|
+
flushIntervalMs?: number;
|
|
21
|
+
/** Per-request timeout (ms). Default 10000. */
|
|
22
|
+
timeoutMs?: number;
|
|
23
|
+
/** Optional error reporter; defaults to console.warn. Never throws into the caller. */
|
|
24
|
+
onError?: (error: unknown) => void;
|
|
25
|
+
}
|
|
26
|
+
/** Appends the OTLP traces path unless the endpoint already targets it. */
|
|
27
|
+
export declare function resolveTracesUrl(endpoint: string): string;
|
|
28
|
+
/** Parses the W3C-style `OTEL_EXPORTER_OTLP_HEADERS` value (comma-separated key=value pairs). */
|
|
29
|
+
export declare function parseOtlpHeaders(raw: string | undefined): Record<string, string>;
|
|
30
|
+
export declare class OtlpHttpSink implements TelemetrySink {
|
|
31
|
+
private readonly url;
|
|
32
|
+
private readonly headers;
|
|
33
|
+
private readonly fetchImpl;
|
|
34
|
+
private readonly batchMax;
|
|
35
|
+
private readonly flushIntervalMs;
|
|
36
|
+
private readonly timeoutMs;
|
|
37
|
+
private readonly semconv;
|
|
38
|
+
private readonly onError;
|
|
39
|
+
private buffer;
|
|
40
|
+
private timer;
|
|
41
|
+
constructor(options: OtlpSinkOptions);
|
|
42
|
+
emitSpan(span: TelemetrySpan): void;
|
|
43
|
+
flush(): Promise<void>;
|
|
44
|
+
private scheduleFlush;
|
|
45
|
+
private clearTimer;
|
|
46
|
+
private send;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=sink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sink.d.ts","sourceRoot":"","sources":["../src/sink.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAGjF;;;;;GAKG;AAEH,MAAM,WAAW,eAAe;IAC9B,qGAAqG;IACrG,QAAQ,EAAE,MAAM,CAAC;IACjB,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uFAAuF;IACvF,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC;AAID,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGzD;AAED,iGAAiG;AACjG,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWhF;AAED,qBAAa,YAAa,YAAW,aAAa;IAChD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2B;IACnD,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,KAAK,CAA4C;gBAE7C,OAAO,EAAE,eAAe;IAapC,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAS7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,UAAU;YAOJ,IAAI;CAsBnB"}
|
package/dist/sink.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { toResourceSpans } from "./semconv.js";
|
|
2
|
+
const TRACES_PATH = "/v1/traces";
|
|
3
|
+
/** Appends the OTLP traces path unless the endpoint already targets it. */
|
|
4
|
+
export function resolveTracesUrl(endpoint) {
|
|
5
|
+
const trimmed = endpoint.replace(/\/+$/, "");
|
|
6
|
+
return trimmed.endsWith(TRACES_PATH) ? trimmed : `${trimmed}${TRACES_PATH}`;
|
|
7
|
+
}
|
|
8
|
+
/** Parses the W3C-style `OTEL_EXPORTER_OTLP_HEADERS` value (comma-separated key=value pairs). */
|
|
9
|
+
export function parseOtlpHeaders(raw) {
|
|
10
|
+
if (!raw)
|
|
11
|
+
return {};
|
|
12
|
+
const headers = {};
|
|
13
|
+
for (const pair of raw.split(",")) {
|
|
14
|
+
const eq = pair.indexOf("=");
|
|
15
|
+
if (eq === -1)
|
|
16
|
+
continue;
|
|
17
|
+
const key = pair.slice(0, eq).trim();
|
|
18
|
+
const value = pair.slice(eq + 1).trim();
|
|
19
|
+
if (key)
|
|
20
|
+
headers[key] = value;
|
|
21
|
+
}
|
|
22
|
+
return headers;
|
|
23
|
+
}
|
|
24
|
+
export class OtlpHttpSink {
|
|
25
|
+
url;
|
|
26
|
+
headers;
|
|
27
|
+
fetchImpl;
|
|
28
|
+
batchMax;
|
|
29
|
+
flushIntervalMs;
|
|
30
|
+
timeoutMs;
|
|
31
|
+
semconv;
|
|
32
|
+
onError;
|
|
33
|
+
buffer = [];
|
|
34
|
+
timer;
|
|
35
|
+
constructor(options) {
|
|
36
|
+
this.url = resolveTracesUrl(options.endpoint);
|
|
37
|
+
this.headers = { "content-type": "application/json", ...(options.headers ?? {}) };
|
|
38
|
+
this.fetchImpl = options.fetch ?? fetch;
|
|
39
|
+
this.batchMax = options.batchMax ?? 64;
|
|
40
|
+
this.flushIntervalMs = options.flushIntervalMs ?? 2000;
|
|
41
|
+
this.timeoutMs = options.timeoutMs ?? 10000;
|
|
42
|
+
this.semconv = {};
|
|
43
|
+
if (options.serviceName)
|
|
44
|
+
this.semconv.serviceName = options.serviceName;
|
|
45
|
+
if (options.scopeVersion)
|
|
46
|
+
this.semconv.scopeVersion = options.scopeVersion;
|
|
47
|
+
this.onError = options.onError ?? ((error) => console.warn("[openeve/otlp] export failed:", error));
|
|
48
|
+
}
|
|
49
|
+
emitSpan(span) {
|
|
50
|
+
this.buffer.push(span);
|
|
51
|
+
if (this.buffer.length >= this.batchMax) {
|
|
52
|
+
void this.flush();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
this.scheduleFlush();
|
|
56
|
+
}
|
|
57
|
+
async flush() {
|
|
58
|
+
this.clearTimer();
|
|
59
|
+
if (this.buffer.length === 0)
|
|
60
|
+
return;
|
|
61
|
+
const batch = this.buffer;
|
|
62
|
+
this.buffer = [];
|
|
63
|
+
await this.send(batch);
|
|
64
|
+
}
|
|
65
|
+
scheduleFlush() {
|
|
66
|
+
if (this.timer)
|
|
67
|
+
return;
|
|
68
|
+
this.timer = setTimeout(() => {
|
|
69
|
+
this.timer = undefined;
|
|
70
|
+
void this.flush();
|
|
71
|
+
}, this.flushIntervalMs);
|
|
72
|
+
// Do not keep the process alive solely to flush telemetry.
|
|
73
|
+
this.timer.unref?.();
|
|
74
|
+
}
|
|
75
|
+
clearTimer() {
|
|
76
|
+
if (this.timer) {
|
|
77
|
+
clearTimeout(this.timer);
|
|
78
|
+
this.timer = undefined;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async send(batch) {
|
|
82
|
+
const payload = toResourceSpans(batch, this.semconv);
|
|
83
|
+
const controller = new AbortController();
|
|
84
|
+
const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
85
|
+
timeout.unref?.();
|
|
86
|
+
try {
|
|
87
|
+
const response = await this.fetchImpl(this.url, {
|
|
88
|
+
method: "POST",
|
|
89
|
+
headers: this.headers,
|
|
90
|
+
body: JSON.stringify(payload),
|
|
91
|
+
signal: controller.signal
|
|
92
|
+
});
|
|
93
|
+
if (!response.ok) {
|
|
94
|
+
const detail = await safeText(response);
|
|
95
|
+
this.onError(new Error(`OTLP export ${response.status}: ${detail}`));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
this.onError(error);
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
clearTimeout(timeout);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async function safeText(response) {
|
|
107
|
+
try {
|
|
108
|
+
return (await response.text()).slice(0, 500);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return "<no body>";
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=sink.js.map
|
package/dist/sink.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sink.js","sourceRoot":"","sources":["../src/sink.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@assemblyline-agents/otlp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"default": "./dist/index.js"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@assemblyline-agents/core": "0.1.0",
|
|
13
|
+
"@assemblyline-agents/runtime": "0.1.0"
|
|
14
|
+
},
|
|
15
|
+
"description": "Official OpenEve OTLP/HTTP instrumentation plugin for GenAI telemetry backends.",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=22.19.0"
|
|
21
|
+
},
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/jasonbadeaux/openeve.git",
|
|
26
|
+
"directory": "packages/otlp"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/jasonbadeaux/openeve/issues"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/jasonbadeaux/openeve#readme",
|
|
32
|
+
"author": "OpenEve contributors",
|
|
33
|
+
"keywords": [
|
|
34
|
+
"openeve",
|
|
35
|
+
"ai",
|
|
36
|
+
"agents",
|
|
37
|
+
"otlp",
|
|
38
|
+
"opentelemetry",
|
|
39
|
+
"telemetry",
|
|
40
|
+
"observability"
|
|
41
|
+
],
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsc -p tsconfig.json",
|
|
47
|
+
"check": "tsc -p tsconfig.json --noEmit"
|
|
48
|
+
}
|
|
49
|
+
}
|