@inline-openclaw/inline 0.0.27 → 0.0.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5837,7 +5837,8 @@ class ConnectionInit$Type extends import_runtime4.MessageType {
5837
5837
  { no: 1, name: "token", kind: "scalar", T: 9 },
5838
5838
  { no: 2, name: "build_number", kind: "scalar", opt: true, T: 5 },
5839
5839
  { no: 3, name: "layer", kind: "scalar", opt: true, T: 13 },
5840
- { no: 4, name: "client_version", kind: "scalar", opt: true, T: 9 }
5840
+ { no: 4, name: "client_version", kind: "scalar", opt: true, T: 9 },
5841
+ { no: 5, name: "os_version", kind: "scalar", opt: true, T: 9 }
5841
5842
  ]);
5842
5843
  }
5843
5844
  create(value) {
@@ -5864,6 +5865,9 @@ class ConnectionInit$Type extends import_runtime4.MessageType {
5864
5865
  case 4:
5865
5866
  message.clientVersion = reader.string();
5866
5867
  break;
5868
+ case 5:
5869
+ message.osVersion = reader.string();
5870
+ break;
5867
5871
  default:
5868
5872
  let u = options.readUnknownField;
5869
5873
  if (u === "throw")
@@ -5884,6 +5888,8 @@ class ConnectionInit$Type extends import_runtime4.MessageType {
5884
5888
  writer.tag(3, import_runtime.WireType.Varint).uint32(message.layer);
5885
5889
  if (message.clientVersion !== undefined)
5886
5890
  writer.tag(4, import_runtime.WireType.LengthDelimited).string(message.clientVersion);
5891
+ if (message.osVersion !== undefined)
5892
+ writer.tag(5, import_runtime.WireType.LengthDelimited).string(message.osVersion);
5887
5893
  let u = options.writeUnknownFields;
5888
5894
  if (u !== false)
5889
5895
  (u == true ? import_runtime2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
@@ -18289,6 +18295,9 @@ class PingPongService {
18289
18295
  sleepTimer = null;
18290
18296
  sleepResolver = null;
18291
18297
  pings = new Map;
18298
+ lastPingAt = null;
18299
+ lastPongAt = null;
18300
+ lastTimeoutAt = null;
18292
18301
  constructor(options) {
18293
18302
  this.log = options?.logger ?? {};
18294
18303
  const cryptoAny = globalThis.crypto;
@@ -18317,13 +18326,16 @@ class PingPongService {
18317
18326
  return;
18318
18327
  const nonce = this.randomNonce();
18319
18328
  await client.sendPing(nonce);
18320
- this.pings.set(nonce, Date.now());
18329
+ const now = Date.now();
18330
+ this.lastPingAt = now;
18331
+ this.pings.set(nonce, now);
18321
18332
  }
18322
18333
  pong(nonce) {
18323
18334
  const pingDate = this.pings.get(nonce);
18324
18335
  if (!pingDate)
18325
18336
  return;
18326
18337
  this.pings.delete(nonce);
18338
+ this.lastPongAt = Date.now();
18327
18339
  }
18328
18340
  async loop() {
18329
18341
  while (this.running) {
@@ -18344,11 +18356,16 @@ class PingPongService {
18344
18356
  if (client.state !== "open")
18345
18357
  return;
18346
18358
  const now = Date.now();
18347
- const hasTimedOutPing = [...this.pings.values()].some((timestamp) => now - timestamp > 30000);
18348
- if (!hasTimedOutPing)
18359
+ const oldestPendingPingAt = [...this.pings.values()].reduce((oldest, timestamp) => oldest == null || timestamp < oldest ? timestamp : oldest, null);
18360
+ if (oldestPendingPingAt == null)
18361
+ return;
18362
+ const oldestPendingAgeMs = now - oldestPendingPingAt;
18363
+ if (oldestPendingAgeMs <= 30000)
18349
18364
  return;
18350
- this.log.warn?.("Ping timeout, reconnecting");
18351
- await client.reconnect();
18365
+ this.lastTimeoutAt = now;
18366
+ this.log.warn?.(`Ping timeout, reconnecting (pending=${this.pings.size}, oldestPendingAgeMs=${oldestPendingAgeMs}${this.lastPongAt != null ? `, lastPongAgeMs=${now - this.lastPongAt}` : ""})`);
18367
+ this.reset();
18368
+ await client.reconnect({ cause: "ping-timeout" });
18352
18369
  }
18353
18370
  async sleep(ms) {
18354
18371
  if (ms <= 0)
@@ -18382,6 +18399,19 @@ class PingPongService {
18382
18399
  }
18383
18400
  return BigInt(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER));
18384
18401
  }
18402
+ getDiagnostics() {
18403
+ const now = Date.now();
18404
+ const oldestPendingPingAt = [...this.pings.values()].reduce((oldest, timestamp) => oldest == null || timestamp < oldest ? timestamp : oldest, null);
18405
+ return {
18406
+ running: this.running,
18407
+ pendingCount: this.pings.size,
18408
+ lastPingAt: this.lastPingAt,
18409
+ lastPongAt: this.lastPongAt,
18410
+ lastTimeoutAt: this.lastTimeoutAt,
18411
+ oldestPendingPingAt,
18412
+ oldestPendingPingAgeMs: oldestPendingPingAt != null ? now - oldestPendingPingAt : null
18413
+ };
18414
+ }
18385
18415
  }
18386
18416
  var isCrypto = (value) => typeof value === "object" && value !== null && ("getRandomValues" in value) && typeof value.getRandomValues === "function";
18387
18417
 
@@ -18411,6 +18441,11 @@ class ProtocolClient {
18411
18441
  reconnectionTimer = null;
18412
18442
  authenticationTimeout = null;
18413
18443
  listenersStarted = false;
18444
+ lastConnectingAt = null;
18445
+ lastOpenAt = null;
18446
+ lastTransportMessageAt = null;
18447
+ lastFailureAt = null;
18448
+ lastFailureReason = null;
18414
18449
  constructor(options) {
18415
18450
  this.transport = options.transport;
18416
18451
  this.log = options.logger ?? {};
@@ -18438,7 +18473,10 @@ class ProtocolClient {
18438
18473
  }
18439
18474
  }
18440
18475
  async reconnect(options) {
18441
- await this.transport.reconnect({ skipDelay: options?.skipDelay });
18476
+ await this.transport.reconnect({
18477
+ skipDelay: options?.skipDelay,
18478
+ cause: options?.cause ?? this.lastFailureReason ?? "protocol-reconnect"
18479
+ });
18442
18480
  }
18443
18481
  async sendRpc(method, input = emptyRpcInput) {
18444
18482
  this.ensureOpenForRpc();
@@ -18499,6 +18537,7 @@ class ProtocolClient {
18499
18537
  });
18500
18538
  }
18501
18539
  async handleTransportMessage(message) {
18540
+ this.lastTransportMessageAt = Date.now();
18502
18541
  switch (message.body.oneofKind) {
18503
18542
  case "connectionOpen":
18504
18543
  await this.connectionOpen();
@@ -18531,7 +18570,7 @@ class ProtocolClient {
18531
18570
  this.pingPong.pong(message.body.pong.nonce);
18532
18571
  break;
18533
18572
  case "connectionError":
18534
- this.handleClientFailure();
18573
+ this.handleClientFailure(describeConnectionError(message.body.connectionError));
18535
18574
  break;
18536
18575
  default:
18537
18576
  break;
@@ -18553,11 +18592,12 @@ class ProtocolClient {
18553
18592
  this.startAuthenticationTimeout();
18554
18593
  } catch (error) {
18555
18594
  this.log.error?.("Failed to authenticate", error);
18556
- this.handleClientFailure();
18595
+ this.handleClientFailure(`authenticate failed: ${summarizeError(error)}`);
18557
18596
  }
18558
18597
  }
18559
18598
  async connectionOpen() {
18560
18599
  this.state = "open";
18600
+ this.lastOpenAt = Date.now();
18561
18601
  await this.events.send({ type: "open" });
18562
18602
  this.stopAuthenticationTimeout();
18563
18603
  if (this.reconnectionTimer) {
@@ -18569,7 +18609,9 @@ class ProtocolClient {
18569
18609
  this.resendPendingRpcRequests();
18570
18610
  }
18571
18611
  async connecting() {
18612
+ this.pingPong.stop();
18572
18613
  this.state = "connecting";
18614
+ this.lastConnectingAt = Date.now();
18573
18615
  await this.events.send({ type: "connecting" });
18574
18616
  }
18575
18617
  async reset() {
@@ -18583,7 +18625,7 @@ class ProtocolClient {
18583
18625
  this.authenticationTimeout = setTimeout(() => {
18584
18626
  if (this.state === "open")
18585
18627
  return;
18586
- this.handleClientFailure();
18628
+ this.handleClientFailure("authentication timeout after 10000ms");
18587
18629
  }, 1e4);
18588
18630
  }
18589
18631
  stopAuthenticationTimeout() {
@@ -18592,19 +18634,23 @@ class ProtocolClient {
18592
18634
  clearTimeout(this.authenticationTimeout);
18593
18635
  this.authenticationTimeout = null;
18594
18636
  }
18595
- handleClientFailure() {
18637
+ handleClientFailure(reason = "connection failure") {
18596
18638
  this.pingPong.stop();
18597
18639
  this.stopAuthenticationTimeout();
18598
18640
  this.state = "connecting";
18641
+ this.lastFailureAt = Date.now();
18642
+ this.lastFailureReason = reason;
18599
18643
  if (this.reconnectionTimer) {
18600
18644
  clearTimeout(this.reconnectionTimer);
18601
18645
  }
18602
18646
  this.connectionAttemptNo = this.connectionAttemptNo + 1 >>> 0;
18647
+ const delayMs = Math.round(this.getReconnectionDelay() * 1000);
18648
+ this.log.warn?.(`Protocol reconnect scheduled (attempt=${this.connectionAttemptNo}, delayMs=${delayMs}, reason=${reason})`);
18603
18649
  this.reconnectionTimer = setTimeout(() => {
18604
18650
  if (this.state === "open")
18605
18651
  return;
18606
18652
  this.reconnect({ skipDelay: true });
18607
- }, this.getReconnectionDelay() * 1000);
18653
+ }, delayMs);
18608
18654
  }
18609
18655
  getReconnectionDelay() {
18610
18656
  const attemptNo = this.connectionAttemptNo;
@@ -18690,11 +18736,25 @@ class ProtocolClient {
18690
18736
  pending.sending = true;
18691
18737
  this.transport.send(pending.message).catch((error) => {
18692
18738
  this.log.warn?.("Failed to send RPC request; waiting for reconnect", error);
18693
- this.handleClientFailure();
18739
+ this.handleClientFailure(`rpc send failed: ${summarizeError(error)}`);
18694
18740
  }).finally(() => {
18695
18741
  pending.sending = false;
18696
18742
  });
18697
18743
  }
18744
+ getDiagnostics() {
18745
+ return {
18746
+ state: this.state,
18747
+ connectionAttemptNo: this.connectionAttemptNo,
18748
+ pendingRpcCount: this.pendingRpcRequests.size,
18749
+ lastConnectingAt: this.lastConnectingAt,
18750
+ lastOpenAt: this.lastOpenAt,
18751
+ lastTransportMessageAt: this.lastTransportMessageAt,
18752
+ lastFailureAt: this.lastFailureAt,
18753
+ lastFailureReason: this.lastFailureReason,
18754
+ ping: this.pingPong.getDiagnostics(),
18755
+ transport: typeof this.transport.getDiagnostics === "function" ? this.transport.getDiagnostics() : null
18756
+ };
18757
+ }
18698
18758
  }
18699
18759
  var normalizeRpcTimeoutMs = (timeoutMs, fallback) => {
18700
18760
  const resolved = timeoutMs === undefined ? fallback : timeoutMs;
@@ -18715,6 +18775,18 @@ class ProtocolClientError extends Error {
18715
18775
  this.name = `ProtocolClientError:${code}`;
18716
18776
  }
18717
18777
  }
18778
+ function summarizeError(error) {
18779
+ if (error instanceof Error) {
18780
+ return `${error.name}: ${error.message}`;
18781
+ }
18782
+ return String(error);
18783
+ }
18784
+ function describeConnectionError(error) {
18785
+ const value = typeof error === "object" && error !== null ? error : null;
18786
+ const code = typeof value?.code === "number" ? value.code : null;
18787
+ const message = typeof value?.message === "string" && value.message.trim() ? value.message.trim() : "unknown";
18788
+ return `server connection error${code != null ? ` (code=${code})` : ""}: ${message}`;
18789
+ }
18718
18790
 
18719
18791
  // ../../node_modules/.bun/ws@8.20.0/node_modules/ws/wrapper.mjs
18720
18792
  var import_stream = __toESM(require_stream(), 1);
@@ -18746,6 +18818,18 @@ class WebSocketTransport {
18746
18818
  connectionAttemptNo = 0;
18747
18819
  socket = null;
18748
18820
  reconnectionTimer = null;
18821
+ lastConnectStartedAt = null;
18822
+ lastConnectedAt = null;
18823
+ lastDisconnectedAt = null;
18824
+ lastMessageAt = null;
18825
+ lastCloseCode = null;
18826
+ lastCloseReason = null;
18827
+ lastErrorAt = null;
18828
+ lastErrorMessage = null;
18829
+ lastReconnectScheduledAt = null;
18830
+ lastReconnectDelayMs = null;
18831
+ lastReconnectCause = null;
18832
+ reconnectCount = 0;
18749
18833
  constructor(options) {
18750
18834
  this.url = options.url;
18751
18835
  this.log = options.logger ?? {};
@@ -18777,7 +18861,13 @@ class WebSocketTransport {
18777
18861
  this.cleanUpPreviousConnection();
18778
18862
  this.connectionAttemptNo = this.connectionAttemptNo + 1 >>> 0;
18779
18863
  const delaySeconds = this.getReconnectionDelaySeconds(this.connectionAttemptNo);
18780
- this.log.debug?.("reconnect scheduled", { attempt: this.connectionAttemptNo, delaySeconds });
18864
+ const delayMs = Math.round(delaySeconds * 1000);
18865
+ const cause = options?.cause?.trim() || "unspecified";
18866
+ this.lastReconnectScheduledAt = Date.now();
18867
+ this.lastReconnectDelayMs = delayMs;
18868
+ this.lastReconnectCause = cause;
18869
+ this.reconnectCount += 1;
18870
+ this.log.warn?.(`WebSocket reconnect scheduled (attempt=${this.connectionAttemptNo}, delayMs=${delayMs}, cause=${cause})`);
18781
18871
  this.reconnectionTimer = setTimeout(() => {
18782
18872
  this.reconnectionTimer = null;
18783
18873
  if (this.state === "idle" || this.state === "connected")
@@ -18821,6 +18911,7 @@ class WebSocketTransport {
18821
18911
  async openConnection() {
18822
18912
  if (this.state === "idle")
18823
18913
  return;
18914
+ this.lastConnectStartedAt = Date.now();
18824
18915
  const socket = new import_websocket.default(this.url);
18825
18916
  this.socket = socket;
18826
18917
  socket.on("open", () => {
@@ -18843,6 +18934,8 @@ class WebSocketTransport {
18843
18934
  return;
18844
18935
  this.connectionAttemptNo = 0;
18845
18936
  this.state = "connected";
18937
+ this.lastConnectedAt = Date.now();
18938
+ this.lastDisconnectedAt = null;
18846
18939
  await this.events.send({ type: "connected" });
18847
18940
  }
18848
18941
  async handleMessage(socket, data) {
@@ -18851,6 +18944,7 @@ class WebSocketTransport {
18851
18944
  try {
18852
18945
  const payload = this.coerceBinary(data);
18853
18946
  const message = ServerProtocolMessage.fromBinary(payload);
18947
+ this.lastMessageAt = Date.now();
18854
18948
  await this.events.send({ type: "message", message });
18855
18949
  } catch (error) {
18856
18950
  this.log.error?.("Failed to decode message", error);
@@ -18870,16 +18964,24 @@ class WebSocketTransport {
18870
18964
  return;
18871
18965
  if (this.state === "idle")
18872
18966
  return;
18873
- this.log.warn?.("WebSocket closed", { code, reason: reason.toString("utf8") });
18874
- await this.reconnect();
18967
+ const reasonText = stringifyCloseReason(reason);
18968
+ this.lastDisconnectedAt = Date.now();
18969
+ this.lastCloseCode = code;
18970
+ this.lastCloseReason = reasonText;
18971
+ const connectedForMs = this.lastConnectedAt != null ? Math.max(0, this.lastDisconnectedAt - this.lastConnectedAt) : null;
18972
+ this.log.warn?.(`WebSocket closed (code=${code}, reason=${reasonText || "none"}${connectedForMs != null ? `, connectedForMs=${connectedForMs}` : ""})`);
18973
+ await this.reconnect({ cause: `socket-close:${code}${reasonText ? `:${reasonText}` : ""}` });
18875
18974
  }
18876
18975
  async handleError(socket, error) {
18877
18976
  if (this.socket !== socket)
18878
18977
  return;
18879
18978
  if (this.state === "idle")
18880
18979
  return;
18881
- this.log.error?.("WebSocket error", error);
18882
- await this.reconnect();
18980
+ const summary = summarizeError2(error);
18981
+ this.lastErrorAt = Date.now();
18982
+ this.lastErrorMessage = summary;
18983
+ this.log.error?.(`WebSocket error: ${summary}`);
18984
+ await this.reconnect({ cause: `socket-error:${summary}` });
18883
18985
  }
18884
18986
  async setIdle() {
18885
18987
  if (this.state === "idle")
@@ -18893,6 +18995,46 @@ class WebSocketTransport {
18893
18995
  this.state = "connecting";
18894
18996
  await this.events.send({ type: "connecting" });
18895
18997
  }
18998
+ getDiagnostics() {
18999
+ return {
19000
+ kind: "websocket",
19001
+ url: redactUrlForDiagnostics(this.url),
19002
+ state: this.state,
19003
+ connectionAttemptNo: this.connectionAttemptNo,
19004
+ reconnectCount: this.reconnectCount,
19005
+ lastConnectStartedAt: this.lastConnectStartedAt,
19006
+ lastConnectedAt: this.lastConnectedAt,
19007
+ lastDisconnectedAt: this.lastDisconnectedAt,
19008
+ lastMessageAt: this.lastMessageAt,
19009
+ lastCloseCode: this.lastCloseCode,
19010
+ lastCloseReason: this.lastCloseReason,
19011
+ lastErrorAt: this.lastErrorAt,
19012
+ lastErrorMessage: this.lastErrorMessage,
19013
+ lastReconnectScheduledAt: this.lastReconnectScheduledAt,
19014
+ lastReconnectDelayMs: this.lastReconnectDelayMs,
19015
+ lastReconnectCause: this.lastReconnectCause,
19016
+ socketReadyState: this.socket?.readyState ?? null
19017
+ };
19018
+ }
19019
+ }
19020
+ function stringifyCloseReason(reason) {
19021
+ const text = reason.toString("utf8").trim();
19022
+ return text;
19023
+ }
19024
+ function summarizeError2(error) {
19025
+ if (error instanceof Error) {
19026
+ const code = typeof error.code === "string" ? error.code : null;
19027
+ return code ? `${error.name}: ${error.message} (code=${code})` : `${error.name}: ${error.message}`;
19028
+ }
19029
+ return String(error);
19030
+ }
19031
+ function redactUrlForDiagnostics(raw) {
19032
+ try {
19033
+ const url = new URL(raw);
19034
+ return `${url.protocol}//${url.host}${url.pathname}`;
19035
+ } catch {
19036
+ return raw;
19037
+ }
18896
19038
  }
18897
19039
 
18898
19040
  // ../sdk/dist/sdk/types.js
@@ -19047,6 +19189,7 @@ class InlineSdkClient {
19047
19189
  saveInFlight = null;
19048
19190
  catchUpInFlightByChatId = new Map;
19049
19191
  catchUpRequestedByChatId = new Map;
19192
+ userCatchUpInFlight = null;
19050
19193
  constructor(options) {
19051
19194
  this.options = options;
19052
19195
  this.log = options.logger ?? noopLogger;
@@ -19114,6 +19257,13 @@ class InlineSdkClient {
19114
19257
  await this.flushStateSave();
19115
19258
  await this.protocol.stopTransport();
19116
19259
  }
19260
+ getDiagnostics() {
19261
+ return {
19262
+ started: this.started,
19263
+ baseUrl: this.httpBaseUrl,
19264
+ protocol: this.protocol.getDiagnostics()
19265
+ };
19266
+ }
19117
19267
  rejectOpen(error) {
19118
19268
  this.openRejecter?.(error);
19119
19269
  this.openResolver = null;
@@ -19126,7 +19276,8 @@ class InlineSdkClient {
19126
19276
  return {
19127
19277
  version: 1,
19128
19278
  ...this.state.dateCursor != null ? { dateCursor: this.state.dateCursor } : {},
19129
- ...this.state.lastSeqByChatId != null ? { lastSeqByChatId: { ...this.state.lastSeqByChatId } } : {}
19279
+ ...this.state.lastSeqByChatId != null ? { lastSeqByChatId: { ...this.state.lastSeqByChatId } } : {},
19280
+ ...this.state.lastUserSeq != null ? { lastUserSeq: this.state.lastUserSeq } : {}
19130
19281
  };
19131
19282
  }
19132
19283
  async getMe() {
@@ -19392,6 +19543,7 @@ class InlineSdkClient {
19392
19543
  this.openResolver = null;
19393
19544
  this.openRejecter = null;
19394
19545
  this.initializeDateCursor();
19546
+ this.requestCatchUpUser();
19395
19547
  }
19396
19548
  async initializeDateCursor() {
19397
19549
  const date = this.state.dateCursor ?? nowSeconds();
@@ -19490,6 +19642,10 @@ class InlineSdkClient {
19490
19642
  }
19491
19643
  case "messageActionInvoked": {
19492
19644
  const payload = update.update.messageActionInvoked;
19645
+ if (this.shouldSkipUserSeq(seq)) {
19646
+ return;
19647
+ }
19648
+ this.bumpUserSeq(seq);
19493
19649
  await this.eventStream.send({
19494
19650
  kind: "message.action.invoke",
19495
19651
  interactionId: payload.interactionId,
@@ -19505,6 +19661,10 @@ class InlineSdkClient {
19505
19661
  }
19506
19662
  case "messageActionAnswered": {
19507
19663
  const payload = update.update.messageActionAnswered;
19664
+ if (this.shouldSkipUserSeq(seq)) {
19665
+ return;
19666
+ }
19667
+ this.bumpUserSeq(seq);
19508
19668
  await this.eventStream.send({
19509
19669
  kind: "message.action.answered",
19510
19670
  interactionId: payload.interactionId,
@@ -19551,6 +19711,86 @@ class InlineSdkClient {
19551
19711
  this.scheduleStateSave();
19552
19712
  }
19553
19713
  }
19714
+ shouldSkipUserSeq(seq) {
19715
+ if (!Number.isFinite(seq))
19716
+ return false;
19717
+ const lastUserSeq = this.state.lastUserSeq ?? 0;
19718
+ return seq > 0 && seq <= lastUserSeq;
19719
+ }
19720
+ bumpUserSeq(seq) {
19721
+ if (!Number.isFinite(seq) || seq <= 0)
19722
+ return;
19723
+ const prev = this.state.lastUserSeq ?? 0;
19724
+ if (seq > prev) {
19725
+ this.state.lastUserSeq = seq;
19726
+ this.scheduleStateSave();
19727
+ }
19728
+ }
19729
+ requestCatchUpUser() {
19730
+ const lastUserSeq = this.state.lastUserSeq ?? 0;
19731
+ if (lastUserSeq <= 0) {
19732
+ return;
19733
+ }
19734
+ if (this.userCatchUpInFlight) {
19735
+ return;
19736
+ }
19737
+ this.userCatchUpInFlight = this.doCatchUpUser(lastUserSeq).catch((error) => {
19738
+ this.log.warn?.("GET_UPDATES user catch-up failed; continuing live delivery", {
19739
+ error: extractErrorMessage(error)
19740
+ });
19741
+ }).finally(() => {
19742
+ this.userCatchUpInFlight = null;
19743
+ });
19744
+ }
19745
+ async doCatchUpUser(startSeq) {
19746
+ let cursor = startSeq;
19747
+ while (true) {
19748
+ const result = await this.invoke(Method.GET_UPDATES, {
19749
+ oneofKind: "getUpdates",
19750
+ getUpdates: GetUpdatesInput.create({
19751
+ bucket: UpdateBucket.create({
19752
+ type: {
19753
+ oneofKind: "user",
19754
+ user: {}
19755
+ }
19756
+ }),
19757
+ startSeq: BigInt(cursor),
19758
+ totalLimit: defaultCatchUpTotalLimit
19759
+ })
19760
+ });
19761
+ const payload = result.getUpdates;
19762
+ const deliveredSeq = Number(payload.seq ?? 0n);
19763
+ if (!Number.isSafeInteger(deliveredSeq)) {
19764
+ this.log.warn?.("GET_UPDATES user catch-up returned non-integer seq; aborting", { deliveredSeq });
19765
+ return;
19766
+ }
19767
+ if (payload.resultType === GetUpdatesResult_ResultType.TOO_LONG) {
19768
+ this.log.warn?.("GET_UPDATES user catch-up too long; fast-forwarding cursor", { seq: deliveredSeq });
19769
+ this.bumpUserSeq(deliveredSeq);
19770
+ if (payload.date !== 0n) {
19771
+ this.state.dateCursor = payload.date;
19772
+ }
19773
+ this.scheduleStateSave();
19774
+ return;
19775
+ }
19776
+ for (const update of payload.updates) {
19777
+ await this.handleUpdate(update);
19778
+ }
19779
+ this.bumpUserSeq(deliveredSeq);
19780
+ if (payload.date !== 0n) {
19781
+ this.state.dateCursor = payload.date;
19782
+ }
19783
+ this.scheduleStateSave();
19784
+ if (payload.final) {
19785
+ return;
19786
+ }
19787
+ if (deliveredSeq <= cursor) {
19788
+ this.log.warn?.("GET_UPDATES user catch-up made no progress; aborting", { cursor, deliveredSeq });
19789
+ return;
19790
+ }
19791
+ cursor = deliveredSeq;
19792
+ }
19793
+ }
19554
19794
  requestCatchUpChat(params) {
19555
19795
  const previous = this.catchUpRequestedByChatId.get(params.chatId);
19556
19796
  this.catchUpRequestedByChatId.set(params.chatId, {
@@ -19715,7 +19955,8 @@ class InlineSdkClient {
19715
19955
  const snapshot = {
19716
19956
  version: 1,
19717
19957
  ...this.state.dateCursor != null ? { dateCursor: this.state.dateCursor } : {},
19718
- ...this.state.lastSeqByChatId != null ? { lastSeqByChatId: { ...this.state.lastSeqByChatId } } : {}
19958
+ ...this.state.lastSeqByChatId != null ? { lastSeqByChatId: { ...this.state.lastSeqByChatId } } : {},
19959
+ ...this.state.lastUserSeq != null ? { lastUserSeq: this.state.lastUserSeq } : {}
19719
19960
  };
19720
19961
  this.saveInFlight = store.save(snapshot).catch((error) => {
19721
19962
  this.log.warn?.("Failed to persist SDK state", error);
@@ -34029,9 +34270,17 @@ function looksLikeInlineTargetId(raw, normalizedInput) {
34029
34270
  // src/inline/monitor.ts
34030
34271
  import { mkdir } from "node:fs/promises";
34031
34272
  import path2 from "node:path";
34273
+ import {
34274
+ buildCommandTextFromArgs,
34275
+ findCommandByNativeName,
34276
+ parseCommandArgs,
34277
+ resolveCommandArgMenu
34278
+ } from "openclaw/plugin-sdk/native-command-registry";
34279
+ import { resolveDefaultModelForAgent } from "openclaw/plugin-sdk/agent-runtime";
34280
+ import { applyModelOverrideToSessionEntry, updateSessionStore } from "openclaw/plugin-sdk/config-runtime";
34281
+ import { buildModelsProviderData } from "openclaw/plugin-sdk/models-provider-runtime";
34032
34282
 
34033
34283
  // src/sdk-runtime-compat.ts
34034
- import { createMessageToolButtonsSchema } from "openclaw/plugin-sdk/channel-actions";
34035
34284
  var HISTORY_CONTEXT_MARKER = "[Chat messages since your last reply - for context]";
34036
34285
  var CURRENT_MESSAGE_MARKER = "[Current message - respond to this]";
34037
34286
  var MAX_HISTORY_KEYS = 1000;
@@ -34122,14 +34371,6 @@ function recordPendingHistoryEntryIfEnabled(params) {
34122
34371
  limit: params.limit
34123
34372
  });
34124
34373
  }
34125
- var TYPEBOX_OPTIONAL_SYMBOL = Symbol.for("TypeBox.Optional");
34126
- function markTypeBoxOptional(schema) {
34127
- schema[TYPEBOX_OPTIONAL_SYMBOL] = "Optional";
34128
- return schema;
34129
- }
34130
- function createMessageToolButtonsSchemaCompat() {
34131
- return markTypeBoxOptional(createMessageToolButtonsSchema());
34132
- }
34133
34374
  function extensionForMimeCompat(mime) {
34134
34375
  const normalized = mime?.trim().toLowerCase();
34135
34376
  if (!normalized)
@@ -34230,44 +34471,6 @@ async function createChannelReplyPipelineCompat(params) {
34230
34471
  };
34231
34472
  }
34232
34473
  }
34233
- async function loadNativeCommandHelpersCompat() {
34234
- try {
34235
- const sdk = await import("openclaw/plugin-sdk/command-auth");
34236
- const listNativeCommandSpecsForConfig = typeof sdk.listNativeCommandSpecsForConfig === "function" ? sdk.listNativeCommandSpecsForConfig : null;
34237
- const listSkillCommandsForAgents = typeof sdk.listSkillCommandsForAgents === "function" ? sdk.listSkillCommandsForAgents : null;
34238
- if (!listNativeCommandSpecsForConfig || !listSkillCommandsForAgents) {
34239
- throw new Error("command-auth helpers unavailable");
34240
- }
34241
- return {
34242
- available: true,
34243
- listNativeCommandSpecsForConfig,
34244
- listSkillCommandsForAgents
34245
- };
34246
- } catch {
34247
- return {
34248
- available: false,
34249
- listNativeCommandSpecsForConfig: () => [],
34250
- listSkillCommandsForAgents: () => []
34251
- };
34252
- }
34253
- }
34254
- async function loadPluginCommandSpecsCompat(provider) {
34255
- try {
34256
- const sdk = await import("openclaw/plugin-sdk/plugin-runtime");
34257
- if (typeof sdk.getPluginCommandSpecs !== "function") {
34258
- throw new Error("plugin runtime command helper unavailable");
34259
- }
34260
- return {
34261
- available: true,
34262
- specs: sdk.getPluginCommandSpecs(provider)
34263
- };
34264
- } catch {
34265
- return {
34266
- available: false,
34267
- specs: []
34268
- };
34269
- }
34270
- }
34271
34474
 
34272
34475
  // src/inline/message-formatting.ts
34273
34476
  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.";
@@ -34926,246 +35129,28 @@ function summarizeInlineMessageContent(message) {
34926
35129
  };
34927
35130
  }
34928
35131
 
34929
- // src/inline/command-menu-compat.ts
34930
- var THINKING_LEVEL_CHOICES = ["off", "minimal", "low", "medium", "high", "xhigh"];
34931
- var COMPAT_COMMANDS = [
34932
- {
34933
- key: "tts",
34934
- nativeName: "tts",
34935
- args: [
34936
- {
34937
- name: "action",
34938
- description: "TTS action",
34939
- choices: [
34940
- { value: "on", label: "On" },
34941
- { value: "off", label: "Off" },
34942
- { value: "status", label: "Status" },
34943
- { value: "provider", label: "Provider" },
34944
- { value: "limit", label: "Limit" },
34945
- { value: "summary", label: "Summary" },
34946
- { value: "audio", label: "Audio" },
34947
- { value: "help", label: "Help" }
34948
- ]
34949
- },
34950
- { name: "value", description: "Provider, limit, or text" }
34951
- ],
34952
- argsMenu: {
34953
- arg: "action",
34954
- title: "Choose TTS action:"
34955
- }
34956
- },
34957
- {
34958
- key: "session",
34959
- nativeName: "session",
34960
- args: [
34961
- { name: "action", description: "idle | max-age", choices: ["idle", "max-age"] },
34962
- { name: "value", description: "Duration or off" }
34963
- ],
34964
- argsMenu: "auto"
34965
- },
34966
- {
34967
- key: "subagents",
34968
- nativeName: "subagents",
34969
- args: [
34970
- {
34971
- name: "action",
34972
- description: "list | kill | log | info | send | steer | spawn",
34973
- choices: ["list", "kill", "log", "info", "send", "steer", "spawn"]
34974
- },
34975
- { name: "target", description: "Run id, index, or session key" },
34976
- { name: "value", description: "Additional input" }
34977
- ],
34978
- argsMenu: "auto"
34979
- },
34980
- {
34981
- key: "acp",
34982
- nativeName: "acp",
34983
- args: [
34984
- {
34985
- name: "action",
34986
- description: "Action to run",
34987
- choices: [
34988
- "spawn",
34989
- "cancel",
34990
- "steer",
34991
- "close",
34992
- "sessions",
34993
- "status",
34994
- "set-mode",
34995
- "set",
34996
- "cwd",
34997
- "permissions",
34998
- "timeout",
34999
- "model",
35000
- "reset-options",
35001
- "doctor",
35002
- "install",
35003
- "help"
35004
- ]
35005
- },
35006
- { name: "value", description: "Action arguments" }
35007
- ],
35008
- argsMenu: "auto"
35009
- },
35010
- {
35011
- key: "usage",
35012
- nativeName: "usage",
35013
- args: [{ name: "mode", description: "off, tokens, full, or cost", choices: ["off", "tokens", "full", "cost"] }],
35014
- argsMenu: "auto"
35015
- },
35016
- {
35017
- key: "activation",
35018
- nativeName: "activation",
35019
- args: [{ name: "mode", description: "mention or always", choices: ["mention", "always"] }],
35020
- argsMenu: "auto"
35021
- },
35022
- {
35023
- key: "send",
35024
- nativeName: "send",
35025
- args: [{ name: "mode", description: "on, off, or inherit", choices: ["on", "off", "inherit"] }],
35026
- argsMenu: "auto"
35027
- },
35028
- {
35029
- key: "think",
35030
- nativeName: "think",
35031
- args: [{ name: "level", description: "thinking level", choices: [...THINKING_LEVEL_CHOICES] }],
35032
- argsMenu: "auto"
35033
- },
35034
- {
35035
- key: "verbose",
35036
- nativeName: "verbose",
35037
- args: [{ name: "mode", description: "on or off", choices: ["on", "off"] }],
35038
- argsMenu: "auto"
35039
- },
35040
- {
35041
- key: "fast",
35042
- nativeName: "fast",
35043
- args: [{ name: "mode", description: "status, on, or off", choices: ["status", "on", "off"] }],
35044
- argsMenu: "auto"
35045
- },
35046
- {
35047
- key: "reasoning",
35048
- nativeName: "reasoning",
35049
- args: [{ name: "mode", description: "on, off, or stream", choices: ["on", "off", "stream"] }],
35050
- argsMenu: "auto"
35051
- },
35052
- {
35053
- key: "elevated",
35054
- nativeName: "elevated",
35055
- args: [{ name: "mode", description: "on, off, ask, or full", choices: ["on", "off", "ask", "full"] }],
35056
- argsMenu: "auto"
35057
- }
35058
- ];
35059
- function parsePositionalArgs(definitions, raw) {
35060
- const values = {};
35061
- const trimmed = raw.trim();
35062
- if (!trimmed)
35063
- return values;
35064
- const tokens = trimmed.split(/\s+/).filter(Boolean);
35065
- let index = 0;
35066
- for (const definition of definitions) {
35067
- if (index >= tokens.length)
35068
- break;
35069
- const token = tokens[index];
35070
- if (!token)
35071
- break;
35072
- values[definition.name] = token;
35073
- index += 1;
35074
- }
35075
- return values;
35076
- }
35077
- function parseCommandArgs(command, raw) {
35078
- const trimmed = raw?.trim();
35079
- if (!trimmed)
35080
- return;
35081
- if (!command.args || command.argsParsing === "none") {
35082
- return { raw: trimmed };
35083
- }
35084
- return {
35085
- raw: trimmed,
35086
- values: parsePositionalArgs(command.args, trimmed)
35087
- };
35088
- }
35089
- function findCommandByNativeName(name) {
35090
- const normalized = name.trim().toLowerCase();
35091
- return COMPAT_COMMANDS.find((command) => command.nativeName.toLowerCase() === normalized);
35092
- }
35093
- function resolveCommandArgChoices(arg) {
35094
- const raw = arg.choices ?? [];
35095
- return raw.map((choice) => typeof choice === "string" ? { value: choice, label: choice } : choice);
35096
- }
35097
- function resolveCommandArgMenu(params) {
35098
- const { command, args } = params;
35099
- if (!command.args || !command.argsMenu)
35100
- return null;
35101
- if (command.argsParsing === "none")
35102
- return null;
35103
- const argName = command.argsMenu === "auto" ? command.args.find((arg2) => resolveCommandArgChoices(arg2).length > 0)?.name : command.argsMenu.arg;
35104
- if (!argName)
35105
- return null;
35106
- if (args?.values && args.values[argName] != null)
35107
- return null;
35108
- if (args?.raw && !args.values)
35109
- return null;
35110
- const arg = command.args.find((entry) => entry.name === argName);
35111
- if (!arg)
35112
- return null;
35113
- const choices = resolveCommandArgChoices(arg);
35114
- if (choices.length === 0)
35115
- return null;
35116
- const title = command.argsMenu !== "auto" ? command.argsMenu.title : undefined;
35117
- return {
35118
- arg,
35119
- choices,
35120
- ...title ? { title } : {}
35121
- };
35122
- }
35123
- function buildCommandTextFromArgs(command, args) {
35124
- const values = args?.values ?? {};
35125
- const argDefs = command.args ?? [];
35126
- const renderedArgs = [];
35127
- for (const argDef of argDefs) {
35128
- const value = values[argDef.name];
35129
- if (value == null)
35130
- continue;
35131
- const normalized = typeof value === "string" ? value.trim() : String(value);
35132
- if (!normalized)
35133
- continue;
35134
- renderedArgs.push(normalized);
35132
+ // src/inline/monitor.ts
35133
+ var CHANNEL_ID = "inline";
35134
+ function summarizeSdkMeta(meta3) {
35135
+ if (meta3 == null)
35136
+ return "";
35137
+ if (meta3 instanceof Error)
35138
+ return `${meta3.name}: ${meta3.message}`;
35139
+ if (typeof meta3 === "string")
35140
+ return meta3;
35141
+ try {
35142
+ const json2 = JSON.stringify(meta3);
35143
+ return json2 === undefined ? String(meta3) : json2;
35144
+ } catch {
35145
+ return String(meta3);
35135
35146
  }
35136
- return renderedArgs.length > 0 ? `/${command.nativeName} ${renderedArgs.join(" ")}` : `/${command.nativeName}`;
35137
35147
  }
35138
- function resolveInlineCompatNativeCommandMenu(commandBody) {
35139
- const normalized = commandBody.trim();
35140
- const match = normalized.match(/^\/([^\s]+)(?:\s+([\s\S]+))?$/);
35141
- if (!match?.[1])
35142
- return null;
35143
- const command = findCommandByNativeName(match[1]);
35144
- if (!command)
35145
- return null;
35146
- const args = parseCommandArgs(command, match[2]);
35147
- const menu = resolveCommandArgMenu({
35148
- command,
35149
- ...args ? { args } : {}
35150
- });
35151
- if (!menu)
35152
- return null;
35153
- const title = menu.title ?? `Choose ${menu.arg.description || menu.arg.name} for /${command.nativeName}.`;
35154
- const rows = [];
35155
- for (let index = 0;index < menu.choices.length; index += 2) {
35156
- const slice = menu.choices.slice(index, index + 2);
35157
- rows.push(slice.map((choice) => ({
35158
- text: choice.label,
35159
- callback_data: buildCommandTextFromArgs(command, {
35160
- values: { [menu.arg.name]: choice.value }
35161
- })
35162
- })));
35163
- }
35164
- return { title, buttons: rows };
35148
+ function formatSdkLogLine(message, meta3) {
35149
+ const detail = summarizeSdkMeta(meta3);
35150
+ if (!detail)
35151
+ return message;
35152
+ return `${message} ${detail}`;
35165
35153
  }
35166
-
35167
- // src/inline/monitor.ts
35168
- var CHANNEL_ID = "inline";
35169
35154
  var DEFAULT_DM_HISTORY_LIMIT = 6;
35170
35155
  var HISTORY_LINE_MAX_CHARS = 280;
35171
35156
  var URL_LIKE_PATTERN = /https?:\/\/\S+/i;
@@ -35228,35 +35213,125 @@ function callbackDataToUtf8(data) {
35228
35213
  return;
35229
35214
  }
35230
35215
  }
35216
+ function buildInlineInboundMessageSid(params) {
35217
+ if (params.callbackActionEvent) {
35218
+ return `callback:${String(params.callbackActionEvent.targetMessageId)}:${String(params.callbackActionEvent.interactionId)}`;
35219
+ }
35220
+ return String(params.msgId);
35221
+ }
35231
35222
  var INLINE_ACTION_MAX_ROWS = 8;
35232
35223
  var INLINE_ACTION_MAX_PER_ROW = 8;
35233
35224
  function isRecord3(value) {
35234
35225
  return typeof value === "object" && value !== null;
35235
35226
  }
35227
+ function resolveInlineNativeCommandMenu(params) {
35228
+ const normalized = params.commandBody.trim();
35229
+ const match = normalized.match(/^\/([^\s]+)(?:\s+([\s\S]+))?$/);
35230
+ if (!match?.[1])
35231
+ return null;
35232
+ const command = findCommandByNativeName(match[1], "telegram");
35233
+ if (!command)
35234
+ return null;
35235
+ const args = parseCommandArgs(command, match[2]);
35236
+ const menu = resolveCommandArgMenu({
35237
+ command,
35238
+ ...args ? { args } : {},
35239
+ cfg: params.cfg
35240
+ });
35241
+ if (!menu)
35242
+ return null;
35243
+ const title = menu.title ?? `Choose ${menu.arg.description || menu.arg.name} for /${command.nativeName}.`;
35244
+ const rows = [];
35245
+ for (let index = 0;index < menu.choices.length; index += 2) {
35246
+ const slice = menu.choices.slice(index, index + 2);
35247
+ rows.push(slice.map((choice) => ({
35248
+ text: choice.label,
35249
+ callback_data: buildCommandTextFromArgs(command, {
35250
+ values: { [menu.arg.name]: choice.value }
35251
+ })
35252
+ })));
35253
+ }
35254
+ return { title, buttons: rows };
35255
+ }
35236
35256
  function mapInlineModelPickerCallbackToCommand(raw) {
35237
- const trimmed = raw.trim();
35238
- if (!trimmed)
35257
+ const callback = parseInlineModelPickerCallback(raw);
35258
+ if (!callback)
35239
35259
  return;
35240
- if (trimmed === "mdl_prov" || trimmed === "mdl_back") {
35241
- return "/models";
35260
+ switch (callback.type) {
35261
+ case "providers":
35262
+ case "back":
35263
+ return "/models";
35264
+ case "list":
35265
+ return `/models ${callback.provider} ${String(callback.page)}`;
35266
+ case "select":
35267
+ return callback.provider ? `/model ${callback.provider}/${callback.model}` : `/model ${callback.model}`;
35242
35268
  }
35269
+ }
35270
+ function parseInlineModelPickerCallback(raw) {
35271
+ const trimmed = raw.trim();
35272
+ if (!trimmed)
35273
+ return null;
35274
+ if (trimmed === "mdl_prov")
35275
+ return { type: "providers" };
35276
+ if (trimmed === "mdl_back")
35277
+ return { type: "back" };
35243
35278
  const listMatch = trimmed.match(/^mdl_list_([a-z0-9_-]+)_(\d+)$/i);
35244
35279
  if (listMatch?.[1] && listMatch[2]) {
35245
35280
  const provider = listMatch[1].trim();
35246
35281
  const page = Number.parseInt(listMatch[2], 10);
35247
35282
  if (provider && Number.isFinite(page) && page > 0) {
35248
- return `/models ${provider} ${String(page)}`;
35283
+ return { type: "list", provider, page };
35249
35284
  }
35250
35285
  }
35251
35286
  const standardSelectionMatch = trimmed.match(/^mdl_sel_(.+)$/);
35252
35287
  if (standardSelectionMatch?.[1]?.trim()) {
35253
- return `/model ${standardSelectionMatch[1].trim()}`;
35288
+ const modelRef = standardSelectionMatch[1].trim();
35289
+ const slashIndex = modelRef.indexOf("/");
35290
+ if (slashIndex > 0 && slashIndex < modelRef.length - 1) {
35291
+ return {
35292
+ type: "select",
35293
+ provider: modelRef.slice(0, slashIndex),
35294
+ model: modelRef.slice(slashIndex + 1)
35295
+ };
35296
+ }
35254
35297
  }
35255
35298
  const compactSelectionMatch = trimmed.match(/^mdl_sel\/(.+)$/);
35256
35299
  if (compactSelectionMatch?.[1]?.trim()) {
35257
- return `/model ${compactSelectionMatch[1].trim()}`;
35300
+ return { type: "select", model: compactSelectionMatch[1].trim() };
35258
35301
  }
35259
- return;
35302
+ return null;
35303
+ }
35304
+ function resolveInlineModelPickerSelection(params) {
35305
+ if (params.callback.provider) {
35306
+ return {
35307
+ kind: "resolved",
35308
+ provider: params.callback.provider,
35309
+ model: params.callback.model
35310
+ };
35311
+ }
35312
+ const matchingProviders = params.providers.filter((id) => params.byProvider.get(id)?.has(params.callback.model));
35313
+ if (matchingProviders.length === 1 && matchingProviders[0]) {
35314
+ return {
35315
+ kind: "resolved",
35316
+ provider: matchingProviders[0],
35317
+ model: params.callback.model
35318
+ };
35319
+ }
35320
+ return {
35321
+ kind: "ambiguous",
35322
+ model: params.callback.model
35323
+ };
35324
+ }
35325
+ function buildInlineModelProviderButtons(providers) {
35326
+ const rows = [];
35327
+ for (let index = 0;index < providers.length; index += 2) {
35328
+ const slice = providers.slice(index, index + 2);
35329
+ rows.push(slice.map((provider) => ({
35330
+ text: `${provider.id} (${provider.count})`,
35331
+ callback_data: `mdl_list_${provider.id}_1`
35332
+ })));
35333
+ }
35334
+ return rows;
35260
35335
  }
35261
35336
  function normalizeInlineActionCallbackData(raw) {
35262
35337
  const trimmed = raw.trim();
@@ -35264,6 +35339,14 @@ function normalizeInlineActionCallbackData(raw) {
35264
35339
  return "";
35265
35340
  return mapInlineModelPickerCallbackToCommand(trimmed) ?? trimmed;
35266
35341
  }
35342
+ function normalizeInlineTelegramButtonCallbackData(raw) {
35343
+ const trimmed = raw.trim();
35344
+ if (!trimmed)
35345
+ return "";
35346
+ if (parseInlineModelPickerCallback(trimmed))
35347
+ return trimmed;
35348
+ return normalizeInlineActionCallbackData(trimmed);
35349
+ }
35267
35350
  function normalizeReplyMarkupButtonsWith(raw, options) {
35268
35351
  if (!Array.isArray(raw))
35269
35352
  return [];
@@ -35305,7 +35388,7 @@ function resolveInlineReplyActions(payload) {
35305
35388
  } else if (telegramData && Object.prototype.hasOwnProperty.call(telegramData, "buttons")) {
35306
35389
  rawButtons = telegramData.buttons;
35307
35390
  hasExplicitButtons = true;
35308
- mapCallbackData = normalizeInlineActionCallbackData;
35391
+ mapCallbackData = normalizeInlineTelegramButtonCallbackData;
35309
35392
  } else if (Object.prototype.hasOwnProperty.call(payload, "buttons")) {
35310
35393
  rawButtons = payload.buttons;
35311
35394
  hasExplicitButtons = true;
@@ -35870,19 +35953,35 @@ async function monitorInlineProvider(params) {
35870
35953
  const stateDir = core3.state.resolveStateDir();
35871
35954
  const statePath = path2.join(stateDir, "channels", "inline", `${account.accountId}.json`);
35872
35955
  await mkdir(path2.dirname(statePath), { recursive: true });
35956
+ let client = null;
35957
+ const pushDiagnostics = (patch) => {
35958
+ statusSink?.({
35959
+ ...patch ?? {},
35960
+ ...client ? { diagnostics: client.getDiagnostics() } : {}
35961
+ });
35962
+ };
35873
35963
  const sdkLog = {
35874
- debug: (msg) => log?.debug?.(msg),
35875
- info: (msg) => log?.info(msg),
35876
- warn: (msg) => log?.warn(msg),
35877
- error: (msg) => log?.error(msg)
35964
+ debug: (msg, meta3) => log?.debug?.(formatSdkLogLine(msg, meta3)),
35965
+ info: (msg, meta3) => log?.info(formatSdkLogLine(msg, meta3)),
35966
+ warn: (msg, meta3) => {
35967
+ const line = formatSdkLogLine(msg, meta3);
35968
+ log?.warn(line);
35969
+ pushDiagnostics({ lastError: line });
35970
+ },
35971
+ error: (msg, meta3) => {
35972
+ const line = formatSdkLogLine(msg, meta3);
35973
+ log?.error(line);
35974
+ pushDiagnostics({ lastError: line });
35975
+ }
35878
35976
  };
35879
- const client = new InlineSdkClient({
35977
+ client = new InlineSdkClient({
35880
35978
  baseUrl: account.baseUrl,
35881
35979
  token,
35882
35980
  logger: sdkLog,
35883
35981
  state: new JsonFileStateStore(statePath)
35884
35982
  });
35885
35983
  await client.connect(abortSignal);
35984
+ pushDiagnostics();
35886
35985
  const meResult = await client.invokeRaw(Method.GET_ME, {
35887
35986
  oneofKind: "getMe",
35888
35987
  getMe: {}
@@ -35893,6 +35992,7 @@ async function monitorInlineProvider(params) {
35893
35992
  const meId = meResult.getMe.user.id;
35894
35993
  const botUsername = normalizeInlineUsername(meResult.getMe.user.username)?.toLowerCase();
35895
35994
  log?.info(`[${account.accountId}] inline connected (me=${String(meId)})`);
35995
+ pushDiagnostics();
35896
35996
  const chatCache = new Map;
35897
35997
  const senderProfilesById = new Map;
35898
35998
  const botMessageIdsByChat = new Map;
@@ -36140,7 +36240,12 @@ ${JSON.stringify(payload)}`;
36140
36240
  await answerInlineMessageAction(client, callbackActionEvent.interactionId);
36141
36241
  callbackActionAnswered = true;
36142
36242
  };
36143
- const shouldEditCallbackTargetInPlace = false;
36243
+ if (callbackActionEvent) {
36244
+ await answerCallbackIfNeeded().catch((error48) => {
36245
+ runtime2.error?.(`inline callback answer failed: ${String(error48)}`);
36246
+ });
36247
+ }
36248
+ const shouldEditCallbackTargetInPlace = callbackActionEvent != null;
36144
36249
  const normalizedCommandBody = callbackCommandBody ?? normalizeInlineCommandBody(rawBody, botUsername);
36145
36250
  const allowTextCommands = core3.channel.commands.shouldHandleTextCommands({
36146
36251
  cfg,
@@ -36316,7 +36421,10 @@ ${JSON.stringify(payload)}`;
36316
36421
  continue;
36317
36422
  }
36318
36423
  const parseMarkdown = account.config.parseMarkdown ?? true;
36319
- const nativeCommandMenu = resolveInlineCompatNativeCommandMenu(normalizedCommandBody);
36424
+ const nativeCommandMenu = resolveInlineNativeCommandMenu({
36425
+ commandBody: normalizedCommandBody,
36426
+ cfg
36427
+ });
36320
36428
  if (nativeCommandMenu) {
36321
36429
  const menuActions = resolveInlineReplyActions({
36322
36430
  channelData: {
@@ -36325,13 +36433,132 @@ ${JSON.stringify(payload)}`;
36325
36433
  }
36326
36434
  }
36327
36435
  });
36328
- const sent = await client.sendMessage({
36329
- chatId,
36330
- text: nativeCommandMenu.title,
36331
- ...menuActions ? { actions: menuActions } : {}
36436
+ let deliveredNativeMenu = false;
36437
+ if (shouldEditCallbackTargetInPlace && callbackActionEvent) {
36438
+ try {
36439
+ const result = await client.invokeRaw(Method.EDIT_MESSAGE, {
36440
+ oneofKind: "editMessage",
36441
+ editMessage: {
36442
+ messageId: callbackActionEvent.targetMessageId,
36443
+ peerId: buildChatPeer2(chatId),
36444
+ text: nativeCommandMenu.title,
36445
+ ...menuActions ? { actions: menuActions } : {},
36446
+ parseMarkdown
36447
+ }
36448
+ });
36449
+ if (result.oneofKind !== "editMessage") {
36450
+ throw new Error(`inline native command menu: expected editMessage result, got ${String(result.oneofKind)}`);
36451
+ }
36452
+ deliveredNativeMenu = true;
36453
+ } catch (error48) {
36454
+ runtime2.error?.(`inline native command menu edit failed; falling back to send (${String(error48)})`);
36455
+ }
36456
+ }
36457
+ if (!deliveredNativeMenu) {
36458
+ const sent = await client.sendMessage({
36459
+ chatId,
36460
+ text: nativeCommandMenu.title,
36461
+ ...menuActions ? { actions: menuActions } : {}
36462
+ });
36463
+ if (sent.messageId != null) {
36464
+ rememberBotMessageId(botMessageIdsByChat, chatId, sent.messageId);
36465
+ }
36466
+ }
36467
+ statusSink?.({ lastOutboundAt: Date.now() });
36468
+ await answerCallbackIfNeeded().catch((error48) => {
36469
+ runtime2.error?.(`inline callback answer failed: ${String(error48)}`);
36470
+ });
36471
+ continue;
36472
+ }
36473
+ const modelPickerCallbackData = callbackActionEvent ? callbackDataToUtf8(callbackActionEvent.data) : undefined;
36474
+ const modelPickerCallback = modelPickerCallbackData ? parseInlineModelPickerCallback(modelPickerCallbackData) : null;
36475
+ if (shouldEditCallbackTargetInPlace && callbackActionEvent && modelPickerCallback?.type === "select") {
36476
+ const deliverModelPickerEdit = async (text, buttons) => {
36477
+ const actions = resolveInlineReplyActions({
36478
+ channelData: {
36479
+ inline: {
36480
+ buttons
36481
+ }
36482
+ }
36483
+ }) ?? { rows: [] };
36484
+ try {
36485
+ const result = await client.invokeRaw(Method.EDIT_MESSAGE, {
36486
+ oneofKind: "editMessage",
36487
+ editMessage: {
36488
+ messageId: callbackActionEvent.targetMessageId,
36489
+ peerId: buildChatPeer2(chatId),
36490
+ text,
36491
+ actions,
36492
+ parseMarkdown
36493
+ }
36494
+ });
36495
+ if (result.oneofKind !== "editMessage") {
36496
+ throw new Error(`inline model picker edit: expected editMessage result, got ${String(result.oneofKind)}`);
36497
+ }
36498
+ } catch (error48) {
36499
+ runtime2.error?.(`inline model picker edit failed; falling back to send (${String(error48)})`);
36500
+ const sent = await client.sendMessage({
36501
+ chatId,
36502
+ text,
36503
+ actions,
36504
+ parseMarkdown
36505
+ });
36506
+ if (sent.messageId != null) {
36507
+ rememberBotMessageId(botMessageIdsByChat, chatId, sent.messageId);
36508
+ }
36509
+ }
36510
+ };
36511
+ const { byProvider, providers } = await buildModelsProviderData(cfg, route.agentId);
36512
+ const providerButtons = buildInlineModelProviderButtons(providers.map((provider) => ({
36513
+ id: provider,
36514
+ count: byProvider.get(provider)?.size ?? 0
36515
+ })));
36516
+ const selection = resolveInlineModelPickerSelection({
36517
+ callback: modelPickerCallback,
36518
+ providers,
36519
+ byProvider
36332
36520
  });
36333
- if (sent.messageId != null) {
36334
- rememberBotMessageId(botMessageIdsByChat, chatId, sent.messageId);
36521
+ if (selection.kind !== "resolved") {
36522
+ await deliverModelPickerEdit(`Could not resolve model "${selection.model}".
36523
+
36524
+ Select a provider:`, providerButtons);
36525
+ } else {
36526
+ const modelSet = byProvider.get(selection.provider);
36527
+ if (!modelSet?.has(selection.model)) {
36528
+ await deliverModelPickerEdit(`❌ Model "${selection.provider}/${selection.model}" is not allowed.`, []);
36529
+ } else {
36530
+ try {
36531
+ const storePath2 = core3.channel.session.resolveStorePath(cfg.session?.store, {
36532
+ agentId: route.agentId
36533
+ });
36534
+ const resolvedDefault = resolveDefaultModelForAgent({
36535
+ cfg,
36536
+ agentId: route.agentId
36537
+ });
36538
+ const isDefaultSelection = selection.provider === resolvedDefault.provider && selection.model === resolvedDefault.model;
36539
+ await updateSessionStore(storePath2, (store) => {
36540
+ const entry = store[route.sessionKey] ?? {
36541
+ sessionId: route.sessionKey,
36542
+ updatedAt: Date.now()
36543
+ };
36544
+ store[route.sessionKey] = entry;
36545
+ applyModelOverrideToSessionEntry({
36546
+ entry,
36547
+ selection: {
36548
+ provider: selection.provider,
36549
+ model: selection.model,
36550
+ isDefault: isDefaultSelection
36551
+ }
36552
+ });
36553
+ });
36554
+ const actionText = isDefaultSelection ? "reset to default" : `changed to **${selection.provider}/${selection.model}**`;
36555
+ await deliverModelPickerEdit(`✅ Model ${actionText}
36556
+
36557
+ This model will be used for your next message.`, []);
36558
+ } catch (error48) {
36559
+ await deliverModelPickerEdit(`❌ Failed to change model: ${String(error48)}`, []);
36560
+ }
36561
+ }
36335
36562
  }
36336
36563
  statusSink?.({ lastOutboundAt: Date.now() });
36337
36564
  await answerCallbackIfNeeded().catch((error48) => {
@@ -36421,7 +36648,10 @@ ${currentEntityText}` : null
36421
36648
  ...senderUsername ? { SenderUsername: senderUsername } : {},
36422
36649
  Provider: CHANNEL_ID,
36423
36650
  Surface: effectiveSurface,
36424
- MessageSid: String(msg.id),
36651
+ MessageSid: buildInlineInboundMessageSid({
36652
+ msgId: msg.id,
36653
+ ...callbackActionEvent ? { callbackActionEvent } : {}
36654
+ }),
36425
36655
  ...replyThreadContext ? { MessageThreadId: String(replyThreadContext.childChatId) } : {},
36426
36656
  ...replyThreadContext?.threadLabel ? { ThreadLabel: replyThreadContext.threadLabel } : {},
36427
36657
  ...msg.replyToMsgId != null ? { ReplyToId: String(msg.replyToMsgId) } : {},
@@ -36476,12 +36706,20 @@ ${currentEntityText}` : null
36476
36706
  responsePrefixContextProvider: replyPipeline.responsePrefixContextProvider
36477
36707
  } : {}
36478
36708
  };
36709
+ const callbackTargetMessage = shouldEditCallbackTargetInPlace && callbackActionEvent ? await findChatMessageById({
36710
+ client,
36711
+ chatId,
36712
+ messageId: callbackActionEvent.targetMessageId,
36713
+ limit: REPLY_TARGET_LOOKUP_LIMIT,
36714
+ meId,
36715
+ botMessageIdsByChat
36716
+ }).catch(() => null) : null;
36479
36717
  const streamViaEditMessage = account.config.streamViaEditMessage === true && !shouldEditCallbackTargetInPlace;
36480
36718
  const defaultReplyToMsgId = isGroup && msg.replyToMsgId != null ? msg.id : undefined;
36481
36719
  const disableBlockStreaming = streamViaEditMessage ? true : typeof account.config.blockStreaming === "boolean" ? !account.config.blockStreaming : undefined;
36482
36720
  const editStreamState = {
36483
- messageId: null,
36484
- accumulatedText: "",
36721
+ messageId: shouldEditCallbackTargetInPlace ? callbackActionEvent?.targetMessageId ?? null : null,
36722
+ accumulatedText: callbackTargetMessage?.message ?? "",
36485
36723
  lastPartialText: "",
36486
36724
  finalTextAccumulator: "",
36487
36725
  failed: false,
@@ -36649,7 +36887,7 @@ ${currentEntityText}` : null
36649
36887
  return false;
36650
36888
  const nextText = text.trim();
36651
36889
  const textForEdit = nextText || editStreamState.accumulatedText;
36652
- if (!textForEdit)
36890
+ if (!textForEdit && actions === undefined)
36653
36891
  return true;
36654
36892
  const shouldSkipTextUpdate = !editStreamState.failed && textForEdit === editStreamState.accumulatedText;
36655
36893
  if (shouldSkipTextUpdate && actions === undefined)
@@ -36675,6 +36913,16 @@ ${currentEntityText}` : null
36675
36913
  return true;
36676
36914
  };
36677
36915
  if (mediaList.length === 0) {
36916
+ if (shouldEditCallbackTargetInPlace && editStreamState.messageId != null) {
36917
+ const callbackEditActions = outboundActions ?? { rows: [] };
36918
+ if (!outboundText.trim() && outboundActions === undefined) {
36919
+ return;
36920
+ }
36921
+ await updateStreamedMessage(outboundText, callbackEditActions);
36922
+ delivered = true;
36923
+ statusSink?.({ lastOutboundAt: Date.now() });
36924
+ return;
36925
+ }
36678
36926
  if (streamViaEditMessage && infoKind === "final" && finalDeliveredForCurrentAssistantMessage && editStreamState.messageId != null) {
36679
36927
  await resetEditStreamForAssistantMessage();
36680
36928
  }
@@ -36790,6 +37038,10 @@ Attachment: ${mediaUrl}` : `Attachment: ${mediaUrl}`;
36790
37038
  runtime2.error?.(`inline monitor loop crashed: ${String(err)}`);
36791
37039
  }
36792
37040
  })();
37041
+ const diagnosticsTimer = setInterval(() => {
37042
+ pushDiagnostics();
37043
+ }, 15000);
37044
+ diagnosticsTimer.unref?.();
36793
37045
  let stopPromise = null;
36794
37046
  const stop = async () => {
36795
37047
  if (stopPromise) {
@@ -36797,6 +37049,7 @@ Attachment: ${mediaUrl}` : `Attachment: ${mediaUrl}`;
36797
37049
  return;
36798
37050
  }
36799
37051
  stopPromise = (async () => {
37052
+ clearInterval(diagnosticsTimer);
36800
37053
  await client.close().catch(() => {});
36801
37054
  await loop.catch(() => {});
36802
37055
  })();
@@ -36809,6 +37062,7 @@ Attachment: ${mediaUrl}` : `Attachment: ${mediaUrl}`;
36809
37062
  }
36810
37063
 
36811
37064
  // src/inline/actions.ts
37065
+ import { createMessageToolButtonsSchema } from "openclaw/plugin-sdk/channel-actions";
36812
37066
  import {
36813
37067
  normalizeInteractiveReply,
36814
37068
  reduceInteractiveReply
@@ -37597,7 +37851,7 @@ function describeInlineMessageTool({
37597
37851
  const schema = buttonsEnabled ? [
37598
37852
  {
37599
37853
  properties: {
37600
- buttons: createMessageToolButtonsSchemaCompat()
37854
+ buttons: createMessageToolButtonsSchema()
37601
37855
  }
37602
37856
  }
37603
37857
  ] : [];
@@ -38649,6 +38903,7 @@ async function probeInlineAccount(account, timeoutMs) {
38649
38903
 
38650
38904
  // src/inline/status-issues.ts
38651
38905
  import { asString, isRecord as isRecord5 } from "openclaw/plugin-sdk/status-helpers";
38906
+ var RECENT_RUNTIME_ISSUE_MS = 30 * 60 * 1000;
38652
38907
  function readInlineProbeSummary(value) {
38653
38908
  if (!isRecord5(value)) {
38654
38909
  return {};
@@ -38666,6 +38921,38 @@ function readInlineProbeSummary(value) {
38666
38921
  function looksLikeAuthError(text) {
38667
38922
  return /(401|403|unauth|forbidden|invalid token|token invalid|unauthorized)/i.test(text);
38668
38923
  }
38924
+ function readInlineDiagnosticsSummary(value) {
38925
+ if (!isRecord5(value)) {
38926
+ return {};
38927
+ }
38928
+ const protocolValue = isRecord5(value.protocol) ? value.protocol : undefined;
38929
+ const transportValue = (protocolValue && isRecord5(protocolValue.transport) ? protocolValue.transport : undefined) ?? (isRecord5(value.transport) ? value.transport : undefined);
38930
+ const pingValue = protocolValue && isRecord5(protocolValue.ping) ? protocolValue.ping : undefined;
38931
+ return {
38932
+ ...protocolValue ? {
38933
+ protocol: {
38934
+ ...typeof protocolValue.lastFailureAt === "number" ? { lastFailureAt: protocolValue.lastFailureAt } : {},
38935
+ ...asString(protocolValue.lastFailureReason) ? { lastFailureReason: asString(protocolValue.lastFailureReason) } : {},
38936
+ ...pingValue && typeof pingValue.lastTimeoutAt === "number" ? {
38937
+ ping: {
38938
+ lastTimeoutAt: pingValue.lastTimeoutAt
38939
+ }
38940
+ } : {}
38941
+ }
38942
+ } : {},
38943
+ ...transportValue ? {
38944
+ transport: {
38945
+ ...typeof transportValue.reconnectCount === "number" ? { reconnectCount: transportValue.reconnectCount } : {},
38946
+ ...asString(transportValue.lastReconnectCause) ? { lastReconnectCause: asString(transportValue.lastReconnectCause) } : {}
38947
+ }
38948
+ } : {}
38949
+ };
38950
+ }
38951
+ function isRecentTimestamp(timestamp) {
38952
+ if (typeof timestamp !== "number" || !Number.isFinite(timestamp) || timestamp <= 0)
38953
+ return false;
38954
+ return Date.now() - timestamp <= RECENT_RUNTIME_ISSUE_MS;
38955
+ }
38669
38956
  function collectInlineStatusIssues(accounts) {
38670
38957
  const issues = [];
38671
38958
  for (const entry of accounts) {
@@ -38721,6 +39008,25 @@ function collectInlineStatusIssues(accounts) {
38721
39008
  fix: "Verify token/baseUrl connectivity, then re-run channel status."
38722
39009
  });
38723
39010
  }
39011
+ const diagnostics = readInlineDiagnosticsSummary(entry.diagnostics);
39012
+ if (isRecentTimestamp(diagnostics.protocol?.lastFailureAt) && (diagnostics.transport?.reconnectCount ?? 0) >= 3) {
39013
+ issues.push({
39014
+ channel: "inline",
39015
+ accountId,
39016
+ kind: "runtime",
39017
+ message: `Inline connection is flapping (${diagnostics.transport?.reconnectCount ?? 0} reconnects). ` + `${diagnostics.protocol?.lastFailureReason ?? diagnostics.transport?.lastReconnectCause ?? "Recent reconnect failures detected."}`,
39018
+ fix: "Inspect gateway logs for websocket close/error details and verify Inline API/network stability."
39019
+ });
39020
+ }
39021
+ if (isRecentTimestamp(diagnostics.protocol?.ping?.lastTimeoutAt)) {
39022
+ issues.push({
39023
+ channel: "inline",
39024
+ accountId,
39025
+ kind: "runtime",
39026
+ message: "Inline ping watchdog triggered a reconnect recently.",
39027
+ fix: "Check websocket latency/packet loss and compare last pong timing in the Inline diagnostics snapshot."
39028
+ });
39029
+ }
38724
39030
  }
38725
39031
  return issues;
38726
39032
  }
@@ -39735,22 +40041,29 @@ var inlineChannelPlugin = {
39735
40041
  buildChannelSummary: ({ snapshot }) => buildTokenChannelStatusSummary(snapshot),
39736
40042
  probeAccount: async ({ account, timeoutMs }) => await probeInlineAccount(account, timeoutMs),
39737
40043
  formatCapabilitiesProbe: ({ probe }) => formatInlineCapabilitiesProbeLines(probe),
39738
- buildAccountSnapshot: ({ account, runtime: runtime2, probe }) => ({
39739
- accountId: account.accountId,
39740
- name: account.name,
39741
- enabled: account.enabled,
39742
- configured: account.configured,
39743
- baseUrl: account.baseUrl ? "[set]" : "[missing]",
39744
- tokenSource: account.token ? "config" : account.tokenFile ? "file" : "missing",
39745
- running: runtime2?.running ?? false,
39746
- lastStartAt: runtime2?.lastStartAt ?? null,
39747
- lastStopAt: runtime2?.lastStopAt ?? null,
39748
- lastError: runtime2?.lastError ?? null,
39749
- lastInboundAt: runtime2?.lastInboundAt ?? null,
39750
- lastOutboundAt: runtime2?.lastOutboundAt ?? null,
39751
- lastProbeAt: runtime2?.lastProbeAt ?? null,
39752
- ...probe !== undefined ? { probe } : {}
39753
- })
40044
+ buildAccountSnapshot: ({ account, runtime: runtime2, probe }) => {
40045
+ const snapshot = {
40046
+ accountId: account.accountId,
40047
+ name: account.name,
40048
+ enabled: account.enabled,
40049
+ configured: account.configured,
40050
+ baseUrl: account.baseUrl ? "[set]" : "[missing]",
40051
+ tokenSource: account.token ? "config" : account.tokenFile ? "file" : "missing",
40052
+ running: runtime2?.running ?? false,
40053
+ lastStartAt: runtime2?.lastStartAt ?? null,
40054
+ lastStopAt: runtime2?.lastStopAt ?? null,
40055
+ lastError: runtime2?.lastError ?? null,
40056
+ lastInboundAt: runtime2?.lastInboundAt ?? null,
40057
+ lastOutboundAt: runtime2?.lastOutboundAt ?? null,
40058
+ lastProbeAt: runtime2?.lastProbeAt ?? null,
40059
+ ...probe !== undefined ? { probe } : {}
40060
+ };
40061
+ const diagnostics = runtime2?.diagnostics;
40062
+ if (diagnostics !== undefined) {
40063
+ snapshot.diagnostics = diagnostics;
40064
+ }
40065
+ return snapshot;
40066
+ }
39754
40067
  },
39755
40068
  gateway: {
39756
40069
  startAccount: async (ctx) => {
@@ -40516,7 +40829,12 @@ async function callInlineBotApi(params) {
40516
40829
  if (params.body !== undefined) {
40517
40830
  request.body = JSON.stringify(params.body);
40518
40831
  }
40519
- const response = await fetch(url2, request);
40832
+ let response;
40833
+ try {
40834
+ response = await fetch(url2, request);
40835
+ } catch (error48) {
40836
+ throw new Error(`inline_bot_commands: ${params.method} ${redactInlineBotApiUrl(url2)} fetch failed: ${summarizeInlineBotApiError(error48)}`);
40837
+ }
40520
40838
  const payload = await response.json().catch(() => null);
40521
40839
  return { response, payload };
40522
40840
  };
@@ -40546,6 +40864,20 @@ async function callInlineBotApi(params) {
40546
40864
  }
40547
40865
  return resolve(headerResult);
40548
40866
  }
40867
+ function summarizeInlineBotApiError(error48) {
40868
+ if (error48 instanceof Error) {
40869
+ return `${error48.name}: ${error48.message}`;
40870
+ }
40871
+ return String(error48);
40872
+ }
40873
+ function redactInlineBotApiUrl(raw) {
40874
+ try {
40875
+ const url2 = new URL(raw);
40876
+ return `${url2.protocol}//${url2.host}${url2.pathname.replace(/\/bot[^/]*\//, "/bot<redacted>/")}`;
40877
+ } catch {
40878
+ return raw.replace(/\/bot[^/]*\//, "/bot<redacted>/");
40879
+ }
40880
+ }
40549
40881
 
40550
40882
  // src/inline/bot-commands-tool.ts
40551
40883
  var BOT_COMMAND_LIMIT = 100;
@@ -40706,6 +41038,9 @@ function createInlineBotCommandsTool(ctx) {
40706
41038
  }
40707
41039
 
40708
41040
  // src/inline/bot-commands-sync.ts
41041
+ import { listNativeCommandSpecsForConfig } from "openclaw/plugin-sdk/native-command-registry";
41042
+ import { getPluginCommandSpecs } from "openclaw/plugin-sdk/plugin-runtime";
41043
+ import { listSkillCommandsForAgents } from "openclaw/plugin-sdk/skill-commands-runtime";
40709
41044
  var INLINE_BASE_NATIVE_COMMANDS = [
40710
41045
  { command: "help", description: "Show available commands." },
40711
41046
  { command: "commands", description: "List all slash commands." },
@@ -40735,15 +41070,6 @@ var INLINE_BASE_NATIVE_COMMANDS = [
40735
41070
  ];
40736
41071
  var INLINE_COMMAND_NAME_RE = /^[a-z0-9_]{1,32}$/;
40737
41072
  var INLINE_COMMAND_LIMIT = 100;
40738
- var FALLBACK_NATIVE_COMMAND_HELPERS = {
40739
- available: false,
40740
- listNativeCommandSpecsForConfig: () => [],
40741
- listSkillCommandsForAgents: () => []
40742
- };
40743
- var FALLBACK_PLUGIN_COMMAND_SPECS = {
40744
- available: false,
40745
- specs: []
40746
- };
40747
41073
  function normalizeDynamicCommandName(raw) {
40748
41074
  const trimmed = raw.trim().toLowerCase();
40749
41075
  const withoutSlash = trimmed.startsWith("/") ? trimmed.slice(1) : trimmed;
@@ -40777,10 +41103,12 @@ async function buildInlineNativeCommandsForConfig(params) {
40777
41103
  if (params.cfg.commands?.debug === true) {
40778
41104
  commands.push({ command: "debug", description: "Set runtime debug overrides." });
40779
41105
  }
40780
- const { listNativeCommandSpecsForConfig, listSkillCommandsForAgents } = params.nativeHelpers;
40781
41106
  const skillCommands = shouldSyncInlineNativeSkills(params.cfg) ? listSkillCommandsForAgents({ cfg: params.cfg }) : [];
40782
- const nativeSpecs = listNativeCommandSpecsForConfig(params.cfg, { skillCommands });
40783
- const { specs: pluginSpecs } = params.pluginSpecs;
41107
+ const nativeSpecs = listNativeCommandSpecsForConfig(params.cfg, {
41108
+ skillCommands,
41109
+ provider: "telegram"
41110
+ });
41111
+ const pluginSpecs = getPluginCommandSpecs("inline");
40784
41112
  const seen = new Set;
40785
41113
  const resolved = [];
40786
41114
  for (const base of commands) {
@@ -40797,19 +41125,13 @@ async function buildInlineNativeCommandsForConfig(params) {
40797
41125
  async function syncInlineNativeCommands(params) {
40798
41126
  const accountIds = listInlineAccountIds(params.cfg);
40799
41127
  const nativeEnabled = shouldSyncInlineNativeCommands(params.cfg);
40800
- const nativeHelpers = nativeEnabled ? await loadNativeCommandHelpersCompat() : FALLBACK_NATIVE_COMMAND_HELPERS;
40801
- const pluginSpecs = nativeEnabled ? await loadPluginCommandSpecsCompat("inline") : FALLBACK_PLUGIN_COMMAND_SPECS;
40802
- const usingSdkSource = nativeHelpers.available || pluginSpecs.available;
40803
41128
  const allCommands = nativeEnabled ? await buildInlineNativeCommandsForConfig({
40804
- cfg: params.cfg,
40805
- nativeHelpers,
40806
- pluginSpecs
41129
+ cfg: params.cfg
40807
41130
  }) : [];
40808
41131
  const commands = allCommands.slice(0, INLINE_COMMAND_LIMIT);
40809
41132
  if (allCommands.length > INLINE_COMMAND_LIMIT) {
40810
41133
  params.logger?.warn?.(`[inline] native command sync truncating ${allCommands.length} commands to ${INLINE_COMMAND_LIMIT}`);
40811
41134
  }
40812
- params.logger?.info?.(`[inline] native command source: ${usingSdkSource ? "plugin-sdk" : "fallback"}`);
40813
41135
  let synced = 0;
40814
41136
  let failed = 0;
40815
41137
  for (const accountId of accountIds) {
@@ -40895,5 +41217,5 @@ export {
40895
41217
  src_default as default
40896
41218
  };
40897
41219
 
40898
- //# debugId=CE0AB31A68AAA68C64756E2164756E21
41220
+ //# debugId=3B7100874DF4D61664756E2164756E21
40899
41221
  //# sourceMappingURL=index.js.map