Skip to content

Commit 6cdbb6b

Browse files
fix(config): preserve modelMaxTokens on export for models with configurable max output (#161)
1 parent 58cc57a commit 6cdbb6b

2 files changed

Lines changed: 55 additions & 2 deletions

File tree

src/core/config/ProviderSettingsManager.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -567,11 +567,18 @@ export class ProviderSettingsManager {
567567
const supportsReasoningBudget =
568568
modelInfo.supportsReasoningBudget || modelInfo.requiredReasoningBudget
569569

570-
// If the model doesn't support reasoning budgets, remove the token fields
570+
// modelMaxThinkingTokens only applies to reasoning budgets, but modelMaxTokens
571+
// also caps output on models that expose a configurable max (e.g. GLM), so keep
572+
// it whenever the model supports either feature.
573+
const supportsMaxTokens = supportsReasoningBudget || modelInfo.supportsMaxTokens
574+
571575
if (!supportsReasoningBudget) {
572-
delete configs[name].modelMaxTokens
573576
delete configs[name].modelMaxThinkingTokens
574577
}
578+
579+
if (!supportsMaxTokens) {
580+
delete configs[name].modelMaxTokens
581+
}
575582
} catch (error) {
576583
// If we can't build the API handler or get model info, skip filtering
577584
// to avoid accidental data loss from incomplete configurations

src/core/config/__tests__/ProviderSettingsManager.spec.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,52 @@ describe("ProviderSettingsManager", () => {
874874
expect(exported.apiConfigs.retired.modelMaxTokens).toBe(4096)
875875
expect(exported.apiConfigs.retired.modelMaxThinkingTokens).toBe(2048)
876876
})
877+
878+
it("should preserve modelMaxTokens for models that support a configurable max output (e.g. GLM)", async () => {
879+
const existingConfig: ProviderProfiles = {
880+
currentApiConfigName: "glm",
881+
apiConfigs: {
882+
glm: {
883+
id: "glm-id",
884+
apiProvider: "zai",
885+
apiModelId: "glm-5.1",
886+
modelMaxTokens: 8192,
887+
modelMaxThinkingTokens: 2048,
888+
},
889+
},
890+
}
891+
892+
mockSecrets.get.mockResolvedValue(JSON.stringify(existingConfig))
893+
894+
const exported = await providerSettingsManager.export()
895+
896+
// GLM exposes a configurable max output (supportsMaxTokens) but no reasoning budget,
897+
// so modelMaxTokens must survive the export while modelMaxThinkingTokens is dropped.
898+
expect(exported.apiConfigs.glm.modelMaxTokens).toBe(8192)
899+
expect(exported.apiConfigs.glm.modelMaxThinkingTokens).toBeUndefined()
900+
})
901+
902+
it("should strip both token fields for models that support neither reasoning budgets nor a configurable max", async () => {
903+
const existingConfig: ProviderProfiles = {
904+
currentApiConfigName: "anthropic",
905+
apiConfigs: {
906+
anthropic: {
907+
id: "anthropic-id",
908+
apiProvider: "anthropic",
909+
apiModelId: "claude-3-5-haiku-20241022",
910+
modelMaxTokens: 8192,
911+
modelMaxThinkingTokens: 2048,
912+
},
913+
},
914+
}
915+
916+
mockSecrets.get.mockResolvedValue(JSON.stringify(existingConfig))
917+
918+
const exported = await providerSettingsManager.export()
919+
920+
expect(exported.apiConfigs.anthropic.modelMaxTokens).toBeUndefined()
921+
expect(exported.apiConfigs.anthropic.modelMaxThinkingTokens).toBeUndefined()
922+
})
877923
})
878924

879925
describe("ResetAllConfigs", () => {

0 commit comments

Comments
 (0)