universal-mcp-agents 0.1.23rc10__tar.gz → 0.1.23rc11__tar.gz

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.
Files changed (65) hide show
  1. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/PKG-INFO +3 -3
  2. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/pyproject.toml +3 -3
  3. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/base.py +2 -0
  4. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/cli.py +2 -2
  5. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/codeact0/agent.py +3 -3
  6. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/codeact0/prompts.py +8 -10
  7. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/codeact0/tools.py +3 -2
  8. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/codeact0/utils.py +51 -1
  9. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/llm.py +9 -2
  10. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/applications/llm/app.py +4 -4
  11. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/uv.lock +9 -9
  12. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/.github/workflows/evals.yml +0 -0
  13. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/.github/workflows/lint.yml +0 -0
  14. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/.github/workflows/release-please.yml +0 -0
  15. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/.github/workflows/tests.yml +0 -0
  16. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/.gitignore +0 -0
  17. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/.pre-commit-config.yaml +0 -0
  18. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/GEMINI.md +0 -0
  19. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/PROMPTS.md +0 -0
  20. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/README.md +0 -0
  21. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/bump_and_release.sh +0 -0
  22. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/evals/__init__.py +0 -0
  23. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/evals/dataset.py +0 -0
  24. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/evals/datasets/exact.jsonl +0 -0
  25. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/evals/datasets/tasks.jsonl +0 -0
  26. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/evals/datasets/test.jsonl +0 -0
  27. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/evals/evaluators.py +0 -0
  28. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/evals/prompts.py +0 -0
  29. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/evals/run.py +0 -0
  30. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/evals/utils.py +0 -0
  31. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/tests/test_agents.py +0 -0
  32. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/tests/test_sandbox.py +0 -0
  33. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/__init__.py +0 -0
  34. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/bigtool/__init__.py +0 -0
  35. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/bigtool/__main__.py +0 -0
  36. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/bigtool/agent.py +0 -0
  37. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/bigtool/context.py +0 -0
  38. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/bigtool/graph.py +0 -0
  39. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/bigtool/prompts.py +0 -0
  40. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/bigtool/state.py +0 -0
  41. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/bigtool/tools.py +0 -0
  42. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/builder/__main__.py +0 -0
  43. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/builder/builder.py +0 -0
  44. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/builder/helper.py +0 -0
  45. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/builder/prompts.py +0 -0
  46. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/builder/state.py +0 -0
  47. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/codeact0/__init__.py +0 -0
  48. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/codeact0/__main__.py +0 -0
  49. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/codeact0/config.py +0 -0
  50. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/codeact0/langgraph_agent.py +0 -0
  51. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/codeact0/llm_tool.py +0 -0
  52. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/codeact0/sandbox.py +0 -0
  53. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/codeact0/state.py +0 -0
  54. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/hil.py +0 -0
  55. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/react.py +0 -0
  56. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/sandbox.py +0 -0
  57. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/shared/__main__.py +0 -0
  58. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/shared/prompts.py +0 -0
  59. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/shared/tool_node.py +0 -0
  60. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/simple.py +0 -0
  61. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/agents/utils.py +0 -0
  62. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/applications/filesystem/__init__.py +0 -0
  63. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/applications/filesystem/app.py +0 -0
  64. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/applications/llm/__init__.py +0 -0
  65. {universal_mcp_agents-0.1.23rc10 → universal_mcp_agents-0.1.23rc11}/src/universal_mcp/applications/ui/app.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: universal-mcp-agents
3
- Version: 0.1.23rc10
3
+ Version: 0.1.23rc11
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
@@ -12,8 +12,8 @@ Requires-Dist: langchain-anthropic>=0.3.19
12
12
  Requires-Dist: langchain-google-genai>=2.1.10
13
13
  Requires-Dist: langchain-openai>=0.3.32
14
14
  Requires-Dist: langgraph>=0.6.6
15
- Requires-Dist: universal-mcp-applications>=0.1.25
16
- Requires-Dist: universal-mcp>=0.1.24rc27
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'
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "universal-mcp-agents"
9
- version = "0.1.23-rc10"
9
+ version = "0.1.23-rc11"
10
10
  description = "Add your description here"
