fix:修正子agent无法正确接收本地图片(参考图)路径的问题#5579
Conversation
…arify usage in multimodal tasks
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! 此拉取请求旨在解决子agent在处理图片(特别是参考图)路径时遇到的一个遗留问题,确保无论图片来源是本地文件、网络链接还是Base64编码,都能被正确解析并转换为子agent可识别的规范化本地文件路径。这一改进使得子agent的图片接收与转换逻辑与主agent的对话流程保持一致,提升了系统的稳定性和图片处理的兼容性。 Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Hey - 我发现了 1 个问题,并给出了一些整体性的反馈:
- 在对
image_urls做归一化和增强之后,建议把处理后的列表重新写回tool_args['image_urls'],这样后续从tool_args读取该字段的逻辑就能看到更新后的值,而不是原始输入。 - 新增的事件/消息/图片遍历逻辑默认假设存在
run_context.context.event及其相关属性;使用getattr/hasattr之类的检查方式可以让这块逻辑在事件缺失或结构不同的情况下更加健壮,避免在边缘场景中出现AttributeError。
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- After normalizing and augmenting `image_urls`, consider writing the resulting list back into `tool_args['image_urls']` to ensure downstream logic that reads from `tool_args` sees the updated value rather than the original input.
- The new event/message/image traversal assumes the presence of `run_context.context.event` and related attributes; using `getattr`/`hasattr`-style checks would make this more robust against missing or differently shaped events and avoid potential `AttributeError`s in edge cases.
## Individual Comments
### Comment 1
<location path="astrbot/core/astr_agent_tool_exec.py" line_range="168-173" />
<code_context>
):
input_ = tool_args.get("input")
image_urls = tool_args.get("image_urls")
+ if image_urls is None:
+ image_urls = []
+ elif isinstance(image_urls, str):
+ image_urls = [image_urls]
+
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Normalize `image_urls` more generally so non-list iterables (e.g., tuples) are handled consistently.
Currently only `None` and `str` are normalized; other iterables (e.g., tuples, sets) pass through unchanged. Because you later treat `image_urls` as a mutable list (e.g., append, membership checks), this can raise runtime errors. Consider coercing any non-list iterable to a list, e.g.:
```python
elif not isinstance(image_urls, list):
image_urls = list(image_urls)
```
This keeps behavior consistent and more robust to upstream changes in how `image_urls` is provided.
```suggestion
image_urls = tool_args.get("image_urls")
if image_urls is None:
image_urls = []
elif isinstance(image_urls, str):
image_urls = [image_urls]
elif not isinstance(image_urls, list):
image_urls = list(image_urls)
```
</issue_to_address>帮我变得更有用!请对每条评论点 👍 或 👎,我会根据你的反馈改进后续的评审。
Original comment in English
Hey - I've found 1 issue, and left some high level feedback:
- After normalizing and augmenting
image_urls, consider writing the resulting list back intotool_args['image_urls']to ensure downstream logic that reads fromtool_argssees the updated value rather than the original input. - The new event/message/image traversal assumes the presence of
run_context.context.eventand related attributes; usinggetattr/hasattr-style checks would make this more robust against missing or differently shaped events and avoid potentialAttributeErrors in edge cases.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- After normalizing and augmenting `image_urls`, consider writing the resulting list back into `tool_args['image_urls']` to ensure downstream logic that reads from `tool_args` sees the updated value rather than the original input.
- The new event/message/image traversal assumes the presence of `run_context.context.event` and related attributes; using `getattr`/`hasattr`-style checks would make this more robust against missing or differently shaped events and avoid potential `AttributeError`s in edge cases.
## Individual Comments
### Comment 1
<location path="astrbot/core/astr_agent_tool_exec.py" line_range="168-173" />
<code_context>
):
input_ = tool_args.get("input")
image_urls = tool_args.get("image_urls")
+ if image_urls is None:
+ image_urls = []
+ elif isinstance(image_urls, str):
+ image_urls = [image_urls]
+
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Normalize `image_urls` more generally so non-list iterables (e.g., tuples) are handled consistently.
Currently only `None` and `str` are normalized; other iterables (e.g., tuples, sets) pass through unchanged. Because you later treat `image_urls` as a mutable list (e.g., append, membership checks), this can raise runtime errors. Consider coercing any non-list iterable to a list, e.g.:
```python
elif not isinstance(image_urls, list):
image_urls = list(image_urls)
```
This keeps behavior consistent and more robust to upstream changes in how `image_urls` is provided.
```suggestion
image_urls = tool_args.get("image_urls")
if image_urls is None:
image_urls = []
elif isinstance(image_urls, str):
image_urls = [image_urls]
elif not isinstance(image_urls, list):
image_urls = list(image_urls)
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
Documentation Updates 1 document(s) were updated by changes in this PR: pr4697的改动View Changes@@ -154,15 +154,33 @@
[PR #5579](https://github.com/AstrBotDevs/AstrBot/pull/5579) 修复了 PR #5348 中遗留的子代理无法正确接收本地图片(参考图)路径的问题。修复后,对话中的参考图片会自动传递给子代理,无需开发者手动处理。
+**问题背景:**
+
+PR #5348 引入了 `image_urls` 参数用于多模态任务,但存在以下问题:
+- 子代理交接(handoff)时无法正确接收本地图片路径
+- 对话中发送的图片(本地文件、网络 URL、Base64 格式)未被自动转换和传递
+- 图片引用验证和扩展名白名单分散在多处,缺乏统一管理
+
**技术实现:**
-在 `_execute_handoff` 方法(`astrbot/core/astr_agent_tool_exec.py`)中新增 Image 组件处理逻辑:
-
-1. 引入 Image 组件:`from astrbot.core.message.components import Image`
-2. 自动提取当前事件消息中的 Image 组件
-3. 对每个 Image 组件调用 `convert_to_file_path()` 异步方法,将图片(本地文件、网络 URL 或 Base64 格式)转换为规范化的本地文件路径
-4. 转换后的路径自动添加到传递给子代理的 `image_urls` 参数中
-5. 确保子代理接收参考图片的行为与主代理一致
+1. **新增 `image_ref_utils.py` 工具模块**:
+ - `is_supported_image_ref()` 函数:验证和规范化图片引用(本地文件、HTTP/HTTPS URL、Base64)
+ - `ALLOWED_IMAGE_EXTENSIONS` 常量:统一图片扩展名白名单(`.png`、`.jpg`、`.jpeg`、`.gif`、`.webp`、`.bmp`、`.tif`、`.tiff`、`.svg`、`.heic`)
+ - 支持无扩展名的临时文件(需存在于指定根目录)
+
+2. **增强 `_execute_handoff` 方法**(`astrbot/core/astr_agent_tool_exec.py`):
+ - 引入 `Image` 组件处理逻辑:`from astrbot.core.message.components import Image`
+ - 新增 `_collect_image_urls_from_message()` 方法:自动提取当前事件消息中的 `Image` 组件
+ - 新增 `_collect_handoff_image_urls()` 方法:
+ - 从工具参数(`image_urls_raw`)和事件消息中收集图片引用
+ - 对每个 `Image` 组件调用 `convert_to_file_path()` 异步方法,将图片(本地文件、网络 URL 或 Base64 格式)转换为规范化的本地文件路径
+ - 使用 `is_supported_image_ref()` 验证和过滤无效图片引用
+ - 自动去重和规范化图片路径
+ - 转换后的路径自动注入 `image_urls` 参数,传递给子代理
+ - 确保子代理接收参考图片的行为与主代理对话流程一致
+
+3. **后台任务支持**:
+ - `_do_handoff_background()` 方法同样调用 `_collect_handoff_image_urls()`,确保后台任务中的图片路径也被正确收集和传递
**使用说明:**
@@ -170,6 +188,8 @@
- 转交任务给子代理时,这些图片路径会自动包含在 `image_urls` 参数中
- 子代理可以直接使用这些参考图片进行多模态任务(如图像分析、视频生成等)
- 无需在 `transfer_to_*` 工具中显式指定对话中已存在的图片路径
+- 支持所有图片格式(本地文件路径、`file://` URL、HTTP/HTTPS URL、Base64 编码)
+- 系统会自动过滤无效图片引用,并记录调试日志
##### 工具调用结果显示配置(PR #5388)
|
There was a problem hiding this comment.
Code Review
这个 PR 修正了子 agent 无法正确接收本地图片路径的问题,通过在 _execute_handoff 方法中添加逻辑来解析 Image 组件并将其转换为文件路径。然而,此实现引入了安全风险,因为它信任地处理来自 LLM 和用户消息事件的本地文件路径。具体来说,convert_to_file_path() 的使用没有进行路径验证,可能导致路径遍历和任意文件读取漏洞。建议实施严格的路径验证,以确保只有授权文件(例如,指定临时目录中的文件)传递给子 agent。此外,为了提高性能,建议在检查重复图片路径时使用 set 来提高效率。
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey - 我在这里给出了一些整体性的反馈:
- 在对
image_urls进行归一化和扩充之后,请确保实际把更新后的列表继续传递下去(例如写回到tool_args,或写入后续代码会读取的那个结构中),否则计算出来的路径在交接流程中可能根本不会被使用。 - 建议在访问
event.message_obj之前,加一层防御性检查,确保run_context.context和run_context.context.event都不是None,以避免在没有 event 的情况下触发交接时出现意料之外的属性错误。 - 在
convert_to_file_path外层直接捕获裸Exception可能会在开发阶段掩盖问题;建议收窄异常类型,或者至少在日志中加入更多上下文信息(例如是哪个组件或哪条消息失败),以便调试。
给 AI Agents 的提示
Please address the comments from this code review:
## Overall Comments
- After normalizing and augmenting `image_urls`, make sure the updated list is actually passed along (e.g., written back into `tool_args` or whatever structure the downstream code reads), otherwise the computed paths may never be used in the handoff.
- Consider adding a defensive check that `run_context.context` and `run_context.context.event` are not `None` before accessing `event.message_obj`, to avoid unexpected attribute errors when the handoff is triggered without an event.
- Catching a bare `Exception` around `convert_to_file_path` may hide issues during development; consider narrowing the exception type or at least including more context in the log (e.g., which component or message failed) to aid debugging.帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进后续的评审。
Original comment in English
Hey - I've left some high level feedback:
- After normalizing and augmenting
image_urls, make sure the updated list is actually passed along (e.g., written back intotool_argsor whatever structure the downstream code reads), otherwise the computed paths may never be used in the handoff. - Consider adding a defensive check that
run_context.contextandrun_context.context.eventare notNonebefore accessingevent.message_obj, to avoid unexpected attribute errors when the handoff is triggered without an event. - Catching a bare
Exceptionaroundconvert_to_file_pathmay hide issues during development; consider narrowing the exception type or at least including more context in the log (e.g., which component or message failed) to aid debugging.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- After normalizing and augmenting `image_urls`, make sure the updated list is actually passed along (e.g., written back into `tool_args` or whatever structure the downstream code reads), otherwise the computed paths may never be used in the handoff.
- Consider adding a defensive check that `run_context.context` and `run_context.context.event` are not `None` before accessing `event.message_obj`, to avoid unexpected attribute errors when the handoff is triggered without an event.
- Catching a bare `Exception` around `convert_to_file_path` may hide issues during development; consider narrowing the exception type or at least including more context in the log (e.g., which component or message failed) to aid debugging.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
@sourcery-ai reivew |
|
Sure! I'm generating a new review now. |
There was a problem hiding this comment.
Hey - 我发现了两个问题,并给出了一些整体反馈:
- 在
_do_handoff_background中,在委托给_execute_handoff之前调用了_prepare_handoff_image_urls,而_execute_handoff本身又会再次调用_prepare_handoff_image_urls,导致重复的规范化和事件图片扫描;建议重构,让准备逻辑只在一个地方执行,同时仍然确保存储的tool_args能准确反映最终的image_urls。 _prepare_handoff_image_urls目前会把任何非字符串的image_urls当作通用可迭代对象来处理,并直接对其执行list(image_urls),这对映射或自定义对象可能会产生出人意料的行为;如果这些不是预期输入类型,可能更安全的做法是只显式处理序列/集合,或者对类型进行校验并尽早失败。
提交给 AI 代理的提示词
Please address the comments from this code review:
## Overall Comments
- In `_do_handoff_background`, `_prepare_handoff_image_urls` is called before delegating to `_execute_handoff`, which itself calls `_prepare_handoff_image_urls` again, causing redundant normalization and event image scanning; consider refactoring so the preparation happens in only one place while still ensuring the stored `tool_args` reflect the final `image_urls`.
- `_prepare_handoff_image_urls` currently treats any non-string `image_urls` as a generic iterable and runs `list(image_urls)`, which can yield surprising behavior for mappings or custom objects; if those are not expected inputs, it may be safer to explicitly handle only sequences/sets or to validate the type and fail fast.
## Individual Comments
### Comment 1
<location path="tests/unit/test_astr_agent_tool_exec.py" line_range="39" />
<code_context>
+ async def _fake_convert_to_file_path(self):
+ return "/tmp/event_image.png"
+
+ monkeypatch.setattr(Image, "convert_to_file_path", _fake_convert_to_file_path)
+
+ run_context = _build_run_context([Image(file="file:///tmp/original.png")])
</code_context>
<issue_to_address>
**suggestion (testing):** Consider a test case for error handling when `convert_to_file_path` raises.
Right now the tests only cover the successful conversion path. Please add a test that monkeypatches `convert_to_file_path` to raise (e.g., `RuntimeError`) and verifies that `_prepare_handoff_image_urls`:
- Does not raise, and
- Skips adding the failed image to `image_urls`.
This will lock in the intended failure-tolerant behavior around image conversion.
</issue_to_address>
### Comment 2
<location path="astrbot/core/astr_agent_tool_exec.py" line_range="69" />
<code_context>
+ return ext in cls._ALLOWED_IMAGE_EXTENSIONS
+
+ @classmethod
+ async def _prepare_handoff_image_urls(
+ cls,
+ run_context: ContextWrapper[AstrAgentContext],
</code_context>
<issue_to_address>
**issue (complexity):** Consider refactoring `_prepare_handoff_image_urls` into small, mostly pure helpers and letting `_execute_handoff` own the mutation of `tool_args` so the background path no longer has to prepare image URLs twice.
You can keep all new behavior while reducing complexity by making `_prepare_handoff_image_urls` mostly pure and limiting its responsibilities. That also lets you remove the double preparation in the background path.
### 1. Split `_prepare_handoff_image_urls` into smaller helpers
Factor out:
- coercion of `image_urls` into `list[str]`
- filtering/deduping
- extraction of event images
```python
@classmethod
def _coerce_image_urls(cls, image_urls: T.Any) -> list[str]:
if image_urls is None:
return []
if isinstance(image_urls, str):
return [image_urls]
if isinstance(image_urls, T.Iterable) and not isinstance(image_urls, (str, bytes)):
return list(image_urls)
# Fail fast or log here if you want a stricter contract
return [str(image_urls)]
@classmethod
def _filter_supported_image_urls(cls, candidates: list[str]) -> list[str]:
normalized = normalize_and_dedupe_strings(candidates)
sanitized = [item for item in normalized if cls._is_supported_image_ref(item)]
dropped_count = len(normalized) - len(sanitized)
if dropped_count > 0:
logger.warning(
"Dropped %d invalid image_urls entries in handoff tool args.",
dropped_count,
)
return sanitized
@classmethod
async def _iter_event_image_paths(
cls, run_context: ContextWrapper[AstrAgentContext]
) -> list[str]:
event = getattr(run_context.context, "event", None)
message_obj = getattr(event, "message_obj", None)
message = getattr(message_obj, "message", None)
if not message:
return []
paths: list[str] = []
for idx, component in enumerate(message):
if not isinstance(component, Image):
continue
try:
path = await component.convert_to_file_path()
if path and cls._is_supported_image_ref(path):
paths.append(path)
except Exception as e:
logger.error(
"Failed to convert handoff image component at index %d: %s",
idx,
e,
exc_info=True,
)
return paths
```
Then `_prepare_handoff_image_urls` becomes a thin orchestrator with a clearer contract:
```python
@classmethod
async def _prepare_handoff_image_urls(
cls,
run_context: ContextWrapper[AstrAgentContext],
image_urls: T.Any,
) -> list[str]:
candidates = cls._coerce_image_urls(image_urls)
event_paths = await cls._iter_event_image_paths(run_context)
candidates.extend(event_paths)
sanitized = cls._filter_supported_image_urls(candidates)
return sanitized
```
This makes `_prepare_handoff_image_urls` pure with respect to `tool_args` and isolates the context walk.
### 2. Stop mutating `tool_args` inside the helper
Use the return value explicitly at the call sites instead of having the helper mutate `tool_args` in-place:
```python
@classmethod
async def _execute_handoff(
cls,
tool: HandoffTool,
run_context: ContextWrapper[AstrAgentContext],
**tool_args,
):
input_ = tool_args.get("input")
image_urls = await cls._prepare_handoff_image_urls(
run_context,
tool_args.get("image_urls"),
)
tool_args["image_urls"] = image_urls
...
```
### 3. Remove double preparation in the background path
With the helper now pure, `_do_handoff_background` doesn’t need a separate pre‑step; let `_execute_handoff` handle it once:
```python
@classmethod
async def _do_handoff_background(
cls,
tool: HandoffTool,
run_context: ContextWrapper[AstrAgentContext],
task_id: str,
**tool_args,
) -> None:
"""Run the subagent handoff and, on completion, wake the main agent."""
result_text = ""
prepared_tool_args = dict(tool_args)
try:
async for r in cls._execute_handoff(
tool,
run_context,
**prepared_tool_args,
):
if isinstance(r, mcp.types.CallToolResult):
for content in r.content:
if isinstance(content, mcp.types.TextContent):
result_text += content.text + "\n"
except Exception as e:
result_text = (
f"error: Background task execution failed, internal error: {e!s}"
)
event = run_context.context.event
await cls._wake_main_agent_for_background_result(
run_context=run_context,
task_id=task_id,
tool_name=tool.name,
result_text=result_text,
tool_args=prepared_tool_args,
note=(
event.get_extra("background_note")
or f"Background task for subagent '{tool.agent.name}' finished."
),
summary_name=f"Dedicated to subagent `{tool.agent.name}`",
extra_result_fields={"subagent_name": tool.agent.name},
)
```
Here, `prepared_tool_args` will have `image_urls` set exactly once by `_execute_handoff` (via the pure helper), and `_do_handoff_background` doesn’t need to know how image URLs are prepared.
This keeps all current behavior (including event image merging and sanitization) but:
- removes the double preparation,
- makes the image URL handling testable in isolation,
- and decouples context traversal from argument coercion.帮我变得更有用!请对每条评论点 👍 或 👎,我会根据你的反馈改进后续评审。
Original comment in English
Hey - I've found 2 issues, and left some high level feedback:
- In
_do_handoff_background,_prepare_handoff_image_urlsis called before delegating to_execute_handoff, which itself calls_prepare_handoff_image_urlsagain, causing redundant normalization and event image scanning; consider refactoring so the preparation happens in only one place while still ensuring the storedtool_argsreflect the finalimage_urls. _prepare_handoff_image_urlscurrently treats any non-stringimage_urlsas a generic iterable and runslist(image_urls), which can yield surprising behavior for mappings or custom objects; if those are not expected inputs, it may be safer to explicitly handle only sequences/sets or to validate the type and fail fast.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `_do_handoff_background`, `_prepare_handoff_image_urls` is called before delegating to `_execute_handoff`, which itself calls `_prepare_handoff_image_urls` again, causing redundant normalization and event image scanning; consider refactoring so the preparation happens in only one place while still ensuring the stored `tool_args` reflect the final `image_urls`.
- `_prepare_handoff_image_urls` currently treats any non-string `image_urls` as a generic iterable and runs `list(image_urls)`, which can yield surprising behavior for mappings or custom objects; if those are not expected inputs, it may be safer to explicitly handle only sequences/sets or to validate the type and fail fast.
## Individual Comments
### Comment 1
<location path="tests/unit/test_astr_agent_tool_exec.py" line_range="39" />
<code_context>
+ async def _fake_convert_to_file_path(self):
+ return "/tmp/event_image.png"
+
+ monkeypatch.setattr(Image, "convert_to_file_path", _fake_convert_to_file_path)
+
+ run_context = _build_run_context([Image(file="file:///tmp/original.png")])
</code_context>
<issue_to_address>
**suggestion (testing):** Consider a test case for error handling when `convert_to_file_path` raises.
Right now the tests only cover the successful conversion path. Please add a test that monkeypatches `convert_to_file_path` to raise (e.g., `RuntimeError`) and verifies that `_prepare_handoff_image_urls`:
- Does not raise, and
- Skips adding the failed image to `image_urls`.
This will lock in the intended failure-tolerant behavior around image conversion.
</issue_to_address>
### Comment 2
<location path="astrbot/core/astr_agent_tool_exec.py" line_range="69" />
<code_context>
+ return ext in cls._ALLOWED_IMAGE_EXTENSIONS
+
+ @classmethod
+ async def _prepare_handoff_image_urls(
+ cls,
+ run_context: ContextWrapper[AstrAgentContext],
</code_context>
<issue_to_address>
**issue (complexity):** Consider refactoring `_prepare_handoff_image_urls` into small, mostly pure helpers and letting `_execute_handoff` own the mutation of `tool_args` so the background path no longer has to prepare image URLs twice.
You can keep all new behavior while reducing complexity by making `_prepare_handoff_image_urls` mostly pure and limiting its responsibilities. That also lets you remove the double preparation in the background path.
### 1. Split `_prepare_handoff_image_urls` into smaller helpers
Factor out:
- coercion of `image_urls` into `list[str]`
- filtering/deduping
- extraction of event images
```python
@classmethod
def _coerce_image_urls(cls, image_urls: T.Any) -> list[str]:
if image_urls is None:
return []
if isinstance(image_urls, str):
return [image_urls]
if isinstance(image_urls, T.Iterable) and not isinstance(image_urls, (str, bytes)):
return list(image_urls)
# Fail fast or log here if you want a stricter contract
return [str(image_urls)]
@classmethod
def _filter_supported_image_urls(cls, candidates: list[str]) -> list[str]:
normalized = normalize_and_dedupe_strings(candidates)
sanitized = [item for item in normalized if cls._is_supported_image_ref(item)]
dropped_count = len(normalized) - len(sanitized)
if dropped_count > 0:
logger.warning(
"Dropped %d invalid image_urls entries in handoff tool args.",
dropped_count,
)
return sanitized
@classmethod
async def _iter_event_image_paths(
cls, run_context: ContextWrapper[AstrAgentContext]
) -> list[str]:
event = getattr(run_context.context, "event", None)
message_obj = getattr(event, "message_obj", None)
message = getattr(message_obj, "message", None)
if not message:
return []
paths: list[str] = []
for idx, component in enumerate(message):
if not isinstance(component, Image):
continue
try:
path = await component.convert_to_file_path()
if path and cls._is_supported_image_ref(path):
paths.append(path)
except Exception as e:
logger.error(
"Failed to convert handoff image component at index %d: %s",
idx,
e,
exc_info=True,
)
return paths
```
Then `_prepare_handoff_image_urls` becomes a thin orchestrator with a clearer contract:
```python
@classmethod
async def _prepare_handoff_image_urls(
cls,
run_context: ContextWrapper[AstrAgentContext],
image_urls: T.Any,
) -> list[str]:
candidates = cls._coerce_image_urls(image_urls)
event_paths = await cls._iter_event_image_paths(run_context)
candidates.extend(event_paths)
sanitized = cls._filter_supported_image_urls(candidates)
return sanitized
```
This makes `_prepare_handoff_image_urls` pure with respect to `tool_args` and isolates the context walk.
### 2. Stop mutating `tool_args` inside the helper
Use the return value explicitly at the call sites instead of having the helper mutate `tool_args` in-place:
```python
@classmethod
async def _execute_handoff(
cls,
tool: HandoffTool,
run_context: ContextWrapper[AstrAgentContext],
**tool_args,
):
input_ = tool_args.get("input")
image_urls = await cls._prepare_handoff_image_urls(
run_context,
tool_args.get("image_urls"),
)
tool_args["image_urls"] = image_urls
...
```
### 3. Remove double preparation in the background path
With the helper now pure, `_do_handoff_background` doesn’t need a separate pre‑step; let `_execute_handoff` handle it once:
```python
@classmethod
async def _do_handoff_background(
cls,
tool: HandoffTool,
run_context: ContextWrapper[AstrAgentContext],
task_id: str,
**tool_args,
) -> None:
"""Run the subagent handoff and, on completion, wake the main agent."""
result_text = ""
prepared_tool_args = dict(tool_args)
try:
async for r in cls._execute_handoff(
tool,
run_context,
**prepared_tool_args,
):
if isinstance(r, mcp.types.CallToolResult):
for content in r.content:
if isinstance(content, mcp.types.TextContent):
result_text += content.text + "\n"
except Exception as e:
result_text = (
f"error: Background task execution failed, internal error: {e!s}"
)
event = run_context.context.event
await cls._wake_main_agent_for_background_result(
run_context=run_context,
task_id=task_id,
tool_name=tool.name,
result_text=result_text,
tool_args=prepared_tool_args,
note=(
event.get_extra("background_note")
or f"Background task for subagent '{tool.agent.name}' finished."
),
summary_name=f"Dedicated to subagent `{tool.agent.name}`",
extra_result_fields={"subagent_name": tool.agent.name},
)
```
Here, `prepared_tool_args` will have `image_urls` set exactly once by `_execute_handoff` (via the pure helper), and `_do_handoff_background` doesn’t need to know how image URLs are prepared.
This keeps all current behavior (including event image merging and sanitization) but:
- removes the double preparation,
- makes the image URL handling testable in isolation,
- and decouples context traversal from argument coercion.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| async def _fake_convert_to_file_path(self): | ||
| return "/tmp/event_image.png" | ||
|
|
||
| monkeypatch.setattr(Image, "convert_to_file_path", _fake_convert_to_file_path) |
There was a problem hiding this comment.
suggestion (testing): 建议增加一个当 convert_to_file_path 抛出异常时的错误处理测试用例。
目前的测试只覆盖了转换成功的路径。请新增一个测试,通过 monkeypatch 让 convert_to_file_path 抛出异常(例如 RuntimeError),并验证 _prepare_handoff_image_urls:
- 本身不会抛出异常;并且
- 会跳过将失败的图片添加到
image_urls中。
这样可以锁定在图片转换场景下预期的容错行为。
Original comment in English
suggestion (testing): Consider a test case for error handling when convert_to_file_path raises.
Right now the tests only cover the successful conversion path. Please add a test that monkeypatches convert_to_file_path to raise (e.g., RuntimeError) and verifies that _prepare_handoff_image_urls:
- Does not raise, and
- Skips adding the failed image to
image_urls.
This will lock in the intended failure-tolerant behavior around image conversion.
|
Hey @zouyonghe, I've posted a new review for you! |
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey - 我发现了 1 个 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="astrbot/core/astr_agent_tool_exec.py" line_range="45" />
<code_context>
+from astrbot.core.utils.string_utils import normalize_and_dedupe_strings
class FunctionToolExecutor(BaseFunctionToolExecutor[AstrAgentContext]):
+ _ALLOWED_IMAGE_EXTENSIONS = {
+ ".png",
</code_context>
<issue_to_address>
**issue (complexity):** 请考虑合并新的图片 URL 帮助方法,并在 `_execute_handoff` 中恢复纯参数处理,以简化数据流并减少辅助函数的数量和暴露面。
你可以在不损失现有行为的情况下,通过以下方式降低新增的复杂度:
1. **将图片相关的 helpers 折叠为一个统一的收集函数**
2. **让 handoff 的参数处理保持“纯函数”风格(不修改共享字典)**
### 1. 将图片 helpers 合并为一个主要 helper
用一个更高层级的 helper 来替代 `_coerce_image_urls`、`_filter_supported_image_urls` 和 `_iter_event_image_paths`,由它统一完成:
- 规范化 `image_urls_raw`
- 收集 event 中的图片路径
- 通过 `_is_supported_image_ref` 进行过滤和去重
保留 `_ALLOWED_IMAGE_EXTENSIONS` 和 `_is_supported_image_ref` 作为仅有的低层级 helper。
```python
class FunctionToolExecutor(BaseFunctionToolExecutor[AstrAgentContext]):
_ALLOWED_IMAGE_EXTENSIONS = {
".png",
".jpg",
".jpeg",
".gif",
".webp",
".bmp",
".tif",
".tiff",
".svg",
".heic",
}
@classmethod
def _is_supported_image_ref(cls, image_ref: str) -> bool:
if not image_ref:
return False
lowered = image_ref.lower()
if lowered.startswith(("http://", "https://", "base64://")):
return True
file_path = image_ref[8:] if lowered.startswith("file:///") else image_ref
ext = os.path.splitext(file_path)[1].lower()
return ext in cls._ALLOWED_IMAGE_EXTENSIONS
@classmethod
async def _collect_handoff_image_urls(
cls,
run_context: ContextWrapper[AstrAgentContext],
image_urls_raw: T.Any,
) -> list[str]:
# normalize input: None | str | Sequence[str]
candidates: list[str] = []
if image_urls_raw is None:
pass
elif isinstance(image_urls_raw, str):
candidates.append(image_urls_raw)
elif isinstance(image_urls_raw, Sequence) and not isinstance(
image_urls_raw, (str, bytes, bytearray)
):
candidates.extend(image_urls_raw)
else:
logger.warning(
"Unsupported image_urls type in handoff tool args: %s",
type(image_urls_raw).__name__,
)
# add event image paths
event = getattr(run_context.context, "event", None)
message_obj = getattr(event, "message_obj", None)
message = getattr(message_obj, "message", None)
if message:
for idx, component in enumerate(message):
if not isinstance(component, Image):
continue
try:
path = await component.convert_to_file_path()
if path and cls._is_supported_image_ref(path):
candidates.append(path)
except Exception as e:
logger.error(
"Failed to convert handoff image component at index %d: %s",
idx,
e,
exc_info=True,
)
# dedupe + filter
normalized = normalize_and_dedupe_strings(candidates)
sanitized = [item for item in normalized if cls._is_supported_image_ref(item)]
dropped_count = len(normalized) - len(sanitized)
if dropped_count > 0:
logger.warning(
"Dropped %d invalid image_urls entries in handoff tool args.",
dropped_count,
)
return sanitized
```
这样可以保持当前的所有行为,同时移除三个高度耦合的 helpers,并让图片 URL 相关的数据流在一个位置清晰可见。
之后你就可以删除 `_coerce_image_urls`、`_filter_supported_image_urls` 和 `_iter_event_image_paths`。
### 2. 让 `_execute_handoff` 对 tool_args 而言是“纯”的
通过以下方式避免共享的可变字典和 `prepared_tool_args`:
- 在 `_execute_handoff` 上恢复使用 `**tool_args`
- 在本地构造一个新的字典,其中包含计算得到的 `image_urls`
- 传递这个新字典,而不是修改调用方传入的字典
```python
@classmethod
async def _execute_handoff(
cls,
tool: HandoffTool,
run_context: ContextWrapper[AstrAgentContext],
**tool_args: T.Any,
):
input_ = tool_args.get("input")
image_urls = await cls._collect_handoff_image_urls(
run_context,
tool_args.get("image_urls"),
)
# new args with normalized image_urls
effective_tool_args: dict[str, T.Any] = {
**tool_args,
"image_urls": image_urls,
}
# ... use effective_tool_args instead of tool_args from here down ...
```
然后 `_do_handoff_background` 就不再需要拷贝/修改参数:
```python
@classmethod
async def _do_handoff_background(
cls,
tool: HandoffTool,
run_context: ContextWrapper[AstrAgentContext],
task_id: str,
**tool_args,
) -> None:
result_text = ""
try:
async for r in cls._execute_handoff(tool, run_context, **tool_args):
if isinstance(r, mcp.types.CallToolResult):
for content in r.content:
if isinstance(content, mcp.types.TextContent):
result_text += content.text + "\n"
except Exception as e:
result_text = (
f"error: Background task execution failed, internal error: {e!s}"
)
event = run_context.context.event
await cls._wake_main_agent_for_background_result(
run_context=run_context,
task_id=task_id,
tool_name=tool.name,
result_text=result_text,
tool_args=tool_args, # original args; image_urls derivation is internal
note=(
event.get_extra("background_note")
or f"Background task for subagent '{tool.agent.name}' finished."
),
summary_name=f"Dedicated to subagent `{tool.agent.name}`",
extra_result_fields={"subagent_name": tool.agent.name},
)
```
这样既保留了新的图片处理行为,又能够:
- 减少需要理解的 helper 数量(一个主要 helper + `_is_supported_image_ref`)
- 移除 `_execute_handoff` 和 `_do_handoff_background` 之间的可变共享状态
- 让调用点(`execute`、`_do_handoff_background`)更容易理解。
</issue_to_address>帮我变得更有用!请对每条评论点 👍 或 👎,我会根据反馈持续改进 review 质量。
Original comment in English
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="astrbot/core/astr_agent_tool_exec.py" line_range="45" />
<code_context>
+from astrbot.core.utils.string_utils import normalize_and_dedupe_strings
class FunctionToolExecutor(BaseFunctionToolExecutor[AstrAgentContext]):
+ _ALLOWED_IMAGE_EXTENSIONS = {
+ ".png",
</code_context>
<issue_to_address>
**issue (complexity):** Consider collapsing the new image URL helper methods and restoring pure argument handling in `_execute_handoff` to simplify the data flow and reduce helper surface area.
You can reduce the added complexity without losing behavior by:
1. **Collapsing the image helpers into a single collector**
2. **Making handoff argument handling pure (no mutation of shared dicts)**
### 1. Collapse image helpers into one main helper
Replace `_coerce_image_urls`, `_filter_supported_image_urls`, and `_iter_event_image_paths` with a single higher‑level helper that does all of:
- Normalize `image_urls_raw`
- Collect event image paths
- Filter + dedupe via `_is_supported_image_ref`
Keep `_ALLOWED_IMAGE_EXTENSIONS` and `_is_supported_image_ref` as the only low-level helpers.
```python
class FunctionToolExecutor(BaseFunctionToolExecutor[AstrAgentContext]):
_ALLOWED_IMAGE_EXTENSIONS = {
".png",
".jpg",
".jpeg",
".gif",
".webp",
".bmp",
".tif",
".tiff",
".svg",
".heic",
}
@classmethod
def _is_supported_image_ref(cls, image_ref: str) -> bool:
if not image_ref:
return False
lowered = image_ref.lower()
if lowered.startswith(("http://", "https://", "base64://")):
return True
file_path = image_ref[8:] if lowered.startswith("file:///") else image_ref
ext = os.path.splitext(file_path)[1].lower()
return ext in cls._ALLOWED_IMAGE_EXTENSIONS
@classmethod
async def _collect_handoff_image_urls(
cls,
run_context: ContextWrapper[AstrAgentContext],
image_urls_raw: T.Any,
) -> list[str]:
# normalize input: None | str | Sequence[str]
candidates: list[str] = []
if image_urls_raw is None:
pass
elif isinstance(image_urls_raw, str):
candidates.append(image_urls_raw)
elif isinstance(image_urls_raw, Sequence) and not isinstance(
image_urls_raw, (str, bytes, bytearray)
):
candidates.extend(image_urls_raw)
else:
logger.warning(
"Unsupported image_urls type in handoff tool args: %s",
type(image_urls_raw).__name__,
)
# add event image paths
event = getattr(run_context.context, "event", None)
message_obj = getattr(event, "message_obj", None)
message = getattr(message_obj, "message", None)
if message:
for idx, component in enumerate(message):
if not isinstance(component, Image):
continue
try:
path = await component.convert_to_file_path()
if path and cls._is_supported_image_ref(path):
candidates.append(path)
except Exception as e:
logger.error(
"Failed to convert handoff image component at index %d: %s",
idx,
e,
exc_info=True,
)
# dedupe + filter
normalized = normalize_and_dedupe_strings(candidates)
sanitized = [item for item in normalized if cls._is_supported_image_ref(item)]
dropped_count = len(normalized) - len(sanitized)
if dropped_count > 0:
logger.warning(
"Dropped %d invalid image_urls entries in handoff tool args.",
dropped_count,
)
return sanitized
```
This preserves all current behavior but removes three tightly-coupled helpers and makes the data flow around image URLs obvious in one place.
You can then delete `_coerce_image_urls`, `_filter_supported_image_urls`, and `_iter_event_image_paths`.
### 2. Make `_execute_handoff` pure w.r.t. tool_args
Avoid the shared mutable dict and `prepared_tool_args` by:
- Restoring `**tool_args` on `_execute_handoff`
- Building a new dict locally that includes the computed `image_urls`
- Passing that dict through, without mutating the caller’s dict
```python
@classmethod
async def _execute_handoff(
cls,
tool: HandoffTool,
run_context: ContextWrapper[AstrAgentContext],
**tool_args: T.Any,
):
input_ = tool_args.get("input")
image_urls = await cls._collect_handoff_image_urls(
run_context,
tool_args.get("image_urls"),
)
# new args with normalized image_urls
effective_tool_args: dict[str, T.Any] = {
**tool_args,
"image_urls": image_urls,
}
# ... use effective_tool_args instead of tool_args from here down ...
```
Then `_do_handoff_background` no longer needs to copy/mutate:
```python
@classmethod
async def _do_handoff_background(
cls,
tool: HandoffTool,
run_context: ContextWrapper[AstrAgentContext],
task_id: str,
**tool_args,
) -> None:
result_text = ""
try:
async for r in cls._execute_handoff(tool, run_context, **tool_args):
if isinstance(r, mcp.types.CallToolResult):
for content in r.content:
if isinstance(content, mcp.types.TextContent):
result_text += content.text + "\n"
except Exception as e:
result_text = (
f"error: Background task execution failed, internal error: {e!s}"
)
event = run_context.context.event
await cls._wake_main_agent_for_background_result(
run_context=run_context,
task_id=task_id,
tool_name=tool.name,
result_text=result_text,
tool_args=tool_args, # original args; image_urls derivation is internal
note=(
event.get_extra("background_note")
or f"Background task for subagent '{tool.agent.name}' finished."
),
summary_name=f"Dedicated to subagent `{tool.agent.name}`",
extra_result_fields={"subagent_name": tool.agent.name},
)
```
This retains the new image handling behavior but:
- Reduces the number of helpers you need to understand (one main helper + `_is_supported_image_ref`)
- Removes mutable shared state across `_execute_handoff` and `_do_handoff_background`
- Makes the call sites (`execute`, `_do_handoff_background`) simpler to follow.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey - 我在这里给出了一些总体反馈:
- 在
_collect_handoff_image_urls中,当image_urls_raw是一个序列/集合时,你在不按str进行过滤的情况下,将它的元素扩展到candidates中,这意味着非字符串条目(例如整数)会被传入normalize_and_dedupe_strings。如果该工具函数假设输入为字符串,建议在这里显式过滤为str或将其转换为str,以避免意外行为或类型错误。
给 AI Agents 的提示
Please address the comments from this code review:
## Overall Comments
- In `_collect_handoff_image_urls`, when `image_urls_raw` is a sequence/set you extend `candidates` with its elements without filtering by `str`, which means non-string entries (e.g., integers) will be passed into `normalize_and_dedupe_strings`; consider explicitly filtering or casting to `str` here to avoid surprises or type errors if that utility assumes string inputs.帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进后续的代码审查。
Original comment in English
Hey - I've left some high level feedback:
- In
_collect_handoff_image_urls, whenimage_urls_rawis a sequence/set you extendcandidateswith its elements without filtering bystr, which means non-string entries (e.g., integers) will be passed intonormalize_and_dedupe_strings; consider explicitly filtering or casting tostrhere to avoid surprises or type errors if that utility assumes string inputs.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `_collect_handoff_image_urls`, when `image_urls_raw` is a sequence/set you extend `candidates` with its elements without filtering by `str`, which means non-string entries (e.g., integers) will be passed into `normalize_and_dedupe_strings`; consider explicitly filtering or casting to `str` here to avoid surprises or type errors if that utility assumes string inputs.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey - 我发现了 1 个问题,并给出了一些高层次的反馈:
- 在
_do_handoff_background中,image_urls似乎绕过了_collect_handoff_image_urls,你可能希望在这里复用相同的归一化/校验辅助函数,以避免前景和后台在处理图像引用方式上的差异。 _is_supported_image_ref检查对文件路径要求已知扩展名;如果Image.convert_to_file_path()将来返回的是没有图片后缀的临时文件,这些文件会被静默丢弃——可以考虑要么放宽这个约束,要么在文档中说明/保证转换器始终保留一个允许的扩展名。
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- 在 `_do_handoff_background` 中,`image_urls` 似乎绕过了 `_collect_handoff_image_urls`,你可能希望在这里复用相同的归一化/校验辅助函数,以避免前景和后台在处理图像引用方式上的差异。
- `_is_supported_image_ref` 检查对文件路径要求已知扩展名;如果 `Image.convert_to_file_path()` 将来返回的是没有图片后缀的临时文件,这些文件会被静默丢弃——可以考虑要么放宽这个约束,要么在文档中说明/保证转换器始终保留一个允许的扩展名。
## Individual Comments
### Comment 1
<location path="astrbot/core/astr_agent_tool_exec.py" line_range="71" />
<code_context>
+ return ext in cls._ALLOWED_IMAGE_EXTENSIONS
+
+ @classmethod
+ async def _collect_handoff_image_urls(
+ cls,
+ run_context: ContextWrapper[AstrAgentContext],
</code_context>
<issue_to_address>
**issue (complexity):** 考虑重构新的图片 URL 处理逻辑,把归一化/提取拆分成各自聚焦的辅助函数,并在原位更新 tool_args,从而简化控制流和职责划分。
在保持新行为不变的前提下,通过一些小的重构,可以减少分支并避免职责混杂。
### 1. 将 `_collect_handoff_image_urls` 拆分为更聚焦的辅助函数
把“规范化参数”和“从消息中提取”分开,这样每个函数只做一件事,也更容易测试:
```python
@classmethod
def _collect_image_urls_from_args(cls, image_urls_raw: T.Any) -> list[str]:
if image_urls_raw is None:
return []
# Treat single string as a one-element list
if isinstance(image_urls_raw, str):
candidates = [image_urls_raw]
# Treat any sequence/set (except bytes-like) as a flat list of candidates
elif isinstance(image_urls_raw, (Sequence, AbstractSet)) and not isinstance(
image_urls_raw, (str, bytes, bytearray)
):
candidates = [item for item in image_urls_raw if isinstance(item, str)]
dropped = sum(1 for item in image_urls_raw if not isinstance(item, str))
if dropped:
logger.warning(
"Dropped %d non-string image_urls entries in handoff tool args.",
dropped,
)
else:
logger.warning(
"Unsupported image_urls type in handoff tool args: %s",
type(image_urls_raw).__name__,
)
candidates = []
return candidates
@classmethod
async def _collect_image_urls_from_message(
cls,
run_context: ContextWrapper[AstrAgentContext],
) -> list[str]:
event = getattr(run_context.context, "event", None)
message_obj = getattr(event, "message_obj", None)
message = getattr(message_obj, "message", None)
if not message:
return []
urls: list[str] = []
for idx, component in enumerate(message):
if not isinstance(component, Image):
continue
try:
path = await component.convert_to_file_path()
if path:
urls.append(path)
except Exception as e:
logger.error(
"Failed to convert handoff image component at index %d: %s",
idx,
e,
exc_info=True,
)
return urls
```
然后 `_collect_handoff_image_urls` 只需要负责协调归一化和过滤:
```python
@classmethod
async def _collect_handoff_image_urls(
cls,
run_context: ContextWrapper[AstrAgentContext],
image_urls_raw: T.Any,
) -> list[str]:
candidates: list[str] = []
candidates.extend(cls._collect_image_urls_from_args(image_urls_raw))
candidates.extend(await cls._collect_image_urls_from_message(run_context))
normalized = normalize_and_dedupe_strings(candidates)
sanitized = [item for item in normalized if cls._is_supported_image_ref(item)]
dropped_count = len(normalized) - len(sanitized)
if dropped_count > 0:
logger.warning(
"Dropped %d invalid image_urls entries in handoff tool args.",
dropped_count,
)
return sanitized
```
这样也去掉了重复的 `_is_supported_image_ref` 调用(就不需要在消息循环内部检查一次、归一化后再检查一次)。
### 2. 避免额外的 `effective_tool_args` 字典
由于只有 `image_urls` 会被转换,你可以就地更新 `tool_args`,并通过局部变量传递,以避免出现额外的“真值来源”:
```python
@classmethod
async def _execute_handoff(
cls,
tool: HandoffTool,
run_context: ContextWrapper[AstrAgentContext],
**tool_args: T.Any,
):
input_ = tool_args.get("input")
image_urls = await cls._collect_handoff_image_urls(
run_context,
tool_args.get("image_urls"),
)
tool_args["image_urls"] = image_urls
# ... build toolset, etc.
llm_resp = await ctx.tool_loop_agent(
event=event,
chat_provider_id=prov_id,
prompt=input_,
image_urls=image_urls,
system_prompt=tool.agent.instructions,
tools=toolset,
contexts=contexts,
max_steps=30,
run_hooks=tool.agent.run_hooks,
stream=ctx.get_config().get("provider_settings", {}).get("stream", False),
)
```
行为保持不变,但 `_execute_handoff` 的数据流更简单、活动部件更少。
</issue_to_address>帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进评审质量。
Original comment in English
Hey - I've found 1 issue, and left some high level feedback:
- In
_do_handoff_backgroundtheimage_urlsappear to bypass_collect_handoff_image_urls, so you may want to reuse the same normalization/validation helper there to avoid foreground vs background divergence in how image references are handled. - The
_is_supported_image_refcheck requires a known extension for file paths; ifImage.convert_to_file_path()ever returns temp files without an image suffix they will be silently dropped—consider either relaxing this constraint or documenting/guaranteeing that the converter always preserves an allowed extension.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `_do_handoff_background` the `image_urls` appear to bypass `_collect_handoff_image_urls`, so you may want to reuse the same normalization/validation helper there to avoid foreground vs background divergence in how image references are handled.
- The `_is_supported_image_ref` check requires a known extension for file paths; if `Image.convert_to_file_path()` ever returns temp files without an image suffix they will be silently dropped—consider either relaxing this constraint or documenting/guaranteeing that the converter always preserves an allowed extension.
## Individual Comments
### Comment 1
<location path="astrbot/core/astr_agent_tool_exec.py" line_range="71" />
<code_context>
+ return ext in cls._ALLOWED_IMAGE_EXTENSIONS
+
+ @classmethod
+ async def _collect_handoff_image_urls(
+ cls,
+ run_context: ContextWrapper[AstrAgentContext],
</code_context>
<issue_to_address>
**issue (complexity):** Consider refactoring the new image URL handling to split normalization/extraction into focused helpers and update tool_args in place to simplify control flow and responsibilities.
You can keep the new behavior while reducing branching and responsibility-mixing with a few small refactors.
### 1. Split `_collect_handoff_image_urls` into focused helpers
Separate “normalize args” and “extract from message” so each function does one thing and is easier to test:
```python
@classmethod
def _collect_image_urls_from_args(cls, image_urls_raw: T.Any) -> list[str]:
if image_urls_raw is None:
return []
# Treat single string as a one-element list
if isinstance(image_urls_raw, str):
candidates = [image_urls_raw]
# Treat any sequence/set (except bytes-like) as a flat list of candidates
elif isinstance(image_urls_raw, (Sequence, AbstractSet)) and not isinstance(
image_urls_raw, (str, bytes, bytearray)
):
candidates = [item for item in image_urls_raw if isinstance(item, str)]
dropped = sum(1 for item in image_urls_raw if not isinstance(item, str))
if dropped:
logger.warning(
"Dropped %d non-string image_urls entries in handoff tool args.",
dropped,
)
else:
logger.warning(
"Unsupported image_urls type in handoff tool args: %s",
type(image_urls_raw).__name__,
)
candidates = []
return candidates
@classmethod
async def _collect_image_urls_from_message(
cls,
run_context: ContextWrapper[AstrAgentContext],
) -> list[str]:
event = getattr(run_context.context, "event", None)
message_obj = getattr(event, "message_obj", None)
message = getattr(message_obj, "message", None)
if not message:
return []
urls: list[str] = []
for idx, component in enumerate(message):
if not isinstance(component, Image):
continue
try:
path = await component.convert_to_file_path()
if path:
urls.append(path)
except Exception as e:
logger.error(
"Failed to convert handoff image component at index %d: %s",
idx,
e,
exc_info=True,
)
return urls
```
Then `_collect_handoff_image_urls` just orchestrates normalization and filtering:
```python
@classmethod
async def _collect_handoff_image_urls(
cls,
run_context: ContextWrapper[AstrAgentContext],
image_urls_raw: T.Any,
) -> list[str]:
candidates: list[str] = []
candidates.extend(cls._collect_image_urls_from_args(image_urls_raw))
candidates.extend(await cls._collect_image_urls_from_message(run_context))
normalized = normalize_and_dedupe_strings(candidates)
sanitized = [item for item in normalized if cls._is_supported_image_ref(item)]
dropped_count = len(normalized) - len(sanitized)
if dropped_count > 0:
logger.warning(
"Dropped %d invalid image_urls entries in handoff tool args.",
dropped_count,
)
return sanitized
```
This also removes the double `_is_supported_image_ref` calls (no need to check inside the message loop and again after normalization).
### 2. Avoid the extra `effective_tool_args` dict
Since only `image_urls` is being transformed, you can update `tool_args` in place and pass the local variable to avoid an additional source of truth:
```python
@classmethod
async def _execute_handoff(
cls,
tool: HandoffTool,
run_context: ContextWrapper[AstrAgentContext],
**tool_args: T.Any,
):
input_ = tool_args.get("input")
image_urls = await cls._collect_handoff_image_urls(
run_context,
tool_args.get("image_urls"),
)
tool_args["image_urls"] = image_urls
# ... build toolset, etc.
llm_resp = await ctx.tool_loop_agent(
event=event,
chat_provider_id=prov_id,
prompt=input_,
image_urls=image_urls,
system_prompt=tool.agent.instructions,
tools=toolset,
contexts=contexts,
max_steps=30,
run_hooks=tool.agent.run_hooks,
stream=ctx.get_config().get("provider_settings", {}).get("stream", False),
)
```
Behavior stays the same, but `_execute_handoff` now has simpler data flow and fewer moving parts.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey - 我发现了 5 个问题,并留下了一些高层次的反馈:
- 图像 URL 规范化逻辑(包括
_ALLOWED_IMAGE_EXTENSIONS和_collect_handoff_image_urls)似乎与主 agent 的行为重复;建议将其抽取为一个共享的 helper,这样未来的改动可以在各个 agent 之间保持同步。 - 在
_collect_image_urls_from_args和_collect_handoff_image_urls中,对于被丢弃/无效条目的 warning 日志,在有用户输入的场景下可能会非常嘈杂;可以考虑降到 debug 级别,或者增加某种聚合/限流机制。
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The image URL normalization logic (including `_ALLOWED_IMAGE_EXTENSIONS` and `_collect_handoff_image_urls`) appears to duplicate the main-agent behavior; consider extracting this into a shared helper so future changes stay in sync across agents.
- In `_collect_image_urls_from_args` and `_collect_handoff_image_urls`, the warning logs for dropped/invalid entries could become noisy with user-provided input; consider downgrading to debug level or adding some form of aggregation/rate limiting.
## Individual Comments
### Comment 1
<location path="astrbot/core/astr_agent_tool_exec.py" line_range="66" />
<code_context>
+ lowered = image_ref.lower()
+ if lowered.startswith(("http://", "https://", "base64://")):
+ return True
+ file_path = image_ref[8:] if lowered.startswith("file:///") else image_ref
+ ext = os.path.splitext(file_path)[1].lower()
+ if ext in cls._ALLOWED_IMAGE_EXTENSIONS:
</code_context>
<issue_to_address>
**suggestion:** 考虑对 `file://` URL 做更健壮的解析以避免边界情况。
目前只会对 `file:///` 前缀做裁剪,因此 `file://path` 或 `file://host/path` 的处理会不一致。通过 `urllib.parse.urlparse`(或类似方法)解析出 path 组件,可以让对所有 `file://` 形式的支持更加健壮,并且不再需要硬编码偏移量。
建议实现:
```python
import os
from urllib.parse import urlparse, unquote
```
```python
@classmethod
def _is_supported_image_ref(cls, image_ref: str) -> bool:
if not image_ref:
return False
lowered = image_ref.lower()
if lowered.startswith(("http://", "https://", "base64://")):
return True
file_path = image_ref
if lowered.startswith("file://"):
parsed = urlparse(image_ref)
if parsed.scheme == "file":
# 对于 file:// URL,使用解析出的 path 组件并解码任何 URL 编码。
file_path = unquote(parsed.path or "")
ext = os.path.splitext(file_path)[1].lower()
if ext in cls._ALLOWED_IMAGE_EXTENSIONS:
return True
# 保持对由图像转换器返回的无扩展名临时文件的支持。
return ext == "" and os.path.exists(file_path)
```
</issue_to_address>
### Comment 2
<location path="astrbot/core/astr_agent_tool_exec.py" line_range="136-141" />
<code_context>
+ candidates.extend(cls._collect_image_urls_from_args(image_urls_raw))
+ candidates.extend(await cls._collect_image_urls_from_message(run_context))
+
+ normalized = normalize_and_dedupe_strings(candidates)
+ sanitized = [item for item in normalized if cls._is_supported_image_ref(item)]
+ dropped_count = len(normalized) - len(sanitized)
+ if dropped_count > 0:
+ logger.warning(
+ "Dropped %d invalid image_urls entries in handoff tool args.",
+ dropped_count,
+ )
</code_context>
<issue_to_address>
**nitpick:** 这个 warning 提示看起来只是在说丢弃了来自工具参数的条目,但实际上也包含了从消息中提取的 URL。
`candidates` 中同时包含来自工具参数和入站消息的 URL,但 warning 文案只提到 "handoff tool args"。由于被丢弃的条目有可能来自任一来源,可以考虑在日志中区分来源,或者使用更通用的措辞(例如 "handoff image inputs"),以避免调试时产生混淆。
</issue_to_address>
### Comment 3
<location path="tests/unit/test_astr_agent_tool_exec.py" line_range="32-33" />
<code_context>
+ return ContextWrapper(context=ctx)
+
+
+@pytest.mark.asyncio
+async def test_collect_handoff_image_urls_normalizes_filters_and_appends_event_image(
+ monkeypatch: pytest.MonkeyPatch,
+):
</code_context>
<issue_to_address>
**suggestion (testing):** 增加对 `base64://` 和 `file:///` 图像引用以及其他受支持扩展名的测试,以覆盖 `_is_supported_image_ref` 的行为。
当前测试覆盖了 HTTP URL、一个有效的图像扩展名、一个非图像扩展名以及无扩展名的事件文件。由于 `_is_supported_image_ref` 还支持 `base64://` URI、`file:///...` 路径和其他扩展名(如 `.heic` 和 `.svg`),请添加一个参数化测试,将这些引用的混合输入传给 `_collect_handoff_image_urls`(或 `_collect_image_urls_from_args`),并断言只返回受支持的引用。这样可以让测试与 `_is_supported_image_ref` 的行为更加一致,并防止在处理不同图像 scheme 和扩展名时出现回归。
建议实现:
```python
def _build_run_context(message_components: list[object] | None = None):
event = _DummyEvent(message_components=message_components)
ctx = SimpleNamespace(event=event, context=SimpleNamespace())
return ContextWrapper(context=ctx)
@pytest.mark.asyncio
async def test_collect_handoff_image_urls_normalizes_filters_and_appends_event_image(
monkeypatch: pytest.MonkeyPatch,
):
async def _fake_convert_to_file_path(self):
return "/tmp/event_image.png"
monkeypatch.setattr(Image, "convert_to_file_path", _fake_convert_to_file_path)
run_context = _build_run_context([Image(file="file:///tmp/original.png")])
image_urls_input = (
" https://example.com/a.png ",
"/tmp/not_an_image.txt",
"/tmp/local.webp",
)
@pytest.mark.asyncio
@pytest.mark.parametrize(
"image_refs, expected_supported_refs",
[
pytest.param(
(
# supported HTTP(S) URL
"https://example.com/valid.png",
# supported base64 URI
"base64://iVBORw0KGgoAAAANSUhEUgAAAAUA",
# supported file:// paths with different extensions
"file:///tmp/photo.heic",
"file:///tmp/vector.svg",
# unsupported refs that should be filtered out
"file:///tmp/not-image.txt",
"mailto:user@example.com",
"random-string-without-scheme-or-extension",
),
{
"https://example.com/valid.png",
"base64://iVBORw0KGgoAAAANSUhEUgAAAAUA",
"file:///tmp/photo.heic",
"file:///tmp/vector.svg",
},
id="mixed_supported_and_unsupported_schemes_and_extensions",
),
],
)
async def test_collect_handoff_image_urls_filters_supported_schemes_and_extensions(
monkeypatch: pytest.MonkeyPatch,
image_refs: tuple[str, ...],
expected_supported_refs: set[str],
):
# 确保事件图片处理是确定性的,并且不会影响过滤行为
async def _fake_convert_to_file_path(self):
return "/tmp/event_image.png"
monkeypatch.setattr(Image, "convert_to_file_path", _fake_convert_to_file_path)
# 对于该测试,不传入事件图片:我们只关注函数如何过滤引用
run_context = _build_run_context([])
# 调用与 handoff 图像收集测试中相同的 helper,传入混合了受支持和不受支持的图像引用。
result = await _collect_handoff_image_urls(run_context, *image_refs)
# 函数应只返回受支持的引用(HTTP(S)、base64://、具有受支持图像扩展名的 file://),并过滤掉其余的。
assert expected_supported_refs.issubset(set(result))
```
这里有一些假设:
1. `_collect_handoff_image_urls` 是该测试文件中其他地方使用的 helper,并接受 `(run_context, *image_refs)` 作为参数。
如果它的签名不同(例如期望 `image_urls_input=image_refs` 或单个可迭代对象),请相应调整调用方式:
- 示例:`result = await _collect_handoff_image_urls(run_context, image_urls_input=image_refs)` 或
- 示例:`result = await _collect_handoff_image_urls(run_context, image_refs)`。
2. 该函数可能会追加其他 URL(例如事件图片),因此断言使用 `issubset` 而非严格相等。
如果在空 `run_context` 的情况下可以保证函数只返回过滤后的 `image_refs` 而不会追加额外 URL,则可以将断言收紧为:
- `assert set(result) == expected_supported_refs`。
3. 如果你的测试套件更倾向于直接使用 `_collect_image_urls_from_args`,可以将对 `_collect_handoff_image_urls` 的调用替换为 `_collect_image_urls_from_args`,同时保持相同的参数和断言。
</issue_to_address>
### Comment 4
<location path="tests/unit/test_astr_agent_tool_exec.py" line_range="41-49" />
<code_context>
+
+ monkeypatch.setattr(Image, "convert_to_file_path", _fake_convert_to_file_path)
+
+ run_context = _build_run_context([Image(file="file:///tmp/original.png")])
+ image_urls_input = (
+ " https://example.com/a.png ",
+ "/tmp/not_an_image.txt",
+ "/tmp/local.webp",
+ 123,
+ )
+
+ image_urls = await FunctionToolExecutor._collect_handoff_image_urls(
+ run_context,
+ image_urls_input,
</code_context>
<issue_to_address>
**suggestion (testing):** 覆盖 `image_urls` 为 `None` 且只应收集事件图片的场景。
当前测试总是传入非 `None` 的 `image_urls`(字符串/元组/列表)。请添加一个测试,将 `image_urls_raw` 设为 `None`,并在消息中包含一个或多个 `Image` 组件,以验证事件派生的图像路径仍然会被收集,并确保这种默认行为不会出现回归。
</issue_to_address>
### Comment 5
<location path="tests/unit/test_astr_agent_tool_exec.py" line_range="118-127" />
<code_context>
+
+
+@pytest.mark.asyncio
+async def test_collect_handoff_image_urls_keeps_extensionless_existing_event_file(
+ monkeypatch: pytest.MonkeyPatch,
+):
+ async def _fake_convert_to_file_path(self):
+ return "/tmp/astrbot-handoff-image"
+
+ monkeypatch.setattr(Image, "convert_to_file_path", _fake_convert_to_file_path)
+ monkeypatch.setattr(
+ "astrbot.core.astr_agent_tool_exec.os.path.exists", lambda _: True
+ )
+
+ run_context = _build_run_context([Image(file="file:///tmp/original.png")])
+ image_urls = await FunctionToolExecutor._collect_handoff_image_urls(
+ run_context,
+ [],
+ )
+
+ assert image_urls == ["/tmp/astrbot-handoff-image"]
</code_context>
<issue_to_address>
**suggestion (testing):** 为不存在的无扩展名路径补充一个测试,断言它们会被过滤掉。
为了覆盖 `_is_supported_image_ref` 的反向分支,可以将 `convert_to_file_path` 打补丁为返回一个无扩展名路径,并让 `os.path.exists` 返回 `False`,然后断言 `image_urls` 为空(或者至少不包含该路径)。这样可以锁定现有与不存在的无扩展名文件之间在行为上的预期差异。
</issue_to_address>帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进 review 质量。
Original comment in English
Hey - I've found 5 issues, and left some high level feedback:
- The image URL normalization logic (including
_ALLOWED_IMAGE_EXTENSIONSand_collect_handoff_image_urls) appears to duplicate the main-agent behavior; consider extracting this into a shared helper so future changes stay in sync across agents. - In
_collect_image_urls_from_argsand_collect_handoff_image_urls, the warning logs for dropped/invalid entries could become noisy with user-provided input; consider downgrading to debug level or adding some form of aggregation/rate limiting.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The image URL normalization logic (including `_ALLOWED_IMAGE_EXTENSIONS` and `_collect_handoff_image_urls`) appears to duplicate the main-agent behavior; consider extracting this into a shared helper so future changes stay in sync across agents.
- In `_collect_image_urls_from_args` and `_collect_handoff_image_urls`, the warning logs for dropped/invalid entries could become noisy with user-provided input; consider downgrading to debug level or adding some form of aggregation/rate limiting.
## Individual Comments
### Comment 1
<location path="astrbot/core/astr_agent_tool_exec.py" line_range="66" />
<code_context>
+ lowered = image_ref.lower()
+ if lowered.startswith(("http://", "https://", "base64://")):
+ return True
+ file_path = image_ref[8:] if lowered.startswith("file:///") else image_ref
+ ext = os.path.splitext(file_path)[1].lower()
+ if ext in cls._ALLOWED_IMAGE_EXTENSIONS:
</code_context>
<issue_to_address>
**suggestion:** Consider more robust parsing of file:// URLs to avoid edge cases.
This currently only strips the prefix for `file:///`, so `file://path` or `file://host/path` will be handled inconsistently. Parsing via `urllib.parse.urlparse` (or similar) to get the path component would make this robust across all `file://` forms and remove the need for hardcoded offsets.
Suggested implementation:
```python
import os
from urllib.parse import urlparse, unquote
```
```python
@classmethod
def _is_supported_image_ref(cls, image_ref: str) -> bool:
if not image_ref:
return False
lowered = image_ref.lower()
if lowered.startswith(("http://", "https://", "base64://")):
return True
file_path = image_ref
if lowered.startswith("file://"):
parsed = urlparse(image_ref)
if parsed.scheme == "file":
# For file:// URLs, use the parsed path component and decode any URL encoding.
file_path = unquote(parsed.path or "")
ext = os.path.splitext(file_path)[1].lower()
if ext in cls._ALLOWED_IMAGE_EXTENSIONS:
return True
# Keep support for extension-less temp files returned by image converters.
return ext == "" and os.path.exists(file_path)
```
</issue_to_address>
### Comment 2
<location path="astrbot/core/astr_agent_tool_exec.py" line_range="136-141" />
<code_context>
+ candidates.extend(cls._collect_image_urls_from_args(image_urls_raw))
+ candidates.extend(await cls._collect_image_urls_from_message(run_context))
+
+ normalized = normalize_and_dedupe_strings(candidates)
+ sanitized = [item for item in normalized if cls._is_supported_image_ref(item)]
+ dropped_count = len(normalized) - len(sanitized)
+ if dropped_count > 0:
+ logger.warning(
+ "Dropped %d invalid image_urls entries in handoff tool args.",
+ dropped_count,
+ )
</code_context>
<issue_to_address>
**nitpick:** The warning message suggests only tool-arg drops, but it also includes message-derived URLs.
`candidates` includes URLs from both tool args and the incoming message, but the warning only mentions "handoff tool args." Since dropped entries can come from either source, consider either distinguishing the sources in the log or using more generic wording (e.g., "handoff image inputs") to avoid confusion during debugging.
</issue_to_address>
### Comment 3
<location path="tests/unit/test_astr_agent_tool_exec.py" line_range="32-33" />
<code_context>
+ return ContextWrapper(context=ctx)
+
+
+@pytest.mark.asyncio
+async def test_collect_handoff_image_urls_normalizes_filters_and_appends_event_image(
+ monkeypatch: pytest.MonkeyPatch,
+):
</code_context>
<issue_to_address>
**suggestion (testing):** Add tests for `base64://` and `file:///` image refs plus other supported extensions to match `_is_supported_image_ref` behavior.
Current tests cover HTTP URLs, one valid image extension, a non-image extension, and extensionless event files. Since `_is_supported_image_ref` also supports `base64://` URIs, `file:///...` paths, and other extensions like `.heic` and `.svg`, please add a parameterized test that passes a mix of these refs into `_collect_handoff_image_urls` (or `_collect_image_urls_from_args`) and asserts that only supported refs are returned. This will better align the tests with `_is_supported_image_ref` and guard against regressions in handling different image schemes and extensions.
Suggested implementation:
```python
def _build_run_context(message_components: list[object] | None = None):
event = _DummyEvent(message_components=message_components)
ctx = SimpleNamespace(event=event, context=SimpleNamespace())
return ContextWrapper(context=ctx)
@pytest.mark.asyncio
async def test_collect_handoff_image_urls_normalizes_filters_and_appends_event_image(
monkeypatch: pytest.MonkeyPatch,
):
async def _fake_convert_to_file_path(self):
return "/tmp/event_image.png"
monkeypatch.setattr(Image, "convert_to_file_path", _fake_convert_to_file_path)
run_context = _build_run_context([Image(file="file:///tmp/original.png")])
image_urls_input = (
" https://example.com/a.png ",
"/tmp/not_an_image.txt",
"/tmp/local.webp",
)
@pytest.mark.asyncio
@pytest.mark.parametrize(
"image_refs, expected_supported_refs",
[
pytest.param(
(
# supported HTTP(S) URL
"https://example.com/valid.png",
# supported base64 URI
"base64://iVBORw0KGgoAAAANSUhEUgAAAAUA",
# supported file:// paths with different extensions
"file:///tmp/photo.heic",
"file:///tmp/vector.svg",
# unsupported refs that should be filtered out
"file:///tmp/not-image.txt",
"mailto:user@example.com",
"random-string-without-scheme-or-extension",
),
{
"https://example.com/valid.png",
"base64://iVBORw0KGgoAAAANSUhEUgAAAAUA",
"file:///tmp/photo.heic",
"file:///tmp/vector.svg",
},
id="mixed_supported_and_unsupported_schemes_and_extensions",
),
],
)
async def test_collect_handoff_image_urls_filters_supported_schemes_and_extensions(
monkeypatch: pytest.MonkeyPatch,
image_refs: tuple[str, ...],
expected_supported_refs: set[str],
):
# Ensure event image handling is deterministic and does not affect filtering behavior
async def _fake_convert_to_file_path(self):
return "/tmp/event_image.png"
monkeypatch.setattr(Image, "convert_to_file_path", _fake_convert_to_file_path)
# No event images for this test: we only care about how the function filters the refs
run_context = _build_run_context([])
# Call the same helper used by handoff image collection tests,
# passing in a mix of supported and unsupported image references.
result = await _collect_handoff_image_urls(run_context, *image_refs)
# The function should only return the supported refs (HTTP(S), base64://, file://
# with supported image extensions) and filter out the rest.
assert expected_supported_refs.issubset(set(result))
```
This change assumes:
1. `_collect_handoff_image_urls` is the helper used elsewhere in this test file and accepts `(run_context, *image_refs)` as arguments.
If its signature differs (e.g., it expects `image_urls_input=image_refs` or a single iterable), adjust the call accordingly:
- Example: `result = await _collect_handoff_image_urls(run_context, image_urls_input=image_refs)` or
- Example: `result = await _collect_handoff_image_urls(run_context, image_refs)`.
2. The function may append additional URLs (such as event images), so the assertion uses `issubset` instead of strict equality.
If the function is guaranteed to only return filtered `image_refs` without extra URLs for an empty `run_context`, you can tighten the assertion to:
- `assert set(result) == expected_supported_refs`.
3. If your test suite prefers using `_collect_image_urls_from_args` directly, replace the call to `_collect_handoff_image_urls` with `_collect_image_urls_from_args` while keeping the same arguments and assertions.
</issue_to_address>
### Comment 4
<location path="tests/unit/test_astr_agent_tool_exec.py" line_range="41-49" />
<code_context>
+
+ monkeypatch.setattr(Image, "convert_to_file_path", _fake_convert_to_file_path)
+
+ run_context = _build_run_context([Image(file="file:///tmp/original.png")])
+ image_urls_input = (
+ " https://example.com/a.png ",
+ "/tmp/not_an_image.txt",
+ "/tmp/local.webp",
+ 123,
+ )
+
+ image_urls = await FunctionToolExecutor._collect_handoff_image_urls(
+ run_context,
+ image_urls_input,
</code_context>
<issue_to_address>
**suggestion (testing):** Cover the case where `image_urls` is `None` and only event images should be collected.
Current tests always pass a non-`None` `image_urls` value (string/tuple/list). Please add a test where `image_urls_raw` is `None` and the message includes one or more `Image` components, to verify that event-derived image paths are still collected and this default behavior doesn’t regress.
</issue_to_address>
### Comment 5
<location path="tests/unit/test_astr_agent_tool_exec.py" line_range="118-127" />
<code_context>
+
+
+@pytest.mark.asyncio
+async def test_collect_handoff_image_urls_keeps_extensionless_existing_event_file(
+ monkeypatch: pytest.MonkeyPatch,
+):
+ async def _fake_convert_to_file_path(self):
+ return "/tmp/astrbot-handoff-image"
+
+ monkeypatch.setattr(Image, "convert_to_file_path", _fake_convert_to_file_path)
+ monkeypatch.setattr(
+ "astrbot.core.astr_agent_tool_exec.os.path.exists", lambda _: True
+ )
+
+ run_context = _build_run_context([Image(file="file:///tmp/original.png")])
+ image_urls = await FunctionToolExecutor._collect_handoff_image_urls(
+ run_context,
+ [],
+ )
+
+ assert image_urls == ["/tmp/astrbot-handoff-image"]
</code_context>
<issue_to_address>
**suggestion (testing):** Add a complementary test for extensionless paths that do *not* exist to assert they are filtered out.
To exercise the opposite branch of `_is_supported_image_ref`, patch `convert_to_file_path` to return an extensionless path and `os.path.exists` to return `False`, then assert that `image_urls` is empty (or at least does not include that path). This will lock in the intended behavior difference between existing and non-existing extensionless files.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| @pytest.mark.asyncio | ||
| async def test_collect_handoff_image_urls_normalizes_filters_and_appends_event_image( |
There was a problem hiding this comment.
suggestion (testing): 增加对 base64:// 和 file:/// 图像引用以及其他受支持扩展名的测试,以覆盖 _is_supported_image_ref 的行为。
当前测试覆盖了 HTTP URL、一个有效的图像扩展名、一个非图像扩展名以及无扩展名的事件文件。由于 _is_supported_image_ref 还支持 base64:// URI、file:///... 路径和其他扩展名(如 .heic 和 .svg),请添加一个参数化测试,将这些引用的混合输入传给 _collect_handoff_image_urls(或 _collect_image_urls_from_args),并断言只返回受支持的引用。这样可以让测试与 _is_supported_image_ref 的行为更加一致,并防止在处理不同图像 scheme 和扩展名时出现回归。
建议实现:
def _build_run_context(message_components: list[object] | None = None):
event = _DummyEvent(message_components=message_components)
ctx = SimpleNamespace(event=event, context=SimpleNamespace())
return ContextWrapper(context=ctx)
@pytest.mark.asyncio
async def test_collect_handoff_image_urls_normalizes_filters_and_appends_event_image(
monkeypatch: pytest.MonkeyPatch,
):
async def _fake_convert_to_file_path(self):
return "/tmp/event_image.png"
monkeypatch.setattr(Image, "convert_to_file_path", _fake_convert_to_file_path)
run_context = _build_run_context([Image(file="file:///tmp/original.png")])
image_urls_input = (
" https://example.com/a.png ",
"/tmp/not_an_image.txt",
"/tmp/local.webp",
)
@pytest.mark.asyncio
@pytest.mark.parametrize(
"image_refs, expected_supported_refs",
[
pytest.param(
(
# supported HTTP(S) URL
"https://example.com/valid.png",
# supported base64 URI
"base64://iVBORw0KGgoAAAANSUhEUgAAAAUA",
# supported file:// paths with different extensions
"file:///tmp/photo.heic",
"file:///tmp/vector.svg",
# unsupported refs that should be filtered out
"file:///tmp/not-image.txt",
"mailto:user@example.com",
"random-string-without-scheme-or-extension",
),
{
"https://example.com/valid.png",
"base64://iVBORw0KGgoAAAANSUhEUgAAAAUA",
"file:///tmp/photo.heic",
"file:///tmp/vector.svg",
},
id="mixed_supported_and_unsupported_schemes_and_extensions",
),
],
)
async def test_collect_handoff_image_urls_filters_supported_schemes_and_extensions(
monkeypatch: pytest.MonkeyPatch,
image_refs: tuple[str, ...],
expected_supported_refs: set[str],
):
# 确保事件图片处理是确定性的,并且不会影响过滤行为
async def _fake_convert_to_file_path(self):
return "/tmp/event_image.png"
monkeypatch.setattr(Image, "convert_to_file_path", _fake_convert_to_file_path)
# 对于该测试,不传入事件图片:我们只关注函数如何过滤引用
run_context = _build_run_context([])
# 调用与 handoff 图像收集测试中相同的 helper,传入混合了受支持和不受支持的图像引用。
result = await _collect_handoff_image_urls(run_context, *image_refs)
# 函数应只返回受支持的引用(HTTP(S)、base64://、具有受支持图像扩展名的 file://),并过滤掉其余的。
assert expected_supported_refs.issubset(set(result))这里有一些假设:
-
_collect_handoff_image_urls是该测试文件中其他地方使用的 helper,并接受(run_context, *image_refs)作为参数。
如果它的签名不同(例如期望image_urls_input=image_refs或单个可迭代对象),请相应调整调用方式:- 示例:
result = await _collect_handoff_image_urls(run_context, image_urls_input=image_refs)或 - 示例:
result = await _collect_handoff_image_urls(run_context, image_refs)。
- 示例:
-
该函数可能会追加其他 URL(例如事件图片),因此断言使用
issubset而非严格相等。
如果在空run_context的情况下可以保证函数只返回过滤后的image_refs而不会追加额外 URL,则可以将断言收紧为:assert set(result) == expected_supported_refs。
-
如果你的测试套件更倾向于直接使用
_collect_image_urls_from_args,可以将对_collect_handoff_image_urls的调用替换为_collect_image_urls_from_args,同时保持相同的参数和断言。
Original comment in English
suggestion (testing): Add tests for base64:// and file:/// image refs plus other supported extensions to match _is_supported_image_ref behavior.
Current tests cover HTTP URLs, one valid image extension, a non-image extension, and extensionless event files. Since _is_supported_image_ref also supports base64:// URIs, file:///... paths, and other extensions like .heic and .svg, please add a parameterized test that passes a mix of these refs into _collect_handoff_image_urls (or _collect_image_urls_from_args) and asserts that only supported refs are returned. This will better align the tests with _is_supported_image_ref and guard against regressions in handling different image schemes and extensions.
Suggested implementation:
def _build_run_context(message_components: list[object] | None = None):
event = _DummyEvent(message_components=message_components)
ctx = SimpleNamespace(event=event, context=SimpleNamespace())
return ContextWrapper(context=ctx)
@pytest.mark.asyncio
async def test_collect_handoff_image_urls_normalizes_filters_and_appends_event_image(
monkeypatch: pytest.MonkeyPatch,
):
async def _fake_convert_to_file_path(self):
return "/tmp/event_image.png"
monkeypatch.setattr(Image, "convert_to_file_path", _fake_convert_to_file_path)
run_context = _build_run_context([Image(file="file:///tmp/original.png")])
image_urls_input = (
" https://example.com/a.png ",
"/tmp/not_an_image.txt",
"/tmp/local.webp",
)
@pytest.mark.asyncio
@pytest.mark.parametrize(
"image_refs, expected_supported_refs",
[
pytest.param(
(
# supported HTTP(S) URL
"https://example.com/valid.png",
# supported base64 URI
"base64://iVBORw0KGgoAAAANSUhEUgAAAAUA",
# supported file:// paths with different extensions
"file:///tmp/photo.heic",
"file:///tmp/vector.svg",
# unsupported refs that should be filtered out
"file:///tmp/not-image.txt",
"mailto:user@example.com",
"random-string-without-scheme-or-extension",
),
{
"https://example.com/valid.png",
"base64://iVBORw0KGgoAAAANSUhEUgAAAAUA",
"file:///tmp/photo.heic",
"file:///tmp/vector.svg",
},
id="mixed_supported_and_unsupported_schemes_and_extensions",
),
],
)
async def test_collect_handoff_image_urls_filters_supported_schemes_and_extensions(
monkeypatch: pytest.MonkeyPatch,
image_refs: tuple[str, ...],
expected_supported_refs: set[str],
):
# Ensure event image handling is deterministic and does not affect filtering behavior
async def _fake_convert_to_file_path(self):
return "/tmp/event_image.png"
monkeypatch.setattr(Image, "convert_to_file_path", _fake_convert_to_file_path)
# No event images for this test: we only care about how the function filters the refs
run_context = _build_run_context([])
# Call the same helper used by handoff image collection tests,
# passing in a mix of supported and unsupported image references.
result = await _collect_handoff_image_urls(run_context, *image_refs)
# The function should only return the supported refs (HTTP(S), base64://, file://
# with supported image extensions) and filter out the rest.
assert expected_supported_refs.issubset(set(result))This change assumes:
-
_collect_handoff_image_urlsis the helper used elsewhere in this test file and accepts(run_context, *image_refs)as arguments.
If its signature differs (e.g., it expectsimage_urls_input=image_refsor a single iterable), adjust the call accordingly:- Example:
result = await _collect_handoff_image_urls(run_context, image_urls_input=image_refs)or - Example:
result = await _collect_handoff_image_urls(run_context, image_refs).
- Example:
-
The function may append additional URLs (such as event images), so the assertion uses
issubsetinstead of strict equality.
If the function is guaranteed to only return filteredimage_refswithout extra URLs for an emptyrun_context, you can tighten the assertion to:assert set(result) == expected_supported_refs.
-
If your test suite prefers using
_collect_image_urls_from_argsdirectly, replace the call to_collect_handoff_image_urlswith_collect_image_urls_from_argswhile keeping the same arguments and assertions.
| run_context = _build_run_context([Image(file="file:///tmp/original.png")]) | ||
| image_urls_input = ( | ||
| " https://example.com/a.png ", | ||
| "/tmp/not_an_image.txt", | ||
| "/tmp/local.webp", | ||
| 123, | ||
| ) | ||
|
|
||
| image_urls = await FunctionToolExecutor._collect_handoff_image_urls( |
There was a problem hiding this comment.
suggestion (testing): 覆盖 image_urls 为 None 且只应收集事件图片的场景。
当前测试总是传入非 None 的 image_urls(字符串/元组/列表)。请添加一个测试,将 image_urls_raw 设为 None,并在消息中包含一个或多个 Image 组件,以验证事件派生的图像路径仍然会被收集,并确保这种默认行为不会出现回归。
Original comment in English
suggestion (testing): Cover the case where image_urls is None and only event images should be collected.
Current tests always pass a non-None image_urls value (string/tuple/list). Please add a test where image_urls_raw is None and the message includes one or more Image components, to verify that event-derived image paths are still collected and this default behavior doesn’t regress.
| async def test_collect_handoff_image_urls_keeps_extensionless_existing_event_file( | ||
| monkeypatch: pytest.MonkeyPatch, | ||
| ): | ||
| async def _fake_convert_to_file_path(self): | ||
| return "/tmp/astrbot-handoff-image" | ||
|
|
||
| monkeypatch.setattr(Image, "convert_to_file_path", _fake_convert_to_file_path) | ||
| monkeypatch.setattr( | ||
| "astrbot.core.astr_agent_tool_exec.os.path.exists", lambda _: True | ||
| ) |
There was a problem hiding this comment.
suggestion (testing): 为不存在的无扩展名路径补充一个测试,断言它们会被过滤掉。
为了覆盖 _is_supported_image_ref 的反向分支,可以将 convert_to_file_path 打补丁为返回一个无扩展名路径,并让 os.path.exists 返回 False,然后断言 image_urls 为空(或者至少不包含该路径)。这样可以锁定现有与不存在的无扩展名文件之间在行为上的预期差异。
Original comment in English
suggestion (testing): Add a complementary test for extensionless paths that do not exist to assert they are filtered out.
To exercise the opposite branch of _is_supported_image_ref, patch convert_to_file_path to return an extensionless path and os.path.exists to return False, then assert that image_urls is empty (or at least does not include that path). This will lock in the intended behavior difference between existing and non-existing extensionless files.
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey - 我发现了 3 个问题,并给出了一些高层反馈:
FunctionToolExecutor._ALLOWED_IMAGE_EXTENSIONS这个类属性从未被使用,而且和image_ref_utils中的ALLOWED_IMAGE_EXTENSIONS重复;建议移除它,以避免混淆,并将“单一事实来源”保持在一个地方。FunctionToolExecutor._is_supported_image_ref目前只是对is_supported_image_ref的一个薄封装;如果你不打算在子类中覆盖它,可以考虑将其内联,或者直接导入/使用is_supported_image_ref来减少间接调用。
给 AI Agents 的提示
Please address the comments from this code review:
## Overall Comments
- The `FunctionToolExecutor._ALLOWED_IMAGE_EXTENSIONS` class attribute is never used and duplicates `ALLOWED_IMAGE_EXTENSIONS` from `image_ref_utils`; consider removing it to avoid confusion and keep the source of truth in one place.
- `FunctionToolExecutor._is_supported_image_ref` is currently a thin passthrough to `is_supported_image_ref`; if you don't anticipate overriding it in subclasses, you could inline the function or import/use `is_supported_image_ref` directly to reduce indirection.
## Individual Comments
### Comment 1
<location path="astrbot/core/astr_agent_tool_exec.py" line_range="48-49" />
<code_context>
+from astrbot.core.utils.string_utils import normalize_and_dedupe_strings
class FunctionToolExecutor(BaseFunctionToolExecutor[AstrAgentContext]):
+ _ALLOWED_IMAGE_EXTENSIONS = ALLOWED_IMAGE_EXTENSIONS
+
+ @classmethod
</code_context>
<issue_to_address>
**suggestion:** `_ALLOWED_IMAGE_EXTENSIONS` 这个类属性被定义了,但没有在任何地方使用。
由于这个类属性只是重新导出了 `ALLOWED_IMAGE_EXTENSIONS`,而本身并未被使用,建议移除它,并直接引用模块级常量,除非你明确需要在未来为每个子类单独覆盖它。
建议的实现方式:
```python
from astrbot.core.utils.image_ref_utils import (
is_supported_image_ref,
)
```
```python
class FunctionToolExecutor(BaseFunctionToolExecutor[AstrAgentContext]):
```
如果 `_ALLOWED_IMAGE_EXTENSIONS` 在该文件的其他位置(不在当前展示的片段中)被引用了,那么这些引用应当更新为直接使用 `astrbot.core.utils.image_ref_utils` 中的模块级常量 `ALLOWED_IMAGE_EXTENSIONS`;或者,撤销上面的 import 删除,并只在真正需要的地方保留该类属性。
</issue_to_address>
### Comment 2
<location path="astrbot/core/utils/image_ref_utils.py" line_range="40-49" />
<code_context>
+ return path or image_ref
+
+
+def is_supported_image_ref(
+ image_ref: str,
+ *,
+ allow_extensionless_existing_local_file: bool = True,
+) -> bool:
+ if not image_ref:
+ return False
+
+ lowered = image_ref.lower()
+ if lowered.startswith(("http://", "https://", "base64://")):
+ return True
+
+ file_path = (
+ resolve_file_url_path(image_ref) if lowered.startswith("file://") else image_ref
+ )
+ ext = os.path.splitext(file_path)[1].lower()
+ if ext in ALLOWED_IMAGE_EXTENSIONS:
+ return True
+ if not allow_extensionless_existing_local_file:
+ return False
+ # Keep support for extension-less temp files returned by image converters.
+ return ext == "" and os.path.exists(file_path)
</code_context>
<issue_to_address>
**🚨 issue (security):** 将任意存在的无扩展名本地文件都视为有效的图片引用,会让文件访问范围比预期更宽。
因为该分支会把任意存在的无扩展名路径当作合法的图片引用,非图片文件(例如文本文件或配置文件)也可能被当作图片来处理,具体取决于 `image_ref` 的来源。如果你需要为无扩展名的临时图片文件保留向后兼容性,可以考虑收缩该行为(例如限制在特定目录下、添加基本的大小/内容校验,或在调用方通过显式选项开启),以避免隐式接受任意本地路径作为图片。
</issue_to_address>
### Comment 3
<location path="astrbot/core/astr_agent_tool_exec.py" line_range="84" />
<code_context>
+ return candidates
+
+ @classmethod
+ async def _collect_image_urls_from_message(
+ cls, run_context: ContextWrapper[AstrAgentContext]
+ ) -> list[str]:
</code_context>
<issue_to_address>
**issue (complexity):** 建议通过在调用点保留 kwargs 形式、直接调用图片引用的辅助方法,并精简类型转换逻辑来简化新的 handoff 和图片 URL 处理,从而减少间接调用和分支。
- 你可以通过三个小而集中的修改,在保留新行为的同时降低间接性。
### 1. 为 `_execute_handoff` 保留 kwargs 透传
你不需要修改调用点改为传递一个 dict;可以继续保持对外形态为 `**tool_args`,并在内部操作一个本地 dict:
```python
@classmethod
async def _execute_handoff(
cls,
tool: HandoffTool,
run_context: ContextWrapper[AstrAgentContext],
**tool_args: T.Any,
):
# Work on a local dict copy
tool_args = dict(tool_args)
input_ = tool_args.get("input")
image_urls = await cls._collect_handoff_image_urls(
run_context,
tool_args.get("image_urls"),
)
tool_args["image_urls"] = image_urls
# ... rest of existing logic ...
```
然后你可以保持调用点不变:
```python
# execute()
async for r in cls._execute_handoff(tool, run_context, **tool_args):
yield r
# _do_handoff_background()
async for r in cls._execute_handoff(tool, run_context, **tool_args):
...
```
这样既移除了调用点额外的 “dict 管道” 逻辑,又保留了在 `_execute_handoff` 内部对 `tool_args` 的修改能力。
---
### 2. 删除与图片引用支持相关的类级封装
这个类属性和薄封装方法增加了一次跳转,却没有带来可配置性方面的收益。你可以直接调用模块级函数:
```python
# Remove this
# _ALLOWED_IMAGE_EXTENSIONS = ALLOWED_IMAGE_EXTENSIONS
#
# @classmethod
# def _is_supported_image_ref(cls, image_ref: str) -> bool:
# return is_supported_image_ref(image_ref)
```
并在 `_collect_handoff_image_urls` 中:
```python
normalized = normalize_and_dedupe_strings(candidates)
sanitized = [item for item in normalized if is_supported_image_ref(item)]
```
如果之后需要为子类做自定义,你仍然可以重新引入一个 hook,但现在这样可以简化间接调用。
---
### 3. 简化 `_collect_image_urls_from_args` 的类型转换逻辑
当前的日志和 `non_string_count` 统计可能比实际需求更“防御性”。如果你只需要处理 “None / str / 字符串可迭代对象”,并忽略其他类型,一个更紧凑的辅助函数会更易读:
```python
@classmethod
def _collect_image_urls_from_args(cls, image_urls_raw: T.Any) -> list[str]:
if image_urls_raw is None:
return []
if isinstance(image_urls_raw, str):
return [image_urls_raw]
if isinstance(image_urls_raw, (Sequence, AbstractSet)) and not isinstance(
image_urls_raw, (str, bytes, bytearray)
):
return [item for item in image_urls_raw if isinstance(item, str)]
# Optionally keep a single debug if you still want visibility:
# logger.debug("Unsupported image_urls type in handoff tool args: %s",
# type(image_urls_raw).__name__)
return []
```
这样可以保持现有行为(只使用字符串 URL;忽略非字符串),同时去掉额外的记账和分支,从而降低该功能相关的认知负担。
</issue_to_address>帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进后续的评审。
Original comment in English
Hey - I've found 3 issues, and left some high level feedback:
- The
FunctionToolExecutor._ALLOWED_IMAGE_EXTENSIONSclass attribute is never used and duplicatesALLOWED_IMAGE_EXTENSIONSfromimage_ref_utils; consider removing it to avoid confusion and keep the source of truth in one place. FunctionToolExecutor._is_supported_image_refis currently a thin passthrough tois_supported_image_ref; if you don't anticipate overriding it in subclasses, you could inline the function or import/useis_supported_image_refdirectly to reduce indirection.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `FunctionToolExecutor._ALLOWED_IMAGE_EXTENSIONS` class attribute is never used and duplicates `ALLOWED_IMAGE_EXTENSIONS` from `image_ref_utils`; consider removing it to avoid confusion and keep the source of truth in one place.
- `FunctionToolExecutor._is_supported_image_ref` is currently a thin passthrough to `is_supported_image_ref`; if you don't anticipate overriding it in subclasses, you could inline the function or import/use `is_supported_image_ref` directly to reduce indirection.
## Individual Comments
### Comment 1
<location path="astrbot/core/astr_agent_tool_exec.py" line_range="48-49" />
<code_context>
+from astrbot.core.utils.string_utils import normalize_and_dedupe_strings
class FunctionToolExecutor(BaseFunctionToolExecutor[AstrAgentContext]):
+ _ALLOWED_IMAGE_EXTENSIONS = ALLOWED_IMAGE_EXTENSIONS
+
+ @classmethod
</code_context>
<issue_to_address>
**suggestion:** The `_ALLOWED_IMAGE_EXTENSIONS` class attribute is defined but not used anywhere.
Since this class attribute just re-exports `ALLOWED_IMAGE_EXTENSIONS` and isn’t used, consider removing it and referring to the module-level constant directly, unless you specifically need a per-subclass override in the future.
Suggested implementation:
```python
from astrbot.core.utils.image_ref_utils import (
is_supported_image_ref,
)
```
```python
class FunctionToolExecutor(BaseFunctionToolExecutor[AstrAgentContext]):
```
If `_ALLOWED_IMAGE_EXTENSIONS` is referenced elsewhere in this file (outside the shown snippet), those references should be updated to use the module-level constant `ALLOWED_IMAGE_EXTENSIONS` from `astrbot.core.utils.image_ref_utils` directly, or the import removal above should be reverted and the attribute kept only where needed.
</issue_to_address>
### Comment 2
<location path="astrbot/core/utils/image_ref_utils.py" line_range="40-49" />
<code_context>
+ return path or image_ref
+
+
+def is_supported_image_ref(
+ image_ref: str,
+ *,
+ allow_extensionless_existing_local_file: bool = True,
+) -> bool:
+ if not image_ref:
+ return False
+
+ lowered = image_ref.lower()
+ if lowered.startswith(("http://", "https://", "base64://")):
+ return True
+
+ file_path = (
+ resolve_file_url_path(image_ref) if lowered.startswith("file://") else image_ref
+ )
+ ext = os.path.splitext(file_path)[1].lower()
+ if ext in ALLOWED_IMAGE_EXTENSIONS:
+ return True
+ if not allow_extensionless_existing_local_file:
+ return False
+ # Keep support for extension-less temp files returned by image converters.
+ return ext == "" and os.path.exists(file_path)
</code_context>
<issue_to_address>
**🚨 issue (security):** Treating any existing extension-less local file as a valid image reference can broaden file access more than intended.
Because this branch treats any existing extension-less path as a valid image ref, non-image files (e.g., text or config files) could be processed as images, depending on where `image_ref` values come from. If you need this for backward compatibility with temp image files, consider narrowing the behavior (e.g., constrain to a specific directory, add basic size/content validation, or gate it behind an explicit opt-in at call sites) so arbitrary local paths aren’t implicitly accepted as images.
</issue_to_address>
### Comment 3
<location path="astrbot/core/astr_agent_tool_exec.py" line_range="84" />
<code_context>
+ return candidates
+
+ @classmethod
+ async def _collect_image_urls_from_message(
+ cls, run_context: ContextWrapper[AstrAgentContext]
+ ) -> list[str]:
</code_context>
<issue_to_address>
**issue (complexity):** Consider simplifying the new handoff and image URL handling by keeping kwargs at the call sites, calling the image-ref helper directly, and trimming the coercion logic to reduce indirection and branching.
- You can keep the new behavior while reducing indirection in three small, targeted changes.
### 1. Keep kwargs pass‑through for `_execute_handoff`
You don’t need to change the call sites to pass a dict; you can keep the public shape as `**tool_args` and work on a local dict internally:
```python
@classmethod
async def _execute_handoff(
cls,
tool: HandoffTool,
run_context: ContextWrapper[AstrAgentContext],
**tool_args: T.Any,
):
# Work on a local dict copy
tool_args = dict(tool_args)
input_ = tool_args.get("input")
image_urls = await cls._collect_handoff_image_urls(
run_context,
tool_args.get("image_urls"),
)
tool_args["image_urls"] = image_urls
# ... rest of existing logic ...
```
Then you can keep your call sites as they were:
```python
# execute()
async for r in cls._execute_handoff(tool, run_context, **tool_args):
yield r
# _do_handoff_background()
async for r in cls._execute_handoff(tool, run_context, **tool_args):
...
```
This removes the extra “dict plumbing” at call sites while preserving mutation of `tool_args` inside `_execute_handoff`.
---
### 2. Drop the class‑level wrapper for image ref support
The class attribute and thin wrapper add an extra hop without buying configurability. You can call the module‑level function directly:
```python
# Remove this
# _ALLOWED_IMAGE_EXTENSIONS = ALLOWED_IMAGE_EXTENSIONS
#
# @classmethod
# def _is_supported_image_ref(cls, image_ref: str) -> bool:
# return is_supported_image_ref(image_ref)
```
And in `_collect_handoff_image_urls`:
```python
normalized = normalize_and_dedupe_strings(candidates)
sanitized = [item for item in normalized if is_supported_image_ref(item)]
```
If you later need subclass customization, you can reintroduce a hook, but for now this simplifies the indirection.
---
### 3. Simplify `_collect_image_urls_from_args` coercion
The logging and `non_string_count` tracking may be more defensive than necessary. If you only need to coerce “None / str / iterable of strs” and ignore others, a tighter helper is easier to scan:
```python
@classmethod
def _collect_image_urls_from_args(cls, image_urls_raw: T.Any) -> list[str]:
if image_urls_raw is None:
return []
if isinstance(image_urls_raw, str):
return [image_urls_raw]
if isinstance(image_urls_raw, (Sequence, AbstractSet)) and not isinstance(
image_urls_raw, (str, bytes, bytearray)
):
return [item for item in image_urls_raw if isinstance(item, str)]
# Optionally keep a single debug if you still want visibility:
# logger.debug("Unsupported image_urls type in handoff tool args: %s",
# type(image_urls_raw).__name__)
return []
```
This keeps behavior (only string URLs are used; non‑strings are ignored) but removes bookkeeping and branching, reducing cognitive load around the feature.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey - 我在这里给出了一些整体性的反馈:
- 在
_do_handoff_background中,你已经通过_collect_handoff_image_urls对image_urls做了清洗和去重,但在image_urls_prepared=True时,_execute_handoff又调用了一次normalize_and_dedupe_strings;建议考虑跳过第二次规范化,以避免重复处理,并让image_urls_prepared这个参数的契约语义更清晰。
给 AI Agent 的提示
Please address the comments from this code review:
## Overall Comments
- 在 `_do_handoff_background` 中,你已经通过 `_collect_handoff_image_urls` 对 `image_urls` 做了清洗和去重,但在 `image_urls_prepared=True` 时,`_execute_handoff` 又调用了一次 `normalize_and_dedupe_strings`;建议考虑跳过第二次规范化,以避免重复处理,并让 `image_urls_prepared` 这个参数的契约语义更清晰。帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据反馈改进后续的评审。
Original comment in English
Hey - I've left some high level feedback:
- In
_do_handoff_backgroundyou already sanitize and de‑dupeimage_urlsvia_collect_handoff_image_urls, but_execute_handoffthen callsnormalize_and_dedupe_stringsagain whenimage_urls_prepared=True; consider skipping the second normalization to avoid redundant processing and make the contract forimage_urls_preparedclearer.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `_do_handoff_background` you already sanitize and de‑dupe `image_urls` via `_collect_handoff_image_urls`, but `_execute_handoff` then calls `normalize_and_dedupe_strings` again when `image_urls_prepared=True`; consider skipping the second normalization to avoid redundant processing and make the contract for `image_urls_prepared` clearer.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
@sourcery-ai review |
There was a problem hiding this comment.
嘿,我已经审查了你的更改,一切看起来都很棒!
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈来改进后续的审查。
Original comment in English
Hey - I've reviewed your changes and they look great!
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
Generated docs update PR (pending manual review): AI change summary:
Experimental bot notice:
|
fix:修正PR(#5348)中遗留的子agent无法正确接收本地图片(参考图)路径的问题
Modifications / 改动点
修改文件:
astrbot/core/astr_agent_tool_exec.py。在
_execute_handoff方法中,引入了Image组件的异步解析逻辑。通过调用convert_to_file_path(),确保无论是本地文件、网络 URL 还是 Base64 格式的参考图,都能被自动转换为子 Agent 可识别的规范化本地文件路径,并正确注入image_urls参数。确保此行为中的图片接收与转换逻辑与主agent对话流程一致。
Screenshots or Test Results / 运行截图或测试结果
Checklist / 检查清单
requirements.txt和pyproject.toml文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations inrequirements.txtandpyproject.toml.Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests:
Original summary in English
Summary by Sourcery
修复子代理交接(sub-agent handoff),确保被引用的图片被规范化并作为可用的本地路径传递。
Bug Fixes(错误修复):
Enhancements(功能增强):
Tests(测试):
Original summary in English
Summary by Sourcery
Fix sub-agent handoff so referenced images are normalized and passed as usable local paths.
Bug Fixes:
Enhancements:
Tests: