Skip to content

feat: display model name in Feishu card footer#199

Open
qianhaizhang wants to merge 2 commits intolarksuite:mainfrom
qianhaizhang:feature/footer-model-display
Open

feat: display model name in Feishu card footer#199
qianhaizhang wants to merge 2 commits intolarksuite:mainfrom
qianhaizhang:feature/footer-model-display

Conversation

@qianhaizhang
Copy link
Copy Markdown

@qianhaizhang qianhaizhang commented Mar 19, 2026

Summary

Add support for displaying the AI model name in the Feishu card footer. This feature allows users to see which model (including provider and think mode) was used to generate responses directly in the Feishu message card.

Changes

  • Added footer.model config option to enable/disable model display
  • Display format: provider/model (e.g., "anthropic/claude-sonnet-4-6")
  • Filter out models ending with "off" (think mode indicator)
  • Show thinkLevel as suffix when not "off" (e.g., "model (extended)")

Files Changed

  • src/card/builder.ts - Main footer rendering logic
  • src/card/reply-dispatcher.ts - Pass model info to controller
  • src/card/streaming-card-controller.ts - Handle model selection
  • src/core/config-schema.ts - Config schema update
  • src/core/footer-config.ts - Footer config type
  • src/card/__tests__/footer-model.test.ts - 30 unit tests

Test plan

  • Verify model name displays correctly in Feishu card footer
  • Test with different provider/model combinations
  • Test think mode filtering (models ending with "off")
  • Test thinkLevel suffix display when not "off"
  • Run existing unit tests to ensure no regression
  • Test with footer.model disabled (should not show model)

🤖 Generated with Claude Code

qianhai and others added 2 commits March 19, 2026 02:54
Add support for displaying the selected model name in the Feishu
message card footer. Users can enable this via the footer.model
configuration option.

- Add model field to FeishuFooterConfig type
- Update default footer config with model: false
- Pass model info from onModelSelected callback to StreamingCardController
- Render model name in card footer when enabled
- Filter models ending with "off" from display (e.g., "claude-sonnet-4-6-off")
- Display provider in format: provider/model (e.g., "anthropic/claude-sonnet-4-6")
- Show thinkLevel as suffix when not "off" (e.g., "model (extended)")

Example display:
- Chinese: 已完成 · 耗时 12.3s · anthropic/claude-sonnet-4-6
- English: Completed · Elapsed 12.3s · anthropic/claude-sonnet-4-6

Configuration:
  openclaw config set channels.feishu.footer.model true

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 30 unit tests covering all 8 combinations of footer elements:
- Happy path: model display with/without provider, thinkLevel filtering
- Edge cases: all 8 combinations of status/elapsed/model toggles
- Error and aborted states with model display
- Fix bug: model parameter not passed to buildCompleteCard
- Fix bug: thinkLevel "off" still displayed as suffix

Footer combinations covered:
✓ status + elapsed + model
✓ status + elapsed
✓ status + model
✓ elapsed + model
✓ status only
✓ elapsed only
✓ model only
✓ all disabled

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@HanShaoshuai-k HanShaoshuai-k added feature request New feature or request messaging src/messaging/ + src/card/ — message rendering, cards, streaming labels Mar 20, 2026
Copy link
Copy Markdown
Collaborator

@HanShaoshuai-k HanShaoshuai-k left a comment

Choose a reason for hiding this comment

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

Nice feature! The test coverage is solid and the default-off behavior is a good design choice. A few things to address:

Must Fix:

reply-dispatcher.ts L305-L320: The onModelSelectedWrapper breaks the original callback semantics — when ctx is undefined, prefixContext.onModelSelected is never called, which may break prefix context state reset. The forward should be unconditional:

const onModelSelectedWrapper = (
  ctx: { provider: string; model: string; thinkLevel: string | undefined } | undefined,
) => {
  if (ctx && controller) {
    controller.setModel(ctx);
  }
  prefixContext.onModelSelected(ctx);
};

Should Fix:

  1. The model type { provider: string; model: string; thinkLevel?: string } is duplicated inline in 4+ places. Consider extracting a shared ModelInfo interface in src/core/types.ts.
  2. Missing vitest.config.ts — the PR adds vitest as a dependency but no config file. vitest run may not behave as expected without it.
  3. provider is typed as required string but tests pass objects without it (e.g. { model: 'claude-haiku-4-5' }). Should be provider?: string.

Minor:

  • Missing newline at end of footer-model.test.ts
  • setModel tests only assert expect(controller).toBeDefined() — not very meaningful

Question: The "filter models ending with off" logic relies on SDK internal naming conventions. Is this a stable contract, or would it be safer to rely solely on the thinkLevel field?

@HanShaoshuai-k HanShaoshuai-k added the changes requested Need do changes label Mar 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changes requested Need do changes feature request New feature or request messaging src/messaging/ + src/card/ — message rendering, cards, streaming

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants