Compare commits

...
4 Commits
Author SHA1 Message Date
Mervin Praison faa014b8b0 Merge pull request #333 from MervinPraison/develop
2.0.59
2025-01-24 17:17:53 +00:00
MervinPraison 6d454d0c6e Update PraisonAI to version 2.0.59 and enhance dependencies
- Bumped PraisonAI version from 2.0.58 to 2.0.59 in `Dockerfile`, `pyproject.toml`, and `uv.lock` to reflect the latest updates.
- Updated the `praisonaiagents` dependency version from `0.0.53` to `0.0.56` across relevant files for improved functionality.
- Modified agent task descriptions in `repetitive-agents.py` to clarify expected outputs.
- Enhanced the `process.py` file to improve task handling and expected output management.

These changes aim to refine the PraisonAI framework's capabilities and ensure compatibility with the latest dependencies.
2025-01-24 17:17:32 +00:00
MervinPraison 0ec3fe3510 Add new agent scripts and update version to 0.0.55
- Introduced three new Python scripts: `deepseek-reasoning-output-tokens.py`, `llm-deepseek-reasoning-steps.py`, and `llm-langchain-toolcall.py` to enhance reasoning capabilities and multi-source information retrieval.
- Updated `pyproject.toml` and `uv.lock` to reflect the new version 0.0.55.
- Enhanced `wikipedia-agent.py` to utilize the new `gpt-4o-mini` model for improved performance.
- Improved `agent.py` to support tool calls in chat completions, refining the overall functionality of the agent framework.

These changes aim to expand the capabilities of the PraisonAI framework by integrating new reasoning features and improving user experience with updated versioning.
2025-01-24 13:04:34 +00:00
MervinPraison 707888cdf9 Remove deprecated agent scripts and update version to 0.0.54
- Deleted `any-llm-agents.py` and `any-llm-agents-advanced.py` scripts to streamline the agent framework.
- Updated `pyproject.toml` and `uv.lock` to reflect the new version 0.0.54.
- Enhanced `agent.py` and `llm.py` to improve handling of reasoning steps by ensuring `reasoning_steps` is properly managed in API calls.

These changes aim to simplify the agent framework and improve the overall functionality of the PraisonAI system.
2025-01-24 10:35:42 +00:00
18 changed files with 279 additions and 138 deletions

No files matched your search

