@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.
Files changed (117) hide show
  1. package/bundled-plugins/.rynx-plugin/marketplace.json +10 -0
  2. package/bundled-plugins/plugins/lark/.rynx-plugin/plugin.json +37 -0
  3. package/bundled-plugins/plugins/lark/dist/cli-mirror/mirror-index.d.ts +48 -0
  4. package/bundled-plugins/plugins/lark/dist/cli-mirror/mirror-index.js +54 -0
  5. package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-mirror.d.ts +85 -0
  6. package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-mirror.js +333 -0
  7. package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-watcher.d.ts +109 -0
  8. package/bundled-plugins/plugins/lark/dist/cli-mirror/rollout-watcher.js +347 -0
  9. package/bundled-plugins/plugins/lark/dist/host-adapters.d.ts +95 -0
  10. package/bundled-plugins/plugins/lark/dist/host-adapters.js +504 -0
  11. package/bundled-plugins/plugins/lark/dist/index.d.ts +7 -0
  12. package/bundled-plugins/plugins/lark/dist/index.js +7 -0
  13. package/bundled-plugins/plugins/lark/dist/lark-card-stream.d.ts +363 -0
  14. package/bundled-plugins/plugins/lark/dist/lark-card-stream.js +1335 -0
  15. package/bundled-plugins/plugins/lark/dist/lark-config-store.d.ts +30 -0
  16. package/bundled-plugins/plugins/lark/dist/lark-config-store.js +135 -0
  17. package/bundled-plugins/plugins/lark/dist/lark-content.d.ts +30 -0
  18. package/bundled-plugins/plugins/lark/dist/lark-content.js +138 -0
  19. package/bundled-plugins/plugins/lark/dist/lark-conversation-directory.d.ts +65 -0
  20. package/bundled-plugins/plugins/lark/dist/lark-conversation-directory.js +106 -0
  21. package/bundled-plugins/plugins/lark/dist/lark-diff-card.d.ts +25 -0
  22. package/bundled-plugins/plugins/lark/dist/lark-diff-card.js +58 -0
  23. package/bundled-plugins/plugins/lark/dist/lark-fork-transcript.d.ts +16 -0
  24. package/bundled-plugins/plugins/lark/dist/lark-fork-transcript.js +141 -0
  25. package/bundled-plugins/plugins/lark/dist/lark-resume-card.d.ts +31 -0
  26. package/bundled-plugins/plugins/lark/dist/lark-resume-card.js +105 -0
  27. package/bundled-plugins/plugins/lark/dist/lark-runtime-state-store.d.ts +18 -0
  28. package/bundled-plugins/plugins/lark/dist/lark-runtime-state-store.js +95 -0
  29. package/bundled-plugins/plugins/lark/dist/lark-sdk/client.d.ts +8 -0
  30. package/bundled-plugins/plugins/lark/dist/lark-sdk/client.js +32 -0
  31. package/bundled-plugins/plugins/lark/dist/lark-sdk/index.d.ts +1 -0
  32. package/bundled-plugins/plugins/lark/dist/lark-sdk/index.js +1 -0
  33. package/bundled-plugins/plugins/lark/dist/lark-sender.d.ts +114 -0
  34. package/bundled-plugins/plugins/lark/dist/lark-sender.js +323 -0
  35. package/bundled-plugins/plugins/lark/dist/lark-session-store.d.ts +13 -0
  36. package/bundled-plugins/plugins/lark/dist/lark-session-store.js +14 -0
  37. package/bundled-plugins/plugins/lark/dist/lark-settings-card.d.ts +55 -0
  38. package/bundled-plugins/plugins/lark/dist/lark-settings-card.js +158 -0
  39. package/bundled-plugins/plugins/lark/dist/lark-setup.d.ts +39 -0
  40. package/bundled-plugins/plugins/lark/dist/lark-setup.js +103 -0
  41. package/bundled-plugins/plugins/lark/dist/lark.d.ts +507 -0
  42. package/bundled-plugins/plugins/lark/dist/lark.js +1977 -0
  43. package/bundled-plugins/plugins/lark/dist/runtime.d.ts +13 -0
  44. package/bundled-plugins/plugins/lark/dist/runtime.js +131316 -0
  45. package/bundled-plugins/plugins/lark/dist/settings.d.ts +7 -0
  46. package/bundled-plugins/plugins/lark/dist/settings.js +126958 -0
  47. package/bundled-plugins/plugins/lark/package.json +57 -0
  48. package/bundled-plugins/plugins/lark/ui/assets/index-B2dhMlMU.css +1 -0
  49. package/bundled-plugins/plugins/lark/ui/assets/index-D9N-AkLX.js +201 -0
  50. package/bundled-plugins/plugins/lark/ui/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  51. package/bundled-plugins/plugins/lark/ui/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  52. package/bundled-plugins/plugins/lark/ui/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  53. package/bundled-plugins/plugins/lark/ui/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  54. package/bundled-plugins/plugins/lark/ui/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  55. package/bundled-plugins/plugins/lark/ui/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  56. package/bundled-plugins/plugins/lark/ui/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  57. package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  58. package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  59. package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  60. package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  61. package/bundled-plugins/plugins/lark/ui/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  62. package/bundled-plugins/plugins/lark/ui/index.html +13 -0
  63. package/dist/bundled-plugins.d.ts +15 -0
  64. package/dist/bundled-plugins.js +134 -0
  65. package/dist/cli.js +26 -208
  66. package/dist/control-deps.js +2 -79
  67. package/dist/daemon-server.d.ts +4 -1
  68. package/dist/daemon-server.js +167 -57
  69. package/dist/db.js +145 -124
  70. package/dist/index-daemon.js +25 -4
  71. package/dist/migrations/cleanup-legacy-sessions.d.ts +1 -1
  72. package/dist/migrations/cleanup-legacy-sessions.js +33 -15
  73. package/dist/official-plugins.d.ts +2 -0
  74. package/dist/official-plugins.js +2 -0
  75. package/dist/plugin-cli.d.ts +1 -3
  76. package/dist/plugin-cli.js +56 -45
  77. package/dist/plugin-host-leases.d.ts +4 -0
  78. package/dist/plugin-host-leases.js +7 -0
  79. package/dist/plugin-host-rpc.d.ts +42 -4
  80. package/dist/plugin-host-rpc.js +144 -34
  81. package/dist/plugin-installer.d.ts +24 -55
  82. package/dist/plugin-installer.js +202 -415
  83. package/dist/plugin-management-service.d.ts +30 -23
  84. package/dist/plugin-management-service.js +290 -105
  85. package/dist/plugin-marketplace.d.ts +35 -0
  86. package/dist/plugin-marketplace.js +299 -0
  87. package/dist/plugin-package.d.ts +22 -24
  88. package/dist/plugin-package.js +520 -571
  89. package/dist/plugin-skill-context.d.ts +4 -0
  90. package/dist/plugin-skill-context.js +35 -0
  91. package/dist/plugin-store.d.ts +36 -37
  92. package/dist/plugin-store.js +140 -92
  93. package/dist/plugin-supervisor.d.ts +45 -125
  94. package/dist/plugin-supervisor.js +516 -1053
  95. package/dist/pm2.js +15 -10
  96. package/dist/runtime-project-store.d.ts +9 -0
  97. package/dist/runtime-project-store.js +83 -0
  98. package/dist/session-fallback-workspace.d.ts +22 -0
  99. package/dist/session-fallback-workspace.js +120 -0
  100. package/dist/session-fork-store.d.ts +41 -0
  101. package/dist/session-fork-store.js +288 -0
  102. package/dist/session-launch-operations.d.ts +14 -2
  103. package/dist/session-launch-operations.js +34 -2
  104. package/dist/session-meta-store.d.ts +7 -9
  105. package/dist/session-meta-store.js +28 -49
  106. package/dist/setup.js +26 -14
  107. package/package.json +14 -11
  108. package/dist/channel-store.d.ts +0 -22
  109. package/dist/channel-store.js +0 -65
  110. package/dist/instance-store.d.ts +0 -38
  111. package/dist/instance-store.js +0 -85
  112. package/dist/plugin-install-restart.d.ts +0 -13
  113. package/dist/plugin-install-restart.js +0 -24
  114. package/dist/plugin-runtime-control.d.ts +0 -2
  115. package/dist/plugin-runtime-control.js +0 -37
  116. package/dist/registry.d.ts +0 -10
  117. 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>;