@grafana/sigil-sdk-js 0.5.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.
Files changed (49) hide show
  1. package/README.md +9 -3
  2. package/dist/cache-diagnostics.d.ts +15 -0
  3. package/dist/cache-diagnostics.d.ts.map +1 -0
  4. package/dist/cache-diagnostics.js +15 -0
  5. package/dist/cache-diagnostics.js.map +1 -0
  6. package/dist/client.d.ts +5 -4
  7. package/dist/client.d.ts.map +1 -1
  8. package/dist/client.js +172 -53
  9. package/dist/client.js.map +1 -1
  10. package/dist/config.js +1 -1
  11. package/dist/config.js.map +1 -1
  12. package/dist/content_capture.d.ts +3 -4
  13. package/dist/content_capture.d.ts.map +1 -1
  14. package/dist/content_capture.js +7 -9
  15. package/dist/content_capture.js.map +1 -1
  16. package/dist/context.d.ts.map +1 -1
  17. package/dist/context.js +29 -2
  18. package/dist/context.js.map +1 -1
  19. package/dist/core.d.ts +13 -0
  20. package/dist/core.d.ts.map +1 -0
  21. package/dist/core.js +12 -0
  22. package/dist/core.js.map +1 -0
  23. package/dist/exporters/http.js +6 -1
  24. package/dist/exporters/http.js.map +1 -1
  25. package/dist/frameworks/vercel-ai-sdk/hooks.d.ts.map +1 -1
  26. package/dist/frameworks/vercel-ai-sdk/hooks.js +70 -39
  27. package/dist/frameworks/vercel-ai-sdk/hooks.js.map +1 -1
  28. package/dist/frameworks/vercel-ai-sdk/index.d.ts +1 -1
  29. package/dist/frameworks/vercel-ai-sdk/index.d.ts.map +1 -1
  30. package/dist/frameworks/vercel-ai-sdk/index.js +1 -1
  31. package/dist/frameworks/vercel-ai-sdk/index.js.map +1 -1
  32. package/dist/frameworks/vercel-ai-sdk/mapping.d.ts +9 -1
  33. package/dist/frameworks/vercel-ai-sdk/mapping.d.ts.map +1 -1
  34. package/dist/frameworks/vercel-ai-sdk/mapping.js +56 -0
  35. package/dist/frameworks/vercel-ai-sdk/mapping.js.map +1 -1
  36. package/dist/frameworks/vercel-ai-sdk/types.d.ts +6 -0
  37. package/dist/frameworks/vercel-ai-sdk/types.d.ts.map +1 -1
  38. package/dist/hooks.js +4 -1
  39. package/dist/hooks.js.map +1 -1
  40. package/dist/index.d.ts +1 -11
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +1 -10
  43. package/dist/index.js.map +1 -1
  44. package/dist/types.d.ts +13 -1
  45. package/dist/types.d.ts.map +1 -1
  46. package/dist/utils.d.ts.map +1 -1
  47. package/dist/utils.js +13 -2
  48. package/dist/utils.js.map +1 -1
  49. package/package.json +9 -9
package/README.md CHANGED
@@ -8,6 +8,12 @@ Sigil records normalized LLM generation and tool-execution telemetry using your
8
8
  pnpm add @grafana/sigil-sdk-js
9
9
  ```
10
10
 
11
+ For low-dependency runtimes that only need the core `SigilClient` and generation export APIs, use the slim core package:
12
+
13
+ ```bash
14
+ pnpm add @grafana/sigil-sdk-js-core
15
+ ```
16
+
11
17
  For a Grafana Cloud setup walkthrough (where to find the endpoint URL, instance ID, and API token), refer to the [Grafana Cloud setup guide](https://grafana.com/docs/grafana-cloud/machine-learning/ai-observability/get-started/grafana-cloud/).
12
18
 
13
19
  ## Validation
@@ -368,12 +374,12 @@ auth: {
368
374
  },
369
375
  ```
370
376
 
371
- ## Env-secret wiring example
377
+ ## Wiring custom env vars
372
378
 
373
- The SDK does not auto-load env vars. Resolve env secrets in your app and map them into config.
379
+ The SDK only auto-loads `SIGIL_*` env vars (`SIGIL_ENDPOINT`, `SIGIL_PROTOCOL`, `SIGIL_AUTH_MODE`, `SIGIL_AUTH_TOKEN`, etc.) when you call `new SigilClient()`. For any other env var (for example one your secret manager exposes under a different name), read it in your app and pass the value into the config:
374
380
 
