universal-mcp-agents 0.1.22__py3-none-any.whl → 0.1.23__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.
- universal_mcp/agents/__init__.py +2 -8
- universal_mcp/agents/base.py +44 -34
- universal_mcp/agents/bigtool/state.py +1 -1
- universal_mcp/agents/cli.py +2 -2
- universal_mcp/agents/codeact0/__main__.py +2 -5
- universal_mcp/agents/codeact0/agent.py +314 -154
- universal_mcp/agents/codeact0/prompts.py +210 -128
- universal_mcp/agents/codeact0/sandbox.py +21 -17
- universal_mcp/agents/codeact0/state.py +14 -14
- universal_mcp/agents/codeact0/tools.py +384 -163
- universal_mcp/agents/codeact0/utils.py +77 -6
- universal_mcp/agents/llm.py +10 -4
- universal_mcp/agents/react.py +3 -3
- universal_mcp/agents/sandbox.py +124 -69
- universal_mcp/applications/llm/app.py +20 -19
- {universal_mcp_agents-0.1.22.dist-info → universal_mcp_agents-0.1.23.dist-info}/METADATA +6 -5
- {universal_mcp_agents-0.1.22.dist-info → universal_mcp_agents-0.1.23.dist-info}/RECORD +18 -18
- {universal_mcp_agents-0.1.22.dist-info → universal_mcp_agents-0.1.23.dist-info}/WHEEL +0 -0
|
@@ -4,12 +4,82 @@ import re
|
|
|
4
4
|
from collections.abc import Sequence
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
|
-
from langchain_core.messages import BaseMessage
|
|
7
|
+
from langchain_core.messages import AIMessage, BaseMessage
|
|
8
8
|
from universal_mcp.types import ToolConfig
|
|
9
9
|
|
|
10
10
|
MAX_CHARS = 5000
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
def build_anthropic_cache_message(text: str, role: str = "system", ttl: str = "1h") -> list[dict[str, Any]]:
|
|
14
|
+
"""Build a complete Anthropic cache messages array from text.
|
|
15
|
+
|
|
16
|
+
Returns a list with a single cache message whose content is the
|
|
17
|
+
cached Anthropic content array with ephemeral cache control and TTL.
|
|
18
|
+
"""
|
|
19
|
+
return [
|
|
20
|
+
{
|
|
21
|
+
"role": role,
|
|
22
|
+
"content": [
|
|
23
|
+
{
|
|
24
|
+
"type": "text",
|
|
25
|
+
"text": text,
|
|
26
|
+
"cache_control": {"type": "ephemeral", "ttl": ttl},
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
def strip_thinking(messages: list[BaseMessage]):
|
|
33
|
+
"""Remove Anthropic 'thinking' segments from the most recent AIMessage in-place.
|
|
34
|
+
|
|
35
|
+
Scans from the end to find the last AIMessage, then removes thinking blocks
|
|
36
|
+
from its content. Handles both plain-string and block-array content.
|
|
37
|
+
"""
|
|
38
|
+
if not messages:
|
|
39
|
+
return messages
|
|
40
|
+
|
|
41
|
+
# Find the last AIMessage from the end
|
|
42
|
+
last_ai_index = None
|
|
43
|
+
for i in range(len(messages) - 1, -1, -1):
|
|
44
|
+
if isinstance(messages[i], AIMessage):
|
|
45
|
+
last_ai_index = i
|
|
46
|
+
break
|
|
47
|
+
|
|
48
|
+
if last_ai_index is None:
|
|
49
|
+
return messages
|
|
50
|
+
|
|
51
|
+
ai_msg = messages[last_ai_index]
|
|
52
|
+
content = ai_msg.content
|
|
53
|
+
|
|
54
|
+
# If it's already plain text, nothing to strip
|
|
55
|
+
if isinstance(content, str):
|
|
56
|
+
return messages
|
|
57
|
+
|
|
58
|
+
# If Anthropic-style content blocks
|
|
59
|
+
if isinstance(content, list):
|
|
60
|
+
filtered_output: list[object] = []
|
|
61
|
+
removed_any = False
|
|
62
|
+
for b in content:
|
|
63
|
+
is_thinking = False
|
|
64
|
+
if isinstance(b, dict):
|
|
65
|
+
t = b.get("type")
|
|
66
|
+
if t == "thinking":
|
|
67
|
+
is_thinking = True
|
|
68
|
+
elif "thinking" in b and isinstance(b["thinking"], str):
|
|
69
|
+
is_thinking = True
|
|
70
|
+
|
|
71
|
+
if is_thinking:
|
|
72
|
+
removed_any = True
|
|
73
|
+
continue
|
|
74
|
+
filtered_output.append(b)
|
|
75
|
+
|
|
76
|
+
if removed_any:
|
|
77
|
+
ai_msg.content = filtered_output
|
|
78
|
+
messages[last_ai_index] = ai_msg
|
|
79
|
+
|
|
80
|
+
return messages
|
|
81
|
+
|
|
82
|
+
|
|
13
83
|
def add_tools(tool_config: ToolConfig, tools_to_add: ToolConfig):
|
|
14
84
|
for app_id, new_tools in tools_to_add.items():
|
|
15
85
|
all_tools = tool_config.get(app_id, []) + new_tools
|
|
@@ -375,6 +445,7 @@ def schema_to_signature(schema: dict, func_name: str = "my_function") -> str:
|
|
|
375
445
|
param_str = ",\n ".join(params)
|
|
376
446
|
return f"def {func_name}(\n {param_str},\n):"
|
|
377
447
|
|
|
448
|
+
|
|
378
449
|
def smart_truncate(
|
|
379
450
|
output: str, max_chars_full: int = 2000, max_lines_headtail: int = 20, summary_threshold: int = 10000
|
|
380
451
|
) -> str:
|
|
@@ -413,21 +484,21 @@ async def get_connected_apps_string(registry) -> str:
|
|
|
413
484
|
"""Get a formatted string of connected applications from the registry."""
|
|
414
485
|
if not registry:
|
|
415
486
|
return ""
|
|
416
|
-
|
|
487
|
+
|
|
417
488
|
try:
|
|
418
489
|
# Get connected apps from registry
|
|
419
490
|
connections = await registry.list_connected_apps()
|
|
420
491
|
if not connections:
|
|
421
492
|
return "No applications are currently connected."
|
|
422
|
-
|
|
493
|
+
|
|
423
494
|
# Extract app names from connections
|
|
424
495
|
connected_app_ids = {connection["app_id"] for connection in connections}
|
|
425
|
-
|
|
496
|
+
|
|
426
497
|
# Format the apps list
|
|
427
498
|
apps_list = []
|
|
428
499
|
for app_id in connected_app_ids:
|
|
429
500
|
apps_list.append(f"- {app_id}")
|
|
430
|
-
|
|
501
|
+
|
|
431
502
|
return "\n".join(apps_list)
|
|
432
503
|
except Exception:
|
|
433
|
-
return "Unable to retrieve connected applications."
|
|
504
|
+
return "Unable to retrieve connected applications."
|
universal_mcp/agents/llm.py
CHANGED
|
@@ -4,26 +4,33 @@ from langchain_anthropic import ChatAnthropic
|
|
|
4
4
|
from langchain_core.language_models import BaseChatModel
|
|
5
5
|
from langchain_google_genai import ChatGoogleGenerativeAI
|
|
6
6
|
from langchain_openai import AzureChatOpenAI
|
|
7
|
+
from loguru import logger
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
@lru_cache(maxsize=8)
|
|
10
11
|
def load_chat_model(
|
|
11
|
-
fully_specified_name: str, temperature: float = 1.0, tags:
|
|
12
|
+
fully_specified_name: str, temperature: float = 1.0, tags: tuple[str, ...] | None = None, thinking: bool = True, disable_streaming: bool = False
|
|
12
13
|
) -> BaseChatModel:
|
|
13
14
|
"""Load a chat model from a fully specified name.
|
|
14
15
|
Args:
|
|
15
16
|
fully_specified_name (str): String in the format 'provider/model'.
|
|
16
17
|
"""
|
|
17
18
|
fully_specified_name = fully_specified_name.replace("/", ":")
|
|
19
|
+
if tags:
|
|
20
|
+
if isinstance(tags, str):
|
|
21
|
+
tags = [tags]
|
|
22
|
+
else:
|
|
23
|
+
tags = list[str](tags)
|
|
18
24
|
provider, model = fully_specified_name.split(":", maxsplit=1)
|
|
19
25
|
if provider == "anthropic":
|
|
20
26
|
return ChatAnthropic(
|
|
21
27
|
model=model,
|
|
22
28
|
temperature=temperature,
|
|
23
29
|
thinking={"type": "enabled", "budget_tokens": 2048} if thinking else None,
|
|
24
|
-
max_tokens=
|
|
30
|
+
max_tokens=8096,
|
|
25
31
|
tags=tags,
|
|
26
32
|
stream_usage=True,
|
|
33
|
+
disable_streaming = disable_streaming
|
|
27
34
|
) # pyright: ignore[reportCallIssue]
|
|
28
35
|
elif provider == "azure":
|
|
29
36
|
return AzureChatOpenAI(
|
|
@@ -33,6 +40,7 @@ def load_chat_model(
|
|
|
33
40
|
temperature=temperature,
|
|
34
41
|
tags=tags,
|
|
35
42
|
stream_usage=True,
|
|
43
|
+
disable_streaming = disable_streaming
|
|
36
44
|
)
|
|
37
45
|
elif provider == "gemini":
|
|
38
46
|
return ChatGoogleGenerativeAI(model=model, temperature=temperature)
|
|
@@ -41,8 +49,6 @@ def load_chat_model(
|
|
|
41
49
|
|
|
42
50
|
|
|
43
51
|
if __name__ == "__main__":
|
|
44
|
-
from loguru import logger
|
|
45
|
-
|
|
46
52
|
models_to_test = [
|
|
47
53
|
"azure/gpt-5-chat",
|
|
48
54
|
"anthropic/claude-4-sonnet-20250514",
|
universal_mcp/agents/react.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
from langchain.agents import create_agent
|
|
1
2
|
from langgraph.checkpoint.base import BaseCheckpointSaver
|
|
2
|
-
from langgraph.prebuilt import create_react_agent
|
|
3
3
|
from loguru import logger
|
|
4
4
|
from rich import print
|
|
5
5
|
from universal_mcp.agentr.registry import AgentrRegistry
|
|
@@ -75,10 +75,10 @@ class ReactAgent(BaseAgent):
|
|
|
75
75
|
tools = []
|
|
76
76
|
|
|
77
77
|
logger.debug(f"Initialized ReactAgent: name={self.name}, model={self.model}")
|
|
78
|
-
return
|
|
78
|
+
return create_agent(
|
|
79
79
|
self.llm,
|
|
80
80
|
tools,
|
|
81
|
-
|
|
81
|
+
system_prompt=self._build_system_message(),
|
|
82
82
|
checkpointer=self.memory,
|
|
83
83
|
)
|
|
84
84
|
|
universal_mcp/agents/sandbox.py
CHANGED
|
@@ -1,90 +1,145 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
import base64
|
|
1
3
|
import contextlib
|
|
2
|
-
import inspect
|
|
3
4
|
import io
|
|
4
|
-
import
|
|
5
|
-
import re
|
|
6
|
-
import socket
|
|
7
|
-
import threading
|
|
8
|
-
import types
|
|
9
|
-
from typing import Any
|
|
5
|
+
import traceback
|
|
10
6
|
|
|
11
|
-
|
|
7
|
+
import cloudpickle as pickle
|
|
8
|
+
from loguru import logger
|
|
12
9
|
|
|
13
10
|
|
|
14
11
|
class Sandbox:
|
|
15
12
|
"""
|
|
16
|
-
A
|
|
13
|
+
A simulated environment for executing Python code cells with context
|
|
14
|
+
maintained across multiple runs.
|
|
17
15
|
"""
|
|
18
16
|
|
|
19
|
-
def __init__(self
|
|
17
|
+
def __init__(self):
|
|
18
|
+
# Dictionary to store variables (context) across runs
|
|
19
|
+
self.context = {}
|
|
20
|
+
|
|
21
|
+
def add_context(self, context: dict[str, any]):
|
|
22
|
+
"""
|
|
23
|
+
Adds a dictionary of context to the sandbox.
|
|
24
|
+
"""
|
|
25
|
+
self.context.update(context)
|
|
26
|
+
|
|
27
|
+
def save_context(self) -> str:
|
|
28
|
+
"""
|
|
29
|
+
Saves the context to a base64 string.
|
|
30
|
+
files, IO, threads, etc. are not pickable. So we only pickle the context that is pickable.
|
|
31
|
+
"""
|
|
32
|
+
pickable_context = {}
|
|
33
|
+
for key, value in self.context.items():
|
|
34
|
+
try:
|
|
35
|
+
pickle.dumps(value)
|
|
36
|
+
pickable_context[key] = value
|
|
37
|
+
except Exception as e:
|
|
38
|
+
logger.error(f"Error picking {key}: {e}")
|
|
39
|
+
pickled_data = pickle.dumps(pickable_context)
|
|
40
|
+
base64_encoded = base64.b64encode(pickled_data).decode("utf-8")
|
|
41
|
+
return base64_encoded
|
|
42
|
+
|
|
43
|
+
def load_context(self, context: str, add_context: list[str] = []):
|
|
20
44
|
"""
|
|
21
|
-
|
|
45
|
+
Loads the context from a base64 string.
|
|
46
|
+
Also executes the add_context code strings to add to the context.
|
|
47
|
+
"""
|
|
48
|
+
if context:
|
|
49
|
+
pickled_data = base64.b64decode(context)
|
|
50
|
+
new_context = pickle.loads(pickled_data)
|
|
51
|
+
self.context.update(new_context)
|
|
52
|
+
for code in add_context:
|
|
53
|
+
self.run(code)
|
|
54
|
+
return self.context
|
|
55
|
+
|
|
56
|
+
def _filter_context(self, context: dict[str, any]) -> dict[str, any]:
|
|
57
|
+
"""
|
|
58
|
+
Filters the context to only include pickable variables.
|
|
59
|
+
"""
|
|
60
|
+
return {k: v for k, v in context.items() if not k.startswith("__")}
|
|
61
|
+
|
|
62
|
+
def run(self, code: str) -> dict[str, any]:
|
|
63
|
+
"""
|
|
64
|
+
Executes the provided Python code string in the maintained context.
|
|
65
|
+
|
|
22
66
|
Args:
|
|
23
|
-
|
|
67
|
+
code (str): The Python code to execute.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
dict: A dictionary containing the execution results.
|
|
24
71
|
"""
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
72
|
+
# Prepare the execution environment:
|
|
73
|
+
# Use a copy of the context for execution locals/globals
|
|
74
|
+
exec_scope = self.context.copy()
|
|
75
|
+
|
|
76
|
+
stdout_capture = io.StringIO()
|
|
77
|
+
stderr_output = ""
|
|
28
78
|
|
|
29
|
-
|
|
79
|
+
# Use a true context manager for robust stdout capture
|
|
80
|
+
try:
|
|
81
|
+
with contextlib.redirect_stdout(stdout_capture):
|
|
82
|
+
# Execute the code. Using the same dictionary for globals and locals
|
|
83
|
+
# allows newly created variables to be visible immediately.
|
|
84
|
+
exec(code, exec_scope, exec_scope)
|
|
85
|
+
|
|
86
|
+
# Update the context with any new/modified variables
|
|
87
|
+
# Filter out dunder methods/system keys that might be introduced by exec
|
|
88
|
+
new_context = self._filter_context(exec_scope)
|
|
89
|
+
self.context.update(new_context)
|
|
90
|
+
|
|
91
|
+
except Exception:
|
|
92
|
+
# Capture the traceback for better error reporting (simulated stderr)
|
|
93
|
+
stderr_output = traceback.format_exc()
|
|
94
|
+
|
|
95
|
+
# The execution scope might contain partially defined variables,
|
|
96
|
+
# but we continue to maintain the *previous* valid context.
|
|
97
|
+
# We don't update self.context on failure to avoid polluting it.
|
|
98
|
+
|
|
99
|
+
return {"stdout": stdout_capture.getvalue(), "stderr": stderr_output, "success": stderr_output == ""}
|
|
100
|
+
|
|
101
|
+
def get_context(self) -> dict[str, any]:
|
|
30
102
|
"""
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
103
|
+
Returns a copy of the current execution context.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
dict: A copy of the context dictionary.
|
|
35
107
|
"""
|
|
108
|
+
return self.context.copy()
|
|
36
109
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
threading.Event,
|
|
43
|
-
threading.Condition,
|
|
44
|
-
threading.Semaphore,
|
|
45
|
-
queue.Queue,
|
|
46
|
-
socket.socket,
|
|
47
|
-
io.IOBase,
|
|
48
|
-
)
|
|
110
|
+
def reset(self):
|
|
111
|
+
"""
|
|
112
|
+
Resets the sandbox's context, clearing all defined variables.
|
|
113
|
+
"""
|
|
114
|
+
self.context = {}
|
|
49
115
|
|
|
50
|
-
|
|
116
|
+
async def arun(self, code: str) -> dict[str, any]:
|
|
117
|
+
"""
|
|
118
|
+
Asynchronously executes Python code, supporting top-level await.
|
|
119
|
+
"""
|
|
120
|
+
# Use a copy of the context for execution
|
|
121
|
+
exec_scope = self.context.copy()
|
|
122
|
+
stdout_capture = io.StringIO()
|
|
123
|
+
stderr_output = ""
|
|
51
124
|
|
|
52
|
-
def target():
|
|
53
|
-
try:
|
|
54
|
-
with contextlib.redirect_stdout(io.StringIO()) as f:
|
|
55
|
-
exec(code, self._locals, self._locals)
|
|
56
|
-
result_container["output"] = f.getvalue() or "<code ran, no output printed to stdout>"
|
|
57
|
-
except Exception as e:
|
|
58
|
-
result_container["output"] = "Error during execution: " + str(e)
|
|
59
|
-
|
|
60
|
-
thread = threading.Thread(target=target)
|
|
61
|
-
thread.start()
|
|
62
|
-
thread.join(self.timeout)
|
|
63
|
-
|
|
64
|
-
if thread.is_alive():
|
|
65
|
-
result_container["output"] = f"Code timeout: code execution exceeded {self.timeout} seconds."
|
|
66
|
-
|
|
67
|
-
# Filter locals for picklable/storable variables
|
|
68
|
-
all_vars = {}
|
|
69
|
-
for key, value in self._locals.items():
|
|
70
|
-
if key == "__builtins__":
|
|
71
|
-
continue
|
|
72
|
-
if inspect.iscoroutine(value) or inspect.iscoroutinefunction(value):
|
|
73
|
-
continue
|
|
74
|
-
if inspect.isasyncgen(value) or inspect.isasyncgenfunction(value):
|
|
75
|
-
continue
|
|
76
|
-
if isinstance(value, EXCLUDE_TYPES):
|
|
77
|
-
continue
|
|
78
|
-
if not callable(value) or not hasattr(value, "__name__"):
|
|
79
|
-
all_vars[key] = value
|
|
80
|
-
|
|
81
|
-
self._locals = all_vars
|
|
82
|
-
|
|
83
|
-
# Safely derive context
|
|
84
125
|
try:
|
|
85
|
-
|
|
126
|
+
# Compile the code with the special flag to allow top-level await
|
|
127
|
+
compiled_code = compile(code, "<string>", "exec", flags=ast.PyCF_ALLOW_TOP_LEVEL_AWAIT)
|
|
128
|
+
|
|
129
|
+
with contextlib.redirect_stdout(stdout_capture):
|
|
130
|
+
# Eval the compiled code to get a coroutine
|
|
131
|
+
coroutine = eval(compiled_code, exec_scope, exec_scope)
|
|
132
|
+
|
|
133
|
+
# Await the coroutine to run the code if it's async
|
|
134
|
+
if coroutine:
|
|
135
|
+
await coroutine
|
|
136
|
+
|
|
137
|
+
# Update the context with any new/modified variables
|
|
138
|
+
new_context = self._filter_context(exec_scope)
|
|
139
|
+
if new_context:
|
|
140
|
+
self.context.update(new_context)
|
|
141
|
+
|
|
86
142
|
except Exception:
|
|
87
|
-
|
|
88
|
-
pass
|
|
143
|
+
stderr_output = traceback.format_exc()
|
|
89
144
|
|
|
90
|
-
return
|
|
145
|
+
return {"stdout": stdout_capture.getvalue(), "stderr": stderr_output, "success": stderr_output == ""}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from typing import Any, Literal, cast
|
|
3
3
|
|
|
4
|
-
from langchain.
|
|
4
|
+
from langchain.agents import create_agent
|
|
5
5
|
from pydantic import BaseModel, Field
|
|
6
6
|
from universal_mcp.applications.application import BaseApplication
|
|
7
7
|
|
|
@@ -91,8 +91,8 @@ class LlmApp(BaseApplication):
|
|
|
91
91
|
|
|
92
92
|
full_prompt = f"{prompt}\n\nContext:\n{context_str}\n\n"
|
|
93
93
|
|
|
94
|
-
model = load_chat_model("azure/gpt-5-mini")
|
|
95
|
-
response = model.with_retry(stop_after_attempt=MAX_RETRIES).invoke(full_prompt)
|
|
94
|
+
model = load_chat_model("azure/gpt-5-mini", disable_streaming = True, tags=("quiet",))
|
|
95
|
+
response = model.with_retry(stop_after_attempt=MAX_RETRIES).invoke(full_prompt, stream=False)
|
|
96
96
|
return str(response.content)
|
|
97
97
|
|
|
98
98
|
def classify_data(
|
|
@@ -151,22 +151,22 @@ class LlmApp(BaseApplication):
|
|
|
151
151
|
f"This is a classification task.\nPossible classes and descriptions:\n"
|
|
152
152
|
f"{json.dumps(class_descriptions, indent=2)}\n\n"
|
|
153
153
|
f"Context:\n{context_str}\n\n"
|
|
154
|
-
"Return ONLY a valid JSON object, no extra text."
|
|
155
154
|
)
|
|
156
155
|
|
|
157
|
-
model = init_chat_model(model="claude-4-sonnet-20250514", temperature=0)
|
|
158
|
-
|
|
159
156
|
class ClassificationResult(BaseModel):
|
|
160
157
|
probabilities: dict[str, float] = Field(..., description="The probabilities for each class.")
|
|
161
158
|
reason: str = Field(..., description="The reasoning behind the classification.")
|
|
162
159
|
top_class: str = Field(..., description="The class with the highest probability.")
|
|
163
160
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
161
|
+
model = load_chat_model("azure/gpt-5-mini", temperature=0, disable_streaming = True, tags=("quiet",))
|
|
162
|
+
agent = create_agent(
|
|
163
|
+
model=model,
|
|
164
|
+
tools=[],
|
|
165
|
+
response_format=ClassificationResult, # Auto-selects ProviderStrategy
|
|
168
166
|
)
|
|
169
|
-
|
|
167
|
+
|
|
168
|
+
result = agent.invoke({"messages": [{"role": "user", "content": prompt}]}, stream=False)
|
|
169
|
+
return result["structured_response"].model_dump()
|
|
170
170
|
|
|
171
171
|
def extract_data(
|
|
172
172
|
self,
|
|
@@ -229,12 +229,12 @@ class LlmApp(BaseApplication):
|
|
|
229
229
|
"Return ONLY a valid JSON object that conforms to the provided schema, with no extra text."
|
|
230
230
|
)
|
|
231
231
|
|
|
232
|
-
model =
|
|
232
|
+
model = load_chat_model("azure/gpt-5-mini", temperature=0, disable_streaming = True, tags=("quiet",))
|
|
233
233
|
|
|
234
234
|
response = (
|
|
235
235
|
model.with_structured_output(schema=output_schema, method="json_mode")
|
|
236
236
|
.with_retry(stop_after_attempt=MAX_RETRIES)
|
|
237
|
-
.invoke(prompt)
|
|
237
|
+
.invoke(prompt, stream=False)
|
|
238
238
|
)
|
|
239
239
|
return cast(dict[str, Any], response)
|
|
240
240
|
|
|
@@ -282,14 +282,15 @@ class LlmApp(BaseApplication):
|
|
|
282
282
|
|
|
283
283
|
prompt = f"{task_instructions}\n\nContext:\n{context_str}\n\nReturn ONLY a valid JSON object, no extra text."
|
|
284
284
|
|
|
285
|
-
model =
|
|
285
|
+
model = load_chat_model("azure/gpt-5-mini", temperature=0, disable_streaming = True, tags=("quiet",))
|
|
286
286
|
|
|
287
|
-
|
|
288
|
-
model
|
|
289
|
-
|
|
290
|
-
|
|
287
|
+
agent = create_agent(
|
|
288
|
+
model=model,
|
|
289
|
+
tools=[],
|
|
290
|
+
response_format=output_schema,
|
|
291
291
|
)
|
|
292
|
-
|
|
292
|
+
result = agent.invoke({"messages": [{"role": "user", "content": prompt}]}, stream=False)
|
|
293
|
+
return result["structured_response"]
|
|
293
294
|
|
|
294
295
|
def list_tools(self):
|
|
295
296
|
return [
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: universal-mcp-agents
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.23
|
|
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
|
|
7
7
|
Author-email: Manoj Bajaj <manojbajaj95@gmail.com>
|
|
8
8
|
License: MIT
|
|
9
9
|
Requires-Python: >=3.11
|
|
10
|
+
Requires-Dist: cloudpickle>=3.1.1
|
|
10
11
|
Requires-Dist: langchain-anthropic>=0.3.19
|
|
11
12
|
Requires-Dist: langchain-google-genai>=2.1.10
|
|
12
13
|
Requires-Dist: langchain-openai>=0.3.32
|
|
13
14
|
Requires-Dist: langgraph>=0.6.6
|
|
14
|
-
Requires-Dist:
|
|
15
|
-
Requires-Dist: universal-mcp
|
|
16
|
-
Requires-Dist: universal-mcp>=0.1.24rc25
|
|
15
|
+
Requires-Dist: universal-mcp-applications>=0.1.30
|
|
16
|
+
Requires-Dist: universal-mcp>=0.1.24rc29
|
|
17
17
|
Provides-Extra: dev
|
|
18
18
|
Requires-Dist: pre-commit; extra == 'dev'
|
|
19
19
|
Requires-Dist: ruff; extra == 'dev'
|
|
20
|
+
Requires-Dist: typer>=0.17.4; extra == 'dev'
|
|
20
21
|
Provides-Extra: test
|
|
21
|
-
Requires-Dist: pytest-asyncio>=1.
|
|
22
|
+
Requires-Dist: pytest-asyncio>=1.2.0; extra == 'test'
|
|
22
23
|
Requires-Dist: pytest-cov; extra == 'test'
|
|
23
24
|
Requires-Dist: pytest<9.0.0,>=7.0.0; extra == 'test'
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
universal_mcp/agents/__init__.py,sha256=
|
|
2
|
-
universal_mcp/agents/base.py,sha256=
|
|
3
|
-
universal_mcp/agents/cli.py,sha256=
|
|
1
|
+
universal_mcp/agents/__init__.py,sha256=Ythw8tyq7p-w1SPnuO2JtS4TvYEP75PkQpdyvZv-ww4,914
|
|
2
|
+
universal_mcp/agents/base.py,sha256=HkTQzh8EudkG4_5teiD0aDidWpfp2obOz0XR9XsZeUI,7949
|
|
3
|
+
universal_mcp/agents/cli.py,sha256=d3O5BxkT4axHcKnL7gM1SvneWoZMh1QQoElk03KeuU4,950
|
|
4
4
|
universal_mcp/agents/hil.py,sha256=_5PCK6q0goGm8qylJq44aSp2MadP-yCPvhOJYKqWLMo,3808
|
|
5
|
-
universal_mcp/agents/llm.py,sha256=
|
|
6
|
-
universal_mcp/agents/react.py,sha256=
|
|
7
|
-
universal_mcp/agents/sandbox.py,sha256=
|
|
5
|
+
universal_mcp/agents/llm.py,sha256=AOijT3hCt3VId97FnvARsPG9lx0sLmn-yiUo8Qx90lQ,2043
|
|
6
|
+
universal_mcp/agents/react.py,sha256=ocYm94HOiJVI2zwTjO1K2PNfVY7EILLJ6cd__jnGHPs,3327
|
|
7
|
+
universal_mcp/agents/sandbox.py,sha256=YxTGp_zsajuN7FUn0Q4PFjuXczgLht7oKql_gyb2Gf4,5112
|
|
8
8
|
universal_mcp/agents/simple.py,sha256=NSATg5TWzsRNS7V3LFiDG28WSOCIwCdcC1g7NRwg2nM,2095
|
|
9
9
|
universal_mcp/agents/utils.py,sha256=P6W9k6XAOBp6tdjC2VTP4tE0B2M4-b1EDmr-ylJ47Pw,7765
|
|
10
10
|
universal_mcp/agents/bigtool/__init__.py,sha256=mZG8dsaCVyKlm82otxtiTA225GIFLUCUUYPEIPF24uw,2299
|
|
@@ -13,7 +13,7 @@ universal_mcp/agents/bigtool/agent.py,sha256=mtCDNN8WjE2hjJjooDqusmbferKBHeJMHrh
|
|
|
13
13
|
universal_mcp/agents/bigtool/context.py,sha256=ny7gd-vvVpUOYAeQbAEUT0A6Vm6Nn2qGywxTzPBzYFg,929
|
|
14
14
|
universal_mcp/agents/bigtool/graph.py,sha256=2Sy0dtevTWeT3hJDq4BDerZFvk_zJqx15j8VH2XLq8Y,5848
|
|
15
15
|
universal_mcp/agents/bigtool/prompts.py,sha256=Joi5mCzZX63aM_6eBrMOKuNRHjTkceVIibSsGBGqhYE,2041
|
|
16
|
-
universal_mcp/agents/bigtool/state.py,sha256=
|
|
16
|
+
universal_mcp/agents/bigtool/state.py,sha256=Voh7HXGC0PVe_0qoRZ8ZYg9akg65_2jQIAV2eIwperE,737
|
|
17
17
|
universal_mcp/agents/bigtool/tools.py,sha256=-u80ta6xEaqzEMSzDVe3QZiTZm3YlgLkBD8WTghzClw,6315
|
|
18
18
|
universal_mcp/agents/builder/__main__.py,sha256=VJDJOr-dJJerT53ibh5LVqIsMJ0m0sG2UlzFB784pKw,11680
|
|
19
19
|
universal_mcp/agents/builder/builder.py,sha256=mh3MZpMVB1FE1DWzvMW9NnfiaF145VGn8cJzKSYUlzY,8587
|
|
@@ -21,24 +21,24 @@ universal_mcp/agents/builder/helper.py,sha256=8igR1b3Gy_N2u3WxHYKIWzvw7F5BMnfpO2
|
|
|
21
21
|
universal_mcp/agents/builder/prompts.py,sha256=8Xs6uzTUHguDRngVMLak3lkXFkk2VV_uQXaDllzP5cI,4670
|
|
22
22
|
universal_mcp/agents/builder/state.py,sha256=7DeWllxfN-yD6cd9wJ3KIgjO8TctkJvVjAbZT8W_zqk,922
|
|
23
23
|
universal_mcp/agents/codeact0/__init__.py,sha256=8-fvUo1Sm6dURGI-lW-X3Kd78LqySYbb5NMkNJ4NDwg,76
|
|
24
|
-
universal_mcp/agents/codeact0/__main__.py,sha256=
|
|
25
|
-
universal_mcp/agents/codeact0/agent.py,sha256=
|
|
24
|
+
universal_mcp/agents/codeact0/__main__.py,sha256=YyIoecUcKVUhTcCACzLlSmYrayMDsdwzDEqaV4VV4CE,766
|
|
25
|
+
universal_mcp/agents/codeact0/agent.py,sha256=sJmTrFudHMJkkRVJgmd3KdB-kFU-yCwPvyRJE18pJ3g,23497
|
|
26
26
|
universal_mcp/agents/codeact0/config.py,sha256=H-1woj_nhSDwf15F63WYn723y4qlRefXzGxuH81uYF0,2215
|
|
27
27
|
universal_mcp/agents/codeact0/langgraph_agent.py,sha256=8nz2wq-LexImx-l1y9_f81fK72IQetnCeljwgnduNGY,420
|
|
28
28
|
universal_mcp/agents/codeact0/llm_tool.py,sha256=-pAz04OrbZ_dJ2ueysT1qZd02DrbLY4EbU0tiuF_UNU,798
|
|
29
|
-
universal_mcp/agents/codeact0/prompts.py,sha256=
|
|
30
|
-
universal_mcp/agents/codeact0/sandbox.py,sha256=
|
|
31
|
-
universal_mcp/agents/codeact0/state.py,sha256=
|
|
32
|
-
universal_mcp/agents/codeact0/tools.py,sha256=
|
|
33
|
-
universal_mcp/agents/codeact0/utils.py,sha256=
|
|
29
|
+
universal_mcp/agents/codeact0/prompts.py,sha256=TaGxbEka0wxaHIynVe_El_8Qy7bhIpXFLW817lGq3os,17264
|
|
30
|
+
universal_mcp/agents/codeact0/sandbox.py,sha256=Zcr7fvYtcGbwNWd7RPV7-Btl2HtycPIPofEGVmzxSmE,4696
|
|
31
|
+
universal_mcp/agents/codeact0/state.py,sha256=cf-94hfVub-HSQJk6b7_SzqBS-oxMABjFa8jqyjdDK0,1925
|
|
32
|
+
universal_mcp/agents/codeact0/tools.py,sha256=7w-04moo7gBkqjmGzz_rTbmJEG23W0vd71pZ0D9CA9M,23299
|
|
33
|
+
universal_mcp/agents/codeact0/utils.py,sha256=eOdqemLx6RqI5g--vtM9WP2LHrYXro2bxScNAVUU0Do,19683
|
|
34
34
|
universal_mcp/agents/shared/__main__.py,sha256=XxH5qGDpgFWfq7fwQfgKULXGiUgeTp_YKfcxftuVZq8,1452
|
|
35
35
|
universal_mcp/agents/shared/prompts.py,sha256=yjP3zbbuKi87qCj21qwTTicz8TqtkKgnyGSeEjMu3ho,3761
|
|
36
36
|
universal_mcp/agents/shared/tool_node.py,sha256=DC9F-Ri28Pam0u3sXWNODVgmj9PtAEUb5qP1qOoGgfs,9169
|
|
37
37
|
universal_mcp/applications/filesystem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
38
|
universal_mcp/applications/filesystem/app.py,sha256=0TRjjm8YnslVRSmfkXI7qQOAlqWlD1eEn8Jm0xBeigs,5561
|
|
39
39
|
universal_mcp/applications/llm/__init__.py,sha256=_XGRxN3O1--ZS5joAsPf8IlI9Qa6negsJrwJ5VJXno0,46
|
|
40
|
-
universal_mcp/applications/llm/app.py,sha256=
|
|
40
|
+
universal_mcp/applications/llm/app.py,sha256=2BIH6JDqw6LPD9Iuo3_LoXa48813o6G4gmeRBR_v9oc,12933
|
|
41
41
|
universal_mcp/applications/ui/app.py,sha256=c7OkZsO2fRtndgAzAQbKu-1xXRuRp9Kjgml57YD2NR4,9459
|
|
42
|
-
universal_mcp_agents-0.1.
|
|
43
|
-
universal_mcp_agents-0.1.
|
|
44
|
-
universal_mcp_agents-0.1.
|
|
42
|
+
universal_mcp_agents-0.1.23.dist-info/METADATA,sha256=sBzwtuZHot_QhhiMDcIWVVHxi1V373IFHpBTYl9zFyg,928
|
|
43
|
+
universal_mcp_agents-0.1.23.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
44
|
+
universal_mcp_agents-0.1.23.dist-info/RECORD,,
|
|
File without changes
|