mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
fix(chat): don't fold a pipe-bearing prose line into a preceding table (#3978)
Co-authored-by: ly-wang19 <ly-wang19@users.noreply.github.com>
This commit is contained in:
@@ -51,6 +51,29 @@ describe('splitAgentMessageIntoBubbles', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('does not absorb a following prose line whose pipes give a different column count', () => {
|
||||
// The prose line satisfies looksLikeMarkdownTableRow (it contains pipes) but
|
||||
// has 3 "cells" vs the table's 2; absorbing it makes parseMarkdownTable
|
||||
// reject the block (null), suppressing the table renderer and merging the
|
||||
// prose into the table bubble.
|
||||
const content =
|
||||
'| Plan | Cost |\n| --- | --- |\n| Basic | $10 |\nEither pick Basic | Pro, then run `ps aux | grep node`.';
|
||||
expect(splitAgentMessageIntoBubbles(content)).toEqual([
|
||||
'| Plan | Cost |\n| --- | --- |\n| Basic | $10 |',
|
||||
'Either pick Basic | Pro, then run `ps aux | grep node`.',
|
||||
]);
|
||||
});
|
||||
|
||||
it('keeps a table whose first data row carries a code-span pipe as one readable block', () => {
|
||||
// splitMarkdownTableCells splits naively on "|", so a genuine first data row
|
||||
// with a pipe inside a code span over-counts its cells (3 vs the header's 2).
|
||||
// Dropping it would leave a header+separator-only block that renders as an
|
||||
// empty-row table and detaches the real row; keeping the first data row makes
|
||||
// parseMarkdownTable return null so the block falls back to readable markdown.
|
||||
const content = '| Command | Use |\n| --- | --- |\n| `ps aux | grep node` | Find it |';
|
||||
expect(splitAgentMessageIntoBubbles(content)).toEqual([content]);
|
||||
});
|
||||
|
||||
it('keeps double-newline paragraphs in the same bubble', () => {
|
||||
const content = 'First line\nSecond line\n\nThird paragraph\nFourth line';
|
||||
expect(splitAgentMessageIntoBubbles(content)).toEqual([
|
||||
|
||||
@@ -47,10 +47,29 @@ export function splitAgentMessageIntoBubbles(content: string): string[] {
|
||||
if (currentLines.length > 0) {
|
||||
flushCurrent();
|
||||
}
|
||||
// A prose line that merely contains a pipe (e.g. "pick A | B, then run
|
||||
// `ps aux | grep x`") satisfies looksLikeMarkdownTableRow but is not a
|
||||
// table row. Require the same column count as the header so it isn't
|
||||
// absorbed into the table — otherwise parseMarkdownTable rejects the
|
||||
// mismatched block (returns null), suppressing the table UI and merging
|
||||
// the prose line into the table bubble.
|
||||
//
|
||||
// Always keep at least the first data row, though: splitMarkdownTableCells
|
||||
// splits naively on "|" and does not honor escaped "\|" or pipes inside
|
||||
// code spans, so a genuine first row carrying such a pipe over-counts its
|
||||
// cells. Dropping it here would leave a header+separator-only block that
|
||||
// parseMarkdownTable renders as an empty-row table (and detaches the real
|
||||
// row). Keeping it preserves the count mismatch so parseMarkdownTable
|
||||
// returns null and the block falls back to readable raw markdown.
|
||||
const headerCellCount = splitMarkdownTableCells(line).length;
|
||||
const tableLines = [line, lines[index + 1]];
|
||||
index += 2;
|
||||
let dataRowsAbsorbed = 0;
|
||||
while (index < lines.length && looksLikeMarkdownTableRow(lines[index])) {
|
||||
const matches = splitMarkdownTableCells(lines[index]).length === headerCellCount;
|
||||
if (!matches && dataRowsAbsorbed > 0) break;
|
||||
tableLines.push(lines[index]);
|
||||
dataRowsAbsorbed += 1;
|
||||
index += 1;
|
||||
}
|
||||
index -= 1;
|
||||
|
||||
Reference in New Issue
Block a user