Skip to content

Commit fb7ed81

Browse files
committed
wip: test/versioned/google-genai
1 parent f3021c6 commit fb7ed81

File tree

5 files changed

+35
-30
lines changed

5 files changed

+35
-30
lines changed

lib/llm-events/error-message.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,21 @@ module.exports = class LlmErrorMessage {
2323
* @param {LlmTool} [params.tool] Details about the tool event if it was a tool event.
2424
*/
2525
constructor({ response, cause, summary, embedding, vectorsearch, tool } = {}) {
26-
this['http.statusCode'] = response?.status ?? cause?.status
26+
// For @google/genai only, cause does not have the `error` or `status` fields,
27+
// but it does have `message` with the info we need. So, we need to parse
28+
// the relevant fields from cause.message to get `status` and `error`.
29+
let parsedError
30+
if ((embedding?.vendor === 'gemini' || summary?.vendor === 'gemini') && cause?.message) {
31+
// Extract the JSON portion of the cause.message
32+
const jsonStartIndex = cause.message.indexOf('{')
33+
if (jsonStartIndex !== -1) {
34+
const jsonString = cause.message.substring(jsonStartIndex)
35+
parsedError = JSON.parse(jsonString)?.error
36+
}
37+
}
38+
this['http.statusCode'] = response?.status ?? cause?.status ?? parsedError?.code
2739
this['error.message'] = cause?.message
28-
this['error.code'] = response?.code ?? cause?.error?.code
40+
this['error.code'] = response?.code ?? cause?.error?.code ?? parsedError?.code
2941
this['error.param'] = response?.param ?? cause?.error?.param
3042
this.completion_id = summary?.id
3143
this.embedding_id = embedding?.id

test/unit/instrumentation/@google/genai.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ test('@google/genai unit tests', async (t) => {
2323
ctx.nr.agent = agent
2424
ctx.nr.shim = shim
2525
ctx.nr.sandbox = sandbox
26-
ctx.nr.initialize = require('../../../../lib/instrumentation/@google/genai.js')
26+
ctx.nr.initialize = require('#agentlib/instrumentation/@google/genai.js')
2727
})
2828

2929
t.afterEach(function (ctx) {

test/versioned/google-genai/embeddings.test.js

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ test('should create span on successful embedding create', (t, end) => {
6464
})
6565

6666
assert.equal(results.headers, undefined, 'should remove response headers from user result')
67-
assert.equal(results.model, 'text-embedding-004')
6867

6968
const name = `External/${host}:${port}/embeddings`
7069
assertSegments(
@@ -115,19 +114,18 @@ test('should create an embedding message', (t, end) => {
115114
const [embedding] = events
116115
const [segment] = tx.trace.getChildren(tx.trace.root.id)
117116
const expectedEmbedding = {
118-
id: /[a-f0-9]{36}/,
119117
appName: 'New Relic for Node.js tests',
120-
request_id: 'c70828b2293314366a76a2b1dcb20688',
121-
trace_id: tx.traceId,
122-
span_id: segment.id,
123-
'response.model': 'text-embedding-004',
124-
vendor: 'gemini',
118+
duration: segment.getDurationInMillis(),
119+
error: false,
120+
id: /[a-f0-9]{36}/,
125121
ingest_source: 'Node',
122+
input: 'This is an embedding test.',
126123
'request.model': 'text-embedding-004',
127-
duration: segment.getDurationInMillis(),
124+
'response.model': undefined,
128125
token_count: undefined,
129-
contents: 'This is an embedding test.',
130-
error: false
126+
span_id: segment.id,
127+
trace_id: tx.traceId,
128+
vendor: 'gemini',
131129
}
132130

133131
assert.equal(embedding[0].type, 'LlmEmbedding')
@@ -151,11 +149,11 @@ test('embedding invalid payload errors should be tracked', (t, end) => {
151149
assert.equal(tx.exceptions.length, 1)
152150
match(tx.exceptions[0], {
153151
error: {
154-
status: 404, // "NOT_FOUND"
152+
message: /.*models\/gemini-2\.0-flash is not found for API version v1beta, or is not supported for embedContent\..*/,
155153
},
156154
customAttributes: {
157155
'http.statusCode': 404,
158-
'error.message': /You are not allowed to generate embeddings from this model/,
156+
'error.message': /.*models\/gemini-2\.0-flash is not found for API version v1beta, or is not supported for embedContent\..*/,
159157
'error.code': 404,
160158
completion_id: undefined,
161159
embedding_id: /\w{32}/

test/versioned/google-genai/mock-responses.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,12 @@ responses.set('You are a mathematician.', {
9696
}
9797
})
9898

99-
// "got status: 404 Not Found. {\"error\":{\"code\":404,\"message\":\"models/gemini-2.0-flash is not found for API version v1beta, or is not supported for embedContent. Call ListModels to see the list of available models and their supported methods.\",\"status\":\"NOT_FOUND\"}}"
10099
responses.set('Embedding not allowed.', {
101100
code: 404,
102101
body: {
103102
error: {
104-
message: 'models/gemini-2.0-flash is not found for API version v1beta, or is not supported for embedContent. Call ListModels to see the list of available models and their supported methods.',
105-
code: 404,
106-
status: 'NOT_FOUND',
103+
name: 'ClientError',
104+
message: '"got status: 404 Not Found. {\\"error\\":{\\"code\\":404,\\"message\\":\\"models/gemini-2.0-flash is not found for API version v1beta, or is not supported for embedContent. Call ListModels to see the list of available models and their supported methods.\\",\\"status\\":\\"NOT_FOUND\\"}}"',
107105
}
108106
}
109107
})

test/versioned/google-genai/mock-server.js

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,7 @@ function handler(req, res) {
6666
return
6767
}
6868

69-
const { headers, code, body, streamData } = RESPONSES.get(prompt)
70-
for (const [key, value] of Object.entries(headers)) {
71-
res.setHeader(key, value)
72-
}
69+
const { code, body, streamData } = RESPONSES.get(prompt)
7370
res.statusCode = code
7471

7572
if (payload.stream === true) {
@@ -143,19 +140,19 @@ function randomStream(chunkTemplate) {
143140
return new Readable({
144141
read(size = 16) {
145142
const data = crypto.randomBytes(size)
146-
chunkTemplate.choices[0].delta.content = data.toString('base64')
143+
chunkTemplate.candidates[0].delta.content = data.toString('base64')
147144
this.push('data: ' + JSON.stringify(chunkTemplate) + '\n\n')
148145
}
149146
}).pause()
150147
}
151148

152149
function getShortenedPrompt(reqBody) {
153-
const prompt =
154-
reqBody.prompt || reqBody.input || reqBody.messages.map((m) => m.content).join('\n')
150+
try {
151+
const prompt = reqBody.contents?.[0]?.parts?.[0]?.text ||
152+
reqBody.requests?.[0]?.content?.parts?.[0]?.text
155153

156-
if (Array.isArray(prompt)) {
157-
return prompt[0]
154+
return prompt.split('\n')[0]
155+
} catch {
156+
return ''
158157
}
159-
160-
return prompt.split('\n')[0]
161158
}

0 commit comments

Comments
 (0)