universal-mcp-agents 0.1.12__py3-none-any.whl → 0.1.14__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.

Potentially problematic release.


This version of universal-mcp-agents might be problematic. Click here for more details.

Files changed (31) hide show
  1. universal_mcp/agents/__init__.py +1 -1
  2. universal_mcp/agents/base.py +2 -0
  3. universal_mcp/agents/bigtool/__init__.py +1 -1
  4. universal_mcp/agents/bigtool/agent.py +2 -2
  5. universal_mcp/agents/bigtool/graph.py +65 -31
  6. universal_mcp/agents/bigtool/prompts.py +2 -2
  7. universal_mcp/agents/bigtool/tools.py +18 -4
  8. universal_mcp/agents/builder/__main__.py +105 -30
  9. universal_mcp/agents/builder/builder.py +149 -160
  10. universal_mcp/agents/builder/helper.py +73 -0
  11. universal_mcp/agents/builder/prompts.py +33 -152
  12. universal_mcp/agents/builder/state.py +1 -1
  13. universal_mcp/agents/cli.py +2 -2
  14. universal_mcp/agents/codeact/agent.py +1 -1
  15. universal_mcp/agents/codeact/sandbox.py +1 -5
  16. universal_mcp/agents/codeact0/agent.py +5 -4
  17. universal_mcp/agents/codeact0/langgraph_agent.py +17 -0
  18. universal_mcp/agents/codeact0/llm_tool.py +1 -1
  19. universal_mcp/agents/codeact0/prompts.py +34 -23
  20. universal_mcp/agents/codeact0/usecases/11-github.yaml +6 -5
  21. universal_mcp/agents/codeact0/utils.py +42 -63
  22. universal_mcp/agents/shared/__main__.py +43 -0
  23. universal_mcp/agents/shared/prompts.py +50 -99
  24. universal_mcp/agents/shared/tool_node.py +149 -203
  25. universal_mcp/agents/utils.py +65 -0
  26. universal_mcp/applications/ui/app.py +2 -2
  27. {universal_mcp_agents-0.1.12.dist-info → universal_mcp_agents-0.1.14.dist-info}/METADATA +1 -1
  28. {universal_mcp_agents-0.1.12.dist-info → universal_mcp_agents-0.1.14.dist-info}/RECORD +29 -28
  29. universal_mcp/agents/codeact0/langgraph_graph.py +0 -17
  30. universal_mcp/agents/codeact0/legacy_codeact.py +0 -104
  31. {universal_mcp_agents-0.1.12.dist-info → universal_mcp_agents-0.1.14.dist-info}/WHEEL +0 -0
@@ -1,260 +1,206 @@
1
1
  import asyncio
2
+ from collections import defaultdict
2
3
  from typing import Annotated, TypedDict
3
4
 
4
5
  from langchain_core.language_models import BaseChatModel
5
- from langchain_core.messages import AIMessage, AnyMessage, HumanMessage
6
+ from langchain_core.messages import AIMessage, AnyMessage
6
7
  from langgraph.graph import END, StateGraph
7
8
  from langgraph.graph.message import add_messages
9
+ from langgraph.types import Command
8
10
  from loguru import logger
9
11
  from pydantic import BaseModel, Field
10
12
  from universal_mcp.tools.registry import ToolRegistry
13
+ from universal_mcp.types import ToolConfig
11
14
 
12
15
  from universal_mcp.agents.shared.prompts import (
13
- APP_SEARCH_QUERY_PROMPT,
14
- REVISE_DECOMPOSITION_PROMPT,
15
- TASK_DECOMPOSITION_PROMPT,
16
- TOOL_SEARCH_QUERY_PROMPT,
16
+ APP_SELECTION_PROMPT,
17
+ TOOL_SEARCH_QUERIES_PROMPT,
17
18
  TOOL_SELECTION_PROMPT,
18
19
  )
19
20
 
20
- MAX_DECOMPOSITION_ATTEMPTS = 2
21
+ MAX_RETRIES = 1
21
22
 
22
- # --- Pydantic Models for Structured LLM Outputs ---
23
23
 
24
+ class SearchQueries(BaseModel):
25
+ queries: list[str] = Field(description="A list of search queries for finding tools.")
24
26
 
25
- class TaskDecomposition(BaseModel):
26
- sub_tasks: list[str] = Field(description="A list of sub-task descriptions.")
27
27
 
28
-
29
- class SearchQuery(BaseModel):
30
- query: str = Field(description="A concise search query.")
28
+ class AppSelection(BaseModel):
29
+ app_ids: list[str] = Field(description="The IDs of the selected applications.")
31
30
 
32
31
 
33
32
  class ToolSelection(BaseModel):
34
33
  tool_ids: list[str] = Field(description="The IDs of the selected tools.")
35
34
 
36
35
 
37
- # --- LangGraph Agent State ---
38
-
39
-
40
- class SubTask(TypedDict, total=False):
41
- """Represents a single step in the execution plan."""
42
-
43
- task: str
44
- status: str # "pending", "success", "failed"
45
- app_id: str
46
- tool_ids: list[str]
47
- reasoning: str
48
-
49
-
50
36
  class AgentState(TypedDict):
51
37
  """The central state of our agent graph."""
