universal-mcp-agents 0.1.11__py3-none-any.whl → 0.1.12__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.
Files changed (65) hide show
  1. universal_mcp/agents/__init__.py +17 -19
  2. universal_mcp/agents/base.py +10 -7
  3. universal_mcp/agents/{bigtoolcache → bigtool}/__init__.py +2 -2
  4. universal_mcp/agents/{bigtoolcache → bigtool}/__main__.py +0 -1
  5. universal_mcp/agents/{bigtoolcache → bigtool}/agent.py +0 -1
  6. universal_mcp/agents/{bigtoolcache → bigtool}/graph.py +6 -5
  7. universal_mcp/agents/builder/__main__.py +125 -0
  8. universal_mcp/agents/builder/builder.py +225 -0
  9. universal_mcp/agents/builder/prompts.py +173 -0
  10. universal_mcp/agents/builder/state.py +24 -0
  11. universal_mcp/agents/cli.py +3 -2
  12. universal_mcp/agents/codeact/__main__.py +2 -4
  13. universal_mcp/agents/codeact/agent.py +165 -63
  14. universal_mcp/agents/codeact/models.py +11 -0
  15. universal_mcp/agents/codeact/prompts.py +12 -12
  16. universal_mcp/agents/codeact/sandbox.py +73 -23
  17. universal_mcp/agents/codeact/state.py +2 -0
  18. universal_mcp/agents/codeact0/__init__.py +3 -0
  19. universal_mcp/agents/codeact0/__main__.py +35 -0
  20. universal_mcp/agents/codeact0/agent.py +136 -0
  21. universal_mcp/agents/codeact0/config.py +77 -0
  22. universal_mcp/agents/codeact0/langgraph_graph.py +17 -0
  23. universal_mcp/agents/codeact0/legacy_codeact.py +104 -0
  24. universal_mcp/agents/codeact0/llm_tool.py +379 -0
  25. universal_mcp/agents/codeact0/prompts.py +156 -0
  26. universal_mcp/agents/codeact0/sandbox.py +90 -0
  27. universal_mcp/agents/codeact0/state.py +12 -0
  28. universal_mcp/agents/codeact0/usecases/1-unsubscribe.yaml +4 -0
  29. universal_mcp/agents/codeact0/usecases/10-reddit2.yaml +10 -0
  30. universal_mcp/agents/codeact0/usecases/11-github.yaml +13 -0
  31. universal_mcp/agents/codeact0/usecases/2-reddit.yaml +27 -0
  32. universal_mcp/agents/codeact0/usecases/2.1-instructions.md +81 -0
  33. universal_mcp/agents/codeact0/usecases/2.2-instructions.md +71 -0
  34. universal_mcp/agents/codeact0/usecases/3-earnings.yaml +4 -0
  35. universal_mcp/agents/codeact0/usecases/4-maps.yaml +41 -0
  36. universal_mcp/agents/codeact0/usecases/5-gmailreply.yaml +8 -0
  37. universal_mcp/agents/codeact0/usecases/6-contract.yaml +6 -0
  38. universal_mcp/agents/codeact0/usecases/7-overnight.yaml +14 -0
  39. universal_mcp/agents/codeact0/usecases/8-sheets_chart.yaml +25 -0
  40. universal_mcp/agents/codeact0/usecases/9-learning.yaml +9 -0
  41. universal_mcp/agents/codeact0/utils.py +374 -0
  42. universal_mcp/agents/hil.py +4 -4
  43. universal_mcp/agents/planner/__init__.py +7 -1
  44. universal_mcp/agents/react.py +11 -3
  45. universal_mcp/agents/simple.py +12 -2
  46. universal_mcp/agents/utils.py +17 -0
  47. universal_mcp/applications/llm/__init__.py +3 -0
  48. universal_mcp/applications/llm/app.py +158 -0
  49. universal_mcp/applications/ui/app.py +118 -144
  50. {universal_mcp_agents-0.1.11.dist-info → universal_mcp_agents-0.1.12.dist-info}/METADATA +1 -1
  51. universal_mcp_agents-0.1.12.dist-info/RECORD +65 -0
  52. universal_mcp/agents/bigtool2/__init__.py +0 -67
  53. universal_mcp/agents/bigtool2/__main__.py +0 -23
  54. universal_mcp/agents/bigtool2/agent.py +0 -13
  55. universal_mcp/agents/bigtool2/graph.py +0 -155
  56. universal_mcp/agents/bigtool2/meta_tools.py +0 -120
  57. universal_mcp/agents/bigtool2/prompts.py +0 -15
  58. universal_mcp/agents/bigtoolcache/state.py +0 -27
  59. universal_mcp/agents/builder.py +0 -204
  60. universal_mcp_agents-0.1.11.dist-info/RECORD +0 -42
  61. /universal_mcp/agents/{bigtoolcache → bigtool}/context.py +0 -0
  62. /universal_mcp/agents/{bigtoolcache → bigtool}/prompts.py +0 -0
  63. /universal_mcp/agents/{bigtool2 → bigtool}/state.py +0 -0
  64. /universal_mcp/agents/{bigtoolcache → bigtool}/tools.py +0 -0
  65. {universal_mcp_agents-0.1.11.dist-info → universal_mcp_agents-0.1.12.dist-info}/WHEEL +0 -0
