pgits Claude commited on
Commit
e2bd3c2
Β·
1 Parent(s): c35b458

Fix version-agnostic WorkflowHandler implementation

Browse files

- Research-based solution using official LlamaIndex docs
- Auto-detect .chat() method (0.12.x) vs .run() method (0.14.x)
- Use proper `await handler` pattern for WorkflowHandler (0.14.x)
- Tested locally with 0.12.x - agent returns responses correctly
- Version bumped to 1.0.11

πŸ€– Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

Files changed (3) hide show
  1. app/core/agent.py +50 -15
  2. debug_version.py +83 -1
  3. pyproject.toml +1 -1
app/core/agent.py CHANGED
@@ -820,28 +820,63 @@ class ChatCalAgent:
820
  print(f"πŸ” Debug: Agent type: {type(self.agent)}")
821
  # Skip tools debug - ReActAgent doesn't expose tools attribute
822
 
823
- # Simplified approach - just call the agent synchronously
824
- # LlamaIndex 0.14.2 ReActAgent.run() should work synchronously
825
  import time
 
826
  start_time = time.time()
827
  print(f"πŸš€ Debug: Starting agent execution at {start_time}")
828
 
829
  try:
830
- print(f"πŸ”„ Debug: Running agent with max_iterations=15")
831
- print("πŸ” Debug: Calling agent.run() synchronously")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
832
 
833
- # Call agent.chat() directly - ReActAgent uses chat method
834
- result = self.agent.chat(message)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
835
 
836
- execution_time = time.time() - start_time
837
- print(f"⏱️ Debug: Agent execution completed in {execution_time:.2f} seconds")
838
- print(f"πŸ” Debug: Result type: {type(result)}")
839
- print(f"πŸ” Debug: Result: {str(result)[:200]}...")
840
-
841
- # Convert result to string response
842
- response_content = str(result)
843
- print(f"βœ… Debug: Returning agent result ({len(response_content)} chars)")
844
- return response_content
845
 
846
  except Exception as e:
847
  execution_time = time.time() - start_time
 
820
  print(f"πŸ” Debug: Agent type: {type(self.agent)}")
821
  # Skip tools debug - ReActAgent doesn't expose tools attribute
822
 
823
+ # Handle both local (0.12.x with .chat) and HuggingFace (0.14.x with .run) versions
 
824
  import time
825
+ import asyncio
826
  start_time = time.time()
827
  print(f"πŸš€ Debug: Starting agent execution at {start_time}")
828
 
829
  try:
830
+ # Check which method is available
831
+ if hasattr(self.agent, 'chat'):
832
+ print("πŸ” Debug: Using .chat() method (LlamaIndex 0.12.x)")
833
+ result = self.agent.chat(message)
834
+ response_content = str(result)
835
+ execution_time = time.time() - start_time
836
+ print(f"βœ… Debug: .chat() completed in {execution_time:.2f} seconds")
837
+ return response_content
838
+
839
+ elif hasattr(self.agent, 'run'):
840
+ print("πŸ” Debug: Using .run() method (LlamaIndex 0.14.x) - returns WorkflowHandler")
841
+
842
+ # Use async approach for WorkflowHandler
843
+ async def get_workflow_result():
844
+ workflow_handler = self.agent.run(user_msg=message, max_iterations=15)
845
+ print(f"πŸ” Debug: WorkflowHandler type: {type(workflow_handler)}")
846
+
847
+ # Use await handler pattern from docs
848
+ print("πŸ” Debug: Awaiting final response from WorkflowHandler")
849
+ final_response = await workflow_handler
850
+ print(f"πŸ” Debug: Final response type: {type(final_response)}")
851
+
852
+ # Extract response based on response format
853
+ if isinstance(final_response, dict) and "response" in final_response:
854
+ return final_response["response"]
855
+ elif hasattr(final_response, 'response'):
856
+ return str(final_response.response)
857
+ else:
858
+ return str(final_response)
859
 
860
+ # Run async function
861
+ try:
862
+ # Check if we're already in an event loop
863
+ loop = asyncio.get_running_loop()
864
+ # If in a loop, use a thread to run new event loop
865
+ import concurrent.futures
866
+ with concurrent.futures.ThreadPoolExecutor() as executor:
867
+ future = executor.submit(lambda: asyncio.run(get_workflow_result()))
868
+ response_content = future.result(timeout=60)
869
+ except RuntimeError:
870
+ # No event loop, can use asyncio.run directly
871
+ response_content = asyncio.run(get_workflow_result())
872
+
873
+ execution_time = time.time() - start_time
874
+ print(f"βœ… Debug: WorkflowHandler completed in {execution_time:.2f} seconds")
875
+ return response_content
876
 
877
+ else:
878
+ print("❌ Debug: Agent has neither .chat() nor .run() method")
879
+ return "I'm having trouble with the agent configuration. Please try again."
 
 
 
 
 
 
880
 
