@inline-openclaw/inline 0.0.21 → 0.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +44 -7
  2. package/dist/index.d.ts +1 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +1083 -215
  5. package/dist/index.js.map +20 -17
  6. package/dist/inline/accounts.d.ts +1 -1
  7. package/dist/inline/accounts.d.ts.map +1 -1
  8. package/dist/inline/actions.d.ts +30 -3
  9. package/dist/inline/actions.d.ts.map +1 -1
  10. package/dist/inline/bot-commands-sync.d.ts +1 -1
  11. package/dist/inline/bot-commands-sync.d.ts.map +1 -1
  12. package/dist/inline/bot-commands-tool.d.ts +1 -1
  13. package/dist/inline/bot-commands-tool.d.ts.map +1 -1
  14. package/dist/inline/channel.d.ts +1 -1
  15. package/dist/inline/channel.d.ts.map +1 -1
  16. package/dist/inline/config-schema.d.ts +35 -14
  17. package/dist/inline/config-schema.d.ts.map +1 -1
  18. package/dist/inline/media.d.ts +1 -1
  19. package/dist/inline/media.d.ts.map +1 -1
  20. package/dist/inline/members-tool.d.ts +1 -1
  21. package/dist/inline/members-tool.d.ts.map +1 -1
  22. package/dist/inline/message-tools.d.ts +1 -1
  23. package/dist/inline/message-tools.d.ts.map +1 -1
  24. package/dist/inline/monitor.d.ts +2 -1
  25. package/dist/inline/monitor.d.ts.map +1 -1
  26. package/dist/inline/policy.d.ts +1 -1
  27. package/dist/inline/policy.d.ts.map +1 -1
  28. package/dist/inline/profile-tool.d.ts +1 -1
  29. package/dist/inline/profile-tool.d.ts.map +1 -1
  30. package/dist/inline/reply-threads.d.ts +34 -0
  31. package/dist/inline/reply-threads.d.ts.map +1 -0
  32. package/dist/openclaw-compat.d.ts +141 -0
  33. package/dist/openclaw-compat.d.ts.map +1 -0
  34. package/dist/runtime.d.ts +1 -1
  35. package/dist/runtime.d.ts.map +1 -1
  36. package/dist/sdk-runtime-compat.d.ts +83 -0
  37. package/dist/sdk-runtime-compat.d.ts.map +1 -0
  38. package/dist/tsconfig.tsbuildinfo +1 -1
  39. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -5539,17 +5539,6 @@ var require_websocket_server = __commonJS((exports, module) => {
5539
5539
  }
5540
5540
  });
5541
5541
 
5542
- // src/index.ts
5543
- import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
5544
-
5545
- // src/inline/channel.ts
5546
- import {
5547
- buildChannelConfigSchema,
5548
- DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID2,
5549
- formatPairingApproveHint,
5550
- PAIRING_APPROVED_MESSAGE
5551
- } from "openclaw/plugin-sdk";
5552
-
5553
5542
  // ../protocol/dist/core.js
5554
5543
  var import_runtime = __toESM(require_commonjs(), 1);
5555
5544
  var import_runtime2 = __toESM(require_commonjs(), 1);
@@ -19960,15 +19949,6 @@ class JsonFileStateStore {
19960
19949
  await rename(tempPath, this.path);
19961
19950
  }
19962
19951
  }
19963
- // src/inline/config-schema.ts
19964
- import {
19965
- BlockStreamingCoalesceSchema,
19966
- DmPolicySchema,
19967
- GroupPolicySchema,
19968
- ToolPolicySchema,
19969
- requireOpenAllowFrom
19970
- } from "openclaw/plugin-sdk";
19971
-
19972
19952
  // ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
19973
19953
  var exports_external = {};
