diff --git a/frontend/apps/main/src/features/conversation/ReplyBox.vue b/frontend/apps/main/src/features/conversation/ReplyBox.vue index c48c8bdd..f98c666b 100644 --- a/frontend/apps/main/src/features/conversation/ReplyBox.vue +++ b/frontend/apps/main/src/features/conversation/ReplyBox.vue @@ -223,7 +223,8 @@ const runAiGeneration = async (requestFn) => { if (uuid !== currentConversationUUID.value) return const out = resp.data.data || '' // A model can ignore the HTML-output instruction; plain text pasted into the editor loses its line breaks. - htmlContent.value = /<[a-z][\s\S]*>/i.test(out) ? out : convertTextToHtml(out) + // The tag check must not match angle-bracketed plain text like "Contact ". + htmlContent.value = /<\/?[a-z][a-z0-9]*(\s[^>]*)?\/?>/i.test(out) ? out : convertTextToHtml(out) } catch (error) { emitter.emit(EMITTER_EVENTS.SHOW_TOAST, { variant: 'destructive', diff --git a/internal/ai/ai.go b/internal/ai/ai.go index c99ed5e2..feae902d 100644 --- a/internal/ai/ai.go +++ b/internal/ai/ai.go @@ -40,7 +40,7 @@ var ( //go:embed queries.sql efs embed.FS - codeFenceOpenRe = regexp.MustCompile("^```[a-zA-Z0-9]*$") + codeFenceOpenRe = regexp.MustCompile("^```[a-zA-Z0-9+#./_-]*$") ErrInvalidAPIKey = errors.New("invalid API Key") ErrApiKeyNotSet = errors.New("api Key not set") diff --git a/internal/ai/ai_test.go b/internal/ai/ai_test.go index 5b3cb6ce..f911164d 100644 --- a/internal/ai/ai_test.go +++ b/internal/ai/ai_test.go @@ -48,6 +48,16 @@ func TestStripCodeFence(t *testing.T) { in: "```

Hello,

\n

Thanks.

\n```", want: "```

Hello,

\n

Thanks.

\n```", }, + { + name: "c++ fence unwrapped", + in: "```c++\nint main() {}\n```", + want: "int main() {}", + }, + { + name: "text/plain fence unwrapped", + in: "```text/plain\nHello there.\n```", + want: "Hello there.", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {