An installable, build-pinned patch for the OpenClaw Feishu channel plugin.
It turns tool-call progress, commentary and process events into one readable streaming card instead of a wall of bubbles. The answer body stays clean: a phase status line and a transient activity line show progress while the turn runs, and the full history collapses into a chronological process record after the answer.
- Supported plugin build:
@openclaw/feishu2026.10.9 - Patch type: unified diff against the installed
dist/.setup/monitor.account-*.mjs - Install: one shell script; exact SHA-256 check; automatic backup; automatic rollback on failure
- No credentials required by this repository
This repository ships the patch, installer, tests, adapter and docs only. It does not redistribute the upstream plugin bundle.
- Folds recognized tool/narration/process progress into one streaming card, including generic bare labels such as
Nodes. - Phase status line shows stage, tool count and elapsed time; the final status keeps a single completion summary.
- Phase status line is a single grey row that also carries the latest narration while the turn runs; the separate activity row was removed.
- Process panel keeps a static header and writes its body in place, so an expanded panel stays expanded; the body opens with a grey breakdown such as
3 次工具 · 2 条旁白 · 1 个错误instead of overlapping totals. - Process rows use per-tool icons with grey relative timestamps and friendly display names (
读取,网页抓取); zero-second stamps and code-styled labels are gone, and dropped early entries are marked explicitly. - Empty/tool-only turns keep a readable chat preview (
✅ 完成 · N 工具 · Xs) instead of an invisible zero-width summary; per-turn update budgets roll over each minute so long tool runs are not frozen. - Long answers surface the page index in the status line (
✅ 完成 · … · 📄 1/3) instead of hiding it in the footer; tool errors raise a 4s transient status notice. - Transient activity line shows only the latest narration before the answer starts, then disappears so the answer body is not displaced.
- One collapsed
🧾 过程记录panel contains reasoning plus a chronological activity timeline. - Consecutive identical tools are merged (
Exec ×N); the timeline marks how many earlier entries were omitted when the 12-entry/1200-character cap is reached. - Background progress gets a dedicated
🧾 后台任务 · <agent>card instead of standalone posts. - Long answers paginate: the first chunk stays in the streaming card (footer
1/N), continuation cards are numbered2/N,3/Nand omit details/footer; media is delivered after the page sequence. - Group mention requirements are preserved on paginated cards and continuations.
- Final dedupe covers paginated sends; background card closes are serialized so a new turn cannot race a stale background card.
- Prewarms the card at reply start and shows an immediate status (no blank warm card).
- Holds an active card until final delivery; merges cumulative block text instead of blindly appending; prevents duplicate cards and duplicated answer prefixes.
- The 2026.10.9 monitor bundle is byte-identical to 2026.10.8: it keeps upstream's frozen-prefix streaming model (
onAssistantMessageStartboundary, PR #182438) and the Card JSON 2.0column_setaction-card fix (PR #79832) on top of the aggregation layout. - Caches/limits reasoning preview; final cards remove the thinking panel when an answer exists. Truncated reasoning closes open code fences so it cannot swallow the activity timeline.
- Card updates are coalesced into a 300ms window; status and process-record writes have per-turn budgets.
- Reliability batch 2: status-element writes retry transient failures (HTTP 408/429/5xx, network, Feishu backoff codes) with a bounded backoff before falling back into the content element; permanent validation/permission errors fall back immediately.
- Batch 3/4: the final grey completion status is written even after the session is marked closed; it no longer stays at
✍️ 生成回复中when a turn finishes. The delete-failure fallback clears the status element through the same post-close path. - Reliability batch 2: content/status/detail writes only advance the acknowledged cache after the provider confirms success; failed writes are retried (bounded) instead of being treated as delivered.
- A card watchdog force-finalizes cards that exceed the maximum lifetime.
- Reasoning and tool-error text are capped/redacted before entering the process record; dynamic card text is HTML/markdown escaped and the footer note is escaped before its grey wrapper.
- Exact-build installer: unknown builds are refused, never fuzzy-patched; automatic backup and rollback.
- Anchor adapter for future builds; CI validates the pinned 2026.10.9 npm tarball.
- Content-free diagnostics for tool-shaped payloads that could not be aggregated.
- Installer
--check/--dry-run, atomic target replacement, install lock and GNUsha256sum/ BSDshasumfallback. - Generated installer version/upgrade tables + CI release/docs consistency checks.
| item | value |
|---|---|
| OpenClaw Feishu plugin | @openclaw/feishu@2026.10.9 |
| pristine bundle | ec9d77bfcaf19bad9e888e62bc7c3a1dce8b3c1b4cfbcb1eca9a2b26070cfdf4 |
| patched bundle | 6b183987c2d954c99693ce3b94a7a47e05e8bac87a7fa94a8aaca7a6b9aab1e9 |
| patch | c00af363bf35c6384f26eef029e5ff70f54982d94f49e295a401a9bc4fc85686 |
| batch-1 upgrade source | 9cd54d3261639e2e40a401dcf6480acd555a8c458b29b696836b0f85a3f54496 |
| batch-2 upgrade source | c70fc9c5739de593fa91b1aead322bee55d8d0e7ef7c48415e2ae5b1b822b7d1 |
| batch-3 upgrade source | e49cb6dab0d7c2b408f86304e7d93ce18b6ad542cc1d44a73fe4aa9f5359c6b0 |
| patch hunks | 34 |
| test assertions | 578 |
The installer computes the SHA-256 of the target bundle and applies when it matches a pristine build or a known upgradable batch-1/batch-2/batch-3 build. If the target is already patched, it reports already patched. Any other build is refused.
Requirements: Linux/macOS (or WSL), bash, patch, sha256sum.
git clone https://github.com/Leorand-dev/openclaw-feishu-patch.git
cd openclaw-feishu-patch
TARGET=$(ls ~/.openclaw/npm/projects/*/node_modules/@openclaw/feishu/dist/.setup/monitor.account-*.mjs | head -1)
./install.sh "$TARGET"
# restart the OpenClaw gateway (systemd example)
systemctl --user restart openclaw-gateway.serviceThe installer prints the backup path and the patched SHA-256. It verifies the post-patch hash and restores the backup automatically on any failure.
The installer also accepts the UI-batch-1 bundle (9cd54d3261639e2e40a401dcf6480acd555a8c458b29b696836b0f85a3f54496), the batch-2
bundle (c70fc9c5739de593fa91b1aead322bee55d8d0e7ef7c48415e2ae5b1b822b7d1) and the batch-3 bundle
(e49cb6dab0d7c2b408f86304e7d93ce18b6ad542cc1d44a73fe4aa9f5359c6b0) and applies the matching delta. No pristine restore is
required:
./install.sh --check "$TARGET" # status=upgradable from=<current sha>
./install.sh "$TARGET" # applies the delta, verifies 6b183987c2d954c99693ce3b94a7a47e05e8bac87a7fa94a8aaca7a6b9aab1e9The deltas are shipped as
patches/2026.10.9/feishu-tool-aggregation-batch1-to-batch4.patch,
patches/2026.10.9/feishu-tool-aggregation-batch2-to-batch4.patch and
patches/2026.10.9/feishu-tool-aggregation-batch3-to-batch4.patch, recorded in
patches/UPGRADES.json. A backup is created before the upgrade.
For agent-oriented instructions see AGENTS.md.
sha256sum -c SHA256SUMS
cd tests
node run-all.mjs "$TARGET"run-all.mjs runs all thirteen suites. Node 24+ is expected. The suites read the bundle path from argv[2] (or BUNDLE), so they can also audit an installed live copy.
Mechanical checks:
# requires the pristine/patched bundle pairs next to each patch (internal worktree)
python3 tools/verify_patch.py --all=patchesExpected result: 34 hunks, forward/reverse byte-exact, 13/13 suites, 578 assertions. CI re-runs all of it against the pristine 2026.10.9 npm tarball.
The installer creates .monitor.backup-*.mjs next to the target. To roll back:
TARGET=$(ls ~/.openclaw/npm/projects/*/node_modules/@openclaw/feishu/dist/.setup/monitor.account-*.mjs | head -1)
cp -p "$(ls -t "$(dirname "$TARGET")"/.monitor.backup-*.mjs | head -1)" "$TARGET"
systemctl --user restart openclaw-gateway.serviceThe patched bundle hash can also be matched against patches/MANIFEST.json to confirm state.
The patch currently exposes behavior through code defaults. OpenClaw's plugin schema rejects unknown Feishu config keys (must not have additional properties), so do not add these keys to channels.feishu unless a schema adapter is installed; it will make the config invalid.
Current defaults:
| behavior | default |
|---|---|
| prewarm card at reply start | on |
dedicated status element |
on |
| status position | top |
| elapsed refresh | 15s |
| compact status | single phase line |
| narration cap | 80 characters |
| details display | one collapsed 🧾 过程记录 panel with reasoning and a chronological activity timeline |
| narration display | transient activity line above the answer while running; hidden once the answer starts; history in the process timeline |
| no-card progress | a dedicated background card instead of standalone posts |
| long answer pagination | first chunk stays in the streaming card; continuation cards are numbered 2/N, 3/N with no repeated details/footer; media is sent after the pages |
| completion status | final status element keeps ✅ 完成 · tools · errors · elapsed; the body does not repeat it |
| background card | background work gets a distinct 🧾 后台任务 · <agent> header |
| hide reasoning in final card | panel removed when answer exists |
| final tool summary | on |
| final chat preview | answer summary, ✅ 已回复 fallback |
Prerequisite for tool-summary aggregation: verboseLevel: on. With verboseLevel: off tool events never reach the plugin hooks, so no progress line is aggregated.
This is intentionally not a fuzzy patch. For a new @openclaw/feishu build:
-
Fetch/extract the new pristine bundle.
-
Run the anchor adapter using the current patch as the reference:
python3 tools/adapt_patch.py \ --pristine "$NEW_BUNDLE" \ --from-patch patches/2026.10.9/feishu-tool-aggregation.patch \ --version <new-version> \ --out-dir patches/<new-version> \ --update-manifest --set-current
-
The adapter re-locates every hunk by its full old block, requires a unique match, and never uses line numbers/fuzz. If upstream changed the block, it fails loudly.
-
Review the diff, add the printed install line to
install.sh, add the version to the CI matrix, run the tests, canary the new build, then commit.
The CI workflow (.github/workflows/verify.yml) validates supported versions by fetching the pristine npm package, running the anchor adapter, applying the patch, doing a reverse-diff sanity check, and running all tests.
verboseLevel: onis required for tool-summary aggregation.- MCP/custom tools outside the normalized label whitelist, and shell summaries emitted as detail-only text in
verboseLevel: full, keep the legacy delivery path rather than being counted in the card. - This patch targets one exact plugin build. Upgrading
@openclaw/feishurewritesdist/and reverts the patch; re-apply or re-derive it. - The plugin's config schema is not extended by this repository; behavior defaults are compiled in.
- The installer uses
patch,sha256sumandbash; Windows users should use WSL or an equivalent POSIX environment. - No credentials, tokens or host-specific data are stored in this repository.
If the OpenClaw gateway is restarted while a turn is streaming (for example
via a /restart command or a supervisor restart), the plugin's streaming card
is closed by the outage. During restart recovery, tool and narration progress
can be emitted before a new streaming card exists, so some of it may appear as
standalone posts (for example Exec, View Image, 💬 ...). A separate
recovery card may also appear.
This is restart-recovery behavior, not a missing label in the aggregation
whitelist. Labels such as Exec and View Image are already covered. Once a
new user turn starts after the gateway is healthy, progress returns to the
single-card flow.
Mitigation: restart the gateway when idle. An optional future guard could suppress recognized tool-summary posts while streaming start is in backoff, at the cost of temporarily hiding tool progress during recovery.
A prewarmed card shows ⏳ 思考中… until the first tool, narration, or answer
text arrives. Silent turns with no content/tools/narration discard the empty
card instead of leaving it behind.
README.md this file
AGENTS.md concise instructions for automated agents
VERIFICATION.md verification evidence for the current build
LICENSE MIT
install.sh exact-build installer: hash select, backup, rollback
SHA256SUMS installer + manifest/upgrade + patch hashes
patches/
MANIFEST.json supported version hashes/status + upgrade sources
UPGRADES.json batch-1/batch-2/batch-3 -> batch-4 delta metadata
2026.10.9/
feishu-tool-aggregation.patch
feishu-tool-aggregation-batch1-to-batch4.patch
feishu-tool-aggregation-batch2-to-batch4.patch
feishu-tool-aggregation-batch3-to-batch4.patch
tests/ thirteen JavaScript suites
tools/
adapt_patch.py anchor-based adapter for future builds
check_docs.py release metadata/docs consistency check
finalize.py regenerate canonical patch + metadata + checksums
verify_patch.py strict patch applier/verifier
.github/workflows/verify.yml CI matrix
MIT — see LICENSE.
This is a modification of the OpenClaw Feishu channel plugin; the upstream plugin and its code remain subject to their own license.