add magenta log prefixes for delegated subagents (#387)

When delegate() runs multiple subagents in parallel, their logs
interleave without visual distinction. Use AsyncLocalStorage to
automatically prefix every log line inside runSubagent() with the
task label in magenta (e.g. [frontend-review]).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Colin McDonnell
2026-02-25 05:53:18 +00:00
committed by pullfrog[bot]
parent d5ab3706db
commit 1ed3da8273
5 changed files with 207 additions and 118 deletions
+66 -45
View File
@@ -135589,6 +135589,7 @@ var Effort = type.enumerated("mini", "auto", "max");
// utils/log.ts
var core = __toESM(require_core(), 1);
var import_table = __toESM(require_src(), 1);
import { AsyncLocalStorage } from "node:async_hooks";
// utils/globals.ts
import { existsSync } from "node:fs";
@@ -135597,6 +135598,23 @@ var isGitHubActions = !!process.env.GITHUB_ACTIONS;
var isInsideDocker = existsSync("/.dockerenv");
// utils/log.ts
var logContext = new AsyncLocalStorage();
var MAGENTA = "\x1B[35m";
var RESET = "\x1B[0m";
function withLogPrefix(prefix, fn2) {
return logContext.run({ prefix }, fn2);
}
function prefixLines(message) {
const ctx = logContext.getStore();
if (!ctx) return message;
const colored = `${MAGENTA}${ctx.prefix}${RESET} `;
return message.split("\n").map((line) => `${colored}${line}`).join("\n");
}
function prefixPlain(name) {
const ctx = logContext.getStore();
if (!ctx) return name;
return `${ctx.prefix} ${name}`;
}
var isRunnerDebugEnabled = () => core.isDebug();
var isLocalDebugEnabled = () => process.env.LOG_LEVEL === "debug" || process.env.ACTIONS_STEP_DEBUG === "true";
var isDebugEnabled = () => isLocalDebugEnabled() || isRunnerDebugEnabled();
@@ -135612,10 +135630,11 @@ ${arg.stack}`;
}).join(" ");
}
function startGroup2(name) {
const prefixed = prefixPlain(name);
if (isGitHubActions) {
core.startGroup(name);
core.startGroup(prefixed);
} else {
console.group(name);
console.group(prefixed);
}
}
function endGroup2() {
@@ -135688,7 +135707,7 @@ function boxString(text, options) {
}
function box(text, options) {
const boxContent = boxString(text, options);
core.info(boxContent);
core.info(prefixLines(boxContent));
}
async function writeSummary(text) {
if (!isGitHubActions) return;
@@ -135708,42 +135727,42 @@ function printTable(rows, options) {
);
const formatted = (0, import_table.table)(tableData);
if (title) {
core.info(`
${title}`);
core.info(prefixLines(`
${title}`));
}
core.info(`
core.info(prefixLines(`
${formatted}
`);
`));
}
function separator(length = 50) {
const separatorText = "\u2500".repeat(length);
core.info(separatorText);
core.info(prefixLines(separatorText));
}
var log = {
/** Print info message */
info: (...args2) => {
core.info(`${ts()}${formatArgs(args2)}`);
core.info(prefixLines(`${ts()}${formatArgs(args2)}`));
},
/** Print a warning message. Use only for warnings that should be displayed in the job summary. */
warning: (...args2) => {
core.warning(`${ts()}${formatArgs(args2)}`);
core.warning(prefixLines(`${ts()}${formatArgs(args2)}`));
},
/** Print an error message. Use only for errors that should be displayed in the job summary. */
error: (...args2) => {
core.error(`${ts()}${formatArgs(args2)}`);
core.error(prefixLines(`${ts()}${formatArgs(args2)}`));
},
/** Print success message */
success: (...args2) => {
core.info(`${ts()}\xBB ${formatArgs(args2)}`);
core.info(prefixLines(`${ts()}\xBB ${formatArgs(args2)}`));
},
/** Print debug message (only when debug mode is enabled) */
debug: (...args2) => {
if (isRunnerDebugEnabled()) {
core.debug(formatArgs(args2));
core.debug(prefixLines(formatArgs(args2)));
return;
}
if (isLocalDebugEnabled()) {
core.info(`${ts()}[DEBUG] ${formatArgs(args2)}`);
core.info(prefixLines(`${ts()}[DEBUG] ${formatArgs(args2)}`));
}
},
/** Print a formatted box with text */
@@ -136443,41 +136462,43 @@ ${params.instructions}`;
};
}
async function runSubagent(params) {
params.subagent.keepAliveInterval = setInterval(markActivity, 3e4);
const mcpServer = await startSubagentMcpServer({
ctx: params.ctx,
subagentId: params.subagent.id
});
const subagentTmpdir = join(params.ctx.tmpdir, params.subagent.id);
mkdirSync(subagentTmpdir, { recursive: true });
try {
const subagentPayload = { ...params.ctx.payload, effort: params.effort };
const subagentInstructions = buildSubagentInstructions({
return withLogPrefix(`[${params.subagent.label}]`, async () => {
params.subagent.keepAliveInterval = setInterval(markActivity, 3e4);
const mcpServer = await startSubagentMcpServer({
ctx: params.ctx,
label: params.subagent.label,
instructions: params.instructions
subagentId: params.subagent.id
});
const result = await params.ctx.agent.run({
payload: subagentPayload,
mcpServerUrl: mcpServer.url,
tmpdir: subagentTmpdir,
instructions: subagentInstructions
});
params.subagent.usage = result.usage;
writeFileSync(params.subagent.stdoutFilePath, result.output ?? "", "utf-8");
completeSubagent({ ctx: params.ctx, subagent: params.subagent, success: result.success });
return { success: result.success, error: result.error };
} catch (err) {
const errorMessage = err instanceof Error ? err.message : String(err);
const subagentTmpdir = join(params.ctx.tmpdir, params.subagent.id);
mkdirSync(subagentTmpdir, { recursive: true });
try {
writeFileSync(params.subagent.stdoutFilePath, "", "utf-8");
} catch {
const subagentPayload = { ...params.ctx.payload, effort: params.effort };
const subagentInstructions = buildSubagentInstructions({
ctx: params.ctx,
label: params.subagent.label,
instructions: params.instructions
});
const result = await params.ctx.agent.run({
payload: subagentPayload,
mcpServerUrl: mcpServer.url,
tmpdir: subagentTmpdir,
instructions: subagentInstructions
});
params.subagent.usage = result.usage;
writeFileSync(params.subagent.stdoutFilePath, result.output ?? "", "utf-8");
completeSubagent({ ctx: params.ctx, subagent: params.subagent, success: result.success });
return { success: result.success, error: result.error };
} catch (err) {
const errorMessage = err instanceof Error ? err.message : String(err);
try {
writeFileSync(params.subagent.stdoutFilePath, "", "utf-8");
} catch {
}
completeSubagent({ ctx: params.ctx, subagent: params.subagent, success: false });
return { success: false, error: errorMessage };
} finally {
await mcpServer.stop();
}
completeSubagent({ ctx: params.ctx, subagent: params.subagent, success: false });
return { success: false, error: errorMessage };
} finally {
await mcpServer.stop();
}
});
}
// mcp/askQuestion.ts