11
11
  readme = "README.md"
12
12
  authors = [
@@ -19,8 +19,8 @@ dependencies = [
19
19
  "langchain-google-genai>=2.1.10",
20
20
  "langchain-openai>=0.3.32",
21
21
  "langgraph>=0.6.6",
22
- "universal-mcp>=0.1.24rc27",
23
- "universal-mcp-applications>=0.1.25",
22
+ "universal-mcp>=0.1.24rc29",
23
+ "universal-mcp-applications>=0.1.30",
24
24
  ]
25
25
 
26
26
  [project.license]
@@ -67,6 +67,8 @@ class BaseAgent:
67
67
  ):
68
68
  if event == "messages" and isinstance(meta, (tuple, list)) and len(meta) == 2: # noqa: PLR2004
69
69
  payload, meta_dict = meta
70
+ if meta_dict.get("tags") and "quiet" in meta_dict.get("tags"):
71
+ continue
70
72
  is_agent_builder = (
71
73
  isinstance(meta_dict, dict) and meta_dict.get("langgraph_node") == "agent_builder"
72
74
  )
@@ -18,14 +18,14 @@ app = Typer()
18
18
  mcp client run --config client_config.json
19
19
  """,
20
20
  )
21
- def run(name: str = "react"):
21
+ def run(name: str = "codeact-repl"):
22
22
  """Run the agent CLI"""
23
23
 
24
24
  setup_logger(log_file=None, level="ERROR")
25
25
  client = AgentrClient()
26
26
  params = {
27
27
  "instructions": "You are a helpful assistant",
28
- "model": "azure/gpt-4.1",
28
+ "model": "anthropic:claude-4-sonnet-20250514",
29
29
  "registry": AgentrRegistry(client=client),
30
30
  "memory": MemorySaver(),
31
31
  }
@@ -27,7 +27,7 @@ from universal_mcp.agents.codeact0.tools import (
27
27
  create_meta_tools,
28
28
  enter_agent_builder_mode,
29
29
  )
30
- from universal_mcp.agents.codeact0.utils import build_anthropic_cache_message, get_connected_apps_string
30
+ from universal_mcp.agents.codeact0.utils import build_anthropic_cache_message, get_connected_apps_string, strip_thinking
31
31
  from universal_mcp.agents.llm import load_chat_model
32
32
  from universal_mcp.agents.utils import convert_tool_ids_to_dict, filter_retry_on, get_message_text
33
33
 
@@ -52,7 +52,7 @@ class CodeActPlaybookAgent(BaseAgent):
52
52
  **kwargs,
53
53
  )
54
54
  self.model_instance = load_chat_model(model)
55
- self.agent_builder_model_instance = load_chat_model("anthropic:claude-sonnet-4-5-20250929")
55
+ self.agent_builder_model_instance = load_chat_model("anthropic:claude-sonnet-4-5-20250929", thinking = False)
56
56
  self.registry = registry
57
57
  self.agent_builder_registry = agent_builder_registry
58
58
  self.agent = agent_builder_registry.get_agent() if agent_builder_registry else None
@@ -217,7 +217,7 @@ class CodeActPlaybookAgent(BaseAgent):
217
217
  plan_id = str(uuid.uuid4())
218
218
  writer({"type": "custom", id: plan_id, "name": "planning", "data": {"update": bool(self.agent)}})
219
219
  planning_instructions = self.instructions + AGENT_BUILDER_PLANNING_PROMPT + self.preloaded_defs
220
- messages = [{"role": "system", "content": planning_instructions}] + state["messages"]
220
+ messages = [{"role": "system", "content": planning_instructions}] + strip_thinking(state["messages"])
221
221
 
222
222
  model_with_structured_output = self.agent_builder_model_instance.with_structured_output(
223
223
  AgentBuilderPlan
@@ -6,13 +6,13 @@ uneditable_prompt = """
6
6
  You are **Ruzo**, an AI Assistant created by AgentR — a creative, straight-forward, and direct principal software engineer with access to tools.
7
7
 
8
8
  Your job is to answer the user's question or perform the task they ask for.
