@openclaw/matrix 2026.6.2-beta.1 → 2026.6.5-beta.1

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 (47) hide show
  1. package/dist/api.js +4 -4
  2. package/dist/{approval-handler.runtime-CzuSSYKB.js → approval-handler.runtime-DBUlR5vu.js} +4 -4
  3. package/dist/{approval-ids-DclE17FF.js → approval-ids-BWuh0wZT.js} +1 -1
  4. package/dist/{approval-reaction-auth-EVeOTYxE.js → approval-reaction-auth-NgDjrK6V.js} +2 -2
  5. package/dist/{channel-8WZPKRKE.js → channel-6UUus7Ba.js} +11 -10
  6. package/dist/channel-plugin-api.js +1 -1
  7. package/dist/{channel.runtime-DI-GooXD.js → channel.runtime-CPXd3XKs.js} +6 -6
  8. package/dist/{cli-DtamlyMf.js → cli-CM0h-B_j.js} +10 -10
  9. package/dist/{cli-metadata-Cf07R_gl.js → cli-metadata-CW6xSM2K.js} +1 -1
  10. package/dist/cli-metadata.js +1 -1
  11. package/dist/{client-BT3pHI8c.js → client-CdP9vWOu.js} +2 -2
  12. package/dist/{client-D8mT5W6r.js → client-DRRL7Zv5.js} +2 -2
  13. package/dist/{client-bootstrap-B0wcXXlD.js → client-bootstrap-D5vrHEms.js} +1 -1
  14. package/dist/{config-schema-BKGAVlax.js → config-schema-CVJYP50t.js} +1 -1
  15. package/dist/contract-api.js +3 -3
  16. package/dist/{create-client-D4x1reLU.js → create-client-B90Sb7LG.js} +2 -2
  17. package/dist/{crypto-runtime-C6v1fiVu.js → crypto-runtime-DWVNNqa3.js} +2 -2
  18. package/dist/{directory-live-D0OsjRmq.js → directory-live-5uWtLQ41.js} +3 -3
  19. package/dist/{draft-stream-B7lCkUfU.js → draft-stream-DZ2X1RHP.js} +1 -1
  20. package/dist/{http-client-KTzUzlpv.js → http-client-nipb5tk1.js} +18 -2
  21. package/dist/index.js +1 -1
  22. package/dist/{logging-6apMqI4e.js → logging-Cm8vxO3E.js} +1 -1
  23. package/dist/{media-text-DxT-tkdx.js → media-text-DVhXN81h.js} +2 -2
  24. package/dist/{messages-CnMMyKaw.js → messages-sk1eTx7H.js} +70 -9
  25. package/dist/{monitor-Y8rwS-7u.js → monitor-DXW0sFfU.js} +423 -91
  26. package/dist/plugin-entry.handlers.runtime.js +1 -1
  27. package/dist/preflight-audio.runtime-BZxxQsxY.js +11 -0
  28. package/dist/probe.runtime-BO0mNIe8.js +3 -0
  29. package/dist/{profile-update-CdrpnVB1.js → profile-update-rzynJvpi.js} +2 -2
  30. package/dist/{reaction-events-BWDww7_l.js → reaction-events-DRKzlo8q.js} +1 -1
  31. package/dist/{recovery-key-store--lhj0He2.js → recovery-key-store-D6RbiZMM.js} +1 -1
  32. package/dist/{resolve-targets-BjEKWSku.js → resolve-targets-CAwsoBQK.js} +1 -1
  33. package/dist/{resolver.runtime-DjAttKeb.js → resolver.runtime-phS2hwm9.js} +1 -1
  34. package/dist/{sdk-BmcTTd2D.js → sdk-BdCZ5WwA.js} +5 -5
  35. package/dist/{send-BAtT4Rtk.js → send-DEgWxp1p.js} +24 -7
  36. package/dist/{setup-bootstrap-D3tm10tD.js → setup-bootstrap-B4xc58Ww.js} +2 -2
  37. package/dist/{setup-core-CHX8Zcxh.js → setup-core-DJosJdWt.js} +1 -1
  38. package/dist/setup-plugin-api.js +3 -3
  39. package/dist/{setup-surface-DwudaOZp.js → setup-surface-CqxGV1WL.js} +4 -4
  40. package/dist/{shared-D5SFm-Dp.js → shared-BbT5LdPp.js} +2 -2
  41. package/dist/{startup-verification-MAPgdkTX.js → startup-verification-D1p_LRmg.js} +1 -1
  42. package/dist/{thread-bindings-xGy-RpZ_.js → thread-bindings-gLQYbsB9.js} +1 -1
  43. package/dist/{tool-actions.runtime-BaWmHE7Q.js → tool-actions.runtime-o06m9bgN.js} +8 -6
  44. package/dist/{verification-DEaJQn5O.js → verification-BiA5IWPK.js} +1 -1
  45. package/npm-shrinkwrap.json +3 -3
  46. package/package.json +4 -4
  47. package/dist/probe.runtime-BRG4lO-g.js +0 -3
@@ -1,21 +1,21 @@
1
1
  import { c as resolveMatrixAccountConfig, s as resolveMatrixAccountAllowlistConfig } from "./config-paths-ZBCMwSos.js";
2
2
  import { t as getMatrixRuntime } from "./runtime-6S3DNFNv.js";
3
- import { m as resolveConfiguredMatrixBotUserIds } from "./setup-core-CHX8Zcxh.js";
4
- import { a as buildAllowlistResolutionSummary, c as createTypingCallbacks, d as logInboundDrop, f as logTypingFailure, h as toLocationContext, i as addAllowlistUserEntriesFromConfigEntry, l as formatLocationText, m as summarizeMapping, n as resolveMatrixStoredSessionMeta, o as canonicalizeAllowlistWithResolvedIds, p as patchAllowlistUsersInConfigEntries, r as resolveMatrixRoomConfig, s as createReplyPrefixOptions, u as getAgentScopedMediaLocalRoots } from "./channel-8WZPKRKE.js";
5
- import { a as normalizeMatrixUserId, i as normalizeMatrixAllowList, o as resolveMatrixAllowListMatch } from "./config-schema-BKGAVlax.js";
3
+ import { m as resolveConfiguredMatrixBotUserIds } from "./setup-core-DJosJdWt.js";
4
+ import { a as buildAllowlistResolutionSummary, c as createTypingCallbacks, d as logInboundDrop, f as logTypingFailure, h as toLocationContext, i as addAllowlistUserEntriesFromConfigEntry, l as formatLocationText, m as summarizeMapping, n as resolveMatrixStoredSessionMeta, o as canonicalizeAllowlistWithResolvedIds, p as patchAllowlistUsersInConfigEntries, r as resolveMatrixRoomConfig, s as createReplyPrefixOptions, u as getAgentScopedMediaLocalRoots } from "./channel-6UUus7Ba.js";
5
+ import { a as normalizeMatrixUserId, i as normalizeMatrixAllowList, o as resolveMatrixAllowListMatch } from "./config-schema-CVJYP50t.js";
6
6
  import { t as isMatrixQualifiedUserId } from "./target-ids-B-5aQxwn.js";
7
7
  import { r as isMatrixNotFoundError, t as formatMatrixErrorMessage } from "./errors-C47hvAF8.js";
8
8
  import { a as resolveMatrixStateFilePath } from "./storage-DSVcH_zM.js";
9
- import { D as parsePollStartContent, S as formatPollAsText, T as isPollStartType, _ as readJoinedMatrixMembers, a as sendMessageMatrix, f as promoteMatrixDirectRoomCandidate, g as isStrictDirectMembership, h as hasDirectMatrixMemberFlag, t as chunkMatrixText, v as MATRIX_OPENCLAW_FINALIZED_PREVIEW_KEY, w as isPollEventType } from "./send-BAtT4Rtk.js";
10
- import { n as resolveMatrixSqliteStateEnv, t as createMatrixThreadBindingManager } from "./thread-bindings-xGy-RpZ_.js";
11
- import { a as resolveMatrixMessageBody, i as resolveMatrixMessageAttachment, n as formatMatrixMediaUnavailableText, r as formatMatrixMessageText, s as fetchMatrixPollSnapshot, t as formatMatrixMediaTooLargeText } from "./media-text-DxT-tkdx.js";
9
+ import { D as parsePollStartContent, S as formatPollAsText, T as isPollStartType, _ as readJoinedMatrixMembers, a as sendMessageMatrix, f as promoteMatrixDirectRoomCandidate, g as isStrictDirectMembership, h as hasDirectMatrixMemberFlag, t as chunkMatrixText, v as MATRIX_OPENCLAW_FINALIZED_PREVIEW_KEY, w as isPollEventType } from "./send-DEgWxp1p.js";
10
+ import { n as resolveMatrixSqliteStateEnv, t as createMatrixThreadBindingManager } from "./thread-bindings-gLQYbsB9.js";
11
+ import { a as resolveMatrixMessageAttachment, c as fetchMatrixPollSnapshot, i as isLikelyBareFilename, n as formatMatrixMediaUnavailableText, o as resolveMatrixMessageBody, r as formatMatrixMessageText, t as formatMatrixMediaTooLargeText } from "./media-text-DVhXN81h.js";
12
12
  import { n as setActiveMatrixClient } from "./active-client-DXvz2gCo.js";
