






















@@ -47,21 +47,42 @@ function createModelRegistry(models: ProviderRuntimeModel[]) {
4747};
4848}
494950+function requireRecord(value: unknown, label: string): Record<string, unknown> {
51+expect(value, label).toBeTypeOf("object");
52+expect(value, label).not.toBeNull();
53+return value as Record<string, unknown>;
54+}
55+56+function expectFields(value: unknown, fields: Record<string, unknown>) {
57+const record = requireRecord(value, "record");
58+for (const [key, expected] of Object.entries(fields)) {
59+expect(record[key]).toEqual(expected);
60+}
61+}
62+63+function expectModelParams(models: unknown, modelId: string, params: Record<string, unknown>) {
64+const model = requireRecord(requireRecord(models, "models")[modelId], modelId);
65+expectFields(model.params, params);
66+}
67+68+function levelIds(profile: unknown): Array<unknown> {
69+const levels = requireRecord(profile, "thinking profile").levels;
70+expect(Array.isArray(levels), "thinking levels").toBe(true);
71+return (levels as Array<{ id?: unknown }>).map((level) => level.id);
72+}
73+5074describe("anthropic provider replay hooks", () => {
5175it("registers the claude-cli backend", () => {
5276const captured = capturePluginRegistration({ register: anthropicPlugin.register });
537754-expect(captured.cliBackends).toContainEqual(
55-expect.objectContaining({
56-id: "claude-cli",
57-bundleMcp: true,
58-config: expect.objectContaining({
59-command: "claude",
60-modelArg: "--model",
61-sessionArg: "--session-id",
62-}),
63-}),
64-);
78+const backend = captured.cliBackends.find((entry) => entry.id === "claude-cli");
79+expect(backend).toBeDefined();
80+expect(backend?.bundleMcp).toBe(true);
81+expectFields(backend?.config, {
82+command: "claude",
83+modelArg: "--model",
84+sessionArg: "--session-id",
85+});
6586});
66876788it("owns native reasoning output mode for Claude transports", async () => {
@@ -101,30 +122,32 @@ describe("anthropic provider replay hooks", () => {
101122const provider = await registerSingleProviderPlugin(anthropicPlugin);
102123103124expect(
104-provider.normalizeConfig?.({
105-provider: "anthropic",
106-providerConfig: {
107-models: [{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" }],
108-},
109-} as never),
110-).toMatchObject({
111-api: "anthropic-messages",
112-});
125+requireRecord(
126+provider.normalizeConfig?.({
127+provider: "anthropic",
128+providerConfig: {
129+models: [{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" }],
130+},
131+} as never),
132+"normalized config",
133+).api,
134+).toBe("anthropic-messages");
113135});
114136115137it("defaults Claude CLI provider api through plugin config normalization", async () => {
116138const provider = await registerSingleProviderPlugin(anthropicPlugin);
117139118140expect(
119-provider.normalizeConfig?.({
120-provider: "claude-cli",
121-providerConfig: {
122-models: [{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" }],
123-},
124-} as never),
125-).toMatchObject({
126-api: "anthropic-messages",
127-});
141+requireRecord(
142+provider.normalizeConfig?.({
143+provider: "claude-cli",
144+providerConfig: {
145+models: [{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" }],
146+},
147+} as never),
148+"normalized config",
149+).api,
150+).toBe("anthropic-messages");
128151});
129152130153it("does not default non-Anthropic provider api through plugin config normalization", async () => {
@@ -162,11 +185,11 @@ describe("anthropic provider replay hooks", () => {
162185},
163186} as never);
164187165-expect(next?.agents?.defaults?.contextPruning).toMatchObject({
188+expectFields(next?.agents?.defaults?.contextPruning, {
166189mode: "cache-ttl",
167190ttl: "1h",
168191});
169-expect(next?.agents?.defaults?.heartbeat).toMatchObject({
192+expectFields(next?.agents?.defaults?.heartbeat, {
170193every: "30m",
171194});
172195expect(
@@ -197,10 +220,9 @@ describe("anthropic provider replay hooks", () => {
197220},
198221} as never);
199222200-expect(next?.agents?.defaults?.models).toMatchObject({
201-"anthropic/claude-sonnet-4-6": { params: { cacheRetention: "short" } },
202-"anthropic/claude-haiku-4-5": { params: { cacheRetention: "short" } },
203-});
223+const models = next?.agents?.defaults?.models;
224+expectModelParams(models, "anthropic/claude-sonnet-4-6", { cacheRetention: "short" });
225+expectModelParams(models, "anthropic/claude-haiku-4-5", { cacheRetention: "short" });
204226});
205227206228it("backfills Claude CLI allowlist defaults through plugin hooks for older configs", async () => {
@@ -227,17 +249,20 @@ describe("anthropic provider replay hooks", () => {
227249},
228250} as never);
229251230-expect(next?.agents?.defaults?.heartbeat).toMatchObject({
252+expectFields(next?.agents?.defaults?.heartbeat, {
231253every: "1h",
232254});
233-expect(next?.agents?.defaults?.models).toMatchObject({
234-"anthropic/claude-opus-4-7": {},
235-"anthropic/claude-sonnet-4-6": {},
236-"anthropic/claude-opus-4-6": {},
237-"anthropic/claude-opus-4-5": {},
238-"anthropic/claude-sonnet-4-5": {},
239-"anthropic/claude-haiku-4-5": {},
240-});
255+const models = requireRecord(next?.agents?.defaults?.models, "models");
256+for (const modelId of [
257+"anthropic/claude-opus-4-7",
258+"anthropic/claude-sonnet-4-6",
259+"anthropic/claude-opus-4-6",
260+"anthropic/claude-opus-4-5",
261+"anthropic/claude-sonnet-4-5",
262+"anthropic/claude-haiku-4-5",
263+]) {
264+expect(models[modelId]).toEqual({});
265+}
241266});
242267243268it("resolves explicit claude-opus-4-7 refs from the 4.6 template family", async () => {
@@ -260,32 +285,29 @@ describe("anthropic provider replay hooks", () => {
260285]),
261286} as ProviderResolveDynamicModelContext);
262287263-expect(resolved).toMatchObject({
288+expectFields(resolved, {
264289provider: "anthropic",
265290id: "claude-opus-4-7",
266291api: "anthropic-messages",
267292reasoning: true,
268293contextWindow: 1_048_576,
269294contextTokens: 1_048_576,
270295});
271-expect(
272-provider.resolveThinkingProfile?.({
273-provider: "anthropic",
274-modelId: "claude-opus-4-7",
275-} as never),
276-).toMatchObject({
277-levels: expect.arrayContaining([{ id: "xhigh" }, { id: "adaptive" }, { id: "max" }]),
278-defaultLevel: "off",
279-});
280-expect(
281-provider.resolveThinkingProfile?.({
282-provider: "anthropic",
283-modelId: "claude-opus-4-6",
284-} as never),
285-).toMatchObject({
286-levels: expect.arrayContaining([{ id: "adaptive" }]),
287-defaultLevel: "adaptive",
288-});
296+const opus47Profile = provider.resolveThinkingProfile?.({
297+provider: "anthropic",
298+modelId: "claude-opus-4-7",
299+} as never);
300+const opus47LevelIds = levelIds(opus47Profile);
301+expect(opus47LevelIds).toContain("xhigh");
302+expect(opus47LevelIds).toContain("adaptive");
303+expect(opus47LevelIds).toContain("max");
304+expect(requireRecord(opus47Profile, "opus 4.7 thinking profile").defaultLevel).toBe("off");
305+const opus46Profile = provider.resolveThinkingProfile?.({
306+provider: "anthropic",
307+modelId: "claude-opus-4-6",
308+} as never);
309+expect(levelIds(opus46Profile)).toContain("adaptive");
310+expect(requireRecord(opus46Profile, "opus 4.6 thinking profile").defaultLevel).toBe("adaptive");
289311expect(
290312provider
291313.resolveThinkingProfile?.({
@@ -327,7 +349,7 @@ describe("anthropic provider replay hooks", () => {
327349["anthropic", "claude-opus-4-7"],
328350["claude-cli", "claude-opus-4.7-20260219"],
329351] as const) {
330-expect(
352+expectFields(
331353provider.normalizeResolvedModel?.({
332354provider: runtimeProvider,
333355 modelId,
@@ -344,10 +366,11 @@ describe("anthropic provider replay hooks", () => {
344366maxTokens: 32_000,
345367},
346368} as never),
347-).toMatchObject({
348-contextWindow: 1_048_576,
349-contextTokens: 1_048_576,
350-});
369+{
370+contextWindow: 1_048_576,
371+contextTokens: 1_048_576,
372+},
373+);
351374}
352375});
353376此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。