@inline-openclaw/inline 0.0.39 → 0.0.41

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.
@@ -5589,7 +5589,7 @@ function hasInlineConfiguredState(params) {
5589
5589
 
5590
5590
  // src/inline/channel.ts
5591
5591
  import { unlink } from "node:fs/promises";
5592
- import path4 from "node:path";
5592
+ import path5 from "node:path";
5593
5593
  import {
5594
5594
  buildChannelOutboundSessionRoute,
5595
5595
  buildThreadAwareOutboundSessionRoute
@@ -5630,6 +5630,8 @@ var MessageEntity_Type;
5630
5630
  MessageEntity_Type2[MessageEntity_Type2["CODE"] = 8] = "CODE";
5631
5631
  MessageEntity_Type2[MessageEntity_Type2["PRE"] = 9] = "PRE";
5632
5632
  MessageEntity_Type2[MessageEntity_Type2["PHONE_NUMBER"] = 10] = "PHONE_NUMBER";
5633
+ MessageEntity_Type2[MessageEntity_Type2["THREAD"] = 11] = "THREAD";
5634
+ MessageEntity_Type2[MessageEntity_Type2["THREAD_TITLE"] = 12] = "THREAD_TITLE";
5633
5635
  })(MessageEntity_Type || (MessageEntity_Type = {}));
5634
5636
  var Member_Role;
5635
5637
  (function(Member_Role2) {
@@ -7760,7 +7762,9 @@ class MessageEntity$Type extends import_runtime4.MessageType {
7760
7762
  { no: 3, name: "length", kind: "scalar", T: 3, L: 0 },
7761
7763
  { no: 4, name: "mention", kind: "message", oneof: "entity", T: () => MessageEntity_MessageEntityMention },
7762
7764
  { no: 5, name: "text_url", kind: "message", oneof: "entity", T: () => MessageEntity_MessageEntityTextUrl },
7763
- { no: 6, name: "pre", kind: "message", oneof: "entity", T: () => MessageEntity_MessageEntityPre }
7765
+ { no: 6, name: "pre", kind: "message", oneof: "entity", T: () => MessageEntity_MessageEntityPre },
7766
+ { no: 7, name: "thread", kind: "message", oneof: "entity", T: () => MessageEntity_MessageEntityThread },
7767
+ { no: 8, name: "thread_title", kind: "message", oneof: "entity", T: () => MessageEntity_MessageEntityThreadTitle }
7764
7768
  ]);
7765
7769
  }
