Skip to content

Commit 327d0d3

Browse files
Merge pull request #63 from MervinPraison/develop
v0.0.36
2 parents bfe954e + 44920c9 commit 327d0d3

File tree

10 files changed

+451
-104
lines changed

10 files changed

+451
-104
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
FROM python:3.11-slim
22
WORKDIR /app
33
COPY . .
4-
RUN pip install flask praisonai==0.0.35 gunicorn markdown
4+
RUN pip install flask praisonai==0.0.36 gunicorn markdown
55
EXPOSE 8080
66
CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]

docs/api/praisonai/agents_generator.html

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
5252
<dl>
5353
<dt id="praisonai.agents_generator.AgentsGenerator"><code class="flex name class">
5454
<span>class <span class="ident">AgentsGenerator</span></span>
55-
<span>(</span><span>agent_file, framework, config_list, log_level=20, agent_callback=None, task_callback=None)</span>
55+
<span>(</span><span>agent_file, framework, config_list, log_level=None, agent_callback=None, task_callback=None)</span>
5656
</code></dt>
5757
<dd>
5858
<div class="desc"><p>Initialize the AgentsGenerator object.</p>
@@ -83,7 +83,7 @@ <h2 id="attributes">Attributes</h2>
8383
<span>Expand source code</span>
8484
</summary>
8585
<pre><code class="python">class AgentsGenerator:
86-
def __init__(self, agent_file, framework, config_list, log_level=logging.INFO, agent_callback=None, task_callback=None):
86+
def __init__(self, agent_file, framework, config_list, log_level=None, agent_callback=None, task_callback=None):
8787
&#34;&#34;&#34;
8888
Initialize the AgentsGenerator object.
8989

