fix(btw): fold the result delivery outcome into the work status - #172
Merged
YUZHEthefool merged 1 commit intoSep 14, 2026
Conversation
10 tasks
The respond stage reports a refused or unconfirmed send as a delivery receipt and returns normally, so a work run whose final result the platform rejected still ended as completed. An unknown outcome -- a raised send or a platform that returned no acceptance receipt -- was worse: it does not prove the user received anything, yet it also read as completed. Read the receipt after the detached run delivers and adjust a completed session: an explicit rejection is a failure, and an unknown outcome gets its own status so the two stay distinguishable. A failed or cancelled run keeps the stronger answer it already has, which update_status_if enforces. The new state is user-visible, so it lands with both locale bundles and the status list in the zh and en command docs. Fixes #156 AI-Generated: true Generated-At: 2026-09-11T14:16:28Z
YUZHEthefool
added this pull request to stack #174
September 11, 2026 15:57
YUZHEthefool
force-pushed
the
fix/btw-work-delivery-status-156
branch
from
September 11, 2026 16:00
8ecbe04 to
8e3adc1
Compare
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
A work run whose final result the platform explicitly rejected still reported
completed, and so did a send whose outcome is unknown. Expected the platform'sanswer about the result to be reflected in the work status, with an explicit
rejection and an unknown outcome kept apart.
Related issue
Fixes #156
Root cause
RespondStageconverts a rejected send into aDeliveryReceiptand returnsnormally, so the detached runner saw no failure. An unknown outcome — a raised
send or a platform that returned no acceptance receipt — is worse: it does not
prove the user received anything, yet it also read as
completed.Reproduction
Wire the real
PipelineScheduler,RespondStage, andWorkLoopwith a platformstub that accepts the acknowledgement and answers the final result with
PlatformSendResult(success=False), then read the event'sdelivery_receiptandthe
WorkSession: receiptfailed, sessioncompleted. A second stub thatraises on send gives receipt
unknownand sessioncompleted.Implementation notes
Read the receipt after the detached run has delivered and adjust a completed
session:
failedwith a generic message, so theplatform's own error text never surfaces;
WorkSessionStatus.UNCONFIRMED, which isdistinct from both
completedandfailed;accepted,partial, andskippedkeep the execution status (skippedmeansthere was nothing to deliver).
update_status_ifapplies the change only fromCOMPLETED, so a failed orcancelled run keeps the stronger answer it already has. The new state is
user-visible, so it lands with both locale bundles and the status list in the
docs/zhanddocs/encommand pages.Validation
Both new tests were run against the unmodified tree first, where they fail with
WorkSessionStatus.COMPLETED, so they are real regression tests.pnpm run docs:buildwas not run locally (the docs dependencies are notinstalled in this checkout), and neither were
make check,make quality, or thecoverage-gated
--test-profile allrun; this PR relies on CI for those, as #168did.
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
unconfirmed(zh: 投递未确认) reachable through/work status, with a matching key added to both built-in command localebundles.
is now
failed, and one with an unknown outcome isunconfirmed, instead ofboth reading
completed.passing unchanged. No route, schema, configuration, or dependency change.
Checklist
docs/zh/anddocs/en/when needed.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 #156 by folding the platform's answer about the
result into the work status, keeping BTW off by default and preserving
authorization and request identity.
Paths touched:
astrbot/core/agent/btw/types.py,astrbot/core/agent/btw/i18n.py,astrbot/core/agent/btw/work_loop.py,astrbot/core/agent/btw/work_sessions.py,astrbot/builtin_stars/builtin_commands/.astrbot-plugin/i18n/{zh-CN,en-US}.json,docs/{zh,en}/use/command.md, andtests/unit/test_btw_delivery.py.Checks run: the commands under Validation, plus the new tests against the
unmodified tree.
Residual risk: the receipt is read after the detached dispatch loop, so a run
whose last delivery happens after that point would not be reflected. The
dispatch loop drives each delivery, so the final receipt is stored before the
loop ends; the tests use the real
RespondStageto confirm this end to end.Tools used: Claude Code (Opus 5) with the repository's AGENTS.md and AI_POLICY.md.
This PR is stacked on #171; merge that first.