fix(chat): an edit after a broken edit call no longer fails, found with Opus 5.5

- Claude Opus 5.5 sent an edit with invalid JSON, then the same edit
  again. The first call's streamed preview was never undone: its input
  has no operations, and the undo sat behind that check. The second edit
  then started from the preview, failed on a duplicate id, and the model
  had to try a third time. The undo now runs first, and an edit that
  starts in the same render uses the undone diagram.
- The SDK passes an invalid tool call's error as a string, which was
  wrapped as a provider error. streamErrorText keeps it as the text the
  model reads.
- Bedrock's "on-demand throughput isn't supported" gets the model id hint.
- The thinking header uses the page language ("Thought for 1 second" in
  English), from the dictionary entries that were already there.
This commit is contained in:
dayuan.jiang
2026-10-04 21:18:54 +09:00
parent 65e3dd1dde
commit 2ac4c54eb2
9 changed files with 271 additions and 18 deletions
+2 -7
View File
@@ -38,7 +38,7 @@ import {
setTraceOutput,
wrapWithObserve,
} from "@/lib/langfuse"
import { classifyLLMError, isToolCallError } from "@/lib/llm-errors"
import { classifyLLMError, streamErrorText } from "@/lib/llm-errors"
import {
resolveMaxOutputTokens,
withOutputTokenLimitFallback,
@@ -724,12 +724,7 @@ Call this tool to get shape names and usage syntax for a specific library.`,
const response = result.toUIMessageStreamResponse({
sendReasoning: true,
// The same text goes back to the model when its tool call was
// invalid, so it can fix it: keep that one as it is
onError: (error) =>
isToolCallError(error)
? (error as Error).message
: JSON.stringify(classifyLLMError(error)),
onError: streamErrorText,
messageMetadata: ({ part }) => {
if (part.type === "finish") {
const usage = (part as any).totalUsage