Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions src/praisonai-agents/praisonaiagents/agent/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -1536,7 +1536,7 @@ def clean_json_output(self, output: str) -> str:
cleaned = cleaned[:-3].strip()
return cleaned

async def achat(self, prompt: str, temperature=0.2, tools=None, output_json=None, output_pydantic=None, reasoning_steps=False):
async def achat(self, prompt: str, temperature=0.2, tools=None, output_json=None, output_pydantic=None, reasoning_steps=False, task_name=None, task_description=None, task_id=None):
"""Async version of chat method with self-reflection support."""
# Log all parameter values when in debug mode
if logging.getLogger().getEffectiveLevel() == logging.DEBUG:
Expand Down Expand Up @@ -1944,7 +1944,11 @@ async def aexecute(self, task, context=None):
prompt = task
else:
prompt = str(task)
return await self.achat(prompt)
# Extract task info if available
task_name = getattr(task, 'name', None)
task_description = getattr(task, 'description', None)
task_id = getattr(task, 'id', None)
return await self.achat(prompt, task_name=task_name, task_description=task_description, task_id=task_id)

async def execute_tool_async(self, function_name: str, arguments: Dict[str, Any]) -> Any:
"""Async version of execute_tool"""
Expand Down Expand Up @@ -2113,7 +2117,7 @@ async def handle_agent_query(request: Request, query_data: Optional[AgentQuery]
try:
# Use async version if available, otherwise use sync version
if asyncio.iscoroutinefunction(self.chat):
response = await self.achat(query)
response = await self.achat(query, task_name=None, task_description=None, task_id=None)
else:
# Run sync function in a thread to avoid blocking
loop = asyncio.get_event_loop()
Expand Down Expand Up @@ -2234,7 +2238,7 @@ async def execute_agent_task(prompt: str) -> str:
try:
# Ensure self.achat is used as it's the async version and pass its tools
if hasattr(self, 'achat') and asyncio.iscoroutinefunction(self.achat):
response = await self.achat(prompt, tools=self.tools)
response = await self.achat(prompt, tools=self.tools, task_name=None, task_description=None, task_id=None)
elif hasattr(self, 'chat'): # Fallback for synchronous chat
loop = asyncio.get_event_loop()
response = await loop.run_in_executor(None, lambda p=prompt: self.chat(p, tools=self.tools))
Expand Down
14 changes: 10 additions & 4 deletions src/praisonai-agents/praisonaiagents/agents/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,14 +362,20 @@ def _get_multimodal_message(text_prompt, images):
_get_multimodal_message(task_prompt, task.images),
tools=tools,
output_json=task.output_json,
output_pydantic=task.output_pydantic
output_pydantic=task.output_pydantic,
task_name=task.name,
task_description=task.description,
task_id=task.id
)
else:
agent_output = await executor_agent.achat(
task_prompt,
tools=tools,
output_json=task.output_json,
output_pydantic=task.output_pydantic
output_pydantic=task.output_pydantic,
task_name=task.name,
task_description=task.description,
task_id=task.id
)

