78 lines
3.7 KiB
TypeScript
78 lines
3.7 KiB
TypeScript
import { feature } from 'bun:bundle'
|
|
import type { QuerySource } from '../../constants/querySource.js'
|
|
import { clearSystemPromptSections } from '../../constants/systemPromptSections.js'
|
|
import { getUserContext } from '../../context.js'
|
|
import { clearSpeculativeChecks } from '../../tools/BashTool/bashPermissions.js'
|
|
import { clearClassifierApprovals } from '../../utils/classifierApprovals.js'
|
|
import { resetGetMemoryFilesCache } from '../../utils/claudemd.js'
|
|
import { clearSessionMessagesCache } from '../../utils/sessionStorage.js'
|
|
import { clearBetaTracingState } from '../../utils/telemetry/betaSessionTracing.js'
|
|
import { resetMicrocompactState } from './microCompact.js'
|
|
|
|
/**
|
|
* Run cleanup of caches and tracking state after compaction.
|
|
* Call this after both auto-compact and manual /compact to free memory
|
|
* held by tracking structures that are invalidated by compaction.
|
|
*
|
|
* Note: We intentionally do NOT clear invoked skill content here.
|
|
* Skill content must survive across multiple compactions so that
|
|
* createSkillAttachmentIfNeeded() can include the full skill text
|
|
* in subsequent compaction attachments.
|
|
*
|
|
* querySource: pass the compacting query's source so we can skip
|
|
* resets that would clobber main-thread module-level state. Subagents
|
|
* (agent:*) run in the same process and share module-level state
|
|
* (context-collapse store, getMemoryFiles one-shot hook flag,
|
|
* getUserContext cache); resetting those when a SUBAGENT compacts
|
|
* would corrupt the MAIN thread's state. All compaction callers should
|
|
* pass querySource — undefined is only safe for callers that are
|
|
* genuinely main-thread-only (/compact, /clear).
|
|
*/
|
|
export function runPostCompactCleanup(querySource?: QuerySource): void {
|
|
// Subagents (agent:*) run in the same process and share module-level
|
|
// state with the main thread. Only reset main-thread module-level state
|
|
// (context-collapse, memory file cache) for main-thread compacts.
|
|
// Same startsWith pattern as isMainThread (index.ts:188).
|
|
const isMainThreadCompact =
|
|
querySource === undefined ||
|
|
querySource.startsWith('repl_main_thread') ||
|
|
querySource === 'sdk'
|
|
|
|
resetMicrocompactState()
|
|
if (feature('CONTEXT_COLLAPSE')) {
|
|
if (isMainThreadCompact) {
|
|
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
;(
|
|
require('../contextCollapse/index.js') as typeof import('../contextCollapse/index.js')
|
|
).resetContextCollapse()
|
|
/* eslint-enable @typescript-eslint/no-require-imports */
|
|
}
|
|
}
|
|
if (isMainThreadCompact) {
|
|
// getUserContext is a memoized outer layer wrapping getClaudeMds() →
|
|
// getMemoryFiles(). If only the inner getMemoryFiles cache is cleared,
|
|
// the next turn hits the getUserContext cache and never reaches
|
|
// getMemoryFiles(), so the armed InstructionsLoaded hook never fires.
|
|
// Manual /compact already clears this explicitly at its call sites;
|
|
// auto-compact and reactive-compact did not — this centralizes the
|
|
// clear so all compaction paths behave consistently.
|
|
getUserContext.cache.clear?.()
|
|
resetGetMemoryFilesCache('compact')
|
|
}
|
|
clearSystemPromptSections()
|
|
clearClassifierApprovals()
|
|
clearSpeculativeChecks()
|
|
// Intentionally NOT calling resetSentSkillNames(): re-injecting the full
|
|
// skill_listing (~4K tokens) post-compact is pure cache_creation. The
|
|
// model still has SkillTool in schema, invoked_skills preserves used
|
|
// skills, and dynamic additions are handled by skillChangeDetector /
|
|
// cacheUtils resets. See compactConversation() for full rationale.
|
|
clearBetaTracingState()
|
|
if (feature('COMMIT_ATTRIBUTION')) {
|
|
void import('../../utils/attributionHooks.js').then(m =>
|
|
m.sweepFileContentCache(),
|
|
)
|
|
}
|
|
clearSessionMessagesCache()
|
|
}
|