Compare commits

...
5 Commits
Author SHA1 Message Date
Mervin Praison f49ad9fbc2 Merge pull request #306 from MervinPraison/develop
Develop
2025-01-17 17:35:18 +00:00
MervinPraison c086c60fd6 Update PraisonAI to version 2.0.50 and enhance dependencies
- Bumped PraisonAI version from 2.0.49 to 2.0.50 in `Dockerfile`, `pyproject.toml`, and `uv.lock` to reflect the latest updates.
- Updated the `praisonai.rb` formula to point to the new version's tarball.
- Updated the `praisonaiagents` dependency version from `0.0.40` to `0.0.41` across relevant files for improved functionality.
- Added a new `context-agents.py` file to introduce a CV analysis agent with comprehensive evaluation capabilities.
- Modified deployment scripts to ensure compatibility with the updated package version.

These changes improve the overall functionality and usability of the PraisonAI framework, particularly in dependency management and the introduction of new agent capabilities.
2025-01-17 17:35:00 +00:00
MervinPraison 4f8f4f2036 Update package version to 0.0.41 in uv.lock
- Bumped the version of the PraisonAI agents package from 0.0.40 to 0.0.41 to reflect recent updates.
- This change ensures that the latest features and improvements are properly versioned and available for users.
2025-01-17 17:26:51 +00:00
MervinPraison 8e91c20967 Update package version to 0.0.41 in pyproject.toml
- Bumped the version of the PraisonAI agents package from 0.0.40 to 0.0.41 to reflect recent updates.
- This change ensures that the latest features and improvements are properly versioned and available for users.

These updates maintain the integrity of the PraisonAI framework and prepare it for future enhancements.
2025-01-17 17:26:34 +00:00
MervinPraison 6f092c1507 Refactor agent context handling and improve task prompt generation
- Updated `crewai-tools-example.py` to remove unnecessary whitespace.
- Modified `agent.py` to replace `schema_json()` with `model_json_schema()` for JSON output consistency.
- Enhanced context handling in `agents.py` to avoid duplicates and improve clarity in task prompts by using lists instead of strings.
- Added support for passing content to tasks in both `start` and `astart` methods, allowing for dynamic context management.
- Improved task prompt generation in `task.py` to handle various context types, ensuring better output formatting.

