11from mcpx_pydantic_ai import Agent , pydantic_ai
22
33
4- from typing import TypedDict
5-
6- from . import builtin_tools
4+ import asyncio
75
86
97SYSTEM_PROMPT = """
@@ -32,7 +30,6 @@ class Chat:
3230 def __init__ (
3331 self ,
3432 * args ,
35- ignore_builtin_tools : bool = False ,
3633 ** kw ,
3734 ):
3835 if "system_prompt" not in kw :
@@ -42,14 +39,8 @@ def __init__(
4239 * args ,
4340 ** kw ,
4441 )
45- if not ignore_builtin_tools :
46- self ._register_builtins ()
4742 self .history = []
4843
49- def _register_builtins (self ):
50- for tool in builtin_tools .TOOLS :
51- self .agent .register_tool (tool , getattr (self , "_tool_" + tool .name ))
52-
5344 @property
5445 def client (self ):
5546 """
@@ -63,121 +54,126 @@ def clear_history(self):
6354 """
6455 self .history = []
6556
66- async def send_message (self , msg : str , * args , ** kw ):
57+ async def send_message (self , msg : str , run_mcp_servers : bool = True , * args , ** kw ):
6758 """
6859 Send a chat message to the LLM
6960 """
70- with pydantic_ai .capture_run_messages () as messages :
71- res = await self .agent .run (
72- msg ,
73- message_history = self .history ,
74- * args ,
75- ** kw ,
76- )
61+
62+ async def inner ():
63+ with pydantic_ai .capture_run_messages () as messages :
64+ return (
65+ await self .agent .run (
66+ msg ,
67+ message_history = self .history ,
68+ * args ,
69+ ** kw ,
70+ ),
71+ messages ,
72+ )
73+
74+ if run_mcp_servers :
75+ async with self .agent .run_mcp_servers ():
76+ res , messages = await inner ()
77+ else :
78+ res , messages = await inner ()
7779 self .history .extend (messages )
7880 return res
7981
80- def send_message_sync (self , msg , * args , ** kw ):
81- """
82- Send a chat message to the LLM
82+ def send_message_sync (self , * args , ** kw ):
8383 """
84- with pydantic_ai .capture_run_messages () as messages :
85- res = self .agent .run_sync (
86- msg ,
87- message_history = self .history ,
88- * args ,
89- ** kw ,
90- )
91- self .history .extend (messages )
92- return res
84+ Send a chat message to the LLM synchronously
9385
94- async def iter (self , msg , * args , ** kw ):
86+ This creates a new event loop to run the async send_message method.
87+ """
88+ # Create a new event loop to avoid warnings about coroutines not being awaited
89+ loop = asyncio .new_event_loop ()
90+ try :
91+ return loop .run_until_complete (self .send_message (* args , ** kw ))
92+ finally :
93+ loop .close ()
94+
95+ async def iter (self , msg : str , run_mcp_servers : bool = True , * args , ** kw ):
9596 """
9697 Send a chat message to the LLM
9798 """
98- with pydantic_ai .capture_run_messages () as messages :
99- async with self .agent .iter (
100- msg , message_history = self .history , * args , ** kw
101- ) as run :
102- async for node in run :
103- yield node
104- self .history .extend (messages )
10599
106- async def iter_content (self , msg , * args , ** kw ):
100+ async def inner ():
101+ with pydantic_ai .capture_run_messages () as messages :
102+ async with self .agent .iter (
103+ msg , message_history = self .history , * args , ** kw
104+ ) as run :
105+ async for node in run :
106+ yield node
107+ self .history .extend (messages )
108+
109+ if run_mcp_servers :
110+ async with self .agent .run_mcp_servers ():
111+ async for msg in inner ():
112+ yield msg
113+ else :
114+ async for msg in inner ():
115+ yield msg
116+
117+ async def iter_content (self , msg : str , run_mcp_servers : bool = True , * args , ** kw ):
107118 """
108119 Send a chat message to the LLM
109120 """
110- with pydantic_ai .capture_run_messages () as messages :
111- async with self .agent .iter (
112- msg , message_history = self .history , * args , ** kw
113- ) as run :
114- async for node in run :
115- if hasattr (node , "response" ):
116- content = node .response
117- elif hasattr (node , "model_response" ):
118- content = node .model_response
119- elif hasattr (node , "request" ):
120- content = node .request
121- elif hasattr (node , "model_request" ):
122- content = node .model_request
123- elif hasattr (node , "data" ):
124- content = node .data
125- else :
126- continue
127- yield content
128- self .history .extend (messages )
129121
130- async def inspect (self , msg , * args , ** kw ):
122+ async def inner ():
123+ with pydantic_ai .capture_run_messages () as messages :
124+ async with self .agent .iter (
125+ msg , message_history = self .history , * args , ** kw
126+ ) as run :
127+ async for node in run :
128+ if hasattr (node , "response" ):
129+ content = node .response
130+ elif hasattr (node , "model_response" ):
131+ content = node .model_response
132+ elif hasattr (node , "request" ):
133+ content = node .request
134+ elif hasattr (node , "model_request" ):
135+ content = node .model_request
136+ elif hasattr (node , "data" ):
137+ content = node .data
138+ elif hasattr (node , "output" ):
139+ content = node
140+ else :
141+ continue
142+ yield content
143+ self .history .extend (messages )
144+
145+ f = inner ()
146+ if run_mcp_servers :
147+ async with self .agent .run_mcp_servers ():
148+ async for msg in f :
149+ yield msg
150+ else :
151+ async for msg in f :
152+ yield msg
153+
154+ async def inspect (self , msg : str , run_mcp_servers : bool = True , * args , ** kw ):
131155 """
132156 Send a chat message to the LLM
133157 """
134- with pydantic_ai .capture_run_messages () as messages :
135- res = await self .send_message (msg , * args , ** kw )
136- return res , messages
137158
138- def _tool_mcp_run_search_servlets (
139- self , input : TypedDict ("SearchServlets" , {"q" : str })
140- ):
141- q = input .get ("q" , "" )
142- if q == "" :
143- return "ERROR: provide a query when searching"
144- x = []
145- for r in self .agent .client .search (input ["q" ]):
146- x .append (
147- {
148- "slug" : r .slug ,
149- "schema" : {
150- "name" : r .meta .get ("name" ),
151- "description" : r .meta .get ("description" ),
152- },
153- "installation_count" : r .installation_count ,
154- }
155- )
156- return x
157-
158- def _tool_mcp_run_get_profiles (self , input : TypedDict ("GetProfile" , {})):
159- p = []
160- for user , u in self .agent .client .profiles .items ():
161- if user == "~" :
162- continue
163- for profile in u .values ():
164- p .append (
165- {
166- "name" : f"{ user } /{ profile .slug } " , # Assume slug is string
167- "description" : profile .description ,
168- }
159+ async def inner ():
160+ with pydantic_ai .capture_run_messages () as messages :
161+ res = await self .agent .run (
162+ msg ,
163+ message_history = self .history ,
164+ * args ,
165+ ** kw ,
169166 )
170- return p
171-
172- def _tool_mcp_run_set_profile (
173- self , input : TypedDict ("SetProfile" , {"profile" : str })
174- ):
175- profile = input ["profile" ]
176- if "/" not in profile :
177- profile = "~/" + profile
178- self .agent .set_profile (profile )
179- return f"Active profile set to { profile } "
180-
181- def _tool_mcp_run_current_profile (self , input : TypedDict ("CurrentProfile" , {})):
182- """Get current profile name"""
183- return self .agent .client .config .profile
167+ return res , messages
168+
169+ if run_mcp_servers :
170+ async with self .agent .run_mcp_servers ():
171+ return await inner ()
172+ else :
173+ return await inner ()
174+
175+ async def list_tools (self ):
176+ async with self .client .mcp_sse (self .agent .client .profile ).connect () as session :
177+ tools = await session .list_tools ()
178+ for tool in tools .tools :
179+ yield tool
0 commit comments