
























@@ -2,13 +2,15 @@
22import type { MemoryEmbeddingProviderCreateOptions } from "openclaw/plugin-sdk/memory-core-host-engine-embeddings";
33import { beforeEach, describe, expect, it, vi } from "vitest";
445+const DEFAULT_MOCK_CLIENT = {
6+baseUrl: "https://embeddings.example/v1",
7+headers: { Authorization: "Bearer test" },
8+model: "text-embedding-3-small",
9+};
10+511const mocks = vi.hoisted(() => ({
612fetchRemoteEmbeddingVectors: vi.fn(async () => [[1, 0]]),
7-resolveRemoteEmbeddingClient: vi.fn(async () => ({
8-baseUrl: "https://embeddings.example/v1",
9-headers: { Authorization: "Bearer test" },
10-model: "text-embedding-3-small",
11-})),
13+resolveRemoteEmbeddingClient: vi.fn(async () => ({ ...DEFAULT_MOCK_CLIENT })),
1214}));
13151416vi.mock("openclaw/plugin-sdk/memory-core-host-engine-embeddings", () => ({
@@ -120,4 +122,93 @@ describe("OpenAI embedding provider", () => {
120122}),
121123);
122124});
125+126+// --- openai/ prefix preservation ---
127+128+it("strips openai/ prefix when using native OpenAI API base URL", async () => {
129+mocks.resolveRemoteEmbeddingClient.mockResolvedValueOnce({
130+ ...DEFAULT_MOCK_CLIENT,
131+baseUrl: "https://api.openai.com/v1",
132+model: "text-embedding-3-small",
133+});
134+135+const { provider } = await createOpenAiEmbeddingProvider(
136+createOptions({ model: "openai/text-embedding-3-small" }),
137+);
138+139+expect(provider.model).toBe("text-embedding-3-small");
140+});
141+142+it("strips openai/ prefix for semantically native URLs (uppercase hostname)", async () => {
143+mocks.resolveRemoteEmbeddingClient.mockResolvedValueOnce({
144+ ...DEFAULT_MOCK_CLIENT,
145+baseUrl: "https://API.OPENAI.COM/v1",
146+model: "text-embedding-3-small",
147+});
148+149+const { provider } = await createOpenAiEmbeddingProvider(
150+createOptions({ model: "openai/text-embedding-3-small" }),
151+);
152+153+expect(provider.model).toBe("text-embedding-3-small");
154+});
155+156+it("preserves openai/ prefix for non-native OpenAI base URLs", async () => {
157+mocks.resolveRemoteEmbeddingClient.mockResolvedValueOnce({
158+ ...DEFAULT_MOCK_CLIENT,
159+baseUrl: "https://router.requesty.ai/v1",
160+model: "text-embedding-3-small",
161+});
162+163+const { provider } = await createOpenAiEmbeddingProvider(
164+createOptions({ model: "openai/text-embedding-3-small" }),
165+);
166+167+expect(provider.model).toBe("openai/text-embedding-3-small");
168+});
169+170+it("provides maxInputTokens for qualified model with non-native base URL", async () => {
171+mocks.resolveRemoteEmbeddingClient.mockResolvedValueOnce({
172+ ...DEFAULT_MOCK_CLIENT,
173+baseUrl: "https://router.requesty.ai/v1",
174+model: "text-embedding-3-small",
175+});
176+177+const { provider } = await createOpenAiEmbeddingProvider(
178+createOptions({ model: "openai/text-embedding-3-small" }),
179+);
180+181+expect(provider.maxInputTokens).toBe(8192);
182+});
183+184+it("preserves openai/ prefix in embedding request body for non-native base URLs", async () => {
185+mocks.resolveRemoteEmbeddingClient.mockResolvedValueOnce({
186+ ...DEFAULT_MOCK_CLIENT,
187+baseUrl: "https://router.requesty.ai/v1",
188+model: "text-embedding-3-small",
189+});
190+191+const { provider } = await createOpenAiEmbeddingProvider(
192+createOptions({
193+model: "openai/text-embedding-3-small",
194+inputType: "query",
195+}),
196+);
197+198+await provider.embedQuery("test");
199+200+expect(mocks.fetchRemoteEmbeddingVectors).toHaveBeenCalledWith({
201+url: "https://router.requesty.ai/v1/embeddings",
202+headers: { Authorization: "Bearer test" },
203+ssrfPolicy: undefined,
204+fetchImpl: undefined,
205+signal: undefined,
206+body: {
207+model: "openai/text-embedding-3-small",
208+input: ["test"],
209+input_type: "query",
210+},
211+errorPrefix: "openai embeddings failed",
212+});
213+});
123214});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。