diff --git a/apps/x/packages/core/src/turns/context-elision.test.ts b/apps/x/packages/core/src/turns/context-elision.test.ts index 0864d206..19f9c5ef 100644 --- a/apps/x/packages/core/src/turns/context-elision.test.ts +++ b/apps/x/packages/core/src/turns/context-elision.test.ts @@ -179,6 +179,18 @@ describe("elideHistoricToolResults", () => { expect(elided[0].content).toContain("101"); }); + it("keeps a head preview ahead of the placeholder", () => { + const content = `SKILL GUIDE${"y".repeat(5000)}`; + const [elided] = elideHistoricToolResults([toolMsg(content)], 2500); + // Starts with the first 400 chars verbatim, then the marker. + expect(elided.content.startsWith(content.slice(0, 400))).toBe(true); + expect(elided.content).toContain("Rest of tool result elided"); + expect(elided.content.length).toBeLessThan(700); + // Preview never exceeds a tiny threshold. + const [tiny] = elideHistoricToolResults([toolMsg(content)], 50); + expect(tiny.content.startsWith(`${content.slice(0, 50)}\n[Rest`)).toBe(true); + }); + it("keeps tool results at or below the threshold verbatim", () => { const exact = toolMsg("x".repeat(100)); expect(elideHistoricToolResults([exact], 100)).toEqual([exact]); diff --git a/apps/x/packages/core/src/turns/context-elision.ts b/apps/x/packages/core/src/turns/context-elision.ts index 05fbfb43..22ff2d6f 100644 --- a/apps/x/packages/core/src/turns/context-elision.ts +++ b/apps/x/packages/core/src/turns/context-elision.ts @@ -54,6 +54,9 @@ export const DEFAULT_ELISION_POLICY: ElisionPolicy = { // placeholder saves nothing and a short note may carry useful context. const MIDDLE_PANE_CONTENT_FLOOR_CHARS = 500; +// Head of an elided tool result kept verbatim ahead of the placeholder. +const TOOL_RESULT_PREVIEW_CHARS = 400; + const ContextConfig = z.object({ elideHistoricToolResults: z.boolean().optional(), elideHistoricToolResultsThresholdChars: z.number().int().min(0).optional(), @@ -102,9 +105,16 @@ export function elideHistoricToolResults( ) { return message; } + // Keep a head preview so the model knows what it is declining to + // re-fetch (a skill body reads very differently from a web page). + // Capped at the threshold so tiny thresholds still shrink content. + const preview = message.content.slice( + 0, + Math.min(TOOL_RESULT_PREVIEW_CHARS, thresholdChars), + ); return { ...message, - content: `[Tool result elided to save context: "${message.toolName}" returned ${message.content.length} characters in an earlier turn. Call the tool again if you need this output now.]`, + content: `${preview}\n[Rest of tool result elided to save context: "${message.toolName}" returned ${message.content.length} characters in an earlier turn. Call the tool again if you need the full output now.]`, }; }); }