Skip to content

Commit bf88368

Browse files
committed
结构化的共享上下文;更新subagent后台任务逻辑
1 parent 923a58e commit bf88368

3 files changed

Lines changed: 677 additions & 41 deletions

File tree

astrbot/core/astr_agent_tool_exec.py

Lines changed: 163 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import datetime
33
import inspect
44
import json
5+
import time
56
import traceback
67
import typing as T
78
import uuid
@@ -366,7 +367,9 @@ async def _execute_handoff(
366367

367368
# 注入公共上下文
368369
shared_context_prompt = (
369-
DynamicSubAgentManager.build_shared_context_prompt(umo, agent_name)
370+
DynamicSubAgentManager.build_shared_context_prompt_v2(
371+
umo, agent_name
372+
)
370373
)
371374
if shared_context_prompt:
372375
subagent_system_prompt += f"\n{shared_context_prompt}"
@@ -430,38 +433,75 @@ async def _execute_handoff_background(
430433
):
431434
"""Execute a handoff as a background task.
432435
433-
Immediately yields a success response with a task_id, then runs
434-
the subagent asynchronously. When the subagent finishes, a
435-
``CronMessageEvent`` is created so the main LLM can inform the
436-
user of the result – the same pattern used by
437-
``_execute_background`` for regular background tasks.
436+
当启用增强SubAgent时,会在 DynamicSubAgentManager 中创建 pending 任务,
437+
并返回 task_id 给主 Agent,以便后续通过 wait_for_subagent 获取结果。
438438
"""
439-
task_id = uuid.uuid4().hex
439+
event = run_context.context.event
440+
umo = event.unified_msg_origin
441+
agent_name = getattr(tool.agent, "name", None)
442+
443+
# 生成 subagent_task_id(用于 DynamicSubAgentManager)
444+
subagent_task_id = None
445+
446+
# 检查是否启用增强版 SubAgent
447+
try:
448+
from astrbot.core.dynamic_subagent_manager import DynamicSubAgentManager
449+
450+
if agent_name:
451+
session = DynamicSubAgentManager.get_session(umo)
452+
if session and agent_name in session.agents:
453+
# 增强版:在 DynamicSubAgentManager 中创建 pending 任务
454+
subagent_task_id = (
455+
DynamicSubAgentManager.create_pending_subagent_task(
456+
session_id=umo, agent_name=agent_name
457+
)
458+
)
459+
logger.info(
460+
f"[EnhancedSubAgent] Created pending task {subagent_task_id} for {agent_name}"
461+
)
462+
except Exception as e:
463+
logger.debug(f"[EnhancedSubAgent] Failed to create pending task: {e}")
464+
465+
# 生成原始的 task_id(用于唤醒机制等)
466+
original_task_id = uuid.uuid4().hex
440467

441468
async def _run_handoff_in_background() -> None:
442469
try:
443470
await cls._do_handoff_background(
444471
tool=tool,
445472
run_context=run_context,
446-
task_id=task_id,
473+
task_id=original_task_id,
474+
subagent_task_id=subagent_task_id,
447475
**tool_args,
448476
)
477+
449478
except Exception as e: # noqa: BLE001
450479
logger.error(
451-
f"Background handoff {task_id} ({tool.name}) failed: {e!s}",
480+
f"Background handoff {original_task_id} ({tool.name}) failed: {e!s}",
452481
exc_info=True,
453482
)
454483

455484
asyncio.create_task(_run_handoff_in_background())
456485

457-
text_content = mcp.types.TextContent(
458-
type="text",
459-
text=(
460-
f"Background task dedicated to subagent '{tool.agent.name}' submitted. task_id={task_id}. "
461-
f"The subagent '{tool.agent.name}' is working on the task on hehalf you. "
462-
f"You will be notified when it finishes."
463-
),
464-
)
486+
# 构建返回消息
487+
if subagent_task_id:
488+
text_content = mcp.types.TextContent(
489+
type="text",
490+
text=(
491+
f"Background task submitted. subagent_task_id={subagent_task_id}. "
492+
f"SubAgent '{agent_name}' is working on the task. "
493+
f"Use wait_for_subagent(subagent_name='{agent_name}', task_id='{subagent_task_id}') to get the result."
494+
),
495+
)
496+
else:
497+
text_content = mcp.types.TextContent(
498+
type="text",
499+
text=(
500+
f"Background task submitted. task_id={original_task_id}. "
501+
f"SubAgent '{agent_name}' is working on the task. "
502+
f"You will be notified when it finishes."
503+
),
504+
)
465505
yield mcp.types.CallToolResult(content=[text_content])
466506

467507
@classmethod
@@ -472,13 +512,24 @@ async def _do_handoff_background(
472512
task_id: str,
473513
**tool_args,
474514
) -> None:
475-
"""Run the subagent handoff and, on completion, wake the main agent."""
515+
"""Run the subagent handoff.
516+
当增强版 SubAgent 启用时,结果存储到 DynamicSubAgentManager,主 Agent 可通过 wait_for_subagent 获取。
517+
否则使用原有的 _wake_main_agent_for_background_result 流程。
518+
"""
519+
520+
start_time = time.time()
476521
result_text = ""
522+
error_text = None
477523
tool_args = dict(tool_args)
478524
tool_args["image_urls"] = await cls._collect_handoff_image_urls(
479525
run_context,
480526
tool_args.get("image_urls"),
481527
)
528+
529+
event = run_context.context.event
530+
umo = event.unified_msg_origin
531+
agent_name = getattr(tool.agent, "name", None)
532+
482533
try:
483534
async for r in cls._execute_handoff(
484535
tool,
@@ -490,26 +541,106 @@ async def _do_handoff_background(
490541
for content in r.content:
491542
if isinstance(content, mcp.types.TextContent):
492543
result_text += content.text + "\n"
544+
493545
except Exception as e:
546+
error_text = str(e)
494547
result_text = (
495548
f"error: Background task execution failed, internal error: {e!s}"
496549
)
497550

498-
event = run_context.context.event
551+
execution_time = time.time() - start_time
552+
success = error_text is None
499553

500-
await cls._wake_main_agent_for_background_result(
501-
run_context=run_context,
502-
task_id=task_id,
503-
tool_name=tool.name,
504-
result_text=result_text,
505-
tool_args=tool_args,
506-
note=(
507-
event.get_extra("background_note")
508-
or f"Background task for subagent '{tool.agent.name}' finished."
509-
),
510-
summary_name=f"Dedicated to subagent `{tool.agent.name}`",
511-
extra_result_fields={"subagent_name": tool.agent.name},
512-
)
554+
# 检查是否是增强版 SubAgent
555+
enhanced_enabled = False
556+
try:
557+
from astrbot.core.dynamic_subagent_manager import DynamicSubAgentManager
558+
559+
session = DynamicSubAgentManager.get_session(umo)
560+
if session and agent_name:
561+
# 检查是否是动态创建的 SubAgent
562+
if agent_name in session.agents:
563+
enhanced_enabled = True
564+
except Exception:
565+
pass
566+
567+
subagent_task_id = tool_args.get("subagent_task_id", None)
568+
569+
if enhanced_enabled and agent_name and subagent_task_id:
570+
# 增强版:存储结果到 DynamicSubAgentManager
571+
try:
572+
from astrbot.core.dynamic_subagent_manager import DynamicSubAgentManager
573+
574+
# 存储结果(使用 subagent_task_id)
575+
DynamicSubAgentManager.store_subagent_result(
576+
session_id=umo,
577+
agent_name=agent_name,
578+
task_id=subagent_task_id,
579+
success=success,
580+
result=result_text.strip() if result_text else "",
581+
error=error_text,
582+
execution_time=execution_time,
583+
)
584+
585+
# 如果启用了 shared_context,发布完成状态
586+
if session.shared_context_enabled:
587+
status_content = (
588+
f" SubAgent '{agent_name}' 任务完成,耗时 {execution_time:.1f}s"
589+
)
590+
if error_text:
591+
status_content = (
592+
f" SubAgent '{agent_name}' 任务失败: {error_text}"
593+
)
594+
595+
DynamicSubAgentManager.add_shared_context(
596+
session_id=umo,
597+
sender=agent_name,
598+
context_type="status",
599+
content=status_content,
600+
target="all",
601+
)
602+
603+
logger.info(
604+
f"[EnhancedSubAgent] Stored result for {agent_name} task {subagent_task_id}: "
605+
f"success={success}, time={execution_time:.1f}s"
606+
)
607+
608+
except Exception as e:
609+
logger.error(
610+
f"[EnhancedSubAgent] Failed to store result for {agent_name}: {e}"
611+
)
612+
# 存储失败时,回退到原有的唤醒机制
613+
await cls._wake_main_agent_for_background_result(
614+
run_context=run_context,
615+
task_id=task_id,
616+
tool_name=tool.name,
617+
result_text=result_text,
618+
tool_args=tool_args,
619+
note=(
620+
event.get_extra("background_note")
621+
or f"Background task for subagent '{agent_name}' finished."
622+
),
623+
summary_name=f"Dedicated to subagent `{agent_name}`",
624+
extra_result_fields={
625+
"subagent_name": agent_name,
626+
"subagent_task_id": subagent_task_id,
627+
},
628+
)
629+
else:
630+
# 非增强版:使用原有的唤醒机制
631+
await cls._wake_main_agent_for_background_result(
632+
run_context=run_context,
633+
task_id=task_id,
634+
tool_name=tool.name,
635+
result_text=result_text,
636+
tool_args=tool_args,
637+
note=(
638+
event.get_extra("background_note")
639+
or f"Background task for subagent '{agent_name}' finished."
640+
),
641+
summary_name=f"Dedicated to subagent `{agent_name}`",
642+
extra_result_fields={"subagent_name": agent_name},
643+
)
513644

514645
@classmethod
515646
async def _execute_background(

astrbot/core/astr_main_agent.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,7 @@ def _apply_enhanced_subagent_tools(
957957
SEND_SHARED_CONTEXT_TOOL_FOR_MAIN_AGENT,
958958
UNPROTECT_SUBAGENT_TOOL,
959959
VIEW_SHARED_CONTEXT_TOOL,
960+
WAIT_FOR_SUBAGENT_TOOL,
960961
DynamicSubAgentManager,
961962
)
962963
from astrbot.core.subagent_logger import SubAgentLogger
@@ -971,6 +972,7 @@ def _apply_enhanced_subagent_tools(
971972
req.func_tool.add_tool(UNPROTECT_SUBAGENT_TOOL)
972973
req.func_tool.add_tool(VIEW_SHARED_CONTEXT_TOOL)
973974
req.func_tool.add_tool(SEND_SHARED_CONTEXT_TOOL_FOR_MAIN_AGENT)
975+
req.func_tool.add_tool(WAIT_FOR_SUBAGENT_TOOL)
974976

975977
# Configure logger
976978
SubAgentLogger.configure(level=config.enhanced_subagent.get("log_level"))

0 commit comments

Comments
 (0)