Commit 8f8389d
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
0 commit comments