Skip to content

Commit 403cd13

Browse files
committed
fix: speech recognition cleanup, preview stale closure, assistant tag leak
1 parent 4aa9eb2 commit 403cd13

3 files changed

Lines changed: 23 additions & 6 deletions

File tree

app/components/chat/AssistantMessage.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,21 +71,30 @@ const COMPLETE_ARTIFACT_BLOCK_RE = /<devonzArtifact[^>]*>[\s\S]*?<\/devonzArtifa
7171
const UNCLOSED_ARTIFACT_RE = /<devonzArtifact[^>]*>[\s\S]*$/;
7272
const LEFTOVER_TAG_RE = /<\/?devonz(?:Artifact|Action)[^>]*>/g;
7373

74+
/** Matches complete or partial `</assistant>` / `<assistant>` XML tags that LLMs sometimes emit */
75+
const ASSISTANT_TAG_RE = /<\/?assist(?:ant)?>|<\/assis(?:t(?:a(?:n(?:t)?)?)?)?\s*$/g;
76+
7477
/**
7578
* Strip raw artifact/action markup that leaks through the parser during
7679
* streaming. Complete blocks are removed first, then everything after an
7780
* unclosed `<devonzArtifact` tag (whose closing tag hasn't arrived yet) is
7881
* chopped — this prevents code content from appearing in the chat bubble
7982
* while the AI is still generating.
83+
*
84+
* Also strips stray `</assistant>` or partial fragments like `</assis`
85+
* that some models emit at the end of their response.
8086
*/
8187
function stripRawArtifactTags(text: string): string {
82-
if (!text.includes('devonzA')) {
83-
return text;
84-
}
88+
let result = text;
8589

86-
let result = text.replace(COMPLETE_ARTIFACT_BLOCK_RE, '').replace(UNCLOSED_ARTIFACT_RE, '');
90+
if (result.includes('devonzA')) {
91+
result = result.replace(COMPLETE_ARTIFACT_BLOCK_RE, '').replace(UNCLOSED_ARTIFACT_RE, '');
92+
result = result.replace(LEFTOVER_TAG_RE, '');
93+
}
8794

88-
result = result.replace(LEFTOVER_TAG_RE, '');
95+
if (result.includes('assis') || result.includes('Assis')) {
96+
result = result.replace(ASSISTANT_TAG_RE, '');
97+
}
8998

9099
return result;
91100
}

app/components/chat/BaseChat.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,15 @@ export const BaseChat = React.memo(
326326
};
327327

328328
setRecognition(recognition);
329+
330+
return () => {
331+
recognition.abort();
332+
recognition.onresult = null;
333+
recognition.onerror = null;
334+
};
329335
}
336+
337+
return undefined;
330338
}, []);
331339

332340
useEffect(() => {

app/components/workbench/Preview.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ export const Preview = memo(({ setSelectedElement }: PreviewProps) => {
443443
window.addEventListener('devonz:refresh-preview', handler);
444444

445445
return () => window.removeEventListener('devonz:refresh-preview', handler);
446-
}, []);
446+
}, [reloadPreview]);
447447

448448
const toggleFullscreen = async () => {
449449
if (!isFullscreen && containerRef.current) {

0 commit comments

Comments
 (0)