xgae 0.1.17__py3-none-any.whl → 0.1.18__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of xgae might be problematic. Click here for more details.
- xgae/engine/engine_base.py +4 -1
- xgae/engine/mcp_tool_box.py +32 -19
- xgae/engine/prompt_builder.py +17 -2
- xgae/engine/responser/non_stream_responser.py +1 -1
- xgae/engine/responser/responser_base.py +25 -32
- xgae/engine/responser/stream_responser.py +10 -16
- xgae/engine/task_engine.py +8 -4
- xgae/tools/without_general_tools_app.py +3 -3
- {xgae-0.1.17.dist-info → xgae-0.1.18.dist-info}/METADATA +1 -1
- xgae-0.1.18.dist-info/RECORD +21 -0
- {xgae-0.1.17.dist-info → xgae-0.1.18.dist-info}/entry_points.txt +1 -0
- xgae-0.1.17.dist-info/RECORD +0 -21
- {xgae-0.1.17.dist-info → xgae-0.1.18.dist-info}/WHEEL +0 -0
xgae/engine/engine_base.py
CHANGED
|
@@ -21,9 +21,12 @@ class XGATaskResult(TypedDict, total=False):
|
|
|
21
21
|
content: str
|
|
22
22
|
attachments: Optional[List[str]]
|
|
23
23
|
|
|
24
|
+
XGAToolType = Literal["general", "custom", "agent"]
|
|
25
|
+
|
|
24
26
|
@dataclass
|
|
25
27
|
class XGAToolSchema:
|
|
26
28
|
tool_name: str
|
|
29
|
+
tool_type: XGAToolType
|
|
27
30
|
server_name: str
|
|
28
31
|
description: str
|
|
29
32
|
input_schema: Dict[str, Any]
|
|
@@ -46,7 +49,7 @@ class XGAToolBox(ABC):
|
|
|
46
49
|
pass
|
|
47
50
|
|
|
48
51
|
@abstractmethod
|
|
49
|
-
def get_task_tool_schemas(self, task_id: str, type:
|
|
52
|
+
def get_task_tool_schemas(self, task_id: str, type: XGAToolType) -> List[XGAToolSchema]:
|
|
50
53
|
pass
|
|
51
54
|
|
|
52
55
|
@abstractmethod
|
xgae/engine/mcp_tool_box.py
CHANGED
|
@@ -7,10 +7,11 @@ from typing import List, Any, Dict, Optional, Literal, override
|
|
|
7
7
|
from langchain_mcp_adapters.client import MultiServerMCPClient
|
|
8
8
|
from langchain_mcp_adapters.tools import load_mcp_tools
|
|
9
9
|
|
|
10
|
-
from xgae.engine.engine_base import XGAError, XGAToolSchema, XGAToolBox, XGAToolResult
|
|
10
|
+
from xgae.engine.engine_base import XGAError, XGAToolSchema, XGAToolBox, XGAToolResult, XGAToolType
|
|
11
11
|
|
|
12
12
|
class XGAMcpToolBox(XGAToolBox):
|
|
13
13
|
GENERAL_MCP_SERVER_NAME = "xga_general"
|
|
14
|
+
AGENT_MCP_SERVER_PREFIX = "_@_"
|
|
14
15
|
|
|
15
16
|
def __init__(self,
|
|
16
17
|
custom_mcp_server_file: Optional[str] = None,
|
|
@@ -37,7 +38,7 @@ class XGAMcpToolBox(XGAToolBox):
|
|
|
37
38
|
@override
|
|
38
39
|
async def creat_task_tool_box(self, task_id: str, general_tools: List[str], custom_tools: List[str]):
|
|
39
40
|
task_tool_schemas = {}
|
|
40
|
-
general_tool_schemas = self.mcp_tool_schemas.get(
|
|
41
|
+
general_tool_schemas = self.mcp_tool_schemas.get(self.GENERAL_MCP_SERVER_NAME, {})
|
|
41
42
|
if "*" in general_tools:
|
|
42
43
|
task_tool_schemas = {tool_schema.tool_name: tool_schema for tool_schema in general_tool_schemas}
|
|
43
44
|
else:
|
|
@@ -49,7 +50,7 @@ class XGAMcpToolBox(XGAToolBox):
|
|
|
49
50
|
if len(custom_tools) == 1 and custom_tools[0] == "*":
|
|
50
51
|
custom_tools = []
|
|
51
52
|
for server_name in self.mcp_server_names:
|
|
52
|
-
if server_name !=
|
|
53
|
+
if server_name != self.GENERAL_MCP_SERVER_NAME:
|
|
53
54
|
custom_tools.append(f"{server_name}.*")
|
|
54
55
|
|
|
55
56
|
for server_tool_name in custom_tools:
|
|
@@ -76,7 +77,7 @@ class XGAMcpToolBox(XGAToolBox):
|
|
|
76
77
|
|
|
77
78
|
@override
|
|
78
79
|
async def destroy_task_tool_box(self, task_id: str):
|
|
79
|
-
tool_schemas = self.get_task_tool_schemas(task_id,
|
|
80
|
+
tool_schemas = self.get_task_tool_schemas(task_id, "general")
|
|
80
81
|
if len(tool_schemas) > 0:
|
|
81
82
|
await self.call_tool(task_id, "end_task", {'task_id': task_id})
|
|
82
83
|
self.task_tool_schemas.pop(task_id, None)
|
|
@@ -88,14 +89,12 @@ class XGAMcpToolBox(XGAToolBox):
|
|
|
88
89
|
return task_tool_names
|
|
89
90
|
|
|
90
91
|
@override
|
|
91
|
-
def get_task_tool_schemas(self, task_id: str,
|
|
92
|
+
def get_task_tool_schemas(self, task_id: str, tool_type: XGAToolType) -> List[XGAToolSchema]:
|
|
92
93
|
task_tool_schemas = []
|
|
93
94
|
|
|
94
95
|
all_task_tool_schemas = self.task_tool_schemas.get(task_id, {})
|
|
95
96
|
for tool_schema in all_task_tool_schemas.values():
|
|
96
|
-
if
|
|
97
|
-
task_tool_schemas.append(tool_schema)
|
|
98
|
-
elif type == "custom_tool" and tool_schema.server_name != self.GENERAL_MCP_SERVER_NAME:
|
|
97
|
+
if tool_schema.tool_type == tool_type:
|
|
99
98
|
task_tool_schemas.append(tool_schema)
|
|
100
99
|
|
|
101
100
|
return task_tool_schemas
|
|
@@ -114,16 +113,16 @@ class XGAMcpToolBox(XGAToolBox):
|
|
|
114
113
|
async with self._mcp_client.session(server_name) as session:
|
|
115
114
|
tools = await load_mcp_tools(session)
|
|
116
115
|
mcp_tool = next((t for t in tools if t.name == tool_name), None)
|
|
117
|
-
|
|
116
|
+
|
|
118
117
|
if mcp_tool:
|
|
119
118
|
tool_args = args or {}
|
|
120
|
-
|
|
119
|
+
tool_type = self._get_tool_type(server_name)
|
|
120
|
+
if tool_type == "general" or tool_type == "agent":
|
|
121
121
|
tool_args = dict({'task_id': task_id}, **tool_args)
|
|
122
|
-
is_general_tool = True
|
|
123
122
|
|
|
124
123
|
try:
|
|
125
124
|
tool_result = await mcp_tool.arun(tool_args)
|
|
126
|
-
if
|
|
125
|
+
if tool_type == "general":
|
|
127
126
|
tool_result = json.loads(tool_result)
|
|
128
127
|
result = XGAToolResult(success=tool_result['success'], output=str(tool_result['output']))
|
|
129
128
|
else:
|
|
@@ -144,11 +143,17 @@ class XGAMcpToolBox(XGAToolBox):
|
|
|
144
143
|
if not self.is_loaded_tool_schemas:
|
|
145
144
|
for server_name in self.mcp_server_names:
|
|
146
145
|
self.mcp_tool_schemas[server_name] = []
|
|
147
|
-
|
|
146
|
+
try:
|
|
147
|
+
mcp_tools = await self._mcp_client.get_tools(server_name=server_name)
|
|
148
|
+
except Exception as e:
|
|
149
|
+
logging.error(f"### McpToolBox load_mcp_tools_schema: Langchain mcp get_tools failed, "
|
|
150
|
+
f"need start mcp server '{server_name}' !")
|
|
151
|
+
continue
|
|
148
152
|
|
|
153
|
+
tool_type = self._get_tool_type(server_name)
|
|
149
154
|
for tool in mcp_tools:
|
|
150
155
|
input_schema = tool.args_schema
|
|
151
|
-
if
|
|
156
|
+
if tool_type == "general" or tool_type == "agent":
|
|
152
157
|
input_schema['properties'].pop("task_id", None)
|
|
153
158
|
if 'task_id' in input_schema['required']:
|
|
154
159
|
input_schema['required'].remove('task_id')
|
|
@@ -158,6 +163,7 @@ class XGAMcpToolBox(XGAToolBox):
|
|
|
158
163
|
|
|
159
164
|
metadata = tool.metadata or {}
|
|
160
165
|
tool_schema = XGAToolSchema(tool_name=tool.name,
|
|
166
|
+
tool_type=tool_type,
|
|
161
167
|
server_name=server_name,
|
|
162
168
|
description=tool.description,
|
|
163
169
|
input_schema=input_schema,
|
|
@@ -169,8 +175,8 @@ class XGAMcpToolBox(XGAToolBox):
|
|
|
169
175
|
self.is_loaded_tool_schemas = False
|
|
170
176
|
await self.load_mcp_tools_schema()
|
|
171
177
|
|
|
172
|
-
|
|
173
|
-
def _load_mcp_servers_config(mcp_config_path: str) -> Dict[str, Any]:
|
|
178
|
+
|
|
179
|
+
def _load_mcp_servers_config(self, mcp_config_path: str) -> Dict[str, Any]:
|
|
174
180
|
try:
|
|
175
181
|
if os.path.exists(mcp_config_path):
|
|
176
182
|
with open(mcp_config_path, 'r', encoding="utf-8") as f:
|
|
@@ -192,6 +198,13 @@ class XGAMcpToolBox(XGAToolBox):
|
|
|
192
198
|
logging.error(f"McpToolBox load_mcp_servers_config: Failed to load MCP servers config: {e}")
|
|
193
199
|
return {'mcpServers': {}}
|
|
194
200
|
|
|
201
|
+
def _get_tool_type(self, server_name: str) -> XGAToolType:
|
|
202
|
+
tool_type: XGAToolType = "custom"
|
|
203
|
+
if server_name == self.GENERAL_MCP_SERVER_NAME:
|
|
204
|
+
tool_type = "general"
|
|
205
|
+
elif server_name.startswith(self.AGENT_MCP_SERVER_PREFIX):
|
|
206
|
+
tool_type = "agent"
|
|
207
|
+
return tool_type
|
|
195
208
|
|
|
196
209
|
if __name__ == "__main__":
|
|
197
210
|
import asyncio
|
|
@@ -207,14 +220,14 @@ if __name__ == "__main__":
|
|
|
207
220
|
|
|
208
221
|
task_id = "task1"
|
|
209
222
|
await mcp_tool_box.load_mcp_tools_schema()
|
|
210
|
-
await mcp_tool_box.creat_task_tool_box(task_id=task_id, general_tools=["*"], custom_tools=["
|
|
211
|
-
tool_schemas = mcp_tool_box.get_task_tool_schemas(task_id, "
|
|
223
|
+
await mcp_tool_box.creat_task_tool_box(task_id=task_id, general_tools=["*"], custom_tools=["*"])
|
|
224
|
+
tool_schemas = mcp_tool_box.get_task_tool_schemas(task_id, "general")
|
|
212
225
|
print("general_tools_schemas" + "*"*50)
|
|
213
226
|
for tool_schema in tool_schemas:
|
|
214
227
|
print(asdict(tool_schema))
|
|
215
228
|
print()
|
|
216
229
|
|
|
217
|
-
tool_schemas = mcp_tool_box.get_task_tool_schemas(task_id, "
|
|
230
|
+
tool_schemas = mcp_tool_box.get_task_tool_schemas(task_id, "custom")
|
|
218
231
|
print("custom_tools_schemas" + "*" * 50)
|
|
219
232
|
for tool_schema in tool_schemas:
|
|
220
233
|
print(asdict(tool_schema))
|
xgae/engine/prompt_builder.py
CHANGED
|
@@ -11,7 +11,11 @@ class XGAPromptBuilder():
|
|
|
11
11
|
def __init__(self, system_prompt: Optional[str] = None):
|
|
12
12
|
self.system_prompt = system_prompt
|
|
13
13
|
|
|
14
|
-
def build_task_prompt(self,
|
|
14
|
+
def build_task_prompt(self,
|
|
15
|
+
model_name: str,
|
|
16
|
+
general_tool_schemas: List[XGAToolSchema],
|
|
17
|
+
custom_tool_schemas: List[XGAToolSchema],
|
|
18
|
+
agent_tool_schemas: List[XGAToolSchema])-> str:
|
|
15
19
|
if self.system_prompt is None:
|
|
16
20
|
self.system_prompt = self._load_default_system_prompt(model_name)
|
|
17
21
|
|
|
@@ -23,6 +27,9 @@ class XGAPromptBuilder():
|
|
|
23
27
|
tool_prompt = self.build_custom_tool_prompt(custom_tool_schemas)
|
|
24
28
|
task_prompt = task_prompt + "\n" + tool_prompt
|
|
25
29
|
|
|
30
|
+
tool_prompt = self.build_agent_tool_prompt(agent_tool_schemas)
|
|
31
|
+
task_prompt = task_prompt + "\n" + tool_prompt
|
|
32
|
+
|
|
26
33
|
return task_prompt
|
|
27
34
|
|
|
28
35
|
def build_general_tool_prompt(self, tool_schemas:List[XGAToolSchema])-> str:
|
|
@@ -61,10 +68,18 @@ class XGAPromptBuilder():
|
|
|
61
68
|
|
|
62
69
|
|
|
63
70
|
def build_custom_tool_prompt(self, tool_schemas:List[XGAToolSchema])-> str:
|
|
71
|
+
tool_prompt = self.build_mcp_tool_prompt("templates/custom_tool_prompt_template.txt", tool_schemas)
|
|
72
|
+
return tool_prompt
|
|
73
|
+
|
|
74
|
+
def build_agent_tool_prompt(self, tool_schemas:List[XGAToolSchema])-> str:
|
|
75
|
+
tool_prompt = self.build_mcp_tool_prompt("templates/agent_tool_prompt_template.txt", tool_schemas)
|
|
76
|
+
return tool_prompt
|
|
77
|
+
|
|
78
|
+
def build_mcp_tool_prompt(self, file_path: str, tool_schemas:List[XGAToolSchema])-> str:
|
|
64
79
|
tool_prompt = ""
|
|
65
80
|
tool_schemas = tool_schemas or []
|
|
66
81
|
if len(tool_schemas) > 0:
|
|
67
|
-
tool_prompt = read_file(
|
|
82
|
+
tool_prompt = read_file(file_path)
|
|
68
83
|
tool_info = ""
|
|
69
84
|
for tool_schema in tool_schemas:
|
|
70
85
|
description = tool_schema.description if tool_schema.description else 'No description available'
|
|
@@ -64,7 +64,7 @@ class NonStreamTaskResponser(TaskResponseProcessor):
|
|
|
64
64
|
tool_start_msg = self._add_tool_start_message(tool_context)
|
|
65
65
|
yield tool_start_msg
|
|
66
66
|
|
|
67
|
-
tool_message = self._add_tool_messsage(
|
|
67
|
+
tool_message = self._add_tool_messsage(tool_context, self.xml_adding_strategy)
|
|
68
68
|
|
|
69
69
|
tool_completed_msg = self._add_tool_completed_message(tool_context, tool_message['message_id'])
|
|
70
70
|
yield tool_completed_msg
|
|
@@ -376,19 +376,31 @@ class TaskResponseProcessor(ABC):
|
|
|
376
376
|
logging.info(f"TaskProcessor execute_tools_in_parallel: Execution completed for {len(results)} tools, total {tool_num} tools)")
|
|
377
377
|
return processed_results
|
|
378
378
|
|
|
379
|
+
def _create_tool_context(self,
|
|
380
|
+
tool_call: Dict[str, Any],
|
|
381
|
+
tool_index: int,
|
|
382
|
+
assistant_message_id: Optional[str] = None,
|
|
383
|
+
parsing_details: Optional[Dict[str, Any]] = None,
|
|
384
|
+
result: Optional[XGAToolResult] = None,
|
|
385
|
+
) -> ToolExecutionContext:
|
|
386
|
+
"""Create a tool execution context with display name and parsing details populated."""
|
|
387
|
+
return ToolExecutionContext(
|
|
388
|
+
tool_call = tool_call,
|
|
389
|
+
tool_index = tool_index,
|
|
390
|
+
function_name = tool_call['function_name'],
|
|
391
|
+
xml_tag_name = tool_call['xml_tag_name'],
|
|
392
|
+
assistant_message_id = assistant_message_id,
|
|
393
|
+
parsing_details = parsing_details,
|
|
394
|
+
result = result
|
|
395
|
+
)
|
|
379
396
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
result: XGAToolResult,
|
|
383
|
-
strategy: XmlAddingStrategy = "assistant_message",
|
|
384
|
-
assistant_message_id: Optional[str] = None,
|
|
385
|
-
parsing_details: Optional[Dict[str, Any]] = None
|
|
386
|
-
) -> Optional[Dict[str, Any]]: # Return the full message object
|
|
397
|
+
|
|
398
|
+
def _add_tool_messsage(self,context:ToolExecutionContext, strategy: XmlAddingStrategy) -> Optional[Dict[str, Any]]: # Return the full message object
|
|
387
399
|
# Create two versions of the structured result
|
|
388
400
|
# Rich version for the frontend
|
|
389
|
-
result_for_frontend = self._create_structured_tool_result(tool_call, result, parsing_details, for_llm=False)
|
|
401
|
+
result_for_frontend = self._create_structured_tool_result(context.tool_call, context.result, context.parsing_details, for_llm=False)
|
|
390
402
|
# Concise version for the LLM
|
|
391
|
-
result_for_llm = self._create_structured_tool_result(tool_call, result, parsing_details, for_llm=True)
|
|
403
|
+
result_for_llm = self._create_structured_tool_result(context.tool_call, context.result, context.parsing_details, for_llm=True)
|
|
392
404
|
|
|
393
405
|
# Add the message with the appropriate role to the conversation history
|
|
394
406
|
# This allows the LLM to see the tool result in subsequent interactions
|
|
@@ -399,11 +411,11 @@ class TaskResponseProcessor(ABC):
|
|
|
399
411
|
}
|
|
400
412
|
|
|
401
413
|
metadata = {}
|
|
402
|
-
if assistant_message_id:
|
|
403
|
-
metadata['assistant_message_id'] = assistant_message_id
|
|
414
|
+
if context.assistant_message_id:
|
|
415
|
+
metadata['assistant_message_id'] = context.assistant_message_id
|
|
404
416
|
|
|
405
|
-
if parsing_details:
|
|
406
|
-
metadata['parsing_details'] = parsing_details
|
|
417
|
+
if context.parsing_details:
|
|
418
|
+
metadata['parsing_details'] = context.parsing_details
|
|
407
419
|
|
|
408
420
|
metadata['frontend_content'] = result_for_frontend
|
|
409
421
|
|
|
@@ -455,25 +467,6 @@ class TaskResponseProcessor(ABC):
|
|
|
455
467
|
return structured_result
|
|
456
468
|
|
|
457
469
|
|
|
458
|
-
def _create_tool_context(self,
|
|
459
|
-
tool_call: Dict[str, Any],
|
|
460
|
-
tool_index: int,
|
|
461
|
-
assistant_message_id: Optional[str] = None,
|
|
462
|
-
parsing_details: Optional[Dict[str, Any]] = None,
|
|
463
|
-
result: Optional[XGAToolResult] = None,
|
|
464
|
-
) -> ToolExecutionContext:
|
|
465
|
-
"""Create a tool execution context with display name and parsing details populated."""
|
|
466
|
-
return ToolExecutionContext(
|
|
467
|
-
tool_call = tool_call,
|
|
468
|
-
tool_index = tool_index,
|
|
469
|
-
function_name = tool_call['function_name'],
|
|
470
|
-
xml_tag_name = tool_call['xml_tag_name'],
|
|
471
|
-
assistant_message_id = assistant_message_id,
|
|
472
|
-
parsing_details = parsing_details,
|
|
473
|
-
result = result
|
|
474
|
-
)
|
|
475
|
-
|
|
476
|
-
|
|
477
470
|
def _add_tool_start_message(self, context: ToolExecutionContext) -> Optional[Dict[str, Any]]:
|
|
478
471
|
"""Formats, saves, and returns a tool started status message."""
|
|
479
472
|
content = {
|
|
@@ -43,8 +43,9 @@ class StreamTaskResponser(TaskResponseProcessor):
|
|
|
43
43
|
chunk_content = llm_chunk_msg.content
|
|
44
44
|
accumulated_content += chunk_content
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
xml_tool_chunks = self._extract_xml_chunks(accumulated_content)
|
|
47
|
+
xml_tool_chunk_len = len(xml_tool_chunks)
|
|
48
|
+
if self.max_xml_tool_calls <= 0 or xml_tool_chunk_len <= self.max_xml_tool_calls:
|
|
48
49
|
if use_assistant_chunk_msg:
|
|
49
50
|
message_data = {"role": "assistant", "content": chunk_content}
|
|
50
51
|
metadata = {"sequence": msg_sequence}
|
|
@@ -57,19 +58,13 @@ class StreamTaskResponser(TaskResponseProcessor):
|
|
|
57
58
|
else:
|
|
58
59
|
finish_reason = "xml_tool_limit_reached"
|
|
59
60
|
logging.warning(f"StreamResp: Over XML Tool Limit, finish_reason='xml_tool_limit_reached', "
|
|
60
|
-
f"
|
|
61
|
+
f"xml_tool_chunk_len={xml_tool_chunk_len}")
|
|
61
62
|
break
|
|
62
63
|
|
|
64
|
+
parsed_xml_data = self._parse_xml_tool_calls(accumulated_content)
|
|
63
65
|
if finish_reason == "xml_tool_limit_reached":
|
|
64
|
-
|
|
65
|
-
if len(xml_chunks) > self.max_xml_tool_calls:
|
|
66
|
-
limited_chunks = xml_chunks[:self.max_xml_tool_calls]
|
|
67
|
-
if limited_chunks:
|
|
68
|
-
last_chunk = limited_chunks[-1]
|
|
69
|
-
last_chunk_pos = accumulated_content.find(last_chunk) + len(last_chunk)
|
|
70
|
-
accumulated_content = accumulated_content[:last_chunk_pos]
|
|
66
|
+
parsed_xml_data = parsed_xml_data[:self.max_xml_tool_calls]
|
|
71
67
|
|
|
72
|
-
parsed_xml_data = self._parse_xml_tool_calls(accumulated_content)
|
|
73
68
|
should_auto_continue = (can_auto_continue and finish_reason == 'length')
|
|
74
69
|
|
|
75
70
|
self.root_span.event(name=f"stream_processor_start[{self.task_no}]({auto_continue_count})", level="DEFAULT",
|
|
@@ -77,13 +72,12 @@ class StreamTaskResponser(TaskResponseProcessor):
|
|
|
77
72
|
f"parsed_xml_data_len={len(parsed_xml_data)}, accumulated_content_len={len(accumulated_content)}, "
|
|
78
73
|
f"should_auto_continue={should_auto_continue}")
|
|
79
74
|
|
|
80
|
-
|
|
75
|
+
assistant_msg_id = None
|
|
81
76
|
if accumulated_content and not should_auto_continue:
|
|
82
77
|
message_data = {"role": "assistant", "content": accumulated_content}
|
|
83
78
|
assistant_msg = self.add_response_message(type="assistant", content=message_data, is_llm_message=True)
|
|
84
79
|
yield assistant_msg
|
|
85
|
-
|
|
86
|
-
assistant_msg_id = assistant_msg['message_id'] if assistant_msg else None
|
|
80
|
+
assistant_msg_id = assistant_msg['message_id']
|
|
87
81
|
|
|
88
82
|
tool_calls_to_execute = [item['tool_call'] for item in parsed_xml_data]
|
|
89
83
|
if len(tool_calls_to_execute) > 0 and not should_auto_continue:
|
|
@@ -94,12 +88,12 @@ class StreamTaskResponser(TaskResponseProcessor):
|
|
|
94
88
|
tool_call = parsed_xml_item['tool_call']
|
|
95
89
|
parsing_details = parsed_xml_item['parsing_details']
|
|
96
90
|
|
|
97
|
-
tool_context = self._create_tool_context(tool_call, tool_index, assistant_msg_id,parsing_details, tool_result)
|
|
91
|
+
tool_context = self._create_tool_context(tool_call, tool_index, assistant_msg_id, parsing_details, tool_result)
|
|
98
92
|
|
|
99
93
|
tool_start_msg = self._add_tool_start_message(tool_context)
|
|
100
94
|
yield tool_start_msg
|
|
101
95
|
|
|
102
|
-
tool_message = self._add_tool_messsage(
|
|
96
|
+
tool_message = self._add_tool_messsage(tool_context, self.xml_adding_strategy)
|
|
103
97
|
|
|
104
98
|
tool_completed_msg = self._add_tool_completed_message(tool_context, tool_message['message_id'])
|
|
105
99
|
yield tool_completed_msg
|
xgae/engine/task_engine.py
CHANGED
|
@@ -114,10 +114,14 @@ class XGATaskEngine:
|
|
|
114
114
|
await self.tool_box.load_mcp_tools_schema()
|
|
115
115
|
|
|
116
116
|
await self.tool_box.creat_task_tool_box(self.task_id, general_tools, custom_tools)
|
|
117
|
-
general_tool_schemas = self.tool_box.get_task_tool_schemas(self.task_id, "
|
|
118
|
-
custom_tool_schemas = self.tool_box.get_task_tool_schemas(self.task_id, "
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
general_tool_schemas = self.tool_box.get_task_tool_schemas(self.task_id, "general")
|
|
118
|
+
custom_tool_schemas = self.tool_box.get_task_tool_schemas(self.task_id, "custom")
|
|
119
|
+
agent_tool_schemas = self.tool_box.get_task_tool_schemas(self.task_id, "agent")
|
|
120
|
+
|
|
121
|
+
self.task_prompt = self.prompt_builder.build_task_prompt(self.model_name,
|
|
122
|
+
general_tool_schemas,
|
|
123
|
+
custom_tool_schemas,
|
|
124
|
+
agent_tool_schemas)
|
|
121
125
|
|
|
122
126
|
logging.info("*" * 10 + f" XGATaskEngine Task'{self.task_id}' Initialized " + "*" * 10)
|
|
123
127
|
logging.info(f"model_name={self.model_name}, is_stream={self.is_stream}")
|
|
@@ -10,7 +10,7 @@ mcp = FastMCP(name="XGAE Message Tools")
|
|
|
10
10
|
@mcp.tool(
|
|
11
11
|
description="""A special tool to indicate you have completed all tasks and are about to enter complete state. Use ONLY when: 1) All tasks in todo.md are marked complete [x], 2) The user's original request has been fully addressed, 3) There are no pending actions or follow-ups required, 4) You've delivered all final outputs and results to the user. IMPORTANT: This is the ONLY way to properly terminate execution. Never use this tool unless ALL tasks are complete and verified. Always ensure you've provided all necessary outputs and references before using this tool. Include relevant attachments when the completion relates to specific files or resources."""
|
|
12
12
|
)
|
|
13
|
-
|
|
13
|
+
def complete(task_id: str,
|
|
14
14
|
text: Annotated[Optional[str], Field(default=None,
|
|
15
15
|
description="Completion summary. Include: 1) Task summary 2) Key deliverables 3) Next steps 4) Impact achieved")],
|
|
16
16
|
attachments: Annotated[Optional[str], Field(default=None,
|
|
@@ -23,7 +23,7 @@ async def complete(task_id: str,
|
|
|
23
23
|
@mcp.tool(
|
|
24
24
|
description="""Ask user a question and wait for response. Use for: 1) Requesting clarification on ambiguous requirements, 2) Seeking confirmation before proceeding with high-impact changes, 3) Gathering additional information needed to complete a task, 4) Offering options and requesting user preference, 5) Validating assumptions when critical to task success, 6) When encountering unclear or ambiguous results during task execution, 7) When tool results don't match expectations, 8) For natural conversation and follow-up questions, 9) When research reveals multiple entities with the same name, 10) When user requirements are unclear or could be interpreted differently. IMPORTANT: Use this tool when user input is essential to proceed. Always provide clear context and options when applicable. Use natural, conversational language that feels like talking with a helpful friend. Include relevant attachments when the question relates to specific files or resources. CRITICAL: When you discover ambiguity (like multiple people with the same name), immediately stop and ask for clarification rather than making assumptions."""
|
|
25
25
|
)
|
|
26
|
-
|
|
26
|
+
def ask(task_id: str,
|
|
27
27
|
text: Annotated[str, Field(
|
|
28
28
|
description="Question text to present to user. Include: 1) Clear question/request 2) Context why input is needed 3) Available options 4) Impact of choices 5) Relevant constraints")],
|
|
29
29
|
attachments: Annotated[Optional[str], Field(default=None,
|
|
@@ -36,7 +36,7 @@ async def ask(task_id: str,
|
|
|
36
36
|
@mcp.tool(
|
|
37
37
|
description="end task, destroy sandbox"
|
|
38
38
|
)
|
|
39
|
-
|
|
39
|
+
def end_task(task_id: str) :
|
|
40
40
|
print(f"<XGAETools-end_task> task_id: {task_id}")
|
|
41
41
|
return XGAToolResult(success=True, output="")
|
|
42
42
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
xgae/__init__.py,sha256=OEUd9y9AoGBd3xYerdTTpz9xl4NWkmXeq1a2eil7Qro,72
|
|
2
|
+
xgae/cli_app.py,sha256=ieTaS0b532P_8g9Mz2xda8TOZwYD2hKGnNZiarADAM0,3000
|
|
3
|
+
xgae/engine/engine_base.py,sha256=RR1em2wHiM2jP-peHt77SKdHWjnYOjdIIzN93zT61cA,1715
|
|
4
|
+
xgae/engine/mcp_tool_box.py,sha256=G4hKIMguwg1cO4Us2NMfdloYim8kuikVyVTIPucJr7o,10903
|
|
5
|
+
xgae/engine/prompt_builder.py,sha256=6I5rjgvNJ27QJ8DDuBTplutoPZdGs9LYFv3TSgT7zmc,5045
|
|
6
|
+
xgae/engine/task_engine.py,sha256=_GfIpWGBd83jf2xnS0vDvgyQR0mqQSb6ZrGoBFFrMt4,21249
|
|
7
|
+
xgae/engine/task_langfuse.py,sha256=n2bajsHq2Zt3jetel8cSlN2lo42mZgTmbR4Zbx9JvsM,2416
|
|
8
|
+
xgae/engine/responser/non_stream_responser.py,sha256=zEJjqCgZVe2B8gkHYRFU7tmBV834f7w2a4Ws25P1N-c,5289
|
|
9
|
+
xgae/engine/responser/responser_base.py,sha256=jhl1Bdz1Fs3KofGEymThNXlQuCORFTTkTAR_U47krds,24403
|
|
10
|
+
xgae/engine/responser/stream_responser.py,sha256=cv4UGcxj8OksEogW7DUGTCvSJabu-DF6GceFyUwaXI4,7627
|
|
11
|
+
xgae/tools/without_general_tools_app.py,sha256=KqsdhxD3hvTpiygaGUVHysRFjvv_1A8zOwMKN1J0J0U,3821
|
|
12
|
+
xgae/utils/__init__.py,sha256=ElaGS-zdeZeu6is41u3Ny7lkvhg7BDSK-jMNg9j6K5A,499
|
|
13
|
+
xgae/utils/json_helpers.py,sha256=WD4G5U9Dh8N6J9O0L5wGyqj-NHi09kcXHGdLD_26nlc,3607
|
|
14
|
+
xgae/utils/llm_client.py,sha256=mWRtvtSMk_8NuzFReT9x52ayHlCNVZMZAltD6TQ-xZ8,14404
|
|
15
|
+
xgae/utils/misc.py,sha256=aMWOvJ9VW52q-L9Lkjl1hvXqLwpJAmyxA-Z8jzqFG0U,907
|
|
16
|
+
xgae/utils/setup_env.py,sha256=MqNG0c2QQBDFU1kI8frxr9kB5d08Mmi3QZ1OoorgIa0,2662
|
|
17
|
+
xgae/utils/xml_tool_parser.py,sha256=Mb0d8kBrfyAEvUwW1Nqir-3BgxZRr0ZX3WymQouuFSo,4859
|
|
18
|
+
xgae-0.1.18.dist-info/METADATA,sha256=zMbJrDIxmWY79uRRluq-HuNOtxdE7jOQELEcRvVB57w,310
|
|
19
|
+
xgae-0.1.18.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
20
|
+
xgae-0.1.18.dist-info/entry_points.txt,sha256=KdL6b_heFPyb1XIq5_L8Rgydpn64VDExFZafU_Qd9ow,222
|
|
21
|
+
xgae-0.1.18.dist-info/RECORD,,
|
xgae-0.1.17.dist-info/RECORD
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
xgae/__init__.py,sha256=OEUd9y9AoGBd3xYerdTTpz9xl4NWkmXeq1a2eil7Qro,72
|
|
2
|
-
xgae/cli_app.py,sha256=ieTaS0b532P_8g9Mz2xda8TOZwYD2hKGnNZiarADAM0,3000
|
|
3
|
-
xgae/engine/engine_base.py,sha256=-QZqLRbQdwRUfbY4l3i7dFfMB-BL267a-wGZR9bMPLc,1662
|
|
4
|
-
xgae/engine/mcp_tool_box.py,sha256=iAWUWP_goHAEeYYMUvTKiMkR2VkEOoRtNmjLV9HaIUg,10415
|
|
5
|
-
xgae/engine/prompt_builder.py,sha256=dqv0xcB-UWQhqISbMCYCTM1ANtthY6xUe7sJ9vPRqQ4,4364
|
|
6
|
-
xgae/engine/task_engine.py,sha256=oEyDORfDqHn7MzodeLrbhITd8TIIZrDIouF09j0twf0,20940
|
|
7
|
-
xgae/engine/task_langfuse.py,sha256=n2bajsHq2Zt3jetel8cSlN2lo42mZgTmbR4Zbx9JvsM,2416
|
|
8
|
-
xgae/engine/responser/non_stream_responser.py,sha256=HkmeFBIoxORhnFVh6XT0i6ixfF5vNzvN7B_BP6FzPVM,5334
|
|
9
|
-
xgae/engine/responser/responser_base.py,sha256=eQ4E1p_PoQISrIOLmjapGRH_RRX-7LOY1P2SrDjvyTM,24624
|
|
10
|
-
xgae/engine/responser/stream_responser.py,sha256=P6IkPniGli8XNq_BVciHeMCJiE0k3lNokTvX1GqRRbc,8046
|
|
11
|
-
xgae/tools/without_general_tools_app.py,sha256=H3JrwA0u7BIKW69yYBPLDpPesklY5quQIMaSVyvJ4s8,3839
|
|
12
|
-
xgae/utils/__init__.py,sha256=ElaGS-zdeZeu6is41u3Ny7lkvhg7BDSK-jMNg9j6K5A,499
|
|
13
|
-
xgae/utils/json_helpers.py,sha256=WD4G5U9Dh8N6J9O0L5wGyqj-NHi09kcXHGdLD_26nlc,3607
|
|
14
|
-
xgae/utils/llm_client.py,sha256=mWRtvtSMk_8NuzFReT9x52ayHlCNVZMZAltD6TQ-xZ8,14404
|
|
15
|
-
xgae/utils/misc.py,sha256=aMWOvJ9VW52q-L9Lkjl1hvXqLwpJAmyxA-Z8jzqFG0U,907
|
|
16
|
-
xgae/utils/setup_env.py,sha256=MqNG0c2QQBDFU1kI8frxr9kB5d08Mmi3QZ1OoorgIa0,2662
|
|
17
|
-
xgae/utils/xml_tool_parser.py,sha256=Mb0d8kBrfyAEvUwW1Nqir-3BgxZRr0ZX3WymQouuFSo,4859
|
|
18
|
-
xgae-0.1.17.dist-info/METADATA,sha256=mdr1LUj6EQejsp3BWcl8_RKvtg5kLwpS4jlW-wi2_1k,310
|
|
19
|
-
xgae-0.1.17.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
20
|
-
xgae-0.1.17.dist-info/entry_points.txt,sha256=SWN01JNAncV0oApEvFzpH0wsXfnFlB1adCH4IrAJxGc,163
|
|
21
|
-
xgae-0.1.17.dist-info/RECORD,,
|
|
File without changes
|