19974
19954
  __export(exports_external, {
@@ -33501,6 +33481,246 @@ function date4(params) {
33501
33481
 
33502
33482
  // ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
33503
33483
  config(en_default());
33484
+ // src/openclaw-compat.ts
33485
+ var MB = 1024 * 1024;
33486
+ var VALID_ACCOUNT_ID_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/i;
33487
+ var INVALID_ACCOUNT_ID_CHARS_RE = /[^a-z0-9_-]+/g;
33488
+ var LEADING_DASH_RE = /^-+/g;
33489
+ var TRAILING_DASH_RE = /-+$/g;
33490
+ var BLOCKED_OBJECT_KEYS = new Set(["__proto__", "constructor", "prototype"]);
33491
+ var DEFAULT_ACCOUNT_ID = "default";
33492
+ var PAIRING_APPROVED_MESSAGE = "✅ OpenClaw access approved. Send a message to start chatting.";
33493
+ function normalizeAccountId(value) {
33494
+ const trimmed = (value ?? "").trim();
33495
+ if (!trimmed)
33496
+ return DEFAULT_ACCOUNT_ID;
33497
+ const normalized = VALID_ACCOUNT_ID_RE.test(trimmed) ? trimmed.toLowerCase() : trimmed.toLowerCase().replace(INVALID_ACCOUNT_ID_CHARS_RE, "-").replace(LEADING_DASH_RE, "").replace(TRAILING_DASH_RE, "").slice(0, 64);
33498
+ if (!normalized || BLOCKED_OBJECT_KEYS.has(normalized)) {
33499
+ return DEFAULT_ACCOUNT_ID;
33500
+ }
33501
+ return normalized;
33502
+ }
33503
+ function emptyPluginConfigSchema() {
33504
+ function error48(message) {
33505
+ return { success: false, error: { issues: [{ path: [], message }] } };
33506
+ }
33507
+ return {
33508
+ safeParse(value) {
33509
+ if (value === undefined) {
33510
+ return { success: true, data: undefined };
33511
+ }
33512
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
33513
+ return error48("expected config object");
33514
+ }
33515
+ if (Object.keys(value).length > 0) {
33516
+ return error48("config must be empty");
33517
+ }
33518
+ return { success: true, data: value };
33519
+ },
33520
+ jsonSchema: {
33521
+ type: "object",
33522
+ additionalProperties: false,
33523
+ properties: {}
33524
+ }
33525
+ };
33526
+ }
33527
+ function buildChannelConfigSchema(schema) {
33528
+ const schemaWithJson = schema;
33529
+ if (typeof schemaWithJson.toJSONSchema === "function") {
33530
+ return {
33531
+ schema: schemaWithJson.toJSONSchema({
33532
+ target: "draft-07",
33533
+ unrepresentable: "any"
33534
+ })
33535
+ };
33536
+ }
33537
+ return {
33538
+ schema: {
33539
+ type: "object",
33540
+ additionalProperties: true
33541
+ }
33542
+ };
33543
+ }
33544
+ function formatPairingApproveHint(channelId) {
33545
+ return `Approve via: openclaw pairing list ${channelId} / openclaw pairing approve ${channelId} <code>`;
33546
+ }
33547
+ var GroupPolicySchema = exports_external.enum(["open", "disabled", "allowlist"]);
33548
+ var DmPolicySchema = exports_external.enum(["pairing", "allowlist", "open", "disabled"]);
33549
+ var BlockStreamingCoalesceSchema = exports_external.object({
33550
+ minChars: exports_external.number().int().positive().optional(),
33551
+ maxChars: exports_external.number().int().positive().optional(),
33552
+ idleMs: exports_external.number().int().nonnegative().optional()
33553
+ }).strict();
33554
+ var ToolPolicyBaseSchema = exports_external.object({
33555
+ allow: exports_external.array(exports_external.string()).optional(),
33556
+ alsoAllow: exports_external.array(exports_external.string()).optional(),
33557
+ deny: exports_external.array(exports_external.string()).optional()
33558
+ }).strict();
33559
+ var ToolPolicySchema = ToolPolicyBaseSchema.superRefine((value, ctx) => {
33560
+ if (value.allow && value.allow.length > 0 && value.alsoAllow && value.alsoAllow.length > 0) {
33561
+ ctx.addIssue({
33562
+ code: exports_external.ZodIssueCode.custom,
33563
+ message: "tools policy cannot set both allow and alsoAllow in the same scope (merge alsoAllow into allow, or remove allow and use profile + alsoAllow)"
33564
+ });
33565
+ }
33566
+ }).optional();
33567
+ function requireOpenAllowFrom(params) {
33568
+ if (params.policy !== "open") {
33569
+ return;
33570
+ }
33571
+ const allow = (params.allowFrom ?? []).map((entry) => String(entry).trim()).filter(Boolean);
33572
+ if (allow.includes("*")) {
33573
+ return;
33574
+ }
33575
+ params.ctx.addIssue({
33576
+ code: exports_external.ZodIssueCode.custom,
33577
+ path: params.path,
33578
+ message: params.message
33579
+ });
33580
+ }
33581
+ function resolveControlCommandGate(params) {
33582
+ const mode = params.modeWhenAccessGroupsOff ?? "allow";
33583
+ let commandAuthorized = false;
33584
+ if (!params.useAccessGroups) {
33585
+ if (mode === "allow") {
33586
+ commandAuthorized = true;
33587
+ } else if (mode === "deny") {
33588
+ commandAuthorized = false;
33589
+ } else {
33590
+ const anyConfigured = params.authorizers.some((entry) => entry.configured);
33591
+ commandAuthorized = !anyConfigured || params.authorizers.some((entry) => entry.configured && entry.allowed);
33592
+ }
33593
+ } else {
33594
+ commandAuthorized = params.authorizers.some((entry) => entry.configured && entry.allowed);
33595
+ }
33596
+ return {
33597
+ commandAuthorized,
33598
+ shouldBlock: params.allowTextCommands && params.hasControlCommand && !commandAuthorized
33599
+ };
33600
+ }
33601
+ function resolveMentionGatingWithBypass(params) {
33602
+ const shouldBypassMention = params.isGroup && params.requireMention && !params.wasMentioned && !(params.hasAnyMention ?? false) && params.allowTextCommands && params.commandAuthorized && params.hasControlCommand;
33603
+ const effectiveWasMentioned = params.wasMentioned || params.implicitMention === true || shouldBypassMention;
33604
+ return {
33605
+ effectiveWasMentioned,
33606
+ shouldSkip: params.requireMention && params.canDetectMention && !effectiveWasMentioned,
33607
+ shouldBypassMention
33608
+ };
33609
+ }
33610
+ function logInboundDrop(params) {
33611
+ const target = params.target ? ` target=${params.target}` : "";
33612
+ params.log(`${params.channel}: drop ${params.reason}${target}`);
33613
+ }
33614
+ function resolveChannelMediaMaxBytes(params) {
33615
+ const accountId = normalizeAccountId(params.accountId);
33616
+ const channelLimit = params.resolveChannelLimitMb({
33617
+ cfg: params.cfg,
33618
+ accountId
33619
+ });
33620
+ if (channelLimit) {
33621
+ return channelLimit * MB;
33622
+ }
33623
+ if (params.cfg.agents?.defaults?.mediaMaxMb) {
33624
+ return params.cfg.agents.defaults.mediaMaxMb * MB;
33625
+ }
33626
+ return;
33627
+ }
33628
+ function createActionGate(actions) {
33629
+ return (key, defaultValue = true) => {
33630
+ const value = actions?.[key];
33631
+ if (value === undefined) {
33632
+ return defaultValue;
33633
+ }
33634
+ return value !== false;
33635
+ };
33636
+ }
33637
+ function toSnakeCaseKey(key) {
33638
+ return key.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
33639
+ }
33640
+ function readSnakeCaseParamRaw(params, key) {
33641
+ if (Object.hasOwn(params, key)) {
33642
+ return params[key];
33643
+ }
33644
+ const snakeKey = toSnakeCaseKey(key);
33645
+ if (snakeKey !== key && Object.hasOwn(params, snakeKey)) {
33646
+ return params[snakeKey];
33647
+ }
33648
+ return;
33649
+ }
33650
+
33651
+ class ToolInputError extends Error {
33652
+ status = 400;
33653
+ constructor(message) {
33654
+ super(message);
33655
+ this.name = "ToolInputError";
33656
+ }
33657
+ }
33658
+ function readStringParam(params, key, options = {}) {
33659
+ const { required: required2 = false, trim = true, label = key, allowEmpty = false } = options;
33660
+ const raw = readSnakeCaseParamRaw(params, key);
33661
+ if (typeof raw !== "string") {
33662
+ if (required2) {
33663
+ throw new ToolInputError(`${label} required`);
33664
+ }
33665
+ return;
33666
+ }
33667
+ const value = trim ? raw.trim() : raw;
33668
+ if (!value && !allowEmpty) {
33669
+ if (required2) {
33670
+ throw new ToolInputError(`${label} required`);
33671
+ }
33672
+ return;
33673
+ }
33674
+ return value;
33675
+ }
33676
+ function readNumberParam(params, key, options = {}) {
33677
+ const { required: required2 = false, label = key, integer: integer2 = false, strict = false } = options;
33678
+ const raw = readSnakeCaseParamRaw(params, key);
33679
+ let value;
33680
+ if (typeof raw === "number" && Number.isFinite(raw)) {
33681
+ value = raw;
33682
+ } else if (typeof raw === "string") {
33683
+ const trimmed = raw.trim();
33684
+ if (trimmed) {
33685
+ const parsed = strict ? Number(trimmed) : Number.parseFloat(trimmed);
33686
+ if (Number.isFinite(parsed)) {
33687
+ value = parsed;
33688
+ }
33689
+ }
33690
+ }
33691
+ if (value === undefined) {
33692
+ if (required2) {
33693
+ throw new ToolInputError(`${label} required`);
33694
+ }
33695
+ return;
33696
+ }
33697
+ return integer2 ? Math.trunc(value) : value;
33698
+ }
33699
+ function readReactionParams(params, options) {
33700
+ const emojiKey = options.emojiKey ?? "emoji";
33701
+ const removeKey = options.removeKey ?? "remove";
33702
+ const remove = typeof params[removeKey] === "boolean" ? params[removeKey] : false;
33703
+ const emoji3 = readStringParam(params, emojiKey, {
33704
+ required: true,
33705
+ allowEmpty: true
33706
+ });
33707
+ if (remove && !emoji3) {
33708
+ throw new ToolInputError(options.removeErrorMessage);
33709
+ }
33710
+ return { emoji: emoji3 ?? "", remove, isEmpty: !emoji3 };
33711
+ }
33712
+ function jsonResult(payload) {
33713
+ return {
33714
+ content: [
33715
+ {
33716
+ type: "text",
33717
+ text: JSON.stringify(payload, (_key, value) => typeof value === "bigint" ? value.toString() : value, 2)
33718
+ }
33719
+ ],
33720
+ details: payload
33721
+ };
33722
+ }
33723
+
33504
33724
  // src/inline/config-schema.ts
33505
33725
  var InlineActionsSchema = exports_external.object({
33506
33726
  send: exports_external.boolean().optional(),
@@ -33515,6 +33735,9 @@ var InlineActionsSchema = exports_external.object({
33515
33735
  pins: exports_external.boolean().optional(),
33516
33736
  permissions: exports_external.boolean().optional()
33517
33737
  }).strict();
33738
+ var InlineCapabilitiesSchema = exports_external.object({
33739
+ replyThreads: exports_external.boolean().optional()
33740
+ }).strict();
33518
33741
  var InlineGroupSchema = exports_external.object({
33519
33742
  requireMention: exports_external.boolean().optional(),
33520
33743
  systemPrompt: exports_external.string().optional(),
@@ -33531,6 +33754,7 @@ var InlineAccountSchemaBase = exports_external.object({
33531
33754
  baseUrl: exports_external.string().optional(),
33532
33755
  token: exports_external.string().optional(),
33533
33756
  tokenFile: exports_external.string().optional(),
33757
+ capabilities: InlineCapabilitiesSchema.optional(),
33534
33758
  dmPolicy: DmPolicySchema.optional().default("pairing"),
33535
33759
  allowFrom: exports_external.array(exports_external.string()).optional(),
33536
33760
  systemPrompt: exports_external.string().optional(),
@@ -33577,7 +33801,6 @@ var InlineConfigSchema = InlineAccountSchemaBase.extend({
33577
33801
  });
33578
33802
 
33579
33803
  // src/inline/accounts.ts
33580
- import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk";
33581
33804
  import { readFile as readFile2 } from "node:fs/promises";
33582
33805
  var DEFAULT_BASE_URL = "https://api.inline.chat";
33583
33806
  function normalizeInlineAccountId(raw) {
@@ -33655,6 +33878,97 @@ async function resolveInlineToken(account) {
33655
33878
  return token;
33656
33879
  }
33657
33880
 
33881
+ // src/inline/reply-threads.ts
33882
+ var GET_CHAT_METHOD = typeof Method.GET_CHAT === "number" && Number.isInteger(Method.GET_CHAT) && Method.GET_CHAT > 0 ? Method.GET_CHAT : 25;
33883
+ 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;
33884
+ var GET_MESSAGES_METHOD = typeof Method.GET_MESSAGES === "number" && Number.isInteger(Method.GET_MESSAGES) && Method.GET_MESSAGES > 0 ? Method.GET_MESSAGES : 38;
33885
+ function buildChatPeer(chatId) {
33886
+ return {
33887
+ type: {
33888
+ oneofKind: "chat",
33889
+ chat: { chatId }
33890
+ }
33891
+ };
33892
+ }
33893
+ function getInlineReplyThreadsCapabilityConfig(params) {
33894
+ const account = resolveInlineAccount({
33895
+ cfg: params.cfg,
33896
+ accountId: params.accountId ?? null
33897
+ });
33898
+ return {
33899
+ replyThreads: account.config.capabilities?.replyThreads === true
33900
+ };
33901
+ }
33902
+ function isInlineReplyThreadsEnabled(params) {
33903
+ return getInlineReplyThreadsCapabilityConfig(params).replyThreads;
33904
+ }
33905
+ function resolveInlineReplyThreadChatId(params) {
33906
+ if (!isInlineReplyThreadsEnabled({ cfg: params.cfg, accountId: params.accountId ?? null })) {
33907
+ return params.parentChatId;
33908
+ }
33909
+ if (params.parentChatId == null) {
33910
+ return null;
33911
+ }
33912
+ if (params.threadId == null) {
33913
+ return params.parentChatId;
33914
+ }
33915
+ const normalized = typeof params.threadId === "number" ? Number.isFinite(params.threadId) && Number.isInteger(params.threadId) && params.threadId >= 0 ? BigInt(params.threadId) : null : typeof params.threadId === "string" ? params.threadId.trim() ? (() => {
33916
+ try {
33917
+ return BigInt(params.threadId.trim());
33918
+ } catch {
33919
+ return null;
33920
+ }
33921
+ })() : null : null;
33922
+ return normalized ?? params.parentChatId;
33923
+ }
33924
+ async function loadInlineReplyThreadMetadata(params) {
33925
+ const result = await params.client.invokeRaw(GET_CHAT_METHOD, {
33926
+ oneofKind: "getChat",
33927
+ getChat: { peerId: buildChatPeer(params.chatId) }
33928
+ }).catch(() => null);
33929
+ if (result?.oneofKind !== "getChat") {
33930
+ return null;
33931
+ }
33932
+ const chat = result.getChat.chat;
33933
+ const parentChatId = chat?.parentChatId;
33934
+ if (parentChatId == null) {
33935
+ return null;
33936
+ }
33937
+ return {
33938
+ childChatId: chat?.id ?? params.chatId,
33939
+ parentChatId,
33940
+ parentMessageId: chat?.parentMessageId ?? null,
33941
+ title: chat?.title?.trim() || null
33942
+ };
33943
+ }
33944
+ async function loadInlineReplyThreadAnchorMessage(params) {
33945
+ const directResult = await params.client.invokeRaw(GET_MESSAGES_METHOD, {
33946
+ oneofKind: "getMessages",
33947
+ getMessages: {
33948
+ peerId: buildChatPeer(params.parentChatId),
33949
+ messageIds: [params.parentMessageId]
33950
+ }
33951
+ }).catch(() => null);
33952
+ if (directResult?.oneofKind === "getMessages") {
33953
+ const directTarget = (directResult.getMessages.messages ?? []).find((item) => item.id === params.parentMessageId) ?? null;
33954
+ if (directTarget) {
33955
+ return directTarget;
33956
+ }
33957
+ }
33958
+ const historyResult = await params.client.invokeRaw(GET_CHAT_HISTORY_METHOD, {
33959
+ oneofKind: "getChatHistory",
33960
+ getChatHistory: {
33961
+ peerId: buildChatPeer(params.parentChatId),
33962
+ offsetId: params.parentMessageId + 1n,
33963
+ limit: 8
33964
+ }
33965
+ }).catch(() => null);
33966
+ if (historyResult?.oneofKind !== "getChatHistory") {
33967
+ return null;
33968
+ }
33969
+ return (historyResult.getChatHistory.messages ?? []).find((item) => item.id === params.parentMessageId) ?? null;
33970
+ }
33971
+
33658
33972
  // src/inline/normalize.ts
33659
33973
  function normalizeInlineTarget(raw) {
33660
33974
  let normalized = raw.trim();
@@ -33683,17 +33997,255 @@ function looksLikeInlineTargetId(raw, normalizedInput) {
33683
33997
  // src/inline/monitor.ts
33684
33998
  import { mkdir } from "node:fs/promises";
33685
33999
  import path2 from "node:path";
33686
- import {
33687
- buildPendingHistoryContextFromMap,
33688
- clearHistoryEntriesIfEnabled,
33689
- createReplyPrefixOptions,
33690
- createTypingCallbacks,
33691
- logInboundDrop,
33692
- recordPendingHistoryEntryIfEnabled,
33693
- resolveChannelMediaMaxBytes as resolveChannelMediaMaxBytes2,
33694
- resolveControlCommandGate,
33695
- resolveMentionGatingWithBypass
33696
- } from "openclaw/plugin-sdk";
34000
+
34001
+ // src/sdk-runtime-compat.ts
34002
+ var HISTORY_CONTEXT_MARKER = "[Chat messages since your last reply - for context]";
34003
+ var CURRENT_MESSAGE_MARKER = "[Current message - respond to this]";
34004
+ var MAX_HISTORY_KEYS = 1000;
34005
+ var DEFAULT_GROUP_HISTORY_LIMIT = 50;
34006
+ function evictOldHistoryKeys(historyMap, maxKeys = MAX_HISTORY_KEYS) {
34007
+ if (historyMap.size <= maxKeys) {
34008
+ return;
34009
+ }
34010
+ const keysToDelete = historyMap.size - maxKeys;
34011
+ const iterator = historyMap.keys();
34012
+ for (let index = 0;index < keysToDelete; index += 1) {
34013
+ const key = iterator.next().value;
34014
+ if (key !== undefined) {
34015
+ historyMap.delete(key);
34016
+ }
34017
+ }
34018
+ }
34019
+ function buildHistoryContext(params) {
34020
+ const lineBreak = params.lineBreak ?? `
34021
+ `;
34022
+ if (!params.historyText.trim()) {
34023
+ return params.currentMessage;
34024
+ }
34025
+ return [
34026
+ HISTORY_CONTEXT_MARKER,
34027
+ params.historyText,
34028
+ "",
34029
+ CURRENT_MESSAGE_MARKER,
34030
+ params.currentMessage
34031
+ ].join(lineBreak);
34032
+ }
34033
+ function appendHistoryEntry(params) {
34034
+ if (params.limit <= 0) {
34035
+ return [];
34036
+ }
34037
+ const history = params.historyMap.get(params.historyKey) ?? [];
34038
+ history.push(params.entry);
34039
+ while (history.length > params.limit) {
34040
+ history.shift();
34041
+ }
34042
+ if (params.historyMap.has(params.historyKey)) {
34043
+ params.historyMap.delete(params.historyKey);
34044
+ }
34045
+ params.historyMap.set(params.historyKey, history);
34046
+ evictOldHistoryKeys(params.historyMap);
34047
+ return history;
34048
+ }
34049
+ function buildHistoryContextFromEntries(params) {
34050
+ const lineBreak = params.lineBreak ?? `
34051
+ `;
34052
+ const entries = params.excludeLast === false ? params.entries : params.entries.slice(0, -1);
34053
+ if (entries.length === 0) {
34054
+ return params.currentMessage;
34055
+ }
34056
+ return buildHistoryContext({
34057
+ historyText: entries.map(params.formatEntry).join(lineBreak),
34058
+ currentMessage: params.currentMessage,
34059
+ lineBreak
34060
+ });
34061
+ }
34062
+ function buildPendingHistoryContextFromMap(params) {
34063
+ if (params.limit <= 0) {
34064
+ return params.currentMessage;
34065
+ }
34066
+ const entries = params.historyMap.get(params.historyKey) ?? [];
34067
+ return buildHistoryContextFromEntries({
34068
+ entries,
34069
+ currentMessage: params.currentMessage,
34070
+ formatEntry: params.formatEntry,
34071
+ ...params.lineBreak !== undefined ? { lineBreak: params.lineBreak } : {},
34072
+ excludeLast: false
34073
+ });
34074
+ }
34075
+ function clearHistoryEntriesIfEnabled(params) {
34076
+ if (params.limit <= 0) {
34077
+ return;
34078
+ }
34079
+ params.historyMap.set(params.historyKey, []);
34080
+ }
34081
+ function recordPendingHistoryEntryIfEnabled(params) {
34082
+ if (!params.entry || params.limit <= 0) {
34083
+ return [];
34084
+ }
34085
+ return appendHistoryEntry({
34086
+ historyMap: params.historyMap,
34087
+ historyKey: params.historyKey,
34088
+ entry: params.entry,
34089
+ limit: params.limit
34090
+ });
34091
+ }
34092
+ function createMessageToolButtonsSchemaCompat() {
34093
+ return {
34094
+ type: "array",
34095
+ description: "Button rows for channels that support button-style actions.",
34096
+ items: {
34097
+ type: "array",
34098
+ items: {
34099
+ type: "object",
34100
+ additionalProperties: false,
34101
+ required: ["text", "callback_data"],
34102
+ properties: {
34103
+ text: { type: "string" },
34104
+ callback_data: { type: "string" },
34105
+ style: { type: "string", enum: ["danger", "success", "primary"] }
34106
+ }
34107
+ }
34108
+ }
34109
+ };
34110
+ }
34111
+ function extensionForMimeCompat(mime) {
34112
+ const normalized = mime?.trim().toLowerCase();
34113
+ if (!normalized)
34114
+ return;
34115
+ const directMap = {
34116
+ "image/jpeg": "jpg",
34117
+ "image/jpg": "jpg",
34118
+ "image/png": "png",
34119
+ "image/gif": "gif",
34120
+ "image/webp": "webp",
34121
+ "video/mp4": "mp4",
34122
+ "audio/mpeg": "mp3",
34123
+ "audio/mp4": "m4a",
34124
+ "audio/wav": "wav",
34125
+ "audio/ogg": "ogg",
34126
+ "application/pdf": "pdf",
34127
+ "text/plain": "txt"
34128
+ };
34129
+ const mapped = directMap[normalized];
34130
+ if (mapped)
34131
+ return mapped;
34132
+ const [, subtype] = normalized.split("/", 2);
34133
+ return subtype?.split("+", 1)[0] || undefined;
34134
+ }
34135
+ function createInlineTypingCallbacks(params) {
34136
+ const keepaliveIntervalMs = params.keepaliveIntervalMs ?? 3000;
34137
+ const maxConsecutiveFailures = Math.max(1, params.maxConsecutiveFailures ?? 2);
34138
+ const maxDurationMs = params.maxDurationMs ?? 60000;
34139
+ let closed = false;
34140
+ let stopSent = false;
34141
+ let consecutiveFailures = 0;
34142
+ let keepaliveTimer;
34143
+ let ttlTimer;
34144
+ const clearTimers = () => {
34145
+ if (keepaliveTimer) {
34146
+ clearInterval(keepaliveTimer);
34147
+ keepaliveTimer = undefined;
34148
+ }
34149
+ if (ttlTimer) {
34150
+ clearTimeout(ttlTimer);
34151
+ ttlTimer = undefined;
34152
+ }
34153
+ };
34154
+ const fireStop = () => {
34155
+ closed = true;
34156
+ clearTimers();
34157
+ if (!params.stop || stopSent) {
34158
+ return;
34159
+ }
34160
+ stopSent = true;
34161
+ params.stop().catch((err) => (params.onStopError ?? params.onStartError)(err));
34162
+ };
34163
+ const fireStart = async () => {
34164
+ if (closed)
34165
+ return;
34166
+ try {
34167
+ await params.start();
34168
+ consecutiveFailures = 0;
34169
+ } catch (err) {
34170
+ consecutiveFailures += 1;
34171
+ params.onStartError(err);
34172
+ if (consecutiveFailures >= maxConsecutiveFailures) {
34173
+ fireStop();
34174
+ }
34175
+ }
34176
+ };
34177
+ return {
34178
+ onReplyStart: async () => {
34179
+ if (closed)
34180
+ return;
34181
+ stopSent = false;
34182
+ consecutiveFailures = 0;
34183
+ clearTimers();
34184
+ await fireStart();
34185
+ if (closed)
34186
+ return;
34187
+ keepaliveTimer = setInterval(() => {
34188
+ fireStart();
34189
+ }, keepaliveIntervalMs);
34190
+ if (maxDurationMs > 0) {
34191
+ ttlTimer = setTimeout(() => {
34192
+ fireStop();
34193
+ }, maxDurationMs);
34194
+ }
34195
+ },
34196
+ onIdle: fireStop,
34197
+ onCleanup: fireStop
34198
+ };
34199
+ }
34200
+ async function createChannelReplyPipelineCompat(params) {
34201
+ try {
34202
+ const sdk = await import("openclaw/plugin-sdk/channel-reply-pipeline");
34203
+ return sdk.createChannelReplyPipeline(params);
34204
+ } catch {
34205
+ return {
34206
+ onModelSelected: () => {},
34207
+ ...params.typingCallbacks ? { typingCallbacks: params.typingCallbacks } : params.typing ? { typingCallbacks: createInlineTypingCallbacks(params.typing) } : {}
34208
+ };
34209
+ }
34210
+ }
34211
+ async function loadNativeCommandHelpersCompat() {
34212
+ try {
34213
+ const sdk = await import("openclaw/plugin-sdk/command-auth");
34214
+ const listNativeCommandSpecsForConfig = typeof sdk.listNativeCommandSpecsForConfig === "function" ? sdk.listNativeCommandSpecsForConfig : null;
34215
+ const listSkillCommandsForAgents = typeof sdk.listSkillCommandsForAgents === "function" ? sdk.listSkillCommandsForAgents : null;
34216
+ if (!listNativeCommandSpecsForConfig || !listSkillCommandsForAgents) {
34217
+ throw new Error("command-auth helpers unavailable");
34218
+ }
34219
+ return {
34220
+ available: true,
34221
+ listNativeCommandSpecsForConfig,
34222
+ listSkillCommandsForAgents
34223
+ };
34224
+ } catch {
34225
+ return {
34226
+ available: false,
34227
+ listNativeCommandSpecsForConfig: () => [],
34228
+ listSkillCommandsForAgents: () => []
34229
+ };
34230
+ }
34231
+ }
34232
+ async function loadPluginCommandSpecsCompat(provider) {
34233
+ try {
34234
+ const sdk = await import("openclaw/plugin-sdk/plugin-runtime");
34235
+ if (typeof sdk.getPluginCommandSpecs !== "function") {
34236
+ throw new Error("plugin runtime command helper unavailable");
34237
+ }
34238
+ return {
34239
+ available: true,
34240
+ specs: sdk.getPluginCommandSpecs(provider)
34241
+ };
34242
+ } catch {
34243
+ return {
34244
+ available: false,
34245
+ specs: []
34246
+ };
34247
+ }
34248
+ }
33697
34249
 
33698
34250
  // src/inline/message-formatting.ts
33699
34251
  var INLINE_FORMATTING_NOTE = "Inline formatting note: prefer bullet lists over markdown tables. If a table is necessary, render it inside a fenced code block. Do not wrap bare URLs in inline code or backticks. Use plain URLs or markdown links. Use inline code only for actual code, commands, file paths, env vars, or identifiers.";
@@ -33720,9 +34272,8 @@ function sanitizeInlineOutgoingText(text) {
33720
34272
  }
33721
34273
 
33722
34274
  // src/inline/policy.ts
33723
- import { normalizeAccountId as normalizePluginAccountId } from "openclaw/plugin-sdk";
33724
34275
  function normalizeAccountId2(raw) {
33725
- return normalizePluginAccountId(raw);
34276
+ return normalizeAccountId(raw);
33726
34277
  }
33727
34278
  function resolveInlineGroups(cfg, accountId) {
33728
34279
  const inline = cfg.channels?.inline;
@@ -33840,19 +34391,12 @@ function getInlineRuntime() {
33840
34391
 
33841
34392
  // src/inline/media.ts
33842
34393
  import path from "node:path";
33843
- import {
33844
- detectMime,
33845
- extensionForMime,
33846
- loadWebMedia,
33847
- resolveChannelMediaMaxBytes
33848
- } from "openclaw/plugin-sdk";
33849
34394
  var DEFAULT_MEDIA_MAX_MB = 300;
33850
34395
  var SUPPORTED_INLINE_PHOTO_MIME = new Set(["image/jpeg", "image/png", "image/gif"]);
33851
34396
  var SUPPORTED_INLINE_VIDEO_MIME = new Set(["video/mp4"]);
33852
34397
  var DEFAULT_VIDEO_WIDTH = 1280;
33853
34398
  var DEFAULT_VIDEO_HEIGHT = 720;
33854
34399
  var DEFAULT_VIDEO_DURATION = 1;
33855
- var loadWebMediaCompat = loadWebMedia;
33856
34400
  function looksLikeLocalMediaSource(mediaUrl) {
33857
34401
  return !/^https?:\/\//i.test(mediaUrl.trim());
33858
34402
  }
@@ -33895,7 +34439,7 @@ function ensureUploadFileName(params) {
33895
34439
  if (ext)
33896
34440
  return baseName;
33897
34441
  }
33898
- const inferredExt = params.ext ?? extensionForMime(params.mime) ?? undefined;
34442
+ const inferredExt = params.ext ?? extensionForMimeCompat(params.mime) ?? undefined;
33899
34443
  const fallbackExt = inferredExt ?? (params.uploadType === "photo" ? "jpg" : params.uploadType === "video" ? "mp4" : "bin");
33900
34444
  return `attachment.${fallbackExt}`;
33901
34445
  }
@@ -33973,13 +34517,15 @@ async function uploadInlineMediaFromUrl(params) {
33973
34517
  cfg: params.cfg,
33974
34518
  accountId: params.accountId ?? null
33975
34519
  });
34520
+ const runtimeMedia = getInlineRuntime().media;
34521
+ const loadWebMediaCompat = runtimeMedia.loadWebMedia;
33976
34522
  let loaded;
33977
34523
  let detectedMime;
33978
34524
  let uploadType;
33979
34525
  let fileName;
33980
34526
  try {
33981
34527
  try {
33982
- loaded = await loadWebMedia(params.mediaUrl, maxBytes);
34528
+ loaded = await runtimeMedia.loadWebMedia(params.mediaUrl, maxBytes);
33983
34529
  } catch (error48) {
33984
34530
  const message = String(error48);
33985
34531
  const deniedLocalPath = /not under an allowed directory/i.test(message);
@@ -33993,7 +34539,7 @@ async function uploadInlineMediaFromUrl(params) {
33993
34539
  if (!loaded) {
33994
34540
  throw new Error("inline media upload: media load returned no data");
33995
34541
  }
33996
- detectedMime = normalizeMime(loaded.contentType ?? await detectMime({
34542
+ detectedMime = normalizeMime(loaded.contentType ?? await runtimeMedia.detectMime({
33997
34543
  buffer: loaded.buffer,
33998
34544
  ...loaded.fileName ? { filePath: loaded.fileName } : {}
33999
34545
  }));
@@ -34583,7 +35129,6 @@ function resolveInlineCompatNativeCommandMenu(commandBody) {
34583
35129
 
34584
35130
  // src/inline/monitor.ts
34585
35131
  var CHANNEL_ID = "inline";
34586
- var DEFAULT_GROUP_HISTORY_LIMIT = 12;
34587
35132
  var DEFAULT_DM_HISTORY_LIMIT = 6;
34588
35133
  var HISTORY_LINE_MAX_CHARS = 280;
34589
35134
  var BOT_MESSAGE_CACHE_LIMIT = 500;
@@ -34591,7 +35136,7 @@ var REACTION_TARGET_LOOKUP_LIMIT = 8;
34591
35136
  var REPLY_TARGET_LOOKUP_LIMIT = 8;
34592
35137
  var ATTACHMENT_CONTEXT_LIMIT = 6;
34593
35138
  var DEFAULT_INLINE_MEDIA_MAX_BYTES = 300 * 1024 * 1024;
34594
- var GET_MESSAGES_METHOD = typeof Method.GET_MESSAGES === "number" && Number.isInteger(Method.GET_MESSAGES) && Method.GET_MESSAGES > 0 ? Method.GET_MESSAGES : null;
35139
+ var GET_MESSAGES_METHOD2 = typeof Method.GET_MESSAGES === "number" && Number.isInteger(Method.GET_MESSAGES) && Method.GET_MESSAGES > 0 ? Method.GET_MESSAGES : null;
34595
35140
  function normalizeAllowEntry(raw) {
34596
35141
  return raw.trim().replace(/^inline:/i, "").replace(/^user:/i, "");
34597
35142
  }
@@ -34815,7 +35360,7 @@ function rememberBotMessagesFromList(params) {
34815
35360
  }
34816
35361
  }
34817
35362
  }
34818
- function buildChatPeer(chatId) {
35363
+ function buildChatPeer2(chatId) {
34819
35364
  return {
34820
35365
  type: {
34821
35366
  oneofKind: "chat",
@@ -34827,7 +35372,7 @@ async function loadChatHistoryMessages(params) {
34827
35372
  const result = await params.client.invokeRaw(Method.GET_CHAT_HISTORY, {
34828
35373
  oneofKind: "getChatHistory",
34829
35374
  getChatHistory: {
34830
- peerId: buildChatPeer(params.chatId),
35375
+ peerId: buildChatPeer2(params.chatId),
34831
35376
  ...params.offsetId != null ? { offsetId: params.offsetId } : {},
34832
35377
  limit: params.limit
34833
35378
  }
@@ -34838,10 +35383,10 @@ async function loadChatHistoryMessages(params) {
34838
35383
  return result.getChatHistory.messages ?? [];
34839
35384
  }
34840
35385
  async function findChatMessageById(params) {
34841
- const directResult = GET_MESSAGES_METHOD == null ? null : await params.client.invokeRaw(GET_MESSAGES_METHOD, {
35386
+ const directResult = GET_MESSAGES_METHOD2 == null ? null : await params.client.invokeRaw(GET_MESSAGES_METHOD2, {
34842
35387
  oneofKind: "getMessages",
34843
35388
  getMessages: {
34844
- peerId: buildChatPeer(params.chatId),
35389
+ peerId: buildChatPeer2(params.chatId),
34845
35390
  messageIds: [params.messageId]
34846
35391
  }
34847
35392
  }).catch(() => null);
@@ -34939,12 +35484,129 @@ function resolveHistorySenderLabel(params) {
34939
35484
  }
34940
35485
  function resolveHistoryLimit(params) {
34941
35486
  if (params.isGroup) {
34942
- return params.historyLimit ?? DEFAULT_GROUP_HISTORY_LIMIT;
35487
+ return Math.max(0, params.historyLimit ?? params.cfg.messages?.groupChat?.historyLimit ?? DEFAULT_GROUP_HISTORY_LIMIT);
35488
+ }
35489
+ return Math.max(0, params.dmHistoryLimit ?? params.historyLimit ?? DEFAULT_DM_HISTORY_LIMIT);
35490
+ }
35491
+ function historyEntryDedupeKey(entry) {
35492
+ if (entry.messageId)
35493
+ return `id:${entry.messageId}`;
35494
+ return `ts:${entry.timestamp ?? "unknown"}:${entry.sender}:${entry.body}`;
35495
+ }
35496
+ function mergeInboundHistoryEntries(params) {
35497
+ if (params.limit <= 0)
35498
+ return [];
35499
+ const deduped = [];
35500
+ const seen = new Set;
35501
+ for (const entry of [...params.historyContextEntries, ...params.pendingEntries]) {
35502
+ const key = historyEntryDedupeKey(entry);
35503
+ if (seen.has(key))
35504
+ continue;
35505
+ seen.add(key);
35506
+ deduped.push(entry);
34943
35507
  }
34944
- return params.dmHistoryLimit ?? params.historyLimit ?? DEFAULT_DM_HISTORY_LIMIT;
35508
+ return deduped.slice(-params.limit).map((entry) => ({
35509
+ sender: entry.sender,
35510
+ body: entry.body,
35511
+ ...entry.timestamp != null ? { timestamp: entry.timestamp } : {}
35512
+ }));
35513
+ }
35514
+ function buildInlineHistoryEntryPayload(params) {
35515
+ const content = summarizeInlineMessageContent(params.message);
35516
+ const text = normalizeHistoryText(content.text);
35517
+ if (!text) {
35518
+ return {
35519
+ line: null,
35520
+ attachmentLine: null,
35521
+ entityLine: null,
35522
+ inboundEntry: null
35523
+ };
35524
+ }
35525
+ const label = resolveHistorySenderLabel({
35526
+ senderId: params.message.fromId,
35527
+ meId: params.meId,
35528
+ senderProfilesById: params.senderProfilesById
35529
+ });
35530
+ const replySuffix = params.message.replyToMsgId != null ? ` ->${String(params.message.replyToMsgId)}` : "";
35531
+ const messageId = params.syntheticMessageId ?? String(params.message.id);
35532
+ const attachmentText = normalizeHistoryText(content.attachmentText);
35533
+ const entityText = normalizeHistoryText(content.entityText);
35534
+ return {
35535
+ line: `#${String(params.message.id)}${replySuffix} ${label}: ${text}`,
35536
+ attachmentLine: attachmentText ? `#${String(params.message.id)}${replySuffix} ${label}: ${attachmentText}` : null,
35537
+ entityLine: entityText ? `#${String(params.message.id)}${replySuffix} ${label}: ${entityText}` : null,
35538
+ inboundEntry: {
35539
+ sender: label,
35540
+ body: text,
35541
+ ...params.message.date != null ? { timestamp: Number(params.message.date) * 1000 } : {},
35542
+ messageId
35543
+ }
35544
+ };
35545
+ }
35546
+ function appendInlineHistoryEntry(target, entry) {
35547
+ if (!entry.inboundEntry || !entry.line)
35548
+ return;
35549
+ target.inboundHistory.push(entry.inboundEntry);
35550
+ target.lines.push(entry.line);
35551
+ if (entry.attachmentLine) {
35552
+ target.attachmentLines.push(entry.attachmentLine);
35553
+ }
35554
+ if (entry.entityLine) {
35555
+ target.entityLines.push(entry.entityLine);
35556
+ }
35557
+ }
35558
+ function prependLabeledHistoryLine(params) {
35559
+ if (!params.line)
35560
+ return params.existing;
35561
+ const prefix = `${params.heading}
35562
+ `;
35563
+ const existingBody = params.existing?.startsWith(prefix) ? params.existing.slice(prefix.length) : params.existing;
35564
+ return existingBody ? `${prefix}${params.line}
35565
+ ${existingBody}` : `${prefix}${params.line}`;
35566
+ }
35567
+ function prependInlineReplyThreadAnchor(params) {
35568
+ const entry = buildInlineHistoryEntryPayload({
35569
+ message: params.anchorMessage,
35570
+ senderProfilesById: params.senderProfilesById,
35571
+ meId: params.meId,
35572
+ syntheticMessageId: `anchor:${String(params.parentChatId)}:${String(params.anchorMessage.id)}`
35573
+ });
35574
+ if (!entry.inboundEntry || !entry.line) {
35575
+ return params.historyContext;
35576
+ }
35577
+ return {
35578
+ ...params.historyContext,
35579
+ inboundHistory: [entry.inboundEntry, ...params.historyContext.inboundHistory],
35580
+ historyText: prependLabeledHistoryLine({
35581
+ existing: params.historyContext.historyText,
35582
+ heading: "Recent thread messages (oldest -> newest):",
35583
+ line: entry.line
35584
+ }),
35585
+ attachmentText: prependLabeledHistoryLine({
35586
+ existing: params.historyContext.attachmentText,
35587
+ heading: "Recent media/attachments:",
35588
+ line: entry.attachmentLine
35589
+ }),
35590
+ entityText: prependLabeledHistoryLine({
35591
+ existing: params.historyContext.entityText,
35592
+ heading: "Recent message entities:",
35593
+ line: entry.entityLine
35594
+ })
35595
+ };
35596
+ }
35597
+ function buildInlineBodyForAgent(params) {
35598
+ return [
35599
+ params.rawBody,
35600
+ params.currentAttachmentText && params.currentAttachmentText !== params.rawBody ? `Current media/attachments:
35601
+ ${params.currentAttachmentText}` : null,
35602
+ params.currentEntityText ? `Current message entities:
35603
+ ${params.currentEntityText}` : null
35604
+ ].filter(Boolean).join(`
35605
+
35606
+ `) || params.rawBody;
34945
35607
  }
34946
35608
  function resolveInlineMediaMaxBytes(params) {
34947
- return resolveChannelMediaMaxBytes2({
35609
+ return resolveChannelMediaMaxBytes({
34948
35610
  cfg: params.cfg,
34949
35611
  accountId: params.account.accountId,
34950
35612
  resolveChannelLimitMb: ({ accountId }) => {
@@ -35035,7 +35697,35 @@ async function resolveInlineInboundMedia(params) {
35035
35697
  }
35036
35698
  return out;
35037
35699
  }
35038
- async function buildHistoryContext(params) {
35700
+ async function resolveInlineInboundReplyThreadContext(params) {
35701
+ if (params.chatInfo.kind === "direct" || !params.replyThreadsEnabled) {
35702
+ return null;
35703
+ }
35704
+ const metadata = await loadInlineReplyThreadMetadata({
35705
+ client: params.client,
35706
+ chatId: params.chatId
35707
+ });
35708
+ if (!metadata) {
35709
+ return null;
35710
+ }
35711
+ const parentChatInfo = metadata.parentChatId === params.chatId ? params.chatInfo : await resolveChatInfo(params.client, params.chatCache, metadata.parentChatId).catch(() => ({
35712
+ kind: "group",
35713
+ title: null
35714
+ }));
35715
+ const anchorMessage = metadata.parentMessageId != null ? await loadInlineReplyThreadAnchorMessage({
35716
+ client: params.client,
35717
+ parentChatId: metadata.parentChatId,
35718
+ parentMessageId: metadata.parentMessageId
35719
+ }).catch(() => null) : null;
35720
+ return {
35721
+ childChatId: metadata.childChatId,
35722
+ parentChatId: metadata.parentChatId,
35723
+ parentChatTitle: parentChatInfo.title ?? null,
35724
+ threadLabel: metadata.title ?? params.chatInfo.title ?? null,
35725
+ anchorMessage
35726
+ };
35727
+ }
35728
+ async function buildHistoryContext2(params) {
35039
35729
  const cachedReplyToBot = params.replyToMsgId != null && hasBotMessageId(params.botMessageIdsByChat, params.chatId, params.replyToMsgId);
35040
35730
  let repliedToBot = cachedReplyToBot;
35041
35731
  let replyToSenderId = null;
@@ -35043,6 +35733,7 @@ async function buildHistoryContext(params) {
35043
35733
  const lines = [];
35044
35734
  const attachmentLines = [];
35045
35735
  const entityLines = [];
35736
+ const inboundHistory = [];
35046
35737
  if (params.historyLimit > 0) {
35047
35738
  const messages = await loadChatHistoryMessages({
35048
35739
  client: params.client,
@@ -35070,25 +35761,16 @@ async function buildHistoryContext(params) {
35070
35761
  replyToSenderId = String(item.fromId);
35071
35762
  repliedToBot = item.fromId === params.meId;
35072
35763
  }
35073
- const content = summarizeInlineMessageContent(item);
35074
- const text = normalizeHistoryText(content.text);
35075
- if (!text)
35076
- continue;
35077
- const label = resolveHistorySenderLabel({
35078
- senderId: item.fromId,
35079
- meId: params.meId,
35080
- senderProfilesById: params.senderProfilesById
35081
- });
35082
- const replySuffix = item.replyToMsgId != null ? ` ->${String(item.replyToMsgId)}` : "";
35083
- lines.push(`#${String(item.id)}${replySuffix} ${label}: ${text}`);
35084
- const attachmentText = normalizeHistoryText(content.attachmentText);
35085
- if (attachmentText) {
35086
- attachmentLines.push(`#${String(item.id)}${replySuffix} ${label}: ${attachmentText}`);
35087
- }
35088
- const entityText = normalizeHistoryText(content.entityText);
35089
- if (entityText) {
35090
- entityLines.push(`#${String(item.id)}${replySuffix} ${label}: ${entityText}`);
35091
- }
35764
+ appendInlineHistoryEntry({
35765
+ lines,
35766
+ attachmentLines,
35767
+ entityLines,
35768
+ inboundHistory
35769
+ }, buildInlineHistoryEntryPayload({
35770
+ message: item,
35771
+ senderProfilesById: params.senderProfilesById,
35772
+ meId: params.meId
35773
+ }));
35092
35774
  }
35093
35775
  }
35094
35776
  }
@@ -35115,6 +35797,7 @@ async function buildHistoryContext(params) {
35115
35797
  `) : null,
35116
35798
  entityText: entityLines.length ? entityLines.slice(-ATTACHMENT_CONTEXT_LIMIT).join(`
35117
35799
  `) : null,
35800
+ inboundHistory,
35118
35801
  repliedToBot,
35119
35802
  replyToSenderId
35120
35803
  };
@@ -35129,6 +35812,7 @@ ${attachmentLines.slice(-ATTACHMENT_CONTEXT_LIMIT).join(`
35129
35812
  entityText: entityLines.length ? `Recent message entities:
35130
35813
  ${entityLines.slice(-ATTACHMENT_CONTEXT_LIMIT).join(`
35131
35814
  `)}` : null,
35815
+ inboundHistory,
35132
35816
  repliedToBot,
35133
35817
  replyToSenderId
35134
35818
  };
@@ -35344,6 +36028,19 @@ async function monitorInlineProvider(params) {
35344
36028
  statusSink?.({ lastError: `getChat failed: ${String(err)}` });
35345
36029
  }
35346
36030
  const isGroup = chatInfo.kind !== "direct";
36031
+ const replyThreadsEnabled = account.config.capabilities?.replyThreads === true || isInlineReplyThreadsEnabled({ cfg, accountId: account.accountId });
36032
+ const replyThreadContext = await resolveInlineInboundReplyThreadContext({
36033
+ replyThreadsEnabled,
36034
+ client,
36035
+ chatId,
36036
+ chatInfo,
36037
+ chatCache
36038
+ }).catch((err) => {
36039
+ statusSink?.({ lastError: `getChat (reply thread) failed: ${String(err)}` });
36040
+ return null;
36041
+ });
36042
+ const effectiveChatId = replyThreadContext?.parentChatId ?? chatId;
36043
+ const effectiveGroupTitle = replyThreadContext?.parentChatTitle ?? chatInfo.title ?? null;
35347
36044
  const senderId = String(msg.fromId);
35348
36045
  await hydrateChatParticipants(chatId);
35349
36046
  const senderProfile = senderProfilesById.get(senderId);
@@ -35477,7 +36174,7 @@ ${JSON.stringify(payload)}`;
35477
36174
  }
35478
36175
  }
35479
36176
  }
35480
- if (commandGate.shouldBlock) {
36177
+ if (isGroup && commandGate.shouldBlock) {
35481
36178
  logInboundDrop({
35482
36179
  log: (m) => runtime2.log?.(m),
35483
36180
  channel: CHANNEL_ID,
@@ -35495,7 +36192,7 @@ ${JSON.stringify(payload)}`;
35495
36192
  accountId: account.accountId,
35496
36193
  peer: {
35497
36194
  kind: isGroup ? "group" : "direct",
35498
- id: isGroup ? String(chatId) : senderId
36195
+ id: isGroup ? String(effectiveChatId) : senderId
35499
36196
  }
35500
36197
  });
35501
36198
  const mentionRegexes = core3.channel.mentions.buildMentionRegexes(cfg, route.agentId);
@@ -35503,14 +36200,15 @@ ${JSON.stringify(payload)}`;
35503
36200
  const patternMentioned = mentionRegexes.length ? core3.channel.mentions.matchesMentionPatterns(rawBody, mentionRegexes) : false;
35504
36201
  const wasMentioned = nativeMentioned || patternMentioned;
35505
36202
  const messageTimestamp = Number(msg.date) * 1000;
35506
- const groupHistoryKey = isGroup ? route.sessionKey : null;
36203
+ const groupHistoryKey = isGroup ? replyThreadContext ? `${route.sessionKey}:thread:${String(replyThreadContext.childChatId)}` : route.sessionKey : null;
35507
36204
  const pendingHistorySender = senderUsername ? `@${senderUsername}` : senderName ?? `user:${senderId}`;
35508
36205
  const historyLimit = resolveHistoryLimit({
36206
+ cfg,
35509
36207
  isGroup,
35510
36208
  historyLimit: account.config.historyLimit,
35511
36209
  dmHistoryLimit: account.config.dmHistoryLimit
35512
36210
  });
35513
- const historyContext = await buildHistoryContext({
36211
+ const historyContext = await buildHistoryContext2({
35514
36212
  client,
35515
36213
  chatId,
35516
36214
  currentMessageId: msg.id,
@@ -35521,12 +36219,26 @@ ${JSON.stringify(payload)}`;
35521
36219
  botMessageIdsByChat
35522
36220
  }).catch((err) => {
35523
36221
  statusSink?.({ lastError: `getChatHistory failed: ${String(err)}` });
35524
- return { historyText: null, attachmentText: null, entityText: null, repliedToBot: false, replyToSenderId: null };
36222
+ return {
36223
+ historyText: null,
36224
+ attachmentText: null,
36225
+ entityText: null,
36226
+ inboundHistory: [],
36227
+ repliedToBot: false,
36228
+ replyToSenderId: null
36229
+ };
35525
36230
  });
35526
- const implicitMention = (reactionEvent != null || callbackActionEvent != null) && isGroup || isGroup && (account.config.replyToBotWithoutMention ?? false) && msg.replyToMsgId != null && historyContext.repliedToBot;
36231
+ const effectiveHistoryContext = replyThreadContext?.anchorMessage != null ? prependInlineReplyThreadAnchor({
36232
+ historyContext,
36233
+ anchorMessage: replyThreadContext.anchorMessage,
36234
+ parentChatId: replyThreadContext.parentChatId,
36235
+ senderProfilesById,
36236
+ meId
36237
+ }) : historyContext;
36238
+ const implicitMention = (reactionEvent != null || callbackActionEvent != null) && isGroup || isGroup && (account.config.replyToBotWithoutMention ?? false) && msg.replyToMsgId != null && effectiveHistoryContext.repliedToBot;
35527
36239
  const requireMention = isGroup ? resolveInlineGroupRequireMention({
35528
36240
  cfg,
35529
- groupId: String(chatId),
36241
+ groupId: String(effectiveChatId),
35530
36242
  accountId: account.accountId,
35531
36243
  requireMentionDefault: account.config.requireMention ?? false
35532
36244
  }) : false;
@@ -35589,14 +36301,14 @@ ${JSON.stringify(payload)}`;
35589
36301
  ...log ? { log } : {}
35590
36302
  });
35591
36303
  const timestamp = messageTimestamp;
35592
- const fromLabel = isGroup ? `chat:${chatInfo.title ?? String(chatId)}` : `user:${senderId}`;
36304
+ const fromLabel = isGroup ? `chat:${effectiveGroupTitle ?? String(effectiveChatId)}` : `user:${senderId}`;
35593
36305
  const storePath = core3.channel.session.resolveStorePath(cfg.session?.store, { agentId: route.agentId });
35594
36306
  const envelopeOptions = core3.channel.reply.resolveEnvelopeFormatOptions(cfg);
35595
36307
  const previousTimestamp = core3.channel.session.readSessionUpdatedAt({ storePath, sessionKey: route.sessionKey });
35596
36308
  const combinedBody = [
35597
- historyContext.historyText,
35598
- historyContext.attachmentText,
35599
- historyContext.entityText,
36309
+ effectiveHistoryContext.historyText,
36310
+ effectiveHistoryContext.attachmentText,
36311
+ effectiveHistoryContext.entityText,
35600
36312
  INLINE_FORMATTING_NOTE,
35601
36313
  `Current message:
35602
36314
  ${rawBody}`,
@@ -35630,31 +36342,46 @@ ${currentEntityText}` : null
35630
36342
  })
35631
36343
  });
35632
36344
  }
36345
+ const inboundHistory = isGroup && groupHistoryKey ? mergeInboundHistoryEntries({
36346
+ historyContextEntries: effectiveHistoryContext.inboundHistory,
36347
+ pendingEntries: groupPendingHistories.get(groupHistoryKey) ?? [],
36348
+ limit: historyLimit
36349
+ }) : [];
36350
+ const bodyForAgent = buildInlineBodyForAgent({
36351
+ rawBody,
36352
+ currentAttachmentText,
36353
+ currentEntityText
36354
+ });
35633
36355
  const effectiveSurface = shouldUseTelegramSurfaceForModelCommands(normalizedCommandBody) ? "telegram" : CHANNEL_ID;
35634
36356
  const systemPrompt = resolveInlineSystemPrompt({
35635
36357
  account,
35636
- ...isGroup ? { groupId: String(chatId) } : {}
36358
+ ...isGroup ? { groupId: String(effectiveChatId) } : {}
35637
36359
  });
35638
36360
  const ctxPayload = core3.channel.reply.finalizeInboundContext({
35639
36361
  Body: body,
36362
+ BodyForAgent: bodyForAgent,
36363
+ ...isGroup ? { InboundHistory: inboundHistory } : {},
35640
36364
  RawBody: rawBody,
35641
36365
  CommandBody: normalizedCommandBody,
35642
- From: isGroup ? `inline:chat:${String(chatId)}` : `inline:${senderId}`,
35643
- To: `inline:${String(chatId)}`,
36366
+ From: isGroup ? `inline:chat:${String(effectiveChatId)}` : `inline:${senderId}`,
36367
+ To: `inline:${String(effectiveChatId)}`,
35644
36368
  SessionKey: route.sessionKey,
36369
+ ...replyThreadContext ? { ParentSessionKey: route.sessionKey } : {},
35645
36370
  AccountId: route.accountId,
35646
36371
  ChatType: isGroup ? "group" : "direct",
35647
36372
  ConversationLabel: fromLabel,
35648
- ...isGroup ? { GroupSubject: chatInfo.title ?? String(chatId) } : {},
36373
+ ...isGroup ? { GroupSubject: effectiveGroupTitle ?? String(effectiveChatId) } : {},
35649
36374
  SenderId: senderId,
35650
36375
  ...senderName ? { SenderName: senderName } : {},
35651
36376
  ...senderUsername ? { SenderUsername: senderUsername } : {},
35652
36377
  Provider: CHANNEL_ID,
35653
36378
  Surface: effectiveSurface,
35654
36379
  MessageSid: String(msg.id),
36380
+ ...replyThreadContext ? { MessageThreadId: String(replyThreadContext.childChatId) } : {},
36381
+ ...replyThreadContext?.threadLabel ? { ThreadLabel: replyThreadContext.threadLabel } : {},
35655
36382
  ...msg.replyToMsgId != null ? { ReplyToId: String(msg.replyToMsgId) } : {},
35656
- ...historyContext.replyToSenderId != null ? { ReplyToSenderId: historyContext.replyToSenderId } : {},
35657
- ...msg.replyToMsgId != null ? { ReplyToWasBot: historyContext.repliedToBot } : {},
36383
+ ...effectiveHistoryContext.replyToSenderId != null ? { ReplyToSenderId: effectiveHistoryContext.replyToSenderId } : {},
36384
+ ...msg.replyToMsgId != null ? { ReplyToWasBot: effectiveHistoryContext.repliedToBot } : {},
35658
36385
  ...callbackActionEvent ? {
35659
36386
  MessageActionInteractionId: String(callbackActionEvent.interactionId),
35660
36387
  MessageActionId: callbackActionEvent.actionId,
@@ -35667,7 +36394,7 @@ ${currentEntityText}` : null
35667
36394
  CommandAuthorized: commandAuthorized,
35668
36395
  GroupSystemPrompt: systemPrompt,
35669
36396
  OriginatingChannel: CHANNEL_ID,
35670
- OriginatingTo: `inline:${String(chatId)}`
36397
+ OriginatingTo: `inline:${String(effectiveChatId)}`
35671
36398
  });
35672
36399
  await core3.channel.session.recordInboundSession({
35673
36400
  storePath,
@@ -35677,26 +36404,33 @@ ${currentEntityText}` : null
35677
36404
  updateLastRoute: {
35678
36405
  sessionKey: route.mainSessionKey,
35679
36406
  channel: CHANNEL_ID,
35680
- to: `inline:${String(chatId)}`,
36407
+ to: `inline:${String(effectiveChatId)}`,
35681
36408
  accountId: route.accountId
35682
36409
  }
35683
36410
  } : {},
35684
36411
  onRecordError: (err) => runtime2.error?.(`inline: failed updating session meta: ${String(err)}`)
35685
36412
  });
35686
- const prefixConfig = typeof createReplyPrefixOptions === "function" ? createReplyPrefixOptions({
36413
+ const replyPipeline = await createChannelReplyPipelineCompat({
35687
36414
  cfg,
35688
36415
  agentId: route.agentId,
35689
36416
  channel: CHANNEL_ID,
35690
- accountId: account.accountId
35691
- }) : {};
35692
- const onModelSelected = typeof prefixConfig.onModelSelected === "function" ? prefixConfig.onModelSelected : undefined;
35693
- const { onModelSelected: _ignoredOnModelSelected, ...prefixOptions } = prefixConfig;
35694
- const typingCallbacks = typeof createTypingCallbacks === "function" ? createTypingCallbacks({
35695
- start: () => client.sendTyping({ chatId, typing: true }),
35696
- stop: () => client.sendTyping({ chatId, typing: false }),
35697
- onStartError: (err) => runtime2.error?.(`inline typing start failed: ${String(err)}`),
35698
- onStopError: (err) => runtime2.error?.(`inline typing stop failed: ${String(err)}`)
35699
- }) : {};
36417
+ accountId: account.accountId,
36418
+ typing: {
36419
+ start: () => client.sendTyping({ chatId, typing: true }),
36420
+ stop: () => client.sendTyping({ chatId, typing: false }),
36421
+ onStartError: (err) => runtime2.error?.(`inline typing start failed: ${String(err)}`),
36422
+ onStopError: (err) => runtime2.error?.(`inline typing stop failed: ${String(err)}`)
36423
+ }
36424
+ });
36425
+ const onModelSelected = replyPipeline.onModelSelected;
36426
+ const typingCallbacks = replyPipeline.typingCallbacks;
36427
+ const prefixOptions = {
36428
+ ...replyPipeline.responsePrefix !== undefined ? { responsePrefix: replyPipeline.responsePrefix } : {},
36429
+ ...replyPipeline.enableSlackInteractiveReplies !== undefined ? { enableSlackInteractiveReplies: replyPipeline.enableSlackInteractiveReplies } : {},
36430
+ ...replyPipeline.responsePrefixContextProvider ? {
36431
+ responsePrefixContextProvider: replyPipeline.responsePrefixContextProvider
36432
+ } : {}
36433
+ };
35700
36434
  const streamViaEditMessage = account.config.streamViaEditMessage === true && !shouldEditCallbackTargetInPlace;
35701
36435
  const defaultReplyToMsgId = isGroup && msg.replyToMsgId != null ? msg.id : undefined;
35702
36436
  const disableBlockStreaming = streamViaEditMessage ? true : typeof account.config.blockStreaming === "boolean" ? !account.config.blockStreaming : undefined;
@@ -35747,7 +36481,7 @@ ${currentEntityText}` : null
35747
36481
  oneofKind: "editMessage",
35748
36482
  editMessage: {
35749
36483
  messageId: editStreamState.messageId,
35750
- peerId: buildChatPeer(chatId),
36484
+ peerId: buildChatPeer2(chatId),
35751
36485
  text: nextText,
35752
36486
  parseMarkdown
35753
36487
  }
@@ -35774,7 +36508,7 @@ ${currentEntityText}` : null
35774
36508
  cfg,
35775
36509
  dispatcherOptions: {
35776
36510
  ...prefixOptions,
35777
- ...typingCallbacks,
36511
+ ...typingCallbacks ? { typingCallbacks } : {},
35778
36512
  deliver: async (payload) => {
35779
36513
  const rawText = payload.text ?? "";
35780
36514
  const mediaList = payload.mediaUrls?.length ? payload.mediaUrls : payload.mediaUrl ? [payload.mediaUrl] : [];
@@ -35821,7 +36555,7 @@ ${currentEntityText}` : null
35821
36555
  oneofKind: "editMessage",
35822
36556
  editMessage: {
35823
36557
  messageId: editStreamState.messageId,
35824
- peerId: buildChatPeer(chatId),
36558
+ peerId: buildChatPeer2(chatId),
35825
36559
  text: textForEdit,
35826
36560
  parseMarkdown,
35827
36561
  ...actions !== undefined ? { actions } : {}
@@ -35935,15 +36669,6 @@ Attachment: ${mediaUrl}` : `Attachment: ${mediaUrl}`;
35935
36669
  return { stop, done: loop.catch(() => {}) };
35936
36670
  }
35937
36671
 
35938
- // src/inline/actions.ts
35939
- import {
35940
- createActionGate,
35941
- jsonResult,
35942
- readReactionParams,
35943
- readNumberParam,
35944
- readStringParam
35945
- } from "openclaw/plugin-sdk";
35946
-
35947
36672
  // src/inline/space-members.ts
35948
36673
  function buildInlineUserDisplayName(user) {
35949
36674
  const explicit = [user.firstName?.trim(), user.lastName?.trim()].filter(Boolean).join(" ");
@@ -36038,7 +36763,8 @@ for (const group of ACTION_GROUPS) {
36038
36763
  }
36039
36764
  }
36040
36765
  var SUPPORTED_ACTIONS = Array.from(ACTION_TO_GATE_KEY.keys());
36041
- var GET_MESSAGES_METHOD2 = typeof Method.GET_MESSAGES === "number" && Number.isInteger(Method.GET_MESSAGES) && Method.GET_MESSAGES > 0 ? Method.GET_MESSAGES : null;
36766
+ var GET_MESSAGES_METHOD3 = typeof Method.GET_MESSAGES === "number" && Number.isInteger(Method.GET_MESSAGES) && Method.GET_MESSAGES > 0 ? Method.GET_MESSAGES : null;
36767
+ var CREATE_SUBTHREAD_METHOD = typeof Method.CREATE_SUBTHREAD === "number" && Number.isInteger(Method.CREATE_SUBTHREAD) && Method.CREATE_SUBTHREAD > 0 ? Method.CREATE_SUBTHREAD : 43;
36042
36768
  var INLINE_ACTION_MAX_ROWS2 = 8;
36043
36769
  var INLINE_ACTION_MAX_PER_ROW2 = 8;
36044
36770
  function isRecord4(value) {
@@ -36379,7 +37105,7 @@ function resolveMessageSendTargetFromParams(params) {
36379
37105
  chatId: BigInt(normalized)
36380
37106
  };
36381
37107
  }
36382
- function buildChatPeer2(chatId) {
37108
+ function buildChatPeer3(chatId) {
36383
37109
  return {
36384
37110
  type: {
36385
37111
  oneofKind: "chat",
@@ -36468,10 +37194,10 @@ async function loadMessageReactions(params) {
36468
37194
  return Array.from(byEmoji.values());
36469
37195
  }
36470
37196
  async function findMessageById(params) {
36471
- const directResult = GET_MESSAGES_METHOD2 == null ? null : await params.client.invokeRaw(GET_MESSAGES_METHOD2, {
37197
+ const directResult = GET_MESSAGES_METHOD3 == null ? null : await params.client.invokeRaw(GET_MESSAGES_METHOD3, {
36472
37198
  oneofKind: "getMessages",
36473
37199
  getMessages: {
36474
- peerId: buildChatPeer2(params.chatId),
37200
+ peerId: buildChatPeer3(params.chatId),
36475
37201
  messageIds: [params.messageId]
36476
37202
  }
36477
37203
  }).catch(() => null);
@@ -36481,7 +37207,7 @@ async function findMessageById(params) {
36481
37207
  const result = await params.client.invokeRaw(Method.GET_CHAT_HISTORY, {
36482
37208
  oneofKind: "getChatHistory",
36483
37209
  getChatHistory: {
36484
- peerId: buildChatPeer2(params.chatId),
37210
+ peerId: buildChatPeer3(params.chatId),
36485
37211
  offsetId: params.messageId + 1n,
36486
37212
  limit: 8
36487
37213
  }
@@ -36555,7 +37281,7 @@ async function resolveSpaceIdFromParams(params) {
36555
37281
  const chatId = BigInt(normalizeChatId(chatTarget));
36556
37282
  const chatResult = await params.client.invokeRaw(Method.GET_CHAT, {
36557
37283
  oneofKind: "getChat",
36558
- getChat: { peerId: buildChatPeer2(chatId) }
37284
+ getChat: { peerId: buildChatPeer3(chatId) }
36559
37285
  });
36560
37286
  if (chatResult.oneofKind !== "getChat") {
36561
37287
  throw new Error(`inline action: expected getChat result, got ${String(chatResult.oneofKind)}`);
@@ -36575,6 +37301,50 @@ function listAllActions() {
36575
37301
  }
36576
37302
  return Array.from(out);
36577
37303
  }
37304
+ function listEnabledInlineActions(cfg) {
37305
+ const account = resolveInlineAccount({ cfg, accountId: null });
37306
+ if (!account.enabled || !account.configured)
37307
+ return [];
37308
+ const gate = createActionGate(account.config.actions ?? {});
37309
+ const actions = new Set;
37310
+ for (const group of ACTION_GROUPS) {
37311
+ if (!gate(group.key, group.defaultEnabled))
37312
+ continue;
37313
+ for (const action of group.actions) {
37314
+ actions.add(action);
37315
+ }
37316
+ }
37317
+ return Array.from(actions);
37318
+ }
37319
+ function supportsInlineMessageButtons(actions) {
37320
+ return actions.some((action) => action === "send" || action === "reply" || action === "thread-reply" || action === "edit");
37321
+ }
37322
+ function describeInlineMessageTool({
37323
+ cfg
37324
+ }) {
37325
+ const actions = listEnabledInlineActions(cfg);
37326
+ if (actions.length === 0) {
37327
+ return {
37328
+ actions: [],
37329
+ capabilities: [],
37330
+ schema: null
37331
+ };
37332
+ }
37333
+ const buttonsEnabled = supportsInlineMessageButtons(actions);
37334
+ const capabilities = buttonsEnabled ? ["interactive", "buttons"] : [];
37335
+ const schema = buttonsEnabled ? [
37336
+ {
37337
+ properties: {
37338
+ buttons: createMessageToolButtonsSchemaCompat()
37339
+ }
37340
+ }
37341
+ ] : [];
37342
+ return {
37343
+ actions,
37344
+ capabilities,
37345
+ schema
37346
+ };
37347
+ }
36578
37348
  function isActionEnabled(params) {
36579
37349
  const key = ACTION_TO_GATE_KEY.get(params.action);
36580
37350
  if (!key)
@@ -36590,21 +37360,10 @@ function isActionEnabled(params) {
36590
37360
  return gate(key, group.defaultEnabled);
36591
37361
  }
36592
37362
  var inlineMessageActions = {
36593
- listActions: ({ cfg }) => {
36594
- const account = resolveInlineAccount({ cfg, accountId: null });
36595
- if (!account.enabled || !account.configured)
36596
- return [];
36597
- const gate = createActionGate(account.config.actions ?? {});
36598
- const actions = new Set;
36599
- for (const group of ACTION_GROUPS) {
36600
- if (!gate(group.key, group.defaultEnabled))
36601
- continue;
36602
- for (const action of group.actions) {
36603
- actions.add(action);
36604
- }
36605
- }
36606
- return Array.from(actions);
36607
- },
37363
+ describeMessageTool: describeInlineMessageTool,
37364
+ listActions: ({ cfg }) => listEnabledInlineActions(cfg),
37365
+ supportsButtons: ({ cfg }) => supportsInlineMessageButtons(listEnabledInlineActions(cfg)),
37366
+ supportsCards: () => false,
36608
37367
  supportsAction: ({ action }) => SUPPORTED_ACTIONS.includes(action),
36609
37368
  extractToolSend: ({ args }) => {
36610
37369
  const action = typeof args.action === "string" ? args.action.trim() : "";
@@ -36692,11 +37451,35 @@ var inlineMessageActions = {
36692
37451
  }
36693
37452
  if (normalizedAction === "reply" || normalizedAction === "thread-reply") {
36694
37453
  const parseMarkdown = resolveInlineAccount({ cfg, accountId: accountId ?? null }).config.parseMarkdown ?? true;
37454
+ const replyThreadsEnabled = normalizedAction === "thread-reply" && isInlineReplyThreadsEnabled({ cfg, accountId: accountId ?? null });
36695
37455
  return await withInlineClient({
36696
37456
  cfg,
36697
37457
  accountId,
36698
37458
  fn: async (client) => {
36699
37459
  const actions = resolveInlineMessageActionsParam(params);
37460
+ if (replyThreadsEnabled) {
37461
+ const rawThreadId = readFlexibleId(params, "threadId") ?? readStringParam(params, "threadId");
37462
+ if (!rawThreadId) {
37463
+ throw new Error("inline thread-reply: threadId is required when reply threads are enabled");
37464
+ }
37465
+ const chatId2 = parseInlineId(rawThreadId, "threadId");
37466
+ const replyToMsgId2 = parseOptionalInlineId(readFlexibleId(params, "messageId") ?? readFlexibleId(params, "replyTo") ?? readFlexibleId(params, "replyToId") ?? readStringParam(params, "messageId") ?? readStringParam(params, "replyTo") ?? readStringParam(params, "replyToId"), "messageId");
37467
+ const text2 = readStringParam(params, "message") ?? readStringParam(params, "text", { required: true, allowEmpty: true });
37468
+ const sent2 = await client.sendMessage({
37469
+ chatId: chatId2,
37470
+ text: text2,
37471
+ ...actions !== undefined ? { actions } : {},
37472
+ ...replyToMsgId2 != null ? { replyToMsgId: replyToMsgId2 } : {},
37473
+ parseMarkdown
37474
+ });
37475
+ return jsonResult({
37476
+ ok: true,
37477
+ chatId: String(chatId2),
37478
+ threadId: String(chatId2),
37479
+ messageId: sent2.messageId != null ? String(sent2.messageId) : null,
37480
+ replyToId: replyToMsgId2 != null ? String(replyToMsgId2) : null
37481
+ });
37482
+ }
36700
37483
  const replyParams = normalizedAction === "thread-reply" && params.threadId != null && params.to == null && params.chatId == null && params.channelId == null ? { ...params, to: params.threadId } : params;
36701
37484
  const chatId = resolveChatIdFromParams(replyParams);
36702
37485
  const replyToMsgId = parseInlineId(readFlexibleId(replyParams, "messageId") ?? readFlexibleId(replyParams, "replyTo") ?? readFlexibleId(replyParams, "replyToId") ?? readStringParam(replyParams, "messageId") ?? readStringParam(replyParams, "replyTo") ?? readStringParam(replyParams, "replyToId", { required: true }), "messageId");
@@ -36735,7 +37518,7 @@ var inlineMessageActions = {
36735
37518
  oneofKind: "deleteReaction",
36736
37519
  deleteReaction: {
36737
37520
  emoji: emoji3,
36738
- peerId: buildChatPeer2(chatId),
37521
+ peerId: buildChatPeer3(chatId),
36739
37522
  messageId
36740
37523
  }
36741
37524
  });
@@ -36748,7 +37531,7 @@ var inlineMessageActions = {
36748
37531
  addReaction: {
36749
37532
  emoji: emoji3,
36750
37533
  messageId,
36751
- peerId: buildChatPeer2(chatId)
37534
+ peerId: buildChatPeer3(chatId)
36752
37535
  }
36753
37536
  });
36754
37537
  if (result.oneofKind !== "addReaction") {
@@ -36797,7 +37580,7 @@ var inlineMessageActions = {
36797
37580
  const result = await client.invokeRaw(Method.GET_CHAT_HISTORY, {
36798
37581
  oneofKind: "getChatHistory",
36799
37582
  getChatHistory: {
36800
- peerId: buildChatPeer2(chatId),
37583
+ peerId: buildChatPeer3(chatId),
36801
37584
  ...offsetId != null ? { offsetId } : {},
36802
37585
  limit
36803
37586
  }
@@ -36825,7 +37608,7 @@ var inlineMessageActions = {
36825
37608
  const result = await client.invokeRaw(Method.SEARCH_MESSAGES, {
36826
37609
  oneofKind: "searchMessages",
36827
37610
  searchMessages: {
36828
- peerId: buildChatPeer2(chatId),
37611
+ peerId: buildChatPeer3(chatId),
36829
37612
  queries: [query],
36830
37613
  limit,
36831
37614
  ...offsetId != null ? { offsetId } : {}
@@ -36857,7 +37640,7 @@ var inlineMessageActions = {
36857
37640
  oneofKind: "editMessage",
36858
37641
  editMessage: {
36859
37642
  messageId,
36860
- peerId: buildChatPeer2(chatId),
37643
+ peerId: buildChatPeer3(chatId),
36861
37644
  text,
36862
37645
  ...actions !== undefined ? { actions } : {},
36863
37646
  parseMarkdown
@@ -36878,7 +37661,7 @@ var inlineMessageActions = {
36878
37661
  const chatId = resolveChatIdFromParams(params);
36879
37662
  const result = await client.invokeRaw(Method.GET_CHAT, {
36880
37663
  oneofKind: "getChat",
36881
- getChat: { peerId: buildChatPeer2(chatId) }
37664
+ getChat: { peerId: buildChatPeer3(chatId) }
36882
37665
  });
36883
37666
  if (result.oneofKind !== "getChat") {
36884
37667
  throw new Error(`inline action: expected getChat result, got ${String(result.oneofKind)}`);
@@ -36957,6 +37740,7 @@ var inlineMessageActions = {
36957
37740
  });
36958
37741
  }
36959
37742
  if (normalizedAction === "channel-create" || normalizedAction === "thread-create") {
37743
+ const replyThreadsEnabled = normalizedAction === "thread-create" && isInlineReplyThreadsEnabled({ cfg, accountId: accountId ?? null });
36960
37744
  return await withInlineClient({
36961
37745
  cfg,
36962
37746
  accountId,
@@ -36979,6 +37763,33 @@ var inlineMessageActions = {
36979
37763
  values: participantRefs,
36980
37764
  label: "participant"
36981
37765
  });
37766
+ if (replyThreadsEnabled) {
37767
+ const parentChatId = resolveChatIdFromParams(params);
37768
+ const parentMessageId = parseOptionalInlineId(readFlexibleId(params, "parentMessageId") ?? readFlexibleId(params, "messageId") ?? readFlexibleId(params, "replyTo") ?? readFlexibleId(params, "replyToId") ?? readStringParam(params, "parentMessageId") ?? readStringParam(params, "messageId") ?? readStringParam(params, "replyTo") ?? readStringParam(params, "replyToId"), "parentMessageId");
37769
+ const result2 = await client.invokeRaw(CREATE_SUBTHREAD_METHOD, {
37770
+ oneofKind: "createSubthread",
37771
+ createSubthread: {
37772
+ parentChatId,
37773
+ ...parentMessageId != null ? { parentMessageId } : {},
37774
+ title,
37775
+ ...description ? { description } : {},
37776
+ ...emoji3 ? { emoji: emoji3 } : {},
37777
+ participants: dedupedParticipants.map((userId) => ({ userId }))
37778
+ }
37779
+ });
37780
+ if (result2.oneofKind !== "createSubthread") {
37781
+ throw new Error(`inline action: expected createSubthread result, got ${String(result2.oneofKind)}`);
37782
+ }
37783
+ return jsonResult(toJsonSafe({
37784
+ ok: true,
37785
+ title,
37786
+ parentChatId: String(parentChatId),
37787
+ parentMessageId: parentMessageId != null ? String(parentMessageId) : null,
37788
+ chat: result2.createSubthread.chat ?? null,
37789
+ dialog: result2.createSubthread.dialog ?? null,
37790
+ anchorMessage: result2.createSubthread.anchorMessage ?? null
37791
+ }));
37792
+ }
36982
37793
  const result = await client.invokeRaw(Method.CREATE_CHAT, {
36983
37794
  oneofKind: "createChat",
36984
37795
  createChat: {
@@ -37014,7 +37825,7 @@ var inlineMessageActions = {
37014
37825
  const result = await client.invokeRaw(Method.DELETE_CHAT, {
37015
37826
  oneofKind: "deleteChat",
37016
37827
  deleteChat: {
37017
- peerId: buildChatPeer2(chatId)
37828
+ peerId: buildChatPeer3(chatId)
37018
37829
  }
37019
37830
  });
37020
37831
  if (result.oneofKind !== "deleteChat") {
@@ -37224,7 +38035,7 @@ var inlineMessageActions = {
37224
38035
  const result = await client.invokeRaw(Method.DELETE_MESSAGES, {
37225
38036
  oneofKind: "deleteMessages",
37226
38037
  deleteMessages: {
37227
- peerId: buildChatPeer2(chatId),
38038
+ peerId: buildChatPeer3(chatId),
37228
38039
  messageIds: deduped
37229
38040
  }
37230
38041
  });
@@ -37250,7 +38061,7 @@ var inlineMessageActions = {
37250
38061
  const result = await client.invokeRaw(Method.PIN_MESSAGE, {
37251
38062
  oneofKind: "pinMessage",
37252
38063
  pinMessage: {
37253
- peerId: buildChatPeer2(chatId),
38064
+ peerId: buildChatPeer3(chatId),
37254
38065
  messageId,
37255
38066
  unpin
37256
38067
  }
@@ -37275,7 +38086,7 @@ var inlineMessageActions = {
37275
38086
  const chatId = resolveChatIdFromParams(params);
37276
38087
  const result = await client.invokeRaw(Method.GET_CHAT, {
37277
38088
  oneofKind: "getChat",
37278
- getChat: { peerId: buildChatPeer2(chatId) }
38089
+ getChat: { peerId: buildChatPeer3(chatId) }
37279
38090
  });
37280
38091
  if (result.oneofKind !== "getChat") {
37281
38092
  throw new Error(`inline action: expected getChat result, got ${String(result.oneofKind)}`);
@@ -37624,8 +38435,14 @@ async function sendMessageInline(params) {
37624
38435
  context: "sendText",
37625
38436
  target
37626
38437
  });
38438
+ const effectiveChatId = resolvedTarget.kind === "chat" ? resolveInlineReplyThreadChatId({
38439
+ cfg: params.cfg,
38440
+ accountId: account.accountId,
38441
+ parentChatId: resolvedTarget.targetId,
38442
+ threadId: params.threadId ?? null
38443
+ }) : null;
37627
38444
  const result = await client.sendMessage({
37628
- ...buildInlineSendTarget(resolvedTarget),
38445
+ ...effectiveChatId != null ? { chatId: effectiveChatId } : buildInlineSendTarget(resolvedTarget),
37629
38446
  text: params.text,
37630
38447
  ...replyToMsgId != null ? { replyToMsgId } : {},
37631
38448
  parseMarkdown: account.config.parseMarkdown ?? true
@@ -37640,7 +38457,7 @@ async function sendMessageInline(params) {
37640
38457
  const bestEffort = result.messageId != null ? String(result.messageId) : BigInt(Date.now()).toString();
37641
38458
  return {
37642
38459
  messageId: bestEffort,
37643
- chatId: formatInlineResultChatId(resolvedTarget)
38460
+ chatId: effectiveChatId != null ? String(effectiveChatId) : formatInlineResultChatId(resolvedTarget)
37644
38461
  };
37645
38462
  } finally {
37646
38463
  await client.close().catch(() => {});
@@ -37669,6 +38486,12 @@ async function sendMediaInline(params) {
37669
38486
  context: "sendMedia",
37670
38487
  target
37671
38488
  });
38489
+ const effectiveChatId = resolvedTarget.kind === "chat" ? resolveInlineReplyThreadChatId({
38490
+ cfg: params.cfg,
38491
+ accountId: account.accountId,
38492
+ parentChatId: resolvedTarget.targetId,
38493
+ threadId: params.threadId ?? null
38494
+ }) : null;
37672
38495
  const media = await uploadInlineMediaFromUrl({
37673
38496
  client,
37674
38497
  cfg: params.cfg,
@@ -37676,7 +38499,7 @@ async function sendMediaInline(params) {
37676
38499
  mediaUrl: params.mediaUrl
37677
38500
  });
37678
38501
  const result = await client.sendMessage({
37679
- ...buildInlineSendTarget(resolvedTarget),
38502
+ ...effectiveChatId != null ? { chatId: effectiveChatId } : buildInlineSendTarget(resolvedTarget),
37680
38503
  ...caption ? { text: caption } : {},
37681
38504
  media,
37682
38505
  ...replyToMsgId != null ? { replyToMsgId } : {},
@@ -37692,7 +38515,7 @@ async function sendMediaInline(params) {
37692
38515
  const bestEffort = result.messageId != null ? String(result.messageId) : BigInt(Date.now()).toString();
37693
38516
  return {
37694
38517
  messageId: bestEffort,
37695
- chatId: formatInlineResultChatId(resolvedTarget)
38518
+ chatId: effectiveChatId != null ? String(effectiveChatId) : formatInlineResultChatId(resolvedTarget)
37696
38519
  };
37697
38520
  } finally {
37698
38521
  await client.close().catch(() => {});
@@ -37775,7 +38598,7 @@ var inlineChannelPlugin = {
37775
38598
  edit: true,
37776
38599
  reply: true,
37777
38600
  groupManagement: true,
37778
- threads: false,
38601
+ threads: true,
37779
38602
  nativeCommands: true,
37780
38603
  blockStreaming: true
37781
38604
  },
@@ -37809,7 +38632,7 @@ var inlineChannelPlugin = {
37809
38632
  },
37810
38633
  security: {
37811
38634
  resolveDmPolicy: ({ cfg, accountId, account }) => {
37812
- const resolvedAccountId = accountId ?? account.accountId ?? DEFAULT_ACCOUNT_ID2;
38635
+ const resolvedAccountId = accountId ?? account.accountId ?? DEFAULT_ACCOUNT_ID;
37813
38636
  const useAccountPath = Boolean(cfg.channels?.inline?.accounts?.[resolvedAccountId]);
37814
38637
  const basePath = useAccountPath ? `channels.inline.accounts.${resolvedAccountId}.` : "channels.inline.";
37815
38638
  return {
@@ -37858,11 +38681,42 @@ var inlineChannelPlugin = {
37858
38681
  senderE164
37859
38682
  })
37860
38683
  },
38684
+ threading: {
38685
+ resolveReplyToMode: () => "off",
38686
+ buildToolContext: ({ cfg, accountId, context, hasRepliedRef }) => {
38687
+ if (!isInlineReplyThreadsEnabled({ cfg, accountId: accountId ?? null })) {
38688
+ return;
38689
+ }
38690
+ const currentChannelId = context.To?.trim() || undefined;
38691
+ if (!currentChannelId) {
38692
+ return;
38693
+ }
38694
+ return {
38695
+ currentChannelId,
38696
+ ...context.MessageThreadId != null ? { currentThreadTs: String(context.MessageThreadId) } : {},
38697
+ ...context.CurrentMessageId != null ? { currentMessageId: context.CurrentMessageId } : {},
38698
+ replyToMode: "off",
38699
+ ...hasRepliedRef ? { hasRepliedRef } : {}
38700
+ };
38701
+ },
38702
+ resolveReplyTransport: ({ cfg, accountId, threadId, replyToId }) => {
38703
+ if (!isInlineReplyThreadsEnabled({ cfg, accountId: accountId ?? null })) {
38704
+ return null;
38705
+ }
38706
+ return {
38707
+ threadId: threadId != null ? String(threadId) : null,
38708
+ replyToId: replyToId ?? null
38709
+ };
38710
+ }
38711
+ },
37861
38712
  agentPrompt: {
37862
- messageToolHints: () => [
38713
+ messageToolHints: ({ cfg, accountId }) => [
37863
38714
  "- Inline targeting: omit `target` to reply in the current chat.",
37864
38715
  "- Inline explicit targets: `chat:<chatId>` for chats and `user:<userId>` for direct users. Prefer `user:` for DM user targets.",
37865
- "- Inline special tools: use `inline_nudge` to send a nudge, and `inline_forward` to forward message ids between chats or users."
38716
+ "- Inline special tools: use `inline_nudge` to send a nudge, and `inline_forward` to forward message ids between chats or users.",
38717
+ ...isInlineReplyThreadsEnabled({ cfg, accountId: accountId ?? null }) ? [
38718
+ "- Inline reply threads are enabled: use `thread-reply` to send into a real reply thread, with `threadId` set to the reply-thread chat id."
38719
+ ] : []
37866
38720
  ]
37867
38721
  },
37868
38722
  messaging: {
@@ -38009,7 +38863,8 @@ var inlineChannelPlugin = {
38009
38863
  to,
38010
38864
  text,
38011
38865
  accountId: accountId ?? null,
38012
- replyToId: effectiveReplyToId
38866
+ replyToId: effectiveReplyToId,
38867
+ threadId: null
38013
38868
  });
38014
38869
  return { channel: "inline", to, messageId: result.messageId, chatId: result.chatId };
38015
38870
  }
@@ -38025,7 +38880,8 @@ var inlineChannelPlugin = {
38025
38880
  text: isFirst ? text : "",
38026
38881
  mediaUrl,
38027
38882
  accountId: accountId ?? null,
38028
- replyToId: isFirst ? effectiveReplyToId : null
38883
+ replyToId: isFirst ? effectiveReplyToId : null,
38884
+ threadId: null
38029
38885
  });
38030
38886
  }
38031
38887
  if (!finalResult) {
@@ -38034,7 +38890,8 @@ var inlineChannelPlugin = {
38034
38890
  to,
38035
38891
  text,
38036
38892
  accountId: accountId ?? null,
38037
- replyToId: effectiveReplyToId
38893
+ replyToId: effectiveReplyToId,
38894
+ threadId: null
38038
38895
  });
38039
38896
  return { channel: "inline", to, messageId: result.messageId, chatId: result.chatId };
38040
38897
  }
@@ -38046,7 +38903,8 @@ var inlineChannelPlugin = {
38046
38903
  to,
38047
38904
  text,
38048
38905
  accountId: accountId ?? null,
38049
- replyToId: replyToId ?? null
38906
+ replyToId: replyToId ?? null,
38907
+ threadId: threadId ?? null
38050
38908
  });
38051
38909
  return { channel: "inline", to, messageId: result.messageId, chatId: result.chatId };
38052
38910
  },
@@ -38057,7 +38915,8 @@ var inlineChannelPlugin = {
38057
38915
  to,
38058
38916
  text,
38059
38917
  accountId: accountId ?? null,
38060
- replyToId: replyToId ?? null
38918
+ replyToId: replyToId ?? null,
38919
+ threadId: threadId ?? null
38061
38920
  });
38062
38921
  return { channel: "inline", to, messageId: result2.messageId, chatId: result2.chatId };
38063
38922
  }
@@ -38067,14 +38926,15 @@ var inlineChannelPlugin = {
38067
38926
  text,
38068
38927
  mediaUrl,
38069
38928
  accountId: accountId ?? null,
38070
- replyToId: replyToId ?? null
38929
+ replyToId: replyToId ?? null,
38930
+ threadId: threadId ?? null
38071
38931
  });
38072
38932
  return { channel: "inline", to, messageId: result.messageId, chatId: result.chatId };
38073
38933
  }
38074
38934
  },
38075
38935
  status: {
38076
38936
  defaultRuntime: {
38077
- accountId: DEFAULT_ACCOUNT_ID2,
38937
+ accountId: DEFAULT_ACCOUNT_ID,
38078
38938
  running: false,
38079
38939
  lastStartAt: null,
38080
38940
  lastStopAt: null,
@@ -38159,9 +39019,6 @@ var inlineChannelPlugin = {
38159
39019
  };
38160
39020
 
38161
39021
  // src/inline/message-tools.ts
38162
- import {
38163
- jsonResult as jsonResult2
38164
- } from "openclaw/plugin-sdk";
38165
39022
  var InlineNudgeToolParameters = {
38166
39023
  type: "object",
38167
39024
  additionalProperties: false,
@@ -38473,7 +39330,7 @@ function createInlineNudgeTool(ctx) {
38473
39330
  }
38474
39331
  });
38475
39332
  const messageId = result.oneofKind === "sendMessage" ? extractFirstMessageId2(result.sendMessage.updates) : null;
38476
- return jsonResult2({
39333
+ return jsonResult({
38477
39334
  ok: true,
38478
39335
  accountId: resolvedAccountId,
38479
39336
  nudged: true,
@@ -38527,7 +39384,7 @@ function createInlineForwardTool(ctx) {
38527
39384
  }
38528
39385
  });
38529
39386
  const forwardedMessageId = result.oneofKind === "forwardMessages" ? extractFirstMessageId2(result.forwardMessages.updates) : null;
38530
- return jsonResult2({
39387
+ return jsonResult({
38531
39388
  ok: true,
38532
39389
  accountId: resolvedAccountId,
38533
39390
  from: source.normalized,
@@ -38613,7 +39470,7 @@ function filterSpaceMembers(params) {
38613
39470
  target: `user:${member.userId}`
38614
39471
  }));
38615
39472
  }
38616
- function jsonResult3(payload) {
39473
+ function jsonResult2(payload) {
38617
39474
  return {
38618
39475
  content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
38619
39476
  details: payload
@@ -38664,7 +39521,7 @@ function createInlineMembersTool(ctx) {
38664
39521
  userId,
38665
39522
  limit
38666
39523
  });
38667
- return jsonResult3({
39524
+ return jsonResult2({
38668
39525
  ok: true,
38669
39526
  accountId: resolvedAccountId,
38670
39527
  spaceId: String(spaceId),
@@ -38680,10 +39537,6 @@ function createInlineMembersTool(ctx) {
38680
39537
  }
38681
39538
 
38682
39539
  // src/inline/profile-tool.ts
38683
- import {
38684
- detectMime as detectMime2,
38685
- loadWebMedia as loadWebMedia2
38686
- } from "openclaw/plugin-sdk";
38687
39540
  var InlineProfileToolParameters = {
38688
39541
  type: "object",
38689
39542
  additionalProperties: false,
@@ -38710,7 +39563,7 @@ var InlineProfileToolParameters = {
38710
39563
  }
38711
39564
  }
38712
39565
  };
38713
- function jsonResult4(payload) {
39566
+ function jsonResult3(payload) {
38714
39567
  return {
38715
39568
  content: [
38716
39569
  {
@@ -38747,9 +39600,24 @@ function readTrimmedString(value) {
38747
39600
  function resolvePhotoSource(args) {
38748
39601
  return readTrimmedString(args.photoPath) ?? readTrimmedString(args.photoUrl);
38749
39602
  }
39603
+ function looksLikeLocalMediaSource2(mediaUrl) {
39604
+ return !/^https?:\/\//i.test(mediaUrl.trim());
39605
+ }
38750
39606
  async function uploadProfilePhoto(client, rawSource) {
38751
- const loaded = await loadWebMedia2(rawSource);
38752
- const contentType = loaded.contentType ?? await detectMime2({
39607
+ const runtimeMedia = getInlineRuntime().media;
39608
+ const loadWebMediaCompat = runtimeMedia.loadWebMedia;
39609
+ let loaded;
39610
+ try {
39611
+ loaded = await runtimeMedia.loadWebMedia(rawSource);
39612
+ } catch (error48) {
39613
+ const message = String(error48);
39614
+ const deniedLocalPath = /not under an allowed directory/i.test(message);
39615
+ if (!deniedLocalPath || !looksLikeLocalMediaSource2(rawSource)) {
39616
+ throw error48;
39617
+ }
39618
+ loaded = await loadWebMediaCompat(rawSource, undefined, { localRoots: "any" });
39619
+ }
39620
+ const contentType = loaded.contentType ?? await runtimeMedia.detectMime({
38753
39621
  buffer: loaded.buffer,
38754
39622
  ...loaded.fileName ? { filePath: loaded.fileName } : {}
38755
39623
  }) ?? undefined;
@@ -38799,7 +39667,7 @@ function createInlineProfileTool(ctx) {
38799
39667
  if (result.oneofKind !== "updateBotProfile") {
38800
39668
  throw new Error(`inline_update_profile: expected updateBotProfile result, got ${String(result.oneofKind)}`);
38801
39669
  }
38802
- return jsonResult4({
39670
+ return jsonResult3({
38803
39671
  ok: true,
38804
39672
  accountId: resolvedAccountId,
38805
39673
  botUserId: String(me.userId),
@@ -38815,9 +39683,6 @@ function createInlineProfileTool(ctx) {
38815
39683
  };
38816
39684
  }
38817
39685
 
38818
- // src/inline/bot-commands-tool.ts
38819
- import { jsonResult as jsonResult5 } from "openclaw/plugin-sdk";
38820
-
38821
39686
  // src/inline/bot-commands-api.ts
38822
39687
  function normalizeInlineBotBaseUrl(baseUrl) {
38823
39688
  return baseUrl.replace(/\/+$/, "");
@@ -38988,7 +39853,7 @@ function createInlineBotCommandsTool(ctx) {
38988
39853
  method: "GET"
38989
39854
  });
38990
39855
  const commands = Array.isArray(result.commands) ? result.commands : [];
38991
- return jsonResult5({
39856
+ return jsonResult({
38992
39857
  ok: true,
38993
39858
  action,
38994
39859
  accountId: account.accountId,
@@ -39005,7 +39870,7 @@ function createInlineBotCommandsTool(ctx) {
39005
39870
  method: "POST",
39006
39871
  body: { commands }
39007
39872
  });
39008
- return jsonResult5({
39873
+ return jsonResult({
39009
39874
  ok: true,
39010
39875
  action,
39011
39876
  accountId: account.accountId,
@@ -39019,7 +39884,7 @@ function createInlineBotCommandsTool(ctx) {
39019
39884
  methodName: "deleteMyCommands",
39020
39885
  method: "POST"
39021
39886
  });
39022
- return jsonResult5({
39887
+ return jsonResult({
39023
39888
  ok: true,
39024
39889
  action,
39025
39890
  accountId: account.accountId
@@ -39029,7 +39894,6 @@ function createInlineBotCommandsTool(ctx) {
39029
39894
  }
39030
39895
 
39031
39896
  // src/inline/bot-commands-sync.ts
39032
- import * as pluginSdk from "openclaw/plugin-sdk";
39033
39897
  var INLINE_BASE_NATIVE_COMMANDS = [
39034
39898
  { command: "help", description: "Show available commands." },
39035
39899
  { command: "commands", description: "List all slash commands." },
@@ -39059,12 +39923,15 @@ var INLINE_BASE_NATIVE_COMMANDS = [
39059
39923
  ];
39060
39924
  var INLINE_COMMAND_NAME_RE = /^[a-z0-9_]{1,32}$/;
39061
39925
  var INLINE_COMMAND_LIMIT = 100;
39062
- function getPluginSdkFunction(name) {
39063
- const raw = pluginSdk[name];
39064
- if (typeof raw !== "function")
39065
- return null;
39066
- return raw;
39067
- }
39926
+ var FALLBACK_NATIVE_COMMAND_HELPERS = {
39927
+ available: false,
39928
+ listNativeCommandSpecsForConfig: () => [],
39929
+ listSkillCommandsForAgents: () => []
39930
+ };
39931
+ var FALLBACK_PLUGIN_COMMAND_SPECS = {
39932
+ available: false,
39933
+ specs: []
39934
+ };
39068
39935
  function normalizeDynamicCommandName(raw) {
39069
39936
  const trimmed = raw.trim().toLowerCase();
39070
39937
  const withoutSlash = trimmed.startsWith("/") ? trimmed.slice(1) : trimmed;
@@ -39090,41 +39957,42 @@ function shouldSyncInlineNativeSkills(cfg) {
39090
39957
  const effective = inlineNativeSkillsSetting ?? cfg.commands?.nativeSkills ?? "auto";
39091
39958
  return effective !== false;
39092
39959
  }
39093
- function buildInlineNativeCommandsForConfig(cfg) {
39094
- const listNativeCommandSpecsForConfig = getPluginSdkFunction("listNativeCommandSpecsForConfig");
39095
- const listSkillCommandsForAgents = getPluginSdkFunction("listSkillCommandsForAgents");
39096
- const getPluginCommandSpecs = getPluginSdkFunction("getPluginCommandSpecs");
39097
- if (!listNativeCommandSpecsForConfig) {
39098
- const commands2 = [...INLINE_BASE_NATIVE_COMMANDS];
39099
- if (cfg.commands?.config === true) {
39100
- commands2.push({ command: "config", description: "Show or set config values." });
39101
- }
39102
- if (cfg.commands?.debug === true) {
39103
- commands2.push({ command: "debug", description: "Set runtime debug overrides." });
39104
- }
39105
- return commands2;
39960
+ async function buildInlineNativeCommandsForConfig(params) {
39961
+ const commands = [...INLINE_BASE_NATIVE_COMMANDS];
39962
+ if (params.cfg.commands?.config === true) {
39963
+ commands.push({ command: "config", description: "Show or set config values." });
39964
+ }
39965
+ if (params.cfg.commands?.debug === true) {
39966
+ commands.push({ command: "debug", description: "Set runtime debug overrides." });
39106
39967
  }
39107
- const skillCommands = shouldSyncInlineNativeSkills(cfg) && listSkillCommandsForAgents ? listSkillCommandsForAgents({ cfg }) : [];
39108
- const nativeSpecs = listNativeCommandSpecsForConfig(cfg, { skillCommands });
39109
- const pluginSpecs = getPluginCommandSpecs?.() ?? [];
39110
- const commands = [];
39968
+ const { listNativeCommandSpecsForConfig, listSkillCommandsForAgents } = params.nativeHelpers;
39969
+ const skillCommands = shouldSyncInlineNativeSkills(params.cfg) ? listSkillCommandsForAgents({ cfg: params.cfg }) : [];
39970
+ const nativeSpecs = listNativeCommandSpecsForConfig(params.cfg, { skillCommands });
39971
+ const { specs: pluginSpecs } = params.pluginSpecs;
39111
39972
  const seen = new Set;
39973
+ const resolved = [];
39974
+ for (const base of commands) {
39975
+ appendUniqueCommand(resolved, seen, base.command, base.description);
39976
+ }
39112
39977
  for (const spec of nativeSpecs) {
39113
- appendUniqueCommand(commands, seen, spec.name, spec.description);
39978
+ appendUniqueCommand(resolved, seen, spec.name, spec.description);
39114
39979
  }
39115
39980
  for (const spec of pluginSpecs) {
39116
- appendUniqueCommand(commands, seen, spec.name, spec.description);
39981
+ appendUniqueCommand(resolved, seen, spec.name, spec.description);
39117
39982
  }
39118
- return commands;
39119
- }
39120
- function isSdkNativeCommandSourceAvailable() {
39121
- return Boolean(getPluginSdkFunction("listNativeCommandSpecsForConfig"));
39983
+ return resolved;
39122
39984
  }
39123
39985
  async function syncInlineNativeCommands(params) {
39124
39986
  const accountIds = listInlineAccountIds(params.cfg);
39125
39987
  const nativeEnabled = shouldSyncInlineNativeCommands(params.cfg);
39126
- const usingSdkSource = isSdkNativeCommandSourceAvailable();
39127
- const allCommands = nativeEnabled ? buildInlineNativeCommandsForConfig(params.cfg) : [];
39988
+ const nativeHelpers = nativeEnabled ? await loadNativeCommandHelpersCompat() : FALLBACK_NATIVE_COMMAND_HELPERS;
39989
+ const pluginSpecs = nativeEnabled ? await loadPluginCommandSpecsCompat("inline") : FALLBACK_PLUGIN_COMMAND_SPECS;
39990
+ const usingSdkSource = nativeHelpers.available || pluginSpecs.available;
39991
+ const allCommands = nativeEnabled ? await buildInlineNativeCommandsForConfig({
39992
+ cfg: params.cfg,
39993
+ nativeHelpers,
39994
+ pluginSpecs
39995
+ }) : [];
39128
39996
  const commands = allCommands.slice(0, INLINE_COMMAND_LIMIT);
39129
39997
  if (allCommands.length > INLINE_COMMAND_LIMIT) {
39130
39998
  params.logger?.warn?.(`[inline] native command sync truncating ${allCommands.length} commands to ${INLINE_COMMAND_LIMIT}`);
@@ -39215,5 +40083,5 @@ export {
39215
40083
  src_default as default
39216
40084
  };
39217
40085
 
39218
- //# debugId=ECFAEB3746DF293B64756E2164756E21
40086
+ //# debugId=FEB892391BE8BCD464756E2164756E21
39219
40087
  //# sourceMappingURL=index.js.map