@inline-openclaw/inline 0.0.14 → 0.0.15

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/README.md CHANGED
@@ -100,6 +100,7 @@ channels:
100
100
  # Streaming + chunking:
101
101
  mediaMaxMb: 20
102
102
  blockStreaming: true
103
+ streamViaEditMessage: true # optional: paragraph-level text streaming via send+edit fallback; off by default
103
104
  chunkMode: "newline" # length|newline
104
105
  blockStreamingCoalesce:
105
106
  minChars: 600
@@ -136,14 +137,16 @@ For `message send`/plugin outbound sends:
136
137
  ## Message Tool RPC Actions
137
138
 
138
139
  The plugin exposes Inline RPC-backed actions through OpenClaw's `message` tool.
139
- Inline RPC-backed actions use a numeric chat id via `to`, `chatId`, or `channelId`.
140
+ Most Inline RPC-backed actions use a numeric chat id via `to`, `chatId`, or `channelId`.
141
+ Direct DM sends can also target `user:<id>`.
140
142
 
143
+ - Sending: `send`, `sendAttachment`
141
144
  - Replying: `reply`, `thread-reply`
142
145
  - Reactions: `react`, `reactions`
143
146
  - Reading/searching: `read`, `search`
144
147
  - Editing: `edit`
145
- - Channels/threads: `channel-info`, `channel-edit`, `channel-list`, `channel-create`, `channel-delete`, `channel-move`, `thread-list`, `thread-create`
146
- - Participants: `addParticipant`, `removeParticipant`, `leaveGroup`, `member-info`
148
+ - Channels/threads: `channel-info`, `channel-edit`, `renameGroup`, `channel-list`, `channel-create`, `channel-delete`, `channel-move`, `thread-list`, `thread-create`
149
+ - Participants: `addParticipant`, `removeParticipant`, `kick`, `leaveGroup`, `member-info`
147
150
  - Message lifecycle: `delete`, `unsend`
148
151
  - Pins: `pin`, `unpin`, `list-pins`
149
152
  - Space permissions: `permissions`
@@ -154,6 +157,7 @@ You can gate action groups from config:
154
157
  channels:
155
158
  inline:
156
159
  actions:
160
+ send: true
157
161
  reply: true
158
162
  reactions: true
159
163
  read: true
@@ -166,6 +170,14 @@ channels:
166
170
  permissions: true
167
171
  ```
168
172
 
173
+ ## Extra Agent Tools
174
+
175
+ The plugin also registers a dedicated `inline_members` tool for space-member discovery outside the `message` action surface.
176
+
177
+ - Required input: `spaceId`
178
+ - Optional filters: `query`, `userId`, `limit`, `accountId`
179
+ - Returned members include explicit DM targets like `user:123`
180
+
169
181
  Multi-account:
170
182
 
171
183
  ```yaml
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAK5D,QAAA,MAAM,MAAM,EAAE;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IAGnB,YAAY,EAAE,OAAO,CAAA;IACrB,QAAQ,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,IAAI,CAAA;CAU3C,CAAA;AAED,eAAe,MAAM,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAM1E,QAAA,MAAM,MAAM,EAAE;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IAGnB,YAAY,EAAE,OAAO,CAAA;IACrB,QAAQ,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,IAAI,CAAA;CAa3C,CAAA;AAED,eAAe,MAAM,CAAA"}
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
2
2
  import { inlineChannelPlugin } from "./inline/channel.js";
3
+ import { createInlineMembersTool } from "./inline/members-tool.js";
3
4
  import { setInlineRuntime } from "./runtime.js";
