feat(ai-proxy): support aws bedrock#13249
feat(ai-proxy): support aws bedrock#13249shreemaan-abhishek wants to merge 35 commits intoapache:masterfrom
Conversation
Signed-off-by: Abhishek Choudhary <shreemaan.abhishek@gmail.com>
Rename double_encode_path to encode_path_for_canonical_uri since the function only does a single ngx.escape_uri pass. The double-encoding required by AWS SigV4 is achieved by combining this pass with the upstream encoding done by bedrock.lua on the model ID. Update the function comment to accurately describe this two-stage flow.
construct_forward_headers() in http.lua lowercases all header keys, so writing signed headers (Authorization, X-Amz-Date, X-Amz-Security-Token, Host) in mixed case could result in duplicate headers depending on the HTTP client's behavior. Write them back as lowercase to match the convention used elsewhere.
Add an explicit nil/empty check on params.path at the start of sign_request() to return a clear error instead of crashing in encode_path_for_canonical_uri() with "attempt to index a nil value". This can happen when the Bedrock provider's path capability returns nil (e.g., when options.model is missing).
Bedrock Converse API only accepts 'user' and 'assistant' roles in
messages[*].role. System prompts must go in the top-level body.system
field as an array of {text: "..."} blocks.
Update prepend_messages and append_messages to split incoming messages
by role: system entries are routed to body.system as text blocks, while
user/assistant entries go to body.messages as before. Without this,
prompt-decorator plugins inserting canonical system messages would
produce invalid Bedrock requests.
Bedrock builds the upstream URL path from the model ID. Without options.model and without override.endpoint, the path resolves to nil and the request fails later with a low-signal transport error. Add a schema-level rule to require options.model when provider=bedrock and override.endpoint is not set, so misconfigurations fail fast at config validation time.
TEST 2-4 depend on the route created in TEST 1, and TEST 7 depends on the route created in TEST 6. Add no_shuffle() so tests run in declared order and these dependencies are honored consistently.
Switch oneOf to anyOf in the conditional schemas for vertex-ai and bedrock. With oneOf, users couldn't set both provider_conf and override.endpoint together. This blocked valid use cases like AWS PrivateLink (custom endpoint) combined with explicit signing region, since the code does not parse the region from the override URL. anyOf still requires at least one of the two to be set.
… endpoint Add test scenarios covering edge cases introduced by the Bedrock provider: - TEST 8/9: model as inference profile ARN (validates URL encoding of ":" and "/" in the path and SigV4 canonical URI handling) - TEST 10/11: auth.aws.session_token propagation as x-amz-security-token header to the upstream - TEST 12: route with provider_conf.region but no override.endpoint (validates schema accepts default endpoint construction) Mock server appends session_token to the response body so TEST 11 can assert propagation via response_body regex.
Move all SigV4 path encoding into auth-aws.lua so callers don't need to know about the AWS double-encoding rule. The previous design split encoding between bedrock.lua (pre-encoded the model) and auth-aws.lua (added the second encoding pass), which produced an incorrect canonical URI when params.path came from a raw source like override.endpoint. Now bedrock.lua passes the raw model in the path, and auth-aws.lua normalizes the input (decode-then-encode is idempotent for both raw and once-encoded inputs) and produces: - params.path: once-encoded for HTTP wire transport - canonicalURI: twice-encoded for SigV4 canonical request This handles both default-endpoint and override.endpoint paths correctly regardless of whether the input is raw or pre-encoded.
There was a problem hiding this comment.
Pull request overview
Adds Amazon Bedrock support to the ai-proxy / ai-proxy-multi plugin by introducing a Bedrock provider implementation, Bedrock Converse protocol handling, and AWS SigV4 request signing.
Changes:
- Introduces a new
bedrockprovider +bedrock-converseprotocol adapter (detection, request shaping, response parsing). - Adds AWS SigV4 signing support (incl. session token propagation) and updates HTTP transport to accept pre-serialized bodies.
- Extends ai-proxy schemas and log sanitization, plus adds an end-to-end Bedrock-focused test suite.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
t/plugin/ai-proxy-bedrock.t |
New test coverage for Bedrock Converse routing, schema validation, ARN model handling, and session token propagation. |
apisix/utils/log-sanitize.lua |
Redacts x-amz-security-token in logged headers. |
apisix/plugins/ai-transport/http.lua |
Allows params.body to be a pre-serialized string (needed after SigV4 signing). |
apisix/plugins/ai-transport/auth-aws.lua |
New AWS SigV4 signing helper for outbound AI provider requests. |
apisix/plugins/ai-proxy/schema.lua |
Adds AWS auth schema + encrypt_fields updates; adds Bedrock provider_conf schema and conditional validation. |
apisix/plugins/ai-providers/schema.lua |
Registers bedrock as a known provider. |
apisix/plugins/ai-providers/bedrock.lua |
New Bedrock provider implementation (host/path generation; remove model from body). |
apisix/plugins/ai-providers/base.lua |
Hooks AWS SigV4 signing into the shared request build pipeline. |
apisix/plugins/ai-protocols/init.lua |
Registers bedrock-converse and adjusts protocol detection order. |
apisix/plugins/ai-protocols/bedrock-converse.lua |
New Bedrock Converse protocol adapter (non-streaming). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Previously the override schema didn't require any fields, so a config
like override = {} would pass validation despite being meaningless.
This was particularly problematic because the schema's anyOf accepted
"override" as an alternative to "provider_conf" — letting an empty
override silently bypass the provider_conf requirement and break
downstream request construction.
Make endpoint required in the override schema since it's the only
field and the only purpose of override is to set the endpoint.
Add minLength = 1 to auth.aws.access_key_id, secret_access_key, session_token, and provider_conf.region for the Bedrock provider. The 'required' constraint only checks key presence; without minLength, empty strings pass schema validation and fail later during signing or upstream URL construction. Catch these as admin-side validation errors instead.
…nsert prepend_messages and append_messages only checked for nil before calling core.table.insert(body.system/messages, ...), which would crash if those fields existed but weren't tables (e.g., a string). Use type(...) ~= "table" to normalize, preventing request-time exceptions on malformed input.
Bedrock provider falls back to AWS_REGION env var (or us-east-1 default) when provider_conf.region is not set, so the schema should not require provider_conf or override. The inner rule still requires options.model when override.endpoint is not set, ensuring a valid upstream URL can always be constructed.
The previous code passed n=1 to normalize_and_encode_path for the canonical URI, but n=1 means decode-then-encode-once, which cancels out and produces the same once-encoded form as params.path. AWS SigV4 requires reserved characters to be encoded TWICE in the canonical URI (e.g., raw ":" → "%3A" on the wire → "%253A" in canonicalURI). Pass n=2 so the function decodes each segment then encodes it twice, producing the required double-encoded form. Tests pass because the local mock doesn't validate signatures, but real AWS requests would have failed with signature mismatch.
Application inference profile ARNs contain "/" (e.g.
"...:application-inference-profile/abc") which would be split as path
segments if interpolated raw into "/model/{id}/converse". Encode the
model with ngx.escape_uri so "/" becomes "%2F" and ":" becomes "%3A",
keeping the model as a single path segment.
This is safe to combine with auth-aws.lua's normalize_and_encode_path
since that function decodes-then-encodes (idempotent for both raw and
once-encoded inputs).
Update the override.endpoint description to: - Recommend host-only overrides for the typical use case (PrivateLink, reverse proxies) so the plugin computes the path with proper encoding - Document that any reserved characters in an included path (e.g., Bedrock inference profile ARNs with ':' or '/') must be URL-encoded
- Fix test URIs to end with /converse so bedrock-converse protocol detection matches (previous URIs like /ai/converse-arn don't end with /converse and would fall through to openai-chat) - Log the request URI in the mock so tests can assert specific paths - Update TEST 8 override.endpoint to use a properly URL-encoded ARN (matching what users should provide per the schema documentation) - Add an error_log assertion in TEST 9 verifying the wire path keeps the ARN as a single percent-encoded segment (%3A and %2F preserved)
The mock server extracted text from the first user message into first_content but never used it. Remove the dead code to make the mock handler clearer.
Remove the AWS_REGION env var fallback and "us-east-1" default for
the Bedrock provider's region. Silently defaulting to us-east-1 was a
footgun — requests would route to the wrong region and fail SigV4
signature validation with confusing errors.
Now provider_conf.region must be set explicitly for Bedrock at the
schema level. The runtime in base.lua also returns a clear error
("missing region for AWS SigV4 signing (provider_conf.region required
for bedrock)") as a defense-in-depth check.
Also remove the hanging schema comment that explained the (now
removed) fallback behavior. Update docs (en + zh) to remove env var /
default mentions and clarify provider_conf.region is required.
Tests updated to set provider_conf.region in all bedrock instance
configs; AWS_REGION env var dropped from the test main_config.
Validate the structure of the SigV4 Authorization and X-Amz-Date headers instead of just checking presence. A broken signer would now fail tests instead of silently passing. Checks: - Authorization starts with "AWS4-HMAC-SHA256 " - Credential matches AKIAIOSFODNN7EXAMPLE/<DATE>/us-east-1/bedrock/aws4_request - SignedHeaders=... is present - Signature= is followed by exactly 64 hex chars - X-Amz-Date matches YYYYMMDDTHHMMSSZ format
normalize_and_encode_path used path:gmatch("[^/]+") which silently
dropped empty segments (e.g., "//foo" became "/foo") and trailing
slashes (e.g., "/foo/" became "/foo"). For paths with these
structures, the wire path and the SigV4 canonical URI would differ
from what AWS computes, breaking signature validation.
Switch to path:gsub("[^/]+", ...) so only non-slash runs are touched
and all "/" characters (including empties and trailing) are preserved
verbatim. Bedrock paths don't currently exercise this case, but the
function should be correct independent of caller.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated 10 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| -- AWS SigV4 signing (must be last — signs the finalized body) | ||
| if auth.aws then | ||
| local auth_aws = require("apisix.plugins.ai-transport.auth-aws") | ||
| local region = opts.conf and opts.conf.region | ||
| if not region then | ||
| return nil, "missing region for AWS SigV4 signing " | ||
| .. "(provider_conf.region required for bedrock)" | ||
| end | ||
| local sign_err = auth_aws.sign_request(params, auth.aws, region) | ||
| if sign_err then | ||
| return nil, "failed to sign AWS request: " .. sign_err | ||
| end | ||
| end |
There was a problem hiding this comment.
AWS SigV4 signing is triggered solely by the presence of auth.aws, regardless of which provider is selected. Because the schema doesn’t currently restrict auth.aws to Bedrock-only, a misconfigured instance could end up SigV4-signing requests to non-AWS providers (adding/overwriting authorization, host, etc.). Consider gating this behind self/provider type (e.g., only sign when provider is bedrock) and/or tightening the schema so auth.aws is only allowed/required for Bedrock.
There was a problem hiding this comment.
If we can follow this way, it is much better @shreemaan-abhishek
| | provider_conf.region | string | True | | | Google Cloud Region. | | ||
| | provider_conf.region | string | True | | minLength = 1 | AWS region used to construct the Bedrock endpoint and to sign the request with SigV4. Required when `provider` is set to `bedrock`. | |
There was a problem hiding this comment.
The attributes table now lists provider_conf.region twice (once for Google Cloud Region and once for AWS Region). This is ambiguous for readers and makes it unclear which providers each row applies to. Please consolidate into a single provider_conf.region row that explains the per-provider meaning/requirements, or split provider-specific configuration into separate subsections to avoid duplicate keys.
| | provider_conf.region | string | True | | | Google Cloud Region. | | |
| | provider_conf.region | string | True | | minLength = 1 | AWS region used to construct the Bedrock endpoint and to sign the request with SigV4. Required when `provider` is set to `bedrock`. | | |
| | provider_conf.region | string | True | | minLength = 1 | Provider-specific region. For `vertex-ai`, this is the Google Cloud region. For `bedrock`, this is the AWS region used to construct the Bedrock endpoint and sign the request with SigV4. Required when `provider` is set to `bedrock`. | |
| | instances.provider_conf.region | string | True | | | Google Cloud Region. | | ||
| | instances.provider_conf.region | string | True | | minLength = 1 | AWS region used to construct the Bedrock endpoint and to sign the request with SigV4. Required when `provider` is set to `bedrock`. | | ||
| | instances.priority | integer | False | 0 | | Priority of the LLM instance in load balancing. `priority` takes precedence over `weight`. | | ||
| | instances.weight | string | True | 0 | greater or equal to 0 | Weight of the LLM instance in load balancing. | | ||
| | instances.auth | object | True | | | Authentication configurations. | |
There was a problem hiding this comment.
The attributes table now lists instances.provider_conf.region twice (Google Cloud Region vs AWS Region). Duplicate keys in the same table are ambiguous and make it hard to tell which providers each row applies to. Please consolidate into a single row with provider-specific semantics/requirements, or split provider-specific config into separate subsections.
| | instances.provider_conf.region | string | True | | | Google Cloud Region. | | |
| | instances.provider_conf.region | string | True | | minLength = 1 | AWS region used to construct the Bedrock endpoint and to sign the request with SigV4. Required when `provider` is set to `bedrock`. | | |
| | instances.priority | integer | False | 0 | | Priority of the LLM instance in load balancing. `priority` takes precedence over `weight`. | | |
| | instances.weight | string | True | 0 | greater or equal to 0 | Weight of the LLM instance in load balancing. | | |
| | instances.auth | object | True | | | Authentication configurations. | | |
| | instances.provider_conf.region | string | True | | minLength = 1 | Provider-specific region. For `vertex-ai`, this is the Google Cloud region. For `bedrock`, this is the AWS region used to construct the Bedrock endpoint and sign the request with SigV4. Required when `provider` is set to `bedrock`, and required for `vertex-ai` when `provider_conf` is used. | | |
| | instances.priority | integer | False | 0 | | Priority of the LLM instance in load balancing. `priority` takes precedence over `weight`. | | |
| | instances.weight | string | True | 0 | greater or equal to 0 | Weight of the LLM instance in load balancing. | | |
| | instances.auth | object | True | | | Authentication configurations. | |
| | instances.provider_conf.region | string | 是 | | | Google Cloud 区域。 | | ||
| | instances.provider_conf.region | string | 是 | | minLength = 1 | 用于构造 Bedrock 端点并使用 SigV4 对请求进行签名的 AWS 区域。当 `provider` 设置为 `bedrock` 时必填。 | |
There was a problem hiding this comment.
属性表中 instances.provider_conf.region 现在出现了两次(一次表示 Google Cloud Region,一次表示 AWS Region)。同一表格内重复键会导致含义不清晰。建议合并为同一行并在描述中注明不同 provider 的语义/必选条件,或将 provider-specific 配置拆分到单独小节。
| | instances.provider_conf.region | string | 是 | | | Google Cloud 区域。 | | |
| | instances.provider_conf.region | string | 是 | | minLength = 1 | 用于构造 Bedrock 端点并使用 SigV4 对请求进行签名的 AWS 区域。当 `provider` 设置为 `bedrock` 时必填。 | | |
| | instances.provider_conf.region | string | 是 | | minLength = 1 | 区域配置:当 `provider` 设置为 `vertex-ai` 时表示 Google Cloud 区域;当 `provider` 设置为 `bedrock` 时表示 AWS 区域,用于构造 Bedrock 端点并使用 SigV4 对请求进行签名,且该场景下必填。 | |
| - AI | ||
| - LLM | ||
| description: The ai-proxy-multi Plugin extends the capabilities of ai-proxy with load balancing, retries, fallbacks, and health chekcs, simplifying the integration with OpenAI, DeepSeek, Azure, AIMLAPI, Anthropic, OpenRouter, Gemini, Vertex AI, and other OpenAI-compatible APIs. | ||
| description: The ai-proxy-multi Plugin extends the capabilities of ai-proxy with load balancing, retries, fallbacks, and health chekcs, simplifying the integration with OpenAI, DeepSeek, Azure, AIMLAPI, Anthropic, OpenRouter, Gemini, Vertex AI, Amazon Bedrock, and other OpenAI-compatible APIs. |
There was a problem hiding this comment.
Typo in the front-matter description: “health chekcs” should be “health checks”.
| description: The ai-proxy-multi Plugin extends the capabilities of ai-proxy with load balancing, retries, fallbacks, and health chekcs, simplifying the integration with OpenAI, DeepSeek, Azure, AIMLAPI, Anthropic, OpenRouter, Gemini, Vertex AI, Amazon Bedrock, and other OpenAI-compatible APIs. | |
| description: The ai-proxy-multi Plugin extends the capabilities of ai-proxy with load balancing, retries, fallbacks, and health checks, simplifying the integration with OpenAI, DeepSeek, Azure, AIMLAPI, Anthropic, OpenRouter, Gemini, Vertex AI, Amazon Bedrock, and other OpenAI-compatible APIs. |
| "uri": "/ai/converse", | ||
| "plugins": { | ||
| "ai-proxy-multi": { | ||
| "instances": [ | ||
| { | ||
| "name": "bedrock", | ||
| "provider": "bedrock", |
There was a problem hiding this comment.
This test suite exercises Bedrock via ai-proxy-multi only. Since the PR claims Bedrock support for both ai-proxy and ai-proxy-multi, it would be good to add at least one analogous happy-path + schema-validation case for the single-instance ai-proxy plugin (especially around required provider_conf.region and auth.aws).
| .. "PrivateLink, reverse proxies) — provide only the " | ||
| .. "scheme + host so the plugin computes the path. " | ||
| .. "If you include a path with reserved characters " | ||
| .. "(e.g., Bedrock inference profile ARNs containing " | ||
| .. "':' or '/'), they must be URL-encoded.", |
There was a problem hiding this comment.
The schema description for override.endpoint says to “provide only the scheme + host so the plugin computes the path”, but ai-providers/base.lua explicitly uses parsed_url.path when a path is present (and the Bedrock tests/examples set a full /model/.../converse path). This description is misleading; please update it to reflect that override.endpoint may include a path (and query), and clarify when the plugin computes vs honors the provided path.
| .. "PrivateLink, reverse proxies) — provide only the " | |
| .. "scheme + host so the plugin computes the path. " | |
| .. "If you include a path with reserved characters " | |
| .. "(e.g., Bedrock inference profile ARNs containing " | |
| .. "':' or '/'), they must be URL-encoded.", | |
| .. "PrivateLink, reverse proxies). You may provide " | |
| .. "only the scheme + host, in which case the plugin " | |
| .. "computes the provider-specific path, or provide " | |
| .. "a full endpoint including path and query, in " | |
| .. "which case the plugin uses the supplied path/query. " | |
| .. "If your custom path or query contains reserved " | |
| .. "characters (e.g., Bedrock inference profile ARNs " | |
| .. "containing ':' or '/'), they must be URL-encoded.", |
| encrypt_fields = { | ||
| "auth.header", "auth.query", "auth.gcp.service_account_json", | ||
| "auth.aws.secret_access_key", "auth.aws.session_token", | ||
| }, |
There was a problem hiding this comment.
For the single-instance ai-proxy schema, Bedrock-specific requirements described in this PR (e.g., provider_conf.region and auth.aws being required for provider=bedrock) are not enforced here—only the encrypt_fields list was updated. This allows misconfigured Bedrock routes to pass schema validation and fail later at runtime during SigV4 signing/path construction. Please add Bedrock-specific conditional requirements to ai_proxy_schema (similar to the instances schema in this file).
| }, | ||
| required = { "provider_conf" }, |
There was a problem hiding this comment.
For provider=bedrock, the schema currently enforces provider_conf.region and (optionally) options.model, but it does not require auth.aws. Given the provider relies on SigV4 signing, it’s better to fail fast at config time by requiring auth.aws (and potentially disallowing it for non-AWS providers) to avoid unsigned requests reaching Bedrock and returning confusing upstream errors.
| }, | |
| required = { "provider_conf" }, | |
| auth = { | |
| required = { "aws" }, | |
| }, | |
| }, | |
| required = { "provider_conf", "auth" }, |
| | provider_conf.region | string | 是 | | | Google Cloud 区域。 | | ||
| | provider_conf.region | string | 是 | | minLength = 1 | 用于构造 Bedrock 端点并使用 SigV4 对请求进行签名的 AWS 区域。当 `provider` 设置为 `bedrock` 时必填。 | |
There was a problem hiding this comment.
属性表中 provider_conf.region 现在出现了两次(一次表示 Google Cloud Region,一次表示 AWS Region)。这会让读者难以区分该字段在不同 provider 下的含义/必选条件。建议合并为同一行并在描述中注明不同 provider 的语义与要求,或将 provider-specific 配置拆分到单独小节,避免重复键。
| | provider_conf.region | string | 是 | | | Google Cloud 区域。 | | |
| | provider_conf.region | string | 是 | | minLength = 1 | 用于构造 Bedrock 端点并使用 SigV4 对请求进行签名的 AWS 区域。当 `provider` 设置为 `bedrock` 时必填。 | | |
| | provider_conf.region | string | 是 | | minLength = 1 | 区域配置:当 `provider` 设置为 `vertex-ai` 时,表示 Google Cloud 区域;当 `provider` 设置为 `bedrock` 时,表示 AWS 区域,用于构造 Bedrock 端点并使用 SigV4 对请求进行签名。在 `bedrock` 场景下该字段必填且不能为空。 | |
…edrock Signed-off-by: Abhishek Choudhary <shreemaan.abhishek@gmail.com>
Signed-off-by: Abhishek Choudhary <shreemaan.abhishek@gmail.com>
Three related fixes: 1. The single ai-proxy schema lacked provider_conf entirely and didn't carry the Bedrock conditional rules — only ai-proxy-multi enforced them. Add provider_conf and the same allOf block to ai_proxy_schema so single-instance Bedrock routes fail validation if misconfigured. 2. Require auth.aws (not just any auth) when provider=bedrock. Without AWS credentials the signing block silently skips and AWS rejects with confusing errors — better to fail fast at config time. 3. Gate SigV4 signing in base.lua on a per-provider aws_sigv4 flag (set true on bedrock). Previously a stray auth.aws block on any provider would trigger SigV4 signing and overwrite headers.
- Merge the duplicate provider_conf.region rows (vertex-ai vs bedrock)
into a single row that documents per-provider semantics. The two
separate rows were ambiguous about which providers each applied to.
- Update override.endpoint description: clarify that the URL may
include a path (which overrides the plugin-computed path), and add
a Bedrock-specific tip about URL-encoding reserved characters in
inference profile ARNs (':' → '%3A', '/' → '%2F').
- Fix "health chekcs" → "health checks" typo in ai-proxy-multi.md
front-matter description.
Applied to en + zh versions of both ai-proxy.md and ai-proxy-multi.md.
Mirror all 12 ai-proxy-bedrock.t test cases for the single-instance ai-proxy plugin (the existing test file only exercises ai-proxy-multi). Both plugins now have parity coverage for: - Basic Converse request + response - System prompt (top-level body.system) - Token usage extraction - Schema validation (missing auth.aws.secret_access_key) - Protocol mismatch (URI not ending in /converse) - ARN model with override.endpoint and URL-encoded path - session_token propagation as x-amz-security-token - Default endpoint construction (no override) Mock server (SigV4 assertions, response shape) is byte-identical to the existing test file.
Four small fixes to make the Bedrock + AWS SigV4 path more robust: 1. Guard nil conf in bedrock.lua host capability: provider_conf can be nil when override.endpoint is the only config; the previous conf.region access would crash before the base layer could fall back to the parsed override URL. 2. Validate aws_conf and region at the top of sign_request, matching the existing params.path validation. Returns a clean error string instead of crashing on missing inputs. 3. Initialize params.headers before copying signed values so the helper can be reused safely from contexts that don't pre-populate headers. 4. Make endpointPrefix configurable via aws_conf.endpoint_prefix (default "bedrock") so the helper isn't permanently Bedrock-specific and can be reused for future AWS-backed providers (e.g., SageMaker).
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Add Amazon Bedrock support to ai-proxy and ai-proxy-multi
Adds a new
bedrockprovider that proxies requests to Amazon Bedrock's Converse API, with full AWS SigV4 request signing.What's new
Provider & protocol:
bedrockprovider that signs requests with SigV4 and routes them tobedrock-runtime.{region}.amazonaws.com/model/{modelId}/conversebedrock-converseprotocol module that parses Bedrock's native message/content-block formatmessagesarray sent to a URI ending with/converseAuthentication:
auth.awsblock withaccess_key_id,secret_access_key(required), andsession_token(optional, for temporary credentials from STS / assumed roles)secret_access_key,session_token) are encrypted at the schema levelx-amz-security-token) are redacted from logsRegion & endpoint:
provider_conf.regionis required forbedrock(no env-var fallback or hardcoded default — fails fast on misconfiguration)override.endpointsupported for AWS PrivateLink, custom proxies, etc.Model identifiers (
options.model):anthropic.claude-3-5-sonnet-20240620-v1:0)us.anthropic.claude-3-5-sonnet-20240620-v1:0)arn:aws:bedrock:us-east-1:123456789012:application-inference-profile/abc123)ARN model IDs are URL-encoded automatically so reserved characters (
:,/) stay as a single path segment.Example
Implementation highlights
resty.aws.request.sign(already a dependency):→%3Aon the wire →%253Ain canonical URI)path:gsubpreserves slash structure including trailing slashes and empty segmentsconstruct_forward_headers()and avoid duplicatesLimitations / future work
ConverseStream(which uses AWS EventStream binary protocol, not SSE) is not yet supported.Checklist