These changes enhance the functionality and usability of the PraisonAI agents, particularly in context management and task execution clarity.
2025-01-17 17:25:58 +00:00
16 changed files with 395 additions and 41 deletions

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install flask praisonai==2.0.49 gunicorn markdown
RUN pip install flask praisonai==2.0.50 gunicorn markdown
EXPOSE 8080
CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]
+53
View File
@@ -0,0 +1,53 @@
from praisonaiagents import Agent, Task, PraisonAIAgents
from pydantic import BaseModel
from typing import List, Dict
class CVAnalysisReport(BaseModel):
overall_score: int
key_strengths: List[str]
areas_for_improvement: List[str]
market_fit: str
recommendations: List[str]
technical_skills: List[str]
soft_skills: List[str]
skill_gaps: List[str]
key_achievements: List[str]
impact_metrics: List[Dict[str, str]]
areas_of_expertise: List[str]
# Create single CV analysis agent
cv_analyzer = Agent(
role="CV Analysis Expert",
goal="Provide comprehensive CV evaluation and recommendations",
backstory="""You are an expert CV analyst with deep knowledge of industry requirements,
market trends, and talent assessment. You excel at evaluating skills, experience,
and providing actionable recommendations.""",
verbose=True
)
# Single comprehensive analysis task
cv_analysis_task = Task(
description="""Analyze the CV comprehensively including:
1. Technical and soft skills assessment
2. Experience and achievements evaluation
3. Overall CV evaluation with recommendations
Provide detailed insights and actionable recommendations.""",
expected_output="Complete CV analysis report",
agent=cv_analyzer,
output_pydantic=CVAnalysisReport
)
# Create and run the agent
agents = PraisonAIAgents(
agents=[cv_analyzer],
tasks=[cv_analysis_task]
)
# Read and pass CV content through start()
with open('cv.txt', 'r') as file:
cv_content = file.read()
# Start the analysis by passing CV content
result = agents.start(cv_content)
print(result)
+61
View File
@@ -0,0 +1,61 @@
from praisonaiagents import Agent, Task, PraisonAIAgents
from pydantic import BaseModel
from typing import List, Dict
class CVAnalysisReport(BaseModel):
overall_score: int
key_strengths: List[str]
areas_for_improvement: List[str]
market_fit: str
recommendations: List[str]
technical_skills: List[str]
soft_skills: List[str]
skill_gaps: List[str]
key_achievements: List[str]
impact_metrics: List[Dict[str, str]]
areas_of_expertise: List[str]
# Create single CV analysis agent
cv_analyzer = Agent(
role="CV Analysis Expert",
goal="Provide comprehensive CV evaluation and recommendations",
backstory="""You are an expert CV analyst with deep knowledge of industry requirements,
market trends, and talent assessment. You excel at evaluating skills, experience,
and providing actionable recommendations.""",
verbose=True
)
# Read CV content first
with open('cv.txt', 'r') as file:
cv_content = file.read()
cv_key_strengths = Task(
description="List the key strengths to look",
expected_output="List of key strengths",
agent=cv_analyzer,
)
# Single comprehensive analysis task with CV content in context
cv_analysis_task = Task(
description="""Analyze the CV comprehensively including:
1. Technical and soft skills assessment
2. Experience and achievements evaluation
3. Overall CV evaluation with recommendations
Provide detailed insights and actionable recommendations.""",
expected_output="Complete CV analysis report",
agent=cv_analyzer,
output_pydantic=CVAnalysisReport,
context=[cv_content, cv_key_strengths] # Pass CV content directly in task context
)
# Create and run the agent
agents = PraisonAIAgents(
agents=[cv_analyzer],
tasks=[cv_key_strengths,cv_analysis_task],
process="sequential"
)
# Start the analysis - no need to pass content again since it's in task context
result = agents.start()
print(result)
-1
View File
@@ -23,6 +23,5 @@ agent = Agent(
)
# Run the agent
result = PraisonAIAgents(agents=[agent], verbose=10).start()
print(result)
+57
View File
@@ -0,0 +1,57 @@
Name: Alex Johnson
Location: London, UK
Professional Summary
Dynamic and results-oriented leader with a proven track record of driving innovation, scaling operations, and achieving transformational growth. Over 15 years of experience in engineering, strategic management, and executive leadership in the automotive and renewable energy sectors. Passionate about sustainable technologies and visionary leadership.
Professional Experience
Chief Operating Officer (COO)
NextGen Mobility Ltd. | Palo Alto, CA | 2020 – Present
Spearheaded global operations for an electric vehicle company, scaling production by 200% in three years.
Introduced automation-driven supply chain strategies, reducing costs by 15%.
Collaborated with R&D to launch three new EV models, driving 25% revenue growth annually.
Vice President of Engineering
ElectroDrive Systems | San Francisco, CA | 2015 – 2020
Led a team of 500+ engineers in developing next-generation EV batteries, achieving a 30% increase in energy efficiency.
Secured $50M in government funding for sustainable energy innovation.
Drove cross-functional collaboration, aligning product development with market needs.
Director of Renewable Energy Initiatives
GreenTech Innovations | London, UK | 2011 – 2015
Oversaw £100M projects in solar and wind energy deployment across Europe.
Established partnerships with policymakers to influence renewable energy legislation.
Pioneered a smart energy grid system, enhancing energy distribution efficiency by 40%.
Senior Project Manager
Innovate Auto Ltd. | Munich, Germany | 2008 – 2011
Managed R&D projects for autonomous driving technologies.
Delivered projects 20% under budget through strategic resource allocation.
Filed 10+ patents in automotive AI and renewable integration.
Mechanical Engineer
AutoFusion Technologies | Berlin, Germany | 2005 – 2008
Designed core systems for EV powertrains, optimising energy consumption by 15%.
Collaborated with suppliers to improve material efficiency, cutting costs by £5M annually.
Education
MBA in Strategic Management
Harvard Business School | Cambridge, MA | 2015
MSc in Renewable Energy Engineering
Imperial College London | London, UK | 2007
BSc in Mechanical Engineering
Technical University of Munich | Munich, Germany | 2005
Skills
Strategic Leadership & Visionary Thinking
Electric Vehicle Engineering
Renewable Energy Systems
Global Operations Management
Policy Advocacy & Government Relations
Supply Chain Optimisation
Achievements
Featured in Forbes 30 Under 40 for innovations in EV technology.
Author of The Future of Sustainable Mobility.
Keynote speaker at World Energy Summit, 2023.
+4 -4
View File
@@ -485,9 +485,9 @@ Your Role: {self.role}\n
Your Goal: {self.goal}
"""
if output_json:
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {output_json.schema_json()}"
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_json.model_json_schema())}"
elif output_pydantic:
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {output_pydantic.schema_json()}"
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_pydantic.model_json_schema())}"
else:
system_prompt = None
@@ -677,9 +677,9 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
# Build system prompt
system_prompt = self.system_prompt
if output_json:
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {output_json.schema_json()}"
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_json.model_json_schema())}"
elif output_pydantic:
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {output_pydantic.schema_json()}"
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {json.dumps(output_pydantic.model_json_schema())}"
# Build messages
if isinstance(prompt, str):
+66 -19
View File
@@ -229,15 +229,28 @@ You need to do the following task: {task.description}.
Expected Output: {task.expected_output}.
"""
if task.context:
context_results = ""
for context_task in task.context:
if context_task.result:
context_results += f"Result of previous task {context_task.name if context_task.name else context_task.description}: {context_task.result.raw}\n"
else:
context_results += f"Previous task {context_task.name if context_task.name else context_task.description} had no result.\n"
context_results = [] # Use list to avoid duplicates
for context_item in task.context:
if isinstance(context_item, str):
context_results.append(f"Input Content:\n{context_item}")
elif isinstance(context_item, list):
context_results.append(f"Input Content: {' '.join(str(x) for x in context_item)}")
elif hasattr(context_item, 'result'): # Task object
if context_item.result:
context_results.append(
f"Result of previous task {context_item.name if context_item.name else context_item.description}:\n{context_item.result.raw}"
)
else:
context_results.append(
f"Previous task {context_item.name if context_item.name else context_item.description} has no result yet."
)
# Join unique context results
unique_contexts = list(dict.fromkeys(context_results)) # Remove duplicates
task_prompt += f"""
Here are the results of previous tasks that might be useful:\n
{context_results}
Context:
{' '.join(unique_contexts)}
"""
task_prompt += "Please provide only the final result of your work. Do not add any conversation or extra explanation."
@@ -427,8 +440,16 @@ Here are the results of previous tasks that might be useful:\n
else:
self.run_task(task_id)
async def astart(self):
async def astart(self, content=None, **kwargs):
"""Async version of start method"""
if content:
# Add content to context of all tasks
for task in self.tasks.values():
if isinstance(content, (str, list)):
if not task.context:
task.context = []
task.context.append(content)
await self.arun_all_tasks()
return {
"task_status": self.get_all_tasks_status(),
@@ -485,16 +506,30 @@ You need to do the following task: {task.description}.
Expected Output: {task.expected_output}.
"""
if task.context:
context_results = ""
for context_task in task.context:
if context_task.result:
context_results += f"Result of previous task {context_task.name if context_task.name else context_task.description}: {context_task.result.raw}\n"
else:
context_results += f"Previous task {context_task.name if context_task.name else context_task.description} had no result.\n"
context_results = [] # Use list to avoid duplicates
for context_item in task.context:
if isinstance(context_item, str):
context_results.append(f"Input Content:\n{context_item}")
elif isinstance(context_item, list):
context_results.append(f"Input Content: {' '.join(str(x) for x in context_item)}")
elif hasattr(context_item, 'result'): # Task object
if context_item.result:
context_results.append(
f"Result of previous task {context_item.name if context_item.name else context_item.description}:\n{context_item.result.raw}"
)
else:
context_results.append(
f"Previous task {context_item.name if context_item.name else context_item.description} has no result yet."
)
# Join unique context results
unique_contexts = list(dict.fromkeys(context_results)) # Remove duplicates
task_prompt += f"""
Here are the results of previous tasks that might be useful:\n
{context_results}
Context:
{' '.join(unique_contexts)}
"""
# Add memory context if available
if task.memory:
try:
@@ -714,12 +749,24 @@ Here are the results of previous tasks that might be useful:\n
return str(agent[0])
return None
def start(self):
def start(self, content=None, **kwargs):
"""Start agent execution with optional content and config"""
if content:
# Add content to context of all tasks
for task in self.tasks.values():
if isinstance(content, (str, list)):
# If context is empty, initialize it
if not task.context:
task.context = []
# Add content to context
task.context.append(content)
# Run tasks as before
self.run_all_tasks()
return {
"task_status": self.get_all_tasks_status(),
"task_results": {task_id: self.get_task_result(task_id) for task_id in self.tasks}
}
}
def set_state(self, key: str, value: Any) -> None:
"""Set a state value"""
+31 -2
View File
@@ -19,7 +19,7 @@ class Task:
agent: Optional[Agent] = None,
name: Optional[str] = None,
tools: Optional[List[Any]] = None,
context: Optional[List["Task"]] = None,
context: Optional[List[Union[str, List, 'Task']]] = None,
async_execution: Optional[bool] = False,
config: Optional[Dict[str, Any]] = None,
output_file: Optional[str] = None,
@@ -219,4 +219,33 @@ class Task:
self.callback(task_output)
except Exception as e:
logger.error(f"Task {self.id}: Failed to execute callback: {e}")
logger.exception(e)
logger.exception(e)
task_prompt = f"""
You need to do the following task: {self.description}.
Expected Output: {self.expected_output}.
"""
if self.context:
context_results = [] # Use list to avoid duplicates
for context_item in self.context:
if isinstance(context_item, str):
context_results.append(f"Input Content:\n{context_item}")
elif isinstance(context_item, list):
context_results.append(f"Input Content: {' '.join(str(x) for x in context_item)}")
elif hasattr(context_item, 'result'): # Task object
if context_item.result:
context_results.append(
f"Result of previous task {context_item.name if context_item.name else context_item.description}:\n{context_item.result.raw}"
)
else:
context_results.append(
f"Previous task {context_item.name if context_item.name else context_item.description} has no result yet."
)
# Join unique context results
unique_contexts = list(dict.fromkeys(context_results)) # Remove duplicates
task_prompt += f"""
Context:
{' '.join(unique_contexts)}
"""
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "praisonaiagents"
version = "0.0.40"
version = "0.0.41"
description = "Praison AI agents for completing complex tasks with Self Reflection Agents"
authors = [
{ name="Mervin Praison" }
+1 -1
View File
@@ -1558,7 +1558,7 @@ wheels = [
[[package]]
name = "praisonaiagents"
version = "0.0.40"
version = "0.0.41"
source = { editable = "." }
dependencies = [
{ name = "openai" },
+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.49 gunicorn markdown\n&#34;)
file.write(&#34;RUN pip install flask praisonai==2.0.50 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;)
+108
View File
@@ -0,0 +1,108 @@
from praisonaiagents import Agent, Task, PraisonAIAgents
from pydantic import BaseModel
from typing import List, Dict
# Define structured output models
class SkillAnalysis(BaseModel):
technical_skills: List[str]
soft_skills: List[str]
skill_gaps: List[str]
recommendations: List[str]
class ExperienceAnalysis(BaseModel):
key_achievements: List[str]
impact_metrics: List[Dict[str, str]]
areas_of_expertise: List[str]
improvement_suggestions: List[str]
class CVAnalysisReport(BaseModel):
overall_score: int
key_strengths: List[str]
areas_for_improvement: List[str]
market_fit: str
recommendations: List[str]
skill_analysis: SkillAnalysis
experience_analysis: ExperienceAnalysis
# Create specialized agents
skill_analyst = Agent(
role="Skills Analysis Expert",
goal="Analyze technical and soft skills in CV",
backstory="""You are an experienced skills analyst with deep knowledge of industry requirements
and current market trends. You excel at identifying valuable skills and potential skill gaps.""",
verbose=True
)
experience_analyst = Agent(
role="Experience Analysis Expert",
goal="Analyze professional experience and achievements",
backstory="""You are an expert in evaluating professional experience and achievements.
You can identify impactful contributions and quantifiable results.""",
verbose=True
)
cv_evaluator = Agent(
role="Senior CV Evaluator",
goal="Provide comprehensive CV evaluation and recommendations",
backstory="""You are a senior CV evaluation expert with years of experience in talent assessment.
You provide detailed analysis and actionable recommendations for CV improvement.""",
verbose=True
)
# Create tasks with structured outputs
skills_analysis_task = Task(
description="""Analyze the CV's technical and soft skills. Identify skill gaps and provide recommendations
for skill development based on current market trends.""",
expected_output="Detailed analysis of skills with recommendations",
agent=skill_analyst,
output_pydantic=SkillAnalysis,
context=["test"],
)
experience_analysis_task = Task(
description="""Evaluate professional experience, achievements, and impact.
Identify key accomplishments and areas of expertise.""",
expected_output="Comprehensive analysis of professional experience",
agent=experience_analyst,
output_pydantic=ExperienceAnalysis
)
final_evaluation_task = Task(
description="""Review all analyses and provide a comprehensive evaluation of the CV.
Include overall assessment, key strengths, areas for improvement, and specific recommendations.""",
expected_output="Final CV evaluation report",
agent=cv_evaluator,
context=[skills_analysis_task, experience_analysis_task],
output_pydantic=CVAnalysisReport
)
# Create and run the agents
agents = PraisonAIAgents(
agents=[skill_analyst, experience_analyst, cv_evaluator],
tasks=[skills_analysis_task, experience_analysis_task, final_evaluation_task],
process="sequential",
verbose=True
)
# Start the analysis
result = agents.start()
# Access the structured results
print("\nCV Analysis Results:")
print(f"\nOverall Score: {result.pydantic.overall_score}/100")
print("\nKey Strengths:")
for strength in result.pydantic.key_strengths:
print(f"- {strength}")
print("\nSkill Analysis:")
print("\nTechnical Skills:")
for skill in result.pydantic.skill_analysis.technical_skills:
print(f"- {skill}")
print("\nExperience Highlights:")
for achievement in result.pydantic.experience_analysis.key_achievements:
print(f"- {achievement}")
print("\nRecommendations:")
for recommendation in result.pydantic.recommendations:
print(f"- {recommendation}")
+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.49.tar.gz"
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/2.0.50.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.49 gunicorn markdown\n")
file.write("RUN pip install flask praisonai==2.0.50 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.49"
version = "2.0.50"
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.40",
"praisonaiagents>=0.0.41",
"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.49"
version = "2.0.50"
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.40"
praisonaiagents = ">=0.0.41"
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.49"
version = "2.0.50"
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.40" },
{ name = "praisonaiagents", specifier = ">=0.0.41" },
{ 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.40"
version = "0.0.41"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "openai" },
{ name = "pydantic" },
{ name = "rich" },
]
sdist = { url = "https://files.pythonhosted.org/packages/93/75/1915862918beb4cc32b5ef6e9b6a9d30aada34d0f17a068932739559c2e8/praisonaiagents-0.0.40.tar.gz", hash = "sha256:a94eee27dabc86c8a71d28d7f1d91c75a4879265dde9d760384cddcfbd20cf5a", size = 75243 }
sdist = { url = "https://files.pythonhosted.org/packages/d9/39/2e97f6f1ea30948ae93c15cfab67998c999fe859b26481e2dfbddbc5543c/praisonaiagents-0.0.41.tar.gz", hash = "sha256:f8760446ff2bae5957a695616bc23b990bf422054edc2d2d37f2336fd708475b", size = 75859 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/aa/a6/6ee1e9cc8951dd792af8f1101d97fe95d9264d053b03301bc176c324e0a8/praisonaiagents-0.0.40-py3-none-any.whl", hash = "sha256:13a99faa574c372d6828cb82e22d4d639597e273e0d4b7546e36f63f0a7a9544", size = 92934 },
{ url = "https://files.pythonhosted.org/packages/63/7a/3da6a6076b2501246a0770d662c5d72158eaacfc10eb4b0938ae43b17d19/praisonaiagents-0.0.41-py3-none-any.whl", hash = "sha256:72dc3e1f5c939ab74898e952bba2b106e3f2b5bf4577f9ff96bc725e17d5b212", size = 93589 },
]
[[package]]