-
Notifications
You must be signed in to change notification settings - Fork 73
Wrap agent log rendering in collapsible details section #14208
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1414,6 +1414,28 @@ function generateCopilotCliStyleSummary(logEntries, options = {}) { | |
| return lines.join("\n"); | ||
| } | ||
|
|
||
| /** | ||
| * Wraps agent log markdown in a details/summary section | ||
| * @param {string} markdown - The agent log markdown content | ||
| * @param {Object} options - Configuration options | ||
| * @param {string} [options.parserName="Agent"] - Name of the parser (e.g., "Copilot", "Claude") | ||
| * @param {boolean} [options.open=true] - Whether the section should be open by default | ||
| * @returns {string} Wrapped markdown in details/summary tags | ||
| */ | ||
| function wrapAgentLogInSection(markdown, options = {}) { | ||
| const { parserName = "Agent", open = true } = options; | ||
|
|
||
| if (!markdown || markdown.trim().length === 0) { | ||
| return ""; | ||
| } | ||
|
|
||
| const openAttr = open ? " open" : ""; | ||
| const emoji = "🤖"; | ||
| const title = `${emoji} ${parserName} CLI Session`; | ||
|
|
||
| return `<details${openAttr}>\n<summary>${title}</summary>\n\n${markdown}\n</details>`; | ||
|
Comment on lines
+1432
to
+1436
|
||
| } | ||
|
|
||
| /** | ||
| * Formats safe outputs preview for display in logs | ||
| * @param {string} safeOutputsContent - The raw JSONL content from safe outputs file | ||
|
|
@@ -1591,6 +1613,7 @@ module.exports = { | |
| formatToolCallAsDetails, | ||
| generatePlainTextSummary, | ||
| generateCopilotCliStyleSummary, | ||
| wrapAgentLogInSection, | ||
| formatSafeOutputsPreview, | ||
| wrapLogParser, | ||
| createEngineLogParser, | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -2087,6 +2087,66 @@ describe("log_parser_shared.cjs", () => { | |||||||
| }); | ||||||||
| }); | ||||||||
|
|
||||||||
| describe("wrapAgentLogInSection", () => { | ||||||||
| it("should wrap markdown in details/summary with default open attribute", async () => { | ||||||||
| const { wrapAgentLogInSection } = await import("./log_parser_shared.cjs"); | ||||||||
|
|
||||||||
| const markdown = "```\nConversation:\n\nAgent: Hello\n```"; | ||||||||
| const result = wrapAgentLogInSection(markdown, { parserName: "Copilot" }); | ||||||||
|
|
||||||||
| expect(result).toContain("<details open>"); | ||||||||
| expect(result).toContain("<summary>🤖 Copilot CLI Session</summary>"); | ||||||||
| expect(result).toContain(markdown); | ||||||||
| expect(result).toContain("</details>"); | ||||||||
| }); | ||||||||
|
|
||||||||
| it("should support custom parser names", async () => { | ||||||||
| const { wrapAgentLogInSection } = await import("./log_parser_shared.cjs"); | ||||||||
|
|
||||||||
| const markdown = "Test content"; | ||||||||
| const result = wrapAgentLogInSection(markdown, { parserName: "Claude" }); | ||||||||
|
|
||||||||
| expect(result).toContain("🤖 Claude CLI Session"); | ||||||||
| }); | ||||||||
|
|
||||||||
| it("should allow closed state when open is false", async () => { | ||||||||
| const { wrapAgentLogInSection } = await import("./log_parser_shared.cjs"); | ||||||||
|
|
||||||||
| const markdown = "Test content"; | ||||||||
| const result = wrapAgentLogInSection(markdown, { parserName: "Copilot", open: false }); | ||||||||
|
|
||||||||
| expect(result).toContain("<details>"); | ||||||||
| expect(result).not.toContain("<details open>"); | ||||||||
| }); | ||||||||
|
|
||||||||
| it("should default to Agent parser name when not provided", async () => { | ||||||||
| const { wrapAgentLogInSection } = await import("./log_parser_shared.cjs"); | ||||||||
|
|
||||||||
| const markdown = "Test content"; | ||||||||
| const result = wrapAgentLogInSection(markdown); | ||||||||
|
|
||||||||
| expect(result).toContain("🤖 Agent CLI Session"); | ||||||||
| }); | ||||||||
|
|
||||||||
| it("should return empty string for empty or undefined markdown", async () => { | ||||||||
| const { wrapAgentLogInSection } = await import("./log_parser_shared.cjs"); | ||||||||
|
|
||||||||
| expect(wrapAgentLogInSection("")).toBe(""); | ||||||||
| expect(wrapAgentLogInSection(" ")).toBe(""); | ||||||||
|
||||||||
| expect(wrapAgentLogInSection(" ")).toBe(""); | |
| expect(wrapAgentLogInSection(" ")).toBe(""); | |
| expect(wrapAgentLogInSection(undefined)).toBe(""); |
Copilot
AI
Feb 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test claims the wrapper “properly escape[s] markdown content”, but wrapAgentLogInSection currently injects markdown verbatim and the assertions only check that the raw string is present. Either update the test name/expectations, or implement escaping/sanitization if the intent is to render <tags> literally rather than as HTML.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This wrapping is applied for the main parsed-markdown paths, but the earlier Copilot
conversation.mdfast-path still writesresult.markdowndirectly to the step summary (unwrapped). That means Copilot--shareoutput won’t get the collapsible section even though other paths do. Consider wrapping that path too (or update the PR description/behavior to be consistent).