Skip to content

feat(agents): plan checklist renderer — 4 formats, all statuses, activeForm [Phase 3.B]#67534

Closed
100yenadmin wants to merge 10 commits into
openclaw:mainfrom
electricsheephq:phase3/plan-rendering
Closed

feat(agents): plan checklist renderer — 4 formats, all statuses, activeForm [Phase 3.B]#67534
100yenadmin wants to merge 10 commits into
openclaw:mainfrom
electricsheephq:phase3/plan-rendering

Conversation

@100yenadmin

@100yenadmin 100yenadmin commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

TL;DR

Core plan rendering utility that formats plan checklists for HTML (Telegram), Markdown (GitHub), plaintext (SMS), and Slack mrkdwn. Supports all 4 statuses (pending, in_progress, completed, cancelled) with `activeForm` live progress text.

Tracking

What this PR does

`renderPlanChecklist()` + `renderPlanWithHeader()` utilities that take a plan's step array and produce formatted output for any channel:

Format Channel Example output
HTML Telegram ` Deploy to staging`
Markdown GitHub, CLI `- [x] Deploy to staging`
Plaintext SMS, logs `[✓] Deploy to staging`
Slack mrkdwn Slack `Deploy to staging` (cancelled)

`activeForm` renders live progress: shows "Building artifacts" instead of "Build artifacts" during `in_progress`.

Files changed

File Change Tests
`src/agents/plan-render.ts` New — renderer utilities 23 tests
`src/agents/plan-render.test.ts` New — all formats × statuses × edge cases Self

23 unit tests

  • All 4 formats × all 4 statuses
  • activeForm rendering
  • HTML escaping for injection prevention
  • Empty plan edge case
  • Header formatting

Dependencies

What follows

  • Channel adapters wire `renderPlanChecklist()` when handling plan events

…bility

Phase 3.B of the GPT 5.4 parity sprint. Adds a renderPlanChecklist()
utility that produces formatted checklists from AgentPlanEventData for
every delivery surface:

- html: Telegram HTML parse mode (emoji + <b>/<s> tags)
- markdown: GitHub-flavored checkboxes (Control UI, Matrix)
- plaintext: ASCII markers (iMessage, BlueBubbles, SMS)
- slack-mrkdwn: Slack's native formatting (*bold*, ~strike~)

Supports all four plan statuses from #67514:
- pending (⬚), in_progress (⏳), completed (✅), cancelled (❌)
- Uses activeForm for in_progress steps when available
- HTML-escapes user content to prevent injection

Includes renderPlanWithHeader() for titled checklists.
23 unit tests covering all formats, all statuses, edge cases.

This is the core renderer. Channel adapter wiring follows once
#67514 (task-system parity) merges and the extended AgentPlanEventData
type is available.

Tracking: #66345, #67519.
Copilot AI review requested due to automatic review settings April 16, 2026 05:43
@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: M labels Apr 16, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a core, format-agnostic plan checklist renderer under src/agents/ to support cross-channel visibility of structured agent plans (Phase 3.B), along with unit tests to validate output across formats/statuses.

Changes:

  • Introduces renderPlanChecklist() to render plan steps in HTML, Markdown, plaintext, and Slack mrkdwn.
  • Adds renderPlanWithHeader() to prepend a format-appropriate header to rendered checklists.
  • Adds Vitest coverage for all formats, all statuses, activeForm behavior, and HTML escaping.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
src/agents/plan-render.ts New plan rendering utilities for multiple channel-oriented text formats.
src/agents/plan-render.test.ts Unit tests validating renderer output across formats, statuses, and edge cases.

Comment thread src/agents/plan-render.ts Outdated
Comment thread src/agents/plan-render.ts Outdated
Comment thread src/agents/plan-render.ts Outdated
Comment thread src/agents/plan-render.test.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6e7675df0b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/agents/plan-render.ts Outdated
@greptile-apps

greptile-apps Bot commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds renderPlanChecklist() and renderPlanWithHeader() — new utilities that render structured plan steps as HTML, GFM markdown, plaintext, and Slack mrkdwn. The escaping pipeline is thorough and the test suite is well-structured, covering all format×status combinations, activeForm fallback, newline stripping, and mention neutralization. One gap in escapeMarkdown: the ~ character is absent from the character class, leaving GFM strikethrough injection possible (a step like "Deploy ~~now~~" renders as a struck-through span, and a cancelled row with embedded ~~ corrupts the renderer-added wrapper).

Confidence Score: 5/5

Safe to merge — only P2 findings remain; no logic errors, security issues, or broken paths.

All findings are P2: a missing ~ in the markdown escape character class (causes visual rendering quirks, not injection with code-execution risk) and a module-level Set that could affect test deduplication under --isolate=false. Both are minor and non-blocking.

