Skip to content

Commit 57b887d

Browse files
fix: handles problems due to tools now having uuid suffixes
1 parent 6e3a52f commit 57b887d

2 files changed

Lines changed: 51 additions & 4 deletions

File tree

src/askui/models/shared/tools.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,12 +465,47 @@ def _run_tool(
465465
mcp_tool = self._get_mcp_tools().get(tool_use_block_param.name)
466466
if mcp_tool:
467467
return self._run_mcp_tool(tool_use_block_param)
468+
# Fallback: try prefix matching (for cached trajectories with different UUIDs)
469+
tool = self._find_tool_by_prefix(tool_use_block_param.name)
470+
if tool:
471+
return self._run_regular_tool(tool_use_block_param, tool)
472+
msg = f"no matching tool found with name {tool_use_block_param.name}"
473+
logger.error(msg)
468474
return ToolResultBlockParam(
469475
content=f"Tool not found: {tool_use_block_param.name}",
470476
is_error=True,
471477
tool_use_id=tool_use_block_param.id,
472478
)
473479

480+
def _find_tool_by_prefix(self, cached_name: str) -> Tool | None:
481+
"""Find a tool by matching name prefix (without UUID suffix).
482+
483+
Tool names have format: {base_name}_tags_{tags}_{uuid} or {base_name}_{uuid}
484+
This method strips the UUID suffix and matches by the remaining prefix.
485+
486+
Args:
487+
cached_name: Tool name from cached trajectory (may have different UUID)
488+
489+
Returns:
490+
Matching Tool if found, None otherwise
491+
"""
492+
# Extract prefix by removing trailing UUID (pattern: _xxxxxxxx-xxxx-...)
493+
# UUIDs start with 8 hex chars after an underscore
494+
uuid_pattern = re.compile(r"_[0-9a-f]{8}-[0-9a-f]{4}.*$", re.IGNORECASE)
495+
cached_prefix = uuid_pattern.sub("", cached_name)
496+
497+
if not cached_prefix or cached_prefix == cached_name:
498+
# No UUID found or name unchanged, can't match by prefix
499+
return None
500+
501+
# Find a tool whose name starts with the same prefix
502+
for tool_name, tool in self.tool_map.items():
503+
tool_prefix = uuid_pattern.sub("", tool_name)
504+
if tool_prefix == cached_prefix:
505+
return tool
506+
507+
return None
508+
474509
async def _list_mcp_tools(self, mcp_client: McpClientProtocol) -> list[McpTool]:
475510
async with mcp_client:
476511
return await mcp_client.list_tools()

src/askui/tools/caching_tools.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,18 +122,30 @@ def __call__(self, trajectory_file: str) -> str:
122122
info_msg = f"Executing cached trajectory from {trajectory_file}"
123123
logger.info(info_msg)
124124
for step in trajectory:
125+
# Skip non-action tools (screenshots, cache management tools)
125126
if (
126127
"screenshot" in step.name
127-
or step.name == "retrieve_available_trajectories_tool"
128+
or step.name.startswith("retrieve_available_trajectories_tool")
129+
or step.name.startswith("execute_cached_executions_tool")
128130
):
129131
continue
130132
try:
131-
self._toolbox.run([step])
133+
results = self._toolbox.run([step])
134+
# Check for tool execution errors
135+
if results and hasattr(results[0], "is_error") and results[0].is_error:
136+
error_content = getattr(results[0], "content", "Unknown error")
137+
error_msg = f"Tool error during cached execution: {error_content}"
138+
logger.error(error_msg)
139+
return (
140+
f"An error occurred while executing the trajectory from "
141+
f"{trajectory_file}: {error_content}. Please verify the UI "
142+
"state and continue without cache."
143+
)
132144
except Exception as e:
133-
error_msg = f"An error occured during the cached execution: {e}"
145+
error_msg = f"An error occurred during the cached execution: {e}"
134146
logger.exception(error_msg)
135147
return (
136-
f"An error occured while executing the trajectory from "
148+
f"An error occurred while executing the trajectory from "
137149
f"{trajectory_file}. Please verify the UI state and "
138150
"continue without cache."
139151
)

0 commit comments

Comments
 (0)