@@ -109,6 +109,9 @@ <h2 id="attributes">Attributes</h2>
109109
self.log_level = log_level
110110
self.agent_callback = agent_callback
111111
self.task_callback = task_callback
112+
self.log_level = log_level or logging.getLogger().getEffectiveLevel()
113+
if self.log_level == logging.NOTSET:
114+
self.log_level = os.environ.get(&#39;LOGLEVEL&#39;, &#39;INFO&#39;).upper()
112115

113116
logging.basicConfig(level=self.log_level, format=&#39;%(asctime)s - %(levelname)s - %(message)s&#39;)
114117
self.logger = logging.getLogger(__name__)
@@ -241,10 +244,10 @@ <h2 id="attributes">Attributes</h2>
241244

242245
if os.path.isfile(tools_py_path):
243246
tools_dict.update(self.load_tools_from_module_class(tools_py_path))
244-
# print(&#34;tools.py exists in the root directory. Loading tools.py and skipping tools folder.&#34;)
247+
self.logger.debug(&#34;tools.py exists in the root directory. Loading tools.py and skipping tools folder.&#34;)
245248
elif tools_dir_path.is_dir():
246249
tools_dict.update(self.load_tools_from_module_class(tools_dir_path))
247-
# print(&#34;tools folder exists in the root directory&#34;)
250+
self.logger.debug(&#34;tools folder exists in the root directory&#34;)
248251

249252
framework = self.framework or config.get(&#39;framework&#39;)
250253

@@ -328,11 +331,15 @@ <h2 id="attributes">Attributes</h2>
328331
task.callback = self.task_callback
329332

330333
tasks.append(task)
334+
if agentops:
335+
agentops.init()
331336
crew = Crew(
332337
agents=list(agents.values()),
333338
tasks=tasks,
334339
verbose=2
335340
)
341+
if agentops:
342+
agentops.end_session(&#34;Success&#34;)
336343

337344
self.logger.debug(&#34;Final Crew Configuration:&#34;)
338345
self.logger.debug(f&#34;Agents: {crew.agents}&#34;)

docs/api/praisonai/deploy.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ <h2 id="raises">Raises</h2>
110110
file.write(&#34;FROM python:3.11-slim\n&#34;)
111111
file.write(&#34;WORKDIR /app\n&#34;)
112112
file.write(&#34;COPY . .\n&#34;)
113-
file.write(&#34;RUN pip install flask praisonai==0.0.35 gunicorn markdown\n&#34;)
113+
file.write(&#34;RUN pip install flask praisonai==0.0.36 gunicorn markdown\n&#34;)
114114
file.write(&#34;EXPOSE 8080\n&#34;)
115115
file.write(&#39;CMD [&#34;gunicorn&#34;, &#34;-b&#34;, &#34;0.0.0.0:8080&#34;, &#34;api:app&#34;]\n&#39;)
116116

poetry.lock

Lines changed: 312 additions & 85 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

praisonai/agents_generator.py

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@
2424
import importlib.util
2525
from praisonai_tools import BaseTool
2626
import os
27+
import logging
28+
29+
agentops = False
30+
try:
31+
import agentops
32+
agentops = True
33+
except ImportError:
34+
agentops = False
2735

2836
os.environ["OTEL_SDK_DISABLED"] = "true"
2937

@@ -38,23 +46,39 @@ def disable_crewai_telemetry():
3846
disable_crewai_telemetry()
3947

4048
class AgentsGenerator:
41-
def __init__(self, agent_file, framework, config_list):
49+
def __init__(self, agent_file, framework, config_list, log_level=None, agent_callback=None, task_callback=None):
4250
"""
4351
Initialize the AgentsGenerator object.
4452
4553
Parameters:
4654
agent_file (str): The path to the agent file.
4755
framework (str): The framework to be used for the agents.
4856
config_list (list): A list of configurations for the agents.
57+
log_level (int, optional): The logging level to use. Defaults to logging.INFO.
58+
agent_callback (callable, optional): A callback function to be executed after each agent step.
59+
task_callback (callable, optional): A callback function to be executed after each tool run.
4960
5061
Attributes:
5162
agent_file (str): The path to the agent file.
5263
framework (str): The framework to be used for the agents.
5364
config_list (list): A list of configurations for the agents.
65+
log_level (int): The logging level to use.
66+
agent_callback (callable, optional): A callback function to be executed after each agent step.
67+
task_callback (callable, optional): A callback function to be executed after each tool run.
5468
"""
5569
self.agent_file = agent_file
5670
self.framework = framework
5771
self.config_list = config_list
72+
self.log_level = log_level
73+
self.agent_callback = agent_callback
74+
self.task_callback = task_callback
75+
self.log_level = log_level or logging.getLogger().getEffectiveLevel()
76+
if self.log_level == logging.NOTSET:
77+
self.log_level = os.environ.get('LOGLEVEL', 'INFO').upper()
78+
79+
logging.basicConfig(level=self.log_level, format='%(asctime)s - %(levelname)s - %(message)s')
80+
self.logger = logging.getLogger(__name__)
81+
self.logger.setLevel(self.log_level)
5882

5983
def is_function_or_decorated(self, obj):
6084
"""
@@ -183,10 +207,10 @@ def generate_crew_and_kickoff(self):
183207

184208
if os.path.isfile(tools_py_path):
185209
tools_dict.update(self.load_tools_from_module_class(tools_py_path))
186-
# print("tools.py exists in the root directory. Loading tools.py and skipping tools folder.")
210+
self.logger.debug("tools.py exists in the root directory. Loading tools.py and skipping tools folder.")
187211
elif tools_dir_path.is_dir():
188212
tools_dict.update(self.load_tools_from_module_class(tools_dir_path))
189-
# print("tools folder exists in the root directory")
213+
self.logger.debug("tools folder exists in the root directory")
190214

191215
framework = self.framework or config.get('framework')
192216

@@ -252,20 +276,39 @@ def generate_crew_and_kickoff(self):
252276
# Adding tools to the agent if exists
253277
agent_tools = [tools_dict[tool] for tool in details.get('tools', []) if tool in tools_dict]
254278
agent = Agent(role=role_filled, goal=goal_filled, backstory=backstory_filled, tools=agent_tools, allow_delegation=False)
279+
280+
# Set agent callback if provided
281+
if self.agent_callback:
282+
agent.step_callback = self.agent_callback
283+
255284
agents[role] = agent
256285

257286
for task_name, task_details in details.get('tasks', {}).items():
258287
description_filled = task_details['description'].format(topic=topic)
259288
expected_output_filled = task_details['expected_output'].format(topic=topic)
260289

261290
task = Task(description=description_filled, expected_output=expected_output_filled, agent=agent)
291+
292+
# Set tool callback if provided
293+
if self.task_callback:
294+
task.callback = self.task_callback
295+
262296
tasks.append(task)
297+
if agentops:
298+
agentops.init()
263299
crew = Crew(
264300
agents=list(agents.values()),
265301
tasks=tasks,
266302
verbose=2
267303
)
304+
if agentops:
305+
agentops.end_session("Success")
306+
307+
self.logger.debug("Final Crew Configuration:")
308+
self.logger.debug(f"Agents: {crew.agents}")
309+
self.logger.debug(f"Tasks: {crew.tasks}")
268310

269311
response = crew.kickoff()
270312
result = f"### Task Output ###\n{response}"
271313
return result
314+

praisonai/chainlit_ui.py

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from typing import Optional
99
from dotenv import load_dotenv
1010
load_dotenv()
11+
from contextlib import redirect_stdout
12+
from io import StringIO
1113

1214
framework = "crewai"
1315
config_list = [
@@ -178,20 +180,80 @@ async def on_chat_resume(thread: ThreadDict):
178180
# async def tool(data: Optional[str] = None, language: Optional[str] = None):
179181
# return cl.Message(content=data, language=language)
180182

183+
@cl.step(type="tool", show_input=False)
184+
async def run_agents(agent_file: str, framework: str):
185+
"""Runs the agents and returns the result."""
186+
agents_generator = AgentsGenerator(agent_file, framework, config_list)
187+
current_step = cl.context.current_step
188+
print("Current Step:", current_step)
189+
190+
stdout_buffer = StringIO()
191+
with redirect_stdout(stdout_buffer):
192+
result = agents_generator.generate_crew_and_kickoff()
193+
194+
complete_output = stdout_buffer.getvalue()
195+
196+
async with cl.Step(name="gpt4", type="llm", show_input=True) as step:
197+
step.input = ""
198+
199+
for line in stdout_buffer.getvalue().splitlines():
200+
print(line)
201+
await step.stream_token(line)
202+
203+
tool_res = await output(complete_output)
204+
205+
yield result
206+
207+
@cl.step(type="tool", show_input=False, language="yaml")
208+
async def output(output):
209+
return output
210+
211+
@cl.step(type="tool", show_input=False, language="yaml")
212+
def agent(output):
213+
return(f"""
214+
Agent Step Completed!
215+
Output: {output}
216+
""")
217+
218+
@cl.step(type="tool", show_input=False, language="yaml")
219+
def task(output):
220+
return(f"""
221+
Task Completed!
222+
Task: {output.description}
223+
Output: {output.raw_output}
224+
{output}
225+
""")
226+
181227
@cl.on_message
182228
async def main(message: cl.Message):
183229
"""Run PraisonAI with the provided message as the topic."""
184230
message_history = cl.user_session.get("message_history")
231+
if message_history is None:
232+
message_history = []
233+
cl.user_session.set("message_history", message_history)
185234
message_history.append({"role": "user", "content": message.content})
186235
topic = message.content
187236
chat_profile = cl.user_session.get("chat_profile")
188237

189238
if chat_profile == "Auto":
190239
agent_file = "agents.yaml"
191240
generator = AutoGenerator(topic=topic, agent_file=agent_file, framework=framework, config_list=config_list)
241+
await cl.sleep(2)
192242
agent_file = generator.generate()
193-
agents_generator = AgentsGenerator(agent_file, framework, config_list)
194-
result = agents_generator.generate_crew_and_kickoff()
243+
agents_generator = AgentsGenerator(
244+
agent_file,
245+
framework,
246+
config_list,
247+
# agent_callback=agent,
248+
# task_callback=task
249+
)
250+
# Capture stdout
251+
stdout_buffer = StringIO()
252+
with redirect_stdout(stdout_buffer):
253+
result = agents_generator.generate_crew_and_kickoff()
254+
255+
complete_output = stdout_buffer.getvalue()
256+
tool_res = await output(complete_output)
195257
msg = cl.Message(content=result)
196258
await msg.send()
197259
message_history.append({"role": "assistant", "content": message.content})

praisonai/deploy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def create_dockerfile(self):
5656
file.write("FROM python:3.11-slim\n")
5757
file.write("WORKDIR /app\n")
5858
file.write("COPY . .\n")
59-
file.write("RUN pip install flask praisonai==0.0.35 gunicorn markdown\n")
59+
file.write("RUN pip install flask praisonai==0.0.36 gunicorn markdown\n")
6060
file.write("EXPOSE 8080\n")
6161
file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
6262

praisonai/inbuilt_tools/autogen_tools.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import os
1515
import inspect
1616
import sys
17+
import logging
18+
logging.basicConfig(level=os.environ.get('LOGLEVEL', 'INFO'), format='%(asctime)s - %(levelname)s - %(message)s')
1719

1820
def create_autogen_tool_function(tool_name):
1921
def autogen_tool(assistant, user_proxy):
@@ -51,10 +53,10 @@ def tool_func(query: str) -> Any:
5153
tools_module = None
5254

5355
if os.path.isfile(tools_py_path):
54-
print(f"{tools_py_path} exists in the root directory. Loading {tools_py_path} and skipping tools folder.")
56+
logging.info(f"{tools_py_path} exists in the root directory. Loading {tools_py_path} and skipping tools folder.")
5557
tools_module = importlib.import_module("tools")
5658
elif tools_dir_path.is_dir():
57-
print(f"tools folder exists in the root directory. Loading {tool_name} from tools/{tool_name}.py.")
59+
logging.info(f"tools folder exists in the root directory. Loading {tool_name} from tools/{tool_name}.py.")
5860
tools_module = importlib.import_module(f"tools.{tool_name}")
5961

6062
# Create autogen_TOOL_NAME_HERE function for each tool

pyproject.toml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "PraisonAI"
3-
version = "0.0.35"
3+
version = "0.0.36"
44
description = "PraisonAI application combines AutoGen and CrewAI or similar frameworks into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customization, and efficient human-agent collaboration."
55
authors = ["Mervin Praison"]
66
license = ""
@@ -24,10 +24,12 @@ pyparsing = ">=3.0.0"
2424
chainlit = {version = "^1.1.301", optional = true}
2525
gradio = {version = ">=4.26.0", optional = true}
2626
flask = {version = ">=3.0.0", optional = true}
27+
agentops = {version = "==0.2.3", optional = true}
2728

2829
[tool.poetry.dev-dependencies]
29-
pytest = "^8.0.0"
30-
pre-commit = "^3.7"
30+
pytest = "8.2.2"
31+
pre-commit = "3.7.1"
32+
unittest-xml-reporting = "3.2.0"
3133

3234
[build-system]
3335
requires = ["poetry-core"]
@@ -39,4 +41,5 @@ praisonai = "praisonai.__main__:main"
3941
[tool.poetry.extras]
4042
ui = ["chainlit"]
4143
gradio = ["gradio"]
42-
api = ["flask"]
44+
api = ["flask"]
45+
agentops = ["agentops"]

tests/test.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# tests/test.py
21
import unittest
32
import subprocess
43
from praisonai.cli import PraisonAI
@@ -7,6 +6,10 @@
76
from .auto_example import auto
87
from xmlrunner import XMLTestRunner
98

9+
# Patch for collections.abc MutableMapping issue
10+
import collections.abc
11+
collections.MutableMapping = collections.abc.MutableMapping
12+
1013
class TestPraisonAIFramework(unittest.TestCase):
1114
def test_main_with_autogen_framework(self):
1215
praison_ai = PraisonAI(agent_file='tests/autogen-agents.yaml')

0 commit comments

Comments
 (0)