universal-mcp-agents 0.1.19rc1__py3-none-any.whl → 0.1.24rc3__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.
- universal_mcp/agents/__init__.py +15 -16
- universal_mcp/agents/base.py +46 -35
- universal_mcp/agents/bigtool/state.py +1 -1
- universal_mcp/agents/cli.py +2 -5
- universal_mcp/agents/codeact0/__init__.py +2 -3
- universal_mcp/agents/codeact0/__main__.py +4 -7
- universal_mcp/agents/codeact0/agent.py +444 -96
- universal_mcp/agents/codeact0/langgraph_agent.py +1 -1
- universal_mcp/agents/codeact0/llm_tool.py +2 -254
- universal_mcp/agents/codeact0/prompts.py +247 -137
- universal_mcp/agents/codeact0/sandbox.py +52 -18
- universal_mcp/agents/codeact0/state.py +26 -6
- universal_mcp/agents/codeact0/tools.py +400 -74
- universal_mcp/agents/codeact0/utils.py +175 -11
- universal_mcp/agents/codeact00/__init__.py +3 -0
- universal_mcp/agents/{unified → codeact00}/__main__.py +4 -6
- universal_mcp/agents/codeact00/agent.py +578 -0
- universal_mcp/agents/codeact00/config.py +77 -0
- universal_mcp/agents/{unified → codeact00}/langgraph_agent.py +2 -2
- universal_mcp/agents/{unified → codeact00}/llm_tool.py +1 -1
- universal_mcp/agents/codeact00/prompts.py +364 -0
- universal_mcp/agents/{unified → codeact00}/sandbox.py +52 -18
- universal_mcp/agents/codeact00/state.py +66 -0
- universal_mcp/agents/codeact00/tools.py +525 -0
- universal_mcp/agents/codeact00/utils.py +678 -0
- universal_mcp/agents/codeact01/__init__.py +3 -0
- universal_mcp/agents/{codeact → codeact01}/__main__.py +4 -11
- universal_mcp/agents/codeact01/agent.py +413 -0
- universal_mcp/agents/codeact01/config.py +77 -0
- universal_mcp/agents/codeact01/langgraph_agent.py +14 -0
- universal_mcp/agents/codeact01/llm_tool.py +25 -0
- universal_mcp/agents/codeact01/prompts.py +246 -0
- universal_mcp/agents/codeact01/sandbox.py +162 -0
- universal_mcp/agents/{unified → codeact01}/state.py +26 -10
- universal_mcp/agents/codeact01/tools.py +648 -0
- universal_mcp/agents/{unified → codeact01}/utils.py +175 -11
- universal_mcp/agents/llm.py +14 -4
- universal_mcp/agents/react.py +3 -3
- universal_mcp/agents/sandbox.py +124 -69
- universal_mcp/applications/llm/app.py +76 -24
- {universal_mcp_agents-0.1.19rc1.dist-info → universal_mcp_agents-0.1.24rc3.dist-info}/METADATA +6 -5
- universal_mcp_agents-0.1.24rc3.dist-info/RECORD +66 -0
- universal_mcp/agents/codeact/__init__.py +0 -3
- universal_mcp/agents/codeact/agent.py +0 -240
- universal_mcp/agents/codeact/models.py +0 -11
- universal_mcp/agents/codeact/prompts.py +0 -82
- universal_mcp/agents/codeact/sandbox.py +0 -85
- universal_mcp/agents/codeact/state.py +0 -11
- universal_mcp/agents/codeact/utils.py +0 -68
- universal_mcp/agents/codeact0/playbook_agent.py +0 -355
- universal_mcp/agents/unified/README.md +0 -45
- universal_mcp/agents/unified/__init__.py +0 -3
- universal_mcp/agents/unified/agent.py +0 -289
- universal_mcp/agents/unified/prompts.py +0 -192
- universal_mcp/agents/unified/tools.py +0 -188
- universal_mcp_agents-0.1.19rc1.dist-info/RECORD +0 -64
- {universal_mcp_agents-0.1.19rc1.dist-info → universal_mcp_agents-0.1.24rc3.dist-info}/WHEEL +0 -0
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
from dataclasses import dataclass
|
|
3
|
-
from typing import Any, Literal, cast
|
|
1
|
+
from typing import Any
|
|
4
2
|
|
|
5
|
-
from
|
|
6
|
-
from langchain_openai import AzureChatOpenAI
|
|
7
|
-
|
|
8
|
-
from universal_mcp.agents.codeact0.utils import get_message_text, light_copy
|
|
3
|
+
from universal_mcp.agents.codeact0.utils import light_copy
|
|
9
4
|
|
|
10
5
|
MAX_RETRIES = 3
|
|
11
6
|
|
|
@@ -28,250 +23,3 @@ def smart_print(data: Any) -> None:
|
|
|
28
23
|
data: Either a dictionary with string keys, or a list of such dictionaries
|
|
29
24
|
"""
|
|
30
25
|
print(light_copy(data)) # noqa: T201
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def creative_writer(
|
|
34
|
-
task: str,
|
|
35
|
-
context: Any | list[Any] | dict[str, Any],
|
|
36
|
-
tone: str = "normal",
|
|
37
|
-
format: Literal["markdown", "html", "plain"] = "markdown",
|
|
38
|
-
length: Literal["very-short", "concise", "normal", "long"] = "concise",
|
|
39
|
-
) -> str:
|
|
40
|
-
"""
|
|
41
|
-
Given a high-level writing task and context, returns a well-written text
|
|
42
|
-
that achieves the task, given the context.
|
|
43
|
-
|
|
44
|
-
Example Call:
|
|
45
|
-
creative_writer("Summarize this website with the goal of making it easy to understand.", web_content)
|
|
46
|
-
creative_writer("Make a markdown table summarizing the key differences between doc_1 and doc_2.", {"doc_1": str(doc_1), "doc_2": str(doc_2)})
|
|
47
|
-
creative_writer("Summarize all the provided documents.", [doc_1, doc_2, doc_3])
|
|
48
|
-
|
|
49
|
-
Important:
|
|
50
|
-
- Include specifics of the goal in the context verbatim.
|
|
51
|
-
- Be precise and direct in the task, and include as much context as possible.
|
|
52
|
-
- Include relevant high-level goals or intent in the task.
|
|
53
|
-
- You can provide multiple documents as input, and reference them in the task.
|
|
54
|
-
- You MUST provide the contents of any source documents to `creative_writer`.
|
|
55
|
-
- NEVER use `creative_writer` to produce JSON for a Pydantic model.
|
|
56
|
-
|
|
57
|
-
Args:
|
|
58
|
-
task: The main writing task or directive.
|
|
59
|
-
context: A single string, list of strings, or dict mapping labels to content.
|
|
60
|
-
tone: The desired tone of the output (e.g., "normal", "flirty", "formal", "casual", "crisp", "poetic", "technical", "internet-chat", "smartass", etc.).
|
|
61
|
-
format: Output format ('markdown', 'html', 'plain-text').
|
|
62
|
-
length: Desired length of the output ('very-short', 'concise', 'normal', 'long').
|
|
63
|
-
|
|
64
|
-
Returns:
|
|
65
|
-
str: The generated text output.
|
|
66
|
-
"""
|
|
67
|
-
|
|
68
|
-
context = get_context_str(context)
|
|
69
|
-
|
|
70
|
-
task = task.strip() + "\n\n"
|
|
71
|
-
if format == "markdown":
|
|
72
|
-
task += "Please write in Markdown format.\n\n"
|
|
73
|
-
elif format == "html":
|
|
74
|
-
task += "Please write in HTML format.\n\n"
|
|
75
|
-
else:
|
|
76
|
-
task += "Please write in plain text format. Don't use markdown or HTML.\n\n"
|
|
77
|
-
|
|
78
|
-
if tone not in ["normal", "default", ""]:
|
|
79
|
-
task = f"{task} (Tone instructions: {tone})"
|
|
80
|
-
|
|
81
|
-
if length not in ["normal", "default", ""]:
|
|
82
|
-
task = f"{task} (Length instructions: {length})"
|
|
83
|
-
|
|
84
|
-
prompt = f"{task}\n\nContext:\n{context}\n\n"
|
|
85
|
-
|
|
86
|
-
model = AzureChatOpenAI(model="gpt-4o", temperature=0.7)
|
|
87
|
-
|
|
88
|
-
response = model.with_retry(stop_after_attempt=MAX_RETRIES).invoke(prompt)
|
|
89
|
-
return get_message_text(response)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def ai_classify(
|
|
93
|
-
classification_task_and_requirements: str,
|
|
94
|
-
context: Any | list[Any] | dict[str, Any],
|
|
95
|
-
class_descriptions: dict[str, str],
|
|
96
|
-
) -> dict[str, Any]:
|
|
97
|
-
"""
|
|
98
|
-
Classifies and compares data based on given requirements.
|
|
99
|
-
|
|
100
|
-
Use `ai_classify` for tasks which need to classify data into one of many categories.
|
|
101
|
-
If making multiple binary classifications, call `ai_classify` for each.
|
|
102
|
-
|
|
103
|
-
Guidance:
|
|
104
|
-
- Prefer to use ai_classify operations to compare strings, rather than string ops.
|
|
105
|
-
- Prefer to include an "Unsure" category for classification tasks.
|
|
106
|
-
- The `class_descriptions` dict argument MUST be a map from possible class names to a precise description.
|
|
107
|
-
- Use precise and specific class names and concise descriptions.
|
|
108
|
-
- Pass ALL relevant context, preferably as a dict mapping labels to content.
|
|
109
|
-
- Returned dict maps each possible class name to a probability.
|
|
110
|
-
|
|
111
|
-
Example Usage:
|
|
112
|
-
classification_task_and_requirements = "Does the document contain an address?"
|
|
113
|
-
class_descriptions = {
|
|
114
|
-
"Is_Address": "Valid addresses usually have street names, city, and zip codes.",
|
|
115
|
-
"Not_Address": "Not valid addresses."
|
|
116
|
-
}
|
|
117
|
-
classification = ai_classify(
|
|
118
|
-
classification_task_and_requirements,
|
|
119
|
-
{"address": extracted_address},
|
|
120
|
-
class_descriptions
|
|
121
|
-
)
|
|
122
|
-
if classification["probabilities"]["Is_Address"] > 0.5:
|
|
123
|
-
...
|
|
124
|
-
|
|
125
|
-
Args:
|
|
126
|
-
classification_task_and_requirements: The classification question and rules.
|
|
127
|
-
context: The data to classify (string, list, or dict).
|
|
128
|
-
class_descriptions: Mapping from class names to descriptions.
|
|
129
|
-
|
|
130
|
-
Returns:
|
|
131
|
-
dict: {
|
|
132
|
-
probabilities: dict[str, float],
|
|
133
|
-
reason: str,
|
|
134
|
-
top_class: str,
|
|
135
|
-
}
|
|
136
|
-
"""
|
|
137
|
-
|
|
138
|
-
context = get_context_str(context)
|
|
139
|
-
|
|
140
|
-
prompt = (
|
|
141
|
-
f"{classification_task_and_requirements}\n\n"
|
|
142
|
-
f"\nThis is classification task\nPossible classes and descriptions:\n"
|
|
143
|
-
f"{json.dumps(class_descriptions, indent=2)}\n"
|
|
144
|
-
f"\nContext:\n{context}\n\n"
|
|
145
|
-
"Return ONLY a valid JSON object, no extra text."
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
model = init_chat_model(model="claude-4-sonnet-20250514", temperature=0)
|
|
149
|
-
|
|
150
|
-
@dataclass
|
|
151
|
-
class ClassificationResult:
|
|
152
|
-
probabilities: dict[str, float]
|
|
153
|
-
reason: str
|
|
154
|
-
top_class: str
|
|
155
|
-
|
|
156
|
-
response = (
|
|
157
|
-
model.with_structured_output(schema=ClassificationResult, method="json_mode")
|
|
158
|
-
.with_retry(stop_after_attempt=MAX_RETRIES)
|
|
159
|
-
.invoke(prompt)
|
|
160
|
-
)
|
|
161
|
-
return cast(dict[str, Any], response)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
def call_llm(
|
|
165
|
-
task_instructions: str, context: Any | list[Any] | dict[str, Any], output_json_schema: dict[str, Any]
|
|
166
|
-
) -> dict[str, Any]:
|
|
167
|
-
"""
|
|
168
|
-
Call a Large Language Model (LLM) with an instruction and contextual information,
|
|
169
|
-
returning a dictionary matching the given output_json_schema.
|
|
170
|
-
Can be used for tasks like creative writing, llm reasoning based content generation, etc.
|
|
171
|
-
|
|
172
|
-
You MUST anticipate Exceptions in reasoning based tasks which will lead to some empty fields
|
|
173
|
-
in the returned output; skip this item if applicable.
|
|
174
|
-
|
|
175
|
-
General Guidelines:
|
|
176
|
-
- Be comprehensive, specific, and precise on the task instructions.
|
|
177
|
-
- Include as much context as possible.
|
|
178
|
-
- You can provide multiple items in context, and reference them in the task.
|
|
179
|
-
- Include relevant high-level goals or intent in the task.
|
|
180
|
-
- In the output_json_schema, use required field wherever necessary.
|
|
181
|
-
- The more specific your task instructions and output_json_schema are, the better the results.
|
|
182
|
-
|
|
183
|
-
Guidelines for content generation tasks:
|
|
184
|
-
- Feel free to add instructions for tone, length, and format (markdown, html, plain-text, xml)
|
|
185
|
-
- Some examples of tone are: "normal", "flirty", "formal", "casual", "crisp", "poetic", "technical", "internet-chat", "smartass", etc.
|
|
186
|
-
- Prefer length to be concise by default. Other examples are: "very-short", "concise", "normal", "long", "2-3 lines", etc.
|
|
187
|
-
- In format prefer plain-text but you can also use markdown and html wherever useful.
|
|
188
|
-
|
|
189
|
-
Args:
|
|
190
|
-
instruction: The main directive for the LLM (e.g., "Summarize the article" or "Extract key entities").
|
|
191
|
-
context:
|
|
192
|
-
A dictionary containing named text elements that provide additional
|
|
193
|
-
information for the LLM. Keys are labels (e.g., 'article', 'transcript'),
|
|
194
|
-
values are strings of content.
|
|
195
|
-
output_json_schema: must be a valid JSON schema with top-level 'title' and 'description' keys.
|
|
196
|
-
|
|
197
|
-
Returns:
|
|
198
|
-
dict: Parsed JSON object matching the desired output_json_schema.
|
|
199
|
-
|
|
200
|
-
"""
|
|
201
|
-
context = get_context_str(context)
|
|
202
|
-
|
|
203
|
-
prompt = f"{task_instructions}\n\nContext:\n{context}\n\nReturn ONLY a valid JSON object, no extra text."
|
|
204
|
-
|
|
205
|
-
model = init_chat_model(model="claude-4-sonnet-20250514", temperature=0)
|
|
206
|
-
|
|
207
|
-
response = (
|
|
208
|
-
model.with_structured_output(schema=output_json_schema, method="json_mode")
|
|
209
|
-
.with_retry(stop_after_attempt=MAX_RETRIES)
|
|
210
|
-
.invoke(prompt)
|
|
211
|
-
)
|
|
212
|
-
return cast(dict[str, Any], response)
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
def data_extractor(
|
|
216
|
-
extraction_task: str, source: Any | list[Any] | dict[str, Any], output_json_schema: dict[str, Any]
|
|
217
|
-
) -> dict[str, Any]:
|
|
218
|
-
"""
|
|
219
|
-
Extracts structured data from unstructured data (documents, webpages, images, large bodies of text),
|
|
220
|
-
returning a dictionary matching the given output_json_schema.
|
|
221
|
-
|
|
222
|
-
You MUST anticipate Exception raised for unextractable data; skip this item if applicable.
|
|
223
|
-
|
|
224
|
-
Strongly prefer to:
|
|
225
|
-
- Be comprehensive, specific, and precise on the data you want to extract.
|
|
226
|
-
- Use optional fields everywhere.
|
|
227
|
-
- Extract multiple items from each source unless otherwise specified.
|
|
228
|
-
- The more specific your extraction task and output_json_schema are, the better the results.
|
|
229
|
-
|
|
230
|
-
Args:
|
|
231
|
-
extraction_task: The directive describing what to extract.
|
|
232
|
-
source: The unstructured data to extract from.
|
|
233
|
-
output_json_schema: must be a valid JSON schema with top-level 'title' and 'description' keys.
|
|
234
|
-
|
|
235
|
-
Returns:
|
|
236
|
-
dict: Parsed JSON object matching the desired output_json_schema.
|
|
237
|
-
|
|
238
|
-
Example:
|
|
239
|
-
news_articles_schema = {
|
|
240
|
-
"title": "NewsArticleList",
|
|
241
|
-
"description": "A list of news articles with headlines and URLs",
|
|
242
|
-
"type": "object",
|
|
243
|
-
"properties": {
|
|
244
|
-
"articles": {
|
|
245
|
-
"type": "array",
|
|
246
|
-
"items": {
|
|
247
|
-
"type": "object",
|
|
248
|
-
"properties": {
|
|
249
|
-
"headline": {
|
|
250
|
-
"type": "string"
|
|
251
|
-
},
|
|
252
|
-
"url": {
|
|
253
|
-
"type": "string"
|
|
254
|
-
}
|
|
255
|
-
},
|
|
256
|
-
"required": ["headline", "url"]
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
},
|
|
260
|
-
"required": ["articles"]
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
news_articles = data_extractor("Extract headlines and their corresponding URLs.", content, news_articles_schema)
|
|
264
|
-
"""
|
|
265
|
-
|
|
266
|
-
context = get_context_str(source)
|
|
267
|
-
|
|
268
|
-
prompt = f"{extraction_task}\n\nContext:\n{context}\n\nReturn ONLY a valid JSON object, no extra text."
|
|
269
|
-
|
|
270
|
-
model = init_chat_model(model="claude-4-sonnet-20250514", temperature=0)
|
|
271
|
-
|
|
272
|
-
response = (
|
|
273
|
-
model.with_structured_output(schema=output_json_schema, method="json_mode")
|
|
274
|
-
.with_retry(stop_after_attempt=MAX_RETRIES)
|
|
275
|
-
.invoke(prompt)
|
|
276
|
-
)
|
|
277
|
-
return cast(dict[str, Any], response)
|