if agent_output:
Expand Down Expand Up @@ -1138,7 +1144,7 @@ async def handle_query(request: Request, query_data: Optional[AgentQuery] = None
try:
# Use async version if available, otherwise use sync version
if asyncio.iscoroutinefunction(agent_instance.chat):
response = await agent_instance.achat(current_input)
response = await agent_instance.achat(current_input, task_name=None, task_description=None, task_id=None)
else:
# Run sync function in a thread to avoid blocking
loop = asyncio.get_running_loop()
Expand Down Expand Up @@ -1294,7 +1300,7 @@ async def execute_workflow_tool(query: str) -> str: # Renamed for clarity
try:
logging.debug(f"Processing with agent: {agent_instance.name}")
if hasattr(agent_instance, 'achat') and asyncio.iscoroutinefunction(agent_instance.achat):
response = await agent_instance.achat(current_input, tools=agent_instance.tools)
response = await agent_instance.achat(current_input, tools=agent_instance.tools, task_name=None, task_description=None, task_id=None)
elif hasattr(agent_instance, 'chat'): # Fallback to sync chat if achat not suitable
loop = asyncio.get_running_loop()
response = await loop.run_in_executor(None, lambda ci=current_input: agent_instance.chat(ci, tools=agent_instance.tools))
Expand Down
168 changes: 168 additions & 0 deletions test_task_name_fix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#!/usr/bin/env python3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

It's great that you've added a test to validate the fix! To improve the project's test suite and long-term maintainability, I have a couple of suggestions:

  • Test Framework: Consider using a standard testing framework like pytest. It simplifies test discovery, provides richer assertions, and would allow you to remove the manual main function and print statements. Your test functions are already named in a pytest-compatible way (test_*), so the transition would be smooth.

  • Project Structure: Test files are conventionally placed in a tests/ directory at the root of the project. This helps separate test code from application code and is a standard practice that many tools recognize.

  • Path Manipulation: Using sys.path.insert() can be brittle. Adopting a standard project structure with a pyproject.toml and installing the package in editable mode (pip install -e .) for development would make imports cleaner and more robust.

"""
Test script to validate the task_name fix for agentic parallelization.
This script tests the structure without requiring API keys.
"""

import asyncio
import sys
import os

# Add the source path to sys.path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src', 'praisonai-agents'))

def test_achat_signature():
"""Test that achat method has the correct signature"""
try:
from praisonaiagents import Agent

# Create a basic agent
agent = Agent(
name="TestAgent",
role="Test Role",
goal="Test Goal",
llm="mock-llm" # Using a mock LLM
)

# Check if achat method exists and has the correct signature
import inspect
achat_sig = inspect.signature(agent.achat)
params = list(achat_sig.parameters.keys())

required_params = ['prompt', 'temperature', 'tools', 'output_json', 'output_pydantic', 'reasoning_steps', 'task_name', 'task_description', 'task_id']

print("✅ Agent.achat signature test:")
print(f" Method parameters: {params}")

missing_params = [p for p in required_params if p not in params]
if missing_params:
print(f" ❌ Missing parameters: {missing_params}")
return False
else:
print(" ✅ All required parameters present")
return True

except Exception as e:
print(f"❌ Error testing achat signature: {e}")
return False

def test_task_structure():
"""Test that Task objects have the required attributes"""
try:
from praisonaiagents import Agent, Task

# Create a basic task
agent = Agent(
name="TestAgent",
role="Test Role",
goal="Test Goal",
llm="mock-llm"
)

task = Task(
name="test_task",
description="Test task description",
expected_output="Test output",
agent=agent
)

print("✅ Task structure test:")
print(f" Task name: {getattr(task, 'name', 'MISSING')}")
print(f" Task description: {getattr(task, 'description', 'MISSING')}")
print(f" Task id: {getattr(task, 'id', 'MISSING')}")

has_name = hasattr(task, 'name')
has_description = hasattr(task, 'description')
has_id = hasattr(task, 'id')

if has_name and has_description and has_id:
print(" ✅ Task has all required attributes")
return True
else:
print(f" ❌ Task missing attributes - name: {has_name}, description: {has_description}, id: {has_id}")
return False

except Exception as e:
print(f"❌ Error testing task structure: {e}")
return False

async def test_achat_call():
"""Test that achat can be called with task parameters"""
try:
from praisonaiagents import Agent

# Create a basic agent
agent = Agent(
name="TestAgent",
role="Test Role",
goal="Test Goal",
llm="mock-llm" # This should gracefully handle mock LLM
)

print("✅ Testing achat call with task parameters:")

# This should not raise a NameError for task_name anymore
try:
# We expect this to fail due to mock LLM, but NOT due to NameError: task_name not defined
await agent.achat(
"Test prompt",
task_name="test_task",
task_description="Test description",
task_id="test_id"
)
print(" ✅ achat call succeeded (unexpected but good!)")
return True
except NameError as e:
if "task_name" in str(e):
print(f" ❌ Still getting task_name NameError: {e}")
return False
else:
print(f" ⚠️ Different NameError (acceptable): {e}")
return True
except Exception as e:
if "task_name" in str(e) and "not defined" in str(e):
print(f" ❌ Still getting task_name error: {e}")
return False
else:
print(f" ✅ Different error (expected with mock LLM): {type(e).__name__}: {e}")
return True

except Exception as e:
print(f"❌ Error testing achat call: {e}")
return False

async def main():
"""Run all tests"""
print("🧪 Testing task_name fix for agentic parallelization...")
print()

results = []

# Test 1: Check achat signature
results.append(test_achat_signature())
print()

# Test 2: Check task structure
results.append(test_task_structure())
print()

# Test 3: Test achat call
results.append(await test_achat_call())
print()

# Summary
passed = sum(results)
total = len(results)

print(f"📊 Test Results: {passed}/{total} tests passed")

if passed == total:
print("🎉 All tests passed! The task_name fix appears to be working.")
return 0
else:
print("❌ Some tests failed. The fix may need more work.")
return 1

if __name__ == "__main__":
exit_code = asyncio.run(main())
sys.exit(exit_code)