feat: add dynamic truncation to rules/readme/agents injectors (#257)
- Apply dynamic truncation to rules-injector, directory-readme-injector, and directory-agents-injector - Add truncation notice encouraging users to read full content - Save context window space while maintaining awareness of complete documentation - Resolves #221 (part 1) Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
clearInjectedPaths,
|
||||
} from "./storage";
|
||||
import { AGENTS_FILENAME } from "./constants";
|
||||
import { createDynamicTruncator } from "../../shared/dynamic-truncator";
|
||||
|
||||
interface ToolExecuteInput {
|
||||
tool: string;
|
||||
@@ -39,6 +40,7 @@ interface EventInput {
|
||||
export function createDirectoryAgentsInjectorHook(ctx: PluginInput) {
|
||||
const sessionCaches = new Map<string, Set<string>>();
|
||||
const pendingBatchReads = new Map<string, string[]>();
|
||||
const truncator = createDynamicTruncator(ctx);
|
||||
|
||||
function getSessionCache(sessionID: string): Set<string> {
|
||||
if (!sessionCaches.has(sessionID)) {
|
||||
@@ -73,11 +75,11 @@ export function createDirectoryAgentsInjectorHook(ctx: PluginInput) {
|
||||
return found.reverse();
|
||||
}
|
||||
|
||||
function processFilePathForInjection(
|
||||
async function processFilePathForInjection(
|
||||
filePath: string,
|
||||
sessionID: string,
|
||||
output: ToolExecuteOutput,
|
||||
): void {
|
||||
): Promise<void> {
|
||||
const resolved = resolveFilePath(filePath);
|
||||
if (!resolved) return;
|
||||
|
||||
@@ -91,7 +93,11 @@ export function createDirectoryAgentsInjectorHook(ctx: PluginInput) {
|
||||
|
||||
try {
|
||||
const content = readFileSync(agentsPath, "utf-8");
|
||||
output.output += `\n\n[Directory Context: ${agentsPath}]\n${content}`;
|
||||
const { result, truncated } = await truncator.truncate(sessionID, content);
|
||||
const truncationNotice = truncated
|
||||
? `\n\n[Note: Content was truncated to save context window space. For full context, please read the file directly: ${agentsPath}]`
|
||||
: "";
|
||||
output.output += `\n\n[Directory Context: ${agentsPath}]\n${result}${truncationNotice}`;
|
||||
cache.add(agentsDir);
|
||||
} catch {}
|
||||
}
|
||||
@@ -127,7 +133,7 @@ export function createDirectoryAgentsInjectorHook(ctx: PluginInput) {
|
||||
const toolName = input.tool.toLowerCase();
|
||||
|
||||
if (toolName === "read") {
|
||||
processFilePathForInjection(output.title, input.sessionID, output);
|
||||
await processFilePathForInjection(output.title, input.sessionID, output);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -135,7 +141,7 @@ export function createDirectoryAgentsInjectorHook(ctx: PluginInput) {
|
||||
const filePaths = pendingBatchReads.get(input.callID);
|
||||
if (filePaths) {
|
||||
for (const filePath of filePaths) {
|
||||
processFilePathForInjection(filePath, input.sessionID, output);
|
||||
await processFilePathForInjection(filePath, input.sessionID, output);
|
||||
}
|
||||
pendingBatchReads.delete(input.callID);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
clearInjectedPaths,
|
||||
} from "./storage";
|
||||
import { README_FILENAME } from "./constants";
|
||||
import { createDynamicTruncator } from "../../shared/dynamic-truncator";
|
||||
|
||||
interface ToolExecuteInput {
|
||||
tool: string;
|
||||
@@ -39,6 +40,7 @@ interface EventInput {
|
||||
export function createDirectoryReadmeInjectorHook(ctx: PluginInput) {
|
||||
const sessionCaches = new Map<string, Set<string>>();
|
||||
const pendingBatchReads = new Map<string, string[]>();
|
||||
const truncator = createDynamicTruncator(ctx);
|
||||
|
||||
function getSessionCache(sessionID: string): Set<string> {
|
||||
if (!sessionCaches.has(sessionID)) {
|
||||
@@ -73,11 +75,11 @@ export function createDirectoryReadmeInjectorHook(ctx: PluginInput) {
|
||||
return found.reverse();
|
||||
}
|
||||
|
||||
function processFilePathForInjection(
|
||||
async function processFilePathForInjection(
|
||||
filePath: string,
|
||||
sessionID: string,
|
||||
output: ToolExecuteOutput,
|
||||
): void {
|
||||
): Promise<void> {
|
||||
const resolved = resolveFilePath(filePath);
|
||||
if (!resolved) return;
|
||||
|
||||
@@ -91,7 +93,11 @@ export function createDirectoryReadmeInjectorHook(ctx: PluginInput) {
|
||||
|
||||
try {
|
||||
const content = readFileSync(readmePath, "utf-8");
|
||||
output.output += `\n\n[Project README: ${readmePath}]\n${content}`;
|
||||
const { result, truncated } = await truncator.truncate(sessionID, content);
|
||||
const truncationNotice = truncated
|
||||
? `\n\n[Note: Content was truncated to save context window space. For full context, please read the file directly: ${readmePath}]`
|
||||
: "";
|
||||
output.output += `\n\n[Project README: ${readmePath}]\n${result}${truncationNotice}`;
|
||||
cache.add(readmeDir);
|
||||
} catch {}
|
||||
}
|
||||
@@ -127,7 +133,7 @@ export function createDirectoryReadmeInjectorHook(ctx: PluginInput) {
|
||||
const toolName = input.tool.toLowerCase();
|
||||
|
||||
if (toolName === "read") {
|
||||
processFilePathForInjection(output.title, input.sessionID, output);
|
||||
await processFilePathForInjection(output.title, input.sessionID, output);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -135,7 +141,7 @@ export function createDirectoryReadmeInjectorHook(ctx: PluginInput) {
|
||||
const filePaths = pendingBatchReads.get(input.callID);
|
||||
if (filePaths) {
|
||||
for (const filePath of filePaths) {
|
||||
processFilePathForInjection(filePath, input.sessionID, output);
|
||||
await processFilePathForInjection(filePath, input.sessionID, output);
|
||||
}
|
||||
pendingBatchReads.delete(input.callID);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
loadInjectedRules,
|
||||
saveInjectedRules,
|
||||
} from "./storage";
|
||||
import { createDynamicTruncator } from "../../shared/dynamic-truncator";
|
||||
|
||||
interface ToolExecuteInput {
|
||||
tool: string;
|
||||
@@ -59,6 +60,7 @@ export function createRulesInjectorHook(ctx: PluginInput) {
|
||||
{ contentHashes: Set<string>; realPaths: Set<string> }
|
||||
>();
|
||||
const pendingBatchFiles = new Map<string, string[]>();
|
||||
const truncator = createDynamicTruncator(ctx);
|
||||
|
||||
function getSessionCache(sessionID: string): {
|
||||
contentHashes: Set<string>;
|
||||
@@ -76,11 +78,11 @@ export function createRulesInjectorHook(ctx: PluginInput) {
|
||||
return resolve(ctx.directory, path);
|
||||
}
|
||||
|
||||
function processFilePathForInjection(
|
||||
async function processFilePathForInjection(
|
||||
filePath: string,
|
||||
sessionID: string,
|
||||
output: ToolExecuteOutput
|
||||
): void {
|
||||
): Promise<void> {
|
||||
const resolved = resolveFilePath(filePath);
|
||||
if (!resolved) return;
|
||||
|
||||
@@ -125,7 +127,11 @@ export function createRulesInjectorHook(ctx: PluginInput) {
|
||||
toInject.sort((a, b) => a.distance - b.distance);
|
||||
|
||||
for (const rule of toInject) {
|
||||
output.output += `\n\n[Rule: ${rule.relativePath}]\n[Match: ${rule.matchReason}]\n${rule.content}`;
|
||||
const { result, truncated } = await truncator.truncate(sessionID, rule.content);
|
||||
const truncationNotice = truncated
|
||||
? `\n\n[Note: Content was truncated to save context window space. For full context, please read the file directly: ${rule.relativePath}]`
|
||||
: "";
|
||||
output.output += `\n\n[Rule: ${rule.relativePath}]\n[Match: ${rule.matchReason}]\n${result}${truncationNotice}`;
|
||||
}
|
||||
|
||||
saveInjectedRules(sessionID, cache);
|
||||
@@ -167,7 +173,7 @@ export function createRulesInjectorHook(ctx: PluginInput) {
|
||||
const toolName = input.tool.toLowerCase();
|
||||
|
||||
if (TRACKED_TOOLS.includes(toolName)) {
|
||||
processFilePathForInjection(output.title, input.sessionID, output);
|
||||
await processFilePathForInjection(output.title, input.sessionID, output);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -175,7 +181,7 @@ export function createRulesInjectorHook(ctx: PluginInput) {
|
||||
const filePaths = pendingBatchFiles.get(input.callID);
|
||||
if (filePaths) {
|
||||
for (const filePath of filePaths) {
|
||||
processFilePathForInjection(filePath, input.sessionID, output);
|
||||
await processFilePathForInjection(filePath, input.sessionID, output);
|
||||
}
|
||||
pendingBatchFiles.delete(input.callID);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user