






























@@ -8,6 +8,28 @@ import {
88resolveClaudeThinkingProfile,
99} from "./provider-model-shared.js";
101011+function expectFields(value: unknown, expected: Record<string, unknown>): void {
12+expect(value).toBeTypeOf("object");
13+expect(value).not.toBeNull();
14+const record = value as Record<string, unknown>;
15+for (const [key, expectedValue] of Object.entries(expected)) {
16+expect(record[key], key).toEqual(expectedValue);
17+}
18+}
19+20+function readLevelIds(profile: unknown): string[] {
21+const levels = (profile as { levels?: Array<{ id?: unknown }> } | undefined)?.levels;
22+expect(Array.isArray(levels)).toBe(true);
23+return (levels ?? []).map((level) => String(level.id));
24+}
25+26+function expectLevelIdsInclude(profile: unknown, expectedIds: readonly string[]): void {
27+const ids = readLevelIds(profile);
28+for (const id of expectedIds) {
29+expect(ids.includes(id), `level ${id}`).toBe(true);
30+}
31+}
32+1133describe("buildProviderReplayFamilyHooks", () => {
1234it("covers the replay family matrix", () => {
1335const cases = [
@@ -36,7 +58,6 @@ describe("buildProviderReplayFamilyHooks", () => {
3658},
3759match: {
3860validateAnthropicTurns: true,
39-// Sonnet 4.6 preserves thinking blocks (no dropThinkingBlocks)
4061},
4162absent: ["dropThinkingBlocks"],
4263hasSanitizeReplayHistory: false,
@@ -106,7 +127,6 @@ describe("buildProviderReplayFamilyHooks", () => {
106127},
107128match: {
108129validateAnthropicTurns: true,
109-// Sonnet 4.6 preserves thinking blocks even with flag set
110130},
111131absent: ["dropThinkingBlocks"],
112132hasSanitizeReplayHistory: false,
@@ -125,7 +145,7 @@ describe("buildProviderReplayFamilyHooks", () => {
125145);
126146127147const policy = hooks.buildReplayPolicy?.(testCase.ctx as never);
128-expect(policy).toMatchObject(testCase.match);
148+expectFields(policy, testCase.match);
129149if ((testCase as { absent?: string[] }).absent) {
130150for (const key of (testCase as { absent: string[] }).absent) {
131151expect(policy).not.toHaveProperty(key);
@@ -160,7 +180,7 @@ describe("buildProviderReplayFamilyHooks", () => {
160180},
161181} as never);
162182163-expect(sanitized?.[0]).toMatchObject({
183+expectFields(sanitized?.[0], {
164184role: "user",
165185content: "(session bootstrap)",
166186});
@@ -181,18 +201,19 @@ describe("buildProviderReplayFamilyHooks", () => {
181201});
182202183203it("exposes canonical replay hooks for reused provider families", () => {
184-expect(
204+expectFields(
185205OPENAI_COMPATIBLE_REPLAY_HOOKS.buildReplayPolicy?.({
186206provider: "xai",
187207modelApi: "openai-completions",
188208modelId: "google/gemma-4-26b-a4b-it",
189209} as never),
190-).toMatchObject({
191-sanitizeToolCallIds: true,
192-applyAssistantFirstOrderingFix: true,
193-validateGeminiTurns: true,
194-dropReasoningFromHistory: true,
195-});
210+{
211+sanitizeToolCallIds: true,
212+applyAssistantFirstOrderingFix: true,
213+validateGeminiTurns: true,
214+dropReasoningFromHistory: true,
215+},
216+);
196217197218const nativeIdsHooks = buildProviderReplayFamilyHooks({
198219family: "openai-compatible",
@@ -204,74 +225,80 @@ describe("buildProviderReplayFamilyHooks", () => {
204225modelApi: "openai-completions",
205226modelId: "kimi-k2.6",
206227} as never);
207-expect(nativeIdsPolicy).toMatchObject({
228+expectFields(nativeIdsPolicy, {
208229applyAssistantFirstOrderingFix: true,
209230validateGeminiTurns: true,
210231validateAnthropicTurns: true,
211232});
212233expect(nativeIdsPolicy).not.toHaveProperty("sanitizeToolCallIds");
213234expect(nativeIdsPolicy).not.toHaveProperty("toolCallIdMode");
214235215-expect(
236+expectFields(
216237PASSTHROUGH_GEMINI_REPLAY_HOOKS.buildReplayPolicy?.({
217238provider: "openrouter",
218239modelApi: "openai-completions",
219240modelId: "gemini-2.5-pro",
220241} as never),
221-).toMatchObject({
222-applyAssistantFirstOrderingFix: false,
223-validateGeminiTurns: false,
224-validateAnthropicTurns: false,
225-sanitizeThoughtSignatures: {
226-allowBase64Only: true,
227-includeCamelCase: true,
242+{
243+applyAssistantFirstOrderingFix: false,
244+validateGeminiTurns: false,
245+validateAnthropicTurns: false,
246+sanitizeThoughtSignatures: {
247+allowBase64Only: true,
248+includeCamelCase: true,
249+},
228250},
229-});
251+);
230252231-expect(
253+expectFields(
232254ANTHROPIC_BY_MODEL_REPLAY_HOOKS.buildReplayPolicy?.({
233255provider: "amazon-bedrock",
234256modelApi: "bedrock-converse-stream",
235257modelId: "claude-sonnet-4-6",
236258} as never),
237-).toMatchObject({
238-validateAnthropicTurns: true,
239-repairToolUseResultPairing: true,
240-});
259+{
260+validateAnthropicTurns: true,
261+repairToolUseResultPairing: true,
262+},
263+);
241264242-expect(
265+expectFields(
243266NATIVE_ANTHROPIC_REPLAY_HOOKS.buildReplayPolicy?.({
244267provider: "anthropic",
245268modelApi: "anthropic-messages",
246269modelId: "claude-sonnet-4-6",
247270} as never),
248-).toMatchObject({
249-preserveNativeAnthropicToolUseIds: true,
250-preserveSignatures: true,
251-validateAnthropicTurns: true,
252-});
271+{
272+preserveNativeAnthropicToolUseIds: true,
273+preserveSignatures: true,
274+validateAnthropicTurns: true,
275+},
276+);
253277});
254278});
255279256280describe("resolveClaudeThinkingProfile", () => {
257281it("exposes Opus 4.7 thinking levels for direct and proxied Claude providers", () => {
258-expect(resolveClaudeThinkingProfile("claude-opus-4-7")).toMatchObject({
259- levels: expect.arrayContaining([{ id: "xhigh" }, { id: "adaptive" }, { id: "max" }]),
282+const directProfile = resolveClaudeThinkingProfile("claude-opus-4-7");
283+expectFields(directProfile, {
260284defaultLevel: "off",
261285});
262-expect(resolveClaudeThinkingProfile("claude-opus-4.7-20260219")).toMatchObject({
263-levels: expect.arrayContaining([{ id: "xhigh" }, { id: "adaptive" }, { id: "max" }]),
286+expectLevelIdsInclude(directProfile, ["xhigh", "adaptive", "max"]);
287+288+const proxiedProfile = resolveClaudeThinkingProfile("claude-opus-4.7-20260219");
289+expectFields(proxiedProfile, {
264290defaultLevel: "off",
265291});
292+expectLevelIdsInclude(proxiedProfile, ["xhigh", "adaptive", "max"]);
266293});
267294268295it("keeps adaptive-only Claude variants from advertising xhigh or max", () => {
269296const profile = resolveClaudeThinkingProfile("claude-sonnet-4-6");
270297271-expect(profile).toMatchObject({
272-levels: expect.arrayContaining([{ id: "adaptive" }]),
298+expectFields(profile, {
273299defaultLevel: "adaptive",
274300});
301+expectLevelIdsInclude(profile, ["adaptive"]);
275302const fixedBudgetLevels = profile.levels.filter(
276303(level) => level.id === "xhigh" || level.id === "max",
277304);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。