@openclaw/slack 2026.11.3 → 2026.11.5-beta.2
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/.setup/{account-inspect-CmkKiSb9.mjs → account-inspect-BLVha-ov.mjs} +11 -8
- package/dist/.setup/{accounts-msihSF3-.mjs → accounts-CGJScKtk.mjs} +10 -1
- package/dist/.setup/{action-runtime-ChRfnnBu.mjs → action-runtime-D01wBhx5.mjs} +38 -45
- package/dist/.setup/action-runtime.runtime-VQGaR6g8.mjs +1 -0
- package/dist/.setup/{actions-By7tvpvv.mjs → actions-D5S6D_BU.mjs} +89 -76
- package/dist/.setup/{approval-handler.runtime-D8ArtDQt.mjs → approval-handler.runtime-Buw5jh2Y.mjs} +26 -30
- package/dist/.setup/{approval-message-updates-DT7XBPbV.mjs → approval-message-updates-pmXcve5E.mjs} +1 -1
- package/dist/.setup/{channel-DLFiMJm2.mjs → channel-C_R98Nbv.mjs} +569 -339
- package/dist/.setup/{channel-type-BEFP2ORi.mjs → channel-type-B5P3w9eA.mjs} +4 -8
- package/dist/.setup/{channel.setup-CzFw73mU.mjs → channel.setup-Lq2OxKkF.mjs} +13 -13
- package/dist/.setup/{config-schema-DNnh6bWU.mjs → config-schema-BWAaa5au.mjs} +3 -7
- package/dist/.setup/cursor-pages-CATAzbTT.mjs +313 -0
- package/dist/.setup/{directory-config-Cjj0N8R0.mjs → directory-config-D-hf9KGQ.mjs} +3 -3
- package/dist/.setup/{directory-live-BIKD-5B_.mjs → directory-live-onKAFI1E.mjs} +4 -4
- package/dist/.setup/{doctor-contract-Cd4-VzIM.mjs → doctor-contract-9-QJRCXk.mjs} +37 -45
- package/dist/.setup/{message-tool-api-BS5ekEA_.mjs → message-tool-api-LGIgVXJf.mjs} +4 -3
- package/dist/.setup/{monitor-CV6Z6FKP.mjs → monitor-Cm1TuqxN.mjs} +3424 -3703
- package/dist/.setup/{outbound-adapter-9dbnYtL1.mjs → outbound-adapter-C-95EWl2.mjs} +30 -36
- package/dist/.setup/paths-B1u59oLK.mjs +8 -0
- package/dist/.setup/{pipeline.runtime-DLIQf1Bo.mjs → pipeline.runtime-DGnV6akc.mjs} +416 -534
- package/dist/.setup/{policy-yhn48xf5.mjs → policy-DxhGRvc2.mjs} +1 -2
- package/dist/.setup/{session-status-Dv8wNBEt.mjs → probe-DANukR3O.mjs} +1206 -839
- package/dist/.setup/question-delivery-CWC7sRhH.mjs +39 -0
- package/dist/.setup/{relay-source-CxDcrn16.mjs → relay-source-DoyOlTbK.mjs} +5 -3
- package/dist/.setup/{replies-MRkrg3rC.mjs → replies-BcmUKord.mjs} +34 -19
- package/dist/.setup/{reply-blocks-Ca-raz2z.mjs → reply-blocks-BzsXUUUL.mjs} +201 -206
- package/dist/.setup/{resolve-channels-DRRhElwz.mjs → resolve-channels-XDPgnesf.mjs} +4 -7
- package/dist/.setup/{resolve-users-Cz8e17ky.mjs → resolve-users-aDAv24U2.mjs} +8 -16
- package/dist/.setup/runtime-setter-api-Cx_PV-xu.mjs +2 -0
- package/dist/.setup/{scopes-DfQVi8Jw.mjs → scopes-BocHwImV.mjs} +2 -1
- package/dist/.setup/secret-contract-api-BlLz88mj.mjs +2 -0
- package/dist/.setup/{secret-contract-vVRMoE1D.mjs → secret-contract-uiQtoNlu.mjs} +2 -2
- package/dist/.setup/{send-results-eeOu_HYm.mjs → send-results-BGxlroJ-.mjs} +3 -4
- package/dist/.setup/{send-C-8wY0lK.mjs → send-yK6_-px6.mjs} +297 -334
- package/dist/.setup/setup-plugin-api-Cfz58xoh.mjs +2 -0
- package/dist/.setup/{setup-surface--n8VsDvV.mjs → setup-surface-C0KRtyqa.mjs} +5 -6
- package/dist/.setup/{slash-dispatch.runtime-D3Wq45ER.mjs → slash-dispatch.runtime-CyVC3bYx.mjs} +2 -2
- package/dist/.setup/{target-parsing-FFE26kOV.mjs → target-parsing-Bx2UZniD.mjs} +1 -2
- package/dist/.setup/{targets-C6LZQL1Q.mjs → targets-D-ASeWHy.mjs} +1 -1
- package/dist/.source-module-urls/c5ffd0957b234c7c12090e7de4eca2482ef339b8561e078da55b734211b0ba58.json +1 -0
- package/dist/account-inspect-api.js +1 -1
- package/dist/api.js +16 -17
- package/dist/channel-config-api.js +1 -2
- package/dist/channel-plugin-api.js +1 -2
- package/dist/directory-contract-api.js +1 -2
- package/dist/doctor-contract-api.js +1 -2
- package/dist/index.js +0 -6
- package/dist/message-tool-api.js +1 -2
- package/dist/runtime-api.js +10 -12
- package/dist/runtime-setter-api.js +1 -2
- package/dist/secret-contract-api.js +1 -2
- package/dist/security-contract-api.js +1 -2
- package/dist/setup-entry.js +3 -3
- package/dist/setup-plugin-api.js +1 -2
- package/node_modules/@slack/bolt/node_modules/@types/node/README.md +1 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/package.json +2 -2
- package/node_modules/@slack/bolt/node_modules/@types/node/util.d.ts +6 -3
- package/node_modules/@slack/bolt/node_modules/content-disposition/README.md +105 -35
- package/node_modules/@slack/bolt/node_modules/content-disposition/dist/index.d.ts +72 -0
- package/node_modules/@slack/bolt/node_modules/content-disposition/dist/index.js +388 -0
- package/node_modules/@slack/bolt/node_modules/content-disposition/dist/index.js.map +1 -0
- package/node_modules/@slack/bolt/node_modules/content-disposition/package.json +31 -19
- package/node_modules/@slack/bolt/node_modules/content-type/README.md +34 -57
- package/node_modules/@slack/bolt/node_modules/content-type/package.json +35 -25
- package/node_modules/@slack/bolt/node_modules/express/Readme.md +15 -9
- package/node_modules/@slack/bolt/node_modules/express/lib/application.js +2 -2
- package/node_modules/@slack/bolt/node_modules/express/lib/request.js +32 -19
- package/node_modules/@slack/bolt/node_modules/express/lib/response.js +27 -30
- package/node_modules/@slack/bolt/node_modules/express/package.json +10 -10
- package/node_modules/@slack/bolt/node_modules/qs/.github/THREAT_MODEL.md +4 -2
- package/node_modules/@slack/bolt/node_modules/qs/CHANGELOG.md +38 -14
- package/node_modules/@slack/bolt/node_modules/qs/README.md +31 -3
- package/node_modules/@slack/bolt/node_modules/qs/dist/qs.js +20 -20
- package/node_modules/@slack/bolt/node_modules/qs/lib/parse.js +94 -4
- package/node_modules/@slack/bolt/node_modules/qs/lib/stringify.js +4 -4
- package/node_modules/@slack/bolt/node_modules/qs/lib/utils.js +130 -6
- package/node_modules/@slack/bolt/node_modules/qs/package.json +4 -4
- package/node_modules/@slack/bolt/node_modules/qs/test/parse.js +174 -0
- package/node_modules/@slack/bolt/node_modules/qs/test/stringify.js +263 -33
- package/node_modules/@slack/bolt/node_modules/qs/test/utils.js +184 -0
- package/node_modules/@slack/web-api/node_modules/@types/node/README.md +1 -1
- package/node_modules/@slack/web-api/node_modules/@types/node/package.json +2 -2
- package/node_modules/@slack/web-api/node_modules/@types/node/util.d.ts +6 -3
- package/node_modules/typebox/build/format/duration.d.mts +2 -2
- package/node_modules/typebox/build/format/duration.mjs +2 -2
- package/node_modules/typebox/build/format/idn_email.d.mts +1 -0
- package/node_modules/typebox/build/format/idn_email.mjs +1 -0
- package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -1
- package/node_modules/typebox/build/format/idn_hostname.mjs +1 -1
- package/node_modules/typebox/build/format/ipv4.d.mts +2 -2
- package/node_modules/typebox/build/format/ipv4.mjs +2 -2
- package/node_modules/typebox/build/format/ipv6.d.mts +1 -1
- package/node_modules/typebox/build/format/ipv6.mjs +1 -1
- package/node_modules/typebox/build/format/relative_json_pointer.d.mts +2 -2
- package/node_modules/typebox/build/format/relative_json_pointer.mjs +2 -2
- package/node_modules/typebox/build/schema/build.mjs +1 -0
- package/node_modules/typebox/build/schema/engine/_unique.d.mts +4 -2
- package/node_modules/typebox/build/schema/engine/_unique.mjs +7 -3
- package/node_modules/typebox/build/schema/engine/additionalItems.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/additionalProperties.d.mts +0 -3
- package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +15 -17
- package/node_modules/typebox/build/schema/engine/contains.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/index.d.mts +1 -0
- package/node_modules/typebox/build/schema/engine/index.mjs +1 -0
- package/node_modules/typebox/build/schema/engine/items.mjs +7 -4
- package/node_modules/typebox/build/schema/engine/maxContains.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/minContains.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/oneOf.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/patternProperties.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/unevaluatedItems.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/unevaluatedProperties.mjs +2 -2
- package/node_modules/typebox/build/system/hashing/hash.mjs +63 -34
- package/node_modules/typebox/build/system/locale/en_US.mjs +2 -1
- package/node_modules/typebox/build/system/memory/assign.d.mts +2 -8
- package/node_modules/typebox/build/system/memory/assign.mjs +13 -6
- package/node_modules/typebox/build/system/memory/clone.d.mts +4 -5
- package/node_modules/typebox/build/system/memory/clone.mjs +8 -96
- package/node_modules/typebox/build/system/memory/create.d.mts +1 -5
- package/node_modules/typebox/build/system/memory/create.mjs +18 -13
- package/node_modules/typebox/build/system/memory/deep.d.mts +2 -0
- package/node_modules/typebox/build/system/memory/deep.mjs +108 -0
- package/node_modules/typebox/build/system/memory/discard.d.mts +1 -1
- package/node_modules/typebox/build/system/memory/discard.mjs +9 -8
- package/node_modules/typebox/build/system/memory/finalize.d.mts +4 -0
- package/node_modules/typebox/build/system/memory/finalize.mjs +30 -0
- package/node_modules/typebox/build/system/memory/keys.d.mts +2 -0
- package/node_modules/typebox/build/system/memory/keys.mjs +8 -0
- package/node_modules/typebox/build/system/memory/update.d.mts +1 -4
- package/node_modules/typebox/build/system/memory/update.mjs +43 -16
- package/node_modules/typebox/build/type/engine/call/index.d.mts +1 -0
- package/node_modules/typebox/build/type/engine/call/index.mjs +1 -0
- package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +2 -24
- package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +2 -29
- package/node_modules/typebox/build/type/engine/evaluate/index.d.mts +1 -0
- package/node_modules/typebox/build/type/engine/evaluate/index.mjs +1 -0
- package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +5 -1
- package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +6 -1
- package/node_modules/typebox/build/type/engine/evaluate/property.d.mts +30 -0
- package/node_modules/typebox/build/type/engine/evaluate/property.mjs +29 -0
- package/node_modules/typebox/build/type/engine/immutable/instantiate_add.d.mts +1 -3
- package/node_modules/typebox/build/type/engine/immutable/instantiate_add.mjs +1 -4
- package/node_modules/typebox/build/type/engine/object/from_intersect.d.mts +2 -2
- package/node_modules/typebox/build/type/engine/object/from_intersect.mjs +2 -2
- package/node_modules/typebox/build/type/engine/object/from_union.d.mts +2 -2
- package/node_modules/typebox/build/type/engine/object/from_union.mjs +2 -2
- package/node_modules/typebox/build/type/engine/optional/instantiate_add.d.mts +1 -3
- package/node_modules/typebox/build/type/engine/optional/instantiate_add.mjs +1 -4
- package/node_modules/typebox/build/type/engine/readonly/instantiate_add.d.mts +1 -3
- package/node_modules/typebox/build/type/engine/readonly/instantiate_add.mjs +1 -4
- package/node_modules/typebox/build/type/engine/this/index.d.mts +1 -0
- package/node_modules/typebox/build/type/engine/this/index.mjs +1 -0
- package/node_modules/typebox/build/value/clone/clone.d.mts +4 -3
- package/node_modules/typebox/build/value/clone/clone.mjs +5 -7
- package/node_modules/typebox/build/value/repair/from_cyclic.d.mts +2 -0
- package/node_modules/typebox/build/value/repair/from_cyclic.mjs +6 -0
- package/node_modules/typebox/build/value/shared/union_priority_sort.mjs +25 -14
- package/node_modules/typebox/package.json +1 -1
- package/node_modules/typebox/readme.md +1 -1
- package/node_modules/undici/docs/docs/api/Interceptors.md +15 -2
- package/node_modules/undici/lib/dispatcher/client-h2.js +78 -3
- package/node_modules/undici/lib/dispatcher/pool-base.js +20 -3
- package/node_modules/undici/package.json +3 -3
- package/node_modules/undici/types/api.d.ts +1 -1
- package/node_modules/undici/types/utility.d.ts +4 -4
- package/node_modules/zod/package.json +1 -1
- package/node_modules/zod/src/v4/classic/tests/array.test.ts +27 -0
- package/node_modules/zod/src/v4/classic/tests/map.test.ts +7 -0
- package/node_modules/zod/src/v4/classic/tests/set.test.ts +6 -0
- package/node_modules/zod/src/v4/core/compile.ts +9 -0
- package/node_modules/zod/src/v4/core/schemas.ts +35 -1
- package/node_modules/zod/src/v4/core/util.ts +13 -0
- package/node_modules/zod/src/v4/core/versions.ts +1 -1
- package/node_modules/zod/v4/core/compile.cjs +8 -0
- package/node_modules/zod/v4/core/compile.js +8 -0
- package/node_modules/zod/v4/core/schemas.cjs +30 -0
- package/node_modules/zod/v4/core/schemas.d.cts +3 -1
- package/node_modules/zod/v4/core/schemas.d.ts +3 -1
- package/node_modules/zod/v4/core/schemas.js +30 -0
- package/node_modules/zod/v4/core/util.cjs +15 -0
- package/node_modules/zod/v4/core/util.d.cts +2 -0
- package/node_modules/zod/v4/core/util.d.ts +2 -0
- package/node_modules/zod/v4/core/util.js +14 -0
- package/node_modules/zod/v4/core/versions.cjs +1 -1
- package/node_modules/zod/v4/core/versions.js +1 -1
- package/openclaw.plugin.json +6 -30
- package/package.json +7 -7
- package/dist/.setup/action-runtime.runtime-vLxx_7s2.mjs +0 -2
- package/dist/.setup/http-C9sM-FXe.mjs +0 -2
- package/dist/.setup/plugin-routes-D4qozHVn.mjs +0 -22
- package/dist/.setup/probe-IiHogLQN.mjs +0 -694
- package/dist/.setup/registry-DizWcnNp.mjs +0 -36
- package/dist/.setup/runtime-setter-api-CMFvhrAr.mjs +0 -3
- package/dist/.setup/secret-contract-api-DK9gZldc.mjs +0 -3
- package/dist/.setup/setup-plugin-api-BGD1TYnK.mjs +0 -3
- package/dist/.setup/shared-BhJHIZs1.mjs +0 -259
- package/dist/http-routes-api.js +0 -2
- package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/LICENSE +0 -22
- package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/README.md +0 -71
- package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/package.json +0 -52
- package/node_modules/@slack/bolt/node_modules/content-disposition/index.js +0 -536
- package/node_modules/@slack/bolt/node_modules/content-type/HISTORY.md +0 -29
- package/node_modules/@slack/bolt/node_modules/content-type/index.js +0 -225
- package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/LICENSE +0 -22
- package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/README.md +0 -71
- package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +0 -46
- package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.js +0 -176
- package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.js.map +0 -1
- package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/package.json +0 -52
- package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/LICENSE +0 -22
- package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/README.md +0 -71
- package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.d.ts +0 -46
- package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.js +0 -176
- package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.js.map +0 -1
- package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/package.json +0 -52
- package/node_modules/typebox/build/system/memory/freeze.d.mts +0 -4
- package/node_modules/typebox/build/system/memory/freeze.mjs +0 -6
- /package/node_modules/@slack/bolt/node_modules/{body-parser/node_modules/content-type → content-type}/dist/index.d.ts +0 -0
- /package/node_modules/@slack/bolt/node_modules/{body-parser/node_modules/content-type → content-type}/dist/index.js +0 -0
- /package/node_modules/@slack/bolt/node_modules/{body-parser/node_modules/content-type → content-type}/dist/index.js.map +0 -0
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { n as __reExport, t as __exportAll } from "./rolldown-runtime-B4FMCO8f.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { n as formatSlackTarget } from "./target-parsing-
|
|
4
|
-
import {
|
|
5
|
-
import { M as resolveSlackUserAllowed, O as normalizeSlackAllowOwnerEntry, b as writeLruMapEntry, o as formatSlackError, v as pruneExpiredMapEntries, y as readLruMapEntry } from "./probe-IiHogLQN.mjs";
|
|
6
|
-
import { a as prepareSlackReply, l as resolveSlackReplyRenderPlan, s as resolveSlackReplyBlocks } from "./reply-blocks-Ca-raz2z.mjs";
|
|
2
|
+
import { d as resolveSlackMarkdownOptions, o as resolveDefaultSlackAccountId, p as resolveSlackReplyToMode } from "./accounts-CGJScKtk.mjs";
|
|
3
|
+
import { n as formatSlackTarget } from "./target-parsing-Bx2UZniD.mjs";
|
|
4
|
+
import { F as truncateSlackText, Gt as resolveSlackUserAllowed, I as truncateSlackTextByUtf8Bytes, O as hasSlackNativeDataBlock, P as countSlackTextUtf8Bytes, Tt as escapeSlackMrkdwn, U as SLACK_SESSION_LINK_ACTION_ID, Vt as normalizeSlackAllowOwnerEntry, _ as qualifySlackRoutePeerId, at as buildSlackCompleteBlocksFallbackText, it as buildSlackBlocksFallbackText, m as formatSlackError, vt as SLACK_EDIT_TEXT_MAX_BYTES, wt as normalizeSlackOutboundText, xt as SLACK_TEXT_LIMIT } from "./probe-DANukR3O.mjs";
|
|
7
5
|
import { n as resolveSlackReplyThreadTs } from "./thread-ts-Cvt7WD6B.mjs";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { n as
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
6
|
+
import { c as resolveSlackReplyRenderPlan, i as prepareSlackReply, o as resolveSlackReplyBlocks } from "./reply-blocks-BzsXUUUL.mjs";
|
|
7
|
+
import { d as getOrCreateWeakOwnerMap, m as writeLruMapEntry, p as readLruMapEntry } from "./cursor-pages-CATAzbTT.mjs";
|
|
8
|
+
import { C as hasSlackTableBlock, D as buildSlackEditTextPayload, E as resolveSlackMessageText$1, T as resolveSlackBlocksText, a as editSlackRenderedMessage, b as formatSlackFileReference, d as reactSlackMessage, i as editSlackMessage, m as removeSlackReaction, n as deleteSlackMessage, w as isSlackUnfurlAttachment, x as formatSlackFileReferenceList } from "./actions-D5S6D_BU.mjs";
|
|
9
|
+
import { a as clearSlackThreadFailureNotice, c as hasSlackThreadParticipation, d as recordSlackThreadParticipation, h as buildSlackNativeDataDeliveryPlan, l as hasSlackThreadParticipationWithPersistence, m as hasSlackMessageIdentity, s as hasSlackThreadFailureNotice, t as sendMessageSlack, u as recordSlackThreadFailureNotice } from "./send-yK6_-px6.mjs";
|
|
10
|
+
import { n as resolveSlackChannelConfig } from "./policy-DxhGRvc2.mjs";
|
|
11
|
+
import { C as resolveSlackChatType, E as stripSlackMentionsForCommandDetection, S as normalizeSlackChannelType, T as readSlackAssistantThreadContext, _ as appendSlackStream, b as stopSlackStream, c as registerSlackSessionRun, g as SlackStreamNotDeliveredError, h as resolveSlackEffectiveAllowFrom, l as resolveSlackThreadContext, m as resolveSlackCommandIngress, o as authorizeSlackDirectMessage, p as authorizeSlackBotRoomMessage, r as resolveSlackRoomContextHints, s as resolveSlackRoutingContext, u as trackSlackDraftMessage, v as markSlackStreamFallbackDelivered, w as buildSlackAssistantThreadMetadata, y as startSlackStream } from "./monitor-Cm1TuqxN.mjs";
|
|
12
|
+
import { a as emitSlackMessageSentHooks, i as sanitizeSlackMonitorReplyPayload, n as deliverReplies, t as createSlackReplyDeliveryPlan } from "./replies-BcmUKord.mjs";
|
|
13
13
|
import { asOptionalRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, readNonBlankString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
14
|
+
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
14
15
|
import { resolveInboundLastRouteSessionKey } from "openclaw/plugin-sdk/routing";
|
|
15
16
|
import { buildChannelProgressDraftLine, compactChannelProgressDraftLine, createChannelMessageReplyPipeline, createChannelProgressDraftCompositor, createChannelProgressWorkCounter, createDraftStreamLoop, createFinalizableDraftLifecycle, createLivePreviewLifecycle, createMessageReceiptFromOutboundResults, resolveAgentOutboundIdentity, resolveChannelMessageSourceReplyDeliveryMode, resolveChannelProgressDraftConfig, resolveChannelProgressDraftMaxLineChars, resolveChannelStreamingBlockEnabled, resolveChannelStreamingPreviewToolProgress, resolveChannelStreamingSuppressDefaultToolProgressMessages, selectPlanChecklistSteps } from "openclaw/plugin-sdk/channel-outbound";
|
|
16
17
|
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
@@ -18,10 +19,9 @@ import { danger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtim
|
|
|
18
19
|
import { sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
|
|
19
20
|
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
20
21
|
import { normalizeStringEntriesLower } from "openclaw/plugin-sdk/string-normalization-runtime";
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
22
|
+
import { createStaleWhileRevalidateCache } from "openclaw/plugin-sdk/collection-runtime";
|
|
23
|
+
import { asFiniteNumberInRange, parseStrictFiniteNumber, resolvePromptHistoryLimit } from "openclaw/plugin-sdk/number-runtime";
|
|
23
24
|
import { buildTtsSupplementMediaPayload, getReplyPayloadTtsSupplement, isReplyPayloadNonTerminalToolErrorWarning, resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
|
|
24
|
-
import { asDateTimestampMs, asFiniteNumberInRange, parseStrictFiniteNumber, resolveExpiresAtMsFromDurationMs, resolvePromptHistoryLimit } from "openclaw/plugin-sdk/number-runtime";
|
|
25
25
|
import { hash } from "node:crypto";
|
|
26
26
|
import { resolveChannelImplicitMentions } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
27
27
|
import fs from "node:fs/promises";
|
|
@@ -32,10 +32,10 @@ import { mimeTypeFromFilePath, normalizeMimeType } from "openclaw/plugin-sdk/med
|
|
|
32
32
|
import { ensureConfiguredBindingRouteReady, resolveConversationLabel } from "openclaw/plugin-sdk/conversation-runtime";
|
|
33
33
|
import { mergePairLoopGuardConfig } from "openclaw/plugin-sdk/pair-loop-guard-runtime";
|
|
34
34
|
import { getSessionEntryAsync, readSessionUpdatedAtAsync, resolveChannelResetConfig, resolveStorePath, updateLastRoute } from "openclaw/plugin-sdk/session-store-runtime";
|
|
35
|
-
import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
|
|
36
35
|
import { enqueueRoutedSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
|
|
37
36
|
import { getGlobalHookRunner } from "openclaw/plugin-sdk/plugin-runtime";
|
|
38
|
-
import {
|
|
37
|
+
import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
|
|
38
|
+
import { buildChannelInboundEventContext, buildMentionRegexes, classifyChannelInboundEvent, dispatchChannelInboundTurn, formatInboundEnvelope, formatInboundMediaUnavailableText, hasVisibleInboundReplyDispatch, isGroupThreadRouteExclusive, matchesMentionWithExplicit, readAgentRunTerminalOutcome, resolveEnvelopeFormatOptions, resolveGroupThreadConfig, resolveGroupThreadMentionFacts, resolveInboundMentionDecision, resolveUnmentionedGroupInboundPolicy, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
|
|
39
39
|
import { resolveGatewayPublicOrigin } from "openclaw/plugin-sdk/config-contracts";
|
|
40
40
|
import { buildControlUiSessionPath } from "openclaw/plugin-sdk/session-discussion";
|
|
41
41
|
import { createStatusReactionController, logAckFailure, logTypingFailure, resolveAckReaction, shouldAckReaction } from "openclaw/plugin-sdk/channel-feedback";
|
|
@@ -97,13 +97,6 @@ function resolveSlackNativeProgressTaskCards(entry, style) {
|
|
|
97
97
|
}
|
|
98
98
|
const SLACK_STREAM_RECIPIENT_TEAM_CACHE_MAX = 2e3;
|
|
99
99
|
const slackStreamRecipientTeamCaches = /* @__PURE__ */ new WeakMap();
|
|
100
|
-
function getSlackStreamRecipientTeamCache(client) {
|
|
101
|
-
const existing = slackStreamRecipientTeamCaches.get(client);
|
|
102
|
-
if (existing) return existing;
|
|
103
|
-
const cache = /* @__PURE__ */ new Map();
|
|
104
|
-
slackStreamRecipientTeamCaches.set(client, cache);
|
|
105
|
-
return cache;
|
|
106
|
-
}
|
|
107
100
|
function buildSlackEventDeliveryKey(params, preparedReply = prepareSlackReply(params.payload)) {
|
|
108
101
|
const reply = resolveSendableOutboundReplyParts(params.payload, { text: params.textOverride });
|
|
109
102
|
const renderPlan = preparedReply.resolvePreview(params.textOverride);
|
|
@@ -122,7 +115,7 @@ function buildSlackEventDeliveryKey(params, preparedReply = prepareSlackReply(pa
|
|
|
122
115
|
}
|
|
123
116
|
async function resolveSlackStreamRecipientTeamId(params) {
|
|
124
117
|
const cacheKey = params.fallbackTeamId && params.userId ? `${params.fallbackTeamId}:${params.userId}` : void 0;
|
|
125
|
-
const cache = cacheKey ?
|
|
118
|
+
const cache = cacheKey ? getOrCreateWeakOwnerMap(slackStreamRecipientTeamCaches, params.client) : void 0;
|
|
126
119
|
const cachedTeamId = cache && cacheKey ? readLruMapEntry(cache, cacheKey) : void 0;
|
|
127
120
|
if (cachedTeamId) return cachedTeamId;
|
|
128
121
|
if (params.userId) try {
|
|
@@ -146,8 +139,6 @@ const DEFAULT_THROTTLE_MS = 1e3;
|
|
|
146
139
|
function createSlackDraftStream(params) {
|
|
147
140
|
const maxChars = Math.min(params.maxChars ?? 8e3, SLACK_TEXT_LIMIT);
|
|
148
141
|
const throttleMs = Math.max(250, params.throttleMs ?? DEFAULT_THROTTLE_MS);
|
|
149
|
-
const send = params.send ?? sendMessageSlack;
|
|
150
|
-
const remove = params.remove ?? deleteSlackMessage;
|
|
151
142
|
let streamMessage;
|
|
152
143
|
let untrackConversationBoundary;
|
|
153
144
|
let lastSentKey = "";
|
|
@@ -161,7 +152,7 @@ function createSlackDraftStream(params) {
|
|
|
161
152
|
streamMessage = void 0;
|
|
162
153
|
lastSentKey = "";
|
|
163
154
|
};
|
|
164
|
-
const editPreview = (message, update) => (
|
|
155
|
+
const editPreview = (message, update) => (update.textIsSlackMrkdwn ? editSlackRenderedMessage : editSlackMessage)(message.channelId, message.messageId, update.text, {
|
|
165
156
|
cfg: params.cfg,
|
|
166
157
|
token: params.token,
|
|
167
158
|
accountId: params.accountId,
|
|
@@ -208,7 +199,7 @@ function createSlackDraftStream(params) {
|
|
|
208
199
|
onInterveningMessage: () => forceNewMessage("human")
|
|
209
200
|
});
|
|
210
201
|
await lifecycle.createMessage(async () => {
|
|
211
|
-
const sent = await
|
|
202
|
+
const sent = await sendMessageSlack(params.target, visibleUpdate.text, {
|
|
212
203
|
cfg: params.cfg,
|
|
213
204
|
token: params.token,
|
|
214
205
|
accountId: params.accountId,
|
|
@@ -253,7 +244,7 @@ function createSlackDraftStream(params) {
|
|
|
253
244
|
clearMessageId,
|
|
254
245
|
isValidMessageId: (value) => typeof value === "object" && value !== null,
|
|
255
246
|
deleteMessage: async (message) => {
|
|
256
|
-
if (!message.retained && !(preserveHumanReplies && message.detachedByHuman)) await
|
|
247
|
+
if (!message.retained && !(preserveHumanReplies && message.detachedByHuman)) await deleteSlackMessage(message.channelId, message.messageId, {
|
|
257
248
|
token: params.token,
|
|
258
249
|
accountId: params.accountId,
|
|
259
250
|
...params.eventScope ? { client: params.eventScope.client } : {}
|
|
@@ -301,7 +292,6 @@ function createSlackDraftStream(params) {
|
|
|
301
292
|
stopTrackingConversationBoundary();
|
|
302
293
|
return true;
|
|
303
294
|
};
|
|
304
|
-
params.log?.(`slack stream preview ready (maxChars=${maxChars}, throttleMs=${throttleMs})`);
|
|
305
295
|
return {
|
|
306
296
|
update,
|
|
307
297
|
flush: loop.flush,
|
|
@@ -375,12 +365,6 @@ const SLACK_PROGRESS_TASK_TITLE_MAX = 120;
|
|
|
375
365
|
const SLACK_PROGRESS_PLAN_FALLBACK_TITLE = "Thinking";
|
|
376
366
|
const SLACK_PROGRESS_LINE_DELTA_RE = /(?:^|\s)\+(\d+)\s+[−-](\d+)(?=\s|$)/u;
|
|
377
367
|
const SLACK_ATTENTION_TASK_PREFIX = "openclaw-attention-";
|
|
378
|
-
function buildSessionSources(links) {
|
|
379
|
-
return links.map((link) => ({
|
|
380
|
-
type: "url_source",
|
|
381
|
-
...link
|
|
382
|
-
}));
|
|
383
|
-
}
|
|
384
368
|
function field(text) {
|
|
385
369
|
return {
|
|
386
370
|
type: "mrkdwn",
|
|
@@ -439,10 +423,6 @@ function lineTaskTitle(line) {
|
|
|
439
423
|
if (fallback && fallback !== label) return compactTitle(lineDetailParts(line).length > 0 || line.status ? label : fallback);
|
|
440
424
|
return compactTitle(label);
|
|
441
425
|
}
|
|
442
|
-
function lineTaskDetails(line, maxLineChars) {
|
|
443
|
-
const detail = line.detail?.replace(SLACK_PROGRESS_LINE_DELTA_RE, "").replace(/\s+·\s*$/u, "").trim();
|
|
444
|
-
return detail && detail !== line.status?.trim() ? compactDetail(detail, maxLineChars) : void 0;
|
|
445
|
-
}
|
|
446
426
|
function lineTaskOutput(line) {
|
|
447
427
|
const match = line.detail ? SLACK_PROGRESS_LINE_DELTA_RE.exec(line.detail) : null;
|
|
448
428
|
if (match) return `+${match[1]} −${match[2]}`;
|
|
@@ -473,48 +453,39 @@ function resolveLineTaskIdentity(line, contentIdOccurrences) {
|
|
|
473
453
|
contentIdOccurrences.set(id, occurrence);
|
|
474
454
|
return `${id}_${occurrence}`;
|
|
475
455
|
}
|
|
476
|
-
function
|
|
456
|
+
function formatProgressAttentionTitle(line, finalStatus) {
|
|
457
|
+
if (line.kind === "approval") return line.status === "requested" && finalStatus === void 0 ? compactTitle(`Approval required: ${line.detail || line.label}`) : void 0;
|
|
458
|
+
if (lineTaskStatus(line) !== "error") return;
|
|
459
|
+
const title = [...new Set([
|
|
460
|
+
line.label,
|
|
461
|
+
line.detail,
|
|
462
|
+
line.status
|
|
463
|
+
].filter(Boolean))].join(" — ");
|
|
464
|
+
return compactTitle(finalStatus === "complete" ? `Recovered: ${title}` : title);
|
|
465
|
+
}
|
|
466
|
+
function buildSlackProgressStreamChunks(params) {
|
|
467
|
+
const approvals = params.lines.filter((line) => line.kind === "approval");
|
|
468
|
+
const taskLines = params.summaryRow ? [] : params.lines.filter((line) => line.kind !== "approval");
|
|
477
469
|
const tasks = (params.plan ?? []).map((entry, index) => ({
|
|
478
470
|
id: `plan_step_${index + 1}`,
|
|
479
471
|
title: compactTitle(entry.step),
|
|
480
472
|
status: entry.status === "completed" ? "complete" : entry.status
|
|
481
473
|
}));
|
|
482
474
|
const maxLineChars = resolveMaxLineChars(params.maxLineChars, DEFAULT_SLACK_PROGRESS_TASK_DETAIL_MAX_CHARS);
|
|
483
|
-
const
|
|
484
|
-
for (const line of
|
|
475
|
+
const taskContentIdOccurrences = /* @__PURE__ */ new Map();
|
|
476
|
+
for (const line of taskLines) {
|
|
485
477
|
const task = {
|
|
486
|
-
id: resolveLineTaskIdentity(line,
|
|
478
|
+
id: resolveLineTaskIdentity(line, taskContentIdOccurrences),
|
|
487
479
|
title: lineTaskTitle(line),
|
|
488
480
|
status: lineTaskStatus(line)
|
|
489
481
|
};
|
|
490
|
-
const
|
|
482
|
+
const detail = line.detail?.replace(SLACK_PROGRESS_LINE_DELTA_RE, "").replace(/\s+·\s*$/u, "").trim();
|
|
483
|
+
const details = detail && detail !== line.status?.trim() ? compactDetail(detail, maxLineChars) : void 0;
|
|
491
484
|
const output = lineTaskOutput(line);
|
|
492
485
|
if (details) task.details = details;
|
|
493
486
|
if (output) task.output = output;
|
|
494
487
|
tasks.push(task);
|
|
495
488
|
}
|
|
496
|
-
return tasks;
|
|
497
|
-
}
|
|
498
|
-
function formatProgressAttentionTitle(line, finalStatus) {
|
|
499
|
-
if (line.kind === "approval") return line.status === "requested" && finalStatus === void 0 ? compactTitle(`Approval required: ${line.detail || line.label}`) : void 0;
|
|
500
|
-
if (lineTaskStatus(line) !== "error") return;
|
|
501
|
-
const title = [...new Set([
|
|
502
|
-
line.label,
|
|
503
|
-
line.detail,
|
|
504
|
-
line.status
|
|
505
|
-
].filter(Boolean))].join(" — ");
|
|
506
|
-
return compactTitle(finalStatus === "complete" ? `Recovered: ${title}` : title);
|
|
507
|
-
}
|
|
508
|
-
function formatTaskDiffOutput(diffStat) {
|
|
509
|
-
return diffStat && (diffStat.added > 0 || diffStat.removed > 0) ? `+${diffStat.added} −${diffStat.removed}` : void 0;
|
|
510
|
-
}
|
|
511
|
-
function buildSlackProgressStreamChunks(params) {
|
|
512
|
-
const approvals = params.lines.filter((line) => line.kind === "approval");
|
|
513
|
-
const tasks = buildNativeTasks({
|
|
514
|
-
lines: params.summaryRow ? [] : params.lines.filter((line) => line.kind !== "approval"),
|
|
515
|
-
plan: params.plan,
|
|
516
|
-
maxLineChars: params.maxLineChars
|
|
517
|
-
});
|
|
518
489
|
const contentIdOccurrences = /* @__PURE__ */ new Map();
|
|
519
490
|
const attention = [];
|
|
520
491
|
for (const line of approvals) {
|
|
@@ -525,11 +496,11 @@ function buildSlackProgressStreamChunks(params) {
|
|
|
525
496
|
status: "pending"
|
|
526
497
|
});
|
|
527
498
|
}
|
|
528
|
-
const headline = params.title?.trim()
|
|
499
|
+
const headline = params.title?.trim();
|
|
529
500
|
const summaryTitle = params.finalInProgressStatus === "error" ? "Failed" : params.finalInProgressStatus === "complete" || !params.summaryRow ? "Completed" : "Working";
|
|
530
501
|
const newest = tasks.at(-1);
|
|
531
502
|
const title = compactTitle(headline || (newest?.details ? `${newest.title} — ${newest.details}` : newest?.title) || (params.summaryRow ? summaryTitle : attention.at(-1)?.title) || SLACK_PROGRESS_PLAN_FALLBACK_TITLE, SLACK_PROGRESS_CHUNK_TEXT_MAX);
|
|
532
|
-
const diffOutput =
|
|
503
|
+
const diffOutput = params.diffStat && (params.diffStat.added > 0 || params.diffStat.removed > 0) ? `+${params.diffStat.added} −${params.diffStat.removed}` : void 0;
|
|
533
504
|
if (tasks.length === 0 && (params.summaryRow || params.sessionLinks?.length || diffOutput)) tasks.push({
|
|
534
505
|
id: "openclaw_summary",
|
|
535
506
|
title: params.summaryRow ? compactTitle(title) : summaryTitle,
|
|
@@ -549,7 +520,10 @@ function buildSlackProgressStreamChunks(params) {
|
|
|
549
520
|
chunk.title = recovered ? compactTitle(`Recovered: ${task.title}`) : task.title;
|
|
550
521
|
chunk.status = recovered ? "complete" : task.status === "in_progress" ? params.finalInProgressStatus ?? task.status : task.status;
|
|
551
522
|
if (index === finalTaskIndex && diffOutput) chunk.output = [task.output, diffOutput].filter(Boolean).join(" · ");
|
|
552
|
-
if (index === finalTaskIndex && params.sessionLinks?.length) chunk.sources =
|
|
523
|
+
if (index === finalTaskIndex && params.sessionLinks?.length) chunk.sources = params.sessionLinks.map((link) => ({
|
|
524
|
+
type: "url_source",
|
|
525
|
+
...link
|
|
526
|
+
}));
|
|
553
527
|
return chunk;
|
|
554
528
|
});
|
|
555
529
|
return [{
|
|
@@ -568,13 +542,6 @@ function joinRecentProgressRows(rows) {
|
|
|
568
542
|
}
|
|
569
543
|
return rendered.toReversed().join("\n");
|
|
570
544
|
}
|
|
571
|
-
function buildActivityText(lines, maxLineChars) {
|
|
572
|
-
return joinRecentProgressRows(lines.slice(-50).map((line) => {
|
|
573
|
-
if (line.kind === "item" && !line.toolName) return `_${renderProgressCardText(compactDetail(line.text, maxLineChars), "italic")}_`;
|
|
574
|
-
const detail = compactDetail(lineDetailParts(line).join(" · "), maxLineChars);
|
|
575
|
-
return escapeSlackMrkdwn(detail ? `${line.label} — ${detail}` : line.label);
|
|
576
|
-
}));
|
|
577
|
-
}
|
|
578
545
|
function buildSlackProgressCardBlocks(params) {
|
|
579
546
|
const maxLineChars = resolveMaxLineChars(params.maxLineChars, DEFAULT_SLACK_PROGRESS_DETAIL_MAX_CHARS);
|
|
580
547
|
const selected = selectPlanChecklistSteps(params.detailed ? params.plan ?? [] : [], { maxLines: 50 });
|
|
@@ -604,7 +571,11 @@ function buildSlackProgressCardBlocks(params) {
|
|
|
604
571
|
});
|
|
605
572
|
const sections = [
|
|
606
573
|
planLines.map((line) => renderProgressCardText(line)).join("\n"),
|
|
607
|
-
|
|
574
|
+
joinRecentProgressRows(lines.filter((line) => line.kind !== "approval" && lineTaskStatus(line) !== "error").slice(-50).map((line) => {
|
|
575
|
+
if (line.kind === "item" && !line.toolName) return `_${renderProgressCardText(compactDetail(line.text, maxLineChars), "italic")}_`;
|
|
576
|
+
const detail = compactDetail(lineDetailParts(line).join(" · "), maxLineChars);
|
|
577
|
+
return escapeSlackMrkdwn(detail ? `${line.label} — ${detail}` : line.label);
|
|
578
|
+
})),
|
|
608
579
|
joinRecentProgressRows(attention)
|
|
609
580
|
];
|
|
610
581
|
const title = params.title?.trim();
|
|
@@ -684,6 +655,13 @@ function reconcileSlackNativeTaskChunks(params) {
|
|
|
684
655
|
const nextTasks = /* @__PURE__ */ new Map();
|
|
685
656
|
let planTitle = params.previous.planTitle;
|
|
686
657
|
const emitted = [];
|
|
658
|
+
if (!params.chunks?.length && planTitle && planTitle !== SLACK_PROGRESS_PLAN_FALLBACK_TITLE) {
|
|
659
|
+
planTitle = SLACK_PROGRESS_PLAN_FALLBACK_TITLE;
|
|
660
|
+
emitted.push({
|
|
661
|
+
type: "plan_update",
|
|
662
|
+
title: planTitle
|
|
663
|
+
});
|
|
664
|
+
}
|
|
687
665
|
for (const chunk of params.chunks ?? []) {
|
|
688
666
|
if (chunk.type === "plan_update") {
|
|
689
667
|
if (chunk.title !== planTitle) {
|
|
@@ -795,12 +773,6 @@ function isSlackProgressTitleText(text, snapshot, explicitTitle) {
|
|
|
795
773
|
}
|
|
796
774
|
//#endregion
|
|
797
775
|
//#region extensions/slack/src/monitor/message-handler/preview-finalize.ts
|
|
798
|
-
function buildExpectedSlackEditText(params) {
|
|
799
|
-
const trimmedText = params.text.trim();
|
|
800
|
-
if (trimmedText) return normalizeSlackOutboundText(trimmedText);
|
|
801
|
-
if (params.blocks?.length) return normalizeSlackOutboundText(buildSlackBlocksFallbackText(params.blocks));
|
|
802
|
-
return " ";
|
|
803
|
-
}
|
|
804
776
|
function blocksMatch(expected, actual) {
|
|
805
777
|
if (!expected?.length) return !actual?.length;
|
|
806
778
|
if (!actual?.length) {
|
|
@@ -820,45 +792,6 @@ function blocksMatch(expected, actual) {
|
|
|
820
792
|
return false;
|
|
821
793
|
}
|
|
822
794
|
}
|
|
823
|
-
async function readSlackMessageAfterEditError(params) {
|
|
824
|
-
const query = {
|
|
825
|
-
token: params.token,
|
|
826
|
-
channel: params.channelId,
|
|
827
|
-
latest: params.messageId,
|
|
828
|
-
oldest: params.messageId,
|
|
829
|
-
inclusive: true,
|
|
830
|
-
limit: 1
|
|
831
|
-
};
|
|
832
|
-
const result = params.threadTs ? await params.client.conversations.replies({
|
|
833
|
-
...query,
|
|
834
|
-
ts: params.threadTs
|
|
835
|
-
}) : await params.client.conversations.history(query);
|
|
836
|
-
const message = params.threadTs ? result.messages?.find((entry) => entry?.ts === params.messageId) : result.messages?.[0];
|
|
837
|
-
return message?.ts && message.ts === params.messageId ? message : null;
|
|
838
|
-
}
|
|
839
|
-
async function didSlackPreviewEditApplyAfterError(params) {
|
|
840
|
-
const readback = await readSlackMessageAfterEditError(params);
|
|
841
|
-
if (!readback) return false;
|
|
842
|
-
const expectedText = buildExpectedSlackEditText({
|
|
843
|
-
text: params.text,
|
|
844
|
-
blocks: params.blocks
|
|
845
|
-
});
|
|
846
|
-
const acceptedTexts = /* @__PURE__ */ new Set([
|
|
847
|
-
expectedText,
|
|
848
|
-
normalizeSlackOutboundText(truncateSlackTextByUtf8Bytes(expectedText, SLACK_EDIT_TEXT_MAX_BYTES)),
|
|
849
|
-
normalizeSlackOutboundText(buildSlackEditTextPayload(params.text, params.blocks))
|
|
850
|
-
]);
|
|
851
|
-
if (params.blocks?.length && hasSlackNativeDataBlock(params.blocks)) {
|
|
852
|
-
const fallbackPlan = buildSlackNativeDataDeliveryPlan({
|
|
853
|
-
baseText: params.text,
|
|
854
|
-
blocks: params.blocks
|
|
855
|
-
});
|
|
856
|
-
for (const message of fallbackPlan.fallbackMessages) acceptedTexts.add(normalizeSlackOutboundText(message.text));
|
|
857
|
-
}
|
|
858
|
-
const actualText = normalizeSlackOutboundText((readback.text ?? "").trim());
|
|
859
|
-
if (params.blocks?.length) return acceptedTexts.has(actualText) && blocksMatch(params.blocks, readback.blocks);
|
|
860
|
-
return actualText === expectedText;
|
|
861
|
-
}
|
|
862
795
|
async function finalizeSlackPreviewEdit(params) {
|
|
863
796
|
try {
|
|
864
797
|
await editSlackRenderedMessage(params.channelId, params.messageId, params.text, {
|
|
@@ -869,9 +802,40 @@ async function finalizeSlackPreviewEdit(params) {
|
|
|
869
802
|
});
|
|
870
803
|
} catch (err) {
|
|
871
804
|
try {
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
805
|
+
const query = {
|
|
806
|
+
token: params.token,
|
|
807
|
+
channel: params.channelId,
|
|
808
|
+
latest: params.messageId,
|
|
809
|
+
oldest: params.messageId,
|
|
810
|
+
inclusive: true,
|
|
811
|
+
limit: 1
|
|
812
|
+
};
|
|
813
|
+
const result = params.threadTs ? await params.client.conversations.replies({
|
|
814
|
+
...query,
|
|
815
|
+
ts: params.threadTs
|
|
816
|
+
}) : await params.client.conversations.history(query);
|
|
817
|
+
const message = params.threadTs ? result.messages?.find((entry) => entry?.ts === params.messageId) : result.messages?.[0];
|
|
818
|
+
const readback = message?.ts && message.ts === params.messageId ? message : null;
|
|
819
|
+
if (readback) {
|
|
820
|
+
const trimmedText = params.text.trim();
|
|
821
|
+
const expectedText = trimmedText ? normalizeSlackOutboundText(trimmedText) : params.blocks?.length ? normalizeSlackOutboundText(buildSlackBlocksFallbackText(params.blocks)) : " ";
|
|
822
|
+
const acceptedTexts = /* @__PURE__ */ new Set([
|
|
823
|
+
expectedText,
|
|
824
|
+
normalizeSlackOutboundText(truncateSlackTextByUtf8Bytes(expectedText, SLACK_EDIT_TEXT_MAX_BYTES)),
|
|
825
|
+
normalizeSlackOutboundText(buildSlackEditTextPayload(params.text, params.blocks))
|
|
826
|
+
]);
|
|
827
|
+
if (params.blocks?.length && hasSlackNativeDataBlock(params.blocks)) {
|
|
828
|
+
const fallbackPlan = buildSlackNativeDataDeliveryPlan({
|
|
829
|
+
baseText: params.text,
|
|
830
|
+
blocks: params.blocks
|
|
831
|
+
});
|
|
832
|
+
for (const fallbackMessage of fallbackPlan.fallbackMessages) acceptedTexts.add(normalizeSlackOutboundText(fallbackMessage.text));
|
|
833
|
+
}
|
|
834
|
+
const actualText = normalizeSlackOutboundText((readback.text ?? "").trim());
|
|
835
|
+
if (params.blocks?.length ? acceptedTexts.has(actualText) && blocksMatch(params.blocks, readback.blocks) : actualText === expectedText) {
|
|
836
|
+
logVerbose(`slack: preview final edit response failed but readback matched message ${params.channelId}/${params.messageId}; suppressing duplicate fallback send`);
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
875
839
|
}
|
|
876
840
|
} catch (readbackErr) {
|
|
877
841
|
logVerbose(`slack: preview final edit readback failed (${String(readbackErr)})`);
|
|
@@ -1049,7 +1013,7 @@ function createSlackNativeProgressTransport(params) {
|
|
|
1049
1013
|
const delivered = markDelivered(streamThreadTs);
|
|
1050
1014
|
return update.chunks?.length ? delivered : true;
|
|
1051
1015
|
} finally {
|
|
1052
|
-
|
|
1016
|
+
delivery.nativeProgressStreamStartPromise = null;
|
|
1053
1017
|
}
|
|
1054
1018
|
};
|
|
1055
1019
|
const append = async (update) => {
|
|
@@ -1081,7 +1045,6 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1081
1045
|
cfg,
|
|
1082
1046
|
token: ctx.botToken,
|
|
1083
1047
|
accountId: account.accountId,
|
|
1084
|
-
conversationChannelId: message.channel,
|
|
1085
1048
|
eventScope: prepared.eventScope,
|
|
1086
1049
|
...!hasSlackCustomIdentity && slackIdentity ? { identity: slackIdentity } : {},
|
|
1087
1050
|
...slackMessageMetadata ? { metadata: slackMessageMetadata } : {},
|
|
@@ -1091,7 +1054,6 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1091
1054
|
if (ts) delivery.usedReplyThreadTs ??= ts;
|
|
1092
1055
|
return ts;
|
|
1093
1056
|
},
|
|
1094
|
-
log: logVerbose,
|
|
1095
1057
|
warn: logVerbose
|
|
1096
1058
|
}) : void 0;
|
|
1097
1059
|
const isProgressMode = slackStreaming.mode === "progress";
|
|
@@ -1510,7 +1472,6 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1510
1472
|
return {
|
|
1511
1473
|
draftStream,
|
|
1512
1474
|
previewLifecycle,
|
|
1513
|
-
isProgressMode,
|
|
1514
1475
|
useDraftProgressCard,
|
|
1515
1476
|
useNativeProgressStreaming,
|
|
1516
1477
|
progressDraftActive,
|
|
@@ -1703,9 +1664,7 @@ async function createSlackDispatchSetup(prepared) {
|
|
|
1703
1664
|
status: "active",
|
|
1704
1665
|
eventScope: prepared.eventScope
|
|
1705
1666
|
});
|
|
1706
|
-
if (reportFailure && !restored)
|
|
1707
|
-
runtime.error?.("Slack session status could not return to active after processing. Enable verbose logging to inspect the Slack API failure.");
|
|
1708
|
-
} catch {}
|
|
1667
|
+
if (reportFailure && !restored) runtime.error?.("Slack session status could not return to active after processing. Enable verbose logging to inspect the Slack API failure.");
|
|
1709
1668
|
}
|
|
1710
1669
|
if (didAddTypingReaction && typingReaction && message.ts) {
|
|
1711
1670
|
didAddTypingReaction = false;
|
|
@@ -1770,6 +1729,10 @@ async function createSlackDispatchSetup(prepared) {
|
|
|
1770
1729
|
function createSlackStreamingDeliveryRuntime(setup) {
|
|
1771
1730
|
const { isThreadReply, messageSentHookContext, messageSentHookTarget, prepared, replyDeliveryMode, replyPlan, runtime, slackClient, slackClientOptions, slackIdentity, slackStreamFallbackTeamId } = setup;
|
|
1772
1731
|
const { account, ctx, forcedReplyThreadTs, message, slackMessageMetadata } = prepared;
|
|
1732
|
+
const markdownOptions = resolveSlackMarkdownOptions({
|
|
1733
|
+
cfg: ctx.cfg,
|
|
1734
|
+
accountId: account.accountId
|
|
1735
|
+
});
|
|
1773
1736
|
const state = {
|
|
1774
1737
|
streamSession: null,
|
|
1775
1738
|
streamBoundary: null,
|
|
@@ -1850,7 +1813,7 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1850
1813
|
if (key) deliveredKeys.add(key);
|
|
1851
1814
|
};
|
|
1852
1815
|
const markPreviewPayloadDelivered = (params) => {
|
|
1853
|
-
const preparedReply = prepareSlackReply(params.payload);
|
|
1816
|
+
const preparedReply = prepareSlackReply(params.payload, markdownOptions);
|
|
1854
1817
|
markDelivered(buildSlackEventDeliveryKey(params, preparedReply));
|
|
1855
1818
|
const nextThreadTs = replyPlan.peekThreadTs();
|
|
1856
1819
|
if (nextThreadTs !== params.threadTs) markDelivered(buildSlackEventDeliveryKey({
|
|
@@ -1891,7 +1854,7 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1891
1854
|
}
|
|
1892
1855
|
const fallbackText = fallbackError.pendingText.trim();
|
|
1893
1856
|
if (!fallbackText) return;
|
|
1894
|
-
const sent = await deliverPreparedReply(prepareSlackReply({ text: fallbackText }), session.threadTs, true);
|
|
1857
|
+
const sent = await deliverPreparedReply(prepareSlackReply({ text: fallbackText }, markdownOptions), session.threadTs, true);
|
|
1895
1858
|
if (!sent?.receipt.platformMessageIds.length) return;
|
|
1896
1859
|
markSlackStreamFallbackDelivered(session);
|
|
1897
1860
|
if (!session.stopped) try {
|
|
@@ -1949,16 +1912,13 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1949
1912
|
if (state.streamSession?.stoppedBySlack) return { visibleReplySent: false };
|
|
1950
1913
|
const replyThreadTs = params.forcedThreadTs ?? state.interruptedThreadTs ?? resolveDeliveryThreadTs(params);
|
|
1951
1914
|
const deliveryReplyThreadTs = replyDeliveryMode === "off" && !forcedReplyThreadTs && !isThreadReply ? void 0 : replyThreadTs;
|
|
1952
|
-
const preparedReply = prepareSlackReply(params.payload);
|
|
1915
|
+
const preparedReply = prepareSlackReply(params.payload, markdownOptions);
|
|
1953
1916
|
const deliveryKey = buildSlackEventDeliveryKey({
|
|
1954
1917
|
kind: params.kind,
|
|
1955
1918
|
payload: params.payload,
|
|
1956
1919
|
threadTs: deliveryReplyThreadTs
|
|
1957
1920
|
}, preparedReply);
|
|
1958
|
-
if (deliveryKey && deliveredKeys.has(deliveryKey)) {
|
|
1959
|
-
logVerbose("slack: suppressed duplicate normal delivery within the same turn");
|
|
1960
|
-
return { visibleReplySent: false };
|
|
1961
|
-
}
|
|
1921
|
+
if (deliveryKey && deliveredKeys.has(deliveryKey)) return { visibleReplySent: false };
|
|
1962
1922
|
const sent = await deliverPreparedReply(preparedReply, deliveryReplyThreadTs);
|
|
1963
1923
|
if (!sent?.receipt.platformMessageIds.length) return { visibleReplySent: false };
|
|
1964
1924
|
state.observedReplyDelivery = true;
|
|
@@ -1980,9 +1940,16 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1980
1940
|
};
|
|
1981
1941
|
const isStreamingEligible = (payload, options) => {
|
|
1982
1942
|
const reply = resolveSendableOutboundReplyParts(payload);
|
|
1983
|
-
const renderPlan = resolveSlackReplyRenderPlan(payload);
|
|
1943
|
+
const renderPlan = resolveSlackReplyRenderPlan(payload, payload.text, markdownOptions);
|
|
1984
1944
|
const plannedBlocks = renderPlan.mode === "single" ? renderPlan.blocks : renderPlan.blockPart?.blocks;
|
|
1985
|
-
|
|
1945
|
+
const previewThreadTs = state.streamSession?.threadTs ?? state.interruptedThreadTs ?? state.nativeProgressStreamThreadTs;
|
|
1946
|
+
const finalThreadTs = resolveSlackReplyThreadTs({
|
|
1947
|
+
replyToMode: replyDeliveryMode,
|
|
1948
|
+
replyToId: payload.replyToId,
|
|
1949
|
+
threadId: previewThreadTs,
|
|
1950
|
+
replyToCurrent: payload.replyToCurrent
|
|
1951
|
+
});
|
|
1952
|
+
return !state.streamFailed && (!previewThreadTs || finalThreadTs === previewThreadTs) && !reply.hasMedia && renderPlan.mode !== "split" && !renderPlan.textIsSlackPlainText && !plannedBlocks?.length && !resolveSlackReplyBlocks(payload)?.length && reply.hasText && (!options?.maxTextBytes || countSlackTextUtf8Bytes(reply.trimmedText) <= options.maxTextBytes);
|
|
1986
1953
|
};
|
|
1987
1954
|
const deliverWithStreaming = async (params) => {
|
|
1988
1955
|
if (state.streamSession?.stoppedBySlack) return { visibleReplySent: false };
|
|
@@ -1995,7 +1962,12 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1995
1962
|
await rotateInterruptedStream();
|
|
1996
1963
|
if (state.streamSession?.stoppedBySlack) return { visibleReplySent: false };
|
|
1997
1964
|
let session = state.streamSession;
|
|
1998
|
-
const threadTs =
|
|
1965
|
+
const threadTs = resolveSlackReplyThreadTs({
|
|
1966
|
+
replyToMode: replyDeliveryMode,
|
|
1967
|
+
replyToId: params.payload.replyToId,
|
|
1968
|
+
threadId: session?.threadTs ?? state.interruptedThreadTs ?? replyPlan.nextThreadTs(),
|
|
1969
|
+
replyToCurrent: params.payload.replyToCurrent
|
|
1970
|
+
});
|
|
1999
1971
|
if (state.streamFailed || !threadTs) {
|
|
2000
1972
|
state.streamFailed = true;
|
|
2001
1973
|
return await deliverNormally({
|
|
@@ -2010,11 +1982,8 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
2010
1982
|
...params,
|
|
2011
1983
|
threadTs,
|
|
2012
1984
|
textOverride: text
|
|
2013
|
-
});
|
|
2014
|
-
if (deliveryKey && deliveredKeys.has(deliveryKey)) {
|
|
2015
|
-
logVerbose("slack-stream: suppressed duplicate reply payload");
|
|
2016
|
-
return { visibleReplySent: false };
|
|
2017
|
-
}
|
|
1985
|
+
}, prepareSlackReply(params.payload, markdownOptions));
|
|
1986
|
+
if (deliveryKey && deliveredKeys.has(deliveryKey)) return { visibleReplySent: false };
|
|
2018
1987
|
let messageId;
|
|
2019
1988
|
let fallbackDelivery;
|
|
2020
1989
|
try {
|
|
@@ -2096,6 +2065,75 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
2096
2065
|
});
|
|
2097
2066
|
}
|
|
2098
2067
|
//#endregion
|
|
2068
|
+
//#region extensions/slack/src/monitor/message-handler/failure-notice.ts
|
|
2069
|
+
/** One outage policy for immediate replies and later origin-routed queue drains. */
|
|
2070
|
+
function createSlackFailureNoticePolicy(params, hasVisibleReply) {
|
|
2071
|
+
const { context, accountId, channelId, failureNoticeThreadTs, failureNoticeTeamId, statusThreadTs } = params;
|
|
2072
|
+
let sawTerminalFailurePayload = false;
|
|
2073
|
+
let pendingFailureNotice;
|
|
2074
|
+
const filterPassiveThreadFailure = (payload) => {
|
|
2075
|
+
if (payload.isError !== true || context.ChatType !== "channel" || isReplyPayloadNonTerminalToolErrorWarning(payload)) return payload;
|
|
2076
|
+
sawTerminalFailurePayload = true;
|
|
2077
|
+
if (hasVisibleReply()) return payload;
|
|
2078
|
+
const explicitlyAddressed = context.ExplicitlyMentionedBot === true || context.MentionSource === "explicit_bot" || context.MentionSource === "subteam" || context.MentionSource === "mention_pattern" || context.MentionSource === "command_bypass" || context.CommandTurn?.kind !== void 0 && context.CommandTurn.kind !== "normal" && context.CommandTurn.authorized;
|
|
2079
|
+
const noticeThreadTs = failureNoticeThreadTs ?? (explicitlyAddressed ? statusThreadTs : void 0);
|
|
2080
|
+
const notice = {
|
|
2081
|
+
accountId,
|
|
2082
|
+
channelId,
|
|
2083
|
+
...noticeThreadTs ? { threadTs: noticeThreadTs } : {},
|
|
2084
|
+
failureText: payload.text ?? "",
|
|
2085
|
+
...failureNoticeTeamId ? { teamId: failureNoticeTeamId } : {}
|
|
2086
|
+
};
|
|
2087
|
+
if (failureNoticeThreadTs && !explicitlyAddressed && context.MentionSource !== "implicit_thread" && !hasSlackThreadParticipation(notice.accountId, notice.channelId, failureNoticeThreadTs, failureNoticeTeamId)) {
|
|
2088
|
+
logVerbose("slack: suppressed passive failure before thread participation");
|
|
2089
|
+
return null;
|
|
2090
|
+
}
|
|
2091
|
+
if (!explicitlyAddressed && hasSlackThreadFailureNotice(notice)) {
|
|
2092
|
+
logVerbose("slack: suppressed repeated passive channel or thread failure");
|
|
2093
|
+
return null;
|
|
2094
|
+
}
|
|
2095
|
+
pendingFailureNotice = notice;
|
|
2096
|
+
return payload;
|
|
2097
|
+
};
|
|
2098
|
+
return {
|
|
2099
|
+
filter: filterPassiveThreadFailure,
|
|
2100
|
+
recordDelivered(payload) {
|
|
2101
|
+
if (pendingFailureNotice && (!payload || payload.isError === true && !isReplyPayloadNonTerminalToolErrorWarning(payload) && (payload.text ?? "") === pendingFailureNotice.failureText)) {
|
|
2102
|
+
recordSlackThreadFailureNotice(pendingFailureNotice);
|
|
2103
|
+
pendingFailureNotice = void 0;
|
|
2104
|
+
}
|
|
2105
|
+
},
|
|
2106
|
+
complete() {
|
|
2107
|
+
if (!sawTerminalFailurePayload && context.ChatType === "channel") clearSlackThreadFailureNotice({
|
|
2108
|
+
accountId,
|
|
2109
|
+
channelId,
|
|
2110
|
+
...failureNoticeThreadTs ? { threadTs: failureNoticeThreadTs } : {},
|
|
2111
|
+
...failureNoticeTeamId ? { teamId: failureNoticeTeamId } : {}
|
|
2112
|
+
});
|
|
2113
|
+
}
|
|
2114
|
+
};
|
|
2115
|
+
}
|
|
2116
|
+
function createSlackQueuedFailureNoticePolicy(params, beginSessionRun) {
|
|
2117
|
+
let visibleReplySent = false;
|
|
2118
|
+
let policy = createSlackFailureNoticePolicy(params, () => visibleReplySent);
|
|
2119
|
+
return {
|
|
2120
|
+
begin() {
|
|
2121
|
+
visibleReplySent = false;
|
|
2122
|
+
policy = createSlackFailureNoticePolicy(params, () => visibleReplySent);
|
|
2123
|
+
const release = beginSessionRun();
|
|
2124
|
+
return (settlement) => {
|
|
2125
|
+
if (settlement?.completed && !settlement.failed && !settlement.transportPending) policy.complete();
|
|
2126
|
+
release();
|
|
2127
|
+
};
|
|
2128
|
+
},
|
|
2129
|
+
shouldSuppressReply: (payload) => policy.filter(payload) === null,
|
|
2130
|
+
onReplyDelivered(payload) {
|
|
2131
|
+
policy.recordDelivered(payload);
|
|
2132
|
+
visibleReplySent = true;
|
|
2133
|
+
}
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
2136
|
+
//#endregion
|
|
2099
2137
|
//#region extensions/slack/src/monitor/message-handler/dispatch.ts
|
|
2100
2138
|
function formatSlackGroupThreadReply(text, participant) {
|
|
2101
2139
|
return `**${participant.name.replace(/[\\`*_{}[\]()<>#!|]/g, "\\$&").replace(/\s+/g, " ")}**\n${text}`;
|
|
@@ -2121,7 +2159,7 @@ async function dispatchPreparedSlackMessage(prepared) {
|
|
|
2121
2159
|
},
|
|
2122
2160
|
onSettled: () => {
|
|
2123
2161
|
releaseDeferred?.();
|
|
2124
|
-
upstreamLifecycle.onSettled?.();
|
|
2162
|
+
return upstreamLifecycle.onSettled?.();
|
|
2125
2163
|
}
|
|
2126
2164
|
};
|
|
2127
2165
|
const release = beginSessionRun();
|
|
@@ -2130,6 +2168,10 @@ async function dispatchPreparedSlackMessage(prepared) {
|
|
|
2130
2168
|
async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptionLifecycle) {
|
|
2131
2169
|
const { prepared } = setup;
|
|
2132
2170
|
const { account, ctx, message, route } = prepared;
|
|
2171
|
+
const markdownOptions = resolveSlackMarkdownOptions({
|
|
2172
|
+
cfg: ctx.cfg,
|
|
2173
|
+
accountId: account.accountId
|
|
2174
|
+
});
|
|
2133
2175
|
const { cfg, disableBlockStreaming, hasSlackCustomIdentity, hasRepliedRef, messageSentHookContext, messageSentHookTarget, onModelSelected, previewStreamingEnabled, replyPipeline, replyPlan, runtime, slackClient, slackStreaming, sourceReplyDeliveryMode, statusReactions, statusReactionsEnabled, statusThreadTs, suppressRoomEventTyping, useStreaming } = setup;
|
|
2134
2176
|
let dispatchError;
|
|
2135
2177
|
const delivery = createSlackStreamingDeliveryRuntime(setup);
|
|
@@ -2141,41 +2183,22 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2141
2183
|
let turnCommentaryVisible = false;
|
|
2142
2184
|
const { draftStream, previewLifecycle } = progress;
|
|
2143
2185
|
setup.threadStatusGate.hasVisibleOutput = () => delivery.observedReplyDelivery || previewLifecycle.previewFinalized || Boolean(draftStream?.messageId());
|
|
2144
|
-
const
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
if (delivery.observedReplyDelivery || previewLifecycle.previewFinalized) return payload;
|
|
2152
|
-
const explicitlyAddressed = prepared.ctxPayload.ExplicitlyMentionedBot === true || prepared.ctxPayload.MentionSource === "explicit_bot" || prepared.ctxPayload.MentionSource === "subteam" || prepared.ctxPayload.MentionSource === "mention_pattern" || prepared.ctxPayload.MentionSource === "command_bypass" || prepared.ctxPayload.CommandTurn?.kind !== void 0 && prepared.ctxPayload.CommandTurn.kind !== "normal" && prepared.ctxPayload.CommandTurn.authorized;
|
|
2153
|
-
const noticeThreadTs = failureNoticeThreadTs ?? (explicitlyAddressed ? statusThreadTs : void 0);
|
|
2154
|
-
const notice = {
|
|
2155
|
-
accountId: account.accountId,
|
|
2156
|
-
channelId: message.channel,
|
|
2157
|
-
...noticeThreadTs ? { threadTs: noticeThreadTs } : {},
|
|
2158
|
-
failureText: payload.text ?? "",
|
|
2159
|
-
...failureNoticeTeamId ? { teamId: failureNoticeTeamId } : {}
|
|
2160
|
-
};
|
|
2161
|
-
if (failureNoticeThreadTs && !explicitlyAddressed && prepared.ctxPayload.MentionSource !== "implicit_thread" && !hasSlackThreadParticipation(notice.accountId, notice.channelId, failureNoticeThreadTs, failureNoticeTeamId)) {
|
|
2162
|
-
logVerbose("slack: suppressed passive failure before thread participation");
|
|
2163
|
-
return null;
|
|
2164
|
-
}
|
|
2165
|
-
if (!explicitlyAddressed && hasSlackThreadFailureNotice(notice)) {
|
|
2166
|
-
logVerbose("slack: suppressed repeated passive channel or thread failure");
|
|
2167
|
-
return null;
|
|
2168
|
-
}
|
|
2169
|
-
pendingFailureNotice = notice;
|
|
2170
|
-
return payload;
|
|
2186
|
+
const failurePolicyParams = {
|
|
2187
|
+
context: prepared.ctxPayload,
|
|
2188
|
+
accountId: account.accountId,
|
|
2189
|
+
channelId: message.channel,
|
|
2190
|
+
failureNoticeThreadTs: message.thread_ts,
|
|
2191
|
+
failureNoticeTeamId: prepared.eventScope?.teamId,
|
|
2192
|
+
statusThreadTs
|
|
2171
2193
|
};
|
|
2194
|
+
const failurePolicy = createSlackFailureNoticePolicy(failurePolicyParams, () => delivery.observedReplyDelivery || previewLifecycle.previewFinalized);
|
|
2172
2195
|
const deliverSlackPayload = async (incomingPayload, info) => {
|
|
2173
2196
|
let payload = incomingPayload;
|
|
2174
2197
|
if (info.participant && (payload.text || payload.mediaUrl || payload.mediaUrls?.length)) payload = {
|
|
2175
2198
|
...payload,
|
|
2176
2199
|
text: formatSlackGroupThreadReply(payload.text ?? "", info.participant)
|
|
2177
2200
|
};
|
|
2178
|
-
if (info.kind === "final" && slackStreaming.mode === "progress"
|
|
2201
|
+
if (info.kind === "final" && slackStreaming.mode === "progress") {
|
|
2179
2202
|
const supplement = getReplyPayloadTtsSupplement(payload);
|
|
2180
2203
|
const finalPayload = !progress.useDraftProgressCard && !progress.useNativeProgressStreaming && supplement && !supplement.visibleTextAlreadyDelivered && !payload.text?.trim() ? {
|
|
2181
2204
|
...payload,
|
|
@@ -2215,15 +2238,11 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2215
2238
|
const reply = resolveSendableOutboundReplyParts(payload);
|
|
2216
2239
|
const ttsSupplement = getReplyPayloadTtsSupplement(payload);
|
|
2217
2240
|
const replySourceText = payload.text ?? ttsSupplement?.spokenText;
|
|
2218
|
-
const replyRenderPlan = resolveSlackReplyRenderPlan(payload, replySourceText);
|
|
2241
|
+
const replyRenderPlan = resolveSlackReplyRenderPlan(payload, replySourceText, markdownOptions);
|
|
2219
2242
|
const slackBlocks = replyRenderPlan.mode === "single" ? replyRenderPlan.blocks : replyRenderPlan.blockPart?.blocks;
|
|
2220
2243
|
const requiresSeparateFallbackDelivery = replyRenderPlan.mode === "split" || replyRenderPlan.textIsSlackPlainText === true;
|
|
2221
2244
|
const trimmedFinalText = replyRenderPlan.mode === "single" ? replyRenderPlan.text.trim() : replyRenderPlan.fallbackText.trim();
|
|
2222
|
-
const previewFinalText = replyRenderPlan.mode === "single" && replyRenderPlan.textIsSlackMrkdwn ? trimmedFinalText : normalizeSlackOutboundText((replySourceText ?? "").trim(),
|
|
2223
|
-
cfg,
|
|
2224
|
-
channel: "slack",
|
|
2225
|
-
accountId: account.accountId
|
|
2226
|
-
}) });
|
|
2245
|
+
const previewFinalText = replyRenderPlan.mode === "single" && replyRenderPlan.textIsSlackMrkdwn ? trimmedFinalText : normalizeSlackOutboundText((replySourceText ?? "").trim(), markdownOptions);
|
|
2227
2246
|
const previewFinalTextFitsEdit = countSlackTextUtf8Bytes(previewFinalText) <= SLACK_EDIT_TEXT_MAX_BYTES;
|
|
2228
2247
|
const shouldRestoreTtsSupplementTextForPreviewFallback = Boolean(ttsSupplement) && ttsSupplement?.visibleTextAlreadyDelivered !== true && Boolean(draftStream) && !previewLifecycle.previewFinalized && !previewLifecycle.finalDelivered && previewStreamingEnabled && !payload.text?.trim();
|
|
2229
2248
|
let ttsPreviewFinalization;
|
|
@@ -2233,11 +2252,18 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2233
2252
|
isError: payload.isError === true,
|
|
2234
2253
|
adapter: {
|
|
2235
2254
|
buildFinalEdit: () => {
|
|
2236
|
-
|
|
2255
|
+
const threadTs = delivery.usedReplyThreadTs ?? statusThreadTs;
|
|
2256
|
+
const finalThreadTs = resolveSlackReplyThreadTs({
|
|
2257
|
+
replyToMode: setup.replyDeliveryMode,
|
|
2258
|
+
replyToId: payload.replyToId,
|
|
2259
|
+
threadId: threadTs,
|
|
2260
|
+
replyToCurrent: payload.replyToCurrent
|
|
2261
|
+
});
|
|
2262
|
+
if (hasSlackCustomIdentity || finalThreadTs !== threadTs || !previewStreamingEnabled || reply.hasMedia && !ttsSupplement || payload.isError || requiresSeparateFallbackDelivery || !previewFinalTextFitsEdit || trimmedFinalText.length === 0 && !slackBlocks?.length) return;
|
|
2237
2263
|
return {
|
|
2238
2264
|
text: previewFinalText,
|
|
2239
2265
|
blocks: slackBlocks,
|
|
2240
|
-
threadTs
|
|
2266
|
+
threadTs
|
|
2241
2267
|
};
|
|
2242
2268
|
},
|
|
2243
2269
|
editFinal: async (preview, edit) => {
|
|
@@ -2332,7 +2358,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2332
2358
|
...replyPipeline,
|
|
2333
2359
|
transformReplyPayload: (payload) => {
|
|
2334
2360
|
const transformed = replyPipeline.transformReplyPayload ? replyPipeline.transformReplyPayload(payload) : payload;
|
|
2335
|
-
return transformed ?
|
|
2361
|
+
return transformed ? failurePolicy.filter(transformed) : null;
|
|
2336
2362
|
},
|
|
2337
2363
|
humanDelay: resolveHumanDelayConfig(cfg, route.agentId)
|
|
2338
2364
|
},
|
|
@@ -2349,7 +2375,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2349
2375
|
replyOptions: {
|
|
2350
2376
|
onVisibleWorkSessions: progress.onVisibleWorkSessions,
|
|
2351
2377
|
groupThreadReplyFormatter: formatSlackGroupThreadReply,
|
|
2352
|
-
queuedDeliveryCorrelations: [
|
|
2378
|
+
queuedDeliveryCorrelations: [createSlackQueuedFailureNoticePolicy(failurePolicyParams, beginSessionRun)],
|
|
2353
2379
|
...turnAdoptionLifecycle ? { turnAdoptionLifecycle } : {},
|
|
2354
2380
|
skillFilter: prepared.channelConfig?.skills,
|
|
2355
2381
|
sourceReplyDeliveryMode,
|
|
@@ -2393,7 +2419,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2393
2419
|
if (payload.kind === "preamble" && await shouldYieldDraftProgress()) return false;
|
|
2394
2420
|
if (prepared.turnAdoptionLifecycle?.abortSignal?.aborted) return false;
|
|
2395
2421
|
progress.progressWorkCounter.noteItem(payload);
|
|
2396
|
-
return progress.preambleOnlyProgress && payload.kind !== "preamble" ? await progress.progressDraft.noteActivity() : await progress.progressDraft.pushItemEvent(payload);
|
|
2422
|
+
return progress.preambleOnlyProgress && payload.kind !== "preamble" && payload.kind !== "model-wait" ? await progress.progressDraft.noteActivity() : await progress.progressDraft.pushItemEvent(payload);
|
|
2397
2423
|
},
|
|
2398
2424
|
onPlanUpdate: async (payload) => {
|
|
2399
2425
|
if (payload.phase !== "update") return false;
|
|
@@ -2407,12 +2433,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2407
2433
|
settledDispatchResult = result;
|
|
2408
2434
|
const agentRunOutcome = readAgentRunTerminalOutcome(result);
|
|
2409
2435
|
agentRunFailed = agentRunOutcome === "failed";
|
|
2410
|
-
if (agentRunOutcome === "completed"
|
|
2411
|
-
accountId: account.accountId,
|
|
2412
|
-
channelId: message.channel,
|
|
2413
|
-
...failureNoticeThreadTs ? { threadTs: failureNoticeThreadTs } : {},
|
|
2414
|
-
...failureNoticeTeamId ? { teamId: failureNoticeTeamId } : {}
|
|
2415
|
-
});
|
|
2436
|
+
if (agentRunOutcome === "completed") failurePolicy.complete();
|
|
2416
2437
|
}
|
|
2417
2438
|
} catch (err) {
|
|
2418
2439
|
dispatchError ??= err;
|
|
@@ -2428,7 +2449,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2428
2449
|
if (hasVisibleInboundReplyDispatch(settledDispatchResult)) await previewLifecycle.observeDelivery({ visibleReplySent: true });
|
|
2429
2450
|
}
|
|
2430
2451
|
await previewLifecycle.cleanup({ failed: Boolean(dispatchError || agentRunFailed) });
|
|
2431
|
-
if (
|
|
2452
|
+
if (anyReplyDelivered) failurePolicy.recordDelivered();
|
|
2432
2453
|
if (dispatchError || agentRunFailed) await progress.finalizeDraftProgressCard("error", { postIfMissing: !anyReplyDelivered });
|
|
2433
2454
|
await progress.dropDetachedProgressCards();
|
|
2434
2455
|
if (statusReactionsEnabled) {
|
|
@@ -2448,11 +2469,6 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2448
2469
|
if (dispatchError) throw toErrorObject(dispatchError, "Slack dispatch failed");
|
|
2449
2470
|
if (!anyReplyDelivered && !previewLifecycle.previewFinalized && !(agentRunFailed && progress.useDraftProgressCard)) {
|
|
2450
2471
|
if (progress.useDraftProgressCard) await draftStream?.clear();
|
|
2451
|
-
return;
|
|
2452
|
-
}
|
|
2453
|
-
if (shouldLogVerbose()) {
|
|
2454
|
-
const finalCount = resolveInboundReplyDispatchCounts(settledDispatchResult).final;
|
|
2455
|
-
logVerbose(`slack: delivered ${finalCount} repl${finalCount === 1 ? "y" : "ies"} to ${prepared.replyTarget}`);
|
|
2456
2472
|
}
|
|
2457
2473
|
}
|
|
2458
2474
|
//#endregion
|
|
@@ -2496,13 +2512,12 @@ function normalizeSlackAppContextEntities(value) {
|
|
|
2496
2512
|
}
|
|
2497
2513
|
//#endregion
|
|
2498
2514
|
//#region extensions/slack/src/monitor/thread.ts
|
|
2499
|
-
const
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
}
|
|
2515
|
+
const threadStarterCache = createStaleWhileRevalidateCache({
|
|
2516
|
+
maxEntries: 2e3,
|
|
2517
|
+
maxPending: Number.POSITIVE_INFINITY,
|
|
2518
|
+
ttlMs: 216e5,
|
|
2519
|
+
cacheable: (starter) => starter !== null
|
|
2520
|
+
});
|
|
2506
2521
|
function formatSlackFilePlaceholder(files) {
|
|
2507
2522
|
return `[attached: ${formatSlackFileReferenceList(files)}]`;
|
|
2508
2523
|
}
|
|
@@ -2537,40 +2552,35 @@ function resolveSlackMessageText(message) {
|
|
|
2537
2552
|
}, { preserveMessageTextWhitespace: true });
|
|
2538
2553
|
}
|
|
2539
2554
|
async function resolveSlackThreadStarter(params) {
|
|
2540
|
-
evictThreadStarterCache();
|
|
2541
2555
|
const cacheKey = JSON.stringify([
|
|
2542
2556
|
params.workspaceScope.accountId,
|
|
2543
2557
|
params.workspaceScope.teamId,
|
|
2544
2558
|
params.channelId,
|
|
2545
2559
|
params.threadTs
|
|
2546
2560
|
]);
|
|
2547
|
-
const cached = THREAD_STARTER_CACHE.get(cacheKey);
|
|
2548
|
-
if (cached && !params.refresh) return cached.value;
|
|
2549
|
-
if (params.refresh) THREAD_STARTER_CACHE.delete(cacheKey);
|
|
2550
2561
|
try {
|
|
2551
|
-
const
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2562
|
+
const { value } = await threadStarterCache.read(cacheKey, async () => {
|
|
2563
|
+
const message = (await params.client.conversations.replies({
|
|
2564
|
+
channel: params.channelId,
|
|
2565
|
+
ts: params.threadTs,
|
|
2566
|
+
limit: 1,
|
|
2567
|
+
inclusive: true
|
|
2568
|
+
}))?.messages?.[0];
|
|
2569
|
+
const text = message ? resolveSlackMessageText(message) : void 0;
|
|
2570
|
+
const files = message?.files?.length ? message.files : void 0;
|
|
2571
|
+
if (!message || !text && !files) return null;
|
|
2572
|
+
return {
|
|
2573
|
+
text: text || formatSlackFilePlaceholder(files),
|
|
2574
|
+
userId: message.user,
|
|
2575
|
+
botId: message.bot_id,
|
|
2576
|
+
ts: message.ts,
|
|
2577
|
+
files
|
|
2578
|
+
};
|
|
2579
|
+
}, {
|
|
2580
|
+
allowStale: false,
|
|
2581
|
+
refresh: params.refresh
|
|
2571
2582
|
});
|
|
2572
|
-
|
|
2573
|
-
return starter;
|
|
2583
|
+
return value;
|
|
2574
2584
|
} catch (err) {
|
|
2575
2585
|
logVerbose(`slack thread starter fetch failed channel=${params.channelId} ts=${params.threadTs}: ${formatErrorMessage(err)}`);
|
|
2576
2586
|
return null;
|
|
@@ -2624,8 +2634,7 @@ async function resolveSlackThreadHistory(params) {
|
|
|
2624
2634
|
retained.push([msg, text]);
|
|
2625
2635
|
}
|
|
2626
2636
|
if (retained.length > maxMessages) retained.splice(0, retained.length - maxMessages);
|
|
2627
|
-
|
|
2628
|
-
cursor = typeof next === "string" && next.trim().length > 0 ? next.trim() : void 0;
|
|
2637
|
+
cursor = normalizeOptionalString(response.response_metadata?.next_cursor);
|
|
2629
2638
|
if (response.has_more && !cursor) {
|
|
2630
2639
|
params.onOmission?.("Slack returned an incomplete thread page without a cursor");
|
|
2631
2640
|
return [];
|
|
@@ -2674,7 +2683,7 @@ async function resolveSlackChannelHistory(params) {
|
|
|
2674
2683
|
cursor = response.response_metadata?.next_cursor?.trim() || void 0;
|
|
2675
2684
|
if (!cursor || scanned >= params.limit) break;
|
|
2676
2685
|
}
|
|
2677
|
-
return messages.slice(0, params.limit).
|
|
2686
|
+
return messages.slice(0, params.limit).reverse();
|
|
2678
2687
|
}
|
|
2679
2688
|
//#endregion
|
|
2680
2689
|
//#region extensions/slack/src/monitor/message-handler/preflight-audio.ts
|
|
@@ -2726,7 +2735,7 @@ const SLACK_MENTION_RESOLUTION_CONCURRENCY = 4;
|
|
|
2726
2735
|
const SLACK_MENTION_RESOLUTION_MAX_LOOKUPS_PER_MESSAGE = 20;
|
|
2727
2736
|
const SLACK_USER_MENTION_RE$1 = /<@([A-Z0-9]+)(?:\|[^>]+)?>/gi;
|
|
2728
2737
|
const MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS = 2e3;
|
|
2729
|
-
const loadSlackMediaModule$
|
|
2738
|
+
const loadSlackMediaModule$2 = createLazyRuntimeModule(() => import("./actions-D5S6D_BU.mjs").then((n) => n._));
|
|
2730
2739
|
function formatSlackUnavailableMedia(params) {
|
|
2731
2740
|
let fileReferences = params.files?.map((file) => `${formatSlackFileReference(file)} unavailable (${file.reason})`).join(", ");
|
|
2732
2741
|
if (fileReferences && fileReferences.length > MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS) fileReferences = `${truncateUtf16Safe(fileReferences, MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS)}; … (file references truncated)`;
|
|
@@ -2747,7 +2756,6 @@ function collectUniqueSlackMentionIds(texts) {
|
|
|
2747
2756
|
const seen = /* @__PURE__ */ new Set();
|
|
2748
2757
|
for (const text of texts) {
|
|
2749
2758
|
if (!text) continue;
|
|
2750
|
-
SLACK_USER_MENTION_RE$1.lastIndex = 0;
|
|
2751
2759
|
for (const match of text.matchAll(SLACK_USER_MENTION_RE$1)) {
|
|
2752
2760
|
const userId = match[1];
|
|
2753
2761
|
if (userId) seen.add(userId);
|
|
@@ -2757,35 +2765,24 @@ function collectUniqueSlackMentionIds(texts) {
|
|
|
2757
2765
|
}
|
|
2758
2766
|
function renderSlackUserMentions(text, renderedMentions) {
|
|
2759
2767
|
if (!text || renderedMentions.size === 0) return text;
|
|
2760
|
-
SLACK_USER_MENTION_RE$1.lastIndex = 0;
|
|
2761
2768
|
return text.replace(SLACK_USER_MENTION_RE$1, (full, userId) => {
|
|
2762
2769
|
return renderedMentions.get(userId) ?? full;
|
|
2763
2770
|
});
|
|
2764
2771
|
}
|
|
2765
|
-
function filterInheritedParentFiles(params) {
|
|
2766
|
-
const { files, isThreadReply, threadStarter } = params;
|
|
2767
|
-
if (!isThreadReply || !files?.length || !threadStarter?.files?.length) return files;
|
|
2768
|
-
const starterFileIds = new Set(threadStarter.files.map((file) => file.id));
|
|
2769
|
-
const filtered = files.filter((file) => !file.id || !starterFileIds.has(file.id));
|
|
2770
|
-
if (filtered.length < files.length) logVerbose(`slack: filtered ${files.length - filtered.length} inherited parent file(s) from thread reply`);
|
|
2771
|
-
return filtered.length > 0 ? filtered : void 0;
|
|
2772
|
-
}
|
|
2773
2772
|
async function resolveSlackMessageContent(params) {
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
threadStarter
|
|
2778
|
-
|
|
2779
|
-
|
|
2773
|
+
let ownFiles = params.message.files;
|
|
2774
|
+
const { isThreadReply, threadStarter } = params;
|
|
2775
|
+
if (isThreadReply && ownFiles?.length && threadStarter?.files?.length) {
|
|
2776
|
+
const starterFileIds = new Set(threadStarter.files.map((file) => file.id));
|
|
2777
|
+
const filtered = ownFiles.filter((file) => !file.id || !starterFileIds.has(file.id));
|
|
2778
|
+
ownFiles = filtered.length > 0 ? filtered : void 0;
|
|
2779
|
+
}
|
|
2780
|
+
const attachmentContent = ownFiles?.length || params.message.attachments?.length ? await loadSlackMediaModule$2().then(({ resolveSlackAttachmentContent }) => resolveSlackAttachmentContent({
|
|
2780
2781
|
files: ownFiles,
|
|
2781
2782
|
attachments: params.message.attachments,
|
|
2782
2783
|
client: params.client,
|
|
2783
2784
|
token: params.botToken,
|
|
2784
2785
|
maxBytes: params.mediaMaxBytes,
|
|
2785
|
-
readIdleTimeoutMs: params.mediaReadIdleTimeoutMs,
|
|
2786
|
-
totalTimeoutMs: params.mediaTotalTimeoutMs,
|
|
2787
|
-
abortSignal: params.abortSignal,
|
|
2788
|
-
assertCurrent: params.assertCurrent,
|
|
2789
2786
|
preloadedMedia: params.preloadedMedia
|
|
2790
2787
|
})) : null;
|
|
2791
2788
|
const effectiveDirectMedia = attachmentContent?.media.length ? attachmentContent.media : null;
|
|
@@ -2841,7 +2838,7 @@ function resolveSlackDmHistoryLimit(params) {
|
|
|
2841
2838
|
return resolvePromptHistoryLimit(override ?? params.defaultLimit, 0);
|
|
2842
2839
|
}
|
|
2843
2840
|
async function resolveSlackDmHistoryContext(params) {
|
|
2844
|
-
const maxMessages =
|
|
2841
|
+
const maxMessages = params.limit;
|
|
2845
2842
|
if (maxMessages <= 0) return {
|
|
2846
2843
|
body: void 0,
|
|
2847
2844
|
inboundHistory: void 0
|
|
@@ -2862,7 +2859,7 @@ async function resolveSlackDmHistoryContext(params) {
|
|
|
2862
2859
|
message,
|
|
2863
2860
|
body
|
|
2864
2861
|
}] : [];
|
|
2865
|
-
}).slice(0, maxMessages).
|
|
2862
|
+
}).slice(0, maxMessages).reverse();
|
|
2866
2863
|
if (messages.length === 0) return {
|
|
2867
2864
|
body: void 0,
|
|
2868
2865
|
inboundHistory: void 0
|
|
@@ -2922,6 +2919,7 @@ const SLACK_HISTORY_MEDIA_MAX_ATTACHMENTS = 4;
|
|
|
2922
2919
|
const SLACK_HISTORY_MEDIA_MAX_BYTES = 10485760;
|
|
2923
2920
|
const SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS = 1e3;
|
|
2924
2921
|
const SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS = 3e3;
|
|
2922
|
+
const loadSlackMediaModule$1 = createLazyRuntimeModule(() => import("./actions-D5S6D_BU.mjs").then((n) => n._));
|
|
2925
2923
|
async function resolveSlackRoomHistory(params) {
|
|
2926
2924
|
if (params.ctx.historyLimit <= 0 || !params.message.ts) return [];
|
|
2927
2925
|
const warnOmission = (reason) => {
|
|
@@ -2975,26 +2973,51 @@ async function resolveSlackRoomHistory(params) {
|
|
|
2975
2973
|
sender: user?.name ?? message.userId ?? `Bot (${message.botId ?? "unknown"})`
|
|
2976
2974
|
});
|
|
2977
2975
|
}
|
|
2976
|
+
async function resolveSlackHistoryMedia(message, maxAttachments) {
|
|
2977
|
+
const { ctx, eventScope, assertCurrent, abortSignal } = params;
|
|
2978
|
+
const files = sliceSlackImageFileCandidates(message.files, maxAttachments);
|
|
2979
|
+
const attachments = [];
|
|
2980
|
+
let remaining = Math.max(0, maxAttachments - files.length);
|
|
2981
|
+
if (remaining > 0 && message.attachments?.length) for (const attachment of message.attachments) {
|
|
2982
|
+
if (attachment.is_share !== true) continue;
|
|
2983
|
+
const hasImageUrl = Boolean(normalizeOptionalString(attachment.image_url));
|
|
2984
|
+
const attachmentFiles = sliceSlackImageFileCandidates(attachment.files, remaining - (hasImageUrl ? 1 : 0));
|
|
2985
|
+
if (!hasImageUrl && attachmentFiles.length === 0) continue;
|
|
2986
|
+
attachments.push({
|
|
2987
|
+
...attachment,
|
|
2988
|
+
files: attachmentFiles
|
|
2989
|
+
});
|
|
2990
|
+
remaining -= (hasImageUrl ? 1 : 0) + attachmentFiles.length;
|
|
2991
|
+
if (remaining <= 0) break;
|
|
2992
|
+
}
|
|
2993
|
+
if (files.length === 0 && attachments.length === 0) return {
|
|
2994
|
+
media: [],
|
|
2995
|
+
attempted: 0
|
|
2996
|
+
};
|
|
2997
|
+
const { resolveSlackAttachmentContent } = await loadSlackMediaModule$1();
|
|
2998
|
+
const content = await resolveSlackAttachmentContent({
|
|
2999
|
+
files,
|
|
3000
|
+
attachments,
|
|
3001
|
+
client: eventScope?.client ?? ctx.app.client,
|
|
3002
|
+
token: ctx.botToken,
|
|
3003
|
+
maxBytes: Math.min(ctx.mediaMaxBytes, SLACK_HISTORY_MEDIA_MAX_BYTES),
|
|
3004
|
+
readIdleTimeoutMs: SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS,
|
|
3005
|
+
totalTimeoutMs: SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS,
|
|
3006
|
+
assertCurrent,
|
|
3007
|
+
abortSignal
|
|
3008
|
+
});
|
|
3009
|
+
return {
|
|
3010
|
+
media: await toInboundMediaFactsWithMetadata(content?.media, {
|
|
3011
|
+
kind: "image",
|
|
3012
|
+
messageId: message.ts
|
|
3013
|
+
}),
|
|
3014
|
+
attempted: maxAttachments - remaining
|
|
3015
|
+
};
|
|
3016
|
+
}
|
|
2978
3017
|
const entries = [];
|
|
2979
3018
|
let mediaRemaining = SLACK_HISTORY_MEDIA_MAX_ATTACHMENTS;
|
|
2980
3019
|
for (const { message, sender } of permitted.slice(-params.ctx.historyLimit)) {
|
|
2981
|
-
const { media, attempted } = mediaRemaining > 0 && (message.files?.length || message.attachments?.length) ? await resolveSlackHistoryMedia({
|
|
2982
|
-
ctx: params.ctx,
|
|
2983
|
-
eventScope: params.eventScope,
|
|
2984
|
-
maxAttachments: mediaRemaining,
|
|
2985
|
-
assertCurrent: params.assertCurrent,
|
|
2986
|
-
abortSignal: params.abortSignal,
|
|
2987
|
-
message: {
|
|
2988
|
-
type: "message",
|
|
2989
|
-
channel: params.message.channel,
|
|
2990
|
-
ts: message.ts,
|
|
2991
|
-
user: message.userId,
|
|
2992
|
-
bot_id: message.botId,
|
|
2993
|
-
text: message.text,
|
|
2994
|
-
files: message.files,
|
|
2995
|
-
attachments: message.attachments
|
|
2996
|
-
}
|
|
2997
|
-
}) : {
|
|
3020
|
+
const { media, attempted } = mediaRemaining > 0 && (message.files?.length || message.attachments?.length) ? await resolveSlackHistoryMedia(message, mediaRemaining) : {
|
|
2998
3021
|
media: [],
|
|
2999
3022
|
attempted: 0
|
|
3000
3023
|
};
|
|
@@ -3021,57 +3044,6 @@ function sliceSlackImageFileCandidates(files, limit) {
|
|
|
3021
3044
|
if (limit <= 0 || !files?.length) return [];
|
|
3022
3045
|
return files.filter(isSlackImageFileCandidate).slice(0, limit);
|
|
3023
3046
|
}
|
|
3024
|
-
function sliceSlackHistoryAttachmentCandidates(attachments, limit) {
|
|
3025
|
-
if (limit <= 0 || !attachments?.length) return [];
|
|
3026
|
-
const out = [];
|
|
3027
|
-
let remaining = limit;
|
|
3028
|
-
for (const attachment of attachments) {
|
|
3029
|
-
if (attachment.is_share !== true) continue;
|
|
3030
|
-
const hasImageUrl = Boolean(normalizeOptionalString(attachment.image_url));
|
|
3031
|
-
const files = sliceSlackImageFileCandidates(attachment.files, remaining - (hasImageUrl ? 1 : 0));
|
|
3032
|
-
if (!hasImageUrl && files.length === 0) continue;
|
|
3033
|
-
out.push({
|
|
3034
|
-
...attachment,
|
|
3035
|
-
files
|
|
3036
|
-
});
|
|
3037
|
-
remaining -= (hasImageUrl ? 1 : 0) + files.length;
|
|
3038
|
-
if (remaining <= 0) break;
|
|
3039
|
-
}
|
|
3040
|
-
return out;
|
|
3041
|
-
}
|
|
3042
|
-
async function resolveSlackHistoryMedia(params) {
|
|
3043
|
-
const files = sliceSlackImageFileCandidates(params.message.files, params.maxAttachments);
|
|
3044
|
-
const attachments = sliceSlackHistoryAttachmentCandidates(params.message.attachments, Math.max(0, params.maxAttachments - files.length));
|
|
3045
|
-
if (files.length === 0 && attachments.length === 0) return {
|
|
3046
|
-
media: [],
|
|
3047
|
-
attempted: 0
|
|
3048
|
-
};
|
|
3049
|
-
const attempted = files.length + attachments.reduce((count, attachment) => count + (normalizeOptionalString(attachment.image_url) ? 1 : 0) + (attachment.files?.length ?? 0), 0);
|
|
3050
|
-
const content = await resolveSlackMessageContent({
|
|
3051
|
-
message: {
|
|
3052
|
-
...params.message,
|
|
3053
|
-
files,
|
|
3054
|
-
attachments
|
|
3055
|
-
},
|
|
3056
|
-
isThreadReply: false,
|
|
3057
|
-
threadStarter: null,
|
|
3058
|
-
isBotMessage: Boolean(params.message.bot_id),
|
|
3059
|
-
client: params.eventScope?.client ?? params.ctx.app.client,
|
|
3060
|
-
botToken: params.ctx.botToken,
|
|
3061
|
-
mediaMaxBytes: Math.min(params.ctx.mediaMaxBytes, SLACK_HISTORY_MEDIA_MAX_BYTES),
|
|
3062
|
-
mediaReadIdleTimeoutMs: SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS,
|
|
3063
|
-
mediaTotalTimeoutMs: SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS,
|
|
3064
|
-
assertCurrent: params.assertCurrent,
|
|
3065
|
-
abortSignal: params.abortSignal
|
|
3066
|
-
});
|
|
3067
|
-
return {
|
|
3068
|
-
media: await toInboundMediaFactsWithMetadata(content?.effectiveDirectMedia, {
|
|
3069
|
-
kind: "image",
|
|
3070
|
-
messageId: params.message.ts
|
|
3071
|
-
}),
|
|
3072
|
-
attempted
|
|
3073
|
-
};
|
|
3074
|
-
}
|
|
3075
3047
|
//#endregion
|
|
3076
3048
|
//#region extensions/slack/src/monitor/message-handler/prepare-session-presentation.ts
|
|
3077
3049
|
function resolveSlackGroupSessionSubject(params) {
|
|
@@ -3082,7 +3054,7 @@ function resolveSlackGroupSessionSubject(params) {
|
|
|
3082
3054
|
}
|
|
3083
3055
|
//#endregion
|
|
3084
3056
|
//#region extensions/slack/src/monitor/message-handler/prepare-thread-context.ts
|
|
3085
|
-
const loadSlackMediaModule = createLazyRuntimeModule(() => import("./actions-
|
|
3057
|
+
const loadSlackMediaModule = createLazyRuntimeModule(() => import("./actions-D5S6D_BU.mjs").then((n) => n._));
|
|
3086
3058
|
const SLACK_THREAD_CONTEXT_USER_LOOKUP_CONCURRENCY = 4;
|
|
3087
3059
|
function formatSlackThreadLabelSnippet(text) {
|
|
3088
3060
|
return truncateUtf16Safe(text.replace(/\s+/g, " "), 80);
|
|
@@ -3131,13 +3103,14 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3131
3103
|
const isOutboundOnlyThreadSession = threadSessionFreshness !== void 0 && threadSessionFreshness.state !== "missing" && threadSessionFreshness.entry.lastInteractionAt === void 0 && threadSessionFreshness.entry.updatedAt !== 0;
|
|
3132
3104
|
const shouldSeedInitialThreadContext = Boolean(params.isThreadReply && params.threadTs && (threadSessionFreshness ? threadSessionFreshness.state !== "fresh" || isOutboundOnlyThreadSession : threadSessionPreviousTimestamp === void 0));
|
|
3133
3105
|
const shouldLoadInitialThreadHistory = shouldSeedInitialThreadContext || params.forceInitialHistory === true;
|
|
3134
|
-
|
|
3106
|
+
const readThreadContextData = () => ({
|
|
3135
3107
|
threadStarterBody,
|
|
3136
3108
|
threadHistoryBody,
|
|
3137
3109
|
shouldSeedInitialThreadContext,
|
|
3138
3110
|
threadLabel,
|
|
3139
3111
|
threadStarterMedia
|
|
3140
|
-
};
|
|
3112
|
+
});
|
|
3113
|
+
if (!params.isThreadReply || !params.threadTs) return readThreadContextData();
|
|
3141
3114
|
const starter = params.threadStarter;
|
|
3142
3115
|
const starterSenderName = params.allowNameMatching && params.allowFromLower.length > 0 && starter?.userId ? (await params.ctx.resolveUserName(starter.userId, params.eventScope))?.name : void 0;
|
|
3143
3116
|
params.assertHistoryCurrent?.();
|
|
@@ -3177,10 +3150,6 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3177
3150
|
unavailableMediaCount: attachmentContent.unavailableMediaCount,
|
|
3178
3151
|
prependUnavailable: true
|
|
3179
3152
|
});
|
|
3180
|
-
if (threadStarterMedia) {
|
|
3181
|
-
const starterPlaceholders = threadStarterMedia.map((item) => item.placeholder).join(", ");
|
|
3182
|
-
logVerbose(`slack: hydrated thread starter file ${starterPlaceholders} from root message`);
|
|
3183
|
-
}
|
|
3184
3153
|
}
|
|
3185
3154
|
} else threadLabel = `Slack thread ${params.roomLabel}`;
|
|
3186
3155
|
const includeBotStarterAsRootContext = Boolean(starter?.text && starterIsCurrentBot && shouldSeedInitialThreadContext);
|
|
@@ -3189,7 +3158,6 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3189
3158
|
else if (includeBotStarterAsRootContext) {
|
|
3190
3159
|
const snippet = formatSlackThreadLabelSnippet(starter?.text ?? "").trim();
|
|
3191
3160
|
threadLabel = `Slack thread ${params.roomLabel}${snippet ? ` (assistant root): ${snippet}` : ""}`;
|
|
3192
|
-
logVerbose("slack: retained current-bot thread starter as assistant root context");
|
|
3193
3161
|
}
|
|
3194
3162
|
const threadInitialHistoryLimit = Math.min(params.account.config?.thread?.initialHistoryLimit ?? 20, params.historyLimit ?? Number.POSITIVE_INFINITY);
|
|
3195
3163
|
if (threadInitialHistoryLimit > 0 && shouldLoadInitialThreadHistory) {
|
|
@@ -3214,28 +3182,22 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3214
3182
|
}, "Slack automatic thread history omitted");
|
|
3215
3183
|
}
|
|
3216
3184
|
});
|
|
3217
|
-
if (historyOmitted) return
|
|
3218
|
-
threadStarterBody,
|
|
3219
|
-
threadHistoryBody,
|
|
3220
|
-
shouldSeedInitialThreadContext,
|
|
3221
|
-
threadLabel,
|
|
3222
|
-
threadStarterMedia
|
|
3223
|
-
};
|
|
3185
|
+
if (historyOmitted) return readThreadContextData();
|
|
3224
3186
|
const enrichedStarter = starter && threadStarterBody && threadStarterBody !== starter.text ? {
|
|
3225
3187
|
...starter,
|
|
3226
3188
|
text: threadStarterBody,
|
|
3227
3189
|
ts: currentBotRootTs
|
|
3228
3190
|
} : null;
|
|
3229
|
-
const
|
|
3230
|
-
const threadHistoryWithBotRoot = includeBotStarterAsRootContext && starter && !threadHistoryWithEnrichedRoot.some((entry) => entry.ts === currentBotRootTs) ? [{
|
|
3191
|
+
const rootContext = enrichedStarter ?? (includeBotStarterAsRootContext && starter ? {
|
|
3231
3192
|
...starter,
|
|
3232
3193
|
ts: currentBotRootTs
|
|
3233
|
-
}
|
|
3234
|
-
|
|
3194
|
+
} : null);
|
|
3195
|
+
const threadHistoryWithRoot = rootContext && !threadHistory.some((entry) => entry.ts === currentBotRootTs) ? [rootContext, ...enrichedStarter && threadHistory.length >= threadInitialHistoryLimit ? threadHistory.slice(1) : threadHistory] : threadHistory;
|
|
3196
|
+
if (threadHistoryWithRoot.length > 0) {
|
|
3235
3197
|
const retainCurrentBotHistory = params.isGroupDm && (isMissingThreadSession || isOutboundOnlyThreadSession);
|
|
3236
|
-
const threadHistoryWithoutCurrentBot =
|
|
3237
|
-
const omittedCurrentBotHistoryCount =
|
|
3238
|
-
const userMapForFilter = params.contextVisibilityMode !== "all" && params.allowNameMatching && params.allowFromLower.length > 0 ? await resolveThreadUserMap(threadHistoryWithoutCurrentBot) :
|
|
3198
|
+
const threadHistoryWithoutCurrentBot = threadHistoryWithRoot.filter((entry) => !isCurrentBotAuthor(entry) || retainCurrentBotHistory || includeBotStarterAsRootContext && entry.ts === currentBotRootTs);
|
|
3199
|
+
const omittedCurrentBotHistoryCount = threadHistoryWithRoot.length - threadHistoryWithoutCurrentBot.length;
|
|
3200
|
+
const userMapForFilter = params.contextVisibilityMode !== "all" && params.allowNameMatching && params.allowFromLower.length > 0 ? await resolveThreadUserMap(threadHistoryWithoutCurrentBot) : void 0;
|
|
3239
3201
|
params.assertHistoryCurrent?.();
|
|
3240
3202
|
const { items: filteredThreadHistory, omitted: omittedHistoryCount } = params.contextVisibilityMode === "all" ? {
|
|
3241
3203
|
items: threadHistoryWithoutCurrentBot,
|
|
@@ -3246,7 +3208,7 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3246
3208
|
kind: "thread",
|
|
3247
3209
|
isSenderAllowed: (historyMsg) => {
|
|
3248
3210
|
if (isCurrentBotAuthor(historyMsg)) return true;
|
|
3249
|
-
const msgUser = historyMsg.userId ? userMapForFilter
|
|
3211
|
+
const msgUser = historyMsg.userId ? userMapForFilter?.get(historyMsg.userId) : null;
|
|
3250
3212
|
return resolveSlackUserAllowed({
|
|
3251
3213
|
allowList: params.allowFromLower,
|
|
3252
3214
|
teamId: params.eventScope?.teamId ?? params.ctx.teamId,
|
|
@@ -3256,7 +3218,7 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3256
3218
|
});
|
|
3257
3219
|
}
|
|
3258
3220
|
});
|
|
3259
|
-
const userMap = await resolveThreadUserMap(filteredThreadHistory);
|
|
3221
|
+
const userMap = userMapForFilter ?? await resolveThreadUserMap(filteredThreadHistory);
|
|
3260
3222
|
params.assertHistoryCurrent?.();
|
|
3261
3223
|
if (omittedHistoryCount > 0 || omittedCurrentBotHistoryCount > 0) logVerbose(`slack: omitted ${omittedHistoryCount + omittedCurrentBotHistoryCount} thread message(s) from context (mode=${params.contextVisibilityMode})`);
|
|
3262
3224
|
const historyParts = [];
|
|
@@ -3275,19 +3237,10 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3275
3237
|
envelope: params.envelopeOptions
|
|
3276
3238
|
}));
|
|
3277
3239
|
}
|
|
3278
|
-
if (historyParts.length > 0)
|
|
3279
|
-
threadHistoryBody = historyParts.join("\n\n");
|
|
3280
|
-
logVerbose(`slack: populated thread history with ${filteredThreadHistory.length} messages for new session`);
|
|
3281
|
-
}
|
|
3240
|
+
if (historyParts.length > 0) threadHistoryBody = historyParts.join("\n\n");
|
|
3282
3241
|
}
|
|
3283
3242
|
}
|
|
3284
|
-
return
|
|
3285
|
-
threadStarterBody,
|
|
3286
|
-
threadHistoryBody,
|
|
3287
|
-
shouldSeedInitialThreadContext,
|
|
3288
|
-
threadLabel,
|
|
3289
|
-
threadStarterMedia
|
|
3290
|
-
};
|
|
3243
|
+
return readThreadContextData();
|
|
3291
3244
|
}
|
|
3292
3245
|
//#endregion
|
|
3293
3246
|
//#region src/channels/mention-gating.ts
|
|
@@ -3358,53 +3311,46 @@ function collectSlackMentionIds(text, regex) {
|
|
|
3358
3311
|
}
|
|
3359
3312
|
return [...ids];
|
|
3360
3313
|
}
|
|
3361
|
-
async function readSlackSubteamUsers(params) {
|
|
3362
|
-
let bySubteam = subteamMemberCache.get(params.client);
|
|
3363
|
-
if (!bySubteam) {
|
|
3364
|
-
bySubteam = /* @__PURE__ */ new Map();
|
|
3365
|
-
subteamMemberCache.set(params.client, bySubteam);
|
|
3366
|
-
}
|
|
3367
|
-
const cacheKey = `${normalizeSlackId(params.teamId) ?? ""}:${params.subteamId}`;
|
|
3368
|
-
const cached = bySubteam.get(cacheKey);
|
|
3369
|
-
const now = asDateTimestampMs(params.now);
|
|
3370
|
-
if (cached) {
|
|
3371
|
-
if (now !== void 0 && asDateTimestampMs(cached.expiresAt) !== void 0 && cached.expiresAt > now) return cached.users;
|
|
3372
|
-
bySubteam.delete(cacheKey);
|
|
3373
|
-
}
|
|
3374
|
-
try {
|
|
3375
|
-
const response = await params.client.usergroups.users.list({
|
|
3376
|
-
usergroup: params.subteamId,
|
|
3377
|
-
...params.teamId ? { team_id: params.teamId } : {}
|
|
3378
|
-
});
|
|
3379
|
-
if (!response.ok) {
|
|
3380
|
-
params.log?.(`slack: failed to resolve user-group mention ${params.subteamId}: ${response.error ?? "unknown_error"}`);
|
|
3381
|
-
return /* @__PURE__ */ new Set();
|
|
3382
|
-
}
|
|
3383
|
-
const users = new Set((response.users ?? []).map(normalizeSlackId).filter((userId) => userId !== void 0));
|
|
3384
|
-
const expiresAt = resolveExpiresAtMsFromDurationMs(SUBTEAM_MEMBER_CACHE_TTL_MS, { nowMs: params.now });
|
|
3385
|
-
if (expiresAt !== void 0) bySubteam.set(cacheKey, {
|
|
3386
|
-
expiresAt,
|
|
3387
|
-
users
|
|
3388
|
-
});
|
|
3389
|
-
return users;
|
|
3390
|
-
} catch (err) {
|
|
3391
|
-
params.log?.(`slack: failed to resolve user-group mention ${params.subteamId}: ${formatErrorMessage(err)}`);
|
|
3392
|
-
return /* @__PURE__ */ new Set();
|
|
3393
|
-
}
|
|
3394
|
-
}
|
|
3395
3314
|
async function isSlackSubteamMentionForBot(params) {
|
|
3396
3315
|
const botUserId = normalizeSlackId(params.botUserId);
|
|
3397
3316
|
if (!botUserId) return false;
|
|
3398
3317
|
const subteamIds = collectSlackMentionIds(params.text, SUBTEAM_MENTION_RE);
|
|
3399
3318
|
if (subteamIds.length === 0) return false;
|
|
3400
|
-
const now =
|
|
3401
|
-
for (const subteamId of subteamIds)
|
|
3402
|
-
client
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3319
|
+
const now = Date.now();
|
|
3320
|
+
for (const subteamId of subteamIds) {
|
|
3321
|
+
const { client, log } = params;
|
|
3322
|
+
const teamId = normalizeOptionalString(params.teamId);
|
|
3323
|
+
const bySubteam = getOrCreateWeakOwnerMap(subteamMemberCache, client);
|
|
3324
|
+
const cacheKey = `${normalizeSlackId(teamId) ?? ""}:${subteamId}`;
|
|
3325
|
+
const cached = bySubteam.get(cacheKey);
|
|
3326
|
+
if (cached) {
|
|
3327
|
+
if (cached.expiresAt > now) {
|
|
3328
|
+
if (cached.users.has(botUserId)) return true;
|
|
3329
|
+
continue;
|
|
3330
|
+
}
|
|
3331
|
+
bySubteam.delete(cacheKey);
|
|
3332
|
+
}
|
|
3333
|
+
let users;
|
|
3334
|
+
try {
|
|
3335
|
+
const response = await client.usergroups.users.list({
|
|
3336
|
+
usergroup: subteamId,
|
|
3337
|
+
...teamId ? { team_id: teamId } : {}
|
|
3338
|
+
});
|
|
3339
|
+
if (!response.ok) {
|
|
3340
|
+
log?.(`slack: failed to resolve user-group mention ${subteamId}: ${response.error ?? "unknown_error"}`);
|
|
3341
|
+
continue;
|
|
3342
|
+
}
|
|
3343
|
+
users = new Set((response.users ?? []).map(normalizeSlackId).filter((userId) => userId !== void 0));
|
|
3344
|
+
bySubteam.set(cacheKey, {
|
|
3345
|
+
expiresAt: now + SUBTEAM_MEMBER_CACHE_TTL_MS,
|
|
3346
|
+
users
|
|
3347
|
+
});
|
|
3348
|
+
} catch (err) {
|
|
3349
|
+
log?.(`slack: failed to resolve user-group mention ${subteamId}: ${formatErrorMessage(err)}`);
|
|
3350
|
+
continue;
|
|
3351
|
+
}
|
|
3352
|
+
if (users.has(botUserId)) return true;
|
|
3353
|
+
}
|
|
3408
3354
|
return false;
|
|
3409
3355
|
}
|
|
3410
3356
|
//#endregion
|
|
@@ -3415,18 +3361,6 @@ const SLACK_USER_MENTION_RE = /<@([^>|]+)(?:\|[^>]+)?>/g;
|
|
|
3415
3361
|
const SLACK_SUBTEAM_MENTION_RE = /<!subteam\^([^>|]+)(?:\|[^>]+)?>/g;
|
|
3416
3362
|
const SLACK_SUBTEAM_MENTION_MARKER = "<!subteam^";
|
|
3417
3363
|
const SLACK_CHANNEL_ACCESS_DOCS_URL = "https://docs.openclaw.ai/channels/slack#access-control-and-routing";
|
|
3418
|
-
function mergeSlackAssistantThreadContext(primary, fallback) {
|
|
3419
|
-
if (!primary) return fallback;
|
|
3420
|
-
if (!fallback) return primary;
|
|
3421
|
-
return {
|
|
3422
|
-
assistantChannelId: primary.assistantChannelId || fallback.assistantChannelId,
|
|
3423
|
-
threadTs: primary.threadTs || fallback.threadTs,
|
|
3424
|
-
userId: primary.userId ?? fallback.userId,
|
|
3425
|
-
channelId: primary.channelId ?? fallback.channelId,
|
|
3426
|
-
teamId: primary.teamId ?? fallback.teamId,
|
|
3427
|
-
enterpriseId: primary.enterpriseId !== void 0 ? primary.enterpriseId : fallback.enterpriseId
|
|
3428
|
-
};
|
|
3429
|
-
}
|
|
3430
3364
|
function hasSlackAssistantThreadMetadata(context) {
|
|
3431
3365
|
return Boolean(context?.channelId || context?.teamId || context?.enterpriseId !== void 0);
|
|
3432
3366
|
}
|
|
@@ -3440,7 +3374,6 @@ function resolveSlackMessageAssistantThreadContext(message) {
|
|
|
3440
3374
|
return {
|
|
3441
3375
|
assistantChannelId,
|
|
3442
3376
|
threadTs,
|
|
3443
|
-
userId: normalizeOptionalString(thread.user_id) ?? message.user,
|
|
3444
3377
|
channelId: normalizeOptionalString(context?.channel_id),
|
|
3445
3378
|
teamId: normalizeOptionalString(context?.team_id),
|
|
3446
3379
|
enterpriseId: context?.enterprise_id === null ? null : normalizeOptionalString(context?.enterprise_id)
|
|
@@ -3454,8 +3387,7 @@ async function restoreSlackAssistantThreadContextFromMetadata(params) {
|
|
|
3454
3387
|
return await readSlackAssistantThreadContext({
|
|
3455
3388
|
client: params.eventScope?.client ?? params.ctx.app.client,
|
|
3456
3389
|
channelId: params.message.channel,
|
|
3457
|
-
threadTs
|
|
3458
|
-
userId: params.message.user
|
|
3390
|
+
threadTs
|
|
3459
3391
|
});
|
|
3460
3392
|
} catch (err) {
|
|
3461
3393
|
logVerbose(`slack assistant context restore failed channel=${params.message.channel} ts=${threadTs}: ${formatErrorMessage(err)}`);
|
|
@@ -3468,41 +3400,40 @@ function resolveCachedMentionRegexes(ctx, agentId, options) {
|
|
|
3468
3400
|
normalizeOptionalString(options?.conversationId ?? void 0),
|
|
3469
3401
|
options?.providerPolicy ? JSON.stringify(options.providerPolicy) : ""
|
|
3470
3402
|
].join("");
|
|
3471
|
-
|
|
3472
|
-
if (!byAgent) {
|
|
3473
|
-
byAgent = /* @__PURE__ */ new Map();
|
|
3474
|
-
mentionRegexCache.set(ctx, byAgent);
|
|
3475
|
-
}
|
|
3403
|
+
const byAgent = getOrCreateWeakOwnerMap(mentionRegexCache, ctx);
|
|
3476
3404
|
const cached = byAgent.get(key);
|
|
3477
3405
|
if (cached) return cached;
|
|
3478
3406
|
const built = buildMentionRegexes(ctx.cfg, agentId, options);
|
|
3479
3407
|
byAgent.set(key, built);
|
|
3480
3408
|
return built;
|
|
3481
3409
|
}
|
|
3482
|
-
function
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3410
|
+
async function prepareSlackMessage(params) {
|
|
3411
|
+
const { ctx, account, message, opts } = params;
|
|
3412
|
+
const drop = (reason, parentUserId) => {
|
|
3413
|
+
ctx.logger.info({
|
|
3414
|
+
provider: "slack",
|
|
3415
|
+
accountId: account.accountId,
|
|
3416
|
+
teamId: opts.eventScope?.teamId ?? ctx.teamId,
|
|
3417
|
+
channelId: message.channel,
|
|
3418
|
+
messageTs: message.ts,
|
|
3419
|
+
source: opts.source,
|
|
3420
|
+
reason,
|
|
3421
|
+
...parentUserId ? { parentUserId } : {}
|
|
3422
|
+
}, "Slack inbound event rejected during preparation");
|
|
3423
|
+
return null;
|
|
3424
|
+
};
|
|
3425
|
+
const slackClient = opts.eventScope?.client ?? ctx.app.client;
|
|
3426
|
+
const threadStarterWorkspaceScope = {
|
|
3427
|
+
accountId: account.accountId,
|
|
3428
|
+
teamId: opts.eventScope?.teamId ?? ctx.teamId
|
|
3488
3429
|
};
|
|
3489
|
-
}
|
|
3490
|
-
function resolveSlackMentionSource(params) {
|
|
3491
|
-
if (params.explicitBotMention) return "explicit_bot";
|
|
3492
|
-
if (params.explicitSubteamMention) return "subteam";
|
|
3493
|
-
if (params.shouldBypassMention) return "command_bypass";
|
|
3494
|
-
if (params.wasMentioned) return "mention_pattern";
|
|
3495
|
-
if (params.matchedImplicitMentionKinds.length > 0) return "implicit_thread";
|
|
3496
|
-
return "none";
|
|
3497
|
-
}
|
|
3498
|
-
async function resolveSlackConversationContext(params) {
|
|
3499
|
-
const { ctx, account, message } = params;
|
|
3500
3430
|
const cfg = ctx.cfg;
|
|
3431
|
+
const conversationEventScope = opts.eventScope;
|
|
3501
3432
|
let channelInfo = {};
|
|
3502
3433
|
let resolvedChannelType = normalizeSlackChannelType(message.channel_type, message.channel);
|
|
3503
3434
|
if (resolvedChannelType !== "im" && message.channel_type !== "im") {
|
|
3504
|
-
channelInfo = await ctx.resolveChannelName(message.channel,
|
|
3505
|
-
resolvedChannelType = normalizeSlackChannelType(message.channel_type ?? channelInfo.type ?? ctx.recallSlackChannelType(message.channel,
|
|
3435
|
+
channelInfo = await ctx.resolveChannelName(message.channel, conversationEventScope);
|
|
3436
|
+
resolvedChannelType = normalizeSlackChannelType(message.channel_type ?? channelInfo.type ?? ctx.recallSlackChannelType(message.channel, conversationEventScope), message.channel);
|
|
3506
3437
|
}
|
|
3507
3438
|
const channelName = channelInfo.name;
|
|
3508
3439
|
const isDirectMessage = resolvedChannelType === "im";
|
|
@@ -3510,7 +3441,7 @@ async function resolveSlackConversationContext(params) {
|
|
|
3510
3441
|
const isRoom = resolvedChannelType === "channel" || resolvedChannelType === "group";
|
|
3511
3442
|
const isRoomish = isRoom || isGroupDm;
|
|
3512
3443
|
const channelConfig = isRoom ? resolveSlackChannelConfig({
|
|
3513
|
-
teamId:
|
|
3444
|
+
teamId: conversationEventScope?.teamId ?? ctx.teamId,
|
|
3514
3445
|
allowUnscoped: ctx.installationIdentity?.kind !== "enterprise",
|
|
3515
3446
|
channelId: message.channel,
|
|
3516
3447
|
channelName,
|
|
@@ -3520,22 +3451,19 @@ async function resolveSlackConversationContext(params) {
|
|
|
3520
3451
|
allowNameMatching: ctx.allowNameMatching
|
|
3521
3452
|
}) : null;
|
|
3522
3453
|
const allowBotsSetting = channelConfig?.allowBots ?? account.config?.allowBots ?? cfg.channels?.slack?.allowBots ?? true;
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
channelConfig,
|
|
3532
|
-
allowBotsMode: allowBotsSetting === "mentions" ? "mentions" : allowBotsSetting ? "all" : "off",
|
|
3533
|
-
isBotMessage: Boolean(message.bot_id)
|
|
3454
|
+
const allowBotsMode = allowBotsSetting === "mentions" ? "mentions" : allowBotsSetting ? "all" : "off";
|
|
3455
|
+
const isBotMessage = Boolean(message.bot_id);
|
|
3456
|
+
const messageText = message.text ?? "";
|
|
3457
|
+
const mentionMetadata = {
|
|
3458
|
+
mentionedUserIds: collectSlackMentionIds(messageText, SLACK_USER_MENTION_RE),
|
|
3459
|
+
mentionedSubteamIds: collectSlackMentionIds(messageText, SLACK_SUBTEAM_MENTION_RE),
|
|
3460
|
+
hasAnyMention: SLACK_ANY_MENTION_RE.test(messageText),
|
|
3461
|
+
hasSubteamMention: messageText.includes(SLACK_SUBTEAM_MENTION_MARKER)
|
|
3534
3462
|
};
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
const
|
|
3538
|
-
const
|
|
3463
|
+
const normalizedBotUserId = normalizeSlackId(ctx.botUserId);
|
|
3464
|
+
const explicitBotMention = opts.source === "app_mention" || Boolean(normalizedBotUserId && mentionMetadata.mentionedUserIds.includes(normalizedBotUserId));
|
|
3465
|
+
const authorizationEventScope = opts.eventScope;
|
|
3466
|
+
const onVisibleDrop = opts.onVisibleDrop;
|
|
3539
3467
|
if (isBotMessage) {
|
|
3540
3468
|
if (ctx.botUserId && message.user === ctx.botUserId || ctx.botId && message.bot_id === ctx.botId) return null;
|
|
3541
3469
|
if (allowBotsMode === "off") return drop("bot-disabled");
|
|
@@ -3544,28 +3472,28 @@ async function authorizeSlackInboundMessage(params) {
|
|
|
3544
3472
|
const senderId = message.user ?? (isBotMessage ? message.bot_id : void 0);
|
|
3545
3473
|
if (!senderId) return drop("missing-sender");
|
|
3546
3474
|
if (!ctx.isChannelAllowed({
|
|
3547
|
-
teamId:
|
|
3475
|
+
teamId: authorizationEventScope?.teamId ?? ctx.teamId,
|
|
3548
3476
|
channelId: message.channel,
|
|
3549
3477
|
channelName,
|
|
3550
3478
|
channelType: resolvedChannelType
|
|
3551
3479
|
})) {
|
|
3552
|
-
if (
|
|
3480
|
+
if (isRoom && ctx.groupPolicy === "allowlist" && explicitBotMention && !isBotMessage && message.user) {
|
|
3553
3481
|
let subject = "This OpenClaw bot";
|
|
3554
3482
|
if (ctx.botUserId) try {
|
|
3555
|
-
const botIdentity = await ctx.resolveUserName(ctx.botUserId,
|
|
3483
|
+
const botIdentity = await ctx.resolveUserName(ctx.botUserId, authorizationEventScope);
|
|
3556
3484
|
const botName = normalizeOptionalString(botIdentity?.name);
|
|
3557
3485
|
if (botName) subject = escapeSlackMrkdwn(botName);
|
|
3558
3486
|
} catch (error) {
|
|
3559
3487
|
logVerbose(`slack allowlist denial bot-name lookup failed: ${formatSlackError(error)}`);
|
|
3560
3488
|
}
|
|
3561
3489
|
try {
|
|
3562
|
-
await (
|
|
3490
|
+
await (authorizationEventScope?.client ?? ctx.app.client).chat.postEphemeral({
|
|
3563
3491
|
token: ctx.botToken,
|
|
3564
3492
|
channel: message.channel,
|
|
3565
3493
|
user: message.user,
|
|
3566
3494
|
text: `${subject} can’t reply here because this channel isn’t in its OpenClaw channel allowlist. Ask the OpenClaw owner to allow this channel. <${SLACK_CHANNEL_ACCESS_DOCS_URL}|Learn how to configure Slack channel access.>`
|
|
3567
3495
|
});
|
|
3568
|
-
|
|
3496
|
+
onVisibleDrop?.();
|
|
3569
3497
|
} catch (error) {
|
|
3570
3498
|
ctx.runtime.error?.(`slack allowlist denial notice failed for channel ${message.channel}: ${formatSlackError(error)}`);
|
|
3571
3499
|
}
|
|
@@ -3574,7 +3502,7 @@ async function authorizeSlackInboundMessage(params) {
|
|
|
3574
3502
|
}
|
|
3575
3503
|
const allowFromLower = await resolveSlackEffectiveAllowFrom(ctx, {
|
|
3576
3504
|
includePairingStore: isDirectMessage,
|
|
3577
|
-
eventScope:
|
|
3505
|
+
eventScope: authorizationEventScope
|
|
3578
3506
|
});
|
|
3579
3507
|
if (isDirectMessage) {
|
|
3580
3508
|
const directUserId = message.user;
|
|
@@ -3584,16 +3512,16 @@ async function authorizeSlackInboundMessage(params) {
|
|
|
3584
3512
|
ctx,
|
|
3585
3513
|
accountId: account.accountId,
|
|
3586
3514
|
senderId: directUserId,
|
|
3587
|
-
eventScope:
|
|
3515
|
+
eventScope: authorizationEventScope,
|
|
3588
3516
|
allowFromLower,
|
|
3589
|
-
resolveSenderName: (userId) => ctx.resolveUserName(userId,
|
|
3517
|
+
resolveSenderName: (userId) => ctx.resolveUserName(userId, authorizationEventScope),
|
|
3590
3518
|
sendPairingReply: async (text) => {
|
|
3591
3519
|
await sendMessageSlack(message.channel, text, {
|
|
3592
3520
|
cfg: ctx.cfg,
|
|
3593
3521
|
token: ctx.botToken,
|
|
3594
|
-
client:
|
|
3522
|
+
client: authorizationEventScope?.client ?? ctx.app.client,
|
|
3595
3523
|
accountId: account.accountId,
|
|
3596
|
-
eventScope:
|
|
3524
|
+
eventScope: authorizationEventScope
|
|
3597
3525
|
});
|
|
3598
3526
|
},
|
|
3599
3527
|
onDisabled: () => {
|
|
@@ -3605,54 +3533,6 @@ async function authorizeSlackInboundMessage(params) {
|
|
|
3605
3533
|
log: logVerbose
|
|
3606
3534
|
})) return drop(dropReason);
|
|
3607
3535
|
}
|
|
3608
|
-
return {
|
|
3609
|
-
senderId,
|
|
3610
|
-
allowFromLower
|
|
3611
|
-
};
|
|
3612
|
-
}
|
|
3613
|
-
async function prepareSlackMessage(params) {
|
|
3614
|
-
const { ctx, account, message, opts } = params;
|
|
3615
|
-
const drop = (reason, parentUserId) => {
|
|
3616
|
-
ctx.logger.info({
|
|
3617
|
-
provider: "slack",
|
|
3618
|
-
accountId: account.accountId,
|
|
3619
|
-
teamId: opts.eventScope?.teamId ?? ctx.teamId,
|
|
3620
|
-
channelId: message.channel,
|
|
3621
|
-
messageTs: message.ts,
|
|
3622
|
-
source: opts.source,
|
|
3623
|
-
reason,
|
|
3624
|
-
...parentUserId ? { parentUserId } : {}
|
|
3625
|
-
}, "Slack inbound event rejected during preparation");
|
|
3626
|
-
return null;
|
|
3627
|
-
};
|
|
3628
|
-
const slackClient = opts.eventScope?.client ?? ctx.app.client;
|
|
3629
|
-
const threadStarterWorkspaceScope = {
|
|
3630
|
-
accountId: account.accountId,
|
|
3631
|
-
teamId: opts.eventScope?.teamId ?? ctx.teamId
|
|
3632
|
-
};
|
|
3633
|
-
const cfg = ctx.cfg;
|
|
3634
|
-
const conversation = await resolveSlackConversationContext({
|
|
3635
|
-
ctx,
|
|
3636
|
-
account,
|
|
3637
|
-
message,
|
|
3638
|
-
eventScope: opts.eventScope
|
|
3639
|
-
});
|
|
3640
|
-
const { channelInfo, channelName, isDirectMessage, isGroupDm, isRoom, isRoomish, channelConfig, allowBotsMode, isBotMessage } = conversation;
|
|
3641
|
-
const messageText = message.text ?? "";
|
|
3642
|
-
const mentionMetadata = collectSlackMentionMetadata(messageText);
|
|
3643
|
-
const normalizedBotUserId = normalizeSlackId(ctx.botUserId);
|
|
3644
|
-
const authorization = await authorizeSlackInboundMessage({
|
|
3645
|
-
ctx,
|
|
3646
|
-
account,
|
|
3647
|
-
message,
|
|
3648
|
-
conversation,
|
|
3649
|
-
explicitBotMention: opts.source === "app_mention" || Boolean(normalizedBotUserId && mentionMetadata.mentionedUserIds.includes(normalizedBotUserId)),
|
|
3650
|
-
eventScope: opts.eventScope,
|
|
3651
|
-
onVisibleDrop: opts.onVisibleDrop,
|
|
3652
|
-
drop
|
|
3653
|
-
});
|
|
3654
|
-
if (!authorization) return null;
|
|
3655
|
-
const { senderId, allowFromLower } = authorization;
|
|
3656
3536
|
let resolvedSenderName = normalizeOptionalString(message.username);
|
|
3657
3537
|
const resolveSenderName = async () => {
|
|
3658
3538
|
if (resolvedSenderName) return resolvedSenderName;
|
|
@@ -3688,9 +3568,17 @@ async function prepareSlackMessage(params) {
|
|
|
3688
3568
|
});
|
|
3689
3569
|
const explicitlyMentioned = explicitlyMentionedBotUser || explicitlyMentionedBotSubteam || opts.source === "app_mention";
|
|
3690
3570
|
const channelRequireMention = channelConfig?.requireMention ?? ctx.defaultRequireMention ?? true;
|
|
3691
|
-
const chatType = resolveSlackChatType(
|
|
3571
|
+
const chatType = resolveSlackChatType(resolvedChannelType);
|
|
3692
3572
|
const restoredAssistantThreadContext = await restoredAssistantThreadContextPromise;
|
|
3693
|
-
const
|
|
3573
|
+
const primary = messageAssistantThreadContext;
|
|
3574
|
+
const fallback = cachedAssistantThreadContext ?? restoredAssistantThreadContext;
|
|
3575
|
+
const assistantThreadContext = !primary ? fallback : !fallback ? primary : {
|
|
3576
|
+
assistantChannelId: primary.assistantChannelId || fallback.assistantChannelId,
|
|
3577
|
+
threadTs: primary.threadTs || fallback.threadTs,
|
|
3578
|
+
channelId: primary.channelId ?? fallback.channelId,
|
|
3579
|
+
teamId: primary.teamId ?? fallback.teamId,
|
|
3580
|
+
enterpriseId: primary.enterpriseId !== void 0 ? primary.enterpriseId : fallback.enterpriseId
|
|
3581
|
+
};
|
|
3694
3582
|
const assistantThreadContextToCache = messageAssistantThreadContext || restoredAssistantThreadContext ? assistantThreadContext : void 0;
|
|
3695
3583
|
if (assistantThreadContextToCache) ctx.saveSlackAssistantThreadContext(assistantThreadContextToCache, opts.eventScope);
|
|
3696
3584
|
const canUseManagedView = isDirectMessage && !opts.eventScope && !assistantThreadContext;
|
|
@@ -3754,19 +3642,16 @@ async function prepareSlackMessage(params) {
|
|
|
3754
3642
|
let mentionRegexes = buildPolicyMentionRegexes(routing.route.agentId);
|
|
3755
3643
|
let wasMentioned = resolveWasMentioned(mentionRegexes);
|
|
3756
3644
|
const hasBoundSession = Boolean(routing.runtimeBoundSessionKey || routing.configuredBindingSessionKey);
|
|
3757
|
-
const { configuredBinding
|
|
3645
|
+
const { configuredBinding } = routing;
|
|
3758
3646
|
const isAssistantThreadMessage = Boolean(isDirectMessage && messageAssistantThreadContext);
|
|
3759
3647
|
const forcedAssistantReplyThreadTs = Boolean(assistantThreadContext?.threadTs && (routing.isThreadReply || isAssistantThreadMessage || routing.replyToMode !== "off")) ? assistantThreadContext?.threadTs : void 0;
|
|
3760
3648
|
const forcedReplyThreadTs = agentViewThreadTs ?? forcedAssistantReplyThreadTs;
|
|
3761
|
-
if (routing.runtimeBinding && shouldLogVerbose()) logVerbose(`slack: routed via bound conversation ${routing.runtimeBinding.conversation.conversationId} -> ${routing.runtimeBinding.targetSessionKey}`);
|
|
3762
3649
|
if (configuredBinding) {
|
|
3763
3650
|
const ensured = await ensureConfiguredBindingRouteReady({
|
|
3764
3651
|
cfg,
|
|
3765
3652
|
bindingResolution: configuredBinding
|
|
3766
3653
|
});
|
|
3767
|
-
if (ensured.ok) {
|
|
3768
|
-
if (shouldLogVerbose()) logVerbose(`slack: using configured ACP binding for ${configuredBinding.record.conversation.conversationId} -> ${configuredBindingSessionKey}`);
|
|
3769
|
-
} else {
|
|
3654
|
+
if (!ensured.ok) {
|
|
3770
3655
|
if (shouldLogVerbose()) logVerbose(`slack: configured ACP binding unavailable for ${configuredBinding.record.conversation.conversationId}: ${ensured.error}`);
|
|
3771
3656
|
return drop("configured-binding-unavailable");
|
|
3772
3657
|
}
|
|
@@ -3804,7 +3689,11 @@ async function prepareSlackMessage(params) {
|
|
|
3804
3689
|
ctx,
|
|
3805
3690
|
account,
|
|
3806
3691
|
message,
|
|
3807
|
-
conversation
|
|
3692
|
+
conversation: {
|
|
3693
|
+
isRoom,
|
|
3694
|
+
isDirectMessage,
|
|
3695
|
+
channelConfig
|
|
3696
|
+
},
|
|
3808
3697
|
thread: routing,
|
|
3809
3698
|
wasMentioned,
|
|
3810
3699
|
teamId: opts.eventScope?.teamId,
|
|
@@ -3822,14 +3711,14 @@ async function prepareSlackMessage(params) {
|
|
|
3822
3711
|
const textForCommandDetection = stripSlackMentionsForCommandDetection(message.text ?? "");
|
|
3823
3712
|
const hasControlCommandInMessage = hasControlCommand(textForCommandDetection, cfg);
|
|
3824
3713
|
const hasAbortRequest = isAbortRequestText(textForCommandDetection);
|
|
3825
|
-
const channelUsersAllowlistConfigured = isRoom &&
|
|
3714
|
+
const channelUsersAllowlistConfigured = isRoom && (channelConfig?.users?.length ?? 0) > 0;
|
|
3826
3715
|
const resolveMessageIngress = async (contextBinding, threadId) => await resolveSlackCommandIngress({
|
|
3827
3716
|
ctx,
|
|
3828
3717
|
teamId: opts.eventScope?.teamId ?? ctx.teamId,
|
|
3829
3718
|
senderId,
|
|
3830
3719
|
senderAuthentication: message.user ? opts.senderAuthentication : void 0,
|
|
3831
3720
|
senderName: senderNameForAuth,
|
|
3832
|
-
channelType:
|
|
3721
|
+
channelType: resolvedChannelType ?? "channel",
|
|
3833
3722
|
channelId: message.channel,
|
|
3834
3723
|
threadId,
|
|
3835
3724
|
ownerAllowFromLower: allowFromLower,
|
|
@@ -3964,13 +3853,7 @@ async function prepareSlackMessage(params) {
|
|
|
3964
3853
|
const effectiveWasMentioned = mentionDecision.effectiveWasMentioned;
|
|
3965
3854
|
const shouldBypassMention = mentionDecision.shouldBypassMention;
|
|
3966
3855
|
const matchedImplicitMentionKinds = mentionDecision.matchedImplicitMentionKinds;
|
|
3967
|
-
const mentionSource =
|
|
3968
|
-
explicitBotMention: explicitlyMentionedBotUser || opts.source === "app_mention",
|
|
3969
|
-
explicitSubteamMention: explicitlyMentionedBotSubteam,
|
|
3970
|
-
matchedImplicitMentionKinds,
|
|
3971
|
-
shouldBypassMention,
|
|
3972
|
-
wasMentioned
|
|
3973
|
-
});
|
|
3856
|
+
const mentionSource = explicitlyMentionedBotUser || opts.source === "app_mention" ? "explicit_bot" : explicitlyMentionedBotSubteam ? "subteam" : shouldBypassMention ? "command_bypass" : wasMentioned ? "mention_pattern" : matchedImplicitMentionKinds.length > 0 ? "implicit_thread" : "none";
|
|
3974
3857
|
if (isBotMessage && allowBotsMode === "mentions") {
|
|
3975
3858
|
if (!(isDirectMessage || effectiveWasMentioned || shouldBypassMention)) return drop("bot-missing-mention");
|
|
3976
3859
|
}
|
|
@@ -4301,7 +4184,6 @@ async function prepareSlackMessage(params) {
|
|
|
4301
4184
|
originatingTo: preflightChannelTarget,
|
|
4302
4185
|
messageThreadId: threadContext.messageThreadId
|
|
4303
4186
|
});
|
|
4304
|
-
if (shouldLogVerbose()) logVerbose(`slack inbound: account=${route.accountId} agent=${route.agentId} channel=${message.channel} message_ts=${message.ts ?? "unknown"} thread_ts=${effectiveMessageThreadId ?? "none"} from=${slackFrom} chat=${chatType} chars=${rawBody.length}`);
|
|
4305
4187
|
const updateLastRouteSessionKey = resolveInboundLastRouteSessionKey({
|
|
4306
4188
|
route,
|
|
4307
4189
|
sessionKey
|