larksuite / larksuite/cli

feat(im): support generating AppLinks to open chat directly to thread / thread sidepanel (im +applink & thread_app_link)

Open
#2,706 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

domain/im enhancement
Dominant language
Go
Stars
17.3k
Forks
1.4k
Avg merge
2d 4h
Merged PRs (30d)
105

Description

Problem Statement / Background

In Feishu / Lark, discussions in group chats and direct messages (P2P) frequently happen in threads (reply in thread / 话题回复). In the desktop and mobile clients, threads in standard chats (chat_mode: normal / group / p2p) open in a sidepanel (右侧边栏) alongside the chat stream, while topic chats (chat_mode: topic) open the thread in a dedicated view.

When AI agents or automated workflows interact with Lark/Feishu using lark-cli, a critical need is generating a clickable AppLink that directs the user:

  1. Directly to a specific thread in a chat (opening the thread in the chat sidepanel or scrolling to it).
  2. Directly to a joined chat at a specific message or thread anchor.

Currently, lark-cli has several limitations in this regard:

  1. No Standalone AppLink Generation Command / Shortcut:
    • There is no command like lark-cli im +applink to generate/assemble AppLinks on demand from known chat_id, thread_id, and message_id.
    • AppLinks are only generated as incidental read fields (chat_app_link, message_app_link) during query commands (+chat-list, +chat-messages-list, etc.).
  2. Missing thread_app_link in Thread Operations:
    • lark-cli im +threads-messages-list --thread <om_xxx> returns { "thread_id": "...", "messages": [...] } without a top-level thread_app_link for the thread container itself.
    • lark-cli im +messages-reply --reply-in-thread returns only { "message_id": "...", "chat_id": "...", "create_time": "..." }, omitting thread_id, message_app_link, and thread_app_link.
  3. Fragile Thread AppLink Assembly (assembleMessageAppLink):
    • In shortcuts/im/convert_lib/content_convert.go:
      if threadID != "" && chatID != "" && okThreadPos {
          // Generates https://<domain>/client/thread/open?openthreadid=...&openchatid=...
      }
      
      thread_message_position is strictly required for /client/thread/open. If position metadata is missing (common across various OpenAPI payloads or when only thread root is known), it falls back to chat or returns nothing.
  4. No Direct Support for Sidepanel Navigation in Group/Private Chats:
    • /client/thread/open is designed for topic-group streams. In normal group chats and P2P chats, users expect threads to open in the sidepanel (/client/chat/open with thread/message focus or position) rather than a separate topic window.

Proposed Solution & CLI Design

1. New Shortcut: lark-cli im +applink

Provide a dedicated shortcut to compute/assemble AppLinks deterministically (offline or lightweight):

# Generate link to chat
lark-cli im +applink --chat-id oc_xxx

# Generate link to thread (with sidepanel & topic link variants)
lark-cli im +applink --chat-id oc_xxx --thread-id om_xxx

# Generate link directly from a message ID (optionally resolves container via API if needed)
lark-cli im +applink --message-id om_xxx

Output payload:

{
  "chat_app_link": "https://applink.feishu.cn/client/chat/open?openChatId=oc_xxx",
  "thread_app_link": "https://applink.feishu.cn/client/thread/open?openthreadid=om_xxx&openchatid=oc_xxx&open_thread_id=om_xxx&open_chat_id=oc_xxx",
  "sidepanel_app_link": "https://applink.feishu.cn/client/chat/open?openChatId=oc_xxx&position=12",
  "message_app_link": "https://applink.feishu.cn/client/chat/open?openChatId=oc_xxx&position=12"
}
2. Enrich +threads-messages-list and +messages-reply
  • im +threads-messages-list: add thread_app_link at the root of the output envelope.
  • im +messages-reply: when replying (especially --reply-in-thread), include thread_app_link and message_app_link in the output so the caller immediately receives a clickable link to share with users.
3. Make assembleThreadAppLink resilient
  • Remove the strict okThreadPos prerequisite: if threadID and chatID are present, assemble /client/thread/open even without thread_message_position.
  • When available, also provide the chat-level navigation AppLink pointing to the root message position.

Compatibility

  • Fully backward-compatible: existing fields and envelopes remain unchanged.
  • Multi-brand: respects core.ResolveEndpoints(brand).AppLink (applink.feishu.cn for Feishu, applink.larksuite.com for Lark).

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with shortcuts/im/convert_lib/content_convert.go, especially assembleMessageAppLink and the thread-position handling described in the issue. Then trace the existing IM shortcuts for +threads-messages-list and +messages-reply to understand their output envelopes. Done means +applink and the enriched thread/reply outputs provide the requested links while preserving existing fields and endpoint resolution.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
cli
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.