Files
OmniRoute/open-sse/services/opencodeReasoningSanitizer.ts
Chewji af0a9609f4 feat(sse): support native max reasoning effort and per-model clamping (#11875)
* fix(sse): map normalized xhigh to max for GLM-5.x+, DeepSeek-V4+, and provider aliases

* feat(sse): support native max reasoning effort and per-model clamping

* test(sse): add unit tests for Qwen 3.8, Claude 4.7+, GPT-5.6, and 2026 reasoning models

* fix(sse): align tests and file-size split for native max effort

Keep `max` as a first-class canonical tier. Split the new sanitizer
coverage out of base-executor-sanitize-effort.test.ts so the file stays
under testCap, and update discovery/catalog/vscode assertions to expect
native max instead of the old xhigh alias.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* fix(sse): keep combo effort lists and drop unused collectSSE helper

Combo vscode routes still advertise the 5-tier list. Canonical `max` is
preserved in discovery (#9160) and github model metadata. Remove the
unused collectSSE helper that failed the absolute ESLint gate.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: Chewji <Chewji9875@users.noreply.github.com>
2026-09-02 00:12:13 -03:00

55 lines
1.9 KiB
TypeScript

type JsonRecord = Record<string, unknown>;
/**
* Strip boolean `reasoning` for opencode-go based providers.
*
* Providers backed by the opencode-go backend (ollama-cloud, opencode-go,
* opencode, opencode-zen) use a Go ChatCompletionRequest struct where the
* `reasoning` field is typed as `openai.Reasoning` (a structured type, not
* a bool). When a client sends `reasoning: true` or `reasoning: false` —
* which is valid per the OpenAI API for enabling/disabling reasoning — the
* Go JSON decoder rejects it with:
*
* 400: json: cannot unmarshal bool into Go struct field
* ChatCompletionRequest.reasoning of type openai.Reasoning
*
* This strips the boolean `reasoning` field from the request body before it
* is forwarded to these providers, allowing the upstream to apply its own
* default reasoning behavior. If `reasoning` is already an object/string
* (matching the Go struct), it is left untouched.
*
* Related: services/mimoThinking.ts uses the same pattern for Xiaomi MiMo.
*/
const OPENCODE_GO_PROVIDERS = new Set([
"ollama-cloud",
"ollamacloud",
"ollama_cloud",
"opencode-go",
"opencode_go",
"opencode",
"opencode-zen",
]);
/** True when the provider is backed by the opencode-go backend. */
export function isOpencodeGoProvider(provider: string): boolean {
return OPENCODE_GO_PROVIDERS.has(provider);
}
/**
* Remove a boolean `reasoning` field from the request body.
* Returns the same object reference if no change is needed, or a shallow
* clone with the field removed.
*/
export function stripBooleanReasoning(body: JsonRecord): JsonRecord {
if (!body || typeof body !== "object") return body;
if (!("reasoning" in body)) return body;
const reasoning = body.reasoning;
// Only strip when reasoning is a boolean — object/string forms are valid
// for the Go struct and should be forwarded as-is.
if (typeof reasoning !== "boolean") return body;
const next = { ...body };
delete next.reasoning;
return next;
}