feat(search): 实现 SearchToolDispatcher 工具调度器 (Task 7)
- 新增 app/search/tools.py:
- get_tool_descriptions() 工具描述文本(与 TRM4 一致)
- SearchToolDispatcher 类实现 ToolDispatcher Protocol
- dispatch() 按工具名路由: view_node / search_similar /
observe_frame / submit_answer / read_skill
- ValueError(未知工具)上抛,KeyError/FileNotFoundError 捕获返回错误文本
- view_node: env.get_node_text + summarize_node + get_children_info + summarize_children
- search_similar: env.search_similar + summarize_nodes_batch
- observe_frame: env.resolve_frame_paths + get_subtitle + observe_frame + 字幕前置
- 修复 app/tree/environment.py get_children_info():
- 原实现返回 _format_time_range (str) 导致 summarize_children 解包失败
- 改为返回原始数值元组 via 新增 _node_time_range_raw 静态方法
- 新增 tests/unit/test_search_tools.py (14 tests):
- get_tool_descriptions 含/不含 read_skill
- 五种工具 dispatch 路由验证
- 未知工具 ValueError + 节点不存在错误文本
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+21
-1
@@ -339,6 +339,7 @@ class TreeEnvironment:
|
||||
|
||||
返回:
|
||||
子节点信息列表,每项包含 {"id", "time_range", "summary"}。
|
||||
time_range 为 (start, end) 数值元组(L3 节点退化为 (ts, ts))。
|
||||
L3 叶子节点返回空列表。
|
||||
|
||||
异常:
|
||||
@@ -357,7 +358,7 @@ class TreeEnvironment:
|
||||
result.append(
|
||||
{
|
||||
"id": child.id,
|
||||
"time_range": self._format_time_range(child),
|
||||
"time_range": self._node_time_range_raw(child),
|
||||
"summary": desc,
|
||||
}
|
||||
)
|
||||
@@ -504,6 +505,25 @@ class TreeEnvironment:
|
||||
return f"{node.timestamp:.1f}s"
|
||||
return "N/A"
|
||||
|
||||
@staticmethod
|
||||
def _node_time_range_raw(node: AnyNode) -> tuple[float, float]:
|
||||
"""提取节点时间范围的原始数值元组。
|
||||
|
||||
L1/L2 返回 time_range 元组;L3 退化为 (timestamp, timestamp);
|
||||
全部为 None 时兜底 (0.0, 0.0)。
|
||||
|
||||
参数:
|
||||
node: 树节点。
|
||||
|
||||
返回:
|
||||
(start, end) 秒级数值元组。
|
||||
"""
|
||||
if isinstance(node, (L1Node, L2Node)) and node.time_range:
|
||||
return node.time_range
|
||||
if isinstance(node, L3Node) and node.timestamp is not None:
|
||||
return (node.timestamp, node.timestamp)
|
||||
return (0.0, 0.0)
|
||||
|
||||
@staticmethod
|
||||
def _get_children(node: AnyNode) -> list[AnyNode]:
|
||||
"""获取节点的直接子节点列表。
|
||||
|
||||
Reference in New Issue
Block a user