feat: 尝试深度拷贝数据以分离引用

This commit is contained in:
claude-code-best
2026-05-05 12:41:01 +08:00
parent 75952bde9c
commit cf2bf29dcd
2 changed files with 36 additions and 1 deletions

View File

@@ -479,6 +479,22 @@ async function* queryLoop(
let messagesForQuery = getMessagesAfterCompactBoundary(messages)
// Release toolUseResult payloads from previous turns. By this point the
// UI has already rendered those results and the next API call only needs
// message.message.content (tool_result blocks), not the raw output object.
// This prevents unbounded memory growth in long sessions before compact
// triggers — a single FileRead of a 400KB file would otherwise stay in
// mutableMessages forever.
for (const msg of messagesForQuery) {
if (
msg.type === 'user' &&
'toolUseResult' in msg &&
msg.toolUseResult !== undefined
) {
delete (msg as Message & { toolUseResult?: unknown }).toolUseResult
}
}
let tracking = autoCompactTracking
// Enforce per-message budget on aggregate tool result size. Runs BEFORE

View File

@@ -336,12 +336,31 @@ export type RecompactionInfo = {
export function buildPostCompactMessages(result: CompactionResult): Message[] {
return ([result.boundaryMarker] as Message[]).concat(
result.summaryMessages,
result.messagesToKeep ?? [],
stripToolUseResults(result.messagesToKeep),
result.attachments,
result.hookResults,
)
}
/** Release large tool result payloads from kept messages after compaction.
* toolUseResult is only used for UI rendering, not API calls. */
function stripToolUseResults(messages: Message[] | undefined): Message[] {
if (!messages) return []
return messages.map(msg => {
if (
msg.type === 'user' &&
'toolUseResult' in msg &&
msg.toolUseResult !== undefined
) {
const { toolUseResult, ...rest } = msg as Message & {
toolUseResult: unknown
}
return rest as Message
}
return msg
})
}
/**
* Annotate a compact boundary with relink metadata for messagesToKeep.
* Preserved messages keep their original parentUuids on disk (dedup-skipped);