mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 07:40:44 +00:00
fix: strip opencode image reasoning none
This commit is contained in:
@@ -1,8 +1,29 @@
|
||||
import { describe, it } from "vitest";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { registerProviderPlugin } from "../../test/helpers/plugins/provider-registration.js";
|
||||
import { expectPassthroughReplayPolicy } from "../../test/helpers/provider-replay-policy.ts";
|
||||
import plugin from "./index.js";
|
||||
|
||||
describe("opencode provider plugin", () => {
|
||||
it("registers image media understanding through the OpenCode plugin", async () => {
|
||||
const { mediaProviders } = await registerProviderPlugin({
|
||||
plugin,
|
||||
id: "opencode",
|
||||
name: "OpenCode Zen Provider",
|
||||
});
|
||||
|
||||
expect(mediaProviders).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: "opencode",
|
||||
capabilities: ["image"],
|
||||
defaultModels: { image: "gpt-5-nano" },
|
||||
describeImage: expect.any(Function),
|
||||
describeImages: expect.any(Function),
|
||||
}),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("owns passthrough-gemini replay policy for Gemini-backed models", async () => {
|
||||
await expectPassthroughReplayPolicy({
|
||||
plugin,
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
} from "openclaw/plugin-sdk/provider-model-shared";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { applyOpencodeZenConfig, OPENCODE_ZEN_DEFAULT_MODEL } from "./api.js";
|
||||
import { opencodeMediaUnderstandingProvider } from "./media-understanding-provider.js";
|
||||
|
||||
const PROVIDER_ID = "opencode";
|
||||
const MINIMAX_MODERN_MODEL_MATCHERS = ["minimax-m2.7"] as const;
|
||||
@@ -49,5 +50,6 @@ export default definePluginEntry({
|
||||
...PASSTHROUGH_GEMINI_REPLAY_HOOKS,
|
||||
isModernModelRef: ({ modelId }) => isModernOpencodeModel(modelId),
|
||||
});
|
||||
api.registerMediaUnderstandingProvider(opencodeMediaUnderstandingProvider);
|
||||
},
|
||||
});
|
||||
|
||||
48
extensions/opencode/media-understanding-provider.test.ts
Normal file
48
extensions/opencode/media-understanding-provider.test.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
opencodeMediaUnderstandingProvider,
|
||||
stripOpencodeDisabledResponsesReasoningPayload,
|
||||
} from "./media-understanding-provider.js";
|
||||
|
||||
describe("opencode media understanding provider", () => {
|
||||
it("strips disabled Responses reasoning payloads", () => {
|
||||
const payload = {
|
||||
reasoning: { effort: "none" },
|
||||
include: ["reasoning.encrypted_content"],
|
||||
store: false,
|
||||
};
|
||||
|
||||
stripOpencodeDisabledResponsesReasoningPayload(payload);
|
||||
|
||||
expect(payload).toEqual({
|
||||
include: ["reasoning.encrypted_content"],
|
||||
store: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps supported Responses reasoning payloads", () => {
|
||||
const payload = {
|
||||
reasoning: { effort: "low" },
|
||||
store: false,
|
||||
};
|
||||
|
||||
stripOpencodeDisabledResponsesReasoningPayload(payload);
|
||||
|
||||
expect(payload).toEqual({
|
||||
reasoning: { effort: "low" },
|
||||
store: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("declares OpenCode image understanding support", () => {
|
||||
expect(opencodeMediaUnderstandingProvider).toEqual(
|
||||
expect.objectContaining({
|
||||
id: "opencode",
|
||||
capabilities: ["image"],
|
||||
defaultModels: { image: "gpt-5-nano" },
|
||||
describeImage: expect.any(Function),
|
||||
describeImages: expect.any(Function),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
42
extensions/opencode/media-understanding-provider.ts
Normal file
42
extensions/opencode/media-understanding-provider.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import type { ProviderStreamOptions } from "@mariozechner/pi-ai";
|
||||
import {
|
||||
describeImageWithModelPayloadTransform,
|
||||
describeImagesWithModelPayloadTransform,
|
||||
type MediaUnderstandingProvider,
|
||||
} from "openclaw/plugin-sdk/media-understanding";
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
||||
}
|
||||
|
||||
export function stripOpencodeDisabledResponsesReasoningPayload(payload: unknown): void {
|
||||
if (!isRecord(payload)) {
|
||||
return;
|
||||
}
|
||||
const reasoning = payload.reasoning;
|
||||
if (reasoning === "none") {
|
||||
delete payload.reasoning;
|
||||
return;
|
||||
}
|
||||
if (!isRecord(reasoning) || reasoning.effort !== "none") {
|
||||
return;
|
||||
}
|
||||
delete payload.reasoning;
|
||||
}
|
||||
|
||||
const stripDisabledResponsesReasoning: ProviderStreamOptions["onPayload"] = (payload) => {
|
||||
stripOpencodeDisabledResponsesReasoningPayload(payload);
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const opencodeMediaUnderstandingProvider: MediaUnderstandingProvider = {
|
||||
id: "opencode",
|
||||
capabilities: ["image"],
|
||||
defaultModels: {
|
||||
image: "gpt-5-nano",
|
||||
},
|
||||
describeImage: (request) =>
|
||||
describeImageWithModelPayloadTransform(request, stripDisabledResponsesReasoning),
|
||||
describeImages: (request) =>
|
||||
describeImagesWithModelPayloadTransform(request, stripDisabledResponsesReasoning),
|
||||
};
|
||||
Reference in New Issue
Block a user