feat: preserve read_file context across pruning with file-read summary injection
This commit is contained in:
@@ -150,6 +150,11 @@ async function runOllamaLoop(ctx: AgentRunContext): Promise<AgentResult> {
|
|||||||
let addedContinueNudge = false;
|
let addedContinueNudge = false;
|
||||||
let reportProgressCount = 0;
|
let reportProgressCount = 0;
|
||||||
let selectedModeName = "";
|
let selectedModeName = "";
|
||||||
|
// Accumulates content previews from read_file calls so that when tool
|
||||||
|
// messages are pruned under context pressure, the model retains a compact
|
||||||
|
// summary of what it already read. User messages survive pruning.
|
||||||
|
const readFileLog = new Map<string, string>(); // path → content excerpt
|
||||||
|
let injectedFileReadSummary = false;
|
||||||
|
|
||||||
while (iterations < MAX_ITERATIONS) {
|
while (iterations < MAX_ITERATIONS) {
|
||||||
iterations++;
|
iterations++;
|
||||||
@@ -205,6 +210,22 @@ async function runOllamaLoop(ctx: AgentRunContext): Promise<AgentResult> {
|
|||||||
);
|
);
|
||||||
if (promptTokens > numCtx * 0.77) {
|
if (promptTokens > numCtx * 0.77) {
|
||||||
messages = pruneToolMessages(messages);
|
messages = pruneToolMessages(messages);
|
||||||
|
// Inject a compact summary of all files read so far as a user message
|
||||||
|
// so the model retains the context even after tool messages are pruned.
|
||||||
|
// Only inject once — subsequent prune events leave this message intact.
|
||||||
|
if (readFileLog.size > 0 && !injectedFileReadSummary) {
|
||||||
|
injectedFileReadSummary = true;
|
||||||
|
const entries = [...readFileLog.entries()]
|
||||||
|
.map(([p, c]) => `### ${p}\n${c}`)
|
||||||
|
.join("\n\n");
|
||||||
|
messages.push({
|
||||||
|
role: "user",
|
||||||
|
content:
|
||||||
|
`The following files were read earlier but their content was pruned from context. ` +
|
||||||
|
`Use these excerpts as your understanding of each file when writing the review:\n\n${entries}`,
|
||||||
|
});
|
||||||
|
log.info(`» injected file-read summary: ${readFileLog.size} file(s)`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,6 +306,39 @@ async function runOllamaLoop(ctx: AgentRunContext): Promise<AgentResult> {
|
|||||||
content: result,
|
content: result,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Track read_file calls so we can reconstruct context after pruning.
|
||||||
|
if (toolName === "read_file") {
|
||||||
|
const path = (toolArgs as Record<string, unknown>)?.path;
|
||||||
|
if (typeof path === "string" && !readFileLog.has(path)) {
|
||||||
|
readFileLog.set(path, result.slice(0, 500));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// After checkout_pr returns, extract and pin the diffPath as a user
|
||||||
|
// message. Only tool messages are pruned — user messages survive context
|
||||||
|
// pressure — so the model retains the exact diff file path and knows how
|
||||||
|
// to call read_file with offset/limit to read diff ranges.
|
||||||
|
if (toolName === "checkout_pr") {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(result) as Record<string, unknown>;
|
||||||
|
if (typeof parsed?.diffPath === "string") {
|
||||||
|
const dp = parsed.diffPath;
|
||||||
|
messages.push({
|
||||||
|
role: "user",
|
||||||
|
content:
|
||||||
|
`The diff file is at: ${dp}\n\n` +
|
||||||
|
`Read each file's diff by calling read_file on this path with the line range from the TOC.\n` +
|
||||||
|
`Example — for "device.ts (163 lines, 1146-1308)": read_file(path="${dp}", offset=1146, limit=163)\n` +
|
||||||
|
`IMPORTANT: Do NOT call read_file on source files (apps/..., packages/...). ` +
|
||||||
|
`Use read_file on the diff file path above with the TOC ranges.`,
|
||||||
|
});
|
||||||
|
log.info(`» pinned diffPath to context: ${dp}`);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// best-effort: if checkout_pr result isn't JSON, skip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// report_progress called more than once means the model is looping —
|
// report_progress called more than once means the model is looping —
|
||||||
// it has no signal to stop since the tool always returns success.
|
// it has no signal to stop since the tool always returns success.
|
||||||
if (toolName === "report_progress") {
|
if (toolName === "report_progress") {
|
||||||
|
|||||||
Reference in New Issue
Block a user