




















11import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
22import type { OpenClawConfig } from "../config/types.openclaw.js";
33import { resolveProviderRuntimePlugin } from "../plugins/provider-hook-runtime.js";
4+import type { ProviderRuntimeModel } from "../plugins/provider-runtime-model.types.js";
4556vi.mock("../plugins/provider-hook-runtime.js", async () => {
67const replayHelpers = await vi.importActual<
@@ -229,6 +230,24 @@ describe("resolveTranscriptPolicy", () => {
229230expect(policy.validateAnthropicTurns).toBe(true);
230231}
231232233+function makeOpenAiCompatibleReasoningModel(
234+overrides: Partial<ProviderRuntimeModel> = {},
235+): ProviderRuntimeModel {
236+return {
237+id: "qwen3.6-27b",
238+name: "Qwen3.6 27B",
239+provider: "custom-openai-proxy",
240+api: "openai-completions",
241+baseUrl: "https://example.invalid",
242+reasoning: false,
243+input: ["text"],
244+cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
245+contextWindow: 128_000,
246+maxTokens: 16_384,
247+ ...overrides,
248+};
249+}
250+232251it("enables sanitizeToolCallIds for Anthropic provider", () => {
233252const policy = resolveTranscriptPolicy({
234253provider: "anthropic",
@@ -345,7 +364,7 @@ describe("resolveTranscriptPolicy", () => {
345364expect(policy.validateAnthropicTurns).toBe(true);
346365});
347366348-it("strips historical reasoning for strict OpenAI-compatible providers", () => {
367+it("strips historical reasoning for strict OpenAI-compatible providers by default", () => {
349368const policy = resolveTranscriptPolicy({
350369provider: "custom-openai-proxy",
351370modelId: "qwen3.6-27b",
@@ -361,6 +380,17 @@ describe("resolveTranscriptPolicy", () => {
361380expect(responsesPolicy.dropReasoningFromHistory).toBe(false);
362381});
363382383+it("preserves historical reasoning for strict OpenAI-compatible models with reasoning metadata", () => {
384+const policy = resolveTranscriptPolicy({
385+provider: "custom-openai-proxy",
386+modelId: "qwen3.6-27b",
387+modelApi: "openai-completions",
388+model: makeOpenAiCompatibleReasoningModel({ reasoning: true }),
389+});
390+391+expect(policy.dropReasoningFromHistory).toBe(false);
392+});
393+364394it.each([
365395"kimi-for-coding",
366396"moonshotai/kimi-k2.6",
@@ -488,6 +518,28 @@ describe("resolveTranscriptPolicy", () => {
488518expect(noReasoningPolicy.dropThinkingBlocks).toBe(true);
489519});
490520521+it("does not reuse cached OpenAI-compatible policies across reasoning metadata changes", () => {
522+const config = {} as OpenClawConfig;
523+524+const defaultPolicy = resolveTranscriptPolicy({
525+ config,
526+provider: "custom-openai-proxy",
527+modelId: "qwen3.6-27b",
528+modelApi: "openai-completions",
529+model: makeOpenAiCompatibleReasoningModel(),
530+});
531+const reasoningPolicy = resolveTranscriptPolicy({
532+ config,
533+provider: "custom-openai-proxy",
534+modelId: "qwen3.6-27b",
535+modelApi: "openai-completions",
536+model: makeOpenAiCompatibleReasoningModel({ reasoning: true }),
537+});
538+539+expect(defaultPolicy.dropReasoningFromHistory).toBe(true);
540+expect(reasoningPolicy.dropReasoningFromHistory).toBe(false);
541+});
542+491543it("preserves transport defaults when a runtime plugin has not adopted replay hooks", () => {
492544expectStrictOpenAiCompatibleReplayDefaults("vllm");
493545});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。