7766
7770
  create(value) {
@@ -7805,6 +7809,18 @@ class MessageEntity$Type extends import_runtime4.MessageType {
7805
7809
  pre: MessageEntity_MessageEntityPre.internalBinaryRead(reader, reader.uint32(), options, message.entity.pre)
7806
7810
  };
7807
7811
  break;
7812
+ case 7:
7813
+ message.entity = {
7814
+ oneofKind: "thread",
7815
+ thread: MessageEntity_MessageEntityThread.internalBinaryRead(reader, reader.uint32(), options, message.entity.thread)
7816
+ };
7817
+ break;
7818
+ case 8:
7819
+ message.entity = {
7820
+ oneofKind: "threadTitle",
7821
+ threadTitle: MessageEntity_MessageEntityThreadTitle.internalBinaryRead(reader, reader.uint32(), options, message.entity.threadTitle)
7822
+ };
7823
+ break;
7808
7824
  default:
7809
7825
  let u = options.readUnknownField;
7810
7826
  if (u === "throw")
@@ -7829,6 +7845,10 @@ class MessageEntity$Type extends import_runtime4.MessageType {
7829
7845
  MessageEntity_MessageEntityTextUrl.internalBinaryWrite(message.entity.textUrl, writer.tag(5, import_runtime.WireType.LengthDelimited).fork(), options).join();
7830
7846
  if (message.entity.oneofKind === "pre")
7831
7847
  MessageEntity_MessageEntityPre.internalBinaryWrite(message.entity.pre, writer.tag(6, import_runtime.WireType.LengthDelimited).fork(), options).join();
7848
+ if (message.entity.oneofKind === "thread")
7849
+ MessageEntity_MessageEntityThread.internalBinaryWrite(message.entity.thread, writer.tag(7, import_runtime.WireType.LengthDelimited).fork(), options).join();
7850
+ if (message.entity.oneofKind === "threadTitle")
7851
+ MessageEntity_MessageEntityThreadTitle.internalBinaryWrite(message.entity.threadTitle, writer.tag(8, import_runtime.WireType.LengthDelimited).fork(), options).join();
7832
7852
  let u = options.writeUnknownFields;
7833
7853
  if (u !== false)
7834
7854
  (u == true ? import_runtime2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
@@ -7966,6 +7986,99 @@ class MessageEntity_MessageEntityPre$Type extends import_runtime4.MessageType {
7966
7986
  }
7967
7987
  var MessageEntity_MessageEntityPre = new MessageEntity_MessageEntityPre$Type;
7968
7988
 
7989
+ class MessageEntity_MessageEntityThread$Type extends import_runtime4.MessageType {
7990
+ constructor() {
7991
+ super("MessageEntity.MessageEntityThread", [
7992
+ { no: 1, name: "chat_id", kind: "scalar", T: 3, L: 0 }
7993
+ ]);
7994
+ }
7995
+ create(value) {
7996
+ const message = globalThis.Object.create(this.messagePrototype);
7997
+ message.chatId = 0n;
7998
+ if (value !== undefined)
7999
+ import_runtime3.reflectionMergePartial(this, message, value);
8000
+ return message;
8001
+ }
8002
+ internalBinaryRead(reader, length, options, target) {
8003
+ let message = target ?? this.create(), end = reader.pos + length;
8004
+ while (reader.pos < end) {
8005
+ let [fieldNo, wireType] = reader.tag();
8006
+ switch (fieldNo) {
8007
+ case 1:
8008
+ message.chatId = reader.int64().toBigInt();
8009
+ break;
8010
+ default:
8011
+ let u = options.readUnknownField;
8012
+ if (u === "throw")
8013
+ throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
8014
+ let d = reader.skip(wireType);
8015
+ if (u !== false)
8016
+ (u === true ? import_runtime2.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
8017
+ }
8018
+ }
8019
+ return message;
8020
+ }
8021
+ internalBinaryWrite(message, writer, options) {
8022
+ if (message.chatId !== 0n)
8023
+ writer.tag(1, import_runtime.WireType.Varint).int64(message.chatId);
8024
+ let u = options.writeUnknownFields;
8025
+ if (u !== false)
8026
+ (u == true ? import_runtime2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
8027
+ return writer;
8028
+ }
8029
+ }
8030
+ var MessageEntity_MessageEntityThread = new MessageEntity_MessageEntityThread$Type;
8031
+
8032
+ class MessageEntity_MessageEntityThreadTitle$Type extends import_runtime4.MessageType {
8033
+ constructor() {
8034
+ super("MessageEntity.MessageEntityThreadTitle", [
8035
+ { no: 1, name: "space_id", kind: "scalar", T: 3, L: 0 },
8036
+ { no: 2, name: "title", kind: "scalar", T: 9 }
8037
+ ]);
8038
+ }
8039
+ create(value) {
8040
+ const message = globalThis.Object.create(this.messagePrototype);
8041
+ message.spaceId = 0n;
8042
+ message.title = "";
8043
+ if (value !== undefined)
8044
+ import_runtime3.reflectionMergePartial(this, message, value);
8045
+ return message;
8046
+ }
8047
+ internalBinaryRead(reader, length, options, target) {
8048
+ let message = target ?? this.create(), end = reader.pos + length;
8049
+ while (reader.pos < end) {
8050
+ let [fieldNo, wireType] = reader.tag();
8051
+ switch (fieldNo) {
8052
+ case 1:
8053
+ message.spaceId = reader.int64().toBigInt();
8054
+ break;
8055
+ case 2:
8056
+ message.title = reader.string();
8057
+ break;
8058
+ default:
8059
+ let u = options.readUnknownField;
8060
+ if (u === "throw")
8061
+ throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
8062
+ let d = reader.skip(wireType);
8063
+ if (u !== false)
8064
+ (u === true ? import_runtime2.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
8065
+ }
8066
+ }
8067
+ return message;
8068
+ }
8069
+ internalBinaryWrite(message, writer, options) {
8070
+ if (message.spaceId !== 0n)
8071
+ writer.tag(1, import_runtime.WireType.Varint).int64(message.spaceId);
8072
+ if (message.title !== "")
8073
+ writer.tag(2, import_runtime.WireType.LengthDelimited).string(message.title);
8074
+ let u = options.writeUnknownFields;
8075
+ if (u !== false)
8076
+ (u == true ? import_runtime2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
8077
+ return writer;
8078
+ }
8079
+ }
8080
+ var MessageEntity_MessageEntityThreadTitle = new MessageEntity_MessageEntityThreadTitle$Type;
8081
+
7969
8082
  class MessageReactions$Type extends import_runtime4.MessageType {
7970
8083
  constructor() {
7971
8084
  super("MessageReactions", [
@@ -36567,27 +36680,6 @@ var GET_CHAT_METHOD = typeof Method.GET_CHAT === "number" && Number.isInteger(Me
36567
36680
  var GET_CHAT_HISTORY_METHOD = typeof Method.GET_CHAT_HISTORY === "number" && Number.isInteger(Method.GET_CHAT_HISTORY) && Method.GET_CHAT_HISTORY > 0 ? Method.GET_CHAT_HISTORY : 5;
36568
36681
  var GET_MESSAGES_METHOD = typeof Method.GET_MESSAGES === "number" && Number.isInteger(Method.GET_MESSAGES) && Method.GET_MESSAGES > 0 ? Method.GET_MESSAGES : 38;
36569
36682
  var CREATE_SUBTHREAD_METHOD = typeof Method.CREATE_SUBTHREAD === "number" && Number.isInteger(Method.CREATE_SUBTHREAD) && Method.CREATE_SUBTHREAD > 0 ? Method.CREATE_SUBTHREAD : 42;
36570
- function isPlacementMode(raw) {
36571
- return raw === "thread" || raw === "main";
36572
- }
36573
- function hasReplyThreadConfig(config2) {
36574
- if (isPlacementMode(config2.replyThreadMode))
36575
- return true;
36576
- if (typeof config2.replyThreadAutoCreateMinMessages === "number")
36577
- return true;
36578
- if (typeof config2.replyThreadRequireExplicitMention === "boolean")
36579
- return true;
36580
- if (typeof config2.replyThreadParentHistoryLimit === "number")
36581
- return true;
36582
- if (!config2.groups || typeof config2.groups !== "object" || Array.isArray(config2.groups))
36583
- return false;
36584
- return Object.values(config2.groups).some((group) => {
36585
- if (!group || typeof group !== "object" || Array.isArray(group))
36586
- return false;
36587
- const groupConfig = group;
36588
- return isPlacementMode(groupConfig.replyThreadMode) || typeof groupConfig.replyThreadAutoCreateMinMessages === "number" || typeof groupConfig.replyThreadRequireExplicitMention === "boolean" || typeof groupConfig.replyThreadParentHistoryLimit === "number";
36589
- });
36590
- }
36591
36683
  function buildChatPeer(chatId) {
36592
36684
  return {
36593
36685
  type: {
@@ -36597,21 +36689,14 @@ function buildChatPeer(chatId) {
36597
36689
  };
36598
36690
  }
36599
36691
  function getInlineReplyThreadsCapabilityConfig(params) {
36600
- const account = resolveInlineAccount({
36601
- cfg: params.cfg,
36602
- accountId: params.accountId ?? null
36603
- });
36604
- return {
36605
- replyThreads: account.config.capabilities?.replyThreads === true || hasReplyThreadConfig(account.config)
36606
- };
36692
+ return { replyThreads: true };
36607
36693
  }
36608
36694
  function isInlineReplyThreadsEnabled(params) {
36609
36695
  return getInlineReplyThreadsCapabilityConfig(params).replyThreads;
36610
36696
  }
36611
36697
  function resolveInlineReplyThreadChatId(params) {
36612
- if (!isInlineReplyThreadsEnabled({ cfg: params.cfg, accountId: params.accountId ?? null })) {
36613
- return params.parentChatId;
36614
- }
36698
+ params.cfg;
36699
+ params.accountId;
36615
36700
  if (params.parentChatId == null) {
36616
36701
  return null;
36617
36702
  }
@@ -36726,7 +36811,7 @@ function looksLikeInlineTargetId(raw, normalizedInput) {
36726
36811
 
36727
36812
  // src/inline/monitor.ts
36728
36813
  import { mkdir } from "node:fs/promises";
36729
- import path3 from "node:path";
36814
+ import path4 from "node:path";
36730
36815
  import {
36731
36816
  buildCommandTextFromArgs,
36732
36817
  findCommandByNativeName,
@@ -37529,6 +37614,315 @@ function sanitizeInlineOutgoingText(text) {
37529
37614
  });
37530
37615
  }
37531
37616
 
37617
+ // src/inline/thread-routes.ts
37618
+ import path2 from "node:path";
37619
+ import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
37620
+ import { readJsonFileWithFallback, writeJsonFileAtomically } from "openclaw/plugin-sdk/json-store";
37621
+ var TTL_MS = 7 * 24 * 60 * 60 * 1000;
37622
+ var MAX_ENTRIES = 5000;
37623
+ var PERSISTENT_MAX_ENTRIES = 2000;
37624
+ var STORE_VERSION = 1;
37625
+ var PERSISTENT_NAMESPACE = "inline.reply-thread-routes";
37626
+ var INLINE_REPLY_THREAD_ROUTE_KEY = Symbol.for("openclaw.inlineReplyThreadRoutes");
37627
+ var DEFAULT_AGENT_KEY = "__any__";
37628
+ var DEFAULT_STORE_KEY = "__default__";
37629
+ var routeState;
37630
+ var persistentStore;
37631
+ var persistentStoreDisabled = false;
37632
+ function getRouteState() {
37633
+ if (routeState)
37634
+ return routeState;
37635
+ const globalStore = globalThis;
37636
+ const existing = globalStore[INLINE_REPLY_THREAD_ROUTE_KEY];
37637
+ routeState = existing ?? {
37638
+ memory: new Map,
37639
+ fileWrites: new Map
37640
+ };
37641
+ globalStore[INLINE_REPLY_THREAD_ROUTE_KEY] = routeState;
37642
+ return routeState;
37643
+ }
37644
+ function normalizePositiveId(raw) {
37645
+ if (raw == null)
37646
+ return;
37647
+ if (typeof raw === "bigint")
37648
+ return raw >= 0n ? String(raw) : undefined;
37649
+ if (typeof raw === "number") {
37650
+ return Number.isInteger(raw) && raw >= 0 ? String(raw) : undefined;
37651
+ }
37652
+ const trimmed = raw.trim();
37653
+ if (!/^\d+$/.test(trimmed))
37654
+ return;
37655
+ return trimmed;
37656
+ }
37657
+ function normalizeOptionalText(raw) {
37658
+ const trimmed = raw?.trim();
37659
+ return trimmed || undefined;
37660
+ }
37661
+ function safePathSegment(value) {
37662
+ return value.trim().replace(/[^a-z0-9._-]+/gi, "_").slice(0, 80) || "global";
37663
+ }
37664
+ function isRecord3(value) {
37665
+ return typeof value === "object" && value !== null && !Array.isArray(value);
37666
+ }
37667
+ function readString(record2, key) {
37668
+ const value = record2[key];
37669
+ return typeof value === "string" && value.trim() ? value.trim() : undefined;
37670
+ }
37671
+ function readTimestamp(record2, key, fallback) {
37672
+ const value = record2[key];
37673
+ return typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.floor(value)) : fallback;
37674
+ }
37675
+ function normalizeRecord(value) {
37676
+ if (!isRecord3(value))
37677
+ return null;
37678
+ const accountId = readString(value, "accountId");
37679
+ const parentChatId = normalizePositiveId(readString(value, "parentChatId"));
37680
+ const threadId = normalizePositiveId(readString(value, "threadId"));
37681
+ if (!accountId || !parentChatId || !threadId)
37682
+ return null;
37683
+ const now = Date.now();
37684
+ const parentMessageId = normalizePositiveId(readString(value, "parentMessageId"));
37685
+ const title = normalizeOptionalText(readString(value, "title"));
37686
+ const threadLabel = normalizeOptionalText(readString(value, "threadLabel"));
37687
+ const agentId = normalizeOptionalText(readString(value, "agentId"));
37688
+ return {
37689
+ accountId,
37690
+ parentChatId,
37691
+ threadId,
37692
+ createdAt: readTimestamp(value, "createdAt", now),
37693
+ updatedAt: readTimestamp(value, "updatedAt", now),
37694
+ ...parentMessageId ? { parentMessageId } : {},
37695
+ ...title ? { title } : {},
37696
+ ...threadLabel ? { threadLabel } : {},
37697
+ ...agentId ? { agentId } : {}
37698
+ };
37699
+ }
37700
+ function isExpired(record2, now) {
37701
+ return now - record2.updatedAt > TTL_MS;
37702
+ }
37703
+ function reportRouteStateError(error51) {
37704
+ try {
37705
+ getOptionalInlineRuntime()?.logging.getChildLogger({ plugin: "inline", feature: "reply-thread-route-state" }).warn("Inline reply-thread route state failed", { error: String(error51) });
37706
+ } catch {}
37707
+ }
37708
+ function disablePersistentStore(error51) {
37709
+ persistentStoreDisabled = true;
37710
+ persistentStore = undefined;
37711
+ if (!String(error51).includes("openKeyedStore is only available")) {
37712
+ reportRouteStateError(error51);
37713
+ }
37714
+ }
37715
+ function getPersistentStore() {
37716
+ if (persistentStoreDisabled)
37717
+ return;
37718
+ if (persistentStore)
37719
+ return persistentStore;
37720
+ const openKeyedStore = getOptionalInlineRuntime()?.state?.openKeyedStore;
37721
+ if (typeof openKeyedStore !== "function")
37722
+ return;
37723
+ try {
37724
+ persistentStore = openKeyedStore({
37725
+ namespace: PERSISTENT_NAMESPACE,
37726
+ maxEntries: PERSISTENT_MAX_ENTRIES,
37727
+ defaultTtlMs: TTL_MS
37728
+ });
37729
+ return persistentStore;
37730
+ } catch (error51) {
37731
+ disablePersistentStore(error51);
37732
+ return;
37733
+ }
37734
+ }
37735
+ function resolveRoutesPath(accountId) {
37736
+ const resolveStateDir = getOptionalInlineRuntime()?.state?.resolveStateDir;
37737
+ if (typeof resolveStateDir !== "function")
37738
+ return;
37739
+ return path2.join(resolveStateDir(), "inline", "reply-thread-routes", `${safePathSegment(accountId)}.json`);
37740
+ }
37741
+ function activeKey(accountId, parentChatId, agentId) {
37742
+ return `${accountId}:parent:${parentChatId}:agent:${agentId || DEFAULT_AGENT_KEY}`;
37743
+ }
37744
+ function messageKey(accountId, parentChatId, parentMessageId) {
37745
+ return `${accountId}:parent:${parentChatId}:message:${parentMessageId}`;
37746
+ }
37747
+ function keysForRecord(record2) {
37748
+ const keys = new Set;
37749
+ if (record2.parentMessageId) {
37750
+ keys.add(messageKey(record2.accountId, record2.parentChatId, record2.parentMessageId));
37751
+ }
37752
+ if (record2.agentId) {
37753
+ keys.add(activeKey(record2.accountId, record2.parentChatId, record2.agentId));
37754
+ }
37755
+ keys.add(activeKey(record2.accountId, record2.parentChatId));
37756
+ return [...keys];
37757
+ }
37758
+ function keysForLookup(params) {
37759
+ const keys = new Set;
37760
+ if (params.parentMessageId) {
37761
+ keys.add(messageKey(params.accountId, params.parentChatId, params.parentMessageId));
37762
+ }
37763
+ if (params.agentId) {
37764
+ keys.add(activeKey(params.accountId, params.parentChatId, params.agentId));
37765
+ }
37766
+ keys.add(activeKey(params.accountId, params.parentChatId));
37767
+ return [...keys];
37768
+ }
37769
+ function setMemory(key, value, now) {
37770
+ const memory = getRouteState().memory;
37771
+ memory.delete(key);
37772
+ memory.set(key, { value, updatedAt: now });
37773
+ pruneMapToMaxSize(memory, MAX_ENTRIES);
37774
+ }
37775
+ function getMemory(key, now) {
37776
+ const memory = getRouteState().memory;
37777
+ const entry = memory.get(key);
37778
+ if (!entry)
37779
+ return;
37780
+ if (now - entry.updatedAt > TTL_MS) {
37781
+ memory.delete(key);
37782
+ return;
37783
+ }
37784
+ memory.delete(key);
37785
+ memory.set(key, { ...entry, updatedAt: now });
37786
+ return entry.value;
37787
+ }
37788
+ async function readFileRoutes(accountId) {
37789
+ const filePath = resolveRoutesPath(accountId);
37790
+ if (!filePath)
37791
+ return new Map;
37792
+ const fallback = { version: STORE_VERSION, routes: {} };
37793
+ const now = Date.now();
37794
+ try {
37795
+ const { value } = await readJsonFileWithFallback(filePath, fallback);
37796
+ if (value.version !== STORE_VERSION || !isRecord3(value.routes)) {
37797
+ return new Map;
37798
+ }
37799
+ const routes = new Map;
37800
+ for (const [key, raw] of Object.entries(value.routes)) {
37801
+ const route = normalizeRecord(raw);
37802
+ if (route && !isExpired(route, now))
37803
+ routes.set(key, route);
37804
+ }
37805
+ return routes;
37806
+ } catch (error51) {
37807
+ reportRouteStateError(error51);
37808
+ return new Map;
37809
+ }
37810
+ }
37811
+ async function writeFileRoutes(accountId, routes) {
37812
+ const filePath = resolveRoutesPath(accountId);
37813
+ if (!filePath)
37814
+ return;
37815
+ const pruned = [...routes.entries()].sort((left, right) => right[1].updatedAt - left[1].updatedAt).slice(0, PERSISTENT_MAX_ENTRIES);
37816
+ await writeJsonFileAtomically(filePath, {
37817
+ version: STORE_VERSION,
37818
+ routes: Object.fromEntries(pruned)
37819
+ });
37820
+ }
37821
+ function rememberFileRoutes(params) {
37822
+ const state = getRouteState();
37823
+ const queueKey = params.accountId || DEFAULT_STORE_KEY;
37824
+ const previous = state.fileWrites.get(queueKey) ?? Promise.resolve();
37825
+ const next = previous.catch(() => {
37826
+ return;
37827
+ }).then(async () => {
37828
+ const routes = await readFileRoutes(params.accountId);
37829
+ for (const key of params.keys) {
37830
+ routes.set(key, params.record);
37831
+ }
37832
+ await writeFileRoutes(params.accountId, routes);
37833
+ });
37834
+ state.fileWrites.set(queueKey, next);
37835
+ const cleanup = () => {
37836
+ if (state.fileWrites.get(queueKey) === next) {
37837
+ state.fileWrites.delete(queueKey);
37838
+ }
37839
+ };
37840
+ next.then(cleanup, cleanup);
37841
+ next.catch(reportRouteStateError);
37842
+ }
37843
+ function rememberInlineReplyThreadRoute(params) {
37844
+ const accountId = params.accountId.trim();
37845
+ const parentChatId = normalizePositiveId(params.parentChatId);
37846
+ const threadId = normalizePositiveId(params.threadId);
37847
+ if (!accountId || !parentChatId || !threadId)
37848
+ return null;
37849
+ const now = Date.now();
37850
+ const parentMessageId = normalizePositiveId(params.parentMessageId);
37851
+ const title = normalizeOptionalText(params.title);
37852
+ const threadLabel = normalizeOptionalText(params.threadLabel);
37853
+ const agentId = normalizeOptionalText(params.agentId);
37854
+ const record2 = {
37855
+ accountId,
37856
+ parentChatId,
37857
+ threadId,
37858
+ createdAt: now,
37859
+ updatedAt: now,
37860
+ ...parentMessageId ? { parentMessageId } : {},
37861
+ ...title ? { title } : {},
37862
+ ...threadLabel ? { threadLabel } : {},
37863
+ ...agentId ? { agentId } : {}
37864
+ };
37865
+ const keys = keysForRecord(record2);
37866
+ for (const key of keys) {
37867
+ setMemory(key, record2, now);
37868
+ }
37869
+ const store = getPersistentStore();
37870
+ if (store) {
37871
+ for (const key of keys) {
37872
+ store.register(key, record2, { ttlMs: TTL_MS }).catch(disablePersistentStore);
37873
+ }
37874
+ return record2;
37875
+ }
37876
+ rememberFileRoutes({ accountId, keys, record: record2 });
37877
+ return record2;
37878
+ }
37879
+ async function lookupInlineReplyThreadRoute(params) {
37880
+ const accountId = params.accountId.trim();
37881
+ const parentChatId = normalizePositiveId(params.parentChatId);
37882
+ if (!accountId || !parentChatId)
37883
+ return null;
37884
+ const parentMessageId = normalizePositiveId(params.parentMessageId);
37885
+ const agentId = normalizeOptionalText(params.agentId);
37886
+ const keys = keysForLookup({
37887
+ accountId,
37888
+ parentChatId,
37889
+ ...parentMessageId ? { parentMessageId } : {},
37890
+ ...agentId ? { agentId } : {}
37891
+ });
37892
+ const now = Date.now();
37893
+ for (const key of keys) {
37894
+ const cached3 = getMemory(key, now);
37895
+ if (cached3)
37896
+ return cached3;
37897
+ }
37898
+ const store = getPersistentStore();
37899
+ if (store) {
37900
+ for (const key of keys) {
37901
+ try {
37902
+ const found = await store.lookup(key);
37903
+ const normalized = normalizeRecord(found);
37904
+ if (normalized && !isExpired(normalized, now)) {
37905
+ setMemory(key, normalized, now);
37906
+ return normalized;
37907
+ }
37908
+ } catch (error51) {
37909
+ disablePersistentStore(error51);
37910
+ break;
37911
+ }
37912
+ }
37913
+ }
37914
+ const fileRoutes = await readFileRoutes(accountId);
37915
+ for (const key of keys) {
37916
+ const found = fileRoutes.get(key);
37917
+ const normalized = normalizeRecord(found);
37918
+ if (normalized) {
37919
+ setMemory(key, normalized, now);
37920
+ return normalized;
37921
+ }
37922
+ }
37923
+ return null;
37924
+ }
37925
+
37532
37926
  // src/inline/outbound-sanitize.ts
37533
37927
  var HEARTBEAT_TOKEN = "HEARTBEAT_OK";
37534
37928
  var OPENCLAW_RUNTIME_CONTEXT_NOTICE = "This context is runtime-generated, not user-authored. Keep internal details private.";
@@ -37942,7 +38336,7 @@ function optionalVisibleActionText(raw, label) {
37942
38336
  }
37943
38337
  return visible.text.trim() || undefined;
37944
38338
  }
37945
- function isRecord3(value) {
38339
+ function isRecord4(value) {
37946
38340
  return typeof value === "object" && value !== null;
37947
38341
  }
37948
38342
  function normalizeReplyMarkupButtons(raw) {
@@ -37954,7 +38348,7 @@ function normalizeReplyMarkupButtons(raw) {
37954
38348
  continue;
37955
38349
  const row = [];
37956
38350
  for (const candidateButton of candidateRow) {
37957
- if (!isRecord3(candidateButton))
38351
+ if (!isRecord4(candidateButton))
37958
38352
  continue;
37959
38353
  const text = sanitizeInlineActionLabel(typeof candidateButton.text === "string" ? candidateButton.text : "");
37960
38354
  const callbackData = sanitizeInlineActionCallbackData(typeof candidateButton.callback_data === "string" ? candidateButton.callback_data : "");
@@ -38536,7 +38930,7 @@ async function withInlineClient(params) {
38536
38930
  });
38537
38931
  await client.connect();
38538
38932
  try {
38539
- return await params.fn(client);
38933
+ return await params.fn(client, account);
38540
38934
  } finally {
38541
38935
  await client.close().catch(() => {});
38542
38936
  }
@@ -38805,16 +39199,16 @@ var inlineMessageActions = {
38805
39199
  }
38806
39200
  if (normalizedAction === "reply" || normalizedAction === "thread-reply") {
38807
39201
  const parseMarkdown = resolveInlineAccount({ cfg, accountId: accountId ?? null }).config.parseMarkdown ?? true;
38808
- const replyThreadsEnabled = normalizedAction === "thread-reply" && isInlineReplyThreadsEnabled({ cfg, accountId: accountId ?? null });
39202
+ const isThreadReply = normalizedAction === "thread-reply";
38809
39203
  return await withInlineClient({
38810
39204
  cfg,
38811
39205
  accountId,
38812
39206
  fn: async (client) => {
38813
39207
  const actions = resolveInlineMessageActionsParam(params);
38814
- if (replyThreadsEnabled) {
39208
+ if (isThreadReply) {
38815
39209
  const rawThreadId = readFlexibleId(params, "threadId") ?? readStringParam(params, "threadId");
38816
39210
  if (!rawThreadId) {
38817
- throw new Error("inline thread-reply: threadId is required when reply threads are enabled");
39211
+ throw new Error("inline thread-reply: threadId is required. Call thread-create first or use reply for the parent chat.");
38818
39212
  }
38819
39213
  const chatId2 = parseInlineId(rawThreadId, "threadId");
38820
39214
  const replyToMsgId2 = parseOptionalInlineId(readFlexibleId(params, "messageId") ?? readFlexibleId(params, "replyTo") ?? readFlexibleId(params, "replyToId") ?? readStringParam(params, "messageId") ?? readStringParam(params, "replyTo") ?? readStringParam(params, "replyToId"), "messageId");
@@ -38838,7 +39232,7 @@ var inlineMessageActions = {
38838
39232
  replyToId: replyToMsgId2 != null ? String(replyToMsgId2) : null
38839
39233
  });
38840
39234
  }
38841
- const replyParams = normalizedAction === "thread-reply" && params.threadId != null && params.to == null && params.chatId == null && params.channelId == null ? { ...params, to: params.threadId } : params;
39235
+ const replyParams = params;
38842
39236
  const chatId = resolveChatIdFromParams(replyParams);
38843
39237
  const replyToMsgId = parseInlineId(readFlexibleId(replyParams, "messageId") ?? readFlexibleId(replyParams, "replyTo") ?? readFlexibleId(replyParams, "replyToId") ?? readStringParam(replyParams, "messageId") ?? readStringParam(replyParams, "replyTo") ?? readStringParam(replyParams, "replyToId", { required: true }), "messageId");
38844
39238
  const text = resolveInlineActionText(replyParams, { required: true });
@@ -39177,11 +39571,11 @@ var inlineMessageActions = {
39177
39571
  });
39178
39572
  }
39179
39573
  if (normalizedAction === "channel-create" || normalizedAction === "thread-create") {
39180
- const replyThreadsEnabled = normalizedAction === "thread-create" && isInlineReplyThreadsEnabled({ cfg, accountId: accountId ?? null });
39574
+ const isThreadCreate = normalizedAction === "thread-create";
39181
39575
  return await withInlineClient({
39182
39576
  cfg,
39183
39577
  accountId,
39184
- fn: async (client) => {
39578
+ fn: async (client, account) => {
39185
39579
  const title = requireVisibleActionText(readStringParam(params, "title") ?? readStringParam(params, "name") ?? readStringParam(params, "threadName") ?? readStringParam(params, "message", { required: true }), "title");
39186
39580
  const description = optionalVisibleActionText(readStringParam(params, "description"), "description");
39187
39581
  const emoji3 = readStringParam(params, "emoji");
@@ -39200,7 +39594,7 @@ var inlineMessageActions = {
39200
39594
  values: participantRefs,
39201
39595
  label: "participant"
39202
39596
  });
39203
- if (replyThreadsEnabled) {
39597
+ if (isThreadCreate) {
39204
39598
  const parentChatId = resolveChatIdFromParams(params);
39205
39599
  const parentMessageId = parseOptionalInlineId(resolveThreadParentMessageId({
39206
39600
  args: params,
@@ -39220,12 +39614,23 @@ var inlineMessageActions = {
39220
39614
  if (result2.oneofKind !== "createSubthread") {
39221
39615
  throw new Error(`inline action: expected createSubthread result, got ${String(result2.oneofKind)}`);
39222
39616
  }
39617
+ const createdChat = result2.createSubthread.chat ?? null;
39618
+ if (createdChat?.id != null) {
39619
+ const routeParentMessageId = createdChat.parentMessageId ?? parentMessageId;
39620
+ rememberInlineReplyThreadRoute({
39621
+ accountId: account.accountId,
39622
+ parentChatId: createdChat.parentChatId ?? parentChatId,
39623
+ threadId: createdChat.id,
39624
+ title: createdChat.title ?? title,
39625
+ ...routeParentMessageId != null ? { parentMessageId: routeParentMessageId } : {}
39626
+ });
39627
+ }
39223
39628
  return jsonResult(toJsonSafe({
39224
39629
  ok: true,
39225
39630
  title,
39226
39631
  parentChatId: String(parentChatId),
39227
39632
  parentMessageId: parentMessageId != null ? String(parentMessageId) : null,
39228
- chat: result2.createSubthread.chat ?? null,
39633
+ chat: createdChat,
39229
39634
  dialog: result2.createSubthread.dialog ?? null,
39230
39635
  anchorMessage: result2.createSubthread.anchorMessage ?? null
39231
39636
  }));
@@ -40054,26 +40459,26 @@ function buildInlineModelBrowseChannelData() {
40054
40459
  }
40055
40460
 
40056
40461
  // src/inline/thread-participation.ts
40057
- import path2 from "node:path";
40462
+ import path3 from "node:path";
40058
40463
  import { resolveGlobalDedupeCache } from "openclaw/plugin-sdk/dedupe-runtime";
40059
40464
  import { createPersistentDedupe } from "openclaw/plugin-sdk/persistent-dedupe";
40060
- var TTL_MS = 24 * 60 * 60 * 1000;
40061
- var MAX_ENTRIES = 5000;
40062
- var PERSISTENT_MAX_ENTRIES = 1000;
40063
- var PERSISTENT_NAMESPACE = "inline.thread-participation";
40465
+ var TTL_MS2 = 24 * 60 * 60 * 1000;
40466
+ var MAX_ENTRIES2 = 5000;
40467
+ var PERSISTENT_MAX_ENTRIES2 = 1000;
40468
+ var PERSISTENT_NAMESPACE2 = "inline.thread-participation";
40064
40469
  var PERSISTENT_DEDUPE_NAMESPACE = "participation";
40065
40470
  var INLINE_THREAD_PARTICIPATION_KEY = Symbol.for("openclaw.inlineThreadParticipation");
40066
40471
  var threadParticipation = resolveGlobalDedupeCache(INLINE_THREAD_PARTICIPATION_KEY, {
40067
- ttlMs: TTL_MS,
40068
- maxSize: MAX_ENTRIES
40472
+ ttlMs: TTL_MS2,
40473
+ maxSize: MAX_ENTRIES2
40069
40474
  });
40070
- var persistentStore;
40071
- var persistentStoreDisabled = false;
40475
+ var persistentStore2;
40476
+ var persistentStoreDisabled2 = false;
40072
40477
  var persistentDedupe;
40073
40478
  function makeKey(accountId, parentChatId, threadId) {
40074
40479
  return `${accountId}:${String(parentChatId)}:${String(threadId)}`;
40075
40480
  }
40076
- function safePathSegment(value) {
40481
+ function safePathSegment2(value) {
40077
40482
  return value.trim().replace(/[^a-z0-9._-]+/gi, "_").slice(0, 80) || "global";
40078
40483
  }
40079
40484
  function isExpectedOpenKeyedStoreUnavailable(error51) {
@@ -40085,28 +40490,28 @@ function reportPersistentThreadParticipationError(error51) {
40085
40490
  } catch {}
40086
40491
  }
40087
40492
  function disablePersistentThreadParticipation(error51) {
40088
- persistentStoreDisabled = true;
40089
- persistentStore = undefined;
40493
+ persistentStoreDisabled2 = true;
40494
+ persistentStore2 = undefined;
40090
40495
  if (!isExpectedOpenKeyedStoreUnavailable(error51)) {
40091
40496
  reportPersistentThreadParticipationError(error51);
40092
40497
  }
40093
40498
  }
40094
40499
  function getPersistentThreadParticipationStore() {
40095
- if (persistentStoreDisabled)
40500
+ if (persistentStoreDisabled2)
40096
40501
  return;
40097
- if (persistentStore)
40098
- return persistentStore;
40502
+ if (persistentStore2)
40503
+ return persistentStore2;
40099
40504
  const runtime = getOptionalInlineRuntime();
40100
40505
  const openKeyedStore = runtime?.state?.openKeyedStore;
40101
40506
  if (typeof openKeyedStore !== "function")
40102
40507
  return;
40103
40508
  try {
40104
- persistentStore = openKeyedStore({
40105
- namespace: PERSISTENT_NAMESPACE,
40106
- maxEntries: PERSISTENT_MAX_ENTRIES,
40107
- defaultTtlMs: TTL_MS
40509
+ persistentStore2 = openKeyedStore({
40510
+ namespace: PERSISTENT_NAMESPACE2,
40511
+ maxEntries: PERSISTENT_MAX_ENTRIES2,
40512
+ defaultTtlMs: TTL_MS2
40108
40513
  });
40109
- return persistentStore;
40514
+ return persistentStore2;
40110
40515
  } catch (error51) {
40111
40516
  disablePersistentThreadParticipation(error51);
40112
40517
  return;
@@ -40121,10 +40526,10 @@ function getPersistentThreadParticipationDedupe() {
40121
40526
  try {
40122
40527
  const stateDir = resolveStateDir();
40123
40528
  persistentDedupe = createPersistentDedupe({
40124
- ttlMs: TTL_MS,
40125
- memoryMaxSize: MAX_ENTRIES,
40126
- fileMaxEntries: PERSISTENT_MAX_ENTRIES,
40127
- resolveFilePath: (namespace) => path2.join(stateDir, "inline", "thread-participation", `${safePathSegment(namespace)}.json`),
40529
+ ttlMs: TTL_MS2,
40530
+ memoryMaxSize: MAX_ENTRIES2,
40531
+ fileMaxEntries: PERSISTENT_MAX_ENTRIES2,
40532
+ resolveFilePath: (namespace) => path3.join(stateDir, "inline", "thread-participation", `${safePathSegment2(namespace)}.json`),
40128
40533
  onDiskError: reportPersistentThreadParticipationError
40129
40534
  });
40130
40535
  return persistentDedupe;
@@ -40139,7 +40544,7 @@ function rememberPersistentThreadParticipation(params) {
40139
40544
  store.register(params.key, {
40140
40545
  ...params.agentId ? { agentId: params.agentId } : {},
40141
40546
  repliedAt: Date.now()
40142
- }, { ttlMs: TTL_MS }).catch(disablePersistentThreadParticipation);
40547
+ }, { ttlMs: TTL_MS2 }).catch(disablePersistentThreadParticipation);
40143
40548
  return;
40144
40549
  }
40145
40550
  getPersistentThreadParticipationDedupe()?.checkAndRecord(params.key, { namespace: PERSISTENT_DEDUPE_NAMESPACE }).catch(reportPersistentThreadParticipationError);
@@ -40832,7 +41237,7 @@ function buildSyntheticInlineTextMessage(params) {
40832
41237
  }
40833
41238
  var INLINE_ACTION_MAX_ROWS2 = 8;
40834
41239
  var INLINE_ACTION_MAX_PER_ROW2 = 8;
40835
- function isRecord4(value) {
41240
+ function isRecord5(value) {
40836
41241
  return typeof value === "object" && value !== null && !Array.isArray(value);
40837
41242
  }
40838
41243
  function normalizeOptionalString2(value) {
@@ -40853,7 +41258,7 @@ function normalizeInlineStreamingMode(value) {
40853
41258
  }
40854
41259
  }
40855
41260
  function resolveExplicitInlineStreamingMode(config2) {
40856
- const streaming = isRecord4(config2.streaming) ? config2.streaming : null;
41261
+ const streaming = isRecord5(config2.streaming) ? config2.streaming : null;
40857
41262
  return normalizeInlineStreamingMode(streaming?.mode) ?? normalizeInlineStreamingMode(config2.streaming) ?? normalizeInlineStreamingMode(config2.streamMode);
40858
41263
  }
40859
41264
  function resolveInlineStreamingMode(config2) {
@@ -40873,14 +41278,14 @@ function resolveInlineProgressPlaceholderEnabled(config2) {
40873
41278
  return true;
40874
41279
  if (config2.streaming === false)
40875
41280
  return false;
40876
- if (isRecord4(config2.streaming) && isRecord4(config2.streaming.progress))
41281
+ if (isRecord5(config2.streaming) && isRecord5(config2.streaming.progress))
40877
41282
  return true;
40878
41283
  return config2.streaming === undefined && config2.streamMode === undefined && config2.streamViaEditMessage !== true;
40879
41284
  }
40880
41285
  function resolveInlineBlockStreamingEnabled(config2) {
40881
41286
  const mode = resolveInlineStreamingMode(config2);
40882
- const streaming = isRecord4(config2.streaming) ? config2.streaming : null;
40883
- const block = streaming && isRecord4(streaming.block) ? streaming.block : null;
41287
+ const streaming = isRecord5(config2.streaming) ? config2.streaming : null;
41288
+ const block = streaming && isRecord5(streaming.block) ? streaming.block : null;
40884
41289
  if (typeof block?.enabled === "boolean")
40885
41290
  return block.enabled;
40886
41291
  if (typeof config2.blockStreaming === "boolean")
@@ -41104,7 +41509,7 @@ function normalizeReplyMarkupButtonsWith(raw, options) {
41104
41509
  continue;
41105
41510
  const row = [];
41106
41511
  for (const candidateButton of candidateRow) {
41107
- if (!isRecord4(candidateButton))
41512
+ if (!isRecord5(candidateButton))
41108
41513
  continue;
41109
41514
  const text = sanitizeInlineActionLabel(typeof candidateButton.text === "string" ? candidateButton.text : "");
41110
41515
  const callbackDataRaw = typeof candidateButton.callback_data === "string" ? candidateButton.callback_data.trim() : "";
@@ -41125,9 +41530,9 @@ function normalizeReplyMarkupButtonsWith(raw, options) {
41125
41530
  return rows;
41126
41531
  }
41127
41532
  function resolveInlineReplyActions(payload) {
41128
- const channelData = isRecord4(payload.channelData) ? payload.channelData : undefined;
41129
- const inlineData = channelData && isRecord4(channelData.inline) ? channelData.inline : undefined;
41130
- const telegramData = channelData && isRecord4(channelData.telegram) ? channelData.telegram : undefined;
41533
+ const channelData = isRecord5(payload.channelData) ? payload.channelData : undefined;
41534
+ const inlineData = channelData && isRecord5(channelData.inline) ? channelData.inline : undefined;
41535
+ const telegramData = channelData && isRecord5(channelData.telegram) ? channelData.telegram : undefined;
41131
41536
  let rawButtons = undefined;
41132
41537
  let hasExplicitButtons = false;
41133
41538
  let mapCallbackData;
@@ -41223,6 +41628,14 @@ function rememberInlineBotDelivery(params) {
41223
41628
  if (!params.replyThreadContext || params.chatId !== params.replyThreadContext.childChatId)
41224
41629
  return;
41225
41630
  recordInlineThreadParticipation(params.accountId, params.replyThreadContext.parentChatId, params.replyThreadContext.childChatId, { agentId: params.agentId });
41631
+ rememberInlineReplyThreadRoute({
41632
+ accountId: params.accountId,
41633
+ parentChatId: params.replyThreadContext.parentChatId,
41634
+ threadId: params.replyThreadContext.childChatId,
41635
+ parentMessageId: params.replyThreadContext.parentMessageId,
41636
+ threadLabel: params.replyThreadContext.threadLabel,
41637
+ agentId: params.agentId
41638
+ });
41226
41639
  }
41227
41640
  function hasBotMessageId(cache, chatId, messageId) {
41228
41641
  const key = String(chatId);
@@ -41637,7 +42050,7 @@ function resolveFilePathHint(params) {
41637
42050
  return preferred;
41638
42051
  try {
41639
42052
  const pathname = new URL(params.sourceUrl).pathname;
41640
- const base = path3.basename(pathname).trim();
42053
+ const base = path4.basename(pathname).trim();
41641
42054
  if (base)
41642
42055
  return base;
41643
42056
  } catch {}
@@ -41712,6 +42125,44 @@ async function resolveInlineInboundReplyThreadContext(params) {
41712
42125
  anchorMessage
41713
42126
  };
41714
42127
  }
42128
+ function parseCachedInlineId(raw) {
42129
+ if (!raw || !/^\d+$/.test(raw))
42130
+ return null;
42131
+ try {
42132
+ return BigInt(raw);
42133
+ } catch {
42134
+ return null;
42135
+ }
42136
+ }
42137
+ async function resolveInlineReplyThreadContextFromRoute(params) {
42138
+ const parentChatId = parseCachedInlineId(params.route.parentChatId);
42139
+ const childChatId = parseCachedInlineId(params.route.threadId);
42140
+ if (parentChatId == null || childChatId == null) {
42141
+ return null;
42142
+ }
42143
+ const parentMessageId = parseCachedInlineId(params.route.parentMessageId);
42144
+ const parentChatInfo = await resolveChatInfo(params.client, params.chatCache, parentChatId).catch(() => ({
42145
+ kind: "group",
42146
+ title: params.fallbackParentChatTitle
42147
+ }));
42148
+ const anchorMessage = parentMessageId != null ? await loadInlineReplyThreadAnchorMessage({
42149
+ client: params.client,
42150
+ parentChatId,
42151
+ parentMessageId
42152
+ }).catch(() => null) : null;
42153
+ const labelSource = params.route.threadLabel ?? params.route.title ?? null;
42154
+ return {
42155
+ childChatId,
42156
+ parentChatId,
42157
+ parentChatTitle: parentChatInfo.title ?? params.fallbackParentChatTitle,
42158
+ parentMessageId,
42159
+ threadLabel: buildInlineReplyThreadLabel({
42160
+ title: labelSource,
42161
+ anchorMessage
42162
+ }),
42163
+ anchorMessage
42164
+ };
42165
+ }
41715
42166
  function normalizeInlineReplyThreadMode(raw) {
41716
42167
  return raw === "thread" || raw === "main" ? raw : "auto";
41717
42168
  }
@@ -41840,8 +42291,8 @@ async function monitorInlineProvider(params) {
41840
42291
  }
41841
42292
  const token = await resolveInlineToken(account);
41842
42293
  const stateDir = core3.state.resolveStateDir();
41843
- const statePath = path3.join(stateDir, "channels", "inline", `${account.accountId}.json`);
41844
- await mkdir(path3.dirname(statePath), { recursive: true });
42294
+ const statePath = path4.join(stateDir, "channels", "inline", `${account.accountId}.json`);
42295
+ await mkdir(path4.dirname(statePath), { recursive: true });
41845
42296
  let client = null;
41846
42297
  const pushDiagnostics = (patch) => {
41847
42298
  statusSink?.({
@@ -41953,7 +42404,7 @@ async function monitorInlineProvider(params) {
41953
42404
  statusSink?.({ lastError: `getChat failed: ${String(err)}` });
41954
42405
  }
41955
42406
  const isGroup = chatInfo.kind !== "direct";
41956
- const replyThreadsEnabled = account.config.capabilities?.replyThreads === true || isInlineReplyThreadsEnabled({ cfg, accountId: account.accountId });
42407
+ const replyThreadsEnabled = isInlineReplyThreadsEnabled({ cfg, accountId: account.accountId });
41957
42408
  const replyThreadContext = await resolveInlineInboundReplyThreadContext({
41958
42409
  replyThreadsEnabled,
41959
42410
  client,
@@ -42193,7 +42644,7 @@ async function monitorInlineProvider(params) {
42193
42644
  statusSink?.({ lastError: `getChat failed: ${String(err)}` });
42194
42645
  }
42195
42646
  const isGroup = chatInfo.kind !== "direct";
42196
- const replyThreadsEnabled = account.config.capabilities?.replyThreads === true || isInlineReplyThreadsEnabled({ cfg, accountId: account.accountId });
42647
+ const replyThreadsEnabled = isInlineReplyThreadsEnabled({ cfg, accountId: account.accountId });
42197
42648
  const replyThreadContext = await resolveInlineInboundReplyThreadContext({
42198
42649
  replyThreadsEnabled,
42199
42650
  client,
@@ -42290,6 +42741,16 @@ async function monitorInlineProvider(params) {
42290
42741
  }
42291
42742
  });
42292
42743
  const inboundSessionKey = replyThreadContext && isGroup ? buildInlineReplyThreadSessionKey(route.sessionKey, replyThreadContext.childChatId) : route.sessionKey;
42744
+ if (replyThreadContext && isGroup) {
42745
+ rememberInlineReplyThreadRoute({
42746
+ accountId: account.accountId,
42747
+ parentChatId: replyThreadContext.parentChatId,
42748
+ threadId: replyThreadContext.childChatId,
42749
+ parentMessageId: replyThreadContext.parentMessageId,
42750
+ threadLabel: replyThreadContext.threadLabel,
42751
+ agentId: route.agentId
42752
+ });
42753
+ }
42293
42754
  const rememberSentBotMessage = (params2) => {
42294
42755
  if (params2.messageId == null)
42295
42756
  return;
@@ -42723,6 +43184,30 @@ This model will be used for your next message.`, []);
42723
43184
  minMessages: replyThreadAutoCreateMinMessages
42724
43185
  }) && !shouldEditCallbackTargetInPlace;
42725
43186
  if (shouldCreateDeliveryThread) {
43187
+ const cachedRoute = await lookupInlineReplyThreadRoute({
43188
+ accountId: account.accountId,
43189
+ parentChatId: effectiveChatId,
43190
+ parentMessageId: msg.id,
43191
+ agentId: route.agentId
43192
+ }).catch((error51) => {
43193
+ statusSink?.({ lastError: `reply-thread route lookup failed: ${String(error51)}` });
43194
+ runtime.error?.(`inline reply-thread route lookup failed: ${String(error51)}`);
43195
+ return null;
43196
+ });
43197
+ if (cachedRoute) {
43198
+ deliveryReplyThreadContext = await resolveInlineReplyThreadContextFromRoute({
43199
+ route: cachedRoute,
43200
+ client,
43201
+ chatCache,
43202
+ fallbackParentChatTitle: effectiveGroupTitle
43203
+ }).catch((error51) => {
43204
+ statusSink?.({ lastError: `reply-thread route restore failed: ${String(error51)}` });
43205
+ runtime.error?.(`inline reply-thread route restore failed: ${String(error51)}`);
43206
+ return null;
43207
+ });
43208
+ }
43209
+ }
43210
+ if (shouldCreateDeliveryThread && !deliveryReplyThreadContext) {
42726
43211
  const createdThread = await createInlineReplyThreadForMessage({
42727
43212
  client,
42728
43213
  parentChatId: effectiveChatId,
@@ -42744,13 +43229,35 @@ This model will be used for your next message.`, []);
42744
43229
  }),
42745
43230
  anchorMessage: createdThread.anchorMessage
42746
43231
  };
43232
+ rememberInlineReplyThreadRoute({
43233
+ accountId: account.accountId,
43234
+ parentChatId: deliveryReplyThreadContext.parentChatId,
43235
+ threadId: deliveryReplyThreadContext.childChatId,
43236
+ parentMessageId: deliveryReplyThreadContext.parentMessageId,
43237
+ title: createdThread.title,
43238
+ threadLabel: deliveryReplyThreadContext.threadLabel,
43239
+ agentId: route.agentId
43240
+ });
42747
43241
  }
42748
43242
  }
42749
43243
  if (shouldCreateDeliveryThread && !deliveryReplyThreadContext) {
42750
- await answerCallbackIfNeeded().catch((error51) => {
42751
- runtime.error?.(`inline callback answer failed: ${String(error51)}`);
42752
- });
42753
- return;
43244
+ const cachedRoute = await lookupInlineReplyThreadRoute({
43245
+ accountId: account.accountId,
43246
+ parentChatId: effectiveChatId,
43247
+ parentMessageId: msg.id,
43248
+ agentId: route.agentId
43249
+ }).catch(() => null);
43250
+ if (cachedRoute) {
43251
+ deliveryReplyThreadContext = await resolveInlineReplyThreadContextFromRoute({
43252
+ route: cachedRoute,
43253
+ client,
43254
+ chatCache,
43255
+ fallbackParentChatTitle: effectiveGroupTitle
43256
+ }).catch(() => null);
43257
+ }
43258
+ }
43259
+ if (shouldCreateDeliveryThread && !deliveryReplyThreadContext) {
43260
+ runtime.error?.("inline create reply thread failed; falling back to parent chat delivery");
42754
43261
  }
42755
43262
  if (!replyThreadContext && deliveryReplyThreadContext?.anchorMessage != null) {
42756
43263
  effectiveHistoryContext = prependInlineReplyThreadAnchor({
@@ -43688,7 +44195,7 @@ Attachment: ${mediaUrl}` : `Attachment: ${mediaUrl}`;
43688
44195
  }
43689
44196
 
43690
44197
  // src/inline/doctor.ts
43691
- function isRecord5(value) {
44198
+ function isRecord6(value) {
43692
44199
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
43693
44200
  }
43694
44201
  function readInherited(account, parent, key) {
@@ -43699,12 +44206,12 @@ function hasEntries(value) {
43699
44206
  }
43700
44207
  function hasConfiguredGroups(account, parent) {
43701
44208
  const groups = readInherited(account, parent, "groups");
43702
- return isRecord5(groups) && Object.keys(groups).length > 0;
44209
+ return isRecord6(groups) && Object.keys(groups).length > 0;
43703
44210
  }
43704
44211
  function hasGroupScopedSenders(groups) {
43705
- if (!isRecord5(groups))
44212
+ if (!isRecord6(groups))
43706
44213
  return false;
43707
- return Object.values(groups).some((group) => isRecord5(group) && hasEntries(group.allowFrom));
44214
+ return Object.values(groups).some((group) => isRecord6(group) && hasEntries(group.allowFrom));
43708
44215
  }
43709
44216
  function hasGroupSenders(account, parent) {
43710
44217
  return hasEntries(readInherited(account, parent, "groupAllowFrom")) || hasGroupScopedSenders(readInherited(account, parent, "groups"));
@@ -44291,11 +44798,11 @@ async function probeInlineAccount(account, timeoutMs) {
44291
44798
  }
44292
44799
 
44293
44800
  // src/inline/status-issues.ts
44294
- import { asString, isRecord as isRecord6 } from "openclaw/plugin-sdk/status-helpers";
44801
+ import { asString, isRecord as isRecord7 } from "openclaw/plugin-sdk/status-helpers";
44295
44802
  var RECENT_RUNTIME_ISSUE_MS = 30 * 60 * 1000;
44296
44803
  var INLINE_CONNECT_GRACE_MS = 120 * 1000;
44297
44804
  function readInlineProbeSummary(value) {
44298
- if (!isRecord6(value)) {
44805
+ if (!isRecord7(value)) {
44299
44806
  return {};
44300
44807
  }
44301
44808
  const summary = {};
@@ -44312,12 +44819,12 @@ function looksLikeAuthError(text) {
44312
44819
  return /(401|403|unauth|forbidden|invalid token|token invalid|unauthorized)/i.test(text);
44313
44820
  }
44314
44821
  function readInlineDiagnosticsSummary(value) {
44315
- if (!isRecord6(value)) {
44822
+ if (!isRecord7(value)) {
44316
44823
  return {};
44317
44824
  }
44318
- const protocolValue = isRecord6(value.protocol) ? value.protocol : undefined;
44319
- const transportValue = (protocolValue && isRecord6(protocolValue.transport) ? protocolValue.transport : undefined) ?? (isRecord6(value.transport) ? value.transport : undefined);
44320
- const pingValue = protocolValue && isRecord6(protocolValue.ping) ? protocolValue.ping : undefined;
44825
+ const protocolValue = isRecord7(value.protocol) ? value.protocol : undefined;
44826
+ const transportValue = (protocolValue && isRecord7(protocolValue.transport) ? protocolValue.transport : undefined) ?? (isRecord7(value.transport) ? value.transport : undefined);
44827
+ const pingValue = protocolValue && isRecord7(protocolValue.ping) ? protocolValue.ping : undefined;
44321
44828
  return {
44322
44829
  ...protocolValue ? {
44323
44830
  protocol: {
@@ -44349,7 +44856,7 @@ function asFiniteNumber(value) {
44349
44856
  function collectInlineStatusIssues(accounts) {
44350
44857
  const issues = [];
44351
44858
  for (const entry of accounts) {
44352
- if (!isRecord6(entry)) {
44859
+ if (!isRecord7(entry)) {
44353
44860
  continue;
44354
44861
  }
44355
44862
  const accountId = asString(entry.accountId);
@@ -44848,7 +45355,7 @@ var inlineNativeApprovalAdapter = splitChannelApprovalCapability(inlineApprovalC
44848
45355
  // src/inline/channel.ts
44849
45356
  var activeMonitors = new Map;
44850
45357
  function resolveInlineStatePath(accountId) {
44851
- return path4.join(getInlineRuntime().state.resolveStateDir(), "channels", "inline", `${accountId}.json`);
45358
+ return path5.join(getInlineRuntime().state.resolveStateDir(), "channels", "inline", `${accountId}.json`);
44852
45359
  }
44853
45360
  async function deleteInlineAccountState(accountId) {
44854
45361
  try {
@@ -45974,13 +46481,10 @@ var inlineChannelPlugin = {
45974
46481
  ] : [],
45975
46482
  "- Inline history tools: `read` and `search` return media-aware message payloads (`media`, `attachments`, `attachmentUrls`) so image-only history remains discoverable. `search` is chat-scoped; run it per chat.",
45976
46483
  "- Inline special tools: use `inline_nudge` to send a nudge, and `inline_forward` to forward message ids between chats or users.",
45977
- ...isInlineReplyThreadsEnabled({ cfg, accountId: accountId ?? null }) ? [
45978
- "- Inline reply threads are enabled: use `thread-create` to create a real reply thread under the current/target chat. On inbound turns, omit `messageId` to anchor it to the current message, or pass `messageId`/`parentMessageId` explicitly.",
45979
- "- Inline reply threads are enabled: use `thread-reply` to send into a real reply thread, with `threadId` set to the reply-thread chat id returned by `thread-create`.",
45980
- "- Inline reply-thread turns include nearby parent-chat context by default. If that context is incomplete, call `inline_parent_context` before answering."
45981
- ] : [
45982
- "- Inline reply threads are disabled: `thread-reply` uses the legacy reply path and `thread-create` creates a normal chat, not a dedicated Inline reply-thread chat."
45983
- ]
46484
+ "- Inline reply threads: use normal `reply` for short or newly started parent-chat conversations unless the user asks for a thread.",
46485
+ "- Inline reply threads: use `thread-create` to create or reuse a real reply thread under the current/target chat. On inbound turns, omit `messageId` to anchor it to the current message, or pass `messageId`/`parentMessageId` explicitly.",
46486
+ "- Inline reply threads: use `thread-reply` to send into a real reply thread, with `threadId` set to the reply-thread chat id returned by `thread-create`. Reuse that `threadId`; do not create one thread per message.",
46487
+ "- Inline reply-thread turns include nearby parent-chat context by default. If that context is incomplete, call `inline_parent_context` before answering."
45984
46488
  ]
45985
46489
  },
45986
46490
  messaging: {
@@ -46343,5 +46847,5 @@ export {
46343
46847
  inlineChannelPlugin
46344
46848
  };
46345
46849
 
46346
- //# debugId=8D08B1A22511109264756E2164756E21
46850
+ //# debugId=A439BD5C99EA226864756E2164756E21
46347
46851
  //# sourceMappingURL=channel-plugin-api.js.map