Skip to content

feat(feishu): support optional header in streaming cards#22826

Merged
Takhoffman merged 1 commit intoopenclaw:mainfrom
nszhsl:feat/streaming-card-header
Feb 28, 2026
Merged

feat(feishu): support optional header in streaming cards#22826
Takhoffman merged 1 commit intoopenclaw:mainfrom
nszhsl:feat/streaming-card-header

Conversation

@nszhsl
Copy link
Copy Markdown
Contributor

@nszhsl nszhsl commented Feb 21, 2026

Summary

  • Add optional header parameter to FeishuStreamingSession.start() so streaming cards can display a colored title bar
  • The Card Kit API already supports header alongside streaming_mode, but the current implementation omits it — producing headerless white cards
  • Fully backward-compatible: when header is not provided, behavior is identical to before

Motivation

Streaming cards currently render without a title bar, making them visually inconsistent with non-streaming interactive cards. Users who set renderMode: "card" expect consistent card styling. Adding header support allows callers to pass a title and color template for a richer UI.

Related: #13267

Changes

extensions/feishu/src/streaming-card.ts

  • Export new type StreamingCardHeader with title (required) and template (optional color, defaults to "blue")
  • Add optional third parameter header?: StreamingCardHeader to start()
  • When provided, inject header into the Card Kit card JSON before creating the card entity

Test plan

  • Verify streaming cards without header param work unchanged (backward compat)
  • Verify streaming cards with header: { title: "Test", template: "green" } show colored title bar
  • Verify on both Feishu (飞书) and Lark clients

🤖 Generated with Claude Code

Greptile Summary

Adds optional header support to FeishuStreamingSession.start() so streaming cards can display a colored title bar via the Card Kit API. The change introduces a new exported StreamingCardHeader type and conditionally injects the header into the card JSON when provided. Fully backward-compatible — existing callers pass no header and behavior is unchanged.

  • The Card Kit header structure (title.tag, title.content, template) follows the Feishu v2 card schema correctly
  • The only current caller (reply-dispatcher.ts:102) does not yet pass a header, so this is plumbing-only at this stage — callers will need updates to actually surface the feature
  • Minor style note: cardJson type was widened from an inferred literal to Record<string, unknown>, which could be avoided with a spread pattern to preserve compile-time type safety

Confidence Score: 4/5

  • This PR is safe to merge — it adds an optional parameter with no behavioral change to existing callers.
  • Small, well-scoped change that is fully backward-compatible. The new parameter is optional and unused by current callers, so there is no risk of regression. Only a minor type-safety style concern was found.
  • No files require special attention.

Last reviewed commit: 999f82b

(2/5) Greptile learns from your feedback when you react with thumbs up/down!

Context used:

  • Context from dashboard - CLAUDE.md (source)

@openclaw-barnacle openclaw-barnacle bot added channel: feishu Channel integration: feishu size: XS labels Feb 21, 2026
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

