refactor(agent): exhaust recovery and compaction decisions
Dispatch RequestErrorDecision and CompactionTrigger through explicit discriminant switches. End each closed union with assertNever so new variants fail compilation instead of silently inheriting fail or pressure behavior. This preserves the current retry, fail, pressure, and overflow semantics while aligning the new recovery seams with the repository closed-union contract.
This commit is contained in:
@@ -9,7 +9,7 @@ import z from 'schemastery'
|
|||||||
import { CompactService } from '@deepseek-ai/dsh-compact'
|
import { CompactService } from '@deepseek-ai/dsh-compact'
|
||||||
import type { CompactionResult, CompactionTrigger } from '@deepseek-ai/dsh-compact'
|
import type { CompactionResult, CompactionTrigger } from '@deepseek-ai/dsh-compact'
|
||||||
import type { Session } from '@deepseek-ai/dsh-session'
|
import type { Session } from '@deepseek-ai/dsh-session'
|
||||||
import { CONTEXT_WINDOW_EXCEEDED_CODE } from '@deepseek-ai/dsh-llm'
|
import { CONTEXT_WINDOW_EXCEEDED_CODE, assertNever } from '@deepseek-ai/dsh-llm'
|
||||||
import type { ContentBlock } from '@deepseek-ai/dsh-llm'
|
import type { ContentBlock } from '@deepseek-ai/dsh-llm'
|
||||||
import type { Agent } from '@deepseek-ai/dsh-agent'
|
import type { Agent } from '@deepseek-ai/dsh-agent'
|
||||||
import { resolveConfig } from './config.ts'
|
import { resolveConfig } from './config.ts'
|
||||||
@@ -152,11 +152,18 @@ export class BasicCompactService extends CompactService {
|
|||||||
const model = routedModel(agent.session)
|
const model = routedModel(agent.session)
|
||||||
if (model === undefined) return null
|
if (model === undefined) return null
|
||||||
const meter = this.ctx.tokenMeter
|
const meter = this.ctx.tokenMeter
|
||||||
if (trigger === 'context-overflow') {
|
switch (trigger) {
|
||||||
const measurement = meter.measure(agent.session)
|
case 'context-overflow': {
|
||||||
const range = selectCompactableRange(agent.session, measurement, 0)
|
const measurement = meter.measure(agent.session)
|
||||||
if (range === null) return null
|
const range = selectCompactableRange(agent.session, measurement, 0)
|
||||||
return this.compactRegion(range.start, range.end, agent, signal)
|
if (range === null) return null
|
||||||
|
return this.compactRegion(range.start, range.end, agent, signal)
|
||||||
|
}
|
||||||
|
case 'pressure':
|
||||||
|
break
|
||||||
|
/* v8 ignore next -- closed-union exhaustiveness guard */
|
||||||
|
default:
|
||||||
|
assertNever(trigger, 'compaction trigger')
|
||||||
}
|
}
|
||||||
|
|
||||||
const threshold = Math.floor(meter.contextWindow * this.config.thresholdRatio)
|
const threshold = Math.floor(meter.contextWindow * this.config.thresholdRatio)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
import type { Context } from 'cordis'
|
import type { Context } from 'cordis'
|
||||||
import type { ContentBlock, FinishReason, GenerateOptions, LlmCallConfig, Message } from '@deepseek-ai/dsh-llm'
|
import type { ContentBlock, FinishReason, GenerateOptions, LlmCallConfig, Message } from '@deepseek-ai/dsh-llm'
|
||||||
import { isDeepStrictEqual } from 'node:util'
|
import { isDeepStrictEqual } from 'node:util'
|
||||||
import { BlockAssembler, HarnessError, deepFreeze, isLlmAdapterFailure } from '@deepseek-ai/dsh-llm'
|
import { BlockAssembler, HarnessError, assertNever, deepFreeze, isLlmAdapterFailure } from '@deepseek-ai/dsh-llm'
|
||||||
import { agentEvents, assembleContextFor } from '@deepseek-ai/dsh-agent'
|
import { agentEvents, assembleContextFor } from '@deepseek-ai/dsh-agent'
|
||||||
import type { AgentEventDispatch, ContinuationDecision, HookContext, PromptDecision, RequestError, RequestErrorDecision } from '@deepseek-ai/dsh-agent'
|
import type { AgentEventDispatch, ContinuationDecision, HookContext, PromptDecision, RequestError, RequestErrorDecision } from '@deepseek-ai/dsh-agent'
|
||||||
import { canonicalHeader } from '@deepseek-ai/dsh-session'
|
import { canonicalHeader } from '@deepseek-ai/dsh-session'
|
||||||
@@ -392,11 +392,17 @@ async function runTurn(
|
|||||||
: { kind: 'aborted', reason: String(abort.signal.reason) }
|
: { kind: 'aborted', reason: String(abort.signal.reason) }
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (recoveryDecision.action === 'retry') {
|
switch (recoveryDecision.action) {
|
||||||
requestRetryAttempt += 1
|
case 'retry':
|
||||||
continue
|
requestRetryAttempt += 1
|
||||||
|
continue
|
||||||
|
case 'fail':
|
||||||
|
failTurn(stepOutcome.requestError)
|
||||||
|
break
|
||||||
|
/* v8 ignore next -- closed-union exhaustiveness guard */
|
||||||
|
default:
|
||||||
|
assertNever(recoveryDecision, 'agent request-error decision')
|
||||||
}
|
}
|
||||||
failTurn(stepOutcome.requestError)
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user