universal-mcp-agents 0.1.9__py3-none-any.whl → 0.1.11__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 (49) hide show
  1. universal_mcp/agents/__init__.py +9 -9
  2. universal_mcp/agents/base.py +13 -18
  3. universal_mcp/agents/bigtool2/__init__.py +6 -7
  4. universal_mcp/agents/bigtool2/__main__.py +2 -4
  5. universal_mcp/agents/bigtool2/agent.py +1 -0
  6. universal_mcp/agents/bigtool2/graph.py +48 -184
  7. universal_mcp/agents/bigtool2/meta_tools.py +120 -0
  8. universal_mcp/agents/bigtoolcache/__init__.py +31 -22
  9. universal_mcp/agents/bigtoolcache/__main__.py +1 -4
  10. universal_mcp/agents/bigtoolcache/agent.py +1 -3
  11. universal_mcp/agents/bigtoolcache/graph.py +101 -191
  12. universal_mcp/agents/bigtoolcache/prompts.py +7 -31
  13. universal_mcp/agents/bigtoolcache/tools.py +141 -0
  14. universal_mcp/agents/builder.py +10 -20
  15. universal_mcp/agents/cli.py +1 -2
  16. universal_mcp/agents/codeact/__init__.py +1 -1
  17. universal_mcp/agents/codeact/__main__.py +15 -5
  18. universal_mcp/agents/codeact/agent.py +67 -100
  19. universal_mcp/agents/codeact/prompts.py +32 -42
  20. universal_mcp/agents/codeact/sandbox.py +30 -39
  21. universal_mcp/agents/codeact/state.py +3 -6
  22. universal_mcp/agents/codeact/utils.py +12 -5
  23. universal_mcp/agents/hil.py +1 -6
  24. universal_mcp/agents/planner/__init__.py +1 -3
  25. universal_mcp/agents/planner/graph.py +1 -3
  26. universal_mcp/agents/react.py +14 -6
  27. universal_mcp/agents/shared/prompts.py +3 -3
  28. universal_mcp/agents/shared/tool_node.py +47 -47
  29. universal_mcp/agents/simple.py +2 -1
  30. universal_mcp/agents/utils.py +4 -15
  31. universal_mcp/applications/ui/app.py +5 -15
  32. {universal_mcp_agents-0.1.9.dist-info → universal_mcp_agents-0.1.11.dist-info}/METADATA +2 -1
  33. universal_mcp_agents-0.1.11.dist-info/RECORD +42 -0
  34. universal_mcp/agents/autoagent/__init__.py +0 -30
  35. universal_mcp/agents/autoagent/__main__.py +0 -25
  36. universal_mcp/agents/autoagent/context.py +0 -26
  37. universal_mcp/agents/autoagent/graph.py +0 -170
  38. universal_mcp/agents/autoagent/prompts.py +0 -9
  39. universal_mcp/agents/autoagent/state.py +0 -27
  40. universal_mcp/agents/autoagent/utils.py +0 -13
  41. universal_mcp/agents/bigtool/__init__.py +0 -58
  42. universal_mcp/agents/bigtool/__main__.py +0 -23
  43. universal_mcp/agents/bigtool/graph.py +0 -210
  44. universal_mcp/agents/bigtool/prompts.py +0 -31
  45. universal_mcp/agents/bigtool/state.py +0 -27
  46. universal_mcp/agents/bigtoolcache/tools_all.txt +0 -956
  47. universal_mcp/agents/bigtoolcache/tools_important.txt +0 -474
  48. universal_mcp_agents-0.1.9.dist-info/RECORD +0 -54
  49. {universal_mcp_agents-0.1.9.dist-info → universal_mcp_agents-0.1.11.dist-info}/WHEEL +0 -0
@@ -26,9 +26,7 @@ class PlannerAgent(BaseAgent):
26
26
  self.executor_agent_cls = executor_agent_cls
27
27
 
28
28
  def _build_system_message(self):
29
- return DEVELOPER_PROMPT.format(
30
- name=self.name, instructions=self.instructions
31
- )
29
+ return DEVELOPER_PROMPT.format(name=self.name, instructions=self.instructions)
32
30
 
33
31
  async def _build_graph(self):
