Skip to content

Commit 959e2b8

Browse files
committed
Add generateContentThinkingFunctionCalling integration test
1 parent 0a7329f commit 959e2b8

File tree

1 file changed

+122
-0
lines changed

1 file changed

+122
-0
lines changed

FirebaseAI/Tests/TestApp/Tests/Integration/GenerateContentIntegrationTests.swift

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,128 @@ struct GenerateContentIntegrationTests {
231231
))
232232
}
233233

234+
@Test(
235+
arguments: [
236+
(.vertexAI_v1beta_global, ModelNames.gemini2_5_Flash, ThinkingConfig(thinkingBudget: 0)),
237+
(.vertexAI_v1beta_global, ModelNames.gemini2_5_Flash, ThinkingConfig(thinkingBudget: 24576)),
238+
(.vertexAI_v1beta_global, ModelNames.gemini2_5_Flash, ThinkingConfig(
239+
thinkingBudget: 24576, includeThoughts: true
240+
)),
241+
(.vertexAI_v1beta_global, ModelNames.gemini2_5_Pro, ThinkingConfig(thinkingBudget: 128)),
242+
(.vertexAI_v1beta_global, ModelNames.gemini2_5_Pro, ThinkingConfig(thinkingBudget: 32768)),
243+
(.vertexAI_v1beta_global, ModelNames.gemini2_5_Pro, ThinkingConfig(
244+
thinkingBudget: 32768, includeThoughts: true
245+
)),
246+
(.googleAI_v1beta, ModelNames.gemini2_5_Flash, ThinkingConfig(thinkingBudget: 0)),
247+
(.googleAI_v1beta, ModelNames.gemini2_5_Flash, ThinkingConfig(thinkingBudget: 24576)),
248+
(.googleAI_v1beta, ModelNames.gemini2_5_Flash, ThinkingConfig(
249+
thinkingBudget: 24576, includeThoughts: true
250+
)),
251+
(.googleAI_v1beta, ModelNames.gemini2_5_Pro, ThinkingConfig(thinkingBudget: 128)),
252+
(.googleAI_v1beta, ModelNames.gemini2_5_Pro, ThinkingConfig(thinkingBudget: 32768)),
253+
(.googleAI_v1beta, ModelNames.gemini2_5_Pro, ThinkingConfig(
254+
thinkingBudget: 32768, includeThoughts: true
255+
)),
256+
] as [(InstanceConfig, String, ThinkingConfig)]
257+
)
258+
func generateContentThinkingFunctionCalling(_ config: InstanceConfig, modelName: String,
259+
thinkingConfig: ThinkingConfig) async throws {
260+
let currentLocationDeclaration = FunctionDeclaration(
261+
name: "currentLocation",
262+
description: "Returns the user's current city, province or state, and country",
263+
parameters: [:]
264+
)
265+
let getTemperatureDeclaration = FunctionDeclaration(
266+
name: "getTemperature",
267+
description: "Returns the current temperature in Celsius for the specified location",
268+
parameters: [
269+
"city": .string(),
270+
"region": .string(description: "The province or state"),
271+
"country": .string(),
272+
]
273+
)
274+
let model = FirebaseAI.componentInstance(config).generativeModel(
275+
modelName: modelName,
276+
generationConfig: GenerationConfig(
277+
temperature: 0.0,
278+
topP: 0.0,
279+
topK: 1,
280+
thinkingConfig: thinkingConfig
281+
),
282+
safetySettings: safetySettings,
283+
tools: [.functionDeclarations([currentLocationDeclaration, getTemperatureDeclaration])]
284+
)
285+
let chat = model.startChat()
286+
let prompt = """
287+
What is the temperature outside right now? Respond in the format:
288+
- Location: City, Province/State, Country
289+
- Temperature: #C
290+
291+
Example Output:
292+
- Location: Vancouver, British Columbia, Canada
293+
- Temperature: 15C
294+
"""
295+
296+
let response = try await chat.sendMessage(prompt)
297+
298+
var thoughtSignatureCount = 0
299+
#expect(response.functionCalls.count == 1)
300+
let locationFunctionCall = try #require(response.functionCalls.first)
301+
try #require(locationFunctionCall.name == currentLocationDeclaration.name)
302+
#expect(locationFunctionCall.args.isEmpty)
303+
#expect(locationFunctionCall.isThought == false)
304+
if locationFunctionCall.thoughtSignature != nil {
305+
thoughtSignatureCount += 1
306+
}
307+
308+
let locationFunctionResponse = FunctionResponsePart(
309+
name: locationFunctionCall.name,
310+
response: [
311+
"city": .string("Waterloo"),
312+
"province": .string("Ontario"),
313+
"country": .string("Canada"),
314+
]
315+
)
316+
317+
let response2 = try await chat.sendMessage(locationFunctionResponse)
318+
319+
#expect(response2.functionCalls.count == 1)
320+
let temperatureFunctionCall = try #require(response2.functionCalls.first)
321+
try #require(temperatureFunctionCall.name == getTemperatureDeclaration.name)
322+
#expect(temperatureFunctionCall.args == [
323+
"city": .string("Waterloo"),
324+
"region": .string("Ontario"),
325+
"country": .string("Canada"),
326+
])
327+
#expect(temperatureFunctionCall.isThought == false)
328+
if temperatureFunctionCall.thoughtSignature != nil {
329+
thoughtSignatureCount += 1
330+
}
331+
332+
let temperatureFunctionResponse = FunctionResponsePart(
333+
name: locationFunctionCall.name,
334+
response: [
335+
"temperature": .number(25),
336+
"units": .string("Celsius"),
337+
]
338+
)
339+
340+
let response3 = try await chat.sendMessage(temperatureFunctionResponse)
341+
342+
#expect(response3.functionCalls.isEmpty)
343+
let finalText = try #require(response3.text).trimmingCharacters(in: .whitespacesAndNewlines)
344+
#expect(finalText == """
345+
- Location: Waterloo, Ontario, Canada
346+
- Temperature: 25C
347+
""")
348+
349+
if let _ = thinkingConfig.includeThoughts, case .googleAI = config.apiConfig.service {
350+
#expect(thoughtSignatureCount > 0)
351+
} else {
352+
#expect(thoughtSignatureCount == 0)
353+
}
354+
}
355+
234356
@Test(arguments: [
235357
InstanceConfig.vertexAI_v1beta,
236358
InstanceConfig.vertexAI_v1beta_global,

0 commit comments

Comments
 (0)