chatmsg

package
v1.0.57-beta.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 6, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Overview

Package chatmsg holds the shared, read-only projection helpers for DingTalk message-list responses (list_individual_chat_message, list_conversation_message_v2, search_at_me_message, search_messages_by_keyword, list_topic_replies, …). Several shortcuts reshape those raw responses into a clean speaker/text/time list; centralising the fiddly bits here keeps them consistent and fixed in one place:

  • Sender: the display name lives under the bare "sender" key, forwarded entries carry the literal string "null", and some responses nest the speaker in a {name:…} object — all handled here.
  • Text: out-of-office auto-replies / cards arrive as raw rich-content JSON, and card/robot messages arrive as undecryptable ciphertext; CleanText renders the former to readable text and marks the latter, WITHOUT ever rewriting ordinary text that merely contains a JSON fragment.
  • Forwarded: a forwarded chat record ("聊天记录") hides its real per-message bodies in forwardMessages while the top-level content is a lossy summary.

Index

Constants

View Source
const MessageListContractVersion = "im.message-list.v1"

MessageListContractVersion identifies the additive, compatibility-preserving public envelope shared by message list/search/mget/thread projections.

Variables

This section is empty.

Functions

func ApplyMessagePagination

func ApplyMessagePagination(payload, data map[string]any, messages []map[string]any, direction string)

ApplyMessagePagination publishes message-list completeness without claiming the lower response's nextCursor is a valid CLI input. DingTalk's executable message-list contract paginates with the boundary message createTime, so the resume object uses exactly that accepted parameter.

func ApplyPagination

func ApplyPagination(payload, data map[string]any)

ApplyPagination carries lower-layer completeness facts into a projected Shortcut payload. It intentionally preserves cursor values only in the command output (where callers need them to continue); audit reports redact those values and retain only their presence.

func CleanText

func CleanText(s string) string

CleanText makes a message body human-readable WITHOUT ever rewriting ordinary text. It only transforms a body that is a genuine DingTalk structured message:

  • Encrypted card/robot ciphertext (base64 + "||v||t||len" trailer) → a clear "[加密消息]" marker instead of the raw base64.
  • A rich-content card (out-of-office auto-reply, link/preview card, …) whose lines include at least one recognised rich-content block → the readable text extracted from those blocks, with the card's decorative JSON lines and "empty" placeholders dropped.

Crucially, if NO line is a recognised rich-content block (e.g. ordinary text that merely embeds a `{"approved":false}` fragment), the original string is returned verbatim — a JSON line is never silently dropped.

func ConversationID

func ConversationID(m map[string]any) any

ConversationID preserves the stable conversation identity carried by list and search responses.

func CreateTime

func CreateTime(m map[string]any) any

CreateTime reads a message's create/send time under whichever candidate key is present, returning the raw value.

func Forwarded

func Forwarded(m map[string]any, project func(map[string]any) map[string]any) []map[string]any

Forwarded projects the nested messages of a forwarded chat record. The caller supplies its own per-message projection so each command keeps its own row shape; project is applied recursively, so multi-level forwards expand too.

func IsEncrypted

func IsEncrypted(s string) bool

IsEncrypted reports whether a message body is a raw DingTalk encrypted-message ciphertext: a base64 blob (DingTalk wraps it across several lines) followed by the "||v||t||len" trailer. It is intentionally strict — both the trailer and a pure-base64 body are required — so ordinary text (CJK, punctuation, …) never trips it.

func MessageID

func MessageID(m map[string]any) any

MessageID preserves the stable message identity needed by follow-up reply, reaction, resource and deduplication operations.

func MessageType

func MessageType(m map[string]any) any

MessageType preserves the lower message type when present.

func NewMessageListPayload added in v1.0.57

func NewMessageListPayload(messages []map[string]any) map[string]any

NewMessageListPayload initializes the common result ledger before a caller adds pagination or resource-download facts.

func Pagination

func Pagination(data map[string]any) map[string]any

Pagination extracts hasMore/nextCursor from the response root or a common result/data envelope. When hasMore is present it also emits the explicit inverse "complete", making truncation hard for an Agent to overlook.

