Skip to content

Commit 0988bfa

Browse files
committed
fix: omit non-positive max_tokens for custom models
Custom models used sane-default metadata with maxTokens: -1 (unlimited), which Fireworks rejects with '400 max_tokens must be non-negative'. OpenAI API spec does not specify -1 as special value and explicitly allows max tokens to be omitted. Remove max tokens from the sane-default metadata.
1 parent 46e9068 commit 0988bfa

4 files changed

Lines changed: 39 additions & 2 deletions

File tree

‎packages/types/src/providers/openai.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -930,8 +930,9 @@ export const openAiNativeModels = {
930930
},
931931
} as const satisfies Record<string, ModelInfo>
932932

933+
// `maxTokens` is intentionally omitted so that no max output token limit is sent to the
934+
// provider by default.
933935
export const openAiModelInfoSaneDefaults: ModelInfo = {
934-
maxTokens: -1,
935936
contextWindow: 128_000,
936937
supportsImages: true,
937938
supportsPromptCache: false,

‎src/api/providers/__tests__/base-openai-compatible-provider.spec.ts‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ describe("BaseOpenAiCompatibleProvider", () => {
325325
expect(model.id).not.toBe("test-model")
326326
// Falls back to sane default metadata so the rest of the pipeline works.
327327
expect(model.info).toEqual(openAiModelInfoSaneDefaults)
328+
expect(model.info).not.toHaveProperty("maxTokens")
328329
})
329330

330331
it("sends the custom model id verbatim to the API", async () => {
@@ -343,6 +344,18 @@ describe("BaseOpenAiCompatibleProvider", () => {
343344
)
344345
})
345346

347+
it("omits max_tokens for a custom model", async () => {
348+
mockCreate.mockImplementationOnce(() => asyncStreamFrom([]))
349+
350+
const customHandler = new TestOpenAiCompatibleProvider("test-api-key", {
351+
apiModelId: "some/custom-model-not-in-list",
352+
})
353+
354+
await collectStream(customHandler.createMessage("system prompt", []))
355+
356+
expect(mockCreate.mock.calls[0][0].max_tokens).toBeUndefined()
357+
})
358+
346359
it("completePrompt sends the custom model id verbatim to the API", async () => {
347360
mockCreate.mockResolvedValueOnce({ choices: [{ message: { content: "ok" } }] })
348361

‎src/api/providers/__tests__/fireworks.spec.ts‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,29 @@ describe("FireworksHandler", () => {
9898
expect(model.info).toEqual(expect.objectContaining(fireworksModels[testModelId]))
9999
})
100100

101+
it("should omit max_tokens for a custom model", async () => {
102+
const handlerWithCustomModel = new FireworksHandler({
103+
apiModelId: "accounts/fireworks/models/deepseek-v4p1-flash",
104+
fireworksApiKey: "test-fireworks-api-key",
105+
})
106+
107+
await collectStream(handlerWithCustomModel.createMessage("system prompt", []))
108+
109+
expect(mockCreate.mock.calls[0][0].model).toBe("accounts/fireworks/models/deepseek-v4p1-flash")
110+
expect(mockCreate.mock.calls[0][0].max_tokens).toBeUndefined()
111+
})
112+
113+
it("should still send a positive max_tokens for a known model", async () => {
114+
const handlerWithModel = new FireworksHandler({
115+
apiModelId: "accounts/fireworks/models/kimi-k2-instruct",
116+
fireworksApiKey: "test-fireworks-api-key",
117+
})
118+
119+
await collectStream(handlerWithModel.createMessage("system prompt", []))
120+
121+
expect(mockCreate.mock.calls[0][0].max_tokens).toBe(16384)
122+
})
123+
101124
it.each([
102125
{
103126
modelId: "accounts/fireworks/models/glm-5p1" as const,

‎src/api/providers/__tests__/lmstudio.spec.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ describe("LmStudioHandler", () => {
239239
const modelInfo = handler.getModel()
240240
expect(modelInfo.id).toBe(mockOptions.lmStudioModelId)
241241
expect(modelInfo.info).toBeDefined()
242-
expect(modelInfo.info.maxTokens).toBe(-1)
242+
expect(modelInfo.info.maxTokens).toBeUndefined()
243243
expect(modelInfo.info.contextWindow).toBe(128_000)
244244
})
245245
})

0 commit comments

Comments
 (0)