Skip to content

Commit 82df420

Browse files
committed
fix: limit proactive cron llm retries
1 parent d0e5e68 commit 82df420

3 files changed

Lines changed: 137 additions & 2 deletions

File tree

astrbot/core/config/default.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@
169169
},
170170
"proactive_capability": {
171171
"add_cron_tools": True,
172+
"request_max_retries": 1,
172173
},
173174
"computer_use_runtime": "none",
174175
"computer_use_require_admin": True,
@@ -2895,6 +2896,9 @@
28952896
"add_cron_tools": {
28962897
"type": "bool",
28972898
},
2899+
"request_max_retries": {
2900+
"type": "int",
2901+
},
28982902
},
28992903
},
29002904
},

astrbot/core/cron/manager.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
_CRONTAB_WEEKDAY_NAMES = ("sun", "mon", "tue", "wed", "thu", "fri", "sat")
2828
_CRONTAB_WEEKDAY_PATTERN = re.compile(r"^(?:(\*)|(\d+)(?:-(\d+))?)(?:/(\d+))?$")
29+
_DEFAULT_PROACTIVE_REQUEST_MAX_RETRIES = 1
2930

3031

3132
def _normalize_crontab_day_of_week(day_of_week: str) -> str:
@@ -417,12 +418,22 @@ async def _woke_main_agent(
417418
cron_event.role = "admin"
418419

419420
provider_settings = cfg.get("provider_settings", {}) or {}
421+
proactive_settings = provider_settings.get("proactive_capability", {})
422+
if not isinstance(proactive_settings, dict):
423+
proactive_settings = {}
424+
proactive_request_max_retries = proactive_settings.get("request_max_retries")
425+
if proactive_request_max_retries is None:
426+
proactive_request_max_retries = _DEFAULT_PROACTIVE_REQUEST_MAX_RETRIES
427+
cron_provider_settings = {
428+
**provider_settings,
429+
"request_max_retries": proactive_request_max_retries,
430+
}
420431
tool_call_timeout = provider_settings.get("tool_call_timeout", 120)
421432
config = MainAgentBuildConfig(
422433
tool_call_timeout=tool_call_timeout,
423434
llm_safety_mode=False,
424435
streaming_response=False,
425-
provider_settings=provider_settings,
436+
provider_settings=cron_provider_settings,
426437
)
427438
req = ProviderRequest()
428439
conv = await _get_session_conv(event=cron_event, plugin_context=self.ctx)

tests/unit/test_cron_manager.py

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -596,8 +596,128 @@ async def fake_persist_agent_history(*args, **kwargs):
596596

597597
config = captured["config"]
598598
assert config.tool_call_timeout == 77
599-
assert config.provider_settings is provider_settings
599+
assert config.provider_settings is not provider_settings
600600
assert config.provider_settings["fallback_chat_models"] == ["fallback-provider"]
601+
assert config.provider_settings["request_max_retries"] == 1
602+
assert "request_max_retries" not in provider_settings
603+
604+
@pytest.mark.asyncio
605+
async def test_woke_main_agent_allows_proactive_retry_override(
606+
self, cron_manager
607+
):
608+
"""Test active cron agent can override request retries for proactive runs."""
609+
provider_settings = {
610+
"tool_call_timeout": 77,
611+
"request_max_retries": 5,
612+
"proactive_capability": {"request_max_retries": 2},
613+
}
614+
ctx = MagicMock()
615+
ctx.get_config.return_value = {
616+
"admins_id": [],
617+
"provider_settings": provider_settings,
618+
}
619+
cron_manager.ctx = ctx
620+
621+
conv = MagicMock()
622+
conv.history = "[]"
623+
624+
class FakeRunner:
625+
def step_until_done(self, max_step):
626+
async def gen():
627+
if False:
628+
yield None
629+
630+
return gen()
631+
632+
def get_final_llm_resp(self):
633+
return None
634+
635+
captured = {}
636+
637+
async def fake_build_main_agent(*, event, plugin_context, config, req):
638+
captured["config"] = config
639+
return MagicMock(agent_runner=FakeRunner())
640+
641+
with (
642+
patch(
643+
"astrbot.core.astr_main_agent._get_session_conv",
644+
AsyncMock(return_value=conv),
645+
),
646+
patch(
647+
"astrbot.core.astr_main_agent.build_main_agent",
648+
side_effect=fake_build_main_agent,
649+
),
650+
patch(
651+
"astrbot.core.cron.manager.persist_agent_history",
652+
AsyncMock(return_value=None),
653+
),
654+
):
655+
await cron_manager._woke_main_agent(
656+
message="run scheduled task",
657+
session_str="test:FriendMessage:user123",
658+
extras={"cron_job": {"id": "job-1"}, "cron_payload": {}},
659+
)
660+
661+
assert captured["config"].provider_settings["request_max_retries"] == 2
662+
assert provider_settings["request_max_retries"] == 5
663+
664+
@pytest.mark.asyncio
665+
async def test_woke_main_agent_uses_default_when_proactive_retry_is_none(
666+
self, cron_manager
667+
):
668+
"""Test None proactive retry config falls back to the cron default."""
669+
provider_settings = {
670+
"request_max_retries": 5,
671+
"proactive_capability": {"request_max_retries": None},
672+
}
673+
ctx = MagicMock()
674+
ctx.get_config.return_value = {
675+
"admins_id": [],
676+
"provider_settings": provider_settings,
677+
}
678+
cron_manager.ctx = ctx
679+
680+
conv = MagicMock()
681+
conv.history = "[]"
682+
683+
class FakeRunner:
684+
def step_until_done(self, max_step):
685+
async def gen():
686+
if False:
687+
yield None
688+
689+
return gen()
690+
691+
def get_final_llm_resp(self):
692+
return None
693+
694+
captured = {}
695+
696+
async def fake_build_main_agent(*, event, plugin_context, config, req):
697+
captured["config"] = config
698+
return MagicMock(agent_runner=FakeRunner())
699+
700+
with (
701+
patch(
702+
"astrbot.core.astr_main_agent._get_session_conv",
703+
AsyncMock(return_value=conv),
704+
),
705+
patch(
706+
"astrbot.core.astr_main_agent.build_main_agent",
707+
side_effect=fake_build_main_agent,
708+
),
709+
patch(
710+
"astrbot.core.cron.manager.persist_agent_history",
711+
AsyncMock(return_value=None),
712+
),
713+
):
714+
await cron_manager._woke_main_agent(
715+
message="run scheduled task",
716+
session_str="test:FriendMessage:user123",
717+
extras={"cron_job": {"id": "job-1"}, "cron_payload": {}},
718+
)
719+
720+
assert captured["config"].provider_settings["request_max_retries"] == 1
601721

602722

603723
class TestGetNextRunTime:

0 commit comments

Comments
 (0)