@glassflow-ai/rius 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 +328 -0
- package/dist/index.cjs +914 -0
- package/dist/index.d.cts +156 -0
- package/dist/index.d.ts +156 -0
- package/dist/index.js +889 -0
- package/package.json +85 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,914 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __esm = (fn, res) => function __init() {
|
|
7
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
8
|
+
};
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
22
|
+
|
|
23
|
+
// src/config.ts
|
|
24
|
+
function bool(name, raw, fallback) {
|
|
25
|
+
if (raw === void 0) return fallback;
|
|
26
|
+
const value = raw.trim().toLowerCase();
|
|
27
|
+
if (AFFIRMATIVE.has(value)) return true;
|
|
28
|
+
if (NEGATIVE.has(value)) return false;
|
|
29
|
+
console.warn(
|
|
30
|
+
`[rius] ${name}="${raw}" is not a recognised boolean; using the default (${fallback}). Accepted: 1/true/yes/on, 0/false/no/off.`
|
|
31
|
+
);
|
|
32
|
+
return fallback;
|
|
33
|
+
}
|
|
34
|
+
function rate(raw, fallback) {
|
|
35
|
+
if (raw === void 0) return fallback;
|
|
36
|
+
const parsed = Number.parseFloat(raw);
|
|
37
|
+
if (Number.isNaN(parsed)) return fallback;
|
|
38
|
+
return Math.min(1, Math.max(0, parsed));
|
|
39
|
+
}
|
|
40
|
+
function resolveConfig(options = {}, env = process.env) {
|
|
41
|
+
const endpoint = (options.endpoint ?? env.RIUS_ENDPOINT ?? DEFAULT_ENDPOINT).replace(/\/+$/, "");
|
|
42
|
+
return {
|
|
43
|
+
endpoint,
|
|
44
|
+
apiKey: options.apiKey ?? env.RIUS_API_KEY,
|
|
45
|
+
serviceName: options.serviceName ?? env.RIUS_SERVICE_NAME ?? DEFAULT_SERVICE_NAME,
|
|
46
|
+
disabled: options.disabled ?? bool("RIUS_DISABLED", env.RIUS_DISABLED, false),
|
|
47
|
+
sampleRate: options.sampleRate ?? rate(env.RIUS_SAMPLE_RATE, 1),
|
|
48
|
+
captureContent: options.captureContent ?? bool("RIUS_CAPTURE_CONTENT", env.RIUS_CAPTURE_CONTENT, true),
|
|
49
|
+
mask: options.mask
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
var DEFAULT_ENDPOINT, DEFAULT_SERVICE_NAME, AFFIRMATIVE, NEGATIVE;
|
|
53
|
+
var init_config = __esm({
|
|
54
|
+
"src/config.ts"() {
|
|
55
|
+
"use strict";
|
|
56
|
+
DEFAULT_ENDPOINT = "https://ingest.eu.console.rius-glassflow.com";
|
|
57
|
+
DEFAULT_SERVICE_NAME = "unknown_service";
|
|
58
|
+
AFFIRMATIVE = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
|
|
59
|
+
NEGATIVE = /* @__PURE__ */ new Set(["0", "false", "no", "off"]);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// src/delegatingProcessor.ts
|
|
64
|
+
var DelegatingSpanProcessor;
|
|
65
|
+
var init_delegatingProcessor = __esm({
|
|
66
|
+
"src/delegatingProcessor.ts"() {
|
|
67
|
+
"use strict";
|
|
68
|
+
DelegatingSpanProcessor = class {
|
|
69
|
+
delegates = [];
|
|
70
|
+
add(processor) {
|
|
71
|
+
this.delegates.push(processor);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Insert ahead of existing delegates, for a processor that must observe a span
|
|
75
|
+
* before the exporting processor queues it.
|
|
76
|
+
*
|
|
77
|
+
* Required by attribute-transforming processors: once a span is queued for
|
|
78
|
+
* export, later mutation is not guaranteed to be seen, and attributes a
|
|
79
|
+
* transform ADDS would bypass the masking applied in the exporter chain.
|
|
80
|
+
*/
|
|
81
|
+
addFirst(processor) {
|
|
82
|
+
this.delegates.unshift(processor);
|
|
83
|
+
}
|
|
84
|
+
onStart(span, parentContext) {
|
|
85
|
+
for (const delegate of this.delegates) delegate.onStart(span, parentContext);
|
|
86
|
+
}
|
|
87
|
+
onEnd(span) {
|
|
88
|
+
for (const delegate of this.delegates) delegate.onEnd(span);
|
|
89
|
+
}
|
|
90
|
+
async forceFlush() {
|
|
91
|
+
await Promise.allSettled(this.delegates.map((d) => d.forceFlush()));
|
|
92
|
+
}
|
|
93
|
+
async shutdown() {
|
|
94
|
+
await Promise.allSettled(this.delegates.map((d) => d.shutdown()));
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// node_modules/@opentelemetry/core/build/esm/ExportResult.js
|
|
101
|
+
var ExportResultCode;
|
|
102
|
+
var init_ExportResult = __esm({
|
|
103
|
+
"node_modules/@opentelemetry/core/build/esm/ExportResult.js"() {
|
|
104
|
+
"use strict";
|
|
105
|
+
(function(ExportResultCode2) {
|
|
106
|
+
ExportResultCode2[ExportResultCode2["SUCCESS"] = 0] = "SUCCESS";
|
|
107
|
+
ExportResultCode2[ExportResultCode2["FAILED"] = 1] = "FAILED";
|
|
108
|
+
})(ExportResultCode || (ExportResultCode = {}));
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// node_modules/@opentelemetry/core/build/esm/index.js
|
|
113
|
+
var init_esm = __esm({
|
|
114
|
+
"node_modules/@opentelemetry/core/build/esm/index.js"() {
|
|
115
|
+
"use strict";
|
|
116
|
+
init_ExportResult();
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// src/exportHealth.ts
|
|
121
|
+
var ExportOutcomeExporter;
|
|
122
|
+
var init_exportHealth = __esm({
|
|
123
|
+
"src/exportHealth.ts"() {
|
|
124
|
+
"use strict";
|
|
125
|
+
init_esm();
|
|
126
|
+
ExportOutcomeExporter = class {
|
|
127
|
+
constructor(inner, onFirstFailure = (m) => console.warn(m)) {
|
|
128
|
+
this.inner = inner;
|
|
129
|
+
this.onFirstFailure = onFirstFailure;
|
|
130
|
+
}
|
|
131
|
+
inner;
|
|
132
|
+
onFirstFailure;
|
|
133
|
+
failed = false;
|
|
134
|
+
warned = false;
|
|
135
|
+
get lastExportFailed() {
|
|
136
|
+
return this.failed;
|
|
137
|
+
}
|
|
138
|
+
export(spans, resultCallback) {
|
|
139
|
+
this.inner.export(spans, (result) => {
|
|
140
|
+
if (result.code === ExportResultCode.FAILED) {
|
|
141
|
+
this.failed = true;
|
|
142
|
+
if (!this.warned) {
|
|
143
|
+
this.warned = true;
|
|
144
|
+
try {
|
|
145
|
+
this.onFirstFailure(
|
|
146
|
+
`[rius] span export failed: ${result.error?.message ?? "unknown error"}. Check RIUS_API_KEY and RIUS_ENDPOINT. Further failures will not be logged.`
|
|
147
|
+
);
|
|
148
|
+
} catch {
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
this.failed = false;
|
|
153
|
+
}
|
|
154
|
+
resultCallback(result);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
shutdown() {
|
|
158
|
+
return this.inner.shutdown();
|
|
159
|
+
}
|
|
160
|
+
forceFlush() {
|
|
161
|
+
return this.inner.forceFlush?.() ?? Promise.resolve();
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// src/semconv.ts
|
|
168
|
+
function kindAttributes(kind) {
|
|
169
|
+
const attributes = { [OPENINFERENCE_SPAN_KIND]: kind };
|
|
170
|
+
const operation = OPERATION_BY_KIND[kind];
|
|
171
|
+
if (operation !== void 0) attributes[GEN_AI_OPERATION_NAME] = operation;
|
|
172
|
+
return attributes;
|
|
173
|
+
}
|
|
174
|
+
var TRACER_NAME, OPENINFERENCE_SPAN_KIND, INPUT_VALUE, OUTPUT_VALUE, GEN_AI_OPERATION_NAME, GEN_AI_PROVIDER_NAME, GEN_AI_REQUEST_MODEL, GEN_AI_RESPONSE_MODEL, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, GEN_AI_INPUT_MESSAGES, GEN_AI_OUTPUT_MESSAGES, GEN_AI_RESPONSE_FINISH_REASONS, GEN_AI_TOOL_NAME, GEN_AI_REQUEST_PREFIX, MCP_RESULT_TYPE, GEN_AI_FIRST_TOKEN_EVENT, SpanKind, OPERATION_BY_KIND, CONTENT_ATTRIBUTES, CONTENT_ATTRIBUTE_PREFIXES, CONTENT_ATTRIBUTE_SUFFIXES;
|
|
175
|
+
var init_semconv = __esm({
|
|
176
|
+
"src/semconv.ts"() {
|
|
177
|
+
"use strict";
|
|
178
|
+
TRACER_NAME = "glassflow";
|
|
179
|
+
OPENINFERENCE_SPAN_KIND = "openinference.span.kind";
|
|
180
|
+
INPUT_VALUE = "input.value";
|
|
181
|
+
OUTPUT_VALUE = "output.value";
|
|
182
|
+
GEN_AI_OPERATION_NAME = "gen_ai.operation.name";
|
|
183
|
+
GEN_AI_PROVIDER_NAME = "gen_ai.provider.name";
|
|
184
|
+
GEN_AI_REQUEST_MODEL = "gen_ai.request.model";
|
|
185
|
+
GEN_AI_RESPONSE_MODEL = "gen_ai.response.model";
|
|
186
|
+
GEN_AI_USAGE_INPUT_TOKENS = "gen_ai.usage.input_tokens";
|
|
187
|
+
GEN_AI_USAGE_OUTPUT_TOKENS = "gen_ai.usage.output_tokens";
|
|
188
|
+
GEN_AI_INPUT_MESSAGES = "gen_ai.input.messages";
|
|
189
|
+
GEN_AI_OUTPUT_MESSAGES = "gen_ai.output.messages";
|
|
190
|
+
GEN_AI_RESPONSE_FINISH_REASONS = "gen_ai.response.finish_reasons";
|
|
191
|
+
GEN_AI_TOOL_NAME = "gen_ai.tool.name";
|
|
192
|
+
GEN_AI_REQUEST_PREFIX = "gen_ai.request.";
|
|
193
|
+
MCP_RESULT_TYPE = "mcp.result_type";
|
|
194
|
+
GEN_AI_FIRST_TOKEN_EVENT = "gen_ai.first_token";
|
|
195
|
+
SpanKind = /* @__PURE__ */ ((SpanKind2) => {
|
|
196
|
+
SpanKind2["AGENT"] = "AGENT";
|
|
197
|
+
SpanKind2["LLM"] = "LLM";
|
|
198
|
+
SpanKind2["TOOL"] = "TOOL";
|
|
199
|
+
SpanKind2["RETRIEVER"] = "RETRIEVER";
|
|
200
|
+
SpanKind2["EMBEDDING"] = "EMBEDDING";
|
|
201
|
+
SpanKind2["CHAIN"] = "CHAIN";
|
|
202
|
+
return SpanKind2;
|
|
203
|
+
})(SpanKind || {});
|
|
204
|
+
OPERATION_BY_KIND = {
|
|
205
|
+
["LLM" /* LLM */]: "chat",
|
|
206
|
+
["TOOL" /* TOOL */]: "execute_tool",
|
|
207
|
+
["EMBEDDING" /* EMBEDDING */]: "embeddings",
|
|
208
|
+
["AGENT" /* AGENT */]: "invoke_agent"
|
|
209
|
+
};
|
|
210
|
+
CONTENT_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
211
|
+
INPUT_VALUE,
|
|
212
|
+
OUTPUT_VALUE,
|
|
213
|
+
GEN_AI_INPUT_MESSAGES,
|
|
214
|
+
GEN_AI_OUTPUT_MESSAGES,
|
|
215
|
+
"gen_ai.prompt",
|
|
216
|
+
"gen_ai.completion",
|
|
217
|
+
"llm.input_messages",
|
|
218
|
+
"llm.output_messages",
|
|
219
|
+
// The prefix list below covers the flattened "llm.prompts." and
|
|
220
|
+
// "llm.prompt_template." forms, but an instrumentation may emit either as a
|
|
221
|
+
// single unflattened array attribute under the bare key, which no prefix
|
|
222
|
+
// matches. Both bare keys are therefore listed here as well.
|
|
223
|
+
"llm.prompts",
|
|
224
|
+
"llm.prompt_template",
|
|
225
|
+
"mlflow.spanInputs",
|
|
226
|
+
"mlflow.spanOutputs",
|
|
227
|
+
"traceloop.entity.input",
|
|
228
|
+
"traceloop.entity.output"
|
|
229
|
+
]);
|
|
230
|
+
CONTENT_ATTRIBUTE_PREFIXES = [
|
|
231
|
+
"llm.input_messages.",
|
|
232
|
+
"llm.output_messages.",
|
|
233
|
+
"gen_ai.prompt.",
|
|
234
|
+
"gen_ai.completion.",
|
|
235
|
+
"llm.prompts.",
|
|
236
|
+
"llm.prompt_template."
|
|
237
|
+
];
|
|
238
|
+
CONTENT_ATTRIBUTE_SUFFIXES = [
|
|
239
|
+
".document.content",
|
|
240
|
+
".embedding.text"
|
|
241
|
+
];
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// src/serde.ts
|
|
246
|
+
function toAttributeValue(value) {
|
|
247
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
248
|
+
return value;
|
|
249
|
+
}
|
|
250
|
+
if (value === null || value === void 0) return "";
|
|
251
|
+
const ancestors = [];
|
|
252
|
+
try {
|
|
253
|
+
return JSON.stringify(value, function(_key, v) {
|
|
254
|
+
if (typeof v === "object" && v !== null) {
|
|
255
|
+
while (ancestors.length > 0 && ancestors[ancestors.length - 1] !== this) {
|
|
256
|
+
ancestors.pop();
|
|
257
|
+
}
|
|
258
|
+
if (ancestors.includes(v)) return "[Circular]";
|
|
259
|
+
ancestors.push(v);
|
|
260
|
+
}
|
|
261
|
+
return v;
|
|
262
|
+
}) ?? String(value);
|
|
263
|
+
} catch {
|
|
264
|
+
return "[unserializable]";
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
var init_serde = __esm({
|
|
268
|
+
"src/serde.ts"() {
|
|
269
|
+
"use strict";
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// src/spans.ts
|
|
274
|
+
function configure(observation, options) {
|
|
275
|
+
if (options.input !== void 0) observation.setInput(options.input);
|
|
276
|
+
return observation;
|
|
277
|
+
}
|
|
278
|
+
function startSpan(name, options = {}) {
|
|
279
|
+
const span = getTracer().startSpan(name, {
|
|
280
|
+
attributes: kindAttributes(options.kind ?? "CHAIN" /* CHAIN */)
|
|
281
|
+
});
|
|
282
|
+
return configure(new Observation(span), options);
|
|
283
|
+
}
|
|
284
|
+
function startAsCurrentSpan(name, optionsOrFn, maybeFn) {
|
|
285
|
+
const [options, fn] = typeof optionsOrFn === "function" ? [{}, optionsOrFn] : [optionsOrFn, maybeFn];
|
|
286
|
+
return getTracer().startActiveSpan(
|
|
287
|
+
name,
|
|
288
|
+
{ attributes: kindAttributes(options.kind ?? "CHAIN" /* CHAIN */) },
|
|
289
|
+
async (span) => {
|
|
290
|
+
const observation = configure(new Observation(span), options);
|
|
291
|
+
try {
|
|
292
|
+
return await fn(observation);
|
|
293
|
+
} catch (error) {
|
|
294
|
+
observation.recordException(error);
|
|
295
|
+
throw error;
|
|
296
|
+
} finally {
|
|
297
|
+
observation.end();
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
var import_api, Observation;
|
|
303
|
+
var init_spans = __esm({
|
|
304
|
+
"src/spans.ts"() {
|
|
305
|
+
"use strict";
|
|
306
|
+
import_api = require("@opentelemetry/api");
|
|
307
|
+
init_client();
|
|
308
|
+
init_semconv();
|
|
309
|
+
init_serde();
|
|
310
|
+
Observation = class {
|
|
311
|
+
constructor(span) {
|
|
312
|
+
this.span = span;
|
|
313
|
+
}
|
|
314
|
+
span;
|
|
315
|
+
ended = false;
|
|
316
|
+
setInput(value) {
|
|
317
|
+
this.span.setAttribute(INPUT_VALUE, toAttributeValue(value));
|
|
318
|
+
return this;
|
|
319
|
+
}
|
|
320
|
+
setOutput(value) {
|
|
321
|
+
this.span.setAttribute(OUTPUT_VALUE, toAttributeValue(value));
|
|
322
|
+
return this;
|
|
323
|
+
}
|
|
324
|
+
setAttribute(key, value) {
|
|
325
|
+
this.span.setAttribute(key, toAttributeValue(value));
|
|
326
|
+
return this;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Record an error on the span and set ERROR status. This is exactly what the
|
|
330
|
+
* `startAsCurrent*` helpers do on a thrown error, exposed so the manual
|
|
331
|
+
* `start*` path does not have to reach through `.span` to match it.
|
|
332
|
+
*
|
|
333
|
+
* Accepts `unknown` because that is what a `catch` binding is; a non-Error
|
|
334
|
+
* throwable is wrapped so `recordException` still gets a real Error.
|
|
335
|
+
*/
|
|
336
|
+
recordException(error) {
|
|
337
|
+
const wrapped = error instanceof Error ? error : new Error(String(error));
|
|
338
|
+
this.span.recordException(wrapped);
|
|
339
|
+
this.span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: wrapped.message });
|
|
340
|
+
return this;
|
|
341
|
+
}
|
|
342
|
+
end() {
|
|
343
|
+
if (this.ended) return;
|
|
344
|
+
this.ended = true;
|
|
345
|
+
this.span.end();
|
|
346
|
+
}
|
|
347
|
+
/** Lets callers write `using obs = startSpan(...)`. Sugar over end(). */
|
|
348
|
+
[Symbol.dispose]() {
|
|
349
|
+
this.end();
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
// src/instrumentationMcp.ts
|
|
356
|
+
var instrumentationMcp_exports = {};
|
|
357
|
+
__export(instrumentationMcp_exports, {
|
|
358
|
+
instrumentMcpClient: () => instrumentMcpClient
|
|
359
|
+
});
|
|
360
|
+
function recordResult(observation, result) {
|
|
361
|
+
const resultType = typeof result === "object" && result !== null ? result.result_type ?? result.resultType : void 0;
|
|
362
|
+
if (resultType === INPUT_REQUIRED) {
|
|
363
|
+
observation.setAttribute(MCP_RESULT_TYPE, INPUT_REQUIRED);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
observation.setOutput(result);
|
|
367
|
+
}
|
|
368
|
+
function instrumentMcpClient(ClientClass) {
|
|
369
|
+
const current = ClientClass.prototype.callTool;
|
|
370
|
+
const alreadyWrapped = current.riusOriginal;
|
|
371
|
+
if (alreadyWrapped !== void 0) {
|
|
372
|
+
return () => {
|
|
373
|
+
ClientClass.prototype.callTool = alreadyWrapped;
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
const original = ClientClass.prototype.callTool;
|
|
377
|
+
const instrumented = function instrumentedCallTool(params, ...rest) {
|
|
378
|
+
return startAsCurrentSpan(
|
|
379
|
+
params.name,
|
|
380
|
+
{ kind: "TOOL" /* TOOL */, input: params.arguments },
|
|
381
|
+
async (observation) => {
|
|
382
|
+
observation.setAttribute(GEN_AI_TOOL_NAME, params.name);
|
|
383
|
+
const result = await original.call(this, params, ...rest);
|
|
384
|
+
recordResult(observation, result);
|
|
385
|
+
return result;
|
|
386
|
+
}
|
|
387
|
+
);
|
|
388
|
+
};
|
|
389
|
+
instrumented.riusOriginal = original;
|
|
390
|
+
ClientClass.prototype.callTool = instrumented;
|
|
391
|
+
return () => {
|
|
392
|
+
ClientClass.prototype.callTool = original;
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
var INPUT_REQUIRED;
|
|
396
|
+
var init_instrumentationMcp = __esm({
|
|
397
|
+
"src/instrumentationMcp.ts"() {
|
|
398
|
+
"use strict";
|
|
399
|
+
init_semconv();
|
|
400
|
+
init_spans();
|
|
401
|
+
INPUT_REQUIRED = "input_required";
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
// src/instrumentation.ts
|
|
406
|
+
function packageOf(specifier) {
|
|
407
|
+
const segments = specifier.split("/");
|
|
408
|
+
const take = specifier.startsWith("@") ? 2 : 1;
|
|
409
|
+
return segments.slice(0, take).join("/");
|
|
410
|
+
}
|
|
411
|
+
function escapeRegExp(value) {
|
|
412
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
413
|
+
}
|
|
414
|
+
function isUnresolved(error, specifier) {
|
|
415
|
+
if (typeof error !== "object" || error === null) return false;
|
|
416
|
+
const message = error.message;
|
|
417
|
+
if (typeof message !== "string") return false;
|
|
418
|
+
const alternatives = [specifier, packageOf(specifier)].map(escapeRegExp).join("|");
|
|
419
|
+
return new RegExp(
|
|
420
|
+
`(?:cannot find (?:module|package)|could not resolve|failed to load url)\\s*['"\`]?(?:${alternatives})['"\`]?(?![\\w./@-])`,
|
|
421
|
+
"i"
|
|
422
|
+
).test(message);
|
|
423
|
+
}
|
|
424
|
+
async function optional(specifier) {
|
|
425
|
+
try {
|
|
426
|
+
return await dynamicImport(specifier);
|
|
427
|
+
} catch (error) {
|
|
428
|
+
if (isUnresolved(error, specifier)) return void 0;
|
|
429
|
+
if (error.code === "ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING") {
|
|
430
|
+
try {
|
|
431
|
+
return await import(specifier);
|
|
432
|
+
} catch (fallbackError) {
|
|
433
|
+
if (isUnresolved(fallbackError, specifier)) return void 0;
|
|
434
|
+
warnBroken(specifier, fallbackError);
|
|
435
|
+
return void 0;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
warnBroken(specifier, error);
|
|
439
|
+
return void 0;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
function warnBroken(subject, error) {
|
|
443
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
444
|
+
console.warn(`[rius] integration "${subject}" is installed but failed to load: ${message}`);
|
|
445
|
+
}
|
|
446
|
+
function cachedCjsExports(pkg, toPatchable) {
|
|
447
|
+
let cache;
|
|
448
|
+
try {
|
|
449
|
+
cache = (0, import_node_module.createRequire)((0, import_node_path.join)(process.cwd(), "noop.js")).cache;
|
|
450
|
+
} catch {
|
|
451
|
+
return void 0;
|
|
452
|
+
}
|
|
453
|
+
if (cache === void 0 || cache === null) return void 0;
|
|
454
|
+
const needle = `${import_node_path.sep}node_modules${import_node_path.sep}${pkg.split("/").join(import_node_path.sep)}${import_node_path.sep}`;
|
|
455
|
+
for (const key of Object.keys(cache)) {
|
|
456
|
+
if (!key.includes(needle)) continue;
|
|
457
|
+
const exports2 = cache[key]?.exports;
|
|
458
|
+
if (typeof exports2 !== "object" || exports2 === null) continue;
|
|
459
|
+
const patchable = toPatchable(exports2);
|
|
460
|
+
if (patchable !== void 0) return patchable;
|
|
461
|
+
}
|
|
462
|
+
return void 0;
|
|
463
|
+
}
|
|
464
|
+
async function patchActiveBuild(instrumentation, pkg, toPatchable) {
|
|
465
|
+
const cached = cachedCjsExports(pkg, toPatchable);
|
|
466
|
+
if (cached !== void 0) {
|
|
467
|
+
instrumentation.manuallyInstrument(cached);
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
const ns = await optional(pkg);
|
|
471
|
+
if (ns === void 0) return;
|
|
472
|
+
const patchable = toPatchable(ns);
|
|
473
|
+
if (patchable === void 0) {
|
|
474
|
+
warnBroken(pkg, new Error("unrecognised module shape, instrumentation not applied"));
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
instrumentation.manuallyInstrument(patchable);
|
|
478
|
+
}
|
|
479
|
+
function openaiPatchable(exports2) {
|
|
480
|
+
const cls = exports2.OpenAI ?? exports2.default;
|
|
481
|
+
return cls?.Chat?.Completions?.prototype?.create ? { OpenAI: cls } : void 0;
|
|
482
|
+
}
|
|
483
|
+
function anthropicPatchable(exports2) {
|
|
484
|
+
const cls = exports2.default ?? exports2.Anthropic;
|
|
485
|
+
return cls?.Messages?.prototype?.create ? { default: cls } : void 0;
|
|
486
|
+
}
|
|
487
|
+
function mcpClientPatchable(exports2) {
|
|
488
|
+
const cls = exports2.Client;
|
|
489
|
+
return typeof cls?.prototype?.callTool === "function" ? { Client: cls } : void 0;
|
|
490
|
+
}
|
|
491
|
+
async function enableInstrumentations(sink, tracerProvider, names) {
|
|
492
|
+
const wanted = names ? REGISTRY.filter((e) => names.includes(e.name)) : REGISTRY;
|
|
493
|
+
const enabled = [];
|
|
494
|
+
for (const entry of wanted) {
|
|
495
|
+
try {
|
|
496
|
+
const loaded = await entry.load();
|
|
497
|
+
if (loaded === void 0) continue;
|
|
498
|
+
if (entry.kind === "processor") {
|
|
499
|
+
if (entry.insert === "first") sink.addFirst(loaded);
|
|
500
|
+
else sink.add(loaded);
|
|
501
|
+
} else if (entry.kind === "instrumentation") {
|
|
502
|
+
(0, import_instrumentation.registerInstrumentations)({
|
|
503
|
+
instrumentations: [loaded],
|
|
504
|
+
tracerProvider
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
enabled.push(entry.name);
|
|
508
|
+
} catch (error) {
|
|
509
|
+
warnBroken(entry.name, error);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return enabled;
|
|
513
|
+
}
|
|
514
|
+
var import_node_module, import_node_path, import_instrumentation, dynamicImport, REGISTRY;
|
|
515
|
+
var init_instrumentation = __esm({
|
|
516
|
+
"src/instrumentation.ts"() {
|
|
517
|
+
"use strict";
|
|
518
|
+
import_node_module = require("module");
|
|
519
|
+
import_node_path = require("path");
|
|
520
|
+
import_instrumentation = require("@opentelemetry/instrumentation");
|
|
521
|
+
dynamicImport = new Function("s", "return import(s)");
|
|
522
|
+
REGISTRY = [
|
|
523
|
+
{
|
|
524
|
+
name: "vercel-ai",
|
|
525
|
+
kind: "processor",
|
|
526
|
+
// The transform can ADD content attributes such as input.value. Masking
|
|
527
|
+
// runs in the exporter chain, which executes after a span is queued, so the
|
|
528
|
+
// transform has to run before the exporting processor sees the span or the
|
|
529
|
+
// attributes it added would never be sanitised.
|
|
530
|
+
insert: "first",
|
|
531
|
+
async load() {
|
|
532
|
+
const utils = await optional("@arizeai/openinference-vercel/utils");
|
|
533
|
+
const add = utils?.addOpenInferenceAttributesToSpan;
|
|
534
|
+
if (add === void 0) return void 0;
|
|
535
|
+
return {
|
|
536
|
+
onStart() {
|
|
537
|
+
},
|
|
538
|
+
onEnd(span) {
|
|
539
|
+
add(span);
|
|
540
|
+
},
|
|
541
|
+
async forceFlush() {
|
|
542
|
+
},
|
|
543
|
+
async shutdown() {
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
name: "openai",
|
|
550
|
+
kind: "instrumentation",
|
|
551
|
+
async load() {
|
|
552
|
+
const mod = await optional("@arizeai/openinference-instrumentation-openai");
|
|
553
|
+
const Ctor = mod?.OpenAIInstrumentation;
|
|
554
|
+
if (Ctor === void 0) return void 0;
|
|
555
|
+
const instrumentation = new Ctor();
|
|
556
|
+
await patchActiveBuild(instrumentation, "openai", openaiPatchable);
|
|
557
|
+
return instrumentation;
|
|
558
|
+
}
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
name: "anthropic",
|
|
562
|
+
kind: "instrumentation",
|
|
563
|
+
async load() {
|
|
564
|
+
const mod = await optional("@arizeai/openinference-instrumentation-anthropic");
|
|
565
|
+
const Ctor = mod?.AnthropicInstrumentation;
|
|
566
|
+
if (Ctor === void 0) return void 0;
|
|
567
|
+
const instrumentation = new Ctor();
|
|
568
|
+
await patchActiveBuild(instrumentation, "@anthropic-ai/sdk", anthropicPatchable);
|
|
569
|
+
return instrumentation;
|
|
570
|
+
}
|
|
571
|
+
},
|
|
572
|
+
{
|
|
573
|
+
name: "langchain",
|
|
574
|
+
kind: "instrumentation",
|
|
575
|
+
async load() {
|
|
576
|
+
const mod = await optional("@arizeai/openinference-instrumentation-langchain");
|
|
577
|
+
const Ctor = mod?.LangChainInstrumentation;
|
|
578
|
+
if (Ctor === void 0) return void 0;
|
|
579
|
+
const callbacks = await optional("@langchain/core/callbacks/manager");
|
|
580
|
+
if (callbacks?.CallbackManager === void 0) return void 0;
|
|
581
|
+
const instrumentation = new Ctor();
|
|
582
|
+
instrumentation.manuallyInstrument(callbacks);
|
|
583
|
+
return instrumentation;
|
|
584
|
+
}
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
name: "mcp",
|
|
588
|
+
kind: "self-applying",
|
|
589
|
+
async load() {
|
|
590
|
+
const mod = await optional("@modelcontextprotocol/sdk/client/index.js");
|
|
591
|
+
const ClientClass = mod?.Client;
|
|
592
|
+
if (ClientClass === void 0) return void 0;
|
|
593
|
+
const { instrumentMcpClient: instrumentMcpClient2 } = await Promise.resolve().then(() => (init_instrumentationMcp(), instrumentationMcp_exports));
|
|
594
|
+
instrumentMcpClient2(ClientClass);
|
|
595
|
+
const cjs = cachedCjsExports("@modelcontextprotocol/sdk", mcpClientPatchable);
|
|
596
|
+
if (cjs !== void 0) instrumentMcpClient2(cjs.Client);
|
|
597
|
+
return true;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
];
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
// src/masking.ts
|
|
605
|
+
function isContentKey(key) {
|
|
606
|
+
if (CONTENT_ATTRIBUTES.has(key)) return true;
|
|
607
|
+
if (CONTENT_ATTRIBUTE_PREFIXES.some((p) => key.startsWith(p))) return true;
|
|
608
|
+
return CONTENT_ATTRIBUTE_SUFFIXES.some((s) => key.endsWith(s));
|
|
609
|
+
}
|
|
610
|
+
var import_api2, EXCEPTION_EVENT_NAME, EXCEPTION_CONTENT_KEYS, MaskingSpanExporter;
|
|
611
|
+
var init_masking = __esm({
|
|
612
|
+
"src/masking.ts"() {
|
|
613
|
+
"use strict";
|
|
614
|
+
import_api2 = require("@opentelemetry/api");
|
|
615
|
+
init_semconv();
|
|
616
|
+
init_serde();
|
|
617
|
+
EXCEPTION_EVENT_NAME = "exception";
|
|
618
|
+
EXCEPTION_CONTENT_KEYS = ["exception.message", "exception.stacktrace"];
|
|
619
|
+
MaskingSpanExporter = class {
|
|
620
|
+
constructor(inner, opts) {
|
|
621
|
+
this.inner = inner;
|
|
622
|
+
this.opts = opts;
|
|
623
|
+
}
|
|
624
|
+
inner;
|
|
625
|
+
opts;
|
|
626
|
+
export(spans, resultCallback) {
|
|
627
|
+
this.inner.export(
|
|
628
|
+
spans.map((s) => this.sanitized(s)),
|
|
629
|
+
resultCallback
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
sanitized(span) {
|
|
633
|
+
this.sanitizeAttributes(span.attributes);
|
|
634
|
+
for (const event of span.events ?? []) {
|
|
635
|
+
const attributes = event.attributes;
|
|
636
|
+
this.sanitizeAttributes(attributes);
|
|
637
|
+
if (this.opts.captureContent || attributes === void 0) continue;
|
|
638
|
+
if (event.name !== EXCEPTION_EVENT_NAME) continue;
|
|
639
|
+
for (const key of EXCEPTION_CONTENT_KEYS) delete attributes[key];
|
|
640
|
+
}
|
|
641
|
+
for (const link of span.links ?? []) {
|
|
642
|
+
this.sanitizeAttributes(link.attributes);
|
|
643
|
+
}
|
|
644
|
+
if (!this.opts.captureContent && span.status?.code === import_api2.SpanStatusCode.ERROR) {
|
|
645
|
+
span.status.message = void 0;
|
|
646
|
+
}
|
|
647
|
+
return span;
|
|
648
|
+
}
|
|
649
|
+
/** Strips or masks the content keys of one attribute bag, in place. */
|
|
650
|
+
sanitizeAttributes(attributes) {
|
|
651
|
+
if (attributes === void 0) return;
|
|
652
|
+
for (const key of Object.keys(attributes)) {
|
|
653
|
+
if (!isContentKey(key)) continue;
|
|
654
|
+
if (!this.opts.captureContent) {
|
|
655
|
+
delete attributes[key];
|
|
656
|
+
continue;
|
|
657
|
+
}
|
|
658
|
+
if (this.opts.mask === void 0) continue;
|
|
659
|
+
try {
|
|
660
|
+
attributes[key] = toAttributeValue(this.opts.mask(attributes[key], { key }));
|
|
661
|
+
} catch {
|
|
662
|
+
attributes[key] = "[mask error]";
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
shutdown() {
|
|
667
|
+
return this.inner.shutdown();
|
|
668
|
+
}
|
|
669
|
+
forceFlush() {
|
|
670
|
+
return this.inner.forceFlush?.() ?? Promise.resolve();
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
// src/client.ts
|
|
677
|
+
function init(options = {}) {
|
|
678
|
+
if (globalClient !== void 0) {
|
|
679
|
+
console.warn(
|
|
680
|
+
"[rius] init() called twice; returning the existing client. Call shutdown() first to reconfigure."
|
|
681
|
+
);
|
|
682
|
+
return globalClient;
|
|
683
|
+
}
|
|
684
|
+
const config = resolveConfig(options);
|
|
685
|
+
const processors = new DelegatingSpanProcessor();
|
|
686
|
+
let health;
|
|
687
|
+
if (!config.disabled) {
|
|
688
|
+
const base = options.spanExporter ?? new import_exporter_trace_otlp_http.OTLPTraceExporter({
|
|
689
|
+
url: `${config.endpoint}/v1/traces`,
|
|
690
|
+
headers: config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : void 0
|
|
691
|
+
});
|
|
692
|
+
health = new ExportOutcomeExporter(base);
|
|
693
|
+
const exporter = !config.captureContent || config.mask !== void 0 ? new MaskingSpanExporter(health, {
|
|
694
|
+
captureContent: config.captureContent,
|
|
695
|
+
mask: config.mask
|
|
696
|
+
}) : health;
|
|
697
|
+
processors.add(new import_sdk_trace_base.BatchSpanProcessor(exporter));
|
|
698
|
+
}
|
|
699
|
+
const provider = new import_sdk_trace_node.NodeTracerProvider({
|
|
700
|
+
resource: (0, import_resources.resourceFromAttributes)({ [import_semantic_conventions.ATTR_SERVICE_NAME]: config.serviceName }),
|
|
701
|
+
// Always ParentBased, with no AlwaysOn shortcut at rate 1. They are not
|
|
702
|
+
// equivalent: ParentBased honours a remote UNSAMPLED parent and drops,
|
|
703
|
+
// while AlwaysOn records regardless, producing children of a span the
|
|
704
|
+
// upstream service dropped. Rate 1 is the default, so the shortcut would
|
|
705
|
+
// have been the default path for every user.
|
|
706
|
+
sampler: new import_sdk_trace_base.ParentBasedSampler({ root: new import_sdk_trace_base.TraceIdRatioBasedSampler(config.sampleRate) }),
|
|
707
|
+
spanProcessors: [processors]
|
|
708
|
+
});
|
|
709
|
+
const ready = config.disabled ? Promise.resolve([]) : enableInstrumentations(processors, provider).catch(() => []);
|
|
710
|
+
provider.register();
|
|
711
|
+
globalClient = createClient({ provider, processors, health, ready });
|
|
712
|
+
return globalClient;
|
|
713
|
+
}
|
|
714
|
+
function getTracer() {
|
|
715
|
+
return import_api3.trace.getTracer(TRACER_NAME);
|
|
716
|
+
}
|
|
717
|
+
var import_api3, import_exporter_trace_otlp_http, import_resources, import_sdk_trace_base, import_sdk_trace_node, import_semantic_conventions, sinks, createClient, RiusClient, globalClient;
|
|
718
|
+
var init_client = __esm({
|
|
719
|
+
"src/client.ts"() {
|
|
720
|
+
"use strict";
|
|
721
|
+
import_api3 = require("@opentelemetry/api");
|
|
722
|
+
import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
|
|
723
|
+
import_resources = require("@opentelemetry/resources");
|
|
724
|
+
import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
|
|
725
|
+
import_sdk_trace_node = require("@opentelemetry/sdk-trace-node");
|
|
726
|
+
import_semantic_conventions = require("@opentelemetry/semantic-conventions");
|
|
727
|
+
init_config();
|
|
728
|
+
init_delegatingProcessor();
|
|
729
|
+
init_exportHealth();
|
|
730
|
+
init_instrumentation();
|
|
731
|
+
init_masking();
|
|
732
|
+
init_semconv();
|
|
733
|
+
sinks = /* @__PURE__ */ new WeakMap();
|
|
734
|
+
RiusClient = class _RiusClient {
|
|
735
|
+
provider;
|
|
736
|
+
health;
|
|
737
|
+
/** Resolves with the names of the auto-instrumentations that attached. */
|
|
738
|
+
ready;
|
|
739
|
+
constructor(parts) {
|
|
740
|
+
this.provider = parts.provider;
|
|
741
|
+
this.health = parts.health;
|
|
742
|
+
this.ready = parts.ready;
|
|
743
|
+
sinks.set(this, parts.processors);
|
|
744
|
+
}
|
|
745
|
+
static {
|
|
746
|
+
createClient = (parts) => new _RiusClient(parts);
|
|
747
|
+
}
|
|
748
|
+
/** Drains the queue. Resolves false if the most recent export failed. */
|
|
749
|
+
async flush() {
|
|
750
|
+
await this.provider.forceFlush();
|
|
751
|
+
return this.health?.lastExportFailed !== true;
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Drains and tears down the provider, then releases the global registration
|
|
755
|
+
* so a later init() can reconfigure the SDK.
|
|
756
|
+
*/
|
|
757
|
+
async shutdown() {
|
|
758
|
+
try {
|
|
759
|
+
await this.provider.shutdown();
|
|
760
|
+
} finally {
|
|
761
|
+
if (globalClient === this) {
|
|
762
|
+
globalClient = void 0;
|
|
763
|
+
import_api3.trace.disable();
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
// src/index.ts
|
|
772
|
+
var index_exports = {};
|
|
773
|
+
__export(index_exports, {
|
|
774
|
+
Generation: () => Generation,
|
|
775
|
+
Observation: () => Observation,
|
|
776
|
+
RiusClient: () => RiusClient,
|
|
777
|
+
SpanKind: () => SpanKind,
|
|
778
|
+
VERSION: () => VERSION,
|
|
779
|
+
getTracer: () => getTracer,
|
|
780
|
+
init: () => init,
|
|
781
|
+
observe: () => observe,
|
|
782
|
+
startAsCurrentGeneration: () => startAsCurrentGeneration,
|
|
783
|
+
startAsCurrentSpan: () => startAsCurrentSpan,
|
|
784
|
+
startGeneration: () => startGeneration,
|
|
785
|
+
startSpan: () => startSpan
|
|
786
|
+
});
|
|
787
|
+
module.exports = __toCommonJS(index_exports);
|
|
788
|
+
init_client();
|
|
789
|
+
|
|
790
|
+
// src/generation.ts
|
|
791
|
+
init_client();
|
|
792
|
+
init_semconv();
|
|
793
|
+
init_serde();
|
|
794
|
+
init_spans();
|
|
795
|
+
var Generation = class extends Observation {
|
|
796
|
+
firstTokenRecorded = false;
|
|
797
|
+
setInput(value) {
|
|
798
|
+
this.span.setAttribute(GEN_AI_INPUT_MESSAGES, toAttributeValue(value));
|
|
799
|
+
return this;
|
|
800
|
+
}
|
|
801
|
+
setOutput(value) {
|
|
802
|
+
this.span.setAttribute(GEN_AI_OUTPUT_MESSAGES, toAttributeValue(value));
|
|
803
|
+
return this;
|
|
804
|
+
}
|
|
805
|
+
setModel(model) {
|
|
806
|
+
this.span.setAttribute(GEN_AI_RESPONSE_MODEL, model);
|
|
807
|
+
return this;
|
|
808
|
+
}
|
|
809
|
+
setUsage(usage) {
|
|
810
|
+
if (usage.inputTokens !== void 0) {
|
|
811
|
+
this.span.setAttribute(GEN_AI_USAGE_INPUT_TOKENS, usage.inputTokens);
|
|
812
|
+
}
|
|
813
|
+
if (usage.outputTokens !== void 0) {
|
|
814
|
+
this.span.setAttribute(GEN_AI_USAGE_OUTPUT_TOKENS, usage.outputTokens);
|
|
815
|
+
}
|
|
816
|
+
return this;
|
|
817
|
+
}
|
|
818
|
+
/**
|
|
819
|
+
* Why generation stopped (`gen_ai.response.finish_reasons`), e.g. `"stop"`,
|
|
820
|
+
* `"length"`, `"tool_calls"`. The convention is a list; a single reason is
|
|
821
|
+
* wrapped so callers do not have to.
|
|
822
|
+
*/
|
|
823
|
+
setFinishReasons(reasons) {
|
|
824
|
+
this.span.setAttribute(
|
|
825
|
+
GEN_AI_RESPONSE_FINISH_REASONS,
|
|
826
|
+
typeof reasons === "string" ? [reasons] : reasons
|
|
827
|
+
);
|
|
828
|
+
return this;
|
|
829
|
+
}
|
|
830
|
+
/**
|
|
831
|
+
* The TTFT anchor: event time minus span start. Idempotent: only the
|
|
832
|
+
* first call records the event, so a streaming loop can call this
|
|
833
|
+
* unconditionally on every chunk without inflating the span. A no-op
|
|
834
|
+
* after the span has ended.
|
|
835
|
+
*/
|
|
836
|
+
recordFirstToken() {
|
|
837
|
+
if (this.firstTokenRecorded || !this.span.isRecording()) {
|
|
838
|
+
return this;
|
|
839
|
+
}
|
|
840
|
+
this.span.addEvent(GEN_AI_FIRST_TOKEN_EVENT);
|
|
841
|
+
this.firstTokenRecorded = true;
|
|
842
|
+
return this;
|
|
843
|
+
}
|
|
844
|
+
};
|
|
845
|
+
function attributesFor(options) {
|
|
846
|
+
const attributes = { ...kindAttributes("LLM" /* LLM */) };
|
|
847
|
+
if (options.model !== void 0) attributes[GEN_AI_REQUEST_MODEL] = options.model;
|
|
848
|
+
if (options.provider !== void 0) attributes[GEN_AI_PROVIDER_NAME] = options.provider;
|
|
849
|
+
return attributes;
|
|
850
|
+
}
|
|
851
|
+
function configure2(generation, options) {
|
|
852
|
+
for (const [key, value] of Object.entries(options.modelParameters ?? {})) {
|
|
853
|
+
generation.setAttribute(`${GEN_AI_REQUEST_PREFIX}${key}`, value);
|
|
854
|
+
}
|
|
855
|
+
if (options.input !== void 0) generation.setInput(options.input);
|
|
856
|
+
return generation;
|
|
857
|
+
}
|
|
858
|
+
function startGeneration(name, options = {}) {
|
|
859
|
+
const span = getTracer().startSpan(name, { attributes: attributesFor(options) });
|
|
860
|
+
return configure2(new Generation(span), options);
|
|
861
|
+
}
|
|
862
|
+
function startAsCurrentGeneration(name, optionsOrFn, maybeFn) {
|
|
863
|
+
const [options, fn] = typeof optionsOrFn === "function" ? [{}, optionsOrFn] : [optionsOrFn, maybeFn];
|
|
864
|
+
return getTracer().startActiveSpan(name, { attributes: attributesFor(options) }, async (span) => {
|
|
865
|
+
const generation = configure2(new Generation(span), options);
|
|
866
|
+
try {
|
|
867
|
+
return await fn(generation);
|
|
868
|
+
} catch (error) {
|
|
869
|
+
generation.recordException(error);
|
|
870
|
+
throw error;
|
|
871
|
+
} finally {
|
|
872
|
+
generation.end();
|
|
873
|
+
}
|
|
874
|
+
});
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
// src/observe.ts
|
|
878
|
+
init_spans();
|
|
879
|
+
function observe(fn, options = {}) {
|
|
880
|
+
const name = options.name ?? (fn.name || "anonymous");
|
|
881
|
+
const captureInput = options.captureInput ?? true;
|
|
882
|
+
const captureOutput = options.captureOutput ?? true;
|
|
883
|
+
const wrapped = (...args) => startAsCurrentSpan(
|
|
884
|
+
name,
|
|
885
|
+
{ kind: options.kind, input: captureInput ? args : void 0 },
|
|
886
|
+
async (observation) => {
|
|
887
|
+
const result = await fn(...args);
|
|
888
|
+
if (captureOutput && result !== void 0) observation.setOutput(result);
|
|
889
|
+
return result;
|
|
890
|
+
}
|
|
891
|
+
);
|
|
892
|
+
Object.defineProperty(wrapped, "name", { value: name, configurable: true });
|
|
893
|
+
return wrapped;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
// src/index.ts
|
|
897
|
+
init_semconv();
|
|
898
|
+
init_spans();
|
|
899
|
+
var VERSION = "0.1.0";
|
|
900
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
901
|
+
0 && (module.exports = {
|
|
902
|
+
Generation,
|
|
903
|
+
Observation,
|
|
904
|
+
RiusClient,
|
|
905
|
+
SpanKind,
|
|
906
|
+
VERSION,
|
|
907
|
+
getTracer,
|
|
908
|
+
init,
|
|
909
|
+
observe,
|
|
910
|
+
startAsCurrentGeneration,
|
|
911
|
+
startAsCurrentSpan,
|
|
912
|
+
startGeneration,
|
|
913
|
+
startSpan
|
|
914
|
+
});
|