Agent: unify bootstrap truncation warning handling (#32769)

Merged via squash.

Prepared head SHA: 5d6d4ddfa6
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
Gustavo Madeira Santana
2026-03-03 16:28:38 -05:00
committed by GitHub
parent 3ad3a90db3
commit e4b4486a96
34 changed files with 1488 additions and 224 deletions

View File

@@ -1,6 +1,6 @@
import path from "node:path";
import type { AgentTool } from "@mariozechner/pi-agent-core";
import type { SessionSystemPromptReport } from "../config/sessions/types.js";
import { buildBootstrapInjectionStats } from "./bootstrap-budget.js";
import type { EmbeddedContextFile } from "./pi-embedded-helpers.js";
import type { WorkspaceBootstrapFile } from "./workspace.js";
@@ -36,46 +36,6 @@ function parseSkillBlocks(skillsPrompt: string): Array<{ name: string; blockChar
.filter((b) => b.blockChars > 0);
}
function buildInjectedWorkspaceFiles(params: {
bootstrapFiles: WorkspaceBootstrapFile[];
injectedFiles: EmbeddedContextFile[];
}): SessionSystemPromptReport["injectedWorkspaceFiles"] {
const injectedByPath = new Map<string, string>();
const injectedByBaseName = new Map<string, string>();
for (const file of params.injectedFiles) {
const pathValue = typeof file.path === "string" ? file.path.trim() : "";
if (!pathValue) {
continue;
}
if (!injectedByPath.has(pathValue)) {
injectedByPath.set(pathValue, file.content);
}
const normalizedPath = pathValue.replace(/\\/g, "/");
const baseName = path.posix.basename(normalizedPath);
if (!injectedByBaseName.has(baseName)) {
injectedByBaseName.set(baseName, file.content);
}
}
return params.bootstrapFiles.map((file) => {
const pathValue = typeof file.path === "string" ? file.path.trim() : "";
const rawChars = file.missing ? 0 : (file.content ?? "").trimEnd().length;
const injected =
(pathValue ? injectedByPath.get(pathValue) : undefined) ??
injectedByPath.get(file.name) ??
injectedByBaseName.get(file.name);
const injectedChars = injected ? injected.length : 0;
const truncated = !file.missing && injectedChars < rawChars;
return {
name: file.name,
path: pathValue || file.name,
missing: file.missing,
rawChars,
injectedChars,
truncated,
};
});
}
function buildToolsEntries(tools: AgentTool[]): SessionSystemPromptReport["tools"]["entries"] {
return tools.map((tool) => {
const name = tool.name;
@@ -127,6 +87,7 @@ export function buildSystemPromptReport(params: {
workspaceDir?: string;
bootstrapMaxChars: number;
bootstrapTotalMaxChars?: number;
bootstrapTruncation?: SessionSystemPromptReport["bootstrapTruncation"];
sandbox?: SessionSystemPromptReport["sandbox"];
systemPrompt: string;
bootstrapFiles: WorkspaceBootstrapFile[];
@@ -157,13 +118,14 @@ export function buildSystemPromptReport(params: {
workspaceDir: params.workspaceDir,
bootstrapMaxChars: params.bootstrapMaxChars,
bootstrapTotalMaxChars: params.bootstrapTotalMaxChars,
...(params.bootstrapTruncation ? { bootstrapTruncation: params.bootstrapTruncation } : {}),
sandbox: params.sandbox,
systemPrompt: {
chars: systemPrompt.length,
projectContextChars,
nonProjectContextChars: Math.max(0, systemPrompt.length - projectContextChars),
},
injectedWorkspaceFiles: buildInjectedWorkspaceFiles({
injectedWorkspaceFiles: buildBootstrapInjectionStats({
bootstrapFiles: params.bootstrapFiles,
injectedFiles: params.injectedFiles,
}),