trodo-node 1.1.0 → 2.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.
Files changed (68) hide show
  1. package/README.md +340 -103
  2. package/dist/cjs/TrodoClient.js +77 -19
  3. package/dist/cjs/TrodoClient.js.map +1 -1
  4. package/dist/cjs/api/ApiClient.js +21 -3
  5. package/dist/cjs/api/ApiClient.js.map +1 -1
  6. package/dist/cjs/api/endpoints.js +7 -1
  7. package/dist/cjs/api/endpoints.js.map +1 -1
  8. package/dist/cjs/index.js +104 -8
  9. package/dist/cjs/index.js.map +1 -1
  10. package/dist/cjs/otel/autoInstrument.js +253 -0
  11. package/dist/cjs/otel/autoInstrument.js.map +1 -0
  12. package/dist/cjs/otel/context.js +49 -0
  13. package/dist/cjs/otel/context.js.map +1 -0
  14. package/dist/cjs/otel/helpers.js +254 -0
  15. package/dist/cjs/otel/helpers.js.map +1 -0
  16. package/dist/cjs/otel/processor.js +129 -0
  17. package/dist/cjs/otel/processor.js.map +1 -0
  18. package/dist/cjs/otel/uuid.js +24 -0
  19. package/dist/cjs/otel/uuid.js.map +1 -0
  20. package/dist/cjs/otel/wrapAgent.js +399 -0
  21. package/dist/cjs/otel/wrapAgent.js.map +1 -0
  22. package/dist/cjs/queue/BatchFlusher.js +1 -1
  23. package/dist/cjs/queue/BatchFlusher.js.map +1 -1
  24. package/dist/esm/TrodoClient.d.ts +34 -1
  25. package/dist/esm/TrodoClient.d.ts.map +1 -1
  26. package/dist/esm/TrodoClient.js +77 -19
  27. package/dist/esm/TrodoClient.js.map +1 -1
  28. package/dist/esm/api/ApiClient.d.ts +9 -1
  29. package/dist/esm/api/ApiClient.d.ts.map +1 -1
  30. package/dist/esm/api/ApiClient.js +21 -3
  31. package/dist/esm/api/ApiClient.js.map +1 -1
  32. package/dist/esm/api/endpoints.d.ts +6 -1
  33. package/dist/esm/api/endpoints.d.ts.map +1 -1
  34. package/dist/esm/api/endpoints.js +7 -1
  35. package/dist/esm/api/endpoints.js.map +1 -1
  36. package/dist/esm/index.d.ts +84 -8
  37. package/dist/esm/index.d.ts.map +1 -1
  38. package/dist/esm/index.js +89 -7
  39. package/dist/esm/index.js.map +1 -1
  40. package/dist/esm/otel/autoInstrument.d.ts +61 -0
  41. package/dist/esm/otel/autoInstrument.d.ts.map +1 -0
  42. package/dist/esm/otel/autoInstrument.js +248 -0
  43. package/dist/esm/otel/autoInstrument.js.map +1 -0
  44. package/dist/esm/otel/context.d.ts +26 -0
  45. package/dist/esm/otel/context.d.ts.map +1 -0
  46. package/dist/esm/otel/context.js +44 -0
  47. package/dist/esm/otel/context.js.map +1 -0
  48. package/dist/esm/otel/helpers.d.ts +119 -0
  49. package/dist/esm/otel/helpers.d.ts.map +1 -0
  50. package/dist/esm/otel/helpers.js +244 -0
  51. package/dist/esm/otel/helpers.js.map +1 -0
  52. package/dist/esm/otel/processor.d.ts +94 -0
  53. package/dist/esm/otel/processor.d.ts.map +1 -0
  54. package/dist/esm/otel/processor.js +125 -0
  55. package/dist/esm/otel/processor.js.map +1 -0
  56. package/dist/esm/otel/uuid.d.ts +7 -0
  57. package/dist/esm/otel/uuid.d.ts.map +1 -0
  58. package/dist/esm/otel/uuid.js +21 -0
  59. package/dist/esm/otel/uuid.js.map +1 -0
  60. package/dist/esm/otel/wrapAgent.d.ts +100 -0
  61. package/dist/esm/otel/wrapAgent.d.ts.map +1 -0
  62. package/dist/esm/otel/wrapAgent.js +389 -0
  63. package/dist/esm/otel/wrapAgent.js.map +1 -0
  64. package/dist/esm/queue/BatchFlusher.js +1 -1
  65. package/dist/esm/queue/BatchFlusher.js.map +1 -1
  66. package/dist/esm/types/index.d.ts +26 -0
  67. package/dist/esm/types/index.d.ts.map +1 -1
  68. package/package.json +1 -1
