@inline-openclaw/inline 0.0.13 → 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;AAsiB5B,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"] },
@@ -38,6 +43,11 @@ for (const group of ACTION_GROUPS) {
38
43
  }
39
44
  }
40
45
  const SUPPORTED_ACTIONS = Array.from(ACTION_TO_GATE_KEY.keys());
46
+ const GET_MESSAGES_METHOD = typeof Method.GET_MESSAGES === "number" &&
47
+ Number.isInteger(Method.GET_MESSAGES) &&
48
+ Method.GET_MESSAGES > 0
49
+ ? Method.GET_MESSAGES
50
+ : null;
41
51
  function normalizeChatId(raw) {
42
52
  const normalized = normalizeInlineTarget(raw) ?? raw.trim();
43
53
  if (!/^[0-9]+$/.test(normalized)) {
@@ -160,6 +170,25 @@ function parseInlineListValuesFromParams(params, keys) {
160
170
  const entries = keys.flatMap((key) => parseInlineListValue(params[key], key));
161
171
  return Array.from(new Set(entries.map((entry) => entry.trim()).filter(Boolean)));
162
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
+ }
163
192
  function normalizeInlineUserLookupToken(raw) {
164
193
  return raw
165
194
  .trim()
@@ -256,6 +285,56 @@ function resolveChatIdFromParams(params) {
256
285
  }
257
286
  return BigInt(normalizeChatId(raw));
258
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
+ }
259
338
  function buildChatPeer(chatId) {
260
339
  return {
261
340
  type: {
@@ -264,16 +343,8 @@ function buildChatPeer(chatId) {
264
343
  },
265
344
  };
266
345
  }
267
- function buildInlineUserDisplayName(user) {
268
- const explicit = [user.firstName?.trim(), user.lastName?.trim()].filter(Boolean).join(" ");
269
- if (explicit)
270
- return explicit;
271
- const username = user.username?.trim();
272
- if (username)
273
- return `@${username}`;
274
- return "Unknown";
275
- }
276
346
  function mapMessage(message) {
347
+ const content = summarizeInlineMessageContent(message);
277
348
  const reactions = (message.reactions?.reactions ?? []).map((reaction) => ({
278
349
  emoji: reaction.emoji ?? "",
279
350
  userId: String(reaction.userId),
@@ -285,9 +356,17 @@ function mapMessage(message) {
285
356
  id: String(message.id),
286
357
  fromId: String(message.fromId),
287
358
  date: Number(message.date) * 1000,
288
- text: message.message ?? "",
359
+ text: content.text,
360
+ rawText: content.rawText,
361
+ attachmentText: content.attachmentText,
362
+ entityText: content.entityText,
289
363
  out: Boolean(message.out),
290
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,
291
370
  reactions,
292
371
  };
293
372
  }
@@ -320,17 +399,6 @@ function mapChatEntry(params) {
320
399
  : null,
321
400
  };
322
401
  }
323
- function mapSpaceMemberRole(role) {
324
- if (role == null)
325
- return null;
326
- if (role === Member_Role.OWNER)
327
- return "owner";
328
- if (role === Member_Role.ADMIN)
329
- return "admin";
330
- if (role === Member_Role.MEMBER)
331
- return "member";
332
- return null;
333
- }
334
402
  async function loadMessageReactions(params) {
335
403
  const target = await findMessageById({
336
404
  client: params.client,
@@ -360,15 +428,17 @@ async function loadMessageReactions(params) {
360
428
  return Array.from(byEmoji.values());
361
429
  }
362
430
  async function findMessageById(params) {
363
- const directResult = await params.client
364
- .invokeRaw(Method.GET_MESSAGES, {
365
- oneofKind: "getMessages",
366
- getMessages: {
367
- peerId: buildChatPeer(params.chatId),
368
- messageIds: [params.messageId],
369
- },
370
- })
371
- .catch(() => null);
431
+ const directResult = GET_MESSAGES_METHOD == null
432
+ ? null
433
+ : await params.client
434
+ .invokeRaw(GET_MESSAGES_METHOD, {
435
+ oneofKind: "getMessages",
436
+ getMessages: {
437
+ peerId: buildChatPeer(params.chatId),
438
+ messageIds: [params.messageId],
439
+ },
440
+ })
441
+ .catch(() => null);
372
442
  if (directResult?.oneofKind === "getMessages") {
373
443
  return (directResult.getMessages.messages ?? []).find((message) => message.id === params.messageId) ?? null;
374
444
  }
@@ -439,6 +509,33 @@ function buildUserMap(users) {
439
509
  }
440
510
  return map;
441
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
+ }
442
539
  function listAllActions() {
443
540
  const out = new Set();
444
541
  for (const group of ACTION_GROUPS) {
@@ -487,7 +584,7 @@ export const inlineMessageActions = {
487
584
  if (!to)
488
585
  return null;
489
586
  const normalized = normalizeInlineTarget(to) ?? to;
490
- if (!/^[0-9]+$/.test(normalized))
587
+ if (!/^(user:)?[0-9]+$/i.test(normalized))
491
588
  return null;
492
589
  return { to: normalized };
493
590
  },
@@ -499,21 +596,98 @@ export const inlineMessageActions = {
499
596
  throw new Error(`inline action: ${action} is disabled by channels.inline.actions`);
500
597
  }
501
598
  const normalizedAction = action;
502
- if (normalizedAction === "reply") {
599
+ if (normalizedAction === "send" || normalizedAction === "sendAttachment") {
503
600
  const parseMarkdown = resolveInlineAccount({ cfg, accountId: accountId ?? null }).config.parseMarkdown ?? true;
504
601
  return await withInlineClient({
505
602
  cfg,
506
603
  accountId,
507
604
  fn: async (client) => {
508
- const chatId = resolveChatIdFromParams(params);
509
- 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") ??
510
616
  readFlexibleId(params, "replyTo") ??
511
617
  readFlexibleId(params, "replyToId") ??
512
618
  readStringParam(params, "messageId") ??
513
619
  readStringParam(params, "replyTo") ??
514
- readStringParam(params, "replyToId", { required: true }), "messageId");
515
- const text = readStringParam(params, "message") ??
516
- 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 });
517
691
  const sent = await client.sendMessage({
518
692
  chatId,
519
693
  text,
@@ -661,6 +835,7 @@ export const inlineMessageActions = {
661
835
  });
662
836
  }
663
837
  if (normalizedAction === "edit") {
838
+ const parseMarkdown = resolveInlineAccount({ cfg, accountId: accountId ?? null }).config.parseMarkdown ?? true;
664
839
  return await withInlineClient({
665
840
  cfg,
666
841
  accountId,
@@ -675,12 +850,13 @@ export const inlineMessageActions = {
675
850
  messageId,
676
851
  peerId: buildChatPeer(chatId),
677
852
  text,
853
+ parseMarkdown,
678
854
  },
679
855
  });
680
856
  if (result.oneofKind !== "editMessage") {
681
857
  throw new Error(`inline action: expected editMessage result, got ${String(result.oneofKind)}`);
682
858
  }
683
- 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 }));
684
860
  },
685
861
  });
686
862
  }
@@ -707,7 +883,7 @@ export const inlineMessageActions = {
707
883
  },
708
884
  });
709
885
  }
710
- if (normalizedAction === "channel-edit") {
886
+ if (normalizedAction === "channel-edit" || normalizedAction === "renameGroup") {
711
887
  return await withInlineClient({
712
888
  cfg,
713
889
  accountId,
@@ -935,7 +1111,7 @@ export const inlineMessageActions = {
935
1111
  },
936
1112
  });
937
1113
  }
938
- if (normalizedAction === "removeParticipant") {
1114
+ if (normalizedAction === "removeParticipant" || normalizedAction === "kick") {
939
1115
  return await withInlineClient({
940
1116
  cfg,
941
1117
  accountId,
@@ -1128,17 +1304,11 @@ export const inlineMessageActions = {
1128
1304
  accountId,
1129
1305
  fn: async (client) => {
1130
1306
  const chatId = resolveChatIdFromParams(params);
1131
- const chatResult = await client.invokeRaw(Method.GET_CHAT, {
1132
- oneofKind: "getChat",
1133
- getChat: { peerId: buildChatPeer(chatId) },
1307
+ const spaceId = await resolveSpaceIdFromParams({
1308
+ client,
1309
+ action: "permissions",
1310
+ rawParams: params,
1134
1311
  });
1135
- if (chatResult.oneofKind !== "getChat") {
1136
- throw new Error(`inline action: expected getChat result, got ${String(chatResult.oneofKind)}`);
1137
- }
1138
- const spaceId = chatResult.getChat.chat?.spaceId ?? chatResult.getChat.dialog?.spaceId;
1139
- if (spaceId == null) {
1140
- throw new Error("inline action: permissions requires a chat that belongs to a space");
1141
- }
1142
1312
  const userIdRaw = readFlexibleId(params, "userId") ??
1143
1313
  readFlexibleId(params, "memberId") ??
1144
1314
  readStringParam(params, "userId");
@@ -1173,31 +1343,9 @@ export const inlineMessageActions = {
1173
1343
  throw new Error(`inline action: expected updateMemberAccess result, got ${String(updateResult.oneofKind)}`);
1174
1344
  }
1175
1345
  }
1176
- const membersResult = await client.invokeRaw(Method.GET_SPACE_MEMBERS, {
1177
- oneofKind: "getSpaceMembers",
1178
- getSpaceMembers: {
1179
- spaceId,
1180
- },
1181
- });
1182
- if (membersResult.oneofKind !== "getSpaceMembers") {
1183
- throw new Error(`inline action: expected getSpaceMembers result, got ${String(membersResult.oneofKind)}`);
1184
- }
1185
- const usersById = buildUserMap(membersResult.getSpaceMembers.users ?? []);
1186
- const members = (membersResult.getSpaceMembers.members ?? []).map((member) => {
1187
- const linkedUser = usersById.get(String(member.userId));
1188
- return {
1189
- userId: String(member.userId),
1190
- role: mapSpaceMemberRole(member.role),
1191
- canAccessPublicChats: member.canAccessPublicChats,
1192
- date: Number(member.date) * 1000,
1193
- user: linkedUser
1194
- ? {
1195
- id: String(linkedUser.id),
1196
- name: buildInlineUserDisplayName(linkedUser),
1197
- username: linkedUser.username ?? null,
1198
- }
1199
- : null,
1200
- };
1346
+ const members = await getSpaceMembersWithUsers({
1347
+ client,
1348
+ spaceId,
1201
1349
  });
1202
1350
  const filteredMembers = userId != null ? members.filter((member) => member.userId === String(userId)) : members;
1203
1351
  return jsonResult(toJsonSafe({