@rynx-ai/daemon 0.1.10 → 0.1.11-beta.2
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.
- package/bundled-plugins/.rynx-plugin/marketplace.json +10 -0
- package/bundled-plugins/plugins/lark/.rynx-plugin/plugin.json +37 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/mirror-index.d.ts +48 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/mirror-index.js +54 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-mirror.d.ts +85 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-mirror.js +333 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-watcher.d.ts +109 -0
- package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-watcher.js +347 -0
- package/bundled-plugins/plugins/lark/dist/host-adapters.d.ts +95 -0
- package/bundled-plugins/plugins/lark/dist/host-adapters.js +504 -0
- package/bundled-plugins/plugins/lark/dist/index.d.ts +7 -0
- package/bundled-plugins/plugins/lark/dist/index.js +7 -0
- package/bundled-plugins/plugins/lark/dist/lark-card-stream.d.ts +363 -0
- package/bundled-plugins/plugins/lark/dist/lark-card-stream.js +1335 -0
- package/bundled-plugins/plugins/lark/dist/lark-config-store.d.ts +30 -0
- package/bundled-plugins/plugins/lark/dist/lark-config-store.js +135 -0
- package/bundled-plugins/plugins/lark/dist/lark-content.d.ts +30 -0
- package/bundled-plugins/plugins/lark/dist/lark-content.js +138 -0
- package/bundled-plugins/plugins/lark/dist/lark-conversation-directory.d.ts +65 -0
- package/bundled-plugins/plugins/lark/dist/lark-conversation-directory.js +106 -0
- package/bundled-plugins/plugins/lark/dist/lark-diff-card.d.ts +25 -0
- package/bundled-plugins/plugins/lark/dist/lark-diff-card.js +58 -0
- package/bundled-plugins/plugins/lark/dist/lark-fork-transcript.d.ts +16 -0
- package/bundled-plugins/plugins/lark/dist/lark-fork-transcript.js +141 -0
- package/bundled-plugins/plugins/lark/dist/lark-resume-card.d.ts +31 -0
- package/bundled-plugins/plugins/lark/dist/lark-resume-card.js +105 -0
- package/bundled-plugins/plugins/lark/dist/lark-runtime-state-store.d.ts +18 -0
- package/bundled-plugins/plugins/lark/dist/lark-runtime-state-store.js +95 -0
- package/bundled-plugins/plugins/lark/dist/lark-sdk/client.d.ts +8 -0
- package/bundled-plugins/plugins/lark/dist/lark-sdk/client.js +32 -0
- package/bundled-plugins/plugins/lark/dist/lark-sdk/index.d.ts +1 -0
- package/bundled-plugins/plugins/lark/dist/lark-sdk/index.js +1 -0
- package/bundled-plugins/plugins/lark/dist/lark-sender.d.ts +114 -0
- package/bundled-plugins/plugins/lark/dist/lark-sender.js +323 -0
- package/bundled-plugins/plugins/lark/dist/lark-session-store.d.ts +13 -0
- package/bundled-plugins/plugins/lark/dist/lark-session-store.js +14 -0
- package/bundled-plugins/plugins/lark/dist/lark-settings-card.d.ts +55 -0
- package/bundled-plugins/plugins/lark/dist/lark-settings-card.js +158 -0
- package/bundled-plugins/plugins/lark/dist/lark-setup.d.ts +39 -0
- package/bundled-plugins/plugins/lark/dist/lark-setup.js +103 -0
- package/bundled-plugins/plugins/lark/dist/lark.d.ts +507 -0
- package/bundled-plugins/plugins/lark/dist/lark.js +1977 -0
- package/bundled-plugins/plugins/lark/dist/runtime.d.ts +13 -0
- package/bundled-plugins/plugins/lark/dist/runtime.js +131316 -0
- package/bundled-plugins/plugins/lark/dist/settings.d.ts +7 -0
- package/bundled-plugins/plugins/lark/dist/settings.js +126958 -0
- package/bundled-plugins/plugins/lark/package.json +57 -0
- package/bundled-plugins/plugins/lark/ui/assets/index-B2dhMlMU.css +1 -0
- package/bundled-plugins/plugins/lark/ui/assets/index-D9N-AkLX.js +201 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
- package/bundled-plugins/plugins/lark/ui/index.html +13 -0
- package/dist/bundled-plugins.d.ts +15 -0
- package/dist/bundled-plugins.js +134 -0
- package/dist/cli.js +26 -208
- package/dist/control-deps.js +2 -79
- package/dist/daemon-server.d.ts +4 -1
- package/dist/daemon-server.js +167 -57
- package/dist/db.js +145 -124
- package/dist/index-daemon.js +25 -4
- package/dist/migrations/cleanup-legacy-sessions.d.ts +1 -1
- package/dist/migrations/cleanup-legacy-sessions.js +33 -15
- package/dist/official-plugins.d.ts +2 -0
- package/dist/official-plugins.js +2 -0
- package/dist/plugin-cli.d.ts +1 -3
- package/dist/plugin-cli.js +56 -45
- package/dist/plugin-host-leases.d.ts +4 -0
- package/dist/plugin-host-leases.js +7 -0
- package/dist/plugin-host-rpc.d.ts +42 -4
- package/dist/plugin-host-rpc.js +144 -34
- package/dist/plugin-installer.d.ts +24 -55
- package/dist/plugin-installer.js +202 -415
- package/dist/plugin-management-service.d.ts +30 -23
- package/dist/plugin-management-service.js +290 -105
- package/dist/plugin-marketplace.d.ts +35 -0
- package/dist/plugin-marketplace.js +299 -0
- package/dist/plugin-package.d.ts +22 -24
- package/dist/plugin-package.js +520 -571
- package/dist/plugin-skill-context.d.ts +4 -0
- package/dist/plugin-skill-context.js +35 -0
- package/dist/plugin-store.d.ts +36 -37
- package/dist/plugin-store.js +140 -92
- package/dist/plugin-supervisor.d.ts +45 -125
- package/dist/plugin-supervisor.js +516 -1053
- package/dist/pm2.js +15 -10
- package/dist/runtime-project-store.d.ts +9 -0
- package/dist/runtime-project-store.js +83 -0
- package/dist/session-fallback-workspace.d.ts +22 -0
- package/dist/session-fallback-workspace.js +120 -0
- package/dist/session-fork-store.d.ts +41 -0
- package/dist/session-fork-store.js +288 -0
- package/dist/session-launch-operations.d.ts +14 -2
- package/dist/session-launch-operations.js +34 -2
- package/dist/session-meta-store.d.ts +7 -9
- package/dist/session-meta-store.js +28 -49
- package/dist/setup.js +26 -14
- package/package.json +14 -11
- package/dist/channel-store.d.ts +0 -22
- package/dist/channel-store.js +0 -65
- package/dist/instance-store.d.ts +0 -38
- package/dist/instance-store.js +0 -85
- package/dist/plugin-install-restart.d.ts +0 -13
- package/dist/plugin-install-restart.js +0 -24
- package/dist/plugin-runtime-control.d.ts +0 -2
- package/dist/plugin-runtime-control.js +0 -37
- package/dist/registry.d.ts +0 -10
- package/dist/registry.js +0 -52
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import * as Lark from "@larksuiteoapi/node-sdk";
|
|
2
|
+
import { createLarkSdkClient, createLarkWsClient } from "./lark-sdk/index.js";
|
|
3
|
+
export class LarkSdkMessageSender {
|
|
4
|
+
client;
|
|
5
|
+
constructor(client) {
|
|
6
|
+
this.client = client;
|
|
7
|
+
}
|
|
8
|
+
async getMessage({ messageId }) {
|
|
9
|
+
const response = await this.client.im.v1.message.get({
|
|
10
|
+
path: {
|
|
11
|
+
message_id: messageId,
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
if (response.code && response.code !== 0) {
|
|
15
|
+
throw new Error(response.msg ?? "Failed to get the Feishu message.");
|
|
16
|
+
}
|
|
17
|
+
const item = response.data?.items?.[0];
|
|
18
|
+
if (!item) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
messageId: item.message_id,
|
|
23
|
+
msgType: item.msg_type,
|
|
24
|
+
body: {
|
|
25
|
+
content: item.body?.content,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
async createText({ chatId, text, uuid, }) {
|
|
30
|
+
const response = await this.client.im.message.create({
|
|
31
|
+
params: {
|
|
32
|
+
receive_id_type: "chat_id",
|
|
33
|
+
},
|
|
34
|
+
data: {
|
|
35
|
+
receive_id: chatId,
|
|
36
|
+
msg_type: "text",
|
|
37
|
+
content: JSON.stringify({ text }),
|
|
38
|
+
uuid,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
if (response.code && response.code !== 0) {
|
|
42
|
+
throw new Error(response.msg ?? "Failed to send Feishu chat message.");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async createReaction({ messageId, emojiType, }) {
|
|
46
|
+
const response = await this.client.im.messageReaction.create({
|
|
47
|
+
path: {
|
|
48
|
+
message_id: messageId,
|
|
49
|
+
},
|
|
50
|
+
data: {
|
|
51
|
+
reaction_type: {
|
|
52
|
+
emoji_type: emojiType,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
if (response.code && response.code !== 0) {
|
|
57
|
+
throw new Error(response.msg ?? "Failed to add Feishu message reaction.");
|
|
58
|
+
}
|
|
59
|
+
return response.data?.reaction_id;
|
|
60
|
+
}
|
|
61
|
+
async deleteReaction({ messageId, reactionId, }) {
|
|
62
|
+
const response = await this.client.im.messageReaction.delete({
|
|
63
|
+
path: {
|
|
64
|
+
message_id: messageId,
|
|
65
|
+
reaction_id: reactionId,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
if (response.code && response.code !== 0) {
|
|
69
|
+
throw new Error(response.msg ?? "Failed to delete Feishu message reaction.");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async replyText({ messageId, text, uuid, replyInThread, }) {
|
|
73
|
+
const response = await this.client.im.message.reply({
|
|
74
|
+
path: {
|
|
75
|
+
message_id: messageId,
|
|
76
|
+
},
|
|
77
|
+
data: {
|
|
78
|
+
msg_type: "text",
|
|
79
|
+
content: JSON.stringify({ text }),
|
|
80
|
+
reply_in_thread: replyInThread,
|
|
81
|
+
uuid,
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
if (response.code && response.code !== 0) {
|
|
85
|
+
throw new Error(response.msg ?? "Failed to reply to the Feishu message.");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async createCard({ cardJson }) {
|
|
89
|
+
const response = await this.client.cardkit.v1.card.create({
|
|
90
|
+
data: {
|
|
91
|
+
type: "card_json",
|
|
92
|
+
data: cardJson,
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
if (response.code && response.code !== 0) {
|
|
96
|
+
throw new Error(response.msg ?? "Failed to create the Feishu CardKit card.");
|
|
97
|
+
}
|
|
98
|
+
const cardId = response.data?.card_id;
|
|
99
|
+
if (!cardId) {
|
|
100
|
+
throw new Error("Feishu CardKit create returned no card_id.");
|
|
101
|
+
}
|
|
102
|
+
return { cardId };
|
|
103
|
+
}
|
|
104
|
+
async batchUpdateCard({ cardId, sequence, actions, uuid, }) {
|
|
105
|
+
const response = await this.client.cardkit.v1.card.batchUpdate({
|
|
106
|
+
data: {
|
|
107
|
+
sequence,
|
|
108
|
+
actions,
|
|
109
|
+
...(uuid ? { uuid } : {}),
|
|
110
|
+
},
|
|
111
|
+
path: {
|
|
112
|
+
card_id: cardId,
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
if (response.code && response.code !== 0) {
|
|
116
|
+
throw new Error(response.msg ?? "Failed to batch update the Feishu CardKit card.");
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async sendInteractive({ chatId, cardId, uuid, }) {
|
|
120
|
+
const response = await this.client.im.message.create({
|
|
121
|
+
params: {
|
|
122
|
+
receive_id_type: "chat_id",
|
|
123
|
+
},
|
|
124
|
+
data: {
|
|
125
|
+
receive_id: chatId,
|
|
126
|
+
msg_type: "interactive",
|
|
127
|
+
content: JSON.stringify({ type: "card", data: { card_id: cardId } }),
|
|
128
|
+
uuid,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
if (response.code && response.code !== 0) {
|
|
132
|
+
throw new Error(response.msg ?? "Failed to send the Feishu interactive card.");
|
|
133
|
+
}
|
|
134
|
+
const messageId = response.data?.message_id;
|
|
135
|
+
if (!messageId) {
|
|
136
|
+
throw new Error("Feishu interactive send returned no message_id.");
|
|
137
|
+
}
|
|
138
|
+
return { messageId };
|
|
139
|
+
}
|
|
140
|
+
async replyInteractive({ messageId, cardId, uuid, replyInThread, }) {
|
|
141
|
+
const response = await this.client.im.message.reply({
|
|
142
|
+
path: {
|
|
143
|
+
message_id: messageId,
|
|
144
|
+
},
|
|
145
|
+
data: {
|
|
146
|
+
msg_type: "interactive",
|
|
147
|
+
content: JSON.stringify({ type: "card", data: { card_id: cardId } }),
|
|
148
|
+
reply_in_thread: replyInThread,
|
|
149
|
+
uuid,
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
if (response.code && response.code !== 0) {
|
|
153
|
+
throw new Error(response.msg ?? "Failed to reply with the Feishu interactive card.");
|
|
154
|
+
}
|
|
155
|
+
const replyMessageId = response.data?.message_id;
|
|
156
|
+
if (!replyMessageId) {
|
|
157
|
+
throw new Error("Feishu interactive reply returned no message_id.");
|
|
158
|
+
}
|
|
159
|
+
return { messageId: replyMessageId };
|
|
160
|
+
}
|
|
161
|
+
async forwardThread({ threadId, receiveId, receiveIdType, uuid, }) {
|
|
162
|
+
const response = await this.client.im.v1.thread.forward({
|
|
163
|
+
path: { thread_id: threadId },
|
|
164
|
+
params: { receive_id_type: receiveIdType, uuid },
|
|
165
|
+
data: { receive_id: receiveId },
|
|
166
|
+
});
|
|
167
|
+
if (response.code && response.code !== 0) {
|
|
168
|
+
throw new Error(response.msg ?? "Failed to forward the Feishu thread.");
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async sendText({ chatId, text, uuid, }) {
|
|
172
|
+
const response = await this.client.im.message.create({
|
|
173
|
+
params: { receive_id_type: "chat_id" },
|
|
174
|
+
data: {
|
|
175
|
+
receive_id: chatId,
|
|
176
|
+
msg_type: "text",
|
|
177
|
+
content: JSON.stringify({ text }),
|
|
178
|
+
uuid,
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
if (response.code && response.code !== 0) {
|
|
182
|
+
throw new Error(response.msg ?? "Failed to send Feishu chat message.");
|
|
183
|
+
}
|
|
184
|
+
const data = response.data;
|
|
185
|
+
return { messageId: data?.message_id ?? "", threadId: data?.thread_id };
|
|
186
|
+
}
|
|
187
|
+
async createChat({ name, userIdList, uuid, }) {
|
|
188
|
+
const response = await this.client.im.v1.chat.create({
|
|
189
|
+
params: { user_id_type: "open_id", uuid },
|
|
190
|
+
data: { name, user_id_list: userIdList, group_message_type: "chat" },
|
|
191
|
+
});
|
|
192
|
+
if (response.code && response.code !== 0) {
|
|
193
|
+
throw new Error(response.msg ?? "Failed to create the Feishu chat.");
|
|
194
|
+
}
|
|
195
|
+
const chatId = response.data?.chat_id;
|
|
196
|
+
if (!chatId) {
|
|
197
|
+
throw new Error("Feishu chat create returned no chat_id.");
|
|
198
|
+
}
|
|
199
|
+
return { chatId };
|
|
200
|
+
}
|
|
201
|
+
async getChat({ chatId }) {
|
|
202
|
+
const response = await this.client.im.v1.chat.get({ path: { chat_id: chatId } });
|
|
203
|
+
if (response.code && response.code !== 0) {
|
|
204
|
+
throw new Error(response.msg ?? "Failed to get the Feishu chat.");
|
|
205
|
+
}
|
|
206
|
+
const name = response.data?.name ?? "";
|
|
207
|
+
return { name };
|
|
208
|
+
}
|
|
209
|
+
async listChatMembers({ chatId, }) {
|
|
210
|
+
const response = await this.client.im.v1.chatMembers.get({
|
|
211
|
+
path: { chat_id: chatId },
|
|
212
|
+
params: { member_id_type: "open_id", page_size: 100 },
|
|
213
|
+
});
|
|
214
|
+
if (response.code && response.code !== 0) {
|
|
215
|
+
throw new Error(response.msg ?? "Failed to list Feishu chat members.");
|
|
216
|
+
}
|
|
217
|
+
const items = response.data
|
|
218
|
+
?.items ?? [];
|
|
219
|
+
return items
|
|
220
|
+
.filter((item) => item.member_id)
|
|
221
|
+
.map((item) => ({ memberId: item.member_id, name: item.name ?? "" }));
|
|
222
|
+
}
|
|
223
|
+
async listMessages({ containerIdType, containerId, pageSize = 50, }) {
|
|
224
|
+
const response = await this.client.im.v1.message.list({
|
|
225
|
+
params: {
|
|
226
|
+
container_id_type: containerIdType,
|
|
227
|
+
container_id: containerId,
|
|
228
|
+
sort_type: "ByCreateTimeAsc",
|
|
229
|
+
page_size: pageSize,
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
if (response.code && response.code !== 0) {
|
|
233
|
+
throw new Error(response.msg ?? "Failed to list Feishu messages.");
|
|
234
|
+
}
|
|
235
|
+
const items = response.data?.items ?? [];
|
|
236
|
+
return items.map((item) => ({
|
|
237
|
+
msgType: item.msg_type ?? "",
|
|
238
|
+
senderId: item.sender?.id,
|
|
239
|
+
senderType: item.sender?.sender_type,
|
|
240
|
+
content: item.body?.content ?? "",
|
|
241
|
+
}));
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/** Read a per-instance string option, trimmed; undefined when absent/blank. */
|
|
245
|
+
function larkOption(options, key) {
|
|
246
|
+
const value = options?.[key];
|
|
247
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
248
|
+
}
|
|
249
|
+
export class LarkClientProvider {
|
|
250
|
+
client;
|
|
251
|
+
wsClient;
|
|
252
|
+
botOpenIdPromise;
|
|
253
|
+
constructor(options, logger) {
|
|
254
|
+
// Credentials come from this channel instance's stored config (`options`).
|
|
255
|
+
const appId = larkOption(options, "LARK_APP_ID");
|
|
256
|
+
const appSecret = larkOption(options, "LARK_APP_SECRET");
|
|
257
|
+
this.client = createLarkSdkClient({ appId: appId, appSecret: appSecret }, logger);
|
|
258
|
+
this.wsClient = createLarkWsClient({ appId: appId, appSecret: appSecret }, logger);
|
|
259
|
+
}
|
|
260
|
+
getMessageSender() {
|
|
261
|
+
return new LarkSdkMessageSender(this.client);
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* This bot's own `open_id`, fetched once from the bot info API and memoized.
|
|
265
|
+
* Lets the ingestor tell, in a group hosting multiple bots, whether an
|
|
266
|
+
* incoming `@` actually targets us. Returns `null` if the lookup fails so the
|
|
267
|
+
* caller can fall back to its legacy behavior rather than going silent.
|
|
268
|
+
*/
|
|
269
|
+
async getBotOpenId() {
|
|
270
|
+
if (!this.botOpenIdPromise) {
|
|
271
|
+
this.botOpenIdPromise = this.client
|
|
272
|
+
.request({
|
|
273
|
+
method: "GET",
|
|
274
|
+
url: "/open-apis/bot/v3/info",
|
|
275
|
+
})
|
|
276
|
+
.then((response) => response?.bot?.open_id ?? null)
|
|
277
|
+
.catch(() => null);
|
|
278
|
+
}
|
|
279
|
+
return this.botOpenIdPromise;
|
|
280
|
+
}
|
|
281
|
+
async start({ onMessage, onCardAction }) {
|
|
282
|
+
const handlers = {
|
|
283
|
+
"im.message.receive_v1": async (data) => {
|
|
284
|
+
onMessage(data);
|
|
285
|
+
},
|
|
286
|
+
};
|
|
287
|
+
if (onCardAction) {
|
|
288
|
+
// Feishu CardKit button clicks arrive as `card.action.trigger` events
|
|
289
|
+
// over the same WS pipe (self-built bot, persistent connection).
|
|
290
|
+
// The return value (e.g. `{ toast: {...} }`) is forwarded back to
|
|
291
|
+
// Feishu so the user gets immediate UI feedback — also required for
|
|
292
|
+
// Feishu to consider the callback well-formed (avoids error 200340).
|
|
293
|
+
handlers["card.action.trigger"] = async (data) => {
|
|
294
|
+
const payload = data;
|
|
295
|
+
const rawValue = payload.action?.value;
|
|
296
|
+
const value = rawValue && typeof rawValue === "object" && !Array.isArray(rawValue)
|
|
297
|
+
? rawValue
|
|
298
|
+
: null;
|
|
299
|
+
// `option` carries the picked value of a `select_static`; `form_value`
|
|
300
|
+
// carries all fields of a `form_submit`. Both are surfaced so settings
|
|
301
|
+
// cards can read selections without a dedicated form round-trip.
|
|
302
|
+
const option = typeof payload.action?.option === "string" ? payload.action.option : null;
|
|
303
|
+
const rawForm = payload.action?.form_value;
|
|
304
|
+
const formValue = rawForm && typeof rawForm === "object" && !Array.isArray(rawForm)
|
|
305
|
+
? rawForm
|
|
306
|
+
: null;
|
|
307
|
+
return await onCardAction({
|
|
308
|
+
value,
|
|
309
|
+
option,
|
|
310
|
+
formValue,
|
|
311
|
+
messageId: payload.context?.open_message_id,
|
|
312
|
+
});
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
const eventDispatcher = new Lark.EventDispatcher({}).register(handlers);
|
|
316
|
+
await this.wsClient.start({
|
|
317
|
+
eventDispatcher,
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
async stop() {
|
|
321
|
+
this.wsClient.close();
|
|
322
|
+
}
|
|
323
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lark binding over the channel-agnostic @rynx-ai/core conversation session store.
|
|
3
|
+
* The store engine (the conversation → current-session + execution binding) lives
|
|
4
|
+
* in core; Lark only supplies the per-instance file path + keeps the historical
|
|
5
|
+
* `Lark*` export names so existing importers are unchanged.
|
|
6
|
+
*/
|
|
7
|
+
import { FileConversationSessionStore, type ConversationSessionStoreOptions } from "@rynx-ai/core";
|
|
8
|
+
export type { ConversationSessionRecord as LarkActiveSessionRecord, ConversationSessionStore as LarkActiveSessionStore, SessionSettingsUpdate as LarkSettingsUpdate, EnsureSessionResult as LarkEnsureSessionResult, RotateSessionResult as LarkRotateSessionResult, SessionExecution as LarkSessionExecution, } from "@rynx-ai/core";
|
|
9
|
+
/** File-backed active-session store for a Lark bot instance: the core engine with
|
|
10
|
+
* the Lark per-instance file path injected by default. */
|
|
11
|
+
export declare class FileLarkActiveSessionStore extends FileConversationSessionStore {
|
|
12
|
+
constructor(options: ConversationSessionStoreOptions);
|
|
13
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lark binding over the channel-agnostic @rynx-ai/core conversation session store.
|
|
3
|
+
* The store engine (the conversation → current-session + execution binding) lives
|
|
4
|
+
* in core; Lark only supplies the per-instance file path + keeps the historical
|
|
5
|
+
* `Lark*` export names so existing importers are unchanged.
|
|
6
|
+
*/
|
|
7
|
+
import { FileConversationSessionStore, } from "@rynx-ai/core";
|
|
8
|
+
/** File-backed active-session store for a Lark bot instance: the core engine with
|
|
9
|
+
* the Lark per-instance file path injected by default. */
|
|
10
|
+
export class FileLarkActiveSessionStore extends FileConversationSessionStore {
|
|
11
|
+
constructor(options) {
|
|
12
|
+
super(options);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { AgentRuntimeId } from "@rynx-ai/core";
|
|
2
|
+
import type { ReasoningEffort } from "@rynx-ai/core";
|
|
3
|
+
/** Sentinel option value meaning "use the runtime/model default". */
|
|
4
|
+
export declare const SETTINGS_DEFAULT_VALUE = "__default__";
|
|
5
|
+
export interface SettingsCardModelOption {
|
|
6
|
+
value: string;
|
|
7
|
+
label: string;
|
|
8
|
+
isDefault?: boolean;
|
|
9
|
+
/** Reasoning efforts this model supports; empty/unknown → full effort set. */
|
|
10
|
+
supportedEfforts?: ReasoningEffort[];
|
|
11
|
+
}
|
|
12
|
+
export interface SettingsCardRuntimeOption {
|
|
13
|
+
value: AgentRuntimeId;
|
|
14
|
+
label: string;
|
|
15
|
+
}
|
|
16
|
+
export interface SettingsCardInput {
|
|
17
|
+
sessionKey: string;
|
|
18
|
+
/** `/runtime` shows the runtime selector; `/model` hides it. */
|
|
19
|
+
includeRuntime: boolean;
|
|
20
|
+
runtimeOptions: SettingsCardRuntimeOption[];
|
|
21
|
+
/** Models available for the selected runtime (excludes the default sentinel). */
|
|
22
|
+
models: SettingsCardModelOption[];
|
|
23
|
+
/** Pre-selected dropdown values (drive `initial_option`). */
|
|
24
|
+
selectedRuntime: AgentRuntimeId;
|
|
25
|
+
selectedModel: string;
|
|
26
|
+
selectedEffort: string;
|
|
27
|
+
}
|
|
28
|
+
export declare const SETTINGS_EFFORT_VALUES: ReasoningEffort[];
|
|
29
|
+
/**
|
|
30
|
+
* Build the `/runtime` / `/model` settings card object: dropdowns for runtime
|
|
31
|
+
* (optional), model and reasoning effort, plus confirm / cancel buttons.
|
|
32
|
+
* Selections round-trip via `card.action.trigger` callbacks (`settings_select`
|
|
33
|
+
* per change — runtime/model changes re-render this card; `settings_apply` /
|
|
34
|
+
* `settings_cancel` on the buttons). The effort options reflect the currently
|
|
35
|
+
* selected model's supported efforts.
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildSettingsCard(input: SettingsCardInput): Record<string, unknown>;
|
|
38
|
+
/** String form of {@link buildSettingsCard} (for the initial card send). */
|
|
39
|
+
export declare function buildSettingsCardJson(input: SettingsCardInput): string;
|
|
40
|
+
/**
|
|
41
|
+
* Build a static result card shown after the user confirms or cancels the
|
|
42
|
+
* settings card — replaces the interactive form with a plain conclusion.
|
|
43
|
+
* Returned as a plain object so it can be embedded in a card-action response.
|
|
44
|
+
*/
|
|
45
|
+
export declare function buildSettingsResultCard(input: {
|
|
46
|
+
includeRuntime: boolean;
|
|
47
|
+
template: "green" | "grey";
|
|
48
|
+
content: string;
|
|
49
|
+
}): Record<string, unknown>;
|
|
50
|
+
/** String form of {@link buildSettingsResultCard}. */
|
|
51
|
+
export declare function buildSettingsResultCardJson(input: {
|
|
52
|
+
includeRuntime: boolean;
|
|
53
|
+
template: "green" | "grey";
|
|
54
|
+
content: string;
|
|
55
|
+
}): string;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/** Sentinel option value meaning "use the runtime/model default". */
|
|
2
|
+
export const SETTINGS_DEFAULT_VALUE = "__default__";
|
|
3
|
+
export const SETTINGS_EFFORT_VALUES = [
|
|
4
|
+
"none",
|
|
5
|
+
"minimal",
|
|
6
|
+
"low",
|
|
7
|
+
"medium",
|
|
8
|
+
"high",
|
|
9
|
+
"xhigh",
|
|
10
|
+
"max",
|
|
11
|
+
"ultra",
|
|
12
|
+
];
|
|
13
|
+
const EFFORT_LABELS = {
|
|
14
|
+
minimal: "minimal · 最小",
|
|
15
|
+
low: "low · 低",
|
|
16
|
+
medium: "medium · 中",
|
|
17
|
+
high: "high · 高",
|
|
18
|
+
xhigh: "xhigh · 极高",
|
|
19
|
+
none: "none · 关闭",
|
|
20
|
+
max: "max · 最大",
|
|
21
|
+
ultra: "ultra · 自动委派",
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Effort options for the currently-selected model: the model's own
|
|
25
|
+
* `supportedEfforts` when it advertises them, otherwise the full effort set.
|
|
26
|
+
* Always prefixed with the "follow the model default" sentinel.
|
|
27
|
+
*/
|
|
28
|
+
function effortOptionsFor(models, selectedModel) {
|
|
29
|
+
const model = models.find((m) => m.value === selectedModel);
|
|
30
|
+
const supported = Array.from(new Set(model?.supportedEfforts ?? []));
|
|
31
|
+
const values = supported.length > 0 ? supported : SETTINGS_EFFORT_VALUES;
|
|
32
|
+
return [
|
|
33
|
+
{ text: plainText("默认(跟随模型)"), value: SETTINGS_DEFAULT_VALUE },
|
|
34
|
+
...values.map((value) => ({ text: plainText(EFFORT_LABELS[value] ?? value), value })),
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
function plainText(content) {
|
|
38
|
+
return { tag: "plain_text", content };
|
|
39
|
+
}
|
|
40
|
+
function buildSelect(field, sessionKey, includeRuntime, placeholder, options, initialValue) {
|
|
41
|
+
return {
|
|
42
|
+
tag: "select_static",
|
|
43
|
+
name: field,
|
|
44
|
+
placeholder: plainText(placeholder),
|
|
45
|
+
initial_option: initialValue,
|
|
46
|
+
options,
|
|
47
|
+
behaviors: [
|
|
48
|
+
{
|
|
49
|
+
type: "callback",
|
|
50
|
+
value: { kind: "settings_select", field, sessionKey, includeRuntime },
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function labelMarkdown(content) {
|
|
56
|
+
return { tag: "markdown", content };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Build the `/runtime` / `/model` settings card object: dropdowns for runtime
|
|
60
|
+
* (optional), model and reasoning effort, plus confirm / cancel buttons.
|
|
61
|
+
* Selections round-trip via `card.action.trigger` callbacks (`settings_select`
|
|
62
|
+
* per change — runtime/model changes re-render this card; `settings_apply` /
|
|
63
|
+
* `settings_cancel` on the buttons). The effort options reflect the currently
|
|
64
|
+
* selected model's supported efforts.
|
|
65
|
+
*/
|
|
66
|
+
export function buildSettingsCard(input) {
|
|
67
|
+
const { sessionKey, includeRuntime, models, selectedRuntime, selectedModel, selectedEffort } = input;
|
|
68
|
+
const elements = [];
|
|
69
|
+
elements.push(labelMarkdown(includeRuntime
|
|
70
|
+
? "选择**运行时 / 模型 / 思考强度**,点击确认后对新会话生效。"
|
|
71
|
+
: "为当前运行时选择**模型 / 思考强度**,点击确认后对新会话生效。"));
|
|
72
|
+
if (includeRuntime) {
|
|
73
|
+
const runtimeOptions = input.runtimeOptions.map((option) => ({
|
|
74
|
+
text: plainText(option.label),
|
|
75
|
+
value: option.value,
|
|
76
|
+
}));
|
|
77
|
+
elements.push(labelMarkdown("**运行时**"));
|
|
78
|
+
elements.push(buildSelect("runtime", sessionKey, includeRuntime, "选择运行时", runtimeOptions, selectedRuntime));
|
|
79
|
+
}
|
|
80
|
+
const modelOptions = [
|
|
81
|
+
{ text: plainText("跟随运行时默认"), value: SETTINGS_DEFAULT_VALUE },
|
|
82
|
+
...models.map((model) => ({
|
|
83
|
+
text: plainText(`${model.label}${model.isDefault ? " ⭐️" : ""}`),
|
|
84
|
+
value: model.value,
|
|
85
|
+
})),
|
|
86
|
+
];
|
|
87
|
+
elements.push(labelMarkdown("**模型**"));
|
|
88
|
+
elements.push(buildSelect("model", sessionKey, includeRuntime, "选择模型", modelOptions, selectedModel));
|
|
89
|
+
elements.push(labelMarkdown("**思考强度**"));
|
|
90
|
+
elements.push(buildSelect("effort", sessionKey, includeRuntime, "选择思考强度", effortOptionsFor(models, selectedModel), selectedEffort));
|
|
91
|
+
const confirmButton = {
|
|
92
|
+
tag: "button",
|
|
93
|
+
text: plainText("确认"),
|
|
94
|
+
type: "primary",
|
|
95
|
+
size: "medium",
|
|
96
|
+
behaviors: [
|
|
97
|
+
{
|
|
98
|
+
type: "callback",
|
|
99
|
+
value: { kind: "settings_apply", sessionKey, includeRuntime },
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
};
|
|
103
|
+
const cancelButton = {
|
|
104
|
+
tag: "button",
|
|
105
|
+
text: plainText("取消"),
|
|
106
|
+
type: "default",
|
|
107
|
+
size: "medium",
|
|
108
|
+
behaviors: [
|
|
109
|
+
{
|
|
110
|
+
type: "callback",
|
|
111
|
+
value: { kind: "settings_cancel", sessionKey, includeRuntime },
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
};
|
|
115
|
+
// `flex_mode: "none"` + auto-width columns keep the two buttons sized to
|
|
116
|
+
// their content and sitting adjacent on the left (weighted columns would
|
|
117
|
+
// stretch each button across half the card, pushing 取消 to the far right).
|
|
118
|
+
elements.push({
|
|
119
|
+
tag: "column_set",
|
|
120
|
+
flex_mode: "none",
|
|
121
|
+
horizontal_spacing: "8px",
|
|
122
|
+
columns: [
|
|
123
|
+
{ tag: "column", width: "auto", elements: [confirmButton] },
|
|
124
|
+
{ tag: "column", width: "auto", elements: [cancelButton] },
|
|
125
|
+
],
|
|
126
|
+
});
|
|
127
|
+
return {
|
|
128
|
+
schema: "2.0",
|
|
129
|
+
header: {
|
|
130
|
+
title: plainText(includeRuntime ? "⚙️ 运行设置" : "⚙️ 模型设置"),
|
|
131
|
+
template: "blue",
|
|
132
|
+
},
|
|
133
|
+
body: { elements },
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/** String form of {@link buildSettingsCard} (for the initial card send). */
|
|
137
|
+
export function buildSettingsCardJson(input) {
|
|
138
|
+
return JSON.stringify(buildSettingsCard(input));
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Build a static result card shown after the user confirms or cancels the
|
|
142
|
+
* settings card — replaces the interactive form with a plain conclusion.
|
|
143
|
+
* Returned as a plain object so it can be embedded in a card-action response.
|
|
144
|
+
*/
|
|
145
|
+
export function buildSettingsResultCard(input) {
|
|
146
|
+
return {
|
|
147
|
+
schema: "2.0",
|
|
148
|
+
header: {
|
|
149
|
+
title: plainText(input.includeRuntime ? "⚙️ 运行设置" : "⚙️ 模型设置"),
|
|
150
|
+
template: input.template,
|
|
151
|
+
},
|
|
152
|
+
body: { elements: [{ tag: "markdown", content: input.content }] },
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/** String form of {@link buildSettingsResultCard}. */
|
|
156
|
+
export function buildSettingsResultCardJson(input) {
|
|
157
|
+
return JSON.stringify(buildSettingsResultCard(input));
|
|
158
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface LarkSetupField {
|
|
2
|
+
key: "LARK_APP_ID" | "LARK_APP_SECRET";
|
|
3
|
+
label: string;
|
|
4
|
+
type: "string" | "secret";
|
|
5
|
+
required: boolean;
|
|
6
|
+
help?: string;
|
|
7
|
+
}
|
|
8
|
+
export type LarkAuthorizationMaterial = {
|
|
9
|
+
kind: "qr";
|
|
10
|
+
url: string;
|
|
11
|
+
expireIn?: number;
|
|
12
|
+
} | {
|
|
13
|
+
kind: "link";
|
|
14
|
+
url: string;
|
|
15
|
+
label?: string;
|
|
16
|
+
} | {
|
|
17
|
+
kind: "status";
|
|
18
|
+
text: string;
|
|
19
|
+
};
|
|
20
|
+
export interface LarkAuthorizationCredentials {
|
|
21
|
+
LARK_APP_ID: string;
|
|
22
|
+
LARK_APP_SECRET: string;
|
|
23
|
+
botName?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Minimal tenant (app-identity) scopes the Lark channel needs: receive/send
|
|
27
|
+
* messages, add reactions, read chat + members, upload/download resources, and
|
|
28
|
+
* resolve user display info. Pre-filled into the scan-confirm page; editable.
|
|
29
|
+
*/
|
|
30
|
+
export declare const LARK_BOT_SCOPES: string[];
|
|
31
|
+
/** The bot only needs to be told when a message arrives. */
|
|
32
|
+
export declare const LARK_BOT_EVENTS: string[];
|
|
33
|
+
/** Config mode 1: paste an existing app's credentials. */
|
|
34
|
+
export declare const larkConfigSchema: LarkSetupField[];
|
|
35
|
+
/**
|
|
36
|
+
* Scan-to-create/authorize. Emits a `qr` material and `status` updates, then
|
|
37
|
+
* resolves with the App ID / App Secret to persist. Aborts via `signal`.
|
|
38
|
+
*/
|
|
39
|
+
export declare function authorizeLark(emit: (material: LarkAuthorizationMaterial) => void, signal: AbortSignal): Promise<LarkAuthorizationCredentials>;
|