@axlsdk/axl 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/README.md +363 -0
- package/dist/chunk-EE2BCC37.js +79 -0
- package/dist/chunk-EE2BCC37.js.map +1 -0
- package/dist/index.cjs +5410 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1576 -0
- package/dist/index.d.ts +1576 -0
- package/dist/index.js +5265 -0
- package/dist/index.js.map +1 -0
- package/dist/span-manager-LGX7QHZ7.js +7 -0
- package/dist/span-manager-LGX7QHZ7.js.map +1 -0
- package/package.json +85 -0
package/README.md
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
# axl
|
|
2
|
+
|
|
3
|
+
Core SDK for orchestrating agentic systems in TypeScript.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install axl zod
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## API
|
|
12
|
+
|
|
13
|
+
### `tool(config)`
|
|
14
|
+
|
|
15
|
+
Define a tool with Zod input validation:
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { tool } from 'axl';
|
|
19
|
+
import { z } from 'zod';
|
|
20
|
+
|
|
21
|
+
const calculator = tool({
|
|
22
|
+
name: 'calculator',
|
|
23
|
+
description: 'Evaluate arithmetic expressions',
|
|
24
|
+
input: z.object({ expression: z.string() }),
|
|
25
|
+
handler: ({ expression }) => {
|
|
26
|
+
const result = new Function(`return (${expression})`)();
|
|
27
|
+
return { result };
|
|
28
|
+
},
|
|
29
|
+
retry: { attempts: 3, backoff: 'exponential' },
|
|
30
|
+
sensitive: false,
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### `agent(config)`
|
|
35
|
+
|
|
36
|
+
Define an agent with model, system prompt, tools, and handoffs:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { agent } from 'axl';
|
|
40
|
+
|
|
41
|
+
const researcher = agent({
|
|
42
|
+
name: 'researcher',
|
|
43
|
+
model: 'openai:gpt-4o',
|
|
44
|
+
system: 'You are a research assistant.',
|
|
45
|
+
tools: [calculator],
|
|
46
|
+
maxTurns: 10,
|
|
47
|
+
timeout: '30s',
|
|
48
|
+
temperature: 0.7,
|
|
49
|
+
version: 'v1.2',
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Dynamic model and system prompt selection:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
const dynamicAgent = agent({
|
|
57
|
+
model: (ctx) => ctx.metadata?.tier === 'premium'
|
|
58
|
+
? 'openai:gpt-4o'
|
|
59
|
+
: 'openai:gpt-4.1-nano',
|
|
60
|
+
system: (ctx) => `You are a ${ctx.metadata?.role ?? 'general'} assistant.`,
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### `workflow(config)`
|
|
65
|
+
|
|
66
|
+
Define a named workflow with typed input/output:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import { workflow } from 'axl';
|
|
70
|
+
import { z } from 'zod';
|
|
71
|
+
|
|
72
|
+
const myWorkflow = workflow({
|
|
73
|
+
name: 'my-workflow',
|
|
74
|
+
input: z.object({ query: z.string() }),
|
|
75
|
+
output: z.object({ answer: z.string() }),
|
|
76
|
+
handler: async (ctx) => {
|
|
77
|
+
const answer = await ctx.ask(researcher, ctx.input.query);
|
|
78
|
+
return { answer };
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### `AxlRuntime`
|
|
84
|
+
|
|
85
|
+
Register and execute workflows:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { AxlRuntime } from 'axl';
|
|
89
|
+
|
|
90
|
+
const runtime = new AxlRuntime();
|
|
91
|
+
runtime.register(myWorkflow);
|
|
92
|
+
|
|
93
|
+
// Execute
|
|
94
|
+
const result = await runtime.execute('my-workflow', { query: 'Hello' });
|
|
95
|
+
|
|
96
|
+
// Stream
|
|
97
|
+
const stream = runtime.stream('my-workflow', { query: 'Hello' });
|
|
98
|
+
for await (const event of stream) {
|
|
99
|
+
if (event.type === 'token') process.stdout.write(event.data);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Sessions
|
|
103
|
+
const session = runtime.session('user-123');
|
|
104
|
+
await session.send('my-workflow', { query: 'Hello' });
|
|
105
|
+
await session.send('my-workflow', { query: 'Follow-up' });
|
|
106
|
+
const history = await session.history();
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Context Primitives
|
|
110
|
+
|
|
111
|
+
All available on `ctx` inside workflow handlers:
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
// Invoke an agent
|
|
115
|
+
const answer = await ctx.ask(agent, 'prompt', { schema, retries });
|
|
116
|
+
|
|
117
|
+
// Run N concurrent tasks
|
|
118
|
+
const results = await ctx.spawn(3, async (i) => ctx.ask(agent, prompts[i]));
|
|
119
|
+
|
|
120
|
+
// Consensus vote
|
|
121
|
+
const winner = ctx.vote(results, { strategy: 'majority', key: 'answer' });
|
|
122
|
+
|
|
123
|
+
// Self-correcting validation
|
|
124
|
+
const valid = await ctx.verify(
|
|
125
|
+
async (lastOutput, error) => ctx.ask(agent, prompt),
|
|
126
|
+
schema,
|
|
127
|
+
{ retries: 3, fallback: defaultValue },
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
// Cost control
|
|
131
|
+
const budgeted = await ctx.budget({ cost: '$1.00', onExceed: 'hard_stop' }, async () => {
|
|
132
|
+
return ctx.ask(agent, prompt);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// First to complete
|
|
136
|
+
const fastest = await ctx.race([
|
|
137
|
+
() => ctx.ask(agentA, prompt),
|
|
138
|
+
() => ctx.ask(agentB, prompt),
|
|
139
|
+
], { schema });
|
|
140
|
+
|
|
141
|
+
// Concurrent independent tasks
|
|
142
|
+
const [a, b] = await ctx.parallel([
|
|
143
|
+
() => ctx.ask(agentA, promptA),
|
|
144
|
+
() => ctx.ask(agentB, promptB),
|
|
145
|
+
]);
|
|
146
|
+
|
|
147
|
+
// Map with bounded concurrency
|
|
148
|
+
const mapped = await ctx.map(items, async (item) => ctx.ask(agent, item), {
|
|
149
|
+
concurrency: 5,
|
|
150
|
+
quorum: 3,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Human-in-the-loop
|
|
154
|
+
const decision = await ctx.awaitHuman({
|
|
155
|
+
channel: 'slack',
|
|
156
|
+
prompt: 'Approve this action?',
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// Durable checkpoint
|
|
160
|
+
const value = await ctx.checkpoint(async () => expensiveOperation());
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### OpenTelemetry Observability
|
|
164
|
+
|
|
165
|
+
Automatic span emission for every `ctx.*` primitive with cost-per-span attribution. Install `@opentelemetry/api` as an optional peer dependency.
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
import { defineConfig, AxlRuntime } from 'axl';
|
|
169
|
+
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
|
|
170
|
+
|
|
171
|
+
const config = defineConfig({
|
|
172
|
+
telemetry: {
|
|
173
|
+
enabled: true,
|
|
174
|
+
serviceName: 'my-app',
|
|
175
|
+
exporter: new OTLPTraceExporter({ url: 'http://localhost:4318/v1/traces' }),
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
const runtime = new AxlRuntime(config);
|
|
180
|
+
runtime.initializeTelemetry();
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Span model:** `axl.workflow.execute` > `axl.agent.ask` > `axl.tool.call`. Also: `axl.ctx.spawn`, `axl.ctx.race`, `axl.ctx.vote`, `axl.ctx.budget`, `axl.ctx.checkpoint`, `axl.ctx.awaitHuman`. Each span includes relevant attributes (cost, duration, token counts, etc.).
|
|
184
|
+
|
|
185
|
+
When disabled (default), `NoopSpanManager` provides zero overhead.
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
import { createSpanManager, NoopSpanManager } from 'axl';
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Memory Primitives
|
|
192
|
+
|
|
193
|
+
Working memory backed by the existing `StateStore` interface:
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// Store and retrieve structured state
|
|
197
|
+
await ctx.remember('user-preferences', { theme: 'dark', lang: 'en' });
|
|
198
|
+
const prefs = await ctx.recall('user-preferences');
|
|
199
|
+
await ctx.forget('user-preferences');
|
|
200
|
+
|
|
201
|
+
// Scoped to session (default) or global
|
|
202
|
+
await ctx.remember('user-profile', data, { scope: 'global' });
|
|
203
|
+
const profile = await ctx.recall('user-profile', { scope: 'global' });
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Semantic recall requires a vector store and embedder configured on the runtime:
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
import { AxlRuntime, InMemoryVectorStore, OpenAIEmbedder } from 'axl';
|
|
210
|
+
|
|
211
|
+
const runtime = new AxlRuntime({
|
|
212
|
+
memory: {
|
|
213
|
+
vector: new InMemoryVectorStore(),
|
|
214
|
+
embedder: new OpenAIEmbedder({ model: 'text-embedding-3-small' }),
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// In a workflow:
|
|
219
|
+
const relevant = await ctx.recall('knowledge-base', {
|
|
220
|
+
query: 'refund policy',
|
|
221
|
+
topK: 5,
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Vector store implementations: `InMemoryVectorStore` (testing), `SqliteVectorStore` (production, requires `better-sqlite3`).
|
|
226
|
+
|
|
227
|
+
### Agent Guardrails
|
|
228
|
+
|
|
229
|
+
Input and output validation at the agent boundary:
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
const safe = agent({
|
|
233
|
+
model: 'openai:gpt-4o',
|
|
234
|
+
system: 'You are a helpful assistant.',
|
|
235
|
+
guardrails: {
|
|
236
|
+
input: async (prompt, ctx) => {
|
|
237
|
+
if (containsPII(prompt)) return { block: true, reason: 'PII detected' };
|
|
238
|
+
return { block: false };
|
|
239
|
+
},
|
|
240
|
+
output: async (response, ctx) => {
|
|
241
|
+
if (isOffTopic(response)) return { block: true, reason: 'Off-topic response' };
|
|
242
|
+
return { block: false };
|
|
243
|
+
},
|
|
244
|
+
onBlock: 'retry', // 'retry' | 'throw' | (reason, ctx) => fallbackResponse
|
|
245
|
+
maxRetries: 2,
|
|
246
|
+
},
|
|
247
|
+
});
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
When `onBlock` is `'retry'`, the LLM sees the block reason and self-corrects (same pattern as `ctx.verify()`). Throws `GuardrailError` if retries are exhausted or `onBlock` is `'throw'`.
|
|
251
|
+
|
|
252
|
+
### Session Options
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
const session = runtime.session('user-123', {
|
|
256
|
+
history: {
|
|
257
|
+
maxMessages: 100, // Trim oldest messages when exceeded
|
|
258
|
+
summarize: true, // Auto-summarize trimmed messages
|
|
259
|
+
},
|
|
260
|
+
persist: true, // Save to StateStore (default: true)
|
|
261
|
+
});
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
`SessionOptions` type:
|
|
265
|
+
|
|
266
|
+
| Option | Type | Default | Description |
|
|
267
|
+
|--------|------|---------|-------------|
|
|
268
|
+
| `history.maxMessages` | `number` | unlimited | Max messages to retain |
|
|
269
|
+
| `history.summarize` | `boolean` | `false` | Summarize trimmed messages |
|
|
270
|
+
| `persist` | `boolean` | `true` | Persist history to StateStore |
|
|
271
|
+
|
|
272
|
+
### Error Hierarchy
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
import {
|
|
276
|
+
AxlError, // Base class
|
|
277
|
+
VerifyError, // Schema validation failed after retries
|
|
278
|
+
QuorumNotMet, // Quorum threshold not reached
|
|
279
|
+
NoConsensus, // Vote could not reach consensus
|
|
280
|
+
TimeoutError, // Operation exceeded timeout
|
|
281
|
+
MaxTurnsError, // Agent exceeded max tool-calling turns
|
|
282
|
+
BudgetExceededError, // Budget limit exceeded
|
|
283
|
+
GuardrailError, // Guardrail blocked input or output
|
|
284
|
+
ToolDenied, // Agent tried to call unauthorized tool
|
|
285
|
+
} from 'axl';
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### State Stores
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
import { MemoryStore, SQLiteStore, RedisStore } from 'axl';
|
|
292
|
+
|
|
293
|
+
// In-memory (default)
|
|
294
|
+
const runtime = new AxlRuntime();
|
|
295
|
+
|
|
296
|
+
// SQLite (requires better-sqlite3)
|
|
297
|
+
const runtime = new AxlRuntime({
|
|
298
|
+
state: { store: 'sqlite', sqlite: { path: './data/axl.db' } },
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
// Redis (requires ioredis)
|
|
302
|
+
const runtime = new AxlRuntime({
|
|
303
|
+
state: { store: 'redis', redis: { url: 'redis://localhost:6379' } },
|
|
304
|
+
});
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Provider URIs
|
|
308
|
+
|
|
309
|
+
Four built-in providers are supported:
|
|
310
|
+
|
|
311
|
+
```
|
|
312
|
+
# OpenAI — Chat Completions API
|
|
313
|
+
openai:gpt-4o # Flagship multimodal
|
|
314
|
+
openai:gpt-4o-mini # Fast and affordable
|
|
315
|
+
openai:gpt-4.1 # GPT-4.1
|
|
316
|
+
openai:gpt-4.1-mini # GPT-4.1 small
|
|
317
|
+
openai:gpt-4.1-nano # GPT-4.1 cheapest
|
|
318
|
+
openai:gpt-5 # GPT-5
|
|
319
|
+
openai:gpt-5-mini # GPT-5 small
|
|
320
|
+
openai:gpt-5-nano # GPT-5 cheapest
|
|
321
|
+
openai:gpt-5.1 # GPT-5.1
|
|
322
|
+
openai:gpt-5.2 # GPT-5.2
|
|
323
|
+
openai:o1 # Reasoning
|
|
324
|
+
openai:o1-mini # Reasoning (small)
|
|
325
|
+
openai:o1-pro # Reasoning (pro)
|
|
326
|
+
openai:o3 # Reasoning
|
|
327
|
+
openai:o3-mini # Reasoning (small)
|
|
328
|
+
openai:o3-pro # Reasoning (pro)
|
|
329
|
+
openai:o4-mini # Reasoning (small)
|
|
330
|
+
openai:gpt-4-turbo # Legacy
|
|
331
|
+
openai:gpt-4 # Legacy
|
|
332
|
+
openai:gpt-3.5-turbo # Legacy
|
|
333
|
+
|
|
334
|
+
# OpenAI — Responses API (same models, better caching, native reasoning)
|
|
335
|
+
openai-responses:gpt-4o
|
|
336
|
+
openai-responses:o3
|
|
337
|
+
|
|
338
|
+
# Anthropic
|
|
339
|
+
anthropic:claude-opus-4-6 # Most capable
|
|
340
|
+
anthropic:claude-sonnet-4-5 # Balanced
|
|
341
|
+
anthropic:claude-haiku-4-5 # Fast and affordable
|
|
342
|
+
anthropic:claude-sonnet-4 # Previous gen
|
|
343
|
+
anthropic:claude-opus-4 # Previous gen
|
|
344
|
+
anthropic:claude-3-7-sonnet # Legacy
|
|
345
|
+
anthropic:claude-3-5-sonnet # Legacy
|
|
346
|
+
anthropic:claude-3-5-haiku # Legacy
|
|
347
|
+
anthropic:claude-3-opus # Legacy
|
|
348
|
+
anthropic:claude-3-sonnet # Legacy
|
|
349
|
+
anthropic:claude-3-haiku # Legacy
|
|
350
|
+
|
|
351
|
+
# Google Gemini
|
|
352
|
+
google:gemini-2.5-pro # Most capable
|
|
353
|
+
google:gemini-2.5-flash # Fast
|
|
354
|
+
google:gemini-2.5-flash-lite # Cheapest 2.5
|
|
355
|
+
google:gemini-2.0-flash # Previous gen
|
|
356
|
+
google:gemini-2.0-flash-lite # Previous gen (lite)
|
|
357
|
+
google:gemini-3-pro-preview # Next gen (preview)
|
|
358
|
+
google:gemini-3-flash-preview # Next gen fast (preview)
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
## License
|
|
362
|
+
|
|
363
|
+
[Apache 2.0](../../LICENSE)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// src/telemetry/span-manager.ts
|
|
9
|
+
var OTelSpanManager = class _OTelSpanManager {
|
|
10
|
+
tracer;
|
|
11
|
+
otelApi;
|
|
12
|
+
tracerProvider;
|
|
13
|
+
constructor(otelApi, tracer, tracerProvider) {
|
|
14
|
+
this.otelApi = otelApi;
|
|
15
|
+
this.tracer = tracer;
|
|
16
|
+
this.tracerProvider = tracerProvider;
|
|
17
|
+
}
|
|
18
|
+
static async create(config) {
|
|
19
|
+
let otelApi;
|
|
20
|
+
try {
|
|
21
|
+
otelApi = await import("@opentelemetry/api");
|
|
22
|
+
} catch {
|
|
23
|
+
throw new Error(
|
|
24
|
+
"@opentelemetry/api is required for telemetry. Install it with: npm install @opentelemetry/api"
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
const tracerProvider = config.tracerProvider ?? otelApi.trace.getTracerProvider();
|
|
28
|
+
const serviceName = config.serviceName ?? "axl";
|
|
29
|
+
const tracer = tracerProvider.getTracer(serviceName);
|
|
30
|
+
return new _OTelSpanManager(otelApi, tracer, tracerProvider);
|
|
31
|
+
}
|
|
32
|
+
async withSpanAsync(name, attributes, fn) {
|
|
33
|
+
const otelApi = this.otelApi;
|
|
34
|
+
return this.tracer.startActiveSpan(name, { attributes }, async (otelSpan) => {
|
|
35
|
+
const handle = {
|
|
36
|
+
setAttribute(key, value) {
|
|
37
|
+
otelSpan.setAttribute(key, value);
|
|
38
|
+
},
|
|
39
|
+
addEvent(eventName, attrs) {
|
|
40
|
+
otelSpan.addEvent(eventName, attrs);
|
|
41
|
+
},
|
|
42
|
+
setStatus(code, message) {
|
|
43
|
+
const statusCode = code === "ok" ? otelApi.SpanStatusCode.OK : otelApi.SpanStatusCode.ERROR;
|
|
44
|
+
otelSpan.setStatus({ code: statusCode, message });
|
|
45
|
+
},
|
|
46
|
+
end() {
|
|
47
|
+
otelSpan.end();
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
try {
|
|
51
|
+
const result = await fn(handle);
|
|
52
|
+
handle.setStatus("ok");
|
|
53
|
+
return result;
|
|
54
|
+
} catch (err) {
|
|
55
|
+
handle.setStatus("error", err instanceof Error ? err.message : String(err));
|
|
56
|
+
throw err;
|
|
57
|
+
} finally {
|
|
58
|
+
handle.end();
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
addEventToActiveSpan(name, attributes) {
|
|
63
|
+
const activeSpan = this.otelApi.trace.getActiveSpan?.();
|
|
64
|
+
if (activeSpan) {
|
|
65
|
+
activeSpan.addEvent(name, attributes);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async shutdown() {
|
|
69
|
+
if (this.tracerProvider && typeof this.tracerProvider.shutdown === "function") {
|
|
70
|
+
await this.tracerProvider.shutdown();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export {
|
|
76
|
+
__require,
|
|
77
|
+
OTelSpanManager
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=chunk-EE2BCC37.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/telemetry/span-manager.ts"],"sourcesContent":["import type { SpanHandle, SpanManager, TelemetryConfig } from './types.js';\n\n/**\n * OpenTelemetry-backed SpanManager.\n * Dynamically imports @opentelemetry/api to avoid hard dependency.\n */\nexport class OTelSpanManager implements SpanManager {\n private tracer: any;\n private otelApi: any;\n private tracerProvider: any;\n\n private constructor(otelApi: any, tracer: any, tracerProvider: any) {\n this.otelApi = otelApi;\n this.tracer = tracer;\n this.tracerProvider = tracerProvider;\n }\n\n static async create(config: TelemetryConfig): Promise<OTelSpanManager> {\n let otelApi: any;\n try {\n otelApi = await import('@opentelemetry/api');\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 = config.tracerProvider ?? otelApi.trace.getTracerProvider();\n const serviceName = config.serviceName ?? 'axl';\n const tracer = (tracerProvider as any).getTracer(serviceName);\n\n return new OTelSpanManager(otelApi, tracer, tracerProvider);\n }\n\n async withSpanAsync<T>(\n name: string,\n attributes: Record<string, string | number | boolean>,\n fn: (span: SpanHandle) => Promise<T>,\n ): Promise<T> {\n const otelApi = this.otelApi;\n\n return this.tracer.startActiveSpan(name, { attributes }, async (otelSpan: any) => {\n const handle: SpanHandle = {\n setAttribute(key: string, value: string | number | boolean) {\n otelSpan.setAttribute(key, value);\n },\n addEvent(eventName: string, attrs?: Record<string, string | number | boolean>) {\n otelSpan.addEvent(eventName, attrs);\n },\n setStatus(code: 'ok' | 'error', message?: string) {\n const statusCode =\n code === 'ok' ? otelApi.SpanStatusCode.OK : otelApi.SpanStatusCode.ERROR;\n otelSpan.setStatus({ code: statusCode, message });\n },\n end() {\n otelSpan.end();\n },\n };\n\n try {\n const result = await fn(handle);\n handle.setStatus('ok');\n return result;\n } catch (err) {\n handle.setStatus('error', err instanceof Error ? err.message : String(err));\n throw err;\n } finally {\n handle.end();\n }\n });\n }\n\n addEventToActiveSpan(name: string, attributes?: Record<string, string | number | boolean>): void {\n const activeSpan = this.otelApi.trace.getActiveSpan?.();\n if (activeSpan) {\n activeSpan.addEvent(name, attributes);\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.tracerProvider && typeof this.tracerProvider.shutdown === 'function') {\n await this.tracerProvider.shutdown();\n }\n }\n}\n"],"mappings":";;;;;;;;AAMO,IAAM,kBAAN,MAAM,iBAAuC;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY,SAAc,QAAa,gBAAqB;AAClE,SAAK,UAAU;AACf,SAAK,SAAS;AACd,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,aAAa,OAAO,QAAmD;AACrE,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,OAAO,oBAAoB;AAAA,IAC7C,QAAQ;AACN,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,iBAAiB,OAAO,kBAAkB,QAAQ,MAAM,kBAAkB;AAChF,UAAM,cAAc,OAAO,eAAe;AAC1C,UAAM,SAAU,eAAuB,UAAU,WAAW;AAE5D,WAAO,IAAI,iBAAgB,SAAS,QAAQ,cAAc;AAAA,EAC5D;AAAA,EAEA,MAAM,cACJ,MACA,YACA,IACY;AACZ,UAAM,UAAU,KAAK;AAErB,WAAO,KAAK,OAAO,gBAAgB,MAAM,EAAE,WAAW,GAAG,OAAO,aAAkB;AAChF,YAAM,SAAqB;AAAA,QACzB,aAAa,KAAa,OAAkC;AAC1D,mBAAS,aAAa,KAAK,KAAK;AAAA,QAClC;AAAA,QACA,SAAS,WAAmB,OAAmD;AAC7E,mBAAS,SAAS,WAAW,KAAK;AAAA,QACpC;AAAA,QACA,UAAU,MAAsB,SAAkB;AAChD,gBAAM,aACJ,SAAS,OAAO,QAAQ,eAAe,KAAK,QAAQ,eAAe;AACrE,mBAAS,UAAU,EAAE,MAAM,YAAY,QAAQ,CAAC;AAAA,QAClD;AAAA,QACA,MAAM;AACJ,mBAAS,IAAI;AAAA,QACf;AAAA,MACF;AAEA,UAAI;AACF,cAAM,SAAS,MAAM,GAAG,MAAM;AAC9B,eAAO,UAAU,IAAI;AACrB,eAAO;AAAA,MACT,SAAS,KAAK;AACZ,eAAO,UAAU,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAC1E,cAAM;AAAA,MACR,UAAE;AACA,eAAO,IAAI;AAAA,MACb;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,qBAAqB,MAAc,YAA8D;AAC/F,UAAM,aAAa,KAAK,QAAQ,MAAM,gBAAgB;AACtD,QAAI,YAAY;AACd,iBAAW,SAAS,MAAM,UAAU;AAAA,IACtC;AAAA,EACF;AAAA,EAEA,MAAM,WAA0B;AAC9B,QAAI,KAAK,kBAAkB,OAAO,KAAK,eAAe,aAAa,YAAY;AAC7E,YAAM,KAAK,eAAe,SAAS;AAAA,IACrC;AAAA,EACF;AACF;","names":[]}
|