4
5
  const plugin = {
5
6
  id: "inline",
@@ -9,6 +10,9 @@ const plugin = {
9
10
  register(api) {
10
11
  setInlineRuntime(api.runtime);
11
12
  api.registerChannel({ plugin: inlineChannelPlugin });
13
+ api.registerTool((ctx) => createInlineMembersTool(ctx), {
14
+ names: ["inline_members"],
15
+ });
12
16
  },
13
17
  };
14
18
  export default plugin;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAE/C,MAAM,MAAM,GAQR;IACF,EAAE,EAAE,QAAQ;IACZ,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,2CAA2C;IACxD,YAAY,EAAE,uBAAuB,EAAE;IACvC,QAAQ,CAAC,GAAsB;QAC7B,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QAC7B,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC,CAAA;IACtD,CAAC;CACF,CAAA;AAED,eAAe,MAAM,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAE/C,MAAM,MAAM,GAQR;IACF,EAAE,EAAE,QAAQ;IACZ,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,2CAA2C;IACxD,YAAY,EAAE,uBAAuB,EAAE;IACvC,QAAQ,CAAC,GAAsB;QAC7B,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QAC7B,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC,CAAA;QACpD,GAAG,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,uBAAuB,CAAC,GAAG,CAAiB,EAAE;YACtE,KAAK,EAAE,CAAC,gBAAgB,CAAC;SAC1B,CAAC,CAAA;IACJ,CAAC;CACF,CAAA;AAED,eAAe,MAAM,CAAA"}
@@ -1,4 +1,4 @@
1
1
  import { type ChannelMessageActionAdapter } from "openclaw/plugin-sdk";
2
2
  export declare const inlineMessageActions: ChannelMessageActionAdapter;
3
- export declare const inlineSupportedActions: ("send" | "broadcast" | "poll" | "react" | "reactions" | "read" | "edit" | "unsend" | "reply" | "sendWithEffect" | "renameGroup" | "setGroupIcon" | "addParticipant" | "removeParticipant" | "leaveGroup" | "sendAttachment" | "delete" | "pin" | "unpin" | "list-pins" | "permissions" | "thread-create" | "thread-list" | "thread-reply" | "search" | "sticker" | "sticker-search" | "member-info" | "role-info" | "emoji-list" | "emoji-upload" | "sticker-upload" | "role-add" | "role-remove" | "channel-info" | "channel-list" | "channel-create" | "channel-edit" | "channel-delete" | "channel-move" | "category-create" | "category-edit" | "category-delete" | "voice-status" | "event-list" | "event-create" | "timeout" | "kick" | "ban" | "set-presence")[];
3
+ export declare const inlineSupportedActions: ("send" | "reply" | "reactions" | "read" | "search" | "edit" | "delete" | "permissions" | "broadcast" | "poll" | "react" | "unsend" | "sendWithEffect" | "renameGroup" | "setGroupIcon" | "addParticipant" | "removeParticipant" | "leaveGroup" | "sendAttachment" | "pin" | "unpin" | "list-pins" | "thread-create" | "thread-list" | "thread-reply" | "sticker" | "sticker-search" | "member-info" | "role-info" | "emoji-list" | "emoji-upload" | "sticker-upload" | "role-add" | "role-remove" | "channel-info" | "channel-list" | "channel-create" | "channel-edit" | "channel-delete" | "channel-move" | "category-create" | "category-edit" | "category-delete" | "voice-status" | "event-list" | "event-create" | "timeout" | "kick" | "ban" | "set-presence")[];
4
4
  //# sourceMappingURL=actions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/inline/actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,2BAA2B,EAGjC,MAAM,qBAAqB,CAAA;AA+iB5B,eAAO,MAAM,oBAAoB,EAAE,2BA82BlC,CAAA;AAED,eAAO,MAAM,sBAAsB,0uBAAmB,CAAA"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/inline/actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,2BAA2B,EAGjC,MAAM,qBAAqB,CAAA;AAqqB5B,eAAO,MAAM,oBAAoB,EAAE,2BAy6BlC,CAAA;AAED,eAAO,MAAM,sBAAsB,0uBAAmB,CAAA"}
@@ -1,9 +1,13 @@
1
1
  import { createActionGate, jsonResult, readReactionParams, readNumberParam, readStringParam, } from "openclaw/plugin-sdk";
2
- import { InlineSdkClient, Method, Member_Role, } from "@inline-chat/realtime-sdk";
2
+ import { InlineSdkClient, Method, } from "@inline-chat/realtime-sdk";
3
3
  import { resolveInlineAccount, resolveInlineToken } from "./accounts.js";
4
+ import { uploadInlineMediaFromUrl } from "./media.js";
5
+ import { summarizeInlineMessageContent } from "./message-content.js";
4
6
  import { normalizeInlineTarget } from "./normalize.js";
7
+ import { buildInlineUserDisplayName, getSpaceMembersWithUsers } from "./space-members.js";
5
8
  const ACTION_GROUPS = [
6
- { key: "reply", defaultEnabled: true, actions: ["reply"] },
9
+ { key: "send", defaultEnabled: true, actions: ["send", "sendAttachment"] },
10
+ { key: "reply", defaultEnabled: true, actions: ["reply", "thread-reply"] },
7
11
  { key: "reactions", defaultEnabled: true, actions: ["react", "reactions"] },
8
12
  { key: "read", defaultEnabled: true, actions: ["read"] },
9
13
  { key: "search", defaultEnabled: true, actions: ["search"] },
@@ -14,6 +18,7 @@ const ACTION_GROUPS = [
14
18
  actions: [
15
19
  "channel-info",
16
20
  "channel-edit",
21
+ "renameGroup",
17
22
  "channel-list",
18
23
  "channel-create",
19
24
  "channel-delete",
@@ -25,7 +30,7 @@ const ACTION_GROUPS = [
25
30
  {
26
31
  key: "participants",
27
32
  defaultEnabled: true,
28
- actions: ["addParticipant", "removeParticipant", "leaveGroup", "member-info"],
33
+ actions: ["addParticipant", "removeParticipant", "kick", "leaveGroup", "member-info"],
29
34
  },
30
35
  { key: "delete", defaultEnabled: true, actions: ["delete", "unsend"] },
31
36
  { key: "pins", defaultEnabled: true, actions: ["pin", "unpin", "list-pins"] },
@@ -165,6 +170,25 @@ function parseInlineListValuesFromParams(params, keys) {
165
170
  const entries = keys.flatMap((key) => parseInlineListValue(params[key], key));
166
171
  return Array.from(new Set(entries.map((entry) => entry.trim()).filter(Boolean)));
167
172
  }
173
+ function resolveInlineOutboundMediaInputs(params) {
174
+ const plural = parseInlineListValuesFromParams(params, [
175
+ "mediaUrls",
176
+ "attachmentUrls",
177
+ "filePaths",
178
+ "paths",
179
+ "files",
180
+ ]);
181
+ const single = parseInlineListValuesFromParams(params, [
182
+ "mediaUrl",
183
+ "attachmentUrl",
184
+ "url",
185
+ "media",
186
+ "filePath",
187
+ "path",
188
+ "file",
189
+ ]);
190
+ return Array.from(new Set([...plural, ...single]));
191
+ }
168
192
  function normalizeInlineUserLookupToken(raw) {
169
193
  return raw
170
194
  .trim()
@@ -261,6 +285,56 @@ function resolveChatIdFromParams(params) {
261
285
  }
262
286
  return BigInt(normalizeChatId(raw));
263
287
  }
288
+ function resolveMessageSendTargetFromParams(params) {
289
+ const explicitUserIdRaw = readFlexibleId(params, "userId") ?? readStringParam(params, "userId");
290
+ if (explicitUserIdRaw) {
291
+ const userId = parseInlineId(explicitUserIdRaw, "userId");
292
+ return {
293
+ target: `user:${String(userId)}`,
294
+ userId,
295
+ };
296
+ }
297
+ const rawTarget = readFlexibleId(params, "to") ?? readStringParam(params, "to");
298
+ if (rawTarget) {
299
+ const normalized = normalizeInlineTarget(rawTarget) ?? rawTarget.trim();
300
+ const userMatch = normalized.match(/^user:([0-9]+)$/i);
301
+ if (userMatch?.[1]) {
302
+ return {
303
+ target: `user:${userMatch[1]}`,
304
+ userId: BigInt(userMatch[1]),
305
+ };
306
+ }
307
+ if (!/^[0-9]+$/.test(normalized)) {
308
+ throw new Error(`inline action: invalid target "${rawTarget}"`);
309
+ }
310
+ return {
311
+ target: normalized,
312
+ chatId: BigInt(normalized),
313
+ };
314
+ }
315
+ const rawChatId = readFlexibleId(params, "chatId") ??
316
+ readStringParam(params, "chatId") ??
317
+ readFlexibleId(params, "channelId") ??
318
+ readStringParam(params, "channelId");
319
+ if (!rawChatId) {
320
+ throw new Error("inline action requires to/chatId/channelId/userId");
321
+ }
322
+ const normalized = normalizeInlineTarget(rawChatId) ?? rawChatId.trim();
323
+ const userMatch = normalized.match(/^user:([0-9]+)$/i);
324
+ if (userMatch?.[1]) {
325
+ return {
326
+ target: `user:${userMatch[1]}`,
327
+ userId: BigInt(userMatch[1]),
328
+ };
329
+ }
330
+ if (!/^[0-9]+$/.test(normalized)) {
331
+ throw new Error(`inline action: invalid target "${rawChatId}"`);
332
+ }
333
+ return {
334
+ target: normalized,
335
+ chatId: BigInt(normalized),
336
+ };
337
+ }
264
338
  function buildChatPeer(chatId) {
265
339
  return {
266
340
  type: {
@@ -269,16 +343,8 @@ function buildChatPeer(chatId) {
269
343
  },
270
344
  };
271
345
  }
272
- function buildInlineUserDisplayName(user) {
273
- const explicit = [user.firstName?.trim(), user.lastName?.trim()].filter(Boolean).join(" ");
274
- if (explicit)
275
- return explicit;
276
- const username = user.username?.trim();
277
- if (username)
278
- return `@${username}`;
279
- return "Unknown";
280
- }
281
346
  function mapMessage(message) {
347
+ const content = summarizeInlineMessageContent(message);
282
348
  const reactions = (message.reactions?.reactions ?? []).map((reaction) => ({
283
349
  emoji: reaction.emoji ?? "",
284
350
  userId: String(reaction.userId),
@@ -290,9 +356,17 @@ function mapMessage(message) {
290
356
  id: String(message.id),
291
357
  fromId: String(message.fromId),
292
358
  date: Number(message.date) * 1000,
293
- text: message.message ?? "",
359
+ text: content.text,
360
+ rawText: content.rawText,
361
+ attachmentText: content.attachmentText,
362
+ entityText: content.entityText,
294
363
  out: Boolean(message.out),
295
364
  replyToId: message.replyToMsgId != null ? String(message.replyToMsgId) : undefined,
365
+ attachmentUrls: content.attachmentUrls,
366
+ links: content.links,
367
+ media: content.media,
368
+ attachments: content.attachments,
369
+ entities: content.entities,
296
370
  reactions,
297
371
  };
298
372
  }
@@ -325,17 +399,6 @@ function mapChatEntry(params) {
325
399
  : null,
326
400
  };
327
401
  }
328
- function mapSpaceMemberRole(role) {
329
- if (role == null)
330
- return null;
331
- if (role === Member_Role.OWNER)
332
- return "owner";
333
- if (role === Member_Role.ADMIN)
334
- return "admin";
335
- if (role === Member_Role.MEMBER)
336
- return "member";
337
- return null;
338
- }
339
402
  async function loadMessageReactions(params) {
340
403
  const target = await findMessageById({
341
404
  client: params.client,
@@ -446,6 +509,33 @@ function buildUserMap(users) {
446
509
  }
447
510
  return map;
448
511
  }
512
+ async function resolveSpaceIdFromParams(params) {
513
+ const directSpaceId = parseOptionalInlineId(readFlexibleId(params.rawParams, "spaceId") ??
514
+ readFlexibleId(params.rawParams, "space") ??
515
+ readStringParam(params.rawParams, "spaceId"), "spaceId");
516
+ if (directSpaceId != null)
517
+ return directSpaceId;
518
+ const chatTarget = readFlexibleId(params.rawParams, "chatId") ??
519
+ readFlexibleId(params.rawParams, "channelId") ??
520
+ readFlexibleId(params.rawParams, "to") ??
521
+ readStringParam(params.rawParams, "to");
522
+ if (!chatTarget) {
523
+ throw new Error(`inline action: ${params.action} requires spaceId (or a chat target in a space)`);
524
+ }
525
+ const chatId = BigInt(normalizeChatId(chatTarget));
526
+ const chatResult = await params.client.invokeRaw(Method.GET_CHAT, {
527
+ oneofKind: "getChat",
528
+ getChat: { peerId: buildChatPeer(chatId) },
529
+ });
530
+ if (chatResult.oneofKind !== "getChat") {
531
+ throw new Error(`inline action: expected getChat result, got ${String(chatResult.oneofKind)}`);
532
+ }
533
+ const inferredSpaceId = chatResult.getChat.chat?.spaceId ?? chatResult.getChat.dialog?.spaceId;
534
+ if (inferredSpaceId == null) {
535
+ throw new Error(`inline action: ${params.action} requires a spaceId or a chat that belongs to a space`);
536
+ }
537
+ return inferredSpaceId;
538
+ }
449
539
  function listAllActions() {
450
540
  const out = new Set();
451
541
  for (const group of ACTION_GROUPS) {
@@ -494,7 +584,7 @@ export const inlineMessageActions = {
494
584
  if (!to)
495
585
  return null;
496
586
  const normalized = normalizeInlineTarget(to) ?? to;
497
- if (!/^[0-9]+$/.test(normalized))
587
+ if (!/^(user:)?[0-9]+$/i.test(normalized))
498
588
  return null;
499
589
  return { to: normalized };
500
590
  },
@@ -506,21 +596,98 @@ export const inlineMessageActions = {
506
596
  throw new Error(`inline action: ${action} is disabled by channels.inline.actions`);
507
597
  }
508
598
  const normalizedAction = action;
509
- if (normalizedAction === "reply") {
599
+ if (normalizedAction === "send" || normalizedAction === "sendAttachment") {
510
600
  const parseMarkdown = resolveInlineAccount({ cfg, accountId: accountId ?? null }).config.parseMarkdown ?? true;
511
601
  return await withInlineClient({
512
602
  cfg,
513
603
  accountId,
514
604
  fn: async (client) => {
515
- const chatId = resolveChatIdFromParams(params);
516
- const replyToMsgId = parseInlineId(readFlexibleId(params, "messageId") ??
605
+ const target = resolveMessageSendTargetFromParams(params);
606
+ const sendTarget = target.chatId != null ? { chatId: target.chatId } : target.userId != null ? { userId: target.userId } : null;
607
+ if (!sendTarget) {
608
+ throw new Error("inline action: missing message target");
609
+ }
610
+ const mediaSources = resolveInlineOutboundMediaInputs(params);
611
+ const text = readStringParam(params, "message") ??
612
+ readStringParam(params, "text") ??
613
+ readStringParam(params, "caption") ??
614
+ "";
615
+ const replyToMsgId = parseOptionalInlineId(readFlexibleId(params, "messageId") ??
517
616
  readFlexibleId(params, "replyTo") ??
518
617
  readFlexibleId(params, "replyToId") ??
519
618
  readStringParam(params, "messageId") ??
520
619
  readStringParam(params, "replyTo") ??
521
- readStringParam(params, "replyToId", { required: true }), "messageId");
522
- const text = readStringParam(params, "message") ??
523
- readStringParam(params, "text", { required: true, allowEmpty: true });
620
+ readStringParam(params, "replyToId"), "messageId");
621
+ if (normalizedAction === "sendAttachment" && mediaSources.length === 0) {
622
+ throw new Error("inline action: sendAttachment requires media/file input");
623
+ }
624
+ if (mediaSources.length === 0) {
625
+ const message = readStringParam(params, "message") ??
626
+ readStringParam(params, "text", { required: true, allowEmpty: true });
627
+ const sent = await client.sendMessage({
628
+ ...sendTarget,
629
+ text: message,
630
+ ...(replyToMsgId != null ? { replyToMsgId } : {}),
631
+ parseMarkdown,
632
+ });
633
+ return jsonResult({
634
+ ok: true,
635
+ target: target.target,
636
+ messageId: sent.messageId != null ? String(sent.messageId) : null,
637
+ replyToId: replyToMsgId != null ? String(replyToMsgId) : null,
638
+ });
639
+ }
640
+ let lastSent = null;
641
+ for (let index = 0; index < mediaSources.length; index += 1) {
642
+ const mediaUrl = mediaSources[index];
643
+ if (!mediaUrl)
644
+ continue;
645
+ const media = await uploadInlineMediaFromUrl({
646
+ client,
647
+ cfg,
648
+ accountId: accountId ?? null,
649
+ mediaUrl,
650
+ });
651
+ lastSent = await client.sendMessage({
652
+ ...sendTarget,
653
+ ...(index === 0 && text ? { text } : {}),
654
+ media,
655
+ ...(index === 0 && replyToMsgId != null ? { replyToMsgId } : {}),
656
+ ...(index === 0 && text ? { parseMarkdown } : {}),
657
+ });
658
+ }
659
+ return jsonResult({
660
+ ok: true,
661
+ target: target.target,
662
+ messageId: lastSent?.messageId != null ? String(lastSent.messageId) : null,
663
+ ...(mediaSources.length === 1 ? { mediaUrl: mediaSources[0] } : { mediaUrls: mediaSources }),
664
+ replyToId: replyToMsgId != null ? String(replyToMsgId) : null,
665
+ });
666
+ },
667
+ });
668
+ }
669
+ if (normalizedAction === "reply" || normalizedAction === "thread-reply") {
670
+ const parseMarkdown = resolveInlineAccount({ cfg, accountId: accountId ?? null }).config.parseMarkdown ?? true;
671
+ return await withInlineClient({
672
+ cfg,
673
+ accountId,
674
+ fn: async (client) => {
675
+ const replyParams = normalizedAction === "thread-reply" &&
676
+ params.threadId != null &&
677
+ params.to == null &&
678
+ params.chatId == null &&
679
+ params.channelId == null
680
+ ? { ...params, to: params.threadId }
681
+ : params;
682
+ const chatId = resolveChatIdFromParams(replyParams);
683
+ const replyToMsgId = parseInlineId(readFlexibleId(replyParams, "messageId") ??
684
+ readFlexibleId(replyParams, "replyTo") ??
685
+ readFlexibleId(replyParams, "replyToId") ??
686
+ readStringParam(replyParams, "messageId") ??
687
+ readStringParam(replyParams, "replyTo") ??
688
+ readStringParam(replyParams, "replyToId", { required: true }), "messageId");
689
+ const text = readStringParam(replyParams, "message") ??
690
+ readStringParam(replyParams, "text", { required: true, allowEmpty: true });
524
691
  const sent = await client.sendMessage({
525
692
  chatId,
526
693
  text,
@@ -668,6 +835,7 @@ export const inlineMessageActions = {
668
835
  });
669
836
  }
670
837
  if (normalizedAction === "edit") {
838
+ const parseMarkdown = resolveInlineAccount({ cfg, accountId: accountId ?? null }).config.parseMarkdown ?? true;
671
839
  return await withInlineClient({
672
840
  cfg,
673
841
  accountId,
@@ -682,12 +850,13 @@ export const inlineMessageActions = {
682
850
  messageId,
683
851
  peerId: buildChatPeer(chatId),
684
852
  text,
853
+ parseMarkdown,
685
854
  },
686
855
  });
687
856
  if (result.oneofKind !== "editMessage") {
688
857
  throw new Error(`inline action: expected editMessage result, got ${String(result.oneofKind)}`);
689
858
  }
690
- return jsonResult(toJsonSafe({ ok: true, chatId: String(chatId), messageId: String(messageId), text }));
859
+ return jsonResult(toJsonSafe({ ok: true, chatId: String(chatId), messageId: String(messageId), text, parseMarkdown }));
691
860
  },
692
861
  });
693
862
  }
@@ -714,7 +883,7 @@ export const inlineMessageActions = {
714
883
  },
715
884
  });
716
885
  }
717
- if (normalizedAction === "channel-edit") {
886
+ if (normalizedAction === "channel-edit" || normalizedAction === "renameGroup") {
718
887
  return await withInlineClient({
719
888
  cfg,
720
889
  accountId,
@@ -942,7 +1111,7 @@ export const inlineMessageActions = {
942
1111
  },
943
1112
  });
944
1113
  }
945
- if (normalizedAction === "removeParticipant") {
1114
+ if (normalizedAction === "removeParticipant" || normalizedAction === "kick") {
946
1115
  return await withInlineClient({
947
1116
  cfg,
948
1117
  accountId,
@@ -1135,17 +1304,11 @@ export const inlineMessageActions = {
1135
1304
  accountId,
1136
1305
  fn: async (client) => {
1137
1306
  const chatId = resolveChatIdFromParams(params);
1138
- const chatResult = await client.invokeRaw(Method.GET_CHAT, {
1139
- oneofKind: "getChat",
1140
- getChat: { peerId: buildChatPeer(chatId) },
1307
+ const spaceId = await resolveSpaceIdFromParams({
1308
+ client,
1309
+ action: "permissions",
1310
+ rawParams: params,
1141
1311
  });
1142
- if (chatResult.oneofKind !== "getChat") {
1143
- throw new Error(`inline action: expected getChat result, got ${String(chatResult.oneofKind)}`);
1144
- }
1145
- const spaceId = chatResult.getChat.chat?.spaceId ?? chatResult.getChat.dialog?.spaceId;
1146
- if (spaceId == null) {
1147
- throw new Error("inline action: permissions requires a chat that belongs to a space");
1148
- }
1149
1312
  const userIdRaw = readFlexibleId(params, "userId") ??
1150
1313
  readFlexibleId(params, "memberId") ??
1151
1314
  readStringParam(params, "userId");
@@ -1180,31 +1343,9 @@ export const inlineMessageActions = {
1180
1343
  throw new Error(`inline action: expected updateMemberAccess result, got ${String(updateResult.oneofKind)}`);
1181
1344
  }
1182
1345
  }
1183
- const membersResult = await client.invokeRaw(Method.GET_SPACE_MEMBERS, {
1184
- oneofKind: "getSpaceMembers",
1185
- getSpaceMembers: {
1186
- spaceId,
1187
- },
1188
- });
1189
- if (membersResult.oneofKind !== "getSpaceMembers") {
1190
- throw new Error(`inline action: expected getSpaceMembers result, got ${String(membersResult.oneofKind)}`);
1191
- }
1192
- const usersById = buildUserMap(membersResult.getSpaceMembers.users ?? []);
1193
- const members = (membersResult.getSpaceMembers.members ?? []).map((member) => {
1194
- const linkedUser = usersById.get(String(member.userId));
1195
- return {
1196
- userId: String(member.userId),
1197
- role: mapSpaceMemberRole(member.role),
1198
- canAccessPublicChats: member.canAccessPublicChats,
1199
- date: Number(member.date) * 1000,
1200
- user: linkedUser
1201
- ? {
1202
- id: String(linkedUser.id),
1203
- name: buildInlineUserDisplayName(linkedUser),
1204
- username: linkedUser.username ?? null,
1205
- }
1206
- : null,
1207
- };
1346
+ const members = await getSpaceMembersWithUsers({
1347
+ client,
1348
+ spaceId,
1208
1349
  });
1209
1350
  const filteredMembers = userId != null ? members.filter((member) => member.userId === String(userId)) : members;
1210
1351
  return jsonResult(toJsonSafe({