chore(deps): strands-agents 1.57.1 + bedrock-agentcore 1.23.1 + boto 1.43.103 (paired bump) - #1367
Open
philmerrell wants to merge 2 commits into
Open
philmerrell wants to merge 2 commits into
philmerrell wants to merge 2 commits into
Conversation
…boto 1.43.103 One paired bump (kaizen review 2026-09-25, Proposal 4): - strands-agents / strands-agents[bidi] 1.55.0 -> 1.57.1 - bedrock-agentcore 1.21.0 -> 1.23.1 (strands >=1.56 removed the Bidi hook events agentcore <=1.23.0 imports at module load) - boto3/botocore 1.43.68 -> 1.43.103 (agentcore 1.23.1 floor is 1.43.72) - mcp 1.28.1 -> 1.30.0, still held below 2 by the declared uv constraint - Lambda requirements files follow the lock The two guard rails from the superseded 1.56 entry are now assertions in tests/supply_chain/test_strands_agentcore_pairing.py: the strands/agentcore pairing (declared, locked, and in the Lambda images), and mcp<2 held by a declared [tool.uv] constraint rather than incidentally by the idna pin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s 1.57 Breakage caused by the strands-agents bump: - Voice: 1.56/1.57 rewrote the experimental Bidi API (provider audio config and voice kwarg, BidiAgent.send() input shapes, renamed and reshaped output events). VoiceWireAdapter translates the new events back to the existing WebSocket contract, so the SPA and voice routes are unchanged. - TurnBasedSessionManager: a BidiAgent now drives the ordinary session hooks. initialize() restores it without the text-only compaction/repair path, and retrieve_customer_context() skips it, mirroring agentcore 1.23.1's guard. - Context window: the SDK table now resolves the hosted OpenAI ids via its nested prefix strip; tests and docstring updated (the curated 272K cap still wins). - Usage: pin #4361's Chat Completions cache-write mapping (normalized once) and add a tripwire for harness-sdk#4618 (_total_prompt_tokens). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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
One paired dependency bump, per kaizen review 2026-09-25 Proposal 4 ("Ship"). It also fixes the places where the bump broke our own code. The biggest of those is voice mode, which the research pass had called non-breaking.
strands-agents/strands-agents[bidi]bedrock-agentcoreboto3/botocore(locked)mcp(transitive, locked)[tool.uv]constraint)awscrt(transitive,[bidi])strands-agents-toolsThe Lambda images that pip-install from their own requirements files move with the lock: scheduled-runs worker and dispatcher, kb-sync, and kb-migration. I checked kb-migration's load-bearing boto pin against 1.43.103. The
MANAGEDKB type,managedKnowledgeBaseConfiguration, and all four*KnowledgeBaseDocumentsoperations are still there. The RAG ingestion image has its own hash-lockedrequirements.lock(boto3 1.42.73). It carries neither strands nor agentcore, so I left it alone.Guard rails, now tests (
backend/tests/supply_chain/test_strands_agentcore_pairing.py)uv.lock, and the Lambda requirements files (agentcore/boto3/botocore must match the lock). It also requiresstrands-agentsandstrands-agents[bidi]to be pinned to the same version.mcp<2comes from a declared constraint, not by accident.[tool.uv].constraint-dependenciesmust exclude every 2.x release.uv.lock's[manifest]must record that constraint, and the lockedmcpmust be below 2.<3, and a Lambda file drifting. Each one fails the suite.Breakage the bump caused, and the fixes
1. Voice mode. Without this PR, every voice turn would break after deploy. Strands 1.56 and 1.57 rewrote the experimental Bidi API:
BedrockNovaSonicModel(audio=...)now takes{"input": {"sample_rate"}, "output": {"sample_rate"}}, andvoiceis its own kwarg. Our five-key dict still constructs, but it only warns, so the voice silently fell back tomatthew.BidiAgent.send()accepts only{"audio_delta": {...bytes}},{"text": ...}or astr. Our{"type": "bidi_audio_input", ...}dicts now raiseValueError.bidi_audio_delta,bidi_transcript_start/delta/stop,bidi_barge_in,bidi_response_stop(with nostop_reason) andbidi_connection_stop.bidi_response_startnow fires at the user's first content, before any user speech has been transcribed. The FINAL assistant transcript pass is gone.Fix: a
VoiceWireAdapterinvoice_agent.pytranslates 1.57 events back to the existing WebSocket contract, so the SPA andvoice_routes.pyare unchanged. The legacybidi_response_startis emitted when the assistant starts, which is where 1.55 emitted it. Without that, the SPA would file each user utterance one turn late. Assistant transcript deltas go out withis_final=True, because the speculative pass is now the only one. Turn and usage accounting runs on the translated stream.One side effect:
response_start_countis now one per turn. Under 1.55 it was about four per turn, because it counted every NovacontentStart._finalize_voice_sessiontakesmax(completed, started), so voice sessions'message_countstops being inflated.2.
TurnBasedSessionManagernow sees the voiceBidiAgent. ABidiAgentnow drives the ordinary session hooks (AgentInitializedEvent→initialize,MessageAddedEvent→retrieve_customer_context) instead of the dedicated Bidi callbacks it used before. Two guards:initializerestores aBidiAgentthrough the SDK and returns. Without this, the text agent's session-level compaction checkpoint would be applied to the voice agent's own message list, which slices the wrong history.retrieve_customer_contextskips aBidiAgent. This matches the guard agentcore 1.23.1 added to the method we override. Without it, every voice transcript would trigger an LTM retrieval spliced into the live Bidi history.3. The context-window fallback now resolves the hosted OpenAI ids. 1.56's nested-prefix strip (#4221) resolves
us.openai.gpt-6-astraandus.openai.gpt-5.6-*to 1,050,000. The curated rows' deliberatemaxInputTokens: 272_000pricing cap still wins, so each pair now logs onecontext_window_disagreementwarning per process, as expected. I updated the tests and the docstring.maxInputTokensabsent would now fall through to 1.05M instead ofNone. That means compaction would cut past the 272K price tier. I did not add a guard, because that is a policy call. Worth checking that no dev or prod row lacks the field.harness-sdk#4618 assessment: no Bedrock usage change in 1.57.1
strands/models/bedrock.pychanged only in formatting between 1.55.0 and 1.57.1 (two reasoning-delta dicts were re-wrapped).strands/telemetry/metrics.pydid not change._total_prompt_tokens, the tell the kaizen gate names, is still present.usage_normalization.py's "leave Bedrock untouched" contract holds.test_usage_normalization.pyfails the day_total_prompt_tokensdisappears.cache_write_tokensmapping) merged after 1.57.1 was cut, so it is not in this pin.#4361 did land, for Chat Completions only.
OpenAIModelnow reportscacheWriteInputTokensfromprompt_tokens_details.cache_write_tokens, next to aninputTokensthat is still inclusive. Ourusage_normalizedwrapper subtracts it exactly once. With 10,000 prompt tokens, 6,000 cached and 3,000 written, the result isinputTokens=1000, read 6000, write 3000, which is disjoint. A test pins this against the real SDK class. On the Chat Completions path, cache writes are now priced at the write rate instead of as plain input. Responses still needs our own mapping, which is unchanged.Upstream diff: what touches our surface (1.55.0 to 1.57.1, read in site-packages)
CacheConfigbehaviour on the Bedrock path.cache_keynow auto-derivesstrands-<session_id>for OpenAI/LiteLLM/Mistral when unset (1.56 #4083), but we only setcache_configon Bedrock, andbedrock_responsessets its ownprompt_cache_keyfirst.probe_bedrock_cache_point_support.py --offline-onlygives an identical table on 1.55.0 and 1.57.1: Haiku gets a tools point, and our system point survives on all five probe models.ContextManager. Upstream changed its default strategies (truncate at 1,500 with a 750 preview; summarize at 0.85 withpreserve_recent=4). The Stash now always namespaces per(session_id, agent_id), so trap 2 still stands and #4367 is still the blocker.clear_session()is new. The retrieval tool now returns media instead of an error. TheContextOffloaderplugin we subclass,S3Storage's write/read path andSlidingWindowConversationManagerare unchanged. #4254's session integration carries Strands' own stash into its session snapshots; nothing in it addresses our DynamoDB checkpoint or truncation anchor.BeforeModelCallEventhooks.BeforeModelCallEventis still not_Interruptible, and none of our hooks interrupt.InterruptExceptionis no longer wrapped inEventLoopException. We have noexcept EventLoopExceptionpause detection.interventionsnow propagates handler interrupts regardless ofon_error(#4371).MessageUpdatedEventis new.AfterToolsEvent/MessageAddedEventsemantics are unchanged for steering.SessionManagerbecameGeneric[_SessionAgentT]and its Bidi callbacks moved (see fix 2).strands/tools/mcp/mcp_client.pyis byte-identical, so theClientSessionsubstitution is unaffected.gen_ai.system_instructionsthrough_redact, so ourgen_ai_unredacted_attributes=allowlist redacts them like the model spans.Capabilities worth adopting later (not in this PR):
strands.vended_tools.handoff_to_userhas the same interrupt shape as ourask_user_question. Read it before building a third interrupt tool.requestTimeoutin the 1.57.0 notes is the TypeScript SDK (#4408). The PythonBedrockModelhas no such option; we already bound reads throughboto_client_config.mcp_routeranda2a_clientvended tools,Agent.shutdown(), background tasks, andbedrock_mantle_config.endpoint="bedrock-runtime", which acceptsus.openai.*CRIS ids.Tests
uv sync --extra agentcore --extra dev, then again with--extra bidi): 10891 passed, 3 skipped, 0 failed in both envs (CI-shaped without bidi, and with bidi so the voice path is exercised against the real 1.57.1 Bidi classes).tests/supply_chain/: 48 passed.Dev validation after merge (develop auto-deploys dev)
A missed pairing does not fail at import in a unit test. On the Runtime it shows up as "Runtime initialization time exceeded (30s)" → 502. So validate real turns, not an import:
GET /admin/costs/sessions/{id}/calls. TheC#rows should have the same shape as before:cacheStatuspresent, turn 2 ahit,cacheReadInputTokensnon-zero, andtoolConfigHash/systemPromptHashstable between the two turns.inputTokensshould be small relative tocacheReadInputTokens. If they are comparable, Bedrock usage has gone inclusive.tiffany, notmatthew); each user utterance shows before its reply; barge-in stops playback.cacheWriteInputTokensmay now be non-zero, and the three input buckets should still sum to the call's total input.context_window_disagreementwarning per OpenAI model id per process is expected. Anything more is not.Kaizen docs are deliberately untouched; the queue entry moves in a separate PR.
🤖 Generated with Claude Code