googleapis / googleapis/python-genai

Providing thought signatures back DOES NOT change input tokens count

Open
#1,129 7 comments 0 reactions 1 assignee Assigned to @kkorpal View on GitHub
priority: p2 type: bug
Dominant language
Python
Stars
4k
Forks
1k
Avg merge
2d 11h
Merged PRs (30d)
40

Description

According to the docs in https://ai.google.dev/gemini-api/docs/thinking#pricing, it says

> Thought signatures will increase the input tokens you are charged when sent back as part of the request.

However, when I try to send the thought signature back, it DOES NOT increase the input tokens. This makes me believe that there is a bug somewhere and that thought signatures are not actually sent back. To repro, use this code
```
import google.genai as genai
from copy import deepcopy

client = genai.Client()

tool_def = {
"name": "get_weather",
"description": "Get the weather of a city",
"parameters": {
"properties": {
"city": {"description": "The city to get the weather of", "type": "string"}
},
"required": ["city"],
"type": "object",
},
}

def get_llm_response(conversation_history):
return client.models.generate_content(
model="gemini-2.5-flash",
contents=conversation_history,
config={
"tools": [{"function_declarations": [tool_def]}],
"thinking_config": {"thinking_budget": 24576, "include_thoughts": True},
},
)

init_conversation_history = [
{
"role": "user",
"parts": [{"text": "hey, how are you? Be careful, its a trick question"}],
}
]

response = get_llm_response(init_conversation_history)
assert len(response.candidates[0].content.parts) == 2, (
"The response must have two parts for the rest of the code to work. Please retry."
)
assert response.candidates[0].content.parts[0].thought is True, (
"The response must have a thought for the rest of the code to work. Please retry."
)
assert (
response.usage_metadata.thoughts_token_count is not None
and response.usage_metadata.thoughts_token_count > 0
), (
"The response must have a thought token count for the rest of the code to work. Please retry."
)
thought_signature = response.candidates[0].content.parts[1].thought_signature
assert (
thought_signature is not None
and type(thought_signature) is bytes
and len(thought_signature) > 0
), (
"The response must have a thought signature for the rest of the code to work. Please retry."
)
assert (
response.candidates[0].content.parts[1].text is not None
and len(response.candidates[0].content.parts[1].text) > 0
), (
"The response must have a text response for the rest of the code to work. Please retry."
)

def extend_conversation_history(conversation_history, prev_response, thought_signature):
if thought_signature is not None:
conversation_history.append(
{
"role": "model",
"parts": [
{
"text": prev_response.candidates[0].content.parts[1].text,
"thought_signature": thought_signature,
}
],
}
)
else:
conversation_history.append(
{
"role": "model",
"parts": [
{
"text": prev_response.candidates[0].content.parts[1].text,
}
],
}
)
conversation_history.append({"role": "user", "parts": [{"text": "hi"}]})

conversation_history_WITH_thought_signature = deepcopy(init_conversation_history)
extend_conversation_history(
conversation_history_WITH_thought_signature,
response,
thought_signature=thought_signature,
)

conversation_history_WITHOUT_thought_signature = deepcopy(init_conversation_history)
extend_conversation_history(
conversation_history_WITHOUT_thought_signature,
response,
thought_signature=None,
)

response_WITH_thought_signature = get_llm_response(
conversation_history_WITH_thought_signature
)
response_WITHOUT_thought_signature = get_llm_response(
conversation_history_WITHOUT_thought_signature
)

assert (
response_WITH_thought_signature.usage_metadata.prompt_token_count
!= response_WITHOUT_thought_signature.usage_metadata.prompt_token_count
), (
"The repro code worked as expected. The prompt token count should be different but they are not."
)
```

#### Environment details

- Programming language: python 3.11
- OS:
- Language runtime version:
- Package version: google-genai>=1.25.0

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.