9
- - Answer simple questions (which do not require you to write any code or access any external resources) directly. Note that any operation that involves using ONLY print functions should be answered directly in the chat. NEVER write a string yourself and print it.
9
+ - Answer simple questions (which do not require you to write any code or access any external resources) directly. Note that any operation that involves using ONLY print functions should be answered directly in the chat. NEVER write a string or sequences of strings yourself and print it.
10
10
  - For task requiring operations or access to external resources, you should achieve the task by executing Python code snippets.
11
11
  - You have access to `execute_ipython_cell` tool that allows you to execute Python code in an IPython notebook cell.
12
+ - For writing, text/document generation (like HTML/markdown document generation) or language processing tasks DO NOT answer directly. Instead you MUST use `execute_ipython_cell` tool with the llm functions provided to you for tasks like summarizing, text generation, classification, data extraction from text or unstructured data, etc. Avoid hardcoded approaches to classification, data extraction, or creative writing.
12
13
  - You also have access to two tools for finding and loading more python functions- `search_functions` and `load_functions`, which you must use for finding functions for using different external applications or additional functionality.
13
14
  - Prioritize connected applications over unconnected ones from the output of `search_functions`. However, if the user specifically asks for an application, you MUST use that irrespective of connection status.
14
15
  - When multiple apps are connected, or none of the apps are connected, YOU MUST ask the user to choose the application(s). The search results will inform you when such a case occurs, and you must stop and ask the user if multiple apps are relevant.
15
- - In writing or natural language processing tasks DO NOT answer directly. Instead use `execute_ipython_cell` tool with the AI functions provided to you for tasks like summarizing, text generation, classification, data extraction from text or unstructured data, etc. Avoid hardcoded approaches to classification, data extraction, or creative writing.
16
16
  - The code you write will be executed in a sandbox environment, and you can use the output of previous executions in your code. variables, functions, imports are retained.
17
17
  - Read and understand the output of the previous code snippet and use it to answer the user's request. Note that the code output is NOT visible to the user, so after the task is complete, you have to give the output to the user in a markdown format. Similarly, you should only use print/smart_print for your own analysis, the user does not get the output.
18
18
  - If needed, feel free to ask for more information from the user (without using the `execute_ipython_cell` tool) to clarify the task.
@@ -21,14 +21,14 @@ Your job is to answer the user's question or perform the task they ask for.
21
21
  - The code you write will be executed in a sandbox environment, and you can use the output of previous executions in your code. Variables, functions, imports are retained.
22
22
  - Read and understand the output of the previous code snippet and use it to answer the user's request. Note that the code output is NOT visible to the user, so after the task is complete, you have to give the output to the user in a markdown format. Similarly, you should only use print/smart_print for your own analysis, the user does not get the output.
23
23
  - If needed, feel free to ask for more information from the user (without using the `execute_ipython_cell` tool) to clarify the task.
24
- - Always describe in 2-3 lines about the current progress. In each step, mention what has been achieved and what you are planning to do next.
25
- - DO NOT use the code execution to communicate with the user. The user is not able to see the output of the code cells.
24
+ - DO NOT use the code execution to communicate/show anything to the user. The user is not able to see the output of the code cells, it is only for your processing and actions.
25
+ - Whenever you need to generate a large body of text, such as a document, an HTML file, or a report, use llm functions and save the output file using save functions. Do not generate text yourself and do not print the entire text in order to save your memory.
26
26
 
27
27
  **Coding Best Practices:**
28
- - Variables defined at the top level of previous code snippets can be referenced in your code.
28
+ - Structure your code into multiple small, well-defined functions within a single execution snippet. This ensures modularity and makes it easier to debug or update specific logic without rewriting or re-executing large portions of code. You can only rewrite the function/portion that you need to edit since the others are retained in context.
29
+ - Variables, functions, classes defined at the top level of previous code snippets can be referenced in your code.
29
30
  - External functions which return a dict or list[dict] are ambiguous. Therefore, you MUST explore the structure of the returned data using `smart_print()` statements before using it, printing keys and values. `smart_print` truncates long strings from data, preventing huge output logs.
30
31
  - When an operation involves running a fixed set of steps on a list of items, run one run correctly and then use a for loop to run the steps on each item in the list.