881
  except Exception as e:
882
  execution_time = time.time() - start_time
debug_version.py CHANGED
@@ -38,6 +38,88 @@ def check_react_agent_api():
38
  except Exception as e:
39
  print(f"Error checking ReActAgent API: {e}")
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  if __name__ == "__main__":
42
  check_llama_index_version()
43
- check_react_agent_api()
 
 
38
  except Exception as e:
39
  print(f"Error checking ReActAgent API: {e}")
40
 
41
+ def test_workflow_handler():
42
+ """Test what WorkflowHandler actually returns and what methods it has."""
43
+ try:
44
+ print("\n=== WORKFLOW HANDLER TEST ===")
45
+
46
+ # Import what we need
47
+ from llama_index.core.agent import ReActAgent
48
+ from llama_index.core.tools import BaseTool, FunctionTool
49
+ from llama_index.core.llms.mock import MockLLM
50
+ import inspect
51
+
52
+ # Create a simple mock tool
53
+ def mock_tool(query: str) -> str:
54
+ """A simple mock tool."""
55
+ return f"Mock response for: {query}"
56
+
57
+ tool = FunctionTool.from_defaults(fn=mock_tool, name="mock_tool")
58
+
59
+ # Create a mock LLM
60
+ llm = MockLLM(max_tokens=100)
61
+
62
+ # Create ReActAgent
63
+ agent = ReActAgent(tools=[tool], llm=llm, verbose=True)
64
+ print(f"βœ… Created ReActAgent successfully")
65
+
66
+ # Test the run method
67
+ print("πŸ” Testing agent.run()...")
68
+ workflow_handler = agent.run(user_msg="Hello test")
69
+
70
+ print(f"πŸ” WorkflowHandler type: {type(workflow_handler)}")
71
+ print(f"πŸ” WorkflowHandler module: {type(workflow_handler).__module__}")
72
+
73
+ # Check WorkflowHandler methods
74
+ wh_methods = [m for m in dir(workflow_handler) if not m.startswith('_')]
75
+ print(f"πŸ” WorkflowHandler methods: {sorted(wh_methods)}")
76
+
77
+ # Check for specific methods we're interested in
78
+ for method_name in ['result', 'get_result', 'run', '__iter__', '__next__', 'wait', 'done']:
79
+ if hasattr(workflow_handler, method_name):
80
+ method = getattr(workflow_handler, method_name)
81
+ if callable(method):
82
+ try:
83
+ sig = inspect.signature(method)
84
+ is_async = inspect.iscoroutinefunction(method)
85
+ print(f"βœ… {method_name}: exists, callable, async={is_async}, sig={sig}")
86
+ except:
87
+ print(f"βœ… {method_name}: exists, callable (signature unavailable)")
88
+ else:
89
+ print(f"βœ… {method_name}: exists, not callable, value={method}")
90
+ else:
91
+ print(f"❌ {method_name}: NOT FOUND")
92
+
93
+ # Test iteration
94
+ print("\nπŸ” Testing iteration...")
95
+ try:
96
+ step_count = 0
97
+ for step in workflow_handler:
98
+ step_count += 1
99
+ print(f" Step {step_count}: {type(step)} = {str(step)[:100]}...")
100
+ if step_count >= 3: # Limit to avoid infinite loops
101
+ break
102
+ print(f"βœ… Iteration completed with {step_count} steps")
103
+ except Exception as e:
104
+ print(f"❌ Iteration failed: {e}")
105
+
106
+ # Test result() method if it exists
107
+ print("\nπŸ” Testing .result() method...")
108
+ try:
109
+ if hasattr(workflow_handler, 'result'):
110
+ result = workflow_handler.result()
111
+ print(f"βœ… .result() returned: {type(result)} = {str(result)[:100]}...")
112
+ else:
113
+ print("❌ No .result() method")
114
+ except Exception as e:
115
+ print(f"❌ .result() failed: {e}")
116
+
117
+ except Exception as e:
118
+ print(f"❌ WorkflowHandler test failed: {e}")
119
+ import traceback
120
+ traceback.print_exc()
121
+
122
  if __name__ == "__main__":
123
  check_llama_index_version()
124
+ check_react_agent_api()
125
+ test_workflow_handler()
pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
  [tool.poetry]
2
  name = "voicecal-ai"
3
- version = "1.0.9"
4
  description = "A friendly AI chatbot for booking Google Calendar appointments"
5
  authors = ["Peter <pgits.job@gmail.com>"]
6
 
 
1
  [tool.poetry]
2
  name = "voicecal-ai"
3
+ version = "1.0.11"
4
  description = "A friendly AI chatbot for booking Google Calendar appointments"
5
  authors = ["Peter <pgits.job@gmail.com>"]
6