diff --git a/docker/Dockerfile b/docker/Dockerfile index aa702f2a6..277d55751 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,6 +1,6 @@ FROM python:3.11-slim WORKDIR /app COPY . . -RUN pip install flask praisonai==2.2.0 gunicorn markdown +RUN pip install flask praisonai==2.2.1 gunicorn markdown EXPOSE 8080 CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"] diff --git a/docker/Dockerfile.chat b/docker/Dockerfile.chat index 0157ce181..10a9e8b00 100644 --- a/docker/Dockerfile.chat +++ b/docker/Dockerfile.chat @@ -13,7 +13,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ RUN pip install --no-cache-dir \ praisonaiagents>=0.0.4 \ praisonai_tools \ - "praisonai==2.2.0" \ + "praisonai==2.2.1" \ "praisonai[chat]" \ "embedchain[github,youtube]" diff --git a/docker/Dockerfile.dev b/docker/Dockerfile.dev index e86e365cd..c0130b5cc 100644 --- a/docker/Dockerfile.dev +++ b/docker/Dockerfile.dev @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ RUN pip install --no-cache-dir \ praisonaiagents>=0.0.4 \ praisonai_tools \ - "praisonai==2.2.0" \ + "praisonai==2.2.1" \ "praisonai[ui]" \ "praisonai[chat]" \ "praisonai[realtime]" \ diff --git a/docker/Dockerfile.ui b/docker/Dockerfile.ui index a4f566904..8a92e9b16 100644 --- a/docker/Dockerfile.ui +++ b/docker/Dockerfile.ui @@ -13,7 +13,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ RUN pip install --no-cache-dir \ praisonaiagents>=0.0.4 \ praisonai_tools \ - "praisonai==2.2.0" \ + "praisonai==2.2.1" \ "praisonai[ui]" \ "praisonai[crewai]" diff --git a/docs/api/praisonai/deploy.html b/docs/api/praisonai/deploy.html index 49d95c40e..d53fd43dd 100644 --- a/docs/api/praisonai/deploy.html +++ b/docs/api/praisonai/deploy.html @@ -110,7 +110,7 @@

Raises

