@glassflow-ai/rius 0.4.0 → 0.6.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.d.cts CHANGED
@@ -118,6 +118,7 @@ interface InitOptions extends RiusOptions {
118
118
  declare class RiusClient {
119
119
  private readonly provider;
120
120
  private readonly health?;
121
+ private readonly teardown;
121
122
  /** Resolves with the names of the auto-instrumentations that attached. */
122
123
  readonly ready: Promise<string[]>;
123
124
  private constructor();
@@ -145,9 +146,10 @@ declare class RiusClient {
145
146
  * {@link RiusClient.ready} if instrumentation must be attached before your
146
147
  * first span.
147
148
  *
148
- * The SDK installs no process exit hook: short-lived processes must call
149
+ * The SDK installs no exit hook for SPANS: short-lived processes must call
149
150
  * {@link RiusClient.flush} before exiting or spans still in the batch queue
150
- * are lost.
151
+ * are lost. (The heartbeat does register a `beforeExit` listener, only to
152
+ * send its final `stopped` ping; it flushes nothing.)
151
153
  */
152
154
  declare function init(options?: InitOptions): RiusClient;
153
155
  /** The SDK tracer. Scope name is wire-visible; do not parameterize it. */
@@ -170,6 +172,21 @@ declare enum SpanKind {
170
172
  interface SpanOptions {
171
173
  kind?: SpanKind;
172
174
  input?: unknown;
175
+ /**
176
+ * End-user identity (`user.id`). Sugar for `withUser`: set on this span at
177
+ * creation and, for the scoped variant, on every span opened inside it.
178
+ * To attribute a whole request, including auto-instrumented spans, prefer
179
+ * `withUser` around the handler.
180
+ */
181
+ userId?: string;
182
+ /**
183
+ * Identity attributes to set at span CREATION rather than after it. Pending
184
+ * snapshots are built at start, so anything a caller would otherwise
185
+ * `setAttribute` first thing (a tool name, say) belongs here to reach them.
186
+ * Content never does: it is not known at start and would bypass masking's
187
+ * assumptions about where content lives.
188
+ */
189
+ attributes?: Record<string, string>;
173
190
  }
174
191
  /** A handle over a span. Chainable setters; `end()` is idempotent. */
175
192
  declare class Observation {
@@ -178,6 +195,12 @@ declare class Observation {
178
195
  constructor(span: Span);
179
196
  setInput(value: unknown): this;
180
197
  setOutput(value: unknown): this;
198
+ /**
199
+ * Set an arbitrary attribute. Primitives and homogeneous primitive arrays
200
+ * are passed through as the OTel values they are; objects are JSON-encoded
201
+ * and bounded; `undefined` and `null` set nothing, since "no value" is not
202
+ * an empty string.
203
+ */
181
204
  setAttribute(key: string, value: unknown): this;
182
205
  /**
183
206
  * Record an error on the span and set ERROR status. This is exactly what the
@@ -223,19 +246,68 @@ interface GenerationOptions {
223
246
  * so use the provider's own parameter names.
224
247
  */
225
248
  modelParameters?: Record<string, unknown>;
249
+ /**
250
+ * Requested reasoning/thinking effort level
251
+ * (`gen_ai.request.reasoning.level`), e.g. OpenAI's `reasoning.effort`
252
+ * values. Provider-defined string, recorded verbatim. A first-class option
253
+ * because the `modelParameters` pass-through would spell the key
254
+ * `gen_ai.request.reasoning_level`, which is not the convention's name.
255
+ */
256
+ reasoningLevel?: string;
257
+ /**
258
+ * The request's tool/function definitions, recorded immediately via
259
+ * {@link Generation.setToolDefinitions} — verbatim, any provider shape.
260
+ */
261
+ tools?: unknown[];
262
+ /**
263
+ * End-user identity (`user.id`). Sugar for `withUser`: set on this span at
264
+ * creation and, for the scoped variant, on every span opened inside it.
265
+ */
266
+ userId?: string;
267
+ /**
268
+ * Operation name (`gen_ai.operation.name`); default `"chat"`. Set it for
269
+ * `text_completion`, `embeddings` or `generate_content` calls, as the
270
+ * Python SDK's `operation=` allows.
271
+ */
272
+ operation?: string;
226
273
  }
227
274
  /** An LLM call. Content uses gen_ai message keys, never input.value. */
228
275
  declare class Generation extends Observation {
276
+ private readonly provider?;
229
277
  private firstTokenRecorded;
278
+ /**
279
+ * The provider passed at creation; drives the Anthropic input-token summing
280
+ * in {@link setUsage}. A bare `new Generation(span)` has none and never sums.
281
+ */
282
+ constructor(span: ConstructorParameters<typeof Observation>[0], provider?: string | undefined);
283
+ /**
284
+ * Record the request messages (`gen_ai.input.messages`), normalised to the
285
+ * GenAI `{role, parts}` shape like the Python SDK does: bare strings, OpenAI
286
+ * dicts (including `tool_calls` and tool responses) and multimodal content
287
+ * lists are all accepted. Bare strings default to the `user` role.
288
+ */
230
289
  setInput(value: unknown): this;
290
+ /** Record the response messages (`gen_ai.output.messages`); bare strings default to `assistant`. */
231
291
  setOutput(value: unknown): this;
292
+ /**
293
+ * The request's tool/function definitions (`gen_ai.tool.definitions`).
294
+ * Serialized verbatim, in whatever shape the provider request used (OpenAI
295
+ * nests each tool under `function`, Anthropic uses top-level
296
+ * `name`/`input_schema`) — no normalization, so what is recorded is exactly
297
+ * what the model was shown. Definitions are content, not identity: they are
298
+ * masked/stripped under `captureContent: false` like messages are.
299
+ */
300
+ setToolDefinitions(tools: unknown[]): this;
232
301
  setModel(model: string): this;
233
302
  /**
234
- * Token usage (`gen_ai.usage.*`). Pass provider-reported values as-is.
235
- * Per the GenAI conventions, `inputTokens` is the total including cached
236
- * tokens (the cache counts are subsets of it); providers that report an
237
- * exclusive `inputTokens` (e.g. Anthropic) are detected and normalized by
238
- * the backend, so no client-side arithmetic is needed.
303
+ * Token usage (`gen_ai.usage.*`). Pass provider-reported values as-is;
304
+ * never pre-add anything. Per the GenAI conventions, `inputTokens` is the
305
+ * total including cached tokens (the cache counts are subsets of it).
306
+ * Anthropic's API reports `input_tokens` excluding the cache counts, and
307
+ * the conventions require the instrumentation to do the summing, so when
308
+ * the generation's provider is `"anthropic"` the emitted total is
309
+ * `inputTokens` plus both cache counts. Every other provider is recorded
310
+ * verbatim.
239
311
  */
240
312
  setUsage(usage: {
241
313
  inputTokens?: number;
@@ -247,6 +319,13 @@ declare class Generation extends Observation {
247
319
  * (called "cache creation" by Anthropic).
248
320
  */
249
321
  cacheWriteInputTokens?: number;
322
+ /**
323
+ * Output tokens spent on reasoning / extended thinking. A subset of
324
+ * `outputTokens`, never in addition to it: providers already include
325
+ * reasoning tokens in the output total, so pass both as reported and
326
+ * do no arithmetic.
327
+ */
328
+ reasoningOutputTokens?: number;
250
329
  }): this;
251
330
  /**
252
331
  * Why generation stopped (`gen_ai.response.finish_reasons`), e.g. `"stop"`,
@@ -283,8 +362,10 @@ interface ObserveOptions {
283
362
  captureOutput?: boolean;
284
363
  }
285
364
  /**
286
- * Wrap a function so each call becomes a span. Returns a function with the
287
- * same signature, so call sites and types are unchanged.
365
+ * Wrap a function so each call becomes a span. The returned function takes
366
+ * the same parameters and always returns a Promise of the original's result
367
+ * (a synchronous function becomes asynchronous), so call sites need an
368
+ * `await` but no other change.
288
369
  *
289
370
  * A wrapper rather than a decorator on purpose: TypeScript decorators apply
290
371
  * only to class members, and most agent code is plain functions.
@@ -315,6 +396,51 @@ declare function observe<F extends (...args: never[]) => unknown>(fn: F, options
315
396
  declare function withSession<T>(fn: (sessionId: string) => T): T;
316
397
  declare function withSession<T>(sessionId: string, fn: (sessionId: string) => T): T;
317
398
 
318
- declare const VERSION = "0.4.0";
399
+ /**
400
+ * Users: attribute every span of a request to the end user it served.
401
+ *
402
+ * The caller supplies the id (`withUser` for a scope) and `UserSpanProcessor`
403
+ * stamps it as the `user.id` attribute on every span started in scope. That
404
+ * key is the one OpenInference defines, Langfuse reads natively, and the
405
+ * OpenTelemetry registry lists; the sink also accepts OTel's `enduser.id`
406
+ * from third-party instrumentors, but this SDK emits one name for one fact.
407
+ *
408
+ * Stamping happens in `onStart`, as for sessions: the sink derives its user
409
+ * column per span, and pending snapshots are built at span start from the
410
+ * identity allowlist, so an attribute set later would reach neither.
411
+ *
412
+ * Two deliberate differences from `withSession`:
413
+ *
414
+ * - No process-wide default and no environment variable. A user is a
415
+ * property of a request, and a global default would attribute every
416
+ * request a process ever handles to one person.
417
+ * - Nothing is minted when the caller passes nothing. A session without an
418
+ * id is still a session; a span without a user is simply anonymous, and
419
+ * the backend treats an empty user id as exactly that.
420
+ *
421
+ * The id rides OTel context, so scopes nest, unwind with the callback even
422
+ * on a throw, and follow async continuations the same way the active span
423
+ * does.
424
+ */
425
+
426
+ /**
427
+ * Scope every span started inside `fn` to one end user.
428
+ *
429
+ * Pass the application's own identifier for the person the request serves.
430
+ * Prefer an opaque id over an email: it is stored on every span and shown
431
+ * in the console. When only sensitive identifiers exist, hash them first
432
+ * (OTel's `user.hash` / `enduser.pseudo.id` guidance). Nested scopes
433
+ * override outer ones. The id is passed to the callback so it can be logged
434
+ * alongside the work.
435
+ *
436
+ * ```typescript
437
+ * await withUser(request.userId, async () => {
438
+ * await handle(request) // every span of the request carries user.id
439
+ * })
440
+ * ```
441
+ */
442
+ declare function withUser<T>(userId: string, fn: (userId: string) => T): T;
443
+
444
+ declare const VERSION = "0.6.0";
319
445
 
320
- export { Generation, type GenerationBody, type GenerationOptions, type InitOptions, type Mask, Observation, type ObserveOptions, RiusClient, type RiusOptions, type SpanBody, SpanKind, type SpanOptions, VERSION, type WorkspaceExporterFactory, getTracer, init, observe, registerWorkspace, startAsCurrentGeneration, startAsCurrentSpan, startGeneration, startSpan, withSession, withWorkspace };
446
+ export { Generation, type GenerationBody, type GenerationOptions, type InitOptions, type Mask, Observation, type ObserveOptions, RiusClient, type RiusOptions, type SpanBody, SpanKind, type SpanOptions, VERSION, type WorkspaceExporterFactory, getTracer, init, observe, registerWorkspace, startAsCurrentGeneration, startAsCurrentSpan, startGeneration, startSpan, withSession, withUser, withWorkspace };
package/dist/index.d.ts CHANGED
@@ -118,6 +118,7 @@ interface InitOptions extends RiusOptions {
118
118
  declare class RiusClient {
119
119
  private readonly provider;
120
120
  private readonly health?;
121
+ private readonly teardown;
121
122
  /** Resolves with the names of the auto-instrumentations that attached. */
122
123
  readonly ready: Promise<string[]>;
123
124
  private constructor();
@@ -145,9 +146,10 @@ declare class RiusClient {
145
146
  * {@link RiusClient.ready} if instrumentation must be attached before your
146
147
  * first span.
147
148
  *
148
- * The SDK installs no process exit hook: short-lived processes must call
149
+ * The SDK installs no exit hook for SPANS: short-lived processes must call
149
150
  * {@link RiusClient.flush} before exiting or spans still in the batch queue
150
- * are lost.
151
+ * are lost. (The heartbeat does register a `beforeExit` listener, only to
152
+ * send its final `stopped` ping; it flushes nothing.)
151
153
  */
152
154
  declare function init(options?: InitOptions): RiusClient;
153
155
  /** The SDK tracer. Scope name is wire-visible; do not parameterize it. */
@@ -170,6 +172,21 @@ declare enum SpanKind {
170
172
  interface SpanOptions {
171
173
  kind?: SpanKind;
172
174
  input?: unknown;
175
+ /**
176
+ * End-user identity (`user.id`). Sugar for `withUser`: set on this span at
177
+ * creation and, for the scoped variant, on every span opened inside it.
178
+ * To attribute a whole request, including auto-instrumented spans, prefer
179
+ * `withUser` around the handler.
180
+ */
181
+ userId?: string;
182
+ /**
183
+ * Identity attributes to set at span CREATION rather than after it. Pending
184
+ * snapshots are built at start, so anything a caller would otherwise
185
+ * `setAttribute` first thing (a tool name, say) belongs here to reach them.
186
+ * Content never does: it is not known at start and would bypass masking's
187
+ * assumptions about where content lives.
188
+ */
189
+ attributes?: Record<string, string>;
173
190
  }
174
191
  /** A handle over a span. Chainable setters; `end()` is idempotent. */
175
192
  declare class Observation {
@@ -178,6 +195,12 @@ declare class Observation {
178
195
  constructor(span: Span);
179
196
  setInput(value: unknown): this;
180
197
  setOutput(value: unknown): this;
198
+ /**
199
+ * Set an arbitrary attribute. Primitives and homogeneous primitive arrays
200
+ * are passed through as the OTel values they are; objects are JSON-encoded
201
+ * and bounded; `undefined` and `null` set nothing, since "no value" is not
202
+ * an empty string.
203
+ */
181
204
  setAttribute(key: string, value: unknown): this;
182
205
  /**
183
206
  * Record an error on the span and set ERROR status. This is exactly what the
@@ -223,19 +246,68 @@ interface GenerationOptions {
223
246
  * so use the provider's own parameter names.
224
247
  */
225
248
  modelParameters?: Record<string, unknown>;
249
+ /**
250
+ * Requested reasoning/thinking effort level
251
+ * (`gen_ai.request.reasoning.level`), e.g. OpenAI's `reasoning.effort`
252
+ * values. Provider-defined string, recorded verbatim. A first-class option
253
+ * because the `modelParameters` pass-through would spell the key
254
+ * `gen_ai.request.reasoning_level`, which is not the convention's name.
255
+ */
256
+ reasoningLevel?: string;
257
+ /**
258
+ * The request's tool/function definitions, recorded immediately via
259
+ * {@link Generation.setToolDefinitions} — verbatim, any provider shape.
260
+ */
261
+ tools?: unknown[];
262
+ /**
263
+ * End-user identity (`user.id`). Sugar for `withUser`: set on this span at
264
+ * creation and, for the scoped variant, on every span opened inside it.
265
+ */
266
+ userId?: string;
267
+ /**
268
+ * Operation name (`gen_ai.operation.name`); default `"chat"`. Set it for
269
+ * `text_completion`, `embeddings` or `generate_content` calls, as the
270
+ * Python SDK's `operation=` allows.
271
+ */
272
+ operation?: string;
226
273
  }
227
274
  /** An LLM call. Content uses gen_ai message keys, never input.value. */
228
275
  declare class Generation extends Observation {
276
+ private readonly provider?;
229
277
  private firstTokenRecorded;
278
+ /**
279
+ * The provider passed at creation; drives the Anthropic input-token summing
280
+ * in {@link setUsage}. A bare `new Generation(span)` has none and never sums.
281
+ */
282
+ constructor(span: ConstructorParameters<typeof Observation>[0], provider?: string | undefined);
283
+ /**
284
+ * Record the request messages (`gen_ai.input.messages`), normalised to the
285
+ * GenAI `{role, parts}` shape like the Python SDK does: bare strings, OpenAI
286
+ * dicts (including `tool_calls` and tool responses) and multimodal content
287
+ * lists are all accepted. Bare strings default to the `user` role.
288
+ */
230
289
  setInput(value: unknown): this;
290
+ /** Record the response messages (`gen_ai.output.messages`); bare strings default to `assistant`. */
231
291
  setOutput(value: unknown): this;
292
+ /**
293
+ * The request's tool/function definitions (`gen_ai.tool.definitions`).
294
+ * Serialized verbatim, in whatever shape the provider request used (OpenAI
295
+ * nests each tool under `function`, Anthropic uses top-level
296
+ * `name`/`input_schema`) — no normalization, so what is recorded is exactly
297
+ * what the model was shown. Definitions are content, not identity: they are
298
+ * masked/stripped under `captureContent: false` like messages are.
299
+ */
300
+ setToolDefinitions(tools: unknown[]): this;
232
301
  setModel(model: string): this;
233
302
  /**
234
- * Token usage (`gen_ai.usage.*`). Pass provider-reported values as-is.
235
- * Per the GenAI conventions, `inputTokens` is the total including cached
236
- * tokens (the cache counts are subsets of it); providers that report an
237
- * exclusive `inputTokens` (e.g. Anthropic) are detected and normalized by
238
- * the backend, so no client-side arithmetic is needed.
303
+ * Token usage (`gen_ai.usage.*`). Pass provider-reported values as-is;
304
+ * never pre-add anything. Per the GenAI conventions, `inputTokens` is the
305
+ * total including cached tokens (the cache counts are subsets of it).
306
+ * Anthropic's API reports `input_tokens` excluding the cache counts, and
307
+ * the conventions require the instrumentation to do the summing, so when
308
+ * the generation's provider is `"anthropic"` the emitted total is
309
+ * `inputTokens` plus both cache counts. Every other provider is recorded
310
+ * verbatim.
239
311
  */
240
312
  setUsage(usage: {
241
313
  inputTokens?: number;
@@ -247,6 +319,13 @@ declare class Generation extends Observation {
247
319
  * (called "cache creation" by Anthropic).
248
320
  */
249
321
  cacheWriteInputTokens?: number;
322
+ /**
323
+ * Output tokens spent on reasoning / extended thinking. A subset of
324
+ * `outputTokens`, never in addition to it: providers already include
325
+ * reasoning tokens in the output total, so pass both as reported and
326
+ * do no arithmetic.
327
+ */
328
+ reasoningOutputTokens?: number;
250
329
  }): this;
251
330
  /**
252
331
  * Why generation stopped (`gen_ai.response.finish_reasons`), e.g. `"stop"`,
@@ -283,8 +362,10 @@ interface ObserveOptions {
283
362
  captureOutput?: boolean;
284
363
  }
285
364
  /**
286
- * Wrap a function so each call becomes a span. Returns a function with the
287
- * same signature, so call sites and types are unchanged.
365
+ * Wrap a function so each call becomes a span. The returned function takes
366
+ * the same parameters and always returns a Promise of the original's result
367
+ * (a synchronous function becomes asynchronous), so call sites need an
368
+ * `await` but no other change.
288
369
  *
289
370
  * A wrapper rather than a decorator on purpose: TypeScript decorators apply
290
371
  * only to class members, and most agent code is plain functions.
@@ -315,6 +396,51 @@ declare function observe<F extends (...args: never[]) => unknown>(fn: F, options
315
396
  declare function withSession<T>(fn: (sessionId: string) => T): T;
316
397
  declare function withSession<T>(sessionId: string, fn: (sessionId: string) => T): T;
317
398
 
318
- declare const VERSION = "0.4.0";
399
+ /**
400
+ * Users: attribute every span of a request to the end user it served.
401
+ *
402
+ * The caller supplies the id (`withUser` for a scope) and `UserSpanProcessor`
403
+ * stamps it as the `user.id` attribute on every span started in scope. That
404
+ * key is the one OpenInference defines, Langfuse reads natively, and the
405
+ * OpenTelemetry registry lists; the sink also accepts OTel's `enduser.id`
406
+ * from third-party instrumentors, but this SDK emits one name for one fact.
407
+ *
408
+ * Stamping happens in `onStart`, as for sessions: the sink derives its user
409
+ * column per span, and pending snapshots are built at span start from the
410
+ * identity allowlist, so an attribute set later would reach neither.
411
+ *
412
+ * Two deliberate differences from `withSession`:
413
+ *
414
+ * - No process-wide default and no environment variable. A user is a
415
+ * property of a request, and a global default would attribute every
416
+ * request a process ever handles to one person.
417
+ * - Nothing is minted when the caller passes nothing. A session without an
418
+ * id is still a session; a span without a user is simply anonymous, and
419
+ * the backend treats an empty user id as exactly that.
420
+ *
421
+ * The id rides OTel context, so scopes nest, unwind with the callback even
422
+ * on a throw, and follow async continuations the same way the active span
423
+ * does.
424
+ */
425
+
426
+ /**
427
+ * Scope every span started inside `fn` to one end user.
428
+ *
429
+ * Pass the application's own identifier for the person the request serves.
430
+ * Prefer an opaque id over an email: it is stored on every span and shown
431
+ * in the console. When only sensitive identifiers exist, hash them first
432
+ * (OTel's `user.hash` / `enduser.pseudo.id` guidance). Nested scopes
433
+ * override outer ones. The id is passed to the callback so it can be logged
434
+ * alongside the work.
435
+ *
436
+ * ```typescript
437
+ * await withUser(request.userId, async () => {
438
+ * await handle(request) // every span of the request carries user.id
439
+ * })
440
+ * ```
441
+ */
442
+ declare function withUser<T>(userId: string, fn: (userId: string) => T): T;
443
+
444
+ declare const VERSION = "0.6.0";
319
445
 
320
- export { Generation, type GenerationBody, type GenerationOptions, type InitOptions, type Mask, Observation, type ObserveOptions, RiusClient, type RiusOptions, type SpanBody, SpanKind, type SpanOptions, VERSION, type WorkspaceExporterFactory, getTracer, init, observe, registerWorkspace, startAsCurrentGeneration, startAsCurrentSpan, startGeneration, startSpan, withSession, withWorkspace };
446
+ export { Generation, type GenerationBody, type GenerationOptions, type InitOptions, type Mask, Observation, type ObserveOptions, RiusClient, type RiusOptions, type SpanBody, SpanKind, type SpanOptions, VERSION, type WorkspaceExporterFactory, getTracer, init, observe, registerWorkspace, startAsCurrentGeneration, startAsCurrentSpan, startGeneration, startSpan, withSession, withUser, withWorkspace };