mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-15 00:17:27 +00:00
feat(feishu): include reply context when user replies to a message (#272)
When a Feishu/Lark user replies to an existing message, the agent now sees the quoted message content via the GetMessage API, formatted as [Replying to SenderName]...[/Replying] — matching the Telegram channel behavior. Previously parent_id was parsed but the content was silently discarded, so the agent had no idea what the user was replying to. Requires im:message:readonly scope on the Lark app. Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
This commit is contained in:
1 parent
0dd4ebd6e6
commit
44197011f8
2 files changed
+75
No files matched your search
@@ -110,6 +110,13 @@ func (c *Channel) handleMessageEvent(ctx context.Context, event *MessageEvent) {
|
||||
content = "[empty message]"
|
||||
}
|
||||
|
||||
// 7b. Fetch reply context if this is a reply to another message
|
||||
if mc.ParentID != "" {
|
||||
if replyCtx := c.fetchReplyContext(ctx, mc.ParentID); replyCtx != "" {
|
||||
content += "\n\n" + replyCtx
|
||||
}
|
||||
}
|
||||
|
||||
// 8. Topic session
|
||||
chatID := mc.ChatID
|
||||
if mc.RootID != "" && c.cfg.TopicSessionMode == "enabled" {
|
||||
@@ -258,3 +265,35 @@ func (c *Channel) handleMessageEvent(ctx context.Context, event *MessageEvent) {
|
||||
c.groupHistory.Clear(chatID)
|
||||
}
|
||||
}
|
||||
|
||||
const replyContextMaxLen = 500
|
||||
|
||||
// fetchReplyContext fetches the parent message content and returns a formatted
|
||||
// reply context string, similar to Telegram's [Replying to ...] format.
|
||||
func (c *Channel) fetchReplyContext(ctx context.Context, parentID string) string {
|
||||
resp, err := c.client.GetMessage(ctx, parentID)
|
||||
if err != nil {
|
||||
slog.Debug("feishu: failed to fetch parent message", "parent_id", parentID, "error", err)
|
||||
return ""
|
||||
}
|
||||
if len(resp.Items) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
item := &resp.Items[0]
|
||||
body := parseMessageContent(item.Body.Content, item.MsgType)
|
||||
if body == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Resolve sender name
|
||||
senderName := "unknown"
|
||||
if item.Sender.ID != "" {
|
||||
if name := c.resolveSenderName(ctx, item.Sender.ID); name != "" {
|
||||
senderName = name
|
||||
}
|
||||
}
|
||||
|
||||
body = channels.Truncate(body, replyContextMaxLen)
|
||||
return fmt.Sprintf("[Replying to %s]\n%s\n[/Replying]", senderName, body)
|
||||
}
|
||||
@@ -89,6 +89,42 @@ func (c *LarkClient) UploadFile(ctx context.Context, data io.Reader, fileName, f
|
||||
return result.FileKey, nil
|
||||
}
|
||||
|
||||
// --- IM API: Get Message ---
|
||||
|
||||
// GetMessageResp holds the response from GET /open-apis/im/v1/messages/{message_id}.
|
||||
type GetMessageResp struct {
|
||||
Items []struct {
|
||||
MessageID string `json:"message_id"`
|
||||
MsgType string `json:"msg_type"`
|
||||
Body struct {
|
||||
Content string `json:"content"`
|
||||
} `json:"body"`
|
||||
Sender struct {
|
||||
ID string `json:"id"`
|
||||
IDType string `json:"id_type"`
|
||||
SenderType string `json:"sender_type"`
|
||||
} `json:"sender"`
|
||||
} `json:"items"`
|
||||
}
|
||||
|
||||
// GetMessage retrieves a message by ID.
|
||||
// Lark API: GET /open-apis/im/v1/messages/{message_id}
|
||||
func (c *LarkClient) GetMessage(ctx context.Context, messageID string) (*GetMessageResp, error) {
|
||||
path := fmt.Sprintf("/open-apis/im/v1/messages/%s", messageID)
|
||||
resp, err := c.doJSON(ctx, "GET", path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Code != 0 {
|
||||
return nil, fmt.Errorf("get message: code=%d msg=%s", resp.Code, resp.Msg)
|
||||
}
|
||||
var data GetMessageResp
|
||||
if err := json.Unmarshal(resp.Data, &data); err != nil {
|
||||
return nil, fmt.Errorf("unmarshal get message: %w", err)
|
||||
}
|
||||
return &data, nil
|
||||
}
|
||||
|
||||
// --- IM API: Message Resources ---
|
||||
|
||||
func (c *LarkClient) DownloadMessageResource(ctx context.Context, messageID, fileKey, resourceType string) ([]byte, string, error) {
|
||||
|
||||
Reference in new issue
Block a user