@grafana/sigil-sdk-js 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.
Files changed (54) hide show
  1. package/README.md +19 -9
  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 -59
  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 +59 -3
  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/providers/anthropic.js +3 -3
  45. package/dist/providers/anthropic.js.map +1 -1
  46. package/dist/providers/gemini.js +3 -3
  47. package/dist/providers/gemini.js.map +1 -1
  48. package/dist/types.d.ts +13 -2
  49. package/dist/types.d.ts.map +1 -1
  50. package/dist/utils.d.ts.map +1 -1
  51. package/dist/utils.js +13 -2
  52. package/dist/utils.js.map +1 -1
  53. package/package.json +17 -17
  54. package/proto/sigil/v1/generation_ingest.proto +9 -13
package/README.md CHANGED
@@ -8,6 +8,14 @@ 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
+
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/).
18
+
11
19
  ## Validation
12
20
 
13
21
  Run the shared core conformance suite for the JavaScript SDK from the repo root:
@@ -24,6 +32,8 @@ mise run sdk:conformance
24
32
 
25
33
  ## Quick Start
26
34
 
35
+ The snippet below configures the SDK explicitly. As an alternative, set `SIGIL_*` environment variables and call `new SigilClient()` with no arguments — refer to the [Grafana Cloud setup guide](https://grafana.com/docs/grafana-cloud/machine-learning/ai-observability/get-started/grafana-cloud/) for the variable names.
36
+
27
37
  ```ts
28
38
  import { SigilClient } from "@grafana/sigil-sdk-js";
29
39
 
@@ -316,7 +326,7 @@ Auth is configured for `generationExport`.
316
326
  - `mode: "none"`
317
327
  - `mode: "tenant"` (requires `tenantId`, injects `X-Scope-OrgID`)
318
328
  - `mode: "bearer"` (requires `bearerToken`, injects `Authorization: Bearer <token>`)
319
- - `mode: "basic"` (requires `basicPassword` + `basicUser` or `tenantId`, injects `Authorization: Basic <base64(user:password)>`; also injects `X-Scope-OrgID` when `tenantId` is set — for self-hosted multi-tenancy only, not needed for Grafana Cloud)
329
+ - `mode: "basic"` (requires `basicPassword` + `basicUser` or `tenantId`, injects `Authorization: Basic <base64(user:password)>`; also injects `X-Scope-OrgID` when `tenantId` is set — for multi-tenant deployments only, not needed for Grafana Cloud)
320
330
 
321
331
  Invalid mode/field combinations throw during client config resolution.
322
332
 
@@ -346,8 +356,8 @@ const client = new SigilClient({
346
356
  endpoint: "https://sigil-prod-<region>.grafana.net",
347
357
  auth: {
348
358
  mode: "basic",
349
- tenantId: process.env.GRAFANA_CLOUD_INSTANCE_ID,
350
- basicPassword: process.env.GRAFANA_CLOUD_API_KEY,
359
+ tenantId: process.env.SIGIL_AUTH_TENANT_ID,
360
+ basicPassword: process.env.SIGIL_AUTH_TOKEN,
351
361
  },
352
362
  },
353
363
  });
@@ -358,18 +368,18 @@ If your deployment requires a distinct username, set `basicUser` explicitly:
358
368
  ```ts
359
369
  auth: {
360
370
  mode: "basic",
361
- tenantId: process.env.GRAFANA_CLOUD_INSTANCE_ID,
362
- basicUser: process.env.GRAFANA_CLOUD_INSTANCE_ID,
363
- basicPassword: process.env.GRAFANA_CLOUD_API_KEY,
371
+ tenantId: process.env.SIGIL_AUTH_TENANT_ID,
372
+ basicUser: process.env.SIGIL_AUTH_TENANT_ID,
373
+ basicPassword: process.env.SIGIL_AUTH_TOKEN,
364
374
  },
365
375
  ```
366
376
 
367
- ## Env-secret wiring example
377
+ ## Wiring custom env vars
368
378
 
369
- 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:
370
380
 
371
381
  ```ts
372
- const generationBearerToken = (process.env.SIGIL_GEN_BEARER_TOKEN ?? "").trim();
382
+ const generationBearerToken = (process.env.MY_APP_SIGIL_TOKEN ?? "").trim();
373
383
 
374
384
  const client = new SigilClient({
375
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';
@@ -42,7 +43,6 @@ const spanAttrEmbeddingDimCount = 'gen_ai.embeddings.dimension.count';
42
43
  const spanAttrRequestEncodingFormats = 'gen_ai.request.encoding_formats';
43
44
  const spanAttrCacheReadTokens = 'gen_ai.usage.cache_read_input_tokens';
44
45
  const spanAttrCacheWriteTokens = 'gen_ai.usage.cache_write_input_tokens';
45
- const spanAttrCacheCreationTokens = 'gen_ai.usage.cache_creation_input_tokens';
46
46
  const spanAttrReasoningTokens = 'gen_ai.usage.reasoning_tokens';
47
47
  const spanAttrToolName = 'gen_ai.tool.name';
48
48
  const spanAttrToolCallID = 'gen_ai.tool.call.id';
@@ -66,7 +66,6 @@ const metricTokenTypeInput = 'input';
66
66
  const metricTokenTypeOutput = 'output';
67
67
  const metricTokenTypeCacheRead = 'cache_read';
68
68
  const metricTokenTypeCacheWrite = 'cache_write';
69
- const metricTokenTypeCacheCreation = 'cache_creation';
70
69
  const metricTokenTypeReasoning = 'reasoning';
71
70
  const durationBucketsSeconds = [
72
71
  0.01, 0.02, 0.04, 0.08, 0.16, 0.32, 0.64, 1.28, 2.56, 5.12, 10.24, 20.48, 40.96, 81.92,
@@ -451,9 +450,16 @@ export class SigilClient {
451
450
  const clientMode = resolveClientContentCaptureMode(resolveContentCaptureMode(resolverMode, this.config.contentCapture));
452
451
  return resolveContentCaptureMode(seed.contentCapture ?? 'default', clientMode);
453
452
  }
454
- 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) {
455
460
  const resolverMode = callContentCaptureResolver(this.config.contentCaptureResolver, undefined);
456
- 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);
457
463
  }
458
464
  internalHasGenerationSanitizer() {
459
465
  return this.config.generationSanitizer !== undefined;
@@ -469,16 +475,23 @@ export class SigilClient {
469
475
  }
470
476
  return cloneGeneration(sanitized);
471
477
  }
472
- internalStartGenerationSpan(seed, mode, startedAt) {
478
+ internalStartGenerationSpan(seed, mode, startedAt, contentCaptureMode) {
473
479
  const operationName = seed.operationName ?? defaultOperationNameForMode(mode);
474
480
  const span = this.tracer.startSpan(generationSpanName(operationName, seed.model.name), {
475
481
  kind: SpanKind.CLIENT,
476
482
  startTime: startedAt,
477
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;
478
491
  setGenerationSpanAttributes(span, {
479
492
  id: seed.id,
480
493
  conversationId: seed.conversationId,
481
- conversationTitle: seed.conversationTitle,
494
+ conversationTitle: spanTitle,
482
495
  userId: seed.userId,
483
496
  agentName: seed.agentName,
484
497
  agentVersion: seed.agentVersion,
@@ -561,16 +574,23 @@ export class SigilClient {
561
574
  else {
562
575
  span.setStatus({ code: SpanStatusCode.OK });
563
576
  }
564
- 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
+ });
565
581
  span.end(generation.completedAt);
566
582
  }
567
- internalFinalizeEmbeddingSpan(span, seed, result, hasResult, callError, localError, startedAt, completedAt) {
583
+ internalFinalizeEmbeddingSpan(span, seed, result, hasResult, callError, localError, startedAt, completedAt, contentCaptureMode = 'default') {
568
584
  span.updateName(embeddingSpanName(seed.model.name));
569
- setEmbeddingEndSpanAttributes(span, result, hasResult, this.config.embeddingCapture);
570
- 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) {
571
591
  span.recordException(callError);
572
592
  }
573
- if (localError !== undefined) {
593
+ if (localError !== undefined && !redactSpanErrors) {
574
594
  span.recordException(localError);
575
595
  }
576
596
  let errorType = '';
@@ -578,12 +598,18 @@ export class SigilClient {
578
598
  if (callError !== undefined) {
579
599
  errorType = 'provider_call_error';
580
600
  errorCategory = errorCategoryFromError(callError, true);
581
- span.setStatus({ code: SpanStatusCode.ERROR, message: callError.message });
601
+ span.setStatus({
602
+ code: SpanStatusCode.ERROR,
603
+ message: redactSpanErrors ? errorCategory : callError.message,
604
+ });
582
605
  }
583
606
  else if (localError !== undefined) {
584
607
  errorType = 'validation_error';
585
608
  errorCategory = 'sdk_error';
586
- span.setStatus({ code: SpanStatusCode.ERROR, message: localError.message });
609
+ span.setStatus({
610
+ code: SpanStatusCode.ERROR,
611
+ message: redactSpanErrors ? errorCategory : localError.message,
612
+ });
587
613
  }
588
614
  else {
589
615
  span.setStatus({ code: SpanStatusCode.OK });
@@ -592,10 +618,13 @@ export class SigilClient {
592
618
  span.setAttribute(spanAttrErrorType, errorType);
593
619
  span.setAttribute(spanAttrErrorCategory, errorCategory);
594
620
  }
595
- 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
+ });
596
625
  span.end(completedAt);
597
626
  }
598
- internalFinalizeToolExecutionSpan(span, toolExecution, localError) {
627
+ internalFinalizeToolExecutionSpan(span, toolExecution, localError, contentCaptureMode = 'default') {
599
628
  setToolSpanAttributes(span, toolExecution);
600
629
  if (toolExecution.includeContent) {
601
630
  const argumentsResult = serializeToolContent(toolExecution.arguments);
@@ -613,22 +642,41 @@ export class SigilClient {
613
642
  span.setAttribute(spanAttrToolCallResult, resultValue.value);
614
643
  }
615
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';
616
649
  if (toolExecution.callError !== undefined) {
617
- span.recordException(new Error(toolExecution.callError));
650
+ const errorCategory = errorCategoryFromError(toolExecution.callError, true);
651
+ if (!redactSpanErrors) {
652
+ span.recordException(new Error(toolExecution.callError));
653
+ }
618
654
  span.setAttribute(spanAttrErrorType, 'tool_execution_error');
619
- span.setAttribute(spanAttrErrorCategory, errorCategoryFromError(toolExecution.callError, true));
620
- 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
+ });
621
660
  }
622
661
  else if (localError !== undefined) {
623
- span.recordException(localError);
662
+ const errorCategory = errorCategoryFromError(localError, true);
663
+ if (!redactSpanErrors) {
664
+ span.recordException(localError);
665
+ }
624
666
  span.setAttribute(spanAttrErrorType, 'tool_execution_error');
625
- span.setAttribute(spanAttrErrorCategory, errorCategoryFromError(localError, true));
626
- 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
+ });
627
672
  }
628
673
  else {
629
674
  span.setStatus({ code: SpanStatusCode.OK });
630
675
  }
631
- 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
+ });
632
680
  span.end(toolExecution.completedAt);
633
681
  return localError;
634
682
  }
@@ -636,11 +684,10 @@ export class SigilClient {
636
684
  const startedMs = generation.startedAt.getTime();
637
685
  const completedMs = generation.completedAt.getTime();
638
686
  const durationSeconds = Math.max(0, (completedMs - startedMs) / 1_000);
687
+ const identityAttributes = metricIdentityAttributes(generation.model.provider, generation.model.name, generation.agentName, generation.agentVersion);
639
688
  this.operationDurationHistogram.record(durationSeconds, {
640
689
  [spanAttrOperationName]: generation.operationName,
641
- [spanAttrProviderName]: generation.model.provider,
642
- [spanAttrRequestModel]: generation.model.name,
643
- [spanAttrAgentName]: generation.agentName ?? '',
690
+ ...identityAttributes,
644
691
  [spanAttrErrorType]: errorType,
645
692
  [spanAttrErrorCategory]: errorCategory,
646
693
  });
@@ -650,41 +697,33 @@ export class SigilClient {
650
697
  this.recordTokenUsage(generation, metricTokenTypeOutput, usage.outputTokens);
651
698
  this.recordTokenUsage(generation, metricTokenTypeCacheRead, usage.cacheReadInputTokens);
652
699
  this.recordTokenUsage(generation, metricTokenTypeCacheWrite, usage.cacheWriteInputTokens);
653
- this.recordTokenUsage(generation, metricTokenTypeCacheCreation, usage.cacheCreationInputTokens);
654
700
  this.recordTokenUsage(generation, metricTokenTypeReasoning, usage.reasoningTokens);
655
701
  }
656
702
  this.toolCallsHistogram.record(countToolCallParts(generation.output ?? []), {
657
- [spanAttrProviderName]: generation.model.provider,
658
- [spanAttrRequestModel]: generation.model.name,
659
- [spanAttrAgentName]: generation.agentName ?? '',
703
+ ...identityAttributes,
660
704
  });
661
705
  if (generation.operationName === 'streamText' && firstTokenAt !== undefined) {
662
706
  const ttftSeconds = (firstTokenAt.getTime() - startedMs) / 1_000;
663
707
  if (ttftSeconds >= 0) {
664
708
  this.ttftHistogram.record(ttftSeconds, {
665
- [spanAttrProviderName]: generation.model.provider,
666
- [spanAttrRequestModel]: generation.model.name,
667
- [spanAttrAgentName]: generation.agentName ?? '',
709
+ ...identityAttributes,
668
710
  });
669
711
  }
670
712
  }
671
713
  }
672
714
  recordEmbeddingMetrics(seed, result, startedAt, completedAt, errorType, errorCategory) {
673
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);
674
717
  this.operationDurationHistogram.record(durationSeconds, {
675
718
  [spanAttrOperationName]: defaultEmbeddingOperationName,
676
- [spanAttrProviderName]: seed.model.provider,
677
- [spanAttrRequestModel]: seed.model.name,
678
- [spanAttrAgentName]: seed.agentName ?? '',
719
+ ...identityAttributes,
679
720
  [spanAttrErrorType]: errorType,
680
721
  [spanAttrErrorCategory]: errorCategory,
681
722
  });
682
723
  if (result.inputTokens !== undefined && result.inputTokens !== 0) {
683
724
  this.tokenUsageHistogram.record(result.inputTokens, {
684
725
  [spanAttrOperationName]: defaultEmbeddingOperationName,
685
- [spanAttrProviderName]: seed.model.provider,
686
- [spanAttrRequestModel]: seed.model.name,
687
- [spanAttrAgentName]: seed.agentName ?? '',
726
+ ...identityAttributes,
688
727
  [metricAttrTokenType]: metricTokenTypeInput,
689
728
  });
690
729
  }
@@ -695,9 +734,7 @@ export class SigilClient {
695
734
  }
696
735
  this.tokenUsageHistogram.record(value, {
697
736
  [spanAttrOperationName]: generation.operationName,
698
- [spanAttrProviderName]: generation.model.provider,
699
- [spanAttrRequestModel]: generation.model.name,
700
- [spanAttrAgentName]: generation.agentName ?? '',
737
+ ...metricIdentityAttributes(generation.model.provider, generation.model.name, generation.agentName, generation.agentVersion),
701
738
  [metricAttrTokenType]: tokenType,
702
739
  });
703
740
  }
@@ -709,10 +746,8 @@ export class SigilClient {
709
746
  const errorCategory = finalError === undefined ? '' : errorCategoryFromError(finalError, true);
710
747
  this.operationDurationHistogram.record(durationSeconds, {
711
748
  [spanAttrOperationName]: 'execute_tool',
712
- [spanAttrProviderName]: (toolExecution.requestProvider ?? '').trim(),
713
- [spanAttrRequestModel]: (toolExecution.requestModel ?? '').trim(),
714
749
  [spanAttrToolName]: toolExecution.toolName.trim(),
715
- [spanAttrAgentName]: toolExecution.agentName ?? '',
750
+ ...metricIdentityAttributes(toolExecution.requestProvider ?? '', toolExecution.requestModel ?? '', toolExecution.agentName, toolExecution.agentVersion),
716
751
  [spanAttrErrorType]: errorType,
717
752
  [spanAttrErrorCategory]: errorCategory,
718
753
  });
@@ -814,6 +849,7 @@ class GenerationRecorderImpl {
814
849
  callError;
815
850
  localError;
816
851
  firstTokenAt;
852
+ extraMetadata;
817
853
  constructor(client, seed, defaultMode) {
818
854
  this.client = client;
819
855
  this.seed = cloneGenerationStart(seed);
@@ -860,7 +896,7 @@ class GenerationRecorderImpl {
860
896
  this.mode = this.seed.mode ?? defaultMode;
861
897
  this.startedAt = this.seed.startedAt ?? this.client.internalNow();
862
898
  this.contentCaptureMode = this.client.internalResolveGenerationContentCaptureMode(this.seed);
863
- 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);
864
900
  }
865
901
  setResult(result) {
866
902
  if (this.ended) {
@@ -883,6 +919,28 @@ class GenerationRecorderImpl {
883
919
  }
884
920
  this.firstTokenAt = new Date(firstTokenAt);
885
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
+ }
886
944
  end() {
887
945
  if (this.ended) {
888
946
  return;
@@ -920,7 +978,7 @@ class GenerationRecorderImpl {
920
978
  startedAt: new Date(this.startedAt),
921
979
  completedAt: new Date(this.result?.completedAt ?? this.client.internalNow()),
922
980
  tags: mergeStringRecords(this.seed.tags, this.result?.tags),
923
- metadata: mergeUnknownRecords(this.seed.metadata, this.result?.metadata),
981
+ metadata: mergeUnknownRecords(mergeUnknownRecords(this.seed.metadata, this.result?.metadata), this.extraMetadata),
924
982
  artifacts: this.result?.artifacts?.map(cloneArtifact),
925
983
  callError: this.callError,
926
984
  };
@@ -968,8 +1026,20 @@ class GenerationRecorderImpl {
968
1026
  }
969
1027
  }
970
1028
  const validationError = validateGeneration(validationTarget);
971
- this.client.internalSyncGenerationSpan(this.span, generation);
972
- 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.
973
1043
  this.client.internalClearSpanConversationTitle(this.span);
974
1044
  }
975
1045
  this.client.internalApplyTraceContextFromSpan(this.span, generation);
@@ -989,7 +1059,24 @@ class GenerationRecorderImpl {
989
1059
  this.client.internalLogWarn('sigil generation enqueue failed', enqueueError);
990
1060
  }
991
1061
  }
992
- 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
+ }
993
1080
  this.client.internalFinalizeGenerationSpan(this.span, generation, finalCallError, validationError, enqueueError, this.firstTokenAt, callErrorCategory.length > 0 ? callErrorCategory : undefined);
994
1081
  }
995
1082
  getError() {
@@ -1001,6 +1088,7 @@ class EmbeddingRecorderImpl {
1001
1088
  seed;
1002
1089
  startedAt;
1003
1090
  span;
1091
+ contentCaptureMode;
1004
1092
  ended = false;
1005
1093
  callError;
1006
1094
  result;
@@ -1010,6 +1098,7 @@ class EmbeddingRecorderImpl {
1010
1098
  this.client = client;
1011
1099
  this.seed = cloneEmbeddingStart(seed);
1012
1100
  this.startedAt = this.seed.startedAt ?? this.client.internalNow();
1101
+ this.contentCaptureMode = this.client.internalResolveEmbeddingContentCaptureMode(this.seed);
1013
1102
  this.span = this.client.internalStartEmbeddingSpan(this.seed, this.startedAt);
1014
1103
  }
1015
1104
  setCallError(error) {
@@ -1036,7 +1125,7 @@ class EmbeddingRecorderImpl {
1036
1125
  if (localError === undefined) {
1037
1126
  localError = validateEmbeddingResult(normalizedResult);
1038
1127
  }
1039
- 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);
1040
1129
  this.localError = localError;
1041
1130
  }
1042
1131
  getError() {
@@ -1049,6 +1138,7 @@ class ToolExecutionRecorderImpl {
1049
1138
  startedAt;
1050
1139
  span;
1051
1140
  resolvedIncludeContent;
1141
+ toolMode;
1052
1142
  ended = false;
1053
1143
  result;
1054
1144
  callError;
@@ -1080,7 +1170,16 @@ class ToolExecutionRecorderImpl {
1080
1170
  this.seed.agentVersion = fromConfig;
1081
1171
  }
1082
1172
  }
1083
- 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);
1084
1183
  this.startedAt = this.seed.startedAt ?? this.client.internalNow();
1085
1184
  this.span = this.client.internalStartToolExecutionSpan(this.seed, this.startedAt);
1086
1185
  }
@@ -1128,7 +1227,7 @@ class ToolExecutionRecorderImpl {
1128
1227
  else {
1129
1228
  this.client.internalRecordToolExecution(toolExecution);
1130
1229
  }
1131
- this.localError = this.client.internalFinalizeToolExecutionSpan(this.span, toolExecution, this.localError);
1230
+ this.localError = this.client.internalFinalizeToolExecutionSpan(this.span, toolExecution, this.localError, this.toolMode);
1132
1231
  }
1133
1232
  getError() {
1134
1233
  return this.localError;
@@ -1183,6 +1282,17 @@ function toolSpanName(toolName) {
1183
1282
  }
1184
1283
  return `execute_tool ${normalized}`;
1185
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
+ }
1186
1296
  function setGenerationSpanAttributes(span, generation) {
1187
1297
  span.setAttribute(spanAttrOperationName, generation.operationName);
1188
1298
  span.setAttribute(spanAttrSDKName, sdkName);
@@ -1286,9 +1396,6 @@ function setGenerationSpanAttributes(span, generation) {
1286
1396
  if ((usage.cacheWriteInputTokens ?? 0) !== 0) {
1287
1397
  span.setAttribute(spanAttrCacheWriteTokens, usage.cacheWriteInputTokens ?? 0);
1288
1398
  }
1289
- if ((usage.cacheCreationInputTokens ?? 0) !== 0) {
1290
- span.setAttribute(spanAttrCacheCreationTokens, usage.cacheCreationInputTokens ?? 0);
1291
- }
1292
1399
  if ((usage.reasoningTokens ?? 0) !== 0) {
1293
1400
  span.setAttribute(spanAttrReasoningTokens, usage.reasoningTokens ?? 0);
1294
1401
  }
@@ -1315,7 +1422,7 @@ function setEmbeddingStartSpanAttributes(span, start) {
1315
1422
  span.setAttribute(spanAttrRequestEncodingFormats, [start.encodingFormat]);
1316
1423
  }
1317
1424
  }
1318
- function setEmbeddingEndSpanAttributes(span, result, hasResult, captureConfig) {
1425
+ function setEmbeddingEndSpanAttributes(span, result, hasResult, captureConfig, contentCaptureMode = 'default') {
1319
1426
  if (hasResult) {
1320
1427
  span.setAttribute(spanAttrEmbeddingInputCount, result.inputCount);
1321
1428
  }
@@ -1328,7 +1435,10 @@ function setEmbeddingEndSpanAttributes(span, result, hasResult, captureConfig) {
1328
1435
  if (result.dimensions !== undefined) {
1329
1436
  span.setAttribute(spanAttrEmbeddingDimCount, result.dimensions);
1330
1437
  }
1331
- 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) {
1332
1442
  const texts = captureEmbeddingInputTexts(result.inputTexts, captureConfig.maxInputItems, captureConfig.maxTextLength);
1333
1443
  if (texts.length > 0) {
1334
1444
  span.setAttribute(spanAttrEmbeddingInputTexts, texts);
@@ -1444,7 +1554,10 @@ function baseURLFromAPIEndpoint(endpoint, insecure) {
1444
1554
  }
1445
1555
  if (trimmed.startsWith('http://') || trimmed.startsWith('https://')) {
1446
1556
  const parsed = new URL(trimmed);
1447
- 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}`;
1448
1561
  }
1449
1562
  const withoutScheme = trimmed.startsWith('grpc://') ? trimmed.slice('grpc://'.length) : trimmed;
1450
1563
  const host = withoutScheme.split('/')[0]?.trim();