src/agents/plan-render.ts — escapeMarkdown character class at line 175.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/agents/plan-render.ts
Line: 175

Comment:
**`~` missing from `escapeMarkdown` character class**

GFM strikethrough is triggered by `~~text~~`. A step label containing `~~` passes through unescaped, so `"Deploy ~~now~~"` renders as `- [ ] Deploy ~~now~~` (with "now" struck through), and inside a cancelled row it corrupts the renderer-added `~~…~~` wrapper.

```suggestion
  return text.replace(/[\\`*_~{}[\]()#+\-.!<>|]/g, "\\$&");
```

The test suite covers backticks, brackets, and emphasis but has no `~~` case — worth adding one alongside this fix.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/agents/plan-render.ts
Line: 187-196

Comment:
**Module-level `warnedStatuses` Set leaks between test runs**

`warnedStatuses` is never cleared, so any test that exercises the unknown-status path (e.g. a future JS caller bypassing types) will permanently suppress the warning for every subsequent test in the same process under `--isolate=false`. CLAUDE.md flags module state as something tests must be able to clean up.

The Set is purely a deduplication guard for a defensive console path that TypeScript callers can never reach anyway. Exporting a `resetWarningCacheForTest()` helper (or moving it to a closure inside a factory if the module grows) keeps the guard without the bleed risk.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "fix(agents): #67534 — neutralize @mentio..." | Re-trigger Greptile

Comment thread src/agents/plan-render.ts
Comment thread src/agents/plan-render.ts
…title

Step text containing *, ~, `, or <...> tokens would break Slack formatting
or trigger unintended mentions/links. Add escapeSlackMrkdwn() and apply it
to both step labels and the header title in slack-mrkdwn format.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ecd540190d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/agents/plan-render.ts
Eva added 2 commits April 16, 2026 13:48
…sing

Tool names like update_user_profile render as italic in Slack without
escaping. Replace _ with fullwidth low line (U+FF3F) which is visually
identical but not parsed as mrkdwn emphasis.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6496cd3b8d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/agents/plan-render.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

Comment thread src/agents/plan-render.ts
Comment thread src/agents/plan-render.ts
Comment thread src/agents/plan-render.ts Outdated
Comment thread src/agents/plan-render.test.ts
Model output for plan steps can contain embedded newlines which break
the single-line checklist rendering across all formats. Strip \n and
\r from labels before rendering.

Added test covering multi-line step text and activeForm.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread src/agents/plan-render.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6b0bf6e328

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/agents/plan-render.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

Comment thread src/agents/plan-render.ts
Comment thread src/agents/plan-render.ts
Comment thread src/agents/plan-render.ts Outdated
Comment thread src/agents/plan-render.test.ts
Replace @ with U+FE6B (small form variant) in escapeSlackMrkdwn to
prevent model-generated plan text from triggering @here/@channel/@everyone.
@100yenadmin

Copy link
Copy Markdown
Contributor Author

Merge order: 4/8. See #66345 for the full merge sequence.

…095517064)

