* feat(ai): preserve structured metadata for Bedrock provider errors
A failed Bedrock turn only exposed `errorMessage`, so downstream runtimes
could not classify a provider failure or correlate it with AWS support
without parsing that string. The AWS SDK carries the HTTP status, the
modeled error code, and the request id on the thrown exception; the
provider dropped all three.
Attach them as a `bedrock_response_failure` diagnostic on the existing
`AssistantMessage.diagnostics` array. No new core type surface, and no
existing line changed: the diff is purely additive.
`errorMessage` stays byte-identical because `isRetryableAssistantError`
classifies retries by string-matching it, and `BEDROCK_ERROR_PREFIXES` is
documented as load-bearing for that.
Scope note: the serialized-stream noise in the original report
(`Validation error: 400: {"_events":...}`) was already fixed in v0.82.1 by
#7081, which added the unread-stream guard in `normalizeProviderError`.
Verified against main: `errorMessage` is clean today. This change covers
only the remaining half of the issue, the missing structured metadata.
Details:
- Carries `details` only, no `error` block, as `pi_messages_rewrite` does.
A modeled mid-stream exception is not an `Error` at all, so routing it
through `extractDiagnosticError` would record `"[object Object]"` plus a
stack trace pointing into the SDK. The readable text is in `errorMessage`.
- `errorCode` reads `error.name`, which is where the SDK puts the modeled
code for both paths that expose one: service exceptions from
`client.send()` (via `x-amzn-errortype`) and the plain `Error` the
event-stream unmarshaller throws for an unmodeled stream error (via
`:error-code`). All 13 modeled Bedrock errors end in `Exception`, so that
suffix is the gate; it excludes transport failures such as `TimeoutError`
and `CredentialsProviderError`, and the SDK's `Unknown` placeholder,
without enumerating them.
- A modeled mid-stream exception reports only a request id, on purpose.
`@smithy/core` `getMessageUnmarshaller` throws `deserializedException[code]`
after reading the code into a local, and the JSON shape deserializer built
that value as a bare object literal, so the code no longer exists by the
time it reaches us. The request id from the initial response is used as a
fallback so these failures stay correlatable.
- `details.status` matches the key `pi_messages_response_failure` uses.
- Header-derived values are dropped when over-long rather than truncated: a
truncated request id is not a request id.
- Aborted turns emit no diagnostic.
closes#7224
* docs(ai): trim comment density in the Bedrock failure diagnostic
The added block sat at 52 percent comment against 14 percent for the rest
of bedrock-converse-stream.ts and 2-9 percent across the other providers.
Cut to the facts a future maintainer cannot infer from the code: why the
error code is not gated on `BedrockRuntimeServiceException`, why a modeled
mid-stream exception yields only a request id, and the `errorMessage`
byte-identity invariant. Now 29 percent of a 27-line block.
Test comments trimmed the same way, 15 percent to 4 percent, matching
bedrock-custom-headers.test.ts. No behavior change; all tests unchanged
and passing.
---------
Co-authored-by: Brian Stanley <brian.stanley@kavak.com>
Intl.Segmenter can group Indic conjuncts and spacing marks into one grapheme even when wcwidth-style terminals allocate multiple cells. Count visible consonants after marks and Unicode spacing marks separately while preserving zero-width exceptions.
This is a compatibility heuristic. Unicode Spacing_Mark indicates positive advance, not a full terminal cell; Kitty keeps many Indic continuations in the initial cell, while xterm-style terminals advance for them, so Pi overcounts some clusters in Kitty.
Overcounting causes horizontal drift, but undercounting can trigger terminal autowrap, so this change favors overcounting.
Clusters can contain repeated marks and mark-consonant continuations, so this implementation leaves their widths uncapped. Collapsing them would undercount terminals that advance for every visible continuation.
Mode 2027 does not report cluster widths, so Pi still needs local width calculations. This change does not implement OSC 66, which would be preferable where supported.
Fixes#6124
Co-authored-by: Mario Zechner <badlogicgames@gmail.com>
New section 14: streamAssistant and the three-phase tool execution
blocks (prepare/execute/finalize) with durability callbacks, batch rules
(parallel vs sequential, length truncation, terminate), and the
unbreakable agent-loop.ts compatibility requirement with acceptance
criterion. Harness internals rewritten on top of the blocks: runToolBatch
with provisioned-id callbacks, reconciliation via phases 2+3, hook-to-
block wiring table. Auth surface removed from the stream block: Models
resolves auth per request; before_payload/after_response mount on
onPayload/onResponse. Sections 16-22 renumbered.
Prefer function payloads when malformed OpenAI-compatible tool-call deltas also include an empty custom object, preserving parsed arguments.
Fixes#7160
Co-authored-by: Sunny Young <isunnyyoung@gmail.com>