weflayr 0.26.1 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +8 -5
- package/dist/src/auto-instrument.d.ts +4 -3
- package/dist/src/auto-instrument.js +18 -17
- package/dist/src/get-data-uri-mime-type.d.ts +17 -0
- package/dist/src/get-data-uri-mime-type.js +25 -0
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.js +5 -1
- package/dist/src/instrumentation/anthropic/get_streaming_accumulation_telemetry.d.ts +3 -1
- package/dist/src/instrumentation/anthropic/get_streaming_accumulation_telemetry.js +6 -3
- package/dist/src/instrumentation/anthropic/get_vertex_billing_telemetry.d.ts +32 -0
- package/dist/src/instrumentation/anthropic/get_vertex_billing_telemetry.js +100 -0
- package/dist/src/instrumentation/anthropic/get_web_search_telemetry.d.ts +43 -0
- package/dist/src/instrumentation/anthropic/get_web_search_telemetry.js +147 -0
- package/dist/src/instrumentation/anthropic/set_telemetry_attributes.d.ts +5 -2
- package/dist/src/instrumentation/anthropic/set_telemetry_attributes.js +17 -4
- package/dist/src/instrumentation/bedrock/get_cache_config_telemetry.d.ts +13 -1
- package/dist/src/instrumentation/bedrock/get_cache_config_telemetry.js +56 -1
- package/dist/src/instrumentation/bedrock/get_cache_telemetry.js +8 -5
- package/dist/src/instrumentation/bedrock/get_input_message_content_telemetry.js +33 -5
- package/dist/src/instrumentation/bedrock/get_model_id_telemetry.d.ts +1 -1
- package/dist/src/instrumentation/bedrock/get_model_id_telemetry.js +1 -1
- package/dist/src/instrumentation/bedrock/get_openai_chat_format_telemetry.d.ts +45 -0
- package/dist/src/instrumentation/bedrock/get_openai_chat_format_telemetry.js +251 -0
- package/dist/src/instrumentation/bedrock/get_streaming_output_message_telemetry.d.ts +6 -5
- package/dist/src/instrumentation/bedrock/get_streaming_output_message_telemetry.js +15 -12
- package/dist/src/instrumentation/bedrock/get_tool_definitions_telemetry.d.ts +2 -2
- package/dist/src/instrumentation/bedrock/get_tool_definitions_telemetry.js +12 -4
- package/dist/src/instrumentation/bedrock/set_telemetry_attributes.d.ts +4 -2
- package/dist/src/instrumentation/bedrock/set_telemetry_attributes.js +10 -3
- package/dist/src/instrumentation/cohere/get_embeddings_telemetry.js +4 -6
- package/dist/src/instrumentation/cohere/get_input_message_content_telemetry.d.ts +23 -0
- package/dist/src/instrumentation/cohere/get_input_message_content_telemetry.js +105 -0
- package/dist/src/instrumentation/cohere/get_v2_chat_telemetry.d.ts +18 -0
- package/dist/src/instrumentation/cohere/get_v2_chat_telemetry.js +186 -0
- package/dist/src/instrumentation/cohere/set_telemetry_attributes.d.ts +3 -1
- package/dist/src/instrumentation/cohere/set_telemetry_attributes.js +5 -1
- package/dist/src/instrumentation/google/get_embeddings_telemetry.d.ts +8 -4
- package/dist/src/instrumentation/google/get_embeddings_telemetry.js +68 -35
- package/dist/src/instrumentation/google/get_provider_name.d.ts +2 -1
- package/dist/src/instrumentation/google/get_provider_name.js +2 -1
- package/dist/src/instrumentation/google/get_web_search_telemetry.d.ts +38 -0
- package/dist/src/instrumentation/google/get_web_search_telemetry.js +125 -0
- package/dist/src/instrumentation/google/set_telemetry_attributes.d.ts +2 -2
- package/dist/src/instrumentation/google/set_telemetry_attributes.js +6 -2
- package/dist/src/instrumentation/mistral/full_instrumentation.d.ts +60 -0
- package/dist/src/instrumentation/mistral/full_instrumentation.js +364 -0
- package/dist/src/instrumentation/mistral/get_input_message_content_telemetry.d.ts +35 -0
- package/dist/src/instrumentation/mistral/get_input_message_content_telemetry.js +113 -0
- package/dist/src/instrumentation/mistral/get_structured_output_schema_telemetry.d.ts +13 -0
- package/dist/src/instrumentation/mistral/get_structured_output_schema_telemetry.js +24 -0
- package/dist/src/instrumentation/mistral/get_vertex_telemetry.d.ts +54 -0
- package/dist/src/instrumentation/mistral/get_vertex_telemetry.js +153 -0
- package/dist/src/instrumentation/openai/get_bedrock_mantle_telemetry.d.ts +10 -0
- package/dist/src/instrumentation/openai/get_bedrock_mantle_telemetry.js +33 -0
- package/dist/src/instrumentation/openai/get_cache_and_reasoning_telemetry.d.ts +13 -6
- package/dist/src/instrumentation/openai/get_cache_and_reasoning_telemetry.js +17 -7
- package/dist/src/instrumentation/openai/get_cache_config_telemetry.d.ts +21 -4
- package/dist/src/instrumentation/openai/get_cache_config_telemetry.js +50 -11
- package/dist/src/instrumentation/openai/get_embeddings_telemetry.js +14 -6
- package/dist/src/instrumentation/openai/get_file_part_mime_type_telemetry.d.ts +26 -0
- package/dist/src/instrumentation/openai/get_file_part_mime_type_telemetry.js +100 -0
- package/dist/src/instrumentation/openai/get_openai_compatible_provider_telemetry.d.ts +48 -0
- package/dist/src/instrumentation/openai/get_openai_compatible_provider_telemetry.js +123 -0
- package/dist/src/instrumentation/openai/get_reasoning_content_telemetry.d.ts +28 -0
- package/dist/src/instrumentation/openai/get_reasoning_content_telemetry.js +130 -0
- package/dist/src/instrumentation/openai/get_responses_telemetry.d.ts +89 -0
- package/dist/src/instrumentation/openai/get_responses_telemetry.js +587 -0
- package/dist/src/instrumentation/openai/get_service_tier_telemetry.d.ts +20 -0
- package/dist/src/instrumentation/openai/get_service_tier_telemetry.js +84 -0
- package/dist/src/instrumentation/openai/get_structured_output_schema_telemetry.d.ts +7 -5
- package/dist/src/instrumentation/openai/get_structured_output_schema_telemetry.js +15 -8
- package/dist/src/instrumentation/openai/get_vertex_openai_compatible_telemetry.d.ts +23 -0
- package/dist/src/instrumentation/openai/get_vertex_openai_compatible_telemetry.js +69 -0
- package/dist/src/instrumentation/openai/get_web_search_telemetry.d.ts +74 -0
- package/dist/src/instrumentation/openai/get_web_search_telemetry.js +259 -0
- package/dist/src/instrumentation/openai/set_telemetry_attributes.d.ts +13 -1
- package/dist/src/instrumentation/openai/set_telemetry_attributes.js +33 -2
- package/dist/src/instrumentation/shared/get_structured_output_schema_telemetry.d.ts +1 -1
- package/dist/src/instrumentation/shared/get_structured_output_schema_telemetry.js +1 -1
- package/dist/src/instrumentation/shared/is_vertex_base_url.d.ts +17 -0
- package/dist/src/instrumentation/shared/is_vertex_base_url.js +40 -0
- package/dist/src/otel/propagation.d.ts +37 -10
- package/dist/src/otel/propagation.js +62 -22
- package/dist/src/otel/span-filter.d.ts +2 -0
- package/dist/src/otel/span-filter.js +10 -1
- package/dist/src/otel/span-processor.d.ts +1 -2
- package/dist/src/otel/span-processor.js +17 -20
- package/dist/src/otel/strip-media-payloads.d.ts +26 -0
- package/dist/src/otel/strip-media-payloads.js +135 -0
- package/dist/src/propagate-metadata-to-gateway.d.ts +37 -0
- package/dist/src/propagate-metadata-to-gateway.js +213 -0
- package/package.json +8 -5
- package/dist/src/instrumentation/vercel/full_instrumentation.d.ts +0 -3
- package/dist/src/instrumentation/vercel/full_instrumentation.js +0 -54
- package/dist/src/instrumentation/vercel/get_cache_creation_telemetry.d.ts +0 -22
- package/dist/src/instrumentation/vercel/get_cache_creation_telemetry.js +0 -66
- package/dist/src/instrumentation/vercel/get_structured_output_schema_telemetry.d.ts +0 -24
- package/dist/src/instrumentation/vercel/get_structured_output_schema_telemetry.js +0 -84
- package/dist/src/otel/vercel-ai-sdk-span-filter.d.ts +0 -12
- package/dist/src/otel/vercel-ai-sdk-span-filter.js +0 -88
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Media parts of the input messages on Mistral chat spans.
|
|
3
|
+
*
|
|
4
|
+
* The SDK's built-in tracing shapes exactly two kinds of content block: text,
|
|
5
|
+
* and `image_url`, which it records as a `uri` part. Every other block reaches
|
|
6
|
+
* `gen_ai.input.messages` as a bare `{"type": "<block type>"}` (the fallback
|
|
7
|
+
* branch of its `formatting.ts`), so a PDF sent as `document_url` is stored
|
|
8
|
+
* under a name with no mime type, where every other provider stores the
|
|
9
|
+
* byte-less `{"type": "blob", "mime_type": "application/pdf"}`.
|
|
10
|
+
*
|
|
11
|
+
* The mime type it lacks is in the request the caller sent: the block's url is
|
|
12
|
+
* a `data:` URI holding the bytes. This complement walks the parts the tracing
|
|
13
|
+
* just stamped alongside the request's blocks and replaces those nameless parts
|
|
14
|
+
* with the same stub the other providers produce. Blocks the tracing did shape,
|
|
15
|
+
* and blocks whose url points at a hosted file rather than at inline bytes, are
|
|
16
|
+
* left alone.
|
|
17
|
+
*/
|
|
18
|
+
import type { Span } from '@opentelemetry/api';
|
|
19
|
+
export declare const INPUT_MESSAGES_ATTRIBUTE = "gen_ai.input.messages";
|
|
20
|
+
/**
|
|
21
|
+
* `gen_ai.input.messages` with every nameless media part replaced by its blob
|
|
22
|
+
* stub, or null when there was nothing to repair (the tracing's own JSON is
|
|
23
|
+
* then left untouched).
|
|
24
|
+
*
|
|
25
|
+
* A message's content blocks map one-to-one onto its parts, in order, which is
|
|
26
|
+
* what lets the repair walk them in step.
|
|
27
|
+
*/
|
|
28
|
+
export declare function repairMediaInputParts(inputMessagesJson: unknown, requestMessages: unknown): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Re-stamp `gen_ai.input.messages` when the request carries inline media.
|
|
31
|
+
*
|
|
32
|
+
* Only ever rewrites an attribute the tracing already set, so it never adds
|
|
33
|
+
* message content the tracing did not record.
|
|
34
|
+
*/
|
|
35
|
+
export declare function setInputMessageContentTelemetry(span: Span, requestBody: Record<string, unknown>): void;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Media parts of the input messages on Mistral chat spans.
|
|
4
|
+
*
|
|
5
|
+
* The SDK's built-in tracing shapes exactly two kinds of content block: text,
|
|
6
|
+
* and `image_url`, which it records as a `uri` part. Every other block reaches
|
|
7
|
+
* `gen_ai.input.messages` as a bare `{"type": "<block type>"}` (the fallback
|
|
8
|
+
* branch of its `formatting.ts`), so a PDF sent as `document_url` is stored
|
|
9
|
+
* under a name with no mime type, where every other provider stores the
|
|
10
|
+
* byte-less `{"type": "blob", "mime_type": "application/pdf"}`.
|
|
11
|
+
*
|
|
12
|
+
* The mime type it lacks is in the request the caller sent: the block's url is
|
|
13
|
+
* a `data:` URI holding the bytes. This complement walks the parts the tracing
|
|
14
|
+
* just stamped alongside the request's blocks and replaces those nameless parts
|
|
15
|
+
* with the same stub the other providers produce. Blocks the tracing did shape,
|
|
16
|
+
* and blocks whose url points at a hosted file rather than at inline bytes, are
|
|
17
|
+
* left alone.
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.INPUT_MESSAGES_ATTRIBUTE = void 0;
|
|
21
|
+
exports.repairMediaInputParts = repairMediaInputParts;
|
|
22
|
+
exports.setInputMessageContentTelemetry = setInputMessageContentTelemetry;
|
|
23
|
+
const get_data_uri_mime_type_1 = require("../../get-data-uri-mime-type");
|
|
24
|
+
exports.INPUT_MESSAGES_ATTRIBUTE = 'gen_ai.input.messages';
|
|
25
|
+
function asObject(value) {
|
|
26
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
27
|
+
? value
|
|
28
|
+
: null;
|
|
29
|
+
}
|
|
30
|
+
/** The url of a content block, which Mistral names after the block's type:
|
|
31
|
+
* `{"type": "document_url", "document_url": "data:..."}`. Some blocks wrap it
|
|
32
|
+
* in a `{"url": ...}` object, as `image_url` does. */
|
|
33
|
+
function getBlockUrl(block) {
|
|
34
|
+
let url = block[String(block.type ?? '')];
|
|
35
|
+
const wrappedUrl = asObject(url);
|
|
36
|
+
if (wrappedUrl)
|
|
37
|
+
url = wrappedUrl.url;
|
|
38
|
+
return String(url ?? '');
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The byte-less part for a content block carrying inline bytes, or null for a
|
|
42
|
+
* block that carries none.
|
|
43
|
+
*
|
|
44
|
+
* e.g. `{"type": "document_url", "document_url": "data:application/pdf;base64,AAA"}`
|
|
45
|
+
* -> `{"type": "blob", "mime_type": "application/pdf"}`.
|
|
46
|
+
*/
|
|
47
|
+
function getMediaStub(rawBlock) {
|
|
48
|
+
const block = asObject(rawBlock);
|
|
49
|
+
if (block === null)
|
|
50
|
+
return null;
|
|
51
|
+
const mimeType = (0, get_data_uri_mime_type_1.getDataUriMimeType)(getBlockUrl(block));
|
|
52
|
+
if (mimeType === null)
|
|
53
|
+
return null;
|
|
54
|
+
return { type: 'blob', mime_type: mimeType };
|
|
55
|
+
}
|
|
56
|
+
/** True for the `{"type": "<block type>"}` the tracing falls back to on a
|
|
57
|
+
* block it does not shape: a type and nothing else. */
|
|
58
|
+
function isNamelessMediaPart(part) {
|
|
59
|
+
const object = asObject(part);
|
|
60
|
+
return object !== null && Object.keys(object).length === 1 && 'type' in object;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* `gen_ai.input.messages` with every nameless media part replaced by its blob
|
|
64
|
+
* stub, or null when there was nothing to repair (the tracing's own JSON is
|
|
65
|
+
* then left untouched).
|
|
66
|
+
*
|
|
67
|
+
* A message's content blocks map one-to-one onto its parts, in order, which is
|
|
68
|
+
* what lets the repair walk them in step.
|
|
69
|
+
*/
|
|
70
|
+
function repairMediaInputParts(inputMessagesJson, requestMessages) {
|
|
71
|
+
if (typeof inputMessagesJson !== 'string' || !Array.isArray(requestMessages))
|
|
72
|
+
return null;
|
|
73
|
+
let messages;
|
|
74
|
+
try {
|
|
75
|
+
messages = JSON.parse(inputMessagesJson);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
if (!Array.isArray(messages))
|
|
81
|
+
return null;
|
|
82
|
+
let repaired = false;
|
|
83
|
+
const messageCount = Math.min(messages.length, requestMessages.length);
|
|
84
|
+
for (let messageIndex = 0; messageIndex < messageCount; messageIndex++) {
|
|
85
|
+
const parts = asObject(messages[messageIndex])?.parts;
|
|
86
|
+
const content = asObject(requestMessages[messageIndex])?.content;
|
|
87
|
+
if (!Array.isArray(parts) || !Array.isArray(content))
|
|
88
|
+
continue;
|
|
89
|
+
content.forEach((block, index) => {
|
|
90
|
+
if (index >= parts.length || !isNamelessMediaPart(parts[index]))
|
|
91
|
+
return;
|
|
92
|
+
const mediaStub = getMediaStub(block);
|
|
93
|
+
if (mediaStub !== null) {
|
|
94
|
+
parts[index] = mediaStub;
|
|
95
|
+
repaired = true;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return repaired ? JSON.stringify(messages) : null;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Re-stamp `gen_ai.input.messages` when the request carries inline media.
|
|
103
|
+
*
|
|
104
|
+
* Only ever rewrites an attribute the tracing already set, so it never adds
|
|
105
|
+
* message content the tracing did not record.
|
|
106
|
+
*/
|
|
107
|
+
function setInputMessageContentTelemetry(span, requestBody) {
|
|
108
|
+
const attributes = span.attributes ?? {};
|
|
109
|
+
const repairedMessages = repairMediaInputParts(attributes[exports.INPUT_MESSAGES_ATTRIBUTE], requestBody.messages);
|
|
110
|
+
if (repairedMessages !== null) {
|
|
111
|
+
span.setAttribute(exports.INPUT_MESSAGES_ATTRIBUTE, repairedMessages);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured-output schema capture for Mistral spans.
|
|
3
|
+
*
|
|
4
|
+
* Mistral pins an answer to a JSON schema with
|
|
5
|
+
* `response_format: { type: 'json_schema', json_schema: { schema: {...} } }`.
|
|
6
|
+
* The SDK's built-in tracing enriches the span with the request's sampling
|
|
7
|
+
* params, messages and tool definitions, but never the schema. The request
|
|
8
|
+
* body read here is the one sent on the wire, so its keys are snake_case
|
|
9
|
+
* whatever the caller wrote.
|
|
10
|
+
*/
|
|
11
|
+
/** The schema under `response_format.json_schema.schema`, or undefined when
|
|
12
|
+
* the request asked for no structured output. */
|
|
13
|
+
export declare function extractStructuredOutputSchema(requestBody: Record<string, unknown>): unknown;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Structured-output schema capture for Mistral spans.
|
|
4
|
+
*
|
|
5
|
+
* Mistral pins an answer to a JSON schema with
|
|
6
|
+
* `response_format: { type: 'json_schema', json_schema: { schema: {...} } }`.
|
|
7
|
+
* The SDK's built-in tracing enriches the span with the request's sampling
|
|
8
|
+
* params, messages and tool definitions, but never the schema. The request
|
|
9
|
+
* body read here is the one sent on the wire, so its keys are snake_case
|
|
10
|
+
* whatever the caller wrote.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.extractStructuredOutputSchema = extractStructuredOutputSchema;
|
|
14
|
+
/** The schema under `response_format.json_schema.schema`, or undefined when
|
|
15
|
+
* the request asked for no structured output. */
|
|
16
|
+
function extractStructuredOutputSchema(requestBody) {
|
|
17
|
+
const responseFormat = requestBody.response_format;
|
|
18
|
+
if (typeof responseFormat !== 'object' || responseFormat === null)
|
|
19
|
+
return undefined;
|
|
20
|
+
const jsonSchema = responseFormat.json_schema;
|
|
21
|
+
if (typeof jsonSchema !== 'object' || jsonSchema === null)
|
|
22
|
+
return undefined;
|
|
23
|
+
return jsonSchema.schema;
|
|
24
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tracing for Mistral's models called on Vertex AI through `MistralGCP`.
|
|
3
|
+
*
|
|
4
|
+
* `@mistralai/mistralai-gcp` is Mistral's client for its models on Vertex AI
|
|
5
|
+
* (`rawPredict` / `streamRawPredict`). Unlike `@mistralai/mistralai`, it
|
|
6
|
+
* registers no `TracingHook`, so the SDK's built-in tracing that
|
|
7
|
+
* `MistralInstrumentor` opts into never sees its calls. This registers that
|
|
8
|
+
* same hook, from `@mistralai/mistralai`, on every `MistralGCP` client: its
|
|
9
|
+
* `SDKHooks` runs `sdkInit` from the client's constructor, where the hook is
|
|
10
|
+
* registered before the original runs, so the tracing hook's own `sdkInit`
|
|
11
|
+
* wraps the client's HTTP client too. The client's sub-clients (`chat`, `fim`)
|
|
12
|
+
* run `sdkInit` again on the same `SDKHooks`, which then registers nothing.
|
|
13
|
+
*
|
|
14
|
+
* Next to it, a hook of its own stamps two things the tracing hook cannot know:
|
|
15
|
+
* - `weflayr.billing_provider` set to `vertex`, which the worker prices by
|
|
16
|
+
* (Google bills these calls at Vertex's prices), while `gen_ai.provider.name`,
|
|
17
|
+
* which it parses by, stays Mistral's;
|
|
18
|
+
* - the failure of a call Vertex refuses: its error body is Google's
|
|
19
|
+
* (`{"error": {"code": 404, "message": ..., "status": "NOT_FOUND"}}`), not the
|
|
20
|
+
* `{"object": "error"}` one the tracing hook recognizes, so it would otherwise
|
|
21
|
+
* end the span as a success.
|
|
22
|
+
*/
|
|
23
|
+
export declare const MISTRAL_GCP_HOOKS_MODULE = "@mistralai/mistralai-gcp/hooks/hooks.js";
|
|
24
|
+
export type LoadModule = (specifier: string) => Promise<any>;
|
|
25
|
+
/** Stamps the billing provider when the request is sent, and the failure when
|
|
26
|
+
* Vertex refuses it, on the span the tracing hook keeps on the hook context. */
|
|
27
|
+
export declare class VertexHook {
|
|
28
|
+
private readonly tracingSpanKey;
|
|
29
|
+
constructor(tracingSpanKey: string);
|
|
30
|
+
beforeRequest(hookContext: any, request: Request): Request;
|
|
31
|
+
afterError(hookContext: any, response: Response | null, error: unknown): Promise<{
|
|
32
|
+
response: Response | null;
|
|
33
|
+
error: unknown;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The message and the type of the error Vertex answered with. Its body is
|
|
38
|
+
* Google's error object, alone or in a one-item list, or plain text.
|
|
39
|
+
*
|
|
40
|
+
* Example: a 404 whose body is `{"error": {"code": 404, "message": "Not
|
|
41
|
+
* found.", "status": "NOT_FOUND"}}` gives `["Not found.", "NOT_FOUND"]`, a 400
|
|
42
|
+
* whose body is `reasoning_effort is not supported` gives
|
|
43
|
+
* `["reasoning_effort is not supported", null]`.
|
|
44
|
+
*/
|
|
45
|
+
export declare function readVertexError(response: Response): Promise<[string, string | null]>;
|
|
46
|
+
/** Register the tracing hook, and the Vertex one, on every `MistralGCP`. */
|
|
47
|
+
export declare class MistralVertexInstrumentor {
|
|
48
|
+
private readonly loadModule;
|
|
49
|
+
private _sdkHooksClass;
|
|
50
|
+
private _originalSdkInit;
|
|
51
|
+
constructor(loadModule: LoadModule);
|
|
52
|
+
instrument(tracingModule: any): Promise<void>;
|
|
53
|
+
uninstrument(): void;
|
|
54
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tracing for Mistral's models called on Vertex AI through `MistralGCP`.
|
|
4
|
+
*
|
|
5
|
+
* `@mistralai/mistralai-gcp` is Mistral's client for its models on Vertex AI
|
|
6
|
+
* (`rawPredict` / `streamRawPredict`). Unlike `@mistralai/mistralai`, it
|
|
7
|
+
* registers no `TracingHook`, so the SDK's built-in tracing that
|
|
8
|
+
* `MistralInstrumentor` opts into never sees its calls. This registers that
|
|
9
|
+
* same hook, from `@mistralai/mistralai`, on every `MistralGCP` client: its
|
|
10
|
+
* `SDKHooks` runs `sdkInit` from the client's constructor, where the hook is
|
|
11
|
+
* registered before the original runs, so the tracing hook's own `sdkInit`
|
|
12
|
+
* wraps the client's HTTP client too. The client's sub-clients (`chat`, `fim`)
|
|
13
|
+
* run `sdkInit` again on the same `SDKHooks`, which then registers nothing.
|
|
14
|
+
*
|
|
15
|
+
* Next to it, a hook of its own stamps two things the tracing hook cannot know:
|
|
16
|
+
* - `weflayr.billing_provider` set to `vertex`, which the worker prices by
|
|
17
|
+
* (Google bills these calls at Vertex's prices), while `gen_ai.provider.name`,
|
|
18
|
+
* which it parses by, stays Mistral's;
|
|
19
|
+
* - the failure of a call Vertex refuses: its error body is Google's
|
|
20
|
+
* (`{"error": {"code": 404, "message": ..., "status": "NOT_FOUND"}}`), not the
|
|
21
|
+
* `{"object": "error"}` one the tracing hook recognizes, so it would otherwise
|
|
22
|
+
* end the span as a success.
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.MistralVertexInstrumentor = exports.VertexHook = exports.MISTRAL_GCP_HOOKS_MODULE = void 0;
|
|
26
|
+
exports.readVertexError = readVertexError;
|
|
27
|
+
const api_1 = require("@opentelemetry/api");
|
|
28
|
+
const logger_1 = require("../../logger");
|
|
29
|
+
const is_vertex_base_url_1 = require("../shared/is_vertex_base_url");
|
|
30
|
+
exports.MISTRAL_GCP_HOOKS_MODULE = '@mistralai/mistralai-gcp/hooks/hooks.js';
|
|
31
|
+
const ERROR_TYPE_ATTR = 'error.type';
|
|
32
|
+
const FIRST_ERROR_STATUS_CODE = 400;
|
|
33
|
+
// The codes Node throws for a package that is not installed, from require and
|
|
34
|
+
// from import.
|
|
35
|
+
const MODULE_NOT_FOUND_CODES = new Set(['MODULE_NOT_FOUND', 'ERR_MODULE_NOT_FOUND']);
|
|
36
|
+
/** Stamps the billing provider when the request is sent, and the failure when
|
|
37
|
+
* Vertex refuses it, on the span the tracing hook keeps on the hook context. */
|
|
38
|
+
class VertexHook {
|
|
39
|
+
tracingSpanKey;
|
|
40
|
+
constructor(tracingSpanKey) {
|
|
41
|
+
this.tracingSpanKey = tracingSpanKey;
|
|
42
|
+
}
|
|
43
|
+
beforeRequest(hookContext, request) {
|
|
44
|
+
// Never break the user's Mistral call over an enrichment failure.
|
|
45
|
+
try {
|
|
46
|
+
const span = hookContext?.[this.tracingSpanKey];
|
|
47
|
+
if (span?.isRecording() && (0, is_vertex_base_url_1.isVertexBaseURL)(request.url)) {
|
|
48
|
+
span.setAttribute(is_vertex_base_url_1.BILLING_PROVIDER_ATTR, is_vertex_base_url_1.VERTEX_BILLING_PROVIDER);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
(0, logger_1.debug)('mistral vertex: billing provider not stamped: %s', err?.message || err);
|
|
53
|
+
}
|
|
54
|
+
return request;
|
|
55
|
+
}
|
|
56
|
+
async afterError(hookContext, response, error) {
|
|
57
|
+
try {
|
|
58
|
+
await recordVertexError(hookContext?.[this.tracingSpanKey], response);
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
(0, logger_1.debug)('mistral vertex: error not recorded: %s', err?.message || err);
|
|
62
|
+
}
|
|
63
|
+
return { response, error };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.VertexHook = VertexHook;
|
|
67
|
+
async function recordVertexError(span, response) {
|
|
68
|
+
if (!span?.isRecording() || !response || response.status < FIRST_ERROR_STATUS_CODE)
|
|
69
|
+
return;
|
|
70
|
+
const [errorMessage, errorType] = await readVertexError(response);
|
|
71
|
+
span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: errorMessage });
|
|
72
|
+
if (errorType)
|
|
73
|
+
span.setAttribute(ERROR_TYPE_ATTR, errorType);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The message and the type of the error Vertex answered with. Its body is
|
|
77
|
+
* Google's error object, alone or in a one-item list, or plain text.
|
|
78
|
+
*
|
|
79
|
+
* Example: a 404 whose body is `{"error": {"code": 404, "message": "Not
|
|
80
|
+
* found.", "status": "NOT_FOUND"}}` gives `["Not found.", "NOT_FOUND"]`, a 400
|
|
81
|
+
* whose body is `reasoning_effort is not supported` gives
|
|
82
|
+
* `["reasoning_effort is not supported", null]`.
|
|
83
|
+
*/
|
|
84
|
+
async function readVertexError(response) {
|
|
85
|
+
const text = await response.clone().text();
|
|
86
|
+
let body;
|
|
87
|
+
try {
|
|
88
|
+
body = JSON.parse(text);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
body = undefined;
|
|
92
|
+
}
|
|
93
|
+
if (Array.isArray(body) && body.length > 0)
|
|
94
|
+
body = body[0];
|
|
95
|
+
const googleError = typeof body === 'object' && body !== null ? body.error : undefined;
|
|
96
|
+
if (typeof googleError !== 'object' || googleError === null) {
|
|
97
|
+
return [text || `HTTP ${response.status}`, null];
|
|
98
|
+
}
|
|
99
|
+
const { message, status } = googleError;
|
|
100
|
+
return [String(message || `HTTP ${response.status}`), status ? String(status) : null];
|
|
101
|
+
}
|
|
102
|
+
/** Register the tracing hook, and the Vertex one, on every `MistralGCP`. */
|
|
103
|
+
class MistralVertexInstrumentor {
|
|
104
|
+
loadModule;
|
|
105
|
+
_sdkHooksClass;
|
|
106
|
+
_originalSdkInit;
|
|
107
|
+
constructor(loadModule) {
|
|
108
|
+
this.loadModule = loadModule;
|
|
109
|
+
}
|
|
110
|
+
async instrument(tracingModule) {
|
|
111
|
+
let hooksModule;
|
|
112
|
+
try {
|
|
113
|
+
hooksModule = await this.loadModule(exports.MISTRAL_GCP_HOOKS_MODULE);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
// Calls to Vertex need @mistralai/mistralai-gcp, a package of its own.
|
|
117
|
+
if (MODULE_NOT_FOUND_CODES.has(err?.code ?? ''))
|
|
118
|
+
return;
|
|
119
|
+
throw err;
|
|
120
|
+
}
|
|
121
|
+
if (this._originalSdkInit)
|
|
122
|
+
return;
|
|
123
|
+
const { TracingHook, TRACING_SPAN_KEY } = tracingModule;
|
|
124
|
+
const sdkHooksClass = hooksModule.SDKHooks;
|
|
125
|
+
const originalSdkInit = sdkHooksClass.prototype.sdkInit;
|
|
126
|
+
const instrumentedHooks = new WeakSet();
|
|
127
|
+
sdkHooksClass.prototype.sdkInit = function sdkInitWithTracing(...args) {
|
|
128
|
+
if (!instrumentedHooks.has(this)) {
|
|
129
|
+
instrumentedHooks.add(this);
|
|
130
|
+
const tracingHook = new TracingHook();
|
|
131
|
+
const vertexHook = new VertexHook(TRACING_SPAN_KEY);
|
|
132
|
+
this.registerSDKInitHook(tracingHook);
|
|
133
|
+
this.registerBeforeRequestHook(tracingHook);
|
|
134
|
+
this.registerBeforeRequestHook(vertexHook);
|
|
135
|
+
this.registerAfterSuccessHook(tracingHook);
|
|
136
|
+
// Ahead of the tracing hook, which ends the span.
|
|
137
|
+
this.registerAfterErrorHook(vertexHook);
|
|
138
|
+
this.registerAfterErrorHook(tracingHook);
|
|
139
|
+
}
|
|
140
|
+
return originalSdkInit.apply(this, args);
|
|
141
|
+
};
|
|
142
|
+
this._sdkHooksClass = sdkHooksClass;
|
|
143
|
+
this._originalSdkInit = originalSdkInit;
|
|
144
|
+
}
|
|
145
|
+
uninstrument() {
|
|
146
|
+
if (!this._originalSdkInit)
|
|
147
|
+
return;
|
|
148
|
+
this._sdkHooksClass.prototype.sdkInit = this._originalSdkInit;
|
|
149
|
+
this._sdkHooksClass = undefined;
|
|
150
|
+
this._originalSdkInit = undefined;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
exports.MistralVertexInstrumentor = MistralVertexInstrumentor;
|
|
@@ -15,6 +15,11 @@
|
|
|
15
15
|
* OpenLLMetry instrumentor passes the client correctly, so this gap is
|
|
16
16
|
* Node-only.
|
|
17
17
|
*
|
|
18
|
+
* - **The region is missing.** AWS bills a Bedrock call at the price of the
|
|
19
|
+
* region it is sent to, and on Mantle the host names it, so it is read off
|
|
20
|
+
* the client's base URL. A call carrying no region is priced by no row at
|
|
21
|
+
* all.
|
|
22
|
+
*
|
|
18
23
|
* - **The chain of thought is dropped.** Mantle's open-weight models (gpt-oss,
|
|
19
24
|
* qwen, ...) return their reasoning under `reasoning`, which neither the
|
|
20
25
|
* output-message builder nor the stream accumulator knows about. Without it a
|
|
@@ -25,6 +30,11 @@
|
|
|
25
30
|
export declare class OpenAIBedrockMantleInstrumentor {
|
|
26
31
|
private _patched;
|
|
27
32
|
instrument(instrumentation: any): void;
|
|
33
|
+
/**
|
|
34
|
+
* Stamp the AWS region Mantle's host names, the region AWS bills the call at.
|
|
35
|
+
* A client reached at another host names no region.
|
|
36
|
+
*/
|
|
37
|
+
private _patchProviderRegion;
|
|
28
38
|
/** Hand the vendor detection the real client, not the resource it is called with. */
|
|
29
39
|
private _patchVendorDetection;
|
|
30
40
|
/** Accumulate `delta.reasoning` across the streamed chunks. */
|
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
* OpenLLMetry instrumentor passes the client correctly, so this gap is
|
|
17
17
|
* Node-only.
|
|
18
18
|
*
|
|
19
|
+
* - **The region is missing.** AWS bills a Bedrock call at the price of the
|
|
20
|
+
* region it is sent to, and on Mantle the host names it, so it is read off
|
|
21
|
+
* the client's base URL. A call carrying no region is priced by no row at
|
|
22
|
+
* all.
|
|
23
|
+
*
|
|
19
24
|
* - **The chain of thought is dropped.** Mantle's open-weight models (gpt-oss,
|
|
20
25
|
* qwen, ...) return their reasoning under `reasoning`, which neither the
|
|
21
26
|
* output-message builder nor the stream accumulator knows about. Without it a
|
|
@@ -26,6 +31,9 @@
|
|
|
26
31
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
32
|
exports.OpenAIBedrockMantleInstrumentor = void 0;
|
|
28
33
|
const OUTPUT_MESSAGES_ATTR = 'gen_ai.output.messages';
|
|
34
|
+
const PROVIDER_REGION_ATTR = 'weflayr.provider_region';
|
|
35
|
+
// Mantle's host names the AWS region it serves from.
|
|
36
|
+
const MANTLE_HOST_RE = /bedrock-mantle\.([a-z0-9-]+)\.api\.aws/i;
|
|
29
37
|
// Reasoning streamed so far, per open span. Streamed deltas arrive while the
|
|
30
38
|
// stream is consumed, but the output message is only built when the span ends,
|
|
31
39
|
// so the two hooks below meet here.
|
|
@@ -72,9 +80,34 @@ class OpenAIBedrockMantleInstrumentor {
|
|
|
72
80
|
if (!instrumentation)
|
|
73
81
|
return;
|
|
74
82
|
this._patchVendorDetection(instrumentation);
|
|
83
|
+
this._patchProviderRegion(instrumentation);
|
|
75
84
|
this._patchStreamedReasoning(instrumentation);
|
|
76
85
|
this._patchOutputMessages(instrumentation);
|
|
77
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Stamp the AWS region Mantle's host names, the region AWS bills the call at.
|
|
89
|
+
* A client reached at another host names no region.
|
|
90
|
+
*/
|
|
91
|
+
_patchProviderRegion(instrumentation) {
|
|
92
|
+
const original = instrumentation.startSpan;
|
|
93
|
+
if (typeof original !== 'function')
|
|
94
|
+
return;
|
|
95
|
+
instrumentation.startSpan = function startSpanWithProviderRegion(request) {
|
|
96
|
+
const span = original.call(this, request);
|
|
97
|
+
try {
|
|
98
|
+
const client = request && request.client;
|
|
99
|
+
const resolved = client && !client.baseURL && client._client ? client._client : client;
|
|
100
|
+
const hostMatch = MANTLE_HOST_RE.exec(String((resolved && resolved.baseURL) || ''));
|
|
101
|
+
if (hostMatch)
|
|
102
|
+
span.setAttribute(PROVIDER_REGION_ATTR, hostMatch[1]);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Never break span creation over an enrichment failure.
|
|
106
|
+
}
|
|
107
|
+
return span;
|
|
108
|
+
};
|
|
109
|
+
this._patched.push([instrumentation, 'startSpan', original]);
|
|
110
|
+
}
|
|
78
111
|
/** Hand the vendor detection the real client, not the resource it is called with. */
|
|
79
112
|
_patchVendorDetection(instrumentation) {
|
|
80
113
|
const original = instrumentation._detectVendorFromURL;
|
|
@@ -7,18 +7,25 @@
|
|
|
7
7
|
* cached-token count. The Python OpenLLMetry instrumentor sets
|
|
8
8
|
* `gen_ai.usage.cache_read_input_tokens` from the former, so this brings the Node
|
|
9
9
|
* SDK to parity; the latter (GPT-5.6+'s cache-write count) has no OpenLLMetry
|
|
10
|
-
* equivalent on either side, so this is its only source.
|
|
10
|
+
* equivalent on either side, so this is its only source. Alibaba's explicit
|
|
11
|
+
* context cache (a `cache_control: {type: "ephemeral"}` marker on a message
|
|
12
|
+
* content block, confirmed against a real workspace on 2026-09-21) reports the
|
|
13
|
+
* same fact under the Anthropic-shaped `.cache_creation_input_tokens` key
|
|
14
|
+
* instead, read here too.
|
|
11
15
|
*
|
|
12
16
|
* It wraps the instrumentor instance's `_endSpan({ span, type, result })`, which
|
|
13
17
|
* finalizes the span after the response resolves, letting us stamp the
|
|
14
18
|
* cached-token counts off `result.usage` while the span is still open.
|
|
15
|
-
*
|
|
16
|
-
* the attribute name the normalizer already reads for Anthropic/Bedrock
|
|
19
|
+
* Either cache-write key is stamped as `gen_ai.usage.cache_creation_input_tokens`,
|
|
20
|
+
* the attribute name the normalizer already reads for Anthropic/Bedrock.
|
|
17
21
|
*
|
|
18
22
|
* The same hook surfaces the reasoning-token count: reasoning models report it as
|
|
19
|
-
* `usage.completion_tokens_details.reasoning_tokens
|
|
20
|
-
*
|
|
21
|
-
*
|
|
23
|
+
* `usage.completion_tokens_details.reasoning_tokens`, which the Node instrumentor
|
|
24
|
+
* drops, so this stamps the flat `reasoning_tokens` attribute (the form the Python
|
|
25
|
+
* instrumentor emits and the normalizer reads). OpenAI counts those tokens inside
|
|
26
|
+
* `completion_tokens`, xAI counts them outside it (see the worker's
|
|
27
|
+
* `normalizers/spacexai.py`); either way what is stamped here is the raw count the
|
|
28
|
+
* response reported, and the normalizer decides what to add it to.
|
|
22
29
|
*/
|
|
23
30
|
export declare class OpenAIPromptCachingInstrumentor {
|
|
24
31
|
private _patched;
|
|
@@ -8,18 +8,25 @@
|
|
|
8
8
|
* cached-token count. The Python OpenLLMetry instrumentor sets
|
|
9
9
|
* `gen_ai.usage.cache_read_input_tokens` from the former, so this brings the Node
|
|
10
10
|
* SDK to parity; the latter (GPT-5.6+'s cache-write count) has no OpenLLMetry
|
|
11
|
-
* equivalent on either side, so this is its only source.
|
|
11
|
+
* equivalent on either side, so this is its only source. Alibaba's explicit
|
|
12
|
+
* context cache (a `cache_control: {type: "ephemeral"}` marker on a message
|
|
13
|
+
* content block, confirmed against a real workspace on 2026-09-21) reports the
|
|
14
|
+
* same fact under the Anthropic-shaped `.cache_creation_input_tokens` key
|
|
15
|
+
* instead, read here too.
|
|
12
16
|
*
|
|
13
17
|
* It wraps the instrumentor instance's `_endSpan({ span, type, result })`, which
|
|
14
18
|
* finalizes the span after the response resolves, letting us stamp the
|
|
15
19
|
* cached-token counts off `result.usage` while the span is still open.
|
|
16
|
-
*
|
|
17
|
-
* the attribute name the normalizer already reads for Anthropic/Bedrock
|
|
20
|
+
* Either cache-write key is stamped as `gen_ai.usage.cache_creation_input_tokens`,
|
|
21
|
+
* the attribute name the normalizer already reads for Anthropic/Bedrock.
|
|
18
22
|
*
|
|
19
23
|
* The same hook surfaces the reasoning-token count: reasoning models report it as
|
|
20
|
-
* `usage.completion_tokens_details.reasoning_tokens
|
|
21
|
-
*
|
|
22
|
-
*
|
|
24
|
+
* `usage.completion_tokens_details.reasoning_tokens`, which the Node instrumentor
|
|
25
|
+
* drops, so this stamps the flat `reasoning_tokens` attribute (the form the Python
|
|
26
|
+
* instrumentor emits and the normalizer reads). OpenAI counts those tokens inside
|
|
27
|
+
* `completion_tokens`, xAI counts them outside it (see the worker's
|
|
28
|
+
* `normalizers/spacexai.py`); either way what is stamped here is the raw count the
|
|
29
|
+
* response reported, and the normalizer decides what to add it to.
|
|
23
30
|
*/
|
|
24
31
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
32
|
exports.OpenAIPromptCachingInstrumentor = void 0;
|
|
@@ -44,7 +51,10 @@ class OpenAIPromptCachingInstrumentor {
|
|
|
44
51
|
if (cachedTokens && recording) {
|
|
45
52
|
span.setAttribute(CACHE_READ_INPUT_TOKENS_ATTR, cachedTokens);
|
|
46
53
|
}
|
|
47
|
-
const cacheWriteTokens = usage &&
|
|
54
|
+
const cacheWriteTokens = usage &&
|
|
55
|
+
usage.prompt_tokens_details &&
|
|
56
|
+
(usage.prompt_tokens_details.cache_write_tokens ||
|
|
57
|
+
usage.prompt_tokens_details.cache_creation_input_tokens);
|
|
48
58
|
if (cacheWriteTokens && recording) {
|
|
49
59
|
span.setAttribute(CACHE_CREATION_INPUT_TOKENS_ATTR, cacheWriteTokens);
|
|
50
60
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Request-side
|
|
2
|
+
* Request-side param capture for OpenAI chat and Responses spans.
|
|
3
3
|
*
|
|
4
4
|
* OpenAI callers influence the (automatic, server-side) prompt cache with
|
|
5
5
|
* request parameters the traceloop instrumentor never records:
|
|
@@ -11,15 +11,32 @@
|
|
|
11
11
|
* message content block (`prompt_cache_options: { mode: "explicit" }`
|
|
12
12
|
* disables the automatic breakpoint, requiring these to cache anything).
|
|
13
13
|
*
|
|
14
|
+
* It covers the chat and the Responses endpoints alike: both take the same
|
|
15
|
+
* params, and a marker sits on a content block of either `messages` (chat) or
|
|
16
|
+
* `input` (Responses), recorded as `messages[i]` / `input[i]`. A Responses
|
|
17
|
+
* request's `instructions` count as its item 0 when it sends them, as the
|
|
18
|
+
* worker numbers every provider's system prompt.
|
|
19
|
+
*
|
|
14
20
|
* Wrap `startSpan({ type, params })` (covering the streamed and non-streamed
|
|
15
21
|
* paths) to stamp the values as `weflayr.cache.key` / `weflayr.cache.retention`
|
|
16
22
|
* (raw retention/ttl string) and, when any content block carries the marker,
|
|
17
|
-
* `weflayr.cache.breakpoints
|
|
18
|
-
*
|
|
19
|
-
*
|
|
23
|
+
* `weflayr.cache.breakpoints`: a JSON list of `{"location": "messages[i]"}` /
|
|
24
|
+
* `{"location": "input[i]"}` entries for OpenAI's own `prompt_cache_breakpoint`
|
|
25
|
+
* marker (which carries no TTL of its own; the normalizer falls back to the
|
|
26
|
+
* request-level retention and owns the vocabulary) or, for a content block
|
|
27
|
+
* carrying Anthropic's `cache_control` convention instead (Alibaba (Qwen) is
|
|
28
|
+
* reached through this same openai-shape client and opts into its *explicit*
|
|
29
|
+
* cache this way, unlike real OpenAI), `{"location": ..., "ttl": ...}`, the raw
|
|
30
|
+
* `ttl` string carried on the marker itself, omitted when it sets none.
|
|
20
31
|
* `prompt_cache_options: { mode: "explicit" }` is stamped as
|
|
21
32
|
* `weflayr.cache.mode` so the normalizer knows not to also synthesize the
|
|
22
33
|
* automatic "auto"-location breakpoint OpenAI does not create in this mode.
|
|
34
|
+
*
|
|
35
|
+
* The same wrapper stamps the output-token limit when the caller sent it as
|
|
36
|
+
* `max_completion_tokens`: the traceloop instrumentor reads only `max_tokens`,
|
|
37
|
+
* which the reasoning models (o-series, GPT-5 and later) reject, so their calls
|
|
38
|
+
* would record no limit at all. It lives here because this is the one place the
|
|
39
|
+
* request's own params are read.
|
|
23
40
|
*/
|
|
24
41
|
export declare class OpenAICacheConfigInstrumentor {
|
|
25
42
|
private _patched;
|