Codex P2 (PR #67534 r3095517064):
> The plaintext renderer intentionally neutralizes @channel/@here/@everyone
> in step labels, but the header path emits safeTitle verbatim. When callers
> pass model- or user-derived titles (for example '@everyone release plan'),
> plaintext output can still trigger mentions even though checklist lines
> are protected.

Fix: pipe safeTitle through neutralizeMentions() in the plaintext branch
of renderPlanWithHeader. (HTML/markdown/slack-mrkdwn branches escape via
escapeHtml/escapeSlackMrkdwn which already neutralize the mention forms
relevant to those formats.)

Also: dropped a stale 'eslint-disable-next-line no-console' directive on
warnUnknownStatus that lint flagged as unused.

Tests: 2 new in plan-render.test.ts:
- '@everyone release plan' title in plaintext does not match /@everyone\\b/
- '@channel deploy now' / '@here urgent' both neutralized in title
40 tests pass.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

Comment thread src/agents/plan-render.ts
Comment thread src/agents/plan-render.ts
Comment thread src/agents/plan-render.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6069a036fe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/agents/plan-render.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment thread src/agents/plan-render.ts
Comment thread src/agents/plan-render.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment thread src/agents/plan-render.test.ts
Comment thread src/agents/plan-render.ts
@100yenadmin

Copy link
Copy Markdown
Contributor Author

Plan-mode rollout series — status update

This PR is part of a 10-PR plan-mode rollout. The cumulative state ships locally as OpenClaw 2026.4.15 (3a6ec73) from branch feat/plan-channel-parity (= PR #68441 head).

Series overview + landing order: see #68441 (latest comment).

This PR's role in the series: see the original PR description above.

Live test status: covered by the cumulative install — all behaviors from this PR are verified in production-like usage on Telegram + webchat. No regressions detected since the live install (2026-04-18).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread src/agents/plan-render.test.ts
@100yenadmin

Copy link
Copy Markdown
Contributor Author

📋 Architecture & Status — single source of truth (commit 39e63febad)

The plan-mode rollout now has a durable architecture document at docs/plans/PLAN-MODE-ARCHITECTURE.md that survives session compactions and tracks the full series.

Quick reference:

  • This is one of 10 open PRs in the cumulative plan-mode rollout (PR-A through PR-11 internal sprint numbering).
  • Recommended landing order: 5 waves (see ARCHITECTURE.md "Recommended landing waves").
  • The cumulative branch feat/plan-channel-parity is the LIVE install (OpenClaw 2026.4.15 (39e63fe)).
  • All 10 PRs target upstream main; each carries forward the cumulative diff which inflates the file count beyond Greptile's 100-file review cap.

Resolution path for the file-count inflation: land PRs in dependency order so the cumulative diff naturally shrinks as upstream main absorbs them. No PR closure/reopen needed — that would lose review history without solving the structural cumulative-rollout pattern.

Hardening status (review pass 1):

Newly-resolved escalation (commit 39e63febad): the previously-deferred #3104743333 (Codex P2 — update_plan merge-mode sidebar refresh) is now fixed via option C (re-emit merged steps via existing agent_plan_event channel). New AgentPlanEventData.mergedSteps field carries the full structured plan; UI subscribes via new maybeForwardMergedPlanEvent handler.

Current status of THIS PR specifically: see the existing comments + bot reviews above. Triage + reply pass coming in the next sprint.

cc @copilot @greptile-apps @chatgpt-codex-connector

@chatgpt-codex-connector

Copy link
Copy Markdown
Contributor

To use Codex here, create an environment for this repo.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

Comment thread src/agents/plan-render.ts
Comment on lines +146 to +158
/** Escapes Slack mrkdwn control characters: *, ~, `, _, and angle brackets. */
function escapeSlackMrkdwn(text: string): string {
// Replace angle-bracket tokens first, then mrkdwn formatting chars.
return text
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/\*/g, "\u2217") // ∗ (asterisk operator, visually similar)
.replace(/~/g, "\u223C") // ∼ (tilde operator)
.replace(/`/g, "\u2018") // ' (left single quote)
.replace(/_/g, "\uFF3F") // _ (fullwidth low line, prevents italic parse)
.replace(/@/g, "\uFE6B"); // ﹫ (small form variant, prevents mention parsing)
}

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

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

This file defines its own escapeSlackMrkdwn() that replaces characters with Unicode lookalikes and also rewrites @. The repo already has an established Slack mrkdwn escaping helper (extensions/slack/src/monitor/mrkdwn.ts) that backslash-escapes control chars and escapes &<>. To avoid drift and confusion (same name, different semantics), consider either reusing a shared helper (move to a common module) or aligning this implementation + tests with the established semantics.

Copilot uses AI. Check for mistakes.
Comment thread src/agents/plan-render.ts
Comment on lines +74 to +83
const markers: Record<PlanStepForRender["status"], string> = {
completed: "[x]",
in_progress: "[>]",
cancelled: "[~]",
pending: "[ ]",
};
if (!Object.hasOwn(markers, s.status)) {
warnUnknownStatus(s.status);
}
return `${markers[s.status] ?? "[ ]"} ${safe}`;

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

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

Unknown-status warning/handling is currently only implemented in the plaintext branch via Object.hasOwn(markers, s.status), but other formats silently treat unknown statuses as pending. If runtime data can be untrusted, consider validating/status-normalizing once before the switch (and warning consistently across formats), or removing the warning path if the status union is trusted.

Copilot uses AI. Check for mistakes.
Comment thread src/agents/plan-render.ts
Comment on lines +74 to +76
const markers: Record<PlanStepForRender["status"], string> = {
completed: "[x]",
in_progress: "[>]",

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

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

PR description examples say plaintext uses [✓] for completed, but the renderer outputs [x]. If downstream channel adapters/user-facing docs expect the checkmark variant, consider switching the completed marker or updating the documentation/examples to match this output.

Copilot uses AI. Check for mistakes.
@100yenadmin

Copy link
Copy Markdown
Contributor Author

Closing in favor of consolidated PR #68939.

Rationale: this branch was 734 commits behind upstream/main and the
PR's review feedback was firing against a stale base. Rebased the
full 135-commit feature work onto upstream/main @ v2026.4.19-beta.2
(only 5 conflicts to resolve) and consolidated the 10-PR series into
a single umbrella PR for cleaner bot review + faster maintainer
context-loading.

The full iteration history + decision log lives in
docs/plans/PLAN-MODE-ARCHITECTURE.md on the new branch. All
reviewed-and-resolved threads from this PR are honored — see the
architecture doc for what landed where.

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

Labels

agents Agent runtime and tooling size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants