From 8c73e0eda07b09e2c555e2d53fd81c4b3a0c1935 Mon Sep 17 00:00:00 2001 From: Haoqing Wang <1506751656@qq.com> Date: Sat, 4 Apr 2026 07:43:20 -0700 Subject: [PATCH 1/3] fix(web): disable indented code blocks in markdown rendering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In CommonMark, text indented by 4+ spaces is treated as a code block. LLM responses frequently have indented content inside numbered lists or quoted text, causing large chunks to render as a single code block instead of formatted markdown. Add a remark plugin that disables the codeIndented tokenizer. Fenced code blocks (``` … ```) continue to work normally. via [HAPI](https://hapi.run) Co-Authored-By: HAPI --- web/src/components/assistant-ui/markdown-text.tsx | 3 ++- web/src/lib/remark-disable-indented-code.ts | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 web/src/lib/remark-disable-indented-code.ts diff --git a/web/src/components/assistant-ui/markdown-text.tsx b/web/src/components/assistant-ui/markdown-text.tsx index 199067890..2f61a17a4 100644 --- a/web/src/components/assistant-ui/markdown-text.tsx +++ b/web/src/components/assistant-ui/markdown-text.tsx @@ -6,12 +6,13 @@ import { type CodeHeaderProps, } from '@assistant-ui/react-markdown' import remarkGfm from 'remark-gfm' +import remarkDisableIndentedCode from '@/lib/remark-disable-indented-code' import { cn } from '@/lib/utils' import { SyntaxHighlighter } from '@/components/assistant-ui/shiki-highlighter' import { useCopyToClipboard } from '@/hooks/useCopyToClipboard' import { CopyIcon, CheckIcon } from '@/components/icons' -export const MARKDOWN_PLUGINS = [remarkGfm] +export const MARKDOWN_PLUGINS = [remarkGfm, remarkDisableIndentedCode] function CodeHeader(props: CodeHeaderProps) { const { copied, copy } = useCopyToClipboard() diff --git a/web/src/lib/remark-disable-indented-code.ts b/web/src/lib/remark-disable-indented-code.ts new file mode 100644 index 000000000..2caa781e6 --- /dev/null +++ b/web/src/lib/remark-disable-indented-code.ts @@ -0,0 +1,13 @@ +/** + * Remark plugin that disables indented code blocks (4-space indent). + * + * In CommonMark, text indented by 4+ spaces becomes a code block. This + * frequently misparses LLM output where numbered-list items with nested + * content or quoted text are indented. Fenced code blocks (``` … ```) + * still work normally. + */ +export default function remarkDisableIndentedCode(this: { data: () => Record }) { + const data = this.data() + const extensions = data.micromarkExtensions ?? (data.micromarkExtensions = []) + extensions.push({ disable: { null: ['codeIndented'] } }) +} From 6bbe3bf15d3d61c316dd0fba950e1aa8483a9a98 Mon Sep 17 00:00:00 2001 From: Haoqing Wang <1506751656@qq.com> Date: Sat, 4 Apr 2026 07:46:38 -0700 Subject: [PATCH 2/3] fix(web): fix typecheck for remark plugin this binding Use `as any` cast for the unified processor `this` context instead of an explicit type annotation that conflicts with the Processor type. via [HAPI](https://hapi.run) Co-Authored-By: HAPI --- web/src/lib/remark-disable-indented-code.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/web/src/lib/remark-disable-indented-code.ts b/web/src/lib/remark-disable-indented-code.ts index 2caa781e6..591f7c6ac 100644 --- a/web/src/lib/remark-disable-indented-code.ts +++ b/web/src/lib/remark-disable-indented-code.ts @@ -6,8 +6,10 @@ * content or quoted text are indented. Fenced code blocks (``` … ```) * still work normally. */ -export default function remarkDisableIndentedCode(this: { data: () => Record }) { - const data = this.data() +export default function remarkDisableIndentedCode() { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const self = this as any + const data = self.data() const extensions = data.micromarkExtensions ?? (data.micromarkExtensions = []) extensions.push({ disable: { null: ['codeIndented'] } }) } From bb6736df412bd3b9fdab79c667153c07990ddb78 Mon Sep 17 00:00:00 2001 From: Haoqing Wang <1506751656@qq.com> Date: Sat, 4 Apr 2026 07:51:03 -0700 Subject: [PATCH 3/3] fix(web): use this:unknown annotation to satisfy noImplicitThis The previous `as any` cast on `this` still triggers noImplicitThis in strict mode. Annotate the parameter as `this: unknown` and cast to the required shape inside the function body. Also use the key-based `data(key, value)` API instead of mutating the returned object. via [HAPI](https://hapi.run) Co-Authored-By: HAPI --- web/src/lib/remark-disable-indented-code.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/web/src/lib/remark-disable-indented-code.ts b/web/src/lib/remark-disable-indented-code.ts index 591f7c6ac..833a5cd99 100644 --- a/web/src/lib/remark-disable-indented-code.ts +++ b/web/src/lib/remark-disable-indented-code.ts @@ -6,10 +6,9 @@ * content or quoted text are indented. Fenced code blocks (``` … ```) * still work normally. */ -export default function remarkDisableIndentedCode() { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const self = this as any - const data = self.data() - const extensions = data.micromarkExtensions ?? (data.micromarkExtensions = []) - extensions.push({ disable: { null: ['codeIndented'] } }) +export default function remarkDisableIndentedCode(this: unknown) { + const processor = this as { data(key: string, value?: unknown): unknown } + const micromarkExtensions = (processor.data('micromarkExtensions') ?? []) as unknown[] + micromarkExtensions.push({ disable: { null: ['codeIndented'] } }) + processor.data('micromarkExtensions', micromarkExtensions) }