mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 12:10:42 +00:00
refactor: keep ollama compat in extension
This commit is contained in:
@@ -10,6 +10,7 @@ vi.mock("openclaw/plugin-sdk/ssrf-runtime", () => ({
|
||||
|
||||
import {
|
||||
buildOllamaChatRequest,
|
||||
createConfiguredOllamaCompatStreamWrapper,
|
||||
createConfiguredOllamaStreamFn,
|
||||
createOllamaStreamFn,
|
||||
convertToOllamaMessages,
|
||||
@@ -57,6 +58,46 @@ describe("buildOllamaChatRequest", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("createConfiguredOllamaCompatStreamWrapper", () => {
|
||||
it("adds Moonshot thinking config for Ollama cloud Kimi compat requests", async () => {
|
||||
let patchedPayload: Record<string, unknown> | undefined;
|
||||
const baseStreamFn = vi.fn((_model, _context, options) => {
|
||||
options?.onPayload?.({ tool_choice: "auto" });
|
||||
return (async function* () {})();
|
||||
});
|
||||
const model = {
|
||||
api: "openai-completions",
|
||||
provider: "ollama",
|
||||
id: "kimi-k2.5:cloud",
|
||||
contextWindow: 262144,
|
||||
};
|
||||
|
||||
const wrapped = createConfiguredOllamaCompatStreamWrapper({
|
||||
provider: "ollama",
|
||||
modelId: "kimi-k2.5:cloud",
|
||||
model,
|
||||
streamFn: baseStreamFn,
|
||||
thinkingLevel: "high",
|
||||
extraParams: {},
|
||||
} as never);
|
||||
|
||||
await wrapped?.(
|
||||
model as never,
|
||||
{ messages: [] } as never,
|
||||
{
|
||||
onPayload: (payload: unknown) => {
|
||||
patchedPayload = payload as Record<string, unknown>;
|
||||
},
|
||||
} as never,
|
||||
);
|
||||
|
||||
expect(patchedPayload).toMatchObject({
|
||||
thinking: { type: "enabled" },
|
||||
options: { num_ctx: 262144 },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("convertToOllamaMessages", () => {
|
||||
it("converts user text messages", () => {
|
||||
const messages = [{ role: "user", content: "hello" }];
|
||||
|
||||
@@ -67,7 +67,6 @@ export function resolveOpenAICompletionsCompatDefaults(
|
||||
endpointClass === "mistral-public" ||
|
||||
knownProviderFamily === "mistral" ||
|
||||
(isDefaultRoute && isDefaultRouteProvider(provider, "chutes"));
|
||||
const isOllamaCompatProvider = provider === "ollama";
|
||||
return {
|
||||
supportsStore:
|
||||
!isNonStandard && knownProviderFamily !== "mistral" && !usesExplicitProxyLikeEndpoint,
|
||||
@@ -78,8 +77,7 @@ export function resolveOpenAICompletionsCompatDefaults(
|
||||
endpointClass !== "xai-native" &&
|
||||
!usesExplicitProxyLikeEndpoint,
|
||||
supportsUsageInStreaming:
|
||||
isOllamaCompatProvider ||
|
||||
(!isNonStandard && (!usesConfiguredNonOpenAIEndpoint || supportsNativeStreamingUsageCompat)),
|
||||
!isNonStandard && (!usesConfiguredNonOpenAIEndpoint || supportsNativeStreamingUsageCompat),
|
||||
maxTokensField: usesMaxTokens ? "max_tokens" : "max_completion_tokens",
|
||||
thinkingFormat: isZai ? "zai" : isOpenRouterLike ? "openrouter" : "openai",
|
||||
visibleReasoningDetailTypes: isOpenRouterLike ? ["response.output_text", "response.text"] : [],
|
||||
|
||||
@@ -712,7 +712,7 @@ describe("provider attribution", () => {
|
||||
|
||||
expect(
|
||||
resolveProviderRequestCapabilities({
|
||||
provider: "ollama",
|
||||
provider: "custom-local",
|
||||
api: "openai-completions",
|
||||
baseUrl: "http://127.0.0.1:11434/v1",
|
||||
capability: "llm",
|
||||
@@ -720,20 +720,7 @@ describe("provider attribution", () => {
|
||||
}),
|
||||
).toMatchObject({
|
||||
endpointClass: "local",
|
||||
supportsNativeStreamingUsageCompat: true,
|
||||
});
|
||||
|
||||
expect(
|
||||
resolveProviderRequestCapabilities({
|
||||
provider: "ollama",
|
||||
api: "openai-completions",
|
||||
baseUrl: "http://127.0.0.1:11434/v1",
|
||||
capability: "llm",
|
||||
transport: "stream",
|
||||
modelId: "kimi-k2.5:cloud",
|
||||
}),
|
||||
).toMatchObject({
|
||||
compatibilityFamily: "moonshot",
|
||||
supportsNativeStreamingUsageCompat: false,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -928,28 +915,6 @@ describe("provider attribution", () => {
|
||||
supportsNativeStreamingUsageCompat: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Ollama OpenAI-compatible completions",
|
||||
input: {
|
||||
provider: "ollama",
|
||||
api: "openai-completions",
|
||||
baseUrl: "http://127.0.0.1:11434/v1",
|
||||
capability: "llm" as const,
|
||||
transport: "stream" as const,
|
||||
},
|
||||
expected: {
|
||||
knownProviderFamily: "ollama",
|
||||
endpointClass: "local",
|
||||
isKnownNativeEndpoint: false,
|
||||
allowsOpenAIServiceTier: false,
|
||||
supportsOpenAIReasoningCompatPayload: false,
|
||||
allowsResponsesStore: false,
|
||||
supportsResponsesStoreField: false,
|
||||
shouldStripResponsesPromptCache: false,
|
||||
allowsAnthropicServiceTier: false,
|
||||
supportsNativeStreamingUsageCompat: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "native Google Gemini api",
|
||||
input: {
|
||||
|
||||
@@ -132,10 +132,6 @@ const OPENAI_RESPONSES_APIS = new Set([
|
||||
const OPENAI_RESPONSES_PROVIDERS = new Set(["openai", "azure-openai", "azure-openai-responses"]);
|
||||
const MOONSHOT_COMPAT_PROVIDERS = new Set(["moonshot", "kimi"]);
|
||||
|
||||
function isOllamaMoonshotCompatModel(modelId: string | null | undefined): boolean {
|
||||
return /^kimi-k2\.5(?::|$)/i.test(modelId?.trim() ?? "");
|
||||
}
|
||||
|
||||
function formatOpenClawUserAgent(version: string): string {
|
||||
return `${OPENCLAW_ATTRIBUTION_ORIGINATOR}/${version}`;
|
||||
}
|
||||
@@ -575,12 +571,7 @@ export function resolveProviderRequestCapabilities(
|
||||
endpointClass === "google-vertex";
|
||||
|
||||
let compatibilityFamily: ProviderRequestCompatibilityFamily | undefined;
|
||||
const isOllamaOpenAICompletions = provider === "ollama" && api === "openai-completions";
|
||||
if (
|
||||
provider &&
|
||||
(MOONSHOT_COMPAT_PROVIDERS.has(provider) ||
|
||||
(provider === "ollama" && isOllamaMoonshotCompatModel(input.modelId)))
|
||||
) {
|
||||
if (provider && MOONSHOT_COMPAT_PROVIDERS.has(provider)) {
|
||||
compatibilityFamily = "moonshot";
|
||||
}
|
||||
|
||||
@@ -638,9 +629,7 @@ export function resolveProviderRequestCapabilities(
|
||||
// Native endpoint class is the real signal here. Users can point a generic
|
||||
// provider key at Moonshot or DashScope and still need streaming usage.
|
||||
supportsNativeStreamingUsageCompat:
|
||||
endpointClass === "moonshot-native" ||
|
||||
endpointClass === "modelstudio-native" ||
|
||||
isOllamaOpenAICompletions,
|
||||
endpointClass === "moonshot-native" || endpointClass === "modelstudio-native",
|
||||
compatibilityFamily,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user