34
32
  return build_graph(
@@ -18,9 +18,7 @@ def build_graph(llm, registry, instructions, model, executor_agent_cls):
18
18
  task = state["messages"][-1].content
19
19
  logger.info(f"Running tool finder for task: {task}")
20
20
  tool_finder_graph = build_tool_node_graph(llm, registry)
21
- tool_finder_state = await tool_finder_graph.ainvoke(
22
- {"original_task": task, "messages": state["messages"]}
23
- )
21
+ tool_finder_state = await tool_finder_graph.ainvoke({"original_task": task, "messages": state["messages"]})
24
22
 
25
23
  if not tool_finder_state.get("apps_required"):
26
24
  logger.info("Tool finder determined no apps are required.")
@@ -4,6 +4,7 @@ from loguru import logger
4
4
  from universal_mcp.agentr.registry import AgentrRegistry
5
5
  from universal_mcp.tools.registry import ToolRegistry
6
6
  from universal_mcp.types import ToolConfig, ToolFormat
7
+ from rich import print
7
8
 
8
9
  from universal_mcp.agents.base import BaseAgent
9
10
  from universal_mcp.agents.llm import load_chat_model
@@ -40,7 +41,18 @@ class ReactAgent(BaseAgent):
40
41
  self.llm = load_chat_model(model)
41
42
  self.tools = tools or {}
42
43
  if "ui" not in self.tools:
43
- self.tools["ui"] = ["create_bar_chart", "create_line_chart", "create_pie_chart", "create_table", "http_get", "http_post", "http_put", "http_delete", "http_patch", "read_file"]
44
+ self.tools["ui"] = [
45
+ "create_bar_chart",
46
+ "create_line_chart",
47
+ "create_pie_chart",
48
+ "create_table",
49
+ "http_get",
50
+ "http_post",
51
+ "http_put",
52
+ "http_delete",
53
+ "http_patch",
54
+ "read_file",
55
+ ]
44
56
  self.max_iterations = max_iterations
45
57
  self.registry = registry
46
58
 
@@ -54,7 +66,6 @@ class ReactAgent(BaseAgent):
54
66
  else:
55
67
  tools = []
56
68
 
57
-
58
69
  logger.debug(f"Initialized ReactAgent: name={self.name}, model={self.model}")
59
70
  return create_react_agent(
60
71
  self.llm,
@@ -75,10 +86,7 @@ async def main():
75
86
  tools={"google-mail": ["send_email"]},
76
87
  registry=AgentrRegistry(),
77
88
  )
78
- result = await agent.invoke(
79
- "Send an email with the subject 'testing react agent' to manoj@agentr.dev"
80
- )
81
- from rich import print
89
+ result = await agent.invoke("Send an email with the subject 'testing react agent' to manoj@agentr.dev")
82
90
 
83
91
  print(messages_to_list(result["messages"]))
84
92
 
@@ -6,7 +6,7 @@ You are an expert planner. Your goal is to consolidate a complex user request in
6
6
  2. **Focus on Data Handoffs:** A good decomposition often involves one sub-task to *retrieve* information and a subsequent sub-task to *use* that information.
7
7
  3. **Assume Internal Capabilities:** Do NOT create sub-tasks for abstract cognitive work like 'summarize' or 'analyze'.
8
8
  4. **Simplify Single Actions:** If the user's task is already a single, simple action, the output should be a single sub-task that concisely describes that action. Do not make it identical to the user's input.
9
- 5. **General purpose sub tasks:** You also need to realise that these subtasks are going to be used to search for tools and apps. And the names and description of these tools and apps are going to be general in nature so the sub tasks should not be too specific. The task which you will get may be specific in nature but the sub taks must be general.
9
+ 5. **General purpose sub tasks:** You also need to realise that these subtasks are going to be used to search for tools and apps. And the names and description of these tools and apps are going to be general in nature so the sub tasks should not be too specific. The task which you will get may be specific in nature but the sub taks must be general.
10
10
  **--- EXAMPLES ---**
11
11
 
12
12
  **EXAMPLE 1:**
@@ -116,7 +116,7 @@ You are an AI assistant that selects the most appropriate tool(s) from a list to
116
116
  **INSTRUCTIONS:**
117
117
  1. Carefully review the sub-task to understand the required action.
118
118
  2. Examine the list of available tools and their descriptions.
119
- 3. Select the best tool ID that matches the sub-task. You are encouraged to select multiple tools if there are multiple tools with similar capabilties
119
+ 3. Select the best tool ID that matches the sub-task. You are encouraged to select multiple tools if there are multiple tools with similar capabilties
120
120
  or names. It is always good to have more tools than having insufficent tools.
121
121
  4. If no tool is a good fit, return an empty list.
122
122
  5. Only return the tool IDs.
@@ -129,4 +129,4 @@ or names. It is always good to have more tools than having insufficent tools.
129
129
  {tool_candidates}
130
130
 
131
131
  **YOUR SELECTED TOOL ID(s):**
132
- """
132
+ """
@@ -1,5 +1,5 @@
1
1
  import asyncio
2
- from typing import Annotated, TypedDict, List, Dict
2
+ from typing import Annotated, TypedDict
3
3
 
4
4
  from langchain_core.language_models import BaseChatModel
5
5
  from langchain_core.messages import AIMessage, AnyMessage, HumanMessage
@@ -17,43 +17,50 @@ from universal_mcp.agents.shared.prompts import (
17
17
  TOOL_SELECTION_PROMPT,
18
18
  )
19
19
 
20
-
21
20
  MAX_DECOMPOSITION_ATTEMPTS = 2
22
21
 
23
22
  # --- Pydantic Models for Structured LLM Outputs ---
24
23
 
24
+
25
25
  class TaskDecomposition(BaseModel):
26
- sub_tasks: List[str] = Field(description="A list of sub-task descriptions.")
26
+ sub_tasks: list[str] = Field(description="A list of sub-task descriptions.")
27
+
27
28
 
28
29
  class SearchQuery(BaseModel):
29
30
  query: str = Field(description="A concise search query.")
30
31
 
32
+
31
33
  class ToolSelection(BaseModel):
32
- tool_ids: List[str] = Field(description="The IDs of the selected tools.")
34
+ tool_ids: list[str] = Field(description="The IDs of the selected tools.")
33
35
 
34
36
 
35
37
  # --- LangGraph Agent State ---
36
38
 
39
+
37
40
  class SubTask(TypedDict, total=False):
38
41
  """Represents a single step in the execution plan."""
42
+
39
43
  task: str
40
44
  status: str # "pending", "success", "failed"
41
45
  app_id: str
42
- tool_ids: List[str]
46
+ tool_ids: list[str]
43
47
  reasoning: str
44
48
 
49
+
45
50
  class AgentState(TypedDict):
46
51
  """The central state of our agent graph."""
52
+
47
53
  original_task: str
48
54
  decomposition_attempts: int
49
55
  failed_sub_task_info: str # To inform re-decomposition
50
- sub_tasks: List[SubTask]
51
- execution_plan: List[SubTask]
56
+ sub_tasks: list[SubTask]
57
+ execution_plan: list[SubTask]
52
58
  messages: Annotated[list[AnyMessage], add_messages]
53
59
 
54
60
 
55
61
  # --- Graph Builder ---
56
62
 
63
+
57
64
  def build_tool_node_graph(llm: BaseChatModel, registry: ToolRegistry) -> StateGraph:
58
65
  """Builds the adaptive LangGraph workflow for tool selection."""
59
66
 
@@ -65,19 +72,14 @@ def build_tool_node_graph(llm: BaseChatModel, registry: ToolRegistry) -> StateGr
65
72
 
66
73
  if attempts > 0 and failed_info:
67
74
  logger.warning(f"Revising decomposition. Attempt {attempts + 1}.")
68
- prompt = REVISE_DECOMPOSITION_PROMPT.format(
69
- task=task, failed_sub_task=failed_info
70
- )
75
+ prompt = REVISE_DECOMPOSITION_PROMPT.format(task=task, failed_sub_task=failed_info)
71
76
  else:
72
77
  logger.info("Performing initial task decomposition.")
73
78
  prompt = TASK_DECOMPOSITION_PROMPT.format(task=task)
74
79
 
75
80
  response = await llm.with_structured_output(TaskDecomposition).ainvoke(prompt)
76
- sub_tasks = [
77
- {"task": sub_task_str, "status": "pending"}
78
- for sub_task_str in response.sub_tasks
79
- ]
80
-
81
+ sub_tasks = [{"task": sub_task_str, "status": "pending"} for sub_task_str in response.sub_tasks]
82
+
81
83
  return {
82
84
  "sub_tasks": sub_tasks,
83
85
  "decomposition_attempts": attempts + 1,
@@ -99,16 +101,13 @@ def build_tool_node_graph(llm: BaseChatModel, registry: ToolRegistry) -> StateGr
99
101
  plan_context_str = "None. This is the first step."
100
102
  else:
101
103
  context_lines = [
102
- f"- The sub-task '{step['task']}' was assigned to app '{step['app_id']}'."
103
- for step in current_plan
104
+ f"- The sub-task '{step['task']}' was assigned to app '{step['app_id']}'." for step in current_plan
104
105
  ]
105
106
  plan_context_str = "\n".join(context_lines)
106
107
 
107
108
  # 2. Generate the App-specific query using the NEW full-context prompt
108
109
  app_query_prompt = APP_SEARCH_QUERY_PROMPT.format(
109
- original_task=original_task,
110
- plan_context=plan_context_str,
111
- sub_task=task_desc
110
+ original_task=original_task, plan_context=plan_context_str, sub_task=task_desc
112
111
  )
113
112
  app_query_response = await llm.with_structured_output(SearchQuery).ainvoke(app_query_prompt)
114
113
  app_search_query = app_query_response.query
@@ -142,12 +141,14 @@ def build_tool_node_graph(llm: BaseChatModel, registry: ToolRegistry) -> StateGr
142
141
 
143
142
  if selection_response.tool_ids:
144
143
  logger.success(f"Found and selected tool(s) {selection_response.tool_ids} in app '{app_id}'.")
145
- sub_task.update({
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
- })
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
+ )
151
152
  current_plan.append(sub_task)
152
153
  tool_found = True
153
154
  break
@@ -157,12 +158,16 @@ def build_tool_node_graph(llm: BaseChatModel, registry: ToolRegistry) -> StateGr
157
158
  return {"failed_sub_task_info": task_desc, "sub_tasks": []}
158
159
 
159
160
  return {"execution_plan": current_plan, "sub_tasks": []}
160
-
161
+
161
162
  def _handle_planning_failure(state: AgentState) -> AgentState:
162
163
  """Handles the case where all decomposition attempts have failed."""
163
164
  logger.error("Maximum decomposition attempts reached. Planning failed.")
164
165
  return {
165
- "messages": [AIMessage(content="I am unable to create a complete plan for this task with the available tools. Please try rephrasing your request.")]
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
+ ]
166
171
  }