@@ -0,0 +1,19 @@
from praisonaiagents import Agent, Task, PraisonAIAgents
llm_config = {
"model": "deepseek/deepseek-reasoner",
"max_tokens": 1
}
reasoning_agent = Agent(role="Helpful Assistant", llm=llm_config, reasoning_steps=True)
small_agent = Agent(role="Helpful Assistant", llm="openai/gpt-3.5-turbo")
reasoning_task = Task(description="How many r's in the word 'Strawberry'?", agent=reasoning_agent)
small_task = Task(description="With the provided reasoning tell me how many r's in the word 'Strawberry'?", agent=small_agent)
agents = PraisonAIAgents(
agents=[reasoning_agent, small_agent],
tasks=[reasoning_task, small_task]
)
agents.start()
+14
View File
@@ -0,0 +1,14 @@
from praisonaiagents import Agent, Task, PraisonAIAgents
reasoning_agent = Agent(role="Helpful Assistant", reasoning_steps=True, llm="deepseek/deepseek-reasoner")
small_agent = Agent(role="Helpful Assistant", llm="openai/gpt-3.5-turbo")
reasoning_task = Task(description="How many r's in the word 'Strawberry'?", agent=reasoning_agent)
small_task = Task(description="With the provided reasoning tell me how many r's in the word 'Strawberry'?", agent=small_agent)
agents = PraisonAIAgents(
agents=[reasoning_agent, small_agent],
tasks=[reasoning_task, small_task]
)
agents.start()
File renamed without changes.
File renamed without changes.
+30
View File
@@ -0,0 +1,30 @@
from praisonaiagents import Agent, Task, PraisonAIAgents
from langchain_community.tools import YouTubeSearchTool
from langchain_community.utilities import WikipediaAPIWrapper
# Create an agent with both tools
agent = Agent(
name="SearchAgent",
role="Research Assistant",
goal="Search for information from multiple sources",
backstory="I am an AI assistant that can search YouTube and Wikipedia.",
tools=[YouTubeSearchTool, WikipediaAPIWrapper],
llm="openai/gpt-4o-mini"
)
# Create tasks to demonstrate both tools
task = Task(
name="search_task",
description="Search for information about 'AI advancements' on both YouTube and Wikipedia",
expected_output="Combined information from YouTube videos and Wikipedia articles",
agent=agent
)
# Create and start the workflow
agents = PraisonAIAgents(
agents=[agent],
tasks=[task],
verbose=True
)
agents.start()
+172 -103
View File
@@ -97,36 +97,79 @@ def process_stream_chunks(chunks):
content_list = []
reasoning_list = []
tool_calls = []
current_tool_call = None
# First pass: Get initial tool call data
for chunk in chunks:
if not hasattr(chunk, "choices") or not chunk.choices:
continue
# Track usage from each chunk
if hasattr(chunk, "usage"):
completion_tokens += getattr(chunk.usage, "completion_tokens", 0)
prompt_tokens += getattr(chunk.usage, "prompt_tokens", 0)
delta = getattr(chunk.choices[0], "delta", None)
if not delta:
continue
# Handle content and reasoning
if hasattr(delta, "content") and delta.content:
content_list.append(delta.content)
if hasattr(delta, "reasoning_content") and delta.reasoning_content:
reasoning_list.append(delta.reasoning_content)
# Handle tool calls
if hasattr(delta, "tool_calls") and delta.tool_calls:
for tool_call_delta in delta.tool_calls:
if tool_call_delta.index is not None and tool_call_delta.id:
# Found the initial tool call
current_tool_call = {
"id": tool_call_delta.id,
"type": "function",
"function": {
"name": tool_call_delta.function.name,
"arguments": ""
}
}
while len(tool_calls) <= tool_call_delta.index:
tool_calls.append(None)
tool_calls[tool_call_delta.index] = current_tool_call
current_tool_call = tool_calls[tool_call_delta.index]
elif current_tool_call is not None and hasattr(tool_call_delta.function, "arguments"):
if tool_call_delta.function.arguments:
current_tool_call["function"]["arguments"] += tool_call_delta.function.arguments
# Remove any None values and empty tool calls
tool_calls = [tc for tc in tool_calls if tc and tc["id"] and tc["function"]["name"]]
combined_content = "".join(content_list) if content_list else ""
combined_reasoning = "".join(reasoning_list) if reasoning_list else None
finish_reason = getattr(last_chunk.choices[0], "finish_reason", None) if hasattr(last_chunk, "choices") and last_chunk.choices else None
# Create ToolCall objects
processed_tool_calls = []
if tool_calls:
try:
from openai.types.chat import ChatCompletionMessageToolCall
for tc in tool_calls:
tool_call = ChatCompletionMessageToolCall(
id=tc["id"],
type=tc["type"],
function={
"name": tc["function"]["name"],
"arguments": tc["function"]["arguments"]
}
)
processed_tool_calls.append(tool_call)
except Exception as e:
print(f"Error processing tool call: {e}")
message = ChatCompletionMessage(
content=combined_content,
reasoning_content=combined_reasoning
role="assistant",
reasoning_content=combined_reasoning,
tool_calls=processed_tool_calls if processed_tool_calls else None
)
choice = Choice(
finish_reason=finish_reason,
finish_reason=finish_reason or "tool_calls" if processed_tool_calls else None,
index=0,
message=message
)
@@ -528,6 +571,53 @@ Your Goal: {self.goal}
def __str__(self):
return f"Agent(name='{self.name}', role='{self.role}', goal='{self.goal}')"
def _process_stream_response(self, messages, temperature, start_time, formatted_tools=None, reasoning_steps=False):
"""Process streaming response and return final response"""
try:
# Create the response stream
response_stream = client.chat.completions.create(
model=self.llm,
messages=messages,
temperature=temperature,
tools=formatted_tools if formatted_tools else None,
stream=True
)
full_response_text = ""
reasoning_content = ""
chunks = []
# Create Live display with proper configuration
with Live(
display_generating("", start_time),
console=self.console,
refresh_per_second=4,
transient=True,
vertical_overflow="ellipsis",
auto_refresh=True
) as live:
for chunk in response_stream:
chunks.append(chunk)
if chunk.choices[0].delta.content:
full_response_text += chunk.choices[0].delta.content
live.update(display_generating(full_response_text, start_time))
# Update live display with reasoning content if enabled
if reasoning_steps and hasattr(chunk.choices[0].delta, "reasoning_content"):
rc = chunk.choices[0].delta.reasoning_content
if rc:
reasoning_content += rc
live.update(display_generating(f"{full_response_text}\n[Reasoning: {reasoning_content}]", start_time))
# Clear the last generating display with a blank line
self.console.print()
final_response = process_stream_chunks(chunks)
return final_response
except Exception as e:
display_error(f"Error in stream processing: {e}")
return None
def _chat_completion(self, messages, temperature=0.2, tools=None, stream=True, reasoning_steps=False):
start_time = time.time()
logging.debug(f"{self.name} sending messages to LLM: {messages}")
@@ -554,20 +644,31 @@ Your Goal: {self.goal}
logging.warning(f"Tool {tool} not recognized")
try:
initial_response = client.chat.completions.create(
model=self.llm,
messages=messages,
temperature=temperature,
tools=formatted_tools if formatted_tools else None,
stream=False
)
if stream:
# Process as streaming response with formatted tools
final_response = self._process_stream_response(
messages,
temperature,
start_time,
formatted_tools=formatted_tools if formatted_tools else None,
reasoning_steps=reasoning_steps
)
else:
# Process as regular non-streaming response
final_response = client.chat.completions.create(
model=self.llm,
messages=messages,
temperature=temperature,
tools=formatted_tools if formatted_tools else None,
stream=False
)
tool_calls = getattr(initial_response.choices[0].message, 'tool_calls', None)
tool_calls = getattr(final_response.choices[0].message, 'tool_calls', None)
if tool_calls:
messages.append({
"role": "assistant",
"content": initial_response.choices[0].message.content,
"role": "assistant",
"content": final_response.choices[0].message.content,
"tool_calls": tool_calls
})
@@ -590,55 +691,24 @@ Your Goal: {self.goal}
"content": results_str
})
if stream:
response_stream = client.chat.completions.create(
model=self.llm,
messages=messages,
temperature=temperature,
stream=True
)
full_response_text = ""
reasoning_content = ""
chunks = []
# Create Live display with proper configuration
with Live(
display_generating("", start_time),
console=self.console,
refresh_per_second=4,
transient=True,
vertical_overflow="ellipsis",
auto_refresh=True
) as live:
for chunk in response_stream:
chunks.append(chunk)
if chunk.choices[0].delta.content:
full_response_text += chunk.choices[0].delta.content
live.update(display_generating(full_response_text, start_time))
# Update live display with reasoning content if enabled
if reasoning_steps and hasattr(chunk.choices[0].delta, "reasoning_content"):
rc = chunk.choices[0].delta.reasoning_content
if rc:
reasoning_content += rc
live.update(display_generating(f"{full_response_text}\n[Reasoning: {reasoning_content}]", start_time))
# Clear the last generating display with a blank line
self.console.print()
final_response = process_stream_chunks(chunks)
return final_response
else:
if tool_calls:
# Get final response after tool calls
if stream:
final_response = self._process_stream_response(
messages,
temperature,
start_time,
formatted_tools=formatted_tools if formatted_tools else None,
reasoning_steps=reasoning_steps
)
else:
final_response = client.chat.completions.create(
model=self.llm,
messages=messages,
temperature=temperature,
stream=False
)
return final_response
else:
return initial_response
return final_response
except Exception as e:
display_error(f"Error in chat completion: {e}")
@@ -758,8 +828,7 @@ Your Goal: {self.goal}
tool_calls = getattr(response.choices[0].message, 'tool_calls', None)
response_text = response.choices[0].message.content.strip()
if tool_calls:
if tool_calls: ## TODO: Most likely this tool call is already called in _chat_completion, so maybe we can remove this.
messages.append({
"role": "assistant",
"content": response_text,
@@ -988,48 +1057,48 @@ Your Goal: {self.goal}
)
# Format tools if provided
formatted_tools = []
if tools:
for tool in tools:
if isinstance(tool, str):
tool_def = self._generate_tool_definition(tool)
if tool_def:
formatted_tools.append(tool_def)
elif isinstance(tool, dict):
formatted_tools.append(tool)
elif hasattr(tool, "to_openai_tool"):
formatted_tools.append(tool.to_openai_tool())
elif callable(tool):
formatted_tools.append(self._generate_tool_definition(tool.__name__))
formatted_tools = []
if tools:
for tool in tools:
if isinstance(tool, str):
tool_def = self._generate_tool_definition(tool)
if tool_def:
formatted_tools.append(tool_def)
elif isinstance(tool, dict):
formatted_tools.append(tool)
elif hasattr(tool, "to_openai_tool"):
formatted_tools.append(tool.to_openai_tool())
elif callable(tool):
formatted_tools.append(self._generate_tool_definition(tool.__name__))
# Create async OpenAI client
async_client = AsyncOpenAI()
# Create async OpenAI client
async_client = AsyncOpenAI()
# Make the API call based on the type of request
if tools:
response = await async_client.chat.completions.create(
model=self.llm,
messages=messages,
temperature=temperature,
tools=formatted_tools
)
return await self._achat_completion(response, tools)
elif output_json or output_pydantic:
response = await async_client.chat.completions.create(
model=self.llm,
messages=messages,
temperature=temperature,
response_format={"type": "json_object"}
)
# Return the raw response
return response.choices[0].message.content
else:
response = await async_client.chat.completions.create(
model=self.llm,
messages=messages,
temperature=temperature
)
return response.choices[0].message.content
# Make the API call based on the type of request
if tools:
response = await async_client.chat.completions.create(
model=self.llm,
messages=messages,
temperature=temperature,
tools=formatted_tools
)
return await self._achat_completion(response, tools)
elif output_json or output_pydantic:
response = await async_client.chat.completions.create(
model=self.llm,
messages=messages,
temperature=temperature,
response_format={"type": "json_object"}
)
# Return the raw response
return response.choices[0].message.content
else:
response = await async_client.chat.completions.create(
model=self.llm,
messages=messages,
temperature=temperature
)
return response.choices[0].message.content
except Exception as e:
display_error(f"Error in chat completion: {e}")
return None
+18 -15
View File
@@ -17,6 +17,8 @@ from ..main import (
from rich.console import Console
from rich.live import Live
# TODO: Include in-build tool calling in LLM class
# TODO: Restructure so that duplicate calls are not made (Sync with agent.py)
class LLMContextLengthExceededException(Exception):
"""Raised when LLM context length is exceeded"""
def __init__(self, message: str):
@@ -178,7 +180,8 @@ class LLM:
"""Enhanced get_response with all OpenAI-like features"""
try:
import litellm
reasoning_steps = kwargs.get('reasoning_steps', self.reasoning_steps)
# This below **kwargs** is passed to .completion() directly. so reasoning_steps has to be popped. OR find alternate best way of handling this.
reasoning_steps = kwargs.pop('reasoning_steps', self.reasoning_steps)
# Disable litellm debug messages
litellm.set_verbose = False
@@ -240,7 +243,7 @@ class LLM:
messages=messages,
temperature=temperature,
stream=False, # force non-streaming
**kwargs
**{k:v for k,v in kwargs.items() if k != 'reasoning_steps'}
)
reasoning_content = resp["choices"][0]["message"].get("provider_specific_fields", {}).get("reasoning_content")
response_text = resp["choices"][0]["message"]["content"]
@@ -344,7 +347,7 @@ class LLM:
messages=messages,
temperature=temperature,
stream=False, # force non-streaming
**kwargs
**{k:v for k,v in kwargs.items() if k != 'reasoning_steps'}
)
reasoning_content = resp["choices"][0]["message"].get("provider_specific_fields", {}).get("reasoning_content")
response_text = resp["choices"][0]["message"]["content"]
@@ -435,7 +438,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
temperature=temperature,
stream=False, # Force non-streaming
response_format={"type": "json_object"},
**kwargs
**{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")
@@ -469,7 +472,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
temperature=temperature,
stream=True,
response_format={"type": "json_object"},
**kwargs
**{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
@@ -483,7 +486,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
temperature=temperature,
stream=True,
response_format={"type": "json_object"},
**kwargs
**{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
@@ -557,7 +560,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
"""Async version of get_response with identical functionality."""
try:
import litellm
reasoning_steps = kwargs.get('reasoning_steps', self.reasoning_steps)
reasoning_steps = kwargs.pop('reasoning_steps', self.reasoning_steps)
litellm.set_verbose = False
# Build messages list
@@ -669,7 +672,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
messages=messages,
temperature=temperature,
stream=False, # force non-streaming
**kwargs
**{k:v for k,v in kwargs.items() if k != 'reasoning_steps'}
)
reasoning_content = resp["choices"][0]["message"].get("provider_specific_fields", {}).get("reasoning_content")
response_text = resp["choices"][0]["message"]["content"]
@@ -731,7 +734,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
temperature=temperature,
stream=False,
tools=formatted_tools, # We safely pass tools here
**kwargs
**{k:v for k,v in kwargs.items() if k != 'reasoning_steps'}
)
# handle tool_calls from tool_response as usual...
tool_calls = tool_response.choices[0].message.get("tool_calls")
@@ -777,7 +780,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
temperature=temperature,
stream=False, # force non-streaming
tools=formatted_tools, # Include tools
**kwargs
**{k:v for k,v in kwargs.items() if k != 'reasoning_steps'}
)
reasoning_content = resp["choices"][0]["message"].get("provider_specific_fields", {}).get("reasoning_content")
response_text = resp["choices"][0]["message"]["content"]
@@ -807,7 +810,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
temperature=temperature,
stream=True,
tools=formatted_tools,
**kwargs
**{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
@@ -821,7 +824,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
messages=messages,
temperature=temperature,
stream=True,
**kwargs
**{k:v for k,v in kwargs.items() if k != 'reasoning_steps'}
):
if chunk and chunk.choices and chunk.choices[0].delta.content:
response_text += chunk.choices[0].delta.content
@@ -867,7 +870,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
temperature=temperature,
stream=False, # Force non-streaming
response_format={"type": "json_object"},
**kwargs
**{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")
@@ -901,7 +904,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
temperature=temperature,
stream=True,
response_format={"type": "json_object"},
**kwargs
**{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
@@ -915,7 +918,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
temperature=temperature,
stream=True,
response_format={"type": "json_object"},
**kwargs
**{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
+8 -4
View File
@@ -44,6 +44,8 @@ class Process:
current_task = start_task
visited_tasks = set()
loop_data = {} # Store loop-specific data
# TODO: start task with loop feature is not available in aworkflow method
while current_task:
current_iter += 1
@@ -350,9 +352,10 @@ Provide a JSON with the structure:
if row: # Skip empty rows
task_desc = row[0] # Take first column
row_task = Task(
description=task_desc, # Keep full row as description
description=f"{start_task.description}\n{task_desc}" if start_task.description else task_desc,
agent=start_task.agent,
name=task_desc, # Use first column as name
name=f"{start_task.name}_{i+1}" if start_task.name else task_desc,
expected_output=getattr(start_task, 'expected_output', None),
is_start=(i == 0),
task_type="task",
condition={
@@ -374,9 +377,10 @@ Provide a JSON with the structure:
previous_task = None
for i, line in enumerate(lines):
row_task = Task(
description=line.strip(),
description=f"{start_task.description}\n{line.strip()}" if start_task.description else line.strip(),
agent=start_task.agent,
name=line.strip(),
name=f"{start_task.name}_{i+1}" if start_task.name else line.strip(),
expected_output=getattr(start_task, 'expected_output', None),
is_start=(i == 0),
task_type="task",
condition={
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "praisonaiagents"
version = "0.0.53"
version = "0.0.56"
description = "Praison AI agents for completing complex tasks with Self Reflection Agents"
authors = [
{ name="Mervin Praison" }
+2 -1
View File
@@ -6,7 +6,8 @@ agent = Agent(
)
task = Task(
description="Create the list of tasks to be looped through.",
description="complete the task",
expected_output="task completed",
agent=agent,
task_type="loop",
input_file="tasks.csv"
+1 -1
View File
@@ -1868,7 +1868,7 @@ wheels = [
[[package]]
name = "praisonaiagents"
version = "0.0.53"
version = "0.0.56"
source = { editable = "." }
dependencies = [
{ name = "openai" },
+1
View File
@@ -7,6 +7,7 @@ agent = Agent(
self_reflect=True,
min_reflect=3,
max_reflect=5,
llm="gpt-4o-mini"
)
agent.start(
"What is the history of AI?"
+1 -1
View File
@@ -1,6 +1,6 @@
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install flask praisonai==2.0.58 gunicorn markdown
RUN pip install flask praisonai==2.0.59 gunicorn markdown
EXPOSE 8080
CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]
+1 -1
View File
@@ -110,7 +110,7 @@ Loads environment variables from .env file or system and sets them.</p>
file.write(&#34;FROM python:3.11-slim\n&#34;)
file.write(&#34;WORKDIR /app\n&#34;)
file.write(&#34;COPY . .\n&#34;)
file.write(&#34;RUN pip install flask praisonai==2.0.58 gunicorn markdown\n&#34;)
file.write(&#34;RUN pip install flask praisonai==2.0.59 gunicorn markdown\n&#34;)
file.write(&#34;EXPOSE 8080\n&#34;)
file.write(&#39;CMD [&#34;gunicorn&#34;, &#34;-b&#34;, &#34;0.0.0.0:8080&#34;, &#34;api:app&#34;]\n&#39;)
+1 -1
View File
@@ -3,7 +3,7 @@ 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/2.0.58.tar.gz"
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/2.0.59.tar.gz"
sha256 "1828fb9227d10f991522c3f24f061943a254b667196b40b1a3e4a54a8d30ce32" # Replace with actual SHA256 checksum
license "MIT"
+1 -1
View File
@@ -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.0.58 gunicorn markdown\n")
file.write("RUN pip install flask praisonai==2.0.59 gunicorn markdown\n")
file.write("EXPOSE 8080\n")
file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
+4 -4
View File
@@ -1,6 +1,6 @@
[project]
name = "PraisonAI"
version = "2.0.58"
version = "2.0.59"
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.53",
"praisonaiagents>=0.0.56",
"python-dotenv>=0.19.0",
"instructor>=1.3.3",
"PyYAML>=6.0",
@@ -84,7 +84,7 @@ autogen = ["pyautogen>=0.2.19", "praisonai-tools>=0.0.7", "crewai"]
[tool.poetry]
name = "PraisonAI"
version = "2.0.58"
version = "2.0.59"
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 = ""
@@ -102,7 +102,7 @@ python = ">=3.10,<3.13"
rich = ">=13.7"
markdown = ">=3.5"
pyparsing = ">=3.0.0"
praisonaiagents = ">=0.0.53"
praisonaiagents = ">=0.0.56"
python-dotenv = ">=0.19.0"
instructor = ">=1.3.3"
PyYAML = ">=6.0"
Generated
+5 -5
View File
@@ -3060,7 +3060,7 @@ wheels = [
[[package]]
name = "praisonai"
version = "2.0.58"
version = "2.0.59"
source = { editable = "." }
dependencies = [
{ name = "instructor" },
@@ -3197,7 +3197,7 @@ requires-dist = [
{ name = "plotly", marker = "extra == 'realtime'", specifier = ">=5.24.0" },
{ name = "praisonai-tools", marker = "extra == 'autogen'", specifier = ">=0.0.7" },
{ name = "praisonai-tools", marker = "extra == 'crewai'", specifier = ">=0.0.7" },
{ name = "praisonaiagents", specifier = ">=0.0.53" },
{ name = "praisonaiagents", specifier = ">=0.0.56" },
{ name = "pyautogen", marker = "extra == 'autogen'", specifier = ">=0.2.19" },
{ name = "pydantic", marker = "extra == 'chat'", specifier = "<=2.10.1" },
{ name = "pydantic", marker = "extra == 'code'", specifier = "<=2.10.1" },
@@ -3250,16 +3250,16 @@ wheels = [
[[package]]
name = "praisonaiagents"
version = "0.0.53"
version = "0.0.56"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "openai" },
{ name = "pydantic" },
{ name = "rich" },
]
sdist = { url = "https://files.pythonhosted.org/packages/48/7c/c8070c6eb7fcabe22aac9a6b92f72cfcd5a04d02e8f7bcff0e42f62eb31f/praisonaiagents-0.0.53.tar.gz", hash = "sha256:02a8220977776c8a1574b160f3e12b90ac98adc9b3925773e9867c117e10e6f9", size = 87386 }
sdist = { url = "https://files.pythonhosted.org/packages/1f/d0/5b3ee6832c4797cb6dd47496485789e13113014d501856c2b5b286e7108c/praisonaiagents-0.0.56.tar.gz", hash = "sha256:148b6400403a7ad05b105084640e7140799e4e3bfb23a844bb79e10ea98bf859", size = 88236 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/56/9b/0f9f2b146877d5b830173981030c1acb82d10ce719b27af085900c2c4763/praisonaiagents-0.0.53-py3-none-any.whl", hash = "sha256:dd7a08cba8dc283136e7f94111f0ced95f172a8a3d9fcdf64dda6f4f1521d7ff", size = 105546 },
{ url = "https://files.pythonhosted.org/packages/1a/7e/1da42b51510d3bef28f4d450824d7d14fdd2358981adf7c5b8251e586526/praisonaiagents-0.0.56-py3-none-any.whl", hash = "sha256:b198c60a8909c39b2ced09e0c7cc1ad6224af15b8c743f6890ef3985fae4d036", size = 106340 },
]
[[package]]