Skip to content

Commit ee50658

Browse files
fix: attach compression timing to blocks
1 parent 5bd90e7 commit ee50658

10 files changed

Lines changed: 230 additions & 173 deletions

File tree

lib/compress/message.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import { finalizeSession, prepareSession, type NotificationEntry } from "./pipel
77
import { appendProtectedTools } from "./protected-content"
88
import {
99
allocateBlockId,
10-
consumeCompressionDuration,
11-
getCompressionMessageKey,
1210
allocateRunId,
1311
applyCompressionState,
1412
wrapCompressedSummary,
@@ -96,11 +94,6 @@ export function createCompressMessageTool(ctx: ToolContext): ReturnType<typeof t
9694
})
9795
}
9896

99-
const durationMs = consumeCompressionDuration(
100-
ctx.state,
101-
getCompressionMessageKey(toolCtx.sessionID, toolCtx.messageID),
102-
callId,
103-
)
10497
const runId = allocateRunId(ctx.state)
10598

10699
for (const { plan, summaryWithTools } of preparedPlans) {
@@ -118,8 +111,9 @@ export function createCompressMessageTool(ctx: ToolContext): ReturnType<typeof t
118111
mode: "message",
119112
runId,
120113
compressMessageId: toolCtx.messageID,
114+
compressCallId: callId,
121115
summaryTokens,
122-
durationMs,
116+
durationMs: 0,
123117
},
124118
plan.selection,
125119
plan.anchorMessageId,

lib/compress/range.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ import {
1616
import {
1717
COMPRESSED_BLOCK_HEADER,
1818
allocateBlockId,
19-
consumeCompressionDuration,
20-
getCompressionMessageKey,
2119
allocateRunId,
2220
applyCompressionState,
2321
wrapCompressedSummary,
@@ -137,11 +135,6 @@ export function createCompressRangeTool(ctx: ToolContext): ReturnType<typeof too
137135
})
138136
}
139137

140-
const durationMs = consumeCompressionDuration(
141-
ctx.state,
142-
getCompressionMessageKey(toolCtx.sessionID, toolCtx.messageID),
143-
callId,
144-
)
145138
const runId = allocateRunId(ctx.state)
146139

147140
for (const preparedPlan of preparedPlans) {
@@ -159,8 +152,9 @@ export function createCompressRangeTool(ctx: ToolContext): ReturnType<typeof too
159152
mode: "range",
160153
runId,
161154
compressMessageId: toolCtx.messageID,
155+
compressCallId: callId,
162156
summaryTokens,
163-
durationMs,
157+
durationMs: 0,
164158
},
165159
preparedPlan.selection,
166160
preparedPlan.anchorMessageId,

lib/compress/state.ts

