refactor: move bundled replay policy ownership into plugins (#60452)

* refactor: move bundled replay policy ownership into plugins

* test: preserve replay fallback until providers adopt hooks

* test: cover response replay branches for ollama and zai

---------

Co-authored-by: Shakker <shakkerdroid@gmail.com>
This commit is contained in:
Josh Lehman
2026-04-03 11:08:10 -07:00
committed by GitHub
parent 7fb58afb41
commit c52df32878
12 changed files with 444 additions and 8 deletions

View File

@@ -11,16 +11,27 @@ vi.mock("../plugins/provider-runtime.js", () => ({
"kilocode",
"kimi",
"kimi-code",
"minimax",
"minimax-portal",
"mistral",
"moonshot",
"openai",
"openai-codex",
"opencode",
"opencode-go",
"ollama",
"openrouter",
"sglang",
"vllm",
"xai",
"zai",
].includes(provider)
) {
return undefined;
}
if (provider === "sglang" || provider === "vllm") {
return {};
}
return {
buildReplayPolicy: (context?: { modelId?: string; modelApi?: string }) => {
const modelId = context?.modelId?.toLowerCase() ?? "";
@@ -37,6 +48,38 @@ vi.mock("../plugins/provider-runtime.js", () => ({
allowSyntheticToolResults: true,
...(modelId.includes("claude") ? { dropThinkingBlocks: true } : {}),
};
case "minimax":
case "minimax-portal":
return context?.modelApi === "openai-completions"
? {
sanitizeToolCallIds: true,
toolCallIdMode: "strict",
applyAssistantFirstOrderingFix: true,
validateGeminiTurns: true,
validateAnthropicTurns: true,
}
: {
sanitizeMode: "full",
sanitizeToolCallIds: true,
toolCallIdMode: "strict",
preserveSignatures: true,
repairToolUseResultPairing: true,
validateAnthropicTurns: true,
allowSyntheticToolResults: true,
...(modelId.includes("claude") ? { dropThinkingBlocks: true } : {}),
};
case "moonshot":
case "ollama":
case "zai":
return context?.modelApi === "openai-completions"
? {
sanitizeToolCallIds: true,
toolCallIdMode: "strict",
applyAssistantFirstOrderingFix: true,
validateGeminiTurns: true,
validateAnthropicTurns: true,
}
: undefined;
case "google":
return {
sanitizeMode: "full",
@@ -88,6 +131,28 @@ vi.mock("../plugins/provider-runtime.js", () => ({
}
: {}),
};
case "xai":
if (
context?.modelApi === "openai-completions" ||
context?.modelApi === "openai-responses"
) {
return {
sanitizeToolCallIds: true,
toolCallIdMode: "strict",
...(context.modelApi === "openai-completions"
? {
applyAssistantFirstOrderingFix: true,
validateGeminiTurns: true,
validateAnthropicTurns: true,
}
: {
applyAssistantFirstOrderingFix: false,
validateGeminiTurns: false,
validateAnthropicTurns: false,
}),
};
}
return undefined;
case "kilocode":
return modelId.includes("gemini")
? {
@@ -183,10 +248,10 @@ describe("resolveTranscriptPolicy", () => {
expect(policy.validateAnthropicTurns).toBe(true);
});
it("falls back to transport defaults when a plugin replay hook returns undefined", () => {
it("falls back to unowned transport defaults when no owning plugin exists", () => {
const policy = resolveTranscriptPolicy({
provider: "kilocode",
modelId: "kilocode-default",
provider: "custom-openai-proxy",
modelId: "demo-model",
modelApi: "openai-completions",
});
@@ -197,6 +262,49 @@ describe("resolveTranscriptPolicy", () => {
expect(policy.validateAnthropicTurns).toBe(true);
});
it("preserves transport defaults when a runtime plugin has not adopted replay hooks", () => {
const policy = resolveTranscriptPolicy({
provider: "vllm",
modelId: "demo-model",
modelApi: "openai-completions",
});
expect(policy.sanitizeToolCallIds).toBe(true);
expect(policy.toolCallIdMode).toBe("strict");
expect(policy.applyGoogleTurnOrdering).toBe(true);
expect(policy.validateGeminiTurns).toBe(true);
expect(policy.validateAnthropicTurns).toBe(true);
});
it("uses provider-owned Anthropic replay policy for MiniMax transports", () => {
const policy = resolveTranscriptPolicy({
provider: "minimax",
modelId: "MiniMax-M2.7",
modelApi: "anthropic-messages",
});
expect(policy.sanitizeMode).toBe("full");
expect(policy.sanitizeToolCallIds).toBe(true);
expect(policy.preserveSignatures).toBe(true);
expect(policy.validateAnthropicTurns).toBe(true);
});
it("uses provider-owned OpenAI-compatible replay policy for MiniMax portal completions", () => {
const policy = resolveTranscriptPolicy({
provider: "minimax-portal",
modelId: "MiniMax-M2.7",
modelApi: "openai-completions",
});
expect(policy.sanitizeMode).toBe("images-only");
expect(policy.sanitizeToolCallIds).toBe(true);
expect(policy.toolCallIdMode).toBe("strict");
expect(policy.preserveSignatures).toBe(false);
expect(policy.applyGoogleTurnOrdering).toBe(true);
expect(policy.validateGeminiTurns).toBe(true);
expect(policy.validateAnthropicTurns).toBe(true);
});
it("enables Anthropic-compatible policies for Bedrock provider", () => {
const policy = resolveTranscriptPolicy({
provider: "amazon-bedrock",

View File

@@ -44,7 +44,14 @@ function isAnthropicApi(modelApi?: string | null): boolean {
return modelApi === "anthropic-messages" || modelApi === "bedrock-converse-stream";
}
function buildTransportReplayFallback(params: {
/**
* Provides a narrow replay-policy fallback for providers that do not have an
* owning runtime plugin.
*
* This exists to preserve generic custom-provider behavior. Bundled providers
* should express replay ownership through `buildReplayPolicy` instead.
*/
function buildUnownedProviderTransportReplayFallback(params: {
modelApi?: string | null;
modelId?: string | null;
}): ProviderReplayPolicy | undefined {
@@ -162,13 +169,16 @@ export function resolveTranscriptPolicy(params: {
model: params.model,
};
const pluginPolicy = runtimePlugin?.buildReplayPolicy?.(context);
if (pluginPolicy != null) {
return mergeTranscriptPolicy(pluginPolicy);
// Once a provider adopts the replay-policy hook, replay policy should come
// from the plugin, not from transport-family defaults in core.
const buildReplayPolicy = runtimePlugin?.buildReplayPolicy;
if (buildReplayPolicy) {
const pluginPolicy = buildReplayPolicy(context);
return mergeTranscriptPolicy(pluginPolicy ?? undefined);
}
return mergeTranscriptPolicy(
buildTransportReplayFallback({
buildUnownedProviderTransportReplayFallback({
modelApi: params.modelApi,
modelId: params.modelId,
}),