Skip to content

chore(deps): upgrade strands-agents 1.51.0 → 1.55.0 - #1012

Merged
philmerrell merged 1 commit into
developfrom
feature/strands-1-55-upgrade
Sep 9, 2026
Merged

chore(deps): upgrade strands-agents 1.51.0 → 1.55.0#1012
philmerrell merged 1 commit into
developfrom
feature/strands-1-55-upgrade

Conversation

@philmerrell

Copy link
Copy Markdown
Contributor

Upgrades strands-agents 1.51.0 → 1.55.0 in backend/pyproject.toml (both the agentcore and bidi extras).

strands-agents-tools (0.8.6) and bedrock-agentcore (1.21.0) are deliberately left alone — separate PRs.

The prompt-cache contract is unchanged

This is the governing constraint, so it is proven rather than argued:

Offline — the full formatted ConverseStream request for our production config is byte-identical between the two versions:

request SHA-256 (first 32)
1.51.0 58606987da49cd08a6f5489e365f2276
1.55.0 58606987da49cd08a6f5489e365f2276

Live, against dev Bedrock — the same conversation formatted by each version, sent to ConverseStream back to back:

arm cacheWrite cacheRead
A — strands 1.51.0 7,059 0
B — strands 1.55.0 0 7,059

1.55.0 read the exact cache entry 1.51.0 had just written. Bedrock itself confirms the cacheable prefix did not move.

cache_toolsCacheConfig(tools_ttl=...)

1.55.0 deprecates the model-level cache_tools key (_warn_on_deprecated_cache_tools). With cache_config.ttl unset, _build_tools_cache_point resolves tools_ttl=True to the same bare {"cachePoint": {"type": "default"}} the deprecated path emitted — so the toolConfig tail, which sits inside the cached prefix, is unchanged. The unsupported branch now pins tools_ttl=False explicitly rather than falling through the deprecated key. The deprecation warning is gone from the suite.

The new auto-injected system cache point

1.55.0 adds _should_cache_system(), which appends a system cachePoint — guarded by not any("cachePoint" in block ...).

AgentFactory.create_agent already appends its own whenever bedrock_cache_points_supported(), and that predicate is equivalent to the SDK's _cache_strategy test, so the guard always short-circuits on our paths. Audited every path that builds a system prompt:

path outcome
chat agent goes through AgentFactory → our point already present
voice agent BidiNovaSonicModel, no cache_config — not a BedrockModel
skills / agent-designer / marketplace all route through the same factory
/chat/api-converse raw boto3 on the Bedrock branch; OpenAI-surface models otherwise
other BedrockModel sites there is exactly one, in agent_factory

system_prompt_ttl is left at its default True as a safety net for any future path that bypasses the factory. _apply_system_cache_ttl is inert because cache_config.ttl stays unset. A new test asserts the system blocks carry exactly one cachePoint.

⚠️ Nova Sonic provider rename — not in the release notes

1.55.0 moved models.nova_sonic.BidiNovaSonicModelmodels.bedrock.BedrockNovaSonicModel and flattened its constructor (provider_config["audio"]audio, client_config["region"]region).

voice_agent imports the provider inside a try/except ImportError that degrades to BIDI_AVAILABLE = False. The stale import would therefore not have crashed — it would have silently turned voice off in the inference-api image, which does install --extra bidi, leaving one INFO line behind.

Verified the migrated call still lands the voice, sample rates, channels and format on the model, and that usage_is_cumulative is still True (our bidi_usage de-cumulation depends on it). Added a contract test that reads the pinned SDK's source rather than importing it, because tests.yml installs agentcore/dev but not bidi.

boto3

No move needed. 1.55.0 floors at boto3>=1.26.0 and bedrock-agentcore is unchanged at 1.21.0 (>=1.43.35), so 1.43.68 still resolves. It stays pinned in all five files that carry it (pyproject.toml plus four Lambda requirements.txt).

What we gain

