@@ -17,6 +17,9 @@ import {
1717 SENTRY_SEGMENT_NAME ,
1818 SENTRY_TRACE_LIFECYCLE ,
1919 SENTRY_ENVIRONMENT ,
20+ SENTRY_IS_LOCALHOST ,
21+ SENTRY_OP ,
22+ SENTRY_ORIGIN ,
2023} from '@sentry/conventions/attributes' ;
2124import { SDK_VERSION } from '@sentry/core' ;
2225import { expect , it } from 'vitest' ;
@@ -45,8 +48,8 @@ it('traces a basic Workers AI text generation request', async ({ signal }) => {
4548 status : 'ok' ,
4649 is_segment : false ,
4750 attributes : {
48- 'sentry.origin' : { value : 'auto.ai.cloudflare.workers_ai' , type : 'string' } ,
49- 'sentry.op' : { value : 'gen_ai.chat' , type : 'string' } ,
51+ [ SENTRY_ORIGIN ] : { value : 'auto.ai.cloudflare.workers_ai' , type : 'string' } ,
52+ [ SENTRY_OP ] : { value : 'gen_ai.chat' , type : 'string' } ,
5053 [ GEN_AI_PROVIDER_NAME ] : { value : 'cloudflare.workers_ai' , type : 'string' } ,
5154 [ GEN_AI_OPERATION_NAME ] : { value : 'chat' , type : 'string' } ,
5255 [ GEN_AI_REQUEST_MODEL ] : { value : '@cf/meta/llama-3.1-8b-instruct' , type : 'string' } ,
@@ -64,7 +67,7 @@ it('traces a basic Workers AI text generation request', async ({ signal }) => {
6467 type : 'string' ,
6568 value : 'The capital of France is Paris.' ,
6669 } ,
67- 'sentry.is_localhost' : { value : true , type : 'boolean' } ,
70+ [ SENTRY_IS_LOCALHOST ] : { value : true , type : 'boolean' } ,
6871 [ SENTRY_TRACE_LIFECYCLE ] : { value : 'stream' , type : 'string' } ,
6972 [ SENTRY_SEGMENT_NAME ] : { value : segmentSpan ! . name , type : 'string' } ,
7073 [ SENTRY_SEGMENT_ID ] : { value : segmentSpan ! . span_id , type : 'string' } ,
@@ -99,8 +102,8 @@ it('traces a streaming Workers AI text generation request', async ({ signal }) =
99102 status : 'ok' ,
100103 is_segment : false ,
101104 attributes : {
102- 'sentry.origin' : { value : 'auto.ai.cloudflare.workers_ai' , type : 'string' } ,
103- 'sentry.op' : { value : 'gen_ai.chat' , type : 'string' } ,
105+ [ SENTRY_ORIGIN ] : { value : 'auto.ai.cloudflare.workers_ai' , type : 'string' } ,
106+ [ SENTRY_OP ] : { value : 'gen_ai.chat' , type : 'string' } ,
104107 [ GEN_AI_PROVIDER_NAME ] : { value : 'cloudflare.workers_ai' , type : 'string' } ,
105108 [ GEN_AI_OPERATION_NAME ] : { value : 'chat' , type : 'string' } ,
106109 [ GEN_AI_REQUEST_MODEL ] : { value : '@cf/meta/llama-3.1-8b-instruct' , type : 'string' } ,
@@ -118,7 +121,7 @@ it('traces a streaming Workers AI text generation request', async ({ signal }) =
118121 type : 'string' ,
119122 value : 'The capital of France is Paris.' ,
120123 } ,
121- 'sentry.is_localhost' : { value : true , type : 'boolean' } ,
124+ [ SENTRY_IS_LOCALHOST ] : { value : true , type : 'boolean' } ,
122125 [ SENTRY_TRACE_LIFECYCLE ] : { value : 'stream' , type : 'string' } ,
123126 [ SENTRY_SEGMENT_NAME ] : { value : segmentSpan ! . name , type : 'string' } ,
124127 [ SENTRY_SEGMENT_ID ] : { value : segmentSpan ! . span_id , type : 'string' } ,
@@ -150,8 +153,8 @@ it('traces a TypeSafe Jev evaluation like the TypeSafe integration', async ({ si
150153 status : 'ok' ,
151154 is_segment : false ,
152155 attributes : {
153- 'sentry.origin' : { value : 'auto.ai.cloudflare.workers_ai' , type : 'string' } ,
154- 'sentry.op' : { value : 'gen_ai.evaluate' , type : 'string' } ,
156+ [ SENTRY_ORIGIN ] : { value : 'auto.ai.cloudflare.workers_ai' , type : 'string' } ,
157+ [ SENTRY_OP ] : { value : 'gen_ai.evaluate' , type : 'string' } ,
155158 [ GEN_AI_PROVIDER_NAME ] : { value : 'cloudflare.workers_ai' , type : 'string' } ,
156159 [ GEN_AI_OPERATION_NAME ] : { value : 'evaluate' , type : 'string' } ,
157160 [ GEN_AI_REQUEST_MODEL ] : { value : 'typesafe/jev' , type : 'string' } ,
@@ -164,7 +167,7 @@ it('traces a TypeSafe Jev evaluation like the TypeSafe integration', async ({ si
164167 type : 'string' ,
165168 value : '[{"type":"evaluation","answers":{"is_urgent":{"type":"noul","noul":0.97}}}]' ,
166169 } ,
167- 'sentry.is_localhost' : { value : true , type : 'boolean' } ,
170+ [ SENTRY_IS_LOCALHOST ] : { value : true , type : 'boolean' } ,
168171 [ SENTRY_TRACE_LIFECYCLE ] : { value : 'stream' , type : 'string' } ,
169172 [ SENTRY_SEGMENT_NAME ] : { value : segmentSpan ! . name , type : 'string' } ,
170173 [ SENTRY_SEGMENT_ID ] : { value : segmentSpan ! . span_id , type : 'string' } ,
@@ -180,6 +183,52 @@ it('traces a TypeSafe Jev evaluation like the TypeSafe integration', async ({ si
180183 await runner . completed ( ) ;
181184} ) ;
182185
186+ it ( 'traces a Clef evaluation like a TypeSafe Jev evaluation' , async ( { signal } ) => {
187+ const runner = createRunner ( __dirname )
188+ . ignore ( 'event' )
189+ . expect ( envelope => {
190+ const spans = getSpansFromEnvelope ( envelope ) ;
191+ const segmentSpan = spans . find ( span => span . is_segment ) ;
192+
193+ const genAiSpans = spans . filter ( span => getSpanOp ( span ) ?. startsWith ( 'gen_ai.' ) ) ;
194+ expect ( genAiSpans ) . toHaveLength ( 1 ) ;
195+
196+ expect ( genAiSpans [ 0 ] ) . toEqual (
197+ expect . objectContaining ( {
198+ name : 'evaluate @cf/cloudflare/clef' ,
199+ status : 'ok' ,
200+ is_segment : false ,
201+ attributes : {
202+ [ SENTRY_ORIGIN ] : { value : 'auto.ai.cloudflare.workers_ai' , type : 'string' } ,
203+ [ SENTRY_OP ] : { value : 'gen_ai.evaluate' , type : 'string' } ,
204+ [ GEN_AI_PROVIDER_NAME ] : { value : 'cloudflare.workers_ai' , type : 'string' } ,
205+ [ GEN_AI_OPERATION_NAME ] : { value : 'evaluate' , type : 'string' } ,
206+ [ GEN_AI_REQUEST_MODEL ] : { value : '@cf/cloudflare/clef' , type : 'string' } ,
207+ [ GEN_AI_RESPONSE_MODEL ] : { value : 'clef' , type : 'string' } ,
208+ [ GEN_AI_USAGE_INPUT_TOKENS ] : { value : 412 , type : 'integer' } ,
209+ [ GEN_AI_USAGE_OUTPUT_TOKENS ] : { value : 1 , type : 'integer' } ,
210+ [ GEN_AI_USAGE_TOTAL_TOKENS ] : { value : 413 , type : 'integer' } ,
211+ // collect only output messages
212+ [ GEN_AI_OUTPUT_MESSAGES ] : {
213+ type : 'string' ,
214+ value : '[{"type":"evaluation","answers":{"urgent":{"type":"noul","noul":0.98}}}]' ,
215+ } ,
216+ [ SENTRY_IS_LOCALHOST ] : { value : true , type : 'boolean' } ,
217+ [ SENTRY_TRACE_LIFECYCLE ] : { value : 'stream' , type : 'string' } ,
218+ [ SENTRY_SEGMENT_NAME ] : { value : segmentSpan ! . name , type : 'string' } ,
219+ [ SENTRY_SEGMENT_ID ] : { value : segmentSpan ! . span_id , type : 'string' } ,
220+ [ SENTRY_SDK_NAME ] : { value : 'sentry.javascript.cloudflare' , type : 'string' } ,
221+ [ SENTRY_SDK_VERSION ] : { value : SDK_VERSION , type : 'string' } ,
222+ [ SENTRY_ENVIRONMENT ] : { value : 'production' , type : 'string' } ,
223+ } ,
224+ } ) ,
225+ ) ;
226+ } )
227+ . start ( signal ) ;
228+ await runner . makeRequest ( 'get' , '/evaluate-clef' ) ;
229+ await runner . completed ( ) ;
230+ } ) ;
231+
183232// The Workers AI integration deliberately does not call `captureException` itself.
184233// When a `run` call fails, the error must bubble up out of the fetch handler and be
185234// reported by the top-level Cloudflare instrumentation instead — so it shows up in
0 commit comments