@glassflow-ai/rius 0.2.4 → 0.3.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/dist/index.cjs +68 -15
- package/dist/index.d.cts +32 -2
- package/dist/index.d.ts +32 -2
- package/dist/index.js +61 -9
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -89,7 +89,10 @@ function resolveConfig(options = {}, env = process.env) {
|
|
|
89
89
|
// on every heartbeat payload, so `??` would be wrong here.
|
|
90
90
|
agentName: options.agentName || env.RIUS_AGENT_NAME || serviceName,
|
|
91
91
|
partialSpans: options.partialSpans ?? bool("RIUS_PARTIAL_SPANS", env.RIUS_PARTIAL_SPANS, false),
|
|
92
|
-
partialSpansDelayMs: partialSpansDelaySeconds * 1e3
|
|
92
|
+
partialSpansDelayMs: partialSpansDelaySeconds * 1e3,
|
|
93
|
+
// Empty is unset, like agentName: a blank session id would group every
|
|
94
|
+
// span under the meaningless session "".
|
|
95
|
+
sessionId: options.sessionId || env.RIUS_SESSION_ID || void 0
|
|
93
96
|
};
|
|
94
97
|
}
|
|
95
98
|
var DEFAULT_ENDPOINT, DEFAULT_SERVICE_NAME, HEARTBEAT_INTERVAL_MIN, HEARTBEAT_INTERVAL_MAX, DEFAULT_HEARTBEAT_INTERVAL, PARTIAL_SPANS_DELAY_MIN, PARTIAL_SPANS_DELAY_MAX, DEFAULT_PARTIAL_SPANS_DELAY, AFFIRMATIVE, NEGATIVE;
|
|
@@ -234,12 +237,11 @@ function httpTransport(url, headers) {
|
|
|
234
237
|
}
|
|
235
238
|
};
|
|
236
239
|
}
|
|
237
|
-
var
|
|
240
|
+
var import_node_module, PAYLOAD_VERSION, OPEN_TRACES_CAP, DEFAULT_PING_TIMEOUT_MS, DEFAULT_FINAL_PING_TIMEOUT_MS, SDK_VERSION, OpenRootSpanTracker, HeartbeatSender;
|
|
238
241
|
var init_heartbeat = __esm({
|
|
239
242
|
"src/heartbeat.ts"() {
|
|
240
243
|
"use strict";
|
|
241
244
|
init_cjs_shims();
|
|
242
|
-
import_node_crypto = require("crypto");
|
|
243
245
|
import_node_module = require("module");
|
|
244
246
|
PAYLOAD_VERSION = 1;
|
|
245
247
|
OPEN_TRACES_CAP = 32;
|
|
@@ -282,8 +284,8 @@ var init_heartbeat = __esm({
|
|
|
282
284
|
}
|
|
283
285
|
};
|
|
284
286
|
HeartbeatSender = class {
|
|
285
|
-
/** Identity of one process lifetime,
|
|
286
|
-
instanceId
|
|
287
|
+
/** Identity of one process lifetime; injected, shared with span resources. */
|
|
288
|
+
instanceId;
|
|
287
289
|
agentName;
|
|
288
290
|
tracker;
|
|
289
291
|
intervalMs;
|
|
@@ -294,6 +296,7 @@ var init_heartbeat = __esm({
|
|
|
294
296
|
stopped = false;
|
|
295
297
|
deliveryWarned = false;
|
|
296
298
|
constructor(opts) {
|
|
299
|
+
this.instanceId = opts.instanceId;
|
|
297
300
|
this.agentName = opts.agentName;
|
|
298
301
|
this.tracker = opts.tracker;
|
|
299
302
|
this.intervalMs = opts.intervalMs;
|
|
@@ -353,15 +356,17 @@ function kindAttributes(kind) {
|
|
|
353
356
|
if (operation !== void 0) attributes[GEN_AI_OPERATION_NAME] = operation;
|
|
354
357
|
return attributes;
|
|
355
358
|
}
|
|
356
|
-
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, GLASSFLOW_SPAN_PENDING, PENDING_IDENTITY_ATTRIBUTES, PENDING_IDENTITY_PREFIXES;
|
|
359
|
+
var TRACER_NAME, SERVICE_INSTANCE_ID, OPENINFERENCE_SPAN_KIND, INPUT_VALUE, OUTPUT_VALUE, SESSION_ID, 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, GLASSFLOW_SPAN_PENDING, PENDING_IDENTITY_ATTRIBUTES, PENDING_IDENTITY_PREFIXES;
|
|
357
360
|
var init_semconv = __esm({
|
|
358
361
|
"src/semconv.ts"() {
|
|
359
362
|
"use strict";
|
|
360
363
|
init_cjs_shims();
|
|
361
364
|
TRACER_NAME = "glassflow";
|
|
365
|
+
SERVICE_INSTANCE_ID = "service.instance.id";
|
|
362
366
|
OPENINFERENCE_SPAN_KIND = "openinference.span.kind";
|
|
363
367
|
INPUT_VALUE = "input.value";
|
|
364
368
|
OUTPUT_VALUE = "output.value";
|
|
369
|
+
SESSION_ID = "session.id";
|
|
365
370
|
GEN_AI_OPERATION_NAME = "gen_ai.operation.name";
|
|
366
371
|
GEN_AI_PROVIDER_NAME = "gen_ai.provider.name";
|
|
367
372
|
GEN_AI_REQUEST_MODEL = "gen_ai.request.model";
|
|
@@ -427,7 +432,10 @@ var init_semconv = __esm({
|
|
|
427
432
|
OPENINFERENCE_SPAN_KIND,
|
|
428
433
|
GEN_AI_OPERATION_NAME,
|
|
429
434
|
GEN_AI_PROVIDER_NAME,
|
|
430
|
-
GEN_AI_TOOL_NAME
|
|
435
|
+
GEN_AI_TOOL_NAME,
|
|
436
|
+
// Identity, not content: a pending span must be groupable into its
|
|
437
|
+
// session while still running, that is the live view's whole point.
|
|
438
|
+
SESSION_ID
|
|
431
439
|
]);
|
|
432
440
|
PENDING_IDENTITY_PREFIXES = [GEN_AI_REQUEST_PREFIX];
|
|
433
441
|
}
|
|
@@ -968,6 +976,40 @@ var init_pending = __esm({
|
|
|
968
976
|
}
|
|
969
977
|
});
|
|
970
978
|
|
|
979
|
+
// src/session.ts
|
|
980
|
+
function withSession(sessionIdOrFn, maybeFn) {
|
|
981
|
+
const [sessionId, fn] = typeof sessionIdOrFn === "function" ? [(0, import_node_crypto.randomUUID)(), sessionIdOrFn] : [sessionIdOrFn, maybeFn];
|
|
982
|
+
return import_api5.context.with(import_api5.context.active().setValue(SESSION_KEY, sessionId), () => fn(sessionId));
|
|
983
|
+
}
|
|
984
|
+
var import_node_crypto, import_api5, SESSION_KEY, SessionSpanProcessor;
|
|
985
|
+
var init_session = __esm({
|
|
986
|
+
"src/session.ts"() {
|
|
987
|
+
"use strict";
|
|
988
|
+
init_cjs_shims();
|
|
989
|
+
import_node_crypto = require("crypto");
|
|
990
|
+
import_api5 = require("@opentelemetry/api");
|
|
991
|
+
init_semconv();
|
|
992
|
+
SESSION_KEY = (0, import_api5.createContextKey)("rius-session-id");
|
|
993
|
+
SessionSpanProcessor = class {
|
|
994
|
+
constructor(defaultSessionId) {
|
|
995
|
+
this.defaultSessionId = defaultSessionId;
|
|
996
|
+
}
|
|
997
|
+
defaultSessionId;
|
|
998
|
+
onStart(span, parentContext) {
|
|
999
|
+
const value = parentContext.getValue(SESSION_KEY);
|
|
1000
|
+
const sessionId = typeof value === "string" ? value : this.defaultSessionId;
|
|
1001
|
+
if (sessionId !== void 0) span.setAttribute(SESSION_ID, sessionId);
|
|
1002
|
+
}
|
|
1003
|
+
onEnd(_span) {
|
|
1004
|
+
}
|
|
1005
|
+
async forceFlush() {
|
|
1006
|
+
}
|
|
1007
|
+
async shutdown() {
|
|
1008
|
+
}
|
|
1009
|
+
};
|
|
1010
|
+
}
|
|
1011
|
+
});
|
|
1012
|
+
|
|
971
1013
|
// src/client.ts
|
|
972
1014
|
function init(options = {}) {
|
|
973
1015
|
if (globalClient !== void 0) {
|
|
@@ -991,13 +1033,18 @@ function init(options = {}) {
|
|
|
991
1033
|
mask: config.mask
|
|
992
1034
|
}) : health;
|
|
993
1035
|
const batch = new import_sdk_trace_base.BatchSpanProcessor(exporter);
|
|
1036
|
+
processors.add(new SessionSpanProcessor(config.sessionId));
|
|
994
1037
|
if (config.partialSpans) {
|
|
995
1038
|
processors.add(new PendingSpanProcessor(batch, { delayMs: config.partialSpansDelayMs }));
|
|
996
1039
|
}
|
|
997
1040
|
processors.add(batch);
|
|
998
1041
|
}
|
|
1042
|
+
const instanceId = (0, import_node_crypto2.randomUUID)();
|
|
999
1043
|
const provider = new import_sdk_trace_node.NodeTracerProvider({
|
|
1000
|
-
resource: (0, import_resources.resourceFromAttributes)({
|
|
1044
|
+
resource: (0, import_resources.resourceFromAttributes)({
|
|
1045
|
+
[import_semantic_conventions.ATTR_SERVICE_NAME]: config.serviceName,
|
|
1046
|
+
[SERVICE_INSTANCE_ID]: instanceId
|
|
1047
|
+
}),
|
|
1001
1048
|
// Always ParentBased, with no AlwaysOn shortcut at rate 1. They are not
|
|
1002
1049
|
// equivalent: ParentBased honours a remote UNSAMPLED parent and drops,
|
|
1003
1050
|
// while AlwaysOn records regardless, producing children of a span the
|
|
@@ -1017,6 +1064,7 @@ function init(options = {}) {
|
|
|
1017
1064
|
headers: authHeaders,
|
|
1018
1065
|
intervalMs: config.heartbeatIntervalMs,
|
|
1019
1066
|
agentName: config.agentName,
|
|
1067
|
+
instanceId,
|
|
1020
1068
|
tracker,
|
|
1021
1069
|
transport: options.heartbeatTransport
|
|
1022
1070
|
});
|
|
@@ -1031,14 +1079,15 @@ function init(options = {}) {
|
|
|
1031
1079
|
return globalClient;
|
|
1032
1080
|
}
|
|
1033
1081
|
function getTracer() {
|
|
1034
|
-
return
|
|
1082
|
+
return import_api6.trace.getTracer(TRACER_NAME);
|
|
1035
1083
|
}
|
|
1036
|
-
var
|
|
1084
|
+
var import_node_crypto2, import_api6, import_exporter_trace_otlp_proto, import_resources, import_sdk_trace_base, import_sdk_trace_node, import_semantic_conventions, sinks, heartbeats, createClient, RiusClient, globalClient;
|
|
1037
1085
|
var init_client = __esm({
|
|
1038
1086
|
"src/client.ts"() {
|
|
1039
1087
|
"use strict";
|
|
1040
1088
|
init_cjs_shims();
|
|
1041
|
-
|
|
1089
|
+
import_node_crypto2 = require("crypto");
|
|
1090
|
+
import_api6 = require("@opentelemetry/api");
|
|
1042
1091
|
import_exporter_trace_otlp_proto = require("@opentelemetry/exporter-trace-otlp-proto");
|
|
1043
1092
|
import_resources = require("@opentelemetry/resources");
|
|
1044
1093
|
import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
|
|
@@ -1052,6 +1101,7 @@ var init_client = __esm({
|
|
|
1052
1101
|
init_masking();
|
|
1053
1102
|
init_pending();
|
|
1054
1103
|
init_semconv();
|
|
1104
|
+
init_session();
|
|
1055
1105
|
sinks = /* @__PURE__ */ new WeakMap();
|
|
1056
1106
|
heartbeats = /* @__PURE__ */ new WeakMap();
|
|
1057
1107
|
RiusClient = class _RiusClient {
|
|
@@ -1095,7 +1145,7 @@ var init_client = __esm({
|
|
|
1095
1145
|
} finally {
|
|
1096
1146
|
if (globalClient === this) {
|
|
1097
1147
|
globalClient = void 0;
|
|
1098
|
-
|
|
1148
|
+
import_api6.trace.disable();
|
|
1099
1149
|
}
|
|
1100
1150
|
}
|
|
1101
1151
|
}
|
|
@@ -1117,7 +1167,8 @@ __export(index_exports, {
|
|
|
1117
1167
|
startAsCurrentGeneration: () => startAsCurrentGeneration,
|
|
1118
1168
|
startAsCurrentSpan: () => startAsCurrentSpan,
|
|
1119
1169
|
startGeneration: () => startGeneration,
|
|
1120
|
-
startSpan: () => startSpan
|
|
1170
|
+
startSpan: () => startSpan,
|
|
1171
|
+
withSession: () => withSession
|
|
1121
1172
|
});
|
|
1122
1173
|
module.exports = __toCommonJS(index_exports);
|
|
1123
1174
|
init_cjs_shims();
|
|
@@ -1233,8 +1284,9 @@ function observe(fn, options = {}) {
|
|
|
1233
1284
|
|
|
1234
1285
|
// src/index.ts
|
|
1235
1286
|
init_semconv();
|
|
1287
|
+
init_session();
|
|
1236
1288
|
init_spans();
|
|
1237
|
-
var VERSION = "0.
|
|
1289
|
+
var VERSION = "0.3.0";
|
|
1238
1290
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1239
1291
|
0 && (module.exports = {
|
|
1240
1292
|
Generation,
|
|
@@ -1248,5 +1300,6 @@ var VERSION = "0.2.4";
|
|
|
1248
1300
|
startAsCurrentGeneration,
|
|
1249
1301
|
startAsCurrentSpan,
|
|
1250
1302
|
startGeneration,
|
|
1251
|
-
startSpan
|
|
1303
|
+
startSpan,
|
|
1304
|
+
withSession
|
|
1252
1305
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -25,6 +25,12 @@ interface RiusOptions {
|
|
|
25
25
|
partialSpans?: boolean;
|
|
26
26
|
/** Seconds to debounce a pending-span snapshot after span start. */
|
|
27
27
|
partialSpansDelay?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Process-wide session id, stamped as `session.id` on every span. For
|
|
30
|
+
* one-run-per-process agents; a server handling many sessions scopes each
|
|
31
|
+
* one with `withSession()` instead, which overrides this default.
|
|
32
|
+
*/
|
|
33
|
+
sessionId?: string;
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
type HeartbeatTransport = (payload: Record<string, unknown>, timeoutMs: number) => Promise<void>;
|
|
@@ -203,6 +209,30 @@ interface ObserveOptions {
|
|
|
203
209
|
*/
|
|
204
210
|
declare function observe<F extends (...args: never[]) => unknown>(fn: F, options?: ObserveOptions): (...args: Parameters<F>) => Promise<Awaited<ReturnType<F>>>;
|
|
205
211
|
|
|
206
|
-
|
|
212
|
+
/**
|
|
213
|
+
* Scope every span started inside `fn` to one session id.
|
|
214
|
+
*
|
|
215
|
+
* Pass the application's own id (a conversation id, a job id) to correlate
|
|
216
|
+
* with it; omit it to mint a fresh UUID for the scope. Either way the scope's
|
|
217
|
+
* id is passed to the callback, so it can be logged or handed to the next
|
|
218
|
+
* turn. Nested scopes override outer ones, and an active scope overrides the
|
|
219
|
+
* `init({ sessionId })` default.
|
|
220
|
+
*
|
|
221
|
+
* There is deliberately no process-wide auto-generation: without an id the
|
|
222
|
+
* backend groups each trace as its own session, which stays true in a server
|
|
223
|
+
* handling many users, while an auto-minted global id would merge every user
|
|
224
|
+
* into one. A generated id is only ever scoped to an explicit callback, where
|
|
225
|
+
* "this is one session" is the caller's own claim.
|
|
226
|
+
*
|
|
227
|
+
* ```typescript
|
|
228
|
+
* await withSession(conversationId, async () => {
|
|
229
|
+
* await handleTurn(message) // every span of the turn carries session.id
|
|
230
|
+
* })
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
declare function withSession<T>(fn: (sessionId: string) => T): T;
|
|
234
|
+
declare function withSession<T>(sessionId: string, fn: (sessionId: string) => T): T;
|
|
235
|
+
|
|
236
|
+
declare const VERSION = "0.3.0";
|
|
207
237
|
|
|
208
|
-
export { Generation, type GenerationBody, type GenerationOptions, type InitOptions, type Mask, Observation, type ObserveOptions, RiusClient, type RiusOptions, type SpanBody, SpanKind, type SpanOptions, VERSION, getTracer, init, observe, startAsCurrentGeneration, startAsCurrentSpan, startGeneration, startSpan };
|
|
238
|
+
export { Generation, type GenerationBody, type GenerationOptions, type InitOptions, type Mask, Observation, type ObserveOptions, RiusClient, type RiusOptions, type SpanBody, SpanKind, type SpanOptions, VERSION, getTracer, init, observe, startAsCurrentGeneration, startAsCurrentSpan, startGeneration, startSpan, withSession };
|
package/dist/index.d.ts
CHANGED
|
@@ -25,6 +25,12 @@ interface RiusOptions {
|
|
|
25
25
|
partialSpans?: boolean;
|
|
26
26
|
/** Seconds to debounce a pending-span snapshot after span start. */
|
|
27
27
|
partialSpansDelay?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Process-wide session id, stamped as `session.id` on every span. For
|
|
30
|
+
* one-run-per-process agents; a server handling many sessions scopes each
|
|
31
|
+
* one with `withSession()` instead, which overrides this default.
|
|
32
|
+
*/
|
|
33
|
+
sessionId?: string;
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
type HeartbeatTransport = (payload: Record<string, unknown>, timeoutMs: number) => Promise<void>;
|
|
@@ -203,6 +209,30 @@ interface ObserveOptions {
|
|
|
203
209
|
*/
|
|
204
210
|
declare function observe<F extends (...args: never[]) => unknown>(fn: F, options?: ObserveOptions): (...args: Parameters<F>) => Promise<Awaited<ReturnType<F>>>;
|
|
205
211
|
|
|
206
|
-
|
|
212
|
+
/**
|
|
213
|
+
* Scope every span started inside `fn` to one session id.
|
|
214
|
+
*
|
|
215
|
+
* Pass the application's own id (a conversation id, a job id) to correlate
|
|
216
|
+
* with it; omit it to mint a fresh UUID for the scope. Either way the scope's
|
|
217
|
+
* id is passed to the callback, so it can be logged or handed to the next
|
|
218
|
+
* turn. Nested scopes override outer ones, and an active scope overrides the
|
|
219
|
+
* `init({ sessionId })` default.
|
|
220
|
+
*
|
|
221
|
+
* There is deliberately no process-wide auto-generation: without an id the
|
|
222
|
+
* backend groups each trace as its own session, which stays true in a server
|
|
223
|
+
* handling many users, while an auto-minted global id would merge every user
|
|
224
|
+
* into one. A generated id is only ever scoped to an explicit callback, where
|
|
225
|
+
* "this is one session" is the caller's own claim.
|
|
226
|
+
*
|
|
227
|
+
* ```typescript
|
|
228
|
+
* await withSession(conversationId, async () => {
|
|
229
|
+
* await handleTurn(message) // every span of the turn carries session.id
|
|
230
|
+
* })
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
declare function withSession<T>(fn: (sessionId: string) => T): T;
|
|
234
|
+
declare function withSession<T>(sessionId: string, fn: (sessionId: string) => T): T;
|
|
235
|
+
|
|
236
|
+
declare const VERSION = "0.3.0";
|
|
207
237
|
|
|
208
|
-
export { Generation, type GenerationBody, type GenerationOptions, type InitOptions, type Mask, Observation, type ObserveOptions, RiusClient, type RiusOptions, type SpanBody, SpanKind, type SpanOptions, VERSION, getTracer, init, observe, startAsCurrentGeneration, startAsCurrentSpan, startGeneration, startSpan };
|
|
238
|
+
export { Generation, type GenerationBody, type GenerationOptions, type InitOptions, type Mask, Observation, type ObserveOptions, RiusClient, type RiusOptions, type SpanBody, SpanKind, type SpanOptions, VERSION, getTracer, init, observe, startAsCurrentGeneration, startAsCurrentSpan, startGeneration, startSpan, withSession };
|
package/dist/index.js
CHANGED
|
@@ -76,7 +76,10 @@ function resolveConfig(options = {}, env = process.env) {
|
|
|
76
76
|
// on every heartbeat payload, so `??` would be wrong here.
|
|
77
77
|
agentName: options.agentName || env.RIUS_AGENT_NAME || serviceName,
|
|
78
78
|
partialSpans: options.partialSpans ?? bool("RIUS_PARTIAL_SPANS", env.RIUS_PARTIAL_SPANS, false),
|
|
79
|
-
partialSpansDelayMs: partialSpansDelaySeconds * 1e3
|
|
79
|
+
partialSpansDelayMs: partialSpansDelaySeconds * 1e3,
|
|
80
|
+
// Empty is unset, like agentName: a blank session id would group every
|
|
81
|
+
// span under the meaningless session "".
|
|
82
|
+
sessionId: options.sessionId || env.RIUS_SESSION_ID || void 0
|
|
80
83
|
};
|
|
81
84
|
}
|
|
82
85
|
var DEFAULT_ENDPOINT, DEFAULT_SERVICE_NAME, HEARTBEAT_INTERVAL_MIN, HEARTBEAT_INTERVAL_MAX, DEFAULT_HEARTBEAT_INTERVAL, PARTIAL_SPANS_DELAY_MIN, PARTIAL_SPANS_DELAY_MAX, DEFAULT_PARTIAL_SPANS_DELAY, AFFIRMATIVE, NEGATIVE;
|
|
@@ -206,7 +209,6 @@ var init_exportHealth = __esm({
|
|
|
206
209
|
});
|
|
207
210
|
|
|
208
211
|
// src/heartbeat.ts
|
|
209
|
-
import { randomUUID } from "crypto";
|
|
210
212
|
import { createRequire } from "module";
|
|
211
213
|
function httpTransport(url, headers) {
|
|
212
214
|
return async (payload, timeoutMs) => {
|
|
@@ -269,8 +271,8 @@ var init_heartbeat = __esm({
|
|
|
269
271
|
}
|
|
270
272
|
};
|
|
271
273
|
HeartbeatSender = class {
|
|
272
|
-
/** Identity of one process lifetime,
|
|
273
|
-
instanceId
|
|
274
|
+
/** Identity of one process lifetime; injected, shared with span resources. */
|
|
275
|
+
instanceId;
|
|
274
276
|
agentName;
|
|
275
277
|
tracker;
|
|
276
278
|
intervalMs;
|
|
@@ -281,6 +283,7 @@ var init_heartbeat = __esm({
|
|
|
281
283
|
stopped = false;
|
|
282
284
|
deliveryWarned = false;
|
|
283
285
|
constructor(opts) {
|
|
286
|
+
this.instanceId = opts.instanceId;
|
|
284
287
|
this.agentName = opts.agentName;
|
|
285
288
|
this.tracker = opts.tracker;
|
|
286
289
|
this.intervalMs = opts.intervalMs;
|
|
@@ -340,15 +343,17 @@ function kindAttributes(kind) {
|
|
|
340
343
|
if (operation !== void 0) attributes[GEN_AI_OPERATION_NAME] = operation;
|
|
341
344
|
return attributes;
|
|
342
345
|
}
|
|
343
|
-
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, GLASSFLOW_SPAN_PENDING, PENDING_IDENTITY_ATTRIBUTES, PENDING_IDENTITY_PREFIXES;
|
|
346
|
+
var TRACER_NAME, SERVICE_INSTANCE_ID, OPENINFERENCE_SPAN_KIND, INPUT_VALUE, OUTPUT_VALUE, SESSION_ID, 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, GLASSFLOW_SPAN_PENDING, PENDING_IDENTITY_ATTRIBUTES, PENDING_IDENTITY_PREFIXES;
|
|
344
347
|
var init_semconv = __esm({
|
|
345
348
|
"src/semconv.ts"() {
|
|
346
349
|
"use strict";
|
|
347
350
|
init_esm_shims();
|
|
348
351
|
TRACER_NAME = "glassflow";
|
|
352
|
+
SERVICE_INSTANCE_ID = "service.instance.id";
|
|
349
353
|
OPENINFERENCE_SPAN_KIND = "openinference.span.kind";
|
|
350
354
|
INPUT_VALUE = "input.value";
|
|
351
355
|
OUTPUT_VALUE = "output.value";
|
|
356
|
+
SESSION_ID = "session.id";
|
|
352
357
|
GEN_AI_OPERATION_NAME = "gen_ai.operation.name";
|
|
353
358
|
GEN_AI_PROVIDER_NAME = "gen_ai.provider.name";
|
|
354
359
|
GEN_AI_REQUEST_MODEL = "gen_ai.request.model";
|
|
@@ -414,7 +419,10 @@ var init_semconv = __esm({
|
|
|
414
419
|
OPENINFERENCE_SPAN_KIND,
|
|
415
420
|
GEN_AI_OPERATION_NAME,
|
|
416
421
|
GEN_AI_PROVIDER_NAME,
|
|
417
|
-
GEN_AI_TOOL_NAME
|
|
422
|
+
GEN_AI_TOOL_NAME,
|
|
423
|
+
// Identity, not content: a pending span must be groupable into its
|
|
424
|
+
// session while still running, that is the live view's whole point.
|
|
425
|
+
SESSION_ID
|
|
418
426
|
]);
|
|
419
427
|
PENDING_IDENTITY_PREFIXES = [GEN_AI_REQUEST_PREFIX];
|
|
420
428
|
}
|
|
@@ -955,7 +963,42 @@ var init_pending = __esm({
|
|
|
955
963
|
}
|
|
956
964
|
});
|
|
957
965
|
|
|
966
|
+
// src/session.ts
|
|
967
|
+
import { randomUUID } from "crypto";
|
|
968
|
+
import { context as apiContext, createContextKey } from "@opentelemetry/api";
|
|
969
|
+
function withSession(sessionIdOrFn, maybeFn) {
|
|
970
|
+
const [sessionId, fn] = typeof sessionIdOrFn === "function" ? [randomUUID(), sessionIdOrFn] : [sessionIdOrFn, maybeFn];
|
|
971
|
+
return apiContext.with(apiContext.active().setValue(SESSION_KEY, sessionId), () => fn(sessionId));
|
|
972
|
+
}
|
|
973
|
+
var SESSION_KEY, SessionSpanProcessor;
|
|
974
|
+
var init_session = __esm({
|
|
975
|
+
"src/session.ts"() {
|
|
976
|
+
"use strict";
|
|
977
|
+
init_esm_shims();
|
|
978
|
+
init_semconv();
|
|
979
|
+
SESSION_KEY = createContextKey("rius-session-id");
|
|
980
|
+
SessionSpanProcessor = class {
|
|
981
|
+
constructor(defaultSessionId) {
|
|
982
|
+
this.defaultSessionId = defaultSessionId;
|
|
983
|
+
}
|
|
984
|
+
defaultSessionId;
|
|
985
|
+
onStart(span, parentContext) {
|
|
986
|
+
const value = parentContext.getValue(SESSION_KEY);
|
|
987
|
+
const sessionId = typeof value === "string" ? value : this.defaultSessionId;
|
|
988
|
+
if (sessionId !== void 0) span.setAttribute(SESSION_ID, sessionId);
|
|
989
|
+
}
|
|
990
|
+
onEnd(_span) {
|
|
991
|
+
}
|
|
992
|
+
async forceFlush() {
|
|
993
|
+
}
|
|
994
|
+
async shutdown() {
|
|
995
|
+
}
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
});
|
|
999
|
+
|
|
958
1000
|
// src/client.ts
|
|
1001
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
959
1002
|
import { trace } from "@opentelemetry/api";
|
|
960
1003
|
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
|
|
961
1004
|
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
@@ -988,13 +1031,18 @@ function init(options = {}) {
|
|
|
988
1031
|
mask: config.mask
|
|
989
1032
|
}) : health;
|
|
990
1033
|
const batch = new BatchSpanProcessor(exporter);
|
|
1034
|
+
processors.add(new SessionSpanProcessor(config.sessionId));
|
|
991
1035
|
if (config.partialSpans) {
|
|
992
1036
|
processors.add(new PendingSpanProcessor(batch, { delayMs: config.partialSpansDelayMs }));
|
|
993
1037
|
}
|
|
994
1038
|
processors.add(batch);
|
|
995
1039
|
}
|
|
1040
|
+
const instanceId = randomUUID2();
|
|
996
1041
|
const provider = new NodeTracerProvider({
|
|
997
|
-
resource: resourceFromAttributes({
|
|
1042
|
+
resource: resourceFromAttributes({
|
|
1043
|
+
[ATTR_SERVICE_NAME]: config.serviceName,
|
|
1044
|
+
[SERVICE_INSTANCE_ID]: instanceId
|
|
1045
|
+
}),
|
|
998
1046
|
// Always ParentBased, with no AlwaysOn shortcut at rate 1. They are not
|
|
999
1047
|
// equivalent: ParentBased honours a remote UNSAMPLED parent and drops,
|
|
1000
1048
|
// while AlwaysOn records regardless, producing children of a span the
|
|
@@ -1014,6 +1062,7 @@ function init(options = {}) {
|
|
|
1014
1062
|
headers: authHeaders,
|
|
1015
1063
|
intervalMs: config.heartbeatIntervalMs,
|
|
1016
1064
|
agentName: config.agentName,
|
|
1065
|
+
instanceId,
|
|
1017
1066
|
tracker,
|
|
1018
1067
|
transport: options.heartbeatTransport
|
|
1019
1068
|
});
|
|
@@ -1043,6 +1092,7 @@ var init_client = __esm({
|
|
|
1043
1092
|
init_masking();
|
|
1044
1093
|
init_pending();
|
|
1045
1094
|
init_semconv();
|
|
1095
|
+
init_session();
|
|
1046
1096
|
sinks = /* @__PURE__ */ new WeakMap();
|
|
1047
1097
|
heartbeats = /* @__PURE__ */ new WeakMap();
|
|
1048
1098
|
RiusClient = class _RiusClient {
|
|
@@ -1208,8 +1258,9 @@ function observe(fn, options = {}) {
|
|
|
1208
1258
|
|
|
1209
1259
|
// src/index.ts
|
|
1210
1260
|
init_semconv();
|
|
1261
|
+
init_session();
|
|
1211
1262
|
init_spans();
|
|
1212
|
-
var VERSION = "0.
|
|
1263
|
+
var VERSION = "0.3.0";
|
|
1213
1264
|
export {
|
|
1214
1265
|
Generation,
|
|
1215
1266
|
Observation,
|
|
@@ -1222,5 +1273,6 @@ export {
|
|
|
1222
1273
|
startAsCurrentGeneration,
|
|
1223
1274
|
startAsCurrentSpan,
|
|
1224
1275
|
startGeneration,
|
|
1225
|
-
startSpan
|
|
1276
|
+
startSpan,
|
|
1277
|
+
withSession
|
|
1226
1278
|
};
|