On the GPT-5.6 / Mantle Responses path:

  • Finish-reason precedence fixedlength now beats tool_calls. In 1.51.0 a function call cut off by max_tokens surfaced as tool_calls and was executed with truncated arguments.
  • cachePoint blocks filtered rather than passed through. On 1.51.0 a session switched mid-conversation from Claude to GPT-5.6 raised TypeError: content_type=<cachePoint> | unsupported type; our session manager preserves cachePoint in _BEDROCK_CONTENT_BLOCK_KEYS, so this was reachable.
  • Document attachments moved from {"type":"input_file","file_url":…} to {"type":"input_file","filename":…,"file_data":…}.

Also: the sequential executor's per-tool cancellation check moved from agent._cancel_signal to Agent._observe_cancellation() — same semantics plus a synchronous mirror of a caller-supplied external signal. We never pass one, so reset_cancellation_state clearing the internal signal remains sufficient; the canary now binds against the new indirection and a second test pins that relationship.

Verification

  • uv run python -m pytest tests/ -v7783 passed, 3 skipped, 0 failed (full suite).

  • Every strands import in backend/src re-checked against 1.55.0; all resolve. _openai_bedrock.py (we monkeypatch _OPENAI_PATH_MODEL_PREFIXES) is byte-identical.

  • Live 3-turn session on dev driven through a local inference-api running this branch, writing real rows to dev-boisestateai-v2-sessions-metadata:

    call cacheStatus cacheRead cacheWrite toolConfigHash systemPromptHash
    1 first_write 0 9,097 bdec3e8a9801d15c ac3d5e48315be364
    2 hit 9,097 126 bdec3e8a9801d15c ac3d5e48315be364
    3 hit 9,223 34 bdec3e8a9801d15c ac3d5e48315be364

    No partial_miss, wastedUsd 0 on every call, both static hashes constant. Read:write runs 72:1 and 271:1 — the inverse of the ~1:2 write premium a regression would show.

  • GPT-5.6 (Terra) with a document attachment — the model read a verification phrase out of an attached .txt through the new filename/file_data shape, and the Responses-path explicit cache hit (cacheRead 1,538) on the repeat.

Deploy

Merging to develop auto-deploys dev (backend.yml, frontend-deploy.yml, platform.yml are all push-triggered).

🤖 Generated with Claude Code

Migrates the deprecated model-level `cache_tools` key to
`CacheConfig(tools_ttl=...)` and fixes the Nova Sonic provider rename that
1.55.0 makes, which would otherwise have silently disabled voice.

Prompt-cache contract (the governing constraint here) is unchanged, proven
two ways rather than by code reading:

- Offline: the full formatted ConverseStream request for our production
  config is byte-identical between 1.51.0 and 1.55.0 (same request SHA).
- Live against dev Bedrock: a request formatted by 1.55.0 READ the exact
  cache entry (7,059 tokens) that the same request formatted by 1.51.0 had
  just written. Bedrock itself confirms the cacheable prefix did not move.

`cache_tools` -> `tools_ttl`
  `_warn_on_deprecated_cache_tools` fires on the old key in 1.55.0. With
  `cache_config.ttl` unset, `_build_tools_cache_point` resolves `tools_ttl=True`
  to the same bare `{"cachePoint": {"type": "default"}}` the deprecated path
  emitted, so the toolConfig tail — which sits inside the cached prefix — is
  unchanged. The unsupported branch now pins `tools_ttl=False` explicitly
  instead of falling through the deprecated key.

New auto-injected system cache point
  1.55.0 adds `_should_cache_system()`, guarded by
  `not any("cachePoint" in block ...)`. `AgentFactory.create_agent` already
  appends its own whenever `bedrock_cache_points_supported()`, and that
  predicate is equivalent to the SDK's, so no path gains a second point.
  Audited every system-prompt path: the chat agent goes through the factory;
  voice uses BidiNovaSonicModel (no cache_config); `/chat/api-converse` uses
  raw boto3 on the Bedrock branch and OpenAI-surface models otherwise; there
  is exactly one `BedrockModel` construction site. `system_prompt_ttl` is left
  at its default True as a safety net for any future path that bypasses the
  factory. `_apply_system_cache_ttl` is inert because `cache_config.ttl` stays
  unset.

Nova Sonic provider rename (not in the release notes)
  1.55.0 moved `models.nova_sonic.BidiNovaSonicModel` to
  `models.bedrock.BedrockNovaSonicModel` and flattened its constructor
  (`provider_config["audio"]` -> `audio`, `client_config["region"]` -> `region`).
  `voice_agent` imports the provider inside a `try/except ImportError` that
  degrades to `BIDI_AVAILABLE = False`, so the stale import would not have
  crashed — it would have silently turned voice off in the inference-api image,
  which does install `--extra bidi`. Adds a contract test that reads the pinned
  SDK's source rather than importing it, since CI installs `agentcore`/`dev`
  but not `bidi`.

Also updates the sequential-executor cancellation canary: 1.55.0 moved the
per-tool check from `agent._cancel_signal` to `Agent._observe_cancellation()`,
same semantics plus an external-signal mirror.

boto3 stays at 1.43.68 in all five files that pin it — 1.55.0 floors at
>=1.26.0 and `bedrock-agentcore` is unchanged, so nothing forces it.

Fixes we gain on the GPT-5.6 / Mantle Responses path: `length` now beats
`tool_calls` (1.51.0 executed truncated tool arguments), `cachePoint` blocks
are filtered instead of raising `TypeError` on a mid-session model switch, and
document attachments use `filename`/`file_data` instead of `file_url`.

Verified: full backend suite 7783 passed / 0 failed; a 3-turn dev session on
1.55.0 went first_write -> hit -> hit with constant toolConfigHash and
systemPromptHash, no partial_miss, cacheRead:cacheWrite 9097:126 then 9223:34;
a GPT-5.6 (Terra) turn with a text attachment read the document correctly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@philmerrell
philmerrell force-pushed the feature/strands-1-55-upgrade branch from 9d5d1da to 161ce6e Compare September 9, 2026 04:05
@philmerrell

Copy link
Copy Markdown
Contributor Author

Rebased onto develop (was 9 commits behind; CONFLICTINGMERGEABLE).

Both conflicts were in the dependency pins, from #1011 landing strands-agents-tools 0.8.6 → 0.8.8 on the adjacent line:

  • backend/pyproject.toml — resolved by taking both bumps. This branch now carries strands-agents==1.55.0 and develop's strands-agents-tools==0.8.8; the commit itself only touches the strands-agents lines.
  • backend/uv.lock — regenerated with uv lock rather than hand-merged. Resolves to strands-agents 1.55.0 / strands-agents-tools 0.8.8 / boto3 1.43.68 unchanged / bedrock-agentcore 1.21.0.

Re-verified on the combined state

  • Full backend suite: 7848 passed, 3 skipped, 0 failed (65 more tests than the pre-rebase run, from develop's MCP-apps commits).
  • The formatted ConverseStream request is still byte-identical to 1.51.0's, and the migrated tools_ttl config still produces an identical request to the old cache_tools one with no deprecation warning.

One thing worth recording about 0.8.8

0.8.8's sandbox fix edits calculator.py, and we ship the calculator enabled-by-default — so it was worth checking whether it rotates the cached prefix. It does not:

calculator tool spec SHA
strands-agents-tools 0.8.6 e82f7c619ff7679b
strands-agents-tools 0.8.8 e82f7c619ff7679b

Only the module docstring changed (documenting the symbols('...', cls=N) escape); the calculator function docstring — the one Strands turns into the tool description — is byte-identical. So toolConfigHash does not move and no session pays a one-time cache re-write for this deploy.

@philmerrell
philmerrell merged commit f82f6f2 into develop Sep 9, 2026
4 checks passed
@philmerrell
philmerrell deleted the feature/strands-1-55-upgrade branch September 9, 2026 04:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant