MCPcopy Create free account
hub / github.com/QodeXcli/QodeX / compactFileReads

Function compactFileReads

src/agent/read-cache.ts:111–169  ·  view source on GitHub ↗
(messages: Message[], opts: ReadCacheOptions = {})

Source from the content-addressed store, hash-verified

109 * mutated); array length and message order are preserved.
110 */
111export function compactFileReads(messages: Message[], opts: ReadCacheOptions = {}): Message[] {
112 if (!Array.isArray(messages) || messages.length === 0) return messages;
113 const recentWindow = opts.recentWindow ?? 24;
114
115 // 1) tool_call_id -> ReadTarget, from assistant tool_calls that name a read tool.
116 const targetById = new Map<string, ReadTarget>();
117 for (const m of messages) {
118 if (m.role !== 'assistant' || !Array.isArray(m.tool_calls)) continue;
119 for (const tc of m.tool_calls) {
120 if (!tc?.function || !READ_TOOLS.has(tc.function.name)) continue;
121 const t = readTargetFor(parseArgs(tc.function.arguments));
122 if (t) targetById.set(tc.id, t);
123 }
124 }
125 if (targetById.size === 0) return messages;
126
127 // 2) read tool-result messages, in order.
128 const reads: Array<{ idx: number; t: ReadTarget }> = [];
129 messages.forEach((m, idx) => {
130 if (m.role === 'tool' && m.tool_call_id && targetById.has(m.tool_call_id)) {
131 reads.push({ idx, t: targetById.get(m.tool_call_id)! });
132 }
133 });
134 if (reads.length === 0) return messages;
135
136 // 3) superseded: an earlier read covered by a LATER read of the same path
137 // (later full read, or later identical slice).
138 const superseded = new Set<number>();
139 for (let i = 0; i < reads.length; i++) {
140 for (let j = i + 1; j < reads.length; j++) {
141 if (reads[j].t.path !== reads[i].t.path) continue;
142 if (reads[j].t.full || reads[j].t.key === reads[i].t.key) {
143 superseded.add(reads[i].idx);
144 break;
145 }
146 }
147 }
148
149 // 4) rewrite. Superseded → lossless stub (any age). Else, if aging is on and the
150 // read is older than the recent window → outline stub.
151 const boundary = messages.length - recentWindow;
152 const idxToTarget = new Map(reads.map(r => [r.idx, r.t]));
153 let changed = false;
154 const out = messages.map((m, idx) => {
155 const t = idxToTarget.get(idx);
156 if (!t) return m;
157 if (isStub(m.content)) return m; // already compacted on a prior pass
158 if (superseded.has(idx)) {
159 changed = true;
160 return { ...m, content: supersededStub(t.path) };
161 }
162 if (opts.agingOutline && idx < boundary) {
163 changed = true;
164 return { ...m, content: agedStub(t.path, m.content) };
165 }
166 return m;
167 });
168 return changed ? out : messages;

Callers 2

read-cache.test.tsFile · 0.85
runMethod · 0.85

Calls 10

readTargetForFunction · 0.85
parseArgsFunction · 0.85
supersededStubFunction · 0.85
agedStubFunction · 0.85
addMethod · 0.80
isStubFunction · 0.70
hasMethod · 0.45
setMethod · 0.45
pushMethod · 0.45
getMethod · 0.45

Tested by

no test coverage detected