@glassflow-ai/rius 0.6.1 → 0.7.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 CHANGED
@@ -373,7 +373,7 @@ function kindAttributes(kind) {
373
373
  if (operation !== void 0) attributes[GEN_AI_OPERATION_NAME] = operation;
374
374
  return attributes;
375
375
  }
376
- var TRACER_NAME, SERVICE_INSTANCE_ID, OPENINFERENCE_SPAN_KIND, INPUT_VALUE, OUTPUT_VALUE, SESSION_ID, USER_ID, WORKSPACE_ROUTE, GEN_AI_OPERATION_NAME, GEN_AI_PROVIDER_NAME, GEN_AI_REQUEST_MODEL, GEN_AI_REQUEST_REASONING_LEVEL, GEN_AI_RESPONSE_MODEL, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, GEN_AI_USAGE_CACHE_WRITE_INPUT_TOKENS, GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, GEN_AI_INPUT_MESSAGES, GEN_AI_OUTPUT_MESSAGES, GEN_AI_RESPONSE_FINISH_REASONS, GEN_AI_TOOL_NAME, GEN_AI_TOOL_DEFINITIONS, GEN_AI_REQUEST_PREFIX, MCP_RESULT_TYPE, GEN_AI_FIRST_TOKEN_EVENT, SpanKind, OPERATION_BY_KIND, CONTENT_ATTRIBUTES, LLM_INVOCATION_PARAMETERS, INVOCATION_PARAMETERS_CONTENT_MEMBERS, CONTENT_ATTRIBUTE_PREFIXES, CONTENT_ATTRIBUTE_SUFFIXES, GLASSFLOW_SPAN_PENDING, PENDING_IDENTITY_ATTRIBUTES, PENDING_IDENTITY_PREFIXES;
376
+ var TRACER_NAME, SERVICE_INSTANCE_ID, OPENINFERENCE_SPAN_KIND, INPUT_VALUE, OUTPUT_VALUE, SESSION_ID, USER_ID, WORKSPACE_ROUTE, GEN_AI_OPERATION_NAME, GEN_AI_PROVIDER_NAME, GEN_AI_REQUEST_MODEL, GEN_AI_REQUEST_REASONING_LEVEL, GEN_AI_RESPONSE_MODEL, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, GEN_AI_USAGE_CACHE_WRITE_INPUT_TOKENS, GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, GEN_AI_INPUT_MESSAGES, GEN_AI_OUTPUT_MESSAGES, GEN_AI_RESPONSE_FINISH_REASONS, GEN_AI_TOOL_NAME, GEN_AI_TOOL_DEFINITIONS, GEN_AI_REQUEST_PREFIX, MCP_METHOD_NAME, MCP_METHOD_TOOLS_CALL, MCP_PROTOCOL_VERSION, ERROR_TYPE, ERROR_TYPE_TOOL_ERROR, MCP_RESULT_TYPE, GEN_AI_FIRST_TOKEN_EVENT, SpanKind, OPERATION_BY_KIND, CONTENT_ATTRIBUTES, LLM_INVOCATION_PARAMETERS, INVOCATION_PARAMETERS_CONTENT_MEMBERS, CONTENT_ATTRIBUTE_PREFIXES, CONTENT_ATTRIBUTE_SUFFIXES, GLASSFLOW_SPAN_PENDING, PENDING_IDENTITY_ATTRIBUTES, PENDING_IDENTITY_PREFIXES;
377
377
  var init_semconv = __esm({
378
378
  "src/semconv.ts"() {
379
379
  "use strict";
@@ -402,6 +402,11 @@ var init_semconv = __esm({
402
402
  GEN_AI_TOOL_NAME = "gen_ai.tool.name";
403
403
  GEN_AI_TOOL_DEFINITIONS = "gen_ai.tool.definitions";
404
404
  GEN_AI_REQUEST_PREFIX = "gen_ai.request.";
405
+ MCP_METHOD_NAME = "mcp.method.name";
406
+ MCP_METHOD_TOOLS_CALL = "tools/call";
407
+ MCP_PROTOCOL_VERSION = "mcp.protocol.version";
408
+ ERROR_TYPE = "error.type";
409
+ ERROR_TYPE_TOOL_ERROR = "tool_error";
405
410
  MCP_RESULT_TYPE = "mcp.result_type";
406
411
  GEN_AI_FIRST_TOKEN_EVENT = "gen_ai.first_token";
407
412
  SpanKind = /* @__PURE__ */ ((SpanKind2) => {
@@ -503,6 +508,11 @@ var init_semconv = __esm({
503
508
  GEN_AI_OPERATION_NAME,
504
509
  GEN_AI_PROVIDER_NAME,
505
510
  GEN_AI_TOOL_NAME,
511
+ // Protocol identity, not content: a still-running MCP call must be
512
+ // distinguishable from a local tool in the live view — the one place
513
+ // setting the marker at creation pays off.
514
+ MCP_METHOD_NAME,
515
+ MCP_PROTOCOL_VERSION,
506
516
  // Identity, not content: a pending span must be groupable into its
507
517
  // session while still running, that is the live view's whole point.
508
518
  SESSION_ID,
@@ -531,6 +541,9 @@ function renderable(raw, value) {
531
541
  if (raw instanceof ArrayBuffer) return `<ArrayBuffer ${raw.byteLength} bytes>`;
532
542
  return value;
533
543
  }
544
+ function asRecord(value) {
545
+ return typeof value === "object" && value !== null ? value : void 0;
546
+ }
534
547
  function toAttributeValue(value) {
535
548
  if (typeof value === "string") return truncate(value);
536
549
  if (typeof value === "number" || typeof value === "boolean") return value;
@@ -603,7 +616,10 @@ function creationAttributes(options) {
603
616
  return attributes;
604
617
  }
605
618
  function startSpan(name, options = {}) {
606
- const span = getTracer().startSpan(name, { attributes: creationAttributes(options) });
619
+ const span = getTracer().startSpan(name, {
620
+ kind: options.otelKind,
621
+ attributes: creationAttributes(options)
622
+ });
607
623
  return configure(new Observation(span), options);
608
624
  }
609
625
  function startAsCurrentSpan(name, optionsOrFn, maybeFn) {
@@ -613,11 +629,12 @@ function startAsCurrentSpan(name, optionsOrFn, maybeFn) {
613
629
  creationAttributes(options),
614
630
  options.userId,
615
631
  (span) => configure(new Observation(span), options),
616
- fn
632
+ fn,
633
+ options.otelKind
617
634
  );
618
635
  }
619
- function runActive(name, attributes, userId, makeHandle, fn) {
620
- const run = () => getTracer().startActiveSpan(name, { attributes }, async (span) => {
636
+ function runActive(name, attributes, userId, makeHandle, fn, otelKind) {
637
+ const run = () => getTracer().startActiveSpan(name, { kind: otelKind, attributes }, async (span) => {
621
638
  const handle = makeHandle(span);
622
639
  try {
623
640
  return await fn(handle);
@@ -711,27 +728,25 @@ __export(instrumentationMcp_exports, {
711
728
  instrumentMcpClient: () => instrumentMcpClient
712
729
  });
713
730
  function serializeResult(result) {
714
- if (typeof result !== "object" || result === null) return toAttributeValue(result);
715
- const record = result;
731
+ const record = asRecord(result);
732
+ if (record === void 0) return toAttributeValue(result);
716
733
  const structured = record.structured_content ?? record.structuredContent;
717
734
  if (structured !== void 0 && structured !== null) return toAttributeValue(structured);
718
735
  const content = record.content;
719
736
  if (Array.isArray(content)) {
720
- const texts = content.map(
721
- (block) => typeof block === "object" && block !== null ? block.text : void 0
722
- ).filter((text) => typeof text === "string");
737
+ const texts = content.map((block) => asRecord(block)?.text).filter((text) => typeof text === "string");
723
738
  if (texts.length === 1) return truncate(texts[0]);
724
739
  if (texts.length > 1) return toAttributeValue(texts);
725
740
  }
726
741
  return toAttributeValue(result);
727
742
  }
728
743
  function resultIsError(result) {
729
- if (typeof result !== "object" || result === null) return false;
730
- const record = result;
731
- return Boolean(record.is_error ?? record.isError);
744
+ const record = asRecord(result);
745
+ return Boolean(record?.is_error ?? record?.isError);
732
746
  }
733
747
  function recordResult(observation, result) {
734
- const resultType = typeof result === "object" && result !== null ? result.result_type ?? result.resultType : void 0;
748
+ const record = asRecord(result);
749
+ const resultType = record?.result_type ?? record?.resultType;
735
750
  if (resultType === INPUT_REQUIRED) {
736
751
  observation.setAttribute(MCP_RESULT_TYPE, INPUT_REQUIRED);
737
752
  return;
@@ -742,8 +757,24 @@ function recordResult(observation, result) {
742
757
  code: import_api3.SpanStatusCode.ERROR,
743
758
  message: "tool returned an error result"
744
759
  });
760
+ observation.setAttribute(ERROR_TYPE, ERROR_TYPE_TOOL_ERROR);
745
761
  }
746
762
  }
763
+ function errorType(error) {
764
+ return error instanceof Error ? error.name : typeof error;
765
+ }
766
+ function negotiatedProtocolVersion(client) {
767
+ const version = asRecord(asRecord(client)?.transport)?.protocolVersion;
768
+ return typeof version === "string" ? version : void 0;
769
+ }
770
+ function callAttributes(toolName, protocolVersion) {
771
+ const attributes = {
772
+ [GEN_AI_TOOL_NAME]: toolName,
773
+ [MCP_METHOD_NAME]: MCP_METHOD_TOOLS_CALL
774
+ };
775
+ if (protocolVersion !== void 0) attributes[MCP_PROTOCOL_VERSION] = protocolVersion;
776
+ return attributes;
777
+ }
747
778
  function instrumentMcpClient(ClientClass) {
748
779
  const current = ClientClass.prototype.callTool;
749
780
  const alreadyWrapped = current.riusOriginal;
@@ -756,15 +787,23 @@ function instrumentMcpClient(ClientClass) {
756
787
  const instrumented = function instrumentedCallTool(params, ...rest) {
757
788
  return startAsCurrentSpan(
758
789
  `execute_tool ${params.name}`,
759
- // Tool name at CREATION: pending snapshots are built at start, so an
760
- // attribute set inside the callback never reaches them.
761
790
  {
762
791
  kind: "TOOL" /* TOOL */,
792
+ // The OTel SpanKind FIELD (orthogonal to our taxonomy attribute above):
793
+ // a remote tool call is CLIENT under both the MCP and the GenAI
794
+ // execute-tool conventions.
795
+ otelKind: import_api3.SpanKind.CLIENT,
763
796
  input: params.arguments,
764
- attributes: { [GEN_AI_TOOL_NAME]: params.name }
797
+ attributes: callAttributes(params.name, negotiatedProtocolVersion(this))
765
798
  },
766
799
  async (observation) => {
767
- const result = await original.call(this, params, ...rest);
800
+ let result;
801
+ try {
802
+ result = await original.call(this, params, ...rest);
803
+ } catch (error) {
804
+ observation.setAttribute(ERROR_TYPE, errorType(error));
805
+ throw error;
806
+ }
768
807
  recordResult(observation, result);
769
808
  return result;
770
809
  }
@@ -1835,7 +1874,7 @@ init_session();
1835
1874
  init_user();
1836
1875
  init_spans();
1837
1876
  init_workspace();
1838
- var VERSION = "0.6.1";
1877
+ var VERSION = "0.7.0";
1839
1878
  // Annotate the CommonJS export names for ESM import in node:
1840
1879
  0 && (module.exports = {
1841
1880
  Generation,
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { Tracer, Span } from '@opentelemetry/api';
1
+ import { Tracer, Span, SpanKind as SpanKind$1 } from '@opentelemetry/api';
2
2
  import { SpanExporter } from '@opentelemetry/sdk-trace-base';
3
3
 
4
4
  /** Redacts content attribute values at export. Receives the key when it accepts one. */
@@ -171,6 +171,13 @@ declare enum SpanKind {
171
171
  /** Options for {@link startSpan} and {@link startAsCurrentSpan}. */
172
172
  interface SpanOptions {
173
173
  kind?: SpanKind;
174
+ /**
175
+ * The OpenTelemetry `SpanKind` FIELD (INTERNAL, CLIENT, …), orthogonal to
176
+ * `kind` above, which is our taxonomy attribute. Conventions set it per
177
+ * operation — a remote tool call is CLIENT — so it is opt-in here and left
178
+ * at the tracer's default (INTERNAL) otherwise.
179
+ */
180
+ otelKind?: SpanKind$1;
174
181
  input?: unknown;
175
182
  /**
176
183
  * End-user identity (`user.id`). Sugar for `withUser`: set on this span at
@@ -441,6 +448,6 @@ declare function withSession<T>(sessionId: string, fn: (sessionId: string) => T)
441
448
  */
442
449
  declare function withUser<T>(userId: string, fn: (userId: string) => T): T;
443
450
 
444
- declare const VERSION = "0.6.1";
451
+ declare const VERSION = "0.7.0";
445
452
 
446
453
  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
@@ -1,4 +1,4 @@
1
- import { Tracer, Span } from '@opentelemetry/api';
1
+ import { Tracer, Span, SpanKind as SpanKind$1 } from '@opentelemetry/api';
2
2
  import { SpanExporter } from '@opentelemetry/sdk-trace-base';
3
3
 
4
4
  /** Redacts content attribute values at export. Receives the key when it accepts one. */
@@ -171,6 +171,13 @@ declare enum SpanKind {
171
171
  /** Options for {@link startSpan} and {@link startAsCurrentSpan}. */
172
172
  interface SpanOptions {
173
173
  kind?: SpanKind;
174
+ /**
175
+ * The OpenTelemetry `SpanKind` FIELD (INTERNAL, CLIENT, …), orthogonal to
176
+ * `kind` above, which is our taxonomy attribute. Conventions set it per
177
+ * operation — a remote tool call is CLIENT — so it is opt-in here and left
178
+ * at the tracer's default (INTERNAL) otherwise.
179
+ */
180
+ otelKind?: SpanKind$1;
174
181
  input?: unknown;
175
182
  /**
176
183
  * End-user identity (`user.id`). Sugar for `withUser`: set on this span at
@@ -441,6 +448,6 @@ declare function withSession<T>(sessionId: string, fn: (sessionId: string) => T)
441
448
  */
442
449
  declare function withUser<T>(userId: string, fn: (userId: string) => T): T;
443
450
 
444
- declare const VERSION = "0.6.1";
451
+ declare const VERSION = "0.7.0";
445
452
 
446
453
  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.js CHANGED
@@ -360,7 +360,7 @@ function kindAttributes(kind) {
360
360
  if (operation !== void 0) attributes[GEN_AI_OPERATION_NAME] = operation;
361
361
  return attributes;
362
362
  }
363
- var TRACER_NAME, SERVICE_INSTANCE_ID, OPENINFERENCE_SPAN_KIND, INPUT_VALUE, OUTPUT_VALUE, SESSION_ID, USER_ID, WORKSPACE_ROUTE, GEN_AI_OPERATION_NAME, GEN_AI_PROVIDER_NAME, GEN_AI_REQUEST_MODEL, GEN_AI_REQUEST_REASONING_LEVEL, GEN_AI_RESPONSE_MODEL, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, GEN_AI_USAGE_CACHE_WRITE_INPUT_TOKENS, GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, GEN_AI_INPUT_MESSAGES, GEN_AI_OUTPUT_MESSAGES, GEN_AI_RESPONSE_FINISH_REASONS, GEN_AI_TOOL_NAME, GEN_AI_TOOL_DEFINITIONS, GEN_AI_REQUEST_PREFIX, MCP_RESULT_TYPE, GEN_AI_FIRST_TOKEN_EVENT, SpanKind, OPERATION_BY_KIND, CONTENT_ATTRIBUTES, LLM_INVOCATION_PARAMETERS, INVOCATION_PARAMETERS_CONTENT_MEMBERS, CONTENT_ATTRIBUTE_PREFIXES, CONTENT_ATTRIBUTE_SUFFIXES, GLASSFLOW_SPAN_PENDING, PENDING_IDENTITY_ATTRIBUTES, PENDING_IDENTITY_PREFIXES;
363
+ var TRACER_NAME, SERVICE_INSTANCE_ID, OPENINFERENCE_SPAN_KIND, INPUT_VALUE, OUTPUT_VALUE, SESSION_ID, USER_ID, WORKSPACE_ROUTE, GEN_AI_OPERATION_NAME, GEN_AI_PROVIDER_NAME, GEN_AI_REQUEST_MODEL, GEN_AI_REQUEST_REASONING_LEVEL, GEN_AI_RESPONSE_MODEL, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, GEN_AI_USAGE_CACHE_WRITE_INPUT_TOKENS, GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, GEN_AI_INPUT_MESSAGES, GEN_AI_OUTPUT_MESSAGES, GEN_AI_RESPONSE_FINISH_REASONS, GEN_AI_TOOL_NAME, GEN_AI_TOOL_DEFINITIONS, GEN_AI_REQUEST_PREFIX, MCP_METHOD_NAME, MCP_METHOD_TOOLS_CALL, MCP_PROTOCOL_VERSION, ERROR_TYPE, ERROR_TYPE_TOOL_ERROR, MCP_RESULT_TYPE, GEN_AI_FIRST_TOKEN_EVENT, SpanKind, OPERATION_BY_KIND, CONTENT_ATTRIBUTES, LLM_INVOCATION_PARAMETERS, INVOCATION_PARAMETERS_CONTENT_MEMBERS, CONTENT_ATTRIBUTE_PREFIXES, CONTENT_ATTRIBUTE_SUFFIXES, GLASSFLOW_SPAN_PENDING, PENDING_IDENTITY_ATTRIBUTES, PENDING_IDENTITY_PREFIXES;
364
364
  var init_semconv = __esm({
365
365
  "src/semconv.ts"() {
366
366
  "use strict";
@@ -389,6 +389,11 @@ var init_semconv = __esm({
389
389
  GEN_AI_TOOL_NAME = "gen_ai.tool.name";
390
390
  GEN_AI_TOOL_DEFINITIONS = "gen_ai.tool.definitions";
391
391
  GEN_AI_REQUEST_PREFIX = "gen_ai.request.";
392
+ MCP_METHOD_NAME = "mcp.method.name";
393
+ MCP_METHOD_TOOLS_CALL = "tools/call";
394
+ MCP_PROTOCOL_VERSION = "mcp.protocol.version";
395
+ ERROR_TYPE = "error.type";
396
+ ERROR_TYPE_TOOL_ERROR = "tool_error";
392
397
  MCP_RESULT_TYPE = "mcp.result_type";
393
398
  GEN_AI_FIRST_TOKEN_EVENT = "gen_ai.first_token";
394
399
  SpanKind = /* @__PURE__ */ ((SpanKind2) => {
@@ -490,6 +495,11 @@ var init_semconv = __esm({
490
495
  GEN_AI_OPERATION_NAME,
491
496
  GEN_AI_PROVIDER_NAME,
492
497
  GEN_AI_TOOL_NAME,
498
+ // Protocol identity, not content: a still-running MCP call must be
499
+ // distinguishable from a local tool in the live view — the one place
500
+ // setting the marker at creation pays off.
501
+ MCP_METHOD_NAME,
502
+ MCP_PROTOCOL_VERSION,
493
503
  // Identity, not content: a pending span must be groupable into its
494
504
  // session while still running, that is the live view's whole point.
495
505
  SESSION_ID,
@@ -518,6 +528,9 @@ function renderable(raw, value) {
518
528
  if (raw instanceof ArrayBuffer) return `<ArrayBuffer ${raw.byteLength} bytes>`;
519
529
  return value;
520
530
  }
531
+ function asRecord(value) {
532
+ return typeof value === "object" && value !== null ? value : void 0;
533
+ }
521
534
  function toAttributeValue(value) {
522
535
  if (typeof value === "string") return truncate(value);
523
536
  if (typeof value === "number" || typeof value === "boolean") return value;
@@ -591,7 +604,10 @@ function creationAttributes(options) {
591
604
  return attributes;
592
605
  }
593
606
  function startSpan(name, options = {}) {
594
- const span = getTracer().startSpan(name, { attributes: creationAttributes(options) });
607
+ const span = getTracer().startSpan(name, {
608
+ kind: options.otelKind,
609
+ attributes: creationAttributes(options)
610
+ });
595
611
  return configure(new Observation(span), options);
596
612
  }
597
613
  function startAsCurrentSpan(name, optionsOrFn, maybeFn) {
@@ -601,11 +617,12 @@ function startAsCurrentSpan(name, optionsOrFn, maybeFn) {
601
617
  creationAttributes(options),
602
618
  options.userId,
603
619
  (span) => configure(new Observation(span), options),
604
- fn
620
+ fn,
621
+ options.otelKind
605
622
  );
606
623
  }
607
- function runActive(name, attributes, userId, makeHandle, fn) {
608
- const run = () => getTracer().startActiveSpan(name, { attributes }, async (span) => {
624
+ function runActive(name, attributes, userId, makeHandle, fn, otelKind) {
625
+ const run = () => getTracer().startActiveSpan(name, { kind: otelKind, attributes }, async (span) => {
609
626
  const handle = makeHandle(span);
610
627
  try {
611
628
  return await fn(handle);
@@ -697,29 +714,27 @@ var instrumentationMcp_exports = {};
697
714
  __export(instrumentationMcp_exports, {
698
715
  instrumentMcpClient: () => instrumentMcpClient
699
716
  });
700
- import { SpanStatusCode as SpanStatusCode2 } from "@opentelemetry/api";
717
+ import { SpanKind as OtelSpanKind, SpanStatusCode as SpanStatusCode2 } from "@opentelemetry/api";
701
718
  function serializeResult(result) {
702
- if (typeof result !== "object" || result === null) return toAttributeValue(result);
703
- const record = result;
719
+ const record = asRecord(result);
720
+ if (record === void 0) return toAttributeValue(result);
704
721
  const structured = record.structured_content ?? record.structuredContent;
705
722
  if (structured !== void 0 && structured !== null) return toAttributeValue(structured);
706
723
  const content = record.content;
707
724
  if (Array.isArray(content)) {
708
- const texts = content.map(
709
- (block) => typeof block === "object" && block !== null ? block.text : void 0
710
- ).filter((text) => typeof text === "string");
725
+ const texts = content.map((block) => asRecord(block)?.text).filter((text) => typeof text === "string");
711
726
  if (texts.length === 1) return truncate(texts[0]);
712
727
  if (texts.length > 1) return toAttributeValue(texts);
713
728
  }
714
729
  return toAttributeValue(result);
715
730
  }
716
731
  function resultIsError(result) {
717
- if (typeof result !== "object" || result === null) return false;
718
- const record = result;
719
- return Boolean(record.is_error ?? record.isError);
732
+ const record = asRecord(result);
733
+ return Boolean(record?.is_error ?? record?.isError);
720
734
  }
721
735
  function recordResult(observation, result) {
722
- const resultType = typeof result === "object" && result !== null ? result.result_type ?? result.resultType : void 0;
736
+ const record = asRecord(result);
737
+ const resultType = record?.result_type ?? record?.resultType;
723
738
  if (resultType === INPUT_REQUIRED) {
724
739
  observation.setAttribute(MCP_RESULT_TYPE, INPUT_REQUIRED);
725
740
  return;
@@ -730,8 +745,24 @@ function recordResult(observation, result) {
730
745
  code: SpanStatusCode2.ERROR,
731
746
  message: "tool returned an error result"
732
747
  });
748
+ observation.setAttribute(ERROR_TYPE, ERROR_TYPE_TOOL_ERROR);
733
749
  }
734
750
  }
751
+ function errorType(error) {
752
+ return error instanceof Error ? error.name : typeof error;
753
+ }
754
+ function negotiatedProtocolVersion(client) {
755
+ const version = asRecord(asRecord(client)?.transport)?.protocolVersion;
756
+ return typeof version === "string" ? version : void 0;
757
+ }
758
+ function callAttributes(toolName, protocolVersion) {
759
+ const attributes = {
760
+ [GEN_AI_TOOL_NAME]: toolName,
761
+ [MCP_METHOD_NAME]: MCP_METHOD_TOOLS_CALL
762
+ };
763
+ if (protocolVersion !== void 0) attributes[MCP_PROTOCOL_VERSION] = protocolVersion;
764
+ return attributes;
765
+ }
735
766
  function instrumentMcpClient(ClientClass) {
736
767
  const current = ClientClass.prototype.callTool;
737
768
  const alreadyWrapped = current.riusOriginal;
@@ -744,15 +775,23 @@ function instrumentMcpClient(ClientClass) {
744
775
  const instrumented = function instrumentedCallTool(params, ...rest) {
745
776
  return startAsCurrentSpan(
746
777
  `execute_tool ${params.name}`,
747
- // Tool name at CREATION: pending snapshots are built at start, so an
748
- // attribute set inside the callback never reaches them.
749
778
  {
750
779
  kind: "TOOL" /* TOOL */,
780
+ // The OTel SpanKind FIELD (orthogonal to our taxonomy attribute above):
781
+ // a remote tool call is CLIENT under both the MCP and the GenAI
782
+ // execute-tool conventions.
783
+ otelKind: OtelSpanKind.CLIENT,
751
784
  input: params.arguments,
752
- attributes: { [GEN_AI_TOOL_NAME]: params.name }
785
+ attributes: callAttributes(params.name, negotiatedProtocolVersion(this))
753
786
  },
754
787
  async (observation) => {
755
- const result = await original.call(this, params, ...rest);
788
+ let result;
789
+ try {
790
+ result = await original.call(this, params, ...rest);
791
+ } catch (error) {
792
+ observation.setAttribute(ERROR_TYPE, errorType(error));
793
+ throw error;
794
+ }
756
795
  recordResult(observation, result);
757
796
  return result;
758
797
  }
@@ -1806,7 +1845,7 @@ init_session();
1806
1845
  init_user();
1807
1846
  init_spans();
1808
1847
  init_workspace();
1809
- var VERSION = "0.6.1";
1848
+ var VERSION = "0.7.0";
1810
1849
  export {
1811
1850
  Generation,
1812
1851
  Observation,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glassflow-ai/rius",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "OpenTelemetry-native tracing for AI agents and LLM applications",
5
5
  "keywords": [
6
6
  "opentelemetry",