Skip to content

fix(plan-mode): render plan_ready output as Markdown - #293

Open
Matt-qwq wants to merge 2 commits into
openpi-dev:mainfrom
Matt-qwq:fix/plan-ready-markdown-render
Open

fix(plan-mode): render plan_ready output as Markdown#293
Matt-qwq wants to merge 2 commits into
openpi-dev:mainfrom
Matt-qwq:fix/plan-ready-markdown-render

Conversation

@Matt-qwq

Copy link
Copy Markdown

Problem

plan_ready renders the finalized plan as raw Markdown source in the TUI.

extensions/plan-mode/index.ts registers plan_ready with only an execute handler and no renderResult, so the TUI falls back to its default plain-text renderer: headings, lists, and code fences appear as literal #, -, and ```
characters instead of rendered text.

Affects every Plan Mode user — the plan is the one artifact Plan Mode exists to produce, and it is meant to be read, not inspected as source.

No existing issue tracks this. I searched plan_ready, renderResult, and Markdown-rendering across open and closed issues in openpi-dev/openpi; the closest hits (#28, #27, #18, #105, #101, #96, #93, #67, #40) are all about other
subsystems.

Value

Every other extension tool that returns human-readable prose already supplies a renderer — there are 19 renderResult implementations across goal, tasks, git-read, file-search, workflows, subagents, ask-user,
background-terminals, and file-mutation-display. plan_ready is the outlier. Rendering it makes Plan Mode's output consistent with the rest of OpenPI and lets the user read the plan without decoding Markdown syntax.

Approach

Add renderResult to the plan_ready registration, rendering result.details.plan with the Markdown component from @earendil-works/pi-tui using getMarkdownTheme() — the same treatment renderWaitResult() gives subagent results
(extensions/subagents/src/ui/wait-result.ts:59).

Two deliberate choices:

  • No line cap or collapsed preview. Pi already provides Ctrl+O expand/collapse for tool results; adding a second truncation layer would duplicate that mechanism. The plan is bounded upstream at MAX_READY_PLAN_UTF8_BYTES (48 KB).
  • No re-sanitizing. execute already stores sanitizeTerminalText(params.plan), so details.plan is clean on the way in.

Validation

Ran on WSL2 (Fedora 44), Node v22.23.1, bun 1.3.14:

bun run check   # biome format (257 files), biome lint --error-on-warnings, tsc --noEmit
bun run test    # node:test  968 cases: 967 pass / 0 fail / 1 skipped
                # vitest       1 file:  30 tests passed

bun run test grows from 959 to 968 cases — the 9 in tests/extensions/plan-mode/result-rendering.test.ts. Those were verified red against the pre-fix code: with renderResult removed, all nine fail with plan_ready must supply renderResult, so they catch the regression rather than document it.

Manual TUI check. Loaded the checkout with pi install, ran /plan, and called plan_ready with a plan exercising headings, ordered and nested lists, a block quote, a table, inline code, bold, italics, links, three fenced code shapes,
and a thematic break. In the TUI: heading markers are consumed, the table renders with box-drawing characters, the quote gets a gutter, links render as label (URL), the thematic break becomes a rule, and fenced code bodies are
indented two spaces.

Two behaviors are pi-tui's design, not regressions:

  • Code fences keep the literal ``` characters — Markdown renders them via theme.codeBlockBorder() (pi-tui/dist/components/markdown.js:384) and colors them rather than drawing a background block.
  • Headings level 3 and deeper keep their ### prefix; only levels 1–2 hide it (markdown.js:350). Level 3+ still receives heading color and bold.

Impact

  • User-visible behavior: plan_ready output now goes through the TUI Markdown renderer instead of the plain-text fallback. Heading markers are consumed, list bullets and code fences are colored, inline code / bold / italic / link
    markers are consumed, tables are drawn with box characters, and fenced code bodies are indented. Nothing else changes.
  • Model-visible context / tools: none. No change to tool name, description, promptSnippet, promptGuidelines, parameters, or the text returned in content — only how the result is drawn.
  • Runtime / lifecycle: none. renderResult is pure presentation; terminate: true semantics and the plan-state commit are untouched.
  • Persisted config / data: none.
  • Compatibility / risk: low. plan_ready remains parent-only (already in CHILD_EXCLUDED_TOOL_NAMES, extensions/shared/child-session.ts:452), so the child-session drift guard is unaffected — its test passes.

plan_ready registered no renderResult, so the TUI fell back to its plain-text renderer and the recorded plan appeared as raw Markdown source. Render it with the Markdown component, the same treatment subagent results already get.

Validated with bun run check (format, lint, tsc) and bun run test (959 node:test cases and 30 vitest cases pass) on Linux.
Nine cases pin that the renderer is registered and that a realistic plan survives it: headings, ordered and nested lists, block quotes, tables, inline code and bold, links, three fenced code shapes, a thematic break, a 40K plan, and unicode.

Assertions strip ANSI first, because the Markdown component colors itself from the global theme rather than the theme passed to renderResult.

Verified red against the pre-fix code (all nine fail with "plan_ready must supply renderResult"), so these catch the regression rather than just documenting it.

@tt-a1i tt-a1i left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Must-Fix:extensions/plan-mode/index.ts:455-462 的自定义 renderResult 忽略了 options.expanded,折叠态和展开态都会返回完整 Markdown。Pi 会把 expanded 状态传给自定义 renderer,但不会替它截断 renderer 返回的行;因此接近现有 48 KiB 上限的计划会在默认折叠态整段铺进 transcript,Ctrl+O 也不会产生任何折叠效果。新增测试 tests/extensions/plan-mode/result-rendering.test.ts:242-252 还把 collapsed/expanded 完全相同固定成了预期,这与 PR 中“Pi 已提供 expand/collapse,所以不需要第二层截断”的理由相矛盾。请在 expanded === false 时提供有界摘要/预览,在展开态再渲染完整 Markdown,并补一条长计划测试,证明默认输出行数有界且展开能恢复完整内容。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants