diff --git a/.size-limit.js b/.size-limit.js index f70e9927fb13..b775eaadb04f 100644 --- a/.size-limit.js +++ b/.size-limit.js @@ -452,7 +452,7 @@ module.exports = [ ignore: [...builtinModules, ...nodePrefixedBuiltinModules], gzip: false, brotli: false, - limit: '540 KiB', + limit: '541 KiB', disablePlugins: ['@size-limit/webpack'], webpack: false, modifyEsbuildConfig: function (config) { diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/index.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/index.ts index 60755738eccb..619fe9a58cfb 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/workers-ai/index.ts @@ -1,5 +1,4 @@ import * as Sentry from '@sentry/cloudflare'; -import { instrumentWorkersAiClient } from '@sentry/core'; import { MockAi } from './mocks'; interface Env { @@ -24,7 +23,7 @@ export default Sentry.withSentry( // Wrapped in-request, mirroring how `@sentry/cloudflare` instruments `env.AI` on first // property access: after `withSentry` has initialized the SDK, so `dataCollection.genAI` // is visible when recording options are resolved. - const ai = instrumentWorkersAiClient(aiBinding); + const ai = Sentry.instrumentWorkersAiClient(aiBinding); const url = new URL(request.url); diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-agent/worker/index.ts b/dev-packages/e2e-tests/test-applications/cloudflare-agent/worker/index.ts index 46ac9c5d909a..25aeaf628964 100644 --- a/dev-packages/e2e-tests/test-applications/cloudflare-agent/worker/index.ts +++ b/dev-packages/e2e-tests/test-applications/cloudflare-agent/worker/index.ts @@ -1,5 +1,4 @@ import * as Sentry from '@sentry/cloudflare'; -import { instrumentWorkersAiClient } from '@sentry/core'; import { AIChatAgent } from '@cloudflare/ai-chat'; import { Agent, callable, routeAgentRequest } from 'agents'; import { streamText } from 'ai'; @@ -23,7 +22,7 @@ const sentryOptions = (env: Env) => ({ * Vercel AI SDK + `workers-ai-provider` stack (the OpenAI-compatible SSE shape). */ function streamWorkersAi(): Response { - const ai = instrumentWorkersAiClient(new MockAi(), { recordInputs: true, recordOutputs: true }); + const ai = Sentry.instrumentWorkersAiClient(new MockAi(), { recordInputs: true, recordOutputs: true }); const workersai = createWorkersAI({ binding: ai as unknown as Ai }); const result = streamText({ diff --git a/packages/cloudflare/src/index.ts b/packages/cloudflare/src/index.ts index 568e39debcb1..bc27ec6e5d59 100644 --- a/packages/cloudflare/src/index.ts +++ b/packages/cloudflare/src/index.ts @@ -130,6 +130,7 @@ export { instrumentOpenAiClient, instrumentAnthropicAiClient, instrumentGoogleGenAIClient, + instrumentWorkersAiClient, } from '@sentry/server-utils'; // eslint-disable-next-line typescript/no-deprecated diff --git a/packages/cloudflare/src/instrumentations/worker/instrumentEnv.ts b/packages/cloudflare/src/instrumentations/worker/instrumentEnv.ts index 474fbf831b86..5a0dff749419 100644 --- a/packages/cloudflare/src/instrumentations/worker/instrumentEnv.ts +++ b/packages/cloudflare/src/instrumentations/worker/instrumentEnv.ts @@ -1,5 +1,5 @@ import { isObjectLike } from '@sentry/core'; -import { instrumentWorkersAiClient } from '@sentry/core'; +import { instrumentWorkersAiClient } from '@sentry/server-utils'; import type { CloudflareOptions } from '../../client'; import { isAiBinding, diff --git a/packages/core/src/server-exports.ts b/packages/core/src/server-exports.ts index 195cb9777669..79ec35d49969 100644 --- a/packages/core/src/server-exports.ts +++ b/packages/core/src/server-exports.ts @@ -74,5 +74,3 @@ export { export { wrapToolsWithSpans, extractLLMFromParams, extractAgentNameFromParams } from './tracing/langgraph/utils'; export { LANGGRAPH_INTEGRATION_NAME } from './tracing/langgraph/constants'; export type { LangGraphOptions, LangGraphIntegration, CompiledGraph } from './tracing/langgraph/types'; -export { instrumentWorkersAiClient } from './tracing/workers-ai'; -export type { WorkersAiClient, WorkersAiOptions } from './tracing/workers-ai/types'; diff --git a/packages/core/src/tracing/vercel-ai/index.ts b/packages/core/src/tracing/vercel-ai/index.ts index 458077e40ccd..3ae0a7386f06 100644 --- a/packages/core/src/tracing/vercel-ai/index.ts +++ b/packages/core/src/tracing/vercel-ai/index.ts @@ -8,7 +8,6 @@ import type { Event } from '../../types/event'; import type { Span, SpanAttributes, SpanAttributeValue, SpanJSON, StreamedSpanJSON } from '../../types/span'; import { _INTERNAL_skipAiProviderWrapping } from '../../utils/ai/providerSkip'; import { spanToJSON } from '../../utils/spanUtils'; -import { WORKERS_AI_INTEGRATION_NAME } from '../workers-ai/constants'; import { GEN_AI_CONVERSATION_ID, GEN_AI_EMBEDDINGS_INPUT, @@ -65,6 +64,8 @@ import { OPERATION_NAME_ATTRIBUTE, } from './vercel-ai-attributes'; +const WORKERS_AI_INTEGRATION_NAME = 'WorkersAI'; + /** * Post-process spans emitted by the Vercel AI SDK. * This is supposed to be used in `client.on('spanStart', ...) diff --git a/packages/server-utils/src/ai/index.ts b/packages/server-utils/src/ai/index.ts index 15618cf73702..9d1da2c0a107 100644 --- a/packages/server-utils/src/ai/index.ts +++ b/packages/server-utils/src/ai/index.ts @@ -7,3 +7,4 @@ export { instrumentOpenAiClient } from './openai'; export { instrumentAnthropicAiClient } from './anthropic-ai'; export { instrumentGoogleGenAIClient } from './google-genai'; +export { instrumentWorkersAiClient } from './workers-ai'; diff --git a/packages/core/src/tracing/workers-ai/constants.ts b/packages/server-utils/src/ai/workers-ai/constants.ts similarity index 100% rename from packages/core/src/tracing/workers-ai/constants.ts rename to packages/server-utils/src/ai/workers-ai/constants.ts diff --git a/packages/core/src/tracing/workers-ai/index.ts b/packages/server-utils/src/ai/workers-ai/index.ts similarity index 94% rename from packages/core/src/tracing/workers-ai/index.ts rename to packages/server-utils/src/ai/workers-ai/index.ts index 9232b52bd5f1..8e003a522f27 100644 --- a/packages/core/src/tracing/workers-ai/index.ts +++ b/packages/server-utils/src/ai/workers-ai/index.ts @@ -1,9 +1,12 @@ -import { SPAN_STATUS_ERROR } from '../../tracing'; -import { startSpan, startSpanManual } from '../../tracing/trace'; -import type { Span } from '../../types/span'; -import { _INTERNAL_shouldSkipAiProviderWrapping } from '../../utils/ai/providerSkip'; -import { isObjectLike } from '../../utils/is'; -import { resolveAIRecordingOptions, shouldEnableTruncation } from '../ai/utils'; +import { + _INTERNAL_shouldSkipAiProviderWrapping, + isObjectLike, + SPAN_STATUS_ERROR, + startSpan, + startSpanManual, +} from '@sentry/core'; +import type { Span } from '@sentry/core'; +import { resolveAIRecordingOptions, shouldEnableTruncation } from '../core/utils'; import { WORKERS_AI_INTEGRATION_NAME } from './constants'; import { instrumentWorkersAiStream } from './streaming'; import type { WorkersAiOptions } from './types'; diff --git a/packages/core/src/tracing/workers-ai/streaming.ts b/packages/server-utils/src/ai/workers-ai/streaming.ts similarity index 97% rename from packages/core/src/tracing/workers-ai/streaming.ts rename to packages/server-utils/src/ai/workers-ai/streaming.ts index 5a36d5eff2dc..37aefd9a6046 100644 --- a/packages/core/src/tracing/workers-ai/streaming.ts +++ b/packages/server-utils/src/ai/workers-ai/streaming.ts @@ -1,6 +1,6 @@ -import { SPAN_STATUS_ERROR } from '../../tracing'; -import type { Span } from '../../types/span'; -import { endStreamSpan, type StreamResponseState } from '../ai/utils'; +import { SPAN_STATUS_ERROR } from '@sentry/core'; +import type { Span } from '@sentry/core'; +import { endStreamSpan, type StreamResponseState } from '../core/utils'; import type { WorkersAiUsage } from './types'; import { setOutputMessagesAttribute } from './utils'; diff --git a/packages/core/src/tracing/workers-ai/types.ts b/packages/server-utils/src/ai/workers-ai/types.ts similarity index 96% rename from packages/core/src/tracing/workers-ai/types.ts rename to packages/server-utils/src/ai/workers-ai/types.ts index 33334a6ed1bf..31a931604871 100644 --- a/packages/core/src/tracing/workers-ai/types.ts +++ b/packages/server-utils/src/ai/workers-ai/types.ts @@ -1,4 +1,4 @@ -import type { AIRecordingOptions } from '../ai/utils'; +import type { AIRecordingOptions } from '../core/utils'; export interface WorkersAiOptions extends AIRecordingOptions { /** diff --git a/packages/core/src/tracing/workers-ai/utils.ts b/packages/server-utils/src/ai/workers-ai/utils.ts similarity index 95% rename from packages/core/src/tracing/workers-ai/utils.ts rename to packages/server-utils/src/ai/workers-ai/utils.ts index 8caea5e6c0bc..6c1407389fd8 100644 --- a/packages/core/src/tracing/workers-ai/utils.ts +++ b/packages/server-utils/src/ai/workers-ai/utils.ts @@ -16,11 +16,11 @@ import { GEN_AI_RESPONSE_TOOL_CALLS, GEN_AI_SYSTEM_INSTRUCTIONS, } from '@sentry/conventions/attributes'; -import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../semanticAttributes'; -import type { Span, SpanAttributeValue } from '../../types/span'; -import { GEN_AI_REQUEST_STREAM_ATTRIBUTE } from '../ai/gen-ai-attributes'; -import { extractSystemInstructions, getTruncatedJsonString, setTokenUsageAttributes } from '../ai/utils'; -import { stringify } from '../../utils/string'; +import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core'; +import type { Span, SpanAttributeValue } from '@sentry/core'; +import { GEN_AI_REQUEST_STREAM_ATTRIBUTE } from '../core/gen-ai-attributes'; +import { extractSystemInstructions, getTruncatedJsonString, setTokenUsageAttributes } from '../core/utils'; +import { stringify } from '@sentry/core'; import { WORKERS_AI_ORIGIN, WORKERS_AI_PROVIDER_NAME } from './constants'; import type { WorkersAiInput, WorkersAiOutput } from './types'; diff --git a/packages/core/test/lib/tracing/workers-ai-streaming.test.ts b/packages/server-utils/test/ai/lib/tracing/workers-ai-streaming.test.ts similarity index 98% rename from packages/core/test/lib/tracing/workers-ai-streaming.test.ts rename to packages/server-utils/test/ai/lib/tracing/workers-ai-streaming.test.ts index 2b46f77eedc9..433a0774cd20 100644 --- a/packages/core/test/lib/tracing/workers-ai-streaming.test.ts +++ b/packages/server-utils/test/ai/lib/tracing/workers-ai-streaming.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import type { Span } from '../../../src'; +import type { Span } from '@sentry/core'; import { GEN_AI_OUTPUT_MESSAGES, GEN_AI_RESPONSE_STREAMING, @@ -9,7 +9,7 @@ import { GEN_AI_USAGE_OUTPUT_TOKENS, GEN_AI_USAGE_TOTAL_TOKENS, } from '@sentry/conventions/attributes'; -import { instrumentWorkersAiStream } from '../../../src/tracing/workers-ai/streaming'; +import { instrumentWorkersAiStream } from '../../../../src/ai/workers-ai/streaming'; function createMockSpan(): { span: Span; attributes: Record; ended: () => boolean } { const attributes: Record = {}; diff --git a/packages/core/test/lib/tracing/workers-ai.test.ts b/packages/server-utils/test/ai/lib/tracing/workers-ai.test.ts similarity index 91% rename from packages/core/test/lib/tracing/workers-ai.test.ts rename to packages/server-utils/test/ai/lib/tracing/workers-ai.test.ts index e0fefb2ac2b4..5dfef69d8bdf 100644 --- a/packages/core/test/lib/tracing/workers-ai.test.ts +++ b/packages/server-utils/test/ai/lib/tracing/workers-ai.test.ts @@ -8,25 +8,46 @@ import { GEN_AI_SYSTEM_INSTRUCTIONS, } from '@sentry/conventions/attributes'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import type { Span } from '../../../src'; import { + _INTERNAL_clearAiProviderSkips, + addVercelAiProcessors, + Client, + createTransport, getCurrentScope, getGlobalScope, getIsolationScope, + resolvedSyncPromise, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, setCurrentClient, + spanToJSON, startSpan, -} from '../../../src'; -import { addVercelAiProcessors } from '../../../src/tracing/vercel-ai'; -import { AI_OPERATION_ID_ATTRIBUTE } from '../../../src/tracing/vercel-ai/vercel-ai-attributes'; -import { instrumentWorkersAiClient } from '../../../src/tracing/workers-ai'; -import type { DataCollection } from '../../../src/types/datacollection'; -import { _INTERNAL_clearAiProviderSkips } from '../../../src/utils/ai/providerSkip'; -import { spanToJSON } from '../../../src/utils/spanUtils'; -import { getDefaultTestClientOptions, TestClient } from '../../mocks/client'; +} from '@sentry/core'; +import type { ClientOptions, DataCollection, Span } from '@sentry/core'; +import { instrumentWorkersAiClient } from '../../../../src/ai/workers-ai'; + +const AI_OPERATION_ID_ATTRIBUTE = 'ai.operationId'; + +function getDefaultTestClientOptions(options: Partial = {}): ClientOptions { + return { + integrations: [], + transport: () => createTransport({ recordDroppedEvent: () => undefined }, () => resolvedSyncPromise({})), + stackParser: () => [], + ...options, + } as ClientOptions; +} + +class TestClient extends Client { + public eventFromException(): PromiseLike { + return resolvedSyncPromise({}); + } + + public eventFromMessage(): PromiseLike { + return resolvedSyncPromise({}); + } +} const MODEL = '@cf/meta/llama-3.1-8b-instruct'; diff --git a/packages/core/test/lib/utils/workers-ai-utils.test.ts b/packages/server-utils/test/ai/lib/utils/workers-ai-utils.test.ts similarity index 97% rename from packages/core/test/lib/utils/workers-ai-utils.test.ts rename to packages/server-utils/test/ai/lib/utils/workers-ai-utils.test.ts index 24304c3f23dc..a104600bea54 100644 --- a/packages/core/test/lib/utils/workers-ai-utils.test.ts +++ b/packages/server-utils/test/ai/lib/utils/workers-ai-utils.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../../src'; -import type { Span } from '../../../src'; +import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core'; +import type { Span } from '@sentry/core'; import { GEN_AI_PROVIDER_NAME, GEN_AI_EMBEDDINGS_INPUT, @@ -21,14 +21,14 @@ import { GEN_AI_USAGE_OUTPUT_TOKENS, GEN_AI_USAGE_TOTAL_TOKENS, } from '@sentry/conventions/attributes'; -import { GEN_AI_REQUEST_STREAM_ATTRIBUTE } from '../../../src/tracing/ai/gen-ai-attributes'; -import { WORKERS_AI_ORIGIN, WORKERS_AI_PROVIDER_NAME } from '../../../src/tracing/workers-ai/constants'; +import { GEN_AI_REQUEST_STREAM_ATTRIBUTE } from '../../../../src/ai/core/gen-ai-attributes'; +import { WORKERS_AI_ORIGIN, WORKERS_AI_PROVIDER_NAME } from '../../../../src/ai/workers-ai/constants'; import { addRequestAttributes, addResponseAttributes, extractRequestAttributes, getOperationName, -} from '../../../src/tracing/workers-ai/utils'; +} from '../../../../src/ai/workers-ai/utils'; const MODEL = '@cf/meta/llama-3.1-8b-instruct';