diff --git a/scripts/defines.ts b/scripts/defines.ts index 3249e6809..fa7a7b8d8 100644 --- a/scripts/defines.ts +++ b/scripts/defines.ts @@ -59,7 +59,7 @@ export const DEFAULT_BUILD_FEATURES = [ 'DAEMON', // 守护进程模式,长驻 supervisor 管理后台 worker(非 GB 级主因) 'ACP', // ACP 代理协议,支持外部 agent 接入 'WORKFLOW_SCRIPTS', // 工作流脚本(.claude/workflows/ 中的 YAML/MD) - // 'HISTORY_SNIP', // 历史消息裁剪,压缩上下文窗口 + 'HISTORY_SNIP', // 历史消息裁剪,压缩上下文窗口 // 'CONTEXT_COLLAPSE', // 已禁用:实现是空壳 stub,启用后会抑制 auto compact 导致上下文管理完全失效 'MONITOR_TOOL', // Monitor 工具,流式监控后台进程输出 // 'FORK_SUBAGENT', // 已禁用:显式 `fork: true` 参数触发 fork 路径(继承父级上下文和模型),不影响 forceAsync 和探索任务模型选择 diff --git a/src/QueryEngine.ts b/src/QueryEngine.ts index 8ffa5e9d0..8e48ed757 100644 --- a/src/QueryEngine.ts +++ b/src/QueryEngine.ts @@ -1003,15 +1003,6 @@ export class QueryEngine { uuid: msg.uuid, } } - // Proactive truncation: prevent unbounded growth when API doesn't - // return compact_boundary (e.g. third-party compat layers). - if (feature('HISTORY_SNIP') && snipModule) { - const truncated = snipModule.proactiveTruncate(this.mutableMessages) - if (truncated !== this.mutableMessages) { - this.mutableMessages.length = 0 - this.mutableMessages.push(...truncated) - } - } // Don't yield other system messages in headless mode break } diff --git a/src/services/compact/snipCompact.ts b/src/services/compact/snipCompact.ts index 3be2ef624..4e4a0d9fc 100644 --- a/src/services/compact/snipCompact.ts +++ b/src/services/compact/snipCompact.ts @@ -163,77 +163,3 @@ export function isSnipRuntimeEnabled(): boolean { export function shouldNudgeForSnips(messages: Message[]): boolean { return messages.length >= SNIP_NUDGE_THRESHOLD } - -/** - * Maximum total character length of message content before proactive - * truncation kicks in. ~150 MB of string data corresponds to roughly - * 1.5x the default 200k-token context window at 4 chars/token — well - * beyond what any model can actually use in a single request. - */ -const PROACTIVE_TRUNCATE_CHARS = 150_000_000 - -/** - * Minimum number of messages to keep when falling back to tail-only - * retention (i.e. when no compact_boundary exists in the array). - */ -const PROACTIVE_TRUNCATE_MIN_TAIL = 50 - -/** - * Proactively truncate old messages when the in-memory store grows too - * large. Unlike `snipCompactIfNeeded` (which waits for a snip_boundary - * from the API), this runs client-side after every push — ensuring - * unbounded growth cannot happen even when the API never returns a - * compact_boundary (e.g. third-party compat layers). - * - * Strategy: - * 1. If a `compact_boundary` exists, keep it and everything after it. - * 2. Otherwise, keep only the last `PROACTIVE_TRUNCATE_MIN_TAIL` messages. - * - * Returns the same array reference when no truncation is needed. - */ -export function proactiveTruncate(messages: Message[]): Message[] { - if (messages.length < PROACTIVE_TRUNCATE_MIN_TAIL) return messages - - let totalChars = 0 - for (const msg of messages) { - const content = msg.message?.content - if (typeof content === 'string') { - totalChars += content.length - } else if (Array.isArray(content)) { - for (const block of content) { - if (typeof block === 'string') { - totalChars += (block as string).length - } else if (block && typeof block === 'object') { - const obj = block as unknown as Record - const text = obj.text ?? obj.content - if (typeof text === 'string') { - totalChars += text.length - } - } - } - } - } - - if (totalChars < PROACTIVE_TRUNCATE_CHARS) return messages - - // Find last compact_boundary — the standard anchor point - let boundaryIdx = -1 - for (let i = messages.length - 1; i >= 0; i--) { - const msg = messages[i]! - if ( - msg.type === 'system' && - (msg as Record).subtype === 'compact_boundary' - ) { - boundaryIdx = i - break - } - } - - const keepFrom = - boundaryIdx >= 0 - ? boundaryIdx - : Math.max(0, messages.length - PROACTIVE_TRUNCATE_MIN_TAIL) - if (keepFrom === 0) return messages - - return messages.slice(keepFrom) -} diff --git a/src/utils/telemetry/instrumentation.ts b/src/utils/telemetry/instrumentation.ts index d5bcf7ffb..fffe84def 100644 --- a/src/utils/telemetry/instrumentation.ts +++ b/src/utils/telemetry/instrumentation.ts @@ -206,49 +206,10 @@ async function getOtlpReaders() { return exporters.map(exporter => { if ('export' in exporter) { - const reader = new PeriodicExportingMetricReader({ + return new PeriodicExportingMetricReader({ exporter, exportIntervalMillis: exportInterval, }) - // Wrap the export callback to auto-shutdown the reader on auth - // failures (401/403). Without this the PeriodicExportingMetricReader's - // internal setInterval keeps retrying forever, leaking handles. - const originalExport = ( - exporter as unknown as { - export: ( - metrics: unknown, - callback: (result: { error?: Error }) => void, - ) => unknown - } - ).export.bind(exporter) - ;( - exporter as unknown as { - export: ( - metrics: unknown, - callback: (result: { error?: Error }) => void, - ) => unknown - } - ).export = (metrics, callback) => { - return originalExport(metrics, result => { - if (result.error) { - const msg = result.error.message || '' - if ( - msg.includes('401') || - msg.includes('403') || - msg.includes('Unauthorized') || - msg.includes('authentication') - ) { - logForDebugging( - `[3P telemetry] Auth error detected, shutting down metric reader`, - { level: 'error' }, - ) - void reader.shutdown() - } - } - callback(result) - }) - } - return reader } return exporter })