@glassflow-ai/rius 0.8.0 → 1.0.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
@@ -14,6 +14,17 @@ interface RiusOptions {
14
14
  endpoint?: string;
15
15
  apiKey?: string;
16
16
  serviceName?: string;
17
+ /**
18
+ * The running build's version, stamped on the resource as `service.version`.
19
+ * There is deliberately NO default: `service.name` already shows what a
20
+ * missing value costs, where the `unknown_service` placeholder merges every
21
+ * unconfigured process into one bucket. An absent version is a visibly
22
+ * absent version, so the resource simply omits the key.
23
+ *
24
+ * Resolution: this option, then `RIUS_SERVICE_VERSION`, then
25
+ * `service.version` inside `OTEL_RESOURCE_ATTRIBUTES`, then unset.
26
+ */
27
+ serviceVersion?: string;
17
28
  disabled?: boolean;
18
29
  sampleRate?: number;
19
30
  captureContent?: boolean;
@@ -22,6 +33,34 @@ interface RiusOptions {
22
33
  heartbeatInterval?: number;
23
34
  heartbeat?: boolean;
24
35
  agentName?: string;
36
+ /**
37
+ * A STABLE identifier for the agent this process is, stamped on the
38
+ * resource as `rius.main_agent.id`. A registry id or a hosted agent's ARN,
39
+ * NOT a transient in-memory or process-local id: a uuid minted at startup
40
+ * identifies a run, not an agent, and would split one agent into a fresh
41
+ * bucket per restart. `service.instance.id` already answers "which
42
+ * process". Absent by default and never defaulted.
43
+ *
44
+ * Resolution: this option, then `RIUS_MAIN_AGENT_ID`, then unset.
45
+ */
46
+ mainAgentId?: string;
47
+ /**
48
+ * A human-readable description of the agent this process is, stamped as
49
+ * `rius.main_agent.description`. This option, then
50
+ * `RIUS_MAIN_AGENT_DESCRIPTION`, then unset.
51
+ */
52
+ mainAgentDescription?: string;
53
+ /**
54
+ * The version of the AGENT DEFINITION this process runs — its prompt, tools
55
+ * and policy — stamped as `rius.main_agent.version`. Deliberately NOT
56
+ * `serviceVersion`, which is the version of the build hosting it: the two
57
+ * move independently, and neither is ever derived from the other.
58
+ *
59
+ * Resolution: this option, then `RIUS_MAIN_AGENT_VERSION`, then unset. The
60
+ * OTel environment is not consulted, unlike `serviceVersion`: no convention
61
+ * defines this key, so `OTEL_RESOURCE_ATTRIBUTES` cannot be carrying it.
62
+ */
63
+ mainAgentVersion?: string;
25
64
  partialSpans?: boolean;
26
65
  /** Seconds to debounce a pending-span snapshot after span start. */
27
66
  partialSpansDelay?: number;
@@ -31,6 +70,22 @@ interface RiusOptions {
31
70
  * one with `withSession()` instead, which overrides this default.
32
71
  */
33
72
  sessionId?: string;
73
+ /**
74
+ * What to do when another SDK already holds the OpenTelemetry global tracer
75
+ * provider at `init()` (`RIUS_BRIDGE_FOREIGN_PROVIDER`; off by default).
76
+ *
77
+ * Off, Rius keeps to its own provider: LLM spans started inside the other
78
+ * SDK's spans arrive without their parent, flagged `rius.parent.foreign`,
79
+ * counted in the heartbeat, and the first one logs a warning. On, Rius also
80
+ * exports the other SDK's spans (the parents), under Rius's resource
81
+ * identity and subject to Rius's sampling and content settings, and it never
82
+ * modifies what the other SDK exports. Either way the resource records the
83
+ * conflict as `rius.sdk.global_provider`.
84
+ *
85
+ * Off by default: exporting another SDK's spans is consent the caller gives
86
+ * explicitly.
87
+ */
88
+ bridgeForeignProvider?: boolean;
34
89
  }
35
90
 
36
91
  type HeartbeatTransport = (payload: Record<string, unknown>, timeoutMs: number) => Promise<void>;
@@ -186,6 +241,85 @@ interface SpanOptions {
186
241
  * `withUser` around the handler.
187
242
  */
188
243
  userId?: string;
244
+ /**
245
+ * The tool name a TOOL span carries as `gen_ai.tool.name`. Defaults to the
246
+ * span name, which is what a caller who passes nothing meant back when the
247
+ * two were necessarily the same string. Pass it explicitly whenever the
248
+ * span name is not the bare tool name — and prefer passing it INSTEAD of a
249
+ * span name, which gets you the conventions' `execute_tool {tool}` name for
250
+ * free. With neither, the span is named `execute_tool` and carries no tool
251
+ * name: nothing is invented.
252
+ */
253
+ toolName?: string;
254
+ /**
255
+ * The id of the model's tool-call message this TOOL span answers, set as
256
+ * `gen_ai.tool.call.id`. Caller-supplied and nothing else: the id belongs
257
+ * to the assistant turn that requested the call, which the SDK never sees,
258
+ * so there is nothing to derive it from and it is omitted rather than
259
+ * invented. Scoped to TOOL, like `toolName`: on any other kind the key
260
+ * would claim a tool call that is not there.
261
+ */
262
+ toolCallId?: string;
263
+ /**
264
+ * What kind of tool this TOOL span ran, set as `gen_ai.tool.type` — the
265
+ * conventions' examples are `"function"`, `"extension"` and `"datastore"`.
266
+ * Caller-supplied, recorded verbatim, never guessed from the callable: a
267
+ * wrapped function is not automatically a `function` tool, since the same
268
+ * wrapper is what an agent-side extension call goes through. Scoped to
269
+ * TOOL, like `toolCallId`.
270
+ */
271
+ toolType?: string;
272
+ /**
273
+ * The index, collection or knowledge base a RETRIEVER span searched, set as
274
+ * `gen_ai.data_source.id`. Ignored on every other kind: the key means the
275
+ * target of a retrieval, and putting it elsewhere would make the attribute
276
+ * mean something different depending on the span. Omitted when not passed,
277
+ * never guessed.
278
+ */
279
+ dataSourceId?: string;
280
+ /**
281
+ * How many documents a RETRIEVER span asked for, set as
282
+ * `gen_ai.retrieval.top_k`. Ignored on every other kind. What came back is
283
+ * not an option here: it is unknown at span creation, so it is recorded
284
+ * afterwards with `Observation.setRetrievedDocuments`.
285
+ */
286
+ topK?: number;
287
+ /**
288
+ * The agent an AGENT span INVOKES, set as `gen_ai.agent.name`. That is what
289
+ * the key means on an invoke-agent span, where the conventions make it
290
+ * Conditionally Required; on an execute-tool span the same key means the
291
+ * agent DOING the call, which is why this is scoped to AGENT here. Unset,
292
+ * it falls back to the agent name `init()` was given. It is never taken
293
+ * from the span name, unlike the tool name: that fallback exists only
294
+ * because a tool's name and its span name were historically one string,
295
+ * and a wrong agent name mislabels every span beneath it. Ignored on every
296
+ * other kind, where the key would read as "the agent that produced this
297
+ * span" — which is what the resource attribute of the same name says.
298
+ *
299
+ * On the scoped surface this name also becomes the enclosing agent scope,
300
+ * so TOOL spans opened inside the callback carry it as the agent that
301
+ * EXECUTED them. See {@link startAsCurrentSpan}.
302
+ */
303
+ agentName?: string;
304
+ /**
305
+ * The invoked agent's identifier, set as `gen_ai.agent.id`. This key is for
306
+ * a HOSTED agent resource, such as a Bedrock agent ARN; the conventions
307
+ * advise against recording a transient in-memory instance id there, so an
308
+ * in-process agent leaves it unset. Ignored on every other kind.
309
+ */
310
+ agentId?: string;
311
+ /**
312
+ * The invoked agent's version, set as `gen_ai.agent.version`: the version of
313
+ * the agent DEFINITION this span invoked — its prompt, tools and policy.
314
+ * Taken verbatim; the conventions' own examples are `1.0.0` and
315
+ * `2025-05-01`, so there is no one format to hold callers to.
316
+ *
317
+ * Never derived from `service.version` (the build running this process) nor
318
+ * from the main-agent version (the agent this process IS): a process at one
319
+ * version can invoke agents at several others. Ignored on every other kind,
320
+ * like the name and the id it accompanies.
321
+ */
322
+ agentVersion?: string;
189
323
  /**
190
324
  * Identity attributes to set at span CREATION rather than after it. Pending
191
325
  * snapshots are built at start, so anything a caller would otherwise
@@ -202,6 +336,20 @@ declare class Observation {
202
336
  constructor(span: Span);
203
337
  setInput(value: unknown): this;
204
338
  setOutput(value: unknown): this;
339
+ /**
340
+ * Record what a retrieval returned, as `gen_ai.retrieval.documents`.
341
+ *
342
+ * The conventions define this as an array of objects, each with an optional
343
+ * `id` and an optional `score`. Identifiers and relevance, never document
344
+ * text, which is why it is not treated as content: it survives
345
+ * `captureContent: false` the way token counts do. Put the retrieved text in
346
+ * `setOutput` if you want it captured, and masking applies to it there.
347
+ *
348
+ * Unlike `dataSourceId` and `topK`, which describe the request and are
349
+ * passed at span creation, this is only knowable once the search has run, so
350
+ * it never reaches a pending snapshot.
351
+ */
352
+ setRetrievedDocuments(documents: unknown): this;
205
353
  /**
206
354
  * Set an arbitrary attribute. Primitives and homogeneous primitive arrays
207
355
  * are passed through as the OTel values they are; objects are JSON-encoded
@@ -217,8 +365,9 @@ declare class Observation {
217
365
  *
218
366
  * `error.type` is Conditionally Required by the GenAI conventions on every
219
367
  * span that ends in an error, and every helper's throw path funnels through
220
- * here, so this is the one place that sets it. The error's name only, never
221
- * the message: it must stay low-cardinality and free of echoed content.
368
+ * here, so this is the one place that sets it. The error's name or class
369
+ * (see errorType), never the message: it must stay low-cardinality and free
370
+ * of echoed content.
222
371
  *
223
372
  * Accepts `unknown` because that is what a `catch` binding is; a non-Error
224
373
  * throwable is wrapped so `recordException` still gets a real Error.
@@ -231,19 +380,35 @@ declare class Observation {
231
380
  /**
232
381
  * Create a span and return a handle. You MUST call end() (or use `using`).
233
382
  * The span is parented to whatever is current but does NOT become current.
383
+ *
384
+ * Because it never becomes current, an AGENT span created here opens no
385
+ * agent scope: a TOOL span started while it is open falls back to the
386
+ * configured agent name for `gen_ai.agent.name` rather than naming this one.
387
+ * Use {@link startAsCurrentSpan} (or `observe`) where that matters.
388
+ *
389
+ * The name is optional: omit it and the span is named the way the GenAI
390
+ * conventions say to, `{operation} {target}` — `execute_tool get_weather`,
391
+ * `invoke_agent planner`, `retrieval docs-index` — from the attributes it is
392
+ * being created with. A name you pass always wins.
234
393
  */
235
394
  declare function startSpan(name: string, options?: SpanOptions): Observation;
395
+ declare function startSpan(options?: SpanOptions): Observation;
236
396
  /** The body of a scoped span. */
237
397
  type SpanBody<T> = (observation: Observation) => Promise<T> | T;
238
398
  /**
239
399
  * Run `fn` with a new span active, so spans created inside it nest under this
240
400
  * one across async boundaries. Auto-ends, records exceptions, rethrows.
241
401
  *
242
- * `options` is optional, so the common case is `startAsCurrentSpan(name, fn)`
243
- * rather than `startAsCurrentSpan(name, {}, fn)`. The callback stays last.
402
+ * Both the name and `options` are optional, and the callback always comes
403
+ * last: `startAsCurrentSpan(name, fn)`, `startAsCurrentSpan(options, fn)` and
404
+ * `startAsCurrentSpan(fn)` all work, as does the full three-argument form.
405
+ * Omitting the name asks for the conventions' `{operation} {target}` name;
406
+ * see {@link startSpan}.
244
407
  */
245
408
  declare function startAsCurrentSpan<T>(name: string, fn: SpanBody<T>): Promise<T>;
246
409
  declare function startAsCurrentSpan<T>(name: string, options: SpanOptions, fn: SpanBody<T>): Promise<T>;
410
+ declare function startAsCurrentSpan<T>(options: SpanOptions, fn: SpanBody<T>): Promise<T>;
411
+ declare function startAsCurrentSpan<T>(fn: SpanBody<T>): Promise<T>;
247
412
 
248
413
  /**
249
414
  * Options for {@link startGeneration} and {@link startAsCurrentGeneration}:
@@ -254,17 +419,26 @@ interface GenerationOptions {
254
419
  provider?: string;
255
420
  input?: unknown;
256
421
  /**
257
- * Request parameters, each recorded as `gen_ai.request.<key>` — for example
258
- * `{ temperature: 0.2, max_tokens: 512 }`. Keys are passed through verbatim,
259
- * so use the provider's own parameter names.
422
+ * Request parameters, for example `{ temperature: 0.2, max_tokens: 512 }`,
423
+ * recorded at span creation so they ride pending snapshots.
424
+ *
425
+ * A parameter the GenAI conventions define, under its canonical name or a
426
+ * recognised provider spelling (OpenAI's `max_completion_tokens`, Google's
427
+ * `maxOutputTokens`, a camelCase `topP`), is recorded under its canonical
428
+ * `gen_ai.request.*` key and only that one. Everything else is recorded
429
+ * under `rius.request.<key>`, this SDK's own namespace, with the key
430
+ * otherwise untouched. Values that are not scalars or homogeneous scalar
431
+ * arrays are JSON-encoded; `null` and `undefined` mean "not set" and are
432
+ * skipped. The `model` and `reasoningLevel` options win over a parameter
433
+ * that maps to the same key.
260
434
  */
261
435
  modelParameters?: Record<string, unknown>;
262
436
  /**
263
437
  * Requested reasoning/thinking effort level
264
438
  * (`gen_ai.request.reasoning.level`), e.g. OpenAI's `reasoning.effort`
265
- * values. Provider-defined string, recorded verbatim. A first-class option
266
- * because the `modelParameters` pass-through would spell the key
267
- * `gen_ai.request.reasoning_level`, which is not the convention's name.
439
+ * values. Provider-defined string, recorded verbatim. Passing
440
+ * `reasoning_effort` through `modelParameters` lands on the same key; this
441
+ * option wins when both are given.
268
442
  */
269
443
  reasoningLevel?: string;
270
444
  /**
@@ -277,6 +451,17 @@ interface GenerationOptions {
277
451
  * creation and, for the scoped variant, on every span opened inside it.
278
452
  */
279
453
  userId?: string;
454
+ /**
455
+ * The output modality requested of the model (`gen_ai.output.type`) —
456
+ * `"text"`, `"json"`, `"image"` or `"speech"` per the conventions, which
457
+ * make it Conditionally Required when the request asks for a specific
458
+ * output format. An option rather than a setter because it is a property of
459
+ * the REQUEST: known before the call, so it is set at span creation and
460
+ * reaches pending snapshots. The string is recorded verbatim, not validated
461
+ * against the four members: the enum is open, and a provider's own spelling
462
+ * is still what the caller asked for.
463
+ */
464
+ outputType?: string;
280
465
  /**
281
466
  * Operation name (`gen_ai.operation.name`); default `"chat"`. Set it for
282
467
  * `text_completion`, `embeddings` or `generate_content` calls, as the
@@ -294,11 +479,28 @@ declare class Generation extends Observation {
294
479
  * time, so this is what `recordFirstToken` measures the first chunk against.
295
480
  */
296
481
  private readonly startedAt;
482
+ /**
483
+ * The latest normalized input / output and the tool definitions, kept so
484
+ * `rius.context.sizes` can be computed from all three once, in {@link end}.
485
+ */
486
+ private inputMessages?;
487
+ private outputMessages?;
488
+ private tools?;
297
489
  /**
298
490
  * The provider passed at creation; drives the Anthropic input-token summing
299
491
  * in {@link setUsage}. A bare `new Generation(span)` has none and never sums.
300
492
  */
301
493
  constructor(span: ConstructorParameters<typeof Observation>[0], provider?: string | undefined);
494
+ /**
495
+ * Computed once, as the span ends, rather than on every content write: a
496
+ * generation with tools, input and output would otherwise pay for it three
497
+ * times, and only the last result matters. Derived from the normalized
498
+ * messages BEFORE truncation, which is what makes it trustworthy when the
499
+ * content attributes are not.
500
+ */
501
+ private setContextSizes;
502
+ /** Ends the span after recording the context sizes; idempotent like the base. */
503
+ end(): void;
302
504
  /**
303
505
  * Record the request messages (`gen_ai.input.messages`), normalised to the
304
506
  * GenAI `{role, parts}` shape like the Python SDK does: bare strings, OpenAI
@@ -318,6 +520,15 @@ declare class Generation extends Observation {
318
520
  */
319
521
  setToolDefinitions(tools: unknown[]): this;
320
522
  setModel(model: string): this;
523
+ /**
524
+ * The provider's identifier for this completion (`gen_ai.response.id`) —
525
+ * OpenAI's `id`, Anthropic's `id`, and so on. A post-call setter and not a
526
+ * creation option for the reason `setModel` is one: the value arrives WITH
527
+ * the response, so no span can carry it at creation and no pending snapshot
528
+ * can either. Recorded verbatim; it is an opaque provider string, and it is
529
+ * not content, so it survives `captureContent: false`.
530
+ */
531
+ setResponseId(id: string): this;
321
532
  /**
322
533
  * Token usage (`gen_ai.usage.*`). Pass provider-reported values as-is;
323
534
  * never pre-add anything. Per the GenAI conventions, `inputTokens` is the
@@ -364,23 +575,82 @@ declare class Generation extends Observation {
364
575
  */
365
576
  recordFirstToken(): this;
366
577
  }
367
- /** Create a generation span and return a handle. You MUST call end(). */
578
+ /**
579
+ * Create a generation span and return a handle. You MUST call end().
580
+ *
581
+ * The name is optional; omitted, the span is named `{operation} {model}`.
582
+ */
368
583
  declare function startGeneration(name: string, options?: GenerationOptions): Generation;
584
+ declare function startGeneration(options?: GenerationOptions): Generation;
369
585
  /** The body of a scoped generation. */
370
586
  type GenerationBody<T> = (generation: Generation) => Promise<T> | T;
371
587
  /**
372
588
  * Run `fn` with a generation span active. Auto-ends, records exceptions.
373
589
  *
374
- * `options` is optional, so `startAsCurrentGeneration(name, fn)` works without
375
- * an empty object. The callback stays last.
590
+ * Both the name and `options` are optional and the callback stays last, so
591
+ * `startAsCurrentGeneration({ model: "gpt-4o" }, fn)` names the span
592
+ * `chat gpt-4o` for you.
376
593
  */
377
594
  declare function startAsCurrentGeneration<T>(name: string, fn: GenerationBody<T>): Promise<T>;
378
595
  declare function startAsCurrentGeneration<T>(name: string, options: GenerationOptions, fn: GenerationBody<T>): Promise<T>;
596
+ declare function startAsCurrentGeneration<T>(options: GenerationOptions, fn: GenerationBody<T>): Promise<T>;
597
+ declare function startAsCurrentGeneration<T>(fn: GenerationBody<T>): Promise<T>;
379
598
 
380
599
  /** Options for {@link observe}. */
381
600
  interface ObserveOptions {
382
601
  name?: string;
383
602
  kind?: SpanKind;
603
+ /**
604
+ * The tool name a TOOL-kind wrapper carries as `gen_ai.tool.name`. Defaults
605
+ * to the span name, so a wrapped function whose name IS the tool name needs
606
+ * nothing; pass it when the two differ.
607
+ */
608
+ toolName?: string;
609
+ /**
610
+ * The id of the model tool-call a TOOL-kind wrapper answers, set as
611
+ * `gen_ai.tool.call.id`. Only the caller has it — a wrapper sees the
612
+ * arguments, never the assistant message that produced them — so it is
613
+ * passed or omitted, never derived. Ignored on every other kind.
614
+ */
615
+ toolCallId?: string;
616
+ /**
617
+ * What kind of tool a TOOL-kind wrapper runs, set as `gen_ai.tool.type`
618
+ * (`"function"`, `"extension"`, `"datastore"`). Recorded verbatim and never
619
+ * inferred from the wrapped callable: the wrapper shape says nothing about
620
+ * where the tool actually executes. Ignored on every other kind.
621
+ */
622
+ toolType?: string;
623
+ /**
624
+ * The index, collection or knowledge base a RETRIEVER-kind wrapper searched,
625
+ * set as `gen_ai.data_source.id`. Ignored on every other kind.
626
+ */
627
+ dataSourceId?: string;
628
+ /**
629
+ * How many documents a RETRIEVER-kind wrapper asked for, set as
630
+ * `gen_ai.retrieval.top_k`. Ignored on every other kind.
631
+ */
632
+ topK?: number;
633
+ /**
634
+ * The agent an AGENT-kind wrapper invokes, set as `gen_ai.agent.name`.
635
+ * Unset, it falls back to the agent name `init()` was given; it is never
636
+ * taken from the wrapped function's name. Ignored on every other kind.
637
+ *
638
+ * It also scopes the call: TOOL spans opened while the wrapped function
639
+ * runs carry this name as the agent that EXECUTED them, which is what the
640
+ * same key means on an execute-tool span.
641
+ */
642
+ agentName?: string;
643
+ /**
644
+ * The invoked agent's identifier (`gen_ai.agent.id`). For a HOSTED agent
645
+ * resource such as a Bedrock agent ARN; an in-process agent leaves it unset.
646
+ */
647
+ agentId?: string;
648
+ /**
649
+ * The invoked agent's version (`gen_ai.agent.version`): the version of the
650
+ * agent definition, taken verbatim and never derived from the service
651
+ * version or from the version of the agent this process is.
652
+ */
653
+ agentVersion?: string;
384
654
  captureInput?: boolean;
385
655
  captureOutput?: boolean;
386
656
  }
@@ -464,6 +734,6 @@ declare function withSession<T>(sessionId: string, fn: (sessionId: string) => T)
464
734
  */
465
735
  declare function withUser<T>(userId: string, fn: (userId: string) => T): T;
466
736
 
467
- declare const VERSION = "0.8.0";
737
+ declare const VERSION = "1.0.0";
468
738
 
469
739
  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 };