31
- - In a single code snippet, try to achieve as much as possible.
32
32
  - You can only import libraries that come pre-installed with Python. However, do consider searching for external functions first, using the search and load tools to access them in the code.
33
33
  - For displaying final results to the user, you must present your output in markdown format, including image links, so that they are rendered and displayed to the user. The code output is NOT visible to the user.
34
34
  - Call all functions using keyword arguments only, never positional arguments.
@@ -39,7 +39,7 @@ Your job is to answer the user's question or perform the task they ask for.
39
39
  - Anything that's just formatted print statements
40
40
 
41
41
  **Final Output Requirements:**
42
- - Once you have all the information about the task, return the text directly to user in markdown format. Do NOT call `execute_ipython_cell` again just for summarization.
42
+ - Once you have all the information about the task, return the text directly to user in markdown format. Do NOT call `execute_ipython_cell` or any LLM tools again just for summarization. Do NOT use llm__generate_text for this purpose.
43
43
  - Always respond in github flavoured markdown format.
44
44
  - For charts and diagrams, use mermaid chart in markdown directly.
45
45
  - Your final response should contain the complete answer to the user's request in a clear, well-formatted manner that directly addresses what they asked for.
@@ -209,9 +209,7 @@ def create_default_prompt(
209
209
  system_prompt = uneditable_prompt.strip()
210
210
  if apps_string:
211
211
  system_prompt += f"\n\n**Connected external applications (These apps have been logged into by the user):**\n{apps_string}\n\n Use `search_functions` to search for functions you can perform using the above. You can also discover more applications using the `search_functions` tool to find additional tools and integrations, if required. However, you MUST not assume the application when multiple apps are connected for a particular usecase.\n"
212
- system_prompt += (
213
- "\n\nIn addition to the Python Standard Library, you can use the following external functions:\n"
214
- )
212
+ system_prompt += "\n\nIn addition to the Python Standard Library, you can use the following external functions:\n Carefully note which functions are normal and which functions are async. CRITICAL: Use `await` with async functions and async functions ONLY."
215
213
  else:
216
214
  system_prompt = ""
217
215
 
@@ -320,7 +320,8 @@ def create_meta_tools(tool_registry: AgentrRegistry) -> dict[str, Any]:
320
320
  valid_tools, unconnected_links = await get_valid_tools(tool_ids=tool_ids, registry=tool_registry)
321
321
 
322
322
  if not valid_tools:
323
- return "Error: None of the provided tool IDs could be validated or loaded."
323
+ response_string = "Error: None of the provided tool IDs could be validated or loaded."
324
+ return response_string, {}, [], ""
324
325
 
325
326
  # Step 2: Export the schemas of the valid tools.
326
327
  await tool_registry.load_tools(valid_tools)
@@ -502,7 +503,7 @@ async def get_valid_tools(tool_ids: list[str], registry: AgentrRegistry) -> tupl
502
503
  start = text.find(":") + 1
503
504
  end = text.find(". R", start)
504
505
  url = text[start:end].strip()
505
- markdown_link = f"[{app}]({url})"
506
+ markdown_link = f"![Connect to {app.capitalize()}]({url})"
506
507
  unconnected_links.append(markdown_link)
507
508
  for tool_id, tool_name in tool_entries:
508
509
  if tool_name in available:
@@ -4,7 +4,7 @@ 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
@@ -29,6 +29,56 @@ def build_anthropic_cache_message(text: str, role: str = "system", ttl: str = "1
29
29
  }
30
30
  ]
31
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
+
32
82
 
33
83
  def add_tools(tool_config: ToolConfig, tools_to_add: ToolConfig):
34
84
  for app_id, new_tools in tools_to_add.items():
@@ -9,22 +9,28 @@ from loguru import logger
9
9
 
10
10
  @lru_cache(maxsize=8)
11
11
  def load_chat_model(
12
- fully_specified_name: str, temperature: float = 1.0, tags: list[str] | None = None, thinking: bool = True
12
+ fully_specified_name: str, temperature: float = 1.0, tags: tuple[str, ...] | None = None, thinking: bool = True, disable_streaming: bool = False
13
13
  ) -> BaseChatModel:
14
14
  """Load a chat model from a fully specified name.
15
15
  Args:
16
16
  fully_specified_name (str): String in the format 'provider/model'.
17
17
  """
18
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)
19
24
  provider, model = fully_specified_name.split(":", maxsplit=1)
20
25
  if provider == "anthropic":
21
26
  return ChatAnthropic(
22
27
  model=model,
23
28
  temperature=temperature,
24
29
  thinking={"type": "enabled", "budget_tokens": 2048} if thinking else None,
25
- max_tokens=4096,
30
+ max_tokens=8096,
26
31
  tags=tags,
27
32
  stream_usage=True,
33
+ disable_streaming = disable_streaming
28
34
  ) # pyright: ignore[reportCallIssue]
29
35
  elif provider == "azure":
30
36
  return AzureChatOpenAI(
@@ -34,6 +40,7 @@ def load_chat_model(
34
40
  temperature=temperature,
35
41
  tags=tags,
36
42
  stream_usage=True,
43
+ disable_streaming = disable_streaming
37
44
  )
38
45
  elif provider == "gemini":
39
46
  return ChatGoogleGenerativeAI(model=model, temperature=temperature)
@@ -91,7 +91,7 @@ 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")
94
+ model = load_chat_model("azure/gpt-5-mini", disable_streaming = True, tags=("quiet",))
95
95
  response = model.with_retry(stop_after_attempt=MAX_RETRIES).invoke(full_prompt, stream=False)
96
96
  return str(response.content)
97
97
 
@@ -158,7 +158,7 @@ class LlmApp(BaseApplication):
158
158
  reason: str = Field(..., description="The reasoning behind the classification.")
159
159
  top_class: str = Field(..., description="The class with the highest probability.")
160
160
 
161
- model = load_chat_model("azure/gpt-5-mini", temperature=0)
161
+ model = load_chat_model("azure/gpt-5-mini", temperature=0, disable_streaming = True, tags=("quiet",))
162
162
  agent = create_agent(
163
163
  model=model,
164
164
  tools=[],
@@ -229,7 +229,7 @@ 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 = load_chat_model("azure/gpt-5-mini", temperature=0)
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")
@@ -282,7 +282,7 @@ 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 = load_chat_model("azure/gpt-5-mini", temperature=0)
285
+ model = load_chat_model("azure/gpt-5-mini", temperature=0, disable_streaming = True, tags=("quiet",))
286
286
 
287
287
  agent = create_agent(
288
288
  model=model,
@@ -4865,7 +4865,7 @@ wheels = [
4865
4865
 
4866
4866
  [[package]]
4867
4867
  name = "universal-mcp"
4868
- version = "0.1.24rc28"
4868
+ version = "0.1.24rc29"
4869
4869
  source = { registry = "https://pypi.org/simple" }
4870
4870
  dependencies = [
4871
4871
  { name = "agentevals" },
@@ -4895,14 +4895,14 @@ dependencies = [
4895
4895
  { name = "streamlit" },
4896
4896
  { name = "typer" },
4897
4897
  ]
4898
- sdist = { url = "https://files.pythonhosted.org/packages/36/90/4b245ba69d5ec1d489dfd157089982d0bc31bdb68b2499b2b7b6dc9be0c2/universal_mcp-0.1.24rc28.tar.gz", hash = "sha256:fb02abe5619cc5634be754bd47a6d71870825065874568172d28facb6a82b43b", size = 116749, upload-time = "2025-10-22T08:24:17.062Z" }
4898
+ sdist = { url = "https://files.pythonhosted.org/packages/f2/11/68b20ba072217f6197d320e095cadf501c645c534c5903765df23abd35f9/universal_mcp-0.1.24rc29.tar.gz", hash = "sha256:151507659ab13561f5a1b228de9d90e91951894bda8ca065aab632a9bf44fb57", size = 116887, upload-time = "2025-10-27T14:28:10.268Z" }
4899
4899
  wheels = [
4900
- { url = "https://files.pythonhosted.org/packages/6c/25/e75fa129f4164efd7c3ae115980afd3279409bf8bf49e7f2493f9f930f58/universal_mcp-0.1.24rc28-py3-none-any.whl", hash = "sha256:840b3086f378a5e1882f58b8a30a83b11861246bf9965808d7e667ab817ca4ff", size = 133252, upload-time = "2025-10-22T08:24:14.81Z" },
4900
+ { url = "https://files.pythonhosted.org/packages/d2/6b/0c97e0ddcfea5ce9e88e6e243ed358bf1fff6f1bafa8c4997ae5cb902621/universal_mcp-0.1.24rc29-py3-none-any.whl", hash = "sha256:8759cdb5b79937ab61109054578c223fa8890c9bb16bc17a9692bea883ebc90f", size = 133382, upload-time = "2025-10-27T14:28:08.284Z" },
4901
4901
  ]
4902
4902
 
4903
4903
  [[package]]
4904
4904
  name = "universal-mcp-agents"
4905
- version = "0.1.23rc9"
4905
+ version = "0.1.23rc10"
4906
4906
  source = { editable = "." }
4907
4907
  dependencies = [
4908
4908
  { name = "cloudpickle" },
@@ -4939,14 +4939,14 @@ requires-dist = [
4939
4939
  { name = "pytest-cov", marker = "extra == 'test'" },
4940
4940
  { name = "ruff", marker = "extra == 'dev'" },
4941
4941
  { name = "typer", marker = "extra == 'dev'", specifier = ">=0.17.4" },
4942
- { name = "universal-mcp", specifier = ">=0.1.24rc27" },
4943
- { name = "universal-mcp-applications", specifier = ">=0.1.25" },
4942
+ { name = "universal-mcp", specifier = ">=0.1.24rc29" },
4943
+ { name = "universal-mcp-applications", specifier = ">=0.1.30" },
4944
4944
  ]
4945
4945
  provides-extras = ["test", "dev"]
4946
4946
 
4947
4947
  [[package]]
4948
4948
  name = "universal-mcp-applications"
4949
- version = "0.1.29"
4949
+ version = "0.1.30"
4950
4950
  source = { registry = "https://pypi.org/simple" }
4951
4951
  dependencies = [
4952
4952
  { name = "boto3" },
@@ -4975,9 +4975,9 @@ dependencies = [
4975
4975
  { name = "yfinance" },
4976
4976
  { name = "youtube-transcript-api" },
4977
4977
  ]
4978
- sdist = { url = "https://files.pythonhosted.org/packages/42/27/5e1880bf6c7f708c81d2bb3f4195c22b0addb1992f018bc22f5803df76b0/universal_mcp_applications-0.1.29.tar.gz", hash = "sha256:4dd2e03432d5ea5a09a47f7ea6d9af6b5d4a181f409cfccd80642e2d3263a54f", size = 1688583, upload-time = "2025-10-24T19:26:30.202Z" }
4978
+ sdist = { url = "https://files.pythonhosted.org/packages/81/9a/069b94d61d51282d7382633535a89fa6e054fc55a728fdf9b431087225cd/universal_mcp_applications-0.1.30.tar.gz", hash = "sha256:4ed5b0a296ca02e2d29eb7b85066801daf490d504ed2e9ec9829e07499686184", size = 1685544, upload-time = "2025-10-28T00:05:23.517Z" }
4979
4979
  wheels = [
4980
- { url = "https://files.pythonhosted.org/packages/fe/78/f080f3ee1af745d5da287577877dfd3eb7031a757886342567bd7a6e0d70/universal_mcp_applications-0.1.29-py3-none-any.whl", hash = "sha256:5e285c4ee796f15e72f88f3bf858c9df805bd7af4798929a2551b99a1094cdb6", size = 1546271, upload-time = "2025-10-24T19:26:27.994Z" },
4980
+ { url = "https://files.pythonhosted.org/packages/d7/29/900d2e9432e3c6b3b78000c338cd10d81c76d4bfa235406418bb77c02d5d/universal_mcp_applications-0.1.30-py3-none-any.whl", hash = "sha256:4d7708ac51747bced632be40b4da0b58ea23ddfd837af7c6706d72a1f6e0ad83", size = 1541794, upload-time = "2025-10-28T00:05:20.651Z" },
4981
4981
  ]
4982
4982
 
4983
4983
  [[package]]