@@ -0,0 +1,248 @@
1
+ import { getActiveContext } from './context.js';
2
+ function hrToIso(hr) {
3
+ if (!hr)
4
+ return undefined;
5
+ const ms = hr[0] * 1000 + Math.floor(hr[1] / 1e6);
6
+ return new Date(ms).toISOString();
7
+ }
8
+ function inferKind(attrs) {
9
+ if (!attrs)
10
+ return 'generic';
11
+ if (attrs['gen_ai.tool.name'])
12
+ return 'tool';
13
+ if (attrs['gen_ai.operation.name'] || attrs['gen_ai.request.model'])
14
+ return 'llm';
15
+ if (attrs['db.system'] || attrs['retrieval.query'])
16
+ return 'retrieval';
17
+ return 'generic';
18
+ }
19
+ function pickNum(attrs, keys) {
20
+ for (const k of keys) {
21
+ const v = attrs[k];
22
+ if (typeof v === 'number')
23
+ return v;
24
+ if (typeof v === 'string' && v !== '' && !isNaN(Number(v)))
25
+ return Number(v);
26
+ }
27
+ return undefined;
28
+ }
29
+ function pickStr(attrs, keys) {
30
+ for (const k of keys) {
31
+ const v = attrs[k];
32
+ if (typeof v === 'string' && v.length)
33
+ return v;
34
+ }
35
+ return undefined;
36
+ }
37
+ /**
38
+ * Translate an OTel span to our TrodoSpan shape using GenAI semantic
39
+ * conventions (gen_ai.*). Accepts both stable and legacy/experimental keys.
40
+ */
41
+ export function otelSpanToTrodoSpan(otel) {
42
+ const ctx = getActiveContext();
43
+ if (!ctx)
44
+ return null; // outside of wrapAgent — drop
45
+ const sc = otel.spanContext?.();
46
+ if (!sc)
47
+ return null;
48
+ const attrs = otel.attributes || {};
49
+ const kind = inferKind(attrs);
50
+ const startedAt = hrToIso(otel.startTime) || new Date().toISOString();
51
+ const endedAt = hrToIso(otel.endTime);
52
+ const durationMs = otel.startTime && otel.endTime
53
+ ? Math.max(0, (otel.endTime[0] - otel.startTime[0]) * 1000 +
54
+ (otel.endTime[1] - otel.startTime[1]) / 1e6)
55
+ : undefined;
56
+ const model = pickStr(attrs, [
57
+ 'gen_ai.request.model',
58
+ 'gen_ai.response.model',
59
+ 'llm.request.model',
60
+ ]);
61
+ const provider = pickStr(attrs, ['gen_ai.system', 'llm.vendor']);
62
+ const inputTokens = pickNum(attrs, [
63
+ 'gen_ai.usage.input_tokens',
64
+ 'gen_ai.usage.prompt_tokens',
65
+ 'llm.usage.prompt_tokens',
66
+ ]);
67
+ const outputTokens = pickNum(attrs, [
68
+ 'gen_ai.usage.output_tokens',
69
+ 'gen_ai.usage.completion_tokens',
70
+ 'llm.usage.completion_tokens',
71
+ ]);
72
+ const temperature = pickNum(attrs, ['gen_ai.request.temperature']);
73
+ const toolName = pickStr(attrs, ['gen_ai.tool.name']);
74
+ const input = pickStr(attrs, ['gen_ai.prompt', 'llm.prompts']);
75
+ const output = pickStr(attrs, ['gen_ai.completion', 'llm.completion']);
76
+ const span = {
77
+ span_id: sc.spanId,
78
+ run_id: ctx.runId,
79
+ parent_span_id: otel.parentSpanId || ctx.spanId,
80
+ kind,
81
+ name: otel.name,
82
+ status: otel.status?.code === 2 ? 'error' : 'ok',
83
+ started_at: startedAt,
84
+ ended_at: endedAt,
85
+ duration_ms: durationMs,
86
+ model,
87
+ provider,
88
+ input_tokens: inputTokens,
89
+ output_tokens: outputTokens,
90
+ temperature,
91
+ tool_name: toolName,
92
+ input,
93
+ output,
94
+ attributes: attrs,
95
+ };
96
+ return span;
97
+ }
98
+ /**
99
+ * Adapter that lets the OTel SDK push spans into our processor.
100
+ * Register with `sdk.addSpanProcessor(otelAdapter(processor))` in your app
101
+ * bootstrap.
102
+ */
103
+ export function otelAdapter(processor) {
104
+ return {
105
+ onStart() {
106
+ /* noop */
107
+ },
108
+ onEnd(otel) {
109
+ const span = otelSpanToTrodoSpan(otel);
110
+ if (span)
111
+ processor.enqueueSpan(span);
112
+ },
113
+ async forceFlush() {
114
+ await processor.forceFlush();
115
+ },
116
+ async shutdown() {
117
+ await processor.shutdown();
118
+ },
119
+ };
120
+ }
121
+ function buildInstrumentors() {
122
+ return [
123
+ {
124
+ id: 'anthropic',
125
+ factory: () => {
126
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
127
+ const m = require('@opentelemetry/instrumentation-anthropic');
128
+ return new m.AnthropicInstrumentation();
129
+ },
130
+ },
131
+ {
132
+ id: 'openai',
133
+ factory: () => {
134
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
135
+ const m = require('@opentelemetry/instrumentation-openai');
136
+ return new m.OpenAIInstrumentation();
137
+ },
138
+ },
139
+ {
140
+ id: 'langchain',
141
+ factory: () => {
142
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
143
+ const m = require('@opentelemetry/instrumentation-langchain');
144
+ return new m.LangChainInstrumentation();
145
+ },
146
+ },
147
+ {
148
+ id: 'bedrock',
149
+ factory: () => {
150
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
151
+ const m = require('@opentelemetry/instrumentation-bedrock');
152
+ return new m.BedrockInstrumentation();
153
+ },
154
+ },
155
+ {
156
+ id: 'cohere',
157
+ factory: () => {
158
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
159
+ const m = require('@opentelemetry/instrumentation-cohere');
160
+ return new m.CohereInstrumentation();
161
+ },
162
+ },
163
+ {
164
+ id: 'google-generativeai',
165
+ factory: () => {
166
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
167
+ const m = require('@opentelemetry/instrumentation-google-generativeai');
168
+ return new m.GoogleGenerativeAIInstrumentation();
169
+ },
170
+ },
171
+ {
172
+ id: 'vertexai',
173
+ factory: () => {
174
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
175
+ const m = require('@opentelemetry/instrumentation-vertexai');
176
+ return new m.VertexAIInstrumentation();
177
+ },
178
+ },
179
+ {
180
+ id: 'llama-index',
181
+ factory: () => {
182
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
183
+ const m = require('@opentelemetry/instrumentation-llamaindex');
184
+ return new m.LlamaIndexInstrumentation();
185
+ },
186
+ },
187
+ {
188
+ id: 'http',
189
+ factory: () => {
190
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
191
+ const m = require('@opentelemetry/instrumentation-http');
192
+ return new m.HttpInstrumentation();
193
+ },
194
+ },
195
+ {
196
+ id: 'fetch',
197
+ factory: () => {
198
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
199
+ const m = require('@opentelemetry/instrumentation-fetch');
200
+ return new m.FetchInstrumentation();
201
+ },
202
+ },
203
+ ];
204
+ }
205
+ /**
206
+ * Best-effort: register OTel auto-instrumentations if the user has them
207
+ * installed. This is optional — users can also configure OTel themselves and
208
+ * pass `otelAdapter(processor)` as a span processor.
209
+ *
210
+ * Returns the list of instrumentation ids that were successfully registered.
211
+ *
212
+ * Vercel AI SDK note: if you set `experimental_telemetry: { isEnabled: true,
213
+ * tracer: trace.getTracer('ai') }` on generateText/streamText calls, those
214
+ * spans flow through the SDK-registered OTel SpanProcessor automatically.
215
+ */
216
+ export function enableAutoInstrument(opts) {
217
+ const disabled = new Set(opts.disable || []);
218
+ const active = [];
219
+ try {
220
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
221
+ const { NodeSDK } = require('@opentelemetry/sdk-node');
222
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
223
+ const { Resource } = require('@opentelemetry/resources');
224
+ const instrumentations = [];
225
+ for (const spec of buildInstrumentors()) {
226
+ if (disabled.has(spec.id))
227
+ continue;
228
+ try {
229
+ instrumentations.push(spec.factory());
230
+ active.push(spec.id);
231
+ }
232
+ catch {
233
+ /* package not installed — skip */
234
+ }
235
+ }
236
+ const sdk = new NodeSDK({
237
+ resource: new Resource({ 'service.name': 'trodo-agent' }),
238
+ spanProcessor: otelAdapter(opts.processor),
239
+ instrumentations,
240
+ });
241
+ sdk.start();
242
+ }
243
+ catch {
244
+ // @opentelemetry/sdk-node not installed; wrapAgent + withSpan still work.
245
+ }
246
+ return active;
247
+ }
248
+ //# sourceMappingURL=autoInstrument.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autoInstrument.js","sourceRoot":"","sources":["../../../src/otel/autoInstrument.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Run/span active-context — used by wrapAgent, joinRun, and withSpan to
3
+ * thread parent_span_id and run_id through nested function calls without
4
+ * the user touching IDs.
5
+ *
6
+ * Backed by AsyncLocalStorage in Node (Node >= 14). Falls back to a global
7
+ * store in other runtimes (best-effort — only the top of each call chain
8
+ * is preserved).
9
+ *
10
+ * When a user registers a real OpenTelemetry SDK, their OTel ContextManager
11
+ * supersedes this for cross-package propagation. This lightweight store is
12
+ * the baseline so wrapAgent works without any external OTel dependency.
13
+ */
14
+ import type { TrodoSpanProcessor } from './processor.js';
15
+ export interface ActiveSpanContext {
16
+ runId: string;
17
+ spanId: string;
18
+ parentSpanId: string | null;
19
+ teamSiteId: string;
20
+ processor: TrodoSpanProcessor;
21
+ }
22
+ export declare function getActiveContext(): ActiveSpanContext | null;
23
+ export declare function runWithContext<R>(ctx: ActiveSpanContext, fn: () => R): R;
24
+ /** Async variant — context is preserved across awaits via AsyncLocalStorage. */
25
+ export declare function runWithContextAsync<R>(ctx: ActiveSpanContext, fn: () => Promise<R>): Promise<R>;
26
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/otel/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEzD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,kBAAkB,CAAC;CAC/B;AAsBD,wBAAgB,gBAAgB,IAAI,iBAAiB,GAAG,IAAI,CAG3D;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,GAAG,EAAE,iBAAiB,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CASxE;AAED,gFAAgF;AAChF,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,GAAG,EAAE,iBAAiB,EACtB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,CAOZ"}
@@ -0,0 +1,44 @@
1
+ let AsyncLocalStorageCtor = null;
2
+ try {
3
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
4
+ AsyncLocalStorageCtor = require('node:async_hooks').AsyncLocalStorage;
5
+ }
6
+ catch {
7
+ try {
8
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
9
+ AsyncLocalStorageCtor = require('async_hooks').AsyncLocalStorage;
10
+ }
11
+ catch {
12
+ AsyncLocalStorageCtor = null;
13
+ }
14
+ }
15
+ const als = AsyncLocalStorageCtor ? new AsyncLocalStorageCtor() : null;
16
+ let fallbackStore = null;
17
+ export function getActiveContext() {
18
+ if (als)
19
+ return als.getStore() ?? null;
20
+ return fallbackStore;
21
+ }
22
+ export function runWithContext(ctx, fn) {
23
+ if (als)
24
+ return als.run(ctx, fn);
25
+ const prev = fallbackStore;
26
+ fallbackStore = ctx;
27
+ try {
28
+ return fn();
29
+ }
30
+ finally {
31
+ fallbackStore = prev;
32
+ }
33
+ }
34
+ /** Async variant — context is preserved across awaits via AsyncLocalStorage. */
35
+ export function runWithContextAsync(ctx, fn) {
36
+ if (als)
37
+ return als.run(ctx, fn);
38
+ const prev = fallbackStore;
39
+ fallbackStore = ctx;
40
+ return fn().finally(() => {
41
+ fallbackStore = prev;
42
+ });
43
+ }
44
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/otel/context.ts"],"names":[],"mappings":"AAuBA,IAAI,qBAAqB,GAGb,IAAI,CAAC;AAEjB,IAAI,CAAC;IACH,8DAA8D;IAC9D,qBAAqB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC,iBAAiB,CAAC;AACxE,CAAC;AAAC,MAAM,CAAC;IACP,IAAI,CAAC;QACH,8DAA8D;QAC9D,qBAAqB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,iBAAiB,CAAC;IACnE,CAAC;IAAC,MAAM,CAAC;QACP,qBAAqB,GAAG,IAAI,CAAC;IAC/B,CAAC;AACH,CAAC;AAED,MAAM,GAAG,GAAG,qBAAqB,CAAC,CAAC,CAAC,IAAI,qBAAqB,EAAqB,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1F,IAAI,aAAa,GAA6B,IAAI,CAAC;AAEnD,MAAM,UAAU,gBAAgB;IAC9B,IAAI,GAAG;QAAE,OAAO,GAAG,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC;IACvC,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,cAAc,CAAI,GAAsB,EAAE,EAAW;IACnE,IAAI,GAAG;QAAE,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,aAAa,CAAC;IAC3B,aAAa,GAAG,GAAG,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,EAAE,EAAE,CAAC;IACd,CAAC;YAAS,CAAC;QACT,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,mBAAmB,CACjC,GAAsB,EACtB,EAAoB;IAEpB,IAAI,GAAG;QAAE,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,aAAa,CAAC;IAC3B,aAAa,GAAG,GAAG,CAAC;IACpB,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;QACvB,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,119 @@
1
+ import { type WithSpanOptions } from './wrapAgent.js';
2
+ import type { TrodoSpanProcessor } from './processor.js';
3
+ export interface ToolOptions {
4
+ name?: string;
5
+ kind?: 'tool' | 'retrieval' | 'generic';
6
+ }
7
+ type AnyFn<Args extends unknown[], R> = (...args: Args) => Promise<R> | R;
8
+ /**
9
+ * Wrap a function as a tool span — supports two forms:
10
+ *
11
+ * // name-first (uselemma-compatible):
12
+ * const fetchUser = trodo.tool('fetch_user', async (uid) => { ... });
13
+ *
14
+ * // function-first (backward-compatible):
15
+ * const fetchUser = trodo.tool(async (uid) => { ... }, { name: 'fetch_user' });
16
+ */
17
+ export declare function tool<Args extends unknown[], R>(name: string, fn: AnyFn<Args, R>): (...args: Args) => Promise<R>;
18
+ export declare function tool<Args extends unknown[], R>(fn: AnyFn<Args, R>, options?: ToolOptions): (...args: Args) => Promise<R>;
19
+ /**
20
+ * Wrap a function as a generic span. Mirrors the uselemma `trace()` helper.
21
+ *
22
+ * const prepare = trodo.trace('prepare', async (input) => { ... });
23
+ */
24
+ export declare function trace<Args extends unknown[], R>(name: string, fn: AnyFn<Args, R>, options?: WithSpanOptions): (...args: Args) => Promise<R>;
25
+ /** Wrap a retriever / vector search as a kind='retrieval' span. */
26
+ export declare function retrieval<Args extends unknown[], R>(name: string, fn: AnyFn<Args, R>, options?: WithSpanOptions): (...args: Args) => Promise<R>;
27
+ export interface LlmOptions extends WithSpanOptions {
28
+ model?: string;
29
+ provider?: string;
30
+ temperature?: number;
31
+ extractUsage?: (result: unknown) => {
32
+ inputTokens?: number;
33
+ outputTokens?: number;
34
+ };
35
+ }
36
+ /**
37
+ * Wrap an LLM call — auto-extracts tokens from OpenAI/Anthropic/Gemini
38
+ * response shapes.
39
+ *
40
+ * const answer = trodo.llm('answer', callOpenAI, {
41
+ * model: 'gpt-4o-mini', provider: 'openai',
42
+ * });
43
+ */
44
+ export declare function llm<Args extends unknown[], R>(name: string, fn: AnyFn<Args, R>, options?: LlmOptions): (...args: Args) => Promise<R>;
45
+ /**
46
+ * Return a raw OTel tracer — the Trodo processor is already subscribed.
47
+ * Use for advanced cases where you want to emit spans with the raw OTel
48
+ * API; they flow through to Trodo like any other span.
49
+ */
50
+ export declare function getTracer(name?: string): unknown;
51
+ export interface TrackLlmCallParams {
52
+ model?: string;
53
+ provider?: string;
54
+ inputTokens?: number;
55
+ outputTokens?: number;
56
+ prompt?: unknown;
57
+ completion?: unknown;
58
+ temperature?: number;
59
+ cost?: number;
60
+ name?: string;
61
+ metadata?: Record<string, unknown>;
62
+ }
63
+ /**
64
+ * Record a one-shot LLM span for a raw-HTTP caller. Opens and immediately
65
+ * closes a span(kind='llm') populated with the model + token counts +
66
+ * prompt/completion. No-op outside an active run context.
67
+ *
68
+ * Usage:
69
+ * const resp = await fetch(url, { body: JSON.stringify(body) }).then(r => r.json());
70
+ * await trodo.trackLlmCall({
71
+ * model: 'gemini-2.5-flash',
72
+ * provider: 'google',
73
+ * inputTokens: resp.usageMetadata.promptTokenCount,
74
+ * outputTokens: resp.usageMetadata.candidatesTokenCount,
75
+ * prompt: body,
76
+ * completion: resp,
77
+ * });
78
+ */
79
+ export declare function trackLlmCall(params: TrackLlmCallParams): Promise<void>;
80
+ /** Minimal subset of Express Request/Response/NextFn we actually touch. */
81
+ interface ExpressReq {
82
+ headers: Record<string, string | string[] | undefined>;
83
+ method?: string;
84
+ url?: string;
85
+ originalUrl?: string;
86
+ path?: string;
87
+ }
88
+ interface ExpressRes {
89
+ statusCode?: number;
90
+ on?: (event: string, cb: () => void) => void;
91
+ }
92
+ type NextFn = (err?: unknown) => void;
93
+ export interface ExpressMiddlewareDeps {
94
+ processor: TrodoSpanProcessor;
95
+ teamSiteId: string;
96
+ }
97
+ /**
98
+ * Return an Express/Connect middleware that auto-joins inbound runs.
99
+ *
100
+ * If the inbound request has X-Trodo-Run-Id, every span created while
101
+ * handling the request nests under the caller's run. Otherwise the
102
+ * handler runs with no active context (no-op tracking).
103
+ *
104
+ * Usage:
105
+ * import express from 'express';
106
+ * import trodo from 'trodo-node';
107
+ * trodo.init({ siteId: '...' });
108
+ * const app = express();
109
+ * app.use(trodo.expressMiddleware());
110
+ */
111
+ export declare function expressMiddleware(deps: ExpressMiddlewareDeps): (req: ExpressReq, res: ExpressRes, next: NextFn) => void;
112
+ /**
113
+ * Return HTTP headers carrying the current run/span context. Use when
114
+ * making outbound HTTP calls to downstream services so they can joinRun
115
+ * instead of creating their own runs.
116
+ */
117
+ export declare function propagationHeaders(): Record<string, string>;
118
+ export {};
119
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/otel/helpers.ts"],"names":[],"mappings":"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"}