Skip to content

feat(dingtalk): default to public AI Card template for dynamic streaming#1

Open
sls-dev-agent wants to merge 2 commits into
mainfrom
feat/dingtalk-dynamic-card
Open

feat(dingtalk): default to public AI Card template for dynamic streaming#1
sls-dev-agent wants to merge 2 commits into
mainfrom
feat/dingtalk-dynamic-card

Conversation

@sls-dev-agent

Copy link
Copy Markdown
Owner

Summary

  • Make DingTalk channel stream replies into a single updatable AI Card by default, instead of dripping out as separate static markdown messages.
  • Borrows the public AI Card template ID 02fcf2f4-5e02-4a85-b672-46d1f715543e.schema from @dingtalk-real-ai/dingtalk-connector (openclaw plugin) so operators don't need to register a template themselves on DingTalk Open Platform.
  • Existing card_template_id overrides still work — the new behavior is opt-out via dynamic_card = false.

What changed

  • platform/dingtalk/dingtalk.go — new DefaultCardTemplateID constant, dynamic_card/useDefaultTemplate fields; factory falls back to public template when card_template_id unset (and card_template_key defaults to msgContent).
  • platform/dingtalk/card.go
    • For the default template, build the cardParamMap shape DingTalk's public template expects (flowStatus, msgContent, staticMsgContent, sys_full_json_obj, config).
    • Emit PUT /v1.0/card/instances with flowStatus=INPUTING before the first stream chunk and flowStatus=FINISHED on Finalize, so the loading spinner actually clears.
    • Port normalizeForCard (Go): convert single \n<br> outside fenced code blocks / lists / tables / headings, insert blank line before tables, merge consecutive quote-block lines.
    • Trim trailing newlines on intermediate frames to avoid <br> flicker.
    • Process-wide token-bucket QPS limiter (20 QPS, 2s backoff on QpsLimit 403) shared across all DingTalk instances.
  • config.example.toml — document the new defaults & options.
  • platform/dingtalk/card_test.go — 22 new tests.

Test plan

  • go test ./platform/dingtalk/ -count=1 — 22 new + originals all pass
  • go test ./core/ -count=1 — no regressions in engine StreamingCard tests
  • go vet ./platform/dingtalk/ clean
  • Manual: enable a DingTalk app with default config, send a long prompt, confirm reply renders as a single card that updates and finishes cleanly.
  • Manual: set dynamic_card = false, confirm fallback to plain markdown still works.
  • Manual: set a custom card_template_id, confirm legacy simple-shape flow still works.

🤖 Generated with Claude Code

crimson-gao and others added 2 commits May 20, 2026 02:03
Adopts the public AI Card template that @dingtalk-real-ai/dingtalk-connector
uses (02fcf2f4-...schema), so DingTalk replies stream into a single
updatable card out of the box — no manual template setup. Existing
card_template_id overrides keep the legacy simple flow.

- New `dynamic_card` toggle (default true)
- INPUTING / FINISHED flowStatus lifecycle PUTs for the public template
- Markdown normalize: `\n`→`<br>` outside fences/lists/tables, table
  blank-line insertion, consecutive quote-line merge
- Process-wide 20 QPS token bucket with QpsLimit backoff
- 22 new tests covering payload shape, lifecycle, normalize, limiter

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous StreamingCard contract aggregated thinking, tool calls, and
assistant text into a single bundled card body, so every turn ended with
the entire trace stuck in one message. Replicate dingtalk-real-ai's
reply-dispatcher behavior instead: the assistant reply is the persistent
card content, while tool-call and thinking events are short-lived
overlays that the next text chunk overwrites. Finalize now uses the
assistant text only — tool/thinking events do not pollute the final
card body.

- Drop cardToolEntry / buildCardContent / cardToolCalls / cardThinkingText
  from the engine; thinking and tool events Update() with a transient
  overlay string (existing MsgThinking / MsgTool i18n templates).
- Update StreamingCard / StreamingCardPlatform interface docs to match.
- Add TestStreamingCard_ToolAndThinkingDoNotAccumulate which drives
  Thinking + ToolUse + Text events through the engine and asserts the
  Finalize content is the assistant text only, while transient overlays
  do appear during streaming.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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