func ProjectMessageV1 added in v1.0.57

func ProjectMessageV1(m map[string]any, includeReactions bool) map[string]any

ProjectMessageV1 is the single compatibility-preserving core projection for list, search, mget, @me, and thread readers. Public wrappers may retain legacy aliases such as time or msgType, but the underlying identity, context, reaction, quote, forward, and resource semantics come from here.

func QuotedMessage

func QuotedMessage(m map[string]any) map[string]any

QuotedMessage projects one level of quoted/replied-to context. It is deliberately non-recursive: a reply chain may be arbitrarily deep or even cyclic after gateway reshaping, while an Agent primarily needs the quoted message's stable identity, speaker, readable body and time.

func Reactions

func Reactions(m map[string]any) map[string]any

Reactions normalises DingTalk's inline emotionReplyList into one compact, Agent-friendly block. Unlike Lark, DingTalk already returns these reactions with message-list responses, so this projection performs no extra network request.

Output shape:

"reactions": {
  "counts":  [{"emoji": "赞", "count": 3}],
  "details": [{"emoji": "赞", "replyUsers": ["..."]}]
}

func Resources

func Resources(m map[string]any) []map[string]any

Resources extracts actionable media and drive-file references from both structured message fields and the textual mediaId/fileId notation returned by older DingTalk message APIs. Every reference publishes the exact Shortcut arguments already known from the message, plus ready=false and missing fields when a follow-up lookup is still required. This shared shape is used by list, search, mget, quoted messages and thread replies.

func ResourcesDeep added in v1.0.56

func ResourcesDeep(m map[string]any) []map[string]any

ResourcesDeep returns resources from a message and each nested quoted, replied-to or forwarded message. Every nested resource is projected from the child message that owns it, so its download arguments never reuse the parent message ID. A missing child conversation ID inherits the enclosing conversation because quoted and forwarded records often omit that duplicate field.

func Sender

func Sender(m map[string]any) any

Sender reads a message's speaker display name, tolerating common sender-name keys. The message-list responses carry the display name under the bare "sender" key (verified live), so it is probed first; the remaining aliases and the *Id fallbacks keep the projection resilient to other shapes. The literal string "null" (forwarded entries) and the empty string are treated as absent, and a nested {name:…} sender object yields its display name rather than the raw object.

func SenderID added in v1.0.57

func SenderID(m map[string]any) any

SenderID preserves the stable sender identity without replacing the legacy scalar sender display field. Nested sender records and both userId families are accepted because list/search/mget currently expose different shapes.

func SenderType added in v1.0.57

func SenderType(m map[string]any) any

SenderType returns only an explicitly published lower sender type. It does not guess that every sender identity is a user because bot/system messages can share the same generic senderId key.

func StableMessageID added in v1.0.57

func StableMessageID(message map[string]any) string

StableMessageID returns the normalized message identity used for cross-page deduplication. An empty value means the lower response did not publish a stable identity; callers must keep that row rather than guessing.

func Text

func Text(m map[string]any) any

Text reads a message's textual content (tolerating common text keys and one level of nesting) and runs it through CleanText.

func ThreadID

func ThreadID(m map[string]any) any

ThreadID preserves the stable topic/thread identity needed to continue from a message-list result into the thread-replies command.

func UpdateTime

func UpdateTime(m map[string]any) any

UpdateTime reads an edited message's update time. Gateways sometimes echo createTime as updateTime even when the message was never edited; omit that duplicate so Agents do not infer a nonexistent edit.

Types

type MessageResultContract added in v1.0.57

type MessageResultContract struct {
	Version        string
	MessageFields  []string
	EnvelopeFields []string
}

MessageResultContract is the reviewed additive contract shared by message list, search, mget, @me and thread projections. Keep this descriptor small: Runtime owns the values, while Skill references and policy checks consume a copy of these field names so prose cannot silently invent another result shape.

func CurrentMessageResultContract added in v1.0.57

func CurrentMessageResultContract() MessageResultContract

CurrentMessageResultContract returns defensive copies so callers cannot mutate the process-wide reviewed descriptor.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL