mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-07-09 17:29:12 +00:00
fix(kosong): fall back to nearest lower catalogued minor for max tokens (#1463)
* fix(kosong): fall back to nearest lower catalogued minor for Claude max tokens An uncatalogued Claude minor version (e.g. claude-opus-4-8) previously dropped straight to the family/major baseline ceiling, so Opus 4.8 resolved to 32k max output tokens instead of the 128k it supports. Walk the minor version down to the nearest catalogued entry before using the family baseline, so a newer minor inherits its predecessor's documented ceiling. * fix(kosong): catalogue Opus 4.8's documented 128k output ceiling Known models should resolve from explicit table entries; the nearest-lower-minor fallback now only covers minors that are not yet catalogued. Fable 5 already has an explicit entry.
This commit is contained in:
parent
928726ace1
commit
03e78ae190
3 changed files with 29 additions and 10 deletions
5
.changeset/opus-4-8-max-tokens.md
Normal file
5
.changeset/opus-4-8-max-tokens.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"@moonshot-ai/kimi-code": patch
|
||||
---
|
||||
|
||||
Fix newer Claude minor versions (e.g. Opus 4.8) defaulting to the family-baseline max output tokens; an uncatalogued minor now reuses the nearest earlier known version's limit.
|
||||
|
|
@ -151,15 +151,16 @@ const ANTHROPIC_TOOL_CALL_ID_POLICY: ToolCallIdPolicy = {
|
|||
* can silently truncate mid-`tool_use`.
|
||||
*
|
||||
* Keys are `<family>-<major>[-<minor>]`. Lookups try the most specific
|
||||
* key first, then fall back to the family/major-only entry, so an
|
||||
* unrecognized minor version (e.g. a future `opus-4-10`) gets the
|
||||
* family's baseline rather than the generic fallback.
|
||||
* key first, then the nearest lower catalogued minor of the same
|
||||
* family/major (a not-yet-catalogued `opus-4-8` reuses `opus-4-7`'s
|
||||
* ceiling), and finally the family/major-only baseline entry.
|
||||
*/
|
||||
const CEILING_BY_FAMILY_VERSION: Readonly<Record<string, number>> = {
|
||||
// Claude Fable 5 documents a 128k output ceiling.
|
||||
'fable-5': 128000,
|
||||
// Claude Opus per minor version. 4.6 and 4.7 raised the cap to 128k;
|
||||
// Claude Opus per minor version. 4.6 through 4.8 document a 128k cap;
|
||||
// 4.5 ships at 64k; 4.1 and the dated 4.0 release stay at 32k.
|
||||
'opus-4-8': 128000,
|
||||
'opus-4-7': 128000,
|
||||
'opus-4-6': 128000,
|
||||
'opus-4-5': 64000,
|
||||
|
|
@ -269,8 +270,16 @@ function parseClaudeFamilyVersion(model: string, requireClaudeMarker: boolean):
|
|||
function lookupClaudeCeiling(version: ClaudeVersion): number | undefined {
|
||||
const { family, major, minor } = version;
|
||||
if (minor !== null) {
|
||||
const exact = CEILING_BY_FAMILY_VERSION[`${family}-${major}-${minor}`];
|
||||
if (exact !== undefined) return exact;
|
||||
// Exact minor first, then walk down to the nearest catalogued minor:
|
||||
// a newer minor release inherits at least its predecessor's ceiling
|
||||
// (Anthropic has never lowered the cap within a major), so a
|
||||
// not-yet-catalogued 4.8 reuses 4.7's value instead of dropping to
|
||||
// the family baseline. The regex caps minors at two digits, so this
|
||||
// walk is bounded.
|
||||
for (let candidate = minor; candidate >= 0; candidate--) {
|
||||
const ceiling = CEILING_BY_FAMILY_VERSION[`${family}-${major}-${candidate}`];
|
||||
if (ceiling !== undefined) return ceiling;
|
||||
}
|
||||
}
|
||||
return CEILING_BY_FAMILY_VERSION[`${family}-${major}`];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2619,6 +2619,7 @@ describe('AnthropicChatProvider', () => {
|
|||
describe('resolveDefaultMaxTokens', () => {
|
||||
it('returns per-version Messages-API caps for known Claude 4 models', () => {
|
||||
expect(resolveDefaultMaxTokens('claude-fable-5')).toBe(128000);
|
||||
expect(resolveDefaultMaxTokens('claude-opus-4-8')).toBe(128000);
|
||||
expect(resolveDefaultMaxTokens('claude-opus-4-7')).toBe(128000);
|
||||
expect(resolveDefaultMaxTokens('claude-opus-4-6')).toBe(128000);
|
||||
expect(resolveDefaultMaxTokens('claude-opus-4-5-20251101')).toBe(64000);
|
||||
|
|
@ -2650,6 +2651,7 @@ describe('resolveDefaultMaxTokens', () => {
|
|||
});
|
||||
|
||||
it('matches dotted version separators', () => {
|
||||
expect(resolveDefaultMaxTokens('claude-opus-4.8')).toBe(128000);
|
||||
expect(resolveDefaultMaxTokens('claude-opus-4.7')).toBe(128000);
|
||||
expect(resolveDefaultMaxTokens('claude-opus-4.6')).toBe(128000);
|
||||
expect(resolveDefaultMaxTokens('claude-sonnet-4.6')).toBe(64000);
|
||||
|
|
@ -2672,12 +2674,15 @@ describe('resolveDefaultMaxTokens', () => {
|
|||
expect(resolveDefaultMaxTokens('anthropic.claude-3-5-sonnet-20240620-v1:0')).toBe(8192);
|
||||
});
|
||||
|
||||
it('falls back to family-only ceiling for unknown minor versions', () => {
|
||||
// Future opus-4-X release: minor not in table, falls back to opus-4 = 32000.
|
||||
// Better to under-quote and fail loudly than over-quote a model we can't verify.
|
||||
expect(resolveDefaultMaxTokens('claude-opus-4-10')).toBe(32000);
|
||||
it('falls back to the nearest lower catalogued minor for unknown minors', () => {
|
||||
// opus-4-9/4-10 are not in the table; they reuse opus-4-8's 128k
|
||||
// ceiling (a newer minor inherits at least its predecessor's cap).
|
||||
expect(resolveDefaultMaxTokens('claude-opus-4-9')).toBe(128000);
|
||||
expect(resolveDefaultMaxTokens('claude-opus-4-10')).toBe(128000);
|
||||
expect(resolveDefaultMaxTokens('claude-sonnet-4-9')).toBe(64000);
|
||||
expect(resolveDefaultMaxTokens('claude-haiku-4-9')).toBe(64000);
|
||||
// A gap between catalogued minors also resolves to the nearest lower one.
|
||||
expect(resolveDefaultMaxTokens('claude-opus-4-3')).toBe(32000);
|
||||
});
|
||||
|
||||
it('matches case-insensitively', () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue