loom-agent 0.0.2__py3-none-any.whl → 0.0.3__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 loom-agent might be problematic. Click here for more details.
- loom/builtin/tools/task.py +100 -0
- loom/core/agent_executor.py +310 -39
- loom/core/context_assembly.py +115 -7
- loom/core/events.py +246 -0
- loom/core/unified_coordination.py +389 -0
- {loom_agent-0.0.2.dist-info → loom_agent-0.0.3.dist-info}/METADATA +22 -25
- {loom_agent-0.0.2.dist-info → loom_agent-0.0.3.dist-info}/RECORD +9 -8
- {loom_agent-0.0.2.dist-info → loom_agent-0.0.3.dist-info}/WHEEL +0 -0
- {loom_agent-0.0.2.dist-info → loom_agent-0.0.3.dist-info}/licenses/LICENSE +0 -0
loom/builtin/tools/task.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import time
|
|
5
6
|
from typing import TYPE_CHECKING, Any, Optional, Dict, List
|
|
6
7
|
|
|
7
8
|
from pydantic import BaseModel, Field
|
|
@@ -36,6 +37,12 @@ class TaskTool(BaseTool):
|
|
|
36
37
|
Task 工具 - 启动 SubAgent 执行专项任务
|
|
37
38
|
|
|
38
39
|
对应 Claude Code 的 Task 工具和 SubAgent 机制
|
|
40
|
+
|
|
41
|
+
新特性 (Loom 0.0.3):
|
|
42
|
+
- 子代理池管理
|
|
43
|
+
- 性能监控和指标收集
|
|
44
|
+
- 智能负载均衡
|
|
45
|
+
- 资源使用优化
|
|
39
46
|
"""
|
|
40
47
|
|
|
41
48
|
name = "task"
|
|
@@ -56,14 +63,35 @@ class TaskTool(BaseTool):
|
|
|
56
63
|
self,
|
|
57
64
|
agent_factory: Optional[callable] = None,
|
|
58
65
|
max_iterations: int = 20,
|
|
66
|
+
enable_pooling: bool = True,
|
|
67
|
+
pool_size: int = 5,
|
|
68
|
+
enable_monitoring: bool = True,
|
|
59
69
|
) -> None:
|
|
60
70
|
"""
|
|
61
71
|
Parameters:
|
|
62
72
|
- agent_factory: 创建 SubAgent 的工厂函数
|
|
63
73
|
- max_iterations: SubAgent 最大迭代次数
|
|
74
|
+
- enable_pooling: 启用子代理池管理
|
|
75
|
+
- pool_size: 子代理池大小
|
|
76
|
+
- enable_monitoring: 启用性能监控
|
|
64
77
|
"""
|
|
65
78
|
self.agent_factory = agent_factory
|
|
66
79
|
self.max_iterations = max_iterations
|
|
80
|
+
|
|
81
|
+
# Performance optimizations
|
|
82
|
+
self.enable_pooling = enable_pooling
|
|
83
|
+
self.pool_size = pool_size
|
|
84
|
+
self.enable_monitoring = enable_monitoring
|
|
85
|
+
|
|
86
|
+
# Sub-agent pool management
|
|
87
|
+
self._agent_pool: Dict[str, Any] = {}
|
|
88
|
+
self._pool_stats = {
|
|
89
|
+
"total_created": 0,
|
|
90
|
+
"total_executed": 0,
|
|
91
|
+
"average_execution_time": 0.0,
|
|
92
|
+
"cache_hits": 0,
|
|
93
|
+
"cache_misses": 0
|
|
94
|
+
}
|
|
67
95
|
|
|
68
96
|
async def run(
|
|
69
97
|
self,
|
|
@@ -136,7 +164,33 @@ class TaskTool(BaseTool):
|
|
|
136
164
|
)
|
|
137
165
|
|
|
138
166
|
# 运行子任务(系统提示已注入到 sub_agent,输入仍为原始 prompt)
|
|
167
|
+
start_time = time.time() if self.enable_monitoring else None
|
|
168
|
+
|
|
169
|
+
# Check pool for reusable agent
|
|
170
|
+
agent_key = self._get_agent_key(subagent_type, effective_model, permission_policy)
|
|
171
|
+
if self.enable_pooling and agent_key in self._agent_pool:
|
|
172
|
+
sub_agent = self._agent_pool[agent_key]
|
|
173
|
+
self._pool_stats["cache_hits"] += 1
|
|
174
|
+
else:
|
|
175
|
+
self._pool_stats["cache_misses"] += 1
|
|
176
|
+
self._pool_stats["total_created"] += 1
|
|
177
|
+
|
|
178
|
+
# Add to pool if enabled and not at capacity
|
|
179
|
+
if self.enable_pooling and len(self._agent_pool) < self.pool_size:
|
|
180
|
+
self._agent_pool[agent_key] = sub_agent
|
|
181
|
+
|
|
139
182
|
result = await sub_agent.run(prompt)
|
|
183
|
+
|
|
184
|
+
# Update performance metrics
|
|
185
|
+
if self.enable_monitoring and start_time:
|
|
186
|
+
execution_time = time.time() - start_time
|
|
187
|
+
self._pool_stats["total_executed"] += 1
|
|
188
|
+
# Update running average
|
|
189
|
+
current_avg = self._pool_stats["average_execution_time"]
|
|
190
|
+
total_executed = self._pool_stats["total_executed"]
|
|
191
|
+
self._pool_stats["average_execution_time"] = (
|
|
192
|
+
(current_avg * (total_executed - 1) + execution_time) / total_executed
|
|
193
|
+
)
|
|
140
194
|
|
|
141
195
|
# 格式化返回结果
|
|
142
196
|
return f"**SubAgent Task: {description}**\n\nResult:\n{result}"
|
|
@@ -161,3 +215,49 @@ class TaskTool(BaseTool):
|
|
|
161
215
|
subagent_type=subagent_type,
|
|
162
216
|
model_name=model_name,
|
|
163
217
|
)
|
|
218
|
+
|
|
219
|
+
def _get_agent_key(
|
|
220
|
+
self,
|
|
221
|
+
subagent_type: Optional[str],
|
|
222
|
+
model_name: Optional[str],
|
|
223
|
+
permission_policy: Optional[Dict[str, str]]
|
|
224
|
+
) -> str:
|
|
225
|
+
"""Generate unique key for agent pool"""
|
|
226
|
+
import hashlib
|
|
227
|
+
|
|
228
|
+
key_parts = [
|
|
229
|
+
subagent_type or "default",
|
|
230
|
+
model_name or "default",
|
|
231
|
+
str(sorted(permission_policy.items())) if permission_policy else "default"
|
|
232
|
+
]
|
|
233
|
+
|
|
234
|
+
key_string = "|".join(key_parts)
|
|
235
|
+
return hashlib.md5(key_string.encode()).hexdigest()
|
|
236
|
+
|
|
237
|
+
def get_pool_stats(self) -> Dict[str, Any]:
|
|
238
|
+
"""Get sub-agent pool statistics"""
|
|
239
|
+
return {
|
|
240
|
+
**self._pool_stats,
|
|
241
|
+
"pool_size": len(self._agent_pool),
|
|
242
|
+
"max_pool_size": self.pool_size,
|
|
243
|
+
"pool_utilization": len(self._agent_pool) / self.pool_size if self.pool_size > 0 else 0,
|
|
244
|
+
"cache_hit_rate": (
|
|
245
|
+
self._pool_stats["cache_hits"] /
|
|
246
|
+
(self._pool_stats["cache_hits"] + self._pool_stats["cache_misses"])
|
|
247
|
+
if (self._pool_stats["cache_hits"] + self._pool_stats["cache_misses"]) > 0 else 0
|
|
248
|
+
)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
def clear_pool(self) -> None:
|
|
252
|
+
"""Clear the sub-agent pool"""
|
|
253
|
+
self._agent_pool.clear()
|
|
254
|
+
|
|
255
|
+
def reset_stats(self) -> None:
|
|
256
|
+
"""Reset performance statistics"""
|
|
257
|
+
self._pool_stats = {
|
|
258
|
+
"total_created": 0,
|
|
259
|
+
"total_executed": 0,
|
|
260
|
+
"average_execution_time": 0.0,
|
|
261
|
+
"cache_hits": 0,
|
|
262
|
+
"cache_misses": 0
|
|
263
|
+
}
|
loom/core/agent_executor.py
CHANGED
|
@@ -11,7 +11,7 @@ import asyncio
|
|
|
11
11
|
import json
|
|
12
12
|
import time
|
|
13
13
|
from pathlib import Path
|
|
14
|
-
from typing import AsyncGenerator, Dict, List, Optional
|
|
14
|
+
from typing import AsyncGenerator, Dict, List, Optional, Any
|
|
15
15
|
from uuid import uuid4
|
|
16
16
|
|
|
17
17
|
from loom.callbacks.base import BaseCallback
|
|
@@ -37,6 +37,52 @@ try:
|
|
|
37
37
|
except ImportError:
|
|
38
38
|
ContextRetriever = None # type: ignore
|
|
39
39
|
|
|
40
|
+
# Unified coordination support
|
|
41
|
+
try:
|
|
42
|
+
from loom.core.unified_coordination import UnifiedExecutionContext, IntelligentCoordinator
|
|
43
|
+
except ImportError:
|
|
44
|
+
UnifiedExecutionContext = None # type: ignore
|
|
45
|
+
IntelligentCoordinator = None # type: ignore
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class TaskHandler:
|
|
49
|
+
"""
|
|
50
|
+
任务处理器基类
|
|
51
|
+
|
|
52
|
+
开发者可以继承此类来实现自定义的任务处理逻辑
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def can_handle(self, task: str) -> bool:
|
|
56
|
+
"""
|
|
57
|
+
判断是否能处理给定的任务
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
task: 任务描述
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
bool: 是否能处理此任务
|
|
64
|
+
"""
|
|
65
|
+
raise NotImplementedError
|
|
66
|
+
|
|
67
|
+
def generate_guidance(
|
|
68
|
+
self,
|
|
69
|
+
original_task: str,
|
|
70
|
+
result_analysis: Dict[str, Any],
|
|
71
|
+
recursion_depth: int
|
|
72
|
+
) -> str:
|
|
73
|
+
"""
|
|
74
|
+
生成递归指导消息
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
original_task: 原始任务
|
|
78
|
+
result_analysis: 工具结果分析
|
|
79
|
+
recursion_depth: 递归深度
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
str: 生成的指导消息
|
|
83
|
+
"""
|
|
84
|
+
raise NotImplementedError
|
|
85
|
+
|
|
40
86
|
|
|
41
87
|
class AgentExecutor:
|
|
42
88
|
"""
|
|
@@ -78,6 +124,9 @@ class AgentExecutor:
|
|
|
78
124
|
system_instructions: Optional[str] = None,
|
|
79
125
|
callbacks: Optional[List[BaseCallback]] = None,
|
|
80
126
|
enable_steering: bool = False,
|
|
127
|
+
task_handlers: Optional[List[TaskHandler]] = None,
|
|
128
|
+
unified_context: Optional["UnifiedExecutionContext"] = None,
|
|
129
|
+
enable_unified_coordination: bool = True,
|
|
81
130
|
) -> None:
|
|
82
131
|
self.llm = llm
|
|
83
132
|
self.tools = tools or {}
|
|
@@ -94,6 +143,15 @@ class AgentExecutor:
|
|
|
94
143
|
self.system_instructions = system_instructions
|
|
95
144
|
self.callbacks = callbacks or []
|
|
96
145
|
self.enable_steering = enable_steering
|
|
146
|
+
self.task_handlers = task_handlers or []
|
|
147
|
+
|
|
148
|
+
# Unified coordination
|
|
149
|
+
self.unified_context = unified_context
|
|
150
|
+
self.enable_unified_coordination = enable_unified_coordination
|
|
151
|
+
|
|
152
|
+
# Initialize unified coordination if enabled
|
|
153
|
+
if self.enable_unified_coordination and UnifiedExecutionContext and IntelligentCoordinator:
|
|
154
|
+
self._setup_unified_coordination()
|
|
97
155
|
|
|
98
156
|
# Tool execution (legacy pipeline for backward compatibility)
|
|
99
157
|
self.tool_pipeline = ToolExecutionPipeline(
|
|
@@ -102,6 +160,80 @@ class AgentExecutor:
|
|
|
102
160
|
metrics=self.metrics,
|
|
103
161
|
)
|
|
104
162
|
|
|
163
|
+
def _setup_unified_coordination(self):
|
|
164
|
+
"""设置统一协调机制"""
|
|
165
|
+
if not self.unified_context:
|
|
166
|
+
# 创建默认的统一执行上下文
|
|
167
|
+
from loom.core.unified_coordination import CoordinationConfig
|
|
168
|
+
self.unified_context = UnifiedExecutionContext(
|
|
169
|
+
execution_id=f"exec_{int(time.time())}",
|
|
170
|
+
config=CoordinationConfig() # 使用默认配置
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# 集成四大核心能力
|
|
174
|
+
self._integrate_core_capabilities()
|
|
175
|
+
|
|
176
|
+
# 创建智能协调器
|
|
177
|
+
self.coordinator = IntelligentCoordinator(self.unified_context)
|
|
178
|
+
|
|
179
|
+
# 设置跨组件引用
|
|
180
|
+
self._setup_cross_component_references()
|
|
181
|
+
|
|
182
|
+
def _integrate_core_capabilities(self):
|
|
183
|
+
"""集成四大核心能力到统一上下文"""
|
|
184
|
+
|
|
185
|
+
config = self.unified_context.config
|
|
186
|
+
|
|
187
|
+
# 1. 集成 ContextAssembler
|
|
188
|
+
if not self.unified_context.context_assembler:
|
|
189
|
+
from loom.core.context_assembly import ContextAssembler
|
|
190
|
+
self.unified_context.context_assembler = ContextAssembler(
|
|
191
|
+
max_tokens=self.max_context_tokens,
|
|
192
|
+
enable_caching=True,
|
|
193
|
+
cache_size=config.context_cache_size
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
# 2. 集成 TaskTool
|
|
197
|
+
if "task" in self.tools and not self.unified_context.task_tool:
|
|
198
|
+
task_tool = self.tools["task"]
|
|
199
|
+
# 使用配置更新 TaskTool
|
|
200
|
+
task_tool.pool_size = config.subagent_pool_size
|
|
201
|
+
task_tool.enable_pooling = True
|
|
202
|
+
self.unified_context.task_tool = task_tool
|
|
203
|
+
|
|
204
|
+
# 3. 集成 EventProcessor
|
|
205
|
+
if not self.unified_context.event_processor:
|
|
206
|
+
from loom.core.events import EventFilter, EventProcessor, AgentEventType
|
|
207
|
+
|
|
208
|
+
# 创建智能事件过滤器,使用配置值
|
|
209
|
+
llm_filter = EventFilter(
|
|
210
|
+
allowed_types=[
|
|
211
|
+
AgentEventType.LLM_DELTA,
|
|
212
|
+
AgentEventType.TOOL_RESULT,
|
|
213
|
+
AgentEventType.AGENT_FINISH
|
|
214
|
+
],
|
|
215
|
+
enable_batching=True,
|
|
216
|
+
batch_size=config.event_batch_size,
|
|
217
|
+
batch_timeout=config.event_batch_timeout
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
self.unified_context.event_processor = EventProcessor(
|
|
221
|
+
filters=[llm_filter],
|
|
222
|
+
enable_stats=True
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
# 4. 集成 TaskHandlers
|
|
226
|
+
if not self.unified_context.task_handlers:
|
|
227
|
+
self.unified_context.task_handlers = self.task_handlers or []
|
|
228
|
+
|
|
229
|
+
def _setup_cross_component_references(self):
|
|
230
|
+
"""
|
|
231
|
+
设置跨组件引用(已简化)
|
|
232
|
+
|
|
233
|
+
移除了魔法属性注入,改为通过协调器处理所有跨组件通信
|
|
234
|
+
"""
|
|
235
|
+
pass # 跨组件通信现在通过 IntelligentCoordinator 处理
|
|
236
|
+
|
|
105
237
|
# Tool orchestration (Loom 2.0 - intelligent parallel/sequential execution)
|
|
106
238
|
self.tool_orchestrator = ToolOrchestrator(
|
|
107
239
|
tools=self.tools,
|
|
@@ -269,40 +401,50 @@ class AgentExecutor:
|
|
|
269
401
|
},
|
|
270
402
|
)
|
|
271
403
|
|
|
272
|
-
#
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
assembler.add_component(
|
|
278
|
-
name="base_instructions",
|
|
279
|
-
content=self.system_instructions,
|
|
280
|
-
priority=ComponentPriority.CRITICAL,
|
|
281
|
-
truncatable=False,
|
|
404
|
+
# 使用统一协调的智能上下文组装
|
|
405
|
+
if self.enable_unified_coordination and hasattr(self, 'coordinator'):
|
|
406
|
+
# 使用智能协调器进行上下文组装
|
|
407
|
+
execution_plan = self.coordinator.coordinate_tt_recursion(
|
|
408
|
+
messages, turn_state, context
|
|
282
409
|
)
|
|
410
|
+
final_system_prompt = execution_plan.get("context", "")
|
|
411
|
+
# 使用统一协调器的 assembler
|
|
412
|
+
assembler = self.unified_context.context_assembler
|
|
413
|
+
else:
|
|
414
|
+
# 传统方式组装系统提示
|
|
415
|
+
assembler = ContextAssembler(max_tokens=self.max_context_tokens)
|
|
416
|
+
|
|
417
|
+
# Add base instructions (critical priority)
|
|
418
|
+
if self.system_instructions:
|
|
419
|
+
assembler.add_component(
|
|
420
|
+
name="base_instructions",
|
|
421
|
+
content=self.system_instructions,
|
|
422
|
+
priority=ComponentPriority.CRITICAL,
|
|
423
|
+
truncatable=False,
|
|
424
|
+
)
|
|
283
425
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
426
|
+
# Add RAG context (high priority)
|
|
427
|
+
if rag_context:
|
|
428
|
+
assembler.add_component(
|
|
429
|
+
name="retrieved_context",
|
|
430
|
+
content=rag_context,
|
|
431
|
+
priority=ComponentPriority.HIGH,
|
|
432
|
+
truncatable=True,
|
|
433
|
+
)
|
|
292
434
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
435
|
+
# Add tool definitions (medium priority)
|
|
436
|
+
if self.tools:
|
|
437
|
+
tools_spec = self._serialize_tools()
|
|
438
|
+
tools_prompt = f"Available tools:\n{json.dumps(tools_spec, indent=2)}"
|
|
439
|
+
assembler.add_component(
|
|
440
|
+
name="tool_definitions",
|
|
441
|
+
content=tools_prompt,
|
|
442
|
+
priority=ComponentPriority.MEDIUM,
|
|
443
|
+
truncatable=False,
|
|
444
|
+
)
|
|
303
445
|
|
|
304
|
-
|
|
305
|
-
|
|
446
|
+
# Assemble final system prompt
|
|
447
|
+
final_system_prompt = assembler.assemble()
|
|
306
448
|
|
|
307
449
|
# Inject system prompt into history
|
|
308
450
|
if history and history[0].role == "system":
|
|
@@ -442,15 +584,20 @@ class AgentExecutor:
|
|
|
442
584
|
# Prepare next turn state
|
|
443
585
|
next_state = turn_state.next_turn(compacted=compacted_this_turn)
|
|
444
586
|
|
|
445
|
-
# Prepare next turn messages
|
|
446
|
-
next_messages =
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
587
|
+
# Prepare next turn messages with intelligent context guidance
|
|
588
|
+
next_messages = self._prepare_recursive_messages(
|
|
589
|
+
messages, tool_results, turn_state, context
|
|
590
|
+
)
|
|
591
|
+
|
|
592
|
+
# Add tool results
|
|
593
|
+
for r in tool_results:
|
|
594
|
+
next_messages.append(
|
|
595
|
+
Message(
|
|
596
|
+
role="tool",
|
|
597
|
+
content=r.content,
|
|
598
|
+
tool_call_id=r.tool_call_id,
|
|
599
|
+
)
|
|
451
600
|
)
|
|
452
|
-
for r in tool_results
|
|
453
|
-
]
|
|
454
601
|
|
|
455
602
|
# Emit recursion event
|
|
456
603
|
yield AgentEvent(
|
|
@@ -466,6 +613,130 @@ class AgentExecutor:
|
|
|
466
613
|
async for event in self.tt(next_messages, next_state, context):
|
|
467
614
|
yield event
|
|
468
615
|
|
|
616
|
+
# ==========================================
|
|
617
|
+
# Intelligent Recursion Methods
|
|
618
|
+
# ==========================================
|
|
619
|
+
|
|
620
|
+
def _prepare_recursive_messages(
|
|
621
|
+
self,
|
|
622
|
+
messages: List[Message],
|
|
623
|
+
tool_results: List[ToolResult],
|
|
624
|
+
turn_state: TurnState,
|
|
625
|
+
context: ExecutionContext,
|
|
626
|
+
) -> List[Message]:
|
|
627
|
+
"""
|
|
628
|
+
智能准备递归调用的消息
|
|
629
|
+
|
|
630
|
+
基于工具结果类型、任务上下文和递归深度,生成合适的用户指导消息
|
|
631
|
+
"""
|
|
632
|
+
# 分析工具结果
|
|
633
|
+
result_analysis = self._analyze_tool_results(tool_results)
|
|
634
|
+
|
|
635
|
+
# 获取原始任务
|
|
636
|
+
original_task = self._extract_original_task(messages)
|
|
637
|
+
|
|
638
|
+
# 生成智能指导消息
|
|
639
|
+
guidance_message = self._generate_recursion_guidance(
|
|
640
|
+
original_task, result_analysis, turn_state.turn_counter
|
|
641
|
+
)
|
|
642
|
+
|
|
643
|
+
return [Message(role="user", content=guidance_message)]
|
|
644
|
+
|
|
645
|
+
def _analyze_tool_results(self, tool_results: List[ToolResult]) -> Dict[str, Any]:
|
|
646
|
+
"""分析工具结果类型和质量"""
|
|
647
|
+
analysis = {
|
|
648
|
+
"has_data": False,
|
|
649
|
+
"has_errors": False,
|
|
650
|
+
"suggests_completion": False,
|
|
651
|
+
"result_types": [],
|
|
652
|
+
"completeness_score": 0.0
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
for result in tool_results:
|
|
656
|
+
content = result.content.lower()
|
|
657
|
+
|
|
658
|
+
# 检查数据类型
|
|
659
|
+
if any(keyword in content for keyword in ["data", "found", "retrieved", "table", "schema", "获取到", "表结构", "结构"]):
|
|
660
|
+
analysis["has_data"] = True
|
|
661
|
+
analysis["result_types"].append("data")
|
|
662
|
+
analysis["completeness_score"] += 0.3
|
|
663
|
+
|
|
664
|
+
# 检查错误
|
|
665
|
+
if any(keyword in content for keyword in ["error", "failed", "exception", "not found"]):
|
|
666
|
+
analysis["has_errors"] = True
|
|
667
|
+
analysis["result_types"].append("error")
|
|
668
|
+
|
|
669
|
+
# 检查完成建议
|
|
670
|
+
if any(keyword in content for keyword in ["complete", "finished", "done", "ready"]):
|
|
671
|
+
analysis["suggests_completion"] = True
|
|
672
|
+
analysis["result_types"].append("completion")
|
|
673
|
+
analysis["completeness_score"] += 0.5
|
|
674
|
+
|
|
675
|
+
# 检查分析结果
|
|
676
|
+
if any(keyword in content for keyword in ["analysis", "summary", "conclusion", "insights"]):
|
|
677
|
+
analysis["result_types"].append("analysis")
|
|
678
|
+
analysis["completeness_score"] += 0.4
|
|
679
|
+
|
|
680
|
+
analysis["completeness_score"] = min(analysis["completeness_score"], 1.0)
|
|
681
|
+
return analysis
|
|
682
|
+
|
|
683
|
+
def _extract_original_task(self, messages: List[Message]) -> str:
|
|
684
|
+
"""从消息历史中提取原始任务"""
|
|
685
|
+
# 查找第一个用户消息作为原始任务
|
|
686
|
+
for message in messages:
|
|
687
|
+
if message.role == "user" and message.content:
|
|
688
|
+
# 过滤掉系统生成的递归消息
|
|
689
|
+
if not any(keyword in message.content.lower() for keyword in [
|
|
690
|
+
"工具调用已完成", "请基于工具返回的结果", "不要继续调用工具"
|
|
691
|
+
]):
|
|
692
|
+
return message.content
|
|
693
|
+
return "处理用户请求"
|
|
694
|
+
|
|
695
|
+
def _generate_recursion_guidance(
|
|
696
|
+
self,
|
|
697
|
+
original_task: str,
|
|
698
|
+
result_analysis: Dict[str, Any],
|
|
699
|
+
recursion_depth: int
|
|
700
|
+
) -> str:
|
|
701
|
+
"""生成递归指导消息"""
|
|
702
|
+
|
|
703
|
+
# 使用可扩展的任务处理器
|
|
704
|
+
if hasattr(self, 'task_handlers') and self.task_handlers:
|
|
705
|
+
for handler in self.task_handlers:
|
|
706
|
+
if handler.can_handle(original_task):
|
|
707
|
+
return handler.generate_guidance(original_task, result_analysis, recursion_depth)
|
|
708
|
+
|
|
709
|
+
# 默认处理
|
|
710
|
+
return self._generate_default_guidance(original_task, result_analysis, recursion_depth)
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
def _generate_default_guidance(
|
|
714
|
+
self,
|
|
715
|
+
original_task: str,
|
|
716
|
+
result_analysis: Dict[str, Any],
|
|
717
|
+
recursion_depth: int
|
|
718
|
+
) -> str:
|
|
719
|
+
"""生成默认的递归指导"""
|
|
720
|
+
|
|
721
|
+
if result_analysis["suggests_completion"] or recursion_depth >= 6:
|
|
722
|
+
return f"""工具调用已完成。请基于返回的结果完成任务:{original_task}
|
|
723
|
+
|
|
724
|
+
请提供完整、准确的最终答案。"""
|
|
725
|
+
|
|
726
|
+
elif result_analysis["has_errors"]:
|
|
727
|
+
return f"""工具执行遇到问题。请重新尝试完成任务:{original_task}
|
|
728
|
+
|
|
729
|
+
建议:
|
|
730
|
+
- 检查工具参数是否正确
|
|
731
|
+
- 尝试使用不同的工具或方法
|
|
732
|
+
- 如果问题持续,请说明具体错误"""
|
|
733
|
+
|
|
734
|
+
else:
|
|
735
|
+
return f"""继续处理任务:{original_task}
|
|
736
|
+
|
|
737
|
+
当前进度:{result_analysis['completeness_score']:.0%}
|
|
738
|
+
建议:使用更多工具收集信息或分析已获得的结果"""
|
|
739
|
+
|
|
469
740
|
# ==========================================
|
|
470
741
|
# Helper Methods
|
|
471
742
|
# ==========================================
|