Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
adf939c
fix(streaming-markdown): list-marker awareness + table chunk-boundary
claude May 22, 2026
7eda040
refactor(_remend): match remend's flanking check for excluded asterisks
claude May 22, 2026
b7d7f83
fix(markdown): chat-scoped completeness (escaped chars, task lists, m…
claude May 22, 2026
ef085c3
fix(markdown): address PR #101 review findings
claude May 22, 2026
33b2eb5
fix(markdown): stringify round-trip for escapes + task list checked
claude May 22, 2026
797a360
fix(markdown): re-escape block-level markers at paragraph start
claude May 22, 2026
e67aa14
fix(markdown): escape block markers on every line of a paragraph
claude May 22, 2026
0bb0353
fix(streaming-markdown): preserve monotonicity on back-to-back tables
claude May 23, 2026
12fed10
fix(markdown): address PR #101 review findings (math, task nested)
claude May 23, 2026
9a2027f
docs(markdown): note fixed-width lookbehind limitation
claude May 23, 2026
48fa4f3
fix(markdown): doubled-backslash escape via sentinel-based pre-pass
claude May 23, 2026
03033b4
fix(markdown): harden escape sentinel + pin URL escape contract
claude May 23, 2026
79bf845
fix(markdown): don't leak escape sentinel from code spans ending in b…
claude May 23, 2026
97ef356
Merge branch 'claude/wizardly-heisenberg-VLInV' into claude/parser-ch…
claude May 23, 2026
c3b6962
ci: retrigger after pre-existing test_github_webhook flake
claude May 28, 2026
2856d95
fix(markdown): list-item continuation indent + hard break stringify
claude May 28, 2026
3eb87a0
Merge remote-tracking branch 'origin/main' into claude/parser-chat-co…
claude May 28, 2026
4fda9b4
Merge branch 'main' into claude/parser-chat-completeness
patrick-chinchill May 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions src/chat_sdk/shared/base_format_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,11 @@ def _render_list(
) -> str:
"""Render a list node with proper indentation.

Handles ordered and unordered lists and recurses into nested lists.
Handles ordered and unordered lists, recurses into nested lists,
and emits GFM task-list checkbox markers (``[ ]`` / ``[x]``) for
items carrying a ``checked`` attribute. Most chat platforms
either render the marker natively (GitHub, Linear) or display it
as literal text -- either way, dropping it would lose user data.
"""
indent = " " * depth
start = node.get("start", 1)
Expand All @@ -109,19 +113,37 @@ def _render_list(

for i, item in enumerate(get_node_children(node)):
prefix = f"{start + i}." if ordered else unordered_bullet
# GFM task-list marker, only on unordered items.
checked = item.get("checked") if not ordered else None
task_marker = ""
if checked is True:
task_marker = "[x] "
elif checked is False:
task_marker = "[ ] "
is_first_content = True
for child in get_node_children(item):
if child.get("type") == "list":
if is_first_content:
# No text child before this nested list -- emit
# the parent prefix on its own line BEFORE the
# nested list, or the checkbox/parent ordering
# ends up reversed (PR #101 review finding).
lines.append(f"{indent}{prefix} {task_marker}".rstrip())
is_first_content = False
lines.append(self._render_list(child, depth + 1, node_converter, unordered_bullet))
continue
text = node_converter(child)
if not text.strip():
continue
if is_first_content:
lines.append(f"{indent}{prefix} {text}")
lines.append(f"{indent}{prefix} {task_marker}{text}")
is_first_content = False
else:
lines.append(f"{indent} {text}")
# Item with zero rendered children -- still emit a line so the
# listItem (and any task marker) isn't lost.
if is_first_content:
lines.append(f"{indent}{prefix} {task_marker}".rstrip())

return "\n".join(lines)

Expand Down
Loading
Loading