Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] master from Upsonic:master #25

Merged
merged 3 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gpt_computer_assistant/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from .tooler import Tool
except:
pass
__version__ = '0.24.17' # fmt: skip
__version__ = '0.24.18' # fmt: skip


import os
Expand Down
4 changes: 3 additions & 1 deletion gpt_computer_assistant/agent/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from ..cu.computer import *
from ..teams import *
from .agent_tools import get_tools
from ..mcp.tool import mcp_tools

except ImportError:
from llm import get_model
Expand All @@ -17,6 +18,7 @@
from cu.computer import *
from teams import *
from agent.agent_tools import get_tools
from mcp.tool import mcp_tools


from langgraph.prebuilt import chat_agent_executor
Expand Down Expand Up @@ -62,7 +64,7 @@ def get_agent_executor():
pass


tools += [computer_tool]
tools += [computer_tool] + mcp_tools()


if (
Expand Down
245 changes: 245 additions & 0 deletions gpt_computer_assistant/mcp/tool.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
import asyncio
import pathlib
import time
from typing import List, Any, Dict

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from langchain_mcp import MCPToolkit
from langchain_core.tools import BaseTool




from typing import Any, Dict, List
from langchain_core.tools import BaseTool
from pydantic import Field, PrivateAttr





class MCPToolWrapper(BaseTool):
"""A wrapper for an individual tool managed by the SyncInvocationManager."""
_manager: Any = PrivateAttr()
_tool: Any = PrivateAttr()

def __init__(self, tool: BaseTool, manager: "SyncInvocationManager"):
super().__init__(name=tool.name, description=tool.description)
self.name = tool.name
self.description = tool.description
self._manager = manager
self._tool = tool

def _run(self, **kwargs: Any) -> Any:
"""Run the tool synchronously using the SyncInvocationManager."""



try:
from ..gpt_computer_assistant import the_main_window
except ImportError:
from gpt_computer_assistant import the_main_window





function_name = "Tool: " + self.name
the_main_window.active_border_animation(function_name)
try:
result = self._manager.invoke_tool_sync(self._tool, kwargs)
except Exception as e:
time.sleep(1)
the_main_window.deactive_border_animation(function_name)
return e
time.sleep(1)
the_main_window.deactive_border_animation(function_name)

return result

async def _arun(self, **kwargs: Any) -> Any:
"""Asynchronous run (if needed), wraps the synchronous call."""
return self._run(**kwargs)


class MCPToolManager:
"""Manages tools provided by the SyncInvocationManager and converts them into LangChain tools."""

def __init__(self, manager: "SyncInvocationManager"):
self.manager = manager
self.tools: List[BaseTool] = []

def load_tools(self) -> List[BaseTool]:
"""Load tools from SyncInvocationManager and wrap them in LangChain-compatible structure."""
raw_tools = self.manager.get_tools_sync()

self.tools = [MCPToolWrapper(tool, self.manager) for tool in raw_tools]
return self.tools


class SyncInvocationManager:
def __init__(self, command: str, args: list[str], env: dict[str, str] | None = None):
self.loop = asyncio.new_event_loop()
self.server_params = StdioServerParameters(
command=command,
args=args,
env=env,

)
self.client_ctx = None
self.client = None
self.session_ctx = None
self.session = None
self.toolkit = None
self._task = None # Add this line


async def _start_async(self):
# Manually enter the stdio_client context
self.client_ctx = stdio_client(self.server_params)
self.client = await self.client_ctx.__aenter__()
read, write = self.client

# Manually enter the ClientSession context
self.session_ctx = ClientSession(read, write)
self.session = await self.session_ctx.__aenter__()

self.toolkit = MCPToolkit(session=self.session)
await self.toolkit.initialize()

def get_tools_sync(self) -> List[BaseTool]:
# Now that session is open, just return tools directly
return self.toolkit.get_tools()

def invoke_tool_sync(self, tool: BaseTool, input_data: Dict[str, Any]) -> Any:
return self.loop.run_until_complete(tool.ainvoke(input_data))

def start(self):
asyncio.set_event_loop(self.loop)
self._task = self.loop.create_task(self._start_async())
self.loop.run_until_complete(self._task)

def stop(self):
if self._task and not self._task.done():
cleanup_task = self.loop.create_task(self._stop_async())
self.loop.run_until_complete(cleanup_task)
self.loop.close()

async def _stop_async(self):
# Exit contexts in the same task and loop they were entered
if self.session_ctx:
await self.session_ctx.__aexit__(None, None, None)
if self.client_ctx:
await self.client_ctx.__aexit__(None, None, None)




def file_system_tool():
print("""

This is file_system_tool

""")


manager = SyncInvocationManager(command="npx", args=["-y", "@modelcontextprotocol/server-filesystem", str(pathlib.Path(__file__).parent.parent)])
manager.start()
tool_manager = MCPToolManager(manager)
tools = tool_manager.load_tools()
print(tools)
return tools


def memory_tool():

print("""

This is memory_tool

""")


manager = SyncInvocationManager(command="npx", args=["-y", "@modelcontextprotocol/server-memory"])
manager.start()
tool_manager = MCPToolManager(manager)
tools = tool_manager.load_tools()
print(tools)
return tools


def playwright():

print("""

This is playwright

""")

manager = SyncInvocationManager(command="npx", args=["-y", "@executeautomation/playwright-mcp-server"])
manager.start()
tool_manager = MCPToolManager(manager)
tools = tool_manager.load_tools()
print(tools)
return tools


def youtube_transcript():

print("""

This is youtube_transcript

""")

manager = SyncInvocationManager(command="npx", args=["-y", "@kimtaeyoon83/mcp-server-youtube-transcript"])
manager.start()
tool_manager = MCPToolManager(manager)
tools = tool_manager.load_tools()
print(tools)
return tools

def fetch():

print("""

This is fetch

""")

manager = SyncInvocationManager(command="uvx", args=["mcp-server-fetch"])
manager.start()
tool_manager = MCPToolManager(manager)
tools = tool_manager.load_tools()
print(tools)
return tools




def websearch():

print("""

This is websearch

""")


manager = SyncInvocationManager(command="npx", args=["-y", "@executeautomation/playwright-mcp-server"])
manager.start()
tool_manager = MCPToolManager(manager)
tools = tool_manager.load_tools()
print(tools)
return tools




the_tools_ = None
def mcp_tools():
global the_tools_
if the_tools_ is None:
the_tools_ = file_system_tool() + memory_tool() + playwright() + youtube_transcript() + fetch() + websearch()
return the_tools_
5 changes: 4 additions & 1 deletion requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,7 @@ langchain-anthropic==0.3.0



StrEnum==0.4.15
StrEnum==0.4.15


langchain-mcp==0.1.0a1
4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,6 @@ screeninfo==0.8.1
anthropic==0.40.0
langchain-anthropic==0.3.0

StrEnum==0.4.15
StrEnum==0.4.15

langchain-mcp==0.1.0a1
7 changes: 4 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,19 @@

setup(
name="gpt_computer_assistant",
version="0.24.17",
version="0.24.18",
description="""GPT""",
long_description="".join(open("README.md", encoding="utf-8").readlines()),
long_description_content_type="text/markdown",
url="https://github.com/onuratakan/gpt-computer-assistant",
author="Onur Atakan ULUSOY",
author_email="[email protected]",
author="Upsonic",
author_email="[email protected]",
license="MIT",
packages=[
"gpt_computer_assistant",
"gpt_computer_assistant.agent",
"gpt_computer_assistant.cu",
"gpt_computer_assistant.mcp",
"gpt_computer_assistant.gui",
"gpt_computer_assistant.screen",
"gpt_computer_assistant.utils",
Expand Down
Loading