167
172
 
168
173
  def _consolidate_plan(state: AgentState) -> AgentState:
@@ -172,7 +177,7 @@ def build_tool_node_graph(llm: BaseChatModel, registry: ToolRegistry) -> StateGr
172
177
  """
173
178
  logger.info("Consolidating final execution plan.")
174
179
  plan = state["execution_plan"]
175
- merged_apps: Dict[str, SubTask] = {}
180
+ merged_apps: dict[str, SubTask] = {}
176
181
 
177
182
  for step in plan:
178
183
  app_id = step["app_id"]
@@ -189,9 +194,8 @@ def build_tool_node_graph(llm: BaseChatModel, registry: ToolRegistry) -> StateGr
189
194
  for app_id, step_data in merged_apps.items():
190
195
  step_data["tool_ids"] = sorted(list(step_data["tool_ids"]))
191
196
  final_plan.append(step_data)
192
-
193
- return {"execution_plan": final_plan}
194
197
 
198
+ return {"execution_plan": final_plan}
195
199
 
196
200
  # --- Graph Definition ---
197
201
 
@@ -199,26 +203,26 @@ def build_tool_node_graph(llm: BaseChatModel, registry: ToolRegistry) -> StateGr
199
203
 
200
204
  workflow.add_node("decompose_task", _decompose_task)
201
205
  workflow.add_node("resolve_sub_tasks", _resolve_sub_tasks)
202
- workflow.add_node("consolidate_plan", _consolidate_plan) # NEW NODE
206
+ workflow.add_node("consolidate_plan", _consolidate_plan) # NEW NODE
203
207
  workflow.add_node("handle_planning_failure", _handle_planning_failure)
204
208
 
205
209
  workflow.set_entry_point("decompose_task")
206
210
 
207
211
  def should_continue(state: AgentState):
208
- if not state.get("sub_tasks"): # Resolution failed or succeeded
212
+ if not state.get("sub_tasks"): # Resolution failed or succeeded
209
213
  if state.get("execution_plan"):
210
- return "consolidate_plan" # MODIFIED: Go to consolidate on success
214
+ return "consolidate_plan" # MODIFIED: Go to consolidate on success
211
215
  elif state["decomposition_attempts"] >= MAX_DECOMPOSITION_ATTEMPTS:
212
216
  return "handle_planning_failure"
213
217
  else:
214
- return "decompose_task" # Re-try decomposition
218
+ return "decompose_task" # Re-try decomposition
215
219
  else:
216
220
  return "resolve_sub_tasks"
217
221
 
218
222
  workflow.add_conditional_edges("decompose_task", lambda s: "resolve_sub_tasks")
219
223
  workflow.add_conditional_edges("resolve_sub_tasks", should_continue)
220
-
221
- workflow.add_edge("consolidate_plan", END) # NEW EDGE
224
+
225
+ workflow.add_edge("consolidate_plan", END) # NEW EDGE
222
226
  workflow.add_edge("handle_planning_failure", END)
223
227
 
224
228
  return workflow.compile()
@@ -227,15 +231,16 @@ def build_tool_node_graph(llm: BaseChatModel, registry: ToolRegistry) -> StateGr
227
231
  async def main():
228
232
  """Main function to run the agent."""
229
233
  from universal_mcp.agentr.registry import AgentrRegistry
234
+
230
235
  from universal_mcp.agents.llm import load_chat_model
231
236
 
232
237
  registry = AgentrRegistry()
233
238
  llm = load_chat_model("anthropic/claude-4-sonnet-20250514")
234
-
239
+
235
240
  graph = build_tool_node_graph(llm, registry)
236
241
 
237
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"
238
-
243
+
239
244
  initial_state = {
240
245
  "original_task": task,
241
246
  "messages": [HumanMessage(content=task)],
@@ -244,17 +249,12 @@ async def main():
244
249
 
245
250
  final_state = await graph.ainvoke(initial_state)
246
251
 
247
- print("\n--- Final Agent State ---")
248
252
  if final_state.get("execution_plan"):
249
- print("Successfully created a consolidated execution plan:")
250
253
  for step in final_state["execution_plan"]:
251
- print(f"- Sub-task: {step['task']}")
252
- print(f" - App: {step['app_id']}")
253
- print(f" - Tool(s): {', '.join(step['tool_ids'])}")
254
+ pass
254
255
  else:
255
- print("Failed to create an execution plan.")
256
- print(f"Final message: {final_state['messages'][-1].content}")
256
+ pass
257
257
 
258
258
 
259
259
  if __name__ == "__main__":
260
- asyncio.run(main())
260
+ asyncio.run(main())
@@ -4,6 +4,7 @@ from typing import Annotated
4
4
  from langgraph.checkpoint.base import BaseCheckpointSaver
5
5
  from langgraph.graph import END, START, StateGraph
6
6
  from langgraph.graph.message import add_messages
7
+ from rich import print
7
8
  from typing_extensions import TypedDict
8
9
 
9
10
  from universal_mcp.agents.base import BaseAgent
@@ -52,10 +53,10 @@ class SimpleAgent(BaseAgent):
52
53
  graph_builder.add_edge("chatbot", END)
53
54
  return graph_builder.compile(checkpointer=self.memory)
54
55
 
56
+
55
57
  async def main():
56
58
  agent = SimpleAgent("Simple Agent", "Act as a 14 year old kid, reply in Gen-Z lingo", "azure/gpt-5-mini")
57
59
  output = await agent.invoke("What is the capital of France?")
58
- from rich import print
59
60
  print(messages_to_list(output["messages"]))
60
61
 
61
62
 
@@ -8,9 +8,6 @@ from rich.markdown import Markdown
8
8
  from rich.panel import Panel
9
9
  from rich.prompt import Prompt
10
10
  from rich.table import Table
11
- from universal_mcp.tools.manager import ToolManager
12
- from universal_mcp.types import ToolFormat
13
-
14
11
 
15
12
 
16
13
  class RichCLI:
@@ -28,9 +25,7 @@ Available commands:
28
25
  - `/tools` - List available tools
29
26
  - `/exit` - Exit the application
30
27
  """
