Repository navigation
Conversation
Plugin tools reach the tool executor wrapped in _PermissionGuardedTool, which did not copy is_background_task, so tools declared as background tasks always ran in the foreground and the reply waited for them. Fixes AstrBotDevs#10610
Contributor
There was a problem hiding this comment.
Hey - I've found 2 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="astrbot/core/provider/func_tool_manager.py" line_range="245" />
<code_context>
# Mirror mutable state from the underlying tool
self.active = getattr(tool, "active", True)
self.handler_module_path = getattr(tool, "handler_module_path", None)
+ self.is_background_task = getattr(tool, "is_background_task", False)
async def call(self, context: Any, **kwargs: Any) -> Any:
</code_context>
<issue_to_address>
**Tool output gains system prompt authority**
When a user invokes a background plugin tool whose result contains attacker-controlled text, such as content fetched from an external source, `FunctionToolExecutor` now treats guarded plugin tools with this flag as background tasks. Their returned text is serialized into `BACKGROUND_TASK_RESULT_WOKE_SYSTEM_PROMPT` (`astrbot/core/astr_agent_tool_exec.py:625`, `astrbot/core/astr_main_agent_resources.py:121-122`), where attacker-controlled instructions from an external source can steer the autonomous agent and its available tools.
Pass the result as untrusted tool/user data rather than interpolating it into the system prompt, and instruct the agent not to follow instructions contained in tool output.
</issue_to_address>
### Comment 2
<location path="astrbot/core/provider/func_tool_manager.py" line_range="245" />
<code_context>
# Mirror mutable state from the underlying tool
self.active = getattr(tool, "active", True)
self.handler_module_path = getattr(tool, "handler_module_path", None)
+ self.is_background_task = getattr(tool, "is_background_task", False)
async def call(self, context: Any, **kwargs: Any) -> Any:
</code_context>
<issue_to_address>
**Background tools lose temporary attachments**
When a background plugin tool uses an event-tracked temporary attachment after the foreground pipeline finishes, `PipelineScheduler.execute()` calls `event.cleanup_temporary_local_files()` when the foreground pipeline ends, while `_execute_background()` continues using the same event. Cleanup deletes tracked paths, so a plugin tool that reads an attachment after that point fails.
Keep event temporary files until the event’s background tasks finish, or give those tasks their own copies of files they need.
</issue_to_address>Sourcery assessment
Approval pending. 2 findings to address first.
Blocking findings: astrbot/core/provider/func_tool_manager.py:245, astrbot/core/provider/func_tool_manager.py:245
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #10610.
With the default setup, plugin tools declared with
is_background_task=Truerun in the foreground, so the reply waits until the tool is done. Since the per-tool permissions in #8693,FunctionToolManager.get_full_tool_set()wraps every registered tool in_PermissionGuardedTool, and the wrapper didn't copyis_background_task.FunctionToolExecutor.execute()reads the flag from the tool it is given, which is the wrapper, so it was alwaysFalse. Builtin and MCP tools never set the flag, so this only affects plugin tools. The default tool set (a persona without its own tool list) comes fromget_full_tool_set(), so there plugin background tools haven't run in the background since v4.26.0.Modifications / 改动点
astrbot/core/provider/func_tool_manager.py:_PermissionGuardedToolalso copiesis_background_taskfrom the wrapped tool. With this, the wrapper mirrors everyFunctionToolfield excepthandler, which it leavesNoneon purpose so that every call goes through itscall().Plugin tools that set
is_background_task=Truerun in the background again, as they did before v4.26.0. Other tools are unchanged.The permission check still runs: the background task calls the tool through the wrapper's
call(), the same as a foreground call. When it is denied, the usual "Permission denied" text reaches the main agent through the background result, like any other tool error.Tests in
tests/unit/test_astr_agent_tool_exec.py:test_permission_guarded_plugin_tool_keeps_background_flag: a plugin tool taken fromFunctionToolManager.get_full_tool_set(), so it is wrapped, is submitted as a background task whenis_background_task=Trueand its result reaches the wake-up; withFalseit still runs in the foreground. The permission check runs once in both cases.test_permission_guarded_background_tool_still_checks_permission: when the permission check fails, the wrapped tool is not called and the wake-up gets the "Permission denied" text.test_background_execution_lifecycleuses a bareFunctionTool, which is why it didn't catch this.This is NOT a breaking change. / 这不是一个破坏性变更。
Screenshots or Test Results / 运行截图或测试结果
Verification steps:
FunctionToolwithis_background_task=Truethroughcontext.add_llm_tools()(the demo plugin'sgenerate_reporttakes about 10 seconds).I used a scripted OpenAI-compatible endpoint and a small OneBot v11 client in place of NapCat; the rest is a normal
python main.pyinstance. The plugin, the scripts and the log before the fix are in the zip attached to #10610. The full log after the fix:bgtool_live_after.log
Before, on master @ dffe922. The reply waits 10s for the tool:
After. The user gets a reply right away, and the report 10s later:
Tests (Windows 11, Python 3.13):
With the change to
func_tool_manager.pyreverted, the two background tests fail: the tool runs in the foreground and returns its result directly.The deselected test hangs on my machine on master as well, and it passes in CI.
Checklist / 检查清单
😊 No new feature is added in this PR; it is a bug fix for [Bug] 插件声明为后台任务的工具(is_background_task=True)总是被同步执行 #10610.
/ 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。
👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
/ 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。
📚 No WebUI navigation, page structure, or terminology changed, so no update to
docs/zh/docs/enis needed./ 我已对照变化后的 WebUI 入口、页面结构和术语,核对并在本 PR 中更新
docs/zh和docs/en的相关操作说明与截图(或说明无需更新文档的原因)。入口改名、移动或合并时,已在文档和 changelog 中补充 旧入口 → 新入口 对照。🤓 No new dependencies are introduced.
/ 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到
requirements.txt和pyproject.toml文件相应位置。😮 My changes do not introduce malicious code.
/ 我的更改没有引入恶意代码。
Summary by Sourcery
Restore background execution for permission-guarded plugin tools without changing permission enforcement.
Bug Fixes:
Tests: