mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-11 12:58:34 +00:00
fix(deepseek): backfill v4 reasoning for proxy models
This commit is contained in:
@@ -61,6 +61,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Channels/iMessage: wire `action: "reply"` attachments through `imsg send-rich --file` when the installed imsg build advertises that capability (probed once via `imsg send-rich --help` and cached on the private-API status). Reply now hydrates `media`/`mediaUrl`/`fileUrl`/`mediaUrls[0]`/`filePath`/`path`/base64 `buffer`+`filename` through the shared outbound resolver, stages buffers via the existing `withTempFile` helper, rejects `http(s)://` URL attachments with a targeted error pointing callers at `send`'s full attachment-resolver pipeline, and falls back to the explicit `imsg#114 not landed yet` error on older imsg builds. Depends on the upstream `openclaw/imsg#114` capability landing in an installable release; until then the new path stays gated and users see the same explicit fallback `#79822` introduced. (#79864) Thanks @omarshahine.
|
||||
- Telegram: preserve the first-preview debounce while appending true partial-stream deltas, so edited draft previews no longer duplicate earlier text when providers emit incremental output. (#80045) Thanks @TurboTheTurtle.
|
||||
- Volcengine/Kimi: strip provider-unsupported tool schema length and item constraint keywords for direct and coding-plan models so hosted Kimi runs do not reject message tools with `minLength`. Fixes #38817.
|
||||
- DeepSeek: backfill V4 `reasoning_content` replay fields for unowned OpenAI-compatible proxy providers, preventing follow-up request failures outside the bundled DeepSeek and OpenRouter routes. Fixes #79608.
|
||||
|
||||
## 2026.5.9
|
||||
|
||||
|
||||
@@ -678,6 +678,33 @@ describe("applyExtraParamsToAgent", () => {
|
||||
expect(payloads[0]?.thinking).toEqual({ type: "disabled" });
|
||||
});
|
||||
|
||||
it("fills DeepSeek V4 reasoning_content for unowned OpenAI-compatible proxy models", () => {
|
||||
const payload = runResponsesPayloadMutationCase({
|
||||
applyProvider: "opencode",
|
||||
applyModelId: "deepseek-v4-pro",
|
||||
thinkingLevel: "high",
|
||||
model: {
|
||||
api: "openai-completions",
|
||||
provider: "opencode",
|
||||
id: "deepseek-v4-pro",
|
||||
} as Model<"openai-completions">,
|
||||
payload: {
|
||||
messages: [
|
||||
{ role: "user", content: "continue" },
|
||||
{ role: "assistant", content: "I used a tool" },
|
||||
{ role: "tool", content: "ok" },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const messages = payload.messages as Array<Record<string, unknown>>;
|
||||
expect(payload.thinking).toEqual({ type: "enabled" });
|
||||
expect(payload.reasoning_effort).toBe("high");
|
||||
expect(messages[0]).not.toHaveProperty("reasoning_content");
|
||||
expect(messages[1]).toHaveProperty("reasoning_content", "");
|
||||
expect(messages[2]).not.toHaveProperty("reasoning_content");
|
||||
});
|
||||
|
||||
it("strips xai Responses reasoning payload fields", () => {
|
||||
const payload = runResponsesPayloadMutationCase({
|
||||
applyProvider: "xai",
|
||||
|
||||
@@ -4,6 +4,7 @@ import { streamSimple } from "@mariozechner/pi-ai";
|
||||
import type { SettingsManager } from "@mariozechner/pi-coding-agent";
|
||||
import type { ThinkLevel } from "../../auto-reply/thinking.js";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import { createDeepSeekV4OpenAICompatibleThinkingWrapper } from "../../plugin-sdk/provider-stream-shared.js";
|
||||
import {
|
||||
prepareProviderExtraParams as prepareProviderExtraParamsRuntime,
|
||||
type ProviderRuntimePluginHandle,
|
||||
@@ -689,6 +690,12 @@ function applyPostPluginStreamWrappers(
|
||||
ctx.agent.streamFn = createOpenAICompletionsToolsCompatWrapper(ctx.agent.streamFn);
|
||||
|
||||
if (!ctx.providerWrapperHandled) {
|
||||
ctx.agent.streamFn = createDeepSeekV4OpenAICompatibleThinkingWrapper({
|
||||
baseStreamFn: ctx.agent.streamFn,
|
||||
thinkingLevel: ctx.thinkingLevel,
|
||||
shouldPatchModel: isDeepSeekV4OpenAICompatibleModel,
|
||||
});
|
||||
|
||||
// Guard Google-family payloads against invalid negative thinking budgets
|
||||
// emitted by upstream model-ID heuristics for Gemini 3.1 variants.
|
||||
ctx.agent.streamFn = createGoogleThinkingPayloadWrapper(ctx.agent.streamFn, ctx.thinkingLevel);
|
||||
@@ -752,6 +759,22 @@ function applyPostPluginStreamWrappers(
|
||||
log.warn(`ignoring invalid parallel_tool_calls param: ${summary}`);
|
||||
}
|
||||
|
||||
function normalizeDeepSeekV4CandidateId(modelId: unknown): string | undefined {
|
||||
if (typeof modelId !== "string") {
|
||||
return undefined;
|
||||
}
|
||||
const withoutSuffix = modelId.trim().toLowerCase().split(":", 1)[0];
|
||||
return withoutSuffix.split("/").pop();
|
||||
}
|
||||
|
||||
function isDeepSeekV4OpenAICompatibleModel(model: Parameters<StreamFn>[0]): boolean {
|
||||
const normalizedModelId = normalizeDeepSeekV4CandidateId(model.id);
|
||||
return (
|
||||
model.api === "openai-completions" &&
|
||||
(normalizedModelId === "deepseek-v4-flash" || normalizedModelId === "deepseek-v4-pro")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply extra params (like temperature) to an agent's streamFn.
|
||||
* Also applies verified provider-specific request wrappers, such as OpenRouter attribution.
|
||||
|
||||
Reference in New Issue
Block a user