Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-compaction-max-output-size.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@moonshot-ai/kimi-code": patch
---

Fix compaction ignoring the configured max output size.
1 change: 1 addition & 0 deletions packages/agent-core/src/agent/compaction/full.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ export class FullCompaction {
const provider = applyCompletionBudget({
provider: this.agent.config.provider,
budget: resolveCompletionBudget({
maxOutputSize: this.agent.config.maxOutputSize,
reservedContextSize: this.agent.kimiConfig?.loopControl?.reservedContextSize,
}),
capability: this.agent.config.modelCapabilities,
Expand Down
41 changes: 41 additions & 0 deletions packages/agent-core/test/agent/compaction/full.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from '@moonshot-ai/kosong';
import { afterEach, describe, expect, it, vi } from 'vitest';

import type { KimiConfig } from '../../../src/config';
import type { AgentOptions } from '../../../src/agent';
import { DefaultCompactionStrategy, type CompactionStrategy } from '../../../src/agent/compaction';
import { FLAG_DEFINITIONS, MASTER_ENV } from '../../../src/flags';
Expand Down Expand Up @@ -1770,6 +1771,46 @@ describe('FullCompaction', () => {
expect(compactionMaxCompletionTokens).toEqual([undefined]);
});

it('honors maxOutputSize from model config during compaction', async () => {
let callCount = 0;
const compactionMaxCompletionTokens: unknown[] = [];
const generate: GenerateFn = async (provider, _system, _tools, _history, callbacks) => {
callCount += 1;
if (callCount === 1) {
throw new APIContextOverflowError(400, 'Context length exceeded', 'req-max-output');
}
if (callCount === 2) {
compactionMaxCompletionTokens.push(providerMaxCompletionTokens(provider));
return textResult('Max output compacted summary.');
}
await callbacks?.onMessagePart?.({
type: 'text',
text: 'Recovered with max output.',
});
return textResult('Recovered with max output.');
};
const ctx = testAgent({ generate });
ctx.configure({
provider: CATALOGUED_PROVIDER,
modelCapabilities: CATALOGUED_MODEL_CAPABILITIES,
});
// Set maxOutputSize on the harness's internal kimiConfig — the
// compaction path reads it via ConfigState.maxOutputSize.
const models = (ctx as unknown as { kimiConfig: KimiConfig }).kimiConfig.models;
models![CATALOGUED_PROVIDER.model] = {
...models![CATALOGUED_PROVIDER.model]!,
maxOutputSize: 384000,
};
ctx.appendExchange(1, 'old user one', 'old assistant one', 20);
ctx.newEvents();

await ctx.rpc.prompt({ input: [{ type: 'text', text: 'Retry with max output' }] });
await ctx.untilTurnEnd();

expect(callCount).toBe(3);
expect(compactionMaxCompletionTokens).toEqual([384000]);
});

it('ignores filtered assistant placeholders when checking the retained overflow suffix', async () => {
let callCount = 0;
const generate: GenerateFn = async (_provider, _system, _tools, _history, callbacks) => {
Expand Down
Loading