mirror of
https://github.com/MervinPraison/PraisonAI.git
synced 2026-11-09 11:51:37 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6a3bd1240 | ||
|
|
0a18e27f54 |
No files matched your search
+1
-1
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
|
||||
# Install Python packages (using latest versions)
|
||||
RUN pip install --no-cache-dir \
|
||||
flask \
|
||||
"praisonai>=2.2.27" \
|
||||
"praisonai>=2.2.28" \
|
||||
"praisonai[api]" \
|
||||
gunicorn \
|
||||
markdown
|
||||
|
||||
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
|
||||
# Install Python packages (using latest versions)
|
||||
RUN pip install --no-cache-dir \
|
||||
praisonai_tools \
|
||||
"praisonai>=2.2.27" \
|
||||
"praisonai>=2.2.28" \
|
||||
"praisonai[chat]" \
|
||||
"embedchain[github,youtube]"
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ RUN mkdir -p /root/.praison
|
||||
# Install Python packages (using latest versions)
|
||||
RUN pip install --no-cache-dir \
|
||||
praisonai_tools \
|
||||
"praisonai>=2.2.27" \
|
||||
"praisonai>=2.2.28" \
|
||||
"praisonai[ui]" \
|
||||
"praisonai[chat]" \
|
||||
"praisonai[realtime]" \
|
||||
|
||||
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
|
||||
# Install Python packages (using latest versions)
|
||||
RUN pip install --no-cache-dir \
|
||||
praisonai_tools \
|
||||
"praisonai>=2.2.27" \
|
||||
"praisonai>=2.2.28" \
|
||||
"praisonai[ui]" \
|
||||
"praisonai[crewai]"
|
||||
|
||||
|
||||
+2
-2
@@ -121,7 +121,7 @@ healthcheck:
|
||||
## 📦 Package Versions
|
||||
|
||||
All Docker images use consistent, up-to-date versions:
|
||||
- PraisonAI: `>=2.2.27`
|
||||
- PraisonAI: `>=2.2.28`
|
||||
- PraisonAI Agents: `>=0.0.92`
|
||||
- Python: `3.11-slim`
|
||||
|
||||
@@ -218,7 +218,7 @@ docker-compose up -d
|
||||
### Version Pinning
|
||||
To use specific versions, update the Dockerfile:
|
||||
```dockerfile
|
||||
RUN pip install "praisonai==2.2.27" "praisonaiagents==0.0.92"
|
||||
RUN pip install "praisonai==2.2.28" "praisonaiagents==0.0.92"
|
||||
```
|
||||
|
||||
## 🌐 Production Deployment
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
from praisonaiagents import Agent, MCP
|
||||
|
||||
def test_agent_direct():
|
||||
"""Test gpt-4o-mini (agent.py path)"""
|
||||
print("=" * 50)
|
||||
print("TESTING: gpt-4o-mini (agent.py direct calls)")
|
||||
print("=" * 50)
|
||||
|
||||
try:
|
||||
agent = Agent(
|
||||
instructions="""You are a helpful assistant that can break down complex problems.
|
||||
Use the available tools when relevant to perform step-by-step analysis.""",
|
||||
llm="gpt-4o-mini",
|
||||
tools=MCP("npx -y @modelcontextprotocol/server-sequential-thinking")
|
||||
)
|
||||
|
||||
print("✅ Agent created successfully")
|
||||
print(f"✅ Agent LLM: {getattr(agent, 'llm', 'Not set')}")
|
||||
print(f"✅ Agent using custom LLM: {getattr(agent, '_using_custom_llm', False)}")
|
||||
|
||||
result = agent.start("What are 3 steps to make coffee?")
|
||||
print("✅ Agent execution completed successfully")
|
||||
return True, result
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error in agent direct: {e}")
|
||||
traceback.print_exc()
|
||||
return False, str(e)
|
||||
|
||||
def test_llm_class():
|
||||
"""Test openai/gpt-4o-mini (llm.py path)"""
|
||||
print("\n" + "=" * 50)
|
||||
print("TESTING: openai/gpt-4o-mini (llm.py LiteLLM)")
|
||||
print("=" * 50)
|
||||
|
||||
try:
|
||||
agent = Agent(
|
||||
instructions="""You are a helpful assistant that can break down complex problems.
|
||||
Use the available tools when relevant to perform step-by-step analysis.""",
|
||||
llm="openai/gpt-4o-mini",
|
||||
tools=MCP("npx -y @modelcontextprotocol/server-sequential-thinking")
|
||||
)
|
||||
|
||||
print("✅ Agent created successfully")
|
||||
print(f"✅ Agent LLM instance: {getattr(agent, 'llm_instance', 'Not set')}")
|
||||
print(f"✅ Agent using custom LLM: {getattr(agent, '_using_custom_llm', False)}")
|
||||
|
||||
result = agent.start("What are 3 steps to make coffee?")
|
||||
print("✅ Agent execution completed successfully")
|
||||
return True, result
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error in llm class: {e}")
|
||||
traceback.print_exc()
|
||||
return False, str(e)
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("🔍 DEBUGGING: Comparing both LLM approaches\n")
|
||||
|
||||
# Test agent direct
|
||||
success1, result1 = test_agent_direct()
|
||||
|
||||
# Test LLM class
|
||||
success2, result2 = test_llm_class()
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print("FINAL RESULTS")
|
||||
print("=" * 50)
|
||||
|
||||
if success1:
|
||||
print("✅ gpt-4o-mini (agent.py) - SUCCESS")
|
||||
else:
|
||||
print("❌ gpt-4o-mini (agent.py) - FAILED")
|
||||
print(f" Error: {result1}")
|
||||
|
||||
if success2:
|
||||
print("✅ openai/gpt-4o-mini (llm.py) - SUCCESS")
|
||||
else:
|
||||
print("❌ openai/gpt-4o-mini (llm.py) - FAILED")
|
||||
print(f" Error: {result2}")
|
||||
|
||||
if success1 and success2:
|
||||
print("\n🎉 BOTH FORMATS WORK CORRECTLY!")
|
||||
print("📝 The issue mentioned might be resolved or was a different problem.")
|
||||
elif success1 and not success2:
|
||||
print("\n⚠️ CONFIRMED: LLM class path has issues")
|
||||
print("📝 Need to debug the LLM class implementation")
|
||||
elif success2 and not success1:
|
||||
print("\n⚠️ CONFIRMED: Agent direct path has issues")
|
||||
print("📝 Need to debug the agent direct implementation")
|
||||
else:
|
||||
print("\n💥 BOTH PATHS FAILED - Something is fundamentally wrong")
|
||||
@@ -413,24 +413,30 @@ class LLM:
|
||||
start_time = time.time()
|
||||
reflection_count = 0
|
||||
|
||||
while True:
|
||||
try:
|
||||
if verbose:
|
||||
display_text = prompt
|
||||
if isinstance(prompt, list):
|
||||
display_text = next((item["text"] for item in prompt if item["type"] == "text"), "")
|
||||
|
||||
if display_text and str(display_text).strip():
|
||||
display_instruction(
|
||||
f"Agent {agent_name} is processing prompt: {display_text}",
|
||||
console=console,
|
||||
agent_name=agent_name,
|
||||
agent_role=agent_role,
|
||||
agent_tools=agent_tools
|
||||
)
|
||||
# Display initial instruction once
|
||||
if verbose:
|
||||
display_text = prompt
|
||||
if isinstance(prompt, list):
|
||||
display_text = next((item["text"] for item in prompt if item["type"] == "text"), "")
|
||||
|
||||
if display_text and str(display_text).strip():
|
||||
display_instruction(
|
||||
f"Agent {agent_name} is processing prompt: {display_text}",
|
||||
console=console,
|
||||
agent_name=agent_name,
|
||||
agent_role=agent_role,
|
||||
agent_tools=agent_tools
|
||||
)
|
||||
|
||||
# Sequential tool calling loop - similar to agent.py
|
||||
max_iterations = 10 # Prevent infinite loops
|
||||
iteration_count = 0
|
||||
final_response_text = ""
|
||||
|
||||
while iteration_count < max_iterations:
|
||||
try:
|
||||
# Get response from LiteLLM
|
||||
start_time = time.time()
|
||||
current_time = time.time()
|
||||
|
||||
# If reasoning_steps is True, do a single non-streaming call
|
||||
if reasoning_steps:
|
||||
@@ -445,6 +451,7 @@ class LLM:
|
||||
)
|
||||
reasoning_content = resp["choices"][0]["message"].get("provider_specific_fields", {}).get("reasoning_content")
|
||||
response_text = resp["choices"][0]["message"]["content"]
|
||||
final_response = resp
|
||||
|
||||
# Optionally display reasoning if present
|
||||
if verbose and reasoning_content:
|
||||
@@ -452,7 +459,7 @@ class LLM:
|
||||
original_prompt,
|
||||
f"Reasoning:\n{reasoning_content}\n\nAnswer:\n{response_text}",
|
||||
markdown=markdown,
|
||||
generation_time=time.time() - start_time,
|
||||
generation_time=time.time() - current_time,
|
||||
console=console
|
||||
)
|
||||
else:
|
||||
@@ -460,14 +467,14 @@ class LLM:
|
||||
original_prompt,
|
||||
response_text,
|
||||
markdown=markdown,
|
||||
generation_time=time.time() - start_time,
|
||||
generation_time=time.time() - current_time,
|
||||
console=console
|
||||
)
|
||||
|
||||
# Otherwise do the existing streaming approach
|
||||
else:
|
||||
if verbose:
|
||||
with Live(display_generating("", start_time), console=console, refresh_per_second=4) as live:
|
||||
with Live(display_generating("", current_time), console=console, refresh_per_second=4) as live:
|
||||
response_text = ""
|
||||
for chunk in litellm.completion(
|
||||
**self._build_completion_params(
|
||||
@@ -481,7 +488,7 @@ class LLM:
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
content = chunk.choices[0].delta.content
|
||||
response_text += content
|
||||
live.update(display_generating(response_text, start_time))
|
||||
live.update(display_generating(response_text, current_time))
|
||||
else:
|
||||
# Non-verbose mode, just collect the response
|
||||
response_text = ""
|
||||
@@ -499,20 +506,20 @@ class LLM:
|
||||
|
||||
response_text = response_text.strip()
|
||||
|
||||
# Get final completion to check for tool calls
|
||||
final_response = litellm.completion(
|
||||
**self._build_completion_params(
|
||||
messages=messages,
|
||||
tools=formatted_tools,
|
||||
temperature=temperature,
|
||||
stream=False, # No streaming for tool call check
|
||||
**kwargs
|
||||
# Get final completion to check for tool calls
|
||||
final_response = litellm.completion(
|
||||
**self._build_completion_params(
|
||||
messages=messages,
|
||||
tools=formatted_tools,
|
||||
temperature=temperature,
|
||||
stream=False, # No streaming for tool call check
|
||||
**kwargs
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
tool_calls = final_response["choices"][0]["message"].get("tool_calls")
|
||||
|
||||
# Handle tool calls
|
||||
# Handle tool calls - Sequential tool calling logic
|
||||
if tool_calls and execute_tool_fn:
|
||||
# Convert tool_calls to a serializable format for all providers
|
||||
serializable_tool_calls = []
|
||||
@@ -535,6 +542,7 @@ class LLM:
|
||||
"tool_calls": serializable_tool_calls
|
||||
})
|
||||
|
||||
should_continue = False
|
||||
for tool_call in tool_calls:
|
||||
# Handle both object and dict access patterns
|
||||
if isinstance(tool_call, dict):
|
||||
@@ -574,6 +582,18 @@ class LLM:
|
||||
"content": json.dumps(tool_result) if tool_result is not None else "Function returned an empty output"
|
||||
})
|
||||
|
||||
# Check if we should continue (for tools like sequential thinking)
|
||||
# This mimics the logic from agent.py lines 1004-1007
|
||||
if function_name == "sequentialthinking" and arguments.get("nextThoughtNeeded", False):
|
||||
should_continue = True
|
||||
|
||||
# If we should continue, increment iteration and continue loop
|
||||
if should_continue:
|
||||
iteration_count += 1
|
||||
continue
|
||||
|
||||
# If we reach here, no more tool calls needed - get final response
|
||||
# Make one more call to get the final summary response
|
||||
# Special handling for Ollama models that don't automatically process tool results
|
||||
if self.model and self.model.startswith("ollama/") and tool_result:
|
||||
# For Ollama models, we need to explicitly ask the model to process the tool results
|
||||
@@ -666,115 +686,141 @@ class LLM:
|
||||
else:
|
||||
# Get response after tool calls with streaming
|
||||
if verbose:
|
||||
with Live(display_generating("", start_time), console=console, refresh_per_second=4) as live:
|
||||
response_text = ""
|
||||
with Live(display_generating("", current_time), console=console, refresh_per_second=4) as live:
|
||||
final_response_text = ""
|
||||
for chunk in litellm.completion(
|
||||
**self._build_completion_params(
|
||||
messages=messages,
|
||||
tools=formatted_tools,
|
||||
temperature=temperature,
|
||||
stream=True
|
||||
stream=True,
|
||||
**kwargs
|
||||
)
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
content = chunk.choices[0].delta.content
|
||||
response_text += content
|
||||
live.update(display_generating(response_text, start_time))
|
||||
final_response_text += content
|
||||
live.update(display_generating(final_response_text, current_time))
|
||||
else:
|
||||
response_text = ""
|
||||
final_response_text = ""
|
||||
for chunk in litellm.completion(
|
||||
**self._build_completion_params(
|
||||
messages=messages,
|
||||
tools=formatted_tools,
|
||||
temperature=temperature,
|
||||
stream=True
|
||||
stream=True,
|
||||
**kwargs
|
||||
)
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
response_text += chunk.choices[0].delta.content
|
||||
|
||||
response_text = response_text.strip()
|
||||
|
||||
# Handle output formatting
|
||||
if output_json or output_pydantic:
|
||||
self.chat_history.append({"role": "user", "content": original_prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
final_response_text += chunk.choices[0].delta.content
|
||||
|
||||
final_response_text = final_response_text.strip()
|
||||
|
||||
# Display final response
|
||||
if verbose:
|
||||
display_interaction(original_prompt, response_text, markdown=markdown,
|
||||
generation_time=time.time() - start_time, console=console)
|
||||
return response_text
|
||||
display_interaction(
|
||||
original_prompt,
|
||||
final_response_text,
|
||||
markdown=markdown,
|
||||
generation_time=time.time() - start_time,
|
||||
console=console
|
||||
)
|
||||
|
||||
return final_response_text
|
||||
else:
|
||||
# No tool calls, we're done with this iteration
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error in LLM iteration {iteration_count}: {e}")
|
||||
break
|
||||
|
||||
# End of while loop - return final response
|
||||
if final_response_text:
|
||||
return final_response_text
|
||||
|
||||
# No tool calls were made in this iteration, return the response
|
||||
if verbose:
|
||||
display_interaction(
|
||||
original_prompt,
|
||||
response_text,
|
||||
markdown=markdown,
|
||||
generation_time=time.time() - start_time,
|
||||
console=console
|
||||
)
|
||||
|
||||
response_text = response_text.strip()
|
||||
|
||||
# Handle output formatting
|
||||
if output_json or output_pydantic:
|
||||
self.chat_history.append({"role": "user", "content": original_prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
if verbose:
|
||||
display_interaction(original_prompt, response_text, markdown=markdown,
|
||||
generation_time=time.time() - start_time, console=console)
|
||||
return response_text
|
||||
|
||||
if not self_reflect:
|
||||
if verbose:
|
||||
display_interaction(original_prompt, response_text, markdown=markdown,
|
||||
generation_time=time.time() - start_time, console=console)
|
||||
# Return reasoning content if reasoning_steps is True
|
||||
if reasoning_steps and reasoning_content:
|
||||
return reasoning_content
|
||||
return response_text
|
||||
if not self_reflect:
|
||||
if verbose:
|
||||
display_interaction(original_prompt, response_text, markdown=markdown,
|
||||
generation_time=time.time() - start_time, console=console)
|
||||
# Return reasoning content if reasoning_steps is True
|
||||
if reasoning_steps and reasoning_content:
|
||||
return reasoning_content
|
||||
return response_text
|
||||
|
||||
# Handle self-reflection
|
||||
reflection_prompt = f"""
|
||||
# Handle self-reflection loop
|
||||
while reflection_count < max_reflect:
|
||||
# Handle self-reflection
|
||||
reflection_prompt = f"""
|
||||
Reflect on your previous response: '{response_text}'.
|
||||
Identify any flaws, improvements, or actions.
|
||||
Provide a "satisfactory" status ('yes' or 'no').
|
||||
Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
"""
|
||||
|
||||
reflection_messages = messages + [
|
||||
{"role": "assistant", "content": response_text},
|
||||
{"role": "user", "content": reflection_prompt}
|
||||
]
|
||||
"""
|
||||
|
||||
reflection_messages = messages + [
|
||||
{"role": "assistant", "content": response_text},
|
||||
{"role": "user", "content": reflection_prompt}
|
||||
]
|
||||
|
||||
# If reasoning_steps is True, do a single non-streaming call to capture reasoning
|
||||
if reasoning_steps:
|
||||
reflection_resp = litellm.completion(
|
||||
**self._build_completion_params(
|
||||
messages=reflection_messages,
|
||||
temperature=temperature,
|
||||
stream=False, # Force non-streaming
|
||||
response_format={"type": "json_object"},
|
||||
**{k:v for k,v in kwargs.items() if k != 'reasoning_steps'}
|
||||
)
|
||||
# If reasoning_steps is True, do a single non-streaming call to capture reasoning
|
||||
if reasoning_steps:
|
||||
reflection_resp = litellm.completion(
|
||||
**self._build_completion_params(
|
||||
messages=reflection_messages,
|
||||
temperature=temperature,
|
||||
stream=False, # Force non-streaming
|
||||
response_format={"type": "json_object"},
|
||||
**{k:v for k,v in kwargs.items() if k != 'reasoning_steps'}
|
||||
)
|
||||
# Grab reflection text and optional reasoning
|
||||
reasoning_content = reflection_resp["choices"][0]["message"].get("provider_specific_fields", {}).get("reasoning_content")
|
||||
reflection_text = reflection_resp["choices"][0]["message"]["content"]
|
||||
)
|
||||
# Grab reflection text and optional reasoning
|
||||
reasoning_content = reflection_resp["choices"][0]["message"].get("provider_specific_fields", {}).get("reasoning_content")
|
||||
reflection_text = reflection_resp["choices"][0]["message"]["content"]
|
||||
|
||||
# Optionally display reasoning if present
|
||||
if verbose and reasoning_content:
|
||||
display_interaction(
|
||||
"Reflection reasoning:",
|
||||
f"{reasoning_content}\n\nReflection result:\n{reflection_text}",
|
||||
markdown=markdown,
|
||||
generation_time=time.time() - start_time,
|
||||
console=console
|
||||
)
|
||||
elif verbose:
|
||||
display_interaction(
|
||||
"Self-reflection (non-streaming):",
|
||||
reflection_text,
|
||||
markdown=markdown,
|
||||
generation_time=time.time() - start_time,
|
||||
console=console
|
||||
)
|
||||
else:
|
||||
# Existing streaming approach
|
||||
if verbose:
|
||||
with Live(display_generating("", start_time), console=console, refresh_per_second=4) as live:
|
||||
reflection_text = ""
|
||||
for chunk in litellm.completion(
|
||||
**self._build_completion_params(
|
||||
messages=reflection_messages,
|
||||
temperature=temperature,
|
||||
stream=True,
|
||||
response_format={"type": "json_object"},
|
||||
**{k:v for k,v in kwargs.items() if k != 'reasoning_steps'}
|
||||
)
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
content = chunk.choices[0].delta.content
|
||||
reflection_text += content
|
||||
live.update(display_generating(reflection_text, start_time))
|
||||
else:
|
||||
# Optionally display reasoning if present
|
||||
if verbose and reasoning_content:
|
||||
display_interaction(
|
||||
"Reflection reasoning:",
|
||||
f"{reasoning_content}\n\nReflection result:\n{reflection_text}",
|
||||
markdown=markdown,
|
||||
generation_time=time.time() - start_time,
|
||||
console=console
|
||||
)
|
||||
elif verbose:
|
||||
display_interaction(
|
||||
"Self-reflection (non-streaming):",
|
||||
reflection_text,
|
||||
markdown=markdown,
|
||||
generation_time=time.time() - start_time,
|
||||
console=console
|
||||
)
|
||||
else:
|
||||
# Existing streaming approach
|
||||
if verbose:
|
||||
with Live(display_generating("", start_time), console=console, refresh_per_second=4) as live:
|
||||
reflection_text = ""
|
||||
for chunk in litellm.completion(
|
||||
**self._build_completion_params(
|
||||
@@ -786,48 +832,102 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
)
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
reflection_text += chunk.choices[0].delta.content
|
||||
|
||||
try:
|
||||
reflection_data = json.loads(reflection_text)
|
||||
satisfactory = reflection_data.get("satisfactory", "no").lower() == "yes"
|
||||
|
||||
if verbose:
|
||||
display_self_reflection(
|
||||
f"Agent {agent_name} self reflection: reflection='{reflection_data['reflection']}' satisfactory='{reflection_data['satisfactory']}'",
|
||||
console=console
|
||||
content = chunk.choices[0].delta.content
|
||||
reflection_text += content
|
||||
live.update(display_generating(reflection_text, start_time))
|
||||
else:
|
||||
reflection_text = ""
|
||||
for chunk in litellm.completion(
|
||||
**self._build_completion_params(
|
||||
messages=reflection_messages,
|
||||
temperature=temperature,
|
||||
stream=True,
|
||||
response_format={"type": "json_object"},
|
||||
**{k:v for k,v in kwargs.items() if k != 'reasoning_steps'}
|
||||
)
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
reflection_text += chunk.choices[0].delta.content
|
||||
|
||||
if satisfactory and reflection_count >= min_reflect - 1:
|
||||
if verbose:
|
||||
display_interaction(prompt, response_text, markdown=markdown,
|
||||
generation_time=time.time() - start_time, console=console)
|
||||
return response_text
|
||||
try:
|
||||
reflection_data = json.loads(reflection_text)
|
||||
satisfactory = reflection_data.get("satisfactory", "no").lower() == "yes"
|
||||
|
||||
if reflection_count >= max_reflect - 1:
|
||||
if verbose:
|
||||
display_interaction(prompt, response_text, markdown=markdown,
|
||||
generation_time=time.time() - start_time, console=console)
|
||||
return response_text
|
||||
if verbose:
|
||||
display_self_reflection(
|
||||
f"Agent {agent_name} self reflection: reflection='{reflection_data['reflection']}' satisfactory='{reflection_data['satisfactory']}'",
|
||||
console=console
|
||||
)
|
||||
|
||||
reflection_count += 1
|
||||
messages.extend([
|
||||
{"role": "assistant", "content": response_text},
|
||||
{"role": "user", "content": reflection_prompt},
|
||||
{"role": "assistant", "content": reflection_text},
|
||||
{"role": "user", "content": "Now regenerate your response using the reflection you made"}
|
||||
])
|
||||
continue
|
||||
if satisfactory and reflection_count >= min_reflect - 1:
|
||||
if verbose:
|
||||
display_interaction(prompt, response_text, markdown=markdown,
|
||||
generation_time=time.time() - start_time, console=console)
|
||||
return response_text
|
||||
|
||||
except json.JSONDecodeError:
|
||||
reflection_count += 1
|
||||
if reflection_count >= max_reflect:
|
||||
return response_text
|
||||
continue
|
||||
if reflection_count >= max_reflect - 1:
|
||||
if verbose:
|
||||
display_interaction(prompt, response_text, markdown=markdown,
|
||||
generation_time=time.time() - start_time, console=console)
|
||||
return response_text
|
||||
|
||||
reflection_count += 1
|
||||
messages.extend([
|
||||
{"role": "assistant", "content": response_text},
|
||||
{"role": "user", "content": reflection_prompt},
|
||||
{"role": "assistant", "content": reflection_text},
|
||||
{"role": "user", "content": "Now regenerate your response using the reflection you made"}
|
||||
])
|
||||
|
||||
# Get new response after reflection
|
||||
if verbose:
|
||||
with Live(display_generating("", time.time()), console=console, refresh_per_second=4) as live:
|
||||
response_text = ""
|
||||
for chunk in litellm.completion(
|
||||
**self._build_completion_params(
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
stream=True,
|
||||
**kwargs
|
||||
)
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
content = chunk.choices[0].delta.content
|
||||
response_text += content
|
||||
live.update(display_generating(response_text, time.time()))
|
||||
else:
|
||||
response_text = ""
|
||||
for chunk in litellm.completion(
|
||||
**self._build_completion_params(
|
||||
messages=messages,
|
||||
temperature=temperature,
|
||||
stream=True,
|
||||
**kwargs
|
||||
)
|
||||
):
|
||||
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
||||
response_text += chunk.choices[0].delta.content
|
||||
|
||||
response_text = response_text.strip()
|
||||
continue
|
||||
|
||||
except json.JSONDecodeError:
|
||||
reflection_count += 1
|
||||
if reflection_count >= max_reflect:
|
||||
if verbose:
|
||||
display_interaction(prompt, response_text, markdown=markdown,
|
||||
generation_time=time.time() - start_time, console=console)
|
||||
return response_text
|
||||
continue
|
||||
except Exception as e:
|
||||
display_error(f"Error in LLM response: {str(e)}")
|
||||
return None
|
||||
|
||||
# If we've exhausted reflection attempts
|
||||
if verbose:
|
||||
display_interaction(prompt, response_text, markdown=markdown,
|
||||
generation_time=time.time() - start_time, console=console)
|
||||
return response_text
|
||||
|
||||
except Exception as error:
|
||||
display_error(f"Error in get_response: {str(error)}")
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "praisonaiagents"
|
||||
version = "0.0.98"
|
||||
version = "0.0.99"
|
||||
description = "Praison AI agents for completing complex tasks with Self Reflection Agents"
|
||||
requires-python = ">=3.10"
|
||||
authors = [
|
||||
|
||||
@@ -4,7 +4,7 @@ import os
|
||||
sequential_agent = Agent(
|
||||
instructions="""You are a helpful assistant that can break down complex problems.
|
||||
Use the available tools when relevant to perform step-by-step analysis.""",
|
||||
llm="openai/gpt-4o-mini",
|
||||
llm="gpt-4o-mini",
|
||||
tools=MCP("npx -y @modelcontextprotocol/server-sequential-thinking")
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
from praisonaiagents import Agent, MCP
|
||||
import os
|
||||
|
||||
sequential_agent = Agent(
|
||||
instructions="""You are a helpful assistant that can break down complex problems.
|
||||
Use the available tools when relevant to perform step-by-step analysis.""",
|
||||
llm="openai/gpt-4o-mini",
|
||||
tools=MCP("npx -y @modelcontextprotocol/server-sequential-thinking")
|
||||
)
|
||||
|
||||
sequential_agent.start("Break down the process of making a cup of tea")
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from praisonaiagents import Agent, MCP
|
||||
import os
|
||||
|
||||
def test_agent_direct():
|
||||
"""Test using gpt-4o-mini directly (agent.py path)"""
|
||||
print("="*50)
|
||||
print("Testing gpt-4o-mini (agent.py path)")
|
||||
print("="*50)
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a helpful assistant that can break down complex problems.",
|
||||
llm="gpt-4o-mini",
|
||||
tools=MCP("npx -y @modelcontextprotocol/server-sequential-thinking")
|
||||
)
|
||||
|
||||
result = agent.start("What are 5 steps to make coffee?")
|
||||
print("✅ Agent direct path completed successfully")
|
||||
return result
|
||||
|
||||
def test_llm_class():
|
||||
"""Test using openai/gpt-4o-mini (llm.py path)"""
|
||||
print("\n" + "="*50)
|
||||
print("Testing openai/gpt-4o-mini (llm.py path)")
|
||||
print("="*50)
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a helpful assistant that can break down complex problems.",
|
||||
llm="openai/gpt-4o-mini",
|
||||
tools=MCP("npx -y @modelcontextprotocol/server-sequential-thinking")
|
||||
)
|
||||
|
||||
result = agent.start("What are 5 steps to make coffee?")
|
||||
print("✅ LLM class path completed successfully")
|
||||
return result
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
# Test both approaches
|
||||
result1 = test_agent_direct()
|
||||
result2 = test_llm_class()
|
||||
|
||||
print("\n" + "="*50)
|
||||
print("SUMMARY")
|
||||
print("="*50)
|
||||
print("✅ Both formats work correctly!")
|
||||
print("✅ gpt-4o-mini uses agent.py direct OpenAI calls")
|
||||
print("✅ openai/gpt-4o-mini uses llm.py LiteLLM wrapper")
|
||||
print("✅ Both support tool calling and MCP integration")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error occurred: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Test self-reflection functionality in both Agent and LLM classes"""
|
||||
|
||||
from praisonaiagents import Agent
|
||||
from praisonaiagents.llm import LLM
|
||||
|
||||
def test_agent_self_reflection():
|
||||
"""Test self-reflection in Agent class"""
|
||||
print("=== Testing Agent Self-Reflection ===")
|
||||
agent = Agent(
|
||||
name="ReflectiveAgent",
|
||||
instructions="You are a helpful assistant.",
|
||||
llm="gpt-4o-mini",
|
||||
self_reflect=True,
|
||||
min_reflect=1,
|
||||
max_reflect=3
|
||||
)
|
||||
|
||||
response = agent.start("What is 2+2? Be brief.")
|
||||
print(f"Agent Response: {response}")
|
||||
print()
|
||||
|
||||
def test_llm_self_reflection():
|
||||
"""Test self-reflection in LLM class directly"""
|
||||
print("=== Testing LLM Self-Reflection ===")
|
||||
llm = LLM(model="gpt-4o-mini")
|
||||
|
||||
response = llm.get_response(
|
||||
prompt="What is 2+2? Be brief.",
|
||||
system_prompt="You are a helpful assistant.",
|
||||
self_reflect=True,
|
||||
min_reflect=1,
|
||||
max_reflect=3,
|
||||
verbose=True
|
||||
)
|
||||
print(f"LLM Response: {response}")
|
||||
print()
|
||||
|
||||
def test_llm_no_reflection():
|
||||
"""Test LLM without self-reflection for comparison"""
|
||||
print("=== Testing LLM Without Self-Reflection ===")
|
||||
llm = LLM(model="gpt-4o-mini")
|
||||
|
||||
response = llm.get_response(
|
||||
prompt="What is 2+2? Be brief.",
|
||||
system_prompt="You are a helpful assistant.",
|
||||
self_reflect=False,
|
||||
verbose=True
|
||||
)
|
||||
print(f"LLM Response: {response}")
|
||||
print()
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Test without reflection first
|
||||
test_llm_no_reflection()
|
||||
|
||||
# Test with reflection
|
||||
test_llm_self_reflection()
|
||||
|
||||
# Test agent reflection
|
||||
test_agent_self_reflection()
|
||||
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from praisonaiagents import Agent, MCP
|
||||
import os
|
||||
|
||||
def test_agent_direct():
|
||||
"""Test using gpt-4o-mini directly (agent.py path)"""
|
||||
print("=" * 50)
|
||||
print("Testing gpt-4o-mini (agent.py path)")
|
||||
print("=" * 50)
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a helpful assistant that can break down complex problems.",
|
||||
llm="gpt-4o-mini",
|
||||
tools=MCP("npx -y @modelcontextprotocol/server-sequential-thinking")
|
||||
)
|
||||
|
||||
result = agent.start("What are 3 steps to make coffee?")
|
||||
print("✅ Agent direct path completed successfully")
|
||||
return result
|
||||
|
||||
def test_llm_class():
|
||||
"""Test using openai/gpt-4o-mini (llm.py path)"""
|
||||
print("\n" + "=" * 50)
|
||||
print("Testing openai/gpt-4o-mini (llm.py path)")
|
||||
print("=" * 50)
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a helpful assistant that can break down complex problems.",
|
||||
llm="openai/gpt-4o-mini",
|
||||
tools=MCP("npx -y @modelcontextprotocol/server-sequential-thinking")
|
||||
)
|
||||
|
||||
result = agent.start("What are 3 steps to make coffee?")
|
||||
print("✅ LLM class path completed successfully")
|
||||
return result
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
# Test both approaches
|
||||
result1 = test_agent_direct()
|
||||
result2 = test_llm_class()
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print("SUMMARY")
|
||||
print("=" * 50)
|
||||
print("✅ Both formats work correctly!")
|
||||
print("✅ gpt-4o-mini uses agent.py direct OpenAI calls")
|
||||
print("✅ openai/gpt-4o-mini uses llm.py LiteLLM wrapper")
|
||||
print("✅ Both support sequential tool calling and MCP integration")
|
||||
print("✅ Sequential thinking tool works properly in both modes")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error occurred: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
Generated
+2052
-2054
File diff suppressed because it is too large.
Load diff
@@ -3,8 +3,8 @@ class Praisonai < Formula
|
||||
|
||||
desc "AI tools for various AI applications"
|
||||
homepage "https://github.com/MervinPraison/PraisonAI"
|
||||
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.2.27.tar.gz"
|
||||
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.2.27.tar.gz | shasum -a 256`.split.first
|
||||
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.2.28.tar.gz"
|
||||
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.2.28.tar.gz | shasum -a 256`.split.first
|
||||
license "MIT"
|
||||
|
||||
depends_on "[email protected]"
|
||||
|
||||
@@ -56,7 +56,7 @@ class CloudDeployer:
|
||||
file.write("FROM python:3.11-slim\n")
|
||||
file.write("WORKDIR /app\n")
|
||||
file.write("COPY . .\n")
|
||||
file.write("RUN pip install flask praisonai==2.2.27 gunicorn markdown\n")
|
||||
file.write("RUN pip install flask praisonai==2.2.28 gunicorn markdown\n")
|
||||
file.write("EXPOSE 8080\n")
|
||||
file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "PraisonAI"
|
||||
version = "2.2.27"
|
||||
version = "2.2.28"
|
||||
description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration."
|
||||
readme = "README.md"
|
||||
license = ""
|
||||
@@ -12,7 +12,7 @@ dependencies = [
|
||||
"rich>=13.7",
|
||||
"markdown>=3.5",
|
||||
"pyparsing>=3.0.0",
|
||||
"praisonaiagents>=0.0.97",
|
||||
"praisonaiagents>=0.0.99",
|
||||
"python-dotenv>=0.19.0",
|
||||
"instructor>=1.3.3",
|
||||
"PyYAML>=6.0",
|
||||
@@ -95,7 +95,7 @@ autogen = ["pyautogen>=0.2.19", "praisonai-tools>=0.0.15", "crewai"]
|
||||
|
||||
[tool.poetry]
|
||||
name = "PraisonAI"
|
||||
version = "2.2.27"
|
||||
version = "2.2.28"
|
||||
description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration."
|
||||
authors = ["Mervin Praison"]
|
||||
license = ""
|
||||
@@ -113,7 +113,7 @@ python = ">=3.10,<3.13"
|
||||
rich = ">=13.7"
|
||||
markdown = ">=3.5"
|
||||
pyparsing = ">=3.0.0"
|
||||
praisonaiagents = ">=0.0.97"
|
||||
praisonaiagents = ">=0.0.99"
|
||||
python-dotenv = ">=0.19.0"
|
||||
instructor = ">=1.3.3"
|
||||
PyYAML = ">=6.0"
|
||||
|
||||
Generated
+2582
-2584
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user