Skip to content

Commit 37f74cb

Browse files
committed
feat: Enhance Markdown output handling in agent workflow and update UI components
Signed-off-by: Andre Bossard <anbossar@microsoft.com>
1 parent bec2b17 commit 37f74cb

4 files changed

Lines changed: 70 additions & 10 deletions

File tree

backend/agent_workbench/service.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ def _build_react_agent(llm: Any, tools: list[Any], system_prompt: str) -> Any:
5252
return create_react_agent(llm, tools, prompt=system_prompt)
5353

5454

55+
def _append_markdown_output_instruction(system_prompt: str) -> str:
56+
instruction = (
57+
"Format your final answer as GitHub-flavored Markdown. "
58+
"Use headings, bullet lists, and tables when helpful. "
59+
"Do not wrap the entire response in a code block."
60+
)
61+
base_prompt = (system_prompt or "").strip()
62+
if not base_prompt:
63+
return instruction
64+
return f"{base_prompt}\n\n{instruction}"
65+
66+
5567
# ============================================================================
5668
# WORKBENCH SERVICE
5769
# ============================================================================
@@ -366,7 +378,8 @@ async def run_agent(
366378
# -- Execute --
367379
try:
368380
tools = self._registry.resolve(validated_tool_names)
369-
react = _build_react_agent(self.llm, tools, agent_def.system_prompt)
381+
runtime_system_prompt = _append_markdown_output_instruction(agent_def.system_prompt)
382+
react = _build_react_agent(self.llm, tools, runtime_system_prompt)
370383

371384
result = await react.ainvoke(
372385
{"messages": [("user", user_message)]},

backend/tests/test_workbench_integration_e2e.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ async def ainvoke(self, _payload: dict, config: dict | None = None) -> dict:
5656

5757

5858
def _fake_build_react_agent(_llm: object, tools: list[object], _prompt: str) -> _FakeReactAgent:
59+
if "GitHub-flavored Markdown" not in _prompt:
60+
raise AssertionError("Expected markdown output instruction in runtime system prompt")
5961
return _FakeReactAgent(tools)
6062

6163

frontend/src/features/workbench/WorkbenchPage.jsx

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import {
1313
tokens,
1414
} from '@fluentui/react-components'
1515
import { useEffect, useState } from 'react'
16+
import ReactMarkdown from 'react-markdown'
17+
import remarkGfm from 'remark-gfm'
1618
import {
1719
createWorkbenchAgent,
1820
deleteWorkbenchAgent,
@@ -82,6 +84,48 @@ const useStyles = makeStyles({
8284
backgroundColor: tokens.colorNeutralBackground1,
8385
color: tokens.colorNeutralForeground1,
8486
},
87+
runOutputMarkdown: {
88+
border: `1px solid ${tokens.colorNeutralStroke1}`,
89+
borderRadius: tokens.borderRadiusMedium,
90+
padding: `${tokens.spacingVerticalS} ${tokens.spacingHorizontalM}`,
91+
backgroundColor: tokens.colorNeutralBackground1,
92+
maxHeight: '320px',
93+
overflowY: 'auto',
94+
'& h1, & h2, & h3': {
95+
margin: `${tokens.spacingVerticalXS} 0`,
96+
fontWeight: tokens.fontWeightSemibold,
97+
},
98+
'& ul, & ol': {
99+
margin: `${tokens.spacingVerticalXS} 0`,
100+
paddingLeft: tokens.spacingHorizontalL,
101+
},
102+
'& table': {
103+
width: '100%',
104+
borderCollapse: 'collapse',
105+
marginTop: tokens.spacingVerticalXS,
106+
},
107+
'& th, & td': {
108+
border: `1px solid ${tokens.colorNeutralStroke1}`,
109+
padding: tokens.spacingHorizontalXS,
110+
textAlign: 'left',
111+
},
112+
'& pre': {
113+
backgroundColor: tokens.colorNeutralBackground3,
114+
padding: tokens.spacingHorizontalM,
115+
borderRadius: tokens.borderRadiusSmall,
116+
overflowX: 'auto',
117+
},
118+
'& code': {
119+
fontFamily: 'monospace',
120+
backgroundColor: tokens.colorNeutralBackground3,
121+
padding: '0 4px',
122+
borderRadius: tokens.borderRadiusSmall,
123+
},
124+
'& a': {
125+
color: tokens.colorBrandForegroundLink,
126+
textDecoration: 'underline',
127+
},
128+
},
85129
})
86130

87131
export default function WorkbenchPage() {
@@ -543,14 +587,12 @@ export default function WorkbenchPage() {
543587

544588
{runError && <Text data-testid="workbench-run-error">{runError}</Text>}
545589
{runOutput && (
546-
<Field label="Run output">
547-
<Textarea
548-
data-testid="workbench-run-output"
549-
value={runOutput}
550-
readOnly
551-
resize="vertical"
552-
rows={6}
553-
/>
590+
<Field label="Run output (Markdown)">
591+
<div data-testid="workbench-run-output" className={styles.runOutputMarkdown}>
592+
<ReactMarkdown remarkPlugins={[remarkGfm]}>
593+
{runOutput}
594+
</ReactMarkdown>
595+
</div>
554596
</Field>
555597
)}
556598
</div>

tests/e2e/workbench.spec.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ test.describe("Agent Fabric UI", () => {
6161
agent_id: "agent-e2e-1",
6262
input_prompt: "Summarize ticket trends",
6363
status: "completed",
64-
output: "Ticket trend summary: high priority incidents are concentrated in Network services.",
64+
output: "# Ticket trend summary\n\n- High priority incidents are concentrated in **Network services**.",
6565
agent_snapshot: { tool_names: ["csv_ticket_stats"] },
6666
tools_used: ["csv_ticket_stats"],
6767
error: null,
@@ -99,6 +99,9 @@ test.describe("Agent Fabric UI", () => {
9999
"Ticket trend summary",
100100
{ timeout: 10000 }
101101
);
102+
await expect(
103+
page.locator('[data-testid="workbench-run-output"] h1')
104+
).toHaveText("Ticket trend summary");
102105
});
103106

104107
test("requires and forwards configured run input", async ({ page }) => {

0 commit comments

Comments
 (0)