Repository navigation
Retrieval tools declare query as optional, and a call without it fails the run聽#7677
Description
馃敶 Required Information
Describe the Bug:
BaseRetrievalTool._get_declaration (src/google/adk/tools/retrieval/base_retrieval_tool.py) declares one parameter, query, but does not list it in required, in either the JSON schema or the types.Schema form. So every tool built on it tells the model the query is optional: LlamaIndexRetrieval and FilesRetrieval with any model, and VertexAiRagRetrieval with non-Gemini models. None of them can run without one. LlamaIndexRetrieval reads args['query'] and raises KeyError, VertexAiRagRetrieval raises ValueError, and the exception fails the run.
load_memory has the same single query parameter and declares it as required in both forms, and a FunctionTool declaration lists every parameter that has no default and is not Optional.
Steps to Reproduce:
- Install
google-adk2.12.0 withllama-index-core(also reproduced onmainatfacd7dda). - Run the script under "Minimal Reproduction Code". It needs no network or API key: it prints the declared requirements, then lets a scripted model call the tool with no arguments, which the declaration allows.
Expected Behavior:
The declaration lists query in required, as load_memory's does, so the model knows it has to send one.
Observed Behavior:
required: search_docs=None, load_memory=['query']
run failed: KeyError: 'query'
Environment Details:
- ADK Library Version (pip show google-adk): 2.12.0,
mainatfacd7dda - Desktop OS: Windows 11
- Python Version (python -V): Python 3.11.3
Model Information:
- Are you using LiteLLM: No, though
LiteLlmsends the same parameters (see "Logs") - Which model is being used: N/A, a scripted model makes the call
馃煛 Optional Information
Regression:
No. The declaration has not listed query as required since the tool was added.
Logs:
The parameters a model receives for a LlamaIndexRetrieval tool, recorded through Runner, and the same declaration converted by LiteLlm:
Gemini request: {'type': 'object', 'properties': {'query': {'type': 'string', 'description': 'The query to retrieve.'}}}
LiteLlm request: {'type': 'object', 'properties': {'query': {'type': 'string', 'description': 'The query to retrieve.'}}}
Where the run fails:
File ".../google/adk/tools/retrieval/llama_index_retrieval.py", line 41, in run_async
nodes = self.retriever.retrieve(args['query'])
KeyError: 'query'
Screenshots / Video:
N/A
Additional Context:
The Gemini API's VALIDATED function calling mode "ensures function schema adherence", but a call with no arguments adheres to this schema. Listing query in required in both forms, as load_memory_tool.py does, fixes it.
Minimal Reproduction Code:
import asyncio
from google.adk.agents import Agent
from google.adk.models.base_llm import BaseLlm
from google.adk.models.llm_response import LlmResponse
from google.adk.runners import InMemoryRunner
from google.adk.tools.load_memory_tool import load_memory_tool
from google.adk.tools.retrieval.llama_index_retrieval import LlamaIndexRetrieval
from google.genai import types
from llama_index.core import Document
from llama_index.core import VectorStoreIndex
from llama_index.core.embeddings import MockEmbedding
class ScriptedModel(BaseLlm):
"""Calls the tool with no arguments, which its declaration allows."""
model: str = "scripted"
async def generate_content_async(self, llm_request, stream=False):
yield LlmResponse(
content=types.Content(
role="model",
parts=[types.Part.from_function_call(name="search_docs", args={})],
)
)
async def main():
index = VectorStoreIndex.from_documents(
[Document(text="Retrieval tools take the query to look up.")],
embed_model=MockEmbedding(embed_dim=2),
)
tool = LlamaIndexRetrieval(
name="search_docs",
description="Searches the product docs.",
retriever=index.as_retriever(),
)
retrieval_required = tool._get_declaration().parameters_json_schema.get(
"required"
)
memory_required = load_memory_tool._get_declaration().parameters_json_schema[
"required"
]
print(f"required: search_docs={retrieval_required}, load_memory={memory_required}")
runner = InMemoryRunner(
agent=Agent(name="assistant", model=ScriptedModel(), tools=[tool]),
app_name="repro",
)
session = await runner.session_service.create_session(
app_name="repro", user_id="u"
)
try:
async for _ in runner.run_async(
user_id="u",
session_id=session.id,
new_message=types.Content(
role="user", parts=[types.Part(text="Look it up.")]
),
):
pass
except KeyError as e:
print(f"run failed: KeyError: {e}")
asyncio.run(main())How often has this issue occurred?:
- Always (100%) when the model leaves the query out
Activity
sanketpatil06 commentedon Oct 23, 2026
Hi @roydonsequeira, thanks for the detailed report and the reproduction script.
We confirmed the issue on
main:BaseRetrievalTool._get_declarationdoesn't listqueryas required in either declaration form. Your PR #7678 addsrequiredto both forms, along with tests. Our team is reviewing it now, and we'll post updates on the PR.