fix: show agent subtask

This commit is contained in:
Haileyesus
2026-07-07 15:06:06 +03:00
parent baf45b7282
commit 6336d94fd6

View File

@@ -13,6 +13,48 @@ function formatToolResultContent(content: unknown): string {
return toolUseErrorMatch ? toolUseErrorMatch[1] : text;
}
type ParsedTaskNotification = {
status: string;
summary: string;
result: string;
};
/**
* Parses a background-agent `<task-notification>` block.
*
* The harness injects these as user-role messages when a background task stops.
* Newer notifications carry extra fields (`<tool-use-id>`, `<note>`, `<usage>`,
* and a `<result>` markdown payload) that the previous single-shot regex could
* not match, so the whole raw XML block leaked through as plain user text.
* Fields are extracted independently so the block renders as an assistant
* notification plus, when present, the agent's markdown result.
*/
function parseTaskNotification(content: string): ParsedTaskNotification | null {
if (!content.trimStart().startsWith('<task-notification>')) {
return null;
}
const statusMatch = /<status>([\s\S]*?)<\/status>/.exec(content);
const summaryMatch = /<summary>([\s\S]*?)<\/summary>/.exec(content);
let result = '';
const resultOpen = content.indexOf('<result>');
if (resultOpen !== -1) {
const afterOpen = content.slice(resultOpen + '<result>'.length);
const closeIndex = afterOpen.indexOf('</result>');
result =
closeIndex === -1
? afterOpen.replace(/<\/task-notification>\s*$/, '').trim()
: afterOpen.slice(0, closeIndex).trim();
}
return {
status: statusMatch?.[1]?.trim() || 'completed',
summary: summaryMatch?.[1]?.trim() || 'Background task finished',
result,
};
}
/**
* Convert NormalizedMessage[] from the session store into ChatMessage[]
* that the existing UI components expect.
@@ -56,17 +98,26 @@ export function normalizedToChatMessages(messages: NormalizedMessage[]): ChatMes
if (msg.role === 'user') {
// Parse task notifications
const taskNotifRegex = /<task-notification>\s*<task-id>[^<]*<\/task-id>\s*<output-file>[^<]*<\/output-file>\s*<status>([^<]*)<\/status>\s*<summary>([^<]*)<\/summary>\s*<\/task-notification>/g;
const taskNotifMatch = taskNotifRegex.exec(content);
if (taskNotifMatch) {
const taskNotif = parseTaskNotification(content);
if (taskNotif) {
converted.push({
type: 'assistant',
content: taskNotifMatch[2]?.trim() || 'Background task finished',
content: taskNotif.summary,
timestamp: msg.timestamp,
isTaskNotification: true,
taskStatus: taskNotifMatch[1]?.trim() || 'completed',
taskStatus: taskNotif.status,
...sharedMetadata,
});
// Render the agent's result as a normal assistant message so its
// markdown displays correctly instead of leaking raw XML.
if (taskNotif.result) {
converted.push({
type: 'assistant',
content: formatUsageLimitText(unescapeWithMathProtection(decodeHtmlEntities(taskNotif.result))),
timestamp: msg.timestamp,
...sharedMetadata,
});
}
} else {
converted.push({
type: 'user',