file.write("FROM python:3.11-slim\n") file.write("WORKDIR /app\n") file.write("COPY . .\n") - file.write("RUN pip install flask praisonai==2.2.0 gunicorn markdown\n") + file.write("RUN pip install flask praisonai==2.2.1 gunicorn markdown\n") file.write("EXPOSE 8080\n") file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n') diff --git a/docs/developers/local-development.mdx b/docs/developers/local-development.mdx index b919b2116..56f730d42 100644 --- a/docs/developers/local-development.mdx +++ b/docs/developers/local-development.mdx @@ -27,7 +27,7 @@ WORKDIR /app COPY . . -RUN pip install flask praisonai==2.2.0 watchdog +RUN pip install flask praisonai==2.2.1 watchdog EXPOSE 5555 diff --git a/docs/ui/chat.mdx b/docs/ui/chat.mdx index d884788e2..50859cbba 100644 --- a/docs/ui/chat.mdx +++ b/docs/ui/chat.mdx @@ -155,7 +155,7 @@ To facilitate local development with live reload, you can use Docker. Follow the COPY . . - RUN pip install flask praisonai==2.2.0 watchdog + RUN pip install flask praisonai==2.2.1 watchdog EXPOSE 5555 diff --git a/docs/ui/code.mdx b/docs/ui/code.mdx index c5afbbbae..3d73a83aa 100644 --- a/docs/ui/code.mdx +++ b/docs/ui/code.mdx @@ -208,7 +208,7 @@ To facilitate local development with live reload, you can use Docker. Follow the COPY . . - RUN pip install flask praisonai==2.2.0 watchdog + RUN pip install flask praisonai==2.2.1 watchdog EXPOSE 5555 diff --git a/praisonai/deploy.py b/praisonai/deploy.py index e25ac6a9e..084bbc99f 100644 --- a/praisonai/deploy.py +++ b/praisonai/deploy.py @@ -56,7 +56,7 @@ def create_dockerfile(self): file.write("FROM python:3.11-slim\n") file.write("WORKDIR /app\n") file.write("COPY . .\n") - file.write("RUN pip install flask praisonai==2.2.0 gunicorn markdown\n") + file.write("RUN pip install flask praisonai==2.2.1 gunicorn markdown\n") file.write("EXPOSE 8080\n") file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n') diff --git a/pyproject.toml b/pyproject.toml index 55041349f..ee7655b67 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "PraisonAI" -version = "2.2.0" +version = "2.2.1" description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration." readme = "README.md" license = "" @@ -12,7 +12,7 @@ dependencies = [ "rich>=13.7", "markdown>=3.5", "pyparsing>=3.0.0", - "praisonaiagents>=0.0.83", + "praisonaiagents>=0.0.85", "python-dotenv>=0.19.0", "instructor>=1.3.3", "PyYAML>=6.0", @@ -89,7 +89,7 @@ autogen = ["pyautogen>=0.2.19", "praisonai-tools>=0.0.15", "crewai"] [tool.poetry] name = "PraisonAI" -version = "2.2.0" +version = "2.2.1" description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration." authors = ["Mervin Praison"] license = "" @@ -107,7 +107,7 @@ python = ">=3.10,<3.13" rich = ">=13.7" markdown = ">=3.5" pyparsing = ">=3.0.0" -praisonaiagents = ">=0.0.83" +praisonaiagents = ">=0.0.85" python-dotenv = ">=0.19.0" instructor = ">=1.3.3" PyYAML = ">=6.0" diff --git a/src/praisonai-agents/mcp-sse.py b/src/praisonai-agents/mcp-sse.py index 7cb92b995..bd60f4f0f 100644 --- a/src/praisonai-agents/mcp-sse.py +++ b/src/praisonai-agents/mcp-sse.py @@ -1,9 +1,8 @@ from praisonaiagents import Agent, MCP -qa_agent = Agent( - instructions="""You are a Question Answering Agent.""", - llm="openai/gpt-4o-mini", - tools=MCP("http://localhost:8080/agents/sse") +tweet_agent = Agent( + instructions="""You are a Tweet Formatter Agent.""", + tools=MCP("http://localhost:8080/sse") ) -qa_agent.start("AI in 2025") \ No newline at end of file +tweet_agent.start("AI in Healthcare") \ No newline at end of file diff --git a/src/praisonai-agents/openai-mcp.py b/src/praisonai-agents/openai-mcp.py index c03e86c0c..5ed2bf32e 100644 --- a/src/praisonai-agents/openai-mcp.py +++ b/src/praisonai-agents/openai-mcp.py @@ -2,8 +2,7 @@ search_agent = Agent( instructions="""You help book apartments on Airbnb.""", - llm="openai/gpt-4o-mini", tools=MCP("npx -y @openbnb/mcp-server-airbnb --ignore-robots-txt") ) -search_agent.start("I want to book an apartment in Paris for 2 nights. 03/28 - 03/30 for 2 adults") \ No newline at end of file +search_agent.start("Search apartment in Paris for 2 nights. 07/28 - 07/30 for 2 adults") \ No newline at end of file diff --git a/src/praisonai-agents/praisonaiagents/mcp/mcp.py b/src/praisonai-agents/praisonaiagents/mcp/mcp.py index 6233e07a4..a31639001 100644 --- a/src/praisonai-agents/praisonaiagents/mcp/mcp.py +++ b/src/praisonai-agents/praisonaiagents/mcp/mcp.py @@ -16,13 +16,14 @@ class MCPToolRunner(threading.Thread): """A dedicated thread for running MCP operations.""" - def __init__(self, server_params): + def __init__(self, server_params, timeout=60): super().__init__(daemon=True) self.server_params = server_params self.queue = queue.Queue() self.result_queue = queue.Queue() self.initialized = threading.Event() self.tools = [] + self.timeout = timeout self.start() def run(self): @@ -74,9 +75,9 @@ async def _run_async(self): def call_tool(self, tool_name, arguments): """Call an MCP tool and wait for the result.""" if not self.initialized.is_set(): - self.initialized.wait(timeout=30) + self.initialized.wait(timeout=self.timeout) if not self.initialized.is_set(): - return "Error: MCP initialization timed out" + return f"Error: MCP initialization timed out after {self.timeout} seconds" # Put request in queue self.queue.put((tool_name, arguments)) @@ -189,7 +190,7 @@ def __init__(self, command_or_string=None, args=None, *, command=None, timeout=6 if isinstance(command_or_string, str) and re.match(r'^https?://', command_or_string): # Import the SSE client implementation from .mcp_sse import SSEMCPClient - self.sse_client = SSEMCPClient(command_or_string, debug=debug) + self.sse_client = SSEMCPClient(command_or_string, debug=debug, timeout=timeout) self._tools = list(self.sse_client.tools) self.is_sse = True self.is_npx = False @@ -216,11 +217,11 @@ def __init__(self, command_or_string=None, args=None, *, command=None, timeout=6 args=arguments, **kwargs ) - self.runner = MCPToolRunner(self.server_params) + self.runner = MCPToolRunner(self.server_params, timeout) # Wait for initialization - if not self.runner.initialized.wait(timeout=30): - print("Warning: MCP initialization timed out") + if not self.runner.initialized.wait(timeout=self.timeout): + print(f"Warning: MCP initialization timed out after {self.timeout} seconds") # Automatically detect if this is an NPX command self.is_npx = cmd == 'npx' or (isinstance(cmd, str) and os.path.basename(cmd) == 'npx') diff --git a/src/praisonai-agents/praisonaiagents/mcp/mcp_sse.py b/src/praisonai-agents/praisonaiagents/mcp/mcp_sse.py index 67f0f22c8..beb56a713 100644 --- a/src/praisonai-agents/praisonaiagents/mcp/mcp_sse.py +++ b/src/praisonai-agents/praisonaiagents/mcp/mcp_sse.py @@ -31,7 +31,7 @@ def get_event_loop(): class SSEMCPTool: """A wrapper for an MCP tool that can be used with praisonaiagents.""" - def __init__(self, name: str, description: str, session: ClientSession, input_schema: Optional[Dict[str, Any]] = None): + def __init__(self, name: str, description: str, session: ClientSession, input_schema: Optional[Dict[str, Any]] = None, timeout: int = 60): self.name = name self.__name__ = name # Required for Agent to recognize it as a tool self.__qualname__ = name # Required for Agent to recognize it as a tool @@ -39,6 +39,7 @@ def __init__(self, name: str, description: str, session: ClientSession, input_sc self.description = description self.session = session self.input_schema = input_schema or {} + self.timeout = timeout # Create a signature based on input schema params = [] @@ -66,7 +67,7 @@ def __call__(self, **kwargs): future = asyncio.run_coroutine_threadsafe(self._async_call(**kwargs), loop) try: # Wait for the result with a timeout - return future.result(timeout=30) + return future.result(timeout=self.timeout) except Exception as e: logger.error(f"Error calling tool {self.name}: {e}") return f"Error: {str(e)}" @@ -102,16 +103,18 @@ def to_openai_tool(self): class SSEMCPClient: """A client for connecting to an MCP server over SSE.""" - def __init__(self, server_url: str, debug: bool = False): + def __init__(self, server_url: str, debug: bool = False, timeout: int = 60): """ Initialize an SSE MCP client. Args: server_url: The URL of the SSE MCP server debug: Whether to enable debug logging + timeout: Timeout in seconds for operations (default: 60) """ self.server_url = server_url self.debug = debug + self.timeout = timeout self.session = None self.tools = [] @@ -139,7 +142,7 @@ def run_event_loop(): # Run the initialization in the event loop future = asyncio.run_coroutine_threadsafe(self._async_initialize(), loop) - self.tools = future.result(timeout=30) + self.tools = future.result(timeout=self.timeout) async def _async_initialize(self): """Asynchronously initialize the connection and tools.""" @@ -169,7 +172,8 @@ async def _async_initialize(self): name=tool.name, description=tool.description if hasattr(tool, 'description') else f"Call the {tool.name} tool", session=self.session, - input_schema=input_schema + input_schema=input_schema, + timeout=self.timeout ) tools.append(wrapper) diff --git a/src/praisonai-agents/pyproject.toml b/src/praisonai-agents/pyproject.toml index f51527d5a..90d73cbc1 100644 --- a/src/praisonai-agents/pyproject.toml +++ b/src/praisonai-agents/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "praisonaiagents" -version = "0.0.83" +version = "0.0.85" description = "Praison AI agents for completing complex tasks with Self Reflection Agents" authors = [ { name="Mervin Praison" } diff --git a/src/praisonai-agents/simple-mcp-server.py b/src/praisonai-agents/simple-mcp-server.py index 74b20f5ec..39430aabf 100644 --- a/src/praisonai-agents/simple-mcp-server.py +++ b/src/praisonai-agents/simple-mcp-server.py @@ -1,4 +1,4 @@ from praisonaiagents import Agent -agent = Agent(name="TweetAgent", instructions="Create a Tweet based on the topic provided") +agent = Agent(instructions="Create a Tweet") agent.launch(port=8080, protocol="mcp") \ No newline at end of file diff --git a/src/praisonai-agents/uv.lock b/src/praisonai-agents/uv.lock index 4eb08e917..fc8410b67 100644 --- a/src/praisonai-agents/uv.lock +++ b/src/praisonai-agents/uv.lock @@ -1457,7 +1457,7 @@ wheels = [ [[package]] name = "praisonaiagents" -version = "0.0.83" +version = "0.0.85" source = { editable = "." } dependencies = [ { name = "mcp" }, diff --git a/uv.lock b/uv.lock index cd76b3458..f63796b02 100644 --- a/uv.lock +++ b/uv.lock @@ -3614,7 +3614,7 @@ wheels = [ [[package]] name = "praisonai" -version = "2.2.0" +version = "2.2.1" source = { editable = "." } dependencies = [ { name = "instructor" }, @@ -3756,7 +3756,7 @@ requires-dist = [ { name = "plotly", marker = "extra == 'realtime'", specifier = ">=5.24.0" }, { name = "praisonai-tools", marker = "extra == 'autogen'", specifier = ">=0.0.15" }, { name = "praisonai-tools", marker = "extra == 'crewai'", specifier = ">=0.0.15" }, - { name = "praisonaiagents", specifier = ">=0.0.83" }, + { name = "praisonaiagents", specifier = ">=0.0.85" }, { name = "pyautogen", marker = "extra == 'autogen'", specifier = ">=0.2.19" }, { name = "pydantic", marker = "extra == 'chat'", specifier = "<=2.10.1" }, { name = "pydantic", marker = "extra == 'code'", specifier = "<=2.10.1" }, @@ -3813,7 +3813,7 @@ wheels = [ [[package]] name = "praisonaiagents" -version = "0.0.83" +version = "0.0.85" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mcp" }, @@ -3821,9 +3821,9 @@ dependencies = [ { name = "pydantic" }, { name = "rich" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ae/b5/f5d93d8d57149d32918d419eb5a36dcdc30ae17dfc4f82c21287a25103a6/praisonaiagents-0.0.83.tar.gz", hash = "sha256:2356aa349562ea69cb8e717726dcda557c808c0ae160aad1f216565978a1bd61", size = 124557 } +sdist = { url = "https://files.pythonhosted.org/packages/58/18/5984f440ec48f2238bdbd166c2347e8ae2a9e4c3b1782be07a3e0ecc626e/praisonaiagents-0.0.85.tar.gz", hash = "sha256:a4f2c0317a25e04a76b8b0a61921fbe79b309b6031ed4a2c02898951ae58c922", size = 125623 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/9b/e766de5c0ef4017189986994373accad3a1ad761980aee0f2e1f0e8a9edb/praisonaiagents-0.0.83-py3-none-any.whl", hash = "sha256:fa3bf621b1c729283215ced83d13f1519ca0e676ed3a1ad7e17e07af2fbf3a72", size = 144238 }, + { url = "https://files.pythonhosted.org/packages/70/13/46b86b7962c5b74360b8d4a1678fd8b3f4b59be1d4e620418d6ad41761a4/praisonaiagents-0.0.85-py3-none-any.whl", hash = "sha256:91ac555747726a83fff565e76a57ffa7dda9813e745958d8e5ea279eb0777b3c", size = 145314 }, ] [[package]]