Skip to content

Commit 8f8389d

Browse files
committed
docs(aws-strands): make the four Strands documents true against main
Both package READMEs, the architecture document and the Python examples README had drifted in two directions at once. Some of the prose was written ahead of the implementation and never reconciled, and some had fallen behind the work that landed during the partnership refresh. This is a pass over every claim in all four, checked against the source rather than against the prose that preceded it, run through four rounds of unbiased review. ## Claims that were false The MCP snippet could neither resolve nor compile. It imported `@strands-agents/sdk/mcp`, which the SDK's exports map does not carry, and constructed `McpClient` with no `transport`, which `McpClientConfig` requires. The section's premise was also wrong: it blamed an unconnected client, when connectedness is irrelevant. `ToolList` does accept an `McpClient`, but the SDK routes it to an internal client list and registers its tools inside `Agent.initialize()`, which runs on the first invocation, while this adapter clones the resolved `agent.tools` at construction. Measured against 1.1.0: `new Agent({ tools: [client] })` leaves `agent.tools` empty. Same hazard, different reason, and the fix is the same one the section already recommended. The install command omitted `@ag-ui/client` and `@ag-ui/a2ui-toolkit`, both non-optional peers imported by the package root, so a reader following it hit an unresolvable import. The URL-fetch section said `UrlFetchPolicy`, `UrlFetchPolicyError` and `DEFAULT_URL_FETCH_POLICY` are exported so a caller can read the default back. Each carries `export` in `utils.ts`, but neither the root entry nor the `/server` subpath re-exports them and there is no deep path, so all three are unreachable. The example tables described hooks the examples do not use. Measured across every field of both config classes, the examples exercise `tool_behaviors`, `state_context_builder`, `state_from_args`, `state_from_result`, `predict_state` and `a2ui`, plus `continue_after_frontend_call` on the Python side. The line claiming they exercise every built-in hook was wrong by eleven. `shared_state.py` was credited with a `state_from_result` it never calls, `agentic_generative_ui.py` with a `custom_result_handler` and a `stop_streaming_after_result` it never sets. The Python native frontend wait was documented as an explicit `continue_after_frontend_call=False` opt-in. `False` is that field's default and `waits_for_frontend_call` tests only whether a `ToolBehavior` exists, so a frontend tool given a `ToolBehavior` for any unrelated reason waits too. TypeScript reads an optional field and has no equivalent case. Quoted code and signatures had drifted: Python's credentials expression intersects `cors_origins` rather than `origins`; `add_strands_fastapi_endpoint` takes `invocation_state_provider` and `addStrandsExpressEndpoint` takes `bodyParser`; the reconciliation provenance filter was quoted as a line of TypeScript that no longer exists; `ConcurrentInvocationError` was quoted as a complete literal but truncated; and `INCOMPLETE_STREAM` was cited as an AG-UI client verifier rejection when the verifier raises a bare `AGUIError` and defines no such code. Counts were wrong throughout, and are now named sets wherever a set will do: the Python packaging surface listed eight names where `__all__` carries thirty-two; five reconciliation sites, not four, and their log lines are not uniform; two shared codes carry a per-side sentence, not one; the auth guard derives its status from the error rather than always answering `500`; the `tool_stream_event_handler` report is keyed on the tool-and-call pair rather than the call id, which inverts the documented collapse; the dojo route table omitted the citations demo; and neither README listed `MESSAGES_SNAPSHOT`, which both adapters emit by default at four lifecycle boundaries. The reasoning section was premised on a default `BedrockModel` the demo does not use, and its Bedrock snippet omitted the `temperature: 1` that provider requires while thinking is enabled. The abnormal-stop trigger was named in Python's snake_case in the TypeScript README, conflating what arrives from the SDK with what goes out on the wire. The prerequisites named Node 18 where the SDK's own floor is 20. The AgentCore link pointed at an `awslabs` repository that returns 404, and both Python snippets were indented inside their fences, so copying one raised `IndentationError`. The two citation sections contradicted each other. The TypeScript README said a provider supplying a generated span reaches a Python client without either `content` or `source`; `citations.py` reads `source` whenever the value is there, and only the generated span has no field in that SDK's stream shape. The Python README also credited `strands.types.citations` with a search-result location kind it does not declare at the locked 1.18.0, where it carries the three document kinds and nothing else, and pointed at a `Bedrock` column as though it answered a Python-versus-TypeScript question. ## The error-code question, re-derived Every code each bridge emits was extracted from `agent.py` and `agent.ts` and compared against `error-codes.json`, which matches both sides exactly. The TypeScript-only set is `SEED_BUILD_ERROR` and `THREAD_AGENT_CONFIG_ERROR`. Neither README pointed at that file at all, and both now do. ## Capabilities that landed unwritten Multi-agent orchestration in both languages, with the three ways the paths genuinely differ; the per-thread concurrency guard, its orchestrator arm which is Python-only, and what a caller driving `run` directly owes its generator; abnormal model stop reasons and the per-provider mapping that decides whether a hint can arrive at all; unmapped events forwarded as `RAW`; server-side URL validation, including that only Python can replace the policy and that the two policies bound different things; and durable recovery of frontend tool results in TypeScript, with the wire-id change that made it possible. ## Two compatibility breaks, stated plainly Cross-origin access in TypeScript is now opt-in where the factory previously installed CORS unconditionally at `corsOrigin: "*"`, and that break is now named in the architecture document as well as the README. And `RAW` carries framework-shaped payloads whose shape the SDK may change in any release, which both READMEs now say rather than leaving a reader to find out. ## Scope Documents only. The TypeScript package declares no `engines`, so its README no longer claims a floor is enforced; it states the SDK's floor and says plainly that nothing checks it. The related hazard is documented rather than fixed: `@strands-agents/sdk` is ESM-only while this package also ships a CommonJS build whose entry requires it, so a CommonJS consumer needs a runtime with `require(esm)`. Choosing a floor, or dropping the CommonJS build, is a packaging decision for the package owner and the sibling integrations are built the same way. ## Not reworded No runtime string. The error codes and message text quoted in these documents are matched literally by clients and pinned by `error-codes.json`; the docs-contract tests in both languages, the error-code table tests and the example-server route-table test all pass, as do the full suites, TypeScript 1611 and Python 1270.
1 parent 33b1caf commit 8f8389d

4 files changed

Lines changed: 748 additions & 164 deletions

File tree

0 commit comments

Comments
 (0)