Skip to content

Commit 4f95b45

Browse files
Merge pull request #957 from MervinPraison/claude/comprehensive-task-name-fix-20250716
fix: comprehensive task_name undefined error resolution
2 parents 27972b6 + 3d5e665 commit 4f95b45

File tree

3 files changed

+186
-8
lines changed

3 files changed

+186
-8
lines changed

src/praisonai-agents/praisonaiagents/agent/agent.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1536,7 +1536,7 @@ def clean_json_output(self, output: str) -> str:
15361536
cleaned = cleaned[:-3].strip()
15371537
return cleaned
15381538

1539-
async def achat(self, prompt: str, temperature=0.2, tools=None, output_json=None, output_pydantic=None, reasoning_steps=False):
1539+
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):
15401540
"""Async version of chat method with self-reflection support."""
15411541
# Log all parameter values when in debug mode
15421542
if logging.getLogger().getEffectiveLevel() == logging.DEBUG:
@@ -1944,7 +1944,11 @@ async def aexecute(self, task, context=None):
19441944
prompt = task
19451945
else:
19461946
prompt = str(task)
1947-
return await self.achat(prompt)
1947+
# Extract task info if available
1948+
task_name = getattr(task, 'name', None)
1949+
task_description = getattr(task, 'description', None)
1950+
task_id = getattr(task, 'id', None)
1951+
return await self.achat(prompt, task_name=task_name, task_description=task_description, task_id=task_id)
19481952

19491953
async def execute_tool_async(self, function_name: str, arguments: Dict[str, Any]) -> Any:
19501954
"""Async version of execute_tool"""
@@ -2113,7 +2117,7 @@ async def handle_agent_query(request: Request, query_data: Optional[AgentQuery]
21132117
try:
21142118
# Use async version if available, otherwise use sync version
21152119
if asyncio.iscoroutinefunction(self.chat):
2116-
response = await self.achat(query)
2120+
response = await self.achat(query, task_name=None, task_description=None, task_id=None)
21172121
else:
21182122
# Run sync function in a thread to avoid blocking
21192123
loop = asyncio.get_event_loop()
@@ -2234,7 +2238,7 @@ async def execute_agent_task(prompt: str) -> str:
22342238
try:
22352239
# Ensure self.achat is used as it's the async version and pass its tools
22362240
if hasattr(self, 'achat') and asyncio.iscoroutinefunction(self.achat):
2237-
response = await self.achat(prompt, tools=self.tools)
2241+
response = await self.achat(prompt, tools=self.tools, task_name=None, task_description=None, task_id=None)
22382242
elif hasattr(self, 'chat'): # Fallback for synchronous chat
22392243
loop = asyncio.get_event_loop()
22402244
response = await loop.run_in_executor(None, lambda p=prompt: self.chat(p, tools=self.tools))

src/praisonai-agents/praisonaiagents/agents/agents.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -362,14 +362,20 @@ def _get_multimodal_message(text_prompt, images):
362362
_get_multimodal_message(task_prompt, task.images),
363363
tools=tools,
364364
output_json=task.output_json,
365-
output_pydantic=task.output_pydantic
365+
output_pydantic=task.output_pydantic,
366+
task_name=task.name,
367+
task_description=task.description,
368+
task_id=task.id
366369
)
367370
else:
368371
agent_output = await executor_agent.achat(
369372
task_prompt,
370373
tools=tools,
371374
output_json=task.output_json,
372-
output_pydantic=task.output_pydantic
375+
output_pydantic=task.output_pydantic,
376+
task_name=task.name,
377+
task_description=task.description,
378+
task_id=task.id
373379
)
374380

375381
if agent_output:
@@ -1138,7 +1144,7 @@ async def handle_query(request: Request, query_data: Optional[AgentQuery] = None
11381144
try:
11391145
# Use async version if available, otherwise use sync version
11401146
if asyncio.iscoroutinefunction(agent_instance.chat):
1141-
response = await agent_instance.achat(current_input)
1147+
response = await agent_instance.achat(current_input, task_name=None, task_description=None, task_id=None)
11421148
else:
11431149
# Run sync function in a thread to avoid blocking
11441150
loop = asyncio.get_running_loop()
@@ -1294,7 +1300,7 @@ async def execute_workflow_tool(query: str) -> str: # Renamed for clarity
12941300
try:
12951301
logging.debug(f"Processing with agent: {agent_instance.name}")
12961302
if hasattr(agent_instance, 'achat') and asyncio.iscoroutinefunction(agent_instance.achat):
1297-
response = await agent_instance.achat(current_input, tools=agent_instance.tools)
1303+
response = await agent_instance.achat(current_input, tools=agent_instance.tools, task_name=None, task_description=None, task_id=None)
12981304
elif hasattr(agent_instance, 'chat'): # Fallback to sync chat if achat not suitable
12991305
loop = asyncio.get_running_loop()
13001306
response = await loop.run_in_executor(None, lambda ci=current_input: agent_instance.chat(ci, tools=agent_instance.tools))

test_task_name_fix.py

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Test script to validate the task_name fix for agentic parallelization.
4+
This script tests the structure without requiring API keys.
5+
"""
6+
7+
import asyncio
8+
import sys
9+
import os
10+
11+
# Add the source path to sys.path
12+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src', 'praisonai-agents'))
13+
14+
def test_achat_signature():
15+
"""Test that achat method has the correct signature"""
16+
try:
17+
from praisonaiagents import Agent
18+
19+
# Create a basic agent
20+
agent = Agent(
21+
name="TestAgent",
22+
role="Test Role",
23+
goal="Test Goal",
24+
llm="mock-llm" # Using a mock LLM
25+
)
26+
27+
# Check if achat method exists and has the correct signature
28+
import inspect
29+
achat_sig = inspect.signature(agent.achat)
30+
params = list(achat_sig.parameters.keys())
31+
32+
required_params = ['prompt', 'temperature', 'tools', 'output_json', 'output_pydantic', 'reasoning_steps', 'task_name', 'task_description', 'task_id']
33+
34+
print("✅ Agent.achat signature test:")
35+
print(f" Method parameters: {params}")
36+
37+
missing_params = [p for p in required_params if p not in params]
38+
if missing_params:
39+
print(f" ❌ Missing parameters: {missing_params}")
40+
return False
41+
else:
42+
print(" ✅ All required parameters present")
43+
return True
44+
45+
except Exception as e:
46+
print(f"❌ Error testing achat signature: {e}")
47+
return False
48+
49+
def test_task_structure():
50+
"""Test that Task objects have the required attributes"""
51+
try:
52+
from praisonaiagents import Agent, Task
53+
54+
# Create a basic task
55+
agent = Agent(
56+
name="TestAgent",
57+
role="Test Role",
58+
goal="Test Goal",
59+
llm="mock-llm"
60+
)
61+
62+
task = Task(
63+
name="test_task",
64+
description="Test task description",
65+
expected_output="Test output",
66+
agent=agent
67+
)
68+
69+
print("✅ Task structure test:")
70+
print(f" Task name: {getattr(task, 'name', 'MISSING')}")
71+
print(f" Task description: {getattr(task, 'description', 'MISSING')}")
72+
print(f" Task id: {getattr(task, 'id', 'MISSING')}")
73+
74+
has_name = hasattr(task, 'name')
75+
has_description = hasattr(task, 'description')
76+
has_id = hasattr(task, 'id')
77+
78+
if has_name and has_description and has_id:
79+
print(" ✅ Task has all required attributes")
80+
return True
81+
else:
82+
print(f" ❌ Task missing attributes - name: {has_name}, description: {has_description}, id: {has_id}")
83+
return False
84+
85+
except Exception as e:
86+
print(f"❌ Error testing task structure: {e}")
87+
return False
88+
89+
async def test_achat_call():
90+
"""Test that achat can be called with task parameters"""
91+
try:
92+
from praisonaiagents import Agent
93+
94+
# Create a basic agent
95+
agent = Agent(
96+
name="TestAgent",
97+
role="Test Role",
98+
goal="Test Goal",
99+
llm="mock-llm" # This should gracefully handle mock LLM
100+
)
101+
102+
print("✅ Testing achat call with task parameters:")
103+
104+
# This should not raise a NameError for task_name anymore
105+
try:
106+
# We expect this to fail due to mock LLM, but NOT due to NameError: task_name not defined
107+
await agent.achat(
108+
"Test prompt",
109+
task_name="test_task",
110+
task_description="Test description",
111+
task_id="test_id"
112+
)
113+
print(" ✅ achat call succeeded (unexpected but good!)")
114+
return True
115+
except NameError as e:
116+
if "task_name" in str(e):
117+
print(f" ❌ Still getting task_name NameError: {e}")
118+
return False
119+
else:
120+
print(f" ⚠️ Different NameError (acceptable): {e}")
121+
return True
122+
except Exception as e:
123+
if "task_name" in str(e) and "not defined" in str(e):
124+
print(f" ❌ Still getting task_name error: {e}")
125+
return False
126+
else:
127+
print(f" ✅ Different error (expected with mock LLM): {type(e).__name__}: {e}")
128+
return True
129+
130+
except Exception as e:
131+
print(f"❌ Error testing achat call: {e}")
132+
return False
133+
134+
async def main():
135+
"""Run all tests"""
136+
print("🧪 Testing task_name fix for agentic parallelization...")
137+
print()
138+
139+
results = []
140+
141+
# Test 1: Check achat signature
142+
results.append(test_achat_signature())
143+
print()
144+
145+
# Test 2: Check task structure
146+
results.append(test_task_structure())
147+
print()
148+
149+
# Test 3: Test achat call
150+
results.append(await test_achat_call())
151+
print()
152+
153+
# Summary
154+
passed = sum(results)
155+
total = len(results)
156+
157+
print(f"📊 Test Results: {passed}/{total} tests passed")
158+
159+
if passed == total:
160+
print("🎉 All tests passed! The task_name fix appears to be working.")
161+
return 0
162+
else:
163+
print("❌ Some tests failed. The fix may need more work.")
164+
return 1
165+
166+
if __name__ == "__main__":
167+
exit_code = asyncio.run(main())
168+
sys.exit(exit_code)

0 commit comments

Comments
 (0)