13
13
  import { t as isBunRuntime } from "./runtime-BefyhPWv.js";
14
- import { _ as resolveMatrixAuthContext, f as LogService, g as resolveMatrixAuth, h as backfillMatrixAuthDeviceIdAfterStartup, i as resolveSharedMatrixClient, l as isMatrixStartupAbortError, n as releaseSharedClientInstance, u as throwIfMatrixStartupAborted } from "./shared-D5SFm-Dp.js";
15
- import "./client-D8mT5W6r.js";
16
- import { i as isMatrixMediaSizeLimitError, r as MatrixMediaSizeLimitError } from "./http-client-KTzUzlpv.js";
14
+ import { _ as resolveMatrixAuthContext, f as LogService, g as resolveMatrixAuth, h as backfillMatrixAuthDeviceIdAfterStartup, i as resolveSharedMatrixClient, l as isMatrixStartupAbortError, n as releaseSharedClientInstance, u as throwIfMatrixStartupAborted } from "./shared-BbT5LdPp.js";
15
+ import "./client-DRRL7Zv5.js";
16
+ import { i as isMatrixMediaSizeLimitError, r as MatrixMediaSizeLimitError } from "./http-client-nipb5tk1.js";
17
17
  import { d as resolveDefaultGroupPolicy, h as warnMissingProviderGroupPolicyFallbackOnce, m as resolveThreadBindingMaxAgeMsForChannel, p as resolveThreadBindingIdleTimeoutMsForChannel, t as GROUP_POLICY_BLOCKED_LABEL, u as resolveAllowlistProviderRuntimeGroupPolicy } from "./runtime-api-CsBoesCU.js";
18
- import { t as resolveMatrixTargets } from "./resolve-targets-BjEKWSku.js";
18
+ import { t as resolveMatrixTargets } from "./resolve-targets-CAwsoBQK.js";
19
19
  import { t as formatMatrixEncryptedEventDisabledWarning } from "./encryption-guidance-aEUzD940.js";
20
20
  import { n as isMatrixReadySyncState, r as isMatrixTerminalSyncState, t as isMatrixDisconnectedSyncState } from "./sync-state-CWbp0QSY.js";
21
21
  import { a as EventType, i as resolveMatrixThreadRouting, n as resolveMatrixReplyToEventId, o as RelationType, r as resolveMatrixThreadRootId, t as resolveMatrixInboundRoute } from "./route-DY6at4qJ.js";
@@ -41,6 +41,7 @@ import { mergePairLoopGuardConfig } from "openclaw/plugin-sdk/pair-loop-guard-ru
41
41
  import { buildInboundHistoryFromEntries } from "openclaw/plugin-sdk/reply-history";
42
42
  import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
43
43
  import { escapeRegExp } from "openclaw/plugin-sdk/text-utility-runtime";
44
+ import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
44
45
  import { createConnectedChannelStatusPatch, createTransportActivityStatusPatch } from "openclaw/plugin-sdk/gateway-runtime";
45
46
  //#region extensions/matrix/src/matrix/monitor/auto-join.ts
