fix(btw): record runner errors and refused work runs - #170
Merged
YUZHEthefool merged 1 commit intoSep 14, 2026
Merged
YUZHEthefool merged 1 commit into
YUZHEthefool merged 1 commit into
Conversation
10 tasks
The work loop read a single failure marker, so three failing paths ended as completed: - run_agent reports a provider error as a user-facing result and then drains its generator normally, which is indistinguishable from an answer. - The third-party stage records _third_party_runner_error and nothing read it. - A run the session refuses on admission never reaches an Agent, so its executor yields nothing and the generator ending looked like success. Write the failure marker from each of those paths and read both markers in the work loop. The marker keys move into btw/types.py so the writers and their only reader cannot drift apart; mark_work_run_failed keeps chat runs on their existing error path. An executor that produced nothing also no longer counts as completed: a generator ending only proves the task ran when something actually ran. Fixes #154 AI-Generated: true Generated-At: 2026-09-11T13:48:32Z
YUZHEthefool
added this pull request to stack #174
September 11, 2026 15:57
YUZHEthefool
force-pushed
the
fix/btw-work-failure-detection-154
branch
from
September 11, 2026 16:00
3a0463e to
bec2549
Compare
10 tasks
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.
Summary
Work runs that errored, or never ran at all, reported
completed. Expected alocal provider error, a third-party runner error, and a request refused by
session admission to be
failed.Related issue
Fixes #154
Root cause
The work loop read a single failure marker, and nothing set it on these paths:
run_agentturns anerrresponse into a user-facing error result and thendrains its generator normally, which the loop cannot tell apart from an answer.
ThirdPartyAgentSubStagerecords_third_party_runner_errorand nothing read it.AgentRequestSubStagereturns before building an Agent when the provider isdisabled or the session has AI off, so the executor yielded nothing and the
generator ending looked like success.
Reproduction
Enable BTW and the work loop, then (a) drive the real
run_agentwith a runnerthat returns
err, (b) drive the realThirdPartyAgentSubStagenon-streaminghandler with a runner that raises, and (c) drive the real
AgentRequestSubStagewith session AI disabled. All three used to read
completed. Each is aregression test.
Implementation notes
Write the failure marker where the failure happens and read both markers in the
loop. The marker keys move into
btw/types.py, which imports only the standardlibrary, so the writers (agent stages,
run_agent) and their only reader cannotdrift apart;
third_party.THIRD_PARTY_RUNNER_ERROR_EXTRA_KEYstill resolves, nowby import.
mark_work_run_failedkeeps chat runs on their existing error path.An executor that produced nothing also no longer counts as completed: a generator
ending only proves the task ran when something actually ran. That is the
"do not equate normal generator termination with success" criterion, kept narrow
enough that queued work is unaffected — it is owned by the semaphore, not by
this generator.
Validation
All five new tests were run against the unmodified tree first and failed with
WorkSessionStatus.COMPLETED, so they are real regression tests rather thandescriptions of current behavior.
make check,make quality, and the coverage-gated--test-profile allrunwere not run locally on this Windows checkout; this PR relies on CI for those,
as #168 did.
After #168 was rebased onto the updated
masterhead, this branch was rebased ontothe new head as well and the whole stack was re-validated at its tip:
pytest tests/unit -q5233 passed / 6 skipped andpytest --test-profile blocking -q5354 passed / 6 skipped / 1 deselected.The count above was taken on this branch before that rebase.
Compatibility and risk
THIRD_PARTY_RUNNER_ERROR_EXTRA_KEYkeeps its name and value; its definitionmoved from
third_party.pytobtw/types.py.failedinstead ofcompleted. Thatis the intended behavior change.
Checklist
docs/zh/anddocs/en/when needed. (No user-visible text changed.)docs/public/openapi.json, and tests change together when routes or schemas change. (No route or schema change.)pyproject.toml,requirements.txt, anduv.locktogether. (No dependency change.)!and aBREAKING CHANGE:footer. (None; the status change is the fix.)Agent note
Goal: resolve #154 with an explicit terminal outcome instead of
a bare generator end, keeping BTW off by default and preserving authorization and
request identity.
Paths touched:
astrbot/core/agent/btw/types.py,astrbot/core/agent/btw/work_loop.py,astrbot/core/astr_agent_run_util.py,astrbot/core/pipeline/process_stage/method/agent_request.py,.../agent_sub_stages/internal.py,.../agent_sub_stages/third_party.py, andunit tests (
test_btw_work_loop.pyextended,test_agent_request_sub_stage.pyextended).
Checks run: the commands under Validation, plus the new tests against the
unmodified tree.
Residual risk:
run_agentmarks a work run failed on anyerrresponse, even ifa later step were to succeed. An
erralready produced a user-visible error, soreporting the run as failed is the honest reading.
Tools used: Claude Code (Opus 5) with the repository's AGENTS.md and AI_POLICY.md.
This PR is stacked on #169; merge that first.