@milerliu/feishu 0.1.12 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/send.ts +89 -24
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@milerliu/feishu",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "type": "module",
5
5
  "description": "OpenClaw Feishu/Lark channel plugin",
6
6
  "license": "MIT",
package/src/send.ts CHANGED
@@ -48,43 +48,108 @@ export async function sendStreamingMessageFeishu(params: {
48
48
  rawText = buildMentionedMessage(mentions, rawText);
49
49
  }
50
50
 
51
- // Split text into chunks for streaming effect
52
- const chunkSize = 300;
53
- const chunks: string[] = [];
54
- for (let i = 0; i < rawText.length; i += chunkSize) {
55
- chunks.push(rawText.slice(i, i + chunkSize));
51
+ // Create streaming card
52
+ // Using inline card (type: "adaptive") instead of template for dynamic content
53
+ const initialCard = {
54
+ type: "adaptive",
55
+ config: {
56
+ wide_screen_mode: true,
57
+ streaming_update: true,
58
+ },
59
+ elements: [
60
+ {
61
+ tag: "markdown",
62
+ content: rawText,
63
+ },
64
+ ],
65
+ };
66
+
67
+ const cardContent = JSON.stringify(initialCard);
68
+
69
+ // Create card instance
70
+ const cardResponse = await (client as any).cardkit.v1.card.create({
71
+ data: {
72
+ type: "adaptive",
73
+ data: cardContent,
74
+ },
75
+ });
76
+
77
+ if (cardResponse.code !== 0) {
78
+ console.error(`Card creation failed: ${cardResponse.msg}`);
79
+ // Fallback to regular card
80
+ const fallbackCard = buildMarkdownCard(rawText);
81
+ return sendCardFeishu({ cfg, to, card: fallbackCard });
56
82
  }
57
83
 
58
- // Send first chunk
59
- const firstContent = JSON.stringify({ text: chunks[0] });
60
- const firstResponse = await client.im.message.create({
84
+ const cardId = cardResponse.data?.card_id;
85
+ if (!cardId) {
86
+ console.error('No card_id returned');
87
+ const fallbackCard = buildMarkdownCard(rawText);
88
+ return sendCardFeishu({ cfg, to, card: fallbackCard });
89
+ }
90
+
91
+ // Send the card as a message
92
+ const messageContent = JSON.stringify({ card_id: cardId });
93
+ const messageResponse = await client.im.message.create({
61
94
  params: { receive_id_type: receiveIdType },
62
95
  data: {
63
96
  receive_id: receiveId,
64
- content: firstContent,
65
- msg_type: "text",
97
+ content: messageContent,
98
+ msg_type: "interactive",
66
99
  },
67
100
  });
68
101
 
69
- if (firstResponse.code !== 0) {
70
- throw new Error(`Feishu streaming send failed: ${firstResponse.msg || `code ${firstResponse.code}`}`);
102
+ if (messageResponse.code !== 0) {
103
+ throw new Error(`Failed to send streaming card: ${messageResponse.msg || `code ${messageResponse.code}`}`);
71
104
  }
72
105
 
73
- const messageId = firstResponse.data?.message_id ?? "unknown";
106
+ const messageId = messageResponse.data?.message_id ?? "unknown";
107
+
108
+ // Now perform streaming updates using batch_update
109
+ // Split text into chunks for streaming
110
+ const chunkSize = 300;
111
+ const chunks: string[] = [];
112
+ for (let i = 0; i < rawText.length; i += chunkSize) {
113
+ chunks.push(rawText.slice(i, i + chunkSize));
114
+ }
74
115
 
75
- // Send remaining chunks as separate messages
76
- for (let i = 1; i < chunks.length; i++) {
77
- await new Promise((resolve) => setTimeout(resolve, 100));
78
- const chunkContent = JSON.stringify({ text: chunks[i] });
116
+ // Perform streaming updates
117
+ for (let i = 0; i < chunks.length; i++) {
118
+ const uuid = crypto.randomUUID?.() ?? `${Date.now()}-${i}`;
119
+ const sequence = i;
79
120
 
80
- await client.im.message.create({
81
- params: { receive_id_type: receiveIdType },
82
- data: {
83
- receive_id: receiveId,
84
- content: chunkContent,
85
- msg_type: "text",
86
- },
121
+ const updateAction = JSON.stringify({
122
+ tag: "markdown",
123
+ content: chunks[i],
87
124
  });
125
+
126
+ const actions = JSON.stringify([
127
+ {
128
+ action_name: "update_content",
129
+ action_param: {
130
+ tag: "markdown",
131
+ content: chunks[i],
132
+ },
133
+ },
134
+ ]);
135
+
136
+ try {
137
+ await (client as any).cardkit.v1.card.batch_update({
138
+ path: { card_id: cardId },
139
+ data: {
140
+ uuid,
141
+ sequence,
142
+ actions,
143
+ },
144
+ });
145
+
146
+ // Delay between updates for streaming effect
147
+ if (i < chunks.length - 1) {
148
+ await new Promise((resolve) => setTimeout(resolve, 100));
149
+ }
150
+ } catch (err) {
151
+ console.error(`Streaming update failed at chunk ${i}: ${err}`);
152
+ }
88
153
  }
89
154
 
90
155
  return {