@axlsdk/axl 0.25.2 → 0.26.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/README.md +36 -9
- package/dist/{chunk-PJROX3XU.js → chunk-SBQL47BB.js} +40 -25
- package/dist/chunk-SBQL47BB.js.map +1 -0
- package/dist/index.cjs +12827 -10877
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1636 -44
- package/dist/index.d.ts +1636 -44
- package/dist/index.js +12784 -10855
- package/dist/index.js.map +1 -1
- package/dist/{span-manager-L4H6ZCRQ.js → span-manager-I4JFIB5F.js} +2 -2
- package/package.json +2 -2
- package/dist/chunk-PJROX3XU.js.map +0 -1
- /package/dist/{span-manager-L4H6ZCRQ.js.map → span-manager-I4JFIB5F.js.map} +0 -0
package/README.md
CHANGED
|
@@ -509,22 +509,28 @@ const checkpointed = await ctx.checkpoint('expensive-op', async () => expensiveO
|
|
|
509
509
|
|
|
510
510
|
### OpenTelemetry Observability
|
|
511
511
|
|
|
512
|
-
Automatic
|
|
512
|
+
Automatic spans for `ctx.*` primitives and every model call Axl sends. Install
|
|
513
|
+
`@opentelemetry/api` as an optional peer dependency.
|
|
513
514
|
|
|
514
515
|
```typescript
|
|
515
516
|
import { defineConfig, AxlRuntime } from '@axlsdk/axl';
|
|
517
|
+
import { context, trace } from '@opentelemetry/api';
|
|
518
|
+
import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks';
|
|
516
519
|
import {
|
|
517
520
|
BasicTracerProvider,
|
|
518
521
|
SimpleSpanProcessor,
|
|
519
522
|
} from '@opentelemetry/sdk-trace-base';
|
|
520
523
|
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
|
|
521
524
|
|
|
522
|
-
const tracerProvider = new BasicTracerProvider(
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
525
|
+
const tracerProvider = new BasicTracerProvider({
|
|
526
|
+
spanProcessors: [
|
|
527
|
+
new SimpleSpanProcessor(
|
|
528
|
+
new OTLPTraceExporter({ url: 'http://localhost:4318/v1/traces' }),
|
|
529
|
+
),
|
|
530
|
+
],
|
|
531
|
+
});
|
|
532
|
+
context.setGlobalContextManager(new AsyncLocalStorageContextManager());
|
|
533
|
+
trace.setGlobalTracerProvider(tracerProvider);
|
|
528
534
|
|
|
529
535
|
const config = defineConfig({
|
|
530
536
|
telemetry: {
|
|
@@ -536,11 +542,29 @@ const config = defineConfig({
|
|
|
536
542
|
|
|
537
543
|
const runtime = new AxlRuntime(config);
|
|
538
544
|
await runtime.initializeTelemetry();
|
|
545
|
+
|
|
546
|
+
// After the application stops accepting work:
|
|
547
|
+
await runtime.shutdown();
|
|
548
|
+
await tracerProvider.shutdown();
|
|
549
|
+
context.disable();
|
|
550
|
+
trace.disable();
|
|
539
551
|
```
|
|
540
552
|
|
|
541
|
-
**Span model:** `axl.workflow.execute` > `axl.agent.ask` > `
|
|
553
|
+
**Span model:** `axl.workflow.execute` > `axl.agent.ask` > `chat {model}`
|
|
554
|
+
for model calls, with `axl.tool.call` under an agent when tools run. Also:
|
|
555
|
+
`axl.ctx.spawn`, `axl.ctx.race`, `axl.ctx.vote`, `axl.ctx.budget`,
|
|
556
|
+
`axl.ctx.awaitHuman`. Model-call spans use standard `gen_ai.*` attributes.
|
|
557
|
+
Prompt and response content is off by default; see
|
|
558
|
+
[content capture](../../docs/observability.md#genai-content-capture).
|
|
542
559
|
|
|
543
|
-
When disabled (default), `NoopSpanManager`
|
|
560
|
+
When telemetry is disabled (default), `NoopSpanManager` adds no overhead. Axl
|
|
561
|
+
never shuts down your tracer provider; do that after `runtime.shutdown()`.
|
|
562
|
+
|
|
563
|
+
For this Node setup, install the optional OTel packages used above:
|
|
564
|
+
|
|
565
|
+
```bash
|
|
566
|
+
npm install @opentelemetry/api @opentelemetry/context-async-hooks @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-http
|
|
567
|
+
```
|
|
544
568
|
|
|
545
569
|
```typescript
|
|
546
570
|
import { createSpanManager, NoopSpanManager } from '@axlsdk/axl';
|
|
@@ -595,6 +619,9 @@ eval history row that owns them is saved, deleted with it, and reclaimed by a
|
|
|
595
619
|
startup pass plus a periodic sweep. See
|
|
596
620
|
[observability.md](../../docs/observability.md#captured-requests-opt-in) and
|
|
597
621
|
[integration.md](../../docs/integration.md#diagnostic-artifact-storage).
|
|
622
|
+
`foldJournal()` turns journal lines into one validated record per call, and
|
|
623
|
+
`redactModelCallRecord()` returns a redacted copy. See
|
|
624
|
+
[What a record contains](../../docs/observability.md#what-a-record-contains).
|
|
598
625
|
|
|
599
626
|
Compatible loaded ESM/CJS copies share accounting, admission, and capture in
|
|
600
627
|
one JavaScript realm. Cross-copy work emits one warning identifying both copies;
|
|
@@ -12,11 +12,9 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
12
12
|
var OTelSpanManager = class _OTelSpanManager {
|
|
13
13
|
tracer;
|
|
14
14
|
otelApi;
|
|
15
|
-
|
|
16
|
-
constructor(otelApi, tracer, tracerProvider) {
|
|
15
|
+
constructor(otelApi, tracer) {
|
|
17
16
|
this.otelApi = otelApi;
|
|
18
17
|
this.tracer = tracer;
|
|
19
|
-
this.tracerProvider = tracerProvider;
|
|
20
18
|
}
|
|
21
19
|
static async create(config) {
|
|
22
20
|
let otelApi;
|
|
@@ -30,28 +28,14 @@ var OTelSpanManager = class _OTelSpanManager {
|
|
|
30
28
|
const tracerProvider = config.tracerProvider ?? otelApi.trace.getTracerProvider();
|
|
31
29
|
const serviceName = config.serviceName ?? "axl";
|
|
32
30
|
const tracer = tracerProvider.getTracer(serviceName);
|
|
33
|
-
return new _OTelSpanManager(otelApi, tracer
|
|
31
|
+
return new _OTelSpanManager(otelApi, tracer);
|
|
34
32
|
}
|
|
35
33
|
async withSpanAsync(name, attributes, fn) {
|
|
36
|
-
const otelApi = this.otelApi;
|
|
37
34
|
return this.tracer.startActiveSpan(name, { attributes }, async (otelSpan) => {
|
|
38
35
|
let statusWasSet = false;
|
|
39
|
-
const handle = {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
},
|
|
43
|
-
addEvent(eventName, attrs) {
|
|
44
|
-
otelSpan.addEvent(eventName, attrs);
|
|
45
|
-
},
|
|
46
|
-
setStatus(code, message) {
|
|
47
|
-
statusWasSet = true;
|
|
48
|
-
const statusCode = code === "ok" ? otelApi.SpanStatusCode.OK : code === "error" ? otelApi.SpanStatusCode.ERROR : otelApi.SpanStatusCode.UNSET;
|
|
49
|
-
otelSpan.setStatus({ code: statusCode, message });
|
|
50
|
-
},
|
|
51
|
-
end() {
|
|
52
|
-
otelSpan.end();
|
|
53
|
-
}
|
|
54
|
-
};
|
|
36
|
+
const handle = this.handle(otelSpan, () => {
|
|
37
|
+
statusWasSet = true;
|
|
38
|
+
});
|
|
55
39
|
try {
|
|
56
40
|
const result = await fn(handle);
|
|
57
41
|
if (!statusWasSet) handle.setStatus("ok");
|
|
@@ -64,16 +48,47 @@ var OTelSpanManager = class _OTelSpanManager {
|
|
|
64
48
|
}
|
|
65
49
|
});
|
|
66
50
|
}
|
|
51
|
+
/** Start a CLIENT inference span under the current OTel context. The caller ends it. */
|
|
52
|
+
startSpan(name, attributes, options) {
|
|
53
|
+
const span = this.tracer.startSpan(name, {
|
|
54
|
+
attributes,
|
|
55
|
+
...options?.kind === "client" ? { kind: this.otelApi.SpanKind.CLIENT } : {},
|
|
56
|
+
...options?.startTime !== void 0 ? { startTime: options.startTime } : {}
|
|
57
|
+
});
|
|
58
|
+
return this.handle(span);
|
|
59
|
+
}
|
|
60
|
+
handle(span, onStatus) {
|
|
61
|
+
const otelApi = this.otelApi;
|
|
62
|
+
let ended = false;
|
|
63
|
+
return {
|
|
64
|
+
setAttribute(key, value) {
|
|
65
|
+
if (!ended) span.setAttribute(key, value);
|
|
66
|
+
},
|
|
67
|
+
addEvent(name, attributes) {
|
|
68
|
+
if (!ended) span.addEvent(name, attributes);
|
|
69
|
+
},
|
|
70
|
+
setStatus(code, message) {
|
|
71
|
+
if (ended) return;
|
|
72
|
+
onStatus?.();
|
|
73
|
+
const statusCode = code === "ok" ? otelApi.SpanStatusCode.OK : code === "error" ? otelApi.SpanStatusCode.ERROR : otelApi.SpanStatusCode.UNSET;
|
|
74
|
+
span.setStatus({ code: statusCode, message });
|
|
75
|
+
},
|
|
76
|
+
end() {
|
|
77
|
+
if (ended) return;
|
|
78
|
+
ended = true;
|
|
79
|
+
span.end();
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
67
83
|
addEventToActiveSpan(name, attributes) {
|
|
68
84
|
const activeSpan = this.otelApi.trace.getActiveSpan?.();
|
|
69
85
|
if (activeSpan) {
|
|
70
86
|
activeSpan.addEvent(name, attributes);
|
|
71
87
|
}
|
|
72
88
|
}
|
|
89
|
+
// Axl uses an application-owned provider, whether supplied or global.
|
|
90
|
+
// Its lifecycle, including flush and shutdown, belongs to the application.
|
|
73
91
|
async shutdown() {
|
|
74
|
-
if (this.tracerProvider && typeof this.tracerProvider.shutdown === "function") {
|
|
75
|
-
await this.tracerProvider.shutdown();
|
|
76
|
-
}
|
|
77
92
|
}
|
|
78
93
|
};
|
|
79
94
|
|
|
@@ -81,4 +96,4 @@ export {
|
|
|
81
96
|
__require,
|
|
82
97
|
OTelSpanManager
|
|
83
98
|
};
|
|
84
|
-
//# sourceMappingURL=chunk-
|
|
99
|
+
//# sourceMappingURL=chunk-SBQL47BB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/telemetry/span-manager.ts"],"sourcesContent":["import type {\n SpanAttributeValue,\n SpanAttributes,\n SpanHandle,\n SpanManager,\n TelemetryConfig,\n} from './types.js';\n\n/** Minimal interface for an OTel span. */\ninterface OTelSpan {\n setAttribute(key: string, value: SpanAttributeValue): void;\n addEvent(name: string, attributes?: SpanAttributes): void;\n setStatus(status: { code: unknown; message?: string }): void;\n end(): void;\n}\n\n/** Minimal interface for an OTel tracer. */\ninterface OTelTracer {\n startSpan(\n name: string,\n options: { attributes: SpanAttributes; kind?: number; startTime?: number },\n ): OTelSpan;\n startActiveSpan<T>(\n name: string,\n options: { attributes: SpanAttributes },\n fn: (span: OTelSpan) => Promise<T>,\n ): Promise<T>;\n}\n\n/** Minimal interface for an OTel tracer provider. */\ninterface OTelTracerProvider {\n getTracer(name: string): OTelTracer;\n}\n\n/** Minimal interface for the @opentelemetry/api module. */\ninterface OTelApi {\n SpanKind: { CLIENT: number };\n SpanStatusCode: { UNSET: unknown; OK: unknown; ERROR: unknown };\n trace: {\n getTracerProvider(): OTelTracerProvider;\n getActiveSpan?(): OTelSpan | undefined;\n };\n}\n\n/**\n * OpenTelemetry-backed SpanManager.\n * Dynamically imports @opentelemetry/api to avoid hard dependency.\n */\nexport class OTelSpanManager implements SpanManager {\n private tracer: OTelTracer;\n private otelApi: OTelApi;\n\n private constructor(otelApi: OTelApi, tracer: OTelTracer) {\n this.otelApi = otelApi;\n this.tracer = tracer;\n }\n\n static async create(config: TelemetryConfig): Promise<OTelSpanManager> {\n let otelApi: OTelApi;\n try {\n otelApi = (await import('@opentelemetry/api')) as unknown as OTelApi;\n } catch {\n throw new Error(\n '@opentelemetry/api is required for telemetry. Install it with: npm install @opentelemetry/api',\n );\n }\n\n const tracerProvider =\n (config.tracerProvider as OTelTracerProvider | undefined) ??\n otelApi.trace.getTracerProvider();\n const serviceName = config.serviceName ?? 'axl';\n const tracer = tracerProvider.getTracer(serviceName);\n\n return new OTelSpanManager(otelApi, tracer);\n }\n\n async withSpanAsync<T>(\n name: string,\n attributes: SpanAttributes,\n fn: (span: SpanHandle) => Promise<T>,\n ): Promise<T> {\n return this.tracer.startActiveSpan(name, { attributes }, async (otelSpan: OTelSpan) => {\n let statusWasSet = false;\n const handle = this.handle(otelSpan, () => {\n statusWasSet = true;\n });\n\n try {\n const result = await fn(handle);\n if (!statusWasSet) handle.setStatus('ok');\n return result;\n } catch (err) {\n // Error text can contain provider, prompt, or sensitive tool data.\n // Keep exported status structural; host diagnostics remain in Axl's\n // own error and redacted event channels.\n handle.setStatus('error');\n throw err;\n } finally {\n handle.end();\n }\n });\n }\n\n /** Start a CLIENT inference span under the current OTel context. The caller ends it. */\n startSpan(\n name: string,\n attributes: SpanAttributes,\n options?: { kind?: 'client'; startTime?: number },\n ): SpanHandle {\n const span = this.tracer.startSpan(name, {\n attributes,\n ...(options?.kind === 'client' ? { kind: this.otelApi.SpanKind.CLIENT } : {}),\n ...(options?.startTime !== undefined ? { startTime: options.startTime } : {}),\n });\n return this.handle(span);\n }\n\n private handle(span: OTelSpan, onStatus?: () => void): SpanHandle {\n const otelApi = this.otelApi;\n let ended = false;\n return {\n setAttribute(key, value) {\n if (!ended) span.setAttribute(key, value);\n },\n addEvent(name, attributes) {\n if (!ended) span.addEvent(name, attributes);\n },\n setStatus(code, message) {\n if (ended) return;\n onStatus?.();\n const statusCode =\n code === 'ok'\n ? otelApi.SpanStatusCode.OK\n : code === 'error'\n ? otelApi.SpanStatusCode.ERROR\n : otelApi.SpanStatusCode.UNSET;\n span.setStatus({ code: statusCode, message });\n },\n end() {\n if (ended) return;\n ended = true;\n span.end();\n },\n };\n }\n\n addEventToActiveSpan(name: string, attributes?: SpanAttributes): void {\n const activeSpan = this.otelApi.trace.getActiveSpan?.();\n if (activeSpan) {\n activeSpan.addEvent(name, attributes);\n }\n }\n\n // Axl uses an application-owned provider, whether supplied or global.\n // Its lifecycle, including flush and shutdown, belongs to the application.\n async shutdown(): Promise<void> {}\n}\n"],"mappings":";;;;;;;;;;;AAgDO,IAAM,kBAAN,MAAM,iBAAuC;AAAA,EAC1C;AAAA,EACA;AAAA,EAEA,YAAY,SAAkB,QAAoB;AACxD,SAAK,UAAU;AACf,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,aAAa,OAAO,QAAmD;AACrE,QAAI;AACJ,QAAI;AACF,gBAAW,MAAM,OAAO,oBAAoB;AAAA,IAC9C,QAAQ;AACN,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,iBACH,OAAO,kBACR,QAAQ,MAAM,kBAAkB;AAClC,UAAM,cAAc,OAAO,eAAe;AAC1C,UAAM,SAAS,eAAe,UAAU,WAAW;AAEnD,WAAO,IAAI,iBAAgB,SAAS,MAAM;AAAA,EAC5C;AAAA,EAEA,MAAM,cACJ,MACA,YACA,IACY;AACZ,WAAO,KAAK,OAAO,gBAAgB,MAAM,EAAE,WAAW,GAAG,OAAO,aAAuB;AACrF,UAAI,eAAe;AACnB,YAAM,SAAS,KAAK,OAAO,UAAU,MAAM;AACzC,uBAAe;AAAA,MACjB,CAAC;AAED,UAAI;AACF,cAAM,SAAS,MAAM,GAAG,MAAM;AAC9B,YAAI,CAAC,aAAc,QAAO,UAAU,IAAI;AACxC,eAAO;AAAA,MACT,SAAS,KAAK;AAIZ,eAAO,UAAU,OAAO;AACxB,cAAM;AAAA,MACR,UAAE;AACA,eAAO,IAAI;AAAA,MACb;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,UACE,MACA,YACA,SACY;AACZ,UAAM,OAAO,KAAK,OAAO,UAAU,MAAM;AAAA,MACvC;AAAA,MACA,GAAI,SAAS,SAAS,WAAW,EAAE,MAAM,KAAK,QAAQ,SAAS,OAAO,IAAI,CAAC;AAAA,MAC3E,GAAI,SAAS,cAAc,SAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,IAC7E,CAAC;AACD,WAAO,KAAK,OAAO,IAAI;AAAA,EACzB;AAAA,EAEQ,OAAO,MAAgB,UAAmC;AAChE,UAAM,UAAU,KAAK;AACrB,QAAI,QAAQ;AACZ,WAAO;AAAA,MACL,aAAa,KAAK,OAAO;AACvB,YAAI,CAAC,MAAO,MAAK,aAAa,KAAK,KAAK;AAAA,MAC1C;AAAA,MACA,SAAS,MAAM,YAAY;AACzB,YAAI,CAAC,MAAO,MAAK,SAAS,MAAM,UAAU;AAAA,MAC5C;AAAA,MACA,UAAU,MAAM,SAAS;AACvB,YAAI,MAAO;AACX,mBAAW;AACX,cAAM,aACJ,SAAS,OACL,QAAQ,eAAe,KACvB,SAAS,UACP,QAAQ,eAAe,QACvB,QAAQ,eAAe;AAC/B,aAAK,UAAU,EAAE,MAAM,YAAY,QAAQ,CAAC;AAAA,MAC9C;AAAA,MACA,MAAM;AACJ,YAAI,MAAO;AACX,gBAAQ;AACR,aAAK,IAAI;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAAA,EAEA,qBAAqB,MAAc,YAAmC;AACpE,UAAM,aAAa,KAAK,QAAQ,MAAM,gBAAgB;AACtD,QAAI,YAAY;AACd,iBAAW,SAAS,MAAM,UAAU;AAAA,IACtC;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,MAAM,WAA0B;AAAA,EAAC;AACnC;","names":[]}
|