52
38
 
53
39
  original_task: str
54
- decomposition_attempts: int
55
- failed_sub_task_info: str # To inform re-decomposition
56
- sub_tasks: list[SubTask]
57
- execution_plan: list[SubTask]
40
+ queries: list[str]
41
+ candidate_tools: list[dict]
42
+ execution_plan: ToolConfig
58
43
  messages: Annotated[list[AnyMessage], add_messages]
59
-
60
-
61
- # --- Graph Builder ---
44
+ retry_count: int
62
45
 
63
46
 
64
47
  def build_tool_node_graph(llm: BaseChatModel, registry: ToolRegistry) -> StateGraph:
65
- """Builds the adaptive LangGraph workflow for tool selection."""
48
+ """Builds a workflow for tool selection with a retry mechanism."""
66
49
 
67
- async def _decompose_task(state: AgentState) -> AgentState:
68
- """Decomposes the main task or revises a failed decomposition."""
69
- attempts = state.get("decomposition_attempts", 0)
50
+ async def _search_for_tools(state: AgentState) -> Command:
51
+ """
52
+ Performs a hierarchical search:
53
+ 1. Generates search queries for the task.
54
+ 2. Searches for candidate *applications*.
55
+ 3. Uses an LLM to select the most relevant applications.
56
+ 4. Searches for tools only within the selected applications.
57
+ If any step fails, it can trigger a retry.
58
+ """
70
59
  task = state["original_task"]
