universal-mcp-agents 0.1.23rc11__tar.gz → 0.1.24__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.
- universal_mcp_agents-0.1.24/.gemini/settings.json +7 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/PKG-INFO +1 -1
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/pyproject.toml +1 -1
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/__init__.py +1 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/base.py +3 -6
- universal_mcp_agents-0.1.24/src/universal_mcp/agents/codeact0/agent.py +373 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/codeact0/prompts.py +107 -40
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/codeact0/sandbox.py +45 -8
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/codeact0/state.py +8 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/codeact0/tools.py +70 -20
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/codeact0/utils.py +216 -13
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/llm.py +7 -3
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/applications/llm/app.py +71 -18
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/uv.lock +1 -1
- universal_mcp_agents-0.1.23rc11/src/universal_mcp/agents/codeact0/agent.py +0 -495
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/.github/workflows/evals.yml +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/.github/workflows/lint.yml +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/.github/workflows/release-please.yml +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/.github/workflows/tests.yml +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/.gitignore +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/.pre-commit-config.yaml +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/GEMINI.md +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/PROMPTS.md +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/README.md +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/bump_and_release.sh +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/evals/__init__.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/evals/dataset.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/evals/datasets/exact.jsonl +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/evals/datasets/tasks.jsonl +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/evals/datasets/test.jsonl +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/evals/evaluators.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/evals/prompts.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/evals/run.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/evals/utils.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/tests/test_agents.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/tests/test_sandbox.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/bigtool/__init__.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/bigtool/__main__.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/bigtool/agent.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/bigtool/context.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/bigtool/graph.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/bigtool/prompts.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/bigtool/state.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/bigtool/tools.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/builder/__main__.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/builder/builder.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/builder/helper.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/builder/prompts.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/builder/state.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/cli.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/codeact0/__init__.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/codeact0/__main__.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/codeact0/config.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/codeact0/langgraph_agent.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/codeact0/llm_tool.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/hil.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/react.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/sandbox.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/shared/__main__.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/shared/prompts.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/shared/tool_node.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/simple.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/utils.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/applications/filesystem/__init__.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/applications/filesystem/app.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/applications/llm/__init__.py +0 -0
- {universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/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.
|
|
3
|
+
Version: 0.1.24
|
|
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
|
{universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/__init__.py
RENAMED
|
@@ -11,6 +11,7 @@ from universal_mcp.agents.simple import SimpleAgent
|
|
|
11
11
|
def get_agent(
|
|
12
12
|
agent_name: Literal["react", "simple", "builder", "bigtool", "codeact-repl"],
|
|
13
13
|
):
|
|
14
|
+
print("agent_name", agent_name)
|
|
14
15
|
if agent_name == "react":
|
|
15
16
|
return ReactAgent
|
|
16
17
|
elif agent_name == "simple":
|
{universal_mcp_agents-0.1.23rc11 → universal_mcp_agents-0.1.24}/src/universal_mcp/agents/base.py
RENAMED
|
@@ -67,13 +67,10 @@ 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
|
-
|
|
70
|
+
metadata = getattr(payload, "metadata", {}) or {}
|
|
71
|
+
if metadata and "quiet" in metadata.get("tags"):
|
|
71
72
|
continue
|
|
72
|
-
|
|
73
|
-
isinstance(meta_dict, dict) and meta_dict.get("langgraph_node") == "agent_builder"
|
|
74
|
-
)
|
|
75
|
-
additional_kwargs = getattr(payload, "additional_kwargs", {}) or {}
|
|
76
|
-
if is_agent_builder and not additional_kwargs.get("stream"):
|
|
73
|
+
if meta_dict.get("tags") and "quiet" in meta_dict.get("tags"):
|
|
77
74
|
continue
|
|
78
75
|
if isinstance(payload, AIMessageChunk):
|
|
79
76
|
last_ai_chunk = payload
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
import json
|
|
3
|
+
import re
|
|
4
|
+
import uuid
|
|
5
|
+
from typing import Literal, cast
|
|
6
|
+
|
|
7
|
+
from langchain_anthropic import ChatAnthropic
|
|
8
|
+
from langchain_core.messages import AIMessage, HumanMessage, ToolMessage
|
|
9
|
+
from langgraph.checkpoint.base import BaseCheckpointSaver
|
|
10
|
+
from langgraph.graph import START, StateGraph
|
|
11
|
+
from langgraph.types import Command, RetryPolicy, StreamWriter
|
|
12
|
+
from universal_mcp.tools.registry import ToolRegistry
|
|
13
|
+
from universal_mcp.types import ToolFormat
|
|
14
|
+
|
|
15
|
+
from universal_mcp.agents.base import BaseAgent
|
|
16
|
+
from universal_mcp.agents.codeact0.llm_tool import smart_print
|
|
17
|
+
from universal_mcp.agents.codeact0.prompts import (
|
|
18
|
+
AGENT_BUILDER_GENERATING_PROMPT,
|
|
19
|
+
AGENT_BUILDER_META_PROMPT,
|
|
20
|
+
AGENT_BUILDER_PLANNING_PROMPT,
|
|
21
|
+
AGENT_BUILDER_PLAN_PATCH_PROMPT,
|
|
22
|
+
AGENT_BUILDER_CODE_PATCH_PROMPT,
|
|
23
|
+
build_tool_definitions,
|
|
24
|
+
create_default_prompt,
|
|
25
|
+
)
|
|
26
|
+
from universal_mcp.agents.codeact0.sandbox import eval_unsafe, execute_ipython_cell, handle_execute_ipython_cell
|
|
27
|
+
from universal_mcp.agents.codeact0.state import AgentBuilderCode, AgentBuilderMeta, AgentBuilderPlan, AgentBuilderPatch, CodeActState
|
|
28
|
+
from universal_mcp.agents.codeact0.tools import (
|
|
29
|
+
create_agent_builder_tools,
|
|
30
|
+
create_meta_tools,
|
|
31
|
+
)
|
|
32
|
+
from universal_mcp.agents.codeact0.utils import build_anthropic_cache_message, extract_plan_parameters, get_connected_apps_string, strip_thinking
|
|
33
|
+
from universal_mcp.agents.codeact0.utils import apply_patch_or_use_proposed
|
|
34
|
+
from universal_mcp.agents.llm import load_chat_model
|
|
35
|
+
from universal_mcp.agents.utils import convert_tool_ids_to_dict, filter_retry_on
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class CodeActPlaybookAgent(BaseAgent):
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
name: str,
|
|
42
|
+
instructions: str,
|
|
43
|
+
model: str,
|
|
44
|
+
memory: BaseCheckpointSaver | None = None,
|
|
45
|
+
registry: ToolRegistry | None = None,
|
|
46
|
+
agent_builder_registry: object | None = None,
|
|
47
|
+
sandbox_timeout: int = 20,
|
|
48
|
+
**kwargs,
|
|
49
|
+
):
|
|
50
|
+
super().__init__(
|
|
51
|
+
name=name,
|
|
52
|
+
instructions=instructions,
|
|
53
|
+
model=model,
|
|
54
|
+
memory=memory,
|
|
55
|
+
**kwargs,
|
|
56
|
+
)
|
|
57
|
+
self.model_instance = load_chat_model(model)
|
|
58
|
+
self.agent_builder_model_instance = load_chat_model("anthropic:claude-sonnet-4-5-20250929", thinking=False, disable_streaming = True, tags=("quiet",))
|
|
59
|
+
self.registry = registry
|
|
60
|
+
self.agent_builder_registry = agent_builder_registry
|
|
61
|
+
self.agent = agent_builder_registry.get_agent() if agent_builder_registry else None
|
|
62
|
+
|
|
63
|
+
self.tools_config = self.agent.tools if self.agent else {}
|
|
64
|
+
self.eval_fn = eval_unsafe
|
|
65
|
+
self.sandbox_timeout = sandbox_timeout
|
|
66
|
+
self.default_tools_config = {
|
|
67
|
+
"llm": ["generate_text", "classify_data", "extract_data", "call_llm"],
|
|
68
|
+
}
|
|
69
|
+
self.final_instructions = ""
|
|
70
|
+
self.tools_context = {}
|
|
71
|
+
self.eval_mode = kwargs.get("eval_mode", False)
|
|
72
|
+
|
|
73
|
+
async def _build_graph(self): # noqa: PLR0915
|
|
74
|
+
"""Build the graph for the CodeAct Playbook Agent."""
|
|
75
|
+
meta_tools = create_meta_tools(self.registry)
|
|
76
|
+
agent_builder_tools = create_agent_builder_tools()
|
|
77
|
+
self.additional_tools = [
|
|
78
|
+
smart_print,
|
|
79
|
+
meta_tools["web_search"],
|
|
80
|
+
meta_tools["read_file"],
|
|
81
|
+
meta_tools["save_file"],
|
|
82
|
+
meta_tools["upload_file"],
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
if self.tools_config:
|
|
86
|
+
await self.registry.load_tools(self.tools_config) # Load provided tools
|
|
87
|
+
if self.default_tools_config:
|
|
88
|
+
await self.registry.load_tools(self.default_tools_config) # Load default tools
|
|
89
|
+
|
|
90
|
+
async def call_model(state: CodeActState) -> Command[Literal["execute_tools"]]:
|
|
91
|
+
"""This node now only ever binds the four meta-tools to the LLM."""
|
|
92
|
+
messages = build_anthropic_cache_message(self.final_instructions) + state["messages"]
|
|
93
|
+
agent_facing_tools = [
|
|
94
|
+
execute_ipython_cell,
|
|
95
|
+
agent_builder_tools["plan_agent"],
|
|
96
|
+
agent_builder_tools["code_and_save_agent"],
|
|
97
|
+
meta_tools["search_functions"],
|
|
98
|
+
meta_tools["load_functions"],
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
if isinstance(self.model_instance, ChatAnthropic):
|
|
102
|
+
model_with_tools = self.model_instance.bind_tools(
|
|
103
|
+
tools=agent_facing_tools,
|
|
104
|
+
tool_choice="auto",
|
|
105
|
+
cache_control={"type": "ephemeral", "ttl": "1h"},
|
|
106
|
+
)
|
|
107
|
+
if isinstance(messages[-1].content, str):
|
|
108
|
+
pass
|
|
109
|
+
else:
|
|
110
|
+
last = copy.deepcopy(messages[-1])
|
|
111
|
+
last.content[-1]["cache_control"] = {"type": "ephemeral", "ttl": "5m"}
|
|
112
|
+
messages[-1] = last
|
|
113
|
+
else:
|
|
114
|
+
model_with_tools = self.model_instance.bind_tools(
|
|
115
|
+
tools=agent_facing_tools,
|
|
116
|
+
tool_choice="auto",
|
|
117
|
+
)
|
|
118
|
+
response = cast(AIMessage, await model_with_tools.ainvoke(messages))
|
|
119
|
+
if response.tool_calls:
|
|
120
|
+
return Command(goto="execute_tools", update={"messages": [response]})
|
|
121
|
+
else:
|
|
122
|
+
return Command(update={"messages": [response], "model_with_tools": model_with_tools})
|
|
123
|
+
|
|
124
|
+
async def execute_tools(state: CodeActState, writer: StreamWriter) -> Command[Literal["call_model"]]:
|
|
125
|
+
"""Execute tool calls"""
|
|
126
|
+
last_message = state["messages"][-1]
|
|
127
|
+
tool_calls = last_message.tool_calls if isinstance(last_message, AIMessage) else []
|
|
128
|
+
|
|
129
|
+
tool_messages = []
|
|
130
|
+
new_tool_ids = []
|
|
131
|
+
tool_result = ""
|
|
132
|
+
ask_user = False
|
|
133
|
+
ai_msg = None
|
|
134
|
+
effective_previous_add_context = state.get("add_context", {})
|
|
135
|
+
effective_existing_context = state.get("context", {})
|
|
136
|
+
plan = state.get("plan", None)
|
|
137
|
+
agent_name = state.get("agent_name", None)
|
|
138
|
+
agent_description = state.get("agent_description", None)
|
|
139
|
+
# logging.info(f"Initial new_tool_ids_for_context: {new_tool_ids_for_context}")
|
|
140
|
+
|
|
141
|
+
for tool_call in tool_calls:
|
|
142
|
+
tool_name = tool_call["name"]
|
|
143
|
+
tool_args = tool_call["args"]
|
|
144
|
+
try:
|
|
145
|
+
if tool_name == "execute_ipython_cell":
|
|
146
|
+
code = tool_call["args"]["snippet"]
|
|
147
|
+
output, new_context, new_add_context = await handle_execute_ipython_cell(
|
|
148
|
+
code,
|
|
149
|
+
self.tools_context, # Uses the dynamically updated context
|
|
150
|
+
self.eval_fn,
|
|
151
|
+
effective_previous_add_context,
|
|
152
|
+
effective_existing_context,
|
|
153
|
+
)
|
|
154
|
+
effective_existing_context = new_context
|
|
155
|
+
effective_previous_add_context = new_add_context
|
|
156
|
+
tool_result = output
|
|
157
|
+
elif tool_name == "load_functions":
|
|
158
|
+
# The tool now does all the work of validation and formatting.
|
|
159
|
+
tool_result, new_context_for_sandbox, valid_tools, unconnected_links = await meta_tools[
|
|
160
|
+
"load_functions"
|
|
161
|
+
].ainvoke(tool_args)
|
|
162
|
+
# We still need to update the sandbox context for `execute_ipython_cell`
|
|
163
|
+
new_tool_ids.extend(valid_tools)
|
|
164
|
+
if new_tool_ids:
|
|
165
|
+
self.tools_context.update(new_context_for_sandbox)
|
|
166
|
+
if unconnected_links:
|
|
167
|
+
ask_user = True
|
|
168
|
+
ai_msg = f"Please login to the following app(s) using the following links and let me know in order to proceed:\n {unconnected_links} "
|
|
169
|
+
|
|
170
|
+
elif tool_name == "search_functions":
|
|
171
|
+
tool_result = await meta_tools["search_functions"].ainvoke(tool_args)
|
|
172
|
+
|
|
173
|
+
elif tool_name == "plan_agent":
|
|
174
|
+
plan, tool_result = await self._create_or_update_plan(state=state, writer=writer, plan=plan)
|
|
175
|
+
ask_user = True
|
|
176
|
+
|
|
177
|
+
elif tool_name == "code_and_save_agent":
|
|
178
|
+
tool_result, effective_previous_add_context, agent_name, agent_description = await self._build_or_patch_code(
|
|
179
|
+
state=state,
|
|
180
|
+
writer=writer,
|
|
181
|
+
plan=plan,
|
|
182
|
+
agent_name=agent_name,
|
|
183
|
+
agent_description=agent_description,
|
|
184
|
+
effective_previous_add_context=effective_previous_add_context,
|
|
185
|
+
)
|
|
186
|
+
else:
|
|
187
|
+
raise Exception(
|
|
188
|
+
f"Unexpected tool call: {tool_call['name']}. "
|
|
189
|
+
"tool calls must be one of 'execute_ipython_cell', 'load_functions', 'search_functions', 'plan_agent', or 'code_and_save_agent'. For using functions, call them in code using 'execute_ipython_cell'."
|
|
190
|
+
)
|
|
191
|
+
except Exception as e:
|
|
192
|
+
tool_result = str(e)
|
|
193
|
+
|
|
194
|
+
tool_message = ToolMessage(
|
|
195
|
+
content=json.dumps(tool_result),
|
|
196
|
+
name=tool_call["name"],
|
|
197
|
+
tool_call_id=tool_call["id"],
|
|
198
|
+
)
|
|
199
|
+
tool_messages.append(tool_message)
|
|
200
|
+
|
|
201
|
+
if ask_user:
|
|
202
|
+
if ai_msg:
|
|
203
|
+
tool_messages.append(AIMessage(content=ai_msg))
|
|
204
|
+
return Command(
|
|
205
|
+
update={
|
|
206
|
+
"messages": tool_messages,
|
|
207
|
+
"selected_tool_ids": new_tool_ids,
|
|
208
|
+
"context": effective_existing_context,
|
|
209
|
+
"add_context": effective_previous_add_context,
|
|
210
|
+
"agent_name": agent_name,
|
|
211
|
+
"agent_description": agent_description,
|
|
212
|
+
"plan": plan,
|
|
213
|
+
}
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
return Command(
|
|
217
|
+
goto="call_model",
|
|
218
|
+
update={
|
|
219
|
+
"messages": tool_messages,
|
|
220
|
+
"selected_tool_ids": new_tool_ids,
|
|
221
|
+
"context": effective_existing_context,
|
|
222
|
+
"add_context": effective_previous_add_context,
|
|
223
|
+
"agent_name": agent_name,
|
|
224
|
+
"agent_description": agent_description,
|
|
225
|
+
"plan": plan,
|
|
226
|
+
},
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
async def route_entry(state: CodeActState) -> Command[Literal["call_model", "execute_tools"]]:
|
|
230
|
+
"""Route to either normal mode or agent builder creation"""
|
|
231
|
+
pre_tools = await self.registry.export_tools(format=ToolFormat.NATIVE)
|
|
232
|
+
|
|
233
|
+
# Create the initial system prompt and tools_context in one go
|
|
234
|
+
self.final_instructions, self.tools_context = create_default_prompt(
|
|
235
|
+
pre_tools,
|
|
236
|
+
self.additional_tools,
|
|
237
|
+
self.instructions,
|
|
238
|
+
await get_connected_apps_string(self.registry),
|
|
239
|
+
self.agent,
|
|
240
|
+
is_initial_prompt=True,
|
|
241
|
+
)
|
|
242
|
+
self.preloaded_defs, _ = build_tool_definitions(pre_tools)
|
|
243
|
+
self.preloaded_defs = "\n".join(self.preloaded_defs)
|
|
244
|
+
await self.registry.load_tools(state["selected_tool_ids"])
|
|
245
|
+
exported_tools = await self.registry.export_tools(
|
|
246
|
+
state["selected_tool_ids"], ToolFormat.NATIVE
|
|
247
|
+
) # Get definition for only the new tools
|
|
248
|
+
_, loaded_tools_context = build_tool_definitions(exported_tools)
|
|
249
|
+
self.tools_context.update(loaded_tools_context)
|
|
250
|
+
|
|
251
|
+
if (
|
|
252
|
+
len(state["messages"]) == 1 and self.agent
|
|
253
|
+
): # Inject the agent's script function into add_context for execution
|
|
254
|
+
script = self.agent.instructions.get("script")
|
|
255
|
+
add_context = {"functions": [script]}
|
|
256
|
+
return Command(goto="call_model", update={"add_context": add_context})
|
|
257
|
+
return Command(goto="call_model")
|
|
258
|
+
|
|
259
|
+
agent = StateGraph(state_schema=CodeActState)
|
|
260
|
+
agent.add_node(call_model, retry_policy=RetryPolicy(max_attempts=3, retry_on=filter_retry_on))
|
|
261
|
+
agent.add_node(execute_tools)
|
|
262
|
+
agent.add_node(route_entry)
|
|
263
|
+
agent.add_edge(START, "route_entry")
|
|
264
|
+
return agent.compile(checkpointer=self.memory)
|
|
265
|
+
|
|
266
|
+
async def _create_or_update_plan(self, state: "CodeActState", writer: StreamWriter, plan: list[str] | None):
|
|
267
|
+
"""Sub-agent helper: create or patch-update the agent plan and emit UI updates.
|
|
268
|
+
Returns: (plan: list[str], tool_result: str)
|
|
269
|
+
"""
|
|
270
|
+
plan_id = str(uuid.uuid4())
|
|
271
|
+
writer({"type": "custom", id: plan_id, "name": "planning", "data": {"update": bool(plan)}})
|
|
272
|
+
|
|
273
|
+
# Determine existing plan (prefer persisted agent's plan) and base messages
|
|
274
|
+
existing_plan_steps = (self.agent.instructions.get("plan") if self.agent and getattr(self.agent, "instructions", None) else None) or plan
|
|
275
|
+
base = strip_thinking(state["messages"])
|
|
276
|
+
def with_sys(text: str):
|
|
277
|
+
return [{"role": "system", "content": text}] + base
|
|
278
|
+
|
|
279
|
+
if existing_plan_steps:
|
|
280
|
+
current = "\n".join(map(str, existing_plan_steps or []))
|
|
281
|
+
sys_prompt = self.instructions + "\n" + AGENT_BUILDER_PLAN_PATCH_PROMPT + self.preloaded_defs
|
|
282
|
+
msgs = with_sys(sys_prompt) + [HumanMessage(content=f"Current plan (one step per line):\n{current}")]
|
|
283
|
+
patch_model = self.agent_builder_model_instance.with_structured_output(AgentBuilderPatch)
|
|
284
|
+
proposed = cast(AgentBuilderPatch, await patch_model.ainvoke(msgs)).patch
|
|
285
|
+
updated = apply_patch_or_use_proposed(current, proposed)
|
|
286
|
+
plan = [line for line in updated.splitlines() if line.strip()]
|
|
287
|
+
else:
|
|
288
|
+
sys_prompt = self.instructions + AGENT_BUILDER_PLANNING_PROMPT + self.preloaded_defs
|
|
289
|
+
plan_model = self.agent_builder_model_instance.with_structured_output(AgentBuilderPlan)
|
|
290
|
+
plan = cast(AgentBuilderPlan, await plan_model.ainvoke(with_sys(sys_prompt))).steps
|
|
291
|
+
|
|
292
|
+
writer({"type": "custom", id: plan_id, "name": "planning", "data": {"plan": plan}})
|
|
293
|
+
tool_result = {"plan": plan, "update": bool(plan), "message": f"Successfully generated the agent plan."}
|
|
294
|
+
return plan, tool_result
|
|
295
|
+
|
|
296
|
+
async def _build_or_patch_code(
|
|
297
|
+
self,
|
|
298
|
+
state: "CodeActState",
|
|
299
|
+
writer: StreamWriter,
|
|
300
|
+
plan: list[str] | None,
|
|
301
|
+
agent_name: str | None,
|
|
302
|
+
agent_description: str | None,
|
|
303
|
+
effective_previous_add_context: dict,
|
|
304
|
+
):
|
|
305
|
+
"""Sub-agent helper: generate new code or patch existing code, save, and emit UI updates.
|
|
306
|
+
Returns: (tool_result: str, effective_previous_add_context: dict, agent_name: str | None, agent_description: str | None)
|
|
307
|
+
"""
|
|
308
|
+
generation_id = str(uuid.uuid4())
|
|
309
|
+
writer({"type": "custom", "id": generation_id, "name": "generating", "data": {"update": bool(self.agent)}})
|
|
310
|
+
|
|
311
|
+
base = strip_thinking(state["messages"])
|
|
312
|
+
def with_sys(text: str):
|
|
313
|
+
return [{"role": "system", "content": text}] + base
|
|
314
|
+
plan_text = "\n".join(map(str, plan)) if plan else None
|
|
315
|
+
existing_code = self.agent.instructions.get("script") if self.agent and getattr(self.agent, "instructions", None) else None
|
|
316
|
+
|
|
317
|
+
if self.agent:
|
|
318
|
+
agent_name = getattr(self.agent, "name", None)
|
|
319
|
+
agent_description = getattr(self.agent, "description", None)
|
|
320
|
+
|
|
321
|
+
if not agent_name or not agent_description:
|
|
322
|
+
meta_model = self.agent_builder_model_instance.with_structured_output(AgentBuilderMeta)
|
|
323
|
+
meta = cast(AgentBuilderMeta, await meta_model.ainvoke(with_sys(self.instructions + AGENT_BUILDER_META_PROMPT)))
|
|
324
|
+
agent_name, agent_description = meta.name, meta.description
|
|
325
|
+
|
|
326
|
+
writer({"type": "custom", "id": generation_id, "name": "generating", "data": {"update": bool(self.agent), "name": agent_name, "description": agent_description}})
|
|
327
|
+
|
|
328
|
+
if existing_code:
|
|
329
|
+
generating_instructions = self.instructions + AGENT_BUILDER_CODE_PATCH_PROMPT + self.preloaded_defs
|
|
330
|
+
messages = with_sys(generating_instructions)
|
|
331
|
+
if plan_text:
|
|
332
|
+
messages.append(HumanMessage(content=f"Confirmed plan (one step per line):\n{plan_text}"))
|
|
333
|
+
messages.append(HumanMessage(content=f"Current code to update:\n```python\n{existing_code}\n```"))
|
|
334
|
+
patch_model = self.agent_builder_model_instance.with_structured_output(AgentBuilderPatch)
|
|
335
|
+
proposed = cast(AgentBuilderPatch, await patch_model.ainvoke(messages)).patch
|
|
336
|
+
python_code = apply_patch_or_use_proposed(existing_code, proposed)
|
|
337
|
+
else:
|
|
338
|
+
code_model = self.agent_builder_model_instance.with_structured_output(AgentBuilderCode)
|
|
339
|
+
python_code = cast(AgentBuilderCode, await code_model.ainvoke(with_sys(self.instructions + AGENT_BUILDER_GENERATING_PROMPT + self.preloaded_defs))).code
|
|
340
|
+
|
|
341
|
+
try:
|
|
342
|
+
if not self.agent_builder_registry:
|
|
343
|
+
raise ValueError("AgentBuilder registry is not configured")
|
|
344
|
+
|
|
345
|
+
plan_params = extract_plan_parameters(state["plan"])
|
|
346
|
+
instructions_payload = {
|
|
347
|
+
"plan": state["plan"],
|
|
348
|
+
"script": python_code,
|
|
349
|
+
"params": plan_params,
|
|
350
|
+
}
|
|
351
|
+
tool_dict = convert_tool_ids_to_dict(state["selected_tool_ids"])
|
|
352
|
+
res = self.agent_builder_registry.upsert_agent(
|
|
353
|
+
name=agent_name,
|
|
354
|
+
description=agent_description,
|
|
355
|
+
instructions=instructions_payload,
|
|
356
|
+
tools=tool_dict,
|
|
357
|
+
)
|
|
358
|
+
writer({"type": "custom", "id": generation_id, "name": "generating", "data": {"id": str(res.id), "update": bool(self.agent), "name": agent_name, "description": agent_description}})
|
|
359
|
+
tool_result = {
|
|
360
|
+
"id": str(res.id),
|
|
361
|
+
"update": bool(self.agent),
|
|
362
|
+
"name": agent_name,
|
|
363
|
+
"description": agent_description,
|
|
364
|
+
"message": f"Successfully saved the agent code and plan.",
|
|
365
|
+
}
|
|
366
|
+
except Exception:
|
|
367
|
+
tool_result = f"Displaying the final saved code:\n\n{python_code}\nFinal Name: {agent_name}\nDescription: {agent_description}"
|
|
368
|
+
|
|
369
|
+
if "functions" not in effective_previous_add_context:
|
|
370
|
+
effective_previous_add_context["functions"] = []
|
|
371
|
+
effective_previous_add_context["functions"].append(python_code)
|
|
372
|
+
|
|
373
|
+
return tool_result, effective_previous_add_context, agent_name, agent_description
|
|
@@ -9,44 +9,28 @@ Your job is to answer the user's question or perform the task they ask for.
|
|
|
9
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.
|
|
13
12
|
- 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.
|
|
14
13
|
- 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.
|
|
15
|
-
- When multiple apps are connected, or none of the apps are connected, YOU MUST ask the user to choose the application(s).
|
|
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
|
-
- 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.
|
|
14
|
+
- When multiple relevant apps are connected, or none of the apps are connected, YOU MUST ask the user to choose the application(s). Do not assume the application.
|
|
18
15
|
- If needed, feel free to ask for more information from the user (without using the `execute_ipython_cell` tool) to clarify the task.
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
- The
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
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
|
-
|
|
27
|
-
**Coding Best Practices:**
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
- 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
|
-
- Call all functions using keyword arguments only, never positional arguments.
|
|
35
|
-
- NEVER use execute_ipython_cell for:
|
|
36
|
-
- Static analysis or commentary
|
|
37
|
-
- Text that could be written as markdown
|
|
38
|
-
- Final output summarization after analysis
|
|
39
|
-
- Anything that's just formatted print statements
|
|
17
|
+
Agent Builder Scope: The following responsibilities apply when you are building/creating a reusable agent for the user.
|
|
18
|
+
- The tools `plan_agent` and `code_and_save_agent` are non-interactive sub-agents; they only draft a plan or produce code for the agent (and save it) from the context you provide.
|
|
19
|
+
- They cannot talk to the user or fetch context. YOU (the main agent) must gather all requirements, and must ensure all required context and inputs are present in the conversation history.
|
|
20
|
+
- Flow: first call `plan_agent`, share the plan and collect user feedback; only after an explicit go-ahead call `code_and_save_agent` to generate code and save the agent.
|
|
21
|
+
- If the user requests a feature you don't recognize, first use `search_functions` and `load_functions` to discover and load capabilities before invoking the sub-agents.
|
|
40
22
|
|
|
41
23
|
**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` or any LLM tools again just for summarization.
|
|
24
|
+
- 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.
|
|
43
25
|
- Always respond in github flavoured markdown format.
|
|
44
26
|
- For charts and diagrams, use mermaid chart in markdown directly.
|
|
45
27
|
- 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.
|
|
46
|
-
- For file types like images, audio, documents, etc., you must use the `upload_file`
|
|
28
|
+
- For file types like images, audio, documents, etc., you must use the `upload_file`/`save_file` function to upload the file to the server and render the link/path in the markdown response.
|
|
47
29
|
"""
|
|
48
30
|
|
|
49
31
|
AGENT_BUILDER_PLANNING_PROMPT = """TASK: Analyze the conversation history and code execution to create a step-by-step non-technical plan for a reusable function.
|
|
32
|
+
You are a sub-agent invoked by the main agent. You do not interact with the user and you do not call tools; you rely solely on the provided conversation/code history.
|
|
33
|
+
If essential details are missing, represent them as external variables in the plan (backticks), do NOT fabricate values.
|
|
50
34
|
Rules:
|
|
51
35
|
- Do NOT include the searching and loading of functions. Assume that the functions have already been loaded.
|
|
52
36
|
- The plan is a sequence of steps corresponding to the key logical steps taken to achieve the user's task in the conversation history, without focusing on technical specifics.
|
|
@@ -91,16 +75,26 @@ Note that the following tools are pre-loaded for the agent's use, and can be inl
|
|
|
91
75
|
|
|
92
76
|
|
|
93
77
|
AGENT_BUILDER_GENERATING_PROMPT = """
|
|
94
|
-
You are tasked with generating
|
|
95
|
-
|
|
78
|
+
You are tasked with generating granular, reusable Python code for an agent based on the final confirmed plan and the conversation history (user messages, assistant messages, and code executions).
|
|
79
|
+
|
|
80
|
+
You are a sub-agent invoked by the main agent. You do not interact with the user and you do not call tools. Assume any required functions are already loaded by the main agent. If a capability is referenced but not shown, still write code that calls the expected function entry points; the main agent is responsible for ensuring they are loaded.
|
|
81
|
+
|
|
82
|
+
Produce a set of small, single-purpose functions—typically one function per plan step—plus one top-level orchestrator function that calls the step functions in order to complete the task.
|
|
83
|
+
|
|
96
84
|
Rules-
|
|
97
|
-
- Do NOT include the searching and loading of functions. Assume
|
|
98
|
-
- Your response must be **ONLY Python code
|
|
99
|
-
-
|
|
100
|
-
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
-
|
|
85
|
+
- Do NOT include the searching and loading of functions. Assume required functions have already been loaded. Include imports you need.
|
|
86
|
+
- Your response must be **ONLY Python code**. No markdown or explanations.
|
|
87
|
+
- Define multiple top-level functions:
|
|
88
|
+
1) One small, clear function for each plan step (as granular as practical).
|
|
89
|
+
2) One top-level orchestrator function that calls the step functions in sequence to achieve the plan objectives.
|
|
90
|
+
- The orchestrator function's parameters **must exactly match the external variables** in the agent plan (the ones marked with backticks `` `variable_name` ``). Provide defaults exactly as specified in the plan when present. Variables in italics (i.e. enclosed in *...*) are internal and must not be orchestrator parameters.
|
|
91
|
+
- The orchestrator function MUST be declared with `def` or `async def` and be directly runnable with a single Python command (e.g., `image_generator(...)`). If it is async, assume the caller will `await` it.
|
|
92
|
+
- NEVER use asyncio or asyncio.run(). The code is executed in a ipython environment, so using await is enough.
|
|
93
|
+
- Step functions should accept only the inputs they need, return explicit outputs, and pass intermediate results forward via return values—not globals.
|
|
94
|
+
- Name functions in snake_case derived from their purpose/step. Use keyword arguments in calls; avoid positional-only calls.
|
|
95
|
+
- Keep the code self-contained and executable. Put imports at the top of the code. Do not nest functions unless strictly necessary.
|
|
96
|
+
- If previously executed code snippets exist, adapt and reuse their validated logic inside the appropriate step functions.
|
|
97
|
+
- Do not print the final output; return it from the orchestrator.
|
|
104
98
|
|
|
105
99
|
Example:
|
|
106
100
|
|
|
@@ -113,23 +107,96 @@ If the plan has:
|
|
|
113
107
|
"Upload *temp_file_path* to OneDrive folder onedrive_parent_folder(default = 'root')"
|
|
114
108
|
]
|
|
115
109
|
|
|
116
|
-
Then the
|
|
110
|
+
Then the functions should look like:
|
|
117
111
|
|
|
118
112
|
```python
|
|
119
|
-
|
|
120
|
-
#Code based on previously executed snippets
|
|
113
|
+
from typing import Dict
|
|
121
114
|
|
|
122
|
-
|
|
115
|
+
def generate_image(image_prompt: str, style: str = "comic") -> Dict:
|
|
116
|
+
# previously validated code to call Gemini
|
|
117
|
+
...
|
|
123
118
|
|
|
119
|
+
def save_temp_image(image_result: Dict) -> str:
|
|
120
|
+
# previously validated code to write bytes to a temp file
|
|
121
|
+
...
|
|
124
122
|
|
|
125
|
-
|
|
123
|
+
def upload_to_onedrive(temp_file_path: str, onedrive_parent_folder: str = "root") -> Dict:
|
|
124
|
+
# previously validated code to upload
|
|
125
|
+
...
|
|
126
|
+
|
|
127
|
+
def image_generator(image_prompt: str, style: str = "comic", onedrive_parent_folder: str = "root") -> Dict:
|
|
128
|
+
image_result = generate_image(image_prompt=image_prompt, style=style)
|
|
129
|
+
temp_file_path = save_temp_image(image_result=image_result)
|
|
130
|
+
upload_result = upload_to_onedrive(temp_file_path=temp_file_path, onedrive_parent_folder=onedrive_parent_folder)
|
|
131
|
+
return upload_result
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Use this convention consistently to generate the final code.
|
|
126
135
|
Note that the following tools are pre-loaded for the agent's use, and can be included in your code-\n
|
|
127
136
|
"""
|
|
128
137
|
|
|
129
138
|
|
|
139
|
+
AGENT_BUILDER_PLAN_PATCH_PROMPT = """
|
|
140
|
+
You are updating an existing agent plan represented as plain text (one step per line).
|
|
141
|
+
|
|
142
|
+
Output Requirements:
|
|
143
|
+
- ALWAYS output ONLY an OpenAI-style patch between the exact fences:
|
|
144
|
+
*** Begin Patch\n ... \n*** End Patch
|
|
145
|
+
- Use one or more @@ hunks with context lines (' '), deletions ('-'), and additions ('+').
|
|
146
|
+
- Make minimal edits; preserve unrelated lines and preserve step order unless a reordering is explicitly required.
|
|
147
|
+
- Do NOT include any prose, markdown, or code fences other than the patch fences.
|
|
148
|
+
|
|
149
|
+
Plan content constraints (apply while patching; do not rewrite the whole plan):
|
|
150
|
+
- Keep steps non-technical and human-friendly, describing goals/actions rather than implementation details.
|
|
151
|
+
- External inputs must be denoted as `variable_name`; include defaults as `variable_name(default = value)` when appropriate.
|
|
152
|
+
- Intermediate/internal variables must be italicized like *temp_file_path* (never in backticks).
|
|
153
|
+
- Avoid using internal IDs/keys as plan inputs. Keep inputs human-facing.
|
|
154
|
+
- Be concise; avoid unnecessary sub-steps. Prefer a small number of clear steps.
|
|
155
|
+
- Preserve existing variable names and defaults unless the context clearly requires a change.
|
|
156
|
+
- If removing or reordering steps, ensure downstream references remain coherent (do not reference a removed step).
|
|
157
|
+
- Preserve existing bullet/line formatting; one step per line.
|
|
158
|
+
- Idempotence: make the smallest delta that satisfies the requested update.
|
|
159
|
+
- For steps where the assistant's intelligence was used outside of the code to infer/decide/analyse something, replace it with the use of *llm__* functions in the plan if required.
|
|
160
|
+
|
|
161
|
+
Context will include the current plan and conversation history.
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
AGENT_BUILDER_CODE_PATCH_PROMPT = """
|
|
166
|
+
You are updating existing Python code for an agent.
|
|
167
|
+
|
|
168
|
+
Output Requirements:
|
|
169
|
+
- ALWAYS output ONLY an OpenAI-style patch between the exact fences:
|
|
170
|
+
*** Begin Patch\n ... \n*** End Patch
|
|
171
|
+
- Use one or more @@ hunks with context (' '), deletions ('-'), additions ('+').
|
|
172
|
+
- Make minimal edits; preserve unrelated code and keep function/public API signatures stable unless the plan demands changes.
|
|
173
|
+
- Do NOT include any prose or markdown outside the patch.
|
|
174
|
+
- Do NOT wrap the patch in triple backticks; only use the patch fences shown above.
|
|
175
|
+
|
|
176
|
+
Context will include the current code and the confirmed plan.
|
|
177
|
+
|
|
178
|
+
Structural constraints (apply while patching; do not rewrite whole file):
|
|
179
|
+
- Maintain small, single-purpose functions (typically one per plan step) plus ONE top-level orchestrator that invokes them in order.
|
|
180
|
+
- The orchestrator parameters must exactly match the external variables in the plan, including defaults.
|
|
181
|
+
- Preserve function names and public signatures unless the plan explicitly requires a change; if a signature changes, update orchestrator and all call sites consistently in the same patch.
|
|
182
|
+
- Keep imports at the top; pass data via return values (no new globals); avoid nested functions unless necessary.
|
|
183
|
+
- Do not print final results; ensure the orchestrator returns the final value.
|
|
184
|
+
- Prefer adapting and reusing previously validated logic inside affected functions; do not rewrite unrelated functions.
|
|
185
|
+
|
|
186
|
+
Additional rules to ensure reliable, minimal patches:
|
|
187
|
+
- Environment: Code runs in IPython; if a function is async, callers will `await` it. Do NOT use `asyncio.run()` or create event loops.
|
|
188
|
+
- Calling style: Use keyword arguments (no positional-only calls) when you modify call sites.
|
|
189
|
+
- Imports: Add only necessary imports; deduplicate and keep existing import order/formatting when possible.
|
|
190
|
+
- Formatting: Preserve existing formatting, indentation, comments, and docstrings for unchanged code. Do NOT reformat the file.
|
|
191
|
+
- Exceptions/IO: Preserve existing error handling semantics; do not introduce interactive input or random printing.
|
|
192
|
+
- Idempotence: Make the smallest change set that satisfies the plan; avoid broad refactors.
|
|
193
|
+
"""
|
|
194
|
+
|
|
130
195
|
AGENT_BUILDER_META_PROMPT = """
|
|
131
196
|
You are preparing metadata for a reusable agent based on the confirmed step-by-step plan.
|
|
132
197
|
|
|
198
|
+
You are a sub-agent invoked by the main agent. You do not interact with the user and you do not call tools; rely only on the provided context.
|
|
199
|
+
|
|
133
200
|
TASK: Create a concise, human-friendly name and a short description for the agent.
|
|
134
201
|
|
|
135
202
|
INPUTS:
|