feat: adopt band-sdk-core's one-shot delivery lifecycle (INT-1328) - #604
Open
AlexanderZ-Band wants to merge 7 commits into
Open
feat: adopt band-sdk-core's one-shot delivery lifecycle (INT-1328)#604AlexanderZ-Band wants to merge 7 commits into
AlexanderZ-Band wants to merge 7 commits into
Conversation
…oker OneShotInvoker's handle_event/_process_message_event hand-rolled the same ignore/cleanup/self-echo/invocation routing, next-message comparison, drain classification, and ack decision that band_sdk_core's evaluate_delivery_event/ evaluate_next_message/evaluate_drain_candidate/evaluate_adapter_result were extracted from as the reference implementation. Route through those four functions instead, so core's stricter payload validation and one definition of each decision replace the local logic. Two intentional behavior changes: a room-cleanup event with no resolvable room id now raises OneShotEnvelopeError (400) instead of silently no-op'ing, and a malformed self-echo payload raises before classification instead of returning skipped_self. Also introduces OneShotStatus, an SDK-owned StrEnum for the response "status" vocabulary hosts branch on (kept spelled exactly as it always has been), replacing six re-typed magic-string literals in the producer. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018aLCfpQh5vzVzEneDe2kVY
…ore.is_self_echo Both self-echo checks in ExecutionContext (the backlog path and the live WebSocket path) hand-rolled the same sender_type == "Agent" and sender_id == agent_id comparison. Route both through band_sdk_core's new public is_self_echo, the same predicate OneShotInvoker now uses via evaluate_delivery_event/evaluate_drain_candidate, so the two SDKs share one definition instead of two independently-maintained copies. Adds regression coverage for both call sites -- self-echo had no test anywhere in tests/runtime/ before this. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018aLCfpQh5vzVzEneDe2kVY
docs/websocket-events.md read as if band_sdk_core were only an event-validation dependency; note the delivery-lifecycle decisions and that OneShotInvoker's routing is core's, not the SDK's own logic. AGENTS.md gets a short band-sdk-core pointer naming which decisions live in core and the standing obligation to extend the CI wheel-smoke when a new core symbol starts being used. ARCHITECTURE.md now references OneShotStatus instead of a bare status-string literal. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018aLCfpQh5vzVzEneDe2kVY
2.2.0 adds the public is_self_echo used by ExecutionContext and OneShotInvoker (band-sdk-core#64). Extends the wheel-smoke CI step to prove is_self_echo and evaluate_drain_candidate are callable from the isolated pinned install, not just importable -- the standing obligation whenever a new core symbol starts being used. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018aLCfpQh5vzVzEneDe2kVY
… a new section The previous commit added a standalone AGENTS.md heading duplicating the existing WebSocket Channels & Events pointer to docs/websocket-events.md, working against the AGENTS.md slim-down this branch built on (#601). Fold the one durable fact (extend the CI wheel-smoke when a new core symbol starts being used) into that existing section instead. Also fixes ARCHITECTURE.md's OneShotStatus reference: the wire response carries the string "no_pending", not Python enum syntax. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018aLCfpQh5vzVzEneDe2kVY
oneshot.py's numbered inline comments ("# 1. Claim.", "# 4. Mark...")
duplicated _process_message_event's own docstring step list without adding
information; drop the ones that only restate the following line, keep the
ones stating an actual invariant (unnumbered).
test_execution.py re-imported PlatformMessage, MessageMetadata, and
datetime/timezone inside ~20 individual test methods despite each already
being available at module scope (or trivially promotable there) -- moves
them to the top-level import, one source of truth per name.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018aLCfpQh5vzVzEneDe2kVY
AlexanderZ-Band
enabled auto-merge
September 2, 2026 11:18
Collaborator
|
Please run it manually against AWS AgentCore to make sure it works well. |
…e coverage The band-sdk-core migration swapped ExecutionContext's null-safe `==` self-echo comparisons for band_sdk_core.is_self_echo, a pyo3 extension with non-Optional str params. The /next backlog path reads sender_id/sender_type from a Fern REST model that can carry a backend null despite its str type hint (the same hazard oneshot.py's _drain_candidate already guards against); without the guard, a null sender crashes the drain with TypeError instead of being treated as a no-match. Apply the same `or ""` guard on the live WebSocket path for consistency with the one established pattern. Also extend the CI wheel-smoke step to prove evaluate_delivery_event, evaluate_next_message, and evaluate_adapter_result are callable from the pinned wheel, per this PR's own AGENTS.md rule that new band_sdk_core symbols get wheel-smoke coverage -- oneshot.py now calls all three but the smoke step only checked evaluate_drain_candidate and is_self_echo. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YDYPGiaDSYNZnyC5mg18ch
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
Implements INT-1328 (the plan's "Implementation plan" comment is the source of truth) — all phases now present on this branch, including the pin bump that was blocked on band-sdk-core 2.2.0 reaching PyPI (it's live now: band-sdk-core#64 → release-please → PyPI).
chore: bump band-sdk-core to 2.2.0...): pin bump +uv.lockregenerated against the real PyPI wheel + CI wheel-smoke extension provingis_self_echo/evaluate_drain_candidateare callable from the isolated install.OneShotInvoker,src/band/runtime/oneshot.py):handle_event/_process_message_eventnow route through band_sdk_core'sevaluate_delivery_event/evaluate_next_message/evaluate_drain_candidate/evaluate_adapter_resultinstead of hand-rolled ignore/cleanup/self-echo/invocation/drain logic. Two intentional behavior changes called out in that commit: a room-cleanup event with no resolvable room id now raisesOneShotEnvelopeError(400) instead of a silent no-op, and a malformed self-echo payload raises before classification. AddsOneShotStatus(aStrEnum) replacing six re-typed magic-string literals in the producer.ExecutionContext,src/band/runtime/execution.py): both duplicated self-echo booleans (backlog path, live WS path) now call the new publicband_sdk_core.is_self_echo— one shared definition.evaluate_next_message/evaluate_delivery_eventare deliberately not adopted here; see the plan's "Recorded decisions" section for why (ExecutionContext'sdelivery_status//next-cursor model asks different questions than core's id-comparison model).docs/websocket-events.md,AGENTS.md,examples/agentcore/ARCHITECTURE.md.Test plan
uv run pytest tests/runtime/test_oneshot.py tests/runtime/test_execution.py -v— 148 passed, including the five acceptance-named tests unchanged:test_deduplicates_messages,test_pending_next_message_present_in_context_still_executes,test_ack_pending_message_survives_lru_pressure_without_replay,test_sync_skips_permanently_failed,test_retry_saturation_skips_handler_on_next_deliveryuv run pytest tests/ --ignore=tests/integration/ --ignore=tests/e2e/ -q— 5275 passed, 123 skipped (re-run against the real PyPI 2.2.0 install)uv run pytest --markdown-docs $(git ls-files '*.md' ':!:examples/*') --no-cov— 43 passeduv run ruff check ./uv run ruff format --check ./uv run pyrefly check— cleanexamples/agentcore/agentcore_llm_server.pybehindband-bridge) — not run this session🤖 Generated with Claude Code
https://claude.ai/code/session_018aLCfpQh5vzVzEneDe2kVY