




















@@ -491,6 +491,8 @@ describe("wrapAnthropicStreamWithRecovery", () => {
491491const anthropicThinkingError = new Error(
492492"thinking or redacted_thinking blocks in the latest assistant message cannot be modified",
493493);
494+const genericizedProviderError =
495+"LLM request failed: provider rejected the request schema or tool payload.";
494496const terminalThinkingSignatureError =
495497"ValidationException: invalid signature on thinking block in message history";
496498@@ -757,6 +759,57 @@ describe("wrapAnthropicStreamWithRecovery", () => {
757759expect(callCount).toBe(2);
758760});
759761762+it.each([
763+{
764+name: "failover rawError",
765+createError: () =>
766+Object.assign(new Error(genericizedProviderError), {
767+rawError: terminalThinkingSignatureError,
768+}),
769+},
770+{
771+name: "Anthropic SDK error body",
772+createError: () =>
773+Object.assign(new Error(genericizedProviderError), {
774+error: { error: { message: terminalThinkingSignatureError } },
775+}),
776+},
777+{
778+name: "direct errorMessage",
779+createError: () =>
780+Object.assign(new Error(genericizedProviderError), {
781+errorMessage: terminalThinkingSignatureError,
782+}),
783+},
784+{
785+name: "cyclic cause graph",
786+createError: () => {
787+const root = new Error(genericizedProviderError) as Error & { cause?: unknown };
788+const nested = { cause: root, message: terminalThinkingSignatureError };
789+root.cause = nested;
790+return root;
791+},
792+},
793+])(
794+"retries genericized request errors carrying provider detail in $name",
795+async ({ createError }) => {
796+const providerError = createError();
797+let callCount = 0;
798+const wrapped = wrapAnthropicStreamWithRecovery(
799+(() => {
800+callCount += 1;
801+return Promise.reject(providerError);
802+}) as Parameters<typeof wrapAnthropicStreamWithRecovery>[0],
803+{ id: "test-session" },
804+);
805+806+await expect(wrapped({} as never, { messages: [] } as never, {} as never)).rejects.toBe(
807+providerError,
808+);
809+expect(callCount).toBe(2);
810+},
811+);
812+760813it("retries pre-content terminal stream-error events with omitted-reasoning text", async () => {
761814let callCount = 0;
762815const contexts: Array<{ messages?: AgentMessage[] }> = [];
@@ -818,7 +871,11 @@ describe("wrapAnthropicStreamWithRecovery", () => {
818871819872it("does not retry non-thinking terminal stream-error events", async () => {
820873let callCount = 0;
821-const errorMessage = createTestStreamErrorMessage("rate limit exceeded");
874+const errorMessage = createTestAssistantMessage({
875+content: [{ type: "text", text: terminalThinkingSignatureError }],
876+stopReason: "error",
877+errorMessage: "rate limit exceeded",
878+});
822879const wrapped = wrapAnthropicStreamWithRecovery(
823880(() => {
824881callCount += 1;
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。