Lines changed: 19 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@ import type { AppliedCompressionResult, CompressionStateInput, SelectionResoluti
44

55
export const COMPRESSED_BLOCK_HEADER = "[Compressed conversation section]"
66

7-
export function getCompressionMessageKey(sessionId: string, messageId: string): string {
8-
return `${sessionId}:${messageId}`
9-
}
10-
117
export function allocateBlockId(state: SessionState): number {
128
const next = state.prune.messages.nextBlockId
139
if (!Number.isInteger(next) || next < 1) {
@@ -33,54 +29,36 @@ export function allocateRunId(state: SessionState): number {
3329
export function recordCompressionDuration(
3430
state: SessionState,
3531
callId: string,
36-
messageKey: string,
3732
durationMs: number,
3833
): void {
3934
state.compressionDurations.set(callId, durationMs)
40-
41-
const queue = state.compressionDurationQueue.get(messageKey)
42-
if (!queue) {
43-
state.compressionDurationQueue.set(messageKey, [callId])
44-
return
45-
}
46-
47-
queue.push(callId)
4835
}
4936

50-
export function consumeCompressionDuration(
37+
export function attachCompressionDuration(
5138
state: SessionState,
52-
messageKey: string,
53-
callId?: string,
39+
callId: string,
40+
messageId: string,
5441
): number {
55-
if (callId && state.compressionDurations.has(callId)) {
56-
const queue = state.compressionDurationQueue.get(messageKey)
57-
if (queue) {
58-
const next = queue.filter((id) => id !== callId)
59-
if (next.length === 0) {
60-
state.compressionDurationQueue.delete(messageKey)
61-
} else {
62-
state.compressionDurationQueue.set(messageKey, next)
63-
}
64-
}
65-
66-
const durationMs = state.compressionDurations.get(callId) || 0
67-
state.compressionDurations.delete(callId)
68-
return durationMs
42+
const durationMs = state.compressionDurations.get(callId)
43+
if (typeof durationMs !== "number" || !Number.isFinite(durationMs)) {
44+
return 0
6945
}
7046

71-
const queue = state.compressionDurationQueue.get(messageKey)
72-
const queuedCallId = queue?.shift()
73-
if (queue && queue.length === 0) {
74-
state.compressionDurationQueue.delete(messageKey)
75-
}
47+
state.compressionDurations.delete(callId)
7648

77-
if (!queuedCallId) {
78-
return 0
49+
let updates = 0
50+
for (const block of state.prune.messages.blocksById.values()) {
51+
const matchesCall = block.compressCallId === callId
52+
const matchesMessage = !block.compressCallId && block.compressMessageId === messageId
53+
if (!matchesCall && !matchesMessage) {
54+
continue
55+
}
56+
57+
block.durationMs = durationMs
58+
updates++
7959
}
8060

81-
const durationMs = state.compressionDurations.get(queuedCallId) || 0
82-
state.compressionDurations.delete(queuedCallId)
83-
return durationMs
61+
return updates
8462
}
8563

8664
export function wrapCompressedSummary(blockId: number, summary: string): string {
@@ -158,6 +136,7 @@ export function applyCompressionState(
158136
endId: input.endId,
159137
anchorMessageId,
160138
compressMessageId: input.compressMessageId,
139+
compressCallId: input.compressCallId,
161140
includedBlockIds: included,
162141
consumedBlockIds: consumed,
163142
parentBlockIds: [],

lib/compress/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ export interface CompressionStateInput {
102102
mode: CompressionMode
103103
runId: number
104104
compressMessageId: string
105+
compressCallId?: string
105106
summaryTokens: number
106107
durationMs: number
107108
}

lib/hooks.ts

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
} from "./messages"
1717
import { renderSystemPrompt, type PromptStore } from "./prompts"
1818
import { buildProtectedToolsExtension } from "./prompts/extensions/system"
19-
import { getCompressionMessageKey, recordCompressionDuration } from "./compress/state"
19+
import { attachCompressionDuration, recordCompressionDuration } from "./compress/state"
2020
import {
2121
applyPendingManualTrigger,
2222
handleContextCommand,
@@ -30,7 +30,7 @@ import {
3030
} from "./commands"
3131
import { type HostPermissionSnapshot } from "./host-permissions"
3232
import { compressPermission, syncCompressPermissionState } from "./compress-permission"
33-
import { checkSession, ensureSessionInitialized, syncToolCache } from "./state"
33+
import { checkSession, ensureSessionInitialized, saveSessionState, syncToolCache } from "./state"
3434
import { cacheSystemPromptTokens } from "./ui/utils"
3535

3636
const INTERNAL_AGENT_SIGNATURES = [
@@ -317,12 +317,7 @@ export function createEventHandler(state: SessionState, logger: Logger) {
317317

318318
state.compressionStarts.delete(part.callID)
319319
const durationMs = Math.max(0, runningAt - start.startedAt)
320-
recordCompressionDuration(
321-
state,
322-
part.callID,
323-
getCompressionMessageKey(part.sessionID, start.messageId),
324-
durationMs,
325-
)
320+
recordCompressionDuration(state, part.callID, durationMs)
326321

327322
logger.info("Recorded compression time", {
328323
callID: part.callID,
@@ -332,8 +327,33 @@ export function createEventHandler(state: SessionState, logger: Logger) {
332327
return
333328
}
334329

330+
if (part.state.status === "completed") {
331+
if (typeof part.callID !== "string" || typeof part.messageID !== "string") {
332+
return
333+
}
334+
335+
const updates = attachCompressionDuration(state, part.callID, part.messageID)
336+
if (updates === 0) {
337+
return
338+
}
339+
340+
logger.info("Attached compression time to blocks", {
341+
callID: part.callID,
342+
messageID: part.messageID,
343+
blocks: updates,
344+
})
345+
346+
saveSessionState(state, logger).catch((error) => {
347+
logger.warn("Failed to persist compression time update", {
348+
error: error instanceof Error ? error.message : String(error),
349+
})
350+
})
351+
return
352+
}
353+
335354
if (typeof part.callID === "string") {
336355
state.compressionStarts.delete(part.callID)
356+
state.compressionDurations.delete(part.callID)
337357
}
338358
}
339359
}

lib/state/state.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ export function createSessionState(): SessionState {
8383
},
8484
compressionStarts: new Map<string, CompressionStart>(),
8585
compressionDurations: new Map<string, number>(),
86-
compressionDurationQueue: new Map<string, string[]>(),
8786
toolParameters: new Map<string, ToolParameterEntry>(),
8887
subAgentResultCache: new Map<string, string>(),
8988
toolIdList: [],

lib/state/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export interface CompressionBlock {
4949
endId: string
5050
anchorMessageId: string
5151
compressMessageId: string
52+
compressCallId?: string
5253
includedBlockIds: number[]
5354
consumedBlockIds: number[]
5455
parentBlockIds: number[]
@@ -104,7 +105,6 @@ export interface SessionState {
104105
stats: SessionStats
105106
compressionStarts: Map<string, CompressionStart>
106107
compressionDurations: Map<string, number>
107-
compressionDurationQueue: Map<string, string[]>
108108
toolParameters: Map<string, ToolParameterEntry>
109109
subAgentResultCache: Map<string, string>
110110
toolIdList: string[]

lib/state/utils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ export function loadPruneMessagesState(
196196
typeof block.anchorMessageId === "string" ? block.anchorMessageId : "",
197197
compressMessageId:
198198
typeof block.compressMessageId === "string" ? block.compressMessageId : "",
199+
compressCallId:
200+
typeof block.compressCallId === "string" ? block.compressCallId : undefined,
199201
includedBlockIds: toNumberArray(block.includedBlockIds),
200202
consumedBlockIds: toNumberArray(block.consumedBlockIds),
201203
parentBlockIds: toNumberArray(block.parentBlockIds),

0 commit comments

Comments
 (0)