From e5c38290a68bf244dccdaef8de3900ee11b2c9aa Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 14 Apr 2026 16:37:29 +0100 Subject: [PATCH] fix(plugin-sdk): share anthropic replay hook constants --- .../amazon-bedrock/register.sync.runtime.ts | 6 ++--- extensions/anthropic-vertex/index.ts | 5 +--- extensions/anthropic/replay-policy.ts | 6 ++--- src/plugin-sdk/provider-model-shared.test.ts | 25 +++++++++++++++++++ src/plugin-sdk/provider-model-shared.ts | 8 ++++++ 5 files changed, 38 insertions(+), 12 deletions(-) diff --git a/extensions/amazon-bedrock/register.sync.runtime.ts b/extensions/amazon-bedrock/register.sync.runtime.ts index 84a0365ffce..60f282d9a86 100644 --- a/extensions/amazon-bedrock/register.sync.runtime.ts +++ b/extensions/amazon-bedrock/register.sync.runtime.ts @@ -1,7 +1,7 @@ import type { StreamFn } from "@mariozechner/pi-agent-core"; import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry"; import { - buildProviderReplayFamilyHooks, + ANTHROPIC_BY_MODEL_REPLAY_HOOKS, normalizeProviderId, } from "openclaw/plugin-sdk/provider-model-shared"; import { @@ -74,9 +74,7 @@ export function registerAmazonBedrockPlugin(api: OpenClawPluginApi): void { /ValidationException.*(?:exceeds? the (?:maximum|max) (?:number of )?(?:input )?tokens)/i, /ModelStreamErrorException.*(?:Input is too long|too many input tokens)/i, ] as const; - const anthropicByModelReplayHooks = buildProviderReplayFamilyHooks({ - family: "anthropic-by-model", - }); + const anthropicByModelReplayHooks = ANTHROPIC_BY_MODEL_REPLAY_HOOKS; const pluginConfig = (api.pluginConfig ?? {}) as AmazonBedrockPluginConfig; const guardrail = pluginConfig.guardrail; diff --git a/extensions/anthropic-vertex/index.ts b/extensions/anthropic-vertex/index.ts index 6e66ced2827..4d7beabd0fc 100644 --- a/extensions/anthropic-vertex/index.ts +++ b/extensions/anthropic-vertex/index.ts @@ -1,5 +1,5 @@ import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry"; -import { buildProviderReplayFamilyHooks } from "openclaw/plugin-sdk/provider-model-shared"; +import { NATIVE_ANTHROPIC_REPLAY_HOOKS } from "openclaw/plugin-sdk/provider-model-shared"; import { mergeImplicitAnthropicVertexProvider, resolveAnthropicVertexConfigApiKey, @@ -7,9 +7,6 @@ import { } from "./api.js"; const PROVIDER_ID = "anthropic-vertex"; -const NATIVE_ANTHROPIC_REPLAY_HOOKS = buildProviderReplayFamilyHooks({ - family: "native-anthropic-by-model", -}); export default definePluginEntry({ id: PROVIDER_ID, diff --git a/extensions/anthropic/replay-policy.ts b/extensions/anthropic/replay-policy.ts index f79847a9252..251ec8c3bbc 100644 --- a/extensions/anthropic/replay-policy.ts +++ b/extensions/anthropic/replay-policy.ts @@ -1,8 +1,6 @@ -import { buildProviderReplayFamilyHooks } from "openclaw/plugin-sdk/provider-model-shared"; +import { NATIVE_ANTHROPIC_REPLAY_HOOKS } from "openclaw/plugin-sdk/provider-model-shared"; -const { buildReplayPolicy } = buildProviderReplayFamilyHooks({ - family: "native-anthropic-by-model", -}); +const { buildReplayPolicy } = NATIVE_ANTHROPIC_REPLAY_HOOKS; if (!buildReplayPolicy) { throw new Error("Expected native Anthropic replay hooks to expose buildReplayPolicy."); diff --git a/src/plugin-sdk/provider-model-shared.test.ts b/src/plugin-sdk/provider-model-shared.test.ts index 5682bdebb24..2f88ceddd72 100644 --- a/src/plugin-sdk/provider-model-shared.test.ts +++ b/src/plugin-sdk/provider-model-shared.test.ts @@ -1,6 +1,8 @@ import { describe, expect, it } from "vitest"; import { + ANTHROPIC_BY_MODEL_REPLAY_HOOKS, buildProviderReplayFamilyHooks, + NATIVE_ANTHROPIC_REPLAY_HOOKS, OPENAI_COMPATIBLE_REPLAY_HOOKS, PASSTHROUGH_GEMINI_REPLAY_HOOKS, } from "./provider-model-shared.js"; @@ -204,5 +206,28 @@ describe("buildProviderReplayFamilyHooks", () => { includeCamelCase: true, }, }); + + expect( + ANTHROPIC_BY_MODEL_REPLAY_HOOKS.buildReplayPolicy?.({ + provider: "amazon-bedrock", + modelApi: "bedrock-converse-stream", + modelId: "claude-sonnet-4-6", + } as never), + ).toMatchObject({ + validateAnthropicTurns: true, + repairToolUseResultPairing: true, + }); + + expect( + NATIVE_ANTHROPIC_REPLAY_HOOKS.buildReplayPolicy?.({ + provider: "anthropic", + modelApi: "anthropic-messages", + modelId: "claude-sonnet-4-6", + } as never), + ).toMatchObject({ + preserveNativeAnthropicToolUseIds: true, + preserveSignatures: true, + validateAnthropicTurns: true, + }); }); }); diff --git a/src/plugin-sdk/provider-model-shared.ts b/src/plugin-sdk/provider-model-shared.ts index 46e5d612196..f14dff286e7 100644 --- a/src/plugin-sdk/provider-model-shared.ts +++ b/src/plugin-sdk/provider-model-shared.ts @@ -165,6 +165,14 @@ export const OPENAI_COMPATIBLE_REPLAY_HOOKS = buildProviderReplayFamilyHooks({ family: "openai-compatible", }); +export const ANTHROPIC_BY_MODEL_REPLAY_HOOKS = buildProviderReplayFamilyHooks({ + family: "anthropic-by-model", +}); + +export const NATIVE_ANTHROPIC_REPLAY_HOOKS = buildProviderReplayFamilyHooks({ + family: "native-anthropic-by-model", +}); + export const PASSTHROUGH_GEMINI_REPLAY_HOOKS = buildProviderReplayFamilyHooks({ family: "passthrough-gemini", });