375
381
  ```ts
376
- const generationBearerToken = (process.env.SIGIL_GEN_BEARER_TOKEN ?? "").trim();
382
+ const generationBearerToken = (process.env.MY_APP_SIGIL_TOKEN ?? "").trim();
377
383
 
378
384
  const client = new SigilClient({
379
385
  generationExport: {
@@ -0,0 +1,15 @@
1
+ import type { GenerationRecorder } from './types.js';
2
+ /** Reserved generation metadata keys (Sigil docs/guides/cache-diagnostics.md). */
3
+ export declare const CACHE_DIAGNOSTICS_MISS_REASON_KEY = "sigil.cache_diagnostics.miss_reason";
4
+ export declare const CACHE_DIAGNOSTICS_MISSED_INPUT_TOKENS_KEY = "sigil.cache_diagnostics.missed_input_tokens";
5
+ export declare const CACHE_DIAGNOSTICS_PREVIOUS_MESSAGE_ID_KEY = "sigil.cache_diagnostics.previous_message_id";
6
+ export type CacheDiagnosticsOptions = {
7
+ missedInputTokens?: number;
8
+ previousMessageId?: string;
9
+ };
10
+ /**
11
+ * Stamp `sigil.cache_diagnostics.*` metadata on a generation recorder.
12
+ * Call before `end()`, typically after the provider response is available.
13
+ */
14
+ export declare function setCacheDiagnostics(rec: GenerationRecorder | null | undefined, missReason: string, opts?: CacheDiagnosticsOptions): void;
15
+ //# sourceMappingURL=cache-diagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-diagnostics.d.ts","sourceRoot":"","sources":["../src/cache-diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,kFAAkF;AAClF,eAAO,MAAM,iCAAiC,wCAAwC,CAAC;AACvF,eAAO,MAAM,yCAAyC,gDAAgD,CAAC;AACvG,eAAO,MAAM,yCAAyC,gDAAgD,CAAC;AAEvG,MAAM,MAAM,uBAAuB,GAAG;IACpC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,kBAAkB,GAAG,IAAI,GAAG,SAAS,EAC1C,UAAU,EAAE,MAAM,EAClB,IAAI,CAAC,EAAE,uBAAuB,GAC7B,IAAI,CAKN"}
@@ -0,0 +1,15 @@
1
+ /** Reserved generation metadata keys (Sigil docs/guides/cache-diagnostics.md). */
2
+ export const CACHE_DIAGNOSTICS_MISS_REASON_KEY = 'sigil.cache_diagnostics.miss_reason';
3
+ export const CACHE_DIAGNOSTICS_MISSED_INPUT_TOKENS_KEY = 'sigil.cache_diagnostics.missed_input_tokens';
4
+ export const CACHE_DIAGNOSTICS_PREVIOUS_MESSAGE_ID_KEY = 'sigil.cache_diagnostics.previous_message_id';
5
+ /**
6
+ * Stamp `sigil.cache_diagnostics.*` metadata on a generation recorder.
7
+ * Call before `end()`, typically after the provider response is available.
8
+ */
9
+ export function setCacheDiagnostics(rec, missReason, opts) {
10
+ if (rec === null || rec === undefined) {
11
+ return;
12
+ }
13
+ rec.setCacheDiagnostics(missReason, opts);
14
+ }
15
+ //# sourceMappingURL=cache-diagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-diagnostics.js","sourceRoot":"","sources":["../src/cache-diagnostics.ts"],"names":[],"mappings":"AAEA,kFAAkF;AAClF,MAAM,CAAC,MAAM,iCAAiC,GAAG,qCAAqC,CAAC;AACvF,MAAM,CAAC,MAAM,yCAAyC,GAAG,6CAA6C,CAAC;AACvG,MAAM,CAAC,MAAM,yCAAyC,GAAG,6CAA6C,CAAC;AAOvG;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAA0C,EAC1C,UAAkB,EAClB,IAA8B;IAE9B,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtC,OAAO;IACT,CAAC;IACD,GAAG,CAAC,mBAAmB,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AAC5C,CAAC"}
package/dist/client.d.ts CHANGED
@@ -108,18 +108,19 @@ export declare class SigilClient {
108
108
  internalEnqueueGeneration(generation: Generation): void;
109
109
  internalLogWarn(message: string, error?: unknown): void;
110
110
  internalResolveGenerationContentCaptureMode(seed: GenerationStart): ContentCaptureMode;
111
- internalResolveToolIncludeContent(seed: ToolExecutionStart): boolean;
111
+ internalResolveEmbeddingContentCaptureMode(seed: EmbeddingStart): ContentCaptureMode;
112
+ internalResolveToolContentCaptureMode(seed: ToolExecutionStart): ContentCaptureMode;
112
113
  internalHasGenerationSanitizer(): boolean;
113
114
  internalSanitizeGeneration(generation: Generation): Generation;
114
- internalStartGenerationSpan(seed: GenerationStart, mode: GenerationMode, startedAt: Date): Span;
115
+ internalStartGenerationSpan(seed: GenerationStart, mode: GenerationMode, startedAt: Date, contentCaptureMode: ContentCaptureMode): Span;
115
116
  internalStartEmbeddingSpan(seed: EmbeddingStart, startedAt: Date): Span;
116
117
  internalStartToolExecutionSpan(seed: ToolExecutionStart, startedAt: Date): Span;
117
118
  internalApplyTraceContextFromSpan(span: Span, generation: Generation): void;
118
119
  internalSyncGenerationSpan(span: Span, generation: Generation): void;
119
120
  internalClearSpanConversationTitle(span: Span): void;
120
121
  internalFinalizeGenerationSpan(span: Span, generation: Generation, callError: string | undefined, validationError: Error | undefined, enqueueError: Error | undefined, firstTokenAt: Date | undefined, precomputedCallErrorCategory?: string): void;
121
- internalFinalizeEmbeddingSpan(span: Span, seed: EmbeddingStart, result: EmbeddingResult, hasResult: boolean, callError: Error | undefined, localError: Error | undefined, startedAt: Date, completedAt: Date): void;
122
- internalFinalizeToolExecutionSpan(span: Span, toolExecution: ToolExecution, localError: Error | undefined): Error | undefined;
122
+ internalFinalizeEmbeddingSpan(span: Span, seed: EmbeddingStart, result: EmbeddingResult, hasResult: boolean, callError: Error | undefined, localError: Error | undefined, startedAt: Date, completedAt: Date, contentCaptureMode?: ContentCaptureMode): void;
123
+ internalFinalizeToolExecutionSpan(span: Span, toolExecution: ToolExecution, localError: Error | undefined, contentCaptureMode?: ContentCaptureMode): Error | undefined;
123
124
  private recordGenerationMetrics;
124
125
  private recordEmbeddingMetrics;
125
126
  private recordTokenUsage;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -1,4 +1,5 @@
1
- import { metrics, SpanKind, SpanStatusCode, trace, } from '@opentelemetry/api';
1
+ import { context, metrics, SpanKind, SpanStatusCode, trace, } from '@opentelemetry/api';
2
+ import { CACHE_DIAGNOSTICS_MISS_REASON_KEY, CACHE_DIAGNOSTICS_MISSED_INPUT_TOKENS_KEY, CACHE_DIAGNOSTICS_PREVIOUS_MESSAGE_ID_KEY, } from './cache-diagnostics.js';
2
3
  import { defaultLogger, mergeConfig } from './config.js';
3
4
  import { callContentCaptureResolver, resolveClientContentCaptureMode, resolveContentCaptureMode, shouldIncludeToolContent, stampContentCaptureMetadata, stripContent, } from './content_capture.js';
4
5
  import { agentNameFromContext, agentVersionFromContext, conversationIdFromContext, conversationTitleFromContext, userIdFromContext, } from './context.js';
@@ -449,9 +450,16 @@ export class SigilClient {
449
450
  const clientMode = resolveClientContentCaptureMode(resolveContentCaptureMode(resolverMode, this.config.contentCapture));
450
451
  return resolveContentCaptureMode(seed.contentCapture ?? 'default', clientMode);
451
452
  }
452
- internalResolveToolIncludeContent(seed) {
453
+ internalResolveEmbeddingContentCaptureMode(seed) {
454
+ // Mirror generation resolution so a per-call resolver can hide
455
+ // gen_ai.embeddings.input_texts without changing the client default.
456
+ const resolverMode = callContentCaptureResolver(this.config.contentCaptureResolver, seed.metadata);
457
+ return resolveClientContentCaptureMode(resolveContentCaptureMode(resolverMode, this.config.contentCapture));
458
+ }
459
+ internalResolveToolContentCaptureMode(seed) {
453
460
  const resolverMode = callContentCaptureResolver(this.config.contentCaptureResolver, undefined);
454
- return shouldIncludeToolContent(seed.contentCapture ?? 'default', this.config.contentCapture, resolverMode, seed.includeContent ?? false);
461
+ const clientMode = resolveClientContentCaptureMode(resolveContentCaptureMode(resolverMode, this.config.contentCapture));
462
+ return resolveContentCaptureMode(seed.contentCapture ?? 'default', clientMode);
455
463
  }
456
464
  internalHasGenerationSanitizer() {
457
465
  return this.config.generationSanitizer !== undefined;
@@ -467,16 +475,23 @@ export class SigilClient {
467
475
  }
468
476
  return cloneGeneration(sanitized);
469
477
  }
470
- internalStartGenerationSpan(seed, mode, startedAt) {
478
+ internalStartGenerationSpan(seed, mode, startedAt, contentCaptureMode) {
471
479
  const operationName = seed.operationName ?? defaultOperationNameForMode(mode);
472
480
  const span = this.tracer.startSpan(generationSpanName(operationName, seed.model.name), {
473
481
  kind: SpanKind.CLIENT,
474
482
  startTime: startedAt,
475
483
  });
484
+ // metadata_only and full_with_metadata_spans both drop the title from
485
+ // the span. Under full_with_metadata_spans the proto payload still
486
+ // carries the title — it is rebuilt from `seed.conversationTitle` in
487
+ // end(), so we only zero the value sent to the span here.
488
+ const spanTitle = contentCaptureMode === 'metadata_only' || contentCaptureMode === 'full_with_metadata_spans'
489
+ ? undefined
490
+ : seed.conversationTitle;
476
491
  setGenerationSpanAttributes(span, {
477
492
  id: seed.id,
478
493
  conversationId: seed.conversationId,
479
- conversationTitle: seed.conversationTitle,
494
+ conversationTitle: spanTitle,
480
495
  userId: seed.userId,
481
496
  agentName: seed.agentName,
482
497
  agentVersion: seed.agentVersion,
@@ -559,16 +574,23 @@ export class SigilClient {
559
574
  else {
560
575
  span.setStatus({ code: SpanStatusCode.OK });
561
576
  }
562
- this.recordGenerationMetrics(generation, errorType, errorCategory, firstTokenAt);
577
+ const spanCtx = trace.setSpan(context.active(), span);
578
+ context.with(spanCtx, () => {
579
+ this.recordGenerationMetrics(generation, errorType, errorCategory, firstTokenAt);
580
+ });
563
581
  span.end(generation.completedAt);
564
582
  }
565
- internalFinalizeEmbeddingSpan(span, seed, result, hasResult, callError, localError, startedAt, completedAt) {
583
+ internalFinalizeEmbeddingSpan(span, seed, result, hasResult, callError, localError, startedAt, completedAt, contentCaptureMode = 'default') {
566
584
  span.updateName(embeddingSpanName(seed.model.name));
567
- setEmbeddingEndSpanAttributes(span, result, hasResult, this.config.embeddingCapture);
568
- if (callError !== undefined) {
585
+ setEmbeddingEndSpanAttributes(span, result, hasResult, this.config.embeddingCapture, contentCaptureMode);
586
+ // Redact span-side error text under both stripped modes. Embeddings have
587
+ // no proto export, so the raw provider error never escapes the span
588
+ // path; matches the generation full_with_metadata_spans contract.
589
+ const redactSpanErrors = contentCaptureMode === 'metadata_only' || contentCaptureMode === 'full_with_metadata_spans';
590
+ if (callError !== undefined && !redactSpanErrors) {
569
591
  span.recordException(callError);
570
592
  }
571
- if (localError !== undefined) {
593
+ if (localError !== undefined && !redactSpanErrors) {
572
594
  span.recordException(localError);
573
595
  }
574
596
  let errorType = '';
@@ -576,12 +598,18 @@ export class SigilClient {
576
598
  if (callError !== undefined) {
577
599
  errorType = 'provider_call_error';
578
600
  errorCategory = errorCategoryFromError(callError, true);
579
- span.setStatus({ code: SpanStatusCode.ERROR, message: callError.message });
601
+ span.setStatus({
602
+ code: SpanStatusCode.ERROR,
603
+ message: redactSpanErrors ? errorCategory : callError.message,
604
+ });
580
605
  }
581
606
  else if (localError !== undefined) {
582
607
  errorType = 'validation_error';
583
608
  errorCategory = 'sdk_error';
584
- span.setStatus({ code: SpanStatusCode.ERROR, message: localError.message });
609
+ span.setStatus({
610
+ code: SpanStatusCode.ERROR,
611
+ message: redactSpanErrors ? errorCategory : localError.message,
612
+ });
585
613
  }
586
614
  else {
587
615
  span.setStatus({ code: SpanStatusCode.OK });
@@ -590,10 +618,13 @@ export class SigilClient {
590
618
  span.setAttribute(spanAttrErrorType, errorType);
591
619
  span.setAttribute(spanAttrErrorCategory, errorCategory);
592
620
  }
593
- this.recordEmbeddingMetrics(seed, result, startedAt, completedAt, errorType, errorCategory);
621
+ const spanCtx = trace.setSpan(context.active(), span);
622
+ context.with(spanCtx, () => {
623
+ this.recordEmbeddingMetrics(seed, result, startedAt, completedAt, errorType, errorCategory);
624
+ });
594
625
  span.end(completedAt);
595
626
  }
596
- internalFinalizeToolExecutionSpan(span, toolExecution, localError) {
627
+ internalFinalizeToolExecutionSpan(span, toolExecution, localError, contentCaptureMode = 'default') {
597
628
  setToolSpanAttributes(span, toolExecution);
598
629
  if (toolExecution.includeContent) {
599
630
  const argumentsResult = serializeToolContent(toolExecution.arguments);
@@ -611,22 +642,41 @@ export class SigilClient {
611
642
  span.setAttribute(spanAttrToolCallResult, resultValue.value);
612
643
  }
613
644
  }
645
+ // Tools have no proto export; under both stripped modes the span must
646
+ // not echo raw provider exception text via recordException events or the
647
+ // status description.
648
+ const redactSpanErrors = contentCaptureMode === 'metadata_only' || contentCaptureMode === 'full_with_metadata_spans';
614
649
  if (toolExecution.callError !== undefined) {
615
- span.recordException(new Error(toolExecution.callError));
650
+ const errorCategory = errorCategoryFromError(toolExecution.callError, true);
651
+ if (!redactSpanErrors) {
652
+ span.recordException(new Error(toolExecution.callError));
653
+ }
616
654
  span.setAttribute(spanAttrErrorType, 'tool_execution_error');
617
- span.setAttribute(spanAttrErrorCategory, errorCategoryFromError(toolExecution.callError, true));
618
- span.setStatus({ code: SpanStatusCode.ERROR, message: toolExecution.callError });
655
+ span.setAttribute(spanAttrErrorCategory, errorCategory);
656
+ span.setStatus({
657
+ code: SpanStatusCode.ERROR,
658
+ message: redactSpanErrors ? errorCategory : toolExecution.callError,
659
+ });
619
660
  }
620
661
  else if (localError !== undefined) {
621
- span.recordException(localError);
662
+ const errorCategory = errorCategoryFromError(localError, true);
663
+ if (!redactSpanErrors) {
664
+ span.recordException(localError);
665
+ }
622
666
  span.setAttribute(spanAttrErrorType, 'tool_execution_error');
623
- span.setAttribute(spanAttrErrorCategory, errorCategoryFromError(localError, true));
624
- span.setStatus({ code: SpanStatusCode.ERROR, message: localError.message });
667
+ span.setAttribute(spanAttrErrorCategory, errorCategory);
668
+ span.setStatus({
669
+ code: SpanStatusCode.ERROR,
670
+ message: redactSpanErrors ? errorCategory : localError.message,
671
+ });
625
672
  }
626
673
  else {
627
674
  span.setStatus({ code: SpanStatusCode.OK });
628
675
  }
629
- this.recordToolExecutionMetrics(toolExecution, localError ?? (toolExecution.callError !== undefined ? new Error(toolExecution.callError) : undefined));
676
+ const spanCtx = trace.setSpan(context.active(), span);
677
+ context.with(spanCtx, () => {
678
+ this.recordToolExecutionMetrics(toolExecution, localError ?? (toolExecution.callError !== undefined ? new Error(toolExecution.callError) : undefined));
679
+ });
630
680
  span.end(toolExecution.completedAt);
631
681
  return localError;
632
682
  }
@@ -634,11 +684,10 @@ export class SigilClient {
634
684
  const startedMs = generation.startedAt.getTime();
635
685
  const completedMs = generation.completedAt.getTime();
636
686
  const durationSeconds = Math.max(0, (completedMs - startedMs) / 1_000);
687
+ const identityAttributes = metricIdentityAttributes(generation.model.provider, generation.model.name, generation.agentName, generation.agentVersion);
637
688
  this.operationDurationHistogram.record(durationSeconds, {
638
689
  [spanAttrOperationName]: generation.operationName,
639
- [spanAttrProviderName]: generation.model.provider,
640
- [spanAttrRequestModel]: generation.model.name,
641
- [spanAttrAgentName]: generation.agentName ?? '',
690
+ ...identityAttributes,
642
691
  [spanAttrErrorType]: errorType,
643
692
  [spanAttrErrorCategory]: errorCategory,
644
693
  });
@@ -651,37 +700,30 @@ export class SigilClient {
651
700
  this.recordTokenUsage(generation, metricTokenTypeReasoning, usage.reasoningTokens);
652
701
  }
653
702
  this.toolCallsHistogram.record(countToolCallParts(generation.output ?? []), {
654
- [spanAttrProviderName]: generation.model.provider,
655
- [spanAttrRequestModel]: generation.model.name,
656
- [spanAttrAgentName]: generation.agentName ?? '',
703
+ ...identityAttributes,
657
704
  });
658
705
  if (generation.operationName === 'streamText' && firstTokenAt !== undefined) {
659
706
  const ttftSeconds = (firstTokenAt.getTime() - startedMs) / 1_000;
660
707
  if (ttftSeconds >= 0) {
661
708
  this.ttftHistogram.record(ttftSeconds, {
662
- [spanAttrProviderName]: generation.model.provider,
663
- [spanAttrRequestModel]: generation.model.name,
664
- [spanAttrAgentName]: generation.agentName ?? '',
709
+ ...identityAttributes,
665
710
  });
666
711
  }
667
712
  }
668
713
  }
669
714
  recordEmbeddingMetrics(seed, result, startedAt, completedAt, errorType, errorCategory) {
670
715
  const durationSeconds = Math.max(0, (completedAt.getTime() - startedAt.getTime()) / 1_000);
716
+ const identityAttributes = metricIdentityAttributes(seed.model.provider, seed.model.name, seed.agentName, seed.agentVersion);
671
717
  this.operationDurationHistogram.record(durationSeconds, {
672
718
  [spanAttrOperationName]: defaultEmbeddingOperationName,
673
- [spanAttrProviderName]: seed.model.provider,
674
- [spanAttrRequestModel]: seed.model.name,
675
- [spanAttrAgentName]: seed.agentName ?? '',
719
+ ...identityAttributes,
676
720
  [spanAttrErrorType]: errorType,
677
721
  [spanAttrErrorCategory]: errorCategory,
678
722
  });
679
723
  if (result.inputTokens !== undefined && result.inputTokens !== 0) {
680
724
  this.tokenUsageHistogram.record(result.inputTokens, {
681
725
  [spanAttrOperationName]: defaultEmbeddingOperationName,
682
- [spanAttrProviderName]: seed.model.provider,
683
- [spanAttrRequestModel]: seed.model.name,
684
- [spanAttrAgentName]: seed.agentName ?? '',
726
+ ...identityAttributes,
685
727
  [metricAttrTokenType]: metricTokenTypeInput,
686
728
  });
687
729
  }
@@ -692,9 +734,7 @@ export class SigilClient {
692
734
  }
693
735
  this.tokenUsageHistogram.record(value, {
694
736
  [spanAttrOperationName]: generation.operationName,
695
- [spanAttrProviderName]: generation.model.provider,
696
- [spanAttrRequestModel]: generation.model.name,
697
- [spanAttrAgentName]: generation.agentName ?? '',
737
+ ...metricIdentityAttributes(generation.model.provider, generation.model.name, generation.agentName, generation.agentVersion),
698
738
  [metricAttrTokenType]: tokenType,
699
739
  });
700
740
  }
@@ -706,10 +746,8 @@ export class SigilClient {
706
746
  const errorCategory = finalError === undefined ? '' : errorCategoryFromError(finalError, true);
707
747
  this.operationDurationHistogram.record(durationSeconds, {
708
748
  [spanAttrOperationName]: 'execute_tool',
709
- [spanAttrProviderName]: (toolExecution.requestProvider ?? '').trim(),
710
- [spanAttrRequestModel]: (toolExecution.requestModel ?? '').trim(),
711
749
  [spanAttrToolName]: toolExecution.toolName.trim(),
712
- [spanAttrAgentName]: toolExecution.agentName ?? '',
750
+ ...metricIdentityAttributes(toolExecution.requestProvider ?? '', toolExecution.requestModel ?? '', toolExecution.agentName, toolExecution.agentVersion),
713
751
  [spanAttrErrorType]: errorType,
714
752
  [spanAttrErrorCategory]: errorCategory,
715
753
  });
@@ -811,6 +849,7 @@ class GenerationRecorderImpl {
811
849
  callError;
812
850
  localError;
813
851
  firstTokenAt;
852
+ extraMetadata;
814
853
  constructor(client, seed, defaultMode) {
815
854
  this.client = client;
816
855
  this.seed = cloneGenerationStart(seed);
@@ -857,7 +896,7 @@ class GenerationRecorderImpl {
857
896
  this.mode = this.seed.mode ?? defaultMode;
858
897
  this.startedAt = this.seed.startedAt ?? this.client.internalNow();
859
898
  this.contentCaptureMode = this.client.internalResolveGenerationContentCaptureMode(this.seed);
860
- this.span = this.client.internalStartGenerationSpan(this.seed, this.mode, this.startedAt);
899
+ this.span = this.client.internalStartGenerationSpan(this.seed, this.mode, this.startedAt, this.contentCaptureMode);
861
900
  }
862
901
  setResult(result) {
863
902
  if (this.ended) {
@@ -880,6 +919,28 @@ class GenerationRecorderImpl {
880
919
  }
881
920
  this.firstTokenAt = new Date(firstTokenAt);
882
921
  }
922
+ setCacheDiagnostics(missReason, opts) {
923
+ if (this.ended) {
924
+ return;
925
+ }
926
+ const trimmed = missReason.trim();
927
+ if (trimmed.length === 0) {
928
+ return;
929
+ }
930
+ if (this.extraMetadata === undefined) {
931
+ this.extraMetadata = {};
932
+ }
933
+ delete this.extraMetadata[CACHE_DIAGNOSTICS_MISSED_INPUT_TOKENS_KEY];
934
+ delete this.extraMetadata[CACHE_DIAGNOSTICS_PREVIOUS_MESSAGE_ID_KEY];
935
+ this.extraMetadata[CACHE_DIAGNOSTICS_MISS_REASON_KEY] = trimmed;
936
+ if (opts?.missedInputTokens !== undefined) {
937
+ this.extraMetadata[CACHE_DIAGNOSTICS_MISSED_INPUT_TOKENS_KEY] = String(opts.missedInputTokens);
938
+ }
939
+ const prev = opts?.previousMessageId?.trim();
940
+ if (prev !== undefined && prev.length > 0) {
941
+ this.extraMetadata[CACHE_DIAGNOSTICS_PREVIOUS_MESSAGE_ID_KEY] = prev;
942
+ }
943
+ }
883
944
  end() {
884
945
  if (this.ended) {
885
946
  return;
@@ -917,7 +978,7 @@ class GenerationRecorderImpl {
917
978
  startedAt: new Date(this.startedAt),
918
979
  completedAt: new Date(this.result?.completedAt ?? this.client.internalNow()),
919
980
  tags: mergeStringRecords(this.seed.tags, this.result?.tags),
920
- metadata: mergeUnknownRecords(this.seed.metadata, this.result?.metadata),
981
+ metadata: mergeUnknownRecords(mergeUnknownRecords(this.seed.metadata, this.result?.metadata), this.extraMetadata),
921
982
  artifacts: this.result?.artifacts?.map(cloneArtifact),
922
983
  callError: this.callError,
923
984
  };
@@ -965,8 +1026,20 @@ class GenerationRecorderImpl {
965
1026
  }
966
1027
  }
967
1028
  const validationError = validateGeneration(validationTarget);
968
- this.client.internalSyncGenerationSpan(this.span, generation);
969
- if (effectiveContentCaptureMode === 'metadata_only') {
1029
+ // full_with_metadata_spans: proto export keeps the title, but the span
1030
+ // path must drop it. Pass a shallow copy with the title cleared so the
1031
+ // in-memory generation (the proto payload) stays untouched.
1032
+ const spanGeneration = effectiveContentCaptureMode === 'full_with_metadata_spans'
1033
+ ? { ...generation, conversationTitle: '' }
1034
+ : generation;
1035
+ this.client.internalSyncGenerationSpan(this.span, spanGeneration);
1036
+ if (effectiveContentCaptureMode === 'metadata_only' &&
1037
+ this.contentCaptureMode !== 'metadata_only' &&
1038
+ this.contentCaptureMode !== 'full_with_metadata_spans') {
1039
+ // Sanitizer fallback downgrades effective mode to metadata_only.
1040
+ // Skipped when the original mode already left the attribute absent at
1041
+ // start time (metadata_only / full_with_metadata_spans) so the
1042
+ // start-span omission isn't re-emitted here as an empty value.
970
1043
  this.client.internalClearSpanConversationTitle(this.span);
971
1044
  }
972
1045
  this.client.internalApplyTraceContextFromSpan(this.span, generation);
@@ -986,7 +1059,24 @@ class GenerationRecorderImpl {
986
1059
  this.client.internalLogWarn('sigil generation enqueue failed', enqueueError);
987
1060
  }
988
1061
  }
989
- const finalCallError = effectiveContentCaptureMode === 'metadata_only' ? generation.callError : this.callError;
1062
+ // Under metadata_only stripContent already replaced generation.callError
1063
+ // with the category, so the span path can read it back from the
1064
+ // generation. Under full_with_metadata_spans generation.callError stays
1065
+ // raw for the gRPC export, so we substitute the precomputed category for
1066
+ // the span path here.
1067
+ let finalCallError;
1068
+ if (this.callError === undefined) {
1069
+ finalCallError = undefined;
1070
+ }
1071
+ else if (effectiveContentCaptureMode === 'metadata_only') {
1072
+ finalCallError = generation.callError;
1073
+ }
1074
+ else if (effectiveContentCaptureMode === 'full_with_metadata_spans') {
1075
+ finalCallError = callErrorCategory.length > 0 ? callErrorCategory : 'sdk_error';
1076
+ }
1077
+ else {
1078
+ finalCallError = this.callError;
1079
+ }
990
1080
  this.client.internalFinalizeGenerationSpan(this.span, generation, finalCallError, validationError, enqueueError, this.firstTokenAt, callErrorCategory.length > 0 ? callErrorCategory : undefined);
991
1081
  }
992
1082
  getError() {
@@ -998,6 +1088,7 @@ class EmbeddingRecorderImpl {
998
1088
  seed;
999
1089
  startedAt;
1000
1090
  span;
1091
+ contentCaptureMode;
1001
1092
  ended = false;
1002
1093
  callError;
1003
1094
  result;
@@ -1007,6 +1098,7 @@ class EmbeddingRecorderImpl {
1007
1098
  this.client = client;
1008
1099
  this.seed = cloneEmbeddingStart(seed);
1009
1100
  this.startedAt = this.seed.startedAt ?? this.client.internalNow();
1101
+ this.contentCaptureMode = this.client.internalResolveEmbeddingContentCaptureMode(this.seed);
1010
1102
  this.span = this.client.internalStartEmbeddingSpan(this.seed, this.startedAt);
1011
1103
  }
1012
1104
  setCallError(error) {
@@ -1033,7 +1125,7 @@ class EmbeddingRecorderImpl {
1033
1125
  if (localError === undefined) {
1034
1126
  localError = validateEmbeddingResult(normalizedResult);
1035
1127
  }
1036
- this.client.internalFinalizeEmbeddingSpan(this.span, this.seed, normalizedResult, this.hasResult, this.callError, localError, this.startedAt, completedAt);
1128
+ this.client.internalFinalizeEmbeddingSpan(this.span, this.seed, normalizedResult, this.hasResult, this.callError, localError, this.startedAt, completedAt, this.contentCaptureMode);
1037
1129
  this.localError = localError;
1038
1130
  }
1039
1131
  getError() {
@@ -1046,6 +1138,7 @@ class ToolExecutionRecorderImpl {
1046
1138
  startedAt;
1047
1139
  span;
1048
1140
  resolvedIncludeContent;
1141
+ toolMode;
1049
1142
  ended = false;
1050
1143
  result;
1051
1144
  callError;
@@ -1077,7 +1170,16 @@ class ToolExecutionRecorderImpl {
1077
1170
  this.seed.agentVersion = fromConfig;
1078
1171
  }
1079
1172
  }
1080
- this.resolvedIncludeContent = this.client.internalResolveToolIncludeContent(this.seed);
1173
+ // Under metadata_only or full_with_metadata_spans, the start-time tool
1174
+ // span must not carry any content-bearing seed field. Tools have no
1175
+ // proto export, so dropping these on the seed is the only redaction
1176
+ // surface.
1177
+ this.toolMode = this.client.internalResolveToolContentCaptureMode(this.seed);
1178
+ if (this.toolMode === 'metadata_only' || this.toolMode === 'full_with_metadata_spans') {
1179
+ this.seed.conversationTitle = undefined;
1180
+ this.seed.toolDescription = undefined;
1181
+ }
1182
+ this.resolvedIncludeContent = shouldIncludeToolContent(this.toolMode, this.seed.includeContent ?? false);
1081
1183
  this.startedAt = this.seed.startedAt ?? this.client.internalNow();
1082
1184
  this.span = this.client.internalStartToolExecutionSpan(this.seed, this.startedAt);
1083
1185
  }
@@ -1125,7 +1227,7 @@ class ToolExecutionRecorderImpl {
1125
1227
  else {
1126
1228
  this.client.internalRecordToolExecution(toolExecution);
1127
1229
  }
1128
- this.localError = this.client.internalFinalizeToolExecutionSpan(this.span, toolExecution, this.localError);
1230
+ this.localError = this.client.internalFinalizeToolExecutionSpan(this.span, toolExecution, this.localError, this.toolMode);
1129
1231
  }
1130
1232
  getError() {
1131
1233
  return this.localError;
@@ -1180,6 +1282,17 @@ function toolSpanName(toolName) {
1180
1282
  }
1181
1283
  return `execute_tool ${normalized}`;
1182
1284
  }
1285
+ function metricIdentityAttributes(provider, model, agentName, agentVersion) {
1286
+ const attributes = {
1287
+ [spanAttrProviderName]: provider.trim(),
1288
+ [spanAttrRequestModel]: model.trim(),
1289
+ [spanAttrAgentName]: agentName?.trim() ?? '',
1290
+ };
1291
+ if (notEmpty(agentVersion)) {
1292
+ attributes[spanAttrAgentVersion] = agentVersion.trim();
1293
+ }
1294
+ return attributes;
1295
+ }
1183
1296
  function setGenerationSpanAttributes(span, generation) {
1184
1297
  span.setAttribute(spanAttrOperationName, generation.operationName);
1185
1298
  span.setAttribute(spanAttrSDKName, sdkName);
@@ -1309,7 +1422,7 @@ function setEmbeddingStartSpanAttributes(span, start) {
1309
1422
  span.setAttribute(spanAttrRequestEncodingFormats, [start.encodingFormat]);
1310
1423
  }
1311
1424
  }
1312
- function setEmbeddingEndSpanAttributes(span, result, hasResult, captureConfig) {
1425
+ function setEmbeddingEndSpanAttributes(span, result, hasResult, captureConfig, contentCaptureMode = 'default') {
1313
1426
  if (hasResult) {
1314
1427
  span.setAttribute(spanAttrEmbeddingInputCount, result.inputCount);
1315
1428
  }
@@ -1322,7 +1435,10 @@ function setEmbeddingEndSpanAttributes(span, result, hasResult, captureConfig) {
1322
1435
  if (result.dimensions !== undefined) {
1323
1436
  span.setAttribute(spanAttrEmbeddingDimCount, result.dimensions);
1324
1437
  }
1325
- if (captureConfig.captureInput && result.inputTexts !== undefined) {
1438
+ // Embeddings have no proto export; full_with_metadata_spans matches
1439
+ // metadata_only for input-text span attributes.
1440
+ const omitInputTexts = contentCaptureMode === 'metadata_only' || contentCaptureMode === 'full_with_metadata_spans';
1441
+ if (captureConfig.captureInput && result.inputTexts !== undefined && !omitInputTexts) {
1326
1442
  const texts = captureEmbeddingInputTexts(result.inputTexts, captureConfig.maxInputItems, captureConfig.maxTextLength);
1327
1443
  if (texts.length > 0) {
1328
1444
  span.setAttribute(spanAttrEmbeddingInputTexts, texts);
@@ -1438,7 +1554,10 @@ function baseURLFromAPIEndpoint(endpoint, insecure) {
1438
1554
  }
1439
1555
  if (trimmed.startsWith('http://') || trimmed.startsWith('https://')) {
1440
1556
  const parsed = new URL(trimmed);
1441
- return `${parsed.protocol}//${parsed.host}`;
1557
+ // Preserve a path prefix so prefix-mounted Sigil deployments
1558
+ // (https://host/sigil) route /api/v1/conversations/... under the prefix.
1559
+ const path = parsed.pathname.replace(/\/+$/, '');
1560
+ return `${parsed.protocol}//${parsed.host}${path}`;
1442
1561
  }
1443
1562
  const withoutScheme = trimmed.startsWith('grpc://') ? trimmed.slice('grpc://'.length) : trimmed;
1444
1563
  const host = withoutScheme.split('/')[0]?.trim();