fix(chat-params): use conservative token fallback for invalid limits
Avoid inflating non-positive maxOutputTokens values to model capability maxima by always falling back to a safe fixed budget. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -5,7 +5,7 @@ import { join } from "node:path"
|
||||
|
||||
import { createChatParamsHandler, type ChatParamsOutput } from "./chat-params"
|
||||
import * as dataPathModule from "../shared/data-path"
|
||||
import { writeProviderModelsCache } from "../shared"
|
||||
import * as sharedModule from "../shared"
|
||||
import {
|
||||
clearSessionPromptParams,
|
||||
getSessionPromptParams,
|
||||
@@ -21,13 +21,13 @@ describe("createChatParamsHandler", () => {
|
||||
getCacheDirSpy = spyOn(dataPathModule, "getOmoOpenCodeCacheDir").mockReturnValue(
|
||||
join(tempCacheRoot, "oh-my-opencode"),
|
||||
)
|
||||
writeProviderModelsCache({ connected: [], models: {} })
|
||||
sharedModule.writeProviderModelsCache({ connected: [], models: {} })
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
clearSessionPromptParams("ses_chat_params")
|
||||
clearSessionPromptParams("ses_chat_params_temperature")
|
||||
writeProviderModelsCache({ connected: [], models: {} })
|
||||
sharedModule.writeProviderModelsCache({ connected: [], models: {} })
|
||||
getCacheDirSpy?.mockRestore()
|
||||
if (tempCacheRoot) {
|
||||
rmSync(tempCacheRoot, { recursive: true, force: true })
|
||||
@@ -101,7 +101,7 @@ describe("createChatParamsHandler", () => {
|
||||
|
||||
test("applies stored prompt params for the session", async () => {
|
||||
//#given
|
||||
writeProviderModelsCache({
|
||||
sharedModule.writeProviderModelsCache({
|
||||
connected: ["openai"],
|
||||
models: {
|
||||
openai: [
|
||||
@@ -256,6 +256,7 @@ describe("createChatParamsHandler", () => {
|
||||
|
||||
test("falls back to default maxOutputTokens when stored and compatibility tokens are non-positive", async () => {
|
||||
//#given
|
||||
const logSpy = spyOn(sharedModule, "log").mockImplementation(() => undefined)
|
||||
setSessionPromptParams("ses_chat_params", {
|
||||
maxOutputTokens: 0,
|
||||
})
|
||||
@@ -282,6 +283,43 @@ describe("createChatParamsHandler", () => {
|
||||
//#when
|
||||
await handler(input, output)
|
||||
|
||||
//#then
|
||||
expect(output.maxOutputTokens).toBe(4096)
|
||||
expect(logSpy).toHaveBeenCalledWith(
|
||||
"[plugin] maxOutputTokens=0 is non-positive; using safe fallback 4096",
|
||||
)
|
||||
|
||||
logSpy.mockRestore()
|
||||
})
|
||||
|
||||
test("uses safe fallback instead of model max when stored maxOutputTokens is non-positive", async () => {
|
||||
//#given
|
||||
setSessionPromptParams("ses_chat_params", {
|
||||
maxOutputTokens: -1,
|
||||
})
|
||||
|
||||
const handler = createChatParamsHandler({
|
||||
anthropicEffort: null,
|
||||
})
|
||||
|
||||
const input = {
|
||||
sessionID: "ses_chat_params",
|
||||
agent: { name: "oracle" },
|
||||
model: { providerID: "openai", modelID: "gpt-5.4" },
|
||||
provider: { id: "openai" },
|
||||
message: {},
|
||||
}
|
||||
|
||||
const output: ChatParamsOutput = {
|
||||
topP: 1,
|
||||
topK: 1,
|
||||
maxOutputTokens: -1,
|
||||
options: {},
|
||||
}
|
||||
|
||||
//#when
|
||||
await handler(input, output)
|
||||
|
||||
//#then
|
||||
expect(output.maxOutputTokens).toBe(4096)
|
||||
})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { getSessionPromptParams } from "../shared/session-prompt-params-state"
|
||||
import { getModelCapabilities, resolveCompatibleModelSettings } from "../shared"
|
||||
import { getModelCapabilities, log, resolveCompatibleModelSettings } from "../shared"
|
||||
|
||||
const SAFE_MAX_OUTPUT_TOKENS_FALLBACK = 4096
|
||||
|
||||
export type ChatParamsInput = {
|
||||
sessionID: string
|
||||
@@ -168,9 +170,15 @@ export function createChatParamsHandler(args: {
|
||||
if (compatibility.maxTokens !== undefined && compatibility.maxTokens > 0) {
|
||||
output.maxOutputTokens = compatibility.maxTokens
|
||||
} else {
|
||||
const capabilitiesLimit = capabilities?.maxOutputTokens
|
||||
output.maxOutputTokens =
|
||||
typeof capabilitiesLimit === "number" && capabilitiesLimit > 0 ? capabilitiesLimit : 4096
|
||||
const originalMaxOutputTokens = typeof output.maxOutputTokens === "number"
|
||||
? output.maxOutputTokens
|
||||
: compatibility.maxTokens
|
||||
output.maxOutputTokens = SAFE_MAX_OUTPUT_TOKENS_FALLBACK
|
||||
if (typeof originalMaxOutputTokens === "number" && originalMaxOutputTokens <= 0) {
|
||||
log(
|
||||
`[plugin] maxOutputTokens=${originalMaxOutputTokens} is non-positive; using safe fallback ${SAFE_MAX_OUTPUT_TOKENS_FALLBACK}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user