fyodorov-llm-agents 0.4.61__py3-none-any.whl → 0.4.65__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,10 @@ from datetime import datetime
2
2
  import os
3
3
  from supabase import Client
4
4
  import litellm
5
+ import requests
6
+
5
7
  from fyodorov_utils.config.supabase import get_supabase
8
+ from fyodorov_utils.service_discovery import get_service_url
6
9
  from fyodorov_llm_agents.agents.agent_model import Agent as AgentModel
7
10
  from fyodorov_llm_agents.tools.mcp_tool_model import MCPTool as ToolModel
8
11
  from fyodorov_llm_agents.tools.mcp_tool_service import MCPTool as ToolService
@@ -230,7 +233,10 @@ class Agent(AgentModel):
230
233
  if not mcp_tool:
231
234
  raise ValueError(f"Tool '{fn_name}' not found in loaded MCP tools")
232
235
 
233
- tool_output = mcp_tool.call(args)
236
+ # Forward tool call to Tsiolkovsky instead of calling locally
237
+ tool_output = await self._forward_tool_call_to_tsiolkovsky(
238
+ mcp_tool.id, args, user_session
239
+ )
234
240
 
235
241
  messages.append({
236
242
  "role": "assistant",
@@ -255,5 +261,26 @@ class Agent(AgentModel):
255
261
  print(f"Answer: {answer}")
256
262
  return {
257
263
  "answer": answer,
258
-
259
- }
264
+ }
265
+
266
+ async def _forward_tool_call_to_tsiolkovsky(self, tool_id: str, args: str, user_session: str) -> str:
267
+ """Forward function call to Tsiolkovsky for execution"""
268
+ try:
269
+ tsiolkovsky_url = get_service_url('Tsiolkovsky')
270
+
271
+ response = await asyncio.to_thread(
272
+ requests.post,
273
+ f"{tsiolkovsky_url}/tools/{tool_id}/call",
274
+ json={"args": args},
275
+ headers={"Authorization": f"Bearer {user_session}"},
276
+ timeout=30
277
+ )
278
+
279
+ if response.status_code == 200:
280
+ result = response.json()
281
+ return result.get("result", "")
282
+ else:
283
+ return f"Error calling tool: {response.status_code} - {response.text}"
284
+
285
+ except Exception as e:
286
+ return f"Error forwarding tool call: {str(e)}"
@@ -18,7 +18,7 @@ JWT = "eyJhbGciOiJIUzI1NiIsImtpZCI6Im14MmVrTllBY3ZYN292LzMiLCJ0eXAiOiJKV1QifQ.ey
18
18
  class Instance(InstanceModel):
19
19
 
20
20
  async def chat_w_fn_calls(self, input: str = "", access_token: str = JWT, user_id: str = "") -> str:
21
- agent: AgentModel = await Agent.get_in_db(access_token=access_token, id = self.agent_id)
21
+ agent: AgentModel = await Agent.get_in_db(id = self.agent_id)
22
22
  print(f"Model fetched via LLM.get_model in chat_w_fn_calls: {agent.model}")
23
23
  agent.provider = await Provider.get_provider_by_id(id = agent.model.provider)
24
24
  agent.prompt = f"{agent.prompt}\n\n{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
@@ -37,6 +37,11 @@ class MCPTool(BaseModel):
37
37
  health_status: Optional[str] = None
38
38
  usage_notes: Optional[str] = None
39
39
 
40
+ # Fields for launching local tools
41
+ launch_command: Optional[str] = None # The command to execute (e.g., "npx", "python")
42
+ launch_args: Optional[list[str]] = None # Arguments for the command (e.g., ["-y", "mcp-remote@latest"])
43
+ launch_working_directory: Optional[str] = None # Working directory for the command
44
+
40
45
  # Example validations below. Adjust/extend to fit your needs.
41
46
 
42
47
  def validate(self) -> bool:
@@ -1,7 +1,12 @@
1
1
  from datetime import datetime
2
+ import json
3
+ from typing import Any, Optional
4
+
5
+ import requests
2
6
  from fyodorov_utils.config.supabase import get_supabase
3
7
  from .mcp_tool_model import MCPTool as ToolModel
4
8
 
9
+
5
10
  class MCPTool():
6
11
 
7
12
  @staticmethod
@@ -125,7 +130,7 @@ class MCPTool():
125
130
  tool["user_id"] = str(tool["user_id"])
126
131
  tool["created_at"] = str(tool["created_at"])
127
132
  tool["updated_at"] = str(tool["updated_at"])
128
- if tool and (tool['public'] == True or (user_id and 'user_id' in tool and tool['user_id'] == user_id)):
133
+ if tool and (tool['public'] or (user_id and 'user_id' in tool and tool['user_id'] == user_id)):
129
134
  print('tool is public or belongs to user', tool)
130
135
  tool_model = ToolModel(**tool)
131
136
  if tool_model.validate():
@@ -169,4 +174,36 @@ class MCPTool():
169
174
  return agent_ids
170
175
  except Exception as e:
171
176
  print('Error setting tool agents', str(e))
172
- raise
177
+ raise e
178
+
179
+ @staticmethod
180
+ async def call_mcp_server(id: str, access_token: Optional[str] = None, args: Optional[dict[str, Any]] = None) -> str:
181
+ """Invoke an MCP tool via the tool's configured MCP server."""
182
+ if not id:
183
+ raise ValueError('Tool ID is required')
184
+ tool = await MCPTool.get_in_db(access_token, id)
185
+ if not tool:
186
+ raise ValueError('Tool not found')
187
+ if not tool.handle:
188
+ raise ValueError('Tool handle is required')
189
+ if not tool.api_url:
190
+ raise ValueError('Tool api_url is required')
191
+
192
+ url = f"{tool.api_url}:call"
193
+ headers = {'Content-Type': 'application/json'}
194
+ if access_token:
195
+ headers['Authorization'] = f'Bearer {access_token}'
196
+ if args is None:
197
+ args = {}
198
+
199
+ try:
200
+ print(f"Calling MCP server at {url} with args {args}")
201
+ response = requests.post(url, headers=headers, json=args, timeout=30)
202
+ response.raise_for_status()
203
+ content_type = response.headers.get('Content-Type', '')
204
+ if 'application/json' in content_type:
205
+ return json.dumps(response.json())
206
+ return response.text
207
+ except requests.RequestException as e:
208
+ print('Error calling MCP server', str(e))
209
+ raise e
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fyodorov_llm_agents
3
- Version: 0.4.61
3
+ Version: 0.4.65
4
4
  Summary: LLM agents for the Fyodorov AI suite
5
5
  Author-email: Daniel Ransom <02masseur.alibis@icloud.com>
6
6
  Project-URL: Homepage, https://github.com/FyodorovAI/fyodorov-llm-agents
@@ -1,17 +1,17 @@
1
1
  fyodorov_llm_agents/base_model.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  fyodorov_llm_agents/agents/agent_model.py,sha256=JNbRBWtErHnFqlP_ONd0B8Vf3o_AyigHKchsd3COZrk,3899
3
- fyodorov_llm_agents/agents/agent_service.py,sha256=Exu_-pA4tkC67jv63G27dvAY_oQyih12xKS7TpFrjb4,10302
3
+ fyodorov_llm_agents/agents/agent_service.py,sha256=ufNfYYLtPoI9ZQR0AZb7fGYP3T0U7fFxQq6EDRcUpZk,11447
4
4
  fyodorov_llm_agents/agents/openai.py,sha256=FA5RS7yn3JwvFA8PXju60XSYC_2oUZFNgBUzeIYtGv0,1154
5
5
  fyodorov_llm_agents/instances/instance_model.py,sha256=swRzCXeUk2FFKzGMEjeToklBJRK7GdAJl1ZIoQALuxs,1368
6
- fyodorov_llm_agents/instances/instance_service.py,sha256=k5uiPB5rFyHlhDdNN8jICCIASErr5zgxnDlwXE1TLmI,8799
6
+ fyodorov_llm_agents/instances/instance_service.py,sha256=3e9qfBGfd2RydSu8skQhA_PaRiiqWjOt0jyjUTek6a0,8772
7
7
  fyodorov_llm_agents/models/llm_model.py,sha256=9sAM2QbVp62yFxhETii1x4VhZCn3HNwut4wqA9RUABM,1918
8
8
  fyodorov_llm_agents/models/llm_service.py,sha256=t7p8pRExJr-B8MD7KleKNe8YlHZ1geDuqYzbTFo_0MM,4837
9
9
  fyodorov_llm_agents/providers/provider_model.py,sha256=7G0WSPJYGcLIFgyQF0Y-Rv4f37-TMGg7fyeZxrC3fNE,1100
10
10
  fyodorov_llm_agents/providers/provider_service.py,sha256=dbLyi4_sOfciksBgbyf_iViMud93Kzpn23D7-aYIBj8,6761
11
- fyodorov_llm_agents/tools/mcp_tool_model.py,sha256=aCJGW1WZoeTX5UVD8K-ljUTf0dxPLpPZphIKZTIuipM,5278
12
- fyodorov_llm_agents/tools/mcp_tool_service.py,sha256=ijgR74pLcH9Bk-b-yAo9I8ZcXHJcrZOrgoWYGljxGhA,7697
11
+ fyodorov_llm_agents/tools/mcp_tool_model.py,sha256=pMQ8VMYMUn8l80UVj4WefdzlGZxSrTrZOP-R2cPAGUs,5629
12
+ fyodorov_llm_agents/tools/mcp_tool_service.py,sha256=dl6svc6ncqpAAQRTP8PM_xGH8EVnoENbvjzi7froT2Y,9089
13
13
  fyodorov_llm_agents/tools/tool.py,sha256=HyOk0X_3XE23sa8J-8UZx657tJ0sxwZWMbA4OPxXU6E,7940
14
- fyodorov_llm_agents-0.4.61.dist-info/METADATA,sha256=4u-ZOLhE7aqZ9FEUbGwNhgFdzpIJujc91qwOULs_Cj8,551
15
- fyodorov_llm_agents-0.4.61.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
16
- fyodorov_llm_agents-0.4.61.dist-info/top_level.txt,sha256=4QOslsBp8Gh7ng25DceA7fHp4KguTIdAxwURz97gH-g,20
17
- fyodorov_llm_agents-0.4.61.dist-info/RECORD,,
14
+ fyodorov_llm_agents-0.4.65.dist-info/METADATA,sha256=7vw4WbLBBPNFM5SDMMw890iZhlLQ918eFoe9ztEhvxI,551
15
+ fyodorov_llm_agents-0.4.65.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
+ fyodorov_llm_agents-0.4.65.dist-info/top_level.txt,sha256=4QOslsBp8Gh7ng25DceA7fHp4KguTIdAxwURz97gH-g,20
17
+ fyodorov_llm_agents-0.4.65.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.3.1)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5