diff --git a/src/agents/simple-completion-runtime.test.ts b/src/agents/simple-completion-runtime.test.ts index 2549ed94ac2..773a4ccc744 100644 --- a/src/agents/simple-completion-runtime.test.ts +++ b/src/agents/simple-completion-runtime.test.ts @@ -91,6 +91,21 @@ beforeEach(() => { hoisted.prepareProviderRuntimeAuthMock.mockResolvedValue(undefined); }); +function expectPreparedModelResult( + result: Awaited>, +): asserts result is Exclude { + expect(result).not.toHaveProperty("error"); + if ("error" in result) { + throw new Error(result.error); + } +} + +function callArg(mock: { mock: { calls: unknown[][] } }, index = 0): T { + const call = mock.mock.calls[index]; + expect(call).toBeDefined(); + return call?.[0] as T; +} + describe("prepareSimpleCompletionModel", () => { it("resolves model auth and sets runtime api key", async () => { hoisted.getApiKeyForModelMock.mockResolvedValueOnce({ @@ -106,18 +121,11 @@ describe("prepareSimpleCompletionModel", () => { agentDir: "/tmp/openclaw-agent", }); - expect(result).toEqual( - expect.objectContaining({ - model: expect.objectContaining({ - provider: "anthropic", - id: "claude-opus-4-6", - }), - auth: expect.objectContaining({ - mode: "api-key", - source: "env:TEST_API_KEY", - }), - }), - ); + expectPreparedModelResult(result); + expect(result.model.provider).toBe("anthropic"); + expect(result.model.id).toBe("claude-opus-4-6"); + expect(result.auth.mode).toBe("api-key"); + expect(result.auth.source).toBe("env:TEST_API_KEY"); expect(hoisted.setRuntimeApiKeyMock).toHaveBeenCalledWith("anthropic", "sk-test"); }); @@ -187,18 +195,13 @@ describe("prepareSimpleCompletionModel", () => { allowMissingApiKeyModes: ["aws-sdk"], }); - expect(result).toEqual( - expect.objectContaining({ - model: expect.objectContaining({ - provider: "amazon-bedrock", - id: "anthropic.claude-sonnet-4-6", - }), - auth: { - source: "aws-sdk default chain", - mode: "aws-sdk", - }, - }), - ); + expectPreparedModelResult(result); + expect(result.model.provider).toBe("amazon-bedrock"); + expect(result.model.id).toBe("anthropic.claude-sonnet-4-6"); + expect(result.auth).toEqual({ + source: "aws-sdk default chain", + mode: "aws-sdk", + }); expect(hoisted.setRuntimeApiKeyMock).not.toHaveBeenCalled(); }); @@ -301,11 +304,7 @@ describe("prepareSimpleCompletionModel", () => { if ("error" in result) { return; } - expect(result.model).toEqual( - expect.objectContaining({ - baseUrl: "https://api.copilot.enterprise.example", - }), - ); + expect(result.model.baseUrl).toBe("https://api.copilot.enterprise.example"); }); it("returns error when getApiKeyForModel throws", async () => { @@ -353,24 +352,24 @@ describe("prepareSimpleCompletionModel", () => { modelId: "chat-local", }); - expect(hoisted.applyLocalNoAuthHeaderOverrideMock).toHaveBeenCalledWith( - expect.objectContaining({ - provider: "local-openai", - id: "chat-local", - }), - expect.objectContaining({ - apiKey: "custom-local", - source: "models.providers.local-openai (synthetic local key)", - mode: "api-key", - }), + const overrideCall = hoisted.applyLocalNoAuthHeaderOverrideMock.mock.calls[0]; + expect((overrideCall?.[0] as { provider?: string; id?: string } | undefined)?.provider).toBe( + "local-openai", ); - expect(result).toEqual( - expect.objectContaining({ - model: expect.objectContaining({ - headers: expect.objectContaining({ Authorization: null }), - }), - }), + expect((overrideCall?.[0] as { provider?: string; id?: string } | undefined)?.id).toBe( + "chat-local", ); + expect((overrideCall?.[1] as { apiKey?: string; source?: string; mode?: string })?.apiKey).toBe( + "custom-local", + ); + expect((overrideCall?.[1] as { apiKey?: string; source?: string; mode?: string })?.source).toBe( + "models.providers.local-openai (synthetic local key)", + ); + expect((overrideCall?.[1] as { apiKey?: string; source?: string; mode?: string })?.mode).toBe( + "api-key", + ); + expectPreparedModelResult(result); + expect(result.model.headers?.Authorization).toBeNull(); }); it("applies provider runtime auth before storing simple-completion credentials", async () => { @@ -403,32 +402,29 @@ describe("prepareSimpleCompletionModel", () => { agentDir: "/tmp/openclaw-agent", }); - expect(hoisted.prepareProviderRuntimeAuthMock).toHaveBeenCalledWith( - expect.objectContaining({ - provider: "amazon-bedrock-mantle", - workspaceDir: "/tmp/openclaw-agent", - context: expect.objectContaining({ - apiKey: "__amazon_bedrock_mantle_iam__", - authMode: "api-key", - modelId: "anthropic.claude-opus-4-7", - profileId: "mantle", - }), - }), - ); + const runtimeAuthInput = callArg<{ + provider?: string; + workspaceDir?: string; + context?: { + apiKey?: string; + authMode?: string; + modelId?: string; + profileId?: string; + }; + }>(hoisted.prepareProviderRuntimeAuthMock); + expect(runtimeAuthInput.provider).toBe("amazon-bedrock-mantle"); + expect(runtimeAuthInput.workspaceDir).toBe("/tmp/openclaw-agent"); + expect(runtimeAuthInput.context?.apiKey).toBe("__amazon_bedrock_mantle_iam__"); + expect(runtimeAuthInput.context?.authMode).toBe("api-key"); + expect(runtimeAuthInput.context?.modelId).toBe("anthropic.claude-opus-4-7"); + expect(runtimeAuthInput.context?.profileId).toBe("mantle"); expect(hoisted.setRuntimeApiKeyMock).toHaveBeenCalledWith( "amazon-bedrock-mantle", "bedrock-runtime-token", ); - expect(result).toEqual( - expect.objectContaining({ - model: expect.objectContaining({ - baseUrl: "https://bedrock-mantle.us-east-1.api.aws/anthropic", - }), - auth: expect.objectContaining({ - apiKey: "bedrock-runtime-token", - }), - }), - ); + expectPreparedModelResult(result); + expect(result.model.baseUrl).toBe("https://bedrock-mantle.us-east-1.api.aws/anthropic"); + expect(result.auth.apiKey).toBe("bedrock-runtime-token"); }); it("can skip Pi model/auth discovery for config-scoped one-shot completions", async () => {