@@ -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+
744828fn indent_block ( s : & str ) -> String {
745829 let mut out = String :: new ( ) ;
746830 for line in s. lines ( ) {
0 commit comments