Skip to content

Commit 0706e36

Browse files
taetaetaetaetaetae-woowahan
authored andcommitted
feat(context-window-monitor): add progressive warnings at 50%, 60%, 70%, 80%
- Replace single 70% threshold with stepped warnings - Add ANSI color coding for visual urgency (blue → yellow → orange → red) - Track notified thresholds per session to avoid duplicate alerts - Each threshold triggers once with appropriate urgency level: - 50% INFO: checkpoint notification - 60% NOTICE: awareness notification - 70% WARNING: caution notification - 80% CRITICAL: urgent action needed
1 parent 96e7b39 commit 0706e36

File tree

1 file changed

+73
-17
lines changed

1 file changed

+73
-17
lines changed

src/hooks/context-window-monitor.ts

Lines changed: 73 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,59 @@ const ANTHROPIC_ACTUAL_LIMIT =
77
process.env.VERTEX_ANTHROPIC_1M_CONTEXT === "true"
88
? 1_000_000
99
: 200_000
10-
const CONTEXT_WARNING_THRESHOLD = 0.70
1110

12-
const CONTEXT_REMINDER = `${createSystemDirective(SystemDirectiveTypes.CONTEXT_WINDOW_MONITOR)}
11+
const PROGRESSIVE_WARNING_THRESHOLDS = [0.50, 0.60, 0.70, 0.80] as const
12+
13+
type ThresholdLevel = (typeof PROGRESSIVE_WARNING_THRESHOLDS)[number]
14+
15+
const ANSI = {
16+
RESET: "\x1b[0m",
17+
BOLD: "\x1b[1m",
18+
BLUE: "\x1b[34m",
19+
YELLOW: "\x1b[33m",
20+
ORANGE: "\x1b[38;5;208m",
21+
RED: "\x1b[31m",
22+
BG_BLUE: "\x1b[44m",
23+
BG_YELLOW: "\x1b[43m",
24+
BG_ORANGE: "\x1b[48;5;208m",
25+
BG_RED: "\x1b[41m",
26+
WHITE: "\x1b[37m",
27+
} as const
28+
29+
const THRESHOLD_CONFIG: Record<ThresholdLevel, { emoji: string; urgency: string; color: string; bgColor: string }> = {
30+
0.50: { emoji: "📊", urgency: "INFO", color: ANSI.BLUE, bgColor: ANSI.BG_BLUE },
31+
0.60: { emoji: "📈", urgency: "NOTICE", color: ANSI.YELLOW, bgColor: ANSI.BG_YELLOW },
32+
0.70: { emoji: "⚠️", urgency: "WARNING", color: ANSI.ORANGE, bgColor: ANSI.BG_ORANGE },
33+
0.80: { emoji: "🚨", urgency: "CRITICAL", color: ANSI.RED, bgColor: ANSI.BG_RED },
34+
}
35+
36+
function createContextReminder(threshold: ThresholdLevel): string {
37+
const { emoji, urgency, color, bgColor } = THRESHOLD_CONFIG[threshold]
38+
const baseReminder = createSystemDirective(SystemDirectiveTypes.CONTEXT_WINDOW_MONITOR)
39+
40+
const coloredHeader = `${bgColor}${ANSI.WHITE}${ANSI.BOLD} ${emoji} [${urgency}] ${ANSI.RESET}${color}`
41+
42+
if (threshold >= 0.80) {
43+
return `${baseReminder}
44+
45+
${coloredHeader} Context window is running LOW!
46+
Consider wrapping up current task or preparing for session handoff.
47+
Prioritize completing critical work before context limit is reached.${ANSI.RESET}`
48+
}
49+
50+
if (threshold >= 0.70) {
51+
return `${baseReminder}
52+
53+
${coloredHeader} Context window usage is getting high.
54+
Continue working but be mindful of context consumption.
55+
Consider summarizing progress if approaching complex tasks.${ANSI.RESET}`
56+
}
1357

14-
You are using Anthropic Claude with 1M context window.
15-
You have plenty of context remaining - do NOT rush or skip tasks.
16-
Complete your work thoroughly and methodically.`
58+
return `${baseReminder}
59+
60+
${coloredHeader} Context window checkpoint.
61+
You have sufficient context remaining - continue working normally.${ANSI.RESET}`
62+
}
1763

