diff --git a/extensions/cohere/index.test.ts b/extensions/cohere/index.test.ts index b3e773ae6e8f..e20eef4268a6 100644 --- a/extensions/cohere/index.test.ts +++ b/extensions/cohere/index.test.ts @@ -32,11 +32,14 @@ function captureCoherePayload(context: Context): Record { { maxTokens: 2048 } as never, ); options?.onPayload?.(payload, model); - captured = payload; return {} as ReturnType; }; - void createCohereCompletionsWrapper(baseStreamFn)(requireCohereModel(), context, {}); + void createCohereCompletionsWrapper(baseStreamFn)(requireCohereModel(), context, { + onPayload: (payload) => { + captured = payload as Record; + }, + }); if (!captured) { throw new Error("Cohere payload was not captured"); } @@ -104,5 +107,11 @@ describe("Cohere provider plugin", () => { expect(params).not.toHaveProperty("store"); expect(params).not.toHaveProperty("stream_options"); expect(params).not.toHaveProperty("tool_choice"); + expect(params.messages).toEqual( + expect.arrayContaining([expect.objectContaining({ role: "developer", content: "system" })]), + ); + expect(params.messages).not.toEqual( + expect.arrayContaining([expect.objectContaining({ role: "system", content: "system" })]), + ); }); }); diff --git a/extensions/cohere/stream.ts b/extensions/cohere/stream.ts index 032800a8437a..5038cc7acc7a 100644 --- a/extensions/cohere/stream.ts +++ b/extensions/cohere/stream.ts @@ -1,17 +1,26 @@ import type { ProviderWrapStreamFnContext } from "openclaw/plugin-sdk/plugin-entry"; import { createPayloadPatchStreamWrapper } from "openclaw/plugin-sdk/provider-stream-shared"; +function patchCoherePayload(payload: Record): void { + // Cohere's Compatibility API uses developer, not system, for instructions. + if (Array.isArray(payload.messages)) { + payload.messages = payload.messages.map((message) => + message && + typeof message === "object" && + (message as Record).role === "system" + ? { ...(message as Record), role: "developer" } + : message, + ); + } + + // Cohere lets tool-capable models choose a tool when tool_choice is omitted. + delete payload.tool_choice; +} + export function createCohereCompletionsWrapper( baseStreamFn: ProviderWrapStreamFnContext["streamFn"], ): ProviderWrapStreamFnContext["streamFn"] { - return createPayloadPatchStreamWrapper( - baseStreamFn, - ({ payload }) => { - // Cohere lets tool-capable models choose a tool when tool_choice is omitted. - delete payload.tool_choice; - }, - { - shouldPatch: ({ model }) => model.provider === "cohere" && model.api === "openai-completions", - }, + return createPayloadPatchStreamWrapper(baseStreamFn, ({ payload }) => + patchCoherePayload(payload), ); }