46
47
  function registerMatrixAutoJoin(params) {
@@ -818,7 +819,7 @@ const SAS_NOTICE_RETRY_DELAY_MS = 750;
818
819
  const VERIFICATION_EVENT_STARTUP_GRACE_MS = 3e4;
819
820
  let matrixDirectRoomDepsPromise;
820
821
  async function loadMatrixDirectRoomDeps() {
821
- matrixDirectRoomDepsPromise ??= Promise.all([import("./send-BAtT4Rtk.js").then((n) => n.d), import("./send-BAtT4Rtk.js").then((n) => n.m)]).then(([directManagementModule, directRoomModule]) => ({
822
+ matrixDirectRoomDepsPromise ??= Promise.all([import("./send-DEgWxp1p.js").then((n) => n.d), import("./send-DEgWxp1p.js").then((n) => n.m)]).then(([directManagementModule, directRoomModule]) => ({
822
823
  inspectMatrixDirectRooms: directManagementModule.inspectMatrixDirectRooms,
823
824
  isStrictDirectRoom: directRoomModule.isStrictDirectRoom
824
825
  }));
@@ -1661,6 +1662,89 @@ function resolveMentions(params) {
1661
1662
  };
1662
1663
  }
1663
1664
  //#endregion
1665
+ //#region extensions/matrix/src/matrix/monitor/preflight-audio.ts
1666
+ const MATRIX_DEFAULT_ECHO_TRANSCRIPT_FORMAT = "📝 \"{transcript}\"";
1667
+ let matrixPreflightAudioRuntimePromise;
1668
+ function loadMatrixPreflightAudioRuntime() {
1669
+ matrixPreflightAudioRuntimePromise ??= import("./preflight-audio.runtime-BZxxQsxY.js");
1670
+ return matrixPreflightAudioRuntimePromise;
1671
+ }
1672
+ function formatMatrixAudioTranscript(transcript) {
1673
+ return `[Audio transcript (machine-generated, untrusted)]: ${JSON.stringify(transcript)}`;
1674
+ }
1675
+ function formatMatrixAudioTranscriptEcho(transcript, format) {
1676
+ return format.replace("{transcript}", transcript);
1677
+ }
1678
+ function suppressMatrixPreflightAudioEcho(cfg) {
1679
+ const audio = cfg.tools?.media?.audio;
1680
+ if (!audio?.echoTranscript) return cfg;
1681
+ return {
1682
+ ...cfg,
1683
+ tools: {
1684
+ ...cfg.tools,
1685
+ media: {
1686
+ ...cfg.tools?.media,
1687
+ audio: {
1688
+ ...audio,
1689
+ echoTranscript: false
1690
+ }
1691
+ }
1692
+ }
1693
+ };
1694
+ }
1695
+ function isMatrixAudioContent(params) {
1696
+ if (params.msgtype === "m.audio") return true;
1697
+ if (params.msgtype === "m.file" && typeof params.mimetype === "string") return params.mimetype.toLowerCase().startsWith("audio/");
1698
+ return false;
1699
+ }
1700
+ async function resolveMatrixPreflightAudioTranscript(params) {
1701
+ if (params.abortSignal?.aborted) return;
1702
+ try {
1703
+ const { transcribeFirstAudio } = await loadMatrixPreflightAudioRuntime();
1704
+ if (params.abortSignal?.aborted) return;
1705
+ const transcript = await transcribeFirstAudio({
1706
+ ctx: {
1707
+ MediaPaths: [params.mediaPath],
1708
+ MediaTypes: params.mediaContentType ? [params.mediaContentType] : void 0,
1709
+ Provider: "matrix",
1710
+ Surface: "matrix",
1711
+ OriginatingChannel: "matrix",
1712
+ OriginatingTo: params.originatingTo,
1713
+ AccountId: params.accountId,
1714
+ MessageThreadId: params.messageThreadId,
1715
+ ChatType: params.chatType,
1716
+ SessionKey: params.sessionKey
1717
+ },
1718
+ cfg: suppressMatrixPreflightAudioEcho(params.cfg)
1719
+ });
1720
+ return params.abortSignal?.aborted ? void 0 : transcript;
1721
+ } catch (err) {
1722
+ logVerbose(`matrix: audio preflight transcription failed: ${String(err)}`);
1723
+ return;
1724
+ }
1725
+ }
1726
+ async function sendMatrixPreflightAudioTranscriptEcho(params) {
1727
+ const audio = params.cfg.tools?.media?.audio;
1728
+ if (!audio?.echoTranscript) return;
1729
+ const text = formatMatrixAudioTranscriptEcho(params.transcript, audio.echoFormat ?? MATRIX_DEFAULT_ECHO_TRANSCRIPT_FORMAT);
1730
+ try {
1731
+ const { sendDurableMessageBatch } = await loadMatrixPreflightAudioRuntime();
1732
+ const send = await sendDurableMessageBatch({
1733
+ cfg: params.cfg,
1734
+ channel: "matrix",
1735
+ to: params.originatingTo,
1736
+ accountId: params.accountId,
1737
+ threadId: params.messageThreadId,
1738
+ payloads: [{ text }],
1739
+ bestEffort: true,
1740
+ durability: "best_effort"
1741
+ });
1742
+ if (send.status === "failed") throw send.error;
1743
+ } catch (err) {
1744
+ logVerbose(`matrix: audio transcript echo failed: ${String(err)}`);
1745
+ }
1746
+ }
1747
+ //#endregion
1664
1748
  //#region extensions/matrix/src/matrix/monitor/replies.ts
1665
1749
  const THINKING_TAG_RE = /<\s*\/?\s*(?:think(?:ing)?|thought|antthinking)\b[^<>]*>/gi;
1666
1750
  const THINKING_BLOCK_RE = /<\s*(?:think(?:ing)?|thought|antthinking)\b[^<>]*>[\s\S]*?<\s*\/\s*(?:think(?:ing)?|thought|antthinking)\s*>/gi;
@@ -1702,11 +1786,11 @@ async function deliverMatrixReplies(params) {
1702
1786
  params.runtime.error?.("matrix reply missing text/media");
1703
1787
  continue;
1704
1788
  }
1705
- const replyToIdRaw = reply.replyToId?.trim();
1706
- const replyToId = params.threadId || params.replyToMode === "off" ? void 0 : replyToIdRaw;
1789
+ const replyToIdRaw = (reply.replyToId ?? params.replyToId)?.trim();
1790
+ const replyToId = params.threadId ? replyToIdRaw : params.replyToMode === "off" ? void 0 : replyToIdRaw;
1707
1791
  const rawText = reply.text ?? "";
1708
1792
  const mediaList = reply.mediaUrls?.length ? reply.mediaUrls : reply.mediaUrl ? [reply.mediaUrl] : [];
1709
- const shouldIncludeReply = (id) => Boolean(id) && (params.replyToMode === "all" || !hasReplied);
1793
+ const shouldIncludeReply = (id) => Boolean(id) && (params.threadId || params.replyToMode === "all" || !hasReplied);
1710
1794
  const replyToIdForReply = shouldIncludeReply(replyToId) ? replyToId : void 0;
1711
1795
  if (mediaList.length === 0) {
1712
1796
  let sentTextChunk = false;
@@ -1838,23 +1922,36 @@ const DEFAULT_MAX_ROOM_QUEUES = 1e3;
1838
1922
  const MAX_WATERMARK_ENTRIES = 5e3;
1839
1923
  /** Maximum prepared trigger snapshots retained per room for retry reuse. */
1840
1924
  const MAX_PREPARED_TRIGGER_ENTRIES = 500;
1925
+ /** Maximum thread queues retained per room (FIFO eviction beyond this). */
1926
+ const MAX_THREAD_QUEUES_PER_ROOM = 200;
1841
1927
  function createRoomHistoryTrackerInternal(maxQueueSize = DEFAULT_MAX_QUEUE_SIZE, maxRoomQueues = DEFAULT_MAX_ROOM_QUEUES, maxWatermarkEntries = MAX_WATERMARK_ENTRIES, maxPreparedTriggerEntries = MAX_PREPARED_TRIGGER_ENTRIES) {
1842
1928
  const roomQueues = /* @__PURE__ */ new Map();
1843
- /** Maps `${agentId}:${roomId}` → absolute consumed-up-to index */
1929
+ /** Maps `{agentId, roomId, scope}` → absolute consumed-up-to index */
1844
1930
  const agentWatermarks = /* @__PURE__ */ new Map();
1845
1931
  let nextQueueGeneration = 1;
1846
1932
  function clearRoomWatermarks(roomId) {
1847
- const roomSuffix = `:${roomId}`;
1848
- for (const key of agentWatermarks.keys()) if (key.endsWith(roomSuffix)) agentWatermarks.delete(key);
1933
+ for (const key of agentWatermarks.keys()) if (JSON.parse(key)?.roomId === roomId) agentWatermarks.delete(key);
1934
+ }
1935
+ function clearThreadWatermarks(roomId, threadRootId) {
1936
+ for (const key of agentWatermarks.keys()) {
1937
+ const parsed = JSON.parse(key);
1938
+ if (parsed?.roomId === roomId && parsed.scope === threadRootId) agentWatermarks.delete(key);
1939
+ }
1940
+ }
1941
+ function createHistoryQueue() {
1942
+ return {
1943
+ entries: [],
1944
+ baseIndex: 0,
1945
+ generation: nextQueueGeneration++,
1946
+ preparedTriggers: /* @__PURE__ */ new Map()
1947
+ };
1849
1948
  }
1850
1949
  function getOrCreateQueue(roomId) {
1851
1950
  let queue = roomQueues.get(roomId);
1852
1951
  if (!queue) {
1853
1952
  queue = {
1854
- entries: [],
1855
- baseIndex: 0,
1856
- generation: nextQueueGeneration++,
1857
- preparedTriggers: /* @__PURE__ */ new Map()
1953
+ ...createHistoryQueue(),
1954
+ threadQueues: /* @__PURE__ */ new Map()
1858
1955
  };
1859
1956
  roomQueues.set(roomId, queue);
1860
1957
  if (roomQueues.size > maxRoomQueues) {
@@ -1867,6 +1964,30 @@ function createRoomHistoryTrackerInternal(maxQueueSize = DEFAULT_MAX_QUEUE_SIZE,
1867
1964
  }
1868
1965
  return queue;
1869
1966
  }
1967
+ function getOrCreateThreadQueue(roomId, roomQueue, threadRootId) {
1968
+ let queue = roomQueue.threadQueues.get(threadRootId);
1969
+ if (!queue) {
1970
+ queue = createHistoryQueue();
1971
+ roomQueue.threadQueues.set(threadRootId, queue);
1972
+ if (roomQueue.threadQueues.size > MAX_THREAD_QUEUES_PER_ROOM) {
1973
+ const oldest = roomQueue.threadQueues.keys().next().value;
1974
+ if (oldest !== void 0) {
1975
+ roomQueue.threadQueues.delete(oldest);
1976
+ clearThreadWatermarks(roomId, oldest);
1977
+ }
1978
+ }
1979
+ }
1980
+ return queue;
1981
+ }
1982
+ function getScopedQueue(roomId, threadRootId) {
1983
+ const roomQueue = getOrCreateQueue(roomId);
1984
+ return threadRootId ? getOrCreateThreadQueue(roomId, roomQueue, threadRootId) : roomQueue;
1985
+ }
1986
+ function findScopedQueue(roomId, threadRootId) {
1987
+ const roomQueue = roomQueues.get(roomId);
1988
+ if (!roomQueue) return;
1989
+ return threadRootId ? roomQueue.threadQueues.get(threadRootId) : roomQueue;
1990
+ }
1870
1991
  function appendToQueue(queue, entry) {
1871
1992
  queue.entries.push(entry);
1872
1993
  if (queue.entries.length > maxQueueSize) {
@@ -1879,8 +2000,12 @@ function createRoomHistoryTrackerInternal(maxQueueSize = DEFAULT_MAX_QUEUE_SIZE,
1879
2000
  queueGeneration: queue.generation
1880
2001
  };
1881
2002
  }
1882
- function wmKey(agentId, roomId) {
1883
- return `${agentId}:${roomId}`;
2003
+ function wmKey(agentId, roomId, threadRootId) {
2004
+ return JSON.stringify({
2005
+ agentId,
2006
+ roomId,
2007
+ scope: threadRootId ?? "main"
2008
+ });
1884
2009
  }
1885
2010
  function preparedTriggerKey(agentId, messageId) {
1886
2011
  if (!messageId?.trim()) return null;
@@ -1895,6 +2020,15 @@ function createRoomHistoryTrackerInternal(maxQueueSize = DEFAULT_MAX_QUEUE_SIZE,
1895
2020
  if (oldest !== void 0) agentWatermarks.delete(oldest);
1896
2021
  }
1897
2022
  }
2023
+ function markConsumedAfterReservedGap(queue, key, firstReservedRel, snapshotIdx) {
2024
+ const endRel = Math.min(snapshotIdx - queue.baseIndex, queue.entries.length);
2025
+ for (let rel = firstReservedRel + 1; rel < endRel; rel += 1) {
2026
+ const entry = queue.entries[rel];
2027
+ if (!entry || entry.reserved || entry.discarded) continue;
2028
+ entry.consumedBy ??= /* @__PURE__ */ new Set();
2029
+ entry.consumedBy.add(key);
2030
+ }
2031
+ }
1898
2032
  function rememberPreparedTrigger(queue, retryKey, prepared) {
1899
2033
  if (queue.preparedTriggers.has(retryKey)) queue.preparedTriggers.delete(retryKey);
1900
2034
  queue.preparedTriggers.set(retryKey, prepared);
@@ -1904,50 +2038,113 @@ function createRoomHistoryTrackerInternal(maxQueueSize = DEFAULT_MAX_QUEUE_SIZE,
1904
2038
  }
1905
2039
  return prepared;
1906
2040
  }
1907
- function computePendingHistory(queue, agentId, roomId, limit) {
2041
+ function computePendingHistory(queue, agentId, roomId, limit, endAbsExclusive = queue.baseIndex + queue.entries.length, startAbsOverride, threadRootId) {
1908
2042
  if (limit <= 0 || queue.entries.length === 0) return [];
1909
- const wm = agentWatermarks.get(wmKey(agentId, roomId)) ?? 0;
2043
+ const wm = startAbsOverride ?? agentWatermarks.get(wmKey(agentId, roomId, threadRootId)) ?? 0;
1910
2044
  const startRel = Math.max(wm, queue.baseIndex) - queue.baseIndex;
1911
- const available = queue.entries.slice(startRel);
2045
+ const endRel = Math.max(startRel, Math.min(endAbsExclusive - queue.baseIndex, queue.entries.length));
2046
+ const available = queue.entries.slice(startRel, endRel).filter((entry) => !entry.discarded && !entry.reserved && !entry.consumedBy?.has(wmKey(agentId, roomId, threadRootId)));
1912
2047
  return available.length > limit ? available.slice(-limit) : available;
1913
2048
  }
2049
+ function prepareTriggerInternal(agentId, roomId, limit, entry, threadRootId) {
2050
+ const queue = getScopedQueue(roomId, threadRootId);
2051
+ const retryKey = preparedTriggerKey(agentId, entry.messageId);
2052
+ if (retryKey) {
2053
+ const prepared = queue.preparedTriggers.get(retryKey);
2054
+ if (prepared) return rememberPreparedTrigger(queue, retryKey, prepared);
2055
+ }
2056
+ const prepared = {
2057
+ history: computePendingHistory(queue, agentId, roomId, limit, void 0, void 0, threadRootId),
2058
+ ...appendToQueue(queue, entry)
2059
+ };
2060
+ if (retryKey) return rememberPreparedTrigger(queue, retryKey, prepared);
2061
+ return prepared;
2062
+ }
1914
2063
  return {
1915
- recordPending(roomId, entry) {
1916
- appendToQueue(getOrCreateQueue(roomId), entry);
2064
+ recordPending(roomId, entry, threadRootId) {
2065
+ appendToQueue(getScopedQueue(roomId, threadRootId), entry);
2066
+ },
2067
+ reservePending(agentId, roomId, entry, threadRootId) {
2068
+ const snapshot = appendToQueue(getScopedQueue(roomId, threadRootId), {
2069
+ ...entry,
2070
+ reserved: true
2071
+ });
2072
+ return {
2073
+ ...snapshot,
2074
+ slotIdx: snapshot.snapshotIdx - 1,
2075
+ watermarkIdx: agentWatermarks.get(wmKey(agentId, roomId, threadRootId)) ?? 0
2076
+ };
1917
2077
  },
1918
- getPendingHistory(agentId, roomId, limit) {
1919
- const queue = roomQueues.get(roomId);
2078
+ finalizePending(roomId, slot, entry, threadRootId) {
2079
+ const queue = findScopedQueue(roomId, threadRootId);
2080
+ if (!queue || queue.generation !== slot.queueGeneration) return;
2081
+ const rel = slot.slotIdx - queue.baseIndex;
2082
+ if (rel < 0 || rel >= queue.entries.length) return;
2083
+ queue.entries[rel] = entry;
2084
+ },
2085
+ discardPending(roomId, slot, threadRootId) {
2086
+ const queue = findScopedQueue(roomId, threadRootId);
2087
+ if (!queue || queue.generation !== slot.queueGeneration) return;
2088
+ const rel = slot.slotIdx - queue.baseIndex;
2089
+ if (rel < 0 || rel >= queue.entries.length) return;
2090
+ queue.entries[rel] = {
2091
+ sender: "",
2092
+ body: "",
2093
+ messageId: void 0,
2094
+ discarded: true
2095
+ };
2096
+ },
2097
+ getPendingHistory(agentId, roomId, limit, threadRootId) {
2098
+ const queue = findScopedQueue(roomId, threadRootId);
1920
2099
  if (!queue) return [];
1921
- return computePendingHistory(queue, agentId, roomId, limit);
2100
+ return computePendingHistory(queue, agentId, roomId, limit, void 0, void 0, threadRootId);
2101
+ },
2102
+ recordTrigger(roomId, entry, threadRootId) {
2103
+ return appendToQueue(getScopedQueue(roomId, threadRootId), entry);
1922
2104
  },
1923
- recordTrigger(roomId, entry) {
1924
- return appendToQueue(getOrCreateQueue(roomId), entry);
2105
+ prepareTrigger(agentId, roomId, limit, entry, threadRootId) {
2106
+ return prepareTriggerInternal(agentId, roomId, limit, entry, threadRootId);
1925
2107
  },
1926
- prepareTrigger(agentId, roomId, limit, entry) {
1927
- const queue = getOrCreateQueue(roomId);
2108
+ prepareReservedTrigger(agentId, roomId, limit, slot, entry, threadRootId) {
2109
+ const queue = findScopedQueue(roomId, threadRootId);
2110
+ if (!queue || queue.generation !== slot.queueGeneration) return prepareTriggerInternal(agentId, roomId, limit, entry, threadRootId);
2111
+ const rel = slot.slotIdx - queue.baseIndex;
2112
+ if (rel < 0 || rel >= queue.entries.length) return prepareTriggerInternal(agentId, roomId, limit, entry, threadRootId);
1928
2113
  const retryKey = preparedTriggerKey(agentId, entry.messageId);
1929
2114
  if (retryKey) {
1930
2115
  const prepared = queue.preparedTriggers.get(retryKey);
1931
- if (prepared) return rememberPreparedTrigger(queue, retryKey, prepared);
2116
+ if (prepared) {
2117
+ queue.entries[rel] = {
2118
+ sender: "",
2119
+ body: "",
2120
+ messageId: void 0,
2121
+ discarded: true
2122
+ };
2123
+ return rememberPreparedTrigger(queue, retryKey, prepared);
2124
+ }
1932
2125
  }
2126
+ queue.entries[rel] = entry;
1933
2127
  const prepared = {
1934
- history: computePendingHistory(queue, agentId, roomId, limit),
1935
- ...appendToQueue(queue, entry)
2128
+ history: computePendingHistory(queue, agentId, roomId, limit, slot.slotIdx, slot.watermarkIdx, threadRootId),
2129
+ snapshotIdx: slot.slotIdx + 1,
2130
+ queueGeneration: queue.generation
1936
2131
  };
1937
2132
  if (retryKey) return rememberPreparedTrigger(queue, retryKey, prepared);
1938
2133
  return prepared;
1939
2134
  },
1940
- consumeHistory(agentId, roomId, snapshot, messageId) {
1941
- const key = wmKey(agentId, roomId);
1942
- const queue = roomQueues.get(roomId);
2135
+ consumeHistory(agentId, roomId, snapshot, messageId, threadRootId) {
2136
+ const key = wmKey(agentId, roomId, threadRootId);
2137
+ const queue = findScopedQueue(roomId, threadRootId);
1943
2138
  if (!queue) {
1944
2139
  agentWatermarks.delete(key);
1945
2140
  return;
1946
2141
  }
1947
2142
  if (queue.generation !== snapshot.queueGeneration) return;
1948
- rememberWatermark(key, snapshot.snapshotIdx);
2143
+ const firstReservedRel = queue.entries.findIndex((entry, index) => entry.reserved === true && queue.baseIndex + index < snapshot.snapshotIdx);
2144
+ if (firstReservedRel >= 0) markConsumedAfterReservedGap(queue, key, firstReservedRel, snapshot.snapshotIdx);
2145
+ rememberWatermark(key, firstReservedRel >= 0 ? queue.baseIndex + firstReservedRel : snapshot.snapshotIdx);
1949
2146
  const retryKey = preparedTriggerKey(agentId, messageId);
1950
- if (queue && retryKey) queue.preparedTriggers.delete(retryKey);
2147
+ if (retryKey) queue.preparedTriggers.delete(retryKey);
1951
2148
  }
1952
2149
  };
1953
2150
  }
@@ -1955,7 +2152,11 @@ function createRoomHistoryTracker(maxQueueSize = DEFAULT_MAX_QUEUE_SIZE, maxRoom
1955
2152
  const tracker = createRoomHistoryTrackerInternal(maxQueueSize, maxRoomQueues, maxWatermarkEntries, maxPreparedTriggerEntries);
1956
2153
  return {
1957
2154
  recordPending: tracker.recordPending,
2155
+ reservePending: tracker.reservePending,
2156
+ finalizePending: tracker.finalizePending,
2157
+ discardPending: tracker.discardPending,
1958
2158
  prepareTrigger: tracker.prepareTrigger,
2159
+ prepareReservedTrigger: tracker.prepareReservedTrigger,
1959
2160
  consumeHistory: tracker.consumeHistory
1960
2161
  };
1961
2162
  }
@@ -2030,7 +2231,7 @@ let sessionBindingRuntimePromise;
2030
2231
  let matrixReactionEventsPromise;
2031
2232
  let matrixDraftStreamPromise;
2032
2233
  function loadMatrixSendModule() {
2033
- matrixSendModulePromise ??= import("./send-BAtT4Rtk.js").then((n) => n.l);
2234
+ matrixSendModulePromise ??= import("./send-DEgWxp1p.js").then((n) => n.l);
2034
2235
  return matrixSendModulePromise;
2035
2236
  }
2036
2237
  function loadAcpBindingRuntime() {
@@ -2042,11 +2243,11 @@ function loadSessionBindingRuntime() {
2042
2243
  return sessionBindingRuntimePromise;
2043
2244
  }
2044
2245
  function loadMatrixReactionEvents() {
2045
- matrixReactionEventsPromise ??= import("./reaction-events-BWDww7_l.js");
2246
+ matrixReactionEventsPromise ??= import("./reaction-events-DRKzlo8q.js");
2046
2247
  return matrixReactionEventsPromise;
2047
2248
  }
2048
2249
  function loadMatrixDraftStream() {
2049
- matrixDraftStreamPromise ??= import("./draft-stream-B7lCkUfU.js");
2250
+ matrixDraftStreamPromise ??= import("./draft-stream-DZ2X1RHP.js");
2050
2251
  return matrixDraftStreamPromise;
2051
2252
  }
2052
2253
  async function matrixTextWouldActivateMentions(client, text) {
@@ -2150,6 +2351,21 @@ function resolveMatrixPendingHistoryText(params) {
2150
2351
  })
2151
2352
  }) ?? "";
2152
2353
  }
2354
+ function isMatrixAudioMediaEnabled(cfg) {
2355
+ return cfg.tools?.media?.audio?.enabled !== false;
2356
+ }
2357
+ function shouldDeferMatrixAudioPreflightForRoomIngress(params) {
2358
+ if (!isMatrixAudioMediaEnabled(params.cfg)) return false;
2359
+ const content = params.content;
2360
+ const contentUrl = "url" in content && typeof content.url === "string" ? content.url : void 0;
2361
+ const contentFile = "file" in content && content.file && typeof content.file === "object" ? content.file : void 0;
2362
+ const mediaUrl = contentUrl ?? contentFile?.url;
2363
+ const contentInfo = "info" in content && content.info && typeof content.info === "object" ? content.info : void 0;
2364
+ return mediaUrl?.startsWith("mxc://") === true && isMatrixAudioContent({
2365
+ msgtype: typeof content.msgtype === "string" ? content.msgtype : void 0,
2366
+ mimetype: contentInfo?.mimetype
2367
+ });
2368
+ }
2153
2369
  function resolveMatrixAllowBotsMode(value) {
2154
2370
  if (value === true) return "all";
2155
2371
  if (value === "mentions") return "mentions";
@@ -2329,9 +2545,33 @@ function createMatrixRoomMessageHandler(params) {
2329
2545
  let content = paramsLocal.content;
2330
2546
  const isDirectMessage = paramsLocal.isDirectMessage;
2331
2547
  const isRoom = !isDirectMessage;
2332
- const { locationPayload, selfUserId } = paramsLocal;
2333
- if (isRoom && groupPolicy === "disabled") {
2548
+ const { audioPreflightMode, locationPayload, reservedHistorySlot, selfUserId } = paramsLocal;
2549
+ const messageId = event.event_id ?? "";
2550
+ const threadRootId = resolveMatrixThreadRootId({
2551
+ event,
2552
+ content
2553
+ });
2554
+ const thread = resolveMatrixThreadRouting({
2555
+ isDirectMessage,
2556
+ threadReplies,
2557
+ dmThreadReplies,
2558
+ messageId,
2559
+ threadRootId
2560
+ });
2561
+ const historyThreadId = threadRootId ? thread.threadId : void 0;
2562
+ let reservedHistorySlotConsumed = false;
2563
+ const discardReservedHistorySlot = () => {
2564
+ if (reservedHistorySlot && !reservedHistorySlotConsumed) {
2565
+ roomHistoryTracker.discardPending(roomId, reservedHistorySlot, historyThreadId);
2566
+ reservedHistorySlotConsumed = true;
2567
+ }
2568
+ };
2569
+ const commitInboundEventIfClaimedAndDiscardReserved = async () => {
2570
+ discardReservedHistorySlot();
2334
2571
  await commitInboundEventIfClaimed();
2572
+ };
2573
+ if (isRoom && groupPolicy === "disabled") {
2574
+ await commitInboundEventIfClaimedAndDiscardReserved();
2335
2575
  return;
2336
2576
  }
2337
2577
  const roomInfoForConfig = isRoom && needsRoomAliasesForConfig ? await getRoomInfo(roomId, { includeAliases: true }) : void 0;
@@ -2347,7 +2587,7 @@ function createMatrixRoomMessageHandler(params) {
2347
2587
  const roomMatchMeta = roomConfigInfo ? `matchKey=${roomConfigInfo.matchKey ?? "none"} matchSource=${roomConfigInfo.matchSource ?? "none"}` : "matchKey=none matchSource=none";
2348
2588
  if (isConfiguredBotSender && allowBotsMode === "off") {
2349
2589
  logVerboseMessage(`matrix: drop configured bot sender=${senderId} (allowBots=false${isDirectMessage ? "" : `, ${roomMatchMeta}`})`);
2350
- await commitInboundEventIfClaimed();
2590
+ await commitInboundEventIfClaimedAndDiscardReserved();
2351
2591
  return;
2352
2592
  }
2353
2593
  const botLoopProtection = isConfiguredBotSender && senderId !== selfUserId ? {
@@ -2362,18 +2602,18 @@ function createMatrixRoomMessageHandler(params) {
2362
2602
  } : void 0;
2363
2603
  if (isRoom && roomConfig && !roomConfigInfo?.allowed) {
2364
2604
  logVerboseMessage(`matrix: room disabled room=${roomId} (${roomMatchMeta})`);
2365
- await commitInboundEventIfClaimed();
2605
+ await commitInboundEventIfClaimedAndDiscardReserved();
2366
2606
  return;
2367
2607
  }
2368
2608
  if (isRoom && groupPolicy === "allowlist") {
2369
2609
  if (!roomConfigInfo?.allowlistConfigured) {
2370
2610
  logVerboseMessage(`matrix: drop room message (no allowlist, ${roomMatchMeta})`);
2371
- await commitInboundEventIfClaimed();
2611
+ await commitInboundEventIfClaimedAndDiscardReserved();
2372
2612
  return;
2373
2613
  }
2374
2614
  if (!roomConfig) {
2375
2615
  logVerboseMessage(`matrix: drop room message (not in allowlist, ${roomMatchMeta})`);
2376
- await commitInboundEventIfClaimed();
2616
+ await commitInboundEventIfClaimedAndDiscardReserved();
2377
2617
  return;
2378
2618
  }
2379
2619
  }
@@ -2422,7 +2662,7 @@ function createMatrixRoomMessageHandler(params) {
2422
2662
  const ingressDecision = messageIngress.ingress;
2423
2663
  if (isDirectMessage) {
2424
2664
  if (!dmEnabled || dmPolicy === "disabled") {
2425
- await commitInboundEventIfClaimed();
2665
+ await commitInboundEventIfClaimedAndDiscardReserved();
2426
2666
  return;
2427
2667
  }
2428
2668
  const senderReason = messageIngress.senderAccess.reasonCode;
@@ -2452,23 +2692,24 @@ function createMatrixRoomMessageHandler(params) {
2452
2692
  await commitInboundEventIfClaimed();
2453
2693
  } catch (err) {
2454
2694
  logVerboseMessage(`matrix pairing reply failed for ${senderId}: ${String(err)}`);
2695
+ discardReservedHistorySlot();
2455
2696
  return;
2456
2697
  }
2457
2698
  } else {
2458
2699
  logVerboseMessage(`matrix pairing reminder suppressed sender=${senderId} (cooldown)`);
2459
- await commitInboundEventIfClaimed();
2700
+ await commitInboundEventIfClaimedAndDiscardReserved();
2460
2701
  }
2461
2702
  }
2462
2703
  if (isReactionEvent || dmPolicy !== "pairing") {
2463
2704
  logVerboseMessage(`matrix: blocked ${isReactionEvent ? "reaction" : "dm"} sender ${senderId} (dmPolicy=${dmPolicy}, reason=${senderReason})`);
2464
- await commitInboundEventIfClaimed();
2705
+ await commitInboundEventIfClaimedAndDiscardReserved();
2465
2706
  }
2466
2707
  return;
2467
2708
  }
2468
2709
  }
2469
2710
  if (isRoom && ingressDecision.decision !== "allow") {
2470
2711
  logVerboseMessage(`matrix: blocked sender ${senderId} (ingress=${ingressDecision.reasonCode}, ${roomMatchMeta})`);
2471
- await commitInboundEventIfClaimed();
2712
+ await commitInboundEventIfClaimedAndDiscardReserved();
2472
2713
  return;
2473
2714
  }
2474
2715
  if (isRoom) logVerboseMessage(`matrix: allow room ${roomId} (${roomMatchMeta})`);
@@ -2488,7 +2729,7 @@ function createMatrixRoomMessageHandler(params) {
2488
2729
  isDirectMessage,
2489
2730
  logVerboseMessage
2490
2731
  });
2491
- await commitInboundEventIfClaimed();
2732
+ await commitInboundEventIfClaimedAndDiscardReserved();
2492
2733
  return;
2493
2734
  }
2494
2735
  let pollSnapshotPromise = null;
@@ -2508,6 +2749,11 @@ function createMatrixRoomMessageHandler(params) {
2508
2749
  const contentUrl = "url" in content && typeof content.url === "string" ? content.url : void 0;
2509
2750
  const contentFile = "file" in content && content.file && typeof content.file === "object" ? content.file : void 0;
2510
2751
  const mediaUrl = contentUrl ?? contentFile?.url;
2752
+ const earlyContentInfo = "info" in content && content.info && typeof content.info === "object" ? content.info : void 0;
2753
+ const earlyContentType = earlyContentInfo?.mimetype;
2754
+ const earlyContentSize = typeof earlyContentInfo?.size === "number" ? earlyContentInfo.size : void 0;
2755
+ const earlyContentBody = typeof content.body === "string" ? content.body.trim() : "";
2756
+ const earlyOriginalFilename = (typeof content.filename === "string" ? content.filename.trim() : "") || earlyContentBody || void 0;
2511
2757
  const pendingHistoryText = resolveMatrixPendingHistoryText({
2512
2758
  mentionPrecheckText,
2513
2759
  content,
@@ -2515,21 +2761,13 @@ function createMatrixRoomMessageHandler(params) {
2515
2761
  });
2516
2762
  const pendingHistoryPollText = !pendingHistoryText && isPollEvent && historyLimit > 0 ? (await getPollSnapshot())?.text : "";
2517
2763
  if (!mentionPrecheckText && !mediaUrl && !isPollEvent) {
2518
- await commitInboundEventIfClaimed();
2764
+ await commitInboundEventIfClaimedAndDiscardReserved();
2519
2765
  return;
2520
2766
  }
2521
- const messageId = event.event_id ?? "";
2522
- const threadRootId = resolveMatrixThreadRootId({
2523
- event,
2524
- content
2525
- });
2526
- const thread = resolveMatrixThreadRouting({
2527
- isDirectMessage,
2528
- threadReplies,
2529
- dmThreadReplies,
2530
- messageId,
2531
- threadRootId
2532
- });
2767
+ let preflightMedia = null;
2768
+ let preflightMediaDownloadFailed = false;
2769
+ let preflightMediaSizeLimitExceeded = false;
2770
+ let preflightAudioTranscript;
2533
2771
  const { route: _route, configuredBinding: _configuredBinding, runtimeBindingId: _runtimeBindingId } = resolveMatrixInboundRoute({
2534
2772
  cfg,
2535
2773
  accountId,
@@ -2542,22 +2780,76 @@ function createMatrixRoomMessageHandler(params) {
2542
2780
  resolveAgentRoute: core.channel.routing.resolveAgentRoute
2543
2781
  });
2544
2782
  const hasExplicitSessionBinding = _configuredBinding !== null || _runtimeBindingId !== null;
2783
+ const preflightAudioMediaUrl = mediaUrl?.startsWith("mxc://") ? mediaUrl : void 0;
2784
+ const shouldRunMatrixAudioPreflight = isMatrixAudioContent({
2785
+ msgtype: typeof content.msgtype === "string" ? content.msgtype : void 0,
2786
+ mimetype: earlyContentType
2787
+ }) && isMatrixAudioMediaEnabled(cfg) && preflightAudioMediaUrl !== void 0;
2788
+ if (shouldRunMatrixAudioPreflight && audioPreflightMode === "defer" && isRoom && historyLimit > 0 && !reservedHistorySlot) {
2789
+ const reserved = roomHistoryTracker.reservePending(_route.agentId, roomId, {
2790
+ sender: senderId,
2791
+ body: pendingHistoryText,
2792
+ timestamp: eventTs ?? void 0,
2793
+ messageId
2794
+ }, historyThreadId);
2795
+ return { deferredPrefix: {
2796
+ ...paramsLocal,
2797
+ audioPreflightMode: "run",
2798
+ reservedHistorySlot: reserved
2799
+ } };
2800
+ }
2801
+ if (shouldRunMatrixAudioPreflight) {
2802
+ try {
2803
+ preflightMedia = await downloadMatrixMedia({
2804
+ client,
2805
+ mxcUrl: preflightAudioMediaUrl,
2806
+ contentType: earlyContentType,
2807
+ sizeBytes: earlyContentSize,
2808
+ maxBytes: mediaMaxBytes,
2809
+ file: contentFile,
2810
+ originalFilename: earlyOriginalFilename
2811
+ });
2812
+ } catch (err) {
2813
+ preflightMediaDownloadFailed = true;
2814
+ if (isMatrixMediaSizeLimitError(err)) preflightMediaSizeLimitExceeded = true;
2815
+ const errorText = formatMatrixErrorMessage(err);
2816
+ logVerboseMessage(`matrix: media download failed room=${roomId} id=${event.event_id ?? "unknown"} type=${content.msgtype} error=${errorText}`);
2817
+ logger.warn("matrix media download failed", {
2818
+ roomId,
2819
+ eventId: event.event_id,
2820
+ msgtype: content.msgtype,
2821
+ encrypted: Boolean(contentFile),
2822
+ error: errorText
2823
+ });
2824
+ }
2825
+ if (preflightMedia) preflightAudioTranscript = await resolveMatrixPreflightAudioTranscript({
2826
+ mediaPath: preflightMedia.path,
2827
+ mediaContentType: preflightMedia.contentType,
2828
+ cfg,
2829
+ accountId,
2830
+ chatType: isDirectMessage ? "direct" : "channel",
2831
+ originatingTo: `room:${roomId}`,
2832
+ messageThreadId: thread.threadId,
2833
+ sessionKey: _route.sessionKey
2834
+ });
2835
+ }
2545
2836
  const agentMentionRegexes = core.channel.mentions.buildMentionRegexes(cfg, _route.agentId, {
2546
2837
  provider: "matrix",
2547
2838
  conversationId: roomId,
2548
2839
  providerPolicy: accountConfig?.mentionPatterns
2549
2840
  });
2550
2841
  const selfDisplayName = content.formatted_body ? await getMemberDisplayName(roomId, selfUserId).catch(() => void 0) : void 0;
2842
+ const mentionPrecheckTextWithTranscript = preflightAudioTranscript ? [mentionPrecheckText, preflightAudioTranscript].filter(Boolean).join("\n").trim() : mentionPrecheckText;
2551
2843
  const { wasMentioned, hasExplicitMention } = resolveMentions({
2552
2844
  content,
2553
2845
  userId: selfUserId,
2554
2846
  displayName: selfDisplayName,
2555
- text: mentionPrecheckText,
2847
+ text: mentionPrecheckTextWithTranscript,
2556
2848
  mentionRegexes: agentMentionRegexes
2557
2849
  });
2558
2850
  if (isConfiguredBotSender && allowBotsMode === "mentions" && !isDirectMessage && !wasMentioned) {
2559
2851
  logVerboseMessage(`matrix: drop configured bot sender=${senderId} (allowBots=mentions, missing mention, ${roomMatchMeta})`);
2560
- await commitInboundEventIfClaimed();
2852
+ await commitInboundEventIfClaimedAndDiscardReserved();
2561
2853
  return;
2562
2854
  }
2563
2855
  const allowTextCommands = core.channel.commands.shouldHandleTextCommands({
@@ -2585,14 +2877,14 @@ function createMatrixRoomMessageHandler(params) {
2585
2877
  reason: "control command (unauthorized)",
2586
2878
  target: senderId
2587
2879
  });
2588
- await commitInboundEventIfClaimed();
2880
+ await commitInboundEventIfClaimedAndDiscardReserved();
2589
2881
  return;
2590
2882
  }
2591
2883
  const shouldRequireMention = isRoom ? roomConfig?.autoReply === true ? false : roomConfig?.autoReply === false ? true : typeof roomConfig?.requireMention === "boolean" ? roomConfig?.requireMention : true : false;
2592
2884
  const shouldBypassMention = allowTextCommands && isRoom && shouldRequireMention && !wasMentioned && !hasExplicitMention && commandAuthorized && hasControlCommandInMessage;
2593
2885
  const canDetectMention = agentMentionRegexes.length > 0 || hasExplicitMention;
2594
2886
  if (isRoom && shouldRequireMention && !wasMentioned && !shouldBypassMention) {
2595
- const pendingHistoryBody = pendingHistoryText || pendingHistoryPollText;
2887
+ const pendingHistoryBody = preflightAudioTranscript ? formatMatrixAudioTranscript(preflightAudioTranscript) : pendingHistoryText || pendingHistoryPollText;
2596
2888
  if (historyLimit > 0 && pendingHistoryBody) {
2597
2889
  const pendingEntry = {
2598
2890
  sender: senderId,
@@ -2600,7 +2892,10 @@ function createMatrixRoomMessageHandler(params) {
2600
2892
  timestamp: eventTs ?? void 0,
2601
2893
  messageId
2602
2894
  };
2603
- roomHistoryTracker.recordPending(roomId, pendingEntry);
2895
+ if (reservedHistorySlot) {
2896
+ roomHistoryTracker.finalizePending(roomId, reservedHistorySlot, pendingEntry, historyThreadId);
2897
+ reservedHistorySlotConsumed = true;
2898
+ } else roomHistoryTracker.recordPending(roomId, pendingEntry, historyThreadId);
2604
2899
  }
2605
2900
  logger.info("skipping room message", {
2606
2901
  roomId,
@@ -2609,17 +2904,27 @@ function createMatrixRoomMessageHandler(params) {
2609
2904
  await commitInboundEventIfClaimed();
2610
2905
  return;
2611
2906
  }
2907
+ if (preflightAudioTranscript) await sendMatrixPreflightAudioTranscriptEcho({
2908
+ transcript: preflightAudioTranscript,
2909
+ cfg,
2910
+ accountId,
2911
+ originatingTo: `room:${roomId}`,
2912
+ messageThreadId: thread.threadId
2913
+ });
2612
2914
  if (isPollEvent) {
2613
2915
  const pollSnapshot = await getPollSnapshot();
2614
- if (!pollSnapshot) return;
2916
+ if (!pollSnapshot) {
2917
+ discardReservedHistorySlot();
2918
+ return;
2919
+ }
2615
2920
  content = {
2616
2921
  msgtype: "m.text",
2617
2922
  body: pollSnapshot.text
2618
2923
  };
2619
2924
  }
2620
- let media = null;
2621
- let mediaDownloadFailed = false;
2622
- let mediaSizeLimitExceeded = false;
2925
+ let media = preflightMedia;
2926
+ let mediaDownloadFailed = preflightMediaDownloadFailed;
2927
+ let mediaSizeLimitExceeded = preflightMediaSizeLimitExceeded;
2623
2928
  const finalContentUrl = "url" in content && typeof content.url === "string" ? content.url : void 0;
2624
2929
  const finalContentFile = "file" in content && content.file && typeof content.file === "object" ? content.file : void 0;
2625
2930
  const finalMediaUrl = finalContentUrl ?? finalContentFile?.url;
@@ -2628,7 +2933,7 @@ function createMatrixRoomMessageHandler(params) {
2628
2933
  const contentInfo = "info" in content && content.info && typeof content.info === "object" ? content.info : void 0;
2629
2934
  const contentType = contentInfo?.mimetype;
2630
2935
  const contentSize = typeof contentInfo?.size === "number" ? contentInfo.size : void 0;
2631
- if (finalMediaUrl?.startsWith("mxc://")) try {
2936
+ if (!media && !mediaDownloadFailed && finalMediaUrl?.startsWith("mxc://")) try {
2632
2937
  media = await downloadMatrixMedia({
2633
2938
  client,
2634
2939
  mxcUrl: finalMediaUrl,
@@ -2651,7 +2956,7 @@ function createMatrixRoomMessageHandler(params) {
2651
2956
  error: errorText
2652
2957
  });
2653
2958
  }
2654
- const bodyText = resolveMatrixInboundBodyText({
2959
+ let bodyText = resolveMatrixInboundBodyText({
2655
2960
  rawBody: locationPayload?.text ?? contentBody,
2656
2961
  filename: typeof content.filename === "string" ? content.filename : void 0,
2657
2962
  mediaPlaceholder: media?.placeholder,
@@ -2660,8 +2965,13 @@ function createMatrixRoomMessageHandler(params) {
2660
2965
  mediaDownloadFailed,
2661
2966
  mediaSizeLimitExceeded
2662
2967
  });
2968
+ if (preflightMedia && bodyText && bodyText !== preflightMedia.placeholder && isLikelyBareFilename(bodyText)) bodyText = preflightMedia.placeholder;
2969
+ if (preflightAudioTranscript) {
2970
+ const transcriptBody = formatMatrixAudioTranscript(preflightAudioTranscript);
2971
+ bodyText = !bodyText || bodyText === media?.placeholder ? transcriptBody : `${bodyText}\n${transcriptBody}`;
2972
+ }
2663
2973
  if (!bodyText) {
2664
- await commitInboundEventIfClaimed();
2974
+ await commitInboundEventIfClaimedAndDiscardReserved();
2665
2975
  return;
2666
2976
  }
2667
2977
  const commandBodyText = hasControlCommandInMessage ? commandCheckText : bodyText;
@@ -2678,6 +2988,7 @@ function createMatrixRoomMessageHandler(params) {
2678
2988
  reason: "configured ACP binding unavailable",
2679
2989
  target: _configuredBinding.spec.conversationId
2680
2990
  });
2991
+ discardReservedHistorySlot();
2681
2992
  return;
2682
2993
  }
2683
2994
  }
@@ -2685,12 +2996,18 @@ function createMatrixRoomMessageHandler(params) {
2685
2996
  const { getSessionBindingService } = await loadSessionBindingRuntime();
2686
2997
  getSessionBindingService().touch(_runtimeBindingId, eventTs ?? void 0);
2687
2998
  }
2688
- const preparedTrigger = isRoom && historyLimit > 0 ? roomHistoryTracker.prepareTrigger(_route.agentId, roomId, historyLimit, {
2999
+ const preparedTrigger = isRoom && historyLimit > 0 ? reservedHistorySlot ? roomHistoryTracker.prepareReservedTrigger(_route.agentId, roomId, historyLimit, reservedHistorySlot, {
2689
3000
  sender: senderName,
2690
3001
  body: bodyText,
2691
3002
  timestamp: eventTs ?? void 0,
2692
3003
  messageId
2693
- }) : void 0;
3004
+ }, historyThreadId) : roomHistoryTracker.prepareTrigger(_route.agentId, roomId, historyLimit, {
3005
+ sender: senderName,
3006
+ body: bodyText,
3007
+ timestamp: eventTs ?? void 0,
3008
+ messageId
3009
+ }, historyThreadId) : void 0;
3010
+ if (reservedHistorySlot && preparedTrigger) reservedHistorySlotConsumed = true;
2694
3011
  return {
2695
3012
  route: _route,
2696
3013
  hasExplicitSessionBinding,
@@ -2710,6 +3027,7 @@ function createMatrixRoomMessageHandler(params) {
2710
3027
  bodyText,
2711
3028
  commandBodyText,
2712
3029
  media,
3030
+ preflightAudioTranscript,
2713
3031
  locationPayload,
2714
3032
  messageId,
2715
3033
  triggerSnapshot: preparedTrigger,
@@ -2724,7 +3042,14 @@ function createMatrixRoomMessageHandler(params) {
2724
3042
  const prefix = await readIngressPrefix();
2725
3043
  if (!prefix) return;
2726
3044
  if (prefix.isDirectMessage) return { deferredPrefix: prefix };
2727
- return { ingressResult: await continueIngress(prefix) };
3045
+ const result = await continueIngress({
3046
+ ...prefix,
3047
+ audioPreflightMode: shouldDeferMatrixAudioPreflightForRoomIngress({
3048
+ content: prefix.content,
3049
+ cfg
3050
+ }) ? "defer" : "run"
3051
+ });
3052
+ return result && "deferredPrefix" in result ? { deferredPrefix: result.deferredPrefix } : { ingressResult: result };
2728
3053
  }) : void 0;
2729
3054
  const resolvedIngressResult = historyLimit > 0 ? ingressResult?.deferredPrefix ? await continueIngress(ingressResult.deferredPrefix) : ingressResult?.ingressResult : await (async () => {
2730
3055
  const prefix = await readIngressPrefix();
@@ -2732,7 +3057,8 @@ function createMatrixRoomMessageHandler(params) {
2732
3057
  return await continueIngress(prefix);
2733
3058
  })();
2734
3059
  if (!resolvedIngressResult) return;
2735
- const { route: _route, hasExplicitSessionBinding, roomConfig, isDirectMessage, isRoom, shouldRequireMention, wasMentioned, shouldBypassMention, canDetectMention, commandAuthorized, inboundHistory, senderName, bodyText, commandBodyText, media, locationPayload, messageId, triggerSnapshot, threadRootId, thread, botLoopProtection, effectiveGroupAllowFrom, effectiveRoomUsers } = resolvedIngressResult;
3060
+ if ("deferredPrefix" in resolvedIngressResult) return;
3061
+ const { route: _route, hasExplicitSessionBinding, roomConfig, isDirectMessage, isRoom, shouldRequireMention, wasMentioned, shouldBypassMention, canDetectMention, commandAuthorized, inboundHistory, senderName, bodyText, commandBodyText, media, preflightAudioTranscript, locationPayload, messageId, triggerSnapshot, threadRootId, thread, botLoopProtection, effectiveGroupAllowFrom, effectiveRoomUsers } = resolvedIngressResult;
2736
3062
  const replyToEventId = resolveMatrixReplyToEventId(event.content);
2737
3063
  const threadTarget = thread.threadId;
2738
3064
  const isRoomContextSenderAllowed = (contextSenderId) => {
@@ -2830,7 +3156,8 @@ function createMatrixRoomMessageHandler(params) {
2830
3156
  media: toInboundMediaFacts(media ? [{
2831
3157
  path: media.path,
2832
3158
  url: media.path,
2833
- contentType: media.contentType
3159
+ contentType: media.contentType,
3160
+ transcribed: preflightAudioTranscript !== void 0
2834
3161
  }] : void 0),
2835
3162
  messageId,
2836
3163
  timestamp: eventTs ?? void 0,
@@ -3157,6 +3484,7 @@ function createMatrixRoomMessageHandler(params) {
3157
3484
  textLimit,
3158
3485
  replyToMode,
3159
3486
  threadId: threadTarget,
3487
+ replyToId: threadTarget ?? replyToEventId ?? void 0,
3160
3488
  accountId: _route.accountId,
3161
3489
  mediaLocalRoots,
3162
3490
  tableMode
@@ -3223,6 +3551,7 @@ function createMatrixRoomMessageHandler(params) {
3223
3551
  textLimit,
3224
3552
  replyToMode,
3225
3553
  threadId: threadTarget,
3554
+ replyToId: threadTarget ?? replyToEventId ?? void 0,
3226
3555
  accountId: _route.accountId,
3227
3556
  mediaLocalRoots,
3228
3557
  tableMode
@@ -3262,6 +3591,7 @@ function createMatrixRoomMessageHandler(params) {
3262
3591
  textLimit,
3263
3592
  replyToMode,
3264
3593
  threadId: threadTarget,
3594
+ replyToId: threadTarget ?? replyToEventId ?? void 0,
3265
3595
  accountId: _route.accountId,
3266
3596
  mediaLocalRoots,
3267
3597
  tableMode
@@ -3279,6 +3609,7 @@ function createMatrixRoomMessageHandler(params) {
3279
3609
  textLimit,
3280
3610
  replyToMode,
3281
3611
  threadId: threadTarget,
3612
+ replyToId: threadTarget ?? replyToEventId ?? void 0,
3282
3613
  accountId: _route.accountId,
3283
3614
  mediaLocalRoots,
3284
3615
  tableMode
@@ -3303,6 +3634,7 @@ function createMatrixRoomMessageHandler(params) {
3303
3634
  textLimit,
3304
3635
  replyToMode,
3305
3636
  threadId: threadTarget,
3637
+ replyToId: threadTarget ?? replyToEventId ?? void 0,
3306
3638
  accountId: _route.accountId,
3307
3639
  mediaLocalRoots,
3308
3640
  tableMode
@@ -3467,7 +3799,7 @@ function createMatrixRoomMessageHandler(params) {
3467
3799
  await commitInboundEventIfClaimed();
3468
3800
  return;
3469
3801
  }
3470
- if (isRoom && triggerSnapshot) roomHistoryTracker.consumeHistory(_route.agentId, roomId, triggerSnapshot, messageId);
3802
+ if (isRoom && triggerSnapshot) roomHistoryTracker.consumeHistory(_route.agentId, roomId, triggerSnapshot, messageId, threadRootId ? thread.threadId : void 0);
3471
3803
  if (!hasFinalInboundReplyDispatch({
3472
3804
  queuedFinal,
3473
3805
  counts
@@ -3803,11 +4135,11 @@ function createMatrixRoomInfoResolver(client) {
3803
4135
  let matrixStartupMaintenanceDepsPromise;
3804
4136
  async function loadMatrixStartupMaintenanceDeps() {
3805
4137
  matrixStartupMaintenanceDepsPromise ??= Promise.all([
3806
- import("./setup-core-CHX8Zcxh.js").then((n) => n.s),
4138
+ import("./setup-core-DJosJdWt.js").then((n) => n.s),
3807
4139
  import("./device-health-D4LBxuPq.js"),
3808
- import("./setup-core-CHX8Zcxh.js").then((n) => n.a),
4140
+ import("./setup-core-DJosJdWt.js").then((n) => n.a),
3809
4141
  import("./legacy-crypto-restore-CbVSppMd.js"),
3810
- import("./startup-verification-MAPgdkTX.js")
4142
+ import("./startup-verification-D1p_LRmg.js")
3811
4143
  ]).then(([configUpdateModule, deviceHealthModule, profileModule, legacyCryptoRestoreModule, startupVerificationModule]) => ({
3812
4144
  updateMatrixAccountConfig: configUpdateModule.updateMatrixAccountConfig,
3813
4145
  summarizeMatrixDeviceHealth: deviceHealthModule.summarizeMatrixDeviceHealth,