fix: guard against undefined path in bootstrap file entries

The session-context hook pushed bootstrap entries without the required
`path` property, causing a TypeError in buildInjectedWorkspaceFiles when
it called .replace() on undefined. Add fallback to file.name when path
is missing, and skip entries with no path in the report builder.

Also add stack trace logging to lane task errors and embedded agent
failures to make future debugging faster.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Tarun Sukhani
2026-02-15 07:40:34 +08:00
parent fc92b05046
commit 0a55711110
4 changed files with 13 additions and 5 deletions

View File

@@ -199,15 +199,16 @@ export function buildBootstrapContextFiles(
if (remainingTotalChars <= 0) {
break;
}
const filePath = file.path ?? file.name;
if (file.missing) {
const missingText = `[MISSING] Expected at: ${file.path}`;
const missingText = `[MISSING] Expected at: ${filePath}`;
const cappedMissingText = clampToBudget(missingText, remainingTotalChars);
if (!cappedMissingText) {
break;
}
remainingTotalChars = Math.max(0, remainingTotalChars - cappedMissingText.length);
result.push({
path: file.path,
path: filePath,
content: cappedMissingText,
});
continue;
@@ -231,7 +232,7 @@ export function buildBootstrapContextFiles(
}
remainingTotalChars = Math.max(0, remainingTotalChars - contentWithinBudget.length);
result.push({
path: file.path,
path: filePath,
content: contentWithinBudget,
});
}

View File

@@ -44,6 +44,9 @@ function buildInjectedWorkspaceFiles(params: {
const injectedByPath = new Map(params.injectedFiles.map((f) => [f.path, f.content]));
const injectedByBaseName = new Map<string, string>();
for (const file of params.injectedFiles) {
if (!file.path) {
continue;
}
const normalizedPath = file.path.replace(/\\/g, "/");
const baseName = path.posix.basename(normalizedPath);
if (!injectedByBaseName.has(baseName)) {

View File

@@ -540,7 +540,10 @@ export async function runAgentTurnWithFallback(params: {
continue;
}
defaultRuntime.error(`Embedded agent failed before reply: ${message}`);
const stack = err instanceof Error ? err.stack : undefined;
defaultRuntime.error(
`Embedded agent failed before reply: ${message}${stack ? `\n${stack}` : ""}`,
);
const safeMessage = isTransientHttp
? sanitizeUserFacingText(message, { errorContext: true })
: message;

View File

@@ -100,8 +100,9 @@ function drainLane(lane: string) {
const completedCurrentGeneration = completeTask(state, taskId, taskGeneration);
const isProbeLane = lane.startsWith("auth-probe:") || lane.startsWith("session:probe-");
if (!isProbeLane) {
const stack = err instanceof Error ? err.stack : undefined;
diag.error(
`lane task error: lane=${lane} durationMs=${Date.now() - startTime} error="${String(err)}"`,
`lane task error: lane=${lane} durationMs=${Date.now() - startTime} error="${String(err)}"${stack ? `\n${stack}` : ""}`,
);
}
if (completedCurrentGeneration) {