mirror of
https://github.com/MervinPraison/PraisonAI.git
synced 2026-11-07 12:47:55 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df3c97e73a | ||
|
|
27808964be | ||
|
|
b5daf16e0d | ||
|
|
a2cac05d16 | ||
|
|
ad9828d3bb | ||
|
|
85ddf04b47 | ||
|
|
1c1a1b719b | ||
|
|
a8e0914e05 | ||
|
|
ec6d883f4f | ||
|
|
d094cbfac5 | ||
|
|
14e3724aed | ||
|
|
92436277d9 | ||
|
|
3e0fd298e2 | ||
|
|
fad0b41b52 | ||
|
|
6c3e5ee187 | ||
|
|
f842ee7048 | ||
|
|
b0ff6f3f60 | ||
|
|
798f6dad14 | ||
|
|
629bf0d669 | ||
|
|
eaca447b82 | ||
|
|
bef3693627 | ||
|
|
aa62babed6 | ||
|
|
b73f181200 | ||
|
|
66d2998047 | ||
|
|
c5b6f8b91a | ||
|
|
823e46ca84 | ||
|
|
57040333a7 | ||
|
|
8c6800f876 | ||
|
|
0d701ae43c | ||
|
|
7a8c25621c | ||
|
|
218c5443b1 | ||
|
|
f56810341c | ||
|
|
4f601a573f | ||
|
|
43c03f4813 | ||
|
|
03856b74bf | ||
|
|
eadfc0cff0 | ||
|
|
f33c44d4c5 | ||
|
|
3f7885289d | ||
|
|
833c795e9a | ||
|
|
c460c9da60 | ||
|
|
656887c700 | ||
|
|
e0089cac41 | ||
|
|
bf5e069c7b | ||
|
|
94cf264b4c | ||
|
|
ab44fd4b27 |
No files matched your search
+2
-1
@@ -65,4 +65,5 @@ outputs
|
||||
agents/praisonaiagents/build
|
||||
agents/praisonaiagents/dist
|
||||
agents/praisonaiagents/praisonaiagents.egg-info
|
||||
.codegpt
|
||||
.codegpt
|
||||
.praison
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
FROM python:3.11-slim
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN pip install flask praisonai==2.0.29 gunicorn markdown
|
||||
RUN pip install flask praisonai==2.0.42 gunicorn markdown
|
||||
EXPOSE 8080
|
||||
CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]
|
||||
@@ -1,6 +1,7 @@
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
topic: create movie script about cat in mars
|
||||
memory: false
|
||||
roles:
|
||||
researcher:
|
||||
backstory: Skilled in research, with a focus on gathering accurate and relevant
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
1. Make minimal code changes as possible
|
||||
2. if you are creating function, make sure to name it in more easy, user friendly , optimised manner.
|
||||
3. Never copy the exact code if presented with a code from other location or file or codebase, just make it optimised
|
||||
4. Always Follow the principle LESS IS MORE
|
||||
5. Make it minimal change as possible
|
||||
6. Firstly try not to make any modification to the existing code as possible
|
||||
7. Only modify the existing code if its highly required, without that if it cant be done, then add new code section.
|
||||
8. If you are adding new code, make sure to add it in a way that it can be easily integrated with the existing codebase.
|
||||
+2
-1
@@ -83,4 +83,5 @@ dist
|
||||
build
|
||||
*.mp4
|
||||
*.png
|
||||
graph.py
|
||||
graph.py
|
||||
chroma_db/
|
||||
Whitespace-only changes.
@@ -0,0 +1,32 @@
|
||||
.cursorrules
|
||||
.gitignore
|
||||
.praisoncontext
|
||||
.praisonignore
|
||||
.windsurfrules
|
||||
async_example.py
|
||||
async_example_full.py
|
||||
async_example_full_multigroups.py
|
||||
auto_agents_example.py
|
||||
code_agents_example.py
|
||||
example_callback.py
|
||||
example_custom_tools.py
|
||||
example_sequential.py
|
||||
image.jpg
|
||||
langchain_example.py
|
||||
langchain_logs.py
|
||||
long_term.db
|
||||
mini_agents_example.py
|
||||
multimodal.py
|
||||
praisonaiagents/tools/*
|
||||
praisonaiagents/process/*
|
||||
pyproject.toml
|
||||
short_term.db
|
||||
structured_agents_example.py
|
||||
structured_response_example.py
|
||||
test.py
|
||||
tools_example.py
|
||||
uv.lock
|
||||
workflow_example_basic.py
|
||||
workflow_example_detailed.py
|
||||
__pycache__
|
||||
__pycache__/*
|
||||
@@ -0,0 +1,8 @@
|
||||
1. Make minimal code changes as possible
|
||||
2. if you are creating function, make sure to name it in more easy, user friendly , optimised manner.
|
||||
3. Never copy the exact code if presented with a code from other location or file or codebase, just make it optimised
|
||||
4. Always Follow the principle LESS IS MORE
|
||||
5. Make it minimal change as possible
|
||||
6. Firstly try not to make any modification to the existing code as possible
|
||||
7. Only modify the existing code if its highly required, without that if it cant be done, then add new code section.
|
||||
8. If you are adding new code, make sure to add it in a way that it can be easily integrated with the existing codebase.
|
||||
@@ -0,0 +1,11 @@
|
||||
from praisonaiagents import AutoAgents
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
agents = AutoAgents(
|
||||
instructions="Search for information about AI Agents",
|
||||
tools=[duckduckgo],
|
||||
process="sequential",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
agents.start()
|
||||
@@ -0,0 +1,50 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
import json
|
||||
from e2b_code_interpreter import Sandbox
|
||||
|
||||
def code_interpreter(code: str):
|
||||
"""
|
||||
A function to demonstrate running Python code dynamically using e2b_code_interpreter.
|
||||
"""
|
||||
print(f"\n{'='*50}\n> Running following AI-generated code:\n{code}\n{'='*50}")
|
||||
exec_result = Sandbox().run_code(code)
|
||||
if exec_result.error:
|
||||
print("[Code Interpreter error]", exec_result.error)
|
||||
return {"error": str(exec_result.error)}
|
||||
else:
|
||||
results = []
|
||||
for result in exec_result.results:
|
||||
if hasattr(result, '__iter__'):
|
||||
results.extend(list(result))
|
||||
else:
|
||||
results.append(str(result))
|
||||
logs = {"stdout": list(exec_result.logs.stdout), "stderr": list(exec_result.logs.stderr)}
|
||||
return json.dumps({"results": results, "logs": logs})
|
||||
|
||||
code_agent = Agent(
|
||||
name="code_agent",
|
||||
llm="gpt-4o-mini",
|
||||
backstory="Expert in writing Python scripts",
|
||||
self_reflect=False
|
||||
)
|
||||
execution_agent = Agent(
|
||||
name="execution_agent",
|
||||
llm="gpt-4o-mini",
|
||||
backstory="Expert in executing Python scripts",
|
||||
self_reflect=False,
|
||||
tools=[code_interpreter]
|
||||
)
|
||||
|
||||
code_agent_task = Task(
|
||||
description="Write a simple Python script to print 'Hello, World!'",
|
||||
expected_output="A Python script that prints 'Hello, World!'",
|
||||
agent=code_agent
|
||||
)
|
||||
execution_agent_task = Task(
|
||||
description="Execute the Python script",
|
||||
expected_output="The output of the Python script",
|
||||
agent=execution_agent
|
||||
)
|
||||
|
||||
agents = PraisonAIAgents(agents=[code_agent, execution_agent], tasks=[code_agent_task, execution_agent_task])
|
||||
agents.start()
|
||||
@@ -0,0 +1,151 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from typing import List, Dict, Union
|
||||
from duckduckgo_search import DDGS
|
||||
from langchain_community.tools import YouTubeSearchTool
|
||||
from langchain_community.utilities import WikipediaAPIWrapper
|
||||
|
||||
# 1. Tool
|
||||
def internet_search_tool(query: str) -> List[Dict]:
|
||||
"""
|
||||
Perform a search using DuckDuckGo.
|
||||
|
||||
Args:
|
||||
query (str): The search query.
|
||||
|
||||
Returns:
|
||||
list: A list of search result titles, URLs, and snippets.
|
||||
"""
|
||||
try:
|
||||
results = []
|
||||
ddgs = DDGS()
|
||||
for result in ddgs.text(keywords=query, max_results=10):
|
||||
results.append({
|
||||
"title": result.get("title", ""),
|
||||
"url": result.get("href", ""),
|
||||
"snippet": result.get("body", "")
|
||||
})
|
||||
return results
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error during DuckDuckGo search: {e}")
|
||||
return []
|
||||
|
||||
def youtube_search_tool(query: str, inspect: bool = False, max_results: int = 2):
|
||||
"""
|
||||
Provide a custom wrapper around the YouTubeSearchTool.
|
||||
|
||||
Args:
|
||||
query (str): The search query for YouTube.
|
||||
inspect (bool): If True, returns tool inspection info instead of search results.
|
||||
max_results (int): Maximum number of results to return (default: 2).
|
||||
Returns:
|
||||
Union[List[str], dict]: List of YouTube video URLs or tool inspection info.
|
||||
"""
|
||||
yt = YouTubeSearchTool()
|
||||
|
||||
if inspect:
|
||||
inspection_info = {
|
||||
"type": type(yt),
|
||||
"attributes": [attr for attr in dir(yt) if not attr.startswith('_')],
|
||||
"methods": {
|
||||
"run": getattr(yt, 'run', None),
|
||||
"arun": getattr(yt, 'arun', None)
|
||||
},
|
||||
"properties": {
|
||||
"name": getattr(yt, 'name', 'youtube_search'),
|
||||
"description": getattr(yt, 'description', 'Search YouTube videos'),
|
||||
"return_direct": getattr(yt, 'return_direct', False)
|
||||
}
|
||||
}
|
||||
return inspection_info
|
||||
|
||||
# Format query with max_results
|
||||
formatted_query = f"{query}, {max_results}"
|
||||
return yt.run(formatted_query)
|
||||
|
||||
def wikipedia_search_tool(query: str, inspect: bool = False, max_chars: int = 4000, top_k: int = 3):
|
||||
"""
|
||||
Provide a custom wrapper around langchain_community's WikipediaAPIWrapper.
|
||||
|
||||
Args:
|
||||
query (str): A search query for Wikipedia.
|
||||
inspect (bool): If True, returns tool inspection info instead of search results.
|
||||
max_chars (int): Maximum characters to return (default: 4000).
|
||||
top_k (int): Number of top results to consider (default: 3).
|
||||
Returns:
|
||||
Union[str, dict]: Summary from Wikipedia or tool inspection info if inspect=True.
|
||||
"""
|
||||
w = WikipediaAPIWrapper(
|
||||
top_k_results=top_k,
|
||||
doc_content_chars_max=max_chars,
|
||||
lang='en'
|
||||
)
|
||||
|
||||
if inspect:
|
||||
inspection_info = {
|
||||
"type": type(w),
|
||||
"attributes": [attr for attr in dir(w) if not attr.startswith('_')],
|
||||
"methods": {
|
||||
"run": getattr(w, 'run', None),
|
||||
"arun": getattr(w, 'arun', None)
|
||||
},
|
||||
"properties": {
|
||||
"name": "wikipedia",
|
||||
"description": "Search and get summaries from Wikipedia",
|
||||
"top_k": w.top_k_results,
|
||||
"lang": w.lang,
|
||||
"max_chars": w.doc_content_chars_max
|
||||
}
|
||||
}
|
||||
return inspection_info
|
||||
|
||||
try:
|
||||
result = w.run(query)
|
||||
return result
|
||||
except Exception as e:
|
||||
return f"Error searching Wikipedia: {str(e)}"
|
||||
|
||||
# 2. Agent
|
||||
data_agent = Agent(
|
||||
name="DataCollector",
|
||||
role="Search Specialist",
|
||||
goal="Perform internet searches to collect relevant information.",
|
||||
backstory="Expert in finding and organizing internet data from multiple sources.",
|
||||
tools=[internet_search_tool, youtube_search_tool, wikipedia_search_tool],
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# 3. Tasks
|
||||
collect_task = Task(
|
||||
description="Perform an internet search using the query: 'AI job trends in 2024'. Return results as a list of title, URL, and snippet.",
|
||||
expected_output="List of search results with titles, URLs, and snippets.",
|
||||
agent=data_agent,
|
||||
name="collect_data",
|
||||
is_start=True,
|
||||
next_tasks=["validate_data"]
|
||||
)
|
||||
|
||||
validate_task = Task(
|
||||
description="""Validate the collected data. Check if:
|
||||
1. At least 5 results are returned.
|
||||
2. Each result contains a title and a URL.
|
||||
Return validation_result as 'valid' or 'invalid' only no other text.""",
|
||||
expected_output="Validation result indicating if data is valid or invalid.",
|
||||
agent=data_agent,
|
||||
name="validate_data",
|
||||
task_type="decision",
|
||||
condition={
|
||||
"valid": [], # End the workflow on valid data
|
||||
"invalid": ["collect_data"] # Retry data collection on invalid data
|
||||
},
|
||||
)
|
||||
|
||||
# 4. Workflow
|
||||
agents = PraisonAIAgents(
|
||||
agents=[data_agent],
|
||||
tasks=[collect_task, validate_task],
|
||||
verbose=1,
|
||||
process="workflow"
|
||||
)
|
||||
|
||||
agents.start()
|
||||
File renamed without changes.
@@ -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],
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# 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()
|
||||
@@ -0,0 +1,73 @@
|
||||
from langchain_community.tools import YouTubeSearchTool
|
||||
from langchain_community.utilities import WikipediaAPIWrapper
|
||||
|
||||
def test_tools():
|
||||
"""Test both YouTube and Wikipedia tools"""
|
||||
|
||||
print("\n=== Testing YouTube Search ===")
|
||||
# Test YouTube
|
||||
yt = YouTubeSearchTool()
|
||||
|
||||
# Test basic search
|
||||
print("\nBasic YouTube Search:")
|
||||
query = "AI advancements 2024"
|
||||
print(f"Query: {query}")
|
||||
result = yt.run(query)
|
||||
print(f"Results: {result}")
|
||||
|
||||
# Test with max results
|
||||
print("\nYouTube Search with max results:")
|
||||
query = "AI advancements 2024, 3" # Format: query, max_results
|
||||
print(f"Query: {query}")
|
||||
result = yt.run(query)
|
||||
print(f"Results: {result}")
|
||||
|
||||
print("\n=== Testing Wikipedia Search ===")
|
||||
# Test Wikipedia
|
||||
wiki = WikipediaAPIWrapper(
|
||||
top_k_results=2,
|
||||
doc_content_chars_max=500
|
||||
)
|
||||
|
||||
# Test basic search
|
||||
print("\nBasic Wikipedia Search:")
|
||||
query = "Artificial Intelligence"
|
||||
print(f"Query: {query}")
|
||||
result = wiki.run(query)
|
||||
print(f"Results: {result[:200]}..." if result else "No result")
|
||||
|
||||
# Test with different parameters
|
||||
print("\nWikipedia Search with different language:")
|
||||
wiki_fr = WikipediaAPIWrapper(
|
||||
lang='fr',
|
||||
top_k_results=1,
|
||||
doc_content_chars_max=300
|
||||
)
|
||||
result = wiki_fr.run("Intelligence Artificielle")
|
||||
print(f"French Results: {result[:200]}..." if result else "No result")
|
||||
|
||||
def print_tool_info():
|
||||
"""Print detailed information about the tools"""
|
||||
|
||||
print("\n=== Tool Information ===")
|
||||
|
||||
# YouTube Tool Info
|
||||
print("\nYouTube Tool:")
|
||||
yt = YouTubeSearchTool()
|
||||
print("Type:", type(yt))
|
||||
print("Name:", getattr(yt, 'name', None))
|
||||
print("Description:", getattr(yt, 'description', None))
|
||||
print("Arguments:", getattr(yt, 'args', None))
|
||||
|
||||
# Wikipedia Tool Info
|
||||
print("\nWikipedia Tool:")
|
||||
wiki = WikipediaAPIWrapper()
|
||||
print("Type:", type(wiki))
|
||||
print("Available Settings:")
|
||||
print("- Language:", wiki.lang)
|
||||
print("- Top K Results:", wiki.top_k_results)
|
||||
print("- Max Characters:", wiki.doc_content_chars_max)
|
||||
|
||||
if __name__ == "__main__":
|
||||
print_tool_info()
|
||||
test_tools()
|
||||
@@ -0,0 +1,183 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
import logging
|
||||
import os
|
||||
|
||||
def main():
|
||||
# Initialize memory config
|
||||
memory_config = {
|
||||
"provider": "rag",
|
||||
"use_embedding": True,
|
||||
"storage": {
|
||||
"type": "sqlite",
|
||||
"path": "./.praison/memory.db"
|
||||
},
|
||||
"rag_db_path": "./.praison/chroma_db"
|
||||
}
|
||||
|
||||
# Test facts
|
||||
fact1 = "The capital city of Jujuha is Hahanu and its population is 102300"
|
||||
fact2 = "Three main ingredients in a classic proloder are eggs, sugar, and flour"
|
||||
fact3 = "The year the first Josinga was released is 2007"
|
||||
|
||||
# # Check if database exists
|
||||
# if os.path.exists("./memory.db"):
|
||||
# logger.info("Found existing memory database")
|
||||
# else:
|
||||
# logger.info("Creating new memory database")
|
||||
|
||||
# Create task config (without memory config since it's moved to PraisonAIAgents)
|
||||
task_config = {}
|
||||
|
||||
# Create agents with different roles
|
||||
researcher = Agent(
|
||||
role="Research Analyst",
|
||||
goal="Research and document key information about topics",
|
||||
backstory="Expert at analyzing and storing information in memory",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
retriever = Agent(
|
||||
role="Information Retriever",
|
||||
goal="Retrieve and verify stored information from memory",
|
||||
backstory="Specialist in searching and validating information from memory",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
# Task 1: Process the facts
|
||||
store_task = Task(
|
||||
description=f"""
|
||||
Process and analyze this information:
|
||||
1. {fact1}
|
||||
2. {fact2}
|
||||
3. {fact3}
|
||||
|
||||
Provide a clear summary of each fact.
|
||||
""",
|
||||
expected_output="""
|
||||
Clear statements summarizing each fact.
|
||||
Example format:
|
||||
1. [Summary of fact 1]
|
||||
2. [Summary of fact 2]
|
||||
3. [Summary of fact 3]
|
||||
""",
|
||||
agent=researcher
|
||||
)
|
||||
|
||||
# Task 2: Write essay about AI
|
||||
verify_task = Task(
|
||||
description="""
|
||||
write few points about AI
|
||||
""",
|
||||
expected_output="Points about AI",
|
||||
agent=retriever
|
||||
)
|
||||
|
||||
# Task 3: Query memory
|
||||
query_task = Task(
|
||||
description="""
|
||||
Using ONLY information found in memory:
|
||||
1. What is stored in memory about Hahanu?
|
||||
2. What ingredients for proloder are recorded in memory?
|
||||
3. What year is stored in memory for the Josinga release?
|
||||
|
||||
For each answer, cite the memory record you found.
|
||||
""",
|
||||
expected_output="Answers based solely on memory records with citations",
|
||||
agent=retriever
|
||||
)
|
||||
|
||||
# Task 4: Query both short-term and long-term memory
|
||||
query_both_task = Task(
|
||||
description="""
|
||||
Using ONLY information found in memory:
|
||||
1. What is stored in both short-term and long-term memory about Jujuha?
|
||||
2. What ingredients for proloder are recorded in both short-term and long-term memory?
|
||||
3. What year is stored in both short-term and long-term memory for the Josinga release?
|
||||
|
||||
For each answer, cite the memory record you found.
|
||||
""",
|
||||
expected_output="Answers based solely on memory records with citations",
|
||||
agent=retriever
|
||||
)
|
||||
|
||||
# Initialize PraisonAIAgents with memory configuration
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher, retriever],
|
||||
tasks=[store_task, verify_task, query_task, query_both_task],
|
||||
verbose=True, # Use same verbose level as memory
|
||||
memory=True,
|
||||
embedder={
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "text-embedding-3-small"
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
# agents = PraisonAIAgents(
|
||||
# agents=[researcher, retriever],
|
||||
# tasks=[store_task, verify_task, query_task, query_both_task],
|
||||
# verbose=True, # Use same verbose level as memory
|
||||
# memory=True
|
||||
# )
|
||||
|
||||
# Execute tasks
|
||||
print("\nExecuting Memory Test Tasks...")
|
||||
print("-" * 50)
|
||||
agents.start()
|
||||
|
||||
# Use shared memory for final checks
|
||||
memory = agents.shared_memory
|
||||
|
||||
# Test memory retrieval with different quality thresholds
|
||||
if memory:
|
||||
print("\nFinal Memory Check:")
|
||||
print("-" * 50)
|
||||
|
||||
queries = ["Jujuha", "proloder", "Josinga"]
|
||||
for query in queries:
|
||||
print(f"\nSearching memory for: {query}")
|
||||
|
||||
# Search in both short-term and long-term memory
|
||||
print("\nShort-term memory results:")
|
||||
stm_results = memory.search_short_term(query)
|
||||
if stm_results:
|
||||
for item in stm_results:
|
||||
print(f"Content: {item.get('content', '')[:200]}")
|
||||
if 'meta' in item:
|
||||
print(f"Metadata: {item['meta']}")
|
||||
print("-" * 20)
|
||||
else:
|
||||
print("No results found in short-term memory")
|
||||
|
||||
print("\nLong-term memory results:")
|
||||
ltm_results = memory.search_long_term(query)
|
||||
if ltm_results:
|
||||
for item in ltm_results:
|
||||
print(f"Content: {item.get('text', '')[:200]}")
|
||||
if 'metadata' in item:
|
||||
print(f"Metadata: {item['metadata']}")
|
||||
print("-" * 20)
|
||||
else:
|
||||
print("No results found in long-term memory")
|
||||
|
||||
# Also check ChromaDB if using RAG
|
||||
if memory.use_rag and hasattr(memory, "chroma_col"):
|
||||
print("\nChromaDB results:")
|
||||
try:
|
||||
all_items = memory.chroma_col.get()
|
||||
print(f"Found {len(all_items['ids'])} items in ChromaDB")
|
||||
for i in range(len(all_items['ids'])):
|
||||
print(f"ID: {all_items['ids'][i]}")
|
||||
print(f"Content: {all_items['documents'][i][:200]}")
|
||||
print(f"Metadata: {all_items['metadatas'][i]}")
|
||||
print("-" * 20)
|
||||
except Exception as e:
|
||||
print(f"Error querying ChromaDB: {e}")
|
||||
|
||||
print("-" * 30)
|
||||
else:
|
||||
print("\nNo memory available for final checks")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,63 @@
|
||||
from praisonaiagents.agents.agents import Agent, Task, PraisonAIAgents
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
# Test facts
|
||||
fact1 = "The capital city of Jujuha is Hahanu and its population is 102300"
|
||||
fact2 = "Three main ingredients in a classic proloder are eggs, sugar, and flour"
|
||||
fact3 = "The year the first Josinga was released is 2007"
|
||||
|
||||
fact_agent = Agent(
|
||||
name="Fact Agent",
|
||||
instructions="You are a fact agent, you store and retrieve facts in memory",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
research_agent = Agent(
|
||||
name="Research Agent",
|
||||
instructions="You are a research analyst, you research and document key points about topics",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
blog_agent = Agent(
|
||||
name="Blog Agent",
|
||||
instructions="You are a blog writer, you write a blog post about the research",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
fact_task = Task(
|
||||
description="Store the following facts in memory: " + fact1 + ", " + fact2 + ", " + fact3,
|
||||
agent=fact_agent
|
||||
)
|
||||
|
||||
research_task = Task(
|
||||
description="Research and document 2 key points about AI",
|
||||
agent=research_agent
|
||||
)
|
||||
|
||||
research_task2 = Task(
|
||||
description="Research and document 2 key points about AI in healthcare",
|
||||
agent=research_agent
|
||||
)
|
||||
|
||||
research_task3 = Task(
|
||||
description="Research and document 2 key points about AI in education",
|
||||
agent=research_agent
|
||||
)
|
||||
|
||||
research_task4 = Task(
|
||||
description="Research and document 2 key points about AI in finance",
|
||||
agent=research_agent
|
||||
)
|
||||
|
||||
blog_task = Task(
|
||||
description="Write a blog post about Jujuha",
|
||||
agent=blog_agent
|
||||
)
|
||||
|
||||
agents = PraisonAIAgents(
|
||||
agents=[fact_agent, research_agent, blog_agent],
|
||||
tasks=[fact_task, research_task, research_task2, research_task3, research_task4, blog_task],
|
||||
memory=True
|
||||
)
|
||||
|
||||
agents.start()
|
||||
@@ -6,6 +6,8 @@ from .agent.agent import Agent
|
||||
from .agents.agents import PraisonAIAgents
|
||||
from .task.task import Task
|
||||
from .tools.tools import Tools
|
||||
from .agents.autoagents import AutoAgents
|
||||
from .memory.memory import Memory
|
||||
from .main import (
|
||||
TaskOutput,
|
||||
ReflectionOutput,
|
||||
@@ -33,6 +35,8 @@ __all__ = [
|
||||
'Task',
|
||||
'TaskOutput',
|
||||
'ReflectionOutput',
|
||||
'AutoAgents',
|
||||
'Memory',
|
||||
'display_interaction',
|
||||
'display_self_reflection',
|
||||
'display_instruction',
|
||||
|
||||
@@ -18,6 +18,7 @@ from ..main import (
|
||||
client,
|
||||
error_logs
|
||||
)
|
||||
import inspect
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..task.task import Task
|
||||
@@ -67,9 +68,24 @@ class Agent:
|
||||
return None
|
||||
|
||||
import inspect
|
||||
# Langchain tools
|
||||
if inspect.isclass(func) and hasattr(func, 'run'):
|
||||
original_func = func
|
||||
func = func.run
|
||||
function_name = original_func.__name__
|
||||
|
||||
sig = inspect.signature(func)
|
||||
logging.debug(f"Function signature: {sig}")
|
||||
|
||||
# Skip self, *args, **kwargs, so they don't get passed in arguments
|
||||
parameters_list = []
|
||||
for name, param in sig.parameters.items():
|
||||
if name == "self":
|
||||
continue
|
||||
if param.kind in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD):
|
||||
continue
|
||||
parameters_list.append((name, param))
|
||||
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {},
|
||||
@@ -95,7 +111,7 @@ class Agent:
|
||||
|
||||
logging.debug(f"Parameter descriptions: {param_descriptions}")
|
||||
|
||||
for name, param in sig.parameters.items():
|
||||
for name, param in parameters_list:
|
||||
param_type = "string" # Default type
|
||||
if param.annotation != inspect.Parameter.empty:
|
||||
if param.annotation == int:
|
||||
@@ -140,13 +156,13 @@ class Agent:
|
||||
goal: Optional[str] = None,
|
||||
backstory: Optional[str] = None,
|
||||
instructions: Optional[str] = None,
|
||||
llm: Optional[Union[str, Any]] = "gpt-4o",
|
||||
llm: Optional[Union[str, Any]] = None,
|
||||
tools: Optional[List[Any]] = None,
|
||||
function_calling_llm: Optional[Any] = None,
|
||||
max_iter: int = 20,
|
||||
max_rpm: Optional[int] = None,
|
||||
max_execution_time: Optional[int] = None,
|
||||
memory: bool = True,
|
||||
memory: Optional[Any] = None,
|
||||
verbose: bool = True,
|
||||
allow_delegation: bool = False,
|
||||
step_callback: Optional[Any] = None,
|
||||
@@ -162,7 +178,7 @@ class Agent:
|
||||
knowledge_sources: Optional[List[Any]] = None,
|
||||
use_system_prompt: Optional[bool] = True,
|
||||
markdown: bool = True,
|
||||
self_reflect: Optional[bool] = None,
|
||||
self_reflect: bool = False,
|
||||
max_reflect: int = 3,
|
||||
min_reflect: int = 1,
|
||||
reflect_llm: Optional[str] = None
|
||||
@@ -189,7 +205,8 @@ class Agent:
|
||||
self.self_reflect = True if self_reflect is None else self_reflect
|
||||
|
||||
self.instructions = instructions
|
||||
self.llm = llm
|
||||
# Check for model name in environment variable if not provided
|
||||
self.llm = llm or os.getenv('OPENAI_MODEL_NAME', 'gpt-4o')
|
||||
self.tools = tools if tools else [] # Store original tools
|
||||
self.function_calling_llm = function_calling_llm
|
||||
self.max_iter = max_iter
|
||||
@@ -214,7 +231,8 @@ class Agent:
|
||||
self.markdown = markdown
|
||||
self.max_reflect = max_reflect
|
||||
self.min_reflect = min_reflect
|
||||
self.reflect_llm = reflect_llm
|
||||
# Use the same model selection logic for reflect_llm
|
||||
self.reflect_llm = reflect_llm or os.getenv('OPENAI_MODEL_NAME', 'gpt-4o')
|
||||
self.console = Console() # Create a single console instance for the agent
|
||||
|
||||
# Initialize system prompt
|
||||
@@ -247,25 +265,31 @@ Your Goal: {self.goal}
|
||||
# Try to find the function in the agent's tools list first
|
||||
func = None
|
||||
for tool in self.tools:
|
||||
if callable(tool) and getattr(tool, '__name__', '') == function_name:
|
||||
if (callable(tool) and getattr(tool, '__name__', '') == function_name) or \
|
||||
(inspect.isclass(tool) and tool.__name__ == function_name):
|
||||
func = tool
|
||||
break
|
||||
|
||||
logging.debug(f"Looking for {function_name} in agent tools: {func is not None}")
|
||||
|
||||
# If not found in tools, try globals and main
|
||||
if not func:
|
||||
if func is None:
|
||||
# If not found in tools, try globals and main
|
||||
func = globals().get(function_name)
|
||||
logging.debug(f"Looking for {function_name} in globals: {func is not None}")
|
||||
|
||||
if not func:
|
||||
import __main__
|
||||
func = getattr(__main__, function_name, None)
|
||||
logging.debug(f"Looking for {function_name} in __main__: {func is not None}")
|
||||
|
||||
if func and callable(func):
|
||||
if func:
|
||||
try:
|
||||
return func(**arguments)
|
||||
# If it's a class with run method, instantiate and call run
|
||||
if inspect.isclass(func) and hasattr(func, 'run'):
|
||||
instance = func()
|
||||
# Extract only the parameters that run() expects
|
||||
run_params = {k: v for k, v in arguments.items()
|
||||
if k in inspect.signature(instance.run).parameters
|
||||
and k != 'self'}
|
||||
return instance.run(**run_params)
|
||||
# Otherwise treat as regular function
|
||||
elif callable(func):
|
||||
return func(**arguments)
|
||||
except Exception as e:
|
||||
error_msg = str(e)
|
||||
logging.error(f"Error executing tool {function_name}: {error_msg}")
|
||||
@@ -357,7 +381,7 @@ Your Goal: {self.goal}
|
||||
display_generating("", start_time),
|
||||
console=self.console,
|
||||
refresh_per_second=4,
|
||||
transient=False, # Changed to False to preserve output
|
||||
transient=True, # Changed to False to preserve output
|
||||
vertical_overflow="ellipsis",
|
||||
auto_refresh=True
|
||||
) as live:
|
||||
@@ -392,7 +416,7 @@ Your Goal: {self.goal}
|
||||
display_error(f"Error in chat completion: {e}")
|
||||
return None
|
||||
|
||||
def chat(self, prompt, temperature=0.2, tools=None, output_json=None):
|
||||
def chat(self, prompt, temperature=0.2, tools=None, output_json=None, output_pydantic=None):
|
||||
if self.use_system_prompt:
|
||||
system_prompt = f"""{self.backstory}\n
|
||||
Your Role: {self.role}\n
|
||||
@@ -400,6 +424,8 @@ Your Goal: {self.goal}
|
||||
"""
|
||||
if output_json:
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {output_json.schema_json()}"
|
||||
elif output_pydantic:
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {output_pydantic.schema_json()}"
|
||||
else:
|
||||
system_prompt = None
|
||||
|
||||
@@ -408,9 +434,9 @@ Your Goal: {self.goal}
|
||||
messages.append({"role": "system", "content": system_prompt})
|
||||
messages.extend(self.chat_history)
|
||||
|
||||
# Modify prompt if output_json is specified
|
||||
# Modify prompt if output_json or output_pydantic is specified
|
||||
original_prompt = prompt
|
||||
if output_json:
|
||||
if output_json or output_pydantic:
|
||||
if isinstance(prompt, str):
|
||||
prompt += "\nReturn ONLY a valid JSON object. No other text or explanation."
|
||||
elif isinstance(prompt, list):
|
||||
@@ -440,7 +466,15 @@ Your Goal: {self.goal}
|
||||
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 {self.name} is processing prompt: {display_text}", console=self.console)
|
||||
# Pass agent information to display_instruction
|
||||
agent_tools = [t.__name__ if hasattr(t, '__name__') else str(t) for t in self.tools]
|
||||
display_instruction(
|
||||
f"Agent {self.name} is processing prompt: {display_text}",
|
||||
console=self.console,
|
||||
agent_name=self.name,
|
||||
agent_role=self.role,
|
||||
agent_tools=agent_tools
|
||||
)
|
||||
|
||||
response = self._chat_completion(messages, temperature=temperature, tools=tools if tools else None)
|
||||
if not response:
|
||||
@@ -485,29 +519,21 @@ Your Goal: {self.goal}
|
||||
return None
|
||||
response_text = response.choices[0].message.content.strip()
|
||||
|
||||
# Handle output_json if specified
|
||||
if output_json:
|
||||
try:
|
||||
# Clean the response text to get only JSON
|
||||
cleaned_json = self.clean_json_output(response_text)
|
||||
# Parse into Pydantic model
|
||||
parsed_model = output_json.model_validate_json(cleaned_json)
|
||||
# Add to chat history and return
|
||||
self.chat_history.append({"role": "user", "content": original_prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
if self.verbose:
|
||||
display_interaction(original_prompt, response_text, markdown=self.markdown,
|
||||
generation_time=time.time() - start_time, console=self.console)
|
||||
return parsed_model
|
||||
except Exception as e:
|
||||
display_error(f"Failed to parse response as {output_json.__name__}: {e}")
|
||||
return None
|
||||
# Handle output_json or output_pydantic if specified
|
||||
if output_json or output_pydantic:
|
||||
# Add to chat history and return raw response
|
||||
self.chat_history.append({"role": "user", "content": original_prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
if self.verbose:
|
||||
display_interaction(original_prompt, response_text, markdown=self.markdown,
|
||||
generation_time=time.time() - start_time, console=self.console)
|
||||
return response_text
|
||||
|
||||
if not self.self_reflect:
|
||||
self.chat_history.append({"role": "user", "content": original_prompt})
|
||||
self.chat_history.append({"role": "assistant", "content": response_text})
|
||||
if self.verbose:
|
||||
logging.info(f"Agent {self.name} final response: {response_text}")
|
||||
logging.debug(f"Agent {self.name} final response: {response_text}")
|
||||
display_interaction(original_prompt, response_text, markdown=self.markdown, generation_time=time.time() - start_time, console=self.console)
|
||||
return response_text
|
||||
|
||||
@@ -583,19 +609,21 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
cleaned = cleaned[:-3].strip()
|
||||
return cleaned
|
||||
|
||||
async def achat(self, prompt, temperature=0.2, tools=None, output_json=None):
|
||||
async def achat(self, prompt, temperature=0.2, tools=None, output_json=None, output_pydantic=None):
|
||||
"""Async version of chat method"""
|
||||
try:
|
||||
# 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()}"
|
||||
elif output_pydantic:
|
||||
system_prompt += f"\nReturn ONLY a JSON object that matches this Pydantic model: {output_pydantic.schema_json()}"
|
||||
|
||||
# Build messages
|
||||
if isinstance(prompt, str):
|
||||
messages = [
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": prompt + ("\nReturn ONLY a valid JSON object. No other text or explanation." if output_json else "")}
|
||||
{"role": "user", "content": prompt + ("\nReturn ONLY a valid JSON object. No other text or explanation." if (output_json or output_pydantic) else "")}
|
||||
]
|
||||
else:
|
||||
# For multimodal prompts
|
||||
@@ -603,13 +631,29 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": prompt}
|
||||
]
|
||||
if output_json:
|
||||
if output_json or output_pydantic:
|
||||
# Add JSON instruction to text content
|
||||
for item in messages[-1]["content"]:
|
||||
if item["type"] == "text":
|
||||
item["text"] += "\nReturn ONLY a valid JSON object. No other text or explanation."
|
||||
break
|
||||
|
||||
# Display instruction with agent info if verbose
|
||||
if self.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():
|
||||
agent_tools = [t.__name__ if hasattr(t, '__name__') else str(t) for t in self.tools]
|
||||
await adisplay_instruction(
|
||||
f"Agent {self.name} is processing prompt: {display_text}",
|
||||
console=self.console,
|
||||
agent_name=self.name,
|
||||
agent_role=self.role,
|
||||
agent_tools=agent_tools
|
||||
)
|
||||
|
||||
# Format tools if provided
|
||||
formatted_tools = []
|
||||
if tools:
|
||||
@@ -637,22 +681,15 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
tools=formatted_tools
|
||||
)
|
||||
return await self._achat_completion(response, tools)
|
||||
elif output_json:
|
||||
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"}
|
||||
)
|
||||
result = response.choices[0].message.content
|
||||
# Clean and parse the JSON response
|
||||
cleaned_json = self.clean_json_output(result)
|
||||
try:
|
||||
parsed = json.loads(cleaned_json)
|
||||
return output_json(**parsed)
|
||||
except Exception as e:
|
||||
display_error(f"Error parsing JSON response: {e}")
|
||||
return None
|
||||
# Return the raw response
|
||||
return response.choices[0].message.content
|
||||
else:
|
||||
response = await async_client.chat.completions.create(
|
||||
model=self.llm,
|
||||
@@ -720,4 +757,8 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
||||
return None
|
||||
except Exception as e:
|
||||
display_error(f"Error in _achat_completion: {e}")
|
||||
return None
|
||||
return None
|
||||
|
||||
def run(self):
|
||||
"""Alias for start() method"""
|
||||
return self.start()
|
||||
@@ -1,4 +1,5 @@
|
||||
"""Agents module for managing multiple AI agents"""
|
||||
from .agents import PraisonAIAgents
|
||||
from .autoagents import AutoAgents
|
||||
|
||||
__all__ = ['PraisonAIAgents']
|
||||
__all__ = ['PraisonAIAgents', 'AutoAgents']
|
||||
@@ -13,6 +13,9 @@ from ..task.task import Task
|
||||
from ..process.process import Process, LoopItems
|
||||
import asyncio
|
||||
|
||||
# Set up logger
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def encode_file_to_base64(file_path: str) -> str:
|
||||
"""Base64-encode a file."""
|
||||
import base64
|
||||
@@ -41,7 +44,7 @@ def process_video(video_path: str, seconds_per_frame=2):
|
||||
return base64_frames
|
||||
|
||||
class PraisonAIAgents:
|
||||
def __init__(self, agents, tasks=None, verbose=0, completion_checker=None, max_retries=5, process="sequential", manager_llm=None):
|
||||
def __init__(self, agents, tasks=None, verbose=0, completion_checker=None, max_retries=5, process="sequential", manager_llm=None, memory=False, memory_config=None, embedder=None):
|
||||
if not agents:
|
||||
raise ValueError("At least one agent must be provided")
|
||||
|
||||
@@ -54,9 +57,24 @@ class PraisonAIAgents:
|
||||
self.verbose = verbose
|
||||
self.max_retries = max_retries
|
||||
self.process = process
|
||||
if not manager_llm:
|
||||
logging.debug("No manager_llm provided. Using OPENAI_MODEL_NAME environment variable or defaulting to 'gpt-4o'")
|
||||
self.manager_llm = manager_llm if manager_llm else os.getenv('OPENAI_MODEL_NAME', 'gpt-4o')
|
||||
|
||||
# Check for manager_llm in environment variable if not provided
|
||||
self.manager_llm = manager_llm or os.getenv('OPENAI_MODEL_NAME', 'gpt-4o')
|
||||
|
||||
# Set logger level based on verbose
|
||||
if verbose >= 5:
|
||||
logger.setLevel(logging.INFO)
|
||||
else:
|
||||
logger.setLevel(logging.WARNING)
|
||||
|
||||
# Also set third-party loggers to WARNING
|
||||
logging.getLogger('chromadb').setLevel(logging.WARNING)
|
||||
logging.getLogger('openai').setLevel(logging.WARNING)
|
||||
logging.getLogger('httpx').setLevel(logging.WARNING)
|
||||
logging.getLogger('httpcore').setLevel(logging.WARNING)
|
||||
|
||||
if self.verbose:
|
||||
logger.info(f"Using model {self.manager_llm} for manager")
|
||||
|
||||
# If no tasks provided, generate them from agents
|
||||
if tasks is None:
|
||||
@@ -64,12 +82,12 @@ class PraisonAIAgents:
|
||||
for agent in self.agents:
|
||||
task = agent.generate_task()
|
||||
tasks.append(task)
|
||||
logging.info(f"Auto-generated {len(tasks)} tasks from agents")
|
||||
logger.info(f"Auto-generated {len(tasks)} tasks from agents")
|
||||
else:
|
||||
# Validate tasks for backward compatibility
|
||||
if not tasks:
|
||||
raise ValueError("If tasks are provided, at least one task must be present")
|
||||
logging.info(f"Using {len(tasks)} provided tasks")
|
||||
logger.info(f"Using {len(tasks)} provided tasks")
|
||||
|
||||
# Add tasks and set their status
|
||||
for task in tasks:
|
||||
@@ -85,9 +103,65 @@ class PraisonAIAgents:
|
||||
if tasks[i + 1].context is None:
|
||||
tasks[i + 1].context = []
|
||||
tasks[i + 1].context.append(tasks[i])
|
||||
logging.info("Set up sequential flow with automatic context passing")
|
||||
logger.info("Set up sequential flow with automatic context passing")
|
||||
|
||||
self._state = {} # Add state storage at PraisonAIAgents level
|
||||
|
||||
# Initialize memory system
|
||||
self.shared_memory = None
|
||||
if memory:
|
||||
try:
|
||||
from ..memory.memory import Memory
|
||||
|
||||
# Get memory config from parameter or first task
|
||||
mem_cfg = memory_config
|
||||
if not mem_cfg:
|
||||
mem_cfg = next((t.config.get('memory_config') for t in tasks if hasattr(t, 'config') and t.config), None)
|
||||
|
||||
# Set default memory config if none provided
|
||||
if not mem_cfg:
|
||||
mem_cfg = {
|
||||
"provider": "rag",
|
||||
"use_embedding": True,
|
||||
"storage": {
|
||||
"type": "sqlite",
|
||||
"path": "./.praison/memory.db"
|
||||
},
|
||||
"rag_db_path": "./.praison/chroma_db"
|
||||
}
|
||||
|
||||
# Add embedder config if provided
|
||||
if embedder:
|
||||
if isinstance(embedder, dict):
|
||||
mem_cfg = mem_cfg or {}
|
||||
mem_cfg["embedder"] = embedder
|
||||
else:
|
||||
# Handle direct embedder function
|
||||
mem_cfg = mem_cfg or {}
|
||||
mem_cfg["embedder_function"] = embedder
|
||||
|
||||
if mem_cfg:
|
||||
# Pass verbose level to Memory
|
||||
self.shared_memory = Memory(config=mem_cfg, verbose=verbose)
|
||||
if verbose >= 5:
|
||||
logger.info("Initialized shared memory for PraisonAIAgents")
|
||||
|
||||
# Distribute memory to tasks
|
||||
for task in tasks:
|
||||
if not task.memory:
|
||||
task.memory = self.shared_memory
|
||||
if verbose >= 5:
|
||||
logger.info(f"Assigned shared memory to task {task.id}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to initialize shared memory: {e}")
|
||||
|
||||
# Update tasks with shared memory
|
||||
if self.shared_memory:
|
||||
for task in tasks:
|
||||
if not task.memory:
|
||||
task.memory = self.shared_memory
|
||||
logger.info(f"Assigned shared memory to task {task.id}")
|
||||
|
||||
def add_task(self, task):
|
||||
task_id = self.task_id_counter
|
||||
@@ -140,7 +214,7 @@ class PraisonAIAgents:
|
||||
task_prompt = f"""
|
||||
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:
|
||||
@@ -155,8 +229,8 @@ Here are the results of previous tasks that might be useful:\n
|
||||
task_prompt += "Please provide only the final result of your work. Do not add any conversation or extra explanation."
|
||||
|
||||
if self.verbose >= 2:
|
||||
logging.info(f"Executing task {task_id}: {task.description} using {executor_agent.name}")
|
||||
logging.debug(f"Starting execution of task {task_id} with prompt:\n{task_prompt}")
|
||||
logger.info(f"Executing task {task_id}: {task.description} using {executor_agent.name}")
|
||||
logger.debug(f"Starting execution of task {task_id} with prompt:\n{task_prompt}")
|
||||
|
||||
if task.images:
|
||||
def _get_multimodal_message(text_prompt, images):
|
||||
@@ -193,10 +267,17 @@ Here are the results of previous tasks that might be useful:\n
|
||||
|
||||
agent_output = await executor_agent.achat(
|
||||
_get_multimodal_message(task_prompt, task.images),
|
||||
tools=task.tools
|
||||
tools=task.tools,
|
||||
output_json=task.output_json,
|
||||
output_pydantic=task.output_pydantic
|
||||
)
|
||||
else:
|
||||
agent_output = await executor_agent.achat(task_prompt, tools=task.tools)
|
||||
agent_output = await executor_agent.achat(
|
||||
task_prompt,
|
||||
tools=task.tools,
|
||||
output_json=task.output_json,
|
||||
output_pydantic=task.output_pydantic
|
||||
)
|
||||
|
||||
if agent_output:
|
||||
task_output = TaskOutput(
|
||||
@@ -214,8 +295,8 @@ Here are the results of previous tasks that might be useful:\n
|
||||
task_output.json_dict = parsed
|
||||
task_output.output_format = "JSON"
|
||||
except:
|
||||
logging.warning(f"Warning: Could not parse output of task {task_id} as JSON")
|
||||
logging.debug(f"Output that failed JSON parsing: {agent_output}")
|
||||
logger.warning(f"Warning: Could not parse output of task {task_id} as JSON")
|
||||
logger.debug(f"Output that failed JSON parsing: {agent_output}")
|
||||
|
||||
if task.output_pydantic:
|
||||
cleaned = self.clean_json_output(agent_output)
|
||||
@@ -225,8 +306,8 @@ Here are the results of previous tasks that might be useful:\n
|
||||
task_output.pydantic = pyd_obj
|
||||
task_output.output_format = "Pydantic"
|
||||
except:
|
||||
logging.warning(f"Warning: Could not parse output of task {task_id} as Pydantic Model")
|
||||
logging.debug(f"Output that failed Pydantic parsing: {agent_output}")
|
||||
logger.warning(f"Warning: Could not parse output of task {task_id} as Pydantic Model")
|
||||
logger.debug(f"Output that failed Pydantic parsing: {agent_output}")
|
||||
|
||||
task.result = task_output
|
||||
return task_output
|
||||
@@ -241,37 +322,53 @@ Here are the results of previous tasks that might be useful:\n
|
||||
return
|
||||
task = self.tasks[task_id]
|
||||
if task.status == "completed":
|
||||
logging.info(f"Task with ID {task_id} is already completed")
|
||||
logger.info(f"Task with ID {task_id} is already completed")
|
||||
return
|
||||
|
||||
retries = 0
|
||||
while task.status != "completed" and retries < self.max_retries:
|
||||
logging.debug(f"Attempt {retries+1} for task {task_id}")
|
||||
logger.debug(f"Attempt {retries+1} for task {task_id}")
|
||||
if task.status in ["not started", "in progress"]:
|
||||
task_output = await self.aexecute_task(task_id)
|
||||
if task_output and self.completion_checker(task, task_output.raw):
|
||||
task.status = "completed"
|
||||
if task.callback:
|
||||
# Run execute_callback for memory operations
|
||||
try:
|
||||
await task.execute_callback(task_output)
|
||||
except Exception as e:
|
||||
logger.error(f"Error executing memory callback for task {task_id}: {e}")
|
||||
logger.exception(e)
|
||||
|
||||
# Run task callback if exists
|
||||
if task.callback:
|
||||
try:
|
||||
if asyncio.iscoroutinefunction(task.callback):
|
||||
await task.callback(task_output)
|
||||
else:
|
||||
task.callback(task_output)
|
||||
except Exception as e:
|
||||
logger.error(f"Error executing task callback for task {task_id}: {e}")
|
||||
logger.exception(e)
|
||||
|
||||
self.save_output_to_file(task, task_output)
|
||||
if self.verbose >= 1:
|
||||
logging.info(f"Task {task_id} completed successfully.")
|
||||
logger.info(f"Task {task_id} completed successfully.")
|
||||
else:
|
||||
task.status = "in progress"
|
||||
if self.verbose >= 1:
|
||||
logging.info(f"Task {task_id} not completed, retrying")
|
||||
logger.info(f"Task {task_id} not completed, retrying")
|
||||
await asyncio.sleep(1)
|
||||
retries += 1
|
||||
else:
|
||||
if task.status == "failed":
|
||||
logging.info("Task is failed, resetting to in-progress for another try...")
|
||||
logger.info("Task is failed, resetting to in-progress for another try...")
|
||||
task.status = "in progress"
|
||||
else:
|
||||
logging.info("Invalid Task status")
|
||||
logger.info("Invalid Task status")
|
||||
break
|
||||
|
||||
if retries == self.max_retries and task.status != "completed":
|
||||
logging.info(f"Task {task_id} failed after {self.max_retries} retries.")
|
||||
logger.info(f"Task {task_id} failed after {self.max_retries} retries.")
|
||||
|
||||
async def arun_all_tasks(self):
|
||||
"""Async version of run_all_tasks method"""
|
||||
@@ -319,7 +416,7 @@ Here are the results of previous tasks that might be useful:\n
|
||||
with open(task.output_file, "w") as f:
|
||||
f.write(str(task_output))
|
||||
if self.verbose >= 1:
|
||||
logging.info(f"Task output saved to {task.output_file}")
|
||||
logger.info(f"Task output saved to {task.output_file}")
|
||||
except Exception as e:
|
||||
display_error(f"Error saving task output to file: {e}")
|
||||
|
||||
@@ -330,6 +427,15 @@ Here are the results of previous tasks that might be useful:\n
|
||||
return
|
||||
task = self.tasks[task_id]
|
||||
|
||||
logger.info(f"Starting execution of task {task_id}")
|
||||
logger.info(f"Task config: {task.config}")
|
||||
|
||||
# Initialize memory before task execution
|
||||
if not task.memory:
|
||||
task.memory = task.initialize_memory()
|
||||
|
||||
logger.info(f"Task memory status: {'Initialized' if task.memory else 'Not initialized'}")
|
||||
|
||||
# Only import multimodal dependencies if task has images
|
||||
if task.images and task.status == "not started":
|
||||
try:
|
||||
@@ -362,11 +468,20 @@ Expected Output: {task.expected_output}.
|
||||
Here are the results of previous tasks that might be useful:\n
|
||||
{context_results}
|
||||
"""
|
||||
# Add memory context if available
|
||||
if task.memory:
|
||||
try:
|
||||
memory_context = task.memory.build_context_for_task(task.description)
|
||||
if memory_context:
|
||||
task_prompt += f"\n\nRelevant memory context:\n{memory_context}"
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting memory context: {e}")
|
||||
|
||||
task_prompt += "Please provide only the final result of your work. Do not add any conversation or extra explanation."
|
||||
|
||||
if self.verbose >= 2:
|
||||
logging.info(f"Executing task {task_id}: {task.description} using {executor_agent.name}")
|
||||
logging.debug(f"Starting execution of task {task_id} with prompt:\n{task_prompt}")
|
||||
logger.info(f"Executing task {task_id}: {task.description} using {executor_agent.name}")
|
||||
logger.debug(f"Starting execution of task {task_id} with prompt:\n{task_prompt}")
|
||||
|
||||
if task.images:
|
||||
def _get_multimodal_message(text_prompt, images):
|
||||
@@ -403,12 +518,30 @@ Here are the results of previous tasks that might be useful:\n
|
||||
|
||||
agent_output = executor_agent.chat(
|
||||
_get_multimodal_message(task_prompt, task.images),
|
||||
tools=task.tools
|
||||
tools=task.tools,
|
||||
output_json=task.output_json,
|
||||
output_pydantic=task.output_pydantic
|
||||
)
|
||||
else:
|
||||
agent_output = executor_agent.chat(task_prompt, tools=task.tools)
|
||||
agent_output = executor_agent.chat(
|
||||
task_prompt,
|
||||
tools=task.tools,
|
||||
output_json=task.output_json,
|
||||
output_pydantic=task.output_pydantic
|
||||
)
|
||||
|
||||
if agent_output:
|
||||
# Store the response in memory
|
||||
if task.memory:
|
||||
try:
|
||||
task.store_in_memory(
|
||||
content=agent_output,
|
||||
agent_name=executor_agent.name,
|
||||
task_id=task_id
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to store agent output in memory: {e}")
|
||||
|
||||
task_output = TaskOutput(
|
||||
description=task.description,
|
||||
summary=task.description[:10],
|
||||
@@ -424,8 +557,8 @@ Here are the results of previous tasks that might be useful:\n
|
||||
task_output.json_dict = parsed
|
||||
task_output.output_format = "JSON"
|
||||
except:
|
||||
logging.warning(f"Warning: Could not parse output of task {task_id} as JSON")
|
||||
logging.debug(f"Output that failed JSON parsing: {agent_output}")
|
||||
logger.warning(f"Warning: Could not parse output of task {task_id} as JSON")
|
||||
logger.debug(f"Output that failed JSON parsing: {agent_output}")
|
||||
|
||||
if task.output_pydantic:
|
||||
cleaned = self.clean_json_output(agent_output)
|
||||
@@ -435,8 +568,8 @@ Here are the results of previous tasks that might be useful:\n
|
||||
task_output.pydantic = pyd_obj
|
||||
task_output.output_format = "Pydantic"
|
||||
except:
|
||||
logging.warning(f"Warning: Could not parse output of task {task_id} as Pydantic Model")
|
||||
logging.debug(f"Output that failed Pydantic parsing: {agent_output}")
|
||||
logger.warning(f"Warning: Could not parse output of task {task_id} as Pydantic Model")
|
||||
logger.debug(f"Output that failed Pydantic parsing: {agent_output}")
|
||||
|
||||
task.result = task_output
|
||||
return task_output
|
||||
@@ -451,37 +584,54 @@ Here are the results of previous tasks that might be useful:\n
|
||||
return
|
||||
task = self.tasks[task_id]
|
||||
if task.status == "completed":
|
||||
logging.info(f"Task with ID {task_id} is already completed")
|
||||
logger.info(f"Task with ID {task_id} is already completed")
|
||||
return
|
||||
|
||||
retries = 0
|
||||
while task.status != "completed" and retries < self.max_retries:
|
||||
logging.debug(f"Attempt {retries+1} for task {task_id}")
|
||||
logger.debug(f"Attempt {retries+1} for task {task_id}")
|
||||
if task.status in ["not started", "in progress"]:
|
||||
task_output = self.execute_task(task_id)
|
||||
if task_output and self.completion_checker(task, task_output.raw):
|
||||
task.status = "completed"
|
||||
# Run execute_callback for memory operations
|
||||
try:
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(task.execute_callback(task_output))
|
||||
except Exception as e:
|
||||
logger.error(f"Error executing memory callback for task {task_id}: {e}")
|
||||
logger.exception(e)
|
||||
|
||||
# Run task callback if exists
|
||||
if task.callback:
|
||||
task.callback(task_output)
|
||||
try:
|
||||
if asyncio.iscoroutinefunction(task.callback):
|
||||
loop.run_until_complete(task.callback(task_output))
|
||||
else:
|
||||
task.callback(task_output)
|
||||
except Exception as e:
|
||||
logger.error(f"Error executing task callback for task {task_id}: {e}")
|
||||
logger.exception(e)
|
||||
|
||||
self.save_output_to_file(task, task_output)
|
||||
if self.verbose >= 1:
|
||||
logging.info(f"Task {task_id} completed successfully.")
|
||||
logger.info(f"Task {task_id} completed successfully.")
|
||||
else:
|
||||
task.status = "in progress"
|
||||
if self.verbose >= 1:
|
||||
logging.info(f"Task {task_id} not completed, retrying")
|
||||
logger.info(f"Task {task_id} not completed, retrying")
|
||||
time.sleep(1)
|
||||
retries += 1
|
||||
else:
|
||||
if task.status == "failed":
|
||||
logging.info("Task is failed, resetting to in-progress for another try...")
|
||||
logger.info("Task is failed, resetting to in-progress for another try...")
|
||||
task.status = "in progress"
|
||||
else:
|
||||
logging.info("Invalid Task status")
|
||||
logger.info("Invalid Task status")
|
||||
break
|
||||
|
||||
if retries == self.max_retries and task.status != "completed":
|
||||
logging.info(f"Task {task_id} failed after {self.max_retries} retries.")
|
||||
logger.info(f"Task {task_id} failed after {self.max_retries} retries.")
|
||||
|
||||
def run_all_tasks(self):
|
||||
"""Synchronous version of run_all_tasks method"""
|
||||
|
||||
@@ -0,0 +1,335 @@
|
||||
"""
|
||||
AutoAgents - A class for automatically creating and managing AI agents and tasks.
|
||||
|
||||
This class provides a simplified interface for creating and running AI agents with tasks.
|
||||
It automatically handles agent creation, task setup, and execution flow.
|
||||
"""
|
||||
|
||||
from .agents import PraisonAIAgents
|
||||
from ..agent.agent import Agent
|
||||
from ..task.task import Task
|
||||
from typing import List, Any, Optional, Dict, Union
|
||||
import logging
|
||||
import os
|
||||
from pydantic import BaseModel, Field
|
||||
from ..main import display_instruction, display_tool_call, display_interaction, client
|
||||
|
||||
# Define Pydantic models for structured output
|
||||
class TaskConfig(BaseModel):
|
||||
name: str
|
||||
description: str
|
||||
expected_output: str
|
||||
tools: List[str]
|
||||
|
||||
class AgentConfig(BaseModel):
|
||||
name: str
|
||||
role: str
|
||||
goal: str
|
||||
backstory: str
|
||||
tools: List[str]
|
||||
tasks: List[TaskConfig]
|
||||
|
||||
class AutoAgentsConfig(BaseModel):
|
||||
main_instruction: str
|
||||
process_type: str
|
||||
agents: List[AgentConfig]
|
||||
|
||||
class AutoAgents(PraisonAIAgents):
|
||||
def __init__(
|
||||
self,
|
||||
instructions: str,
|
||||
tools: Optional[List[Any]] = None,
|
||||
verbose: bool = False,
|
||||
process: str = "sequential",
|
||||
manager_llm: Optional[str] = None,
|
||||
max_retries: int = 5,
|
||||
completion_checker: Optional[Any] = None,
|
||||
allow_code_execution: bool = False,
|
||||
memory: bool = True,
|
||||
markdown: bool = True,
|
||||
self_reflect: bool = False,
|
||||
max_reflect: int = 3,
|
||||
min_reflect: int = 1,
|
||||
llm: Optional[str] = None,
|
||||
function_calling_llm: Optional[str] = None,
|
||||
respect_context_window: bool = True,
|
||||
code_execution_mode: str = "safe",
|
||||
embedder_config: Optional[Dict[str, Any]] = None,
|
||||
knowledge_sources: Optional[List[Any]] = None,
|
||||
use_system_prompt: bool = True,
|
||||
cache: bool = True,
|
||||
allow_delegation: bool = False,
|
||||
step_callback: Optional[Any] = None,
|
||||
system_template: Optional[str] = None,
|
||||
prompt_template: Optional[str] = None,
|
||||
response_template: Optional[str] = None,
|
||||
max_rpm: Optional[int] = None,
|
||||
max_execution_time: Optional[int] = None,
|
||||
max_iter: int = 20,
|
||||
reflect_llm: Optional[str] = None,
|
||||
base_url: Optional[str] = None,
|
||||
api_key: Optional[str] = None,
|
||||
max_agents: int = 3 # New parameter for maximum number of agents
|
||||
):
|
||||
"""Initialize AutoAgents with configuration for automatic agent and task creation."""
|
||||
if max_agents < 1:
|
||||
raise ValueError("max_agents must be at least 1")
|
||||
if max_agents > 10:
|
||||
raise ValueError("max_agents cannot exceed 10")
|
||||
|
||||
# Store all configuration parameters first
|
||||
self.instructions = instructions
|
||||
self.tools = tools or []
|
||||
self.verbose = verbose # Store verbose parameter
|
||||
self.max_agents = max_agents # Store max_agents parameter
|
||||
self.allow_code_execution = allow_code_execution
|
||||
self.memory = memory
|
||||
self.markdown = markdown
|
||||
self.self_reflect = self_reflect
|
||||
self.max_reflect = max_reflect
|
||||
self.min_reflect = min_reflect
|
||||
self.llm = llm or os.getenv('OPENAI_MODEL_NAME', 'gpt-4o')
|
||||
self.function_calling_llm = function_calling_llm
|
||||
self.respect_context_window = respect_context_window
|
||||
self.code_execution_mode = code_execution_mode
|
||||
self.embedder_config = embedder_config
|
||||
self.knowledge_sources = knowledge_sources
|
||||
self.use_system_prompt = use_system_prompt
|
||||
self.cache = cache
|
||||
self.allow_delegation = allow_delegation
|
||||
self.step_callback = step_callback
|
||||
self.system_template = system_template
|
||||
self.prompt_template = prompt_template
|
||||
self.response_template = response_template
|
||||
self.max_rpm = max_rpm
|
||||
self.max_execution_time = max_execution_time
|
||||
self.max_iter = max_iter
|
||||
self.reflect_llm = reflect_llm
|
||||
|
||||
# Display initial instruction
|
||||
if self.verbose:
|
||||
display_instruction(f"🎯 Main Task: {self.instructions}")
|
||||
display_instruction(f"📊 Maximum Agents: {self.max_agents}")
|
||||
if self.tools:
|
||||
tool_names = [t.__name__ if hasattr(t, '__name__') else str(t) for t in self.tools]
|
||||
display_tool_call(f"🛠️ Available Tools: {', '.join(tool_names)}")
|
||||
|
||||
# Generate agents and tasks configuration
|
||||
config = self._generate_config()
|
||||
agents, tasks = self._create_agents_and_tasks(config)
|
||||
|
||||
# Display agents and their tasks
|
||||
if self.verbose:
|
||||
self._display_agents_and_tasks(agents, tasks)
|
||||
|
||||
# Initialize parent class with generated agents and tasks
|
||||
super().__init__(
|
||||
agents=agents,
|
||||
tasks=tasks,
|
||||
verbose=verbose,
|
||||
completion_checker=completion_checker,
|
||||
max_retries=max_retries,
|
||||
process=process,
|
||||
manager_llm=manager_llm
|
||||
)
|
||||
|
||||
def _display_agents_and_tasks(self, agents: List[Agent], tasks: List[Task]):
|
||||
"""Display the created agents and their assigned tasks"""
|
||||
display_instruction("\n🤖 Generated Agents and Tasks:")
|
||||
|
||||
# Create a mapping of agents to their tasks
|
||||
agent_tasks = {}
|
||||
for task in tasks:
|
||||
if task.agent not in agent_tasks:
|
||||
agent_tasks[task.agent] = []
|
||||
agent_tasks[task.agent].append(task)
|
||||
|
||||
# Display each agent and their tasks
|
||||
for agent in agents:
|
||||
agent_tools = [t.__name__ if hasattr(t, '__name__') else str(t) for t in agent.tools]
|
||||
display_interaction(
|
||||
f"\n👤 Agent: {agent.name}",
|
||||
f"""Role: {agent.role}
|
||||
Goal: {agent.goal}
|
||||
Tools: {', '.join(agent_tools)}"""
|
||||
)
|
||||
|
||||
# Display tasks for this agent
|
||||
if agent in agent_tasks:
|
||||
for i, task in enumerate(agent_tasks[agent], 1):
|
||||
task_tools = [t.__name__ if hasattr(t, '__name__') else str(t) for t in task.tools]
|
||||
display_instruction(
|
||||
f""" 📋 Task {i}: {task.name}
|
||||
Description: {task.description}
|
||||
Expected Output: {task.expected_output}
|
||||
Tools: {', '.join(task_tools)}"""
|
||||
)
|
||||
|
||||
def _get_available_tools(self) -> List[str]:
|
||||
"""Get list of available tools"""
|
||||
if not self.tools:
|
||||
return []
|
||||
return [t.__name__ if hasattr(t, '__name__') else str(t) for t in self.tools]
|
||||
|
||||
def _get_tool_by_name(self, tool_name: str) -> Optional[Any]:
|
||||
"""Get tool object by its name"""
|
||||
for tool in self.tools:
|
||||
if (hasattr(tool, '__name__') and tool.__name__ == tool_name) or str(tool) == tool_name:
|
||||
return tool
|
||||
return None
|
||||
|
||||
def _assign_tools_to_agent(self, agent_config: AgentConfig) -> List[Any]:
|
||||
"""
|
||||
Assign appropriate tools to an agent based on its role and tasks.
|
||||
|
||||
Args:
|
||||
agent_config: The agent configuration containing role and required tools
|
||||
|
||||
Returns:
|
||||
List of tool objects assigned to this agent
|
||||
"""
|
||||
assigned_tools = []
|
||||
tool_names = set(agent_config.tools)
|
||||
|
||||
# Also look at task requirements
|
||||
for task in agent_config.tasks:
|
||||
tool_names.update(task.tools)
|
||||
|
||||
# Assign tools that match the requirements
|
||||
for tool_name in tool_names:
|
||||
tool = self._get_tool_by_name(tool_name)
|
||||
if tool:
|
||||
assigned_tools.append(tool)
|
||||
|
||||
# If no specific tools matched but we have tools available,
|
||||
# assign all tools to ensure functionality
|
||||
if not assigned_tools and self.tools:
|
||||
assigned_tools = self.tools
|
||||
|
||||
return assigned_tools
|
||||
|
||||
def _generate_config(self) -> AutoAgentsConfig:
|
||||
"""Generate the configuration for agents and tasks"""
|
||||
prompt = f"""
|
||||
Generate a configuration for AI agents to accomplish this task: "{self.instructions}"
|
||||
|
||||
The configuration should include:
|
||||
1. A main instruction that clearly states the overall goal
|
||||
2. A process type (sequential, workflow, or hierarchical)
|
||||
3. A list of maximum {self.max_agents} agents (no more, no less), each with:
|
||||
- Name, role, goal, and backstory
|
||||
- List of required tools from: {self._get_available_tools()}
|
||||
- Only add tools that are needed for the agent to perform its task
|
||||
- Only one task per agent. Add more than one task if absolutely necessary.
|
||||
- List of specific tasks they need to perform
|
||||
- Whether they should self-reflect or allow delegation
|
||||
|
||||
Requirements:
|
||||
1. Each agent should have clear, focused responsibilities
|
||||
2. Tasks should be broken down into manageable steps
|
||||
3. Tool selection should be appropriate for each task
|
||||
4. The process type should match the task requirements
|
||||
5. Generate maximum {self.max_agents} agents to handle this task efficiently
|
||||
|
||||
Return the configuration in a structured JSON format matching the AutoAgentsConfig schema.
|
||||
"""
|
||||
|
||||
try:
|
||||
response = client.beta.chat.completions.parse(
|
||||
model=self.llm,
|
||||
response_format=AutoAgentsConfig,
|
||||
messages=[
|
||||
{"role": "system", "content": "You are a helpful assistant designed to generate AI agent configurations."},
|
||||
{"role": "user", "content": prompt}
|
||||
]
|
||||
)
|
||||
|
||||
# Ensure we have exactly max_agents number of agents
|
||||
if len(response.choices[0].message.parsed.agents) > self.max_agents:
|
||||
response.choices[0].message.parsed.agents = response.choices[0].message.parsed.agents[:self.max_agents]
|
||||
elif len(response.choices[0].message.parsed.agents) < self.max_agents:
|
||||
logging.warning(f"Generated {len(response.choices[0].message.parsed.agents)} agents, expected {self.max_agents}")
|
||||
|
||||
return response.choices[0].message.parsed
|
||||
except Exception as e:
|
||||
logging.error(f"Error generating configuration: {e}")
|
||||
raise
|
||||
|
||||
def _create_agents_and_tasks(self, config: AutoAgentsConfig) -> tuple[List[Agent], List[Task]]:
|
||||
"""Create agents and tasks from configuration"""
|
||||
agents = []
|
||||
tasks = []
|
||||
|
||||
for agent_config in config.agents:
|
||||
# Get appropriate tools for this agent
|
||||
agent_tools = self._assign_tools_to_agent(agent_config)
|
||||
|
||||
# Create the agent with all parameters
|
||||
agent = Agent(
|
||||
name=agent_config.name,
|
||||
role=agent_config.role,
|
||||
goal=agent_config.goal,
|
||||
backstory=agent_config.backstory,
|
||||
tools=agent_tools, # Use assigned tools
|
||||
verbose=self.verbose >= 1,
|
||||
allow_code_execution=self.allow_code_execution,
|
||||
memory=self.memory,
|
||||
markdown=self.markdown,
|
||||
self_reflect=self.self_reflect,
|
||||
max_reflect=self.max_reflect,
|
||||
min_reflect=self.min_reflect,
|
||||
llm=self.llm,
|
||||
function_calling_llm=self.function_calling_llm,
|
||||
respect_context_window=self.respect_context_window,
|
||||
code_execution_mode=self.code_execution_mode,
|
||||
embedder_config=self.embedder_config,
|
||||
knowledge_sources=self.knowledge_sources,
|
||||
use_system_prompt=self.use_system_prompt,
|
||||
cache=self.cache,
|
||||
allow_delegation=self.allow_delegation,
|
||||
step_callback=self.step_callback,
|
||||
system_template=self.system_template,
|
||||
prompt_template=self.prompt_template,
|
||||
response_template=self.response_template,
|
||||
max_rpm=self.max_rpm,
|
||||
max_execution_time=self.max_execution_time,
|
||||
max_iter=self.max_iter,
|
||||
reflect_llm=self.reflect_llm
|
||||
)
|
||||
agents.append(agent)
|
||||
|
||||
# Create tasks for this agent
|
||||
for task_config in agent_config.tasks:
|
||||
# Get task-specific tools
|
||||
task_tools = [self._get_tool_by_name(t) for t in task_config.tools]
|
||||
task_tools = [t for t in task_tools if t] # Remove None values
|
||||
|
||||
# If no specific tools matched, use agent's tools
|
||||
if not task_tools:
|
||||
task_tools = agent_tools
|
||||
|
||||
task = Task(
|
||||
name=task_config.name,
|
||||
description=task_config.description,
|
||||
expected_output=task_config.expected_output,
|
||||
agent=agent,
|
||||
tools=task_tools # Use task-specific tools
|
||||
)
|
||||
tasks.append(task)
|
||||
|
||||
return agents, tasks
|
||||
|
||||
async def astart(self):
|
||||
"""
|
||||
Async version of start() method.
|
||||
Creates tasks based on the instructions, then starts execution.
|
||||
Returns the task status and results dictionary.
|
||||
"""
|
||||
return await super().astart()
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Creates tasks based on the instructions, then starts execution.
|
||||
Returns the task status and results dictionary.
|
||||
"""
|
||||
return super().start()
|
||||
@@ -116,10 +116,10 @@ def display_interaction(message, response, markdown=True, generation_time=None,
|
||||
console.print(Text(f"Response generated in {generation_time:.1f}s", style="dim"))
|
||||
|
||||
if markdown:
|
||||
console.print(Panel.fit(Markdown(message), title="Message", border_style="cyan"))
|
||||
console.print(Panel.fit(Markdown(message), title="Task", border_style="cyan"))
|
||||
console.print(Panel.fit(Markdown(response), title="Response", border_style="cyan"))
|
||||
else:
|
||||
console.print(Panel.fit(Text(message, style="bold green"), title="Message", border_style="cyan"))
|
||||
console.print(Panel.fit(Text(message, style="bold green"), title="Task", border_style="cyan"))
|
||||
console.print(Panel.fit(Text(response, style="bold blue"), title="Response", border_style="cyan"))
|
||||
|
||||
def display_self_reflection(message: str, console=None):
|
||||
@@ -135,7 +135,7 @@ def display_self_reflection(message: str, console=None):
|
||||
|
||||
console.print(Panel.fit(Text(message, style="bold yellow"), title="Self Reflection", border_style="magenta"))
|
||||
|
||||
def display_instruction(message: str, console=None):
|
||||
def display_instruction(message: str, console=None, agent_name: str = None, agent_role: str = None, agent_tools: List[str] = None):
|
||||
if not message or not message.strip():
|
||||
return
|
||||
if console is None:
|
||||
@@ -146,7 +146,19 @@ def display_instruction(message: str, console=None):
|
||||
if 'instruction' in sync_display_callbacks:
|
||||
sync_display_callbacks['instruction'](message=message)
|
||||
|
||||
console.print(Panel.fit(Text(message, style="bold blue"), title="Instruction", border_style="cyan"))
|
||||
# Display agent info if available
|
||||
if agent_name:
|
||||
agent_info = f"[bold #FF9B9B]👤 Agent:[/] [#FFE5E5]{agent_name}[/]"
|
||||
if agent_role:
|
||||
agent_info += f"\n[bold #B4B4B3]Role:[/] [#FFE5E5]{agent_role}[/]"
|
||||
if agent_tools:
|
||||
tools_str = ", ".join(f"[italic #B4D4FF]{tool}[/]" for tool in agent_tools)
|
||||
agent_info += f"\n[bold #86A789]Tools:[/] {tools_str}"
|
||||
console.print(Panel(agent_info, border_style="#D2E3C8", title="[bold]Agent Info[/]", title_align="left", padding=(1, 2)))
|
||||
|
||||
# Only print if log level is DEBUG
|
||||
if logging.getLogger().getEffectiveLevel() == logging.DEBUG:
|
||||
console.print(Panel.fit(Text(message, style="bold blue"), title="Instruction", border_style="cyan"))
|
||||
|
||||
def display_tool_call(message: str, console=None):
|
||||
if not message or not message.strip():
|
||||
@@ -222,10 +234,10 @@ async def adisplay_interaction(message, response, markdown=True, generation_time
|
||||
console.print(Text(f"Response generated in {generation_time:.1f}s", style="dim"))
|
||||
|
||||
if markdown:
|
||||
console.print(Panel.fit(Markdown(message), title="Message", border_style="cyan"))
|
||||
console.print(Panel.fit(Markdown(message), title="Task", border_style="cyan"))
|
||||
console.print(Panel.fit(Markdown(response), title="Response", border_style="cyan"))
|
||||
else:
|
||||
console.print(Panel.fit(Text(message, style="bold green"), title="Message", border_style="cyan"))
|
||||
console.print(Panel.fit(Text(message, style="bold green"), title="Task", border_style="cyan"))
|
||||
console.print(Panel.fit(Text(response, style="bold blue"), title="Response", border_style="cyan"))
|
||||
|
||||
async def adisplay_self_reflection(message: str, console=None):
|
||||
@@ -241,7 +253,7 @@ async def adisplay_self_reflection(message: str, console=None):
|
||||
|
||||
console.print(Panel.fit(Text(message, style="bold yellow"), title="Self Reflection", border_style="magenta"))
|
||||
|
||||
async def adisplay_instruction(message: str, console=None):
|
||||
async def adisplay_instruction(message: str, console=None, agent_name: str = None, agent_role: str = None, agent_tools: List[str] = None):
|
||||
"""Async version of display_instruction."""
|
||||
if not message or not message.strip():
|
||||
return
|
||||
@@ -252,7 +264,19 @@ async def adisplay_instruction(message: str, console=None):
|
||||
if 'instruction' in async_display_callbacks:
|
||||
await async_display_callbacks['instruction'](message=message)
|
||||
|
||||
console.print(Panel.fit(Text(message, style="bold blue"), title="Instruction", border_style="cyan"))
|
||||
# Display agent info if available
|
||||
if agent_name:
|
||||
agent_info = f"[bold #FF9B9B]👤 Agent:[/] [#FFE5E5]{agent_name}[/]"
|
||||
if agent_role:
|
||||
agent_info += f"\n[bold #B4B4B3]Role:[/] [#FFE5E5]{agent_role}[/]"
|
||||
if agent_tools:
|
||||
tools_str = ", ".join(f"[italic #B4D4FF]{tool}[/]" for tool in agent_tools)
|
||||
agent_info += f"\n[bold #86A789]Tools:[/] {tools_str}"
|
||||
console.print(Panel(agent_info, border_style="#D2E3C8", title="[bold]Agent Info[/]", title_align="left", padding=(1, 2)))
|
||||
|
||||
# Only print if log level is DEBUG
|
||||
if logging.getLogger().getEffectiveLevel() == logging.DEBUG:
|
||||
console.print(Panel.fit(Text(message, style="bold blue"), title="Instruction", border_style="cyan"))
|
||||
|
||||
async def adisplay_tool_call(message: str, console=None):
|
||||
"""Async version of display_tool_call."""
|
||||
|
||||
@@ -0,0 +1,931 @@
|
||||
import os
|
||||
import sqlite3
|
||||
import json
|
||||
import time
|
||||
import shutil
|
||||
from typing import Any, Dict, List, Optional, Union, Literal
|
||||
import logging
|
||||
|
||||
# Set up logger
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import chromadb
|
||||
from chromadb.config import Settings as ChromaSettings
|
||||
CHROMADB_AVAILABLE = True
|
||||
except ImportError:
|
||||
CHROMADB_AVAILABLE = False
|
||||
logger.warning("To use memory features, please run: pip install \"praisonaiagents[memory]\"")
|
||||
|
||||
try:
|
||||
import mem0
|
||||
MEM0_AVAILABLE = True
|
||||
except ImportError:
|
||||
MEM0_AVAILABLE = False
|
||||
|
||||
try:
|
||||
import openai
|
||||
OPENAI_AVAILABLE = True
|
||||
except ImportError:
|
||||
OPENAI_AVAILABLE = False
|
||||
|
||||
|
||||
|
||||
|
||||
class Memory:
|
||||
"""
|
||||
A single-file memory manager covering:
|
||||
- Short-term memory (STM) for ephemeral context
|
||||
- Long-term memory (LTM) for persistent knowledge
|
||||
- Entity memory (structured data about named entities)
|
||||
- User memory (preferences/history for each user)
|
||||
- Quality score logic for deciding which data to store in LTM
|
||||
- Context building from multiple memory sources
|
||||
|
||||
Config example:
|
||||
{
|
||||
"provider": "rag" or "mem0" or "none",
|
||||
"use_embedding": True,
|
||||
"short_db": "short_term.db",
|
||||
"long_db": "long_term.db",
|
||||
"rag_db_path": "rag_db", # optional path for local embedding store
|
||||
"config": {
|
||||
"api_key": "...", # if mem0 usage
|
||||
"org_id": "...",
|
||||
"project_id": "...",
|
||||
...
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(self, config: Dict[str, Any], verbose: int = 0):
|
||||
self.cfg = config or {}
|
||||
self.verbose = verbose
|
||||
|
||||
# Set logger level based on verbose
|
||||
if verbose >= 5:
|
||||
logger.setLevel(logging.INFO)
|
||||
else:
|
||||
logger.setLevel(logging.WARNING)
|
||||
|
||||
# Also set ChromaDB and OpenAI client loggers to WARNING
|
||||
logging.getLogger('chromadb').setLevel(logging.WARNING)
|
||||
logging.getLogger('openai').setLevel(logging.WARNING)
|
||||
logging.getLogger('httpx').setLevel(logging.WARNING)
|
||||
logging.getLogger('httpcore').setLevel(logging.WARNING)
|
||||
logging.getLogger('chromadb.segment.impl.vector.local_persistent_hnsw').setLevel(logging.ERROR)
|
||||
|
||||
self.provider = self.cfg.get("provider", "rag")
|
||||
self.use_mem0 = (self.provider.lower() == "mem0") and MEM0_AVAILABLE
|
||||
self.use_rag = (self.provider.lower() == "rag") and CHROMADB_AVAILABLE and self.cfg.get("use_embedding", False)
|
||||
|
||||
# Create .praison directory if it doesn't exist
|
||||
os.makedirs(".praison", exist_ok=True)
|
||||
|
||||
# Short-term DB
|
||||
self.short_db = self.cfg.get("short_db", ".praison/short_term.db")
|
||||
self._init_stm()
|
||||
|
||||
# Long-term DB
|
||||
self.long_db = self.cfg.get("long_db", ".praison/long_term.db")
|
||||
self._init_ltm()
|
||||
|
||||
# Conditionally init Mem0 or local RAG
|
||||
if self.use_mem0:
|
||||
self._init_mem0()
|
||||
elif self.use_rag:
|
||||
self._init_chroma()
|
||||
|
||||
def _log_verbose(self, msg: str, level: int = logging.INFO):
|
||||
"""Only log if verbose >= 5"""
|
||||
if self.verbose >= 5:
|
||||
logger.log(level, msg)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Initialization
|
||||
# -------------------------------------------------------------------------
|
||||
def _init_stm(self):
|
||||
"""Creates or verifies short-term memory table."""
|
||||
os.makedirs(os.path.dirname(self.short_db) or ".", exist_ok=True)
|
||||
conn = sqlite3.connect(self.short_db)
|
||||
c = conn.cursor()
|
||||
c.execute("""
|
||||
CREATE TABLE IF NOT EXISTS short_mem (
|
||||
id TEXT PRIMARY KEY,
|
||||
content TEXT,
|
||||
meta TEXT,
|
||||
created_at REAL
|
||||
)
|
||||
""")
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def _init_ltm(self):
|
||||
"""Creates or verifies long-term memory table."""
|
||||
os.makedirs(os.path.dirname(self.long_db) or ".", exist_ok=True)
|
||||
conn = sqlite3.connect(self.long_db)
|
||||
c = conn.cursor()
|
||||
c.execute("""
|
||||
CREATE TABLE IF NOT EXISTS long_mem (
|
||||
id TEXT PRIMARY KEY,
|
||||
content TEXT,
|
||||
meta TEXT,
|
||||
created_at REAL
|
||||
)
|
||||
""")
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def _init_mem0(self):
|
||||
"""Initialize Mem0 client for agent or user memory."""
|
||||
from mem0 import MemoryClient
|
||||
mem_cfg = self.cfg.get("config", {})
|
||||
api_key = mem_cfg.get("api_key", os.getenv("MEM0_API_KEY"))
|
||||
org_id = mem_cfg.get("org_id")
|
||||
proj_id = mem_cfg.get("project_id")
|
||||
if org_id and proj_id:
|
||||
self.mem0_client = MemoryClient(api_key=api_key, org_id=org_id, project_id=proj_id)
|
||||
else:
|
||||
self.mem0_client = MemoryClient(api_key=api_key)
|
||||
|
||||
def _init_chroma(self):
|
||||
"""Initialize a local Chroma client for embedding-based search."""
|
||||
try:
|
||||
# Create directory if it doesn't exist
|
||||
rag_path = self.cfg.get("rag_db_path", "chroma_db")
|
||||
os.makedirs(rag_path, exist_ok=True)
|
||||
|
||||
# Initialize ChromaDB with persistent storage
|
||||
self.chroma_client = chromadb.PersistentClient(
|
||||
path=rag_path,
|
||||
settings=ChromaSettings(
|
||||
anonymized_telemetry=False,
|
||||
allow_reset=True
|
||||
)
|
||||
)
|
||||
|
||||
collection_name = "memory_store"
|
||||
try:
|
||||
self.chroma_col = self.chroma_client.get_collection(name=collection_name)
|
||||
self._log_verbose("Using existing ChromaDB collection")
|
||||
except Exception as e:
|
||||
self._log_verbose(f"Collection '{collection_name}' not found. Creating new collection. Error: {e}")
|
||||
self.chroma_col = self.chroma_client.create_collection(
|
||||
name=collection_name,
|
||||
metadata={"hnsw:space": "cosine"}
|
||||
)
|
||||
self._log_verbose("Created new ChromaDB collection")
|
||||
|
||||
except Exception as e:
|
||||
self._log_verbose(f"Failed to initialize ChromaDB: {e}", logging.ERROR)
|
||||
self.use_rag = False
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Basic Quality Score Computation
|
||||
# -------------------------------------------------------------------------
|
||||
def compute_quality_score(
|
||||
self,
|
||||
completeness: float,
|
||||
relevance: float,
|
||||
clarity: float,
|
||||
accuracy: float,
|
||||
weights: Dict[str, float] = None
|
||||
) -> float:
|
||||
"""
|
||||
Combine multiple sub-metrics into one final score, as an example.
|
||||
|
||||
Args:
|
||||
completeness (float): 0-1
|
||||
relevance (float): 0-1
|
||||
clarity (float): 0-1
|
||||
accuracy (float): 0-1
|
||||
weights (Dict[str, float]): optional weighting like {"completeness": 0.25, "relevance": 0.3, ...}
|
||||
|
||||
Returns:
|
||||
float: Weighted average 0-1
|
||||
"""
|
||||
if not weights:
|
||||
weights = {
|
||||
"completeness": 0.25,
|
||||
"relevance": 0.25,
|
||||
"clarity": 0.25,
|
||||
"accuracy": 0.25
|
||||
}
|
||||
total = (completeness * weights["completeness"]
|
||||
+ relevance * weights["relevance"]
|
||||
+ clarity * weights["clarity"]
|
||||
+ accuracy * weights["accuracy"]
|
||||
)
|
||||
return round(total, 3) # e.g. round to 3 decimal places
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Short-Term Methods
|
||||
# -------------------------------------------------------------------------
|
||||
def store_short_term(
|
||||
self,
|
||||
text: str,
|
||||
metadata: Dict[str, Any] = None,
|
||||
completeness: float = None,
|
||||
relevance: float = None,
|
||||
clarity: float = None,
|
||||
accuracy: float = None,
|
||||
weights: Dict[str, float] = None,
|
||||
evaluator_quality: float = None
|
||||
):
|
||||
"""Store in short-term memory with optional quality metrics"""
|
||||
logger.info(f"Storing in short-term memory: {text[:100]}...")
|
||||
logger.info(f"Metadata: {metadata}")
|
||||
|
||||
metadata = self._process_quality_metrics(
|
||||
metadata, completeness, relevance, clarity,
|
||||
accuracy, weights, evaluator_quality
|
||||
)
|
||||
logger.info(f"Processed metadata: {metadata}")
|
||||
|
||||
# Existing store logic
|
||||
try:
|
||||
conn = sqlite3.connect(self.short_db)
|
||||
ident = str(time.time_ns())
|
||||
conn.execute(
|
||||
"INSERT INTO short_mem (id, content, meta, created_at) VALUES (?,?,?,?)",
|
||||
(ident, text, json.dumps(metadata), time.time())
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
logger.info(f"Successfully stored in short-term memory with ID: {ident}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to store in short-term memory: {e}")
|
||||
raise
|
||||
|
||||
def search_short_term(
|
||||
self,
|
||||
query: str,
|
||||
limit: int = 5,
|
||||
min_quality: float = 0.0,
|
||||
relevance_cutoff: float = 0.0
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Search short-term memory with optional quality filter"""
|
||||
self._log_verbose(f"Searching short memory for: {query}")
|
||||
|
||||
if self.use_mem0 and hasattr(self, "mem0_client"):
|
||||
results = self.mem0_client.search(query=query, limit=limit)
|
||||
filtered = [r for r in results if r.get("score", 1.0) >= relevance_cutoff]
|
||||
return filtered
|
||||
|
||||
elif self.use_rag and hasattr(self, "chroma_col"):
|
||||
try:
|
||||
from openai import OpenAI
|
||||
client = OpenAI()
|
||||
|
||||
response = client.embeddings.create(
|
||||
input=query,
|
||||
model="text-embedding-3-small"
|
||||
)
|
||||
query_embedding = response.data[0].embedding
|
||||
|
||||
resp = self.chroma_col.query(
|
||||
query_embeddings=[query_embedding],
|
||||
n_results=limit
|
||||
)
|
||||
|
||||
results = []
|
||||
if resp["ids"]:
|
||||
for i in range(len(resp["ids"][0])):
|
||||
metadata = resp["metadatas"][0][i] if "metadatas" in resp else {}
|
||||
quality = metadata.get("quality", 0.0)
|
||||
score = 1.0 - (resp["distances"][0][i] if "distances" in resp else 0.0)
|
||||
if quality >= min_quality and score >= relevance_cutoff:
|
||||
results.append({
|
||||
"id": resp["ids"][0][i],
|
||||
"text": resp["documents"][0][i],
|
||||
"metadata": metadata,
|
||||
"score": score
|
||||
})
|
||||
return results
|
||||
except Exception as e:
|
||||
self._log_verbose(f"Error searching ChromaDB: {e}", logging.ERROR)
|
||||
return []
|
||||
|
||||
else:
|
||||
# Local fallback
|
||||
conn = sqlite3.connect(self.short_db)
|
||||
c = conn.cursor()
|
||||
rows = c.execute(
|
||||
"SELECT id, content, meta FROM short_mem WHERE content LIKE ? LIMIT ?",
|
||||
(f"%{query}%", limit)
|
||||
).fetchall()
|
||||
conn.close()
|
||||
|
||||
results = []
|
||||
for row in rows:
|
||||
meta = json.loads(row[2] or "{}")
|
||||
quality = meta.get("quality", 0.0)
|
||||
if quality >= min_quality:
|
||||
results.append({
|
||||
"id": row[0],
|
||||
"text": row[1],
|
||||
"metadata": meta
|
||||
})
|
||||
return results
|
||||
|
||||
def reset_short_term(self):
|
||||
"""Completely clears short-term memory."""
|
||||
conn = sqlite3.connect(self.short_db)
|
||||
conn.execute("DELETE FROM short_mem")
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Long-Term Methods
|
||||
# -------------------------------------------------------------------------
|
||||
def _sanitize_metadata(self, metadata: Dict) -> Dict:
|
||||
"""Sanitize metadata for ChromaDB - convert to acceptable types"""
|
||||
sanitized = {}
|
||||
for k, v in metadata.items():
|
||||
if v is None:
|
||||
continue
|
||||
if isinstance(v, (str, int, float, bool)):
|
||||
sanitized[k] = v
|
||||
elif isinstance(v, dict):
|
||||
# Convert dict to string representation
|
||||
sanitized[k] = str(v)
|
||||
else:
|
||||
# Convert other types to string
|
||||
sanitized[k] = str(v)
|
||||
return sanitized
|
||||
|
||||
def store_long_term(
|
||||
self,
|
||||
text: str,
|
||||
metadata: Dict[str, Any] = None,
|
||||
completeness: float = None,
|
||||
relevance: float = None,
|
||||
clarity: float = None,
|
||||
accuracy: float = None,
|
||||
weights: Dict[str, float] = None,
|
||||
evaluator_quality: float = None
|
||||
):
|
||||
"""Store in long-term memory with optional quality metrics"""
|
||||
logger.info(f"Storing in long-term memory: {text[:100]}...")
|
||||
logger.info(f"Initial metadata: {metadata}")
|
||||
|
||||
# Process metadata
|
||||
metadata = metadata or {}
|
||||
metadata = self._process_quality_metrics(
|
||||
metadata, completeness, relevance, clarity,
|
||||
accuracy, weights, evaluator_quality
|
||||
)
|
||||
logger.info(f"Processed metadata: {metadata}")
|
||||
|
||||
# Generate unique ID
|
||||
ident = str(time.time_ns())
|
||||
created = time.time()
|
||||
|
||||
# Store in SQLite
|
||||
try:
|
||||
conn = sqlite3.connect(self.long_db)
|
||||
conn.execute(
|
||||
"INSERT INTO long_mem (id, content, meta, created_at) VALUES (?,?,?,?)",
|
||||
(ident, text, json.dumps(metadata), created)
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
logger.info(f"Successfully stored in SQLite with ID: {ident}")
|
||||
except Exception as e:
|
||||
logger.error(f"Error storing in SQLite: {e}")
|
||||
return
|
||||
|
||||
# Store in vector database if enabled
|
||||
if self.use_rag and hasattr(self, "chroma_col"):
|
||||
try:
|
||||
from openai import OpenAI
|
||||
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) # Ensure API key is correctly set
|
||||
|
||||
logger.info("Getting embeddings from OpenAI...")
|
||||
logger.debug(f"Embedding input text: {text}") # Log the input text
|
||||
|
||||
response = client.embeddings.create(
|
||||
input=text,
|
||||
model="text-embedding-3-small"
|
||||
)
|
||||
embedding = response.data[0].embedding
|
||||
logger.info("Successfully got embeddings")
|
||||
logger.debug(f"Received embedding of length: {len(embedding)}") # Log embedding details
|
||||
|
||||
# Sanitize metadata for ChromaDB
|
||||
sanitized_metadata = self._sanitize_metadata(metadata)
|
||||
|
||||
# Store in ChromaDB with embedding
|
||||
self.chroma_col.add(
|
||||
documents=[text],
|
||||
metadatas=[sanitized_metadata],
|
||||
ids=[ident],
|
||||
embeddings=[embedding]
|
||||
)
|
||||
logger.info(f"Successfully stored in ChromaDB with ID: {ident}")
|
||||
except Exception as e:
|
||||
logger.error(f"Error storing in ChromaDB: {e}")
|
||||
|
||||
elif self.use_mem0 and hasattr(self, "mem0_client"):
|
||||
try:
|
||||
self.mem0_client.add(text, metadata=metadata)
|
||||
logger.info("Successfully stored in Mem0")
|
||||
except Exception as e:
|
||||
logger.error(f"Error storing in Mem0: {e}")
|
||||
|
||||
|
||||
def search_long_term(
|
||||
self,
|
||||
query: str,
|
||||
limit: int = 5,
|
||||
relevance_cutoff: float = 0.0,
|
||||
min_quality: float = 0.0
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Search long-term memory with optional quality filter"""
|
||||
self._log_verbose(f"Searching long memory for: {query}")
|
||||
self._log_verbose(f"Min quality: {min_quality}")
|
||||
|
||||
found = []
|
||||
|
||||
if self.use_mem0 and hasattr(self, "mem0_client"):
|
||||
results = self.mem0_client.search(query=query, limit=limit)
|
||||
# Filter by quality
|
||||
filtered = [r for r in results if r.get("metadata", {}).get("quality", 0.0) >= min_quality]
|
||||
logger.info(f"Found {len(filtered)} results in Mem0")
|
||||
return filtered
|
||||
|
||||
elif self.use_rag and hasattr(self, "chroma_col"):
|
||||
try:
|
||||
from openai import OpenAI
|
||||
client = OpenAI()
|
||||
|
||||
# Get query embedding
|
||||
response = client.embeddings.create(
|
||||
input=query,
|
||||
model="text-embedding-3-small" # Using consistent model
|
||||
)
|
||||
query_embedding = response.data[0].embedding
|
||||
|
||||
# Search ChromaDB with embedding
|
||||
resp = self.chroma_col.query(
|
||||
query_embeddings=[query_embedding],
|
||||
n_results=limit,
|
||||
include=["documents", "metadatas", "distances"]
|
||||
)
|
||||
|
||||
results = []
|
||||
if resp["ids"]:
|
||||
for i in range(len(resp["ids"][0])):
|
||||
metadata = resp["metadatas"][0][i] if "metadatas" in resp else {}
|
||||
text = resp["documents"][0][i]
|
||||
# Add memory record citation
|
||||
text = f"{text} (Memory record: {text})"
|
||||
found.append({
|
||||
"id": resp["ids"][0][i],
|
||||
"text": text,
|
||||
"metadata": metadata,
|
||||
"score": 1.0 - (resp["distances"][0][i] if "distances" in resp else 0.0)
|
||||
})
|
||||
logger.info(f"Found {len(found)} results in ChromaDB")
|
||||
|
||||
except Exception as e:
|
||||
self._log_verbose(f"Error searching ChromaDB: {e}", logging.ERROR)
|
||||
|
||||
# Always try SQLite as fallback or additional source
|
||||
conn = sqlite3.connect(self.long_db)
|
||||
c = conn.cursor()
|
||||
rows = c.execute(
|
||||
"SELECT id, content, meta, created_at FROM long_mem WHERE content LIKE ? LIMIT ?",
|
||||
(f"%{query}%", limit)
|
||||
).fetchall()
|
||||
conn.close()
|
||||
|
||||
for row in rows:
|
||||
meta = json.loads(row[2] or "{}")
|
||||
text = row[1]
|
||||
# Add memory record citation if not already present
|
||||
if "(Memory record:" not in text:
|
||||
text = f"{text} (Memory record: {text})"
|
||||
# Only add if not already found by ChromaDB/Mem0
|
||||
if not any(f["id"] == row[0] for f in found):
|
||||
found.append({
|
||||
"id": row[0],
|
||||
"text": text,
|
||||
"metadata": meta,
|
||||
"created_at": row[3]
|
||||
})
|
||||
logger.info(f"Found {len(found)} total results after SQLite")
|
||||
|
||||
results = found
|
||||
|
||||
# Filter by quality if needed
|
||||
if min_quality > 0:
|
||||
self._log_verbose(f"Found {len(results)} initial results")
|
||||
results = [
|
||||
r for r in results
|
||||
if r.get("metadata", {}).get("quality", 0.0) >= min_quality
|
||||
]
|
||||
self._log_verbose(f"After quality filter: {len(results)} results")
|
||||
|
||||
# Apply relevance cutoff if specified
|
||||
if relevance_cutoff > 0:
|
||||
results = [r for r in results if r.get("score", 1.0) >= relevance_cutoff]
|
||||
logger.info(f"After relevance filter: {len(results)} results")
|
||||
|
||||
return results[:limit]
|
||||
|
||||
def reset_long_term(self):
|
||||
"""Clear local LTM DB, plus Chroma or mem0 if in use."""
|
||||
conn = sqlite3.connect(self.long_db)
|
||||
conn.execute("DELETE FROM long_mem")
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
if self.use_mem0 and hasattr(self, "mem0_client"):
|
||||
# Mem0 has no universal reset API. Could implement partial or no-op.
|
||||
pass
|
||||
if self.use_rag and hasattr(self, "chroma_client"):
|
||||
self.chroma_client.reset() # entire DB
|
||||
self._init_chroma() # re-init fresh
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Entity Memory Methods
|
||||
# -------------------------------------------------------------------------
|
||||
def store_entity(self, name: str, type_: str, desc: str, relations: str):
|
||||
"""
|
||||
Save entity info in LTM (or mem0/rag).
|
||||
We'll label the metadata type = entity for easy filtering.
|
||||
"""
|
||||
data = f"Entity {name}({type_}): {desc} | relationships: {relations}"
|
||||
self.store_long_term(data, metadata={"category": "entity"})
|
||||
|
||||
def search_entity(self, query: str, limit: int = 5) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Filter to items that have metadata 'category=entity'.
|
||||
"""
|
||||
all_hits = self.search_long_term(query, limit=20) # gather more
|
||||
ents = []
|
||||
for h in all_hits:
|
||||
meta = h.get("metadata") or {}
|
||||
if meta.get("category") == "entity":
|
||||
ents.append(h)
|
||||
return ents[:limit]
|
||||
|
||||
def reset_entity_only(self):
|
||||
"""
|
||||
If you only want to drop entity items from LTM, you'd do a custom
|
||||
delete from local DB where meta LIKE '%category=entity%'.
|
||||
For brevity, we do a full LTM reset here.
|
||||
"""
|
||||
self.reset_long_term()
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# User Memory Methods
|
||||
# -------------------------------------------------------------------------
|
||||
def store_user_memory(self, user_id: str, text: str, extra: Dict[str, Any] = None):
|
||||
"""
|
||||
If mem0 is used, do user-based addition. Otherwise store in LTM with user in metadata.
|
||||
"""
|
||||
meta = {"user_id": user_id}
|
||||
if extra:
|
||||
meta.update(extra)
|
||||
|
||||
if self.use_mem0 and hasattr(self, "mem0_client"):
|
||||
self.mem0_client.add(text, user_id=user_id, metadata=meta)
|
||||
else:
|
||||
self.store_long_term(text, metadata=meta)
|
||||
|
||||
def search_user_memory(self, user_id: str, query: str, limit: int = 5) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
If mem0 is used, pass user_id in. Otherwise fallback to local filter on user in metadata.
|
||||
"""
|
||||
if self.use_mem0 and hasattr(self, "mem0_client"):
|
||||
return self.mem0_client.search(query=query, limit=limit, user_id=user_id)
|
||||
else:
|
||||
hits = self.search_long_term(query, limit=20)
|
||||
filtered = []
|
||||
for h in hits:
|
||||
meta = h.get("metadata", {})
|
||||
if meta.get("user_id") == user_id:
|
||||
filtered.append(h)
|
||||
return filtered[:limit]
|
||||
|
||||
def reset_user_memory(self):
|
||||
"""
|
||||
Clear all user-based info. For simplicity, we do a full LTM reset.
|
||||
Real usage might filter only metadata "user_id".
|
||||
"""
|
||||
self.reset_long_term()
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Putting it all Together: Task Finalization
|
||||
# -------------------------------------------------------------------------
|
||||
def finalize_task_output(
|
||||
self,
|
||||
content: str,
|
||||
agent_name: str,
|
||||
quality_score: float,
|
||||
threshold: float = 0.7,
|
||||
metrics: Dict[str, Any] = None,
|
||||
task_id: str = None
|
||||
):
|
||||
"""Store task output in memory with appropriate metadata"""
|
||||
logger.info(f"Finalizing task output: {content[:100]}...")
|
||||
logger.info(f"Agent: {agent_name}, Quality: {quality_score}, Threshold: {threshold}")
|
||||
|
||||
metadata = {
|
||||
"task_id": task_id,
|
||||
"agent": agent_name,
|
||||
"quality": quality_score,
|
||||
"metrics": metrics,
|
||||
"task_type": "output",
|
||||
"stored_at": time.time()
|
||||
}
|
||||
logger.info(f"Prepared metadata: {metadata}")
|
||||
|
||||
# Always store in short-term memory
|
||||
try:
|
||||
logger.info("Storing in short-term memory...")
|
||||
self.store_short_term(
|
||||
text=content,
|
||||
metadata=metadata
|
||||
)
|
||||
logger.info("Successfully stored in short-term memory")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to store in short-term memory: {e}")
|
||||
|
||||
# Store in long-term memory if quality meets threshold
|
||||
if quality_score >= threshold:
|
||||
try:
|
||||
logger.info(f"Quality score {quality_score} >= {threshold}, storing in long-term memory...")
|
||||
self.store_long_term(
|
||||
text=content,
|
||||
metadata=metadata
|
||||
)
|
||||
logger.info("Successfully stored in long-term memory")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to store in long-term memory: {e}")
|
||||
else:
|
||||
logger.info(f"Quality score {quality_score} < {threshold}, skipping long-term storage")
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Building Context (Short, Long, Entities, User)
|
||||
# -------------------------------------------------------------------------
|
||||
def build_context_for_task(
|
||||
self,
|
||||
task_descr: str,
|
||||
user_id: Optional[str] = None,
|
||||
additional: str = "",
|
||||
max_items: int = 3
|
||||
) -> str:
|
||||
"""
|
||||
Merges relevant short-term, long-term, entity, user memories
|
||||
into a single text block with deduplication and clean formatting.
|
||||
"""
|
||||
q = (task_descr + " " + additional).strip()
|
||||
lines = []
|
||||
seen_contents = set() # Track unique contents
|
||||
|
||||
def normalize_content(content: str) -> str:
|
||||
"""Normalize content for deduplication"""
|
||||
# Extract just the main content without citations for comparison
|
||||
normalized = content.split("(Memory record:")[0].strip()
|
||||
# Keep more characters to reduce false duplicates
|
||||
normalized = ''.join(c.lower() for c in normalized if not c.isspace())
|
||||
return normalized
|
||||
|
||||
def format_content(content: str, max_len: int = 150) -> str:
|
||||
"""Format content with clean truncation at word boundaries"""
|
||||
if not content:
|
||||
return ""
|
||||
|
||||
# Clean up content by removing extra whitespace and newlines
|
||||
content = ' '.join(content.split())
|
||||
|
||||
# If content contains a memory citation, preserve it
|
||||
if "(Memory record:" in content:
|
||||
return content # Keep original citation format
|
||||
|
||||
# Regular content truncation
|
||||
if len(content) <= max_len:
|
||||
return content
|
||||
|
||||
truncate_at = content.rfind(' ', 0, max_len - 3)
|
||||
if truncate_at == -1:
|
||||
truncate_at = max_len - 3
|
||||
return content[:truncate_at] + "..."
|
||||
|
||||
def add_section(title: str, hits: List[Any]) -> None:
|
||||
"""Add a section of memory hits with deduplication"""
|
||||
if not hits:
|
||||
return
|
||||
|
||||
formatted_hits = []
|
||||
for h in hits:
|
||||
content = h.get('text', '') if isinstance(h, dict) else str(h)
|
||||
if not content:
|
||||
continue
|
||||
|
||||
# Keep original format if it has a citation
|
||||
if "(Memory record:" in content:
|
||||
formatted = content
|
||||
else:
|
||||
formatted = format_content(content)
|
||||
|
||||
# Only add if we haven't seen this normalized content before
|
||||
normalized = normalize_content(formatted)
|
||||
if normalized not in seen_contents:
|
||||
seen_contents.add(normalized)
|
||||
formatted_hits.append(formatted)
|
||||
|
||||
if formatted_hits:
|
||||
# Add section header
|
||||
if lines:
|
||||
lines.append("") # Space before new section
|
||||
lines.append(title)
|
||||
lines.append("=" * len(title)) # Underline the title
|
||||
lines.append("") # Space after title
|
||||
|
||||
# Add formatted content with bullet points
|
||||
for content in formatted_hits:
|
||||
lines.append(f" • {content}")
|
||||
|
||||
# Add each section
|
||||
# First get all results
|
||||
short_term = self.search_short_term(q, limit=max_items)
|
||||
long_term = self.search_long_term(q, limit=max_items)
|
||||
entities = self.search_entity(q, limit=max_items)
|
||||
user_mem = self.search_user_memory(user_id, q, limit=max_items) if user_id else []
|
||||
|
||||
# Add sections in order of priority
|
||||
add_section("Short-term Memory Context", short_term)
|
||||
add_section("Long-term Memory Context", long_term)
|
||||
add_section("Entity Context", entities)
|
||||
if user_id:
|
||||
add_section("User Context", user_mem)
|
||||
|
||||
return "\n".join(lines) if lines else ""
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Master Reset (Everything)
|
||||
# -------------------------------------------------------------------------
|
||||
def reset_all(self):
|
||||
"""
|
||||
Fully wipes short-term, long-term, and any memory in mem0 or rag.
|
||||
"""
|
||||
self.reset_short_term()
|
||||
self.reset_long_term()
|
||||
# Entities & user memory are stored in LTM or mem0, so no separate step needed.
|
||||
|
||||
def _process_quality_metrics(
|
||||
self,
|
||||
metadata: Dict[str, Any],
|
||||
completeness: float = None,
|
||||
relevance: float = None,
|
||||
clarity: float = None,
|
||||
accuracy: float = None,
|
||||
weights: Dict[str, float] = None,
|
||||
evaluator_quality: float = None
|
||||
) -> Dict[str, Any]:
|
||||
"""Process and store quality metrics in metadata"""
|
||||
metadata = metadata or {}
|
||||
|
||||
# Handle sub-metrics if provided
|
||||
if None not in [completeness, relevance, clarity, accuracy]:
|
||||
metadata.update({
|
||||
"completeness": completeness,
|
||||
"relevance": relevance,
|
||||
"clarity": clarity,
|
||||
"accuracy": accuracy,
|
||||
"quality": self.compute_quality_score(
|
||||
completeness, relevance, clarity, accuracy, weights
|
||||
)
|
||||
})
|
||||
# Handle external evaluator quality if provided
|
||||
elif evaluator_quality is not None:
|
||||
metadata["quality"] = evaluator_quality
|
||||
|
||||
return metadata
|
||||
|
||||
def calculate_quality_metrics(
|
||||
self,
|
||||
output: str,
|
||||
expected_output: str,
|
||||
llm: Optional[str] = None,
|
||||
custom_prompt: Optional[str] = None
|
||||
) -> Dict[str, float]:
|
||||
"""Calculate quality metrics using LLM"""
|
||||
logger.info("Calculating quality metrics for output")
|
||||
logger.info(f"Output: {output[:100]}...")
|
||||
logger.info(f"Expected: {expected_output[:100]}...")
|
||||
|
||||
# Default evaluation prompt
|
||||
default_prompt = f"""
|
||||
Evaluate the following output against expected output.
|
||||
Score each metric from 0.0 to 1.0:
|
||||
- Completeness: Does it address all requirements?
|
||||
- Relevance: Does it match expected output?
|
||||
- Clarity: Is it clear and well-structured?
|
||||
- Accuracy: Is it factually correct?
|
||||
|
||||
Expected: {expected_output}
|
||||
Actual: {output}
|
||||
|
||||
Return ONLY a JSON with these keys: completeness, relevance, clarity, accuracy
|
||||
Example: {{"completeness": 0.95, "relevance": 0.8, "clarity": 0.9, "accuracy": 0.85}}
|
||||
"""
|
||||
|
||||
try:
|
||||
# Use OpenAI client from main.py
|
||||
from ..main import client
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model=llm or "gpt-4o",
|
||||
messages=[{
|
||||
"role": "user",
|
||||
"content": custom_prompt or default_prompt
|
||||
}],
|
||||
response_format={"type": "json_object"},
|
||||
temperature=0.3
|
||||
)
|
||||
|
||||
metrics = json.loads(response.choices[0].message.content)
|
||||
|
||||
# Validate metrics
|
||||
required = ["completeness", "relevance", "clarity", "accuracy"]
|
||||
if not all(k in metrics for k in required):
|
||||
raise ValueError("Missing required metrics in LLM response")
|
||||
|
||||
logger.info(f"Calculated metrics: {metrics}")
|
||||
return metrics
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error calculating metrics: {e}")
|
||||
return {
|
||||
"completeness": 0.0,
|
||||
"relevance": 0.0,
|
||||
"clarity": 0.0,
|
||||
"accuracy": 0.0
|
||||
}
|
||||
|
||||
def store_quality(
|
||||
self,
|
||||
text: str,
|
||||
quality_score: float,
|
||||
task_id: Optional[str] = None,
|
||||
iteration: Optional[int] = None,
|
||||
metrics: Optional[Dict[str, float]] = None,
|
||||
memory_type: Literal["short", "long"] = "long"
|
||||
) -> None:
|
||||
"""Store quality metrics in memory"""
|
||||
logger.info(f"Attempting to store in {memory_type} memory: {text[:100]}...")
|
||||
|
||||
metadata = {
|
||||
"quality": quality_score,
|
||||
"task_id": task_id,
|
||||
"iteration": iteration
|
||||
}
|
||||
|
||||
if metrics:
|
||||
metadata.update({
|
||||
k: v for k, v in metrics.items() # Remove metric_ prefix
|
||||
})
|
||||
|
||||
logger.info(f"With metadata: {metadata}")
|
||||
|
||||
try:
|
||||
if memory_type == "short":
|
||||
self.store_short_term(text, metadata=metadata)
|
||||
logger.info("Successfully stored in short-term memory")
|
||||
else:
|
||||
self.store_long_term(text, metadata=metadata)
|
||||
logger.info("Successfully stored in long-term memory")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to store in memory: {e}")
|
||||
|
||||
def search_with_quality(
|
||||
self,
|
||||
query: str,
|
||||
min_quality: float = 0.0,
|
||||
memory_type: Literal["short", "long"] = "long",
|
||||
limit: int = 5
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Search with quality filter"""
|
||||
logger.info(f"Searching {memory_type} memory for: {query}")
|
||||
logger.info(f"Min quality: {min_quality}")
|
||||
|
||||
search_func = (
|
||||
self.search_short_term if memory_type == "short"
|
||||
else self.search_long_term
|
||||
)
|
||||
|
||||
results = search_func(query, limit=limit)
|
||||
logger.info(f"Found {len(results)} initial results")
|
||||
|
||||
filtered = [
|
||||
r for r in results
|
||||
if r.get("metadata", {}).get("quality", 0.0) >= min_quality
|
||||
]
|
||||
logger.info(f"After quality filter: {len(filtered)} results")
|
||||
|
||||
return filtered
|
||||
@@ -130,22 +130,28 @@ Return a JSON object with an 'items' array containing the items to process.
|
||||
|
||||
# Determine next task based on result
|
||||
next_task = None
|
||||
if current_task.result:
|
||||
if current_task and current_task.result:
|
||||
if current_task.task_type in ["decision", "loop"]:
|
||||
result = current_task.result.raw.lower()
|
||||
# Check conditions
|
||||
for condition, tasks in current_task.condition.items():
|
||||
if condition.lower() in result and tasks:
|
||||
next_task_name = tasks[0]
|
||||
if condition.lower() in result:
|
||||
# Handle both list and direct string values
|
||||
task_value = tasks[0] if isinstance(tasks, list) else tasks
|
||||
if not task_value or task_value == "exit": # If empty or explicit exit
|
||||
logging.info("Workflow exit condition met, ending workflow")
|
||||
current_task = None
|
||||
break
|
||||
next_task_name = task_value
|
||||
next_task = next((t for t in self.tasks.values() if t.name == next_task_name), None)
|
||||
# For loops, allow revisiting the same task
|
||||
if next_task and next_task.id == current_task.id:
|
||||
visited_tasks.discard(current_task.id)
|
||||
break
|
||||
|
||||
if not next_task and current_task.next_tasks:
|
||||
next_task_name = current_task.next_tasks[0]
|
||||
next_task = next((t for t in self.tasks.values() if t.name == next_task_name), None)
|
||||
if not next_task and current_task and current_task.next_tasks:
|
||||
next_task_name = current_task.next_tasks[0]
|
||||
next_task = next((t for t in self.tasks.values() if t.name == next_task_name), None)
|
||||
|
||||
current_task = next_task
|
||||
if not current_task:
|
||||
@@ -391,22 +397,28 @@ Return a JSON object with an 'items' array containing the items to process.
|
||||
|
||||
# Determine next task based on result
|
||||
next_task = None
|
||||
if current_task.result:
|
||||
if current_task and current_task.result:
|
||||
if current_task.task_type in ["decision", "loop"]:
|
||||
result = current_task.result.raw.lower()
|
||||
# Check conditions
|
||||
for condition, tasks in current_task.condition.items():
|
||||
if condition.lower() in result and tasks:
|
||||
next_task_name = tasks[0]
|
||||
if condition.lower() in result:
|
||||
# Handle both list and direct string values
|
||||
task_value = tasks[0] if isinstance(tasks, list) else tasks
|
||||
if not task_value or task_value == "exit": # If empty or explicit exit
|
||||
logging.info("Workflow exit condition met, ending workflow")
|
||||
current_task = None
|
||||
break
|
||||
next_task_name = task_value
|
||||
next_task = next((t for t in self.tasks.values() if t.name == next_task_name), None)
|
||||
# For loops, allow revisiting the same task
|
||||
if next_task and next_task.id == current_task.id:
|
||||
visited_tasks.discard(current_task.id)
|
||||
break
|
||||
|
||||
if not next_task and current_task.next_tasks:
|
||||
next_task_name = current_task.next_tasks[0]
|
||||
next_task = next((t for t in self.tasks.values() if t.name == next_task_name), None)
|
||||
if not next_task and current_task and current_task.next_tasks:
|
||||
next_task_name = current_task.next_tasks[0]
|
||||
next_task = next((t for t in self.tasks.values() if t.name == next_task_name), None)
|
||||
|
||||
current_task = next_task
|
||||
if not current_task:
|
||||
|
||||
@@ -5,12 +5,17 @@ from pydantic import BaseModel
|
||||
from ..main import TaskOutput
|
||||
from ..agent.agent import Agent
|
||||
import uuid
|
||||
import os
|
||||
import time
|
||||
|
||||
# Set up logger
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class Task:
|
||||
def __init__(
|
||||
self,
|
||||
description: str,
|
||||
expected_output: str,
|
||||
expected_output: Optional[str] = None,
|
||||
agent: Optional[Agent] = None,
|
||||
name: Optional[str] = None,
|
||||
tools: Optional[List[Any]] = None,
|
||||
@@ -30,12 +35,14 @@ class Task:
|
||||
task_type: str = "task",
|
||||
condition: Optional[Dict[str, List[str]]] = None,
|
||||
is_start: bool = False,
|
||||
loop_state: Optional[Dict[str, Union[str, int]]] = None
|
||||
loop_state: Optional[Dict[str, Union[str, int]]] = None,
|
||||
memory=None,
|
||||
quality_check=True
|
||||
):
|
||||
self.id = str(uuid.uuid4()) if id is None else str(id)
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.expected_output = expected_output
|
||||
self.expected_output = expected_output if expected_output is not None else "Complete the task successfully"
|
||||
self.agent = agent
|
||||
self.tools = tools if tools else []
|
||||
self.context = context if context else []
|
||||
@@ -54,6 +61,21 @@ class Task:
|
||||
self.condition = condition if condition else {}
|
||||
self.is_start = is_start
|
||||
self.loop_state = loop_state if loop_state else {}
|
||||
self.memory = memory
|
||||
self.quality_check = quality_check
|
||||
|
||||
# Set logger level based on config verbose level
|
||||
verbose = self.config.get("verbose", 0)
|
||||
if verbose >= 5:
|
||||
logger.setLevel(logging.INFO)
|
||||
else:
|
||||
logger.setLevel(logging.WARNING)
|
||||
|
||||
# Also set third-party loggers to WARNING
|
||||
logging.getLogger('chromadb').setLevel(logging.WARNING)
|
||||
logging.getLogger('openai').setLevel(logging.WARNING)
|
||||
logging.getLogger('httpx').setLevel(logging.WARNING)
|
||||
logging.getLogger('httpcore').setLevel(logging.WARNING)
|
||||
|
||||
if self.output_json and self.output_pydantic:
|
||||
raise ValueError("Only one output type can be defined")
|
||||
@@ -64,11 +86,137 @@ class Task:
|
||||
def __str__(self):
|
||||
return f"Task(name='{self.name if self.name else 'None'}', description='{self.description}', agent='{self.agent.name if self.agent else 'None'}', status='{self.status}')"
|
||||
|
||||
def initialize_memory(self):
|
||||
"""Initialize memory if config exists but memory doesn't"""
|
||||
if not self.memory and self.config.get('memory_config'):
|
||||
try:
|
||||
from ..memory.memory import Memory
|
||||
logger.info(f"Task {self.id}: Initializing memory from config: {self.config['memory_config']}")
|
||||
self.memory = Memory(config=self.config['memory_config'])
|
||||
logger.info(f"Task {self.id}: Memory initialized successfully")
|
||||
|
||||
# Verify database was created
|
||||
if os.path.exists(self.config['memory_config']['storage']['path']):
|
||||
logger.info(f"Task {self.id}: Memory database exists after initialization")
|
||||
else:
|
||||
logger.error(f"Task {self.id}: Failed to create memory database!")
|
||||
return self.memory
|
||||
except Exception as e:
|
||||
logger.error(f"Task {self.id}: Failed to initialize memory: {e}")
|
||||
logger.exception(e)
|
||||
return None
|
||||
|
||||
def store_in_memory(self, content: str, agent_name: str = None, task_id: str = None):
|
||||
"""Store content in memory with metadata"""
|
||||
if self.memory:
|
||||
try:
|
||||
logger.info(f"Task {self.id}: Storing content in memory...")
|
||||
self.memory.store_long_term(
|
||||
text=content,
|
||||
metadata={
|
||||
"agent_name": agent_name or "Agent",
|
||||
"task_id": task_id or self.id,
|
||||
"timestamp": time.time()
|
||||
}
|
||||
)
|
||||
logger.info(f"Task {self.id}: Content stored in memory")
|
||||
except Exception as e:
|
||||
logger.error(f"Task {self.id}: Failed to store content in memory: {e}")
|
||||
logger.exception(e)
|
||||
|
||||
async def execute_callback(self, task_output: TaskOutput) -> None:
|
||||
"""Execute the callback function, handling both sync and async callbacks"""
|
||||
"""Execute callback and store quality metrics if enabled"""
|
||||
logger.info(f"Task {self.id}: execute_callback called")
|
||||
logger.info(f"Quality check enabled: {self.quality_check}")
|
||||
|
||||
# Initialize memory if not already initialized
|
||||
if not self.memory:
|
||||
self.memory = self.initialize_memory()
|
||||
|
||||
logger.info(f"Memory object exists: {self.memory is not None}")
|
||||
if self.memory:
|
||||
logger.info(f"Memory config: {self.memory.cfg}")
|
||||
# Store task output in memory
|
||||
try:
|
||||
logger.info(f"Task {self.id}: Storing task output in memory...")
|
||||
self.store_in_memory(
|
||||
content=task_output.raw,
|
||||
agent_name=self.agent.name if self.agent else "Agent",
|
||||
task_id=self.id
|
||||
)
|
||||
logger.info(f"Task {self.id}: Task output stored in memory")
|
||||
except Exception as e:
|
||||
logger.error(f"Task {self.id}: Failed to store task output in memory: {e}")
|
||||
logger.exception(e)
|
||||
|
||||
logger.info(f"Task output: {task_output.raw[:100]}...")
|
||||
|
||||
if self.quality_check and self.memory:
|
||||
try:
|
||||
logger.info(f"Task {self.id}: Starting memory operations")
|
||||
logger.info(f"Task {self.id}: Calculating quality metrics for output: {task_output.raw[:100]}...")
|
||||
|
||||
# Get quality metrics from LLM
|
||||
metrics = self.memory.calculate_quality_metrics(
|
||||
task_output.raw,
|
||||
self.expected_output
|
||||
)
|
||||
logger.info(f"Task {self.id}: Quality metrics calculated: {metrics}")
|
||||
|
||||
quality_score = metrics.get("accuracy", 0.0)
|
||||
logger.info(f"Task {self.id}: Quality score: {quality_score}")
|
||||
|
||||
# Store in both short and long-term memory with higher threshold
|
||||
logger.info(f"Task {self.id}: Finalizing task output in memory...")
|
||||
self.memory.finalize_task_output(
|
||||
content=task_output.raw,
|
||||
agent_name=self.agent.name if self.agent else "Agent",
|
||||
quality_score=quality_score,
|
||||
threshold=0.7, # Only high quality outputs in long-term memory
|
||||
metrics=metrics,
|
||||
task_id=self.id
|
||||
)
|
||||
logger.info(f"Task {self.id}: Finalized task output in memory")
|
||||
|
||||
# Store quality metrics separately
|
||||
logger.info(f"Task {self.id}: Storing quality metrics...")
|
||||
self.memory.store_quality(
|
||||
text=task_output.raw,
|
||||
quality_score=quality_score,
|
||||
task_id=self.id,
|
||||
metrics=metrics
|
||||
)
|
||||
|
||||
# Store in both short and long-term memory with higher threshold
|
||||
self.memory.finalize_task_output(
|
||||
content=task_output.raw,
|
||||
agent_name=self.agent.name if self.agent else "Agent",
|
||||
quality_score=quality_score,
|
||||
threshold=0.7 # Only high quality outputs in long-term memory
|
||||
)
|
||||
|
||||
# Build context for next tasks
|
||||
if self.next_tasks:
|
||||
logger.info(f"Task {self.id}: Building context for next tasks...")
|
||||
context = self.memory.build_context_for_task(
|
||||
task_descr=task_output.raw,
|
||||
max_items=5
|
||||
)
|
||||
logger.info(f"Task {self.id}: Built context for next tasks: {len(context)} items")
|
||||
|
||||
logger.info(f"Task {self.id}: Memory operations complete")
|
||||
except Exception as e:
|
||||
logger.error(f"Task {self.id}: Failed to process memory operations: {e}")
|
||||
logger.exception(e) # Print full stack trace
|
||||
# Continue execution even if memory operations fail
|
||||
|
||||
# Execute original callback
|
||||
if self.callback:
|
||||
if asyncio.iscoroutinefunction(self.callback):
|
||||
await self.callback(task_output)
|
||||
else:
|
||||
loop = asyncio.get_event_loop()
|
||||
await loop.run_in_executor(None, self.callback, task_output)
|
||||
try:
|
||||
if asyncio.iscoroutinefunction(self.callback):
|
||||
await self.callback(task_output)
|
||||
else:
|
||||
self.callback(task_output)
|
||||
except Exception as e:
|
||||
logger.error(f"Task {self.id}: Failed to execute callback: {e}")
|
||||
logger.exception(e)
|
||||
@@ -0,0 +1,149 @@
|
||||
# PraisonAI Tools Guide
|
||||
|
||||
Welcome to the PraisonAI Tools directory! This guide will help you understand how our tools work and how to create new ones, whether you're a beginner or an experienced programmer.
|
||||
|
||||
## What is a Tool?
|
||||
|
||||
A tool is a piece of code that helps our AI agents perform specific tasks. Think of tools as special abilities that we give to our agents. For example:
|
||||
- An internet search tool lets agents search the web
|
||||
- A stock market tool lets agents check stock prices
|
||||
- A weather tool lets agents check the weather
|
||||
|
||||
## Creating New Tools: The Two Approaches
|
||||
|
||||
### 1. Function-Based Approach (Simple Tools)
|
||||
|
||||
Best for simple tools that do one specific thing. Like a calculator that just adds numbers.
|
||||
|
||||
**When to use:**
|
||||
- Tool does one simple task
|
||||
- Doesn't need to remember information between uses
|
||||
- Doesn't need to share information with other tools
|
||||
- Quick, one-time operations
|
||||
|
||||
**Example:**
|
||||
```python
|
||||
def internet_search(query: str):
|
||||
# Search the internet and return results
|
||||
return search_results
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
```python
|
||||
from praisonaiagents.tools import internet_search
|
||||
|
||||
results = internet_search("AI news")
|
||||
```
|
||||
|
||||
### 2. Class-Based Approach (Complex Tools)
|
||||
|
||||
Best for tools that do multiple related things or need to remember information. Like a smart calculator that remembers your previous calculations and can do many different math operations.
|
||||
|
||||
**When to use:**
|
||||
- Tool has multiple related functions
|
||||
- Needs to remember or share information
|
||||
- Needs to manage resources efficiently
|
||||
- Has complex setup requirements
|
||||
|
||||
**Example:**
|
||||
```python
|
||||
class StockTools:
|
||||
def get_stock_price(self, symbol):
|
||||
# Get current stock price
|
||||
return price
|
||||
|
||||
def get_stock_info(self, symbol):
|
||||
# Get detailed stock information
|
||||
return info
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
```python
|
||||
from praisonaiagents.tools import get_stock_price, get_stock_info
|
||||
|
||||
price = get_stock_price("AAPL")
|
||||
info = get_stock_info("AAPL")
|
||||
```
|
||||
|
||||
## How to Choose Your Approach
|
||||
|
||||
Ask yourself these questions:
|
||||
|
||||
1. **Is your tool doing one simple thing?**
|
||||
- Yes → Use Function-Based Approach
|
||||
- No → Consider Class-Based Approach
|
||||
|
||||
2. **Does your tool need to remember information?**
|
||||
- Yes → Use Class-Based Approach
|
||||
- No → Use Function-Based Approach
|
||||
|
||||
3. **Are your tool's operations related to each other?**
|
||||
- Yes → Use Class-Based Approach
|
||||
- No → Use Function-Based Approach
|
||||
|
||||
4. **Does your tool need to manage resources efficiently?**
|
||||
- Yes → Use Class-Based Approach
|
||||
- No → Use Function-Based Approach
|
||||
|
||||
## Real-World Examples
|
||||
|
||||
### Internet Search Tool (Function-Based)
|
||||
- Does one thing: searches the internet
|
||||
- Doesn't need to remember previous searches
|
||||
- Each search is independent
|
||||
- Simple input/output operation
|
||||
|
||||
### Stock Market Tool (Class-Based)
|
||||
- Does multiple things: check prices, get company info, get historical data
|
||||
- Remembers stock information to avoid repeated downloads
|
||||
- Operations are related (all about stocks)
|
||||
- Manages connections efficiently
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. **Choose Your Approach** based on the guidelines above
|
||||
|
||||
2. **Create Your Tool File**:
|
||||
- Name it descriptively (e.g., `weather_tools.py`)
|
||||
- Place it in the `praisonaiagents/tools` directory
|
||||
|
||||
3. **Write Your Tool**:
|
||||
- Add clear documentation
|
||||
- Include type hints for better understanding
|
||||
- Handle errors gracefully
|
||||
|
||||
4. **Test Your Tool**:
|
||||
- Make sure it works as expected
|
||||
- Test error cases
|
||||
- Check performance
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Documentation**:
|
||||
- Explain what your tool does
|
||||
- Provide examples
|
||||
- List any requirements
|
||||
|
||||
2. **Error Handling**:
|
||||
- Always handle possible errors
|
||||
- Return helpful error messages
|
||||
- Don't let your tool crash
|
||||
|
||||
3. **Performance**:
|
||||
- Keep it efficient
|
||||
- Don't waste resources
|
||||
- Cache when helpful
|
||||
|
||||
4. **User-Friendly**:
|
||||
- Make it easy to use
|
||||
- Use clear function/method names
|
||||
- Keep it simple
|
||||
|
||||
## Need Help?
|
||||
|
||||
- Check existing tools for examples
|
||||
- Ask in our community
|
||||
- Read the documentation
|
||||
- Don't hesitate to ask questions!
|
||||
|
||||
Remember: The goal is to make tools that are easy to use and maintain. Choose the approach that makes the most sense for your specific tool's needs.
|
||||
@@ -1,4 +1,178 @@
|
||||
"""Tools package for PraisonAI Agents"""
|
||||
from .tools import Tools
|
||||
from importlib import import_module
|
||||
from typing import Any
|
||||
|
||||
__all__ = ['Tools']
|
||||
# Map of function names to their module and class (if any)
|
||||
TOOL_MAPPINGS = {
|
||||
# Direct functions
|
||||
'internet_search': ('.duckduckgo_tools', None),
|
||||
'duckduckgo': ('.duckduckgo_tools', None),
|
||||
|
||||
# arXiv Tools
|
||||
'search_arxiv': ('.arxiv_tools', None),
|
||||
'get_arxiv_paper': ('.arxiv_tools', None),
|
||||
'get_papers_by_author': ('.arxiv_tools', None),
|
||||
'get_papers_by_category': ('.arxiv_tools', None),
|
||||
'arxiv_tools': ('.arxiv_tools', None),
|
||||
|
||||
# Wikipedia Tools
|
||||
'wiki_search': ('.wikipedia_tools', None),
|
||||
'wiki_summary': ('.wikipedia_tools', None),
|
||||
'wiki_page': ('.wikipedia_tools', None),
|
||||
'wiki_random': ('.wikipedia_tools', None),
|
||||
'wiki_language': ('.wikipedia_tools', None),
|
||||
'wikipedia_tools': ('.wikipedia_tools', None),
|
||||
|
||||
# Newspaper Tools
|
||||
'get_article': ('.newspaper_tools', None),
|
||||
'get_news_sources': ('.newspaper_tools', None),
|
||||
'get_articles_from_source': ('.newspaper_tools', None),
|
||||
'get_trending_topics': ('.newspaper_tools', None),
|
||||
'newspaper_tools': ('.newspaper_tools', None),
|
||||
|
||||
# Spider Tools
|
||||
'scrape_page': ('.spider_tools', None),
|
||||
'extract_links': ('.spider_tools', None),
|
||||
'crawl': ('.spider_tools', None),
|
||||
'extract_text': ('.spider_tools', None),
|
||||
'spider_tools': ('.spider_tools', None),
|
||||
|
||||
# DuckDB Tools
|
||||
'query': ('.duckdb_tools', None),
|
||||
'create_table': ('.duckdb_tools', None),
|
||||
'load_data': ('.duckdb_tools', None),
|
||||
'export_data': ('.duckdb_tools', None),
|
||||
'get_table_info': ('.duckdb_tools', None),
|
||||
'analyze_data': ('.duckdb_tools', None),
|
||||
'duckdb_tools': ('.duckdb_tools', None),
|
||||
|
||||
# Shell Tools
|
||||
'execute_command': ('.shell_tools', None),
|
||||
'list_processes': ('.shell_tools', None),
|
||||
'kill_process': ('.shell_tools', None),
|
||||
'get_system_info': ('.shell_tools', None),
|
||||
'shell_tools': ('.shell_tools', None),
|
||||
|
||||
# Calculator Tools
|
||||
'evaluate': ('.calculator_tools', None),
|
||||
'solve_equation': ('.calculator_tools', None),
|
||||
'convert_units': ('.calculator_tools', None),
|
||||
'calculate_statistics': ('.calculator_tools', None),
|
||||
'calculate_financial': ('.calculator_tools', None),
|
||||
'calculator_tools': ('.calculator_tools', None),
|
||||
|
||||
# Class methods from YFinance
|
||||
'get_stock_price': ('.yfinance_tools', 'YFinanceTools'),
|
||||
'get_stock_info': ('.yfinance_tools', 'YFinanceTools'),
|
||||
'get_historical_data': ('.yfinance_tools', 'YFinanceTools'),
|
||||
'yfinance': ('.yfinance_tools', 'YFinanceTools'),
|
||||
|
||||
# File Tools
|
||||
'read_file': ('.file_tools', 'FileTools'),
|
||||
'write_file': ('.file_tools', 'FileTools'),
|
||||
'list_files': ('.file_tools', 'FileTools'),
|
||||
'get_file_info': ('.file_tools', 'FileTools'),
|
||||
'copy_file': ('.file_tools', 'FileTools'),
|
||||
'move_file': ('.file_tools', 'FileTools'),
|
||||
'delete_file': ('.file_tools', 'FileTools'),
|
||||
'file_tools': ('.file_tools', 'FileTools'),
|
||||
|
||||
# CSV Tools
|
||||
'read_csv': ('.csv_tools', 'CSVTools'),
|
||||
'write_csv': ('.csv_tools', 'CSVTools'),
|
||||
'merge_csv': ('.csv_tools', 'CSVTools'),
|
||||
'analyze_csv': ('.csv_tools', 'CSVTools'),
|
||||
'split_csv': ('.csv_tools', 'CSVTools'),
|
||||
'csv_tools': ('.csv_tools', 'CSVTools'),
|
||||
|
||||
# JSON Tools
|
||||
'read_json': ('.json_tools', 'JSONTools'),
|
||||
'write_json': ('.json_tools', 'JSONTools'),
|
||||
'merge_json': ('.json_tools', 'JSONTools'),
|
||||
'validate_json': ('.json_tools', 'JSONTools'),
|
||||
'analyze_json': ('.json_tools', 'JSONTools'),
|
||||
'transform_json': ('.json_tools', 'JSONTools'),
|
||||
'json_tools': ('.json_tools', 'JSONTools'),
|
||||
|
||||
# Excel Tools
|
||||
'read_excel': ('.excel_tools', 'ExcelTools'),
|
||||
'write_excel': ('.excel_tools', 'ExcelTools'),
|
||||
'merge_excel': ('.excel_tools', 'ExcelTools'),
|
||||
'create_chart': ('.excel_tools', 'ExcelTools'),
|
||||
'add_chart_to_sheet': ('.excel_tools', 'ExcelTools'),
|
||||
'excel_tools': ('.excel_tools', 'ExcelTools'),
|
||||
|
||||
# XML Tools
|
||||
'read_xml': ('.xml_tools', 'XMLTools'),
|
||||
'write_xml': ('.xml_tools', 'XMLTools'),
|
||||
'transform_xml': ('.xml_tools', 'XMLTools'),
|
||||
'validate_xml': ('.xml_tools', 'XMLTools'),
|
||||
'xml_to_dict': ('.xml_tools', 'XMLTools'),
|
||||
'dict_to_xml': ('.xml_tools', 'XMLTools'),
|
||||
'xpath_query': ('.xml_tools', 'XMLTools'),
|
||||
'xml_tools': ('.xml_tools', 'XMLTools'),
|
||||
|
||||
# YAML Tools
|
||||
'read_yaml': ('.yaml_tools', 'YAMLTools'),
|
||||
'write_yaml': ('.yaml_tools', 'YAMLTools'),
|
||||
'merge_yaml': ('.yaml_tools', 'YAMLTools'),
|
||||
'validate_yaml': ('.yaml_tools', 'YAMLTools'),
|
||||
'analyze_yaml': ('.yaml_tools', 'YAMLTools'),
|
||||
'transform_yaml': ('.yaml_tools', 'YAMLTools'),
|
||||
'yaml_tools': ('.yaml_tools', 'YAMLTools'),
|
||||
|
||||
# Python Tools
|
||||
'execute_code': ('.python_tools', 'PythonTools'),
|
||||
'analyze_code': ('.python_tools', 'PythonTools'),
|
||||
'format_code': ('.python_tools', 'PythonTools'),
|
||||
'lint_code': ('.python_tools', 'PythonTools'),
|
||||
'disassemble_code': ('.python_tools', 'PythonTools'),
|
||||
'python_tools': ('.python_tools', 'PythonTools'),
|
||||
|
||||
# Pandas Tools
|
||||
'filter_data': ('.pandas_tools', 'PandasTools'),
|
||||
'get_summary': ('.pandas_tools', 'PandasTools'),
|
||||
'group_by': ('.pandas_tools', 'PandasTools'),
|
||||
'pivot_table': ('.pandas_tools', 'PandasTools'),
|
||||
'pandas_tools': ('.pandas_tools', 'PandasTools'),
|
||||
}
|
||||
|
||||
_instances = {} # Cache for class instances
|
||||
|
||||
def __getattr__(name: str) -> Any:
|
||||
"""Smart lazy loading of tools with class method support."""
|
||||
if name not in TOOL_MAPPINGS:
|
||||
raise AttributeError(f"module '{__package__}' has no attribute '{name}'")
|
||||
|
||||
module_path, class_name = TOOL_MAPPINGS[name]
|
||||
|
||||
if class_name is None:
|
||||
# Direct function import
|
||||
module = import_module(module_path, __package__)
|
||||
if name in [
|
||||
'duckduckgo', 'internet_search',
|
||||
'search_arxiv', 'get_arxiv_paper', 'get_papers_by_author', 'get_papers_by_category',
|
||||
'wiki_search', 'wiki_summary', 'wiki_page', 'wiki_random', 'wiki_language',
|
||||
'get_article', 'get_news_sources', 'get_articles_from_source', 'get_trending_topics',
|
||||
'scrape_page', 'extract_links', 'crawl', 'extract_text',
|
||||
'query', 'create_table', 'load_data', 'export_data', 'get_table_info', 'analyze_data',
|
||||
'execute_command', 'list_processes', 'kill_process', 'get_system_info',
|
||||
'evaluate', 'solve_equation', 'convert_units', 'calculate_statistics', 'calculate_financial'
|
||||
]:
|
||||
return getattr(module, name)
|
||||
if name in ['file_tools', 'pandas_tools', 'wikipedia_tools',
|
||||
'newspaper_tools', 'arxiv_tools', 'spider_tools', 'duckdb_tools', 'csv_tools', 'json_tools', 'excel_tools', 'xml_tools', 'yaml_tools', 'calculator_tools', 'python_tools', 'shell_tools']:
|
||||
return module # Returns the callable module
|
||||
return getattr(module, name)
|
||||
else:
|
||||
# Class method import
|
||||
if class_name not in _instances:
|
||||
module = import_module(module_path, __package__)
|
||||
class_ = getattr(module, class_name)
|
||||
_instances[class_name] = class_()
|
||||
|
||||
# Get the method and bind it to the instance
|
||||
method = getattr(_instances[class_name], name)
|
||||
return method
|
||||
|
||||
__all__ = list(TOOL_MAPPINGS.keys())
|
||||
@@ -0,0 +1,292 @@
|
||||
"""Tools for searching and retrieving papers from arXiv.
|
||||
|
||||
Usage:
|
||||
from praisonaiagents.tools import arxiv_tools
|
||||
papers = arxiv_tools.search("quantum computing")
|
||||
paper = arxiv_tools.get_paper("2401.00123")
|
||||
|
||||
or
|
||||
from praisonaiagents.tools import search_arxiv, get_arxiv_paper
|
||||
papers = search_arxiv("quantum computing")
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Dict, Union, Optional, Any
|
||||
from importlib import util
|
||||
import json
|
||||
|
||||
# Map sort criteria to arxiv.SortCriterion
|
||||
SORT_CRITERIA = {
|
||||
"relevance": "Relevance",
|
||||
"lastupdateddate": "LastUpdatedDate",
|
||||
"submitteddate": "SubmittedDate"
|
||||
}
|
||||
|
||||
# Map sort order to arxiv.SortOrder
|
||||
SORT_ORDER = {
|
||||
"ascending": "Ascending",
|
||||
"descending": "Descending"
|
||||
}
|
||||
|
||||
class ArxivTools:
|
||||
"""Tools for searching and retrieving papers from arXiv."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize ArxivTools and check for arxiv package."""
|
||||
self._check_arxiv()
|
||||
|
||||
def _check_arxiv(self):
|
||||
"""Check if arxiv package is installed."""
|
||||
if util.find_spec("arxiv") is None:
|
||||
raise ImportError("arxiv package is not available. Please install it using: pip install arxiv")
|
||||
global arxiv
|
||||
import arxiv
|
||||
|
||||
def search(
|
||||
self,
|
||||
query: str,
|
||||
max_results: int = 10,
|
||||
sort_by: str = "relevance",
|
||||
sort_order: str = "descending",
|
||||
include_fields: Optional[List[str]] = None
|
||||
) -> Union[List[Dict[str, Any]], Dict[str, str]]:
|
||||
"""
|
||||
Search arXiv for papers matching the query.
|
||||
|
||||
Args:
|
||||
query: Search query (e.g., "quantum computing", "author:Einstein")
|
||||
max_results: Maximum number of results to return
|
||||
sort_by: Sort results by ("relevance", "lastUpdatedDate", "submittedDate")
|
||||
sort_order: Sort order ("ascending" or "descending")
|
||||
include_fields: List of fields to include in results. If None, includes all.
|
||||
Available fields: ["title", "authors", "summary", "comment", "journal_ref",
|
||||
"doi", "primary_category", "categories", "links"]
|
||||
|
||||
Returns:
|
||||
List[Dict] or Dict: List of papers or error dict
|
||||
"""
|
||||
try:
|
||||
import arxiv
|
||||
|
||||
# Configure search client
|
||||
client = arxiv.Client()
|
||||
|
||||
# Map sort criteria
|
||||
sort_by_enum = getattr(arxiv.SortCriterion, SORT_CRITERIA[sort_by.lower()])
|
||||
sort_order_enum = getattr(arxiv.SortOrder, SORT_ORDER[sort_order.lower()])
|
||||
|
||||
# Build search query
|
||||
search = arxiv.Search(
|
||||
query=query,
|
||||
max_results=max_results,
|
||||
sort_by=sort_by_enum,
|
||||
sort_order=sort_order_enum
|
||||
)
|
||||
|
||||
# Execute search
|
||||
results = []
|
||||
for result in client.results(search):
|
||||
# Convert to dict with selected fields
|
||||
paper = self._result_to_dict(result, include_fields)
|
||||
results.append(paper)
|
||||
|
||||
return results
|
||||
except Exception as e:
|
||||
error_msg = f"Error searching arXiv: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def get_paper(
|
||||
self,
|
||||
paper_id: str,
|
||||
include_fields: Optional[List[str]] = None
|
||||
) -> Union[Dict[str, Any], Dict[str, str]]:
|
||||
"""
|
||||
Get details of a specific paper by its arXiv ID.
|
||||
|
||||
Args:
|
||||
paper_id: arXiv paper ID (e.g., "2401.00123")
|
||||
include_fields: List of fields to include in results. If None, includes all.
|
||||
Available fields: ["title", "authors", "summary", "comment", "journal_ref",
|
||||
"doi", "primary_category", "categories", "links"]
|
||||
|
||||
Returns:
|
||||
Dict: Paper details or error dict
|
||||
"""
|
||||
try:
|
||||
import arxiv
|
||||
|
||||
# Configure client
|
||||
client = arxiv.Client()
|
||||
|
||||
# Get paper by ID
|
||||
search = arxiv.Search(id_list=[paper_id])
|
||||
results = list(client.results(search))
|
||||
|
||||
if not results:
|
||||
return {"error": f"Paper with ID {paper_id} not found"}
|
||||
|
||||
# Convert to dict with selected fields
|
||||
paper = self._result_to_dict(results[0], include_fields)
|
||||
return paper
|
||||
except Exception as e:
|
||||
error_msg = f"Error getting paper {paper_id}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def get_papers_by_author(
|
||||
self,
|
||||
author: str,
|
||||
max_results: int = 10,
|
||||
sort_by: str = "submittedDate",
|
||||
sort_order: str = "descending",
|
||||
include_fields: Optional[List[str]] = None
|
||||
) -> Union[List[Dict[str, Any]], Dict[str, str]]:
|
||||
"""
|
||||
Get papers by a specific author.
|
||||
|
||||
Args:
|
||||
author: Author name (e.g., "Einstein")
|
||||
max_results: Maximum number of results to return
|
||||
sort_by: Sort results by ("relevance", "lastUpdatedDate", "submittedDate")
|
||||
sort_order: Sort order ("ascending" or "descending")
|
||||
include_fields: List of fields to include in results
|
||||
|
||||
Returns:
|
||||
List[Dict] or Dict: List of papers or error dict
|
||||
"""
|
||||
query = f'au:"{author}"'
|
||||
return self.search(query, max_results, sort_by, sort_order, include_fields)
|
||||
|
||||
def get_papers_by_category(
|
||||
self,
|
||||
category: str,
|
||||
max_results: int = 10,
|
||||
sort_by: str = "submittedDate",
|
||||
sort_order: str = "descending",
|
||||
include_fields: Optional[List[str]] = None
|
||||
) -> Union[List[Dict[str, Any]], Dict[str, str]]:
|
||||
"""
|
||||
Get papers from a specific category.
|
||||
|
||||
Args:
|
||||
category: arXiv category (e.g., "cs.AI", "physics.gen-ph")
|
||||
max_results: Maximum number of results to return
|
||||
sort_by: Sort results by ("relevance", "lastUpdatedDate", "submittedDate")
|
||||
sort_order: Sort order ("ascending" or "descending")
|
||||
include_fields: List of fields to include in results
|
||||
|
||||
Returns:
|
||||
List[Dict] or Dict: List of papers or error dict
|
||||
"""
|
||||
query = f'cat:{category}'
|
||||
return self.search(query, max_results, sort_by, sort_order, include_fields)
|
||||
|
||||
def _result_to_dict(
|
||||
self,
|
||||
result: Any,
|
||||
include_fields: Optional[List[str]] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""Convert arxiv.Result to dictionary with selected fields."""
|
||||
# Default fields to include
|
||||
if include_fields is None:
|
||||
include_fields = [
|
||||
"title", "authors", "summary", "comment", "journal_ref",
|
||||
"doi", "primary_category", "categories", "links"
|
||||
]
|
||||
|
||||
# Build paper dict with selected fields
|
||||
paper = {}
|
||||
|
||||
# Always include these basic fields
|
||||
paper["arxiv_id"] = result.entry_id.split("/")[-1]
|
||||
paper["updated"] = result.updated.isoformat() if result.updated else None
|
||||
paper["published"] = result.published.isoformat() if result.published else None
|
||||
|
||||
# Add requested fields
|
||||
if "title" in include_fields:
|
||||
paper["title"] = result.title
|
||||
if "authors" in include_fields:
|
||||
paper["authors"] = [str(author) for author in result.authors]
|
||||
if "summary" in include_fields:
|
||||
paper["summary"] = result.summary
|
||||
if "comment" in include_fields:
|
||||
paper["comment"] = result.comment
|
||||
if "journal_ref" in include_fields:
|
||||
paper["journal_ref"] = result.journal_ref
|
||||
if "doi" in include_fields:
|
||||
paper["doi"] = result.doi
|
||||
if "primary_category" in include_fields:
|
||||
paper["primary_category"] = result.primary_category
|
||||
if "categories" in include_fields:
|
||||
paper["categories"] = result.categories
|
||||
if "links" in include_fields:
|
||||
paper["pdf_url"] = result.pdf_url
|
||||
paper["abstract_url"] = f"https://arxiv.org/abs/{paper['arxiv_id']}"
|
||||
|
||||
return paper
|
||||
|
||||
# Create instance for direct function access
|
||||
_arxiv_tools = ArxivTools()
|
||||
search_arxiv = _arxiv_tools.search
|
||||
get_arxiv_paper = _arxiv_tools.get_paper
|
||||
get_papers_by_author = _arxiv_tools.get_papers_by_author
|
||||
get_papers_by_category = _arxiv_tools.get_papers_by_category
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
print("\n==================================================")
|
||||
print("ArxivTools Demonstration")
|
||||
print("==================================================\n")
|
||||
|
||||
# 1. Search for papers
|
||||
print("1. Searching for Papers")
|
||||
print("------------------------------")
|
||||
query = "quantum computing"
|
||||
papers = search_arxiv(query, max_results=3)
|
||||
print(f"Papers about {query}:")
|
||||
if isinstance(papers, list):
|
||||
print(json.dumps(papers, indent=2))
|
||||
else:
|
||||
print(papers) # Show error
|
||||
print()
|
||||
|
||||
# 2. Get specific paper
|
||||
print("2. Getting Specific Paper")
|
||||
print("------------------------------")
|
||||
if isinstance(papers, list) and papers:
|
||||
paper_id = papers[0]["arxiv_id"]
|
||||
paper = get_arxiv_paper(paper_id)
|
||||
print(f"Paper {paper_id}:")
|
||||
if "error" not in paper:
|
||||
print(json.dumps(paper, indent=2))
|
||||
else:
|
||||
print(paper) # Show error
|
||||
print()
|
||||
|
||||
# 3. Get papers by author
|
||||
print("3. Getting Papers by Author")
|
||||
print("------------------------------")
|
||||
author = "Yoshua Bengio"
|
||||
author_papers = get_papers_by_author(author, max_results=3)
|
||||
print(f"Papers by {author}:")
|
||||
if isinstance(author_papers, list):
|
||||
print(json.dumps(author_papers, indent=2))
|
||||
else:
|
||||
print(author_papers) # Show error
|
||||
print()
|
||||
|
||||
# 4. Get papers by category
|
||||
print("4. Getting Papers by Category")
|
||||
print("------------------------------")
|
||||
category = "cs.AI"
|
||||
category_papers = get_papers_by_category(category, max_results=3)
|
||||
print(f"Papers in category {category}:")
|
||||
if isinstance(category_papers, list):
|
||||
print(json.dumps(category_papers, indent=2))
|
||||
else:
|
||||
print(category_papers) # Show error
|
||||
|
||||
print("\n==================================================")
|
||||
print("Demonstration Complete")
|
||||
print("==================================================")
|
||||
@@ -0,0 +1,278 @@
|
||||
"""Tools for performing calculations.
|
||||
|
||||
Usage:
|
||||
from praisonaiagents.tools import calculator_tools
|
||||
result = calculator_tools.evaluate("2 + 2 * 3")
|
||||
|
||||
or
|
||||
from praisonaiagents.tools import evaluate, solve_equation, convert_units
|
||||
result = evaluate("2 + 2 * 3")
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Dict, Optional, Any
|
||||
from importlib import util
|
||||
import math
|
||||
|
||||
class CalculatorTools:
|
||||
"""Tools for performing calculations."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize CalculatorTools."""
|
||||
self._check_dependencies()
|
||||
|
||||
def _check_dependencies(self):
|
||||
"""Check if required packages are installed."""
|
||||
missing = []
|
||||
for package in ['sympy', 'pint']:
|
||||
if util.find_spec(package) is None:
|
||||
missing.append(package)
|
||||
|
||||
if missing:
|
||||
raise ImportError(
|
||||
f"Required packages not available. Please install: {', '.join(missing)}\n"
|
||||
f"Run: pip install {' '.join(missing)}"
|
||||
)
|
||||
|
||||
def evaluate(
|
||||
self,
|
||||
expression: str,
|
||||
variables: Optional[Dict[str, float]] = None,
|
||||
precision: int = 10
|
||||
) -> Dict[str, Any]:
|
||||
"""Evaluate a mathematical expression."""
|
||||
try:
|
||||
if util.find_spec('sympy') is None:
|
||||
error_msg = "sympy package is not available. Please install it using: pip install sympy"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
# Import sympy only when needed
|
||||
import sympy
|
||||
|
||||
# Replace common mathematical functions
|
||||
expression = expression.lower()
|
||||
replacements = {
|
||||
'sin(': 'math.sin(',
|
||||
'cos(': 'math.cos(',
|
||||
'tan(': 'math.tan(',
|
||||
'sqrt(': 'math.sqrt(',
|
||||
'log(': 'math.log(',
|
||||
'exp(': 'math.exp(',
|
||||
'pi': str(math.pi),
|
||||
'e': str(math.e)
|
||||
}
|
||||
for old, new in replacements.items():
|
||||
expression = expression.replace(old, new)
|
||||
|
||||
# Create safe namespace
|
||||
safe_dict = {
|
||||
'math': math,
|
||||
'__builtins__': None
|
||||
}
|
||||
if variables:
|
||||
safe_dict.update(variables)
|
||||
|
||||
# Evaluate expression
|
||||
result = eval(expression, safe_dict)
|
||||
|
||||
# Round to specified precision
|
||||
if isinstance(result, (int, float)):
|
||||
return {"result": round(float(result), precision)}
|
||||
return {"error": "Invalid expression"}
|
||||
except Exception as e:
|
||||
error_msg = f"Error evaluating expression: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def solve_equation(
|
||||
self,
|
||||
equation: str,
|
||||
variable: str = 'x'
|
||||
) -> Dict[str, Any]:
|
||||
"""Solve a mathematical equation."""
|
||||
try:
|
||||
if util.find_spec('sympy') is None:
|
||||
error_msg = "sympy package is not available. Please install it using: pip install sympy"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
# Import sympy only when needed
|
||||
import sympy
|
||||
|
||||
# Parse equation
|
||||
if '=' in equation:
|
||||
left, right = equation.split('=')
|
||||
equation = f"({left}) - ({right})"
|
||||
|
||||
# Convert to SymPy expression
|
||||
x = sympy.Symbol(variable)
|
||||
expr = sympy.sympify(equation)
|
||||
|
||||
# Solve equation
|
||||
solutions = sympy.solve(expr, x)
|
||||
|
||||
# Convert complex solutions to real if possible
|
||||
real_solutions = []
|
||||
for sol in solutions:
|
||||
if sol.is_real:
|
||||
real_solutions.append(float(sol))
|
||||
|
||||
return {"solutions": real_solutions} if real_solutions else {"error": "No real solutions found"}
|
||||
except Exception as e:
|
||||
error_msg = f"Error solving equation: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def convert_units(
|
||||
self,
|
||||
value: float,
|
||||
from_unit: str,
|
||||
to_unit: str
|
||||
) -> Dict[str, Any]:
|
||||
"""Convert between different units."""
|
||||
try:
|
||||
if util.find_spec('pint') is None:
|
||||
error_msg = "pint package is not available. Please install it using: pip install pint"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
# Import pint only when needed
|
||||
import pint
|
||||
|
||||
# Create quantity with source unit
|
||||
ureg = pint.UnitRegistry()
|
||||
quantity = value * ureg(from_unit)
|
||||
|
||||
# Convert to target unit
|
||||
result = quantity.to(to_unit)
|
||||
|
||||
return {"result": float(result.magnitude)}
|
||||
except Exception as e:
|
||||
error_msg = f"Error converting units: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def calculate_statistics(
|
||||
self,
|
||||
numbers: List[float]
|
||||
) -> Dict[str, Any]:
|
||||
"""Calculate basic statistics for a list of numbers."""
|
||||
try:
|
||||
if not numbers:
|
||||
return {"error": "No numbers provided"}
|
||||
|
||||
n = len(numbers)
|
||||
mean = sum(numbers) / n
|
||||
|
||||
# Calculate variance and std dev
|
||||
squared_diff_sum = sum((x - mean) ** 2 for x in numbers)
|
||||
variance = squared_diff_sum / (n - 1) if n > 1 else 0
|
||||
std_dev = math.sqrt(variance)
|
||||
|
||||
# Calculate median
|
||||
sorted_nums = sorted(numbers)
|
||||
if n % 2 == 0:
|
||||
median = (sorted_nums[n//2 - 1] + sorted_nums[n//2]) / 2
|
||||
else:
|
||||
median = sorted_nums[n//2]
|
||||
|
||||
return {
|
||||
"mean": mean,
|
||||
"median": median,
|
||||
"std_dev": std_dev,
|
||||
"variance": variance,
|
||||
"min": min(numbers),
|
||||
"max": max(numbers),
|
||||
"range": max(numbers) - min(numbers),
|
||||
"count": n
|
||||
}
|
||||
except Exception as e:
|
||||
error_msg = f"Error calculating statistics: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def calculate_financial(
|
||||
self,
|
||||
principal: float,
|
||||
rate: float,
|
||||
time: float,
|
||||
frequency: str = 'yearly'
|
||||
) -> Dict[str, Any]:
|
||||
"""Calculate financial metrics like compound interest."""
|
||||
try:
|
||||
# Convert rate to decimal
|
||||
rate = rate / 100
|
||||
|
||||
# Get compounding frequency
|
||||
freq_map = {
|
||||
'yearly': 1,
|
||||
'semi-annual': 2,
|
||||
'quarterly': 4,
|
||||
'monthly': 12,
|
||||
'daily': 365
|
||||
}
|
||||
n = freq_map.get(frequency.lower(), 1)
|
||||
|
||||
# Calculate compound interest
|
||||
amount = principal * (1 + rate/n)**(n*time)
|
||||
interest = amount - principal
|
||||
|
||||
# Calculate simple interest
|
||||
simple_interest = principal * rate * time
|
||||
|
||||
return {
|
||||
"final_amount": amount,
|
||||
"compound_interest": interest,
|
||||
"simple_interest": simple_interest,
|
||||
"difference": interest - simple_interest
|
||||
}
|
||||
except Exception as e:
|
||||
error_msg = f"Error calculating financial metrics: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
# Create instance for direct function access
|
||||
_calculator_tools = CalculatorTools()
|
||||
evaluate = _calculator_tools.evaluate
|
||||
solve_equation = _calculator_tools.solve_equation
|
||||
convert_units = _calculator_tools.convert_units
|
||||
calculate_statistics = _calculator_tools.calculate_statistics
|
||||
calculate_financial = _calculator_tools.calculate_financial
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("\n==================================================")
|
||||
print("CalculatorTools Demonstration")
|
||||
print("==================================================\n")
|
||||
|
||||
print("1. Basic Arithmetic")
|
||||
print("------------------------------")
|
||||
print("2 + 2 =", evaluate("2 + 2")["result"])
|
||||
print("5 * 6 =", evaluate("5 * 6")["result"])
|
||||
print("10 / 3 =", evaluate("10 / 3")["result"])
|
||||
print()
|
||||
|
||||
print("2. Complex Expressions")
|
||||
print("------------------------------")
|
||||
print("(2 + 3) * 4 =", evaluate("(2 + 3) * 4")["result"])
|
||||
print("2^3 + 4 =", evaluate("2^3 + 4")["result"])
|
||||
print("sqrt(16) + 2 =", evaluate("sqrt(16) + 2")["result"])
|
||||
print()
|
||||
|
||||
print("3. Solving Equations")
|
||||
print("------------------------------")
|
||||
result = solve_equation("x^2 - 5*x + 6 = 0")
|
||||
print("x^2 - 5*x + 6 = 0")
|
||||
print("Solutions:", result["solutions"])
|
||||
print()
|
||||
|
||||
print("4. Unit Conversions")
|
||||
print("------------------------------")
|
||||
print("100 meters to kilometers:", convert_units(100, "meters", "kilometers")["result"])
|
||||
print("1 hour to minutes:", convert_units(1, "hours", "minutes")["result"])
|
||||
print("32 fahrenheit to celsius:", convert_units(32, "fahrenheit", "celsius")["result"])
|
||||
print()
|
||||
|
||||
print("==================================================")
|
||||
print("Demonstration Complete")
|
||||
print("==================================================")
|
||||
@@ -0,0 +1,266 @@
|
||||
"""Tools for working with CSV files.
|
||||
|
||||
Usage:
|
||||
from praisonaiagents.tools import csv_tools
|
||||
df = csv_tools.read_csv("data.csv")
|
||||
|
||||
or
|
||||
from praisonaiagents.tools import read_csv, write_csv, merge_csv
|
||||
df = read_csv("data.csv")
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Dict, Union, Optional, Any, TYPE_CHECKING
|
||||
from importlib import util
|
||||
import json
|
||||
import csv
|
||||
from pathlib import Path
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import pandas as pd
|
||||
|
||||
class CSVTools:
|
||||
"""Tools for working with CSV files."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize CSVTools."""
|
||||
pass
|
||||
|
||||
def _get_pandas(self) -> Optional['pd']:
|
||||
"""Get pandas module, installing if needed"""
|
||||
if util.find_spec('pandas') is None:
|
||||
error_msg = "pandas package is not available. Please install it using: pip install pandas"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
import pandas as pd
|
||||
return pd
|
||||
|
||||
def read_csv(
|
||||
self,
|
||||
filepath: str,
|
||||
encoding: str = 'utf-8',
|
||||
delimiter: str = ',',
|
||||
header: Union[int, List[int], None] = 0,
|
||||
usecols: Optional[List[str]] = None,
|
||||
dtype: Optional[Dict[str, str]] = None,
|
||||
parse_dates: Optional[List[str]] = None,
|
||||
na_values: Optional[List[str]] = None,
|
||||
nrows: Optional[int] = None
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Read a CSV file with advanced options.
|
||||
|
||||
Args:
|
||||
filepath: Path to CSV file
|
||||
encoding: File encoding
|
||||
delimiter: Column delimiter
|
||||
header: Row number(s) to use as column names
|
||||
usecols: Columns to read
|
||||
dtype: Dict of column dtypes
|
||||
parse_dates: List of columns to parse as dates
|
||||
na_values: Additional strings to recognize as NA/NaN
|
||||
nrows: Number of rows to read
|
||||
|
||||
Returns:
|
||||
List of row dicts
|
||||
"""
|
||||
try:
|
||||
pd = self._get_pandas()
|
||||
if pd is None:
|
||||
return {"error": "pandas package not available"}
|
||||
|
||||
df = pd.read_csv(
|
||||
filepath,
|
||||
encoding=encoding,
|
||||
delimiter=delimiter,
|
||||
header=header,
|
||||
usecols=usecols,
|
||||
dtype=dtype,
|
||||
parse_dates=parse_dates,
|
||||
na_values=na_values,
|
||||
nrows=nrows
|
||||
)
|
||||
return df.to_dict('records')
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error reading CSV file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def write_csv(
|
||||
self,
|
||||
filepath: str,
|
||||
data: List[Dict[str, Any]],
|
||||
encoding: str = 'utf-8',
|
||||
delimiter: str = ',',
|
||||
index: bool = False,
|
||||
header: bool = True,
|
||||
float_format: Optional[str] = None,
|
||||
date_format: Optional[str] = None,
|
||||
mode: str = 'w'
|
||||
) -> bool:
|
||||
"""Write data to a CSV file.
|
||||
|
||||
Args:
|
||||
filepath: Path to CSV file
|
||||
data: List of row dicts to write
|
||||
encoding: File encoding
|
||||
delimiter: Column delimiter
|
||||
index: Whether to write row indices
|
||||
header: Whether to write column headers
|
||||
float_format: Format string for float values
|
||||
date_format: Format string for date values
|
||||
mode: Write mode ('w' for write, 'a' for append)
|
||||
|
||||
Returns:
|
||||
bool: Success status
|
||||
"""
|
||||
try:
|
||||
pd = self._get_pandas()
|
||||
if pd is None:
|
||||
return False
|
||||
|
||||
df = pd.DataFrame(data)
|
||||
df.to_csv(
|
||||
filepath,
|
||||
encoding=encoding,
|
||||
sep=delimiter,
|
||||
index=index,
|
||||
header=header,
|
||||
float_format=float_format,
|
||||
date_format=date_format,
|
||||
mode=mode
|
||||
)
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error writing CSV file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
def merge_csv(
|
||||
self,
|
||||
files: List[str],
|
||||
output_file: str,
|
||||
how: str = 'inner',
|
||||
on: Optional[Union[str, List[str]]] = None,
|
||||
suffixes: Optional[tuple] = None
|
||||
) -> bool:
|
||||
"""Merge multiple CSV files.
|
||||
|
||||
Args:
|
||||
files: List of CSV files to merge
|
||||
output_file: Output file path
|
||||
how: Merge method ('inner', 'outer', 'left', 'right')
|
||||
on: Column(s) to merge on
|
||||
suffixes: Suffixes for overlapping columns
|
||||
|
||||
Returns:
|
||||
bool: Success status
|
||||
"""
|
||||
try:
|
||||
if len(files) < 2:
|
||||
error_msg = "At least two files are required for merging"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
pd = self._get_pandas()
|
||||
if pd is None:
|
||||
return False
|
||||
|
||||
# Read first file
|
||||
result = pd.read_csv(files[0])
|
||||
|
||||
# Merge with remaining files
|
||||
for file in files[1:]:
|
||||
df = pd.read_csv(file)
|
||||
result = pd.merge(
|
||||
result,
|
||||
df,
|
||||
how=how,
|
||||
on=on,
|
||||
suffixes=suffixes or ('_1', '_2')
|
||||
)
|
||||
|
||||
# Write merged result
|
||||
result.to_csv(output_file, index=False)
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error merging CSV files: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
# Create instance for direct function access
|
||||
_csv_tools = CSVTools()
|
||||
read_csv = _csv_tools.read_csv
|
||||
write_csv = _csv_tools.write_csv
|
||||
merge_csv = _csv_tools.merge_csv
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("\n==================================================")
|
||||
print("CSVTools Demonstration")
|
||||
print("==================================================\n")
|
||||
|
||||
# Create a temporary file for testing
|
||||
import tempfile
|
||||
import os
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix='.csv', delete=False) as temp:
|
||||
temp_file = temp.name
|
||||
|
||||
print("1. Writing CSV File")
|
||||
print("------------------------------")
|
||||
data = [
|
||||
{"name": "Alice", "age": 25, "city": "New York"},
|
||||
{"name": "Bob", "age": 30, "city": "San Francisco"},
|
||||
{"name": "Charlie", "age": 35, "city": "Chicago"}
|
||||
]
|
||||
result = write_csv(temp_file, data)
|
||||
print(f"Data written successfully: {result}")
|
||||
print()
|
||||
|
||||
print("2. Reading CSV File")
|
||||
print("------------------------------")
|
||||
read_data = read_csv(temp_file)
|
||||
print("Contents of CSV file:")
|
||||
for row in read_data:
|
||||
print(row)
|
||||
print()
|
||||
|
||||
print("3. Merging CSV Files")
|
||||
print("------------------------------")
|
||||
# Create a second file for merging
|
||||
with tempfile.NamedTemporaryFile(suffix='.csv', delete=False) as temp2:
|
||||
temp_file2 = temp2.name
|
||||
data2 = [
|
||||
{"name": "Alice", "salary": 75000},
|
||||
{"name": "Bob", "salary": 85000},
|
||||
{"name": "Charlie", "salary": 95000}
|
||||
]
|
||||
write_csv(temp_file2, data2)
|
||||
|
||||
# Merge files
|
||||
with tempfile.NamedTemporaryFile(suffix='.csv', delete=False) as temp3:
|
||||
temp_file3 = temp3.name
|
||||
result = merge_csv(
|
||||
[temp_file, temp_file2],
|
||||
temp_file3,
|
||||
how='inner',
|
||||
on='name'
|
||||
)
|
||||
print(f"Files merged successfully: {result}")
|
||||
if result:
|
||||
merged_data = read_csv(temp_file3)
|
||||
print("\nMerged contents:")
|
||||
for row in merged_data:
|
||||
print(row)
|
||||
print()
|
||||
|
||||
# Clean up temporary files
|
||||
os.unlink(temp_file)
|
||||
os.unlink(temp_file2)
|
||||
os.unlink(temp_file3)
|
||||
|
||||
print("==================================================")
|
||||
print("Demonstration Complete")
|
||||
print("==================================================\n")
|
||||
@@ -0,0 +1,268 @@
|
||||
"""Tools for working with DuckDB databases.
|
||||
|
||||
Usage:
|
||||
from praisonaiagents.tools import duckdb_tools
|
||||
df = duckdb_tools.query("SELECT * FROM my_table")
|
||||
|
||||
or
|
||||
from praisonaiagents.tools import query_db, create_table, load_data
|
||||
df = query_db("SELECT * FROM my_table")
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Dict, Any, Optional, Union, TYPE_CHECKING
|
||||
from importlib import util
|
||||
import json
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import duckdb
|
||||
import pandas as pd
|
||||
|
||||
class DuckDBTools:
|
||||
"""Tools for working with DuckDB databases."""
|
||||
|
||||
def __init__(self, database: str = ':memory:'):
|
||||
"""Initialize DuckDBTools.
|
||||
|
||||
Args:
|
||||
database: Path to database file or ':memory:' for in-memory database
|
||||
"""
|
||||
self.database = database
|
||||
self._conn = None
|
||||
|
||||
def _get_duckdb(self) -> Optional['duckdb']:
|
||||
"""Get duckdb module, installing if needed"""
|
||||
if util.find_spec('duckdb') is None:
|
||||
error_msg = "duckdb package is not available. Please install it using: pip install duckdb"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
import duckdb
|
||||
return duckdb
|
||||
|
||||
def _get_pandas(self) -> Optional['pd']:
|
||||
"""Get pandas module, installing if needed"""
|
||||
if util.find_spec('pandas') is None:
|
||||
error_msg = "pandas package is not available. Please install it using: pip install pandas"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
import pandas as pd
|
||||
return pd
|
||||
|
||||
def _get_connection(self) -> Optional['duckdb.DuckDBPyConnection']:
|
||||
"""Get or create database connection"""
|
||||
if self._conn is None:
|
||||
duckdb = self._get_duckdb()
|
||||
if duckdb is None:
|
||||
return None
|
||||
try:
|
||||
self._conn = duckdb.connect(self.database)
|
||||
except Exception as e:
|
||||
error_msg = f"Error connecting to database {self.database}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
return self._conn
|
||||
|
||||
def execute_query(
|
||||
self,
|
||||
query: str,
|
||||
params: Optional[Union[tuple, dict]] = None,
|
||||
return_df: bool = True
|
||||
) -> Union[List[Dict[str, Any]], Dict[str, str]]:
|
||||
"""Execute a SQL query.
|
||||
|
||||
Args:
|
||||
query: SQL query to execute
|
||||
params: Query parameters
|
||||
return_df: If True, return results as DataFrame records
|
||||
|
||||
Returns:
|
||||
Query results as list of dicts, or error dict
|
||||
"""
|
||||
try:
|
||||
conn = self._get_connection()
|
||||
if conn is None:
|
||||
return {"error": "Could not connect to database"}
|
||||
|
||||
if params:
|
||||
result = conn.execute(query, params)
|
||||
else:
|
||||
result = conn.execute(query)
|
||||
|
||||
if return_df:
|
||||
pd = self._get_pandas()
|
||||
if pd is None:
|
||||
return {"error": "pandas package not available"}
|
||||
df = result.df()
|
||||
return df.to_dict('records')
|
||||
else:
|
||||
return [dict(row) for row in result.fetchall()]
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error executing query: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def load_csv(
|
||||
self,
|
||||
table_name: str,
|
||||
filepath: str,
|
||||
schema: Optional[Dict[str, str]] = None,
|
||||
if_exists: str = 'replace'
|
||||
) -> bool:
|
||||
"""Load a CSV file into a table.
|
||||
|
||||
Args:
|
||||
table_name: Name of table to create
|
||||
filepath: Path to CSV file
|
||||
schema: Optional column definitions
|
||||
if_exists: What to do if table exists ('fail', 'replace', 'append')
|
||||
|
||||
Returns:
|
||||
bool: Success status
|
||||
"""
|
||||
try:
|
||||
conn = self._get_connection()
|
||||
if conn is None:
|
||||
return False
|
||||
|
||||
# Check if table exists
|
||||
exists = conn.execute(f"""
|
||||
SELECT name FROM sqlite_master
|
||||
WHERE type='table' AND name='{table_name}'
|
||||
""").fetchone() is not None
|
||||
|
||||
if exists:
|
||||
if if_exists == 'fail':
|
||||
raise ValueError(f"Table {table_name} already exists")
|
||||
elif if_exists == 'replace':
|
||||
conn.execute(f"DROP TABLE IF EXISTS {table_name}")
|
||||
elif if_exists != 'append':
|
||||
raise ValueError("if_exists must be 'fail', 'replace', or 'append'")
|
||||
|
||||
# Create table if needed
|
||||
if not exists or if_exists == 'replace':
|
||||
if schema:
|
||||
# Create table with schema
|
||||
columns = ', '.join(f"{k} {v}" for k, v in schema.items())
|
||||
conn.execute(f"CREATE TABLE {table_name} ({columns})")
|
||||
else:
|
||||
# Infer schema from CSV
|
||||
conn.execute(f"""
|
||||
CREATE TABLE {table_name} AS
|
||||
SELECT * FROM read_csv_auto('{filepath}')
|
||||
WHERE 1=0
|
||||
""")
|
||||
|
||||
# Load data
|
||||
conn.execute(f"""
|
||||
INSERT INTO {table_name}
|
||||
SELECT * FROM read_csv_auto('{filepath}')
|
||||
""")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error loading CSV file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
def export_csv(
|
||||
self,
|
||||
query: str,
|
||||
filepath: str,
|
||||
params: Optional[Union[tuple, dict]] = None
|
||||
) -> bool:
|
||||
"""Export query results to CSV.
|
||||
|
||||
Args:
|
||||
query: SQL query to execute
|
||||
filepath: Output file path
|
||||
params: Optional query parameters
|
||||
|
||||
Returns:
|
||||
bool: Success status
|
||||
"""
|
||||
try:
|
||||
# Execute query and get results as DataFrame
|
||||
results = self.execute_query(query, params)
|
||||
if isinstance(results, dict) and 'error' in results:
|
||||
return False
|
||||
|
||||
pd = self._get_pandas()
|
||||
if pd is None:
|
||||
return False
|
||||
|
||||
# Convert to DataFrame and save
|
||||
df = pd.DataFrame(results)
|
||||
df.to_csv(filepath, index=False)
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error exporting to CSV file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
def close(self):
|
||||
"""Close database connection."""
|
||||
if self._conn:
|
||||
self._conn.close()
|
||||
self._conn = None
|
||||
|
||||
# Create instance for direct function access
|
||||
_duckdb_tools = DuckDBTools()
|
||||
execute_query = _duckdb_tools.execute_query
|
||||
load_csv = _duckdb_tools.load_csv
|
||||
export_csv = _duckdb_tools.export_csv
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("\n==================================================")
|
||||
print("DuckDBTools Demonstration")
|
||||
print("==================================================\n")
|
||||
|
||||
# Create a temporary file for testing
|
||||
import tempfile
|
||||
import os
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix='.csv', delete=False) as temp:
|
||||
temp_file = temp.name
|
||||
|
||||
# Create sample data
|
||||
with open(temp_file, 'w') as f:
|
||||
f.write("name,age,city\n")
|
||||
f.write("Alice,25,New York\n")
|
||||
f.write("Bob,30,San Francisco\n")
|
||||
f.write("Charlie,35,Chicago\n")
|
||||
|
||||
print("1. Loading CSV File")
|
||||
print("------------------------------")
|
||||
result = load_csv('users', temp_file)
|
||||
print(f"CSV loaded successfully: {result}")
|
||||
print()
|
||||
|
||||
print("2. Executing Query")
|
||||
print("------------------------------")
|
||||
query = "SELECT * FROM users WHERE age > 25"
|
||||
results = execute_query(query)
|
||||
print("Query results:")
|
||||
for row in results:
|
||||
print(row)
|
||||
print()
|
||||
|
||||
print("3. Exporting Query Results")
|
||||
print("------------------------------")
|
||||
with tempfile.NamedTemporaryFile(suffix='.csv', delete=False) as temp2:
|
||||
temp_file2 = temp2.name
|
||||
result = export_csv(query, temp_file2)
|
||||
print(f"Results exported successfully: {result}")
|
||||
if result:
|
||||
print("\nExported file contents:")
|
||||
with open(temp_file2) as f:
|
||||
print(f.read())
|
||||
|
||||
# Clean up temporary files
|
||||
os.unlink(temp_file)
|
||||
os.unlink(temp_file2)
|
||||
|
||||
print("==================================================")
|
||||
print("Demonstration Complete")
|
||||
print("==================================================\n")
|
||||
@@ -0,0 +1,52 @@
|
||||
"""DuckDuckGo search functionality.
|
||||
|
||||
Usage:
|
||||
from praisonaiagents.tools import internet_search
|
||||
results = internet_search("AI news")
|
||||
|
||||
or
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
results = duckduckgo("AI news")
|
||||
"""
|
||||
|
||||
from typing import List, Dict
|
||||
import logging
|
||||
from importlib import util
|
||||
|
||||
def internet_search(query: str) -> List[Dict]:
|
||||
"""Perform an internet search using DuckDuckGo."""
|
||||
# Check if duckduckgo_search is installed
|
||||
if util.find_spec("duckduckgo_search") is None:
|
||||
error_msg = "DuckDuckGo search is not available. Please install duckduckgo_search package using: pip install duckduckgo_search"
|
||||
logging.error(error_msg)
|
||||
return [{"error": error_msg}]
|
||||
|
||||
try:
|
||||
# Import only when needed
|
||||
from duckduckgo_search import DDGS
|
||||
results = []
|
||||
ddgs = DDGS()
|
||||
for result in ddgs.text(keywords=query, max_results=5):
|
||||
results.append({
|
||||
"title": result.get("title", ""),
|
||||
"url": result.get("href", ""),
|
||||
"snippet": result.get("body", "")
|
||||
})
|
||||
return results
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error during DuckDuckGo search: {e}"
|
||||
logging.error(error_msg)
|
||||
return [{"error": error_msg}]
|
||||
|
||||
def duckduckgo(query: str) -> List[Dict]:
|
||||
"""Alias for internet_search function."""
|
||||
return internet_search(query)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
results = internet_search("Python programming")
|
||||
for result in results:
|
||||
print(f"\nTitle: {result.get('title')}")
|
||||
print(f"URL: {result.get('url')}")
|
||||
print(f"Snippet: {result.get('snippet')}")
|
||||
@@ -0,0 +1,310 @@
|
||||
"""Tools for working with Excel files.
|
||||
|
||||
Usage:
|
||||
from praisonaiagents.tools import excel_tools
|
||||
df = excel_tools.read_excel("data.xlsx")
|
||||
|
||||
or
|
||||
from praisonaiagents.tools import read_excel, write_excel, merge_excel
|
||||
df = read_excel("data.xlsx")
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Dict, Union, Optional, Any, TYPE_CHECKING, Tuple
|
||||
from importlib import util
|
||||
import json
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
import os
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import pandas as pd
|
||||
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
|
||||
from openpyxl.chart import BarChart, LineChart, PieChart, Reference
|
||||
from openpyxl.chart.label import DataLabelList
|
||||
|
||||
class ExcelTools:
|
||||
"""Tools for working with Excel files."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize ExcelTools."""
|
||||
pass
|
||||
|
||||
def _get_pandas(self) -> Optional['pd']:
|
||||
"""Get pandas module, installing if needed"""
|
||||
if util.find_spec('pandas') is None:
|
||||
error_msg = "pandas package is not available. Please install it using: pip install pandas"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
if util.find_spec('openpyxl') is None:
|
||||
error_msg = "openpyxl package is not available. Please install it using: pip install openpyxl"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
import pandas as pd
|
||||
return pd
|
||||
|
||||
def read_excel(
|
||||
self,
|
||||
filepath: str,
|
||||
sheet_name: Optional[Union[str, int, List[Union[str, int]]]] = 0,
|
||||
header: Optional[int] = 0,
|
||||
usecols: Optional[List[str]] = None,
|
||||
skiprows: Optional[Union[int, List[int]]] = None,
|
||||
na_values: Optional[List[str]] = None,
|
||||
dtype: Optional[Dict[str, str]] = None
|
||||
) -> Union[Dict[str, List[Dict[str, Any]]], List[Dict[str, Any]]]:
|
||||
"""Read an Excel file with advanced options.
|
||||
|
||||
Args:
|
||||
filepath: Path to Excel file
|
||||
sheet_name: Sheet name(s) or index(es)
|
||||
header: Row number(s) to use as column names
|
||||
usecols: Columns to read
|
||||
skiprows: Line numbers to skip
|
||||
na_values: Additional strings to recognize as NA/NaN
|
||||
dtype: Dict of column dtypes
|
||||
|
||||
Returns:
|
||||
Dict of sheet names to data if multiple sheets, else list of row dicts
|
||||
"""
|
||||
try:
|
||||
pd = self._get_pandas()
|
||||
if pd is None:
|
||||
return {"error": "Required packages not available"}
|
||||
|
||||
# Read Excel file
|
||||
df = pd.read_excel(
|
||||
filepath,
|
||||
sheet_name=sheet_name,
|
||||
header=header,
|
||||
usecols=usecols,
|
||||
skiprows=skiprows,
|
||||
na_values=na_values,
|
||||
dtype=dtype,
|
||||
engine='openpyxl'
|
||||
)
|
||||
|
||||
# Convert to dict format
|
||||
if isinstance(df, dict):
|
||||
return {
|
||||
name: df[name].to_dict('records')
|
||||
for name in df.keys()
|
||||
}
|
||||
else:
|
||||
return df.to_dict('records')
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error reading Excel file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def write_excel(
|
||||
self,
|
||||
filepath: str,
|
||||
data: Union[Dict[str, List[Dict[str, Any]]], List[Dict[str, Any]]],
|
||||
sheet_name: Optional[str] = None,
|
||||
index: bool = False,
|
||||
header: bool = True,
|
||||
mode: str = 'w'
|
||||
) -> bool:
|
||||
"""Write data to an Excel file.
|
||||
|
||||
Args:
|
||||
filepath: Path to Excel file
|
||||
data: Data to write (dict of sheet names to data or list of row dicts)
|
||||
sheet_name: Sheet name if data is a list
|
||||
index: Whether to write row indices
|
||||
header: Whether to write column headers
|
||||
mode: Write mode ('w' for write, 'a' for append)
|
||||
|
||||
Returns:
|
||||
bool: Success status
|
||||
"""
|
||||
try:
|
||||
pd = self._get_pandas()
|
||||
if pd is None:
|
||||
return False
|
||||
|
||||
# Convert data to DataFrame(s)
|
||||
if isinstance(data, dict):
|
||||
if mode == 'a' and os.path.exists(filepath):
|
||||
book = pd.ExcelFile(filepath)
|
||||
with pd.ExcelWriter(filepath, engine='openpyxl') as writer:
|
||||
# Copy existing sheets
|
||||
for sheet in book.sheet_names:
|
||||
pd.read_excel(filepath, sheet_name=sheet).to_excel(
|
||||
writer, sheet_name=sheet, index=index, header=header
|
||||
)
|
||||
# Add new sheets
|
||||
for name, sheet_data in data.items():
|
||||
df = pd.DataFrame(sheet_data)
|
||||
df.to_excel(
|
||||
writer, sheet_name=name, index=index, header=header
|
||||
)
|
||||
else:
|
||||
with pd.ExcelWriter(filepath, engine='openpyxl') as writer:
|
||||
for name, sheet_data in data.items():
|
||||
df = pd.DataFrame(sheet_data)
|
||||
df.to_excel(
|
||||
writer, sheet_name=name, index=index, header=header
|
||||
)
|
||||
else:
|
||||
if mode == 'a' and os.path.exists(filepath):
|
||||
book = pd.ExcelFile(filepath)
|
||||
with pd.ExcelWriter(filepath, engine='openpyxl') as writer:
|
||||
# Copy existing sheets
|
||||
for sheet in book.sheet_names:
|
||||
pd.read_excel(filepath, sheet_name=sheet).to_excel(
|
||||
writer, sheet_name=sheet, index=index, header=header
|
||||
)
|
||||
# Add new sheet
|
||||
df = pd.DataFrame(data)
|
||||
df.to_excel(
|
||||
writer,
|
||||
sheet_name=sheet_name or 'Sheet1',
|
||||
index=index,
|
||||
header=header
|
||||
)
|
||||
else:
|
||||
df = pd.DataFrame(data)
|
||||
df.to_excel(
|
||||
filepath,
|
||||
sheet_name=sheet_name or 'Sheet1',
|
||||
index=index,
|
||||
header=header,
|
||||
engine='openpyxl'
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error writing Excel file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
def merge_excel(
|
||||
self,
|
||||
files: List[str],
|
||||
output_file: str,
|
||||
how: str = 'inner',
|
||||
on: Optional[Union[str, List[str]]] = None,
|
||||
suffixes: Optional[Tuple[str, str]] = None
|
||||
) -> bool:
|
||||
"""Merge multiple Excel files.
|
||||
|
||||
Args:
|
||||
files: List of Excel files to merge
|
||||
output_file: Output file path
|
||||
how: Merge method ('inner', 'outer', 'left', 'right')
|
||||
on: Column(s) to merge on
|
||||
suffixes: Suffixes for overlapping columns
|
||||
|
||||
Returns:
|
||||
bool: Success status
|
||||
"""
|
||||
try:
|
||||
if len(files) < 2:
|
||||
error_msg = "At least two files are required for merging"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
# Read first file
|
||||
result = self.read_excel(files[0])
|
||||
|
||||
# Merge with remaining files
|
||||
for file in files[1:]:
|
||||
df = self.read_excel(file)
|
||||
if isinstance(df, dict):
|
||||
df = next(iter(df.values()))
|
||||
|
||||
pd = self._get_pandas()
|
||||
if pd is None:
|
||||
return False
|
||||
|
||||
result = pd.merge(
|
||||
pd.DataFrame(result),
|
||||
pd.DataFrame(df),
|
||||
how=how,
|
||||
on=on,
|
||||
suffixes=suffixes or ('_1', '_2')
|
||||
).to_dict('records')
|
||||
|
||||
# Write merged result
|
||||
return self.write_excel(output_file, result)
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error merging Excel files: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
# Create instance for direct function access
|
||||
_excel_tools = ExcelTools()
|
||||
read_excel = _excel_tools.read_excel
|
||||
write_excel = _excel_tools.write_excel
|
||||
merge_excel = _excel_tools.merge_excel
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("\n==================================================")
|
||||
print("ExcelTools Demonstration")
|
||||
print("==================================================\n")
|
||||
|
||||
# Create a temporary file for testing
|
||||
with tempfile.NamedTemporaryFile(suffix='.xlsx', delete=False) as temp:
|
||||
temp_file = temp.name
|
||||
|
||||
print("1. Writing Excel File")
|
||||
print("------------------------------")
|
||||
data = [
|
||||
{"name": "Alice", "age": 25, "city": "New York"},
|
||||
{"name": "Bob", "age": 30, "city": "San Francisco"},
|
||||
{"name": "Charlie", "age": 35, "city": "Chicago"}
|
||||
]
|
||||
result = write_excel(temp_file, data, "People")
|
||||
print(f"Data written successfully: {result}")
|
||||
print()
|
||||
|
||||
print("2. Reading Excel File")
|
||||
print("------------------------------")
|
||||
read_data = read_excel(temp_file)
|
||||
print("Contents of Excel file:")
|
||||
for row in read_data:
|
||||
print(row)
|
||||
print()
|
||||
|
||||
print("3. Merging Excel Files")
|
||||
print("------------------------------")
|
||||
# Create a second file for merging
|
||||
with tempfile.NamedTemporaryFile(suffix='.xlsx', delete=False) as temp2:
|
||||
temp_file2 = temp2.name
|
||||
data2 = [
|
||||
{"name": "Alice", "salary": 75000},
|
||||
{"name": "Bob", "salary": 85000},
|
||||
{"name": "Charlie", "salary": 95000}
|
||||
]
|
||||
write_excel(temp_file2, data2, "Salaries")
|
||||
|
||||
# Merge files
|
||||
with tempfile.NamedTemporaryFile(suffix='.xlsx', delete=False) as temp3:
|
||||
temp_file3 = temp3.name
|
||||
result = merge_excel(
|
||||
[temp_file, temp_file2],
|
||||
temp_file3,
|
||||
how='inner',
|
||||
on='name'
|
||||
)
|
||||
print(f"Files merged successfully: {result}")
|
||||
if result:
|
||||
merged_data = read_excel(temp_file3)
|
||||
print("\nMerged contents:")
|
||||
for row in merged_data:
|
||||
print(row)
|
||||
print()
|
||||
|
||||
# Clean up temporary files
|
||||
os.unlink(temp_file)
|
||||
os.unlink(temp_file2)
|
||||
os.unlink(temp_file3)
|
||||
|
||||
print("==================================================")
|
||||
print("Demonstration Complete")
|
||||
print("==================================================\n")
|
||||
@@ -0,0 +1,274 @@
|
||||
"""File handling tools for basic file operations.
|
||||
|
||||
Usage:
|
||||
from praisonaiagents.tools import file_tools
|
||||
content = file_tools.read_file("example.txt")
|
||||
file_tools.write_file("output.txt", "Hello World")
|
||||
|
||||
or
|
||||
from praisonaiagents.tools import read_file, write_file, list_files
|
||||
content = read_file("example.txt")
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
from typing import List, Dict, Union, Optional
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import logging
|
||||
|
||||
class FileTools:
|
||||
"""Tools for file operations including read, write, list, and information."""
|
||||
|
||||
@staticmethod
|
||||
def read_file(filepath: str, encoding: str = 'utf-8') -> str:
|
||||
"""
|
||||
Read content from a file.
|
||||
|
||||
Args:
|
||||
filepath: Path to the file
|
||||
encoding: File encoding (default: utf-8)
|
||||
|
||||
Returns:
|
||||
str: Content of the file
|
||||
"""
|
||||
try:
|
||||
with open(filepath, 'r', encoding=encoding) as f:
|
||||
return f.read()
|
||||
except Exception as e:
|
||||
error_msg = f"Error reading file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return error_msg
|
||||
|
||||
@staticmethod
|
||||
def write_file(filepath: str, content: str, encoding: str = 'utf-8') -> bool:
|
||||
"""
|
||||
Write content to a file.
|
||||
|
||||
Args:
|
||||
filepath: Path to the file
|
||||
content: Content to write
|
||||
encoding: File encoding (default: utf-8)
|
||||
|
||||
Returns:
|
||||
bool: True if successful, False otherwise
|
||||
"""
|
||||
try:
|
||||
# Create directory if it doesn't exist
|
||||
os.makedirs(os.path.dirname(filepath), exist_ok=True)
|
||||
with open(filepath, 'w', encoding=encoding) as f:
|
||||
f.write(content)
|
||||
return True
|
||||
except Exception as e:
|
||||
error_msg = f"Error writing to file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def list_files(directory: str, pattern: Optional[str] = None) -> List[Dict[str, Union[str, int]]]:
|
||||
"""
|
||||
List files in a directory with optional pattern matching.
|
||||
|
||||
Args:
|
||||
directory: Directory path
|
||||
pattern: Optional glob pattern (e.g., "*.txt")
|
||||
|
||||
Returns:
|
||||
List[Dict]: List of file information dictionaries
|
||||
"""
|
||||
try:
|
||||
path = Path(directory)
|
||||
if pattern:
|
||||
files = path.glob(pattern)
|
||||
else:
|
||||
files = path.iterdir()
|
||||
|
||||
result = []
|
||||
for file in files:
|
||||
if file.is_file():
|
||||
stat = file.stat()
|
||||
result.append({
|
||||
'name': file.name,
|
||||
'path': str(file),
|
||||
'size': stat.st_size,
|
||||
'modified': stat.st_mtime,
|
||||
'created': stat.st_ctime
|
||||
})
|
||||
return result
|
||||
except Exception as e:
|
||||
error_msg = f"Error listing files in {directory}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return [{'error': error_msg}]
|
||||
|
||||
@staticmethod
|
||||
def get_file_info(filepath: str) -> Dict[str, Union[str, int]]:
|
||||
"""
|
||||
Get detailed information about a file.
|
||||
|
||||
Args:
|
||||
filepath: Path to the file
|
||||
|
||||
Returns:
|
||||
Dict: File information including size, dates, etc.
|
||||
"""
|
||||
try:
|
||||
path = Path(filepath)
|
||||
if not path.exists():
|
||||
return {'error': f'File not found: {filepath}'}
|
||||
|
||||
stat = path.stat()
|
||||
return {
|
||||
'name': path.name,
|
||||
'path': str(path),
|
||||
'size': stat.st_size,
|
||||
'modified': stat.st_mtime,
|
||||
'created': stat.st_ctime,
|
||||
'is_file': path.is_file(),
|
||||
'is_dir': path.is_dir(),
|
||||
'extension': path.suffix,
|
||||
'parent': str(path.parent)
|
||||
}
|
||||
except Exception as e:
|
||||
error_msg = f"Error getting file info for {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {'error': error_msg}
|
||||
|
||||
@staticmethod
|
||||
def copy_file(src: str, dst: str) -> bool:
|
||||
"""
|
||||
Copy a file from source to destination.
|
||||
|
||||
Args:
|
||||
src: Source file path
|
||||
dst: Destination file path
|
||||
|
||||
Returns:
|
||||
bool: True if successful, False otherwise
|
||||
"""
|
||||
try:
|
||||
# Create destination directory if it doesn't exist
|
||||
os.makedirs(os.path.dirname(dst), exist_ok=True)
|
||||
shutil.copy2(src, dst)
|
||||
return True
|
||||
except Exception as e:
|
||||
error_msg = f"Error copying file from {src} to {dst}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def move_file(src: str, dst: str) -> bool:
|
||||
"""
|
||||
Move a file from source to destination.
|
||||
|
||||
Args:
|
||||
src: Source file path
|
||||
dst: Destination file path
|
||||
|
||||
Returns:
|
||||
bool: True if successful, False otherwise
|
||||
"""
|
||||
try:
|
||||
# Create destination directory if it doesn't exist
|
||||
os.makedirs(os.path.dirname(dst), exist_ok=True)
|
||||
shutil.move(src, dst)
|
||||
return True
|
||||
except Exception as e:
|
||||
error_msg = f"Error moving file from {src} to {dst}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def delete_file(filepath: str) -> bool:
|
||||
"""
|
||||
Delete a file.
|
||||
|
||||
Args:
|
||||
filepath: Path to the file
|
||||
|
||||
Returns:
|
||||
bool: True if successful, False otherwise
|
||||
"""
|
||||
try:
|
||||
os.remove(filepath)
|
||||
return True
|
||||
except Exception as e:
|
||||
error_msg = f"Error deleting file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
# Create instance for direct function access
|
||||
_file_tools = FileTools()
|
||||
read_file = _file_tools.read_file
|
||||
write_file = _file_tools.write_file
|
||||
list_files = _file_tools.list_files
|
||||
get_file_info = _file_tools.get_file_info
|
||||
copy_file = _file_tools.copy_file
|
||||
move_file = _file_tools.move_file
|
||||
delete_file = _file_tools.delete_file
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
print("\n==================================================")
|
||||
print("FileTools Demonstration")
|
||||
print("==================================================\n")
|
||||
|
||||
# Create a test directory
|
||||
test_dir = os.path.join(os.getcwd(), "test_files")
|
||||
os.makedirs(test_dir, exist_ok=True)
|
||||
|
||||
# Create test files
|
||||
test_file = os.path.join(test_dir, "test_file.txt")
|
||||
test_content = "Hello, this is a test file!"
|
||||
|
||||
print("1. Writing to file")
|
||||
print("------------------------------")
|
||||
success = write_file(test_file, test_content)
|
||||
print(f"Write successful: {success}\n")
|
||||
|
||||
print("2. Reading from file")
|
||||
print("------------------------------")
|
||||
content = read_file(test_file)
|
||||
print(f"Content: {content}\n")
|
||||
|
||||
print("3. File Information")
|
||||
print("------------------------------")
|
||||
info = get_file_info(test_file)
|
||||
print(json.dumps(info, indent=2))
|
||||
print()
|
||||
|
||||
print("4. Listing Files")
|
||||
print("------------------------------")
|
||||
files = list_files(test_dir, "*.txt")
|
||||
for file in files:
|
||||
print(f"Found: {file['name']} ({file['size']} bytes)")
|
||||
print()
|
||||
|
||||
print("5. Copying File")
|
||||
print("------------------------------")
|
||||
copy_file_path = os.path.join(test_dir, "test_file_copy.txt")
|
||||
copy_success = copy_file(test_file, copy_file_path)
|
||||
print(f"Copy successful: {copy_success}\n")
|
||||
|
||||
print("6. Moving File")
|
||||
print("------------------------------")
|
||||
move_file_path = os.path.join(test_dir, "test_file_moved.txt")
|
||||
move_success = move_file(copy_file_path, move_file_path)
|
||||
print(f"Move successful: {move_success}\n")
|
||||
|
||||
print("7. Deleting Files")
|
||||
print("------------------------------")
|
||||
delete_success = delete_file(test_file)
|
||||
print(f"Delete original successful: {delete_success}")
|
||||
delete_success = delete_file(move_file_path)
|
||||
print(f"Delete moved file successful: {delete_success}\n")
|
||||
|
||||
# Clean up test directory
|
||||
try:
|
||||
shutil.rmtree(test_dir)
|
||||
print("Test directory cleaned up successfully")
|
||||
except Exception as e:
|
||||
print(f"Error cleaning up test directory: {str(e)}")
|
||||
|
||||
print("\n==================================================")
|
||||
print("Demonstration Complete")
|
||||
print("==================================================")
|
||||
@@ -0,0 +1,515 @@
|
||||
"""Tools for working with JSON files.
|
||||
|
||||
Usage:
|
||||
from praisonaiagents.tools import json_tools
|
||||
data = json_tools.read_json("data.json")
|
||||
|
||||
or
|
||||
from praisonaiagents.tools import read_json, write_json, merge_json
|
||||
data = read_json("data.json")
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Dict, Union, Optional, Any, Tuple
|
||||
from importlib import util
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
class JSONTools:
|
||||
"""Tools for working with JSON files."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize JSONTools."""
|
||||
pass
|
||||
|
||||
def read_json(
|
||||
self,
|
||||
filepath: str,
|
||||
encoding: str = 'utf-8',
|
||||
validate_schema: Optional[Dict[str, Any]] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""Read a JSON file with optional schema validation.
|
||||
|
||||
Args:
|
||||
filepath: Path to JSON file
|
||||
encoding: File encoding
|
||||
validate_schema: Optional JSON schema for validation
|
||||
|
||||
Returns:
|
||||
Dict with JSON data
|
||||
"""
|
||||
try:
|
||||
# Read JSON file
|
||||
with open(filepath, 'r', encoding=encoding) as f:
|
||||
data = json.load(f)
|
||||
|
||||
# Validate against schema if provided
|
||||
if validate_schema:
|
||||
if util.find_spec('jsonschema') is None:
|
||||
error_msg = "jsonschema package is not available. Please install it using: pip install jsonschema"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
import jsonschema
|
||||
try:
|
||||
jsonschema.validate(instance=data, schema=validate_schema)
|
||||
except jsonschema.exceptions.ValidationError as e:
|
||||
error_msg = f"JSON validation failed: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
return data
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error reading JSON file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def write_json(
|
||||
self,
|
||||
data: Union[Dict[str, Any], List[Any]],
|
||||
filepath: str,
|
||||
encoding: str = 'utf-8',
|
||||
indent: int = 2,
|
||||
sort_keys: bool = False,
|
||||
ensure_ascii: bool = False
|
||||
) -> bool:
|
||||
"""Write data to a JSON file.
|
||||
|
||||
Args:
|
||||
data: Data to write
|
||||
filepath: Output file path
|
||||
encoding: File encoding
|
||||
indent: Number of spaces for indentation
|
||||
sort_keys: Sort dictionary keys
|
||||
ensure_ascii: Escape non-ASCII characters
|
||||
|
||||
Returns:
|
||||
True if successful, False otherwise
|
||||
"""
|
||||
try:
|
||||
with open(filepath, 'w', encoding=encoding) as f:
|
||||
json.dump(
|
||||
data,
|
||||
f,
|
||||
indent=indent,
|
||||
sort_keys=sort_keys,
|
||||
ensure_ascii=ensure_ascii
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
error_msg = f"Error writing JSON file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
def merge_json(
|
||||
self,
|
||||
files: List[str],
|
||||
output_file: str,
|
||||
merge_arrays: bool = True,
|
||||
overwrite_duplicates: bool = True
|
||||
) -> bool:
|
||||
"""Merge multiple JSON files.
|
||||
|
||||
Args:
|
||||
files: List of JSON files to merge
|
||||
output_file: Output file path
|
||||
merge_arrays: Merge arrays instead of overwriting
|
||||
overwrite_duplicates: Overwrite duplicate keys
|
||||
|
||||
Returns:
|
||||
True if successful, False otherwise
|
||||
"""
|
||||
try:
|
||||
if len(files) < 2:
|
||||
raise ValueError("At least two files are required for merging")
|
||||
|
||||
# Read first file
|
||||
result = self.read_json(files[0])
|
||||
|
||||
# Merge with remaining files
|
||||
for file in files[1:]:
|
||||
data = self.read_json(file)
|
||||
result = self._deep_merge(
|
||||
result,
|
||||
data,
|
||||
merge_arrays=merge_arrays,
|
||||
overwrite_duplicates=overwrite_duplicates
|
||||
)
|
||||
|
||||
# Write merged result
|
||||
return self.write_json(result, output_file)
|
||||
except Exception as e:
|
||||
error_msg = f"Error merging JSON files: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
def _deep_merge(
|
||||
self,
|
||||
dict1: Dict[str, Any],
|
||||
dict2: Dict[str, Any],
|
||||
merge_arrays: bool = True,
|
||||
overwrite_duplicates: bool = True
|
||||
) -> Dict[str, Any]:
|
||||
"""Deep merge two dictionaries.
|
||||
|
||||
Args:
|
||||
dict1: First dictionary
|
||||
dict2: Second dictionary
|
||||
merge_arrays: Merge arrays instead of overwriting
|
||||
overwrite_duplicates: Overwrite duplicate keys
|
||||
|
||||
Returns:
|
||||
Merged dictionary
|
||||
"""
|
||||
result = dict1.copy()
|
||||
|
||||
for key, value in dict2.items():
|
||||
if key in result:
|
||||
if isinstance(result[key], dict) and isinstance(value, dict):
|
||||
result[key] = self._deep_merge(
|
||||
result[key],
|
||||
value,
|
||||
merge_arrays=merge_arrays,
|
||||
overwrite_duplicates=overwrite_duplicates
|
||||
)
|
||||
elif isinstance(result[key], list) and isinstance(value, list):
|
||||
if merge_arrays:
|
||||
result[key].extend(value)
|
||||
elif overwrite_duplicates:
|
||||
result[key] = value
|
||||
elif overwrite_duplicates:
|
||||
result[key] = value
|
||||
else:
|
||||
result[key] = value
|
||||
|
||||
return result
|
||||
|
||||
def validate_json(
|
||||
self,
|
||||
data: Union[Dict[str, Any], str],
|
||||
schema: Dict[str, Any]
|
||||
) -> Tuple[bool, Optional[str]]:
|
||||
"""Validate JSON data against a schema.
|
||||
|
||||
Args:
|
||||
data: JSON data or filepath
|
||||
schema: JSON schema for validation
|
||||
|
||||
Returns:
|
||||
Tuple of (is_valid, error_message)
|
||||
"""
|
||||
try:
|
||||
if util.find_spec('jsonschema') is None:
|
||||
error_msg = "jsonschema package is not available. Please install it using: pip install jsonschema"
|
||||
logging.error(error_msg)
|
||||
return False, error_msg
|
||||
import jsonschema
|
||||
|
||||
# Load data if filepath provided
|
||||
if isinstance(data, str):
|
||||
with open(data, 'r') as f:
|
||||
data = json.load(f)
|
||||
|
||||
jsonschema.validate(instance=data, schema=schema)
|
||||
return True, None
|
||||
|
||||
except jsonschema.exceptions.ValidationError as e:
|
||||
error_msg = f"JSON validation failed: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False, error_msg
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error validating JSON: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False, error_msg
|
||||
|
||||
def analyze_json(
|
||||
self,
|
||||
data: Union[Dict[str, Any], str],
|
||||
max_depth: int = 10
|
||||
) -> Dict[str, Any]:
|
||||
"""Analyze JSON data structure.
|
||||
|
||||
Args:
|
||||
data: JSON data or filepath
|
||||
max_depth: Maximum depth to analyze
|
||||
|
||||
Returns:
|
||||
Dict with analysis results
|
||||
"""
|
||||
try:
|
||||
# Load data if filepath provided
|
||||
if isinstance(data, str):
|
||||
data = self.read_json(data)
|
||||
|
||||
def analyze_value(value: Any, depth: int = 0) -> Dict[str, Any]:
|
||||
if depth >= max_depth:
|
||||
return {'type': 'max_depth_reached'}
|
||||
|
||||
result = {'type': type(value).__name__}
|
||||
|
||||
if isinstance(value, dict):
|
||||
result['size'] = len(value)
|
||||
result['keys'] = list(value.keys())
|
||||
if depth < max_depth - 1:
|
||||
result['children'] = {
|
||||
k: analyze_value(v, depth + 1)
|
||||
for k, v in value.items()
|
||||
}
|
||||
|
||||
elif isinstance(value, list):
|
||||
result['length'] = len(value)
|
||||
if value:
|
||||
result['element_types'] = list(set(
|
||||
type(x).__name__ for x in value
|
||||
))
|
||||
if depth < max_depth - 1:
|
||||
result['sample_elements'] = [
|
||||
analyze_value(x, depth + 1)
|
||||
for x in value[:5]
|
||||
]
|
||||
|
||||
elif isinstance(value, (int, float)):
|
||||
result.update({
|
||||
'value': value,
|
||||
'is_integer': isinstance(value, int)
|
||||
})
|
||||
|
||||
elif isinstance(value, str):
|
||||
result.update({
|
||||
'length': len(value),
|
||||
'sample': value[:100] if len(value) > 100 else value
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
return {
|
||||
'analysis_time': datetime.now().isoformat(),
|
||||
'structure': analyze_value(data)
|
||||
}
|
||||
except Exception as e:
|
||||
error_msg = f"Error analyzing JSON: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {}
|
||||
|
||||
def transform_json(
|
||||
self,
|
||||
data: Union[Dict[str, Any], str],
|
||||
transformations: List[Dict[str, Any]]
|
||||
) -> Dict[str, Any]:
|
||||
"""Transform JSON data using a list of operations.
|
||||
|
||||
Args:
|
||||
data: JSON data or filepath
|
||||
transformations: List of transformation operations
|
||||
|
||||
Returns:
|
||||
Transformed JSON data
|
||||
"""
|
||||
try:
|
||||
# Load data if filepath provided
|
||||
if isinstance(data, str):
|
||||
data = self.read_json(data)
|
||||
|
||||
result = data.copy()
|
||||
|
||||
for transform in transformations:
|
||||
op = transform.get('operation')
|
||||
path = transform.get('path', '').split('.')
|
||||
value = transform.get('value')
|
||||
|
||||
if op == 'set':
|
||||
self._set_value(result, path, value)
|
||||
elif op == 'delete':
|
||||
self._delete_value(result, path)
|
||||
elif op == 'rename':
|
||||
old_path = path
|
||||
new_path = value.split('.')
|
||||
self._rename_key(result, old_path, new_path)
|
||||
elif op == 'move':
|
||||
old_path = path
|
||||
new_path = value.split('.')
|
||||
self._move_value(result, old_path, new_path)
|
||||
|
||||
return result
|
||||
except Exception as e:
|
||||
error_msg = f"Error transforming JSON: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return data
|
||||
|
||||
def _set_value(self, data: Dict[str, Any], path: List[str], value: Any):
|
||||
"""Set a value at the specified path."""
|
||||
current = data
|
||||
for key in path[:-1]:
|
||||
if key not in current:
|
||||
current[key] = {}
|
||||
current = current[key]
|
||||
current[path[-1]] = value
|
||||
|
||||
def _delete_value(self, data: Dict[str, Any], path: List[str]):
|
||||
"""Delete a value at the specified path."""
|
||||
current = data
|
||||
for key in path[:-1]:
|
||||
if key not in current:
|
||||
return
|
||||
current = current[key]
|
||||
if path[-1] in current:
|
||||
del current[path[-1]]
|
||||
|
||||
def _rename_key(
|
||||
self,
|
||||
data: Dict[str, Any],
|
||||
old_path: List[str],
|
||||
new_path: List[str]
|
||||
):
|
||||
"""Rename a key at the specified path."""
|
||||
value = self._get_value(data, old_path)
|
||||
if value is not None:
|
||||
self._delete_value(data, old_path)
|
||||
self._set_value(data, new_path, value)
|
||||
|
||||
def _move_value(
|
||||
self,
|
||||
data: Dict[str, Any],
|
||||
old_path: List[str],
|
||||
new_path: List[str]
|
||||
):
|
||||
"""Move a value from one path to another."""
|
||||
self._rename_key(data, old_path, new_path)
|
||||
|
||||
def _get_value(
|
||||
self,
|
||||
data: Dict[str, Any],
|
||||
path: List[str]
|
||||
) -> Optional[Any]:
|
||||
"""Get a value at the specified path."""
|
||||
current = data
|
||||
for key in path:
|
||||
if key not in current:
|
||||
return None
|
||||
current = current[key]
|
||||
return current
|
||||
|
||||
# Create instance for direct function access
|
||||
_json_tools = JSONTools()
|
||||
read_json = _json_tools.read_json
|
||||
write_json = _json_tools.write_json
|
||||
merge_json = _json_tools.merge_json
|
||||
validate_json = _json_tools.validate_json
|
||||
analyze_json = _json_tools.analyze_json
|
||||
transform_json = _json_tools.transform_json
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
print("\n==================================================")
|
||||
print("JSONTools Demonstration")
|
||||
print("==================================================\n")
|
||||
|
||||
# Sample data
|
||||
data1 = {
|
||||
'id': 1,
|
||||
'name': 'Alice',
|
||||
'scores': [95, 87, 92],
|
||||
'details': {
|
||||
'age': 25,
|
||||
'city': 'New York'
|
||||
}
|
||||
}
|
||||
|
||||
data2 = {
|
||||
'id': 2,
|
||||
'name': 'Bob',
|
||||
'scores': [88, 90, 85],
|
||||
'details': {
|
||||
'age': 30,
|
||||
'country': 'USA'
|
||||
}
|
||||
}
|
||||
|
||||
# 1. Write JSON files
|
||||
print("1. Writing JSON Files")
|
||||
print("------------------------------")
|
||||
success = write_json(data1, 'test1.json')
|
||||
print(f"First file written: {success}")
|
||||
success = write_json(data2, 'test2.json')
|
||||
print(f"Second file written: {success}")
|
||||
print()
|
||||
|
||||
# 2. Read JSON file
|
||||
print("2. Reading JSON File")
|
||||
print("------------------------------")
|
||||
data = read_json('test1.json')
|
||||
print("Contents of test1.json:")
|
||||
print(json.dumps(data, indent=2))
|
||||
print()
|
||||
|
||||
# 3. Merge JSON files
|
||||
print("3. Merging JSON Files")
|
||||
print("------------------------------")
|
||||
success = merge_json(['test1.json', 'test2.json'], 'merged.json')
|
||||
print(f"Files merged: {success}")
|
||||
if success:
|
||||
print("Merged contents:")
|
||||
print(json.dumps(read_json('merged.json'), indent=2))
|
||||
print()
|
||||
|
||||
# 4. Validate JSON
|
||||
print("4. Validating JSON")
|
||||
print("------------------------------")
|
||||
schema = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'id': {'type': 'integer'},
|
||||
'name': {'type': 'string'},
|
||||
'scores': {
|
||||
'type': 'array',
|
||||
'items': {'type': 'number'}
|
||||
},
|
||||
'details': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'age': {'type': 'integer'},
|
||||
'city': {'type': 'string'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'required': ['id', 'name']
|
||||
}
|
||||
|
||||
is_valid, error = validate_json(data1, schema)
|
||||
print(f"Validation result: {is_valid}")
|
||||
if error:
|
||||
print(f"Validation error: {error}")
|
||||
print()
|
||||
|
||||
# 5. Analyze JSON
|
||||
print("5. Analyzing JSON")
|
||||
print("------------------------------")
|
||||
analysis = analyze_json(data1)
|
||||
print("Analysis results:")
|
||||
print(json.dumps(analysis, indent=2))
|
||||
print()
|
||||
|
||||
# 6. Transform JSON
|
||||
print("6. Transforming JSON")
|
||||
print("------------------------------")
|
||||
transformations = [
|
||||
{
|
||||
'operation': 'set',
|
||||
'path': 'details.status',
|
||||
'value': 'active'
|
||||
},
|
||||
{
|
||||
'operation': 'rename',
|
||||
'path': 'details.city',
|
||||
'value': 'details.location'
|
||||
}
|
||||
]
|
||||
|
||||
transformed = transform_json(data1, transformations)
|
||||
print("Transformed data:")
|
||||
print(json.dumps(transformed, indent=2))
|
||||
|
||||
print("\n==================================================")
|
||||
print("Demonstration Complete")
|
||||
print("==================================================")
|
||||
@@ -0,0 +1,354 @@
|
||||
"""Newspaper tools for scraping and parsing news articles.
|
||||
|
||||
Usage:
|
||||
from praisonaiagents.tools import newspaper_tools
|
||||
article = newspaper_tools.get_article("https://example.com/article")
|
||||
sources = newspaper_tools.get_news_sources("technology")
|
||||
articles = newspaper_tools.get_articles_from_source("https://techcrunch.com")
|
||||
|
||||
or
|
||||
from praisonaiagents.tools import get_article, get_news_sources
|
||||
article = get_article("https://example.com/article")
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Dict, Union, Optional, Any
|
||||
from importlib import util
|
||||
import json
|
||||
from urllib.parse import urlparse
|
||||
|
||||
# Predefined list of popular news sources
|
||||
POPULAR_NEWS_SOURCES = {
|
||||
'technology': [
|
||||
'https://techcrunch.com',
|
||||
'https://www.theverge.com',
|
||||
'https://www.wired.com',
|
||||
'https://www.engadget.com',
|
||||
'https://arstechnica.com'
|
||||
],
|
||||
'business': [
|
||||
'https://www.bloomberg.com',
|
||||
'https://www.reuters.com',
|
||||
'https://www.wsj.com',
|
||||
'https://www.ft.com',
|
||||
'https://www.cnbc.com'
|
||||
],
|
||||
'general': [
|
||||
'https://www.nytimes.com',
|
||||
'https://www.theguardian.com',
|
||||
'https://www.washingtonpost.com',
|
||||
'https://www.bbc.com',
|
||||
'https://www.cnn.com'
|
||||
],
|
||||
'sports': [
|
||||
'https://www.espn.com',
|
||||
'https://sports.yahoo.com',
|
||||
'https://www.cbssports.com',
|
||||
'https://www.skysports.com',
|
||||
'https://www.bleacherreport.com'
|
||||
],
|
||||
'entertainment': [
|
||||
'https://variety.com',
|
||||
'https://www.hollywoodreporter.com',
|
||||
'https://www.ew.com',
|
||||
'https://www.deadline.com',
|
||||
'https://www.imdb.com/news'
|
||||
],
|
||||
'science': [
|
||||
'https://www.scientificamerican.com',
|
||||
'https://www.sciencedaily.com',
|
||||
'https://www.newscientist.com',
|
||||
'https://www.sciencemag.org',
|
||||
'https://www.nature.com/news'
|
||||
]
|
||||
}
|
||||
|
||||
class NewspaperTools:
|
||||
"""Tools for scraping and parsing news articles."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize NewspaperTools and check for newspaper package."""
|
||||
self._check_newspaper()
|
||||
|
||||
def _check_newspaper(self):
|
||||
"""Check if newspaper package is installed."""
|
||||
if util.find_spec("newspaper") is None:
|
||||
raise ImportError("newspaper3k package is not available. Please install it using: pip install newspaper3k")
|
||||
global newspaper
|
||||
import newspaper
|
||||
|
||||
def get_article(
|
||||
self,
|
||||
url: str,
|
||||
language: str = 'en'
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Extract and parse a news article from a URL.
|
||||
|
||||
Args:
|
||||
url: URL of the article
|
||||
language: Language code (e.g., 'en' for English)
|
||||
|
||||
Returns:
|
||||
Dict: Article information including title, text, authors, etc.
|
||||
"""
|
||||
try:
|
||||
from newspaper import Article, Config
|
||||
|
||||
# Configure article download
|
||||
config = Config()
|
||||
config.browser_user_agent = 'Mozilla/5.0'
|
||||
config.language = language
|
||||
|
||||
# Download and parse article
|
||||
article = Article(url, config=config)
|
||||
article.download()
|
||||
article.parse()
|
||||
|
||||
# Try to extract additional information
|
||||
try:
|
||||
article.nlp()
|
||||
except Exception as e:
|
||||
logging.warning(f"NLP processing failed: {str(e)}")
|
||||
|
||||
# Build response
|
||||
response = {
|
||||
"url": url,
|
||||
"title": article.title,
|
||||
"text": article.text,
|
||||
"authors": article.authors,
|
||||
"publish_date": article.publish_date.isoformat() if article.publish_date else None,
|
||||
"top_image": article.top_image,
|
||||
"images": list(article.images),
|
||||
"movies": list(article.movies),
|
||||
"source_domain": urlparse(url).netloc,
|
||||
}
|
||||
|
||||
# Add NLP results if available
|
||||
if hasattr(article, 'keywords') and article.keywords:
|
||||
response["keywords"] = article.keywords
|
||||
if hasattr(article, 'summary') and article.summary:
|
||||
response["summary"] = article.summary
|
||||
|
||||
return response
|
||||
except Exception as e:
|
||||
error_msg = f"Error extracting article from {url}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def get_news_sources(
|
||||
self,
|
||||
category: Optional[str] = None,
|
||||
language: str = 'en',
|
||||
country: Optional[str] = None
|
||||
) -> Union[List[Dict[str, str]], Dict[str, str]]:
|
||||
"""
|
||||
Get a list of news sources, optionally filtered by category.
|
||||
|
||||
Args:
|
||||
category: Category to filter by (e.g., 'technology', 'sports')
|
||||
language: Language code
|
||||
country: Country code
|
||||
|
||||
Returns:
|
||||
List[Dict] or Dict: List of news sources or error dict
|
||||
"""
|
||||
try:
|
||||
sources = []
|
||||
|
||||
# Get sources for the specified category or all categories
|
||||
if category:
|
||||
category = category.lower()
|
||||
if category in POPULAR_NEWS_SOURCES:
|
||||
urls = POPULAR_NEWS_SOURCES[category]
|
||||
else:
|
||||
urls = []
|
||||
for cat_urls in POPULAR_NEWS_SOURCES.values():
|
||||
urls.extend(cat_urls)
|
||||
else:
|
||||
urls = []
|
||||
for cat_urls in POPULAR_NEWS_SOURCES.values():
|
||||
urls.extend(cat_urls)
|
||||
|
||||
# Create source objects
|
||||
for url in urls:
|
||||
domain = urlparse(url).netloc
|
||||
source = {
|
||||
"url": url,
|
||||
"domain": domain,
|
||||
"name": domain.replace("www.", "").split(".")[0].title(),
|
||||
"category": category if category else "general"
|
||||
}
|
||||
sources.append(source)
|
||||
|
||||
return sources
|
||||
except Exception as e:
|
||||
error_msg = f"Error getting news sources: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def get_articles_from_source(
|
||||
self,
|
||||
source_url: str,
|
||||
limit: int = 10,
|
||||
language: str = 'en'
|
||||
) -> Union[List[Dict[str, Any]], Dict[str, str]]:
|
||||
"""
|
||||
Get recent articles from a news source.
|
||||
|
||||
Args:
|
||||
source_url: URL of the news source
|
||||
limit: Maximum number of articles to return
|
||||
language: Language code
|
||||
|
||||
Returns:
|
||||
List[Dict] or Dict: List of articles or error dict
|
||||
"""
|
||||
try:
|
||||
from newspaper import Source, Config
|
||||
|
||||
# Configure source scraping
|
||||
config = Config()
|
||||
config.browser_user_agent = 'Mozilla/5.0'
|
||||
config.language = language
|
||||
config.fetch_images = False # Speed up processing
|
||||
|
||||
# Build news source
|
||||
source = Source(source_url, config=config)
|
||||
source.build()
|
||||
|
||||
# Get articles
|
||||
articles = []
|
||||
for article_url in source.article_urls()[:limit]:
|
||||
try:
|
||||
article = self.get_article(article_url, language)
|
||||
if "error" not in article:
|
||||
articles.append(article)
|
||||
except Exception as e:
|
||||
logging.warning(f"Error processing article {article_url}: {str(e)}")
|
||||
continue
|
||||
|
||||
if len(articles) >= limit:
|
||||
break
|
||||
|
||||
return articles
|
||||
except Exception as e:
|
||||
error_msg = f"Error getting articles from {source_url}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def get_trending_topics(
|
||||
self,
|
||||
sources: Optional[List[str]] = None,
|
||||
limit: int = 10,
|
||||
language: str = 'en'
|
||||
) -> Union[List[str], Dict[str, str]]:
|
||||
"""
|
||||
Get trending topics across news sources.
|
||||
|
||||
Args:
|
||||
sources: List of source URLs to analyze
|
||||
limit: Maximum number of trending topics to return
|
||||
language: Language code
|
||||
|
||||
Returns:
|
||||
List[str] or Dict: List of trending topics or error dict
|
||||
"""
|
||||
try:
|
||||
from collections import Counter
|
||||
|
||||
# Use default sources if none provided
|
||||
if not sources:
|
||||
sources_data = self.get_news_sources(language=language)
|
||||
if isinstance(sources_data, dict) and "error" in sources_data:
|
||||
return sources_data
|
||||
sources = [s["url"] for s in sources_data[:5]] # Use top 5 sources
|
||||
|
||||
# Collect keywords from articles
|
||||
all_keywords = []
|
||||
for source_url in sources:
|
||||
try:
|
||||
articles = self.get_articles_from_source(source_url, limit=5, language=language)
|
||||
if isinstance(articles, list):
|
||||
for article in articles:
|
||||
if "keywords" in article:
|
||||
all_keywords.extend(article["keywords"])
|
||||
except Exception as e:
|
||||
logging.warning(f"Error processing source {source_url}: {str(e)}")
|
||||
continue
|
||||
|
||||
# Get most common keywords
|
||||
trending = Counter(all_keywords).most_common(limit)
|
||||
return [topic for topic, count in trending]
|
||||
except Exception as e:
|
||||
error_msg = f"Error getting trending topics: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
# Create instance for direct function access
|
||||
_newspaper_tools = NewspaperTools()
|
||||
get_article = _newspaper_tools.get_article
|
||||
get_news_sources = _newspaper_tools.get_news_sources
|
||||
get_articles_from_source = _newspaper_tools.get_articles_from_source
|
||||
get_trending_topics = _newspaper_tools.get_trending_topics
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
print("\n==================================================")
|
||||
print("NewspaperTools Demonstration")
|
||||
print("==================================================\n")
|
||||
|
||||
# 1. Get news sources
|
||||
print("1. Getting News Sources")
|
||||
print("------------------------------")
|
||||
tech_sources = get_news_sources("technology")
|
||||
print("Technology news sources:")
|
||||
if isinstance(tech_sources, list):
|
||||
print(json.dumps(tech_sources[:3], indent=2)) # Show first 3 sources
|
||||
else:
|
||||
print(tech_sources) # Show error
|
||||
print()
|
||||
|
||||
if isinstance(tech_sources, list) and tech_sources:
|
||||
source_url = tech_sources[0]["url"]
|
||||
|
||||
# 2. Get articles from a source
|
||||
print("2. Getting Articles from Source")
|
||||
print("------------------------------")
|
||||
articles = get_articles_from_source(source_url, limit=2)
|
||||
print(f"Articles from {source_url}:")
|
||||
if isinstance(articles, list):
|
||||
for article in articles:
|
||||
print(f"- {article['title']}")
|
||||
if "summary" in article:
|
||||
print(f" Summary: {article['summary'][:200]}...")
|
||||
else:
|
||||
print(articles) # Show error
|
||||
print()
|
||||
|
||||
# 3. Get a single article
|
||||
print("3. Getting Single Article")
|
||||
print("------------------------------")
|
||||
if isinstance(articles, list) and articles:
|
||||
article_url = articles[0]["url"]
|
||||
article = get_article(article_url)
|
||||
if "error" not in article:
|
||||
print(f"Article: {article['title']}")
|
||||
if "summary" in article:
|
||||
print(f"Summary: {article['summary'][:200]}...")
|
||||
print(f"Authors: {', '.join(article['authors'])}")
|
||||
print(f"Date: {article['publish_date']}")
|
||||
else:
|
||||
print(article) # Show error
|
||||
print()
|
||||
|
||||
# 4. Get trending topics
|
||||
print("4. Getting Trending Topics")
|
||||
print("------------------------------")
|
||||
topics = get_trending_topics([source_url], limit=5)
|
||||
print("Trending topics:")
|
||||
print(json.dumps(topics, indent=2))
|
||||
|
||||
print("\n==================================================")
|
||||
print("Demonstration Complete")
|
||||
print("==================================================")
|
||||
@@ -0,0 +1,326 @@
|
||||
"""Pandas tools for data manipulation and analysis.
|
||||
|
||||
Usage:
|
||||
from praisonaiagents.tools import pandas_tools
|
||||
df = pandas_tools.read_csv("data.csv")
|
||||
df = pandas_tools.filter_data(df, "column > 5")
|
||||
summary = pandas_tools.get_summary(df)
|
||||
|
||||
or
|
||||
from praisonaiagents.tools import read_csv, filter_data, get_summary
|
||||
df = read_csv("data.csv")
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Dict, Union, Optional, Any
|
||||
from importlib import util
|
||||
import json
|
||||
import os
|
||||
|
||||
# Import pandas for type hints, but don't use it until we check it's installed
|
||||
if util.find_spec("pandas") is not None:
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
else:
|
||||
# Create a placeholder for type hints
|
||||
class pd:
|
||||
DataFrame = None
|
||||
|
||||
def _convert_to_serializable(obj: Any) -> Any:
|
||||
"""Convert numpy/pandas types to JSON serializable Python types."""
|
||||
if isinstance(obj, (np.integer, np.floating)):
|
||||
return obj.item()
|
||||
elif isinstance(obj, np.ndarray):
|
||||
return obj.tolist()
|
||||
elif isinstance(obj, pd.Series):
|
||||
return obj.to_list()
|
||||
elif isinstance(obj, pd.DataFrame):
|
||||
return obj.to_dict(orient='records')
|
||||
return obj
|
||||
|
||||
class PandasTools:
|
||||
"""Tools for data manipulation and analysis using pandas."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize PandasTools and check for pandas installation."""
|
||||
self._check_pandas()
|
||||
|
||||
def _check_pandas(self):
|
||||
"""Check if pandas is installed."""
|
||||
if util.find_spec("pandas") is None:
|
||||
raise ImportError("pandas is not available. Please install it using: pip install pandas")
|
||||
global pd, np
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
|
||||
def read_csv(self, filepath: str, **kwargs) -> Union[pd.DataFrame, Dict[str, str]]:
|
||||
"""
|
||||
Read a CSV file into a pandas DataFrame.
|
||||
|
||||
Args:
|
||||
filepath: Path to the CSV file
|
||||
**kwargs: Additional arguments to pass to pd.read_csv()
|
||||
|
||||
Returns:
|
||||
pd.DataFrame or Dict: DataFrame if successful, error dict if failed
|
||||
"""
|
||||
try:
|
||||
return pd.read_csv(filepath, **kwargs)
|
||||
except Exception as e:
|
||||
error_msg = f"Error reading CSV file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def read_excel(self, filepath: str, **kwargs) -> Union[pd.DataFrame, Dict[str, str]]:
|
||||
"""
|
||||
Read an Excel file into a pandas DataFrame.
|
||||
|
||||
Args:
|
||||
filepath: Path to the Excel file
|
||||
**kwargs: Additional arguments to pass to pd.read_excel()
|
||||
|
||||
Returns:
|
||||
pd.DataFrame or Dict: DataFrame if successful, error dict if failed
|
||||
"""
|
||||
try:
|
||||
return pd.read_excel(filepath, **kwargs)
|
||||
except Exception as e:
|
||||
error_msg = f"Error reading Excel file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def write_csv(self, df: pd.DataFrame, filepath: str, **kwargs) -> bool:
|
||||
"""
|
||||
Write DataFrame to a CSV file.
|
||||
|
||||
Args:
|
||||
df: DataFrame to write
|
||||
filepath: Output file path
|
||||
**kwargs: Additional arguments to pass to df.to_csv()
|
||||
|
||||
Returns:
|
||||
bool: True if successful, False otherwise
|
||||
"""
|
||||
try:
|
||||
os.makedirs(os.path.dirname(filepath), exist_ok=True)
|
||||
df.to_csv(filepath, **kwargs)
|
||||
return True
|
||||
except Exception as e:
|
||||
error_msg = f"Error writing CSV file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
def write_excel(self, df: pd.DataFrame, filepath: str, **kwargs) -> bool:
|
||||
"""
|
||||
Write DataFrame to an Excel file.
|
||||
|
||||
Args:
|
||||
df: DataFrame to write
|
||||
filepath: Output file path
|
||||
**kwargs: Additional arguments to pass to df.to_excel()
|
||||
|
||||
Returns:
|
||||
bool: True if successful, False otherwise
|
||||
"""
|
||||
try:
|
||||
os.makedirs(os.path.dirname(filepath), exist_ok=True)
|
||||
df.to_excel(filepath, **kwargs)
|
||||
return True
|
||||
except Exception as e:
|
||||
error_msg = f"Error writing Excel file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
def filter_data(self, df: pd.DataFrame, query: str) -> Union[pd.DataFrame, Dict[str, str]]:
|
||||
"""
|
||||
Filter DataFrame using a query string.
|
||||
|
||||
Args:
|
||||
df: Input DataFrame
|
||||
query: Query string (e.g., "column > 5 and other_column == 'value'")
|
||||
|
||||
Returns:
|
||||
pd.DataFrame or Dict: Filtered DataFrame if successful, error dict if failed
|
||||
"""
|
||||
try:
|
||||
return df.query(query)
|
||||
except Exception as e:
|
||||
error_msg = f"Error filtering data with query '{query}': {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def get_summary(self, df: pd.DataFrame) -> Dict[str, Any]:
|
||||
"""
|
||||
Get a summary of the DataFrame including basic statistics and info.
|
||||
|
||||
Args:
|
||||
df: Input DataFrame
|
||||
|
||||
Returns:
|
||||
Dict: Summary statistics and information
|
||||
"""
|
||||
try:
|
||||
numeric_summary = df.describe().to_dict()
|
||||
# Convert numpy types to native Python types
|
||||
for col in numeric_summary:
|
||||
numeric_summary[col] = {k: _convert_to_serializable(v)
|
||||
for k, v in numeric_summary[col].items()}
|
||||
|
||||
summary = {
|
||||
"shape": list(df.shape),
|
||||
"columns": list(df.columns),
|
||||
"dtypes": df.dtypes.astype(str).to_dict(),
|
||||
"null_counts": df.isnull().sum().to_dict(),
|
||||
"numeric_summary": numeric_summary,
|
||||
"memory_usage": int(df.memory_usage(deep=True).sum()),
|
||||
}
|
||||
return summary
|
||||
except Exception as e:
|
||||
error_msg = f"Error getting data summary: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def group_by(
|
||||
self,
|
||||
df: pd.DataFrame,
|
||||
columns: Union[str, List[str]],
|
||||
agg_dict: Dict[str, Union[str, List[str]]]
|
||||
) -> Union[pd.DataFrame, Dict[str, str]]:
|
||||
"""
|
||||
Group DataFrame by columns and apply aggregation functions.
|
||||
|
||||
Args:
|
||||
df: Input DataFrame
|
||||
columns: Column(s) to group by
|
||||
agg_dict: Dictionary of column:function pairs for aggregation
|
||||
|
||||
Returns:
|
||||
pd.DataFrame or Dict: Grouped DataFrame if successful, error dict if failed
|
||||
"""
|
||||
try:
|
||||
return df.groupby(columns).agg(agg_dict).reset_index()
|
||||
except Exception as e:
|
||||
error_msg = f"Error grouping data: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def pivot_table(
|
||||
self,
|
||||
df: pd.DataFrame,
|
||||
index: Union[str, List[str]],
|
||||
columns: Optional[Union[str, List[str]]] = None,
|
||||
values: Optional[Union[str, List[str]]] = None,
|
||||
aggfunc: str = "mean"
|
||||
) -> Union[pd.DataFrame, Dict[str, str]]:
|
||||
"""
|
||||
Create a pivot table from DataFrame.
|
||||
|
||||
Args:
|
||||
df: Input DataFrame
|
||||
index: Column(s) to use as index
|
||||
columns: Column(s) to use as columns
|
||||
values: Column(s) to aggregate
|
||||
aggfunc: Aggregation function to use
|
||||
|
||||
Returns:
|
||||
pd.DataFrame or Dict: Pivot table if successful, error dict if failed
|
||||
"""
|
||||
try:
|
||||
return pd.pivot_table(
|
||||
df,
|
||||
index=index,
|
||||
columns=columns,
|
||||
values=values,
|
||||
aggfunc=aggfunc
|
||||
).reset_index()
|
||||
except Exception as e:
|
||||
error_msg = f"Error creating pivot table: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
# Create instance for direct function access
|
||||
_pandas_tools = PandasTools()
|
||||
read_csv = _pandas_tools.read_csv
|
||||
read_excel = _pandas_tools.read_excel
|
||||
write_csv = _pandas_tools.write_csv
|
||||
write_excel = _pandas_tools.write_excel
|
||||
filter_data = _pandas_tools.filter_data
|
||||
get_summary = _pandas_tools.get_summary
|
||||
group_by = _pandas_tools.group_by
|
||||
pivot_table = _pandas_tools.pivot_table
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
print("\n==================================================")
|
||||
print("PandasTools Demonstration")
|
||||
print("==================================================\n")
|
||||
|
||||
# Create a test directory
|
||||
test_dir = os.path.join(os.getcwd(), "test_files")
|
||||
os.makedirs(test_dir, exist_ok=True)
|
||||
|
||||
# Create a sample DataFrame
|
||||
df = pd.DataFrame({
|
||||
'name': ['John', 'Jane', 'Bob', 'Alice', 'Charlie'],
|
||||
'age': [25, 30, 35, 28, 32],
|
||||
'city': ['New York', 'London', 'Paris', 'Tokyo', 'London'],
|
||||
'salary': [50000, 60000, 75000, 65000, 55000]
|
||||
})
|
||||
|
||||
# 1. Write to CSV
|
||||
print("1. Writing to CSV")
|
||||
print("------------------------------")
|
||||
csv_file = os.path.join(test_dir, "sample.csv")
|
||||
success = write_csv(df, csv_file, index=False)
|
||||
print(f"Write successful: {success}\n")
|
||||
|
||||
# 2. Read from CSV
|
||||
print("2. Reading from CSV")
|
||||
print("------------------------------")
|
||||
df_read = read_csv(csv_file)
|
||||
print("First few rows:")
|
||||
print(df_read.head())
|
||||
print()
|
||||
|
||||
# 3. Filter Data
|
||||
print("3. Filtering Data")
|
||||
print("------------------------------")
|
||||
filtered_df = filter_data(df, "age > 30 and salary > 60000")
|
||||
print("People over 30 with salary > 60000:")
|
||||
print(filtered_df)
|
||||
print()
|
||||
|
||||
# 4. Get Summary
|
||||
print("4. Data Summary")
|
||||
print("------------------------------")
|
||||
summary = get_summary(df)
|
||||
print(json.dumps(summary, indent=2))
|
||||
print()
|
||||
|
||||
# 5. Group By
|
||||
print("5. Group By")
|
||||
print("------------------------------")
|
||||
grouped = group_by(df, "city", {"salary": ["mean", "count"], "age": "mean"})
|
||||
print("Statistics by city:")
|
||||
print(grouped)
|
||||
print()
|
||||
|
||||
# 6. Pivot Table
|
||||
print("6. Pivot Table")
|
||||
print("------------------------------")
|
||||
pivoted = pivot_table(df, index="city", values=["salary", "age"])
|
||||
print("Pivot table by city:")
|
||||
print(pivoted)
|
||||
print()
|
||||
|
||||
# Clean up test directory
|
||||
try:
|
||||
import shutil
|
||||
shutil.rmtree(test_dir)
|
||||
print("Test directory cleaned up successfully")
|
||||
except Exception as e:
|
||||
print(f"Error cleaning up test directory: {str(e)}")
|
||||
|
||||
print("\n==================================================")
|
||||
print("Demonstration Complete")
|
||||
print("==================================================")
|
||||
@@ -0,0 +1,423 @@
|
||||
"""Tools for Python code execution and analysis.
|
||||
|
||||
Usage:
|
||||
from praisonaiagents.tools import python_tools
|
||||
result = python_tools.execute_code("print('Hello, World!')")
|
||||
|
||||
or
|
||||
from praisonaiagents.tools import execute_code, analyze_code, format_code
|
||||
result = execute_code("print('Hello, World!')")
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Dict, List, Optional, Any
|
||||
from importlib import util
|
||||
import io
|
||||
from contextlib import redirect_stdout, redirect_stderr
|
||||
import traceback
|
||||
|
||||
class PythonTools:
|
||||
"""Tools for Python code execution and analysis."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize PythonTools."""
|
||||
self._check_dependencies()
|
||||
|
||||
def _check_dependencies(self):
|
||||
"""Check if required packages are installed."""
|
||||
missing = []
|
||||
for package in ['black', 'pylint', 'autopep8']:
|
||||
if util.find_spec(package) is None:
|
||||
missing.append(package)
|
||||
|
||||
if missing:
|
||||
raise ImportError(
|
||||
f"Required packages not available. Please install: {', '.join(missing)}\n"
|
||||
f"Run: pip install {' '.join(missing)}"
|
||||
)
|
||||
|
||||
def execute_code(
|
||||
self,
|
||||
code: str,
|
||||
globals_dict: Optional[Dict[str, Any]] = None,
|
||||
locals_dict: Optional[Dict[str, Any]] = None,
|
||||
timeout: int = 30,
|
||||
max_output_size: int = 10000
|
||||
) -> Dict[str, Any]:
|
||||
"""Execute Python code safely."""
|
||||
try:
|
||||
# Set up execution environment
|
||||
if globals_dict is None:
|
||||
globals_dict = {'__builtins__': __builtins__}
|
||||
if locals_dict is None:
|
||||
locals_dict = {}
|
||||
|
||||
# Capture output
|
||||
stdout_buffer = io.StringIO()
|
||||
stderr_buffer = io.StringIO()
|
||||
|
||||
try:
|
||||
# Compile code
|
||||
compiled_code = compile(code, '<string>', 'exec')
|
||||
|
||||
# Execute with output capture
|
||||
with redirect_stdout(stdout_buffer), redirect_stderr(stderr_buffer):
|
||||
exec(compiled_code, globals_dict, locals_dict)
|
||||
|
||||
# Get last expression value if any
|
||||
import ast
|
||||
tree = ast.parse(code)
|
||||
if tree.body and isinstance(tree.body[-1], ast.Expr):
|
||||
result = eval(
|
||||
compile(ast.Expression(tree.body[-1].value), '<string>', 'eval'),
|
||||
globals_dict,
|
||||
locals_dict
|
||||
)
|
||||
else:
|
||||
result = None
|
||||
|
||||
# Get output
|
||||
stdout = stdout_buffer.getvalue()
|
||||
stderr = stderr_buffer.getvalue()
|
||||
|
||||
# Truncate output if too large
|
||||
if len(stdout) > max_output_size:
|
||||
stdout = stdout[:max_output_size] + "...[truncated]"
|
||||
if len(stderr) > max_output_size:
|
||||
stderr = stderr[:max_output_size] + "...[truncated]"
|
||||
|
||||
return {
|
||||
'result': result,
|
||||
'stdout': stdout,
|
||||
'stderr': stderr,
|
||||
'success': True
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error executing code: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {
|
||||
'result': None,
|
||||
'stdout': stdout_buffer.getvalue(),
|
||||
'stderr': error_msg,
|
||||
'success': False
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error executing code: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {
|
||||
'result': None,
|
||||
'stdout': '',
|
||||
'stderr': error_msg,
|
||||
'success': False
|
||||
}
|
||||
|
||||
def analyze_code(
|
||||
self,
|
||||
code: str
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
"""Analyze Python code structure and quality.
|
||||
|
||||
Args:
|
||||
code: Python code to analyze
|
||||
|
||||
Returns:
|
||||
Dictionary with analysis results
|
||||
"""
|
||||
try:
|
||||
# Import ast only when needed
|
||||
import ast
|
||||
|
||||
# Parse code
|
||||
tree = ast.parse(code)
|
||||
|
||||
# Analyze structure
|
||||
analysis = {
|
||||
'imports': [],
|
||||
'functions': [],
|
||||
'classes': [],
|
||||
'variables': [],
|
||||
'complexity': {
|
||||
'lines': len(code.splitlines()),
|
||||
'functions': 0,
|
||||
'classes': 0,
|
||||
'branches': 0
|
||||
}
|
||||
}
|
||||
|
||||
# Analyze nodes
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.Import):
|
||||
for name in node.names:
|
||||
analysis['imports'].append(name.name)
|
||||
elif isinstance(node, ast.ImportFrom):
|
||||
module = node.module or ''
|
||||
for name in node.names:
|
||||
analysis['imports'].append(f"{module}.{name.name}")
|
||||
elif isinstance(node, ast.FunctionDef):
|
||||
analysis['functions'].append({
|
||||
'name': node.name,
|
||||
'args': [
|
||||
arg.arg for arg in node.args.args
|
||||
],
|
||||
'decorators': [
|
||||
ast.unparse(d) for d in node.decorator_list
|
||||
]
|
||||
})
|
||||
analysis['complexity']['functions'] += 1
|
||||
elif isinstance(node, ast.ClassDef):
|
||||
analysis['classes'].append({
|
||||
'name': node.name,
|
||||
'bases': [
|
||||
ast.unparse(base) for base in node.bases
|
||||
],
|
||||
'decorators': [
|
||||
ast.unparse(d) for d in node.decorator_list
|
||||
]
|
||||
})
|
||||
analysis['complexity']['classes'] += 1
|
||||
elif isinstance(node, ast.Assign):
|
||||
for target in node.targets:
|
||||
if isinstance(target, ast.Name):
|
||||
analysis['variables'].append(target.id)
|
||||
elif isinstance(node, (ast.If, ast.While, ast.For)):
|
||||
analysis['complexity']['branches'] += 1
|
||||
|
||||
return analysis
|
||||
except Exception as e:
|
||||
error_msg = f"Error analyzing code: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
|
||||
def format_code(
|
||||
self,
|
||||
code: str,
|
||||
style: str = 'black',
|
||||
line_length: int = 88
|
||||
) -> Optional[str]:
|
||||
"""Format Python code according to style guide.
|
||||
|
||||
Args:
|
||||
code: Python code to format
|
||||
style: Formatting style ('black' or 'pep8')
|
||||
line_length: Maximum line length
|
||||
|
||||
Returns:
|
||||
Formatted code
|
||||
"""
|
||||
try:
|
||||
if util.find_spec(style) is None:
|
||||
error_msg = f"{style} package is not available. Please install it using: pip install {style}"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
|
||||
if style == 'black':
|
||||
import black
|
||||
return black.format_str(
|
||||
code,
|
||||
mode=black.FileMode(
|
||||
line_length=line_length
|
||||
)
|
||||
)
|
||||
else: # pep8
|
||||
import autopep8
|
||||
return autopep8.fix_code(
|
||||
code,
|
||||
options={
|
||||
'max_line_length': line_length
|
||||
}
|
||||
)
|
||||
except Exception as e:
|
||||
error_msg = f"Error formatting code: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
|
||||
def lint_code(
|
||||
self,
|
||||
code: str
|
||||
) -> Optional[Dict[str, List[Dict[str, Any]]]]:
|
||||
"""Lint Python code for potential issues.
|
||||
|
||||
Args:
|
||||
code: Python code to lint
|
||||
|
||||
Returns:
|
||||
Dictionary with linting results
|
||||
"""
|
||||
try:
|
||||
if util.find_spec('pylint') is None:
|
||||
error_msg = "pylint package is not available. Please install it using: pip install pylint"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
|
||||
# Import pylint only when needed
|
||||
from pylint.reporters import JSONReporter
|
||||
from pylint.lint.run import Run
|
||||
|
||||
# Create temporary file for pylint
|
||||
import tempfile
|
||||
with tempfile.NamedTemporaryFile(
|
||||
mode='w',
|
||||
suffix='.py',
|
||||
delete=False
|
||||
) as f:
|
||||
f.write(code)
|
||||
temp_path = f.name
|
||||
|
||||
# Run pylint
|
||||
reporter = JSONReporter()
|
||||
Run(
|
||||
[temp_path],
|
||||
reporter=reporter,
|
||||
exit=False
|
||||
)
|
||||
|
||||
# Process results
|
||||
results = {
|
||||
'errors': [],
|
||||
'warnings': [],
|
||||
'conventions': []
|
||||
}
|
||||
|
||||
for msg in reporter.messages:
|
||||
item = {
|
||||
'type': msg.category,
|
||||
'module': msg.module,
|
||||
'obj': msg.obj,
|
||||
'line': msg.line,
|
||||
'column': msg.column,
|
||||
'path': msg.path,
|
||||
'symbol': msg.symbol,
|
||||
'message': msg.msg,
|
||||
'message-id': msg.msg_id
|
||||
}
|
||||
|
||||
if msg.category in ['error', 'fatal']:
|
||||
results['errors'].append(item)
|
||||
elif msg.category == 'warning':
|
||||
results['warnings'].append(item)
|
||||
else:
|
||||
results['conventions'].append(item)
|
||||
|
||||
# Clean up
|
||||
import os
|
||||
os.unlink(temp_path)
|
||||
|
||||
return results
|
||||
except Exception as e:
|
||||
error_msg = f"Error linting code: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {
|
||||
'errors': [],
|
||||
'warnings': [],
|
||||
'conventions': []
|
||||
}
|
||||
|
||||
def disassemble_code(
|
||||
self,
|
||||
code: str
|
||||
) -> Optional[str]:
|
||||
"""Disassemble Python code to bytecode.
|
||||
|
||||
Args:
|
||||
code: Python code to disassemble
|
||||
|
||||
Returns:
|
||||
Disassembled bytecode as string
|
||||
"""
|
||||
try:
|
||||
# Import dis only when needed
|
||||
import dis
|
||||
|
||||
# Compile code
|
||||
compiled_code = compile(code, '<string>', 'exec')
|
||||
|
||||
# Capture disassembly
|
||||
output = io.StringIO()
|
||||
with redirect_stdout(output):
|
||||
dis.dis(compiled_code)
|
||||
|
||||
return output.getvalue()
|
||||
except Exception as e:
|
||||
error_msg = f"Error disassembling code: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
|
||||
# Create instance for direct function access
|
||||
_python_tools = PythonTools()
|
||||
execute_code = _python_tools.execute_code
|
||||
analyze_code = _python_tools.analyze_code
|
||||
format_code = _python_tools.format_code
|
||||
lint_code = _python_tools.lint_code
|
||||
disassemble_code = _python_tools.disassemble_code
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("\n==================================================")
|
||||
print("PythonTools Demonstration")
|
||||
print("==================================================\n")
|
||||
|
||||
print("1. Execute Python Code")
|
||||
print("------------------------------")
|
||||
code = """
|
||||
def greet(name):
|
||||
return f"Hello, {name}!"
|
||||
|
||||
result = greet("World")
|
||||
print(result)
|
||||
"""
|
||||
print("Code to execute:")
|
||||
print(code)
|
||||
print("\nOutput:")
|
||||
result = execute_code(code)
|
||||
print(result["stdout"])
|
||||
print()
|
||||
|
||||
print("2. Format Python Code")
|
||||
print("------------------------------")
|
||||
code = """
|
||||
def messy_function(x,y, z):
|
||||
if x>0:
|
||||
return y+z
|
||||
else:
|
||||
return y-z
|
||||
"""
|
||||
print("Before formatting:")
|
||||
print(code)
|
||||
print("\nAfter formatting:")
|
||||
result = format_code(code)
|
||||
print(result)
|
||||
print()
|
||||
|
||||
print("3. Lint Python Code")
|
||||
print("------------------------------")
|
||||
code = """
|
||||
def bad_function():
|
||||
unused_var = 42
|
||||
return 'result'
|
||||
"""
|
||||
print("Code to lint:")
|
||||
print(code)
|
||||
print("\nLinting results:")
|
||||
result = lint_code(code)
|
||||
print(result)
|
||||
print()
|
||||
|
||||
print("4. Execute Code with Variables")
|
||||
print("------------------------------")
|
||||
code = """
|
||||
x = 10
|
||||
y = 20
|
||||
result = x + y
|
||||
print(f"The sum of {x} and {y} is {result}")
|
||||
"""
|
||||
print("Code to execute:")
|
||||
print(code)
|
||||
print("\nOutput:")
|
||||
result = execute_code(code)
|
||||
print(result["stdout"])
|
||||
print()
|
||||
|
||||
print("==================================================")
|
||||
print("Demonstration Complete")
|
||||
print("==================================================")
|
||||
@@ -0,0 +1,278 @@
|
||||
"""Tools for executing shell commands safely.
|
||||
|
||||
This module provides a safe interface for executing shell commands with:
|
||||
- Timeout control
|
||||
- Output capture
|
||||
- Error handling
|
||||
- Resource limits
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import shlex
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
from typing import Dict, List, Optional, Union
|
||||
|
||||
class ShellTools:
|
||||
"""Tools for executing shell commands safely."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize ShellTools."""
|
||||
self._check_dependencies()
|
||||
|
||||
def _check_dependencies(self):
|
||||
"""Check if required packages are installed."""
|
||||
try:
|
||||
import psutil
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"Required package not available. Please install: psutil\n"
|
||||
"Run: pip install psutil"
|
||||
)
|
||||
|
||||
def execute_command(
|
||||
self,
|
||||
command: str,
|
||||
cwd: Optional[str] = None,
|
||||
timeout: int = 30,
|
||||
shell: bool = False,
|
||||
env: Optional[Dict[str, str]] = None,
|
||||
max_output_size: int = 10000
|
||||
) -> Dict[str, Union[str, int, bool]]:
|
||||
"""Execute a shell command safely.
|
||||
|
||||
Args:
|
||||
command: Command to execute
|
||||
cwd: Working directory
|
||||
timeout: Maximum execution time in seconds
|
||||
shell: Whether to run command in shell
|
||||
env: Environment variables
|
||||
max_output_size: Maximum output size in bytes
|
||||
|
||||
Returns:
|
||||
Dictionary with execution results
|
||||
"""
|
||||
try:
|
||||
# Split command if not using shell
|
||||
if not shell:
|
||||
command = shlex.split(command)
|
||||
|
||||
# Set up process environment
|
||||
process_env = os.environ.copy()
|
||||
if env:
|
||||
process_env.update(env)
|
||||
|
||||
# Start process
|
||||
start_time = time.time()
|
||||
process = subprocess.Popen(
|
||||
command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
cwd=cwd,
|
||||
shell=shell,
|
||||
env=process_env,
|
||||
text=True
|
||||
)
|
||||
|
||||
try:
|
||||
# Wait for process with timeout
|
||||
stdout, stderr = process.communicate(timeout=timeout)
|
||||
|
||||
# Truncate output if too large
|
||||
if len(stdout) > max_output_size:
|
||||
stdout = stdout[:max_output_size] + "...[truncated]"
|
||||
if len(stderr) > max_output_size:
|
||||
stderr = stderr[:max_output_size] + "...[truncated]"
|
||||
|
||||
return {
|
||||
'stdout': stdout,
|
||||
'stderr': stderr,
|
||||
'exit_code': process.returncode,
|
||||
'success': process.returncode == 0,
|
||||
'execution_time': time.time() - start_time
|
||||
}
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
# Kill process on timeout
|
||||
parent = psutil.Process(process.pid)
|
||||
children = parent.children(recursive=True)
|
||||
for child in children:
|
||||
child.kill()
|
||||
parent.kill()
|
||||
|
||||
return {
|
||||
'stdout': '',
|
||||
'stderr': f'Command timed out after {timeout} seconds',
|
||||
'exit_code': -1,
|
||||
'success': False,
|
||||
'execution_time': timeout
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error executing command: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {
|
||||
'stdout': '',
|
||||
'stderr': error_msg,
|
||||
'exit_code': -1,
|
||||
'success': False,
|
||||
'execution_time': 0
|
||||
}
|
||||
|
||||
def list_processes(self) -> List[Dict[str, Union[int, str, float]]]:
|
||||
"""List running processes with their details.
|
||||
|
||||
Returns:
|
||||
List of process information dictionaries
|
||||
"""
|
||||
try:
|
||||
processes = []
|
||||
for proc in psutil.process_iter(['pid', 'name', 'username', 'memory_percent', 'cpu_percent']):
|
||||
try:
|
||||
pinfo = proc.info
|
||||
processes.append({
|
||||
'pid': pinfo['pid'],
|
||||
'name': pinfo['name'],
|
||||
'username': pinfo['username'],
|
||||
'memory_percent': round(pinfo['memory_percent'], 2),
|
||||
'cpu_percent': round(pinfo['cpu_percent'], 2)
|
||||
})
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
|
||||
pass
|
||||
return processes
|
||||
except Exception as e:
|
||||
error_msg = f"Error listing processes: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return []
|
||||
|
||||
def kill_process(
|
||||
self,
|
||||
pid: int,
|
||||
force: bool = False
|
||||
) -> Dict[str, Union[bool, str]]:
|
||||
"""Kill a process by its PID.
|
||||
|
||||
Args:
|
||||
pid: Process ID to kill
|
||||
force: Whether to force kill (-9)
|
||||
|
||||
Returns:
|
||||
Dictionary with operation results
|
||||
"""
|
||||
try:
|
||||
process = psutil.Process(pid)
|
||||
if force:
|
||||
process.kill() # SIGKILL
|
||||
else:
|
||||
process.terminate() # SIGTERM
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'message': f'Process {pid} killed successfully'
|
||||
}
|
||||
except psutil.NoSuchProcess:
|
||||
return {
|
||||
'success': False,
|
||||
'message': f'No process found with PID {pid}'
|
||||
}
|
||||
except psutil.AccessDenied:
|
||||
return {
|
||||
'success': False,
|
||||
'message': f'Access denied to kill process {pid}'
|
||||
}
|
||||
except Exception as e:
|
||||
error_msg = f"Error killing process: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {
|
||||
'success': False,
|
||||
'message': error_msg
|
||||
}
|
||||
|
||||
def get_system_info(self) -> Dict[str, Union[float, int, str, Dict]]:
|
||||
"""Get system information.
|
||||
|
||||
Returns:
|
||||
Dictionary with system information
|
||||
"""
|
||||
try:
|
||||
cpu_percent = psutil.cpu_percent(interval=1)
|
||||
memory = psutil.virtual_memory()
|
||||
disk = psutil.disk_usage('/')
|
||||
|
||||
return {
|
||||
'cpu': {
|
||||
'percent': cpu_percent,
|
||||
'cores': psutil.cpu_count(),
|
||||
'physical_cores': psutil.cpu_count(logical=False)
|
||||
},
|
||||
'memory': {
|
||||
'total': memory.total,
|
||||
'available': memory.available,
|
||||
'percent': memory.percent,
|
||||
'used': memory.used,
|
||||
'free': memory.free
|
||||
},
|
||||
'disk': {
|
||||
'total': disk.total,
|
||||
'used': disk.used,
|
||||
'free': disk.free,
|
||||
'percent': disk.percent
|
||||
},
|
||||
'boot_time': psutil.boot_time(),
|
||||
'platform': os.uname().sysname
|
||||
}
|
||||
except Exception as e:
|
||||
error_msg = f"Error getting system info: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {}
|
||||
|
||||
# Create instance for direct function access
|
||||
_shell_tools = ShellTools()
|
||||
execute_command = _shell_tools.execute_command
|
||||
list_processes = _shell_tools.list_processes
|
||||
kill_process = _shell_tools.kill_process
|
||||
get_system_info = _shell_tools.get_system_info
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
print("\n==================================================")
|
||||
print("ShellTools Demonstration")
|
||||
print("==================================================\n")
|
||||
|
||||
# 1. Execute command
|
||||
print("1. Command Execution")
|
||||
print("------------------------------")
|
||||
result = execute_command("ls -la")
|
||||
print(f"Success: {result['success']}")
|
||||
print(f"Output:\n{result['stdout']}")
|
||||
if result['stderr']:
|
||||
print(f"Errors:\n{result['stderr']}")
|
||||
print(f"Execution time: {result['execution_time']:.2f}s")
|
||||
print()
|
||||
|
||||
# 2. System Information
|
||||
print("2. System Information")
|
||||
print("------------------------------")
|
||||
info = get_system_info()
|
||||
print(f"CPU Usage: {info['cpu']['percent']}%")
|
||||
print(f"Memory Usage: {info['memory']['percent']}%")
|
||||
print(f"Disk Usage: {info['disk']['percent']}%")
|
||||
print(f"Platform: {info['platform']}")
|
||||
print()
|
||||
|
||||
# 3. Process List
|
||||
print("3. Process List (top 5 by CPU)")
|
||||
print("------------------------------")
|
||||
processes = sorted(
|
||||
list_processes(),
|
||||
key=lambda x: x['cpu_percent'],
|
||||
reverse=True
|
||||
)[:5]
|
||||
for proc in processes:
|
||||
print(f"PID: {proc['pid']}, Name: {proc['name']}, CPU: {proc['cpu_percent']}%")
|
||||
print()
|
||||
|
||||
print("\n==================================================")
|
||||
print("Demonstration Complete")
|
||||
print("==================================================")
|
||||
@@ -0,0 +1,431 @@
|
||||
"""Tools for web scraping and crawling.
|
||||
|
||||
Usage:
|
||||
from praisonaiagents.tools import spider_tools
|
||||
content = spider_tools.scrape_page("https://example.com")
|
||||
links = spider_tools.extract_links("https://example.com")
|
||||
|
||||
or
|
||||
from praisonaiagents.tools import scrape_page, extract_links
|
||||
content = scrape_page("https://example.com")
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Dict, Union, Optional, Any
|
||||
from importlib import util
|
||||
import json
|
||||
from urllib.parse import urljoin, urlparse
|
||||
import re
|
||||
import os
|
||||
import hashlib
|
||||
import time
|
||||
|
||||
class SpiderTools:
|
||||
"""Tools for web scraping and crawling."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize SpiderTools and check for required packages."""
|
||||
self._session = None
|
||||
|
||||
def _get_session(self):
|
||||
"""Get or create requests session with common headers."""
|
||||
if util.find_spec('requests') is None:
|
||||
error_msg = "requests package is not available. Please install it using: pip install requests"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
|
||||
if self._session is None:
|
||||
import requests
|
||||
self._session = requests.Session()
|
||||
self._session.headers.update({
|
||||
'User-Agent': 'Mozilla/5.0 (compatible; PraisonAI/1.0; +http://praisonai.com/bot)',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||||
'Accept-Language': 'en-US,en;q=0.5',
|
||||
'Accept-Encoding': 'gzip, deflate, br',
|
||||
'Connection': 'keep-alive',
|
||||
})
|
||||
return self._session
|
||||
|
||||
def scrape_page(
|
||||
self,
|
||||
url: str,
|
||||
selector: Optional[str] = None,
|
||||
extract_images: bool = False,
|
||||
extract_links: bool = False,
|
||||
timeout: int = 30,
|
||||
verify_ssl: bool = True
|
||||
) -> Union[Dict[str, Any], Dict[str, str]]:
|
||||
"""
|
||||
Scrape content from a webpage.
|
||||
|
||||
Args:
|
||||
url: URL to scrape
|
||||
selector: Optional CSS selector to extract specific content
|
||||
extract_images: Whether to extract image URLs
|
||||
extract_links: Whether to extract links
|
||||
timeout: Request timeout in seconds
|
||||
verify_ssl: Whether to verify SSL certificates
|
||||
|
||||
Returns:
|
||||
Dict: Scraped content or error dict
|
||||
"""
|
||||
try:
|
||||
session = self._get_session()
|
||||
if session is None:
|
||||
return {"error": "requests package not available"}
|
||||
|
||||
# Import BeautifulSoup only when needed
|
||||
if util.find_spec('bs4') is None:
|
||||
error_msg = "bs4 package is not available. Please install it using: pip install beautifulsoup4"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
# Make request
|
||||
response = session.get(
|
||||
url,
|
||||
timeout=timeout,
|
||||
verify=verify_ssl
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
# Parse HTML
|
||||
soup = BeautifulSoup(response.text, 'lxml')
|
||||
|
||||
# Remove unwanted elements
|
||||
for element in soup(['script', 'style']):
|
||||
element.decompose()
|
||||
|
||||
# Initialize result
|
||||
result = {
|
||||
'url': url,
|
||||
'status_code': response.status_code,
|
||||
'encoding': response.encoding,
|
||||
'headers': dict(response.headers),
|
||||
}
|
||||
|
||||
# Extract content based on selector
|
||||
if selector:
|
||||
elements = soup.select(selector)
|
||||
result['content'] = [elem.get_text(strip=True) for elem in elements]
|
||||
result['html'] = [str(elem) for elem in elements]
|
||||
else:
|
||||
result['title'] = soup.title.string if soup.title else None
|
||||
result['content'] = soup.get_text(separator=' ', strip=True)
|
||||
result['html'] = str(soup)
|
||||
|
||||
# Extract metadata
|
||||
meta_tags = {}
|
||||
for meta in soup.find_all('meta'):
|
||||
name = meta.get('name') or meta.get('property')
|
||||
if name:
|
||||
meta_tags[name] = meta.get('content')
|
||||
result['meta_tags'] = meta_tags
|
||||
|
||||
# Extract images if requested
|
||||
if extract_images:
|
||||
images = []
|
||||
for img in soup.find_all('img'):
|
||||
src = img.get('src')
|
||||
if src:
|
||||
images.append({
|
||||
'src': urljoin(url, src),
|
||||
'alt': img.get('alt', ''),
|
||||
'title': img.get('title', '')
|
||||
})
|
||||
result['images'] = images
|
||||
|
||||
# Extract links if requested
|
||||
if extract_links:
|
||||
links = []
|
||||
for link in soup.find_all('a'):
|
||||
href = link.get('href')
|
||||
if href:
|
||||
links.append({
|
||||
'url': urljoin(url, href),
|
||||
'text': link.get_text(strip=True),
|
||||
'title': link.get('title', '')
|
||||
})
|
||||
result['links'] = links
|
||||
|
||||
return result
|
||||
except Exception as e:
|
||||
error_msg = f"Error scraping {url}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def extract_links(
|
||||
self,
|
||||
url: str,
|
||||
same_domain: bool = True,
|
||||
exclude_patterns: Optional[List[str]] = None,
|
||||
timeout: int = 30,
|
||||
verify_ssl: bool = True
|
||||
) -> Union[List[Dict[str, str]], Dict[str, str]]:
|
||||
"""
|
||||
Extract all links from a webpage.
|
||||
|
||||
Args:
|
||||
url: URL to extract links from
|
||||
same_domain: Only return links from the same domain
|
||||
exclude_patterns: List of regex patterns to exclude
|
||||
timeout: Request timeout in seconds
|
||||
verify_ssl: Whether to verify SSL certificates
|
||||
|
||||
Returns:
|
||||
List[Dict] or Dict: List of links or error dict
|
||||
"""
|
||||
try:
|
||||
# Compile exclude patterns
|
||||
if exclude_patterns:
|
||||
exclude_patterns = [re.compile(p) for p in exclude_patterns]
|
||||
|
||||
# Get base domain
|
||||
base_domain = urlparse(url).netloc
|
||||
|
||||
# Scrape page
|
||||
result = self.scrape_page(
|
||||
url,
|
||||
extract_links=True,
|
||||
timeout=timeout,
|
||||
verify_ssl=verify_ssl
|
||||
)
|
||||
|
||||
if "error" in result:
|
||||
return result
|
||||
|
||||
# Filter and clean links
|
||||
links = []
|
||||
seen_urls = set()
|
||||
|
||||
for link in result.get('links', []):
|
||||
link_url = link['url']
|
||||
|
||||
# Skip if already seen
|
||||
if link_url in seen_urls:
|
||||
continue
|
||||
|
||||
# Parse URL
|
||||
parsed = urlparse(link_url)
|
||||
|
||||
# Skip if not same domain and same_domain is True
|
||||
if same_domain and parsed.netloc != base_domain:
|
||||
continue
|
||||
|
||||
# Skip if matches exclude patterns
|
||||
if exclude_patterns and any(p.search(link_url) for p in exclude_patterns):
|
||||
continue
|
||||
|
||||
# Add to results
|
||||
links.append(link)
|
||||
seen_urls.add(link_url)
|
||||
|
||||
return links
|
||||
except Exception as e:
|
||||
error_msg = f"Error extracting links from {url}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def crawl(
|
||||
self,
|
||||
start_url: str,
|
||||
max_pages: int = 10,
|
||||
same_domain: bool = True,
|
||||
exclude_patterns: Optional[List[str]] = None,
|
||||
delay: float = 1.0,
|
||||
timeout: int = 30,
|
||||
verify_ssl: bool = True,
|
||||
output_dir: Optional[str] = None
|
||||
) -> Union[List[Dict[str, Any]], Dict[str, str]]:
|
||||
"""
|
||||
Crawl multiple pages starting from a URL.
|
||||
|
||||
Args:
|
||||
start_url: Starting URL
|
||||
max_pages: Maximum number of pages to crawl
|
||||
same_domain: Only crawl pages from the same domain
|
||||
exclude_patterns: List of regex patterns to exclude
|
||||
delay: Delay between requests in seconds
|
||||
timeout: Request timeout in seconds
|
||||
verify_ssl: Whether to verify SSL certificates
|
||||
output_dir: Directory to save crawled pages
|
||||
|
||||
Returns:
|
||||
List[Dict] or Dict: Crawled pages or error dict
|
||||
"""
|
||||
try:
|
||||
# Create output directory if needed
|
||||
if output_dir:
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
# Initialize crawl state
|
||||
to_visit = {start_url}
|
||||
visited = set()
|
||||
results = []
|
||||
|
||||
while to_visit and len(visited) < max_pages:
|
||||
# Get next URL
|
||||
url = to_visit.pop()
|
||||
|
||||
# Skip if already visited
|
||||
if url in visited:
|
||||
continue
|
||||
|
||||
# Add to visited
|
||||
visited.add(url)
|
||||
|
||||
# Delay if not first request
|
||||
if len(visited) > 1:
|
||||
time.sleep(delay)
|
||||
|
||||
# Scrape page
|
||||
result = self.scrape_page(
|
||||
url,
|
||||
extract_links=True,
|
||||
timeout=timeout,
|
||||
verify_ssl=verify_ssl
|
||||
)
|
||||
|
||||
if "error" in result:
|
||||
logging.warning(f"Error crawling {url}: {result['error']}")
|
||||
continue
|
||||
|
||||
# Save result
|
||||
results.append(result)
|
||||
|
||||
# Save to file if requested
|
||||
if output_dir:
|
||||
filename = hashlib.md5(url.encode()).hexdigest() + '.json'
|
||||
filepath = os.path.join(output_dir, filename)
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
json.dump(result, f, indent=2, ensure_ascii=False)
|
||||
|
||||
# Add new links to visit
|
||||
for link in result.get('links', []):
|
||||
link_url = link['url']
|
||||
parsed = urlparse(link_url)
|
||||
|
||||
# Skip if not same domain and same_domain is True
|
||||
if same_domain and parsed.netloc != urlparse(start_url).netloc:
|
||||
continue
|
||||
|
||||
# Skip if matches exclude patterns
|
||||
if exclude_patterns and any(
|
||||
re.compile(p).search(link_url) for p in exclude_patterns
|
||||
):
|
||||
continue
|
||||
|
||||
# Add to visit if not visited
|
||||
if link_url not in visited:
|
||||
to_visit.add(link_url)
|
||||
|
||||
return results
|
||||
except Exception as e:
|
||||
error_msg = f"Error crawling from {start_url}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def extract_text(
|
||||
self,
|
||||
url: str,
|
||||
selector: Optional[str] = None,
|
||||
timeout: int = 30,
|
||||
verify_ssl: bool = True
|
||||
) -> Union[str, Dict[str, str]]:
|
||||
"""
|
||||
Extract clean text content from a webpage.
|
||||
|
||||
Args:
|
||||
url: URL to extract text from
|
||||
selector: Optional CSS selector to extract specific content
|
||||
timeout: Request timeout in seconds
|
||||
verify_ssl: Whether to verify SSL certificates
|
||||
|
||||
Returns:
|
||||
str or Dict: Extracted text or error dict
|
||||
"""
|
||||
try:
|
||||
result = self.scrape_page(
|
||||
url,
|
||||
selector=selector,
|
||||
timeout=timeout,
|
||||
verify_ssl=verify_ssl
|
||||
)
|
||||
|
||||
if "error" in result:
|
||||
return result
|
||||
|
||||
if selector:
|
||||
return '\n'.join(result['content'])
|
||||
return result['content']
|
||||
except Exception as e:
|
||||
error_msg = f"Error extracting text from {url}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
# Create instance for direct function access
|
||||
_spider_tools = SpiderTools()
|
||||
scrape_page = _spider_tools.scrape_page
|
||||
extract_links = _spider_tools.extract_links
|
||||
crawl = _spider_tools.crawl
|
||||
extract_text = _spider_tools.extract_text
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
print("\n==================================================")
|
||||
print("SpiderTools Demonstration")
|
||||
print("==================================================\n")
|
||||
|
||||
# 1. Scrape a webpage
|
||||
print("1. Scraping Webpage")
|
||||
print("------------------------------")
|
||||
url = "https://example.com"
|
||||
result = scrape_page(url, extract_images=True, extract_links=True)
|
||||
print(f"Content from {url}:")
|
||||
if "error" not in result:
|
||||
print(f"Title: {result['title']}")
|
||||
print(f"Content length: {len(result['content'])} characters")
|
||||
print(f"Number of images: {len(result.get('images', []))}")
|
||||
print(f"Number of links: {len(result.get('links', []))}")
|
||||
else:
|
||||
print(result) # Show error
|
||||
print()
|
||||
|
||||
# 2. Extract links
|
||||
print("2. Extracting Links")
|
||||
print("------------------------------")
|
||||
links = extract_links(url)
|
||||
print(f"Links from {url}:")
|
||||
if isinstance(links, list):
|
||||
for link in links:
|
||||
print(f"- {link['url']} ({link['text']})")
|
||||
else:
|
||||
print(links) # Show error
|
||||
print()
|
||||
|
||||
# 3. Extract text
|
||||
print("3. Extracting Text")
|
||||
print("------------------------------")
|
||||
text = extract_text(url)
|
||||
print(f"Text from {url}:")
|
||||
if isinstance(text, str):
|
||||
print(text[:500] + "..." if len(text) > 500 else text)
|
||||
else:
|
||||
print(text) # Show error
|
||||
print()
|
||||
|
||||
# 4. Crawl multiple pages
|
||||
print("4. Crawling Multiple Pages")
|
||||
print("------------------------------")
|
||||
results = crawl(url, max_pages=2, delay=1.0)
|
||||
print(f"Crawl results from {url}:")
|
||||
if isinstance(results, list):
|
||||
print(f"Crawled {len(results)} pages")
|
||||
for result in results:
|
||||
print(f"- {result['url']}: {result['title']}")
|
||||
else:
|
||||
print(results) # Show error
|
||||
|
||||
print("\n==================================================")
|
||||
print("Demonstration Complete")
|
||||
print("==================================================")
|
||||
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Test runner for all tools."""
|
||||
|
||||
import os
|
||||
import glob
|
||||
import logging
|
||||
import subprocess
|
||||
|
||||
# Set up logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def main():
|
||||
"""Run all tool files."""
|
||||
logger.info("Starting tests...")
|
||||
|
||||
# Get all *_tools.py files
|
||||
tools_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
tool_files = glob.glob(os.path.join(tools_dir, "*_tools.py"))
|
||||
|
||||
# Run each tool file
|
||||
for tool_file in sorted(tool_files):
|
||||
module_name = os.path.basename(tool_file)
|
||||
logger.info(f"\nRunning {module_name}...")
|
||||
|
||||
try:
|
||||
# Run the tool file directly
|
||||
result = subprocess.run(
|
||||
["python3", tool_file],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=tools_dir
|
||||
)
|
||||
|
||||
# Log output
|
||||
if result.stdout:
|
||||
logger.info(f"Output:\n{result.stdout}")
|
||||
if result.stderr:
|
||||
logger.error(f"Errors:\n{result.stderr}")
|
||||
|
||||
if result.returncode == 0:
|
||||
logger.info(f" {module_name} completed successfully")
|
||||
else:
|
||||
logger.error(f" {module_name} failed with return code {result.returncode}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error running {module_name}: {str(e)}")
|
||||
continue
|
||||
|
||||
logger.info("\nAll tests completed!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,40 +1,9 @@
|
||||
"""Tools module for PraisonAI Agents"""
|
||||
from typing import List, Dict
|
||||
import logging
|
||||
import importlib
|
||||
from .duckduckgo_tools import internet_search
|
||||
|
||||
class Tools:
|
||||
@staticmethod
|
||||
def internet_search(query: str) -> List[Dict]:
|
||||
"""
|
||||
Perform a search using DuckDuckGo.
|
||||
"""Tools class for backward compatibility"""
|
||||
internet_search = staticmethod(internet_search)
|
||||
|
||||
Args:
|
||||
query (str): The search query.
|
||||
|
||||
Returns:
|
||||
list: A list of search result titles, URLs, and snippets.
|
||||
"""
|
||||
# Check if duckduckgo_search is installed
|
||||
if importlib.util.find_spec("duckduckgo_search") is None:
|
||||
error_msg = "DuckDuckGo search is not available. Please install duckduckgo_search package using: pip install duckduckgo_search"
|
||||
logging.error(error_msg)
|
||||
return [{"error": error_msg}]
|
||||
|
||||
try:
|
||||
# Import only when needed
|
||||
from duckduckgo_search import DDGS
|
||||
results = []
|
||||
ddgs = DDGS()
|
||||
for result in ddgs.text(keywords=query, max_results=5):
|
||||
results.append({
|
||||
"title": result.get("title", ""),
|
||||
"url": result.get("href", ""),
|
||||
"snippet": result.get("body", "")
|
||||
})
|
||||
return results
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error during DuckDuckGo search: {e}"
|
||||
logging.error(error_msg)
|
||||
return [{"error": error_msg}]
|
||||
# Re-export the function
|
||||
__all__ = ['Tools', 'internet_search']
|
||||
@@ -0,0 +1,272 @@
|
||||
"""Wikipedia tools for accessing and searching Wikipedia content.
|
||||
|
||||
Usage:
|
||||
from praisonaiagents.tools import wikipedia_tools
|
||||
summary = wikipedia_tools.wiki_summary("Python programming language")
|
||||
page = wikipedia_tools.wiki_page("Python programming language")
|
||||
results = wikipedia_tools.wiki_search("Python programming")
|
||||
|
||||
or
|
||||
from praisonaiagents.tools import wiki_search, wiki_summary, wiki_page
|
||||
summary = wiki_summary("Python programming language")
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Dict, Union, Any
|
||||
from importlib import util
|
||||
import json
|
||||
|
||||
class WikipediaTools:
|
||||
"""Tools for accessing and searching Wikipedia content."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize WikipediaTools and check for wikipedia package."""
|
||||
self._check_wikipedia()
|
||||
|
||||
def _check_wikipedia(self):
|
||||
"""Check if wikipedia package is installed."""
|
||||
if util.find_spec("wikipedia") is None:
|
||||
raise ImportError("wikipedia package is not available. Please install it using: pip install wikipedia")
|
||||
global wikipedia
|
||||
import wikipedia
|
||||
# Set default language to English
|
||||
wikipedia.set_lang("en")
|
||||
|
||||
def wiki_search(
|
||||
self,
|
||||
query: str,
|
||||
results: int = 10,
|
||||
suggestion: bool = True
|
||||
) -> Union[List[str], Dict[str, str]]:
|
||||
"""
|
||||
Search Wikipedia for a query.
|
||||
|
||||
Args:
|
||||
query: Search query
|
||||
results: Maximum number of results to return
|
||||
suggestion: Whether to suggest similar queries
|
||||
|
||||
Returns:
|
||||
List[str] or Dict: List of search results or error dict
|
||||
"""
|
||||
try:
|
||||
search_results = wikipedia.search(query, results=results, suggestion=suggestion)
|
||||
if isinstance(search_results, tuple):
|
||||
# If suggestion is True, returns (results, suggestion)
|
||||
return {
|
||||
"results": search_results[0],
|
||||
"suggestion": search_results[1] if search_results[1] else None
|
||||
}
|
||||
return {"results": search_results, "suggestion": None}
|
||||
except Exception as e:
|
||||
error_msg = f"Error searching Wikipedia for '{query}': {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def wiki_summary(
|
||||
self,
|
||||
title: str,
|
||||
sentences: int = 5,
|
||||
auto_suggest: bool = True
|
||||
) -> Union[str, Dict[str, str]]:
|
||||
"""
|
||||
Get a summary of a Wikipedia page.
|
||||
|
||||
Args:
|
||||
title: Title of the Wikipedia page
|
||||
sentences: Number of sentences to return
|
||||
auto_suggest: Whether to auto-suggest similar titles
|
||||
|
||||
Returns:
|
||||
str or Dict: Page summary if successful, error dict if failed
|
||||
"""
|
||||
try:
|
||||
return wikipedia.summary(title, sentences=sentences, auto_suggest=auto_suggest)
|
||||
except wikipedia.exceptions.DisambiguationError as e:
|
||||
return {
|
||||
"error": "Disambiguation page",
|
||||
"options": e.options[:10] # Limit to first 10 options
|
||||
}
|
||||
except Exception as e:
|
||||
error_msg = f"Error getting summary for '{title}': {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def wiki_page(
|
||||
self,
|
||||
title: str,
|
||||
auto_suggest: bool = True
|
||||
) -> Union[Dict[str, Any], Dict[str, str]]:
|
||||
"""
|
||||
Get detailed information about a Wikipedia page.
|
||||
|
||||
Args:
|
||||
title: Title of the Wikipedia page
|
||||
auto_suggest: Whether to auto-suggest similar titles
|
||||
|
||||
Returns:
|
||||
Dict: Page information if successful, error dict if failed
|
||||
"""
|
||||
try:
|
||||
page = wikipedia.page(title, auto_suggest=auto_suggest)
|
||||
return {
|
||||
"title": page.title,
|
||||
"url": page.url,
|
||||
"content": page.content,
|
||||
"summary": page.summary,
|
||||
"references": page.references,
|
||||
"categories": page.categories,
|
||||
"links": page.links,
|
||||
"images": page.images,
|
||||
"sections": self.get_sections(page)
|
||||
}
|
||||
except wikipedia.exceptions.DisambiguationError as e:
|
||||
return {
|
||||
"error": "Disambiguation page",
|
||||
"options": e.options[:10] # Limit to first 10 options
|
||||
}
|
||||
except Exception as e:
|
||||
error_msg = f"Error getting page for '{title}': {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def get_sections(self, page: Any) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Extract sections and their content from a Wikipedia page.
|
||||
|
||||
Args:
|
||||
page: Wikipedia page object
|
||||
|
||||
Returns:
|
||||
List[Dict]: List of sections with their titles and content
|
||||
"""
|
||||
sections = []
|
||||
content = page.content
|
||||
section_titles = [s.strip() for s in content.split("==")[1::2]]
|
||||
section_contents = [s.strip() for s in content.split("==")[2::2]]
|
||||
|
||||
# Add introduction section
|
||||
intro = content.split("==")[0].strip()
|
||||
if intro:
|
||||
sections.append({
|
||||
"title": "Introduction",
|
||||
"level": 0,
|
||||
"content": intro
|
||||
})
|
||||
|
||||
# Process remaining sections
|
||||
for title, content in zip(section_titles, section_contents):
|
||||
# Count leading '=' to determine section level
|
||||
level = title.count("=") // 2
|
||||
clean_title = title.strip("= ")
|
||||
|
||||
sections.append({
|
||||
"title": clean_title,
|
||||
"level": level,
|
||||
"content": content.strip()
|
||||
})
|
||||
|
||||
return sections
|
||||
|
||||
def wiki_random(self, pages: int = 1) -> Union[List[str], Dict[str, str]]:
|
||||
"""
|
||||
Get random Wikipedia page titles.
|
||||
|
||||
Args:
|
||||
pages: Number of random pages to return
|
||||
|
||||
Returns:
|
||||
List[str] or Dict: List of random page titles or error dict
|
||||
"""
|
||||
try:
|
||||
return wikipedia.random(pages)
|
||||
except Exception as e:
|
||||
error_msg = f"Error getting random pages: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def wiki_language(self, language: str) -> bool:
|
||||
"""
|
||||
Set the language for Wikipedia searches.
|
||||
|
||||
Args:
|
||||
language: Language code (e.g., 'en' for English, 'es' for Spanish)
|
||||
|
||||
Returns:
|
||||
bool: True if successful, False if failed
|
||||
"""
|
||||
try:
|
||||
wikipedia.set_lang(language)
|
||||
return True
|
||||
except Exception as e:
|
||||
error_msg = f"Error setting language to '{language}': {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
# Create instance for direct function access
|
||||
_wikipedia_tools = WikipediaTools()
|
||||
wiki_search = _wikipedia_tools.wiki_search
|
||||
wiki_summary = _wikipedia_tools.wiki_summary
|
||||
wiki_page = _wikipedia_tools.wiki_page
|
||||
wiki_random = _wikipedia_tools.wiki_random
|
||||
wiki_language = _wikipedia_tools.wiki_language
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
print("\n==================================================")
|
||||
print("WikipediaTools Demonstration")
|
||||
print("==================================================\n")
|
||||
|
||||
# 1. Search for a topic
|
||||
print("1. Searching Wikipedia")
|
||||
print("------------------------------")
|
||||
search_results = wiki_search("Python programming language")
|
||||
print("Search results:")
|
||||
print(json.dumps(search_results, indent=2))
|
||||
print()
|
||||
|
||||
# 2. Get a page summary
|
||||
print("2. Getting Page Summary")
|
||||
print("------------------------------")
|
||||
summary = wiki_summary("Python programming language", sentences=3)
|
||||
print("Summary:")
|
||||
print(summary)
|
||||
print()
|
||||
|
||||
# 3. Get detailed page information
|
||||
print("3. Getting Full Page Information")
|
||||
print("------------------------------")
|
||||
page = wiki_page("Python programming language")
|
||||
if isinstance(page, dict) and "error" not in page:
|
||||
print("Page sections:")
|
||||
for section in page["sections"]:
|
||||
print(f"- {section['title']} (Level {section['level']})")
|
||||
print(f"\nNumber of references: {len(page['references'])}")
|
||||
print(f"Number of categories: {len(page['categories'])}")
|
||||
print(f"Number of links: {len(page['links'])}")
|
||||
print(f"Number of images: {len(page['images'])}")
|
||||
else:
|
||||
print("Error getting page:", page.get("error"))
|
||||
print()
|
||||
|
||||
# 4. Get random pages
|
||||
print("4. Getting Random Pages")
|
||||
print("------------------------------")
|
||||
random_pages = wiki_random(3)
|
||||
print("Random page titles:")
|
||||
print(json.dumps(random_pages, indent=2))
|
||||
print()
|
||||
|
||||
# 5. Try different language
|
||||
print("5. Changing Language")
|
||||
print("------------------------------")
|
||||
success = wiki_language("es")
|
||||
if success:
|
||||
summary = wiki_summary("Python (lenguaje de programación)", sentences=1)
|
||||
print("Spanish summary:")
|
||||
print(summary)
|
||||
print()
|
||||
|
||||
print("\n==================================================")
|
||||
print("Demonstration Complete")
|
||||
print("==================================================")
|
||||
@@ -0,0 +1,498 @@
|
||||
"""Tools for working with XML files.
|
||||
|
||||
Usage:
|
||||
from praisonaiagents.tools import xml_tools
|
||||
tree = xml_tools.read_xml("data.xml")
|
||||
|
||||
or
|
||||
from praisonaiagents.tools import read_xml, write_xml, transform_xml
|
||||
tree = read_xml("data.xml")
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Dict, Union, Optional, Any, Tuple
|
||||
from importlib import util
|
||||
import xml.etree.ElementTree as ET
|
||||
import xml.dom.minidom as minidom
|
||||
from io import StringIO
|
||||
import json
|
||||
|
||||
class XMLTools:
|
||||
"""Tools for working with XML files."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize XMLTools."""
|
||||
pass
|
||||
|
||||
def read_xml(
|
||||
self,
|
||||
filepath: str,
|
||||
encoding: str = 'utf-8',
|
||||
validate_schema: Optional[str] = None,
|
||||
parser: str = 'lxml'
|
||||
) -> ET.Element:
|
||||
"""Read an XML file with optional schema validation.
|
||||
|
||||
Args:
|
||||
filepath: Path to XML file
|
||||
encoding: File encoding
|
||||
validate_schema: Optional path to XSD schema file
|
||||
parser: XML parser to use ('lxml' or 'etree')
|
||||
|
||||
Returns:
|
||||
ElementTree root element
|
||||
"""
|
||||
try:
|
||||
if parser == 'lxml':
|
||||
if util.find_spec('lxml') is None:
|
||||
error_msg = "lxml package is not available. Please install it using: pip install lxml"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
import lxml.etree as lxml_etree
|
||||
tree = lxml_etree.parse(filepath)
|
||||
root = tree.getroot()
|
||||
else:
|
||||
tree = ET.parse(filepath)
|
||||
root = tree.getroot()
|
||||
|
||||
if validate_schema:
|
||||
if util.find_spec('xmlschema') is None:
|
||||
error_msg = "xmlschema package is not available. Please install it using: pip install xmlschema"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
import xmlschema
|
||||
schema = xmlschema.XMLSchema(validate_schema)
|
||||
if not schema.is_valid(filepath):
|
||||
error_msg = f"XML file does not validate against schema: {schema.validate(filepath)}"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
|
||||
return root
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error reading XML file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
|
||||
def write_xml(
|
||||
self,
|
||||
root: ET.Element,
|
||||
filepath: str,
|
||||
encoding: str = 'utf-8',
|
||||
pretty: bool = True,
|
||||
xml_declaration: bool = True
|
||||
) -> bool:
|
||||
"""Write XML Element tree to file.
|
||||
|
||||
Args:
|
||||
root: XML Element tree root
|
||||
filepath: Output file path
|
||||
encoding: File encoding
|
||||
pretty: Format output with proper indentation
|
||||
xml_declaration: Include XML declaration
|
||||
|
||||
Returns:
|
||||
True if successful, False otherwise
|
||||
"""
|
||||
try:
|
||||
# Convert to string
|
||||
if pretty:
|
||||
xml_str = minidom.parseString(
|
||||
ET.tostring(root, encoding='unicode')
|
||||
).toprettyxml(indent=' ')
|
||||
else:
|
||||
xml_str = ET.tostring(
|
||||
root,
|
||||
encoding='unicode'
|
||||
)
|
||||
|
||||
# Add declaration if requested
|
||||
if xml_declaration:
|
||||
if not xml_str.startswith('<?xml'):
|
||||
xml_str = (
|
||||
f'<?xml version="1.0" encoding="{encoding}"?>\n'
|
||||
+ xml_str
|
||||
)
|
||||
|
||||
# Write to file
|
||||
with open(filepath, 'w', encoding=encoding) as f:
|
||||
f.write(xml_str)
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
error_msg = f"Error writing XML file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
def transform_xml(
|
||||
self,
|
||||
xml_file: str,
|
||||
xslt_file: str,
|
||||
output_file: str,
|
||||
params: Optional[Dict[str, str]] = None
|
||||
) -> bool:
|
||||
"""Transform XML using XSLT stylesheet.
|
||||
|
||||
Args:
|
||||
xml_file: Input XML file
|
||||
xslt_file: XSLT stylesheet file
|
||||
output_file: Output file path
|
||||
params: Optional parameters for transformation
|
||||
|
||||
Returns:
|
||||
True if successful, False otherwise
|
||||
"""
|
||||
try:
|
||||
# Parse XML and XSLT
|
||||
if util.find_spec('lxml') is None:
|
||||
error_msg = "lxml package is not available. Please install it using: pip install lxml"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
import lxml.etree as lxml_etree
|
||||
xml_doc = lxml_etree.parse(xml_file)
|
||||
xslt_doc = lxml_etree.parse(xslt_file)
|
||||
transform = lxml_etree.XSLT(xslt_doc)
|
||||
|
||||
# Apply transformation
|
||||
if params:
|
||||
result = transform(xml_doc, **params)
|
||||
else:
|
||||
result = transform(xml_doc)
|
||||
|
||||
# Write result
|
||||
result.write(
|
||||
output_file,
|
||||
pretty_print=True,
|
||||
xml_declaration=True,
|
||||
encoding='utf-8'
|
||||
)
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
error_msg = f"Error transforming XML: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
def validate_xml(
|
||||
self,
|
||||
xml_file: str,
|
||||
schema_file: str
|
||||
) -> Tuple[bool, Optional[str]]:
|
||||
"""Validate XML against XSD schema.
|
||||
|
||||
Args:
|
||||
xml_file: XML file to validate
|
||||
schema_file: XSD schema file
|
||||
|
||||
Returns:
|
||||
Tuple of (is_valid, error_message)
|
||||
"""
|
||||
try:
|
||||
if util.find_spec('xmlschema') is None:
|
||||
error_msg = "xmlschema package is not available. Please install it using: pip install xmlschema"
|
||||
logging.error(error_msg)
|
||||
return False, error_msg
|
||||
import xmlschema
|
||||
schema = xmlschema.XMLSchema(schema_file)
|
||||
schema.validate(xml_file)
|
||||
return True, None
|
||||
except xmlschema.validators.exceptions.XMLSchemaValidationError as e:
|
||||
return False, str(e)
|
||||
except Exception as e:
|
||||
error_msg = f"Error validating XML: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False, error_msg
|
||||
|
||||
def xml_to_dict(
|
||||
self,
|
||||
root: Union[str, ET.Element],
|
||||
preserve_attrs: bool = True
|
||||
) -> Dict[str, Any]:
|
||||
"""Convert XML to dictionary.
|
||||
|
||||
Args:
|
||||
root: XML string or Element tree root
|
||||
preserve_attrs: Keep XML attributes in result
|
||||
|
||||
Returns:
|
||||
Dict representation of XML
|
||||
"""
|
||||
try:
|
||||
# Parse XML if string
|
||||
if isinstance(root, str):
|
||||
if root.startswith('<'):
|
||||
root = ET.fromstring(root)
|
||||
else:
|
||||
root = ET.parse(root).getroot()
|
||||
|
||||
result = {}
|
||||
|
||||
# Add attributes if present and requested
|
||||
if preserve_attrs and root.attrib:
|
||||
result['@attributes'] = dict(root.attrib)
|
||||
|
||||
# Add children
|
||||
children = list(root)
|
||||
if not children:
|
||||
text = root.text
|
||||
if text is not None and text.strip():
|
||||
result = text.strip()
|
||||
else:
|
||||
for child in children:
|
||||
child_data = self.xml_to_dict(child, preserve_attrs)
|
||||
if child.tag in result:
|
||||
if not isinstance(result[child.tag], list):
|
||||
result[child.tag] = [result[child.tag]]
|
||||
result[child.tag].append(child_data)
|
||||
else:
|
||||
result[child.tag] = child_data
|
||||
|
||||
return result
|
||||
except Exception as e:
|
||||
error_msg = f"Error converting XML to dict: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {}
|
||||
|
||||
def dict_to_xml(
|
||||
self,
|
||||
data: Dict[str, Any],
|
||||
root_tag: str = 'root'
|
||||
) -> Optional[ET.Element]:
|
||||
"""Convert dictionary to XML.
|
||||
|
||||
Args:
|
||||
data: Dictionary to convert
|
||||
root_tag: Tag for root element
|
||||
|
||||
Returns:
|
||||
XML Element tree root
|
||||
"""
|
||||
try:
|
||||
def _create_element(
|
||||
parent: ET.Element,
|
||||
key: str,
|
||||
value: Any
|
||||
):
|
||||
"""Create XML element from key-value pair."""
|
||||
if key == '@attributes':
|
||||
for attr_key, attr_val in value.items():
|
||||
parent.set(attr_key, str(attr_val))
|
||||
elif isinstance(value, dict):
|
||||
child = ET.SubElement(parent, key)
|
||||
for k, v in value.items():
|
||||
_create_element(child, k, v)
|
||||
elif isinstance(value, list):
|
||||
for item in value:
|
||||
child = ET.SubElement(parent, key)
|
||||
if isinstance(item, dict):
|
||||
for k, v in item.items():
|
||||
_create_element(child, k, v)
|
||||
else:
|
||||
child.text = str(item)
|
||||
else:
|
||||
child = ET.SubElement(parent, key)
|
||||
child.text = str(value)
|
||||
|
||||
root = ET.Element(root_tag)
|
||||
for key, value in data.items():
|
||||
_create_element(root, key, value)
|
||||
|
||||
return root
|
||||
except Exception as e:
|
||||
error_msg = f"Error converting dict to XML: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
|
||||
def xpath_query(
|
||||
self,
|
||||
root: Union[str, ET.Element],
|
||||
query: str,
|
||||
namespaces: Optional[Dict[str, str]] = None
|
||||
) -> List[ET.Element]:
|
||||
"""Execute XPath query on XML.
|
||||
|
||||
Args:
|
||||
root: XML string or Element tree root
|
||||
query: XPath query string
|
||||
namespaces: Optional namespace mappings
|
||||
|
||||
Returns:
|
||||
List of matching elements
|
||||
"""
|
||||
try:
|
||||
# Parse XML if string
|
||||
if isinstance(root, str):
|
||||
if root.startswith('<'):
|
||||
if util.find_spec('lxml') is None:
|
||||
error_msg = "lxml package is not available. Please install it using: pip install lxml"
|
||||
logging.error(error_msg)
|
||||
return []
|
||||
import lxml.etree as lxml_etree
|
||||
tree = lxml_etree.fromstring(root)
|
||||
else:
|
||||
tree = ET.parse(root)
|
||||
else:
|
||||
if util.find_spec('lxml') is None:
|
||||
error_msg = "lxml package is not available. Please install it using: pip install lxml"
|
||||
logging.error(error_msg)
|
||||
return []
|
||||
import lxml.etree as lxml_etree
|
||||
tree = lxml_etree.fromstring(
|
||||
ET.tostring(root, encoding='unicode')
|
||||
)
|
||||
|
||||
# Execute query
|
||||
results = tree.xpath(
|
||||
query,
|
||||
namespaces=namespaces or {}
|
||||
)
|
||||
|
||||
# Convert results to standard ElementTree elements
|
||||
return [
|
||||
ET.fromstring(lxml_etree.tostring(elem, encoding='unicode'))
|
||||
for elem in results
|
||||
]
|
||||
except Exception as e:
|
||||
error_msg = f"Error executing XPath query: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return []
|
||||
|
||||
# Create instance for direct function access
|
||||
_xml_tools = XMLTools()
|
||||
read_xml = _xml_tools.read_xml
|
||||
write_xml = _xml_tools.write_xml
|
||||
transform_xml = _xml_tools.transform_xml
|
||||
validate_xml = _xml_tools.validate_xml
|
||||
xml_to_dict = _xml_tools.xml_to_dict
|
||||
dict_to_xml = _xml_tools.dict_to_xml
|
||||
xpath_query = _xml_tools.xpath_query
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("\n==================================================")
|
||||
print("XMLTools Demonstration")
|
||||
print("==================================================\n")
|
||||
|
||||
# Create temporary files
|
||||
import tempfile
|
||||
import os
|
||||
|
||||
temp_file = tempfile.mktemp(suffix='.xml')
|
||||
try:
|
||||
print("1. Creating XML Document")
|
||||
print("------------------------------")
|
||||
xml_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bookstore>
|
||||
<book category="fiction">
|
||||
<title>The Great Gatsby</title>
|
||||
<author>F. Scott Fitzgerald</author>
|
||||
<year>1925</year>
|
||||
<price>10.99</price>
|
||||
</book>
|
||||
<book category="non-fiction">
|
||||
<title>A Brief History of Time</title>
|
||||
<author>Stephen Hawking</author>
|
||||
<year>1988</year>
|
||||
<price>15.99</price>
|
||||
</book>
|
||||
</bookstore>"""
|
||||
|
||||
with open(temp_file, 'w') as f:
|
||||
f.write(xml_content)
|
||||
print("Sample XML file created")
|
||||
print()
|
||||
|
||||
print("2. Parsing XML")
|
||||
print("------------------------------")
|
||||
result = read_xml(temp_file)
|
||||
print("XML structure:")
|
||||
print(minidom.parseString(ET.tostring(result, encoding='unicode')).toprettyxml(indent=' '))
|
||||
print()
|
||||
|
||||
print("3. Querying XML")
|
||||
print("------------------------------")
|
||||
xpath = "//book[@category='fiction']/title/text()"
|
||||
result = xpath_query(result, xpath)
|
||||
print(f"Fiction book titles (XPath: {xpath}):")
|
||||
for title in result:
|
||||
print(title.text)
|
||||
print()
|
||||
|
||||
print("4. Validating XML")
|
||||
print("------------------------------")
|
||||
schema_file = tempfile.mktemp(suffix='.xsd')
|
||||
schema_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:element name="bookstore">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="book" maxOccurs="unbounded">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="title" type="xs:string"/>
|
||||
<xs:element name="author" type="xs:string"/>
|
||||
<xs:element name="year" type="xs:integer"/>
|
||||
<xs:element name="price" type="xs:decimal"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="category" type="xs:string"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>"""
|
||||
with open(schema_file, 'w') as f:
|
||||
f.write(schema_content)
|
||||
result, error = validate_xml(temp_file, schema_file)
|
||||
print(f"XML validation result: {result}")
|
||||
if error:
|
||||
print(f"Error: {error}")
|
||||
print()
|
||||
|
||||
print("5. Transforming XML")
|
||||
print("------------------------------")
|
||||
xslt_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:template match="/">
|
||||
<html>
|
||||
<body>
|
||||
<h2>Bookstore Inventory</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th>Author</th>
|
||||
<th>Price</th>
|
||||
</tr>
|
||||
<xsl:for-each select="bookstore/book">
|
||||
<tr>
|
||||
<td><xsl:value-of select="title"/></td>
|
||||
<td><xsl:value-of select="author"/></td>
|
||||
<td><xsl:value-of select="price"/></td>
|
||||
</tr>
|
||||
</xsl:for-each>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>"""
|
||||
|
||||
xslt_file = tempfile.mktemp(suffix='.xslt')
|
||||
with open(xslt_file, 'w') as f:
|
||||
f.write(xslt_content)
|
||||
|
||||
output_file = tempfile.mktemp(suffix='.html')
|
||||
result = transform_xml(temp_file, xslt_file, output_file)
|
||||
print(f"XML transformation result: {result}")
|
||||
if result and os.path.exists(output_file):
|
||||
print("\nTransformed HTML content:")
|
||||
with open(output_file, 'r') as f:
|
||||
print(f.read())
|
||||
|
||||
finally:
|
||||
# Clean up temporary files
|
||||
for file in [temp_file, schema_file, xslt_file, output_file]:
|
||||
if os.path.exists(file):
|
||||
os.unlink(file)
|
||||
|
||||
print("\n==================================================")
|
||||
print("Demonstration Complete")
|
||||
print("==================================================")
|
||||
@@ -0,0 +1,417 @@
|
||||
"""Tools for working with YAML files.
|
||||
|
||||
Usage:
|
||||
from praisonaiagents.tools import yaml_tools
|
||||
data = yaml_tools.read_yaml("config.yaml")
|
||||
|
||||
or
|
||||
from praisonaiagents.tools import read_yaml, write_yaml, merge_yaml
|
||||
data = read_yaml("config.yaml")
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Dict, Union, Optional, Any
|
||||
from importlib import util
|
||||
import os
|
||||
from copy import deepcopy
|
||||
|
||||
class YAMLTools:
|
||||
"""Tools for working with YAML files."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize YAMLTools."""
|
||||
self._check_dependencies()
|
||||
|
||||
def _check_dependencies(self):
|
||||
"""Check if required packages are installed."""
|
||||
missing = []
|
||||
for package, module in [('pyyaml', 'yaml'), ('jsonschema', 'jsonschema')]:
|
||||
if util.find_spec(module) is None:
|
||||
missing.append(package)
|
||||
|
||||
if missing:
|
||||
raise ImportError(
|
||||
f"Required packages not available. Please install: {', '.join(missing)}\n"
|
||||
f"Run: pip install {' '.join(missing)}"
|
||||
)
|
||||
|
||||
def read_yaml(
|
||||
self,
|
||||
filepath: str,
|
||||
safe_load: bool = True,
|
||||
encoding: str = 'utf-8'
|
||||
) -> Optional[Union[Dict[str, Any], List[Any]]]:
|
||||
"""Read a YAML file."""
|
||||
try:
|
||||
if util.find_spec('yaml') is None:
|
||||
error_msg = "pyyaml package is not available. Please install it using: pip install pyyaml"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
|
||||
# Import yaml only when needed
|
||||
import yaml
|
||||
|
||||
with open(filepath, 'r', encoding=encoding) as f:
|
||||
if safe_load:
|
||||
return yaml.safe_load(f)
|
||||
return yaml.load(f, Loader=yaml.FullLoader)
|
||||
except Exception as e:
|
||||
error_msg = f"Error reading YAML file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
|
||||
def write_yaml(
|
||||
self,
|
||||
data: Union[Dict[str, Any], List[Any]],
|
||||
filepath: str,
|
||||
default_flow_style: bool = False,
|
||||
encoding: str = 'utf-8',
|
||||
sort_keys: bool = False,
|
||||
allow_unicode: bool = True
|
||||
) -> bool:
|
||||
"""Write data to YAML file."""
|
||||
try:
|
||||
if util.find_spec('yaml') is None:
|
||||
error_msg = "pyyaml package is not available. Please install it using: pip install pyyaml"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
# Import yaml only when needed
|
||||
import yaml
|
||||
|
||||
with open(filepath, 'w', encoding=encoding) as f:
|
||||
yaml.dump(
|
||||
data,
|
||||
f,
|
||||
default_flow_style=default_flow_style,
|
||||
sort_keys=sort_keys,
|
||||
allow_unicode=allow_unicode
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
error_msg = f"Error writing YAML file {filepath}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
def merge_yaml(
|
||||
self,
|
||||
files: List[str],
|
||||
output_file: Optional[str] = None,
|
||||
strategy: str = 'deep'
|
||||
) -> Union[Dict[str, Any], List[Any], None]:
|
||||
"""Merge multiple YAML files."""
|
||||
try:
|
||||
if util.find_spec('yaml') is None:
|
||||
error_msg = "pyyaml package is not available. Please install it using: pip install pyyaml"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
|
||||
def deep_merge(source: dict, destination: dict) -> dict:
|
||||
"""Deep merge two dictionaries."""
|
||||
for key, value in source.items():
|
||||
if key in destination:
|
||||
if isinstance(value, dict) and isinstance(destination[key], dict):
|
||||
destination[key] = deep_merge(value, destination[key])
|
||||
elif isinstance(value, list) and isinstance(destination[key], list):
|
||||
destination[key].extend(value)
|
||||
else:
|
||||
destination[key] = value
|
||||
else:
|
||||
destination[key] = value
|
||||
return destination
|
||||
|
||||
result = {}
|
||||
for file in files:
|
||||
data = self.read_yaml(file)
|
||||
if data is None:
|
||||
continue
|
||||
|
||||
if strategy == 'deep':
|
||||
if isinstance(data, dict):
|
||||
result = deep_merge(data, result)
|
||||
elif isinstance(data, list):
|
||||
if not result:
|
||||
result = []
|
||||
result.extend(data)
|
||||
else: # shallow
|
||||
if isinstance(data, dict):
|
||||
result.update(data)
|
||||
elif isinstance(data, list):
|
||||
if not result:
|
||||
result = []
|
||||
result.extend(data)
|
||||
|
||||
if output_file:
|
||||
self.write_yaml(result, output_file)
|
||||
|
||||
return result
|
||||
except Exception as e:
|
||||
error_msg = f"Error merging YAML files: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
|
||||
def validate_yaml(
|
||||
self,
|
||||
data: Union[Dict[str, Any], List[Any], str],
|
||||
schema: Dict[str, Any]
|
||||
) -> bool:
|
||||
"""Validate YAML data against a schema."""
|
||||
try:
|
||||
if util.find_spec('jsonschema') is None:
|
||||
error_msg = "jsonschema package is not available. Please install it using: pip install jsonschema"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
# Import jsonschema only when needed
|
||||
from jsonschema import validate, ValidationError
|
||||
|
||||
# Load data if file path
|
||||
if isinstance(data, str):
|
||||
data = self.read_yaml(data)
|
||||
if data is None:
|
||||
return False
|
||||
|
||||
try:
|
||||
validate(instance=data, schema=schema)
|
||||
return True
|
||||
except ValidationError as e:
|
||||
logging.error(f"YAML validation error: {str(e)}")
|
||||
return False
|
||||
except Exception as e:
|
||||
error_msg = f"Error validating YAML: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return False
|
||||
|
||||
def analyze_yaml(
|
||||
self,
|
||||
data: Union[Dict[str, Any], List[Any], str]
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
"""Analyze YAML data structure."""
|
||||
try:
|
||||
# Load data if file path
|
||||
if isinstance(data, str):
|
||||
data = self.read_yaml(data)
|
||||
if data is None:
|
||||
return None
|
||||
|
||||
def analyze_value(value: Any) -> Dict[str, Any]:
|
||||
"""Analyze a single value."""
|
||||
result = {
|
||||
'type': type(value).__name__,
|
||||
'size': len(value) if hasattr(value, '__len__') else 1
|
||||
}
|
||||
|
||||
if isinstance(value, dict):
|
||||
result['keys'] = list(value.keys())
|
||||
result['nested_types'] = {
|
||||
k: type(v).__name__
|
||||
for k, v in value.items()
|
||||
}
|
||||
elif isinstance(value, list):
|
||||
result['element_types'] = list(set(
|
||||
type(x).__name__ for x in value
|
||||
))
|
||||
|
||||
return result
|
||||
|
||||
result = {
|
||||
'structure': analyze_value(data),
|
||||
'stats': {
|
||||
'total_keys': sum(1 for _ in self._walk_dict(data))
|
||||
if isinstance(data, dict) else len(data)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
except Exception as e:
|
||||
error_msg = f"Error analyzing YAML: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
|
||||
def _walk_dict(self, d: Dict[str, Any]) -> Any:
|
||||
"""Walk through nested dictionary."""
|
||||
for k, v in d.items():
|
||||
yield k
|
||||
if isinstance(v, dict):
|
||||
yield from self._walk_dict(v)
|
||||
|
||||
def transform_yaml(
|
||||
self,
|
||||
data: Union[Dict[str, Any], List[Any], str],
|
||||
operations: List[Dict[str, Any]]
|
||||
) -> Optional[Union[Dict[str, Any], List[Any]]]:
|
||||
"""Transform YAML data using specified operations."""
|
||||
try:
|
||||
# Load data if file path
|
||||
if isinstance(data, str):
|
||||
data = self.read_yaml(data)
|
||||
if data is None:
|
||||
return None
|
||||
|
||||
result = deepcopy(data)
|
||||
|
||||
for op in operations:
|
||||
op_type = op.get('type')
|
||||
path = op.get('path', '')
|
||||
value = op.get('value')
|
||||
|
||||
if not op_type:
|
||||
continue
|
||||
|
||||
# Split path into parts
|
||||
parts = [p for p in path.split('/') if p]
|
||||
|
||||
# Get reference to target location
|
||||
target = result
|
||||
parent = None
|
||||
last_key = None
|
||||
|
||||
for part in parts[:-1]:
|
||||
if isinstance(target, dict):
|
||||
if part not in target:
|
||||
target[part] = {}
|
||||
parent = target
|
||||
target = target[part]
|
||||
last_key = part
|
||||
elif isinstance(target, list):
|
||||
idx = int(part)
|
||||
while len(target) <= idx:
|
||||
target.append({})
|
||||
parent = target
|
||||
target = target[idx]
|
||||
last_key = idx
|
||||
|
||||
if parts:
|
||||
last_part = parts[-1]
|
||||
if isinstance(target, dict):
|
||||
if op_type == 'set':
|
||||
target[last_part] = value
|
||||
elif op_type == 'delete':
|
||||
target.pop(last_part, None)
|
||||
elif op_type == 'append' and isinstance(target.get(last_part), list):
|
||||
target[last_part].append(value)
|
||||
elif isinstance(target, list):
|
||||
idx = int(last_part)
|
||||
if op_type == 'set':
|
||||
while len(target) <= idx:
|
||||
target.append(None)
|
||||
target[idx] = value
|
||||
elif op_type == 'delete' and idx < len(target):
|
||||
del target[idx]
|
||||
elif op_type == 'append':
|
||||
target.append(value)
|
||||
else:
|
||||
if op_type == 'set':
|
||||
result = value
|
||||
elif op_type == 'append' and isinstance(result, list):
|
||||
result.append(value)
|
||||
|
||||
return result
|
||||
except Exception as e:
|
||||
error_msg = f"Error transforming YAML: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
|
||||
# Create instance for direct function access
|
||||
_yaml_tools = YAMLTools()
|
||||
read_yaml = _yaml_tools.read_yaml
|
||||
write_yaml = _yaml_tools.write_yaml
|
||||
merge_yaml = _yaml_tools.merge_yaml
|
||||
validate_yaml = _yaml_tools.validate_yaml
|
||||
analyze_yaml = _yaml_tools.analyze_yaml
|
||||
transform_yaml = _yaml_tools.transform_yaml
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
print("\n==================================================")
|
||||
print("YAMLTools Demonstration")
|
||||
print("==================================================\n")
|
||||
|
||||
# Sample data
|
||||
data1 = {
|
||||
'server': {
|
||||
'host': 'localhost',
|
||||
'port': 8080,
|
||||
'debug': True
|
||||
},
|
||||
'database': {
|
||||
'url': 'postgresql://localhost:5432/db',
|
||||
'pool_size': 5
|
||||
}
|
||||
}
|
||||
|
||||
data2 = {
|
||||
'server': {
|
||||
'workers': 4,
|
||||
'timeout': 30
|
||||
},
|
||||
'logging': {
|
||||
'level': 'INFO',
|
||||
'file': 'app.log'
|
||||
}
|
||||
}
|
||||
|
||||
# 1. Write YAML files
|
||||
print("1. Writing YAML Files")
|
||||
print("------------------------------")
|
||||
success1 = write_yaml(data1, 'config1.yaml')
|
||||
success2 = write_yaml(data2, 'config2.yaml')
|
||||
print(f"First file written: {success1}")
|
||||
print(f"Second file written: {success2}")
|
||||
print()
|
||||
|
||||
# 2. Read YAML file
|
||||
print("2. Reading YAML File")
|
||||
print("------------------------------")
|
||||
config = read_yaml('config1.yaml')
|
||||
print("YAML content:")
|
||||
print(config)
|
||||
print()
|
||||
|
||||
# 3. Merge YAML files
|
||||
print("3. Merging YAML Files")
|
||||
print("------------------------------")
|
||||
merged = merge_yaml(['config1.yaml', 'config2.yaml'])
|
||||
print("Merged content:")
|
||||
print(merged)
|
||||
print()
|
||||
|
||||
# 4. Analyze YAML
|
||||
print("4. Analyzing YAML")
|
||||
print("------------------------------")
|
||||
analysis = analyze_yaml(merged)
|
||||
print("Analysis results:")
|
||||
print(analysis)
|
||||
print()
|
||||
|
||||
# 5. Transform YAML
|
||||
print("5. Transforming YAML")
|
||||
print("------------------------------")
|
||||
operations = [
|
||||
{
|
||||
'type': 'set',
|
||||
'path': 'server/host',
|
||||
'value': '0.0.0.0'
|
||||
},
|
||||
{
|
||||
'type': 'delete',
|
||||
'path': 'server/debug'
|
||||
},
|
||||
{
|
||||
'type': 'set',
|
||||
'path': 'logging/handlers',
|
||||
'value': ['console', 'file']
|
||||
}
|
||||
]
|
||||
transformed = transform_yaml(merged, operations)
|
||||
print("Transformed content:")
|
||||
print(transformed)
|
||||
|
||||
print("\n==================================================")
|
||||
print("Demonstration Complete")
|
||||
print("==================================================")
|
||||
|
||||
# Cleanup
|
||||
for file in ['config1.yaml', 'config2.yaml']:
|
||||
if os.path.exists(file):
|
||||
os.remove(file)
|
||||
@@ -0,0 +1,213 @@
|
||||
"""YFinance tools for stock market data.
|
||||
|
||||
Usage:
|
||||
from praisonaiagents.tools import get_stock_price, get_stock_info
|
||||
price = get_stock_price("AAPL")
|
||||
info = get_stock_info("AAPL")
|
||||
|
||||
or
|
||||
from praisonaiagents.tools import yfinance
|
||||
price = yfinance.get_stock_price("AAPL")
|
||||
info = yfinance.get_stock_info("AAPL")
|
||||
"""
|
||||
|
||||
from typing import List, Dict, Optional, Any
|
||||
import logging
|
||||
from importlib import util
|
||||
from datetime import datetime
|
||||
|
||||
class YFinanceTools:
|
||||
"""A comprehensive tool for financial data analysis using yfinance"""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize YFinanceTools"""
|
||||
self._tickers = {}
|
||||
|
||||
def _get_yfinance(self):
|
||||
"""Get yfinance module, installing if needed"""
|
||||
if util.find_spec('yfinance') is None:
|
||||
error_msg = "yfinance package is not available. Please install it using: pip install yfinance"
|
||||
logging.error(error_msg)
|
||||
return None
|
||||
import yfinance as yf
|
||||
return yf
|
||||
|
||||
def _get_ticker(self, symbol: str):
|
||||
"""Get or create ticker instance"""
|
||||
if symbol not in self._tickers:
|
||||
yf = self._get_yfinance()
|
||||
if yf is None:
|
||||
return None
|
||||
self._tickers[symbol] = yf.Ticker(symbol)
|
||||
return self._tickers[symbol]
|
||||
|
||||
def get_stock_price(self, symbol: str) -> Dict[str, float]:
|
||||
"""
|
||||
Get current stock price and related price metrics
|
||||
|
||||
Args:
|
||||
symbol (str): Stock ticker symbol
|
||||
|
||||
Returns:
|
||||
Dict[str, float]: Current price information
|
||||
"""
|
||||
try:
|
||||
ticker = self._get_ticker(symbol)
|
||||
if ticker is None:
|
||||
return {"error": "yfinance package not available"}
|
||||
|
||||
info = ticker.info
|
||||
return {
|
||||
'symbol': symbol,
|
||||
'price': info.get('regularMarketPrice', 0.0),
|
||||
'open': info.get('regularMarketOpen', 0.0),
|
||||
'high': info.get('regularMarketDayHigh', 0.0),
|
||||
'low': info.get('regularMarketDayLow', 0.0),
|
||||
'volume': info.get('regularMarketVolume', 0),
|
||||
'previous_close': info.get('regularMarketPreviousClose', 0.0),
|
||||
'change': info.get('regularMarketChange', 0.0),
|
||||
'change_percent': info.get('regularMarketChangePercent', 0.0)
|
||||
}
|
||||
except Exception as e:
|
||||
error_msg = f"Error getting stock price for {symbol}: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def get_stock_info(self, symbol: str) -> Dict:
|
||||
"""
|
||||
Get detailed information about a stock
|
||||
|
||||
Args:
|
||||
symbol (str): Stock ticker symbol
|
||||
|
||||
Returns:
|
||||
Dict: Stock information including company details and key metrics
|
||||
"""
|
||||
try:
|
||||
ticker = self._get_ticker(symbol)
|
||||
if ticker is None:
|
||||
return {"error": "yfinance package not available"}
|
||||
|
||||
info = ticker.info
|
||||
|
||||
relevant_info = {
|
||||
"longName": info.get("longName"),
|
||||
"symbol": info.get("symbol"),
|
||||
"sector": info.get("sector"),
|
||||
"industry": info.get("industry"),
|
||||
"country": info.get("country"),
|
||||
"marketCap": info.get("marketCap"),
|
||||
"currentPrice": info.get("currentPrice"),
|
||||
"currency": info.get("currency"),
|
||||
"exchange": info.get("exchange"),
|
||||
"fiftyTwoWeekHigh": info.get("fiftyTwoWeekHigh"),
|
||||
"fiftyTwoWeekLow": info.get("fiftyTwoWeekLow"),
|
||||
"trailingPE": info.get("trailingPE"),
|
||||
"forwardPE": info.get("forwardPE"),
|
||||
"dividendYield": info.get("dividendYield"),
|
||||
"beta": info.get("beta"),
|
||||
"volume": info.get("volume"),
|
||||
"averageVolume": info.get("averageVolume"),
|
||||
"sharesOutstanding": info.get("sharesOutstanding"),
|
||||
"website": info.get("website"),
|
||||
"longBusinessSummary": info.get("longBusinessSummary")
|
||||
}
|
||||
return {k: v for k, v in relevant_info.items() if v is not None}
|
||||
except Exception as e:
|
||||
error_msg = f"Error fetching stock info: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return {"error": error_msg}
|
||||
|
||||
def get_historical_data(
|
||||
self,
|
||||
symbol: str,
|
||||
period: str = "1y",
|
||||
interval: str = "1d",
|
||||
start: Optional[datetime] = None,
|
||||
end: Optional[datetime] = None
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Get historical price data for a stock
|
||||
|
||||
Args:
|
||||
symbol (str): Stock ticker symbol
|
||||
period (str): Data period e.g. 1d, 5d, 1mo, 3mo, 6mo, 1y, 2y, 5y, 10y, ytd, max
|
||||
interval (str): Data interval e.g. 1m, 2m, 5m, 15m, 30m, 60m, 90m, 1h, 1d, 5d, 1wk, 1mo, 3mo
|
||||
start (datetime, optional): Start date for data
|
||||
end (datetime, optional): End date for data
|
||||
|
||||
Returns:
|
||||
List[Dict[str, Any]]: List of historical price data points
|
||||
"""
|
||||
try:
|
||||
ticker = self._get_ticker(symbol)
|
||||
if ticker is None:
|
||||
return [{"error": "yfinance package not available"}]
|
||||
|
||||
hist = ticker.history(period=period, interval=interval, start=start, end=end)
|
||||
return hist.reset_index().to_dict('records')
|
||||
except Exception as e:
|
||||
error_msg = f"Error fetching historical data: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
return [{"error": error_msg}]
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
print("\n==================================================")
|
||||
print("YFinanceTools Demonstration")
|
||||
print("==================================================\n")
|
||||
|
||||
try:
|
||||
yf_tools = YFinanceTools()
|
||||
|
||||
# 1. Basic Stock Information
|
||||
print("1. Basic Stock Information for AAPL")
|
||||
print("------------------------------")
|
||||
info = yf_tools.get_stock_info("AAPL")
|
||||
if "error" not in info:
|
||||
print(f"Company: {info.get('longName')}")
|
||||
print(f"Sector: {info.get('sector')}")
|
||||
print(f"Industry: {info.get('industry')}")
|
||||
print(f"Country: {info.get('country')}\n")
|
||||
else:
|
||||
print(f"Error: {info['error']}\n")
|
||||
|
||||
# 2. Current Price Data
|
||||
print("2. Current Price Data")
|
||||
print("------------------------------")
|
||||
price_data = yf_tools.get_stock_price("AAPL")
|
||||
if "error" not in price_data:
|
||||
print(f"Current Price: ${price_data.get('price', 'N/A')}")
|
||||
print(f"Previous Close: ${price_data.get('previous_close', 'N/A')}")
|
||||
print(f"Day Range: ${price_data.get('low', 'N/A')} - ${price_data.get('high', 'N/A')}\n")
|
||||
else:
|
||||
print(f"Error: {price_data['error']}\n")
|
||||
|
||||
# 3. Historical Data
|
||||
print("3. Historical Data (Last 5 Days)")
|
||||
print("------------------------------")
|
||||
hist_data = yf_tools.get_historical_data("AAPL", period="5d")
|
||||
if not any("error" in d for d in hist_data):
|
||||
for day in hist_data:
|
||||
print(f"Date: {day.get('Date')}, Close: ${day.get('Close', 'N/A'):.2f}")
|
||||
print()
|
||||
else:
|
||||
print(f"{hist_data[0]['error']}\n")
|
||||
|
||||
# 4. Multi-Stock Example
|
||||
print("5. Multi-Stock Current Prices")
|
||||
print("------------------------------")
|
||||
for symbol in ["AAPL", "MSFT", "GOOGL"]:
|
||||
price_data = yf_tools.get_stock_price(symbol)
|
||||
if "error" not in price_data:
|
||||
print(f"{symbol}: ${price_data.get('price', 'N/A')}")
|
||||
else:
|
||||
print(f"{symbol}: Error fetching price")
|
||||
print()
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {str(e)}")
|
||||
|
||||
print("==================================================")
|
||||
print("Analysis Complete")
|
||||
print("==================================================")
|
||||
@@ -0,0 +1,91 @@
|
||||
from praisonaiagents.agent import Agent
|
||||
from praisonaiagents.task import Task
|
||||
from praisonaiagents.agents import PraisonAIAgents
|
||||
from typing import List, Dict
|
||||
import time
|
||||
|
||||
def get_time_check():
|
||||
current_time = int(time.time())
|
||||
result = "even" if current_time % 2 == 0 else "odd"
|
||||
print(f"Time check: {current_time} is {result}")
|
||||
return result
|
||||
|
||||
def create_prompt_chain():
|
||||
# Create agents for each step in the chain
|
||||
agent1 = Agent(
|
||||
name="Time Checker",
|
||||
role="Time checker",
|
||||
goal="Check if the time is even or odd",
|
||||
instructions="Check if the time is even or odd",
|
||||
tools=[get_time_check]
|
||||
)
|
||||
|
||||
agent2 = Agent(
|
||||
name="Advanced Analyzer",
|
||||
role="Advanced data analyzer",
|
||||
goal="Perform in-depth analysis of processed data",
|
||||
instructions="Analyze the processed data in detail"
|
||||
)
|
||||
|
||||
agent3 = Agent(
|
||||
name="Final Processor",
|
||||
role="Final data processor",
|
||||
goal="Generate final output based on analysis",
|
||||
instructions="Create final output based on analyzed data"
|
||||
)
|
||||
|
||||
# Create tasks for each step
|
||||
initial_task = Task(
|
||||
name="time_check",
|
||||
description="Getting time check and checking if it is even or odd",
|
||||
expected_output="Getting time check and checking if it is even or odd",
|
||||
agent=agent1,
|
||||
is_start=True, # Mark as the starting task
|
||||
task_type="decision", # This task will make a decision
|
||||
next_tasks=["advanced_analysis"], # Next task if condition passes
|
||||
condition={
|
||||
"even": ["advanced_analysis"], # If passes, go to advanced analysis
|
||||
"odd": ["final_processing"] # If fails, exit the chain
|
||||
}
|
||||
)
|
||||
|
||||
analysis_task = Task(
|
||||
name="advanced_analysis",
|
||||
description="Perform advanced analysis on the processed data",
|
||||
expected_output="Analyzed data ready for final processing",
|
||||
agent=agent2,
|
||||
next_tasks=["final_processing"]
|
||||
)
|
||||
|
||||
final_task = Task(
|
||||
name="final_processing",
|
||||
description="Generate final output",
|
||||
expected_output="Final processed result",
|
||||
agent=agent3
|
||||
)
|
||||
|
||||
# Create the workflow manager
|
||||
workflow = PraisonAIAgents(
|
||||
agents=[agent1, agent2, agent3],
|
||||
tasks=[initial_task, analysis_task, final_task],
|
||||
process="workflow", # Use workflow process type
|
||||
verbose=True
|
||||
)
|
||||
|
||||
return workflow
|
||||
|
||||
def main():
|
||||
# Create and run the prompt chain
|
||||
workflow = create_prompt_chain()
|
||||
|
||||
# Run the workflow
|
||||
results = workflow.start()
|
||||
|
||||
# Print results
|
||||
print("\nWorkflow Results:")
|
||||
for task_id, result in results["task_results"].items():
|
||||
if result:
|
||||
print(f"Task {task_id}: {result.raw}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,81 @@
|
||||
from praisonaiagents.agent import Agent
|
||||
from praisonaiagents.task import Task
|
||||
from praisonaiagents.agents import PraisonAIAgents
|
||||
from typing import List, Dict
|
||||
import time
|
||||
|
||||
def get_time_check():
|
||||
current_time = int(time.time())
|
||||
result = "even" if current_time % 2 == 0 else "odd"
|
||||
print(f"Time check: {current_time} is {result}")
|
||||
return result
|
||||
|
||||
# Create agents for each step in the chain
|
||||
agent1 = Agent(
|
||||
name="Time Checker",
|
||||
role="Time checker",
|
||||
goal="Check if the time is even or odd",
|
||||
instructions="Check if the time is even or odd",
|
||||
tools=[get_time_check]
|
||||
)
|
||||
|
||||
agent2 = Agent(
|
||||
name="Advanced Analyzer",
|
||||
role="Advanced data analyzer",
|
||||
goal="Perform in-depth analysis of processed data",
|
||||
instructions="Analyze the processed data in detail"
|
||||
)
|
||||
|
||||
agent3 = Agent(
|
||||
name="Final Processor",
|
||||
role="Final data processor",
|
||||
goal="Generate final output based on analysis",
|
||||
instructions="Create final output based on analyzed data"
|
||||
)
|
||||
|
||||
# Create tasks for each step
|
||||
initial_task = Task(
|
||||
name="time_check",
|
||||
description="Getting time check and checking if it is even or odd",
|
||||
expected_output="Getting time check and checking if it is even or odd",
|
||||
agent=agent1,
|
||||
is_start=True, # Mark as the starting task
|
||||
task_type="decision", # This task will make a decision
|
||||
next_tasks=["advanced_analysis"], # Next task if condition passes
|
||||
condition={
|
||||
"even": ["advanced_analysis"], # If passes, go to advanced analysis
|
||||
"odd": "" # If fails, exit the chain
|
||||
}
|
||||
)
|
||||
|
||||
analysis_task = Task(
|
||||
name="advanced_analysis",
|
||||
description="Perform advanced analysis on the processed data",
|
||||
expected_output="Analyzed data ready for final processing",
|
||||
agent=agent2,
|
||||
next_tasks=["final_processing"]
|
||||
)
|
||||
|
||||
final_task = Task(
|
||||
name="final_processing",
|
||||
description="Generate final output",
|
||||
expected_output="Final processed result",
|
||||
agent=agent3
|
||||
)
|
||||
|
||||
# Create the workflow manager
|
||||
workflow = PraisonAIAgents(
|
||||
agents=[agent1, agent2, agent3],
|
||||
tasks=[initial_task, analysis_task, final_task],
|
||||
process="workflow", # Use workflow process type
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Run the workflow
|
||||
results = workflow.start()
|
||||
|
||||
# Print results
|
||||
print("\nWorkflow Results:")
|
||||
for task_id, result in results["task_results"].items():
|
||||
if result:
|
||||
print(f"Task {task_id}: {result.raw}")
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "praisonaiagents"
|
||||
version = "0.0.21"
|
||||
version = "0.0.32"
|
||||
description = "Praison AI agents for completing complex tasks with Self Reflection Agents"
|
||||
authors = [
|
||||
{ name="Mervin Praison" }
|
||||
@@ -13,4 +13,9 @@ dependencies = [
|
||||
"pydantic",
|
||||
"rich",
|
||||
"openai"
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
memory = [
|
||||
"chromadb>=0.6.0"
|
||||
]
|
||||
@@ -0,0 +1,82 @@
|
||||
from praisonaiagents.agent import Agent
|
||||
from praisonaiagents.task import Task
|
||||
from praisonaiagents.agents import PraisonAIAgents
|
||||
import time
|
||||
|
||||
current_time = int(time.time())
|
||||
result = "even" if current_time % 2 == 0 else "odd"
|
||||
print(f"Time check: {current_time} is {result}")
|
||||
|
||||
# Create specialized agents
|
||||
router = Agent(
|
||||
name="Router",
|
||||
role="Input Router",
|
||||
goal="Evaluate input and determine routing path",
|
||||
instructions="Analyze input and decide whether to proceed or exit",
|
||||
tools=[get_time_check]
|
||||
)
|
||||
|
||||
processor1 = Agent(
|
||||
name="Processor 1",
|
||||
role="Secondary Processor",
|
||||
goal="Process valid inputs that passed initial check",
|
||||
instructions="Process data that passed the routing check"
|
||||
)
|
||||
|
||||
processor2 = Agent(
|
||||
name="Processor 2",
|
||||
role="Final Processor",
|
||||
goal="Perform final processing on validated data",
|
||||
instructions="Generate final output for processed data"
|
||||
)
|
||||
|
||||
# Create tasks with routing logic
|
||||
routing_task = Task(
|
||||
name="initial_routing",
|
||||
description="check the time and return according to what is returned",
|
||||
expected_output="pass or fail based on what is returned",
|
||||
agent=router,
|
||||
is_start=True,
|
||||
task_type="decision",
|
||||
condition={
|
||||
"pass": ["process_valid"],
|
||||
"fail": "exit"
|
||||
}
|
||||
)
|
||||
|
||||
processing_task = Task(
|
||||
name="process_valid",
|
||||
description="Process validated input",
|
||||
expected_output="Processed data ready for final step",
|
||||
agent=processor1,
|
||||
next_tasks=["final_process"]
|
||||
)
|
||||
|
||||
final_task = Task(
|
||||
name="final_process",
|
||||
description="Generate final output",
|
||||
expected_output="Final processed result",
|
||||
agent=processor2
|
||||
)
|
||||
|
||||
# Create and run workflow
|
||||
workflow = PraisonAIAgents(
|
||||
agents=[router, processor1, processor2],
|
||||
tasks=[routing_task, processing_task, final_task],
|
||||
process="workflow",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
print("\nStarting Routing Workflow...")
|
||||
print("=" * 50)
|
||||
|
||||
results = workflow.start()
|
||||
|
||||
print("\nWorkflow Results:")
|
||||
print("=" * 50)
|
||||
for task_id, result in results["task_results"].items():
|
||||
if result:
|
||||
task_name = result.description
|
||||
print(f"\nTask: {task_name}")
|
||||
print(f"Result: {result.raw}")
|
||||
print("-" * 50)
|
||||
@@ -0,0 +1,83 @@
|
||||
from praisonaiagents.agent import Agent
|
||||
from praisonaiagents.task import Task
|
||||
from praisonaiagents.agents import PraisonAIAgents
|
||||
import time
|
||||
|
||||
def get_time_check():
|
||||
current_time = int(time.time())
|
||||
result = "even" if current_time % 2 == 0 else "odd"
|
||||
print(f"Time check: {current_time} is {result}")
|
||||
return result
|
||||
|
||||
# Create specialized agents
|
||||
router = Agent(
|
||||
name="Router",
|
||||
role="Input Router",
|
||||
goal="Evaluate input and determine routing path",
|
||||
instructions="Analyze input and decide whether to proceed or exit",
|
||||
tools=[get_time_check]
|
||||
)
|
||||
|
||||
processor1 = Agent(
|
||||
name="Processor 1",
|
||||
role="Secondary Processor",
|
||||
goal="Process valid inputs that passed initial check",
|
||||
instructions="Process data that passed the routing check"
|
||||
)
|
||||
|
||||
processor2 = Agent(
|
||||
name="Processor 2",
|
||||
role="Final Processor",
|
||||
goal="Perform final processing on validated data",
|
||||
instructions="Generate final output for processed data"
|
||||
)
|
||||
|
||||
# Create tasks with routing logic
|
||||
routing_task = Task(
|
||||
name="initial_routing",
|
||||
description="check the time and return according to what is returned",
|
||||
expected_output="pass or fail based on what is returned",
|
||||
agent=router,
|
||||
is_start=True,
|
||||
task_type="decision",
|
||||
condition={
|
||||
"pass": ["process_valid"],
|
||||
"fail": ["process_invalid"]
|
||||
}
|
||||
)
|
||||
|
||||
processing_task = Task(
|
||||
name="process_valid",
|
||||
description="Process validated input",
|
||||
expected_output="Processed data ready for final step",
|
||||
agent=processor1,
|
||||
)
|
||||
|
||||
final_task = Task(
|
||||
name="process_invalid",
|
||||
description="Generate final output",
|
||||
expected_output="Final processed result",
|
||||
agent=processor2
|
||||
)
|
||||
|
||||
# Create and run workflow
|
||||
workflow = PraisonAIAgents(
|
||||
agents=[router, processor1, processor2],
|
||||
tasks=[routing_task, processing_task, final_task],
|
||||
process="workflow",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
print("\nStarting Routing Workflow...")
|
||||
print("=" * 50)
|
||||
|
||||
results = workflow.start()
|
||||
|
||||
print("\nWorkflow Results:")
|
||||
print("=" * 50)
|
||||
for task_id, result in results["task_results"].items():
|
||||
if result:
|
||||
task_name = result.description
|
||||
print(f"\nTask: {task_name}")
|
||||
print(f"Result: {result.raw}")
|
||||
print("-" * 50)
|
||||
@@ -0,0 +1,56 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents, Tools
|
||||
from pydantic import BaseModel
|
||||
|
||||
class AnalysisReport(BaseModel):
|
||||
title: str
|
||||
findings: str
|
||||
summary: str
|
||||
|
||||
# Create a researcher agent
|
||||
researcher = Agent(
|
||||
name="AIResearcher",
|
||||
role="Technology Research Analyst",
|
||||
goal="Analyze and structure information about AI developments",
|
||||
backstory="Expert analyst specializing in AI technology trends",
|
||||
verbose=True,
|
||||
llm="gpt-4o-mini",
|
||||
tools=[Tools.internet_search],
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# Create an analyst agent
|
||||
analyst = Agent(
|
||||
name="DataAnalyst",
|
||||
role="Data Insights Specialist",
|
||||
goal="Structure and analyze research findings",
|
||||
backstory="Senior data analyst with expertise in pattern recognition",
|
||||
verbose=True,
|
||||
llm="gpt-4o-mini",
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# Define structured tasks
|
||||
research_task = Task(
|
||||
name="gather_research",
|
||||
description="Research recent AI developments in 2024",
|
||||
agent=researcher,
|
||||
expected_output="Research findings"
|
||||
)
|
||||
|
||||
analysis_task = Task(
|
||||
name="analyze_findings",
|
||||
description="Analyze research findings and create structured report. No additional text or explanation.",
|
||||
agent=analyst,
|
||||
output_json=AnalysisReport,
|
||||
expected_output="JSON object"
|
||||
)
|
||||
|
||||
# Initialize and run agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher, analyst],
|
||||
tasks=[research_task, analysis_task],
|
||||
process="sequential",
|
||||
verbose=True
|
||||
)
|
||||
result = agents.start()
|
||||
print(result)
|
||||
@@ -0,0 +1,95 @@
|
||||
from praisonaiagents import Agent
|
||||
from pydantic import BaseModel
|
||||
from typing import List, Optional
|
||||
|
||||
# Define structured output models
|
||||
class SearchResult(BaseModel):
|
||||
title: str
|
||||
url: Optional[str]
|
||||
snippet: str
|
||||
|
||||
class AnalysisReport(BaseModel):
|
||||
topic: str
|
||||
key_findings: List[str]
|
||||
search_results: List[SearchResult]
|
||||
summary: str
|
||||
confidence_score: float
|
||||
|
||||
def get_structured_analysis(query: str, verbose: bool = True) -> AnalysisReport:
|
||||
"""
|
||||
Performs a search and returns a structured analysis using an AI agent.
|
||||
|
||||
Args:
|
||||
query (str): The search query or topic to analyze
|
||||
verbose (bool): Whether to show detailed output
|
||||
|
||||
Returns:
|
||||
AnalysisReport: A structured report containing the analysis
|
||||
"""
|
||||
# Create an agent with search capabilities
|
||||
agent = Agent(
|
||||
name="StructuredAnalyst",
|
||||
role="Research Analyst",
|
||||
goal="Analyze topics and provide structured reports",
|
||||
backstory="Expert at gathering information and providing structured analysis",
|
||||
verbose=verbose,
|
||||
self_reflect=True, # Enable self-reflection for better quality
|
||||
markdown=True,
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
# Create the analysis prompt
|
||||
prompt = f"""
|
||||
Analyze the following topic: "{query}"
|
||||
|
||||
Provide a structured analysis in JSON format that matches this schema:
|
||||
{{
|
||||
"topic": "string",
|
||||
"key_findings": ["string"],
|
||||
"search_results": [
|
||||
{{
|
||||
"title": "string",
|
||||
"url": "string",
|
||||
"snippet": "string"
|
||||
}}
|
||||
],
|
||||
"summary": "string",
|
||||
"confidence_score": float (0-1)
|
||||
}}
|
||||
|
||||
Requirements:
|
||||
1. Include at least 3 key findings
|
||||
2. Include at least 2 relevant search results
|
||||
3. Provide a comprehensive summary
|
||||
4. Set confidence score based on quality of sources (0-1)
|
||||
|
||||
Return ONLY the JSON object, no other text.
|
||||
"""
|
||||
|
||||
# Get structured response from agent
|
||||
response = agent.chat(
|
||||
prompt=prompt,
|
||||
output_json=AnalysisReport # This ensures response matches our model
|
||||
)
|
||||
|
||||
return AnalysisReport.model_validate_json(response)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
analysis = get_structured_analysis("Latest developments in AI agents and autonomous systems")
|
||||
print(analysis)
|
||||
# Print the structured results
|
||||
print("\n=== Structured Analysis Report ===")
|
||||
print(f"Topic: {analysis.topic}")
|
||||
print("\nKey Findings:")
|
||||
for i, finding in enumerate(analysis.key_findings, 1):
|
||||
print(f"{i}. {finding}")
|
||||
|
||||
print("\nSearch Results:")
|
||||
for result in analysis.search_results:
|
||||
print(f"\nTitle: {result.title}")
|
||||
print(f"URL: {result.url}")
|
||||
print(f"Snippet: {result.snippet}")
|
||||
|
||||
print(f"\nSummary: {analysis.summary}")
|
||||
print(f"Confidence Score: {analysis.confidence_score:.2f}")
|
||||
@@ -0,0 +1,30 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from praisonaiagents.tools import get_article, get_news_sources, get_articles_from_source, get_trending_topics
|
||||
|
||||
# Create Wikipedia agent
|
||||
news_agent = Agent(
|
||||
name="NewsAgent",
|
||||
role="News Analyst",
|
||||
goal="Collect and analyze news articles from various sources.",
|
||||
backstory="Expert in news gathering and content analysis.",
|
||||
tools=[get_article, get_news_sources, get_articles_from_source, get_trending_topics],
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
|
||||
# Define research task
|
||||
news_task = Task(
|
||||
description="Analyze news articles about 'AI developments' from major tech news sources.",
|
||||
expected_output="Summary of key AI developments with source articles.",
|
||||
agent=news_agent,
|
||||
name="ai_news"
|
||||
)
|
||||
|
||||
|
||||
# Run agent
|
||||
agents = PraisonAIAgents(
|
||||
agents=[news_agent],
|
||||
tasks=[news_task],
|
||||
process="sequential"
|
||||
)
|
||||
agents.start()
|
||||
Generated
+1271
-2
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,233 @@
|
||||
import asyncio
|
||||
import time
|
||||
from typing import List, Dict
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents, TaskOutput
|
||||
from praisonaiagents.main import (
|
||||
display_error,
|
||||
display_interaction,
|
||||
display_tool_call,
|
||||
display_instruction,
|
||||
error_logs,
|
||||
Console
|
||||
)
|
||||
from duckduckgo_search import DDGS
|
||||
from pydantic import BaseModel
|
||||
|
||||
console = Console()
|
||||
|
||||
# 1. Define output model for structured results
|
||||
class SearchResult(BaseModel):
|
||||
query: str
|
||||
results: List[Dict[str, str]]
|
||||
total_results: int
|
||||
|
||||
# 2. Define both sync and async tools
|
||||
def sync_search_tool(query: str) -> List[Dict]:
|
||||
"""
|
||||
Synchronous search using DuckDuckGo.
|
||||
Args:
|
||||
query (str): The search query.
|
||||
Returns:
|
||||
list: Search results
|
||||
"""
|
||||
display_tool_call(f"Running sync search for: {query}", console)
|
||||
time.sleep(1) # Simulate network delay
|
||||
try:
|
||||
results = []
|
||||
ddgs = DDGS()
|
||||
for result in ddgs.text(keywords=query, max_results=5):
|
||||
results.append({
|
||||
"title": result.get("title", ""),
|
||||
"url": result.get("href", ""),
|
||||
"snippet": result.get("body", "")
|
||||
})
|
||||
return results
|
||||
except Exception as e:
|
||||
error_msg = f"Error during sync search: {e}"
|
||||
display_error(error_msg, console)
|
||||
error_logs.append(error_msg)
|
||||
return []
|
||||
|
||||
async def async_search_tool(query: str) -> List[Dict]:
|
||||
"""
|
||||
Asynchronous search using DuckDuckGo.
|
||||
Args:
|
||||
query (str): The search query.
|
||||
Returns:
|
||||
list: Search results
|
||||
"""
|
||||
display_tool_call(f"Running async search for: {query}", console)
|
||||
await asyncio.sleep(1) # Simulate network delay
|
||||
try:
|
||||
results = []
|
||||
ddgs = DDGS()
|
||||
for result in ddgs.text(keywords=query, max_results=5):
|
||||
results.append({
|
||||
"title": result.get("title", ""),
|
||||
"url": result.get("href", ""),
|
||||
"snippet": result.get("body", "")
|
||||
})
|
||||
return results
|
||||
except Exception as e:
|
||||
error_msg = f"Error during async search: {e}"
|
||||
display_error(error_msg, console)
|
||||
error_logs.append(error_msg)
|
||||
return []
|
||||
|
||||
# 3. Define both sync and async callbacks
|
||||
def sync_callback(output: TaskOutput):
|
||||
display_interaction("Sync Callback", f"Processing output: {output.raw[:100]}...", markdown=True, console=console)
|
||||
time.sleep(1) # Simulate processing
|
||||
if output.output_format == "JSON":
|
||||
display_tool_call(f"Processed JSON result: {output.json_dict}", console)
|
||||
elif output.output_format == "Pydantic":
|
||||
display_tool_call(f"Processed Pydantic result: {output.pydantic}", console)
|
||||
|
||||
async def async_callback(output: TaskOutput):
|
||||
display_interaction("Async Callback", f"Processing output: {output.raw[:100]}...", markdown=True, console=console)
|
||||
await asyncio.sleep(1) # Simulate processing
|
||||
if output.output_format == "JSON":
|
||||
display_tool_call(f"Processed JSON result: {output.json_dict}", console)
|
||||
elif output.output_format == "Pydantic":
|
||||
display_tool_call(f"Processed Pydantic result: {output.pydantic}", console)
|
||||
|
||||
# 4. Create agents with different tools
|
||||
sync_agent = Agent(
|
||||
name="SyncAgent",
|
||||
role="Synchronous Search Specialist",
|
||||
goal="Perform synchronous searches and return structured results",
|
||||
backstory="Expert in sync operations and data organization",
|
||||
tools=[sync_search_tool],
|
||||
self_reflect=False,
|
||||
verbose=True,
|
||||
markdown=True
|
||||
)
|
||||
|
||||
async_agent = Agent(
|
||||
name="AsyncAgent",
|
||||
role="Asynchronous Search Specialist",
|
||||
goal="Perform asynchronous searches and return structured results",
|
||||
backstory="Expert in async operations and data organization",
|
||||
tools=[async_search_tool],
|
||||
self_reflect=False,
|
||||
verbose=True,
|
||||
markdown=True
|
||||
)
|
||||
|
||||
# 5. Create tasks with different configurations
|
||||
sync_task = Task(
|
||||
name="sync_search",
|
||||
description="Search for 'Python programming' using sync tool and return structured results",
|
||||
expected_output="SearchResult model with query details and results",
|
||||
agent=sync_agent,
|
||||
async_execution=False,
|
||||
callback=sync_callback,
|
||||
output_pydantic=SearchResult
|
||||
)
|
||||
|
||||
async_task = Task(
|
||||
name="async_search",
|
||||
description="Search for 'Async programming' using async tool and return structured results",
|
||||
expected_output="SearchResult model with query details and results",
|
||||
agent=async_agent,
|
||||
async_execution=True,
|
||||
callback=async_callback,
|
||||
output_pydantic=SearchResult
|
||||
)
|
||||
|
||||
# 6. Create workflow tasks
|
||||
workflow_sync_task = Task(
|
||||
name="workflow_sync",
|
||||
description="Workflow sync search for 'AI trends' with structured output",
|
||||
expected_output="SearchResult model with AI trends data",
|
||||
agent=sync_agent,
|
||||
async_execution=False,
|
||||
is_start=True,
|
||||
next_tasks=["workflow_async"],
|
||||
output_pydantic=SearchResult
|
||||
)
|
||||
|
||||
workflow_async_task = Task(
|
||||
name="workflow_async",
|
||||
description="Workflow async search for 'Future of AI' with structured output",
|
||||
expected_output="SearchResult model with Future of AI data",
|
||||
agent=async_agent,
|
||||
async_execution=True,
|
||||
output_pydantic=SearchResult
|
||||
)
|
||||
|
||||
# 7. Example usage functions
|
||||
def run_sync_example():
|
||||
"""Run synchronous example"""
|
||||
display_instruction("\nRunning Synchronous Example...", console)
|
||||
agents = PraisonAIAgents(
|
||||
agents=[sync_agent],
|
||||
tasks=[sync_task],
|
||||
verbose=1,
|
||||
process="sequential"
|
||||
)
|
||||
result = agents.start()
|
||||
display_interaction("Sync Example", f"Result: {result}", markdown=True, console=console)
|
||||
|
||||
async def run_async_example():
|
||||
"""Run asynchronous example"""
|
||||
display_instruction("\nRunning Asynchronous Example...", console)
|
||||
agents = PraisonAIAgents(
|
||||
agents=[async_agent],
|
||||
tasks=[async_task],
|
||||
verbose=1,
|
||||
process="sequential"
|
||||
)
|
||||
result = await agents.astart()
|
||||
display_interaction("Async Example", f"Result: {result}", markdown=True, console=console)
|
||||
|
||||
async def run_mixed_example():
|
||||
"""Run mixed sync/async example"""
|
||||
display_instruction("\nRunning Mixed Sync/Async Example...", console)
|
||||
agents = PraisonAIAgents(
|
||||
agents=[sync_agent, async_agent],
|
||||
tasks=[sync_task, async_task],
|
||||
verbose=1,
|
||||
process="sequential"
|
||||
)
|
||||
result = await agents.astart()
|
||||
display_interaction("Mixed Example", f"Result: {result}", markdown=True, console=console)
|
||||
|
||||
async def run_workflow_example():
|
||||
"""Run workflow example with both sync and async tasks"""
|
||||
display_instruction("\nRunning Workflow Example...", console)
|
||||
agents = PraisonAIAgents(
|
||||
agents=[sync_agent, async_agent],
|
||||
tasks=[workflow_sync_task, workflow_async_task],
|
||||
verbose=1,
|
||||
process="workflow"
|
||||
)
|
||||
result = await agents.astart()
|
||||
display_interaction("Workflow Example", f"Result: {result}", markdown=True, console=console)
|
||||
|
||||
# 8. Main execution
|
||||
async def main():
|
||||
"""Main execution function"""
|
||||
display_instruction("Starting PraisonAI Agents Examples...", console)
|
||||
|
||||
try:
|
||||
# Run sync example in a separate thread to not block the event loop
|
||||
loop = asyncio.get_event_loop()
|
||||
await loop.run_in_executor(None, run_sync_example)
|
||||
|
||||
# Run async examples
|
||||
await run_async_example()
|
||||
await run_mixed_example()
|
||||
await run_workflow_example()
|
||||
|
||||
if error_logs:
|
||||
display_error("\nErrors encountered during execution:", console)
|
||||
for error in error_logs:
|
||||
display_error(error, console)
|
||||
except Exception as e:
|
||||
display_error(f"Error in main execution: {e}", console)
|
||||
error_logs.append(str(e))
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run the main function
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,152 @@
|
||||
import asyncio
|
||||
import time
|
||||
from typing import List, Dict
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents, TaskOutput
|
||||
from duckduckgo_search import DDGS
|
||||
from pydantic import BaseModel
|
||||
|
||||
# 1. Define output model for structured results
|
||||
class SearchResult(BaseModel):
|
||||
query: str
|
||||
results: List[Dict[str, str]]
|
||||
total_results: int
|
||||
|
||||
# 2. Define async tool
|
||||
async def async_search_tool(query: str) -> Dict:
|
||||
"""Perform asynchronous search and return structured results."""
|
||||
await asyncio.sleep(1) # Simulate network delay
|
||||
try:
|
||||
results = []
|
||||
ddgs = DDGS()
|
||||
for result in ddgs.text(keywords=query, max_results=5):
|
||||
results.append({
|
||||
"title": result.get("title", ""),
|
||||
"url": result.get("href", ""),
|
||||
"snippet": result.get("body", "")
|
||||
})
|
||||
|
||||
return {
|
||||
"query": query,
|
||||
"results": results,
|
||||
"total_results": len(results)
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"Error during async search: {e}")
|
||||
return {
|
||||
"query": query,
|
||||
"results": [],
|
||||
"total_results": 0
|
||||
}
|
||||
|
||||
# 3. Define async callback
|
||||
async def async_callback(output: TaskOutput):
|
||||
await asyncio.sleep(1) # Simulate processing
|
||||
if output.output_format == "JSON":
|
||||
print(f"Processed JSON result: {output.json_dict}")
|
||||
elif output.output_format == "Pydantic":
|
||||
print(f"Processed Pydantic result: {output.pydantic}")
|
||||
|
||||
# 4. Create specialized agents
|
||||
async_agent = Agent(
|
||||
name="AsyncSearchAgent",
|
||||
role="Search Specialist",
|
||||
goal="Perform fast parallel searches with structured results",
|
||||
backstory="Expert in efficient data retrieval and parallel search operations",
|
||||
tools=[async_search_tool],
|
||||
self_reflect=False,
|
||||
verbose=True,
|
||||
markdown=True
|
||||
)
|
||||
|
||||
summary_agent = Agent(
|
||||
name="SummaryAgent",
|
||||
role="Research Synthesizer",
|
||||
goal="Create concise summaries from multiple search results",
|
||||
backstory="Expert in analyzing and synthesizing information from multiple sources",
|
||||
self_reflect=True,
|
||||
verbose=True,
|
||||
markdown=True
|
||||
)
|
||||
|
||||
# 5. Create async tasks
|
||||
async_task = Task(
|
||||
name="async_search",
|
||||
description="Search for 'Async programming' and return results in JSON format with query, results array, and total_results count.",
|
||||
expected_output="SearchResult model with structured data",
|
||||
agent=async_agent,
|
||||
async_execution=True,
|
||||
callback=async_callback,
|
||||
output_json=SearchResult
|
||||
)
|
||||
|
||||
async def run_parallel_tasks():
|
||||
"""Run multiple async tasks in parallel"""
|
||||
print("\nRunning Parallel Async Tasks...")
|
||||
|
||||
# Define different search topics
|
||||
search_topics = [
|
||||
"Latest AI Developments 2024",
|
||||
"Machine Learning Best Practices",
|
||||
"Neural Networks Architecture"
|
||||
]
|
||||
|
||||
# Create tasks for different topics
|
||||
parallel_tasks = [
|
||||
Task(
|
||||
name=f"search_task_{i}",
|
||||
description=f"Search for '{topic}' and return structured results with query details and findings.",
|
||||
expected_output="SearchResult model with search data",
|
||||
agent=async_agent,
|
||||
async_execution=True,
|
||||
callback=async_callback,
|
||||
output_json=SearchResult
|
||||
) for i, topic in enumerate(search_topics)
|
||||
]
|
||||
|
||||
# Create summarization task
|
||||
summary_task = Task(
|
||||
name="summary_task",
|
||||
description="Analyze all search results and create a concise summary highlighting key findings, patterns, and implications.",
|
||||
expected_output="Structured summary with key findings and insights",
|
||||
agent=summary_agent,
|
||||
async_execution=False,
|
||||
callback=async_callback,
|
||||
context=parallel_tasks
|
||||
)
|
||||
|
||||
# Create a single PraisonAIAgents instance with both agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[async_agent, summary_agent],
|
||||
tasks=parallel_tasks + [summary_task],
|
||||
verbose=1,
|
||||
process="sequential"
|
||||
)
|
||||
|
||||
# Run all tasks
|
||||
results = await agents.astart()
|
||||
print(f"Tasks Results: {results}")
|
||||
|
||||
# Return results in a serializable format
|
||||
return {
|
||||
"search_results": {
|
||||
"task_status": {k: v for k, v in results["task_status"].items() if k != summary_task.id},
|
||||
"task_results": [str(results["task_results"][i]) if results["task_results"][i] else None
|
||||
for i in range(len(parallel_tasks))]
|
||||
},
|
||||
"summary": str(results["task_results"][summary_task.id]) if results["task_results"].get(summary_task.id) else None,
|
||||
"topics": search_topics
|
||||
}
|
||||
|
||||
# 6. Main execution
|
||||
async def main():
|
||||
"""Main execution function"""
|
||||
print("Starting Async AI Agents Examples...")
|
||||
|
||||
try:
|
||||
await run_parallel_tasks()
|
||||
except Exception as e:
|
||||
print(f"Error in main execution: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run the main function
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,248 @@
|
||||
import asyncio
|
||||
import time
|
||||
from typing import List, Dict
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents, TaskOutput
|
||||
from duckduckgo_search import DDGS
|
||||
from pydantic import BaseModel
|
||||
|
||||
# 1. Define output model for structured results
|
||||
class SearchResult(BaseModel):
|
||||
query: str
|
||||
results: List[Dict[str, str]]
|
||||
total_results: int
|
||||
|
||||
# 2. Define async tool
|
||||
async def async_search_tool(query: str) -> Dict:
|
||||
"""
|
||||
Asynchronous search using DuckDuckGo.
|
||||
Args:
|
||||
query (str): The search query.
|
||||
Returns:
|
||||
dict: Search results in SearchResult model format
|
||||
"""
|
||||
await asyncio.sleep(1) # Simulate network delay
|
||||
try:
|
||||
results = []
|
||||
ddgs = DDGS()
|
||||
for result in ddgs.text(keywords=query, max_results=5):
|
||||
results.append({
|
||||
"title": result.get("title", ""),
|
||||
"url": result.get("href", ""),
|
||||
"snippet": result.get("body", "")
|
||||
})
|
||||
|
||||
# Format response to match SearchResult model
|
||||
return {
|
||||
"query": query,
|
||||
"results": results,
|
||||
"total_results": len(results)
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"Error during async search: {e}")
|
||||
return {
|
||||
"query": query,
|
||||
"results": [],
|
||||
"total_results": 0
|
||||
}
|
||||
|
||||
# 3. Define async callback
|
||||
async def async_callback(output: TaskOutput):
|
||||
await asyncio.sleep(1) # Simulate processing
|
||||
if output.output_format == "JSON":
|
||||
print(f"Processed JSON result: {output.json_dict}")
|
||||
elif output.output_format == "Pydantic":
|
||||
print(f"Processed Pydantic result: {output.pydantic}")
|
||||
|
||||
# 4. Create specialized agents
|
||||
async_agent = Agent(
|
||||
name="AsyncSearchAgent",
|
||||
role="Asynchronous Search Specialist",
|
||||
goal="Perform fast and efficient asynchronous searches with structured results",
|
||||
backstory="Expert in parallel search operations and data retrieval",
|
||||
tools=[async_search_tool],
|
||||
self_reflect=False,
|
||||
verbose=True,
|
||||
markdown=True
|
||||
)
|
||||
|
||||
summary_agent = Agent(
|
||||
name="SummaryAgent",
|
||||
role="Research Synthesizer",
|
||||
goal="Create comprehensive summaries and identify patterns across multiple search results",
|
||||
backstory="""Expert in analyzing and synthesizing information from multiple sources.
|
||||
Skilled at identifying patterns, trends, and connections between different topics.
|
||||
Specializes in creating clear, structured summaries that highlight key insights.""",
|
||||
self_reflect=True, # Enable self-reflection for better summary quality
|
||||
verbose=True,
|
||||
markdown=True
|
||||
)
|
||||
|
||||
# 5. Create async tasks
|
||||
async_task = Task(
|
||||
name="async_search",
|
||||
description="""Search for 'Async programming' and return results in the following JSON format:
|
||||
{
|
||||
"query": "the search query",
|
||||
"results": [
|
||||
{
|
||||
"title": "result title",
|
||||
"url": "result url",
|
||||
"snippet": "result snippet"
|
||||
}
|
||||
],
|
||||
"total_results": number of results
|
||||
}""",
|
||||
expected_output="SearchResult model with query details and results",
|
||||
agent=async_agent,
|
||||
async_execution=True,
|
||||
callback=async_callback,
|
||||
output_json=SearchResult
|
||||
)
|
||||
|
||||
# 6. Example usage functions
|
||||
async def run_single_task():
|
||||
"""Run single async task"""
|
||||
print("\nRunning Single Async Task...")
|
||||
agents = PraisonAIAgents(
|
||||
agents=[async_agent],
|
||||
tasks=[async_task],
|
||||
verbose=1,
|
||||
process="sequential"
|
||||
)
|
||||
result = await agents.astart()
|
||||
print(f"Single Task Result: {result}")
|
||||
|
||||
async def run_parallel_tasks():
|
||||
"""Run multiple async tasks in parallel"""
|
||||
print("\nRunning Parallel Async Tasks...")
|
||||
|
||||
# Define different search topics
|
||||
search_topics = [
|
||||
"Latest AI Developments 2024",
|
||||
"Machine Learning Best Practices",
|
||||
"Neural Networks Architecture"
|
||||
]
|
||||
|
||||
# Create tasks for different topics
|
||||
parallel_tasks = [
|
||||
Task(
|
||||
name=f"search_task_{i}",
|
||||
description=f"""Search for '{topic}' and return results in the following JSON format:
|
||||
{{
|
||||
"query": "{topic}",
|
||||
"results": [
|
||||
{{
|
||||
"title": "result title",
|
||||
"url": "result url",
|
||||
"snippet": "result snippet"
|
||||
}}
|
||||
],
|
||||
"total_results": number of results
|
||||
}}""",
|
||||
expected_output="SearchResult model with detailed information",
|
||||
agent=async_agent,
|
||||
async_execution=True,
|
||||
callback=async_callback,
|
||||
output_json=SearchResult
|
||||
) for i, topic in enumerate(search_topics)
|
||||
]
|
||||
|
||||
# Create summarization task with the specialized summary agent
|
||||
summary_task = Task(
|
||||
name="summary_task",
|
||||
description="""As a Research Synthesizer, analyze the search results and create a comprehensive summary. Your task:
|
||||
|
||||
1. Analyze Results:
|
||||
- Review all search results thoroughly
|
||||
- Extract key findings from each topic
|
||||
- Identify main themes and concepts
|
||||
|
||||
2. Find Connections:
|
||||
- Identify relationships between topics
|
||||
- Spot common patterns or contradictions
|
||||
- Note emerging trends across sources
|
||||
|
||||
3. Create Structured Summary:
|
||||
- Main findings per topic
|
||||
- Cross-cutting themes
|
||||
- Emerging trends
|
||||
- Practical implications
|
||||
- Future directions
|
||||
|
||||
4. Quality Checks:
|
||||
- Ensure all topics are covered
|
||||
- Verify accuracy of connections
|
||||
- Confirm clarity of insights
|
||||
- Validate practical relevance
|
||||
|
||||
Present the summary in a clear, structured format with sections for findings, patterns, trends, and implications.""",
|
||||
expected_output="""A comprehensive research synthesis containing:
|
||||
- Detailed findings from each search topic
|
||||
- Cross-topic patterns and relationships
|
||||
- Emerging trends and their implications
|
||||
- Practical applications and future directions""",
|
||||
agent=summary_agent, # Use the specialized summary agent
|
||||
async_execution=False, # Run synchronously after search tasks
|
||||
callback=async_callback
|
||||
)
|
||||
|
||||
# First run parallel search tasks
|
||||
agents = PraisonAIAgents(
|
||||
agents=[async_agent],
|
||||
tasks=parallel_tasks, # Only run search tasks first
|
||||
verbose=1,
|
||||
process="sequential"
|
||||
)
|
||||
search_results = await agents.astart()
|
||||
print(f"Search Tasks Results: {search_results}")
|
||||
|
||||
# Create task objects with results for context
|
||||
completed_tasks = []
|
||||
for i, topic in enumerate(search_topics):
|
||||
task = Task(
|
||||
name=f"search_task_{i}_result",
|
||||
description=f"Search results for: {topic}",
|
||||
expected_output="Search results from previous task",
|
||||
agent=async_agent,
|
||||
result=search_results["task_results"][i]
|
||||
)
|
||||
completed_tasks.append(task)
|
||||
|
||||
# Update summary task with context from search results
|
||||
summary_task.context = completed_tasks
|
||||
|
||||
# Run summarization task with summary agent
|
||||
summary_agents = PraisonAIAgents(
|
||||
agents=[summary_agent], # Use summary agent for synthesis
|
||||
tasks=[summary_task],
|
||||
verbose=1,
|
||||
process="sequential"
|
||||
)
|
||||
summary_result = await summary_agents.astart()
|
||||
print(f"Summary Task Result: {summary_result}")
|
||||
|
||||
# Return results in a serializable format
|
||||
return {
|
||||
"search_results": {
|
||||
"task_status": search_results["task_status"],
|
||||
"task_results": [str(result) if result else None for result in search_results["task_results"]]
|
||||
},
|
||||
"summary": str(summary_result),
|
||||
"topics": search_topics
|
||||
}
|
||||
|
||||
# 7. Main execution
|
||||
async def main():
|
||||
"""Main execution function"""
|
||||
print("Starting Async AI Agents Examples...")
|
||||
|
||||
try:
|
||||
# Run different async patterns
|
||||
await run_single_task()
|
||||
await run_parallel_tasks()
|
||||
except Exception as e:
|
||||
print(f"Error in main execution: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run the main function
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,11 @@
|
||||
from praisonaiagents import AutoAgents
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
agents = AutoAgents(
|
||||
instructions="Search for information about AI Agents",
|
||||
tools=[duckduckgo],
|
||||
process="sequential",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
agents.start()
|
||||
@@ -0,0 +1,50 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
import json
|
||||
from e2b_code_interpreter import Sandbox
|
||||
|
||||
def code_interpreter(code: str):
|
||||
"""
|
||||
A function to demonstrate running Python code dynamically using e2b_code_interpreter.
|
||||
"""
|
||||
print(f"\n{'='*50}\n> Running following AI-generated code:\n{code}\n{'='*50}")
|
||||
exec_result = Sandbox().run_code(code)
|
||||
if exec_result.error:
|
||||
print("[Code Interpreter error]", exec_result.error)
|
||||
return {"error": str(exec_result.error)}
|
||||
else:
|
||||
results = []
|
||||
for result in exec_result.results:
|
||||
if hasattr(result, '__iter__'):
|
||||
results.extend(list(result))
|
||||
else:
|
||||
results.append(str(result))
|
||||
logs = {"stdout": list(exec_result.logs.stdout), "stderr": list(exec_result.logs.stderr)}
|
||||
return json.dumps({"results": results, "logs": logs})
|
||||
|
||||
code_agent = Agent(
|
||||
name="code_agent",
|
||||
llm="gpt-4o-mini",
|
||||
backstory="Expert in writing Python scripts",
|
||||
self_reflect=False
|
||||
)
|
||||
execution_agent = Agent(
|
||||
name="execution_agent",
|
||||
llm="gpt-4o-mini",
|
||||
backstory="Expert in executing Python scripts",
|
||||
self_reflect=False,
|
||||
tools=[code_interpreter]
|
||||
)
|
||||
|
||||
code_agent_task = Task(
|
||||
description="Write a simple Python script to print 'Hello, World!'",
|
||||
expected_output="A Python script that prints 'Hello, World!'",
|
||||
agent=code_agent
|
||||
)
|
||||
execution_agent_task = Task(
|
||||
description="Execute the Python script",
|
||||
expected_output="The output of the Python script",
|
||||
agent=execution_agent
|
||||
)
|
||||
|
||||
agents = PraisonAIAgents(agents=[code_agent, execution_agent], tasks=[code_agent_task, execution_agent_task])
|
||||
agents.start()
|
||||
@@ -0,0 +1,204 @@
|
||||
from praisonaiagents import (
|
||||
Agent,
|
||||
Task,
|
||||
PraisonAIAgents,
|
||||
error_logs,
|
||||
register_display_callback,
|
||||
sync_display_callbacks,
|
||||
async_display_callbacks
|
||||
)
|
||||
from duckduckgo_search import DDGS
|
||||
from rich.console import Console
|
||||
import json
|
||||
from datetime import datetime
|
||||
import logging
|
||||
|
||||
# Setup logging
|
||||
logging.basicConfig(
|
||||
filename='ai_interactions.log',
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
|
||||
# Callback functions for different display types
|
||||
def interaction_callback(message=None, response=None, markdown=None, generation_time=None):
|
||||
"""Callback for display_interaction"""
|
||||
logging.info(f"""
|
||||
=== INTERACTION ===
|
||||
Time: {datetime.now()}
|
||||
Generation Time: {generation_time}s
|
||||
Message: {message}
|
||||
Response: {response}
|
||||
Markdown: {markdown}
|
||||
""")
|
||||
|
||||
def error_callback(message=None):
|
||||
"""Callback for display_error"""
|
||||
logging.error(f"""
|
||||
=== ERROR ===
|
||||
Time: {datetime.now()}
|
||||
Message: {message}
|
||||
""")
|
||||
|
||||
def tool_call_callback(message=None):
|
||||
"""Callback for display_tool_call"""
|
||||
logging.info(f"""
|
||||
=== TOOL CALL ===
|
||||
Time: {datetime.now()}
|
||||
Message: {message}
|
||||
""")
|
||||
|
||||
def instruction_callback(message=None):
|
||||
"""Callback for display_instruction"""
|
||||
logging.info(f"""
|
||||
=== INSTRUCTION ===
|
||||
Time: {datetime.now()}
|
||||
Message: {message}
|
||||
""")
|
||||
|
||||
def self_reflection_callback(message=None):
|
||||
"""Callback for display_self_reflection"""
|
||||
logging.info(f"""
|
||||
=== SELF REFLECTION ===
|
||||
Time: {datetime.now()}
|
||||
Message: {message}
|
||||
""")
|
||||
|
||||
def generating_callback(content=None, elapsed_time=None):
|
||||
"""Callback for display_generating"""
|
||||
logging.info(f"""
|
||||
=== GENERATING ===
|
||||
Time: {datetime.now()}
|
||||
Content: {content}
|
||||
Elapsed Time: {elapsed_time}
|
||||
""")
|
||||
|
||||
# Register all callbacks
|
||||
register_display_callback('interaction', interaction_callback)
|
||||
register_display_callback('error', error_callback)
|
||||
register_display_callback('tool_call', tool_call_callback)
|
||||
register_display_callback('instruction', instruction_callback)
|
||||
register_display_callback('self_reflection', self_reflection_callback)
|
||||
# register_display_callback('generating', generating_callback)
|
||||
|
||||
def task_callback(output):
|
||||
"""Callback for task completion"""
|
||||
logging.info(f"""
|
||||
=== TASK COMPLETED ===
|
||||
Time: {datetime.now()}
|
||||
Description: {output.description}
|
||||
Agent: {output.agent}
|
||||
Output: {output.raw[:200]}...
|
||||
""")
|
||||
|
||||
def internet_search_tool(query) -> list:
|
||||
"""
|
||||
Perform a search using DuckDuckGo.
|
||||
|
||||
Args:
|
||||
query (str): The search query.
|
||||
|
||||
Returns:
|
||||
list: A list of search result titles and URLs.
|
||||
"""
|
||||
try:
|
||||
results = []
|
||||
ddgs = DDGS()
|
||||
for result in ddgs.text(keywords=query, max_results=10):
|
||||
results.append({
|
||||
"title": result.get("title", ""),
|
||||
"url": result.get("href", ""),
|
||||
"snippet": result.get("body", "")
|
||||
})
|
||||
return results
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error during DuckDuckGo search: {e}")
|
||||
return []
|
||||
|
||||
def main():
|
||||
# Create agents
|
||||
researcher = Agent(
|
||||
name="Researcher",
|
||||
role="Senior Research Analyst",
|
||||
goal="Uncover cutting-edge developments in AI and data science",
|
||||
backstory="""You are an expert at a technology research group,
|
||||
skilled in identifying trends and analyzing complex data.""",
|
||||
verbose=True,
|
||||
allow_delegation=False,
|
||||
tools=[internet_search_tool],
|
||||
llm="gpt-4o",
|
||||
markdown=True,
|
||||
reflect_llm="gpt-4o",
|
||||
min_reflect=2,
|
||||
max_reflect=4
|
||||
)
|
||||
|
||||
writer = Agent(
|
||||
name="Writer",
|
||||
role="Tech Content Strategist",
|
||||
goal="Craft compelling content on tech advancements",
|
||||
backstory="""You are a content strategist known for
|
||||
making complex tech topics interesting and easy to understand.""",
|
||||
verbose=True,
|
||||
allow_delegation=True,
|
||||
llm="gpt-4o",
|
||||
tools=[],
|
||||
markdown=True
|
||||
)
|
||||
|
||||
# Create tasks with callbacks
|
||||
task1 = Task(
|
||||
name="research_task",
|
||||
description="""Analyze 2024's AI advancements.
|
||||
Find major trends, new technologies, and their effects.""",
|
||||
expected_output="""A detailed report on 2024 AI advancements""",
|
||||
agent=researcher,
|
||||
tools=[internet_search_tool],
|
||||
callback=task_callback
|
||||
)
|
||||
|
||||
task2 = Task(
|
||||
name="writing_task",
|
||||
description="""Create a blog post about major AI advancements using the insights you have.
|
||||
Make it interesting, clear, and suited for tech enthusiasts.
|
||||
It should be at least 4 paragraphs long.""",
|
||||
expected_output="A blog post of at least 4 paragraphs",
|
||||
agent=writer,
|
||||
context=[task1],
|
||||
callback=task_callback,
|
||||
tools=[]
|
||||
)
|
||||
|
||||
task3 = Task(
|
||||
name="json_task",
|
||||
description="""Create a json object with a title of "My Task" and content of "My content".""",
|
||||
expected_output="""JSON output with title and content""",
|
||||
agent=researcher,
|
||||
callback=task_callback
|
||||
)
|
||||
|
||||
task4 = Task(
|
||||
name="save_output_task",
|
||||
description="""Save the AI blog post to a file""",
|
||||
expected_output="""File saved successfully""",
|
||||
agent=writer,
|
||||
context=[task2],
|
||||
output_file='test.txt',
|
||||
create_directory=True,
|
||||
callback=task_callback
|
||||
)
|
||||
|
||||
# Create and run agents manager
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher, writer],
|
||||
tasks=[task1, task2, task3, task4],
|
||||
verbose=True,
|
||||
process="sequential",
|
||||
manager_llm="gpt-4o"
|
||||
)
|
||||
|
||||
agents.start()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,151 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from typing import List, Dict, Union
|
||||
from duckduckgo_search import DDGS
|
||||
from langchain_community.tools import YouTubeSearchTool
|
||||
from langchain_community.utilities import WikipediaAPIWrapper
|
||||
|
||||
# 1. Tool
|
||||
def internet_search_tool(query: str) -> List[Dict]:
|
||||
"""
|
||||
Perform a search using DuckDuckGo.
|
||||
|
||||
Args:
|
||||
query (str): The search query.
|
||||
|
||||
Returns:
|
||||
list: A list of search result titles, URLs, and snippets.
|
||||
"""
|
||||
try:
|
||||
results = []
|
||||
ddgs = DDGS()
|
||||
for result in ddgs.text(keywords=query, max_results=10):
|
||||
results.append({
|
||||
"title": result.get("title", ""),
|
||||
"url": result.get("href", ""),
|
||||
"snippet": result.get("body", "")
|
||||
})
|
||||
return results
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error during DuckDuckGo search: {e}")
|
||||
return []
|
||||
|
||||
def youtube_search_tool(query: str, inspect: bool = False, max_results: int = 2):
|
||||
"""
|
||||
Provide a custom wrapper around the YouTubeSearchTool.
|
||||
|
||||
Args:
|
||||
query (str): The search query for YouTube.
|
||||
inspect (bool): If True, returns tool inspection info instead of search results.
|
||||
max_results (int): Maximum number of results to return (default: 2).
|
||||
Returns:
|
||||
Union[List[str], dict]: List of YouTube video URLs or tool inspection info.
|
||||
"""
|
||||
yt = YouTubeSearchTool()
|
||||
|
||||
if inspect:
|
||||
inspection_info = {
|
||||
"type": type(yt),
|
||||
"attributes": [attr for attr in dir(yt) if not attr.startswith('_')],
|
||||
"methods": {
|
||||
"run": getattr(yt, 'run', None),
|
||||
"arun": getattr(yt, 'arun', None)
|
||||
},
|
||||
"properties": {
|
||||
"name": getattr(yt, 'name', 'youtube_search'),
|
||||
"description": getattr(yt, 'description', 'Search YouTube videos'),
|
||||
"return_direct": getattr(yt, 'return_direct', False)
|
||||
}
|
||||
}
|
||||
return inspection_info
|
||||
|
||||
# Format query with max_results
|
||||
formatted_query = f"{query}, {max_results}"
|
||||
return yt.run(formatted_query)
|
||||
|
||||
def wikipedia_search_tool(query: str, inspect: bool = False, max_chars: int = 4000, top_k: int = 3):
|
||||
"""
|
||||
Provide a custom wrapper around langchain_community's WikipediaAPIWrapper.
|
||||
|
||||
Args:
|
||||
query (str): A search query for Wikipedia.
|
||||
inspect (bool): If True, returns tool inspection info instead of search results.
|
||||
max_chars (int): Maximum characters to return (default: 4000).
|
||||
top_k (int): Number of top results to consider (default: 3).
|
||||
Returns:
|
||||
Union[str, dict]: Summary from Wikipedia or tool inspection info if inspect=True.
|
||||
"""
|
||||
w = WikipediaAPIWrapper(
|
||||
top_k_results=top_k,
|
||||
doc_content_chars_max=max_chars,
|
||||
lang='en'
|
||||
)
|
||||
|
||||
if inspect:
|
||||
inspection_info = {
|
||||
"type": type(w),
|
||||
"attributes": [attr for attr in dir(w) if not attr.startswith('_')],
|
||||
"methods": {
|
||||
"run": getattr(w, 'run', None),
|
||||
"arun": getattr(w, 'arun', None)
|
||||
},
|
||||
"properties": {
|
||||
"name": "wikipedia",
|
||||
"description": "Search and get summaries from Wikipedia",
|
||||
"top_k": w.top_k_results,
|
||||
"lang": w.lang,
|
||||
"max_chars": w.doc_content_chars_max
|
||||
}
|
||||
}
|
||||
return inspection_info
|
||||
|
||||
try:
|
||||
result = w.run(query)
|
||||
return result
|
||||
except Exception as e:
|
||||
return f"Error searching Wikipedia: {str(e)}"
|
||||
|
||||
# 2. Agent
|
||||
data_agent = Agent(
|
||||
name="DataCollector",
|
||||
role="Search Specialist",
|
||||
goal="Perform internet searches to collect relevant information.",
|
||||
backstory="Expert in finding and organizing internet data from multiple sources.",
|
||||
tools=[internet_search_tool, youtube_search_tool, wikipedia_search_tool],
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# 3. Tasks
|
||||
collect_task = Task(
|
||||
description="Perform an internet search using the query: 'AI job trends in 2024'. Return results as a list of title, URL, and snippet.",
|
||||
expected_output="List of search results with titles, URLs, and snippets.",
|
||||
agent=data_agent,
|
||||
name="collect_data",
|
||||
is_start=True,
|
||||
next_tasks=["validate_data"]
|
||||
)
|
||||
|
||||
validate_task = Task(
|
||||
description="""Validate the collected data. Check if:
|
||||
1. At least 5 results are returned.
|
||||
2. Each result contains a title and a URL.
|
||||
Return validation_result as 'valid' or 'invalid' only no other text.""",
|
||||
expected_output="Validation result indicating if data is valid or invalid.",
|
||||
agent=data_agent,
|
||||
name="validate_data",
|
||||
task_type="decision",
|
||||
condition={
|
||||
"valid": [], # End the workflow on valid data
|
||||
"invalid": ["collect_data"] # Retry data collection on invalid data
|
||||
},
|
||||
)
|
||||
|
||||
# 4. Workflow
|
||||
agents = PraisonAIAgents(
|
||||
agents=[data_agent],
|
||||
tasks=[collect_task, validate_task],
|
||||
verbose=1,
|
||||
process="workflow"
|
||||
)
|
||||
|
||||
agents.start()
|
||||
@@ -0,0 +1,141 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents, error_logs
|
||||
from duckduckgo_search import DDGS
|
||||
|
||||
def my_callback(output):
|
||||
print(f"Callback Task output: {output}")
|
||||
|
||||
def internet_search_tool(query) -> list:
|
||||
"""
|
||||
Perform a search using DuckDuckGo.
|
||||
|
||||
Args:
|
||||
query (str): The search query.
|
||||
|
||||
Returns:
|
||||
list: A list of search result titles and URLs.
|
||||
"""
|
||||
try:
|
||||
results = []
|
||||
ddgs = DDGS()
|
||||
for result in ddgs.text(keywords=query, max_results=10):
|
||||
results.append({
|
||||
"title": result.get("title", ""),
|
||||
"url": result.get("href", ""),
|
||||
"snippet": result.get("body", "")
|
||||
})
|
||||
return results
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error during DuckDuckGo search: {e}")
|
||||
return []
|
||||
|
||||
# Create agents
|
||||
researcher = Agent(
|
||||
name="Researcher",
|
||||
role="Senior Research Analyst",
|
||||
goal="Uncover cutting-edge developments in AI and data science",
|
||||
backstory="""You are an expert at a technology research group,
|
||||
skilled in identifying trends and analyzing complex data.""",
|
||||
verbose=True,
|
||||
allow_delegation=False,
|
||||
tools=[internet_search_tool],
|
||||
llm="gpt-4o",
|
||||
markdown=True,
|
||||
reflect_llm="gpt-4o",
|
||||
min_reflect=2,
|
||||
max_reflect=4
|
||||
)
|
||||
writer = Agent(
|
||||
name="Writer",
|
||||
role="Tech Content Strategist",
|
||||
goal="Craft compelling content on tech advancements",
|
||||
backstory="""You are a content strategist known for
|
||||
making complex tech topics interesting and easy to understand.""",
|
||||
verbose=True,
|
||||
allow_delegation=True,
|
||||
llm="gpt-4o",
|
||||
tools=[],
|
||||
markdown=True
|
||||
)
|
||||
|
||||
# Create tasks
|
||||
task1 = Task(
|
||||
name="research_task",
|
||||
description="""Analyze 2024's AI advancements.
|
||||
Find major trends, new technologies, and their effects.""",
|
||||
expected_output="""A detailed report on 2024 AI advancements""",
|
||||
agent=researcher,
|
||||
tools=[internet_search_tool]
|
||||
)
|
||||
|
||||
task2 = Task(
|
||||
name="writing_task",
|
||||
description="""Create a blog post about major AI advancements using the insights you have.
|
||||
Make it interesting, clear, and suited for tech enthusiasts.
|
||||
It should be at least 4 paragraphs long.
|
||||
Also, call the get_weather tool to get the weather in Paris.""",
|
||||
expected_output="A blog post of at least 4 paragraphs, and weather in Paris",
|
||||
agent=writer,
|
||||
context=[task1],
|
||||
callback=my_callback,
|
||||
tools=[]
|
||||
)
|
||||
|
||||
task3 = Task(
|
||||
name="json_task",
|
||||
description="""Create a json object with a title of "My Task" and content of "My content".""",
|
||||
expected_output="""JSON output with title and content""",
|
||||
agent=researcher,
|
||||
)
|
||||
|
||||
task4 = Task(
|
||||
name="save_output_task",
|
||||
description="""Save the AI blog post to a file""",
|
||||
expected_output="""File saved successfully""",
|
||||
agent=writer,
|
||||
context=[task2],
|
||||
output_file='outputs/ai_blog_post.txt',
|
||||
create_directory=True
|
||||
)
|
||||
|
||||
# Create and run agents manager
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher, writer],
|
||||
tasks=[task1, task2, task3, task4],
|
||||
verbose=False,
|
||||
process="sequential", # "sequential" or "hierarchical"
|
||||
manager_llm="gpt-4o"
|
||||
)
|
||||
|
||||
result = agents.start()
|
||||
|
||||
# Print results and error summary
|
||||
print("\n=== Task Results ===")
|
||||
for task_id, task_status in result['task_status'].items():
|
||||
print(f"Task {task_id}: {task_status}")
|
||||
if task_result := result['task_results'].get(task_id):
|
||||
print(f"Output: {task_result.raw[:200]}...") # Show first 200 chars
|
||||
|
||||
# Print task details
|
||||
print("\n=== Task Details ===")
|
||||
for i in range(4):
|
||||
print(agents.get_task_details(i))
|
||||
|
||||
# Print agent details
|
||||
print("\n=== Agent Details ===")
|
||||
print(agents.get_agent_details('Researcher'))
|
||||
print(agents.get_agent_details('Writer'))
|
||||
|
||||
# Print any errors
|
||||
if error_logs:
|
||||
print("\n=== Error Summary ===")
|
||||
for err in error_logs:
|
||||
print(f"- {err}")
|
||||
if "parsing self-reflection json" in err:
|
||||
print(" Reason: The self-reflection JSON response was not valid JSON.")
|
||||
elif "Error: Task with ID" in err:
|
||||
print(" Reason: Task ID referenced does not exist.")
|
||||
elif "saving task output to file" in err:
|
||||
print(" Reason: Possible file permissions or invalid path.")
|
||||
else:
|
||||
print(" Reason not identified")
|
||||
@@ -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],
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# 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()
|
||||
@@ -0,0 +1,183 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
import logging
|
||||
import os
|
||||
|
||||
def main():
|
||||
# Initialize memory config
|
||||
memory_config = {
|
||||
"provider": "rag",
|
||||
"use_embedding": True,
|
||||
"storage": {
|
||||
"type": "sqlite",
|
||||
"path": "./.praison/memory.db"
|
||||
},
|
||||
"rag_db_path": "./.praison/chroma_db"
|
||||
}
|
||||
|
||||
# Test facts
|
||||
fact1 = "The capital city of Jujuha is Hahanu and its population is 102300"
|
||||
fact2 = "Three main ingredients in a classic proloder are eggs, sugar, and flour"
|
||||
fact3 = "The year the first Josinga was released is 2007"
|
||||
|
||||
# # Check if database exists
|
||||
# if os.path.exists("./memory.db"):
|
||||
# logger.info("Found existing memory database")
|
||||
# else:
|
||||
# logger.info("Creating new memory database")
|
||||
|
||||
# Create task config (without memory config since it's moved to PraisonAIAgents)
|
||||
task_config = {}
|
||||
|
||||
# Create agents with different roles
|
||||
researcher = Agent(
|
||||
role="Research Analyst",
|
||||
goal="Research and document key information about topics",
|
||||
backstory="Expert at analyzing and storing information in memory",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
retriever = Agent(
|
||||
role="Information Retriever",
|
||||
goal="Retrieve and verify stored information from memory",
|
||||
backstory="Specialist in searching and validating information from memory",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
# Task 1: Process the facts
|
||||
store_task = Task(
|
||||
description=f"""
|
||||
Process and analyze this information:
|
||||
1. {fact1}
|
||||
2. {fact2}
|
||||
3. {fact3}
|
||||
|
||||
Provide a clear summary of each fact.
|
||||
""",
|
||||
expected_output="""
|
||||
Clear statements summarizing each fact.
|
||||
Example format:
|
||||
1. [Summary of fact 1]
|
||||
2. [Summary of fact 2]
|
||||
3. [Summary of fact 3]
|
||||
""",
|
||||
agent=researcher
|
||||
)
|
||||
|
||||
# Task 2: Write essay about AI
|
||||
verify_task = Task(
|
||||
description="""
|
||||
write few points about AI
|
||||
""",
|
||||
expected_output="Points about AI",
|
||||
agent=retriever
|
||||
)
|
||||
|
||||
# Task 3: Query memory
|
||||
query_task = Task(
|
||||
description="""
|
||||
Using ONLY information found in memory:
|
||||
1. What is stored in memory about Hahanu?
|
||||
2. What ingredients for proloder are recorded in memory?
|
||||
3. What year is stored in memory for the Josinga release?
|
||||
|
||||
For each answer, cite the memory record you found.
|
||||
""",
|
||||
expected_output="Answers based solely on memory records with citations",
|
||||
agent=retriever
|
||||
)
|
||||
|
||||
# Task 4: Query both short-term and long-term memory
|
||||
query_both_task = Task(
|
||||
description="""
|
||||
Using ONLY information found in memory:
|
||||
1. What is stored in both short-term and long-term memory about Jujuha?
|
||||
2. What ingredients for proloder are recorded in both short-term and long-term memory?
|
||||
3. What year is stored in both short-term and long-term memory for the Josinga release?
|
||||
|
||||
For each answer, cite the memory record you found.
|
||||
""",
|
||||
expected_output="Answers based solely on memory records with citations",
|
||||
agent=retriever
|
||||
)
|
||||
|
||||
# Initialize PraisonAIAgents with memory configuration
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher, retriever],
|
||||
tasks=[store_task, verify_task, query_task, query_both_task],
|
||||
verbose=True, # Use same verbose level as memory
|
||||
memory=True,
|
||||
embedder={
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "text-embedding-3-small"
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
# agents = PraisonAIAgents(
|
||||
# agents=[researcher, retriever],
|
||||
# tasks=[store_task, verify_task, query_task, query_both_task],
|
||||
# verbose=True, # Use same verbose level as memory
|
||||
# memory=True
|
||||
# )
|
||||
|
||||
# Execute tasks
|
||||
print("\nExecuting Memory Test Tasks...")
|
||||
print("-" * 50)
|
||||
agents.start()
|
||||
|
||||
# Use shared memory for final checks
|
||||
memory = agents.shared_memory
|
||||
|
||||
# Test memory retrieval with different quality thresholds
|
||||
if memory:
|
||||
print("\nFinal Memory Check:")
|
||||
print("-" * 50)
|
||||
|
||||
queries = ["Jujuha", "proloder", "Josinga"]
|
||||
for query in queries:
|
||||
print(f"\nSearching memory for: {query}")
|
||||
|
||||
# Search in both short-term and long-term memory
|
||||
print("\nShort-term memory results:")
|
||||
stm_results = memory.search_short_term(query)
|
||||
if stm_results:
|
||||
for item in stm_results:
|
||||
print(f"Content: {item.get('content', '')[:200]}")
|
||||
if 'meta' in item:
|
||||
print(f"Metadata: {item['meta']}")
|
||||
print("-" * 20)
|
||||
else:
|
||||
print("No results found in short-term memory")
|
||||
|
||||
print("\nLong-term memory results:")
|
||||
ltm_results = memory.search_long_term(query)
|
||||
if ltm_results:
|
||||
for item in ltm_results:
|
||||
print(f"Content: {item.get('text', '')[:200]}")
|
||||
if 'metadata' in item:
|
||||
print(f"Metadata: {item['metadata']}")
|
||||
print("-" * 20)
|
||||
else:
|
||||
print("No results found in long-term memory")
|
||||
|
||||
# Also check ChromaDB if using RAG
|
||||
if memory.use_rag and hasattr(memory, "chroma_col"):
|
||||
print("\nChromaDB results:")
|
||||
try:
|
||||
all_items = memory.chroma_col.get()
|
||||
print(f"Found {len(all_items['ids'])} items in ChromaDB")
|
||||
for i in range(len(all_items['ids'])):
|
||||
print(f"ID: {all_items['ids'][i]}")
|
||||
print(f"Content: {all_items['documents'][i][:200]}")
|
||||
print(f"Metadata: {all_items['metadatas'][i]}")
|
||||
print("-" * 20)
|
||||
except Exception as e:
|
||||
print(f"Error querying ChromaDB: {e}")
|
||||
|
||||
print("-" * 30)
|
||||
else:
|
||||
print("\nNo memory available for final checks")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,63 @@
|
||||
from praisonaiagents.agents.agents import Agent, Task, PraisonAIAgents
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
# Test facts
|
||||
fact1 = "The capital city of Jujuha is Hahanu and its population is 102300"
|
||||
fact2 = "Three main ingredients in a classic proloder are eggs, sugar, and flour"
|
||||
fact3 = "The year the first Josinga was released is 2007"
|
||||
|
||||
fact_agent = Agent(
|
||||
name="Fact Agent",
|
||||
instructions="You are a fact agent, you store and retrieve facts in memory",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
research_agent = Agent(
|
||||
name="Research Agent",
|
||||
instructions="You are a research analyst, you research and document key points about topics",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
blog_agent = Agent(
|
||||
name="Blog Agent",
|
||||
instructions="You are a blog writer, you write a blog post about the research",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
fact_task = Task(
|
||||
description="Store the following facts in memory: " + fact1 + ", " + fact2 + ", " + fact3,
|
||||
agent=fact_agent
|
||||
)
|
||||
|
||||
research_task = Task(
|
||||
description="Research and document 2 key points about AI",
|
||||
agent=research_agent
|
||||
)
|
||||
|
||||
research_task2 = Task(
|
||||
description="Research and document 2 key points about AI in healthcare",
|
||||
agent=research_agent
|
||||
)
|
||||
|
||||
research_task3 = Task(
|
||||
description="Research and document 2 key points about AI in education",
|
||||
agent=research_agent
|
||||
)
|
||||
|
||||
research_task4 = Task(
|
||||
description="Research and document 2 key points about AI in finance",
|
||||
agent=research_agent
|
||||
)
|
||||
|
||||
blog_task = Task(
|
||||
description="Write a blog post about Jujuha",
|
||||
agent=blog_agent
|
||||
)
|
||||
|
||||
agents = PraisonAIAgents(
|
||||
agents=[fact_agent, research_agent, blog_agent],
|
||||
tasks=[fact_task, research_task, research_task2, research_task3, research_task4, blog_task],
|
||||
memory=True
|
||||
)
|
||||
|
||||
agents.start()
|
||||
@@ -0,0 +1,6 @@
|
||||
from praisonaiagents import Agent, Agents, Tools
|
||||
|
||||
research_agent = Agent(instructions="You are a research agent to search internet about AI 2024", tools=[Tools.internet_search])
|
||||
summarise_agent = Agent(instructions="You are a summarize agent to summarise in points")
|
||||
agents = Agents(agents=[research_agent, summarise_agent])
|
||||
agents.start()
|
||||
@@ -0,0 +1,59 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create Vision Analysis Agent
|
||||
vision_agent = Agent(
|
||||
name="VisionAnalyst",
|
||||
role="Computer Vision Specialist",
|
||||
goal="Analyze images and videos to extract meaningful information",
|
||||
backstory="""You are an expert in computer vision and image analysis.
|
||||
You excel at describing images, detecting objects, and understanding visual content.""",
|
||||
llm="gpt-4o-mini",
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# 1. Task with Image URL
|
||||
task1 = Task(
|
||||
name="analyze_landmark",
|
||||
description="Describe this famous landmark and its architectural features.",
|
||||
expected_output="Detailed description of the landmark's architecture and significance",
|
||||
agent=vision_agent,
|
||||
images=["https://upload.wikimedia.org/wikipedia/commons/b/bf/Krakow_-_Kosciol_Mariacki.jpg"]
|
||||
)
|
||||
|
||||
# 2. Task with Local Image File
|
||||
task2 = Task(
|
||||
name="analyze_local_image",
|
||||
description="What objects can you see in this image? Describe their arrangement.",
|
||||
expected_output="Detailed description of objects and their spatial relationships",
|
||||
agent=vision_agent,
|
||||
images=["image.jpg"]
|
||||
)
|
||||
|
||||
# 3. Task with Video File
|
||||
task3 = Task(
|
||||
name="analyze_video",
|
||||
description="""Watch this video and provide:
|
||||
1. A summary of the main events
|
||||
2. Key objects and people visible
|
||||
3. Any text or important information shown
|
||||
4. The overall context and setting""",
|
||||
expected_output="Comprehensive analysis of the video content",
|
||||
agent=vision_agent,
|
||||
images=["video.mp4"]
|
||||
)
|
||||
|
||||
# Create PraisonAIAgents instance
|
||||
agents = PraisonAIAgents(
|
||||
agents=[vision_agent],
|
||||
tasks=[task1, task2, task3],
|
||||
process="sequential",
|
||||
verbose=1
|
||||
)
|
||||
|
||||
# Run all tasks
|
||||
result = agents.start()
|
||||
|
||||
# Print results
|
||||
for task_id, task_result in result["task_results"].items():
|
||||
print(f"\nTask {task_id} Result:")
|
||||
print(task_result.raw)
|
||||
@@ -0,0 +1,81 @@
|
||||
from praisonaiagents.agent import Agent
|
||||
from praisonaiagents.task import Task
|
||||
from praisonaiagents.agents import PraisonAIAgents
|
||||
from typing import List, Dict
|
||||
import time
|
||||
|
||||
def get_time_check():
|
||||
current_time = int(time.time())
|
||||
result = "even" if current_time % 2 == 0 else "odd"
|
||||
print(f"Time check: {current_time} is {result}")
|
||||
return result
|
||||
|
||||
# Create agents for each step in the chain
|
||||
agent1 = Agent(
|
||||
name="Time Checker",
|
||||
role="Time checker",
|
||||
goal="Check if the time is even or odd",
|
||||
instructions="Check if the time is even or odd",
|
||||
tools=[get_time_check]
|
||||
)
|
||||
|
||||
agent2 = Agent(
|
||||
name="Advanced Analyzer",
|
||||
role="Advanced data analyzer",
|
||||
goal="Perform in-depth analysis of processed data",
|
||||
instructions="Analyze the processed data in detail"
|
||||
)
|
||||
|
||||
agent3 = Agent(
|
||||
name="Final Processor",
|
||||
role="Final data processor",
|
||||
goal="Generate final output based on analysis",
|
||||
instructions="Create final output based on analyzed data"
|
||||
)
|
||||
|
||||
# Create tasks for each step
|
||||
initial_task = Task(
|
||||
name="time_check",
|
||||
description="Getting time check and checking if it is even or odd",
|
||||
expected_output="Getting time check and checking if it is even or odd",
|
||||
agent=agent1,
|
||||
is_start=True, # Mark as the starting task
|
||||
task_type="decision", # This task will make a decision
|
||||
next_tasks=["advanced_analysis"], # Next task if condition passes
|
||||
condition={
|
||||
"even": ["advanced_analysis"], # If passes, go to advanced analysis
|
||||
"odd": "" # If fails, exit the chain
|
||||
}
|
||||
)
|
||||
|
||||
analysis_task = Task(
|
||||
name="advanced_analysis",
|
||||
description="Perform advanced analysis on the processed data",
|
||||
expected_output="Analyzed data ready for final processing",
|
||||
agent=agent2,
|
||||
next_tasks=["final_processing"]
|
||||
)
|
||||
|
||||
final_task = Task(
|
||||
name="final_processing",
|
||||
description="Generate final output",
|
||||
expected_output="Final processed result",
|
||||
agent=agent3
|
||||
)
|
||||
|
||||
# Create the workflow manager
|
||||
workflow = PraisonAIAgents(
|
||||
agents=[agent1, agent2, agent3],
|
||||
tasks=[initial_task, analysis_task, final_task],
|
||||
process="workflow", # Use workflow process type
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Run the workflow
|
||||
results = workflow.start()
|
||||
|
||||
# Print results
|
||||
print("\nWorkflow Results:")
|
||||
for task_id, result in results["task_results"].items():
|
||||
if result:
|
||||
print(f"Task {task_id}: {result.raw}")
|
||||
@@ -0,0 +1,56 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents, Tools
|
||||
from pydantic import BaseModel
|
||||
|
||||
class AnalysisReport(BaseModel):
|
||||
title: str
|
||||
findings: str
|
||||
summary: str
|
||||
|
||||
# Create a researcher agent
|
||||
researcher = Agent(
|
||||
name="AIResearcher",
|
||||
role="Technology Research Analyst",
|
||||
goal="Analyze and structure information about AI developments",
|
||||
backstory="Expert analyst specializing in AI technology trends",
|
||||
verbose=True,
|
||||
llm="gpt-4o-mini",
|
||||
tools=[Tools.internet_search],
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# Create an analyst agent
|
||||
analyst = Agent(
|
||||
name="DataAnalyst",
|
||||
role="Data Insights Specialist",
|
||||
goal="Structure and analyze research findings",
|
||||
backstory="Senior data analyst with expertise in pattern recognition",
|
||||
verbose=True,
|
||||
llm="gpt-4o-mini",
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# Define structured tasks
|
||||
research_task = Task(
|
||||
name="gather_research",
|
||||
description="Research recent AI developments in 2024",
|
||||
agent=researcher,
|
||||
expected_output="Research findings"
|
||||
)
|
||||
|
||||
analysis_task = Task(
|
||||
name="analyze_findings",
|
||||
description="Analyze research findings and create structured report. No additional text or explanation.",
|
||||
agent=analyst,
|
||||
output_json=AnalysisReport,
|
||||
expected_output="JSON object"
|
||||
)
|
||||
|
||||
# Initialize and run agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher, analyst],
|
||||
tasks=[research_task, analysis_task],
|
||||
process="sequential",
|
||||
verbose=True
|
||||
)
|
||||
result = agents.start()
|
||||
print(result)
|
||||
@@ -0,0 +1,95 @@
|
||||
from praisonaiagents import Agent
|
||||
from pydantic import BaseModel
|
||||
from typing import List, Optional
|
||||
|
||||
# Define structured output models
|
||||
class SearchResult(BaseModel):
|
||||
title: str
|
||||
url: Optional[str]
|
||||
snippet: str
|
||||
|
||||
class AnalysisReport(BaseModel):
|
||||
topic: str
|
||||
key_findings: List[str]
|
||||
search_results: List[SearchResult]
|
||||
summary: str
|
||||
confidence_score: float
|
||||
|
||||
def get_structured_analysis(query: str, verbose: bool = True) -> AnalysisReport:
|
||||
"""
|
||||
Performs a search and returns a structured analysis using an AI agent.
|
||||
|
||||
Args:
|
||||
query (str): The search query or topic to analyze
|
||||
verbose (bool): Whether to show detailed output
|
||||
|
||||
Returns:
|
||||
AnalysisReport: A structured report containing the analysis
|
||||
"""
|
||||
# Create an agent with search capabilities
|
||||
agent = Agent(
|
||||
name="StructuredAnalyst",
|
||||
role="Research Analyst",
|
||||
goal="Analyze topics and provide structured reports",
|
||||
backstory="Expert at gathering information and providing structured analysis",
|
||||
verbose=verbose,
|
||||
self_reflect=True, # Enable self-reflection for better quality
|
||||
markdown=True,
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
# Create the analysis prompt
|
||||
prompt = f"""
|
||||
Analyze the following topic: "{query}"
|
||||
|
||||
Provide a structured analysis in JSON format that matches this schema:
|
||||
{{
|
||||
"topic": "string",
|
||||
"key_findings": ["string"],
|
||||
"search_results": [
|
||||
{{
|
||||
"title": "string",
|
||||
"url": "string",
|
||||
"snippet": "string"
|
||||
}}
|
||||
],
|
||||
"summary": "string",
|
||||
"confidence_score": float (0-1)
|
||||
}}
|
||||
|
||||
Requirements:
|
||||
1. Include at least 3 key findings
|
||||
2. Include at least 2 relevant search results
|
||||
3. Provide a comprehensive summary
|
||||
4. Set confidence score based on quality of sources (0-1)
|
||||
|
||||
Return ONLY the JSON object, no other text.
|
||||
"""
|
||||
|
||||
# Get structured response from agent
|
||||
response = agent.chat(
|
||||
prompt=prompt,
|
||||
output_json=AnalysisReport # This ensures response matches our model
|
||||
)
|
||||
|
||||
return AnalysisReport.model_validate_json(response)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
analysis = get_structured_analysis("Latest developments in AI agents and autonomous systems")
|
||||
print(analysis)
|
||||
# Print the structured results
|
||||
print("\n=== Structured Analysis Report ===")
|
||||
print(f"Topic: {analysis.topic}")
|
||||
print("\nKey Findings:")
|
||||
for i, finding in enumerate(analysis.key_findings, 1):
|
||||
print(f"{i}. {finding}")
|
||||
|
||||
print("\nSearch Results:")
|
||||
for result in analysis.search_results:
|
||||
print(f"\nTitle: {result.title}")
|
||||
print(f"URL: {result.url}")
|
||||
print(f"Snippet: {result.snippet}")
|
||||
|
||||
print(f"\nSummary: {analysis.summary}")
|
||||
print(f"Confidence Score: {analysis.confidence_score:.2f}")
|
||||
@@ -0,0 +1,30 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from praisonaiagents.tools import get_article, get_news_sources, get_articles_from_source, get_trending_topics
|
||||
|
||||
# Create Wikipedia agent
|
||||
news_agent = Agent(
|
||||
name="NewsAgent",
|
||||
role="News Analyst",
|
||||
goal="Collect and analyze news articles from various sources.",
|
||||
backstory="Expert in news gathering and content analysis.",
|
||||
tools=[get_article, get_news_sources, get_articles_from_source, get_trending_topics],
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
|
||||
# Define research task
|
||||
news_task = Task(
|
||||
description="Analyze news articles about 'AI developments' from major tech news sources.",
|
||||
expected_output="Summary of key AI developments with source articles.",
|
||||
agent=news_agent,
|
||||
name="ai_news"
|
||||
)
|
||||
|
||||
|
||||
# Run agent
|
||||
agents = PraisonAIAgents(
|
||||
agents=[news_agent],
|
||||
tasks=[news_task],
|
||||
process="sequential"
|
||||
)
|
||||
agents.start()
|
||||
@@ -27,7 +27,7 @@ def internet_search_tool(query: str) -> List[Dict]:
|
||||
except Exception as e:
|
||||
print(f"Error during DuckDuckGo search: {e}")
|
||||
return []
|
||||
|
||||
|
||||
# 2. Agent
|
||||
data_agent = Agent(
|
||||
name="DataCollector",
|
||||
@@ -63,7 +63,7 @@ validate_task = Task(
|
||||
},
|
||||
)
|
||||
|
||||
# 4. Workflow
|
||||
# 4. AI Agents Workflow
|
||||
agents = PraisonAIAgents(
|
||||
agents=[data_agent],
|
||||
tasks=[collect_task, validate_task],
|
||||
@@ -0,0 +1,253 @@
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
import random
|
||||
from typing import List, Dict, Union
|
||||
import json
|
||||
from pydantic import BaseModel
|
||||
|
||||
# Add Pydantic models for data validation
|
||||
class Person(BaseModel):
|
||||
name: str
|
||||
age: int
|
||||
job: str
|
||||
city: str
|
||||
salary: int
|
||||
|
||||
class ProcessedPerson(Person):
|
||||
salary_category: str
|
||||
age_group: str
|
||||
processing_status: str
|
||||
|
||||
class DataList(BaseModel):
|
||||
items: List[Dict]
|
||||
|
||||
class ValidationResult(BaseModel):
|
||||
validation_result: str
|
||||
details: str = ""
|
||||
|
||||
def random_data_of_individuals() -> List[Dict]:
|
||||
"""Generate random individual data"""
|
||||
names = ["John", "Jane", "Mike", "Sarah", "David", "Emma"]
|
||||
jobs = ["Engineer", "Doctor", "Teacher", "Artist", "Developer"]
|
||||
cities = ["New York", "London", "Tokyo", "Paris", "Berlin"]
|
||||
|
||||
data = []
|
||||
for _ in range(random.randint(3, 7)):
|
||||
person = {
|
||||
"name": random.choice(names),
|
||||
"age": random.randint(25, 65),
|
||||
"job": random.choice(jobs),
|
||||
"city": random.choice(cities),
|
||||
"salary": random.randint(30000, 120000)
|
||||
}
|
||||
data.append(person)
|
||||
return data
|
||||
|
||||
def process_data_of_individuals(data: Union[List[Dict], Dict, str]) -> Dict:
|
||||
"""Process individual data by adding categories and analysis"""
|
||||
try:
|
||||
print("\n[DEBUG] process_data_of_individuals input:", data)
|
||||
print("[DEBUG] Current workflow state:")
|
||||
print("- total_records:", workflow.get_state("total_records"))
|
||||
print("- current_index:", workflow.get_state("current_index"))
|
||||
print("- remaining:", workflow.get_state("remaining"))
|
||||
|
||||
# Get the items list from the collect_task result
|
||||
collect_result = None
|
||||
for task in workflow.tasks.values():
|
||||
if task.name == "collect_data" and task.result:
|
||||
try:
|
||||
collect_data = json.loads(task.result.raw)
|
||||
collect_result = collect_data.get("items", [])
|
||||
print("[DEBUG] Found collect_data items:", len(collect_result))
|
||||
except:
|
||||
print("[DEBUG] Failed to parse collect_data result")
|
||||
|
||||
# Handle string input by trying to parse it as JSON
|
||||
if isinstance(data, str):
|
||||
if ":" in data and not data.strip().startswith("{"):
|
||||
# Convert string format to dictionary
|
||||
pairs = [pair.strip() for pair in data.split(",")]
|
||||
data_dict = {}
|
||||
for pair in pairs:
|
||||
key, value = pair.split(":")
|
||||
key = key.strip().lower()
|
||||
value = value.strip()
|
||||
if key == "age" or key == "salary":
|
||||
value = int(value)
|
||||
data_dict[key] = value
|
||||
data = data_dict
|
||||
else:
|
||||
data = json.loads(data)
|
||||
print("[DEBUG] Parsed data:", data)
|
||||
|
||||
# Handle single record
|
||||
if isinstance(data, dict):
|
||||
person = data
|
||||
# Initialize total records if not set
|
||||
total_records = workflow.get_state("total_records")
|
||||
if total_records is None and collect_result:
|
||||
total_records = len(collect_result)
|
||||
workflow.set_state("total_records", total_records)
|
||||
print(f"[DEBUG] Initialized total_records to {total_records}")
|
||||
|
||||
current_index = workflow.get_state("current_index", 0)
|
||||
total_records = total_records or 1
|
||||
remaining = total_records - (current_index + 1)
|
||||
workflow.set_state("remaining", remaining)
|
||||
print(f"[DEBUG] Processing record {current_index + 1}/{total_records}")
|
||||
|
||||
elif isinstance(data, list):
|
||||
if len(data) == 0:
|
||||
raise ValueError("Empty data list")
|
||||
person = data[0]
|
||||
workflow.set_state("total_records", len(data))
|
||||
workflow.set_state("current_index", 0)
|
||||
workflow.set_state("remaining", len(data) - 1)
|
||||
print(f"[DEBUG] First record from list of {len(data)} items")
|
||||
else:
|
||||
raise ValueError("Input must be a dictionary or list with at least one record")
|
||||
|
||||
processed_person = person.copy()
|
||||
|
||||
# Add salary category
|
||||
salary = person.get("salary", 0)
|
||||
if salary < 50000:
|
||||
processed_person["salary_category"] = "entry"
|
||||
elif salary < 90000:
|
||||
processed_person["salary_category"] = "mid"
|
||||
else:
|
||||
processed_person["salary_category"] = "senior"
|
||||
|
||||
# Add age group
|
||||
age = person.get("age", 0)
|
||||
if age < 35:
|
||||
processed_person["age_group"] = "young"
|
||||
elif age < 50:
|
||||
processed_person["age_group"] = "mid"
|
||||
else:
|
||||
processed_person["age_group"] = "senior"
|
||||
|
||||
# Add processing status using workflow state
|
||||
remaining = workflow.get_state("remaining", 0)
|
||||
current_index = workflow.get_state("current_index", 0)
|
||||
total_records = workflow.get_state("total_records", 1)
|
||||
|
||||
# Update current index for next iteration
|
||||
workflow.set_state("current_index", current_index + 1)
|
||||
|
||||
print(f"[DEBUG] Status check - remaining: {remaining}, current_index: {current_index}, total_records: {total_records}")
|
||||
|
||||
if remaining <= 0 and current_index >= total_records - 1:
|
||||
print("[DEBUG] Setting status to 'all records processed'")
|
||||
processed_person["processing_status"] = "all records processed"
|
||||
else:
|
||||
print(f"[DEBUG] More records to process. Remaining: {remaining}")
|
||||
processed_person["processing_status"] = f"more records to process ({remaining} remaining)"
|
||||
|
||||
print("[DEBUG] Final processed person:", processed_person)
|
||||
return processed_person
|
||||
|
||||
except Exception as e:
|
||||
print(f"[DEBUG] Error processing data: {str(e)}")
|
||||
return {"error": str(e), "processing_status": "error occurred"}
|
||||
|
||||
# Create agents
|
||||
data_agent = Agent(
|
||||
name="DataCollector",
|
||||
role="Data collection specialist",
|
||||
goal="Collect and validate data about individuals",
|
||||
backstory="Expert in gathering and validating demographic data",
|
||||
tools=[random_data_of_individuals],
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
process_agent = Agent(
|
||||
name="DataProcessor",
|
||||
role="Data processor",
|
||||
goal="Process and categorize individual data",
|
||||
backstory="Expert in data analysis and categorization",
|
||||
tools=[process_data_of_individuals],
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# Modify tasks to use Pydantic models
|
||||
collect_task = Task(
|
||||
description="Collect random individual data using the random_data_of_individuals tool. Return as a JSON object with 'items' array.",
|
||||
expected_output="List of individual records with basic information",
|
||||
agent=data_agent,
|
||||
name="collect_data",
|
||||
tools=[random_data_of_individuals],
|
||||
is_start=True,
|
||||
next_tasks=["validate_data"],
|
||||
output_json=DataList
|
||||
)
|
||||
|
||||
validate_task = Task(
|
||||
description="""Validate the collected data. Check if:
|
||||
1. All required fields are present (name, age, job, city, salary)
|
||||
2. Age is between 25 and 65
|
||||
3. Salary is between 30000 and 120000
|
||||
Return validation_result as 'valid' or 'invalid' with optional details.""",
|
||||
expected_output="Validation result indicating if data is valid or invalid",
|
||||
agent=data_agent,
|
||||
name="validate_data",
|
||||
task_type="decision",
|
||||
condition={
|
||||
"valid": ["process_data"],
|
||||
"invalid": ["collect_data"]
|
||||
},
|
||||
output_json=ValidationResult
|
||||
)
|
||||
|
||||
process_task = Task(
|
||||
description="""Process one record at a time from the input data.
|
||||
Current progress will be shown in Loop Status.
|
||||
|
||||
For the current record:
|
||||
1. Use process_data_of_individuals tool to add categories
|
||||
2. Return the processed record with remaining count
|
||||
|
||||
Current remaining: {remaining}
|
||||
Current item: {current_item}
|
||||
|
||||
Process this record and indicate if more records remain.""",
|
||||
expected_output="Processed record with categories and status",
|
||||
agent=process_agent,
|
||||
name="process_data",
|
||||
tools=[process_data_of_individuals],
|
||||
task_type="loop",
|
||||
condition={
|
||||
"more records to process": ["process_data"],
|
||||
"all records processed": []
|
||||
},
|
||||
context=[collect_task],
|
||||
output_json=ProcessedPerson
|
||||
)
|
||||
|
||||
# Create PraisonAIAgents instance with workflow process
|
||||
workflow = PraisonAIAgents(
|
||||
agents=[data_agent, process_agent],
|
||||
tasks=[collect_task, validate_task, process_task],
|
||||
verbose=1,
|
||||
process="workflow"
|
||||
)
|
||||
|
||||
# Run the workflow
|
||||
result = workflow.start()
|
||||
|
||||
# Print results
|
||||
print("\nWorkflow Results:")
|
||||
print("----------------")
|
||||
for task_id, task in workflow.tasks.items():
|
||||
print(f"\nTask: {task.name}")
|
||||
print(f"Status: {task.status}")
|
||||
if task.result:
|
||||
print("Output:")
|
||||
try:
|
||||
# Try to format as pretty JSON
|
||||
import json
|
||||
output = json.loads(task.result.raw)
|
||||
print(json.dumps(output, indent=2))
|
||||
except:
|
||||
# If not JSON, print raw output
|
||||
print(task.result.raw[:500] + "..." if len(task.result.raw) > 500 else task.result.raw)
|
||||
@@ -110,7 +110,7 @@ Loads environment variables from .env file or system and sets them.</p>
|
||||
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.29 gunicorn markdown\n")
|
||||
file.write("RUN pip install flask praisonai==2.0.42 gunicorn markdown\n")
|
||||
file.write("EXPOSE 8080\n")
|
||||
file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
|
||||
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
---
|
||||
title: "AutoAgents Module"
|
||||
description: "Documentation for the praisonaiagents.agents.autoagents module"
|
||||
icon: "robot"
|
||||
---
|
||||
|
||||
# Module praisonaiagents.agents.autoagents
|
||||
|
||||
The AutoAgents module provides automatic creation and management of AI agents and tasks based on high-level instructions.
|
||||
|
||||
## Classes
|
||||
|
||||
### AutoAgents
|
||||
The main class for automatically creating and managing AI agents and tasks.
|
||||
|
||||
#### Parameters
|
||||
- `instructions: str` - High-level task description for the agents
|
||||
- `tools: Optional[List[Any]] = None` - List of tools available to the agents
|
||||
- `verbose: bool = False` - Enable detailed logging
|
||||
- `process: str = "sequential"` - Process type (sequential or hierarchical)
|
||||
- `manager_llm: Optional[str] = None` - Language model for manager agent
|
||||
- `max_retries: int = 5` - Maximum retry attempts
|
||||
- `completion_checker: Optional[Any] = None` - Custom completion checker
|
||||
- `allow_code_execution: bool = False` - Allow code execution
|
||||
- `memory: bool = True` - Enable agent memory
|
||||
- `markdown: bool = True` - Enable markdown formatting
|
||||
- `self_reflect: bool = False` - Enable agent self-reflection
|
||||
- `max_reflect: int = 3` - Maximum reflection iterations
|
||||
- `min_reflect: int = 1` - Minimum reflection iterations
|
||||
- `llm: Optional[str] = None` - Language model for agents
|
||||
- `function_calling_llm: Optional[str] = None` - Language model for tool calling
|
||||
- `respect_context_window: bool = True` - Respect model context window
|
||||
- `code_execution_mode: str = "safe"` - Code execution mode (safe/unsafe)
|
||||
- `embedder_config: Optional[Dict[str, Any]] = None` - Embedder configuration
|
||||
- `knowledge_sources: Optional[List[Any]] = None` - Knowledge sources
|
||||
- `use_system_prompt: bool = True` - Use system prompts
|
||||
- `cache: bool = True` - Enable caching
|
||||
- `allow_delegation: bool = False` - Allow task delegation
|
||||
- `step_callback: Optional[Any] = None` - Callback for each step
|
||||
- `system_template: Optional[str] = None` - Custom system template
|
||||
- `prompt_template: Optional[str] = None` - Custom prompt template
|
||||
- `response_template: Optional[str] = None` - Custom response template
|
||||
- `max_rpm: Optional[int] = None` - Maximum requests per minute
|
||||
- `max_execution_time: Optional[int] = None` - Maximum execution time
|
||||
- `max_iter: int = 20` - Maximum iterations
|
||||
- `reflect_llm: Optional[str] = None` - Language model for reflection
|
||||
- `max_agents: int = 3` - Maximum number of agents to create
|
||||
|
||||
#### Methods
|
||||
|
||||
##### start()
|
||||
Start the agents synchronously.
|
||||
|
||||
```python
|
||||
def start(self):
|
||||
"""
|
||||
Creates tasks based on the instructions, then starts execution.
|
||||
Returns the task status and results dictionary.
|
||||
"""
|
||||
return super().start()
|
||||
```
|
||||
|
||||
##### astart()
|
||||
Start the agents asynchronously.
|
||||
|
||||
```python
|
||||
async def astart(self):
|
||||
"""
|
||||
Async version of start() method.
|
||||
Creates tasks based on the instructions, then starts execution.
|
||||
Returns the task status and results dictionary.
|
||||
"""
|
||||
return await super().astart()
|
||||
```
|
||||
|
||||
#### Internal Methods
|
||||
|
||||
##### _generate_config()
|
||||
Generate the configuration for agents and tasks.
|
||||
|
||||
```python
|
||||
def _generate_config(self) -> AutoAgentsConfig:
|
||||
"""
|
||||
Generate the configuration for agents and tasks based on instructions.
|
||||
Returns AutoAgentsConfig object containing agent and task configurations.
|
||||
"""
|
||||
```
|
||||
|
||||
##### _create_agents_and_tasks()
|
||||
Create agents and tasks from configuration.
|
||||
|
||||
```python
|
||||
def _create_agents_and_tasks(self, config: AutoAgentsConfig) -> tuple[List[Agent], List[Task]]:
|
||||
"""
|
||||
Create agents and tasks based on the generated configuration.
|
||||
Returns tuple of (agents, tasks).
|
||||
"""
|
||||
```
|
||||
|
||||
##### _assign_tools_to_agent()
|
||||
Assign appropriate tools to an agent.
|
||||
|
||||
```python
|
||||
def _assign_tools_to_agent(self, agent_config: AgentConfig) -> List[Any]:
|
||||
"""
|
||||
Assign tools to an agent based on its role and tasks.
|
||||
Returns list of assigned tools.
|
||||
"""
|
||||
```
|
||||
|
||||
## Pydantic Models
|
||||
|
||||
### TaskConfig
|
||||
Configuration for a task.
|
||||
|
||||
#### Attributes
|
||||
- `name: str` - Task name
|
||||
- `description: str` - Task description
|
||||
- `expected_output: str` - Expected output description
|
||||
- `tools: List[str]` - Required tools for the task
|
||||
|
||||
### AgentConfig
|
||||
Configuration for an agent.
|
||||
|
||||
#### Attributes
|
||||
- `name: str` - Agent name
|
||||
- `role: str` - Agent role
|
||||
- `goal: str` - Agent goal
|
||||
- `backstory: str` - Agent backstory
|
||||
- `tools: List[str]` - Required tools
|
||||
- `tasks: List[TaskConfig]` - Tasks assigned to the agent
|
||||
|
||||
### AutoAgentsConfig
|
||||
Overall configuration for AutoAgents.
|
||||
|
||||
#### Attributes
|
||||
- `main_instruction: str` - Main instruction for the agents
|
||||
- `process_type: str` - Process type (sequential/hierarchical)
|
||||
- `agents: List[AgentConfig]` - List of agent configurations
|
||||
|
||||
## Example Usage
|
||||
|
||||
### Basic Usage
|
||||
```python
|
||||
from praisonaiagents import AutoAgents
|
||||
from praisonaiagents.tools import SerperDevTool
|
||||
|
||||
agents = AutoAgents(
|
||||
instructions="Research recent AI developments",
|
||||
tools=[SerperDevTool()],
|
||||
verbose=True
|
||||
)
|
||||
result = agents.start()
|
||||
```
|
||||
|
||||
### Async Usage
|
||||
```python
|
||||
async def main():
|
||||
agents = AutoAgents(
|
||||
instructions="Research recent AI developments",
|
||||
tools=[SerperDevTool()],
|
||||
process="hierarchical"
|
||||
)
|
||||
result = await agents.astart()
|
||||
|
||||
import asyncio
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
### Advanced Configuration
|
||||
```python
|
||||
agents = AutoAgents(
|
||||
instructions="Complex research task",
|
||||
tools=[SerperDevTool()],
|
||||
max_agents=5,
|
||||
process="hierarchical",
|
||||
manager_llm="gpt-4o",
|
||||
memory=True,
|
||||
allow_delegation=True,
|
||||
max_execution_time=600,
|
||||
self_reflect=True
|
||||
)
|
||||
```
|
||||
|
||||
<Note>
|
||||
For optimal results, provide clear instructions and appropriate tools for your use case.
|
||||
</Note>
|
||||
@@ -1,69 +0,0 @@
|
||||
---
|
||||
title: Installation
|
||||
description: Set up PraisonAI in your development environment
|
||||
icon: download
|
||||
---
|
||||
|
||||
<Note>
|
||||
**Requirements**
|
||||
|
||||
- Python 3.10 or higher
|
||||
- pip package manager
|
||||
- Virtual environment (recommended)
|
||||
</Note>
|
||||
|
||||
# Installing PraisonAI
|
||||
|
||||
Follow these steps to set up PraisonAI in your development environment.
|
||||
|
||||
<Steps>
|
||||
<Step title="Create Virtual Environment (Optional)">
|
||||
First, create and activate a virtual environment:
|
||||
<CodeGroup>
|
||||
```bash Mac/Linux
|
||||
python -m venv praisonai-env
|
||||
source praisonai-env/bin/activate
|
||||
```
|
||||
|
||||
```bash Windows
|
||||
python -m venv praisonai-env
|
||||
.\praisonai-env\Scripts\activate
|
||||
```
|
||||
</CodeGroup>
|
||||
</Step>
|
||||
|
||||
<Step title="Install PraisonAI">
|
||||
Install the core package and tools:
|
||||
```bash Terminal
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Configure Environment">
|
||||
```bash Terminal
|
||||
export OPENAI_API_KEY=your_openai_key
|
||||
```
|
||||
Generate your OpenAI API key from [OpenAI](https://platform.openai.com/api-keys)
|
||||
You can also use other LLM providers like Anthropic, Google, etc. Please refer to the [Models](/models) for more information.
|
||||
</Step>
|
||||
|
||||
</Steps>
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
title="Quick Start Guide"
|
||||
icon="bolt"
|
||||
href="/code/quickstart"
|
||||
>
|
||||
Build your first AI agent
|
||||
</Card>
|
||||
<Card
|
||||
title="API Reference"
|
||||
icon="code"
|
||||
href="/api/praisonaiagents/index"
|
||||
>
|
||||
Explore the API documentation
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -1,188 +0,0 @@
|
||||
---
|
||||
title: "Introduction"
|
||||
description: "Welcome to PraisonAI - The Next Generation AI Agent Framework"
|
||||
icon: "book-open"
|
||||
---
|
||||
|
||||
<Note>
|
||||
PraisonAI is a powerful framework for building and deploying AI agents that can understand, reason, and execute complex tasks autonomously.
|
||||
</Note>
|
||||
|
||||
# What is PraisonAI?
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
%% Define the main flow
|
||||
Start([▶ Start]) --> Agent1
|
||||
Agent1 --> Process[⚙ Process]
|
||||
Process --> Agent2
|
||||
Agent2 --> Output([✓ Output])
|
||||
Process -.-> Agent1
|
||||
|
||||
%% Styling for main elements
|
||||
style Start fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
style Output fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
style Process fill:#5C80BC,stroke:#7C90A0,color:#fff
|
||||
|
||||
%% Define subgraphs for agents and their tasks
|
||||
subgraph Agent1[" "]
|
||||
Task1[📋 Task]
|
||||
AgentIcon1[🤖 AI Agent]
|
||||
Tools1[🔧 Tools]
|
||||
|
||||
Task1 --- AgentIcon1
|
||||
AgentIcon1 --- Tools1
|
||||
|
||||
style Task1 fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
style AgentIcon1 fill:#5C80BC,stroke:#7C90A0,color:#fff
|
||||
style Tools1 fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
end
|
||||
|
||||
subgraph Agent2[" "]
|
||||
Task2[📋 Task]
|
||||
AgentIcon2[🤖 AI Agent]
|
||||
Tools2[🔧 Tools]
|
||||
|
||||
Task2 --- AgentIcon2
|
||||
AgentIcon2 --- Tools2
|
||||
|
||||
style Task2 fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
style AgentIcon2 fill:#5C80BC,stroke:#7C90A0,color:#fff
|
||||
style Tools2 fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
end
|
||||
|
||||
%% Style for agent containers
|
||||
style Agent1 fill:#1B1F3B,stroke:#7C90A0,color:#fff
|
||||
style Agent2 fill:#1B1F3B,stroke:#7C90A0,color:#fff
|
||||
|
||||
%% Global styles
|
||||
classDef default fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
linkStyle default stroke:#7C90A0,stroke-width:2px
|
||||
```
|
||||
|
||||
## Core Components
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Agents" icon="user-robot">
|
||||
Autonomous AI entities that can understand context and execute tasks
|
||||
</Card>
|
||||
<Card title="Tasks" icon="list-check">
|
||||
Units of work that agents can execute independently or collaboratively
|
||||
</Card>
|
||||
<Card title="Process" icon="diagram-project">
|
||||
Workflow management for coordinating agent activities
|
||||
</Card>
|
||||
<Card title="Tools" icon="toolbox">
|
||||
Extensible capabilities that agents can leverage
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Key Features
|
||||
|
||||
<Steps>
|
||||
<Step title="Autonomous Agents">
|
||||
Create intelligent agents that can:
|
||||
- Understand natural language instructions
|
||||
- Make decisions based on context
|
||||
- Execute complex tasks autonomously
|
||||
</Step>
|
||||
<Step title="Flexible Architecture">
|
||||
Build with:
|
||||
- Modular components
|
||||
- Extensible tools
|
||||
- Customizable workflows
|
||||
</Step>
|
||||
<Step title="Advanced Capabilities">
|
||||
Leverage:
|
||||
- Multi-agent collaboration
|
||||
- Memory and context management
|
||||
- Tool integration
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Use Cases
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Customer Service" icon="headset">
|
||||
Build intelligent support agents that can handle customer inquiries and resolve issues autonomously.
|
||||
</Card>
|
||||
<Card title="Data Analysis" icon="chart-line">
|
||||
Create agents that can process, analyze, and derive insights from complex datasets.
|
||||
</Card>
|
||||
<Card title="Content Creation" icon="pen-nib">
|
||||
Deploy agents that can generate, edit, and optimize content across various formats.
|
||||
</Card>
|
||||
<Card title="Process Automation" icon="gears">
|
||||
Automate complex workflows with intelligent agents that can coordinate and execute tasks.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Getting Started
|
||||
|
||||
<Warning>
|
||||
Before proceeding, ensure you have Python 3.9+ installed on your system.
|
||||
</Warning>
|
||||
|
||||
### Quick Setup
|
||||
|
||||
<CodeGroup>
|
||||
```bash pip
|
||||
pip install praisonai
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Basic Example
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create an agent
|
||||
researcher = Agent(
|
||||
name="Researcher",
|
||||
role="Senior Research Analyst",
|
||||
goal="Uncover cutting-edge developments in AI",
|
||||
backstory="You are an expert at a technology research group",
|
||||
verbose=True,
|
||||
llm="gpt-4o"
|
||||
)
|
||||
|
||||
# Define a task
|
||||
task = Task(
|
||||
name="research_task",
|
||||
description="Analyze 2024's AI advancements",
|
||||
expected_output="A detailed report",
|
||||
agent=researcher
|
||||
)
|
||||
|
||||
# Run the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher],
|
||||
tasks=[task],
|
||||
verbose=False
|
||||
)
|
||||
|
||||
result = agents.start()
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
title="Installation"
|
||||
icon="download"
|
||||
href="/code/installation"
|
||||
>
|
||||
Complete installation guide and setup instructions
|
||||
</Card>
|
||||
<Card
|
||||
title="Quick Start"
|
||||
icon="play"
|
||||
href="/code/quickstart"
|
||||
>
|
||||
Build your first AI agent in minutes
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Tip>
|
||||
Join our community on [Discord](https://www.youtube.com/redirect?event=channel_description&redir_token=QUFFLUhqbUpiZE00YlF1MjB1LVNIeTFxTnV6MWRRc18wZ3xBQ3Jtc0ttQVZ0aFJ4RXRDanlBQU1Vd3lHU3BBcml3bzhoek1pTmlkZkFkWjlNVDBpRkxZd1dTOWhPc20xbHJOb1NibmNYeTEydklJT0pZOVJFQW93MmJOQXU0WkJNVzNsd29SZ3FBNFVwMTFGNThNSHBWVUhjSQ&q=https%3A%2F%2Fdiscord.gg%2FnNZu5gGT59) to connect with other developers and get help!
|
||||
</Tip>
|
||||
@@ -1,195 +0,0 @@
|
||||
---
|
||||
title: Quick Start
|
||||
description: Build your first AI agent with PraisonAI
|
||||
icon: bolt
|
||||
---
|
||||
|
||||
<Steps>
|
||||
|
||||
<Step title="Install PraisonAI">
|
||||
Install the core package:
|
||||
```bash Terminal
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Configure Environment">
|
||||
```bash Terminal
|
||||
export OPENAI_API_KEY=your_openai_key
|
||||
```
|
||||
Generate your OpenAI API key from [OpenAI](https://platform.openai.com/api-keys)
|
||||
You can also use other LLM providers like Anthropic, Google, etc. Please refer to the [Models](/models) for more information.
|
||||
</Step>
|
||||
|
||||
<Step title="Create Agent">
|
||||
Create `app.py`:
|
||||
## Code Example
|
||||
|
||||
<CodeGroup>
|
||||
```python Basic
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create an agent
|
||||
researcher = Agent(
|
||||
name="Researcher",
|
||||
role="Senior Research Analyst",
|
||||
goal="Uncover cutting-edge developments in AI",
|
||||
backstory="You are an expert at a technology research group",
|
||||
verbose=True,
|
||||
llm="gpt-4o"
|
||||
)
|
||||
|
||||
# Define a task
|
||||
task = Task(
|
||||
name="research_task",
|
||||
description="Analyze 2024's AI advancements",
|
||||
expected_output="A detailed report",
|
||||
agent=researcher
|
||||
)
|
||||
|
||||
# Run the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher],
|
||||
tasks=[task],
|
||||
verbose=False
|
||||
)
|
||||
|
||||
result = agents.start()
|
||||
```
|
||||
|
||||
```python Advanced
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create multiple agents
|
||||
researcher = Agent(
|
||||
name="Researcher",
|
||||
role="Senior Research Analyst",
|
||||
goal="Uncover cutting-edge developments in AI",
|
||||
backstory="You are an expert at a technology research group",
|
||||
verbose=True,
|
||||
llm="gpt-4o",
|
||||
markdown=True
|
||||
)
|
||||
|
||||
writer = Agent(
|
||||
name="Writer",
|
||||
role="Tech Content Strategist",
|
||||
goal="Craft compelling content on tech advancements",
|
||||
backstory="You are a content strategist",
|
||||
llm="gpt-4o",
|
||||
markdown=True
|
||||
)
|
||||
|
||||
# Define multiple tasks
|
||||
task1 = Task(
|
||||
name="research_task",
|
||||
description="Analyze 2024's AI advancements",
|
||||
expected_output="A detailed report",
|
||||
agent=researcher
|
||||
)
|
||||
|
||||
task2 = Task(
|
||||
name="writing_task",
|
||||
description="Create a blog post about AI advancements",
|
||||
expected_output="A blog post",
|
||||
agent=writer
|
||||
)
|
||||
|
||||
# Run with hierarchical process
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher, writer],
|
||||
tasks=[task1, task2],
|
||||
verbose=False,
|
||||
process="hierarchical",
|
||||
manager_llm="gpt-4o"
|
||||
)
|
||||
|
||||
result = agents.start()
|
||||
```
|
||||
</CodeGroup>
|
||||
</Step>
|
||||
|
||||
<Step title="Run the Program">
|
||||
Execute your script:
|
||||
```bash Terminal
|
||||
python app.py
|
||||
```
|
||||
|
||||
You should see:
|
||||
- Agent initialization
|
||||
- Agents progress
|
||||
- Final results
|
||||
- Generated report
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Creating Custom Tool
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from duckduckgo_search import DDGS
|
||||
from typing import List, Dict
|
||||
|
||||
# 1. Tool
|
||||
def internet_search_tool(query: str) -> List[Dict]:
|
||||
"""
|
||||
Perform Internet Search
|
||||
"""
|
||||
results = []
|
||||
ddgs = DDGS()
|
||||
for result in ddgs.text(keywords=query, max_results=5):
|
||||
results.append({
|
||||
"title": result.get("title", ""),
|
||||
"url": result.get("href", ""),
|
||||
"snippet": result.get("body", "")
|
||||
})
|
||||
return results
|
||||
|
||||
# 2. Agent
|
||||
data_agent = Agent(
|
||||
name="DataCollector",
|
||||
role="Search Specialist",
|
||||
goal="Perform internet searches to collect relevant information.",
|
||||
backstory="Expert in finding and organising internet data.",
|
||||
tools=[internet_search_tool],
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# 3. Tasks
|
||||
collect_task = Task(
|
||||
description="Perform an internet search using the query: 'AI job trends in 2024'. Return results as a list of title, URL, and snippet.",
|
||||
expected_output="List of search results with titles, URLs, and snippets.",
|
||||
agent=data_agent,
|
||||
name="collect_data",
|
||||
)
|
||||
|
||||
# 4. Start Agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[data_agent],
|
||||
tasks=[collect_task],
|
||||
process="sequential"
|
||||
)
|
||||
|
||||
agents.start()
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
title="Core Concepts"
|
||||
icon="book"
|
||||
href="/concepts/agents"
|
||||
>
|
||||
Learn about agents, tasks, and processes
|
||||
</Card>
|
||||
<Card
|
||||
title="API Reference"
|
||||
icon="code"
|
||||
href="/api/praisonaiagents/index"
|
||||
>
|
||||
Explore detailed API documentation
|
||||
</Card>
|
||||
</CardGroup>
|
||||
+237
-26
@@ -105,43 +105,254 @@ graph LR
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Agent Types
|
||||
|
||||
<Steps>
|
||||
<Step title="Basic Agent">
|
||||
- Single-purpose focus
|
||||
- Direct user interaction
|
||||
- Limited tool set
|
||||
|
||||
<Step title="Install PraisonAI">
|
||||
Install the core package:
|
||||
```bash Terminal
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
<Step title="Specialized Agent">
|
||||
- Domain expertise
|
||||
- Advanced capabilities
|
||||
- Custom tools
|
||||
|
||||
<Step title="Configure Environment">
|
||||
```bash Terminal
|
||||
export OPENAI_API_KEY=your_openai_key
|
||||
```
|
||||
Generate your OpenAI API key from [OpenAI](https://platform.openai.com/api-keys)
|
||||
Use other LLM providers like Ollama, Anthropic, Groq, Google, etc. Please refer to the [Models](/models) for more information.
|
||||
</Step>
|
||||
<Step title="Collaborative Agent">
|
||||
- Team interaction
|
||||
- Task delegation
|
||||
- Shared context
|
||||
|
||||
<Step title="Create Agent">
|
||||
Create `app.py`:
|
||||
<CodeGroup>
|
||||
```python Single Agent
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create an agent
|
||||
researcher = Agent(
|
||||
name="Researcher",
|
||||
role="Senior Research Analyst",
|
||||
goal="Uncover cutting-edge developments in AI",
|
||||
backstory="You are an expert at a technology research group",
|
||||
verbose=True,
|
||||
llm="gpt-4o"
|
||||
)
|
||||
|
||||
# Define a task
|
||||
task = Task(
|
||||
name="research_task",
|
||||
description="Analyze 2024's AI advancements",
|
||||
expected_output="A detailed report",
|
||||
agent=researcher
|
||||
)
|
||||
|
||||
# Run the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher],
|
||||
tasks=[task],
|
||||
verbose=False
|
||||
)
|
||||
|
||||
result = agents.start()
|
||||
```
|
||||
|
||||
```python Multiple Agents
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create multiple agents
|
||||
researcher = Agent(
|
||||
name="Researcher",
|
||||
role="Senior Research Analyst",
|
||||
goal="Uncover cutting-edge developments in AI",
|
||||
backstory="You are an expert at a technology research group",
|
||||
verbose=True,
|
||||
llm="gpt-4o",
|
||||
markdown=True
|
||||
)
|
||||
|
||||
writer = Agent(
|
||||
name="Writer",
|
||||
role="Tech Content Strategist",
|
||||
goal="Craft compelling content on tech advancements",
|
||||
backstory="You are a content strategist",
|
||||
llm="gpt-4o",
|
||||
markdown=True
|
||||
)
|
||||
|
||||
# Define multiple tasks
|
||||
task1 = Task(
|
||||
name="research_task",
|
||||
description="Analyze 2024's AI advancements",
|
||||
expected_output="A detailed report",
|
||||
agent=researcher
|
||||
)
|
||||
|
||||
task2 = Task(
|
||||
name="writing_task",
|
||||
description="Create a blog post about AI advancements",
|
||||
expected_output="A blog post",
|
||||
agent=writer
|
||||
)
|
||||
|
||||
# Run with hierarchical process
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher, writer],
|
||||
tasks=[task1, task2],
|
||||
verbose=False,
|
||||
process="hierarchical",
|
||||
manager_llm="gpt-4o"
|
||||
)
|
||||
|
||||
result = agents.start()
|
||||
```
|
||||
</CodeGroup>
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Execute your script:
|
||||
```bash Terminal
|
||||
python app.py
|
||||
```
|
||||
|
||||
You should see:
|
||||
- Agent initialization
|
||||
- Agents progress
|
||||
- Final results
|
||||
- Generated report
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Agent Types
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card title="Basic Agent" icon="user" iconType="solid">
|
||||
<AccordionGroup>
|
||||
<Accordion title="Overview">
|
||||
Perfect for straightforward tasks and direct interactions
|
||||
</Accordion>
|
||||
<Accordion title="Features">
|
||||
- Single-purpose focus
|
||||
- Direct user interaction
|
||||
- Limited tool set
|
||||
- Ideal for simple tasks
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
</Card>
|
||||
|
||||
<Card title="Specialized Agent" icon="user-gear" iconType="solid">
|
||||
<AccordionGroup>
|
||||
<Accordion title="Overview">
|
||||
Experts in specific domains with advanced capabilities
|
||||
</Accordion>
|
||||
<Accordion title="Features">
|
||||
- Domain expertise
|
||||
- Advanced capabilities
|
||||
- Custom tools
|
||||
- Deep knowledge base
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
</Card>
|
||||
|
||||
<Card title="Collaborative Agent" icon="users" iconType="solid">
|
||||
<AccordionGroup>
|
||||
<Accordion title="Overview">
|
||||
Designed for team-based operations and complex workflows
|
||||
</Accordion>
|
||||
<Accordion title="Features">
|
||||
- Team interaction
|
||||
- Task delegation
|
||||
- Shared context
|
||||
- Coordinated actions
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Best Practices
|
||||
|
||||
<Warning>
|
||||
Always implement proper error handling and resource management in your agent configurations.
|
||||
</Warning>
|
||||
<Note>
|
||||
Always implement proper error handling and resource management in your agent configurations.
|
||||
</Note>
|
||||
|
||||
### Agent Design
|
||||
1. Clear role definition
|
||||
2. Specific, measurable goals
|
||||
3. Relevant tool selection
|
||||
4. Appropriate memory configuration
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Agent Design" icon="compass-drafting" iconType="solid">
|
||||
<Steps>
|
||||
<Step title="Role Definition">
|
||||
Define clear, specific roles for each agent
|
||||
</Step>
|
||||
<Step title="Goal Setting">
|
||||
Set specific, measurable goals
|
||||
</Step>
|
||||
<Step title="Tool Selection">
|
||||
Choose relevant tools for the task
|
||||
</Step>
|
||||
<Step title="Memory Setup">
|
||||
Configure appropriate memory settings
|
||||
</Step>
|
||||
</Steps>
|
||||
</Card>
|
||||
|
||||
### Agent Interaction
|
||||
1. Clear communication protocols
|
||||
2. Defined delegation rules
|
||||
3. Error handling mechanisms
|
||||
4. Resource management
|
||||
<Card title="Agent Interaction" icon="network-wired" iconType="solid">
|
||||
<Steps>
|
||||
<Step title="Communication">
|
||||
Establish clear communication protocols
|
||||
</Step>
|
||||
<Step title="Delegation">
|
||||
Define explicit delegation rules
|
||||
</Step>
|
||||
<Step title="Error Handling">
|
||||
Implement robust error handling
|
||||
</Step>
|
||||
<Step title="Resource Management">
|
||||
Set up efficient resource allocation
|
||||
</Step>
|
||||
</Steps>
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Async Capabilities
|
||||
|
||||
<CardGroup cols={1}>
|
||||
<Card title="Key Features" icon="bolt" iconType="solid">
|
||||
<Tabs>
|
||||
<Tab title="Async Support">
|
||||
```python
|
||||
async def main():
|
||||
agent = Agent(name="AsyncAgent")
|
||||
result = await agent.aprocess_task()
|
||||
```
|
||||
- Full async/await support
|
||||
- Non-blocking operations
|
||||
- Enhanced performance
|
||||
</Tab>
|
||||
|
||||
<Tab title="Parallel Execution">
|
||||
```python
|
||||
async def parallel_tasks():
|
||||
tasks = [agent1.task(), agent2.task()]
|
||||
results = await asyncio.gather(*tasks)
|
||||
```
|
||||
- Parallel task execution
|
||||
- Efficient resource usage
|
||||
- Improved throughput
|
||||
</Tab>
|
||||
|
||||
<Tab title="Integration">
|
||||
```python
|
||||
@agent.async_tool
|
||||
async def custom_tool():
|
||||
async with aiohttp.ClientSession() as session:
|
||||
# Async operations
|
||||
pass
|
||||
```
|
||||
- Async tool integration
|
||||
- Callback support
|
||||
- Mixed sync/async operations
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Advanced Features
|
||||
|
||||
|
||||
@@ -0,0 +1,441 @@
|
||||
---
|
||||
title: "AI Agents with Memory"
|
||||
sidebarTitle: "Memory"
|
||||
description: "Learn how to create AI agents with memory capabilities for maintaining context and information across tasks."
|
||||
icon: "brain"
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install "praisonaiagents[memory]" duckduckgo_search
|
||||
```
|
||||
duckduckgo_search is a tool that allows agents to search the web.
|
||||
It is required for the multiple agents example shown below.
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `app.py` with the basic setup:
|
||||
<CodeGroup>
|
||||
```python Single Agent
|
||||
from praisonaiagents.agents.agents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create blog writer agent
|
||||
blog_agent = Agent(
|
||||
role="Blog Writer",
|
||||
goal="Write a blog post about AI",
|
||||
backstory="Expert at writing blog posts",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
# Create blog writing task
|
||||
blog_task = Task(
|
||||
description="Write a blog post about AI trends",
|
||||
expected_output="Well-written blog post about AI trends",
|
||||
agent=blog_agent
|
||||
)
|
||||
|
||||
# Create and start the agents with memory enabled
|
||||
agents = PraisonAIAgents(
|
||||
agents=[blog_agent],
|
||||
tasks=[blog_task],
|
||||
memory=True
|
||||
)
|
||||
|
||||
# Start execution
|
||||
result = agents.start()
|
||||
print(result)
|
||||
```
|
||||
|
||||
```python Multiple Agents
|
||||
from praisonaiagents.agents.agents import Agent, Task, PraisonAIAgents
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
# Create research agent with memory
|
||||
research_agent = Agent(
|
||||
role="Research Analyst",
|
||||
goal="Research and document key information about topics",
|
||||
backstory="Expert at analyzing and storing information in memory",
|
||||
llm="gpt-4o-mini",
|
||||
tools=[duckduckgo]
|
||||
)
|
||||
|
||||
# Create blog writer agent
|
||||
blog_agent = Agent(
|
||||
role="Blog Writer",
|
||||
goal="Write a blog post about the research",
|
||||
backstory="Expert at writing blog posts",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
# Create research task
|
||||
research_task = Task(
|
||||
description="Research and document key information about AI trends",
|
||||
expected_output="Detailed research findings about AI trends",
|
||||
agent=research_agent
|
||||
)
|
||||
|
||||
# Create blog writing task
|
||||
blog_task = Task(
|
||||
description="Write a blog post about the research findings",
|
||||
expected_output="Well-written blog post based on research",
|
||||
agent=blog_agent
|
||||
)
|
||||
|
||||
# Create and start the agents with advanced memory configuration
|
||||
agents = PraisonAIAgents(
|
||||
agents=[research_agent, blog_agent],
|
||||
tasks=[research_task, blog_task],
|
||||
memory=True
|
||||
)
|
||||
|
||||
# Start execution
|
||||
result = agents.start()
|
||||
print(result)
|
||||
```
|
||||
</CodeGroup>
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
Install the PraisonAI package:
|
||||
```bash
|
||||
pip install praisonai
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create a file">
|
||||
Create a new file `agents.yaml` with the basic setup:
|
||||
```yaml
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
memory: true
|
||||
roles:
|
||||
researcher:
|
||||
backstory: Expert at analyzing and storing information in memory.
|
||||
goal: Research and document key information about topics
|
||||
role: Research Analyst
|
||||
llm: gpt-4o-mini
|
||||
tools:
|
||||
- duckduckgo
|
||||
tasks:
|
||||
research_task:
|
||||
description: Research and document key information about topics.
|
||||
expected_output: Detailed research findings.
|
||||
|
||||
writer:
|
||||
backstory: Expert at writing blog posts.
|
||||
goal: Write a blog post about the research
|
||||
role: Blog Writer
|
||||
llm: gpt-4o-mini
|
||||
tasks:
|
||||
blog_task:
|
||||
description: Write a blog post about the research.
|
||||
expected_output: Well-written blog post based on research.
|
||||
```
|
||||
</Step>
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
praisonai agents.yaml
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Note>
|
||||
**Requirements**
|
||||
- Python 3.10 or higher
|
||||
- OpenAI API key. Generate OpenAI API key [here](https://platform.openai.com/api-keys). Use Other models using [this guide](/models).
|
||||
- Basic understanding of Python
|
||||
</Note>
|
||||
|
||||
## Understanding Memory
|
||||
|
||||
<Card title="What is Agent Memory?" icon="question">
|
||||
Memory in AI agents enables them to:
|
||||
- Maintain context across multiple tasks
|
||||
- Remember previous interactions and findings
|
||||
- Build upon past knowledge
|
||||
- Share information between agents
|
||||
- Create more coherent and contextual responses
|
||||
</Card>
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Context Retention" icon="brain">
|
||||
Maintain information across multiple interactions.
|
||||
</Card>
|
||||
<Card title="Information Sharing" icon="share-nodes">
|
||||
Share knowledge between multiple agents.
|
||||
</Card>
|
||||
<Card title="Long-term Storage" icon="database">
|
||||
Store and retrieve information over extended periods.
|
||||
</Card>
|
||||
<Card title="Memory Types" icon="layer-group">
|
||||
Support for different memory types (short-term, long-term).
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Multi-Agent Memory
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
# Create first agent for research
|
||||
researcher = Agent(
|
||||
role="Research Analyst",
|
||||
goal="Research and analyze market trends",
|
||||
backstory="Expert in market research and data analysis",
|
||||
tools=[duckduckgo],
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Create second agent for report writing
|
||||
writer = Agent(
|
||||
role="Report Writer",
|
||||
goal="Create comprehensive market reports",
|
||||
backstory="Expert in technical writing and report creation",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Create research task
|
||||
research_task = Task(
|
||||
description="Research current market trends",
|
||||
expected_output="Detailed market analysis",
|
||||
agent=researcher
|
||||
)
|
||||
|
||||
# Create writing task
|
||||
report_task = Task(
|
||||
description="Create a market report based on research",
|
||||
expected_output="Comprehensive market report",
|
||||
agent=writer
|
||||
)
|
||||
|
||||
# Create and start the agents with memory
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher, writer],
|
||||
tasks=[research_task, report_task],
|
||||
memory=True,
|
||||
process="sequential"
|
||||
)
|
||||
|
||||
# Start execution
|
||||
result = agents.start()
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
```yaml
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
memory: true
|
||||
roles:
|
||||
researcher:
|
||||
backstory: Expert in market research and data analysis.
|
||||
goal: Research and analyze market trends
|
||||
role: Research Analyst
|
||||
tools:
|
||||
- duckduckgo
|
||||
tasks:
|
||||
research_task:
|
||||
description: Research current market trends.
|
||||
expected_output: Detailed market analysis.
|
||||
|
||||
writer:
|
||||
backstory: Expert in technical writing and report creation.
|
||||
goal: Create comprehensive market reports
|
||||
role: Report Writer
|
||||
tasks:
|
||||
report_task:
|
||||
description: Create a market report based on research.
|
||||
expected_output: Comprehensive market report.
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### Configuration Options
|
||||
|
||||
```python
|
||||
# Create an agent with memory configuration
|
||||
agent = Agent(
|
||||
role="Research Analyst",
|
||||
goal="Research and retain information",
|
||||
backstory="Expert in research and analysis",
|
||||
tools=[duckduckgo],
|
||||
verbose=True, # Enable detailed logging
|
||||
llm="gpt-4o" # Language model to use
|
||||
)
|
||||
|
||||
# Create agents with memory options
|
||||
agents = PraisonAIAgents(
|
||||
agents=[agent],
|
||||
tasks=[task],
|
||||
memory=True, # Enable memory
|
||||
memory_config={
|
||||
"provider": "rag", # Use RAG for semantic search
|
||||
"use_embedding": True, # Enable embeddings for better search
|
||||
"short_db": ".praison/short_term.db", # Path for short-term memory
|
||||
"long_db": ".praison/long_term.db", # Path for long-term memory
|
||||
"rag_db_path": ".praison/chroma_db" # Path for vector database
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Memory Issues" icon="triangle-exclamation">
|
||||
If memory isn't working as expected:
|
||||
- Check memory configuration
|
||||
- Enable verbose mode for debugging
|
||||
- Verify memory provider settings
|
||||
</Card>
|
||||
|
||||
<Card title="Context Flow" icon="code">
|
||||
If context isn't being maintained:
|
||||
- Review task dependencies
|
||||
- Check memory configuration
|
||||
- Verify agent communication
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="AutoAgents" icon="robot" href="../features/autoagents">
|
||||
Learn about automatically created and managed AI agents
|
||||
</Card>
|
||||
<Card title="Mini Agents" icon="microchip" href="../features/mini">
|
||||
Explore lightweight, focused AI agents
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Note>
|
||||
For optimal results, configure memory settings based on your specific use case requirements and expected interaction patterns.
|
||||
</Note>
|
||||
|
||||
### Memory Configuration Options
|
||||
|
||||
The memory system in PraisonAI supports various configuration options to customize how agents store and retrieve information:
|
||||
|
||||
```python
|
||||
memory_config = {
|
||||
# Memory Provider
|
||||
"provider": "rag", # Options: "rag", "mem0", "none"
|
||||
"use_embedding": True, # Enable semantic search with embeddings
|
||||
|
||||
# Storage Paths
|
||||
"short_db": ".praison/short_term.db", # Short-term memory SQLite DB
|
||||
"long_db": ".praison/long_term.db", # Long-term memory SQLite DB
|
||||
"rag_db_path": ".praison/chroma_db", # Vector database path
|
||||
|
||||
# Memory Settings
|
||||
"ttl": 3600, # Time to live for memory items (in seconds)
|
||||
|
||||
# Optional Mem0 Config (if using mem0 provider)
|
||||
"config": {
|
||||
"api_key": "...", # Mem0 API key
|
||||
"org_id": "...", # Organization ID
|
||||
"project_id": "..." # Project ID
|
||||
}
|
||||
}
|
||||
|
||||
# Create agents with memory configuration
|
||||
agents = PraisonAIAgents(
|
||||
agents=[agent],
|
||||
tasks=[task],
|
||||
memory=True,
|
||||
memory_config=memory_config
|
||||
)
|
||||
```
|
||||
|
||||
### Memory Types
|
||||
|
||||
PraisonAI's memory system includes several types of memory:
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Short-term Memory" icon="bolt">
|
||||
- Temporary storage for current context
|
||||
- Automatically cleared between sessions
|
||||
- Fast access for immediate task context
|
||||
</Card>
|
||||
<Card title="Long-term Memory" icon="database">
|
||||
- Persistent storage for important information
|
||||
- Semantic search capabilities with RAG
|
||||
- Quality-based storage decisions
|
||||
</Card>
|
||||
<Card title="Entity Memory" icon="diagram-project">
|
||||
- Store information about specific entities
|
||||
- Track relationships and attributes
|
||||
- Specialized search for entity information
|
||||
</Card>
|
||||
<Card title="User Memory" icon="user">
|
||||
- Store user-specific information
|
||||
- Personalized context for each user
|
||||
- Persistent across sessions
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
### Memory Quality Control
|
||||
|
||||
PraisonAI includes built-in quality control for memory storage:
|
||||
|
||||
```python
|
||||
# Example of storing with quality metrics
|
||||
agents.memory.store_long_term(
|
||||
text="Important information to remember",
|
||||
metadata={
|
||||
"task_id": "task_123",
|
||||
"agent": "research_agent"
|
||||
},
|
||||
completeness=0.9, # How complete is the information
|
||||
relevance=0.85, # How relevant to the task
|
||||
clarity=0.95, # How clear and well-structured
|
||||
accuracy=0.9, # How accurate is the information
|
||||
weights={ # Custom weights for quality score
|
||||
"completeness": 0.3,
|
||||
"relevance": 0.3,
|
||||
"clarity": 0.2,
|
||||
"accuracy": 0.2
|
||||
}
|
||||
)
|
||||
|
||||
# Search with quality filter
|
||||
results = agents.memory.search_long_term(
|
||||
query="search query",
|
||||
min_quality=0.8, # Only return high-quality matches
|
||||
limit=5 # Maximum number of results
|
||||
)
|
||||
```
|
||||
+327
-172
@@ -10,96 +10,209 @@ Process types in PraisonAI define how tasks are executed and how agents collabor
|
||||
|
||||
## Process Types Overview
|
||||
|
||||
Three types of processes are implemented in PraisonAI:
|
||||
<CardGroup cols={3}>
|
||||
<Card
|
||||
title="Sequential Process"
|
||||
icon="arrow-right"
|
||||
href="/sequential-process"
|
||||
>
|
||||
Linear task execution in a predefined order
|
||||
</Card>
|
||||
<Card
|
||||
title="Hierarchical Process"
|
||||
icon="sitemap"
|
||||
href="/hierarchical-process"
|
||||
>
|
||||
Manager-coordinated task execution with dynamic assignment
|
||||
</Card>
|
||||
<Card
|
||||
title="Workflow Process"
|
||||
icon="diagram-project"
|
||||
href="/workflow-process"
|
||||
>
|
||||
Complex task flows with conditional execution and state management
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Frame>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div className="p-4 border rounded-lg bg-white dark:bg-gray-800">
|
||||
<div className="flex items-center mb-4">
|
||||
<div className="p-2 bg-blue-100 dark:bg-blue-900 rounded-lg">
|
||||
<svg className="w-6 h-6 text-blue-600 dark:text-blue-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16m-7 6h7" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="ml-3 text-lg font-semibold">Sequential Process</h3>
|
||||
</div>
|
||||
<p>Linear task execution in a predefined order</p>
|
||||
</div>
|
||||
## Sequential Process
|
||||
|
||||
<div className="p-4 border rounded-lg bg-white dark:bg-gray-800">
|
||||
<div className="flex items-center mb-4">
|
||||
<div className="p-2 bg-green-100 dark:bg-green-900 rounded-lg">
|
||||
<svg className="w-6 h-6 text-green-600 dark:text-green-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="ml-3 text-lg font-semibold">Hierarchical Process</h3>
|
||||
</div>
|
||||
<p>Manager-coordinated task execution with dynamic assignment</p>
|
||||
</div>
|
||||
|
||||
<div className="p-4 border rounded-lg bg-white dark:bg-gray-800">
|
||||
<div className="flex items-center mb-4">
|
||||
<div className="p-2 bg-purple-100 dark:bg-purple-900 rounded-lg">
|
||||
<svg className="w-6 h-6 text-purple-600 dark:text-purple-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="ml-3 text-lg font-semibold">Workflow Process</h3>
|
||||
</div>
|
||||
<p>Complex task flows with conditional execution and state management</p>
|
||||
</div>
|
||||
</div>
|
||||
</Frame>
|
||||
|
||||
### Sequential Process
|
||||
The simplest form of task execution where tasks are performed one after another.
|
||||
|
||||
<Frame>
|
||||
<div className="p-4 bg-white dark:bg-gray-800 rounded-lg">
|
||||
#### Characteristics
|
||||
- Linear execution flow
|
||||
- Predictable order
|
||||
- Simple dependency management
|
||||
- Direct task progression
|
||||
<Card>
|
||||
### Characteristics
|
||||
- Linear execution flow
|
||||
- Predictable order
|
||||
- Simple dependency management
|
||||
- Direct task progression
|
||||
|
||||
#### Usage
|
||||
```python
|
||||
agents = PraisonAIAgents(
|
||||
agents=[agent1, agent2],
|
||||
tasks=[task1, task2, task3],
|
||||
process="sequential"
|
||||
)
|
||||
```
|
||||
</div>
|
||||
</Frame>
|
||||
### Usage
|
||||
```python
|
||||
agents = PraisonAIAgents(
|
||||
agents=[agent1, agent2],
|
||||
tasks=[task1, task2, task3],
|
||||
process="sequential"
|
||||
)
|
||||
```
|
||||
</Card>
|
||||
|
||||
## Hierarchical Process
|
||||
|
||||
### Hierarchical Process
|
||||
Uses a manager agent to coordinate task execution and agent assignments.
|
||||
|
||||
<Frame>
|
||||
<div className="p-4 bg-white dark:bg-gray-800 rounded-lg">
|
||||
#### Characteristics
|
||||
- Manager-driven coordination
|
||||
- Dynamic task assignment
|
||||
- Flexible execution order
|
||||
- Intelligent resource allocation
|
||||
<Card>
|
||||
### Characteristics
|
||||
- Manager-driven coordination
|
||||
- Dynamic task assignment
|
||||
- Flexible execution order
|
||||
- Intelligent resource allocation
|
||||
|
||||
#### Configuration
|
||||
```python
|
||||
agents = PraisonAIAgents(
|
||||
agents=[manager_agent, worker_agent1, worker_agent2],
|
||||
tasks=[task1, task2],
|
||||
process="hierarchical",
|
||||
manager_llm="gpt-4o"
|
||||
)
|
||||
```
|
||||
</div>
|
||||
</Frame>
|
||||
### Configuration
|
||||
```python
|
||||
agents = PraisonAIAgents(
|
||||
agents=[manager_agent, worker_agent1, worker_agent2],
|
||||
tasks=[task1, task2],
|
||||
process="hierarchical",
|
||||
manager_llm="gpt-4o"
|
||||
)
|
||||
```
|
||||
</Card>
|
||||
|
||||
## Workflow Process
|
||||
|
||||
### Workflow Process
|
||||
Advanced process type supporting complex task relationships and conditional execution.
|
||||
|
||||
<Card>
|
||||
### Features
|
||||
- Task dependencies
|
||||
- Conditional branching
|
||||
- Loop handling
|
||||
- Context sharing
|
||||
- State management
|
||||
|
||||
### Implementation
|
||||
```python
|
||||
task_workflow = {
|
||||
"start_task": {
|
||||
"next": ["decision_task"],
|
||||
"type": "task"
|
||||
},
|
||||
"decision_task": {
|
||||
"type": "decision",
|
||||
"conditions": {
|
||||
"success": ["process_task"],
|
||||
"failure": ["error_task"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
</Card>
|
||||
|
||||
## Getting Started
|
||||
|
||||
<Steps>
|
||||
<Step title="Install PraisonAI">
|
||||
Install the core package:
|
||||
```bash Terminal
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Configure Environment">
|
||||
```bash Terminal
|
||||
export OPENAI_API_KEY=your_openai_key
|
||||
```
|
||||
Generate your OpenAI API key from [OpenAI](https://platform.openai.com/api-keys)
|
||||
Use other LLM providers like Ollama, Anthropic, Groq, Google, etc. Please refer to the [Models](/models) for more information.
|
||||
</Step>
|
||||
|
||||
<Step title="Create Agent">
|
||||
Create `app.py`:
|
||||
<CodeGroup>
|
||||
```python Single Agent Sequential Process
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create an agent
|
||||
researcher = Agent(
|
||||
name="Researcher",
|
||||
role="Senior Research Analyst",
|
||||
goal="Uncover cutting-edge developments in AI",
|
||||
backstory="You are an expert at a technology research group",
|
||||
verbose=True,
|
||||
llm="gpt-4o"
|
||||
)
|
||||
|
||||
# Define a task
|
||||
task = Task(
|
||||
name="research_task",
|
||||
description="Analyze 2024's AI advancements",
|
||||
expected_output="A detailed report",
|
||||
agent=researcher
|
||||
)
|
||||
|
||||
# Run the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher],
|
||||
tasks=[task],
|
||||
verbose=False,
|
||||
process="sequential"
|
||||
)
|
||||
|
||||
result = agents.start()
|
||||
```
|
||||
|
||||
```python Multiple Agents Hierarchical Process
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create multiple agents
|
||||
researcher = Agent(
|
||||
name="Researcher",
|
||||
role="Senior Research Analyst",
|
||||
goal="Uncover cutting-edge developments in AI",
|
||||
backstory="You are an expert at a technology research group",
|
||||
verbose=True,
|
||||
llm="gpt-4o",
|
||||
markdown=True
|
||||
)
|
||||
|
||||
writer = Agent(
|
||||
name="Writer",
|
||||
role="Tech Content Strategist",
|
||||
goal="Craft compelling content on tech advancements",
|
||||
backstory="You are a content strategist",
|
||||
llm="gpt-4o",
|
||||
markdown=True
|
||||
)
|
||||
|
||||
# Define multiple tasks
|
||||
task1 = Task(
|
||||
name="research_task",
|
||||
description="Analyze 2024's AI advancements",
|
||||
expected_output="A detailed report",
|
||||
agent=researcher
|
||||
)
|
||||
|
||||
task2 = Task(
|
||||
name="writing_task",
|
||||
description="Create a blog post about AI advancements",
|
||||
expected_output="A blog post",
|
||||
agent=writer
|
||||
)
|
||||
|
||||
# Run with hierarchical process
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher, writer],
|
||||
tasks=[task1, task2],
|
||||
verbose=False,
|
||||
process="hierarchical",
|
||||
manager_llm="gpt-4o"
|
||||
)
|
||||
|
||||
result = agents.start()
|
||||
```
|
||||
</CodeGroup>
|
||||
</Step>
|
||||
</Steps>
|
||||
<br /><br />
|
||||
<div className="relative w-full aspect-video">
|
||||
<iframe
|
||||
className="absolute top-0 left-0 w-full h-full"
|
||||
@@ -111,110 +224,152 @@ Advanced process type supporting complex task relationships and conditional exec
|
||||
</div>
|
||||
<br />
|
||||
|
||||
|
||||
<Frame>
|
||||
<div className="p-4 bg-white dark:bg-gray-800 rounded-lg">
|
||||
#### Features
|
||||
- Task dependencies
|
||||
- Conditional branching
|
||||
- Loop handling
|
||||
- Context sharing
|
||||
- State management
|
||||
|
||||
#### Implementation
|
||||
```python
|
||||
task_workflow = {
|
||||
"start_task": {
|
||||
"next": ["decision_task"],
|
||||
"type": "task"
|
||||
},
|
||||
"decision_task": {
|
||||
"type": "decision",
|
||||
"conditions": {
|
||||
"success": ["process_task"],
|
||||
"failure": ["error_task"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
</div>
|
||||
</Frame>
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### State Management
|
||||
- Task state tracking
|
||||
- Context preservation
|
||||
- Data flow control
|
||||
<CardGroup cols={2}>
|
||||
<Card title="State Management" icon="database" iconType="solid">
|
||||
<AccordionGroup>
|
||||
<Accordion title="Task State Tracking">
|
||||
Monitor and manage the progress of each task in real-time
|
||||
</Accordion>
|
||||
<Accordion title="Context Preservation">
|
||||
Maintain important information across different stages of execution
|
||||
</Accordion>
|
||||
<Accordion title="Data Flow Control">
|
||||
Manage how data moves between tasks and agents efficiently
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
</Card>
|
||||
|
||||
### Error Handling
|
||||
- Graceful failure recovery
|
||||
- Alternative path execution
|
||||
- Error reporting
|
||||
<Card title="Error Handling" icon="shield-check" iconType="solid">
|
||||
<AccordionGroup>
|
||||
<Accordion title="Graceful Recovery">
|
||||
Automatically handle failures and continue execution
|
||||
</Accordion>
|
||||
<Accordion title="Alternative Paths">
|
||||
Switch to backup plans when primary execution fails
|
||||
</Accordion>
|
||||
<Accordion title="Error Reporting">
|
||||
Detailed error logs and diagnostic information
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
</Card>
|
||||
|
||||
### Monitoring
|
||||
- Progress tracking
|
||||
- Performance metrics
|
||||
- Resource utilization
|
||||
<Card title="Monitoring" icon="chart-line" iconType="solid">
|
||||
<AccordionGroup>
|
||||
<Accordion title="Progress Tracking">
|
||||
Real-time visibility into task completion status
|
||||
</Accordion>
|
||||
<Accordion title="Performance Metrics">
|
||||
Measure execution time and resource efficiency
|
||||
</Accordion>
|
||||
<Accordion title="Resource Usage">
|
||||
Monitor system resource utilization
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
</Card>
|
||||
|
||||
### Integration
|
||||
- External system coordination
|
||||
- API synchronization
|
||||
- Event handling
|
||||
<Card title="Integration" icon="plug" iconType="solid">
|
||||
<AccordionGroup>
|
||||
<Accordion title="External Systems">
|
||||
Connect with other services and platforms
|
||||
</Accordion>
|
||||
<Accordion title="API Sync">
|
||||
Maintain data consistency across systems
|
||||
</Accordion>
|
||||
<Accordion title="Event Handling">
|
||||
React to system and external events
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Async Process Execution
|
||||
All process types (sequential, workflow, hierarchical) support async execution through async generators. This enables efficient handling of async tasks and parallel processing.
|
||||
## Async Processing
|
||||
|
||||
### Async Process Methods
|
||||
- `asequential`: Async version of sequential process
|
||||
- `aworkflow`: Async version of workflow process
|
||||
- `ahierarchical`: Async version of hierarchical process
|
||||
<Note>
|
||||
All process types support asynchronous execution through async generators, enabling efficient parallel processing and non-blocking operations.
|
||||
</Note>
|
||||
|
||||
### Example Usage:
|
||||
### Core Async Methods
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
<CardGroup cols={3}>
|
||||
<Card title="asequential" icon="arrow-right">
|
||||
Async version of sequential process for non-blocking linear execution
|
||||
</Card>
|
||||
<Card title="aworkflow" icon="diagram-project">
|
||||
Async workflow process for complex parallel task execution
|
||||
</Card>
|
||||
<Card title="ahierarchical" icon="sitemap">
|
||||
Async hierarchical process for distributed task management
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
async def main():
|
||||
# Create agents and tasks
|
||||
agents = [async_agent1, async_agent2]
|
||||
tasks = [async_task1, async_task2]
|
||||
### Process-Specific Features
|
||||
|
||||
# Initialize PraisonAIAgents with async workflow
|
||||
agents = PraisonAIAgents(
|
||||
agents=agents,
|
||||
tasks=tasks,
|
||||
process="workflow" # or "sequential" or "hierarchical"
|
||||
)
|
||||
<Tabs>
|
||||
<Tab title="Sequential Process">
|
||||
<Card>
|
||||
- Tasks execute in order but don't block
|
||||
- Maintains sequence while allowing async operations
|
||||
- Perfect for I/O-heavy tasks
|
||||
```python
|
||||
async def main():
|
||||
agents = PraisonAIAgents(
|
||||
process="sequential",
|
||||
async_mode=True
|
||||
)
|
||||
await agents.astart()
|
||||
```
|
||||
</Card>
|
||||
</Tab>
|
||||
|
||||
<Tab title="Workflow Process">
|
||||
<Card>
|
||||
- Parallel execution of independent tasks
|
||||
- Async branching and merging
|
||||
- Dynamic task scheduling based on conditions
|
||||
```python
|
||||
async def main():
|
||||
agents = PraisonAIAgents(
|
||||
process="workflow",
|
||||
async_mode=True,
|
||||
parallel_tasks=True
|
||||
)
|
||||
await agents.astart()
|
||||
```
|
||||
</Card>
|
||||
</Tab>
|
||||
|
||||
<Tab title="Hierarchical Process">
|
||||
<Card>
|
||||
- Async manager delegation
|
||||
- Parallel subtask execution
|
||||
- Dynamic worker assignment
|
||||
```python
|
||||
async def main():
|
||||
agents = PraisonAIAgents(
|
||||
process="hierarchical",
|
||||
async_mode=True,
|
||||
dynamic_assignment=True
|
||||
)
|
||||
await agents.astart()
|
||||
```
|
||||
</Card>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
# Start async execution
|
||||
result = await agents.astart()
|
||||
print(result)
|
||||
### Key Benefits
|
||||
|
||||
# Run the async workflow
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
### Async Process Features:
|
||||
- Parallel task execution in workflow
|
||||
- Async task delegation in hierarchical process
|
||||
- Non-blocking task execution
|
||||
- Efficient resource utilization
|
||||
- Mixed sync/async task support
|
||||
|
||||
### Process-Specific Async Behavior:
|
||||
1. **Sequential Process**:
|
||||
- Tasks are executed in order
|
||||
- Async tasks don't block other tasks
|
||||
- Maintains sequential order while allowing async execution
|
||||
|
||||
2. **Workflow Process**:
|
||||
- Parallel execution of independent tasks
|
||||
- Async branching and merging
|
||||
- Dynamic task scheduling
|
||||
|
||||
3. **Hierarchical Process**:
|
||||
- Async manager delegation
|
||||
- Parallel subtask execution
|
||||
- Dynamic task assignment
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Performance" icon="bolt">
|
||||
- Efficient resource utilization
|
||||
- Reduced waiting time
|
||||
- Better throughput
|
||||
</Card>
|
||||
|
||||
<Card title="Flexibility" icon="puzzle-piece">
|
||||
- Mix sync and async tasks
|
||||
- Adaptable execution patterns
|
||||
- Easy scaling
|
||||
</Card>
|
||||
</CardGroup>
|
||||
+365
-179
@@ -8,114 +8,6 @@ icon: "list-check"
|
||||
Tasks are the fundamental units of work in PraisonAI, defining what needs to be done, how it should be done, and who should do it.
|
||||
</Note>
|
||||
|
||||
# Understanding Tasks
|
||||
|
||||
<Frame>
|
||||
<div className="p-6 bg-white dark:bg-gray-800 rounded-lg">
|
||||
<div className="grid grid-cols-1 gap-6">
|
||||
{/* Task Flow Steps */}
|
||||
<div className="flex justify-between items-center">
|
||||
{/* Task Definition */}
|
||||
<div className="flex-1 p-4 border-2 border-blue-500 rounded-lg text-center">
|
||||
<div className="flex items-center justify-center mb-2">
|
||||
<div className="p-2 bg-blue-100 dark:bg-blue-900 rounded-full">
|
||||
<svg className="w-6 h-6 text-blue-600 dark:text-blue-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<h4 className="font-semibold">Task Definition</h4>
|
||||
<p className="text-sm mt-1">Description & Requirements</p>
|
||||
</div>
|
||||
|
||||
{/* Arrow 1 */}
|
||||
<div className="flex-none px-4">
|
||||
<svg className="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* Agent Assignment */}
|
||||
<div className="flex-1 p-4 border-2 border-green-500 rounded-lg text-center">
|
||||
<div className="flex items-center justify-center mb-2">
|
||||
<div className="p-2 bg-green-100 dark:bg-green-900 rounded-full">
|
||||
<svg className="w-6 h-6 text-green-600 dark:text-green-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<h4 className="font-semibold">Agent Assignment</h4>
|
||||
<p className="text-sm mt-1">Matching & Delegation</p>
|
||||
</div>
|
||||
|
||||
{/* Arrow 2 */}
|
||||
<div className="flex-none px-4">
|
||||
<svg className="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* Execution */}
|
||||
<div className="flex-1 p-4 border-2 border-purple-500 rounded-lg text-center">
|
||||
<div className="flex items-center justify-center mb-2">
|
||||
<div className="p-2 bg-purple-100 dark:bg-purple-900 rounded-full">
|
||||
<svg className="w-6 h-6 text-purple-600 dark:text-purple-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<h4 className="font-semibold">Execution</h4>
|
||||
<p className="text-sm mt-1">Processing & Tools</p>
|
||||
</div>
|
||||
|
||||
{/* Arrow 3 */}
|
||||
<div className="flex-none px-4">
|
||||
<svg className="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* Output */}
|
||||
<div className="flex-1 p-4 border-2 border-yellow-500 rounded-lg text-center">
|
||||
<div className="flex items-center justify-center mb-2">
|
||||
<div className="p-2 bg-yellow-100 dark:bg-yellow-900 rounded-full">
|
||||
<svg className="w-6 h-6 text-yellow-600 dark:text-yellow-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<h4 className="font-semibold">Output</h4>
|
||||
<p className="text-sm mt-1">Results & Validation</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Task States */}
|
||||
<div className="grid grid-cols-4 gap-4 mt-4">
|
||||
<div className="p-3 border border-gray-200 rounded-lg bg-blue-50 dark:bg-blue-900">
|
||||
<div className="flex items-center justify-center">
|
||||
<span className="font-semibold">Pending</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3 border border-gray-200 rounded-lg bg-yellow-50 dark:bg-yellow-900">
|
||||
<div className="flex items-center justify-center">
|
||||
<span className="font-semibold">In Progress</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3 border border-gray-200 rounded-lg bg-green-50 dark:bg-green-900">
|
||||
<div className="flex items-center justify-center">
|
||||
<span className="font-semibold">Completed</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3 border border-gray-200 rounded-lg bg-red-50 dark:bg-red-900">
|
||||
<div className="flex items-center justify-center">
|
||||
<span className="font-semibold">Failed</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Frame>
|
||||
|
||||
## Core Components
|
||||
|
||||
<CardGroup cols={2}>
|
||||
@@ -155,6 +47,79 @@ icon: "list-check"
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
# Understanding Tasks
|
||||
<br />
|
||||
```mermaid
|
||||
graph LR
|
||||
%% Task Flow Steps
|
||||
Start([▶ Start]) --> TaskDef
|
||||
TaskDef --> AgentAssign
|
||||
AgentAssign --> Exec
|
||||
Exec --> Output([✓ Output])
|
||||
|
||||
%% Define subgraphs for each step
|
||||
subgraph TaskDef[" "]
|
||||
TD_Icon[📋 Task Definition]
|
||||
TD_Desc[Description & Requirements]
|
||||
|
||||
TD_Icon --- TD_Desc
|
||||
|
||||
style TD_Icon fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
style TD_Desc fill:#5C80BC,stroke:#7C90A0,color:#fff
|
||||
end
|
||||
|
||||
subgraph AgentAssign[" "]
|
||||
AA_Icon[🤖 Agent Assignment]
|
||||
AA_Desc[Matching & Delegation]
|
||||
|
||||
AA_Icon --- AA_Desc
|
||||
|
||||
style AA_Icon fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
style AA_Desc fill:#5C80BC,stroke:#7C90A0,color:#fff
|
||||
end
|
||||
|
||||
subgraph Exec[" "]
|
||||
E_Icon[⚙️ Execution]
|
||||
E_Desc[Processing & Tools]
|
||||
|
||||
E_Icon --- E_Desc
|
||||
|
||||
style E_Icon fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
style E_Desc fill:#5C80BC,stroke:#7C90A0,color:#fff
|
||||
end
|
||||
|
||||
%% Styling for main elements
|
||||
style Start fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
style Output fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
|
||||
%% Style for containers
|
||||
style TaskDef fill:#1B1F3B,stroke:#7C90A0,color:#fff
|
||||
style AgentAssign fill:#1B1F3B,stroke:#7C90A0,color:#fff
|
||||
style Exec fill:#1B1F3B,stroke:#7C90A0,color:#fff
|
||||
|
||||
%% Global styles
|
||||
classDef default fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
linkStyle default stroke:#7C90A0,stroke-width:2px
|
||||
```
|
||||
<br /><br />
|
||||
```mermaid
|
||||
graph LR
|
||||
%% Task States
|
||||
Pending([📥 Pending]) --> InProgress([⚡ In Progress])
|
||||
InProgress --> Completed([✅ Completed])
|
||||
InProgress --> Failed([❌ Failed])
|
||||
|
||||
%% Styling
|
||||
style Pending fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
style InProgress fill:#5C80BC,stroke:#7C90A0,color:#fff
|
||||
style Completed fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
style Failed fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
|
||||
%% Global styles
|
||||
classDef default fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
linkStyle default stroke:#7C90A0,stroke-width:2px
|
||||
```
|
||||
|
||||
## Task Types
|
||||
|
||||
<Steps>
|
||||
@@ -223,17 +188,300 @@ task_b = Task(
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Getting Started
|
||||
|
||||
<Steps>
|
||||
|
||||
<Step title="Install PraisonAI">
|
||||
Install the core package:
|
||||
```bash Terminal
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Configure Environment">
|
||||
```bash Terminal
|
||||
export OPENAI_API_KEY=your_openai_key
|
||||
```
|
||||
Generate your OpenAI API key from [OpenAI](https://platform.openai.com/api-keys)
|
||||
Use other LLM providers like Ollama, Anthropic, Groq, Google, etc. Please refer to the [Models](/models) for more information.
|
||||
</Step>
|
||||
|
||||
<Step title="Create Agent">
|
||||
Create `app.py`:
|
||||
<CodeGroup>
|
||||
```python Single Agent
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create an agent
|
||||
researcher = Agent(
|
||||
name="Researcher",
|
||||
role="Senior Research Analyst",
|
||||
goal="Uncover cutting-edge developments in AI",
|
||||
backstory="You are an expert at a technology research group",
|
||||
verbose=True,
|
||||
llm="gpt-4o"
|
||||
)
|
||||
|
||||
# Define a task
|
||||
task = Task(
|
||||
name="research_task",
|
||||
description="Analyze 2024's AI advancements",
|
||||
expected_output="A detailed report",
|
||||
agent=researcher
|
||||
)
|
||||
|
||||
# Run the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher],
|
||||
tasks=[task],
|
||||
verbose=False
|
||||
)
|
||||
|
||||
result = agents.start()
|
||||
```
|
||||
|
||||
```python Multiple Agents
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create multiple agents
|
||||
researcher = Agent(
|
||||
name="Researcher",
|
||||
role="Senior Research Analyst",
|
||||
goal="Uncover cutting-edge developments in AI",
|
||||
backstory="You are an expert at a technology research group",
|
||||
verbose=True,
|
||||
llm="gpt-4o",
|
||||
markdown=True
|
||||
)
|
||||
|
||||
writer = Agent(
|
||||
name="Writer",
|
||||
role="Tech Content Strategist",
|
||||
goal="Craft compelling content on tech advancements",
|
||||
backstory="You are a content strategist",
|
||||
llm="gpt-4o",
|
||||
markdown=True
|
||||
)
|
||||
|
||||
# Define multiple tasks
|
||||
task1 = Task(
|
||||
name="research_task",
|
||||
description="Analyze 2024's AI advancements",
|
||||
expected_output="A detailed report",
|
||||
agent=researcher
|
||||
)
|
||||
|
||||
task2 = Task(
|
||||
name="writing_task",
|
||||
description="Create a blog post about AI advancements",
|
||||
expected_output="A blog post",
|
||||
agent=writer
|
||||
)
|
||||
|
||||
# Run with hierarchical process
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher, writer],
|
||||
tasks=[task1, task2],
|
||||
verbose=False,
|
||||
process="hierarchical",
|
||||
manager_llm="gpt-4o"
|
||||
)
|
||||
|
||||
result = agents.start()
|
||||
```
|
||||
</CodeGroup>
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Best Practices
|
||||
|
||||
<Tip>
|
||||
Design tasks to be atomic and focused. Each task should have a single, clear responsibility.
|
||||
</Tip>
|
||||
<Note>
|
||||
Design tasks to be atomic and focused. Each task should have a single, clear responsibility.
|
||||
</Note>
|
||||
|
||||
1. Clear task descriptions
|
||||
2. Well-defined success criteria
|
||||
3. Appropriate tool selection
|
||||
4. Error handling consideration
|
||||
5. Resource management
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Task Design Principles" icon="compass-drafting" iconType="solid">
|
||||
<AccordionGroup>
|
||||
<Accordion title="Clear Task Descriptions">
|
||||
Write precise, unambiguous task descriptions that clearly state the task's purpose and requirements.
|
||||
```python
|
||||
task = Task(
|
||||
description=(
|
||||
"Analyze Q4 2024 sales data "
|
||||
"and generate growth metrics"
|
||||
),
|
||||
expected_output="Sales growth report"
|
||||
)
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Success Criteria">
|
||||
Define measurable success criteria to ensure task completion can be properly evaluated.
|
||||
```python
|
||||
task = Task(
|
||||
success_criteria={
|
||||
"format": "markdown",
|
||||
"metrics": [
|
||||
"growth_rate",
|
||||
"revenue_change"
|
||||
],
|
||||
"min_confidence": 0.95
|
||||
}
|
||||
)
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Task Dependencies">
|
||||
Specify any dependencies or prerequisites for the task.
|
||||
```python
|
||||
task = Task(
|
||||
description="Generate final report",
|
||||
dependencies=[
|
||||
data_collection_task,
|
||||
analysis_task
|
||||
],
|
||||
wait_for_dependencies=True
|
||||
)
|
||||
```
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
</Card>
|
||||
|
||||
<Card title="Resource Management" icon="server" iconType="solid">
|
||||
<AccordionGroup>
|
||||
<Accordion title="Tool Selection">
|
||||
Choose appropriate tools that match your task's requirements.
|
||||
```python
|
||||
task = Task(
|
||||
tools=[
|
||||
DataAnalyzer(),
|
||||
ReportGenerator(),
|
||||
MetricsCalculator()
|
||||
],
|
||||
tool_config={
|
||||
"timeout": 30,
|
||||
"retry": True
|
||||
}
|
||||
)
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Error Handling">
|
||||
Implement comprehensive error management strategies.
|
||||
```python
|
||||
task = Task(
|
||||
error_strategy="retry",
|
||||
max_retries=3,
|
||||
fallback_handler=handler,
|
||||
error_callbacks=[
|
||||
log_error,
|
||||
notify_admin
|
||||
]
|
||||
)
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Resource Limits">
|
||||
Set appropriate resource constraints for optimal performance.
|
||||
```python
|
||||
task = Task(
|
||||
memory_limit="2GB",
|
||||
timeout=300,
|
||||
max_concurrent=5,
|
||||
cpu_priority="high",
|
||||
auto_scale=True
|
||||
)
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Performance Monitoring">
|
||||
Configure monitoring and logging for task execution.
|
||||
```python
|
||||
task = Task(
|
||||
monitoring={
|
||||
"metrics": ["duration", "memory", "cpu"],
|
||||
"log_level": "INFO",
|
||||
"trace_enabled": True,
|
||||
"alert_threshold": 0.85
|
||||
}
|
||||
)
|
||||
```
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Async Task Execution
|
||||
|
||||
<CardGroup cols={1}>
|
||||
<Card title="Async Task Features" icon="bolt" iconType="solid">
|
||||
<Tabs>
|
||||
<Tab title="Basic Configuration">
|
||||
```python
|
||||
async_task = Task(
|
||||
description="Perform async operation",
|
||||
expected_output="Async result",
|
||||
agent=async_agent,
|
||||
async_execution=True, # Enable async execution
|
||||
callback=async_callback # Optional async callback
|
||||
)
|
||||
```
|
||||
- Enable async execution with `async_execution=True`
|
||||
- Perfect for I/O-heavy operations
|
||||
- Supports parallel task execution
|
||||
</Tab>
|
||||
|
||||
<Tab title="Async Callbacks">
|
||||
```python
|
||||
async def async_callback(output: TaskOutput):
|
||||
await asyncio.sleep(1) # Simulate async operation
|
||||
print(f"Processed output: {output.raw}")
|
||||
|
||||
task = Task(
|
||||
description="Task with async callback",
|
||||
expected_output="Result",
|
||||
agent=agent,
|
||||
async_execution=True,
|
||||
callback=async_callback
|
||||
)
|
||||
```
|
||||
- Support for async callbacks
|
||||
- Process results asynchronously
|
||||
- Handle task completion events
|
||||
</Tab>
|
||||
|
||||
<Tab title="Mixed Execution">
|
||||
```python
|
||||
# Create mixed task types
|
||||
sync_task = Task(
|
||||
description="Synchronous operation",
|
||||
async_execution=False
|
||||
)
|
||||
|
||||
async_task = Task(
|
||||
description="Asynchronous operation",
|
||||
async_execution=True
|
||||
)
|
||||
|
||||
# Run with mixed execution
|
||||
agents = PraisonAIAgents(
|
||||
agents=[sync_agent, async_agent],
|
||||
tasks=[sync_task, async_task]
|
||||
)
|
||||
result = await agents.astart()
|
||||
```
|
||||
- Mix sync and async tasks
|
||||
- Flexible execution patterns
|
||||
- Optimal resource utilization
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Tip>
|
||||
**Pro Tip**: Use async execution for tasks that involve I/O operations (like API calls or file operations) to improve overall performance. Keep CPU-intensive tasks synchronous.
|
||||
</Tip>
|
||||
|
||||
## Next Steps
|
||||
|
||||
@@ -252,66 +500,4 @@ task_b = Task(
|
||||
>
|
||||
Explore the complete Task API documentation
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Async Task Execution
|
||||
Tasks can be executed asynchronously by setting `async_execution=True`. This is particularly useful for tasks that involve I/O operations or when you want to run multiple tasks in parallel.
|
||||
|
||||
### Async Task Configuration
|
||||
```python
|
||||
async_task = Task(
|
||||
description="Perform async operation",
|
||||
expected_output="Async result",
|
||||
agent=async_agent,
|
||||
async_execution=True, # Enable async execution
|
||||
callback=async_callback # Optional async callback
|
||||
)
|
||||
```
|
||||
|
||||
### Async Callbacks
|
||||
Tasks support both synchronous and asynchronous callbacks:
|
||||
|
||||
```python
|
||||
async def async_callback(output: TaskOutput):
|
||||
await asyncio.sleep(1) # Simulate async operation
|
||||
print(f"Processed output: {output.raw}")
|
||||
|
||||
# Task with async callback
|
||||
task = Task(
|
||||
description="Task with async callback",
|
||||
expected_output="Result",
|
||||
agent=agent,
|
||||
async_execution=True,
|
||||
callback=async_callback
|
||||
)
|
||||
```
|
||||
|
||||
### Mixing Sync and Async Tasks
|
||||
You can mix synchronous and asynchronous tasks in the same workflow:
|
||||
|
||||
```python
|
||||
# Sync task
|
||||
sync_task = Task(
|
||||
description="Synchronous operation",
|
||||
expected_output="Sync result",
|
||||
agent=sync_agent,
|
||||
async_execution=False
|
||||
)
|
||||
|
||||
# Async task
|
||||
async_task = Task(
|
||||
description="Asynchronous operation",
|
||||
expected_output="Async result",
|
||||
agent=async_agent,
|
||||
async_execution=True
|
||||
)
|
||||
|
||||
# Create agents with mixed tasks
|
||||
agents = PraisonAIAgents(
|
||||
agents=[sync_agent, async_agent],
|
||||
tasks=[sync_task, async_task]
|
||||
)
|
||||
|
||||
# Run asynchronously
|
||||
result = await agents.astart()
|
||||
```
|
||||
</CardGroup>
|
||||
+501
-226
@@ -8,48 +8,6 @@ icon: "screwdriver-wrench"
|
||||
|
||||
Tools in PraisonAI are functions that agents can use to interact with external systems, perform computations, or access data. They extend the capabilities of agents beyond just language processing.
|
||||
|
||||
## Tools Overview
|
||||
|
||||
<Frame>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div className="p-4 border rounded-lg bg-white dark:bg-gray-800">
|
||||
<div className="flex items-center mb-4">
|
||||
<div className="p-2 bg-blue-100 dark:bg-blue-900 rounded-lg">
|
||||
<svg className="w-6 h-6 text-blue-600 dark:text-blue-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="ml-3 text-lg font-semibold">Search Tools</h3>
|
||||
</div>
|
||||
<p>Tools for searching and retrieving information from various sources</p>
|
||||
</div>
|
||||
|
||||
<div className="p-4 border rounded-lg bg-white dark:bg-gray-800">
|
||||
<div className="flex items-center mb-4">
|
||||
<div className="p-2 bg-green-100 dark:bg-green-900 rounded-lg">
|
||||
<svg className="w-6 h-6 text-green-600 dark:text-green-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2v-2" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="ml-3 text-lg font-semibold">File Tools</h3>
|
||||
</div>
|
||||
<p>Tools for reading, writing, and manipulating files</p>
|
||||
</div>
|
||||
|
||||
<div className="p-4 border rounded-lg bg-white dark:bg-gray-800">
|
||||
<div className="flex items-center mb-4">
|
||||
<div className="p-2 bg-purple-100 dark:bg-purple-900 rounded-lg">
|
||||
<svg className="w-6 h-6 text-purple-600 dark:text-purple-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 6l3 1m0 0l-3 9a5.002 5.002 0 006.001 0M6 7l3 9M6 7l6-2m6 2l3-1m-3 1l-3 9a5.002 5.002 0 006.001 0M18 7l3 9m-3-9l-6-2m0-2v2m0 16V5m0 16H9m3 0h3" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="ml-3 text-lg font-semibold">API Tools</h3>
|
||||
</div>
|
||||
<p>Tools for interacting with external APIs and services</p>
|
||||
</div>
|
||||
</div>
|
||||
</Frame>
|
||||
|
||||
## Creating Custom Tool
|
||||
<Steps>
|
||||
<Step>
|
||||
@@ -99,237 +57,554 @@ Assign the tool to an agent
|
||||
</Card>
|
||||
|
||||
## Implementing Tools Full Code Example
|
||||
<Tabs>
|
||||
|
||||
Tools are implemented as Python functions with type hints and docstrings. Here's a complete example:
|
||||
<Tab title="Code">
|
||||
<Steps>
|
||||
|
||||
<Step title="Install PraisonAI">
|
||||
Install the core package:
|
||||
```bash Terminal
|
||||
pip install praisonaiagents duckduckgo-search
|
||||
```
|
||||
</Step>
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from duckduckgo_search import DDGS
|
||||
from typing import List, Dict
|
||||
<Step title="Configure Environment">
|
||||
```bash Terminal
|
||||
export OPENAI_API_KEY=your_openai_key
|
||||
```
|
||||
Generate your OpenAI API key from [OpenAI](https://platform.openai.com/api-keys)
|
||||
Use other LLM providers like Ollama, Anthropic, Groq, Google, etc. Please refer to the [Models](/models) for more information.
|
||||
</Step>
|
||||
|
||||
# 1. Tool Implementation
|
||||
def internet_search_tool(query: str) -> List[Dict]:
|
||||
"""
|
||||
Perform Internet Search using DuckDuckGo
|
||||
<Step title="Create Agent with Tool">
|
||||
Create `app.py`
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from duckduckgo_search import DDGS
|
||||
from typing import List, Dict
|
||||
|
||||
# 1. Tool Implementation
|
||||
def internet_search_tool(query: str) -> List[Dict]:
|
||||
"""
|
||||
Perform Internet Search using DuckDuckGo
|
||||
|
||||
Args:
|
||||
query (str): The search query string
|
||||
|
||||
Args:
|
||||
query (str): The search query string
|
||||
|
||||
Returns:
|
||||
List[Dict]: List of search results containing title, URL, and snippet
|
||||
"""
|
||||
results = []
|
||||
ddgs = DDGS()
|
||||
for result in ddgs.text(keywords=query, max_results=5):
|
||||
results.append({
|
||||
"title": result.get("title", ""),
|
||||
"url": result.get("href", ""),
|
||||
"snippet": result.get("body", "")
|
||||
})
|
||||
return results
|
||||
Returns:
|
||||
List[Dict]: List of search results containing title, URL, and snippet
|
||||
"""
|
||||
results = []
|
||||
ddgs = DDGS()
|
||||
for result in ddgs.text(keywords=query, max_results=5):
|
||||
results.append({
|
||||
"title": result.get("title", ""),
|
||||
"url": result.get("href", ""),
|
||||
"snippet": result.get("body", "")
|
||||
})
|
||||
return results
|
||||
|
||||
# 2. Assign the tool to an agent
|
||||
data_agent = Agent(
|
||||
name="DataCollector",
|
||||
role="Search Specialist",
|
||||
goal="Perform internet searches to collect relevant information.",
|
||||
backstory="Expert in finding and organising internet data.",
|
||||
tools=[internet_search_tool],
|
||||
self_reflect=False
|
||||
)
|
||||
# 2. Assign the tool to an agent
|
||||
data_agent = Agent(
|
||||
name="DataCollector",
|
||||
role="Search Specialist",
|
||||
goal="Perform internet searches to collect relevant information.",
|
||||
backstory="Expert in finding and organising internet data.",
|
||||
tools=[internet_search_tool],
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# 3. Task Definition
|
||||
collect_task = Task(
|
||||
description="Perform an internet search using the query: 'AI job trends in 2024'. Return results as a list of title, URL, and snippet.",
|
||||
expected_output="List of search results with titles, URLs, and snippets.",
|
||||
agent=data_agent,
|
||||
name="collect_data",
|
||||
)
|
||||
# 3. Task Definition
|
||||
collect_task = Task(
|
||||
description="Perform an internet search using the query: 'AI job trends in 2024'. Return results as a list of title, URL, and snippet.",
|
||||
expected_output="List of search results with titles, URLs, and snippets.",
|
||||
agent=data_agent,
|
||||
name="collect_data",
|
||||
)
|
||||
|
||||
# 4. Start Agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[data_agent],
|
||||
tasks=[collect_task],
|
||||
process="sequential"
|
||||
)
|
||||
# 4. Start Agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[data_agent],
|
||||
tasks=[collect_task],
|
||||
process="sequential"
|
||||
)
|
||||
|
||||
agents.start()
|
||||
```
|
||||
agents.start()
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Execute your script:
|
||||
```bash Terminal
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
<Steps>
|
||||
<Step title="Install PraisonAI">
|
||||
Install the core package and duckduckgo_search package:
|
||||
```bash Terminal
|
||||
pip install praisonai duckduckgo_search
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create Custom Tool">
|
||||
<Info>
|
||||
To add additional tools/features you need some coding which can be generated using ChatGPT or any LLM
|
||||
</Info>
|
||||
Create a new file `tools.py` with the following content:
|
||||
```python
|
||||
from duckduckgo_search import DDGS
|
||||
from typing import List, Dict
|
||||
|
||||
# 1. Tool
|
||||
def internet_search_tool(query: str) -> List[Dict]:
|
||||
"""
|
||||
Perform Internet Search
|
||||
"""
|
||||
results = []
|
||||
ddgs = DDGS()
|
||||
for result in ddgs.text(keywords=query, max_results=5):
|
||||
results.append({
|
||||
"title": result.get("title", ""),
|
||||
"url": result.get("href", ""),
|
||||
"snippet": result.get("body", "")
|
||||
})
|
||||
return results
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create Agent">
|
||||
|
||||
Create a new file `agents.yaml` with the following content:
|
||||
```yaml
|
||||
framework: praisonai
|
||||
topic: create movie script about cat in mars
|
||||
roles:
|
||||
scriptwriter:
|
||||
backstory: Expert in dialogue and script structure, translating concepts into
|
||||
scripts.
|
||||
goal: Write a movie script about a cat in Mars
|
||||
role: Scriptwriter
|
||||
tools:
|
||||
- internet_search_tool # <-- Tool assigned to Agent here
|
||||
tasks:
|
||||
scriptwriting_task:
|
||||
description: Turn the story concept into a production-ready movie script,
|
||||
including dialogue and scene details.
|
||||
expected_output: Final movie script with dialogue and scene details.
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
|
||||
Execute your script:
|
||||
```bash Terminal
|
||||
praisonai agents.yaml
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## In-build Tools in PraisonAI
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Search Tools" icon="magnifying-glass" href="/tools/search">
|
||||
Tools for searching and retrieving information from various sources
|
||||
</Card>
|
||||
<Card title="Python Tools" icon="python" href="/tools/python_tools">
|
||||
Essential Python utilities for data manipulation and scripting
|
||||
</Card>
|
||||
<Card title="Spider Tools" icon="spider" href="/tools/spider_tools">
|
||||
Web crawling and scraping capabilities for data extraction
|
||||
</Card>
|
||||
<Card title="Arxiv Tools" icon="book" href="/tools/arxiv_tools">
|
||||
Access and search academic papers from arXiv repository
|
||||
</Card>
|
||||
<Card title="Newspaper Tools" icon="newspaper" href="/tools/newspaper_tools">
|
||||
Extract and parse content from news articles and websites
|
||||
</Card>
|
||||
<Card title="DuckDB Tools" icon="database" href="/tools/duckdb_tools">
|
||||
Fast analytical SQL database operations and queries
|
||||
</Card>
|
||||
<Card title="DuckDuckGo Tools" icon="duck" href="/tools/duckduckgo_tools">
|
||||
Web search functionality using DuckDuckGo's API
|
||||
</Card>
|
||||
<Card title="Calculator Tools" icon="calculator" href="/tools/calculator_tools">
|
||||
Perform mathematical calculations and conversions
|
||||
</Card>
|
||||
<Card title="YAML Tools" icon="file-code" href="/tools/yaml_tools">
|
||||
Parse and manipulate YAML format data
|
||||
</Card>
|
||||
<Card title="JSON Tools" icon="brackets-curly" href="/tools/json_tools">
|
||||
Handle JSON data structures and operations
|
||||
</Card>
|
||||
<Card title="Pandas Tools" icon="table" href="/tools/pandas_tools">
|
||||
Data analysis and manipulation using Pandas
|
||||
</Card>
|
||||
<Card title="YFinance Tools" icon="chart-line" href="/tools/yfinance_tools">
|
||||
Fetch financial market data from Yahoo Finance
|
||||
</Card>
|
||||
<Card title="Shell Tools" icon="terminal" href="/tools/shell_tools">
|
||||
Execute shell commands and system operations
|
||||
</Card>
|
||||
<Card title="Wikipedia Tools" icon="book-open" href="/tools/wikipedia_tools">
|
||||
Access and search Wikipedia articles and data
|
||||
</Card>
|
||||
<Card title="XML Tools" icon="code" href="/tools/xml_tools">
|
||||
Process and manipulate XML format data
|
||||
</Card>
|
||||
<Card title="File Tools" icon="file" href="/tools/file_tools">
|
||||
File system operations and management utilities
|
||||
</Card>
|
||||
<Card title="Excel Tools" icon="file-excel" href="/tools/excel_tools">
|
||||
Work with Excel spreadsheets and workbooks
|
||||
</Card>
|
||||
<Card title="CSV Tools" icon="file-csv" href="/tools/csv_tools">
|
||||
Handle CSV file operations and transformations
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Tools Overview
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card
|
||||
title="Search Tools"
|
||||
icon="magnifying-glass"
|
||||
iconType="solid"
|
||||
>
|
||||
Tools for searching and retrieving information from various sources
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title="File Tools"
|
||||
icon="file"
|
||||
iconType="solid"
|
||||
>
|
||||
Tools for reading, writing, and manipulating files
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title="API Tools"
|
||||
icon="code"
|
||||
iconType="solid"
|
||||
>
|
||||
Tools for interacting with external APIs and services
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Advanced Tool Features
|
||||
|
||||
### Tool Configuration
|
||||
<Frame>
|
||||
<div className="p-4 bg-white dark:bg-gray-800 rounded-lg">
|
||||
```python
|
||||
def configured_tool(
|
||||
query: str,
|
||||
max_results: int = 5,
|
||||
timeout: int = 10
|
||||
) -> List[Dict]:
|
||||
"""
|
||||
Example of a configurable tool
|
||||
```python
|
||||
def configured_tool(
|
||||
query: str,
|
||||
max_results: int = 5,
|
||||
timeout: int = 10
|
||||
) -> List[Dict]:
|
||||
"""
|
||||
Example of a configurable tool
|
||||
|
||||
Args:
|
||||
query (str): Search query
|
||||
max_results (int): Maximum number of results
|
||||
timeout (int): Request timeout in seconds
|
||||
|
||||
Args:
|
||||
query (str): Search query
|
||||
max_results (int): Maximum number of results
|
||||
timeout (int): Request timeout in seconds
|
||||
|
||||
Returns:
|
||||
List[Dict]: Search results
|
||||
"""
|
||||
# Tool implementation
|
||||
pass
|
||||
```
|
||||
</div>
|
||||
Returns:
|
||||
List[Dict]: Search results
|
||||
"""
|
||||
# Tool implementation
|
||||
pass
|
||||
```
|
||||
</Frame>
|
||||
|
||||
### Tool Chaining
|
||||
<Frame>
|
||||
<div className="p-4 bg-white dark:bg-gray-800 rounded-lg">
|
||||
```python
|
||||
def chain_tools(input_data: str) -> Dict:
|
||||
"""
|
||||
Example of chaining multiple tools
|
||||
```python
|
||||
def chain_tools(input_data: str) -> Dict:
|
||||
"""
|
||||
Example of chaining multiple tools
|
||||
|
||||
Args:
|
||||
input_data (str): Input data
|
||||
|
||||
Args:
|
||||
input_data (str): Input data
|
||||
|
||||
Returns:
|
||||
Dict: Processed results
|
||||
"""
|
||||
# 1. Search for data
|
||||
search_results = internet_search_tool(input_data)
|
||||
|
||||
# 2. Process results
|
||||
processed_data = process_tool(search_results)
|
||||
|
||||
# 3. Format output
|
||||
return format_tool(processed_data)
|
||||
```
|
||||
</div>
|
||||
Returns:
|
||||
Dict: Processed results
|
||||
"""
|
||||
# 1. Search for data
|
||||
search_results = internet_search_tool(input_data)
|
||||
|
||||
# 2. Process results
|
||||
processed_data = process_tool(search_results)
|
||||
|
||||
# 3. Format output
|
||||
return format_tool(processed_data)
|
||||
```
|
||||
</Frame>
|
||||
|
||||
### Tool Categories
|
||||
|
||||
1. **Data Collection Tools**
|
||||
- Web scraping
|
||||
- API integration
|
||||
- Database queries
|
||||
|
||||
2. **Processing Tools**
|
||||
- Data transformation
|
||||
- Text analysis
|
||||
- Image processing
|
||||
|
||||
3. **Output Tools**
|
||||
- File generation
|
||||
- Report creation
|
||||
- Data visualization
|
||||
<CardGroup cols={3}>
|
||||
<Card title="Data Collection Tools">
|
||||
- Web scraping
|
||||
- API integration
|
||||
- Database queries
|
||||
</Card>
|
||||
|
||||
<Card title="Processing Tools">
|
||||
- Data transformation
|
||||
- Text analysis
|
||||
- Image processing
|
||||
</Card>
|
||||
|
||||
<Card title="Output Tools">
|
||||
- File generation
|
||||
- Report creation
|
||||
- Data visualization
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Tool Integration
|
||||
|
||||
### Adding Tools to Agents
|
||||
<Frame>
|
||||
<div className="p-4 bg-white dark:bg-gray-800 rounded-lg">
|
||||
```python
|
||||
# Multiple tools
|
||||
agent = Agent(
|
||||
name="MultiTool Agent",
|
||||
tools=[
|
||||
internet_search_tool,
|
||||
file_processing_tool,
|
||||
api_integration_tool
|
||||
]
|
||||
)
|
||||
```
|
||||
</div>
|
||||
```python
|
||||
# Multiple tools
|
||||
agent = Agent(
|
||||
name="MultiTool Agent",
|
||||
tools=[
|
||||
internet_search_tool,
|
||||
file_processing_tool,
|
||||
api_integration_tool
|
||||
]
|
||||
)
|
||||
```
|
||||
</Frame>
|
||||
|
||||
### Tool Dependencies
|
||||
<Frame>
|
||||
<div className="p-4 bg-white dark:bg-gray-800 rounded-lg">
|
||||
```python
|
||||
# Tool with dependencies
|
||||
def advanced_tool(data: Dict) -> Dict:
|
||||
"""
|
||||
Tool that depends on external libraries
|
||||
```python
|
||||
# Tool with dependencies
|
||||
def advanced_tool(data: Dict) -> Dict:
|
||||
"""
|
||||
Tool that depends on external libraries
|
||||
|
||||
Args:
|
||||
data (Dict): Input data
|
||||
|
||||
Args:
|
||||
data (Dict): Input data
|
||||
|
||||
Returns:
|
||||
Dict: Processed data
|
||||
"""
|
||||
try:
|
||||
import required_library
|
||||
# Tool implementation
|
||||
return processed_result
|
||||
except ImportError:
|
||||
raise Exception("Required library not installed")
|
||||
```
|
||||
</div>
|
||||
Returns:
|
||||
Dict: Processed data
|
||||
"""
|
||||
try:
|
||||
import required_library
|
||||
# Tool implementation
|
||||
return processed_result
|
||||
except ImportError:
|
||||
raise Exception("Required library not installed")
|
||||
```
|
||||
</Frame>
|
||||
|
||||
## Tool Guidelines
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="p-4 border rounded-lg bg-white dark:bg-gray-800">
|
||||
<h3 className="text-lg font-semibold mb-3">Best Practices</h3>
|
||||
1. **Type Hints**
|
||||
- Use Python type hints
|
||||
- Define clear input/output types
|
||||
- Document complex types
|
||||
|
||||
2. **Documentation**
|
||||
- Write clear docstrings
|
||||
- Explain parameters
|
||||
- Provide usage examples
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Best Practices">
|
||||
1. **Type Hints**
|
||||
- Use Python type hints
|
||||
- Define clear input/output types
|
||||
- Document complex types
|
||||
|
||||
3. **Error Handling**
|
||||
- Handle exceptions gracefully
|
||||
- Return meaningful errors
|
||||
- Validate inputs
|
||||
</div>
|
||||
2. **Documentation**
|
||||
- Write clear docstrings
|
||||
- Explain parameters
|
||||
- Provide usage examples
|
||||
|
||||
<div className="p-4 border rounded-lg bg-white dark:bg-gray-800">
|
||||
<h3 className="text-lg font-semibold mb-3">Tool Types</h3>
|
||||
1. **Search Tools**
|
||||
- Web search
|
||||
- Database queries
|
||||
- Document search
|
||||
3. **Error Handling**
|
||||
- Handle exceptions gracefully
|
||||
- Return meaningful errors
|
||||
- Validate inputs
|
||||
</Card>
|
||||
|
||||
2. **File Tools**
|
||||
- Read/write operations
|
||||
- File conversion
|
||||
- Data extraction
|
||||
<Card title="Tool Types">
|
||||
1. **Search Tools**
|
||||
- Web search
|
||||
- Database queries
|
||||
- Document search
|
||||
|
||||
3. **API Tools**
|
||||
- REST API calls
|
||||
- GraphQL queries
|
||||
- Service integration
|
||||
</div>
|
||||
</div>
|
||||
2. **File Tools**
|
||||
- Read/write operations
|
||||
- File conversion
|
||||
- Data extraction
|
||||
|
||||
3. **API Tools**
|
||||
- REST API calls
|
||||
- GraphQL queries
|
||||
- Service integration
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Best Practices Summary
|
||||
|
||||
1. **Design Principles**
|
||||
- Single responsibility
|
||||
- Clear interfaces
|
||||
- Proper documentation
|
||||
- Error handling
|
||||
<Note>
|
||||
Following these best practices will help you create robust, efficient, and secure tools in PraisonAI.
|
||||
</Note>
|
||||
|
||||
2. **Performance**
|
||||
- Efficient processing
|
||||
- Resource management
|
||||
- Caching when appropriate
|
||||
- Asynchronous operations
|
||||
<CardGroup cols={1}>
|
||||
<Card title="Design Principles" icon="compass-drafting" iconType="solid">
|
||||
<AccordionGroup>
|
||||
<Accordion title="Single Responsibility">
|
||||
Each tool should have one clear purpose and do it well. Avoid creating tools that try to do too many things.
|
||||
```python
|
||||
# Good Example
|
||||
def process_image(image: np.array) -> np.array:
|
||||
return processed_image
|
||||
|
||||
3. **Security**
|
||||
- Input validation
|
||||
- Rate limiting
|
||||
- API key management
|
||||
- Error masking
|
||||
# Avoid
|
||||
def process_and_save_and_upload(image):
|
||||
# Too many responsibilities
|
||||
pass
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Clear Interfaces">
|
||||
Define explicit input/output types and maintain consistent parameter naming.
|
||||
```python
|
||||
def search_tool(
|
||||
query: str,
|
||||
max_results: int = 10
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Search for information with clear parameters
|
||||
"""
|
||||
pass
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Documentation">
|
||||
Always include detailed docstrings and type hints.
|
||||
```python
|
||||
def analyze_text(
|
||||
text: str,
|
||||
language: str = "en"
|
||||
) -> Dict[str, float]:
|
||||
"""
|
||||
Analyze text sentiment and emotions.
|
||||
|
||||
Args:
|
||||
text: Input text to analyze
|
||||
language: ISO language code
|
||||
|
||||
Returns:
|
||||
Dict with sentiment scores
|
||||
"""
|
||||
pass
|
||||
```
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<br />
|
||||
|
||||
<CardGroup cols={1}>
|
||||
<Card title="Performance Optimization" icon="bolt" iconType="solid">
|
||||
<AccordionGroup>
|
||||
<Accordion title="Efficient Processing">
|
||||
Optimize resource usage and processing time.
|
||||
```python
|
||||
# Use generators for large datasets
|
||||
def process_large_data():
|
||||
for chunk in data_generator():
|
||||
yield process_chunk(chunk)
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Resource Management">
|
||||
Properly handle resource allocation and cleanup.
|
||||
```python
|
||||
async with aiohttp.ClientSession() as session:
|
||||
# Resource automatically managed
|
||||
await process_data(session)
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Caching">
|
||||
Implement caching for frequently accessed data.
|
||||
```python
|
||||
@cache.memoize(timeout=300)
|
||||
def expensive_operation(data: str) -> Dict:
|
||||
return process_expensive(data)
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Async Operations">
|
||||
Use async/await for I/O-bound operations.
|
||||
```python
|
||||
async def fetch_data(urls: List[str]):
|
||||
async with aiohttp.ClientSession() as session:
|
||||
tasks = [fetch_url(session, url) for url in urls]
|
||||
return await asyncio.gather(*tasks)
|
||||
```
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<br />
|
||||
|
||||
<CardGroup cols={1}>
|
||||
<Card title="Security Best Practices" icon="shield-check" iconType="solid">
|
||||
<AccordionGroup>
|
||||
<Accordion title="Input Validation">
|
||||
Always validate and sanitize inputs to prevent security vulnerabilities.
|
||||
```python
|
||||
def process_user_input(data: str) -> str:
|
||||
if not isinstance(data, str):
|
||||
raise ValueError("Input must be string")
|
||||
return sanitize_input(data.strip())
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Rate Limiting">
|
||||
Implement rate limiting for API calls to prevent abuse.
|
||||
```python
|
||||
@rate_limit(calls=100, period=60)
|
||||
async def api_call():
|
||||
return await make_request()
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="API Key Management">
|
||||
Securely handle API keys and credentials using environment variables.
|
||||
```python
|
||||
# Use environment variables
|
||||
api_key = os.getenv('API_KEY')
|
||||
if not api_key:
|
||||
raise ConfigError("API key not found")
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Error Masking">
|
||||
Hide sensitive information in error messages to prevent information leakage.
|
||||
```python
|
||||
try:
|
||||
result = process_sensitive_data()
|
||||
except Exception as e:
|
||||
# Log detailed error internally
|
||||
logger.error(f"Detailed error: {str(e)}")
|
||||
# Return sanitized error to user
|
||||
raise PublicError("Processing failed")
|
||||
```
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<br />
|
||||
|
||||
<Tip>
|
||||
**Pro Tip**: Start with these practices from the beginning of your project. It's easier to maintain good practices than to retrofit them later.
|
||||
</Tip>
|
||||
@@ -0,0 +1,224 @@
|
||||
---
|
||||
title: "Agentic Routing"
|
||||
description: "Learn how to create AI agents with dynamic routing capabilities for workflow management."
|
||||
icon: "route"
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `app.py` with the basic setup:
|
||||
```python
|
||||
from praisonaiagents.agent import Agent
|
||||
from praisonaiagents.task import Task
|
||||
from praisonaiagents.agents import PraisonAIAgents
|
||||
import time
|
||||
|
||||
def get_time_check():
|
||||
current_time = int(time.time())
|
||||
result = "even" if current_time % 2 == 0 else "odd"
|
||||
print(f"Time check: {current_time} is {result}")
|
||||
return result
|
||||
|
||||
# Create specialized agents
|
||||
router = Agent(
|
||||
name="Router",
|
||||
role="Input Router",
|
||||
goal="Evaluate input and determine routing path",
|
||||
instructions="Analyze input and decide whether to proceed or exit",
|
||||
tools=[get_time_check]
|
||||
)
|
||||
|
||||
processor1 = Agent(
|
||||
name="Processor 1",
|
||||
role="Secondary Processor",
|
||||
goal="Process valid inputs that passed initial check",
|
||||
instructions="Process data that passed the routing check"
|
||||
)
|
||||
|
||||
processor2 = Agent(
|
||||
name="Processor 2",
|
||||
role="Final Processor",
|
||||
goal="Perform final processing on validated data",
|
||||
instructions="Generate final output for processed data"
|
||||
)
|
||||
|
||||
# Create tasks with routing logic
|
||||
routing_task = Task(
|
||||
name="initial_routing",
|
||||
description="check the time and return according to what is returned",
|
||||
expected_output="pass or fail based on what is returned",
|
||||
agent=router,
|
||||
is_start=True,
|
||||
task_type="decision",
|
||||
condition={
|
||||
"pass": ["process_valid"],
|
||||
"fail": ["process_invalid"]
|
||||
}
|
||||
)
|
||||
|
||||
processing_task = Task(
|
||||
name="process_valid",
|
||||
description="Process validated input",
|
||||
expected_output="Processed data ready for final step",
|
||||
agent=processor1,
|
||||
)
|
||||
|
||||
final_task = Task(
|
||||
name="process_invalid",
|
||||
description="Generate final output",
|
||||
expected_output="Final processed result",
|
||||
agent=processor2
|
||||
)
|
||||
|
||||
# Create and run workflow
|
||||
workflow = PraisonAIAgents(
|
||||
agents=[router, processor1, processor2],
|
||||
tasks=[routing_task, processing_task, final_task],
|
||||
process="workflow",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
print("\nStarting Routing Workflow...")
|
||||
print("=" * 50)
|
||||
|
||||
results = workflow.start()
|
||||
|
||||
print("\nWorkflow Results:")
|
||||
print("=" * 50)
|
||||
for task_id, result in results["task_results"].items():
|
||||
if result:
|
||||
task_name = result.description
|
||||
print(f"\nTask: {task_name}")
|
||||
print(f"Result: {result.raw}")
|
||||
print("-" * 50)
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Note>
|
||||
**Requirements**
|
||||
- Python 3.10 or higher
|
||||
- OpenAI API key. Generate OpenAI API key [here](https://platform.openai.com/api-keys). Use Other models using [this guide](/models).
|
||||
- Basic understanding of Python
|
||||
</Note>
|
||||
|
||||
<div className="relative w-full aspect-video">
|
||||
<iframe
|
||||
className="absolute top-0 left-0 w-full h-full"
|
||||
src="https://www.youtube.com/embed/KNDVWGN3TpM"
|
||||
title="YouTube video player"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
## Understanding Agentic Routing
|
||||
|
||||
<Card title="What is Agentic Routing?" icon="question">
|
||||
Agentic routing enables:
|
||||
- Dynamic decision-making in workflows
|
||||
- Conditional task execution paths
|
||||
- Automated process branching
|
||||
- Intelligent workflow management
|
||||
</Card>
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Dynamic Routing" icon="route">
|
||||
Route tasks based on real-time decisions and conditions.
|
||||
</Card>
|
||||
<Card title="Conditional Logic" icon="code-branch">
|
||||
Implement complex branching logic in workflows.
|
||||
</Card>
|
||||
<Card title="Task Management" icon="tasks">
|
||||
Handle task dependencies and execution order.
|
||||
</Card>
|
||||
<Card title="Process Control" icon="sliders">
|
||||
Control workflow execution with detailed monitoring.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Configuration Options
|
||||
|
||||
```python
|
||||
# Create a router agent
|
||||
router = Agent(
|
||||
name="Router",
|
||||
role="Input Router",
|
||||
goal="Evaluate input and determine routing path",
|
||||
instructions="Analyze input and decide whether to proceed or exit",
|
||||
tools=[get_time_check], # Custom tools for routing decisions
|
||||
verbose=True # Enable detailed logging
|
||||
)
|
||||
|
||||
# Task with routing configuration
|
||||
routing_task = Task(
|
||||
name="initial_routing",
|
||||
description="Route based on conditions",
|
||||
expected_output="Routing decision",
|
||||
agent=router,
|
||||
is_start=True,
|
||||
task_type="decision",
|
||||
condition={
|
||||
"pass": ["next_task"],
|
||||
"fail": ["alternate_task"]
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Routing Issues" icon="triangle-exclamation">
|
||||
If routing doesn't work as expected:
|
||||
- Verify condition mappings
|
||||
- Check task dependencies
|
||||
- Enable verbose mode for debugging
|
||||
</Card>
|
||||
|
||||
<Card title="Workflow Flow" icon="diagram-project">
|
||||
If workflow is unclear:
|
||||
- Review task connections
|
||||
- Verify agent configurations
|
||||
- Check routing conditions
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="AutoAgents" icon="robot" href="./autoagents">
|
||||
Learn about automatically created and managed AI agents
|
||||
</Card>
|
||||
<Card title="Mini Agents" icon="microchip" href="./mini">
|
||||
Explore lightweight, focused AI agents
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Note>
|
||||
For optimal results, ensure your routing conditions are well-defined and your task dependencies are properly configured.
|
||||
</Note>
|
||||
+136
-69
@@ -1,82 +1,126 @@
|
||||
---
|
||||
title: "Async AI Agents"
|
||||
title: "Async Agents"
|
||||
description: "Async AI Agents allow you to run AI tasks asynchronously, improving performance and efficiency in your applications."
|
||||
icon: "clock"
|
||||
---
|
||||
|
||||
<Note>
|
||||
**Requirements**
|
||||
|
||||
- Python 3.10 or higher
|
||||
- Basic understanding of async/await in Python
|
||||
</Note>
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create Project">
|
||||
Create a new file `app.py` with the basic setup:
|
||||
```python
|
||||
import asyncio
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
<Step title="Create Project">
|
||||
Create a new file `app.py` with the basic setup:
|
||||
```python
|
||||
import asyncio
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create an agent
|
||||
agent = Agent(
|
||||
name="AsyncAgent",
|
||||
role="Assistant",
|
||||
goal="Help with tasks",
|
||||
backstory="Expert in async operations"
|
||||
)
|
||||
# Create an agent
|
||||
agent = Agent(
|
||||
name="AsyncAgent",
|
||||
role="Assistant",
|
||||
goal="Help with tasks",
|
||||
backstory="Expert in async operations"
|
||||
)
|
||||
|
||||
# Create a task
|
||||
task = Task(
|
||||
name="hello_task",
|
||||
description="Say hello and introduce yourself",
|
||||
agent=agent,
|
||||
async_execution=True,
|
||||
expected_output="Answer to the question"
|
||||
)
|
||||
# Create a task
|
||||
task = Task(
|
||||
name="hello_task",
|
||||
description="Say hello and introduce yourself",
|
||||
agent=agent,
|
||||
async_execution=True,
|
||||
expected_output="Answer to the question"
|
||||
)
|
||||
|
||||
# Create agents manager
|
||||
agents = PraisonAIAgents(
|
||||
agents=[agent],
|
||||
tasks=[task],
|
||||
process="sequential"
|
||||
)
|
||||
# Create agents manager
|
||||
agents = PraisonAIAgents(
|
||||
agents=[agent],
|
||||
tasks=[task],
|
||||
process="sequential"
|
||||
)
|
||||
|
||||
# Main async function
|
||||
async def main():
|
||||
result = await agents.astart()
|
||||
print(result)
|
||||
# Main async function
|
||||
async def main():
|
||||
result = await agents.astart()
|
||||
print(result)
|
||||
|
||||
# Run the program
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
# Run the program
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
</Step>
|
||||
|
||||
```
|
||||
</Step>
|
||||
<Step title="Run the Program">
|
||||
Run your async AI agent:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
Install the PraisonAI package:
|
||||
```bash
|
||||
pip install praisonai
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create Project">
|
||||
Create a new file `agents.yaml` with the basic setup:
|
||||
```yaml
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
topic: async operations
|
||||
roles:
|
||||
assistant:
|
||||
name: AsyncAgent
|
||||
role: Assistant
|
||||
goal: Help with tasks
|
||||
backstory: Expert in async operations
|
||||
tasks:
|
||||
hello_task:
|
||||
description: Say hello and introduce yourself
|
||||
expected_output: Answer to the question
|
||||
async_execution: true
|
||||
```
|
||||
</Step>
|
||||
<Step title="Run the Program">
|
||||
Run your async AI agent:
|
||||
```bash
|
||||
praisonai agents.yaml
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Step title="Run the Program">
|
||||
Run your async AI agent:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
<Note>
|
||||
**Requirements**
|
||||
- Python 3.10 or higher
|
||||
- OpenAI API key. Generate OpenAI API key [here](https://platform.openai.com/api-keys). Use Other models using [this guide](/models).
|
||||
- Basic understanding of async/await in Python
|
||||
</Note>
|
||||
|
||||
<div className="relative w-full aspect-video">
|
||||
<iframe
|
||||
@@ -129,7 +173,9 @@ icon: "clock"
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Async Tasks with Callbacks and Tools Example Code
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
### Async Tasks with Callbacks and Tools Example Code
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
@@ -357,7 +403,6 @@ async def main():
|
||||
if __name__ == "__main__":
|
||||
# Run the main function
|
||||
asyncio.run(main())
|
||||
|
||||
```
|
||||
|
||||
### 1. Async Tasks with Callbacks
|
||||
@@ -402,6 +447,28 @@ async def process_multiple_tasks():
|
||||
)
|
||||
return results
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
```yaml
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
topic: async operations
|
||||
roles:
|
||||
async_agent:
|
||||
name: AsyncSearchAgent
|
||||
role: Asynchronous Search Specialist
|
||||
goal: Perform fast and efficient asynchronous searches
|
||||
backstory: Expert in parallel search operations
|
||||
tools:
|
||||
- async_search_tool
|
||||
tasks:
|
||||
search_task:
|
||||
description: Perform async search operations
|
||||
expected_output: Structured search results
|
||||
async_execution: true
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Best Practices
|
||||
|
||||
@@ -481,11 +548,11 @@ async def process_multiple_tasks():
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Examples" icon="code" href="./examples">
|
||||
Check out more examples in our examples directory
|
||||
<Card title="AutoAgents" icon="robot" href="./autoagents">
|
||||
Learn about automatically created and managed AI agents
|
||||
</Card>
|
||||
<Card title="Advanced Topics" icon="book" href="./advanced">
|
||||
Learn about advanced async patterns and optimizations
|
||||
<Card title="Mini Agents" icon="microchip" href="./mini">
|
||||
Explore lightweight, focused AI agents
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
|
||||
@@ -0,0 +1,308 @@
|
||||
---
|
||||
title: "AutoAgents"
|
||||
description: "AutoAgents automatically creates and manages AI agents and tasks based on high-level instructions."
|
||||
icon: "robot"
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents duckduckgo_search
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `app.py` with the basic setup:
|
||||
```python
|
||||
from praisonaiagents import AutoAgents
|
||||
from praisonaiagents.tools import duckduckgo
|
||||
|
||||
# Create AutoAgents instance
|
||||
agents = AutoAgents(
|
||||
instructions="Search for information about AI Agents",
|
||||
tools=[duckduckgo],
|
||||
process="sequential",
|
||||
verbose=True,
|
||||
max_agents=3 # Maximum number of agents to create
|
||||
)
|
||||
|
||||
# Start the agents
|
||||
result = agents.start()
|
||||
print(result)
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start AutoAgents">
|
||||
Run your AutoAgents:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Note>
|
||||
**Requirements**
|
||||
|
||||
- Python 3.10 or higher
|
||||
- OpenAI API key. Generate OpenAI API key [here](https://platform.openai.com/api-keys). Use Other models using [this guide](/models).
|
||||
</Note>
|
||||
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
Install the PraisonAI package:
|
||||
```bash
|
||||
pip install praisonai
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
<Step title="Start AutoAgents">
|
||||
Run your AutoAgents:
|
||||
```bash
|
||||
praisonai --auto "Create a movie script about a robot in Mars"
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Understanding AutoAgents
|
||||
|
||||
<Card title="What are AutoAgents?" icon="question">
|
||||
AutoAgents automatically:
|
||||
- Creates appropriate AI agents based on your instructions
|
||||
- Assigns relevant tools to each agent
|
||||
- Breaks down tasks into manageable steps
|
||||
- Manages execution flow between agents
|
||||
- Handles agent coordination and task delegation
|
||||
</Card>
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Automatic Agent Creation" icon="wand-magic-sparkles">
|
||||
Creates specialized agents based on task requirements.
|
||||
</Card>
|
||||
<Card title="Smart Tool Assignment" icon="toolbox">
|
||||
Automatically assigns relevant tools to each agent.
|
||||
</Card>
|
||||
<Card title="Task Management" icon="list-check">
|
||||
Breaks down complex tasks into manageable steps.
|
||||
</Card>
|
||||
<Card title="Process Optimization" icon="gauge-high">
|
||||
Chooses optimal execution process (sequential/hierarchical).
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<CodeGroup>
|
||||
```python Basic
|
||||
# Basic usage with default settings
|
||||
agents = AutoAgents(
|
||||
instructions="Your high-level task description",
|
||||
tools=[tool1, tool2]
|
||||
)
|
||||
```
|
||||
|
||||
```python Advanced
|
||||
# Advanced usage with custom settings
|
||||
agents = AutoAgents(
|
||||
instructions="Your task description",
|
||||
tools=[tool1, tool2],
|
||||
max_agents=3,
|
||||
process="hierarchical",
|
||||
verbose=True,
|
||||
memory=True,
|
||||
allow_delegation=True
|
||||
)
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Configuration Options
|
||||
|
||||
```python
|
||||
|
||||
# Create AutoAgents with advanced configuration
|
||||
agents = AutoAgents(
|
||||
instructions="Research and summarize recent AI developments",
|
||||
tools=[SerperDevTool, WikipediaTools],
|
||||
max_agents=3, # Maximum number of agents to create
|
||||
verbose=True, # Enable detailed logging
|
||||
process="hierarchical", # Use hierarchical process
|
||||
memory=True, # Enable memory for agents
|
||||
allow_delegation=True, # Allow task delegation
|
||||
max_rpm=60, # Maximum requests per minute
|
||||
max_execution_time=300, # Maximum execution time in seconds
|
||||
allow_code_execution=True, # Allow code execution
|
||||
code_execution_mode="safe", # Use safe mode for code execution
|
||||
self_reflect=True, # Enable agent self-reflection
|
||||
markdown=True # Enable markdown formatting
|
||||
)
|
||||
```
|
||||
|
||||
### Process Types
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Sequential Process">
|
||||
```python
|
||||
# Tasks are executed in sequence
|
||||
agents = AutoAgents(
|
||||
instructions="Your task",
|
||||
process="sequential"
|
||||
)
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Hierarchical Process">
|
||||
```python
|
||||
# Manager agent coordinates other agents
|
||||
agents = AutoAgents(
|
||||
instructions="Your task",
|
||||
process="hierarchical",
|
||||
manager_llm="gpt-4o" # Specify LLM for manager
|
||||
)
|
||||
```
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Best Practices
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Clear Instructions">
|
||||
```python
|
||||
# Good instruction example
|
||||
agents = AutoAgents(
|
||||
instructions="""
|
||||
Research the latest developments in AI for 2024:
|
||||
1. Focus on breakthrough technologies
|
||||
2. Include real-world applications
|
||||
3. Consider future implications
|
||||
"""
|
||||
)
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Tool Selection">
|
||||
```python
|
||||
# Provide relevant tools for the task
|
||||
|
||||
agents = AutoAgents(
|
||||
instructions="Research task",
|
||||
tools=[
|
||||
SerperDevTool, # For web search
|
||||
WikipediaTools, # For background info
|
||||
CustomTool # Your custom tool
|
||||
]
|
||||
)
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Resource Management">
|
||||
|
||||
```python
|
||||
# Configure resource limits
|
||||
agents = AutoAgents(
|
||||
instructions="Your task",
|
||||
max_rpm=60, # Rate limiting
|
||||
max_execution_time=300, # Timeout
|
||||
max_agents=3 # Agent limit
|
||||
)
|
||||
```
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Tool Assignment Issues" icon="triangle-exclamation">
|
||||
If tools aren't being assigned correctly:
|
||||
- Check tool compatibility
|
||||
- Verify tool names
|
||||
- Enable verbose mode for debugging
|
||||
</Card>
|
||||
|
||||
<Card title="Performance Issues" icon="gauge">
|
||||
If execution is slow:
|
||||
- Reduce max_agents
|
||||
- Adjust max_rpm
|
||||
- Consider process type
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## API Reference
|
||||
|
||||
### Main Parameters
|
||||
|
||||
<ResponseField name="instructions" type="str" required>
|
||||
High-level task description for the agents
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="tools" type="List[Any]">
|
||||
List of tools available to the agents
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="max_agents" type="int" default="3">
|
||||
Maximum number of agents to create
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="process" type="str" default="sequential">
|
||||
Process type: "sequential" or "hierarchical"
|
||||
</ResponseField>
|
||||
|
||||
### Optional Parameters
|
||||
|
||||
<ResponseField name="verbose" type="bool" default="False">
|
||||
Enable detailed logging
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="memory" type="bool" default="True">
|
||||
Enable agent memory
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="allow_delegation" type="bool" default="False">
|
||||
Allow agents to delegate tasks
|
||||
</ResponseField>
|
||||
|
||||
### Methods
|
||||
|
||||
<ResponseField name="start()" type="method">
|
||||
Start the agents synchronously
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="astart()" type="method">
|
||||
Start the agents asynchronously
|
||||
</ResponseField>
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Examples" icon="code" href="./examples">
|
||||
Explore more examples in our examples directory
|
||||
</Card>
|
||||
<Card title="Custom Tools" icon="screwdriver-wrench" href="./tools">
|
||||
Learn how to create custom tools for your agents
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Note>
|
||||
For optimal results, provide clear instructions and appropriate tools for your use case.
|
||||
</Note>
|
||||
+757
-564
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,353 @@
|
||||
---
|
||||
title: "Code Execution AI Agent"
|
||||
sidebarTitle: "Code Agent"
|
||||
description: "Learn how to create AI agents that can write and execute Python code safely using e2b code interpreter."
|
||||
icon: "code"
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the required packages:
|
||||
```bash
|
||||
pip install praisonaiagents e2b_code_interpreter
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key and E2B API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
export E2B_API_KEY=your_e2b_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `app.py` with the basic setup:
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from e2b_code_interpreter import Sandbox
|
||||
|
||||
def code_interpreter(code: str):
|
||||
print(f"\n{'='*50}\n> Running following AI-generated code:\n{code}\n{'='*50}")
|
||||
exec_result = Sandbox().run_code(code)
|
||||
if exec_result.error:
|
||||
print("[Code Interpreter error]", exec_result.error)
|
||||
return {"error": str(exec_result.error)}
|
||||
else:
|
||||
results = []
|
||||
for result in exec_result.results:
|
||||
if hasattr(result, '__iter__'):
|
||||
results.extend(list(result))
|
||||
else:
|
||||
results.append(str(result))
|
||||
logs = {"stdout": list(exec_result.logs.stdout), "stderr": list(exec_result.logs.stderr)}
|
||||
return json.dumps({"results": results, "logs": logs})
|
||||
|
||||
# Create code agent
|
||||
code_agent = Agent(
|
||||
role="Code Developer",
|
||||
goal="Write and execute Python code",
|
||||
backstory="Expert Python developer with strong coding skills",
|
||||
tools=[code_interpreter],
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Create a task
|
||||
task = Task(
|
||||
description="Write and execute a Python script to analyze data",
|
||||
expected_output="Working Python script with execution results",
|
||||
agent=code_agent
|
||||
)
|
||||
|
||||
# Create and start the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[code_agent],
|
||||
tasks=[task],
|
||||
process="sequential",
|
||||
verbose=2
|
||||
)
|
||||
|
||||
# Start execution
|
||||
agents.start()
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
Install the PraisonAI package:
|
||||
```bash
|
||||
pip install praisonai e2b_code_interpreter
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create a file">
|
||||
Create a new file `agents.yaml` with the basic setup:
|
||||
```yaml
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
topic: write and execute Python code
|
||||
roles:
|
||||
developer:
|
||||
backstory: Expert Python developer with strong coding skills.
|
||||
goal: Write and execute Python code safely
|
||||
role: Code Developer
|
||||
tools:
|
||||
- code_interpreter
|
||||
tasks:
|
||||
coding_task:
|
||||
description: Write and execute a Python script to analyze data.
|
||||
expected_output: Working Python script with execution results.
|
||||
```
|
||||
</Step>
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
praisonai agents.yaml
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Note>
|
||||
**Requirements**
|
||||
- Python 3.10 or higher
|
||||
- OpenAI API key. Generate OpenAI API key [here](https://platform.openai.com/api-keys). Use Other models using [this guide](/models).
|
||||
- e2b_code_interpreter package installed
|
||||
</Note>
|
||||
|
||||
## Understanding Code Agents
|
||||
|
||||
<Card title="What are Code Agents?" icon="question">
|
||||
Code agents are specialized AI agents that can:
|
||||
- Write Python code based on requirements
|
||||
- Execute code safely in a sandboxed environment
|
||||
- Handle code execution results and errors
|
||||
- Work together in a pipeline (writer → executor)
|
||||
</Card>
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Code Writer" icon="pencil">
|
||||
Writes Python code based on requirements.
|
||||
</Card>
|
||||
<Card title="Safe Execution" icon="shield">
|
||||
Executes code in a sandboxed environment.
|
||||
</Card>
|
||||
<Card title="Error Handling" icon="bug">
|
||||
Manages code execution errors and debugging.
|
||||
</Card>
|
||||
<Card title="Results Processing" icon="output">
|
||||
Processes and formats execution results.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Multi-Agent Code Development
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the required packages:
|
||||
```bash
|
||||
pip install praisonaiagents e2b_code_interpreter
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `app.py` with the basic setup:
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from e2b_code_interpreter import Sandbox
|
||||
|
||||
def code_interpreter(code: str):
|
||||
print(f"\n{'='*50}\n> Running following AI-generated code:\n{code}\n{'='*50}")
|
||||
exec_result = Sandbox().run_code(code)
|
||||
if exec_result.error:
|
||||
print("[Code Interpreter error]", exec_result.error)
|
||||
return {"error": str(exec_result.error)}
|
||||
else:
|
||||
results = []
|
||||
for result in exec_result.results:
|
||||
if hasattr(result, '__iter__'):
|
||||
results.extend(list(result))
|
||||
else:
|
||||
results.append(str(result))
|
||||
logs = {"stdout": list(exec_result.logs.stdout), "stderr": list(exec_result.logs.stderr)}
|
||||
return json.dumps({"results": results, "logs": logs})
|
||||
|
||||
# Create first agent for writing code
|
||||
code_writer = Agent(
|
||||
role="Code Writer",
|
||||
goal="Write efficient Python code",
|
||||
backstory="Expert Python developer specializing in code writing",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Create second agent for code execution
|
||||
code_executor = Agent(
|
||||
role="Code Executor",
|
||||
goal="Execute and validate Python code",
|
||||
backstory="Expert in code execution and testing",
|
||||
tools=[code_interpreter],
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Create first task
|
||||
writing_task = Task(
|
||||
description="Write a Python script for data analysis",
|
||||
expected_output="Complete Python script",
|
||||
agent=code_writer
|
||||
)
|
||||
|
||||
# Create second task
|
||||
execution_task = Task(
|
||||
description="Execute and validate the Python script",
|
||||
expected_output="Execution results and validation",
|
||||
agent=code_executor
|
||||
)
|
||||
|
||||
# Create and start the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[code_writer, code_executor],
|
||||
tasks=[writing_task, execution_task],
|
||||
process="sequential"
|
||||
)
|
||||
|
||||
# Start execution
|
||||
agents.start()
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
Install the PraisonAI package:
|
||||
```bash
|
||||
pip install praisonai e2b_code_interpreter
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create a file">
|
||||
Create a new file `agents.yaml` with the basic setup:
|
||||
```yaml
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
topic: develop and execute Python code
|
||||
roles:
|
||||
writer:
|
||||
backstory: Expert Python developer specializing in code writing.
|
||||
goal: Write efficient Python code
|
||||
role: Code Writer
|
||||
tasks:
|
||||
writing_task:
|
||||
description: Write a Python script for data analysis.
|
||||
expected_output: Complete Python script.
|
||||
|
||||
executor:
|
||||
backstory: Expert in code execution and testing.
|
||||
goal: Execute and validate Python code
|
||||
role: Code Executor
|
||||
tools:
|
||||
- code_interpreter
|
||||
tasks:
|
||||
execution_task:
|
||||
description: Execute and validate the Python script.
|
||||
expected_output: Execution results and validation.
|
||||
```
|
||||
</Step>
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
praisonai agents.yaml
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### Configuration Options
|
||||
|
||||
```python
|
||||
# Create an agent with advanced code execution configuration
|
||||
agent = Agent(
|
||||
role="Code Developer",
|
||||
goal="Write and execute Python code",
|
||||
backstory="Expert in Python development",
|
||||
tools=[code_interpreter],
|
||||
verbose=True, # Enable detailed logging
|
||||
llm="gpt-4o" # Language model to use
|
||||
)
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Code Errors" icon="triangle-exclamation">
|
||||
If code execution fails:
|
||||
- Check syntax errors
|
||||
- Verify package imports
|
||||
- Enable verbose mode for debugging
|
||||
</Card>
|
||||
|
||||
<Card title="Sandbox Issues" icon="box">
|
||||
If sandbox execution fails:
|
||||
- Check environment setup
|
||||
- Verify permissions
|
||||
- Review resource limits
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="AutoAgents" icon="robot" href="./autoagents">
|
||||
Learn about automatically created and managed AI agents
|
||||
</Card>
|
||||
<Card title="Mini Agents" icon="microchip" href="./mini">
|
||||
Explore lightweight, focused AI agents
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Note>
|
||||
For optimal results, ensure code is properly formatted and tested in the sandbox environment before production use.
|
||||
</Note>
|
||||
@@ -0,0 +1,219 @@
|
||||
---
|
||||
title: "LangChain Agents"
|
||||
sidebarTitle: "LangChain Agents"
|
||||
description: "Learn how to use LangChain tools and utilities with PraisonAI agents."
|
||||
icon: "link-simple"
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the required packages:
|
||||
```bash
|
||||
pip install praisonaiagents langchain-community wikipedia
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `app.py` with the basic setup:
|
||||
<CodeGroup>
|
||||
```python Single Tool
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from langchain_community.utilities import WikipediaAPIWrapper
|
||||
|
||||
# Create an agent with Wikipedia tool
|
||||
agent = Agent(
|
||||
name="WikiAgent",
|
||||
role="Research Assistant",
|
||||
goal="Search Wikipedia for accurate information",
|
||||
backstory="I am an AI assistant specialized in Wikipedia research",
|
||||
tools=[WikipediaAPIWrapper],
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# Create a research task
|
||||
task = Task(
|
||||
name="wiki_search",
|
||||
description="Research 'Artificial Intelligence' on Wikipedia",
|
||||
expected_output="Comprehensive information from Wikipedia articles",
|
||||
agent=agent
|
||||
)
|
||||
|
||||
# Create and start the workflow
|
||||
agents = PraisonAIAgents(
|
||||
agents=[agent],
|
||||
tasks=[task],
|
||||
verbose=True
|
||||
)
|
||||
|
||||
agents.start()
|
||||
```
|
||||
|
||||
```python Multiple Tools
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from langchain_community.tools import YouTubeSearchTool
|
||||
from langchain_community.utilities import WikipediaAPIWrapper
|
||||
|
||||
# Create YouTube search agent
|
||||
agent = Agent(
|
||||
name="SearchAgent",
|
||||
role="Research Assistant",
|
||||
goal="Search for information from YouTube",
|
||||
backstory="I am an AI assistant that can search YouTube for relevant videos.",
|
||||
tools=[YouTubeSearchTool],
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# Create Wikipedia research agent
|
||||
agent2 = Agent(
|
||||
name="WikiAgent",
|
||||
role="Research Assistant",
|
||||
goal="Search for information from Wikipedia",
|
||||
backstory="I am an AI assistant that can search Wikipedia for accurate information.",
|
||||
tools=[WikipediaAPIWrapper],
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# Create YouTube search task
|
||||
task = Task(
|
||||
name="search_task",
|
||||
description="Search for information about 'AI advancements' on YouTube",
|
||||
expected_output="Relevant information from YouTube videos",
|
||||
agent=agent
|
||||
)
|
||||
|
||||
# Create Wikipedia research task
|
||||
task2 = Task(
|
||||
name="wiki_task",
|
||||
description="Search for information about 'AI advancements' on Wikipedia",
|
||||
expected_output="Comprehensive information from Wikipedia articles",
|
||||
agent=agent2
|
||||
)
|
||||
|
||||
# Create and start the workflow
|
||||
agents = PraisonAIAgents(
|
||||
agents=[agent, agent2],
|
||||
tasks=[task, task2],
|
||||
verbose=True
|
||||
)
|
||||
|
||||
agents.start()
|
||||
```
|
||||
</CodeGroup>
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
(Upcoming Feature)
|
||||
Install the PraisonAI package:
|
||||
```bash
|
||||
pip install "praisonai"
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create a file">
|
||||
Create a new file `agents.yaml` with the basic setup:
|
||||
```yaml
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
roles:
|
||||
researcher:
|
||||
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:
|
||||
- youtube_search
|
||||
- wikipedia
|
||||
tasks:
|
||||
search_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
|
||||
```
|
||||
</Step>
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
praisonai agents.yaml
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Note>
|
||||
**Requirements**
|
||||
- Python 3.10 or higher
|
||||
- OpenAI API key. Generate OpenAI API key [here](https://platform.openai.com/api-keys)
|
||||
- LangChain compatible tools and utilities
|
||||
</Note>
|
||||
|
||||
## Understanding LangChain Integration
|
||||
|
||||
<Card title="What is LangChain Integration?" icon="question">
|
||||
LangChain integration enables agents to:
|
||||
- Use LangChain's extensive tool ecosystem
|
||||
- Access various data sources and APIs
|
||||
- Leverage pre-built utilities and wrappers
|
||||
- Combine multiple tools in a single agent
|
||||
- Extend agent capabilities with community tools
|
||||
</Card>
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Tool Integration" icon="plug">
|
||||
Seamlessly use LangChain tools with PraisonAI agents.
|
||||
</Card>
|
||||
<Card title="Multiple Sources" icon="database">
|
||||
Access various data sources through LangChain utilities.
|
||||
</Card>
|
||||
<Card title="Community Tools" icon="users">
|
||||
Leverage the extensive LangChain community ecosystem.
|
||||
</Card>
|
||||
<Card title="Custom Tools" icon="wrench">
|
||||
Create and integrate custom LangChain tools.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Memory Integration" icon="brain" href="../concepts/memory">
|
||||
Learn how to combine LangChain tools with agent memory
|
||||
</Card>
|
||||
<Card title="Custom Tools" icon="wrench" href="./tools">
|
||||
Create your own custom tools for agents
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Note>
|
||||
For optimal results, ensure all required dependencies are installed and API keys are properly configured for each tool.
|
||||
</Note>
|
||||
@@ -0,0 +1,347 @@
|
||||
---
|
||||
title: "Math AI Agent"
|
||||
sidebarTitle: "Math Agent"
|
||||
description: "Learn how to create AI agents that can perform complex mathematical calculations, unit conversions, and financial computations."
|
||||
icon: "calculator"
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents sympy pint
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `app.py` with the basic setup:
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from praisonaiagents.tools import (
|
||||
evaluate, solve_equation, convert_units,
|
||||
calculate_statistics, calculate_financial
|
||||
)
|
||||
|
||||
# Create math agent
|
||||
math_agent = Agent(
|
||||
role="Math Expert",
|
||||
goal="Perform complex mathematical calculations",
|
||||
backstory="Expert in mathematical computations and analysis",
|
||||
tools=[
|
||||
evaluate, solve_equation, convert_units,
|
||||
calculate_statistics, calculate_financial
|
||||
],
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Create a task
|
||||
task = Task(
|
||||
description="Calculate compound interest and statistical analysis",
|
||||
expected_output="Detailed mathematical analysis",
|
||||
agent=math_agent
|
||||
)
|
||||
|
||||
# Create and start the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[math_agent],
|
||||
tasks=[task],
|
||||
process="sequential",
|
||||
verbose=2
|
||||
)
|
||||
|
||||
# Start execution
|
||||
agents.start()
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
Install the PraisonAI package:
|
||||
```bash
|
||||
pip install praisonai sympy pint
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create a file">
|
||||
Create a new file `agents.yaml` with the basic setup:
|
||||
```yaml
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
topic: perform mathematical analysis
|
||||
roles:
|
||||
mathematician:
|
||||
backstory: Expert in mathematical computations and analysis.
|
||||
goal: Perform complex mathematical calculations
|
||||
role: Math Expert
|
||||
tools:
|
||||
- evaluate
|
||||
- solve_equation
|
||||
- convert_units
|
||||
- calculate_statistics
|
||||
- calculate_financial
|
||||
tasks:
|
||||
math_task:
|
||||
description: Calculate compound interest and perform statistical analysis.
|
||||
expected_output: Detailed mathematical analysis with results.
|
||||
```
|
||||
</Step>
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
praisonai agents.yaml
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Note>
|
||||
**Requirements**
|
||||
|
||||
- Python 3.10 or higher
|
||||
- OpenAI API key. Generate OpenAI API key [here](https://platform.openai.com/api-keys). Use Other models using [this guide](/models).
|
||||
- sympy and pint packages (automatically installed when needed)
|
||||
</Note>
|
||||
|
||||
## Understanding Math Agents
|
||||
|
||||
<Card title="What are Math Agents?" icon="question">
|
||||
Math agents are specialized AI agents that can:
|
||||
- Evaluate mathematical expressions
|
||||
- Solve equations and systems of equations
|
||||
- Perform unit conversions
|
||||
- Calculate statistical metrics
|
||||
- Handle financial calculations
|
||||
</Card>
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Expression Evaluator" icon="function">
|
||||
Evaluates mathematical expressions and formulas.
|
||||
</Card>
|
||||
<Card title="Equation Solver" icon="equals">
|
||||
Solves mathematical equations and systems.
|
||||
</Card>
|
||||
<Card title="Unit Converter" icon="arrows-rotate">
|
||||
Converts between different units of measurement.
|
||||
</Card>
|
||||
<Card title="Statistical Calculator" icon="chart-simple">
|
||||
Calculates statistical metrics and analysis.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Multi-Agent AI Math Analysis
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `app.py` with the basic setup:
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
from praisonaiagents.tools import (
|
||||
evaluate, solve_equation, convert_units,
|
||||
calculate_statistics, calculate_financial
|
||||
)
|
||||
|
||||
# Create first agent for calculations
|
||||
calculator = Agent(
|
||||
role="Mathematical Calculator",
|
||||
goal="Perform complex calculations and analysis",
|
||||
backstory="Expert in mathematical computations",
|
||||
tools=[evaluate, solve_equation, convert_units],
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Create second agent for statistics
|
||||
statistician = Agent(
|
||||
role="Statistical Analyst",
|
||||
goal="Perform statistical analysis and interpretation",
|
||||
backstory="Expert in statistical analysis",
|
||||
tools=[calculate_statistics, calculate_financial],
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Create first task
|
||||
calc_task = Task(
|
||||
description="Calculate compound interest for $10000 at 5% for 3 years",
|
||||
expected_output="Detailed interest calculation",
|
||||
agent=calculator
|
||||
)
|
||||
|
||||
# Create second task
|
||||
stats_task = Task(
|
||||
description="Analyze the monthly interest distribution",
|
||||
expected_output="Statistical analysis of interest data",
|
||||
agent=statistician
|
||||
)
|
||||
|
||||
# Create and start the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[calculator, statistician],
|
||||
tasks=[calc_task, stats_task],
|
||||
process="sequential"
|
||||
)
|
||||
|
||||
# Start execution
|
||||
agents.start()
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
Install the PraisonAI package:
|
||||
```bash
|
||||
pip install praisonai
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create a file">
|
||||
Create a new file `agents.yaml` with the basic setup:
|
||||
```yaml
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
topic: perform financial and statistical analysis
|
||||
roles:
|
||||
calculator:
|
||||
backstory: Expert in mathematical computations and analysis.
|
||||
goal: Perform complex calculations
|
||||
role: Mathematical Calculator
|
||||
tools:
|
||||
- evaluate
|
||||
- solve_equation
|
||||
- convert_units
|
||||
tasks:
|
||||
calc_task:
|
||||
description: Calculate compound interest for investment scenario.
|
||||
expected_output: Detailed interest calculations.
|
||||
|
||||
statistician:
|
||||
backstory: Expert in statistical analysis and interpretation.
|
||||
goal: Analyze numerical data and patterns
|
||||
role: Statistical Analyst
|
||||
tools:
|
||||
- calculate_statistics
|
||||
- calculate_financial
|
||||
tasks:
|
||||
stats_task:
|
||||
description: Analyze the monthly interest distribution.
|
||||
expected_output: Statistical analysis report.
|
||||
```
|
||||
</Step>
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
praisonai agents.yaml
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### Configuration Options
|
||||
|
||||
```python
|
||||
# Create an agent with advanced math configuration
|
||||
agent = Agent(
|
||||
role="Math Expert",
|
||||
goal="Perform complex mathematical analysis",
|
||||
backstory="Expert in mathematical computations",
|
||||
tools=[
|
||||
evaluate,
|
||||
solve_equation,
|
||||
convert_units,
|
||||
calculate_statistics,
|
||||
calculate_financial
|
||||
],
|
||||
verbose=True, # Enable detailed logging
|
||||
llm="gpt-4o" # Language model to use
|
||||
)
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Expression Errors" icon="triangle-exclamation">
|
||||
If expressions are not evaluating:
|
||||
- Check syntax and formatting
|
||||
- Verify variable definitions
|
||||
- Enable verbose mode for debugging
|
||||
</Card>
|
||||
|
||||
<Card title="Calculation Issues" icon="calculator">
|
||||
If calculations are incorrect:
|
||||
- Review input formats
|
||||
- Check unit compatibility
|
||||
- Verify formula structure
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="AutoAgents" icon="robot" href="./autoagents">
|
||||
Learn about automatically created and managed AI agents
|
||||
</Card>
|
||||
<Card title="Mini Agents" icon="microchip" href="./mini">
|
||||
Explore lightweight, focused AI agents
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Note>
|
||||
For optimal results, ensure mathematical expressions and units are properly formatted for your specific use case.
|
||||
</Note>
|
||||
+103
-65
@@ -4,47 +4,112 @@ description: "Learn how to create simple yet powerful AI agents in just a few li
|
||||
icon: "robot"
|
||||
---
|
||||
|
||||
<Note>
|
||||
**Prerequisites**
|
||||
- Python 3.10 or higher
|
||||
- PraisonAI Agents package installed
|
||||
- Basic understanding of Python
|
||||
</Note>
|
||||
|
||||
## Quick Start
|
||||
|
||||
Create multiple AI agents that can work together in just a few lines of code!
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents duckduckgo_search
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create Your Agents">
|
||||
<CodeGroup>
|
||||
```python Single Agent
|
||||
from praisonaiagents import Agent, PraisonAIAgents
|
||||
summarise_agent = Agent(instructions="Summarise Photosynthesis")
|
||||
agents = PraisonAIAgents(agents=[summarise_agent])
|
||||
agents.start()
|
||||
```
|
||||
```python Multiple Agents
|
||||
# Agent with Internet Search Tool
|
||||
from praisonaiagents import Agent, PraisonAIAgents
|
||||
research_agent = Agent(instructions="Research about AI 2024", tools=[Tools.internet_search])
|
||||
summarise_agent = Agent(instructions="Summarise research agent's findings")
|
||||
agents = PraisonAIAgents(agents=[research_agent, summarise_agent])
|
||||
agents.start()
|
||||
```
|
||||
</CodeGroup>
|
||||
</Step>
|
||||
<Step title="Run Your Agents">
|
||||
Execute your agents by running:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents duckduckgo_search
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create Your Agents">
|
||||
<CodeGroup>
|
||||
```yaml Single Agent
|
||||
# Create a new file `agents.yaml` with the following content:
|
||||
roles:
|
||||
summarise_agent
|
||||
instructions: Summarise Photosynthesis
|
||||
```
|
||||
```yaml Multiple Agents
|
||||
# Create a new file `agents.yaml` with the following content:
|
||||
# Agent with Internet Search Tool
|
||||
roles:
|
||||
research_agent
|
||||
instructions: Research about AI 2024
|
||||
tools:
|
||||
- internet_search
|
||||
summarise_agent
|
||||
instructions: Summarise research agent's findings
|
||||
```
|
||||
</CodeGroup>
|
||||
</Step>
|
||||
<Step title="Run Your Agents">
|
||||
Execute your agents by running:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
<Note>
|
||||
**Prerequisites**
|
||||
- Python 3.10 or higher
|
||||
- OpenAI API key. Generate OpenAI API key [here](https://platform.openai.com/api-keys). Use Other models using [this guide](/models).
|
||||
</Note>
|
||||
<br />
|
||||
|
||||
<Step title="Import Required Components">
|
||||
Import the necessary components:
|
||||
```python
|
||||
from praisonaiagents import Agent, Agents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create Your Agents">
|
||||
Create specialized agents with specific roles:
|
||||
```python
|
||||
summarise_agent = Agent(instructions="Summarise what is Photosynthesis")
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start Your Agents">
|
||||
Initialize and run your agents:
|
||||
```python
|
||||
agents = Agents(agents=[summarise_agent])
|
||||
agents.start()
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
<div className="relative w-full aspect-video">
|
||||
<iframe
|
||||
className="absolute top-0 left-0 w-full h-full"
|
||||
src="https://www.youtube.com/embed/OkvYp5aAGSg"
|
||||
title="YouTube video player"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
## Understanding Mini AI Agents
|
||||
|
||||
@@ -96,34 +161,7 @@ Create multiple AI agents that can work together in just a few lines of code!
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Research and Summary
|
||||
|
||||
```terminal
|
||||
pip install praisonaiagents duckduckgo_search
|
||||
```
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent, Agents, Tools
|
||||
|
||||
# Create a research agent
|
||||
research_agent = Agent(
|
||||
instructions="You are a research agent to search internet about AI 2024",
|
||||
tools=[Tools.internet_search]
|
||||
)
|
||||
|
||||
# Create a summarize agent
|
||||
summarise_agent = Agent(
|
||||
instructions="You are a summarize agent to summarise research agent's findings"
|
||||
)
|
||||
|
||||
# Initialize and run agents
|
||||
agents = Agents(agents=[research_agent, summarise_agent])
|
||||
agents.start()
|
||||
```
|
||||
|
||||
### Custom Instructions
|
||||
## Custom Instructions
|
||||
|
||||
<CodeGroup>
|
||||
```python Basic
|
||||
@@ -245,4 +283,4 @@ agents = Agents(agents=[collector, summarizer, writer])
|
||||
|
||||
<Note>
|
||||
Mini AI Agents are designed to be simple yet powerful. They're perfect for quick prototypes and straightforward automation tasks.
|
||||
</Note>
|
||||
</Note>
|
||||
@@ -0,0 +1,314 @@
|
||||
---
|
||||
title: "Multimodal Agents"
|
||||
description: "Guide for creating and using multimodal AI agents in PraisonAI for processing images, videos, and other media types"
|
||||
icon: "images"
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=xxxxxxxxxxxxxxxxxxxxxx
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create a file">
|
||||
Create a new file `app.py` with the basic setup:
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create Vision Analysis Agent
|
||||
vision_agent = Agent(
|
||||
name="VisionAnalyst",
|
||||
role="Computer Vision Specialist",
|
||||
goal="Analyze images and videos to extract meaningful information",
|
||||
backstory="""You are an expert in computer vision and image analysis.
|
||||
You excel at describing images, detecting objects, and understanding visual content.""",
|
||||
llm="gpt-4o-mini",
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# Create tasks with different media types
|
||||
task = Task(
|
||||
name="analyze_landmark",
|
||||
description="Describe this famous landmark and its architectural features.",
|
||||
expected_output="Detailed description of the landmark's architecture and significance",
|
||||
agent=vision_agent,
|
||||
images=["https://upload.wikimedia.org/wikipedia/commons/b/bf/Krakow_-_Kosciol_Mariacki.jpg"]
|
||||
)
|
||||
|
||||
# Run the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[vision_agent],
|
||||
tasks=[task],
|
||||
process="sequential",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
agents.start()
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
Install the PraisonAI package:
|
||||
```bash
|
||||
pip install praisonai
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=xxxxxxxxxxxxxxxxxxxxxx
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create a file">
|
||||
Create a new file `agents.yaml` with the basic setup:
|
||||
```yaml
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
topic: analyze landmark image
|
||||
roles:
|
||||
vision_analyst:
|
||||
name: VisionAnalyst
|
||||
role: Computer Vision Specialist
|
||||
goal: Analyze images and videos to extract meaningful information
|
||||
backstory: |
|
||||
You are an expert in computer vision and image analysis.
|
||||
You excel at describing images, detecting objects, and understanding visual content.
|
||||
llm: gpt-4o-mini
|
||||
self_reflect: false
|
||||
tasks:
|
||||
analyze_landmark:
|
||||
description: Describe this famous landmark and its architectural features.
|
||||
expected_output: Detailed description of the landmark's architecture and significance
|
||||
images:
|
||||
- https://upload.wikimedia.org/wikipedia/commons/b/bf/Krakow_-_Kosciol_Mariacki.jpg
|
||||
```
|
||||
</Step>
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
praisonai agents.yaml
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Note>
|
||||
**Requirements**
|
||||
- Python 3.10 or higher
|
||||
- OpenAI API key with vision model access
|
||||
- Basic understanding of Python and media handling
|
||||
</Note>
|
||||
|
||||
<div className="relative w-full aspect-video">
|
||||
<iframe
|
||||
className="absolute top-0 left-0 w-full h-full"
|
||||
src="https://www.youtube.com/embed/hjAWmUT1qqY"
|
||||
title="YouTube video player"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
## Understanding Multimodal Agents
|
||||
|
||||
<Card title="What are Multimodal Agents?" icon="question">
|
||||
Multimodal agents are designed to:
|
||||
- Process multiple types of data (text, images, videos)
|
||||
- Understand context across different modalities
|
||||
- Generate insights from diverse media sources
|
||||
- Handle complex multimedia tasks
|
||||
</Card>
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Vision Processing" icon="eye">
|
||||
Analyze images, detect objects, and understand visual content.
|
||||
</Card>
|
||||
<Card title="Video Analysis" icon="video">
|
||||
Process video content for events and actions.
|
||||
</Card>
|
||||
<Card title="Text Extraction" icon="font">
|
||||
Extract and analyze text from images and documents.
|
||||
</Card>
|
||||
<Card title="Cross-Modal Understanding" icon="arrows-repeat">
|
||||
Integrate insights across different media types.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Multi-Agent Media Processing
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create first agent for image analysis
|
||||
vision_agent = Agent(
|
||||
role="Image Analyst",
|
||||
goal="Analyze visual content and extract key information",
|
||||
backstory="Expert in visual analysis and image understanding",
|
||||
llm="gpt-4o-mini",
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# Create second agent for content writing
|
||||
writer_agent = Agent(
|
||||
role="Content Writer",
|
||||
goal="Create engaging content based on image analysis",
|
||||
backstory="Expert in creating compelling content from visual insights",
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
# Create tasks for different media types
|
||||
document_task = Task(
|
||||
description="Extract and summarize text from this document image",
|
||||
expected_output="Structured text content with key information highlighted",
|
||||
agent=vision_agent,
|
||||
images=["document.jpg"]
|
||||
)
|
||||
|
||||
writing_task = Task(
|
||||
description="Create engaging content based on image analysis",
|
||||
expected_output="Compelling article incorporating visual insights",
|
||||
agent=writer_agent
|
||||
)
|
||||
|
||||
# Create and start the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[vision_agent, writer_agent],
|
||||
tasks=[document_task, writing_task],
|
||||
process="sequential"
|
||||
)
|
||||
|
||||
result = agents.start()
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
```yaml
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
topic: document analysis and content creation
|
||||
roles:
|
||||
vision_analyst:
|
||||
role: Image Analyst
|
||||
goal: Analyze visual content and extract key information
|
||||
backstory: Expert in visual analysis and image understanding
|
||||
llm: gpt-4o-mini
|
||||
self_reflect: false
|
||||
tasks:
|
||||
document_task:
|
||||
description: Extract and summarize text from this document image
|
||||
expected_output: Structured text content with key information highlighted
|
||||
images:
|
||||
- document.jpg
|
||||
|
||||
content_writer:
|
||||
role: Content Writer
|
||||
goal: Create engaging content based on image analysis
|
||||
backstory: Expert in creating compelling content from visual insights
|
||||
llm: gpt-4o-mini
|
||||
tasks:
|
||||
writing_task:
|
||||
description: Create engaging content based on image analysis
|
||||
expected_output: Compelling article incorporating visual insights
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### Configuration Options
|
||||
|
||||
```python
|
||||
# Create an agent with multimodal configuration
|
||||
agent = Agent(
|
||||
role="Media Analyst",
|
||||
goal="Process multiple types of media",
|
||||
backstory="Expert in multimedia analysis",
|
||||
llm="gpt-4o-mini", # Must support vision capabilities
|
||||
verbose=True, # Enable detailed logging
|
||||
self_reflect=False # Optional: disable self-reflection
|
||||
)
|
||||
|
||||
# Task with media requirements
|
||||
task = Task(
|
||||
description="Analyze media content",
|
||||
expected_output="Comprehensive analysis",
|
||||
agent=agent,
|
||||
images=[ # Support multiple media sources
|
||||
"https://example.com/image1.jpg",
|
||||
"path/to/local/image.jpg",
|
||||
"path/to/video.mp4"
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Media Handling" icon="image">
|
||||
- Use supported formats (JPEG, PNG)
|
||||
- Keep reasonable file sizes
|
||||
- Provide high-quality media
|
||||
- Validate files before processing
|
||||
</Card>
|
||||
<Card title="Task Design" icon="list-check">
|
||||
- Write clear descriptions
|
||||
- Break down complex analyses
|
||||
- Specify expected outputs
|
||||
- Handle errors gracefully
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Example Use Cases
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Document Analysis" icon="file-lines">
|
||||
Extract and analyze text from document images.
|
||||
</Card>
|
||||
<Card title="Security Monitoring" icon="camera-cctv">
|
||||
Monitor security feeds for suspicious activity.
|
||||
</Card>
|
||||
<Card title="Medical Imaging" icon="microscope">
|
||||
Analyze medical scans for abnormalities.
|
||||
</Card>
|
||||
<Card title="Architectural Analysis" icon="building">
|
||||
Study architectural features and designs.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="AutoAgents" icon="robot" href="./autoagents">
|
||||
Learn about automatically created and managed AI agents
|
||||
</Card>
|
||||
<Card title="Mini Agents" icon="microchip" href="./mini">
|
||||
Explore lightweight, focused AI agents
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Note>
|
||||
For optimal results, ensure your media files are in supported formats and sizes for processing.
|
||||
</Note>
|
||||
@@ -0,0 +1,248 @@
|
||||
---
|
||||
title: "Agentic Prompt Chaining"
|
||||
description: "Learn how to create AI agents with sequential prompt chaining for complex workflows."
|
||||
icon: "link"
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `app.py` with the basic setup:
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
import time
|
||||
|
||||
def get_time_check():
|
||||
current_time = int(time.time())
|
||||
result = "even" if current_time % 2 == 0 else "odd"
|
||||
print(f"Time check: {current_time} is {result}")
|
||||
return result
|
||||
|
||||
# Create agents for each step in the chain
|
||||
agent1 = Agent(
|
||||
name="Time Checker",
|
||||
role="Time checker",
|
||||
goal="Check if the time is even or odd",
|
||||
instructions="Check if the time is even or odd",
|
||||
tools=[get_time_check]
|
||||
)
|
||||
|
||||
agent2 = Agent(
|
||||
name="Advanced Analyzer",
|
||||
role="Advanced data analyzer",
|
||||
goal="Perform in-depth analysis of processed data",
|
||||
instructions="Analyze the processed data in detail"
|
||||
)
|
||||
|
||||
agent3 = Agent(
|
||||
name="Final Processor",
|
||||
role="Final data processor",
|
||||
goal="Generate final output based on analysis",
|
||||
instructions="Create final output based on analyzed data"
|
||||
)
|
||||
|
||||
# Create tasks for each step
|
||||
initial_task = Task(
|
||||
name="time_check",
|
||||
description="Getting time check and checking if it is even or odd",
|
||||
expected_output="Getting time check and checking if it is even or odd",
|
||||
agent=agent1,
|
||||
is_start=True, # Mark as the starting task
|
||||
task_type="decision", # This task will make a decision
|
||||
next_tasks=["advanced_analysis"], # Next task if condition passes
|
||||
condition={
|
||||
"even": ["advanced_analysis"], # If passes, go to advanced analysis
|
||||
"odd": "" # If fails, exit the chain
|
||||
}
|
||||
)
|
||||
|
||||
analysis_task = Task(
|
||||
name="advanced_analysis",
|
||||
description="Perform advanced analysis on the processed data",
|
||||
expected_output="Analyzed data ready for final processing",
|
||||
agent=agent2,
|
||||
next_tasks=["final_processing"]
|
||||
)
|
||||
|
||||
final_task = Task(
|
||||
name="final_processing",
|
||||
description="Generate final output",
|
||||
expected_output="Final processed result",
|
||||
agent=agent3
|
||||
)
|
||||
|
||||
# Create the workflow manager
|
||||
workflow = PraisonAIAgents(
|
||||
agents=[agent1, agent2, agent3],
|
||||
tasks=[initial_task, analysis_task, final_task],
|
||||
process="workflow", # Use workflow process type
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Run the workflow
|
||||
results = workflow.start()
|
||||
|
||||
# Print results
|
||||
print("\nWorkflow Results:")
|
||||
for task_id, result in results["task_results"].items():
|
||||
if result:
|
||||
print(f"Task {task_id}: {result.raw}")
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Note>
|
||||
**Requirements**
|
||||
- Python 3.10 or higher
|
||||
- OpenAI API key. Generate OpenAI API key [here](https://platform.openai.com/api-keys). Use Other models using [this guide](/models).
|
||||
- Basic understanding of Python
|
||||
</Note>
|
||||
|
||||
## Understanding Prompt Chaining
|
||||
|
||||
<Card title="What is Prompt Chaining?" icon="question">
|
||||
Prompt chaining enables:
|
||||
- Sequential execution of prompts
|
||||
- Data flow between agents
|
||||
- Conditional branching in workflows
|
||||
- Step-by-step processing of complex tasks
|
||||
</Card>
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Sequential Processing" icon="arrow-right">
|
||||
Execute tasks in a defined sequence with data passing between steps.
|
||||
</Card>
|
||||
<Card title="Decision Points" icon="code-branch">
|
||||
Implement conditional logic to control workflow progression.
|
||||
</Card>
|
||||
<Card title="Data Flow" icon="arrows-up-down">
|
||||
Pass data seamlessly between agents in the chain.
|
||||
</Card>
|
||||
<Card title="Process Control" icon="sliders">
|
||||
Monitor and control the execution of each step in the chain.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Configuration Options to exit the chain
|
||||
|
||||
```python
|
||||
# Task with chaining configuration
|
||||
task = Task(
|
||||
name="time_check",
|
||||
description="Check time and make decision",
|
||||
expected_output="Time check result",
|
||||
agent=agent,
|
||||
is_start=True,
|
||||
task_type="decision",
|
||||
next_tasks=["next_step"],
|
||||
condition={
|
||||
"even": ["next_step"],
|
||||
"odd": ""
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
```python
|
||||
task = Task(
|
||||
name="time_check",
|
||||
description="Check time and make decision",
|
||||
expected_output="Time check result",
|
||||
agent=agent,
|
||||
is_start=True,
|
||||
task_type="decision",
|
||||
next_tasks=["next_step"],
|
||||
condition={
|
||||
"even": ["next_step"],
|
||||
"odd": "exit"
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
```python
|
||||
task = Task(
|
||||
name="time_check",
|
||||
description="Check time and make decision",
|
||||
expected_output="Time check result",
|
||||
agent=agent,
|
||||
is_start=True,
|
||||
task_type="decision",
|
||||
next_tasks=["next_step"],
|
||||
condition={
|
||||
"even": ["next_step"],
|
||||
"odd": ["exit"]
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
```python
|
||||
task = Task(
|
||||
name="time_check",
|
||||
description="Check time and make decision",
|
||||
expected_output="Time check result",
|
||||
agent=agent,
|
||||
is_start=True,
|
||||
task_type="decision",
|
||||
next_tasks=["next_step"],
|
||||
condition={
|
||||
"even": ["next_step"],
|
||||
"odd": [""]
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Chain Issues" icon="triangle-exclamation">
|
||||
If chain execution fails:
|
||||
- Verify task connections
|
||||
- Check condition logic
|
||||
- Enable verbose mode for debugging
|
||||
</Card>
|
||||
|
||||
<Card title="Data Flow" icon="diagram-project">
|
||||
If data flow is incorrect:
|
||||
- Review task outputs
|
||||
- Check agent configurations
|
||||
- Verify task dependencies
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="AutoAgents" icon="robot" href="./autoagents">
|
||||
Learn about automatically created and managed AI agents
|
||||
</Card>
|
||||
<Card title="Mini Agents" icon="microchip" href="./mini">
|
||||
Explore lightweight, focused AI agents
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Note>
|
||||
For optimal results, ensure your chain is properly configured with clear task dependencies and conditions for branching logic.
|
||||
</Note>
|
||||
+305
-209
@@ -1,10 +1,121 @@
|
||||
---
|
||||
title: "Reasoning AI Agents"
|
||||
sidebarTitle: "Reasoning"
|
||||
description: "Reasoning enables AI agents to think logically, solve complex problems autonomously, and make human-like decisions through multi-step logical reasoning."
|
||||
icon: "brain-circuit"
|
||||
title: "Reasoning Agents"
|
||||
description: "Learn how to create AI agents with advanced reasoning capabilities for complex problem-solving."
|
||||
icon: "brain"
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `app.py` with the basic setup:
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents, Tools
|
||||
|
||||
# Create reasoning agent
|
||||
reasoner = Agent(
|
||||
role="Problem Solver",
|
||||
goal="Solve complex problems using logical reasoning",
|
||||
backstory="Expert in logical analysis and problem-solving",
|
||||
tools=[Tools.internet_search],
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Create task
|
||||
task = Task(
|
||||
description="Analyze and solve a complex business problem",
|
||||
expected_output="Detailed solution with reasoning steps",
|
||||
agent=reasoner
|
||||
)
|
||||
|
||||
# Create and start the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[reasoner],
|
||||
tasks=[task],
|
||||
process="sequential",
|
||||
verbose=2
|
||||
)
|
||||
|
||||
# Start execution
|
||||
result = agents.start()
|
||||
print(result)
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
Install the PraisonAI package:
|
||||
```bash
|
||||
pip install praisonai
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create a file">
|
||||
Create a new file `agents.yaml` with the basic setup:
|
||||
```yaml
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
topic: solve complex business problem
|
||||
roles:
|
||||
reasoner:
|
||||
backstory: Expert in logical analysis and problem-solving.
|
||||
goal: Solve complex problems using logical reasoning
|
||||
role: Problem Solver
|
||||
tools:
|
||||
- internet_search
|
||||
tasks:
|
||||
analysis_task:
|
||||
description: Analyze and solve a complex business problem.
|
||||
expected_output: Detailed solution with reasoning steps.
|
||||
```
|
||||
</Step>
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
praisonai agents.yaml
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Note>
|
||||
**Requirements**
|
||||
- Python 3.10 or higher
|
||||
- OpenAI API key. Generate OpenAI API key [here](https://platform.openai.com/api-keys). Use Other models using [this guide](/models).
|
||||
- Basic understanding of Python
|
||||
</Note>
|
||||
|
||||
<div className="relative w-full aspect-video">
|
||||
<iframe
|
||||
className="absolute top-0 left-0 w-full h-full"
|
||||
@@ -15,225 +126,210 @@ icon: "brain-circuit"
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
## Overview
|
||||
## Understanding Reasoning
|
||||
|
||||
Reasoning in PraisonAI agents enables:
|
||||
- Autonomous problem solving
|
||||
- Multi-step logical reasoning
|
||||
- Human-like decision making
|
||||
- Deep comprehension of tasks
|
||||
- Error handling with alternative solutions
|
||||
<Card title="What is Reasoning?" icon="question">
|
||||
Reasoning agents are designed to:
|
||||
- Break down complex problems into manageable steps
|
||||
- Apply logical analysis to find solutions
|
||||
- Explain their thought process and decisions
|
||||
- Handle uncertainty and incomplete information
|
||||
</Card>
|
||||
|
||||
## Usage
|
||||
## Features
|
||||
|
||||
Reasoning is controlled through reflection cycles using `min_reflect` and `max_reflect` parameters:
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Problem Decomposition" icon="puzzle-piece">
|
||||
Break complex problems into smaller, manageable parts.
|
||||
</Card>
|
||||
<Card title="Logical Analysis" icon="brain">
|
||||
Apply structured thinking to solve problems.
|
||||
</Card>
|
||||
<Card title="Error Recovery" icon="shield-check">
|
||||
Handle edge cases and recover from errors.
|
||||
</Card>
|
||||
<Card title="Explanation" icon="comment">
|
||||
Provide detailed reasoning for decisions.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Multi-Agent Reasoning
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `app.py` with the basic setup:
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents, Tools
|
||||
|
||||
# Create first agent for analysis
|
||||
analyst = Agent(
|
||||
role="Business Analyst",
|
||||
goal="Analyze business problems and identify key issues",
|
||||
backstory="Expert in business analysis and problem identification",
|
||||
tools=[Tools.internet_search],
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Create second agent for solution development
|
||||
solver = Agent(
|
||||
role="Solution Architect",
|
||||
goal="Develop comprehensive solutions to business problems",
|
||||
backstory="Expert in solution design and implementation",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Create first task
|
||||
analysis_task = Task(
|
||||
description="Analyze the current market challenges",
|
||||
expected_output="Detailed analysis of key issues",
|
||||
agent=analyst
|
||||
)
|
||||
|
||||
# Create second task
|
||||
solution_task = Task(
|
||||
description="Develop solutions for identified challenges",
|
||||
expected_output="Comprehensive solution strategy",
|
||||
agent=solver
|
||||
)
|
||||
|
||||
# Create and start the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[analyst, solver],
|
||||
tasks=[analysis_task, solution_task],
|
||||
process="sequential"
|
||||
)
|
||||
|
||||
# Start execution
|
||||
result = agents.start()
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
Install the PraisonAI package:
|
||||
```bash
|
||||
pip install praisonai
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create a file">
|
||||
Create a new file `agents.yaml` with the basic setup:
|
||||
```yaml
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
topic: solve market challenges
|
||||
roles:
|
||||
analyst:
|
||||
backstory: Expert in business analysis and problem identification.
|
||||
goal: Analyze business problems and identify key issues
|
||||
role: Business Analyst
|
||||
tools:
|
||||
- internet_search
|
||||
tasks:
|
||||
analysis_task:
|
||||
description: Analyze the current market challenges.
|
||||
expected_output: Detailed analysis of key issues.
|
||||
|
||||
solver:
|
||||
backstory: Expert in solution design and implementation.
|
||||
goal: Develop comprehensive solutions to business problems
|
||||
role: Solution Architect
|
||||
tasks:
|
||||
solution_task:
|
||||
description: Develop solutions for identified challenges.
|
||||
expected_output: Comprehensive solution strategy.
|
||||
```
|
||||
</Step>
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
praisonai agents.yaml
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### Configuration Options
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent
|
||||
|
||||
# Create an agent with reasoning configuration
|
||||
agent = Agent(
|
||||
name="SystemOps",
|
||||
role="System Administrator",
|
||||
goal="Manage and monitor system operations",
|
||||
backstory="You are an expert system administrator",
|
||||
min_reflect=6, # Minimum reflection cycles
|
||||
max_reflect=10 # Maximum reflection cycles
|
||||
)
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
- **Deep Comprehension**: Instead of rule-based responses, agents understand tasks deeply
|
||||
- **Error Recovery**: Agents can reason through errors and find alternative solutions
|
||||
- **Step-by-Step Processing**: Complex tasks are broken down and processed systematically
|
||||
- **Quality Control**: Multiple reflection cycles ensure high-quality outputs
|
||||
- **Adaptive Problem Solving**: Agents can adjust their approach based on reasoning
|
||||
|
||||
## Example
|
||||
|
||||
Here's a complete example showing reasoning in action:
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
def run_terminal_command(command: str):
|
||||
"""
|
||||
Run a terminal command and return its output.
|
||||
"""
|
||||
try:
|
||||
result = subprocess.run(command, shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
print(f"Command output: {result}")
|
||||
return {"stdout": result.stdout, "stderr": result.stderr}
|
||||
except subprocess.CalledProcessError as e:
|
||||
return {"error": str(e), "stdout": e.stdout, "stderr": e.stderr}
|
||||
|
||||
def save_to_file(file_path: str, content: str):
|
||||
"""
|
||||
Save the given content to the specified file path. Create the folder/file if it doesn't exist.
|
||||
"""
|
||||
# Ensure the directory exists
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
|
||||
# Write the content to the file
|
||||
with open(file_path, 'w') as file:
|
||||
file.write(content)
|
||||
|
||||
return file_path
|
||||
|
||||
# Create System Operations Agent
|
||||
system_ops_agent = Agent(
|
||||
name="SystemOps",
|
||||
role="System Operations Specialist",
|
||||
goal="Execute and manage complex system operations and commands",
|
||||
backstory="""You are an expert system administrator with deep knowledge of Unix/Linux systems.
|
||||
You excel at running complex system commands, managing processes, and handling system operations.
|
||||
You always validate commands before execution and ensure they are safe to run.""",
|
||||
min_reflect=6,
|
||||
max_reflect=10,
|
||||
tools=[run_terminal_command, save_to_file],
|
||||
llm="gpt-4o-mini"
|
||||
role="Problem Solver",
|
||||
goal="Solve complex problems",
|
||||
backstory="Expert in problem-solving",
|
||||
tools=[Tools.internet_search],
|
||||
verbose=True, # Enable detailed logging
|
||||
llm="gpt-4o" # Language model to use
|
||||
)
|
||||
|
||||
# Create a complex task that tests various system operations
|
||||
# Task with reasoning requirements
|
||||
task = Task(
|
||||
name="system_analysis_task",
|
||||
description="""Perform a comprehensive system analysis by executing the following operations in sequence:
|
||||
1. Get system information (OS, kernel version)
|
||||
2. List 5 running processes and sort them by CPU usage
|
||||
3. Check disk space usage and list directories over 1GB
|
||||
4. Display current system load and memory usage
|
||||
5. List 5 network connections
|
||||
6. Create a summary report with all findings in a text file called system_report.txt
|
||||
|
||||
Do it step by step. One task at a time.
|
||||
Save only the Summary report in the file.
|
||||
Use appropriate commands for each step and ensure proper error handling.""",
|
||||
expected_output="A comprehensive system report containing all requested information saved in system_report.txt",
|
||||
agent=system_ops_agent,
|
||||
description="Solve complex problem",
|
||||
expected_output="Detailed solution",
|
||||
agent=agent
|
||||
)
|
||||
|
||||
agents = PraisonAIAgents(
|
||||
agents=[system_ops_agent],
|
||||
tasks=[task],
|
||||
process="sequential"
|
||||
)
|
||||
|
||||
result = agents.start()
|
||||
```
|
||||
|
||||
## e2b Tool Integration Example
|
||||
## Troubleshooting
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents, error_logs
|
||||
import json
|
||||
from e2b_code_interpreter import Sandbox
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Reasoning Errors" icon="triangle-exclamation">
|
||||
If reasoning seems incorrect:
|
||||
- Check problem description clarity
|
||||
- Enable verbose mode for debugging
|
||||
- Review agent configuration
|
||||
</Card>
|
||||
|
||||
def code_interpret(code: str):
|
||||
"""
|
||||
A function to demonstrate running Python code dynamically using e2b_code_interpreter.
|
||||
"""
|
||||
print(f"\n{'='*50}\n> Running following AI-generated code:\n{code}\n{'='*50}")
|
||||
exec_result = Sandbox().run_code(code)
|
||||
if exec_result.error:
|
||||
print("[Code Interpreter error]", exec_result.error)
|
||||
return {"error": str(exec_result.error)}
|
||||
else:
|
||||
results = []
|
||||
for result in exec_result.results:
|
||||
if hasattr(result, '__iter__'):
|
||||
results.extend(list(result))
|
||||
else:
|
||||
results.append(str(result))
|
||||
logs = {"stdout": list(exec_result.logs.stdout), "stderr": list(exec_result.logs.stderr)}
|
||||
return json.dumps({"results": results, "logs": logs})
|
||||
<Card title="Process Flow" icon="code">
|
||||
If process flow is unclear:
|
||||
- Verify task dependencies
|
||||
- Check agent roles and goals
|
||||
- Review task descriptions
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
# 1) Create Agents
|
||||
web_scraper_agent = Agent(
|
||||
name="WebScraper",
|
||||
role="Web Scraper",
|
||||
goal="Extract URLs from https://quotes.toscrape.com/",
|
||||
backstory="An expert in data extraction from websites, adept at navigating and retrieving detailed information.",
|
||||
tools=[code_interpret],
|
||||
llm="gpt-4o"
|
||||
)
|
||||
## Next Steps
|
||||
|
||||
url_data_extractor_agent = Agent(
|
||||
name="URLDataExtractor",
|
||||
role="URL Data Extractor",
|
||||
goal="Crawl each URL for data extraction",
|
||||
backstory="Specializes in crawling websites to gather comprehensive data, ensuring nothing is missed from each link.",
|
||||
tools=[code_interpret],
|
||||
llm="gpt-4o"
|
||||
)
|
||||
<CardGroup cols={2}>
|
||||
<Card title="AutoAgents" icon="robot" href="./autoagents">
|
||||
Learn about automatically created and managed AI agents
|
||||
</Card>
|
||||
<Card title="Mini Agents" icon="microchip" href="./mini">
|
||||
Explore lightweight, focused AI agents
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
blog_writer_agent = Agent(
|
||||
name="BlogWriter",
|
||||
role="Creative Content Writer",
|
||||
goal="Create engaging and insightful blog posts from provided data",
|
||||
backstory="An experienced content creator and storyteller with a knack for weaving compelling narratives. Skilled at analyzing quotes and creating meaningful connections that resonate with readers.",
|
||||
tools=[code_interpret],
|
||||
llm="gpt-4o"
|
||||
)
|
||||
|
||||
# 2) Create Tasks
|
||||
task_url_extraction = Task(
|
||||
name="url_extraction_task",
|
||||
description="""Use code_interpret to run Python code that fetches https://quotes.toscrape.com/
|
||||
and extracts 5 URLs from the page, then outputs them as a list. Only first 5 urls""",
|
||||
expected_output="A list of URLs extracted from the source page.",
|
||||
agent=web_scraper_agent,
|
||||
output_file="urls.txt"
|
||||
)
|
||||
|
||||
task_data_extraction = Task(
|
||||
name="data_extraction_task",
|
||||
description="""Take the URLs from url_extraction_task, crawl each URL and extract all pertinent
|
||||
data using code_interpret to run Python code, then output raw txt, not the html.""",
|
||||
expected_output="Raw data collected from each crawled URL.",
|
||||
agent=url_data_extractor_agent,
|
||||
context=[task_url_extraction]
|
||||
)
|
||||
|
||||
blog_writing_task = Task(
|
||||
name="blog_writing_task",
|
||||
description="""Write an engaging blog post using the extracted quotes data. The blog post should:
|
||||
1. Have a catchy title
|
||||
2. Include relevant quotes from the data
|
||||
3. Provide commentary and insights about the quotes
|
||||
4. Be well-structured with introduction, body, and conclusion
|
||||
5. Be approximately 500 words long""",
|
||||
expected_output="A well-written blog post incorporating the extracted quotes with analysis",
|
||||
agent=blog_writer_agent,
|
||||
context=[task_data_extraction],
|
||||
output_file="blog_post.txt"
|
||||
)
|
||||
|
||||
# 3) Create and run Agents manager
|
||||
agents_manager = PraisonAIAgents(
|
||||
agents=[web_scraper_agent, url_data_extractor_agent, blog_writer_agent],
|
||||
tasks=[task_url_extraction, task_data_extraction, blog_writing_task],
|
||||
verbose=True,
|
||||
process="hierarchical",
|
||||
manager_llm="gpt-4o"
|
||||
)
|
||||
|
||||
result = agents_manager.start()
|
||||
```
|
||||
|
||||
## Integration with Tools
|
||||
|
||||
Reasoning works particularly well with tools that require complex decision-making:
|
||||
|
||||
- **Code Interpreter**: For dynamic code generation and execution
|
||||
- **System Operations**: For multi-step system management tasks
|
||||
- **Data Analysis**: For complex data processing workflows
|
||||
- **Web Scraping**: For intelligent data extraction and processing
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
- Higher reflection cycles mean more thorough reasoning but longer processing time
|
||||
- `min_reflect` ensures minimum quality standards
|
||||
- `max_reflect` prevents excessive processing
|
||||
- Balance based on task complexity and quality requirements
|
||||
<Note>
|
||||
For optimal results, ensure your problem descriptions are clear and provide sufficient context for the reasoning agents.
|
||||
</Note>
|
||||
@@ -1,10 +1,125 @@
|
||||
---
|
||||
title: "Self Reflection AI Agents"
|
||||
sidebarTitle: "Self-Reflection"
|
||||
description: "Self-reflection is a powerful feature in PraisonAI that enables agents to evaluate and improve their own responses before delivering them. This leads to higher quality outputs and more reliable task completion."
|
||||
sidebarTitle: "Self Reflection Agents"
|
||||
description: "Self-reflection enables agents to evaluate and improve their own responses before delivering them."
|
||||
icon: "brain"
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `app.py` with the basic setup:
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create an agent with self-reflection
|
||||
agent = Agent(
|
||||
role="Senior Research Analyst",
|
||||
goal="Analyze and provide insights on given topics",
|
||||
backstory="You are an expert analyst with strong critical thinking skills",
|
||||
self_reflect=True # Enable self-reflection
|
||||
)
|
||||
|
||||
# Create a task
|
||||
task = Task(
|
||||
description="Analyze recent developments in AI",
|
||||
expected_output="A detailed analysis report",
|
||||
agent=agent
|
||||
)
|
||||
|
||||
# Create and start the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[agent],
|
||||
tasks=[task],
|
||||
process="sequential",
|
||||
verbose=2
|
||||
)
|
||||
|
||||
# Start execution
|
||||
agents.start()
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
Install the PraisonAI package:
|
||||
```bash
|
||||
pip install praisonai
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create a file">
|
||||
Create a new file `agents.yaml` with the basic setup:
|
||||
```yaml
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
topic: create movie script about cat in mars
|
||||
roles:
|
||||
scriptwriter:
|
||||
backstory: Expert in dialogue and script structure, translating concepts into
|
||||
scripts.
|
||||
goal: Write a movie script about a cat in Mars
|
||||
role: Scriptwriter
|
||||
self_reflect: true
|
||||
min_reflect: 1
|
||||
max_reflect: 2
|
||||
tasks:
|
||||
scriptwriting_task:
|
||||
description: Turn the story concept into a production-ready movie script,
|
||||
including dialogue and scene details.
|
||||
expected_output: Final movie script with dialogue and scene details.
|
||||
tools:
|
||||
- search_tool
|
||||
```
|
||||
</Step>
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
praisonai agents.yaml
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Note>
|
||||
**Requirements**
|
||||
|
||||
- Python 3.10 or higher
|
||||
- OpenAI API key. Generate OpenAI API key [here](https://platform.openai.com/api-keys). Use Other models using [this guide](/models).
|
||||
</Note>
|
||||
|
||||
<div className="relative w-full aspect-video">
|
||||
<iframe
|
||||
className="absolute top-0 left-0 w-full h-full"
|
||||
@@ -15,88 +130,209 @@ icon: "brain"
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
## Overview
|
||||
## Understanding Self-Reflection
|
||||
|
||||
When an agent with self-reflection enabled processes a task:
|
||||
1. It generates an initial response using its tools and capabilities
|
||||
2. The agent then reflects on its own response, evaluating:
|
||||
- Completeness
|
||||
- Accuracy
|
||||
- Relevance
|
||||
- Quality
|
||||
3. Based on this reflection, the agent may revise and improve its response
|
||||
4. This cycle can repeat until the agent is satisfied with the quality
|
||||
<Card title="What is Self-Reflection?" icon="question">
|
||||
Self-reflection enables agents to:
|
||||
- Evaluate their own responses before delivery
|
||||
- Check for completeness and accuracy
|
||||
- Improve output quality through iteration
|
||||
- Ensure task requirements are met
|
||||
- Make conscious decisions about their responses
|
||||
</Card>
|
||||
|
||||
## Usage
|
||||
## Features
|
||||
|
||||
Self-reflection is enabled by default for all agents. You can explicitly control it using the `self_reflect` parameter:
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Quality Assurance" icon="check-double">
|
||||
Evaluates and improves response quality through self-review.
|
||||
</Card>
|
||||
<Card title="Iterative Improvement" icon="rotate">
|
||||
Refines responses through multiple reflection cycles.
|
||||
</Card>
|
||||
<Card title="Task Validation" icon="list-check">
|
||||
Ensures all aspects of the task are properly addressed.
|
||||
</Card>
|
||||
<Card title="Conscious Decision Making" icon="brain">
|
||||
Enables thoughtful evaluation of responses.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Multi-Agent Self-Reflection
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `app.py` with the basic setup:
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create first agent with self-reflection
|
||||
researcher = Agent(
|
||||
role="Senior Research Analyst",
|
||||
goal="Research and analyze AI developments",
|
||||
backstory="Expert analyst specializing in AI trends and impacts",
|
||||
self_reflect=True,
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Create second agent with self-reflection
|
||||
writer = Agent(
|
||||
role="Technical Writer",
|
||||
goal="Transform research into clear documentation",
|
||||
backstory="Experienced in creating technical content and documentation",
|
||||
self_reflect=True,
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Create first task
|
||||
research_task = Task(
|
||||
description="Research and analyze recent AI developments",
|
||||
expected_output="Comprehensive analysis of AI trends",
|
||||
agent=researcher
|
||||
)
|
||||
|
||||
# Create second task
|
||||
documentation_task = Task(
|
||||
description="Create technical documentation from research findings",
|
||||
expected_output="Well-structured technical documentation",
|
||||
agent=writer
|
||||
)
|
||||
|
||||
# Create and start the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher, writer],
|
||||
tasks=[research_task, documentation_task],
|
||||
process="sequential"
|
||||
)
|
||||
|
||||
# Start execution
|
||||
agents.start()
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
Install the PraisonAI package:
|
||||
```bash
|
||||
pip install praisonai duckduckgo_search
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create a file">
|
||||
Create a new file `agents.yaml` with the basic setup:
|
||||
```yaml
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
topic: create technical documentation about AI trends
|
||||
roles:
|
||||
researcher:
|
||||
backstory: Expert analyst specializing in AI trends and their implications.
|
||||
goal: Research and analyze current AI developments
|
||||
role: Senior Research Analyst
|
||||
self_reflect: true
|
||||
min_reflect: 1
|
||||
max_reflect: 2
|
||||
tasks:
|
||||
research_task:
|
||||
description: Research and analyze recent developments in AI technology.
|
||||
expected_output: Comprehensive analysis of current AI trends.
|
||||
tools:
|
||||
- duckduckgo
|
||||
|
||||
writer:
|
||||
backstory: Experienced technical writer skilled in creating clear documentation.
|
||||
goal: Transform research into accessible documentation
|
||||
role: Technical Writer
|
||||
tasks:
|
||||
documentation_task:
|
||||
description: Create technical documentation from research findings.
|
||||
expected_output: Well-structured technical documentation.
|
||||
```
|
||||
</Step>
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
praisonai agents.yaml
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### Configuration Options
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent
|
||||
|
||||
# Create an agent with advanced self-reflection configuration
|
||||
agent = Agent(
|
||||
name="Researcher",
|
||||
role="Senior Research Analyst",
|
||||
goal="Uncover cutting-edge developments in AI",
|
||||
backstory="You are an expert at analyzing tech trends",
|
||||
self_reflect=True # Enable self-reflection (default)
|
||||
role="Research Analyst",
|
||||
goal="Provide comprehensive analysis",
|
||||
backstory="Expert analyst with critical thinking skills",
|
||||
self_reflect=True, # Enable self-reflection
|
||||
verbose=True, # Enable detailed logging
|
||||
llm="gpt-4o", # Language model to use
|
||||
allow_delegation=True # Allow task delegation
|
||||
)
|
||||
```
|
||||
|
||||
## Benefits
|
||||
## Troubleshooting
|
||||
|
||||
- **Higher Quality Outputs**: Agents can catch and correct potential issues before delivering responses
|
||||
- **More Reliable Task Completion**: Self-reflection helps ensure all aspects of a task are properly addressed
|
||||
- **Conscious Decision Making**: Agents evaluate their own work, leading to more thoughtful responses
|
||||
- **Improved Accuracy**: Multiple reflection cycles help refine and perfect the output
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Response Issues" icon="rotate">
|
||||
If responses are not meeting expectations:
|
||||
- Enable verbose mode for debugging
|
||||
- Review agent configuration
|
||||
- Check task description clarity
|
||||
</Card>
|
||||
|
||||
## Integration with Processes
|
||||
<Card title="Quality Issues" icon="triangle-exclamation">
|
||||
If output quality is insufficient:
|
||||
- Enable verbose mode
|
||||
- Review agent role and goal
|
||||
- Clarify expected output
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
Self-reflection works seamlessly with both sequential and hierarchical processes:
|
||||
## Next Steps
|
||||
|
||||
- **Sequential**: Each agent self-reflects on their individual tasks
|
||||
- **Hierarchical**: Agents self-reflect before reporting to the manager agent, ensuring high-quality inputs for decision-making
|
||||
<CardGroup cols={2}>
|
||||
<Card title="AutoAgents" icon="robot" href="./autoagents">
|
||||
Learn about automatically created and managed AI agents
|
||||
</Card>
|
||||
<Card title="Mini Agents" icon="microchip" href="./mini">
|
||||
Explore lightweight, focused AI agents
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Example
|
||||
|
||||
Here's a complete example showing self-reflection in action:
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
researcher = Agent(
|
||||
name="Researcher",
|
||||
role="Senior Research Analyst",
|
||||
goal="Uncover cutting-edge developments in AI",
|
||||
backstory="You are an expert at analyzing tech trends",
|
||||
self_reflect=True,
|
||||
llm="gpt-4o"
|
||||
)
|
||||
|
||||
task = Task(
|
||||
name="research_task",
|
||||
description="Analyze 2024's AI advancements",
|
||||
expected_output="A detailed report on AI trends",
|
||||
agent=researcher
|
||||
)
|
||||
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher],
|
||||
tasks=[task],
|
||||
process="sequential"
|
||||
)
|
||||
|
||||
result = agents.start()
|
||||
```
|
||||
|
||||
In this example, the researcher agent will:
|
||||
1. Research AI advancements
|
||||
2. Generate an initial report
|
||||
3. Self-reflect on the report's quality
|
||||
4. Make improvements if needed
|
||||
5. Deliver the final, refined output
|
||||
|
||||
## Performance Impact
|
||||
|
||||
While self-reflection adds additional processing time, the improvement in output quality often justifies the extra computation.
|
||||
The number of reflection cycles need to be manually optimized to balance quality and performance.
|
||||
<Note>
|
||||
For optimal results, configure reflection parameters based on your specific use case requirements.
|
||||
</Note>
|
||||
@@ -0,0 +1,369 @@
|
||||
---
|
||||
title: "Structured AI Agents"
|
||||
description: "Learn how to create AI agents that return structured, type-safe outputs using Pydantic models and JSON."
|
||||
icon: "cube"
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `app.py` with the basic setup:
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents, Tools
|
||||
from pydantic import BaseModel
|
||||
|
||||
# Define your data structure
|
||||
class AnalysisReport(BaseModel):
|
||||
title: str
|
||||
findings: str
|
||||
summary: str
|
||||
|
||||
# Create agent
|
||||
analyst = Agent(
|
||||
role="Data Analyst",
|
||||
goal="Analyze data and provide structured insights",
|
||||
backstory="Expert in data analysis and insights generation",
|
||||
tools=[Tools.internet_search],
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Create task with structured output
|
||||
task = Task(
|
||||
description="Analyze recent AI developments",
|
||||
expected_output="Structured analysis report",
|
||||
agent=analyst,
|
||||
output_pydantic=AnalysisReport
|
||||
)
|
||||
|
||||
# Create and start the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[analyst],
|
||||
tasks=[task],
|
||||
process="sequential",
|
||||
verbose=2
|
||||
)
|
||||
|
||||
# Start execution
|
||||
result = agents.start()
|
||||
print(result.pydantic.title)
|
||||
print(result.pydantic.findings)
|
||||
print(result.pydantic.summary)
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
Install the PraisonAI package:
|
||||
```bash
|
||||
pip install praisonai
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create a file">
|
||||
Create a new file `agents.yaml` with the basic setup:
|
||||
```yaml
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
topic: analyze AI developments with structured output
|
||||
roles:
|
||||
analyst:
|
||||
backstory: Expert in data analysis and insights generation.
|
||||
goal: Analyze data and provide structured insights
|
||||
role: Data Analyst
|
||||
tools:
|
||||
- internet_search
|
||||
tasks:
|
||||
analysis_task:
|
||||
description: Analyze recent AI developments.
|
||||
expected_output: Structured analysis report.
|
||||
output_structure:
|
||||
type: pydantic
|
||||
model:
|
||||
title: str
|
||||
findings: str
|
||||
summary: str
|
||||
```
|
||||
</Step>
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
praisonai agents.yaml
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Note>
|
||||
**Requirements**
|
||||
- Python 3.10 or higher
|
||||
- OpenAI API key. Generate OpenAI API key [here](https://platform.openai.com/api-keys). Use Other models using [this guide](/models).
|
||||
- Basic understanding of Python and Pydantic
|
||||
</Note>
|
||||
|
||||
## Understanding Structured Outputs
|
||||
|
||||
<Card title="What are Structured Outputs?" icon="question">
|
||||
Structured outputs allow you to:
|
||||
- Define exact shape of data using Pydantic models
|
||||
- Get type-safe, validated responses
|
||||
- Choose between Pydantic objects or JSON
|
||||
- Ensure consistent output format across agent responses
|
||||
</Card>
|
||||
|
||||
## Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Pydantic Models" icon="cube">
|
||||
Define exact data structures with validation.
|
||||
</Card>
|
||||
<Card title="JSON Output" icon="brackets-curly">
|
||||
Get structured JSON responses.
|
||||
</Card>
|
||||
<Card title="Type Safety" icon="shield-check">
|
||||
Ensure type-safe, validated outputs.
|
||||
</Card>
|
||||
<Card title="Format Options" icon="code">
|
||||
Choose between Pydantic or JSON.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Multi-Agent Structured Analysis
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
First, install the PraisonAI Agents package:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a file">
|
||||
Create a new file `app.py` with the basic setup:
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents, Tools
|
||||
from pydantic import BaseModel
|
||||
|
||||
# Define output structures
|
||||
class ResearchReport(BaseModel):
|
||||
topic: str
|
||||
findings: str
|
||||
sources: list[str]
|
||||
|
||||
class Analysis(BaseModel):
|
||||
key_points: list[str]
|
||||
implications: str
|
||||
recommendations: str
|
||||
|
||||
# Create first agent for research
|
||||
researcher = Agent(
|
||||
role="Research Analyst",
|
||||
goal="Gather and structure research data",
|
||||
backstory="Expert in research and data collection",
|
||||
tools=[Tools.internet_search],
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Create second agent for analysis
|
||||
analyst = Agent(
|
||||
role="Data Analyst",
|
||||
goal="Analyze research and provide structured insights",
|
||||
backstory="Expert in data analysis and insights generation",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Create first task
|
||||
research_task = Task(
|
||||
description="Research quantum computing developments",
|
||||
expected_output="Structured research findings",
|
||||
agent=researcher,
|
||||
output_pydantic=ResearchReport
|
||||
)
|
||||
|
||||
# Create second task
|
||||
analysis_task = Task(
|
||||
description="Analyze research implications",
|
||||
expected_output="Structured analysis report",
|
||||
agent=analyst,
|
||||
output_pydantic=Analysis
|
||||
)
|
||||
|
||||
# Create and start the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher, analyst],
|
||||
tasks=[research_task, analysis_task],
|
||||
process="sequential"
|
||||
)
|
||||
|
||||
# Start execution
|
||||
result = agents.start()
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
<Steps>
|
||||
<Step title="Install Package">
|
||||
Install the PraisonAI package:
|
||||
```bash
|
||||
pip install praisonai
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key_here
|
||||
```
|
||||
</Step>
|
||||
<Step title="Create a file">
|
||||
Create a new file `agents.yaml` with the basic setup:
|
||||
```yaml
|
||||
framework: praisonai
|
||||
process: sequential
|
||||
topic: research and analyze quantum computing
|
||||
roles:
|
||||
researcher:
|
||||
backstory: Expert in research and data collection.
|
||||
goal: Gather and structure research data
|
||||
role: Research Analyst
|
||||
tools:
|
||||
- internet_search
|
||||
tasks:
|
||||
research_task:
|
||||
description: Research quantum computing developments.
|
||||
expected_output: Structured research findings.
|
||||
output_structure:
|
||||
type: pydantic
|
||||
model:
|
||||
topic: str
|
||||
findings: str
|
||||
sources: list[str]
|
||||
|
||||
analyst:
|
||||
backstory: Expert in data analysis and insights generation.
|
||||
goal: Analyze research and provide structured insights
|
||||
role: Data Analyst
|
||||
tasks:
|
||||
analysis_task:
|
||||
description: Analyze research implications.
|
||||
expected_output: Structured analysis report.
|
||||
output_structure:
|
||||
type: pydantic
|
||||
model:
|
||||
key_points: list[str]
|
||||
implications: str
|
||||
recommendations: str
|
||||
```
|
||||
</Step>
|
||||
<Step title="Start Agents">
|
||||
Type this in your terminal to run your agents:
|
||||
```bash
|
||||
praisonai agents.yaml
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### Configuration Options
|
||||
|
||||
```python
|
||||
# Create an agent with structured output configuration
|
||||
agent = Agent(
|
||||
role="Data Analyst",
|
||||
goal="Provide structured analysis",
|
||||
backstory="Expert in data analysis",
|
||||
tools=[Tools.internet_search],
|
||||
verbose=True, # Enable detailed logging
|
||||
llm="gpt-4o" # Language model to use
|
||||
)
|
||||
|
||||
# Task with Pydantic output
|
||||
task = Task(
|
||||
description="Analyze data",
|
||||
expected_output="Structured report",
|
||||
agent=agent,
|
||||
output_pydantic=AnalysisReport # Use Pydantic model
|
||||
# or output_json=AnalysisReport # Use JSON output
|
||||
)
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Validation Errors" icon="triangle-exclamation">
|
||||
If model validation fails:
|
||||
- Check data types match model
|
||||
- Verify required fields
|
||||
- Enable verbose mode for debugging
|
||||
</Card>
|
||||
|
||||
<Card title="Output Format" icon="code">
|
||||
If output format is incorrect:
|
||||
- Verify model definition
|
||||
- Check output_pydantic vs output_json
|
||||
- Review field specifications
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="AutoAgents" icon="robot" href="./autoagents">
|
||||
Learn about automatically created and managed AI agents
|
||||
</Card>
|
||||
<Card title="Mini Agents" icon="microchip" href="./mini">
|
||||
Explore lightweight, focused AI agents
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Note>
|
||||
For optimal results, ensure your Pydantic models accurately represent your desired output structure.
|
||||
</Note>
|
||||
@@ -1,198 +0,0 @@
|
||||
---
|
||||
title: "Multimodal AI Agents"
|
||||
description: "Guide for creating and using multimodal AI agents in PraisonAI for processing images, videos, and other media types"
|
||||
icon: "images"
|
||||
---
|
||||
|
||||
<div className="relative w-full aspect-video">
|
||||
<iframe
|
||||
className="absolute top-0 left-0 w-full h-full"
|
||||
src="https://www.youtube.com/embed/hjAWmUT1qqY"
|
||||
title="YouTube video player"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
# Multimodal AI Agents
|
||||
|
||||
PraisonAI supports multimodal AI agents capable of processing various types of media including images and videos. This enables you to create agents that can understand and analyze visual content alongside text.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
export OPENAI_API_KEY=xxxxxxxxxxxxxxxxxxxxxx
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
Create `multimodal_app.py` and add the following code:
|
||||
|
||||
```python
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create Vision Analysis Agent
|
||||
vision_agent = Agent(
|
||||
name="VisionAnalyst",
|
||||
role="Computer Vision Specialist",
|
||||
goal="Analyze images and videos to extract meaningful information",
|
||||
backstory="""You are an expert in computer vision and image analysis.
|
||||
You excel at describing images, detecting objects, and understanding visual content.""",
|
||||
llm="gpt-4o-mini",
|
||||
self_reflect=False
|
||||
)
|
||||
|
||||
# Create tasks with different media types
|
||||
task = Task(
|
||||
name="analyze_landmark",
|
||||
description="Describe this famous landmark and its architectural features.",
|
||||
expected_output="Detailed description of the landmark's architecture and significance",
|
||||
agent=vision_agent,
|
||||
images=["https://upload.wikimedia.org/wikipedia/commons/b/bf/Krakow_-_Kosciol_Mariacki.jpg"]
|
||||
)
|
||||
|
||||
# Run the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[vision_agent],
|
||||
tasks=[task],
|
||||
process="sequential",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
result = agents.start()
|
||||
print(result)
|
||||
```
|
||||
|
||||
## Agent Configuration
|
||||
|
||||
### Core Attributes
|
||||
- All standard agent attributes apply (role, goal, backstory, etc.)
|
||||
- `llm`: Must be a model that supports vision capabilities (e.g., "gpt-4o-mini")
|
||||
- `verbose`: Enable detailed logs (default: False)
|
||||
|
||||
## Task Configuration
|
||||
|
||||
### Media Support
|
||||
Tasks can include various types of media through the `images` parameter:
|
||||
|
||||
1. **Image URLs**
|
||||
```python
|
||||
task = Task(
|
||||
description="Analyze the image",
|
||||
images=["https://example.com/image.jpg"]
|
||||
)
|
||||
```
|
||||
|
||||
2. **Local Image Files**
|
||||
```python
|
||||
task = Task(
|
||||
description="Analyze the local image",
|
||||
images=["path/to/local/image.jpg"]
|
||||
)
|
||||
```
|
||||
|
||||
3. **Video Files**
|
||||
```python
|
||||
task = Task(
|
||||
description="Analyze the video content",
|
||||
images=["path/to/video.mp4"]
|
||||
)
|
||||
```
|
||||
|
||||
### Task Types
|
||||
|
||||
1. **Image Analysis**
|
||||
- Object detection
|
||||
- Scene description
|
||||
- Architectural analysis
|
||||
- Text extraction from images
|
||||
|
||||
2. **Video Analysis**
|
||||
- Event summarization
|
||||
- Object tracking
|
||||
- Action recognition
|
||||
- Text and caption extraction
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Multiple Media Sources
|
||||
Tasks can process multiple media sources simultaneously:
|
||||
|
||||
```python
|
||||
task = Task(
|
||||
description="Compare these images and describe the differences",
|
||||
images=[
|
||||
"https://example.com/image1.jpg",
|
||||
"https://example.com/image2.jpg"
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
### Combining Text and Visual Analysis
|
||||
Create tasks that leverage both text and visual understanding:
|
||||
|
||||
```python
|
||||
task = Task(
|
||||
description="""Analyze this technical diagram and:
|
||||
1. Explain the components
|
||||
2. Describe their relationships
|
||||
3. Identify any text or labels
|
||||
4. Provide technical insights""",
|
||||
images=["diagram.jpg"]
|
||||
)
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Media Handling**
|
||||
- Ensure images are in supported formats (JPEG, PNG, etc.)
|
||||
- Keep video files within reasonable size limits
|
||||
- Provide clear, high-quality media for best results
|
||||
|
||||
2. **Task Design**
|
||||
- Write clear, specific descriptions
|
||||
- Break complex analyses into subtasks
|
||||
- Include expected output format
|
||||
|
||||
3. **Performance Optimization**
|
||||
- Use appropriate model versions for your needs
|
||||
- Consider caching for repeated analyses
|
||||
- Monitor token usage with visual content
|
||||
|
||||
4. **Error Handling**
|
||||
- Validate media files before processing
|
||||
- Handle missing or corrupted files gracefully
|
||||
- Implement retry logic for failed analyses
|
||||
|
||||
## Example Use Cases
|
||||
|
||||
1. **Document Analysis**
|
||||
```python
|
||||
document_task = Task(
|
||||
description="Extract and summarize text from this document image",
|
||||
expected_output="Structured text content with key information highlighted",
|
||||
agent=vision_agent,
|
||||
images=["document.jpg"]
|
||||
)
|
||||
```
|
||||
|
||||
2. **Security Monitoring**
|
||||
```python
|
||||
security_task = Task(
|
||||
description="Monitor this security camera feed and report any suspicious activity",
|
||||
expected_output="Detailed report of detected events and anomalies",
|
||||
agent=vision_agent,
|
||||
images=["security_feed.mp4"]
|
||||
)
|
||||
```
|
||||
|
||||
3. **Medical Imaging**
|
||||
```python
|
||||
medical_task = Task(
|
||||
description="Analyze this medical scan and identify any abnormalities",
|
||||
expected_output="Professional medical image analysis report",
|
||||
agent=vision_agent,
|
||||
images=["medical_scan.jpg"]
|
||||
)
|
||||
```
|
||||
+97
-46
@@ -1,64 +1,115 @@
|
||||
---
|
||||
title: "Installation"
|
||||
description: "Guide for installing PraisonAI and its various components including framework support and additional features"
|
||||
icon: "download"
|
||||
title: Installation
|
||||
description: Set up PraisonAI in your development environment
|
||||
icon: download
|
||||
---
|
||||
|
||||
## Basic Installation
|
||||
```bash
|
||||
<RequestExample>
|
||||
```bash Code
|
||||
pip install praisonaiagents
|
||||
```
|
||||
```bash No Code
|
||||
pip install praisonai
|
||||
```
|
||||
</RequestExample>
|
||||
|
||||
## Framework-specific Installation
|
||||
<Note>
|
||||
**Requirements**
|
||||
|
||||
- Python 3.10 or higher
|
||||
- pip package manager
|
||||
- Virtual environment (recommended)
|
||||
</Note>
|
||||
|
||||
### PraisonAI Agents Support (Default)
|
||||
# Installing PraisonAI
|
||||
|
||||
```bash
|
||||
pip install praisonai
|
||||
```
|
||||
Follow these steps to set up PraisonAI in your development environment.
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
|
||||
### CrewAI Support
|
||||
```bash
|
||||
pip install "praisonai[crewai]"
|
||||
```
|
||||
<Steps>
|
||||
<Step title="Create Virtual Environment (Optional)">
|
||||
First, create and activate a virtual environment:
|
||||
<CodeGroup>
|
||||
```bash Mac/Linux
|
||||
python -m venv praisonai-env
|
||||
source praisonai-env/bin/activate
|
||||
```
|
||||
|
||||
Includes:
|
||||
- CrewAI framework
|
||||
- PraisonAI tools integration
|
||||
- Task delegation capabilities
|
||||
- Sequential and parallel task execution
|
||||
```bash Windows
|
||||
python -m venv praisonai-env
|
||||
.\praisonai-env\Scripts\activate
|
||||
```
|
||||
</CodeGroup>
|
||||
</Step>
|
||||
|
||||
### AutoGen Support
|
||||
```bash
|
||||
pip install "praisonai[autogen]"
|
||||
```
|
||||
<Step title="Install PraisonAI Agents">
|
||||
Install the core PraisonAI Package:
|
||||
```bash Terminal
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
Includes:
|
||||
- AutoGen framework
|
||||
- PraisonAI tools integration
|
||||
- Multi-agent conversation capabilities
|
||||
- Code execution environment
|
||||
<Step title="Configure Environment">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash Terminal
|
||||
export OPENAI_API_KEY=your_openai_key
|
||||
```
|
||||
</Step>
|
||||
|
||||
### Both Frameworks
|
||||
```bash
|
||||
pip install "praisonai[crewai,autogen]"
|
||||
```
|
||||
</Steps>
|
||||
</Tab>
|
||||
<Tab title="No Code">
|
||||
|
||||
## Additional Features
|
||||
<Steps>
|
||||
<Step title="Create Virtual Environment (Optional)">
|
||||
First, create and activate a virtual environment:
|
||||
<CodeGroup>
|
||||
```bash Mac/Linux
|
||||
python -m venv praisonai-env
|
||||
source praisonai-env/bin/activate
|
||||
```
|
||||
|
||||
```bash
|
||||
# UI support
|
||||
pip install "praisonai[ui]"
|
||||
```bash Windows
|
||||
python -m venv praisonai-env
|
||||
.\praisonai-env\Scripts\activate
|
||||
```
|
||||
</CodeGroup>
|
||||
</Step>
|
||||
<Step title="Install PraisonAI">
|
||||
Install the PraisonAI package:
|
||||
```bash
|
||||
pip install praisonai
|
||||
```
|
||||
</Step>
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_openai_key
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
# Chat interface
|
||||
pip install "praisonai[chat]"
|
||||
Generate your OpenAI API key from [OpenAI](https://platform.openai.com/api-keys)
|
||||
You can also use other LLM providers like Anthropic, Google, etc. Please refer to the [Models](/models) for more information.
|
||||
|
||||
# Code interface
|
||||
pip install "praisonai[code]"
|
||||
## Next Steps
|
||||
|
||||
# Realtime voice interaction
|
||||
pip install "praisonai[realtime]"
|
||||
|
||||
# Call feature
|
||||
pip install "praisonai[call]"
|
||||
```
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
title="Quick Start Guide"
|
||||
icon="bolt"
|
||||
href="/code/quickstart"
|
||||
>
|
||||
Build your first AI agent
|
||||
</Card>
|
||||
<Card
|
||||
title="API Reference"
|
||||
icon="code"
|
||||
href="/api/praisonaiagents/index"
|
||||
>
|
||||
Explore the API documentation
|
||||
</Card>
|
||||
</CardGroup>
|
||||
+343
-58
@@ -1,76 +1,361 @@
|
||||
---
|
||||
title: 'Introduction'
|
||||
description: 'Get started with PraisonAI, an intelligent AI-powered tool'
|
||||
icon: "hand-wave"
|
||||
title: "Introduction"
|
||||
description: "Welcome to PraisonAI - The Next Generation AI Agent Framework"
|
||||
icon: "book-open"
|
||||
---
|
||||
|
||||
## What is PraisonAI?
|
||||
|
||||
<Note>
|
||||
PraisonAI is a low-code, centralized framework designed to simplify the creation and orchestration of multi-agent systems for various LLM applications.
|
||||
PraisonAI is a powerful Multi-Agent Framework for building and deploying AI agents that can understand, reason, and execute complex tasks autonomously.
|
||||
</Note>
|
||||
|
||||
# Welcome to PraisonAI
|
||||
|
||||
<Frame caption="PraisonAI Framework Overview">
|
||||

|
||||
</Frame>
|
||||
|
||||
## Core Features
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Multi-Agent Systems" icon="users">
|
||||
Create and orchestrate sophisticated multi-agent systems with ease
|
||||
</Card>
|
||||
<Card title="Framework Integration" icon="puzzle-piece">
|
||||
Seamlessly integrates AutoGen and CrewAI capabilities
|
||||
</Card>
|
||||
<Card title="Low-Code Design" icon="code">
|
||||
Build complex AI systems with minimal coding required
|
||||
</Card>
|
||||
<Card title="Human-AI Interaction" icon="people-arrows">
|
||||
Enhanced support for human-agent collaboration
|
||||
<CardGroup cols={1}>
|
||||
<Card title="Welcome to PraisonAI" icon="wand-magic-sparkles">
|
||||
Build powerful autonomous agents that understand, decide, and execute with unprecedented capability.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Getting Started
|
||||
# Core Components
|
||||
<br />
|
||||
```mermaid
|
||||
graph LR
|
||||
%% Define the main flow
|
||||
Start([▶ Start]) --> Agent1
|
||||
Agent1 --> Process[⚙ Process]
|
||||
Process --> Agent2
|
||||
Agent2 --> Output([✓ Output])
|
||||
Process -.-> Agent1
|
||||
|
||||
%% Styling for main elements
|
||||
style Start fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
style Output fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
style Process fill:#5C80BC,stroke:#7C90A0,color:#fff
|
||||
|
||||
%% Define subgraphs for agents and their tasks
|
||||
subgraph Agent1[" "]
|
||||
Task1[📋 Task]
|
||||
AgentIcon1[🤖 AI Agent]
|
||||
Tools1[🔧 Tools]
|
||||
|
||||
Task1 --- AgentIcon1
|
||||
AgentIcon1 --- Tools1
|
||||
|
||||
style Task1 fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
style AgentIcon1 fill:#5C80BC,stroke:#7C90A0,color:#fff
|
||||
style Tools1 fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
end
|
||||
|
||||
subgraph Agent2[" "]
|
||||
Task2[📋 Task]
|
||||
AgentIcon2[🤖 AI Agent]
|
||||
Tools2[🔧 Tools]
|
||||
|
||||
Task2 --- AgentIcon2
|
||||
AgentIcon2 --- Tools2
|
||||
|
||||
style Task2 fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
style AgentIcon2 fill:#5C80BC,stroke:#7C90A0,color:#fff
|
||||
style Tools2 fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
end
|
||||
|
||||
%% Style for agent containers
|
||||
style Agent1 fill:#1B1F3B,stroke:#7C90A0,color:#fff
|
||||
style Agent2 fill:#1B1F3B,stroke:#7C90A0,color:#fff
|
||||
|
||||
%% Global styles
|
||||
classDef default fill:#2D3047,stroke:#7C90A0,color:#fff
|
||||
linkStyle default stroke:#7C90A0,stroke-width:2px
|
||||
```
|
||||
<br />
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Agents" icon="user-robot">
|
||||
Autonomous AI entities that can understand context and execute tasks
|
||||
</Card>
|
||||
<Card title="Tasks" icon="list-check">
|
||||
Units of work that agents can execute independently or collaboratively
|
||||
</Card>
|
||||
<Card title="Process" icon="diagram-project">
|
||||
Workflow management for coordinating agent activities
|
||||
</Card>
|
||||
<Card title="Tools" icon="toolbox">
|
||||
Extensible capabilities that agents can leverage
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Steps>
|
||||
<Step title="Installation">
|
||||
Follow our [Installation Guide](./installation) to set up PraisonAI
|
||||
</Step>
|
||||
<Step title="Quick Overview">
|
||||
Check out our [TL;DR](./tldr) for a rapid introduction
|
||||
</Step>
|
||||
<Step title="First Project">
|
||||
Create your first project following our [Quick Start](./quickstart) guide
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Key Components
|
||||
|
||||
| Component | Description | Benefits |
|
||||
|:----------|:------------|:---------|
|
||||
| **UI Tools** | Intuitive interface components | Easy system interaction and monitoring |
|
||||
| **Model Integration** | Support for various LLM models | Flexibility in AI model selection |
|
||||
| **Tool System** | Extensible tool framework | Custom capability integration |
|
||||
| **API Layer** | Comprehensive API access | Full programmatic control |
|
||||
|
||||
## Explore Further
|
||||
## Use Cases
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="User Interface" icon="desktop" href="./ui/ui">
|
||||
Learn about our intuitive UI components
|
||||
<Card title="Customer Service" icon="headset">
|
||||
Build intelligent support agents that can handle customer inquiries and resolve issues autonomously.
|
||||
</Card>
|
||||
<Card title="Models" icon="robot" href="./models">
|
||||
Explore supported AI models
|
||||
<Card title="Data Analysis" icon="chart-line">
|
||||
Create agents that can process, analyze, and derive insights from complex datasets.
|
||||
</Card>
|
||||
<Card title="Tools" icon="wrench" href="./tools">
|
||||
Discover available tools and integrations
|
||||
<Card title="Content Creation" icon="pen-nib">
|
||||
Deploy agents that can generate, edit, and optimize content across various formats.
|
||||
</Card>
|
||||
<Card title="API Reference" icon="code" href="./api-reference">
|
||||
Access comprehensive API documentation
|
||||
<Card title="Process Automation" icon="gears">
|
||||
Automate complex workflows with intelligent agents that can coordinate and execute tasks.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Getting Started is Easy
|
||||
<Tabs>
|
||||
<Tab title="Code">
|
||||
<Steps>
|
||||
|
||||
<Step title="Install PraisonAI">
|
||||
Install the core package:
|
||||
```bash Terminal
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Configure Environment">
|
||||
```bash Terminal
|
||||
export OPENAI_API_KEY=your_openai_key
|
||||
```
|
||||
Generate your OpenAI API key from [OpenAI](https://platform.openai.com/api-keys)
|
||||
Use other LLM providers like Ollama, Anthropic, Groq, Google, etc. Please refer to the [Models](/models) for more information.
|
||||
</Step>
|
||||
|
||||
<Step title="Create Agent">
|
||||
Create `app.py`:
|
||||
<CodeGroup>
|
||||
```python Single Agent
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create an agent
|
||||
researcher = Agent(
|
||||
name="Researcher",
|
||||
role="Senior Research Analyst",
|
||||
goal="Uncover cutting-edge developments in AI",
|
||||
backstory="You are an expert at a technology research group",
|
||||
verbose=True,
|
||||
llm="gpt-4o"
|
||||
)
|
||||
|
||||
# Define a task
|
||||
task = Task(
|
||||
name="research_task",
|
||||
description="Analyze 2024's AI advancements",
|
||||
expected_output="A detailed report",
|
||||
agent=researcher
|
||||
)
|
||||
|
||||
# Run the agents
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher],
|
||||
tasks=[task],
|
||||
verbose=False
|
||||
)
|
||||
|
||||
result = agents.start()
|
||||
```
|
||||
|
||||
```python Multiple Agents
|
||||
from praisonaiagents import Agent, Task, PraisonAIAgents
|
||||
|
||||
# Create multiple agents
|
||||
researcher = Agent(
|
||||
name="Researcher",
|
||||
role="Senior Research Analyst",
|
||||
goal="Uncover cutting-edge developments in AI",
|
||||
backstory="You are an expert at a technology research group",
|
||||
verbose=True,
|
||||
llm="gpt-4o",
|
||||
markdown=True
|
||||
)
|
||||
|
||||
writer = Agent(
|
||||
name="Writer",
|
||||
role="Tech Content Strategist",
|
||||
goal="Craft compelling content on tech advancements",
|
||||
backstory="You are a content strategist",
|
||||
llm="gpt-4o",
|
||||
markdown=True
|
||||
)
|
||||
|
||||
# Define multiple tasks
|
||||
task1 = Task(
|
||||
name="research_task",
|
||||
description="Analyze 2024's AI advancements",
|
||||
expected_output="A detailed report",
|
||||
agent=researcher
|
||||
)
|
||||
|
||||
task2 = Task(
|
||||
name="writing_task",
|
||||
description="Create a blog post about AI advancements",
|
||||
expected_output="A blog post",
|
||||
agent=writer
|
||||
)
|
||||
|
||||
# Run with hierarchical process
|
||||
agents = PraisonAIAgents(
|
||||
agents=[researcher, writer],
|
||||
tasks=[task1, task2],
|
||||
verbose=False,
|
||||
process="hierarchical",
|
||||
manager_llm="gpt-4o"
|
||||
)
|
||||
|
||||
result = agents.start()
|
||||
```
|
||||
</CodeGroup>
|
||||
</Step>
|
||||
|
||||
<Step title="Start Agents">
|
||||
Execute your script:
|
||||
```bash Terminal
|
||||
python app.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
|
||||
<Tab title="No Code">
|
||||
<Steps>
|
||||
|
||||
<Step title="Install PraisonAI">
|
||||
Install the PraisonAI package:
|
||||
```bash
|
||||
pip install praisonai
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set API Key">
|
||||
Set your OpenAI API key as an environment variable in your terminal:
|
||||
```bash Terminal
|
||||
export OPENAI_API_KEY=your_openai_key
|
||||
```
|
||||
Generate your OpenAI API key from [OpenAI](https://platform.openai.com/api-keys)
|
||||
Use other LLM providers like Ollama, Anthropic, Groq, Google, etc. Please refer to the [Models](/models) for more information.
|
||||
</Step>
|
||||
|
||||
<Step title="Start AutoAgents">
|
||||
Run your AutoAgents:
|
||||
```bash
|
||||
praisonai --auto "Create a movie script about a robot in Mars"
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Key Features
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card title="Autonomous Agents" icon="robot">
|
||||
Create intelligent agents that can:
|
||||
|
||||
- Understand natural language instructions
|
||||
- Make decisions based on context
|
||||
- Execute complex tasks autonomously
|
||||
</Card>
|
||||
|
||||
<Card title="Flexible Architecture" icon="cubes">
|
||||
Build with:
|
||||
|
||||
- Modular components
|
||||
- Extensible tools
|
||||
- Customizable workflows
|
||||
</Card>
|
||||
|
||||
<Card title="Advanced Capabilities" icon="wand-sparkles">
|
||||
Leverage:
|
||||
|
||||
- Multi-agent collaboration
|
||||
- Memory and context management
|
||||
- Tool integration
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
|
||||
<Card title="Why Choose PraisonAI?" icon="stars">
|
||||
<CardGroup cols={2}>
|
||||
## Developer First
|
||||
Build with modern tools and frameworks you already love. Our SDK is designed to be intuitive and powerful.
|
||||
|
||||
## Production Ready
|
||||
Enterprise-grade reliability with built-in security features and scalable architecture.
|
||||
|
||||
## Open Source
|
||||
PraisonAI is open source and available on [GitHub](https://github.com/MervinPraison/PraisonAI).
|
||||
|
||||
## Low Code User Friendly
|
||||
PraisonAI is designed to be easy to learn and use for non technical users.
|
||||
</CardGroup>
|
||||
</Card>
|
||||
|
||||
## Chat with One Agent
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Basic Agent">
|
||||
<Steps>
|
||||
<Step title="Install PraisonAI">
|
||||
Get started with a simple pip install:
|
||||
```bash
|
||||
pip install praisonaiagents
|
||||
```
|
||||
</Step>
|
||||
<Step title="Initialize Your Agent">
|
||||
Create your first autonomous agent in just a few lines:
|
||||
```python
|
||||
from praisonaiagents import Agent
|
||||
agent = Agent(instructions="Your are a helpful AI assistant")
|
||||
agent.chat("Write a movie script about a robot in Mars")
|
||||
```
|
||||
</Step>
|
||||
<Step title="Build Amazing Things">
|
||||
Start building powerful AI applications with autonomous capabilities!
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
|
||||
<Tab title="Agent with Tools">
|
||||
<Steps>
|
||||
<Step title="Install PraisonAI">
|
||||
Get started with a simple pip install:
|
||||
```bash
|
||||
pip install praisonaiagents duckduckgo_search
|
||||
```
|
||||
</Step>
|
||||
<Step title="Initialize Your Agent">
|
||||
|
||||
Create your first autonomous agent in just a few lines:
|
||||
```python
|
||||
from praisonaiagents import Agent, Tools
|
||||
agent = Agent(instructions="Your are a helpful AI assistant", tools=[Tools.internet_search])
|
||||
agent.chat("Write a movie script about a robot in Mars")
|
||||
```
|
||||
</Step>
|
||||
<Step title="Build Amazing Things">
|
||||
Start building powerful AI applications with autonomous capabilities!
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
title="Installation"
|
||||
icon="download"
|
||||
href="/code/installation"
|
||||
>
|
||||
Complete installation guide and setup instructions
|
||||
</Card>
|
||||
<Card
|
||||
title="Quick Start"
|
||||
icon="play"
|
||||
href="/code/quickstart"
|
||||
>
|
||||
Build your first AI agent in minutes
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Tip>
|
||||
Start with our no-code interface to learn the basics, then transition to code-based development for more advanced use cases.
|
||||
</Tip>
|
||||
Join our community on [Discord](https://www.youtube.com/redirect?event=channel_description&redir_token=QUFFLUhqbUpiZE00YlF1MjB1LVNIeTFxTnV6MWRRc18wZ3xBQ3Jtc0ttQVZ0aFJ4RXRDanlBQU1Vd3lHU3BBcml3bzhoek1pTmlkZkFkWjlNVDBpRkxZd1dTOWhPc20xbHJOb1NibmNYeTEydklJT0pZOVJFQW93MmJOQXU0WkJNVzNsd29SZ3FBNFVwMTFGNThNSHBWVUhjSQ&q=https%3A%2F%2Fdiscord.gg%2FnNZu5gGT59) to connect with other developers and get help!
|
||||
</Tip>
|
||||
Loaded 100 of 135 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user