@inline-openclaw/inline 0.0.44 → 0.0.45

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.
@@ -11192,7 +11192,8 @@ class UpdateSidecars$Type extends import_runtime4.MessageType {
11192
11192
  super("UpdateSidecars", [
11193
11193
  { no: 1, name: "users", kind: "message", repeat: 1, T: () => User },
11194
11194
  { no: 2, name: "chats", kind: "message", repeat: 1, T: () => Chat },
11195
- { no: 3, name: "dialogs", kind: "message", repeat: 1, T: () => Dialog }
11195
+ { no: 3, name: "dialogs", kind: "message", repeat: 1, T: () => Dialog },
11196
+ { no: 4, name: "spaces", kind: "message", repeat: 1, T: () => Space }
11196
11197
  ]);
11197
11198
  }
11198
11199
  create(value) {
@@ -11200,6 +11201,7 @@ class UpdateSidecars$Type extends import_runtime4.MessageType {
11200
11201
  message.users = [];
11201
11202
  message.chats = [];
11202
11203
  message.dialogs = [];
11204
+ message.spaces = [];
11203
11205
  if (value !== undefined)
11204
11206
  import_runtime3.reflectionMergePartial(this, message, value);
11205
11207
  return message;
@@ -11218,6 +11220,9 @@ class UpdateSidecars$Type extends import_runtime4.MessageType {
11218
11220
  case 3:
11219
11221
  message.dialogs.push(Dialog.internalBinaryRead(reader, reader.uint32(), options));
11220
11222
  break;
11223
+ case 4:
11224
+ message.spaces.push(Space.internalBinaryRead(reader, reader.uint32(), options));
11225
+ break;
11221
11226
  default:
11222
11227
  let u = options.readUnknownField;
11223
11228
  if (u === "throw")
@@ -11236,6 +11241,8 @@ class UpdateSidecars$Type extends import_runtime4.MessageType {
11236
11241
  Chat.internalBinaryWrite(message.chats[i], writer.tag(2, import_runtime.WireType.LengthDelimited).fork(), options).join();
11237
11242
  for (let i = 0;i < message.dialogs.length; i++)
11238
11243
  Dialog.internalBinaryWrite(message.dialogs[i], writer.tag(3, import_runtime.WireType.LengthDelimited).fork(), options).join();
11244
+ for (let i = 0;i < message.spaces.length; i++)
11245
+ Space.internalBinaryWrite(message.spaces[i], writer.tag(4, import_runtime.WireType.LengthDelimited).fork(), options).join();
11239
11246
  let u = options.writeUnknownFields;
11240
11247
  if (u !== false)
11241
11248
  (u == true ? import_runtime2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
@@ -21056,7 +21063,7 @@ class InlineSdkClient {
21056
21063
  await this.handleUpdate(update);
21057
21064
  }
21058
21065
  }
21059
- async handleUpdate(update) {
21066
+ async handleUpdate(update, options) {
21060
21067
  const seq = update.seq ?? 0;
21061
21068
  const date = update.date ?? 0n;
21062
21069
  switch (update.update.oneofKind) {
@@ -21188,6 +21195,34 @@ class InlineSdkClient {
21188
21195
  });
21189
21196
  return;
21190
21197
  }
21198
+ case "participantAdd": {
21199
+ const payload = update.update.participantAdd;
21200
+ if (options?.source !== "user" && options?.source !== "space") {
21201
+ this.bumpChatSeq(payload.chatId, seq);
21202
+ }
21203
+ await this.eventStream.send({
21204
+ kind: "chat.participant.add",
21205
+ chatId: payload.chatId,
21206
+ ...payload.participant ? { participant: payload.participant } : {},
21207
+ seq,
21208
+ date
21209
+ });
21210
+ return;
21211
+ }
21212
+ case "participantDelete": {
21213
+ const payload = update.update.participantDelete;
21214
+ if (options?.source !== "user" && options?.source !== "space") {
21215
+ this.bumpChatSeq(payload.chatId, seq);
21216
+ }
21217
+ await this.eventStream.send({
21218
+ kind: "chat.participant.delete",
21219
+ chatId: payload.chatId,
21220
+ userId: payload.userId,
21221
+ seq,
21222
+ date
21223
+ });
21224
+ return;
21225
+ }
21191
21226
  case "messageActionInvoked": {
21192
21227
  const payload = update.update.messageActionInvoked;
21193
21228
  if (this.shouldSkipUserSeq(seq)) {
@@ -21288,14 +21323,14 @@ class InlineSdkClient {
21288
21323
  }
21289
21324
  }
21290
21325
  requestCatchUpUser() {
21291
- const lastUserSeq = this.state.lastUserSeq ?? 0;
21292
- if (lastUserSeq <= 0) {
21326
+ const lastUserSeq = this.state.lastUserSeq;
21327
+ if (lastUserSeq == null && !this.options.catchUpUserFromStart) {
21293
21328
  return;
21294
21329
  }
21295
21330
  if (this.userCatchUpInFlight) {
21296
21331
  return;
21297
21332
  }
21298
- this.userCatchUpInFlight = this.doCatchUpUser(lastUserSeq).catch((error) => {
21333
+ this.userCatchUpInFlight = this.doCatchUpUser(lastUserSeq ?? 0).catch((error) => {
21299
21334
  this.log.warn?.("GET_UPDATES user catch-up failed; continuing live delivery", {
21300
21335
  error: extractErrorMessage(error)
21301
21336
  });
@@ -21336,7 +21371,7 @@ class InlineSdkClient {
21336
21371
  return;
21337
21372
  }
21338
21373
  for (const update of payload.updates) {
21339
- await this.handleUpdate(update);
21374
+ await this.handleUpdate(update, { source: "user" });
21340
21375
  }
21341
21376
  this.bumpUserSeq(deliveredSeq);
21342
21377
  if (payload.date !== 0n) {
@@ -21435,7 +21470,7 @@ class InlineSdkClient {
21435
21470
  }
21436
21471
  this.bumpChatSeq(chatId, deliveredSeq);
21437
21472
  for (const update of payload.updates) {
21438
- await this.handleUpdate(update);
21473
+ await this.handleUpdate(update, { source: "chat" });
21439
21474
  }
21440
21475
  if (payload.date !== 0n) {
21441
21476
  this.state.dateCursor = payload.date;
@@ -21537,7 +21572,7 @@ class InlineSdkClient {
21537
21572
  }
21538
21573
  this.bumpSpaceSeq(spaceId, deliveredSeq);
21539
21574
  for (const update of payload.updates) {
21540
- await this.handleUpdate(update);
21575
+ await this.handleUpdate(update, { source: "space" });
21541
21576
  }
21542
21577
  if (payload.date !== 0n) {
21543
21578
  this.state.dateCursor = payload.date;
@@ -36472,6 +36507,8 @@ var InlineExecApprovalsSchema = exports_external.object({
36472
36507
  var InlineReactionNotificationsSchema = exports_external.enum(["off", "own", "all", "allowlist"]);
36473
36508
  var InlineStreamingModeSchema = exports_external.enum(["off", "partial", "block", "progress"]);
36474
36509
  var InlineStreamingCommandTextSchema = exports_external.enum(["raw", "status"]);
36510
+ var INLINE_DEFAULT_GROUP_POLICY = "open";
36511
+ var INLINE_DEFAULT_REQUIRE_MENTION = true;
36475
36512
  var InlineStreamingChunkSchema = exports_external.object({
36476
36513
  minChars: exports_external.number().int().positive().optional(),
36477
36514
  maxChars: exports_external.number().int().positive().optional(),
@@ -36543,7 +36580,7 @@ var InlineAccountSchemaBase = exports_external.object({
36543
36580
  defaultTo: InlineTargetSchema.optional(),
36544
36581
  systemPrompt: exports_external.string().optional(),
36545
36582
  groupAllowFrom: exports_external.array(InlineAllowEntrySchema).optional(),
36546
- groupPolicy: GroupPolicySchema.optional().default("allowlist"),
36583
+ groupPolicy: GroupPolicySchema.optional().default(INLINE_DEFAULT_GROUP_POLICY),
36547
36584
  groups: exports_external.record(exports_external.string(), InlineGroupSchema.optional()).optional(),
36548
36585
  requireMention: exports_external.boolean().optional(),
36549
36586
  replyThreadMode: InlineReplyThreadModeSchema.optional(),
@@ -37042,7 +37079,7 @@ function looksLikeInlineTargetId(raw, normalizedInput) {
37042
37079
  }
37043
37080
 
37044
37081
  // src/inline/monitor.ts
37045
- import { mkdir } from "node:fs/promises";
37082
+ import { mkdir, stat } from "node:fs/promises";
37046
37083
  import path4 from "node:path";
37047
37084
  import {
37048
37085
  buildCommandTextFromArgs,
@@ -40897,11 +40934,339 @@ function redactInlineBotApiUrl(raw) {
40897
40934
  }
40898
40935
  }
40899
40936
 
40937
+ // src/inline/threadreply-command.ts
40938
+ var MODE_LABELS = {
40939
+ auto: "auto",
40940
+ thread: "thread",
40941
+ main: "main"
40942
+ };
40943
+ var DEFAULT_REPLY_THREAD_AUTO_CREATE_MIN_MESSAGES = 50;
40944
+ var INLINE_THREADREPLY_NATIVE_NAME = "threadreply";
40945
+ var INLINE_THREADREPLY_COMMAND_SPEC = {
40946
+ name: "threadreply",
40947
+ nativeNames: { inline: INLINE_THREADREPLY_NATIVE_NAME },
40948
+ description: "Set Inline reply-thread mode for this chat.",
40949
+ channels: ["inline"],
40950
+ acceptsArgs: true
40951
+ };
40952
+ function listInlineBuiltinCommandSpecs() {
40953
+ return [
40954
+ {
40955
+ name: INLINE_THREADREPLY_COMMAND_SPEC.nativeNames.inline ?? INLINE_THREADREPLY_COMMAND_SPEC.name,
40956
+ description: INLINE_THREADREPLY_COMMAND_SPEC.description,
40957
+ acceptsArgs: INLINE_THREADREPLY_COMMAND_SPEC.acceptsArgs
40958
+ }
40959
+ ];
40960
+ }
40961
+ function isRecord5(value) {
40962
+ return typeof value === "object" && value !== null && !Array.isArray(value);
40963
+ }
40964
+ function asInlineConfig(value) {
40965
+ return isRecord5(value) ? value : undefined;
40966
+ }
40967
+ function normalizeMode(raw) {
40968
+ if (typeof raw !== "string")
40969
+ return null;
40970
+ const normalized = raw.trim().toLowerCase();
40971
+ if (normalized === "on" || normalized === "threads")
40972
+ return "thread";
40973
+ if (normalized === "off" || normalized === "parent" || normalized === "parentchat")
40974
+ return "main";
40975
+ if (normalized === "auto" || normalized === "thread" || normalized === "main")
40976
+ return normalized;
40977
+ return null;
40978
+ }
40979
+ function normalizeMin(raw) {
40980
+ if (typeof raw !== "number")
40981
+ return null;
40982
+ if (!Number.isInteger(raw) || raw < 0)
40983
+ return null;
40984
+ return raw;
40985
+ }
40986
+ function parseMinArg(raw) {
40987
+ const value = raw?.trim().toLowerCase();
40988
+ if (!value)
40989
+ return null;
40990
+ if (value === "inherit" || value === "default" || value === "unset")
40991
+ return "inherit";
40992
+ if (!/^\d+$/.test(value))
40993
+ return null;
40994
+ const parsed = Number(value);
40995
+ return Number.isSafeInteger(parsed) ? parsed : null;
40996
+ }
40997
+ function resolveInlineGroupId(ctx) {
40998
+ const raw = ctx.from?.trim() ?? "";
40999
+ if (!/(^|:)chat:/i.test(raw))
41000
+ return null;
41001
+ const normalized = normalizeInlineTarget(raw);
41002
+ return normalized && /^[0-9]+$/.test(normalized) ? normalized : null;
41003
+ }
41004
+ function resolveInlineConfigForAccount(inline, accountId) {
41005
+ const normalized = normalizeAccountId(accountId);
41006
+ const accounts = isRecord5(inline.accounts) ? inline.accounts : undefined;
41007
+ const accountKey = accounts ? Object.keys(accounts).find((key) => normalizeAccountId(key) === normalized) : undefined;
41008
+ if (accountKey && accounts?.[accountKey]) {
41009
+ return accounts[accountKey];
41010
+ }
41011
+ if (normalized !== DEFAULT_ACCOUNT_ID) {
41012
+ return {};
41013
+ }
41014
+ return inline;
41015
+ }
41016
+ function resolveCurrentMode(params) {
41017
+ const inline = asInlineConfig(params.cfg.channels?.inline) ?? {};
41018
+ const accountConfig = resolveInlineConfigForAccount(inline, params.accountId);
41019
+ return resolveInlineGroupReplyThreadMode({
41020
+ cfg: params.cfg,
41021
+ accountId: params.accountId ?? null,
41022
+ groupId: params.groupId,
41023
+ defaultMode: normalizeMode(accountConfig.replyThreadMode) ?? "auto"
41024
+ });
41025
+ }
41026
+ function resolveCurrentMinMessages(params) {
41027
+ const inline = asInlineConfig(params.cfg.channels?.inline) ?? {};
41028
+ const accountConfig = resolveInlineConfigForAccount(inline, params.accountId);
41029
+ return resolveInlineGroupReplyThreadAutoCreateMinMessages({
41030
+ cfg: params.cfg,
41031
+ accountId: params.accountId ?? null,
41032
+ groupId: params.groupId,
41033
+ defaultMinMessages: normalizeMin(accountConfig.replyThreadAutoCreateMinMessages) ?? DEFAULT_REPLY_THREAD_AUTO_CREATE_MIN_MESSAGES
41034
+ });
41035
+ }
41036
+ function readExplicitMode(params) {
41037
+ const inline = asInlineConfig(params.cfg.channels?.inline);
41038
+ if (!inline)
41039
+ return null;
41040
+ const accountConfig = resolveInlineConfigForAccount(inline, params.accountId);
41041
+ const group = accountConfig.groups?.[params.groupId];
41042
+ return normalizeMode(group?.replyThreadMode);
41043
+ }
41044
+ function readExplicitMinMessages(params) {
41045
+ const inline = asInlineConfig(params.cfg.channels?.inline);
41046
+ if (!inline)
41047
+ return null;
41048
+ const accountConfig = resolveInlineConfigForAccount(inline, params.accountId);
41049
+ const group = accountConfig.groups?.[params.groupId];
41050
+ return normalizeMin(group?.replyThreadAutoCreateMinMessages);
41051
+ }
41052
+ function ensureRecordField(parent, key) {
41053
+ const current = parent[key];
41054
+ if (isRecord5(current))
41055
+ return current;
41056
+ const next = {};
41057
+ parent[key] = next;
41058
+ return next;
41059
+ }
41060
+ function resolveMutableInlineConfigForAccount(inline, accountId) {
41061
+ const normalized = normalizeAccountId(accountId);
41062
+ if (normalized === DEFAULT_ACCOUNT_ID) {
41063
+ const accounts2 = isRecord5(inline.accounts) ? inline.accounts : undefined;
41064
+ const defaultKey = accounts2 ? Object.keys(accounts2).find((key) => normalizeAccountId(key) === DEFAULT_ACCOUNT_ID) : undefined;
41065
+ const defaultAccount = defaultKey ? accounts2?.[defaultKey] : undefined;
41066
+ return defaultAccount ?? inline;
41067
+ }
41068
+ const accounts = ensureRecordField(inline, "accounts");
41069
+ const accountKey = Object.keys(accounts).find((key) => normalizeAccountId(key) === normalized) ?? normalized;
41070
+ const account = asInlineConfig(accounts[accountKey]) ?? {};
41071
+ accounts[accountKey] = account;
41072
+ return account;
41073
+ }
41074
+ function setGroupMode(params) {
41075
+ const root = params.draft;
41076
+ const channels = root.channels ?? {};
41077
+ root.channels = channels;
41078
+ const inline = asInlineConfig(channels.inline) ?? {};
41079
+ channels.inline = inline;
41080
+ const accountConfig = resolveMutableInlineConfigForAccount(inline, params.accountId);
41081
+ const groups = ensureRecordField(accountConfig, "groups");
41082
+ const group = isRecord5(groups[params.groupId]) ? groups[params.groupId] : {};
41083
+ groups[params.groupId] = group;
41084
+ if (params.mode === "inherit") {
41085
+ delete group.replyThreadMode;
41086
+ return;
41087
+ }
41088
+ group.replyThreadMode = params.mode;
41089
+ }
41090
+ function setGroupMinMessages(params) {
41091
+ const root = params.draft;
41092
+ const channels = root.channels ?? {};
41093
+ root.channels = channels;
41094
+ const inline = asInlineConfig(channels.inline) ?? {};
41095
+ channels.inline = inline;
41096
+ const accountConfig = resolveMutableInlineConfigForAccount(inline, params.accountId);
41097
+ const groups = ensureRecordField(accountConfig, "groups");
41098
+ const group = isRecord5(groups[params.groupId]) ? groups[params.groupId] : {};
41099
+ groups[params.groupId] = group;
41100
+ if (params.minMessages === "inherit") {
41101
+ delete group.replyThreadAutoCreateMinMessages;
41102
+ return;
41103
+ }
41104
+ group.replyThreadAutoCreateMinMessages = params.minMessages;
41105
+ }
41106
+ function buildStatusText(params) {
41107
+ const explicit = readExplicitMode(params);
41108
+ const current = resolveCurrentMode(params);
41109
+ const explicitMin = readExplicitMinMessages(params);
41110
+ const currentMin = resolveCurrentMinMessages(params);
41111
+ return [
41112
+ `Thread reply mode for chat ${params.groupId}: ${MODE_LABELS[current]}.`,
41113
+ explicit ? `Explicit chat override: ${MODE_LABELS[explicit]}.` : "Explicit chat override: inherit.",
41114
+ `Auto-create minimum messages: ${currentMin}.`,
41115
+ explicitMin != null ? `Explicit minimum override: ${explicitMin}.` : "Explicit minimum override: inherit."
41116
+ ].join(`
41117
+ `);
41118
+ }
41119
+ function buildMenuText(params) {
41120
+ return [
41121
+ buildStatusText(params),
41122
+ "",
41123
+ "Choose where automatic replies for this group should go."
41124
+ ].join(`
41125
+ `);
41126
+ }
41127
+ function buildModeButtons() {
41128
+ return {
41129
+ inline: {
41130
+ buttons: [
41131
+ [
41132
+ { text: "Thread", callback_data: "/threadreply thread" },
41133
+ { text: "Main", callback_data: "/threadreply main" },
41134
+ { text: "Auto", callback_data: "/threadreply auto" }
41135
+ ],
41136
+ [{ text: "Inherit Mode", callback_data: "/threadreply inherit" }],
41137
+ [
41138
+ { text: "Min 0", callback_data: "/threadreply min 0" },
41139
+ { text: "Min 50", callback_data: "/threadreply min 50" },
41140
+ { text: "Inherit Min", callback_data: "/threadreply min inherit" }
41141
+ ]
41142
+ ]
41143
+ }
41144
+ };
41145
+ }
41146
+ function normalizeAction(args) {
41147
+ const [first = ""] = args.split(/\s+/).filter(Boolean);
41148
+ const normalized = first.trim().toLowerCase();
41149
+ if (!normalized || normalized === "help" || normalized === "options")
41150
+ return "help";
41151
+ if (normalized === "status" || normalized === "show")
41152
+ return "status";
41153
+ if (normalized === "inherit" || normalized === "default" || normalized === "unset")
41154
+ return "inherit";
41155
+ return normalizeMode(normalized);
41156
+ }
41157
+ async function handleInlineThreadReplyCommand(api2, ctx) {
41158
+ return await handleInlineThreadReplyCommandWithConfigRuntime(api2.runtime.config, ctx);
41159
+ }
41160
+ async function handleInlineThreadReplyCommandWithConfigRuntime(configRuntime, ctx) {
41161
+ if (!ctx.isAuthorizedSender) {
41162
+ return { text: "This command requires authorization." };
41163
+ }
41164
+ const groupId = resolveInlineGroupId(ctx);
41165
+ if (!groupId) {
41166
+ return { text: "/threadreply is only available in Inline group chats." };
41167
+ }
41168
+ const currentConfig = configRuntime.current();
41169
+ const args = ctx.args?.trim() ?? "";
41170
+ const [first = "", second, ...rest] = args.split(/\s+/).filter(Boolean);
41171
+ if (["min", "minimum", "threshold", "limit"].includes(first.trim().toLowerCase())) {
41172
+ const minMessages = parseMinArg(second);
41173
+ if (minMessages == null || rest.length > 0) {
41174
+ return { text: "Usage: /threadreply min <0-or-greater>|inherit" };
41175
+ }
41176
+ const committed2 = await configRuntime.mutateConfigFile({
41177
+ afterWrite: { mode: "auto" },
41178
+ mutate: (draft) => {
41179
+ setGroupMinMessages({
41180
+ draft,
41181
+ accountId: ctx.accountId,
41182
+ groupId,
41183
+ minMessages
41184
+ });
41185
+ }
41186
+ });
41187
+ const nextConfig2 = committed2.nextConfig;
41188
+ return {
41189
+ text: buildStatusText({
41190
+ cfg: nextConfig2,
41191
+ accountId: ctx.accountId,
41192
+ groupId
41193
+ })
41194
+ };
41195
+ }
41196
+ const action = normalizeAction(args);
41197
+ if (action === "help") {
41198
+ return {
41199
+ text: buildMenuText({
41200
+ cfg: currentConfig,
41201
+ accountId: ctx.accountId,
41202
+ groupId
41203
+ }),
41204
+ channelData: buildModeButtons()
41205
+ };
41206
+ }
41207
+ if (action === "status") {
41208
+ return {
41209
+ text: buildStatusText({
41210
+ cfg: currentConfig,
41211
+ accountId: ctx.accountId,
41212
+ groupId
41213
+ })
41214
+ };
41215
+ }
41216
+ if (!action) {
41217
+ return {
41218
+ text: [
41219
+ "Usage: /threadreply thread|main|auto|inherit|status",
41220
+ " /threadreply min <0-or-greater>|inherit",
41221
+ "",
41222
+ "- thread: auto-route parent-chat replies into per-message Inline reply threads once the minimum is reached.",
41223
+ "- main: keep automatic replies in the parent chat.",
41224
+ "- auto: use Inline's automatic default behavior for this chat.",
41225
+ "- inherit: remove this chat override and use account/default config.",
41226
+ "- min: set how many parent-chat messages must exist before automatic thread creation."
41227
+ ].join(`
41228
+ `)
41229
+ };
41230
+ }
41231
+ const committed = await configRuntime.mutateConfigFile({
41232
+ afterWrite: { mode: "auto" },
41233
+ mutate: (draft) => {
41234
+ setGroupMode({
41235
+ draft,
41236
+ accountId: ctx.accountId,
41237
+ groupId,
41238
+ mode: action
41239
+ });
41240
+ }
41241
+ });
41242
+ const nextConfig = committed.nextConfig;
41243
+ return {
41244
+ text: buildStatusText({
41245
+ cfg: nextConfig,
41246
+ accountId: ctx.accountId,
41247
+ groupId
41248
+ })
41249
+ };
41250
+ }
41251
+ function createInlineThreadReplyCommand(api2) {
41252
+ return {
41253
+ ...INLINE_THREADREPLY_COMMAND_SPEC,
41254
+ handler: async (ctx) => await handleInlineThreadReplyCommand(api2, ctx)
41255
+ };
41256
+ }
41257
+
40900
41258
  // src/inline/bot-commands-sync.ts
40901
41259
  var INLINE_COMMAND_NAME_RE = /^[a-z0-9_]{1,32}$/;
40902
41260
  var INLINE_COMMAND_LIMIT = 100;
40903
41261
  var INLINE_COMMAND_DESCRIPTION_LIMIT = 256;
40904
41262
  var INLINE_NATIVE_COMMAND_PROVIDER = "inline";
41263
+ function resolveInlineChannelCommands(cfg) {
41264
+ const inline = cfg.channels?.inline;
41265
+ if (typeof inline !== "object" || inline === null || Array.isArray(inline))
41266
+ return;
41267
+ const commands = inline.commands;
41268
+ return typeof commands === "object" && commands !== null && !Array.isArray(commands) ? commands : undefined;
41269
+ }
40905
41270
  function normalizeDynamicCommandName(raw) {
40906
41271
  const trimmed = raw.trim().toLowerCase();
40907
41272
  const withoutSlash = trimmed.startsWith("/") ? trimmed.slice(1) : trimmed;
@@ -40922,11 +41287,11 @@ function appendUniqueCommand(out, seen, command, description, logger) {
40922
41287
  out.push({ command: normalized, description: trimmedDescription });
40923
41288
  }
40924
41289
  function shouldSyncInlineNativeCommandsForAccount(params) {
40925
- const effective = params.account.config.commands?.native ?? params.cfg.commands?.native ?? "auto";
41290
+ const effective = params.account.config.commands?.native ?? resolveInlineChannelCommands(params.cfg)?.native ?? params.cfg.commands?.native ?? "auto";
40926
41291
  return effective !== false;
40927
41292
  }
40928
41293
  function shouldSyncInlineNativeSkillsForAccount(params) {
40929
- const effective = params.account.config.commands?.nativeSkills ?? params.cfg.commands?.nativeSkills ?? "auto";
41294
+ const effective = params.account.config.commands?.nativeSkills ?? resolveInlineChannelCommands(params.cfg)?.nativeSkills ?? params.cfg.commands?.nativeSkills ?? "auto";
40930
41295
  return effective !== false;
40931
41296
  }
40932
41297
  async function buildInlineNativeCommandsForConfig(params) {
@@ -40943,7 +41308,10 @@ async function buildInlineNativeCommandsForConfig(params) {
40943
41308
  skillCommands,
40944
41309
  provider: INLINE_NATIVE_COMMAND_PROVIDER
40945
41310
  });
40946
- const pluginSpecs = getPluginCommandSpecs("inline", { config: params.cfg });
41311
+ const pluginSpecs = [
41312
+ ...getPluginCommandSpecs("inline", { config: params.cfg }),
41313
+ ...listInlineBuiltinCommandSpecs()
41314
+ ];
40947
41315
  const seen = new Set;
40948
41316
  const resolved = [];
40949
41317
  for (const spec of nativeSpecs) {
@@ -41047,8 +41415,9 @@ var INLINE_NATIVE_COMMAND_PROVIDER2 = CHANNEL_ID;
41047
41415
  var INLINE_NATIVE_COMMAND_CALLBACK_PREFIX = "icmd:";
41048
41416
  var INLINE_REQUEST_ERROR_FALLBACK = "OpenClaw could not process that request. Please try again.";
41049
41417
  var INLINE_DEBOUNCE_ERROR_FALLBACK = "OpenClaw could not process those messages. Please try again.";
41050
- var DEFAULT_REPLY_THREAD_AUTO_CREATE_MIN_MESSAGES = 50;
41418
+ var DEFAULT_REPLY_THREAD_AUTO_CREATE_MIN_MESSAGES2 = 50;
41051
41419
  var DEFAULT_REPLY_THREAD_PARENT_HISTORY_LIMIT = 10;
41420
+ var INLINE_PARTICIPANT_ADD_READY_MAX_EVENT_AGE_MS = 10 * 60 * 1000;
41052
41421
  var INLINE_REPLY_THREAD_SYSTEM_PROMPT = "Inline reply threads are scoped conversations: answer only the current reply-thread message and this thread's own history; use parent-chat context only as background, and do not answer unrelated questions from the parent chat or other reply threads.";
41053
41422
  function buildInlineTypingDispatcherOptions(typingCallbacks) {
41054
41423
  if (!typingCallbacks) {
@@ -41362,6 +41731,23 @@ function buildInlineReactionContextKey(params) {
41362
41731
  const emoji3 = params.emoji.trim() || "emoji";
41363
41732
  return `inline:reaction:${params.action}:${String(params.chatId)}:${String(params.messageId)}:${String(params.senderId)}:${emoji3}`;
41364
41733
  }
41734
+ function describeInlineParticipantAddSystemEvent(params) {
41735
+ const header = `Inline bot was added as a participant in ${params.channelLabel}.`;
41736
+ if (params.recentLines.length === 0)
41737
+ return header;
41738
+ return `${header}
41739
+ Recent messages before join:
41740
+ ${params.recentLines.join(`
41741
+ `)}`;
41742
+ }
41743
+ function buildInlineParticipantAddContextKey(params) {
41744
+ return [
41745
+ "inline:participant:added",
41746
+ String(params.chatId),
41747
+ String(params.userId),
41748
+ params.participantDate != null ? String(params.participantDate) : String(params.seq ?? 0)
41749
+ ].join(":");
41750
+ }
41365
41751
  function normalizeInlineUsername(raw) {
41366
41752
  const trimmed = raw?.trim();
41367
41753
  if (!trimmed)
@@ -41403,6 +41789,28 @@ function parseInlineNativeCommandCallbackData(raw) {
41403
41789
  const commandText = trimmed.slice(INLINE_NATIVE_COMMAND_CALLBACK_PREFIX.length).trim();
41404
41790
  return commandText.startsWith("/") ? commandText : null;
41405
41791
  }
41792
+ function listHostInlinePluginCommandSpecs(cfg) {
41793
+ return getPluginCommandSpecs2("inline", { config: cfg });
41794
+ }
41795
+ function listInlinePluginCommandSpecs(cfg) {
41796
+ return [
41797
+ ...listHostInlinePluginCommandSpecs(cfg),
41798
+ ...listInlineBuiltinCommandSpecs()
41799
+ ];
41800
+ }
41801
+ function hasInlineCommandSpec(specs, commandName) {
41802
+ const normalized = commandName.trim().toLowerCase();
41803
+ if (!normalized)
41804
+ return false;
41805
+ return specs.some((spec) => spec.name.trim().toLowerCase() === normalized);
41806
+ }
41807
+ function isInlineThreadReplyCommandBody(commandBody) {
41808
+ return resolveInlineCommandNameFromBody(commandBody) === "threadreply";
41809
+ }
41810
+ function parseInlineCommandArgs(commandBody) {
41811
+ const match = commandBody.trim().match(/^\/[^\s]+(?:\s+([\s\S]*))?$/);
41812
+ return match?.[1]?.trim() ?? "";
41813
+ }
41406
41814
  function isInlineNativeCommandBody(params) {
41407
41815
  if (!shouldSyncInlineNativeCommandsForAccount({ cfg: params.cfg, account: params.account })) {
41408
41816
  return false;
@@ -41425,7 +41833,7 @@ function isInlineNativeCommandBody(params) {
41425
41833
  if (spec.name.trim().toLowerCase() === commandName)
41426
41834
  return true;
41427
41835
  }
41428
- for (const spec of getPluginCommandSpecs2("inline", { config: params.cfg })) {
41836
+ for (const spec of listInlinePluginCommandSpecs(params.cfg)) {
41429
41837
  if (spec.name.trim().toLowerCase() === commandName)
41430
41838
  return true;
41431
41839
  }
@@ -41506,7 +41914,7 @@ function buildSyntheticInlineTextMessage(params) {
41506
41914
  }
41507
41915
  var INLINE_ACTION_MAX_ROWS2 = 8;
41508
41916
  var INLINE_ACTION_MAX_PER_ROW2 = 8;
41509
- function isRecord5(value) {
41917
+ function isRecord6(value) {
41510
41918
  return typeof value === "object" && value !== null && !Array.isArray(value);
41511
41919
  }
41512
41920
  function normalizeOptionalString2(value) {
@@ -41527,7 +41935,7 @@ function normalizeInlineStreamingMode(value) {
41527
41935
  }
41528
41936
  }
41529
41937
  function resolveExplicitInlineStreamingMode(config2) {
41530
- const streaming = isRecord5(config2.streaming) ? config2.streaming : null;
41938
+ const streaming = isRecord6(config2.streaming) ? config2.streaming : null;
41531
41939
  return normalizeInlineStreamingMode(streaming?.mode) ?? normalizeInlineStreamingMode(config2.streaming) ?? normalizeInlineStreamingMode(config2.streamMode);
41532
41940
  }
41533
41941
  function resolveInlineStreamingMode(config2) {
@@ -41547,14 +41955,14 @@ function resolveInlineProgressPlaceholderEnabled(config2) {
41547
41955
  return true;
41548
41956
  if (config2.streaming === false)
41549
41957
  return false;
41550
- if (isRecord5(config2.streaming) && isRecord5(config2.streaming.progress))
41958
+ if (isRecord6(config2.streaming) && isRecord6(config2.streaming.progress))
41551
41959
  return true;
41552
41960
  return config2.streaming === undefined && config2.streamMode === undefined && config2.streamViaEditMessage !== true;
41553
41961
  }
41554
41962
  function resolveInlineBlockStreamingEnabled(config2) {
41555
41963
  const mode = resolveInlineStreamingMode(config2);
41556
- const streaming = isRecord5(config2.streaming) ? config2.streaming : null;
41557
- const block = streaming && isRecord5(streaming.block) ? streaming.block : null;
41964
+ const streaming = isRecord6(config2.streaming) ? config2.streaming : null;
41965
+ const block = streaming && isRecord6(streaming.block) ? streaming.block : null;
41558
41966
  if (typeof block?.enabled === "boolean")
41559
41967
  return block.enabled;
41560
41968
  if (typeof config2.blockStreaming === "boolean")
@@ -41778,7 +42186,7 @@ function normalizeReplyMarkupButtonsWith(raw, options) {
41778
42186
  continue;
41779
42187
  const row = [];
41780
42188
  for (const candidateButton of candidateRow) {
41781
- if (!isRecord5(candidateButton))
42189
+ if (!isRecord6(candidateButton))
41782
42190
  continue;
41783
42191
  const text = sanitizeInlineActionLabel(typeof candidateButton.text === "string" ? candidateButton.text : "");
41784
42192
  const callbackDataRaw = typeof candidateButton.callback_data === "string" ? candidateButton.callback_data.trim() : "";
@@ -41799,9 +42207,9 @@ function normalizeReplyMarkupButtonsWith(raw, options) {
41799
42207
  return rows;
41800
42208
  }
41801
42209
  function resolveInlineReplyActions(payload) {
41802
- const channelData = isRecord5(payload.channelData) ? payload.channelData : undefined;
41803
- const inlineData = channelData && isRecord5(channelData.inline) ? channelData.inline : undefined;
41804
- const telegramData = channelData && isRecord5(channelData.telegram) ? channelData.telegram : undefined;
42210
+ const channelData = isRecord6(payload.channelData) ? payload.channelData : undefined;
42211
+ const inlineData = channelData && isRecord6(channelData.inline) ? channelData.inline : undefined;
42212
+ const telegramData = channelData && isRecord6(channelData.telegram) ? channelData.telegram : undefined;
41805
42213
  let rawButtons = undefined;
41806
42214
  let hasExplicitButtons = false;
41807
42215
  let mapCallbackData;
@@ -42550,6 +42958,34 @@ ${entityLines.slice(-ATTACHMENT_CONTEXT_LIMIT).join(`
42550
42958
  hasBotMessage
42551
42959
  };
42552
42960
  }
42961
+ function buildInlineRecentHistoryLines(params) {
42962
+ if (params.maxLines <= 0)
42963
+ return [];
42964
+ return params.messages.slice().sort((a, b) => {
42965
+ const byDate = Number(a.date - b.date);
42966
+ if (byDate !== 0)
42967
+ return byDate;
42968
+ if (a.id === b.id)
42969
+ return 0;
42970
+ return a.id < b.id ? -1 : 1;
42971
+ }).map((message) => buildInlineHistoryEntryPayload({
42972
+ message,
42973
+ senderProfilesById: params.senderProfilesById,
42974
+ meId: params.meId
42975
+ })).map((entry) => entry.line ?? entry.attachmentLine ?? entry.entityLine).filter((line) => Boolean(line)).slice(-params.maxLines);
42976
+ }
42977
+ function buildInlineParticipantAddReadyText(botUsername) {
42978
+ const mention = botUsername ? `@${botUsername}` : "me";
42979
+ return `I'm here and ready. Mention ${mention} to ask me something.`;
42980
+ }
42981
+ function shouldSendInlineParticipantAddReadyMessage(participantDate, now = Date.now()) {
42982
+ if (participantDate == null)
42983
+ return true;
42984
+ const eventMs = Number(participantDate) * 1000;
42985
+ if (!Number.isFinite(eventMs) || eventMs <= 0)
42986
+ return true;
42987
+ return now - eventMs <= INLINE_PARTICIPANT_ADD_READY_MAX_EVENT_AGE_MS;
42988
+ }
42553
42989
  async function monitorInlineProvider(params) {
42554
42990
  const { cfg, account, runtime, abortSignal, log, statusSink } = params;
42555
42991
  const core3 = getInlineRuntime();
@@ -42559,6 +42995,7 @@ async function monitorInlineProvider(params) {
42559
42995
  const token = await resolveInlineToken(account);
42560
42996
  const stateDir = core3.state.resolveStateDir();
42561
42997
  const statePath = path4.join(stateDir, "channels", "inline", `${account.accountId}.json`);
42998
+ const hasExistingState = await stat(statePath).then(() => true).catch(() => false);
42562
42999
  await mkdir(path4.dirname(statePath), { recursive: true });
42563
43000
  let client = null;
42564
43001
  const pushDiagnostics = (patch) => {
@@ -42585,7 +43022,8 @@ async function monitorInlineProvider(params) {
42585
43022
  baseUrl: account.baseUrl,
42586
43023
  token,
42587
43024
  logger: sdkLog,
42588
- state: new JsonFileStateStore(statePath)
43025
+ state: new JsonFileStateStore(statePath),
43026
+ catchUpUserFromStart: hasExistingState
42589
43027
  });
42590
43028
  await client.connect(abortSignal);
42591
43029
  pushDiagnostics();
@@ -42687,7 +43125,7 @@ async function monitorInlineProvider(params) {
42687
43125
  const senderId = params2.senderId != null ? String(params2.senderId) : null;
42688
43126
  const dmPolicy = account.config.dmPolicy ?? "pairing";
42689
43127
  const defaultGroupPolicy = cfg.channels?.defaults?.groupPolicy;
42690
- const groupPolicy = account.config.groupPolicy ?? defaultGroupPolicy ?? "allowlist";
43128
+ const groupPolicy = account.config.groupPolicy ?? defaultGroupPolicy ?? INLINE_DEFAULT_GROUP_POLICY;
42691
43129
  if (isGroup) {
42692
43130
  if (groupPolicy === "disabled") {
42693
43131
  log?.info(`[${account.accountId}] inline: drop ${params2.eventKind} chat=${String(params2.chatId)} (groupPolicy=disabled)`);
@@ -42700,6 +43138,7 @@ async function monitorInlineProvider(params) {
42700
43138
  senderId
42701
43139
  });
42702
43140
  if (groupPolicy === "allowlist") {
43141
+ const shouldBypassGroupAccess = params2.eventKind === "participant.add";
42703
43142
  const groupAccess = resolveInlineGroupAccessPolicy({
42704
43143
  cfg,
42705
43144
  accountId: account.accountId,
@@ -42707,11 +43146,11 @@ async function monitorInlineProvider(params) {
42707
43146
  hasGroupAllowFrom: groupSenderAllowlist.raw.length > 0,
42708
43147
  groupPolicy
42709
43148
  });
42710
- if (groupAccess.allowlistEnabled && !groupAccess.allowed) {
43149
+ if (groupAccess.allowlistEnabled && !groupAccess.allowed && !shouldBypassGroupAccess) {
42711
43150
  log?.info(`[${account.accountId}] inline: drop ${params2.eventKind} chat=${String(effectiveChatId)} (groupPolicy=allowlist)`);
42712
43151
  return null;
42713
43152
  }
42714
- if (groupSenderAllowlist.raw.length > 0) {
43153
+ if (groupSenderAllowlist.raw.length > 0 && !shouldBypassGroupAccess) {
42715
43154
  if (senderId == null && !groupSenderAllowlist.raw.includes("*")) {
42716
43155
  log?.info(`[${account.accountId}] inline: drop ${params2.eventKind} chat=${String(effectiveChatId)} (sender unknown)`);
42717
43156
  return null;
@@ -42850,6 +43289,74 @@ async function monitorInlineProvider(params) {
42850
43289
  messageId: params2.messageId
42851
43290
  }), eventOptions);
42852
43291
  };
43292
+ const queueInlineParticipantAddSystemEvent = async (params2) => {
43293
+ if (params2.participant?.userId !== meId)
43294
+ return;
43295
+ const inboundAt = Date.now();
43296
+ statusSink?.({
43297
+ lastInboundAt: inboundAt,
43298
+ lastEventAt: inboundAt,
43299
+ ...createTransportActivityStatusPatch(inboundAt)
43300
+ });
43301
+ const ingress = await resolveInlineSystemEventContext({
43302
+ chatId: params2.chatId,
43303
+ senderId: null,
43304
+ eventKind: "participant.add"
43305
+ });
43306
+ if (!ingress)
43307
+ return;
43308
+ await hydrateChatParticipants(params2.chatId);
43309
+ const chatInfo = chatCache.get(params2.chatId);
43310
+ const isGroup = chatInfo?.kind !== "direct";
43311
+ const historyLimit = resolveHistoryLimit({
43312
+ cfg,
43313
+ isGroup,
43314
+ historyLimit: account.config.historyLimit,
43315
+ dmHistoryLimit: account.config.dmHistoryLimit
43316
+ });
43317
+ const recentMessages = historyLimit > 0 ? await loadChatHistoryMessages({
43318
+ client,
43319
+ chatId: params2.chatId,
43320
+ limit: Math.min(historyLimit, 10)
43321
+ }).catch((err) => {
43322
+ statusSink?.({ lastError: `getChatHistory (participant add) failed: ${String(err)}` });
43323
+ return null;
43324
+ }) : null;
43325
+ const recentLines = recentMessages ? buildInlineRecentHistoryLines({
43326
+ messages: recentMessages,
43327
+ senderProfilesById,
43328
+ meId,
43329
+ maxLines: Math.min(historyLimit, 10)
43330
+ }) : [];
43331
+ const contextKey = buildInlineParticipantAddContextKey({
43332
+ chatId: params2.chatId,
43333
+ userId: meId,
43334
+ ...params2.participant.date != null ? { participantDate: params2.participant.date } : {},
43335
+ ...params2.seq != null ? { seq: params2.seq } : {}
43336
+ });
43337
+ core3.system.enqueueSystemEvent(describeInlineParticipantAddSystemEvent({
43338
+ channelLabel: ingress.channelLabel,
43339
+ recentLines
43340
+ }), {
43341
+ sessionKey: ingress.sessionKey,
43342
+ contextKey,
43343
+ forceSenderIsOwnerFalse: true,
43344
+ trusted: false
43345
+ });
43346
+ if (shouldSendInlineParticipantAddReadyMessage(params2.participant.date)) {
43347
+ try {
43348
+ await client.sendMessage({
43349
+ chatId: params2.chatId,
43350
+ text: buildInlineParticipantAddReadyText(botUsername),
43351
+ parseMarkdown: account.config.parseMarkdown ?? true
43352
+ });
43353
+ statusSink?.({ lastOutboundAt: Date.now() });
43354
+ } catch (err) {
43355
+ runtime.error?.(`inline participant-add ready message failed: ${String(err)}`);
43356
+ statusSink?.({ lastError: `participant-add ready message failed: ${String(err)}` });
43357
+ }
43358
+ }
43359
+ };
42853
43360
  const shouldQueueInlineReactionSystemEvent = async (params2) => {
42854
43361
  const mode = account.config.reactionNotifications ?? "own";
42855
43362
  if (mode === "off")
@@ -42935,8 +43442,8 @@ async function monitorInlineProvider(params) {
42935
43442
  cfg,
42936
43443
  accountId: account.accountId,
42937
43444
  groupId: String(effectiveChatId),
42938
- defaultMinMessages: account.config.replyThreadAutoCreateMinMessages ?? inlineThreadDefaults.replyThreadAutoCreateMinMessages ?? DEFAULT_REPLY_THREAD_AUTO_CREATE_MIN_MESSAGES
42939
- }) : DEFAULT_REPLY_THREAD_AUTO_CREATE_MIN_MESSAGES;
43445
+ defaultMinMessages: account.config.replyThreadAutoCreateMinMessages ?? inlineThreadDefaults.replyThreadAutoCreateMinMessages ?? DEFAULT_REPLY_THREAD_AUTO_CREATE_MIN_MESSAGES2
43446
+ }) : DEFAULT_REPLY_THREAD_AUTO_CREATE_MIN_MESSAGES2;
42940
43447
  const replyThreadRequireExplicitMention = isGroup && replyThreadsEnabled ? resolveInlineGroupReplyThreadRequireExplicitMention({
42941
43448
  cfg,
42942
43449
  accountId: account.accountId,
@@ -42960,7 +43467,7 @@ async function monitorInlineProvider(params) {
42960
43467
  }
42961
43468
  const dmPolicy = account.config.dmPolicy ?? "pairing";
42962
43469
  const defaultGroupPolicy = cfg.channels?.defaults?.groupPolicy;
42963
- const groupPolicy = account.config.groupPolicy ?? defaultGroupPolicy ?? "allowlist";
43470
+ const groupPolicy = account.config.groupPolicy ?? defaultGroupPolicy ?? INLINE_DEFAULT_GROUP_POLICY;
42964
43471
  const configAllowFrom = await resolveInlineAllowlist({
42965
43472
  cfg,
42966
43473
  accountId: account.accountId,
@@ -43040,6 +43547,8 @@ async function monitorInlineProvider(params) {
43040
43547
  });
43041
43548
  const hasControlCommand = hasTextControlCommand || isRegisteredNativeCommand;
43042
43549
  const commandSource = hasControlCommand ? isRegisteredNativeCommand ? "native" : "text" : undefined;
43550
+ const normalizedCommandName = resolveInlineCommandNameFromBody(normalizedCommandBody);
43551
+ const hostInlinePluginCommandRegistered = normalizedCommandName ? hasInlineCommandSpec(listHostInlinePluginCommandSpecs(cfg), normalizedCommandName) : false;
43043
43552
  const allowTextCommands = core3.channel.commands.shouldHandleTextCommands({
43044
43553
  cfg,
43045
43554
  surface: CHANNEL_ID,
@@ -43063,6 +43572,7 @@ async function monitorInlineProvider(params) {
43063
43572
  commandAuthorized: commandGate.commandAuthorized
43064
43573
  });
43065
43574
  const shouldBlockControlCommand = allowTextCommands && hasControlCommand && !commandAuthorized;
43575
+ const nativeMentioned = typeof msg.mentioned === "boolean" ? msg.mentioned : false;
43066
43576
  if (isGroup) {
43067
43577
  if (groupPolicy === "disabled") {
43068
43578
  log?.info(`[${account.accountId}] inline: drop group chat=${String(chatId)} (groupPolicy=disabled)`);
@@ -43079,7 +43589,7 @@ async function monitorInlineProvider(params) {
43079
43589
  hasGroupAllowFrom: groupSenderAllowlist.raw.length > 0,
43080
43590
  groupPolicy
43081
43591
  });
43082
- if (groupAccess.allowlistEnabled && !groupAccess.allowed) {
43592
+ if (groupAccess.allowlistEnabled && !groupAccess.allowed && !nativeMentioned) {
43083
43593
  log?.info(`[${account.accountId}] inline: drop group chat=${String(effectiveChatId)} (groupPolicy=allowlist)`);
43084
43594
  await answerCallbackIfNeeded().catch((error51) => {
43085
43595
  runtime.error?.(`inline callback answer failed: ${String(error51)}`);
@@ -43151,7 +43661,6 @@ async function monitorInlineProvider(params) {
43151
43661
  return;
43152
43662
  }
43153
43663
  const mentionRegexes = core3.channel.mentions.buildMentionRegexes(cfg, route.agentId);
43154
- const nativeMentioned = typeof msg.mentioned === "boolean" ? msg.mentioned : false;
43155
43664
  const patternMentioned = mentionRegexes.length ? core3.channel.mentions.matchesMentionPatterns(rawBody, mentionRegexes) : false;
43156
43665
  const wasMentioned = nativeMentioned || patternMentioned;
43157
43666
  const messageTimestamp = Number(msg.date) * 1000;
@@ -43209,7 +43718,7 @@ async function monitorInlineProvider(params) {
43209
43718
  cfg,
43210
43719
  groupId: String(effectiveChatId),
43211
43720
  accountId: account.accountId,
43212
- requireMentionDefault: account.config.requireMention ?? false
43721
+ requireMentionDefault: account.config.requireMention ?? INLINE_DEFAULT_REQUIRE_MENTION
43213
43722
  }) : false;
43214
43723
  const mentionGate = resolveMentionGatingWithBypass({
43215
43724
  isGroup,
@@ -43254,6 +43763,74 @@ async function monitorInlineProvider(params) {
43254
43763
  return;
43255
43764
  }
43256
43765
  const parseMarkdown = account.config.parseMarkdown ?? true;
43766
+ if (isInlineThreadReplyCommandBody(normalizedCommandBody) && !hostInlinePluginCommandRegistered) {
43767
+ const configRuntime = core3.config;
43768
+ if (typeof configRuntime?.current !== "function" || typeof configRuntime.mutateConfigFile !== "function") {
43769
+ runtime.error?.("inline /threadreply fallback unavailable: runtime config API missing");
43770
+ } else {
43771
+ const result = await handleInlineThreadReplyCommandWithConfigRuntime(configRuntime, {
43772
+ senderId,
43773
+ channel: CHANNEL_ID,
43774
+ channelId: CHANNEL_ID,
43775
+ isAuthorizedSender: commandAuthorized,
43776
+ senderIsOwner: commandAuthorized,
43777
+ sessionKey: inboundSessionKey,
43778
+ args: parseInlineCommandArgs(normalizedCommandBody),
43779
+ commandBody: normalizedCommandBody,
43780
+ config: cfg,
43781
+ from: isGroup ? `inline:chat:${String(effectiveChatId)}` : `inline:${senderId}`,
43782
+ to: `inline:${String(effectiveChatId)}`,
43783
+ accountId: account.accountId,
43784
+ ...replyThreadContext ? {
43785
+ messageThreadId: String(replyThreadContext.childChatId),
43786
+ threadParentId: String(replyThreadContext.parentChatId)
43787
+ } : {},
43788
+ requestConversationBinding: async () => ({ ok: false }),
43789
+ detachConversationBinding: async () => ({ removed: false }),
43790
+ getCurrentConversationBinding: async () => null
43791
+ });
43792
+ const resultRecord = result;
43793
+ const actions = resolveInlineReplyActions(resultRecord);
43794
+ const text = typeof result.text === "string" ? sanitizeInlineDeliveryText(result.text) : "";
43795
+ if (text || actions) {
43796
+ let delivered = false;
43797
+ if (shouldEditCallbackTargetInPlace && callbackActionEvent) {
43798
+ try {
43799
+ const editResult = await client.invokeRaw(Method.EDIT_MESSAGE, {
43800
+ oneofKind: "editMessage",
43801
+ editMessage: {
43802
+ messageId: callbackActionEvent.targetMessageId,
43803
+ peerId: buildChatPeer3(chatId),
43804
+ text,
43805
+ ...actions ? { actions } : {},
43806
+ parseMarkdown
43807
+ }
43808
+ });
43809
+ if (editResult.oneofKind !== "editMessage") {
43810
+ throw new Error(`inline /threadreply edit: expected editMessage result, got ${String(editResult.oneofKind)}`);
43811
+ }
43812
+ delivered = true;
43813
+ } catch (error51) {
43814
+ runtime.error?.(`inline /threadreply edit failed; falling back to send (${String(error51)})`);
43815
+ }
43816
+ }
43817
+ if (!delivered) {
43818
+ const sent = await client.sendMessage({
43819
+ chatId,
43820
+ text,
43821
+ ...actions ? { actions } : {},
43822
+ parseMarkdown
43823
+ });
43824
+ rememberSentBotMessage({ chatId, messageId: sent.messageId, replyThreadContext });
43825
+ }
43826
+ statusSink?.({ lastOutboundAt: Date.now() });
43827
+ }
43828
+ await answerCallbackIfNeeded().catch((error51) => {
43829
+ runtime.error?.(`inline callback answer failed: ${String(error51)}`);
43830
+ });
43831
+ return;
43832
+ }
43833
+ }
43257
43834
  const commandsPageCallback = callbackActionEvent ? parseInlineCommandsPageCallback(callbackDataToUtf8(callbackActionEvent.data)) : null;
43258
43835
  if (shouldEditCallbackTargetInPlace && callbackActionEvent && commandsPageCallback) {
43259
43836
  if (commandsPageCallback.page === "noop")
@@ -44418,6 +44995,19 @@ Attachment: ${mediaUrl}` : `Attachment: ${mediaUrl}`;
44418
44995
  });
44419
44996
  continue;
44420
44997
  }
44998
+ if (rawEvent["kind"] === "chat.participant.add") {
44999
+ const eventChatId = rawEvent["chatId"];
45000
+ if (!eventChatId)
45001
+ continue;
45002
+ const participant = rawEvent["participant"];
45003
+ const seq = rawEvent["seq"];
45004
+ await queueInlineParticipantAddSystemEvent({
45005
+ chatId: eventChatId,
45006
+ ...participant ? { participant } : {},
45007
+ ...seq != null ? { seq } : {}
45008
+ });
45009
+ continue;
45010
+ }
44421
45011
  if (rawEvent["kind"] === "message.action.invoke") {
44422
45012
  const actorUserId = rawEvent["actorUserId"];
44423
45013
  const interactionId = rawEvent["interactionId"];
@@ -44482,7 +45072,7 @@ Attachment: ${mediaUrl}` : `Attachment: ${mediaUrl}`;
44482
45072
  }
44483
45073
 
44484
45074
  // src/inline/doctor.ts
44485
- function isRecord6(value) {
45075
+ function isRecord7(value) {
44486
45076
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
44487
45077
  }
44488
45078
  function readInherited(account, parent, key) {
@@ -44493,18 +45083,18 @@ function hasEntries(value) {
44493
45083
  }
44494
45084
  function hasConfiguredGroups(account, parent) {
44495
45085
  const groups = readInherited(account, parent, "groups");
44496
- return isRecord6(groups) && Object.keys(groups).length > 0;
45086
+ return isRecord7(groups) && Object.keys(groups).length > 0;
44497
45087
  }
44498
45088
  function hasGroupScopedSenders(groups) {
44499
- if (!isRecord6(groups))
45089
+ if (!isRecord7(groups))
44500
45090
  return false;
44501
- return Object.values(groups).some((group) => isRecord6(group) && hasEntries(group.allowFrom));
45091
+ return Object.values(groups).some((group) => isRecord7(group) && hasEntries(group.allowFrom));
44502
45092
  }
44503
45093
  function hasGroupSenders(account, parent) {
44504
45094
  return hasEntries(readInherited(account, parent, "groupAllowFrom")) || hasGroupScopedSenders(readInherited(account, parent, "groups"));
44505
45095
  }
44506
45096
  function getGroupPolicy(account, parent) {
44507
- return String(readInherited(account, parent, "groupPolicy") ?? "allowlist");
45097
+ return String(readInherited(account, parent, "groupPolicy") ?? INLINE_DEFAULT_GROUP_POLICY);
44508
45098
  }
44509
45099
  function collectInlineEmptyAllowlistWarnings(params) {
44510
45100
  if (params.channelName !== "inline")
@@ -44661,7 +45251,8 @@ var INLINE_USER_ID_HELP_LINES = [
44661
45251
  "Docs: https://inline.chat/docs/openclaw"
44662
45252
  ];
44663
45253
  var INLINE_GROUP_HELP_LINES = [
44664
- "Allowlist Inline group chats by numeric chat id.",
45254
+ "Inline groups are open by default and require a bot mention by default.",
45255
+ "Optionally allowlist Inline group chats by numeric chat id.",
44665
45256
  "Accepted forms: 123456789, chat:123456789, inline:123456789, *.",
44666
45257
  "Use * for every group chat; the setup keeps requireMention=true for broad group access.",
44667
45258
  "Use /whoami in a group and copy the Chat line to get the Inline chat id.",
@@ -44808,7 +45399,7 @@ function buildInlineDmAccessWarningLines(accountId) {
44808
45399
  function buildInlineGroupAccessWarningLines(params) {
44809
45400
  const resolved = resolveInlineAccount({ cfg: params.cfg, accountId: params.accountId });
44810
45401
  const configBase = formatInlineConfigBase(params.accountId);
44811
- const policy = resolved.config.groupPolicy ?? "allowlist";
45402
+ const policy = resolved.config.groupPolicy ?? INLINE_DEFAULT_GROUP_POLICY;
44812
45403
  const groups = resolved.config.groups ?? {};
44813
45404
  const hasGroups = Object.keys(groups).length > 0;
44814
45405
  const hasGroupAllowFrom = (resolved.config.groupAllowFrom ?? []).some((entry) => String(entry).trim());
@@ -44821,7 +45412,8 @@ function buildInlineGroupAccessWarningLines(params) {
44821
45412
  ];
44822
45413
  }
44823
45414
  const wildcard = groups["*"];
44824
- if (policy === "open" && wildcard?.requireMention !== true) {
45415
+ const requireMention = wildcard?.requireMention ?? resolved.config.requireMention ?? INLINE_DEFAULT_REQUIRE_MENTION;
45416
+ if (policy === "open" && requireMention !== true) {
44825
45417
  return [
44826
45418
  "Inline groups are open to every group chat without a default mention requirement.",
44827
45419
  "For safer broad group access, require bot mentions or switch to an explicit group allowlist:",
@@ -45085,11 +45677,11 @@ async function probeInlineAccount(account, timeoutMs) {
45085
45677
  }
45086
45678
 
45087
45679
  // src/inline/status-issues.ts
45088
- import { asString, isRecord as isRecord7 } from "openclaw/plugin-sdk/status-helpers";
45680
+ import { asString, isRecord as isRecord8 } from "openclaw/plugin-sdk/status-helpers";
45089
45681
  var RECENT_RUNTIME_ISSUE_MS = 30 * 60 * 1000;
45090
45682
  var INLINE_CONNECT_GRACE_MS = 120 * 1000;
45091
45683
  function readInlineProbeSummary(value) {
45092
- if (!isRecord7(value)) {
45684
+ if (!isRecord8(value)) {
45093
45685
  return {};
45094
45686
  }
45095
45687
  const summary = {};
@@ -45106,12 +45698,12 @@ function looksLikeAuthError(text) {
45106
45698
  return /(401|403|unauth|forbidden|invalid token|token invalid|unauthorized)/i.test(text);
45107
45699
  }
45108
45700
  function readInlineDiagnosticsSummary(value) {
45109
- if (!isRecord7(value)) {
45701
+ if (!isRecord8(value)) {
45110
45702
  return {};
45111
45703
  }
45112
- const protocolValue = isRecord7(value.protocol) ? value.protocol : undefined;
45113
- const transportValue = (protocolValue && isRecord7(protocolValue.transport) ? protocolValue.transport : undefined) ?? (isRecord7(value.transport) ? value.transport : undefined);
45114
- const pingValue = protocolValue && isRecord7(protocolValue.ping) ? protocolValue.ping : undefined;
45704
+ const protocolValue = isRecord8(value.protocol) ? value.protocol : undefined;
45705
+ const transportValue = (protocolValue && isRecord8(protocolValue.transport) ? protocolValue.transport : undefined) ?? (isRecord8(value.transport) ? value.transport : undefined);
45706
+ const pingValue = protocolValue && isRecord8(protocolValue.ping) ? protocolValue.ping : undefined;
45115
45707
  return {
45116
45708
  ...protocolValue ? {
45117
45709
  protocol: {
@@ -45143,7 +45735,7 @@ function asFiniteNumber(value) {
45143
45735
  function collectInlineStatusIssues(accounts) {
45144
45736
  const issues = [];
45145
45737
  for (const entry of accounts) {
45146
- if (!isRecord7(entry)) {
45738
+ if (!isRecord8(entry)) {
45147
45739
  continue;
45148
45740
  }
45149
45741
  const accountId = asString(entry.accountId);
@@ -45279,6 +45871,14 @@ function hasInlineCommandAllowFrom(cfg) {
45279
45871
  const byProvider = allowFrom;
45280
45872
  return hasEntries2(byProvider.inline) || hasEntries2(byProvider["*"]);
45281
45873
  }
45874
+ function groupDefaultRequiresMention(account) {
45875
+ const groups = account.config.groups;
45876
+ const wildcard = groups && typeof groups === "object" && !Array.isArray(groups) ? groups["*"] : undefined;
45877
+ const wildcardRequireMention = wildcard && typeof wildcard === "object" && !Array.isArray(wildcard) ? wildcard.requireMention : undefined;
45878
+ if (typeof wildcardRequireMention === "boolean")
45879
+ return wildcardRequireMention;
45880
+ return account.config.requireMention ?? INLINE_DEFAULT_REQUIRE_MENTION;
45881
+ }
45282
45882
  function collectInvalidAllowFromEntries(params) {
45283
45883
  if (!Array.isArray(params.entries))
45284
45884
  return;
@@ -45335,7 +45935,7 @@ var inlineSecurityAdapter = {
45335
45935
  },
45336
45936
  collectWarnings: ({ account, cfg }) => {
45337
45937
  const defaultGroupPolicy = cfg.channels?.defaults?.groupPolicy;
45338
- const groupPolicy = account.config.groupPolicy ?? defaultGroupPolicy ?? "allowlist";
45938
+ const groupPolicy = account.config.groupPolicy ?? defaultGroupPolicy ?? INLINE_DEFAULT_GROUP_POLICY;
45339
45939
  const groupRulesConfigured = Boolean(account.config.groups) && Object.keys(account.config.groups ?? {}).length > 0;
45340
45940
  const groupSendersConfigured = hasGroupSenderEntries(account);
45341
45941
  if (groupPolicy === "allowlist" && !groupRulesConfigured && !groupSendersConfigured) {
@@ -45346,14 +45946,12 @@ var inlineSecurityAdapter = {
45346
45946
  if (groupPolicy !== "open") {
45347
45947
  return [];
45348
45948
  }
45349
- if (groupRulesConfigured) {
45949
+ if (!groupDefaultRequiresMention(account)) {
45350
45950
  return [
45351
- '- Inline groups: groupPolicy="open" allows any group message to reach the agent (subject to mention policy). Set channels.inline.groupPolicy="allowlist" for stricter routing.'
45951
+ '- Inline groups: groupPolicy="open" allows every group message to trigger replies because requireMention is disabled. Set channels.inline.requireMention=true or channels.inline.groups."*".requireMention=true.'
45352
45952
  ];
45353
45953
  }
45354
- return [
45355
- '- Inline groups: groupPolicy="open" with no group rules means every group can trigger replies. Consider channels.inline.groupPolicy="allowlist".'
45356
- ];
45954
+ return [];
45357
45955
  },
45358
45956
  collectAuditFindings: ({ account, cfg }) => {
45359
45957
  const findings = [];
@@ -45378,7 +45976,7 @@ var inlineSecurityAdapter = {
45378
45976
  });
45379
45977
  appendInvalidReactionAllowlistFinding(findings, invalidReactionAllowlistEntries);
45380
45978
  const defaultGroupPolicy = cfg.channels?.defaults?.groupPolicy;
45381
- const groupPolicy = account.config.groupPolicy ?? defaultGroupPolicy ?? "allowlist";
45979
+ const groupPolicy = account.config.groupPolicy ?? defaultGroupPolicy ?? INLINE_DEFAULT_GROUP_POLICY;
45382
45980
  const groupsConfigured = Boolean(account.config.groups) && Object.keys(account.config.groups ?? {}).length > 0;
45383
45981
  const groupSendersConfigured = hasGroupSenderEntries(account);
45384
45982
  const groupAccessEnabled = groupPolicy === "open" || groupPolicy === "allowlist" && (groupsConfigured || groupSendersConfigured);
@@ -46711,7 +47309,7 @@ var inlineChannelPlugin = {
46711
47309
  cfg,
46712
47310
  groupId,
46713
47311
  accountId,
46714
- requireMentionDefault: resolved.config.requireMention ?? false
47312
+ requireMentionDefault: resolved.config.requireMention ?? INLINE_DEFAULT_REQUIRE_MENTION
46715
47313
  });
46716
47314
  },
46717
47315
  resolveToolPolicy: ({ cfg, accountId, groupId, senderId, senderName, senderUsername, senderE164 }) => resolveInlineGroupToolPolicy({
@@ -47135,5 +47733,5 @@ export {
47135
47733
  inlineChannelPlugin
47136
47734
  };
47137
47735
 
47138
- //# debugId=C3CE4C015D5193F764756E2164756E21
47736
+ //# debugId=93A450B5B900350964756E2164756E21
47139
47737
  //# sourceMappingURL=channel-plugin-api.js.map