@@ -8,6 +8,9 @@ const sinon = require('sinon')
88const agent = require ( '../plugins/agent' )
99const NoopAIGuard = require ( '../../src/aiguard/noop' )
1010const AIGuard = require ( '../../src/aiguard/sdk' )
11+ const tracerVersion = require ( '../../../../package.json' ) . version
12+ const telemetryMetrics = require ( '../../src/telemetry/metrics' )
13+ const appsecNamespace = telemetryMetrics . manager . namespace ( 'appsec' )
1114
1215describe ( 'AIGuard SDK' , ( ) => {
1316 const config = {
@@ -29,6 +32,7 @@ describe('AIGuard SDK', () => {
2932 }
3033 let tracer
3134 let aiguard
35+ let count , inc
3236
3337 const toolCall = [
3438 { role : 'system' , content : 'You are a beautiful AI assistant' } ,
@@ -67,21 +71,32 @@ describe('AIGuard SDK', () => {
6771 originalFetch = global . fetch
6872 global . fetch = sinon . stub ( )
6973
74+ inc = sinon . spy ( )
75+ count = sinon . stub ( appsecNamespace , 'count' ) . returns ( {
76+ inc
77+ } )
78+ appsecNamespace . metrics . clear ( )
79+
7080 aiguard = new AIGuard ( tracer , config )
7181
7282 return agent . load ( null , [ ] )
7383 } )
7484
7585 afterEach ( ( ) => {
7686 global . fetch = originalFetch
87+ sinon . restore ( )
7788 agent . close ( )
7889 } )
7990
8091 const mockFetch = ( options ) => {
81- global . fetch . resolves ( {
82- status : options . status ?? 200 ,
83- json : sinon . stub ( ) . resolves ( options . body )
84- } )
92+ if ( options . error ) {
93+ global . fetch . rejects ( options . error )
94+ } else {
95+ global . fetch . resolves ( {
96+ status : options . status ?? 200 ,
97+ json : sinon . stub ( ) . resolves ( options . body )
98+ } )
99+ }
85100 }
86101
87102 const assertFetch = ( messages , url ) => {
@@ -96,7 +111,10 @@ describe('AIGuard SDK', () => {
96111 'Content-Type' : 'application/json' ,
97112 'Content-Length' : Buffer . byteLength ( postData ) ,
98113 'DD-API-KEY' : config . apiKey ,
99- 'DD-APPLICATION-KEY' : config . appKey
114+ 'DD-APPLICATION-KEY' : config . appKey ,
115+ 'DD-AI-GUARD-VERSION' : tracerVersion ,
116+ 'DD-AI-GUARD-SOURCE' : 'SDK' ,
117+ 'DD-AI-GUARD-LANGUAGE' : 'nodejs'
100118 } ,
101119 body : postData ,
102120 signal : sinon . match . instanceOf ( AbortSignal )
@@ -115,6 +133,10 @@ describe('AIGuard SDK', () => {
115133 } , { rejectFirst : true } )
116134 }
117135
136+ const assertTelemetry = ( metric , tags ) => {
137+ sinon . assert . calledWith ( count , metric , tags )
138+ }
139+
118140 const testSuite = [
119141 { action : 'ALLOW' , reason : 'Go ahead' } ,
120142 { action : 'DENY' , reason : 'Nope' } ,
@@ -144,6 +166,7 @@ describe('AIGuard SDK', () => {
144166 expect ( evaluation . reason ) . to . equal ( reason )
145167 }
146168
169+ assertTelemetry ( 'ai_guard.requests' , { error : false , action, block : shouldBlock } )
147170 assertFetch ( messages )
148171 await assertAIGuardSpan ( {
149172 'ai_guard.target' : target ,
@@ -169,6 +192,26 @@ describe('AIGuard SDK', () => {
169192 err . name === 'AIGuardClientError' && JSON . stringify ( err . errors ) === JSON . stringify ( errors )
170193 )
171194
195+ assertTelemetry ( 'ai_guard.requests' , { error : true } )
196+ assertFetch ( toolCall )
197+ await assertAIGuardSpan ( {
198+ 'ai_guard.target' : 'tool' ,
199+ 'error.type' : 'AIGuardClientError'
200+ } )
201+ } )
202+
203+ it ( 'test evaluate with API exception' , async ( ) => {
204+ mockFetch ( {
205+ error : new Error ( 'Boom!!!' ) ,
206+ } )
207+
208+ await rejects (
209+ ( ) => aiguard . evaluate ( toolCall ) ,
210+ err =>
211+ err . name === 'AIGuardClientError' && err . message === 'Unexpected error calling AI Guard service: Boom!!!' ,
212+ )
213+
214+ assertTelemetry ( 'ai_guard.requests' , { error : true } )
172215 assertFetch ( toolCall )
173216 await assertAIGuardSpan ( {
174217 'ai_guard.target' : 'tool' ,
@@ -184,6 +227,7 @@ describe('AIGuard SDK', () => {
184227 err => err . name === 'AIGuardClientError'
185228 )
186229
230+ assertTelemetry ( 'ai_guard.requests' , { error : true } )
187231 assertFetch ( toolCall )
188232 await assertAIGuardSpan ( {
189233 'ai_guard.target' : 'tool' ,
@@ -199,6 +243,7 @@ describe('AIGuard SDK', () => {
199243 err => err . name === 'AIGuardClientError'
200244 )
201245
246+ assertTelemetry ( 'ai_guard.requests' , { error : true } )
202247 assertFetch ( toolCall )
203248 await assertAIGuardSpan ( {
204249 'ai_guard.target' : 'tool' ,
@@ -225,6 +270,7 @@ describe('AIGuard SDK', () => {
225270
226271 await aiguard . evaluate ( messages )
227272
273+ assertTelemetry ( 'ai_guard.truncated' , { type : 'messages' } )
228274 assertFetch ( messages )
229275 await assertAIGuardSpan (
230276 { 'ai_guard.target' : 'prompt' , 'ai_guard.action' : 'ALLOW' } ,
@@ -242,6 +288,7 @@ describe('AIGuard SDK', () => {
242288
243289 await aiguard . evaluate ( messages )
244290
291+ assertTelemetry ( 'ai_guard.truncated' , { type : 'content' } )
245292 assertFetch ( messages )
246293 await assertAIGuardSpan (
247294 { 'ai_guard.target' : 'prompt' , 'ai_guard.action' : 'ALLOW' } ,
0 commit comments