31
- self.console.print(
32
- Panel(Markdown(welcome_text), title="🤖 AI Agent CLI", border_style="blue")
33
- )
28
+ self.console.print(Panel(Markdown(welcome_text), title="🤖 AI Agent CLI", border_style="blue"))
34
29
 
35
30
  def display_agent_response(self, response: str, agent_name: str):
36
31
  """Display agent response with formatting"""
@@ -54,13 +49,9 @@ Available commands:
54
49
  # Check if type has changed and reset content if so
55
50
  if self.type_ != type_:
56
51
  if type_ == "thinking":
57
- self.content += (
58
- "\n[bold yellow]💭 Thinking:[/bold yellow] :"
59
- )
52
+ self.content += "\n[bold yellow]💭 Thinking:[/bold yellow] :"
60
53
  elif type_ == "text":
61
- self.content += (
62
- f"\n[bold green]🤖 {agent_name}[/bold green] :"
63
- )
54
+ self.content += f"\n[bold green]🤖 {agent_name}[/bold green] :"
64
55
  self.type_ = type_
65
56
  self.content += chunk
66
57
  content_text = "".join(self.content)
@@ -120,9 +111,7 @@ Available commands:
120
111
  value = Prompt.ask(interrupt.value["question"])
121
112
  return value
122
113
  elif interrupt_type == "bool":