71
- failed_info = state.get("failed_sub_task_info")
72
-
73
- if attempts > 0 and failed_info:
74
- logger.warning(f"Revising decomposition. Attempt {attempts + 1}.")
75
- prompt = REVISE_DECOMPOSITION_PROMPT.format(task=task, failed_sub_task=failed_info)
76
- else:
77
- logger.info("Performing initial task decomposition.")
78
- prompt = TASK_DECOMPOSITION_PROMPT.format(task=task)
79
-
80
- response = await llm.with_structured_output(TaskDecomposition).ainvoke(prompt)
81
- sub_tasks = [{"task": sub_task_str, "status": "pending"} for sub_task_str in response.sub_tasks]
82
-
83
- return {
84
- "sub_tasks": sub_tasks,
85
- "decomposition_attempts": attempts + 1,
86
- "messages": [AIMessage(content=f"New plan created with {len(sub_tasks)} steps.")],
87
- }
88
-
89
- async def _resolve_sub_tasks(state: AgentState) -> AgentState:
90
- """Iterates through sub-tasks, providing full plan context to the app selection prompt."""
91
- sub_tasks = state["sub_tasks"]
92
- original_task = state["original_task"]
93
- current_plan = []
94
-
95
- for i, sub_task in enumerate(sub_tasks):
96
- task_desc = sub_task["task"]
97
- logger.info(f"Resolving sub-task: '{task_desc}'")
98
-
99
- # 1. Build the FULL context string from the entire plan so far
100
- if not current_plan:
101
- plan_context_str = "None. This is the first step."
102
- else:
103
- context_lines = [
104
- f"- The sub-task '{step['task']}' was assigned to app '{step['app_id']}'." for step in current_plan
105
- ]
106
- plan_context_str = "\n".join(context_lines)
107
-
108
- # 2. Generate the App-specific query using the NEW full-context prompt
109
- app_query_prompt = APP_SEARCH_QUERY_PROMPT.format(
110
- original_task=original_task, plan_context=plan_context_str, sub_task=task_desc
60
+ logger.info(f"Starting hierarchical tool search for task: '{task}'")
61
+
62
+ prompt = TOOL_SEARCH_QUERIES_PROMPT.format(task=task)
63
+ response = await llm.with_structured_output(SearchQueries).ainvoke(prompt)
64
+ queries = response.queries
65
+ logger.info(f"Generated search queries: {queries}")
66
+
67
+ if not queries:
68
+ logger.error("LLM failed to generate any search queries.")
69
+ return Command(
70
+ update={"messages": [AIMessage(content="I could not understand the task to search for tools.")]},
71
+ goto="handle_failure",
111
72
  )
112
- app_query_response = await llm.with_structured_output(SearchQuery).ainvoke(app_query_prompt)
113
- app_search_query = app_query_response.query
114
- logger.info(f"Generated context-aware app search query: '{app_search_query}'")
115
-
116
- # 3. Search for candidate apps (the rest of the logic is the same)
117
- candidate_apps = await registry.search_apps(query=app_search_query, limit=5)
118
- if not candidate_apps:
119
- logger.error(f"No apps found for query '{app_search_query}' from sub-task: '{task_desc}'")
120
- return {"failed_sub_task_info": task_desc, "sub_tasks": []}
121
-
122
- # 4. Generate Action-specific query for finding the tool
123
- tool_query_prompt = TOOL_SEARCH_QUERY_PROMPT.format(sub_task=task_desc)
124
- tool_query_response = await llm.with_structured_output(SearchQuery).ainvoke(tool_query_prompt)
125
- tool_search_query = tool_query_response.query
126
- logger.info(f"Generated tool search query: '{tool_search_query}'")
127
-
128
- # 5. Find a suitable tool within the candidate apps
129
- tool_found = False
130
- for app in candidate_apps:
131
- app_id = app["id"]
132
- logger.info(f"Searching for tools in app '{app_id}' with query '{tool_search_query}'...")
133
-
134
- found_tools = await registry.search_tools(query=tool_search_query, app_id=app_id, limit=5)
135
- if not found_tools:
136
- continue
137
-
138
- tool_candidates_str = "\n - ".join([f"{tool['name']}: {tool['description']}" for tool in found_tools])
139
- selection_prompt = TOOL_SELECTION_PROMPT.format(sub_task=task_desc, tool_candidates=tool_candidates_str)
140
- selection_response = await llm.with_structured_output(ToolSelection).ainvoke(selection_prompt)
141
-
142
- if selection_response.tool_ids:
143
- logger.success(f"Found and selected tool(s) {selection_response.tool_ids} in app '{app_id}'.")
144
- sub_task.update(
145
- {
146
- "status": "success",
147
- "app_id": app_id,
148
- "tool_ids": selection_response.tool_ids,
149
- "reasoning": f"Selected tool(s) {selection_response.tool_ids} from app '{app_id}' for sub-task.",
150
- }
151
- )
152
- current_plan.append(sub_task)
153
- tool_found = True
154
- break
155
-
156
- if not tool_found:
157
- logger.error(f"Could not find any suitable tool for sub-task: '{task_desc}'")
158
- return {"failed_sub_task_info": task_desc, "sub_tasks": []}
159
-
160
- return {"execution_plan": current_plan, "sub_tasks": []}
161
-
162
- def _handle_planning_failure(state: AgentState) -> AgentState:
163
- """Handles the case where all decomposition attempts have failed."""
164
- logger.error("Maximum decomposition attempts reached. Planning failed.")
165
- return {
166
- "messages": [
167
- AIMessage(
168
- content="I am unable to create a complete plan for this task with the available tools. Please try rephrasing your request."
169
- )
170
- ]
171
- }
172
73
 
173
- def _consolidate_plan(state: AgentState) -> AgentState:
174
- """
175
- NEW: Merges steps in the execution plan that use the same app_id.
176
- It combines their tool_ids into a single unique list.
177
- """
178
- logger.info("Consolidating final execution plan.")
179
- plan = state["execution_plan"]
180
- merged_apps: dict[str, SubTask] = {}
181
-
182
- for step in plan:
183
- app_id = step["app_id"]
184
- if app_id not in merged_apps:
185
- # Store the first occurrence of this app
186
- merged_apps[app_id] = step.copy()
187
- merged_apps[app_id]["tool_ids"] = set(step["tool_ids"])
188
- else:
189
- # If app already seen, just update its set of tool_ids
190
- merged_apps[app_id]["tool_ids"].update(step["tool_ids"])
74
+ # Always store queries for potential retry
75
+ update_state = {"queries": queries}
191
76
 
192
- # Convert the merged dictionary back to a list of SubTasks
193
- final_plan = []
194
- for app_id, step_data in merged_apps.items():
195
- step_data["tool_ids"] = sorted(list(step_data["tool_ids"]))
196
- final_plan.append(step_data)
77
+ app_search_tasks = [registry.search_apps(query, distance_threshold=0.7) for query in queries]
78
+ app_results = await asyncio.gather(*app_search_tasks)
79
+ unique_apps = {app["id"]: app for app_list in app_results for app in app_list}
197
80
 
198
- return {"execution_plan": final_plan}
81
+ if not unique_apps:
82
+ logger.warning(f"No applications found for queries: {queries}. Triggering retry.")
83
+ return Command(update=update_state, goto="general_search_and_select")
199
84
 
200
- # --- Graph Definition ---
85
+ logger.info(f"Found {len(unique_apps)} candidate applications.")
201
86
 
202
- workflow = StateGraph(AgentState)
87
+ app_candidates_str = "\n - ".join([f"{app['id']}: {app['description']}" for app in unique_apps.values()])
88
+ app_selection_prompt = APP_SELECTION_PROMPT.format(task=task, app_candidates=app_candidates_str)
89
+ app_selection_response = await llm.with_structured_output(AppSelection).ainvoke(app_selection_prompt)
90
+ selected_app_ids = app_selection_response.app_ids
203
91
 
204
- workflow.add_node("decompose_task", _decompose_task)
205
- workflow.add_node("resolve_sub_tasks", _resolve_sub_tasks)
206
- workflow.add_node("consolidate_plan", _consolidate_plan) # NEW NODE
207
- workflow.add_node("handle_planning_failure", _handle_planning_failure)
92
+ if not selected_app_ids:
93
+ logger.warning("LLM did not select any applications from the candidate list. Triggering retry.")
94
+ return Command(update=update_state, goto="general_search_and_select")
208
95
 
209
- workflow.set_entry_point("decompose_task")
96
+ logger.success(f"Selected {len(selected_app_ids)} applications: {selected_app_ids}")
210
97
 
211
- def should_continue(state: AgentState):
212
- if not state.get("sub_tasks"): # Resolution failed or succeeded
213
- if state.get("execution_plan"):
214
- return "consolidate_plan" # MODIFIED: Go to consolidate on success
215
- elif state["decomposition_attempts"] >= MAX_DECOMPOSITION_ATTEMPTS:
216
- return "handle_planning_failure"
217
- else:
218
- return "decompose_task" # Re-try decomposition
219
- else:
220
- return "resolve_sub_tasks"
98
+ tool_search_tasks = [
99
+ registry.search_tools(task, app_id=app_id, distance_threshold=0.8) for app_id in selected_app_ids
100
+ ]
101
+ tool_results = await asyncio.gather(*tool_search_tasks)
102
+ candidate_tools = [tool for tool_list in tool_results for tool in tool_list]
221
103
 
222
- workflow.add_conditional_edges("decompose_task", lambda s: "resolve_sub_tasks")
223
- workflow.add_conditional_edges("resolve_sub_tasks", should_continue)
104
+ if not candidate_tools:
105
+ logger.warning(f"No tools found within the selected applications: {selected_app_ids}. Triggering retry.")
106
+ return Command(update=update_state, goto="general_search_and_select")
224
107
 
225
- workflow.add_edge("consolidate_plan", END) # NEW EDGE
226
- workflow.add_edge("handle_planning_failure", END)
108
+ logger.success(f"Found {len(candidate_tools)} candidate tools from selected apps.")
109
+ update_state["candidate_tools"] = candidate_tools
110
+ return Command(update=update_state, goto="select_tools_for_plan")
227
111
 
228
- return workflow.compile()
112
+ async def _general_search_and_select(state: AgentState) -> Command:
113
+ """
114
+ A retry node that performs a general tool search without app filters.
115
+ """
116
+ task = state["original_task"]
117
+ queries = state["queries"]
118
+ retry_count = state.get("retry_count", 0)
119
+
120
+ if retry_count >= MAX_RETRIES:
121
+ logger.error("Max retries reached. Failing the planning process.")
122
+ return Command(
123
+ update={"messages": [AIMessage(content="I could not find any relevant tools after extensive searching.")]},
124
+ goto="handle_failure",
125
+ )
229
126
 
127
+ logger.info(f"--- RETRY {retry_count + 1}/{MAX_RETRIES} ---")
128
+ logger.info("Performing a general tool search without app filters.")
129
+
130
+ general_search_tasks = [
131
+ registry.search_tools(query, distance_threshold=0.85) for query in queries
132
+ ]
133
+ tool_results = await asyncio.gather(*general_search_tasks)
134
+
135
+ unique_tools = {tool['id']: tool for tool_list in tool_results for tool in tool_list}
136
+ candidate_tools = list(unique_tools.values())
137
+
138
+ if not candidate_tools:
139
+ logger.error("General search (retry) also failed to find any tools.")
140
+ return Command(
141
+ update={
142
+ "messages": [AIMessage(content="I could not find any tools for your request, even with a broader search.")],
143
+ "retry_count": retry_count + 1,
144
+ },
145
+ goto="handle_failure",
146
+ )
230
147
 
231
- async def main():
232
- """Main function to run the agent."""
233
- from universal_mcp.agentr.registry import AgentrRegistry
148
+ logger.success(f"General search found {len(candidate_tools)} candidate tools.")
149
+ return Command(
150
+ update={"candidate_tools": candidate_tools, "retry_count": retry_count + 1},
151
+ goto="select_tools_for_plan",
152
+ )
234
153
 
235
- from universal_mcp.agents.llm import load_chat_model
154
+ async def _select_tools_for_plan(state: AgentState) -> Command:
155
+ """Selects the best tools from the candidates and builds the final execution plan."""
156
+ task = state["original_task"]
157
+ candidate_tools = state["candidate_tools"]
158
+ retry_count = state.get("retry_count", 0)
159
+ logger.info("Starting tool selection from candidate list.")
160
+
161
+ tool_candidates_str = "\n - ".join([f"{tool['id']}: {tool['description']}" for tool in candidate_tools])
162
+ prompt = TOOL_SELECTION_PROMPT.format(task=task, tool_candidates=tool_candidates_str)
163
+ response = await llm.with_structured_output(ToolSelection).ainvoke(prompt)
164
+ selected_tool_ids = response.tool_ids
165
+
166
+ if not selected_tool_ids:
167
+ if retry_count >= MAX_RETRIES:
168
+ logger.error("LLM did not select any tools, even after a retry. Failing.")
169
+ return Command(
170
+ update={"messages": [AIMessage(content="I found potential tools, but could not create a final plan.")]},
171
+ goto="handle_failure",
172
+ )
173
+ else:
174
+ logger.warning("LLM did not select any tools from the current candidate list. Triggering general search.")
175
+ return Command(goto="general_search_and_select")
236
176
 
237
- registry = AgentrRegistry()
238
- llm = load_chat_model("anthropic/claude-4-sonnet-20250514")
239
177
 
240
- graph = build_tool_node_graph(llm, registry)
178
+ logger.success(f"Selected {len(selected_tool_ids)} tools for the final plan: {selected_tool_ids}")
241
179
 
242
- task = "Find my latest order confirmation in Gmail, search for reviews of the main product on perplexity, and then send an email to ankit@agentr.dev telling about the reviews"
180
+ final_plan = defaultdict(list)
181
+ for tool_id in selected_tool_ids:
182
+ if "__" in tool_id:
183
+ app_id, tool_name = tool_id.split("__", 1)
184
+ final_plan[app_id].append(tool_name)
243
185
 
244
- initial_state = {
245
- "original_task": task,
246
- "messages": [HumanMessage(content=task)],
247
- "decomposition_attempts": 0,
248
- }
186
+ sorted_final_plan = {app_id: sorted(tools) for app_id, tools in final_plan.items()}
187
+ return Command(update={"execution_plan": sorted_final_plan}, goto=END)
249
188
 
250
- final_state = await graph.ainvoke(initial_state)
189
+ def _handle_planning_failure(state: AgentState) -> Command:
190
+ """Handles cases where tool search or selection fails by logging the final error message."""
191
+ if messages := state.get("messages"):
192
+ last_message = messages[-1].content
193
+ logger.error(f"Planning failed. Final message: {last_message}")
194
+ else:
195
+ logger.error("Planning failed with no specific message.")
196
+ return Command(goto=END)
251
197
 
252
- if final_state.get("execution_plan"):
253
- for step in final_state["execution_plan"]:
254
- pass
255
- else:
256
- pass
198
+ workflow = StateGraph(AgentState)
199
+ workflow.add_node("search_for_tools", _search_for_tools)
200
+ workflow.add_node("general_search_and_select", _general_search_and_select)
201
+ workflow.add_node("select_tools_for_plan", _select_tools_for_plan)
202
+ workflow.add_node("handle_failure", _handle_planning_failure)
257
203
 
204
+ workflow.set_entry_point("search_for_tools")
258
205
 
259
- if __name__ == "__main__":
260
- asyncio.run(main())
206
+ return workflow.compile()
@@ -9,6 +9,8 @@ from rich.markdown import Markdown
9
9
  from rich.panel import Panel
10
10
  from rich.prompt import Prompt
11
11
  from rich.table import Table
12
+ from pydantic import ValidationError
13
+ from requests import JSONDecodeError
12
14
 
13
15
 
14
16
  class RichCLI:
@@ -143,3 +145,66 @@ def get_message_text(message: BaseMessage):
143
145
  logger.error(f"Error getting message text: {e}")
144
146
  logger.error(f"Message: {message}")
145
147
  raise e
148
+
149
+
150
+ def filter_retry_on(exc: Exception) -> bool:
151
+ import httpx
152
+ import requests
153
+
154
+ # Transient local/network issues and parsing hiccups
155
+ if isinstance(
156
+ exc,
157
+ (
158
+ TimeoutError,
159
+ ConnectionError,
160
+ JSONDecodeError,
161
+ ValidationError,
162
+ ),
163
+ ):
164
+ return True
165
+
166
+ # httpx transient request-layer errors
167
+ if isinstance(
168
+ exc,
169
+ (
170
+ httpx.TimeoutException,
171
+ httpx.ConnectError,
172
+ httpx.ReadError,
173
+ ),
174
+ ):
175
+ return True
176
+
177
+ if isinstance(exc, (requests.Timeout, requests.ConnectionError)):
178
+ return True
179
+
180
+ # HTTP status based retries: 408 (timeout), 429 (rate limit), and 5xx
181
+ if isinstance(exc, httpx.HTTPStatusError):
182
+ status = exc.response.status_code
183
+ return status == 408 or status == 429 or 500 <= status < 600
184
+ if isinstance(exc, requests.HTTPError):
185
+ if exc.response is None:
186
+ return True
187
+ status = exc.response.status_code
188
+ return status == 408 or status == 429 or 500 <= status < 600
189
+
190
+ if isinstance(
191
+ exc,
192
+ (
193
+ ValueError,
194
+ TypeError,
195
+ ArithmeticError,
196
+ ImportError,
197
+ LookupError,
198
+ NameError,
199
+ SyntaxError,
200
+ RuntimeError,
201
+ ReferenceError,
202
+ StopIteration,
203
+ StopAsyncIteration,
204
+ OSError,
205
+ ),
206
+ ):
207
+ return False
208
+
209
+ # Default: do not retry unknown exceptions
210
+ return False
@@ -1,10 +1,10 @@
1
1
  import os
2
2
  from typing import Any, Literal, TypedDict
3
3
 
4
- from dotenv import load_dotenv
5
4
  import httpx
6
- from universal_mcp.applications.application import BaseApplication
5
+ from dotenv import load_dotenv
7
6
  from markitdown import MarkItDown
7
+ from universal_mcp.applications.application import BaseApplication
8
8
 
9
9
  load_dotenv()
10
10
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: universal-mcp-agents
3
- Version: 0.1.12
3
+ Version: 0.1.14
4
4
  Summary: Add your description here
5
5
  Project-URL: Homepage, https://github.com/universal-mcp/applications
6
6
  Project-URL: Repository, https://github.com/universal-mcp/applications
@@ -1,45 +1,45 @@
1
- universal_mcp/agents/__init__.py,sha256=xQ0Yoln3f0MQrqTQhAZ0im7Tp1DawEJ04YPp20Nw1DQ,1244
2
- universal_mcp/agents/base.py,sha256=le5vy02eXN15u8ntHWCu6Y-LgOmE_DA8tWmPOmLohAk,6908
3
- universal_mcp/agents/cli.py,sha256=Yv9g8VHOyK__V7me4UcWsWIXiviPz7F1vqMYH1jkCms,1016
1
+ universal_mcp/agents/__init__.py,sha256=kM4mC6Pf6lmaaZF1volo7VtKgA8FDyzb1sNenpB7Ulk,1244
2
+ universal_mcp/agents/base.py,sha256=xQ_zMHTvULaiE4LiE7IfhrLmlBtvJ5zVE9Rq2nJ4Hm4,6976
3
+ universal_mcp/agents/cli.py,sha256=AG9e4iSX3GazT537573YrYT1wSaZYOr42rrYQ7xP3YA,1016
4
4
  universal_mcp/agents/hil.py,sha256=_5PCK6q0goGm8qylJq44aSp2MadP-yCPvhOJYKqWLMo,3808
5
5
  universal_mcp/agents/llm.py,sha256=hVRwjZs3MHl5_3BWedmurs2Jt1oZDfFX0Zj9F8KH7fk,1787
6
6
  universal_mcp/agents/react.py,sha256=8XQvJ0HLVgc-K0qn9Ml48WGcgUGuIKtL67HatlT6Da0,3334
7
7
  universal_mcp/agents/simple.py,sha256=NSATg5TWzsRNS7V3LFiDG28WSOCIwCdcC1g7NRwg2nM,2095
8
- universal_mcp/agents/utils.py,sha256=QeysgwRCHvoe7LpIQkD05y9FGG7us4kWA8ApNj2ACr8,5274
9
- universal_mcp/agents/bigtool/__init__.py,sha256=uTA6KzZlRhL2reAUazwYmwCHFt9q4hERo27e13ifBX4,2250
8
+ universal_mcp/agents/utils.py,sha256=pZFAqH__csH-gRLlTOnuU8kNix3_t5eC3yIk926FWpQ,6898
9
+ universal_mcp/agents/bigtool/__init__.py,sha256=mZG8dsaCVyKlm82otxtiTA225GIFLUCUUYPEIPF24uw,2299
10
10
  universal_mcp/agents/bigtool/__main__.py,sha256=a15OUoqPR938x7eseWtxu0aLX7lRS3nu8k5Ks3giUY4,472
11
- universal_mcp/agents/bigtool/agent.py,sha256=anXjMgFWS95RYrnQsZJJxYq8HoCB6z9Poi-Uv5fhPis,266
11
+ universal_mcp/agents/bigtool/agent.py,sha256=FsWa7S00RHmzrLd2ms_aR4wJ09h_KFJ8DDzFnADKJOQ,251
12
12
  universal_mcp/agents/bigtool/context.py,sha256=ny7gd-vvVpUOYAeQbAEUT0A6Vm6Nn2qGywxTzPBzYFg,929
13
- universal_mcp/agents/bigtool/graph.py,sha256=DEsuSm9OYWBTeGEmvPk_nv_yb7EvCflHe4pbja5-jC0,4337
14
- universal_mcp/agents/bigtool/prompts.py,sha256=Rz30qNGdscDG65vMj9d0Vfe7X1pQjBDQBBNc3BuyC94,1886
13
+ universal_mcp/agents/bigtool/graph.py,sha256=SE1IavwrSciIWsb_miekEh3H46UJWpeIOkcp7CsRG_w,5764
14
+ universal_mcp/agents/bigtool/prompts.py,sha256=Joi5mCzZX63aM_6eBrMOKuNRHjTkceVIibSsGBGqhYE,2041
15
15
  universal_mcp/agents/bigtool/state.py,sha256=TQeGZD99okclkoCh5oz-VYIlEsC9yLQyDpnBnm7QCN8,759
16
- universal_mcp/agents/bigtool/tools.py,sha256=ynyEj9mVwKKDhxm76sjspyH51SFi63g2Vydi39pY0qY,5562
17
- universal_mcp/agents/builder/__main__.py,sha256=XaXpJNwkj5Os1Vn1er8wokPKd4O4WW_L2XkGkvqEhao,4912
18
- universal_mcp/agents/builder/builder.py,sha256=1p32txpFlG1l6XP1N5UOFAhNnQS02nmvA_uMDO5i-m4,9015
19
- universal_mcp/agents/builder/prompts.py,sha256=RFzDBdGxF5BsAQL09BVas9RjAwt_Q2ZACghG5pOxqas,8623
20
- universal_mcp/agents/builder/state.py,sha256=7DeWllxfN-yD6cd9wJ3KIgjO8TctkJvVjAbZT8W_zqk,922
16
+ universal_mcp/agents/bigtool/tools.py,sha256=vlydQQnITS7OPaSzyILf3czrgO3_fEB-i7zItKcEWjU,6377
17
+ universal_mcp/agents/builder/__main__.py,sha256=mGw5xHK53qNGgs6q7s2PPPPWozWPDKXD2AZGQTqCDQc,10750
18
+ universal_mcp/agents/builder/builder.py,sha256=uhUOH6S7F2iWDhpNOpfzVUT1VB0MQnmcEkLPYJs65gY,8151
19
+ universal_mcp/agents/builder/helper.py,sha256=G6IoXB433zAwfOGhDXOIGsf_EC9bbOSGN8WPWGSzmrk,2700
20
+ universal_mcp/agents/builder/prompts.py,sha256=k0IfhWZ10zou3I2e3kczxf2zpY2AsPshjeY_h5oQ1KA,2673
21
+ universal_mcp/agents/builder/state.py,sha256=nJrH-ChSpqv-fsXhvP4UkouVdQw0ji376uFM0aJ91D0,921
21
22
  universal_mcp/agents/codeact/__init__.py,sha256=rLE8gvOo5H4YSr71DRq76b3RV3uuotxuAy_VnBVaVwk,60
22
23
  universal_mcp/agents/codeact/__main__.py,sha256=W2cHXRwH1dZG3ETIkMwUqA_d62K3IctHP-FDZWDjxdw,1067
23
- universal_mcp/agents/codeact/agent.py,sha256=RRMeXVgn3Ow2gxhDKszx9hSUYGDTk6yqqDVyNIOu5kI,9778
24
+ universal_mcp/agents/codeact/agent.py,sha256=sKZWokTHcuL68Y6SNyaaHe6_XkWxaIq36TrNmPJfQto,9762
24
25
  universal_mcp/agents/codeact/models.py,sha256=2fdAcF5bxWDpljjEwDEdPBflTMShSPwwncHrphRjsYg,222
25
26
  universal_mcp/agents/codeact/prompts.py,sha256=EMI-imnd0Ps0Bd2FOvSqgiicvvtFFu0MF9s93PiC_3k,4493
26
- universal_mcp/agents/codeact/sandbox.py,sha256=gEAmZ08PovnFmCKP7uIQaKXHFLOyrnuSmoh7E_SHhjQ,2307
27
+ universal_mcp/agents/codeact/sandbox.py,sha256=NjN6ISj8psFtHf8V0w24ChJdUMUWkq7OrlbHdzm4wBc,2299
27
28
  universal_mcp/agents/codeact/state.py,sha256=WTPfpxDlGRnlr5tZuXMg_KU7GS7TZbnrIKslOvZLbQI,565
28
29
  universal_mcp/agents/codeact/utils.py,sha256=JUbT_HYGS_D1BzmzoVpORIe7SGur1KgJguTZ_1tZ4JY,1918
29
30
  universal_mcp/agents/codeact0/__init__.py,sha256=rLE8gvOo5H4YSr71DRq76b3RV3uuotxuAy_VnBVaVwk,60
30
31
  universal_mcp/agents/codeact0/__main__.py,sha256=V2wLWW9ym3rtiSvPEs-N0Mki7G5dYHzV5dAsAoF-ygQ,1148
31
- universal_mcp/agents/codeact0/agent.py,sha256=e1v_XVRqblKrAgrkyiPz7bs4atgDRTVHPnZQUjnT_4o,6495
32
+ universal_mcp/agents/codeact0/agent.py,sha256=WmCHhhGN1q2Q1s14FN2kaNBEIVlYRoMpWJOqQEYjaBo,6538
32
33
  universal_mcp/agents/codeact0/config.py,sha256=H-1woj_nhSDwf15F63WYn723y4qlRefXzGxuH81uYF0,2215
33
- universal_mcp/agents/codeact0/langgraph_graph.py,sha256=mP3JrZ1I-Cqhk6E2DMRHUdLFevpyyad-Y3qhERn45JA,550
34
- universal_mcp/agents/codeact0/legacy_codeact.py,sha256=Lj4oH-AaP1zg6ifBkUxzWJcwMs9X5SepGzzZ6S5QMSg,4096
35
- universal_mcp/agents/codeact0/llm_tool.py,sha256=GEG8L2crRPyO5la_wlHohuqI9m6xH9KXgQxcP5fCFuU,13814
36
- universal_mcp/agents/codeact0/prompts.py,sha256=GTUwnxyyUVdeAoAwo4ODGOlEtZStMkoP_lJEFRbDglY,7324
34
+ universal_mcp/agents/codeact0/langgraph_agent.py,sha256=8-Y3-OOEpY_XLcnjvFX-KyAQA5SzBjya3YBrrV9Qh_8,652
35
+ universal_mcp/agents/codeact0/llm_tool.py,sha256=9xgRylNZo3lya33L3iqS7yipJYaHCeUEEBCfjUp71vc,13821
36
+ universal_mcp/agents/codeact0/prompts.py,sha256=VT3v61JkAvZwjQoxwKR3QsYdkbyd_1E8bIm3oABNfMg,7512
37
37
  universal_mcp/agents/codeact0/sandbox.py,sha256=tkrhQoV7sAIT5rtd5kpNYEgDz4y82WSHKpMGE6bqthE,3108
38
38
  universal_mcp/agents/codeact0/state.py,sha256=kcoCoz-kd0Ukw1YNGDHNggixCK34KzMl2t6GztakSo4,412
39
- universal_mcp/agents/codeact0/utils.py,sha256=QIT4XIUln9o3H7MOmMen7i-dhDgvM8q0p--oy9Kbkss,15345
39
+ universal_mcp/agents/codeact0/utils.py,sha256=6yeUVsB2CkcrutHjfpMI3KsMJkVpFj3Piag6A2IG0Jc,14733
40
40
  universal_mcp/agents/codeact0/usecases/1-unsubscribe.yaml,sha256=DiChHW-mNOcaaiec7f_04_A0Xyf9a2ihzXiPA9-Fw1I,239
41
41
  universal_mcp/agents/codeact0/usecases/10-reddit2.yaml,sha256=R3vrZZNv_E-m_SuSJ5tSv11HqMomm8Gtxp_LDhkrnAw,618
42
- universal_mcp/agents/codeact0/usecases/11-github.yaml,sha256=IRom0gDPcj0w0qa2LSARQbvrwJhLGQRaHI2U2rglcG0,650
42
+ universal_mcp/agents/codeact0/usecases/11-github.yaml,sha256=iu4-vlvopPct9vfAseElLXPUAWN5sMVri4oMbDYlA4s,672
43
43
  universal_mcp/agents/codeact0/usecases/2-reddit.yaml,sha256=-dstvFMjsuP9UQM3B_G1HBn7ImNIMxSCNbITpfwgwAY,2525
44
44
  universal_mcp/agents/codeact0/usecases/2.1-instructions.md,sha256=0gQBY_A3jT_lgKNiu6GdyEYupbX0Xz2unlCoTQwv-Es,5098
45
45
  universal_mcp/agents/codeact0/usecases/2.2-instructions.md,sha256=Cx-VkcC55MrgFxlMBMBCD83jEge_yZgBWKwtuK1OPFc,4458
@@ -55,11 +55,12 @@ universal_mcp/agents/planner/__main__.py,sha256=OfhTfYDZK_ZUfc8sX-Sa6TWk-dNqD2rl
55
55
  universal_mcp/agents/planner/graph.py,sha256=70hhIoEZOcYojpiyVSCedgYpnmxVP7aqdn8s6VBu-D4,3228
56
56
  universal_mcp/agents/planner/prompts.py,sha256=_JoHqiAvswtqCDu90AGUHmfsu8eWE1-_yI4LLn3pqMU,657
57
57
  universal_mcp/agents/planner/state.py,sha256=qqyp-jSGsCxe1US-PRLT4-y1sITAcVE6nCMlQLnvop0,278
58
- universal_mcp/agents/shared/prompts.py,sha256=VOsXSUEwBXPaAuxJTUF6bgDGr41u6uctUNQSMRt_OJc,6414
59
- universal_mcp/agents/shared/tool_node.py,sha256=Ua_wzMt4YgIx4zLp3_ZCow-28qORwrZ2FvKqLPt3RlI,10415
58
+ universal_mcp/agents/shared/__main__.py,sha256=u6ezelmT7poaMRr5AfKp3uXGOV7zEwj017j_iAeUcZs,1450
59
+ universal_mcp/agents/shared/prompts.py,sha256=-gNyfhrJFtPEG4YeoJRYKmkmRHsI8a5f5ssxk_AWrOI,3760
60
+ universal_mcp/agents/shared/tool_node.py,sha256=syydbbKFMpu9Gg45yGP-kpN5KvD2oSRXWtqo1YpD6gY,9038
60
61
  universal_mcp/applications/llm/__init__.py,sha256=xnpxq4Wl_pevvwtSUtEwcty8_d61ywO1V2YnEXyCREY,46
61
62
  universal_mcp/applications/llm/app.py,sha256=iNLU6z2LRZc01GfSKvV0vNzT1LhKAjq_UrSJEmjthjw,6032
62
- universal_mcp/applications/ui/app.py,sha256=56h9GvkHiELyAVOZvi0YjiowSymlqkJ5GW4O7LmGIPs,9459
63
- universal_mcp_agents-0.1.12.dist-info/METADATA,sha256=hqXAJNr5hrlsdZHsQwHed6ELV0b0h4q-l8Ar1IpsoEI,878
64
- universal_mcp_agents-0.1.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
65
- universal_mcp_agents-0.1.12.dist-info/RECORD,,
63
+ universal_mcp/applications/ui/app.py,sha256=c7OkZsO2fRtndgAzAQbKu-1xXRuRp9Kjgml57YD2NR4,9459
64
+ universal_mcp_agents-0.1.14.dist-info/METADATA,sha256=6a7VjzkIfQdp6b4UfQVAMKFzg2qE8wszgkocVRgqNok,878
65
+ universal_mcp_agents-0.1.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
66
+ universal_mcp_agents-0.1.14.dist-info/RECORD,,
@@ -1,17 +0,0 @@
1
- from langgraph.checkpoint.memory import MemorySaver
2
- from universal_mcp.agentr.registry import AgentrRegistry
3
-
4
- from universal_mcp.agents.codeact0.agent import CodeActAgent
5
-
6
-
7
- async def agent():
8
- memory = MemorySaver()
9
- agent_object = await CodeActAgent(
10
- name="CodeAct Agent",
11
- instructions="Be very concise in your answers.",
12
- model="anthropic:claude-4-sonnet-20250514",
13
- tools={"google_mail": ["list_messages"]},
14
- registry=AgentrRegistry(),
15
- memory=memory,
16
- )._build_graph()
17
- return agent_object