-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Open
Labels
bugSomething isn't workingSomething isn't working
Description
Question
Overview
I am wondering if thought_signature
s returned from Google-GLA are conserved in Pydantic AI.
In the GenAI SDK for Python, if I do the following:
from google import genai
from google.genai import types as genai_types
client = genai.Client(
api_key="API_KEY_HERE", # I believe this will _not_ use vertex
)
tool_def = {
"name": "is_prime",
"description": "Check if a number is prime.",
"parameters": {
"properties": {
"value": {
"description": "If the number is prime",
"type": "integer",
}
},
"required": ["value"],
"type": "object",
},
}
stream = client.aio.models.generate_content_stream(
model="gemini-2.5-pro",
contents=[
"Compute the sum of all prime numbers on [0, 10]. "
"Think very hard and use tools."
],
config=genai_types.GenerateContentConfig(
thinking_config=genai_types.ThinkingConfig(
include_thoughts=True,
thinking_budget=-1,
),
system_instruction="You are a helpful assistant",
tools=[{"function_declarations": [tool_def]}],
),
)
async def main() -> None:
async for chunk in await stream:
for part in chunk.candidates[0].content.parts:
print(part)
print("Has thought signature:", bool(part.thought_signature))
print("-" * 100)
I get the payload in Appendix 1 (below). As can be seen, it includes a thought_signature
(attached to the part with a function call).
However, if I do:
from google.genai.types import ThinkingConfigDict
from pydantic_ai import Agent
from pydantic_ai.messages import (
FinalResultEvent,
ToolCallPartDelta,
TextPartDelta,
PartDeltaEvent,
PartStartEvent,
FunctionToolCallEvent,
FunctionToolResultEvent,
)
from pydantic_ai.models.google import GoogleModel, GoogleModelSettings
from pydantic_ai.providers.google import GoogleProvider
from pydantic_ai.toolsets import FunctionToolset
def multiply(a: float, b: float) -> float:
return a * b
agent_toolset = FunctionToolset(
tools=[
multiply,
]
)
agent = Agent(
GoogleModel(
model_name="gemini-2.5-pro",
provider=GoogleProvider(
api_key="API_KEY_HERE",
),
),
system_prompt="You are a helpful assistant.",
model_settings=GoogleModelSettings(
google_thinking_config=ThinkingConfigDict(
include_thoughts=True,
thinking_budget=256,
)
),
toolsets=[agent_toolset],
)
async def main() -> None:
prompt = ("How many quarters would fit between Earth and the Moon? Assume a quarter is 0.07 inches in width and the distance between the Earth and Moon is 238,855 miles."
"Reason carefully, guess when you need to and use tools along the way to help you with the math.")
all_nodes = []
async with agent.iter(prompt) as run:
async for node in run:
all_nodes.append(node)
then look for the signature
all_nodes[2]
# CallToolsNode(model_response=ModelResponse(parts=[ThinkingPart(content='....
type(all_nodes[2].model_response.parts[0])
# pydantic_ai.messages.ThinkingPart
assert all_nodes[2].model_response.parts[0].signature is None
type(all_nodes[2].model_response.parts[1])
# pydantic_ai.messages.TextPart
type(all_nodes[2].model_response.parts[2])
# pydantic_ai.messages.ToolCallPart
all_nodes[2].model_response.parts[2]
# ToolCallPart(tool_name='divide', args={'a': 15133852800, 'b': 0.25}, tool_call_id='...')
I can't find it in any of the parts.
Some Additional Notes
- I can see that there is a
thought_signature
field formodels.gemini._GeminiThoughtPart()
, but not for Google. - The vertex endpoint has never returned
thinking_signature
for me (even when using Google's Python SDK). I've only encountered it when using GLA. - Google states here that this signature is necessary for thinking to work as expected.
Please let me know if I'm missing something. I'm still new to the library (which is great by the way!)
Appendix
Appendix 1
video_metadata=None thought=True inline_data=None file_data=None thought_signature=None code_execution_result=None executable_code=None function_call=None function_response=None text="**Analyzing Prime Summation**\n\nI'm currently focused on the problem of calculating the sum of primes within the range [0, 10]. I've pinpointed the `is_prime` tool and its parameter, `value`, as the core components for this task. I'm exploring how to iterate through the range and effectively use this tool to determine the primes.\n\n\n"
Has thought signature: False
----------------------------------------------------------------------------------------------------
video_metadata=None thought=True inline_data=None file_data=None thought_signature=None code_execution_result=None executable_code=None function_call=None function_response=None text="**Devising the Prime Summation**\n\nI'm now building the step-by-step logic, focusing on using the `is_prime` tool within a loop for the [0, 10] range. I'm initializing an `is_prime_numbers` list to collect prime numbers, intending to sum them later. I've mapped out the tool calls for each number and its expected `True` or `False` outcome to test the program.\n\n\n"
Has thought signature: False
----------------------------------------------------------------------------------------------------
video_metadata=None thought=True inline_data=None file_data=None thought_signature=None code_execution_result=None executable_code=None function_call=None function_response=None text="**Formulating a Concise Solution**\n\nI've outlined a step-by-step approach: initialize `total_sum` to zero, loop through the range [0, 10], and for each number, call `is_prime`. If `is_prime` returns True, I'll add the number to `total_sum`. I'll then present the final sum to provide a clear and organized solution for the user. I plan to use print statements to show the prime identification as I work through the process.\n\n\n"
Has thought signature: False
----------------------------------------------------------------------------------------------------
video_metadata=None thought=True inline_data=None file_data=None thought_signature=None code_execution_result=None executable_code=None function_call=None function_response=None text="**Developing the Prime Algorithm**\n\nI'm now integrating the steps. I'll initialize `total_sum` to zero and iterate through [0, 10], calling `is_prime` as planned. If `True`, I'll update `total_sum`, printing each step for clarity. Afterward, the final `total_sum` of 17 will be presented with the primes (2, 3, 5, 7) for a complete and understandable solution.\n\n\n"
Has thought signature: False
----------------------------------------------------------------------------------------------------
video_metadata=None thought=None inline_data=None file_data=None thought_signature=b'<BYTES_HERE>' code_execution_result=None executable_code=None function_call=FunctionCall(
args={
'value': 0
},
name='is_prime'
) function_response=None text=None
Has thought signature: True
----------------------------------------------------------------------------------------------------
video_metadata=None thought=None inline_data=None file_data=None thought_signature=None code_execution_result=None executable_code=None function_call=FunctionCall(
args={
'value': 1
},
name='is_prime'
) function_response=None text=None
Has thought signature: False
----------------------------------------------------------------------------------------------------
video_metadata=None thought=None inline_data=None file_data=None thought_signature=None code_execution_result=None executable_code=None function_call=FunctionCall(
args={
'value': 2
},
name='is_prime'
) function_response=None text=None
Has thought signature: False
----------------------------------------------------------------------------------------------------
video_metadata=None thought=None inline_data=None file_data=None thought_signature=None code_execution_result=None executable_code=None function_call=FunctionCall(
args={
'value': 3
},
name='is_prime'
) function_response=None text=None
Has thought signature: False
----------------------------------------------------------------------------------------------------
video_metadata=None thought=None inline_data=None file_data=None thought_signature=None code_execution_result=None executable_code=None function_call=FunctionCall(
args={
'value': 4
},
name='is_prime'
) function_response=None text=None
Has thought signature: False
----------------------------------------------------------------------------------------------------
video_metadata=None thought=None inline_data=None file_data=None thought_signature=None code_execution_result=None executable_code=None function_call=FunctionCall(
args={
'value': 5
},
name='is_prime'
) function_response=None text=None
Has thought signature: False
----------------------------------------------------------------------------------------------------
video_metadata=None thought=None inline_data=None file_data=None thought_signature=None code_execution_result=None executable_code=None function_call=FunctionCall(
args={
'value': 6
},
name='is_prime'
) function_response=None text=None
Has thought signature: False
----------------------------------------------------------------------------------------------------
video_metadata=None thought=None inline_data=None file_data=None thought_signature=None code_execution_result=None executable_code=None function_call=FunctionCall(
args={
'value': 7
},
name='is_prime'
) function_response=None text=None
Has thought signature: False
----------------------------------------------------------------------------------------------------
video_metadata=None thought=None inline_data=None file_data=None thought_signature=None code_execution_result=None executable_code=None function_call=FunctionCall(
args={
'value': 8
},
name='is_prime'
) function_response=None text=None
Has thought signature: False
----------------------------------------------------------------------------------------------------
video_metadata=None thought=None inline_data=None file_data=None thought_signature=None code_execution_result=None executable_code=None function_call=FunctionCall(
args={
'value': 9
},
name='is_prime'
) function_response=None text=None
Has thought signature: False
----------------------------------------------------------------------------------------------------
video_metadata=None thought=None inline_data=None file_data=None thought_signature=None code_execution_result=None executable_code=None function_call=FunctionCall(
args={
'value': 10
},
name='is_prime'
) function_response=None text=None
Has thought signature: False
----------------------------------------------------------------------------------------------------
Additional Context
No response
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working