tool & is llm message for xml tool adds

This commit is contained in:
marko-kraemer 2025-04-07 12:23:32 +01:00
parent cfb3e561ed
commit 91081bc646
4 changed files with 85 additions and 14 deletions

View File

@ -82,4 +82,5 @@ def get_system_prompt():
''' '''
Returns the system prompt with XML tool usage instructions. Returns the system prompt with XML tool usage instructions.
''' '''
return SYSTEM_PROMPT + RESPONSE_FORMAT return SYSTEM_PROMPT
#+ RESPONSE_FORMAT

View File

@ -56,8 +56,8 @@ Current development environment workspace state:
llm_temperature=0.1, llm_temperature=0.1,
llm_max_tokens=8000, llm_max_tokens=8000,
processor_config=ProcessorConfig( processor_config=ProcessorConfig(
xml_tool_calling=True, xml_tool_calling=False,
native_tool_calling=False, native_tool_calling=True,
execute_tools=True, execute_tools=True,
execute_on_stream=True, execute_on_stream=True,
tool_execution_strategy="sequential", tool_execution_strategy="sequential",
@ -126,6 +126,7 @@ async def test_agent():
chunk_counter = 0 chunk_counter = 0
current_response = "" current_response = ""
tool_call_counter = 0 # Track number of tool calls
async for chunk in run_agent(thread_id=thread_id, stream=True, thread_manager=thread_manager): async for chunk in run_agent(thread_id=thread_id, stream=True, thread_manager=thread_manager):
chunk_counter += 1 chunk_counter += 1
@ -139,9 +140,47 @@ async def test_agent():
print(f"🛠️ Tool Result: {chunk.get('function_name', 'Unknown Tool')}") print(f"🛠️ Tool Result: {chunk.get('function_name', 'Unknown Tool')}")
print(f"📝 {chunk.get('result', chunk)}") print(f"📝 {chunk.get('result', chunk)}")
print("="*50 + "\n") print("="*50 + "\n")
elif chunk.get('type') == 'tool_call_chunk':
# Display native tool call chunks as they arrive
tool_call = chunk.get('tool_call', {})
# Check if it's a meaningful part of the tool call to display
if tool_call.get('function', {}).get('arguments'):
args = tool_call.get('function', {}).get('arguments', '')
# Only show when we have substantial arguments or a function name
should_display = (
len(args) > 3 or # More than just '{}'
tool_call.get('function', {}).get('name') # Or we have a name
)
if should_display:
tool_call_counter += 1
print("\n" + "-"*50)
print(f"🔧 Tool Call #{tool_call_counter}: {tool_call.get('function', {}).get('name', 'Building...')}")
# Try to parse and pretty print the arguments if they're JSON
try:
# Check if it's complete JSON or just a fragment
if args.strip().startswith('{') and args.strip().endswith('}'):
args_obj = json.loads(args)
print(f"📋 Arguments: {json.dumps(args_obj, indent=2)}")
else:
print(f"📋 Arguments (partial): {args}")
except json.JSONDecodeError:
print(f"📋 Arguments (building): {args}")
print("-"*50)
# Return to the current content display
if current_response:
print("\nContinuing response:", flush=True)
print(current_response, end='', flush=True)
print("\n" + "="*50) print("\n" + "="*50)
print(f"✅ Agent completed. Processed {chunk_counter} chunks.") print(f"✅ Agent completed. Processed {chunk_counter} chunks.")
if tool_call_counter > 0:
print(f"🔧 Found {tool_call_counter} native tool calls.")
print("="*50 + "\n") print("="*50 + "\n")
print("\n" + "="*50) print("\n" + "="*50)

View File

@ -175,6 +175,37 @@ class ResponseProcessor:
# Process native tool calls # Process native tool calls
if config.native_tool_calling and delta and hasattr(delta, 'tool_calls') and delta.tool_calls: if config.native_tool_calling and delta and hasattr(delta, 'tool_calls') and delta.tool_calls:
for tool_call in delta.tool_calls: for tool_call in delta.tool_calls:
# Yield the raw tool call chunk directly to the stream
# Safely extract tool call data even if model_dump isn't available
tool_call_data = {}
if hasattr(tool_call, 'model_dump'):
# Use model_dump if available (OpenAI client)
tool_call_data = tool_call.model_dump()
else:
# Manual extraction if model_dump not available
if hasattr(tool_call, 'id'):
tool_call_data['id'] = tool_call.id
if hasattr(tool_call, 'index'):
tool_call_data['index'] = tool_call.index
if hasattr(tool_call, 'type'):
tool_call_data['type'] = tool_call.type
if hasattr(tool_call, 'function'):
tool_call_data['function'] = {}
if hasattr(tool_call.function, 'name'):
tool_call_data['function']['name'] = tool_call.function.name
if hasattr(tool_call.function, 'arguments'):
tool_call_data['function']['arguments'] = tool_call.function.arguments
# Yield the chunk data
yield {
"type": "tool_call_chunk",
"tool_call": tool_call_data
}
# Log the tool call chunk for debugging
logger.debug(f"Yielded native tool call chunk: {tool_call_data}")
if not hasattr(tool_call, 'function'): if not hasattr(tool_call, 'function'):
continue continue
@ -988,9 +1019,9 @@ class ResponseProcessor:
} }
await self.add_message( await self.add_message(
thread_id=thread_id, thread_id=thread_id,
type=result_role if result_role == "assistant" else "user", type="tool",
content=result_message, content=result_message,
is_llm_message=(result_role == "assistant") is_llm_message=True
) )
except Exception as e: except Exception as e:
logger.error(f"Error adding tool result: {str(e)}", exc_info=True) logger.error(f"Error adding tool result: {str(e)}", exc_info=True)
@ -1002,7 +1033,7 @@ class ResponseProcessor:
} }
await self.add_message( await self.add_message(
thread_id=thread_id, thread_id=thread_id,
type="user", type="tool",
content=fallback_message, content=fallback_message,
is_llm_message=True is_llm_message=True
) )

View File

@ -187,14 +187,14 @@ class ThreadManager:
logger.debug(f"Processor config: XML={processor_config.xml_tool_calling}, Native={processor_config.native_tool_calling}, " logger.debug(f"Processor config: XML={processor_config.xml_tool_calling}, Native={processor_config.native_tool_calling}, "
f"Execute tools={processor_config.execute_tools}, Strategy={processor_config.tool_execution_strategy}") f"Execute tools={processor_config.execute_tools}, Strategy={processor_config.tool_execution_strategy}")
# Check if native_tool_calling is enabled and throw an error if it is # # Check if native_tool_calling is enabled and throw an error if it is
if processor_config.native_tool_calling: # if processor_config.native_tool_calling:
error_message = "Native tool calling is not supported in this version" # error_message = "Native tool calling is not supported in this version"
logger.error(error_message) # logger.error(error_message)
return { # return {
"status": "error", # "status": "error",
"message": error_message # "message": error_message
} # }
# 4. Prepare tools for LLM call # 4. Prepare tools for LLM call
openapi_tool_schemas = None openapi_tool_schemas = None