@@ -1,39 +1,89 @@
1
1
  import asyncio
2
- import builtins
3
2
  import contextlib
4
3
  import io
4
+ from collections.abc import Callable
5
5
  from typing import Any
6
6
 
7
7
  from loguru import logger
8
8
 
9
+ from .models import SandboxOutput
9
10
 
10
- async def eval_unsafe(code: str, _locals: dict[str, Any], timeout: int = 10) -> tuple[str, dict[str, Any]]:
11
+ # Define a whitelist of safe built-in functions
12
+ SAFE_BUILTINS = {
13
+ "abs": abs,
14
+ "all": all,
15
+ "any": any,
16
+ "bool": bool,
17
+ "callable": callable,
18
+ "chr": chr,
19
+ "dict": dict,
20
+ "divmod": divmod,
21
+ "enumerate": enumerate,
22
+ "filter": filter,
23
+ "float": float,
24
+ "getattr": getattr,
25
+ "hasattr": hasattr,
26
+ "hash": hash,
27
+ "id": id,
28
+ "int": int,
29
+ "isinstance": isinstance,
30
+ "iter": iter,
31
+ "len": len,
32
+ "list": list,
33
+ "max": max,
34
+ "min": min,
35
+ "next": next,
36
+ "ord": ord,
37
+ "pow": pow,
38
+ "print": print,
39
+ "range": range,
40
+ "repr": repr,
41
+ "reversed": reversed,
42
+ "round": round,
43
+ "set": set,
44
+ "slice": slice,
45
+ "sorted": sorted,
46
+ "str": str,
47
+ "sum": sum,
48
+ "tuple": tuple,
49
+ "type": type,
50
+ "zip": zip,
51
+ }
52
+
53
+
54
+ # (The SAFE_BUILTINS definition remains the same)
55
+ # ...
56
+
57
+
58
+ async def eval_unsafe(
59
+ code: str, _locals: dict[str, Callable], timeout: int = 10
60
+ ) -> tuple[SandboxOutput, dict[str, Any]]:
11
61
  """Executes a string of Python code in a sandboxed environment."""
12
- # Store original keys before execution
13
62
  original_keys = set(_locals.keys())
14
- result = f"Executing code...\n{code}\n\nOutput:\n"
15
- result += "=" * 50 + "\n"
63
+ execution_context = _locals.copy()
64
+ execution_context["__builtins__"] = SAFE_BUILTINS
65
+
66
+ stdout_capture = io.StringIO()
67
+ output = SandboxOutput(stdout="")
68
+
16
69
  try:
17
70
  logger.debug(f"Executing code with timeout {timeout}")
18
- with contextlib.redirect_stdout(io.StringIO()) as f:
19
- # Execute the code in the provided locals context
20
- # This should define an async function `main`
21
- exec(code, builtins.__dict__, _locals)
22
-
23
- if "main" in _locals and asyncio.iscoroutinefunction(_locals["main"]):
24
- # Run the main async function
25
- await asyncio.wait_for(_locals["main"](), timeout=timeout)
71
+ with contextlib.redirect_stdout(stdout_capture):
72
+ exec(code, execution_context)
73
+
74
+ if "main" in execution_context and asyncio.iscoroutinefunction(execution_context["main"]):
75
+ return_val = await asyncio.wait_for(execution_context["main"](), timeout=timeout)
76
+ output.return_value = return_val
26
77
  else:
27
- result += "\nError: No `async def main()` function found in the script."
78
+ output.error = "No `async def main()` function found in the script."
79
+
80
+ output.stdout = stdout_capture.getvalue()
28
81
 
