mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-28 23:06:48 +00:00
* fix(bootstrap): guard bootstrap name checks against undefined names Add optional chaining to isAgentsBootstrapFile and isAgentsBootstrapName to prevent TypeError: Cannot read properties of undefined (reading 'toLowerCase') when bootstrap file entries have undefined name properties. This crash was observed in 2026.5.20 where a workspace bootstrap file entry with an undefined name caused every incoming message to fail during bootstrap context building, completely blocking all agent replies. Fixes #85523 * test(agents): cover unnamed bootstrap truncation entries * test(agents): keep bootstrap truncation fixture typed --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
@@ -103,6 +103,29 @@ describe("analyzeBootstrapBudget", () => {
|
||||
});
|
||||
|
||||
describe("bootstrap prompt warnings", () => {
|
||||
it("handles malformed truncation entries without names", () => {
|
||||
const analysis = analyzeBootstrapBudget({
|
||||
files: [
|
||||
{
|
||||
name: "TEMP.md",
|
||||
path: "/tmp/unknown",
|
||||
missing: false,
|
||||
rawChars: 10,
|
||||
injectedChars: 1,
|
||||
truncated: true,
|
||||
},
|
||||
],
|
||||
bootstrapMaxChars: 5,
|
||||
bootstrapTotalMaxChars: 5,
|
||||
});
|
||||
(analysis.truncatedFiles[0] as { name?: string }).name = undefined;
|
||||
|
||||
const lines = formatBootstrapTruncationWarningLines({
|
||||
analysis,
|
||||
});
|
||||
expect(lines.join("\n")).toContain("10 raw -> 1 injected");
|
||||
});
|
||||
|
||||
it("appends warning details to the turn prompt instead of mutating the system prompt", () => {
|
||||
const prompt = appendBootstrapPromptWarning("Please continue.", [
|
||||
"AGENTS.md: 200 raw -> 0 injected",
|
||||
|
||||
@@ -68,8 +68,8 @@ function formatWarningCause(cause: BootstrapTruncationCause): string {
|
||||
return cause === "per-file-limit" ? "max/file" : "max/total";
|
||||
}
|
||||
|
||||
function isAgentsBootstrapName(name: string): boolean {
|
||||
return name.toLowerCase() === "agents.md";
|
||||
function isAgentsBootstrapName(name: string | undefined): boolean {
|
||||
return name?.toLowerCase() === "agents.md";
|
||||
}
|
||||
|
||||
function normalizeSeenSignatures(signatures?: string[]): string[] {
|
||||
|
||||
@@ -241,6 +241,21 @@ describe("buildBootstrapContextFiles", () => {
|
||||
warnings.filter((warning) => !warning.includes('missing or invalid "path" field')),
|
||||
).toStrictEqual([]);
|
||||
});
|
||||
|
||||
it("handles undefined file names without crashing", () => {
|
||||
const fileWithUndefinedName = {
|
||||
name: undefined,
|
||||
path: "/tmp/test.md",
|
||||
content: "content",
|
||||
missing: false,
|
||||
} as unknown as WorkspaceBootstrapFile;
|
||||
const warnings: string[] = [];
|
||||
const result = buildBootstrapContextFiles([fileWithUndefinedName], {
|
||||
warn: (msg) => warnings.push(msg),
|
||||
});
|
||||
expect(result).toBeDefined();
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
type BootstrapLimitResolverCase = {
|
||||
|
||||
@@ -151,8 +151,8 @@ export function resolveBootstrapPromptTruncationWarningMode(
|
||||
return DEFAULT_BOOTSTRAP_PROMPT_TRUNCATION_WARNING_MODE;
|
||||
}
|
||||
|
||||
function isAgentsBootstrapFile(fileName: string): boolean {
|
||||
return fileName.toLowerCase() === AGENTS_BOOTSTRAP_FILENAME.toLowerCase();
|
||||
function isAgentsBootstrapFile(fileName: string | undefined): boolean {
|
||||
return fileName?.toLowerCase() === AGENTS_BOOTSTRAP_FILENAME.toLowerCase();
|
||||
}
|
||||
|
||||
function isPolicyDigestCandidate(line: string): boolean {
|
||||
|
||||
Reference in New Issue
Block a user