fix: v2 full compaction

This commit is contained in:
_Kerman 2026-07-08 20:16:49 +08:00
parent f6aa8a8e7b
commit d0af37bbc6
2 changed files with 31 additions and 11 deletions

View file

@ -239,7 +239,9 @@ export class AgentFullCompactionService extends Disposable implements IAgentFull
next: () => Promise<void>,
): Promise<void> {
const isOverflow =
isContextOverflowError(context.error) || this.shouldRecoverFromPlain413(context.error);
isContextOverflowError(context.error) ||
findAPIStatusError(context.error) instanceof APIContextOverflowError ||
this.shouldRecoverFromPlain413(context.error);
if (!isOverflow) {
await next();
return;
@ -525,9 +527,10 @@ export class AgentFullCompactionService extends Disposable implements IAgentFull
tokens_after: result.tokensAfter,
duration_ms: Date.now() - startedAt,
compacted_count: result.compactedCount,
dropped_count: result.droppedCount,
retry_count: retryCount,
round,
thinking_level: this.profile.data().thinkingLevel,
thinking_effort: this.profile.data().thinkingLevel,
...usageTelemetry(attempt.usage),
});
return result;
@ -539,7 +542,7 @@ export class AgentFullCompactionService extends Disposable implements IAgentFull
duration_ms: Date.now() - startedAt,
round,
retry_count: retryCount,
thinking_level: this.profile.data().thinkingLevel,
thinking_effort: this.profile.data().thinkingLevel,
error_type: error instanceof Error ? error.name : 'Unknown',
});
if (isKimiError(error) && error.code === ErrorCodes.AUTH_LOGIN_REQUIRED) throw error;
@ -567,7 +570,8 @@ export class AgentFullCompactionService extends Disposable implements IAgentFull
error: unknown,
estimatedRequestTokens = this.tokenCountWithPending(),
): boolean {
if (!(error instanceof APIStatusError) || error.statusCode !== 413) return false;
const statusError = findAPIStatusError(error);
if (statusError === undefined || statusError.statusCode !== 413) return false;
const maxContextTokens = this.profile.getModelCapabilities().max_context_tokens;
return (
maxContextTokens > 0 &&
@ -584,6 +588,17 @@ export class AgentFullCompactionService extends Disposable implements IAgentFull
}
}
function findAPIStatusError(error: unknown): APIStatusError | undefined {
let current: unknown = error;
const seen = new Set<unknown>();
while (current !== undefined && current !== null && !seen.has(current)) {
if (current instanceof APIStatusError) return current;
seen.add(current);
current = current instanceof Error ? current.cause : undefined;
}
return undefined;
}
function collectSummary(finish: LLMRequestFinish): CompactionAttemptResult {
if (finish.providerFinishReason === 'truncated') {
throw new CompactionTruncatedError();

View file

@ -274,7 +274,7 @@ describe('FullCompaction', () => {
duration_ms: expect.any(Number),
compacted_count: 6,
retry_count: 0,
thinking_level: 'off',
thinking_effort: 'off',
input_other: 1181,
output: 8,
input_cache_read: 0,
@ -1975,12 +1975,16 @@ describe('FullCompaction', () => {
await ctx.untilTurnEnd();
expect(callCount).toBe(3);
expect(providerThinkingEfforts).toEqual(['high', 'high', 'high']);
// The catalogued model declares no supportEfforts, so the Kimi provider
// normalizes to boolean thinking and reports 'on' rather than the
// requested 'high'. The stored thinkingLevel still carries 'high' across
// compaction, which is asserted through telemetry below.
expect(providerThinkingEfforts).toEqual(['on', 'on', 'on']);
expect(records).toContainEqual({
event: 'compaction_finished',
properties: expect.objectContaining({
source: 'auto',
thinking_level: 'high',
thinking_effort: 'high',
}),
});
});
@ -2014,10 +2018,11 @@ describe('FullCompaction', () => {
const modelResolver = ctx.modelResolver;
if (modelResolver === undefined) throw new Error('Expected model provider');
const resolve = modelResolver.resolve.bind(modelResolver);
modelResolver.resolve = (model: string) => ({
...resolve(model),
modelCapabilities: UNKNOWN_CAPABILITY,
});
modelResolver.resolve = (model: string) => {
const resolved = resolve(model);
Object.defineProperty(resolved, 'capabilities', { value: UNKNOWN_CAPABILITY });
return resolved;
};
expect(ctx.get(IAgentProfileService).data().modelCapabilities.max_context_tokens).toBe(0);
ctx.appendExchange(1, 'old user one', 'old assistant one', 20);
ctx.newEvents();