Skip to content

Commit d7b0d00

Browse files
committed
feat(copilot-ui): render reasoning as Markdown, dimmed for human eyes
- Add context::reasoning_to_markdown, outputs Markdown with bold headers, fenced KCL, and pretty JSON so the Copilot pane is not a wall of text - UI now renders markdown to lines and dims reasoning text, replaces format_reasoning for cleaner output Signed-off-by: Jessie Frazelle <[email protected]>
1 parent 7db6451 commit d7b0d00

File tree

2 files changed

+88
-2
lines changed

2 files changed

+88
-2
lines changed

src/context.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,90 @@ pub(crate) fn format_reasoning(reason: kittycad::types::ReasoningMessage, use_co
741741
}
742742
}
743743

744+
/// Render a ReasoningMessage as Markdown with a bold header and
745+
/// pretty-printed structured content. Intended for Copilot UI rendering.
746+
pub(crate) fn reasoning_to_markdown(reason: &kittycad::types::ReasoningMessage) -> String {
747+
use serde_json::json;
748+
749+
match reason {
750+
kittycad::types::ReasoningMessage::Text { content } => {
751+
format!("**Reasoning**\n\n{}", content.trim())
752+
}
753+
kittycad::types::ReasoningMessage::KclDocs { content } => {
754+
format!("**KCL Docs**\n\n{}", content.trim())
755+
}
756+
kittycad::types::ReasoningMessage::KclCodeExamples { content } => {
757+
format!("**KCL Examples**\n\n{}", content.trim())
758+
}
759+
kittycad::types::ReasoningMessage::FeatureTreeOutline { content } => {
760+
format!("**Feature Tree**\n\n{}", content.trim())
761+
}
762+
kittycad::types::ReasoningMessage::DesignPlan { steps } => {
763+
let mut md = String::from("**Design Plan**\n");
764+
for step in steps {
765+
let obj = json!({
766+
"file": step.filepath_to_edit,
767+
"edit_instructions": step.edit_instructions,
768+
});
769+
let pretty = serde_json::to_string_pretty(&obj).unwrap_or_else(|_| obj.to_string());
770+
md.push_str("\n```json\n");
771+
md.push_str(&pretty);
772+
md.push_str("\n```\n");
773+
}
774+
md
775+
}
776+
kittycad::types::ReasoningMessage::GeneratedKclCode { code } => {
777+
// Keep as fenced code for readability; UI flattens to lines.
778+
let mut md = String::from("**Generated KCL**\n\n");
779+
md.push_str("```kcl\n");
780+
md.push_str(code);
781+
md.push_str("\n```\n");
782+
md
783+
}
784+
kittycad::types::ReasoningMessage::KclCodeError { error } => {
785+
let mut md = String::from("**KCL Error**\n\n");
786+
md.push_str("```text\n");
787+
md.push_str(error.trim());
788+
md.push_str("\n```\n");
789+
md
790+
}
791+
kittycad::types::ReasoningMessage::CreatedKclFile { file_name, content } => {
792+
let meta = json!({ "action": "created", "file": file_name });
793+
let mut md = String::from("**Created File**\n\n");
794+
md.push_str("```json\n");
795+
md.push_str(&serde_json::to_string_pretty(&meta).unwrap_or_else(|_| meta.to_string()));
796+
md.push_str("\n```\n");
797+
if !content.trim().is_empty() {
798+
md.push_str("\n```kcl\n");
799+
md.push_str(content);
800+
md.push_str("\n```\n");
801+
}
802+
md
803+
}
804+
kittycad::types::ReasoningMessage::UpdatedKclFile { file_name, content } => {
805+
let meta = json!({ "action": "updated", "file": file_name });
806+
let mut md = String::from("**Updated File**\n\n");
807+
md.push_str("```json\n");
808+
md.push_str(&serde_json::to_string_pretty(&meta).unwrap_or_else(|_| meta.to_string()));
809+
md.push_str("\n```\n");
810+
if !content.trim().is_empty() {
811+
md.push_str("\n```kcl\n");
812+
md.push_str(content);
813+
md.push_str("\n```\n");
814+
}
815+
md
816+
}
817+
kittycad::types::ReasoningMessage::DeletedKclFile { file_name } => {
818+
let meta = json!({ "action": "deleted", "file": file_name });
819+
let mut md = String::from("**Deleted File**\n\n");
820+
md.push_str("```json\n");
821+
md.push_str(&serde_json::to_string_pretty(&meta).unwrap_or_else(|_| meta.to_string()));
822+
md.push_str("\n```\n");
823+
md
824+
}
825+
}
826+
}
827+
744828
fn indent_block(s: &str) -> String {
745829
let mut out = String::new();
746830
for line in s.lines() {

src/ml/copilot/ui.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,12 @@ pub fn draw(frame: &mut Frame, app: &App) {
117117
}
118118
}
119119
kittycad::types::MlCopilotServerMessage::Reasoning(reason) => {
120-
for l in crate::context::format_reasoning(reason.clone(), false) {
120+
// Render reasoning as dimmed markdown lines for readability.
121+
let md = crate::context::reasoning_to_markdown(reason);
122+
for l in render_markdown_to_lines(&md) {
121123
lines.push(Line::from(vec![
122124
Span::styled("ML-ephant> ", Style::default().fg(Color::Green)),
123-
Span::raw(l),
125+
Span::styled(l, Style::default().fg(Color::Rgb(150, 150, 150))),
124126
]));
125127
}
126128
}

0 commit comments

Comments
 (0)