29
- output = f.getvalue()
30
- result += output
31
- if not output:
32
- result += "<code ran, no output printed to stdout>"
33
82
  except Exception as e:
34
- result += f"Error during execution: {repr(e)}"
83
+ output.error = f"{type(e).__name__}: {e}"
84
+ output.stdout = stdout_capture.getvalue()
85
+
86
+ new_keys = set(execution_context.keys()) - original_keys - {"__builtins__"}
87
+ new_vars = {key: execution_context[key] for key in new_keys}
35
88
 
36
- # Determine new variables created during execution
37
- new_keys = set(_locals.keys()) - original_keys
38
- new_vars = {key: _locals[key] for key in new_keys}
39
- return result, new_vars
89
+ return output, new_vars
@@ -7,3 +7,5 @@ class CodeActState(MessagesState):
7
7
 
8
8
  script: str | None = Field(default=None, description="The Python code script to be executed.")
9
9
  sandbox_output: str | None = Field(default=None, description="The output of the Python code script execution.")
10
+ syntax_error: str | None = Field(default=None, description="The syntax error from the last script validation.")
11
+ task_complete: bool = Field(default=False, description="Whether the task is complete.")
@@ -0,0 +1,3 @@
1
+ from .agent import CodeActAgent
2
+
3
+ __all__ = ["CodeActAgent"]
@@ -0,0 +1,35 @@
1
+ import asyncio
2
+
3
+ from langgraph.checkpoint.memory import MemorySaver
4
+ from rich import print
5
+ from universal_mcp.agentr.registry import AgentrRegistry
6
+
7
+ from universal_mcp.agents.codeact0.agent import CodeActAgent
8
+ from universal_mcp.agents.utils import messages_to_list
9
+
10
+
11
+ async def main():
12
+ memory = MemorySaver()
13
+ agent = CodeActAgent(
14
+ name="CodeAct Agent",
15
+ instructions="Be very concise in your answers.",
16
+ model="anthropic:claude-4-sonnet-20250514",
17
+ tools={"google_mail": ["list_messages"]},
18
+ registry=AgentrRegistry(),
19
+ memory=memory,
20
+ )
21
+ print("Starting agent...")
22
+ # await agent.ainit()
23
+ # await agent.run_interactive()
24
+ # async for event in agent.stream(
25
+ # user_input="Fetch unsubscribe links from my Gmail inbox for promo emails I have received in the last 7 days"
26
+ # ):
27
+ # print(event.content, end="")
28
+ result = await agent.invoke(
29
+ user_input="Fetch unsubscribe links from my Gmail inbox for promo emails I have received in the last 7 days"
30
+ )
31
+ print(messages_to_list(result["messages"]))
32
+
33
+
34
+ if __name__ == "__main__":
35
+ asyncio.run(main())
@@ -0,0 +1,136 @@
1
+ import inspect
2
+ from collections.abc import Callable
3
+ from typing import Literal, cast
4
+
5
+ from langchain_core.messages import AIMessage, ToolMessage
6
+ from langchain_core.tools import StructuredTool
7
+ from langchain_core.tools import tool as create_tool
8
+ from langgraph.checkpoint.base import BaseCheckpointSaver
9
+ from langgraph.graph import START, StateGraph
10
+ from langgraph.types import Command, RetryPolicy
11
+ from universal_mcp.tools.registry import ToolRegistry
12
+ from universal_mcp.types import ToolConfig, ToolFormat
13
+
14
+ from universal_mcp.agents.base import BaseAgent
15
+ from universal_mcp.agents.codeact0.llm_tool import ai_classify, call_llm, data_extractor, smart_print
16
+ from universal_mcp.agents.codeact0.prompts import (
17
+ create_default_prompt,
18
+ )
19
+ from universal_mcp.agents.codeact0.sandbox import eval_unsafe, execute_ipython_cell
20
+ from universal_mcp.agents.codeact0.state import CodeActState
21
+ from universal_mcp.agents.codeact0.utils import filter_retry_on, inject_context
22
+ from universal_mcp.agents.llm import load_chat_model
23
+
24
+
25
+ class CodeActAgent(BaseAgent):
26
+ def __init__(
27
+ self,
28
+ name: str,
29
+ instructions: str,
30
+ model: str,
31
+ memory: BaseCheckpointSaver | None = None,
32
+ tools: ToolConfig | None = None,
33
+ registry: ToolRegistry | None = None,
34
+ sandbox_timeout: int = 20,
35
+ **kwargs,
36
+ ):
37
+ super().__init__(
38
+ name=name,
39
+ instructions=instructions,
40
+ model=model,
41
+ memory=memory,
42
+ **kwargs,
43
+ )
44
+ self.model_instance = load_chat_model(model, thinking=True)
45
+ self.tools_config = tools or {}
46
+ self.registry = registry
47
+ self.eval_fn = eval_unsafe
48
+ self.sandbox_timeout = sandbox_timeout
49
+ self.processed_tools: list[StructuredTool | Callable] = []
50
+
51
+ # TODO(manoj): Use toolformat native instead of langchain
52
+ # TODO(manoj, later): Add better sandboxing
53
+ # Old Nishant TODO s:
54
+ # - Make codeact faster by calling upto API call (this done but should be tested)
55
+ # - Add support for async eval_fn
56
+ # - Throw Error if code snippet is too long (> 1000 characters) and suggest to split it into smaller parts
57
+ # - Multiple models from config
58
+
59
+ async def _build_graph(self):
60
+ exported_tools = []
61
+ if self.tools_config:
62
+ if not self.registry:
63
+ raise ValueError("Tools are configured but no registry is provided")
64
+ # Langchain tools are fine
65
+ exported_tools = await self.registry.export_tools(self.tools_config, ToolFormat.LANGCHAIN)
66
+ exported_tools.extend([smart_print, data_extractor, ai_classify, call_llm])
67
+ self.processed_tools = [t if isinstance(t, StructuredTool) else create_tool(t) for t in exported_tools]
68
+ self.instructions, self.tools_context = create_default_prompt(self.processed_tools, self.instructions)
69
+
70
+ def call_model(state: CodeActState) -> Command[Literal["sandbox"]]:
71
+ messages = [{"role": "system", "content": self.instructions}] + state["messages"]
72
+
73
+ # Run the model and potentially loop for reflection
74
+ model_with_tools = self.model_instance.bind_tools(tools=[execute_ipython_cell], tool_choice="auto")
75
+ response = cast(AIMessage, model_with_tools.invoke(messages))
76
+
77
+ if response.tool_calls:
78
+ if len(response.tool_calls) > 1:
79
+ raise Exception("Not possible in Claude with llm.bind_tools(tools=tools, tool_choice='auto')")
80
+ if response.tool_calls[0]["name"] != "execute_ipython_cell":
81
+ raise Exception(
82
+ f"Unexpected tool call: {response.tool_calls[0]['name']}. Expected 'execute_ipython_cell'."
83
+ )
84
+ if (
85
+ response.tool_calls[0]["args"].get("snippet") is None
86
+ or not response.tool_calls[0]["args"]["snippet"].strip()
87
+ ):
88
+ raise Exception("Tool call 'execute_ipython_cell' requires a non-empty 'snippet' argument.")
89
+ return Command(goto="sandbox", update={"messages": [response]})
90
+ else:
91
+ return Command(update={"messages": [response]})
92
+
93
+ # If eval_fn is a async, we define async node function.
94
+ if inspect.iscoroutinefunction(self.eval_fn):
95
+ raise ValueError("eval_fn must be a synchronous function, not a coroutine.")
96
+ # async def sandbox(state: StateSchema):
97
+ # existing_context = state.get("context", {})
98
+ # context = {**existing_context, **tools_context}
99
+ # # Execute the script in the sandbox
100
+ # output, new_vars = await eval_fn(state["script"], context)
101
+ # new_context = {**existing_context, **new_vars}
102
+ # return {
103
+ # "messages": [{"role": "user", "content": output}],
104
+ # "context": new_context,
105
+ # }
106
+ else:
107
+
108
+ def sandbox(state: CodeActState) -> Command[Literal["call_model"]]:
109
+ tool_call = state["messages"][-1].tool_calls[0] # type: ignore
110
+ code = tool_call["args"]["snippet"]
111
+ previous_add_context = state.get("add_context", {})
112
+ add_context = inject_context(previous_add_context, self.tools_context)
113
+ existing_context = state.get("context", {})
114
+ context = {**existing_context, **add_context}
115
+ # Execute the script in the sandbox
116
+ output, new_context, new_add_context = self.eval_fn(code, context, previous_add_context)
117
+ return Command(
118
+ goto="call_model",
119
+ update={
120
+ "messages": [
121
+ ToolMessage(
122
+ content=output,
123
+ name=tool_call["name"],
124
+ tool_call_id=tool_call["id"],
125
+ )
126
+ ],
127
+ "context": new_context,
128
+ "add_context": new_add_context,
129
+ },
130
+ )
131
+
132
+ agent = StateGraph(state_schema=CodeActState)
133
+ agent.add_node(call_model, retry_policy=RetryPolicy(max_attempts=3, retry_on=filter_retry_on))
134
+ agent.add_node(sandbox)
135
+ agent.add_edge(START, "call_model")
136
+ return agent.compile(checkpointer=self.memory)
@@ -0,0 +1,77 @@
1
+ from typing import Annotated, Literal
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+ # Literal type for all available usecase filenames
6
+ UseCaseName = Literal[
7
+ " ",
8
+ "1-unsubscribe",
9
+ "2-reddit",
10
+ "2.1-reddit",
11
+ "3-earnings",
12
+ "4-maps",
13
+ "4.1-maps",
14
+ "5-gmailreply",
15
+ "6-contract",
16
+ "7-overnight",
17
+ "8-sheets_chart",
18
+ "9-learning",
19
+ "10-reddit2",
20
+ "11-github",
21
+ ]
22
+
23
+
24
+ class ContextSchema(BaseModel):
25
+ """The configuration for the agent."""
26
+
27
+ base_prompt: str = Field(
28
+ default=" ",
29
+ description="The base prompt to use for the agent's interactions. Leave blank if using a JSON prompt from the dropdown.",
30
+ )
31
+ model_provider: Annotated[
32
+ Literal[
33
+ "openai",
34
+ "anthropic",
35
+ "azure_openai",
36
+ "azure_ai",
37
+ "google_vertexai",
38
+ "google_genai",
39
+ "bedrock",
40
+ "bedrock_converse",
41
+ "cohere",
42
+ "fireworks",
43
+ "together",
44
+ "mistralai",
45
+ "huggingface",
46
+ "groq",
47
+ "ollama",
48
+ "google_anthropic_vertex",
49
+ "deepseek",
50
+ "ibm",
51
+ "nvidia",
52
+ "xai",
53
+ "perplexity",
54
+ ],
55
+ {"__template_metadata__": {"kind": "provider"}},
56
+ ] = Field(
57
+ default="anthropic",
58
+ description="The name of the model provider to use for the agent's main interactions. ",
59
+ )
60
+ model: Annotated[
61
+ Literal[
62
+ "claude-4-sonnet-20250514",
63
+ "claude-sonnet-4@20250514",
64
+ ],
65
+ {"__template_metadata__": {"kind": "llm"}},
66
+ ] = Field(
67
+ default="claude-4-sonnet-20250514",
68
+ description="The name of the language model to use for the agent's main interactions. ",
69
+ )
70
+ tool_names: list[str] = Field(
71
+ default=[],
72
+ description="The names of the tools to use for the agent's main interactions. Leave blank if using a JSON prompt from the dropdown.",
73
+ )
74
+ json_prompt_name: UseCaseName = Field(
75
+ default=" ",
76
+ description="The name of the JSON prompt to use for the agent's main interactions, instead of providing a base prompt and tool names. ",
77
+ )
@@ -0,0 +1,17 @@
1
+ from langgraph.checkpoint.memory import MemorySaver
2
+ from universal_mcp.agentr.registry import AgentrRegistry
3
+
4
+ from universal_mcp.agents.codeact0.agent import CodeActAgent
5
+
6
+
7
+ async def agent():
8
+ memory = MemorySaver()
9
+ agent_object = await CodeActAgent(
10
+ name="CodeAct Agent",
11
+ instructions="Be very concise in your answers.",
12
+ model="anthropic:claude-4-sonnet-20250514",
13
+ tools={"google_mail": ["list_messages"]},
14
+ registry=AgentrRegistry(),
15
+ memory=memory,
16
+ )._build_graph()
17
+ return agent_object
@@ -0,0 +1,104 @@
1
+ import contextlib
2
+ import inspect
3
+ import io
4
+ import queue
5
+ import re
6
+ import socket
7
+ import threading
8
+ import types
9
+ from typing import Any
10
+
11
+ import yaml
12
+ from langchain.chat_models import init_chat_model
13
+ from langchain_anthropic import ChatAnthropic
14
+ from langchain_core.runnables import RunnableConfig
15
+ from langchain_google_vertexai.model_garden import ChatAnthropicVertex
16
+ from universal_mcp.agentr import Agentr
17
+ from universal_mcp.types import ToolFormat
18
+
19
+ from universal_mcp.agents.codeact0 import create_codeact
20
+ from universal_mcp.agents.codeact0.config import ContextSchema
21
+ from universal_mcp.agents.codeact0.utils import derive_context
22
+
23
+
24
+ def eval(code: str, _locals: dict[str, Any], add_context: dict[str, Any]) -> tuple[str, dict[str, Any], dict[str, Any]]:
25
+ # print(_locals)
26
+ EXCLUDE_TYPES = (
27
+ types.ModuleType, # modules
28
+ type(re.match("", "")),
29
+ type(threading.Lock()), # instead of threading.Lock
30
+ type(threading.RLock()), # reentrant lock
31
+ threading.Event, # events
32
+ threading.Condition, # condition vars
33
+ threading.Semaphore, # semaphores
34
+ queue.Queue, # thread-safe queues
35
+ socket.socket, # network sockets
36
+ io.IOBase, # file handles (and StringIO/BytesIO)
37
+ )
38
+ try:
39
+ with contextlib.redirect_stdout(io.StringIO()) as f:
40
+ # Execute the code in the provided locals context
41
+ # Using exec to allow dynamic code execution
42
+ # This is a simplified version; in production, consider security implications
43
+ exec(code, _locals, _locals)
44
+ result = f.getvalue()
45
+ if not result:
46
+ result = "<code ran, no output printed to stdout>"
47
+ except Exception as e:
48
+ result = f"Error during execution: {repr(e)}"
49
+
50
+ # Return all variables in locals except __builtins__ and unpicklable objects (including tools)
51
+ all_vars = {}
52
+ for key, value in _locals.items():
53
+ if key == "__builtins__":
54
+ continue
55
+
56
+ # Skip coroutines, async generators, and coroutine functions
57
+ if inspect.iscoroutine(value) or inspect.iscoroutinefunction(value):
58
+ continue
59
+ if inspect.isasyncgen(value) or inspect.isasyncgenfunction(value):
60
+ continue
61
+
62
+ # Skip "obviously unpicklable" types
63
+ if isinstance(value, EXCLUDE_TYPES):
64
+ continue
65
+
66
+ # Keep if it's not a callable OR if it has no __name__ attribute
67
+ if not callable(value) or not hasattr(value, "__name__"):
68
+ all_vars[key] = value
69
+
70
+ new_add_context = derive_context(code, add_context)
71
+ return result, all_vars, new_add_context
72
+
73
+
74
+ async def agent(config: RunnableConfig):
75
+ cfg = ContextSchema(**config.get("configurable", {}))
76
+
77
+ if cfg.json_prompt_name and cfg.json_prompt_name.strip():
78
+ with open(f"usecases/{cfg.json_prompt_name}.yaml", encoding="utf-8") as f:
79
+ content = f.read()
80
+ data = yaml.safe_load(content)
81
+ if cfg.base_prompt and cfg.base_prompt.strip():
82
+ pass
83
+ else:
84
+ cfg.base_prompt = data["base_prompt"]
85
+ cfg.tool_names = data["tools"]
86
+ agentr = Agentr()
87
+ agentr.load_tools(cfg.tool_names)
88
+ tools = [] # can add custom tools here like get_weather, get_simple_weather, etc.
89
+
90
+ tools_agentr = agentr.list_tools(format=ToolFormat.NATIVE)
91
+ tools.extend(tools_agentr)
92
+
93
+ if cfg.model_provider == "google_anthropic_vertex":
94
+ # For Google Anthropic Vertex, we need to use the specific model initialization due to location
95
+ model = ChatAnthropicVertex(model=cfg.model, temperature=0.2, location="asia-east1")
96
+ elif cfg.model == "claude-4-sonnet-20250514":
97
+ model = ChatAnthropic(
98
+ model=cfg.model, temperature=1, thinking={"type": "enabled", "budget_tokens": 2048}, max_tokens=4096
99
+ ) # pyright: ignore[reportCallIssue]
100
+ else:
101
+ model = init_chat_model(model=cfg.model, model_provider=cfg.model_provider, temperature=0.2)
102
+
103
+ code_act = create_codeact(model, cfg.base_prompt, tools, eval)
104
+ return code_act.compile()