Add warning when detecting context messages referring to missing tools

This commit is contained in:
Paul Kompfner
2026-01-30 12:38:34 -05:00
parent 2c16faa662
commit bcaa3164f6
8 changed files with 59 additions and 0 deletions

View File

@@ -129,4 +129,42 @@ class BaseLLMAdapter(ABC, Generic[TLLMInvocationParams]):
# Fallback to return the same tools in case they are not in a standard format
return tools
def _warn_about_orphaned_tool_messages(self, context: LLMContext) -> None:
"""Warn if context contains messages referencing tools that aren't currently available.
This can happen when tools are removed/deactivated but the conversation history
still contains function calls or tool responses for those tools. Such orphaned
messages may cause API errors from the LLM provider.
Args:
context: The LLM context to check.
"""
# Get the set of currently available tool names
available_tool_names: set[str] = set()
if isinstance(context.tools, ToolsSchema):
available_tool_names = {tool.name for tool in context.tools.standard_tools}
# Note: We don't check custom tools as they may have varying formats
# Track orphaned function names found in messages
orphaned_tools: set[str] = set()
for message in self.get_messages(context):
if isinstance(message, LLMSpecificMessage):
# Skip LLM-specific messages for now
continue
# Check for tool_calls in assistant messages
if message.get("tool_calls"):
for tc in message["tool_calls"]:
func_name = tc.get("function", {}).get("name")
if func_name and available_tool_names and func_name not in available_tool_names:
orphaned_tools.add(func_name)
# Log warning for orphaned messages
if orphaned_tools:
logger.warning(
f"Context contains references to tools that are no longer available: "
f"{sorted(orphaned_tools)}. This may cause unexpected behavior or API errors."
)
# TODO: we can move the logic to also handle the Messages here

View File

@@ -59,6 +59,9 @@ class AnthropicLLMAdapter(BaseLLMAdapter[AnthropicLLMInvocationParams]):
Returns:
Dictionary of parameters for invoking Anthropic's LLM API.
"""
# Warn about orphaned tool-related messages
self._warn_about_orphaned_tool_messages(context)
messages = self._from_universal_context_messages(self.get_messages(context))
return {
"system": messages.system,

View File

@@ -83,6 +83,9 @@ class AWSNovaSonicLLMAdapter(BaseLLMAdapter[AWSNovaSonicLLMInvocationParams]):
Returns:
Dictionary of parameters for invoking AWS Nova Sonic's LLM API.
"""
# Warn about orphaned tool-related messages
self._warn_about_orphaned_tool_messages(context)
messages = self._from_universal_context_messages(self.get_messages(context))
return {
"system_instruction": messages.system_instruction,

View File

@@ -56,6 +56,9 @@ class AWSBedrockLLMAdapter(BaseLLMAdapter[AWSBedrockLLMInvocationParams]):
Returns:
Dictionary of parameters for invoking AWS Bedrock's LLM API.
"""
# Warn about orphaned tool-related messages
self._warn_about_orphaned_tool_messages(context)
messages = self._from_universal_context_messages(self.get_messages(context))
return {
"system": messages.system,

View File

@@ -62,6 +62,9 @@ class GeminiLLMAdapter(BaseLLMAdapter[GeminiLLMInvocationParams]):
Returns:
Dictionary of parameters for Gemini's API.
"""
# Warn about orphaned tool-related messages
self._warn_about_orphaned_tool_messages(context)
messages = self._from_universal_context_messages(self.get_messages(context))
return {
"system_instruction": messages.system_instruction,

View File

@@ -59,6 +59,9 @@ class GrokRealtimeLLMAdapter(BaseLLMAdapter):
Returns:
Dictionary of parameters for invoking Grok's Voice Agent API.
"""
# Warn about orphaned tool-related messages
self._warn_about_orphaned_tool_messages(context)
messages = self._from_universal_context_messages(self.get_messages(context))
return {
"system_instruction": messages.system_instruction,

View File

@@ -60,6 +60,9 @@ class OpenAILLMAdapter(BaseLLMAdapter[OpenAILLMInvocationParams]):
Returns:
Dictionary of parameters for OpenAI's ChatCompletion API.
"""
# Warn about orphaned tool-related messages
self._warn_about_orphaned_tool_messages(context)
return {
"messages": self._from_universal_context_messages(self.get_messages(context)),
# NOTE; LLMContext's tools are guaranteed to be a ToolsSchema (or NOT_GIVEN)

View File

@@ -54,6 +54,9 @@ class OpenAIRealtimeLLMAdapter(BaseLLMAdapter):
Returns:
Dictionary of parameters for invoking OpenAI Realtime's API.
"""
# Warn about orphaned tool-related messages
self._warn_about_orphaned_tool_messages(context)
messages = self._from_universal_context_messages(self.get_messages(context))
return {
"system_instruction": messages.system_instruction,