123
- value = Prompt.ask(
124
- interrupt.value["question"], choices=["y", "n"], default="y"
125
- )
114
+ value = Prompt.ask(interrupt.value["question"], choices=["y", "n"], default="y")
126
115
  return value
127
116
  elif interrupt_type == "choice":
128
117
  value = Prompt.ask(
@@ -134,9 +134,7 @@ class UiApp(BaseApplication):
134
134
  "headers": dict(response.headers),
135
135
  }
136
136
 
137
- def http_get(
138
- self, url: str, headers: dict | None = None, query_params: dict | None = None
139
- ):
137
+ def http_get(self, url: str, headers: dict | None = None, query_params: dict | None = None):
140
138
  """
141
139
  Perform a GET request to the specified URL with optional parameters.
142
140
 
@@ -150,16 +148,12 @@ class UiApp(BaseApplication):
150
148
  Tags:
151
149
  get, important
152
150
  """
153
- logger.debug(
154
- f"GET request to {url} with headers {headers} and query params {query_params}"
155
- )
151
+ logger.debug(f"GET request to {url} with headers {headers} and query params {query_params}")
156
152
  response = httpx.get(url, params=query_params, headers=headers)
157
153
  response.raise_for_status()
158
154
  return self._handle_response(response)
159
155
 
