feat(ui): render subagent results as markdown
This commit is contained in:
54
index.ts
54
index.ts
@@ -11,7 +11,7 @@ import {
|
||||
parseFrontmatter,
|
||||
withFileMutationQueue,
|
||||
} from "@mariozechner/pi-coding-agent";
|
||||
import { Text } from "@mariozechner/pi-tui";
|
||||
import { Markdown, Text, type MarkdownTheme } from "@mariozechner/pi-tui";
|
||||
import { Type } from "typebox";
|
||||
|
||||
interface PromptConfig {
|
||||
@@ -62,6 +62,27 @@ const PROMPTS_DIR = path.join(EXTENSION_DIR, "prompts");
|
||||
const FINALIZE_TOOL_NAME = "subagent_finalize";
|
||||
const MAX_FINALIZE_RETRIES = 2;
|
||||
|
||||
// Markdown Theme - Render finalized subagent text with Pi's terminal markdown component.
|
||||
function getSubagentMarkdownTheme(theme: Theme): MarkdownTheme {
|
||||
return {
|
||||
heading: (text) => theme.fg("mdHeading", text),
|
||||
link: (text) => theme.fg("mdLink", text),
|
||||
linkUrl: (text) => theme.fg("mdLinkUrl", text),
|
||||
code: (text) => theme.fg("mdCode", text),
|
||||
codeBlock: (text) => theme.fg("mdCodeBlock", text),
|
||||
codeBlockBorder: (text) => theme.fg("mdCodeBlockBorder", text),
|
||||
quote: (text) => theme.fg("mdQuote", text),
|
||||
quoteBorder: (text) => theme.fg("mdQuoteBorder", text),
|
||||
hr: (text) => theme.fg("mdHr", text),
|
||||
listBullet: (text) => theme.fg("mdListBullet", text),
|
||||
bold: (text) => theme.bold(text),
|
||||
italic: (text) => theme.italic(text),
|
||||
strikethrough: (text) => theme.strikethrough(text),
|
||||
underline: (text) => theme.underline(text),
|
||||
codeBlockIndent: " ",
|
||||
};
|
||||
}
|
||||
|
||||
// Format Tool Content - Some clients hide structured details from the model.
|
||||
function formatSubagentContent(
|
||||
status: "SUCCESS" | "ERROR",
|
||||
@@ -73,7 +94,9 @@ function formatSubagentContent(
|
||||
if (error?.trim()) header.push(`**Error:** ${error.trim()}`);
|
||||
|
||||
const body = result?.trimEnd();
|
||||
return body ? `${header.join(" \n")}\n\n---\n\n${body}` : header.join(" \n");
|
||||
return body
|
||||
? `${header.join(" \n")}\n\n---\n\n${body}`
|
||||
: header.join(" \n");
|
||||
}
|
||||
|
||||
// Parse Tool List - Frontmatter may use YAML arrays or comma-delimited strings.
|
||||
@@ -180,7 +203,9 @@ function getSubagentSessionPath(
|
||||
}
|
||||
|
||||
// Validate Finalize Payload - Keep the parent contract strict and small.
|
||||
function validateFinalizePayload(value: unknown): SubagentFinalizePayload | null {
|
||||
function validateFinalizePayload(
|
||||
value: unknown,
|
||||
): SubagentFinalizePayload | null {
|
||||
if (!value || typeof value !== "object") return null;
|
||||
const payload = value as Record<string, unknown>;
|
||||
if (payload.status === "SUCCESS") {
|
||||
@@ -437,7 +462,8 @@ async function runAgent(
|
||||
);
|
||||
const toolName = String(event.toolName ?? "tool");
|
||||
if (toolName === FINALIZE_TOOL_NAME) {
|
||||
result.finalized = validateFinalizePayload(event.args) ?? undefined;
|
||||
result.finalized =
|
||||
validateFinalizePayload(event.args) ?? undefined;
|
||||
}
|
||||
activeToolIds.add(id);
|
||||
result.status.state = "running";
|
||||
@@ -647,7 +673,11 @@ export default function (pi: ExtensionAPI) {
|
||||
await fs.promises.mkdir(path.dirname(sessionPath), { recursive: true });
|
||||
|
||||
let result: SubagentResult | null = null;
|
||||
for (let retryCount = 0; retryCount <= MAX_FINALIZE_RETRIES; retryCount += 1) {
|
||||
for (
|
||||
let retryCount = 0;
|
||||
retryCount <= MAX_FINALIZE_RETRIES;
|
||||
retryCount += 1
|
||||
) {
|
||||
const task =
|
||||
retryCount === 0
|
||||
? `Task: ${params.task}`
|
||||
@@ -700,7 +730,12 @@ export default function (pi: ExtensionAPI) {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: formatSubagentContent("ERROR", sessionId, undefined, fallback),
|
||||
text: formatSubagentContent(
|
||||
"ERROR",
|
||||
sessionId,
|
||||
undefined,
|
||||
fallback,
|
||||
),
|
||||
},
|
||||
],
|
||||
details: { sessionId },
|
||||
@@ -760,7 +795,12 @@ export default function (pi: ExtensionAPI) {
|
||||
}
|
||||
|
||||
const text = result.content[0];
|
||||
return new Text(text?.type === "text" ? text.text : "", 0, 0);
|
||||
return new Markdown(
|
||||
text?.type === "text" ? text.text : "",
|
||||
0,
|
||||
0,
|
||||
getSubagentMarkdownTheme(theme),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user