weflayr 0.27.0 → 0.29.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 +4 -4
- 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_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 +49 -13
- package/dist/src/otel/propagation.js +71 -28
- 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 +4 -4
- 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
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "weflayr",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"description": "Weflayr JS/TS SDK — instrument any LLM client",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -31,15 +31,15 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@opentelemetry/api": "^1.9.1",
|
|
34
|
-
"@opentelemetry/exporter-trace-otlp-http": "^0.
|
|
35
|
-
"@opentelemetry/instrumentation": "^0.
|
|
34
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.222.0",
|
|
35
|
+
"@opentelemetry/instrumentation": "^0.222.0",
|
|
36
36
|
"@opentelemetry/resources": "^2.8.0",
|
|
37
37
|
"@opentelemetry/sdk-trace-base": "^2.8.0",
|
|
38
38
|
"@opentelemetry/sdk-trace-node": "^2.8.0",
|
|
39
39
|
"async-retry": "^1.3.3"
|
|
40
40
|
},
|
|
41
41
|
"overrides": {
|
|
42
|
-
"js-yaml": "^4.3.
|
|
42
|
+
"js-yaml": "^4.3.2"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@hey-api/openapi-ts": "^0.99.0",
|
|
@@ -6,7 +6,7 @@ export declare const AiSdk: Readonly<{
|
|
|
6
6
|
COHERE: "cohere";
|
|
7
7
|
GOOGLE_GENAI: "google-genai";
|
|
8
8
|
ELEVENLABS: "elevenlabs";
|
|
9
|
-
|
|
9
|
+
MISTRAL: "mistral";
|
|
10
10
|
}>;
|
|
11
11
|
export type AiSdk = (typeof AiSdk)[keyof typeof AiSdk];
|
|
12
12
|
export declare const AIProviderName: Readonly<{
|
|
@@ -17,9 +17,10 @@ export declare const AIProviderName: Readonly<{
|
|
|
17
17
|
COHERE: "cohere";
|
|
18
18
|
ELEVENLABS: "elevenlabs";
|
|
19
19
|
MISTRAL: "mistral";
|
|
20
|
-
|
|
21
|
-
GEMINI: "gemini";
|
|
20
|
+
GOOGLE: "google";
|
|
22
21
|
VERTEX: "vertex";
|
|
22
|
+
ALIBABA: "alibaba";
|
|
23
|
+
SPACEXAI: "spacexai";
|
|
23
24
|
}>;
|
|
24
25
|
export type AIProviderName = (typeof AIProviderName)[keyof typeof AIProviderName];
|
|
25
26
|
interface RegistryEntry {
|
|
@@ -12,13 +12,13 @@ exports.AiSdk = Object.freeze({
|
|
|
12
12
|
COHERE: 'cohere',
|
|
13
13
|
GOOGLE_GENAI: 'google-genai',
|
|
14
14
|
ELEVENLABS: 'elevenlabs',
|
|
15
|
-
|
|
15
|
+
MISTRAL: 'mistral',
|
|
16
16
|
});
|
|
17
|
-
// Allowed values for `propagateMetadata({
|
|
17
|
+
// Allowed values for `propagateMetadata({ providerNameOverrideIfTelemetryInstrumentation })`: the actual AI
|
|
18
18
|
// providers a call can be attributed to. Unlike AiSdk this names providers,
|
|
19
|
-
// not SDKs — google-genai is an SDK whose calls are
|
|
20
|
-
// and mistral
|
|
21
|
-
//
|
|
19
|
+
// not SDKs — google-genai is an SDK whose calls are labeled google or vertex,
|
|
20
|
+
// and mistral can also be reached through the OpenAI SDK (OpenAI-compatible
|
|
21
|
+
// endpoint) while being reported as itself.
|
|
22
22
|
exports.AIProviderName = Object.freeze({
|
|
23
23
|
OPENAI: 'openai',
|
|
24
24
|
AZURE_OPENAI: 'azure',
|
|
@@ -27,15 +27,16 @@ exports.AIProviderName = Object.freeze({
|
|
|
27
27
|
COHERE: 'cohere',
|
|
28
28
|
ELEVENLABS: 'elevenlabs',
|
|
29
29
|
MISTRAL: 'mistral',
|
|
30
|
-
|
|
31
|
-
GEMINI: 'gemini',
|
|
30
|
+
GOOGLE: 'google',
|
|
32
31
|
VERTEX: 'vertex',
|
|
32
|
+
ALIBABA: 'alibaba',
|
|
33
|
+
SPACEXAI: 'spacexai',
|
|
33
34
|
});
|
|
34
35
|
// The primary instrumentor for each provider SDK. Most are third-party
|
|
35
36
|
// traceloop packages, loaded by `package` name. Providers with no usable
|
|
36
|
-
// third-party instrumentor (
|
|
37
|
-
// `className` pointing at the instrumentor
|
|
38
|
-
//
|
|
37
|
+
// third-party instrumentor (ElevenLabs, and Mistral, whose SDK traces itself)
|
|
38
|
+
// instead carry a `requirePath` + `className` pointing at the instrumentor
|
|
39
|
+
// weflayr ships itself; `package` then names the provider SDK.
|
|
39
40
|
const REGISTRY = {
|
|
40
41
|
[exports.AiSdk.OPENAI]: { package: '@traceloop/instrumentation-openai' },
|
|
41
42
|
[exports.AiSdk.ANTHROPIC]: { package: '@traceloop/instrumentation-anthropic' },
|
|
@@ -47,10 +48,10 @@ const REGISTRY = {
|
|
|
47
48
|
requirePath: './instrumentation/elevenlabs/full_instrumentation',
|
|
48
49
|
className: 'ElevenLabsInstrumentor',
|
|
49
50
|
},
|
|
50
|
-
[exports.AiSdk.
|
|
51
|
-
package: '
|
|
52
|
-
requirePath: './instrumentation/
|
|
53
|
-
className: '
|
|
51
|
+
[exports.AiSdk.MISTRAL]: {
|
|
52
|
+
package: '@mistralai/mistralai',
|
|
53
|
+
requirePath: './instrumentation/mistral/full_instrumentation',
|
|
54
|
+
className: 'MistralInstrumentor',
|
|
54
55
|
},
|
|
55
56
|
};
|
|
56
57
|
exports.REGISTRY = REGISTRY;
|
|
@@ -105,10 +106,10 @@ async function _instrumentAiSdk(aiSdk) {
|
|
|
105
106
|
}
|
|
106
107
|
const entry = REGISTRY[aiSdk];
|
|
107
108
|
if (entry.requirePath) {
|
|
108
|
-
// No usable third-party instrumentor
|
|
109
|
-
//
|
|
109
|
+
// No usable third-party instrumentor: use the one bundled with weflayr
|
|
110
|
+
// (it covers every endpoint of the provider).
|
|
110
111
|
const Instrumentor = require(entry.requirePath)[entry.className];
|
|
111
|
-
new Instrumentor().instrument();
|
|
112
|
+
await new Instrumentor().instrument();
|
|
112
113
|
(0, logger_1.debug)('autoInstrument: registered aiSdk=%s package=%s', aiSdk, entry.package);
|
|
113
114
|
return;
|
|
114
115
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading the mime type out of a `data:` URI.
|
|
3
|
+
*
|
|
4
|
+
* Providers hand inline media to the span in several shapes, and four of them
|
|
5
|
+
* carry the bytes as a data URI: OpenAI's `image_url.url` and `file.file_data`,
|
|
6
|
+
* Mistral's `image_url` and `document_url`, and Cohere v2's `image_url.url`.
|
|
7
|
+
* The instrumentation complements and the span processor all need the mime type
|
|
8
|
+
* out of those, so they read it here rather than each parsing the URI again.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* The mime type of a `data:<mime_type>[;base64],<payload>` URI, or null when
|
|
12
|
+
* the string is not a data URI.
|
|
13
|
+
*
|
|
14
|
+
* e.g. `"data:image/png;base64,AAA"` -> `"image/png"`,
|
|
15
|
+
* `"https://example.com/cat.png"` -> `null`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getDataUriMimeType(uri: string): string | null;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Reading the mime type out of a `data:` URI.
|
|
4
|
+
*
|
|
5
|
+
* Providers hand inline media to the span in several shapes, and four of them
|
|
6
|
+
* carry the bytes as a data URI: OpenAI's `image_url.url` and `file.file_data`,
|
|
7
|
+
* Mistral's `image_url` and `document_url`, and Cohere v2's `image_url.url`.
|
|
8
|
+
* The instrumentation complements and the span processor all need the mime type
|
|
9
|
+
* out of those, so they read it here rather than each parsing the URI again.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getDataUriMimeType = getDataUriMimeType;
|
|
13
|
+
const DATA_URI_PREFIX = 'data:';
|
|
14
|
+
/**
|
|
15
|
+
* The mime type of a `data:<mime_type>[;base64],<payload>` URI, or null when
|
|
16
|
+
* the string is not a data URI.
|
|
17
|
+
*
|
|
18
|
+
* e.g. `"data:image/png;base64,AAA"` -> `"image/png"`,
|
|
19
|
+
* `"https://example.com/cat.png"` -> `null`.
|
|
20
|
+
*/
|
|
21
|
+
function getDataUriMimeType(uri) {
|
|
22
|
+
if (!uri.startsWith(DATA_URI_PREFIX))
|
|
23
|
+
return null;
|
|
24
|
+
return uri.slice(DATA_URI_PREFIX.length).split(';')[0].split(',')[0];
|
|
25
|
+
}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { setup, flush, type SetupOptions } from './setup';
|
|
2
2
|
import { autoInstrument, AiSdk, AIProviderName } from './auto-instrument';
|
|
3
|
-
import { propagateMetadata, type PropagateMetadataOptions } from './otel/propagation';
|
|
3
|
+
import { createFeatureRunUuid, propagateMetadata, setCallName, type PropagateMetadataOptions } from './otel/propagation';
|
|
4
|
+
import { enablePropagateMetadataToGateway } from './propagate-metadata-to-gateway';
|
|
4
5
|
import type { Tags, OtelSpanAttributes } from './otel/span-processor';
|
|
5
6
|
import * as api from './api';
|
|
6
|
-
export { setup, flush, autoInstrument, AiSdk, AIProviderName, propagateMetadata, api };
|
|
7
|
+
export { setup, flush, autoInstrument, AiSdk, AIProviderName, createFeatureRunUuid, propagateMetadata, setCallName, enablePropagateMetadataToGateway, api, };
|
|
7
8
|
export type { SetupOptions, PropagateMetadataOptions, Tags, OtelSpanAttributes };
|
|
8
9
|
export declare const client: typeof api.client;
|
|
9
10
|
export type { ApiClientOptions } from './api';
|
package/dist/src/index.js
CHANGED
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.client = exports.api = exports.propagateMetadata = exports.AIProviderName = exports.AiSdk = exports.autoInstrument = exports.flush = exports.setup = void 0;
|
|
36
|
+
exports.client = exports.api = exports.enablePropagateMetadataToGateway = exports.setCallName = exports.propagateMetadata = exports.createFeatureRunUuid = exports.AIProviderName = exports.AiSdk = exports.autoInstrument = exports.flush = exports.setup = void 0;
|
|
37
37
|
const setup_1 = require("./setup");
|
|
38
38
|
Object.defineProperty(exports, "setup", { enumerable: true, get: function () { return setup_1.setup; } });
|
|
39
39
|
Object.defineProperty(exports, "flush", { enumerable: true, get: function () { return setup_1.flush; } });
|
|
@@ -42,7 +42,11 @@ Object.defineProperty(exports, "autoInstrument", { enumerable: true, get: functi
|
|
|
42
42
|
Object.defineProperty(exports, "AiSdk", { enumerable: true, get: function () { return auto_instrument_1.AiSdk; } });
|
|
43
43
|
Object.defineProperty(exports, "AIProviderName", { enumerable: true, get: function () { return auto_instrument_1.AIProviderName; } });
|
|
44
44
|
const propagation_1 = require("./otel/propagation");
|
|
45
|
+
Object.defineProperty(exports, "createFeatureRunUuid", { enumerable: true, get: function () { return propagation_1.createFeatureRunUuid; } });
|
|
45
46
|
Object.defineProperty(exports, "propagateMetadata", { enumerable: true, get: function () { return propagation_1.propagateMetadata; } });
|
|
47
|
+
Object.defineProperty(exports, "setCallName", { enumerable: true, get: function () { return propagation_1.setCallName; } });
|
|
48
|
+
const propagate_metadata_to_gateway_1 = require("./propagate-metadata-to-gateway");
|
|
49
|
+
Object.defineProperty(exports, "enablePropagateMetadataToGateway", { enumerable: true, get: function () { return propagate_metadata_to_gateway_1.enablePropagateMetadataToGateway; } });
|
|
46
50
|
// Public-API client (revenue, key metrics, customer tags).
|
|
47
51
|
const api = __importStar(require("./api"));
|
|
48
52
|
exports.api = api;
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
* - the `message_delta` chunk's `delta.stop_reason`, so streamed spans format
|
|
7
7
|
* their output message with an empty `finish_reason`, and
|
|
8
8
|
* - the `content_block_delta` chunks' `input_json_delta` fragments, so a
|
|
9
|
-
* streamed tool call's `tool_call` part carries no `arguments`.
|
|
9
|
+
* streamed tool call's `tool_call` part carries no `arguments`. This covers
|
|
10
|
+
* both a caller's own `tool_use` block and the `server_tool_use` block of a
|
|
11
|
+
* provider-run web search, whose query streams the same way.
|
|
10
12
|
*
|
|
11
13
|
* `_streamingWrapPromise(client, moduleExports, { span, type, promise })`
|
|
12
14
|
* returns `new moduleExports.APIPromise(...)` whose parse step wraps the real
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
* - the `message_delta` chunk's `delta.stop_reason`, so streamed spans format
|
|
8
8
|
* their output message with an empty `finish_reason`, and
|
|
9
9
|
* - the `content_block_delta` chunks' `input_json_delta` fragments, so a
|
|
10
|
-
* streamed tool call's `tool_call` part carries no `arguments`.
|
|
10
|
+
* streamed tool call's `tool_call` part carries no `arguments`. This covers
|
|
11
|
+
* both a caller's own `tool_use` block and the `server_tool_use` block of a
|
|
12
|
+
* provider-run web search, whose query streams the same way.
|
|
11
13
|
*
|
|
12
14
|
* `_streamingWrapPromise(client, moduleExports, { span, type, promise })`
|
|
13
15
|
* returns `new moduleExports.APIPromise(...)` whose parse step wraps the real
|
|
@@ -109,9 +111,10 @@ class AnthropicStreamingAccumulationInstrumentor {
|
|
|
109
111
|
for (const [index, argumentsJson] of gaps.toolArgumentsJsonByIndex) {
|
|
110
112
|
const block = Array.isArray(args.result.content) && args.result.content[index];
|
|
111
113
|
// Only fill the gap: a block whose input upstream DID accumulate
|
|
112
|
-
// (a future version) is left alone.
|
|
114
|
+
// (a future version) is left alone. `server_tool_use` is the
|
|
115
|
+
// provider-run tool (web search), whose query streams the same way.
|
|
113
116
|
if (block &&
|
|
114
|
-
block.type === 'tool_use' &&
|
|
117
|
+
(block.type === 'tool_use' || block.type === 'server_tool_use') &&
|
|
115
118
|
(!block.input || !Object.keys(block.input).length)) {
|
|
116
119
|
try {
|
|
117
120
|
block.input = JSON.parse(argumentsJson);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Billing attribution for Claude called on Vertex AI through `AnthropicVertex`.
|
|
3
|
+
*
|
|
4
|
+
* `AnthropicVertex` (`@anthropic-ai/vertex-sdk`) is Anthropic's client for
|
|
5
|
+
* Claude on Vertex: the same `Messages` resource as the plain `Anthropic`
|
|
6
|
+
* client, pointed at a Vertex AI host. The traceloop instrumentor attributes
|
|
7
|
+
* its calls to "anthropic", which is right for parsing them (the payload and
|
|
8
|
+
* usage are Anthropic's) but not for pricing them: Google bills them at
|
|
9
|
+
* Vertex's prices. So their spans get `weflayr.billing_provider` set to
|
|
10
|
+
* `vertex`, which the worker prices by, while `gen_ai.provider.name`, which it
|
|
11
|
+
* parses by, stays "anthropic".
|
|
12
|
+
*
|
|
13
|
+
* traceloop starts the span in `startSpan`, which is handed the request but not
|
|
14
|
+
* the client. So the client of each call is recorded, for the duration of the
|
|
15
|
+
* call, around the method `patchAnthropic` builds for each wrapped `create`,
|
|
16
|
+
* and read back in `startSpan`, which that method calls synchronously before
|
|
17
|
+
* the request is sent, the error path included.
|
|
18
|
+
*
|
|
19
|
+
* `@anthropic-ai/vertex-sdk` loads `@anthropic-ai/sdk` by its subpaths only
|
|
20
|
+
* (`@anthropic-ai/sdk/client`, `.../resources/index`), which the traceloop
|
|
21
|
+
* hook, registered on the main module, never sees: an app that only uses
|
|
22
|
+
* `AnthropicVertex` would get no span at all. Its `Messages` class is the same
|
|
23
|
+
* object as the main module's `Anthropic.Messages`, so loading the main module
|
|
24
|
+
* once here is what gets it patched.
|
|
25
|
+
*/
|
|
26
|
+
export declare class AnthropicVertexBillingInstrumentor {
|
|
27
|
+
private readonly loadAnthropicSdk;
|
|
28
|
+
private _patched;
|
|
29
|
+
constructor(loadAnthropicSdk?: () => void);
|
|
30
|
+
instrument(instrumentation: any): void;
|
|
31
|
+
uninstrument(): void;
|
|
32
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Billing attribution for Claude called on Vertex AI through `AnthropicVertex`.
|
|
4
|
+
*
|
|
5
|
+
* `AnthropicVertex` (`@anthropic-ai/vertex-sdk`) is Anthropic's client for
|
|
6
|
+
* Claude on Vertex: the same `Messages` resource as the plain `Anthropic`
|
|
7
|
+
* client, pointed at a Vertex AI host. The traceloop instrumentor attributes
|
|
8
|
+
* its calls to "anthropic", which is right for parsing them (the payload and
|
|
9
|
+
* usage are Anthropic's) but not for pricing them: Google bills them at
|
|
10
|
+
* Vertex's prices. So their spans get `weflayr.billing_provider` set to
|
|
11
|
+
* `vertex`, which the worker prices by, while `gen_ai.provider.name`, which it
|
|
12
|
+
* parses by, stays "anthropic".
|
|
13
|
+
*
|
|
14
|
+
* traceloop starts the span in `startSpan`, which is handed the request but not
|
|
15
|
+
* the client. So the client of each call is recorded, for the duration of the
|
|
16
|
+
* call, around the method `patchAnthropic` builds for each wrapped `create`,
|
|
17
|
+
* and read back in `startSpan`, which that method calls synchronously before
|
|
18
|
+
* the request is sent, the error path included.
|
|
19
|
+
*
|
|
20
|
+
* `@anthropic-ai/vertex-sdk` loads `@anthropic-ai/sdk` by its subpaths only
|
|
21
|
+
* (`@anthropic-ai/sdk/client`, `.../resources/index`), which the traceloop
|
|
22
|
+
* hook, registered on the main module, never sees: an app that only uses
|
|
23
|
+
* `AnthropicVertex` would get no span at all. Its `Messages` class is the same
|
|
24
|
+
* object as the main module's `Anthropic.Messages`, so loading the main module
|
|
25
|
+
* once here is what gets it patched.
|
|
26
|
+
*/
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.AnthropicVertexBillingInstrumentor = void 0;
|
|
29
|
+
const is_vertex_base_url_1 = require("../shared/is_vertex_base_url");
|
|
30
|
+
// The anthropic client of the Messages call in progress, undefined outside of
|
|
31
|
+
// one. A module variable is enough: it is set and read in the same synchronous
|
|
32
|
+
// stretch of the call.
|
|
33
|
+
let clientOfTheCallInProgress;
|
|
34
|
+
function requireAnthropicSdk() {
|
|
35
|
+
try {
|
|
36
|
+
require('@anthropic-ai/sdk');
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
throw new Error(`weflayr: @anthropic-ai/sdk could not be loaded (${err?.message || err}). ` +
|
|
40
|
+
'Install it with: npm install @anthropic-ai/sdk');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
class AnthropicVertexBillingInstrumentor {
|
|
44
|
+
loadAnthropicSdk;
|
|
45
|
+
// [instrumentation, methodName, originalFunction] for uninstrument().
|
|
46
|
+
_patched = [];
|
|
47
|
+
constructor(loadAnthropicSdk = requireAnthropicSdk) {
|
|
48
|
+
this.loadAnthropicSdk = loadAnthropicSdk;
|
|
49
|
+
}
|
|
50
|
+
instrument(instrumentation) {
|
|
51
|
+
if (!instrumentation)
|
|
52
|
+
return;
|
|
53
|
+
const originalPatchAnthropic = instrumentation.patchAnthropic;
|
|
54
|
+
const originalStartSpan = instrumentation.startSpan;
|
|
55
|
+
if (typeof originalPatchAnthropic !== 'function' || typeof originalStartSpan !== 'function') {
|
|
56
|
+
throw new Error('weflayr: @traceloop/instrumentation-anthropic no longer defines patchAnthropic and ' +
|
|
57
|
+
'startSpan, so Claude calls made through AnthropicVertex cannot be billed to Vertex.');
|
|
58
|
+
}
|
|
59
|
+
instrumentation.patchAnthropic = function patchAnthropicRecordingTheClient(...patchArgs) {
|
|
60
|
+
const buildTracedMethod = originalPatchAnthropic.apply(this, patchArgs);
|
|
61
|
+
return (original) => {
|
|
62
|
+
const tracedMethod = buildTracedMethod(original);
|
|
63
|
+
return function methodRecordingTheClient(...args) {
|
|
64
|
+
const previousClient = clientOfTheCallInProgress;
|
|
65
|
+
clientOfTheCallInProgress = this?._client;
|
|
66
|
+
try {
|
|
67
|
+
return tracedMethod.apply(this, args);
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
clientOfTheCallInProgress = previousClient;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
this._patched.push([instrumentation, 'patchAnthropic', originalPatchAnthropic]);
|
|
76
|
+
instrumentation.startSpan = function startSpanBilledToVertex(args) {
|
|
77
|
+
const span = originalStartSpan.call(this, args);
|
|
78
|
+
try {
|
|
79
|
+
if (span?.isRecording?.() && (0, is_vertex_base_url_1.isVertexBaseURL)(clientOfTheCallInProgress?.baseURL)) {
|
|
80
|
+
span.setAttribute(is_vertex_base_url_1.BILLING_PROVIDER_ATTR, is_vertex_base_url_1.VERTEX_BILLING_PROVIDER);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// Never break span creation over an enrichment failure.
|
|
85
|
+
}
|
|
86
|
+
return span;
|
|
87
|
+
};
|
|
88
|
+
this._patched.push([instrumentation, 'startSpan', originalStartSpan]);
|
|
89
|
+
// After the two patches above, so the traceloop patch this load triggers
|
|
90
|
+
// builds its methods through them.
|
|
91
|
+
this.loadAnthropicSdk();
|
|
92
|
+
}
|
|
93
|
+
uninstrument() {
|
|
94
|
+
for (const [owner, methodName, original] of [...this._patched].reverse()) {
|
|
95
|
+
owner[methodName] = original;
|
|
96
|
+
}
|
|
97
|
+
this._patched = [];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
exports.AnthropicVertexBillingInstrumentor = AnthropicVertexBillingInstrumentor;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-run web search capture for Anthropic spans.
|
|
3
|
+
*
|
|
4
|
+
* Anthropic runs the search itself when the request carries its server tool
|
|
5
|
+
* (`{ type: 'web_search_20250305', name: 'web_search', ... }`), and bills every
|
|
6
|
+
* search the call ran, reported as `usage.server_tool_use.web_search_requests`.
|
|
7
|
+
*
|
|
8
|
+
* Unlike the Python instrumentor, `@traceloop/instrumentation-anthropic` does
|
|
9
|
+
* put the answer's search blocks on the span, but in its own shapes: a
|
|
10
|
+
* `server_tool_use` block becomes a `server_tool_call` part, and a
|
|
11
|
+
* `web_search_tool_result` block falls through its unknown-block branch and is
|
|
12
|
+
* copied verbatim, `encrypted_content` blobs included, several kilobytes per
|
|
13
|
+
* result, which must never reach the queue. It also drops
|
|
14
|
+
* `usage.server_tool_use`, so the searches are not billed.
|
|
15
|
+
*
|
|
16
|
+
* So this complement does three things, all off `_endSpan`'s accumulated result
|
|
17
|
+
* (which both the streamed and non-streamed paths reach):
|
|
18
|
+
*
|
|
19
|
+
* 1. stamps the request's server tool, the answer's search blocks and the
|
|
20
|
+
* billed count under `weflayr.web_search.*`, in Anthropic's own vocabulary,
|
|
21
|
+
* for `normalizers/anthropic.py` to map;
|
|
22
|
+
* 2. drops the `encrypted_content` blob of every result on the way, the same
|
|
23
|
+
* rule as inline media;
|
|
24
|
+
* 3. removes the search blocks from the result before the instrumentor formats
|
|
25
|
+
* the output message, so the search is recorded once and in one shape. The
|
|
26
|
+
* Python instrumentor writes no such parts, and both SDKs must produce the
|
|
27
|
+
* same event for the same call.
|
|
28
|
+
*/
|
|
29
|
+
/** The request's web search server-tool definitions, as sent. A user-defined
|
|
30
|
+
* function tool carries no `type`, so it never matches. */
|
|
31
|
+
export declare function extractWebSearchToolDefinitions(tools: any): any[];
|
|
32
|
+
/** The answer's search blocks: what the model searched for, and the pages it read
|
|
33
|
+
* back, with the page blobs dropped. */
|
|
34
|
+
export declare function extractWebSearchOutputBlocks(content: any): any[];
|
|
35
|
+
export declare class AnthropicWebSearchInstrumentor {
|
|
36
|
+
private _patched;
|
|
37
|
+
instrument(instrumentation: any): void;
|
|
38
|
+
uninstrument(): void;
|
|
39
|
+
}
|
|
40
|
+
/** Stamp the call's searches and the count it is billed for, then take the search
|
|
41
|
+
* blocks out of the result so the instrumentor's own output message does not
|
|
42
|
+
* carry them a second time. */
|
|
43
|
+
export declare function stampAndStripSearchBlocks(span: any, result: any): void;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Provider-run web search capture for Anthropic spans.
|
|
4
|
+
*
|
|
5
|
+
* Anthropic runs the search itself when the request carries its server tool
|
|
6
|
+
* (`{ type: 'web_search_20250305', name: 'web_search', ... }`), and bills every
|
|
7
|
+
* search the call ran, reported as `usage.server_tool_use.web_search_requests`.
|
|
8
|
+
*
|
|
9
|
+
* Unlike the Python instrumentor, `@traceloop/instrumentation-anthropic` does
|
|
10
|
+
* put the answer's search blocks on the span, but in its own shapes: a
|
|
11
|
+
* `server_tool_use` block becomes a `server_tool_call` part, and a
|
|
12
|
+
* `web_search_tool_result` block falls through its unknown-block branch and is
|
|
13
|
+
* copied verbatim, `encrypted_content` blobs included, several kilobytes per
|
|
14
|
+
* result, which must never reach the queue. It also drops
|
|
15
|
+
* `usage.server_tool_use`, so the searches are not billed.
|
|
16
|
+
*
|
|
17
|
+
* So this complement does three things, all off `_endSpan`'s accumulated result
|
|
18
|
+
* (which both the streamed and non-streamed paths reach):
|
|
19
|
+
*
|
|
20
|
+
* 1. stamps the request's server tool, the answer's search blocks and the
|
|
21
|
+
* billed count under `weflayr.web_search.*`, in Anthropic's own vocabulary,
|
|
22
|
+
* for `normalizers/anthropic.py` to map;
|
|
23
|
+
* 2. drops the `encrypted_content` blob of every result on the way, the same
|
|
24
|
+
* rule as inline media;
|
|
25
|
+
* 3. removes the search blocks from the result before the instrumentor formats
|
|
26
|
+
* the output message, so the search is recorded once and in one shape. The
|
|
27
|
+
* Python instrumentor writes no such parts, and both SDKs must produce the
|
|
28
|
+
* same event for the same call.
|
|
29
|
+
*/
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
exports.AnthropicWebSearchInstrumentor = void 0;
|
|
32
|
+
exports.extractWebSearchToolDefinitions = extractWebSearchToolDefinitions;
|
|
33
|
+
exports.extractWebSearchOutputBlocks = extractWebSearchOutputBlocks;
|
|
34
|
+
exports.stampAndStripSearchBlocks = stampAndStripSearchBlocks;
|
|
35
|
+
const REQUESTS_ATTR = 'weflayr.web_search.requests';
|
|
36
|
+
const TOOL_DEFINITIONS_ATTR = 'weflayr.web_search.tool_definitions';
|
|
37
|
+
const OUTPUT_BLOCKS_ATTR = 'weflayr.web_search.output_blocks';
|
|
38
|
+
// Anthropic versions its server tools by date, so the type of the web search
|
|
39
|
+
// tool changes with each revision while the prefix stays.
|
|
40
|
+
const WEB_SEARCH_TOOL_TYPE_PREFIX = 'web_search';
|
|
41
|
+
// The answer blocks a server-run search produces: the query the model ran, then
|
|
42
|
+
// the pages it got back.
|
|
43
|
+
const SEARCH_QUERY_BLOCK_TYPE = 'server_tool_use';
|
|
44
|
+
const SEARCH_RESULTS_BLOCK_TYPE = 'web_search_tool_result';
|
|
45
|
+
// Per result, an opaque blob of the page Anthropic read. Nothing reads it back.
|
|
46
|
+
const ENCRYPTED_RESULT_FIELD = 'encrypted_content';
|
|
47
|
+
function isWebSearchBlock(block) {
|
|
48
|
+
return (!!block && (block.type === SEARCH_QUERY_BLOCK_TYPE || block.type === SEARCH_RESULTS_BLOCK_TYPE));
|
|
49
|
+
}
|
|
50
|
+
/** A `web_search_tool_result` block without the opaque page blob each of its
|
|
51
|
+
* results carries. */
|
|
52
|
+
function dropEncryptedResults(block) {
|
|
53
|
+
if (!Array.isArray(block.content))
|
|
54
|
+
return block;
|
|
55
|
+
return {
|
|
56
|
+
...block,
|
|
57
|
+
content: block.content.map((result) => {
|
|
58
|
+
if (!result || typeof result !== 'object')
|
|
59
|
+
return result;
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
61
|
+
const { [ENCRYPTED_RESULT_FIELD]: _encrypted, ...kept } = result;
|
|
62
|
+
return kept;
|
|
63
|
+
}),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/** The request's web search server-tool definitions, as sent. A user-defined
|
|
67
|
+
* function tool carries no `type`, so it never matches. */
|
|
68
|
+
function extractWebSearchToolDefinitions(tools) {
|
|
69
|
+
if (!Array.isArray(tools))
|
|
70
|
+
return [];
|
|
71
|
+
return tools.filter((tool) => tool && typeof tool.type === 'string' && tool.type.startsWith(WEB_SEARCH_TOOL_TYPE_PREFIX));
|
|
72
|
+
}
|
|
73
|
+
/** The answer's search blocks: what the model searched for, and the pages it read
|
|
74
|
+
* back, with the page blobs dropped. */
|
|
75
|
+
function extractWebSearchOutputBlocks(content) {
|
|
76
|
+
if (!Array.isArray(content))
|
|
77
|
+
return [];
|
|
78
|
+
return content.filter(isWebSearchBlock).map(dropEncryptedResults);
|
|
79
|
+
}
|
|
80
|
+
class AnthropicWebSearchInstrumentor {
|
|
81
|
+
// [instrumentation, methodName, originalFunction] for uninstrument().
|
|
82
|
+
_patched = [];
|
|
83
|
+
// No-op (and never throws) if the instrumentor's internals have changed shape:
|
|
84
|
+
// the worst case is a missing web search, never a crash.
|
|
85
|
+
instrument(instrumentation) {
|
|
86
|
+
if (!instrumentation)
|
|
87
|
+
return;
|
|
88
|
+
// Request side: the same `startSpan(request)` the tool-definitions
|
|
89
|
+
// complement wraps, for both the streamed and non-streamed paths.
|
|
90
|
+
const startSpanOriginal = instrumentation.startSpan;
|
|
91
|
+
if (typeof startSpanOriginal === 'function') {
|
|
92
|
+
instrumentation.startSpan = function startSpanWithWebSearch(request) {
|
|
93
|
+
const span = startSpanOriginal.call(this, request);
|
|
94
|
+
try {
|
|
95
|
+
const definitions = extractWebSearchToolDefinitions(request?.params?.tools);
|
|
96
|
+
if (definitions.length) {
|
|
97
|
+
span.setAttribute(TOOL_DEFINITIONS_ATTR, JSON.stringify(definitions));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// Never break span creation over an enrichment failure.
|
|
102
|
+
}
|
|
103
|
+
return span;
|
|
104
|
+
};
|
|
105
|
+
this._patched.push([instrumentation, 'startSpan', startSpanOriginal]);
|
|
106
|
+
}
|
|
107
|
+
// Response side: the accumulated result, before the output message is
|
|
108
|
+
// formatted from it.
|
|
109
|
+
const endSpanOriginal = instrumentation._endSpan;
|
|
110
|
+
if (typeof endSpanOriginal === 'function') {
|
|
111
|
+
instrumentation._endSpan = function endSpanWithWebSearch(args) {
|
|
112
|
+
try {
|
|
113
|
+
stampAndStripSearchBlocks(args && args.span, args && args.result);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// Never break span finalization over an enrichment failure.
|
|
117
|
+
}
|
|
118
|
+
return endSpanOriginal.call(this, args);
|
|
119
|
+
};
|
|
120
|
+
this._patched.push([instrumentation, '_endSpan', endSpanOriginal]);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
uninstrument() {
|
|
124
|
+
// Restore newest first, so a double instrument() unwinds back to the true
|
|
125
|
+
// original instead of reinstalling the first wrapper.
|
|
126
|
+
for (const [owner, methodName, original] of [...this._patched].reverse()) {
|
|
127
|
+
owner[methodName] = original;
|
|
128
|
+
}
|
|
129
|
+
this._patched = [];
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
exports.AnthropicWebSearchInstrumentor = AnthropicWebSearchInstrumentor;
|
|
133
|
+
/** Stamp the call's searches and the count it is billed for, then take the search
|
|
134
|
+
* blocks out of the result so the instrumentor's own output message does not
|
|
135
|
+
* carry them a second time. */
|
|
136
|
+
function stampAndStripSearchBlocks(span, result) {
|
|
137
|
+
if (!span || !span.isRecording || !span.isRecording() || !result)
|
|
138
|
+
return;
|
|
139
|
+
const requests = result.usage?.server_tool_use?.web_search_requests;
|
|
140
|
+
if (requests)
|
|
141
|
+
span.setAttribute(REQUESTS_ATTR, requests);
|
|
142
|
+
const blocks = extractWebSearchOutputBlocks(result.content);
|
|
143
|
+
if (!blocks.length)
|
|
144
|
+
return;
|
|
145
|
+
span.setAttribute(OUTPUT_BLOCKS_ATTR, JSON.stringify(blocks));
|
|
146
|
+
result.content = result.content.filter((block) => !isWebSearchBlock(block));
|
|
147
|
+
}
|
|
@@ -4,8 +4,11 @@
|
|
|
4
4
|
* Wires the weflayr-supplied patches the traceloop Anthropic instrumentor
|
|
5
5
|
* misses: cached-prompt token counts on the chat span (it reads them off the
|
|
6
6
|
* response but writes no `gen_ai.usage.cache_*` attribute), the request's tool
|
|
7
|
-
* definitions and structured-output schema,
|
|
8
|
-
* tool-call arguments (its stream accumulator drops both)
|
|
7
|
+
* definitions and structured-output schema, the streamed stop reason and
|
|
8
|
+
* tool-call arguments (its stream accumulator drops both), and the provider-run
|
|
9
|
+
* web search (the tool's type, the queries the answer ran and the searches
|
|
10
|
+
* Anthropic bills for), and the billing of the calls `AnthropicVertex` makes
|
|
11
|
+
* to Claude on Vertex AI, which it attributes to Anthropic.
|
|
9
12
|
*/
|
|
10
13
|
export declare class AnthropicTelemetryInstrumentor {
|
|
11
14
|
private _subInstrumentors;
|
|
@@ -5,8 +5,11 @@
|
|
|
5
5
|
* Wires the weflayr-supplied patches the traceloop Anthropic instrumentor
|
|
6
6
|
* misses: cached-prompt token counts on the chat span (it reads them off the
|
|
7
7
|
* response but writes no `gen_ai.usage.cache_*` attribute), the request's tool
|
|
8
|
-
* definitions and structured-output schema,
|
|
9
|
-
* tool-call arguments (its stream accumulator drops both)
|
|
8
|
+
* definitions and structured-output schema, the streamed stop reason and
|
|
9
|
+
* tool-call arguments (its stream accumulator drops both), and the provider-run
|
|
10
|
+
* web search (the tool's type, the queries the answer ran and the searches
|
|
11
|
+
* Anthropic bills for), and the billing of the calls `AnthropicVertex` makes
|
|
12
|
+
* to Claude on Vertex AI, which it attributes to Anthropic.
|
|
10
13
|
*/
|
|
11
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
15
|
exports.AnthropicTelemetryInstrumentor = void 0;
|
|
@@ -15,16 +18,25 @@ const get_cache_config_telemetry_1 = require("./get_cache_config_telemetry");
|
|
|
15
18
|
const get_cache_and_reasoning_telemetry_1 = require("./get_cache_and_reasoning_telemetry");
|
|
16
19
|
const get_streaming_accumulation_telemetry_1 = require("./get_streaming_accumulation_telemetry");
|
|
17
20
|
const get_tool_definitions_telemetry_1 = require("./get_tool_definitions_telemetry");
|
|
21
|
+
const get_vertex_billing_telemetry_1 = require("./get_vertex_billing_telemetry");
|
|
22
|
+
const get_web_search_telemetry_1 = require("./get_web_search_telemetry");
|
|
18
23
|
const get_structured_output_schema_telemetry_2 = require("./get_structured_output_schema_telemetry");
|
|
19
24
|
class AnthropicTelemetryInstrumentor {
|
|
20
25
|
_subInstrumentors;
|
|
21
26
|
constructor() {
|
|
27
|
+
// Order matters between the last two of these three: each wraps `_endSpan`
|
|
28
|
+
// and does its own work BEFORE delegating, so the one registered LAST runs
|
|
29
|
+
// FIRST. The web-search complement reads the streamed `server_tool_use`
|
|
30
|
+
// block's query, which the streamed-accumulation one fills in, so
|
|
31
|
+
// accumulation has to be registered after it to run before it.
|
|
22
32
|
this._subInstrumentors = [
|
|
23
33
|
new get_cache_and_reasoning_telemetry_1.AnthropicPromptCachingInstrumentor(),
|
|
24
34
|
new get_cache_config_telemetry_1.AnthropicCacheConfigInstrumentor(),
|
|
25
|
-
new get_streaming_accumulation_telemetry_1.AnthropicStreamingAccumulationInstrumentor(),
|
|
26
35
|
new get_tool_definitions_telemetry_1.AnthropicToolDefinitionsInstrumentor(),
|
|
36
|
+
new get_web_search_telemetry_1.AnthropicWebSearchInstrumentor(),
|
|
37
|
+
new get_streaming_accumulation_telemetry_1.AnthropicStreamingAccumulationInstrumentor(),
|
|
27
38
|
new get_structured_output_schema_telemetry_1.TraceloopStructuredOutputSchemaInstrumentor(get_structured_output_schema_telemetry_2.readStructuredOutputSchema),
|
|
39
|
+
new get_vertex_billing_telemetry_1.AnthropicVertexBillingInstrumentor(),
|
|
28
40
|
];
|
|
29
41
|
}
|
|
30
42
|
instrument(instrumentation) {
|
|
@@ -32,7 +44,8 @@ class AnthropicTelemetryInstrumentor {
|
|
|
32
44
|
sub.instrument(instrumentation);
|
|
33
45
|
}
|
|
34
46
|
uninstrument() {
|
|
35
|
-
|
|
47
|
+
// Newest first: several of them patch the same function.
|
|
48
|
+
for (const sub of [...this._subInstrumentors].reverse())
|
|
36
49
|
sub.uninstrument();
|
|
37
50
|
}
|
|
38
51
|
}
|