@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.
- package/README.md +19 -9
- package/dist/cache-diagnostics.d.ts +15 -0
- package/dist/cache-diagnostics.d.ts.map +1 -0
- package/dist/cache-diagnostics.js +15 -0
- package/dist/cache-diagnostics.js.map +1 -0
- package/dist/client.d.ts +5 -4
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +172 -59
- package/dist/client.js.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/content_capture.d.ts +3 -4
- package/dist/content_capture.d.ts.map +1 -1
- package/dist/content_capture.js +7 -9
- package/dist/content_capture.js.map +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +29 -2
- package/dist/context.js.map +1 -1
- package/dist/core.d.ts +13 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +12 -0
- package/dist/core.js.map +1 -0
- package/dist/exporters/http.js +6 -1
- package/dist/exporters/http.js.map +1 -1
- package/dist/frameworks/vercel-ai-sdk/hooks.d.ts.map +1 -1
- package/dist/frameworks/vercel-ai-sdk/hooks.js +70 -39
- package/dist/frameworks/vercel-ai-sdk/hooks.js.map +1 -1
- package/dist/frameworks/vercel-ai-sdk/index.d.ts +1 -1
- package/dist/frameworks/vercel-ai-sdk/index.d.ts.map +1 -1
- package/dist/frameworks/vercel-ai-sdk/index.js +1 -1
- package/dist/frameworks/vercel-ai-sdk/index.js.map +1 -1
- package/dist/frameworks/vercel-ai-sdk/mapping.d.ts +9 -1
- package/dist/frameworks/vercel-ai-sdk/mapping.d.ts.map +1 -1
- package/dist/frameworks/vercel-ai-sdk/mapping.js +59 -3
- package/dist/frameworks/vercel-ai-sdk/mapping.js.map +1 -1
- package/dist/frameworks/vercel-ai-sdk/types.d.ts +6 -0
- package/dist/frameworks/vercel-ai-sdk/types.d.ts.map +1 -1
- package/dist/hooks.js +4 -1
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +1 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -10
- package/dist/index.js.map +1 -1
- package/dist/providers/anthropic.js +3 -3
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/gemini.js +3 -3
- package/dist/providers/gemini.js.map +1 -1
- package/dist/types.d.ts +13 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +13 -2
- package/dist/utils.js.map +1 -1
- package/package.json +17 -17
- 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
|
|
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.
|
|
350
|
-
basicPassword: process.env.
|
|
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.
|
|
362
|
-
basicUser: process.env.
|
|
363
|
-
basicPassword: process.env.
|
|
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
|
-
##
|
|
377
|
+
## Wiring custom env vars
|
|
368
378
|
|
|
369
|
-
The SDK
|
|
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.
|
|
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
|
-
|
|
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;
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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({
|
|
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({
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
620
|
-
span.setStatus({
|
|
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
|
-
|
|
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,
|
|
626
|
-
span.setStatus({
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
972
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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();
|