1864
interface AssistantMessageInfo {
1965
role: "assistant"
@@ -31,16 +77,14 @@ interface MessageWrapper {
3177
}
3278

3379
export function createContextWindowMonitorHook(ctx: PluginInput) {
34-
const remindedSessions = new Set<string>()
80+
const notifiedThresholdsPerSession = new Map<string, Set<ThresholdLevel>>()
3581

3682
const toolExecuteAfter = async (
3783
input: { tool: string; sessionID: string; callID: string },
3884
output: { title: string; output: string; metadata: unknown }
3985
) => {
4086
const { sessionID } = input
4187

42-
if (remindedSessions.has(sessionID)) return
43-
4488
try {
4589
const response = await ctx.client.session.messages({
4690
path: { id: sessionID },
@@ -57,27 +101,39 @@ export function createContextWindowMonitorHook(ctx: PluginInput) {
57101
const lastAssistant = assistantMessages[assistantMessages.length - 1]
58102
if (lastAssistant.providerID !== "anthropic") return
59103

60-
// Use only the last assistant message's input tokens
61-
// This reflects the ACTUAL current context window usage (post-compaction)
62104
const lastTokens = lastAssistant.tokens
63105
const totalInputTokens = (lastTokens?.input ?? 0) + (lastTokens?.cache?.read ?? 0)
64-
65106
const actualUsagePercentage = totalInputTokens / ANTHROPIC_ACTUAL_LIMIT
66107

67-
if (actualUsagePercentage < CONTEXT_WARNING_THRESHOLD) return
108+
if (!notifiedThresholdsPerSession.has(sessionID)) {
109+
notifiedThresholdsPerSession.set(sessionID, new Set())
110+
}
111+
const sessionNotified = notifiedThresholdsPerSession.get(sessionID)!
68112

69-
remindedSessions.add(sessionID)
113+
let thresholdToNotify: ThresholdLevel | null = null
114+
for (const threshold of PROGRESSIVE_WARNING_THRESHOLDS) {
115+
if (actualUsagePercentage >= threshold && !sessionNotified.has(threshold)) {
116+
thresholdToNotify = threshold
117+
}
118+
}
119+
120+
if (thresholdToNotify === null) return
70121

122+
sessionNotified.add(thresholdToNotify)
123+
124+
const { color } = THRESHOLD_CONFIG[thresholdToNotify]
71125
const displayUsagePercentage = totalInputTokens / ANTHROPIC_DISPLAY_LIMIT
72126
const usedPct = (displayUsagePercentage * 100).toFixed(1)
73127
const remainingPct = ((1 - displayUsagePercentage) * 100).toFixed(1)
74128
const usedTokens = totalInputTokens.toLocaleString()
75129
const limitTokens = ANTHROPIC_DISPLAY_LIMIT.toLocaleString()
76130

77-
output.output += `\n\n${CONTEXT_REMINDER}
78-
[Context Status: ${usedPct}% used (${usedTokens}/${limitTokens} tokens), ${remainingPct}% remaining]`
131+
const reminder = createContextReminder(thresholdToNotify)
132+
133+
output.output += `\n\n${reminder}
134+
${color}[Context Status: ${usedPct}% used (${usedTokens}/${limitTokens} tokens), ${remainingPct}% remaining]${ANSI.RESET}`
79135
} catch {
80-
// Graceful degradation - do not disrupt tool execution
136+
// Graceful degradation
81137
}
82138
}
83139

@@ -87,7 +143,7 @@ export function createContextWindowMonitorHook(ctx: PluginInput) {
87143
if (event.type === "session.deleted") {
88144
const sessionInfo = props?.info as { id?: string } | undefined
89145
if (sessionInfo?.id) {
90-
remindedSessions.delete(sessionInfo.id)
146+
notifiedThresholdsPerSession.delete(sessionInfo.id)
91147
}
92148
}
93149
}

0 commit comments

Comments
 (0)