160
- def http_post(
161
- self, url: str, headers: dict | None = None, body: dict | None = None
162
- ):
156
+ def http_post(self, url: str, headers: dict | None = None, body: dict | None = None):
163
157
  """
164
158
  Perform a POST request to the specified URL with optional parameters.
165
159
 
@@ -197,9 +191,7 @@ class UiApp(BaseApplication):
197
191
  response.raise_for_status()
198
192
  return self._handle_response(response)
199
193
 
200
- def http_delete(
201
- self, url: str, headers: dict | None = None, body: dict | None = None
202
- ):
194
+ def http_delete(self, url: str, headers: dict | None = None, body: dict | None = None):
203
195
  """
204
196
  Perform a DELETE request to the specified URL with optional parameters.
205
197
 
@@ -218,9 +210,7 @@ class UiApp(BaseApplication):
218
210
  response.raise_for_status()
219
211
  return self._handle_response(response)
220
212
 
221
- def http_patch(
222
- self, url: str, headers: dict | None = None, body: dict | None = None
223
- ):
213
+ def http_patch(self, url: str, headers: dict | None = None, body: dict | None = None):
224
214
  """
225
215
  Perform a PATCH request to the specified URL with optional parameters.
226
216
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: universal-mcp-agents
3
- Version: 0.1.9
3
+ Version: 0.1.11
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
@@ -11,6 +11,7 @@ Requires-Dist: langchain-anthropic>=0.3.19
11
11
  Requires-Dist: langchain-google-genai>=2.1.10
12
12
  Requires-Dist: langchain-openai>=0.3.32
13
13
  Requires-Dist: langgraph>=0.6.6
14
+ Requires-Dist: typer>=0.17.4
14
15
  Requires-Dist: universal-mcp-applications>=0.1.14
15
16
  Requires-Dist: universal-mcp>=0.1.24rc21
16
17
  Provides-Extra: dev
@@ -0,0 +1,42 @@
1
+ universal_mcp/agents/__init__.py,sha256=oPoHMITGbHN4Ey68ZrVbmy7sNzVYhoXQgVII9fZwqL8,1245
2
+ universal_mcp/agents/base.py,sha256=KXBxf3TXrVHi-wBVD-cs6PSKfMtUnm73l-hC83FjOog,6753
3
+ universal_mcp/agents/builder.py,sha256=Xl_dGmzbtop3lICH2njnN6yxFF0SnEGY8u1tOIJy2Pk,8677
4
+ universal_mcp/agents/cli.py,sha256=-luC55FHCTwnpcRgqnV95yQa-mGlLYDlseUjLqFrAfs,1014
5
+ universal_mcp/agents/hil.py,sha256=_xLlBte4v5ex-RxXy5H3LqwFhtd3KE1QUHX1QDGIl2w,3760
6
+ universal_mcp/agents/llm.py,sha256=hVRwjZs3MHl5_3BWedmurs2Jt1oZDfFX0Zj9F8KH7fk,1787
7
+ universal_mcp/agents/react.py,sha256=0OZvdBTnQdFF3Wliv2l4wiF2BMd0VG1cVflOaWDC8r0,3166
8
+ universal_mcp/agents/simple.py,sha256=W5_zb2DAGtAx_p5weSQGIC3gheZwxhmwZBuKKBTjd04,1938
9
+ universal_mcp/agents/utils.py,sha256=lnRmP6HBIme4W-iKy1BOb9gTyb9-ooJxXwCyWAQFP9k,4712
10
+ universal_mcp/agents/bigtool2/__init__.py,sha256=i4virR9r1_1FcS_-iuSHZWgEzYZwOroT6J44qPb0ZgM,2462
11
+ universal_mcp/agents/bigtool2/__main__.py,sha256=t6fWhLh3SnpN_05cww3LA_r_5Rb0gaF_U4FH1Mpsv1Y,655
12
+ universal_mcp/agents/bigtool2/agent.py,sha256=4GIQIy2VQgdXOezmET8G7tvP_37Vv8C027bGdGXJbTI,437
13
+ universal_mcp/agents/bigtool2/graph.py,sha256=FuW1XyTIr1aUbAC4ea8JWRR0JENvLfZGUSgQFmk0h3A,6544
14
+ universal_mcp/agents/bigtool2/meta_tools.py,sha256=02xOsGdxZpXBirn2KWk63UqYPQjI41nQ2KGj2zKBf7Y,5306
15
+ universal_mcp/agents/bigtool2/prompts.py,sha256=rQFtZDkwU9z8d4PWdt6jpohGhyab658Xvk8hvNVBFBA,1843
16
+ universal_mcp/agents/bigtool2/state.py,sha256=TQeGZD99okclkoCh5oz-VYIlEsC9yLQyDpnBnm7QCN8,759
17
+ universal_mcp/agents/bigtoolcache/__init__.py,sha256=qrUwYqhZNE0PdmUCGc5jRQt45Tr1xPDSfBxCPJA1DDM,2260
18
+ universal_mcp/agents/bigtoolcache/__main__.py,sha256=noqT7Nqr17q7Eeiib-Dk2qG6AH4LkNyveeU_ceNDfMA,473
19
+ universal_mcp/agents/bigtoolcache/agent.py,sha256=NCF6fdBPwVcaOyhv8xbAy5DBqbGxJiv8_fLqKib7QJc,267
20
+ universal_mcp/agents/bigtoolcache/context.py,sha256=ny7gd-vvVpUOYAeQbAEUT0A6Vm6Nn2qGywxTzPBzYFg,929
21
+ universal_mcp/agents/bigtoolcache/graph.py,sha256=9KUjsVu5dtPdnyNkqJ5LsMnfH-IF_4H2me_L5aHgsug,4315
22
+ universal_mcp/agents/bigtoolcache/prompts.py,sha256=Rz30qNGdscDG65vMj9d0Vfe7X1pQjBDQBBNc3BuyC94,1886
23
+ universal_mcp/agents/bigtoolcache/state.py,sha256=TQeGZD99okclkoCh5oz-VYIlEsC9yLQyDpnBnm7QCN8,759
24
+ universal_mcp/agents/bigtoolcache/tools.py,sha256=ynyEj9mVwKKDhxm76sjspyH51SFi63g2Vydi39pY0qY,5562
25
+ universal_mcp/agents/codeact/__init__.py,sha256=rLE8gvOo5H4YSr71DRq76b3RV3uuotxuAy_VnBVaVwk,60
26
+ universal_mcp/agents/codeact/__main__.py,sha256=FRfIkgcZfawP-M66v4ePijA6J2fs7nQv92G_8cj5qYA,1142
27
+ universal_mcp/agents/codeact/agent.py,sha256=yB99aTRHWOdl4b67UxRstuV7WplrTjUZuqP1odwSS5o,5586
28
+ universal_mcp/agents/codeact/prompts.py,sha256=6NZkWQCaS7X7CLOTV-hMZgeWa1jf6iKbAT00INuluM0,4668
29
+ universal_mcp/agents/codeact/sandbox.py,sha256=pG6M1elzWw4KS46ewl-2d_U9Ap8HnHJDY9Rna_76sRI,1489
30
+ universal_mcp/agents/codeact/state.py,sha256=K25HcEljNNJDaeUgG5P68Kj752XzWTh8BwILY8w_EtE,357
31
+ universal_mcp/agents/codeact/utils.py,sha256=JUbT_HYGS_D1BzmzoVpORIe7SGur1KgJguTZ_1tZ4JY,1918
32
+ universal_mcp/agents/planner/__init__.py,sha256=9P1UL-ABvrTIWTJ8wcvZmkqT8uyROZxsmUFhpjTK-Q4,1313
33
+ universal_mcp/agents/planner/__main__.py,sha256=OfhTfYDZK_ZUfc8sX-Sa6TWk-dNqD2rl13Ln64mNAtw,771
34
+ universal_mcp/agents/planner/graph.py,sha256=70hhIoEZOcYojpiyVSCedgYpnmxVP7aqdn8s6VBu-D4,3228
35
+ universal_mcp/agents/planner/prompts.py,sha256=_JoHqiAvswtqCDu90AGUHmfsu8eWE1-_yI4LLn3pqMU,657
36
+ universal_mcp/agents/planner/state.py,sha256=qqyp-jSGsCxe1US-PRLT4-y1sITAcVE6nCMlQLnvop0,278
37
+ universal_mcp/agents/shared/prompts.py,sha256=VOsXSUEwBXPaAuxJTUF6bgDGr41u6uctUNQSMRt_OJc,6414
38
+ universal_mcp/agents/shared/tool_node.py,sha256=Ua_wzMt4YgIx4zLp3_ZCow-28qORwrZ2FvKqLPt3RlI,10415
39
+ universal_mcp/applications/ui/app.py,sha256=uaS1KrwrGxw9oexdLj2Jok77DrZQAmby3uVxCONQyV8,11276
40
+ universal_mcp_agents-0.1.11.dist-info/METADATA,sha256=MosDAsvQTSvUr41527xNHF8QpEeatOh7g0bpBDr7lW0,878
41
+ universal_mcp_agents-0.1.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
42
+ universal_mcp_agents-0.1.11.dist-info/RECORD,,
@@ -1,30 +0,0 @@
1
- from langgraph.checkpoint.base import BaseCheckpointSaver
2
- from universal_mcp.tools.registry import ToolRegistry
3
-
4
- from universal_mcp.agents.autoagent.graph import build_graph
5
- from universal_mcp.agents.base import BaseAgent
6
-
7
-
8
- class AutoAgent(BaseAgent):
9
- def __init__(
10
- self,
11
- name: str,
12
- instructions: str,
13
- model: str,
14
- memory: BaseCheckpointSaver | None = None,
15
- registry: ToolRegistry | None = None,
16
- **kwargs,
17
- ):
18
- super().__init__(name, instructions, model, memory, **kwargs)
19
- self.tool_registry = registry
20
-
21
- async def _build_graph(self):
22
- builder = await build_graph(self.tool_registry, self.instructions)
23
- return builder.compile(checkpointer=self.memory)
24
-
25
- @property
26
- def graph(self):
27
- return self._graph
28
-
29
-
30
- __all__ = ["AutoAgent"]
@@ -1,25 +0,0 @@
1
- import asyncio
2
-
3
- from loguru import logger
4
- from universal_mcp.agentr.registry import AgentrRegistry
5
-
6
- from universal_mcp.agents.autoagent import AutoAgent
7
-
8
-
9
- async def main():
10
- agent = AutoAgent(
11
- name="autoagent",
12
- instructions="You are a helpful assistant that can use tools to help the user.",
13
- model="azure/gpt-4.1",
14
- registry=AgentrRegistry(),
15
- )
16
- async for event in agent.stream(
17
- user_input="Send an email to manoj@agentr.dev",
18
- thread_id="test123",
19
- ):
20
- logger.info(event.content)
21
- # from loguru import logger; logger.debug(result)
22
-
23
-
24
- if __name__ == "__main__":
25
- asyncio.run(main())
@@ -1,26 +0,0 @@
1
- from dataclasses import dataclass, field
2
- from typing import Annotated
3
-
4
- from universal_mcp.agents.autoagent.prompts import SYSTEM_PROMPT
5
-
6
-
7
- @dataclass(kw_only=True)
8
- class Context:
9
- """The context for the agent."""
10
-
11
- system_prompt: str = field(
12
- default=SYSTEM_PROMPT,
13
- metadata={
14
- "description": "The system prompt to use for the agent's interactions. "
15
- "This prompt sets the context and behavior for the agent."
16
- },
17
- )
18
-
19
- model: Annotated[str, {"__template_metadata__": {"kind": "llm"}}] = field(
20
- default="anthropic/claude-4-sonnet-20250514",
21
- # default="vertex/gemini-2.5-flash",
22
- metadata={
23
- "description": "The name of the language model to use for the agent's main interactions. "
24
- "Should be in the form: provider/model-name."
25
- },
26
- )