const cardJson: Record<string, unknown> = {
schema: "2.0",
config: {
streaming_mode: true,
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.

Widened type loses compile-time safety

Changing cardJson from the inferred object literal to Record<string, unknown> drops all type information on the card structure. Per repo guidelines (prefer strict typing; avoid any), consider keeping the original inferred type and spreading the header into the object literal instead:

Suggested change
streaming_mode: true,
const cardJson = {

Then construct with the header inline:

const cardJson = {
  schema: "2.0" as const,
  config: { ... },
  body: { ... },
  ...(header && {
    header: {
      title: { tag: "plain_text" as const, content: header.title },
      template: header.template ?? "blue",
    },
  }),
};

This preserves the inferred literal type while conditionally including the header.

Context Used: Context from dashboard - CLAUDE.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/feishu/src/streaming-card.ts
Line: 98

Comment:
**Widened type loses compile-time safety**

Changing `cardJson` from the inferred object literal to `Record<string, unknown>` drops all type information on the card structure. Per repo guidelines (prefer strict typing; avoid `any`), consider keeping the original inferred type and spreading the header into the object literal instead:

```suggestion
    const cardJson = {
```

Then construct with the header inline:

```ts
const cardJson = {
  schema: "2.0" as const,
  config: { ... },
  body: { ... },
  ...(header && {
    header: {
      title: { tag: "plain_text" as const, content: header.title },
      template: header.template ?? "blue",
    },
  }),
};
```

This preserves the inferred literal type while conditionally including the header.

**Context Used:** Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8))

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

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

@openclaw-barnacle
Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle bot added the stale Marked as stale due to inactivity label Feb 28, 2026
Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes #13267 (partial)

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@Takhoffman Takhoffman force-pushed the feat/streaming-card-header branch from 999f82b to 5e87e30 Compare February 28, 2026 05:21
@Takhoffman Takhoffman merged commit 8a2273e into openclaw:main Feb 28, 2026
9 checks passed
@Takhoffman
Copy link
Copy Markdown
Contributor

PR #22826 - feat(feishu): support optional header in streaming cards (#22826)

Merged via squash.

  • Merge commit: 8a2273e
  • Verified:
    • pnpm check
    • pnpm test extensions/feishu/src/reply-dispatcher.test.ts
  • Changes made:
    • Rebased onto current main and resolved conflict in extensions/feishu/src/streaming-card.ts
    • Kept current thread/root reply options and added optional header support through existing start(..., options) API
  • Why these changes were made:
    • Preserve recently-landed Feishu topic/root threading behavior while landing the header feature without introducing API regressions.

Thanks @nszhsl!

r4jiv007 pushed a commit to r4jiv007/openclaw that referenced this pull request Feb 28, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
mylukin pushed a commit to mylukin/openclaw that referenced this pull request Feb 28, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
wanjizheng pushed a commit to wanjizheng/openclaw that referenced this pull request Feb 28, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
wanjizheng pushed a commit to wanjizheng/openclaw that referenced this pull request Feb 28, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
(cherry picked from commit f406fd6)
wanjizheng pushed a commit to wanjizheng/openclaw that referenced this pull request Feb 28, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
(cherry picked from commit f406fd6)
wanjizheng pushed a commit to wanjizheng/openclaw that referenced this pull request Feb 28, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
(cherry picked from commit f406fd6)
vincentkoc pushed a commit to Sid-Qin/openclaw that referenced this pull request Feb 28, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
vincentkoc pushed a commit to rylena/rylen-openclaw that referenced this pull request Feb 28, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
newtontech pushed a commit to newtontech/openclaw-fork that referenced this pull request Feb 28, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
wanjizheng pushed a commit to wanjizheng/openclaw that referenced this pull request Mar 1, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
wanjizheng pushed a commit to wanjizheng/openclaw that referenced this pull request Mar 1, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
zooqueen added a commit to hanzoai/bot that referenced this pull request Mar 1, 2026
ansh pushed a commit to vibecode/openclaw that referenced this pull request Mar 2, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
steipete pushed a commit to Sid-Qin/openclaw that referenced this pull request Mar 2, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
safzanpirani pushed a commit to safzanpirani/clawdbot that referenced this pull request Mar 2, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
steipete pushed a commit to Sid-Qin/openclaw that referenced this pull request Mar 2, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
venjiang pushed a commit to venjiang/openclaw that referenced this pull request Mar 2, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
execute008 pushed a commit to execute008/openclaw that referenced this pull request Mar 2, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
dorgonman pushed a commit to kanohorizonia/openclaw that referenced this pull request Mar 3, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
sachinkundu pushed a commit to sachinkundu/openclaw that referenced this pull request Mar 6, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
zooqueen added a commit to hanzoai/bot that referenced this pull request Mar 6, 2026
zooqueen pushed a commit to hanzoai/bot that referenced this pull request Mar 6, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)
Mateljan1 pushed a commit to Mateljan1/openclaw that referenced this pull request Mar 7, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
alexey-pelykh pushed a commit to remoteclaw/remoteclaw that referenced this pull request Mar 15, 2026
)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)

Co-authored-by: Claude Opus 4.6 <[email protected]>
(cherry picked from commit 8a2273e)
alexey-pelykh added a commit to remoteclaw/remoteclaw that referenced this pull request Mar 15, 2026
) (#1474)

Add an optional `header` parameter to `FeishuStreamingSession.start()`
so that streaming cards can display a colored title bar, matching the
appearance of non-streaming interactive cards.

The Card Kit API already supports `header` alongside `streaming_mode`,
but the current implementation omits it, producing headerless cards.

This change is fully backward-compatible: when `header` is not provided,
behavior is identical to before.

Closes openclaw#13267 (partial)


(cherry picked from commit 8a2273e)

Co-authored-by: songlei <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: feishu Channel integration: feishu size: XS stale Marked as stale due to inactivity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants